@deftai/directive-core 0.103.0 → 0.105.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 (255) hide show
  1. package/dist/authz/classify.js +682 -35
  2. package/dist/check/cached-orchestrator.d.ts +1 -1
  3. package/dist/check/cached-orchestrator.js +2 -2
  4. package/dist/check/gate-lists.d.ts +3 -2
  5. package/dist/check/gate-lists.js +5 -2
  6. package/dist/check/index.d.ts +1 -0
  7. package/dist/check/index.js +1 -0
  8. package/dist/check/named-cause.d.ts +1 -1
  9. package/dist/check/named-cause.js +33 -3
  10. package/dist/check/session-completed-ac.d.ts +39 -0
  11. package/dist/check/session-completed-ac.js +198 -0
  12. package/dist/codebase/default-extractor.d.ts +5 -0
  13. package/dist/codebase/default-extractor.js +7 -15
  14. package/dist/deposit/copy-tree.js +60 -0
  15. package/dist/deposit/python-free.js +26 -18
  16. package/dist/doctor/checks.d.ts +8 -0
  17. package/dist/doctor/checks.js +37 -25
  18. package/dist/doctor/doctor-state.d.ts +4 -0
  19. package/dist/doctor/doctor-state.js +7 -1
  20. package/dist/doctor/main.js +9 -14
  21. package/dist/doctor/types.d.ts +9 -0
  22. package/dist/fs/contained-write.d.ts +115 -1
  23. package/dist/fs/contained-write.js +242 -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 +2 -0
  31. package/dist/index.js +3 -0
  32. package/dist/init-deposit/agent-hooks.js +17 -15
  33. package/dist/init-deposit/core-guard-pin-content.d.ts +7 -0
  34. package/dist/init-deposit/core-guard-pin-content.js +393 -0
  35. package/dist/init-deposit/gitignore.js +9 -0
  36. package/dist/init-deposit/hygiene.d.ts +47 -11
  37. package/dist/init-deposit/hygiene.js +172 -37
  38. package/dist/init-deposit/legacy-detect.js +6 -2
  39. package/dist/init-deposit/refresh.d.ts +21 -1
  40. package/dist/init-deposit/refresh.js +106 -9
  41. package/dist/init-deposit/scaffold.js +28 -279
  42. package/dist/init-deposit/slash-deposit.js +13 -7
  43. package/dist/init-deposit/xbrief-projections.d.ts +8 -1
  44. package/dist/init-deposit/xbrief-projections.js +24 -11
  45. package/dist/intake/clause-derivation.d.ts +74 -0
  46. package/dist/intake/clause-derivation.js +409 -0
  47. package/dist/intake/index.d.ts +1 -0
  48. package/dist/intake/index.js +1 -0
  49. package/dist/intake/issue-ingest.d.ts +3 -1
  50. package/dist/intake/issue-ingest.js +36 -43
  51. package/dist/lifecycle/completed-tracked-on-delivery.d.ts +5 -0
  52. package/dist/lifecycle/completed-tracked-on-delivery.js +85 -18
  53. package/dist/literal-acceptance/capture.d.ts +10 -0
  54. package/dist/literal-acceptance/capture.js +224 -75
  55. package/dist/literal-acceptance/evaluate.d.ts +29 -4
  56. package/dist/literal-acceptance/evaluate.js +70 -2
  57. package/dist/literal-acceptance/index.d.ts +3 -3
  58. package/dist/literal-acceptance/index.js +3 -3
  59. package/dist/literal-acceptance/safety.d.ts +41 -0
  60. package/dist/literal-acceptance/safety.js +126 -2
  61. package/dist/literal-acceptance/types.d.ts +8 -0
  62. package/dist/orphan-active/evaluate.d.ts +7 -1
  63. package/dist/orphan-active/evaluate.js +102 -23
  64. package/dist/platform/platform-capabilities.js +2 -3
  65. package/dist/policy/base-branch.d.ts +37 -0
  66. package/dist/policy/base-branch.js +114 -0
  67. package/dist/policy/branch-sync.d.ts +80 -0
  68. package/dist/policy/branch-sync.js +211 -0
  69. package/dist/policy/ceremony-dial-escalation.js +1 -0
  70. package/dist/policy/ceremony-dial.js +4 -14
  71. package/dist/policy/delivery-branch.d.ts +5 -3
  72. package/dist/policy/delivery-branch.js +7 -3
  73. package/dist/policy/file-size-thresholds.d.ts +24 -0
  74. package/dist/policy/file-size-thresholds.js +23 -0
  75. package/dist/policy/forge-outage-retry.d.ts +47 -0
  76. package/dist/policy/forge-outage-retry.js +157 -0
  77. package/dist/policy/index.d.ts +7 -0
  78. package/dist/policy/index.js +66 -7
  79. package/dist/policy/project-invariants.d.ts +50 -0
  80. package/dist/policy/project-invariants.js +205 -0
  81. package/dist/policy/sync-default.d.ts +129 -0
  82. package/dist/policy/sync-default.js +452 -0
  83. package/dist/policy/sync-max-files.d.ts +93 -0
  84. package/dist/policy/sync-max-files.js +192 -0
  85. package/dist/pr-monitor/absent-required.d.ts +11 -0
  86. package/dist/pr-monitor/absent-required.js +61 -0
  87. package/dist/pr-monitor/constants.d.ts +7 -0
  88. package/dist/pr-monitor/constants.js +7 -0
  89. package/dist/pr-monitor/index.d.ts +2 -1
  90. package/dist/pr-monitor/index.js +2 -1
  91. package/dist/pr-monitor/main.js +4 -0
  92. package/dist/pr-monitor/monitor.js +24 -1
  93. package/dist/pr-wait-mergeable/classify.js +6 -0
  94. package/dist/preflight/evaluate.d.ts +9 -0
  95. package/dist/preflight/evaluate.js +49 -1
  96. package/dist/preflight/index.d.ts +5 -1
  97. package/dist/preflight/index.js +2 -0
  98. package/dist/preflight/intended-placement.d.ts +62 -0
  99. package/dist/preflight/intended-placement.js +275 -0
  100. package/dist/preflight/project-invariants-gate.d.ts +29 -0
  101. package/dist/preflight/project-invariants-gate.js +82 -0
  102. package/dist/product-first-done-gate/acceptance-resolver.d.ts +128 -0
  103. package/dist/product-first-done-gate/acceptance-resolver.js +144 -0
  104. package/dist/product-first-done-gate/acceptance.d.ts +7 -4
  105. package/dist/product-first-done-gate/acceptance.js +79 -8
  106. package/dist/product-first-done-gate/empty-resolution.d.ts +5 -2
  107. package/dist/product-first-done-gate/empty-resolution.js +13 -2
  108. package/dist/product-first-done-gate/evaluate.d.ts +29 -0
  109. package/dist/product-first-done-gate/evaluate.js +307 -33
  110. package/dist/product-first-done-gate/index.d.ts +3 -1
  111. package/dist/product-first-done-gate/index.js +2 -1
  112. package/dist/release/build-dist.d.ts +101 -0
  113. package/dist/release/build-dist.js +428 -46
  114. package/dist/run-summary/emit.d.ts +50 -4
  115. package/dist/run-summary/emit.js +262 -26
  116. package/dist/run-summary/index.d.ts +3 -2
  117. package/dist/run-summary/index.js +2 -1
  118. package/dist/run-summary/session-id.d.ts +21 -0
  119. package/dist/run-summary/session-id.js +92 -0
  120. package/dist/run-summary/share.d.ts +1 -1
  121. package/dist/run-summary/share.js +2 -2
  122. package/dist/run-summary/types.d.ts +38 -6
  123. package/dist/run-summary/types.js +1 -0
  124. package/dist/scope/acceptance-activate-gate.d.ts +1 -1
  125. package/dist/scope/acceptance-activate-gate.js +4 -4
  126. package/dist/scope/acceptance-evidence.d.ts +27 -0
  127. package/dist/scope/acceptance-evidence.js +66 -0
  128. package/dist/scope/capacity-stamp.d.ts +2 -0
  129. package/dist/scope/capacity-stamp.js +4 -0
  130. package/dist/scope/delivery-evidence.d.ts +9 -3
  131. package/dist/scope/delivery-evidence.js +39 -27
  132. package/dist/scope/index.d.ts +1 -0
  133. package/dist/scope/index.js +1 -0
  134. package/dist/scope/parent-lineage.js +7 -6
  135. package/dist/scope/project-invariant-coverage.d.ts +54 -0
  136. package/dist/scope/project-invariant-coverage.js +322 -0
  137. package/dist/scope/transition.js +66 -4
  138. package/dist/scope-provenance/compare-intent.d.ts +27 -0
  139. package/dist/scope-provenance/compare-intent.js +233 -0
  140. package/dist/scope-provenance/digest.d.ts +18 -1
  141. package/dist/scope-provenance/digest.js +16 -11
  142. package/dist/scope-provenance/evaluate.d.ts +5 -1
  143. package/dist/scope-provenance/evaluate.js +64 -4
  144. package/dist/scope-provenance/extract-intent.d.ts +43 -0
  145. package/dist/scope-provenance/extract-intent.js +262 -0
  146. package/dist/scope-provenance/index.d.ts +7 -1
  147. package/dist/scope-provenance/index.js +7 -1
  148. package/dist/scope-provenance/intent-digest.d.ts +12 -0
  149. package/dist/scope-provenance/intent-digest.js +33 -0
  150. package/dist/scope-provenance/intent-evaluate.d.ts +43 -0
  151. package/dist/scope-provenance/intent-evaluate.js +149 -0
  152. package/dist/scope-provenance/json-tokenizer.d.ts +19 -0
  153. package/dist/scope-provenance/json-tokenizer.js +225 -0
  154. package/dist/scope-provenance/known-machine.d.ts +38 -0
  155. package/dist/scope-provenance/known-machine.js +157 -0
  156. package/dist/scope-provenance/mint-artifacts.d.ts +102 -0
  157. package/dist/scope-provenance/mint-artifacts.js +425 -0
  158. package/dist/session/ac-pass-banking.d.ts +4 -36
  159. package/dist/session/ac-pass-banking.js +30 -77
  160. package/dist/session/ac-pass-reuse.d.ts +53 -0
  161. package/dist/session/ac-pass-reuse.js +95 -0
  162. package/dist/session/ceremony-dial-evidence.d.ts +42 -0
  163. package/dist/session/ceremony-dial-evidence.js +194 -0
  164. package/dist/session/git.js +19 -4
  165. package/dist/session/index.d.ts +5 -0
  166. package/dist/session/index.js +5 -0
  167. package/dist/session/occupancy-stress-worker.d.ts +7 -0
  168. package/dist/session/occupancy-stress-worker.js +36 -0
  169. package/dist/session/occupancy.d.ts +97 -0
  170. package/dist/session/occupancy.js +422 -0
  171. package/dist/session/openclaw-soft-rebind-deposit.js +6 -6
  172. package/dist/session/product-state-hash.d.ts +26 -0
  173. package/dist/session/product-state-hash.js +683 -0
  174. package/dist/session/session-ready.d.ts +2 -0
  175. package/dist/session/session-ready.js +52 -30
  176. package/dist/session/session-start.d.ts +7 -0
  177. package/dist/session/session-start.js +88 -5
  178. package/dist/session/verify-ac-session-cache.d.ts +42 -0
  179. package/dist/session/verify-ac-session-cache.js +126 -0
  180. package/dist/session/verify-session-ritual.d.ts +5 -0
  181. package/dist/session/verify-session-ritual.js +9 -0
  182. package/dist/slash/openclaw-deposit.js +13 -9
  183. package/dist/slice/constants.d.ts +2 -2
  184. package/dist/slice/constants.js +2 -2
  185. package/dist/slice/existing.js +21 -4
  186. package/dist/slice/lock.d.ts +16 -1
  187. package/dist/slice/lock.js +137 -11
  188. package/dist/slice/record.d.ts +8 -5
  189. package/dist/slice/record.js +21 -13
  190. package/dist/story-ready/evaluate.d.ts +2 -0
  191. package/dist/story-ready/evaluate.js +13 -0
  192. package/dist/swarm/complete-cohort.d.ts +3 -0
  193. package/dist/swarm/complete-cohort.js +59 -11
  194. package/dist/swarm/finalize-cohort.js +33 -2
  195. package/dist/swarm/launch.d.ts +22 -0
  196. package/dist/swarm/launch.js +155 -0
  197. package/dist/swarm/routing-set-cli.d.ts +11 -1
  198. package/dist/swarm/routing-set-cli.js +13 -3
  199. package/dist/swarm/routing-verify.d.ts +12 -0
  200. package/dist/swarm/routing-verify.js +59 -20
  201. package/dist/swarm/routing.d.ts +14 -0
  202. package/dist/swarm/routing.js +53 -3
  203. package/dist/telemetry-coverage/evaluate.d.ts +42 -0
  204. package/dist/telemetry-coverage/evaluate.js +148 -0
  205. package/dist/telemetry-coverage/fake-trial.d.ts +45 -0
  206. package/dist/telemetry-coverage/fake-trial.js +204 -0
  207. package/dist/telemetry-coverage/index.d.ts +5 -0
  208. package/dist/telemetry-coverage/index.js +5 -0
  209. package/dist/telemetry-coverage/kinds.d.ts +19 -0
  210. package/dist/telemetry-coverage/kinds.js +54 -0
  211. package/dist/telemetry-coverage/scan-callers.d.ts +25 -0
  212. package/dist/telemetry-coverage/scan-callers.js +168 -0
  213. package/dist/triage/actions/index.js +4 -1
  214. package/dist/ts-check-lane/index.d.ts +3 -0
  215. package/dist/ts-check-lane/index.js +2 -0
  216. package/dist/ts-check-lane/progress-reporter.d.ts +17 -0
  217. package/dist/ts-check-lane/progress-reporter.js +38 -0
  218. package/dist/ts-check-lane/progress.d.ts +32 -0
  219. package/dist/ts-check-lane/progress.js +57 -0
  220. package/dist/ts-check-lane/run-lane.d.ts +3 -1
  221. package/dist/ts-check-lane/run-lane.js +8 -6
  222. package/dist/validate-content/validate-links.d.ts +8 -0
  223. package/dist/validate-content/validate-links.js +9 -15
  224. package/dist/value/feedback-file.js +12 -2
  225. package/dist/vbrief-build/index.d.ts +1 -0
  226. package/dist/vbrief-build/index.js +1 -0
  227. package/dist/vbrief-build/project-invariants-io.d.ts +16 -0
  228. package/dist/vbrief-build/project-invariants-io.js +41 -0
  229. package/dist/vbrief-reconcile/graph.js +18 -1
  230. package/dist/vbrief-reconcile/index.d.ts +3 -1
  231. package/dist/vbrief-reconcile/index.js +2 -1
  232. package/dist/vbrief-reconcile/origin-freshness.d.ts +44 -0
  233. package/dist/vbrief-reconcile/origin-freshness.js +221 -0
  234. package/dist/vbrief-reconcile/types.d.ts +13 -0
  235. package/dist/vbrief-reconcile/umbrellas.d.ts +14 -0
  236. package/dist/vbrief-reconcile/umbrellas.js +261 -26
  237. package/dist/vbrief-validate/index.d.ts +1 -1
  238. package/dist/vbrief-validate/index.js +1 -1
  239. package/dist/vbrief-validate/plan-hooks.d.ts +4 -0
  240. package/dist/vbrief-validate/plan-hooks.js +68 -0
  241. package/dist/verify-ac/evaluate.d.ts +7 -1
  242. package/dist/verify-ac/evaluate.js +34 -26
  243. package/dist/verify-ac/flag.d.ts +4 -0
  244. package/dist/verify-ac/flag.js +16 -0
  245. package/dist/verify-ac/index.d.ts +2 -2
  246. package/dist/verify-ac/index.js +2 -2
  247. package/dist/verify-source/contained-writes.js +2 -0
  248. package/dist/verify-source/index.d.ts +1 -0
  249. package/dist/verify-source/index.js +1 -0
  250. package/dist/verify-source/verify-stubs.d.ts +15 -1
  251. package/dist/verify-source/verify-stubs.js +20 -16
  252. package/dist/vitest-runner/win32-coverage-tmp-setup.d.ts +5 -6
  253. package/dist/vitest-runner/win32-coverage-tmp-setup.js +5 -6
  254. package/dist/xbrief-migrate/migrate-project.js +2 -5
  255. package/package.json +3 -3
