@lumenflow/cli 1.0.0 → 1.3.0

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.
@@ -0,0 +1,158 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * WU Unlock Lane Helper
4
+ *
5
+ * Provides a dedicated audited command for operators to safely clear lane locks.
6
+ *
7
+ * Safety-first approach:
8
+ * - Zombie locks (PID not running): Can be unlocked without --force
9
+ * - Stale locks (>24h old): Can be unlocked without --force
10
+ * - Active locks (recent, PID running): Require --force to unlock
11
+ *
12
+ * All unlocks require a --reason parameter for audit purposes.
13
+ *
14
+ * Usage:
15
+ * pnpm wu:unlock-lane --lane "Core" --reason "Process crashed"
16
+ * pnpm wu:unlock-lane --lane "Core" --reason "Emergency" --force
17
+ * pnpm wu:unlock-lane --list # List all current locks
18
+ */
19
+ import { createWUParser, WU_OPTIONS } from '@lumenflow/core/dist/arg-parser.js';
20
+ import { die } from '@lumenflow/core/dist/error-handler.js';
21
+ import { auditedUnlock, checkLaneLock, getAllLaneLocks, isLockStale, isZombieLock, } from '@lumenflow/core/dist/lane-lock.js';
22
+ import { LOG_PREFIX, EXIT_CODES } from '@lumenflow/core/dist/wu-constants.js';
23
+ const PREFIX = LOG_PREFIX.UNLOCK_LANE || '[wu-unlock-lane]';
24
+ function listLocks() {
25
+ const locks = getAllLaneLocks();
26
+ if (locks.size === 0) {
27
+ console.log(`${PREFIX} No lane locks found.`);
28
+ return;
29
+ }
30
+ console.log(`${PREFIX} Current lane locks:`);
31
+ console.log('');
32
+ for (const [lane, metadata] of locks) {
33
+ const stale = isLockStale(metadata);
34
+ const zombie = isZombieLock(metadata);
35
+ let status;
36
+ if (zombie) {
37
+ status = 'ZOMBIE (PID not running - safe to remove)';
38
+ }
39
+ else if (stale) {
40
+ status = 'STALE (>24h old - safe to remove)';
41
+ }
42
+ else {
43
+ status = 'ACTIVE (requires --force)';
44
+ }
45
+ console.log(` Lane: ${lane}`);
46
+ console.log(` WU: ${metadata.wuId}`);
47
+ console.log(` PID: ${metadata.pid}`);
48
+ console.log(` Timestamp: ${metadata.timestamp}`);
49
+ console.log(` Status: ${status}`);
50
+ console.log('');
51
+ }
52
+ }
53
+ function showLaneStatus(lane) {
54
+ const lockStatus = checkLaneLock(lane);
55
+ if (!lockStatus.locked) {
56
+ console.log(`${PREFIX} Lane "${lane}" is not locked.`);
57
+ return;
58
+ }
59
+ const { metadata } = lockStatus;
60
+ const stale = isLockStale(metadata);
61
+ const zombie = isZombieLock(metadata);
62
+ console.log(`${PREFIX} Lane "${lane}" is locked:`);
63
+ console.log(` WU: ${metadata.wuId}`);
64
+ console.log(` PID: ${metadata.pid}`);
65
+ console.log(` Timestamp: ${metadata.timestamp}`);
66
+ console.log(` Agent Session: ${metadata.agentSession || 'N/A'}`);
67
+ console.log('');
68
+ if (zombie) {
69
+ console.log(` Status: ZOMBIE`);
70
+ console.log(` The process that acquired this lock is no longer running.`);
71
+ console.log(` This lock can be safely removed without --force.`);
72
+ console.log('');
73
+ console.log(` Suggested command:`);
74
+ console.log(` pnpm wu:unlock-lane --lane "${lane}" --reason "Zombie lock cleanup"`);
75
+ }
76
+ else if (stale) {
77
+ console.log(` Status: STALE`);
78
+ console.log(` This lock is more than 24 hours old.`);
79
+ console.log(` This lock can be safely removed without --force.`);
80
+ console.log('');
81
+ console.log(` Suggested command:`);
82
+ console.log(` pnpm wu:unlock-lane --lane "${lane}" --reason "Stale lock cleanup"`);
83
+ }
84
+ else {
85
+ console.log(` Status: ACTIVE`);
86
+ console.log(` This lock is recent and the process (PID ${metadata.pid}) is still running.`);
87
+ console.log(` Removing this lock requires --force and should only be done in emergencies.`);
88
+ console.log('');
89
+ console.log(` Emergency unlock (use with caution):`);
90
+ console.log(` pnpm wu:unlock-lane --lane "${lane}" --reason "<explanation>" --force`);
91
+ }
92
+ }
93
+ async function main() {
94
+ const args = createWUParser({
95
+ name: 'wu-unlock-lane',
96
+ description: 'Safely unlock a lane lock with audit logging',
97
+ options: [
98
+ WU_OPTIONS.lane,
99
+ WU_OPTIONS.reason,
100
+ WU_OPTIONS.force,
101
+ {
102
+ name: 'list',
103
+ flags: '--list',
104
+ description: 'List all current lane locks',
105
+ },
106
+ {
107
+ name: 'status',
108
+ flags: '--status',
109
+ description: 'Show detailed status for the specified lane',
110
+ },
111
+ ],
112
+ required: [],
113
+ allowPositionalId: false,
114
+ });
115
+ if (args.list) {
116
+ listLocks();
117
+ process.exit(EXIT_CODES.SUCCESS);
118
+ }
119
+ if (!args.lane) {
120
+ die('Missing --lane parameter.\n\n' +
121
+ 'Usage:\n' +
122
+ ' pnpm wu:unlock-lane --lane "Core" --reason "<text>"\n' +
123
+ ' pnpm wu:unlock-lane --list\n' +
124
+ ' pnpm wu:unlock-lane --lane "Core" --status');
125
+ }
126
+ if (args.status) {
127
+ showLaneStatus(args.lane);
128
+ process.exit(EXIT_CODES.SUCCESS);
129
+ }
130
+ if (!args.reason) {
131
+ die('Missing --reason parameter.\n\n' +
132
+ 'A reason is required for audit purposes.\n\n' +
133
+ 'Example:\n' +
134
+ ` pnpm wu:unlock-lane --lane "${args.lane}" --reason "Process crashed during claim"`);
135
+ }
136
+ console.log(`${PREFIX} Attempting to unlock lane "${args.lane}"...`);
137
+ const result = auditedUnlock(args.lane, {
138
+ reason: args.reason,
139
+ force: args.force || false,
140
+ });
141
+ if (result.notFound) {
142
+ console.log(`${PREFIX} Lane "${args.lane}" was not locked.`);
143
+ process.exit(EXIT_CODES.SUCCESS);
144
+ }
145
+ if (!result.released) {
146
+ console.error(`${PREFIX} Failed to unlock lane.`);
147
+ console.error(`${PREFIX} ${result.error}`);
148
+ process.exit(EXIT_CODES.FAILURE);
149
+ }
150
+ console.log(`${PREFIX} Successfully unlocked lane "${args.lane}".`);
151
+ if (result.forced) {
152
+ console.warn(`${PREFIX} ⚠️ This was a forced unlock of an active lock.`);
153
+ console.warn(`${PREFIX} Ensure ${result.previousLock?.wuId || 'the owning WU'} is notified.`);
154
+ }
155
+ console.log(`${PREFIX} Previous owner: ${result.previousLock?.wuId || 'unknown'}`);
156
+ console.log(`${PREFIX} Reason: ${result.reason}`);
157
+ }
158
+ main();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lumenflow/cli",
3
- "version": "1.0.0",
3
+ "version": "1.3.0",
4
4
  "description": "Command-line interface for LumenFlow workflow framework",
