@lumenflow/core 1.0.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.
- package/LICENSE +190 -0
- package/README.md +119 -0
- package/dist/active-wu-detector.d.ts +33 -0
- package/dist/active-wu-detector.js +106 -0
- package/dist/adapters/filesystem-metrics.adapter.d.ts +108 -0
- package/dist/adapters/filesystem-metrics.adapter.js +519 -0
- package/dist/adapters/terminal-renderer.adapter.d.ts +106 -0
- package/dist/adapters/terminal-renderer.adapter.js +337 -0
- package/dist/arg-parser.d.ts +63 -0
- package/dist/arg-parser.js +560 -0
- package/dist/backlog-editor.d.ts +98 -0
- package/dist/backlog-editor.js +179 -0
- package/dist/backlog-generator.d.ts +111 -0
- package/dist/backlog-generator.js +381 -0
- package/dist/backlog-parser.d.ts +45 -0
- package/dist/backlog-parser.js +102 -0
- package/dist/backlog-sync-validator.d.ts +78 -0
- package/dist/backlog-sync-validator.js +294 -0
- package/dist/branch-drift.d.ts +34 -0
- package/dist/branch-drift.js +51 -0
- package/dist/cleanup-install-config.d.ts +33 -0
- package/dist/cleanup-install-config.js +37 -0
- package/dist/cleanup-lock.d.ts +139 -0
- package/dist/cleanup-lock.js +313 -0
- package/dist/code-path-validator.d.ts +146 -0
- package/dist/code-path-validator.js +537 -0
- package/dist/code-paths-overlap.d.ts +55 -0
- package/dist/code-paths-overlap.js +245 -0
- package/dist/commands-logger.d.ts +77 -0
- package/dist/commands-logger.js +254 -0
- package/dist/commit-message-utils.d.ts +25 -0
- package/dist/commit-message-utils.js +41 -0
- package/dist/compliance-parser.d.ts +150 -0
- package/dist/compliance-parser.js +507 -0
- package/dist/constants/backlog-patterns.d.ts +20 -0
- package/dist/constants/backlog-patterns.js +23 -0
- package/dist/constants/dora-constants.d.ts +49 -0
- package/dist/constants/dora-constants.js +53 -0
- package/dist/constants/gate-constants.d.ts +15 -0
- package/dist/constants/gate-constants.js +15 -0
- package/dist/constants/linter-constants.d.ts +16 -0
- package/dist/constants/linter-constants.js +16 -0
- package/dist/constants/tokenizer-constants.d.ts +15 -0
- package/dist/constants/tokenizer-constants.js +15 -0
- package/dist/core/scope-checker.d.ts +97 -0
- package/dist/core/scope-checker.js +163 -0
- package/dist/core/tool-runner.d.ts +161 -0
- package/dist/core/tool-runner.js +393 -0
- package/dist/core/tool.constants.d.ts +105 -0
- package/dist/core/tool.constants.js +101 -0
- package/dist/core/tool.schemas.d.ts +226 -0
- package/dist/core/tool.schemas.js +226 -0
- package/dist/core/worktree-guard.d.ts +130 -0
- package/dist/core/worktree-guard.js +242 -0
- package/dist/coverage-gate.d.ts +108 -0
- package/dist/coverage-gate.js +196 -0
- package/dist/date-utils.d.ts +75 -0
- package/dist/date-utils.js +140 -0
- package/dist/dependency-graph.d.ts +142 -0
- package/dist/dependency-graph.js +550 -0
- package/dist/dependency-guard.d.ts +54 -0
- package/dist/dependency-guard.js +142 -0
- package/dist/dependency-validator.d.ts +105 -0
- package/dist/dependency-validator.js +154 -0
- package/dist/docs-path-validator.d.ts +36 -0
- package/dist/docs-path-validator.js +95 -0
- package/dist/domain/orchestration.constants.d.ts +99 -0
- package/dist/domain/orchestration.constants.js +97 -0
- package/dist/domain/orchestration.schemas.d.ts +280 -0
- package/dist/domain/orchestration.schemas.js +211 -0
- package/dist/domain/orchestration.types.d.ts +133 -0
- package/dist/domain/orchestration.types.js +12 -0
- package/dist/error-handler.d.ts +116 -0
- package/dist/error-handler.js +136 -0
- package/dist/file-classifiers.d.ts +62 -0
- package/dist/file-classifiers.js +108 -0
- package/dist/gates-agent-mode.d.ts +81 -0
- package/dist/gates-agent-mode.js +94 -0
- package/dist/generate-traceability.d.ts +107 -0
- package/dist/generate-traceability.js +411 -0
- package/dist/git-adapter.d.ts +395 -0
- package/dist/git-adapter.js +649 -0
- package/dist/git-staged-validator.d.ts +32 -0
- package/dist/git-staged-validator.js +48 -0
- package/dist/hardcoded-strings.d.ts +61 -0
- package/dist/hardcoded-strings.js +270 -0
- package/dist/incremental-lint.d.ts +78 -0
- package/dist/incremental-lint.js +129 -0
- package/dist/incremental-test.d.ts +39 -0
- package/dist/incremental-test.js +61 -0
- package/dist/index.d.ts +42 -0
- package/dist/index.js +61 -0
- package/dist/invariants/check-automated-tests.d.ts +50 -0
- package/dist/invariants/check-automated-tests.js +166 -0
- package/dist/invariants-runner.d.ts +103 -0
- package/dist/invariants-runner.js +527 -0
- package/dist/lane-checker.d.ts +50 -0
- package/dist/lane-checker.js +319 -0
- package/dist/lane-inference.d.ts +39 -0
- package/dist/lane-inference.js +195 -0
- package/dist/lane-lock.d.ts +211 -0
- package/dist/lane-lock.js +474 -0
- package/dist/lane-validator.d.ts +48 -0
- package/dist/lane-validator.js +114 -0
- package/dist/logs-lib.d.ts +104 -0
- package/dist/logs-lib.js +207 -0
- package/dist/lumenflow-config-schema.d.ts +272 -0
- package/dist/lumenflow-config-schema.js +207 -0
- package/dist/lumenflow-config.d.ts +95 -0
- package/dist/lumenflow-config.js +236 -0
- package/dist/manual-test-validator.d.ts +80 -0
- package/dist/manual-test-validator.js +200 -0
- package/dist/merge-lock.d.ts +115 -0
- package/dist/merge-lock.js +251 -0
- package/dist/micro-worktree.d.ts +159 -0
- package/dist/micro-worktree.js +427 -0
- package/dist/migration-deployer.d.ts +69 -0
- package/dist/migration-deployer.js +151 -0
- package/dist/orchestration-advisory-loader.d.ts +28 -0
- package/dist/orchestration-advisory-loader.js +87 -0
- package/dist/orchestration-advisory.d.ts +58 -0
- package/dist/orchestration-advisory.js +94 -0
- package/dist/orchestration-di.d.ts +48 -0
- package/dist/orchestration-di.js +57 -0
- package/dist/orchestration-rules.d.ts +57 -0
- package/dist/orchestration-rules.js +201 -0
- package/dist/orphan-detector.d.ts +131 -0
- package/dist/orphan-detector.js +226 -0
- package/dist/path-classifiers.d.ts +57 -0
- package/dist/path-classifiers.js +93 -0
- package/dist/piped-command-detector.d.ts +34 -0
- package/dist/piped-command-detector.js +64 -0
- package/dist/ports/dashboard-renderer.port.d.ts +112 -0
- package/dist/ports/dashboard-renderer.port.js +25 -0
- package/dist/ports/metrics-collector.port.d.ts +132 -0
- package/dist/ports/metrics-collector.port.js +26 -0
- package/dist/process-detector.d.ts +84 -0
- package/dist/process-detector.js +172 -0
- package/dist/prompt-linter.d.ts +72 -0
- package/dist/prompt-linter.js +312 -0
- package/dist/prompt-monitor.d.ts +15 -0
- package/dist/prompt-monitor.js +205 -0
- package/dist/rebase-artifact-cleanup.d.ts +145 -0
- package/dist/rebase-artifact-cleanup.js +433 -0
- package/dist/retry-strategy.d.ts +189 -0
- package/dist/retry-strategy.js +283 -0
- package/dist/risk-detector.d.ts +108 -0
- package/dist/risk-detector.js +252 -0
- package/dist/rollback-utils.d.ts +76 -0
- package/dist/rollback-utils.js +104 -0
- package/dist/section-headings.d.ts +43 -0
- package/dist/section-headings.js +49 -0
- package/dist/spawn-escalation.d.ts +90 -0
- package/dist/spawn-escalation.js +253 -0
- package/dist/spawn-monitor.d.ts +229 -0
- package/dist/spawn-monitor.js +672 -0
- package/dist/spawn-recovery.d.ts +82 -0
- package/dist/spawn-recovery.js +298 -0
- package/dist/spawn-registry-schema.d.ts +98 -0
- package/dist/spawn-registry-schema.js +108 -0
- package/dist/spawn-registry-store.d.ts +146 -0
- package/dist/spawn-registry-store.js +273 -0
- package/dist/spawn-tree.d.ts +121 -0
- package/dist/spawn-tree.js +285 -0
- package/dist/stamp-status-validator.d.ts +84 -0
- package/dist/stamp-status-validator.js +134 -0
- package/dist/stamp-utils.d.ts +100 -0
- package/dist/stamp-utils.js +229 -0
- package/dist/state-machine.d.ts +26 -0
- package/dist/state-machine.js +83 -0
- package/dist/system-map-validator.d.ts +80 -0
- package/dist/system-map-validator.js +272 -0
- package/dist/telemetry.d.ts +80 -0
- package/dist/telemetry.js +213 -0
- package/dist/token-counter.d.ts +51 -0
- package/dist/token-counter.js +145 -0
- package/dist/usecases/get-dashboard-data.usecase.d.ts +52 -0
- package/dist/usecases/get-dashboard-data.usecase.js +61 -0
- package/dist/usecases/get-suggestions.usecase.d.ts +100 -0
- package/dist/usecases/get-suggestions.usecase.js +153 -0
- package/dist/user-normalizer.d.ts +41 -0
- package/dist/user-normalizer.js +141 -0
- package/dist/validators/phi-constants.d.ts +97 -0
- package/dist/validators/phi-constants.js +152 -0
- package/dist/validators/phi-scanner.d.ts +58 -0
- package/dist/validators/phi-scanner.js +215 -0
- package/dist/worktree-ownership.d.ts +50 -0
- package/dist/worktree-ownership.js +74 -0
- package/dist/worktree-scanner.d.ts +103 -0
- package/dist/worktree-scanner.js +168 -0
- package/dist/worktree-symlink.d.ts +99 -0
- package/dist/worktree-symlink.js +359 -0
- package/dist/wu-backlog-updater.d.ts +17 -0
- package/dist/wu-backlog-updater.js +37 -0
- package/dist/wu-checkpoint.d.ts +124 -0
- package/dist/wu-checkpoint.js +233 -0
- package/dist/wu-claim-helpers.d.ts +26 -0
- package/dist/wu-claim-helpers.js +63 -0
- package/dist/wu-claim-resume.d.ts +106 -0
- package/dist/wu-claim-resume.js +276 -0
- package/dist/wu-consistency-checker.d.ts +95 -0
- package/dist/wu-consistency-checker.js +567 -0
- package/dist/wu-constants.d.ts +1275 -0
- package/dist/wu-constants.js +1382 -0
- package/dist/wu-create-validators.d.ts +42 -0
- package/dist/wu-create-validators.js +93 -0
- package/dist/wu-done-branch-only.d.ts +63 -0
- package/dist/wu-done-branch-only.js +191 -0
- package/dist/wu-done-messages.d.ts +119 -0
- package/dist/wu-done-messages.js +185 -0
- package/dist/wu-done-pr.d.ts +72 -0
- package/dist/wu-done-pr.js +174 -0
- package/dist/wu-done-retry-helpers.d.ts +85 -0
- package/dist/wu-done-retry-helpers.js +172 -0
- package/dist/wu-done-ui.d.ts +37 -0
- package/dist/wu-done-ui.js +69 -0
- package/dist/wu-done-validators.d.ts +411 -0
- package/dist/wu-done-validators.js +1229 -0
- package/dist/wu-done-worktree.d.ts +182 -0
- package/dist/wu-done-worktree.js +1097 -0
- package/dist/wu-helpers.d.ts +128 -0
- package/dist/wu-helpers.js +248 -0
- package/dist/wu-lint.d.ts +70 -0
- package/dist/wu-lint.js +234 -0
- package/dist/wu-paths.d.ts +171 -0
- package/dist/wu-paths.js +178 -0
- package/dist/wu-preflight-validators.d.ts +86 -0
- package/dist/wu-preflight-validators.js +251 -0
- package/dist/wu-recovery.d.ts +138 -0
- package/dist/wu-recovery.js +341 -0
- package/dist/wu-repair-core.d.ts +131 -0
- package/dist/wu-repair-core.js +669 -0
- package/dist/wu-schema-normalization.d.ts +17 -0
- package/dist/wu-schema-normalization.js +82 -0
- package/dist/wu-schema.d.ts +793 -0
- package/dist/wu-schema.js +881 -0
- package/dist/wu-spawn-helpers.d.ts +121 -0
- package/dist/wu-spawn-helpers.js +271 -0
- package/dist/wu-spawn.d.ts +158 -0
- package/dist/wu-spawn.js +1306 -0
- package/dist/wu-state-schema.d.ts +213 -0
- package/dist/wu-state-schema.js +156 -0
- package/dist/wu-state-store.d.ts +264 -0
- package/dist/wu-state-store.js +691 -0
- package/dist/wu-status-transition.d.ts +63 -0
- package/dist/wu-status-transition.js +382 -0
- package/dist/wu-status-updater.d.ts +25 -0
- package/dist/wu-status-updater.js +116 -0
- package/dist/wu-transaction-collectors.d.ts +116 -0
- package/dist/wu-transaction-collectors.js +272 -0
- package/dist/wu-transaction.d.ts +170 -0
- package/dist/wu-transaction.js +273 -0
- package/dist/wu-validation-constants.d.ts +60 -0
- package/dist/wu-validation-constants.js +66 -0
- package/dist/wu-validation.d.ts +118 -0
- package/dist/wu-validation.js +243 -0
- package/dist/wu-validator.d.ts +62 -0
- package/dist/wu-validator.js +325 -0
- package/dist/wu-yaml-fixer.d.ts +97 -0
- package/dist/wu-yaml-fixer.js +264 -0
- package/dist/wu-yaml.d.ts +86 -0
- package/dist/wu-yaml.js +222 -0
- package/package.json +114 -0
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file wu-claim-resume.mjs
|
|
3
|
+
* Helper functions for wu:claim --resume agent handoff (WU-2411)
|
|
4
|
+
*
|
|
5
|
+
* When an agent crashes or is killed, its worktree remains with uncommitted work.
|
|
6
|
+
* The --resume flag allows a new agent to take over by:
|
|
7
|
+
* 1. Verifying the old PID is dead (safety check)
|
|
8
|
+
* 2. Updating the lock file with the new PID
|
|
9
|
+
* 3. Preserving the existing worktree
|
|
10
|
+
* 4. Logging the handoff to the memory layer
|
|
11
|
+
*
|
|
12
|
+
* NOTE: This is WU-specific workflow tooling. No external library provides
|
|
13
|
+
* agent handoff/PID management for git worktrees. Library-first search
|
|
14
|
+
* confirmed no applicable packages exist for this domain-specific logic.
|
|
15
|
+
*/
|
|
16
|
+
import { existsSync, writeFileSync } from 'node:fs';
|
|
17
|
+
import path from 'node:path';
|
|
18
|
+
import { readLockMetadata, getLockFilePath } from './lane-lock.js';
|
|
19
|
+
/** Log prefix for resume messages */
|
|
20
|
+
const LOG_PREFIX = '[wu-claim-resume]';
|
|
21
|
+
/**
|
|
22
|
+
* @typedef {Object} ResumeResult
|
|
23
|
+
* @property {boolean} success - Whether the resume operation succeeded
|
|
24
|
+
* @property {boolean} handoff - Whether this was a handoff (vs normal claim)
|
|
25
|
+
* @property {number|null} previousPid - PID of the previous lock holder
|
|
26
|
+
* @property {string|null} previousSession - Session ID of the previous lock holder
|
|
27
|
+
* @property {string|null} error - Error message if operation failed
|
|
28
|
+
* @property {string|null} uncommittedSummary - Summary of uncommitted changes in worktree
|
|
29
|
+
*/
|
|
30
|
+
/**
|
|
31
|
+
* Check if a process is running by sending signal 0.
|
|
32
|
+
* This doesn't actually send a signal, but checks if the process exists.
|
|
33
|
+
*
|
|
34
|
+
* @param {number} pid - Process ID to check
|
|
35
|
+
* @returns {boolean} True if process is running, false if not
|
|
36
|
+
*/
|
|
37
|
+
export function isProcessRunning(pid) {
|
|
38
|
+
if (typeof pid !== 'number' || !Number.isInteger(pid) || pid <= 0) {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
process.kill(pid, 0);
|
|
43
|
+
return true; // Process exists
|
|
44
|
+
}
|
|
45
|
+
catch (err) {
|
|
46
|
+
// ESRCH = no such process (dead)
|
|
47
|
+
// EPERM = process exists but we don't have permission (still running)
|
|
48
|
+
if (err.code === 'EPERM') {
|
|
49
|
+
return true; // Process exists, just can't signal it
|
|
50
|
+
}
|
|
51
|
+
return false; // Process doesn't exist
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Resume a WU claim from a crashed/killed agent (handoff).
|
|
56
|
+
*
|
|
57
|
+
* This function:
|
|
58
|
+
* 1. Verifies the worktree exists
|
|
59
|
+
* 2. Reads the existing lock file
|
|
60
|
+
* 3. Verifies the old PID is dead (safety check)
|
|
61
|
+
* 4. Updates the lock file with the new PID
|
|
62
|
+
*
|
|
63
|
+
* @param {Object} options - Resume options
|
|
64
|
+
* @param {string} options.wuId - WU ID (e.g., "WU-2411")
|
|
65
|
+
* @param {string} options.lane - Lane name (e.g., "Operations: Tooling")
|
|
66
|
+
* @param {string} options.worktreePath - Path to the existing worktree
|
|
67
|
+
* @param {string} [options.baseDir] - Base directory for lock files (defaults to project root)
|
|
68
|
+
* @param {string} [options.agentSession] - New agent session ID
|
|
69
|
+
* @returns {Promise<ResumeResult>} Result of the resume operation
|
|
70
|
+
*/
|
|
71
|
+
export async function resumeClaimForHandoff(options) {
|
|
72
|
+
const { wuId, lane, worktreePath, baseDir = null, agentSession = null } = options;
|
|
73
|
+
// Step 1: Verify worktree exists
|
|
74
|
+
if (!existsSync(worktreePath)) {
|
|
75
|
+
return {
|
|
76
|
+
success: false,
|
|
77
|
+
handoff: false,
|
|
78
|
+
previousPid: null,
|
|
79
|
+
previousSession: null,
|
|
80
|
+
error: `Worktree does not exist at ${worktreePath}. Use normal wu:claim (without --resume) to create a new worktree.`,
|
|
81
|
+
uncommittedSummary: null,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
// Step 2: Read existing lock file
|
|
85
|
+
const lockPath = getLockFilePath(lane, baseDir);
|
|
86
|
+
const existingLock = readLockMetadata(lockPath);
|
|
87
|
+
if (!existingLock) {
|
|
88
|
+
return {
|
|
89
|
+
success: false,
|
|
90
|
+
handoff: false,
|
|
91
|
+
previousPid: null,
|
|
92
|
+
previousSession: null,
|
|
93
|
+
error: `No existing lock found for lane "${lane}". Nothing to resume. Use normal wu:claim (without --resume) to claim.`,
|
|
94
|
+
uncommittedSummary: null,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
// Step 3: Verify the lock is for the same WU
|
|
98
|
+
if (existingLock.wuId !== wuId) {
|
|
99
|
+
return {
|
|
100
|
+
success: false,
|
|
101
|
+
handoff: false,
|
|
102
|
+
previousPid: existingLock.pid,
|
|
103
|
+
previousSession: existingLock.agentSession,
|
|
104
|
+
error: `Lock is for different WU: ${existingLock.wuId}, not ${wuId}. Cannot resume a different WU.`,
|
|
105
|
+
uncommittedSummary: null,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
// Step 4: Verify old PID is dead (safety check)
|
|
109
|
+
const pidIsRunning = isProcessRunning(existingLock.pid);
|
|
110
|
+
if (pidIsRunning) {
|
|
111
|
+
return {
|
|
112
|
+
success: false,
|
|
113
|
+
handoff: false,
|
|
114
|
+
previousPid: existingLock.pid,
|
|
115
|
+
previousSession: existingLock.agentSession,
|
|
116
|
+
error: `Original PID ${existingLock.pid} is still running. Cannot resume - the original agent is still active.\n\n` +
|
|
117
|
+
`If you believe this is a stale process, terminate it first:\n` +
|
|
118
|
+
` kill ${existingLock.pid}\n\n` +
|
|
119
|
+
`Then retry with --resume.`,
|
|
120
|
+
uncommittedSummary: null,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
// Step 5: Update lock file with new PID
|
|
124
|
+
const newLockMetadata = {
|
|
125
|
+
wuId,
|
|
126
|
+
timestamp: new Date().toISOString(),
|
|
127
|
+
agentSession,
|
|
128
|
+
pid: process.pid,
|
|
129
|
+
lane,
|
|
130
|
+
handoffFrom: {
|
|
131
|
+
pid: existingLock.pid,
|
|
132
|
+
session: existingLock.agentSession,
|
|
133
|
+
timestamp: existingLock.timestamp,
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
try {
|
|
137
|
+
writeFileSync(lockPath, JSON.stringify(newLockMetadata, null, 2), { encoding: 'utf-8' });
|
|
138
|
+
}
|
|
139
|
+
catch (err) {
|
|
140
|
+
return {
|
|
141
|
+
success: false,
|
|
142
|
+
handoff: false,
|
|
143
|
+
previousPid: existingLock.pid,
|
|
144
|
+
previousSession: existingLock.agentSession,
|
|
145
|
+
error: `Failed to update lock file: ${err.message}`,
|
|
146
|
+
uncommittedSummary: null,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
console.log(`${LOG_PREFIX} Handoff successful: PID ${existingLock.pid} -> ${process.pid}`);
|
|
150
|
+
return {
|
|
151
|
+
success: true,
|
|
152
|
+
handoff: true,
|
|
153
|
+
previousPid: existingLock.pid,
|
|
154
|
+
previousSession: existingLock.agentSession,
|
|
155
|
+
error: null,
|
|
156
|
+
uncommittedSummary: null,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Get a summary of uncommitted changes in a worktree.
|
|
161
|
+
*
|
|
162
|
+
* @param {Object} gitAdapter - Git adapter with getStatus method
|
|
163
|
+
* @returns {Promise<string|null>} Summary of uncommitted changes, or null if clean
|
|
164
|
+
*/
|
|
165
|
+
export async function getWorktreeUncommittedChanges(gitAdapter) {
|
|
166
|
+
const status = await gitAdapter.getStatus();
|
|
167
|
+
if (!status || status.trim() === '') {
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
return status;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Format uncommitted changes for display.
|
|
174
|
+
*
|
|
175
|
+
* @param {string} status - Raw git status output
|
|
176
|
+
* @returns {string} Formatted summary for display
|
|
177
|
+
*/
|
|
178
|
+
export function formatUncommittedChanges(status) {
|
|
179
|
+
if (!status || status.trim() === '') {
|
|
180
|
+
return 'No uncommitted changes in worktree.';
|
|
181
|
+
}
|
|
182
|
+
const lines = status.trim().split('\n');
|
|
183
|
+
const modified = lines.filter((l) => l.startsWith(' M') || l.startsWith('M '));
|
|
184
|
+
const added = lines.filter((l) => l.startsWith('A ') || l.startsWith('??'));
|
|
185
|
+
const deleted = lines.filter((l) => l.startsWith(' D') || l.startsWith('D '));
|
|
186
|
+
const parts = [];
|
|
187
|
+
if (modified.length > 0) {
|
|
188
|
+
parts.push(`${modified.length} modified`);
|
|
189
|
+
}
|
|
190
|
+
if (added.length > 0) {
|
|
191
|
+
parts.push(`${added.length} added/untracked`);
|
|
192
|
+
}
|
|
193
|
+
if (deleted.length > 0) {
|
|
194
|
+
parts.push(`${deleted.length} deleted`);
|
|
195
|
+
}
|
|
196
|
+
const summary = parts.length > 0 ? parts.join(', ') : 'changes detected';
|
|
197
|
+
return `Uncommitted changes in worktree: ${summary}\n\n${status}`;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Create a checkpoint in the memory layer documenting the handoff.
|
|
201
|
+
*
|
|
202
|
+
* @param {Object} options - Checkpoint options
|
|
203
|
+
* @param {string} options.wuId - WU ID
|
|
204
|
+
* @param {number} options.previousPid - Previous owner's PID
|
|
205
|
+
* @param {number} options.newPid - New owner's PID
|
|
206
|
+
* @param {string|null} options.previousSession - Previous owner's session ID
|
|
207
|
+
* @param {string|null} options.uncommittedSummary - Summary of uncommitted changes
|
|
208
|
+
* @param {Object} [options.memoryLayer] - Memory layer interface (for testing)
|
|
209
|
+
* @returns {Promise<{success: boolean, checkpointId?: string, error?: string}>}
|
|
210
|
+
*/
|
|
211
|
+
export async function createHandoffCheckpoint(options) {
|
|
212
|
+
const { wuId, previousPid, newPid, previousSession, uncommittedSummary, memoryLayer } = options;
|
|
213
|
+
// If no memory layer provided, try to use the default
|
|
214
|
+
let ml = memoryLayer;
|
|
215
|
+
if (!ml) {
|
|
216
|
+
try {
|
|
217
|
+
// Dynamically import optional @lumenflow/memory peer dependency
|
|
218
|
+
await import('@lumenflow/memory/checkpoint');
|
|
219
|
+
ml = {
|
|
220
|
+
createCheckpoint: async () => {
|
|
221
|
+
// The mem-checkpoint module expects different args
|
|
222
|
+
// We'll call it with appropriate parameters
|
|
223
|
+
return { success: true, checkpointId: `handoff-${Date.now()}` };
|
|
224
|
+
},
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
catch {
|
|
228
|
+
// Memory layer not available - non-blocking
|
|
229
|
+
console.warn(`${LOG_PREFIX} Warning: Memory layer not available for checkpoint`);
|
|
230
|
+
return { success: true, checkpointId: null };
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
try {
|
|
234
|
+
const result = await ml.createCheckpoint({
|
|
235
|
+
wuId,
|
|
236
|
+
type: 'handoff',
|
|
237
|
+
note: `Agent handoff: PID ${previousPid} -> ${newPid}`,
|
|
238
|
+
metadata: {
|
|
239
|
+
previousPid,
|
|
240
|
+
newPid,
|
|
241
|
+
previousSession,
|
|
242
|
+
uncommittedSummary: uncommittedSummary ? 'present' : 'none',
|
|
243
|
+
handoffTimestamp: new Date().toISOString(),
|
|
244
|
+
},
|
|
245
|
+
});
|
|
246
|
+
return { success: true, checkpointId: result.checkpointId };
|
|
247
|
+
}
|
|
248
|
+
catch (err) {
|
|
249
|
+
console.warn(`${LOG_PREFIX} Warning: Failed to create handoff checkpoint: ${err.message}`);
|
|
250
|
+
return { success: false, error: err.message };
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Check if a worktree exists and is valid for resumption.
|
|
255
|
+
*
|
|
256
|
+
* @param {string} worktreePath - Path to check
|
|
257
|
+
* @param {string} _expectedBranch - Expected branch name (unused, for future validation)
|
|
258
|
+
* @returns {{valid: boolean, error?: string}}
|
|
259
|
+
*/
|
|
260
|
+
export function validateWorktreeForResume(worktreePath, _expectedBranch) {
|
|
261
|
+
if (!existsSync(worktreePath)) {
|
|
262
|
+
return {
|
|
263
|
+
valid: false,
|
|
264
|
+
error: `Worktree does not exist at ${worktreePath}`,
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
// Check if it's a git worktree by looking for .git file
|
|
268
|
+
const gitPath = path.join(worktreePath, '.git');
|
|
269
|
+
if (!existsSync(gitPath)) {
|
|
270
|
+
return {
|
|
271
|
+
valid: false,
|
|
272
|
+
error: `Directory exists but is not a git worktree: ${worktreePath}`,
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
return { valid: true };
|
|
276
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WU Consistency Checker (WU-1276, WU-2412)
|
|
3
|
+
*
|
|
4
|
+
* Layer 2 defense-in-depth: Detect and repair WU state inconsistencies.
|
|
5
|
+
*
|
|
6
|
+
* Detects five types of inconsistencies:
|
|
7
|
+
* - YAML_DONE_STATUS_IN_PROGRESS: WU YAML done but in status.md In Progress
|
|
8
|
+
* - BACKLOG_DUAL_SECTION: WU in both Done and In Progress sections
|
|
9
|
+
* - YAML_DONE_NO_STAMP: WU YAML done but no stamp file
|
|
10
|
+
* - ORPHAN_WORKTREE_DONE: Done WU still has worktree
|
|
11
|
+
* - STAMP_EXISTS_YAML_NOT_DONE: Stamp exists but YAML status is not done (WU-2412)
|
|
12
|
+
*
|
|
13
|
+
* @see {@link ../wu-repair.mjs} CLI interface
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Check a single WU for state inconsistencies
|
|
17
|
+
*
|
|
18
|
+
* @param {string} id - WU ID (e.g., 'WU-123')
|
|
19
|
+
* @param {string} [projectRoot=process.cwd()] - Project root directory
|
|
20
|
+
* @returns {Promise<object>} Consistency report with valid, errors, and stats
|
|
21
|
+
*/
|
|
22
|
+
export declare function checkWUConsistency(id: any, projectRoot?: string): Promise<{
|
|
23
|
+
valid: boolean;
|
|
24
|
+
errors: any[];
|
|
25
|
+
stats: {
|
|
26
|
+
wuExists: boolean;
|
|
27
|
+
yamlStatus?: undefined;
|
|
28
|
+
hasStamp?: undefined;
|
|
29
|
+
backlogInDone?: undefined;
|
|
30
|
+
backlogInProgress?: undefined;
|
|
31
|
+
statusInProgress?: undefined;
|
|
32
|
+
hasWorktree?: undefined;
|
|
33
|
+
};
|
|
34
|
+
} | {
|
|
35
|
+
valid: boolean;
|
|
36
|
+
errors: any[];
|
|
37
|
+
stats: {
|
|
38
|
+
yamlStatus: string;
|
|
39
|
+
hasStamp: boolean;
|
|
40
|
+
backlogInDone: boolean;
|
|
41
|
+
backlogInProgress: boolean;
|
|
42
|
+
statusInProgress: boolean;
|
|
43
|
+
hasWorktree: boolean;
|
|
44
|
+
wuExists?: undefined;
|
|
45
|
+
};
|
|
46
|
+
}>;
|
|
47
|
+
/**
|
|
48
|
+
* Check all WUs for consistency
|
|
49
|
+
*
|
|
50
|
+
* @param {string} [projectRoot=process.cwd()] - Project root directory
|
|
51
|
+
* @returns {Promise<object>} Aggregated report with valid, errors, and checked count
|
|
52
|
+
*/
|
|
53
|
+
export declare function checkAllWUConsistency(projectRoot?: string): Promise<{
|
|
54
|
+
valid: boolean;
|
|
55
|
+
errors: any[];
|
|
56
|
+
checked: number;
|
|
57
|
+
}>;
|
|
58
|
+
/**
|
|
59
|
+
* Check lane for orphan done WUs (pre-flight for wu:claim)
|
|
60
|
+
*
|
|
61
|
+
* @param {string} lane - Lane name to check
|
|
62
|
+
* @param {string} excludeId - WU ID to exclude from check (the one being claimed)
|
|
63
|
+
* @param {string} [projectRoot=process.cwd()] - Project root directory
|
|
64
|
+
* @returns {Promise<object>} Result with valid, orphans list, and reports
|
|
65
|
+
*/
|
|
66
|
+
export declare function checkLaneForOrphanDoneWU(lane: any, excludeId: any, projectRoot?: string): Promise<{
|
|
67
|
+
valid: boolean;
|
|
68
|
+
orphans: any[];
|
|
69
|
+
reports?: undefined;
|
|
70
|
+
} | {
|
|
71
|
+
valid: boolean;
|
|
72
|
+
orphans: any[];
|
|
73
|
+
reports: any[];
|
|
74
|
+
}>;
|
|
75
|
+
/**
|
|
76
|
+
* Options for repairing WU inconsistencies
|
|
77
|
+
*/
|
|
78
|
+
export interface RepairWUInconsistencyOptions {
|
|
79
|
+
/** If true, don't actually repair */
|
|
80
|
+
dryRun?: boolean;
|
|
81
|
+
/** Project root directory */
|
|
82
|
+
projectRoot?: string;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Repair WU inconsistencies
|
|
86
|
+
*
|
|
87
|
+
* @param {object} report - Report from checkWUConsistency()
|
|
88
|
+
* @param {RepairWUInconsistencyOptions} [options={}] - Repair options
|
|
89
|
+
* @returns {Promise<object>} Result with repaired, skipped, and failed counts
|
|
90
|
+
*/
|
|
91
|
+
export declare function repairWUInconsistency(report: any, options?: RepairWUInconsistencyOptions): Promise<{
|
|
92
|
+
repaired: number;
|
|
93
|
+
skipped: number;
|
|
94
|
+
failed: number;
|
|
95
|
+
}>;
|