@deftai/directive 0.55.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 (261) hide show
  1. package/dist/bin.d.ts +3 -0
  2. package/dist/bin.js +5 -0
  3. package/dist/branch-parity.d.ts +47 -0
  4. package/dist/branch-parity.js +263 -0
  5. package/dist/cache-parity.d.ts +36 -0
  6. package/dist/cache-parity.js +165 -0
  7. package/dist/cache.d.ts +4 -0
  8. package/dist/cache.js +10 -0
  9. package/dist/capacity-backfill.d.ts +3 -0
  10. package/dist/capacity-backfill.js +9 -0
  11. package/dist/capacity-show.d.ts +3 -0
  12. package/dist/capacity-show.js +9 -0
  13. package/dist/check.d.ts +10 -0
  14. package/dist/check.js +60 -0
  15. package/dist/cli-router/index.d.ts +8 -0
  16. package/dist/cli-router/index.js +37 -0
  17. package/dist/cli-router/route-argv.d.ts +32 -0
  18. package/dist/cli-router/route-argv.js +226 -0
  19. package/dist/codebase-default-extractor.d.ts +3 -0
  20. package/dist/codebase-default-extractor.js +9 -0
  21. package/dist/codebase-map-fresh.d.ts +3 -0
  22. package/dist/codebase-map-fresh.js +9 -0
  23. package/dist/codebase-map.d.ts +3 -0
  24. package/dist/codebase-map.js +9 -0
  25. package/dist/codebase-parity.d.ts +30 -0
  26. package/dist/codebase-parity.js +294 -0
  27. package/dist/codebase-projection-registry.d.ts +3 -0
  28. package/dist/codebase-projection-registry.js +9 -0
  29. package/dist/codebase-provider.d.ts +3 -0
  30. package/dist/codebase-provider.js +9 -0
  31. package/dist/content-validate-cli/validate-links.d.ts +11 -0
  32. package/dist/content-validate-cli/validate-links.js +37 -0
  33. package/dist/content-validate-cli/validate-strategy-output.d.ts +13 -0
  34. package/dist/content-validate-cli/validate-strategy-output.js +56 -0
  35. package/dist/content-validate-cli/verify-capacity.d.ts +12 -0
  36. package/dist/content-validate-cli/verify-capacity.js +54 -0
  37. package/dist/dispatch.d.ts +26 -0
  38. package/dist/dispatch.js +569 -0
  39. package/dist/doctor-parity.d.ts +38 -0
  40. package/dist/doctor-parity.js +151 -0
  41. package/dist/doctor.d.ts +3 -0
  42. package/dist/doctor.js +10 -0
  43. package/dist/gates-cli/_helpers.d.ts +18 -0
  44. package/dist/gates-cli/_helpers.js +71 -0
  45. package/dist/index.d.ts +11 -0
  46. package/dist/index.js +15 -0
  47. package/dist/init-cli/constants.d.ts +5 -0
  48. package/dist/init-cli/constants.js +5 -0
  49. package/dist/init-cli/init.d.ts +3 -0
  50. package/dist/init-cli/init.js +11 -0
  51. package/dist/init-cli/resolve-binary.d.ts +34 -0
  52. package/dist/init-cli/resolve-binary.js +78 -0
  53. package/dist/init-cli/run-deft-install.d.ts +23 -0
  54. package/dist/init-cli/run-deft-install.js +71 -0
  55. package/dist/init-cli/update.d.ts +3 -0
  56. package/dist/init-cli/update.js +11 -0
  57. package/dist/install-cli/coverage-map.d.ts +14 -0
  58. package/dist/install-cli/coverage-map.js +111 -0
  59. package/dist/intake-parity.d.ts +30 -0
  60. package/dist/intake-parity.js +203 -0
  61. package/dist/lifecycle-cli/coverage-map.d.ts +16 -0
  62. package/dist/lifecycle-cli/coverage-map.js +254 -0
  63. package/dist/lifecycle-cli/helpers.d.ts +8 -0
  64. package/dist/lifecycle-cli/helpers.js +20 -0
  65. package/dist/lifecycle-packs-parity.d.ts +30 -0
  66. package/dist/lifecycle-packs-parity.js +377 -0
  67. package/dist/orchestration-cli/coverage-map.d.ts +21 -0
  68. package/dist/orchestration-cli/coverage-map.js +225 -0
  69. package/dist/orchestration-cli/helpers.d.ts +11 -0
  70. package/dist/orchestration-cli/helpers.js +35 -0
  71. package/dist/orchestration-parity.d.ts +38 -0
  72. package/dist/orchestration-parity.js +364 -0
  73. package/dist/parity.d.ts +36 -0
  74. package/dist/parity.js +176 -0
  75. package/dist/platform-parity.d.ts +26 -0
  76. package/dist/platform-parity.js +309 -0
  77. package/dist/policy-parity.d.ts +35 -0
  78. package/dist/policy-parity.js +214 -0
  79. package/dist/policy.d.ts +27 -0
  80. package/dist/policy.js +316 -0
  81. package/dist/pr-closing-keywords-parity.d.ts +45 -0
  82. package/dist/pr-closing-keywords-parity.js +259 -0
  83. package/dist/pr-closing-keywords.d.ts +3 -0
  84. package/dist/pr-closing-keywords.js +10 -0
  85. package/dist/pr-merge-readiness-parity.d.ts +44 -0
  86. package/dist/pr-merge-readiness-parity.js +296 -0
  87. package/dist/pr-merge-readiness.d.ts +3 -0
  88. package/dist/pr-merge-readiness.js +10 -0
  89. package/dist/pr-monitor-parity.d.ts +44 -0
  90. package/dist/pr-monitor-parity.js +283 -0
  91. package/dist/pr-monitor.d.ts +3 -0
  92. package/dist/pr-monitor.js +10 -0
  93. package/dist/pr-protected-issues-parity.d.ts +41 -0
  94. package/dist/pr-protected-issues-parity.js +220 -0
  95. package/dist/pr-protected-issues.d.ts +3 -0
  96. package/dist/pr-protected-issues.js +10 -0
  97. package/dist/pr-wait-mergeable-parity.d.ts +45 -0
  98. package/dist/pr-wait-mergeable-parity.js +340 -0
  99. package/dist/pr-wait-mergeable.d.ts +3 -0
  100. package/dist/pr-wait-mergeable.js +10 -0
  101. package/dist/preflight-cache.d.ts +16 -0
  102. package/dist/preflight-cache.js +106 -0
  103. package/dist/preflight-gh.d.ts +12 -0
  104. package/dist/preflight-gh.js +188 -0
  105. package/dist/probe-session.d.ts +3 -0
  106. package/dist/probe-session.js +10 -0
  107. package/dist/release-e2e-parity.d.ts +31 -0
  108. package/dist/release-e2e-parity.js +114 -0
  109. package/dist/release-e2e.d.ts +3 -0
  110. package/dist/release-e2e.js +10 -0
  111. package/dist/release-parity.d.ts +40 -0
  112. package/dist/release-parity.js +223 -0
  113. package/dist/release-publish-parity.d.ts +36 -0
  114. package/dist/release-publish-parity.js +138 -0
  115. package/dist/release-publish.d.ts +3 -0
  116. package/dist/release-publish.js +10 -0
  117. package/dist/release-rollback-parity.d.ts +37 -0
  118. package/dist/release-rollback-parity.js +161 -0
  119. package/dist/release-rollback.d.ts +3 -0
  120. package/dist/release-rollback.js +10 -0
  121. package/dist/release.d.ts +3 -0
  122. package/dist/release.js +10 -0
  123. package/dist/render-cli/deft-ts-runner.d.ts +20 -0
  124. package/dist/render-cli/deft-ts-runner.js +35 -0
  125. package/dist/render-cli/prd-render-cli.d.ts +2 -0
  126. package/dist/render-cli/prd-render-cli.js +7 -0
  127. package/dist/render-cli/project-render-cli.d.ts +2 -0
  128. package/dist/render-cli/project-render-cli.js +6 -0
  129. package/dist/render-cli/spec-render-cli.d.ts +2 -0
  130. package/dist/render-cli/spec-render-cli.js +6 -0
  131. package/dist/render-cli/spec-validate-cli.d.ts +2 -0
  132. package/dist/render-cli/spec-validate-cli.js +6 -0
  133. package/dist/render-parity.d.ts +35 -0
  134. package/dist/render-parity.js +383 -0
  135. package/dist/scm-parity.d.ts +39 -0
  136. package/dist/scm-parity.js +181 -0
  137. package/dist/scope-lifecycle-parity.d.ts +35 -0
  138. package/dist/scope-lifecycle-parity.js +177 -0
  139. package/dist/scope-lifecycle.d.ts +4 -0
  140. package/dist/scope-lifecycle.js +29 -0
  141. package/dist/session-parity.d.ts +39 -0
  142. package/dist/session-parity.js +260 -0
  143. package/dist/slice-parity.d.ts +36 -0
  144. package/dist/slice-parity.js +304 -0
  145. package/dist/slice.d.ts +4 -0
  146. package/dist/slice.js +29 -0
  147. package/dist/story-ready-parity.d.ts +49 -0
  148. package/dist/story-ready-parity.js +254 -0
  149. package/dist/subagent-monitor.d.ts +3 -0
  150. package/dist/subagent-monitor.js +10 -0
  151. package/dist/swarm-parity.d.ts +28 -0
  152. package/dist/swarm-parity.js +326 -0
  153. package/dist/toolchain-check.d.ts +3 -0
  154. package/dist/toolchain-check.js +14 -0
  155. package/dist/triage-actions-parity.d.ts +33 -0
  156. package/dist/triage-actions-parity.js +201 -0
  157. package/dist/triage-actions.d.ts +17 -0
  158. package/dist/triage-actions.js +144 -0
  159. package/dist/triage-aux-a-parity.d.ts +35 -0
  160. package/dist/triage-aux-a-parity.js +172 -0
  161. package/dist/triage-aux-b-parity.d.ts +32 -0
  162. package/dist/triage-aux-b-parity.js +308 -0
  163. package/dist/triage-bootstrap-parity.d.ts +44 -0
  164. package/dist/triage-bootstrap-parity.js +226 -0
  165. package/dist/triage-bootstrap.d.ts +24 -0
  166. package/dist/triage-bootstrap.js +172 -0
  167. package/dist/triage-bulk.d.ts +17 -0
  168. package/dist/triage-bulk.js +154 -0
  169. package/dist/triage-classify-parity.d.ts +40 -0
  170. package/dist/triage-classify-parity.js +227 -0
  171. package/dist/triage-classify.d.ts +13 -0
  172. package/dist/triage-classify.js +76 -0
  173. package/dist/triage-help.d.ts +3 -0
  174. package/dist/triage-help.js +10 -0
  175. package/dist/triage-queue-parity.d.ts +59 -0
  176. package/dist/triage-queue-parity.js +363 -0
  177. package/dist/triage-queue.d.ts +17 -0
  178. package/dist/triage-queue.js +174 -0
  179. package/dist/triage-reconcile.d.ts +11 -0
  180. package/dist/triage-reconcile.js +76 -0
  181. package/dist/triage-refresh.d.ts +7 -0
  182. package/dist/triage-refresh.js +37 -0
  183. package/dist/triage-scope-drift.d.ts +12 -0
  184. package/dist/triage-scope-drift.js +117 -0
  185. package/dist/triage-scope-parity.d.ts +34 -0
  186. package/dist/triage-scope-parity.js +218 -0
  187. package/dist/triage-scope.d.ts +4 -0
  188. package/dist/triage-scope.js +29 -0
  189. package/dist/triage-smoketest.d.ts +3 -0
  190. package/dist/triage-smoketest.js +43 -0
  191. package/dist/triage-subscribe.d.ts +15 -0
  192. package/dist/triage-subscribe.js +157 -0
  193. package/dist/triage-summary-parity.d.ts +50 -0
  194. package/dist/triage-summary-parity.js +306 -0
  195. package/dist/triage-summary.d.ts +14 -0
  196. package/dist/triage-summary.js +77 -0
  197. package/dist/triage-welcome.d.ts +12 -0
  198. package/dist/triage-welcome.js +78 -0
  199. package/dist/ts-check-lane.d.ts +9 -0
  200. package/dist/ts-check-lane.js +49 -0
  201. package/dist/validate-content-parity.d.ts +33 -0
  202. package/dist/validate-content-parity.js +356 -0
  203. package/dist/vbrief-activate-parity.d.ts +39 -0
  204. package/dist/vbrief-activate-parity.js +216 -0
  205. package/dist/vbrief-activate.d.ts +3 -0
  206. package/dist/vbrief-activate.js +7 -0
  207. package/dist/vbrief-build-parity.d.ts +28 -0
  208. package/dist/vbrief-build-parity.js +399 -0
  209. package/dist/vbrief-build.d.ts +3 -0
  210. package/dist/vbrief-build.js +8 -0
  211. package/dist/vbrief-preflight-parity.d.ts +34 -0
  212. package/dist/vbrief-preflight-parity.js +163 -0
  213. package/dist/vbrief-preflight.d.ts +12 -0
  214. package/dist/vbrief-preflight.js +58 -0
  215. package/dist/vbrief-reconcile-parity.d.ts +22 -0
  216. package/dist/vbrief-reconcile-parity.js +600 -0
  217. package/dist/vbrief-reconcile.d.ts +3 -0
  218. package/dist/vbrief-reconcile.js +7 -0
  219. package/dist/vbrief-validate-parity.d.ts +27 -0
  220. package/dist/vbrief-validate-parity.js +122 -0
  221. package/dist/vbrief-validate.d.ts +3 -0
  222. package/dist/vbrief-validate.js +8 -0
  223. package/dist/vbrief-validation-parity.d.ts +28 -0
  224. package/dist/vbrief-validation-parity.js +645 -0
  225. package/dist/vbrief-validation.d.ts +3 -0
  226. package/dist/vbrief-validation.js +8 -0
  227. package/dist/verify-branch.d.ts +14 -0
  228. package/dist/verify-branch.js +81 -0
  229. package/dist/verify-encoding.d.ts +15 -0
  230. package/dist/verify-encoding.js +86 -0
  231. package/dist/verify-env-parity.d.ts +28 -0
  232. package/dist/verify-env-parity.js +272 -0
  233. package/dist/verify-hooks-installed.d.ts +10 -0
  234. package/dist/verify-hooks-installed.js +48 -0
  235. package/dist/verify-investigation.d.ts +3 -0
  236. package/dist/verify-investigation.js +10 -0
  237. package/dist/verify-judgment-gates.d.ts +3 -0
  238. package/dist/verify-judgment-gates.js +10 -0
  239. package/dist/verify-no-task-runtime.d.ts +3 -0
  240. package/dist/verify-no-task-runtime.js +16 -0
  241. package/dist/verify-session-ritual.d.ts +13 -0
  242. package/dist/verify-session-ritual.js +78 -0
  243. package/dist/verify-source-cli/rule-ownership-lint.d.ts +12 -0
  244. package/dist/verify-source-cli/rule-ownership-lint.js +61 -0
  245. package/dist/verify-source-cli/verify-content-manifest.d.ts +12 -0
  246. package/dist/verify-source-cli/verify-content-manifest.js +61 -0
  247. package/dist/verify-source-cli/verify-scm-boundary.d.ts +13 -0
  248. package/dist/verify-source-cli/verify-scm-boundary.js +66 -0
  249. package/dist/verify-source-cli/verify-stubs.d.ts +11 -0
  250. package/dist/verify-source-cli/verify-stubs.js +27 -0
  251. package/dist/verify-source-parity.d.ts +26 -0
  252. package/dist/verify-source-parity.js +178 -0
  253. package/dist/verify-story-ready.d.ts +16 -0
  254. package/dist/verify-story-ready.js +138 -0
  255. package/dist/verify-tools.d.ts +13 -0
  256. package/dist/verify-tools.js +67 -0
  257. package/dist/verify-wip-cap.d.ts +13 -0
  258. package/dist/verify-wip-cap.js +62 -0
  259. package/dist/wip-cap-parity.d.ts +39 -0
  260. package/dist/wip-cap-parity.js +209 -0
  261. package/package.json +50 -0
