ai-sdlc 0.2.0-alpha.6 → 0.2.0-beta.1
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 +53 -1058
- package/dist/agents/implementation.d.ts +6 -0
- package/dist/agents/implementation.d.ts.map +1 -1
- package/dist/agents/implementation.js +87 -13
- package/dist/agents/implementation.js.map +1 -1
- package/dist/agents/planning.d.ts.map +1 -1
- package/dist/agents/planning.js +22 -3
- package/dist/agents/planning.js.map +1 -1
- package/dist/agents/refinement.d.ts.map +1 -1
- package/dist/agents/refinement.js +22 -3
- package/dist/agents/refinement.js.map +1 -1
- package/dist/agents/research.d.ts +85 -1
- package/dist/agents/research.d.ts.map +1 -1
- package/dist/agents/research.js +506 -16
- package/dist/agents/research.js.map +1 -1
- package/dist/agents/review.d.ts +67 -2
- package/dist/agents/review.d.ts.map +1 -1
- package/dist/agents/review.js +477 -68
- package/dist/agents/review.js.map +1 -1
- package/dist/agents/rework.d.ts.map +1 -1
- package/dist/agents/rework.js +22 -3
- package/dist/agents/rework.js.map +1 -1
- package/dist/agents/state-assessor.d.ts +3 -3
- package/dist/agents/state-assessor.d.ts.map +1 -1
- package/dist/agents/state-assessor.js +6 -6
- package/dist/agents/state-assessor.js.map +1 -1
- package/dist/agents/test-pattern-detector.d.ts +49 -0
- package/dist/agents/test-pattern-detector.d.ts.map +1 -0
- package/dist/agents/test-pattern-detector.js +273 -0
- package/dist/agents/test-pattern-detector.js.map +1 -0
- package/dist/agents/verification.d.ts +11 -0
- package/dist/agents/verification.d.ts.map +1 -1
- package/dist/agents/verification.js +74 -1
- package/dist/agents/verification.js.map +1 -1
- package/dist/cli/commands/migrate.js +1 -1
- package/dist/cli/commands/migrate.js.map +1 -1
- package/dist/cli/commands.d.ts +59 -3
- package/dist/cli/commands.d.ts.map +1 -1
- package/dist/cli/commands.js +1042 -204
- package/dist/cli/commands.js.map +1 -1
- package/dist/cli/daemon.d.ts.map +1 -1
- package/dist/cli/daemon.js +20 -3
- package/dist/cli/daemon.js.map +1 -1
- package/dist/cli/runner.d.ts.map +1 -1
- package/dist/cli/runner.js +18 -6
- package/dist/cli/runner.js.map +1 -1
- package/dist/core/auth.d.ts +43 -0
- package/dist/core/auth.d.ts.map +1 -1
- package/dist/core/auth.js +105 -1
- package/dist/core/auth.js.map +1 -1
- package/dist/core/client.d.ts +6 -0
- package/dist/core/client.d.ts.map +1 -1
- package/dist/core/client.js +57 -3
- package/dist/core/client.js.map +1 -1
- package/dist/core/config.d.ts +24 -1
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +95 -1
- package/dist/core/config.js.map +1 -1
- package/dist/core/conflict-detector.d.ts +108 -0
- package/dist/core/conflict-detector.d.ts.map +1 -0
- package/dist/core/conflict-detector.js +413 -0
- package/dist/core/conflict-detector.js.map +1 -0
- package/dist/core/git-utils.d.ts +28 -0
- package/dist/core/git-utils.d.ts.map +1 -0
- package/dist/core/git-utils.js +146 -0
- package/dist/core/git-utils.js.map +1 -0
- package/dist/core/index.d.ts +17 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +17 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/kanban.d.ts +1 -1
- package/dist/core/kanban.d.ts.map +1 -1
- package/dist/core/kanban.js +3 -3
- package/dist/core/kanban.js.map +1 -1
- package/dist/core/logger.d.ts +92 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/logger.js +221 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/story-logger.d.ts +102 -0
- package/dist/core/story-logger.d.ts.map +1 -0
- package/dist/core/story-logger.js +265 -0
- package/dist/core/story-logger.js.map +1 -0
- package/dist/core/story.d.ts +79 -20
- package/dist/core/story.d.ts.map +1 -1
- package/dist/core/story.js +221 -39
- package/dist/core/story.js.map +1 -1
- package/dist/core/workflow-state.d.ts +45 -6
- package/dist/core/workflow-state.d.ts.map +1 -1
- package/dist/core/workflow-state.js +201 -12
- package/dist/core/workflow-state.js.map +1 -1
- package/dist/core/worktree.d.ts +77 -0
- package/dist/core/worktree.d.ts.map +1 -0
- package/dist/core/worktree.js +246 -0
- package/dist/core/worktree.js.map +1 -0
- package/dist/index.js +135 -5
- package/dist/index.js.map +1 -1
- package/dist/types/index.d.ts +151 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +1 -0
- package/dist/types/index.js.map +1 -1
- package/package.json +3 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workflow-state.d.ts","sourceRoot":"","sources":["../../src/core/workflow-state.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,EACL,sBAAsB,EACtB,6BAA6B,EAE9B,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"workflow-state.d.ts","sourceRoot":"","sources":["../../src/core/workflow-state.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,EACL,sBAAsB,EACtB,6BAA6B,EAE9B,MAAM,4BAA4B,CAAC;AAQpC;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAM3E;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAI3C;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAQ5D;AAED;;;;;;;;GAQG;AACH,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,sBAAsB,EAC7B,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CAkCf;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,sBAAsB,GAAG,IAAI,CAAC,CAuCxC;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,GAAG,GAAG,6BAA6B,CAyC/E;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAW1F;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAG5E;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,0BAA0B,CAC9C,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;IAAE,QAAQ,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CA0IjD"}
|
|
@@ -8,12 +8,26 @@ import fs from 'fs';
|
|
|
8
8
|
import path from 'path';
|
|
9
9
|
import crypto from 'crypto';
|
|
10
10
|
import writeFileAtomic from 'write-file-atomic';
|
|
11
|
+
import { STORIES_FOLDER } from '../types/index.js';
|
|
12
|
+
import { sanitizeStoryId } from './story.js';
|
|
13
|
+
import { getLogger } from './logger.js';
|
|
11
14
|
const STATE_FILE_NAME = '.workflow-state.json';
|
|
12
15
|
const CURRENT_VERSION = '1.0';
|
|
13
16
|
/**
|
|
14
|
-
* Get the path to the workflow state file
|
|
17
|
+
* Get the path to the workflow state file.
|
|
18
|
+
*
|
|
19
|
+
* SECURITY: storyId is sanitized using sanitizeStoryId() to prevent path traversal attacks.
|
|
20
|
+
* Never construct paths manually - always use this function to ensure proper sanitization.
|
|
21
|
+
*
|
|
22
|
+
* @param sdlcRoot - Path to the .ai-sdlc directory
|
|
23
|
+
* @param storyId - Optional story ID for per-story state isolation
|
|
24
|
+
* @returns Path to the workflow state file (story-specific or global)
|
|
15
25
|
*/
|
|
16
|
-
export function getStateFilePath(sdlcRoot) {
|
|
26
|
+
export function getStateFilePath(sdlcRoot, storyId) {
|
|
27
|
+
if (storyId) {
|
|
28
|
+
const sanitized = sanitizeStoryId(storyId);
|
|
29
|
+
return path.join(sdlcRoot, STORIES_FOLDER, sanitized, STATE_FILE_NAME);
|
|
30
|
+
}
|
|
17
31
|
return path.join(sdlcRoot, STATE_FILE_NAME);
|
|
18
32
|
}
|
|
19
33
|
/**
|
|
@@ -44,17 +58,33 @@ export function calculateStoryHash(storyPath) {
|
|
|
44
58
|
*
|
|
45
59
|
* @param state - The workflow execution state to save
|
|
46
60
|
* @param sdlcRoot - Path to the .ai-sdlc directory
|
|
61
|
+
* @param storyId - Optional story ID for per-story state isolation
|
|
47
62
|
*/
|
|
48
|
-
export async function saveWorkflowState(state, sdlcRoot) {
|
|
49
|
-
const
|
|
63
|
+
export async function saveWorkflowState(state, sdlcRoot, storyId) {
|
|
64
|
+
const logger = getLogger();
|
|
65
|
+
const statePath = getStateFilePath(sdlcRoot, storyId);
|
|
50
66
|
const stateJson = JSON.stringify(state, null, 2);
|
|
67
|
+
logger.debug('workflow-state', 'Saving workflow state', {
|
|
68
|
+
workflowId: state.workflowId,
|
|
69
|
+
storyId,
|
|
70
|
+
actionCount: state.completedActions.length,
|
|
71
|
+
});
|
|
51
72
|
try {
|
|
52
|
-
// Ensure the directory exists
|
|
53
|
-
|
|
73
|
+
// Ensure the directory exists (including story subdirectories)
|
|
74
|
+
const stateDir = path.dirname(statePath);
|
|
75
|
+
await fs.promises.mkdir(stateDir, { recursive: true });
|
|
54
76
|
// Write atomically to prevent corruption
|
|
55
77
|
await writeFileAtomic(statePath, stateJson, { encoding: 'utf-8' });
|
|
56
78
|
}
|
|
57
79
|
catch (error) {
|
|
80
|
+
// Specific permission error handling
|
|
81
|
+
if (error && typeof error === 'object' && 'code' in error) {
|
|
82
|
+
const code = error.code;
|
|
83
|
+
if (code === 'EACCES' || code === 'EPERM') {
|
|
84
|
+
throw new Error(`Permission denied: Cannot write workflow state to ${statePath}. ` +
|
|
85
|
+
`Check file permissions for the directory and ensure it is writable.`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
58
88
|
throw new Error(`Failed to save workflow state: ${error instanceof Error ? error.message : String(error)}`);
|
|
59
89
|
}
|
|
60
90
|
}
|
|
@@ -62,13 +92,16 @@ export async function saveWorkflowState(state, sdlcRoot) {
|
|
|
62
92
|
* Load workflow state from disk
|
|
63
93
|
*
|
|
64
94
|
* @param sdlcRoot - Path to the .ai-sdlc directory
|
|
95
|
+
* @param storyId - Optional story ID for per-story state isolation
|
|
65
96
|
* @returns The workflow state, or null if no state file exists
|
|
66
97
|
*/
|
|
67
|
-
export async function loadWorkflowState(sdlcRoot) {
|
|
68
|
-
const
|
|
98
|
+
export async function loadWorkflowState(sdlcRoot, storyId) {
|
|
99
|
+
const logger = getLogger();
|
|
100
|
+
const statePath = getStateFilePath(sdlcRoot, storyId);
|
|
69
101
|
try {
|
|
70
102
|
// Check if file exists
|
|
71
103
|
if (!fs.existsSync(statePath)) {
|
|
104
|
+
logger.debug('workflow-state', 'No workflow state found', { storyId });
|
|
72
105
|
return null;
|
|
73
106
|
}
|
|
74
107
|
// Read and parse the state file
|
|
@@ -79,10 +112,17 @@ export async function loadWorkflowState(sdlcRoot) {
|
|
|
79
112
|
if (!validation.valid) {
|
|
80
113
|
throw new Error(`Invalid state file: ${validation.errors.join(', ')}`);
|
|
81
114
|
}
|
|
115
|
+
logger.debug('workflow-state', 'Loaded workflow state', {
|
|
116
|
+
workflowId: state.workflowId,
|
|
117
|
+
storyId,
|
|
118
|
+
actionCount: state.completedActions.length,
|
|
119
|
+
ageMs: Date.now() - new Date(state.timestamp).getTime(),
|
|
120
|
+
});
|
|
82
121
|
return state;
|
|
83
122
|
}
|
|
84
123
|
catch (error) {
|
|
85
124
|
if (error instanceof SyntaxError) {
|
|
125
|
+
logger.error('workflow-state', 'Corrupted state file', { statePath });
|
|
86
126
|
throw new Error(`Corrupted workflow state file at ${statePath}. ` +
|
|
87
127
|
`Delete the file to start fresh: rm "${statePath}"`);
|
|
88
128
|
}
|
|
@@ -136,9 +176,10 @@ export function validateWorkflowState(state) {
|
|
|
136
176
|
* Clear workflow state (delete the state file)
|
|
137
177
|
*
|
|
138
178
|
* @param sdlcRoot - Path to the .ai-sdlc directory
|
|
179
|
+
* @param storyId - Optional story ID for per-story state isolation
|
|
139
180
|
*/
|
|
140
|
-
export async function clearWorkflowState(sdlcRoot) {
|
|
141
|
-
const statePath = getStateFilePath(sdlcRoot);
|
|
181
|
+
export async function clearWorkflowState(sdlcRoot, storyId) {
|
|
182
|
+
const statePath = getStateFilePath(sdlcRoot, storyId);
|
|
142
183
|
try {
|
|
143
184
|
if (fs.existsSync(statePath)) {
|
|
144
185
|
await fs.promises.unlink(statePath);
|
|
@@ -153,10 +194,158 @@ export async function clearWorkflowState(sdlcRoot) {
|
|
|
153
194
|
* Check if workflow state exists
|
|
154
195
|
*
|
|
155
196
|
* @param sdlcRoot - Path to the .ai-sdlc directory
|
|
197
|
+
* @param storyId - Optional story ID for per-story state isolation
|
|
156
198
|
* @returns True if state file exists
|
|
157
199
|
*/
|
|
158
|
-
export function hasWorkflowState(sdlcRoot) {
|
|
159
|
-
const statePath = getStateFilePath(sdlcRoot);
|
|
200
|
+
export function hasWorkflowState(sdlcRoot, storyId) {
|
|
201
|
+
const statePath = getStateFilePath(sdlcRoot, storyId);
|
|
160
202
|
return fs.existsSync(statePath);
|
|
161
203
|
}
|
|
204
|
+
/**
|
|
205
|
+
* Migrate global workflow state to story-specific location.
|
|
206
|
+
*
|
|
207
|
+
* Call this function at CLI startup (before loading workflow state) to automatically
|
|
208
|
+
* move legacy global state files to the new per-story location.
|
|
209
|
+
*
|
|
210
|
+
* Migration behavior:
|
|
211
|
+
* - Extracts story ID from context.options.story, completedActions, or currentAction
|
|
212
|
+
* - Skips migration if workflow is currently in progress (currentAction set)
|
|
213
|
+
* - Skips migration if no story ID can be determined
|
|
214
|
+
* - Validates target file if it already exists before deleting global file
|
|
215
|
+
* - Deletes global file only after successful write to target location
|
|
216
|
+
*
|
|
217
|
+
* @param sdlcRoot - Path to the .ai-sdlc directory
|
|
218
|
+
* @returns Promise resolving to migration result object:
|
|
219
|
+
* - migrated: boolean - true if migration was performed, false if skipped
|
|
220
|
+
* - message: string - Human-readable description of what happened
|
|
221
|
+
*
|
|
222
|
+
* @example
|
|
223
|
+
* const result = await migrateGlobalWorkflowState(sdlcRoot);
|
|
224
|
+
* if (result.migrated) {
|
|
225
|
+
* console.log(result.message); // "Successfully migrated workflow state to story S-0033"
|
|
226
|
+
* }
|
|
227
|
+
*/
|
|
228
|
+
export async function migrateGlobalWorkflowState(sdlcRoot) {
|
|
229
|
+
const globalStatePath = getStateFilePath(sdlcRoot);
|
|
230
|
+
// Check if global state file exists
|
|
231
|
+
if (!fs.existsSync(globalStatePath)) {
|
|
232
|
+
return { migrated: false, message: 'No global workflow state file found' };
|
|
233
|
+
}
|
|
234
|
+
try {
|
|
235
|
+
// Read and parse the global state
|
|
236
|
+
const content = await fs.promises.readFile(globalStatePath, 'utf-8');
|
|
237
|
+
const state = JSON.parse(content);
|
|
238
|
+
// Check if workflow in progress IMMEDIATELY after reading state
|
|
239
|
+
if (state.currentAction) {
|
|
240
|
+
return {
|
|
241
|
+
migrated: false,
|
|
242
|
+
message: 'Skipping migration: workflow currently in progress. Complete or reset workflow before migrating.',
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
// Determine the story ID from the state
|
|
246
|
+
let storyId;
|
|
247
|
+
// Try to get story ID from context.options.story first
|
|
248
|
+
if (state.context?.options?.story) {
|
|
249
|
+
storyId = state.context.options.story;
|
|
250
|
+
}
|
|
251
|
+
// Fallback to first completed action's storyId
|
|
252
|
+
if (!storyId && state.completedActions && state.completedActions.length > 0) {
|
|
253
|
+
const firstAction = state.completedActions[0];
|
|
254
|
+
if (firstAction && 'storyId' in firstAction) {
|
|
255
|
+
storyId = firstAction.storyId;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
// If no story ID found, leave state in place
|
|
259
|
+
if (!storyId) {
|
|
260
|
+
return {
|
|
261
|
+
migrated: false,
|
|
262
|
+
message: 'Cannot migrate: no story ID found in workflow state. Manual migration required.',
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
// SECURITY: Sanitize story ID to prevent path traversal
|
|
266
|
+
let sanitizedStoryId;
|
|
267
|
+
try {
|
|
268
|
+
sanitizedStoryId = sanitizeStoryId(storyId);
|
|
269
|
+
}
|
|
270
|
+
catch (error) {
|
|
271
|
+
return {
|
|
272
|
+
migrated: false,
|
|
273
|
+
message: `Cannot migrate: invalid story ID "${storyId}". ${error instanceof Error ? error.message : String(error)}`,
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
// Check if target location already exists (idempotent)
|
|
277
|
+
const targetPath = getStateFilePath(sdlcRoot, sanitizedStoryId);
|
|
278
|
+
if (fs.existsSync(targetPath)) {
|
|
279
|
+
// Validate existing target is not corrupt before deleting global backup
|
|
280
|
+
try {
|
|
281
|
+
const targetContent = await fs.promises.readFile(targetPath, 'utf-8');
|
|
282
|
+
const targetState = JSON.parse(targetContent);
|
|
283
|
+
const validation = validateWorkflowState(targetState);
|
|
284
|
+
if (!validation.valid) {
|
|
285
|
+
return {
|
|
286
|
+
migrated: false,
|
|
287
|
+
message: `Target state file exists but is invalid. Keeping global file as backup. Manual intervention required. Errors: ${validation.errors.join(', ')}`,
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
// Target is valid, safe to delete global
|
|
291
|
+
await fs.promises.unlink(globalStatePath);
|
|
292
|
+
return {
|
|
293
|
+
migrated: true,
|
|
294
|
+
message: `Global workflow state already migrated to story ${sanitizedStoryId}. Removed duplicate global file.`,
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
catch (error) {
|
|
298
|
+
return {
|
|
299
|
+
migrated: false,
|
|
300
|
+
message: `Target state file exists but is corrupted. Keeping global file as backup. Manual intervention required. Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
// Create target directory
|
|
305
|
+
const targetDir = path.dirname(targetPath);
|
|
306
|
+
await fs.promises.mkdir(targetDir, { recursive: true });
|
|
307
|
+
// Write to target location atomically
|
|
308
|
+
const stateJson = JSON.stringify(state, null, 2);
|
|
309
|
+
await writeFileAtomic(targetPath, stateJson, { encoding: 'utf-8' });
|
|
310
|
+
// Verify target file was created successfully
|
|
311
|
+
if (!fs.existsSync(targetPath)) {
|
|
312
|
+
throw new Error('Target state file was not created successfully');
|
|
313
|
+
}
|
|
314
|
+
// Delete global file only after successful write
|
|
315
|
+
await fs.promises.unlink(globalStatePath);
|
|
316
|
+
return {
|
|
317
|
+
migrated: true,
|
|
318
|
+
message: `Successfully migrated workflow state from global to story-specific location: ${sanitizedStoryId}`,
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
catch (error) {
|
|
322
|
+
// Specific error handling for common cases
|
|
323
|
+
if (error && typeof error === 'object' && 'code' in error) {
|
|
324
|
+
const code = error.code;
|
|
325
|
+
if (code === 'ENOENT') {
|
|
326
|
+
return {
|
|
327
|
+
migrated: false,
|
|
328
|
+
message: 'Global state file disappeared during migration. No action taken.',
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
if (code === 'EACCES' || code === 'EPERM') {
|
|
332
|
+
return {
|
|
333
|
+
migrated: false,
|
|
334
|
+
message: `Permission denied during migration. Check file permissions for: ${globalStatePath}`,
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
if (error instanceof SyntaxError) {
|
|
339
|
+
return {
|
|
340
|
+
migrated: false,
|
|
341
|
+
message: 'Global state file contains invalid JSON. Manual migration required.',
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
345
|
+
return {
|
|
346
|
+
migrated: false,
|
|
347
|
+
message: `Migration failed: ${errorMsg}`,
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
}
|
|
162
351
|
//# sourceMappingURL=workflow-state.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workflow-state.js","sourceRoot":"","sources":["../../src/core/workflow-state.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,eAAe,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"workflow-state.js","sourceRoot":"","sources":["../../src/core/workflow-state.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { WorktreeInfo } from '../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Options for creating a git worktree
|
|
4
|
+
*/
|
|
5
|
+
export interface WorktreeOptions {
|
|
6
|
+
storyId: string;
|
|
7
|
+
slug: string;
|
|
8
|
+
baseBranch?: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Result of worktree validation check
|
|
12
|
+
*/
|
|
13
|
+
export interface WorktreeValidationResult {
|
|
14
|
+
valid: boolean;
|
|
15
|
+
error?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Service for managing git worktrees for isolated story execution
|
|
19
|
+
*/
|
|
20
|
+
export declare class GitWorktreeService {
|
|
21
|
+
private projectRoot;
|
|
22
|
+
private worktreeBasePath;
|
|
23
|
+
constructor(projectRoot: string, worktreeBasePath: string);
|
|
24
|
+
/**
|
|
25
|
+
* Generate the worktree path for a story
|
|
26
|
+
* Format: {worktreeBasePath}/{storyId}-{slug}
|
|
27
|
+
*/
|
|
28
|
+
getWorktreePath(storyId: string, slug: string): string;
|
|
29
|
+
/**
|
|
30
|
+
* Generate the branch name for a worktree
|
|
31
|
+
* Format: ai-sdlc/{storyId}-{slug}
|
|
32
|
+
*/
|
|
33
|
+
getBranchName(storyId: string, slug: string): string;
|
|
34
|
+
/**
|
|
35
|
+
* Detect the base branch (main or master) for branching
|
|
36
|
+
* @returns The detected base branch name
|
|
37
|
+
* @throws Error if neither main nor master exists
|
|
38
|
+
*/
|
|
39
|
+
detectBaseBranch(): string;
|
|
40
|
+
/**
|
|
41
|
+
* Validate that a worktree can be created
|
|
42
|
+
* Checks for uncommitted changes in the working directory
|
|
43
|
+
* Note: Changes in .ai-sdlc/ directory are excluded since they're expected
|
|
44
|
+
* during normal workflow (story file updates, etc.)
|
|
45
|
+
*/
|
|
46
|
+
validateCanCreateWorktree(): WorktreeValidationResult;
|
|
47
|
+
/**
|
|
48
|
+
* Check if a worktree already exists at the given path
|
|
49
|
+
*/
|
|
50
|
+
exists(worktreePath: string): boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Create a new git worktree for isolated story execution
|
|
53
|
+
* @param options - Worktree creation options
|
|
54
|
+
* @returns The path to the created worktree
|
|
55
|
+
* @throws Error if worktree creation fails
|
|
56
|
+
*/
|
|
57
|
+
create(options: WorktreeOptions): string;
|
|
58
|
+
/**
|
|
59
|
+
* Install npm dependencies in a worktree
|
|
60
|
+
* Detects the package manager (npm/yarn/pnpm) and runs the appropriate install command
|
|
61
|
+
* @param worktreePath - Path to the worktree
|
|
62
|
+
* @throws Error if installation fails
|
|
63
|
+
*/
|
|
64
|
+
installDependencies(worktreePath: string): void;
|
|
65
|
+
/**
|
|
66
|
+
* List all ai-sdlc managed worktrees
|
|
67
|
+
* @returns Array of WorktreeInfo objects for worktrees in the basePath
|
|
68
|
+
*/
|
|
69
|
+
list(): WorktreeInfo[];
|
|
70
|
+
/**
|
|
71
|
+
* Remove a git worktree
|
|
72
|
+
* @param worktreePath - Absolute path to the worktree to remove
|
|
73
|
+
* @throws Error if removal fails
|
|
74
|
+
*/
|
|
75
|
+
remove(worktreePath: string): void;
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=worktree.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worktree.d.ts","sourceRoot":"","sources":["../../src/core/worktree.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAKjD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA4BD;;GAEG;AACH,qBAAa,kBAAkB;IAE3B,OAAO,CAAC,WAAW;IACnB,OAAO,CAAC,gBAAgB;gBADhB,WAAW,EAAE,MAAM,EACnB,gBAAgB,EAAE,MAAM;IAGlC;;;OAGG;IACH,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM;IAItD;;;OAGG;IACH,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM;IAIpD;;;;OAIG;IACH,gBAAgB,IAAI,MAAM;IA4B1B;;;;;OAKG;IACH,yBAAyB,IAAI,wBAAwB;IAerD;;OAEG;IACH,MAAM,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO;IAIrC;;;;;OAKG;IACH,MAAM,CAAC,OAAO,EAAE,eAAe,GAAG,MAAM;IA4CxC;;;;;OAKG;IACH,mBAAmB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI;IAgC/C;;;OAGG;IACH,IAAI,IAAI,YAAY,EAAE;IA8CtB;;;;OAIG;IACH,MAAM,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI;CAmBnC"}
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import { spawnSync } from 'child_process';
|
|
2
|
+
import { existsSync } from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { isCleanWorkingDirectory } from './git-utils.js';
|
|
5
|
+
/** Default patterns to exclude from working directory cleanliness checks */
|
|
6
|
+
const DEFAULT_EXCLUDE_PATTERNS = ['.ai-sdlc/**'];
|
|
7
|
+
/**
|
|
8
|
+
* Error messages used by the worktree service
|
|
9
|
+
*/
|
|
10
|
+
const ERROR_MESSAGES = {
|
|
11
|
+
UNCOMMITTED_CHANGES: 'Uncommitted changes exist. Commit or stash before using worktrees.',
|
|
12
|
+
PATH_EXISTS: 'Worktree path already exists',
|
|
13
|
+
CREATE_FAILED: 'Failed to create worktree',
|
|
14
|
+
NO_BASE_BRANCH: 'Could not detect base branch (main or master)',
|
|
15
|
+
NOT_GIT_REPO: 'Not a git repository',
|
|
16
|
+
BRANCH_EXISTS: 'A branch with this name already exists',
|
|
17
|
+
WORKTREE_NOT_FOUND: 'Worktree not found',
|
|
18
|
+
WORKTREE_HAS_CHANGES: 'Worktree has uncommitted changes. Use --force to remove.',
|
|
19
|
+
LIST_FAILED: 'Failed to list worktrees',
|
|
20
|
+
REMOVE_FAILED: 'Failed to remove worktree',
|
|
21
|
+
INSTALL_FAILED: 'Failed to install dependencies',
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Lock file to package manager mapping
|
|
25
|
+
*/
|
|
26
|
+
const LOCK_FILE_TO_PM = {
|
|
27
|
+
'package-lock.json': 'npm',
|
|
28
|
+
'yarn.lock': 'yarn',
|
|
29
|
+
'pnpm-lock.yaml': 'pnpm',
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Service for managing git worktrees for isolated story execution
|
|
33
|
+
*/
|
|
34
|
+
export class GitWorktreeService {
|
|
35
|
+
projectRoot;
|
|
36
|
+
worktreeBasePath;
|
|
37
|
+
constructor(projectRoot, worktreeBasePath) {
|
|
38
|
+
this.projectRoot = projectRoot;
|
|
39
|
+
this.worktreeBasePath = worktreeBasePath;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Generate the worktree path for a story
|
|
43
|
+
* Format: {worktreeBasePath}/{storyId}-{slug}
|
|
44
|
+
*/
|
|
45
|
+
getWorktreePath(storyId, slug) {
|
|
46
|
+
return path.join(this.worktreeBasePath, `${storyId}-${slug}`);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Generate the branch name for a worktree
|
|
50
|
+
* Format: ai-sdlc/{storyId}-{slug}
|
|
51
|
+
*/
|
|
52
|
+
getBranchName(storyId, slug) {
|
|
53
|
+
return `ai-sdlc/${storyId}-${slug}`;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Detect the base branch (main or master) for branching
|
|
57
|
+
* @returns The detected base branch name
|
|
58
|
+
* @throws Error if neither main nor master exists
|
|
59
|
+
*/
|
|
60
|
+
detectBaseBranch() {
|
|
61
|
+
// Check for 'main' first
|
|
62
|
+
const mainResult = spawnSync('git', ['rev-parse', '--verify', 'main'], {
|
|
63
|
+
cwd: this.projectRoot,
|
|
64
|
+
encoding: 'utf-8',
|
|
65
|
+
shell: false,
|
|
66
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
67
|
+
});
|
|
68
|
+
if (mainResult.status === 0) {
|
|
69
|
+
return 'main';
|
|
70
|
+
}
|
|
71
|
+
// Check for 'master' as fallback
|
|
72
|
+
const masterResult = spawnSync('git', ['rev-parse', '--verify', 'master'], {
|
|
73
|
+
cwd: this.projectRoot,
|
|
74
|
+
encoding: 'utf-8',
|
|
75
|
+
shell: false,
|
|
76
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
77
|
+
});
|
|
78
|
+
if (masterResult.status === 0) {
|
|
79
|
+
return 'master';
|
|
80
|
+
}
|
|
81
|
+
throw new Error(ERROR_MESSAGES.NO_BASE_BRANCH);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Validate that a worktree can be created
|
|
85
|
+
* Checks for uncommitted changes in the working directory
|
|
86
|
+
* Note: Changes in .ai-sdlc/ directory are excluded since they're expected
|
|
87
|
+
* during normal workflow (story file updates, etc.)
|
|
88
|
+
*/
|
|
89
|
+
validateCanCreateWorktree() {
|
|
90
|
+
const cleanCheckOptions = {
|
|
91
|
+
excludePatterns: DEFAULT_EXCLUDE_PATTERNS,
|
|
92
|
+
};
|
|
93
|
+
if (!isCleanWorkingDirectory(this.projectRoot, cleanCheckOptions)) {
|
|
94
|
+
return {
|
|
95
|
+
valid: false,
|
|
96
|
+
error: ERROR_MESSAGES.UNCOMMITTED_CHANGES,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
return { valid: true };
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Check if a worktree already exists at the given path
|
|
103
|
+
*/
|
|
104
|
+
exists(worktreePath) {
|
|
105
|
+
return existsSync(worktreePath);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Create a new git worktree for isolated story execution
|
|
109
|
+
* @param options - Worktree creation options
|
|
110
|
+
* @returns The path to the created worktree
|
|
111
|
+
* @throws Error if worktree creation fails
|
|
112
|
+
*/
|
|
113
|
+
create(options) {
|
|
114
|
+
const worktreePath = this.getWorktreePath(options.storyId, options.slug);
|
|
115
|
+
const branchName = this.getBranchName(options.storyId, options.slug);
|
|
116
|
+
const baseBranch = options.baseBranch || this.detectBaseBranch();
|
|
117
|
+
// Check if worktree path already exists
|
|
118
|
+
if (this.exists(worktreePath)) {
|
|
119
|
+
throw new Error(`${ERROR_MESSAGES.PATH_EXISTS}: ${worktreePath}`);
|
|
120
|
+
}
|
|
121
|
+
// Execute git worktree add command
|
|
122
|
+
const result = spawnSync('git', ['worktree', 'add', '-b', branchName, worktreePath, baseBranch], {
|
|
123
|
+
cwd: this.projectRoot,
|
|
124
|
+
encoding: 'utf-8',
|
|
125
|
+
shell: false,
|
|
126
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
127
|
+
});
|
|
128
|
+
// Handle errors
|
|
129
|
+
if (result.status !== 0) {
|
|
130
|
+
const stderr = result.stderr?.toString() || '';
|
|
131
|
+
// Provide specific error messages for common failures
|
|
132
|
+
if (stderr.includes('not a git repository')) {
|
|
133
|
+
throw new Error(ERROR_MESSAGES.NOT_GIT_REPO);
|
|
134
|
+
}
|
|
135
|
+
if (stderr.includes('already exists')) {
|
|
136
|
+
throw new Error(`${ERROR_MESSAGES.BRANCH_EXISTS}: ${branchName}`);
|
|
137
|
+
}
|
|
138
|
+
// Generic error with stderr details
|
|
139
|
+
throw new Error(`${ERROR_MESSAGES.CREATE_FAILED}: ${stderr}`);
|
|
140
|
+
}
|
|
141
|
+
// Install dependencies in the new worktree
|
|
142
|
+
this.installDependencies(worktreePath);
|
|
143
|
+
return worktreePath;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Install npm dependencies in a worktree
|
|
147
|
+
* Detects the package manager (npm/yarn/pnpm) and runs the appropriate install command
|
|
148
|
+
* @param worktreePath - Path to the worktree
|
|
149
|
+
* @throws Error if installation fails
|
|
150
|
+
*/
|
|
151
|
+
installDependencies(worktreePath) {
|
|
152
|
+
const packageJsonPath = path.join(worktreePath, 'package.json');
|
|
153
|
+
// Skip if not a Node.js project
|
|
154
|
+
if (!existsSync(packageJsonPath)) {
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
// Detect package manager from lock file
|
|
158
|
+
let packageManager = 'npm'; // default
|
|
159
|
+
for (const [lockFile, pm] of Object.entries(LOCK_FILE_TO_PM)) {
|
|
160
|
+
if (existsSync(path.join(worktreePath, lockFile))) {
|
|
161
|
+
packageManager = pm;
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
// Run install command
|
|
166
|
+
const result = spawnSync(packageManager, ['install'], {
|
|
167
|
+
cwd: worktreePath,
|
|
168
|
+
encoding: 'utf-8',
|
|
169
|
+
shell: false,
|
|
170
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
171
|
+
timeout: 120000, // 2 minute timeout
|
|
172
|
+
});
|
|
173
|
+
if (result.status !== 0) {
|
|
174
|
+
const stderr = result.stderr?.toString() || '';
|
|
175
|
+
throw new Error(`${ERROR_MESSAGES.INSTALL_FAILED}: ${stderr}`);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* List all ai-sdlc managed worktrees
|
|
180
|
+
* @returns Array of WorktreeInfo objects for worktrees in the basePath
|
|
181
|
+
*/
|
|
182
|
+
list() {
|
|
183
|
+
const result = spawnSync('git', ['worktree', 'list', '--porcelain'], {
|
|
184
|
+
cwd: this.projectRoot,
|
|
185
|
+
encoding: 'utf-8',
|
|
186
|
+
shell: false,
|
|
187
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
188
|
+
});
|
|
189
|
+
if (result.status !== 0) {
|
|
190
|
+
throw new Error(`${ERROR_MESSAGES.LIST_FAILED}: ${result.stderr}`);
|
|
191
|
+
}
|
|
192
|
+
const output = result.stdout || '';
|
|
193
|
+
const worktrees = [];
|
|
194
|
+
const blocks = output.trim().split('\n\n');
|
|
195
|
+
for (const block of blocks) {
|
|
196
|
+
if (!block.trim())
|
|
197
|
+
continue;
|
|
198
|
+
const lines = block.split('\n');
|
|
199
|
+
let worktreePath = '';
|
|
200
|
+
let branch = '';
|
|
201
|
+
for (const line of lines) {
|
|
202
|
+
if (line.startsWith('worktree ')) {
|
|
203
|
+
worktreePath = line.substring(9);
|
|
204
|
+
}
|
|
205
|
+
else if (line.startsWith('branch ')) {
|
|
206
|
+
branch = line.substring(7).replace('refs/heads/', '');
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
// Filter to only ai-sdlc managed worktrees
|
|
210
|
+
if (worktreePath && worktreePath.startsWith(this.worktreeBasePath)) {
|
|
211
|
+
const storyIdMatch = branch.match(/^ai-sdlc\/(S-\d+)-/);
|
|
212
|
+
worktrees.push({
|
|
213
|
+
path: worktreePath,
|
|
214
|
+
branch,
|
|
215
|
+
storyId: storyIdMatch ? storyIdMatch[1] : undefined,
|
|
216
|
+
exists: existsSync(worktreePath),
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return worktrees;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Remove a git worktree
|
|
224
|
+
* @param worktreePath - Absolute path to the worktree to remove
|
|
225
|
+
* @throws Error if removal fails
|
|
226
|
+
*/
|
|
227
|
+
remove(worktreePath) {
|
|
228
|
+
const result = spawnSync('git', ['worktree', 'remove', worktreePath], {
|
|
229
|
+
cwd: this.projectRoot,
|
|
230
|
+
encoding: 'utf-8',
|
|
231
|
+
shell: false,
|
|
232
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
233
|
+
});
|
|
234
|
+
if (result.status !== 0) {
|
|
235
|
+
const stderr = result.stderr?.toString() || '';
|
|
236
|
+
if (stderr.includes('not a working tree')) {
|
|
237
|
+
throw new Error(ERROR_MESSAGES.WORKTREE_NOT_FOUND);
|
|
238
|
+
}
|
|
239
|
+
if (stderr.includes('modified or untracked files')) {
|
|
240
|
+
throw new Error(ERROR_MESSAGES.WORKTREE_HAS_CHANGES);
|
|
241
|
+
}
|
|
242
|
+
throw new Error(`${ERROR_MESSAGES.REMOVE_FAILED}: ${stderr}`);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
//# sourceMappingURL=worktree.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worktree.js","sourceRoot":"","sources":["../../src/core/worktree.ts"],"names":[],"mappings":"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"}
|