@deftai/directive-core 0.106.0 → 0.108.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 (249) hide show
  1. package/dist/architecture/sor-preflight.js +2 -0
  2. package/dist/check/cached-orchestrator.js +28 -3
  3. package/dist/check/gate-lists.js +2 -0
  4. package/dist/check/named-cause.js +18 -3
  5. package/dist/codebase/provider.js +7 -1
  6. package/dist/delivery-attempt/handoff.js +1 -1
  7. package/dist/design-critique/citation-grammar.d.ts +53 -0
  8. package/dist/design-critique/citation-grammar.js +303 -0
  9. package/dist/design-critique/completed-arc-record.d.ts +62 -0
  10. package/dist/design-critique/completed-arc-record.js +232 -0
  11. package/dist/design-critique/exclusive-chip.d.ts +33 -0
  12. package/dist/design-critique/exclusive-chip.js +68 -0
  13. package/dist/design-critique/parent-audit.d.ts +59 -0
  14. package/dist/design-critique/parent-audit.js +121 -0
  15. package/dist/doctor/checks.d.ts +6 -0
  16. package/dist/doctor/checks.js +35 -0
  17. package/dist/freshness/bind.d.ts +32 -3
  18. package/dist/freshness/bind.js +58 -12
  19. package/dist/hooks/classify/host-session-identity.d.ts +76 -0
  20. package/dist/hooks/classify/host-session-identity.js +470 -0
  21. package/dist/hooks/classify/index.d.ts +3 -2
  22. package/dist/hooks/classify/index.js +3 -2
  23. package/dist/hooks/classify/paths.d.ts +7 -0
  24. package/dist/hooks/classify/paths.js +35 -0
  25. package/dist/hooks/classify/stdin.d.ts +5 -0
  26. package/dist/hooks/classify/stdin.js +27 -0
  27. package/dist/hooks/dest-form.d.ts +46 -0
  28. package/dist/hooks/dest-form.js +575 -0
  29. package/dist/hooks/dispatcher.d.ts +69 -2
  30. package/dist/hooks/dispatcher.js +609 -45
  31. package/dist/hooks/fixtures/cases.d.ts +16 -2
  32. package/dist/hooks/fixtures/cases.js +175 -0
  33. package/dist/hooks/index.d.ts +1 -0
  34. package/dist/hooks/index.js +1 -0
  35. package/dist/hooks/scope.js +3 -1
  36. package/dist/init-deposit/agent-hooks.d.ts +2 -1
  37. package/dist/init-deposit/agent-hooks.js +8 -1
  38. package/dist/init-deposit/hook-runtime-travel.d.ts +77 -0
  39. package/dist/init-deposit/hook-runtime-travel.js +269 -0
  40. package/dist/intake/clause-derivation.js +9 -3
  41. package/dist/intake/github-auth-modes-cli.js +14 -2
  42. package/dist/intake/github-auth-modes.d.ts +54 -9
  43. package/dist/intake/github-auth-modes.js +326 -123
  44. package/dist/intake/issue-ingest.js +62 -2
  45. package/dist/intake/platform-capabilities.d.ts +9 -2
  46. package/dist/intake/platform-capabilities.js +38 -9
  47. package/dist/lifecycle/completed-tracked-on-delivery.d.ts +26 -0
  48. package/dist/lifecycle/completed-tracked-on-delivery.js +37 -14
  49. package/dist/lifecycle/completed-write-guard.d.ts +48 -0
  50. package/dist/lifecycle/completed-write-guard.js +373 -0
  51. package/dist/lifecycle/index.d.ts +1 -0
  52. package/dist/lifecycle/index.js +1 -0
  53. package/dist/literal-acceptance/capture.d.ts +16 -0
  54. package/dist/literal-acceptance/capture.js +75 -7
  55. package/dist/literal-acceptance/evaluate.js +25 -3
  56. package/dist/literal-acceptance/index.d.ts +2 -2
  57. package/dist/literal-acceptance/index.js +2 -2
  58. package/dist/literal-acceptance/run.js +9 -3
  59. package/dist/literal-acceptance/types.d.ts +6 -0
  60. package/dist/literal-acceptance/types.js +6 -0
  61. package/dist/orphan-active/evaluate.d.ts +25 -0
  62. package/dist/orphan-active/evaluate.js +193 -128
  63. package/dist/orphan-active/index.d.ts +1 -0
  64. package/dist/orphan-active/index.js +1 -0
  65. package/dist/orphan-active/issue-state.d.ts +121 -0
  66. package/dist/orphan-active/issue-state.js +278 -0
  67. package/dist/platform/cursor-managed-runtime.d.ts +95 -0
  68. package/dist/platform/cursor-managed-runtime.js +241 -0
  69. package/dist/platform/index.d.ts +1 -0
  70. package/dist/platform/index.js +1 -0
  71. package/dist/platform/platform-capabilities.d.ts +23 -1
  72. package/dist/platform/platform-capabilities.js +55 -15
  73. package/dist/policy/ceremony-dial.js +5 -9
  74. package/dist/policy/host-hooks.js +4 -9
  75. package/dist/policy/org-force-on-migration.js +5 -10
  76. package/dist/policy/plan-extensions.d.ts +14 -2
  77. package/dist/policy/plan-extensions.js +24 -3
  78. package/dist/policy/product-signal.js +5 -10
  79. package/dist/policy/require-human-merge.js +5 -9
  80. package/dist/policy/resolve.js +77 -16
  81. package/dist/policy/runtime-authority.d.ts +18 -0
  82. package/dist/policy/runtime-authority.js +11 -0
  83. package/dist/policy/value-feedback.js +9 -18
  84. package/dist/policy/write-fence.js +3 -0
  85. package/dist/pr-closeout-attestable/evaluate.d.ts +80 -0
  86. package/dist/pr-closeout-attestable/evaluate.js +306 -0
  87. package/dist/pr-closeout-attestable/index.d.ts +2 -0
  88. package/dist/pr-closeout-attestable/index.js +2 -0
  89. package/dist/pr-protected-issues/gh.d.ts +6 -2
  90. package/dist/pr-protected-issues/gh.js +7 -3
  91. package/dist/pr-wait-mergeable/cascade.d.ts +9 -1
  92. package/dist/pr-wait-mergeable/cascade.js +21 -1
  93. package/dist/pr-wait-mergeable/types.d.ts +2 -0
  94. package/dist/pr-wait-mergeable/wrappers.d.ts +6 -0
  95. package/dist/pr-wait-mergeable/wrappers.js +11 -0
  96. package/dist/preflight/evaluate.d.ts +15 -0
  97. package/dist/preflight/evaluate.js +29 -3
  98. package/dist/preflight-cache/evaluate.js +9 -3
  99. package/dist/product-first-done-gate/acceptance-resolver.d.ts +14 -2
  100. package/dist/product-first-done-gate/acceptance-resolver.js +13 -2
  101. package/dist/product-first-done-gate/evaluate.js +53 -12
  102. package/dist/release/cli-drift-report.d.ts +68 -0
  103. package/dist/release/cli-drift-report.js +189 -0
  104. package/dist/release/index.d.ts +1 -0
  105. package/dist/release/index.js +1 -0
  106. package/dist/release/issue-state-fetch.d.ts +5 -3
  107. package/dist/release/issue-state-fetch.js +86 -21
  108. package/dist/release/native-steps.js +1 -0
  109. package/dist/release/pipeline.js +19 -0
  110. package/dist/release/types.d.ts +14 -0
  111. package/dist/render/constants.d.ts +4 -0
  112. package/dist/render/constants.js +11 -8
  113. package/dist/render/export-spec.js +31 -5
  114. package/dist/render/index.d.ts +1 -1
  115. package/dist/render/index.js +1 -1
  116. package/dist/render/prd-render.d.ts +4 -1
  117. package/dist/render/prd-render.js +82 -23
  118. package/dist/render/project-render.js +14 -7
  119. package/dist/render/scope-outlook.d.ts +2 -0
  120. package/dist/render/scope-outlook.js +3 -0
  121. package/dist/render/spec-render.js +2 -2
  122. package/dist/resolution/package-manager.d.ts +33 -4
  123. package/dist/resolution/package-manager.js +210 -9
  124. package/dist/review-monitor/constants.d.ts +7 -0
  125. package/dist/review-monitor/constants.js +7 -0
  126. package/dist/review-monitor/github-lease.d.ts +98 -1
  127. package/dist/review-monitor/github-lease.js +182 -1
  128. package/dist/review-monitor/lease-comment.d.ts +36 -0
  129. package/dist/review-monitor/lease-comment.js +103 -2
  130. package/dist/scm/call.js +12 -3
  131. package/dist/scm/design-critique-chip.d.ts +38 -0
  132. package/dist/scm/design-critique-chip.js +187 -0
  133. package/dist/scm/gh-rest.d.ts +9 -1
  134. package/dist/scm/gh-rest.js +103 -0
  135. package/dist/scm/index.d.ts +1 -0
  136. package/dist/scm/index.js +1 -0
  137. package/dist/scm/main.d.ts +3 -0
  138. package/dist/scm/main.js +15 -1
  139. package/dist/scm/readiness-cli.d.ts +2 -0
  140. package/dist/scm/readiness-cli.js +42 -1
  141. package/dist/scm/readiness.d.ts +4 -1
  142. package/dist/scm/readiness.js +35 -5
  143. package/dist/scope/decompose.js +2 -1
  144. package/dist/scope/delivery-evidence.d.ts +27 -1
  145. package/dist/scope/index.d.ts +1 -0
  146. package/dist/scope/index.js +1 -0
  147. package/dist/scope/lifecycle-write.d.ts +24 -0
  148. package/dist/scope/lifecycle-write.js +64 -0
  149. package/dist/scope/main.js +3 -1
  150. package/dist/scope/project-definition-sync.js +14 -7
  151. package/dist/scope/transition.js +90 -11
  152. package/dist/scope-provenance/evaluate.js +5 -1
  153. package/dist/session/git.d.ts +42 -0
  154. package/dist/session/git.js +219 -3
  155. package/dist/session/occupancy.d.ts +239 -12
  156. package/dist/session/occupancy.js +820 -27
  157. package/dist/session/ritual-sentinel.d.ts +5 -0
  158. package/dist/session/ritual-sentinel.js +5 -0
  159. package/dist/session/session-ready.d.ts +5 -1
  160. package/dist/session/session-ready.js +98 -8
  161. package/dist/session/session-start.d.ts +17 -1
  162. package/dist/session/session-start.js +49 -17
  163. package/dist/session/toolchain-preflight.d.ts +13 -3
  164. package/dist/session/toolchain-preflight.js +93 -18
  165. package/dist/session/verify-session-ritual.d.ts +33 -3
  166. package/dist/session/verify-session-ritual.js +89 -19
  167. package/dist/slice/constants.d.ts +1 -1
  168. package/dist/spec-authority/constants.d.ts +10 -2
  169. package/dist/spec-authority/constants.js +53 -8
  170. package/dist/spec-authority/resolver.d.ts +3 -0
  171. package/dist/spec-authority/resolver.js +55 -7
  172. package/dist/subprocess/max-buffer.d.ts +14 -0
  173. package/dist/subprocess/max-buffer.js +15 -0
  174. package/dist/swarm/complete-cohort.d.ts +2 -0
  175. package/dist/swarm/complete-cohort.js +21 -13
  176. package/dist/swarm/index.d.ts +1 -0
  177. package/dist/swarm/index.js +1 -0
  178. package/dist/swarm/launch-cli.js +53 -33
  179. package/dist/swarm/launch.d.ts +77 -0
  180. package/dist/swarm/launch.js +248 -38
  181. package/dist/swarm/pre-dispatch-cli.js +2 -1
  182. package/dist/swarm/pre-dispatch.js +10 -1
  183. package/dist/swarm/subagent-status-dir.d.ts +27 -0
  184. package/dist/swarm/subagent-status-dir.js +42 -0
  185. package/dist/swarm/worktrees.d.ts +17 -3
  186. package/dist/swarm/worktrees.js +48 -4
  187. package/dist/triage/actions/index.d.ts +4 -0
  188. package/dist/triage/actions/index.js +6 -0
  189. package/dist/triage/evaluate/evaluate.d.ts +11 -0
  190. package/dist/triage/evaluate/evaluate.js +169 -0
  191. package/dist/triage/evaluate/github.d.ts +16 -0
  192. package/dist/triage/evaluate/github.js +153 -0
  193. package/dist/triage/evaluate/index.d.ts +9 -0
  194. package/dist/triage/evaluate/index.js +8 -0
  195. package/dist/triage/evaluate/paths.d.ts +7 -0
  196. package/dist/triage/evaluate/paths.js +25 -0
  197. package/dist/triage/evaluate/sink.d.ts +5 -0
  198. package/dist/triage/evaluate/sink.js +52 -0
  199. package/dist/triage/evaluate/types.d.ts +93 -0
  200. package/dist/triage/evaluate/types.js +13 -0
  201. package/dist/triage/evaluate/validity.d.ts +8 -0
  202. package/dist/triage/evaluate/validity.js +87 -0
  203. package/dist/triage/evaluate/value.d.ts +12 -0
  204. package/dist/triage/evaluate/value.js +33 -0
  205. package/dist/triage/evaluate/wip-census.d.ts +5 -0
  206. package/dist/triage/evaluate/wip-census.js +39 -0
  207. package/dist/triage/evaluate/worktrees.d.ts +8 -0
  208. package/dist/triage/evaluate/worktrees.js +68 -0
  209. package/dist/triage/evaluate/xbrief-refs.d.ts +8 -0
  210. package/dist/triage/evaluate/xbrief-refs.js +60 -0
  211. package/dist/triage/help/registry-data.d.ts +21 -7
  212. package/dist/triage/help/registry-data.js +53 -5
  213. package/dist/triage/index.d.ts +1 -0
  214. package/dist/triage/index.js +1 -0
  215. package/dist/triage/scope/mutations-core.d.ts +2 -6
  216. package/dist/triage/scope/mutations-core.js +23 -55
  217. package/dist/triage/scope-drift/add-ignore.js +5 -39
  218. package/dist/triage/subscribe/index.d.ts +2 -6
  219. package/dist/triage/subscribe/index.js +15 -65
  220. package/dist/triage/welcome/writers.js +15 -74
  221. package/dist/value/feedback-file.d.ts +17 -2
  222. package/dist/value/feedback-file.js +80 -6
  223. package/dist/vbrief-build/index.d.ts +2 -1
  224. package/dist/vbrief-build/index.js +2 -1
  225. package/dist/vbrief-build/parity-scenarios.js +5 -5
  226. package/dist/vbrief-build/project-definition-io.d.ts +63 -3
  227. package/dist/vbrief-build/project-definition-io.js +357 -31
  228. package/dist/vbrief-build/project-definition-mutation.d.ts +32 -0
  229. package/dist/vbrief-build/project-definition-mutation.js +43 -0
  230. package/dist/vbrief-reconcile/labels.d.ts +1 -0
  231. package/dist/vbrief-reconcile/labels.js +30 -0
  232. package/dist/vbrief-validate/conformance.d.ts +1 -0
  233. package/dist/vbrief-validate/conformance.js +85 -8
  234. package/dist/vbrief-validate/main.js +2 -0
  235. package/dist/vbrief-validate/precutover.js +5 -10
  236. package/dist/vbrief-validation/story-quality.d.ts +7 -0
  237. package/dist/vbrief-validation/story-quality.js +8 -1
  238. package/dist/verify-ac/clauses.d.ts +62 -2
  239. package/dist/verify-ac/clauses.js +183 -111
  240. package/dist/verify-ac/index.d.ts +1 -1
  241. package/dist/verify-ac/index.js +1 -1
  242. package/dist/verify-env/node-runtime.d.ts +8 -4
  243. package/dist/verify-env/node-runtime.js +9 -6
  244. package/dist/verify-env/toolchain-check.d.ts +35 -3
  245. package/dist/verify-env/toolchain-check.js +155 -36
  246. package/dist/verify-source/project-definition-mutation-boundary.d.ts +104 -0
  247. package/dist/verify-source/project-definition-mutation-boundary.js +326 -0
  248. package/dist/xbrief-migrate/agents-header.js +69 -7
  249. package/package.json +7 -3
