harnessed 3.5.0 → 3.6.1

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.
@@ -0,0 +1,34 @@
1
+ # Third-Party Notices
2
+
3
+ `harnessed` itself is licensed under the Apache License 2.0 (see `LICENSE` and
4
+ `NOTICE` at the repo root). This file enumerates third-party material whose
5
+ text — verbatim or paraphrased — is incorporated into shipped harnessed source
6
+ files. Upstream attributions for each capability *manifest* (and its installed
7
+ side effects on the user's machine) continue to be tracked separately in
8
+ `NOTICES.md` (auto-populated by `harnessed install` from each manifest's
9
+ `metadata.upstream.notice` field).
10
+
11
+ ---
12
+
13
+ ## mattpocock/skills
14
+
15
+ - **Source**: https://github.com/mattpocock/skills
16
+ - **Commit SHA pinned**: `b8be62ffacb0118fa3eaa29a0923c87c8c11985c`
17
+ - **License**: MIT
18
+ - **Used in**: `workflows/role-prompts.yaml` — paraphrased methodology
19
+ excerpts inlined into the `task-clarify`, `task-code`, and `discuss-subtask`
20
+ sub-workflow role-prompt entries (introduced in v3.6.0 Phase 1). Each
21
+ paraphrased block carries an inline attribution comment naming the source
22
+ SKILL.md path and the pinned commit SHA.
23
+ - **Excerpts paraphrased (not redistributed verbatim)**:
24
+ - `skills/engineering/grill-with-docs/SKILL.md` → `task-clarify.responsibility` + checklist
25
+ - `skills/engineering/zoom-out/SKILL.md` → `task-code.checklist`
26
+ - `skills/engineering/improve-codebase-architecture/SKILL.md` → `task-code.checklist`
27
+ - `skills/productivity/grill-me/SKILL.md` → `discuss-subtask.responsibility` + checklist
28
+ - **Full upstream license text**: preserved at
29
+ `.planning/v3.6.0/mattpocock-source/LICENSE` (not shipped in the npm
30
+ tarball; retained for audit + license-compliance evidence). The SHA
31
+ metadata + re-fetch instructions live in
32
+ `.planning/v3.6.0/mattpocock-source/SHA.txt`.
33
+ - **Scope of redistribution**: only the paraphrased excerpts above are
34
+ redistributed (no verbatim SKILL.md content ships in the npm tarball).
package/dist/cli.mjs CHANGED
@@ -621,6 +621,105 @@ var init_check_planning_with_files = __esm({
621
621
  REMEDIATION = "install via Claude Code plugin marketplace: `claude plugin install planning-with-files` (requires >=2.2.0 per R20.15 + D-15)";
622
622
  }
623
623
  });
