@deftai/directive-core 0.104.0 → 0.106.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 (287) hide show
  1. package/dist/authz/classify.js +1108 -67
  2. package/dist/check/cached-orchestrator.d.ts +1 -1
  3. package/dist/check/cached-orchestrator.js +2 -2
  4. package/dist/check/named-cause.d.ts +1 -1
  5. package/dist/check/named-cause.js +34 -4
  6. package/dist/codebase/default-extractor.d.ts +5 -0
  7. package/dist/codebase/default-extractor.js +7 -15
  8. package/dist/deposit/copy-tree.js +60 -0
  9. package/dist/deposit/python-free.js +26 -18
  10. package/dist/doctor/checks.d.ts +8 -0
  11. package/dist/doctor/checks.js +37 -25
  12. package/dist/doctor/doctor-state.d.ts +4 -0
  13. package/dist/doctor/doctor-state.js +7 -1
  14. package/dist/doctor/main.js +9 -19
  15. package/dist/doctor/types.d.ts +9 -0
  16. package/dist/forward-coverage/diff-coverage.d.ts +39 -0
  17. package/dist/forward-coverage/diff-coverage.js +112 -0
  18. package/dist/forward-coverage/diff-lines.d.ts +19 -0
  19. package/dist/forward-coverage/diff-lines.js +173 -0
  20. package/dist/forward-coverage/evaluate.d.ts +24 -9
  21. package/dist/forward-coverage/evaluate.js +125 -19
  22. package/dist/fs/contained-write.d.ts +115 -1
  23. package/dist/fs/contained-write.js +241 -5
  24. package/dist/fs/mutation-ledger.d.ts +54 -0
  25. package/dist/fs/mutation-ledger.js +133 -0
  26. package/dist/fs/non-product-dirs.d.ts +79 -0
  27. package/dist/fs/non-product-dirs.js +96 -0
  28. package/dist/hooks/dispatcher.d.ts +3 -1
  29. package/dist/hooks/dispatcher.js +14 -0
  30. package/dist/index.d.ts +1 -0
  31. package/dist/index.js +2 -0
  32. package/dist/init-deposit/agent-hooks.d.ts +1 -1
  33. package/dist/init-deposit/agent-hooks.js +18 -16
  34. package/dist/init-deposit/core-guard-pin-content.d.ts +7 -0
  35. package/dist/init-deposit/core-guard-pin-content.js +393 -0
  36. package/dist/init-deposit/gitignore.js +9 -0
  37. package/dist/init-deposit/hygiene.d.ts +47 -11
  38. package/dist/init-deposit/hygiene.js +172 -37
  39. package/dist/init-deposit/legacy-detect.js +6 -2
  40. package/dist/init-deposit/refresh.d.ts +21 -1
  41. package/dist/init-deposit/refresh.js +106 -9
  42. package/dist/init-deposit/scaffold.js +28 -279
  43. package/dist/init-deposit/slash-deposit.js +13 -7
  44. package/dist/init-deposit/xbrief-projections.d.ts +8 -1
  45. package/dist/init-deposit/xbrief-projections.js +24 -11
  46. package/dist/intake/clause-derivation.d.ts +47 -1
  47. package/dist/intake/clause-derivation.js +238 -9
  48. package/dist/intake/issue-ingest.d.ts +3 -1
  49. package/dist/intake/issue-ingest.js +35 -6
  50. package/dist/lifecycle/completed-tracked-on-delivery.d.ts +5 -0
  51. package/dist/lifecycle/completed-tracked-on-delivery.js +85 -18
  52. package/dist/lifecycle-visible/evaluate.d.ts +98 -0
  53. package/dist/lifecycle-visible/evaluate.js +710 -0
  54. package/dist/lifecycle-visible/index.d.ts +2 -0
  55. package/dist/lifecycle-visible/index.js +2 -0
  56. package/dist/literal-acceptance/capture.d.ts +10 -0
  57. package/dist/literal-acceptance/capture.js +226 -77
  58. package/dist/literal-acceptance/evaluate.d.ts +29 -4
  59. package/dist/literal-acceptance/evaluate.js +70 -2
  60. package/dist/literal-acceptance/index.d.ts +3 -3
  61. package/dist/literal-acceptance/index.js +3 -3
  62. package/dist/literal-acceptance/safety.d.ts +41 -0
  63. package/dist/literal-acceptance/safety.js +126 -2
  64. package/dist/literal-acceptance/types.d.ts +8 -0
  65. package/dist/orchestration/judgment-policy.d.ts +13 -0
  66. package/dist/orchestration/judgment-policy.js +15 -0
  67. package/dist/orchestration/probe-session.js +13 -8
  68. package/dist/orchestration/verify-judgment-gates.d.ts +4 -0
  69. package/dist/orchestration/verify-judgment-gates.js +43 -11
  70. package/dist/orphan-active/evaluate.d.ts +7 -1
  71. package/dist/orphan-active/evaluate.js +102 -23
  72. package/dist/platform/platform-capabilities.js +2 -3
  73. package/dist/policy/base-branch.d.ts +37 -0
  74. package/dist/policy/base-branch.js +114 -0
  75. package/dist/policy/branch-sync.d.ts +80 -0
  76. package/dist/policy/branch-sync.js +211 -0
  77. package/dist/policy/ceremony-dial-escalation.js +1 -0
  78. package/dist/policy/ceremony-dial.js +11 -21
  79. package/dist/policy/delivery-branch.d.ts +5 -3
  80. package/dist/policy/delivery-branch.js +7 -3
  81. package/dist/policy/file-size-thresholds.d.ts +24 -0
  82. package/dist/policy/file-size-thresholds.js +23 -0
  83. package/dist/policy/forge-outage-retry.d.ts +47 -0
  84. package/dist/policy/forge-outage-retry.js +157 -0
  85. package/dist/policy/host-hooks.d.ts +20 -0
  86. package/dist/policy/host-hooks.js +121 -2
  87. package/dist/policy/index.d.ts +7 -0
  88. package/dist/policy/index.js +66 -7
  89. package/dist/policy/org-force-on-migration.js +2 -1
  90. package/dist/policy/plan-extensions.d.ts +1 -1
  91. package/dist/policy/plan-extensions.js +2 -0
  92. package/dist/policy/product-signal.js +6 -7
  93. package/dist/policy/project-invariants.d.ts +50 -0
  94. package/dist/policy/project-invariants.js +205 -0
  95. package/dist/policy/require-human-merge.js +8 -6
  96. package/dist/policy/resolve.d.ts +7 -2
  97. package/dist/policy/resolve.js +25 -8
  98. package/dist/policy/sync-default.d.ts +129 -0
  99. package/dist/policy/sync-default.js +452 -0
  100. package/dist/policy/sync-max-files.d.ts +93 -0
  101. package/dist/policy/sync-max-files.js +192 -0
  102. package/dist/policy/value-feedback.js +7 -8
  103. package/dist/pr-monitor/absent-required.d.ts +11 -0
  104. package/dist/pr-monitor/absent-required.js +61 -0
  105. package/dist/pr-monitor/constants.d.ts +7 -0
  106. package/dist/pr-monitor/constants.js +7 -0
  107. package/dist/pr-monitor/index.d.ts +2 -1
  108. package/dist/pr-monitor/index.js +2 -1
  109. package/dist/pr-monitor/main.js +4 -0
  110. package/dist/pr-monitor/monitor.js +24 -1
  111. package/dist/pr-wait-mergeable/classify.js +6 -0
  112. package/dist/preflight/evaluate.d.ts +4 -0
  113. package/dist/preflight/evaluate.js +35 -1
  114. package/dist/preflight/index.d.ts +4 -0
  115. package/dist/preflight/index.js +2 -0
  116. package/dist/preflight/intended-placement.d.ts +62 -0
  117. package/dist/preflight/intended-placement.js +275 -0
  118. package/dist/preflight/project-invariants-gate.d.ts +29 -0
  119. package/dist/preflight/project-invariants-gate.js +82 -0
  120. package/dist/preflight-cache/evaluate.d.ts +12 -0
  121. package/dist/preflight-cache/evaluate.js +15 -1
  122. package/dist/preflight-cache/index.d.ts +1 -1
  123. package/dist/preflight-cache/index.js +1 -1
  124. package/dist/product-first-done-gate/acceptance-resolver.d.ts +128 -0
  125. package/dist/product-first-done-gate/acceptance-resolver.js +144 -0
  126. package/dist/product-first-done-gate/acceptance.d.ts +7 -4
  127. package/dist/product-first-done-gate/acceptance.js +79 -8
  128. package/dist/product-first-done-gate/empty-resolution.d.ts +4 -1
  129. package/dist/product-first-done-gate/empty-resolution.js +12 -1
  130. package/dist/product-first-done-gate/evaluate.d.ts +16 -0
  131. package/dist/product-first-done-gate/evaluate.js +298 -34
  132. package/dist/product-first-done-gate/index.d.ts +2 -0
  133. package/dist/product-first-done-gate/index.js +1 -0
  134. package/dist/release/build-dist.d.ts +101 -0
  135. package/dist/release/build-dist.js +428 -46
  136. package/dist/release/closed-verb-gate.d.ts +12 -0
  137. package/dist/release/closed-verb-gate.js +51 -0
  138. package/dist/release/index.d.ts +1 -0
  139. package/dist/release/index.js +1 -0
  140. package/dist/release/pipeline.js +7 -0
  141. package/dist/release/types.d.ts +12 -0
  142. package/dist/render/constants.d.ts +2 -1
  143. package/dist/render/constants.js +2 -1
  144. package/dist/render/framework-commands.js +4 -0
  145. package/dist/render/spec-validate.js +23 -12
  146. package/dist/run-summary/emit.d.ts +16 -10
  147. package/dist/run-summary/emit.js +26 -15
  148. package/dist/run-summary/index.d.ts +3 -2
  149. package/dist/run-summary/index.js +2 -1
  150. package/dist/run-summary/session-id.d.ts +21 -0
  151. package/dist/run-summary/session-id.js +92 -0
  152. package/dist/run-summary/types.d.ts +33 -4
  153. package/dist/run-summary/types.js +1 -0
  154. package/dist/scope/acceptance-evidence.d.ts +19 -7
  155. package/dist/scope/acceptance-evidence.js +38 -11
  156. package/dist/scope/delivery-evidence.d.ts +3 -3
  157. package/dist/scope/delivery-evidence.js +22 -27
  158. package/dist/scope/index.d.ts +1 -0
  159. package/dist/scope/index.js +1 -0
  160. package/dist/scope/main.js +15 -5
  161. package/dist/scope/parent-lineage.js +7 -6
  162. package/dist/scope/project-invariant-coverage.d.ts +54 -0
  163. package/dist/scope/project-invariant-coverage.js +322 -0
  164. package/dist/scope/promote-from-issue.js +5 -5
  165. package/dist/scope/transition.js +1 -1
  166. package/dist/scope-provenance/compare-intent.d.ts +27 -0
  167. package/dist/scope-provenance/compare-intent.js +233 -0
  168. package/dist/scope-provenance/digest.d.ts +18 -1
  169. package/dist/scope-provenance/digest.js +16 -11
  170. package/dist/scope-provenance/evaluate.d.ts +5 -1
  171. package/dist/scope-provenance/evaluate.js +67 -7
  172. package/dist/scope-provenance/extract-intent.d.ts +43 -0
  173. package/dist/scope-provenance/extract-intent.js +262 -0
  174. package/dist/scope-provenance/index.d.ts +7 -1
  175. package/dist/scope-provenance/index.js +7 -1
  176. package/dist/scope-provenance/intent-digest.d.ts +12 -0
  177. package/dist/scope-provenance/intent-digest.js +33 -0
  178. package/dist/scope-provenance/intent-evaluate.d.ts +43 -0
  179. package/dist/scope-provenance/intent-evaluate.js +149 -0
  180. package/dist/scope-provenance/json-tokenizer.d.ts +19 -0
  181. package/dist/scope-provenance/json-tokenizer.js +225 -0
  182. package/dist/scope-provenance/known-machine.d.ts +38 -0
  183. package/dist/scope-provenance/known-machine.js +157 -0
  184. package/dist/scope-provenance/mint-artifacts.d.ts +102 -0
  185. package/dist/scope-provenance/mint-artifacts.js +425 -0
  186. package/dist/session/ac-pass-banking.d.ts +9 -36
  187. package/dist/session/ac-pass-banking.js +33 -79
  188. package/dist/session/ac-pass-reuse.d.ts +53 -0
  189. package/dist/session/ac-pass-reuse.js +95 -0
  190. package/dist/session/git.js +19 -4
  191. package/dist/session/index.d.ts +4 -0
  192. package/dist/session/index.js +4 -0
  193. package/dist/session/occupancy-stress-worker.d.ts +7 -0
  194. package/dist/session/occupancy-stress-worker.js +36 -0
  195. package/dist/session/occupancy.d.ts +97 -0
  196. package/dist/session/occupancy.js +422 -0
  197. package/dist/session/openclaw-soft-rebind-deposit.js +6 -6
  198. package/dist/session/process-cost.d.ts +32 -10
  199. package/dist/session/process-cost.js +189 -1
  200. package/dist/session/product-state-hash.d.ts +26 -0
  201. package/dist/session/product-state-hash.js +700 -0
  202. package/dist/session/ritual-entrypoint.js +16 -1
  203. package/dist/session/session-ready.d.ts +2 -0
  204. package/dist/session/session-ready.js +52 -30
  205. package/dist/session/session-start.d.ts +13 -0
  206. package/dist/session/session-start.js +103 -9
  207. package/dist/session/verify-ac-session-cache.d.ts +42 -0
  208. package/dist/session/verify-ac-session-cache.js +126 -0
  209. package/dist/session/verify-session-ritual.d.ts +28 -0
  210. package/dist/session/verify-session-ritual.js +97 -5
  211. package/dist/slash/openclaw-deposit.js +13 -9
  212. package/dist/slice/constants.d.ts +2 -2
  213. package/dist/slice/constants.js +2 -2
  214. package/dist/slice/existing.js +9 -3
  215. package/dist/slice/lock.d.ts +16 -1
  216. package/dist/slice/lock.js +137 -11
  217. package/dist/story-ready/evaluate.d.ts +2 -0
  218. package/dist/story-ready/evaluate.js +13 -0
  219. package/dist/swarm/complete-cohort.d.ts +3 -0
  220. package/dist/swarm/complete-cohort.js +59 -11
  221. package/dist/swarm/finalize-cohort-cli.d.ts +7 -2
  222. package/dist/swarm/finalize-cohort-cli.js +165 -35
  223. package/dist/swarm/finalize-cohort.d.ts +1 -0
  224. package/dist/swarm/finalize-cohort.js +47 -4
  225. package/dist/swarm/launch.d.ts +22 -0
  226. package/dist/swarm/launch.js +155 -0
  227. package/dist/swarm/routing-set-cli.d.ts +11 -1
  228. package/dist/swarm/routing-set-cli.js +15 -3
  229. package/dist/swarm/routing-verify.d.ts +13 -1
  230. package/dist/swarm/routing-verify.js +60 -21
  231. package/dist/swarm/routing.d.ts +14 -0
  232. package/dist/swarm/routing.js +53 -3
  233. package/dist/telemetry-coverage/fake-trial.js +10 -0
  234. package/dist/telemetry-coverage/kinds.js +2 -0
  235. package/dist/triage/actions/index.js +4 -1
  236. package/dist/triage/bootstrap/index.js +6 -6
  237. package/dist/triage/help/registry-data.d.ts +1 -1
  238. package/dist/triage/help/registry-data.js +1 -1
  239. package/dist/triage/welcome/writers.d.ts +1 -1
  240. package/dist/triage/welcome/writers.js +10 -5
  241. package/dist/ts-check-lane/index.d.ts +3 -0
  242. package/dist/ts-check-lane/index.js +2 -0
  243. package/dist/ts-check-lane/progress-reporter.d.ts +17 -0
  244. package/dist/ts-check-lane/progress-reporter.js +38 -0
  245. package/dist/ts-check-lane/progress.d.ts +32 -0
  246. package/dist/ts-check-lane/progress.js +57 -0
  247. package/dist/ts-check-lane/run-lane.d.ts +3 -1
  248. package/dist/ts-check-lane/run-lane.js +8 -6
  249. package/dist/validate-content/validate-links.d.ts +8 -0
  250. package/dist/validate-content/validate-links.js +9 -15
  251. package/dist/value/feedback-file.js +12 -2
  252. package/dist/value/readback.d.ts +4 -1
  253. package/dist/value/readback.js +51 -12
  254. package/dist/vbrief-build/index.d.ts +1 -0
  255. package/dist/vbrief-build/index.js +1 -0
  256. package/dist/vbrief-build/project-invariants-io.d.ts +16 -0
  257. package/dist/vbrief-build/project-invariants-io.js +41 -0
  258. package/dist/vbrief-reconcile/graph.js +18 -1
  259. package/dist/vbrief-reconcile/index.d.ts +1 -1
  260. package/dist/vbrief-reconcile/index.js +1 -1
  261. package/dist/vbrief-reconcile/types.d.ts +13 -0
  262. package/dist/vbrief-reconcile/umbrellas.d.ts +14 -0
  263. package/dist/vbrief-reconcile/umbrellas.js +261 -26
  264. package/dist/vbrief-validate/index.d.ts +1 -1
  265. package/dist/vbrief-validate/index.js +1 -1
  266. package/dist/vbrief-validate/plan-hooks.d.ts +4 -0
  267. package/dist/vbrief-validate/plan-hooks.js +68 -0
  268. package/dist/vbrief-validate/schema.d.ts +4 -0
  269. package/dist/vbrief-validate/schema.js +1 -1
  270. package/dist/verify-ac/evaluate.d.ts +7 -1
  271. package/dist/verify-ac/evaluate.js +34 -26
  272. package/dist/verify-ac/flag.d.ts +4 -0
  273. package/dist/verify-ac/flag.js +16 -0
  274. package/dist/verify-ac/index.d.ts +2 -2
  275. package/dist/verify-ac/index.js +2 -2
  276. package/dist/verify-env/agent-hook-readiness.d.ts +2 -2
  277. package/dist/verify-env/agent-hook-readiness.js +12 -8
  278. package/dist/verify-env/agent-hooks-live-probe.d.ts +5 -1
  279. package/dist/verify-env/agent-hooks-live-probe.js +26 -5
  280. package/dist/verify-env/agent-hooks.js +3 -4
  281. package/dist/verify-source/contained-writes.js +2 -0
  282. package/dist/verify-source/verify-stubs.d.ts +15 -1
  283. package/dist/verify-source/verify-stubs.js +20 -16
  284. package/dist/vitest-runner/win32-coverage-tmp-setup.d.ts +5 -6
  285. package/dist/vitest-runner/win32-coverage-tmp-setup.js +5 -6
  286. package/dist/xbrief-migrate/migrate-project.js +2 -5
  287. package/package.json +7 -3
