cc-workspace 4.0.4 → 4.0.5

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/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Claude Code Multi-Workspace Orchestrator v4.0
1
+ # Claude Code Multi-Workspace Orchestrator v4.0.5
2
2
 
3
3
  A system to pilot multi-service projects from Claude Code.
4
4
  The orchestrator (Opus) never codes in repos. It clarifies, plans,
@@ -66,8 +66,10 @@ claude --agent team-lead
66
66
  npx cc-workspace update
67
67
  ```
68
68
 
69
- Updates global components (~/.claude/) if the package version is newer.
70
- Workspace files (workspace.md, constitution.md, plans/) are never overwritten.
69
+ Updates all components if the package version is newer:
70
+ - **Global**: skills, rules, agents in `~/.claude/`
71
+ - **Local** (if orchestrator/ found): hooks, settings.json, CLAUDE.md, templates, _TEMPLATE.md
72
+ - **Never overwritten**: workspace.md, constitution.md, plans/
71
73
 
72
74
  ### Diagnostic
73
75
 
@@ -164,7 +166,7 @@ detects if the target path is in a repo (presence of `.git/`).
164
166
 
165
167
  Protection layers:
166
168
  1. `disallowedTools: Bash` in agent frontmatter
167
- 2. `allowed-tools` whitelist in agent frontmatter
169
+ 2. `tools` whitelist in agent frontmatter (note: `allowed-tools` is the skill equivalent)
168
170
  3. `PreToolUse` path-aware hook in agent frontmatter
169
171
  4. `block-orchestrator-writes.sh` hook in .claude/hooks/
170
172
 
@@ -330,12 +332,12 @@ cc-workspace/
330
332
 
331
333
  ## Idempotence
332
334
 
333
- The setup is safe to re-run:
334
- - Does not overwrite `workspace.md` or `constitution.md` if already present
335
- - Always regenerates `service-profiles.md` (fresh scan)
336
- - Always regenerates `settings.json` and `block-orchestrator-writes.sh` (security)
337
- - Templates are always copied
338
- - Global components are only updated if the version is newer
335
+ Both `init` and `update` are safe to re-run:
336
+ - **Never overwritten**: `workspace.md`, `constitution.md`, `plans/*.md` (user content)
337
+ - **Always regenerated**: `settings.json`, `block-orchestrator-writes.sh` (security), `CLAUDE.md`, `_TEMPLATE.md`
338
+ - **Always copied**: hooks, templates
339
+ - **Always regenerated on init**: `service-profiles.md` (fresh scan)
340
+ - **Global components**: only updated if the version is newer (or `--force`)
339
341
 
340
342
  ---
341
343
 
package/bin/cli.js CHANGED
@@ -324,7 +324,7 @@ You clarify, plan, delegate, track.
324
324
 
325
325
  ## Security
326
326
  - \`disallowedTools: Bash\` — no direct shell
327
- - \`allowed-tools\` : Read, Write, Edit, Glob, Grep, Task, Teammate, SendMessage
327
+ - \`tools\` : Read, Write, Edit, Glob, Grep, Task(implementer, Explore), Teammate, SendMessage
328
328
  - Hook \`PreToolUse\` path-aware: allows orchestrator/, blocks sibling repos
329
329
 
330
330
  > settings.json contains env vars + hooks registration.
@@ -424,6 +424,80 @@ function planTemplateContent() {
424
424
  `;
425
425
  }
426
426
 
427
+ // ─── Update local orchestrator/ components ──────────────────
428
+ // Called by `update` when run from a workspace that contains orchestrator/
429
+ // or from inside orchestrator/ itself.
430
+ function updateLocal() {
431
+ const cwd = process.cwd();
432
+ // Detect if we're inside orchestrator/ or in the parent workspace
433
+ let orchDir;
434
+ if (fs.existsSync(path.join(cwd, "workspace.md"))) {
435
+ orchDir = cwd; // inside orchestrator/
436
+ } else if (fs.existsSync(path.join(cwd, "orchestrator", "workspace.md"))) {
437
+ orchDir = path.join(cwd, "orchestrator");
438
+ } else {
439
+ return false; // no local orchestrator found
440
+ }
441
+
442
+ step(`Updating local: ${c.dim}${orchDir}${c.reset}`);
443
+ let count = 0;
444
+
445
+ // ── Hooks (always overwrite — security critical) ──
446
+ const hooksDir = path.join(orchDir, ".claude", "hooks");
447
+ if (fs.existsSync(hooksDir)) {
448
+ generateBlockHook(hooksDir);
449
+ count++;
450
+ const hooksSrc = path.join(SKILLS_DIR, "hooks");
451
+ if (fs.existsSync(hooksSrc)) {
452
+ for (const f of fs.readdirSync(hooksSrc)) {
453
+ if (!f.endsWith(".sh") || f === "verify-cycle-complete.sh") continue;
454
+ copyFile(path.join(hooksSrc, f), path.join(hooksDir, f));
455
+ fs.chmodSync(path.join(hooksDir, f), 0o755);
456
+ count++;
457
+ }
458
+ }
459
+ ok(`${count} hooks updated`);
460
+ }
461
+
462
+ // ── settings.json (always regenerate — hook registration) ──
463
+ const settingsPath = path.join(orchDir, ".claude", "settings.json");
464
+ if (fs.existsSync(path.join(orchDir, ".claude"))) {
465
+ generateSettings(orchDir);
466
+ ok("settings.json regenerated");
467
+ }
468
+
469
+ // ── Templates (always overwrite — reference docs) ──
470
+ const templatesDir = path.join(SKILLS_DIR, "templates");
471
+ const localTemplates = path.join(orchDir, "templates");
472
+ if (fs.existsSync(templatesDir) && fs.existsSync(localTemplates)) {
473
+ let tplCount = 0;
474
+ for (const f of fs.readdirSync(templatesDir)) {
475
+ if (f.endsWith(".md")) {
476
+ copyFile(path.join(templatesDir, f), path.join(localTemplates, f));
477
+ tplCount++;
478
+ }
479
+ }
480
+ ok(`${tplCount} templates updated`);
481
+ }
482
+
483
+ // ── CLAUDE.md (always overwrite — generated file, not user content) ──
484
+ const claudeMd = path.join(orchDir, "CLAUDE.md");
485
+ fs.writeFileSync(claudeMd, claudeMdContent());
486
+ ok("CLAUDE.md updated");
487
+
488
+ // ── Plan template (always overwrite — structure only) ──
489
+ const planTpl = path.join(orchDir, "plans", "_TEMPLATE.md");
490
+ if (fs.existsSync(path.join(orchDir, "plans"))) {
491
+ fs.writeFileSync(planTpl, planTemplateContent());
492
+ ok("_TEMPLATE.md updated");
493
+ }
494
+
495
+ // ── NEVER touch: workspace.md, constitution.md, plans/*.md, service-profiles.md ──
496
+ info(`${c.dim}workspace.md, constitution.md, plans/ — preserved${c.reset}`);
497
+
498
+ return true;
499
+ }
500
+
427
501
  // ─── Setup workspace ────────────────────────────────────────
428
502
  function setupWorkspace(workspacePath, projectName) {
429
503
  const wsAbs = path.resolve(workspacePath);
@@ -685,10 +759,15 @@ switch (command) {
685
759
  const force = args.includes("--force");
686
760
  log(BANNER);
687
761
  const updated = installGlobals(force);
688
- if (!updated) {
762
+ const localUpdated = (updated || force) ? updateLocal() : false;
763
+ if (!updated && !force) {
689
764
  log(`\n ${c.dim}Already up to date. Use --force to reinstall.${c.reset}\n`);
690
765
  } else {
691
- log(`\n ${c.green}${c.bold}Update complete.${c.reset}\n`);
766
+ if (localUpdated) {
767
+ log(`\n ${c.green}${c.bold}Update complete (globals + local orchestrator/).${c.reset}\n`);
768
+ } else {
769
+ log(`\n ${c.green}${c.bold}Update complete (globals only — no local orchestrator/ found).${c.reset}\n`);
770
+ }
692
771
  }
693
772
  break;
694
773
  }
@@ -721,7 +800,9 @@ switch (command) {
721
800
  log(` Installs global skills/rules/agents if version is newer.`);
722
801
  log("");
723
802
  log(` ${c.cyan}npx cc-workspace update${c.reset} ${c.dim}[--force]${c.reset}`);
724
- log(` Update global components to this package version.`);
803
+ log(` Update global components (skills, rules, agents).`);
804
+ log(` Also updates local orchestrator/ if found (hooks, settings, CLAUDE.md, templates).`);
805
+ log(` Never overwrites: workspace.md, constitution.md, plans/.`);
725
806
  log("");
726
807
  log(` ${c.cyan}npx cc-workspace doctor${c.reset}`);
727
808
  log(` Check all components are installed and consistent.`);
@@ -7,9 +7,8 @@ description: >
7
7
  (Agent Teams teammates get automatic isolation).
8
8
  isolation: worktree
9
9
  model: sonnet
10
- allowed-tools: Read, Write, Edit, MultiEdit, Bash, Glob, Grep
10
+ tools: Read, Write, Edit, MultiEdit, Bash, Glob, Grep
11
11
  memory: project
12
- effort: medium
13
12
  maxTurns: 50
14
13
  ---
15
14
 
@@ -6,10 +6,9 @@ description: >
6
6
  quality. Never codes in repos — can write in orchestrator/.
7
7
  Triggered via claude --agent team-lead.
8
8
  model: opus
9
- allowed-tools: Read, Write, Edit, Glob, Grep, Task, Teammate, SendMessage
9
+ tools: Read, Write, Edit, Glob, Grep, Task(implementer, Explore), Teammate, SendMessage
10
10
  disallowedTools: Bash
11
11
  memory: project
12
- effort: high
13
12
  maxTurns: 200
14
13
  hooks:
15
14
  PreToolUse:
@@ -6,9 +6,8 @@ description: >
6
6
  Interactively configures workspace.md and constitution.md if [UNCONFIGURED].
7
7
  Run once via: claude --agent workspace-init
8
8
  model: sonnet
9
- allowed-tools: Read, Write, Edit, Bash, Glob, Grep, Task
9
+ tools: Read, Write, Edit, Bash, Glob, Grep, Task(Explore)
10
10
  memory: project
11
- effort: medium
12
11
  maxTurns: 80
13
12
  ---
14
13
 
@@ -7,6 +7,7 @@ description: >
7
7
  or when a repo is detected without CLAUDE.md during setup.
8
8
  argument-hint: "[repo-path]"
9
9
  context: fork
10
+ agent: general-purpose
10
11
  disable-model-invocation: true
11
12
  model: haiku
12
13
  allowed-tools: Read, Write, Glob, Grep, Bash
@@ -8,6 +8,7 @@ description: >
8
8
  "cross-service", "aligned", "pre-merge".
9
9
  argument-hint: "[feature-name]"
10
10
  context: fork
11
+ agent: general-purpose
11
12
  disable-model-invocation: true
12
13
  allowed-tools: Read, Write, Glob, Grep, Task
13
14
  ---
@@ -8,6 +8,7 @@ description: >
8
8
  "capitalize", "lessons learned", "what did we learn", "improve docs".
9
9
  argument-hint: "[feature-name]"
10
10
  context: fork
11
+ agent: general-purpose
11
12
  disable-model-invocation: true
12
13
  model: haiku
13
14
  allowed-tools: Read, Write, Glob, Grep, Task
@@ -85,6 +85,8 @@ You are teammate-[service]. Read the CLAUDE.md in your repo first.
85
85
 
86
86
  ## Explore/Haiku subagent template (read-only)
87
87
 
88
+ Use `Task` with `subagent_type: Explore` and `model: haiku` for lightweight scans.
89
+
88
90
  ```
89
91
  You are an explorer scanning [target]. Read-only — do NOT modify any files.
90
92
 
@@ -94,3 +96,11 @@ You are an explorer scanning [target]. Read-only — do NOT modify any files.
94
96
  ## Report format
95
97
  [what to extract and how to format the findings]
96
98
  ```
99
+
100
+ ## Failure handling
101
+
102
+ When a teammate reports back:
103
+ - **Test regression or missing file** (recoverable): fix plan, re-dispatch ONCE
104
+ - **Architectural decision not in plan** (blocking): STOP the wave, escalate to user
105
+ - **No report after extended time**: send a status request via SendMessage
106
+ - **Max re-dispatches per teammate per wave**: 2. After that, escalate to user.
@@ -7,6 +7,7 @@ description: >
7
7
  "prepare merge", "merge-prep", "ready to merge".
8
8
  argument-hint: "[feature-name]"
9
9
  context: fork
10
+ agent: general-purpose
10
11
  disable-model-invocation: true
11
12
  allowed-tools: Read, Write, Glob, Grep, Bash, Task
12
13
  ---
@@ -7,6 +7,7 @@ description: >
7
7
  Use when a plan was just written or user says "review plan", "vérifie le plan".
8
8
  argument-hint: "[plan-name.md]"
9
9
  context: fork
10
+ agent: Explore
10
11
  disable-model-invocation: true
11
12
  model: haiku
12
13
  allowed-tools: Read, Glob, Grep
@@ -5,6 +5,7 @@ description: >
5
5
  listed in workspace.md. Use when conventions changed, or user says
6
6
  "refresh profiles", "update profiles", "re-read CLAUDE.md files".
7
7
  context: fork
8
+ agent: Explore
8
9
  disable-model-invocation: true
9
10
  model: haiku
10
11
  allowed-tools: Read, Write, Glob, Grep
@@ -12,7 +12,7 @@ If you write code for a repo (not a markdown plan), you have failed — delegate
12
12
 
13
13
  ## Security layers (3 layers in agent frontmatter — no settings.json pollution)
14
14
  1. **Agent frontmatter**: `disallowedTools` — refused at model level
15
- 2. **Agent frontmatter**: `allowed-tools` — whitelist of permitted tools
15
+ 2. **Agent frontmatter**: `tools` — whitelist of permitted tools (note: `allowed-tools` is for skills only)
16
16
  3. **Agent hook**: `PreToolUse` in frontmatter — structured deny response
17
17
 
18
18
  ## Routing table
@@ -24,18 +24,6 @@ If you write code for a repo (not a markdown plan), you have failed — delegate
24
24
  | Explorers / cross-checks | **Haiku** | `model: haiku` in skill/agent frontmatter |
25
25
  | Plan review | **Haiku** | `model: haiku` in skill frontmatter |
26
26
 
27
- ## Effort levels
28
- | Role | Effort | Rationale |
29
- |------|--------|-----------|
30
- | Orchestrator (team-lead) | **high** | Complex planning, multi-step reasoning |
31
- | Implementation teammates | **medium** | Focused implementation, clear scope |
32
- | QA investigators | **medium** | Thorough but bounded analysis |
33
- | Explorers / cross-checks (Haiku) | **low** | Fast scans, read-only |
34
- | Plan review (Haiku) | **low** | Structural checks, no deep reasoning |
35
-
36
- Effort levels are set in agent frontmatter (`effort: high|medium|low|max`).
37
- Use `max` only for critical debugging or complex architectural decisions.
38
-
39
27
  ## Custom agent `implementer`
40
28
  For Task subagents that need to write code in an isolated worktree,
41
29
  use `@implementer` (frontmatter with `isolation: worktree`).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cc-workspace",
3
- "version": "4.0.4",
3
+ "version": "4.0.5",
4
4
  "description": "Claude Code multi-workspace orchestrator — skills, hooks, agents, and templates for multi-service projects",
5
5
  "bin": {
6
6
  "cc-workspace": "./bin/cli.js"