@@ -1,8 +1,8 @@
1
- import { existsSync, readFileSync } from "node:fs";
2
- import { join } from "node:path";
3
- import { resolveLifecycleLayout, resolveLifecycleRoot, resolveProjectDefinitionPath, } from "../layout/resolve.js";
4
- import { SPEC_RENDER_BANNER } from "../render/constants.js";
5
- import { contentHasGeneratedPdSource, contentHasGeneratedSpecSource, EXPORT_SPEC_PD_BANNER, GENERATED_SPEC_PURPOSE, } from "./constants.js";
1
+ import { existsSync, readFileSync, statSync } from "node:fs";
2
+ import { isAbsolute, join, resolve } from "node:path";
3
+ import { isDeepStrictEqual } from "node:util";
4
+ import { resolveLifecycleLayout, resolveLifecycleRoot, resolveProjectDefinitionPath, resolveSpecArtifactPath, } from "../layout/resolve.js";
5
+ import { buildExportSpecPdBanner, buildGeneratedArtifactBanner, contentHasGeneratedPdSource, contentHasGeneratedSpecSource, GENERATED_SPEC_PURPOSE, generatedSpecSourcePaths, } from "./constants.js";
6
6
  export function resolveSpecAuthority(projectRoot) {
7
7
  const root = projectRoot;
8
8
  let layout;
@@ -20,13 +20,17 @@ export function resolveSpecAuthority(projectRoot) {
20
20
  const specPath = join(vbriefDir, `specification${layout.artifactSuffix}`);
21
21
  const hasSpec = existsSync(specPath);
22
22
  const kind = hasSpec ? "full-spec" : "greenfield";
23
- const banner = kind === "full-spec" ? SPEC_RENDER_BANNER : EXPORT_SPEC_PD_BANNER;
23
+ const sourcePath = hasSpec ? specPath : projectDefPath;
24
+ const banner = hasSpec
25
+ ? buildGeneratedArtifactBanner("task spec:render", "rendered specification", sourcePath)
26
+ : buildExportSpecPdBanner(sourcePath);
24
27
  return {
25
28
  kind,
26
29
  projectRoot: root,
27
30
  vbriefDir,
28
31
  projectDefPath,
29
32
  specPath: hasSpec ? specPath : null,
33
+ sourcePath,
30
34
  banner,
31
35
  };
32
36
  }
@@ -39,12 +43,56 @@ export function readSpecMarkdown(projectRoot) {
39
43
  return "";
40
44
  }
41
45
  }
