@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,255 +0,0 @@
|
|
|
1
|
-
// Copyright (c) 2026 Hellmai Ltd
|
|
2
|
-
// SPDX-License-Identifier: LicenseRef-LumenFlow-Proprietary
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* WU State Schema (WU-1570)
|
|
6
|
-
*
|
|
7
|
-
* Zod schemas for WU state event validation.
|
|
8
|
-
* Defines event types for WU lifecycle: create, claim, block, unblock, complete.
|
|
9
|
-
*
|
|
10
|
-
* @see {@link packages/@lumenflow/cli/src/lib/__tests__/wu-state-store.test.ts} - Tests
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
import { z } from 'zod';
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* WU event types
|
|
17
|
-
*
|
|
18
|
-
* - create: WU created (transitions to ready)
|
|
19
|
-
* - claim: WU claimed (transitions to in_progress)
|
|
20
|
-
* - block: WU blocked (transitions to blocked)
|
|
21
|
-
* - unblock: WU unblocked (transitions back to in_progress)
|
|
22
|
-
* - complete: WU completed (transitions to done)
|
|
23
|
-
* - checkpoint: Progress checkpoint (WU-1748: cross-agent visibility)
|
|
24
|
-
* - delegation: WU delegated from parent (WU-1947: parent-child relationships)
|
|
25
|
-
* - release: WU released (WU-1080: transitions from in_progress to ready for orphan recovery)
|
|
26
|
-
* - wu_renamed: WU id canonicalized or normalized (WU-2552: append-only rename, never rewrites history)
|
|
27
|
-
*/
|
|
28
|
-
export const WU_EVENT_TYPES = [
|
|
29
|
-
'create',
|
|
30
|
-
'claim',
|
|
31
|
-
'block',
|
|
32
|
-
'unblock',
|
|
33
|
-
'complete',
|
|
34
|
-
'checkpoint',
|
|
35
|
-
'delegation',
|
|
36
|
-
'release',
|
|
37
|
-
'wu_renamed',
|
|
38
|
-
] as const;
|
|
39
|
-
|
|
40
|
-
/** Type for WU event types */
|
|
41
|
-
export type WUEventType = (typeof WU_EVENT_TYPES)[number];
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* WU Event Type constant object (WU-2044)
|
|
45
|
-
*
|
|
46
|
-
* Named constants for event type strings, analogous to WU_STATUS.
|
|
47
|
-
* Use WU_EVENT_TYPE.CLAIM instead of raw 'claim' strings.
|
|
48
|
-
*/
|
|
49
|
-
export const WU_EVENT_TYPE = Object.freeze({
|
|
50
|
-
CREATE: 'create' as const,
|
|
51
|
-
CLAIM: 'claim' as const,
|
|
52
|
-
BLOCK: 'block' as const,
|
|
53
|
-
UNBLOCK: 'unblock' as const,
|
|
54
|
-
COMPLETE: 'complete' as const,
|
|
55
|
-
CHECKPOINT: 'checkpoint' as const,
|
|
56
|
-
DELEGATION: 'delegation' as const,
|
|
57
|
-
RELEASE: 'release' as const,
|
|
58
|
-
WU_RENAMED: 'wu_renamed' as const,
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* WU status values (matches LumenFlow state machine)
|
|
63
|
-
*/
|
|
64
|
-
export const WU_STATUSES = ['ready', 'in_progress', 'blocked', 'waiting', 'done'] as const;
|
|
65
|
-
|
|
66
|
-
/** Type for WU status values */
|
|
67
|
-
export type WUStatus = (typeof WU_STATUSES)[number];
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Regex patterns for WU validation
|
|
71
|
-
*/
|
|
72
|
-
export const WU_PATTERNS = {
|
|
73
|
-
/** WU ID format: WU-{digits} */
|
|
74
|
-
WU_ID: /^WU-\d+$/,
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Error messages for schema validation
|
|
79
|
-
*/
|
|
80
|
-
const ERROR_MESSAGES = {
|
|
81
|
-
EVENT_TYPE: `Event type must be one of: ${WU_EVENT_TYPES.join(', ')}`,
|
|
82
|
-
WU_ID: 'WU ID must match pattern WU-XXX (e.g., WU-1570)',
|
|
83
|
-
LANE_REQUIRED: 'Lane is required',
|
|
84
|
-
TITLE_REQUIRED: 'Title is required',
|
|
85
|
-
REASON_REQUIRED: 'Reason is required',
|
|
86
|
-
TIMESTAMP_REQUIRED: 'Timestamp is required',
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Base event schema (common fields for all events)
|
|
91
|
-
*/
|
|
92
|
-
const BaseEventSchema = z.object({
|
|
93
|
-
/** Event type */
|
|
94
|
-
type: z.enum(WU_EVENT_TYPES, {
|
|
95
|
-
error: ERROR_MESSAGES.EVENT_TYPE,
|
|
96
|
-
}),
|
|
97
|
-
|
|
98
|
-
/** WU ID */
|
|
99
|
-
wuId: z.string().regex(WU_PATTERNS.WU_ID, { message: ERROR_MESSAGES.WU_ID }),
|
|
100
|
-
|
|
101
|
-
/** Event timestamp (ISO 8601 datetime) */
|
|
102
|
-
timestamp: z.string().datetime({ message: ERROR_MESSAGES.TIMESTAMP_REQUIRED }),
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Create event schema
|
|
107
|
-
*/
|
|
108
|
-
export const CreateEventSchema = BaseEventSchema.extend({
|
|
109
|
-
type: z.literal('create'),
|
|
110
|
-
lane: z.string().min(1, { message: ERROR_MESSAGES.LANE_REQUIRED }),
|
|
111
|
-
title: z.string().min(1, { message: ERROR_MESSAGES.TITLE_REQUIRED }),
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Claim event schema
|
|
116
|
-
*/
|
|
117
|
-
export const ClaimEventSchema = BaseEventSchema.extend({
|
|
118
|
-
type: z.literal('claim'),
|
|
119
|
-
lane: z.string().min(1, { message: ERROR_MESSAGES.LANE_REQUIRED }),
|
|
120
|
-
title: z.string().min(1, { message: ERROR_MESSAGES.TITLE_REQUIRED }),
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Block event schema
|
|
125
|
-
*/
|
|
126
|
-
export const BlockEventSchema = BaseEventSchema.extend({
|
|
127
|
-
type: z.literal('block'),
|
|
128
|
-
reason: z.string().min(1, { message: ERROR_MESSAGES.REASON_REQUIRED }),
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Unblock event schema
|
|
133
|
-
*/
|
|
134
|
-
export const UnblockEventSchema = BaseEventSchema.extend({
|
|
135
|
-
type: z.literal('unblock'),
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* Complete event schema
|
|
140
|
-
*/
|
|
141
|
-
export const CompleteEventSchema = BaseEventSchema.extend({
|
|
142
|
-
type: z.literal('complete'),
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Checkpoint event schema (WU-1748: cross-agent visibility)
|
|
147
|
-
* Records progress checkpoints for abandoned WU detection
|
|
148
|
-
*/
|
|
149
|
-
export const CheckpointEventSchema = BaseEventSchema.extend({
|
|
150
|
-
type: z.literal('checkpoint'),
|
|
151
|
-
/** Checkpoint note/description */
|
|
152
|
-
note: z.string().min(1, { message: 'Checkpoint note is required' }),
|
|
153
|
-
/** Optional session ID */
|
|
154
|
-
sessionId: z.string().optional(),
|
|
155
|
-
/** Optional progress summary */
|
|
156
|
-
progress: z.string().optional(),
|
|
157
|
-
/** Optional next steps */
|
|
158
|
-
nextSteps: z.string().optional(),
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* Delegation event schema (WU-1947: parent-child relationships)
|
|
163
|
-
* Records WU delegation relationships for tracking parent-child WUs
|
|
164
|
-
*/
|
|
165
|
-
export const DelegationEventSchema = BaseEventSchema.extend({
|
|
166
|
-
type: z.literal('delegation'),
|
|
167
|
-
/** Parent WU ID that delegated this WU */
|
|
168
|
-
parentWuId: z
|
|
169
|
-
.string()
|
|
170
|
-
.regex(WU_PATTERNS.WU_ID, { message: 'Parent WU ID must match pattern WU-XXX' }),
|
|
171
|
-
/** Unique delegation identifier */
|
|
172
|
-
delegationId: z.string().min(1, { message: 'Delegation ID is required' }),
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* Release event schema (WU-1080: orphan recovery)
|
|
177
|
-
* Releases an in_progress WU back to ready state when agent is interrupted.
|
|
178
|
-
* Allows another agent to reclaim the orphaned WU.
|
|
179
|
-
*/
|
|
180
|
-
export const ReleaseEventSchema = BaseEventSchema.extend({
|
|
181
|
-
type: z.literal('release'),
|
|
182
|
-
/** Reason for releasing the WU */
|
|
183
|
-
reason: z.string().min(1, { message: ERROR_MESSAGES.REASON_REQUIRED }),
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
/**
|
|
187
|
-
* WU renamed event schema (WU-2552: canonical WU IDs)
|
|
188
|
-
*
|
|
189
|
-
* Records a WU id change without rewriting history. Historical events
|
|
190
|
-
* before the rename keep their original wuId field (audit trail intact).
|
|
191
|
-
* Projections use {@link buildRenameProjection} to resolve an original id
|
|
192
|
-
* to its current canonical id.
|
|
193
|
-
*
|
|
194
|
-
* Invariants:
|
|
195
|
-
* - `wuId` field mirrors `from` so filter-by-wuId still returns this event
|
|
196
|
-
* for queries about the original id.
|
|
197
|
-
* - `from` and `to` accept any WU ID matching WU_PATTERNS.WU_ID, which is
|
|
198
|
-
* intentionally permissive (matches both padded and unpadded legacy IDs).
|
|
199
|
-
*/
|
|
200
|
-
export const WURenamedEventSchema = BaseEventSchema.extend({
|
|
201
|
-
type: z.literal('wu_renamed'),
|
|
202
|
-
/** Original WU ID (what the WU was called before the rename) */
|
|
203
|
-
from: z.string().regex(WU_PATTERNS.WU_ID, { message: ERROR_MESSAGES.WU_ID }),
|
|
204
|
-
/** New WU ID (what the WU is called after the rename) */
|
|
205
|
-
to: z.string().regex(WU_PATTERNS.WU_ID, { message: ERROR_MESSAGES.WU_ID }),
|
|
206
|
-
/** Optional human reason for the rename (e.g. 'canonicalize WU-5 to WU-0005') */
|
|
207
|
-
reason: z.string().optional(),
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
/**
|
|
211
|
-
* Union schema for all event types
|
|
212
|
-
*/
|
|
213
|
-
export const WUEventSchema = z.discriminatedUnion('type', [
|
|
214
|
-
CreateEventSchema,
|
|
215
|
-
ClaimEventSchema,
|
|
216
|
-
BlockEventSchema,
|
|
217
|
-
UnblockEventSchema,
|
|
218
|
-
CompleteEventSchema,
|
|
219
|
-
CheckpointEventSchema,
|
|
220
|
-
DelegationEventSchema,
|
|
221
|
-
ReleaseEventSchema,
|
|
222
|
-
WURenamedEventSchema,
|
|
223
|
-
]);
|
|
224
|
-
|
|
225
|
-
/**
|
|
226
|
-
* TypeScript types inferred from schemas
|
|
227
|
-
*/
|
|
228
|
-
export type CreateEvent = z.infer<typeof CreateEventSchema>;
|
|
229
|
-
export type ClaimEvent = z.infer<typeof ClaimEventSchema>;
|
|
230
|
-
export type BlockEvent = z.infer<typeof BlockEventSchema>;
|
|
231
|
-
export type UnblockEvent = z.infer<typeof UnblockEventSchema>;
|
|
232
|
-
export type CompleteEvent = z.infer<typeof CompleteEventSchema>;
|
|
233
|
-
export type CheckpointEvent = z.infer<typeof CheckpointEventSchema>;
|
|
234
|
-
export type DelegationEvent = z.infer<typeof DelegationEventSchema>;
|
|
235
|
-
export type ReleaseEvent = z.infer<typeof ReleaseEventSchema>;
|
|
236
|
-
export type WURenamedEvent = z.infer<typeof WURenamedEventSchema>;
|
|
237
|
-
export type WUEvent = z.infer<typeof WUEventSchema>;
|
|
238
|
-
|
|
239
|
-
/**
|
|
240
|
-
* Validates WU event data against schema
|
|
241
|
-
*
|
|
242
|
-
* @param {unknown} data - Data to validate
|
|
243
|
-
* @returns {z.SafeParseReturnType<WUEvent, WUEvent>} Validation result
|
|
244
|
-
*
|
|
245
|
-
* @example
|
|
246
|
-
* const result = validateWUEvent(eventData);
|
|
247
|
-
* if (!result.success) {
|
|
248
|
-
* result.error.issues.forEach(issue => {
|
|
249
|
-
* console.error(`${issue.path.join('.')}: ${issue.message}`);
|
|
250
|
-
* });
|
|
251
|
-
* }
|
|
252
|
-
*/
|
|
253
|
-
export function validateWUEvent(data: unknown) {
|
|
254
|
-
return WUEventSchema.safeParse(data);
|
|
255
|
-
}
|
|
@@ -1,338 +0,0 @@
|
|
|
1
|
-
// Copyright (c) 2026 Hellmai Ltd
|
|
2
|
-
// SPDX-License-Identifier: LicenseRef-LumenFlow-Proprietary
|
|
3
|
-
|
|
4
|
-
import { existsSync, readFileSync, writeFileSync, promises as fs } from 'node:fs';
|
|
5
|
-
|
|
6
|
-
import {
|
|
7
|
-
createError,
|
|
8
|
-
ErrorCodes,
|
|
9
|
-
getErrorMessage,
|
|
10
|
-
} from '@lumenflow/kernel/primitives/error-handler';
|
|
11
|
-
import { parse, stringify } from 'yaml';
|
|
12
|
-
|
|
13
|
-
import { STRING_LITERALS } from '../constants/wu-ui-constants.js';
|
|
14
|
-
|
|
15
|
-
import { createWuPaths } from './wu-paths.js';
|
|
16
|
-
import { BaseWUSchema } from './wu-schema.js';
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Unified WU YAML I/O module.
|
|
20
|
-
*
|
|
21
|
-
* Replaces 4 duplicate read/write functions scattered across wu-claim, wu-done,
|
|
22
|
-
* wu-block, and wu-unblock. Single source of truth for WU YAML operations.
|
|
23
|
-
*
|
|
24
|
-
* WU-1352: Standardized on yaml v2.8.1 (eemeli) with consistent stringify options.
|
|
25
|
-
*
|
|
26
|
-
* Functions:
|
|
27
|
-
* - readWU(path, id): Read and validate WU YAML
|
|
28
|
-
* - readWURaw(path): Read YAML without ID validation
|
|
29
|
-
* - parseYAML(text): Parse YAML string to object
|
|
30
|
-
* - writeWU(path, doc): Write WU YAML with consistent formatting
|
|
31
|
-
* - stringifyYAML(doc): Stringify object to YAML with consistent formatting
|
|
32
|
-
* - appendNote(doc, note): Append note to doc.notes field
|
|
33
|
-
*
|
|
34
|
-
* @example
|
|
35
|
-
* import { readWU, writeWU, appendNote } from './lib/wu-yaml.js';
|
|
36
|
-
* import { createWuPaths } from './wu-paths.js';
|
|
37
|
-
*
|
|
38
|
-
* const wuPaths = createWuPaths();
|
|
39
|
-
*
|
|
40
|
-
* // Read WU
|
|
41
|
-
* const doc = readWU(wuPaths.WU('WU-123'), 'WU-123');
|
|
42
|
-
*
|
|
43
|
-
* // Modify doc
|
|
44
|
-
* doc.status = 'in_progress';
|
|
45
|
-
* appendNote(doc, 'Started work on this WU');
|
|
46
|
-
*
|
|
47
|
-
* // Write back
|
|
48
|
-
* writeWU(wuPaths.WU('WU-123'), doc);
|
|
49
|
-
*/
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* WU-1352: YAML scalar type constants (from yaml library).
|
|
53
|
-
* These match the string values expected by the yaml package.
|
|
54
|
-
* @see https://github.com/eemeli/yaml/blob/main/docs/03_options.md
|
|
55
|
-
*/
|
|
56
|
-
const YAML_SCALAR_TYPES = Object.freeze({
|
|
57
|
-
/** Unquoted string (when safe) */
|
|
58
|
-
PLAIN: 'PLAIN',
|
|
59
|
-
/** Single-quoted string */
|
|
60
|
-
QUOTE_SINGLE: 'QUOTE_SINGLE',
|
|
61
|
-
/** Double-quoted string */
|
|
62
|
-
QUOTE_DOUBLE: 'QUOTE_DOUBLE',
|
|
63
|
-
/** Block literal (|) */
|
|
64
|
-
BLOCK_LITERAL: 'BLOCK_LITERAL',
|
|
65
|
-
/** Block folded (>) */
|
|
66
|
-
BLOCK_FOLDED: 'BLOCK_FOLDED',
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
/** Standard line width for WU YAML files */
|
|
70
|
-
const YAML_LINE_WIDTH = 100;
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* WU-1352: Standardized YAML stringify options.
|
|
74
|
-
*
|
|
75
|
-
* Ensures consistent output across all WU tools:
|
|
76
|
-
* - lineWidth: 100 (wrap long lines)
|
|
77
|
-
* - singleQuote: true (prefer 'single' over "double")
|
|
78
|
-
* - defaultKeyType: PLAIN (unquoted keys when safe)
|
|
79
|
-
*
|
|
80
|
-
* @type {import('yaml').ToStringOptions}
|
|
81
|
-
*/
|
|
82
|
-
export const YAML_STRINGIFY_OPTIONS = Object.freeze({
|
|
83
|
-
lineWidth: YAML_LINE_WIDTH,
|
|
84
|
-
singleQuote: true,
|
|
85
|
-
defaultKeyType: YAML_SCALAR_TYPES.PLAIN,
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* WU-2125: Parse YAML content string into a validated object.
|
|
90
|
-
*
|
|
91
|
-
* Shared parse boundary for all read functions. Wraps YAML parse errors
|
|
92
|
-
* with structured error codes and path context.
|
|
93
|
-
*
|
|
94
|
-
* @param {string} text - Raw YAML content
|
|
95
|
-
* @param {string} sourcePath - File path (for error messages)
|
|
96
|
-
* @returns {Record<string, unknown>} Parsed document
|
|
97
|
-
* @throws {Error} YAML_PARSE_ERROR if YAML is invalid
|
|
98
|
-
*/
|
|
99
|
-
function parseWUYaml(text: string, sourcePath: string): Record<string, unknown> {
|
|
100
|
-
try {
|
|
101
|
-
return parse(text) as Record<string, unknown>;
|
|
102
|
-
} catch (e: unknown) {
|
|
103
|
-
const msg = getErrorMessage(e);
|
|
104
|
-
throw createError(ErrorCodes.YAML_PARSE_ERROR, `Failed to parse YAML ${sourcePath}: ${msg}`, {
|
|
105
|
-
path: sourcePath,
|
|
106
|
-
originalError: msg,
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* WU-2125: Validate that a parsed WU document's id field matches the expected ID.
|
|
113
|
-
*
|
|
114
|
-
* @param {unknown} doc - Parsed YAML document (may be null for empty files)
|
|
115
|
-
* @param {string} expectedId - Expected WU ID (e.g., 'WU-123')
|
|
116
|
-
* @param {string} wuPath - File path (for error messages)
|
|
117
|
-
* @returns {Record<string, unknown>} Validated document
|
|
118
|
-
* @throws {Error} WU_NOT_FOUND if doc is null or ID does not match
|
|
119
|
-
*/
|
|
120
|
-
function validateWUId(doc: unknown, expectedId: string, wuPath: string): Record<string, unknown> {
|
|
121
|
-
const parsed = doc as Record<string, unknown> | null;
|
|
122
|
-
if (!parsed || parsed.id !== expectedId) {
|
|
123
|
-
throw createError(
|
|
124
|
-
ErrorCodes.WU_NOT_FOUND,
|
|
125
|
-
`WU YAML id mismatch. Expected ${expectedId}, found ${parsed && parsed.id}`,
|
|
126
|
-
{ path: wuPath, expectedId, foundId: parsed && parsed.id },
|
|
127
|
-
);
|
|
128
|
-
}
|
|
129
|
-
return parsed;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Read and parse WU YAML file.
|
|
134
|
-
*
|
|
135
|
-
* Validates:
|
|
136
|
-
* - File exists
|
|
137
|
-
* - YAML is valid
|
|
138
|
-
* - WU ID matches expected ID
|
|
139
|
-
*
|
|
140
|
-
* @param {string} wuPath - Path to WU YAML file
|
|
141
|
-
* @param {string} expectedId - Expected WU ID (e.g., 'WU-123')
|
|
142
|
-
* @returns {object} Parsed YAML document
|
|
143
|
-
* @throws {Error} If file not found, YAML invalid, or ID mismatch
|
|
144
|
-
*/
|
|
145
|
-
export function readWU(wuPath: string, expectedId: string): Record<string, unknown> {
|
|
146
|
-
if (!existsSync(wuPath)) {
|
|
147
|
-
throw createError(ErrorCodes.FILE_NOT_FOUND, `WU file not found: ${wuPath}`, {
|
|
148
|
-
path: wuPath,
|
|
149
|
-
expectedId,
|
|
150
|
-
});
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
const text = readFileSync(wuPath, { encoding: 'utf-8' });
|
|
154
|
-
const doc = parseWUYaml(text, wuPath);
|
|
155
|
-
return validateWUId(doc, expectedId, wuPath);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
/**
|
|
159
|
-
* Read and parse WU YAML file asynchronously.
|
|
160
|
-
*
|
|
161
|
-
* Validates:
|
|
162
|
-
* - File exists
|
|
163
|
-
* - YAML is valid
|
|
164
|
-
* - WU ID matches expected ID
|
|
165
|
-
*
|
|
166
|
-
* @param {string} wuPath - Path to WU YAML file
|
|
167
|
-
* @param {string} expectedId - Expected WU ID (e.g., 'WU-123')
|
|
168
|
-
* @returns {Promise<object>} Parsed YAML document
|
|
169
|
-
* @throws {Error} If file not found, YAML invalid, or ID mismatch
|
|
170
|
-
*/
|
|
171
|
-
export async function readWUAsync(
|
|
172
|
-
wuPath: string,
|
|
173
|
-
expectedId: string,
|
|
174
|
-
): Promise<Record<string, unknown>> {
|
|
175
|
-
try {
|
|
176
|
-
const text = await fs.readFile(wuPath, { encoding: 'utf-8' });
|
|
177
|
-
const doc = parseWUYaml(text, wuPath);
|
|
178
|
-
return validateWUId(doc, expectedId, wuPath);
|
|
179
|
-
} catch (err: unknown) {
|
|
180
|
-
const errObj = err as { code?: string };
|
|
181
|
-
if (errObj.code === 'ENOENT') {
|
|
182
|
-
throw createError(ErrorCodes.FILE_NOT_FOUND, `WU file not found: ${wuPath}`, {
|
|
183
|
-
path: wuPath,
|
|
184
|
-
expectedId,
|
|
185
|
-
});
|
|
186
|
-
}
|
|
187
|
-
throw err;
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* Parse YAML string to object.
|
|
193
|
-
* WU-1352: Centralized YAML parsing for consistency.
|
|
194
|
-
*
|
|
195
|
-
* @param {string} text - YAML string to parse
|
|
196
|
-
* @returns {object} Parsed object
|
|
197
|
-
* @throws {Error} If YAML is invalid
|
|
198
|
-
*/
|
|
199
|
-
export function parseYAML(text: string): Record<string, unknown> {
|
|
200
|
-
return parse(text) as Record<string, unknown>;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* Stringify object to YAML with standardized options.
|
|
205
|
-
* WU-1352: Centralized YAML serialization for consistency.
|
|
206
|
-
*
|
|
207
|
-
* @param {object} doc - Object to stringify
|
|
208
|
-
* @param {object} [options] - Additional stringify options (merged with YAML_STRINGIFY_OPTIONS)
|
|
209
|
-
* @returns {string} YAML string
|
|
210
|
-
*/
|
|
211
|
-
export function stringifyYAML(doc: unknown, options: Record<string, unknown> = {}): string {
|
|
212
|
-
return stringify(doc, { ...YAML_STRINGIFY_OPTIONS, ...options });
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* Read and parse YAML file without ID validation.
|
|
217
|
-
* WU-1352: For cases where you don't know/need to validate the WU ID.
|
|
218
|
-
*
|
|
219
|
-
* @param {string} yamlPath - Path to YAML file
|
|
220
|
-
* @returns {object} Parsed YAML document
|
|
221
|
-
* @throws {Error} If file not found or YAML invalid
|
|
222
|
-
*/
|
|
223
|
-
export function readWURaw(yamlPath: string): Record<string, unknown> {
|
|
224
|
-
if (!existsSync(yamlPath)) {
|
|
225
|
-
throw createError(ErrorCodes.FILE_NOT_FOUND, `YAML file not found: ${yamlPath}`, {
|
|
226
|
-
path: yamlPath,
|
|
227
|
-
});
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
const text = readFileSync(yamlPath, { encoding: 'utf-8' });
|
|
231
|
-
return parseWUYaml(text, yamlPath);
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
/**
|
|
235
|
-
* Read and parse YAML file without ID validation asynchronously.
|
|
236
|
-
* WU-1352: For cases where you don't know/need to validate the WU ID.
|
|
237
|
-
*
|
|
238
|
-
* @param {string} yamlPath - Path to YAML file
|
|
239
|
-
* @returns {Promise<object>} Parsed YAML document
|
|
240
|
-
* @throws {Error} If file not found or YAML invalid
|
|
241
|
-
*/
|
|
242
|
-
export async function readWURawAsync(yamlPath: string): Promise<Record<string, unknown>> {
|
|
243
|
-
try {
|
|
244
|
-
const text = await fs.readFile(yamlPath, { encoding: 'utf-8' });
|
|
245
|
-
return parseWUYaml(text, yamlPath);
|
|
246
|
-
} catch (err: unknown) {
|
|
247
|
-
const errObj = err as { code?: string };
|
|
248
|
-
if (errObj.code === 'ENOENT') {
|
|
249
|
-
throw createError(ErrorCodes.FILE_NOT_FOUND, `YAML file not found: ${yamlPath}`, {
|
|
250
|
-
path: yamlPath,
|
|
251
|
-
});
|
|
252
|
-
}
|
|
253
|
-
throw err;
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
/**
|
|
258
|
-
* Write WU YAML file with consistent formatting.
|
|
259
|
-
* WU-1352: Uses YAML_STRINGIFY_OPTIONS for consistent output.
|
|
260
|
-
* WU-2115: Validates doc against BaseWUSchema before writing to prevent
|
|
261
|
-
* malformed WU YAML from being silently persisted.
|
|
262
|
-
*
|
|
263
|
-
* @param {string} wuPath - Path to WU YAML file
|
|
264
|
-
* @param {object} doc - YAML document to write
|
|
265
|
-
* @throws {ZodError} If doc fails BaseWUSchema validation
|
|
266
|
-
*/
|
|
267
|
-
export function writeWU(wuPath: string, doc: unknown): void {
|
|
268
|
-
// WU-2115: Validate against schema before writing — throws ZodError on invalid data
|
|
269
|
-
BaseWUSchema.parse(doc);
|
|
270
|
-
const out = stringify(doc, YAML_STRINGIFY_OPTIONS);
|
|
271
|
-
writeFileSync(wuPath, out, { encoding: 'utf-8' });
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
/**
|
|
275
|
-
* Append note to WU document's notes field.
|
|
276
|
-
*
|
|
277
|
-
* Always outputs a string (Zod schema requires string type).
|
|
278
|
-
* Handles various input formats:
|
|
279
|
-
* - undefined/null/empty: Set note directly as string
|
|
280
|
-
* - string: Append with newline separator
|
|
281
|
-
* - array: Convert to newline-separated string, then append
|
|
282
|
-
* - other: Replace with note
|
|
283
|
-
*
|
|
284
|
-
* @param {object} doc - WU document
|
|
285
|
-
* @param {string} note - Note to append
|
|
286
|
-
*/
|
|
287
|
-
export function appendNote(doc: Record<string, unknown>, note: string): void {
|
|
288
|
-
// Do nothing if note is falsy
|
|
289
|
-
if (!note) return;
|
|
290
|
-
|
|
291
|
-
const existing = doc.notes;
|
|
292
|
-
|
|
293
|
-
if (existing === undefined || existing === null || existing === '') {
|
|
294
|
-
// No existing notes: set directly as string
|
|
295
|
-
doc.notes = note;
|
|
296
|
-
} else if (Array.isArray(existing)) {
|
|
297
|
-
// Array notes: convert to string first (schema requires string), then append
|
|
298
|
-
const joined = existing.filter(Boolean).join(STRING_LITERALS.NEWLINE).trimEnd();
|
|
299
|
-
doc.notes = joined ? `${joined}${STRING_LITERALS.NEWLINE}${note}` : note;
|
|
300
|
-
} else if (typeof existing === 'string') {
|
|
301
|
-
// String notes: append with newline
|
|
302
|
-
const trimmed = existing.trimEnd();
|
|
303
|
-
doc.notes = trimmed ? `${trimmed}${STRING_LITERALS.NEWLINE}${note}` : note;
|
|
304
|
-
} else {
|
|
305
|
-
// Invalid type: replace with note
|
|
306
|
-
doc.notes = note;
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
/**
|
|
311
|
-
* Append an agent session entry to a WU's agent_sessions[] array
|
|
312
|
-
*
|
|
313
|
-
* @param {string} wuId - WU ID (e.g., "WU-1234")
|
|
314
|
-
* @param {object} sessionData - Session summary from endSession()
|
|
315
|
-
* @throws {Error} if WU file not found
|
|
316
|
-
*/
|
|
317
|
-
export function appendAgentSession(wuId: string, sessionData: Record<string, unknown>): void {
|
|
318
|
-
const paths = createWuPaths();
|
|
319
|
-
const wuPath = paths.WU(wuId);
|
|
320
|
-
|
|
321
|
-
if (!existsSync(wuPath)) {
|
|
322
|
-
throw createError(ErrorCodes.FILE_NOT_FOUND, `WU file not found: ${wuPath}`);
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
// Parse WU YAML
|
|
326
|
-
const doc = readWU(wuPath, wuId);
|
|
327
|
-
|
|
328
|
-
// Initialize agent_sessions array if needed
|
|
329
|
-
if (!Array.isArray(doc.agent_sessions)) {
|
|
330
|
-
doc.agent_sessions = [];
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
// Append session
|
|
334
|
-
(doc.agent_sessions as unknown[]).push(sessionData);
|
|
335
|
-
|
|
336
|
-
// Write back
|
|
337
|
-
writeWU(wuPath, doc);
|
|
338
|
-
}
|