harnessed 2.0.1 → 3.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.
Files changed (68) hide show
  1. package/README.md +263 -28
  2. package/dist/cli.mjs +367 -76
  3. package/dist/cli.mjs.map +1 -1
  4. package/dist/index.mjs +1 -1
  5. package/dist/index.mjs.map +1 -1
  6. package/package.json +1 -1
  7. package/workflows/capabilities.yaml +468 -0
  8. package/workflows/defaults.yaml +71 -4
  9. package/workflows/disciplines/karpathy.yaml +47 -0
  10. package/workflows/disciplines/language.yaml +38 -0
  11. package/workflows/disciplines/operational.yaml +61 -0
  12. package/workflows/disciplines/output-style.yaml +62 -0
  13. package/workflows/disciplines/priority.yaml +28 -0
  14. package/workflows/disciplines/protocols.yaml +70 -0
  15. package/workflows/discuss/auto/.gitkeep +0 -0
  16. package/workflows/discuss/auto/SKILL.md +63 -0
  17. package/workflows/discuss/auto/workflow.yaml +40 -0
  18. package/workflows/discuss/phase/SKILL.md +61 -0
  19. package/workflows/discuss/phase/workflow.yaml +35 -0
  20. package/workflows/discuss/strategic/SKILL.md +66 -0
  21. package/workflows/discuss/strategic/workflow.yaml +47 -0
  22. package/workflows/discuss/subtask/SKILL.md +67 -0
  23. package/workflows/discuss/subtask/workflow.yaml +33 -0
  24. package/workflows/judgments/stage-routing.yaml +93 -0
  25. package/workflows/judgments/web-design-routing.yaml +37 -0
  26. package/workflows/judgments/web-search-routing.yaml +52 -0
  27. package/workflows/judgments/web-testing-routing.yaml +50 -0
  28. package/workflows/plan/architecture/SKILL.md +62 -0
  29. package/workflows/plan/architecture/workflow.yaml +33 -0
  30. package/workflows/plan/auto/.gitkeep +0 -0
  31. package/workflows/plan/auto/SKILL.md +63 -0
  32. package/workflows/plan/auto/workflow.yaml +41 -0
  33. package/workflows/plan/phase/SKILL.md +64 -0
  34. package/workflows/plan/phase/workflow.yaml +37 -0
  35. package/workflows/research/SKILL.md +6 -2
  36. package/workflows/research/workflow.yaml +34 -3
  37. package/workflows/retro/SKILL.md +68 -0
  38. package/workflows/retro/workflow.yaml +40 -0
  39. package/workflows/task/auto/.gitkeep +0 -0
  40. package/workflows/task/auto/SKILL.md +68 -0
  41. package/workflows/task/auto/workflow.yaml +57 -0
  42. package/workflows/task/clarify/SKILL.md +83 -0
  43. package/workflows/task/clarify/workflow.yaml +39 -0
  44. package/workflows/task/code/SKILL.md +89 -0
  45. package/workflows/task/code/workflow.yaml +55 -0
  46. package/workflows/task/deliver/SKILL.md +118 -0
  47. package/workflows/task/deliver/workflow.yaml +77 -0
  48. package/workflows/task/test/SKILL.md +93 -0
  49. package/workflows/task/test/workflow.yaml +44 -0
  50. package/workflows/verify/auto/.gitkeep +0 -0
  51. package/workflows/verify/auto/SKILL.md +77 -0
  52. package/workflows/verify/auto/workflow.yaml +74 -0
  53. package/workflows/verify/code-review/SKILL.md +69 -0
  54. package/workflows/verify/code-review/workflow.yaml +32 -0
  55. package/workflows/verify/design/SKILL.md +72 -0
  56. package/workflows/verify/design/workflow.yaml +33 -0
  57. package/workflows/verify/multispec/SKILL.md +86 -0
  58. package/workflows/verify/multispec/workflow.yaml +58 -0
  59. package/workflows/verify/paranoid/SKILL.md +71 -0
  60. package/workflows/verify/paranoid/workflow.yaml +30 -0
  61. package/workflows/verify/progress/SKILL.md +67 -0
  62. package/workflows/verify/progress/workflow.yaml +44 -0
  63. package/workflows/verify/qa/SKILL.md +73 -0
  64. package/workflows/verify/qa/workflow.yaml +31 -0
  65. package/workflows/verify/security/SKILL.md +67 -0
  66. package/workflows/verify/security/workflow.yaml +31 -0
  67. package/workflows/verify/simplify/SKILL.md +67 -0
  68. package/workflows/verify/simplify/workflow.yaml +31 -0
package/dist/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { spawnSync, spawn } from 'child_process';
2
+ import { execSync, spawnSync, spawn } from 'child_process';
3
3
  import { writeFileSync, existsSync, readFileSync, mkdirSync, appendFileSync, readdirSync } from 'fs';
4
4
  import { resolve, join, dirname, relative } from 'path';
5
5
  import { Type } from '@sinclair/typebox';