624
+
625
+ // src/cli/lib/check-mattpocock-skills.ts
626
+ var check_mattpocock_skills_exports = {};
627
+ __export(check_mattpocock_skills_exports, {
628
+ checkMattpocockSkills: () => checkMattpocockSkills
629
+ });
630
+ async function checkMattpocockSkills() {
631
+ const pluginRoot = join(
632
+ homedir(),
633
+ ".claude",
634
+ "plugins",
635
+ "cache",
636
+ "mattpocock-skills",
637
+ "mattpocock-skills"
638
+ );
639
+ const skillRoot = join(homedir(), ".claude", "skills", "mattpocock-skills");
640
+ try {
641
+ const entries = await readdir(pluginRoot);
642
+ const versions = entries.filter((e) => /^\d+\.\d+/.test(e));
643
+ if (versions.length > 0) {
644
+ return {
645
+ name: "mattpocock-skills",
646
+ status: "pass",
647
+ message: `installed as plugin (version ${versions.join(", ")})`
648
+ };
649
+ }
650
+ } catch {
651
+ }
652
+ try {
653
+ await stat(skillRoot);
654
+ return {
655
+ name: "mattpocock-skills",
656
+ status: "pass",
657
+ message: `installed as user-skill (${skillRoot})`
658
+ };
659
+ } catch {
660
+ }
661
+ return {
662
+ name: "mattpocock-skills",
663
+ status: "warn",
664
+ message: "not installed (plugin cache + user-skill paths both missing)",
665
+ fix: REMEDIATION2
666
+ };
667
+ }
668
+ var REMEDIATION2;
669
+ var init_check_mattpocock_skills = __esm({
670
+ "src/cli/lib/check-mattpocock-skills.ts"() {
671
+ REMEDIATION2 = "install via Claude Code plugin marketplace: `claude plugin install mattpocock-skills` (or git clone https://github.com/mattpocock/skills ~/.claude/skills/mattpocock-skills); methodology fallback already inline in role-prompts.yaml per v3.6.0 Phase 1 \u2014 install is optional but enables /grill-with-docs /zoom-out etc. SlashCommand acceleration";
672
+ }
673
+ });
674
+
675
+ // src/cli/lib/check-mcp-availability.ts
676
+ var check_mcp_availability_exports = {};
677
+ __export(check_mcp_availability_exports, {
678
+ checkMcpAvailability: () => checkMcpAvailability
679
+ });
680
+ async function checkMcpAvailability() {
681
+ const settingsPath3 = join(homedir(), ".claude", "settings.json");
682
+ let installed = [];
683
+ let missing = [...TARGET_SERVERS];
684
+ try {
685
+ const raw = await readFile(settingsPath3, "utf8");
686
+ const parsed = JSON.parse(raw);
687
+ const servers = parsed.mcpServers ?? {};
688
+ const serverNames = Object.keys(servers);
689
+ installed = TARGET_SERVERS.filter(
690
+ (s) => serverNames.some((n) => n.includes(s) || s.includes(n))
691
+ );
692
+ missing = TARGET_SERVERS.filter((s) => !installed.includes(s));
693
+ } catch {
694
+ }
695
+ if (missing.length === 0) {
696
+ return {
697
+ name: "MCP servers (tavily/exa/chrome-devtools)",
698
+ status: "pass",
699
+ message: `all 3 installed: ${installed.join(", ")}`
700
+ };
701
+ }
702
+ if (installed.length === 0) {
703
+ return {
704
+ name: "MCP servers (tavily/exa/chrome-devtools)",
705
+ status: "warn",
706
+ message: "none of 3 target MCP servers installed in ~/.claude/settings.json",
707
+ fix: "install via `claude mcp add <server-name>`; harnessed routes web-search to tavily/exa per workflows/judgments/web-search-routing.yaml \u2014 without them, falls back to WebFetch/WebSearch built-in (degraded but functional)"
708
+ };
709
+ }
710
+ return {
711
+ name: "MCP servers (tavily/exa/chrome-devtools)",
712
+ status: "warn",
713
+ message: `${installed.length}/3 installed: ${installed.join(", ")}; missing: ${missing.join(", ")}`,
714
+ fix: `install missing via \`claude mcp add ${missing.join(" && claude mcp add ")}\``
715
+ };
716
+ }
717
+ var TARGET_SERVERS;
718
+ var init_check_mcp_availability = __esm({
719
+ "src/cli/lib/check-mcp-availability.ts"() {
720
+ TARGET_SERVERS = ["tavily-mcp", "exa-mcp", "chrome-devtools"];
721
+ }
722
+ });
624
723
  function statePath() {
625
724
  return harnessedFile("current-workflow.json");
626
725
  }
