@lumenflow/cli 5.4.0 → 5.7.12

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 (227) hide show
  1. package/README.md +42 -40
  2. package/dist/db-journal-recover.js +400 -0
  3. package/dist/db-journal-recover.js.map +1 -0
  4. package/dist/docs-sync.js +8 -3
  5. package/dist/docs-sync.js.map +1 -1
  6. package/dist/gate-defaults.js +191 -9
  7. package/dist/gate-defaults.js.map +1 -1
  8. package/dist/gate-registry.js.map +1 -1
  9. package/dist/gates/monolithic-file-contention-guard.js +167 -0
  10. package/dist/gates/monolithic-file-contention-guard.js.map +1 -0
  11. package/dist/gates/prod-migration-drift.js +207 -0
  12. package/dist/gates/prod-migration-drift.js.map +1 -0
  13. package/dist/gates/test-over-deletion-guard.js +255 -0
  14. package/dist/gates/test-over-deletion-guard.js.map +1 -0
  15. package/dist/gates-runners.js +401 -2
  16. package/dist/gates-runners.js.map +1 -1
  17. package/dist/gates.js +349 -4
  18. package/dist/gates.js.map +1 -1
  19. package/dist/lumenflow-setup.js +144 -0
  20. package/dist/lumenflow-setup.js.map +1 -0
  21. package/dist/lumenflow-upgrade.js +2 -1
  22. package/dist/lumenflow-upgrade.js.map +1 -1
  23. package/dist/mem-create.js +10 -1
  24. package/dist/mem-create.js.map +1 -1
  25. package/dist/mem-signal.js +21 -4
  26. package/dist/mem-signal.js.map +1 -1
  27. package/dist/metrics-cli.js +19 -2
  28. package/dist/metrics-cli.js.map +1 -1
  29. package/dist/metrics-snapshot.js +25 -2
  30. package/dist/metrics-snapshot.js.map +1 -1
  31. package/dist/orchestrate-initiative.js +28 -3
  32. package/dist/orchestrate-initiative.js.map +1 -1
  33. package/dist/public-manifest.js +17 -0
  34. package/dist/public-manifest.js.map +1 -1
  35. package/dist/release.js +53 -18
  36. package/dist/release.js.map +1 -1
  37. package/dist/wu-done-gates.js +121 -8
  38. package/dist/wu-done-gates.js.map +1 -1
  39. package/dist/wu-done.js +30 -6
  40. package/dist/wu-done.js.map +1 -1
  41. package/dist/wu-edit-operations.js +74 -0
  42. package/dist/wu-edit-operations.js.map +1 -1
  43. package/dist/wu-edit-validators.js +58 -0
  44. package/dist/wu-edit-validators.js.map +1 -1
  45. package/dist/wu-edit.js +106 -4
  46. package/dist/wu-edit.js.map +1 -1
  47. package/dist/wu-prep.js +132 -8
  48. package/dist/wu-prep.js.map +1 -1
  49. package/dist/wu-recover.js +6 -0
  50. package/dist/wu-recover.js.map +1 -1
  51. package/dist/wu-release.js +120 -2
  52. package/dist/wu-release.js.map +1 -1
  53. package/dist/wu-sizing-validation.js +47 -17
  54. package/dist/wu-sizing-validation.js.map +1 -1
  55. package/dist/wu-status.js +33 -0
  56. package/dist/wu-status.js.map +1 -1
  57. package/package.json +13 -11
  58. package/packs/agent-runtime/package.json +1 -1
  59. package/packs/sidekick/package.json +1 -1
  60. package/packs/software-delivery/package.json +1 -1
  61. package/templates/core/AGENTS.md.template +162 -26
  62. package/templates/core/LUMENFLOW.md.template +381 -70
  63. package/templates/core/ai/onboarding/agent-invocation-guide.md.template +0 -5
  64. package/templates/core/ai/onboarding/agent-safety-card.md.template +63 -17
  65. package/templates/core/ai/onboarding/initiative-orchestration.md.template +4 -0
  66. package/templates/core/ai/onboarding/release-process.md.template +7 -7
  67. package/templates/core/ai/onboarding/vendor-support.md.template +74 -10
  68. package/templates/vendors/claude/.claude/skills/frontend-design/SKILL.md.template +1 -1
  69. package/templates/vendors/claude/.claude/skills/wu-lifecycle/SKILL.md.template +28 -0
  70. package/packs/agent-runtime/agent-heartbeat.ts +0 -163
  71. package/packs/agent-runtime/auto-session-integration.ts +0 -888
  72. package/packs/agent-runtime/capability-factory.ts +0 -104
  73. package/packs/agent-runtime/constants.ts +0 -21
  74. package/packs/agent-runtime/delegation-registry-schema.ts +0 -220
  75. package/packs/agent-runtime/delegation-registry-store.ts +0 -269
  76. package/packs/agent-runtime/delegation-tree.ts +0 -328
  77. package/packs/agent-runtime/index.ts +0 -20
  78. package/packs/agent-runtime/manifest.ts +0 -348
  79. package/packs/agent-runtime/memory-coordination-contract.ts +0 -86
  80. package/packs/agent-runtime/orchestration.ts +0 -2027
  81. package/packs/agent-runtime/pack-registration.ts +0 -110
  82. package/packs/agent-runtime/policy-factory.ts +0 -165
  83. package/packs/agent-runtime/remote-controls/index.ts +0 -7
  84. package/packs/agent-runtime/remote-controls/operations.ts +0 -405
  85. package/packs/agent-runtime/remote-controls/port.ts +0 -48
  86. package/packs/agent-runtime/remote-controls/state-store.ts +0 -258
  87. package/packs/agent-runtime/remote-controls/types.ts +0 -105
  88. package/packs/agent-runtime/session-schema.ts +0 -467
  89. package/packs/agent-runtime/tool-impl/agent-turn-tools.ts +0 -793
  90. package/packs/agent-runtime/tool-impl/index.ts +0 -6
  91. package/packs/agent-runtime/tool-impl/provider-adapters.ts +0 -1245
  92. package/packs/agent-runtime/tool-impl/remote-controls.mock.ts +0 -256
  93. package/packs/agent-runtime/tool-impl/remote-controls.ts +0 -273
  94. package/packs/agent-runtime/tools/index.ts +0 -4
  95. package/packs/agent-runtime/tools/types.ts +0 -47
  96. package/packs/agent-runtime/turn-lifecycle-events.ts +0 -590
  97. package/packs/agent-runtime/types.ts +0 -128
  98. package/packs/agent-runtime/vitest.config.ts +0 -11
  99. package/packs/sidekick/channel-ingress.ts +0 -137
  100. package/packs/sidekick/constants.ts +0 -10
  101. package/packs/sidekick/index.ts +0 -8
  102. package/packs/sidekick/manifest-schema.ts +0 -49
  103. package/packs/sidekick/manifest.ts +0 -512
  104. package/packs/sidekick/pack-registration.ts +0 -110
  105. package/packs/sidekick/policy-factory.ts +0 -38
  106. package/packs/sidekick/sidekick-events.ts +0 -694
  107. package/packs/sidekick/src/adapters/cloud-queue.ts +0 -101
  108. package/packs/sidekick/src/adapters/control-plane-bridge.adapter.ts +0 -386
  109. package/packs/sidekick/src/adapters/filesystem-bridge.adapter.ts +0 -228
  110. package/packs/sidekick/src/domain/channel.types.ts +0 -64
  111. package/packs/sidekick/src/ports/channel-bridge.port.ts +0 -92
  112. package/packs/sidekick/src/routines/commit.ts +0 -74
  113. package/packs/sidekick/tool-impl/channel-tools.ts +0 -577
  114. package/packs/sidekick/tool-impl/channel-transports.ts +0 -75
  115. package/packs/sidekick/tool-impl/index.ts +0 -29
  116. package/packs/sidekick/tool-impl/memory-tools.ts +0 -290
  117. package/packs/sidekick/tool-impl/routine-commit.ts +0 -102
  118. package/packs/sidekick/tool-impl/routine-tools.ts +0 -440
  119. package/packs/sidekick/tool-impl/runtime-context.ts +0 -28
  120. package/packs/sidekick/tool-impl/shared.ts +0 -125
  121. package/packs/sidekick/tool-impl/storage.ts +0 -325
  122. package/packs/sidekick/tool-impl/system-tools.ts +0 -160
  123. package/packs/sidekick/tool-impl/task-tools.ts +0 -506
  124. package/packs/sidekick/tools/channel-tools.ts +0 -53
  125. package/packs/sidekick/tools/index.ts +0 -9
  126. package/packs/sidekick/tools/memory-tools.ts +0 -53
  127. package/packs/sidekick/tools/routine-tools.ts +0 -53
  128. package/packs/sidekick/tools/system-tools.ts +0 -47
  129. package/packs/sidekick/tools/task-tools.ts +0 -61
  130. package/packs/sidekick/tools/types.ts +0 -57
  131. package/packs/sidekick/vitest.config.ts +0 -11
  132. package/packs/software-delivery/constants.ts +0 -10
  133. package/packs/software-delivery/extensions.ts +0 -140
  134. package/packs/software-delivery/gate-policies.ts +0 -134
  135. package/packs/software-delivery/index.ts +0 -8
  136. package/packs/software-delivery/manifest-schema.ts +0 -268
  137. package/packs/software-delivery/manifest.ts +0 -657
  138. package/packs/software-delivery/pack-registration.ts +0 -113
  139. package/packs/software-delivery/src/commands/index.ts +0 -5
  140. package/packs/software-delivery/src/config/delivery-review-contract.ts +0 -256
  141. package/packs/software-delivery/src/config/env-accessors.ts +0 -66
  142. package/packs/software-delivery/src/config/index.ts +0 -8
  143. package/packs/software-delivery/src/config/normalize-config-keys.ts +0 -9
  144. package/packs/software-delivery/src/config/schemas/lumenflow-config-schema-types.ts +0 -460
  145. package/packs/software-delivery/src/config/workspace-reader.ts +0 -375
  146. package/packs/software-delivery/src/constants/backlog-patterns.ts +0 -31
  147. package/packs/software-delivery/src/constants/client-ids.ts +0 -19
  148. package/packs/software-delivery/src/constants/config-contract.ts +0 -7
  149. package/packs/software-delivery/src/constants/docs-layout-presets.ts +0 -50
  150. package/packs/software-delivery/src/constants/duration-constants.ts +0 -20
  151. package/packs/software-delivery/src/constants/gate-constants.ts +0 -32
  152. package/packs/software-delivery/src/constants/index.ts +0 -29
  153. package/packs/software-delivery/src/constants/lock-constants.ts +0 -35
  154. package/packs/software-delivery/src/constants/object-guards.ts +0 -12
  155. package/packs/software-delivery/src/constants/section-headings.ts +0 -107
  156. package/packs/software-delivery/src/constants/wu-cli-constants.ts +0 -488
  157. package/packs/software-delivery/src/constants/wu-domain-constants.ts +0 -466
  158. package/packs/software-delivery/src/constants/wu-git-constants.ts +0 -7
  159. package/packs/software-delivery/src/constants/wu-id-format.ts +0 -327
  160. package/packs/software-delivery/src/constants/wu-paths-constants.ts +0 -384
  161. package/packs/software-delivery/src/constants/wu-statuses.ts +0 -287
  162. package/packs/software-delivery/src/constants/wu-type-helpers.ts +0 -67
  163. package/packs/software-delivery/src/constants/wu-ui-constants.ts +0 -267
  164. package/packs/software-delivery/src/constants/wu-validation-constants.ts +0 -73
  165. package/packs/software-delivery/src/domain/index.ts +0 -5
  166. package/packs/software-delivery/src/domain/orchestration.constants.ts +0 -166
  167. package/packs/software-delivery/src/domain/orchestration.schemas.ts +0 -238
  168. package/packs/software-delivery/src/domain/orchestration.types.ts +0 -176
  169. package/packs/software-delivery/src/methodology/incremental-test.ts +0 -122
  170. package/packs/software-delivery/src/methodology/index.ts +0 -6
  171. package/packs/software-delivery/src/methodology/manual-test-validator.ts +0 -292
  172. package/packs/software-delivery/src/policy/coverage-gate.ts +0 -270
  173. package/packs/software-delivery/src/policy/gates-agent-mode.ts +0 -223
  174. package/packs/software-delivery/src/policy/gates-config-internal.ts +0 -121
  175. package/packs/software-delivery/src/policy/gates-config.ts +0 -300
  176. package/packs/software-delivery/src/policy/gates-coverage.ts +0 -356
  177. package/packs/software-delivery/src/policy/gates-presets.ts +0 -134
  178. package/packs/software-delivery/src/policy/gates-schemas.ts +0 -173
  179. package/packs/software-delivery/src/policy/index.ts +0 -22
  180. package/packs/software-delivery/src/policy/package-manager-resolver.ts +0 -319
  181. package/packs/software-delivery/src/policy/resolve-policy.ts +0 -601
  182. package/packs/software-delivery/src/ports/config.ports.ts +0 -90
  183. package/packs/software-delivery/src/ports/dashboard-renderer.port.ts +0 -125
  184. package/packs/software-delivery/src/ports/index.ts +0 -10
  185. package/packs/software-delivery/src/ports/sync-validator.ports.ts +0 -59
  186. package/packs/software-delivery/src/ports/wu-helpers.ports.ts +0 -168
  187. package/packs/software-delivery/src/ports/wu-state.ports.ts +0 -241
  188. package/packs/software-delivery/src/primitives/index.ts +0 -5
  189. package/packs/software-delivery/src/runtime/index.ts +0 -6
  190. package/packs/software-delivery/src/runtime/work-classifier.ts +0 -561
  191. package/packs/software-delivery/src/sandbox/index.ts +0 -10
  192. package/packs/software-delivery/src/sandbox/sandbox-allowlist.ts +0 -118
  193. package/packs/software-delivery/src/sandbox/sandbox-backend-linux.ts +0 -88
  194. package/packs/software-delivery/src/sandbox/sandbox-backend-macos.ts +0 -154
  195. package/packs/software-delivery/src/sandbox/sandbox-backend-windows.ts +0 -47
  196. package/packs/software-delivery/src/sandbox/sandbox-profile.ts +0 -153
  197. package/packs/software-delivery/src/schemas/index.ts +0 -5
  198. package/packs/software-delivery/src/state/date-utils.ts +0 -158
  199. package/packs/software-delivery/src/state/index.ts +0 -15
  200. package/packs/software-delivery/src/state/state-machine.ts +0 -119
  201. package/packs/software-delivery/src/state/wu-doc-types.ts +0 -51
  202. package/packs/software-delivery/src/state/wu-paths.ts +0 -381
  203. package/packs/software-delivery/src/state/wu-schema.ts +0 -1139
  204. package/packs/software-delivery/src/state/wu-state-schema.ts +0 -255
  205. package/packs/software-delivery/src/state/wu-yaml.ts +0 -338
  206. package/packs/software-delivery/tool-impl/agent-tools.ts +0 -263
  207. package/packs/software-delivery/tool-impl/delegation-tools.ts +0 -66
  208. package/packs/software-delivery/tool-impl/flow-metrics-tools.ts +0 -219
  209. package/packs/software-delivery/tool-impl/git-runner.ts +0 -113
  210. package/packs/software-delivery/tool-impl/git-tools.ts +0 -316
  211. package/packs/software-delivery/tool-impl/index.ts +0 -15
  212. package/packs/software-delivery/tool-impl/initiative-orchestration-tools.ts +0 -720
  213. package/packs/software-delivery/tool-impl/lane-lock.ts +0 -246
  214. package/packs/software-delivery/tool-impl/memory-tools.ts +0 -470
  215. package/packs/software-delivery/tool-impl/pending-runtime-tools.ts +0 -21
  216. package/packs/software-delivery/tool-impl/runtime-cli-adapter.ts +0 -329
  217. package/packs/software-delivery/tool-impl/runtime-native-tools.ts +0 -687
  218. package/packs/software-delivery/tool-impl/worker-loader.ts +0 -52
  219. package/packs/software-delivery/tool-impl/worktree-tools.ts +0 -46
  220. package/packs/software-delivery/tool-impl/wu-lifecycle-tools.ts +0 -807
  221. package/packs/software-delivery/tools/delegation-tools.ts +0 -23
  222. package/packs/software-delivery/tools/git-tools.ts +0 -55
  223. package/packs/software-delivery/tools/index.ts +0 -8
  224. package/packs/software-delivery/tools/lane-lock-tool.ts +0 -37
  225. package/packs/software-delivery/tools/types.ts +0 -71
  226. package/packs/software-delivery/tools/worktree-tools.ts +0 -49
  227. package/packs/software-delivery/vitest.config.ts +0 -11
