mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-06-18 15:54:13 +08:00
Compare commits
12 Commits
@@ -4,9 +4,9 @@
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
[](https://github.com/affaan-m/everything-claude-code/stargazers)
|
[](https://github.com/affaan-m/ECC/stargazers)
|
||||||
[](https://github.com/affaan-m/everything-claude-code/network/members)
|
[](https://github.com/affaan-m/ECC/network/members)
|
||||||
[](https://github.com/affaan-m/everything-claude-code/graphs/contributors)
|
[](https://github.com/affaan-m/ECC/graphs/contributors)
|
||||||
[](https://www.npmjs.com/package/ecc-universal)
|
[](https://www.npmjs.com/package/ecc-universal)
|
||||||
[](https://www.npmjs.com/package/ecc-agentshield)
|
[](https://www.npmjs.com/package/ecc-agentshield)
|
||||||
[](https://github.com/marketplace/ecc-tools)
|
[](https://github.com/marketplace/ecc-tools)
|
||||||
@@ -59,7 +59,7 @@ ECC v2.0.0-rc.1 adds the public Hermes operator story on top of that reusable la
|
|||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td width="25%" align="center">
|
<td width="25%" align="center">
|
||||||
<a href="https://github.com/affaan-m/everything-claude-code/discussions">
|
<a href="https://github.com/affaan-m/ECC/discussions">
|
||||||
<strong>Community</strong>
|
<strong>Community</strong>
|
||||||
<br />
|
<br />
|
||||||
<sub>Discussions · Q&A · Show & Tell</sub>
|
<sub>Discussions · Q&A · Show & Tell</sub>
|
||||||
@@ -172,7 +172,7 @@ This repo is the raw code only. The guides explain everything.
|
|||||||
|
|
||||||
### v1.4.1 — Bug Fix (Feb 2026)
|
### v1.4.1 — Bug Fix (Feb 2026)
|
||||||
|
|
||||||
- **Fixed instinct import content loss** — `parse_instinct_file()` was silently dropping all content after frontmatter (Action, Evidence, Examples sections) during `/instinct-import`. ([#148](https://github.com/affaan-m/everything-claude-code/issues/148), [#161](https://github.com/affaan-m/everything-claude-code/pull/161))
|
- **Fixed instinct import content loss** — `parse_instinct_file()` was silently dropping all content after frontmatter (Action, Evidence, Examples sections) during `/instinct-import`. ([#148](https://github.com/affaan-m/ECC/issues/148), [#161](https://github.com/affaan-m/ECC/pull/161))
|
||||||
|
|
||||||
### v1.4.0 — Multi-Language Rules, Installation Wizard & PM2 (Feb 2026)
|
### v1.4.0 — Multi-Language Rules, Installation Wizard & PM2 (Feb 2026)
|
||||||
|
|
||||||
@@ -196,7 +196,7 @@ This repo is the raw code only. The guides explain everything.
|
|||||||
- **Session management** — `/sessions` command for session history
|
- **Session management** — `/sessions` command for session history
|
||||||
- **Continuous learning v2** — Instinct-based learning with confidence scoring, import/export, evolution
|
- **Continuous learning v2** — Instinct-based learning with confidence scoring, import/export, evolution
|
||||||
|
|
||||||
See the full changelog in [Releases](https://github.com/affaan-m/everything-claude-code/releases).
|
See the full changelog in [Releases](https://github.com/affaan-m/ECC/releases).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -265,7 +265,7 @@ npx ecc install --profile minimal --target claude --with capability:machine-lear
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Add marketplace
|
# Add marketplace
|
||||||
/plugin marketplace add https://github.com/affaan-m/everything-claude-code
|
/plugin marketplace add https://github.com/affaan-m/ECC
|
||||||
|
|
||||||
# Install plugin
|
# Install plugin
|
||||||
/plugin install ecc@ecc
|
/plugin install ecc@ecc
|
||||||
@@ -275,7 +275,7 @@ npx ecc install --profile minimal --target claude --with capability:machine-lear
|
|||||||
|
|
||||||
ECC now has three public identifiers, and they are not interchangeable:
|
ECC now has three public identifiers, and they are not interchangeable:
|
||||||
|
|
||||||
- GitHub source repo: `affaan-m/everything-claude-code`
|
- GitHub source repo: `affaan-m/ECC`
|
||||||
- Claude marketplace/plugin identifier: `ecc@ecc`
|
- Claude marketplace/plugin identifier: `ecc@ecc`
|
||||||
- npm package: `ecc-universal`
|
- npm package: `ecc-universal`
|
||||||
|
|
||||||
@@ -295,8 +295,8 @@ This is intentional. Anthropic marketplace/plugin installs are keyed by a canoni
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Clone the repo first
|
# Clone the repo first
|
||||||
git clone https://github.com/affaan-m/everything-claude-code.git
|
git clone https://github.com/affaan-m/ECC.git
|
||||||
cd everything-claude-code
|
cd ECC
|
||||||
|
|
||||||
# Install dependencies (pick your package manager)
|
# Install dependencies (pick your package manager)
|
||||||
npm install # or: pnpm install | yarn install | bun install
|
npm install # or: pnpm install | yarn install | bun install
|
||||||
@@ -494,7 +494,7 @@ Windows PowerShell:
|
|||||||
This repo is a **Claude Code plugin** - install it directly or copy components manually.
|
This repo is a **Claude Code plugin** - install it directly or copy components manually.
|
||||||
|
|
||||||
```
|
```
|
||||||
everything-claude-code/
|
ECC/
|
||||||
|-- .claude-plugin/ # Plugin and marketplace manifests
|
|-- .claude-plugin/ # Plugin and marketplace manifests
|
||||||
| |-- plugin.json # Plugin metadata and component paths
|
| |-- plugin.json # Plugin metadata and component paths
|
||||||
| |-- marketplace.json # Marketplace catalog for /plugin marketplace add
|
| |-- marketplace.json # Marketplace catalog for /plugin marketplace add
|
||||||
@@ -812,7 +812,7 @@ Claude Code v2.1+ **automatically loads** `hooks/hooks.json` from any installed
|
|||||||
Duplicate hooks file detected: ./hooks/hooks.json resolves to already-loaded file
|
Duplicate hooks file detected: ./hooks/hooks.json resolves to already-loaded file
|
||||||
```
|
```
|
||||||
|
|
||||||
**History:** This has caused repeated fix/revert cycles in this repo ([#29](https://github.com/affaan-m/everything-claude-code/issues/29), [#52](https://github.com/affaan-m/everything-claude-code/issues/52), [#103](https://github.com/affaan-m/everything-claude-code/issues/103)). The behavior changed between Claude Code versions, leading to confusion. We now have a regression test to prevent this from being reintroduced.
|
**History:** This has caused repeated fix/revert cycles in this repo ([#29](https://github.com/affaan-m/ECC/issues/29), [#52](https://github.com/affaan-m/ECC/issues/52), [#103](https://github.com/affaan-m/ECC/issues/103)). The behavior changed between Claude Code versions, leading to confusion. We now have a regression test to prevent this from being reintroduced.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -824,7 +824,7 @@ The easiest way to use this repo - install as a Claude Code plugin:
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Add this repo as a marketplace
|
# Add this repo as a marketplace
|
||||||
/plugin marketplace add https://github.com/affaan-m/everything-claude-code
|
/plugin marketplace add https://github.com/affaan-m/ECC
|
||||||
|
|
||||||
# Install the plugin
|
# Install the plugin
|
||||||
/plugin install ecc@ecc
|
/plugin install ecc@ecc
|
||||||
@@ -838,7 +838,7 @@ Or add directly to your `~/.claude/settings.json`:
|
|||||||
"ecc": {
|
"ecc": {
|
||||||
"source": {
|
"source": {
|
||||||
"source": "github",
|
"source": "github",
|
||||||
"repo": "affaan-m/everything-claude-code"
|
"repo": "affaan-m/ECC"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -854,20 +854,21 @@ This gives you instant access to all commands, agents, skills, and hooks.
|
|||||||
>
|
>
|
||||||
> ```bash
|
> ```bash
|
||||||
> # Clone the repo first
|
> # Clone the repo first
|
||||||
> git clone https://github.com/affaan-m/everything-claude-code.git
|
> git clone https://github.com/affaan-m/ECC.git
|
||||||
|
> cd ECC
|
||||||
>
|
>
|
||||||
> # Option A: User-level rules (applies to all projects)
|
> # Option A: User-level rules (applies to all projects)
|
||||||
> mkdir -p ~/.claude/rules/ecc
|
> mkdir -p ~/.claude/rules/ecc
|
||||||
> cp -r everything-claude-code/rules/common ~/.claude/rules/ecc/
|
> cp -r rules/common ~/.claude/rules/ecc/
|
||||||
> cp -r everything-claude-code/rules/typescript ~/.claude/rules/ecc/ # pick your stack
|
> cp -r rules/typescript ~/.claude/rules/ecc/ # pick your stack
|
||||||
> cp -r everything-claude-code/rules/python ~/.claude/rules/ecc/
|
> cp -r rules/python ~/.claude/rules/ecc/
|
||||||
> cp -r everything-claude-code/rules/golang ~/.claude/rules/ecc/
|
> cp -r rules/golang ~/.claude/rules/ecc/
|
||||||
> cp -r everything-claude-code/rules/php ~/.claude/rules/ecc/
|
> cp -r rules/php ~/.claude/rules/ecc/
|
||||||
>
|
>
|
||||||
> # Option B: Project-level rules (applies to current project only)
|
> # Option B: Project-level rules (applies to current project only)
|
||||||
> mkdir -p .claude/rules/ecc
|
> mkdir -p .claude/rules/ecc
|
||||||
> cp -r everything-claude-code/rules/common .claude/rules/ecc/
|
> cp -r rules/common .claude/rules/ecc/
|
||||||
> cp -r everything-claude-code/rules/typescript .claude/rules/ecc/ # pick your stack
|
> cp -r rules/typescript .claude/rules/ecc/ # pick your stack
|
||||||
> ```
|
> ```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -878,34 +879,35 @@ If you prefer manual control over what's installed:
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Clone the repo
|
# Clone the repo
|
||||||
git clone https://github.com/affaan-m/everything-claude-code.git
|
git clone https://github.com/affaan-m/ECC.git
|
||||||
|
cd ECC
|
||||||
|
|
||||||
# Copy agents to your Claude config
|
# Copy agents to your Claude config
|
||||||
cp everything-claude-code/agents/*.md ~/.claude/agents/
|
cp agents/*.md ~/.claude/agents/
|
||||||
|
|
||||||
# Copy rules directories (common + language-specific)
|
# Copy rules directories (common + language-specific)
|
||||||
mkdir -p ~/.claude/rules/ecc
|
mkdir -p ~/.claude/rules/ecc
|
||||||
cp -r everything-claude-code/rules/common ~/.claude/rules/ecc/
|
cp -r rules/common ~/.claude/rules/ecc/
|
||||||
cp -r everything-claude-code/rules/typescript ~/.claude/rules/ecc/ # pick your stack
|
cp -r rules/typescript ~/.claude/rules/ecc/ # pick your stack
|
||||||
cp -r everything-claude-code/rules/python ~/.claude/rules/ecc/
|
cp -r rules/python ~/.claude/rules/ecc/
|
||||||
cp -r everything-claude-code/rules/golang ~/.claude/rules/ecc/
|
cp -r rules/golang ~/.claude/rules/ecc/
|
||||||
cp -r everything-claude-code/rules/php ~/.claude/rules/ecc/
|
cp -r rules/php ~/.claude/rules/ecc/
|
||||||
cp -r everything-claude-code/rules/arkts ~/.claude/rules/ecc/
|
cp -r rules/arkts ~/.claude/rules/ecc/
|
||||||
|
|
||||||
# Copy skills first (primary workflow surface)
|
# Copy skills first (primary workflow surface)
|
||||||
# Recommended (new users): core/general skills only
|
# Recommended (new users): core/general skills only
|
||||||
mkdir -p ~/.claude/skills/ecc
|
mkdir -p ~/.claude/skills/ecc
|
||||||
cp -r everything-claude-code/.agents/skills/* ~/.claude/skills/ecc/
|
cp -r .agents/skills/* ~/.claude/skills/ecc/
|
||||||
cp -r everything-claude-code/skills/search-first ~/.claude/skills/ecc/
|
cp -r skills/search-first ~/.claude/skills/ecc/
|
||||||
|
|
||||||
# Optional: add niche/framework-specific skills only when needed
|
# Optional: add niche/framework-specific skills only when needed
|
||||||
# for s in django-patterns django-tdd laravel-patterns springboot-patterns quarkus-patterns; do
|
# for s in django-patterns django-tdd laravel-patterns springboot-patterns quarkus-patterns; do
|
||||||
# cp -r everything-claude-code/skills/$s ~/.claude/skills/ecc/
|
# cp -r skills/$s ~/.claude/skills/ecc/
|
||||||
# done
|
# done
|
||||||
|
|
||||||
# Optional: keep maintained slash-command compatibility during migration
|
# Optional: keep maintained slash-command compatibility during migration
|
||||||
mkdir -p ~/.claude/commands
|
mkdir -p ~/.claude/commands
|
||||||
cp everything-claude-code/commands/*.md ~/.claude/commands/
|
cp commands/*.md ~/.claude/commands/
|
||||||
|
|
||||||
# Retired shims live in legacy-command-shims/commands/.
|
# Retired shims live in legacy-command-shims/commands/.
|
||||||
# Copy individual files from there only if you still need old names such as /tdd.
|
# Copy individual files from there only if you still need old names such as /tdd.
|
||||||
@@ -1083,7 +1085,7 @@ This shows all available agents, commands, and skills from the plugin.
|
|||||||
<details>
|
<details>
|
||||||
<summary><b>My hooks aren't working / I see "Duplicate hooks file" errors</b></summary>
|
<summary><b>My hooks aren't working / I see "Duplicate hooks file" errors</b></summary>
|
||||||
|
|
||||||
This is the most common issue. **Do NOT add a `"hooks"` field to `.claude-plugin/plugin.json`.** Claude Code v2.1+ automatically loads `hooks/hooks.json` from installed plugins. Explicitly declaring it causes duplicate detection errors. See [#29](https://github.com/affaan-m/everything-claude-code/issues/29), [#52](https://github.com/affaan-m/everything-claude-code/issues/52), [#103](https://github.com/affaan-m/everything-claude-code/issues/103).
|
This is the most common issue. **Do NOT add a `"hooks"` field to `.claude-plugin/plugin.json`.** Claude Code v2.1+ automatically loads `hooks/hooks.json` from installed plugins. Explicitly declaring it causes duplicate detection errors. See [#29](https://github.com/affaan-m/ECC/issues/29), [#52](https://github.com/affaan-m/ECC/issues/52), [#103](https://github.com/affaan-m/ECC/issues/103).
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
@@ -1128,11 +1130,11 @@ Yes. Use Option 2 (manual installation) and copy only what you need:
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Just agents
|
# Just agents
|
||||||
cp everything-claude-code/agents/*.md ~/.claude/agents/
|
cp agents/*.md ~/.claude/agents/
|
||||||
|
|
||||||
# Just rules
|
# Just rules
|
||||||
mkdir -p ~/.claude/rules/ecc/
|
mkdir -p ~/.claude/rules/ecc/
|
||||||
cp -r everything-claude-code/rules/common ~/.claude/rules/ecc/
|
cp -r rules/common ~/.claude/rules/ecc/
|
||||||
```
|
```
|
||||||
|
|
||||||
Each component is fully independent.
|
Each component is fully independent.
|
||||||
@@ -1145,7 +1147,7 @@ Yes. ECC is cross-platform:
|
|||||||
- **Cursor**: Pre-translated configs in `.cursor/`. See [Cursor IDE Support](#cursor-ide-support).
|
- **Cursor**: Pre-translated configs in `.cursor/`. See [Cursor IDE Support](#cursor-ide-support).
|
||||||
- **Gemini CLI**: Experimental project-local support via `.gemini/GEMINI.md` and shared installer plumbing.
|
- **Gemini CLI**: Experimental project-local support via `.gemini/GEMINI.md` and shared installer plumbing.
|
||||||
- **OpenCode**: Full plugin support in `.opencode/`. See [OpenCode Support](#opencode-support).
|
- **OpenCode**: Full plugin support in `.opencode/`. See [OpenCode Support](#opencode-support).
|
||||||
- **Codex**: First-class support for both macOS app and CLI, with adapter drift guards and SessionStart fallback. See PR [#257](https://github.com/affaan-m/everything-claude-code/pull/257).
|
- **Codex**: First-class support for both macOS app and CLI, with adapter drift guards and SessionStart fallback. See PR [#257](https://github.com/affaan-m/ECC/pull/257).
|
||||||
- **GitHub Copilot (VS Code)**: Instruction and prompt layer via `.github/copilot-instructions.md`, `.vscode/settings.json`, and `.github/prompts/`. See [GitHub Copilot Support](#github-copilot-support).
|
- **GitHub Copilot (VS Code)**: Instruction and prompt layer via `.github/copilot-instructions.md`, `.vscode/settings.json`, and `.github/prompts/`. See [GitHub Copilot Support](#github-copilot-support).
|
||||||
- **Antigravity**: Tightly integrated setup for workflows, skills, and flattened rules in `.agent/`. See [Antigravity Guide](docs/ANTIGRAVITY-GUIDE.md).
|
- **Antigravity**: Tightly integrated setup for workflows, skills, and flattened rules in `.agent/`. See [Antigravity Guide](docs/ANTIGRAVITY-GUIDE.md).
|
||||||
- **JoyCode / CodeBuddy**: Project-local selective install adapters for commands, agents, skills, and flattened rules. See [JoyCode Adapter Guide](docs/JOYCODE-GUIDE.md).
|
- **JoyCode / CodeBuddy**: Project-local selective install adapters for commands, agents, skills, and flattened rules. See [JoyCode Adapter Guide](docs/JOYCODE-GUIDE.md).
|
||||||
@@ -1488,7 +1490,7 @@ OpenCode's plugin system is MORE sophisticated than Claude Code with 20+ event t
|
|||||||
|
|
||||||
**Option 1: Use directly**
|
**Option 1: Use directly**
|
||||||
```bash
|
```bash
|
||||||
cd everything-claude-code
|
cd ECC
|
||||||
opencode
|
opencode
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -1738,7 +1740,7 @@ This project is free and open source. Sponsors help keep it maintained and growi
|
|||||||
|
|
||||||
## Star History
|
## Star History
|
||||||
|
|
||||||
[](https://star-history.com/#affaan-m/everything-claude-code&Date)
|
[](https://star-history.com/#affaan-m/ECC&Date)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -114,7 +114,31 @@ function isDangerousInvisibleCodePoint(codePoint) {
|
|||||||
(codePoint >= 0x202A && codePoint <= 0x202E) ||
|
(codePoint >= 0x202A && codePoint <= 0x202E) ||
|
||||||
(codePoint >= 0x2066 && codePoint <= 0x2069) ||
|
(codePoint >= 0x2066 && codePoint <= 0x2069) ||
|
||||||
(codePoint >= 0xFE00 && codePoint <= 0xFE0F) ||
|
(codePoint >= 0xFE00 && codePoint <= 0xFE0F) ||
|
||||||
(codePoint >= 0xE0100 && codePoint <= 0xE01EF)
|
(codePoint >= 0xE0100 && codePoint <= 0xE01EF) ||
|
||||||
|
// Unicode Tag block (U+E0000–U+E007F). Tag characters were proposed
|
||||||
|
// for language tagging in Unicode 3.1 and have been deprecated since
|
||||||
|
// Unicode 5.1, so no legitimate text uses them. They are the canonical
|
||||||
|
// vector for "ASCII smuggling" / "Tag smuggling" prompt injection:
|
||||||
|
// an attacker hides instructions inside ASCII-looking strings (PR
|
||||||
|
// bodies, SKILL.md, frontmatter), the LLM consumes the tag bytes,
|
||||||
|
// and the human reviewer sees nothing.
|
||||||
|
(codePoint >= 0xE0000 && codePoint <= 0xE007F) ||
|
||||||
|
// U+180E MONGOLIAN VOWEL SEPARATOR — formerly classified as a space
|
||||||
|
// separator, reclassified as a format control in Unicode 6.3; renders
|
||||||
|
// as zero-width and routinely abused for homograph / smuggling.
|
||||||
|
codePoint === 0x180E ||
|
||||||
|
// U+115F / U+1160 HANGUL CHOSEONG/JUNGSEONG FILLER — zero-width fillers
|
||||||
|
// used in Korean text shaping; abused as invisible characters.
|
||||||
|
codePoint === 0x115F ||
|
||||||
|
codePoint === 0x1160 ||
|
||||||
|
// U+2061–U+2064 invisible math operators (FUNCTION APPLICATION,
|
||||||
|
// INVISIBLE TIMES, INVISIBLE SEPARATOR, INVISIBLE PLUS). Zero-width
|
||||||
|
// and not used outside math typesetting; legitimate Markdown / source
|
||||||
|
// does not contain them.
|
||||||
|
(codePoint >= 0x2061 && codePoint <= 0x2064) ||
|
||||||
|
// U+3164 HANGUL FILLER — zero-width filler reportedly used in Discord
|
||||||
|
// / Twitter smuggling attacks; not used in legitimate Korean text.
|
||||||
|
codePoint === 0x3164
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -109,6 +109,74 @@ if (
|
|||||||
passed++;
|
passed++;
|
||||||
else failed++;
|
else failed++;
|
||||||
|
|
||||||
|
// Invisible code points newly covered by the denylist. These were missing
|
||||||
|
// from the previous denylist and silently passed through both detection and
|
||||||
|
// `--write` mode. Each is a documented LLM-prompt-injection vector
|
||||||
|
// (Tag block "ASCII smuggling"; the other invisibles are widely cited in
|
||||||
|
// homograph / Discord / Twitter smuggling references).
|
||||||
|
|
||||||
|
const NEWLY_COVERED_RANGES = [
|
||||||
|
{ codePoint: 0xE0041, label: 'Tag block U+E0041 (TAG LATIN CAPITAL LETTER A)' },
|
||||||
|
{ codePoint: 0xE007F, label: 'Tag block U+E007F (CANCEL TAG, range end)' },
|
||||||
|
{ codePoint: 0x180E, label: 'U+180E MONGOLIAN VOWEL SEPARATOR' },
|
||||||
|
{ codePoint: 0x115F, label: 'U+115F HANGUL CHOSEONG FILLER' },
|
||||||
|
{ codePoint: 0x1160, label: 'U+1160 HANGUL JUNGSEONG FILLER' },
|
||||||
|
{ codePoint: 0x2061, label: 'U+2061 FUNCTION APPLICATION' },
|
||||||
|
{ codePoint: 0x2064, label: 'U+2064 INVISIBLE PLUS (range end)' },
|
||||||
|
{ codePoint: 0x3164, label: 'U+3164 HANGUL FILLER' },
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const { codePoint, label } of NEWLY_COVERED_RANGES) {
|
||||||
|
if (
|
||||||
|
test(`detects ${label}`, () => {
|
||||||
|
const root = makeTempRoot('ecc-unicode-newly-covered-');
|
||||||
|
fs.mkdirSync(path.join(root, 'docs'), { recursive: true });
|
||||||
|
const hex = codePoint.toString(16).toUpperCase().padStart(4, '0');
|
||||||
|
fs.writeFileSync(
|
||||||
|
path.join(root, 'docs', `probe-${hex}.md`),
|
||||||
|
`# Probe\n\nBenign${String.fromCodePoint(codePoint)}text\n`
|
||||||
|
);
|
||||||
|
const result = runCheck(root);
|
||||||
|
assert.notStrictEqual(result.status, 0,
|
||||||
|
`expected exit non-zero on U+${hex}, got ${result.status}: ${result.stderr}`);
|
||||||
|
assert.match(result.stderr, new RegExp(`dangerous-invisible U\\+${hex}`),
|
||||||
|
`expected violation message for U+${hex}, got: ${result.stderr}`);
|
||||||
|
})
|
||||||
|
)
|
||||||
|
passed++;
|
||||||
|
else failed++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
test('write mode strips newly-covered invisibles from markdown', () => {
|
||||||
|
const root = makeTempRoot('ecc-unicode-newly-covered-write-');
|
||||||
|
fs.mkdirSync(path.join(root, 'docs'), { recursive: true });
|
||||||
|
const tagHidden = [...Array(5)].map((_, i) => String.fromCodePoint(0xE0041 + i)).join('');
|
||||||
|
const mongolianHidden = String.fromCodePoint(0x180E);
|
||||||
|
const filePath = path.join(root, 'docs', 'mixed.md');
|
||||||
|
fs.writeFileSync(filePath, `# Title\n\nBenign${tagHidden}${mongolianHidden}text.\n`);
|
||||||
|
|
||||||
|
const writeResult = runCheck(root, ['--write']);
|
||||||
|
assert.strictEqual(writeResult.status, 0,
|
||||||
|
`expected --write to succeed, got ${writeResult.status}: ${writeResult.stderr}`);
|
||||||
|
|
||||||
|
const sanitized = fs.readFileSync(filePath, 'utf8');
|
||||||
|
assert.doesNotMatch(sanitized, /[\u{E0000}-\u{E007F}]/u,
|
||||||
|
'expected tag block characters stripped');
|
||||||
|
assert.doesNotMatch(sanitized, /\u{180E}/u,
|
||||||
|
'expected U+180E stripped');
|
||||||
|
assert.strictEqual(sanitized, '# Title\n\nBenigntext.\n',
|
||||||
|
'expected only the invisible characters removed, surrounding text preserved');
|
||||||
|
|
||||||
|
// Re-run without --write; should now pass cleanly.
|
||||||
|
const clean = runCheck(root);
|
||||||
|
assert.strictEqual(clean.status, 0,
|
||||||
|
`expected post-sanitize re-run to pass, got: ${clean.stderr}`);
|
||||||
|
})
|
||||||
|
)
|
||||||
|
passed++;
|
||||||
|
else failed++;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
test('skips Python virtual environments', () => {
|
test('skips Python virtual environments', () => {
|
||||||
const root = makeTempRoot('ecc-unicode-venv-');
|
const root = makeTempRoot('ecc-unicode-venv-');
|
||||||
|
|||||||
Reference in New Issue
Block a user