harnessed 1.0.4 → 2.0.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/dist/cli.mjs CHANGED
@@ -148,8 +148,8 @@ var init_path_guard = __esm({
148
148
  }
149
149
  });
150
150
  function branchOnSchemaVersion(v, handlers) {
151
- const isKnownV1 = Object.values(SCHEMA_VERSIONS).includes(v);
152
- return isKnownV1 ? handlers.v1() : handlers.unknown();
151
+ const isKnownVersion = Object.values(SCHEMA_VERSIONS).includes(v);
152
+ return isKnownVersion ? handlers.v1() : handlers.unknown();
153
153
  }
154
154
  var SCHEMA_VERSIONS;
155
155
  var init_schemaVersion = __esm({
@@ -172,8 +172,14 @@ var init_schemaVersion = __esm({
172
172
  // ← Phase 3.3 W0 T0.5 BACKFILL 11th surface (sister Phase 3.2 W2 T2.2 b875e21 commit msg claim "11th surface" was LATENT STALE — never registered; T0.5 surgical fix per sister Phase 3.2 W2 T2.6 latent W1 c37ee29 Rule 1 pattern)
173
173
  aliases: "harnessed.aliases.v1",
174
174
  // ← Phase 3.3 W1 T1.1 ADD 12th surface (D-01 RICH manifests/aliases.yaml upstream rename redirect + metadata)
175
- knownGood: "harnessed.known-good.v1"
175
+ knownGood: "harnessed.known-good.v1",
176
176
  // ← Phase 3.3 W1 T1.1 ADD 13th surface (D-03 YAML versions/<harnessed-ver>-known-good.yaml per-version lock)
177
+ capabilities: "harnessed.capabilities.v1",
178
+ // ← Phase v2.0-2.3 W0 T2.3.W0.6 ADD 14th surface (R20.2 flat yaml capabilities manifest validate)
179
+ judgment: "harnessed.judgment.v1",
180
+ // ← Phase v2.0-2.3 W0 T2.3.W0.6 ADD 15th surface (R20.4 multi-file judgments triggers/rules validate)
181
+ workflow: "harnessed.workflow.v2"
182
+ // ← Phase v2.0-2.4 W0 T2.4.W0.1 ADD 16th surface (R20.1 + R20.2 + R20.9 — workflow.yaml v2 schema: gate / on / capability / args / fallback / parallelism 字段, sister 4 workflow.yaml: plan-feature + execute-task + research + verify-work)
177
183
  };
178
184
  Type.Union([
179
185
  Type.Literal(SCHEMA_VERSIONS.routingSnapshot),
@@ -193,8 +199,14 @@ var init_schemaVersion = __esm({
193
199
  // ← Phase 3.3 W0 T0.5 BACKFILL 11th surface
194
200
  Type.Literal(SCHEMA_VERSIONS.aliases),
195
201
  // ← Phase 3.3 W1 T1.1 ADD 12th surface
196
- Type.Literal(SCHEMA_VERSIONS.knownGood)
202
+ Type.Literal(SCHEMA_VERSIONS.knownGood),
197
203
  // ← Phase 3.3 W1 T1.1 ADD 13th surface
204
+ Type.Literal(SCHEMA_VERSIONS.capabilities),
205
+ // ← Phase v2.0-2.3 W0 T2.3.W0.6 ADD 14th surface
206
+ Type.Literal(SCHEMA_VERSIONS.judgment),
207
+ // ← Phase v2.0-2.3 W0 T2.3.W0.6 ADD 15th surface
208
+ Type.Literal(SCHEMA_VERSIONS.workflow)
209
+ // ← Phase v2.0-2.4 W0 T2.4.W0.1 ADD 16th surface (workflow.yaml v2 schema, NOTE first .v2 surface in union)
198
210
  ]);
199
211
  }
200
212
  });
@@ -456,6 +468,109 @@ var init_check_token_budget = __esm({
456
468
  PER_SKILL_THRESHOLD = 5e3;
457
469
  }
458
470
  });
471
+ async function checkAgentTeams() {
472
+ const envValue = process.env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS;
473
+ const envOn = envValue === "1";
474
+ let settingsValue;
475
+ let settingsOn = false;
476
+ try {
477
+ const path = resolve(homedir(), ".claude", "settings.json");
478
+ const raw = await readFile(path, "utf8");
479
+ const data = JSON.parse(raw);
480
+ settingsValue = data.env?.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS;
481
+ settingsOn = settingsValue === "1";
482
+ } catch {
483
+ }
484
+ const detected = { env: envOn, settingsJson: settingsOn };
485
+ if (envOn || settingsOn) {
486
+ return { status: "pass", detected, envValue, settingsValue };
487
+ }
488
+ return {
489
+ status: "missing",
490
+ detected,
491
+ envValue,
492
+ settingsValue,
493
+ remediation: 'Agent Teams not enabled. Add to ~/.claude/settings.json:\n "env": { "CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1" }\nOR run: claude config set env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS 1\nOR export env var:\n export CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1\nThen restart Claude Code (CC >= 2.1.133 required).'
494
+ };
495
+ }
496
+ var init_checkAgentTeams = __esm({
497
+ "src/cli/lib/checkAgentTeams.ts"() {
498
+ }
499
+ });
500
+
501
+ // src/cli/lib/check-agent-teams-doctor.ts
502
+ var check_agent_teams_doctor_exports = {};
503
+ __export(check_agent_teams_doctor_exports, {
504
+ checkAgentTeamsDoctor: () => checkAgentTeamsDoctor
505
+ });
506
+ async function checkAgentTeamsDoctor() {
507
+ const r = await checkAgentTeams();
508
+ if (r.status === "pass") {
509
+ const source = r.detected.env ? "env var" : "settings.json";
510
+ return {
511
+ name: "Agent Teams env",
512
+ status: "pass",
513
+ message: `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 (${source})`
514
+ };
515
+ }
516
+ return {
517
+ name: "Agent Teams env",
518
+ status: "warn",
519
+ message: "CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS not set (Agent Teams disabled)",
520
+ fix: r.remediation
521
+ };
522
+ }
523
+ var init_check_agent_teams_doctor = __esm({
524
+ "src/cli/lib/check-agent-teams-doctor.ts"() {
525
+ init_checkAgentTeams();
526
+ }
527
+ });
528
+
529
+ // src/cli/lib/check-planning-with-files.ts
530
+ var check_planning_with_files_exports = {};
531
+ __export(check_planning_with_files_exports, {
532
+ checkPlanningWithFiles: () => checkPlanningWithFiles
533
+ });
534
+ async function checkPlanningWithFiles() {
535
+ const root = join(
536
+ homedir(),
537
+ ".claude",
538
+ "plugins",
539
+ "cache",
540
+ "planning-with-files",
541
+ "planning-with-files"
542
+ );
543
+ try {
544
+ const entries = await readdir(root);
545
+ const versions = entries.filter((e) => /^\d+\.\d+/.test(e));
546
+ if (versions.length > 0) {
547
+ return {
548
+ name: "planning-with-files plugin",
549
+ status: "pass",
550
+ message: `installed (version ${versions.join(", ")})`
551
+ };
552
+ }
553
+ return {
554
+ name: "planning-with-files plugin",
555
+ status: "warn",
556
+ message: "plugin directory exists but no version subdir found",
557
+ fix: REMEDIATION
558
+ };
559
+ } catch {
560
+ return {
561
+ name: "planning-with-files plugin",
562
+ status: "warn",
563
+ message: "not installed (plugin cache path missing)",
564
+ fix: REMEDIATION
565
+ };
566
+ }
567
+ }
568
+ var REMEDIATION;
569
+ var init_check_planning_with_files = __esm({
570
+ "src/cli/lib/check-planning-with-files.ts"() {
571
+ REMEDIATION = "install via Claude Code plugin marketplace: `claude plugin install planning-with-files` (requires >=2.2.0 per R20.15 + D-15)";
572
+ }
573
+ });
459
574
  async function withLock(fn) {
460
575
  let release;
461
576
  try {
@@ -670,7 +785,7 @@ var init_resume = __esm({
670
785
 
671
786
  // package.json
672
787
  var package_default = {
673
- version: "1.0.4"};
788
+ version: "2.0.0"};
674
789
 
675
790
  // src/manifest/errors.ts
676
791
  function instancePathToKeyPath(instancePath) {
@@ -1451,7 +1566,7 @@ function renderHumanTable(records) {
1451
1566
  }
1452
1567
  }
1453
1568
  function pipeToJq(filterExpr, lines) {
1454
- return new Promise((resolve10, reject) => {
1569
+ return new Promise((resolve11, reject) => {
1455
1570
  const child = spawn("jq", [filterExpr], {
1456
1571
  stdio: ["pipe", "inherit", "inherit"],
1457
1572
  windowsHide: true
@@ -1460,12 +1575,12 @@ function pipeToJq(filterExpr, lines) {
1460
1575
  const e = err2;
1461
1576
  if (e.code === "ENOENT") {
1462
1577
  console.error("\u2717 jq not found in PATH \u2014 run: harnessed doctor");
1463
- resolve10(1);
1578
+ resolve11(1);
1464
1579
  } else {
1465
1580
  reject(err2);
1466
1581
  }
1467
1582
  });
1468
- child.on("close", (code) => resolve10(code ?? 0));
1583
+ child.on("close", (code) => resolve11(code ?? 0));
1469
1584
  child.stdin.write(lines.join("\n"));
1470
1585
  child.stdin.end();
1471
1586
  });
@@ -1649,29 +1764,36 @@ async function checkDeprecations2() {
1649
1764
  async function checkTokenBudget2() {
1650
1765
  return (await Promise.resolve().then(() => (init_check_token_budget(), check_token_budget_exports))).checkTokenBudget();
1651
1766
  }
1767
+ async function checkAgentTeamsEnv() {
1768
+ return (await Promise.resolve().then(() => (init_check_agent_teams_doctor(), check_agent_teams_doctor_exports))).checkAgentTeamsDoctor();
1769
+ }
1770
+ async function checkPlanningPlugin() {
1771
+ return (await Promise.resolve().then(() => (init_check_planning_with_files(), check_planning_with_files_exports))).checkPlanningWithFiles();
1772
+ }
1652
1773
  function registerDoctor(program2) {
1653
1774
  program2.command("doctor").description(
1654
- "Preflight checks (Node / MCP scope / jq / Win bash / origin URL / gstack prefix / deprecations / token budget)"
1775
+ "Preflight checks (Node / MCP scope / jq / Win bash / origin URL / gstack prefix / deprecations / token budget / Agent Teams / planning-with-files)"
1655
1776
  ).option("--json", "output JSON instead of human-readable").action(async (opts) => {
1656
- const [mcpScope, originUrl, gstackPrefix, deprecations, tokenBudget] = await Promise.all([
1777
+ const [mcp, origin, gstack, dep, tok, at, ppwf] = await Promise.all([
1657
1778
  checkMcpScope(),
1658
1779
  checkOriginUrl(),
1659
1780
  checkGstackPrefix(),
1660
- // ← Phase 3.2 W1 T1.5 ADD 6th check (D-01 PROBE)
1661
1781
  checkDeprecations2(),
1662
- // ← Phase 3.3 W1 T1.7 ADD 7th check (D-02 DOCTOR-ONLY-WARN)
1663
- checkTokenBudget2()
1664
- // ← Phase 3.4 W1 T1.2 ADD 8th check (D-03 + D-04 DOCTOR WARN)
1782
+ checkTokenBudget2(),
1783
+ checkAgentTeamsEnv(),
1784
+ checkPlanningPlugin()
1665
1785
  ]);
1666
1786
  const results = [
1667
1787
  checkNodeVersion(),
1668
- mcpScope,
1788
+ mcp,
1669
1789
  checkJq(),
1670
1790
  checkWinBash(),
1671
- originUrl,
1672
- gstackPrefix,
1673
- deprecations,
1674
- tokenBudget
1791
+ origin,
1792
+ gstack,
1793
+ dep,
1794
+ tok,
1795
+ at,
1796
+ ppwf
1675
1797
  ];
1676
1798
  const hasFail = results.some((r) => r.status === "fail");
1677
1799
  const hasWarn = results.some((r) => r.status === "warn");
@@ -2056,6 +2178,51 @@ async function completePhase(ctx) {
2056
2178
  await complete();
2057
2179
  }
2058
2180
 
2181
+ // src/routing/lib/fallbackHandlers.ts
2182
+ function handleMaxIterationsExceeded(err2, fallback, ctx) {
2183
+ const yamlShort = fallback.message.replace(
2184
+ /\{\{\s*args\.max_iterations\s*\}\}/g,
2185
+ String(ctx.maxIterations)
2186
+ );
2187
+ const truncated = (ctx.lastMessage ?? "<empty>").slice(0, 500);
2188
+ const uxText = `\u274C ralph-loop max-iterations exceeded (${err2.iterations}/${ctx.maxIterations}).
2189
+ Sub-task: ${ctx.subtaskSummary}
2190
+ Workflow: ${ctx.workflowName} / phase ${ctx.phaseId}
2191
+ Last subagent output (truncated): ${truncated}
2192
+ The subagent attempted ${err2.iterations} iterations without emitting verbatim "<promise>COMPLETE</promise>".
2193
+ This indicates one of:
2194
+ 1. Sub-task is genuinely incomplete (escalate to user / re-scope)
2195
+ 2. Subagent is stuck in a loop (review prompt / system instructions)
2196
+ 3. max-iterations too low (override via --max-iterations <N>, hard upper limit 100)
2197
+ Manual options:
2198
+ A) Continue with current state: \`harnessed workflow resume --skip-completion-gate\`
2199
+ B) Re-run from last checkpoint: \`harnessed workflow resume --from-checkpoint\`
2200
+ C) Abort cleanly: exit 1
2201
+ Exit code: ${fallback.exit_code}
2202
+ ${yamlShort}`;
2203
+ console.error(uxText);
2204
+ process.exit(fallback.exit_code);
2205
+ throw new Error("unreachable");
2206
+ }
2207
+ function handleVerbatimCompleteFail(err2, fallback, ctx) {
2208
+ const truncated = err2.lastMessage.slice(0, 500);
2209
+ const uxText = `\u274C ralph-loop verbatim COMPLETE signal missing (F33 P1).
2210
+ Sub-task: ${ctx.subtaskSummary}
2211
+ Workflow: ${ctx.workflowName} / phase ${ctx.phaseId}
2212
+ Last subagent output (truncated): ${truncated}
2213
+ The subagent's final message lacked verbatim "<promise>COMPLETE</promise>" tag.
2214
+ This indicates one of:
2215
+ 1. Subagent skipped the completion-promise contract (review system prompt)
2216
+ 2. Output format misconfigured (check outputFormat schema)
2217
+ Manual options:
2218
+ A) Re-run with explicit COMPLETE instruction in subagent prompt
2219
+ B) Abort cleanly: exit ${fallback.exit_code}
2220
+ Exit code: ${fallback.exit_code}`;
2221
+ console.error(uxText);
2222
+ process.exit(fallback.exit_code);
2223
+ throw new Error("unreachable");
2224
+ }
2225
+
2059
2226
  // src/routing/lib/promiseExtract.ts
2060
2227
  var PROMISE_PATTERN = /<promise>([^<]+)<\/promise>/;
2061
2228
  function extractPromise(text) {
@@ -2265,9 +2432,6 @@ async function runRouting(task, opts = {}) {
2265
2432
  try {
2266
2433
  await ensureSkillsInstalled(decision.required_skills ?? [], skillsRoot);
2267
2434
  } catch (error) {
2268
- if (error instanceof RestartRequiredError || error instanceof SkillNotInstalledError || error instanceof MissingSkillsError) {
2269
- return { ok: false, phase: "install", error };
2270
- }
2271
2435
  return { ok: false, phase: "install", error };
2272
2436
  }
2273
2437
  let agentDef;
@@ -2294,6 +2458,11 @@ async function runRouting(task, opts = {}) {
2294
2458
  onSessionIdInner?.(id);
2295
2459
  }
2296
2460
  });
2461
+ const fbCtx = {
2462
+ subtaskSummary: task.task,
2463
+ workflowName: task.task_type ?? "unknown",
2464
+ phaseId: opts.fallbackPhaseId ?? task.phaseId ?? "unknown"
2465
+ };
2297
2466
  try {
2298
2467
  const result = await ralphLoopWrap(wrappedSpawn, maxIter);
2299
2468
  await completePhase({ phaseId, sessionId: capturedSessionId, status: "complete" });
@@ -2302,10 +2471,16 @@ async function runRouting(task, opts = {}) {
2302
2471
  } catch (error) {
2303
2472
  if (error instanceof MaxIterationsExceededError) {
2304
2473
  emitAudit(task, decision, matched, "max-iter", capturedSessionId);
2474
+ if (opts.fallbackConfig)
2475
+ handleMaxIterationsExceeded(error, opts.fallbackConfig, {
2476
+ ...fbCtx,
2477
+ maxIterations: maxIter
2478
+ });
2305
2479
  return { aborted: true, reason: error.message };
2306
2480
  }
2307
2481
  if (error instanceof VerbatimCompleteFailError) {
2308
2482
  emitAudit(task, decision, matched, "verbatim-fail", capturedSessionId);
2483
+ if (opts.fallbackConfig) handleVerbatimCompleteFail(error, opts.fallbackConfig, fbCtx);
2309
2484
  return { ok: false, phase: "verbatim", error };
2310
2485
  }
2311
2486
  emitAudit(task, decision, matched, "spawn-err", capturedSessionId);
@@ -2346,6 +2521,70 @@ var PhasesSchema = Type.Object(
2346
2521
  { additionalProperties: false }
2347
2522
  );
2348
2523
 
2524
+ // src/workflow/schema/workflow.ts
2525
+ init_schemaVersion();
2526
+ var ModelTier2 = Type.Union([Type.Literal("haiku"), Type.Literal("sonnet"), Type.Literal("opus")]);
2527
+ var OnAction = Type.Union([Type.Literal("skip"), Type.Literal("invoke")]);
2528
+ var OnClause = Type.Object(
2529
+ {
2530
+ if: Type.String(),
2531
+ // expr-eval expression OR judgments.<file>.<gate>.fires ref
2532
+ invoke: Type.Optional(Type.String()),
2533
+ // '{{ capabilities.<name>.cmd }}' OR literal
2534
+ action: Type.Optional(OnAction)
2535
+ },
2536
+ { additionalProperties: false }
2537
+ );
2538
+ var FallbackMaxIterationsExceeded = Type.Object(
2539
+ {
2540
+ action: Type.Literal("emit_warning_and_halt"),
2541
+ // R20.10 acceptance c "explicit NOT silent"
2542
+ message: Type.String(),
2543
+ exit_code: Type.Number()
2544
+ },
2545
+ { additionalProperties: false }
2546
+ );
2547
+ var PhaseFallback = Type.Object(
2548
+ {
2549
+ max_iterations_exceeded: Type.Optional(FallbackMaxIterationsExceeded)
2550
+ },
2551
+ { additionalProperties: false }
2552
+ );
2553
+ var WorkflowPhaseV2 = Type.Object(
2554
+ {
2555
+ id: Type.String({ minLength: 1 }),
2556
+ name: Type.Optional(Type.String()),
2557
+ upstream: Type.Optional(Type.String()),
2558
+ capability: Type.Optional(Type.String()),
2559
+ // '{{ capabilities.ralph-loop.cmd }}'
2560
+ model: Type.Optional(ModelTier2),
2561
+ invokes: Type.Optional(Type.String()),
2562
+ // legacy slash-cmd OR JINJA template
2563
+ args: Type.Optional(Type.Record(Type.String(), Type.Unknown())),
2564
+ gate: Type.Optional(Type.String()),
2565
+ // judgments.<file>.<gate>.fires 4-level ref
2566
+ on: Type.Optional(Type.Array(OnClause)),
2567
+ parallelism: Type.Optional(Type.String()),
2568
+ // judgments.parallelism-gate.<route>.fires
2569
+ fallback: Type.Optional(PhaseFallback),
2570
+ max_iterations: Type.Optional(
2571
+ Type.Union([Type.Number(), Type.String()])
2572
+ // numeric literal OR jinja '{{ defaults.x.y }}'
2573
+ ),
2574
+ artifacts_expected: Type.Optional(Type.Array(Type.String()))
2575
+ },
2576
+ { additionalProperties: false }
2577
+ );
2578
+ var WorkflowSchemaV2 = Type.Object(
2579
+ {
2580
+ schema_version: Type.Literal(SCHEMA_VERSIONS.workflow),
2581
+ workflow: Type.String({ minLength: 1 }),
2582
+ description: Type.Optional(Type.String()),
2583
+ phases: Type.Array(WorkflowPhaseV2, { minItems: 1 })
2584
+ },
2585
+ { additionalProperties: false }
2586
+ );
2587
+
2349
2588
  // src/workflow/loadPhases.ts
2350
2589
  var PhasesValidationError = class extends Error {
2351
2590
  constructor(errors) {
@@ -2358,10 +2597,18 @@ var PhasesValidationError = class extends Error {
2358
2597
  function loadPhases(yamlPath, vars) {
2359
2598
  const raw = readFileSync(yamlPath, "utf8");
2360
2599
  const parsed = parse(raw);
2361
- if (!Value.Check(PhasesSchema, parsed)) {
2362
- throw new PhasesValidationError([...Value.Errors(PhasesSchema, parsed)]);
2600
+ const isV2 = parsed?.schema_version === "harnessed.workflow.v2";
2601
+ if (isV2) {
2602
+ if (!Value.Check(WorkflowSchemaV2, parsed)) {
2603
+ throw new PhasesValidationError([...Value.Errors(WorkflowSchemaV2, parsed)]);
2604
+ }
2605
+ } else {
2606
+ if (!Value.Check(PhasesSchema, parsed)) {
2607
+ throw new PhasesValidationError([...Value.Errors(PhasesSchema, parsed)]);
2608
+ }
2363
2609
  }
2364
- return parsed;
2610
+ const validated = parsed;
2611
+ return validated;
2365
2612
  }
2366
2613
 
2367
2614
  // src/cli/lib/validateFlags.ts
@@ -2407,9 +2654,20 @@ function registerExecuteTask(program2) {
2407
2654
  );
2408
2655
  process.exit(0);
2409
2656
  }
2657
+ let fallbackConfig;
2658
+ let fallbackPhaseId;
2659
+ for (const ph of phases.phases) {
2660
+ if ("fallback" in ph && ph.fallback?.max_iterations_exceeded) {
2661
+ fallbackConfig = ph.fallback.max_iterations_exceeded;
2662
+ fallbackPhaseId = ph.id;
2663
+ break;
2664
+ }
2665
+ }
2410
2666
  const result = await runRouting(taskCtx, {
2411
2667
  maxIterations: raw.maxIterations ?? 20,
2412
- ...raw.model ? { agentOpts: { modelOverride: raw.model } } : {}
2668
+ ...raw.model ? { agentOpts: { modelOverride: raw.model } } : {},
2669
+ ...fallbackConfig ? { fallbackConfig } : {},
2670
+ ...fallbackPhaseId ? { fallbackPhaseId } : {}
2413
2671
  });
2414
2672
  if ("aborted" in result) {
2415
2673
  console.error(`aborted: ${result.reason}`);
@@ -2894,7 +3152,7 @@ var installCcHookAdd = async (ctx) => {
2894
3152
  return { ok: true, backupId: bk.backupId, appliedFiles: [settingsPath] };
2895
3153
  };
2896
3154
  function runArgs(claudeArgs, cwd, timeoutMs = 15e3) {
2897
- return new Promise((resolve10) => {
3155
+ return new Promise((resolve11) => {
2898
3156
  const isWin = process.platform === "win32";
2899
3157
  const child = isWin ? spawn("cmd.exe", ["/c", "claude", ...claudeArgs], { cwd, windowsHide: true }) : spawn("claude", claudeArgs, { cwd, shell: false });
2900
3158
  let stderr = "";
@@ -2903,15 +3161,15 @@ function runArgs(claudeArgs, cwd, timeoutMs = 15e3) {
2903
3161
  });
2904
3162
  const timer = setTimeout(() => {
2905
3163
  child.kill("SIGKILL");
2906
- resolve10({ exitCode: -1, stderr: `${stderr}[timeout after ${timeoutMs}ms]` });
3164
+ resolve11({ exitCode: -1, stderr: `${stderr}[timeout after ${timeoutMs}ms]` });
2907
3165
  }, timeoutMs);
2908
3166
  child.on("error", (e) => {
2909
3167
  clearTimeout(timer);
2910
- resolve10({ exitCode: -1, stderr: `${stderr}${e.message}` });
3168
+ resolve11({ exitCode: -1, stderr: `${stderr}${e.message}` });
2911
3169
  });
2912
3170
  child.on("close", (code) => {
2913
3171
  clearTimeout(timer);
2914
- resolve10({ exitCode: code ?? -1, stderr });
3172
+ resolve11({ exitCode: code ?? -1, stderr });
2915
3173
  });
2916
3174
  });
2917
3175
  }
@@ -3052,7 +3310,7 @@ ${newEntry}
3052
3310
  )
3053
3311
  };
3054
3312
  }
3055
- const vr = await new Promise((resolve10) => {
3313
+ const vr = await new Promise((resolve11) => {
3056
3314
  const child = spawn(verifyShell, [verifyFlag, verifyLine], { cwd: ctx.cwd, windowsHide: true });
3057
3315
  let stderr = "";
3058
3316
  child.stderr?.setEncoding("utf8").on("data", (c) => {
@@ -3060,15 +3318,15 @@ ${newEntry}
3060
3318
  });
3061
3319
  const timer = setTimeout(() => {
3062
3320
  child.kill("SIGKILL");
3063
- resolve10({ exitCode: -1, stderr: `${stderr}[timeout]` });
3321
+ resolve11({ exitCode: -1, stderr: `${stderr}[timeout]` });
3064
3322
  }, 15e3);
3065
3323
  child.on("error", (e) => {
3066
3324
  clearTimeout(timer);
3067
- resolve10({ exitCode: -1, stderr: e.message });
3325
+ resolve11({ exitCode: -1, stderr: e.message });
3068
3326
  });
3069
3327
  child.on("close", (code) => {
3070
3328
  clearTimeout(timer);
3071
- resolve10({ exitCode: code ?? -1, stderr });
3329
+ resolve11({ exitCode: code ?? -1, stderr });
3072
3330
  });
3073
3331
  });
3074
3332
  if (vr.exitCode !== 0) {
@@ -3124,10 +3382,10 @@ async function spawnCmd(ctx, cmd, args) {
3124
3382
  child.stderr?.setEncoding("utf8").on("data", (chunk) => {
3125
3383
  stderr += chunk;
3126
3384
  });
3127
- return await new Promise((resolve10) => {
3385
+ return await new Promise((resolve11) => {
3128
3386
  const timer = setTimeout(() => {
3129
3387
  child.kill("SIGKILL");
3130
- resolve10({
3388
+ resolve11({
3131
3389
  ok: false,
3132
3390
  phase: "spawn",
3133
3391
  error: {
@@ -3142,7 +3400,7 @@ async function spawnCmd(ctx, cmd, args) {
3142
3400
  }, timeoutMs);
3143
3401
  child.on("error", (err2) => {
3144
3402
  clearTimeout(timer);
3145
- resolve10({
3403
+ resolve11({
3146
3404
  ok: false,
3147
3405
  phase: "spawn",
3148
3406
  error: {
@@ -3157,14 +3415,14 @@ async function spawnCmd(ctx, cmd, args) {
3157
3415
  });
3158
3416
  child.on("close", (code) => {
3159
3417
  clearTimeout(timer);
3160
- resolve10({ ok: true, exitCode: code ?? -1, stdout: stdout2, stderr });
3418
+ resolve11({ ok: true, exitCode: code ?? -1, stdout: stdout2, stderr });
3161
3419
  });
3162
3420
  });
3163
3421
  }
3164
3422
 
3165
3423
  // src/installers/gitCloneWithSetup.ts
3166
3424
  function gitRevParseHead(cwd, timeoutMs = 1e4) {
3167
- return new Promise((resolve10) => {
3425
+ return new Promise((resolve11) => {
3168
3426
  const isWin = process.platform === "win32";
3169
3427
  const child = isWin ? spawn("cmd.exe", ["/c", "git", "rev-parse", "HEAD"], { cwd, windowsHide: true }) : spawn("git", ["rev-parse", "HEAD"], { cwd, shell: false });
3170
3428
  let stdout2 = "";
@@ -3173,15 +3431,15 @@ function gitRevParseHead(cwd, timeoutMs = 1e4) {
3173
3431
  });
3174
3432
  const timer = setTimeout(() => {
3175
3433
  child.kill("SIGKILL");
3176
- resolve10({ sha: "", exit: -1 });
3434
+ resolve11({ sha: "", exit: -1 });
3177
3435
  }, timeoutMs);
3178
3436
  child.on("error", () => {
3179
3437
  clearTimeout(timer);
3180
- resolve10({ sha: "", exit: -1 });
3438
+ resolve11({ sha: "", exit: -1 });
3181
3439
  });
3182
3440
  child.on("close", (code) => {
3183
3441
  clearTimeout(timer);
3184
- resolve10({ sha: stdout2.trim(), exit: code ?? -1 });
3442
+ resolve11({ sha: stdout2.trim(), exit: code ?? -1 });
3185
3443
  });
3186
3444
  });
3187
3445
  }
@@ -3521,7 +3779,7 @@ ${newEntry}
3521
3779
  )
3522
3780
  };
3523
3781
  }
3524
- const vr = await new Promise((resolve10) => {
3782
+ const vr = await new Promise((resolve11) => {
3525
3783
  const child = spawn(verifyShell, [verifyFlag, verifyLine], { cwd: ctx.cwd, windowsHide: true });
3526
3784
  let stderr = "";
3527
3785
  child.stderr?.setEncoding("utf8").on("data", (c) => {
@@ -3529,15 +3787,15 @@ ${newEntry}
3529
3787
  });
3530
3788
  const timer = setTimeout(() => {
3531
3789
  child.kill("SIGKILL");
3532
- resolve10({ exitCode: -1, stderr: `${stderr}[timeout]` });
3790
+ resolve11({ exitCode: -1, stderr: `${stderr}[timeout]` });
3533
3791
  }, 15e3);
3534
3792
  child.on("error", (e) => {
3535
3793
  clearTimeout(timer);
3536
- resolve10({ exitCode: -1, stderr: e.message });
3794
+ resolve11({ exitCode: -1, stderr: e.message });
3537
3795
  });
3538
3796
  child.on("close", (code) => {
3539
3797
  clearTimeout(timer);
3540
- resolve10({ exitCode: code ?? -1, stderr });
3798
+ resolve11({ exitCode: code ?? -1, stderr });
3541
3799
  });
3542
3800
  });
3543
3801
  if (vr.exitCode !== 0) {
@@ -3669,7 +3927,7 @@ ${newEntry}
3669
3927
  )
3670
3928
  };
3671
3929
  }
3672
- const vr = await new Promise((resolve10) => {
3930
+ const vr = await new Promise((resolve11) => {
3673
3931
  const child = spawn(verifyShell, [verifyFlag, verifyLine], { cwd: ctx.cwd, windowsHide: true });
3674
3932
  let stderr = "";
3675
3933
  child.stderr?.setEncoding("utf8").on("data", (c) => {
@@ -3677,15 +3935,15 @@ ${newEntry}
3677
3935
  });
3678
3936
  const timer = setTimeout(() => {
3679
3937
  child.kill("SIGKILL");
3680
- resolve10({ exitCode: -1, stderr: `${stderr}[timeout]` });
3938
+ resolve11({ exitCode: -1, stderr: `${stderr}[timeout]` });
3681
3939
  }, 15e3);
3682
3940
  child.on("error", (e) => {
3683
3941
  clearTimeout(timer);
3684
- resolve10({ exitCode: -1, stderr: e.message });
3942
+ resolve11({ exitCode: -1, stderr: e.message });
3685
3943
  });
3686
3944
  child.on("close", (code) => {
3687
3945
  clearTimeout(timer);
3688
- resolve10({ exitCode: code ?? -1, stderr });
3946
+ resolve11({ exitCode: code ?? -1, stderr });
3689
3947
  });
3690
3948
  });
3691
3949
  if (vr.exitCode !== 0) {
@@ -4298,12 +4556,96 @@ function registerRollback(program2) {
4298
4556
  console.log(`restored ${meta.files.length} file(s) from ${timestamp}`);
4299
4557
  });
4300
4558
  }
4559
+ init_checkAgentTeams();
4301
4560
  var PHASE_212 = /* @__PURE__ */ new Set([
4302
4561
  "cc-plugin-marketplace",
4303
4562
  "git-clone-with-setup",
4304
4563
  "npx-skill-installer",
4305
4564
  "mcp-http-add"
4306
4565
  ]);
4566
+ async function warnIfAgentTeamsMissing() {
4567
+ const r = await checkAgentTeams();
4568
+ if (r.status !== "missing") return;
4569
+ console.warn("\n\u26A0\uFE0F Agent Teams \u672A\u542F\u7528 \u2014 parallelism-gate \u5347\u7EA7\u8DEF\u5F84\u4E0D\u53EF\u7528");
4570
+ console.warn(" \u4FEE\u590D: claude config set env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS 1");
4571
+ console.warn(
4572
+ " \u8BF4\u660E: harnessed v2.0 \u4E09\u5C42\u6808\u65B9\u6CD5\u8BBA parallelism-gate \u5347\u7EA7\u8DEF\u5F84\u9700 CC 2.1.133+ Agent Teams enable (sister ~/.claude/rules/agent-teams.md)"
4573
+ );
4574
+ console.warn(
4575
+ " \u4E0D\u963B\u585E setup,\u540E\u7EED parallelism-gate workflow phase \u89E6\u53D1\u65F6\u81EA\u52A8\u964D\u7EA7 subagent fan-out\n"
4576
+ );
4577
+ }
4578
+ async function scanWorkflowsWithSkill(workflowsDir, entries) {
4579
+ const out = [];
4580
+ for (const entry of entries.sort()) {
4581
+ const src = join(workflowsDir, entry);
4582
+ try {
4583
+ const s = await stat(src);
4584
+ if (!s.isDirectory()) continue;
4585
+ await stat(join(src, "SKILL.md"));
4586
+ out.push(entry);
4587
+ } catch {
4588
+ }
4589
+ }
4590
+ return out;
4591
+ }
4592
+ async function runStepBInstall(manifestPaths) {
4593
+ const opts = {
4594
+ apply: true,
4595
+ dryRun: false,
4596
+ system: false,
4597
+ nonInteractive: true,
4598
+ fullDiff: false,
4599
+ color: "auto"
4600
+ };
4601
+ const start = Date.now();
4602
+ const settled = await Promise.allSettled(
4603
+ manifestPaths.map(async (path) => {
4604
+ let yamlSrc;
4605
+ try {
4606
+ yamlSrc = await readFile(path, "utf8");
4607
+ } catch (e) {
4608
+ return { status: "failed", name: path, reason: `read: ${e.message}` };
4609
+ }
4610
+ const v = validateManifestFile(yamlSrc, path);
4611
+ if (!v.ok) {
4612
+ return {
4613
+ status: "failed",
4614
+ name: path,
4615
+ reason: `validate: ${v.errors[0]?.message ?? "unknown"}`
4616
+ };
4617
+ }
4618
+ const name = v.manifest.metadata.name;
4619
+ const method = v.manifest.spec.install.method;
4620
+ if (PHASE_212.has(method)) return { status: "skipped", name };
4621
+ const r = await runInstall(v.manifest, opts);
4622
+ if ("aborted" in r) return { status: "skipped", name };
4623
+ if (r.ok && "alreadyInstalled" in r && r.alreadyInstalled)
4624
+ return { status: "already-installed", name };
4625
+ if (r.ok) return { status: "installed", name };
4626
+ return { status: "failed", name, reason: r.error.message };
4627
+ })
4628
+ );
4629
+ const installed = [];
4630
+ const alreadyInstalled = [];
4631
+ const skipped = [];
4632
+ const failed = [];
4633
+ for (const s of settled) {
4634
+ const v = s.status === "fulfilled" ? s.value : {
4635
+ status: "failed",
4636
+ name: "?",
4637
+ reason: String(s.reason)
4638
+ };
4639
+ if (v.status === "installed") installed.push(v.name);
4640
+ else if (v.status === "already-installed") alreadyInstalled.push(v.name);
4641
+ else if (v.status === "skipped") skipped.push(v.name);
4642
+ else
4643
+ failed.push(`${v.name}: ${v.reason}`);
4644
+ }
4645
+ return { installed, alreadyInstalled, skipped, failed, elapsedMs: Date.now() - start };
4646
+ }
4647
+
4648
+ // src/cli/setup.ts
4307
4649
  async function listBaseManifests2(pkgRoot) {
4308
4650
  const out = [];
4309
4651
  for (const d of ["manifests/tools", "manifests/skill-packs"]) {
@@ -4323,6 +4665,7 @@ function registerSetup(program2) {
4323
4665
  const pkgRoot = getPackageRoot();
4324
4666
  const workflowsDir = resolve(pkgRoot, "workflows");
4325
4667
  const skillsBase = resolve(homedir(), ".claude", "skills");
4668
+ await warnIfAgentTeamsMissing();
4326
4669
  let entries;
4327
4670
  try {
4328
4671
  entries = await readdir(workflowsDir);
@@ -4330,17 +4673,7 @@ function registerSetup(program2) {
4330
4673
  console.error(`error: workflows directory not found at ${workflowsDir}`);
4331
4674
  process.exit(1);
4332
4675
  }
4333
- const toInstall = [];
4334
- for (const entry of entries.sort()) {
4335
- const src = join(workflowsDir, entry);
4336
- try {
4337
- const s = await stat(src);
4338
- if (!s.isDirectory()) continue;
4339
- await stat(join(src, "SKILL.md"));
4340
- toInstall.push(entry);
4341
- } catch {
4342
- }
4343
- }
4676
+ const toInstall = await scanWorkflowsWithSkill(workflowsDir, entries);
4344
4677
  if (toInstall.length === 0) {
4345
4678
  console.log("setup: no workflow directories with SKILL.md found \u2014 nothing to install");
4346
4679
  process.exit(2);
@@ -4372,88 +4705,35 @@ function registerSetup(program2) {
4372
4705
  `
4373
4706
  Step A complete: ${skillsInstalled} workflow skill(s) installed to ${skillsBase}`
4374
4707
  );
4375
- const opts = {
4376
- apply: true,
4377
- dryRun: false,
4378
- system: false,
4379
- nonInteractive: true,
4380
- fullDiff: false,
4381
- color: "auto"
4382
- };
4383
4708
  const manifestPaths = await listBaseManifests2(pkgRoot);
4384
- const stepBStart = Date.now();
4385
- const settled = await Promise.allSettled(
4386
- manifestPaths.map(async (path) => {
4387
- let yamlSrc;
4388
- try {
4389
- yamlSrc = await readFile(path, "utf8");
4390
- } catch (e) {
4391
- return {
4392
- status: "failed",
4393
- name: path,
4394
- reason: `read: ${e.message}`
4395
- };
4396
- }
4397
- const v = validateManifestFile(yamlSrc, path);
4398
- if (!v.ok) {
4399
- return {
4400
- status: "failed",
4401
- name: path,
4402
- reason: `validate: ${v.errors[0]?.message ?? "unknown"}`
4403
- };
4404
- }
4405
- const name = v.manifest.metadata.name;
4406
- const method = v.manifest.spec.install.method;
4407
- if (PHASE_212.has(method)) {
4408
- return { status: "skipped", name };
4409
- }
4410
- const r = await runInstall(v.manifest, opts);
4411
- if ("aborted" in r) return { status: "skipped", name };
4412
- if (r.ok && "alreadyInstalled" in r && r.alreadyInstalled)
4413
- return { status: "already-installed", name };
4414
- if (r.ok) return { status: "installed", name };
4415
- return { status: "failed", name, reason: r.error.message };
4416
- })
4417
- );
4418
- const baseInstalled = [];
4419
- const baseAlreadyInstalled = [];
4420
- const baseSkipped = [];
4421
- const baseFailed = [];
4422
- for (const s of settled) {
4423
- const v = s.status === "fulfilled" ? s.value : {
4424
- status: "failed",
4425
- name: "?",
4426
- reason: String(s.reason)
4427
- };
4428
- if (v.status === "installed") baseInstalled.push(v.name);
4429
- else if (v.status === "already-installed") baseAlreadyInstalled.push(v.name);
4430
- else if (v.status === "skipped") baseSkipped.push(v.name);
4431
- else
4432
- baseFailed.push(
4433
- `${v.name}: ${v.reason}`
4434
- );
4435
- }
4436
- const stepBMs = ((Date.now() - stepBStart) / 1e3).toFixed(1);
4709
+ const b = await runStepBInstall(manifestPaths);
4710
+ const stepBMs = (b.elapsedMs / 1e3).toFixed(1);
4437
4711
  console.log(
4438
- `Step B complete: ${baseInstalled.length} manifest(s) installed / ${baseAlreadyInstalled.length} already-installed / ${baseSkipped.length} skipped / ${baseFailed.length} failed [parallel ${stepBMs}s]`
4712
+ `Step B complete: ${b.installed.length} manifest(s) installed / ${b.alreadyInstalled.length} already-installed / ${b.skipped.length} skipped / ${b.failed.length} failed [parallel ${stepBMs}s]`
4439
4713
  );
4440
- for (const n of baseInstalled) console.log(` [B] installed ${n}`);
4441
- for (const n of baseAlreadyInstalled)
4714
+ for (const n of b.installed) console.log(` [B] installed ${n}`);
4715
+ for (const n of b.alreadyInstalled)
4442
4716
  console.log(
4443
4717
  ` [B] already-installed ${n} \u2014 run \`/mcp\` in Claude Code to verify connection`
4444
4718
  );
4445
- for (const n of baseSkipped) console.log(` [B] skipped ${n}`);
4446
- for (const n of baseFailed) console.error(` [B] failed ${n}`);
4719
+ for (const n of b.skipped) console.log(` [B] skipped ${n}`);
4720
+ for (const n of b.failed) console.error(` [B] failed ${n}`);
4447
4721
  console.log(
4448
4722
  `
4449
- setup complete: ${skillsInstalled} workflow skill(s) + ${baseInstalled.length + baseAlreadyInstalled.length} base manifest(s) configured`
4723
+ setup complete: ${skillsInstalled} workflow skill(s) + ${b.installed.length + b.alreadyInstalled.length} base manifest(s) configured`
4450
4724
  );
4451
- if (baseAlreadyInstalled.length > 0 || baseInstalled.length > 0) {
4725
+ if (b.alreadyInstalled.length > 0 || b.installed.length > 0) {
4452
4726
  console.log(
4453
4727
  `
4454
4728
  MCP servers configured. Run \`/mcp\` in Claude Code to verify each server's connection status. If a server shows disconnected, restart Claude Code or check the MCP command spec.`
4455
4729
  );
4456
4730
  }
4731
+ console.log(
4732
+ "\n\u2713 harnessed v2.0 \u4E09\u5C42\u6808\u65B9\u6CD5\u8BBA bundled \u2014 4 workflows + 6 judgments + 37 capabilities ready"
4733
+ );
4734
+ console.log(
4735
+ " workflows in <packageRoot>/workflows/ (Pure bundled, NOT user-dir override per D-01)"
4736
+ );
4457
4737
  process.exit(0);
4458
4738
  });
4459
4739
  }
@@ -4678,7 +4958,7 @@ var uninstallNpmCli = async (ctx) => {
4678
4958
  const m = install.cmd.match(/npm\s+(?:install|i)\s+(?:-g\s+)?(\S+)/);
4679
4959
  const pkg = m?.[1] ?? ctx.manifest.metadata.upstream.source;
4680
4960
  const isWin = process.platform === "win32";
4681
- const result = await new Promise((resolve10) => {
4961
+ const result = await new Promise((resolve11) => {
4682
4962
  const child = isWin ? spawn("cmd.exe", ["/c", "npm", "uninstall", "-g", pkg], { windowsHide: true }) : spawn("npm", ["uninstall", "-g", pkg], { shell: false });
4683
4963
  let stderr = "";
4684
4964
  child.stderr?.setEncoding("utf8").on("data", (c) => {
@@ -4686,15 +4966,15 @@ var uninstallNpmCli = async (ctx) => {
4686
4966
  });
4687
4967
  const timer = setTimeout(() => {
4688
4968
  child.kill("SIGKILL");
4689
- resolve10({ exitCode: -1, stderr: `${stderr}[timeout]` });
4969
+ resolve11({ exitCode: -1, stderr: `${stderr}[timeout]` });
4690
4970
  }, 3e4);
4691
4971
  child.on("error", (e) => {
4692
4972
  clearTimeout(timer);
4693
- resolve10({ exitCode: -1, stderr: e.message });
4973
+ resolve11({ exitCode: -1, stderr: e.message });
4694
4974
  });
4695
4975
  child.on("close", (code) => {
4696
4976
  clearTimeout(timer);
4697
- resolve10({ exitCode: code ?? -1, stderr });
4977
+ resolve11({ exitCode: code ?? -1, stderr });
4698
4978
  });
4699
4979
  });
4700
4980
  if (result.exitCode !== 0) {