@@ -1,467 +0,0 @@
1
- // Copyright (c) 2026 Hellmai Ltd
2
- // SPDX-License-Identifier: LicenseRef-LumenFlow-Proprietary
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
- export const AGENT_IDENTITY_MIN_LENGTH = 3;
74
-
75
- /** Regex for delegation_id references back into delegation registry. */
76
- export const DELEGATION_ID_PATTERN = /^dlg-[0-9a-f]{4}$/;
77
-
78
- /**
79
- * Session role axes — the three ADR-014 extension 2 fields that bind a live
80
- * session to its delegation parent.
81
- */
82
- export const SessionRoleAxesSchema = z.object({
83
- lifecycle_role: z.string().min(1, { message: 'lifecycle_role must be non-empty' }).optional(),
84
- specialty_profile: z
85
- .string()
86
- .min(1, { message: 'specialty_profile must be non-empty' })
87
- .optional(),
88
- display_name: z.string().min(1, { message: 'display_name must be non-empty' }).optional(),
89
- delegation_id: z
90
- .string()
91
- .regex(DELEGATION_ID_PATTERN, {
92
- message: 'delegation_id must match dlg-XXXX (lowercase hex)',
93
- })
94
- .optional(),
95
- });
96
-
97
- const AgentIdentitySchema = z
98
- .string()
99
- .trim()
100
- .min(AGENT_IDENTITY_MIN_LENGTH, {
101
- message: `agent_identity must be at least ${AGENT_IDENTITY_MIN_LENGTH} characters`,
102
- });
103
- const TenantIdSchema = z.string().trim().min(1, { message: 'tenant_id must be non-empty' });
104
-
105
- /**
106
- * Base session schema — shared fields across v1 and v2.
107
- *
108
- * Intentionally permissive: existing on-disk records have grown organically
109
- * (lane, incidents, tiers, etc.). This schema focuses on the ADR-014 axes
110
- * and only asserts the minimum invariants required for cross-linkage.
111
- */
112
- const SessionRecordBaseSchema = z.object({
113
- session_id: z.string().min(1),
114
- wu_id: z.string().min(1),
115
- started: z.string().min(1),
116
- agent_identity: AgentIdentitySchema.optional(),
117
- tenant_id: TenantIdSchema.optional(),
118
- });
119
-
120
- /**
121
- * v2 session record — ADR-014 axes are optional at the schema level because
122
- * existing callers may not populate them yet. However, the auto-integration
123
- * layer defaults them on every new v2 write (see auto-session-integration.ts).
124
- */
125
- const SessionRecordV2Schema = SessionRecordBaseSchema.extend({
126
- schemaVersion: z.literal(SESSION_SCHEMA_VERSION_V2),
127
- lifecycle_role: z.string().min(1).optional(),
128
- specialty_profile: z.string().min(1).optional(),
129
- display_name: z.string().min(1).optional(),
130
- delegation_id: z
131
- .string()
132
- .regex(DELEGATION_ID_PATTERN, {
133
- message: 'delegation_id must match dlg-XXXX (lowercase hex)',
134
- })
135
- .optional(),
136
- });
137
-
138
- /**
139
- * v1-compat session record — no `schemaVersion` stamp. ADR-014 axes may be
140
- * present (lenient) but are not required.
141
- */
142
- const SessionRecordV1Schema = SessionRecordBaseSchema.extend({
143
- schemaVersion: z.undefined().optional(),
144
- lifecycle_role: z.string().min(1).optional(),
145
- specialty_profile: z.string().min(1).optional(),
146
- display_name: z.string().min(1).optional(),
147
- delegation_id: z.string().optional(),
148
- });
149
-
150
- /**
151
- * Discriminated union — both v1 and v2 records are accepted on read.
152
- */
153
- export const SessionRecordSchema = z.union([SessionRecordV2Schema, SessionRecordV1Schema]);
154
-
155
- export type SessionRecordV1 = z.infer<typeof SessionRecordV1Schema>;
156
- export type SessionRecordV2 = z.infer<typeof SessionRecordV2Schema>;
157
- export type SessionRecord = z.infer<typeof SessionRecordSchema>;
158
- export type SessionRoleAxes = z.infer<typeof SessionRoleAxesSchema>;
159
-
160
- /**
161
- * Validates a session record against the v1/v2 discriminated union.
162
- * Accepts both legacy and v2 records; callers that want strict v2 validation
163
- * should check `isV2SessionRecord` after validation.
164
- */
165
- export function validateSessionRecord(data: unknown) {
166
- return SessionRecordSchema.safeParse(data);
167
- }
168
-
169
- /**
170
- * Type guard: returns true if the session record carries the v2 stamp.
171
- */
172
- export function isV2SessionRecord(record: SessionRecord): record is SessionRecordV2 {
173
- return record.schemaVersion === SESSION_SCHEMA_VERSION_V2;
174
- }
175
-
176
- /**
177
- * Apply ADR-014 v2 defaults to a partial role-axes input. Kernel-agnostic:
178
- * string values passed through as-is; the pack vocabulary (lifecycle_role +
179
- * specialty_profile) is owned by CLI callers.
180
- */
181
- export function withV2RoleDefaults(input: {
182
- lifecycle_role?: string | null;
183
- specialty_profile?: string | null;
184
- display_name?: string | null;
185
- delegation_id?: string | null;
186
- agent_identity?: string | null;
187
- tenant_id?: string | null;
188
- }): {
189
- lifecycle_role: string;
190
- specialty_profile: string;
191
- display_name?: string;
192
- delegation_id?: string;
193
- agent_identity?: string;
194
- tenant_id?: string;
195
- } {
196
- const lifecycle_role =
197
- typeof input.lifecycle_role === 'string' && input.lifecycle_role.trim().length > 0
198
- ? input.lifecycle_role.trim()
199
- : DEFAULT_SESSION_LIFECYCLE_ROLE;
200
- const specialty_profile =
201
- typeof input.specialty_profile === 'string' && input.specialty_profile.trim().length > 0
202
- ? input.specialty_profile.trim()
203
- : DEFAULT_SESSION_SPECIALTY_PROFILE;
204
- const delegation_id =
205
- typeof input.delegation_id === 'string' && DELEGATION_ID_PATTERN.test(input.delegation_id)
206
- ? input.delegation_id
207
- : undefined;
208
- const display_name =
209
- typeof input.display_name === 'string' && input.display_name.trim().length > 0
210
- ? input.display_name.trim()
211
- : undefined;
212
- const identityFields = normalizeOptionalSessionIdentityFields(input);
213
- const out: {
214
- lifecycle_role: string;
215
- specialty_profile: string;
216
- display_name?: string;
217
- delegation_id?: string;
218
- agent_identity?: string;
219
- tenant_id?: string;
220
- } = {
221
- lifecycle_role,
222
- specialty_profile,
223
- };
224
- if (display_name) {
225
- out.display_name = display_name;
226
- }
227
- if (delegation_id) {
228
- out.delegation_id = delegation_id;
229
- }
230
- if (identityFields.agent_identity) {
231
- out.agent_identity = identityFields.agent_identity;
232
- }
233
- if (identityFields.tenant_id) {
234
- out.tenant_id = identityFields.tenant_id;
235
- }
236
- return out;
237
- }
238
-
239
- export function normalizeOptionalSessionIdentityFields(input: {
240
- agent_identity?: string | null;
241
- tenant_id?: string | null;
242
- }): {
243
- agent_identity?: string;
244
- tenant_id?: string;
245
- } {
246
- const out: {
247
- agent_identity?: string;
248
- tenant_id?: string;
249
- } = {};
250
- if (typeof input.agent_identity === 'string' && input.agent_identity.trim().length > 0) {
251
- out.agent_identity = AgentIdentitySchema.parse(input.agent_identity);
252
- }
253
- if (typeof input.tenant_id === 'string' && input.tenant_id.trim().length > 0) {
254
- out.tenant_id = TenantIdSchema.parse(input.tenant_id);
255
- }
256
- return out;
257
- }
258
-
259
- interface DisplayNameReservation {
260
- display_name: string;
261
- session_id: string;
262
- acquired_at: string;
263
- }
264
-
265
- interface DisplayNamePoolDocument {
266
- names?: string[];
267
- reservations?: DisplayNameReservation[];
268
- ttl_hours?: number;
269
- }
270
-
271
- function getDisplayNamePoolPath(workspaceRoot: string): string {
272
- return path.join(workspaceRoot, DISPLAY_NAME_POOL_RELATIVE_PATH);
273
- }
274
-
275
- function getDisplayNameReservationsPath(workspaceRoot: string): string {
276
- return path.join(workspaceRoot, DISPLAY_NAME_RESERVATIONS_RELATIVE_PATH);
277
- }
278
-
279
- function getDisplayNameReservationTtlMs(ttlHours: number | undefined): number {
280
- const hours =
281
- typeof ttlHours === 'number' && Number.isFinite(ttlHours) && ttlHours > 0
282
- ? ttlHours
283
- : DISPLAY_NAME_RESERVATION_TTL_HOURS;
284
- return hours * 60 * 60 * 1000;
285
- }
286
-
287
- function normalizeDisplayNamePoolDocument(raw: unknown): DisplayNamePoolDocument {
288
- if (typeof raw !== 'object' || raw === null) {
289
- return {
290
- names: [...DEFAULT_DISPLAY_NAME_POOL],
291
- reservations: [],
292
- ttl_hours: DISPLAY_NAME_RESERVATION_TTL_HOURS,
293
- };
294
- }
295
-
296
- const candidate = raw as DisplayNamePoolDocument;
297
- return {
298
- names: Array.isArray(candidate.names)
299
- ? candidate.names.filter(
300
- (entry): entry is string => typeof entry === 'string' && entry.length > 0,
301
- )
302
- : [...DEFAULT_DISPLAY_NAME_POOL],
303
- reservations: Array.isArray(candidate.reservations)
304
- ? candidate.reservations.filter(
305
- (entry): entry is DisplayNameReservation =>
306
- typeof entry?.display_name === 'string' &&
307
- entry.display_name.length > 0 &&
308
- typeof entry?.session_id === 'string' &&
309
- entry.session_id.length > 0 &&
310
- typeof entry?.acquired_at === 'string' &&
311
- entry.acquired_at.length > 0,
312
- )
313
- : [],
314
- ttl_hours:
315
- typeof candidate.ttl_hours === 'number' && Number.isFinite(candidate.ttl_hours)
316
- ? candidate.ttl_hours
317
- : DISPLAY_NAME_RESERVATION_TTL_HOURS,
318
- };
319
- }
320
-
321
- function readDisplayNamePoolDocument(workspaceRoot: string): DisplayNamePoolDocument {
322
- const poolPath = getDisplayNamePoolPath(workspaceRoot);
323
- if (!existsSync(poolPath)) {
324
- return {
325
- names: [...DEFAULT_DISPLAY_NAME_POOL],
326
- };
327
- }
328
-
329
- try {
330
- return normalizeDisplayNamePoolDocument(
331
- parseYAML(readFileSync(poolPath, { encoding: 'utf-8' })),
332
- );
333
- } catch {
334
- return {
335
- names: [...DEFAULT_DISPLAY_NAME_POOL],
336
- };
337
- }
338
- }
339
-
340
- function readDisplayNameReservations(workspaceRoot: string): DisplayNameReservation[] {
341
- const reservationsPath = getDisplayNameReservationsPath(workspaceRoot);
342
- if (!existsSync(reservationsPath)) {
343
- return [];
344
- }
345
-
346
- const raw = readFileSync(reservationsPath, { encoding: 'utf-8' }).trim();
347
- if (raw.length === 0) {
348
- return [];
349
- }
350
-
351
- return raw
352
- .split('\n')
353
- .map((line) => {
354
- try {
355
- return JSON.parse(line) as DisplayNameReservation;
356
- } catch {
357
- return null;
358
- }
359
- })
360
- .filter(
361
- (entry): entry is DisplayNameReservation =>
362
- entry !== null &&
363
- typeof entry.display_name === 'string' &&
364
- entry.display_name.length > 0 &&
365
- typeof entry.session_id === 'string' &&
366
- entry.session_id.length > 0 &&
367
- typeof entry.acquired_at === 'string' &&
368
- entry.acquired_at.length > 0,
369
- );
370
- }
371
-
372
- function writeDisplayNameReservations(
373
- workspaceRoot: string,
374
- reservations: DisplayNameReservation[],
375
- ): void {
376
- const reservationsPath = getDisplayNameReservationsPath(workspaceRoot);
377
- if (reservations.length === 0) {
378
- rmSync(reservationsPath, { force: true });
379
- return;
380
- }
381
-
382
- mkdirSync(path.dirname(reservationsPath), { recursive: true });
383
- writeFileSync(
384
- reservationsPath,
385
- `${reservations.map((reservation) => JSON.stringify(reservation)).join('\n')}\n`,
386
- { encoding: 'utf-8' },
387
- );
388
- }
389
-
390
- function loadDisplayNameState(
391
- workspaceRoot: string,
392
- now: Date,
393
- ): {
394
- names: string[];
395
- reservations: DisplayNameReservation[];
396
- } {
397
- const document = readDisplayNamePoolDocument(workspaceRoot);
398
- const names =
399
- document.names && document.names.length > 0 ? document.names : [...DEFAULT_DISPLAY_NAME_POOL];
400
- const ttlMs = getDisplayNameReservationTtlMs(document.ttl_hours);
401
- const reservations = pruneExpiredReservations(
402
- [...readDisplayNameReservations(workspaceRoot), ...(document.reservations ?? [])],
403
- now,
404
- ttlMs,
405
- );
406
-
407
- const uniqueReservations = new Map<string, DisplayNameReservation>();
408
- for (const reservation of reservations) {
409
- uniqueReservations.set(reservation.session_id, reservation);
410
- }
411
-
412
- writeDisplayNameReservations(workspaceRoot, [...uniqueReservations.values()]);
413
-
414
- return {
415
- names,
416
- reservations: [...uniqueReservations.values()],
417
- };
418
- }
419
-
420
- function pruneExpiredReservations(
421
- reservations: DisplayNameReservation[],
422
- now: Date,
423
- ttlMs: number,
424
- ): DisplayNameReservation[] {
425
- return reservations.filter((reservation) => {
426
- const acquiredAt = Date.parse(reservation.acquired_at);
427
- if (Number.isNaN(acquiredAt)) {
428
- return false;
429
- }
430
- return now.getTime() - acquiredAt < ttlMs;
431
- });
432
- }
433
-
434
- export function acquireDisplayName(
435
- workspaceRoot: string,
436
- sessionId: string,
437
- now: Date = new Date(),
438
- ): string {
439
- const state = loadDisplayNameState(workspaceRoot, now);
440
- const reservations = state.reservations.filter(
441
- (reservation) => reservation.session_id !== sessionId,
442
- );
443
- const reservedNames = new Set(reservations.map((reservation) => reservation.display_name));
444
- const selectedName = state.names.find((name) => !reservedNames.has(name)) ?? sessionId;
445
-
446
- reservations.push({
447
- display_name: selectedName,
448
- session_id: sessionId,
449
- acquired_at: now.toISOString(),
450
- });
451
-
452
- writeDisplayNameReservations(workspaceRoot, reservations);
453
-
454
- return selectedName;
455
- }
456
-
457
- export function releaseDisplayName(
458
- workspaceRoot: string,
459
- sessionId: string,
460
- now: Date = new Date(),
461
- ): void {
462
- const state = loadDisplayNameState(workspaceRoot, now);
463
- const reservations = state.reservations.filter(
464
- (reservation) => reservation.session_id !== sessionId,
465
- );
466
- writeDisplayNameReservations(workspaceRoot, reservations);
467
- }