@@ -853,7 +952,7 @@ var init_resume = __esm({
853
952
 
854
953
  // package.json
855
954
  var package_default = {
856
- version: "3.5.0"};
955
+ version: "3.6.1"};
857
956
 
858
957
  // src/manifest/errors.ts
859
958
  function instancePathToKeyPath(instancePath) {
@@ -1704,7 +1803,7 @@ function renderHumanTable(records) {
1704
1803
  }
1705
1804
  }
1706
1805
  function pipeToJq(filterExpr, lines) {
1707
- return new Promise((resolve14, reject) => {
1806
+ return new Promise((resolve15, reject) => {
1708
1807
  const child = spawn("jq", [filterExpr], {
1709
1808
  stdio: ["pipe", "inherit", "inherit"],
1710
1809
  windowsHide: true
@@ -1713,12 +1812,12 @@ function pipeToJq(filterExpr, lines) {
1713
1812
  const e = err2;
1714
1813
  if (e.code === "ENOENT") {
1715
1814
  console.error(t("audit_log.jq_missing"));
1716
- resolve14(1);
1815
+ resolve15(1);
1717
1816
  } else {
1718
1817
  reject(err2);
1719
1818
  }
1720
1819
  });
1721
- child.on("close", (code) => resolve14(code ?? 0));
1820
+ child.on("close", (code) => resolve15(code ?? 0));
1722
1821
  child.stdin.write(lines.join("\n"));
1723
1822
  child.stdin.end();
1724
1823
  });
@@ -2026,18 +2125,26 @@ async function checkAgentTeamsEnv() {
2026
2125
  async function checkPlanningPlugin() {
2027
2126
  return (await Promise.resolve().then(() => (init_check_planning_with_files(), check_planning_with_files_exports))).checkPlanningWithFiles();
2028
2127
  }
2128
+ async function checkMattpocockSkillsInstall() {
2129
+ return (await Promise.resolve().then(() => (init_check_mattpocock_skills(), check_mattpocock_skills_exports))).checkMattpocockSkills();
2130
+ }
2131
+ async function checkMcpAvailabilityCheck() {
2132
+ return (await Promise.resolve().then(() => (init_check_mcp_availability(), check_mcp_availability_exports))).checkMcpAvailability();
2133
+ }
2029
2134
  function registerDoctor(program2) {
2030
2135
  program2.command("doctor").description(
2031
- "Preflight checks (Node / MCP scope / jq / Win bash / origin URL / gstack prefix / deprecations / token budget / Agent Teams / planning-with-files)"
2136
+ "Preflight checks (Node / MCP scope / jq / Win bash / origin URL / gstack prefix / deprecations / token budget / Agent Teams / planning-with-files / mattpocock-skills / MCP availability)"
2032
2137
  ).option("--json", "output JSON instead of human-readable").action(async (opts) => {
2033
- const [mcp, origin, gstack, dep, tok, at, ppwf] = await Promise.all([
2138
+ const [mcp, origin, gstack, dep, tok, at, ppwf, matt, mcpAvail] = await Promise.all([
2034
2139
  checkMcpScope(),
2035
2140
  checkOriginUrl(),
2036
2141
  checkGstackPrefix(),
2037
2142
  checkDeprecations2(),
2038
2143
  checkTokenBudget2(),
2039
2144
  checkAgentTeamsEnv(),
2040
- checkPlanningPlugin()
2145
+ checkPlanningPlugin(),
2146
+ checkMattpocockSkillsInstall(),
2147
+ checkMcpAvailabilityCheck()
2041
2148
  ]);
2042
2149
  const results = [
2043
2150
  checkNodeVersion(),
@@ -2049,7 +2156,9 @@ function registerDoctor(program2) {
2049
2156
  dep,
2050
2157
  tok,
2051
2158
  at,
2052
- ppwf
2159
+ ppwf,
2160
+ matt,
2161
+ mcpAvail
2053
2162
  ];
2054
2163
  const hasFail = results.some((r) => r.status === "fail");
2055
2164
  const hasWarn = results.some((r) => r.status === "warn");
@@ -2530,6 +2639,22 @@ var JudgmentRulesFile = Type.Object(
2530
2639
  { additionalProperties: false }
2531
2640
  );
2532
2641
  Type.Union([JudgmentTriggersFile, JudgmentRulesFile]);
2642
+ var UserOverrideEntry = Type.Object(
2643
+ {
2644
+ id: Type.String({ minLength: 1 }),
2645
+ // kebab-case (e.g. 'brainstorm', 'arch-review')
2646
+ keywords: Type.Array(Type.String({ minLength: 1 }), { minItems: 1 }),
2647
+ triggers: Type.Array(Type.String({ minLength: 1 }), { minItems: 1 })
2648
+ },
2649
+ { additionalProperties: false }
2650
+ );
2651
+ var UserOverridesFile = Type.Object(
2652
+ {
2653
+ schema_version: Type.Literal("harnessed.user-overrides.v1"),
2654
+ overrides: Type.Array(UserOverrideEntry, { minItems: 1 })
2655
+ },
2656
+ { additionalProperties: false }
2657
+ );
2533
2658
 
2534
2659
  // src/workflow/judgmentResolver.ts
2535
2660
  var TriggerNotFoundError = class extends Error {
@@ -2544,6 +2669,10 @@ var TriggerNotFoundError = class extends Error {
2544
2669
  };
2545
2670
  var _fileCache = /* @__PURE__ */ new Map();
2546
2671
  async function resolveJudgmentGate(gateRef, context, packageRoot) {
2672
+ const userOverrides = context.user_overrides;
2673
+ if (Array.isArray(userOverrides) && userOverrides.includes(gateRef)) {
2674
+ return true;
2675
+ }
2547
2676
  const parts = gateRef.split(".");
2548
2677
  if (parts.length !== 4 || parts[0] !== "judgments") {
2549
2678
  throw new Error(`Invalid gate ref: ${gateRef}`);
@@ -3193,13 +3322,33 @@ Five triggers (any one suffices):
3193
3322
  5. **fullstack_three_way** \u2014 the task is a synchronized fullstack push (frontend + backend + tests) requiring API contract alignment across three roles simultaneously.
3194
3323
 
3195
3324
  If none of the five apply, omit \`needs_teams_escalation\` (defaults to false) and proceed normally.`;
3325
+ var TRANSPARENT_SKIP_RULES = `When you encounter a phase gate or routing decision where the input context is missing key fields, default-valued, or contradictory, do NOT proceed silently. Instead, skip the phase and emit a one-line transparent explanation:
3326
+
3327
+ "Skipped <phase>, because <reason>. Tell me if you actually need it."
3328
+ (\u4E2D\u6587: "\u8FD9\u6B21\u8DF3\u8FC7\u4E86 <phase>, \u56E0\u4E3A <reason>. \u5982\u679C\u4F60\u8BA4\u4E3A\u9700\u8981\u8BF7\u660E\u8BF4.")
3329
+
3330
+ This applies to: strategic-layer review skip / phase-layer clarification skip / subtask-brainstorming skip / TDD enforcement skip / Agent Teams escalation skip. Chain-isolation rule: skipping one layer does NOT mandate skipping subsequent layers \u2014 each layer is independently evaluated.`;
3331
+ var AGENT_TEAMS_PREVENTION_RULES = `If you signal needs_teams_escalation=true, ALSO advise the user on these 4 Agent Teams prevention rules in your escalation_reason or summary (the user will be the one calling TeamCreate / SendMessage / TeamDelete; remind them upfront):
3332
+
3333
+ 1. **Session-scoped**: Teams live only in the current Claude Code session. \`/resume\` loses all teammates. Do not treat teams as persistent state \u2014 finish team work within one session.
3334
+
3335
+ 2. **Cleanup mandatory**: Before session ends, send \`SendMessage(to=<teammate>, content="shutdown_request")\` to each teammate, then call \`TeamDelete\`. Orphan teammates consume resources. This is a hard rule, not advisory.
3336
+
3337
+ 3. **Token cost estimation**: Before creating a team, estimate \`team_cost \u2248 N_teammates \xD7 N_rounds \xD7 avg_tokens_per_round + N_teammates \xD7 initial_brief_tokens\`. Compare to subagent fan-out cost (\`\u2248 N_subagents \xD7 (initial_brief + summary_tokens)\`). Only open a team when \`team_cost < 2 \xD7 subagent_cost\` \u2014 otherwise prefer fan-out.
3338
+
3339
+ 4. **Brief must be self-contained**: Each teammate launches WITHOUT main-session context. The Agent() prompt must include enough background, file paths, success criteria, and counter-positions so the teammate can work independently. Generic prompts produce shallow output.`;
3340
+ var CRITICAL_SYSTEM_REMINDER = `${ESCALATION_RULES}
3341
+
3342
+ ${TRANSPARENT_SKIP_RULES}
3343
+
3344
+ ${AGENT_TEAMS_PREVENTION_RULES}`;
3196
3345
  function buildAgentDef(skillName, rolePrompts, workflowName, modelTierOverride) {
3197
3346
  const rp = rolePrompts?.[skillName] ?? (workflowName ? rolePrompts?.[workflowName] : void 0);
3198
3347
  if (!rp) {
3199
3348
  return {
3200
3349
  description: `harnessed workflow phase: ${skillName}`,
3201
3350
  prompt: `You are executing the '${skillName}' workflow phase. Follow the phase intent and emit a structured COMPLETE signal when done.`,
3202
- criticalSystemReminder_EXPERIMENTAL: ESCALATION_RULES,
3351
+ criticalSystemReminder_EXPERIMENTAL: CRITICAL_SYSTEM_REMINDER,
3203
3352
  ...modelTierOverride ? { model: modelTierOverride } : {}
3204
3353
  };
3205
3354
  }
@@ -3220,7 +3369,7 @@ ${rp.checklist.map((c, i) => ` ${i + 1}. ${c}`).join("\n")}` : "";
3220
3369
  return {
3221
3370
  description: rp.description,
3222
3371
  prompt,
3223
- criticalSystemReminder_EXPERIMENTAL: ESCALATION_RULES,
3372
+ criticalSystemReminder_EXPERIMENTAL: CRITICAL_SYSTEM_REMINDER,
3224
3373
  ...modelTierOverride ? { model: modelTierOverride } : {}
3225
3374
  };
3226
3375
  }
@@ -3436,6 +3585,46 @@ function getPackageRoot() {
3436
3585
  }
3437
3586
  return resolve(thisDir, "..", "..", "..");
3438
3587
  }
3588
+ async function loadUserOverrides(packageRoot) {
3589
+ const yamlPath = resolve(packageRoot, "workflows", "judgments", "user-overrides.yaml");
3590
+ let raw;
3591
+ try {
3592
+ raw = await readFile(yamlPath, "utf8");
3593
+ } catch {
3594
+ return [];
3595
+ }
3596
+ let parsed;
3597
+ try {
3598
+ parsed = parse(raw);
3599
+ } catch {
3600
+ return [];
3601
+ }
3602
+ if (!Value.Check(UserOverridesFile, parsed)) {
3603
+ return [];
3604
+ }
3605
+ const valid = parsed;
3606
+ return valid.overrides.map((o) => ({
3607
+ id: o.id,
3608
+ keywords: [...o.keywords],
3609
+ triggers: [...o.triggers]
3610
+ }));
3611
+ }
3612
+ function extractMatchedTriggers(userText, overrides) {
3613
+ if (!userText || overrides.length === 0) return [];
3614
+ const haystack = userText.toLowerCase();
3615
+ const matched = /* @__PURE__ */ new Set();
3616
+ for (const entry of overrides) {
3617
+ for (const kw of entry.keywords) {
3618
+ if (haystack.includes(kw.toLowerCase())) {
3619
+ for (const trigger of entry.triggers) matched.add(trigger);
3620
+ break;
3621
+ }
3622
+ }
3623
+ }
3624
+ return [...matched];
3625
+ }
3626
+
3627
+ // src/cli/run.ts
3439
3628
  var PACKAGE_ROOT = getPackageRoot();
3440
3629
  var WORKFLOWS_DIR = join(PACKAGE_ROOT, "workflows");
3441
3630
  var _autoChainCache = null;
@@ -3473,11 +3662,19 @@ function registerRun(program2) {
3473
3662
  );
3474
3663
  process.exit(2);
3475
3664
  }
3665
+ const overrides = await loadUserOverrides(PACKAGE_ROOT);
3666
+ const matchedTriggers = extractMatchedTriggers(task, overrides);
3667
+ if (matchedTriggers.length > 0) {
3668
+ console.error(
3669
+ `\u2139 user-override detected: ${matchedTriggers.length} trigger(s) forced fires=true via keyword match (${matchedTriggers.join(", ")})`
3670
+ );
3671
+ }
3476
3672
  const gateContext = {
3477
3673
  task,
3478
3674
  ...raw.model ? { modelOverride: raw.model } : {},
3479
3675
  ...raw.maxIterations ? { maxIterations: raw.maxIterations } : {},
3480
- ...raw.staged ? { staged: true } : {}
3676
+ ...raw.staged ? { staged: true } : {},
3677
+ ...matchedTriggers.length > 0 ? { user_overrides: matchedTriggers } : {}
3481
3678
  };
3482
3679
  if (raw.dryRun) {
3483
3680
  console.log(JSON.stringify({ workflow: name, yamlPath, gateContext }, null, 2));
@@ -4052,7 +4249,7 @@ async function isPluginRegistered(pluginName) {
4052
4249
  return Object.keys(plugins).some((k) => k.split("@")[0] === pluginName);
4053
4250
  }
4054
4251
  function runArgs(claudeArgs, cwd, timeoutMs = 15e3) {
4055
- return new Promise((resolve14) => {
4252
+ return new Promise((resolve15) => {
4056
4253
  const isWin = process.platform === "win32";
4057
4254
  const child = isWin ? spawn("cmd.exe", ["/c", "claude", ...claudeArgs], { cwd, windowsHide: true }) : spawn("claude", claudeArgs, { cwd, shell: false });
4058
4255
  let stderr = "";
@@ -4061,15 +4258,15 @@ function runArgs(claudeArgs, cwd, timeoutMs = 15e3) {
4061
4258
  });
4062
4259
  const timer = setTimeout(() => {
4063
4260
  child.kill("SIGKILL");
4064
- resolve14({ exitCode: -1, stderr: `${stderr}[timeout after ${timeoutMs}ms]` });
4261
+ resolve15({ exitCode: -1, stderr: `${stderr}[timeout after ${timeoutMs}ms]` });
4065
4262
  }, timeoutMs);
4066
4263
  child.on("error", (e) => {
4067
4264
  clearTimeout(timer);
4068
- resolve14({ exitCode: -1, stderr: `${stderr}${e.message}` });
4265
+ resolve15({ exitCode: -1, stderr: `${stderr}${e.message}` });
4069
4266
  });
4070
4267
  child.on("close", (code) => {
4071
4268
  clearTimeout(timer);
4072
- resolve14({ exitCode: code ?? -1, stderr });
4269
+ resolve15({ exitCode: code ?? -1, stderr });
4073
4270
  });
4074
4271
  });
4075
4272
  }
@@ -4248,10 +4445,10 @@ async function spawnCmd(ctx, cmd, args, timeoutMs) {
4248
4445
  child.stderr?.setEncoding("utf8").on("data", (chunk) => {
4249
4446
  stderr += chunk;
4250
4447
  });
4251
- return await new Promise((resolve14) => {
4448
+ return await new Promise((resolve15) => {
4252
4449
  const timer = setTimeout(() => {
4253
4450
  child.kill("SIGKILL");
4254
- resolve14({
4451
+ resolve15({
4255
4452
  ok: false,
4256
4453
  phase: "spawn",
4257
4454
  error: {
@@ -4266,7 +4463,7 @@ async function spawnCmd(ctx, cmd, args, timeoutMs) {
4266
4463
  }, effectiveTimeoutMs);
4267
4464
  child.on("error", (err2) => {
4268
4465
  clearTimeout(timer);
4269
- resolve14({
4466
+ resolve15({
4270
4467
  ok: false,
4271
4468
  phase: "spawn",
4272
4469
  error: {
@@ -4281,14 +4478,14 @@ async function spawnCmd(ctx, cmd, args, timeoutMs) {
4281
4478
  });
4282
4479
  child.on("close", (code) => {
4283
4480
  clearTimeout(timer);
4284
- resolve14({ ok: true, exitCode: code ?? -1, stdout: stdout2, stderr });
4481
+ resolve15({ ok: true, exitCode: code ?? -1, stdout: stdout2, stderr });
4285
4482
  });
4286
4483
  });
4287
4484
  }
4288
4485
 
4289
4486
  // src/installers/gitCloneWithSetup.ts
4290
4487
  function gitRevParseHead(cwd, timeoutMs = 1e4) {
4291
- return new Promise((resolve14) => {
4488
+ return new Promise((resolve15) => {
4292
4489
  const isWin = process.platform === "win32";
4293
4490
  const child = isWin ? spawn("cmd.exe", ["/c", "git", "rev-parse", "HEAD"], { cwd, windowsHide: true }) : spawn("git", ["rev-parse", "HEAD"], { cwd, shell: false });
4294
4491
  let stdout2 = "";
@@ -4297,15 +4494,15 @@ function gitRevParseHead(cwd, timeoutMs = 1e4) {
4297
4494
  });
4298
4495
  const timer = setTimeout(() => {
4299
4496
  child.kill("SIGKILL");
4300
- resolve14({ sha: "", exit: -1 });
4497
+ resolve15({ sha: "", exit: -1 });
4301
4498
  }, timeoutMs);
4302
4499
  child.on("error", () => {
4303
4500
  clearTimeout(timer);
4304
- resolve14({ sha: "", exit: -1 });
4501
+ resolve15({ sha: "", exit: -1 });
4305
4502
  });
4306
4503
  child.on("close", (code) => {
4307
4504
  clearTimeout(timer);
4308
- resolve14({ sha: stdout2.trim(), exit: code ?? -1 });
4505
+ resolve15({ sha: stdout2.trim(), exit: code ?? -1 });
4309
4506
  });
4310
4507
  });
4311
4508
  }
@@ -5151,7 +5348,7 @@ function registerInstallBase(program2) {
5151
5348
  }
5152
5349
  console.log(
5153
5350
  `
5154
- installed: ${installed.length} / already-installed: ${alreadyInstalled.length} / skipped (deferred phase 2.1): ${skipped.length} / failed: ${failed.length}`
5351
+ installed: ${installed.length} / already-installed: ${alreadyInstalled.length} / skipped (deferred installer methods awaiting phase 2.1): ${skipped.length} / failed: ${failed.length}`
5155
5352
  );
5156
5353
  for (const i of installed) console.log(` installed ${i}`);
5157
5354
  for (const a of alreadyInstalled)
@@ -5676,13 +5873,18 @@ async function renderAllSkills(skillNames, skillsBase, workflowsDir, homedirOver
5676
5873
  return { results, aggregatedWarnings: [...warningSet] };
5677
5874
  }
5678
5875
  init_checkAgentTeams();
5679
- var FLAT_LEGACY_DEPRECATED = /* @__PURE__ */ new Set(["plan-feature", "execute-task", "verify-work"]);
5680
- var FLAT_LEGACY_KEEP = /* @__PURE__ */ new Set(["research", "retro", "auto"]);
5876
+ var FLAT_LEGACY_KEEP = /* @__PURE__ */ new Set([
5877
+ "research",
5878
+ "retro",
5879
+ "auto",
5880
+ "execute-task",
5881
+ "plan-feature",
5882
+ "verify-work"
5883
+ ]);
5681
5884
  var FLAT_TOP_LEVEL_MASTERS = /* @__PURE__ */ new Set(["auto"]);
5682
5885
  var NON_WORKFLOW_DIRS = /* @__PURE__ */ new Set(["disciplines", "judgments"]);
5683
5886
  async function scanWorkflowsNested(workflowsDir, entries) {
5684
5887
  const workflows = [];
5685
- const deprecated = [];
5686
5888
  for (const entry of entries.sort()) {
5687
5889
  if (NON_WORKFLOW_DIRS.has(entry)) continue;
5688
5890
  const src = join(workflowsDir, entry);
@@ -5701,10 +5903,6 @@ async function scanWorkflowsNested(workflowsDir, entries) {
5701
5903
  hasFlatSkill = false;
5702
5904
  }
5703
5905
  if (hasFlatSkill) {
5704
- if (FLAT_LEGACY_DEPRECATED.has(entry)) {
5705
- deprecated.push(entry);
5706
- continue;
5707
- }
5708
5906
  if (FLAT_LEGACY_KEEP.has(entry)) {
5709
5907
  workflows.push({ name: entry, relPath: entry, isMaster: FLAT_TOP_LEVEL_MASTERS.has(entry) });
5710
5908
  continue;
@@ -5736,20 +5934,7 @@ async function scanWorkflowsNested(workflowsDir, entries) {
5736
5934
  workflows.push({ name, relPath: `${entry}/${sub}`, isMaster: sub === "auto" });
5737
5935
  }
5738
5936
  }
5739
- return { workflows, deprecated };
5740
- }
5741
- function renderDeprecationBlock(deprecated) {
5742
- if (deprecated.length === 0) return "";
5743
- return [
5744
- "\u26A0\uFE0F v3.0 BREAKING \u2014 v2 legacy slash cmd deprecated:",
5745
- " /plan-feature \u2192 /plan (master) | /plan-phase (sub)",
5746
- " /execute-task \u2192 /task (master) | /task-{clarify,code,test,deliver} (sub)",
5747
- " /verify-work \u2192 /verify (master) | /verify-{progress,paranoid,qa,security,design,simplify,multispec} (sub)",
5748
- " /research, /retro \u4E0D\u53D8",
5749
- " \u8BE6\u89C1 CHANGELOG [3.0.0]",
5750
- ` skipped install: ${deprecated.sort().join(", ")}`,
5751
- ""
5752
- ].join("\n");
5937
+ return { workflows };
5753
5938
  }
5754
5939
 
5755
5940
  // src/cli/lib/setup-helpers.ts
@@ -5861,12 +6046,7 @@ function registerSetup(program2) {
5861
6046
  console.error(t("setup.workflows_not_found", { path: workflowsDir }));
5862
6047
  process.exit(1);
5863
6048
  }
5864
- const { workflows: toInstall, deprecated } = await scanWorkflowsWithSkill(
5865
- workflowsDir,
5866
- entries
5867
- );
5868
- const depBlock = renderDeprecationBlock(deprecated);
5869
- if (depBlock) console.log(depBlock);
6049
+ const { workflows: toInstall } = await scanWorkflowsWithSkill(workflowsDir, entries);
5870
6050
  if (toInstall.length === 0) {
5871
6051
  console.log(t("setup.nothing_to_install"));
5872
6052
  process.exit(2);
@@ -6238,7 +6418,7 @@ var uninstallNpmCli = async (ctx) => {
6238
6418
  const m = install.cmd.match(/npm\s+(?:install|i)\s+(?:-g\s+)?(\S+)/);
6239
6419
  const pkg = m?.[1] ?? ctx.manifest.metadata.upstream.source;
6240
6420
  const isWin = process.platform === "win32";
6241
- const result = await new Promise((resolve14) => {
6421
+ const result = await new Promise((resolve15) => {
6242
6422
  const child = isWin ? spawn("cmd.exe", ["/c", "npm", "uninstall", "-g", pkg], { windowsHide: true }) : spawn("npm", ["uninstall", "-g", pkg], { shell: false });
6243
6423
  let stderr = "";
6244
6424
  child.stderr?.setEncoding("utf8").on("data", (c) => {
@@ -6246,15 +6426,15 @@ var uninstallNpmCli = async (ctx) => {
6246
6426
  });
6247
6427
  const timer = setTimeout(() => {
6248
6428
  child.kill("SIGKILL");
6249
- resolve14({ exitCode: -1, stderr: `${stderr}[timeout]` });
6429
+ resolve15({ exitCode: -1, stderr: `${stderr}[timeout]` });
6250
6430
  }, 3e4);
6251
6431
  child.on("error", (e) => {
6252
6432
  clearTimeout(timer);
6253
- resolve14({ exitCode: -1, stderr: e.message });
6433
+ resolve15({ exitCode: -1, stderr: e.message });
6254
6434
  });
6255
6435
  child.on("close", (code) => {
6256
6436
  clearTimeout(timer);
6257
- resolve14({ exitCode: code ?? -1, stderr });
6437
+ resolve15({ exitCode: code ?? -1, stderr });
6258
6438
  });
6259
6439
  });
6260
6440
  if (result.exitCode !== 0) {