@ncoderz/awa 1.7.0 → 1.7.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/dist/index.js CHANGED
@@ -24,7 +24,7 @@ import { Command, Option } from "commander";
24
24
  // src/_generated/package_info.ts
25
25
  var PACKAGE_INFO = {
26
26
  "name": "@ncoderz/awa",
27
- "version": "1.7.0",
27
+ "version": "1.7.2",
28
28
  "author": "Richard Sewell <richard.sewell@ncoderz.com>",
29
29
  "license": "MIT",
30
30
  "description": "awa is an Agent Workflow for AIs. It is also a CLI tool to powerfully manage agent workflow files using templates."
@@ -340,20 +340,15 @@ async function collectCodeFiles(codeGlobs, ignore) {
340
340
  import { readFile as readFile2, writeFile } from "fs/promises";
341
341
  import { basename } from "path";
342
342
  async function fixMatrices(specs, crossRefPatterns) {
343
- const codeToReqFile = buildCodeToReqFileMap(specs.specFiles);
343
+ const reqFileMaps = buildReqFileMaps(specs.specFiles);
344
344
  const fileResults = [];
345
345
  for (const specFile of specs.specFiles) {
346
346
  const fileName = basename(specFile.filePath);
347
347
  if (fileName.startsWith("DESIGN-")) {
348
- const changed = await fixDesignMatrix(specFile.filePath, codeToReqFile, crossRefPatterns);
348
+ const changed = await fixDesignMatrix(specFile.filePath, reqFileMaps, crossRefPatterns);
349
349
  fileResults.push({ filePath: specFile.filePath, changed });
350
350
  } else if (fileName.startsWith("TASK-")) {
351
- const changed = await fixTaskMatrix(
352
- specFile.filePath,
353
- codeToReqFile,
354
- specs,
355
- crossRefPatterns
356
- );
351
+ const changed = await fixTaskMatrix(specFile.filePath, reqFileMaps, specs, crossRefPatterns);
357
352
  fileResults.push({ filePath: specFile.filePath, changed });
358
353
  }
359
354
  }
@@ -362,20 +357,45 @@ async function fixMatrices(specs, crossRefPatterns) {
362
357
  fileResults
363
358
  };
364
359
  }
365
- function buildCodeToReqFileMap(specFiles) {
366
- const map = /* @__PURE__ */ new Map();
360
+ function buildReqFileMaps(specFiles) {
361
+ const idToReqFile = /* @__PURE__ */ new Map();
362
+ const codeToReqFilesSet = /* @__PURE__ */ new Map();
367
363
  for (const sf of specFiles) {
368
- if (/\bREQ-/.test(basename(sf.filePath)) && sf.code) {
369
- map.set(sf.code, basename(sf.filePath));
364
+ const fileName = basename(sf.filePath);
365
+ if (!/\bREQ-/.test(fileName)) continue;
366
+ for (const reqId of sf.requirementIds) {
367
+ idToReqFile.set(reqId, fileName);
368
+ }
369
+ for (const acId of sf.acIds) {
370
+ idToReqFile.set(acId, fileName);
370
371
  }
372
+ if (sf.code) {
373
+ const existing = codeToReqFilesSet.get(sf.code) ?? /* @__PURE__ */ new Set();
374
+ existing.add(fileName);
375
+ codeToReqFilesSet.set(sf.code, existing);
376
+ }
377
+ }
378
+ const codeToReqFiles = /* @__PURE__ */ new Map();
379
+ for (const [code, files] of codeToReqFilesSet) {
380
+ codeToReqFiles.set(code, [...files].sort());
371
381
  }
372
- return map;
382
+ return { idToReqFile, codeToReqFiles };
373
383
  }
374
- function getCodePrefix(id) {
375
- const match = /^([A-Z][A-Z0-9]*)[-_]/.exec(id);
376
- return match?.[1] ?? "";
384
+ function resolveReqFile(id, maps) {
385
+ const direct = maps.idToReqFile.get(id);
386
+ if (direct) return direct;
387
+ const acMatch = /^(.+)_AC-\d+$/.exec(id);
388
+ if (acMatch?.[1]) {
389
+ return maps.idToReqFile.get(acMatch[1]);
390
+ }
391
+ const propMatch = /^([A-Z][A-Z0-9]*)_P-\d+$/.exec(id);
392
+ if (propMatch?.[1]) {
393
+ const files = maps.codeToReqFiles.get(propMatch[1]);
394
+ return files?.[0];
395
+ }
396
+ return void 0;
377
397
  }
378
- async function fixDesignMatrix(filePath, codeToReqFile, crossRefPatterns) {
398
+ async function fixDesignMatrix(filePath, reqFileMaps, crossRefPatterns) {
379
399
  let content;
380
400
  try {
381
401
  content = await readFile2(filePath, "utf-8");
@@ -400,7 +420,7 @@ async function fixDesignMatrix(filePath, codeToReqFile, crossRefPatterns) {
400
420
  }
401
421
  }
402
422
  const allAcIds = [...acToComponents.keys()];
403
- const grouped = groupByReqFile(allAcIds, codeToReqFile);
423
+ const grouped = groupByReqFile(allAcIds, reqFileMaps);
404
424
  const newSection = generateDesignSection(grouped, acToComponents, acToProperties);
405
425
  const newContent = replaceTraceabilitySection(content, newSection);
406
426
  if (newContent === content) return false;
@@ -475,14 +495,14 @@ function generateDesignSection(grouped, acToComponents, acToProperties) {
475
495
  }
476
496
  return lines.join("\n");
477
497
  }
478
- async function fixTaskMatrix(filePath, codeToReqFile, specs, crossRefPatterns) {
498
+ async function fixTaskMatrix(filePath, reqFileMaps, specs, crossRefPatterns) {
479
499
  let content;
480
500
  try {
481
501
  content = await readFile2(filePath, "utf-8");
482
502
  } catch {
483
503
  return false;
484
504
  }
485
- const { tasks, sourceReqs, sourceDesigns } = parseTaskFileData(content, crossRefPatterns);
505
+ const { tasks, sourceDesigns } = parseTaskFileData(content, crossRefPatterns);
486
506
  const acToTasks = /* @__PURE__ */ new Map();
487
507
  for (const task of tasks) {
488
508
  for (const acId of task.implements) {
@@ -499,15 +519,6 @@ async function fixTaskMatrix(filePath, codeToReqFile, specs, crossRefPatterns) {
499
519
  idToTestTasks.set(testId, existing);
500
520
  }
501
521
  }
502
- const sourceAcIds = /* @__PURE__ */ new Set();
503
- for (const reqName of sourceReqs) {
504
- const reqCode = extractCodeFromFileName(reqName);
505
- for (const sf of specs.specFiles) {
506
- if (sf.code === reqCode && /\bREQ-/.test(basename(sf.filePath))) {
507
- for (const acId of sf.acIds) sourceAcIds.add(acId);
508
- }
509
- }
510
- }
511
522
  const sourcePropertyIds = /* @__PURE__ */ new Set();
512
523
  for (const designName of sourceDesigns) {
513
524
  const designCode = extractCodeFromFileName(designName);
@@ -517,24 +528,9 @@ async function fixTaskMatrix(filePath, codeToReqFile, specs, crossRefPatterns) {
517
528
  }
518
529
  }
519
530
  }
520
- const allRefIds = /* @__PURE__ */ new Set([...acToTasks.keys(), ...idToTestTasks.keys()]);
521
- const uncovered = [];
522
- for (const acId of sourceAcIds) {
523
- if (!allRefIds.has(acId)) uncovered.push(acId);
524
- }
525
- for (const propId of sourcePropertyIds) {
526
- if (!allRefIds.has(propId)) uncovered.push(propId);
527
- }
528
- uncovered.sort(compareIds);
529
531
  const allIdsForMatrix = [.../* @__PURE__ */ new Set([...acToTasks.keys(), ...idToTestTasks.keys()])];
530
- const grouped = groupByReqFile(allIdsForMatrix, codeToReqFile);
531
- const newSection = generateTaskSection(
532
- grouped,
533
- acToTasks,
534
- idToTestTasks,
535
- sourcePropertyIds,
536
- uncovered
537
- );
532
+ const grouped = groupByReqFile(allIdsForMatrix, reqFileMaps);
533
+ const newSection = generateTaskSection(grouped, acToTasks, idToTestTasks, sourcePropertyIds);
538
534
  const newContent = replaceTraceabilitySection(content, newSection);
539
535
  if (newContent === content) return false;
540
536
  await writeFile(filePath, newContent, "utf-8");
@@ -601,7 +597,7 @@ function parseTaskFileData(content, crossRefPatterns) {
601
597
  }
602
598
  return { tasks, sourceReqs, sourceDesigns };
603
599
  }
604
- function generateTaskSection(grouped, acToTasks, idToTestTasks, propertyIds, uncovered) {
600
+ function generateTaskSection(grouped, acToTasks, idToTestTasks, propertyIds) {
605
601
  const lines = [];
606
602
  const reqFiles = [...grouped.keys()].sort();
607
603
  for (const reqFile of reqFiles) {
@@ -626,15 +622,12 @@ function generateTaskSection(grouped, acToTasks, idToTestTasks, propertyIds, unc
626
622
  }
627
623
  lines.push("");
628
624
  }
629
- const uncoveredStr = uncovered.length > 0 ? uncovered.join(", ") : "(none)";
630
- lines.push(`UNCOVERED: ${uncoveredStr}`);
631
- return lines.join("\n");
625
+ return lines.join("\n").trimEnd();
632
626
  }
633
- function groupByReqFile(ids, codeToReqFile) {
627
+ function groupByReqFile(ids, maps) {
634
628
  const groups = /* @__PURE__ */ new Map();
635
629
  for (const id of ids) {
636
- const code = getCodePrefix(id);
637
- const reqFile = codeToReqFile.get(code);
630
+ const reqFile = resolveReqFile(id, maps);
638
631
  if (!reqFile) continue;
639
632
  const existing = groups.get(reqFile) ?? [];
640
633
  existing.push(id);