@deksden-com/dd-flow-cli 0.9.0-beta.137 → 0.9.0-beta.138

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 (260) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/README.md +9 -0
  3. package/dist/build-info.json +6 -6
  4. package/dist/cli/argument-values.js +5 -5
  5. package/dist/cli/command-inputs.js +89 -20
  6. package/dist/cli/command-metadata.js +197 -0
  7. package/dist/cli/command-option-descriptions.js +191 -0
  8. package/dist/cli/completion-cli.js +70 -0
  9. package/dist/cli/completion.js +57 -0
  10. package/dist/cli/error-output.js +52 -0
  11. package/dist/cli/executor-onboarding.js +76 -0
  12. package/dist/cli/flows.js +29 -0
  13. package/dist/cli/harnesses.js +84 -0
  14. package/dist/cli/help.js +240 -6
  15. package/dist/cli/input-preparation.js +54 -5
  16. package/dist/cli/memory-flow-admission.js +44 -0
  17. package/dist/cli/memory-init-invocation.js +78 -0
  18. package/dist/cli/memory-init.js +240 -0
  19. package/dist/cli/memory-storage-admission.js +53 -0
  20. package/dist/cli/models.js +39 -0
  21. package/dist/cli/native-hook-ingress.js +1 -1
  22. package/dist/cli/operator-profiles.js +61 -0
  23. package/dist/cli/output-options.js +35 -0
  24. package/dist/cli/response-file.js +71 -0
  25. package/dist/cli/run-cli.js +283 -160
  26. package/dist/cli/setup.js +149 -0
  27. package/dist/cli.js +54 -2
  28. package/dist/domain/stage-handler-identities.js +20 -0
  29. package/dist/harness-runtime/lib/daemon-operations.d.mts +1 -0
  30. package/dist/harness-runtime/lib/daemon-operations.mjs +4 -3
  31. package/dist/harness-runtime/lib/dd-agy-daemon.mjs +4 -2
  32. package/dist/harness-runtime/lib/dd-codex-daemon.mjs +11 -5
  33. package/dist/harness-runtime/lib/dd-codex.mjs +22 -10
  34. package/dist/harness-runtime/lib/dd-droid-daemon.mjs +2 -1
  35. package/dist/harness-runtime/lib/dd-droid.mjs +2 -1
  36. package/dist/harness-runtime/lib/dd-grok-daemon.mjs +4 -2
  37. package/dist/harness-runtime/lib/dd-opencode-daemon.mjs +6 -4
  38. package/dist/harness-runtime/lib/dd-zcode-daemon.mjs +9 -9
  39. package/dist/harness-runtime/lib/delegation-instructions.mjs +5 -3
  40. package/dist/harness-runtime/lib/lifecycle-command.mjs +1 -0
  41. package/dist/harness-runtime/lib/managed-daemon.d.mts +1 -0
  42. package/dist/harness-runtime/lib/managed-daemon.mjs +50 -15
  43. package/dist/harness-runtime/lib/managed-flow-env.mjs +15 -0
  44. package/dist/harness-runtime/lib/native-hook-command.mjs +1 -1
  45. package/dist/harness-runtime/lib/native-request-proof.d.mts +2 -0
  46. package/dist/harness-runtime/lib/native-request-proof.mjs +65 -0
  47. package/dist/harness-runtime/lib/opencode-plugin.mjs +2 -0
  48. package/dist/harness-runtime/lib/operation-progress.mjs +3 -1
  49. package/dist/runtime/context.js +1 -1
  50. package/dist/schemas/discovery-result.schema.json +184 -0
  51. package/dist/schemas/execution-bundle.schema.json +205 -0
  52. package/dist/schemas/execution-settings.schema.json +162 -0
  53. package/dist/schemas/flow-descriptor.schema.json +54 -0
  54. package/dist/schemas/flow-run.schema.json +22 -0
  55. package/dist/schemas/harness-catalog.schema.json +80 -0
  56. package/dist/schemas/mb-init-compose-result.schema.json +457 -0
  57. package/dist/schemas/mb-init-discover-result.schema.json +500 -0
  58. package/dist/schemas/mb-init-finish-result.schema.json +422 -0
  59. package/dist/schemas/mb-init-preflight-result.schema.json +367 -0
  60. package/dist/schemas/mb-init-review-result.schema.json +396 -0
  61. package/dist/schemas/mb-init-verify-result.schema.json +391 -0
  62. package/dist/schemas/memory-bootstrap-receipt-v2.schema.json +67 -0
  63. package/dist/schemas/memory-bootstrap-receipt.schema.json +354 -0
  64. package/dist/schemas/memory-composition-work-result.schema.json +38 -0
  65. package/dist/schemas/memory-repair-work-result.schema.json +49 -0
  66. package/dist/schemas/memory-review-correction-plan.schema.json +30 -0
  67. package/dist/schemas/memory-review-work-result.schema.json +43 -0
  68. package/dist/schemas/model-catalog.schema.json +153 -0
  69. package/dist/schemas/profile-settings.schema.json +122 -0
  70. package/dist/schemas/release-manifest.schema.json +291 -0
  71. package/dist/schemas/run-engine-binding.schema.json +1 -1
  72. package/dist/services/check-runner-evidence.js +51 -4
  73. package/dist/services/cli-operation-classifier.js +8 -47
  74. package/dist/services/cli-upgrade-allowlist.js +27 -0
  75. package/dist/services/code-checks.js +387 -34
  76. package/dist/services/controller-execution.js +88 -0
  77. package/dist/services/controller-fanout.js +71 -12
  78. package/dist/services/dashboard.js +8 -2
  79. package/dist/services/descriptor-coordinator-session.js +35 -0
  80. package/dist/services/descriptor-root-work.js +53 -0
  81. package/dist/services/descriptor-run-settlement.js +105 -0
  82. package/dist/services/descriptor-run-start.js +449 -0
  83. package/dist/services/descriptor-stage-coordinator.js +197 -0
  84. package/dist/services/descriptor-stage-settlement.js +222 -0
  85. package/dist/services/descriptor-stage-start.js +139 -0
  86. package/dist/services/discovery/agy-discovery.js +2 -0
  87. package/dist/services/discovery/codex-discovery.js +2 -0
  88. package/dist/services/discovery/droid-discovery.js +2 -0
  89. package/dist/services/discovery/grok-discovery.js +2 -0
  90. package/dist/services/discovery/opencode-discovery.js +2 -0
  91. package/dist/services/discovery/static.js +31 -0
  92. package/dist/services/discovery/zcode-discovery.js +2 -0
  93. package/dist/services/engines.js +39 -22
  94. package/dist/services/eval-snapshots.js +83 -25
  95. package/dist/services/execution-bundles.js +263 -0
  96. package/dist/services/execution-policy.js +20 -16
  97. package/dist/services/executor-onboarding.js +56 -0
  98. package/dist/services/external-work-launch.js +91 -11
  99. package/dist/services/flow-catalog.js +21 -0
  100. package/dist/services/flow-descriptors.js +82 -0
  101. package/dist/services/frozen-engine.js +242 -0
  102. package/dist/services/generic-execution.js +164 -0
  103. package/dist/services/harness-adapter.js +28 -2
  104. package/dist/services/harness-discovery.js +29 -0
  105. package/dist/services/harness-doctor.js +75 -0
  106. package/dist/services/harness-probe-effects.js +51 -0
  107. package/dist/services/harness-version-probe.js +100 -0
  108. package/dist/services/hooks.js +24 -6
  109. package/dist/services/hybrid-contracts.js +483 -0
  110. package/dist/services/ids.js +29 -1
  111. package/dist/services/installation-lock.js +95 -0
  112. package/dist/services/installed-flow-source.js +183 -0
  113. package/dist/services/lifecycle-invocations.js +257 -78
  114. package/dist/services/memory-accepted-composition.js +77 -0
  115. package/dist/services/memory-baseline-preservation.js +65 -0
  116. package/dist/services/memory-completed-correction-wave.js +320 -0
  117. package/dist/services/memory-compose-handler.js +258 -0
  118. package/dist/services/memory-composition-acceptance.js +199 -0
  119. package/dist/services/memory-composition-graph.js +134 -0
  120. package/dist/services/memory-composition-registration.js +146 -0
  121. package/dist/services/memory-composition-work-custody.js +151 -0
  122. package/dist/services/memory-composition-work-results.js +96 -0
  123. package/dist/services/memory-corrected-review-acceptance.js +129 -0
  124. package/dist/services/memory-corrected-review-batch.js +30 -0
  125. package/dist/services/memory-corrected-review-findings.js +106 -0
  126. package/dist/services/memory-corrected-review-inputs.js +210 -0
  127. package/dist/services/memory-corrected-review-projection.js +78 -0
  128. package/dist/services/memory-corrected-review-receipt.js +170 -0
  129. package/dist/services/memory-corrected-review-registration.js +191 -0
  130. package/dist/services/memory-correction-check-receipt.js +219 -0
  131. package/dist/services/memory-correction-input-owner.js +6 -0
  132. package/dist/services/memory-discover-handler.js +104 -0
  133. package/dist/services/memory-finish-evidence.js +435 -0
  134. package/dist/services/memory-finish-handler.js +215 -0
  135. package/dist/services/memory-finish-integration.js +280 -0
  136. package/dist/services/memory-finish-readiness.js +122 -0
  137. package/dist/services/memory-git-integration.js +151 -0
  138. package/dist/services/memory-historical-corrected-review.js +206 -0
  139. package/dist/services/memory-historical-original-review.js +130 -0
  140. package/dist/services/memory-historical-repair-registration.js +99 -0
  141. package/dist/services/memory-historical-second-review.js +128 -0
  142. package/dist/services/memory-init-bootstrap-readiness.js +210 -0
  143. package/dist/services/memory-init-contexts.js +89 -0
  144. package/dist/services/memory-init-controller-start.js +84 -0
  145. package/dist/services/memory-init-engine-release.js +223 -0
  146. package/dist/services/memory-init-git-policy.js +136 -0
  147. package/dist/services/memory-init-lint-capability.js +185 -0
  148. package/dist/services/memory-init-native-capacity.js +241 -0
  149. package/dist/services/memory-init-preflight.js +312 -0
  150. package/dist/services/memory-init-project-bootstrap.js +599 -0
  151. package/dist/services/memory-init-request-candidate.js +157 -0
  152. package/dist/services/memory-init-request-input.js +66 -0
  153. package/dist/services/memory-init-resource-storage.js +125 -0
  154. package/dist/services/memory-init-run-allocation.js +81 -0
  155. package/dist/services/memory-init-run-bundle.js +98 -0
  156. package/dist/services/memory-init-start.js +175 -0
  157. package/dist/services/memory-init-startup-custody.js +80 -0
  158. package/dist/services/memory-init-startup-input.js +240 -0
  159. package/dist/services/memory-init-storage.js +81 -0
  160. package/dist/services/memory-init-stores.js +359 -0
  161. package/dist/services/memory-init-worktrunk-capability.js +172 -0
  162. package/dist/services/memory-layer-publication.js +611 -0
  163. package/dist/services/memory-layer.js +156 -0
  164. package/dist/services/memory-lint-config.js +85 -0
  165. package/dist/services/memory-native-review-copy.js +165 -0
  166. package/dist/services/memory-normal-flow-entry.js +75 -0
  167. package/dist/services/memory-ordinary-defaults.js +112 -0
  168. package/dist/services/memory-preflight-bootstrap-custody.js +115 -0
  169. package/dist/services/memory-preflight-handler.js +259 -0
  170. package/dist/services/memory-repair-current-view.js +299 -0
  171. package/dist/services/memory-repair-document-delta.js +451 -0
  172. package/dist/services/memory-repair-history.js +491 -0
  173. package/dist/services/memory-repair-physical-binding.js +312 -0
  174. package/dist/services/memory-repair-publication-files.js +152 -0
  175. package/dist/services/memory-repair-publication-intent.js +27 -0
  176. package/dist/services/memory-repair-publication-plan.js +160 -0
  177. package/dist/services/memory-repair-publication-source.js +225 -0
  178. package/dist/services/memory-repair-publication.js +794 -0
  179. package/dist/services/memory-repair-registration.js +239 -0
  180. package/dist/services/memory-repair-work-baseline.js +413 -0
  181. package/dist/services/memory-repair-work-completion.js +97 -0
  182. package/dist/services/memory-repair-work-custody.js +73 -0
  183. package/dist/services/memory-repair-work-results.js +89 -0
  184. package/dist/services/memory-repair-workspace.js +252 -0
  185. package/dist/services/memory-repair-writer-copy.js +735 -0
  186. package/dist/services/memory-result-binding.js +173 -0
  187. package/dist/services/memory-retained-review-authority.js +129 -0
  188. package/dist/services/memory-retained-review-results.js +70 -0
  189. package/dist/services/memory-retained-second-baseline.js +102 -0
  190. package/dist/services/memory-retained-second-repairs.js +156 -0
  191. package/dist/services/memory-review-acceptance.js +214 -0
  192. package/dist/services/memory-review-correction-plan.js +171 -0
  193. package/dist/services/memory-review-handler.js +585 -0
  194. package/dist/services/memory-review-inputs.js +200 -0
  195. package/dist/services/memory-review-receipt.js +180 -0
  196. package/dist/services/memory-review-registration.js +108 -0
  197. package/dist/services/memory-review-work-custody.js +124 -0
  198. package/dist/services/memory-review-work-input.js +72 -0
  199. package/dist/services/memory-review-work-results.js +73 -0
  200. package/dist/services/memory-second-corrected-review-inputs.js +165 -0
  201. package/dist/services/memory-second-correction-plan.js +76 -0
  202. package/dist/services/memory-second-repair-baseline.js +91 -0
  203. package/dist/services/memory-second-repair-launch.js +614 -0
  204. package/dist/services/memory-second-repair-registration.js +88 -0
  205. package/dist/services/memory-second-repair-source.js +187 -0
  206. package/dist/services/memory-second-review-acceptance.js +115 -0
  207. package/dist/services/memory-source-observations.js +117 -0
  208. package/dist/services/memory-stage-dispatch.js +28 -0
  209. package/dist/services/memory-stage-results.js +199 -0
  210. package/dist/services/memory-verification-acceptance.js +135 -0
  211. package/dist/services/memory-verification-checks.js +252 -0
  212. package/dist/services/memory-verification-receipt.js +159 -0
  213. package/dist/services/memory-verify-handler.js +135 -0
  214. package/dist/services/memory-work-result-preparation.js +63 -0
  215. package/dist/services/model-catalog.js +109 -0
  216. package/dist/services/model-discovery.js +46 -0
  217. package/dist/services/operator-profiles.js +236 -0
  218. package/dist/services/projects.js +17 -2
  219. package/dist/services/recovery-snapshot-database.js +416 -1
  220. package/dist/services/release-archive-producer.js +52 -0
  221. package/dist/services/release-archive.js +143 -0
  222. package/dist/services/release-cache.js +142 -0
  223. package/dist/services/release-compatibility.js +18 -0
  224. package/dist/services/release-download.js +67 -0
  225. package/dist/services/release-envelope.js +104 -0
  226. package/dist/services/release-manifest.js +45 -0
  227. package/dist/services/release-payload.js +114 -0
  228. package/dist/services/release-producer.js +63 -0
  229. package/dist/services/release-provenance.js +160 -0
  230. package/dist/services/release-registry.js +66 -0
  231. package/dist/services/release-source.js +194 -0
  232. package/dist/services/repair-intents.js +1 -1
  233. package/dist/services/review-copy.js +10 -2
  234. package/dist/services/run-control.js +80 -9
  235. package/dist/services/run-controller-capture.js +10 -3
  236. package/dist/services/run-controller-process.js +21 -0
  237. package/dist/services/run-controller-recovery.js +3 -1
  238. package/dist/services/run-controller-state.js +1 -1
  239. package/dist/services/run-controller.js +101 -40
  240. package/dist/services/run-recovery-guard.js +2 -0
  241. package/dist/services/run-recovery.js +145 -5
  242. package/dist/services/run-start-custody.js +177 -0
  243. package/dist/services/runs.js +319 -25
  244. package/dist/services/setup.js +377 -0
  245. package/dist/services/stage-context.js +9 -1
  246. package/dist/services/stage-handlers.js +74 -0
  247. package/dist/services/stage-report-renderer.js +63 -0
  248. package/dist/services/stage-work-graph.js +17 -0
  249. package/dist/services/vnext-code.js +3 -3
  250. package/dist/services/vnext-execution-profile.js +2 -2
  251. package/dist/services/vnext-fanout.js +70 -9
  252. package/dist/services/vnext-merge.js +8 -3
  253. package/dist/services/vnext-plan-review.js +6 -4
  254. package/dist/services/work-registry.js +616 -71
  255. package/dist/services/workspace-files.js +1 -1
  256. package/dist/storage/database.js +84 -6
  257. package/dist/storage/writer-contract.js +11 -7
  258. package/package.json +13 -3
  259. package/tools/create-canon-release.mjs +33 -0
  260. package/tools/produce-hybrid-release.mjs +41 -0
