ai-sdlc 0.2.0-alpha.3 → 0.2.0-alpha.31

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.
Files changed (103) hide show
  1. package/README.md +53 -1058
  2. package/dist/agents/implementation.d.ts +62 -0
  3. package/dist/agents/implementation.d.ts.map +1 -1
  4. package/dist/agents/implementation.js +494 -90
  5. package/dist/agents/implementation.js.map +1 -1
  6. package/dist/agents/planning.d.ts.map +1 -1
  7. package/dist/agents/planning.js +22 -3
  8. package/dist/agents/planning.js.map +1 -1
  9. package/dist/agents/refinement.d.ts.map +1 -1
  10. package/dist/agents/refinement.js +22 -3
  11. package/dist/agents/refinement.js.map +1 -1
  12. package/dist/agents/research.d.ts +85 -1
  13. package/dist/agents/research.d.ts.map +1 -1
  14. package/dist/agents/research.js +506 -16
  15. package/dist/agents/research.js.map +1 -1
  16. package/dist/agents/review.d.ts +79 -2
  17. package/dist/agents/review.d.ts.map +1 -1
  18. package/dist/agents/review.js +568 -68
  19. package/dist/agents/review.js.map +1 -1
  20. package/dist/agents/rework.d.ts.map +1 -1
  21. package/dist/agents/rework.js +22 -3
  22. package/dist/agents/rework.js.map +1 -1
  23. package/dist/agents/state-assessor.d.ts +3 -3
  24. package/dist/agents/state-assessor.d.ts.map +1 -1
  25. package/dist/agents/state-assessor.js +6 -6
  26. package/dist/agents/state-assessor.js.map +1 -1
  27. package/dist/agents/test-pattern-detector.d.ts +49 -0
  28. package/dist/agents/test-pattern-detector.d.ts.map +1 -0
  29. package/dist/agents/test-pattern-detector.js +273 -0
  30. package/dist/agents/test-pattern-detector.js.map +1 -0
  31. package/dist/agents/verification.d.ts +11 -0
  32. package/dist/agents/verification.d.ts.map +1 -1
  33. package/dist/agents/verification.js +74 -1
  34. package/dist/agents/verification.js.map +1 -1
  35. package/dist/cli/commands/migrate.js +1 -1
  36. package/dist/cli/commands/migrate.js.map +1 -1
  37. package/dist/cli/commands.d.ts +59 -3
  38. package/dist/cli/commands.d.ts.map +1 -1
  39. package/dist/cli/commands.js +1053 -217
  40. package/dist/cli/commands.js.map +1 -1
  41. package/dist/cli/daemon.d.ts.map +1 -1
  42. package/dist/cli/daemon.js +40 -10
  43. package/dist/cli/daemon.js.map +1 -1
  44. package/dist/cli/formatting.js +1 -1
  45. package/dist/cli/formatting.js.map +1 -1
  46. package/dist/cli/runner.d.ts.map +1 -1
  47. package/dist/cli/runner.js +51 -20
  48. package/dist/cli/runner.js.map +1 -1
  49. package/dist/core/auth.d.ts +51 -2
  50. package/dist/core/auth.d.ts.map +1 -1
  51. package/dist/core/auth.js +267 -7
  52. package/dist/core/auth.js.map +1 -1
  53. package/dist/core/client.d.ts +6 -0
  54. package/dist/core/client.d.ts.map +1 -1
  55. package/dist/core/client.js +68 -4
  56. package/dist/core/client.js.map +1 -1
  57. package/dist/core/config.d.ts +36 -1
  58. package/dist/core/config.d.ts.map +1 -1
  59. package/dist/core/config.js +162 -1
  60. package/dist/core/config.js.map +1 -1
  61. package/dist/core/conflict-detector.d.ts +108 -0
  62. package/dist/core/conflict-detector.d.ts.map +1 -0
  63. package/dist/core/conflict-detector.js +413 -0
  64. package/dist/core/conflict-detector.js.map +1 -0
  65. package/dist/core/git-utils.d.ts +28 -0
  66. package/dist/core/git-utils.d.ts.map +1 -0
  67. package/dist/core/git-utils.js +146 -0
  68. package/dist/core/git-utils.js.map +1 -0
  69. package/dist/core/index.d.ts +17 -0
  70. package/dist/core/index.d.ts.map +1 -0
  71. package/dist/core/index.js +17 -0
  72. package/dist/core/index.js.map +1 -0
  73. package/dist/core/kanban.d.ts +1 -6
  74. package/dist/core/kanban.d.ts.map +1 -1
  75. package/dist/core/kanban.js +10 -49
  76. package/dist/core/kanban.js.map +1 -1
  77. package/dist/core/logger.d.ts +92 -0
  78. package/dist/core/logger.d.ts.map +1 -0
  79. package/dist/core/logger.js +221 -0
  80. package/dist/core/logger.js.map +1 -0
  81. package/dist/core/story-logger.d.ts +102 -0
  82. package/dist/core/story-logger.d.ts.map +1 -0
  83. package/dist/core/story-logger.js +265 -0
  84. package/dist/core/story-logger.js.map +1 -0
  85. package/dist/core/story.d.ts +133 -20
  86. package/dist/core/story.d.ts.map +1 -1
  87. package/dist/core/story.js +426 -61
  88. package/dist/core/story.js.map +1 -1
  89. package/dist/core/workflow-state.d.ts +45 -6
  90. package/dist/core/workflow-state.d.ts.map +1 -1
  91. package/dist/core/workflow-state.js +201 -12
  92. package/dist/core/workflow-state.js.map +1 -1
  93. package/dist/core/worktree.d.ts +77 -0
  94. package/dist/core/worktree.d.ts.map +1 -0
  95. package/dist/core/worktree.js +246 -0
  96. package/dist/core/worktree.js.map +1 -0
  97. package/dist/index.js +135 -5
  98. package/dist/index.js.map +1 -1
  99. package/dist/types/index.d.ts +163 -1
  100. package/dist/types/index.d.ts.map +1 -1
  101. package/dist/types/index.js +1 -0
  102. package/dist/types/index.js.map +1 -1
  103. package/package.json +3 -1