5
5
  "keywords": [
6
6
  "lumenflow",
@@ -36,6 +36,8 @@
36
36
  "wu-cleanup": "./dist/wu-cleanup.js",
37
37
  "wu-deps": "./dist/wu-deps.js",
38
38
  "wu-infer-lane": "./dist/wu-infer-lane.js",
39
+ "wu-delete": "./dist/wu-delete.js",
40
+ "wu-unlock-lane": "./dist/wu-unlock-lane.js",
39
41
  "mem-init": "./dist/mem-init.js",
40
42
  "mem-checkpoint": "./dist/mem-checkpoint.js",
41
43
  "mem-start": "./dist/mem-start.js",
@@ -51,9 +53,22 @@
51
53
  "initiative-list": "./dist/initiative-list.js",
52
54
  "initiative-status": "./dist/initiative-status.js",
53
55
  "initiative-add-wu": "./dist/initiative-add-wu.js",
56
+ "agent-session": "./dist/agent-session.js",
57
+ "agent-session-end": "./dist/agent-session-end.js",
58
+ "agent-log-issue": "./dist/agent-log-issue.js",
59
+ "orchestrate-initiative": "./dist/orchestrate-initiative.js",
60
+ "orchestrate-init-status": "./dist/orchestrate-init-status.js",
61
+ "orchestrate-monitor": "./dist/orchestrate-monitor.js",
54
62
  "spawn-list": "./dist/spawn-list.js",
63
+ "flow-report": "./dist/flow-report.js",
64
+ "flow-bottlenecks": "./dist/flow-bottlenecks.js",
65
+ "metrics-snapshot": "./dist/metrics-snapshot.js",
66
+ "initiative-bulk-assign-wus": "./dist/initiative-bulk-assign-wus.js",
67
+ "agent-issues-query": "./dist/agent-issues-query.js",
55
68
  "gates": "./dist/gates.js",
56
- "lumenflow-gates": "./dist/gates.js"
69
+ "lumenflow-gates": "./dist/gates.js",
70
+ "lumenflow-init": "./dist/init.js",
71
+ "lumenflow": "./dist/init.js"
57
72
  },
