Compare commits

..

2 Commits

Author SHA1 Message Date
zomia 49bd7d4809 docs(i18n): apply cp -r flatten fix to zh-CN, ko-KR, pt-BR, tr translations
Mirrors the previous commit's fix into the remaining translated docs
that carried the same `cp -r .../<lang>/* <target>/rules/` form:

- docs/zh-CN/README.md (3 install sections: Option A/B blockquote,
  manual install block, and "Just rules" subset block)
- docs/zh-CN/skills/configure-ecc/SKILL.md (1 install block; comments
  also updated to drop "flat copy into rules/")
- docs/ko-KR/README.md (Option A/B blockquote, manual install block,
  "Just rules" block)
- docs/pt-BR/README.md (Option A/B blockquote, manual install block)
- docs/tr/README.md (single "Just rules" line)

Same mechanical transformation as the previous commit:
`rules/<lang>/* <target>/rules/` -> `rules/<lang> <target>/rules/<lang>`.

Full test suite (node tests/run-all.js): 2382 passed, 0 failed.
markdownlint clean on all modified files.

Part of #1879.
2026-05-14 09:12:06 +09:00
zomia 4d3033eb64 docs: fix cp -r flatten install instructions that silently overwrite rules
The configure-ecc skill (English source) and ja-JP top-level README plus
its configure-ecc translation documented `cp -r .../<lang>/* <target>/rules/`
for installing rule directories. rules/README.md explicitly warns against
this form because:

- Common and language-specific directories contain same-named files
  (coding-style.md, testing.md, patterns.md, hooks.md, security.md).
  Flattening makes each language overwrite the previous and common.
- The relative `../common/<file>.md` references in language rule files
  break when common/ is no longer a sibling directory.

This is silent — the user gets only the last language's rules with no
error message.

Replace with the directory-form copy already documented in
rules/README.md:

    cp -r .../<lang> <target>/rules/<lang>

