@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
@@ -7,14 +7,25 @@
7
7
  * attempts just emitted by this verify:ac — it does not treat non-file
8
8
  * dest as no evidence.
9
9
  */
10
- import { randomUUID } from "node:crypto";
10
+ import { createHash } from "node:crypto";
11
11
  import { existsSync, readFileSync } from "node:fs";
12
12
  import { resolve } from "node:path";
13
13
  import { parseRunSummaryJsonl, RunSummaryEmitter, resolveRunSummaryDestination, } from "../run-summary/index.js";
14
14
  import { flagPassAfterFailWithMethodChange, readVerificationAttempts, unresolvedMethodChangePasses, } from "./flag.js";
15
15
  function formatUnresolved(flag) {
16
+ const delta = typeof flag.resolved_command_count_delta === "number"
17
+ ? ` command_count_delta=${flag.resolved_command_count_delta}`
18
+ : "";
16
19
  return (`check_id=${flag.check_id} fail method=${flag.failed_method} ` +
17
- `then pass method=${flag.passed_method} without independent re-derivation`);
20
+ `then pass method=${flag.passed_method} without independent re-derivation${delta}`);
21
+ }
22
+ /**
23
+ * Walk-level method fingerprint: command list + cwd hash (#3397 / #3322).
24
+ * Same shape for fail and pass so an honest product fix does not flag.
25
+ */
26
+ export function methodFingerprintForWalk(commands, cwd) {
27
+ const cwdHash = createHash("sha256").update(cwd, "utf8").digest("hex");
28
+ return `${commands.join("\0")}\0${cwdHash}`;
18
29
  }
19
30
  /** Stable prefix for product-oracle check ids emitted by verify:ac (#3322 / #3337). */
20
31
  export const VERIFY_AC_CHECK_ID_PREFIX = "verify:ac";
@@ -36,11 +47,9 @@ export function verifyAcCheckId(scopeKey) {
36
47
  }
37
48
  /** Same-process verification JSONL when dest is stdout (`-`). */
38
49
  const inProcessVerificationLines = [];
39
- let inProcessStdoutSessionId;
40
50
  /** Test seam: isolate stdout-dest buffer across cases. */
41
51
  export function resetInProcessVerificationBuffer() {
42
52
  inProcessVerificationLines.length = 0;
43
- inProcessStdoutSessionId = undefined;
44
53
  }