@@ -4,6 +4,7 @@ import { containedWrite } from "../../fs/contained-write.js";
4
4
  import { assertWriteTargetSafe } from "../../fs/projection-containment.js";
5
5
  import { hasArtifactSuffix, resolveLifecycleFolder, resolveProjectDefinitionPath, } from "../../layout/resolve.js";
6
6
  import { migrateLegacyPolicyKey, PLAN_ONBOARDING_KEY, PLAN_POLICY_KEY, } from "../../policy/plan-extensions.js";
7
+ import { stampChangedToken } from "../../policy/resolve.js";
7
8
  import { projectDefinitionMutationLock } from "../../vbrief-build/project-definition-io.js";
8
9
  import { AUDIT_LOG_REL_PATH, DEFAULT_RELIEF_AGE_DAYS, DEFAULT_WIP_CAP, SUBSCRIPTION_PRESETS, WELCOME_AUDIT_TAG, } from "./constants.js";
9
10
  function projectDefinitionPath(projectRoot) {
@@ -12,9 +13,13 @@ function projectDefinitionPath(projectRoot) {
12
13
  function utcIso() {
13
14
  return new Date().toISOString().replace(/\.\d{3}Z$/, "Z");
14
15
  }
15
- export function appendAuditEntry(projectRoot, entry) {
16
+ export function appendAuditEntry(projectRoot, entry, changed = true) {
16
17
  const root = resolve(projectRoot);
17
18
  const logPath = join(root, AUDIT_LOG_REL_PATH);
19
+ const stamped = stampChangedToken(entry, changed);
20
+ if (!changed) {
21
+ return logPath;
22
+ }
18
23
  // #2980 wave D: product write sink routes through containedWrite.
19
24
  mkdirSync(root, { recursive: true });
20
25
  if (!existsSync(logPath)) {
@@ -28,7 +33,7 @@ export function appendAuditEntry(projectRoot, entry) {
28
33
  containedWrite({
29
34
  root,
30
35
  target: AUDIT_LOG_REL_PATH,
31
- data: `${utcIso()} ${entry}\n`,
36
+ data: `${utcIso()} ${stamped}\n`,
32
37
  mode: "append",
33
38
  });
34
39
  return logPath;
@@ -102,7 +107,7 @@ export function writeTriageScope(projectRoot, rules, options = { presetLabel: "c
102
107
  `rule_count=${rules.length}`,
103
108
  `changed=${changed ? "true" : "false"}`,
104
109
  ].join(" ");
105
- appendAuditEntry(projectRoot, auditEntry);
110
+ appendAuditEntry(projectRoot, auditEntry, changed);
106
111
  return [changed, auditEntry];
107
112
  });
108
113
  }
@@ -153,7 +158,7 @@ export function writeWipCapDecision(projectRoot, options = {}) {
153
158
  `acceptedDefault=${acceptedDefault ? "true" : "false"}`,
154
159
  `changed=${changed ? "true" : "false"}`,
155
160
  ].join(" ");
156
- appendAuditEntry(projectRoot, auditEntry);
161
+ appendAuditEntry(projectRoot, auditEntry, changed);
157
162
  return [changed, auditEntry];
158
163
  });
159
164
  }
@@ -220,7 +225,7 @@ export function writeWipCap(projectRoot, wipCap, options = {}) {
220
225
  const changed = previous !== wipCap;
221
226
  const auditEntry = `actor=${actor} field=plan.policy.wipCap value=${wipCap} previous=${JSON.stringify(previous)} ` +
222
227
  `changed=${changed ? "true" : "false"}`;
223
- appendAuditEntry(projectRoot, auditEntry);
228
+ appendAuditEntry(projectRoot, auditEntry, changed);
224
229
  return [changed, auditEntry];
225
230
  });
