claude-code-arcane 2.10.0 → 2.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/README.md +8 -8
- package/dist/cli.js +15 -0
- package/docs/SKILLS-CATALOG.md +4 -2
- package/docs/USER-GUIDE.md +1 -1
- package/docs/templates/skill-test-spec.md +0 -1
- package/package.json +1 -1
- package/profiles/backend-dotnet.yaml +2 -0
- package/profiles/backend-go.yaml +2 -0
- package/profiles/backend-nestjs.yaml +2 -0
- package/profiles/backend-nextjs.yaml +2 -0
- package/profiles/backend-ts.yaml +2 -0
- package/profiles/backend-typescript.yaml +2 -0
- package/profiles/blender.yaml +1 -0
- package/profiles/infra.yaml +2 -0
- package/profiles/meshy.yaml +1 -0
- package/rules/blender-files.md +72 -0
- package/rules/blender-pipeline.md +1 -63
- package/rules/gamedev/narrative.md +1 -1
- package/rules/meshy-assets.md +9 -78
- package/rules/meshy-files.md +83 -0
- package/skills/agent-protocol/SKILL.md +1 -1
- package/skills/agent-protocol/references/communication-standard.md +2 -2
- package/skills/ai-security/SKILL.md +4 -0
- package/skills/audit-dev/SKILL.md +1 -1
- package/skills/blender-animation/SKILL.md +1 -1
- package/skills/blender-export/SKILL.md +1 -1
- package/skills/blender-materials/SKILL.md +1 -1
- package/skills/blender-modeling/SKILL.md +1 -1
- package/skills/check/SKILL.md +1 -1
- package/skills/chief-of-staff/SKILL.md +1 -1
- package/skills/cloud-security/SKILL.md +4 -0
- package/skills/isms-audit-expert/SKILL.md +2 -0
- package/skills/meshy-derive/SKILL.md +1 -1
- package/skills/meshy-generate/SKILL.md +1 -1
- package/skills/meshy-setup/SKILL.md +1 -1
- package/skills/owasp-top10-check/SKILL.md +1 -1
- package/skills/qms-audit-expert/SKILL.md +2 -0
- package/skills/security-pen-testing/SKILL.md +1 -1
- package/skills/seo-audit/SKILL.md +1 -1
- package/skills/skill-auditor/SKILL.md +0 -1
- package/skills/skill-improve/SKILL.md +6 -7
- package/skills/skill-test/SKILL.md +3 -3
- package/skills/skill-test/references/static-checks.md +13 -8
- package/skills/standup-report/SKILL.md +1 -1
- package/skills/vn-gdd/SKILL.md +2 -0
- package/skills/web-security/SKILL.md +4 -0
- package/skills/worktree-isolation/README.md +6 -6
- package/skills/worktree-isolation/SKILL.md +5 -2
- package/skills/worktree-isolation-setup/README.md +7 -11
- package/skills/worktree-isolation-setup/SKILL.md +15 -6
- package/skills/worktree-isolation-setup/scripts/apply.py +0 -178
- package/skills/worktree-isolation-setup/scripts/install_hook.py +0 -118
- package/skills/worktree-isolation-setup/scripts/lib.py +0 -371
package/skills/check/SKILL.md
CHANGED
|
@@ -17,6 +17,6 @@ Run a comprehensive code quality and security check on the current project:
|
|
|
17
17
|
- Hardcoded secrets, API keys, tokens in source code
|
|
18
18
|
- Known vulnerable dependencies (npm audit, pip audit, etc.)
|
|
19
19
|
- SQL injection, XSS, or command injection patterns
|
|
20
|
-
6. **Report** — Summarize findings with severity levels and suggested fixes
|
|
20
|
+
6. **Report** — Summarize findings with severity levels and suggested fixes, then close with a verdict: **FAIL** if tests or type checks fail, or a secret or critical vulnerability turned up; **CONCERNS** if only lint issues or lower-severity findings remain; **PASS** if nothing actionable came up
|
|
21
21
|
|
|
22
22
|
Focus on actionable issues, not style nitpicks.
|
|
@@ -59,7 +59,7 @@ Before delivering ANY output to the founder:
|
|
|
59
59
|
- Company context loaded (not generic advice)
|
|
60
60
|
- Actions have owners and deadlines
|
|
61
61
|
- Conflicts named, not smoothed
|
|
62
|
-
-
|
|
62
|
+
- About 5 bullets per section, ranked by impact; a critical finding is never dropped to fit
|
|
63
63
|
|
|
64
64
|
## Ecosystem Awareness
|
|
65
65
|
|
|
@@ -73,6 +73,10 @@ Full escalation combos, severity guide, and least privilege recommendations: `re
|
|
|
73
73
|
|
|
74
74
|
Catch misconfigurations at definition time in Terraform, CloudFormation, Kubernetes manifests, and Helm charts. Integrate into CI/CD as a pre-apply gate.
|
|
75
75
|
|
|
76
|
+
### Step 6: Verdict
|
|
77
|
+
|
|
78
|
+
**Verdict:** **FAIL** if any finding is Critical or High; **CONCERNS** if only Medium or Low findings remain; **PASS** if nothing actionable turned up. Apply the severity modifier first: an internet-facing or regulated-data resource raises the finding's severity before the verdict is taken.
|
|
79
|
+
|
|
76
80
|
---
|
|
77
81
|
|
|
78
82
|
## Cloud Provider Coverage
|
|
@@ -54,6 +54,8 @@ For detailed control testing procedures by Annex A control, see [references/secu
|
|
|
54
54
|
| Minor Nonconformity | Isolated deviation with limited impact | 90 days |
|
|
55
55
|
| Observation | Improvement opportunity | Next audit cycle |
|
|
56
56
|
|
|
57
|
+
**Audit conclusion:** **CONFORMING** (observations at most), **MINOR NONCONFORMITIES** (minor only), or **MAJOR NONCONFORMITY** (at least one major, which blocks a certification recommendation until it is corrected).
|
|
58
|
+
|
|
57
59
|
### Corrective Action Workflow
|
|
58
60
|
|
|
59
61
|
1. Auditee acknowledges finding
|
|
@@ -116,4 +116,4 @@ Reportar: targets generados, creditos gastados reales (delta de `check_balance`)
|
|
|
116
116
|
|
|
117
117
|
---
|
|
118
118
|
|
|
119
|
-
> Presupuestos, estructura de `targets
|
|
119
|
+
> Presupuestos, estructura de `targets/` y formato del ledger: `.claude/rules/meshy-files.md`. Tabla de creditos completa: `.claude/rules/meshy-assets.md`.
|
|
@@ -115,4 +115,4 @@ Reportar:
|
|
|
115
115
|
|
|
116
116
|
---
|
|
117
117
|
|
|
118
|
-
> Tabla de creditos completa, reglas de gasto, formato del ledger y convenciones de ejes/escala: `.claude/rules/meshy-assets.md`.
|
|
118
|
+
> Tabla de creditos completa, reglas de gasto, formato del ledger y convenciones de ejes/escala: `.claude/rules/meshy-assets.md` y `.claude/rules/meshy-files.md`. Leerlas antes de la Phase 3.
|
|
@@ -113,4 +113,4 @@ Reportar:
|
|
|
113
113
|
|
|
114
114
|
---
|
|
115
115
|
|
|
116
|
-
> Las reglas de gasto, estructura de `assets/3d/`, ledger `meshy.json` y tabla de derivados estan en `.claude/rules/meshy-assets.md`. Leerlas antes de cualquier operacion que gaste creditos.
|
|
116
|
+
> Las reglas de gasto, estructura de `assets/3d/`, ledger `meshy.json` y tabla de derivados estan en `.claude/rules/meshy-assets.md` y `.claude/rules/meshy-files.md`. Leerlas antes de cualquier operacion que gaste creditos.
|
|
@@ -86,7 +86,7 @@ Auditoría contra OWASP Top 10 2021. Go backend + TS/React frontend. Datos de me
|
|
|
86
86
|
|
|
87
87
|
## Reporte Output
|
|
88
88
|
|
|
89
|
-
Formato: Resumen ejecutivo (hallazgos por severidad) → Hallazgos por categoría (archivo:línea, descripción, PoC, remediación, ticket Jira) → Plan priorizado → Herramientas ejecutadas.
|
|
89
|
+
Formato: Resumen ejecutivo (hallazgos por severidad y veredicto: **FAIL** si hay algún hallazgo Critical o High, **CONCERNS** si quedan solo Medium o Low, **PASS** si no hay nada accionable) → Hallazgos por categoría (archivo:línea, descripción, PoC, remediación, ticket Jira) → Plan priorizado → Herramientas ejecutadas.
|
|
90
90
|
|
|
91
91
|
## Educabot Specifics
|
|
92
92
|
|
|
@@ -63,6 +63,8 @@ Gap: [How evidence fails to meet requirement]
|
|
|
63
63
|
| Minor | Isolated lapse or partial implementation | Recommended | 60 days |
|
|
64
64
|
| Observation | Improvement opportunity | Optional | As appropriate |
|
|
65
65
|
|
|
66
|
+
**Audit conclusion:** **CONFORMING** (observations at most), **MINOR NONCONFORMITIES** (minor only), or **MAJOR NONCONFORMITY** (at least one major, which blocks a certification recommendation until it is corrected).
|
|
67
|
+
|
|
66
68
|
### Corrective Action Integration
|
|
67
69
|
|
|
68
70
|
| Severity | CAPA Depth | Verification |
|
|
@@ -74,7 +74,7 @@ Key tests: XSS (reflected, stored, DOM-based), CSRF (token replay, SameSite), SQ
|
|
|
74
74
|
python scripts/pentest_report_generator.py --findings findings.json --format md --output report.md
|
|
75
75
|
```
|
|
76
76
|
|
|
77
|
-
Report structure: executive summary, scope, methodology, findings table (by severity/CVSS), detailed findings with evidence and remediation, priority matrix.
|
|
77
|
+
Report structure: executive summary with a verdict (**FAIL** if any finding is Critical or High, **CONCERNS** if only Medium or Low remain, **PASS** if nothing actionable turned up), scope, methodology, findings table (by severity/CVSS), detailed findings with evidence and remediation, priority matrix.
|
|
78
78
|
|
|
79
79
|
Responsible disclosure timeline and templates: `references/responsible_disclosure.md`
|
|
80
80
|
|
|
@@ -43,7 +43,7 @@ Before auditing, understand:
|
|
|
43
43
|
### Audit Report Structure
|
|
44
44
|
|
|
45
45
|
**Executive Summary**
|
|
46
|
-
- Overall health
|
|
46
|
+
- Overall health: **HEALTHY** (no critical or high-impact issues), **NEEDS WORK** (high-impact issues, nothing blocking), or **CRITICAL** (something blocks indexation or ranking)
|
|
47
47
|
- Top 3-5 priority issues
|
|
48
48
|
- Quick wins identified
|
|
49
49
|
|
|
@@ -68,7 +68,6 @@ Scan the body for required elements:
|
|
|
68
68
|
|
|
69
69
|
- **Sections**: At least 2 phase headings (`## Phase`, `## Step`, `## Workflow`, or `###` subsections)
|
|
70
70
|
- **Verdict keywords**: For review/analysis skills: APPROVED, PASS, FAIL, NEEDS REVISION (or equivalent)
|
|
71
|
-
- **Collaborative protocol**: For file-modifying skills (Write/Edit in allowed-tools): must contain "May I write" or equivalent approval gate
|
|
72
71
|
- **Next-step handoff**: Last section should guide what to do after the skill completes
|
|
73
72
|
|
|
74
73
|
### 1.4 Detect hallucinations
|
|
@@ -17,7 +17,7 @@ Read skill name from first arg. Verify `skills/[name]/SKILL.md` exists. If missi
|
|
|
17
17
|
|
|
18
18
|
## Phase 2: Baseline Test
|
|
19
19
|
|
|
20
|
-
Run `/skill-test static [name]`. Record FAILs, WARNs, which checks failed (1-
|
|
20
|
+
Run `/skill-test static [name]`. Record FAILs, WARNs, which checks failed (1-6).
|
|
21
21
|
|
|
22
22
|
### Phase 2b: Category Baseline
|
|
23
23
|
|
|
@@ -30,12 +30,11 @@ Read full skill file. For each failing/warning check, identify exact gap:
|
|
|
30
30
|
| Check | Gap if failing |
|
|
31
31
|
|-------|---------------|
|
|
32
32
|
| 1 | Missing frontmatter field |
|
|
33
|
-
| 2 |
|
|
34
|
-
| 3 |
|
|
35
|
-
| 4 |
|
|
36
|
-
| 5 (warn) |
|
|
37
|
-
| 6 (warn) |
|
|
38
|
-
| 7 (warn) | argument-hint empty or mismatched with modes |
|
|
33
|
+
| 2 | Over 40 lines with fewer than two `##` sections |
|
|
34
|
+
| 3 | A value from the catalog's `verdict:` list missing from the skill |
|
|
35
|
+
| 4 (warn) | No follow-up/next-step section |
|
|
36
|
+
| 5 (warn) | `context: fork` with <5 phases |
|
|
37
|
+
| 6 (warn) | argument-hint mismatched with modes |
|
|
39
38
|
|
|
40
39
|
For category checks: identify text gaps (e.g., G2: missing director prompts, A2: no per-section May-I-write, T3: BLOCKED not surfaced). Show full diagnosis before proposing changes.
|
|
41
40
|
|
|
@@ -15,18 +15,18 @@ Validates `skills/*/SKILL.md` for structural compliance and behavioral correctne
|
|
|
15
15
|
|
|
16
16
|
| Mode | Command | Purpose | Cost |
|
|
17
17
|
|------|---------|---------|------|
|
|
18
|
-
| `static` | `/skill-test static [name\|all]` |
|
|
18
|
+
| `static` | `/skill-test static [name\|all]` | 6 structural checks per skill | Low (~1k/skill) |
|
|
19
19
|
| `spec` | `/skill-test spec [name]` | Behavioral assertions from test spec | Medium (~5k/skill) |
|
|
20
20
|
| `category` | `/skill-test category [name\|all]` | Category-specific rubric metrics | Low (~2k/skill) |
|
|
21
21
|
| `audit` | `/skill-test audit` | Coverage report — skills, agents, test dates | Low (~3k total) |
|
|
22
22
|
|
|
23
23
|
## Phase 1: Parse Arguments
|
|
24
24
|
|
|
25
|
-
`static [name]` →
|
|
25
|
+
`static [name]` → 6 checks on one skill. `static all` → all skills (Glob `skills/*/SKILL.md`). `spec [name]` → read skill + test spec, evaluate assertions. `category [name|all]` → category rubric from `skills-selftest/quality-rubric.md`. `audit` (or no arg) → read catalog, list all, show coverage. Missing/unrecognized → output usage and stop.
|
|
26
26
|
|
|
27
27
|
## Phase 2A: Static Mode
|
|
28
28
|
|
|
29
|
-
> → Read references/static-checks.md for the
|
|
29
|
+
> → Read references/static-checks.md for the 6 structural validation checks and verdict criteria
|
|
30
30
|
|
|
31
31
|
## Phase 2B: Spec Mode
|
|
32
32
|
|
|
@@ -1,13 +1,18 @@
|
|
|
1
|
-
# Static Checks —
|
|
1
|
+
# Static Checks — 6 Structural Validations
|
|
2
|
+
|
|
3
|
+
Checks 1-3 are also enforced in CI by `src/__tests__/skill-static.test.ts`, so in this repo a skill that fails them never merges. Apply them here anyway: the skill may be running in a project with its own skills, where no test covers them.
|
|
2
4
|
|
|
3
5
|
| Check | What | Verdict |
|
|
4
6
|
|-------|------|---------|
|
|
5
|
-
| 1 — Frontmatter | `name
|
|
6
|
-
| 2 —
|
|
7
|
-
| 3 — Verdict
|
|
8
|
-
| 4 —
|
|
9
|
-
| 5 —
|
|
10
|
-
| 6 —
|
|
11
|
-
|
|
7
|
+
| 1 — Frontmatter | `name` (matching the directory), `description`, `argument-hint`, `user-invocable`, `allowed-tools` present; an empty `argument-hint` still counts as present | FAIL if any absent |
|
|
8
|
+
| 2 — Sections | A skill longer than 40 lines has at least two `##` sections. Shorter skills are exempt | FAIL if longer than 40 lines with fewer than two |
|
|
9
|
+
| 3 — Verdict | Only for skills that judge something: those with `verdict:` in `skills-selftest/catalog.yaml`. Every value listed there appears in the skill (SKILL.md or `references/`), in the skill's own vocabulary. Skills that build, write or advise do not need a verdict | FAIL if a listed value is missing |
|
|
10
|
+
| 4 — Next-Step Handoff | Final section mentions another skill, "next step", or follow-up | WARN if absent |
|
|
11
|
+
| 5 — Fork Complexity | If `context: fork`, must have >=5 phase headings | WARN if <5 |
|
|
12
|
+
| 6 — Argument Hint | Documented modes should match the hint | WARN if mismatch |
|
|
13
|
+
|
|
14
|
+
A new skill that judges something gets a `verdict:` list in the catalog when it is added; that is what makes check 3 apply to it.
|
|
15
|
+
|
|
16
|
+
There is no check for ask-before-write language. Whether Claude may write without asking is set by the permission mode of each session, not by the skill, so a skill with `Write` or `Edit` is not non-compliant for leaving the decision there.
|
|
12
17
|
|
|
13
18
|
**Output:** per-skill table of check results + verdict (COMPLIANT / WARNINGS / NON-COMPLIANT). For `static all`: summary table + aggregate counts.
|
|
@@ -48,4 +48,4 @@ Flujo: detectar team/proyecto → pull data en paralelo (git, ClickUp, Jira, Git
|
|
|
48
48
|
- NO incluir contenido sensible (PII, passwords, secrets)
|
|
49
49
|
- Grouping lógico: mergear commits del mismo ticket
|
|
50
50
|
- Sugerencias "hoy" basadas en tickets In Progress + priorities
|
|
51
|
-
-
|
|
51
|
+
- Unos 5 bullets por sección, ordenados por impacto, y el resto colapsado. Un blocker nunca se colapsa para respetar el número
|
package/skills/vn-gdd/SKILL.md
CHANGED
|
@@ -82,6 +82,10 @@ HSTS rollout: start with short `max-age` (300s), escalate to 2 years, then submi
|
|
|
82
82
|
- **Threat modeling**: complex trust boundaries need STRIDE before implementation
|
|
83
83
|
- **CSP breaks prod**: revert to report-only immediately; analyze before re-enforcing
|
|
84
84
|
|
|
85
|
+
## Verdict
|
|
86
|
+
|
|
87
|
+
**Verdict:** **FAIL** if any finding is Critical or High; **CONCERNS** if only Medium or Low findings remain; **PASS** if nothing actionable turned up.
|
|
88
|
+
|
|
85
89
|
## Checklist
|
|
86
90
|
|
|
87
91
|
- [ ] All required security headers present and returning correct values (target A+ on securityheaders.com)
|
|
@@ -8,22 +8,22 @@ This README explains **how worktree isolation works under the hood**. For usage,
|
|
|
8
8
|
|
|
9
9
|
## Install
|
|
10
10
|
|
|
11
|
+
Ships with the `infra` and backend profiles. Elsewhere:
|
|
12
|
+
|
|
11
13
|
```bash
|
|
12
|
-
npx
|
|
14
|
+
npx claude-code-arcane add worktree-isolation
|
|
13
15
|
```
|
|
14
16
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
After install, invoke with phrases like:
|
|
17
|
+
Then invoke with phrases like:
|
|
18
18
|
|
|
19
19
|
- `isolate worktree`
|
|
20
20
|
- `regenerate worktree ports`
|
|
21
21
|
- `which ports is this worktree using?`
|
|
22
22
|
|
|
23
|
-
If you also want
|
|
23
|
+
If you also want it to run automatically on every Claude Code session start, install the SessionStart hook once per machine:
|
|
24
24
|
|
|
25
25
|
```bash
|
|
26
|
-
npx
|
|
26
|
+
npx claude-code-arcane global
|
|
27
27
|
```
|
|
28
28
|
|
|
29
29
|
---
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: worktree-isolation
|
|
3
|
-
description:
|
|
3
|
+
description: "Regenerate or show this worktree's Docker ports (.env.worktree + compose overrides) so parallel worktrees don't collide. Leaves repo files alone; to prepare a repo once, use worktree-isolation-setup."
|
|
4
|
+
argument-hint: "[apply | status]"
|
|
5
|
+
user-invocable: true
|
|
6
|
+
allowed-tools: Read, Glob, Grep, Bash
|
|
4
7
|
---
|
|
5
8
|
|
|
6
9
|
# Worktree Isolation — On-Demand
|
|
@@ -81,7 +84,7 @@ This skill does not auto-rewrite `CLAUDE.md` or scripts (zero-touch on project f
|
|
|
81
84
|
|
|
82
85
|
## Out of scope
|
|
83
86
|
|
|
84
|
-
- Does not install the SessionStart hook
|
|
87
|
+
- Does not install the SessionStart hook. `npx claude-code-arcane global` does that, once per machine.
|
|
85
88
|
- Does not modify the repo's compose files / `CLAUDE.md` / `.gitignore`. Use [`worktree-isolation-setup`](../worktree-isolation-setup/) for that.
|
|
86
89
|
- Does not clean up orphan stacks from deleted worktrees. For now, `docker compose ls` and `docker compose -p <project-name> down -v` manually.
|
|
87
90
|
- Does not handle non-docker dev servers (Next.js, uvicorn directly on host).
|
|
@@ -8,13 +8,13 @@ This README explains **what setup does and why**. For step-by-step instructions,
|
|
|
8
8
|
|
|
9
9
|
## Install
|
|
10
10
|
|
|
11
|
+
Ships with the `infra` and backend profiles, next to `worktree-isolation`. Elsewhere:
|
|
12
|
+
|
|
11
13
|
```bash
|
|
12
|
-
npx
|
|
14
|
+
npx claude-code-arcane add worktree-isolation-setup
|
|
13
15
|
```
|
|
14
16
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
After install, run the skill once per repo:
|
|
17
|
+
Then run the skill once per repo:
|
|
18
18
|
|
|
19
19
|
```
|
|
20
20
|
setup worktree isolation in this project
|
|
@@ -80,7 +80,7 @@ After setup, both work in parallel.
|
|
|
80
80
|
│ │
|
|
81
81
|
│ user → "setup worktree isolation in this project" │
|
|
82
82
|
│ → this skill runs │
|
|
83
|
-
│ ├─
|
|
83
|
+
│ ├─ arcane global (one-time per machine; idempotent) │
|
|
84
84
|
│ ├─ rewrites compose files (port + container_name params) │
|
|
85
85
|
│ ├─ updates .gitignore │
|
|
86
86
|
│ └─ amends CLAUDE.md │
|
|
@@ -127,11 +127,7 @@ For deep-dive details on how the runtime script works (port allocation, override
|
|
|
127
127
|
```
|
|
128
128
|
skills/worktree-isolation-setup/
|
|
129
129
|
├── SKILL.md # entry point — step-by-step setup procedure
|
|
130
|
-
|
|
131
|
-
└── scripts/
|
|
132
|
-
├── install_hook.py # idempotent installer for the hook + scripts
|
|
133
|
-
├── apply.py # copied into ~/.claude/scripts/ by install_hook.py
|
|
134
|
-
└── lib.py # ditto
|
|
130
|
+
└── README.md # this file
|
|
135
131
|
```
|
|
136
132
|
|
|
137
|
-
|
|
133
|
+
This skill has no scripts of its own. The runtime scripts live in [`worktree-isolation`](../worktree-isolation/scripts/), and `npx claude-code-arcane global` copies them from there into `~/.claude/scripts/`.
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: worktree-isolation-setup
|
|
3
|
-
description:
|
|
3
|
+
description: "Prepare a repo once for parallel worktrees: parameterize docker-compose ports and container names, update .gitignore and CLAUDE.md, install the SessionStart hook. Edits repo files; to regenerate or show ports, use worktree-isolation."
|
|
4
|
+
argument-hint: ""
|
|
5
|
+
user-invocable: true
|
|
6
|
+
allowed-tools: Read, Glob, Grep, Bash, Edit
|
|
4
7
|
---
|
|
5
8
|
|
|
6
9
|
# Worktree Isolation — Setup (one-time)
|
|
@@ -20,17 +23,23 @@ For an in-depth explanation of how isolation works (hook lifecycle, override gen
|
|
|
20
23
|
|
|
21
24
|
## Step 1 — Ensure the global hook is installed
|
|
22
25
|
|
|
23
|
-
|
|
26
|
+
The hook is per machine, so check first:
|
|
24
27
|
|
|
25
28
|
```bash
|
|
26
|
-
|
|
29
|
+
npx claude-code-arcane global --status
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
If the SessionStart hook is not active, install it. It is idempotent — safe to re-run:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npx claude-code-arcane global
|
|
27
36
|
```
|
|
28
37
|
|
|
29
38
|
What it does:
|
|
30
|
-
1. Copies `
|
|
31
|
-
2. Adds
|
|
39
|
+
1. Copies `apply.py` + `lib.py` into `~/.claude/scripts/worktree-isolation/`
|
|
40
|
+
2. Adds a `SessionStart` hook in `~/.claude/settings.json` that invokes `~/.claude/scripts/worktree-isolation/apply.py --quiet`
|
|
32
41
|
|
|
33
|
-
|
|
42
|
+
It refuses to touch a malformed `settings.json`; if it stops there, tell the user and continue with Step 2 — the repo changes do not depend on the hook.
|
|
34
43
|
|
|
35
44
|
---
|
|
36
45
|
|
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env -S uv run --script --quiet
|
|
2
|
-
# /// script
|
|
3
|
-
# requires-python = ">=3.11"
|
|
4
|
-
# dependencies = ["pyyaml"]
|
|
5
|
-
# ///
|
|
6
|
-
"""Worktree isolation entry point.
|
|
7
|
-
|
|
8
|
-
Two callers:
|
|
9
|
-
1. Claude Code SessionStart hook → `apply.py --quiet` (emits hook JSON).
|
|
10
|
-
2. worktree-isolation skill → `apply.py --verbose --force` or `--status`.
|
|
11
|
-
|
|
12
|
-
Reads the project's docker-compose*.yml files, generates per-worktree override
|
|
13
|
-
files (sibling .worktree.yml) with deterministic randomized host ports + suffixed
|
|
14
|
-
container_names, writes .env.worktree, and registers the generated files in the
|
|
15
|
-
per-worktree git exclude list.
|
|
16
|
-
"""
|
|
17
|
-
|
|
18
|
-
from __future__ import annotations
|
|
19
|
-
|
|
20
|
-
import argparse
|
|
21
|
-
import json
|
|
22
|
-
import sys
|
|
23
|
-
from pathlib import Path
|
|
24
|
-
|
|
25
|
-
sys.path.insert(0, str(Path(__file__).parent))
|
|
26
|
-
|
|
27
|
-
import yaml # noqa: E402
|
|
28
|
-
|
|
29
|
-
from lib import ( # noqa: E402
|
|
30
|
-
PortMapping,
|
|
31
|
-
collect_container_names,
|
|
32
|
-
collect_port_mappings,
|
|
33
|
-
ensure_git_exclude,
|
|
34
|
-
find_compose_files,
|
|
35
|
-
overrides_up_to_date,
|
|
36
|
-
override_path_for,
|
|
37
|
-
render_env_worktree,
|
|
38
|
-
render_override_yaml,
|
|
39
|
-
worktree_id,
|
|
40
|
-
)
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
def _build_summary(
|
|
44
|
-
project_name: str,
|
|
45
|
-
worktree: str,
|
|
46
|
-
compose_chain: list[tuple[Path, Path | None]],
|
|
47
|
-
mappings: list[PortMapping],
|
|
48
|
-
) -> str:
|
|
49
|
-
lines = [
|
|
50
|
-
f"Worktree isolation active: project='{project_name}' (id={worktree}).",
|
|
51
|
-
"",
|
|
52
|
-
"Port mappings (legacy → worktree host):",
|
|
53
|
-
]
|
|
54
|
-
for m in sorted(mappings, key=lambda x: (x.service, x.container_port)):
|
|
55
|
-
lines.append(
|
|
56
|
-
f" {m.service} container :{m.container_port} → host {m.new_host_port} "
|
|
57
|
-
f"(was {m.original_host_port})"
|
|
58
|
-
)
|
|
59
|
-
lines += [
|
|
60
|
-
"",
|
|
61
|
-
"To bring up the stack from this worktree:",
|
|
62
|
-
" set -a; source .env.worktree; set +a",
|
|
63
|
-
" docker compose up -d",
|
|
64
|
-
"(COMPOSE_FILE in .env.worktree auto-chains base + override files.)",
|
|
65
|
-
"",
|
|
66
|
-
"When running ad-hoc commands (e.g. test commands in CLAUDE.md) that hardcode",
|
|
67
|
-
"legacy host ports like " + ", ".join(sorted({str(m.original_host_port) for m in mappings}))
|
|
68
|
-
+ ", substitute the matching new host port from the table above before executing.",
|
|
69
|
-
]
|
|
70
|
-
return "\n".join(lines)
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
def _run(args: argparse.Namespace) -> int:
|
|
74
|
-
cwd = args.cwd.resolve()
|
|
75
|
-
|
|
76
|
-
if args.status:
|
|
77
|
-
env_file = cwd / ".env.worktree"
|
|
78
|
-
if not env_file.exists():
|
|
79
|
-
print(f"No .env.worktree at {cwd}. Run with --force to generate.", file=sys.stderr)
|
|
80
|
-
return 1
|
|
81
|
-
print(env_file.read_text())
|
|
82
|
-
return 0
|
|
83
|
-
|
|
84
|
-
compose_files = find_compose_files(cwd)
|
|
85
|
-
if not compose_files:
|
|
86
|
-
if args.quiet:
|
|
87
|
-
print(json.dumps({"continue": True}))
|
|
88
|
-
elif args.verbose:
|
|
89
|
-
print(f"No docker-compose files in {cwd}. Nothing to isolate.")
|
|
90
|
-
return 0
|
|
91
|
-
|
|
92
|
-
wid = worktree_id(cwd)
|
|
93
|
-
project_name = f"{cwd.name}-{wid}"
|
|
94
|
-
env_file = cwd / ".env.worktree"
|
|
95
|
-
|
|
96
|
-
compose_chain: list[tuple[Path, Path | None]] = []
|
|
97
|
-
all_mappings: list[PortMapping] = []
|
|
98
|
-
regenerated_any = False
|
|
99
|
-
|
|
100
|
-
for base in compose_files:
|
|
101
|
-
mappings = collect_port_mappings(base, wid)
|
|
102
|
-
container_names = collect_container_names(base)
|
|
103
|
-
|
|
104
|
-
if not mappings and not container_names:
|
|
105
|
-
# Nothing to override for this file — still include in chain for completeness? No,
|
|
106
|
-
# if there's nothing to override, the base alone is fine. Skip.
|
|
107
|
-
continue
|
|
108
|
-
|
|
109
|
-
override_path = override_path_for(base)
|
|
110
|
-
|
|
111
|
-
if not args.force and overrides_up_to_date(base, override_path, env_file):
|
|
112
|
-
compose_chain.append((base, override_path))
|
|
113
|
-
all_mappings.extend(mappings)
|
|
114
|
-
continue
|
|
115
|
-
|
|
116
|
-
override_yaml_data = render_override_yaml(mappings, container_names, project_name, wid)
|
|
117
|
-
with open(override_path, "w") as f:
|
|
118
|
-
f.write("# Auto-generated by ~/.claude/scripts/worktree-isolation/apply.py\n")
|
|
119
|
-
f.write("# DO NOT COMMIT. Regenerate with the worktree-isolation skill.\n")
|
|
120
|
-
yaml.safe_dump(override_yaml_data, f, sort_keys=False, default_flow_style=False)
|
|
121
|
-
compose_chain.append((base, override_path))
|
|
122
|
-
all_mappings.extend(mappings)
|
|
123
|
-
regenerated_any = True
|
|
124
|
-
|
|
125
|
-
if not compose_chain:
|
|
126
|
-
if args.quiet:
|
|
127
|
-
print(json.dumps({"continue": True}))
|
|
128
|
-
elif args.verbose:
|
|
129
|
-
print(f"No services with ports or container_name in {cwd}. Nothing to isolate.")
|
|
130
|
-
return 0
|
|
131
|
-
|
|
132
|
-
# Always write env file when we have a chain — covers fresh dirs even if overrides exist.
|
|
133
|
-
env_content = render_env_worktree(project_name, wid, compose_chain, all_mappings)
|
|
134
|
-
if not env_file.exists() or env_file.read_text() != env_content:
|
|
135
|
-
env_file.write_text(env_content)
|
|
136
|
-
regenerated_any = True
|
|
137
|
-
|
|
138
|
-
ensure_git_exclude(cwd, [".env.worktree", "*.worktree.yml", "*.worktree.yaml"])
|
|
139
|
-
|
|
140
|
-
summary = _build_summary(project_name, wid, compose_chain, all_mappings)
|
|
141
|
-
|
|
142
|
-
if args.quiet:
|
|
143
|
-
out = {
|
|
144
|
-
"hookSpecificOutput": {
|
|
145
|
-
"hookEventName": "SessionStart",
|
|
146
|
-
"additionalContext": summary,
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
print(json.dumps(out))
|
|
150
|
-
else:
|
|
151
|
-
print(summary)
|
|
152
|
-
if not regenerated_any:
|
|
153
|
-
print("\n(no changes — overrides already up to date)")
|
|
154
|
-
return 0
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
def main() -> int:
|
|
158
|
-
parser = argparse.ArgumentParser(description="Per-worktree docker-compose isolation.")
|
|
159
|
-
parser.add_argument("--cwd", type=Path, default=Path.cwd(), help="Working directory")
|
|
160
|
-
parser.add_argument("--quiet", action="store_true", help="Hook mode: emit JSON only")
|
|
161
|
-
parser.add_argument("--verbose", action="store_true", help="Skill mode: human output")
|
|
162
|
-
parser.add_argument("--force", action="store_true", help="Regenerate even if up-to-date")
|
|
163
|
-
parser.add_argument("--status", action="store_true", help="Print current .env.worktree only")
|
|
164
|
-
args = parser.parse_args()
|
|
165
|
-
|
|
166
|
-
try:
|
|
167
|
-
return _run(args)
|
|
168
|
-
except Exception as exc: # noqa: BLE001 — fail loud; hook captures stderr
|
|
169
|
-
if args.quiet:
|
|
170
|
-
# Don't break the session — emit a minimal valid hook response and log to stderr.
|
|
171
|
-
print(json.dumps({"continue": True}))
|
|
172
|
-
print(f"worktree-isolation error: {exc}", file=sys.stderr)
|
|
173
|
-
return 0
|
|
174
|
-
raise
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
if __name__ == "__main__":
|
|
178
|
-
sys.exit(main())
|