specsmd 0.1.34 → 0.1.35

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.
@@ -1397,6 +1397,81 @@ function openFileWithDefaultApp(filePath) {
1397
1397
  };
1398
1398
  }
1399
1399
 
1400
+ function buildQuickHelpText(view, options = {}) {
1401
+ const {
1402
+ previewOpen = false,
1403
+ availableFlowCount = 1
1404
+ } = options;
1405
+
1406
+ const parts = ['1/2/3 views', 'g/G sections'];
1407
+
1408
+ if (view === 'runs') {
1409
+ if (previewOpen) {
1410
+ parts.push('tab pane', '↑/↓ nav/scroll', 'v close');
1411
+ } else {
1412
+ parts.push('↑/↓ navigate', 'enter expand', 'v preview');
1413
+ }
1414
+ }
1415
+
1416
+ if (availableFlowCount > 1) {
1417
+ parts.push('[/] flow');
1418
+ }
1419
+
1420
+ parts.push('r refresh', '? shortcuts', 'q quit');
1421
+ return parts.join(' | ');
1422
+ }
1423
+
1424
+ function buildHelpOverlayLines(options = {}) {
1425
+ const {
1426
+ view = 'runs',
1427
+ previewOpen = false,
1428
+ paneFocus = 'main',
1429
+ availableFlowCount = 1,
1430
+ showErrorSection = false
1431
+ } = options;
1432
+
1433
+ const lines = [
1434
+ { text: 'Global', color: 'cyan', bold: true },
1435
+ 'q or Ctrl+C quit',
1436
+ 'r refresh snapshot',
1437
+ '1 runs | 2 overview | 3 health',
1438
+ 'g next section | G previous section',
1439
+ 'h/? toggle this shortcuts overlay',
1440
+ 'esc close overlays (help/preview/fullscreen)',
1441
+ { text: '', color: undefined, bold: false },
1442
+ { text: 'Runs View', color: 'yellow', bold: true },
1443
+ 'a current | f files | p pending',
1444
+ 'up/down or j/k move selection',
1445
+ 'enter expand/collapse pending/completed groups',
1446
+ 'v preview selected file',
1447
+ 'v twice quickly opens fullscreen preview overlay',
1448
+ 'tab switch focus between main and preview panes',
1449
+ 'o open selected file in system default app'
1450
+ ];
1451
+
1452
+ if (previewOpen) {
1453
+ lines.push(`preview is open (focus: ${paneFocus})`);
1454
+ }
1455
+
1456
+ if (availableFlowCount > 1) {
1457
+ lines.push('[/] (and m) switch flow');
1458
+ }
1459
+
1460
+ lines.push(
1461
+ { text: '', color: undefined, bold: false },
1462
+ { text: 'Overview View', color: 'green', bold: true },
1463
+ 'i intents | c completed | s standards | p project',
1464
+ 'when Intents is focused: n next | x completed | left/right toggle filter',
1465
+ { text: '', color: undefined, bold: false },
1466
+ { text: 'Health View', color: 'magenta', bold: true },
1467
+ `t stats | w warnings${showErrorSection ? ' | e errors' : ''}`,
1468
+ { text: '', color: undefined, bold: false },
1469
+ { text: `Current view: ${String(view || 'runs').toUpperCase()}`, color: 'gray', bold: false }
1470
+ );
1471
+
1472
+ return lines;
1473
+ }
1474
+
1400
1475
  function colorizeMarkdownLine(line, inCodeBlock) {
1401
1476
  const text = String(line ?? '');
1402
1477
 
@@ -1823,6 +1898,15 @@ function createDashboardApp(deps) {
1823
1898
  return;
1824
1899
  }
1825
1900
 
1901
+ if (key.escape && ui.showHelp) {
1902
+ setUi((previous) => ({ ...previous, showHelp: false }));
1903
+ return;
1904
+ }
1905
+
1906
+ if (ui.showHelp) {
1907
+ return;
1908
+ }
1909
+
1826
1910
  if (input === '1') {
1827
1911
  setUi((previous) => ({ ...previous, view: 'runs' }));
1828
1912
  setPaneFocus('main');
@@ -2240,16 +2324,16 @@ function createDashboardApp(deps) {
2240
2324
  const rows = Number.isFinite(terminalSize.rows) ? terminalSize.rows : (process.stdout.rows || 40);
2241
2325
 
2242
2326
  const fullWidth = Math.max(40, cols - 1);
2243
- const showHelpLine = ui.showHelp && rows >= 14;
2327
+ const showFooterHelpLine = rows >= 10;
2244
2328
  const showErrorPanel = Boolean(error) && rows >= 18;
2245
2329
  const showErrorInline = Boolean(error) && !showErrorPanel;
2246
2330
  const densePanels = rows <= 28 || cols <= 120;
2247
2331
 
2248
- const reservedRows = 2 + (showHelpLine ? 1 : 0) + (showErrorPanel ? 5 : 0) + (showErrorInline ? 1 : 0);
2332
+ const reservedRows = 2 + (showFooterHelpLine ? 1 : 0) + (showErrorPanel ? 5 : 0) + (showErrorInline ? 1 : 0);
2249
2333
  const contentRowsBudget = Math.max(4, rows - reservedRows);
2250
2334
  const ultraCompact = rows <= 14;
2251
2335
  const panelTitles = getPanelTitles(activeFlow, snapshot);
2252
- const splitPreviewLayout = ui.view === 'runs' && previewOpen && !overlayPreviewOpen && cols >= 110 && rows >= 16;
2336
+ const splitPreviewLayout = ui.view === 'runs' && previewOpen && !overlayPreviewOpen && !ui.showHelp && cols >= 110 && rows >= 16;
2253
2337
  const mainPaneWidth = splitPreviewLayout
2254
2338
  ? Math.max(34, Math.floor((fullWidth - 1) * 0.52))
2255
2339
  : fullWidth;
@@ -2280,8 +2364,30 @@ function createDashboardApp(deps) {
2280
2364
  })
2281
2365
  : [];
2282
2366
 
2367
+ const shortcutsOverlayLines = buildHelpOverlayLines({
2368
+ view: ui.view,
2369
+ previewOpen,
2370
+ paneFocus,
2371
+ availableFlowCount: availableFlowIds.length,
2372
+ showErrorSection: showErrorPanel
2373
+ });
2374
+ const quickHelpText = buildQuickHelpText(ui.view, {
2375
+ previewOpen,
2376
+ paneFocus,
2377
+ availableFlowCount: availableFlowIds.length
2378
+ });
2379
+
2283
2380
  let panelCandidates;
2284
- if (ui.view === 'runs' && previewOpen && overlayPreviewOpen) {
2381
+ if (ui.showHelp) {
2382
+ panelCandidates = [
2383
+ {
2384
+ key: 'shortcuts-overlay',
2385
+ title: 'Keyboard Shortcuts',
2386
+ lines: shortcutsOverlayLines,
2387
+ borderColor: 'cyan'
2388
+ }
2389
+ ];
2390
+ } else if (ui.view === 'runs' && previewOpen && overlayPreviewOpen) {
2285
2391
  panelCandidates = [
2286
2392
  {
2287
2393
  key: 'preview-overlay',
@@ -2382,16 +2488,6 @@ function createDashboardApp(deps) {
2382
2488
  }
2383
2489
 
2384
2490
  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
2491
 
2396
2492
  const renderPanel = (panel, index, width, isFocused) => React.createElement(SectionPanel, {
2397
2493
  key: panel.key,
@@ -2455,9 +2551,11 @@ function createDashboardApp(deps) {
2455
2551
  panel,
2456
2552
  index,
2457
2553
  fullWidth,
2458
- (panel.key === 'preview' || panel.key === 'preview-overlay')
2554
+ ui.showHelp
2555
+ ? true
2556
+ : ((panel.key === 'preview' || panel.key === 'preview-overlay')
2459
2557
  ? paneFocus === 'preview'
2460
- : (paneFocus === 'main' && panel.key === focusedSection)
2558
+ : (paneFocus === 'main' && panel.key === focusedSection))
2461
2559
  ));
2462
2560
  }
2463
2561
 
@@ -2486,8 +2584,8 @@ function createDashboardApp(deps) {
2486
2584
  statusLine !== ''
2487
2585
  ? React.createElement(Text, { color: 'yellow' }, truncate(statusLine, fullWidth))
2488
2586
  : null,
2489
- showHelpLine
2490
- ? React.createElement(Text, { color: 'gray' }, truncate(helpText, fullWidth))
2587
+ showFooterHelpLine
2588
+ ? React.createElement(Text, { color: 'gray' }, truncate(quickHelpText, fullWidth))
2491
2589
  : null
2492
2590
  );
2493
2591
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "specsmd",
3
- "version": "0.1.34",
3
+ "version": "0.1.35",
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": {