@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,220 @@
1
+ // Copyright (c) 2026 Hellmai Ltd
2
+ // SPDX-License-Identifier: AGPL-3.0-only
3
+
4
+ /**
5
+ * Delegation Registry Schema (ADR-014 follow-up, WU-2763)
6
+ *
7
+ * Canonical delegation schema and helpers for agent-runtime coordination
8
+ * records. Core now re-exports this module as a compatibility shim.
9
+ */
10
+
11
+ import crypto from 'node:crypto';
12
+ import { z } from 'zod';
13
+
14
+ /**
15
+ * Delegation status values.
16
+ */
17
+ const DELEGATION_STATUS_COMPLETED = 'completed';
18
+
19
+ export const DelegationStatus = {
20
+ PENDING: 'pending',
21
+ COMPLETED: DELEGATION_STATUS_COMPLETED,
22
+ TIMEOUT: 'timeout',
23
+ CRASHED: 'crashed',
24
+ ESCALATED: 'escalated',
25
+ } as const;
26
+
27
+ /** Type for delegation status values */
28
+ export type DelegationStatusValue = (typeof DelegationStatus)[keyof typeof DelegationStatus];
29
+
30
+ /** Array of valid delegation statuses */
31
+ export const DELEGATION_STATUSES = [
32
+ DelegationStatus.PENDING,
33
+ DelegationStatus.COMPLETED,
34
+ DelegationStatus.TIMEOUT,
35
+ DelegationStatus.CRASHED,
36
+ DelegationStatus.ESCALATED,
37
+ ] as const;
38
+
39
+ /**
40
+ * Optional delegation intent source values.
41
+ */
42
+ export const DelegationIntent = {
43
+ DELEGATION: 'delegation',
44
+ LEGACY_SPAWN: 'legacy-spawn',
45
+ } as const;
46
+
47
+ /** Type for delegation intent values */
48
+ export type DelegationIntentValue = (typeof DelegationIntent)[keyof typeof DelegationIntent];
49
+
50
+ /** Array of valid delegation intent values */
51
+ export const DELEGATION_INTENTS = [
52
+ DelegationIntent.DELEGATION,
53
+ DelegationIntent.LEGACY_SPAWN,
54
+ ] as const;
55
+
56
+ /**
57
+ * Regex patterns for delegation validation.
58
+ */
59
+ export const DELEGATION_PATTERNS = {
60
+ DELEGATION_ID: /^dlg-[0-9a-f]{4}$/,
61
+ WU_ID: /^WU-\d+$/,
62
+ };
63
+
64
+ /**
65
+ * Delegation schema version discriminator (WU-2753, ADR-014 extension 1).
66
+ *
67
+ * v1 records have no `schemaVersion` field (legacy compat path).
68
+ * v2 records stamp `schemaVersion: 'v2'` and MUST carry the four ADR-014
69
+ * axes: requested_role, actual_role, capabilities, ownership_scope.
70
+ *
71
+ * Agent-runtime owns the role metadata contract as opaque strings. The
72
+ * software-delivery pack still owns the canonical vocabulary.
73
+ */
74
+ export const DELEGATION_SCHEMA_VERSION_V2 = 'v2' as const;
75
+
76
+ /** Known delegation schema versions (extensible by additive pack updates). */
77
+ export const DELEGATION_SCHEMA_VERSIONS = [DELEGATION_SCHEMA_VERSION_V2] as const;
78
+
79
+ /** Type union for delegation schema version values. */
80
+ export type DelegationSchemaVersion = (typeof DELEGATION_SCHEMA_VERSIONS)[number];
81
+
82
+ /**
83
+ * Error messages for schema validation.
84
+ */
85
+ const ERROR_MESSAGES = {
86
+ DELEGATION_ID: 'Delegation ID must match pattern dlg-XXXX (e.g., dlg-a1b2)',
87
+ WU_ID: 'WU ID must match pattern WU-XXX (e.g., WU-1000)',
88
+ LANE_REQUIRED: 'Lane is required',
89
+ STATUS: `Status must be one of: ${DELEGATION_STATUSES.join(', ')}`,
90
+ INTENT: `Intent must be one of: ${DELEGATION_INTENTS.join(', ')}`,
91
+ TIMESTAMP_REQUIRED: 'Timestamp is required',
92
+ PICKUP_BY_REQUIRED: 'pickedUpBy must be a non-empty string when pickup is recorded',
93
+ BRIEF_HASH: 'briefAttestation.promptHash must be a 64-character lowercase sha256 hex digest',
94
+ BRIEF_ALGORITHM: 'briefAttestation.algorithm must be sha256',
95
+ BRIEF_CLIENT_REQUIRED: 'briefAttestation.clientName must be a non-empty string',
96
+ } as const;
97
+
98
+ const SHA256_HEX_256_REGEX = /^[a-f0-9]{64}$/;
99
+
100
+ /**
101
+ * Optional wu:brief prompt attestation captured by wu:delegate.
102
+ */
103
+ export const DelegationBriefAttestationSchema = z.object({
104
+ algorithm: z.literal('sha256', { error: ERROR_MESSAGES.BRIEF_ALGORITHM }),
105
+ promptHash: z.string().regex(SHA256_HEX_256_REGEX, { message: ERROR_MESSAGES.BRIEF_HASH }),
106
+ promptLength: z.number().int().nonnegative(),
107
+ generatedAt: z.string().datetime({ message: ERROR_MESSAGES.TIMESTAMP_REQUIRED }),
108
+ clientName: z.string().min(1, { message: ERROR_MESSAGES.BRIEF_CLIENT_REQUIRED }),
109
+ });
110
+
111
+ /**
112
+ * ADR-014 role descriptor — agent-runtime carries opaque strings; the
113
+ * software-delivery pack owns the AgentLifecycleRole vocabulary.
114
+ */
115
+ export const DelegationRoleDescriptorSchema = z.object({
116
+ lifecycle_role: z.string().min(1, { message: 'lifecycle_role must be non-empty' }),
117
+ specialty_profile: z.string().min(1, { message: 'specialty_profile must be non-empty' }),
118
+ role_alias: z.string().min(1).optional(),
119
+ capabilities: z.array(z.string()),
120
+ });
121
+
122
+ /**
123
+ * ADR-014 ownership scope for agent coordination.
124
+ */
125
+ export const DelegationOwnershipScopeSchema = z.object({
126
+ initiative_id: z.string().min(1).optional(),
127
+ wu_ids: z.array(z.string().min(1)).optional(),
128
+ lane: z.string().min(1).optional(),
129
+ responsibility_kinds: z.array(z.string().min(1)),
130
+ });
131
+
132
+ /**
133
+ * Delegation event base schema (shared by v1-compat and v2).
134
+ */
135
+ const DelegationEventBaseSchema = z.object({
136
+ id: z.string().regex(DELEGATION_PATTERNS.DELEGATION_ID, {
137
+ message: ERROR_MESSAGES.DELEGATION_ID,
138
+ }),
139
+ parentWuId: z.string().regex(DELEGATION_PATTERNS.WU_ID, { message: ERROR_MESSAGES.WU_ID }),
140
+ targetWuId: z.string().regex(DELEGATION_PATTERNS.WU_ID, { message: ERROR_MESSAGES.WU_ID }),
141
+ lane: z.string().min(1, { message: ERROR_MESSAGES.LANE_REQUIRED }),
142
+ intent: z.enum(DELEGATION_INTENTS, { error: ERROR_MESSAGES.INTENT }).optional(),
143
+ delegatedAt: z.string().datetime({ message: ERROR_MESSAGES.TIMESTAMP_REQUIRED }),
144
+ status: z.enum(DELEGATION_STATUSES, { error: ERROR_MESSAGES.STATUS }),
145
+ completedAt: z.string().datetime().nullable(),
146
+ pickedUpAt: z.string().datetime().optional(),
147
+ pickedUpBy: z.string().min(1, { message: ERROR_MESSAGES.PICKUP_BY_REQUIRED }).optional(),
148
+ briefAttestation: DelegationBriefAttestationSchema.optional(),
149
+ });
150
+
151
+ /**
152
+ * Legacy v1-compat delegation event schema.
153
+ */
154
+ const DelegationEventV1Schema = DelegationEventBaseSchema.extend({
155
+ schemaVersion: z.undefined().optional(),
156
+ requested_role: DelegationRoleDescriptorSchema.optional(),
157
+ actual_role: DelegationRoleDescriptorSchema.optional(),
158
+ capabilities: z.array(z.string()).optional(),
159
+ ownership_scope: DelegationOwnershipScopeSchema.optional(),
160
+ });
161
+
162
+ /**
163
+ * v2 delegation event schema (WU-2753, ADR-014 extension 1).
164
+ */
165
+ const DelegationEventV2Schema = DelegationEventBaseSchema.extend({
166
+ schemaVersion: z.literal(DELEGATION_SCHEMA_VERSION_V2),
167
+ requested_role: DelegationRoleDescriptorSchema,
168
+ actual_role: DelegationRoleDescriptorSchema,
169
+ capabilities: z.array(z.string()),
170
+ ownership_scope: DelegationOwnershipScopeSchema,
171
+ });
172
+
173
+ /**
174
+ * Delegation event schema — discriminated union across v1-compat and v2.
175
+ */
176
+ export const DelegationEventSchema = z.union([DelegationEventV2Schema, DelegationEventV1Schema]);
177
+
178
+ /** TypeScript type inferred from schema */
179
+ export type DelegationEvent = z.infer<typeof DelegationEventSchema>;
180
+ export type DelegationEventV1 = z.infer<typeof DelegationEventV1Schema>;
181
+ export type DelegationEventV2 = z.infer<typeof DelegationEventV2Schema>;
182
+ export type DelegationBriefAttestation = z.infer<typeof DelegationBriefAttestationSchema>;
183
+ export type DelegationRoleDescriptor = z.infer<typeof DelegationRoleDescriptorSchema>;
184
+ export type DelegationOwnershipScope = z.infer<typeof DelegationOwnershipScopeSchema>;
185
+
186
+ /**
187
+ * Bundle of the four ADR-014 axes that launch receipts and wu:delegate emit
188
+ * on every new delegation (WU-2753).
189
+ */
190
+ export interface DelegationRoleContract {
191
+ requested_role: DelegationRoleDescriptor;
192
+ actual_role: DelegationRoleDescriptor;
193
+ capabilities: string[];
194
+ ownership_scope: DelegationOwnershipScope;
195
+ }
196
+
197
+ /**
198
+ * Validates delegation event data against schema.
199
+ */
200
+ export function validateDelegationEvent(data: unknown) {
201
+ return DelegationEventSchema.safeParse(data);
202
+ }
203
+
204
+ /**
205
+ * Returns true if the delegation event carries the v2 role contract.
206
+ */
207
+ export function isV2DelegationEvent(event: DelegationEvent): event is DelegationEventV2 {
208
+ return event.schemaVersion === DELEGATION_SCHEMA_VERSION_V2;
209
+ }
210
+
211
+ /**
212
+ * Generates a unique delegation ID.
213
+ */
214
+ export function generateDelegationId(parentWuId: string, targetWuId: string): string {
215
+ const timestamp = Date.now().toString();
216
+ const randomBytes = crypto.randomBytes(4).toString('hex');
217
+ const input = `${parentWuId}:${targetWuId}:${timestamp}:${randomBytes}`;
218
+ const hash = crypto.createHash('sha256').update(input).digest('hex');
219
+ return `dlg-${hash.slice(0, 4)}`;
220
+ }
@@ -0,0 +1,269 @@
1
+ // Copyright (c) 2026 Hellmai Ltd
2
+ // SPDX-License-Identifier: AGPL-3.0-only
3
+
4
+ /**
5
+ * Delegation Registry Store (ADR-014 follow-up, WU-2763)
6
+ *
7
+ * Event-sourced state store for tracking sub-agent delegations.
8
+ * Stores events in .lumenflow/state/delegation-registry.jsonl (append-only, git-friendly).
9
+ *
10
+ * Core now re-exports this module as a compatibility shim.
11
+ */
12
+
13
+ import fs from 'node:fs/promises';
14
+ import path from 'node:path';
15
+ import { createError, ErrorCodes } from '@lumenflow/kernel/primitives/error-handler';
16
+ import {
17
+ validateDelegationEvent,
18
+ generateDelegationId,
19
+ DelegationStatus,
20
+ DELEGATION_SCHEMA_VERSION_V2,
21
+ type DelegationEvent,
22
+ type DelegationBriefAttestation,
23
+ type DelegationIntentValue,
24
+ type DelegationRoleContract,
25
+ } from './delegation-registry-schema.js';
26
+
27
+ interface ValidationIssueLike {
28
+ path: PropertyKey[];
29
+ message: string;
30
+ }
31
+
32
+ /** Delegation registry file name constant */
33
+ export const DELEGATION_REGISTRY_FILE_NAME = 'delegation-registry.jsonl';
34
+
35
+ function formatValidationIssues(issues: readonly ValidationIssueLike[]): string {
36
+ return issues.map((issue) => `${issue.path.join('.')}: ${issue.message}`).join(', ');
37
+ }
38
+
39
+ /**
40
+ * Delegation Registry Store class
41
+ */
42
+ export class DelegationRegistryStore {
43
+ private readonly baseDir: string;
44
+ private readonly registryFilePath: string;
45
+ private readonly delegations: Map<string, DelegationEvent>;
46
+ private readonly byParent: Map<string, string[]>;
47
+ private readonly byTarget: Map<string, string>;
48
+
49
+ /**
50
+ * @param {string} baseDir - Directory containing .lumenflow/state/
51
+ */
52
+ constructor(baseDir: string) {
53
+ this.baseDir = baseDir;
54
+ this.registryFilePath = path.join(baseDir, DELEGATION_REGISTRY_FILE_NAME);
55
+ this.delegations = new Map();
56
+ this.byParent = new Map();
57
+ this.byTarget = new Map();
58
+ }
59
+
60
+ /**
61
+ * Loads and replays events from JSONL file into current state.
62
+ */
63
+ async load(): Promise<void> {
64
+ this.delegations.clear();
65
+ this.byParent.clear();
66
+ this.byTarget.clear();
67
+
68
+ let content: string;
69
+ try {
70
+ content = await fs.readFile(this.registryFilePath, 'utf-8');
71
+ } catch (error) {
72
+ if ((error as NodeJS.ErrnoException).code === 'ENOENT') {
73
+ return;
74
+ }
75
+ throw error;
76
+ }
77
+
78
+ const lines = content.split('\n');
79
+ for (let i = 0; i < lines.length; i++) {
80
+ const rawLine = lines[i];
81
+ if (typeof rawLine !== 'string') {
82
+ continue;
83
+ }
84
+ const line = rawLine.trim();
85
+ if (!line) {
86
+ continue;
87
+ }
88
+
89
+ let parsed;
90
+ try {
91
+ parsed = JSON.parse(line);
92
+ } catch (error) {
93
+ throw createError(
94
+ ErrorCodes.PARSE_ERROR,
95
+ `Malformed JSON on line ${i + 1}: ${error.message}`,
96
+ );
97
+ }
98
+
99
+ const validation = validateDelegationEvent(parsed);
100
+ if (!validation.success) {
101
+ throw createError(
102
+ ErrorCodes.VALIDATION_ERROR,
103
+ `Validation error on line ${i + 1}: ${formatValidationIssues(validation.error.issues)}`,
104
+ );
105
+ }
106
+
107
+ this.applyEvent(validation.data);
108
+ }
109
+ }
110
+
111
+ /**
112
+ * Applies an event to the in-memory state.
113
+ */
114
+ private applyEvent(event: DelegationEvent): void {
115
+ const { id, parentWuId, targetWuId } = event;
116
+ this.delegations.set(id, event);
117
+
118
+ if (!this.byParent.has(parentWuId)) {
119
+ this.byParent.set(parentWuId, []);
120
+ }
121
+ const parentDelegations = this.byParent.get(parentWuId);
122
+ if (!parentDelegations) {
123
+ return;
124
+ }
125
+ if (!parentDelegations.includes(id)) {
126
+ parentDelegations.push(id);
127
+ }
128
+
129
+ this.byTarget.set(targetWuId, id);
130
+ }
131
+
132
+ /**
133
+ * Appends an event to the registry file.
134
+ */
135
+ private async appendEvent(event: DelegationEvent): Promise<void> {
136
+ const validation = validateDelegationEvent(event);
137
+ if (!validation.success) {
138
+ throw createError(
139
+ ErrorCodes.VALIDATION_ERROR,
140
+ `Validation error: ${formatValidationIssues(validation.error.issues)}`,
141
+ );
142
+ }
143
+
144
+ await fs.mkdir(this.baseDir, { recursive: true });
145
+ await fs.appendFile(this.registryFilePath, JSON.stringify(event) + '\n', 'utf-8');
146
+ }
147
+
148
+ /**
149
+ * Records a new delegation event with pending status.
150
+ */
151
+ async record(
152
+ parentWuId: string,
153
+ targetWuId: string,
154
+ lane: string,
155
+ intent?: DelegationIntentValue,
156
+ briefAttestation?: DelegationBriefAttestation,
157
+ delegationId?: string,
158
+ roleContract?: DelegationRoleContract,
159
+ ): Promise<string> {
160
+ const id = delegationId ?? generateDelegationId(parentWuId, targetWuId);
161
+
162
+ const event: DelegationEvent = {
163
+ id,
164
+ parentWuId,
165
+ targetWuId,
166
+ lane,
167
+ ...(intent ? { intent } : {}),
168
+ delegatedAt: new Date().toISOString(),
169
+ status: DelegationStatus.PENDING,
170
+ completedAt: null,
171
+ ...(briefAttestation ? { briefAttestation } : {}),
172
+ ...(roleContract
173
+ ? {
174
+ schemaVersion: DELEGATION_SCHEMA_VERSION_V2,
175
+ requested_role: roleContract.requested_role,
176
+ actual_role: roleContract.actual_role,
177
+ capabilities: roleContract.capabilities,
178
+ ownership_scope: roleContract.ownership_scope,
179
+ }
180
+ : {}),
181
+ } as DelegationEvent;
182
+
183
+ await this.appendEvent(event);
184
+ this.applyEvent(event);
185
+ return id;
186
+ }
187
+
188
+ /**
189
+ * Updates the status of a delegation.
190
+ */
191
+ async updateStatus(delegationId: string, status: string): Promise<void> {
192
+ const existing = this.delegations.get(delegationId);
193
+ if (!existing) {
194
+ throw createError(ErrorCodes.DELEGATION_NOT_FOUND, `Delegation ID ${delegationId} not found`);
195
+ }
196
+
197
+ const event: DelegationEvent = {
198
+ ...existing,
199
+ status: status as DelegationEvent['status'],
200
+ completedAt: new Date().toISOString(),
201
+ };
202
+
203
+ await this.appendEvent(event);
204
+ this.applyEvent(event);
205
+ }
206
+
207
+ /**
208
+ * Records claim-time pickup evidence for a delegation entry.
209
+ */
210
+ async recordPickup(delegationId: string, pickedUpBy: string, pickedUpAt?: string): Promise<void> {
211
+ const existing = this.delegations.get(delegationId);
212
+ if (!existing) {
213
+ throw createError(ErrorCodes.DELEGATION_NOT_FOUND, `Delegation ID ${delegationId} not found`);
214
+ }
215
+
216
+ const event: DelegationEvent = {
217
+ ...existing,
218
+ pickedUpBy,
219
+ pickedUpAt: pickedUpAt ?? new Date().toISOString(),
220
+ };
221
+
222
+ await this.appendEvent(event);
223
+ this.applyEvent(event);
224
+ }
225
+
226
+ /**
227
+ * Gets all delegations for a parent WU.
228
+ */
229
+ getByParent(parentWuId: string): DelegationEvent[] {
230
+ const delegationIds = this.byParent.get(parentWuId) ?? [];
231
+ return delegationIds
232
+ .map((id) => this.delegations.get(id))
233
+ .filter((event): event is DelegationEvent => event !== undefined);
234
+ }
235
+
236
+ /**
237
+ * Gets delegation for a target WU.
238
+ */
239
+ getByTarget(targetWuId: string): DelegationEvent | null {
240
+ const delegationId = this.byTarget.get(targetWuId);
241
+ if (!delegationId) {
242
+ return null;
243
+ }
244
+ return this.delegations.get(delegationId) ?? null;
245
+ }
246
+
247
+ /**
248
+ * Gets all pending delegations.
249
+ */
250
+ getPendingDelegations(): DelegationEvent[] {
251
+ return Array.from(this.delegations.values()).filter(
252
+ (delegation) => delegation.status === DelegationStatus.PENDING,
253
+ );
254
+ }
255
+
256
+ /**
257
+ * Gets all delegations as an array.
258
+ */
259
+ getAllDelegations(): DelegationEvent[] {
260
+ return Array.from(this.delegations.values());
261
+ }
262
+
263
+ /**
264
+ * Gets delegation by ID.
265
+ */
266
+ getById(delegationId: string): DelegationEvent | null {
267
+ return this.delegations.get(delegationId) ?? null;
268
+ }
269
+ }