@@ -0,0 +1,100 @@
1
+ import { spawn } from "node:child_process";
2
+ import path from "node:path";
3
+ import { parse } from "semver";
4
+ import { stopProcessGroup } from "../harness-runtime/lib/managed-daemon.mjs";
5
+ import { AppError } from "../shared/errors.js";
6
+ import { runScopedProbe } from "./harness-probe-effects.js";
7
+ // Even --version runs operator-installed code. Do not infer credential/write
8
+ // isolation from an argument spelling or execute it during static discovery.
9
+ export const versionProbeEffects = Object.freeze({
10
+ child_process: true, service_process: false, credential_access: "possible",
11
+ filesystem: "temporary_or_runtime_writes", model_turn: "not_requested",
12
+ source_owner: "services/harness-version-probe.ts:probeHarnessVersion"
13
+ });
14
+ /** Recognized version fields only; unrelated diagnostic numbers are not facts. */
15
+ export function parseHarnessVersion(harness, stdout) {
16
+ const normalize = (value) => {
17
+ const version = parse(value);
18
+ return version ? `${version.version}${version.build.length ? `+${version.build.join(".")}` : ""}` : null;
19
+ };
20
+ if (harness === "grok") {
21
+ try {
22
+ const value = JSON.parse(stdout);
23
+ if (!value || typeof value !== "object" || Array.isArray(value))
24
+ return null;
25
+ const reported = value.currentVersion;
26
+ return typeof reported === "string" ? normalize(reported.trim().split(/\s+/)[0]) : null;
27
+ }
28
+ catch {
29
+ return null;
30
+ }
31
+ }
32
+ const labels = {
33
+ codex: "codex(?:-cli)?", zcode: "zcode", agy: "(?:agy|antigravity)", opencode: "opencode", droid: "droid"
34
+ };
35
+ const pattern = new RegExp(`^(?:${labels[harness]}\\s+)?(v?[0-9]+\\.[0-9]+\\.[0-9]+(?:-[A-Za-z0-9.-]+)?(?:\\+[A-Za-z0-9.-]+)?)$`, "i");
36
+ const versions = new Set(stdout.split(/\r?\n/).flatMap(line => {
37
+ const matched = line.trim().match(pattern)?.[1];
38
+ const version = matched ? normalize(matched) : null;
39
+ return version ? [version] : [];
40
+ }));
41
+ return versions.size === 1 ? [...versions][0] : null;
42
+ }
43
+ /** Diagnostic only: a version is not protocol, account or flow qualification. */
44
+ export function probeHarnessVersion(input) {
45
+ const timeoutMs = input.timeoutMs ?? 3000;
46
+ if (!["codex", "zcode", "agy", "opencode", "grok", "droid"].includes(input.harness)) {
47
+ throw new AppError("usage", "Unknown harness family", 2, { effect: "no_effect" });
48
+ }
49
+ if (!path.isAbsolute(input.executable) || !Number.isSafeInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > 60_000) {
50
+ throw new AppError("usage", "Version probe requires an absolute executable and a timeout of 1–60000 ms", 2, { effect: "no_effect" });
51
+ }
52
+ return runScopedProbe(versionProbeEffects, input.scope, () => new Promise((resolve, reject) => {
53
+ const args = input.harness === "grok" ? ["version", "--json"] : ["--version"];
54
+ const detached = process.platform !== "win32";
55
+ const child = spawn(input.executable, args, { env: input.env, detached, stdio: ["ignore", "pipe", "pipe"] });
56
+ let stdout = "";
57
+ let bytes = 0;
58
+ let failure;
59
+ let cleanup;
60
+ const stop = (code, message) => {
61
+ failure ??= new AppError(code, message, 1, { phase: "version_probe", effect: "process_dispatched" });
62
+ cleanup ??= stopProcessGroup(child, 1000, { detached });
63
+ // Observe immediately; close may arrive after asynchronous cleanup failure.
64
+ void cleanup.catch(() => { });
65
+ };
66
+ const timer = setTimeout(() => stop("probe_timeout", "Version probe exceeded its deadline"), timeoutMs);
67
+ child.stdout.setEncoding("utf8").on("data", (chunk) => {
68
+ bytes += Buffer.byteLength(chunk);
69
+ if (bytes > 64_000)
70
+ stop("probe_output_limit", "Version probe exceeded its output limit");
71
+ else
72
+ stdout += chunk;
73
+ });
74
+ child.stderr.on("data", (chunk) => {
75
+ bytes += chunk.length;
76
+ if (bytes > 64_000)
77
+ stop("probe_output_limit", "Version probe exceeded its output limit");
78
+ });
79
+ child.on("error", () => { failure ??= new AppError("probe_launch_failed", "Version probe could not start", 1); });
80
+ child.on("close", (code, signal) => {
81
+ clearTimeout(timer);
82
+ void (async () => {
83
+ try {
84
+ await cleanup;
85
+ if (failure)
86
+ throw failure;
87
+ if (code !== 0 || signal)
88
+ throw new AppError("probe_failed", "Version probe did not exit successfully", 1);
89
+ // Never expose arbitrary subprocess output: it can contain secrets.
90
+ const version = parseHarnessVersion(input.harness, stdout);
91
+ resolve({ harness: input.harness, version, status: version ? "observed" : "unrecognized",
92
+ compatible: "unknown", protocol: "unknown", auth: "unknown", qualified: "unknown" });
93
+ }
94
+ catch (error) {
95
+ reject(error instanceof AppError ? error : new AppError("probe_cleanup_unconfirmed", "Version probe cleanup could not be confirmed", 1));
96
+ }
97
+ })();
98
+ });
99
+ }));
100
+ }
@@ -9,6 +9,8 @@ import { parseJsonObject } from "../shared/json.js";
9
9
  import { canonicalPath, ensureDir, resolveProjectRoot } from "../storage/paths.js";