@@ -169,17 +169,21 @@ var init_schemaVersion = __esm({
169
169
  governance: "harnessed.governance.v1",
170
170
  // ← Phase 3.2 W1 T1.1 ADD 10th surface (D-04 PUSH veto status)
171
171
  planFeature: "harnessed.plan-feature.v1",
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)
172
+ // ← Phase 3.3 W0 T0.5 BACKFILL 11th surface
173
173
  aliases: "harnessed.aliases.v1",
174
- // ← Phase 3.3 W1 T1.1 ADD 12th surface (D-01 RICH manifests/aliases.yaml upstream rename redirect + metadata)
174
+ // ← Phase 3.3 W1 T1.1 ADD 12th surface (D-01 RICH)
175
175
  knownGood: "harnessed.known-good.v1",
176
- // ← Phase 3.3 W1 T1.1 ADD 13th surface (D-03 YAML versions/<harnessed-ver>-known-good.yaml per-version lock)
176
+ // ← Phase 3.3 W1 T1.1 ADD 13th surface (D-03 YAML manifest)
177
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)
178
+ // ← Phase v2.0-2.3 W0 ADD 14th surface (R20.2 flat yaml capabilities manifest validate)
179
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)
180
+ // ← Phase v2.0-2.3 W0 ADD 15th surface (R20.4 multi-file judgments 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)
183
+ workflow_v3: "harnessed.workflow.v3",
184
+ // ← Phase v3.0-3.3 W0 T3.3.W0.11 ADD 17th surface (D-09 disciplines_applied + D-05 tools_available + master delegates_to per Pattern A B.1 LOCK)
185
+ discipline: "harnessed.discipline.v1"
186
+ // ← Phase v3.0-3.3 W0 T3.3.W0.11 ADD 18th surface (D-09 L0 Discipline Substrate, sister judgment.v1 multi-file pattern)
183
187
  };
184
188
  Type.Union([
185
189
  Type.Literal(SCHEMA_VERSIONS.routingSnapshot),
@@ -202,11 +206,15 @@ var init_schemaVersion = __esm({
202
206
  Type.Literal(SCHEMA_VERSIONS.knownGood),
203
207
  // ← Phase 3.3 W1 T1.1 ADD 13th surface
204
208
  Type.Literal(SCHEMA_VERSIONS.capabilities),
205
- // ← Phase v2.0-2.3 W0 T2.3.W0.6 ADD 14th surface
209
+ // ← Phase v2.0-2.3 W0 ADD 14th surface
206
210
  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)
211
+ // ← Phase v2.0-2.3 W0 ADD 15th surface
212
+ Type.Literal(SCHEMA_VERSIONS.workflow),
213
+ // ← Phase v2.0-2.4 W0 T2.4.W0.1 ADD 16th surface (first .v2 in union)
214
+ Type.Literal(SCHEMA_VERSIONS.workflow_v3),
215
+ // ← Phase v3.0-3.3 W0 T3.3.W0.11 ADD 17th surface (first .v3 in union)
216
+ Type.Literal(SCHEMA_VERSIONS.discipline)
217
+ // ← Phase v3.0-3.3 W0 T3.3.W0.11 ADD 18th surface
210
218
  ]);
211
219
  }
212
220
  });
@@ -692,10 +700,10 @@ __export(knownGood_exports, {
692
700
  loadKnownGood: () => loadKnownGood
693
701
  });
694
702
  function loadKnownGood(harnessedVer) {
695
- if (_cache.has(harnessedVer)) return _cache.get(harnessedVer) ?? null;
703
+ if (_cache2.has(harnessedVer)) return _cache2.get(harnessedVer) ?? null;
696
704
  const path = join(versionsDir(), `${harnessedVer}-known-good.yaml`);
697
705
  if (!existsSync(path)) {
698
- _cache.set(harnessedVer, null);
706
+ _cache2.set(harnessedVer, null);
699
707
  return null;
700
708
  }
701
709
  const raw = readFileSync(path, "utf8");
@@ -706,7 +714,7 @@ function loadKnownGood(harnessedVer) {
706
714
  `${path} schema invalid: ${errs.map((e) => `${e.path} ${e.message}`).join("; ")}`
707
715
  );
708
716
  }
709
- _cache.set(harnessedVer, parsed);
717
+ _cache2.set(harnessedVer, parsed);
710
718
  return parsed;
711
719
  }
