@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,233 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WU-1747: WU Checkpoint Module
|
|
3
|
+
*
|
|
4
|
+
* Provides checkpoint-based gate resumption for wu:done operations.
|
|
5
|
+
* Allows failed wu:done to resume from checkpoint without re-running gates
|
|
6
|
+
* if nothing has changed since the checkpoint was created.
|
|
7
|
+
*
|
|
8
|
+
* Features:
|
|
9
|
+
* - Pre-gates checkpoint creation with worktree state
|
|
10
|
+
* - SHA-based change detection
|
|
11
|
+
* - Schema versioning for forward compatibility
|
|
12
|
+
* - Automatic stale checkpoint cleanup
|
|
13
|
+
*
|
|
14
|
+
* @module wu-checkpoint
|
|
15
|
+
*/
|
|
16
|
+
import { existsSync, readFileSync, writeFileSync, unlinkSync, mkdirSync } from 'node:fs';
|
|
17
|
+
import path from 'node:path';
|
|
18
|
+
import crypto from 'node:crypto';
|
|
19
|
+
import { LOG_PREFIX, EMOJI } from './wu-constants.js';
|
|
20
|
+
/**
|
|
21
|
+
* Schema version for checkpoint files
|
|
22
|
+
* Increment when checkpoint format changes
|
|
23
|
+
*/
|
|
24
|
+
export const CHECKPOINT_SCHEMA_VERSION = 1;
|
|
25
|
+
/**
|
|
26
|
+
* Checkpoint directory within .beacon
|
|
27
|
+
*/
|
|
28
|
+
const CHECKPOINT_DIR = 'checkpoints';
|
|
29
|
+
/**
|
|
30
|
+
* Maximum age for a checkpoint before it's considered stale (24 hours)
|
|
31
|
+
*/
|
|
32
|
+
const CHECKPOINT_MAX_AGE_MS = 24 * 60 * 60 * 1000;
|
|
33
|
+
/**
|
|
34
|
+
* Get the path to a checkpoint file
|
|
35
|
+
*
|
|
36
|
+
* @param {string} wuId - WU ID
|
|
37
|
+
* @param {CheckpointBaseDirOptions} [options]
|
|
38
|
+
* @returns {string} Path to checkpoint file
|
|
39
|
+
*/
|
|
40
|
+
function getCheckpointPath(wuId, options = {}) {
|
|
41
|
+
const baseDir = options.baseDir || process.cwd();
|
|
42
|
+
return path.join(baseDir, '.beacon', CHECKPOINT_DIR, `${wuId}.checkpoint.json`);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Ensure checkpoint directory exists
|
|
46
|
+
*
|
|
47
|
+
* @param {CheckpointBaseDirOptions} [options]
|
|
48
|
+
*/
|
|
49
|
+
function ensureCheckpointDir(options = {}) {
|
|
50
|
+
const baseDir = options.baseDir || process.cwd();
|
|
51
|
+
const checkpointDir = path.join(baseDir, '.beacon', CHECKPOINT_DIR);
|
|
52
|
+
if (!existsSync(checkpointDir)) {
|
|
53
|
+
mkdirSync(checkpointDir, { recursive: true });
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Generate a unique checkpoint ID
|
|
58
|
+
*
|
|
59
|
+
* @returns {string} Unique checkpoint ID
|
|
60
|
+
*/
|
|
61
|
+
function generateCheckpointId() {
|
|
62
|
+
return `ckpt-${crypto.randomUUID().slice(0, 8)}`;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Get the current HEAD SHA from a git directory
|
|
66
|
+
* Falls back to placeholder if git operations fail
|
|
67
|
+
*
|
|
68
|
+
* @param {string} dir - Directory to get HEAD SHA from
|
|
69
|
+
* @returns {string} HEAD SHA or placeholder
|
|
70
|
+
*/
|
|
71
|
+
function getHeadSha(dir) {
|
|
72
|
+
try {
|
|
73
|
+
// Try to read .git/HEAD directly for speed
|
|
74
|
+
const gitDir = path.join(dir, '.git');
|
|
75
|
+
if (existsSync(gitDir)) {
|
|
76
|
+
const headPath = path.join(gitDir, 'HEAD');
|
|
77
|
+
if (existsSync(headPath)) {
|
|
78
|
+
const headContent = readFileSync(headPath, 'utf8').trim();
|
|
79
|
+
// If it's a ref, read the ref file
|
|
80
|
+
if (headContent.startsWith('ref: ')) {
|
|
81
|
+
const refPath = path.join(gitDir, headContent.slice(5));
|
|
82
|
+
if (existsSync(refPath)) {
|
|
83
|
+
return readFileSync(refPath, 'utf8').trim();
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// It's a direct SHA
|
|
87
|
+
return headContent;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// For worktrees, .git is a file pointing to the main repo
|
|
91
|
+
const gitFile = path.join(dir, '.git');
|
|
92
|
+
if (existsSync(gitFile)) {
|
|
93
|
+
const gitFileContent = readFileSync(gitFile, 'utf8').trim();
|
|
94
|
+
if (gitFileContent.startsWith('gitdir: ')) {
|
|
95
|
+
const worktreeGitDir = gitFileContent.slice(8);
|
|
96
|
+
const headPath = path.join(worktreeGitDir, 'HEAD');
|
|
97
|
+
if (existsSync(headPath)) {
|
|
98
|
+
const headContent = readFileSync(headPath, 'utf8').trim();
|
|
99
|
+
if (headContent.startsWith('ref: ')) {
|
|
100
|
+
// Need to resolve from main repo's refs
|
|
101
|
+
const mainGitDir = path.resolve(worktreeGitDir, '..', '..');
|
|
102
|
+
const refPath = path.join(mainGitDir, headContent.slice(5));
|
|
103
|
+
if (existsSync(refPath)) {
|
|
104
|
+
return readFileSync(refPath, 'utf8').trim();
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return headContent;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return 'unknown-sha';
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
return 'unknown-sha';
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Create a checkpoint before running gates
|
|
119
|
+
*
|
|
120
|
+
* @param {Object} params - Checkpoint parameters
|
|
121
|
+
* @param {string} params.wuId - WU ID
|
|
122
|
+
* @param {string} params.worktreePath - Path to worktree
|
|
123
|
+
* @param {string} params.branchName - Lane branch name
|
|
124
|
+
* @param {CreatePreGatesCheckpointOptions} [options]
|
|
125
|
+
* @returns {Promise<Checkpoint>} Created checkpoint
|
|
126
|
+
*/
|
|
127
|
+
export async function createPreGatesCheckpoint(params, options = {}) {
|
|
128
|
+
const { wuId, worktreePath, branchName, gatesPassed = false } = params;
|
|
129
|
+
const { baseDir } = options;
|
|
130
|
+
ensureCheckpointDir({ baseDir });
|
|
131
|
+
const checkpoint = {
|
|
132
|
+
schemaVersion: CHECKPOINT_SCHEMA_VERSION,
|
|
133
|
+
checkpointId: generateCheckpointId(),
|
|
134
|
+
wuId,
|
|
135
|
+
worktreePath,
|
|
136
|
+
branchName,
|
|
137
|
+
worktreeHeadSha: getHeadSha(worktreePath),
|
|
138
|
+
createdAt: new Date().toISOString(),
|
|
139
|
+
gatesPassed,
|
|
140
|
+
gatesPassedAt: gatesPassed ? new Date().toISOString() : null,
|
|
141
|
+
};
|
|
142
|
+
const checkpointPath = getCheckpointPath(wuId, { baseDir });
|
|
143
|
+
writeFileSync(checkpointPath, JSON.stringify(checkpoint, null, 2));
|
|
144
|
+
console.log(`${LOG_PREFIX.DONE} ${EMOJI.SUCCESS} Created pre-gates checkpoint for ${wuId}`);
|
|
145
|
+
return checkpoint;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Mark a checkpoint as having passed gates
|
|
149
|
+
*
|
|
150
|
+
* @param {string} wuId - WU ID
|
|
151
|
+
* @param {CheckpointBaseDirOptions} [options]
|
|
152
|
+
* @returns {boolean} True if checkpoint was updated
|
|
153
|
+
*/
|
|
154
|
+
export function markGatesPassed(wuId, options = {}) {
|
|
155
|
+
const checkpoint = getCheckpoint(wuId, options);
|
|
156
|
+
if (!checkpoint) {
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
checkpoint.gatesPassed = true;
|
|
160
|
+
checkpoint.gatesPassedAt = new Date().toISOString();
|
|
161
|
+
const checkpointPath = getCheckpointPath(wuId, options);
|
|
162
|
+
writeFileSync(checkpointPath, JSON.stringify(checkpoint, null, 2));
|
|
163
|
+
console.log(`${LOG_PREFIX.DONE} ${EMOJI.SUCCESS} Marked gates passed for ${wuId}`);
|
|
164
|
+
return true;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Get a checkpoint for a WU
|
|
168
|
+
*
|
|
169
|
+
* @param {string} wuId - WU ID
|
|
170
|
+
* @param {CheckpointBaseDirOptions} [options]
|
|
171
|
+
* @returns {Checkpoint|null} Checkpoint or null if not found
|
|
172
|
+
*/
|
|
173
|
+
export function getCheckpoint(wuId, options = {}) {
|
|
174
|
+
const checkpointPath = getCheckpointPath(wuId, options);
|
|
175
|
+
if (!existsSync(checkpointPath)) {
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
try {
|
|
179
|
+
const content = readFileSync(checkpointPath, 'utf8');
|
|
180
|
+
return JSON.parse(content);
|
|
181
|
+
}
|
|
182
|
+
catch {
|
|
183
|
+
// Corrupted checkpoint - treat as non-existent
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Clear a checkpoint for a WU
|
|
189
|
+
*
|
|
190
|
+
* @param {string} wuId - WU ID
|
|
191
|
+
* @param {CheckpointBaseDirOptions} [options]
|
|
192
|
+
*/
|
|
193
|
+
export function clearCheckpoint(wuId, options = {}) {
|
|
194
|
+
const checkpointPath = getCheckpointPath(wuId, options);
|
|
195
|
+
if (existsSync(checkpointPath)) {
|
|
196
|
+
unlinkSync(checkpointPath);
|
|
197
|
+
console.log(`${LOG_PREFIX.DONE} ${EMOJI.SUCCESS} Cleared checkpoint for ${wuId}`);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
export function canSkipGates(wuId, options = {}) {
|
|
201
|
+
const { baseDir, currentHeadSha } = options;
|
|
202
|
+
const checkpoint = getCheckpoint(wuId, { baseDir });
|
|
203
|
+
// No checkpoint exists
|
|
204
|
+
if (!checkpoint) {
|
|
205
|
+
return { canSkip: false, reason: 'No checkpoint exists' };
|
|
206
|
+
}
|
|
207
|
+
// Schema version mismatch
|
|
208
|
+
if (checkpoint.schemaVersion !== CHECKPOINT_SCHEMA_VERSION) {
|
|
209
|
+
return {
|
|
210
|
+
canSkip: false,
|
|
211
|
+
reason: `Checkpoint schema version mismatch (got ${checkpoint.schemaVersion}, expected ${CHECKPOINT_SCHEMA_VERSION})`,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
// Gates didn't pass at checkpoint
|
|
215
|
+
if (!checkpoint.gatesPassed) {
|
|
216
|
+
return { canSkip: false, reason: 'Gates did not pass at checkpoint' };
|
|
217
|
+
}
|
|
218
|
+
// Check if checkpoint is stale
|
|
219
|
+
const checkpointAge = Date.now() - new Date(checkpoint.createdAt).getTime();
|
|
220
|
+
if (checkpointAge > CHECKPOINT_MAX_AGE_MS) {
|
|
221
|
+
return { canSkip: false, reason: 'Checkpoint is stale (older than 24 hours)' };
|
|
222
|
+
}
|
|
223
|
+
// SHA has changed since checkpoint
|
|
224
|
+
if (currentHeadSha && currentHeadSha !== checkpoint.worktreeHeadSha) {
|
|
225
|
+
return {
|
|
226
|
+
canSkip: false,
|
|
227
|
+
reason: 'Worktree has changed since checkpoint (SHA mismatch)',
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
// All checks passed - gates can be skipped
|
|
231
|
+
console.log(`${LOG_PREFIX.DONE} ${EMOJI.SUCCESS} Gates can be skipped - checkpoint valid (${checkpoint.checkpointId})`);
|
|
232
|
+
return { canSkip: true, checkpoint };
|
|
233
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file wu-claim-helpers.mjs
|
|
3
|
+
* Helper functions for wu:claim (WU-1423)
|
|
4
|
+
*
|
|
5
|
+
* Extracted email validation logic for testability and SOLID compliance.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Validates if a string is a valid email address.
|
|
9
|
+
*
|
|
10
|
+
* @param {string} value - The string to validate
|
|
11
|
+
* @returns {boolean} True if valid email, false otherwise
|
|
12
|
+
*/
|
|
13
|
+
export declare function isValidEmail(value: any): boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Gets a valid email address for WU assignment.
|
|
16
|
+
*
|
|
17
|
+
* Fallback chain (WU-1423):
|
|
18
|
+
* 1. git config user.email
|
|
19
|
+
* 2. GIT_AUTHOR_EMAIL environment variable
|
|
20
|
+
* 3. Error (no silent fallback to username)
|
|
21
|
+
*
|
|
22
|
+
* @param {object} gitAdapter - Git adapter with getConfigValue method
|
|
23
|
+
* @returns {Promise<string>} Valid email address
|
|
24
|
+
* @throws {Error} If no valid email can be determined
|
|
25
|
+
*/
|
|
26
|
+
export declare function getAssignedEmail(gitAdapter: any): Promise<any>;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file wu-claim-helpers.mjs
|
|
3
|
+
* Helper functions for wu:claim (WU-1423)
|
|
4
|
+
*
|
|
5
|
+
* Extracted email validation logic for testability and SOLID compliance.
|
|
6
|
+
*/
|
|
7
|
+
import { z } from 'zod';
|
|
8
|
+
/**
|
|
9
|
+
* Zod schema for validating email addresses.
|
|
10
|
+
* Uses Zod's built-in email validation (library-first, no regex).
|
|
11
|
+
*/
|
|
12
|
+
const emailSchema = z.string().email();
|
|
13
|
+
/**
|
|
14
|
+
* Validates if a string is a valid email address.
|
|
15
|
+
*
|
|
16
|
+
* @param {string} value - The string to validate
|
|
17
|
+
* @returns {boolean} True if valid email, false otherwise
|
|
18
|
+
*/
|
|
19
|
+
export function isValidEmail(value) {
|
|
20
|
+
if (!value || typeof value !== 'string') {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
return emailSchema.safeParse(value).success;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Gets a valid email address for WU assignment.
|
|
27
|
+
*
|
|
28
|
+
* Fallback chain (WU-1423):
|
|
29
|
+
* 1. git config user.email
|
|
30
|
+
* 2. GIT_AUTHOR_EMAIL environment variable
|
|
31
|
+
* 3. Error (no silent fallback to username)
|
|
32
|
+
*
|
|
33
|
+
* @param {object} gitAdapter - Git adapter with getConfigValue method
|
|
34
|
+
* @returns {Promise<string>} Valid email address
|
|
35
|
+
* @throws {Error} If no valid email can be determined
|
|
36
|
+
*/
|
|
37
|
+
export async function getAssignedEmail(gitAdapter) {
|
|
38
|
+
// Try git config user.email first (WU-1427: properly await async method)
|
|
39
|
+
try {
|
|
40
|
+
const gitEmail = await gitAdapter.getConfigValue('user.email');
|
|
41
|
+
const trimmed = gitEmail?.trim();
|
|
42
|
+
if (trimmed && isValidEmail(trimmed)) {
|
|
43
|
+
return trimmed;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
// Git config not available, continue to fallback
|
|
48
|
+
}
|
|
49
|
+
// Fallback to GIT_AUTHOR_EMAIL (commonly set in CI/scripting)
|
|
50
|
+
const authorEmail = process.env.GIT_AUTHOR_EMAIL?.trim();
|
|
51
|
+
if (authorEmail && isValidEmail(authorEmail)) {
|
|
52
|
+
return authorEmail;
|
|
53
|
+
}
|
|
54
|
+
// WU-1423: NO silent fallback to username (GIT_USER, USER)
|
|
55
|
+
// These are usernames, not email addresses, and would cause wu:done validation failures
|
|
56
|
+
throw new Error('Cannot determine assigned_to email address.\n\n' +
|
|
57
|
+
'Checked:\n' +
|
|
58
|
+
' 1. git config user.email - not set or invalid\n' +
|
|
59
|
+
' 2. GIT_AUTHOR_EMAIL env var - not set or invalid\n\n' +
|
|
60
|
+
'Fix:\n' +
|
|
61
|
+
' git config --global user.email "you@example.com"\n' +
|
|
62
|
+
' OR export GIT_AUTHOR_EMAIL="you@example.com"');
|
|
63
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
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
|
+
/**
|
|
17
|
+
* @typedef {Object} ResumeResult
|
|
18
|
+
* @property {boolean} success - Whether the resume operation succeeded
|
|
19
|
+
* @property {boolean} handoff - Whether this was a handoff (vs normal claim)
|
|
20
|
+
* @property {number|null} previousPid - PID of the previous lock holder
|
|
21
|
+
* @property {string|null} previousSession - Session ID of the previous lock holder
|
|
22
|
+
* @property {string|null} error - Error message if operation failed
|
|
23
|
+
* @property {string|null} uncommittedSummary - Summary of uncommitted changes in worktree
|
|
24
|
+
*/
|
|
25
|
+
/**
|
|
26
|
+
* Check if a process is running by sending signal 0.
|
|
27
|
+
* This doesn't actually send a signal, but checks if the process exists.
|
|
28
|
+
*
|
|
29
|
+
* @param {number} pid - Process ID to check
|
|
30
|
+
* @returns {boolean} True if process is running, false if not
|
|
31
|
+
*/
|
|
32
|
+
export declare function isProcessRunning(pid: any): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Resume a WU claim from a crashed/killed agent (handoff).
|
|
35
|
+
*
|
|
36
|
+
* This function:
|
|
37
|
+
* 1. Verifies the worktree exists
|
|
38
|
+
* 2. Reads the existing lock file
|
|
39
|
+
* 3. Verifies the old PID is dead (safety check)
|
|
40
|
+
* 4. Updates the lock file with the new PID
|
|
41
|
+
*
|
|
42
|
+
* @param {Object} options - Resume options
|
|
43
|
+
* @param {string} options.wuId - WU ID (e.g., "WU-2411")
|
|
44
|
+
* @param {string} options.lane - Lane name (e.g., "Operations: Tooling")
|
|
45
|
+
* @param {string} options.worktreePath - Path to the existing worktree
|
|
46
|
+
* @param {string} [options.baseDir] - Base directory for lock files (defaults to project root)
|
|
47
|
+
* @param {string} [options.agentSession] - New agent session ID
|
|
48
|
+
* @returns {Promise<ResumeResult>} Result of the resume operation
|
|
49
|
+
*/
|
|
50
|
+
export declare function resumeClaimForHandoff(options: any): Promise<{
|
|
51
|
+
success: boolean;
|
|
52
|
+
handoff: boolean;
|
|
53
|
+
previousPid: number;
|
|
54
|
+
previousSession: string;
|
|
55
|
+
error: string;
|
|
56
|
+
uncommittedSummary: any;
|
|
57
|
+
}>;
|
|
58
|
+
/**
|
|
59
|
+
* Get a summary of uncommitted changes in a worktree.
|
|
60
|
+
*
|
|
61
|
+
* @param {Object} gitAdapter - Git adapter with getStatus method
|
|
62
|
+
* @returns {Promise<string|null>} Summary of uncommitted changes, or null if clean
|
|
63
|
+
*/
|
|
64
|
+
export declare function getWorktreeUncommittedChanges(gitAdapter: any): Promise<any>;
|
|
65
|
+
/**
|
|
66
|
+
* Format uncommitted changes for display.
|
|
67
|
+
*
|
|
68
|
+
* @param {string} status - Raw git status output
|
|
69
|
+
* @returns {string} Formatted summary for display
|
|
70
|
+
*/
|
|
71
|
+
export declare function formatUncommittedChanges(status: any): string;
|
|
72
|
+
/**
|
|
73
|
+
* Create a checkpoint in the memory layer documenting the handoff.
|
|
74
|
+
*
|
|
75
|
+
* @param {Object} options - Checkpoint options
|
|
76
|
+
* @param {string} options.wuId - WU ID
|
|
77
|
+
* @param {number} options.previousPid - Previous owner's PID
|
|
78
|
+
* @param {number} options.newPid - New owner's PID
|
|
79
|
+
* @param {string|null} options.previousSession - Previous owner's session ID
|
|
80
|
+
* @param {string|null} options.uncommittedSummary - Summary of uncommitted changes
|
|
81
|
+
* @param {Object} [options.memoryLayer] - Memory layer interface (for testing)
|
|
82
|
+
* @returns {Promise<{success: boolean, checkpointId?: string, error?: string}>}
|
|
83
|
+
*/
|
|
84
|
+
export declare function createHandoffCheckpoint(options: any): Promise<{
|
|
85
|
+
success: boolean;
|
|
86
|
+
checkpointId: any;
|
|
87
|
+
error?: undefined;
|
|
88
|
+
} | {
|
|
89
|
+
success: boolean;
|
|
90
|
+
error: any;
|
|
91
|
+
checkpointId?: undefined;
|
|
92
|
+
}>;
|
|
93
|
+
/**
|
|
94
|
+
* Check if a worktree exists and is valid for resumption.
|
|
95
|
+
*
|
|
96
|
+
* @param {string} worktreePath - Path to check
|
|
97
|
+
* @param {string} _expectedBranch - Expected branch name (unused, for future validation)
|
|
98
|
+
* @returns {{valid: boolean, error?: string}}
|
|
99
|
+
*/
|
|
100
|
+
export declare function validateWorktreeForResume(worktreePath: any, _expectedBranch: any): {
|
|
101
|
+
valid: boolean;
|
|
102
|
+
error: string;
|
|
103
|
+
} | {
|
|
104
|
+
valid: boolean;
|
|
105
|
+
error?: undefined;
|
|
106
|
+
};
|