specsmd 0.1.43 → 0.1.44

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.
@@ -2218,28 +2218,58 @@ function createDashboardApp(deps) {
2218
2218
  const primaryLabel = effectiveFlow === 'aidlc' ? 'BOLTS' : (effectiveFlow === 'simple' ? 'SPECS' : 'RUNS');
2219
2219
  const completedLabel = effectiveFlow === 'aidlc' ? 'COMPLETED BOLTS' : (effectiveFlow === 'simple' ? 'COMPLETED SPECS' : 'COMPLETED RUNS');
2220
2220
  const tabs = [
2221
- { id: 'runs', label: ` 1 ${icons.runs} ${primaryLabel} ` },
2222
- { id: 'intents', label: ` 2 ${icons.overview} INTENTS ` },
2223
- { id: 'completed', label: ` 3 ${icons.runs} ${completedLabel} ` },
2224
- { id: 'health', label: ` 4 ${icons.health} STANDARDS/HEALTH ` }
2221
+ { id: 'runs', label: `1 ${icons.runs} ${primaryLabel}` },
2222
+ { id: 'intents', label: `2 ${icons.overview} INTENTS` },
2223
+ { id: 'completed', label: `3 ${icons.runs} ${completedLabel}` },
2224
+ { id: 'health', label: `4 ${icons.health} STANDARDS/HEALTH` }
2225
2225
  ];
2226
+ const maxWidth = Math.max(8, Math.floor(width));
2227
+ const segments = [];
2228
+ let consumed = 0;
2229
+
2230
+ for (const tab of tabs) {
2231
+ const isActive = tab.id === view;
2232
+ const segmentText = isActive ? `[${tab.label}]` : tab.label;
2233
+ const separator = segments.length > 0 ? ' ' : '';
2234
+ const segmentWidth = stringWidth(separator) + stringWidth(segmentText);
2235
+ if (consumed + segmentWidth > maxWidth) {
2236
+ break;
2237
+ }
2238
+
2239
+ if (separator !== '') {
2240
+ segments.push({
2241
+ key: `${tab.id}:sep`,
2242
+ text: separator,
2243
+ active: false
2244
+ });
2245
+ }
2246
+ segments.push({
2247
+ key: tab.id,
2248
+ text: segmentText,
2249
+ active: isActive
2250
+ });
2251
+ consumed += segmentWidth;
2252
+ }
2253
+
2254
+ if (segments.length === 0) {
2255
+ const fallback = tabs.find((tab) => tab.id === view) || tabs[0];
2256
+ const fallbackText = truncate(`[${fallback.label}]`, maxWidth);
2257
+ return React.createElement(Text, { color: 'white', bold: true }, fallbackText);
2258
+ }
2226
2259
 
2227
2260
  return React.createElement(
2228
2261
  Box,
2229
- { width, flexWrap: 'nowrap' },
2230
- ...tabs.map((tab) => {
2231
- const isActive = tab.id === view;
2232
- return React.createElement(
2233
- Text,
2234
- {
2235
- key: tab.id,
2236
- bold: isActive,
2237
- color: isActive ? 'white' : 'gray',
2238
- backgroundColor: isActive ? 'blue' : undefined
2239
- },
2240
- tab.label
2241
- );
2242
- })
2262
+ { width: maxWidth, flexWrap: 'nowrap' },
2263
+ ...segments.map((segment) => React.createElement(
2264
+ Text,
2265
+ {
2266
+ key: segment.key,
2267
+ bold: segment.active,
2268
+ color: segment.active ? 'white' : 'gray',
2269
+ backgroundColor: segment.active ? 'blue' : undefined
2270
+ },
2271
+ segment.text
2272
+ ))
2243
2273
  );
2244
2274
  }
2245
2275
 
@@ -2248,23 +2278,52 @@ function createDashboardApp(deps) {
2248
2278
  if (!Array.isArray(flowIds) || flowIds.length <= 1) {
2249
2279
  return null;
2250
2280
  }
2281
+ const maxWidth = Math.max(8, Math.floor(width));
2282
+ const segments = [];
2283
+ let consumed = 0;
2284
+
2285
+ for (const flowId of flowIds) {
2286
+ const isActive = flowId === activeFlow;
2287
+ const segmentText = isActive ? `[${flowId.toUpperCase()}]` : flowId.toUpperCase();
2288
+ const separator = segments.length > 0 ? ' ' : '';
2289
+ const segmentWidth = stringWidth(separator) + stringWidth(segmentText);
2290
+ if (consumed + segmentWidth > maxWidth) {
2291
+ break;
2292
+ }
2293
+
2294
+ if (separator !== '') {
2295
+ segments.push({
2296
+ key: `${flowId}:sep`,
2297
+ text: separator,
2298
+ active: false
2299
+ });
2300
+ }
2301
+ segments.push({
2302
+ key: flowId,
2303
+ text: segmentText,
2304
+ active: isActive
2305
+ });
2306
+ consumed += segmentWidth;
2307
+ }
2308
+
2309
+ if (segments.length === 0) {
2310
+ const fallback = (activeFlow || flowIds[0] || 'flow').toUpperCase();
2311
+ return React.createElement(Text, { color: 'black', backgroundColor: 'green', bold: true }, truncate(`[${fallback}]`, maxWidth));
2312
+ }
2251
2313
 
2252
2314
  return React.createElement(
2253
2315
  Box,
2254
- { width, flexWrap: 'nowrap' },
2255
- ...flowIds.map((flowId) => {
2256
- const isActive = flowId === activeFlow;
2257
- return React.createElement(
2258
- Text,
2259
- {
2260
- key: flowId,
2261
- bold: isActive,
2262
- color: isActive ? 'black' : 'gray',
2263
- backgroundColor: isActive ? 'green' : undefined
2264
- },
2265
- ` ${flowId.toUpperCase()} `
2266
- );
2267
- })
2316
+ { width: maxWidth, flexWrap: 'nowrap' },
2317
+ ...segments.map((segment) => React.createElement(
2318
+ Text,
2319
+ {
2320
+ key: segment.key,
2321
+ bold: segment.active,
2322
+ color: segment.active ? 'black' : 'gray',
2323
+ backgroundColor: segment.active ? 'green' : undefined
2324
+ },
2325
+ segment.text
2326
+ ))
2268
2327
  );
2269
2328
  }
2270
2329
 
@@ -2888,6 +2947,12 @@ function createDashboardApp(deps) {
2888
2947
  columns: stdout.columns || process.stdout.columns || 120,
2889
2948
  rows: stdout.rows || process.stdout.rows || 40
2890
2949
  });
2950
+
2951
+ // Resize in some terminals can leave stale frame rows behind.
2952
+ // Force clear so next render paints from a clean origin.
2953
+ if (typeof stdout.write === 'function' && stdout.isTTY !== false) {
2954
+ stdout.write('\u001B[2J\u001B[3J\u001B[H');
2955
+ }
2891
2956
  };
2892
2957
 
2893
2958
  updateSize();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "specsmd",
3
- "version": "0.1.43",
3
+ "version": "0.1.44",
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": {