@@ -15,6 +15,7 @@ import { execFileSync } from "node:child_process";
15
15
  import { join } from "node:path";
16
16
  import { cacheFetchAll } from "../cache/fetch.js";
17
17
  import { formatFrameworkCommand } from "../render/framework-commands.js";
18
+ import { applyWorktreeOccupancy, } from "./occupancy.js";
18
19
  import { runSessionStart, } from "./session-start.js";
19
20
  import { inspectSessionRitual, verifySessionRitual, } from "./verify-session-ritual.js";
20
21
  export const SESSION_READY_FAST_PATH = "fast";
@@ -95,6 +96,54 @@ export function runSessionReady(projectRoot, options = {}) {
95
96
  const start = options.runStart ?? runSessionStart;
96
97
  const fetchAll = options.fetchAll ?? cacheFetchAll;
97
98
  const inferRepo = options.inferRepo ?? ((root) => inferSessionReadyRepo(root, env));
99
+ const applyOccupancy = options.applyOccupancy ?? applyWorktreeOccupancy;
100
+ const occupancyInput = (write) => ({
101
+ env,
102
+ now,
103
+ steal: options.sessionStartOptions?.steal,
104
+ confirm: options.sessionStartOptions?.confirm,
105
+ occupant: options.sessionStartOptions?.occupant,
106
+ newSessionId: options.sessionStartOptions?.newSessionId,
107
+ intent: options.sessionStartOptions?.occupancyIntent ?? "mutation",
108
+ write,
109
+ });
110
+ const previewOccupancy = applyOccupancy(projectRoot, occupancyInput(false));
111
+ if (previewOccupancy.code !== 0) {
112
+ const message = previewOccupancy.message;
113
+ lines.push(message);
114
+ return {
115
+ code: previewOccupancy.code,
116
+ message,
117
+ path: SESSION_READY_FAILED,
118
+ lines,
119
+ steps,
120
+ duration_ms: elapsedMs(started),
121
+ };
122
+ }
123
+ const claimOnSuccess = () => applyOccupancy(projectRoot, occupancyInput(true));
124
+ const finishReady = (path, message) => {
125
+ const claimed = claimOnSuccess();
126
+ if (claimed.code !== 0) {
127
+ lines.push(claimed.message);
128
+ return {
129
+ code: claimed.code,
130
+ message: claimed.message,
131
+ path: SESSION_READY_FAILED,
132
+ lines,
133
+ steps,
134
+ duration_ms: elapsedMs(started),
135
+ };
136
+ }
137
+ lines.push(message);
138
+ return {
139
+ code: 0,
140
+ message,
141
+ path,
142
+ lines,
143
+ steps,
144
+ duration_ms: elapsedMs(started),
145
+ };
146
+ };
98
147
  const verifyOpts = {
99
148
  tier: "gated",
100
149
  posture: "mutation",
@@ -127,16 +176,7 @@ export function runSessionReady(projectRoot, options = {}) {
127
176
  duration_ms: elapsedMs(started),
128
177
  };
129
178
  }
130
- const message = "OK session ready (gated ritual already fresh).";
131
- lines.push(message);
132
- return {
133
- code: 0,
134
- message,
135
- path: SESSION_READY_FAST_PATH,
136
- lines,
137
- steps,
138
- duration_ms: elapsedMs(started),
139
- };
179
+ return finishReady(SESSION_READY_FAST_PATH, "OK session ready (gated ritual already fresh).");
140
180
  }
