specsmd 0.1.40 → 0.1.41

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.
@@ -881,6 +881,30 @@ function pushFileEntry(entries, seenPaths, candidate) {
881
881
  });
882
882
  }
883
883
 
884
+ function buildIntentScopedLabel(snapshot, intentId, filePath, fallbackName = 'file.md') {
885
+ const safeIntentId = typeof intentId === 'string' && intentId.trim() !== ''
886
+ ? intentId
887
+ : '';
888
+ const safeFallback = typeof fallbackName === 'string' && fallbackName.trim() !== ''
889
+ ? fallbackName
890
+ : 'file.md';
891
+
892
+ if (typeof filePath === 'string' && filePath.trim() !== '') {
893
+ if (safeIntentId && typeof snapshot?.rootPath === 'string' && snapshot.rootPath.trim() !== '') {
894
+ const intentPath = path.join(snapshot.rootPath, 'intents', safeIntentId);
895
+ const relativePath = path.relative(intentPath, filePath);
896
+ if (relativePath && !relativePath.startsWith('..') && !path.isAbsolute(relativePath)) {
897
+ return `${safeIntentId}/${relativePath.split(path.sep).join('/')}`;
898
+ }
899
+ }
900
+
901
+ const basename = path.basename(filePath);
902
+ return safeIntentId ? `${safeIntentId}/${basename}` : basename;
903
+ }
904
+
905
+ return safeIntentId ? `${safeIntentId}/${safeFallback}` : safeFallback;
906
+ }
907
+
884
908
  function collectFireRunFiles(run) {
885
909
  if (!run || typeof run.folderPath !== 'string') {
886
910
  return [];
@@ -1023,14 +1047,24 @@ function getRunFileEntries(snapshot, flow, options = {}) {
1023
1047
  const pendingItems = Array.isArray(snapshot?.pendingItems) ? snapshot.pendingItems : [];
1024
1048
  for (const pendingItem of pendingItems) {
1025
1049
  pushFileEntry(entries, seenPaths, {
1026
- label: `${pendingItem?.intentId || 'intent'}/${pendingItem?.id || 'work-item'}.md`,
1050
+ label: buildIntentScopedLabel(
1051
+ snapshot,
1052
+ pendingItem?.intentId,
1053
+ pendingItem?.filePath,
1054
+ `${pendingItem?.id || 'work-item'}.md`
1055
+ ),
1027
1056
  path: pendingItem?.filePath,
1028
1057
  scope: 'upcoming'
1029
1058
  });
1030
1059
 
1031
1060
  if (pendingItem?.intentId) {
1032
1061
  pushFileEntry(entries, seenPaths, {
1033
- label: `${pendingItem.intentId}/brief.md`,
1062
+ label: buildIntentScopedLabel(
1063
+ snapshot,
1064
+ pendingItem.intentId,
1065
+ path.join(snapshot?.rootPath || '', 'intents', pendingItem.intentId, 'brief.md'),
1066
+ 'brief.md'
1067
+ ),
1034
1068
  path: path.join(snapshot?.rootPath || '', 'intents', pendingItem.intentId, 'brief.md'),
1035
1069
  scope: 'intent'
1036
1070
  });
@@ -1049,7 +1083,12 @@ function getRunFileEntries(snapshot, flow, options = {}) {
1049
1083
  : [];
1050
1084
  for (const intent of completedIntents) {
1051
1085
  pushFileEntry(entries, seenPaths, {
1052
- label: `${intent.id}/brief.md`,
1086
+ label: buildIntentScopedLabel(
1087
+ snapshot,
1088
+ intent?.id,
1089
+ path.join(snapshot?.rootPath || '', 'intents', intent?.id || '', 'brief.md'),
1090
+ 'brief.md'
1091
+ ),
1053
1092
  path: path.join(snapshot?.rootPath || '', 'intents', intent.id, 'brief.md'),
1054
1093
  scope: 'intent'
1055
1094
  });
@@ -1315,11 +1354,16 @@ function buildOverviewIntentGroups(snapshot, flow, filter = 'next') {
1315
1354
  const workItems = Array.isArray(intent?.workItems) ? intent.workItems : [];
1316
1355
  const done = workItems.filter((item) => item.status === 'completed').length;
1317
1356
  const files = [{
1318
- label: `${intent?.id || 'intent'}/brief.md`,
1357
+ label: buildIntentScopedLabel(snapshot, intent?.id, intent?.filePath, 'brief.md'),
1319
1358
  path: intent?.filePath,
1320
1359
  scope: 'intent'
1321
1360
  }, ...workItems.map((item) => ({
1322
- label: `${intent?.id || 'intent'}/${item?.id || 'work-item'}.md`,
1361
+ label: buildIntentScopedLabel(
1362
+ snapshot,
1363
+ intent?.id,
1364
+ item?.filePath,
1365
+ `${item?.id || 'work-item'}.md`
1366
+ ),
1323
1367
  path: item?.filePath,
1324
1368
  scope: item?.status === 'completed' ? 'completed' : 'upcoming'
1325
1369
  }))];
@@ -1455,14 +1499,24 @@ function buildPendingGroups(snapshot, flow) {
1455
1499
 
1456
1500
  if (item?.filePath) {
1457
1501
  files.push({
1458
- label: `${item?.intentId || 'intent'}/${item?.id || 'work-item'}.md`,
1502
+ label: buildIntentScopedLabel(
1503
+ snapshot,
1504
+ item?.intentId,
1505
+ item?.filePath,
1506
+ `${item?.id || 'work-item'}.md`
1507
+ ),
1459
1508
  path: item.filePath,
1460
1509
  scope: 'upcoming'
1461
1510
  });
1462
1511
  }
1463
1512
  if (item?.intentId) {
1464
1513
  files.push({
1465
- label: `${item.intentId}/brief.md`,
1514
+ label: buildIntentScopedLabel(
1515
+ snapshot,
1516
+ item.intentId,
1517
+ path.join(snapshot?.rootPath || '', 'intents', item.intentId, 'brief.md'),
1518
+ 'brief.md'
1519
+ ),
1466
1520
  path: path.join(snapshot?.rootPath || '', 'intents', item.intentId, 'brief.md'),
1467
1521
  scope: 'intent'
1468
1522
  });
@@ -1523,7 +1577,12 @@ function buildCompletedGroups(snapshot, flow) {
1523
1577
  key: `completed:intent:${intent?.id || index}`,
1524
1578
  label: `intent ${intent?.id || 'unknown'} [completed]`,
1525
1579
  files: filterExistingFiles([{
1526
- label: `${intent?.id || 'intent'}/brief.md`,
1580
+ label: buildIntentScopedLabel(
1581
+ snapshot,
1582
+ intent?.id,
1583
+ path.join(snapshot?.rootPath || '', 'intents', intent?.id || '', 'brief.md'),
1584
+ 'brief.md'
1585
+ ),
1527
1586
  path: path.join(snapshot?.rootPath || '', 'intents', intent?.id || '', 'brief.md'),
1528
1587
  scope: 'intent'
1529
1588
  }])
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "specsmd",
3
- "version": "0.1.40",
3
+ "version": "0.1.41",
4
4
  "description": "Multi-agent orchestration system for AI-native software development. Delivers AI-DLC, Agile, and custom SDLC flows as markdown-based agent systems.",
5
5
  "main": "lib/installer.js",
6
6
  "bin": {