226
231
  }
@@ -1,3 +1,6 @@
1
+ export type { ProgressLineSink, ProgressTick, WriteFlushedLineOptions, } from "./progress.js";
2
+ export { buildTestLaneCommand, formatProgressLine, nextProgressTick, PROGRESS_BAND_PERCENT, PROGRESS_REPORTER_RELATIVE_PATH, PROGRESS_UNIT, resolveTestLaneCommand, writeFlushedLine, } from "./progress.js";
3
+ export { TsCheckLaneProgressReporter } from "./progress-reporter.js";
1
4
  export type { LaneRunner, ResolvePnpmOptions, RunnerResult, RunTsLaneOptions } from "./run-lane.js";
2
5
  export { LANE_COMMANDS, resolvePnpm, runTsLane, SKIP_NOTICE, sanitizeTsLaneEnv, } from "./run-lane.js";
3
6
  //# sourceMappingURL=index.d.ts.map
@@ -1,2 +1,4 @@
1
+ export { buildTestLaneCommand, formatProgressLine, nextProgressTick, PROGRESS_BAND_PERCENT, PROGRESS_REPORTER_RELATIVE_PATH, PROGRESS_UNIT, resolveTestLaneCommand, writeFlushedLine, } from "./progress.js";
2
+ export { TsCheckLaneProgressReporter } from "./progress-reporter.js";
1
3
  export { LANE_COMMANDS, resolvePnpm, runTsLane, SKIP_NOTICE, sanitizeTsLaneEnv, } from "./run-lane.js";
