@girardmedia/bootspring 2.1.1 → 2.1.2
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/cli/build.js
CHANGED
|
@@ -1229,6 +1229,83 @@ ${c.bold}Next steps:${c.reset}
|
|
|
1229
1229
|
`);
|
|
1230
1230
|
}
|
|
1231
1231
|
|
|
1232
|
+
/**
|
|
1233
|
+
* Extract non-task supplementary content from TASK_QUEUE.md.
|
|
1234
|
+
* Captures context notes, architecture diagrams, integration guidelines,
|
|
1235
|
+
* and any section that isn't the task table or per-task detail blocks.
|
|
1236
|
+
*/
|
|
1237
|
+
function extractSupplementaryContent(queueContent) {
|
|
1238
|
+
const lines = queueContent.split('\n');
|
|
1239
|
+
const sections = [];
|
|
1240
|
+
let currentSection = null;
|
|
1241
|
+
let inTaskTable = false;
|
|
1242
|
+
let inTaskDetail = false;
|
|
1243
|
+
|
|
1244
|
+
for (let i = 0; i < lines.length; i++) {
|
|
1245
|
+
const line = lines[i];
|
|
1246
|
+
|
|
1247
|
+
// Detect task table (starts with | Position | or | # |)
|
|
1248
|
+
if (/^\|\s*(Position|#)\s*\|/.test(line)) {
|
|
1249
|
+
inTaskTable = true;
|
|
1250
|
+
continue;
|
|
1251
|
+
}
|
|
1252
|
+
// Still in task table (rows starting with |)
|
|
1253
|
+
if (inTaskTable && /^\|/.test(line)) {
|
|
1254
|
+
continue;
|
|
1255
|
+
}
|
|
1256
|
+
if (inTaskTable && !/^\|/.test(line)) {
|
|
1257
|
+
inTaskTable = false;
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
// Detect per-task detail blocks (### task-XXX: or ### bs-XXX:)
|
|
1261
|
+
if (/^###\s+(task-\d+|bs-\d+)\s*:/.test(line)) {
|
|
1262
|
+
inTaskDetail = true;
|
|
1263
|
+
continue;
|
|
1264
|
+
}
|
|
1265
|
+
// End task detail at next ### or ## heading
|
|
1266
|
+
if (inTaskDetail && /^#{2,3}\s+/.test(line) && !/^###\s+(task-\d+|bs-\d+)\s*:/.test(line)) {
|
|
1267
|
+
inTaskDetail = false;
|
|
1268
|
+
}
|
|
1269
|
+
if (inTaskDetail) continue;
|
|
1270
|
+
|
|
1271
|
+
// Skip the header, queue status heading, and generated boilerplate
|
|
1272
|
+
if (/^#\s+.*Implementation Queue/.test(line)) continue;
|
|
1273
|
+
if (/^>\s*(Ordered task queue|Last Updated|Current Version)/.test(line)) continue;
|
|
1274
|
+
if (/^## Queue Status/.test(line)) { inTaskTable = true; continue; }
|
|
1275
|
+
if (/^## Task Details/.test(line)) { inTaskDetail = true; continue; }
|
|
1276
|
+
if (/^\*Generated by/.test(line)) continue;
|
|
1277
|
+
if (/^---$/.test(line.trim())) continue;
|
|
1278
|
+
|
|
1279
|
+
// Detect section headings for supplementary content
|
|
1280
|
+
if (/^##\s+/.test(line) && !/^## (Queue Status|Task Details|Execution Guidelines)/.test(line)) {
|
|
1281
|
+
if (currentSection) sections.push(currentSection);
|
|
1282
|
+
currentSection = { heading: line, lines: [] };
|
|
1283
|
+
continue;
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1286
|
+
// Execution Guidelines is useful — keep it
|
|
1287
|
+
if (/^## Execution Guidelines/.test(line)) {
|
|
1288
|
+
if (currentSection) sections.push(currentSection);
|
|
1289
|
+
currentSection = { heading: line, lines: [] };
|
|
1290
|
+
continue;
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
if (currentSection) {
|
|
1294
|
+
currentSection.lines.push(line);
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
if (currentSection) sections.push(currentSection);
|
|
1299
|
+
|
|
1300
|
+
// Filter out empty sections and build output
|
|
1301
|
+
const output = sections
|
|
1302
|
+
.filter(s => s.lines.some(l => l.trim().length > 0))
|
|
1303
|
+
.map(s => `${s.heading}\n\n${s.lines.join('\n').trim()}`)
|
|
1304
|
+
.join('\n\n---\n\n');
|
|
1305
|
+
|
|
1306
|
+
return output.trim();
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1232
1309
|
/**
|
|
1233
1310
|
* Migrate from TASK_QUEUE.md to TODO.md as single source of truth.
|
|
1234
1311
|
*/
|
|
@@ -1266,17 +1343,33 @@ ${c.cyan}${c.bold}Migrating to TODO.md as Single Source of Truth${c.reset}
|
|
|
1266
1343
|
}
|
|
1267
1344
|
}
|
|
1268
1345
|
|
|
1269
|
-
// Step 2:
|
|
1346
|
+
// Step 2: Extract non-task content from TASK_QUEUE.md (context notes, diagrams, guidelines)
|
|
1347
|
+
let supplementaryContent = '';
|
|
1348
|
+
if (fs.existsSync(queuePath)) {
|
|
1349
|
+
const queueContent = fs.readFileSync(queuePath, 'utf-8');
|
|
1350
|
+
supplementaryContent = extractSupplementaryContent(queueContent);
|
|
1351
|
+
}
|
|
1352
|
+
|
|
1353
|
+
// Step 3: Generate enriched TODO.md with full task metadata
|
|
1270
1354
|
const planningTemplate = require('../generators/templates/build-planning.template');
|
|
1271
|
-
|
|
1355
|
+
let todo = planningTemplate.generateTodo(state.implementationQueue, {
|
|
1272
1356
|
projectName: state.projectName
|
|
1273
1357
|
});
|
|
1358
|
+
|
|
1359
|
+
// Append supplementary content if any was extracted
|
|
1360
|
+
if (supplementaryContent) {
|
|
1361
|
+
todo += `\n---\n\n## Reference (from TASK_QUEUE.md)\n\n${supplementaryContent}\n`;
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1274
1364
|
fs.writeFileSync(todoPath, todo);
|
|
1275
1365
|
|
|
1276
1366
|
const stats = buildState.getStats(projectRoot);
|
|
1277
1367
|
console.log(`${c.green}✓${c.reset} Generated TODO.md with ${state.implementationQueue.length} tasks (${stats?.completed || 0} completed)`);
|
|
1368
|
+
if (supplementaryContent) {
|
|
1369
|
+
console.log(`${c.green}✓${c.reset} Preserved supplementary content (context notes, diagrams, guidelines)`);
|
|
1370
|
+
}
|
|
1278
1371
|
|
|
1279
|
-
// Step
|
|
1372
|
+
// Step 4: Archive TASK_QUEUE.md unless --keep-queue
|
|
1280
1373
|
if (fs.existsSync(queuePath) && !keepQueue) {
|
|
1281
1374
|
const archivePath = path.join(planningDir, 'TASK_QUEUE.md.bak');
|
|
1282
1375
|
fs.renameSync(queuePath, archivePath);
|
|
@@ -1290,7 +1383,8 @@ ${c.green}${c.bold}Migration complete${c.reset}
|
|
|
1290
1383
|
|
|
1291
1384
|
${c.bold}What changed:${c.reset}
|
|
1292
1385
|
- ${c.cyan}planning/TODO.md${c.reset} is now the single source of truth
|
|
1293
|
-
- Task IDs, acceptance criteria, and status are all inline
|
|
1386
|
+
- Task IDs, source, description, acceptance criteria, and status are all inline
|
|
1387
|
+
- Non-task content (context notes, diagrams, guidelines) preserved in Reference section
|
|
1294
1388
|
- Build loop reads TODO.md instead of TASK_QUEUE.md
|
|
1295
1389
|
${!keepQueue && fs.existsSync(path.join(planningDir, 'TASK_QUEUE.md.bak')) ? ` - Old TASK_QUEUE.md archived as TASK_QUEUE.md.bak
|
|
1296
1390
|
` : ''}
|
|
@@ -288,7 +288,28 @@ function generateTodo(tasks, options = {}) {
|
|
|
288
288
|
task.status === 'skipped' ? ' (`skipped`)' : '';
|
|
289
289
|
content += `- ${checkbox} \`${task.id}\` ${task.title}${statusTag}\n`;
|
|
290
290
|
|
|
291
|
-
//
|
|
291
|
+
// Source traceability
|
|
292
|
+
if (task.source) {
|
|
293
|
+
const sourceStr = task.sourceSection
|
|
294
|
+
? `${task.source} (${task.sourceSection})`
|
|
295
|
+
: task.source;
|
|
296
|
+
content += ` - **Source:** ${sourceStr}\n`;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// Description
|
|
300
|
+
if (task.description) {
|
|
301
|
+
content += ` - **Description:** ${task.description}\n`;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// Complexity and dependencies
|
|
305
|
+
if (task.estimatedComplexity && task.estimatedComplexity !== 'medium') {
|
|
306
|
+
content += ` - **Complexity:** ${task.estimatedComplexity}\n`;
|
|
307
|
+
}
|
|
308
|
+
if (task.dependencies && task.dependencies.length > 0) {
|
|
309
|
+
content += ` - **Dependencies:** ${task.dependencies.join(', ')}\n`;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// Acceptance criteria as sub-items (all of them — this is the source of truth)
|
|
292
313
|
if (task.acceptanceCriteria && task.acceptanceCriteria.length > 0) {
|
|
293
314
|
for (const criteria of task.acceptanceCriteria) {
|
|
294
315
|
const subCheckbox = task.status === 'completed' ? '[x]' : '[ ]';
|