58
73
  "files": [
59
74
  "dist",
@@ -61,20 +76,25 @@
61
76
  "README.md"
62
77
  ],
63
78
  "dependencies": {
79
+ "chalk": "^5.6.2",
64
80
  "cli-table3": "^0.6.5",
65
- "commander": "^12.1.0",
66
- "js-yaml": "^4.1.0",
81
+ "commander": "^14.0.2",
82
+ "fast-glob": "^3.3.3",
67
83
  "minimatch": "^10.1.1",
68
84
  "ms": "^2.1.3",
69
85
  "pretty-ms": "^9.2.0",
70
- "@lumenflow/core": "1.0.0",
71
- "@lumenflow/memory": "1.0.0",
72
- "@lumenflow/initiatives": "1.0.0",
73
- "@lumenflow/agent": "1.0.0"
86
+ "simple-git": "^3.30.0",
87
+ "yaml": "^2.8.2",
88
+ "@lumenflow/memory": "1.3.0",
89
+ "@lumenflow/agent": "1.3.0",
90
+ "@lumenflow/initiatives": "1.3.0",
91
+ "@lumenflow/metrics": "1.3.0",
92
+ "@lumenflow/core": "1.3.0"
74
93
  },
75
94
  "devDependencies": {
76
- "typescript": "^5.7.0",
77
- "vitest": "^2.1.0"
95
+ "@vitest/coverage-v8": "^4.0.17",
96
+ "typescript": "^5.9.3",
97
+ "vitest": "^4.0.17"
78
98
  },
79
99
  "engines": {
80
100
  "node": ">=22"