@lumenflow/cli 5.5.0 → 5.7.14

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