10
10
  import { resolveWorkReference } from "../storage/work-references.js";
11
11
  import { appendAudit } from "./audit.js";
12
+ import { memoryRepairAssignedHookCwd } from "./memory-repair-physical-binding.js";
13
+ import { memoryNativeReviewAssignedHookCwd } from "./memory-native-review-copy.js";
12
14
  import { prepareTextFile, prepareJsonText, prepareError } from "../cli/input-preparation.js";
13
15
  import { nativeSessionIdentity, storageSessionId } from "./session-identity.js";
14
16
  import { assertRecoveryHookCurrent } from "./run-recovery.js";
@@ -714,6 +716,11 @@ export function handleDroidEvent(context, input) {
714
716
  return handleControlledToolEvent(context, input, event, "droid-cli");
715
717
  }
716
718
  /** Stable project identity is not the native Session's execution workspace. */
719
+ function requiresAssignedLifecycleCwd(facts) {
720
+ // Settlement and user interaction address the retained RUN explicitly;
721
+ // their tools/checks receive owned paths, not the shell's working directory.
722
+ return !facts || !["stage_finish", "stage_pause", "stage_resume", "work_finish", "work_fail"].includes(facts.invocation.operation);
723
+ }
717
724
  function assignedLifecycleCwd(context, projectRoot, facts, providerSessionId, command, observedCwd, identity, harness) {
718
725
  const auxiliary = continuationCommand(command);
719
726
  if ((!facts && !auxiliary) || facts?.analysis.supported === false)
@@ -723,7 +730,9 @@ function assignedLifecycleCwd(context, projectRoot, facts, providerSessionId, co
723
730
  const issuedRunId = facts && !facts.runId && !facts.workId && !facts.bootstrapStageStart && constraint ? observedLifecycleInvocation(context, command, constraint, identity ? { identity } : undefined)?.scope.runId : null;
724
731
  if (facts?.invocation.operation.startsWith("stage_") && !facts.bootstrapStageStart && !facts.runId && !issuedRunId)
725
732
  throw new AppError("invocation_assignment_missing", "Short lifecycle call has no unique issued RUN assignment; its workspace cannot be inferred", 1, { phase: "prepare", effect: "no_effect", recoverable: false });
726
- const expected = controlledLifecycleCwd(context, projectRoot, facts, providerSessionId, auxiliary, issuedRunId);
733
+ if (!requiresAssignedLifecycleCwd(facts))
734
+ return undefined;
735
+ const expected = controlledLifecycleCwd(context, projectRoot, facts, providerSessionId, auxiliary, issuedRunId, observedCwd);
727
736
  // Unknown CLI targets have no assigned workspace. Recording their native
728
737
  // observation must not turn the stable identity root into cwd authority.
729
738
  if (!expected)
@@ -737,7 +746,7 @@ function assignedLifecycleCwd(context, projectRoot, facts, providerSessionId, co
737
746
  // physical process directory, rather than inventing native observation.
738
747
  return expected;
739
748
  }
740
- function controlledLifecycleCwd(context, projectRoot, facts, providerSessionId, auxiliary, issuedRunId) {
749
+ function controlledLifecycleCwd(context, projectRoot, facts, providerSessionId, auxiliary, issuedRunId, observedCwd) {
741
750
  if (facts?.bootstrapStageStart)
742
751
  return projectRoot;
743
752
  const project = context.db.get("SELECT id FROM projects WHERE root = ?", [projectRoot]);
@@ -768,6 +777,14 @@ function controlledLifecycleCwd(context, projectRoot, facts, providerSessionId,
768
777
  if (!run)
769
778
  return undefined; // Hook ingress does not validate a mistyped CLI target.
770
779
  if (work) {
780
+ const repair = memoryRepairAssignedHookCwd(context, { projectRoot, projectId: project.id, runId: run.id,
781
+ workId: work.work_id, providerSessionId, ...(observedCwd ? { observedCwd: resolveProjectRoot(observedCwd) } : {}),
782
+ ...(facts?.invocation.expectedCwd ? { literalExecutionCwd: resolveProjectRoot(facts.invocation.expectedCwd) } : {}) });
783
+ if (repair)
784
+ return resolveProjectRoot(repair.root);
785
+ const nativeReview = memoryNativeReviewAssignedHookCwd(context, { projectId: project.id, runId: run.id, workId: work.work_id, providerSessionId });
786
+ if (nativeReview)
787
+ return resolveProjectRoot(nativeReview);
771
788
  // PROTOCOLIZE provisions the feature checkout after its coordinator
772
789
  // Session has launched in the stable project root. Its transition Work
773
790
  // must keep that physical route until the Stage is complete. Child Works
@@ -862,12 +879,13 @@ function handleControlledToolEvent(context, input, event, harness) {
862
879
  }
863
880
  // These controlled platforms additionally qualify their native launch
864
881
  // route against the stable project root when no CLI target is assigned.
865
- const expectedCwd = shellRefusal ? observedCwd : controlledLifecycleCwd(context, expectedRoot, lifecycle, providerSessionId, auxiliary, issuedRunId) ?? expectedRoot;
866
- const executionRoute = shellRefusal ? undefined : lifecycle?.invocation.expectedCwd ?? auxiliary?.expectedCwd;
882
+ const workspaceBound = requiresAssignedLifecycleCwd(lifecycle);
883
+ const expectedCwd = shellRefusal || !workspaceBound ? observedCwd : controlledLifecycleCwd(context, expectedRoot, lifecycle, providerSessionId, auxiliary, issuedRunId, observedCwd) ?? expectedRoot;
884
+ const executionRoute = shellRefusal || !workspaceBound ? undefined : lifecycle?.invocation.expectedCwd ?? auxiliary?.expectedCwd;
867
885
  if (executionRoute && resolveProjectRoot(executionRoute) !== expectedCwd) {
868
886
  throw new AppError(`${errorPrefix}_directory_mismatch`, "Literal shell cd route does not match the assigned lifecycle workspace", 1, { expected: expectedCwd, actual: executionRoute, actual_provenance: "shell_literal_route", effect: "no_effect", recoverable: false });
869
887
  }
870
- if (!executionRoute && observedCwd !== expectedCwd) {
888
+ if (workspaceBound && !executionRoute && observedCwd !== expectedCwd) {
871
889
  throw new AppError(`${errorPrefix}_directory_mismatch`, `${label} ${agy ? "launch route" : "Session directory"} does not match the assigned execution workspace`, 1, { expected: expectedCwd, actual: observedCwd, effect: "no_effect", recoverable: false, ...(agy ? { actual_provenance: stringValue(event.cwd_provenance) ?? "unknown" } : {}) });
872
890
  }
873
891
  const bootstrapStageStart = !shellRefusal && lifecycle?.bootstrapStageStart;
@@ -906,7 +924,7 @@ function handleControlledToolEvent(context, input, event, harness) {
906
924
  let inserted = false;
907
925
  const receipt = observeLifecycleInvocation(context, {
908
926
  currentEventKey: baseKey,
909
- command, harness, projectId: project.id, ...(!shellRefusal ? { executionCwd: expectedCwd } : {}), identity: { daemonId, rootSessionId: nativeParentId ?? providerSessionId, sessionId: providerSessionId, parentSessionId: nativeParentId ?? null, toolCallId: toolCallId },
927
+ command, harness, projectId: project.id, ...(!shellRefusal && workspaceBound ? { executionCwd: expectedCwd } : {}), identity: { daemonId, rootSessionId: nativeParentId ?? providerSessionId, sessionId: providerSessionId, parentSessionId: nativeParentId ?? null, toolCallId: toolCallId },
910
928
  recordReceipt: scope => { inserted = persist(scope); return baseKey; }
911
929
  });
912
930
  const admitted = { ...result(inserted), ...lifecycleObservationResult(receipt), ...(receipt.invocationId ? { invocation_id: receipt.invocationId } : {}) };