141
181
  // --- Ensure quick-tier ritual state when missing / stale / drifted ---
142
182
  const quickInspect = inspect(projectRoot, {
@@ -175,16 +215,7 @@ export function runSessionReady(projectRoot, options = {}) {
175
215
  steps.push("verify:session-ritual:gated");
176
216
  let verifyResult = verify(projectRoot, verifyOpts);
177
217
  if (isGatedVerifyActuallyReady(verifyResult)) {
178
- const message = "OK session ready (gated ritual verified).";
179
- lines.push(message);
180
- return {
181
- code: 0,
182
- message,
183
- path: SESSION_READY_VERIFIED,
184
- lines,
185
- steps,
186
- duration_ms: elapsedMs(started),
187
- };
218
+ return finishReady(SESSION_READY_VERIFIED, "OK session ready (gated ritual verified).");
188
219
  }
189
220
  if (verifyResult.code === 0 && verifyResult.bypassed) {
190
221
  const message = bypassedReadyFailure(verifyResult);
@@ -241,16 +272,7 @@ export function runSessionReady(projectRoot, options = {}) {
241
272
  steps.push("verify:session-ritual:gated:retry");
242
273
  verifyResult = verify(projectRoot, { ...verifyOpts, forceGatedSteps: [] });
243
274
  if (isGatedVerifyActuallyReady(verifyResult)) {
244
- const message = "OK session ready (recovered via cache refresh).";
245
- lines.push(message);
246
- return {
247
- code: 0,
248
- message,
249
- path: SESSION_READY_RECOVERED,
250
- lines,
251
- steps,
252
- duration_ms: elapsedMs(started),
253
- };
275
+ return finishReady(SESSION_READY_RECOVERED, "OK session ready (recovered via cache refresh).");
254
276
  }
255
277
  if (verifyResult.code === 0 && verifyResult.bypassed) {
256
278
  const message = bypassedReadyFailure(verifyResult);
@@ -6,6 +6,7 @@ import { type ProbeScmReadinessOptions, type ScmReadinessReport } from "../scm/r
6
6
  import { type ResolveUserMdResult } from "../user-config/resolve-user-md.js";
7
7
  import { type DetectHardEffortBudgetInput } from "./effort-budget.js";
8
8
  import type { GitRunner } from "./git.js";
9
+ import { type ApplyOccupancyInput, type OccupancyDecision } from "./occupancy.js";
9
10
  import { type OrientationBundle, type RunOrientationOptions } from "./orientation-compression.js";
10
11
  import { type ReleaseAvailabilityProbeOptions } from "./release-availability.js";
11
12
  import { type RitualState, ritualStatePath } from "./ritual-sentinel.js";
@@ -63,6 +64,12 @@ export interface SessionStartOptions {
63
64
  readonly writeHistory?: boolean;
64
65
  readonly runGit?: GitRunner;
65
66
  readonly newSessionId?: () => string;
67
+ /** #3433: steal the worktree occupancy lease. Requires confirm + occupant. */
68
+ readonly steal?: boolean;
69
+ readonly confirm?: boolean;
70
+ readonly occupant?: string;
71
+ readonly occupancyIntent?: ApplyOccupancyInput["intent"];
72
+ readonly applyOccupancy?: (projectRoot: string, input: ApplyOccupancyInput) => OccupancyDecision;
66
73
  readonly runTriageWelcome?: (projectRoot: string, options: {
67
74
  writeHistory: boolean;
68
75
  now: Date;
@@ -1,4 +1,3 @@
1
- import { randomUUID } from "node:crypto";
2
1
  import { runningInsideDeftRepo } from "../doctor/paths.js";
3
2
  import { emitSessionEvalReadback } from "../eval/readback.js";
4
3
  import { bindSessionGeneration } from "../freshness/bind.js";
@@ -23,8 +22,10 @@ import { runDefaultMode } from "../triage/welcome/default-mode.js";
23
22
  import { resolveUserMdPath } from "../user-config/resolve-user-md.js";
24
23
  import { emitSessionValueReadback } from "../value/readback.js";
25
24
  import { verifyRequiredTools } from "../verify-env/verify-tools.js";
25
+ import { ceremonyDialEvidenceToDict, collectCeremonyDialConsumerEvidence, formatCeremonyDialEvidenceLine, mergeCeremonyDialInputsWithConsumerEvidence, } from "./ceremony-dial-evidence.js";
26
26
  import { effortBudgetToDict, maybeFormatEffortBudgetLines, resolveProductionHostEffortDescriptor, } from "./effort-budget.js";
27
27
  import { defaultGitRunner, gitHead, gitIsAncestor, worktreePath } from "./git.js";
28
+ import { applyWorktreeOccupancy, } from "./occupancy.js";
28
29
  import { runOrientationCompression, } from "./orientation-compression.js";
29
30
  import { emitSessionStartProcessCost } from "./process-cost.js";
30
31
  import { probeSessionReleaseAvailability, } from "./release-availability.js";
@@ -432,6 +433,46 @@ function resolveEffortBudget(options) {
432
433
  };
433
434
  }
434
435
  }
436
+ function occupancyInput(options, now, write) {
437
+ return {
438
+ env: options.env,
439
+ now,
440
+ newSessionId: options.newSessionId,
441
+ steal: options.steal,
442
+ confirm: options.confirm,
443
+ occupant: options.occupant,
444
+ intent: options.occupancyIntent ?? "mutation",
445
+ write,
446
+ };
447
+ }
448
+ function runOccupancy(projectRoot, options, now, write) {
449
+ const apply = options.applyOccupancy ?? applyWorktreeOccupancy;
450
+ return apply(projectRoot, occupancyInput(options, now, write));
451
+ }
452
+ function occupancyDeniedResult(occupancy, environment) {
453
+ return {
454
+ code: occupancy.code,
455
+ payload: {
456
+ ready: false,
457
+ exit_code: occupancy.code,
458
+ posture: MUTATION_POSTURE,
459
+ occupancy: {
460
+ action: occupancy.action,
461
+ session_id: occupancy.sessionId,
462
+ occupant_id: occupancy.record?.sessionId ?? null,
463
+ },
464
+ environment: environmentContextToDict(environment),
465
+ message: occupancy.message,
466
+ },
467
+ lines: occupancy.message.split("\n"),
468
+ };
469
+ }
470
+ function persistOccupancyOrDeny(projectRoot, options, now, environment) {
471
+ const occupancy = runOccupancy(projectRoot, options, now, true);
472
+ if (occupancy.code !== 0)
473
+ return occupancyDeniedResult(occupancy, environment);
474
+ return occupancy;
475
+ }
435
476
  function runReadOnlySessionStart(projectRoot, options, instant, environment) {
436
477
  const lines = [];
437
478
  const resolveUserMd = options.resolveUserMd ?? ((root) => resolveUserMdPath({ projectRoot: root }));
@@ -508,6 +549,10 @@ function runSessionRearm(projectRoot, options, instant, environment) {
508
549
  lines: [formatEnvironmentContext(environment), message],
509
550
  };
510
551
  }
552
+ const plannedOccupancy = runOccupancy(projectRoot, options, instant, options.steal === true);
553
+ if (plannedOccupancy.code !== 0) {
554
+ return occupancyDeniedResult(plannedOccupancy, environment);
555
+ }
511
556
  const resolveUserMd = options.resolveUserMd ?? ((root) => resolveUserMdPath({ projectRoot: root }));
512
557
  const userMd = resolveUserMd(projectRoot);
513
558
  const safePath = userMd.path.replace(/\r?\n/g, " ");
@@ -605,7 +650,12 @@ function runSessionRearm(projectRoot, options, instant, environment) {
605
650
  };
606
651
  const gatedSteps = restampSteps(eligibility.state.gatedSteps, instant);
607
652
  const writeStarted = performance.now();
608
- const rearmSessionId = (options.newSessionId ?? randomUUID)();
653
+ const persistedOccupancy = persistOccupancyOrDeny(projectRoot, options, instant, environment);
654
+ if ("payload" in persistedOccupancy) {
655
+ return persistedOccupancy;
656
+ }
657
+ // #3433: keep DEFT_SESSION_ID / occupant id. Do not mint a new UUID on re-arm.
658
+ const rearmSessionId = persistedOccupancy.sessionId;
609
659
  // Fresh payload (no rearm_needed / compact_resume_at) clears compact markers (#2992).
610
660
  const writePayload = {
611
661
  ...newRitualStatePayload({
@@ -713,6 +763,10 @@ function runSessionRearm(projectRoot, options, instant, environment) {
713
763
  scm: scmReadinessToDict(scm),
714
764
  host_content_surface: hostContentSurfaceToDict(hostSurface.report),
715
765
  effort_budget: effortBudgetToDict(effortBudget.budget),
766
+ occupancy: {
767
+ action: persistedOccupancy.action,
768
+ session_id: rearmSessionId,
769
+ },
716
770
  message: code === 0 ? "session ritual re-armed" : "session ritual re-arm failed",
717
771
  },
718
772
  lines,
@@ -801,7 +855,16 @@ export function runSessionStart(projectRoot, options = {}) {
801
855
  // missing size/tier/shape from env/verb/files/deposit BEFORE resolve — never
802
856
  // block on plan-item effort (post-planning only). Cold incomplete size is
803
857
  // tier-conditional (#3263): mid/low → standard; frontier/unknown → rapid.
804
- const { inputs: resolvedDialInputs, provisional: provisionalDial } = resolveSessionCeremonyDialInputs(projectRoot, options.ceremonyDialInputs, {
858
+ // #3358: fill at least one consumer-supplied input (stamped clause count,
859
+ // host-tier env, failing-gate count) so evaluation is not permanently
860
+ // size=- / modelTier=-. ⊗ Change rapid default when no evidence exists.
861
+ const consumerDialEvidence = collectCeremonyDialConsumerEvidence(projectRoot, {
862
+ env: options.env,
863
+ });
864
+ const dialInputsWithEvidence = options.ceremonyDial === undefined
865
+ ? mergeCeremonyDialInputsWithConsumerEvidence(options.ceremonyDialInputs, consumerDialEvidence)
866
+ : (options.ceremonyDialInputs ?? {});
867
+ const { inputs: resolvedDialInputs, provisional: provisionalDial } = resolveSessionCeremonyDialInputs(projectRoot, dialInputsWithEvidence, {
805
868
  ...options.ceremonyDialHints,
806
869
  env: options.env,
807
870
  });
@@ -837,6 +900,10 @@ export function runSessionStart(projectRoot, options = {}) {
837
900
  lines: [formatEnvironmentContext(environment), payload.message],
838
901
  };
839
902
  }
903
+ const plannedOccupancy = runOccupancy(projectRoot, options, instant, options.steal === true);
904
+ if (plannedOccupancy.code !== 0) {
905
+ return occupancyDeniedResult(plannedOccupancy, environment);
906
+ }
840
907
  const quickSteps = recordDeferredSteps(QUICK_STEPS, effectiveDeferrals, instant);
841
908
  const gatedSteps = recordDeferredSteps(GATED_STEPS, effectiveDeferrals, instant);
842
909
  const lines = [];
@@ -850,6 +917,10 @@ export function runSessionStart(projectRoot, options = {}) {
850
917
  if (provisionalDial.reasons.length > 0 && options.ceremonyDial === undefined) {
851
918
  lines.push(`[deft ceremony-dial] provisional: ${provisionalDial.reasons.join("; ")}`);
852
919
  }
920
+ const evidenceLine = formatCeremonyDialEvidenceLine(consumerDialEvidence);
921
+ if (evidenceLine !== null && options.ceremonyDial === undefined) {
922
+ lines.push(evidenceLine);
923
+ }
853
924
  // Resolve USER.md via the shared first-hit-wins resolver so the alignment
854
925
  // step finds preferences automatically in mismatched / headless sandboxes
855
926
  // with zero manual DEFT_USER_PATH (#2271 / #2124). Never throws: an absent
@@ -1200,7 +1271,11 @@ export function runSessionStart(projectRoot, options = {}) {
1200
1271
  lines.push(consentPrompt.trimEnd());
1201
1272
  }
1202
1273
  const writeStarted = performance.now();
1203
- const coldSessionId = (options.newSessionId ?? randomUUID)();
1274
+ const persistedOccupancy = persistOccupancyOrDeny(projectRoot, options, instant, environment);
1275
+ if ("payload" in persistedOccupancy) {
1276
+ return persistedOccupancy;
1277
+ }
1278
+ const coldSessionId = persistedOccupancy.sessionId;
1204
1279
  const dialDict = {
1205
1280
  ...ceremonyDialToDict(ceremonyDialSelection),
1206
1281
  start_tier: ceremonyDialSelection.depth,
@@ -1211,6 +1286,7 @@ export function runSessionStart(projectRoot, options = {}) {
1211
1286
  projectShape: provisionalDial.projectShape,
1212
1287
  reasons: [...provisionalDial.reasons],
1213
1288
  },
1289
+ consumer_evidence: ceremonyDialEvidenceToDict(consumerDialEvidence),
1214
1290
  };
1215
1291
  const preflightDict = toolchainPreflightResult !== null ? toolchainPreflightToDict(toolchainPreflightResult) : null;
1216
1292
  const payload = {
@@ -1283,7 +1359,10 @@ export function runSessionStart(projectRoot, options = {}) {
1283
1359
  }
1284
1360
  : {}),
1285
1361
  });
1286
- emitter.emitKnownToolTurnDenominator();
1362
+ // #3399: emit a denominator only when a host/harness value is known.
1363
+ // Prefer DEFT_TOTAL_TOOL_TURNS (harness_actual), then DEFT_MAX_TURNS /
1364
+ // host maxTurns (host_planned). Unset → no event; share is unevaluable.
1365
+ emitter.emitSessionToolTurnDenominator(effortBudget.budget.maxTurns);
1287
1366
  // #3319: evaluate escalate-on-evidence only when #3274 is live. A pin
1288
1367
  // emits nothing so never-evaluated stays distinguishable from declined.
1289
1368
  if (!isCeremonyStartTierPinned(startTierProvenance)) {
@@ -1367,6 +1446,10 @@ export function runSessionStart(projectRoot, options = {}) {
1367
1446
  scm: scmReadinessToDict(scm),
1368
1447
  host_content_surface: hostContentSurfaceToDict(hostSurface.report),
1369
1448
  effort_budget: effortBudgetToDict(effortBudget.budget),
1449
+ occupancy: {
1450
+ action: persistedOccupancy.action,
1451
+ session_id: coldSessionId,
1452
+ },
1370
1453
  message: code === 0 ? "session ritual recorded" : "session ritual failed",
1371
1454
  };
1372
1455
  // #2994: local process-cost event (best-effort; never blocks ceremony).
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Same-session verify:ac result cache (#3387).
3
+ *
4
+ * Disk-backed so check composition (spawned verify:ac) can serve from_cache
5
+ * after a green run in the same session when plan + product hash still match.
6
+ */
7
+ export declare const VERIFY_AC_SESSION_CACHE_DIR = ".deft/verify-ac-session-cache";
8
+ export declare const AC_SERVED_FROM: readonly ["bank", "cache", "executed"];
9
+ export type AcServedFrom = (typeof AC_SERVED_FROM)[number];
10
+ export interface CachedVerifyAcSnapshot {
11
+ readonly ok: boolean;
12
+ readonly code: 0 | 1 | 2;
13
+ readonly message: string;
14
+ readonly commands: readonly unknown[];
15
+ readonly runs: readonly unknown[];
16
+ readonly rejected?: readonly unknown[];
17
+ readonly sourceRung: string;
18
+ readonly noneStated: boolean;
19
+ readonly acceptance: unknown;
20
+ readonly resolution: string;
21
+ readonly resolvedCommandCount: number;
22
+ }
23
+ export interface VerifyAcSessionCacheRecord {
24
+ readonly sessionId: string;
25
+ readonly scopeId: string;
26
+ readonly productStateHash: string;
27
+ readonly cachedAt: string;
28
+ readonly snapshot: CachedVerifyAcSnapshot;
29
+ }
30
+ export declare function verifyAcSessionCacheDir(projectRoot: string): string;
31
+ export declare function verifyAcSessionCachePath(projectRoot: string, sessionId: string, scopeId: string): string;
32
+ export declare function resolveVerifyAcSessionId(env?: Readonly<Record<string, string | undefined>>, explicit?: string | null): string | null;
33
+ export declare function readVerifyAcSessionCache(projectRoot: string, sessionId: string, scopeId: string): VerifyAcSessionCacheRecord | null;
34
+ export declare function writeVerifyAcSessionCache(input: {
35
+ readonly projectRoot: string;
36
+ readonly sessionId: string;
37
+ readonly scopeId: string;
38
+ readonly productStateHash: string;
39
+ readonly snapshot: CachedVerifyAcSnapshot;
40
+ readonly now?: string;
41
+ }): VerifyAcSessionCacheRecord;
42
+ //# sourceMappingURL=verify-ac-session-cache.d.ts.map
@@ -0,0 +1,126 @@
1
+ /**
2
+ * Same-session verify:ac result cache (#3387).
3
+ *
4
+ * Disk-backed so check composition (spawned verify:ac) can serve from_cache
5
+ * after a green run in the same session when plan + product hash still match.
6
+ */
7
+ import { existsSync, mkdirSync, readFileSync } from "node:fs";
8
+ import { join, resolve } from "node:path";
9
+ import { containedWrite } from "../fs/contained-write.js";
10
+ import { sanitizeScopeIdForFilename } from "./ac-pass-banking.js";
11
+ export const VERIFY_AC_SESSION_CACHE_DIR = ".deft/verify-ac-session-cache";
12
+ export const AC_SERVED_FROM = ["bank", "cache", "executed"];
13
+ function asRecord(value) {
14
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
15
+ return value;
16
+ }
17
+ return null;
18
+ }
19
+ export function verifyAcSessionCacheDir(projectRoot) {
20
+ return join(resolve(projectRoot), ...VERIFY_AC_SESSION_CACHE_DIR.split("/"));
21
+ }
22
+ export function verifyAcSessionCachePath(projectRoot, sessionId, scopeId) {
23
+ const safeSession = sanitizeScopeIdForFilename(sessionId);
24
+ const safeScope = sanitizeScopeIdForFilename(scopeId);
25
+ return join(verifyAcSessionCacheDir(projectRoot), `${safeSession}-${safeScope}.json`);
26
+ }
27
+ export function resolveVerifyAcSessionId(env, explicit) {
28
+ const injected = explicit?.trim() ?? "";
29
+ if (injected.length > 0)
30
+ return injected;
31
+ const fromEnv = typeof env?.DEFT_SESSION_ID === "string" ? env.DEFT_SESSION_ID.trim() : "";
32
+ return fromEnv.length > 0 ? fromEnv : null;
33
+ }
34
+ function parseSnapshot(raw) {
35
+ const rec = asRecord(raw);
36
+ if (rec === null)
37
+ return null;
38
+ if (typeof rec.ok !== "boolean")
39
+ return null;
40
+ if (rec.code !== 0 && rec.code !== 1 && rec.code !== 2)
41
+ return null;
42
+ if (typeof rec.message !== "string")
43
+ return null;
44
+ if (!Array.isArray(rec.commands) || !Array.isArray(rec.runs))
45
+ return null;
46
+ if (typeof rec.sourceRung !== "string")
47
+ return null;
48
+ if (typeof rec.noneStated !== "boolean")
49
+ return null;
50
+ if (typeof rec.resolution !== "string")
51
+ return null;
52
+ if (typeof rec.resolvedCommandCount !== "number")
53
+ return null;
54
+ return {
55
+ ok: rec.ok,
56
+ code: rec.code,
57
+ message: rec.message,
58
+ commands: rec.commands,
59
+ runs: rec.runs,
60
+ rejected: Array.isArray(rec.rejected) ? rec.rejected : undefined,
61
+ sourceRung: rec.sourceRung,
62
+ noneStated: rec.noneStated,
63
+ acceptance: rec.acceptance,
64
+ resolution: rec.resolution,
65
+ resolvedCommandCount: rec.resolvedCommandCount,
66
+ };
67
+ }
68
+ export function readVerifyAcSessionCache(projectRoot, sessionId, scopeId) {
69
+ const path = verifyAcSessionCachePath(projectRoot, sessionId, scopeId);
70
+ if (!existsSync(path))
71
+ return null;
72
+ let text;
73
+ try {
74
+ text = readFileSync(path, { encoding: "utf8" });
75
+ }
76
+ catch {
77
+ return null;
78
+ }
79
+ try {
80
+ const parsed = JSON.parse(text);
81
+ const rec = asRecord(parsed);
82
+ if (rec === null)
83
+ return null;
84
+ if (rec.sessionId !== sessionId || rec.scopeId !== scopeId)
85
+ return null;
86
+ if (typeof rec.productStateHash !== "string" || rec.productStateHash.length === 0) {
87
+ return null;
88
+ }
89
+ const snapshot = parseSnapshot(rec.snapshot);
90
+ if (snapshot === null || snapshot.ok !== true)
91
+ return null;
92
+ return {
93
+ sessionId,
94
+ scopeId,
95
+ productStateHash: rec.productStateHash,
96
+ cachedAt: typeof rec.cachedAt === "string" ? rec.cachedAt : "",
97
+ snapshot,
98
+ };
99
+ }
100
+ catch {
101
+ return null;
102
+ }
103
+ }
104
+ export function writeVerifyAcSessionCache(input) {
105
+ const root = resolve(input.projectRoot);
106
+ const path = verifyAcSessionCachePath(root, input.sessionId, input.scopeId);
107
+ const dir = verifyAcSessionCacheDir(root);
108
+ if (!existsSync(dir))
109
+ mkdirSync(dir, { recursive: true });
110
+ const record = {
111
+ sessionId: input.sessionId,
112
+ scopeId: input.scopeId,
113
+ productStateHash: input.productStateHash,
114
+ cachedAt: input.now ?? new Date().toISOString().replace(/\.\d{3}Z$/, "Z"),
115
+ snapshot: input.snapshot,
116
+ };
117
+ containedWrite({
118
+ root,
119
+ target: path,
120
+ data: `${JSON.stringify(record, null, 2)}\n`,
121
+ mode: "replace",
122
+ mkdir: true,
123
+ });
124
+ return record;
125
+ }
126
+ //# sourceMappingURL=verify-ac-session-cache.js.map
@@ -28,6 +28,11 @@ export type RitualRunner = (command: readonly string[], projectRoot: string) =>
28
28
  };
29
29
  /** Human recovery line after a failed ritual probe (#2992 / #2993). */
30
30
  export declare function formatRitualRecoveryInstruction(tier?: SessionCeremonyTier): string;
31
+ /**
32
+ * Sanctioned audited defer copy for gated `cache_fresh` failure (#3506 / #3507).
33
+ * The gated argv is always `["verify:cache-fresh"]`, so this is unconditional.
34
+ */
35
+ export declare function formatCacheFreshDeferSoftPath(): string;
31
36
  export interface VerifySessionRitualOptions {
32
37
  readonly tier?: "quick" | "gated";
33
38
  readonly now?: Date;
@@ -50,6 +50,14 @@ export function formatRitualRecoveryInstruction(tier = "cold") {
50
50
  return (`Recovery: run ${ready} ` +
51
51
  `(one-shot: session:start + gated ritual + cache recovery as needed).`);
52
52
  }
53
+ /**
54
+ * Sanctioned audited defer copy for gated `cache_fresh` failure (#3506 / #3507).
55
+ * The gated argv is always `["verify:cache-fresh"]`, so this is unconditional.
56
+ */
57
+ export function formatCacheFreshDeferSoftPath() {
58
+ const cmd = formatFrameworkCommand(["session:start", "--", "--defer", "cache_fresh=<reason>"]);
59
+ return `Soft path (audited): \`${cmd}\`.`;
60
+ }
53
61
  function runGatedStep(projectRoot, payload, stepName, runner, now) {
54
62
  const command = [...GATED_ENTRYPOINT_COMMANDS[stepName]];
55
63
  const { code, stdout, stderr } = runner(command, projectRoot);
@@ -465,6 +473,7 @@ export function emitVerifyJson(result) {
465
473
  would_fail_code: result.wouldFailCode,
466
474
  posture: result.posture,
467
475
  ritual_state_required: result.ritualStateRequired,
476
+ recovery_tier: result.recoveryTier ?? null,
468
477
  });
469
478
  }
470
479
  export function emitBypassWarning(result) {
@@ -10,11 +10,12 @@
10
10
  *
11
11
  * ⊗ Fake project `.openclaw/commands/` file emitter.
12
12
  */
13
- import { existsSync, lstatSync, mkdirSync, readFileSync, renameSync, rmSync, statSync, } from "node:fs";
13
+ import { existsSync, lstatSync, mkdirSync, readFileSync, statSync } from "node:fs";
14
14
  import { homedir } from "node:os";
15
15
  import { join, resolve } from "node:path";
16
16
  import { detectOpenClaw, isEscapingSkillSymlink, listInScopeSkillsDirs, } from "../doctor/openclaw-skills.js";
17
- import { containedWrite } from "../fs/contained-write.js";
17
+ import { containedMkdir, containedRemove, containedRename, containedWrite, } from "../fs/contained-write.js";
18
+ import { isPortRecordMode } from "../fs/mutation-ledger.js";
18
19
  import { readPlanPolicy } from "../policy/plan-extensions.js";
19
20
  import { loadProjectDefinition } from "../policy/resolve.js";
20
21
  import { generateOpenClawSkillArtifacts, isManagedOpenClawL2Skill, listOpenClawManagedSkillSlugs, } from "./openclaw-adapter.js";
@@ -122,7 +123,7 @@ function writeSkillArtifact(skillsDir, artifact) {
122
123
  return "preserved";
123
124
  }
124
125
  }
125
- mkdirSync(skillDir, { recursive: true });
126
+ containedMkdir({ root: skillsDir, target: skillDir });
126
127
  // Re-check after mkdir: concurrent symlink plant is fail-closed.
127
128
  if (skillDirLstatKind(skillDir) === "symlink" && isEscapingSkillSymlink(skillsDir, skillDir)) {
128
129
  return "preserved";
@@ -137,11 +138,11 @@ function writeSkillArtifact(skillsDir, artifact) {
137
138
  data: artifact.skillMarkdown,
138
139
  mode: "replace",
139
140
  });
140
- renameSync(tmp, skillFile);
141
+ containedRename({ root: skillsDir, from: tmp, to: skillFile, mutation: false });
141
142
  }
142
143
  catch (err) {
143
144
  try {
144
- rmSync(tmp, { force: true });
145
+ containedRemove({ root: skillsDir, target: tmp, mutation: false });
145
146
  }
146
147
  catch {
147
148
  /* best-effort */
@@ -172,8 +173,9 @@ function stripManagedSkills(skillsDir) {
172
173
  if (!isManagedOpenClawL2Skill(raw))
173
174
  continue;
174
175
  try {
175
- rmSync(skillDir, { recursive: true, force: true });
176
- removed.push(skillDir);
176
+ if (containedRemove({ root: skillsDir, target: skillDir, recursive: true }).removed) {
177
+ removed.push(skillDir);
178
+ }
177
179
  }
178
180
  catch {
179
181
  /* best-effort */
@@ -221,7 +223,8 @@ export function depositOpenClawL2ProductCommands(options = {}) {
221
223
  const preservedCustomPaths = [];
222
224
  if (!policy) {
223
225
  for (const skillsDir of skillsDirs) {
224
- mkdirSync(skillsDir, { recursive: true });
226
+ if (!isPortRecordMode())
227
+ mkdirSync(skillsDir, { recursive: true });
225
228
  removedPaths.push(...stripManagedSkills(skillsDir));
226
229
  }
227
230
  if (removedPaths.length > 0) {
@@ -242,7 +245,8 @@ export function depositOpenClawL2ProductCommands(options = {}) {
242
245
  }
243
246
  const artifacts = generateOpenClawSkillArtifacts();
244
247
  for (const skillsDir of skillsDirs) {
245
- mkdirSync(skillsDir, { recursive: true });
248
+ if (!isPortRecordMode())
249
+ mkdirSync(skillsDir, { recursive: true });
246
250
  for (const artifact of artifacts) {
247
251
  const outcome = writeSkillArtifact(skillsDir, artifact);
248
252
  const abs = join(skillsDir, artifact.slug);
@@ -1,5 +1,5 @@
1
- /** Default slices log path relative to project root. */
2
- export declare const DEFAULT_SLICES_LOG_REL_PATH = "vbrief/.eval/slices.jsonl";
1
+ /** Default slices log path relative to an xbrief-layout project root (#1703). */
2
+ export declare const DEFAULT_SLICES_LOG_REL_PATH = "xbrief/.triage-cache/slices.jsonl";
3
3
  export declare const ENV_PROJECT_ROOT = "DEFT_PROJECT_ROOT";
4
4
  export declare const ENV_PROJECT_REPO = "DEFT_PROJECT_REPO";
5
5
  export declare const DEFAULT_ACTOR = "manual:operator";
@@ -1,5 +1,5 @@
1
- /** Default slices log path relative to project root. */
2
- export const DEFAULT_SLICES_LOG_REL_PATH = "vbrief/.eval/slices.jsonl";
1
+ /** Default slices log path relative to an xbrief-layout project root (#1703). */
2
+ export const DEFAULT_SLICES_LOG_REL_PATH = "xbrief/.triage-cache/slices.jsonl";
3
3
  export const ENV_PROJECT_ROOT = "DEFT_PROJECT_ROOT";
4
4
  export const ENV_PROJECT_REPO = "DEFT_PROJECT_REPO";
5
5
  export const DEFAULT_ACTOR = "manual:operator";