@lumenflow/cli 4.23.0 → 5.0.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 (296) hide show
  1. package/README.md +54 -52
  2. package/dist/agent-issues-query.js +10 -2
  3. package/dist/agent-issues-query.js.map +1 -1
  4. package/dist/agent-runtime-enrollment-events.js +44 -0
  5. package/dist/agent-runtime-enrollment-events.js.map +1 -0
  6. package/dist/agent-session-end.js +47 -0
  7. package/dist/agent-session-end.js.map +1 -1
  8. package/dist/agent-session-heartbeat.js +250 -0
  9. package/dist/agent-session-heartbeat.js.map +1 -0
  10. package/dist/agent-session.js +299 -5
  11. package/dist/agent-session.js.map +1 -1
  12. package/dist/capacity-snapshot-emitter.js +73 -0
  13. package/dist/capacity-snapshot-emitter.js.map +1 -0
  14. package/dist/claim-queue.js +276 -0
  15. package/dist/claim-queue.js.map +1 -0
  16. package/dist/config-set.js +22 -3
  17. package/dist/config-set.js.map +1 -1
  18. package/dist/control-plane-sidecar-runner.js +145 -0
  19. package/dist/control-plane-sidecar-runner.js.map +1 -0
  20. package/dist/delegation-list.js +160 -1
  21. package/dist/delegation-list.js.map +1 -1
  22. package/dist/delegation-role-resolver.js +69 -0
  23. package/dist/delegation-role-resolver.js.map +1 -0
  24. package/dist/docs-generate-pack-reference.js +500 -0
  25. package/dist/docs-generate-pack-reference.js.map +1 -0
  26. package/dist/docs-sync.js +116 -1
  27. package/dist/docs-sync.js.map +1 -1
  28. package/dist/file-edit.js +28 -8
  29. package/dist/file-edit.js.map +1 -1
  30. package/dist/file-write.js +29 -5
  31. package/dist/file-write.js.map +1 -1
  32. package/dist/gate-co-change.js +25 -7
  33. package/dist/gate-co-change.js.map +1 -1
  34. package/dist/gate-conditional.js +19 -7
  35. package/dist/gate-conditional.js.map +1 -1
  36. package/dist/gates-runners.js +42 -33
  37. package/dist/gates-runners.js.map +1 -1
  38. package/dist/gates-utils.js +34 -20
  39. package/dist/gates-utils.js.map +1 -1
  40. package/dist/gates.js +79 -7
  41. package/dist/gates.js.map +1 -1
  42. package/dist/hooks/config-resolver.js +10 -1
  43. package/dist/hooks/config-resolver.js.map +1 -1
  44. package/dist/init-package-config.js +1 -1
  45. package/dist/init-package-config.js.map +1 -1
  46. package/dist/init-scaffolding.js +5 -1
  47. package/dist/init-scaffolding.js.map +1 -1
  48. package/dist/init-templates.js +10 -0
  49. package/dist/init-templates.js.map +1 -1
  50. package/dist/init.js +1 -1
  51. package/dist/init.js.map +1 -1
  52. package/dist/initiative-create.js +17 -0
  53. package/dist/initiative-create.js.map +1 -1
  54. package/dist/initiative-remove-wu.js +17 -3
  55. package/dist/initiative-remove-wu.js.map +1 -1
  56. package/dist/kernel-event-sync/emitters.js +104 -0
  57. package/dist/kernel-event-sync/emitters.js.map +1 -0
  58. package/dist/kernel-event-sync/index.js +13 -0
  59. package/dist/kernel-event-sync/index.js.map +1 -0
  60. package/dist/kernel-event-sync/lifecycle-emitters.js +160 -0
  61. package/dist/kernel-event-sync/lifecycle-emitters.js.map +1 -0
  62. package/dist/kernel-event-sync/narrow-emissions.js +89 -0
  63. package/dist/kernel-event-sync/narrow-emissions.js.map +1 -0
  64. package/dist/kernel-event-sync/software-delivery-emitters.js +297 -0
  65. package/dist/kernel-event-sync/software-delivery-emitters.js.map +1 -0
  66. package/dist/lane-lock.js +14 -1
  67. package/dist/lane-lock.js.map +1 -1
  68. package/dist/lane-suggest.js +21 -0
  69. package/dist/lane-suggest.js.map +1 -1
  70. package/dist/lumenflow-upgrade.js +7 -5
  71. package/dist/lumenflow-upgrade.js.map +1 -1
  72. package/dist/mem-context.js +145 -0
  73. package/dist/mem-context.js.map +1 -1
  74. package/dist/mem-create.js +39 -6
  75. package/dist/mem-create.js.map +1 -1
  76. package/dist/mem-inbox.js +16 -0
  77. package/dist/mem-inbox.js.map +1 -1
  78. package/dist/mem-roster.js +95 -0
  79. package/dist/mem-roster.js.map +1 -0
  80. package/dist/mem-signal.js +97 -2
  81. package/dist/mem-signal.js.map +1 -1
  82. package/dist/metrics-cli.js +3 -2
  83. package/dist/metrics-cli.js.map +1 -1
  84. package/dist/metrics-snapshot.js +271 -13
  85. package/dist/metrics-snapshot.js.map +1 -1
  86. package/dist/orchestrate-init-status.js +117 -2
  87. package/dist/orchestrate-init-status.js.map +1 -1
  88. package/dist/orchestrate-initiative.js +83 -10
  89. package/dist/orchestrate-initiative.js.map +1 -1
  90. package/dist/orchestrate-monitor-quality.js +289 -0
  91. package/dist/orchestrate-monitor-quality.js.map +1 -0
  92. package/dist/orchestrate-monitor.js +85 -0
  93. package/dist/orchestrate-monitor.js.map +1 -1
  94. package/dist/pack-validate.js +127 -2
  95. package/dist/pack-validate.js.map +1 -1
  96. package/dist/plan-create.js +18 -0
  97. package/dist/plan-create.js.map +1 -1
  98. package/dist/plan-link.js +13 -0
  99. package/dist/plan-link.js.map +1 -1
  100. package/dist/plan-promote.js +14 -0
  101. package/dist/plan-promote.js.map +1 -1
  102. package/dist/pre-commit-check.js +4 -3
  103. package/dist/pre-commit-check.js.map +1 -1
  104. package/dist/public-manifest.js +17 -3
  105. package/dist/public-manifest.js.map +1 -1
  106. package/dist/release.js +10 -10
  107. package/dist/release.js.map +1 -1
  108. package/dist/session-cross-link.js +139 -0
  109. package/dist/session-cross-link.js.map +1 -0
  110. package/dist/sidecar-manager.js +208 -0
  111. package/dist/sidecar-manager.js.map +1 -0
  112. package/dist/state-path-resolvers.js +18 -0
  113. package/dist/state-path-resolvers.js.map +1 -1
  114. package/dist/stream-heartbeat.js +151 -0
  115. package/dist/stream-heartbeat.js.map +1 -0
  116. package/dist/sync-templates.js +56 -2
  117. package/dist/sync-templates.js.map +1 -1
  118. package/dist/wu-block.js +47 -5
  119. package/dist/wu-block.js.map +1 -1
  120. package/dist/wu-claim-branch.js +8 -4
  121. package/dist/wu-claim-branch.js.map +1 -1
  122. package/dist/wu-claim-state.js +5 -3
  123. package/dist/wu-claim-state.js.map +1 -1
  124. package/dist/wu-claim-worktree.js +5 -3
  125. package/dist/wu-claim-worktree.js.map +1 -1
  126. package/dist/wu-claim.js +261 -9
  127. package/dist/wu-claim.js.map +1 -1
  128. package/dist/wu-done-auto-cleanup.js +3 -2
  129. package/dist/wu-done-auto-cleanup.js.map +1 -1
  130. package/dist/wu-done-git-ops.js +12 -8
  131. package/dist/wu-done-git-ops.js.map +1 -1
  132. package/dist/wu-done-preflight.js +3 -3
  133. package/dist/wu-done-preflight.js.map +1 -1
  134. package/dist/wu-done.js +46 -10
  135. package/dist/wu-done.js.map +1 -1
  136. package/dist/wu-lifecycle-sync/gate-scope-resolver.js +16 -0
  137. package/dist/wu-lifecycle-sync/gate-scope-resolver.js.map +1 -0
  138. package/dist/wu-lifecycle-sync/kernel-event-sync-shim.js +10 -0
  139. package/dist/wu-lifecycle-sync/kernel-event-sync-shim.js.map +1 -0
  140. package/dist/wu-prep.js +363 -22
  141. package/dist/wu-prep.js.map +1 -1
  142. package/dist/wu-prune.js +68 -27
  143. package/dist/wu-prune.js.map +1 -1
  144. package/dist/wu-release.js +34 -3
  145. package/dist/wu-release.js.map +1 -1
  146. package/dist/wu-review.js +167 -0
  147. package/dist/wu-review.js.map +1 -0
  148. package/dist/wu-spawn-prompt-builders.js +296 -40
  149. package/dist/wu-spawn-prompt-builders.js.map +1 -1
  150. package/dist/wu-spawn-strategy-resolver.js +126 -14
  151. package/dist/wu-spawn-strategy-resolver.js.map +1 -1
  152. package/dist/wu-unblock.js +52 -22
  153. package/dist/wu-unblock.js.map +1 -1
  154. package/package.json +13 -8
  155. package/packs/agent-runtime/.turbo/turbo-build.log +1 -1
  156. package/packs/agent-runtime/.turbo/turbo-test.log +25 -0
  157. package/packs/agent-runtime/.turbo/turbo-typecheck.log +4 -0
  158. package/packs/agent-runtime/agent-heartbeat.ts +163 -0
  159. package/packs/agent-runtime/auto-session-integration.ts +874 -0
  160. package/packs/agent-runtime/delegation-registry-schema.ts +220 -0
  161. package/packs/agent-runtime/delegation-registry-store.ts +269 -0
  162. package/packs/agent-runtime/delegation-tree.ts +328 -0
  163. package/packs/agent-runtime/index.ts +9 -0
  164. package/packs/agent-runtime/manifest.ts +103 -19
  165. package/packs/agent-runtime/manifest.yaml +132 -0
  166. package/packs/agent-runtime/memory-coordination-contract.ts +86 -0
  167. package/packs/agent-runtime/memory.d.ts +19 -0
  168. package/packs/agent-runtime/orchestration.ts +238 -23
  169. package/packs/agent-runtime/package.json +11 -2
  170. package/packs/agent-runtime/remote-controls/index.ts +7 -0
  171. package/packs/agent-runtime/remote-controls/operations.ts +399 -0
  172. package/packs/agent-runtime/remote-controls/port.ts +48 -0
  173. package/packs/agent-runtime/remote-controls/state-store.ts +258 -0
  174. package/packs/agent-runtime/remote-controls/types.ts +105 -0
  175. package/packs/agent-runtime/session-schema.ts +423 -0
  176. package/packs/agent-runtime/tool-impl/index.ts +1 -0
  177. package/packs/agent-runtime/tool-impl/remote-controls.mock.ts +252 -0
  178. package/packs/agent-runtime/tool-impl/remote-controls.ts +273 -0
  179. package/packs/agent-runtime/tsconfig.json +1 -1
  180. package/packs/agent-runtime/turn-lifecycle-events.ts +501 -0
  181. package/packs/sidekick/.lumenflow/state/conductor/outbox/sidekick-events.jsonl +213 -0
  182. package/packs/sidekick/.turbo/turbo-build.log +1 -1
  183. package/packs/sidekick/.turbo/turbo-test.log +25 -0
  184. package/packs/sidekick/.turbo/turbo-typecheck.log +4 -0
  185. package/packs/sidekick/channel-ingress.ts +137 -0
  186. package/packs/sidekick/manifest.ts +74 -0
  187. package/packs/sidekick/manifest.yaml +88 -0
  188. package/packs/sidekick/package.json +3 -1
  189. package/packs/sidekick/sidekick-events.ts +517 -0
  190. package/packs/sidekick/src/adapters/cloud-queue.ts +101 -0
  191. package/packs/sidekick/src/adapters/control-plane-bridge.adapter.ts +378 -0
  192. package/packs/sidekick/src/adapters/filesystem-bridge.adapter.ts +224 -0
  193. package/packs/sidekick/src/domain/channel.types.ts +84 -0
  194. package/packs/sidekick/src/ports/channel-bridge.port.ts +75 -0
  195. package/packs/sidekick/src/routines/commit.ts +74 -0
  196. package/packs/sidekick/tool-impl/channel-tools.ts +47 -0
  197. package/packs/sidekick/tool-impl/memory-tools.ts +17 -0
  198. package/packs/sidekick/tool-impl/routine-commit.ts +102 -0
  199. package/packs/sidekick/tool-impl/routine-tools.ts +67 -7
  200. package/packs/sidekick/tool-impl/runtime-context.ts +4 -0
  201. package/packs/sidekick/tool-impl/storage.ts +3 -0
  202. package/packs/sidekick/tool-impl/system-tools.ts +7 -0
  203. package/packs/sidekick/tool-impl/task-tools.ts +46 -0
  204. package/packs/sidekick/tsconfig.json +1 -1
  205. package/packs/software-delivery/.turbo/turbo-build.log +1 -1
  206. package/packs/software-delivery/.turbo/turbo-test.log +63 -0
  207. package/packs/software-delivery/.turbo/turbo-typecheck.log +4 -0
  208. package/packs/software-delivery/manifest-schema.ts +30 -0
  209. package/packs/software-delivery/manifest.ts +99 -1
  210. package/packs/software-delivery/manifest.yaml +46 -0
  211. package/packs/software-delivery/package.json +88 -3
  212. package/packs/software-delivery/src/commands/index.ts +5 -0
  213. package/packs/software-delivery/src/config/delivery-review-contract.ts +20 -0
  214. package/packs/software-delivery/src/config/env-accessors.ts +19 -0
  215. package/packs/software-delivery/src/config/index.ts +8 -0
  216. package/packs/software-delivery/src/config/normalize-config-keys.ts +19 -0
  217. package/packs/software-delivery/src/config/schemas/lumenflow-config-schema-types.ts +436 -0
  218. package/packs/software-delivery/src/config/workspace-reader.ts +310 -0
  219. package/packs/software-delivery/src/constants/backlog-patterns.ts +31 -0
  220. package/packs/software-delivery/src/constants/client-ids.ts +19 -0
  221. package/packs/software-delivery/src/constants/config-contract.ts +7 -0
  222. package/packs/software-delivery/src/constants/docs-layout-presets.ts +50 -0
  223. package/packs/software-delivery/src/constants/duration-constants.ts +20 -0
  224. package/packs/software-delivery/src/constants/gate-constants.ts +32 -0
  225. package/packs/software-delivery/src/constants/index.ts +29 -0
  226. package/packs/software-delivery/src/constants/lock-constants.ts +35 -0
  227. package/packs/software-delivery/src/constants/object-guards.ts +12 -0
  228. package/packs/software-delivery/src/constants/section-headings.ts +107 -0
  229. package/packs/software-delivery/src/constants/wu-cli-constants.ts +485 -0
  230. package/packs/software-delivery/src/constants/wu-domain-constants.ts +466 -0
  231. package/packs/software-delivery/src/constants/wu-git-constants.ts +7 -0
  232. package/packs/software-delivery/src/constants/wu-id-format.ts +327 -0
  233. package/packs/software-delivery/src/constants/wu-paths-constants.ts +358 -0
  234. package/packs/software-delivery/src/constants/wu-statuses.ts +287 -0
  235. package/packs/software-delivery/src/constants/wu-type-helpers.ts +67 -0
  236. package/packs/software-delivery/src/constants/wu-ui-constants.ts +267 -0
  237. package/packs/software-delivery/src/constants/wu-validation-constants.ts +73 -0
  238. package/packs/software-delivery/src/domain/index.ts +5 -0
  239. package/packs/software-delivery/src/domain/orchestration.constants.ts +168 -0
  240. package/packs/software-delivery/src/domain/orchestration.schemas.ts +239 -0
  241. package/packs/software-delivery/src/domain/orchestration.types.ts +178 -0
  242. package/packs/software-delivery/src/methodology/incremental-test.ts +90 -0
  243. package/packs/software-delivery/src/methodology/index.ts +6 -0
  244. package/packs/software-delivery/src/methodology/manual-test-validator.ts +292 -0
  245. package/packs/software-delivery/src/policy/coverage-gate.ts +270 -0
  246. package/packs/software-delivery/src/policy/gates-agent-mode.ts +223 -0
  247. package/packs/software-delivery/src/policy/gates-config-internal.ts +121 -0
  248. package/packs/software-delivery/src/policy/gates-config.ts +293 -0
  249. package/packs/software-delivery/src/policy/gates-coverage.ts +247 -0
  250. package/packs/software-delivery/src/policy/gates-presets.ts +134 -0
  251. package/packs/software-delivery/src/policy/gates-schemas.ts +173 -0
  252. package/packs/software-delivery/src/policy/index.ts +22 -0
  253. package/packs/software-delivery/src/policy/package-manager-resolver.ts +319 -0
  254. package/packs/software-delivery/src/policy/resolve-policy.ts +518 -0
  255. package/packs/software-delivery/src/ports/config.ports.ts +90 -0
  256. package/packs/software-delivery/src/ports/dashboard-renderer.port.ts +125 -0
  257. package/packs/software-delivery/src/ports/index.ts +10 -0
  258. package/packs/software-delivery/src/ports/sync-validator.ports.ts +59 -0
  259. package/packs/software-delivery/src/ports/wu-helpers.ports.ts +168 -0
  260. package/packs/software-delivery/src/ports/wu-state.ports.ts +241 -0
  261. package/packs/software-delivery/src/primitives/index.ts +5 -0
  262. package/packs/software-delivery/src/runtime/index.ts +6 -0
  263. package/packs/software-delivery/src/runtime/work-classifier.ts +561 -0
  264. package/packs/software-delivery/src/sandbox/index.ts +10 -0
  265. package/packs/software-delivery/src/sandbox/sandbox-allowlist.ts +118 -0
  266. package/packs/software-delivery/src/sandbox/sandbox-backend-linux.ts +88 -0
  267. package/packs/software-delivery/src/sandbox/sandbox-backend-macos.ts +154 -0
  268. package/packs/software-delivery/src/sandbox/sandbox-backend-windows.ts +47 -0
  269. package/packs/software-delivery/src/sandbox/sandbox-profile.ts +153 -0
  270. package/packs/software-delivery/src/schemas/index.ts +5 -0
  271. package/packs/software-delivery/src/state/date-utils.ts +158 -0
  272. package/packs/software-delivery/src/state/index.ts +15 -0
  273. package/packs/software-delivery/src/state/state-machine.ts +119 -0
  274. package/packs/software-delivery/src/state/wu-doc-types.ts +51 -0
  275. package/packs/software-delivery/src/state/wu-paths.ts +381 -0
  276. package/packs/software-delivery/src/state/wu-schema.ts +1139 -0
  277. package/packs/software-delivery/src/state/wu-state-schema.ts +255 -0
  278. package/packs/software-delivery/src/state/wu-yaml.ts +338 -0
  279. package/packs/software-delivery/src/types.d.ts +16 -0
  280. package/packs/software-delivery/tool-impl/wu-lifecycle-tools.ts +18 -0
  281. package/packs/software-delivery/tsconfig.json +28 -2
  282. package/templates/core/AGENTS.md.template +76 -17
  283. package/templates/core/LUMENFLOW.md.template +265 -66
  284. package/templates/core/_frameworks/lumenflow/wu-sizing-guide.md.template +180 -116
  285. package/templates/core/ai/onboarding/agent-invocation-guide.md.template +26 -8
  286. package/templates/core/ai/onboarding/existing-project-bootstrap.md.template +171 -0
  287. package/templates/core/ai/onboarding/first-15-mins.md.template +3 -1
  288. package/templates/core/ai/onboarding/first-wu-mistakes.md.template +1 -1
  289. package/templates/core/ai/onboarding/initiative-orchestration.md.template +46 -30
  290. package/templates/core/ai/onboarding/quick-ref-commands.md.template +36 -33
  291. package/templates/core/ai/onboarding/release-process.md.template +8 -7
  292. package/templates/core/ai/onboarding/starting-prompt.md.template +2 -0
  293. package/templates/core/ai/onboarding/troubleshooting-wu-done.md.template +62 -0
  294. package/templates/vendors/claude/.claude/CLAUDE.md.template +29 -54
  295. package/templates/vendors/cursor/.cursor/rules/lumenflow.md.template +24 -52
  296. package/templates/vendors/windsurf/.windsurf/rules/lumenflow.md.template +24 -52
