@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.
- package/README.md +41 -40
- package/dist/db-journal-recover.js +400 -0
- package/dist/db-journal-recover.js.map +1 -0
- package/dist/docs-sync.js +8 -3
- package/dist/docs-sync.js.map +1 -1
- package/dist/doctor.js +11 -0
- package/dist/doctor.js.map +1 -1
- package/dist/gate-defaults.js +37 -0
- package/dist/gate-defaults.js.map +1 -1
- package/dist/gates/monolithic-file-contention-guard.js +167 -0
- package/dist/gates/monolithic-file-contention-guard.js.map +1 -0
- package/dist/gates/prod-migration-drift.js +207 -0
- package/dist/gates/prod-migration-drift.js.map +1 -0
- package/dist/gates/test-over-deletion-guard.js +280 -0
- package/dist/gates/test-over-deletion-guard.js.map +1 -0
- package/dist/gates-runners.js +44 -3
- package/dist/gates-runners.js.map +1 -1
- package/dist/gates.js +3 -2
- package/dist/gates.js.map +1 -1
- package/dist/hooks/config-resolver.js +16 -1
- package/dist/hooks/config-resolver.js.map +1 -1
- package/dist/hooks/dirty-guard.js +43 -2
- package/dist/hooks/dirty-guard.js.map +1 -1
- package/dist/hooks/git-status-parser.js +22 -8
- package/dist/hooks/git-status-parser.js.map +1 -1
- package/dist/init-templates.js +241 -0
- package/dist/init-templates.js.map +1 -1
- package/dist/init.js +122 -16
- package/dist/init.js.map +1 -1
- package/dist/lumenflow-setup.js +144 -0
- package/dist/lumenflow-setup.js.map +1 -0
- package/dist/lumenflow-upgrade.js +43 -1
- package/dist/lumenflow-upgrade.js.map +1 -1
- package/dist/mem-create.js +10 -1
- package/dist/mem-create.js.map +1 -1
- package/dist/mem-signal.js +21 -4
- package/dist/mem-signal.js.map +1 -1
- package/dist/orchestrate-initiative.js +28 -3
- package/dist/orchestrate-initiative.js.map +1 -1
- package/dist/public-manifest.js +17 -7
- package/dist/public-manifest.js.map +1 -1
- package/dist/release.js +53 -18
- package/dist/release.js.map +1 -1
- package/dist/wu-done-gates.js +13 -9
- package/dist/wu-done-gates.js.map +1 -1
- package/dist/wu-done.js +14 -2
- package/dist/wu-done.js.map +1 -1
- package/dist/wu-edit-operations.js +74 -0
- package/dist/wu-edit-operations.js.map +1 -1
- package/dist/wu-edit-validators.js +58 -0
- package/dist/wu-edit-validators.js.map +1 -1
- package/dist/wu-edit.js +106 -4
- package/dist/wu-edit.js.map +1 -1
- package/dist/wu-prep.js +57 -9
- package/dist/wu-prep.js.map +1 -1
- package/dist/wu-recover.js +6 -0
- package/dist/wu-recover.js.map +1 -1
- package/dist/wu-release.js +120 -2
- package/dist/wu-release.js.map +1 -1
- package/dist/wu-sizing-validation.js +47 -17
- package/dist/wu-sizing-validation.js.map +1 -1
- package/dist/wu-status.js +33 -0
- package/dist/wu-status.js.map +1 -1
- package/package.json +13 -12
- package/packs/agent-runtime/package.json +1 -1
- package/packs/sidekick/package.json +1 -1
- package/packs/software-delivery/package.json +1 -1
- package/templates/core/AGENTS.md.template +67 -3
- package/templates/core/LUMENFLOW.md.template +196 -47
- package/dist/distribution-preflight.js +0 -230
- package/dist/distribution-preflight.js.map +0 -1
- package/packs/agent-runtime/agent-heartbeat.ts +0 -163
- package/packs/agent-runtime/auto-session-integration.ts +0 -888
- package/packs/agent-runtime/capability-factory.ts +0 -104
- package/packs/agent-runtime/constants.ts +0 -21
- package/packs/agent-runtime/delegation-registry-schema.ts +0 -220
- package/packs/agent-runtime/delegation-registry-store.ts +0 -269
- package/packs/agent-runtime/delegation-tree.ts +0 -328
- package/packs/agent-runtime/index.ts +0 -20
- package/packs/agent-runtime/manifest.ts +0 -348
- package/packs/agent-runtime/memory-coordination-contract.ts +0 -86
- package/packs/agent-runtime/orchestration.ts +0 -2027
- package/packs/agent-runtime/pack-registration.ts +0 -110
- package/packs/agent-runtime/policy-factory.ts +0 -165
- package/packs/agent-runtime/remote-controls/index.ts +0 -7
- package/packs/agent-runtime/remote-controls/operations.ts +0 -405
- package/packs/agent-runtime/remote-controls/port.ts +0 -48
- package/packs/agent-runtime/remote-controls/state-store.ts +0 -258
- package/packs/agent-runtime/remote-controls/types.ts +0 -105
- package/packs/agent-runtime/session-schema.ts +0 -467
- package/packs/agent-runtime/tool-impl/agent-turn-tools.ts +0 -793
- package/packs/agent-runtime/tool-impl/index.ts +0 -6
- package/packs/agent-runtime/tool-impl/provider-adapters.ts +0 -1245
- package/packs/agent-runtime/tool-impl/remote-controls.mock.ts +0 -256
- package/packs/agent-runtime/tool-impl/remote-controls.ts +0 -273
- package/packs/agent-runtime/tools/index.ts +0 -4
- package/packs/agent-runtime/tools/types.ts +0 -47
- package/packs/agent-runtime/turn-lifecycle-events.ts +0 -590
- package/packs/agent-runtime/types.ts +0 -128
- package/packs/agent-runtime/vitest.config.ts +0 -11
- package/packs/sidekick/channel-ingress.ts +0 -137
- package/packs/sidekick/constants.ts +0 -10
- package/packs/sidekick/index.ts +0 -8
- package/packs/sidekick/manifest-schema.ts +0 -49
- package/packs/sidekick/manifest.ts +0 -512
- package/packs/sidekick/pack-registration.ts +0 -110
- package/packs/sidekick/policy-factory.ts +0 -38
- package/packs/sidekick/sidekick-events.ts +0 -694
- package/packs/sidekick/src/adapters/cloud-queue.ts +0 -101
- package/packs/sidekick/src/adapters/control-plane-bridge.adapter.ts +0 -386
- package/packs/sidekick/src/adapters/filesystem-bridge.adapter.ts +0 -228
- package/packs/sidekick/src/domain/channel.types.ts +0 -64
- package/packs/sidekick/src/ports/channel-bridge.port.ts +0 -92
- package/packs/sidekick/src/routines/commit.ts +0 -74
- package/packs/sidekick/tool-impl/channel-tools.ts +0 -577
- package/packs/sidekick/tool-impl/channel-transports.ts +0 -75
- package/packs/sidekick/tool-impl/index.ts +0 -29
- package/packs/sidekick/tool-impl/memory-tools.ts +0 -290
- package/packs/sidekick/tool-impl/routine-commit.ts +0 -102
- package/packs/sidekick/tool-impl/routine-tools.ts +0 -440
- package/packs/sidekick/tool-impl/runtime-context.ts +0 -28
- package/packs/sidekick/tool-impl/shared.ts +0 -125
- package/packs/sidekick/tool-impl/storage.ts +0 -325
- package/packs/sidekick/tool-impl/system-tools.ts +0 -160
- package/packs/sidekick/tool-impl/task-tools.ts +0 -506
- package/packs/sidekick/tools/channel-tools.ts +0 -53
- package/packs/sidekick/tools/index.ts +0 -9
- package/packs/sidekick/tools/memory-tools.ts +0 -53
- package/packs/sidekick/tools/routine-tools.ts +0 -53
- package/packs/sidekick/tools/system-tools.ts +0 -47
- package/packs/sidekick/tools/task-tools.ts +0 -61
- package/packs/sidekick/tools/types.ts +0 -57
- package/packs/sidekick/vitest.config.ts +0 -11
- package/packs/software-delivery/constants.ts +0 -10
- package/packs/software-delivery/extensions.ts +0 -140
- package/packs/software-delivery/gate-policies.ts +0 -134
- package/packs/software-delivery/index.ts +0 -8
- package/packs/software-delivery/manifest-schema.ts +0 -268
- package/packs/software-delivery/manifest.ts +0 -657
- package/packs/software-delivery/pack-registration.ts +0 -113
- package/packs/software-delivery/src/commands/index.ts +0 -5
- package/packs/software-delivery/src/config/delivery-review-contract.ts +0 -256
- package/packs/software-delivery/src/config/env-accessors.ts +0 -66
- package/packs/software-delivery/src/config/index.ts +0 -8
- package/packs/software-delivery/src/config/normalize-config-keys.ts +0 -9
- package/packs/software-delivery/src/config/schemas/lumenflow-config-schema-types.ts +0 -460
- package/packs/software-delivery/src/config/workspace-reader.ts +0 -375
- package/packs/software-delivery/src/constants/backlog-patterns.ts +0 -31
- package/packs/software-delivery/src/constants/client-ids.ts +0 -19
- package/packs/software-delivery/src/constants/config-contract.ts +0 -7
- package/packs/software-delivery/src/constants/docs-layout-presets.ts +0 -50
- package/packs/software-delivery/src/constants/duration-constants.ts +0 -20
- package/packs/software-delivery/src/constants/gate-constants.ts +0 -32
- package/packs/software-delivery/src/constants/index.ts +0 -29
- package/packs/software-delivery/src/constants/lock-constants.ts +0 -35
- package/packs/software-delivery/src/constants/object-guards.ts +0 -12
- package/packs/software-delivery/src/constants/section-headings.ts +0 -107
- package/packs/software-delivery/src/constants/wu-cli-constants.ts +0 -500
- package/packs/software-delivery/src/constants/wu-domain-constants.ts +0 -466
- package/packs/software-delivery/src/constants/wu-git-constants.ts +0 -7
- package/packs/software-delivery/src/constants/wu-id-format.ts +0 -327
- package/packs/software-delivery/src/constants/wu-paths-constants.ts +0 -384
- package/packs/software-delivery/src/constants/wu-statuses.ts +0 -287
- package/packs/software-delivery/src/constants/wu-type-helpers.ts +0 -67
- package/packs/software-delivery/src/constants/wu-ui-constants.ts +0 -267
- package/packs/software-delivery/src/constants/wu-validation-constants.ts +0 -73
- package/packs/software-delivery/src/domain/index.ts +0 -5
- package/packs/software-delivery/src/domain/orchestration.constants.ts +0 -166
- package/packs/software-delivery/src/domain/orchestration.schemas.ts +0 -238
- package/packs/software-delivery/src/domain/orchestration.types.ts +0 -176
- package/packs/software-delivery/src/methodology/incremental-test.ts +0 -122
- package/packs/software-delivery/src/methodology/index.ts +0 -6
- package/packs/software-delivery/src/methodology/manual-test-validator.ts +0 -292
- package/packs/software-delivery/src/policy/coverage-gate.ts +0 -270
- package/packs/software-delivery/src/policy/gates-agent-mode.ts +0 -223
- package/packs/software-delivery/src/policy/gates-config-internal.ts +0 -121
- package/packs/software-delivery/src/policy/gates-config.ts +0 -300
- package/packs/software-delivery/src/policy/gates-coverage.ts +0 -356
- package/packs/software-delivery/src/policy/gates-presets.ts +0 -134
- package/packs/software-delivery/src/policy/gates-schemas.ts +0 -173
- package/packs/software-delivery/src/policy/index.ts +0 -22
- package/packs/software-delivery/src/policy/package-manager-resolver.ts +0 -319
- package/packs/software-delivery/src/policy/resolve-policy.ts +0 -601
- package/packs/software-delivery/src/ports/config.ports.ts +0 -90
- package/packs/software-delivery/src/ports/dashboard-renderer.port.ts +0 -125
- package/packs/software-delivery/src/ports/index.ts +0 -10
- package/packs/software-delivery/src/ports/sync-validator.ports.ts +0 -59
- package/packs/software-delivery/src/ports/wu-helpers.ports.ts +0 -168
- package/packs/software-delivery/src/ports/wu-state.ports.ts +0 -241
- package/packs/software-delivery/src/primitives/index.ts +0 -5
- package/packs/software-delivery/src/runtime/index.ts +0 -6
- package/packs/software-delivery/src/runtime/work-classifier.ts +0 -561
- package/packs/software-delivery/src/sandbox/index.ts +0 -10
- package/packs/software-delivery/src/sandbox/sandbox-allowlist.ts +0 -118
- package/packs/software-delivery/src/sandbox/sandbox-backend-linux.ts +0 -88
- package/packs/software-delivery/src/sandbox/sandbox-backend-macos.ts +0 -154
- package/packs/software-delivery/src/sandbox/sandbox-backend-windows.ts +0 -47
- package/packs/software-delivery/src/sandbox/sandbox-profile.ts +0 -153
- package/packs/software-delivery/src/schemas/index.ts +0 -5
- package/packs/software-delivery/src/state/date-utils.ts +0 -158
- package/packs/software-delivery/src/state/index.ts +0 -15
- package/packs/software-delivery/src/state/state-machine.ts +0 -119
- package/packs/software-delivery/src/state/wu-doc-types.ts +0 -51
- package/packs/software-delivery/src/state/wu-paths.ts +0 -381
- package/packs/software-delivery/src/state/wu-schema.ts +0 -1139
- package/packs/software-delivery/src/state/wu-state-schema.ts +0 -255
- package/packs/software-delivery/src/state/wu-yaml.ts +0 -338
- package/packs/software-delivery/tool-impl/agent-tools.ts +0 -263
- package/packs/software-delivery/tool-impl/delegation-tools.ts +0 -66
- package/packs/software-delivery/tool-impl/flow-metrics-tools.ts +0 -219
- package/packs/software-delivery/tool-impl/git-runner.ts +0 -113
- package/packs/software-delivery/tool-impl/git-tools.ts +0 -316
- package/packs/software-delivery/tool-impl/index.ts +0 -15
- package/packs/software-delivery/tool-impl/initiative-orchestration-tools.ts +0 -720
- package/packs/software-delivery/tool-impl/lane-lock.ts +0 -246
- package/packs/software-delivery/tool-impl/memory-tools.ts +0 -470
- package/packs/software-delivery/tool-impl/pending-runtime-tools.ts +0 -21
- package/packs/software-delivery/tool-impl/runtime-cli-adapter.ts +0 -329
- package/packs/software-delivery/tool-impl/runtime-native-tools.ts +0 -687
- package/packs/software-delivery/tool-impl/worker-loader.ts +0 -52
- package/packs/software-delivery/tool-impl/worktree-tools.ts +0 -46
- package/packs/software-delivery/tool-impl/wu-lifecycle-tools.ts +0 -807
- package/packs/software-delivery/tools/delegation-tools.ts +0 -23
- package/packs/software-delivery/tools/git-tools.ts +0 -55
- package/packs/software-delivery/tools/index.ts +0 -8
- package/packs/software-delivery/tools/lane-lock-tool.ts +0 -37
- package/packs/software-delivery/tools/types.ts +0 -71
- package/packs/software-delivery/tools/worktree-tools.ts +0 -49
- 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
|
-
}
|