@lumenflow/cli 5.5.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 (213) 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 +37 -0
  7. package/dist/gate-defaults.js.map +1 -1
  8. package/dist/gates/monolithic-file-contention-guard.js +167 -0
  9. package/dist/gates/monolithic-file-contention-guard.js.map +1 -0
  10. package/dist/gates/prod-migration-drift.js +207 -0
  11. package/dist/gates/prod-migration-drift.js.map +1 -0
  12. package/dist/gates/test-over-deletion-guard.js +255 -0
  13. package/dist/gates/test-over-deletion-guard.js.map +1 -0
  14. package/dist/gates-runners.js +44 -3
  15. package/dist/gates-runners.js.map +1 -1
  16. package/dist/gates.js +3 -2
  17. package/dist/gates.js.map +1 -1
  18. package/dist/lumenflow-setup.js +144 -0
  19. package/dist/lumenflow-setup.js.map +1 -0
  20. package/dist/lumenflow-upgrade.js +2 -1
  21. package/dist/lumenflow-upgrade.js.map +1 -1
  22. package/dist/mem-create.js +10 -1
  23. package/dist/mem-create.js.map +1 -1
  24. package/dist/mem-signal.js +21 -4
  25. package/dist/mem-signal.js.map +1 -1
  26. package/dist/orchestrate-initiative.js +28 -3
  27. package/dist/orchestrate-initiative.js.map +1 -1
  28. package/dist/public-manifest.js +17 -0
  29. package/dist/public-manifest.js.map +1 -1
  30. package/dist/release.js +53 -18
  31. package/dist/release.js.map +1 -1
  32. package/dist/wu-done-gates.js +13 -9
  33. package/dist/wu-done-gates.js.map +1 -1
  34. package/dist/wu-edit-operations.js +74 -0
  35. package/dist/wu-edit-operations.js.map +1 -1
  36. package/dist/wu-edit-validators.js +58 -0
  37. package/dist/wu-edit-validators.js.map +1 -1
  38. package/dist/wu-edit.js +106 -4
  39. package/dist/wu-edit.js.map +1 -1
  40. package/dist/wu-prep.js +41 -7
  41. package/dist/wu-prep.js.map +1 -1
  42. package/dist/wu-recover.js +6 -0
  43. package/dist/wu-recover.js.map +1 -1
  44. package/dist/wu-release.js +120 -2
  45. package/dist/wu-release.js.map +1 -1
  46. package/dist/wu-sizing-validation.js +47 -17
  47. package/dist/wu-sizing-validation.js.map +1 -1
  48. package/dist/wu-status.js +33 -0
  49. package/dist/wu-status.js.map +1 -1
  50. package/package.json +13 -11
  51. package/packs/agent-runtime/package.json +1 -1
  52. package/packs/sidekick/package.json +1 -1
  53. package/packs/software-delivery/package.json +1 -1
  54. package/templates/core/AGENTS.md.template +67 -3
  55. package/templates/core/LUMENFLOW.md.template +197 -47
  56. package/packs/agent-runtime/agent-heartbeat.ts +0 -163
  57. package/packs/agent-runtime/auto-session-integration.ts +0 -888
  58. package/packs/agent-runtime/capability-factory.ts +0 -104
  59. package/packs/agent-runtime/constants.ts +0 -21
  60. package/packs/agent-runtime/delegation-registry-schema.ts +0 -220
  61. package/packs/agent-runtime/delegation-registry-store.ts +0 -269
  62. package/packs/agent-runtime/delegation-tree.ts +0 -328
  63. package/packs/agent-runtime/index.ts +0 -20
  64. package/packs/agent-runtime/manifest.ts +0 -348
  65. package/packs/agent-runtime/memory-coordination-contract.ts +0 -86
  66. package/packs/agent-runtime/orchestration.ts +0 -2027
  67. package/packs/agent-runtime/pack-registration.ts +0 -110
  68. package/packs/agent-runtime/policy-factory.ts +0 -165
  69. package/packs/agent-runtime/remote-controls/index.ts +0 -7
  70. package/packs/agent-runtime/remote-controls/operations.ts +0 -405
  71. package/packs/agent-runtime/remote-controls/port.ts +0 -48
  72. package/packs/agent-runtime/remote-controls/state-store.ts +0 -258
  73. package/packs/agent-runtime/remote-controls/types.ts +0 -105
  74. package/packs/agent-runtime/session-schema.ts +0 -467
  75. package/packs/agent-runtime/tool-impl/agent-turn-tools.ts +0 -793
  76. package/packs/agent-runtime/tool-impl/index.ts +0 -6
  77. package/packs/agent-runtime/tool-impl/provider-adapters.ts +0 -1245
  78. package/packs/agent-runtime/tool-impl/remote-controls.mock.ts +0 -256
  79. package/packs/agent-runtime/tool-impl/remote-controls.ts +0 -273
  80. package/packs/agent-runtime/tools/index.ts +0 -4
  81. package/packs/agent-runtime/tools/types.ts +0 -47
  82. package/packs/agent-runtime/turn-lifecycle-events.ts +0 -590
  83. package/packs/agent-runtime/types.ts +0 -128
  84. package/packs/agent-runtime/vitest.config.ts +0 -11
  85. package/packs/sidekick/channel-ingress.ts +0 -137
  86. package/packs/sidekick/constants.ts +0 -10
  87. package/packs/sidekick/index.ts +0 -8
  88. package/packs/sidekick/manifest-schema.ts +0 -49
  89. package/packs/sidekick/manifest.ts +0 -512
  90. package/packs/sidekick/pack-registration.ts +0 -110
  91. package/packs/sidekick/policy-factory.ts +0 -38
  92. package/packs/sidekick/sidekick-events.ts +0 -694
  93. package/packs/sidekick/src/adapters/cloud-queue.ts +0 -101
  94. package/packs/sidekick/src/adapters/control-plane-bridge.adapter.ts +0 -386
  95. package/packs/sidekick/src/adapters/filesystem-bridge.adapter.ts +0 -228
  96. package/packs/sidekick/src/domain/channel.types.ts +0 -64
  97. package/packs/sidekick/src/ports/channel-bridge.port.ts +0 -92
  98. package/packs/sidekick/src/routines/commit.ts +0 -74
  99. package/packs/sidekick/tool-impl/channel-tools.ts +0 -577
  100. package/packs/sidekick/tool-impl/channel-transports.ts +0 -75
  101. package/packs/sidekick/tool-impl/index.ts +0 -29
  102. package/packs/sidekick/tool-impl/memory-tools.ts +0 -290
  103. package/packs/sidekick/tool-impl/routine-commit.ts +0 -102
  104. package/packs/sidekick/tool-impl/routine-tools.ts +0 -440
  105. package/packs/sidekick/tool-impl/runtime-context.ts +0 -28
  106. package/packs/sidekick/tool-impl/shared.ts +0 -125
  107. package/packs/sidekick/tool-impl/storage.ts +0 -325
  108. package/packs/sidekick/tool-impl/system-tools.ts +0 -160
  109. package/packs/sidekick/tool-impl/task-tools.ts +0 -506
  110. package/packs/sidekick/tools/channel-tools.ts +0 -53
  111. package/packs/sidekick/tools/index.ts +0 -9
  112. package/packs/sidekick/tools/memory-tools.ts +0 -53
  113. package/packs/sidekick/tools/routine-tools.ts +0 -53
  114. package/packs/sidekick/tools/system-tools.ts +0 -47
  115. package/packs/sidekick/tools/task-tools.ts +0 -61
  116. package/packs/sidekick/tools/types.ts +0 -57
  117. package/packs/sidekick/vitest.config.ts +0 -11
  118. package/packs/software-delivery/constants.ts +0 -10
  119. package/packs/software-delivery/extensions.ts +0 -140
  120. package/packs/software-delivery/gate-policies.ts +0 -134
  121. package/packs/software-delivery/index.ts +0 -8
  122. package/packs/software-delivery/manifest-schema.ts +0 -268
  123. package/packs/software-delivery/manifest.ts +0 -657
  124. package/packs/software-delivery/pack-registration.ts +0 -113
  125. package/packs/software-delivery/src/commands/index.ts +0 -5
  126. package/packs/software-delivery/src/config/delivery-review-contract.ts +0 -256
  127. package/packs/software-delivery/src/config/env-accessors.ts +0 -66
  128. package/packs/software-delivery/src/config/index.ts +0 -8
  129. package/packs/software-delivery/src/config/normalize-config-keys.ts +0 -9
  130. package/packs/software-delivery/src/config/schemas/lumenflow-config-schema-types.ts +0 -460
  131. package/packs/software-delivery/src/config/workspace-reader.ts +0 -375
  132. package/packs/software-delivery/src/constants/backlog-patterns.ts +0 -31
  133. package/packs/software-delivery/src/constants/client-ids.ts +0 -19
  134. package/packs/software-delivery/src/constants/config-contract.ts +0 -7
  135. package/packs/software-delivery/src/constants/docs-layout-presets.ts +0 -50
  136. package/packs/software-delivery/src/constants/duration-constants.ts +0 -20
  137. package/packs/software-delivery/src/constants/gate-constants.ts +0 -32
  138. package/packs/software-delivery/src/constants/index.ts +0 -29
  139. package/packs/software-delivery/src/constants/lock-constants.ts +0 -35
  140. package/packs/software-delivery/src/constants/object-guards.ts +0 -12
  141. package/packs/software-delivery/src/constants/section-headings.ts +0 -107
  142. package/packs/software-delivery/src/constants/wu-cli-constants.ts +0 -500
  143. package/packs/software-delivery/src/constants/wu-domain-constants.ts +0 -466
  144. package/packs/software-delivery/src/constants/wu-git-constants.ts +0 -7
  145. package/packs/software-delivery/src/constants/wu-id-format.ts +0 -327
  146. package/packs/software-delivery/src/constants/wu-paths-constants.ts +0 -384
  147. package/packs/software-delivery/src/constants/wu-statuses.ts +0 -287
  148. package/packs/software-delivery/src/constants/wu-type-helpers.ts +0 -67
  149. package/packs/software-delivery/src/constants/wu-ui-constants.ts +0 -267
  150. package/packs/software-delivery/src/constants/wu-validation-constants.ts +0 -73
  151. package/packs/software-delivery/src/domain/index.ts +0 -5
  152. package/packs/software-delivery/src/domain/orchestration.constants.ts +0 -166
  153. package/packs/software-delivery/src/domain/orchestration.schemas.ts +0 -238
  154. package/packs/software-delivery/src/domain/orchestration.types.ts +0 -176
  155. package/packs/software-delivery/src/methodology/incremental-test.ts +0 -122
  156. package/packs/software-delivery/src/methodology/index.ts +0 -6
  157. package/packs/software-delivery/src/methodology/manual-test-validator.ts +0 -292
  158. package/packs/software-delivery/src/policy/coverage-gate.ts +0 -270
  159. package/packs/software-delivery/src/policy/gates-agent-mode.ts +0 -223
  160. package/packs/software-delivery/src/policy/gates-config-internal.ts +0 -121
  161. package/packs/software-delivery/src/policy/gates-config.ts +0 -300
  162. package/packs/software-delivery/src/policy/gates-coverage.ts +0 -356
  163. package/packs/software-delivery/src/policy/gates-presets.ts +0 -134
  164. package/packs/software-delivery/src/policy/gates-schemas.ts +0 -173
  165. package/packs/software-delivery/src/policy/index.ts +0 -22
  166. package/packs/software-delivery/src/policy/package-manager-resolver.ts +0 -319
  167. package/packs/software-delivery/src/policy/resolve-policy.ts +0 -601
  168. package/packs/software-delivery/src/ports/config.ports.ts +0 -90
  169. package/packs/software-delivery/src/ports/dashboard-renderer.port.ts +0 -125
  170. package/packs/software-delivery/src/ports/index.ts +0 -10
  171. package/packs/software-delivery/src/ports/sync-validator.ports.ts +0 -59
  172. package/packs/software-delivery/src/ports/wu-helpers.ports.ts +0 -168
  173. package/packs/software-delivery/src/ports/wu-state.ports.ts +0 -241
  174. package/packs/software-delivery/src/primitives/index.ts +0 -5
  175. package/packs/software-delivery/src/runtime/index.ts +0 -6
  176. package/packs/software-delivery/src/runtime/work-classifier.ts +0 -561
  177. package/packs/software-delivery/src/sandbox/index.ts +0 -10
  178. package/packs/software-delivery/src/sandbox/sandbox-allowlist.ts +0 -118
  179. package/packs/software-delivery/src/sandbox/sandbox-backend-linux.ts +0 -88
  180. package/packs/software-delivery/src/sandbox/sandbox-backend-macos.ts +0 -154
  181. package/packs/software-delivery/src/sandbox/sandbox-backend-windows.ts +0 -47
  182. package/packs/software-delivery/src/sandbox/sandbox-profile.ts +0 -153
  183. package/packs/software-delivery/src/schemas/index.ts +0 -5
  184. package/packs/software-delivery/src/state/date-utils.ts +0 -158
  185. package/packs/software-delivery/src/state/index.ts +0 -15
  186. package/packs/software-delivery/src/state/state-machine.ts +0 -119
  187. package/packs/software-delivery/src/state/wu-doc-types.ts +0 -51
  188. package/packs/software-delivery/src/state/wu-paths.ts +0 -381
  189. package/packs/software-delivery/src/state/wu-schema.ts +0 -1139
  190. package/packs/software-delivery/src/state/wu-state-schema.ts +0 -255
  191. package/packs/software-delivery/src/state/wu-yaml.ts +0 -338
  192. package/packs/software-delivery/tool-impl/agent-tools.ts +0 -263
  193. package/packs/software-delivery/tool-impl/delegation-tools.ts +0 -66
  194. package/packs/software-delivery/tool-impl/flow-metrics-tools.ts +0 -219
  195. package/packs/software-delivery/tool-impl/git-runner.ts +0 -113
  196. package/packs/software-delivery/tool-impl/git-tools.ts +0 -316
  197. package/packs/software-delivery/tool-impl/index.ts +0 -15
  198. package/packs/software-delivery/tool-impl/initiative-orchestration-tools.ts +0 -720
  199. package/packs/software-delivery/tool-impl/lane-lock.ts +0 -246
  200. package/packs/software-delivery/tool-impl/memory-tools.ts +0 -470
  201. package/packs/software-delivery/tool-impl/pending-runtime-tools.ts +0 -21
  202. package/packs/software-delivery/tool-impl/runtime-cli-adapter.ts +0 -329
  203. package/packs/software-delivery/tool-impl/runtime-native-tools.ts +0 -687
  204. package/packs/software-delivery/tool-impl/worker-loader.ts +0 -52
  205. package/packs/software-delivery/tool-impl/worktree-tools.ts +0 -46
  206. package/packs/software-delivery/tool-impl/wu-lifecycle-tools.ts +0 -807
  207. package/packs/software-delivery/tools/delegation-tools.ts +0 -23
  208. package/packs/software-delivery/tools/git-tools.ts +0 -55
  209. package/packs/software-delivery/tools/index.ts +0 -8
  210. package/packs/software-delivery/tools/lane-lock-tool.ts +0 -37
  211. package/packs/software-delivery/tools/types.ts +0 -71
  212. package/packs/software-delivery/tools/worktree-tools.ts +0 -49
  213. 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
- }