46
+ function sourcePathFromMarker(projectRoot, source) {
47
+ return isAbsolute(source) ? source : resolve(projectRoot, source);
48
+ }
49
+ function contentMatchesResolvedSpecSource(projectRoot, content, resolvedSourcePath) {
50
+ if (contentHasGeneratedSpecSource(content, resolvedSourcePath))
51
+ return true;
52
+ let resolvedSource;
53
+ try {
54
+ resolvedSource = JSON.parse(readFileSync(resolvedSourcePath, "utf8"));
55
+ }
56
+ catch {
57
+ return false;
58
+ }
59
+ for (const source of generatedSpecSourcePaths(content)) {
60
+ try {
61
+ const candidate = sourcePathFromMarker(projectRoot, source);
62
+ if (!statSync(candidate).isFile())
63
+ continue;
64
+ // Explicit --spec paths remain valid aliases only when they identify the
65
+ // same JSON authority as the layout-resolved specification artifact.
66
+ if (isDeepStrictEqual(JSON.parse(readFileSync(candidate, "utf8")), resolvedSource)) {
67
+ return true;
68
+ }
69
+ }
70
+ catch {
71
+ // Missing or unreadable explicit source markers are not resolved authority.
72
+ }
73
+ }
74
+ return false;
75
+ }
76
+ /** True when the markdown source marker resolves to the project's specification authority. */
77
+ export function contentHasResolvedSpecSource(projectRoot, content) {
78
+ let resolvedSourcePath;
79
+ try {
80
+ resolvedSourcePath = resolveSpecArtifactPath(projectRoot);
81
+ }
82
+ catch {
83
+ return false;
84
+ }
85
+ if (!existsSync(resolvedSourcePath))
86
+ return false;
87
+ return contentMatchesResolvedSpecSource(projectRoot, content, resolvedSourcePath);
88
+ }
42
89
  export function isFullSpecState(projectRoot) {
43
90
  const authority = resolveSpecAuthority(projectRoot);
44
91
  if (authority?.kind !== "full-spec")
45
92
  return false;
46
93
  const specMd = readSpecMarkdown(projectRoot);
47
- return specMd.includes(GENERATED_SPEC_PURPOSE) && contentHasGeneratedSpecSource(specMd);
94
+ return (specMd.includes(GENERATED_SPEC_PURPOSE) &&
95
+ contentMatchesResolvedSpecSource(projectRoot, specMd, authority.sourcePath));
48
96
  }