Scope: English source + ja-JP. Closes #1879. Other locale translations
(zh-CN, ko-KR, pt-BR, tr) carry the same pattern and can follow up as
separate PRs to keep this change reviewable.
2026-05-14 08:40:36 +09:00
12 changed files with 75 additions and 513 deletions
+7 -57
View File
@@ -122,37 +122,6 @@ As of 2026-05-13:
billing/entitlement, cost-regression, and cost-policy evidence, excludes billing/entitlement, cost-regression, and cost-policy evidence, excludes
obvious secret-bearing paths from fetches, returns cost-control findings and obvious secret-bearing paths from fetches, returns cost-control findings and
next actions, and charges usage only after successful execution. next actions, and charges usage only after successful execution.
- ECC-Tools PR #62 merged as `781d6733e56f7556edb43fb96bdfb00b1f0a3aa6`
and added the sixth executable hosted analysis job:
`/api/analysis/jobs/team-backlog-routing` now gates on team handoff/project
tracking readiness, evaluates roadmap, runbook, handoff, release-plan,
issue-template, ownership, project-tracker, backlog, and follow-up evidence,
excludes obvious secret-bearing paths from fetches, returns team-routing
findings and next actions, and charges usage only after successful execution.
- ECC-Tools PR #63 merged as `fb9e4c5ceb9ccde50da74c7a69c3fa4bd321fc07`
and made the hosted execution plan operator-visible on queued PR analysis:
the queue now publishes a non-blocking `ECC Tools / Hosted Depth Plan`
check-run on the PR head SHA with ready/blocked hosted executor commands
and next action text, while keeping check-run publication best-effort so
bundle generation and analysis comments are not blocked.
- ECC-Tools PR #64 merged as `72020ef94db94840812977ea7ac37e9344036668`
and added PR-facing hosted job dispatch controls:
`/ecc-tools analyze --job ...` comments now queue hosted jobs against the
PR head SHA, execute them through the existing hosted readiness/evidence
gates, post artifacts/findings/next actions back to the PR, and scope
idempotency keys by job id so hosted jobs do not collide with bundle
analysis.
- ECC-Tools PR #65 merged as `bacd4adf6a3a629e8d403865456d15f127baaf4e`
and added hosted job result history/check-run summaries:
queued hosted jobs now cache both the latest result and immutable run records
for completed or blocked runs, then publish a non-blocking per-job check-run
on the PR head SHA with artifacts, findings, readiness blockers, and next
actions.
- ECC-Tools PR #66 merged as `4e1db48252d068ea5dcf4308b0bc11b0dfe0c9ce`
and added a read-only hosted status command:
`/ecc-tools analyze --job status` now reads the #65 latest-result cache for
the current PR head and posts a compact completed/blocked/not-run table with
the next hosted job command, without queueing work or billing usage.
- Handoff `ecc-supply-chain-audit-20260513-0645.md` under - Handoff `ecc-supply-chain-audit-20260513-0645.md` under
`~/.cluster-swarm/handoffs/` `~/.cluster-swarm/handoffs/`
records the May 13 supply-chain sweep: no active lockfile/manifest hit for records the May 13 supply-chain sweep: no active lockfile/manifest hit for
@@ -366,26 +335,6 @@ As of 2026-05-13:
model-routing, token-budget, usage-limit, rate-limit, billing/entitlement, model-routing, token-budget, usage-limit, rate-limit, billing/entitlement,
cost-regression, and cost-policy evidence while avoiding obvious cost-regression, and cost-policy evidence while avoiding obvious
secret-bearing path fetches. secret-bearing path fetches.
- ECC-Tools PR #62 implemented the sixth job-specific hosted executor:
`/api/analysis/jobs/team-backlog-routing` applies the same hosted gates to
roadmap, runbook, handoff, release-plan, issue-template, ownership,
project-tracker, backlog, and follow-up evidence while avoiding obvious
secret-bearing path fetches.
- ECC-Tools PR #63 publishes the hosted depth-plan check-run after queued PR
analysis completes, making the six hosted executor commands visible on the
PR head SHA without turning the check into a merge blocker.
- ECC-Tools PR #64 wires those commands into the queue: maintainers can comment
`/ecc-tools analyze --job ci-diagnostics`, `security-evidence`,
`harness-compatibility`, `reference-set-evaluation`, `ai-routing-cost`, or
`team-backlog` on a PR and receive hosted job results in a PR comment.
- ECC-Tools PR #65 persists completed and blocked hosted job results to the
analysis cache for 30 days and publishes non-blocking `ECC Tools / Hosted
Job: ...` check-runs so maintainers can scan hosted outcomes from the PR
checks surface instead of rereading older comments.
- ECC-Tools PR #66 exposes the cached results from PR comments with
`/ecc-tools analyze --job status`, summarizing completed, blocked, and
not-yet-run hosted jobs for the PR head and recommending the next hosted job
command.
- ECC PR #1803 landed the contributor Quarkus handling branch after maintainer - ECC PR #1803 landed the contributor Quarkus handling branch after maintainer
cleanup, current-`main` alignment, full local validation, and preservation of cleanup, current-`main` alignment, full local validation, and preservation of
the author's removal of incomplete ja-JP and zh-CN Quarkus translations. the author's removal of incomplete ja-JP and zh-CN Quarkus translations.
@@ -439,10 +388,10 @@ is not complete unless the evidence column exists and has been freshly verified.
| Claude and Codex plugin publication | Contact/submission path with required artifacts and status | Publication readiness, naming matrix, and May 12 dry-run evidence document plugin validation, clean-checkout Claude tag/install smoke, and Codex marketplace CLI shape | Needs explicit approval for real tag/push and marketplace submission | | Claude and Codex plugin publication | Contact/submission path with required artifacts and status | Publication readiness, naming matrix, and May 12 dry-run evidence document plugin validation, clean-checkout Claude tag/install smoke, and Codex marketplace CLI shape | Needs explicit approval for real tag/push and marketplace submission |
| Articles, tweets, and announcements | X thread, LinkedIn copy, GitHub release copy, push checklist | Draft launch collateral exists under rc.1 release docs | Needs URL-backed refresh | | Articles, tweets, and announcements | X thread, LinkedIn copy, GitHub release copy, push checklist | Draft launch collateral exists under rc.1 release docs | Needs URL-backed refresh |
| AgentShield enterprise iteration | Policy gates, SARIF, packs, provenance, corpus, HTML reports, exception lifecycle audit, baseline drift Action/CLI surfaces, evidence-pack redaction, harness adapter registry, enterprise research roadmap, supply-chain hardened release path, CI-safe baseline fingerprints, corpus accuracy recommendations, remediation workflow phases, env proxy hijack corpus coverage | PRs #53, #55-#64, #67-#69, and #78-#82 landed with test evidence; native PDF export deferred in favor of self-contained HTML plus print-to-PDF until explicit enterprise demand appears; `docs/architecture/agentshield-enterprise-research-roadmap.md` now has baseline drift, evidence-pack bundle, redaction, adapter-registry, supply-chain hardening, hashed baseline fingerprints, corpus accuracy recommendation, remediation workflow, and env proxy hijack corpus slices landed | Next hosted evidence-pack workflow depth | | AgentShield enterprise iteration | Policy gates, SARIF, packs, provenance, corpus, HTML reports, exception lifecycle audit, baseline drift Action/CLI surfaces, evidence-pack redaction, harness adapter registry, enterprise research roadmap, supply-chain hardened release path, CI-safe baseline fingerprints, corpus accuracy recommendations, remediation workflow phases, env proxy hijack corpus coverage | PRs #53, #55-#64, #67-#69, and #78-#82 landed with test evidence; native PDF export deferred in favor of self-contained HTML plus print-to-PDF until explicit enterprise demand appears; `docs/architecture/agentshield-enterprise-research-roadmap.md` now has baseline drift, evidence-pack bundle, redaction, adapter-registry, supply-chain hardening, hashed baseline fingerprints, corpus accuracy recommendation, remediation workflow, and env proxy hijack corpus slices landed | Next hosted evidence-pack workflow depth |
| ECC Tools next-level app | Billing audit, PR checks, deep analyzer, sync backlog, evaluator/RAG corpus, analysis-depth readiness, hosted execution planning, hosted CI diagnostics, hosted security evidence review, hosted harness compatibility audit, hosted reference-set evaluation, hosted AI routing/cost review, hosted team backlog routing, hosted depth-plan check-run, PR-comment hosted job dispatch, hosted job result history/check-runs, hosted result status command | PRs #26-#43 plus #53-#66 landed with test evidence, including AgentShield evidence-pack gap routing, canonical bundle recognition, supply-chain signature gates, PR draft follow-up Linear tracking, evidence-backed/deep-ready repository classification, the `/api/analysis/depth-plan` hosted job plan, `/api/analysis/jobs/ci-diagnostics`, `/api/analysis/jobs/security-evidence-review`, `/api/analysis/jobs/harness-compatibility-audit`, `/api/analysis/jobs/reference-set-evaluation`, `/api/analysis/jobs/ai-routing-cost-review`, `/api/analysis/jobs/team-backlog-routing`, the `ECC Tools / Hosted Depth Plan` check-run, `/ecc-tools analyze --job ...` PR-comment dispatch, non-blocking per-hosted-job result check-runs backed by 30-day result cache records, and `/ecc-tools analyze --job status` cache lookup | Next work is evaluator-backed hosted promotion and status-aware depth-plan recommendations | | ECC Tools next-level app | Billing audit, PR checks, deep analyzer, sync backlog, evaluator/RAG corpus, analysis-depth readiness, hosted execution planning, hosted CI diagnostics, hosted security evidence review, hosted harness compatibility audit, hosted reference-set evaluation, hosted AI routing/cost review | PRs #26-#43 plus #53-#61 landed with test evidence, including AgentShield evidence-pack gap routing, canonical bundle recognition, supply-chain signature gates, PR draft follow-up Linear tracking, evidence-backed/deep-ready repository classification, the `/api/analysis/depth-plan` hosted job plan, `/api/analysis/jobs/ci-diagnostics`, `/api/analysis/jobs/security-evidence-review`, `/api/analysis/jobs/harness-compatibility-audit`, `/api/analysis/jobs/reference-set-evaluation`, and `/api/analysis/jobs/ai-routing-cost-review` | Needs the remaining hosted worker executor for team backlog routing |
| GitGuardian/Dependabot/CodeRabbit-style checks | Non-blocking taxonomy, deterministic follow-up checks, and local supply-chain gates | ECC-Tools risk taxonomy check plus follow-up signals landed, including Skill Quality, Deep Analyzer Evidence, Analyzer Corpus Evidence, RAG/Evaluator Evidence, PR Review/Salvage Evidence, and AgentShield evidence-pack evidence; #1846 added npm registry signature gates; #1848 added the supply-chain incident-response playbook and `pull_request_target` cache-poisoning validator guard; #1851 added the privileged checkout credential-persistence guard; AgentShield #78, JARVIS #13, and ECC-Tools #53 applied the same hardening outside trunk | Current supply-chain gate complete; deeper hosted review features remain future | | GitGuardian/Dependabot/CodeRabbit-style checks | Non-blocking taxonomy, deterministic follow-up checks, and local supply-chain gates | ECC-Tools risk taxonomy check plus follow-up signals landed, including Skill Quality, Deep Analyzer Evidence, Analyzer Corpus Evidence, RAG/Evaluator Evidence, PR Review/Salvage Evidence, and AgentShield evidence-pack evidence; #1846 added npm registry signature gates; #1848 added the supply-chain incident-response playbook and `pull_request_target` cache-poisoning validator guard; #1851 added the privileged checkout credential-persistence guard; AgentShield #78, JARVIS #13, and ECC-Tools #53 applied the same hardening outside trunk | Current supply-chain gate complete; deeper hosted review features remain future |
| Harness-agnostic learning system | Audit, adapter matrix, observability, traces, promotion loop | Audit/adapters/observability gates plus `docs/architecture/evaluator-rag-prototype.md`, `examples/evaluator-rag-prototype/`, and ECC-Tools PR #40 define read-only stale-salvage, billing-readiness, CI-failure-diagnosis, harness-config-quality, AgentShield policy-exception, skill-quality evidence, deep-analyzer evidence, and RAG/evaluator comparison scenarios with trace, report, playbook, verifier, and predictive-check artifacts | Local corpus complete; hosted integration remains future | | Harness-agnostic learning system | Audit, adapter matrix, observability, traces, promotion loop | Audit/adapters/observability gates plus `docs/architecture/evaluator-rag-prototype.md`, `examples/evaluator-rag-prototype/`, and ECC-Tools PR #40 define read-only stale-salvage, billing-readiness, CI-failure-diagnosis, harness-config-quality, AgentShield policy-exception, skill-quality evidence, deep-analyzer evidence, and RAG/evaluator comparison scenarios with trace, report, playbook, verifier, and predictive-check artifacts | Local corpus complete; hosted integration remains future |
| Linear roadmap is detailed | Linear project status plus repo mirror | Repo mirror exists; issue creation was retried on 2026-05-12 and remains blocked by the workspace free issue limit; this May 13 sync adds ECC #1860, AgentShield #78-#82, JARVIS #13, ECC-Tools #53-#66, resolved queue/discussion counts, and Linear project status updates through ECC-Tools #66 | Needs recurring status updates after each merge batch | | Linear roadmap is detailed | Linear project status plus repo mirror | Repo mirror exists; issue creation was retried on 2026-05-12 and remains blocked by the workspace free issue limit; this May 13 sync adds ECC #1860, AgentShield #78-#82, JARVIS #13, ECC-Tools #53-#61, resolved queue/discussion counts, and Linear project status updates through ECC-Tools #61 | Needs recurring status updates after each merge batch |
| Flow separation and progress tracking | Flow lanes with owner artifacts and update cadence | This roadmap defines lanes below and `docs/architecture/progress-sync-contract.md` makes GitHub/Linear/handoff/roadmap sync part of the readiness gate | Active | | Flow separation and progress tracking | Flow lanes with owner artifacts and update cadence | This roadmap defines lanes below and `docs/architecture/progress-sync-contract.md` makes GitHub/Linear/handoff/roadmap sync part of the readiness gate | Active |
| Realtime Linear sync | Project updates while issue limit is blocked; issues later | ECC-Tools #39 implements opt-in Linear API sync for deferred follow-up backlog items, and ECC-Tools #54 adds copy-ready PR drafts to that backlog when draft PR shells are not opened; `docs/architecture/progress-sync-contract.md` defines the local file-backed realtime boundary while issue capacity is blocked | Needs workspace capacity/config rollout | | Realtime Linear sync | Project updates while issue limit is blocked; issues later | ECC-Tools #39 implements opt-in Linear API sync for deferred follow-up backlog items, and ECC-Tools #54 adds copy-ready PR drafts to that backlog when draft PR shells are not opened; `docs/architecture/progress-sync-contract.md` defines the local file-backed realtime boundary while issue capacity is blocked | Needs workspace capacity/config rollout |
| Observability for self-use | Local readiness gate, traces, status snapshots, HUD/status contract, risk ledger, progress-sync contract | `npm run observability:ready` reports 21/21 | Complete for local gate | | Observability for self-use | Local readiness gate, traces, status snapshots, HUD/status contract, risk ledger, progress-sync contract | `npm run observability:ready` reports 21/21 | Complete for local gate |
@@ -463,7 +412,7 @@ repo evidence and merge commits.
| Harness OS core | Audit, adapter matrix, observability docs, `ecc2/` | HUD/session-control acceptance spec | Weekly until GA | | Harness OS core | Audit, adapter matrix, observability docs, `ecc2/` | HUD/session-control acceptance spec | Weekly until GA |
| Evaluation and RAG | Reference-set validation, harness audit, traces, ECC-Tools corpus | Read-only evaluator/RAG prototype plus stale-salvage, billing-readiness, CI-failure-diagnosis, harness-config-quality, AgentShield policy-exception, skill-quality evidence, deep-analyzer evidence, and RAG/evaluator comparison fixtures | Hosted retrieval/check-run automation plan | | Evaluation and RAG | Reference-set validation, harness audit, traces, ECC-Tools corpus | Read-only evaluator/RAG prototype plus stale-salvage, billing-readiness, CI-failure-diagnosis, harness-config-quality, AgentShield policy-exception, skill-quality evidence, deep-analyzer evidence, and RAG/evaluator comparison fixtures | Hosted retrieval/check-run automation plan |
| AgentShield enterprise | AgentShield PR evidence and roadmap notes | Remediation workflow depth or corpus expansion follow-up | Next implementation batch | | AgentShield enterprise | AgentShield PR evidence and roadmap notes | Remediation workflow depth or corpus expansion follow-up | Next implementation batch |
| ECC Tools app | ECC-Tools PR evidence, billing audit, risk taxonomy, evaluator/RAG corpus | ECC-Tools #53 published the supply-chain workflow hardening branch, #54 tracks copy-ready PR drafts in the Linear/project backlog, #55 classifies analysis-depth readiness, #56 exposes the hosted execution plan, #57 executes the first hosted CI diagnostics job, #58 executes the hosted security evidence review job, #59 executes the hosted harness compatibility audit, #60 executes the hosted reference-set evaluation, #61 executes the hosted AI routing/cost review, #62 executes hosted team backlog routing, #63 publishes the hosted depth-plan check-run, and #64 dispatches hosted jobs from PR comments; next work is hosted result history/check-run summaries | Next implementation batch | | ECC Tools app | ECC-Tools PR evidence, billing audit, risk taxonomy, evaluator/RAG corpus | ECC-Tools #53 published the supply-chain workflow hardening branch, #54 tracks copy-ready PR drafts in the Linear/project backlog, #55 classifies analysis-depth readiness, #56 exposes the hosted execution plan, #57 executes the first hosted CI diagnostics job, #58 executes the hosted security evidence review job, #59 executes the hosted harness compatibility audit, #60 executes the hosted reference-set evaluation, and #61 executes the hosted AI routing/cost review; next work is the team backlog routing executor | Next implementation batch |
| Linear progress | Linear project status updates, `docs/architecture/progress-sync-contract.md`, and this mirror | Status update with queue/evidence/missing gates | Every significant merge batch | | Linear progress | Linear project status updates, `docs/architecture/progress-sync-contract.md`, and this mirror | Status update with queue/evidence/missing gates | Every significant merge batch |
The project status update should always include: The project status update should always include:
@@ -680,9 +629,10 @@ Acceptance:
PR #82 expanded corpus coverage for env proxy hijacks and out-of-band PR #82 expanded corpus coverage for env proxy hijacks and out-of-band
exfiltration; and ECC-Tools PRs #42/#43 now route and recognize evidence exfiltration; and ECC-Tools PRs #42/#43 now route and recognize evidence
packs. The next slice is hosted evidence-pack workflow depth. packs. The next slice is hosted evidence-pack workflow depth.
2. Feed the #66 status surface back into hosted depth-plan recommendations so 2. Extend the ECC-Tools hosted execution lane beyond #57's CI diagnostics,
queued analysis can suggest the next unrun or newly blocked hosted job from #58's security evidence review, #59's harness compatibility audit, and
cached outcomes, not only static readiness. #60's reference-set evaluation, and #61's AI routing/cost review into the
remaining depth-plan job: team backlog routing.
3. Enable/configure the merged Linear backlog sync path after workspace issue 3. Enable/configure the merged Linear backlog sync path after workspace issue
capacity clears or the Linear workspace is upgraded, then verify PR-draft capacity clears or the Linear workspace is upgraded, then verify PR-draft
salvage items land in the expected project. salvage items land in the expected project.
+14 -14
View File
@@ -122,12 +122,12 @@
git clone https://github.com/affaan-m/everything-claude-code.git git clone https://github.com/affaan-m/everything-claude-code.git
# 共通ルールをインストール(必須) # 共通ルールをインストール(必須)
cp -r everything-claude-code/rules/common/* ~/.claude/rules/ cp -r everything-claude-code/rules/common ~/.claude/rules/common
# 言語固有ルールをインストール(スタックを選択) # 言語固有ルールをインストール(スタックを選択)
cp -r everything-claude-code/rules/typescript/* ~/.claude/rules/ cp -r everything-claude-code/rules/typescript ~/.claude/rules/typescript
cp -r everything-claude-code/rules/python/* ~/.claude/rules/ cp -r everything-claude-code/rules/python ~/.claude/rules/python
cp -r everything-claude-code/rules/golang/* ~/.claude/rules/ cp -r everything-claude-code/rules/golang ~/.claude/rules/golang
``` ```
### ステップ3:使用開始 ### ステップ3:使用開始
@@ -462,15 +462,15 @@ Duplicate hook file detected: ./hooks/hooks.json is already resolved to a loaded
> >
> # オプション A:ユーザーレベルルール(すべてのプロジェクトに適用) > # オプション A:ユーザーレベルルール(すべてのプロジェクトに適用)
> mkdir -p ~/.claude/rules > mkdir -p ~/.claude/rules
> cp -r everything-claude-code/rules/common/* ~/.claude/rules/ > cp -r everything-claude-code/rules/common ~/.claude/rules/common
> cp -r everything-claude-code/rules/typescript/* ~/.claude/rules/ # スタックを選択 > cp -r everything-claude-code/rules/typescript ~/.claude/rules/typescript # スタックを選択
> cp -r everything-claude-code/rules/python/* ~/.claude/rules/ > cp -r everything-claude-code/rules/python ~/.claude/rules/python
> cp -r everything-claude-code/rules/golang/* ~/.claude/rules/ > cp -r everything-claude-code/rules/golang ~/.claude/rules/golang
> >
> # オプション B:プロジェクトレベルルール(現在のプロジェクトのみ) > # オプション B:プロジェクトレベルルール(現在のプロジェクトのみ)
> mkdir -p .claude/rules > mkdir -p .claude/rules
> cp -r everything-claude-code/rules/common/* .claude/rules/ > cp -r everything-claude-code/rules/common .claude/rules/common
> cp -r everything-claude-code/rules/typescript/* .claude/rules/ # スタックを選択 > cp -r everything-claude-code/rules/typescript .claude/rules/typescript # スタックを選択
> ``` > ```
--- ---
@@ -487,10 +487,10 @@ git clone https://github.com/affaan-m/everything-claude-code.git
cp everything-claude-code/agents/*.md ~/.claude/agents/ cp everything-claude-code/agents/*.md ~/.claude/agents/
# ルール(共通 + 言語固有)をコピー # ルール(共通 + 言語固有)をコピー
cp -r everything-claude-code/rules/common/* ~/.claude/rules/ cp -r everything-claude-code/rules/common ~/.claude/rules/common
cp -r everything-claude-code/rules/typescript/* ~/.claude/rules/ # スタックを選択 cp -r everything-claude-code/rules/typescript ~/.claude/rules/typescript # スタックを選択
cp -r everything-claude-code/rules/python/* ~/.claude/rules/ cp -r everything-claude-code/rules/python ~/.claude/rules/python
cp -r everything-claude-code/rules/golang/* ~/.claude/rules/ cp -r everything-claude-code/rules/golang ~/.claude/rules/golang
# コマンドをコピー # コマンドをコピー
cp everything-claude-code/commands/*.md ~/.claude/commands/ cp everything-claude-code/commands/*.md ~/.claude/commands/
+6 -6
View File
@@ -169,13 +169,13 @@ Options:
インストールを実行: インストールを実行:
```bash ```bash
# 共通ルールrules/ にフラットコピー) # 共通ルール
cp -r $ECC_ROOT/rules/common/* $TARGET/rules/ cp -r $ECC_ROOT/rules/common $TARGET/rules/common
# 言語固有のルール(rules/ にフラットコピー # 言語固有のルール(言語別ディレクトリを保持
cp -r $ECC_ROOT/rules/typescript/* $TARGET/rules/ # 選択された場合 cp -r $ECC_ROOT/rules/typescript $TARGET/rules/typescript # 選択された場合
cp -r $ECC_ROOT/rules/python/* $TARGET/rules/ # 選択された場合 cp -r $ECC_ROOT/rules/python $TARGET/rules/python # 選択された場合
cp -r $ECC_ROOT/rules/golang/* $TARGET/rules/ # 選択された場合 cp -r $ECC_ROOT/rules/golang $TARGET/rules/golang # 選択された場合
``` ```
**重要**: ユーザーが言語固有のルールを選択したが、共通ルールを選択しなかった場合、警告します: **重要**: ユーザーが言語固有のルールを選択したが、共通ルールを選択しなかった場合、警告します:
+6 -6
View File
@@ -387,12 +387,12 @@ Claude Code v2.1+는 설치된 플러그인의 `hooks/hooks.json`을 **자동으
> >
> # 옵션 A: 사용자 레벨 룰 (모든 프로젝트에 적용) > # 옵션 A: 사용자 레벨 룰 (모든 프로젝트에 적용)
> mkdir -p ~/.claude/rules > mkdir -p ~/.claude/rules
> cp -r everything-claude-code/rules/common/* ~/.claude/rules/ > cp -r everything-claude-code/rules/common ~/.claude/rules/common
> cp -r everything-claude-code/rules/typescript/* ~/.claude/rules/ # 사용하는 스택 선택 > cp -r everything-claude-code/rules/typescript ~/.claude/rules/typescript # 사용하는 스택 선택
> >
> # 옵션 B: 프로젝트 레벨 룰 (현재 프로젝트에만 적용) > # 옵션 B: 프로젝트 레벨 룰 (현재 프로젝트에만 적용)
> mkdir -p .claude/rules > mkdir -p .claude/rules
> cp -r everything-claude-code/rules/common/* .claude/rules/ > cp -r everything-claude-code/rules/common .claude/rules/common
> ``` > ```
--- ---
@@ -409,8 +409,8 @@ git clone https://github.com/affaan-m/everything-claude-code.git
cp everything-claude-code/agents/*.md ~/.claude/agents/ cp everything-claude-code/agents/*.md ~/.claude/agents/
# 룰 복사 (common + 언어별) # 룰 복사 (common + 언어별)
cp -r everything-claude-code/rules/common/* ~/.claude/rules/ cp -r everything-claude-code/rules/common ~/.claude/rules/common
cp -r everything-claude-code/rules/typescript/* ~/.claude/rules/ # 사용하는 스택 선택 cp -r everything-claude-code/rules/typescript ~/.claude/rules/typescript # 사용하는 스택 선택
# 커맨드 복사 # 커맨드 복사
cp everything-claude-code/commands/*.md ~/.claude/commands/ cp everything-claude-code/commands/*.md ~/.claude/commands/
@@ -573,7 +573,7 @@ MCP 서버가 너무 많으면 컨텍스트를 잡아먹습니다. 각 MCP 도
cp everything-claude-code/agents/*.md ~/.claude/agents/ cp everything-claude-code/agents/*.md ~/.claude/agents/
# 룰만 # 룰만
cp -r everything-claude-code/rules/common/* ~/.claude/rules/ cp -r everything-claude-code/rules/common ~/.claude/rules/common
``` ```
각 컴포넌트는 완전히 독립적입니다. 각 컴포넌트는 완전히 독립적입니다.
+5 -5
View File
@@ -342,12 +342,12 @@ Ou adicione diretamente ao seu `~/.claude/settings.json`:
> >
> # Opção A: Regras no nível do usuário (aplica a todos os projetos) > # Opção A: Regras no nível do usuário (aplica a todos os projetos)
> mkdir -p ~/.claude/rules > mkdir -p ~/.claude/rules
> cp -r everything-claude-code/rules/common/* ~/.claude/rules/ > cp -r everything-claude-code/rules/common ~/.claude/rules/common
> cp -r everything-claude-code/rules/typescript/* ~/.claude/rules/ # escolha sua stack > cp -r everything-claude-code/rules/typescript ~/.claude/rules/typescript # escolha sua stack
> >
> # Opção B: Regras no nível do projeto (aplica apenas ao projeto atual) > # Opção B: Regras no nível do projeto (aplica apenas ao projeto atual)
> mkdir -p .claude/rules > mkdir -p .claude/rules
> cp -r everything-claude-code/rules/common/* .claude/rules/ > cp -r everything-claude-code/rules/common .claude/rules/common
> ``` > ```
--- ---
@@ -362,8 +362,8 @@ git clone https://github.com/affaan-m/everything-claude-code.git
cp everything-claude-code/agents/*.md ~/.claude/agents/ cp everything-claude-code/agents/*.md ~/.claude/agents/
# Copiar regras (comuns + específicas da linguagem) # Copiar regras (comuns + específicas da linguagem)
cp -r everything-claude-code/rules/common/* ~/.claude/rules/ cp -r everything-claude-code/rules/common ~/.claude/rules/common
cp -r everything-claude-code/rules/typescript/* ~/.claude/rules/ cp -r everything-claude-code/rules/typescript ~/.claude/rules/typescript
# Copiar comandos # Copiar comandos
cp everything-claude-code/commands/*.md ~/.claude/commands/ cp everything-claude-code/commands/*.md ~/.claude/commands/
+1 -1
View File
@@ -390,7 +390,7 @@ Evet. Seçenek 2'yi (manuel kurulum) kullanın ve yalnızca ihtiyacınız olanı
cp everything-claude-code/agents/*.md ~/.claude/agents/ cp everything-claude-code/agents/*.md ~/.claude/agents/
# Sadece rule'lar # Sadece rule'lar
cp -r everything-claude-code/rules/common/* ~/.claude/rules/ cp -r everything-claude-code/rules/common ~/.claude/rules/common
``` ```
Her component tamamen bağımsızdır. Her component tamamen bağımsızdır.
+13 -13
View File
@@ -637,16 +637,16 @@ Claude Code v2.1+ **会自动加载** 任何已安装插件中的 `hooks/hooks.j
> >
> # 选项 A:用户级规则(适用于所有项目) > # 选项 A:用户级规则(适用于所有项目)
> mkdir -p ~/.claude/rules > mkdir -p ~/.claude/rules
> cp -r everything-claude-code/rules/common/* ~/.claude/rules/ > cp -r everything-claude-code/rules/common ~/.claude/rules/common
> cp -r everything-claude-code/rules/typescript/* ~/.claude/rules/ # 选择您的技术栈 > cp -r everything-claude-code/rules/typescript ~/.claude/rules/typescript # 选择您的技术栈
> cp -r everything-claude-code/rules/python/* ~/.claude/rules/ > cp -r everything-claude-code/rules/python ~/.claude/rules/python
> cp -r everything-claude-code/rules/golang/* ~/.claude/rules/ > cp -r everything-claude-code/rules/golang ~/.claude/rules/golang
> cp -r everything-claude-code/rules/php/* ~/.claude/rules/ > cp -r everything-claude-code/rules/php ~/.claude/rules/php
> >
> # 选项 B:项目级规则(仅适用于当前项目) > # 选项 B:项目级规则(仅适用于当前项目)
> mkdir -p .claude/rules > mkdir -p .claude/rules
> cp -r everything-claude-code/rules/common/* .claude/rules/ > cp -r everything-claude-code/rules/common .claude/rules/common
> cp -r everything-claude-code/rules/typescript/* .claude/rules/ # 选择您的技术栈 > cp -r everything-claude-code/rules/typescript .claude/rules/typescript # 选择您的技术栈
> ``` > ```
*** ***
@@ -663,11 +663,11 @@ git clone https://github.com/affaan-m/everything-claude-code.git
cp everything-claude-code/agents/*.md ~/.claude/agents/ cp everything-claude-code/agents/*.md ~/.claude/agents/
# Copy rules (common + language-specific) # Copy rules (common + language-specific)
cp -r everything-claude-code/rules/common/* ~/.claude/rules/ cp -r everything-claude-code/rules/common ~/.claude/rules/common
cp -r everything-claude-code/rules/typescript/* ~/.claude/rules/ # pick your stack cp -r everything-claude-code/rules/typescript ~/.claude/rules/typescript # pick your stack
cp -r everything-claude-code/rules/python/* ~/.claude/rules/ cp -r everything-claude-code/rules/python ~/.claude/rules/python
cp -r everything-claude-code/rules/golang/* ~/.claude/rules/ cp -r everything-claude-code/rules/golang ~/.claude/rules/golang
cp -r everything-claude-code/rules/php/* ~/.claude/rules/ cp -r everything-claude-code/rules/php ~/.claude/rules/php
# Copy maintained commands # Copy maintained commands
cp everything-claude-code/commands/*.md ~/.claude/commands/ cp everything-claude-code/commands/*.md ~/.claude/commands/
@@ -885,7 +885,7 @@ claude
cp everything-claude-code/agents/*.md ~/.claude/agents/ cp everything-claude-code/agents/*.md ~/.claude/agents/
# Just rules # Just rules
cp -r everything-claude-code/rules/common/* ~/.claude/rules/ cp -r everything-claude-code/rules/common ~/.claude/rules/common
``` ```
每个组件都是完全独立的。 每个组件都是完全独立的。
+6 -6
View File
@@ -239,13 +239,13 @@ cp -R "${src%/}" "$TARGET/skills/$(basename "${src%/}")"
执行安装: 执行安装:
```bash ```bash
# Common rules (flat copy into rules/) # Common rules
cp -r $ECC_ROOT/rules/common/* $TARGET/rules/ cp -r $ECC_ROOT/rules/common $TARGET/rules/common
# Language-specific rules (flat copy into rules/) # Language-specific rules (preserve per-language directories)
cp -r $ECC_ROOT/rules/typescript/* $TARGET/rules/ # if selected cp -r $ECC_ROOT/rules/typescript $TARGET/rules/typescript # if selected
cp -r $ECC_ROOT/rules/python/* $TARGET/rules/ # if selected cp -r $ECC_ROOT/rules/python $TARGET/rules/python # if selected
cp -r $ECC_ROOT/rules/golang/* $TARGET/rules/ # if selected cp -r $ECC_ROOT/rules/golang $TARGET/rules/golang # if selected
``` ```
**重要**:如果用户选择了任何特定语言的规则但**没有**选择通用规则,警告他们: **重要**:如果用户选择了任何特定语言的规则但**没有**选择通用规则,警告他们:
+11 -49
View File
@@ -4,10 +4,6 @@
const MAX_STDIN = 1024 * 1024; const MAX_STDIN = 1024 * 1024;
const path = require('path'); const path = require('path');
const { splitShellSegments } = require('../lib/shell-split'); const { splitShellSegments } = require('../lib/shell-split');
const {
extractCommandSubstitutions,
extractSubshellGroups
} = require('../lib/shell-substitution');
const DEV_COMMAND_WORDS = new Set([ const DEV_COMMAND_WORDS = new Set([
'npm', 'npm',
@@ -127,8 +123,6 @@ function getLeadingCommandWord(segment) {
continue; continue;
} }
if (token === '{' || token === '}') continue;
if (/^[A-Za-z_][A-Za-z0-9_]*=.*/.test(token)) continue; if (/^[A-Za-z_][A-Za-z0-9_]*=.*/.test(token)) continue;
const normalizedToken = normalizeCommandWord(token); const normalizedToken = normalizeCommandWord(token);
@@ -160,55 +154,23 @@ process.stdin.on('data', chunk => {
} }
}); });
const TMUX_LAUNCHER = /^\s*tmux\s+(new|new-session|new-window|split-window)\b/;
const DEV_PATTERN = /\b(npm\s+run\s+dev|pnpm(?:\s+run)?\s+dev|yarn(?:\s+run)?\s+dev|bun(?:\s+run)?\s+dev)\b/;
/**
* Collect every command-line segment we should evaluate. Returns the top-level
* segments first, then segments harvested from `$(...)` / backtick command
* substitutions and plain `(...)` subshell groups, recursively.
*
* Without this expansion the leading-command and dev-pattern check below only
* sees the outermost command, so wrappers like `$(npm run dev)` and
* `(npm run dev)` (which still spawn a dev server) sneak past.
*/
function collectCheckSegments(cmd) {
const segments = [...splitShellSegments(cmd)];
const queue = [cmd];
const seen = new Set();
while (queue.length) {
const current = queue.shift();
if (seen.has(current)) continue;
seen.add(current);
for (const body of extractCommandSubstitutions(current)) {
for (const seg of splitShellSegments(body)) segments.push(seg);
queue.push(body);
}
for (const body of extractSubshellGroups(current)) {
for (const seg of splitShellSegments(body)) segments.push(seg);
queue.push(body);
}
}
return segments;
}
function isBlockedDevSegment(segment) {
const commandWord = getLeadingCommandWord(segment);
if (!commandWord || !DEV_COMMAND_WORDS.has(commandWord)) return false;
return DEV_PATTERN.test(segment) && !TMUX_LAUNCHER.test(segment);
}
process.stdin.on('end', () => { process.stdin.on('end', () => {
try { try {
const input = JSON.parse(raw); const input = JSON.parse(raw);
const cmd = String(input.tool_input?.command || ''); const cmd = String(input.tool_input?.command || '');
if (process.platform !== 'win32') { if (process.platform !== 'win32') {
const segments = collectCheckSegments(cmd); const segments = splitShellSegments(cmd);
const hasBlockedDev = segments.some(isBlockedDevSegment); const tmuxLauncher = /^\s*tmux\s+(new|new-session|new-window|split-window)\b/;
const devPattern = /\b(npm\s+run\s+dev|pnpm(?:\s+run)?\s+dev|yarn\s+dev|bun\s+run\s+dev)\b/;
const hasBlockedDev = segments.some(segment => {
const commandWord = getLeadingCommandWord(segment);
if (!commandWord || !DEV_COMMAND_WORDS.has(commandWord)) {
return false;
}
return devPattern.test(segment) && !tmuxLauncher.test(segment);
});
if (hasBlockedDev) { if (hasBlockedDev) {
console.error('[Hook] BLOCKED: Dev server must run in tmux for log access'); console.error('[Hook] BLOCKED: Dev server must run in tmux for log access');
-246
View File
@@ -1,246 +0,0 @@
'use strict';
/**
* Extract executable command-substitution bodies from a shell line.
*
* Single quotes are literal, so substitutions inside them are ignored;
* double quotes still permit substitutions, so those bodies are scanned
* before quoted text is stripped. Returns each substitution body plus
* any nested substitutions discovered recursively.
*
* Originally introduced in scripts/hooks/gateguard-fact-force.js
* (PR #1853 round 2). Extracted to a shared lib so other PreToolUse
* hooks that need the same "scan inside `$(...)` and backticks"
* behavior can reuse it without duplicating the parser.
*
* @param {string} input
* @returns {string[]}
*/
function extractCommandSubstitutions(input) {
const source = String(input || '');
const substitutions = [];
let inSingle = false;
let inDouble = false;
for (let i = 0; i < source.length; i++) {
const ch = source[i];
const prev = source[i - 1];
if (ch === '\\' && !inSingle) {
i += 1;
continue;
}
if (ch === "'" && !inDouble && prev !== '\\') {
inSingle = !inSingle;
continue;
}
if (ch === '"' && !inSingle && prev !== '\\') {
inDouble = !inDouble;
continue;
}
if (inSingle) {
continue;
}
if (ch === '`') {
let body = '';
i += 1;
while (i < source.length) {
const inner = source[i];
if (inner === '\\') {
body += inner;
if (i + 1 < source.length) {
body += source[i + 1];
i += 2;
continue;
}
}
if (inner === '`') {
break;
}
body += inner;
i += 1;
}
if (body.trim()) {
substitutions.push(body);
substitutions.push(...extractCommandSubstitutions(body));
}
continue;
}
if (ch === '$' && source[i + 1] === '(') {
let depth = 1;
let body = '';
let bodyInSingle = false;
let bodyInDouble = false;
i += 2;
while (i < source.length && depth > 0) {
const inner = source[i];
const innerPrev = source[i - 1];
if (inner === '\\' && !bodyInSingle) {
body += inner;
if (i + 1 < source.length) {
body += source[i + 1];
i += 2;
continue;
}
}
if (inner === "'" && !bodyInDouble && innerPrev !== '\\') {
bodyInSingle = !bodyInSingle;
} else if (inner === '"' && !bodyInSingle && innerPrev !== '\\') {
bodyInDouble = !bodyInDouble;
} else if (!bodyInSingle && !bodyInDouble) {
if (inner === '(') {
depth += 1;
} else if (inner === ')') {
depth -= 1;
if (depth === 0) {
break;
}
}
}
body += inner;
i += 1;
}
if (body.trim()) {
substitutions.push(body);
substitutions.push(...extractCommandSubstitutions(body));
}
}
}
return substitutions;
}
/**
* Extract bodies of plain `(...)` subshell groups.
*
* Bash treats `(npm run dev)` as a subshell that executes its contents, but
* the regex-light segment splitters used by our PreToolUse hooks don't peer
* inside those parens. This helper finds top-level `(...)` groups (skipping
* `$(...)` command substitutions and backticks, which `extractCommandSubstitutions`
* already covers) and returns each body, recursing for nested groups.
*
* Quote semantics:
* - Single quotes are literal: `'( ... )'` is a string, not a subshell.
* - Double quotes are literal *for parens*: `"( ... )"` is a string too —
* bash only honors `$( )` inside double quotes, not bare `( )`.
*
* @param {string} input
* @returns {string[]}
*/
function extractSubshellGroups(input) {
const source = String(input || '');
const groups = [];
let inSingle = false;
let inDouble = false;
for (let i = 0; i < source.length; i++) {
const ch = source[i];
const prev = source[i - 1];
if (ch === '\\' && !inSingle) {
i += 1;
continue;
}
if (ch === "'" && !inDouble && prev !== '\\') {
inSingle = !inSingle;
continue;
}
if (ch === '"' && !inSingle && prev !== '\\') {
inDouble = !inDouble;
continue;
}
if (inSingle || inDouble) {
continue;
}
if (ch === '$' && source[i + 1] === '(') {
let depth = 1;
let skipInSingle = false;
let skipInDouble = false;
i += 2;
while (i < source.length && depth > 0) {
const inner = source[i];
const innerPrev = source[i - 1];
if (inner === '\\' && !skipInSingle) {
i += 2;
continue;
}
if (inner === "'" && !skipInDouble && innerPrev !== '\\') {
skipInSingle = !skipInSingle;
} else if (inner === '"' && !skipInSingle && innerPrev !== '\\') {
skipInDouble = !skipInDouble;
} else if (!skipInSingle && !skipInDouble) {
if (inner === '(') depth += 1;
else if (inner === ')') depth -= 1;
}
i += 1;
}
i -= 1;
continue;
}
if (ch === '`') {
i += 1;
while (i < source.length && source[i] !== '`') {
if (source[i] === '\\' && i + 1 < source.length) {
i += 2;
continue;
}
i += 1;
}
continue;
}
if (ch === '(') {
let depth = 1;
let body = '';
let bodyInSingle = false;
let bodyInDouble = false;
i += 1;
while (i < source.length && depth > 0) {
const inner = source[i];
const innerPrev = source[i - 1];
if (inner === '\\' && !bodyInSingle) {
body += inner;
if (i + 1 < source.length) {
body += source[i + 1];
i += 2;
continue;
}
}
if (inner === "'" && !bodyInDouble && innerPrev !== '\\') {
bodyInSingle = !bodyInSingle;
} else if (inner === '"' && !bodyInSingle && innerPrev !== '\\') {
bodyInDouble = !bodyInDouble;
} else if (!bodyInSingle && !bodyInDouble) {
if (inner === '(') {
depth += 1;
} else if (inner === ')') {
depth -= 1;
if (depth === 0) {
break;
}
}
}
body += inner;
i += 1;
}
if (body.trim()) {
groups.push(body);
groups.push(...extractSubshellGroups(body));
}
}
}
return groups;
}
module.exports = { extractCommandSubstitutions, extractSubshellGroups };
+6 -6
View File
@@ -234,13 +234,13 @@ Options:
Execute installation: Execute installation:
```bash ```bash
# Common rules (flat copy into rules/) # Common rules
cp -r $ECC_ROOT/rules/common/* $TARGET/rules/ cp -r $ECC_ROOT/rules/common $TARGET/rules/common
# Language-specific rules (flat copy into rules/) # Language-specific rules (preserve per-language directories)
cp -r $ECC_ROOT/rules/typescript/* $TARGET/rules/ # if selected cp -r $ECC_ROOT/rules/typescript $TARGET/rules/typescript # if selected
cp -r $ECC_ROOT/rules/python/* $TARGET/rules/ # if selected cp -r $ECC_ROOT/rules/python $TARGET/rules/python # if selected
cp -r $ECC_ROOT/rules/golang/* $TARGET/rules/ # if selected cp -r $ECC_ROOT/rules/golang $TARGET/rules/golang # if selected
``` ```
**Important**: If the user selects any language-specific rules but NOT common rules, warn them: **Important**: If the user selects any language-specific rules but NOT common rules, warn them:
@@ -89,110 +89,6 @@ function runTests() {
assert.strictEqual(result.code, 0, `Expected exit code 0, got ${result.code}`); assert.strictEqual(result.code, 0, `Expected exit code 0, got ${result.code}`);
}) ? passed++ : failed++); }) ? passed++ : failed++);
// --- Subshell bypass regression (issue: dev server slipped past via $(), ``, ()) ---
if (!isWindows) {
(test('blocks $(npm run dev) — command substitution', () => {
const result = runScript('$(npm run dev)');
assert.strictEqual(result.code, 2, `Expected exit code 2, got ${result.code}`);
assert.ok(result.stderr.includes('BLOCKED'), 'expected BLOCKED in stderr');
}) ? passed++ : failed++);
(test('blocks `npm run dev` — backtick substitution', () => {
const result = runScript('`npm run dev`');
assert.strictEqual(result.code, 2, `Expected exit code 2, got ${result.code}`);
}) ? passed++ : failed++);
(test('blocks echo $(npm run dev) — substitution nested in argument', () => {
const result = runScript('echo $(npm run dev)');
assert.strictEqual(result.code, 2, `Expected exit code 2, got ${result.code}`);
}) ? passed++ : failed++);
(test('blocks (npm run dev) — plain subshell group', () => {
const result = runScript('(npm run dev)');
assert.strictEqual(result.code, 2, `Expected exit code 2, got ${result.code}`);
}) ? passed++ : failed++);
(test('blocks $(echo a; npm run dev) — substitution with sequenced segments', () => {
const result = runScript('$(echo a; npm run dev)');
assert.strictEqual(result.code, 2, `Expected exit code 2, got ${result.code}`);
}) ? passed++ : failed++);
(test('blocks (pnpm dev) — plain subshell group with pnpm', () => {
const result = runScript('(pnpm dev)');
assert.strictEqual(result.code, 2, `Expected exit code 2, got ${result.code}`);
}) ? passed++ : failed++);
(test('allows tmux launcher inside subshell wrapping (exit code 0)', () => {
const result = runScript('(tmux new-session -d -s dev "npm run dev")');
assert.strictEqual(result.code, 0, `Expected exit code 0, got ${result.code}`);
}) ? passed++ : failed++);
(test('allows single-quoted "(npm run dev)" — literal string, not a subshell', () => {
const result = runScript("git commit -m '(npm run dev)'");
assert.strictEqual(result.code, 0, `Expected exit code 0, got ${result.code}`);
}) ? passed++ : failed++);
(test('allows double-quoted "(npm run dev)" — literal in double quotes (bash does not subshell)', () => {
const result = runScript('echo "(npm run dev)"');
assert.strictEqual(result.code, 0, `Expected exit code 0, got ${result.code}`);
}) ? passed++ : failed++);
(test("allows single-quoted '$(npm run dev)' — literal string, no substitution", () => {
const result = runScript("git commit -m '$(npm run dev) fix'");
assert.strictEqual(result.code, 0, `Expected exit code 0, got ${result.code}`);
}) ? passed++ : failed++);
}
// --- Round 1 review fixes (Greptile + CodeRabbit on PR #1889) ---
if (!isWindows) {
(test('blocks $(echo ")"; (npm run dev)) — quoted ) does not terminate $() early', () => {
const result = runScript('$(echo ")"; (npm run dev))');
assert.strictEqual(result.code, 2, `Expected exit code 2, got ${result.code}`);
}) ? passed++ : failed++);
(test('blocks (echo ")"; npm run dev) — quoted ) does not terminate (...) early', () => {
const result = runScript('(echo ")"; npm run dev)');
assert.strictEqual(result.code, 2, `Expected exit code 2, got ${result.code}`);
}) ? passed++ : failed++);
(test('allows $(echo "(npm run dev)") — () inside double-quoted substitution body is literal', () => {
const result = runScript('$(echo "(npm run dev)")');
assert.strictEqual(result.code, 0, `Expected exit code 0, got ${result.code}`);
}) ? passed++ : failed++);
(test('blocks { npm run dev; } — brace group runs in current shell', () => {
const result = runScript('{ npm run dev; }');
assert.strictEqual(result.code, 2, `Expected exit code 2, got ${result.code}`);
}) ? passed++ : failed++);
(test('blocks echo hi && { npm run dev; } — brace group after &&', () => {
const result = runScript('echo hi && { npm run dev; }');
assert.strictEqual(result.code, 2, `Expected exit code 2, got ${result.code}`);
}) ? passed++ : failed++);
(test('allows {npm run dev} — bash requires space after { to form a group', () => {
const result = runScript('{npm run dev}');
assert.strictEqual(result.code, 0, `Expected exit code 0, got ${result.code}`);
}) ? passed++ : failed++);
(test('blocks yarn run dev — yarn 1.x convention', () => {
const result = runScript('yarn run dev');
assert.strictEqual(result.code, 2, `Expected exit code 2, got ${result.code}`);
}) ? passed++ : failed++);
(test('blocks bun dev — bun bare form', () => {
const result = runScript('bun dev');
assert.strictEqual(result.code, 2, `Expected exit code 2, got ${result.code}`);
}) ? passed++ : failed++);
(test('blocks "$(npm run dev)" — double-quoted substitution still substitutes', () => {
const result = runScript('echo "$(npm run dev)"');
assert.strictEqual(result.code, 2, `Expected exit code 2, got ${result.code}`);
}) ? passed++ : failed++);
}
// --- Edge cases --- // --- Edge cases ---
(test('empty/invalid input passes through (exit code 0)', () => { (test('empty/invalid input passes through (exit code 0)', () => {