45
54
  function inProcessVerificationText() {
46
55
  if (inProcessVerificationLines.length === 0) {
@@ -49,7 +58,8 @@ function inProcessVerificationText() {
49
58
  return inProcessVerificationLines.join("\n");
50
59
  }
51
60
  /**
52
- * Record each executed acceptance command as a verification event (#3322).
61
+ * Record one walk-level verification event for the executed command set (#3322 / #3397).
62
+ * Fail and pass use the same method_fingerprint shape (command list + cwd hash).
53
63
  * Fail-open: missing dest / write errors never change the AC result.
54
64
  * Stdout dest also appends to the same-process buffer so evaluate can
55
65
  * inspect this invocation without re-reading a file.
@@ -63,18 +73,7 @@ export function emitVerifyAcAttempts(options) {
63
73
  const env = options.env ?? process.env;
64
74
  const projectRoot = resolve(options.projectRoot);
65
75
  const dest = resolveRunSummaryDestination(projectRoot, { env });
66
- const explicitSession = options.sessionId?.trim() ||
67
- (typeof env.DEFT_SESSION_ID === "string" ? env.DEFT_SESSION_ID.trim() : "");
68
- let sessionId = explicitSession;
69
- if (!sessionId) {
70
- if (dest.kind === "stdout") {
71
- inProcessStdoutSessionId ??= randomUUID();
72
- sessionId = inProcessStdoutSessionId;
73
- }
74
- else {
75
- sessionId = randomUUID();
76
- }
77
- }
76
+ const sessionId = options.sessionId;
78
77
  const explicitCheck = typeof options.checkId === "string" && options.checkId.trim().length > 0
79
78
  ? options.checkId.trim()
80
79
  : null;
@@ -83,17 +82,26 @@ export function emitVerifyAcAttempts(options) {
83
82
  projectRoot,
84
83
  sessionId,
85
84
  env,
85
+ component: "verify-ac",
86
86
  writeStdout: options.writeStdout,
87
87
  });
88
- for (const run of options.runs) {
89
- const emitted = emitter.emitVerification({
90
- check_id: checkId,
91
- method_fingerprint: `${run.command}\0${run.cwd}`,
92
- outcome: run.ok ? "pass" : "fail",
93
- });
94
- if (dest.kind === "stdout" && emitted.line !== null) {
95
- inProcessVerificationLines.push(JSON.stringify(emitted.line));
96
- }
88
+ // One walk-level event: the method is the command set, not each command.
89
+ // Per-command emit was blind to a shrinking list that kept the first command (#3397).
90
+ const commands = options.runs.map((run) => run.command);
91
+ const firstCwd = options.runs[0]?.cwd ?? "";
92
+ // Hash the cwd key (joined only when cwds differ) so cwd paths never enter
93
+ // the fingerprint; commandCountFromFingerprint can still count commands.
94
+ const cwdKey = options.runs.every((run) => run.cwd === firstCwd)
95
+ ? firstCwd
96
+ : options.runs.map((run) => run.cwd).join("\0");
97
+ const outcome = options.runs.every((run) => run.ok) ? "pass" : "fail";
98
+ const emitted = emitter.emitVerification({
99
+ check_id: checkId,
100
+ method_fingerprint: methodFingerprintForWalk(commands, cwdKey),
101
+ outcome,
102
+ });
103
+ if (dest.kind === "stdout" && emitted.line !== null) {
104
+ inProcessVerificationLines.push(JSON.stringify(emitted.line));
97
105
  }
98
106
  }
99
107
  catch {
@@ -20,7 +20,11 @@ export interface FlaggedMethodChangePass {
20
20
  readonly failed_method: string;
21
21
  readonly passed_method: string;
22
22
  readonly independent_rederivation: boolean;
23
+ /** Pass count minus fail count when both fingerprints carry a command list (#3397). */
24
+ readonly resolved_command_count_delta?: number;
23
25
  }
26
+ /** Command count encoded in a walk fingerprint (`cmd\0cmd\0cwd-or-hash`). */
27
+ export declare function commandCountFromFingerprint(fingerprint: string): number;
24
28
  /** Extract well-formed verification attempts in stream order. */
25
29
  export declare function readVerificationAttempts(lines: readonly RunSummaryLine[]): VerificationAttempt[];
26
30
  /**
@@ -6,6 +6,19 @@
6
6
  * In-place comparison repair then pass is unresolved.
7
7
  */
8
8
  import { parseRunSummaryJsonl } from "../run-summary/index.js";
9
+ /** Command count encoded in a walk fingerprint (`cmd\0cmd\0cwd-or-hash`). */
10
+ export function commandCountFromFingerprint(fingerprint) {
11
+ const parts = fingerprint.split("\0");
12
+ if (parts.length <= 1) {
13
+ return 1;
14
+ }
15
+ const last = parts[parts.length - 1] ?? "";
16
+ const lastIsCwdOrHash = /^[0-9a-f]{8,64}$/i.test(last) ||
17
+ last.includes("/") ||
18
+ last.includes("\\") ||
19
+ last.includes(":");
20
+ return lastIsCwdOrHash ? Math.max(1, parts.length - 1) : parts.length;
21
+ }
9
22
  function asRecord(value) {
10
23
  if (value === null || typeof value !== "object" || Array.isArray(value)) {
11
24
  return null;
@@ -74,11 +87,14 @@ export function flagPassAfterFailWithMethodChange(attempts) {
74
87
  }
75
88
  const other = [...prior].find((method) => method !== attempt.method_fingerprint);
76
89
  if (other !== undefined) {
90
+ const delta = commandCountFromFingerprint(attempt.method_fingerprint) -
91
+ commandCountFromFingerprint(other);
77
92
  flagged.push({
78
93
  check_id: attempt.check_id,
79
94
  failed_method: other,
80
95
  passed_method: attempt.method_fingerprint,
81
96
  independent_rederivation: attempt.independent_rederivation,
97
+ ...(delta !== 0 ? { resolved_command_count_delta: delta } : {}),
82
98
  });
83
99
  }
84
100
  if (attempt.independent_rederivation || other === undefined) {
@@ -5,6 +5,6 @@
5
5
  * by editing the comparison. Deterministic surface is the flagged event.
6
6
  */
7
7
  export { type AcceptanceClause, type AcceptanceClauseReading, type ClauseOutcome, type ClauseWalkReport, type ClauseWalkResult, deriveAcceptanceClauses, formatClauseWalkMessage, isScratchArtifactPath, readAcceptanceClauses, serializeAcceptanceClauses, stampDerivedClausesOnAcceptance, walkAcceptanceClauses, } from "./clauses.js";
8
- export { type EvaluateProductOracleIntegrityOptions, emitVerifyAcAttempts, evaluateProductOracleIntegrity, mergeOracleVerdict, type OracleIntegrityResultFields, type ProductOracleIntegrityVerdict, VERIFY_AC_CHECK_ID_PREFIX, verifyAcCheckId, } from "./evaluate.js";
9
- export { type FlaggedMethodChangePass, flagPassAfterFailFromJsonl, flagPassAfterFailWithMethodChange, readVerificationAttempts, unresolvedMethodChangePasses, type VerificationAttempt, } from "./flag.js";
8
+ export { type EvaluateProductOracleIntegrityOptions, emitVerifyAcAttempts, evaluateProductOracleIntegrity, mergeOracleVerdict, methodFingerprintForWalk, type OracleIntegrityResultFields, type ProductOracleIntegrityVerdict, VERIFY_AC_CHECK_ID_PREFIX, verifyAcCheckId, } from "./evaluate.js";
9
+ export { commandCountFromFingerprint, type FlaggedMethodChangePass, flagPassAfterFailFromJsonl, flagPassAfterFailWithMethodChange, readVerificationAttempts, unresolvedMethodChangePasses, type VerificationAttempt, } from "./flag.js";
10
10
  //# sourceMappingURL=index.d.ts.map
@@ -5,6 +5,6 @@
5
5
  * by editing the comparison. Deterministic surface is the flagged event.
6
6
  */
7
7
  export { deriveAcceptanceClauses, formatClauseWalkMessage, isScratchArtifactPath, readAcceptanceClauses, serializeAcceptanceClauses, stampDerivedClausesOnAcceptance, walkAcceptanceClauses, } from "./clauses.js";
8
- export { emitVerifyAcAttempts, evaluateProductOracleIntegrity, mergeOracleVerdict, VERIFY_AC_CHECK_ID_PREFIX, verifyAcCheckId, } from "./evaluate.js";
9
- export { flagPassAfterFailFromJsonl, flagPassAfterFailWithMethodChange, readVerificationAttempts, unresolvedMethodChangePasses, } from "./flag.js";
8
+ export { emitVerifyAcAttempts, evaluateProductOracleIntegrity, mergeOracleVerdict, methodFingerprintForWalk, VERIFY_AC_CHECK_ID_PREFIX, verifyAcCheckId, } from "./evaluate.js";
9
+ export { commandCountFromFingerprint, flagPassAfterFailFromJsonl, flagPassAfterFailWithMethodChange, readVerificationAttempts, unresolvedMethodChangePasses, } from "./flag.js";
10
10
  //# sourceMappingURL=index.js.map
@@ -5,10 +5,10 @@ import { type AgentHookHealthResult } from "./agent-hooks.js";
5
5
  import { type AgentHookLiveProbeResult, type AgentHookLiveProbeSeams } from "./agent-hooks-live-probe.js";
6
6
  import type { OutputStream } from "./verify-hooks-installed.js";
7
7
  export type AgentHookReadinessRegistration = "registered" | "disabled" | "missing" | "drifted" | "not-applicable";
8
- export type AgentHookReadinessFunctionality = "functional" | "non-functional" | "unavailable" | "not-run" | "disabled" | "not-applicable";
8
+ export type AgentHookReadinessFunctionality = "functional" | "non-functional" | "unavailable" | "timed-out" | "not-run" | "disabled" | "not-applicable";
9
9
  export type AgentHookReadinessTrust = "manual-review-required" | "not-applicable" | "disabled";
10
10
  export type AgentHookReadinessInterception = "not-directly-verified" | "not-applicable" | "disabled";
11
- export type AgentHookReadinessLiveStatus = "functional" | "non-functional" | "unavailable" | "not-run" | "disabled" | "skipped";
11
+ export type AgentHookReadinessLiveStatus = "functional" | "non-functional" | "unavailable" | "timed-out" | "not-run" | "disabled" | "skipped";
12
12
  export interface AgentHookReadinessHostResult {
13
13
  readonly host: HookHost;
14
14
  readonly registration: AgentHookReadinessRegistration;
@@ -1,6 +1,6 @@
1
1
  import { resolve } from "node:path";
2
2
  import { resolveFrameworkRootForProject } from "../doctor/paths.js";
3
- import { loadHostHooksPolicyFromProject } from "../policy/host-hooks.js";
3
+ import { loadHostHooksPolicyFromProject, UNUSED_HOST_HOOKS_RECOVERY, } from "../policy/host-hooks.js";
4
4
  import { evaluateAgentHooks } from "./agent-hooks.js";
5
5
  import { probeAgentHooksLive, } from "./agent-hooks-live-probe.js";
6
6
  /** Stable CLI JSON projection; keep the four readiness dimensions orthogonal. */
@@ -114,31 +114,35 @@ export function evaluateAgentHookReadiness(projectRoot, options = {}) {
114
114
  ? "functional"
115
115
  : liveStatus === "unavailable"
116
116
  ? "unavailable"
117
- : liveStatus === "non-functional"
118
- ? "non-functional"
119
- : "not-run",
117
+ : liveStatus === "timed-out"
118
+ ? "timed-out"
119
+ : liveStatus === "non-functional"
120
+ ? "non-functional"
121
+ : "not-run",
120
122
  };
121
123
  });
122
124
  const allDisabled = enabledHosts.length === 0;
125
+ const timeoutOnly = liveProbe.cases.length > 0 && liveProbe.cases.every((entry) => entry.issue === "timed-out");
123
126
  const liveStatus = allDisabled
124
127
  ? "disabled"
125
128
  : liveProbe.code === 0
126
129
  ? "functional"
127
130
  : liveProbe.code === 2
128
131
  ? "unavailable"
129
- : "non-functional";
132
+ : timeoutOnly
133
+ ? "timed-out"
134
+ : "non-functional";
130
135
  const trustReview = policy.codex
131
136
  ? "\n Codex trust: manual-review-required. Open `/hooks` and approve the exact project hook commands. " +
132
137
  "The live probe validates the shim and codec, not host interception."
133
138
  : "";
139
+ const unusedHostRecovery = liveProbe.code === 0 || timeoutOnly ? "" : `\n ${UNUSED_HOST_HOOKS_RECOVERY}`;
134
140
  return {
135
141
  code: liveProbe.code,
136
142
  message: `${liveProbe.code === 0 ? "✓" : "❌"} deft agent hook readiness: ${liveProbe.message}\n` +
137
143
  renderHosts(evaluatedHosts) +
138
144
  trustReview +
139
- (liveProbe.code === 0
140
- ? ""
141
- : "\n If an affected host is unused, inspect `deft policy:show --field=hostHooks`, set `plan.policy.hostHooks.<host> = false`, and run `deft update`."),
145
+ unusedHostRecovery,
142
146
  stream: liveProbe.code === 0 ? "stdout" : "stderr",
143
147
  skipped: false,
144
148
  liveStatus,
@@ -1,5 +1,9 @@
1
1
  import { type HookEvent, type HookHost } from "../hooks/dispatcher.js";
2
2
  export declare const LIVE_PROBE_CASE_TIMEOUT_MS = 1500;
3
+ /** Extra attempts after a timeout. One retry keeps 4×2×1.5s×2 = 24s under Cursor 30s (#3570). */
4
+ export declare const LIVE_PROBE_CASE_RETRY_COUNT = 1;
5
+ export declare const LIVE_PROBE_TIMEOUT_RECOVERY = "Recovery: retry the gated ritual when load is lower. Do not reinstall @deftai/directive or disable hostHooks for a timeout.";
6
+ export declare const LIVE_PROBE_BROKEN_RECOVERY = "Recovery: reinstall @deftai/directive and run `deft update`.";
3
7
  export type AgentHookLiveProbeIssue = "hook-command-missing" | "spawn-failed" | "timed-out" | "empty-stdout" | "unparseable-json" | "missing-allow" | "missing-deny";
4
8
  export interface AgentHookLiveProbeCase {
5
9
  readonly host: HookHost;
@@ -8,7 +12,7 @@ export interface AgentHookLiveProbeCase {
8
12
  readonly issue: AgentHookLiveProbeIssue;
9
13
  readonly detail: string;
10
14
  }
11
- export type AgentHookLiveProbeHostStatus = "functional" | "non-functional" | "unavailable";
15
+ export type AgentHookLiveProbeHostStatus = "functional" | "non-functional" | "unavailable" | "timed-out";
12
16
  export interface AgentHookLiveProbeHostResult {
13
17
  readonly host: HookHost;
14
18
  readonly status: AgentHookLiveProbeHostStatus;
@@ -6,6 +6,10 @@ import { DEFT_HOOK_COMMAND_MARKER } from "../init-deposit/agent-hooks.js";
6
6
  import { SUBPROCESS_MAX_BUFFER } from "../subprocess/max-buffer.js";
7
7
  import { quoteWin32CommandForShell, resolveCommandOnPath, shouldUseShellForCommand, } from "./command-spawn.js";
8
8
  export const LIVE_PROBE_CASE_TIMEOUT_MS = 1_500;
9
+ /** Extra attempts after a timeout. One retry keeps 4×2×1.5s×2 = 24s under Cursor 30s (#3570). */
10
+ export const LIVE_PROBE_CASE_RETRY_COUNT = 1;
11
+ export const LIVE_PROBE_TIMEOUT_RECOVERY = "Recovery: retry the gated ritual when load is lower. Do not reinstall @deftai/directive or disable hostHooks for a timeout.";
12
+ export const LIVE_PROBE_BROKEN_RECOVERY = "Recovery: reinstall @deftai/directive and run `deft update`.";
9
13
  const LIVE_PROBE_EVENT = "tool.before";
10
14
  function elapsedMs(started) {
11
15
  return Math.max(0, Math.round(performance.now() - started));
@@ -122,21 +126,38 @@ function validateFixtureOutput(host, fixture, stdout) {
122
126
  ? { ok: true }
123
127
  : { ok: false, issue: "missing-deny", detail: `expected ${host} deny envelope` };
124
128
  }
129
+ function liveProbeRecovery(cases) {
130
+ if (cases.length > 0 && cases.every((entry) => entry.issue === "timed-out")) {
131
+ return LIVE_PROBE_TIMEOUT_RECOVERY;
132
+ }
133
+ return LIVE_PROBE_BROKEN_RECOVERY;
134
+ }
135
+ function hostStatusFromFailure(hostFailure) {
136
+ if (hostFailure === null)
137
+ return "functional";
138
+ if (hostFailure.issue === "timed-out")
139
+ return "timed-out";
140
+ return "non-functional";
141
+ }
125
142
  function runFixtureProbe(command, host, projectRoot, fixture, spawnHook) {
126
- const spawned = spawnHook({
143
+ const input = {
127
144
  command,
128
145
  args: ["--host", host, "--event", LIVE_PROBE_EVENT, "--project-root", projectRoot],
129
146
  stdin: fixture === "allow" ? allowFixture(projectRoot) : denyFixture(projectRoot),
130
147
  cwd: projectRoot,
131
148
  env: fixture === "allow" ? process.env : denyProbeEnv(),
132
- });
149
+ };
150
+ let spawned = spawnHook(input);
151
+ for (let retry = 0; retry < LIVE_PROBE_CASE_RETRY_COUNT && spawned.timedOut === true; retry += 1) {
152
+ spawned = spawnHook(input);
153
+ }
133
154
  if (spawned.timedOut === true) {
134
155
  return {
135
156
  host,
136
157
  event: LIVE_PROBE_EVENT,
137
158
  fixture,
138
159
  issue: "timed-out",
139
- detail: `hook command exceeded ${LIVE_PROBE_CASE_TIMEOUT_MS}ms`,
160
+ detail: `hook command exceeded ${LIVE_PROBE_CASE_TIMEOUT_MS}ms after ${LIVE_PROBE_CASE_RETRY_COUNT + 1} attempts`,
140
161
  };
141
162
  }
142
163
  if (spawned.status !== 0) {
@@ -204,7 +225,7 @@ export function probeAgentHooksLive(projectRoot, seams = {}) {
204
225
  break;
205
226
  }
206
227
  }
207
- hostResults.push({ host, status: hostFailure === null ? "functional" : "non-functional" });
228
+ hostResults.push({ host, status: hostStatusFromFailure(hostFailure) });
208
229
  }
209
230
  if (failures.length === 0) {
210
231
  return {
@@ -220,7 +241,7 @@ export function probeAgentHooksLive(projectRoot, seams = {}) {
220
241
  .join("; ");
221
242
  return {
222
243
  code: 1,
223
- message: `deft agent hooks live probe FAILED: ${summary}. Recovery: reinstall @deftai/directive and run \`deft update\`.`,
244
+ message: `deft agent hooks live probe FAILED: ${summary}. ${liveProbeRecovery(failures)}`,
224
245
  cases: failures,
225
246
  hosts: hostResults,
226
247
  durationMs: elapsedMs(started),
@@ -1,7 +1,7 @@
1
1
  import { statSync } from "node:fs";
2
2
  import { resolve } from "node:path";
3
3
  import { inspectAgentHookDeposit } from "../init-deposit/agent-hooks.js";
4
- import { loadHostHooksPolicyFromProject } from "../policy/host-hooks.js";
4
+ import { loadHostHooksPolicyFromProject, UNUSED_HOST_HOOKS_RECOVERY, } from "../policy/host-hooks.js";
5
5
  function isDirectory(path) {
6
6
  try {
7
7
  return statSync(path).isDirectory();
@@ -30,9 +30,8 @@ export function evaluateAgentHooks(projectRoot, hostHooksPolicy = loadHostHooksP
30
30
  unhealthy
31
31
  .map((entry) => ` - ${entry.host}: ${entry.status} at ${entry.path} — ${entry.detail}`)
32
32
  .join("\n") +
33
- "\n Recovery: run `deft update` (or `directive init`) to refresh project hooks." +
34
- " If a failed host is intentionally unused, inspect `deft policy:show --field=hostHooks`, " +
35
- "set `plan.policy.hostHooks.<host> = false`, and run `deft update` again.",
33
+ "\n Recovery: run `deft update` (or `directive init`) to refresh project hooks. " +
34
+ UNUSED_HOST_HOOKS_RECOVERY,
36
35
  stream: "stderr",
37
36
  registrations,
38
37
  };
@@ -46,6 +46,8 @@ export const CONTAINED_WRITES_ALLOWLIST = [
46
46
  // Implementation modules for containment + contained write.
47
47
  "packages/core/src/fs/contained-write.ts",
48
48
  "packages/core/src/fs/projection-containment.ts",
49
+ // #3424: read-only O_NOFOLLOW fd pin in intended-placement inspect (not a write sink).
50
+ "packages/core/src/preflight/intended-placement.ts",
49
51
  // Deposit tree copy / contain primitives (low-level install sinks).
50
52
  "packages/core/src/deposit/copy-tree.ts",
51
53
  "packages/core/src/deposit/contain.ts",
@@ -1,3 +1,8 @@
1
+ /**
2
+ * Shared "not product source" core (#3487) plus the directories only the stub
3
+ * scan treats as non-product: fixtures/tests, vendored trees, the history
4
+ * archive, and operator scripts.
5
+ */
1
6
  export declare const EXCLUDE_DIRS: Set<string>;
2
7
  export declare const EXTENSIONS: Set<string>;
3
8
  export interface StubFinding {
@@ -6,7 +11,16 @@ export interface StubFinding {
6
11
  readonly label: string;
7
12
  readonly text: string;
8
13
  }
9
- /** Recursive sorted rglob mirroring `sorted(Path(".").rglob("*"))`. */
14
+ /**
15
+ * Recursive sorted rglob mirroring `sorted(Path(".").rglob("*"))`, pruning
16
+ * `EXCLUDE_DIRS` before recursing.
17
+ *
18
+ * Pruning is load-bearing, not an optimisation of a filter applied later: on a
19
+ * host with a populated `.deft-scratch/` the unpruned walk enumerates every
20
+ * swarm worktree (millions of entries) only to discard them per-file. #2953
21
+ * added `.deft-scratch` / `swarm-worktrees` to `EXCLUDE_DIRS` for exactly this
22
+ * reason but left the walk descending into them (#3481).
23
+ */
10
24
  export declare function sortedRglob(root: string): string[];
11
25
  export declare function scanFileForStubs(relPath: string, fullPath: string): StubFinding[];
12
26
  export interface VerifyStubsResult {
@@ -1,20 +1,12 @@
1
1
  import { readdirSync, readFileSync, statSync } from "node:fs";
2
2
  import { join, resolve } from "node:path";
3
- export const EXCLUDE_DIRS = new Set([
4
- "tests",
5
- "vendor",
6
- ".git",
7
- "backup",
8
- "history",
9
- "node_modules",
10
- ".venv",
11
- "__pycache__",
12
- "dist",
13
- "scripts",
14
- // Swarm / agent worktrees are not product source (#2953, #1656).
15
- ".deft-scratch",
16
- "swarm-worktrees",
17
- ]);
3
+ import { NON_PRODUCT_DIRS } from "../fs/non-product-dirs.js";
4
+ /**
5
+ * Shared "not product source" core (#3487) plus the directories only the stub
6
+ * scan treats as non-product: fixtures/tests, vendored trees, the history
7
+ * archive, and operator scripts.
8
+ */
9
+ export const EXCLUDE_DIRS = new Set([...NON_PRODUCT_DIRS, "tests", "vendor", "history", "scripts"]);
18
10
  export const EXTENSIONS = new Set([".py", ".go", ".sh"]);
19
11
  function isWordChar(ch) {
20
12
  if (ch.length === 0) {
@@ -73,7 +65,16 @@ function hasReturnNull(text) {
73
65
  }
74
66
  return false;
75
67
  }
76
- /** Recursive sorted rglob mirroring `sorted(Path(".").rglob("*"))`. */
68
+ /**
69
+ * Recursive sorted rglob mirroring `sorted(Path(".").rglob("*"))`, pruning
70
+ * `EXCLUDE_DIRS` before recursing.
71
+ *
72
+ * Pruning is load-bearing, not an optimisation of a filter applied later: on a
73
+ * host with a populated `.deft-scratch/` the unpruned walk enumerates every
74
+ * swarm worktree (millions of entries) only to discard them per-file. #2953
75
+ * added `.deft-scratch` / `swarm-worktrees` to `EXCLUDE_DIRS` for exactly this
76
+ * reason but left the walk descending into them (#3481).
77
+ */
77
78
  export function sortedRglob(root) {
78
79
  const out = [];
79
80
  function walk(dir, relPrefix) {
@@ -95,6 +96,9 @@ export function sortedRglob(root) {
95
96
  continue;
96
97
  }
97
98
  if (st.isDirectory()) {
99
+ if (EXCLUDE_DIRS.has(name)) {
100
+ continue;
101
+ }
98
102
  walk(full, rel);
99
103
  }
100
104
  else {
@@ -3,18 +3,17 @@ export declare const COVERAGE_TMP_CHUNK_RE: RegExp;
3
3
  export declare function isCoverageTmpChunkPath(filePath: string): boolean;
4
4
  export declare function ensureCoverageTmpDir(coverageTmpDir?: string): void;
5
5
  /**
6
- * Vitest 3.2.x writes coverage chunks without mkdir'ing the parent directory
7
- * (fixed upstream in vitest 4.x — vitest-dev/vitest#10117). On Windows the
8
- * directory can disappear between clean() and writeFile under release-scale
6
+ * Vitest 4.x includes the upstream mkdir (vitest-dev/vitest#10117). On Windows the
7
+ * directory can still disappear between clean() and writeFile under release-scale
9
8
  * load; mkdir immediately before chunk writes closes that race without
10
- * soft-failing real threshold failures (#2634).
9
+ * soft-failing real threshold failures (#2634 / #3480).
11
10
  */
12
11
  export declare function installCoverageTmpWriteGuard(): () => void;
13
12
  /**
14
13
  * Win32 globalSetup for coverage runs (#2580, hardened #2634).
15
14
  *
16
- * Keepalive mkdir plus a writeFile guard mirror vitest 4's defensive mkdir until
17
- * directive upgrades past vitest@3 (see vitest.config.ts #2634 upgrade note).
15
+ * Keepalive mkdir plus a writeFile guard remain until a full win32 coverage
16
+ * run proves vitest 4's #10117 mkdir is enough on its own (#3480).
18
17
  */
19
18
  export default function setup(): () => void;
20
19
  //# sourceMappingURL=win32-coverage-tmp-setup.d.ts.map
@@ -10,11 +10,10 @@ export function ensureCoverageTmpDir(coverageTmpDir = defaultCoverageTmp) {
10
10
  mkdirSync(coverageTmpDir, { recursive: true });
11
11
  }
12
12
  /**
13
- * Vitest 3.2.x writes coverage chunks without mkdir'ing the parent directory
14
- * (fixed upstream in vitest 4.x — vitest-dev/vitest#10117). On Windows the
15
- * directory can disappear between clean() and writeFile under release-scale
13
+ * Vitest 4.x includes the upstream mkdir (vitest-dev/vitest#10117). On Windows the
14
+ * directory can still disappear between clean() and writeFile under release-scale
16
15
  * load; mkdir immediately before chunk writes closes that race without
17
- * soft-failing real threshold failures (#2634).
16
+ * soft-failing real threshold failures (#2634 / #3480).
18
17
  */
19
18
  export function installCoverageTmpWriteGuard() {
20
19
  const originalWriteFile = fsPromises.writeFile.bind(fsPromises);
@@ -33,8 +32,8 @@ export function installCoverageTmpWriteGuard() {
33
32
  /**
34
33
  * Win32 globalSetup for coverage runs (#2580, hardened #2634).
35
34
  *
36
- * Keepalive mkdir plus a writeFile guard mirror vitest 4's defensive mkdir until
37
- * directive upgrades past vitest@3 (see vitest.config.ts #2634 upgrade note).
35
+ * Keepalive mkdir plus a writeFile guard remain until a full win32 coverage
36
+ * run proves vitest 4's #10117 mkdir is enough on its own (#3480).
38
37
  */
39
38
  export default function setup() {
40
39
  if (process.platform !== "win32")
@@ -1,6 +1,6 @@
1
1
  import { cpSync, existsSync, mkdirSync, readdirSync, readFileSync, rmSync } from "node:fs";
2
2
  import { join, relative, resolve } from "node:path";
3
- import { containedWrite } from "../fs/contained-write.js";
3
+ import { containedRemove, containedWrite } from "../fs/contained-write.js";
4
4
  import { assertWriteTargetSafe, ProjectionContainmentError } from "../fs/projection-containment.js";
5
5
  import { checkGitClean } from "../migrate-preflight/index.js";
6
6
  import { applyAgentsRefresh } from "../platform/agents-md.js";
@@ -36,10 +36,7 @@ export function shouldOmitLegacyMigrationFile(relativePath) {
36
36
  */
37
37
  export function removeStaleMigratedFrameworkNarrative(projectRoot) {
38
38
  const stale = join(projectRoot, MIGRATED_ARTIFACT_DIR, OBSOLETE_FRAMEWORK_NARRATIVE_FILENAME);
39
- if (!existsSync(stale))
40
- return false;
41
- rmSync(stale, { force: true });
42
- return true;
39
+ return containedRemove({ root: projectRoot, target: stale }).removed;
43
40
  }
44
41
  function mapRelativePath(relativePath) {
45
42
  return relativePath
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deftai/directive-core",
3
- "version": "0.104.0",
3
+ "version": "0.106.0",
4
4
  "description": "TypeScript engine core for the Directive framework.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -283,6 +283,10 @@
283
283
  "types": "./dist/lifecycle/index.d.ts",
284
284
  "default": "./dist/lifecycle/index.js"
285
285
  },
286
+ "./lifecycle-visible": {
287
+ "types": "./dist/lifecycle-visible/index.d.ts",
288
+ "default": "./dist/lifecycle-visible/index.js"
289
+ },
286
290
  "./literal-acceptance": {
287
291
  "types": "./dist/literal-acceptance/index.d.ts",
288
292
  "default": "./dist/literal-acceptance/index.js"
@@ -382,8 +386,8 @@
382
386
  "provenance": true
383
387
  },
384
388
  "dependencies": {
385
- "@deftai/directive-content": "^0.104.0",
386
- "@deftai/directive-types": "^0.104.0",
389
+ "@deftai/directive-content": "^0.106.0",
390
+ "@deftai/directive-types": "^0.106.0",
387
391
  "archiver": "^8.0.0"
388
392
  },
389
393
  "scripts": {