@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,35 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import { dirname, resolve } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ /** Repo root (four levels up from packages/cli/src/render-cli). */
5
+ export function resolveRepoRoot() {
6
+ return resolve(dirname(fileURLToPath(import.meta.url)), "..", "..", "..", "..");
7
+ }
8
+ /** Built deft-ts dispatcher entrypoint. */
9
+ export function resolveBinPath() {
10
+ return resolve(resolveRepoRoot(), "packages/cli/dist/bin.js");
11
+ }
12
+ /** Invoke `node packages/cli/dist/bin.js [...argv]` and capture output. */
13
+ export function runDeftTsArgv(argv, options = {}) {
14
+ const bin = resolveBinPath();
15
+ const result = spawnSync(process.execPath, [bin, ...argv], {
16
+ cwd: options.cwd ?? resolveRepoRoot(),
17
+ encoding: "utf8",
18
+ env: {
19
+ ...process.env,
20
+ DEFT_CACHE_DISABLE: "1",
21
+ PYTHONUTF8: "1",
22
+ ...options.env,
23
+ },
24
+ });
25
+ return {
26
+ exitCode: result.status ?? 2,
27
+ stdout: result.stdout ?? "",
28
+ stderr: result.stderr ?? "",
29
+ };
30
+ }
31
+ /** Invoke `node packages/cli/dist/bin.js <verb> [...args]` and capture output. */
32
+ export function runDeftTs(verb, args = [], options = {}) {
33
+ return runDeftTsArgv([verb, ...args], options);
34
+ }
35
+ //# sourceMappingURL=deft-ts-runner.js.map
@@ -0,0 +1,2 @@
1
+ export declare function runPrdRenderCli(argv: readonly string[]): number;
2
+ //# sourceMappingURL=prd-render-cli.d.ts.map
@@ -0,0 +1,7 @@
1
+ /** Thin CLI wrapper for prd-render (mirrors ``scripts/prd_render.py``). */
2
+ import { parsePrdArgv, prdRenderMain } from "@deftai/directive-core/render";
3
+ export function runPrdRenderCli(argv) {
4
+ prdRenderMain(parsePrdArgv(argv));
5
+ return 0;
6
+ }
7
+ //# sourceMappingURL=prd-render-cli.js.map
@@ -0,0 +1,2 @@
1
+ export declare function runProjectRenderCli(argv: readonly string[]): number;
2
+ //# sourceMappingURL=project-render-cli.d.ts.map
@@ -0,0 +1,6 @@
1
+ /** Thin CLI wrapper for project-render (mirrors ``scripts/project_render.py``). */
2
+ import { projectRenderMain } from "@deftai/directive-core/render";
3
+ export function runProjectRenderCli(argv) {
4
+ return projectRenderMain(argv);
5
+ }
6
+ //# sourceMappingURL=project-render-cli.js.map
@@ -0,0 +1,2 @@
1
+ export declare function runSpecRenderCli(argv: readonly string[]): number;
2
+ //# sourceMappingURL=spec-render-cli.d.ts.map
@@ -0,0 +1,6 @@
1
+ /** Thin CLI wrapper for spec-render (mirrors ``scripts/spec_render.py``). */
2
+ import { specRenderMain } from "@deftai/directive-core/render";
3
+ export function runSpecRenderCli(argv) {
4
+ return specRenderMain(argv);
5
+ }
6
+ //# sourceMappingURL=spec-render-cli.js.map
@@ -0,0 +1,2 @@
1
+ export declare function runSpecValidateCli(argv: readonly string[]): number;
2
+ //# sourceMappingURL=spec-validate-cli.d.ts.map
@@ -0,0 +1,6 @@
1
+ /** Thin CLI wrapper for spec-validate (mirrors ``scripts/spec_validate.py``). */
2
+ import { specValidateMain } from "@deftai/directive-core/render";
3
+ export function runSpecValidateCli(argv) {
4
+ return specValidateMain(argv);
5
+ }
6
+ //# sourceMappingURL=spec-validate-cli.js.map
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env node
2
+ export interface CommandCapture {
3
+ readonly exitCode: number;
4
+ readonly stdout: string;
5
+ readonly stderr: string;
6
+ readonly bytes?: Buffer;
7
+ }
8
+ export interface ParityCase {
9
+ readonly gate: "spec-validate" | "spec-render" | "prd-render" | "project-render" | "roadmap-render" | "framework-commands";
10
+ readonly name: string;
11
+ readonly setup: (root: string) => {
12
+ specPath?: string;
13
+ outPath?: string;
14
+ extra?: Record<string, string>;
15
+ };
16
+ }
17
+ export interface ParityDiff {
18
+ readonly gate: string;
19
+ readonly caseName: string;
20
+ readonly exitMismatch: boolean;
21
+ readonly stdoutMismatch: boolean;
22
+ readonly stderrMismatch: boolean;
23
+ readonly bytesMismatch: boolean;
24
+ readonly pythonExit: number;
25
+ readonly tsExit: number;
26
+ }
27
+ export interface ParityResult {
28
+ readonly ok: boolean;
29
+ readonly diffs: ParityDiff[];
30
+ }
31
+ export declare const PARITY_CASES: readonly ParityCase[];
32
+ export declare function diffCase(python: CommandCapture, ts: CommandCapture, gate: string, caseName: string): ParityDiff;
33
+ export declare function runParity(): ParityResult;
34
+ export declare function renderReport(result: ParityResult): string;
35
+ //# sourceMappingURL=render-parity.d.ts.map
@@ -0,0 +1,383 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Golden-output parity harness (#1785): runs BOTH the Python oracles
4
+ * (frozen render/spec modules) and the ported TS render family over shared
5
+ * fixtures, then diffs exit codes + rendered bytes / stdout/stderr (cache-off).
6
+ *
7
+ * Exit codes: 0 parity / 1 divergence / 2 harness setup error.
8
+ */
9
+ import { execFileSync } from "node:child_process";
10
+ import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
11
+ import { tmpdir } from "node:os";
12
+ import { dirname, join, resolve } from "node:path";
13
+ import { fileURLToPath } from "node:url";
14
+ import { renderPrd, renderProjectDefinition, renderRoadmap, renderSpec, runFrameworkCommand, validateSpec, } from "@deftai/directive-core/render";
15
+ const MINIMAL_SPEC = {
16
+ vBRIEFInfo: { version: "0.6" },
17
+ plan: {
18
+ title: "Parity Spec",
19
+ status: "approved",
20
+ narratives: {
21
+ Overview: "Parity overview.",
22
+ Goals: "Ship byte-identical renders.",
23
+ },
24
+ items: [
25
+ {
26
+ id: "T1",
27
+ title: "First task",
28
+ status: "pending",
29
+ narrative: { Description: "Do the thing.", Acceptance: "- Done when green" },
30
+ },
31
+ ],
32
+ },
33
+ };
34
+ const FIXED_NOW = "2026-06-04T12:00:00Z";
35
+ function resolveDeftRoot() {
36
+ if (process.env.DEFT_ROOT !== undefined && process.env.DEFT_ROOT.length > 0) {
37
+ return resolve(process.env.DEFT_ROOT);
38
+ }
39
+ return resolve(dirname(fileURLToPath(import.meta.url)), "..", "..", "..");
40
+ }
41
+ function runPython(code, deftRoot) {
42
+ try {
43
+ const stdout = execFileSync("uv", ["run", "python", "-c", code], {
44
+ cwd: deftRoot,
45
+ encoding: "utf8",
46
+ env: { ...process.env, DEFT_CACHE_DISABLE: "1", PYTHONUTF8: "1" },
47
+ });
48
+ return { exitCode: 0, stdout: typeof stdout === "string" ? stdout : "", stderr: "" };
49
+ }
50
+ catch (err) {
51
+ const e = err;
52
+ return {
53
+ exitCode: e.status ?? 2,
54
+ stdout: typeof e.stdout === "string" ? e.stdout : "",
55
+ stderr: typeof e.stderr === "string" ? e.stderr : "",
56
+ };
57
+ }
58
+ }
59
+ function scriptsPrefix(deftRoot) {
60
+ const scriptsDir = join(deftRoot, "scripts").replace(/\\/g, "/");
61
+ return `import sys; sys.path.insert(0, ${JSON.stringify(scriptsDir)})`;
62
+ }
63
+ export const PARITY_CASES = [
64
+ {
65
+ gate: "spec-validate",
66
+ name: "valid-spec",
67
+ setup: (root) => {
68
+ const specPath = join(root, "spec.json");
69
+ writeFileSync(specPath, JSON.stringify(MINIMAL_SPEC), "utf8");
70
+ return { specPath };
71
+ },
72
+ },
73
+ {
74
+ gate: "spec-validate",
75
+ name: "missing-spec",
76
+ setup: (root) => ({ specPath: join(root, "missing.json") }),
77
+ },
78
+ {
79
+ gate: "spec-render",
80
+ name: "approved-spec",
81
+ setup: (root) => {
82
+ mkdirSync(join(root, "vbrief"), { recursive: true });
83
+ const specPath = join(root, "vbrief", "specification.vbrief.json");
84
+ const outPath = join(root, "SPECIFICATION.md");
85
+ writeFileSync(specPath, JSON.stringify(MINIMAL_SPEC), "utf8");
86
+ return { specPath, outPath };
87
+ },
88
+ },
89
+ {
90
+ gate: "prd-render",
91
+ name: "basic-prd",
92
+ setup: (root) => {
93
+ const specPath = join(root, "spec.json");
94
+ const outPath = join(root, "PRD.md");
95
+ writeFileSync(specPath, JSON.stringify(MINIMAL_SPEC), "utf8");
96
+ return { specPath, outPath };
97
+ },
98
+ },
99
+ {
100
+ gate: "project-render",
101
+ name: "skeleton-projdef",
102
+ setup: (root) => {
103
+ const vbrief = join(root, "vbrief");
104
+ for (const f of ["proposed", "pending", "active", "completed", "cancelled"]) {
105
+ mkdirSync(join(vbrief, f), { recursive: true });
106
+ }
107
+ return { extra: { vbriefDir: vbrief } };
108
+ },
109
+ },
110
+ {
111
+ gate: "roadmap-render",
112
+ name: "phase-grouped",
113
+ setup: (root) => {
114
+ const pending = join(root, "vbrief", "pending");
115
+ mkdirSync(pending, { recursive: true });
116
+ writeFileSync(join(pending, "2026-01-01-a.vbrief.json"), JSON.stringify({
117
+ vBRIEFInfo: { version: "0.6" },
118
+ plan: {
119
+ title: "Story A",
120
+ status: "pending",
121
+ metadata: { "x-migrator": { Phase: "Phase 2", PhaseDescription: "Wave 6" } },
122
+ references: [{ uri: "https://github.com/deftai/directive/issues/1785" }],
123
+ },
124
+ }), "utf8");
125
+ const outPath = join(root, "ROADMAP.md");
126
+ return { outPath, extra: { pendingDir: pending } };
127
+ },
128
+ },
129
+ {
130
+ gate: "framework-commands",
131
+ name: "unknown-command",
132
+ setup: () => ({}),
133
+ },
134
+ ];
135
+ function runPythonGate(deftRoot, testCase, paths, repoRoot) {
136
+ const scripts = scriptsPrefix(deftRoot);
137
+ if (testCase.gate === "spec-validate") {
138
+ const code = [
139
+ scripts,
140
+ "from spec_validate import validate_spec",
141
+ `ok, msg = validate_spec(${JSON.stringify(paths.specPath ?? "")})`,
142
+ "import sys",
143
+ "stream = sys.stdout if ok else sys.stderr",
144
+ "stream.write(msg + '\\n')",
145
+ "sys.exit(0 if ok else 1)",
146
+ ].join("\n");
147
+ return runPython(code, deftRoot);
148
+ }
149
+ if (testCase.gate === "spec-render") {
150
+ const code = [
151
+ scripts,
152
+ "from spec_render import render_spec",
153
+ `ok, msg = render_spec(${JSON.stringify(paths.specPath ?? "")}, ${JSON.stringify(paths.outPath ?? "")}, include_scopes=False)`,
154
+ "import sys",
155
+ "print(msg)",
156
+ "sys.exit(0 if ok else 1)",
157
+ ].join("\n");
158
+ const cap = runPython(code, deftRoot);
159
+ if (cap.exitCode === 0 && paths.outPath && existsSync(paths.outPath)) {
160
+ return { ...cap, bytes: readFileSync(paths.outPath) };
161
+ }
162
+ return cap;
163
+ }
164
+ if (testCase.gate === "prd-render") {
165
+ const code = [
166
+ scripts,
167
+ "from pathlib import Path",
168
+ "from prd_render import render_prd",
169
+ `render_prd(Path(${JSON.stringify(paths.specPath ?? "")}), Path(${JSON.stringify(paths.outPath ?? "")}))`,
170
+ ].join("\n");
171
+ const cap = runPython(code, deftRoot);
172
+ if (paths.outPath && existsSync(paths.outPath)) {
173
+ return { ...cap, bytes: readFileSync(paths.outPath) };
174
+ }
175
+ return cap;
176
+ }
177
+ if (testCase.gate === "project-render") {
178
+ const vbriefDir = paths.extra?.vbriefDir ?? join(repoRoot, "vbrief");
179
+ const code = [
180
+ scripts,
181
+ "from project_render import render_project_definition",
182
+ `ok, msg = render_project_definition(${JSON.stringify(vbriefDir)})`,
183
+ "import sys",
184
+ "print(msg)",
185
+ "sys.exit(0 if ok else 1)",
186
+ ].join("\n");
187
+ const cap = runPython(code, deftRoot);
188
+ const full = join(vbriefDir, "PROJECT-DEFINITION.vbrief.json");
189
+ if (existsSync(full))
190
+ return { ...cap, bytes: readFileSync(full) };
191
+ return cap;
192
+ }
193
+ if (testCase.gate === "roadmap-render") {
194
+ const pendingDir = paths.extra?.pendingDir ?? join(repoRoot, "vbrief", "pending");
195
+ const outPath = paths.outPath ?? join(repoRoot, "ROADMAP.md");
196
+ const code = [
197
+ scripts,
198
+ "from roadmap_render import render_roadmap",
199
+ `ok, msg = render_roadmap(${JSON.stringify(pendingDir)}, ${JSON.stringify(outPath)})`,
200
+ "import sys",
201
+ "print(msg)",
202
+ "sys.exit(0 if ok else 1)",
203
+ ].join("\n");
204
+ const cap = runPython(code, deftRoot);
205
+ if (existsSync(outPath))
206
+ return { ...cap, bytes: readFileSync(outPath) };
207
+ return cap;
208
+ }
209
+ const code = [
210
+ scripts,
211
+ "from framework_commands import run_framework_command",
212
+ "result = run_framework_command('__missing__', capture=True)",
213
+ "import sys",
214
+ "if result.stdout: sys.stdout.write(result.stdout)",
215
+ "if result.stderr: sys.stderr.write(result.stderr)",
216
+ "sys.exit(result.code)",
217
+ ].join("\n");
218
+ return runPython(code, deftRoot);
219
+ }
220
+ function runTsGate(testCase, paths, repoRoot) {
221
+ if (testCase.gate === "spec-validate") {
222
+ const [ok, msg] = validateSpec(paths.specPath ?? "");
223
+ return {
224
+ exitCode: ok ? 0 : 1,
225
+ stdout: ok ? `${msg}\n` : "",
226
+ stderr: ok ? "" : `${msg}\n`,
227
+ };
228
+ }
229
+ if (testCase.gate === "spec-render") {
230
+ const [ok, msg] = renderSpec(paths.specPath ?? "", paths.outPath ?? "", {
231
+ includeScopes: false,
232
+ });
233
+ const cap = {
234
+ exitCode: ok ? 0 : 1,
235
+ stdout: `${msg}\n`,
236
+ stderr: "",
237
+ };
238
+ if (ok && paths.outPath && existsSync(paths.outPath)) {
239
+ return { ...cap, bytes: readFileSync(paths.outPath) };
240
+ }
241
+ return cap;
242
+ }
243
+ if (testCase.gate === "prd-render") {
244
+ const chunks = { out: "", err: "" };
245
+ const prevOut = process.stdout.write.bind(process.stdout);
246
+ const prevErr = process.stderr.write.bind(process.stderr);
247
+ process.stdout.write = (c) => {
248
+ chunks.out += String(c);
249
+ return true;
250
+ };
251
+ process.stderr.write = (c) => {
252
+ chunks.err += String(c);
253
+ return true;
254
+ };
255
+ let exitCode = 0;
256
+ try {
257
+ renderPrd(paths.specPath ?? "", paths.outPath ?? "");
258
+ }
259
+ catch {
260
+ exitCode = 1;
261
+ }
262
+ finally {
263
+ process.stdout.write = prevOut;
264
+ process.stderr.write = prevErr;
265
+ }
266
+ const cap = { exitCode, stdout: chunks.out, stderr: chunks.err };
267
+ if (paths.outPath && existsSync(paths.outPath)) {
268
+ return { ...cap, bytes: readFileSync(paths.outPath) };
269
+ }
270
+ return cap;
271
+ }
272
+ if (testCase.gate === "project-render") {
273
+ const vbriefDir = paths.extra?.vbriefDir ?? join(repoRoot, "vbrief");
274
+ const [ok, msg] = renderProjectDefinition(vbriefDir, { now: new Date(FIXED_NOW) });
275
+ const full = join(vbriefDir, "PROJECT-DEFINITION.vbrief.json");
276
+ const cap = { exitCode: ok ? 0 : 1, stdout: `${msg}\n`, stderr: "" };
277
+ if (ok && existsSync(full))
278
+ return { ...cap, bytes: readFileSync(full) };
279
+ return cap;
280
+ }
281
+ if (testCase.gate === "roadmap-render") {
282
+ const pendingDir = paths.extra?.pendingDir ?? join(repoRoot, "vbrief", "pending");
283
+ const outPath = paths.outPath ?? join(repoRoot, "ROADMAP.md");
284
+ const [ok, msg] = renderRoadmap(pendingDir, outPath);
285
+ const cap = { exitCode: ok ? 0 : 1, stdout: `${msg}\n`, stderr: "" };
286
+ if (ok && existsSync(outPath))
287
+ return { ...cap, bytes: readFileSync(outPath) };
288
+ return cap;
289
+ }
290
+ const result = runFrameworkCommand("__missing__", [], { capture: true, projectRoot: repoRoot });
291
+ return { exitCode: result.code, stdout: result.stdout, stderr: result.stderr };
292
+ }
293
+ function normalizeProjectBytes(bytes) {
294
+ let text = bytes.toString("utf8");
295
+ text = text.replace(/"updated": "[^"]+"/g, '"updated": "<TS>"');
296
+ text = text.replace(/"created": "[^"]+"/g, '"created": "<TS>"');
297
+ return Buffer.from(text, "utf8");
298
+ }
299
+ function normalizeMessage(text) {
300
+ return text.replace(/\/tmp\/deft-render-parity-(py|ts)-[^/\s]+/g, "<TMP>");
301
+ }
302
+ export function diffCase(python, ts, gate, caseName) {
303
+ let bytesMismatch = false;
304
+ if (python.bytes !== undefined && ts.bytes !== undefined) {
305
+ const pyBytes = gate === "project-render" ? normalizeProjectBytes(python.bytes) : python.bytes;
306
+ const tsBytes = gate === "project-render" ? normalizeProjectBytes(ts.bytes) : ts.bytes;
307
+ bytesMismatch = !pyBytes.equals(tsBytes);
308
+ }
309
+ else if (python.bytes !== undefined || ts.bytes !== undefined) {
310
+ bytesMismatch = true;
311
+ }
312
+ const pyStdout = normalizeMessage(python.stdout);
313
+ const tsStdout = normalizeMessage(ts.stdout);
314
+ const pyStderr = normalizeMessage(python.stderr);
315
+ const tsStderr = normalizeMessage(ts.stderr);
316
+ return {
317
+ gate,
318
+ caseName,
319
+ exitMismatch: python.exitCode !== ts.exitCode,
320
+ stdoutMismatch: pyStdout !== tsStdout,
321
+ stderrMismatch: pyStderr !== tsStderr,
322
+ bytesMismatch,
323
+ pythonExit: python.exitCode,
324
+ tsExit: ts.exitCode,
325
+ };
326
+ }
327
+ export function runParity() {
328
+ const deftRoot = resolveDeftRoot();
329
+ const diffs = [];
330
+ for (const testCase of PARITY_CASES) {
331
+ const pyRepo = mkdtempSync(join(tmpdir(), "deft-render-parity-py-"));
332
+ const tsRepo = mkdtempSync(join(tmpdir(), "deft-render-parity-ts-"));
333
+ try {
334
+ const pyPaths = testCase.setup(pyRepo);
335
+ const tsPaths = testCase.setup(tsRepo);
336
+ const python = runPythonGate(deftRoot, testCase, pyPaths, pyRepo);
337
+ const ts = runTsGate(testCase, tsPaths, tsRepo);
338
+ diffs.push(diffCase(python, ts, testCase.gate, testCase.name));
339
+ }
340
+ finally {
341
+ rmSync(pyRepo, { recursive: true, force: true });
342
+ rmSync(tsRepo, { recursive: true, force: true });
343
+ }
344
+ }
345
+ const ok = diffs.every((d) => !d.exitMismatch && !d.stdoutMismatch && !d.stderrMismatch && !d.bytesMismatch);
346
+ return { ok, diffs };
347
+ }
348
+ export function renderReport(result) {
349
+ if (result.ok) {
350
+ return `render parity: CLEAN -- Python and TS agree on ${PARITY_CASES.length} cases.`;
351
+ }
352
+ const lines = ["render parity: DIVERGENCE"];
353
+ for (const d of result.diffs) {
354
+ if (d.exitMismatch || d.stdoutMismatch || d.stderrMismatch || d.bytesMismatch) {
355
+ lines.push(` gate: ${d.gate} case: ${d.caseName}`);
356
+ if (d.exitMismatch)
357
+ lines.push(` exit: python=${d.pythonExit} ts=${d.tsExit}`);
358
+ if (d.stdoutMismatch)
359
+ lines.push(" stdout mismatch");
360
+ if (d.stderrMismatch)
361
+ lines.push(" stderr mismatch");
362
+ if (d.bytesMismatch)
363
+ lines.push(" rendered bytes mismatch");
364
+ }
365
+ }
366
+ return lines.join("\n");
367
+ }
368
+ if (process.argv[1] !== undefined && fileURLToPath(import.meta.url) === process.argv[1]) {
369
+ try {
370
+ const result = runParity();
371
+ if (result.ok) {
372
+ process.stdout.write(`${renderReport(result)}\n`);
373
+ process.exit(0);
374
+ }
375
+ process.stderr.write(`${renderReport(result)}\n`);
376
+ process.exit(1);
377
+ }
378
+ catch (err) {
379
+ process.stderr.write(`render parity: harness error -- ${String(err)}\n`);
380
+ process.exit(2);
381
+ }
382
+ }
383
+ //# sourceMappingURL=render-parity.js.map
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env node
2
+ export interface ScenarioResult {
3
+ readonly name: string;
4
+ readonly exitCode: number;
5
+ readonly stdout: string;
6
+ readonly stderr: string;
7
+ }
8
+ export interface ParityScenario {
9
+ readonly name: string;
10
+ readonly argv: readonly string[];
11
+ }
12
+ export interface ParityResult {
13
+ readonly ok: boolean;
14
+ readonly scenarios: Array<{
15
+ readonly name: string;
16
+ readonly exitMismatch: boolean;
17
+ readonly pythonExit: number;
18
+ readonly tsExit: number;
19
+ readonly messageMismatch: boolean;
20
+ readonly pythonMessage: string;
21
+ readonly tsMessage: string;
22
+ }>;
23
+ }
24
+ /** Validation-only scenarios (no live gh network). */
25
+ export declare const PARITY_SCENARIOS: readonly ParityScenario[];
26
+ /** Normalise gate output for comparison. */
27
+ export declare function normaliseMessage(stdout: string, stderr: string, exitCode: number): string;
28
+ /** Diff python vs TS outputs for one scenario. */
29
+ export declare function diffParity(python: ScenarioResult, ts: ScenarioResult): {
30
+ exitMismatch: boolean;
31
+ messageMismatch: boolean;
32
+ pythonMessage: string;
33
+ tsMessage: string;
34
+ };
35
+ /** Run all parity scenarios and return a structured result. */
36
+ export declare function runParity(): ParityResult;
37
+ /** Render a human-readable parity report. */
38
+ export declare function renderReport(result: ParityResult): string;
39
+ //# sourceMappingURL=scm-parity.d.ts.map