@sonnechasser/ntrp 2.1.10 → 2.1.11

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/dist/index.js CHANGED
@@ -2244,8 +2244,10 @@ var init_verbosity = __esm({
2244
2244
  // src/trace/result-block.ts
2245
2245
  var result_block_exports = {};
2246
2246
  __export(result_block_exports, {
2247
+ VITAL_PROBLEM_READ: () => VITAL_PROBLEM_READ,
2247
2248
  buildVitalHeadlines: () => buildVitalHeadlines,
2248
2249
  formatDuration: () => formatDuration,
2250
+ formatVitalCall: () => formatVitalCall,
2249
2251
  headlinesFromFindingCards: () => headlinesFromFindingCards,
2250
2252
  printArtifactLine: () => printArtifactLine,
2251
2253
  printMetricsResultBlock: () => printMetricsResultBlock,
@@ -2269,12 +2271,32 @@ function flagLabel(vitals, status) {
2269
2271
  function deltaCell(delta) {
2270
2272
  if (!delta) return " ";
2271
2273
  const rounded = Math.round(delta.delta);
2272
- if (rounded === 0) return chalk5.dim(" 0 ");
2274
+ if (rounded === 0) return " ";
2273
2275
  if (rounded < 0) {
2274
2276
  return paint("error", `\u25BC ${String(Math.abs(rounded)).padStart(2)} `);
2275
2277
  }
2276
2278
  return paint("success", `\u25B2 ${String(rounded).padStart(2)} `);
2277
2279
  }
2280
+ function otherRedLabels(health) {
2281
+ return health.vital_signs.filter((v) => v.status === "red" && v.vital_sign !== health.gating_vital_sign).map((v) => VITAL_SIGN_LABELS[v.vital_sign]);
2282
+ }
2283
+ function formatVitalCall(health) {
2284
+ const gateName = VITAL_SIGN_LABELS[health.gating_vital_sign];
2285
+ const gating = health.vital_signs.find((v) => v.vital_sign === health.gating_vital_sign);
2286
+ const read = VITAL_PROBLEM_READ[health.gating_vital_sign];
2287
+ const alsoRed = otherRedLabels(health);
2288
+ const dollars = health.total_value_at_risk;
2289
+ const head = dollars != null && dollars > 0 ? `${formatCurrency(dollars)} at risk.` : "No dollar-weighted risk.";
2290
+ let start = `Start with ${gateName}`;
2291
+ if (gating && gating.dollar_value != null && gating.dollar_value > 0) {
2292
+ start += `: ${formatCurrency(gating.dollar_value)} ${read}`;
2293
+ }
2294
+ start += ".";
2295
+ if (alsoRed.length > 0) {
2296
+ start += ` Also red: ${alsoRed.join(", ")}.`;
2297
+ }
2298
+ return `${head} ${start}`;
2299
+ }
2278
2300
  function printVitalResultBlock(health, opts = {}) {
2279
2301
  const vitals = health.vital_signs;
2280
2302
  const deltaBySign = new Map((opts.deltas ?? []).map((d) => [d.vital_sign, d]));
@@ -2291,18 +2313,25 @@ function printVitalResultBlock(health, opts = {}) {
2291
2313
  console.log(` ${dot} ${label} ${score} ${delta} ${flag}`.trimEnd());
2292
2314
  }
2293
2315
  console.log();
2316
+ printVitalCall(health);
2317
+ printFindingsList(opts.findings ?? []);
2318
+ }
2319
+ function printVitalCall(health) {
2320
+ const gateName = VITAL_SIGN_LABELS[health.gating_vital_sign];
2321
+ const gating = health.vital_signs.find((v) => v.vital_sign === health.gating_vital_sign);
2322
+ const read = VITAL_PROBLEM_READ[health.gating_vital_sign];
2323
+ const alsoRed = otherRedLabels(health);
2294
2324
  const dollars = health.total_value_at_risk;
2295
- const gating = VITAL_SIGN_LABELS[health.gating_vital_sign];
2296
- const gatingVital = vitals.find((v) => v.vital_sign === health.gating_vital_sign);
2297
- if (dollars != null && dollars > 0) {
2298
- const why = gatingVital?.dollar_label ? ` (${gatingVital.dollar_label})` : "";
2299
- console.log(
2300
- ` ${paint("success", formatCurrency(dollars))} ${chalk5.dim("at risk")} ${chalk5.dim("\u2014")} ${chalk5.dim("held back by")} ${paint("accent", gating)}${chalk5.dim(why)}`
2301
- );
2302
- } else {
2303
- console.log(` ${chalk5.dim("No dollar-weighted risk detected")} ${chalk5.dim("\u2014")} ${chalk5.dim("held back by")} ${paint("accent", gating)}`);
2325
+ const head = dollars != null && dollars > 0 ? `${paint("success", formatCurrency(dollars))} at risk.` : "No dollar-weighted risk.";
2326
+ let start = `Start with ${paint("accent", gateName)}`;
2327
+ if (gating && gating.dollar_value != null && gating.dollar_value > 0) {
2328
+ start += `: ${formatCurrency(gating.dollar_value)} ${read}`;
2304
2329
  }
2305
- printFindingsList(opts.findings ?? []);
2330
+ start += ".";
2331
+ if (alsoRed.length > 0) {
2332
+ start += ` Also red: ${alsoRed.join(", ")}.`;
2333
+ }
2334
+ console.log(` ${head} ${start}`);
2306
2335
  }
2307
2336
  function printMetricsResultBlock(metrics, opts = {}) {
2308
2337
  const flagged = metrics.filter((m) => !m.unavailable_reason && (m.status === "red" || m.status === "yellow"));
@@ -2327,53 +2356,54 @@ function printMetricsResultBlock(metrics, opts = {}) {
2327
2356
  function printFindingsList(findings) {
2328
2357
  if (findings.length === 0) return;
2329
2358
  console.log();
2330
- console.log(` ${chalk5.bold("Findings")}`);
2331
2359
  findings.slice(0, 3).forEach((f, i) => {
2332
2360
  console.log(` ${chalk5.dim(`${i + 1}.`)} ${f.text}`);
2333
2361
  });
2334
2362
  }
2335
2363
  function printArtifactLine(path, description) {
2336
2364
  console.log();
2337
- const label = description?.trim() || "Full report";
2338
- console.log(` ${chalk5.dim(label)} ${chalk5.dim("\u2192")} ${path}`);
2339
- console.log(` ${chalk5.dim("Run with --verbose for per-vital detail.")}`);
2365
+ const label = description?.trim() || "Saved report";
2366
+ console.log(` ${chalk5.dim(label)} ${chalk5.dim("\u2192")} ${chalk5.dim(path)}`);
2340
2367
  console.log();
2341
2368
  }
2369
+ function problemPhrase(vs, who) {
2370
+ const read = VITAL_PROBLEM_READ[vs.vital_sign];
2371
+ const dollars = vs.dollar_value != null && vs.dollar_value > 0 ? formatCurrency(vs.dollar_value) : null;
2372
+ const prefix = who || VITAL_SIGN_LABELS[vs.vital_sign];
2373
+ if (dollars) return `${prefix}: ${dollars} ${read}`;
2374
+ return `${prefix}: ${VITAL_SIGN_LABELS[vs.vital_sign]} ${Math.round(vs.score)}`;
2375
+ }
2342
2376
  function buildVitalHeadlines(health, segments = []) {
2343
- const findings = [];
2344
- const gating = health.vital_signs.find((v) => v.vital_sign === health.gating_vital_sign);
2345
- if (gating) {
2346
- const label = VITAL_SIGN_LABELS[gating.vital_sign];
2347
- const dollars = gating.dollar_value != null && gating.dollar_value > 0 ? ` \u2014 ${formatCurrency(gating.dollar_value)} ${gating.dollar_label ?? ""}`.trimEnd() : "";
2348
- const severity = gating.status === "red" ? "critical" : gating.status === "yellow" ? "warn" : "info";
2349
- findings.push({
2350
- severity,
2351
- text: `${label} ${Math.round(gating.score)}${dollars}`
2352
- });
2353
- }
2354
2377
  const extras = [];
2355
- const sourceVitals = segments.length > 0 ? segments.flatMap(
2356
- (s) => s.result.vital_signs.map((vs) => ({ vs, segment: s.segment.name }))
2357
- ) : health.vital_signs.map((vs) => ({ vs, segment: "" }));
2358
- for (const { vs, segment } of sourceVitals) {
2359
- if (vs.status === "green") continue;
2360
- if (vs.vital_sign === health.gating_vital_sign && !segment) continue;
2361
- if (vs.dollar_value == null || vs.dollar_value <= 0) continue;
2362
- const label = VITAL_SIGN_LABELS[vs.vital_sign];
2363
- const who = segment ? `${segment}: ` : "";
2378
+ const push = (vs, who) => {
2379
+ if (vs.status === "green") return;
2380
+ if (vs.dollar_value == null || vs.dollar_value <= 0) return;
2364
2381
  extras.push({
2365
2382
  severity: vs.status === "red" ? "critical" : "warn",
2366
- text: `${who}${label} ${Math.round(vs.score)} \u2014 ${formatCurrency(vs.dollar_value)} ${vs.dollar_label ?? ""}`.trim(),
2383
+ text: problemPhrase(vs, who),
2367
2384
  dollars: vs.dollar_value
2368
2385
  });
2386
+ };
2387
+ if (segments.length > 0) {
2388
+ for (const s of segments) {
2389
+ for (const vs of s.result.vital_signs) {
2390
+ push(vs, s.segment.name);
2391
+ }
2392
+ }
2393
+ } else {
2394
+ for (const vs of health.vital_signs) {
2395
+ if (vs.vital_sign === health.gating_vital_sign) continue;
2396
+ push(vs);
2397
+ }
2369
2398
  }
2370
2399
  extras.sort((a, b) => b.dollars - a.dollars);
2400
+ const findings = [];
2371
2401
  for (const extra of extras) {
2372
2402
  if (findings.length >= 3) break;
2373
2403
  if (findings.some((f) => f.text === extra.text)) continue;
2374
2404
  findings.push({ severity: extra.severity, text: extra.text });
2375
2405
  }
2376
- return findings.slice(0, 3);
2406
+ return findings;
2377
2407
  }
2378
2408
  function headlinesFromFindingCards(cards) {
2379
2409
  return cards.slice(0, 3).map((card) => ({
@@ -2381,11 +2411,19 @@ function headlinesFromFindingCards(cards) {
2381
2411
  text: stripFindingMarkdown(card.finding)
2382
2412
  }));
2383
2413
  }
2414
+ var VITAL_PROBLEM_READ;
2384
2415
  var init_result_block = __esm({
2385
2416
  "src/trace/result-block.ts"() {
2386
2417
  "use strict";
2387
2418
  init_formatters();
2388
2419
  init_theme();
2420
+ VITAL_PROBLEM_READ = {
2421
+ freshness: "stale",
2422
+ flow_rate: "stuck",
2423
+ drop_rate: "lost at handoff",
2424
+ signal_to_noise: "misdirected effort",
2425
+ thread_depth: "single-threaded"
2426
+ };
2389
2427
  }
2390
2428
  });
2391
2429
 
@@ -2480,11 +2518,10 @@ var init_renderer = __esm({
2480
2518
  }
2481
2519
  const line = `${summary} \xB7 ${formatDuration(durationMs)}`;
2482
2520
  if (this.useSpinner() && this.spinner) {
2483
- this.spinner.succeed(line);
2521
+ this.spinner.stop();
2484
2522
  this.spinner = null;
2485
- return;
2486
2523
  }
2487
- console.log(` ${chalk6.green("\u2713")} ${line}`);
2524
+ console.log(` ${chalk6.green("\u2713")} ${chalk6.dim(line)}`);
2488
2525
  }
2489
2526
  persistDim(message) {
2490
2527
  const spinning = this.spinner?.isSpinning;
@@ -32055,8 +32092,6 @@ async function advanceAfterScopeConfirm(ctx) {
32055
32092
  const offered = await offerDemoToAnswer(ctx);
32056
32093
  if (offered) return "Demo loaded and analysis started";
32057
32094
  if (audit.can_compute) {
32058
- console.log();
32059
- console.log(" " + chalk30.dim("Computing so I can answer\u2026"));
32060
32095
  await runConversationCompute(ctx);
32061
32096
  recordMessage(ctx, "agent", "Scope confirmed. Analysis started.");
32062
32097
  return "Analysis started";
@@ -33346,12 +33381,6 @@ async function resumePendingAsk(ctx) {
33346
33381
  if (!pending?.text) return false;
33347
33382
  ctx.computeInProgress = false;
33348
33383
  if (canUseReplAi(ctx)) {
33349
- console.log();
33350
- console.log(
33351
- " " + chalk32.dim(
33352
- pending.keylessAnswered ? "Picking up your question with the connected engine\u2026" : "Picking up your question\u2026"
33353
- )
33354
- );
33355
33384
  console.log();
33356
33385
  const { runNaturalLanguage: runNaturalLanguage3 } = await Promise.resolve().then(() => (init_nl(), nl_exports));
33357
33386
  await runNaturalLanguage3(pending.text, ctx);
@@ -33633,7 +33662,7 @@ async function runDiagnoseTrace(options) {
33633
33662
  kind: "phase_end",
33634
33663
  phase: "compute",
33635
33664
  durationMs: Date.now() - computeStarted,
33636
- summary: "Vital signs computed"
33665
+ summary: "Pipeline scored"
33637
33666
  });
33638
33667
  computeEnded = true;
33639
33668
  }
@@ -33663,7 +33692,7 @@ async function runDiagnoseTrace(options) {
33663
33692
  kind: "phase_end",
33664
33693
  phase: "compute",
33665
33694
  durationMs: Date.now() - computeStarted,
33666
- summary: "Vital signs computed"
33695
+ summary: "Pipeline scored"
33667
33696
  });
33668
33697
  }
33669
33698
  if (fullResult && fullResult.segments.length > 0) {
@@ -33671,7 +33700,7 @@ async function runDiagnoseTrace(options) {
33671
33700
  kind: "phase_end",
33672
33701
  phase: "segments",
33673
33702
  durationMs: Date.now() - (segmentsStarted ?? Date.now()),
33674
- summary: `Segments computed \xB7 ${fullResult.segments.length}`
33703
+ summary: `${fullResult.segments.length} segment${fullResult.segments.length === 1 ? "" : "s"}`
33675
33704
  });
33676
33705
  }
33677
33706
  if (!fullResult) {
@@ -33777,7 +33806,7 @@ async function runDiagnoseTrace(options) {
33777
33806
  });
33778
33807
  const reportPath = ctx ? await writeSilentMarkdownReport(ctx, fullResult, collectedFindings) : null;
33779
33808
  if (reportPath) {
33780
- bus.emit({ kind: "artifact", path: reportPath, description: "Full report" });
33809
+ bus.emit({ kind: "artifact", path: reportPath, description: "Saved report" });
33781
33810
  } else if (ctx?.events instanceof EventBus) {
33782
33811
  bus.emit({ kind: "artifact", path: logPathForRun(ctx.events.runId), description: "Run log" });
33783
33812
  }
@@ -33998,7 +34027,7 @@ async function runSegmentDiagnose(options, ctx) {
33998
34027
  kind: "phase_end",
33999
34028
  phase: "compute",
34000
34029
  durationMs: Date.now() - t0,
34001
- summary: "Vital signs computed"
34030
+ summary: "Pipeline scored"
34002
34031
  });
34003
34032
  } catch (err) {
34004
34033
  bus.emit({ kind: "debug", message: String(err) });
@@ -34048,7 +34077,7 @@ async function runSegmentDiagnose(options, ctx) {
34048
34077
  }
34049
34078
  const reportPath = await writeSilentMarkdownReport2(ctx, result, []);
34050
34079
  if (reportPath) {
34051
- bus.emit({ kind: "artifact", path: reportPath, description: "Full report" });
34080
+ bus.emit({ kind: "artifact", path: reportPath, description: "Saved report" });
34052
34081
  }
34053
34082
  return buildDiagnoseSummary(match.result, []);
34054
34083
  }
@@ -40129,7 +40158,7 @@ async function handler28(args, ctx) {
40129
40158
  bus.emit({
40130
40159
  kind: "artifact",
40131
40160
  path: logPathForRun(bus.runId),
40132
- description: "Run log"
40161
+ description: "Saved log"
40133
40162
  });
40134
40163
  } catch (err) {
40135
40164
  bus.emit({ kind: "debug", message: String(err) });
@@ -45071,8 +45100,6 @@ async function ingestFromChat(ctx, filePath) {
45071
45100
  printGapCard(audit);
45072
45101
  if (audit.can_compute && ctx.scope?.confirmed_at) {
45073
45102
  if (ctx.pendingAsk) {
45074
- console.log();
45075
- console.log(" " + chalk88.dim("Computing so I can answer\u2026"));
45076
45103
  await runConversationCompute(ctx);
45077
45104
  return true;
45078
45105
  }
@@ -45156,8 +45183,6 @@ async function loadDemoFromChat(ctx, scenario, opts = {}) {
45156
45183
  const audit = await refreshGapAudit(ctx);
45157
45184
  const shouldAuto = opts.autoCompute || Boolean(ctx.pendingAsk && audit.can_compute && ctx.scope?.confirmed_at);
45158
45185
  if (shouldAuto && audit.can_compute) {
45159
- console.log();
45160
- console.log(" " + chalk88.dim("Computing so I can answer\u2026"));
45161
45186
  await runConversationCompute(ctx);
45162
45187
  return true;
45163
45188
  }
@@ -1634,8 +1634,10 @@ var init_verbosity = __esm({
1634
1634
  // src/trace/result-block.ts
1635
1635
  var result_block_exports = {};
1636
1636
  __export(result_block_exports, {
1637
+ VITAL_PROBLEM_READ: () => VITAL_PROBLEM_READ,
1637
1638
  buildVitalHeadlines: () => buildVitalHeadlines,
1638
1639
  formatDuration: () => formatDuration,
1640
+ formatVitalCall: () => formatVitalCall,
1639
1641
  headlinesFromFindingCards: () => headlinesFromFindingCards,
1640
1642
  printArtifactLine: () => printArtifactLine,
1641
1643
  printMetricsResultBlock: () => printMetricsResultBlock,
@@ -1659,12 +1661,32 @@ function flagLabel(vitals, status) {
1659
1661
  function deltaCell(delta) {
1660
1662
  if (!delta) return " ";
1661
1663
  const rounded = Math.round(delta.delta);
1662
- if (rounded === 0) return chalk5.dim(" 0 ");
1664
+ if (rounded === 0) return " ";
1663
1665
  if (rounded < 0) {
1664
1666
  return paint("error", `\u25BC ${String(Math.abs(rounded)).padStart(2)} `);
1665
1667
  }
1666
1668
  return paint("success", `\u25B2 ${String(rounded).padStart(2)} `);
1667
1669
  }
1670
+ function otherRedLabels(health) {
1671
+ return health.vital_signs.filter((v) => v.status === "red" && v.vital_sign !== health.gating_vital_sign).map((v) => VITAL_SIGN_LABELS[v.vital_sign]);
1672
+ }
1673
+ function formatVitalCall(health) {
1674
+ const gateName = VITAL_SIGN_LABELS[health.gating_vital_sign];
1675
+ const gating = health.vital_signs.find((v) => v.vital_sign === health.gating_vital_sign);
1676
+ const read = VITAL_PROBLEM_READ[health.gating_vital_sign];
1677
+ const alsoRed = otherRedLabels(health);
1678
+ const dollars = health.total_value_at_risk;
1679
+ const head = dollars != null && dollars > 0 ? `${formatCurrency(dollars)} at risk.` : "No dollar-weighted risk.";
1680
+ let start = `Start with ${gateName}`;
1681
+ if (gating && gating.dollar_value != null && gating.dollar_value > 0) {
1682
+ start += `: ${formatCurrency(gating.dollar_value)} ${read}`;
1683
+ }
1684
+ start += ".";
1685
+ if (alsoRed.length > 0) {
1686
+ start += ` Also red: ${alsoRed.join(", ")}.`;
1687
+ }
1688
+ return `${head} ${start}`;
1689
+ }
1668
1690
  function printVitalResultBlock(health, opts = {}) {
1669
1691
  const vitals = health.vital_signs;
1670
1692
  const deltaBySign = new Map((opts.deltas ?? []).map((d) => [d.vital_sign, d]));
@@ -1681,18 +1703,25 @@ function printVitalResultBlock(health, opts = {}) {
1681
1703
  console.log(` ${dot} ${label} ${score} ${delta} ${flag}`.trimEnd());
1682
1704
  }
1683
1705
  console.log();
1706
+ printVitalCall(health);
1707
+ printFindingsList(opts.findings ?? []);
1708
+ }
1709
+ function printVitalCall(health) {
1710
+ const gateName = VITAL_SIGN_LABELS[health.gating_vital_sign];
1711
+ const gating = health.vital_signs.find((v) => v.vital_sign === health.gating_vital_sign);
1712
+ const read = VITAL_PROBLEM_READ[health.gating_vital_sign];
1713
+ const alsoRed = otherRedLabels(health);
1684
1714
  const dollars = health.total_value_at_risk;
1685
- const gating = VITAL_SIGN_LABELS[health.gating_vital_sign];
1686
- const gatingVital = vitals.find((v) => v.vital_sign === health.gating_vital_sign);
1687
- if (dollars != null && dollars > 0) {
1688
- const why = gatingVital?.dollar_label ? ` (${gatingVital.dollar_label})` : "";
1689
- console.log(
1690
- ` ${paint("success", formatCurrency(dollars))} ${chalk5.dim("at risk")} ${chalk5.dim("\u2014")} ${chalk5.dim("held back by")} ${paint("accent", gating)}${chalk5.dim(why)}`
1691
- );
1692
- } else {
1693
- console.log(` ${chalk5.dim("No dollar-weighted risk detected")} ${chalk5.dim("\u2014")} ${chalk5.dim("held back by")} ${paint("accent", gating)}`);
1715
+ const head = dollars != null && dollars > 0 ? `${paint("success", formatCurrency(dollars))} at risk.` : "No dollar-weighted risk.";
1716
+ let start = `Start with ${paint("accent", gateName)}`;
1717
+ if (gating && gating.dollar_value != null && gating.dollar_value > 0) {
1718
+ start += `: ${formatCurrency(gating.dollar_value)} ${read}`;
1694
1719
  }
1695
- printFindingsList(opts.findings ?? []);
1720
+ start += ".";
1721
+ if (alsoRed.length > 0) {
1722
+ start += ` Also red: ${alsoRed.join(", ")}.`;
1723
+ }
1724
+ console.log(` ${head} ${start}`);
1696
1725
  }
1697
1726
  function printMetricsResultBlock(metrics, opts = {}) {
1698
1727
  const flagged = metrics.filter((m) => !m.unavailable_reason && (m.status === "red" || m.status === "yellow"));
@@ -1717,53 +1746,54 @@ function printMetricsResultBlock(metrics, opts = {}) {
1717
1746
  function printFindingsList(findings) {
1718
1747
  if (findings.length === 0) return;
1719
1748
  console.log();
1720
- console.log(` ${chalk5.bold("Findings")}`);
1721
1749
  findings.slice(0, 3).forEach((f, i) => {
1722
1750
  console.log(` ${chalk5.dim(`${i + 1}.`)} ${f.text}`);
1723
1751
  });
1724
1752
  }
1725
1753
  function printArtifactLine(path, description) {
1726
1754
  console.log();
1727
- const label = description?.trim() || "Full report";
1728
- console.log(` ${chalk5.dim(label)} ${chalk5.dim("\u2192")} ${path}`);
1729
- console.log(` ${chalk5.dim("Run with --verbose for per-vital detail.")}`);
1755
+ const label = description?.trim() || "Saved report";
1756
+ console.log(` ${chalk5.dim(label)} ${chalk5.dim("\u2192")} ${chalk5.dim(path)}`);
1730
1757
  console.log();
1731
1758
  }
1759
+ function problemPhrase(vs, who) {
1760
+ const read = VITAL_PROBLEM_READ[vs.vital_sign];
1761
+ const dollars = vs.dollar_value != null && vs.dollar_value > 0 ? formatCurrency(vs.dollar_value) : null;
1762
+ const prefix = who || VITAL_SIGN_LABELS[vs.vital_sign];
1763
+ if (dollars) return `${prefix}: ${dollars} ${read}`;
1764
+ return `${prefix}: ${VITAL_SIGN_LABELS[vs.vital_sign]} ${Math.round(vs.score)}`;
1765
+ }
1732
1766
  function buildVitalHeadlines(health, segments = []) {
1733
- const findings = [];
1734
- const gating = health.vital_signs.find((v) => v.vital_sign === health.gating_vital_sign);
1735
- if (gating) {
1736
- const label = VITAL_SIGN_LABELS[gating.vital_sign];
1737
- const dollars = gating.dollar_value != null && gating.dollar_value > 0 ? ` \u2014 ${formatCurrency(gating.dollar_value)} ${gating.dollar_label ?? ""}`.trimEnd() : "";
1738
- const severity = gating.status === "red" ? "critical" : gating.status === "yellow" ? "warn" : "info";
1739
- findings.push({
1740
- severity,
1741
- text: `${label} ${Math.round(gating.score)}${dollars}`
1742
- });
1743
- }
1744
1767
  const extras = [];
1745
- const sourceVitals = segments.length > 0 ? segments.flatMap(
1746
- (s) => s.result.vital_signs.map((vs) => ({ vs, segment: s.segment.name }))
1747
- ) : health.vital_signs.map((vs) => ({ vs, segment: "" }));
1748
- for (const { vs, segment } of sourceVitals) {
1749
- if (vs.status === "green") continue;
1750
- if (vs.vital_sign === health.gating_vital_sign && !segment) continue;
1751
- if (vs.dollar_value == null || vs.dollar_value <= 0) continue;
1752
- const label = VITAL_SIGN_LABELS[vs.vital_sign];
1753
- const who = segment ? `${segment}: ` : "";
1768
+ const push = (vs, who) => {
1769
+ if (vs.status === "green") return;
1770
+ if (vs.dollar_value == null || vs.dollar_value <= 0) return;
1754
1771
  extras.push({
1755
1772
  severity: vs.status === "red" ? "critical" : "warn",
1756
- text: `${who}${label} ${Math.round(vs.score)} \u2014 ${formatCurrency(vs.dollar_value)} ${vs.dollar_label ?? ""}`.trim(),
1773
+ text: problemPhrase(vs, who),
1757
1774
  dollars: vs.dollar_value
1758
1775
  });
1776
+ };
1777
+ if (segments.length > 0) {
1778
+ for (const s of segments) {
1779
+ for (const vs of s.result.vital_signs) {
1780
+ push(vs, s.segment.name);
1781
+ }
1782
+ }
1783
+ } else {
1784
+ for (const vs of health.vital_signs) {
1785
+ if (vs.vital_sign === health.gating_vital_sign) continue;
1786
+ push(vs);
1787
+ }
1759
1788
  }
1760
1789
  extras.sort((a, b) => b.dollars - a.dollars);
1790
+ const findings = [];
1761
1791
  for (const extra of extras) {
1762
1792
  if (findings.length >= 3) break;
1763
1793
  if (findings.some((f) => f.text === extra.text)) continue;
1764
1794
  findings.push({ severity: extra.severity, text: extra.text });
1765
1795
  }
1766
- return findings.slice(0, 3);
1796
+ return findings;
1767
1797
  }
1768
1798
  function headlinesFromFindingCards(cards) {
1769
1799
  return cards.slice(0, 3).map((card) => ({
@@ -1771,11 +1801,19 @@ function headlinesFromFindingCards(cards) {
1771
1801
  text: stripFindingMarkdown(card.finding)
1772
1802
  }));
1773
1803
  }
1804
+ var VITAL_PROBLEM_READ;
1774
1805
  var init_result_block = __esm({
1775
1806
  "src/trace/result-block.ts"() {
1776
1807
  "use strict";
1777
1808
  init_formatters();
1778
1809
  init_theme();
1810
+ VITAL_PROBLEM_READ = {
1811
+ freshness: "stale",
1812
+ flow_rate: "stuck",
1813
+ drop_rate: "lost at handoff",
1814
+ signal_to_noise: "misdirected effort",
1815
+ thread_depth: "single-threaded"
1816
+ };
1779
1817
  }
1780
1818
  });
1781
1819
 
@@ -1870,11 +1908,10 @@ var init_renderer = __esm({
1870
1908
  }
1871
1909
  const line = `${summary} \xB7 ${formatDuration(durationMs)}`;
1872
1910
  if (this.useSpinner() && this.spinner) {
1873
- this.spinner.succeed(line);
1911
+ this.spinner.stop();
1874
1912
  this.spinner = null;
1875
- return;
1876
1913
  }
1877
- console.log(` ${chalk6.green("\u2713")} ${line}`);
1914
+ console.log(` ${chalk6.green("\u2713")} ${chalk6.dim(line)}`);
1878
1915
  }
1879
1916
  persistDim(message) {
1880
1917
  const spinning = this.spinner?.isSpinning;
@@ -30445,8 +30482,6 @@ async function ingestFromChat(ctx, filePath) {
30445
30482
  printGapCard(audit);
30446
30483
  if (audit.can_compute && ctx.scope?.confirmed_at) {
30447
30484
  if (ctx.pendingAsk) {
30448
- console.log();
30449
- console.log(" " + chalk31.dim("Computing so I can answer\u2026"));
30450
30485
  await runConversationCompute(ctx);
30451
30486
  return true;
30452
30487
  }
@@ -30530,8 +30565,6 @@ async function loadDemoFromChat(ctx, scenario, opts = {}) {
30530
30565
  const audit = await refreshGapAudit(ctx);
30531
30566
  const shouldAuto = opts.autoCompute || Boolean(ctx.pendingAsk && audit.can_compute && ctx.scope?.confirmed_at);
30532
30567
  if (shouldAuto && audit.can_compute) {
30533
- console.log();
30534
- console.log(" " + chalk31.dim("Computing so I can answer\u2026"));
30535
30568
  await runConversationCompute(ctx);
30536
30569
  return true;
30537
30570
  }
@@ -30610,12 +30643,6 @@ async function resumePendingAsk(ctx) {
30610
30643
  if (!pending?.text) return false;
30611
30644
  ctx.computeInProgress = false;
30612
30645
  if (canUseReplAi(ctx)) {
30613
- console.log();
30614
- console.log(
30615
- " " + chalk32.dim(
30616
- pending.keylessAnswered ? "Picking up your question with the connected engine\u2026" : "Picking up your question\u2026"
30617
- )
30618
- );
30619
30646
  console.log();
30620
30647
  const { runNaturalLanguage: runNaturalLanguage2 } = await Promise.resolve().then(() => (init_nl(), nl_exports));
30621
30648
  await runNaturalLanguage2(pending.text, ctx);
@@ -30897,7 +30924,7 @@ async function runDiagnoseTrace(options) {
30897
30924
  kind: "phase_end",
30898
30925
  phase: "compute",
30899
30926
  durationMs: Date.now() - computeStarted,
30900
- summary: "Vital signs computed"
30927
+ summary: "Pipeline scored"
30901
30928
  });
30902
30929
  computeEnded = true;
30903
30930
  }
@@ -30927,7 +30954,7 @@ async function runDiagnoseTrace(options) {
30927
30954
  kind: "phase_end",
30928
30955
  phase: "compute",
30929
30956
  durationMs: Date.now() - computeStarted,
30930
- summary: "Vital signs computed"
30957
+ summary: "Pipeline scored"
30931
30958
  });
30932
30959
  }
30933
30960
  if (fullResult && fullResult.segments.length > 0) {
@@ -30935,7 +30962,7 @@ async function runDiagnoseTrace(options) {
30935
30962
  kind: "phase_end",
30936
30963
  phase: "segments",
30937
30964
  durationMs: Date.now() - (segmentsStarted ?? Date.now()),
30938
- summary: `Segments computed \xB7 ${fullResult.segments.length}`
30965
+ summary: `${fullResult.segments.length} segment${fullResult.segments.length === 1 ? "" : "s"}`
30939
30966
  });
30940
30967
  }
30941
30968
  if (!fullResult) {
@@ -31041,7 +31068,7 @@ async function runDiagnoseTrace(options) {
31041
31068
  });
31042
31069
  const reportPath = ctx ? await writeSilentMarkdownReport(ctx, fullResult, collectedFindings) : null;
31043
31070
  if (reportPath) {
31044
- bus.emit({ kind: "artifact", path: reportPath, description: "Full report" });
31071
+ bus.emit({ kind: "artifact", path: reportPath, description: "Saved report" });
31045
31072
  } else if (ctx?.events instanceof EventBus) {
31046
31073
  bus.emit({ kind: "artifact", path: logPathForRun(ctx.events.runId), description: "Run log" });
31047
31074
  }
@@ -31262,7 +31289,7 @@ async function runSegmentDiagnose(options, ctx) {
31262
31289
  kind: "phase_end",
31263
31290
  phase: "compute",
31264
31291
  durationMs: Date.now() - t0,
31265
- summary: "Vital signs computed"
31292
+ summary: "Pipeline scored"
31266
31293
  });
31267
31294
  } catch (err) {
31268
31295
  bus.emit({ kind: "debug", message: String(err) });
@@ -31312,7 +31339,7 @@ async function runSegmentDiagnose(options, ctx) {
31312
31339
  }
31313
31340
  const reportPath = await writeSilentMarkdownReport2(ctx, result, []);
31314
31341
  if (reportPath) {
31315
- bus.emit({ kind: "artifact", path: reportPath, description: "Full report" });
31342
+ bus.emit({ kind: "artifact", path: reportPath, description: "Saved report" });
31316
31343
  }
31317
31344
  return buildDiagnoseSummary(match.result, []);
31318
31345
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sonnechasser/ntrp",
3
- "version": "2.1.10",
3
+ "version": "2.1.11",
4
4
  "description": "GTM Health Diagnostic CLI — local pipeline analysis tool",
5
5
  "homepage": "https://ntrp.sonnechasser.com",
6
6
  "repository": {