@ginkoai/cli 2.0.5 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/epic/index.d.ts +29 -0
- package/dist/commands/epic/index.d.ts.map +1 -0
- package/dist/commands/epic/index.js +94 -0
- package/dist/commands/epic/index.js.map +1 -0
- package/dist/commands/epic/status.d.ts +40 -0
- package/dist/commands/epic/status.d.ts.map +1 -0
- package/dist/commands/epic/status.js +244 -0
- package/dist/commands/epic/status.js.map +1 -0
- package/dist/commands/graph/api-client.d.ts +209 -0
- package/dist/commands/graph/api-client.d.ts.map +1 -1
- package/dist/commands/graph/api-client.js +125 -0
- package/dist/commands/graph/api-client.js.map +1 -1
- package/dist/commands/graph/load.d.ts.map +1 -1
- package/dist/commands/graph/load.js +40 -2
- package/dist/commands/graph/load.js.map +1 -1
- package/dist/commands/migrate/index.d.ts +27 -0
- package/dist/commands/migrate/index.d.ts.map +1 -0
- package/dist/commands/migrate/index.js +76 -0
- package/dist/commands/migrate/index.js.map +1 -0
- package/dist/commands/migrate/status-migration.d.ts +58 -0
- package/dist/commands/migrate/status-migration.d.ts.map +1 -0
- package/dist/commands/migrate/status-migration.js +323 -0
- package/dist/commands/migrate/status-migration.js.map +1 -0
- package/dist/commands/sprint/index.d.ts.map +1 -1
- package/dist/commands/sprint/index.js +4 -0
- package/dist/commands/sprint/index.js.map +1 -1
- package/dist/commands/sprint/status.d.ts +42 -0
- package/dist/commands/sprint/status.d.ts.map +1 -0
- package/dist/commands/sprint/status.js +278 -0
- package/dist/commands/sprint/status.js.map +1 -0
- package/dist/commands/start/start-reflection.d.ts +39 -0
- package/dist/commands/start/start-reflection.d.ts.map +1 -1
- package/dist/commands/start/start-reflection.js +311 -91
- package/dist/commands/start/start-reflection.js.map +1 -1
- package/dist/commands/sync/sprint-syncer.d.ts +19 -12
- package/dist/commands/sync/sprint-syncer.d.ts.map +1 -1
- package/dist/commands/sync/sprint-syncer.js +58 -140
- package/dist/commands/sync/sprint-syncer.js.map +1 -1
- package/dist/commands/sync/sync-command.d.ts.map +1 -1
- package/dist/commands/sync/sync-command.js +6 -18
- package/dist/commands/sync/sync-command.js.map +1 -1
- package/dist/commands/task/index.d.ts +25 -0
- package/dist/commands/task/index.d.ts.map +1 -0
- package/dist/commands/task/index.js +100 -0
- package/dist/commands/task/index.js.map +1 -0
- package/dist/commands/task/status.d.ts +43 -0
- package/dist/commands/task/status.d.ts.map +1 -0
- package/dist/commands/task/status.js +301 -0
- package/dist/commands/task/status.js.map +1 -0
- package/dist/index.js +12 -29
- package/dist/index.js.map +1 -1
- package/dist/lib/context-loader-events.d.ts +1 -0
- package/dist/lib/context-loader-events.d.ts.map +1 -1
- package/dist/lib/context-loader-events.js +28 -41
- package/dist/lib/context-loader-events.js.map +1 -1
- package/dist/lib/output-formatter.d.ts +12 -4
- package/dist/lib/output-formatter.d.ts.map +1 -1
- package/dist/lib/output-formatter.js +186 -14
- package/dist/lib/output-formatter.js.map +1 -1
- package/dist/lib/pending-updates.d.ts +148 -0
- package/dist/lib/pending-updates.d.ts.map +1 -0
- package/dist/lib/pending-updates.js +301 -0
- package/dist/lib/pending-updates.js.map +1 -0
- package/dist/lib/sprint-loader.d.ts +86 -14
- package/dist/lib/sprint-loader.d.ts.map +1 -1
- package/dist/lib/sprint-loader.js +293 -98
- package/dist/lib/sprint-loader.js.map +1 -1
- package/dist/lib/state-cache.d.ts +142 -0
- package/dist/lib/state-cache.d.ts.map +1 -0
- package/dist/lib/state-cache.js +259 -0
- package/dist/lib/state-cache.js.map +1 -0
- package/dist/lib/task-graph-sync.d.ts +105 -0
- package/dist/lib/task-graph-sync.d.ts.map +1 -0
- package/dist/lib/task-graph-sync.js +178 -0
- package/dist/lib/task-graph-sync.js.map +1 -0
- package/dist/lib/task-parser.d.ts +107 -0
- package/dist/lib/task-parser.d.ts.map +1 -0
- package/dist/lib/task-parser.js +384 -0
- package/dist/lib/task-parser.js.map +1 -0
- package/dist/templates/ai-instructions-template.d.ts.map +1 -1
- package/dist/templates/ai-instructions-template.js +7 -5
- package/dist/templates/ai-instructions-template.js.map +1 -1
- package/dist/templates/epic-template.md +0 -2
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/config.js +7 -5
- package/dist/types/config.js.map +1 -1
- package/dist/utils/synthesis.d.ts +4 -0
- package/dist/utils/synthesis.d.ts.map +1 -1
- package/dist/utils/synthesis.js +12 -18
- package/dist/utils/synthesis.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileType: utility
|
|
3
|
+
* @status: current
|
|
4
|
+
* @updated: 2026-01-19
|
|
5
|
+
* @tags: [offline, queue, sync, EPIC-015]
|
|
6
|
+
* @related: [state-cache.ts, api-client.ts]
|
|
7
|
+
* @priority: medium
|
|
8
|
+
* @complexity: medium
|
|
9
|
+
* @dependencies: [fs-extra, path]
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Pending Updates Queue (EPIC-015 Sprint 2 Task 6)
|
|
13
|
+
*
|
|
14
|
+
* Provides offline queueing for status updates when API is unavailable:
|
|
15
|
+
* - Queue status updates when offline
|
|
16
|
+
* - Process queued updates when back online
|
|
17
|
+
* - "Local wins" conflict resolution (queued update takes precedence)
|
|
18
|
+
* - Max 3 retry attempts before permanent failure
|
|
19
|
+
*
|
|
20
|
+
* Queue location: .ginko/pending-updates.json
|
|
21
|
+
* Uses atomic writes (temp file + rename) to prevent partial writes.
|
|
22
|
+
*/
|
|
23
|
+
import fs from 'fs-extra';
|
|
24
|
+
import path from 'path';
|
|
25
|
+
import { randomUUID } from 'crypto';
|
|
26
|
+
import { getGinkoDir } from '../utils/helpers.js';
|
|
27
|
+
// =============================================================================
|
|
28
|
+
// Constants
|
|
29
|
+
// =============================================================================
|
|
30
|
+
const QUEUE_FILE = 'pending-updates.json';
|
|
31
|
+
const QUEUE_VERSION = 1;
|
|
32
|
+
const MAX_ATTEMPTS = 3;
|
|
33
|
+
// =============================================================================
|
|
34
|
+
// Queue Management
|
|
35
|
+
// =============================================================================
|
|
36
|
+
/**
|
|
37
|
+
* Load pending updates from disk
|
|
38
|
+
*
|
|
39
|
+
* @returns Array of pending updates, empty array if no queue file exists
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```typescript
|
|
43
|
+
* const updates = await loadPendingUpdates();
|
|
44
|
+
* console.log(`${updates.length} updates pending`);
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
export async function loadPendingUpdates() {
|
|
48
|
+
try {
|
|
49
|
+
const queuePath = await getQueuePath();
|
|
50
|
+
if (!await fs.pathExists(queuePath)) {
|
|
51
|
+
return [];
|
|
52
|
+
}
|
|
53
|
+
const data = await fs.readJSON(queuePath);
|
|
54
|
+
// Validate queue structure
|
|
55
|
+
if (!isValidQueue(data)) {
|
|
56
|
+
return [];
|
|
57
|
+
}
|
|
58
|
+
return data.updates || [];
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
// File doesn't exist, is invalid JSON, or other read error
|
|
62
|
+
return [];
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Queue a status update for later sync
|
|
67
|
+
* Used when API call fails due to network error
|
|
68
|
+
*
|
|
69
|
+
* @param update - Update to queue (id, queued_at, attempts added automatically)
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```typescript
|
|
73
|
+
* await queueUpdate({
|
|
74
|
+
* type: 'task_status',
|
|
75
|
+
* entity_id: 'e015_s02_t01',
|
|
76
|
+
* new_status: 'complete'
|
|
77
|
+
* });
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
export async function queueUpdate(update) {
|
|
81
|
+
const updates = await loadPendingUpdates();
|
|
82
|
+
// Check if there's already a pending update for this entity
|
|
83
|
+
// If so, replace it (latest update wins)
|
|
84
|
+
const existingIndex = updates.findIndex(u => u.entity_id === update.entity_id && u.type === update.type);
|
|
85
|
+
const newUpdate = {
|
|
86
|
+
id: randomUUID(),
|
|
87
|
+
...update,
|
|
88
|
+
queued_at: new Date().toISOString(),
|
|
89
|
+
attempts: 0,
|
|
90
|
+
};
|
|
91
|
+
if (existingIndex >= 0) {
|
|
92
|
+
// Replace existing update for same entity
|
|
93
|
+
updates[existingIndex] = newUpdate;
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
// Add new update
|
|
97
|
+
updates.push(newUpdate);
|
|
98
|
+
}
|
|
99
|
+
await saveQueue(updates);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Remove a specific update from the queue
|
|
103
|
+
*
|
|
104
|
+
* @param updateId - UUID of the update to remove
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* ```typescript
|
|
108
|
+
* await removeUpdate('abc-123-def');
|
|
109
|
+
* ```
|
|
110
|
+
*/
|
|
111
|
+
export async function removeUpdate(updateId) {
|
|
112
|
+
const updates = await loadPendingUpdates();
|
|
113
|
+
const filtered = updates.filter(u => u.id !== updateId);
|
|
114
|
+
if (filtered.length !== updates.length) {
|
|
115
|
+
await saveQueue(filtered);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Clear all pending updates from the queue
|
|
120
|
+
*
|
|
121
|
+
* @example
|
|
122
|
+
* ```typescript
|
|
123
|
+
* await clearPendingUpdates();
|
|
124
|
+
* ```
|
|
125
|
+
*/
|
|
126
|
+
export async function clearPendingUpdates() {
|
|
127
|
+
try {
|
|
128
|
+
const queuePath = await getQueuePath();
|
|
129
|
+
if (await fs.pathExists(queuePath)) {
|
|
130
|
+
await fs.remove(queuePath);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
// Ignore errors when clearing queue
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Check if there are pending updates
|
|
139
|
+
*
|
|
140
|
+
* @returns true if queue has at least one update
|
|
141
|
+
*
|
|
142
|
+
* @example
|
|
143
|
+
* ```typescript
|
|
144
|
+
* if (await hasPendingUpdates()) {
|
|
145
|
+
* console.log('Pending updates need to sync');
|
|
146
|
+
* }
|
|
147
|
+
* ```
|
|
148
|
+
*/
|
|
149
|
+
export async function hasPendingUpdates() {
|
|
150
|
+
const updates = await loadPendingUpdates();
|
|
151
|
+
return updates.length > 0;
|
|
152
|
+
}
|
|
153
|
+
// =============================================================================
|
|
154
|
+
// Sync Processing
|
|
155
|
+
// =============================================================================
|
|
156
|
+
/**
|
|
157
|
+
* Process all pending updates, syncing them to the API
|
|
158
|
+
*
|
|
159
|
+
* Processing logic:
|
|
160
|
+
* - Iterates oldest-first (FIFO order)
|
|
161
|
+
* - On success: removes update from queue
|
|
162
|
+
* - On failure: increments attempts, keeps in queue (max 3 attempts)
|
|
163
|
+
* - Conflict resolution: "local wins" (queued update takes precedence)
|
|
164
|
+
*
|
|
165
|
+
* @param client - Authenticated GraphApiClient instance
|
|
166
|
+
* @returns Counts of succeeded and failed updates
|
|
167
|
+
*
|
|
168
|
+
* @example
|
|
169
|
+
* ```typescript
|
|
170
|
+
* const client = new GraphApiClient();
|
|
171
|
+
* const result = await processPendingUpdates(client);
|
|
172
|
+
* console.log(`Synced ${result.succeeded}, failed ${result.failed}`);
|
|
173
|
+
* ```
|
|
174
|
+
*/
|
|
175
|
+
export async function processPendingUpdates(client) {
|
|
176
|
+
const updates = await loadPendingUpdates();
|
|
177
|
+
if (updates.length === 0) {
|
|
178
|
+
return { succeeded: 0, failed: 0 };
|
|
179
|
+
}
|
|
180
|
+
let succeeded = 0;
|
|
181
|
+
let failed = 0;
|
|
182
|
+
const remaining = [];
|
|
183
|
+
// Get graph ID from environment
|
|
184
|
+
const graphId = process.env.GINKO_GRAPH_ID || '';
|
|
185
|
+
if (!graphId) {
|
|
186
|
+
// Can't process without graph ID, keep all updates
|
|
187
|
+
return { succeeded: 0, failed: updates.length };
|
|
188
|
+
}
|
|
189
|
+
// Sort by queued_at to process oldest first
|
|
190
|
+
const sortedUpdates = [...updates].sort((a, b) => new Date(a.queued_at).getTime() - new Date(b.queued_at).getTime());
|
|
191
|
+
for (const update of sortedUpdates) {
|
|
192
|
+
try {
|
|
193
|
+
await processUpdate(client, graphId, update);
|
|
194
|
+
succeeded++;
|
|
195
|
+
// Don't add to remaining - it was successful
|
|
196
|
+
}
|
|
197
|
+
catch (error) {
|
|
198
|
+
// Increment attempts
|
|
199
|
+
update.attempts++;
|
|
200
|
+
if (update.attempts >= MAX_ATTEMPTS) {
|
|
201
|
+
// Max attempts reached, count as failed and don't keep
|
|
202
|
+
failed++;
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
// Keep in queue for retry
|
|
206
|
+
remaining.push(update);
|
|
207
|
+
failed++;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
// Save remaining updates (excluding succeeded and permanently failed)
|
|
212
|
+
await saveQueue(remaining);
|
|
213
|
+
return { succeeded, failed };
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Process a single update by calling the appropriate API method
|
|
217
|
+
*/
|
|
218
|
+
async function processUpdate(client, graphId, update) {
|
|
219
|
+
switch (update.type) {
|
|
220
|
+
case 'task_status':
|
|
221
|
+
await client.updateTaskStatus(graphId, update.entity_id, update.new_status, update.reason);
|
|
222
|
+
break;
|
|
223
|
+
case 'sprint_status':
|
|
224
|
+
await client.updateSprintStatus(graphId, update.entity_id, update.new_status);
|
|
225
|
+
break;
|
|
226
|
+
case 'epic_status':
|
|
227
|
+
await client.updateEpicStatus(graphId, update.entity_id, update.new_status);
|
|
228
|
+
break;
|
|
229
|
+
default:
|
|
230
|
+
throw new Error(`Unknown update type: ${update.type}`);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
// =============================================================================
|
|
234
|
+
// Helper Functions
|
|
235
|
+
// =============================================================================
|
|
236
|
+
/**
|
|
237
|
+
* Get the full path to the queue file
|
|
238
|
+
*/
|
|
239
|
+
async function getQueuePath() {
|
|
240
|
+
const ginkoDir = await getGinkoDir();
|
|
241
|
+
return path.join(ginkoDir, QUEUE_FILE);
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Save updates to queue file using atomic write
|
|
245
|
+
*/
|
|
246
|
+
async function saveQueue(updates) {
|
|
247
|
+
const queuePath = await getQueuePath();
|
|
248
|
+
const queueDir = path.dirname(queuePath);
|
|
249
|
+
const tempPath = `${queuePath}.tmp.${Date.now()}`;
|
|
250
|
+
// Ensure .ginko directory exists
|
|
251
|
+
await fs.ensureDir(queueDir);
|
|
252
|
+
const queue = {
|
|
253
|
+
version: QUEUE_VERSION,
|
|
254
|
+
updates,
|
|
255
|
+
};
|
|
256
|
+
// Atomic write: write to temp file, then rename
|
|
257
|
+
try {
|
|
258
|
+
await fs.writeJSON(tempPath, queue, { spaces: 2 });
|
|
259
|
+
await fs.rename(tempPath, queuePath);
|
|
260
|
+
}
|
|
261
|
+
catch (error) {
|
|
262
|
+
// Clean up temp file if rename failed
|
|
263
|
+
try {
|
|
264
|
+
await fs.remove(tempPath);
|
|
265
|
+
}
|
|
266
|
+
catch {
|
|
267
|
+
// Ignore cleanup errors
|
|
268
|
+
}
|
|
269
|
+
throw error;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Validate that queue data has correct structure and version
|
|
274
|
+
*/
|
|
275
|
+
function isValidQueue(data) {
|
|
276
|
+
if (!data || typeof data !== 'object') {
|
|
277
|
+
return false;
|
|
278
|
+
}
|
|
279
|
+
const queue = data;
|
|
280
|
+
// Check version
|
|
281
|
+
if (queue.version !== QUEUE_VERSION) {
|
|
282
|
+
return false;
|
|
283
|
+
}
|
|
284
|
+
// Check updates array exists
|
|
285
|
+
if (!Array.isArray(queue.updates)) {
|
|
286
|
+
return false;
|
|
287
|
+
}
|
|
288
|
+
return true;
|
|
289
|
+
}
|
|
290
|
+
// =============================================================================
|
|
291
|
+
// Exports for Testing
|
|
292
|
+
// =============================================================================
|
|
293
|
+
export const _internal = {
|
|
294
|
+
getQueuePath,
|
|
295
|
+
saveQueue,
|
|
296
|
+
isValidQueue,
|
|
297
|
+
processUpdate,
|
|
298
|
+
QUEUE_VERSION,
|
|
299
|
+
MAX_ATTEMPTS,
|
|
300
|
+
};
|
|
301
|
+
//# sourceMappingURL=pending-updates.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pending-updates.js","sourceRoot":"","sources":["../../src/lib/pending-updates.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,21 +1,49 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileType: utility
|
|
3
3
|
* @status: current
|
|
4
|
-
* @updated:
|
|
5
|
-
* @tags: [sprint, task-
|
|
6
|
-
* @related: [charter-loader.ts, start-reflection.ts, context-loader-events.ts]
|
|
4
|
+
* @updated: 2026-01-19
|
|
5
|
+
* @tags: [sprint, task-content, epic-015, session-context]
|
|
6
|
+
* @related: [charter-loader.ts, start-reflection.ts, context-loader-events.ts, task-extractor.ts]
|
|
7
7
|
* @priority: high
|
|
8
8
|
* @complexity: medium
|
|
9
9
|
* @dependencies: [fs-extra, path]
|
|
10
10
|
*/
|
|
11
11
|
/**
|
|
12
|
-
* Task state enumeration
|
|
12
|
+
* Task state enumeration (kept for backward compatibility)
|
|
13
|
+
* NOTE: As of EPIC-015 Sprint 2, status comes from the graph API.
|
|
14
|
+
* File parsing defaults all tasks to 'todo'. Merge with graph status at runtime.
|
|
13
15
|
* - todo: [ ] Not started
|
|
14
16
|
* - in_progress: [@] Currently being worked on
|
|
15
17
|
* - paused: [Z] Temporarily on hold (sleeping)
|
|
16
18
|
* - complete: [x] Finished
|
|
17
19
|
*/
|
|
18
20
|
export type TaskState = 'todo' | 'in_progress' | 'paused' | 'complete';
|
|
21
|
+
/**
|
|
22
|
+
* Task content extracted from sprint markdown (no status)
|
|
23
|
+
* Status comes from graph API and is merged at runtime.
|
|
24
|
+
*/
|
|
25
|
+
export interface TaskContent {
|
|
26
|
+
id: string;
|
|
27
|
+
title: string;
|
|
28
|
+
files?: string[];
|
|
29
|
+
effort?: string;
|
|
30
|
+
priority?: string;
|
|
31
|
+
relatedADRs?: string[];
|
|
32
|
+
relatedPatterns?: string[];
|
|
33
|
+
relatedGotchas?: string[];
|
|
34
|
+
acceptanceCriteria?: AcceptanceCriterion[];
|
|
35
|
+
dependsOn?: string[];
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Sprint content extracted from markdown (no status-based progress)
|
|
39
|
+
* Status/progress comes from graph API and is merged at runtime.
|
|
40
|
+
*/
|
|
41
|
+
export interface SprintContent {
|
|
42
|
+
name: string;
|
|
43
|
+
file: string;
|
|
44
|
+
tasks: TaskContent[];
|
|
45
|
+
dependencyWarnings?: string[];
|
|
46
|
+
}
|
|
19
47
|
/**
|
|
20
48
|
* Acceptance criterion type - auto-detected from description (EPIC-004 Sprint 3)
|
|
21
49
|
* - test: Unit tests, specs, test suites
|
|
@@ -37,7 +65,9 @@ export interface AcceptanceCriterion {
|
|
|
37
65
|
command?: string;
|
|
38
66
|
}
|
|
39
67
|
/**
|
|
40
|
-
* Individual task from sprint checklist
|
|
68
|
+
* Individual task from sprint checklist (backward compatible interface)
|
|
69
|
+
* NOTE: As of EPIC-015 Sprint 2, state defaults to 'todo' from file parsing.
|
|
70
|
+
* Actual status should be merged from graph API at runtime.
|
|
41
71
|
*/
|
|
42
72
|
export interface Task {
|
|
43
73
|
id: string;
|
|
@@ -54,7 +84,9 @@ export interface Task {
|
|
|
54
84
|
dependsOn?: string[];
|
|
55
85
|
}
|
|
56
86
|
/**
|
|
57
|
-
* Sprint checklist with task states and progress
|
|
87
|
+
* Sprint checklist with task states and progress (backward compatible interface)
|
|
88
|
+
* NOTE: As of EPIC-015 Sprint 2, progress values will be zeroed from file parsing.
|
|
89
|
+
* Actual progress should be calculated from graph API status at runtime.
|
|
58
90
|
*/
|
|
59
91
|
export interface SprintChecklist {
|
|
60
92
|
name: string;
|
|
@@ -75,11 +107,12 @@ export interface SprintChecklist {
|
|
|
75
107
|
* Find active sprint file
|
|
76
108
|
*
|
|
77
109
|
* Priority:
|
|
78
|
-
* 1.
|
|
79
|
-
* 2. Check CURRENT-SPRINT.md for sprint reference → return that file
|
|
80
|
-
* 3. Fall back to scanning SPRINT-*.md files for first incomplete one
|
|
110
|
+
* 1. Scan SPRINT-*.md files for first incomplete one
|
|
81
111
|
* - Respects frontmatter `status` field: active > not_started > (skip paused/complete)
|
|
82
112
|
*
|
|
113
|
+
* EPIC-015 Sprint 3: CURRENT-SPRINT.md is deprecated. Sprint state now comes from
|
|
114
|
+
* the graph API, not from a local file. This function only scans actual sprint files.
|
|
115
|
+
*
|
|
83
116
|
* Valid status values:
|
|
84
117
|
* - active: Currently being worked on
|
|
85
118
|
* - not_started: Planned but not yet started
|
|
@@ -93,25 +126,57 @@ export interface SprintChecklist {
|
|
|
93
126
|
*/
|
|
94
127
|
export declare function findActiveSprint(projectRoot?: string): Promise<string | null>;
|
|
95
128
|
/**
|
|
96
|
-
* Parse sprint markdown into task checklist
|
|
129
|
+
* Parse sprint markdown into task checklist (backward compatible)
|
|
130
|
+
*
|
|
131
|
+
* EPIC-015 Sprint 2: Status parsing removed. All tasks default to 'todo'.
|
|
132
|
+
* Status should be merged from graph API at runtime.
|
|
97
133
|
*
|
|
98
134
|
* Looks for:
|
|
99
135
|
* - Sprint name from title (# SPRINT: ...)
|
|
100
136
|
* - Tasks from ## Sprint Tasks or ### TASK-N sections
|
|
101
|
-
* -
|
|
102
|
-
* -
|
|
137
|
+
* - Task metadata (files, priority, effort, dependencies)
|
|
138
|
+
* - Related knowledge (ADRs, patterns, gotchas)
|
|
139
|
+
* - Acceptance criteria
|
|
103
140
|
*
|
|
104
141
|
* @param markdown - Sprint markdown content
|
|
105
142
|
* @param filePath - Path to sprint file
|
|
106
|
-
* @returns Parsed sprint checklist
|
|
143
|
+
* @returns Parsed sprint checklist (all tasks with state: 'todo')
|
|
107
144
|
*/
|
|
108
145
|
export declare function parseSprintChecklist(markdown: string, filePath: string): SprintChecklist;
|
|
109
146
|
/**
|
|
110
|
-
*
|
|
147
|
+
* Parse sprint markdown into content-only structure (no status)
|
|
148
|
+
*
|
|
149
|
+
* EPIC-015 Sprint 2: New content-focused parsing function.
|
|
150
|
+
* Extracts task content (ID, title, metadata, relationships) without status.
|
|
151
|
+
* Status should be fetched from graph API and merged separately.
|
|
152
|
+
*
|
|
153
|
+
* @param markdown - Sprint markdown content
|
|
154
|
+
* @param filePath - Path to sprint file
|
|
155
|
+
* @returns Parsed sprint content (no status information)
|
|
156
|
+
*/
|
|
157
|
+
export declare function parseSprintContent(markdown: string, filePath: string): SprintContent;
|
|
158
|
+
/**
|
|
159
|
+
* Load active sprint content (no status)
|
|
160
|
+
*
|
|
161
|
+
* EPIC-015 Sprint 2: New content-focused loading function.
|
|
162
|
+
* Finds active sprint file and parses content without status.
|
|
163
|
+
* Status should be fetched from graph API and merged separately.
|
|
164
|
+
*
|
|
165
|
+
* @param projectRoot - Project root directory (defaults to git root)
|
|
166
|
+
* @param sprintFilePath - Optional specific sprint file path
|
|
167
|
+
* @returns Parsed sprint content or null if no sprint found
|
|
168
|
+
*/
|
|
169
|
+
export declare function loadSprintContent(projectRoot?: string, sprintFilePath?: string): Promise<SprintContent | null>;
|
|
170
|
+
/**
|
|
171
|
+
* Load active sprint checklist (backward compatible)
|
|
172
|
+
*
|
|
173
|
+
* EPIC-015 Sprint 2: This function maintained for backward compatibility.
|
|
174
|
+
* All tasks will have state: 'todo'. Merge with graph API status at runtime.
|
|
111
175
|
*
|
|
112
176
|
* Finds active sprint file and parses into structured checklist
|
|
113
177
|
*
|
|
114
178
|
* @param projectRoot - Project root directory (defaults to git root)
|
|
179
|
+
* @param sprintFilePath - Optional specific sprint file path
|
|
115
180
|
* @returns Parsed sprint checklist or null if no sprint found
|
|
116
181
|
*/
|
|
117
182
|
export declare function loadSprintChecklist(projectRoot?: string, sprintFilePath?: string): Promise<SprintChecklist | null>;
|
|
@@ -146,6 +211,13 @@ export interface SprintProgressionInfo {
|
|
|
146
211
|
totalSprints: number;
|
|
147
212
|
completedSprints: number;
|
|
148
213
|
}
|
|
214
|
+
/**
|
|
215
|
+
* Find sprint file by ID
|
|
216
|
+
* @param sprintId - Sprint ID (e.g., 'e011_s01' or 'e016_s03')
|
|
217
|
+
* @param projectRoot - Project root directory
|
|
218
|
+
* @returns Path to sprint file or null if not found
|
|
219
|
+
*/
|
|
220
|
+
export declare function findSprintFileById(sprintId: string, projectRoot: string): Promise<string | null>;
|
|
149
221
|
/**
|
|
150
222
|
* Detect sprint progression and epic completion status
|
|
151
223
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sprint-loader.d.ts","sourceRoot":"","sources":["../../src/lib/sprint-loader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;
|
|
1
|
+
{"version":3,"file":"sprint-loader.d.ts","sourceRoot":"","sources":["../../src/lib/sprint-loader.ts"],"names":[],"mappings":"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"}
|