specsmd 0.1.37 → 0.1.39
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/lib/dashboard/tui/app.js +50 -10
- package/package.json +1 -1
package/lib/dashboard/tui/app.js
CHANGED
|
@@ -1,9 +1,18 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const { spawnSync } = require('child_process');
|
|
4
|
+
const stringWidthModule = require('string-width');
|
|
5
|
+
const sliceAnsiModule = require('slice-ansi');
|
|
4
6
|
const { createWatchRuntime } = require('../runtime/watch-runtime');
|
|
5
7
|
const { createInitialUIState } = require('./store');
|
|
6
8
|
|
|
9
|
+
const stringWidth = typeof stringWidthModule === 'function'
|
|
10
|
+
? stringWidthModule
|
|
11
|
+
: stringWidthModule.default;
|
|
12
|
+
const sliceAnsi = typeof sliceAnsiModule === 'function'
|
|
13
|
+
? sliceAnsiModule
|
|
14
|
+
: sliceAnsiModule.default;
|
|
15
|
+
|
|
7
16
|
function toDashboardError(error, defaultCode = 'DASHBOARD_ERROR') {
|
|
8
17
|
if (!error) {
|
|
9
18
|
return {
|
|
@@ -87,15 +96,26 @@ function resolveIconSet() {
|
|
|
87
96
|
|
|
88
97
|
function truncate(value, width) {
|
|
89
98
|
const text = String(value ?? '');
|
|
90
|
-
if (!Number.isFinite(width)
|
|
99
|
+
if (!Number.isFinite(width)) {
|
|
91
100
|
return text;
|
|
92
101
|
}
|
|
93
102
|
|
|
94
|
-
|
|
95
|
-
|
|
103
|
+
const safeWidth = Math.max(0, Math.floor(width));
|
|
104
|
+
if (safeWidth === 0) {
|
|
105
|
+
return '';
|
|
96
106
|
}
|
|
97
107
|
|
|
98
|
-
|
|
108
|
+
if (stringWidth(text) <= safeWidth) {
|
|
109
|
+
return text;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (safeWidth <= 3) {
|
|
113
|
+
return sliceAnsi(text, 0, safeWidth);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const ellipsis = '...';
|
|
117
|
+
const bodyWidth = Math.max(0, safeWidth - stringWidth(ellipsis));
|
|
118
|
+
return `${sliceAnsi(text, 0, bodyWidth)}${ellipsis}`;
|
|
99
119
|
}
|
|
100
120
|
|
|
101
121
|
function normalizePanelLine(line) {
|
|
@@ -906,7 +926,8 @@ function collectSimpleSpecFiles(spec) {
|
|
|
906
926
|
}));
|
|
907
927
|
}
|
|
908
928
|
|
|
909
|
-
function getRunFileEntries(snapshot, flow) {
|
|
929
|
+
function getRunFileEntries(snapshot, flow, options = {}) {
|
|
930
|
+
const includeBacklog = options.includeBacklog !== false;
|
|
910
931
|
const effectiveFlow = getEffectiveFlow(flow, snapshot);
|
|
911
932
|
const entries = [];
|
|
912
933
|
const seenPaths = new Set();
|
|
@@ -917,6 +938,10 @@ function getRunFileEntries(snapshot, flow) {
|
|
|
917
938
|
pushFileEntry(entries, seenPaths, { ...file, scope: 'active' });
|
|
918
939
|
}
|
|
919
940
|
|
|
941
|
+
if (!includeBacklog) {
|
|
942
|
+
return entries;
|
|
943
|
+
}
|
|
944
|
+
|
|
920
945
|
const pendingBolts = Array.isArray(snapshot?.pendingBolts) ? snapshot.pendingBolts : [];
|
|
921
946
|
for (const pendingBolt of pendingBolts) {
|
|
922
947
|
for (const file of collectAidlcBoltFiles(pendingBolt)) {
|
|
@@ -963,6 +988,10 @@ function getRunFileEntries(snapshot, flow) {
|
|
|
963
988
|
pushFileEntry(entries, seenPaths, { ...file, scope: 'active' });
|
|
964
989
|
}
|
|
965
990
|
|
|
991
|
+
if (!includeBacklog) {
|
|
992
|
+
return entries;
|
|
993
|
+
}
|
|
994
|
+
|
|
966
995
|
const pendingSpecs = Array.isArray(snapshot?.pendingSpecs) ? snapshot.pendingSpecs : [];
|
|
967
996
|
for (const pendingSpec of pendingSpecs) {
|
|
968
997
|
for (const file of collectSimpleSpecFiles(pendingSpec)) {
|
|
@@ -985,6 +1014,10 @@ function getRunFileEntries(snapshot, flow) {
|
|
|
985
1014
|
pushFileEntry(entries, seenPaths, { ...file, scope: 'active' });
|
|
986
1015
|
}
|
|
987
1016
|
|
|
1017
|
+
if (!includeBacklog) {
|
|
1018
|
+
return entries;
|
|
1019
|
+
}
|
|
1020
|
+
|
|
988
1021
|
const pendingItems = Array.isArray(snapshot?.pendingItems) ? snapshot.pendingItems : [];
|
|
989
1022
|
for (const pendingItem of pendingItems) {
|
|
990
1023
|
pushFileEntry(entries, seenPaths, {
|
|
@@ -1154,10 +1187,10 @@ function getFileEntityLabel(fileEntry, fallbackIndex = 0) {
|
|
|
1154
1187
|
return `item-${fallbackIndex + 1}`;
|
|
1155
1188
|
}
|
|
1156
1189
|
|
|
1157
|
-
function buildRunFileEntityGroups(snapshot, flow) {
|
|
1190
|
+
function buildRunFileEntityGroups(snapshot, flow, options = {}) {
|
|
1158
1191
|
const order = ['active', 'upcoming', 'completed', 'intent', 'other'];
|
|
1159
1192
|
const rankByScope = new Map(order.map((scope, index) => [scope, index]));
|
|
1160
|
-
const entries = filterExistingFiles(getRunFileEntries(snapshot, flow));
|
|
1193
|
+
const entries = filterExistingFiles(getRunFileEntries(snapshot, flow, options));
|
|
1161
1194
|
const groupsByEntity = new Map();
|
|
1162
1195
|
|
|
1163
1196
|
for (let index = 0; index < entries.length; index += 1) {
|
|
@@ -2115,7 +2148,9 @@ function createDashboardApp(deps) {
|
|
|
2115
2148
|
currentExpandedGroups
|
|
2116
2149
|
);
|
|
2117
2150
|
const shouldHydrateSecondaryTabs = deferredTabsReady || ui.view !== 'runs';
|
|
2118
|
-
const runFileGroups = buildRunFileEntityGroups(snapshot, activeFlow
|
|
2151
|
+
const runFileGroups = buildRunFileEntityGroups(snapshot, activeFlow, {
|
|
2152
|
+
includeBacklog: shouldHydrateSecondaryTabs
|
|
2153
|
+
});
|
|
2119
2154
|
const runFileExpandedGroups = { ...expandedGroups };
|
|
2120
2155
|
for (const group of runFileGroups) {
|
|
2121
2156
|
if (runFileExpandedGroups[group.key] == null) {
|
|
@@ -2592,14 +2627,19 @@ function createDashboardApp(deps) {
|
|
|
2592
2627
|
}, [activeFlow, rowLengthSignature, snapshot?.generatedAt]);
|
|
2593
2628
|
|
|
2594
2629
|
useEffect(() => {
|
|
2630
|
+
if (ui.view !== 'runs') {
|
|
2631
|
+
setDeferredTabsReady(true);
|
|
2632
|
+
return undefined;
|
|
2633
|
+
}
|
|
2634
|
+
|
|
2595
2635
|
setDeferredTabsReady(false);
|
|
2596
2636
|
const timer = setTimeout(() => {
|
|
2597
2637
|
setDeferredTabsReady(true);
|
|
2598
|
-
},
|
|
2638
|
+
}, 250);
|
|
2599
2639
|
return () => {
|
|
2600
2640
|
clearTimeout(timer);
|
|
2601
2641
|
};
|
|
2602
|
-
}, [activeFlow, snapshot?.generatedAt]);
|
|
2642
|
+
}, [activeFlow, snapshot?.generatedAt, ui.view]);
|
|
2603
2643
|
|
|
2604
2644
|
useEffect(() => {
|
|
2605
2645
|
setPaneFocus('main');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "specsmd",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.39",
|
|
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": {
|