@@ -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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"}
@@ -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,34 +49,68 @@ 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
- * Generate a unique story ID
54
+ * Generate a unique story ID in sequential format (S-0001, S-0002, etc.)
55
+ * Scans the stories folder to find the highest existing number.
56
+ *
57
+ * @param storiesFolder - Path to the stories directory
58
+ * @returns Sequential story ID like "S-0001"
59
+ */
60
+ export declare function generateStoryId(storiesFolder?: string): string;
61
+ /**
62
+ * Generate a legacy story ID (for backwards compatibility/fallback)
63
+ * @deprecated Use generateStoryId() instead
33
64
  */
34
- export declare function generateStoryId(): string;
65
+ export declare function generateLegacyStoryId(): string;
35
66
  /**
36
67
  * Create a slug from a title
37
68
  */
38
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;
39
90
  /**
40
91
  * Create a new story in the folder-per-story structure
41
92
  *
42
93
  * Creates stories/{id}/story.md with slug and priority in frontmatter.
43
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)
44
100
  */
45
- export declare function createStory(title: string, sdlcRoot: string, options?: Partial<StoryFrontmatter>): Story;
101
+ export declare function createStory(title: string, sdlcRoot: string, options?: Partial<StoryFrontmatter>, content?: string): Promise<Story>;
46
102
  /**
47
103
  * Update story frontmatter field
48
104
  */
49
- 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>;
50
106
  /**
51
107
  * Append content to a section in the story
52
108
  */
53
- export declare function appendToSection(story: Story, section: string, content: string): Story;
109
+ export declare function appendToSection(story: Story, section: string, content: string): Promise<Story>;
54
110
  /**
55
111
  * Record a refinement attempt in the story's frontmatter
56
112
  */
57
- export declare function recordRefinementAttempt(story: Story, agentType: string, reviewFeedback: string): Story;
113
+ export declare function recordRefinementAttempt(story: Story, agentType: string, reviewFeedback: string): Promise<Story>;
58
114
  /**
59
115
  * Get the current refinement count for a story
60
116
  */
@@ -66,7 +122,7 @@ export declare function canRetryRefinement(story: Story, maxAttempts: number): b
66
122
  /**
67
123
  * Reset phase completion flags for rework
68
124
  */
69
- export declare function resetPhaseCompletion(story: Story, phase: 'research' | 'plan' | 'implement'): Story;
125
+ export declare function resetPhaseCompletion(story: Story, phase: 'research' | 'plan' | 'implement'): Promise<Story>;
70
126
  /**
71
127
  * Get the latest review feedback from the story content
72
128
  */
@@ -74,7 +130,7 @@ export declare function getLatestReviewFeedback(story: Story): string | null;
74
130
  /**
75
131
  * Append refinement feedback to the story content
76
132
  */
77
- export declare function appendRefinementNote(story: Story, iteration: number, feedback: string): Story;
133
+ export declare function appendRefinementNote(story: Story, iteration: number, feedback: string): Promise<Story>;
78
134
  /**
79
135
  * Get the effective maximum retries for a story (story-specific or config default)
80
136
  */
