specsmd 0.1.39 → 0.1.40
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/index.js +7 -0
- package/lib/dashboard/tui/app.js +56 -19
- package/package.json +2 -1
package/lib/dashboard/index.js
CHANGED
|
@@ -172,12 +172,19 @@ async function runFlowDashboard(options, flow, availableFlows = []) {
|
|
|
172
172
|
}
|
|
173
173
|
|
|
174
174
|
const ink = await import('ink');
|
|
175
|
+
let inkUi = null;
|
|
176
|
+
try {
|
|
177
|
+
inkUi = await import('@inkjs/ui');
|
|
178
|
+
} catch {
|
|
179
|
+
inkUi = null;
|
|
180
|
+
}
|
|
175
181
|
const reactNamespace = await import('react');
|
|
176
182
|
const React = reactNamespace.default || reactNamespace;
|
|
177
183
|
|
|
178
184
|
const App = createDashboardApp({
|
|
179
185
|
React,
|
|
180
186
|
ink,
|
|
187
|
+
inkUi,
|
|
181
188
|
parseSnapshotForFlow,
|
|
182
189
|
workspacePath,
|
|
183
190
|
flow,
|
package/lib/dashboard/tui/app.js
CHANGED
|
@@ -124,7 +124,8 @@ function normalizePanelLine(line) {
|
|
|
124
124
|
text: typeof line.text === 'string' ? line.text : String(line.text ?? ''),
|
|
125
125
|
color: line.color,
|
|
126
126
|
bold: Boolean(line.bold),
|
|
127
|
-
selected: Boolean(line.selected)
|
|
127
|
+
selected: Boolean(line.selected),
|
|
128
|
+
loading: Boolean(line.loading)
|
|
128
129
|
};
|
|
129
130
|
}
|
|
130
131
|
|
|
@@ -132,7 +133,8 @@ function normalizePanelLine(line) {
|
|
|
132
133
|
text: String(line ?? ''),
|
|
133
134
|
color: undefined,
|
|
134
135
|
bold: false,
|
|
135
|
-
selected: false
|
|
136
|
+
selected: false,
|
|
137
|
+
loading: false
|
|
136
138
|
};
|
|
137
139
|
}
|
|
138
140
|
|
|
@@ -1265,6 +1267,15 @@ function toInfoRows(lines, keyPrefix, emptyLabel = 'No data') {
|
|
|
1265
1267
|
});
|
|
1266
1268
|
}
|
|
1267
1269
|
|
|
1270
|
+
function toLoadingRows(label, keyPrefix = 'loading') {
|
|
1271
|
+
return [{
|
|
1272
|
+
kind: 'loading',
|
|
1273
|
+
key: `${keyPrefix}:row`,
|
|
1274
|
+
label: typeof label === 'string' && label !== '' ? label : 'Loading...',
|
|
1275
|
+
selectable: false
|
|
1276
|
+
}];
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1268
1279
|
function buildOverviewIntentGroups(snapshot, flow, filter = 'next') {
|
|
1269
1280
|
const effectiveFlow = getEffectiveFlow(flow, snapshot);
|
|
1270
1281
|
const normalizedFilter = filter === 'completed' ? 'completed' : 'next';
|
|
@@ -1602,6 +1613,16 @@ function buildInteractiveRowsLines(rows, selectedIndex, icons, width, isFocusedS
|
|
|
1602
1613
|
};
|
|
1603
1614
|
}
|
|
1604
1615
|
|
|
1616
|
+
if (row.kind === 'loading') {
|
|
1617
|
+
return {
|
|
1618
|
+
text: truncate(row.label || 'Loading...', width),
|
|
1619
|
+
color: 'cyan',
|
|
1620
|
+
bold: false,
|
|
1621
|
+
selected: false,
|
|
1622
|
+
loading: true
|
|
1623
|
+
};
|
|
1624
|
+
}
|
|
1625
|
+
|
|
1605
1626
|
return {
|
|
1606
1627
|
text: truncate(`${isSelected ? `${cursor} ` : ' '}${row.label || ''}`, width),
|
|
1607
1628
|
color: isSelected ? (isFocusedSection ? 'green' : 'cyan') : (row.color || 'gray'),
|
|
@@ -1941,6 +1962,7 @@ function createDashboardApp(deps) {
|
|
|
1941
1962
|
const {
|
|
1942
1963
|
React,
|
|
1943
1964
|
ink,
|
|
1965
|
+
inkUi,
|
|
1944
1966
|
parseSnapshot,
|
|
1945
1967
|
parseSnapshotForFlow,
|
|
1946
1968
|
workspacePath,
|
|
@@ -1956,6 +1978,9 @@ function createDashboardApp(deps) {
|
|
|
1956
1978
|
|
|
1957
1979
|
const { Box, Text, useApp, useInput, useStdout } = ink;
|
|
1958
1980
|
const { useState, useEffect, useCallback, useRef } = React;
|
|
1981
|
+
const Spinner = inkUi && typeof inkUi.Spinner === 'function'
|
|
1982
|
+
? inkUi.Spinner
|
|
1983
|
+
: null;
|
|
1959
1984
|
|
|
1960
1985
|
function SectionPanel(props) {
|
|
1961
1986
|
const {
|
|
@@ -1990,15 +2015,25 @@ function createDashboardApp(deps) {
|
|
|
1990
2015
|
{ bold: true, color: titleColor, backgroundColor: titleBackground },
|
|
1991
2016
|
truncate(title, contentWidth)
|
|
1992
2017
|
),
|
|
1993
|
-
...visibleLines.map((line, index) =>
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2018
|
+
...visibleLines.map((line, index) => {
|
|
2019
|
+
if (line.loading && Spinner) {
|
|
2020
|
+
return React.createElement(
|
|
2021
|
+
Box,
|
|
2022
|
+
{ key: `${title}-${index}` },
|
|
2023
|
+
React.createElement(Spinner, { label: truncate(line.text, contentWidth) })
|
|
2024
|
+
);
|
|
2025
|
+
}
|
|
2026
|
+
|
|
2027
|
+
return React.createElement(
|
|
2028
|
+
Text,
|
|
2029
|
+
{
|
|
2030
|
+
key: `${title}-${index}`,
|
|
2031
|
+
color: line.color,
|
|
2032
|
+
bold: line.bold
|
|
2033
|
+
},
|
|
2034
|
+
line.text
|
|
2035
|
+
);
|
|
2036
|
+
})
|
|
2002
2037
|
);
|
|
2003
2038
|
}
|
|
2004
2039
|
|
|
@@ -2178,42 +2213,42 @@ function createDashboardApp(deps) {
|
|
|
2178
2213
|
expandedGroups
|
|
2179
2214
|
)
|
|
2180
2215
|
]
|
|
2181
|
-
:
|
|
2216
|
+
: toLoadingRows('Loading intents...', 'intent-loading');
|
|
2182
2217
|
const completedRows = shouldHydrateSecondaryTabs
|
|
2183
2218
|
? toExpandableRows(
|
|
2184
2219
|
buildCompletedGroups(snapshot, activeFlow),
|
|
2185
2220
|
getNoCompletedMessage(effectiveFlow),
|
|
2186
2221
|
expandedGroups
|
|
2187
2222
|
)
|
|
2188
|
-
:
|
|
2223
|
+
: toLoadingRows('Loading completed items...', 'completed-loading');
|
|
2189
2224
|
const standardsRows = shouldHydrateSecondaryTabs
|
|
2190
2225
|
? toExpandableRows(
|
|
2191
2226
|
buildStandardsGroups(snapshot, activeFlow),
|
|
2192
2227
|
effectiveFlow === 'simple' ? 'No standards for SIMPLE flow' : 'No standards found',
|
|
2193
2228
|
expandedGroups
|
|
2194
2229
|
)
|
|
2195
|
-
:
|
|
2230
|
+
: toLoadingRows('Loading standards...', 'standards-loading');
|
|
2196
2231
|
const statsRows = shouldHydrateSecondaryTabs
|
|
2197
2232
|
? toInfoRows(
|
|
2198
2233
|
buildStatsLines(snapshot, 200, activeFlow),
|
|
2199
2234
|
'stats',
|
|
2200
2235
|
'No stats available'
|
|
2201
2236
|
)
|
|
2202
|
-
:
|
|
2237
|
+
: toLoadingRows('Loading stats...', 'stats-loading');
|
|
2203
2238
|
const warningsRows = shouldHydrateSecondaryTabs
|
|
2204
2239
|
? toInfoRows(
|
|
2205
2240
|
buildWarningsLines(snapshot, 200),
|
|
2206
2241
|
'warnings',
|
|
2207
2242
|
'No warnings'
|
|
2208
2243
|
)
|
|
2209
|
-
:
|
|
2244
|
+
: toLoadingRows('Loading warnings...', 'warnings-loading');
|
|
2210
2245
|
const errorDetailsRows = shouldHydrateSecondaryTabs
|
|
2211
2246
|
? toInfoRows(
|
|
2212
2247
|
buildErrorLines(error, 200),
|
|
2213
2248
|
'error-details',
|
|
2214
2249
|
'No error details'
|
|
2215
2250
|
)
|
|
2216
|
-
:
|
|
2251
|
+
: toLoadingRows('Loading error details...', 'error-loading');
|
|
2217
2252
|
|
|
2218
2253
|
const rowsBySection = {
|
|
2219
2254
|
'current-run': currentRunRows,
|
|
@@ -2771,7 +2806,8 @@ function createDashboardApp(deps) {
|
|
|
2771
2806
|
(showGlobalErrorPanel ? 5 : 0) +
|
|
2772
2807
|
(showErrorInline ? 1 : 0) +
|
|
2773
2808
|
(showStatusLine ? 1 : 0);
|
|
2774
|
-
const
|
|
2809
|
+
const frameSafetyRows = 2;
|
|
2810
|
+
const contentRowsBudget = Math.max(4, rows - reservedRows - frameSafetyRows);
|
|
2775
2811
|
const ultraCompact = rows <= 14;
|
|
2776
2812
|
const panelTitles = getPanelTitles(activeFlow, snapshot);
|
|
2777
2813
|
const splitPreviewLayout = previewOpen && !overlayPreviewOpen && !ui.showHelp && cols >= 110 && rows >= 16;
|
|
@@ -2936,12 +2972,13 @@ function createDashboardApp(deps) {
|
|
|
2936
2972
|
|
|
2937
2973
|
let contentNode;
|
|
2938
2974
|
if (splitPreviewLayout && !overlayPreviewOpen) {
|
|
2975
|
+
const previewBodyLines = Math.max(1, contentRowsBudget - 3);
|
|
2939
2976
|
const previewPanel = {
|
|
2940
2977
|
key: 'preview-split',
|
|
2941
2978
|
title: `Preview: ${effectivePreviewTarget?.label || 'unknown'}`,
|
|
2942
2979
|
lines: previewLines,
|
|
2943
2980
|
borderColor: 'magenta',
|
|
2944
|
-
maxLines:
|
|
2981
|
+
maxLines: previewBodyLines
|
|
2945
2982
|
};
|
|
2946
2983
|
|
|
2947
2984
|
contentNode = React.createElement(
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "specsmd",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.40",
|
|
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": {
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
"README.md"
|
|
41
41
|
],
|
|
42
42
|
"dependencies": {
|
|
43
|
+
"@inkjs/ui": "^2.0.0",
|
|
43
44
|
"chalk": "^4.1.2",
|
|
44
45
|
"chokidar": "^4.0.3",
|
|
45
46
|
"commander": "^11.1.0",
|