@sonnechasser/ntrp 2.1.10 → 2.1.12

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.
Files changed (3) hide show
  1. package/dist/index.js +338 -174
  2. package/dist/mcp/server.js +251 -139
  3. package/package.json +1 -1
@@ -1308,6 +1308,34 @@ function voiceHealthGloss(status, prefs) {
1308
1308
  }
1309
1309
  });
1310
1310
  }
1311
+ function voiceExportPickupNudge(input, prefs) {
1312
+ const v = voice(prefs);
1313
+ const phrase = EXPORT_PICKUP_PHRASE;
1314
+ if (input.inboxReady) {
1315
+ return pick(v, {
1316
+ robotic: `Open your desktop AI. Tell it to ${phrase}.`,
1317
+ composed: `Open your desktop AI and tell it to ${phrase}.`,
1318
+ casual: `This terminal is not your AI. Open it and tell it to ${phrase}.`,
1319
+ loose: {
1320
+ light: `Written. Open your desktop AI and tell it to ${phrase}.`,
1321
+ medium: `This CLI cannot see your AI. Open it. Tell it to ${phrase}.`,
1322
+ dark: `The file is on disk. Your AI is not in this window. Open it and ${phrase}.`,
1323
+ heavy: `NTRP wrote it. This window is not your AI. Open the desktop app and ${phrase}.`
1324
+ }
1325
+ });
1326
+ }
1327
+ return pick(v, {
1328
+ robotic: `Your desktop AI cannot see this folder. Type /inbox set, then tell that AI to ${phrase}.`,
1329
+ composed: `These files are on disk. Set a pickup folder (/inbox set), then tell your desktop AI to ${phrase}.`,
1330
+ casual: `Your AI cannot see this folder. Type /inbox set, then tell it to ${phrase}.`,
1331
+ loose: {
1332
+ light: `Your AI cannot see this folder yet. Type /inbox set, then tell it to ${phrase}.`,
1333
+ medium: `This folder is invisible to your AI. Type /inbox set, then tell it to ${phrase}.`,
1334
+ dark: `Your AI cannot see this terminal. Type /inbox set, then ${phrase}.`,
1335
+ heavy: `This window is not your AI. Type /inbox set, then ${phrase}.`
1336
+ }
1337
+ });
1338
+ }
1311
1339
  function voiceHandoffAddendum(prefs) {
1312
1340
  const v = voice(prefs);
1313
1341
  return [
@@ -1322,11 +1350,13 @@ function pick(prefs, map) {
1322
1350
  if (typeof entry === "string") return entry;
1323
1351
  return entry[prefs.roast];
1324
1352
  }
1353
+ var EXPORT_PICKUP_PHRASE;
1325
1354
  var init_copy = __esm({
1326
1355
  "src/voice/copy.ts"() {
1327
1356
  "use strict";
1328
1357
  init_catalog();
1329
1358
  init_prefs();
1359
+ EXPORT_PICKUP_PHRASE = "pick up the latest NTRP handoff";
1330
1360
  }
1331
1361
  });
1332
1362
 
@@ -1634,8 +1664,10 @@ var init_verbosity = __esm({
1634
1664
  // src/trace/result-block.ts
1635
1665
  var result_block_exports = {};
1636
1666
  __export(result_block_exports, {
1667
+ VITAL_PROBLEM_READ: () => VITAL_PROBLEM_READ,
1637
1668
  buildVitalHeadlines: () => buildVitalHeadlines,
1638
1669
  formatDuration: () => formatDuration,
1670
+ formatVitalCall: () => formatVitalCall,
1639
1671
  headlinesFromFindingCards: () => headlinesFromFindingCards,
1640
1672
  printArtifactLine: () => printArtifactLine,
1641
1673
  printMetricsResultBlock: () => printMetricsResultBlock,
@@ -1659,12 +1691,32 @@ function flagLabel(vitals, status) {
1659
1691
  function deltaCell(delta) {
1660
1692
  if (!delta) return " ";
1661
1693
  const rounded = Math.round(delta.delta);
1662
- if (rounded === 0) return chalk5.dim(" 0 ");
1694
+ if (rounded === 0) return " ";
1663
1695
  if (rounded < 0) {
1664
1696
  return paint("error", `\u25BC ${String(Math.abs(rounded)).padStart(2)} `);
1665
1697
  }
1666
1698
  return paint("success", `\u25B2 ${String(rounded).padStart(2)} `);
1667
1699
  }
1700
+ function otherRedLabels(health) {
1701
+ return health.vital_signs.filter((v) => v.status === "red" && v.vital_sign !== health.gating_vital_sign).map((v) => VITAL_SIGN_LABELS[v.vital_sign]);
1702
+ }
1703
+ function formatVitalCall(health) {
1704
+ const gateName = VITAL_SIGN_LABELS[health.gating_vital_sign];
1705
+ const gating = health.vital_signs.find((v) => v.vital_sign === health.gating_vital_sign);
1706
+ const read = VITAL_PROBLEM_READ[health.gating_vital_sign];
1707
+ const alsoRed = otherRedLabels(health);
1708
+ const dollars = health.total_value_at_risk;
1709
+ const head = dollars != null && dollars > 0 ? `${formatCurrency(dollars)} at risk.` : "No dollar-weighted risk.";
1710
+ let start = `Start with ${gateName}`;
1711
+ if (gating && gating.dollar_value != null && gating.dollar_value > 0) {
1712
+ start += `: ${formatCurrency(gating.dollar_value)} ${read}`;
1713
+ }
1714
+ start += ".";
1715
+ if (alsoRed.length > 0) {
1716
+ start += ` Also red: ${alsoRed.join(", ")}.`;
1717
+ }
1718
+ return `${head} ${start}`;
1719
+ }
1668
1720
  function printVitalResultBlock(health, opts = {}) {
1669
1721
  const vitals = health.vital_signs;
1670
1722
  const deltaBySign = new Map((opts.deltas ?? []).map((d) => [d.vital_sign, d]));
@@ -1681,18 +1733,25 @@ function printVitalResultBlock(health, opts = {}) {
1681
1733
  console.log(` ${dot} ${label} ${score} ${delta} ${flag}`.trimEnd());
1682
1734
  }
1683
1735
  console.log();
1736
+ printVitalCall(health);
1737
+ printFindingsList(opts.findings ?? []);
1738
+ }
1739
+ function printVitalCall(health) {
1740
+ const gateName = VITAL_SIGN_LABELS[health.gating_vital_sign];
1741
+ const gating = health.vital_signs.find((v) => v.vital_sign === health.gating_vital_sign);
1742
+ const read = VITAL_PROBLEM_READ[health.gating_vital_sign];
1743
+ const alsoRed = otherRedLabels(health);
1684
1744
  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)}`);
1745
+ const head = dollars != null && dollars > 0 ? `${paint("success", formatCurrency(dollars))} at risk.` : "No dollar-weighted risk.";
1746
+ let start = `Start with ${paint("accent", gateName)}`;
1747
+ if (gating && gating.dollar_value != null && gating.dollar_value > 0) {
1748
+ start += `: ${formatCurrency(gating.dollar_value)} ${read}`;
1694
1749
  }
1695
- printFindingsList(opts.findings ?? []);
1750
+ start += ".";
1751
+ if (alsoRed.length > 0) {
1752
+ start += ` Also red: ${alsoRed.join(", ")}.`;
1753
+ }
1754
+ console.log(` ${head} ${start}`);
1696
1755
  }
1697
1756
  function printMetricsResultBlock(metrics, opts = {}) {
1698
1757
  const flagged = metrics.filter((m) => !m.unavailable_reason && (m.status === "red" || m.status === "yellow"));
@@ -1717,53 +1776,54 @@ function printMetricsResultBlock(metrics, opts = {}) {
1717
1776
  function printFindingsList(findings) {
1718
1777
  if (findings.length === 0) return;
1719
1778
  console.log();
1720
- console.log(` ${chalk5.bold("Findings")}`);
1721
1779
  findings.slice(0, 3).forEach((f, i) => {
1722
1780
  console.log(` ${chalk5.dim(`${i + 1}.`)} ${f.text}`);
1723
1781
  });
1724
1782
  }
1725
1783
  function printArtifactLine(path, description) {
1726
1784
  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.")}`);
1785
+ const label = description?.trim() || "Saved report";
1786
+ console.log(` ${chalk5.dim(label)} ${chalk5.dim("\u2192")} ${chalk5.dim(path)}`);
1730
1787
  console.log();
1731
1788
  }
1789
+ function problemPhrase(vs, who) {
1790
+ const read = VITAL_PROBLEM_READ[vs.vital_sign];
1791
+ const dollars = vs.dollar_value != null && vs.dollar_value > 0 ? formatCurrency(vs.dollar_value) : null;
1792
+ const prefix = who || VITAL_SIGN_LABELS[vs.vital_sign];
1793
+ if (dollars) return `${prefix}: ${dollars} ${read}`;
1794
+ return `${prefix}: ${VITAL_SIGN_LABELS[vs.vital_sign]} ${Math.round(vs.score)}`;
1795
+ }
1732
1796
  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
1797
  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}: ` : "";
1798
+ const push = (vs, who) => {
1799
+ if (vs.status === "green") return;
1800
+ if (vs.dollar_value == null || vs.dollar_value <= 0) return;
1754
1801
  extras.push({
1755
1802
  severity: vs.status === "red" ? "critical" : "warn",
1756
- text: `${who}${label} ${Math.round(vs.score)} \u2014 ${formatCurrency(vs.dollar_value)} ${vs.dollar_label ?? ""}`.trim(),
1803
+ text: problemPhrase(vs, who),
1757
1804
  dollars: vs.dollar_value
1758
1805
  });
1806
+ };
1807
+ if (segments.length > 0) {
1808
+ for (const s of segments) {
1809
+ for (const vs of s.result.vital_signs) {
1810
+ push(vs, s.segment.name);
1811
+ }
1812
+ }
1813
+ } else {
1814
+ for (const vs of health.vital_signs) {
1815
+ if (vs.vital_sign === health.gating_vital_sign) continue;
1816
+ push(vs);
1817
+ }
1759
1818
  }
1760
1819
  extras.sort((a, b) => b.dollars - a.dollars);
1820
+ const findings = [];
1761
1821
  for (const extra of extras) {
1762
1822
  if (findings.length >= 3) break;
1763
1823
  if (findings.some((f) => f.text === extra.text)) continue;
1764
1824
  findings.push({ severity: extra.severity, text: extra.text });
1765
1825
  }
1766
- return findings.slice(0, 3);
1826
+ return findings;
1767
1827
  }
1768
1828
  function headlinesFromFindingCards(cards) {
1769
1829
  return cards.slice(0, 3).map((card) => ({
@@ -1771,11 +1831,19 @@ function headlinesFromFindingCards(cards) {
1771
1831
  text: stripFindingMarkdown(card.finding)
1772
1832
  }));
1773
1833
  }
1834
+ var VITAL_PROBLEM_READ;
1774
1835
  var init_result_block = __esm({
1775
1836
  "src/trace/result-block.ts"() {
1776
1837
  "use strict";
1777
1838
  init_formatters();
1778
1839
  init_theme();
1840
+ VITAL_PROBLEM_READ = {
1841
+ freshness: "stale",
1842
+ flow_rate: "stuck",
1843
+ drop_rate: "lost at handoff",
1844
+ signal_to_noise: "misdirected effort",
1845
+ thread_depth: "single-threaded"
1846
+ };
1779
1847
  }
1780
1848
  });
1781
1849
 
@@ -1870,11 +1938,10 @@ var init_renderer = __esm({
1870
1938
  }
1871
1939
  const line = `${summary} \xB7 ${formatDuration(durationMs)}`;
1872
1940
  if (this.useSpinner() && this.spinner) {
1873
- this.spinner.succeed(line);
1941
+ this.spinner.stop();
1874
1942
  this.spinner = null;
1875
- return;
1876
1943
  }
1877
- console.log(` ${chalk6.green("\u2713")} ${line}`);
1944
+ console.log(` ${chalk6.green("\u2713")} ${chalk6.dim(line)}`);
1878
1945
  }
1879
1946
  persistDim(message) {
1880
1947
  const spinning = this.spinner?.isSpinning;
@@ -2496,6 +2563,9 @@ function maybePrintAiInboxNudge() {
2496
2563
  )
2497
2564
  );
2498
2565
  }
2566
+ function printExportPickupNudge(opts) {
2567
+ console.log(" " + chalk7.dim(voiceExportPickupNudge(opts)));
2568
+ }
2499
2569
  function printStandingSkill() {
2500
2570
  persistStandingSkill();
2501
2571
  const loc = handoffLocations();
@@ -2521,6 +2591,7 @@ var init_handoff_skill = __esm({
2521
2591
  init_store();
2522
2592
  init_theme();
2523
2593
  init_export_kinds();
2594
+ init_copy();
2524
2595
  STANDING_SKILL_NAME = "SKILL.md";
2525
2596
  ARCHIVE_PICKUP_NAME = "pickup.md";
2526
2597
  INBOX_PICKUP_NAME = "latest-pickup.md";
@@ -9643,7 +9714,7 @@ ${strategy.objective}
9643
9714
  ` : "";
9644
9715
  const workstreamSection = strategy.workstreams.length > 0 ? `
9645
9716
  ## Workstreams
9646
- ${strategy.workstreams.map(formatWorkstream).join("\n")}
9717
+ ${strategy.workstreams.map(formatWorkstreamMarkdown).join("\n")}
9647
9718
  ` : "";
9648
9719
  const constraintsSection = filterOperatorLines(strategy.constraints).length > 0 ? `
9649
9720
  ## Constraints
@@ -9699,7 +9770,7 @@ ${strategy.objective}
9699
9770
  ` : "";
9700
9771
  const workstreamSection = strategy.workstreams.length > 0 ? `
9701
9772
  ## Workstreams
9702
- ${strategy.workstreams.map(formatWorkstream).join("\n")}
9773
+ ${strategy.workstreams.map(formatWorkstreamMarkdown).join("\n")}
9703
9774
  ` : "";
9704
9775
  const assumptions = filterOperatorLines(strategy.assumptions);
9705
9776
  const assumptionsSection = assumptions.length > 0 ? `
@@ -9746,7 +9817,7 @@ ${frontmatter}
9746
9817
  ].filter((p) => p != null && String(p).length > 0);
9747
9818
  return parts.join("\n\n") + "\n";
9748
9819
  }
9749
- function formatWorkstream(ws) {
9820
+ function formatWorkstreamMarkdown(ws) {
9750
9821
  const lines = [];
9751
9822
  lines.push(`### ${ws.order}. ${ws.title}`);
9752
9823
  lines.push(`- Problem: ${ws.problem}`);
@@ -11109,6 +11180,7 @@ function resetContextForSwitch(ctx, opts) {
11109
11180
  ctx.thinkState = opts.thinkState;
11110
11181
  ctx.pendingAsk = opts.pendingAsk;
11111
11182
  ctx.lastCraftJobId = opts.lastCraftJobId;
11183
+ ctx.lastStrategyBrief = void 0;
11112
11184
  ctx.gapAudit = void 0;
11113
11185
  ctx.deliverIntent = false;
11114
11186
  ctx.computeInProgress = false;
@@ -23798,20 +23870,7 @@ function renderCraftHandoffMarkdown(opts) {
23798
23870
  lines.push("## Workstreams");
23799
23871
  lines.push("");
23800
23872
  for (const ws of plan.workstreams) {
23801
- lines.push(`### ${ws.order}. ${ws.title}`);
23802
- lines.push("");
23803
- lines.push(`- Problem: ${ws.problem}`);
23804
- if (ws.rationale && !isGenericWorkstreamRationale(ws.rationale)) {
23805
- lines.push(`- Why this order: ${ws.rationale}`);
23806
- }
23807
- if (ws.actions[0]) lines.push(`- First action (48h): ${ws.actions[0]}`);
23808
- lines.push(`- Effort: ~${Math.round(ws.effort_hours)} team-hours`);
23809
- lines.push(
23810
- `- Exam: ${ws.expected_outcome.metric} ${ws.expected_outcome.baseline} \u2192 ${ws.expected_outcome.target_range} by ${ws.expected_outcome.check_date} (${ws.expected_outcome.measured_by})`
23811
- );
23812
- lines.push(
23813
- `- Contingency: if ${ws.contingency.trigger} (check ${ws.contingency.trigger_check_date}) \u2192 ${ws.contingency.fallback}`
23814
- );
23873
+ lines.push(formatWorkstreamMarkdown(ws).trimEnd());
23815
23874
  lines.push("");
23816
23875
  }
23817
23876
  if (opts.roundtableDigest) {
@@ -24091,93 +24150,149 @@ var init_llm_attribution = __esm({
24091
24150
 
24092
24151
  // src/output/strategy-brief.ts
24093
24152
  import chalk17 from "chalk";
24094
- function printWrapped(text, width, prefix = INDENT, style) {
24153
+ function collectWrapped(lines, text, width, prefix = INDENT, style) {
24095
24154
  for (const line of wrapWords(text, width)) {
24096
- console.log(prefix + (style ? style(line) : line));
24155
+ lines.push(prefix + (style ? style(line) : line));
24097
24156
  }
24098
24157
  }
24099
- function outcomeLine(outcome) {
24100
- return `${chalk17.bold(outcome.metric)}: ${outcome.baseline} ${chalk17.dim("\u2192")} ${chalk17.bold(outcome.target_range)} ${chalk17.dim(`by ${outcome.check_date}`)}`;
24158
+ function outcomeLine(outcome, dateStyle) {
24159
+ const by = dateStyle === "accent" ? paint("accent", `by ${outcome.check_date}`) : chalk17.dim(`by ${outcome.check_date}`);
24160
+ return `${chalk17.bold(outcome.metric)}: ${outcome.baseline} ${chalk17.dim("\u2192")} ${chalk17.bold(outcome.target_range)} ${by}`;
24161
+ }
24162
+ function soonestByDue(items) {
24163
+ if (items.length === 0) return void 0;
24164
+ return [...items].sort((a, b) => a.due.localeCompare(b.due) || 0)[0];
24165
+ }
24166
+ function altitudeLine(text) {
24167
+ const sentence = findingHeadline(text) || text.trim();
24168
+ return truncateVisible(sentence, FOH_PROSE_MAX);
24101
24169
  }
24102
- function printWorkstream(ws, width) {
24103
- console.log(`${INDENT}${paint("accent", `${ws.order}.`)} ${chalk17.bold(ws.title)}`);
24104
- printWrapped(ws.problem, width - 5, INDENT + " ", (s) => chalk17.dim(s));
24105
- console.log(`${INDENT} ${outcomeLine(ws.expected_outcome)}`);
24170
+ function coverageLine(plan, stats) {
24171
+ const totalHours = plan.workstreams.reduce((sum, ws) => sum + ws.effort_hours, 0);
24172
+ const hours = `~${Math.round(totalHours)} total team hours across ${plan.workstreams.length} workstream${plan.workstreams.length === 1 ? "" : "s"}`;
24173
+ if (stats.total_targets <= 0) return chalk17.dim(hours);
24174
+ const coverage = `${stats.measurable_targets} of ${stats.total_targets} targets can be measured with current data`;
24175
+ const coverageStyled = stats.measurable_targets === stats.total_targets ? paint("success", coverage) : chalk17.hex("#eab308")(coverage);
24176
+ return `${coverageStyled}${chalk17.dim(` \xB7 ${hours}`)}`;
24177
+ }
24178
+ function renderFohWorkstream(ws, width) {
24179
+ const lines = [];
24180
+ lines.push(`${INDENT}${paint("accent", `${ws.order}.`)} ${chalk17.bold(ws.title)}`);
24181
+ lines.push(`${INDENT} ${outcomeLine(ws.expected_outcome, "accent")}`);
24182
+ const next = soonestByDue(ws.milestones);
24183
+ if (next) {
24184
+ lines.push(`${INDENT} Next ${paint("accent", next.due)} ${next.label}`);
24185
+ }
24186
+ const ship = soonestByDue(ws.deliverables);
24187
+ if (ship) {
24188
+ lines.push(`${INDENT} Ship ${paint("accent", ship.due)} ${ship.label}`);
24189
+ }
24190
+ lines.push("");
24191
+ return lines;
24192
+ }
24193
+ function renderBohWorkstream(ws, width) {
24194
+ const lines = [];
24195
+ lines.push(`${INDENT}${paint("accent", `${ws.order}.`)} ${chalk17.bold(ws.title)}`);
24196
+ collectWrapped(lines, ws.problem, width - 5, INDENT + " ", (s) => chalk17.dim(s));
24197
+ lines.push(`${INDENT} ${outcomeLine(ws.expected_outcome, "dim")}`);
24106
24198
  for (const li of ws.leading_indicators) {
24107
- console.log(`${INDENT} ${chalk17.dim("Lead:")} ${outcomeLine(li)}`);
24199
+ lines.push(`${INDENT} ${chalk17.dim("Lead:")} ${outcomeLine(li, "dim")}`);
24108
24200
  }
24109
24201
  if (ws.actions.length > 0) {
24110
- console.log(`${INDENT} ${chalk17.dim("First steps")}`);
24202
+ lines.push(`${INDENT} ${chalk17.dim("First steps")}`);
24111
24203
  for (const action of ws.actions.slice(0, 3)) {
24112
- printWrapped(`- ${action}`, width - 7, INDENT + " ", (s) => chalk17.dim(s));
24204
+ collectWrapped(lines, `- ${action}`, width - 7, INDENT + " ", (s) => chalk17.dim(s));
24113
24205
  }
24114
24206
  }
24115
24207
  if (ws.milestones.length > 0) {
24116
- console.log(`${INDENT} ${chalk17.dim("Milestones")}`);
24208
+ lines.push(`${INDENT} ${chalk17.dim("Milestones")}`);
24117
24209
  for (const m of ws.milestones) {
24118
- console.log(`${INDENT} ${paint("accent", m.due)} ${m.label}`);
24210
+ lines.push(`${INDENT} ${paint("accent", m.due)} ${m.label}`);
24119
24211
  }
24120
24212
  }
24121
24213
  if (ws.deliverables.length > 0) {
24122
- console.log(`${INDENT} ${chalk17.dim("Deliverables")}`);
24214
+ lines.push(`${INDENT} ${chalk17.dim("Deliverables")}`);
24123
24215
  for (const d of ws.deliverables) {
24124
- console.log(`${INDENT} ${chalk17.dim("[ ]")} ${d.label} ${chalk17.dim(`due ${d.due}`)}`);
24216
+ lines.push(`${INDENT} ${chalk17.dim("[ ]")} ${d.label} ${chalk17.dim(`due ${d.due}`)}`);
24125
24217
  }
24126
24218
  }
24127
- printWrapped(
24219
+ collectWrapped(
24220
+ lines,
24128
24221
  `If ${ws.contingency.trigger} (check ${ws.contingency.trigger_check_date}), then ${ws.contingency.fallback}`,
24129
24222
  width - 5,
24130
24223
  INDENT + " ",
24131
24224
  (s) => chalk17.dim(s)
24132
24225
  );
24133
- console.log(`${INDENT} ${chalk17.dim(`~${Math.round(ws.effort_hours)} team hours`)}`);
24134
- console.log();
24226
+ lines.push(`${INDENT} ${chalk17.dim(`~${Math.round(ws.effort_hours)} team hours`)}`);
24227
+ lines.push("");
24228
+ return lines;
24135
24229
  }
24136
- function printStrategyBrief(plan, stats) {
24230
+ function renderOperatorList(title, items, width) {
24231
+ const lines = [];
24232
+ if (items.length === 0) return lines;
24233
+ lines.push(`${INDENT}${chalk17.dim(title)}`);
24234
+ for (const item of items) {
24235
+ collectWrapped(lines, `- ${item}`, width - 2, INDENT, (s) => chalk17.dim(s));
24236
+ }
24237
+ lines.push("");
24238
+ return lines;
24239
+ }
24240
+ function renderStrategyBrief(plan, stats, opts = {}) {
24241
+ const mode = opts.mode ?? "foh";
24137
24242
  const width = Math.min(termWidth() - 4, 92);
24138
- console.log();
24139
- console.log(
24243
+ const lines = [""];
24244
+ lines.push(
24140
24245
  `${INDENT}${chalk17.bold(`Strategy brief \u2014 ${plan.title}`)} ${chalk17.dim(`confidence ${plan.confidence.toFixed(2)} \xB7 ${plan.priority} priority \xB7 review ${plan.review_cadence.toLowerCase()}`)}`
24141
24246
  );
24142
- console.log(INDENT + chalk17.dim(hr(width)));
24143
- console.log(`${INDENT}${chalk17.dim("The Call")}`);
24144
- printWrapped(plan.summary_30k, width);
24145
- console.log();
24146
- printWrapped(`Objective: ${plan.objective}`, width, INDENT, (s) => paint("accent", s));
24147
- console.log();
24148
- for (const ws of plan.workstreams) {
24149
- printWorkstream(ws, width);
24150
- }
24151
- const constraints = filterOperatorLines(plan.constraints);
24152
- if (constraints.length > 0) {
24153
- console.log(`${INDENT}${chalk17.dim("Constraints")}`);
24154
- for (const c of constraints) {
24155
- printWrapped(`- ${c}`, width - 2, INDENT, (s) => chalk17.dim(s));
24247
+ if (mode === "foh") {
24248
+ collectWrapped(lines, altitudeLine(plan.summary_30k), width, INDENT);
24249
+ lines.push("");
24250
+ collectWrapped(lines, altitudeLine(plan.objective), width, INDENT, (s) => paint("accent", s));
24251
+ lines.push("");
24252
+ for (const ws of plan.workstreams) {
24253
+ lines.push(...renderFohWorkstream(ws, width));
24156
24254
  }
24157
- console.log();
24158
- }
24159
- const assumptions = filterOperatorLines(plan.assumptions);
24160
- if (assumptions.length > 0) {
24161
- console.log(`${INDENT}${chalk17.dim("Assumptions (not verified, not targets)")}`);
24162
- for (const a of assumptions) {
24163
- printWrapped(`- ${a}`, width - 2, INDENT, (s) => chalk17.dim(s));
24255
+ } else {
24256
+ lines.push(INDENT + chalk17.dim(hr(width)));
24257
+ lines.push(`${INDENT}${chalk17.dim("The Call")}`);
24258
+ collectWrapped(lines, plan.summary_30k, width);
24259
+ lines.push("");
24260
+ collectWrapped(lines, `Objective: ${plan.objective}`, width, INDENT, (s) => paint("accent", s));
24261
+ lines.push("");
24262
+ for (const ws of plan.workstreams) {
24263
+ lines.push(...renderBohWorkstream(ws, width));
24164
24264
  }
24165
- console.log();
24265
+ lines.push(
24266
+ ...renderOperatorList("Constraints", filterOperatorLines(plan.constraints), width)
24267
+ );
24268
+ lines.push(
24269
+ ...renderOperatorList(
24270
+ "Assumptions (not verified, not targets)",
24271
+ filterOperatorLines(plan.assumptions),
24272
+ width
24273
+ )
24274
+ );
24275
+ lines.push(...renderOperatorList("Risks", filterOperatorLines(plan.risks), width));
24166
24276
  }
24167
- const risks = filterOperatorLines(plan.risks);
24168
- if (risks.length > 0) {
24169
- console.log(`${INDENT}${chalk17.dim("Risks")}`);
24170
- for (const r of risks) {
24171
- printWrapped(`- ${r}`, width - 2, INDENT, (s) => chalk17.dim(s));
24172
- }
24173
- console.log();
24277
+ lines.push(INDENT + chalk17.dim(hr(width)));
24278
+ lines.push(`${INDENT}${coverageLine(plan, stats)}`);
24279
+ if (opts.hint) {
24280
+ lines.push(`${INDENT}${chalk17.dim(STRATEGY_BRIEF_EXPAND_HINT)}`);
24174
24281
  }
24175
- const totalHours = plan.workstreams.reduce((sum, ws) => sum + ws.effort_hours, 0);
24176
- console.log(INDENT + chalk17.dim(hr(width)));
24177
- const coverage = stats.total_targets > 0 ? `${stats.measurable_targets} of ${stats.total_targets} targets can be measured with current data` : "No measured targets";
24178
- const coverageStyled = stats.total_targets > 0 && stats.measurable_targets === stats.total_targets ? paint("success", coverage) : chalk17.hex("#eab308")(coverage);
24179
- console.log(`${INDENT}${coverageStyled}${chalk17.dim(` \xB7 ~${Math.round(totalHours)} total team hours across ${plan.workstreams.length} workstream${plan.workstreams.length === 1 ? "" : "s"}`)}`);
24180
- console.log();
24282
+ lines.push("");
24283
+ return lines.join("\n");
24284
+ }
24285
+ function printStrategyBrief(plan, stats, opts = {}) {
24286
+ console.log(renderStrategyBrief(plan, stats, opts));
24287
+ }
24288
+ function resolveStrategyBriefMode(host) {
24289
+ return isVerbose(host.execution) ? "boh" : "foh";
24290
+ }
24291
+ function presentStrategyBrief(host, plan, stats, notices = [], meta = {}) {
24292
+ const mode = resolveStrategyBriefMode(host);
24293
+ printStrategyBrief(plan, stats, { mode, hint: mode === "foh" && !host.oneShot });
24294
+ printStrategyBriefFooter(notices, meta);
24295
+ host.lastStrategyBrief = { plan, stats, notices, meta };
24181
24296
  }
24182
24297
  function printStrategyBriefFooter(notices, meta) {
24183
24298
  if (usedGroundedFallback(notices)) {
@@ -24196,7 +24311,10 @@ function printCraftWrapUp(opts) {
24196
24311
  );
24197
24312
  }
24198
24313
  const handoff = opts.inbox_path ?? opts.handoff_path;
24199
- if (handoff) console.log(INDENT + chalk17.dim(handoff));
24314
+ if (handoff) {
24315
+ console.log(INDENT + chalk17.dim(handoff));
24316
+ printExportPickupNudge({ inboxReady: Boolean(opts.inbox_path) });
24317
+ }
24200
24318
  } else {
24201
24319
  console.log(INDENT + paint("accent", "Best so far."));
24202
24320
  const path = opts.library_path ?? opts.handoff_path ?? opts.inbox_path;
@@ -24216,15 +24334,20 @@ function printCraftWrapUp(opts) {
24216
24334
  }
24217
24335
  console.log();
24218
24336
  }
24219
- var INDENT;
24337
+ var STRATEGY_BRIEF_EXPAND_HINT, INDENT, FOH_PROSE_MAX;
24220
24338
  var init_strategy_brief = __esm({
24221
24339
  "src/output/strategy-brief.ts"() {
24222
24340
  "use strict";
24223
24341
  init_theme();
24224
24342
  init_layout();
24343
+ init_formatters();
24225
24344
  init_strategy_signal();
24226
24345
  init_llm_attribution();
24346
+ init_handoff_skill();
24347
+ init_verbosity();
24348
+ STRATEGY_BRIEF_EXPAND_HINT = "Type more to show the full brief.";
24227
24349
  INDENT = " ";
24350
+ FOH_PROSE_MAX = 220;
24228
24351
  }
24229
24352
  });
24230
24353
 
@@ -24585,8 +24708,7 @@ async function runStrategistSession(ctx) {
24585
24708
  console.log();
24586
24709
  return;
24587
24710
  }
24588
- printStrategyBrief(plan, stats);
24589
- printStrategyBriefFooter(notices, meta);
24711
+ presentStrategyBrief(ctx, plan, stats, notices, meta);
24590
24712
  console.log();
24591
24713
  let saved = false;
24592
24714
  if (ctx.rl) {
@@ -24645,14 +24767,14 @@ async function ensureSnapshot(ctx) {
24645
24767
  }
24646
24768
  function printCraftReplResult(ctx, result, objective) {
24647
24769
  if (result.plan) {
24648
- printStrategyBrief(result.plan, {
24770
+ presentStrategyBrief(ctx, result.plan, {
24649
24771
  measurable_targets: result.measurable_targets,
24650
24772
  total_targets: result.total_targets
24651
- });
24773
+ }, result.notices, result.usage);
24652
24774
  } else {
24653
24775
  console.log(" " + chalk18.dim("(No plan produced)"));
24776
+ printStrategyBriefFooter(result.notices, result.usage);
24654
24777
  }
24655
- printStrategyBriefFooter(result.notices, result.usage);
24656
24778
  if (result.library_path) creditStrategySession(ctx);
24657
24779
  printCraftWrapUp({
24658
24780
  status: result.status,
@@ -25505,7 +25627,7 @@ function matchDefinitionExplainer(input) {
25505
25627
  }
25506
25628
  return getMetricExplainer(id);
25507
25629
  }
25508
- function printWrapped2(text, indent = " ") {
25630
+ function printWrapped(text, indent = " ") {
25509
25631
  for (const line of wrapWords(text, 78)) {
25510
25632
  console.log(indent + line);
25511
25633
  }
@@ -25522,10 +25644,10 @@ function tryKeylessDefinitionAnswer(ctx, input) {
25522
25644
  console.log(" " + chalk23.dim(explainer.tagline));
25523
25645
  console.log();
25524
25646
  console.log(" " + bold("Meaning"));
25525
- printWrapped2(explainer.meaning, " ");
25647
+ printWrapped(explainer.meaning, " ");
25526
25648
  console.log();
25527
25649
  console.log(" " + bold("How NTRP calculates it"));
25528
- printWrapped2(explainer.how_computed, " ");
25650
+ printWrapped(explainer.how_computed, " ");
25529
25651
  for (const f of explainer.formula_lines) {
25530
25652
  console.log(" " + paint("accent", f));
25531
25653
  }
@@ -30445,8 +30567,6 @@ async function ingestFromChat(ctx, filePath) {
30445
30567
  printGapCard(audit);
30446
30568
  if (audit.can_compute && ctx.scope?.confirmed_at) {
30447
30569
  if (ctx.pendingAsk) {
30448
- console.log();
30449
- console.log(" " + chalk31.dim("Computing so I can answer\u2026"));
30450
30570
  await runConversationCompute(ctx);
30451
30571
  return true;
30452
30572
  }
@@ -30530,8 +30650,6 @@ async function loadDemoFromChat(ctx, scenario, opts = {}) {
30530
30650
  const audit = await refreshGapAudit(ctx);
30531
30651
  const shouldAuto = opts.autoCompute || Boolean(ctx.pendingAsk && audit.can_compute && ctx.scope?.confirmed_at);
30532
30652
  if (shouldAuto && audit.can_compute) {
30533
- console.log();
30534
- console.log(" " + chalk31.dim("Computing so I can answer\u2026"));
30535
30653
  await runConversationCompute(ctx);
30536
30654
  return true;
30537
30655
  }
@@ -30610,12 +30728,6 @@ async function resumePendingAsk(ctx) {
30610
30728
  if (!pending?.text) return false;
30611
30729
  ctx.computeInProgress = false;
30612
30730
  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
30731
  console.log();
30620
30732
  const { runNaturalLanguage: runNaturalLanguage2 } = await Promise.resolve().then(() => (init_nl(), nl_exports));
30621
30733
  await runNaturalLanguage2(pending.text, ctx);
@@ -30897,7 +31009,7 @@ async function runDiagnoseTrace(options) {
30897
31009
  kind: "phase_end",
30898
31010
  phase: "compute",
30899
31011
  durationMs: Date.now() - computeStarted,
30900
- summary: "Vital signs computed"
31012
+ summary: "Pipeline scored"
30901
31013
  });
30902
31014
  computeEnded = true;
30903
31015
  }
@@ -30927,7 +31039,7 @@ async function runDiagnoseTrace(options) {
30927
31039
  kind: "phase_end",
30928
31040
  phase: "compute",
30929
31041
  durationMs: Date.now() - computeStarted,
30930
- summary: "Vital signs computed"
31042
+ summary: "Pipeline scored"
30931
31043
  });
30932
31044
  }
30933
31045
  if (fullResult && fullResult.segments.length > 0) {
@@ -30935,7 +31047,7 @@ async function runDiagnoseTrace(options) {
30935
31047
  kind: "phase_end",
30936
31048
  phase: "segments",
30937
31049
  durationMs: Date.now() - (segmentsStarted ?? Date.now()),
30938
- summary: `Segments computed \xB7 ${fullResult.segments.length}`
31050
+ summary: `${fullResult.segments.length} segment${fullResult.segments.length === 1 ? "" : "s"}`
30939
31051
  });
30940
31052
  }
30941
31053
  if (!fullResult) {
@@ -31041,7 +31153,7 @@ async function runDiagnoseTrace(options) {
31041
31153
  });
31042
31154
  const reportPath = ctx ? await writeSilentMarkdownReport(ctx, fullResult, collectedFindings) : null;
31043
31155
  if (reportPath) {
31044
- bus.emit({ kind: "artifact", path: reportPath, description: "Full report" });
31156
+ bus.emit({ kind: "artifact", path: reportPath, description: "Saved report" });
31045
31157
  } else if (ctx?.events instanceof EventBus) {
31046
31158
  bus.emit({ kind: "artifact", path: logPathForRun(ctx.events.runId), description: "Run log" });
31047
31159
  }
@@ -31262,7 +31374,7 @@ async function runSegmentDiagnose(options, ctx) {
31262
31374
  kind: "phase_end",
31263
31375
  phase: "compute",
31264
31376
  durationMs: Date.now() - t0,
31265
- summary: "Vital signs computed"
31377
+ summary: "Pipeline scored"
31266
31378
  });
31267
31379
  } catch (err) {
31268
31380
  bus.emit({ kind: "debug", message: String(err) });
@@ -31312,7 +31424,7 @@ async function runSegmentDiagnose(options, ctx) {
31312
31424
  }
31313
31425
  const reportPath = await writeSilentMarkdownReport2(ctx, result, []);
31314
31426
  if (reportPath) {
31315
- bus.emit({ kind: "artifact", path: reportPath, description: "Full report" });
31427
+ bus.emit({ kind: "artifact", path: reportPath, description: "Saved report" });
31316
31428
  }
31317
31429
  return buildDiagnoseSummary(match.result, []);
31318
31430
  }