@@ -0,0 +1,254 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Golden-output parity harness (#1720): builds throwaway git fixture repos for
4
+ * story-start Gate 0 scenarios, runs BOTH the Python oracle
5
+ * (`scripts/preflight_story_start.py`) and the ported TS gate, and diffs exit
6
+ * codes + normalised messages. Exit 0 only on identical results.
7
+ *
8
+ * Exit codes: 0 parity / 1 divergence / 2 harness setup error.
9
+ */
10
+ import { execFileSync } from "node:child_process";
11
+ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
12
+ import { tmpdir } from "node:os";
13
+ import { dirname, join, resolve } from "node:path";
14
+ import { fileURLToPath } from "node:url";
15
+ function writeVbrief(root, rel, status = "running", folder = "active") {
16
+ const full = join(root, "vbrief", folder, rel);
17
+ mkdirSync(dirname(full), { recursive: true });
18
+ const payload = {
19
+ plan: { status, title: "T", items: [] },
20
+ vBRIEFInfo: { version: "0.6" },
21
+ };
22
+ writeFileSync(full, `${JSON.stringify(payload)}\n`, "utf8");
23
+ }
24
+ function renderAllocation(fields) {
25
+ const lines = ["Dispatch envelope.", "", "## Allocation context", ""];
26
+ for (const [key, value] of Object.entries(fields)) {
27
+ lines.push(`- ${key}: ${value === null ? "null" : value}`);
28
+ }
29
+ lines.push("", "## Next section", "- trailing: ignored");
30
+ return lines.join("\n");
31
+ }
32
+ const VALID_COHORT = {
33
+ allocation_plan_id: "orchestrator-run-019e80bd",
34
+ batching_rationale: "Three disjoint-file-scope stories from #1378.",
35
+ cohort_vbriefs: "[vbrief/active/a.json, vbrief/active/b.json]",
36
+ dispatch_kind: "swarm-cohort",
37
+ operator_approval_evidence: "user directive 2026-06-01T02:26Z",
38
+ };
39
+ /** Scenarios exercised by the parity harness (mirrors Python contract cases). */
40
+ export const PARITY_SCENARIOS = [
41
+ {
42
+ name: "clean-active-running-solo",
43
+ vbriefRel: "2026-06-01-story.vbrief.json",
44
+ envelopeRel: null,
45
+ },
46
+ {
47
+ name: "dirty-tree",
48
+ vbriefRel: "2026-06-01-story.vbrief.json",
49
+ envelopeRel: null,
50
+ dirty: true,
51
+ },
52
+ {
53
+ name: "non-running-vbrief",
54
+ vbriefRel: "2026-06-01-pending.vbrief.json",
55
+ vbriefStatus: "approved",
56
+ envelopeRel: null,
57
+ },
58
+ {
59
+ name: "satisfied-swarm-cohort",
60
+ vbriefRel: "2026-06-01-story.vbrief.json",
61
+ envelopeRel: "envelope-cohort.md",
62
+ },
63
+ {
64
+ name: "malformed-allocation",
65
+ vbriefRel: "2026-06-01-story.vbrief.json",
66
+ envelopeRel: "envelope-bad.md",
67
+ },
68
+ ];
69
+ function gitCommit(cwd, message) {
70
+ execFileSync("git", ["commit", "-q", "-m", message], {
71
+ cwd,
72
+ env: {
73
+ ...process.env,
74
+ GIT_AUTHOR_NAME: "deft-parity",
75
+ GIT_AUTHOR_EMAIL: "parity@test.local",
76
+ GIT_COMMITTER_NAME: "deft-parity",
77
+ GIT_COMMITTER_EMAIL: "parity@test.local",
78
+ },
79
+ });
80
+ }
81
+ function runCapture(cmd, args, cwd) {
82
+ try {
83
+ const stdout = execFileSync(cmd, args, {
84
+ cwd,
85
+ encoding: "utf8",
86
+ stdio: ["ignore", "pipe", "pipe"],
87
+ });
88
+ return { status: 0, stdout, stderr: "" };
89
+ }
90
+ catch (err) {
91
+ const e = err;
92
+ return {
93
+ status: typeof e.status === "number" ? e.status : 2,
94
+ stdout: typeof e.stdout === "string" ? e.stdout : "",
95
+ stderr: typeof e.stderr === "string" ? e.stderr : "",
96
+ };
97
+ }
98
+ }
99
+ /** Normalise gate message for comparison (trim, collapse whitespace). */
100
+ export function normaliseMessage(stdout, stderr, exitCode) {
101
+ const raw = exitCode === 0 ? stdout : stderr;
102
+ return raw.trim().replace(/\s+/g, " ");
103
+ }
104
+ /** Build a fixture repo for one scenario; return repo root + vbrief absolute path. */
105
+ export function buildScenarioRepo(scenario) {
106
+ const root = mkdtempSync(join(tmpdir(), "deft-story-ready-parity-"));
107
+ const vbriefName = scenario.vbriefRel;
108
+ const status = scenario.vbriefStatus ?? "running";
109
+ writeVbrief(root, vbriefName, status);
110
+ if (scenario.dirty) {
111
+ writeFileSync(join(root, "scratch.txt"), "dirty\n", "utf8");
112
+ }
113
+ let envelopePath = null;
114
+ if (scenario.envelopeRel === "envelope-cohort.md") {
115
+ envelopePath = join(root, scenario.envelopeRel);
116
+ writeFileSync(envelopePath, renderAllocation(VALID_COHORT), "utf8");
117
+ }
118
+ else if (scenario.envelopeRel === "envelope-bad.md") {
119
+ envelopePath = join(root, scenario.envelopeRel);
120
+ const bad = { ...VALID_COHORT };
121
+ delete bad.dispatch_kind;
122
+ writeFileSync(envelopePath, renderAllocation(bad), "utf8");
123
+ }
124
+ execFileSync("git", ["init", "-q"], { cwd: root });
125
+ execFileSync("git", ["add", "-A"], { cwd: root });
126
+ if (!scenario.dirty) {
127
+ gitCommit(root, "init");
128
+ }
129
+ const vbriefPath = join(root, "vbrief", "active", vbriefName);
130
+ return { root, vbriefPath, envelopePath };
131
+ }
132
+ function resolveDeftRoot() {
133
+ if (process.env.DEFT_ROOT !== undefined && process.env.DEFT_ROOT.length > 0) {
134
+ return resolve(process.env.DEFT_ROOT);
135
+ }
136
+ return resolve(dirname(fileURLToPath(import.meta.url)), "..", "..", "..");
137
+ }
138
+ function runScenario(deftRoot, scenario) {
139
+ const { root, vbriefPath, envelopePath } = buildScenarioRepo(scenario);
140
+ const pyArgs = [
141
+ "run",
142
+ "python",
143
+ join(deftRoot, "scripts", "preflight_story_start.py"),
144
+ "--vbrief-path",
145
+ vbriefPath,
146
+ "--project-root",
147
+ root,
148
+ ];
149
+ if (envelopePath !== null) {
150
+ pyArgs.push("--allocation-context", envelopePath);
151
+ }
152
+ if (scenario.allowDirty) {
153
+ pyArgs.push("--allow-dirty");
154
+ }
155
+ const tsArgs = [
156
+ join(deftRoot, "packages", "cli", "dist", "verify-story-ready.js"),
157
+ "--vbrief-path",
158
+ vbriefPath,
159
+ "--project-root",
160
+ root,
161
+ ];
162
+ if (envelopePath !== null) {
163
+ tsArgs.push("--allocation-context", envelopePath);
164
+ }
165
+ if (scenario.allowDirty) {
166
+ tsArgs.push("--allow-dirty");
167
+ }
168
+ const py = runCapture("uv", pyArgs, deftRoot);
169
+ const ts = runCapture("node", tsArgs, deftRoot);
170
+ return {
171
+ root,
172
+ python: {
173
+ name: scenario.name,
174
+ exitCode: py.status,
175
+ stdout: py.stdout,
176
+ stderr: py.stderr,
177
+ },
178
+ ts: {
179
+ name: scenario.name,
180
+ exitCode: ts.status,
181
+ stdout: ts.stdout,
182
+ stderr: ts.stderr,
183
+ },
184
+ };
185
+ }
186
+ /** Diff python vs TS gate outputs across all parity scenarios. */
187
+ export function diffParity(python, ts) {
188
+ const pythonMessage = normaliseMessage(python.stdout, python.stderr, python.exitCode);
189
+ const tsMessage = normaliseMessage(ts.stdout, ts.stderr, ts.exitCode);
190
+ return {
191
+ exitMismatch: python.exitCode !== ts.exitCode,
192
+ messageMismatch: pythonMessage !== tsMessage,
193
+ pythonMessage,
194
+ tsMessage,
195
+ };
196
+ }
197
+ /** Run all parity scenarios and return a structured result. */
198
+ export function runParity() {
199
+ const deftRoot = resolveDeftRoot();
200
+ const scenarios = [];
201
+ for (const scenario of PARITY_SCENARIOS) {
202
+ const { root, python, ts } = runScenario(deftRoot, scenario);
203
+ try {
204
+ const diff = diffParity(python, ts);
205
+ scenarios.push({
206
+ name: scenario.name,
207
+ pythonExit: python.exitCode,
208
+ tsExit: ts.exitCode,
209
+ ...diff,
210
+ });
211
+ }
212
+ finally {
213
+ rmSync(root, { recursive: true, force: true });
214
+ }
215
+ }
216
+ const ok = scenarios.every((s) => !s.exitMismatch && !s.messageMismatch);
217
+ return { ok, scenarios };
218
+ }
219
+ /** Render a human-readable parity report (exported for unit tests). */
220
+ export function renderReport(result) {
221
+ if (result.ok) {
222
+ return `verify_story_ready parity: CLEAN -- Python and TS agree on ${result.scenarios.length} scenario(s).`;
223
+ }
224
+ const lines = ["verify_story_ready parity: DIVERGENCE"];
225
+ for (const s of result.scenarios) {
226
+ if (s.exitMismatch || s.messageMismatch) {
227
+ lines.push(` scenario: ${s.name}`);
228
+ if (s.exitMismatch) {
229
+ lines.push(` exit mismatch: python=${s.pythonExit} ts=${s.tsExit}`);
230
+ }
231
+ if (s.messageMismatch) {
232
+ lines.push(` python: ${s.pythonMessage}`);
233
+ lines.push(` ts: ${s.tsMessage}`);
234
+ }
235
+ }
236
+ }
237
+ return lines.join("\n");
238
+ }
239
+ if (process.argv[1] !== undefined && fileURLToPath(import.meta.url) === process.argv[1]) {
240
+ try {
241
+ const result = runParity();
242
+ if (result.ok) {
243
+ process.stdout.write(`${renderReport(result)}\n`);
244
+ process.exit(0);
245
+ }
246
+ process.stderr.write(`${renderReport(result)}\n`);
247
+ process.exit(1);
248
+ }
249
+ catch (err) {
250
+ process.stderr.write(`verify_story_ready parity: harness error -- ${String(err)}\n`);
251
+ process.exit(2);
252
+ }
253
+ }
254
+ //# sourceMappingURL=story-ready-parity.js.map
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export declare function run(argv: string[]): number;
3
+ //# sourceMappingURL=subagent-monitor.d.ts.map
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env node
2
+ import { fileURLToPath } from "node:url";
3
+ import { cmdSubagentMonitor } from "@deftai/directive-core/orchestration";
4
+ export function run(argv) {
5
+ return cmdSubagentMonitor(argv);
6
+ }
7
+ if (process.argv[1] !== undefined && fileURLToPath(import.meta.url) === process.argv[1]) {
8
+ process.exit(run(process.argv.slice(2)));
9
+ }
10
+ //# sourceMappingURL=subagent-monitor.js.map
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env node
2
+ export interface Capture {
3
+ exitCode: number;
4
+ stdout: string;
5
+ stderr: string;
6
+ }
7
+ export interface ParityCase {
8
+ name: string;
9
+ run: (deftRoot: string) => {
10
+ python: Capture;
11
+ ts: Capture;
12
+ };
13
+ }
14
+ export declare function normalizeOutput(text: string): string;
15
+ export declare const PARITY_CASES: readonly ParityCase[];
16
+ export declare function diffCase(name: string, python: Capture, ts: Capture): {
17
+ name: string;
18
+ ok: boolean;
19
+ exitMismatch: boolean;
20
+ stdoutMismatch: boolean;
21
+ stderrMismatch: boolean;
22
+ };
23
+ export declare function runParity(): {
24
+ ok: boolean;
25
+ cases: ReturnType<typeof diffCase>[];
26
+ };
27
+ export declare function runParityCli(): number;
28
+ //# sourceMappingURL=swarm-parity.d.ts.map
@@ -0,0 +1,326 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Golden-diff parity harness (#1788): runs TS swarm cohort verbs vs the FROZEN
4
+ * Python oracle (cache-off) across launch-manifest, worktree-map collision,
5
+ * readiness three-state, and review-clean fixtures.
6
+ */
7
+ import { execFileSync, spawnSync } from "node:child_process";
8
+ import { chmodSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
9
+ import { tmpdir } from "node:os";
10
+ import { dirname, join, resolve } from "node:path";
11
+ import { fileURLToPath } from "node:url";
12
+ const HEAD_SHA = "abc1234567890def1234567890abcdef12345678";
13
+ const FAKE_GH_PY = `import json, os, sys
14
+ responses = json.loads(os.environ.get("DEFT_FAKE_GH_RESPONSES", "{}"))
15
+ cmd = " ".join(sys.argv[1:])
16
+ label = "unknown"
17
+ if "headRefOid" in cmd: label = "head-sha"
18
+ elif "/issues/" in cmd and "/comments" in cmd and "--jq" in cmd: label = "comments-jq"
19
+ resp = responses.get(label, {"returncode": 1, "stderr": f"unexpected: {label}", "stdout": ""})
20
+ if resp.get("stdout"): sys.stdout.write(resp["stdout"])
21
+ if resp.get("stderr"): sys.stderr.write(resp["stderr"])
22
+ sys.exit(int(resp.get("returncode", 0)))
23
+ `;
24
+ function runCapture(cmd, args, cwd, env) {
25
+ const result = spawnSync(cmd, args, {
26
+ cwd,
27
+ encoding: "utf8",
28
+ env: env ?? process.env,
29
+ stdio: ["ignore", "pipe", "pipe"],
30
+ });
31
+ return {
32
+ exitCode: result.status ?? 2,
33
+ stdout: typeof result.stdout === "string" ? result.stdout : "",
34
+ stderr: typeof result.stderr === "string" ? result.stderr : "",
35
+ };
36
+ }
37
+ function resolveDeftRoot() {
38
+ if (process.env.DEFT_ROOT !== undefined && process.env.DEFT_ROOT.length > 0) {
39
+ return resolve(process.env.DEFT_ROOT);
40
+ }
41
+ return resolve(dirname(fileURLToPath(import.meta.url)), "..", "..", "..");
42
+ }
43
+ export function normalizeOutput(text) {
44
+ return text
45
+ .replace(/--project-root [^\s]+/g, "--project-root <ROOT>")
46
+ .replace(/--repo-root [^\s]+/g, "--repo-root <ROOT>")
47
+ .replace(/\/tmp\/[^\s]+/g, "<TMP>")
48
+ .replace(/\/home\/[^\s]+/g, "<PATH>")
49
+ .trim()
50
+ .replace(/\s+/g, " ");
51
+ }
52
+ function gitInit(repo) {
53
+ execFileSync("git", ["init", "-q", "-b", "master", repo], { encoding: "utf8" });
54
+ execFileSync("git", ["config", "user.email", "parity@test.local"], {
55
+ cwd: repo,
56
+ encoding: "utf8",
57
+ });
58
+ execFileSync("git", ["config", "user.name", "deft-parity"], { cwd: repo, encoding: "utf8" });
59
+ writeFileSync(join(repo, "f.txt"), "x\n", "utf8");
60
+ execFileSync("git", ["add", "-A"], { cwd: repo, encoding: "utf8" });
61
+ execFileSync("git", ["commit", "-q", "-m", "init"], { cwd: repo, encoding: "utf8" });
62
+ }
63
+ function writeReadyStory(project, filename, storyId, issue) {
64
+ const full = join(project, "vbrief", "active", filename);
65
+ mkdirSync(dirname(full), { recursive: true });
66
+ const acceptanceValues = [
67
+ `Given ${storyId} input, when the story runs, then it returns a scoped result.`,
68
+ `Given ${storyId} failure input, when the story runs, then it rejects the request.`,
69
+ ];
70
+ const payload = {
71
+ vBRIEFInfo: { version: "0.6" },
72
+ plan: {
73
+ id: storyId,
74
+ title: storyId,
75
+ status: "running",
76
+ references: [
77
+ {
78
+ uri: `https://github.com/deftai/directive/issues/${issue}`,
79
+ type: "x-vbrief/github-issue",
80
+ },
81
+ ],
82
+ narratives: {
83
+ Description: `${storyId} implements a focused product behavior for the active workflow. The story stays within a narrow code path and includes targeted tests for success and failure behavior.`,
84
+ ImplementationPlan: `1. Update the ${storyId} source path to implement the focused workflow behavior.\n2. Add targeted tests for ${storyId} success and failure outcomes.`,
85
+ Traces: "FR-1",
86
+ UserStory: `As a product user, I want ${storyId} behavior, so that I can complete the workflow.`,
87
+ },
88
+ items: acceptanceValues.map((criterion, index) => ({
89
+ id: `${storyId}-a${index + 1}`,
90
+ title: `Acceptance item ${index + 1}`,
91
+ status: "pending",
92
+ narrative: { Acceptance: criterion, Traces: "FR-1" },
93
+ })),
94
+ metadata: {
95
+ kind: "story",
96
+ swarm: {
97
+ readiness: "ready",
98
+ parallel_safe: true,
99
+ file_scope: [`src/${storyId}.ts`],
100
+ verify_commands: [`npm test -- ${storyId}`],
101
+ expected_outputs: ["focused tests pass"],
102
+ depends_on: [],
103
+ conflict_group: "auth",
104
+ size: "small",
105
+ file_scope_confidence: "high",
106
+ model_tier: "medium",
107
+ },
108
+ },
109
+ },
110
+ };
111
+ writeFileSync(full, `${JSON.stringify(payload, null, 2)}\n`, "utf8");
112
+ }
113
+ function writeProjectDef(project) {
114
+ const full = join(project, "vbrief", "PROJECT-DEFINITION.vbrief.json");
115
+ mkdirSync(dirname(full), { recursive: true });
116
+ writeFileSync(full, `${JSON.stringify({ vBRIEFInfo: { version: "0.6" }, plan: { policy: { swarmSubagentBackend: "grok-build" } } }, null, 2)}\n`, "utf8");
117
+ }
118
+ function writeBlockedStory(project) {
119
+ const full = join(project, "vbrief", "active", "blocked.vbrief.json");
120
+ mkdirSync(dirname(full), { recursive: true });
121
+ writeFileSync(full, `${JSON.stringify({
122
+ vBRIEFInfo: { version: "0.6" },
123
+ plan: {
124
+ id: "blocked-story",
125
+ title: "blocked",
126
+ status: "running",
127
+ metadata: { kind: "story", swarm: { readiness: "not-ready" } },
128
+ },
129
+ }, null, 2)}\n`, "utf8");
130
+ }
131
+ function setupFakeGh(tmp) {
132
+ const fakeGh = join(tmp, "fake-gh");
133
+ writeFileSync(fakeGh, FAKE_GH_PY, "utf8");
134
+ chmodSync(fakeGh, 0o755);
135
+ return fakeGh;
136
+ }
137
+ function cleanGreptileBody(sha = HEAD_SHA, confidence = 5) {
138
+ return ("## Greptile Summary\n\nNo P0 or P1 issues.\n\n" +
139
+ `**Confidence Score: ${confidence}/5**\n\n` +
140
+ `Last reviewed commit: [fix](https://github.com/deftai/directive/commit/${sha})\n`);
141
+ }
142
+ export const PARITY_CASES = [
143
+ {
144
+ name: "worktree-map-collision-reject",
145
+ run: (deftRoot) => {
146
+ const repo = mkdtempSync(join(tmpdir(), "swarm-wt-"));
147
+ gitInit(repo);
148
+ const mapPath = join(repo, "map.json");
149
+ const wt = join(repo, "wt-shared");
150
+ writeFileSync(mapPath, JSON.stringify([
151
+ { story_id: "alpha", worktree_path: wt },
152
+ { story_id: "beta", worktree_path: wt },
153
+ ]), "utf8");
154
+ const pyArgs = [
155
+ "run",
156
+ "python",
157
+ join(deftRoot, "scripts", "swarm_worktrees.py"),
158
+ "--map",
159
+ mapPath,
160
+ "--base-branch",
161
+ "master",
162
+ "--repo-root",
163
+ repo,
164
+ "--no-create-missing",
165
+ ];
166
+ const tsArgs = [
167
+ join(deftRoot, "packages", "core", "dist", "swarm", "worktrees-cli.js"),
168
+ "--map",
169
+ mapPath,
170
+ "--base-branch",
171
+ "master",
172
+ "--repo-root",
173
+ repo,
174
+ "--no-create-missing",
175
+ ];
176
+ const python = runCapture("uv", pyArgs, deftRoot);
177
+ const ts = runCapture("node", tsArgs, deftRoot);
178
+ rmSync(repo, { recursive: true, force: true });
179
+ return { python, ts };
180
+ },
181
+ },
182
+ {
183
+ name: "readiness-ready-story",
184
+ run: (deftRoot) => {
185
+ const project = mkdtempSync(join(tmpdir(), "swarm-ready-"));
186
+ mkdirSync(join(project, "vbrief", "active"), { recursive: true });
187
+ writeReadyStory(project, "ready.vbrief.json", "ready-a", 9001);
188
+ const storyPath = join(project, "vbrief", "active", "ready.vbrief.json");
189
+ const py = runCapture("uv", [
190
+ "run",
191
+ "python",
192
+ join(deftRoot, "scripts", "swarm_readiness.py"),
193
+ storyPath,
194
+ "--project-root",
195
+ project,
196
+ ], deftRoot);
197
+ const ts = runCapture("node", [
198
+ join(deftRoot, "packages", "core", "dist", "swarm", "readiness-cli.js"),
199
+ storyPath,
200
+ "--project-root",
201
+ project,
202
+ ], deftRoot);
203
+ rmSync(project, { recursive: true, force: true });
204
+ return { python: py, ts };
205
+ },
206
+ },
207
+ {
208
+ name: "readiness-blocked-story",
209
+ run: (deftRoot) => {
210
+ const project = mkdtempSync(join(tmpdir(), "swarm-block-"));
211
+ writeBlockedStory(project);
212
+ const storyPath = join(project, "vbrief", "active", "blocked.vbrief.json");
213
+ const py = runCapture("uv", [
214
+ "run",
215
+ "python",
216
+ join(deftRoot, "scripts", "swarm_readiness.py"),
217
+ storyPath,
218
+ "--project-root",
219
+ project,
220
+ ], deftRoot);
221
+ const ts = runCapture("node", [
222
+ join(deftRoot, "packages", "core", "dist", "swarm", "readiness-cli.js"),
223
+ storyPath,
224
+ "--project-root",
225
+ project,
226
+ ], deftRoot);
227
+ rmSync(project, { recursive: true, force: true });
228
+ return { python: py, ts };
229
+ },
230
+ },
231
+ {
232
+ name: "review-clean-cohort-clean",
233
+ run: (deftRoot) => {
234
+ const tmp = mkdtempSync(join(tmpdir(), "swarm-rc-"));
235
+ const fakeGh = setupFakeGh(tmp);
236
+ const env = {
237
+ ...process.env,
238
+ PATH: `${dirname(fakeGh)}:${process.env.PATH ?? ""}`,
239
+ DEFT_FAKE_GH_RESPONSES: JSON.stringify({
240
+ "head-sha": { returncode: 0, stdout: `${HEAD_SHA}\n` },
241
+ "comments-jq": { returncode: 0, stdout: cleanGreptileBody() },
242
+ }),
243
+ };
244
+ const argv = ["1370", "--repo", "deftai/directive"];
245
+ const py = runCapture("uv", ["run", "python", join(deftRoot, "scripts", "swarm_verify_review_clean.py"), ...argv], deftRoot, env);
246
+ const ts = runCapture("node", [
247
+ join(deftRoot, "packages", "core", "dist", "swarm", "verify-review-clean-cli.js"),
248
+ ...argv,
249
+ ], deftRoot, env);
250
+ rmSync(tmp, { recursive: true, force: true });
251
+ return { python: py, ts };
252
+ },
253
+ },
254
+ {
255
+ name: "launch-manifest-solo",
256
+ run: (deftRoot) => {
257
+ const project = mkdtempSync(join(tmpdir(), "swarm-launch-"));
258
+ mkdirSync(join(project, "vbrief", "active"), { recursive: true });
259
+ writeReadyStory(project, "solo.vbrief.json", "solo-a", 8801);
260
+ writeProjectDef(project);
261
+ const env = { ...process.env, DEFT_PROBE_GROK_BUILD: "yes" };
262
+ const argv = ["--stories", "8801", "--project-root", project, "--autonomous"];
263
+ const py = runCapture("uv", ["run", "python", join(deftRoot, "scripts", "swarm_launch.py"), ...argv], deftRoot, env);
264
+ const ts = runCapture("node", [join(deftRoot, "packages", "core", "dist", "swarm", "launch-cli.js"), ...argv], deftRoot, env);
265
+ rmSync(project, { recursive: true, force: true });
266
+ return { python: py, ts };
267
+ },
268
+ },
269
+ ];
270
+ export function diffCase(name, python, ts) {
271
+ const pyStdout = normalizeOutput(python.stdout);
272
+ const tsStdout = normalizeOutput(ts.stdout);
273
+ const pyStderr = normalizeOutput(python.stderr);
274
+ const tsStderr = normalizeOutput(ts.stderr);
275
+ const exitMismatch = python.exitCode !== ts.exitCode;
276
+ const stdoutMismatch = pyStdout !== tsStdout;
277
+ const stderrMismatch = pyStderr !== tsStderr;
278
+ return {
279
+ name,
280
+ ok: !exitMismatch && !stdoutMismatch && !stderrMismatch,
281
+ exitMismatch,
282
+ stdoutMismatch,
283
+ stderrMismatch,
284
+ };
285
+ }
286
+ export function runParity() {
287
+ const deftRoot = resolveDeftRoot();
288
+ const cases = PARITY_CASES.map((c) => {
289
+ const { python, ts } = c.run(deftRoot);
290
+ return diffCase(c.name, python, ts);
291
+ });
292
+ return { ok: cases.every((c) => c.ok), cases };
293
+ }
294
+ export function runParityCli() {
295
+ try {
296
+ const result = runParity();
297
+ if (result.ok) {
298
+ process.stdout.write(`swarm parity: CLEAN -- Python and TS agree on ${result.cases.length} case(s).\n`);
299
+ return 0;
300
+ }
301
+ process.stderr.write("swarm parity: DIVERGENCE\n");
302
+ for (const c of result.cases) {
303
+ if (!c.ok) {
304
+ process.stderr.write(` case: ${c.name}\n`);
305
+ if (c.exitMismatch) {
306
+ process.stderr.write(" exit code mismatch\n");
307
+ }
308
+ if (c.stdoutMismatch) {
309
+ process.stderr.write(" stdout mismatch\n");
310
+ }
311
+ if (c.stderrMismatch) {
312
+ process.stderr.write(" stderr mismatch\n");
313
+ }
314
+ }
315
+ }
316
+ return 1;
317
+ }
318
+ catch (err) {
319
+ process.stderr.write(`swarm parity: harness error -- ${String(err)}\n`);
320
+ return 2;
321
+ }
322
+ }
323
+ if (process.argv[1] !== undefined && fileURLToPath(import.meta.url) === process.argv[1]) {
324
+ process.exit(runParityCli());
325
+ }
326
+ //# sourceMappingURL=swarm-parity.js.map
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export declare function run(): number;
3
+ //# sourceMappingURL=toolchain-check.d.ts.map
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env node
2
+ import { fileURLToPath } from "node:url";
3
+ import { runToolchainCheck } from "@deftai/directive-core/verify-env";
4
+ export function run() {
5
+ const result = runToolchainCheck();
6
+ for (const line of result.lines) {
7
+ process.stdout.write(`${line}\n`);
8
+ }
9
+ return result.exitCode;
10
+ }
11
+ if (process.argv[1] !== undefined && fileURLToPath(import.meta.url) === process.argv[1]) {
12
+ process.exit(run());
13
+ }
14
+ //# sourceMappingURL=toolchain-check.js.map
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env node
2
+ export interface CommandCapture {
3
+ readonly exitCode: number;
4
+ readonly stdout: string;
5
+ readonly stderr: string;
6
+ }
7
+ export interface ParityCase {
8
+ readonly name: string;
9
+ readonly argv: readonly string[];
10
+ }
11
+ export interface ParityDiff {
12
+ readonly caseName: string;
13
+ readonly exitMismatch: boolean;
14
+ readonly stdoutMismatch: boolean;
15
+ readonly stderrMismatch: boolean;
16
+ readonly pythonExit: number;
17
+ readonly tsExit: number;
18
+ }
19
+ export interface ParityResult {
20
+ readonly ok: boolean;
21
+ readonly diffs: ParityDiff[];
22
+ }
23
+ /** Strip volatile UUIDs and timestamps before compare. */
24
+ export declare function normalizeOutput(text: string): string;
25
+ /** Build a throwaway project root with an empty audit-log parent directory. */
26
+ export declare function buildFixtureRepo(): string;
27
+ /** Diff one parity case between Python oracle and TS CLI. */
28
+ export declare function diffCase(python: CommandCapture, ts: CommandCapture, caseName: string): ParityDiff;
29
+ export declare const PARITY_CASES: readonly ParityCase[];
30
+ /** Run all parity cases; returns aggregate result. */
31
+ export declare function runParity(): ParityResult;
32
+ export declare function renderReport(result: ParityResult): string;
33
+ //# sourceMappingURL=triage-actions-parity.d.ts.map