@@ -0,0 +1,105 @@
1
+ // Copyright (c) 2026 Hellmai Ltd
2
+ // SPDX-License-Identifier: AGPL-3.0-only
3
+ //
4
+ // WU-2732 (INIT-060 Phase 3, ADR-013 §1 + §6 tracer bullet):
5
+ // Remote-control tool name registry and port/result shapes. The six
6
+ // tools here form the conductor-mode governance surface for the
7
+ // agent-runtime pack. Real implementations land in WU-2733; this file
8
+ // defines the wire contract the real impl must satisfy without
9
+ // re-deciding tool names or payload shapes.
10
+
11
+ import type { AgentRuntimeCleanupStatus } from '../turn-lifecycle-events.js';
12
+
13
+ /**
14
+ * Canonical remote-control tool names. Prefixed with the pack slug per
15
+ * ADR-013 §Event Namespacing convention (extended to tool names for
16
+ * consistency with WU-2729 software-delivery pack exposure precedent).
17
+ */
18
+ export const AGENT_RUNTIME_REMOTE_CONTROL_TOOL_NAMES = {
19
+ RESUME_WORKFLOW: 'agent-runtime:resume_workflow',
20
+ PAUSE_TURN: 'agent-runtime:pause_turn',
21
+ ABORT_TURN: 'agent-runtime:abort_turn',
22
+ ELEVATE_AUTONOMY: 'agent-runtime:elevate_autonomy',
23
+ LOWER_AUTONOMY: 'agent-runtime:lower_autonomy',
24
+ APPROVE_INFLIGHT: 'agent-runtime:approve_inflight',
25
+ } as const;
26
+
27
+ export type AgentRuntimeRemoteControlToolName =
28
+ (typeof AGENT_RUNTIME_REMOTE_CONTROL_TOOL_NAMES)[keyof typeof AGENT_RUNTIME_REMOTE_CONTROL_TOOL_NAMES];
29
+
30
+ /**
31
+ * Declaration order matters: callers (HTTP surface allowlist, conductor
32
+ * UI) render the list in this sequence without re-sorting.
33
+ */
34
+ export const AGENT_RUNTIME_REMOTE_CONTROL_TOOL_NAME_VALUES = [
35
+ AGENT_RUNTIME_REMOTE_CONTROL_TOOL_NAMES.RESUME_WORKFLOW,
36
+ AGENT_RUNTIME_REMOTE_CONTROL_TOOL_NAMES.PAUSE_TURN,
37
+ AGENT_RUNTIME_REMOTE_CONTROL_TOOL_NAMES.ABORT_TURN,
38
+ AGENT_RUNTIME_REMOTE_CONTROL_TOOL_NAMES.ELEVATE_AUTONOMY,
39
+ AGENT_RUNTIME_REMOTE_CONTROL_TOOL_NAMES.LOWER_AUTONOMY,
40
+ AGENT_RUNTIME_REMOTE_CONTROL_TOOL_NAMES.APPROVE_INFLIGHT,
41
+ ] as const satisfies readonly AgentRuntimeRemoteControlToolName[];
42
+
43
+ /**
44
+ * Well-known approval identifier the agent-runtime pack requests for
45
+ * safety-critical remote controls (abort, pause, elevate). Single
46
+ * identifier per ADR-013 §6 governance lock — cloud renders the same
47
+ * approval gate regardless of which of the gated tools was invoked.
48
+ */
49
+ export const AGENT_RUNTIME_REMOTE_CONTROL_APPROVAL_ID = 'agent-runtime:remote_control' as const;
50
+
51
+ /**
52
+ * Mapping from remote-control tool name to its declared
53
+ * `required_approvals` manifest entry. Gated tools request an explicit
54
+ * approval identifier; safer/read-only tools declare an empty array so
55
+ * the manifest stays minimally descriptive (matches WU-2729 convention).
56
+ */
57
+ export const AGENT_RUNTIME_REMOTE_CONTROL_APPROVALS: Record<
58
+ AgentRuntimeRemoteControlToolName,
59
+ readonly string[]
60
+ > = {
61
+ [AGENT_RUNTIME_REMOTE_CONTROL_TOOL_NAMES.RESUME_WORKFLOW]: [],
62
+ [AGENT_RUNTIME_REMOTE_CONTROL_TOOL_NAMES.PAUSE_TURN]: [AGENT_RUNTIME_REMOTE_CONTROL_APPROVAL_ID],
63
+ [AGENT_RUNTIME_REMOTE_CONTROL_TOOL_NAMES.ABORT_TURN]: [AGENT_RUNTIME_REMOTE_CONTROL_APPROVAL_ID],
64
+ [AGENT_RUNTIME_REMOTE_CONTROL_TOOL_NAMES.ELEVATE_AUTONOMY]: [
65
+ AGENT_RUNTIME_REMOTE_CONTROL_APPROVAL_ID,
66
+ ],
67
+ [AGENT_RUNTIME_REMOTE_CONTROL_TOOL_NAMES.LOWER_AUTONOMY]: [],
68
+ [AGENT_RUNTIME_REMOTE_CONTROL_TOOL_NAMES.APPROVE_INFLIGHT]: [],
69
+ };
70
+
71
+ /**
72
+ * Deterministic mock session identifier returned by tracer-bullet
73
+ * implementations. The real impl in WU-2733 reads the session from the
74
+ * input payload; the mock returns a fixed value so round-trip tests
75
+ * pin the wire contract without leaking runtime state.
76
+ */
77
+ export const MOCK_SESSION_ID = 'agent-runtime-remote-control-mock-session' as const;
78
+
79
+ /**
80
+ * Shared result shape for the five non-abort remote controls. Real
81
+ * impls may extend this — the additive-only rule lets WU-2733 land
82
+ * without contract drift.
83
+ */
84
+ export interface RemoteControlInvocationResult {
85
+ status: 'ok';
86
+ tool_name: AgentRuntimeRemoteControlToolName;
87
+ session_id: string;
88
+ }
89
+
90
+ /**
91
+ * abort_turn carries the ADR-013 §1 abort contract: cleanup_status +
92
+ * recovery_action. Cloud renders recovery_action as a hint; NEVER
93
+ * auto-executes (see ADR-013 §1 safety lock).
94
+ */
95
+ export interface AbortTurnInvocationResult {
96
+ status: 'ok';
97
+ tool_name: typeof AGENT_RUNTIME_REMOTE_CONTROL_TOOL_NAMES.ABORT_TURN;
98
+ session_id: string;
99
+ cleanup_status: AgentRuntimeCleanupStatus;
100
+ recovery_action: string | null;
101
+ }
102
+
103
+ export type AnyRemoteControlInvocationResult =
104
+ | RemoteControlInvocationResult
105
+ | AbortTurnInvocationResult;
@@ -0,0 +1,423 @@
1
+ // Copyright (c) 2026 Hellmai Ltd
2
+ // SPDX-License-Identifier: AGPL-3.0-only
3
+
4
+ /**
5
+ * Session Schema (WU-2754, ADR-014 extension 2)
6
+ *
7
+ * Canonical schema for agent session records persisted under
8
+ * `.lumenflow/sessions/<WU>.json` and the `current.json` compatibility pointer.
9
+ *
10
+ * ADR-014 extension 2 adds three optional axes:
11
+ * - `lifecycle_role` — what phase of delivery the session owns
12
+ * (opaque string at the kernel layer; pack owns vocabulary)
13
+ * - `specialty_profile` — which skill bundle the agent self-identifies as carrying
14
+ * - `delegation_id` — reference back to the parent delegation registry record
15
+ * (dlg-XXXX) so `delegation:list` can cross-display session
16
+ * axes alongside requested_role / actual_role.
17
+ *
18
+ * Schema-version discipline:
19
+ * - v1 legacy records have NO `schemaVersion` field and may omit the three
20
+ * new axes entirely. Readers MUST accept them without error.
21
+ * - v2 records stamp `schemaVersion: 'v2'`. New writes default to v2 and
22
+ * populate `lifecycle_role` + `specialty_profile` (sensible pack-layer
23
+ * defaults supplied by callers). Kernel-agnostic: the schema itself
24
+ * carries opaque strings; the pack (@lumenflow/packs/software-delivery)
25
+ * owns the canonical vocabulary.
26
+ *
27
+ * Reference: docs/09-architecture-decisions/ADR-014-typed-agent-role-contract.md §181
28
+ */
29
+
30
+ import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
31
+ import path from 'node:path';
32
+ import { parse as parseYAML } from 'yaml';
33
+ import { z } from 'zod';
34
+
35
+ /**
36
+ * Session schema version discriminator.
37
+ *
38
+ * v1 = legacy (no stamp). v2 = ADR-014 extension 2 (may carry role axes).
39
+ */
40
+ export const SESSION_SCHEMA_VERSION_V2 = 'v2' as const;
41
+
42
+ /** Known session schema versions (extensible by additive pack updates). */
43
+ export const SESSION_SCHEMA_VERSIONS = [SESSION_SCHEMA_VERSION_V2] as const;
44
+
45
+ /** Type union for session schema version values. */
46
+ export type SessionSchemaVersion = (typeof SESSION_SCHEMA_VERSIONS)[number];
47
+
48
+ /**
49
+ * Default ADR-014 axes applied when a v2 session is written without explicit
50
+ * caller-supplied values. Kernel-agnostic defaults — the pack may override via
51
+ * `resolveDefaultRoleContract` (CLI delegation-role-resolver.ts).
52
+ */
53
+ export const DEFAULT_SESSION_LIFECYCLE_ROLE = 'executor';
54
+ export const DEFAULT_SESSION_SPECIALTY_PROFILE = 'general';
55
+ export const DEFAULT_DISPLAY_NAME_POOL = [
56
+ 'Planck',
57
+ 'Hegel',
58
+ 'Curie',
59
+ 'Noether',
60
+ 'Turing',
61
+ 'Ada',
62
+ 'Gauss',
63
+ 'Euler',
64
+ 'Raman',
65
+ 'Hopper',
66
+ 'Lovelace',
67
+ 'Shannon',
68
+ ] as const;
69
+ export const DISPLAY_NAME_POOL_RELATIVE_PATH = '.lumenflow/agents/display-name-pool.yaml';
70
+ export const DISPLAY_NAME_RESERVATIONS_RELATIVE_PATH =
71
+ '.lumenflow/state/display-name-reservations.jsonl';
72
+ export const DISPLAY_NAME_RESERVATION_TTL_HOURS = 12;
73
+
74
+ /** Regex for delegation_id references back into delegation registry. */
75
+ export const DELEGATION_ID_PATTERN = /^dlg-[0-9a-f]{4}$/;
76
+
77
+ /**
78
+ * Session role axes — the three ADR-014 extension 2 fields that bind a live
79
+ * session to its delegation parent.
80
+ */
81
+ export const SessionRoleAxesSchema = z.object({
82
+ lifecycle_role: z.string().min(1, { message: 'lifecycle_role must be non-empty' }).optional(),
83
+ specialty_profile: z
84
+ .string()
85
+ .min(1, { message: 'specialty_profile must be non-empty' })
86
+ .optional(),
87
+ display_name: z.string().min(1, { message: 'display_name must be non-empty' }).optional(),
88
+ delegation_id: z
89
+ .string()
90
+ .regex(DELEGATION_ID_PATTERN, {
91
+ message: 'delegation_id must match dlg-XXXX (lowercase hex)',
92
+ })
93
+ .optional(),
94
+ });
95
+
96
+ /**
97
+ * Base session schema — shared fields across v1 and v2.
98
+ *
99
+ * Intentionally permissive: existing on-disk records have grown organically
100
+ * (lane, incidents, tiers, etc.). This schema focuses on the ADR-014 axes
101
+ * and only asserts the minimum invariants required for cross-linkage.
102
+ */
103
+ const SessionRecordBaseSchema = z.object({
104
+ session_id: z.string().min(1),
105
+ wu_id: z.string().min(1),
106
+ started: z.string().min(1),
107
+ });
108
+
109
+ /**
110
+ * v2 session record — ADR-014 axes are optional at the schema level because
111
+ * existing callers may not populate them yet. However, the auto-integration
112
+ * layer defaults them on every new v2 write (see auto-session-integration.ts).
113
+ */
114
+ const SessionRecordV2Schema = SessionRecordBaseSchema.extend({
115
+ schemaVersion: z.literal(SESSION_SCHEMA_VERSION_V2),
116
+ lifecycle_role: z.string().min(1).optional(),
117
+ specialty_profile: z.string().min(1).optional(),
118
+ display_name: z.string().min(1).optional(),
119
+ delegation_id: z
120
+ .string()
121
+ .regex(DELEGATION_ID_PATTERN, {
122
+ message: 'delegation_id must match dlg-XXXX (lowercase hex)',
123
+ })
124
+ .optional(),
125
+ });
126
+
127
+ /**
128
+ * v1-compat session record — no `schemaVersion` stamp. ADR-014 axes may be
129
+ * present (lenient) but are not required.
130
+ */
131
+ const SessionRecordV1Schema = SessionRecordBaseSchema.extend({
132
+ schemaVersion: z.undefined().optional(),
133
+ lifecycle_role: z.string().min(1).optional(),
134
+ specialty_profile: z.string().min(1).optional(),
135
+ display_name: z.string().min(1).optional(),
136
+ delegation_id: z.string().optional(),
137
+ });
138
+
139
+ /**
140
+ * Discriminated union — both v1 and v2 records are accepted on read.
141
+ */
142
+ export const SessionRecordSchema = z.union([SessionRecordV2Schema, SessionRecordV1Schema]);
143
+
144
+ export type SessionRecordV1 = z.infer<typeof SessionRecordV1Schema>;
145
+ export type SessionRecordV2 = z.infer<typeof SessionRecordV2Schema>;
146
+ export type SessionRecord = z.infer<typeof SessionRecordSchema>;
147
+ export type SessionRoleAxes = z.infer<typeof SessionRoleAxesSchema>;
148
+
149
+ /**
150
+ * Validates a session record against the v1/v2 discriminated union.
151
+ * Accepts both legacy and v2 records; callers that want strict v2 validation
152
+ * should check `isV2SessionRecord` after validation.
153
+ */
154
+ export function validateSessionRecord(data: unknown) {
155
+ return SessionRecordSchema.safeParse(data);
156
+ }
157
+
158
+ /**
159
+ * Type guard: returns true if the session record carries the v2 stamp.
160
+ */
161
+ export function isV2SessionRecord(record: SessionRecord): record is SessionRecordV2 {
162
+ return record.schemaVersion === SESSION_SCHEMA_VERSION_V2;
163
+ }
164
+
165
+ /**
166
+ * Apply ADR-014 v2 defaults to a partial role-axes input. Kernel-agnostic:
167
+ * string values passed through as-is; the pack vocabulary (lifecycle_role +
168
+ * specialty_profile) is owned by CLI callers.
169
+ */
170
+ export function withV2RoleDefaults(input: {
171
+ lifecycle_role?: string | null;
172
+ specialty_profile?: string | null;
173
+ display_name?: string | null;
174
+ delegation_id?: string | null;
175
+ }): {
176
+ lifecycle_role: string;
177
+ specialty_profile: string;
178
+ display_name?: string;
179
+ delegation_id?: string;
180
+ } {
181
+ const lifecycle_role =
182
+ typeof input.lifecycle_role === 'string' && input.lifecycle_role.trim().length > 0
183
+ ? input.lifecycle_role.trim()
184
+ : DEFAULT_SESSION_LIFECYCLE_ROLE;
185
+ const specialty_profile =
186
+ typeof input.specialty_profile === 'string' && input.specialty_profile.trim().length > 0
187
+ ? input.specialty_profile.trim()
188
+ : DEFAULT_SESSION_SPECIALTY_PROFILE;
189
+ const delegation_id =
190
+ typeof input.delegation_id === 'string' && DELEGATION_ID_PATTERN.test(input.delegation_id)
191
+ ? input.delegation_id
192
+ : undefined;
193
+ const display_name =
194
+ typeof input.display_name === 'string' && input.display_name.trim().length > 0
195
+ ? input.display_name.trim()
196
+ : undefined;
197
+ const out: {
198
+ lifecycle_role: string;
199
+ specialty_profile: string;
200
+ display_name?: string;
201
+ delegation_id?: string;
202
+ } = {
203
+ lifecycle_role,
204
+ specialty_profile,
205
+ };
206
+ if (display_name) {
207
+ out.display_name = display_name;
208
+ }
209
+ if (delegation_id) {
210
+ out.delegation_id = delegation_id;
211
+ }
212
+ return out;
213
+ }
214
+
215
+ interface DisplayNameReservation {
216
+ display_name: string;
217
+ session_id: string;
218
+ acquired_at: string;
219
+ }
220
+
221
+ interface DisplayNamePoolDocument {
222
+ names?: string[];
223
+ reservations?: DisplayNameReservation[];
224
+ ttl_hours?: number;
225
+ }
226
+
227
+ function getDisplayNamePoolPath(workspaceRoot: string): string {
228
+ return path.join(workspaceRoot, DISPLAY_NAME_POOL_RELATIVE_PATH);
229
+ }
230
+
231
+ function getDisplayNameReservationsPath(workspaceRoot: string): string {
232
+ return path.join(workspaceRoot, DISPLAY_NAME_RESERVATIONS_RELATIVE_PATH);
233
+ }
234
+
235
+ function getDisplayNameReservationTtlMs(ttlHours: number | undefined): number {
236
+ const hours =
237
+ typeof ttlHours === 'number' && Number.isFinite(ttlHours) && ttlHours > 0
238
+ ? ttlHours
239
+ : DISPLAY_NAME_RESERVATION_TTL_HOURS;
240
+ return hours * 60 * 60 * 1000;
241
+ }
242
+
243
+ function normalizeDisplayNamePoolDocument(raw: unknown): DisplayNamePoolDocument {
244
+ if (typeof raw !== 'object' || raw === null) {
245
+ return {
246
+ names: [...DEFAULT_DISPLAY_NAME_POOL],
247
+ reservations: [],
248
+ ttl_hours: DISPLAY_NAME_RESERVATION_TTL_HOURS,
249
+ };
250
+ }
251
+
252
+ const candidate = raw as DisplayNamePoolDocument;
253
+ return {
254
+ names: Array.isArray(candidate.names)
255
+ ? candidate.names.filter(
256
+ (entry): entry is string => typeof entry === 'string' && entry.length > 0,
257
+ )
258
+ : [...DEFAULT_DISPLAY_NAME_POOL],
259
+ reservations: Array.isArray(candidate.reservations)
260
+ ? candidate.reservations.filter(
261
+ (entry): entry is DisplayNameReservation =>
262
+ typeof entry?.display_name === 'string' &&
263
+ entry.display_name.length > 0 &&
264
+ typeof entry?.session_id === 'string' &&
265
+ entry.session_id.length > 0 &&
266
+ typeof entry?.acquired_at === 'string' &&
267
+ entry.acquired_at.length > 0,
268
+ )
269
+ : [],
270
+ ttl_hours:
271
+ typeof candidate.ttl_hours === 'number' && Number.isFinite(candidate.ttl_hours)
272
+ ? candidate.ttl_hours
273
+ : DISPLAY_NAME_RESERVATION_TTL_HOURS,
274
+ };
275
+ }
276
+
277
+ function readDisplayNamePoolDocument(workspaceRoot: string): DisplayNamePoolDocument {
278
+ const poolPath = getDisplayNamePoolPath(workspaceRoot);
279
+ if (!existsSync(poolPath)) {
280
+ return {
281
+ names: [...DEFAULT_DISPLAY_NAME_POOL],
282
+ };
283
+ }
284
+
285
+ try {
286
+ return normalizeDisplayNamePoolDocument(
287
+ parseYAML(readFileSync(poolPath, { encoding: 'utf-8' })),
288
+ );
289
+ } catch {
290
+ return {
291
+ names: [...DEFAULT_DISPLAY_NAME_POOL],
292
+ };
293
+ }
294
+ }
295
+
296
+ function readDisplayNameReservations(workspaceRoot: string): DisplayNameReservation[] {
297
+ const reservationsPath = getDisplayNameReservationsPath(workspaceRoot);
298
+ if (!existsSync(reservationsPath)) {
299
+ return [];
300
+ }
301
+
302
+ const raw = readFileSync(reservationsPath, { encoding: 'utf-8' }).trim();
303
+ if (raw.length === 0) {
304
+ return [];
305
+ }
306
+
307
+ return raw
308
+ .split('\n')
309
+ .map((line) => {
310
+ try {
311
+ return JSON.parse(line) as DisplayNameReservation;
312
+ } catch {
313
+ return null;
314
+ }
315
+ })
316
+ .filter(
317
+ (entry): entry is DisplayNameReservation =>
318
+ entry !== null &&
319
+ typeof entry.display_name === 'string' &&
320
+ entry.display_name.length > 0 &&
321
+ typeof entry.session_id === 'string' &&
322
+ entry.session_id.length > 0 &&
323
+ typeof entry.acquired_at === 'string' &&
324
+ entry.acquired_at.length > 0,
325
+ );
326
+ }
327
+
328
+ function writeDisplayNameReservations(
329
+ workspaceRoot: string,
330
+ reservations: DisplayNameReservation[],
331
+ ): void {
332
+ const reservationsPath = getDisplayNameReservationsPath(workspaceRoot);
333
+ if (reservations.length === 0) {
334
+ rmSync(reservationsPath, { force: true });
335
+ return;
336
+ }
337
+
338
+ mkdirSync(path.dirname(reservationsPath), { recursive: true });
339
+ writeFileSync(
340
+ reservationsPath,
341
+ `${reservations.map((reservation) => JSON.stringify(reservation)).join('\n')}\n`,
342
+ { encoding: 'utf-8' },
343
+ );
344
+ }
345
+
346
+ function loadDisplayNameState(
347
+ workspaceRoot: string,
348
+ now: Date,
349
+ ): {
350
+ names: string[];
351
+ reservations: DisplayNameReservation[];
352
+ } {
353
+ const document = readDisplayNamePoolDocument(workspaceRoot);
354
+ const names =
355
+ document.names && document.names.length > 0 ? document.names : [...DEFAULT_DISPLAY_NAME_POOL];
356
+ const ttlMs = getDisplayNameReservationTtlMs(document.ttl_hours);
357
+ const reservations = pruneExpiredReservations(
358
+ [...readDisplayNameReservations(workspaceRoot), ...(document.reservations ?? [])],
359
+ now,
360
+ ttlMs,
361
+ );
362
+
363
+ const uniqueReservations = new Map<string, DisplayNameReservation>();
364
+ for (const reservation of reservations) {
365
+ uniqueReservations.set(reservation.session_id, reservation);
366
+ }
367
+
368
+ writeDisplayNameReservations(workspaceRoot, [...uniqueReservations.values()]);
369
+
370
+ return {
371
+ names,
372
+ reservations: [...uniqueReservations.values()],
373
+ };
374
+ }
375
+
376
+ function pruneExpiredReservations(
377
+ reservations: DisplayNameReservation[],
378
+ now: Date,
379
+ ttlMs: number,
380
+ ): DisplayNameReservation[] {
381
+ return reservations.filter((reservation) => {
382
+ const acquiredAt = Date.parse(reservation.acquired_at);
383
+ if (Number.isNaN(acquiredAt)) {
384
+ return false;
385
+ }
386
+ return now.getTime() - acquiredAt < ttlMs;
387
+ });
388
+ }
389
+
390
+ export function acquireDisplayName(
391
+ workspaceRoot: string,
392
+ sessionId: string,
393
+ now: Date = new Date(),
394
+ ): string {
395
+ const state = loadDisplayNameState(workspaceRoot, now);
396
+ const reservations = state.reservations.filter(
397
+ (reservation) => reservation.session_id !== sessionId,
398
+ );
399
+ const reservedNames = new Set(reservations.map((reservation) => reservation.display_name));
400
+ const selectedName = state.names.find((name) => !reservedNames.has(name)) ?? sessionId;
401
+
402
+ reservations.push({
403
+ display_name: selectedName,
404
+ session_id: sessionId,
405
+ acquired_at: now.toISOString(),
406
+ });
407
+
408
+ writeDisplayNameReservations(workspaceRoot, reservations);
409
+
410
+ return selectedName;
411
+ }
412
+
413
+ export function releaseDisplayName(
414
+ workspaceRoot: string,
415
+ sessionId: string,
416
+ now: Date = new Date(),
417
+ ): void {
418
+ const state = loadDisplayNameState(workspaceRoot, now);
419
+ const reservations = state.reservations.filter(
420
+ (reservation) => reservation.session_id !== sessionId,
421
+ );
422
+ writeDisplayNameReservations(workspaceRoot, reservations);
423
+ }
@@ -3,3 +3,4 @@
3
3
 
4
4
  export * from './agent-turn-tools.js';
5
5
  export * from './provider-adapters.js';
6
+ export * from './remote-controls.js';