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
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-story logging for concurrent execution
|
|
3
|
+
*
|
|
4
|
+
* Each story execution creates a new timestamped log file with dual output
|
|
5
|
+
* (console + file) for debugging and audit trail.
|
|
6
|
+
*/
|
|
7
|
+
import { LogLevel } from '../types/index.js';
|
|
8
|
+
/**
|
|
9
|
+
* Per-story logger that writes to timestamped files
|
|
10
|
+
*
|
|
11
|
+
* Features:
|
|
12
|
+
* - Dual output: console + timestamped file per execution
|
|
13
|
+
* - Automatic log rotation (keeps last N logs per story)
|
|
14
|
+
* - Crash-safe synchronous writes
|
|
15
|
+
* - Location: stories/{id}/logs/{timestamp}.log
|
|
16
|
+
*/
|
|
17
|
+
export declare class StoryLogger {
|
|
18
|
+
private logStream;
|
|
19
|
+
private storyId;
|
|
20
|
+
private logPath;
|
|
21
|
+
private closed;
|
|
22
|
+
/**
|
|
23
|
+
* Initialize a per-story logger
|
|
24
|
+
*
|
|
25
|
+
* @param storyId - Story ID (sanitized automatically)
|
|
26
|
+
* @param sdlcRoot - Path to .ai-sdlc directory
|
|
27
|
+
* @param maxLogs - Maximum number of log files to retain per story (default: 5)
|
|
28
|
+
*/
|
|
29
|
+
constructor(storyId: string, sdlcRoot: string, maxLogs?: number);
|
|
30
|
+
/**
|
|
31
|
+
* Log a message with specified level
|
|
32
|
+
*
|
|
33
|
+
* Writes to both console and file. Sanitizes message to prevent issues
|
|
34
|
+
* with very long lines or non-printable characters.
|
|
35
|
+
*
|
|
36
|
+
* @param level - Log level (INFO, AGENT, ERROR, WARN, DEBUG)
|
|
37
|
+
* @param message - Message to log
|
|
38
|
+
*/
|
|
39
|
+
log(level: LogLevel, message: string): void;
|
|
40
|
+
/**
|
|
41
|
+
* Close the log stream
|
|
42
|
+
*
|
|
43
|
+
* Should be called when story execution completes or on process exit.
|
|
44
|
+
* Flushes any buffered data and closes the file handle.
|
|
45
|
+
*
|
|
46
|
+
* @returns Promise that resolves when the stream is fully closed
|
|
47
|
+
*/
|
|
48
|
+
close(): Promise<void>;
|
|
49
|
+
/**
|
|
50
|
+
* Get the path to the current log file
|
|
51
|
+
*
|
|
52
|
+
* @returns Absolute path to the current log file
|
|
53
|
+
*/
|
|
54
|
+
getLogPath(): string;
|
|
55
|
+
/**
|
|
56
|
+
* Sanitize log message to prevent issues
|
|
57
|
+
*
|
|
58
|
+
* - Truncates messages longer than 10KB
|
|
59
|
+
* - Strips or escapes non-printable characters (except newlines/tabs)
|
|
60
|
+
* - Preserves ANSI color codes for console output
|
|
61
|
+
*
|
|
62
|
+
* @param message - Raw message to sanitize
|
|
63
|
+
* @returns Sanitized message
|
|
64
|
+
*/
|
|
65
|
+
private sanitizeMessage;
|
|
66
|
+
/**
|
|
67
|
+
* Rotate old log files, keeping only the most recent N logs
|
|
68
|
+
*
|
|
69
|
+
* Sorting is lexicographic (filename-based) since timestamps are in ISO 8601 format.
|
|
70
|
+
* Deletes oldest logs beyond the retention limit.
|
|
71
|
+
*
|
|
72
|
+
* @param logDir - Directory containing log files
|
|
73
|
+
* @param keep - Number of logs to retain
|
|
74
|
+
*/
|
|
75
|
+
private rotateOldLogs;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Get the latest log file path for a story
|
|
79
|
+
*
|
|
80
|
+
* @param sdlcRoot - Path to .ai-sdlc directory
|
|
81
|
+
* @param storyId - Story ID (sanitized automatically)
|
|
82
|
+
* @returns Path to latest log file, or null if no logs exist
|
|
83
|
+
*/
|
|
84
|
+
export declare function getLatestLogPath(sdlcRoot: string, storyId: string): string | null;
|
|
85
|
+
/**
|
|
86
|
+
* Read the last N lines from a log file
|
|
87
|
+
*
|
|
88
|
+
* @param filePath - Path to log file
|
|
89
|
+
* @param lines - Number of lines to read (default: 50)
|
|
90
|
+
* @returns Last N lines as a string
|
|
91
|
+
*/
|
|
92
|
+
export declare function readLastLines(filePath: string, lines?: number): Promise<string>;
|
|
93
|
+
/**
|
|
94
|
+
* Tail a log file (follow mode, like tail -f)
|
|
95
|
+
*
|
|
96
|
+
* Watches the file for changes and outputs new lines as they're written.
|
|
97
|
+
* Press Ctrl+C to exit.
|
|
98
|
+
*
|
|
99
|
+
* @param filePath - Path to log file
|
|
100
|
+
*/
|
|
101
|
+
export declare function tailLog(filePath: string): void;
|
|
102
|
+
//# sourceMappingURL=story-logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"story-logger.d.ts","sourceRoot":"","sources":["../../src/core/story-logger.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,EAAkB,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAI7D;;;;;;;;GAQG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,SAAS,CAAiB;IAClC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,MAAM,CAAkB;IAEhC;;;;;;OAMG;gBACS,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,MAAU;IAwClE;;;;;;;;OAQG;IACH,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAwC3C;;;;;;;OAOG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAatB;;;;OAIG;IACH,UAAU,IAAI,MAAM;IAIpB;;;;;;;;;OASG;IACH,OAAO,CAAC,eAAe;IAgBvB;;;;;;;;OAQG;IACH,OAAO,CAAC,aAAa;CAsBtB;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAmBjF;AAED;;;;;;GAMG;AACH,wBAAsB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,GAAE,MAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAKzF;AAED;;;;;;;GAOG;AACH,wBAAgB,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAiC9C"}
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-story logging for concurrent execution
|
|
3
|
+
*
|
|
4
|
+
* Each story execution creates a new timestamped log file with dual output
|
|
5
|
+
* (console + file) for debugging and audit trail.
|
|
6
|
+
*/
|
|
7
|
+
import fs from 'fs';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
import { sanitizeStoryId } from './story.js';
|
|
10
|
+
import { STORIES_FOLDER } from '../types/index.js';
|
|
11
|
+
const MAX_MESSAGE_LENGTH = 10 * 1024; // 10KB per log entry
|
|
12
|
+
/**
|
|
13
|
+
* Per-story logger that writes to timestamped files
|
|
14
|
+
*
|
|
15
|
+
* Features:
|
|
16
|
+
* - Dual output: console + timestamped file per execution
|
|
17
|
+
* - Automatic log rotation (keeps last N logs per story)
|
|
18
|
+
* - Crash-safe synchronous writes
|
|
19
|
+
* - Location: stories/{id}/logs/{timestamp}.log
|
|
20
|
+
*/
|
|
21
|
+
export class StoryLogger {
|
|
22
|
+
logStream;
|
|
23
|
+
storyId;
|
|
24
|
+
logPath;
|
|
25
|
+
closed = false;
|
|
26
|
+
/**
|
|
27
|
+
* Initialize a per-story logger
|
|
28
|
+
*
|
|
29
|
+
* @param storyId - Story ID (sanitized automatically)
|
|
30
|
+
* @param sdlcRoot - Path to .ai-sdlc directory
|
|
31
|
+
* @param maxLogs - Maximum number of log files to retain per story (default: 5)
|
|
32
|
+
*/
|
|
33
|
+
constructor(storyId, sdlcRoot, maxLogs = 5) {
|
|
34
|
+
// SECURITY: Sanitize story ID to prevent path traversal
|
|
35
|
+
this.storyId = sanitizeStoryId(storyId);
|
|
36
|
+
const logDir = path.join(sdlcRoot, STORIES_FOLDER, this.storyId, 'logs');
|
|
37
|
+
// Ensure log directory exists
|
|
38
|
+
if (!fs.existsSync(logDir)) {
|
|
39
|
+
fs.mkdirSync(logDir, { recursive: true });
|
|
40
|
+
}
|
|
41
|
+
// Generate timestamp for log filename (ISO 8601 with safe characters)
|
|
42
|
+
// Split first to remove milliseconds (.000Z), then replace colons
|
|
43
|
+
const timestamp = new Date()
|
|
44
|
+
.toISOString()
|
|
45
|
+
.split('.')[0] // Remove milliseconds: 2026-01-15T10:30:00
|
|
46
|
+
.replace(/:/g, '-'); // Replace colons: 2026-01-15T10-30-00
|
|
47
|
+
this.logPath = path.join(logDir, `${timestamp}.log`);
|
|
48
|
+
// Ensure file exists before creating write stream (createWriteStream may not create immediately)
|
|
49
|
+
if (!fs.existsSync(this.logPath)) {
|
|
50
|
+
fs.writeFileSync(this.logPath, '');
|
|
51
|
+
}
|
|
52
|
+
// Create write stream in append mode
|
|
53
|
+
this.logStream = fs.createWriteStream(this.logPath, { flags: 'a' });
|
|
54
|
+
// Handle stream errors gracefully to prevent uncaught exceptions during cleanup
|
|
55
|
+
this.logStream.on('error', (err) => {
|
|
56
|
+
// ENOENT errors during cleanup are expected and can be ignored
|
|
57
|
+
if (err.code !== 'ENOENT') {
|
|
58
|
+
console.warn(`Warning: Log stream error: ${err.message}`);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
// Rotate old logs (cleanup happens at initialization, not during writes)
|
|
62
|
+
this.rotateOldLogs(logDir, maxLogs);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Log a message with specified level
|
|
66
|
+
*
|
|
67
|
+
* Writes to both console and file. Sanitizes message to prevent issues
|
|
68
|
+
* with very long lines or non-printable characters.
|
|
69
|
+
*
|
|
70
|
+
* @param level - Log level (INFO, AGENT, ERROR, WARN, DEBUG)
|
|
71
|
+
* @param message - Message to log
|
|
72
|
+
*/
|
|
73
|
+
log(level, message) {
|
|
74
|
+
if (this.closed) {
|
|
75
|
+
console.warn('Warning: Attempted to log to closed logger');
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
// Sanitize and truncate message
|
|
79
|
+
const sanitized = this.sanitizeMessage(message);
|
|
80
|
+
// Format log entry with ISO 8601 timestamp
|
|
81
|
+
const timestamp = new Date().toISOString();
|
|
82
|
+
const entry = `[${timestamp}] [${level}] ${sanitized}\n`;
|
|
83
|
+
// Write to file synchronously (crash-safe)
|
|
84
|
+
try {
|
|
85
|
+
this.logStream.write(entry);
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
// Graceful degradation: if file write fails, continue with console-only
|
|
89
|
+
console.warn(`Warning: Failed to write to log file: ${error instanceof Error ? error.message : String(error)}`);
|
|
90
|
+
}
|
|
91
|
+
// Write to console based on level
|
|
92
|
+
switch (level) {
|
|
93
|
+
case 'ERROR':
|
|
94
|
+
console.error(sanitized);
|
|
95
|
+
break;
|
|
96
|
+
case 'WARN':
|
|
97
|
+
console.warn(sanitized);
|
|
98
|
+
break;
|
|
99
|
+
case 'DEBUG':
|
|
100
|
+
// Only log debug to file, not console (unless explicitly debugging)
|
|
101
|
+
if (process.env.DEBUG) {
|
|
102
|
+
console.log(sanitized);
|
|
103
|
+
}
|
|
104
|
+
break;
|
|
105
|
+
default:
|
|
106
|
+
console.log(sanitized);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Close the log stream
|
|
111
|
+
*
|
|
112
|
+
* Should be called when story execution completes or on process exit.
|
|
113
|
+
* Flushes any buffered data and closes the file handle.
|
|
114
|
+
*
|
|
115
|
+
* @returns Promise that resolves when the stream is fully closed
|
|
116
|
+
*/
|
|
117
|
+
close() {
|
|
118
|
+
return new Promise((resolve) => {
|
|
119
|
+
if (!this.closed) {
|
|
120
|
+
this.logStream.end(() => {
|
|
121
|
+
this.closed = true;
|
|
122
|
+
resolve();
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
resolve();
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Get the path to the current log file
|
|
132
|
+
*
|
|
133
|
+
* @returns Absolute path to the current log file
|
|
134
|
+
*/
|
|
135
|
+
getLogPath() {
|
|
136
|
+
return this.logPath;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Sanitize log message to prevent issues
|
|
140
|
+
*
|
|
141
|
+
* - Truncates messages longer than 10KB
|
|
142
|
+
* - Strips or escapes non-printable characters (except newlines/tabs)
|
|
143
|
+
* - Preserves ANSI color codes for console output
|
|
144
|
+
*
|
|
145
|
+
* @param message - Raw message to sanitize
|
|
146
|
+
* @returns Sanitized message
|
|
147
|
+
*/
|
|
148
|
+
sanitizeMessage(message) {
|
|
149
|
+
let sanitized = message;
|
|
150
|
+
// Truncate very long messages
|
|
151
|
+
if (sanitized.length > MAX_MESSAGE_LENGTH) {
|
|
152
|
+
sanitized = sanitized.substring(0, MAX_MESSAGE_LENGTH) + '\n... [message truncated]';
|
|
153
|
+
}
|
|
154
|
+
// Replace non-printable characters (except newlines, tabs, and ANSI escape codes)
|
|
155
|
+
// ANSI escape codes start with \x1b[ and are followed by formatting codes
|
|
156
|
+
// We preserve these for console output (they're stripped when written to most log viewers)
|
|
157
|
+
sanitized = sanitized.replace(/[\x00-\x08\x0B-\x0C\x0E-\x1F\x7F]/g, '');
|
|
158
|
+
return sanitized;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Rotate old log files, keeping only the most recent N logs
|
|
162
|
+
*
|
|
163
|
+
* Sorting is lexicographic (filename-based) since timestamps are in ISO 8601 format.
|
|
164
|
+
* Deletes oldest logs beyond the retention limit.
|
|
165
|
+
*
|
|
166
|
+
* @param logDir - Directory containing log files
|
|
167
|
+
* @param keep - Number of logs to retain
|
|
168
|
+
*/
|
|
169
|
+
rotateOldLogs(logDir, keep) {
|
|
170
|
+
try {
|
|
171
|
+
const logs = fs
|
|
172
|
+
.readdirSync(logDir)
|
|
173
|
+
.filter((f) => f.endsWith('.log'))
|
|
174
|
+
.sort()
|
|
175
|
+
.reverse(); // Newest first (lexicographic sort of ISO 8601 timestamps)
|
|
176
|
+
// Delete logs beyond the keep limit
|
|
177
|
+
const toDelete = logs.slice(keep);
|
|
178
|
+
for (const log of toDelete) {
|
|
179
|
+
try {
|
|
180
|
+
fs.unlinkSync(path.join(logDir, log));
|
|
181
|
+
}
|
|
182
|
+
catch {
|
|
183
|
+
// Ignore deletion errors (file may have been deleted by another process)
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
catch {
|
|
188
|
+
// Ignore rotation errors (directory may not exist or be readable)
|
|
189
|
+
// Rotation is a best-effort cleanup, not critical
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Get the latest log file path for a story
|
|
195
|
+
*
|
|
196
|
+
* @param sdlcRoot - Path to .ai-sdlc directory
|
|
197
|
+
* @param storyId - Story ID (sanitized automatically)
|
|
198
|
+
* @returns Path to latest log file, or null if no logs exist
|
|
199
|
+
*/
|
|
200
|
+
export function getLatestLogPath(sdlcRoot, storyId) {
|
|
201
|
+
const sanitized = sanitizeStoryId(storyId);
|
|
202
|
+
const logDir = path.join(sdlcRoot, STORIES_FOLDER, sanitized, 'logs');
|
|
203
|
+
if (!fs.existsSync(logDir)) {
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
206
|
+
const logs = fs
|
|
207
|
+
.readdirSync(logDir)
|
|
208
|
+
.filter((f) => f.endsWith('.log'))
|
|
209
|
+
.sort()
|
|
210
|
+
.reverse(); // Newest first
|
|
211
|
+
if (logs.length === 0) {
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
214
|
+
return path.join(logDir, logs[0]);
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Read the last N lines from a log file
|
|
218
|
+
*
|
|
219
|
+
* @param filePath - Path to log file
|
|
220
|
+
* @param lines - Number of lines to read (default: 50)
|
|
221
|
+
* @returns Last N lines as a string
|
|
222
|
+
*/
|
|
223
|
+
export async function readLastLines(filePath, lines = 50) {
|
|
224
|
+
const content = await fs.promises.readFile(filePath, 'utf-8');
|
|
225
|
+
const allLines = content.split('\n').filter((line) => line.trim() !== '');
|
|
226
|
+
const lastLines = allLines.slice(-lines);
|
|
227
|
+
return lastLines.join('\n');
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Tail a log file (follow mode, like tail -f)
|
|
231
|
+
*
|
|
232
|
+
* Watches the file for changes and outputs new lines as they're written.
|
|
233
|
+
* Press Ctrl+C to exit.
|
|
234
|
+
*
|
|
235
|
+
* @param filePath - Path to log file
|
|
236
|
+
*/
|
|
237
|
+
export function tailLog(filePath) {
|
|
238
|
+
// Read existing content first
|
|
239
|
+
const existingContent = fs.readFileSync(filePath, 'utf-8');
|
|
240
|
+
process.stdout.write(existingContent);
|
|
241
|
+
// Track current file size
|
|
242
|
+
let lastSize = existingContent.length;
|
|
243
|
+
// Watch for changes
|
|
244
|
+
const watcher = fs.watchFile(filePath, { interval: 100 }, (curr) => {
|
|
245
|
+
if (curr.size > lastSize) {
|
|
246
|
+
// File grew - read new content
|
|
247
|
+
const stream = fs.createReadStream(filePath, {
|
|
248
|
+
start: lastSize,
|
|
249
|
+
encoding: 'utf-8',
|
|
250
|
+
});
|
|
251
|
+
stream.on('data', (chunk) => {
|
|
252
|
+
process.stdout.write(chunk);
|
|
253
|
+
});
|
|
254
|
+
lastSize = curr.size;
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
// Handle Ctrl+C gracefully
|
|
258
|
+
process.on('SIGINT', () => {
|
|
259
|
+
fs.unwatchFile(filePath);
|
|
260
|
+
process.exit(0);
|
|
261
|
+
});
|
|
262
|
+
// Keep process alive
|
|
263
|
+
console.log('\n[Following log file - Press Ctrl+C to exit]');
|
|
264
|
+
}
|
|
265
|
+
//# sourceMappingURL=story-logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"story-logger.js","sourceRoot":"","sources":["../../src/core/story-logger.ts"],"names":[],"mappings":"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"}
|
package/dist/core/story.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Story, StoryFrontmatter, StoryStatus, ReviewAttempt, Config } from '../types/index.js';
|
|
1
|
+
import { Story, StoryFrontmatter, StoryStatus, ReviewAttempt, Config, LockOptions } from '../types/index.js';
|
|
2
2
|
/**
|
|
3
3
|
* Parse a story markdown file into a Story object
|
|
4
4
|
*
|
|
@@ -7,19 +7,41 @@ import { Story, StoryFrontmatter, StoryStatus, ReviewAttempt, Config } from '../
|
|
|
7
7
|
*/
|
|
8
8
|
export declare function parseStory(filePath: string): Story;
|
|
9
9
|
/**
|
|
10
|
-
* Write a story back to disk
|
|
10
|
+
* Write a story back to disk with file locking for atomic updates.
|
|
11
|
+
*
|
|
12
|
+
* This function acquires an exclusive lock before writing to prevent race conditions
|
|
13
|
+
* from concurrent processes. The lock is always released, even if an error occurs.
|
|
14
|
+
*
|
|
15
|
+
* **IMPORTANT:** Do not nest locks on the same file to avoid deadlock. Batch multiple
|
|
16
|
+
* updates into a single writeStory() call instead.
|
|
17
|
+
*
|
|
18
|
+
* @param story - Story object to write
|
|
19
|
+
* @param options - Lock options (timeout, retries, stale threshold)
|
|
20
|
+
* @throws Error if file is locked by another process or filesystem is read-only
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```typescript
|
|
24
|
+
* // Good: Batch updates
|
|
25
|
+
* story.frontmatter.status = 'in-progress';
|
|
26
|
+
* story.frontmatter.priority = 1;
|
|
27
|
+
* await writeStory(story);
|
|
28
|
+
*
|
|
29
|
+
* // Bad: Nested locks (potential deadlock)
|
|
30
|
+
* await writeStory(story); // holds lock
|
|
31
|
+
* await writeStory(story); // tries to acquire same lock = deadlock
|
|
32
|
+
* ```
|
|
11
33
|
*/
|
|
12
|
-
export declare function writeStory(story: Story): void
|
|
34
|
+
export declare function writeStory(story: Story, options?: LockOptions): Promise<void>;
|
|
13
35
|
/**
|
|
14
36
|
* Update story status in frontmatter without moving files
|
|
15
37
|
* This is the preferred method in the new folder-per-story architecture
|
|
16
38
|
*/
|
|
17
|
-
export declare function updateStoryStatus(story: Story, newStatus: StoryStatus): Story
|
|
39
|
+
export declare function updateStoryStatus(story: Story, newStatus: StoryStatus): Promise<Story>;
|
|
18
40
|
/**
|
|
19
41
|
* Move a story to a different kanban folder
|
|
20
42
|
* @deprecated Use updateStoryStatus() instead. Will be removed in v2.0
|
|
21
43
|
*/
|
|
22
|
-
export declare function moveStory(story: Story, toFolder: string, sdlcRoot: string): Story
|
|
44
|
+
export declare function moveStory(story: Story, toFolder: string, sdlcRoot: string): Promise<Story>;
|
|
23
45
|
/**
|
|
24
46
|
* Move a story to blocked status with reason and timestamp
|
|
25
47
|
* In the new architecture, this only updates frontmatter - file path remains unchanged
|
|
@@ -27,7 +49,7 @@ export declare function moveStory(story: Story, toFolder: string, sdlcRoot: stri
|
|
|
27
49
|
* @param storyPath - Absolute path to the story file
|
|
28
50
|
* @param reason - Reason for blocking (e.g., "Max refinement attempts (2/2) reached")
|
|
29
51
|
*/
|
|
30
|
-
export declare function moveToBlocked(storyPath: string, reason: string): void
|
|
52
|
+
export declare function moveToBlocked(storyPath: string, reason: string): Promise<void>;
|
|
31
53
|
/**
|
|
32
54
|
* Generate a unique story ID in sequential format (S-0001, S-0002, etc.)
|
|
33
55
|
* Scans the stories folder to find the highest existing number.
|
|
@@ -45,25 +67,50 @@ export declare function generateLegacyStoryId(): string;
|
|
|
45
67
|
* Create a slug from a title
|
|
46
68
|
*/
|
|
47
69
|
export declare function slugify(title: string): string;
|
|
70
|
+
/**
|
|
71
|
+
* Sanitize a title string for safe use in file paths and display.
|
|
72
|
+
* Removes dangerous characters that could be used for injection attacks.
|
|
73
|
+
*
|
|
74
|
+
* SECURITY: This function prevents command injection and path traversal through titles.
|
|
75
|
+
*
|
|
76
|
+
* @param title - Title string to sanitize
|
|
77
|
+
* @returns Sanitized title safe for use in paths and commands
|
|
78
|
+
*/
|
|
79
|
+
export declare function sanitizeTitle(title: string): string;
|
|
80
|
+
/**
|
|
81
|
+
* Extract title from file content using safe parsing.
|
|
82
|
+
* Priority: YAML frontmatter > H1 heading > null
|
|
83
|
+
*
|
|
84
|
+
* SECURITY: Uses regex-only approach to avoid YAML parser vulnerabilities.
|
|
85
|
+
*
|
|
86
|
+
* @param content - File content to extract title from
|
|
87
|
+
* @returns Extracted title or null if not found
|
|
88
|
+
*/
|
|
89
|
+
export declare function extractTitleFromContent(content: string): string | null;
|
|
48
90
|
/**
|
|
49
91
|
* Create a new story in the folder-per-story structure
|
|
50
92
|
*
|
|
51
93
|
* Creates stories/{id}/story.md with slug and priority in frontmatter.
|
|
52
94
|
* Priority uses gaps (10, 20, 30...) for easy insertion without renumbering.
|
|
95
|
+
*
|
|
96
|
+
* @param title - Story title
|
|
97
|
+
* @param sdlcRoot - Root path of .ai-sdlc folder
|
|
98
|
+
* @param options - Optional frontmatter fields
|
|
99
|
+
* @param content - Optional custom story content (if not provided, uses default template)
|
|
53
100
|
*/
|
|
54
|
-
export declare function createStory(title: string, sdlcRoot: string, options?: Partial<StoryFrontmatter
|
|
101
|
+
export declare function createStory(title: string, sdlcRoot: string, options?: Partial<StoryFrontmatter>, content?: string): Promise<Story>;
|
|
55
102
|
/**
|
|
56
103
|
* Update story frontmatter field
|
|
57
104
|
*/
|
|
58
|
-
export declare function updateStoryField<K extends keyof StoryFrontmatter>(story: Story, field: K, value: StoryFrontmatter[K]): Story
|
|
105
|
+
export declare function updateStoryField<K extends keyof StoryFrontmatter>(story: Story, field: K, value: StoryFrontmatter[K]): Promise<Story>;
|
|
59
106
|
/**
|
|
60
107
|
* Append content to a section in the story
|
|
61
108
|
*/
|
|
62
|
-
export declare function appendToSection(story: Story, section: string, content: string): Story
|
|
109
|
+
export declare function appendToSection(story: Story, section: string, content: string): Promise<Story>;
|
|
63
110
|
/**
|
|
64
111
|
* Record a refinement attempt in the story's frontmatter
|
|
65
112
|
*/
|
|
66
|
-
export declare function recordRefinementAttempt(story: Story, agentType: string, reviewFeedback: string): Story
|
|
113
|
+
export declare function recordRefinementAttempt(story: Story, agentType: string, reviewFeedback: string): Promise<Story>;
|
|
67
114
|
/**
|
|
68
115
|
* Get the current refinement count for a story
|
|
69
116
|
*/
|
|
@@ -75,7 +122,7 @@ export declare function canRetryRefinement(story: Story, maxAttempts: number): b
|
|
|
75
122
|
/**
|
|
76
123
|
* Reset phase completion flags for rework
|
|
77
124
|
*/
|
|
78
|
-
export declare function resetPhaseCompletion(story: Story, phase: 'research' | 'plan' | 'implement'): Story
|
|
125
|
+
export declare function resetPhaseCompletion(story: Story, phase: 'research' | 'plan' | 'implement'): Promise<Story>;
|
|
79
126
|
/**
|
|
80
127
|
* Get the latest review feedback from the story content
|
|
81
128
|
*/
|
|
@@ -83,7 +130,7 @@ export declare function getLatestReviewFeedback(story: Story): string | null;
|
|
|
83
130
|
/**
|
|
84
131
|
* Append refinement feedback to the story content
|
|
85
132
|
*/
|
|
86
|
-
export declare function appendRefinementNote(story: Story, iteration: number, feedback: string): Story
|
|
133
|
+
export declare function appendRefinementNote(story: Story, iteration: number, feedback: string): Promise<Story>;
|
|
87
134
|
/**
|
|
88
135
|
* Get the effective maximum retries for a story (story-specific or config default)
|
|
89
136
|
*/
|
|
@@ -96,15 +143,15 @@ export declare function isAtMaxRetries(story: Story, config: Config, maxIteratio
|
|
|
96
143
|
/**
|
|
97
144
|
* Increment the retry count for a story
|
|
98
145
|
*/
|
|
99
|
-
export declare function incrementRetryCount(story: Story): Story
|
|
146
|
+
export declare function incrementRetryCount(story: Story): Promise<Story>;
|
|
100
147
|
/**
|
|
101
148
|
* Reset RPIV cycle for a story (keep research, reset plan/implementation/reviews)
|
|
102
149
|
*/
|
|
103
|
-
export declare function resetRPIVCycle(story: Story, reason: string): Story
|
|
150
|
+
export declare function resetRPIVCycle(story: Story, reason: string): Promise<Story>;
|
|
104
151
|
/**
|
|
105
152
|
* Append a review attempt to the story's review history
|
|
106
153
|
*/
|
|
107
|
-
export declare function appendReviewHistory(story: Story, attempt: ReviewAttempt): Story
|
|
154
|
+
export declare function appendReviewHistory(story: Story, attempt: ReviewAttempt): Promise<Story>;
|
|
108
155
|
/**
|
|
109
156
|
* Get the latest review attempt from a story's history
|
|
110
157
|
*/
|
|
@@ -112,11 +159,11 @@ export declare function getLatestReviewAttempt(story: Story): ReviewAttempt | nu
|
|
|
112
159
|
/**
|
|
113
160
|
* Mark a story as complete (all workflow flags set to true)
|
|
114
161
|
*/
|
|
115
|
-
export declare function markStoryComplete(story: Story): Story
|
|
162
|
+
export declare function markStoryComplete(story: Story): Promise<Story>;
|
|
116
163
|
/**
|
|
117
164
|
* Snapshot max_retries from config to story frontmatter (for mid-cycle config change protection)
|
|
118
165
|
*/
|
|
119
|
-
export declare function snapshotMaxRetries(story: Story, config: Config): Story
|
|
166
|
+
export declare function snapshotMaxRetries(story: Story, config: Config): Promise<Story>;
|
|
120
167
|
/**
|
|
121
168
|
* Get the current implementation retry count for a story
|
|
122
169
|
*/
|
|
@@ -135,11 +182,23 @@ export declare function isAtMaxImplementationRetries(story: Story, config: Confi
|
|
|
135
182
|
/**
|
|
136
183
|
* Reset implementation retry count to 0
|
|
137
184
|
*/
|
|
138
|
-
export declare function resetImplementationRetryCount(story: Story): Story
|
|
185
|
+
export declare function resetImplementationRetryCount(story: Story): Promise<Story>;
|
|
139
186
|
/**
|
|
140
187
|
* Increment the implementation retry count for a story
|
|
141
188
|
*/
|
|
142
|
-
export declare function incrementImplementationRetryCount(story: Story): Story
|
|
189
|
+
export declare function incrementImplementationRetryCount(story: Story): Promise<Story>;
|
|
190
|
+
/**
|
|
191
|
+
* Sanitize story ID for safe path construction.
|
|
192
|
+
* Prevents path traversal attacks by rejecting dangerous characters.
|
|
193
|
+
*
|
|
194
|
+
* SECURITY: This function is CRITICAL for preventing path traversal vulnerabilities.
|
|
195
|
+
* Use this before constructing ANY file paths with user-provided story IDs.
|
|
196
|
+
*
|
|
197
|
+
* @param storyId - Story ID to sanitize (e.g., 'S-0001')
|
|
198
|
+
* @returns Sanitized story ID safe for path construction
|
|
199
|
+
* @throws Error if storyId contains dangerous characters or patterns
|
|
200
|
+
*/
|
|
201
|
+
export declare function sanitizeStoryId(storyId: string): string;
|
|
143
202
|
/**
|
|
144
203
|
* Sanitize user-controlled text for safe display and storage.
|
|
145
204
|
* Removes ANSI escape sequences, control characters, and potential injection vectors.
|
|
@@ -179,5 +238,5 @@ export declare function getStory(sdlcRoot: string, storyId: string): Story;
|
|
|
179
238
|
*/
|
|
180
239
|
export declare function unblockStory(storyId: string, sdlcRoot: string, options?: {
|
|
181
240
|
resetRetries?: boolean;
|
|
182
|
-
}): Story
|
|
241
|
+
}): Promise<Story>;
|
|
183
242
|
//# sourceMappingURL=story.d.ts.map
|
package/dist/core/story.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"story.d.ts","sourceRoot":"","sources":["../../src/core/story.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"story.d.ts","sourceRoot":"","sources":["../../src/core/story.ts"],"names":[],"mappings":"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"}
|