@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
@@ -15,7 +15,20 @@
15
15
  * onto this API over bespoke per-sink checks when equivalent. See
16
16
  * `docs/reference/contained-write.md`.
17
17
  *
18
- * Refs #2951.
18
+ * Delete coverage (#3392 / #3456): real dest deletes MUST go through
19
+ * {@link containedRemove} so a bound ledger (and ADR-004 record mode) records
20
+ * them. Raw `rmSync` on a dest path is a chokepoint bypass.
21
+ *
22
+ * Plan-mode zero-mutation (#3456 / ADR-004): `deft update --dry-run` binds
23
+ * this port in record mode (`runInPortRecordMode`). Dest write / remove /
24
+ * chmod / dest-mutating exec record and skip dest IO. Temp-file cleanups
25
+ * either use this chokepoint or live outside the project root.
26
+ *
27
+ * `tryCleanupLegacyDeftTree` is not on the update/dry-run path (classify
28
+ * refuses `migration-required` first). Its default removeDir still routes
29
+ * through containedRemove so the site is not a silent exception.
30
+ *
31
+ * Refs #2951 / #3392 / #3456.
19
32
  */
20
33
  /** Stable machine-readable error codes for contained-write refusals. */
21
34
  export declare const ContainedWriteErrorCode: {
@@ -78,6 +91,38 @@ export interface ContainedWriteInput {
78
91
  * {@link assertWriteTargetSafe}.
79
92
  */
80
93
  readonly followSymlinks?: boolean;
94
+ /**
95
+ * Ledger side-effect (#3392). Default records `wrote` when a ledger is bound.
96
+ * `false` skips. `kind`/`path` override the recorded entry (atomic tmp+rename).
97
+ */
98
+ readonly mutation?: false | {
99
+ readonly kind?: "wrote" | "stripped";
100
+ readonly path?: string;
101
+ };
102
+ }
103
+ export interface ContainedRemoveInput {
104
+ /** Absolute containment root (project root, deposit root, or sandbox). */
105
+ readonly root: string;
106
+ /**
107
+ * Remove target. Relative paths are resolved under `root`. Absolute paths
108
+ * must stay under `root` after normalization.
109
+ */
110
+ readonly target: string;
111
+ /**
112
+ * Ledger side-effect (#3392). Default records `deleted` when a ledger is bound.
113
+ * `false` skips. `path` overrides the recorded path.
114
+ */
115
+ readonly mutation?: false | {
116
+ readonly path?: string;
117
+ };
118
+ /** When true, remove directories recursively. Default `false`. */
119
+ readonly recursive?: boolean;
120
+ }
121
+ export interface ContainedRemoveResult {
122
+ /** Absolute path considered for removal. */
123
+ readonly path: string;
124
+ /** True when a file existed and was removed. */
125
+ readonly removed: boolean;
81
126
  }
82
127
  export interface ContainedWriteResult {
83
128
  /** Absolute path written. */
@@ -86,6 +131,37 @@ export interface ContainedWriteResult {
86
131
  readonly bytesWritten: number;
87
132
  readonly mode: ContainedWriteMode;
88
133
  }
134
+ export interface ContainedChmodInput {
135
+ readonly root: string;
136
+ readonly target: string;
137
+ readonly mode: number;
138
+ readonly mutation?: false | {
139
+ readonly path?: string;
140
+ };
141
+ }
142
+ export interface ContainedRenameInput {
143
+ readonly root: string;
144
+ readonly from: string;
145
+ readonly to: string;
146
+ /**
147
+ * Default records `wrote` on `to`. `false` skips (caller already ledgered).
148
+ */
149
+ readonly mutation?: false | {
150
+ readonly kind?: "wrote" | "stripped";
151
+ readonly path?: string;
152
+ };
153
+ }
154
+ export interface ContainedDestExecInput {
155
+ readonly root: string;
156
+ /** Dest path this exec mutates (e.g. `.git/config`). */
157
+ readonly destTarget: string;
158
+ readonly file: string;
159
+ readonly args: readonly string[];
160
+ }
161
+ export interface ContainedDestExecResult {
162
+ readonly ok: boolean;
163
+ readonly stdout: string;
164
+ }
89
165
  /**
90
166
  * Resolve `target` under `root`. Relative targets join root; absolute targets
91
167
  * must already be nested under root (path-segment containment).
@@ -98,4 +174,42 @@ export declare function resolveContainedTarget(root: string, target: string): st
98
174
  * @throws {ContainedWriteError} on containment refusal or mode violation
99
175
  */
100
176
  export declare function containedWrite(input: ContainedWriteInput): ContainedWriteResult;
177
+ /**
178
+ * Contained remove: resolve under root, refuse parent-path symlink / out-of-root,
179
+ * then delete. An in-root leaf symlink is unlinked (not followed, not refused).
180
+ * Missing targets are a no-op (not ledgered).
181
+ *
182
+ * @throws {ContainedWriteError} on containment refusal
183
+ */
184
+ export declare function containedRemove(input: ContainedRemoveInput): ContainedRemoveResult;
185
+ /**
186
+ * Contained mkdir: nest under root. Record mode skips dest IO (dirs are not
187
+ * dest-file membership). Live path creates recursively.
188
+ */
189
+ export declare function containedMkdir(input: {
190
+ readonly root: string;
191
+ readonly target: string;
192
+ }): {
193
+ path: string;
194
+ };
195
+ /**
196
+ * Contained chmod: resolve under root, refuse parent-path symlink / out-of-root,
197
+ * then set mode. Record mode records `chmod` and skips dest IO.
198
+ */
199
+ export declare function containedChmod(input: ContainedChmodInput): {
200
+ path: string;
201
+ };
202
+ /**
203
+ * Contained rename: both paths must nest under root. Record mode records
204
+ * `wrote` on `to` (unless `mutation: false`) and skips dest IO.
205
+ */
206
+ export declare function containedRename(input: ContainedRenameInput): {
207
+ from: string;
208
+ to: string;
209
+ };
210
+ /**
211
+ * Dest-mutating exec (git config, git add, …). Record mode records `exec` on
212
+ * `destTarget` and skips the child process. Allowlisted as the port impl.
213
+ */
214
+ export declare function containedDestExec(input: ContainedDestExecInput): ContainedDestExecResult;
101
215
  //# sourceMappingURL=contained-write.d.ts.map
@@ -15,10 +15,25 @@
15
15
  * onto this API over bespoke per-sink checks when equivalent. See
16
16
  * `docs/reference/contained-write.md`.
17
17
  *
18
- * Refs #2951.
18
+ * Delete coverage (#3392 / #3456): real dest deletes MUST go through
19
+ * {@link containedRemove} so a bound ledger (and ADR-004 record mode) records
20
+ * them. Raw `rmSync` on a dest path is a chokepoint bypass.
21
+ *
22
+ * Plan-mode zero-mutation (#3456 / ADR-004): `deft update --dry-run` binds
23
+ * this port in record mode (`runInPortRecordMode`). Dest write / remove /
24
+ * chmod / dest-mutating exec record and skip dest IO. Temp-file cleanups
25
+ * either use this chokepoint or live outside the project root.
26
+ *
27
+ * `tryCleanupLegacyDeftTree` is not on the update/dry-run path (classify
28
+ * refuses `migration-required` first). Its default removeDir still routes
29
+ * through containedRemove so the site is not a silent exception.
30
+ *
31
+ * Refs #2951 / #3392 / #3456.
19
32
  */
20
- import { closeSync, constants, existsSync, fsyncSync, lstatSync, mkdirSync, openSync, realpathSync, writeSync, } from "node:fs";
21
- import { dirname, isAbsolute, relative, resolve } from "node:path";
33
+ import { execFileSync } from "node:child_process";
34
+ import { chmodSync, closeSync, constants, existsSync, fsyncSync, lstatSync, mkdirSync, openSync, realpathSync, renameSync, rmSync, unlinkSync, writeSync, } from "node:fs";
35
+ import { dirname, isAbsolute, join, relative, resolve } from "node:path";
36
+ import { isAtomicWriteTemp, isPortRecordMode, recordActiveMutation, } from "./mutation-ledger.js";
22
37
  import { assertWriteTargetSafe, ProjectionContainmentError } from "./projection-containment.js";
23
38
  /** Stable machine-readable error codes for contained-write refusals. */
24
39
  export const ContainedWriteErrorCode = {
@@ -133,6 +148,68 @@ function ensureParents(rootAbs, targetAbs) {
133
148
  function toBuffer(data, encoding) {
134
149
  return Buffer.isBuffer(data) ? data : Buffer.from(data, encoding);
135
150
  }
151
+ /**
152
+ * Remove resolver: lexical nest + refuse parent-path symlinks. The leaf may be
153
+ * a symlink — unlink the link itself (never follow, never abort).
154
+ */
155
+ function resolveExistingRootForRemove(root, target) {
156
+ const rootAbs = resolve(root);
157
+ try {
158
+ realpathSync(rootAbs);
159
+ }
160
+ catch {
161
+ throw new ContainedWriteError(`contained write refused: root ${rootAbs} does not exist`, {
162
+ code: ContainedWriteErrorCode.ROOT_MISSING,
163
+ root: rootAbs,
164
+ target: String(target),
165
+ offendingPath: rootAbs,
166
+ });
167
+ }
168
+ const targetAbs = resolveContainedTarget(rootAbs, target);
169
+ const parentAbs = dirname(targetAbs);
170
+ if (parentAbs !== rootAbs && parentAbs !== targetAbs) {
171
+ const rel = relative(rootAbs, parentAbs);
172
+ if (rel.length > 0 && !rel.startsWith("..") && !isAbsolute(rel)) {
173
+ let current = rootAbs;
174
+ for (const segment of rel.split(/[\\/]+/).filter((part) => part.length > 0)) {
175
+ current = join(current, segment);
176
+ let info;
177
+ try {
178
+ info = lstatSync(current);
179
+ }
180
+ catch {
181
+ break;
182
+ }
183
+ if (info.isSymbolicLink()) {
184
+ throw new ContainedWriteError(`contained write refused: ${current} is a symlink on the remove parent path`, {
185
+ code: ContainedWriteErrorCode.SYMLINK,
186
+ root: rootAbs,
187
+ target: targetAbs,
188
+ offendingPath: current,
189
+ });
190
+ }
191
+ }
192
+ }
193
+ }
194
+ return { rootAbs, targetAbs };
195
+ }
196
+ function recordWriteMutation(targetAbs, mutation) {
197
+ if (mutation === false)
198
+ return;
199
+ const kind = mutation?.kind ?? "wrote";
200
+ const path = mutation?.path ?? targetAbs;
201
+ if (mutation?.path === undefined && isAtomicWriteTemp(path))
202
+ return;
203
+ recordActiveMutation(kind, path);
204
+ }
205
+ function recordRemoveMutation(targetAbs, mutation) {
206
+ if (mutation === false)
207
+ return;
208
+ const path = mutation?.path ?? targetAbs;
209
+ if (mutation?.path === undefined && isAtomicWriteTemp(path))
210
+ return;
211
+ recordActiveMutation("deleted", path);
212
+ }
136
213
  function writeNoFollow(targetAbs, buf, flags) {
137
214
  const fd = openSync(targetAbs, flags, 0o644);
138
215
  try {
@@ -194,6 +271,27 @@ export function containedWrite(input) {
194
271
  }
195
272
  throw err;
196
273
  }
274
+ const encoding = input.encoding ?? "utf8";
275
+ const buf = toBuffer(input.data, encoding);
276
+ if (isPortRecordMode()) {
277
+ if (input.mode === "create") {
278
+ try {
279
+ lstatSync(targetAbs);
280
+ throw new ContainedWriteError(`contained write refused: target ${targetAbs} already exists (mode=create)`, {
281
+ code: ContainedWriteErrorCode.EXISTS,
282
+ root: rootAbs,
283
+ target: targetAbs,
284
+ offendingPath: targetAbs,
285
+ });
286
+ }
287
+ catch (err) {
288
+ if (err instanceof ContainedWriteError)
289
+ throw err;
290
+ }
291
+ }
292
+ recordWriteMutation(targetAbs, input.mutation);
293
+ return { path: targetAbs, bytesWritten: buf.length, mode: input.mode };
294
+ }
197
295
  const doMkdir = input.mkdir !== false;
198
296
  if (doMkdir) {
199
297
  ensureParents(rootAbs, targetAbs);
@@ -208,8 +306,6 @@ export function containedWrite(input) {
208
306
  }
209
307
  throw err;
210
308
  }
211
- const encoding = input.encoding ?? "utf8";
212
- const buf = toBuffer(input.data, encoding);
213
309
  let exists = false;
214
310
  try {
215
311
  lstatSync(targetAbs);
@@ -239,6 +335,7 @@ export function containedWrite(input) {
239
335
  // replace
240
336
  bytesWritten = writeNoFollow(targetAbs, buf, constants.O_WRONLY | constants.O_CREAT | constants.O_TRUNC | constants.O_NOFOLLOW);
241
337
  }
338
+ recordWriteMutation(targetAbs, input.mutation);
242
339
  return { path: targetAbs, bytesWritten, mode: input.mode };
243
340
  }
244
341
  catch (err) {
@@ -279,4 +376,143 @@ export function containedWrite(input) {
279
376
  });
280
377
  }
281
378
  }
379
+ /**
380
+ * Contained remove: resolve under root, refuse parent-path symlink / out-of-root,
381
+ * then delete. An in-root leaf symlink is unlinked (not followed, not refused).
382
+ * Missing targets are a no-op (not ledgered).
383
+ *
384
+ * @throws {ContainedWriteError} on containment refusal
385
+ */
386
+ export function containedRemove(input) {
387
+ const { rootAbs, targetAbs } = resolveExistingRootForRemove(input.root, input.target);
388
+ let info;
389
+ try {
390
+ info = lstatSync(targetAbs);
391
+ }
392
+ catch (err) {
393
+ const code = typeof err === "object" && err !== null && "code" in err
394
+ ? err.code
395
+ : undefined;
396
+ if (code === "ENOENT") {
397
+ return { path: targetAbs, removed: false };
398
+ }
399
+ const msg = err instanceof Error ? err.message : String(err);
400
+ throw new ContainedWriteError(`contained write I/O failed: ${msg}`, {
401
+ code: ContainedWriteErrorCode.IO,
402
+ root: rootAbs,
403
+ target: targetAbs,
404
+ offendingPath: targetAbs,
405
+ });
406
+ }
407
+ if (isPortRecordMode()) {
408
+ recordRemoveMutation(targetAbs, input.mutation);
409
+ return { path: targetAbs, removed: true };
410
+ }
411
+ try {
412
+ if (info.isSymbolicLink()) {
413
+ unlinkSync(targetAbs);
414
+ }
415
+ else {
416
+ rmSync(targetAbs, { force: true, recursive: input.recursive === true });
417
+ }
418
+ }
419
+ catch (err) {
420
+ const msg = err instanceof Error ? err.message : String(err);
421
+ throw new ContainedWriteError(`contained write I/O failed: ${msg}`, {
422
+ code: ContainedWriteErrorCode.IO,
423
+ root: rootAbs,
424
+ target: targetAbs,
425
+ offendingPath: targetAbs,
426
+ });
427
+ }
428
+ recordRemoveMutation(targetAbs, input.mutation);
429
+ return { path: targetAbs, removed: true };
430
+ }
431
+ /**
432
+ * Contained mkdir: nest under root. Record mode skips dest IO (dirs are not
433
+ * dest-file membership). Live path creates recursively.
434
+ */
435
+ export function containedMkdir(input) {
436
+ const targetAbs = resolveContainedTarget(input.root, input.target);
437
+ if (isPortRecordMode()) {
438
+ return { path: targetAbs };
439
+ }
440
+ mkdirSync(targetAbs, { recursive: true });
441
+ return { path: targetAbs };
442
+ }
443
+ /**
444
+ * Contained chmod: resolve under root, refuse parent-path symlink / out-of-root,
445
+ * then set mode. Record mode records `chmod` and skips dest IO.
446
+ */
447
+ export function containedChmod(input) {
448
+ const { rootAbs, targetAbs } = resolveExistingRootForRemove(input.root, input.target);
449
+ if (input.mutation !== false) {
450
+ recordActiveMutation("chmod", input.mutation?.path ?? targetAbs);
451
+ }
452
+ if (isPortRecordMode()) {
453
+ return { path: targetAbs };
454
+ }
455
+ try {
456
+ chmodSync(targetAbs, input.mode);
457
+ }
458
+ catch (err) {
459
+ const msg = err instanceof Error ? err.message : String(err);
460
+ throw new ContainedWriteError(`contained write I/O failed: ${msg}`, {
461
+ code: ContainedWriteErrorCode.IO,
462
+ root: rootAbs,
463
+ target: targetAbs,
464
+ offendingPath: targetAbs,
465
+ });
466
+ }
467
+ return { path: targetAbs };
468
+ }
469
+ /**
470
+ * Contained rename: both paths must nest under root. Record mode records
471
+ * `wrote` on `to` (unless `mutation: false`) and skips dest IO.
472
+ */
473
+ export function containedRename(input) {
474
+ const fromAbs = resolveContainedTarget(input.root, input.from);
475
+ const toAbs = resolveContainedTarget(input.root, input.to);
476
+ if (input.mutation !== false) {
477
+ const kind = input.mutation?.kind ?? "wrote";
478
+ recordActiveMutation(kind, input.mutation?.path ?? toAbs);
479
+ }
480
+ if (isPortRecordMode()) {
481
+ return { from: fromAbs, to: toAbs };
482
+ }
483
+ try {
484
+ renameSync(fromAbs, toAbs);
485
+ }
486
+ catch (err) {
487
+ const msg = err instanceof Error ? err.message : String(err);
488
+ throw new ContainedWriteError(`contained write I/O failed: ${msg}`, {
489
+ code: ContainedWriteErrorCode.IO,
490
+ root: resolve(input.root),
491
+ target: toAbs,
492
+ offendingPath: toAbs,
493
+ });
494
+ }
495
+ return { from: fromAbs, to: toAbs };
496
+ }
497
+ /**
498
+ * Dest-mutating exec (git config, git add, …). Record mode records `exec` on
499
+ * `destTarget` and skips the child process. Allowlisted as the port impl.
500
+ */
501
+ export function containedDestExec(input) {
502
+ const targetAbs = resolveContainedTarget(input.root, input.destTarget);
503
+ recordActiveMutation("exec", targetAbs);
504
+ if (isPortRecordMode()) {
505
+ return { ok: true, stdout: "" };
506
+ }
507
+ try {
508
+ const stdout = execFileSync(input.file, [...input.args], {
509
+ encoding: "utf8",
510
+ cwd: resolve(input.root),
511
+ });
512
+ return { ok: true, stdout };
513
+ }
514
+ catch {
515
+ return { ok: false, stdout: "" };
516
+ }
517
+ }
282
518
  //# sourceMappingURL=contained-write.js.map
@@ -0,0 +1,54 @@
1
+ /**
2
+ * mutation-ledger.ts — typed deposit mutation log at the write chokepoint (#3392).
3
+ *
4
+ * A bound ledger records wrote / stripped / deleted as a side effect of
5
+ * containedWrite / containedRemove. Callers cannot discard mutations by
6
+ * ignoring a writer return value.
7
+ *
8
+ * Refs #3392 / #3378.
9
+ */
10
+ export declare const MUTATION_KINDS: readonly ["wrote", "stripped", "deleted", "chmod", "exec"];
11
+ export type MutationKind = (typeof MUTATION_KINDS)[number];
12
+ export interface MutationEntry {
13
+ readonly kind: MutationKind;
14
+ readonly path: string;
15
+ }
16
+ export interface MutationSummary {
17
+ readonly wrote: readonly string[];
18
+ readonly stripped: readonly string[];
19
+ readonly deleted: readonly string[];
20
+ readonly chmod: readonly string[];
21
+ readonly exec: readonly string[];
22
+ readonly mutations: readonly MutationEntry[];
23
+ }
24
+ export declare function isAtomicWriteTemp(path: string): boolean;
25
+ /** Posix-relative path under `root`, or empty when the target is not nested. */
26
+ export declare function toLedgerPath(root: string, target: string): string;
27
+ export declare function emptyMutationSummary(): MutationSummary;
28
+ /** In-memory ledger for one deposit/refresh run. */
29
+ export declare class MutationLedger {
30
+ readonly root: string;
31
+ private readonly recorded;
32
+ constructor(root: string);
33
+ record(kind: MutationKind, target: string): void;
34
+ entries(): readonly MutationEntry[];
35
+ summarize(): MutationSummary;
36
+ }
37
+ export declare function activeMutationLedger(): MutationLedger | undefined;
38
+ /** ADR-004: dest-mutating port calls record and skip dest IO. */
39
+ export declare function runInPortRecordMode<T>(fn: () => T): T;
40
+ export declare function isPortRecordMode(): boolean;
41
+ /** Bind a ledger for the duration of `fn` (including awaited continuations). */
42
+ export declare function runWithMutationLedger<T>(root: string, fn: () => T): T;
43
+ export declare function recordActiveMutation(kind: MutationKind, target: string): void;
44
+ export declare function snapshotMutationSummary(): MutationSummary;
45
+ /** Human summary: `Removed:` plus wrote/stripped. Empty when nothing mutated. */
46
+ export declare function formatMutationSummary(summary: MutationSummary): string;
47
+ export declare function mutationSummaryJson(summary: MutationSummary): {
48
+ wrote: string[];
49
+ stripped: string[];
50
+ deleted: string[];
51
+ chmod: string[];
52
+ exec: string[];
53
+ };
54
+ //# sourceMappingURL=mutation-ledger.d.ts.map
@@ -0,0 +1,133 @@
1
+ /**
2
+ * mutation-ledger.ts — typed deposit mutation log at the write chokepoint (#3392).
3
+ *
4
+ * A bound ledger records wrote / stripped / deleted as a side effect of
5
+ * containedWrite / containedRemove. Callers cannot discard mutations by
6
+ * ignoring a writer return value.
7
+ *
8
+ * Refs #3392 / #3378.
9
+ */
10
+ import { AsyncLocalStorage } from "node:async_hooks";
11
+ import { isAbsolute, relative, resolve } from "node:path";
12
+ export const MUTATION_KINDS = ["wrote", "stripped", "deleted", "chmod", "exec"];
13
+ /** Atomic-replace temps (`name.deft-<pid>.tmp`) are not logical mutations. */
14
+ const ATOMIC_TMP = /\.deft-\d+\.tmp$/u;
15
+ export function isAtomicWriteTemp(path) {
16
+ return ATOMIC_TMP.test(path.replace(/\\/g, "/"));
17
+ }
18
+ /** Posix-relative path under `root`, or empty when the target is not nested. */
19
+ export function toLedgerPath(root, target) {
20
+ const rootAbs = resolve(root);
21
+ const targetAbs = isAbsolute(target) ? resolve(target) : resolve(rootAbs, target);
22
+ const rel = relative(rootAbs, targetAbs);
23
+ if (rel.length === 0 || rel.startsWith("..") || isAbsolute(rel))
24
+ return "";
25
+ return rel.split("\\").join("/");
26
+ }
27
+ export function emptyMutationSummary() {
28
+ return { wrote: [], stripped: [], deleted: [], chmod: [], exec: [], mutations: [] };
29
+ }
30
+ function summarizeEntries(entries) {
31
+ const latest = new Map();
32
+ const order = [];
33
+ for (const entry of entries) {
34
+ if (!latest.has(entry.path))
35
+ order.push(entry.path);
36
+ latest.set(entry.path, entry.kind);
37
+ }
38
+ const wrote = [];
39
+ const stripped = [];
40
+ const deleted = [];
41
+ const chmod = [];
42
+ const exec = [];
43
+ const mutations = [];
44
+ for (const path of order) {
45
+ const kind = latest.get(path);
46
+ if (kind === undefined)
47
+ continue;
48
+ mutations.push({ kind, path });
49
+ if (kind === "wrote")
50
+ wrote.push(path);
51
+ else if (kind === "stripped")
52
+ stripped.push(path);
53
+ else if (kind === "chmod")
54
+ chmod.push(path);
55
+ else if (kind === "exec")
56
+ exec.push(path);
57
+ else
58
+ deleted.push(path);
59
+ }
60
+ return { wrote, stripped, deleted, chmod, exec, mutations };
61
+ }
62
+ /** In-memory ledger for one deposit/refresh run. */
63
+ export class MutationLedger {
64
+ root;
65
+ recorded = [];
66
+ constructor(root) {
67
+ this.root = resolve(root);
68
+ }
69
+ record(kind, target) {
70
+ const path = toLedgerPath(this.root, target);
71
+ if (path.length === 0)
72
+ return;
73
+ this.recorded.push({ kind, path });
74
+ }
75
+ entries() {
76
+ return this.recorded;
77
+ }
78
+ summarize() {
79
+ return summarizeEntries(this.recorded);
80
+ }
81
+ }
82
+ const storage = new AsyncLocalStorage();
83
+ const recordModeStorage = new AsyncLocalStorage();
84
+ export function activeMutationLedger() {
85
+ return storage.getStore();
86
+ }
87
+ /** ADR-004: dest-mutating port calls record and skip dest IO. */
88
+ export function runInPortRecordMode(fn) {
89
+ return recordModeStorage.run(true, fn);
90
+ }
91
+ export function isPortRecordMode() {
92
+ return recordModeStorage.getStore() === true;
93
+ }
94
+ /** Bind a ledger for the duration of `fn` (including awaited continuations). */
95
+ export function runWithMutationLedger(root, fn) {
96
+ return storage.run(new MutationLedger(root), fn);
97
+ }
98
+ export function recordActiveMutation(kind, target) {
99
+ activeMutationLedger()?.record(kind, target);
100
+ }
101
+ export function snapshotMutationSummary() {
102
+ return activeMutationLedger()?.summarize() ?? emptyMutationSummary();
103
+ }
104
+ /** Human summary: `Removed:` plus wrote/stripped. Empty when nothing mutated. */
105
+ export function formatMutationSummary(summary) {
106
+ const lines = [];
107
+ if (summary.deleted.length > 0) {
108
+ lines.push(`Removed: ${summary.deleted.join(", ")}`);
109
+ }
110
+ if (summary.wrote.length > 0) {
111
+ lines.push(`wrote: ${summary.wrote.join(", ")}`);
112
+ }
113
+ if (summary.stripped.length > 0) {
114
+ lines.push(`stripped: ${summary.stripped.join(", ")}`);
115
+ }
116
+ if (summary.chmod.length > 0) {
117
+ lines.push(`chmod: ${summary.chmod.join(", ")}`);
118
+ }
119
+ if (summary.exec.length > 0) {
120
+ lines.push(`exec: ${summary.exec.join(", ")}`);
121
+ }
122
+ return lines.length > 0 ? `${lines.join("\n")}\n` : "";
123
+ }
124
+ export function mutationSummaryJson(summary) {
125
+ return {
126
+ wrote: [...summary.wrote],
127
+ stripped: [...summary.stripped],
128
+ deleted: [...summary.deleted],
129
+ chmod: [...summary.chmod],
130
+ exec: [...summary.exec],
131
+ };
132
+ }
133
+ //# sourceMappingURL=mutation-ledger.js.map
@@ -0,0 +1,79 @@
1
+ /**
2
+ * non-product-dirs.ts — one source of truth for the "not product source"
3
+ * directory basenames shared by every Directive filesystem walk (#3487).
4
+ *
5
+ * Directive shipped four independently hand-maintained exclusion sets:
6
+ *
7
+ * - `EXCLUDE_DIRS` — `verify-source/verify-stubs.ts`
8
+ * - `EXCLUDE_DIRS` — `validate-content/validate-links.ts`
9
+ * - `SKIP_DIRS` — `codebase/default-extractor.ts`
10
+ * - `DEFAULT_EXCLUDES` — `release/build-dist.ts`
11
+ *
12
+ * They drifted from each other, which is exactly how #2953 added
13
+ * `.deft-scratch` / `swarm-worktrees` to some walks and missed the
14
+ * `verify-stubs` walk (#3481), and how none of them ever learned about agent
15
+ * working directories even though Directive ships first-class support for
16
+ * several agent hosts. Because `@deftai/directive-core` is published, a
17
+ * consumer cannot patch any of the four.
18
+ *
19
+ * `NON_PRODUCT_DIRS` is the common core each walk now extends. It carries only
20
+ * basenames that are never product source in any repo: VCS metadata,
21
+ * dependency trees, build output, tool caches, and agent working directories.
22
+ * Walk-specific entries (`tests`, `specs`, `.planning`, `htmlcov`, …) stay with
23
+ * the walk that needs them — this constant is a floor, not a ceiling.
24
+ *
25
+ * Adding a directory here is a one-line change all four walks pick up, and
26
+ * `non-product-dirs.test.ts` fails if any of them stops agreeing.
27
+ *
28
+ * Refs #3487, #3481, #2953, #2954, #1656.
29
+ */
30
+ /**
31
+ * Swarm / agent scratch worktree roots (#2953, #1656).
32
+ *
33
+ * `.deft-scratch` is the current layout (`.deft-scratch/worktrees/<story-id>`,
34
+ * built by `swarm/launch.ts`); `swarm-worktrees` is the pre-`.deft-scratch`
35
+ * name, kept for repos that still carry one.
36
+ */
37
+ export declare const AGENT_SCRATCH_DIRS: readonly string[];
38
+ /**
39
+ * Agent-host directories that hold host *working* state rather than product
40
+ * source (#3487).
41
+ *
42
+ * Only names with evidence of a real working directory belong here. Directive
43
+ * knows several host directories (`.claude`, `.cursor`, `.grok`, `.codex`,
44
+ * `.github/skills`, `.agents`), but most of them hold nothing except
45
+ * Directive's own committed deposits — `commands.md` § Native multi-host
46
+ * registration (LockedDecision L8) says to *commit* those, so blanket-excluding
47
+ * them would hide committed team surface for no measured gain.
48
+ *
49
+ * `.claude` is different in kind: the Claude Code host keeps live session state
50
+ * in the same directory it keeps config — `settings.local.json`, and agent
51
+ * worktrees under `.claude/worktrees/<agent-id>`, each a full nested checkout.
52
+ * Three such worktrees added ~11,000 walkable entries to this repo
53
+ * (9,128 → 20,393) that no Directive walk skipped. Its Directive-managed
54
+ * contents (`.claude/settings.json`, `.claude/commands/*.md`,
55
+ * `.claude/skills/`) are deposits generated from `content/`, which every walk
56
+ * still visits at the authoring source.
57
+ *
58
+ * Deliberately **not** listed:
59
+ * - `.openclaw` — there is no project-level `.openclaw/`; the host state dir
60
+ * is `~/.openclaw` in `$HOME` (see `doctor/openclaw-skills.ts`), and
61
+ * inventing a project one is explicitly forbidden by
62
+ * `content/docs/openclaw-agent-host.md` and asserted against in
63
+ * `slash/openclaw-adapter.test.ts`.
64
+ * - `.cursor`, `.grok`, `.codex`, `.github` — committed Directive deposits
65
+ * (`.cursor/hooks.json`, `.grok/commands/`, `.codex/prompts/`,
66
+ * `.github/skills/`) with no known working/worktree subtree. No evidence
67
+ * of a scratch convention was found for any of them.
68
+ */
69
+ export declare const AGENT_HOST_WORKING_DIRS: readonly string[];
70
+ /**
71
+ * Directory basenames no Directive walk should descend into.
72
+ *
73
+ * Every walk extends this set; none may shrink it. Keep entries to basenames
74
+ * that cannot be product source in any repo — a name that is merely *usually*
75
+ * uninteresting to one gate (`tests`, `scripts`, `specs`) belongs to that
76
+ * walk's own set, not here.
77
+ */
78
+ export declare const NON_PRODUCT_DIRS: ReadonlySet<string>;
79
+ //# sourceMappingURL=non-product-dirs.d.ts.map