49
97
  export function isGreenfieldSpecExport(projectRoot) {
50
98
  const authority = resolveSpecAuthority(projectRoot);
@@ -15,4 +15,18 @@
15
15
  * so an overflow is never silent again.
16
16
  */
17
17
  export declare const SUBPROCESS_MAX_BUFFER: number;
18
+ /**
19
+ * Reason text for a failed capture, so an overflow is never blank (#1867 / #3903).
20
+ *
21
+ * A spawn-level failure (ENOBUFS past the ceiling, timeout kill, missing
22
+ * binary) reports no exit status and empty stderr, whether it arrives as a
23
+ * `spawnSync` result or as a thrown `execFileSync` error. Only then does the
24
+ * error message stand in for stderr: a process that exited with a status and
25
+ * chose to say nothing keeps its empty stderr.
26
+ */
27
+ export declare function resolveCaptureFailureStderr(capture: {
28
+ readonly captured: string;
29
+ readonly status: number | null | undefined;
30
+ readonly message: string | undefined;
31
+ }): string;
18
32
  //# sourceMappingURL=max-buffer.d.ts.map
@@ -15,4 +15,19 @@
15
15
  * so an overflow is never silent again.
16
16
  */
17
17
  export const SUBPROCESS_MAX_BUFFER = 64 * 1024 * 1024;
18
+ /**
19
+ * Reason text for a failed capture, so an overflow is never blank (#1867 / #3903).
20
+ *
21
+ * A spawn-level failure (ENOBUFS past the ceiling, timeout kill, missing
22
+ * binary) reports no exit status and empty stderr, whether it arrives as a
23
+ * `spawnSync` result or as a thrown `execFileSync` error. Only then does the
24
+ * error message stand in for stderr: a process that exited with a status and
25
+ * chose to say nothing keeps its empty stderr.
26
+ */
27
+ export function resolveCaptureFailureStderr(capture) {
28
+ if (capture.captured.trim().length > 0 || typeof capture.status === "number") {
29
+ return capture.captured;
30
+ }
31
+ return capture.message ?? capture.captured;
32
+ }
18
33
  //# sourceMappingURL=max-buffer.js.map
@@ -47,6 +47,8 @@ export declare function completeCohort(args: {
47
47
  delivery?: CohortDeliveryContext | null;
48
48
  /** Optional launch allocation plan id so close-out reads this cohort's occupancy slot. */
49
49
  allocationPlanId?: string | null;
50
+ /** Test seam and explicit ambient-owner source for close-out corroboration. */
51
+ env?: NodeJS.ProcessEnv;
50
52
  }): {
51
53
  exitCode: number;
52
54
  stdout: string;
@@ -471,25 +471,33 @@ export function completeCohort(args) {
471
471
  });
472
472
  result.errors.push(...errors);
473
473
  if (result.ok && args.dryRun !== true) {
474
- const envSession = process.env.DEFT_SESSION_ID?.trim() ?? "";
475
- let sessionId = envSession;
476
- if (sessionId.length === 0) {
477
- const resolved = resolveLaunchOccupancySessionId(projectRoot, {
478
- allocationPlanId: args.allocationPlanId ?? null,
479
- storyIds: paths.map(storyIdFromPath),
480
- });
481
- if (resolved.reason === "ok" && resolved.sessionId.length > 0) {
482
- sessionId = resolved.sessionId;
483
- }
484
- else if (readOccupancy(projectRoot) !== null) {
474
+ const env = args.env ?? process.env;
475
+ const envSession = env.DEFT_SESSION_ID?.trim() ?? "";
476
+ const liveOccupancy = readOccupancy(projectRoot);
477
+ const resolved = resolveLaunchOccupancySessionId(projectRoot, {
478
+ allocationPlanId: args.allocationPlanId ?? null,
479
+ storyIds: paths.map(storyIdFromPath),
480
+ });
481
+ let sessionId = "";
482
+ if (liveOccupancy !== null) {
483
+ if (resolved.reason !== "ok" || resolved.sessionId.length === 0) {
485
484
  result.ok = false;
486
485
  result.errors.push("swarm close-out occupancy record is missing or belongs to a different cohort. " +
487
- "Steal with occupancy:steal --confirm --occupant <id>.");
486
+ "Re-establish an aligned owner with session:start --steal --confirm " +
487
+ "--occupant <reported-session-id> --session-id=<your-session-id>.");
488
+ }
489
+ else if (envSession.length > 0 && envSession !== resolved.sessionId) {
490
+ result.ok = false;
491
+ result.errors.push(`swarm close-out ambient owner ${envSession} conflicts with cohort owner ` +
492
+ `${resolved.sessionId}; refusing to release a later session's live lease.`);
493
+ }
494
+ else {
495
+ sessionId = resolved.sessionId;
488
496
  }
489
497
  }
490
498
  if (result.ok && sessionId.length > 0) {
491
499
  const released = releaseSwarmOccupancy(projectRoot, {
492
- env: process.env,
500
+ env,
493
501
  sessionId,
494
502
  });
495
503
  if (released.code !== 0) {
@@ -14,6 +14,7 @@ export { routingSetMain } from "./routing-set-cli.js";
14
14
  export * from "./routing-verify.js";
15
15
  export { routingVerifyMain } from "./routing-verify-cli.js";
16
16
  export * from "./subagent-backend.js";
17
+ export * from "./subagent-status-dir.js";
17
18
  export * from "./subprocess.js";
18
19
  export * from "./verify-review-clean.js";
19
20
  export { verifyReviewCleanMain } from "./verify-review-clean-cli.js";
@@ -14,6 +14,7 @@ export { routingSetMain } from "./routing-set-cli.js";
14
14
  export * from "./routing-verify.js";
15
15
  export { routingVerifyMain } from "./routing-verify-cli.js";
16
16
  export * from "./subagent-backend.js";
17
+ export * from "./subagent-status-dir.js";
17
18
  export * from "./subprocess.js";
18
19
  export * from "./verify-review-clean.js";
19
20
  export { verifyReviewCleanMain } from "./verify-review-clean-cli.js";
@@ -17,54 +17,58 @@ export function parseLaunchArgv(argv) {
17
17
  let enforceGatesFlag = false;
18
18
  let noAudit = false;
19
19
  let projectRoot = ".";
20
+ let sessionId = null;
21
+ let parseError = null;
20
22
  for (let i = 0; i < argv.length; i += 1) {
21
23
  const arg = argv[i];
22
- const next = argv[i + 1];
23
- if (arg === "--stories" && next !== undefined) {
24
- stories.push(next);
24
+ const takeValue = () => {
25
+ const value = argv[i + 1];
26
+ if (value === undefined || value.startsWith("--")) {
27
+ parseError ??= `argument ${arg}: expected one argument`;
28
+ return null;
29
+ }
25
30
  i += 1;
31
+ return value;
32
+ };
33
+ if (arg === "--stories") {
34
+ const value = takeValue();
35
+ if (value !== null)
36
+ stories.push(value);
26
37
  }
27
- else if (arg === "--paths" && next !== undefined) {
28
- paths.push(next);
29
- i += 1;
38
+ else if (arg === "--paths") {
39
+ const value = takeValue();
40
+ if (value !== null)
41
+ paths.push(value);
30
42
  }
31
- else if (arg === "--group" && next !== undefined) {
32
- group = next;
33
- i += 1;
43
+ else if (arg === "--group") {
44
+ group = takeValue();
34
45
  }
35
- else if (arg === "--worktree-map" && next !== undefined) {
36
- worktreeMap = next;
37
- i += 1;
46
+ else if (arg === "--worktree-map") {
47
+ worktreeMap = takeValue();
38
48
  }
39
- else if (arg === "--base-branch" && next !== undefined) {
40
- baseBranch = next;
41
- i += 1;
49
+ else if (arg === "--base-branch") {
50
+ baseBranch = takeValue() ?? baseBranch;
42
51
  }
43
52
  else if (arg === "--autonomous") {
44
53
  autonomous = true;
45
54
  }
46
- else if (arg === "--allocation-plan-id" && next !== undefined) {
47
- allocationPlanId = next;
48
- i += 1;
55
+ else if (arg === "--allocation-plan-id") {
56
+ allocationPlanId = takeValue();
49
57
  }
50
- else if (arg === "--batching-rationale" && next !== undefined) {
51
- batchingRationale = next;
52
- i += 1;
58
+ else if (arg === "--batching-rationale") {
59
+ batchingRationale = takeValue();
53
60
  }
54
- else if (arg === "--operator-approval" && next !== undefined) {
55
- operatorApproval = next;
56
- i += 1;
61
+ else if (arg === "--operator-approval") {
62
+ operatorApproval = takeValue();
57
63
  }
58
64
  else if (arg === "--no-create-worktrees") {
59
65
  noCreateWorktrees = true;
60
66
  }
61
- else if (arg === "--output" && next !== undefined) {
62
- output = next;
63
- i += 1;
67
+ else if (arg === "--output") {
68
+ output = takeValue();
64
69
  }
65
- else if (arg === "--gate-clearances" && next !== undefined) {
66
- gateClearancesPath = next;
67
- i += 1;
70
+ else if (arg === "--gate-clearances") {
71
+ gateClearancesPath = takeValue();
68
72
  }
69
73
  else if (arg === "--enforce-gates") {
70
74
  enforceGatesFlag = true;
@@ -72,12 +76,27 @@ export function parseLaunchArgv(argv) {
72
76
  else if (arg === "--no-audit") {
73
77
  noAudit = true;
74
78
  }
75
- else if (arg === "--project-root" && next !== undefined) {
76
- projectRoot = next;
77
- i += 1;
79
+ else if (arg === "--project-root") {
80
+ projectRoot = takeValue() ?? projectRoot;
81
+ }
82
+ else if (arg === "--session-id") {
83
+ const value = takeValue();
84
+ if (value === null) {
85
+ // Keep an explicit invalid sentinel so swarmLaunch fails closed rather
86
+ // than falling back to ambient identity or minting a different owner.
87
+ sessionId = "";
88
+ }
89
+ else {
90
+ sessionId = value;
91
+ }
92
+ }
93
+ else if (arg?.startsWith("--session-id=") === true) {
94
+ const value = arg.slice("--session-id=".length);
95
+ sessionId = value.startsWith("--") ? "" : value;
78
96
  }
79
97
  }
80
98
  return {
99
+ parseError,
81
100
  stories,
82
101
  paths,
83
102
  group,
@@ -93,6 +112,7 @@ export function parseLaunchArgv(argv) {
93
112
  enforceGatesFlag,
94
113
  noAudit,
95
114
  projectRoot,
115
+ sessionId,
96
116
  };
97
117
  }
98
118
  export function launchMain(argv = process.argv.slice(2)) {
@@ -1,3 +1,5 @@
1
+ import { type ExpectedGithubWorkerPrincipal, type GhRunner, GITHUB_AUTH_MODE_HOST_GH, GITHUB_AUTH_MODE_INJECTED_TOKEN } from "../intake/github-auth-modes.js";
2
+ import { releaseOccupancy } from "../session/occupancy.js";
1
3
  import { EXIT_CONFIG_ERROR, EXIT_GATE_FAILED, EXIT_OK } from "./constants.js";
2
4
  import { type WorktreeRecord } from "./worktrees.js";
3
5
  export interface ResolvedStory {
@@ -18,9 +20,74 @@ export type WorktreeResolverFn = (mapping: readonly Record<string, unknown>[], b
18
20
  repoRoot?: string;
19
21
  }) => WorktreeRecord[];
20
22
  export type RuntimeAuthProbeFn = () => [string, string];
23
+ export type OccupancyReleaseFn = typeof releaseOccupancy;
21
24
  export declare const defaultPreflightGate: PreflightGateFn;
22
25
  export declare const defaultReadinessGate: ReadinessGateFn;
23
26
  export declare const defaultRuntimeAuthProbe: RuntimeAuthProbeFn;
27
+ export type WorkerCredentialDispatchPath = "grok-build" | "local-hybrid";
28
+ /**
29
+ * Dispatch-envelope half of the runtime / GitHub auth-mode contract (#1557 / #1351).
30
+ * Policy labels only — never a token value.
31
+ */
32
+ export declare function formatDispatchAuthEnvelope(fields: {
33
+ runtimeMode: string;
34
+ githubAuthMode: string;
35
+ expectedGithubLogin?: string | null;
36
+ }): string;
37
+ export interface WorkerCredentialInjectionRequest {
38
+ environ?: NodeJS.ProcessEnv;
39
+ githubAuthMode: string;
40
+ runtimeMode?: string | null;
41
+ dispatchPath?: WorkerCredentialDispatchPath;
42
+ expectedPrincipal?: ExpectedGithubWorkerPrincipal | null;
43
+ repo?: string;
44
+ runGh?: GhRunner;
45
+ cwd?: string;
46
+ }
47
+ export type WorkerCredentialInjectionResult = {
48
+ ok: true;
49
+ injected: true;
50
+ githubAuthMode: typeof GITHUB_AUTH_MODE_INJECTED_TOKEN;
51
+ runtimeMode: string | null;
52
+ expectedLogin: string;
53
+ spawnEnv: {
54
+ GH_TOKEN: string;
55
+ GITHUB_TOKEN: string;
56
+ GH_ENTERPRISE_TOKEN: string;
57
+ DEFT_EXPECTED_GITHUB_LOGIN: string;
58
+ };
59
+ envelopeSection: string;
60
+ } | {
61
+ ok: true;
62
+ injected: false;
63
+ githubAuthMode: typeof GITHUB_AUTH_MODE_HOST_GH;
64
+ runtimeMode: string | null;
65
+ expectedLogin: string | null;
66
+ spawnEnv: Record<string, never>;
67
+ envelopeSection: string;
68
+ } | {
69
+ ok: false;
70
+ blocked: true;
71
+ githubAuthMode: string;
72
+ runtimeMode: string | null;
73
+ missingCredential: string;
74
+ remedy: string;
75
+ detail: string;
76
+ failureKind: string | null;
77
+ envelopeSection: string;
78
+ };
79
+ /**
80
+ * Validate a held user-bearing worker credential and prepare spawn-time injection (#1351).
81
+ *
82
+ * Comparison is opt-in on the validator. This path always stamps
83
+ * `DEFT_EXPECTED_GITHUB_LOGIN` after a successful user-principal check so the
84
+ * worker envelope does not inherit "any user token is approved."
85
+ *
86
+ * Installation credentials fail closed via the existing validator (#3693).
87
+ * Token values belong only in the returned `spawnEnv` — never in prompts,
88
+ * transcripts, or manifest entries.
89
+ */
90
+ export declare function prepareWorkerCredentialInjection(request: WorkerCredentialInjectionRequest): WorkerCredentialInjectionResult;
24
91
  /**
25
92
  * True when a brief in `xbrief/completed/` (or the legacy `vbrief/completed/`)
26
93
  * references the given issue number in its `references[]` / `Traces`. Used by
@@ -74,10 +141,13 @@ export declare function buildManifest(resolved: readonly ResolvedStory[], option
74
141
  modelSource?: string | null;
75
142
  runtimeMode?: string | null;
76
143
  githubAuthMode?: string | null;
144
+ expectedGithubLogin?: string | null;
77
145
  occupancySessionId?: string | null;
78
146
  }): Record<string, unknown>[];
79
147
  export declare function orderCohort(resolved: readonly ResolvedStory[], _projectRoot: string): ResolvedStory[];
80
148
  export interface LaunchArgs {
149
+ /** CLI parse failure carried into the core so later valid flags cannot erase it. */
150
+ parseError?: string | null;
81
151
  stories?: readonly string[];
82
152
  paths?: readonly string[];
83
153
  group?: string | null;
@@ -93,16 +163,23 @@ export interface LaunchArgs {
93
163
  enforceGatesFlag?: boolean;
94
164
  noAudit?: boolean;
95
165
  projectRoot?: string;
166
+ /** Explicit cooperative owner identity, including host-payload canonical IDs (#3611). */
167
+ sessionId?: string | null;
96
168
  preflightGate?: PreflightGateFn;
97
169
  readinessGate?: ReadinessGateFn;
98
170
  worktreeResolver?: WorktreeResolverFn;
99
171
  runtimeAuthProbe?: RuntimeAuthProbeFn;
172
+ /** Test seam: override occupancy release after a newly minted claim fails. */
173
+ releaseOccupancyFn?: OccupancyReleaseFn;
100
174
  /**
101
175
  * Injection seam for the routing-provider environment lookup, mirroring
102
176
  * `resolveRoutingPath`'s `environ` parameter (#1877 Greptile follow-up).
103
177
  * Defaults to `process.env` when unset.
104
178
  */
105
179
  environ?: NodeJS.ProcessEnv;
180
+ /** Optional gh runner for identity-bound credential injection (#1351). */
181
+ runGh?: GhRunner;
182
+ expectedPrincipal?: ExpectedGithubWorkerPrincipal | null;
106
183
  }
107
184
  export declare function swarmLaunch(args: LaunchArgs): {
108
185
  exitCode: number;