specsmd 0.1.34 → 0.1.36

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.
@@ -793,13 +793,16 @@ function getPanelTitles(flow, snapshot) {
793
793
  }
794
794
 
795
795
  function getSectionOrderForView(view) {
796
- if (view === 'overview') {
797
- return ['intent-status', 'completed-runs', 'standards', 'project'];
796
+ if (view === 'intents') {
797
+ return ['intent-status'];
798
+ }
799
+ if (view === 'completed') {
800
+ return ['completed-runs'];
798
801
  }
799
802
  if (view === 'health') {
800
- return ['stats', 'warnings', 'error-details'];
803
+ return ['standards', 'stats', 'warnings', 'error-details'];
801
804
  }
802
- return ['current-run', 'run-files', 'pending'];
805
+ return ['current-run'];
803
806
  }
804
807
 
805
808
  function cycleSection(view, currentSectionKey, direction = 1, availableSections = null) {
@@ -1054,24 +1057,221 @@ function getNoCompletedMessage(flow) {
1054
1057
  return 'No completed runs yet';
1055
1058
  }
1056
1059
 
1057
- function toRunFileRows(fileEntries, flow) {
1058
- if (!Array.isArray(fileEntries) || fileEntries.length === 0) {
1060
+ function getNoCurrentMessage(flow) {
1061
+ if (flow === 'aidlc') return 'No active bolt';
1062
+ if (flow === 'simple') return 'No active spec';
1063
+ return 'No active run';
1064
+ }
1065
+
1066
+ function buildCurrentGroups(snapshot, flow) {
1067
+ const effectiveFlow = getEffectiveFlow(flow, snapshot);
1068
+
1069
+ if (effectiveFlow === 'aidlc') {
1070
+ const bolt = getCurrentBolt(snapshot);
1071
+ if (!bolt) {
1072
+ return [];
1073
+ }
1074
+ const stages = Array.isArray(bolt.stages) ? bolt.stages : [];
1075
+ const completedStages = stages.filter((stage) => stage.status === 'completed').length;
1076
+ return [{
1077
+ key: `current:bolt:${bolt.id}`,
1078
+ label: `${bolt.id} [${bolt.type}] ${completedStages}/${stages.length} stages`,
1079
+ files: filterExistingFiles([
1080
+ ...collectAidlcBoltFiles(bolt),
1081
+ ...collectAidlcIntentContextFiles(snapshot, bolt.intent)
1082
+ ])
1083
+ }];
1084
+ }
1085
+
1086
+ if (effectiveFlow === 'simple') {
1087
+ const spec = getCurrentSpec(snapshot);
1088
+ if (!spec) {
1089
+ return [];
1090
+ }
1091
+ return [{
1092
+ key: `current:spec:${spec.name}`,
1093
+ label: `${spec.name} [${spec.state}] ${spec.tasksCompleted}/${spec.tasksTotal} tasks`,
1094
+ files: filterExistingFiles(collectSimpleSpecFiles(spec))
1095
+ }];
1096
+ }
1097
+
1098
+ const run = getCurrentRun(snapshot);
1099
+ if (!run) {
1100
+ return [];
1101
+ }
1102
+ const workItems = Array.isArray(run.workItems) ? run.workItems : [];
1103
+ const completed = workItems.filter((item) => item.status === 'completed').length;
1104
+ return [{
1105
+ key: `current:run:${run.id}`,
1106
+ label: `${run.id} [${run.scope}] ${completed}/${workItems.length} items`,
1107
+ files: filterExistingFiles(collectFireRunFiles(run).map((file) => ({ ...file, scope: 'active' })))
1108
+ }];
1109
+ }
1110
+
1111
+ function buildRunFileGroups(fileEntries) {
1112
+ const order = ['active', 'upcoming', 'completed', 'intent', 'other'];
1113
+ const buckets = new Map(order.map((scope) => [scope, []]));
1114
+
1115
+ for (const fileEntry of Array.isArray(fileEntries) ? fileEntries : []) {
1116
+ const scope = order.includes(fileEntry?.scope) ? fileEntry.scope : 'other';
1117
+ buckets.get(scope).push(fileEntry);
1118
+ }
1119
+
1120
+ const groups = [];
1121
+ for (const scope of order) {
1122
+ const files = buckets.get(scope) || [];
1123
+ if (files.length === 0) {
1124
+ continue;
1125
+ }
1126
+ groups.push({
1127
+ key: `run-files:scope:${scope}`,
1128
+ label: `${formatScope(scope)} files (${files.length})`,
1129
+ files: filterExistingFiles(files)
1130
+ });
1131
+ }
1132
+ return groups;
1133
+ }
1134
+
1135
+ function normalizeInfoLine(line) {
1136
+ const normalized = normalizePanelLine(line);
1137
+ return {
1138
+ label: normalized.text,
1139
+ color: normalized.color,
1140
+ bold: normalized.bold
1141
+ };
1142
+ }
1143
+
1144
+ function toInfoRows(lines, keyPrefix, emptyLabel = 'No data') {
1145
+ const safe = Array.isArray(lines) ? lines : [];
1146
+ if (safe.length === 0) {
1059
1147
  return [{
1060
1148
  kind: 'info',
1061
- key: 'run-files:empty',
1062
- label: getNoFileMessage(flow),
1149
+ key: `${keyPrefix}:empty`,
1150
+ label: emptyLabel,
1063
1151
  selectable: false
1064
1152
  }];
1065
1153
  }
1066
1154
 
1067
- return fileEntries.map((file, index) => ({
1068
- kind: 'file',
1069
- key: `run-files:${file.path}:${index}`,
1070
- label: file.label,
1071
- path: file.path,
1072
- scope: file.scope || 'file',
1073
- selectable: true
1074
- }));
1155
+ return safe.map((line, index) => {
1156
+ const normalized = normalizeInfoLine(line);
1157
+ return {
1158
+ kind: 'info',
1159
+ key: `${keyPrefix}:${index}`,
1160
+ label: normalized.label,
1161
+ color: normalized.color,
1162
+ bold: normalized.bold,
1163
+ selectable: true
1164
+ };
1165
+ });
1166
+ }
1167
+
1168
+ function buildOverviewIntentGroups(snapshot, flow, filter = 'next') {
1169
+ const effectiveFlow = getEffectiveFlow(flow, snapshot);
1170
+ const normalizedFilter = filter === 'completed' ? 'completed' : 'next';
1171
+ const isIncluded = (status) => {
1172
+ if (normalizedFilter === 'completed') {
1173
+ return status === 'completed';
1174
+ }
1175
+ return status !== 'completed';
1176
+ };
1177
+
1178
+ if (effectiveFlow === 'aidlc') {
1179
+ const intents = Array.isArray(snapshot?.intents) ? snapshot.intents : [];
1180
+ return intents
1181
+ .filter((intent) => isIncluded(intent?.status || 'pending'))
1182
+ .map((intent, index) => ({
1183
+ key: `overview:intent:${intent?.id || index}`,
1184
+ label: `${intent?.id || 'unknown'}: ${intent?.status || 'pending'} (${intent?.completedStories || 0}/${intent?.storyCount || 0} stories, ${intent?.completedUnits || 0}/${intent?.unitCount || 0} units)`,
1185
+ files: filterExistingFiles(collectAidlcIntentContextFiles(snapshot, intent?.id))
1186
+ }));
1187
+ }
1188
+
1189
+ if (effectiveFlow === 'simple') {
1190
+ const specs = Array.isArray(snapshot?.specs) ? snapshot.specs : [];
1191
+ return specs
1192
+ .filter((spec) => isIncluded(spec?.state || 'pending'))
1193
+ .map((spec, index) => ({
1194
+ key: `overview:spec:${spec?.name || index}`,
1195
+ label: `${spec?.name || 'unknown'}: ${spec?.state || 'pending'} (${spec?.tasksCompleted || 0}/${spec?.tasksTotal || 0} tasks)`,
1196
+ files: filterExistingFiles(collectSimpleSpecFiles(spec))
1197
+ }));
1198
+ }
1199
+
1200
+ const intents = Array.isArray(snapshot?.intents) ? snapshot.intents : [];
1201
+ return intents
1202
+ .filter((intent) => isIncluded(intent?.status || 'pending'))
1203
+ .map((intent, index) => {
1204
+ const workItems = Array.isArray(intent?.workItems) ? intent.workItems : [];
1205
+ const done = workItems.filter((item) => item.status === 'completed').length;
1206
+ const files = [{
1207
+ label: `${intent?.id || 'intent'}/brief.md`,
1208
+ path: intent?.filePath,
1209
+ scope: 'intent'
1210
+ }, ...workItems.map((item) => ({
1211
+ label: `${intent?.id || 'intent'}/${item?.id || 'work-item'}.md`,
1212
+ path: item?.filePath,
1213
+ scope: item?.status === 'completed' ? 'completed' : 'upcoming'
1214
+ }))];
1215
+ return {
1216
+ key: `overview:intent:${intent?.id || index}`,
1217
+ label: `${intent?.id || 'unknown'}: ${intent?.status || 'pending'} (${done}/${workItems.length} work items)`,
1218
+ files: filterExistingFiles(files)
1219
+ };
1220
+ });
1221
+ }
1222
+
1223
+ function buildStandardsGroups(snapshot, flow) {
1224
+ const effectiveFlow = getEffectiveFlow(flow, snapshot);
1225
+ if (effectiveFlow === 'simple') {
1226
+ return [];
1227
+ }
1228
+
1229
+ const standards = Array.isArray(snapshot?.standards) ? snapshot.standards : [];
1230
+ return standards.map((standard, index) => {
1231
+ const id = standard?.type || standard?.name || String(index);
1232
+ const name = `${standard?.name || standard?.type || 'standard'}.md`;
1233
+ return {
1234
+ key: `standards:${id}`,
1235
+ label: name,
1236
+ files: filterExistingFiles([{
1237
+ label: name,
1238
+ path: standard?.filePath,
1239
+ scope: 'file'
1240
+ }])
1241
+ };
1242
+ });
1243
+ }
1244
+
1245
+ function buildProjectGroups(snapshot, flow) {
1246
+ const effectiveFlow = getEffectiveFlow(flow, snapshot);
1247
+ const files = [];
1248
+
1249
+ if (effectiveFlow === 'aidlc') {
1250
+ files.push({
1251
+ label: 'memory-bank/project.yaml',
1252
+ path: path.join(snapshot?.rootPath || '', 'project.yaml'),
1253
+ scope: 'file'
1254
+ });
1255
+ } else if (effectiveFlow === 'simple') {
1256
+ files.push({
1257
+ label: 'package.json',
1258
+ path: path.join(snapshot?.workspacePath || '', 'package.json'),
1259
+ scope: 'file'
1260
+ });
1261
+ } else {
1262
+ files.push({
1263
+ label: '.specs-fire/state.yaml',
1264
+ path: path.join(snapshot?.rootPath || '', 'state.yaml'),
1265
+ scope: 'file'
1266
+ });
1267
+ }
1268
+
1269
+ const projectName = snapshot?.project?.name || 'unknown-project';
1270
+ return [{
1271
+ key: `project:${projectName}`,
1272
+ label: `project ${projectName}`,
1273
+ files: filterExistingFiles(files)
1274
+ }];
1075
1275
  }
1076
1276
 
1077
1277
  function collectAidlcIntentContextFiles(snapshot, intentId) {
@@ -1303,10 +1503,10 @@ function buildInteractiveRowsLines(rows, selectedIndex, icons, width, isFocusedS
1303
1503
  }
1304
1504
 
1305
1505
  return {
1306
- text: truncate(` ${row.label || ''}`, width),
1307
- color: 'gray',
1308
- bold: false,
1309
- selected: false
1506
+ text: truncate(`${isSelected ? `${cursor} ` : ' '}${row.label || ''}`, width),
1507
+ color: isSelected ? (isFocusedSection ? 'green' : 'cyan') : (row.color || 'gray'),
1508
+ bold: isSelected || Boolean(row.bold),
1509
+ selected: isSelected
1310
1510
  };
1311
1511
  });
1312
1512
  }
@@ -1397,6 +1597,95 @@ function openFileWithDefaultApp(filePath) {
1397
1597
  };
1398
1598
  }
1399
1599
 
1600
+ function buildQuickHelpText(view, options = {}) {
1601
+ const {
1602
+ flow = 'fire',
1603
+ previewOpen = false,
1604
+ availableFlowCount = 1
1605
+ } = options;
1606
+ const isAidlc = String(flow || '').toLowerCase() === 'aidlc';
1607
+ const isSimple = String(flow || '').toLowerCase() === 'simple';
1608
+ const activeLabel = isAidlc ? 'active bolt' : (isSimple ? 'active spec' : 'active run');
1609
+
1610
+ const parts = ['1/2/3/4 tabs', 'g/G sections'];
1611
+
1612
+ if (view === 'runs' || view === 'intents' || view === 'completed' || view === 'health') {
1613
+ if (previewOpen) {
1614
+ parts.push('tab pane', '↑/↓ nav/scroll', 'v close');
1615
+ } else {
1616
+ parts.push('↑/↓ navigate', 'enter expand', 'v preview');
1617
+ }
1618
+ }
1619
+ parts.push(`tab1 ${activeLabel}`);
1620
+
1621
+ if (availableFlowCount > 1) {
1622
+ parts.push('[/] flow');
1623
+ }
1624
+
1625
+ parts.push('r refresh', '? shortcuts', 'q quit');
1626
+ return parts.join(' | ');
1627
+ }
1628
+
1629
+ function buildHelpOverlayLines(options = {}) {
1630
+ const {
1631
+ view = 'runs',
1632
+ flow = 'fire',
1633
+ previewOpen = false,
1634
+ paneFocus = 'main',
1635
+ availableFlowCount = 1,
1636
+ showErrorSection = false
1637
+ } = options;
1638
+ const isAidlc = String(flow || '').toLowerCase() === 'aidlc';
1639
+ const isSimple = String(flow || '').toLowerCase() === 'simple';
1640
+ const itemLabel = isAidlc ? 'bolt' : (isSimple ? 'spec' : 'run');
1641
+ const itemPlural = isAidlc ? 'bolts' : (isSimple ? 'specs' : 'runs');
1642
+
1643
+ const lines = [
1644
+ { text: 'Global', color: 'cyan', bold: true },
1645
+ 'q or Ctrl+C quit',
1646
+ 'r refresh snapshot',
1647
+ `1 active ${itemLabel} | 2 intents | 3 completed ${itemPlural} | 4 standards/health`,
1648
+ 'g next section | G previous section',
1649
+ 'h/? toggle this shortcuts overlay',
1650
+ 'esc close overlays (help/preview/fullscreen)',
1651
+ { text: '', color: undefined, bold: false },
1652
+ { text: 'Tab 1 Active', color: 'yellow', bold: true },
1653
+ `a focus active ${itemLabel}`,
1654
+ 'up/down or j/k move selection',
1655
+ 'enter expand/collapse selected folder row',
1656
+ 'v preview selected file',
1657
+ 'v twice quickly opens fullscreen preview overlay',
1658
+ 'tab switch focus between main and preview panes',
1659
+ 'o open selected file in system default app'
1660
+ ];
1661
+
1662
+ if (previewOpen) {
1663
+ lines.push(`preview is open (focus: ${paneFocus})`);
1664
+ }
1665
+
1666
+ if (availableFlowCount > 1) {
1667
+ lines.push('[/] (and m) switch flow');
1668
+ }
1669
+
1670
+ lines.push(
1671
+ { text: '', color: undefined, bold: false },
1672
+ { text: 'Tab 2 Intents', color: 'green', bold: true },
1673
+ 'i focus intents',
1674
+ 'n next intents | x completed intents',
1675
+ 'left/right toggles next/completed when intents is focused',
1676
+ { text: '', color: undefined, bold: false },
1677
+ { text: 'Tab 3 Completed', color: 'blue', bold: true },
1678
+ 'c focus completed items',
1679
+ { text: '', color: undefined, bold: false },
1680
+ { text: 'Tab 4 Standards/Health', color: 'magenta', bold: true },
1681
+ `s standards | t stats | w warnings${showErrorSection ? ' | e errors' : ''}`,
1682
+ { text: '', color: undefined, bold: false },
1683
+ { text: `Current view: ${String(view || 'runs').toUpperCase()}`, color: 'gray', bold: false }
1684
+ );
1685
+
1686
+ return lines;
1687
+ }
1688
+
1400
1689
  function colorizeMarkdownLine(line, inCodeBlock) {
1401
1690
  const text = String(line ?? '');
1402
1691
 
@@ -1610,11 +1899,15 @@ function createDashboardApp(deps) {
1610
1899
  }
1611
1900
 
1612
1901
  function TabsBar(props) {
1613
- const { view, width, icons } = props;
1902
+ const { view, width, icons, flow: activeFlow } = props;
1903
+ const effectiveFlow = String(activeFlow || '').toLowerCase();
1904
+ const primaryLabel = effectiveFlow === 'aidlc' ? 'BOLTS' : (effectiveFlow === 'simple' ? 'SPECS' : 'RUNS');
1905
+ const completedLabel = effectiveFlow === 'aidlc' ? 'COMPLETED BOLTS' : (effectiveFlow === 'simple' ? 'COMPLETED SPECS' : 'COMPLETED RUNS');
1614
1906
  const tabs = [
1615
- { id: 'runs', label: ` 1 ${icons.runs} RUNS ` },
1616
- { id: 'overview', label: ` 2 ${icons.overview} OVERVIEW ` },
1617
- { id: 'health', label: ` 3 ${icons.health} HEALTH ` }
1907
+ { id: 'runs', label: ` 1 ${icons.runs} ${primaryLabel} ` },
1908
+ { id: 'intents', label: ` 2 ${icons.overview} INTENTS ` },
1909
+ { id: 'completed', label: ` 3 ${icons.runs} ${completedLabel} ` },
1910
+ { id: 'health', label: ` 4 ${icons.health} STANDARDS/HEALTH ` }
1618
1911
  ];
1619
1912
 
1620
1913
  return React.createElement(
@@ -1682,18 +1975,24 @@ function createDashboardApp(deps) {
1682
1975
  const [error, setError] = useState(initialNormalizedError);
1683
1976
  const [ui, setUi] = useState(createInitialUIState());
1684
1977
  const [sectionFocus, setSectionFocus] = useState({
1685
- runs: 'run-files',
1686
- overview: 'project',
1687
- health: 'stats'
1978
+ runs: 'current-run',
1979
+ intents: 'intent-status',
1980
+ completed: 'completed-runs',
1981
+ health: 'standards'
1688
1982
  });
1689
1983
  const [selectionBySection, setSelectionBySection] = useState({
1690
- 'run-files': 0,
1691
- pending: 0,
1692
- completed: 0
1984
+ 'current-run': 0,
1985
+ 'intent-status': 0,
1986
+ 'completed-runs': 0,
1987
+ standards: 0,
1988
+ stats: 0,
1989
+ warnings: 0,
1990
+ 'error-details': 0
1693
1991
  });
1694
1992
  const [expandedGroups, setExpandedGroups] = useState({});
1695
1993
  const [previewTarget, setPreviewTarget] = useState(null);
1696
1994
  const [overviewIntentFilter, setOverviewIntentFilter] = useState('next');
1995
+ const [deferredTabsReady, setDeferredTabsReady] = useState(false);
1697
1996
  const [previewOpen, setPreviewOpen] = useState(false);
1698
1997
  const [paneFocus, setPaneFocus] = useState('main');
1699
1998
  const [overlayPreviewOpen, setOverlayPreviewOpen] = useState(false);
@@ -1729,24 +2028,86 @@ function createDashboardApp(deps) {
1729
2028
  return base.filter((sectionKey) => sectionKey !== 'error-details' || showErrorPanelForSections);
1730
2029
  }, [showErrorPanelForSections]);
1731
2030
 
1732
- const runFileEntries = getRunFileEntries(snapshot, activeFlow);
1733
- const runFileRows = toRunFileRows(runFileEntries, activeFlow);
1734
- const pendingRows = toExpandableRows(
1735
- buildPendingGroups(snapshot, activeFlow),
1736
- getNoPendingMessage(getEffectiveFlow(activeFlow, snapshot)),
1737
- expandedGroups
1738
- );
1739
- const completedRows = toExpandableRows(
1740
- buildCompletedGroups(snapshot, activeFlow),
1741
- getNoCompletedMessage(getEffectiveFlow(activeFlow, snapshot)),
1742
- expandedGroups
2031
+ const effectiveFlow = getEffectiveFlow(activeFlow, snapshot);
2032
+ const currentGroups = buildCurrentGroups(snapshot, activeFlow);
2033
+ const currentExpandedGroups = { ...expandedGroups };
2034
+ for (const group of currentGroups) {
2035
+ if (currentExpandedGroups[group.key] == null) {
2036
+ currentExpandedGroups[group.key] = true;
2037
+ }
2038
+ }
2039
+
2040
+ const currentRunRows = toExpandableRows(
2041
+ currentGroups,
2042
+ getNoCurrentMessage(effectiveFlow),
2043
+ currentExpandedGroups
1743
2044
  );
2045
+ const shouldHydrateSecondaryTabs = deferredTabsReady || ui.view !== 'runs';
2046
+ const intentRows = shouldHydrateSecondaryTabs
2047
+ ? [
2048
+ {
2049
+ kind: 'info',
2050
+ key: 'intent-filter',
2051
+ label: `filter ${overviewIntentFilter === 'completed' ? 'next | [COMPLETED]' : '[NEXT] | completed'} (n/x)`,
2052
+ color: 'cyan',
2053
+ bold: true,
2054
+ selectable: false
2055
+ },
2056
+ ...toExpandableRows(
2057
+ buildOverviewIntentGroups(snapshot, activeFlow, overviewIntentFilter),
2058
+ overviewIntentFilter === 'completed' ? 'No completed intents yet' : 'No upcoming intents',
2059
+ expandedGroups
2060
+ )
2061
+ ]
2062
+ : toInfoRows(['Loading intents...'], 'intent-loading');
2063
+ const completedRows = shouldHydrateSecondaryTabs
2064
+ ? toExpandableRows(
2065
+ buildCompletedGroups(snapshot, activeFlow),
2066
+ getNoCompletedMessage(effectiveFlow),
2067
+ expandedGroups
2068
+ )
2069
+ : toInfoRows(['Loading completed items...'], 'completed-loading');
2070
+ const standardsRows = shouldHydrateSecondaryTabs
2071
+ ? toExpandableRows(
2072
+ buildStandardsGroups(snapshot, activeFlow),
2073
+ effectiveFlow === 'simple' ? 'No standards for SIMPLE flow' : 'No standards found',
2074
+ expandedGroups
2075
+ )
2076
+ : toInfoRows(['Loading standards...'], 'standards-loading');
2077
+ const statsRows = shouldHydrateSecondaryTabs
2078
+ ? toInfoRows(
2079
+ buildStatsLines(snapshot, 200, activeFlow),
2080
+ 'stats',
2081
+ 'No stats available'
2082
+ )
2083
+ : toInfoRows(['Loading stats...'], 'stats-loading');
2084
+ const warningsRows = shouldHydrateSecondaryTabs
2085
+ ? toInfoRows(
2086
+ buildWarningsLines(snapshot, 200),
2087
+ 'warnings',
2088
+ 'No warnings'
2089
+ )
2090
+ : toInfoRows(['Loading warnings...'], 'warnings-loading');
2091
+ const errorDetailsRows = shouldHydrateSecondaryTabs
2092
+ ? toInfoRows(
2093
+ buildErrorLines(error, 200),
2094
+ 'error-details',
2095
+ 'No error details'
2096
+ )
2097
+ : toInfoRows(['Loading error details...'], 'error-loading');
1744
2098
 
1745
2099
  const rowsBySection = {
1746
- 'run-files': runFileRows,
1747
- pending: pendingRows,
1748
- completed: completedRows
2100
+ 'current-run': currentRunRows,
2101
+ 'intent-status': intentRows,
2102
+ 'completed-runs': completedRows,
2103
+ standards: standardsRows,
2104
+ stats: statsRows,
2105
+ warnings: warningsRows,
2106
+ 'error-details': errorDetailsRows
1749
2107
  };
2108
+ const rowLengthSignature = Object.entries(rowsBySection)
2109
+ .map(([key, rowsForSection]) => `${key}:${Array.isArray(rowsForSection) ? rowsForSection.length : 0}`)
2110
+ .join('|');
1750
2111
 
1751
2112
  const currentSectionOrder = getAvailableSections(ui.view);
1752
2113
  const focusedSection = currentSectionOrder.includes(sectionFocus[ui.view])
@@ -1823,6 +2184,15 @@ function createDashboardApp(deps) {
1823
2184
  return;
1824
2185
  }
1825
2186
 
2187
+ if (key.escape && ui.showHelp) {
2188
+ setUi((previous) => ({ ...previous, showHelp: false }));
2189
+ return;
2190
+ }
2191
+
2192
+ if (ui.showHelp) {
2193
+ return;
2194
+ }
2195
+
1826
2196
  if (input === '1') {
1827
2197
  setUi((previous) => ({ ...previous, view: 'runs' }));
1828
2198
  setPaneFocus('main');
@@ -1830,12 +2200,18 @@ function createDashboardApp(deps) {
1830
2200
  }
1831
2201
 
1832
2202
  if (input === '2') {
1833
- setUi((previous) => ({ ...previous, view: 'overview' }));
2203
+ setUi((previous) => ({ ...previous, view: 'intents' }));
1834
2204
  setPaneFocus('main');
1835
2205
  return;
1836
2206
  }
1837
2207
 
1838
2208
  if (input === '3') {
2209
+ setUi((previous) => ({ ...previous, view: 'completed' }));
2210
+ setPaneFocus('main');
2211
+ return;
2212
+ }
2213
+
2214
+ if (input === '4') {
1839
2215
  setUi((previous) => ({ ...previous, view: 'health' }));
1840
2216
  setPaneFocus('main');
1841
2217
  return;
@@ -1854,14 +2230,19 @@ function createDashboardApp(deps) {
1854
2230
  return availableFlowIds[nextIndex];
1855
2231
  });
1856
2232
  setSelectionBySection({
1857
- 'run-files': 0,
1858
- pending: 0,
1859
- completed: 0
2233
+ 'current-run': 0,
2234
+ 'intent-status': 0,
2235
+ 'completed-runs': 0,
2236
+ standards: 0,
2237
+ stats: 0,
2238
+ warnings: 0,
2239
+ 'error-details': 0
1860
2240
  });
1861
2241
  setSectionFocus({
1862
- runs: 'run-files',
1863
- overview: 'project',
1864
- health: 'stats'
2242
+ runs: 'current-run',
2243
+ intents: 'intent-status',
2244
+ completed: 'completed-runs',
2245
+ health: 'standards'
1865
2246
  });
1866
2247
  setOverviewIntentFilter('next');
1867
2248
  setExpandedGroups({});
@@ -1886,14 +2267,19 @@ function createDashboardApp(deps) {
1886
2267
  return availableFlowIds[nextIndex];
1887
2268
  });
1888
2269
  setSelectionBySection({
1889
- 'run-files': 0,
1890
- pending: 0,
1891
- completed: 0
2270
+ 'current-run': 0,
2271
+ 'intent-status': 0,
2272
+ 'completed-runs': 0,
2273
+ standards: 0,
2274
+ stats: 0,
2275
+ warnings: 0,
2276
+ 'error-details': 0
1892
2277
  });
1893
2278
  setSectionFocus({
1894
- runs: 'run-files',
1895
- overview: 'project',
1896
- health: 'stats'
2279
+ runs: 'current-run',
2280
+ intents: 'intent-status',
2281
+ completed: 'completed-runs',
2282
+ health: 'standards'
1897
2283
  });
1898
2284
  setOverviewIntentFilter('next');
1899
2285
  setExpandedGroups({});
@@ -1910,12 +2296,12 @@ function createDashboardApp(deps) {
1910
2296
  ? sectionFocus[ui.view]
1911
2297
  : (availableSections[0] || 'current-run');
1912
2298
 
1913
- if (key.tab && ui.view === 'runs' && previewOpen) {
2299
+ if (key.tab && previewOpen) {
1914
2300
  setPaneFocus((previous) => (previous === 'main' ? 'preview' : 'main'));
1915
2301
  return;
1916
2302
  }
1917
2303
 
1918
- if (ui.view === 'overview' && activeSection === 'intent-status') {
2304
+ if (ui.view === 'intents' && activeSection === 'intent-status') {
1919
2305
  if (input === 'n') {
1920
2306
  setOverviewIntentFilter('next');
1921
2307
  return;
@@ -1954,34 +2340,21 @@ function createDashboardApp(deps) {
1954
2340
  setPaneFocus('main');
1955
2341
  return;
1956
2342
  }
1957
- if (input === 'f') {
1958
- setSectionFocus((previous) => ({ ...previous, runs: 'run-files' }));
1959
- setPaneFocus('main');
1960
- return;
1961
- }
1962
- if (input === 'p') {
1963
- setSectionFocus((previous) => ({ ...previous, runs: 'pending' }));
1964
- setPaneFocus('main');
1965
- return;
1966
- }
1967
- } else if (ui.view === 'overview') {
1968
- if (input === 'p') {
1969
- setSectionFocus((previous) => ({ ...previous, overview: 'project' }));
1970
- return;
1971
- }
2343
+ } else if (ui.view === 'intents') {
1972
2344
  if (input === 'i') {
1973
- setSectionFocus((previous) => ({ ...previous, overview: 'intent-status' }));
1974
- return;
1975
- }
1976
- if (input === 's') {
1977
- setSectionFocus((previous) => ({ ...previous, overview: 'standards' }));
2345
+ setSectionFocus((previous) => ({ ...previous, intents: 'intent-status' }));
1978
2346
  return;
1979
2347
  }
2348
+ } else if (ui.view === 'completed') {
1980
2349
  if (input === 'c') {
1981
- setSectionFocus((previous) => ({ ...previous, overview: 'completed-runs' }));
2350
+ setSectionFocus((previous) => ({ ...previous, completed: 'completed-runs' }));
1982
2351
  return;
1983
2352
  }
1984
2353
  } else if (ui.view === 'health') {
2354
+ if (input === 's') {
2355
+ setSectionFocus((previous) => ({ ...previous, health: 'standards' }));
2356
+ return;
2357
+ }
1985
2358
  if (input === 't') {
1986
2359
  setSectionFocus((previous) => ({ ...previous, health: 'stats' }));
1987
2360
  return;
@@ -2010,7 +2383,7 @@ function createDashboardApp(deps) {
2010
2383
  }
2011
2384
  }
2012
2385
 
2013
- if (ui.view === 'runs' && (key.upArrow || key.downArrow || input === 'j' || input === 'k')) {
2386
+ if (key.upArrow || key.downArrow || input === 'j' || input === 'k') {
2014
2387
  const moveDown = key.downArrow || input === 'j';
2015
2388
  const moveUp = key.upArrow || input === 'k';
2016
2389
 
@@ -2023,11 +2396,7 @@ function createDashboardApp(deps) {
2023
2396
  return;
2024
2397
  }
2025
2398
 
2026
- const targetSection = activeSection === 'current-run' ? 'run-files' : activeSection;
2027
- if (targetSection !== activeSection) {
2028
- setSectionFocus((previous) => ({ ...previous, runs: targetSection }));
2029
- }
2030
-
2399
+ const targetSection = activeSection;
2031
2400
  const targetRows = rowsBySection[targetSection] || [];
2032
2401
  if (targetRows.length === 0) {
2033
2402
  return;
@@ -2045,24 +2414,22 @@ function createDashboardApp(deps) {
2045
2414
  return;
2046
2415
  }
2047
2416
 
2048
- if (ui.view === 'runs' && (key.return || key.enter)) {
2049
- if (activeSection === 'pending' || activeSection === 'completed') {
2050
- const rowsForSection = rowsBySection[activeSection] || [];
2051
- const selectedRow = getSelectedRow(rowsForSection, selectionBySection[activeSection] || 0);
2052
- if (selectedRow?.kind === 'group' && selectedRow.expandable) {
2053
- setExpandedGroups((previous) => ({
2054
- ...previous,
2055
- [selectedRow.key]: !previous[selectedRow.key]
2056
- }));
2057
- }
2417
+ if (key.return || key.enter) {
2418
+ const rowsForSection = rowsBySection[activeSection] || [];
2419
+ const selectedRow = getSelectedRow(rowsForSection, selectionBySection[activeSection] || 0);
2420
+ if (selectedRow?.kind === 'group' && selectedRow.expandable) {
2421
+ setExpandedGroups((previous) => ({
2422
+ ...previous,
2423
+ [selectedRow.key]: !previous[selectedRow.key]
2424
+ }));
2058
2425
  }
2059
2426
  return;
2060
2427
  }
2061
2428
 
2062
- if (input === 'v' && ui.view === 'runs') {
2429
+ if (input === 'v') {
2063
2430
  const target = selectedFocusedFile || previewTarget;
2064
2431
  if (!target) {
2065
- setStatusLine('Select a file row first (run files, pending, or completed).');
2432
+ setStatusLine('Select a file row first.');
2066
2433
  return;
2067
2434
  }
2068
2435
 
@@ -2100,7 +2467,7 @@ function createDashboardApp(deps) {
2100
2467
  return;
2101
2468
  }
2102
2469
 
2103
- if (input === 'o' && ui.view === 'runs') {
2470
+ if (input === 'o') {
2104
2471
  const target = selectedFocusedFile || previewTarget;
2105
2472
  const result = openFileWithDefaultApp(target?.path);
2106
2473
  setStatusLine(result.message);
@@ -2112,21 +2479,38 @@ function createDashboardApp(deps) {
2112
2479
  }, [refresh]);
2113
2480
 
2114
2481
  useEffect(() => {
2115
- setSelectionBySection((previous) => ({
2116
- ...previous,
2117
- 'run-files': clampIndex(previous['run-files'] || 0, runFileRows.length),
2118
- pending: clampIndex(previous.pending || 0, pendingRows.length),
2119
- completed: clampIndex(previous.completed || 0, completedRows.length)
2120
- }));
2121
- }, [activeFlow, runFileRows.length, pendingRows.length, completedRows.length, snapshot?.generatedAt]);
2482
+ setSelectionBySection((previous) => {
2483
+ let changed = false;
2484
+ const next = { ...previous };
2485
+
2486
+ for (const [sectionKey, sectionRows] of Object.entries(rowsBySection)) {
2487
+ const previousValue = Number.isFinite(previous[sectionKey]) ? previous[sectionKey] : 0;
2488
+ const clampedValue = clampIndex(previousValue, sectionRows.length);
2489
+ if (previousValue !== clampedValue) {
2490
+ next[sectionKey] = clampedValue;
2491
+ changed = true;
2492
+ } else if (!(sectionKey in next)) {
2493
+ next[sectionKey] = clampedValue;
2494
+ changed = true;
2495
+ }
2496
+ }
2497
+
2498
+ return changed ? next : previous;
2499
+ });
2500
+ }, [activeFlow, rowLengthSignature, snapshot?.generatedAt]);
2122
2501
 
2123
2502
  useEffect(() => {
2124
- if (ui.view !== 'runs') {
2125
- setPreviewOpen(false);
2126
- setOverlayPreviewOpen(false);
2127
- setPreviewScroll(0);
2128
- setPaneFocus('main');
2129
- }
2503
+ setDeferredTabsReady(false);
2504
+ const timer = setTimeout(() => {
2505
+ setDeferredTabsReady(true);
2506
+ }, 0);
2507
+ return () => {
2508
+ clearTimeout(timer);
2509
+ };
2510
+ }, [activeFlow, snapshot?.generatedAt]);
2511
+
2512
+ useEffect(() => {
2513
+ setPaneFocus('main');
2130
2514
  }, [ui.view]);
2131
2515
 
2132
2516
  useEffect(() => {
@@ -2240,16 +2624,17 @@ function createDashboardApp(deps) {
2240
2624
  const rows = Number.isFinite(terminalSize.rows) ? terminalSize.rows : (process.stdout.rows || 40);
2241
2625
 
2242
2626
  const fullWidth = Math.max(40, cols - 1);
2243
- const showHelpLine = ui.showHelp && rows >= 14;
2627
+ const showFooterHelpLine = rows >= 10;
2244
2628
  const showErrorPanel = Boolean(error) && rows >= 18;
2629
+ const showGlobalErrorPanel = showErrorPanel && ui.view !== 'health' && !ui.showHelp;
2245
2630
  const showErrorInline = Boolean(error) && !showErrorPanel;
2246
2631
  const densePanels = rows <= 28 || cols <= 120;
2247
2632
 
2248
- const reservedRows = 2 + (showHelpLine ? 1 : 0) + (showErrorPanel ? 5 : 0) + (showErrorInline ? 1 : 0);
2633
+ const reservedRows = 2 + (showFooterHelpLine ? 1 : 0) + (showGlobalErrorPanel ? 5 : 0) + (showErrorInline ? 1 : 0);
2249
2634
  const contentRowsBudget = Math.max(4, rows - reservedRows);
2250
2635
  const ultraCompact = rows <= 14;
2251
2636
  const panelTitles = getPanelTitles(activeFlow, snapshot);
2252
- const splitPreviewLayout = ui.view === 'runs' && previewOpen && !overlayPreviewOpen && cols >= 110 && rows >= 16;
2637
+ const splitPreviewLayout = previewOpen && !overlayPreviewOpen && !ui.showHelp && cols >= 110 && rows >= 16;
2253
2638
  const mainPaneWidth = splitPreviewLayout
2254
2639
  ? Math.max(34, Math.floor((fullWidth - 1) * 0.52))
2255
2640
  : fullWidth;
@@ -2259,19 +2644,17 @@ function createDashboardApp(deps) {
2259
2644
  const mainCompactWidth = Math.max(18, mainPaneWidth - 4);
2260
2645
  const previewCompactWidth = Math.max(18, previewPaneWidth - 4);
2261
2646
 
2262
- const runFileLines = buildInteractiveRowsLines(
2263
- runFileRows,
2264
- selectionBySection['run-files'] || 0,
2265
- icons,
2266
- mainCompactWidth,
2267
- ui.view === 'runs' && focusedSection === 'run-files' && paneFocus === 'main'
2268
- );
2269
- const pendingLines = buildInteractiveRowsLines(
2270
- pendingRows,
2271
- selectionBySection.pending || 0,
2272
- icons,
2273
- mainCompactWidth,
2274
- ui.view === 'runs' && focusedSection === 'pending' && paneFocus === 'main'
2647
+ const sectionLines = Object.fromEntries(
2648
+ Object.entries(rowsBySection).map(([sectionKey, sectionRows]) => [
2649
+ sectionKey,
2650
+ buildInteractiveRowsLines(
2651
+ sectionRows,
2652
+ selectionBySection[sectionKey] || 0,
2653
+ icons,
2654
+ mainCompactWidth,
2655
+ paneFocus === 'main' && focusedSection === sectionKey
2656
+ )
2657
+ ])
2275
2658
  );
2276
2659
  const effectivePreviewTarget = previewTarget || selectedFocusedFile;
2277
2660
  const previewLines = previewOpen
@@ -2280,8 +2663,32 @@ function createDashboardApp(deps) {
2280
2663
  })
2281
2664
  : [];
2282
2665
 
2666
+ const shortcutsOverlayLines = buildHelpOverlayLines({
2667
+ view: ui.view,
2668
+ flow: activeFlow,
2669
+ previewOpen,
2670
+ paneFocus,
2671
+ availableFlowCount: availableFlowIds.length,
2672
+ showErrorSection: showErrorPanel
2673
+ });
2674
+ const quickHelpText = buildQuickHelpText(ui.view, {
2675
+ flow: activeFlow,
2676
+ previewOpen,
2677
+ paneFocus,
2678
+ availableFlowCount: availableFlowIds.length
2679
+ });
2680
+
2283
2681
  let panelCandidates;
2284
- if (ui.view === 'runs' && previewOpen && overlayPreviewOpen) {
2682
+ if (ui.showHelp) {
2683
+ panelCandidates = [
2684
+ {
2685
+ key: 'shortcuts-overlay',
2686
+ title: 'Keyboard Shortcuts',
2687
+ lines: shortcutsOverlayLines,
2688
+ borderColor: 'cyan'
2689
+ }
2690
+ ];
2691
+ } else if (previewOpen && overlayPreviewOpen) {
2285
2692
  panelCandidates = [
2286
2693
  {
2287
2694
  key: 'preview-overlay',
@@ -2290,45 +2697,42 @@ function createDashboardApp(deps) {
2290
2697
  borderColor: 'magenta'
2291
2698
  }
2292
2699
  ];
2293
- } else if (ui.view === 'overview') {
2700
+ } else if (ui.view === 'intents') {
2294
2701
  panelCandidates = [
2295
2702
  {
2296
2703
  key: 'intent-status',
2297
2704
  title: 'Intents',
2298
- lines: buildOverviewIntentLines(snapshot, mainCompactWidth, activeFlow, overviewIntentFilter),
2705
+ lines: sectionLines['intent-status'],
2299
2706
  borderColor: 'yellow'
2300
- },
2707
+ }
2708
+ ];
2709
+ } else if (ui.view === 'completed') {
2710
+ panelCandidates = [
2301
2711
  {
2302
2712
  key: 'completed-runs',
2303
2713
  title: panelTitles.completed,
2304
- lines: buildCompletedLines(snapshot, mainCompactWidth, activeFlow),
2714
+ lines: sectionLines['completed-runs'],
2305
2715
  borderColor: 'blue'
2306
- },
2716
+ }
2717
+ ];
2718
+ } else if (ui.view === 'health') {
2719
+ panelCandidates = [
2307
2720
  {
2308
2721
  key: 'standards',
2309
2722
  title: 'Standards',
2310
- lines: buildOverviewStandardsLines(snapshot, mainCompactWidth, activeFlow),
2723
+ lines: sectionLines.standards,
2311
2724
  borderColor: 'blue'
2312
2725
  },
2313
- {
2314
- key: 'project',
2315
- title: 'Project + Workspace',
2316
- lines: buildOverviewProjectLines(snapshot, mainCompactWidth, activeFlow),
2317
- borderColor: 'green'
2318
- }
2319
- ];
2320
- } else if (ui.view === 'health') {
2321
- panelCandidates = [
2322
2726
  {
2323
2727
  key: 'stats',
2324
2728
  title: 'Stats',
2325
- lines: buildStatsLines(snapshot, mainCompactWidth, activeFlow),
2729
+ lines: sectionLines.stats,
2326
2730
  borderColor: 'magenta'
2327
2731
  },
2328
2732
  {
2329
2733
  key: 'warnings',
2330
2734
  title: 'Warnings',
2331
- lines: buildWarningsLines(snapshot, mainCompactWidth),
2735
+ lines: sectionLines.warnings,
2332
2736
  borderColor: 'red'
2333
2737
  }
2334
2738
  ];
@@ -2337,61 +2741,40 @@ function createDashboardApp(deps) {
2337
2741
  panelCandidates.push({
2338
2742
  key: 'error-details',
2339
2743
  title: 'Error Details',
2340
- lines: buildErrorLines(error, mainCompactWidth),
2744
+ lines: sectionLines['error-details'],
2341
2745
  borderColor: 'red'
2342
2746
  });
2343
2747
  }
2344
2748
  } else {
2345
- const includeInlinePreviewPanel = previewOpen && !splitPreviewLayout;
2346
2749
  panelCandidates = [
2347
2750
  {
2348
2751
  key: 'current-run',
2349
2752
  title: panelTitles.current,
2350
- lines: buildCurrentRunLines(snapshot, mainCompactWidth, activeFlow),
2753
+ lines: sectionLines['current-run'],
2351
2754
  borderColor: 'green'
2352
- },
2353
- {
2354
- key: 'run-files',
2355
- title: panelTitles.files,
2356
- lines: runFileLines,
2357
- borderColor: 'yellow'
2358
- },
2359
- includeInlinePreviewPanel
2360
- ? {
2361
- key: 'preview',
2362
- title: `Preview: ${effectivePreviewTarget?.label || 'unknown'}`,
2363
- lines: previewLines,
2364
- borderColor: 'magenta'
2365
- }
2366
- : null,
2367
- {
2368
- key: 'pending',
2369
- title: panelTitles.pending,
2370
- lines: pendingLines,
2371
- borderColor: 'yellow'
2372
2755
  }
2373
2756
  ];
2374
2757
  }
2375
2758
 
2759
+ if (!ui.showHelp && previewOpen && !overlayPreviewOpen && !splitPreviewLayout) {
2760
+ panelCandidates.push({
2761
+ key: 'preview',
2762
+ title: `Preview: ${effectivePreviewTarget?.label || 'unknown'}`,
2763
+ lines: previewLines,
2764
+ borderColor: 'magenta'
2765
+ });
2766
+ }
2767
+
2376
2768
  if (ultraCompact && !splitPreviewLayout) {
2377
2769
  if (previewOpen) {
2378
- panelCandidates = panelCandidates.filter((panel) => panel && (panel.key === 'current-run' || panel.key === 'preview'));
2770
+ panelCandidates = panelCandidates.filter((panel) => panel && (panel.key === focusedSection || panel.key === 'preview'));
2379
2771
  } else {
2380
- panelCandidates = [panelCandidates[0]];
2772
+ const focusedPanel = panelCandidates.find((panel) => panel?.key === focusedSection);
2773
+ panelCandidates = [focusedPanel || panelCandidates[0]];
2381
2774
  }
2382
2775
  }
2383
2776
 
2384
2777
  const panels = allocateSingleColumnPanels(panelCandidates, contentRowsBudget);
2385
- const flowSwitchHint = availableFlowIds.length > 1 ? ' | [ or ] switch flow' : '';
2386
- const sectionHint = ui.view === 'runs'
2387
- ? ' | a active | f files | p pending'
2388
- : (ui.view === 'overview' ? ' | i intents | c completed | s standards | p project | n/x intent filter' : ' | t stats | w warnings | e errors');
2389
- const previewHint = ui.view === 'runs'
2390
- ? (previewOpen
2391
- ? ` | tab ${paneFocus === 'preview' ? 'main' : 'preview'} | ↑/↓ ${paneFocus === 'preview' ? 'scroll' : 'navigate'} | v close | vv fullscreen`
2392
- : ' | ↑/↓ navigate | enter expand | v preview | vv fullscreen | o open')
2393
- : '';
2394
- const helpText = `q quit | r refresh | h/? help | 1 runs | 2 overview | 3 health | g/G section${sectionHint}${previewHint}${flowSwitchHint}`;
2395
2778
 
2396
2779
  const renderPanel = (panel, index, width, isFocused) => React.createElement(SectionPanel, {
2397
2780
  key: panel.key,
@@ -2406,7 +2789,7 @@ function createDashboardApp(deps) {
2406
2789
  });
2407
2790
 
2408
2791
  let contentNode;
2409
- if (splitPreviewLayout && ui.view === 'runs' && !overlayPreviewOpen) {
2792
+ if (splitPreviewLayout && !overlayPreviewOpen) {
2410
2793
  const previewPanel = {
2411
2794
  key: 'preview-split',
2412
2795
  title: `Preview: ${effectivePreviewTarget?.label || 'unknown'}`,
@@ -2455,9 +2838,11 @@ function createDashboardApp(deps) {
2455
2838
  panel,
2456
2839
  index,
2457
2840
  fullWidth,
2458
- (panel.key === 'preview' || panel.key === 'preview-overlay')
2841
+ ui.showHelp
2842
+ ? true
2843
+ : ((panel.key === 'preview' || panel.key === 'preview-overlay')
2459
2844
  ? paneFocus === 'preview'
2460
- : (paneFocus === 'main' && panel.key === focusedSection)
2845
+ : (paneFocus === 'main' && panel.key === focusedSection))
2461
2846
  ));
2462
2847
  }
2463
2848
 
@@ -2466,11 +2851,11 @@ function createDashboardApp(deps) {
2466
2851
  { flexDirection: 'column', width: fullWidth },
2467
2852
  React.createElement(Text, { color: 'cyan' }, buildHeaderLine(snapshot, activeFlow, watchEnabled, watchStatus, lastRefreshAt, ui.view, fullWidth)),
2468
2853
  React.createElement(FlowBar, { activeFlow, width: fullWidth, flowIds: availableFlowIds }),
2469
- React.createElement(TabsBar, { view: ui.view, width: fullWidth, icons }),
2854
+ React.createElement(TabsBar, { view: ui.view, width: fullWidth, icons, flow: activeFlow }),
2470
2855
  showErrorInline
2471
2856
  ? React.createElement(Text, { color: 'red' }, truncate(buildErrorLines(error, fullWidth)[0] || 'Error', fullWidth))
2472
2857
  : null,
2473
- showErrorPanel
2858
+ showGlobalErrorPanel
2474
2859
  ? React.createElement(SectionPanel, {
2475
2860
  title: 'Errors',
2476
2861
  lines: buildErrorLines(error, Math.max(18, fullWidth - 4)),
@@ -2486,8 +2871,8 @@ function createDashboardApp(deps) {
2486
2871
  statusLine !== ''
2487
2872
  ? React.createElement(Text, { color: 'yellow' }, truncate(statusLine, fullWidth))
2488
2873
  : null,
2489
- showHelpLine
2490
- ? React.createElement(Text, { color: 'gray' }, truncate(helpText, fullWidth))
2874
+ showFooterHelpLine
2875
+ ? React.createElement(Text, { color: 'gray' }, truncate(quickHelpText, fullWidth))
2491
2876
  : null
2492
2877
  );
2493
2878
  }
@@ -1,15 +1,18 @@
1
1
  function createInitialUIState() {
2
2
  return {
3
3
  view: 'runs',
4
- showHelp: true
4
+ showHelp: false
5
5
  };
6
6
  }
7
7
 
8
8
  function cycleView(current) {
9
9
  if (current === 'runs') {
10
- return 'overview';
10
+ return 'intents';
11
11
  }
12
- if (current === 'overview') {
12
+ if (current === 'intents') {
13
+ return 'completed';
14
+ }
15
+ if (current === 'completed') {
13
16
  return 'health';
14
17
  }
15
18
  return 'runs';
@@ -19,10 +22,13 @@ function cycleViewBackward(current) {
19
22
  if (current === 'runs') {
20
23
  return 'health';
21
24
  }
22
- if (current === 'overview') {
25
+ if (current === 'intents') {
23
26
  return 'runs';
24
27
  }
25
- return 'overview';
28
+ if (current === 'completed') {
29
+ return 'intents';
30
+ }
31
+ return 'completed';
26
32
  }
27
33
 
28
34
  module.exports = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "specsmd",
3
- "version": "0.1.34",
3
+ "version": "0.1.36",
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": {