712
720
  function getPinnedVersion(upstreamName, harnessedVer) {
@@ -715,12 +723,12 @@ function getPinnedVersion(upstreamName, harnessedVer) {
715
723
  const entry = kg.upstreams.find((u) => u.name === upstreamName);
716
724
  return entry?.version ?? null;
717
725
  }
718
- var versionsDir, _cache;
726
+ var versionsDir, _cache2;
719
727
  var init_knownGood = __esm({
720
728
  "src/manifest/knownGood.ts"() {
721
729
  init_known_good_v1();
722
730
  versionsDir = () => join(process.cwd(), "versions");
723
- _cache = /* @__PURE__ */ new Map();
731
+ _cache2 = /* @__PURE__ */ new Map();
724
732
  }
725
733
  });
726
734
 
@@ -785,7 +793,7 @@ var init_resume = __esm({
785
793
 
786
794
  // package.json
787
795
  var package_default = {
788
- version: "2.0.1"};
796
+ version: "3.0.0"};
789
797
 
790
798
  // src/manifest/errors.ts
791
799
  function instancePathToKeyPath(instancePath) {
@@ -1566,7 +1574,7 @@ function renderHumanTable(records) {
1566
1574
  }
1567
1575
  }
1568
1576
  function pipeToJq(filterExpr, lines) {
1569
- return new Promise((resolve8, reject) => {
1577
+ return new Promise((resolve9, reject) => {
1570
1578
  const child = spawn("jq", [filterExpr], {
1571
1579
  stdio: ["pipe", "inherit", "inherit"],
1572
1580
  windowsHide: true
@@ -1575,12 +1583,12 @@ function pipeToJq(filterExpr, lines) {
1575
1583
  const e = err2;
1576
1584
  if (e.code === "ENOENT") {
1577
1585
  console.error("\u2717 jq not found in PATH \u2014 run: harnessed doctor");
1578
- resolve8(1);
1586
+ resolve9(1);
1579
1587
  } else {
1580
1588
  reject(err2);
1581
1589
  }
1582
1590
  });
1583
- child.on("close", (code) => resolve8(code ?? 0));
1591
+ child.on("close", (code) => resolve9(code ?? 0));
1584
1592
  child.stdin.write(lines.join("\n"));
1585
1593
  child.stdin.end();
1586
1594
  });
@@ -1932,6 +1940,107 @@ function registerDoctor(program2) {
1932
1940
  });
1933
1941
  }
1934
1942
 
1943
+ // src/workflow/schema/discipline.ts
1944
+ init_schemaVersion();
1945
+ var EnforcementLayer = Type.Union([
1946
+ Type.Literal("code-writing"),
1947
+ // karpathy 心法 — write code phase
1948
+ Type.Literal("output"),
1949
+ // BLUF / language / no-emoji — emit response phase
1950
+ Type.Literal("commit"),
1951
+ // biome / A7 / commit safety — pre-commit phase
1952
+ Type.Literal("workflow"),
1953
+ // priority hierarchy / protocols — workflow-level arbitration
1954
+ Type.Literal("tool")
1955
+ // tool invoke discipline (reserved for v3.x extension)
1956
+ ]);
1957
+ var Enforcement = Type.Union([
1958
+ Type.Literal("halt"),
1959
+ // process.exit non-zero, sister fallbackHandlers
1960
+ Type.Literal("warn"),
1961
+ // console.warn emit, continue
1962
+ Type.Literal("auto-fix"),
1963
+ // run auto_fix_cmd then continue (biome --write pattern)
1964
+ Type.Literal("info")
1965
+ // log only, no action
1966
+ ]);
1967
+ var DisciplineRule = Type.Object(
1968
+ {
1969
+ id: Type.String({ minLength: 1 }),
1970
+ // kebab-case
1971
+ description: Type.String(),
1972
+ // human-readable
1973
+ enforcement: Enforcement,
1974
+ trigger: Type.Union([Type.String(), Type.Array(Type.String())]),
1975
+ // expr OR always-on list
1976
+ check_method: Type.String(),
1977
+ // heuristic / regex / external-cmd / llm-judge / file-content-match
1978
+ auto_fix_cmd: Type.Optional(Type.String())
1979
+ // only enforcement=auto-fix
1980
+ },
1981
+ { additionalProperties: false }
1982
+ );
1983
+ var PriorityHierarchy = Type.Array(Type.String(), { minItems: 1 });
1984
+ var ProtocolShape = Type.Object(
1985
+ {
1986
+ description: Type.String(),
1987
+ required_fields: Type.Optional(Type.Array(Type.String())),
1988
+ forbidden_phrases: Type.Optional(Type.Array(Type.String())),
1989
+ file_ownership: Type.Optional(Type.Record(Type.String(), Type.Array(Type.String()))),
1990
+ rules: Type.Optional(Type.Array(DisciplineRule))
1991
+ },
1992
+ { additionalProperties: false }
1993
+ );
1994
+ var Discipline = Type.Object(
1995
+ {
1996
+ schema_version: Type.Literal(SCHEMA_VERSIONS.discipline),
1997
+ discipline: Type.String({ minLength: 1 }),
1998
+ // basename (karpathy / output-style / ...)
1999
+ enforcement_layer: EnforcementLayer,
2000
+ auto_enforce: Type.Boolean(),
2001
+ rules: Type.Array(DisciplineRule),
2002
+ priority_hierarchy: Type.Optional(PriorityHierarchy),
2003
+ // priority.yaml only
2004
+ protocols: Type.Optional(Type.Record(Type.String(), ProtocolShape))
2005
+ // protocols.yaml only
2006
+ },
2007
+ { additionalProperties: false }
2008
+ );
2009
+
2010
+ // src/workflow/disciplineLoader.ts
2011
+ var _cache = /* @__PURE__ */ new Map();
2012
+ async function loadDiscipline(basename2, packageRoot) {
2013
+ const cached = _cache.get(basename2);
2014
+ if (cached) return cached;
2015
+ const yamlPath = resolve(packageRoot, "workflows", "disciplines", `${basename2}.yaml`);
2016
+ const raw = await readFile(yamlPath, "utf8");
2017
+ const parsedRaw = parse(raw);
2018
+ if (!Value.Check(Discipline, parsedRaw)) {
2019
+ const errors = [...Value.Errors(Discipline, parsedRaw)].slice(0, 3).map((e) => `${e.path} ${e.message}`).join("; ");
2020
+ throw new Error(`Invalid discipline file ${basename2}.yaml: ${errors}`);
2021
+ }
2022
+ const parsed = parsedRaw;
2023
+ _cache.set(basename2, parsed);
2024
+ return parsed;
2025
+ }
2026
+
2027
+ // src/discipline/enforcement/before-commit.ts
2028
+ var TS_JS_RE = /\.(ts|tsx|js|mjs)$/;
2029
+ async function runBeforeCommitHook(ctx) {
2030
+ const d = await loadDiscipline("operational", ctx.packageRoot);
2031
+ if (ctx.changedFiles.some((f) => TS_JS_RE.test(f))) {
2032
+ const rule = d.rules.find((r) => r.id === "biome-preempt");
2033
+ if (rule?.auto_fix_cmd) {
2034
+ console.warn("\u26A0\uFE0F biome preempt \u2014 running auto-fix before commit");
2035
+ execSync(rule.auto_fix_cmd, { cwd: ctx.packageRoot, stdio: "inherit" });
2036
+ }
2037
+ }
2038
+ if (ctx.cmdArgs.includes("--no-verify")) {
2039
+ console.error("\u274C no-skip-hooks violated: --no-verify forbidden");
2040
+ process.exit(2);
2041
+ }
2042
+ }
2043
+
1935
2044
  // src/routing/completionSchema.ts
1936
2045
  var COMPLETION_SCHEMA = {
1937
2046
  type: "object",
@@ -2636,15 +2745,100 @@ var PhasesSchema = Type.Object(
2636
2745
 
2637
2746
  // src/workflow/schema/workflow.ts
2638
2747
  init_schemaVersion();
2748
+
2749
+ // src/workflow/schema/workflow.v2.ts
2750
+ init_schemaVersion();
2639
2751
  var ModelTier2 = Type.Union([Type.Literal("haiku"), Type.Literal("sonnet"), Type.Literal("opus")]);
2640
2752
  var OnAction = Type.Union([Type.Literal("skip"), Type.Literal("invoke")]);
2753
+ var OnClauseV2 = Type.Object(
2754
+ {
2755
+ if: Type.String(),
2756
+ invoke: Type.Optional(Type.String()),
2757
+ action: Type.Optional(OnAction)
2758
+ },
2759
+ { additionalProperties: false }
2760
+ );
2761
+ var FallbackMaxIterationsExceededV2 = Type.Object(
2762
+ {
2763
+ action: Type.Literal("emit_warning_and_halt"),
2764
+ message: Type.String(),
2765
+ exit_code: Type.Number()
2766
+ },
2767
+ { additionalProperties: false }
2768
+ );
2769
+ var PhaseFallbackV2 = Type.Object(
2770
+ {
2771
+ max_iterations_exceeded: Type.Optional(FallbackMaxIterationsExceededV2)
2772
+ },
2773
+ { additionalProperties: false }
2774
+ );
2775
+ var WorkflowPhaseV2 = Type.Object(
2776
+ {
2777
+ id: Type.String({ minLength: 1 }),
2778
+ name: Type.Optional(Type.String()),
2779
+ upstream: Type.Optional(Type.String()),
2780
+ capability: Type.Optional(Type.String()),
2781
+ model: Type.Optional(ModelTier2),
2782
+ invokes: Type.Optional(Type.String()),
2783
+ args: Type.Optional(Type.Record(Type.String(), Type.Unknown())),
2784
+ gate: Type.Optional(Type.String()),
2785
+ on: Type.Optional(Type.Array(OnClauseV2)),
2786
+ parallelism: Type.Optional(Type.String()),
2787
+ fallback: Type.Optional(PhaseFallbackV2),
2788
+ max_iterations: Type.Optional(Type.Union([Type.Number(), Type.String()])),
2789
+ artifacts_expected: Type.Optional(Type.Array(Type.String()))
2790
+ },
2791
+ { additionalProperties: false }
2792
+ );
2793
+ var WorkflowSchemaV2 = Type.Object(
2794
+ {
2795
+ schema_version: Type.Literal(SCHEMA_VERSIONS.workflow),
2796
+ workflow: Type.String({ minLength: 1 }),
2797
+ description: Type.Optional(Type.String()),
2798
+ phases: Type.Array(WorkflowPhaseV2, { minItems: 1 })
2799
+ },
2800
+ { additionalProperties: false }
2801
+ );
2802
+
2803
+ // src/workflow/schema/workflow.ts
2804
+ var ModelTier3 = Type.Union([Type.Literal("haiku"), Type.Literal("sonnet"), Type.Literal("opus")]);
2805
+ var OnAction2 = Type.Union([Type.Literal("skip"), Type.Literal("invoke")]);
2806
+ var DisciplineName = Type.Union([
2807
+ Type.Literal("karpathy"),
2808
+ Type.Literal("output-style"),
2809
+ Type.Literal("language"),
2810
+ Type.Literal("operational"),
2811
+ Type.Literal("priority"),
2812
+ Type.Literal("protocols")
2813
+ ]);
2641
2814
  var OnClause = Type.Object(
2642
2815
  {
2643
2816
  if: Type.String(),
2644
2817
  // expr-eval expression OR judgments.<file>.<gate>.fires ref
2645
2818
  invoke: Type.Optional(Type.String()),
2646
2819
  // '{{ capabilities.<name>.cmd }}' OR literal
2647
- action: Type.Optional(OnAction)
2820
+ action: Type.Optional(OnAction2)
2821
+ },
2822
+ { additionalProperties: false }
2823
+ );
2824
+ var InvokeToolClause = Type.Object(
2825
+ {
2826
+ if: Type.Optional(Type.String()),
2827
+ // optional — 无 if = unconditional fire
2828
+ tool: Type.String({ minLength: 1 })
2829
+ // capabilities.yaml entry name (cross-validate T3.3.W0.10)
2830
+ },
2831
+ { additionalProperties: false }
2832
+ );
2833
+ var DelegationClause = Type.Object(
2834
+ {
2835
+ sub: Type.String({ minLength: 1 }),
2836
+ // sub-stage workflow name e.g. 'strategic' / 'phase' / 'subtask'
2837
+ gate: Type.Optional(Type.String()),
2838
+ // judgments.<file>.<trigger>.fires 4-level ref
2839
+ mode: Type.Optional(Type.Union([Type.Literal("parallel"), Type.Literal("serial")])),
2840
+ order: Type.Optional(Type.Number())
2841
+ // serial-only: explicit ordering (K9 mitigation enforced in check-workflow-schema)
2648
2842
  },
2649
2843
  { additionalProperties: false }
2650
2844
  );
@@ -2663,14 +2857,14 @@ var PhaseFallback = Type.Object(
2663
2857
  },
2664
2858
  { additionalProperties: false }
2665
2859
  );
2666
- var WorkflowPhaseV2 = Type.Object(
2860
+ var WorkflowPhaseV3 = Type.Object(
2667
2861
  {
2668
2862
  id: Type.String({ minLength: 1 }),
2669
2863
  name: Type.Optional(Type.String()),
2670
2864
  upstream: Type.Optional(Type.String()),
2671
2865
  capability: Type.Optional(Type.String()),
2672
2866
  // '{{ capabilities.ralph-loop.cmd }}'
2673
- model: Type.Optional(ModelTier2),
2867
+ model: Type.Optional(ModelTier3),
2674
2868
  invokes: Type.Optional(Type.String()),
2675
2869
  // legacy slash-cmd OR JINJA template
2676
2870
  args: Type.Optional(Type.Record(Type.String(), Type.Unknown())),
@@ -2684,16 +2878,25 @@ var WorkflowPhaseV2 = Type.Object(
2684
2878
  Type.Union([Type.Number(), Type.String()])
2685
2879
  // numeric literal OR jinja '{{ defaults.x.y }}'
2686
2880
  ),
2687
- artifacts_expected: Type.Optional(Type.Array(Type.String()))
2881
+ artifacts_expected: Type.Optional(Type.Array(Type.String())),
2882
+ invokes_tools: Type.Optional(Type.Array(InvokeToolClause))
2883
+ // NEW v3 D-05 phase-level conditional fire
2688
2884
  },
2689
2885
  { additionalProperties: false }
2690
2886
  );
2691
- var WorkflowSchemaV2 = Type.Object(
2887
+ Type.Object(
2692
2888
  {
2693
- schema_version: Type.Literal(SCHEMA_VERSIONS.workflow),
2889
+ schema_version: Type.Literal(SCHEMA_VERSIONS.workflow_v3),
2694
2890
  workflow: Type.String({ minLength: 1 }),
2695
2891
  description: Type.Optional(Type.String()),
2696
- phases: Type.Array(WorkflowPhaseV2, { minItems: 1 })
2892
+ disciplines_applied: Type.Optional(Type.Array(DisciplineName)),
2893
+ // NEW v3 D-09 (Pattern A A.1 strict Literal Union)
2894
+ tools_available: Type.Optional(Type.Array(Type.String())),
2895
+ // NEW v3 D-05 (cross-validate T3.3.W0.10)
2896
+ delegates_to: Type.Optional(Type.Array(DelegationClause)),
2897
+ // NEW v3 D-01 (master orchestrator only)
2898
+ phases: Type.Optional(Type.Array(WorkflowPhaseV3, { minItems: 1 }))
2899
+ // 改 Optional — master 无 phases, sub/standalone 必有
2697
2900
  },
2698
2901
  { additionalProperties: false }
2699
2902
  );
@@ -2776,6 +2979,22 @@ function registerExecuteTask(program2) {
2776
2979
  break;
2777
2980
  }
2778
2981
  }
2982
+ try {
2983
+ const stagedOut = execSync("git status --porcelain", { encoding: "utf8" });
2984
+ const changedFiles = stagedOut.split("\n").filter((l) => l.trim().length > 0).map((l) => l.slice(3).trim());
2985
+ await runBeforeCommitHook({
2986
+ changedFiles,
2987
+ cmdArgs: [],
2988
+ packageRoot: process.cwd(),
2989
+ cmdType: "git-commit",
2990
+ hasUserApproval: true
2991
+ // --apply explicit
2992
+ });
2993
+ } catch (err2) {
2994
+ console.warn(
2995
+ `\u26A0\uFE0F before-commit pre-flight skipped (${err2.message}); subagent will biome-check at commit time.`
2996
+ );
2997
+ }
2779
2998
  const result = await runRouting(taskCtx, {
2780
2999
  maxIterations: raw.maxIterations ?? 20,
2781
3000
  ...raw.model ? { agentOpts: { modelOverride: raw.model } } : {},
@@ -3157,7 +3376,7 @@ var installCcHookAdd = async (ctx) => {
3157
3376
  return { ok: true, backupId: bk.backupId, appliedFiles: [settingsPath] };
3158
3377
  };
3159
3378
  function runArgs(claudeArgs, cwd, timeoutMs = 15e3) {
3160
- return new Promise((resolve8) => {
3379
+ return new Promise((resolve9) => {
3161
3380
  const isWin = process.platform === "win32";
3162
3381
  const child = isWin ? spawn("cmd.exe", ["/c", "claude", ...claudeArgs], { cwd, windowsHide: true }) : spawn("claude", claudeArgs, { cwd, shell: false });
3163
3382
  let stderr = "";
@@ -3166,15 +3385,15 @@ function runArgs(claudeArgs, cwd, timeoutMs = 15e3) {
3166
3385
  });
3167
3386
  const timer = setTimeout(() => {
3168
3387
  child.kill("SIGKILL");
3169
- resolve8({ exitCode: -1, stderr: `${stderr}[timeout after ${timeoutMs}ms]` });
3388
+ resolve9({ exitCode: -1, stderr: `${stderr}[timeout after ${timeoutMs}ms]` });
3170
3389
  }, timeoutMs);
3171
3390
  child.on("error", (e) => {
3172
3391
  clearTimeout(timer);
3173
- resolve8({ exitCode: -1, stderr: `${stderr}${e.message}` });
3392
+ resolve9({ exitCode: -1, stderr: `${stderr}${e.message}` });
3174
3393
  });
3175
3394
  child.on("close", (code) => {
3176
3395
  clearTimeout(timer);
3177
- resolve8({ exitCode: code ?? -1, stderr });
3396
+ resolve9({ exitCode: code ?? -1, stderr });
3178
3397
  });
3179
3398
  });
3180
3399
  }
@@ -3315,7 +3534,7 @@ ${newEntry}
3315
3534
  )
3316
3535
  };
3317
3536
  }
3318
- const vr = await new Promise((resolve8) => {
3537
+ const vr = await new Promise((resolve9) => {
3319
3538
  const child = spawn(verifyShell, [verifyFlag, verifyLine], { cwd: ctx.cwd, windowsHide: true });
3320
3539
  let stderr = "";
3321
3540
  child.stderr?.setEncoding("utf8").on("data", (c) => {
@@ -3323,15 +3542,15 @@ ${newEntry}
3323
3542
  });
3324
3543
  const timer = setTimeout(() => {
3325
3544
  child.kill("SIGKILL");
3326
- resolve8({ exitCode: -1, stderr: `${stderr}[timeout]` });
3545
+ resolve9({ exitCode: -1, stderr: `${stderr}[timeout]` });
3327
3546
  }, 15e3);
3328
3547
  child.on("error", (e) => {
3329
3548
  clearTimeout(timer);
3330
- resolve8({ exitCode: -1, stderr: e.message });
3549
+ resolve9({ exitCode: -1, stderr: e.message });
3331
3550
  });
3332
3551
  child.on("close", (code) => {
3333
3552
  clearTimeout(timer);
3334
- resolve8({ exitCode: code ?? -1, stderr });
3553
+ resolve9({ exitCode: code ?? -1, stderr });
3335
3554
  });
3336
3555
  });
3337
3556
  if (vr.exitCode !== 0) {
@@ -3387,10 +3606,10 @@ async function spawnCmd(ctx, cmd, args) {
3387
3606
  child.stderr?.setEncoding("utf8").on("data", (chunk) => {
3388
3607
  stderr += chunk;
3389
3608
  });
3390
- return await new Promise((resolve8) => {
3609
+ return await new Promise((resolve9) => {
3391
3610
  const timer = setTimeout(() => {
3392
3611
  child.kill("SIGKILL");
3393
- resolve8({
3612
+ resolve9({
3394
3613
  ok: false,
3395
3614
  phase: "spawn",
3396
3615
  error: {
@@ -3405,7 +3624,7 @@ async function spawnCmd(ctx, cmd, args) {
3405
3624
  }, timeoutMs);
3406
3625
  child.on("error", (err2) => {
3407
3626
  clearTimeout(timer);
3408
- resolve8({
3627
+ resolve9({
3409
3628
  ok: false,
3410
3629
  phase: "spawn",
3411
3630
  error: {
@@ -3420,14 +3639,14 @@ async function spawnCmd(ctx, cmd, args) {
3420
3639
  });
3421
3640
  child.on("close", (code) => {
3422
3641
  clearTimeout(timer);
3423
- resolve8({ ok: true, exitCode: code ?? -1, stdout: stdout2, stderr });
3642
+ resolve9({ ok: true, exitCode: code ?? -1, stdout: stdout2, stderr });
3424
3643
  });
3425
3644
  });
3426
3645
  }
3427
3646
 
3428
3647
  // src/installers/gitCloneWithSetup.ts
3429
3648
  function gitRevParseHead(cwd, timeoutMs = 1e4) {
3430
- return new Promise((resolve8) => {
3649
+ return new Promise((resolve9) => {
3431
3650
  const isWin = process.platform === "win32";
3432
3651
  const child = isWin ? spawn("cmd.exe", ["/c", "git", "rev-parse", "HEAD"], { cwd, windowsHide: true }) : spawn("git", ["rev-parse", "HEAD"], { cwd, shell: false });
3433
3652
  let stdout2 = "";
@@ -3436,15 +3655,15 @@ function gitRevParseHead(cwd, timeoutMs = 1e4) {
3436
3655
  });
3437
3656
  const timer = setTimeout(() => {
3438
3657
  child.kill("SIGKILL");
3439
- resolve8({ sha: "", exit: -1 });
3658
+ resolve9({ sha: "", exit: -1 });
3440
3659
  }, timeoutMs);
3441
3660
  child.on("error", () => {
3442
3661
  clearTimeout(timer);
3443
- resolve8({ sha: "", exit: -1 });
3662
+ resolve9({ sha: "", exit: -1 });
3444
3663
  });
3445
3664
  child.on("close", (code) => {
3446
3665
  clearTimeout(timer);
3447
- resolve8({ sha: stdout2.trim(), exit: code ?? -1 });
3666
+ resolve9({ sha: stdout2.trim(), exit: code ?? -1 });
3448
3667
  });
3449
3668
  });
3450
3669
  }
@@ -3784,7 +4003,7 @@ ${newEntry}
3784
4003
  )
3785
4004
  };
3786
4005
  }
3787
- const vr = await new Promise((resolve8) => {
4006
+ const vr = await new Promise((resolve9) => {
3788
4007
  const child = spawn(verifyShell, [verifyFlag, verifyLine], { cwd: ctx.cwd, windowsHide: true });
3789
4008
  let stderr = "";
3790
4009
  child.stderr?.setEncoding("utf8").on("data", (c) => {
@@ -3792,15 +4011,15 @@ ${newEntry}
3792
4011
  });
3793
4012
  const timer = setTimeout(() => {
3794
4013
  child.kill("SIGKILL");
3795
- resolve8({ exitCode: -1, stderr: `${stderr}[timeout]` });
4014
+ resolve9({ exitCode: -1, stderr: `${stderr}[timeout]` });
3796
4015
  }, 15e3);
3797
4016
  child.on("error", (e) => {
3798
4017
  clearTimeout(timer);
3799
- resolve8({ exitCode: -1, stderr: e.message });
4018
+ resolve9({ exitCode: -1, stderr: e.message });
3800
4019
  });
3801
4020
  child.on("close", (code) => {
3802
4021
  clearTimeout(timer);
3803
- resolve8({ exitCode: code ?? -1, stderr });
4022
+ resolve9({ exitCode: code ?? -1, stderr });
3804
4023
  });
3805
4024
  });
3806
4025
  if (vr.exitCode !== 0) {
@@ -3932,7 +4151,7 @@ ${newEntry}
3932
4151
  )
3933
4152
  };
3934
4153
  }
3935
- const vr = await new Promise((resolve8) => {
4154
+ const vr = await new Promise((resolve9) => {
3936
4155
  const child = spawn(verifyShell, [verifyFlag, verifyLine], { cwd: ctx.cwd, windowsHide: true });
3937
4156
  let stderr = "";
3938
4157
  child.stderr?.setEncoding("utf8").on("data", (c) => {
@@ -3940,15 +4159,15 @@ ${newEntry}
3940
4159
  });
3941
4160
  const timer = setTimeout(() => {
3942
4161
  child.kill("SIGKILL");
3943
- resolve8({ exitCode: -1, stderr: `${stderr}[timeout]` });
4162
+ resolve9({ exitCode: -1, stderr: `${stderr}[timeout]` });
3944
4163
  }, 15e3);
3945
4164
  child.on("error", (e) => {
3946
4165
  clearTimeout(timer);
3947
- resolve8({ exitCode: -1, stderr: e.message });
4166
+ resolve9({ exitCode: -1, stderr: e.message });
3948
4167
  });
3949
4168
  child.on("close", (code) => {
3950
4169
  clearTimeout(timer);
3951
- resolve8({ exitCode: code ?? -1, stderr });
4170
+ resolve9({ exitCode: code ?? -1, stderr });
3952
4171
  });
3953
4172
  });
3954
4173
  if (vr.exitCode !== 0) {
@@ -4562,6 +4781,82 @@ function registerRollback(program2) {
4562
4781
  });
4563
4782
  }
4564
4783
  init_checkAgentTeams();
4784
+ var FLAT_LEGACY_DEPRECATED = /* @__PURE__ */ new Set(["plan-feature", "execute-task", "verify-work"]);
4785
+ var FLAT_LEGACY_KEEP = /* @__PURE__ */ new Set(["research", "retro"]);
4786
+ var NON_WORKFLOW_DIRS = /* @__PURE__ */ new Set(["disciplines", "judgments"]);
4787
+ async function scanWorkflowsNested(workflowsDir, entries) {
4788
+ const workflows = [];
4789
+ const deprecated = [];
4790
+ for (const entry of entries.sort()) {
4791
+ if (NON_WORKFLOW_DIRS.has(entry)) continue;
4792
+ const src = join(workflowsDir, entry);
4793
+ let s;
4794
+ try {
4795
+ s = await stat(src);
4796
+ } catch {
4797
+ continue;
4798
+ }
4799
+ if (!s.isDirectory()) continue;
4800
+ let hasFlatSkill = false;
4801
+ try {
4802
+ await stat(join(src, "SKILL.md"));
4803
+ hasFlatSkill = true;
4804
+ } catch {
4805
+ hasFlatSkill = false;
4806
+ }
4807
+ if (hasFlatSkill) {
4808
+ if (FLAT_LEGACY_DEPRECATED.has(entry)) {
4809
+ deprecated.push(entry);
4810
+ continue;
4811
+ }
4812
+ if (FLAT_LEGACY_KEEP.has(entry)) {
4813
+ workflows.push({ name: entry, relPath: entry, isMaster: false });
4814
+ continue;
4815
+ }
4816
+ workflows.push({ name: entry, relPath: entry, isMaster: false });
4817
+ continue;
4818
+ }
4819
+ let subEntries;
4820
+ try {
4821
+ subEntries = await readdir(src);
4822
+ } catch {
4823
+ continue;
4824
+ }
4825
+ for (const sub of subEntries.sort()) {
4826
+ const subDir = join(src, sub);
4827
+ let ss;
4828
+ try {
4829
+ ss = await stat(subDir);
4830
+ } catch {
4831
+ continue;
4832
+ }
4833
+ if (!ss.isDirectory()) continue;
4834
+ try {
4835
+ await stat(join(subDir, "SKILL.md"));
4836
+ } catch {
4837
+ continue;
4838
+ }
4839
+ const name = sub === "auto" ? entry : `${entry}-${sub}`;
4840
+ workflows.push({ name, relPath: `${entry}/${sub}`, isMaster: sub === "auto" });
4841
+ }
4842
+ }
4843
+ return { workflows, deprecated };
4844
+ }
4845
+ function renderDeprecationBlock(deprecated) {
4846
+ if (deprecated.length === 0) return "";
4847
+ return [
4848
+ "\u26A0\uFE0F v3.0 BREAKING \u2014 v2 legacy slash cmd deprecated:",
4849
+ " /plan-feature \u2192 /plan (master) | /plan-phase (sub)",
4850
+ " /execute-task \u2192 /task (master) | /task-{clarify,code,test,deliver} (sub)",
4851
+ " /verify-work \u2192 /verify (master) | /verify-{progress,paranoid,qa,security,design,simplify,multispec} (sub)",
4852
+ " /research, /retro \u4E0D\u53D8",
4853
+ " \u8BE6\u89C1 CHANGELOG [3.0.0]",
4854
+ ` skipped install: ${deprecated.sort().join(", ")}`,
4855
+ ""
4856
+ ].join("\n");
4857
+ }
4858
+
4859
+ // src/cli/lib/setup-helpers.ts
4565
4860
  var PHASE_212 = /* @__PURE__ */ new Set([
4566
4861
  "cc-plugin-marketplace",
4567
4862
  "git-clone-with-setup",
@@ -4581,18 +4876,7 @@ async function warnIfAgentTeamsMissing() {
4581
4876
  );
4582
4877
  }
4583
4878
  async function scanWorkflowsWithSkill(workflowsDir, entries) {
4584
- const out = [];
4585
- for (const entry of entries.sort()) {
4586
- const src = join(workflowsDir, entry);
4587
- try {
4588
- const s = await stat(src);
4589
- if (!s.isDirectory()) continue;
4590
- await stat(join(src, "SKILL.md"));
4591
- out.push(entry);
4592
- } catch {
4593
- }
4594
- }
4595
- return out;
4879
+ return scanWorkflowsNested(workflowsDir, entries);
4596
4880
  }
4597
4881
  async function runStepBInstall(manifestPaths) {
4598
4882
  const opts = {
@@ -4678,7 +4962,12 @@ function registerSetup(program2) {
4678
4962
  console.error(`error: workflows directory not found at ${workflowsDir}`);
4679
4963
  process.exit(1);
4680
4964
  }
4681
- const toInstall = await scanWorkflowsWithSkill(workflowsDir, entries);
4965
+ const { workflows: toInstall, deprecated } = await scanWorkflowsWithSkill(
4966
+ workflowsDir,
4967
+ entries
4968
+ );
4969
+ const depBlock = renderDeprecationBlock(deprecated);
4970
+ if (depBlock) console.log(depBlock);
4682
4971
  if (toInstall.length === 0) {
4683
4972
  console.log("setup: no workflow directories with SKILL.md found \u2014 nothing to install");
4684
4973
  process.exit(2);
@@ -4687,22 +4976,24 @@ function registerSetup(program2) {
4687
4976
  console.log(
4688
4977
  `[dry-run] setup would install ${toInstall.length} workflow(s) to ${skillsBase}:`
4689
4978
  );
4690
- for (const name of toInstall) {
4691
- console.log(` ${name} \u2192 ${join(skillsBase, name)}`);
4979
+ for (const wf of toInstall) {
4980
+ const masterTag = wf.isMaster ? " (master)" : "";
4981
+ console.log(` ${wf.name} \u2192 ${join(skillsBase, wf.name)}${masterTag}`);
4692
4982
  }
4693
4983
  console.log(` run without --dry-run to execute`);
4694
4984
  process.exit(0);
4695
4985
  }
4696
4986
  let skillsInstalled = 0;
4697
- for (const name of toInstall) {
4698
- const src = join(workflowsDir, name);
4699
- const dst = join(skillsBase, name);
4987
+ for (const wf of toInstall) {
4988
+ const src = join(workflowsDir, wf.relPath);
4989
+ const dst = join(skillsBase, wf.name);
4700
4990
  try {
4701
4991
  await cp(src, dst, { recursive: true, force: true });
4702
- console.log(` [A] installed ${name} \u2192 ${dst}`);
4992
+ const masterTag = wf.isMaster ? " (master)" : "";
4993
+ console.log(` [A] installed ${wf.name} \u2192 ${dst}${masterTag}`);
4703
4994
  skillsInstalled++;
4704
4995
  } catch (e) {
4705
- console.error(` error: failed to copy ${name}: ${e.message}`);
4996
+ console.error(` error: failed to copy ${wf.name}: ${e.message}`);
4706
4997
  process.exit(1);
4707
4998
  }
4708
4999
  }
@@ -4963,7 +5254,7 @@ var uninstallNpmCli = async (ctx) => {
4963
5254
  const m = install.cmd.match(/npm\s+(?:install|i)\s+(?:-g\s+)?(\S+)/);
4964
5255
  const pkg = m?.[1] ?? ctx.manifest.metadata.upstream.source;
4965
5256
  const isWin = process.platform === "win32";
4966
- const result = await new Promise((resolve8) => {
5257
+ const result = await new Promise((resolve9) => {
4967
5258
  const child = isWin ? spawn("cmd.exe", ["/c", "npm", "uninstall", "-g", pkg], { windowsHide: true }) : spawn("npm", ["uninstall", "-g", pkg], { shell: false });
4968
5259
  let stderr = "";
4969
5260
  child.stderr?.setEncoding("utf8").on("data", (c) => {
@@ -4971,15 +5262,15 @@ var uninstallNpmCli = async (ctx) => {
4971
5262
  });
4972
5263
  const timer = setTimeout(() => {
4973
5264
  child.kill("SIGKILL");
4974
- resolve8({ exitCode: -1, stderr: `${stderr}[timeout]` });
5265
+ resolve9({ exitCode: -1, stderr: `${stderr}[timeout]` });
4975
5266
  }, 3e4);
4976
5267
  child.on("error", (e) => {
4977
5268
  clearTimeout(timer);
4978
- resolve8({ exitCode: -1, stderr: e.message });
5269
+ resolve9({ exitCode: -1, stderr: e.message });
4979
5270
  });
4980
5271
  child.on("close", (code) => {
4981
5272
  clearTimeout(timer);
4982
- resolve8({ exitCode: code ?? -1, stderr });
5273
+ resolve9({ exitCode: code ?? -1, stderr });
4983
5274
  });
4984
5275
  });
4985
5276
  if (result.exitCode !== 0) {