@@ -87,15 +143,15 @@ export declare function isAtMaxRetries(story: Story, config: Config, maxIteratio
87
143
  /**
88
144
  * Increment the retry count for a story
89
145
  */
90
- export declare function incrementRetryCount(story: Story): Story;
146
+ export declare function incrementRetryCount(story: Story): Promise<Story>;
91
147
  /**
92
148
  * Reset RPIV cycle for a story (keep research, reset plan/implementation/reviews)
93
149
  */
94
- export declare function resetRPIVCycle(story: Story, reason: string): Story;
150
+ export declare function resetRPIVCycle(story: Story, reason: string): Promise<Story>;
95
151
  /**
96
152
  * Append a review attempt to the story's review history
97
153
  */
98
- export declare function appendReviewHistory(story: Story, attempt: ReviewAttempt): Story;
154
+ export declare function appendReviewHistory(story: Story, attempt: ReviewAttempt): Promise<Story>;
99
155
  /**
100
156
  * Get the latest review attempt from a story's history
101
157
  */
@@ -103,17 +159,74 @@ export declare function getLatestReviewAttempt(story: Story): ReviewAttempt | nu
103
159
  /**
104
160
  * Mark a story as complete (all workflow flags set to true)
105
161
  */
106
- export declare function markStoryComplete(story: Story): Story;
162
+ export declare function markStoryComplete(story: Story): Promise<Story>;
107
163
  /**
108
164
  * Snapshot max_retries from config to story frontmatter (for mid-cycle config change protection)
109
165
  */
110
- export declare function snapshotMaxRetries(story: Story, config: Config): Story;
166
+ export declare function snapshotMaxRetries(story: Story, config: Config): Promise<Story>;
167
+ /**
168
+ * Get the current implementation retry count for a story
169
+ */
170
+ export declare function getImplementationRetryCount(story: Story): number;
171
+ /**
172
+ * Get the effective maximum implementation retries for a story (story-specific or config default)
173
+ * Story-specific overrides are capped at the upper bound to prevent resource exhaustion
174
+ */
175
+ export declare function getEffectiveMaxImplementationRetries(story: Story, config: Config): number;
176
+ /**
177
+ * Check if a story has reached its maximum implementation retry limit.
178
+ * maxRetries represents the number of RETRY attempts allowed after the initial attempt.
179
+ * So with maxRetries=1, you get 1 initial attempt + 1 retry = 2 total attempts.
180
+ */
181
+ export declare function isAtMaxImplementationRetries(story: Story, config: Config): boolean;
182
+ /**
183
+ * Reset implementation retry count to 0
184
+ */
185
+ export declare function resetImplementationRetryCount(story: Story): Promise<Story>;
186
+ /**
187
+ * Increment the implementation retry count for a story
188
+ */
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;
111
202
  /**
112
203
  * Sanitize user-controlled text for safe display and storage.
113
204
  * Removes ANSI escape sequences, control characters, and potential injection vectors.
114
205
  * Truncates to 200 characters maximum.
115
206
  */
116
207
  export declare function sanitizeReasonText(text: string): string;
208
+ /**
209
+ * Find a story by ID using O(1) direct path lookup
210
+ * Falls back to searching old folder structure for backwards compatibility
211
+ *
212
+ * This function is the internal lookup mechanism. Use getStory() for external access.
213
+ *
214
+ * @param sdlcRoot - Root directory of the SDLC workspace
215
+ * @param storyId - Story ID (e.g., 'S-0001')
216
+ * @returns Story object or null if not found
217
+ */
218
+ export declare function findStoryById(sdlcRoot: string, storyId: string): Story | null;
219
+ /**
220
+ * Retrieves a story by ID, resolving its current location across all folders.
221
+ * This is the single source of truth for story lookup - use this instead of
222
+ * directly calling parseStory() with cached paths.
223
+ *
224
+ * @param sdlcRoot - Root directory of the SDLC workspace
225
+ * @param storyId - Story ID (e.g., 'S-0001')
226
+ * @returns Fully parsed Story object with current path and metadata
227
+ * @throws Error if story ID not found in any folder
228
+ */
229
+ export declare function getStory(sdlcRoot: string, storyId: string): Story;
117
230
  /**
118
231
  * Unblock a story and set status back to in-progress
119
232
  * In the new architecture, this only updates frontmatter - file path remains unchanged
@@ -125,5 +238,5 @@ export declare function sanitizeReasonText(text: string): string;
125
238
  */
126
239
  export declare function unblockStory(storyId: string, sdlcRoot: string, options?: {
127
240
  resetRetries?: boolean;
128
- }): Story;
241
+ }): Promise<Story>;
129
242
  //# sourceMappingURL=story.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"story.d.ts","sourceRoot":"","sources":["../../src/core/story.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"story.d.ts","sourceRoot":"","sources":["../../src/core/story.ts"],"names":[],"mappings":"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"}