2
4
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Vitest reporter that emits coarse flushed progress for ts:check-lane (#3470).
3
+ *
4
+ * Wired from the lane via `--reporter` so vitest.config.ts stays unchanged.
5
+ * Does not print test names and does not change pass/fail.
6
+ */
7
+ export declare class TsCheckLaneProgressReporter {
8
+ private total;
9
+ private completed;
10
+ private lastEmittedPercent;
11
+ private readonly sink?;
12
+ constructor(sink?: unknown);
13
+ onTestRunStart(specifications?: ReadonlyArray<unknown>): void;
14
+ onTestModuleEnd(): void;
15
+ }
16
+ export default TsCheckLaneProgressReporter;
17
+ //# sourceMappingURL=progress-reporter.d.ts.map
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Vitest reporter that emits coarse flushed progress for ts:check-lane (#3470).
3
+ *
4
+ * Wired from the lane via `--reporter` so vitest.config.ts stays unchanged.
5
+ * Does not print test names and does not change pass/fail.
6
+ */
7
+ import { formatProgressLine, nextProgressTick, writeFlushedLine, } from "./progress.js";
8
+ function isLineSink(value) {
9
+ return (typeof value === "object" &&
10
+ value !== null &&
11
+ typeof value.write === "function");
12
+ }
13
+ export class TsCheckLaneProgressReporter {
14
+ total = 0;
15
+ completed = 0;
16
+ lastEmittedPercent = 0;
17
+ sink;
18
+ constructor(sink) {
19
+ // Vitest constructs reporters with its options object; only tests pass a sink.
20
+ this.sink = isLineSink(sink) ? sink : undefined;
21
+ }
22
+ onTestRunStart(specifications = []) {
23
+ this.total = specifications.length;
24
+ this.completed = 0;
25
+ this.lastEmittedPercent = 0;
26
+ }
27
+ onTestModuleEnd() {
28
+ this.completed += 1;
29
+ const tick = nextProgressTick(this.completed, this.total, this.lastEmittedPercent);
30
+ if (tick === null) {
31
+ return;
32
+ }
33
+ this.lastEmittedPercent = tick.percent;
34
+ writeFlushedLine(formatProgressLine(tick), this.sink);
35
+ }
36
+ }
37
+ export default TsCheckLaneProgressReporter;
38
+ //# sourceMappingURL=progress-reporter.js.map
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Coarse percent/count ticks for ts:check-lane (#3470).
3
+ *
4
+ * Band math is independent of vitest so tests can cover cadence and flush
5
+ * without running the suite.
6
+ */
7
+ /** Relative to the repo root; wired onto `pnpm run test` from the lane. */
8
+ export declare const PROGRESS_REPORTER_RELATIVE_PATH = "packages/core/src/ts-check-lane/progress-reporter.ts";
9
+ /** One line every 20% of known files -- coarse enough for a log snapshot. */
10
+ export declare const PROGRESS_BAND_PERCENT = 20;
11
+ export declare const PROGRESS_UNIT = "files";
12
+ export interface ProgressTick {
13
+ readonly percent: number;
14
+ readonly completed: number;
15
+ readonly total: number;
16
+ }
17
+ export interface ProgressLineSink {
18
+ write(chunk: string): void;
19
+ flush?: () => void;
20
+ }
21
+ export declare function nextProgressTick(completed: number, total: number, lastEmittedPercent: number, bandPercent?: number): ProgressTick | null;
22
+ export declare function formatProgressLine(tick: ProgressTick, unit?: string): string;
23
+ export interface WriteFlushedLineOptions {
24
+ readonly fd?: number;
25
+ readonly syncWrite?: (fd: number, payload: string) => void;
26
+ }
27
+ /** writeSync so a non-TTY capture sees each tick immediately (#1353). */
28
+ export declare function writeFlushedLine(line: string, sink?: ProgressLineSink, options?: WriteFlushedLineOptions): void;
29
+ export declare function buildTestLaneCommand(reporterPath?: string): readonly string[];
30
+ /** Attach the reporter only when the source file is present (framework checkout). */
31
+ export declare function resolveTestLaneCommand(projectRoot: string, exists?: (path: string) => boolean): readonly string[];
32
+ //# sourceMappingURL=progress.d.ts.map
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Coarse percent/count ticks for ts:check-lane (#3470).
3
+ *
4
+ * Band math is independent of vitest so tests can cover cadence and flush
5
+ * without running the suite.
6
+ */
7
+ import { existsSync, writeSync } from "node:fs";
8
+ import { join } from "node:path";
9
+ /** Relative to the repo root; wired onto `pnpm run test` from the lane. */
10
+ export const PROGRESS_REPORTER_RELATIVE_PATH = "packages/core/src/ts-check-lane/progress-reporter.ts";
11
+ /** One line every 20% of known files -- coarse enough for a log snapshot. */
12
+ export const PROGRESS_BAND_PERCENT = 20;
13
+ export const PROGRESS_UNIT = "files";
14
+ export function nextProgressTick(completed, total, lastEmittedPercent, bandPercent = PROGRESS_BAND_PERCENT) {
15
+ if (!Number.isFinite(completed) ||
16
+ !Number.isFinite(total) ||
17
+ !Number.isFinite(lastEmittedPercent)) {
18
+ return null;
19
+ }
20
+ if (total <= 0 || completed <= 0 || bandPercent <= 0) {
21
+ return null;
22
+ }
23
+ const raw = Math.min(100, Math.floor((completed / total) * 100));
24
+ const band = Math.floor(raw / bandPercent) * bandPercent;
25
+ if (band < bandPercent || band <= lastEmittedPercent) {
26
+ return null;
27
+ }
28
+ return { percent: band, completed, total };
29
+ }
30
+ export function formatProgressLine(tick, unit = PROGRESS_UNIT) {
31
+ return `ts:check-lane ${tick.percent}% (${tick.completed}/${tick.total} ${unit})`;
32
+ }
33
+ /** writeSync so a non-TTY capture sees each tick immediately (#1353). */
34
+ export function writeFlushedLine(line, sink, options = {}) {
35
+ const payload = line.endsWith("\n") ? line : `${line}\n`;
36
+ if (sink !== undefined && typeof sink.write === "function") {
37
+ sink.write(payload);
38
+ sink.flush?.();
39
+ return;
40
+ }
41
+ const syncWrite = options.syncWrite ?? writeSync;
42
+ syncWrite(options.fd ?? 1, payload);
43
+ }
44
+ export function buildTestLaneCommand(reporterPath = PROGRESS_REPORTER_RELATIVE_PATH) {
45
+ // Do not insert a standalone "--": pnpm forwards it to vitest, which then
46
+ // treats later --reporter flags as file filters (#3470).
47
+ return ["run", "test", "--reporter", reporterPath, "--reporter", "default"];
48
+ }
49
+ /** Attach the reporter only when the source file is present (framework checkout). */
50
+ export function resolveTestLaneCommand(projectRoot, exists = existsSync) {
51
+ const reporterAbs = join(projectRoot, ...PROGRESS_REPORTER_RELATIVE_PATH.split("/"));
52
+ if (!exists(reporterAbs)) {
53
+ return ["run", "test"];
54
+ }
55
+ return buildTestLaneCommand();
56
+ }
57
+ //# sourceMappingURL=progress.js.map
@@ -20,7 +20,7 @@
20
20
  * Run order is deliberate: lint (cheapest, catches the biome class first),
21
21
  * then build, then the test suite.
22
22
  */
23
- export declare const LANE_COMMANDS: ReadonlyArray<readonly [string, string]>;
23
+ export declare const LANE_COMMANDS: ReadonlyArray<readonly string[]>;
24
24
  export declare const SKIP_NOTICE: string;
25
25
  /** Result of a single lane command invocation. Mirrors a subset of SpawnSyncReturns. */
26
26
  export interface RunnerResult {
@@ -46,6 +46,8 @@ export interface RunTsLaneOptions {
46
46
  * DEFT_RELEASE_PREFLIGHT (#2618). Defaults to process.env.
47
47
  */
48
48
  readonly env?: NodeJS.ProcessEnv;
49
+ /** Injected reporter-file probe (defaults to existsSync). */
50
+ readonly reporterExists?: (path: string) => boolean;
49
51
  }
50
52
  /** Windows command shims (.cmd/.bat) need a shell; native executables do not. */
51
53
  export declare function shouldUseShellForCommand(command: string, platform?: NodeJS.Platform): boolean;
@@ -21,6 +21,7 @@ import { existsSync } from "node:fs";
21
21
  import { posix, win32 } from "node:path";
22
22
  import { BRANCH_GATE_BYPASS_ENV, RELEASE_PREFLIGHT_ENV } from "../release/constants.js";
23
23
  import { resolveCoverageDebtIssue } from "../vitest-runner/coverage-debt.js";
24
+ import { buildTestLaneCommand, resolveTestLaneCommand } from "./progress.js";
24
25
  /** Release Step-5 vars that must not leak into vitest via inherited pnpm env (#2434). */
25
26
  const TS_LANE_POISON_ENV_KEYS = [BRANCH_GATE_BYPASS_ENV, RELEASE_PREFLIGHT_ENV];
26
27
  /**
@@ -30,7 +31,7 @@ const TS_LANE_POISON_ENV_KEYS = [BRANCH_GATE_BYPASS_ENV, RELEASE_PREFLIGHT_ENV];
30
31
  export const LANE_COMMANDS = [
31
32
  ["run", "lint"],
32
33
  ["run", "build"],
33
- ["run", "test"],
34
+ buildTestLaneCommand(),
34
35
  ];
35
36
  export const SKIP_NOTICE = "[ts:check-lane] pnpm not found on PATH -- skipping the TypeScript lane " +
36
37
  "(build/lint/test). The TS engine stays validated by the dedicated CI job. " +
@@ -107,8 +108,9 @@ export function runTsLane(projectRoot, options) {
107
108
  return 0;
108
109
  }
109
110
  for (const command of LANE_COMMANDS) {
110
- const argv = [pnpm, ...command];
111
- // Soft-pass via lane-private env (vitest 3 CAC rejects unknown CLI debt tokens).
111
+ const resolved = command[1] === "test" ? resolveTestLaneCommand(projectRoot, options.reporterExists) : command;
112
+ const argv = [pnpm, ...resolved];
113
+ // Soft-pass via lane-private env (vitest CAC rejects unknown CLI debt tokens).
112
114
  // vitest.config reads DEFT_TS_LANE_COVERAGE_DEBT without DEFT_RELEASE_PREFLIGHT
113
115
  // (sanitizeTsLaneEnv strips preflight). Refs #2573 / #2618.
114
116
  const prevDebt = process.env.DEFT_TS_LANE_COVERAGE_DEBT;
@@ -137,14 +139,14 @@ export function runTsLane(projectRoot, options) {
137
139
  // (non-zero) for a signal-killed process.
138
140
  if (code === null) {
139
141
  if (result.error) {
140
- out(`[ts:check-lane] \`pnpm ${command.join(" ")}\` failed to start: ${result.error.message}`);
142
+ out(`[ts:check-lane] \`pnpm ${resolved.join(" ")}\` failed to start: ${result.error.message}`);
141
143
  return 1;
142
144
  }
143
- out(`[ts:check-lane] \`pnpm ${command.join(" ")}\` was killed by ${result.signal ?? "a signal"} before exit -- treating as failure.`);
145
+ out(`[ts:check-lane] \`pnpm ${resolved.join(" ")}\` was killed by ${result.signal ?? "a signal"} before exit -- treating as failure.`);
144
146
  return 1;
145
147
  }
146
148
  if (code !== 0) {
147
- out(`[ts:check-lane] \`pnpm ${command.join(" ")}\` failed (exit ${code}).`);
149
+ out(`[ts:check-lane] \`pnpm ${resolved.join(" ")}\` failed (exit ${code}).`);
148
150
  return code;
149
151
  }
150
152
  }
@@ -1,4 +1,12 @@
1
1
  import type { EvaluateResult } from "./types.js";
2
+ /**
3
+ * Shared "not product source" core (#3487) plus the two directories only the
4
+ * link walk skips: generated planning projections and `specs/`.
5
+ *
6
+ * Walking agent worktrees during release Step 5 / `task check` is pure
7
+ * wall-clock waste (#2953, #1656, #3481).
8
+ */
9
+ export declare const EXCLUDE_DIRS: Set<string>;
2
10
  export interface BrokenLink {
3
11
  readonly file: string;
4
12
  readonly line: number;
@@ -1,21 +1,15 @@
1
1
  import { existsSync, readdirSync, readFileSync } from "node:fs";
2
2
  import { join, relative, resolve, sep } from "node:path";
3
+ import { NON_PRODUCT_DIRS } from "../fs/non-product-dirs.js";
3
4
  import { extractLinkTargets, shouldSkipLinkTarget } from "./link-parser.js";
4
- const EXCLUDE_DIRS = new Set([
5
- ".git",
6
- "backup",
7
- "node_modules",
8
- ".venv",
9
- "__pycache__",
10
- "dist",
11
- ".planning",
12
- "specs",
13
- // Swarm / agent worktrees are not framework content; walking them
14
- // during release Step 5 / task check is pure wall-clock waste (#2953, #1656).
15
- ".deft-scratch",
16
- // Legacy swarm worktree root name (pre-.deft-scratch layout).
17
- "swarm-worktrees",
18
- ]);
5
+ /**
6
+ * Shared "not product source" core (#3487) plus the two directories only the
7
+ * link walk skips: generated planning projections and `specs/`.
8
+ *
9
+ * Walking agent worktrees during release Step 5 / `task check` is pure
10
+ * wall-clock waste (#2953, #1656, #3481).
11
+ */
12
+ export const EXCLUDE_DIRS = new Set([...NON_PRODUCT_DIRS, ".planning", "specs"]);
19
13
  function shouldSkipPath(parts) {
20
14
  if (parts.some((p) => EXCLUDE_DIRS.has(p)))
21
15
  return true;
@@ -235,10 +235,17 @@ export function runFeedbackFile(options) {
235
235
  };
236
236
  }
237
237
  }
238
+ /** Join repeated --context values; schema stays `context?: string` (#3454). */
239
+ const CONTEXT_JOIN = "\n";
240
+ function appendContextValue(collected, value) {
241
+ if (typeof value === "string")
242
+ collected.push(value);
243
+ }
238
244
  /** Parse argv for feedback:file. */
239
245
  export function parseFeedbackFileArgs(argv) {
240
246
  const out = {};
241
247
  const positionals = [];
248
+ const contextValues = [];
242
249
  for (let i = 0; i < argv.length; i += 1) {
243
250
  const arg = argv[i];
244
251
  if (arg === "--confirm")
@@ -254,10 +261,10 @@ export function parseFeedbackFileArgs(argv) {
254
261
  out.summary = arg.slice("--summary=".length);
255
262
  }
256
263
  else if (arg === "--context") {
257
- out.context = argv[++i];
264
+ appendContextValue(contextValues, argv[++i]);
258
265
  }
259
266
  else if (arg?.startsWith("--context=")) {
260
- out.context = arg.slice("--context=".length);
267
+ appendContextValue(contextValues, arg.slice("--context=".length));
261
268
  }
262
269
  else if (arg === "--expected") {
263
270
  out.expected = argv[++i];
@@ -302,6 +309,9 @@ export function parseFeedbackFileArgs(argv) {
302
309
  if ((out.summary === undefined || out.summary.trim().length === 0) && positionals.length > 0) {
303
310
  out.summary = positionals.join(" ");
304
311
  }
312
+ if (contextValues.length > 0) {
313
+ out.context = contextValues.join(CONTEXT_JOIN);
314
+ }
305
315
  return out;
306
316
  }
307
317
  /** CLI entry for feedback:file. */
@@ -1,5 +1,6 @@
1
1
  import { type BehavioralEventRecord } from "../lifecycle/events.js";
2
2
  import { type ValueFeedbackResolved } from "../policy/value-feedback.js";
3
+ import { type CeremonyCostRollup } from "../session/process-cost.js";
3
4
  /** Repeat-suppression window for the budgeted session readback (#1709 / #1279 parity). */
4
5
  export declare const VALUE_READBACK_SUPPRESSION_HOURS = 4;
5
6
  export declare const VALUE_READBACK_HISTORY_REL: string;
@@ -24,6 +25,8 @@ export interface ValueShowResult {
24
25
  readonly empty: boolean;
25
26
  readonly text: string;
26
27
  readonly trend: ValueShowTrend | null;
28
+ /** Composed #3508 ceremony-cost rollup (CLI process time, not turn clock). */
29
+ readonly ceremonyCost: CeremonyCostRollup | null;
27
30
  }
28
31
  export interface SessionReadbackResult {
29
32
  readonly line: string | null;
@@ -64,7 +67,7 @@ export declare function computeValueShowTrend(projectRoot: string, options?: {
64
67
  now?: Date;
65
68
  }): ValueShowTrend;
66
69
  export declare function formatValueShowReport(trend: ValueShowTrend): string;
67
- /** Pull-based value:show CLI core (#1709). */
70
+ /** Pull-based value:show CLI core (#1709) with composed ceremony-cost reader (#3508). */
68
71
  export declare function runValueShow(options: {
69
72
  projectRoot?: string | null;
70
73
  window?: string;
@@ -8,6 +8,7 @@ import { DEFAULT_EVENT_LOG, readEvents } from "../lifecycle/events.js";
8
8
  import { policyColonInvocation } from "../policy/policy-invocation.js";
9
9
  import { isValueFeedbackPathAllowed, resolveValueFeedback, } from "../policy/value-feedback.js";
10
10
  import { resolveProjectRoot } from "../scope/project-context.js";
11
+ import { computeCeremonyCostRollup, formatCeremonyCostReport, PROCESS_COST_EVENT_NAMES, } from "../session/process-cost.js";
11
12
  import { MAX_LINE_CHARS } from "../triage/welcome/constants.js";
12
13
  import { probeAdoptionAtWorkBoundary } from "./adoption-emit.js";
13
14
  import { probeFrictionAtWorkBoundary } from "./friction-emit.js";
@@ -391,7 +392,36 @@ export function formatValueShowReport(trend) {
391
392
  ];
392
393
  return `${lines.join("\n")}\n`;
393
394
  }
394
- /** Pull-based value:show CLI core (#1709). */
395
+ function attachCeremonyCost(result, ceremonyCost, format) {
396
+ if (format === "json") {
397
+ const payload = result.trend !== null
398
+ ? {
399
+ ...result.trend,
400
+ ceremonyCost,
401
+ process_cost_events: PROCESS_COST_EVENT_NAMES,
402
+ gated: result.gated,
403
+ attribution_gated: result.gated,
404
+ }
405
+ : {
406
+ ceremonyCost,
407
+ process_cost_events: PROCESS_COST_EVENT_NAMES,
408
+ gated: result.gated,
409
+ attribution_gated: result.gated,
410
+ empty: result.empty,
411
+ };
412
+ return {
413
+ ...result,
414
+ ceremonyCost,
415
+ text: `${JSON.stringify(payload, null, 2)}\n`,
416
+ };
417
+ }
418
+ return {
419
+ ...result,
420
+ ceremonyCost,
421
+ text: `${result.text}${formatCeremonyCostReport(ceremonyCost)}`,
422
+ };
423
+ }
424
+ /** Pull-based value:show CLI core (#1709) with composed ceremony-cost reader (#3508). */
395
425
  export function runValueShow(options) {
396
426
  const rootRaw = resolveProjectRoot(options.projectRoot ?? undefined);
397
427
  if (rootRaw === null) {
@@ -401,30 +431,39 @@ export function runValueShow(options) {
401
431
  empty: true,
402
432
  text: "Error: could not resolve project root.\n",
403
433
  trend: null,
434
+ ceremonyCost: null,
404
435
  };
405
436
  }
406
437
  const root = resolve(rootRaw);
438
+ const windowMs = parseWindowMs(options.window);
439
+ const ceremonyCost = computeCeremonyCostRollup({
440
+ projectRoot: root,
441
+ logPath: options.logPath,
442
+ windowMs,
443
+ now: options.now,
444
+ windowLabel: formatWindowLabel(windowMs),
445
+ });
407
446
  if (maintainerReadbackDisabled(root)) {
408
- return {
447
+ return attachCeremonyCost({
409
448
  exitCode: 0,
410
- gated: true,
449
+ gated: false,
411
450
  empty: true,
412
- text: "[value] Skipped: maintainer framework repo (set DEFT_VALUE_SELF_DOGFOOD=1 to dogfood).\n",
451
+ text: "[value] Attribution skipped: maintainer framework repo " +
452
+ "(set DEFT_VALUE_SELF_DOGFOOD=1 to dogfood).\n",
413
453
  trend: null,
414
- };
454
+ }, ceremonyCost, options.format);
415
455
  }
416
456
  const policy = options.policyOverride ?? resolveValueFeedback(root);
417
457
  if (!policy.enabled) {
418
- return {
458
+ return attachCeremonyCost({
419
459
  exitCode: 1,
420
460
  gated: true,
421
461
  empty: true,
422
462
  text: "[value] Blocked: plan.policy.valueFeedback is OFF. " +
423
463
  `Enable with \`${policyColonInvocation("enable-value-feedback", " -- --confirm")}\`.\n`,
424
464
  trend: null,
425
- };
465
+ }, ceremonyCost, options.format);
426
466
  }
427
- const windowMs = parseWindowMs(options.window);
428
467
  const trend = computeValueShowTrend(root, {
429
468
  windowMs,
430
469
  logPath: options.logPath,
@@ -432,21 +471,21 @@ export function runValueShow(options) {
432
471
  });
433
472
  const empty = trend.total === 0;
434
473
  if (options.format === "json") {
435
- return {
474
+ return attachCeremonyCost({
436
475
  exitCode: 0,
437
476
  gated: false,
438
477
  empty,
439
478
  text: `${JSON.stringify(trend, null, 2)}\n`,
440
479
  trend,
441
- };
480
+ }, ceremonyCost, "json");
442
481
  }
443
- return {
482
+ return attachCeremonyCost({
444
483
  exitCode: 0,
445
484
  gated: false,
446
485
  empty,
447
486
  text: formatValueShowReport(trend),
448
487
  trend,
449
- };
488
+ }, ceremonyCost, "text");
450
489
  }
451
490
  export function parseValueShowArgs(argv) {
452
491
  const out = {};
@@ -4,6 +4,7 @@ export { pythonJsonPretty } from "./json.js";
4
4
  export { cmdVbriefBuild, run, usage } from "./main.js";
5
5
  export { PARITY_SCENARIO_NAMES, renderScenarioOutput, runParityScenario, SAMPLE_PROJECT_MD, SAMPLE_ROADMAP_MD, SAMPLE_SPEC_MD, SAMPLE_SPEC_VBRIEF, } from "./parity-scenarios.js";
6
6
  export { atomicWriteProjectDefinition, loadProjectDefinitionForMutation, projectDefinitionMutationLock, projectDefinitionPath, } from "./project-definition-io.js";
7
+ export { loadProjectInvariants, parseProjectInvariantsField } from "./project-invariants-io.js";
7
8
  export { buildScopeVbriefFromReconciled, defaultStatusForFolder, folderForStatus, migrationTimestamp, planStatusMatchesFolder, } from "./routing.js";
8
9
  export { deriveOverviewNarrative, extractTechStack, firstProseParagraph, parseRoadmapItems, resolveRepoUrl, } from "./sources.js";
9
10
  export { createSpeckitScopeVbrief, dependenciesForItem, edgeNodes, migrateSpeckitPlan, speckitIpIndex, speckitIpSlug, } from "./speckit.js";
@@ -4,6 +4,7 @@ export { pythonJsonPretty } from "./json.js";
4
4
  export { cmdVbriefBuild, run, usage } from "./main.js";
5
5
  export { PARITY_SCENARIO_NAMES, renderScenarioOutput, runParityScenario, SAMPLE_PROJECT_MD, SAMPLE_ROADMAP_MD, SAMPLE_SPEC_MD, SAMPLE_SPEC_VBRIEF, } from "./parity-scenarios.js";
6
6
  export { atomicWriteProjectDefinition, loadProjectDefinitionForMutation, projectDefinitionMutationLock, projectDefinitionPath, } from "./project-definition-io.js";
7
+ export { loadProjectInvariants, parseProjectInvariantsField } from "./project-invariants-io.js";
7
8
  export { buildScopeVbriefFromReconciled, defaultStatusForFolder, folderForStatus, migrationTimestamp, planStatusMatchesFolder, } from "./routing.js";
8
9
  export { deriveOverviewNarrative, extractTechStack, firstProseParagraph, parseRoadmapItems, resolveRepoUrl, } from "./sources.js";
9
10
  export { createSpeckitScopeVbrief, dependenciesForItem, edgeNodes, migrateSpeckitPlan, speckitIpIndex, speckitIpSlug, } from "./speckit.js";
@@ -0,0 +1,16 @@
1
+ /**
2
+ * PROJECT-DEFINITION IO for plan.policy.projectInvariants (#3425 Story A).
3
+ */
4
+ import { type ProjectInvariant, type ProjectInvariantsResolved } from "../policy/project-invariants.js";
5
+ export interface LoadedProjectInvariants {
6
+ readonly path: string;
7
+ readonly resolved: ProjectInvariantsResolved;
8
+ readonly modulePathGlobs: Readonly<Record<string, readonly string[]>>;
9
+ }
10
+ /** Read and parse projectInvariants via the PROJECT-DEFINITION IO path. */
11
+ export declare function loadProjectInvariants(projectRoot: string): LoadedProjectInvariants;
12
+ export declare function parseProjectInvariantsField(raw: unknown): {
13
+ readonly invariants: readonly ProjectInvariant[];
14
+ readonly errors: readonly string[];
15
+ };
16
+ //# sourceMappingURL=project-invariants-io.d.ts.map
@@ -0,0 +1,41 @@
1
+ /**
2
+ * PROJECT-DEFINITION IO for plan.policy.projectInvariants (#3425 Story A).
3
+ */
4
+ import { existsSync, readFileSync } from "node:fs";
5
+ import { extractModulePathGlobs, parseProjectInvariants, resolveProjectInvariantsFromData, } from "../policy/project-invariants.js";
6
+ import { projectDefinitionPath } from "./project-definition-io.js";
7
+ /** Read and parse projectInvariants via the PROJECT-DEFINITION IO path. */
8
+ export function loadProjectInvariants(projectRoot) {
9
+ const path = projectDefinitionPath(projectRoot);
10
+ if (!existsSync(path)) {
11
+ return {
12
+ path,
13
+ resolved: {
14
+ invariants: [],
15
+ source: "default",
16
+ error: `PROJECT-DEFINITION not found at ${path}`,
17
+ },
18
+ modulePathGlobs: {},
19
+ };
20
+ }
21
+ try {
22
+ const data = JSON.parse(readFileSync(path, "utf8"));
23
+ return {
24
+ path,
25
+ resolved: resolveProjectInvariantsFromData(data),
26
+ modulePathGlobs: extractModulePathGlobs(data),
27
+ };
28
+ }
29
+ catch (err) {
30
+ const msg = err instanceof Error ? err.message : String(err);
31
+ return {
32
+ path,
33
+ resolved: { invariants: [], source: "default-on-error", error: msg },
34
+ modulePathGlobs: {},
35
+ };
36
+ }
37
+ }
38
+ export function parseProjectInvariantsField(raw) {
39
+ return parseProjectInvariants(raw);
40
+ }
41
+ //# sourceMappingURL=project-invariants-io.js.map
@@ -34,6 +34,7 @@ export function reconcileGraph(projectRoot, options = {}) {
34
34
  2,
35
35
  {
36
36
  promoted: [],
37
+ promotedNotices: [],
37
38
  deferredWip: [],
38
39
  waiting: [],
39
40
  cycles: [],
@@ -62,6 +63,7 @@ export function reconcileGraph(projectRoot, options = {}) {
62
63
  const [cap, count] = resolveWipState(root);
63
64
  const outcome = {
64
65
  promoted: [],
66
+ promotedNotices: [],
65
67
  deferredWip: [],
66
68
  waiting: [],
67
69
  cycles: [],
@@ -105,6 +107,9 @@ export function reconcileGraph(projectRoot, options = {}) {
105
107
  continue;
106
108
  }
107
109
  outcome.promoted.push(cand.storyId);
110
+ if (result.message.trim().length > 0) {
111
+ outcome.promotedNotices?.push({ story_id: cand.storyId, message: result.message });
112
+ }
108
113
  runningCount += 1;
109
114
  }
110
115
  return [outcome.cycles.length > 0 ? 1 : 0, { ...outcome, count: runningCount }];
@@ -114,8 +119,16 @@ export function renderGraphReport(outcome) {
114
119
  const suffix = outcome.dryRun ? " (dry-run)" : "";
115
120
  lines.push(`Promoted${suffix}:`);
116
121
  if (outcome.promoted.length > 0) {
117
- for (const id of outcome.promoted)
122
+ const notices = new Map((outcome.promotedNotices ?? []).map((n) => [n.story_id, n.message]));
123
+ for (const id of outcome.promoted) {
118
124
  lines.push(`- ${id}`);
125
+ const notice = notices.get(id);
126
+ if (notice !== undefined && notice.trim().length > 0) {
127
+ for (const line of notice.split(/\r?\n/)) {
128
+ lines.push(` ${line}`);
129
+ }
130
+ }
131
+ }
119
132
  }
120
133
  else {
121
134
  lines.push("- none");
@@ -159,6 +172,10 @@ export function renderGraphReport(outcome) {
159
172
  export function graphOutcomeToJson(outcome) {
160
173
  return {
161
174
  promoted: [...outcome.promoted],
175
+ promoted_notices: (outcome.promotedNotices ?? []).map((n) => ({
176
+ story_id: n.story_id,
177
+ message: n.message,
178
+ })),
162
179
  deferred_wip: [...outcome.deferredWip],
163
180
  waiting: outcome.waiting.map((w) => ({ story_id: w.story_id, unresolved: w.unresolved })),
164
181
  cycles: [...outcome.cycles],