specsmd 0.1.42 → 0.1.43

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.
@@ -905,6 +905,46 @@ function buildIntentScopedLabel(snapshot, intentId, filePath, fallbackName = 'fi
905
905
  return safeIntentId ? `${safeIntentId}/${safeFallback}` : safeFallback;
906
906
  }
907
907
 
908
+ function findIntentIdForWorkItem(snapshot, workItemId) {
909
+ if (typeof workItemId !== 'string' || workItemId.trim() === '') {
910
+ return '';
911
+ }
912
+
913
+ const intents = Array.isArray(snapshot?.intents) ? snapshot.intents : [];
914
+ for (const intent of intents) {
915
+ const items = Array.isArray(intent?.workItems) ? intent.workItems : [];
916
+ if (items.some((item) => item?.id === workItemId)) {
917
+ return intent?.id || '';
918
+ }
919
+ }
920
+
921
+ return '';
922
+ }
923
+
924
+ function resolveFireWorkItemPath(snapshot, intentId, workItemId, explicitPath) {
925
+ if (typeof explicitPath === 'string' && explicitPath.trim() !== '') {
926
+ return explicitPath;
927
+ }
928
+
929
+ if (typeof snapshot?.rootPath !== 'string' || snapshot.rootPath.trim() === '') {
930
+ return null;
931
+ }
932
+
933
+ if (typeof workItemId !== 'string' || workItemId.trim() === '') {
934
+ return null;
935
+ }
936
+
937
+ const safeIntentId = typeof intentId === 'string' && intentId.trim() !== ''
938
+ ? intentId
939
+ : findIntentIdForWorkItem(snapshot, workItemId);
940
+
941
+ if (!safeIntentId) {
942
+ return null;
943
+ }
944
+
945
+ return path.join(snapshot.rootPath, 'intents', safeIntentId, 'work-items', `${workItemId}.md`);
946
+ }
947
+
908
948
  function collectFireRunFiles(run) {
909
949
  if (!run || typeof run.folderPath !== 'string') {
910
950
  return [];
@@ -1156,13 +1196,32 @@ function buildFireCurrentRunGroups(snapshot) {
1156
1196
  const status = currentWorkItem?.status || 'pending';
1157
1197
  const statusTag = status === 'in_progress' ? 'current' : status;
1158
1198
 
1159
- const currentWorkItemFiles = currentWorkItem?.filePath
1160
- ? [{
1161
- label: `${currentWorkItem.id || 'work-item'} [${mode}] [${statusTag}] ${phaseTrack}`,
1162
- path: currentWorkItem.filePath,
1163
- scope: 'active'
1164
- }]
1165
- : [];
1199
+ const runIntentId = typeof run?.intent === 'string' ? run.intent : '';
1200
+ const currentWorkItemFiles = workItems.map((item, index) => {
1201
+ const itemId = typeof item?.id === 'string' && item.id !== '' ? item.id : `work-item-${index + 1}`;
1202
+ const intentId = typeof item?.intent === 'string' && item.intent !== ''
1203
+ ? item.intent
1204
+ : (runIntentId || findIntentIdForWorkItem(snapshot, itemId));
1205
+ const filePath = resolveFireWorkItemPath(snapshot, intentId, itemId, item?.filePath);
1206
+ if (!filePath) {
1207
+ return null;
1208
+ }
1209
+
1210
+ const itemMode = String(item?.mode || 'confirm').toUpperCase();
1211
+ const itemStatus = item?.status || 'pending';
1212
+ const isCurrent = Boolean(currentWorkItem?.id) && itemId === currentWorkItem.id;
1213
+ const itemScope = isCurrent
1214
+ ? 'active'
1215
+ : (itemStatus === 'completed' ? 'completed' : 'upcoming');
1216
+ const itemStatusTag = isCurrent ? 'current' : itemStatus;
1217
+ const labelPath = buildIntentScopedLabel(snapshot, intentId, filePath, `${itemId}.md`);
1218
+
1219
+ return {
1220
+ label: `${labelPath} [${itemMode}] [${itemStatusTag}]`,
1221
+ path: filePath,
1222
+ scope: itemScope
1223
+ };
1224
+ }).filter(Boolean);
1166
1225
 
1167
1226
  const currentRunFiles = collectFireRunFiles(run).map((fileEntry) => ({
1168
1227
  ...fileEntry,
@@ -1178,7 +1237,7 @@ function buildFireCurrentRunGroups(snapshot) {
1178
1237
  },
1179
1238
  {
1180
1239
  key: `current:run:${run.id}:work-items`,
1181
- label: 'WORK ITEMS',
1240
+ label: `WORK ITEMS (${currentWorkItemFiles.length})`,
1182
1241
  files: filterExistingFiles(currentWorkItemFiles)
1183
1242
  },
1184
1243
  {
@@ -2774,11 +2833,6 @@ function createDashboardApp(deps) {
2774
2833
  }, [activeFlow, rowLengthSignature, snapshot?.generatedAt]);
2775
2834
 
2776
2835
  useEffect(() => {
2777
- if (ui.view !== 'runs') {
2778
- setDeferredTabsReady(true);
2779
- return undefined;
2780
- }
2781
-
2782
2836
  setDeferredTabsReady(false);
2783
2837
  const timer = setTimeout(() => {
2784
2838
  setDeferredTabsReady(true);
@@ -2786,7 +2840,7 @@ function createDashboardApp(deps) {
2786
2840
  return () => {
2787
2841
  clearTimeout(timer);
2788
2842
  };
2789
- }, [activeFlow, snapshot?.generatedAt, ui.view]);
2843
+ }, [activeFlow]);
2790
2844
 
2791
2845
  useEffect(() => {
2792
2846
  setPaneFocus('main');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "specsmd",
3
- "version": "0.1.42",
3
+ "version": "0.1.43",
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": {