@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,377 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Golden-output parity harness (#1787 s2): runs BOTH the frozen Python oracles
4
+ * (`packs_slice`, `quarantine_ext`, `_lifecycle_hygiene`, `_event_detect`) and
5
+ * the ported TS lifecycle/packs modules over shared fixtures, cache-off.
6
+ *
7
+ * Exit codes: 0 parity / 1 divergence / 2 harness setup error.
8
+ */
9
+ import { execFileSync } from "node:child_process";
10
+ import { mkdirSync, mkdtempSync, 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 { eventDetect, lifecycleHygiene } from "@deftai/directive-core/lifecycle";
15
+ import { packsSlice, quarantineExt } from "@deftai/directive-core/packs";
16
+ const NOW_ISO = "2026-06-01T12:00:00.000Z";
17
+ function runCapture(cmd, args, cwd, env = {}) {
18
+ const merged = {
19
+ ...process.env,
20
+ DEFT_CACHE_DISABLE: "1",
21
+ PYTHONUTF8: "1",
22
+ ...env,
23
+ };
24
+ for (const key of Object.keys(merged)) {
25
+ if (merged[key] === undefined)
26
+ delete merged[key];
27
+ }
28
+ try {
29
+ const stdout = execFileSync(cmd, args, {
30
+ cwd,
31
+ encoding: "utf8",
32
+ env: merged,
33
+ stdio: ["ignore", "pipe", "pipe"],
34
+ });
35
+ return { status: 0, stdout, stderr: "" };
36
+ }
37
+ catch (err) {
38
+ const e = err;
39
+ return {
40
+ status: typeof e.status === "number" ? e.status : 2,
41
+ stdout: typeof e.stdout === "string" ? e.stdout : "",
42
+ stderr: typeof e.stderr === "string" ? e.stderr : "",
43
+ };
44
+ }
45
+ }
46
+ function resolveDeftRoot() {
47
+ if (process.env.DEFT_ROOT !== undefined && process.env.DEFT_ROOT.length > 0) {
48
+ return resolve(process.env.DEFT_ROOT);
49
+ }
50
+ return resolve(dirname(fileURLToPath(import.meta.url)), "..", "..", "..");
51
+ }
52
+ function runPythonScript(deftRoot, script) {
53
+ return runCapture("uv", ["run", "python", "-c", script], deftRoot);
54
+ }
55
+ function writeJson(path, data) {
56
+ writeFileSync(path, `${JSON.stringify(data)}\n`, { encoding: "utf8" });
57
+ }
58
+ function makeLifecycle(root) {
59
+ for (const folder of ["proposed", "pending", "active", "completed", "cancelled"]) {
60
+ mkdirSync(join(root, "vbrief", folder), { recursive: true });
61
+ }
62
+ }
63
+ function writeFixturePack(repo) {
64
+ const schema = {
65
+ "x-sliceRegistry": {
66
+ recent: {
67
+ path: "lessons",
68
+ filters: ["since"],
69
+ description: "Lessons dated on or after --since.",
70
+ },
71
+ "by-tag": {
72
+ path: "lessons",
73
+ filters: ["tag"],
74
+ description: "Lessons carrying any requested --tag.",
75
+ },
76
+ },
77
+ "x-display": {
78
+ heading: "title",
79
+ fields: [],
80
+ body: "body",
81
+ noun: "lessons",
82
+ },
83
+ };
84
+ const source = {
85
+ pack: "lessons-pack-0.1",
86
+ version: "0.1",
87
+ lessons: [
88
+ {
89
+ id: "old-windows",
90
+ title: "Old Windows Lesson (2026-03)",
91
+ date: "2026-03",
92
+ issue_refs: [],
93
+ tags: ["windows", "encoding"],
94
+ source: "PR #1",
95
+ body: "Body about cp1252.",
96
+ },
97
+ {
98
+ id: "mid-swarm",
99
+ title: "Mid Swarm Lesson (2026-05)",
100
+ date: "2026-05",
101
+ issue_refs: ["#42"],
102
+ tags: ["swarm"],
103
+ source: null,
104
+ body: "Body about a swarm cohort.",
105
+ },
106
+ ],
107
+ };
108
+ const packDir = join(repo, "packs", "lessons");
109
+ mkdirSync(packDir, { recursive: true });
110
+ mkdirSync(join(repo, "vbrief", "schemas"), { recursive: true });
111
+ writeJson(join(packDir, "lessons-pack-0.1.json"), source);
112
+ writeJson(join(repo, "vbrief", "schemas", "lessons-pack.schema.json"), schema);
113
+ }
114
+ function writeStrandedEpic(repo) {
115
+ makeLifecycle(repo);
116
+ const old = "2026-04-01T00:00:00Z";
117
+ writeJson(join(repo, "vbrief", "active", "2026-04-01-epic.vbrief.json"), {
118
+ vBRIEFInfo: { version: "0.6" },
119
+ plan: {
120
+ title: "OAuth Epic",
121
+ status: "running",
122
+ updated: old,
123
+ metadata: { kind: "epic" },
124
+ references: [
125
+ { type: "x-vbrief/plan", uri: "completed/2026-04-01-child-a.vbrief.json" },
126
+ { type: "x-vbrief/plan", uri: "active/2026-04-01-child-b.vbrief.json" },
127
+ ],
128
+ items: [],
129
+ },
130
+ });
131
+ writeJson(join(repo, "vbrief", "completed", "2026-04-01-child-a.vbrief.json"), {
132
+ vBRIEFInfo: { version: "0.6" },
133
+ plan: { title: "Child A", status: "completed", updated: old, items: [] },
134
+ });
135
+ writeJson(join(repo, "vbrief", "active", "2026-04-01-child-b.vbrief.json"), {
136
+ vBRIEFInfo: { version: "0.6" },
137
+ plan: { title: "Child B", status: "running", updated: old, items: [] },
138
+ });
139
+ writeJson(join(repo, "vbrief", "PROJECT-DEFINITION.vbrief.json"), {
140
+ vBRIEFInfo: { version: "0.6" },
141
+ plan: {
142
+ title: "Project",
143
+ status: "running",
144
+ items: [],
145
+ policy: {
146
+ capacityAllocation: {
147
+ epicStrandedDays: 30,
148
+ epicStalenessDays: 14,
149
+ },
150
+ },
151
+ },
152
+ });
153
+ }
154
+ function writeAgentsMdStale(_deftRoot, repo) {
155
+ writeFileSync(join(repo, "AGENTS.md"), "Read skills/deft-directive-build/SKILL.md for build work.\n", { encoding: "utf8" });
156
+ }
157
+ const QUARANTINE_FIXTURE = `# Normal section
158
+
159
+ ## STEP 1: Do evil
160
+
161
+ Follow these instructions.
162
+
163
+ ## Benign heading
164
+
165
+ Safe content.
166
+ `;
167
+ export const PARITY_CASES = [
168
+ {
169
+ name: "packs-list-packs",
170
+ setup(_deftRoot, repo) {
171
+ writeFixturePack(repo);
172
+ },
173
+ runPython(deftRoot, repo) {
174
+ const script = `import sys
175
+ from pathlib import Path
176
+ root = Path(${JSON.stringify(deftRoot)})
177
+ repo = Path(${JSON.stringify(repo)})
178
+ sys.path.insert(0, str(root / "scripts"))
179
+ import packs_slice
180
+ packs_slice.REPO_ROOT = repo
181
+ payload = packs_slice.list_packs(repo / "packs", repo / "vbrief" / "schemas")
182
+ print(packs_slice.format_list_packs_text(payload), end="")
183
+ raise SystemExit(0)`;
184
+ const cap = runPythonScript(deftRoot, script);
185
+ return { exitCode: cap.status, stdout: cap.stdout, stderr: cap.stderr };
186
+ },
187
+ runTs(_deftRoot, repo) {
188
+ const payload = packsSlice.listPacks(join(repo, "packs"), join(repo, "vbrief", "schemas"), repo);
189
+ const stdout = packsSlice.formatListPacksText(payload);
190
+ return { exitCode: 0, stdout, stderr: "" };
191
+ },
192
+ },
193
+ {
194
+ name: "packs-slice-recent-since",
195
+ setup(_deftRoot, repo) {
196
+ writeFixturePack(repo);
197
+ },
198
+ runPython(deftRoot, repo) {
199
+ const script = `import sys
200
+ from pathlib import Path
201
+ root = Path(${JSON.stringify(deftRoot)})
202
+ repo = Path(${JSON.stringify(repo)})
203
+ sys.path.insert(0, str(root / "scripts"))
204
+ import packs_slice
205
+ packs_slice.REPO_ROOT = repo
206
+ packs_slice.PACK_REGISTRY["lessons"] = {
207
+ "source": repo / "packs" / "lessons" / "lessons-pack-0.1.json",
208
+ "schema": repo / "vbrief" / "schemas" / "lessons-pack.schema.json",
209
+ }
210
+ source_path = repo / "packs" / "lessons" / "lessons-pack-0.1.json"
211
+ schema_path = repo / "vbrief" / "schemas" / "lessons-pack.schema.json"
212
+ registry = packs_slice.load_registry(schema_path)
213
+ data = packs_slice.load_source(source_path)
214
+ result = packs_slice.slice_pack(data["pack"], "recent", registry, data, source_path, since="2026-05")
215
+ display = packs_slice.load_display(schema_path)
216
+ print(packs_slice.format_slice_text(result, display), end="")
217
+ raise SystemExit(0)`;
218
+ const cap = runPythonScript(deftRoot, script);
219
+ return { exitCode: cap.status, stdout: cap.stdout, stderr: cap.stderr };
220
+ },
221
+ runTs(_deftRoot, repo) {
222
+ const source = join(repo, "packs", "lessons", "lessons-pack-0.1.json");
223
+ const schema = join(repo, "vbrief", "schemas", "lessons-pack.schema.json");
224
+ const registry = packsSlice.loadRegistry(schema);
225
+ const data = packsSlice.loadSource(source);
226
+ const result = packsSlice.slicePack(String(data.pack ?? "lessons"), "recent", registry, data, source, { since: "2026-05", repoRoot: repo });
227
+ const display = packsSlice.loadDisplay(schema);
228
+ return { exitCode: 0, stdout: packsSlice.formatSliceText(result, display), stderr: "" };
229
+ },
230
+ },
231
+ {
232
+ name: "quarantine-ext-heading",
233
+ runPython(deftRoot) {
234
+ const script = `import sys
235
+ from pathlib import Path
236
+ root = Path(${JSON.stringify(deftRoot)})
237
+ sys.path.insert(0, str(root / "scripts"))
238
+ import quarantine_ext
239
+ text = ${JSON.stringify(QUARANTINE_FIXTURE)}
240
+ sys.stdout.write(quarantine_ext.quarantine_body(text))
241
+ raise SystemExit(0)`;
242
+ const cap = runPythonScript(deftRoot, script);
243
+ return { exitCode: cap.status, stdout: cap.stdout, stderr: cap.stderr };
244
+ },
245
+ runTs() {
246
+ const stdout = quarantineExt.quarantineBody(QUARANTINE_FIXTURE);
247
+ return { exitCode: 0, stdout, stderr: "" };
248
+ },
249
+ },
250
+ {
251
+ name: "lifecycle-stranded-nudge",
252
+ setup(_deftRoot, repo) {
253
+ writeStrandedEpic(repo);
254
+ },
255
+ runPython(deftRoot, repo) {
256
+ const script = `import sys
257
+ from datetime import datetime, UTC
258
+ from pathlib import Path
259
+ root = Path(${JSON.stringify(deftRoot)})
260
+ repo = Path(${JSON.stringify(repo)})
261
+ sys.path.insert(0, str(root / "scripts"))
262
+ import _lifecycle_hygiene as lifecycle_hygiene
263
+ now = datetime.fromisoformat(${JSON.stringify(NOW_ISO)}.replace("Z", "+00:00"))
264
+ nudges = lifecycle_hygiene.detect_lifecycle_nudges(repo, now=now)
265
+ lines = [n.message for n in nudges if n.kind == "stranded"]
266
+ print("\\n".join(lines))
267
+ raise SystemExit(0)`;
268
+ const cap = runPythonScript(deftRoot, script);
269
+ return { exitCode: cap.status, stdout: cap.stdout, stderr: cap.stderr };
270
+ },
271
+ runTs(_deftRoot, repo) {
272
+ const now = new Date(NOW_ISO);
273
+ const nudges = lifecycleHygiene.detectLifecycleNudges(repo, { now });
274
+ const lines = nudges.filter((n) => n.kind === "stranded").map((n) => n.message);
275
+ return { exitCode: 0, stdout: `${lines.join("\n")}\n`, stderr: "" };
276
+ },
277
+ },
278
+ {
279
+ name: "event-detect-agents-md-stale",
280
+ setup(deftRoot, repo) {
281
+ writeAgentsMdStale(deftRoot, repo);
282
+ },
283
+ runPython(deftRoot, repo) {
284
+ const script = `import json, sys
285
+ from pathlib import Path
286
+ root = Path(${JSON.stringify(deftRoot)})
287
+ repo = Path(${JSON.stringify(repo)})
288
+ sys.path.insert(0, str(root / "scripts"))
289
+ import _event_detect as event_detect
290
+ payload = event_detect.detect_agents_md_stale(repo, framework_root=root)
291
+ print(json.dumps(payload, sort_keys=True) if payload else "null")
292
+ raise SystemExit(0)`;
293
+ const cap = runPythonScript(deftRoot, script);
294
+ return { exitCode: cap.status, stdout: cap.stdout, stderr: cap.stderr };
295
+ },
296
+ runTs(deftRoot, repo) {
297
+ eventDetect.clearRegistryCache();
298
+ const payload = eventDetect.detectAgentsMdStale(repo, { frameworkRoot: deftRoot });
299
+ const stdout = payload === null ? "null\n" : `${JSON.stringify(payload, Object.keys(payload).sort())}\n`;
300
+ return { exitCode: 0, stdout, stderr: "" };
301
+ },
302
+ },
303
+ ];
304
+ export function normalizeOutput(text) {
305
+ return text.replace(/\r\n/g, "\n");
306
+ }
307
+ export function diffCase(python, ts, caseName) {
308
+ const pyOut = normalizeOutput(python.stdout);
309
+ const tsOut = normalizeOutput(ts.stdout);
310
+ const pyErr = normalizeOutput(python.stderr);
311
+ const tsErr = normalizeOutput(ts.stderr);
312
+ return {
313
+ caseName,
314
+ exitMismatch: python.exitCode !== ts.exitCode,
315
+ stdoutMismatch: pyOut !== tsOut,
316
+ stderrMismatch: pyErr !== tsErr,
317
+ pythonExit: python.exitCode,
318
+ tsExit: ts.exitCode,
319
+ };
320
+ }
321
+ export function runParity() {
322
+ const deftRoot = resolveDeftRoot();
323
+ const diffs = [];
324
+ for (const testCase of PARITY_CASES) {
325
+ const pyRepo = mkdtempSync(join(tmpdir(), "deft-lp-parity-py-"));
326
+ const tsRepo = mkdtempSync(join(tmpdir(), "deft-lp-parity-ts-"));
327
+ try {
328
+ if (testCase.setup !== undefined) {
329
+ testCase.setup(deftRoot, pyRepo);
330
+ testCase.setup(deftRoot, tsRepo);
331
+ }
332
+ const python = testCase.runPython(deftRoot, pyRepo);
333
+ const ts = testCase.runTs(deftRoot, tsRepo);
334
+ diffs.push(diffCase(python, ts, testCase.name));
335
+ }
336
+ finally {
337
+ rmSync(pyRepo, { recursive: true, force: true });
338
+ rmSync(tsRepo, { recursive: true, force: true });
339
+ }
340
+ }
341
+ const ok = diffs.every((d) => !d.exitMismatch && !d.stdoutMismatch && !d.stderrMismatch);
342
+ return { ok, diffs };
343
+ }
344
+ export function renderReport(result) {
345
+ if (result.ok) {
346
+ return `lifecycle-packs parity: CLEAN -- Python and TS agree on ${PARITY_CASES.length} case(s).`;
347
+ }
348
+ const lines = ["lifecycle-packs parity: DIVERGENCE"];
349
+ for (const d of result.diffs) {
350
+ if (d.exitMismatch || d.stdoutMismatch || d.stderrMismatch) {
351
+ lines.push(` case: ${d.caseName}`);
352
+ if (d.exitMismatch)
353
+ lines.push(` exit: python=${d.pythonExit} ts=${d.tsExit}`);
354
+ if (d.stdoutMismatch)
355
+ lines.push(" stdout mismatch");
356
+ if (d.stderrMismatch)
357
+ lines.push(" stderr mismatch");
358
+ }
359
+ }
360
+ return lines.join("\n");
361
+ }
362
+ if (process.argv[1] !== undefined && fileURLToPath(import.meta.url) === process.argv[1]) {
363
+ try {
364
+ const result = runParity();
365
+ if (result.ok) {
366
+ process.stdout.write(`${renderReport(result)}\n`);
367
+ process.exit(0);
368
+ }
369
+ process.stderr.write(`${renderReport(result)}\n`);
370
+ process.exit(1);
371
+ }
372
+ catch (err) {
373
+ process.stderr.write(`lifecycle-packs parity: harness error -- ${String(err)}\n`);
374
+ process.exit(2);
375
+ }
376
+ }
377
+ //# sourceMappingURL=lifecycle-packs-parity.js.map
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Wave 8.5 s4 coverage map (#1838): Python CLI tests → TS vitest / existing core coverage.
3
+ * Used in the PR body table and audited by coverage-map.test.ts.
4
+ */
5
+ export type CoverageKind = "existing-coverage" | "orchestration-cli-spec";
6
+ export interface CoverageEntry {
7
+ readonly pythonTest: string;
8
+ readonly kind: CoverageKind;
9
+ readonly tsTarget: string;
10
+ readonly notes?: string;
11
+ }
12
+ export declare const ORCHESTRATION_CLI_PYTHON_TESTS: readonly ["test_pr_check_closing_keywords.py", "test_pr_check_protected_issues.py", "test_pr_merge_readiness.py", "test_pr_merge_readiness_fallbacks.py", "test_pr_wait_mergeable.py", "test_release.py", "test_release_branch_gate.py", "test_release_e2e.py", "test_release_prerelease.py", "test_release_publish.py", "test_release_pyproject_sync.py", "test_release_rollback.py", "test_release_rollback_725.py", "test_release_skip_flags.py", "test_release_subprocess_path.py", "test_release_summary.py", "test_release_tag_availability.py", "test_release_upgrade_banner.py", "test_release_vbrief_lifecycle.py", "test_swarm_complete_cohort.py", "test_swarm_launch.py", "test_swarm_readiness.py", "test_swarm_verify_review_clean.py", "test_swarm_worktrees.py", "test_subagent_monitor.py", "test_probe_session.py", "test_resolve_changelog_unreleased.py", "test_resolve_version.py"];
13
+ export declare const ORCHESTRATION_CLI_COVERAGE_MAP: readonly CoverageEntry[];
14
+ /** Every in-scope Python file must appear at least once in the map. */
15
+ export declare function coverageMapCompleteness(): {
16
+ ok: boolean;
17
+ missing: string[];
18
+ };
19
+ /** Markdown table for PR body (#1838 Wave 8.5 s4). */
20
+ export declare function renderCoverageMapMarkdown(): string;
21
+ //# sourceMappingURL=coverage-map.d.ts.map
@@ -0,0 +1,225 @@
1
+ export const ORCHESTRATION_CLI_PYTHON_TESTS = [
2
+ "test_pr_check_closing_keywords.py",
3
+ "test_pr_check_protected_issues.py",
4
+ "test_pr_merge_readiness.py",
5
+ "test_pr_merge_readiness_fallbacks.py",
6
+ "test_pr_wait_mergeable.py",
7
+ "test_release.py",
8
+ "test_release_branch_gate.py",
9
+ "test_release_e2e.py",
10
+ "test_release_prerelease.py",
11
+ "test_release_publish.py",
12
+ "test_release_pyproject_sync.py",
13
+ "test_release_rollback.py",
14
+ "test_release_rollback_725.py",
15
+ "test_release_skip_flags.py",
16
+ "test_release_subprocess_path.py",
17
+ "test_release_summary.py",
18
+ "test_release_tag_availability.py",
19
+ "test_release_upgrade_banner.py",
20
+ "test_release_vbrief_lifecycle.py",
21
+ "test_swarm_complete_cohort.py",
22
+ "test_swarm_launch.py",
23
+ "test_swarm_readiness.py",
24
+ "test_swarm_verify_review_clean.py",
25
+ "test_swarm_worktrees.py",
26
+ "test_subagent_monitor.py",
27
+ "test_probe_session.py",
28
+ "test_resolve_changelog_unreleased.py",
29
+ "test_resolve_version.py",
30
+ ];
31
+ export const ORCHESTRATION_CLI_COVERAGE_MAP = [
32
+ {
33
+ pythonTest: "test_pr_check_closing_keywords.py",
34
+ kind: "existing-coverage",
35
+ tsTarget: "packages/core/src/pr-closing-keywords/main.test.ts",
36
+ notes: "Offline + gh argv parsing; parity in pr-closing-keywords-parity.test.ts",
37
+ },
38
+ {
39
+ pythonTest: "test_pr_check_protected_issues.py",
40
+ kind: "existing-coverage",
41
+ tsTarget: "packages/core/src/pr-protected-issues/main.test.ts",
42
+ },
43
+ {
44
+ pythonTest: "test_pr_merge_readiness.py",
45
+ kind: "existing-coverage",
46
+ tsTarget: "packages/core/src/pr-merge-readiness/main.test.ts",
47
+ notes: "Greptile parse + gate evaluation",
48
+ },
49
+ {
50
+ pythonTest: "test_pr_merge_readiness_fallbacks.py",
51
+ kind: "existing-coverage",
52
+ tsTarget: "packages/core/src/pr-merge-readiness/gh.test.ts",
53
+ notes: "Layered gh fallbacks",
54
+ },
55
+ {
56
+ pythonTest: "test_pr_wait_mergeable.py",
57
+ kind: "existing-coverage",
58
+ tsTarget: "packages/core/src/pr-wait-mergeable/main.test.ts",
59
+ },
60
+ {
61
+ pythonTest: "test_pr_check_closing_keywords.py",
62
+ kind: "orchestration-cli-spec",
63
+ tsTarget: "packages/cli/src/orchestration-cli/pr-cli.test.ts",
64
+ notes: "deft-ts pr-closing-keywords argv / exit 2 for missing input",
65
+ },
66
+ {
67
+ pythonTest: "test_pr_merge_readiness.py",
68
+ kind: "orchestration-cli-spec",
69
+ tsTarget: "packages/cli/src/orchestration-cli/pr-cli.test.ts",
70
+ notes: "deft-ts pr-merge-readiness / pr-protected-issues / pr-wait-mergeable dispatcher",
71
+ },
72
+ {
73
+ pythonTest: "test_release.py",
74
+ kind: "existing-coverage",
75
+ tsTarget: "packages/core/src/release/main.test.ts",
76
+ notes: "Pipeline + changelog promotion",
77
+ },
78
+ {
79
+ pythonTest: "test_release_branch_gate.py",
80
+ kind: "existing-coverage",
81
+ tsTarget: "packages/core/src/release/pipeline-branches.test.ts",
82
+ },
83
+ {
84
+ pythonTest: "test_release_e2e.py",
85
+ kind: "existing-coverage",
86
+ tsTarget: "packages/core/src/release-e2e/main.test.ts",
87
+ },
88
+ {
89
+ pythonTest: "test_release_prerelease.py",
90
+ kind: "existing-coverage",
91
+ tsTarget: "packages/core/src/release/version.test.ts",
92
+ },
93
+ {
94
+ pythonTest: "test_release_publish.py",
95
+ kind: "existing-coverage",
96
+ tsTarget: "packages/core/src/release-publish/main.test.ts",
97
+ },
98
+ {
99
+ pythonTest: "test_release_pyproject_sync.py",
100
+ kind: "existing-coverage",
101
+ tsTarget: "packages/core/src/release/pyproject.test.ts",
102
+ },
103
+ {
104
+ pythonTest: "test_release_rollback.py",
105
+ kind: "existing-coverage",
106
+ tsTarget: "packages/core/src/release-rollback/rollback.test.ts",
107
+ },
108
+ {
109
+ pythonTest: "test_release_rollback_725.py",
110
+ kind: "existing-coverage",
111
+ tsTarget: "packages/core/src/release-rollback/rollback-coverage.test.ts",
112
+ },
113
+ {
114
+ pythonTest: "test_release_skip_flags.py",
115
+ kind: "existing-coverage",
116
+ tsTarget: "packages/core/src/release/flags.test.ts",
117
+ },
118
+ {
119
+ pythonTest: "test_release_subprocess_path.py",
120
+ kind: "existing-coverage",
121
+ tsTarget: "packages/core/src/release/python-bridge.test.ts",
122
+ },
123
+ {
124
+ pythonTest: "test_release_summary.py",
125
+ kind: "existing-coverage",
126
+ tsTarget: "packages/core/src/release/pipeline.test.ts",
127
+ },
128
+ {
129
+ pythonTest: "test_release_tag_availability.py",
130
+ kind: "existing-coverage",
131
+ tsTarget: "packages/core/src/release/gh.test.ts",
132
+ },
133
+ {
134
+ pythonTest: "test_release_upgrade_banner.py",
135
+ kind: "existing-coverage",
136
+ tsTarget: "packages/core/src/release/pipeline-branches.test.ts",
137
+ },
138
+ {
139
+ pythonTest: "test_release_vbrief_lifecycle.py",
140
+ kind: "existing-coverage",
141
+ tsTarget: "packages/core/src/release/pipeline.test.ts",
142
+ },
143
+ {
144
+ pythonTest: "test_release.py",
145
+ kind: "orchestration-cli-spec",
146
+ tsTarget: "packages/cli/src/orchestration-cli/release-cli.test.ts",
147
+ notes: "deft-ts release / release-publish / release-rollback / release-e2e argv surface",
148
+ },
149
+ {
150
+ pythonTest: "test_swarm_complete_cohort.py",
151
+ kind: "existing-coverage",
152
+ tsTarget: "packages/core/src/swarm/complete-cohort-sweep.test.ts",
153
+ },
154
+ {
155
+ pythonTest: "test_swarm_launch.py",
156
+ kind: "existing-coverage",
157
+ tsTarget: "packages/core/src/swarm/swarm.test.ts",
158
+ },
159
+ {
160
+ pythonTest: "test_swarm_readiness.py",
161
+ kind: "existing-coverage",
162
+ tsTarget: "packages/core/src/swarm/readiness-branches.test.ts",
163
+ },
164
+ {
165
+ pythonTest: "test_swarm_verify_review_clean.py",
166
+ kind: "existing-coverage",
167
+ tsTarget: "packages/core/src/swarm/swarm-branches.test.ts",
168
+ },
169
+ {
170
+ pythonTest: "test_swarm_worktrees.py",
171
+ kind: "existing-coverage",
172
+ tsTarget: "packages/core/src/swarm/worktrees.test.ts",
173
+ },
174
+ {
175
+ pythonTest: "test_swarm_launch.py",
176
+ kind: "orchestration-cli-spec",
177
+ tsTarget: "packages/cli/src/orchestration-cli/swarm-cli.test.ts",
178
+ notes: "deft-ts swarm-* dispatcher argv + exit codes",
179
+ },
180
+ {
181
+ pythonTest: "test_subagent_monitor.py",
182
+ kind: "existing-coverage",
183
+ tsTarget: "packages/core/src/orchestration/orchestration.test.ts",
184
+ },
185
+ {
186
+ pythonTest: "test_probe_session.py",
187
+ kind: "existing-coverage",
188
+ tsTarget: "packages/core/src/orchestration/orchestration.test.ts",
189
+ },
190
+ {
191
+ pythonTest: "test_subagent_monitor.py",
192
+ kind: "orchestration-cli-spec",
193
+ tsTarget: "packages/cli/src/orchestration-cli/probe-orchestration-cli.test.ts",
194
+ notes: "deft-ts subagent-monitor / probe-session dispatcher",
195
+ },
196
+ {
197
+ pythonTest: "test_probe_session.py",
198
+ kind: "orchestration-cli-spec",
199
+ tsTarget: "packages/cli/src/orchestration-cli/probe-orchestration-cli.test.ts",
200
+ },
201
+ {
202
+ pythonTest: "test_resolve_changelog_unreleased.py",
203
+ kind: "existing-coverage",
204
+ tsTarget: "packages/core/src/platform/platform.test.ts",
205
+ notes: "No deft-ts verb; resolve-changelog is platform module",
206
+ },
207
+ {
208
+ pythonTest: "test_resolve_version.py",
209
+ kind: "existing-coverage",
210
+ tsTarget: "packages/core/src/platform/branch-coverage.test.ts",
211
+ notes: "No deft-ts verb; resolve-version is platform module",
212
+ },
213
+ ];
214
+ /** Every in-scope Python file must appear at least once in the map. */
215
+ export function coverageMapCompleteness() {
216
+ const mapped = new Set(ORCHESTRATION_CLI_COVERAGE_MAP.map((e) => e.pythonTest));
217
+ const missing = ORCHESTRATION_CLI_PYTHON_TESTS.filter((f) => !mapped.has(f));
218
+ return { ok: missing.length === 0, missing: [...missing] };
219
+ }
220
+ /** Markdown table for PR body (#1838 Wave 8.5 s4). */
221
+ export function renderCoverageMapMarkdown() {
222
+ const rows = ORCHESTRATION_CLI_COVERAGE_MAP.map((e) => `| \`${e.pythonTest}\` | ${e.kind} | \`${e.tsTarget}\` | ${e.notes ?? ""} |`);
223
+ return ["| Python test | Kind | TS target | Notes |", "| --- | --- | --- | --- |", ...rows].join("\n");
224
+ }
225
+ //# sourceMappingURL=coverage-map.js.map
@@ -0,0 +1,11 @@
1
+ import type { DispatchIo } from "../dispatch.js";
2
+ /** Silent IO sinks for dispatcher / CLI wrapper tests. */
3
+ export declare function silentIo(): DispatchIo;
4
+ /** Capture stderr while keeping stdout silent. */
5
+ export declare function captureStderrIo(): {
6
+ io: DispatchIo;
7
+ stderr: string[];
8
+ };
9
+ /** Run a CLI `run()` export without polluting the vitest console. */
10
+ export declare function muteProcessStreams<T>(fn: () => T): T;
11
+ //# sourceMappingURL=helpers.d.ts.map
@@ -0,0 +1,35 @@
1
+ /** Silent IO sinks for dispatcher / CLI wrapper tests. */
2
+ export function silentIo() {
3
+ return {
4
+ writeOut: () => { },
5
+ writeErr: () => { },
6
+ };
7
+ }
8
+ /** Capture stderr while keeping stdout silent. */
9
+ export function captureStderrIo() {
10
+ const stderr = [];
11
+ return {
12
+ stderr,
13
+ io: {
14
+ writeOut: () => { },
15
+ writeErr: (text) => {
16
+ stderr.push(text);
17
+ },
18
+ },
19
+ };
20
+ }
21
+ /** Run a CLI `run()` export without polluting the vitest console. */
22
+ export function muteProcessStreams(fn) {
23
+ const stdoutWrite = process.stdout.write.bind(process.stdout);
24
+ const stderrWrite = process.stderr.write.bind(process.stderr);
25
+ process.stdout.write = (() => true);
26
+ process.stderr.write = (() => true);
27
+ try {
28
+ return fn();
29
+ }
30
+ finally {
31
+ process.stdout.write = stdoutWrite;
32
+ process.stderr.write = stderrWrite;
33
+ }
34
+ }
35
+ //# sourceMappingURL=helpers.js.map