@sonnechasser/ntrp 1.3.8 → 1.4.0

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 +1727 -761
  2. package/dist/mcp/server.js +831 -141
  3. package/package.json +2 -1
package/dist/index.js CHANGED
@@ -1685,6 +1685,26 @@ function buildSessionContextDoc(file, opts = {}) {
1685
1685
  if (file.strategist.origin) lines.push(`- Origin: ${file.strategist.origin}`);
1686
1686
  lines.push("");
1687
1687
  }
1688
+ if (file.think) {
1689
+ lines.push("## Think (in flight)");
1690
+ lines.push("");
1691
+ lines.push(`- Step: ${file.think.step}`);
1692
+ if (file.think.seed) lines.push(`- Seed: ${file.think.seed}`);
1693
+ if (file.think.origin) lines.push(`- Origin: ${file.think.origin}`);
1694
+ if (file.think.open_questions?.length) {
1695
+ lines.push("- Open questions:");
1696
+ for (const q of file.think.open_questions) lines.push(` - ${q}`);
1697
+ }
1698
+ if (file.think.challenged_assumptions?.length) {
1699
+ lines.push("- Challenged assumptions:");
1700
+ for (const a of file.think.challenged_assumptions) lines.push(` - ${a}`);
1701
+ }
1702
+ if (file.think.working_hypotheses?.length) {
1703
+ lines.push("- Working hypotheses:");
1704
+ for (const h of file.think.working_hypotheses) lines.push(` - ${h}`);
1705
+ }
1706
+ lines.push("");
1707
+ }
1688
1708
  lines.push("## Deliverables");
1689
1709
  lines.push("");
1690
1710
  if (file.deliverables && file.deliverables.length > 0) {
@@ -8767,6 +8787,7 @@ function initContext(oneShot, execution) {
8767
8787
  snapshot: { computeResult: null, divergences: [] },
8768
8788
  messages: [],
8769
8789
  conversation: [],
8790
+ thinkConversation: [],
8770
8791
  stage: "new",
8771
8792
  deliverables: [],
8772
8793
  analysis: defaultSessionAnalysis(),
@@ -8787,12 +8808,14 @@ function buildSessionFileSnapshot(ctx) {
8787
8808
  if (ctx.dataset) file.dataset = ctx.dataset;
8788
8809
  if (ctx.deliverables.length > 0) file.deliverables = ctx.deliverables;
8789
8810
  if (ctx.conversation.length > 0) file.thread = ctx.conversation;
8811
+ if (ctx.thinkConversation.length > 0) file.think_thread = ctx.thinkConversation;
8790
8812
  if (ctx.resumedFromId) file.resumed_from = ctx.resumedFromId;
8791
8813
  if (ctx.analysis) file.analysis = ctx.analysis;
8792
8814
  if (ctx.scope) file.scope = ctx.scope;
8793
8815
  if (ctx.attachments && ctx.attachments.length > 0) file.attachments = ctx.attachments;
8794
8816
  if (ctx.llm && Object.keys(ctx.llm).length > 0) file.llm = ctx.llm;
8795
8817
  if (ctx.strategistState) file.strategist = ctx.strategistState;
8818
+ if (ctx.thinkState) file.think = ctx.thinkState;
8796
8819
  if (ctx.pendingAsk) file.pending_ask = ctx.pendingAsk;
8797
8820
  return file;
8798
8821
  }
@@ -8919,6 +8942,9 @@ function loadSessionFile(id) {
8919
8942
  if (session.thread?.length) {
8920
8943
  session.thread = normalizeThread(session.thread);
8921
8944
  }
8945
+ if (session.think_thread?.length) {
8946
+ session.think_thread = normalizeThread(session.think_thread);
8947
+ }
8922
8948
  return session;
8923
8949
  } catch {
8924
8950
  return null;
@@ -9121,6 +9147,9 @@ async function finalizeSession(ctx, stage) {
9121
9147
  if (ctx.conversation.length > 0) {
9122
9148
  file.thread = ctx.conversation;
9123
9149
  }
9150
+ if (ctx.thinkConversation.length > 0) {
9151
+ file.think_thread = ctx.thinkConversation;
9152
+ }
9124
9153
  if (ctx.analysis) {
9125
9154
  file.analysis = ctx.analysis;
9126
9155
  }
@@ -9136,6 +9165,9 @@ async function finalizeSession(ctx, stage) {
9136
9165
  if (ctx.strategistState) {
9137
9166
  file.strategist = ctx.strategistState;
9138
9167
  }
9168
+ if (ctx.thinkState) {
9169
+ file.think = ctx.thinkState;
9170
+ }
9139
9171
  if (ctx.pendingAsk) {
9140
9172
  file.pending_ask = ctx.pendingAsk;
9141
9173
  }
@@ -9197,6 +9229,7 @@ function resetContextForSwitch(ctx, opts) {
9197
9229
  ctx.sessionName = opts.sessionName;
9198
9230
  ctx.messages = opts.messages;
9199
9231
  ctx.conversation = opts.conversation ?? [];
9232
+ ctx.thinkConversation = opts.thinkConversation ?? [];
9200
9233
  ctx.resumedFromId = opts.resumedFromId;
9201
9234
  ctx.resumedSessionSummary = opts.resumedSessionSummary;
9202
9235
  ctx.stage = opts.stage ?? "new";
@@ -9207,6 +9240,7 @@ function resetContextForSwitch(ctx, opts) {
9207
9240
  ctx.attachments = opts.attachments ?? [];
9208
9241
  ctx.llm = opts.llm;
9209
9242
  ctx.strategistState = opts.strategistState;
9243
+ ctx.thinkState = opts.thinkState;
9210
9244
  ctx.pendingAsk = opts.pendingAsk;
9211
9245
  ctx.gapAudit = void 0;
9212
9246
  ctx.deliverIntent = false;
@@ -9861,10 +9895,325 @@ var init_layout = __esm({
9861
9895
  }
9862
9896
  });
9863
9897
 
9864
- // src/ui/banner.ts
9898
+ // src/ui/slides.ts
9865
9899
  import chalk6 from "chalk";
9900
+ function liveFromVital(vs) {
9901
+ const dollarLine = vs.dollar_value != null && vs.dollar_value > 0 ? `$${vs.dollar_value >= 1e6 ? `${(vs.dollar_value / 1e6).toFixed(1)}M` : vs.dollar_value >= 1e3 ? `${(vs.dollar_value / 1e3).toFixed(0)}K` : vs.dollar_value.toFixed(0)} ${vs.dollar_label ?? ""}`.trim() : void 0;
9902
+ return {
9903
+ formatted: String(Math.round(vs.score)),
9904
+ status: vs.status,
9905
+ dollarLine
9906
+ };
9907
+ }
9908
+ function liveFromMetric(m) {
9909
+ return {
9910
+ formatted: m.formatted,
9911
+ status: m.status === "neutral" ? "neutral" : m.status,
9912
+ benchmarkNote: m.benchmark_note
9913
+ };
9914
+ }
9915
+ function clearSlideScreen() {
9916
+ if (process.stdout.isTTY) {
9917
+ process.stdout.write("\x1B[2J\x1B[H");
9918
+ }
9919
+ }
9920
+ function slideCardWidth() {
9921
+ return resolveCardWidth({ min: 64, max: 100, margin: 4 });
9922
+ }
9923
+ function tonePaint(tone = "accent") {
9924
+ switch (tone) {
9925
+ case "green":
9926
+ return chalk6.hex("#22c55e");
9927
+ case "yellow":
9928
+ return chalk6.hex("#eab308");
9929
+ case "red":
9930
+ return chalk6.hex("#ef4444");
9931
+ case "neutral":
9932
+ return chalk6.dim;
9933
+ default:
9934
+ return (t) => paint("accent", t);
9935
+ }
9936
+ }
9937
+ function renderBarRow(bar, barWidth, labelW) {
9938
+ const fill = Math.max(0, Math.min(barWidth, Math.round(bar.value / 100 * barWidth)));
9939
+ const body = "\u2588".repeat(fill) + "\u2591".repeat(barWidth - fill);
9940
+ const colored = tonePaint(bar.tone)(body);
9941
+ const label = padRight(truncateVisible(bar.label, labelW), labelW);
9942
+ const pct = String(Math.round(bar.value)).padStart(3);
9943
+ return `${label} ${colored} ${chalk6.dim(pct)}`;
9944
+ }
9945
+ function renderBars(bars, inner) {
9946
+ const labelW = Math.min(18, Math.max(...bars.map((b) => visibleWidth(b.label)), 8));
9947
+ const barWidth = Math.max(8, Math.min(28, inner - labelW - 6));
9948
+ return bars.map((b) => renderBarRow(b, barWidth, labelW));
9949
+ }
9950
+ function renderFunnel(steps, inner) {
9951
+ const maxBar = Math.max(12, Math.min(40, inner - 22));
9952
+ const lines = [];
9953
+ for (const step of steps) {
9954
+ const w = Math.max(2, Math.round(step.widthPct / 100 * maxBar));
9955
+ const bar = paint("accent", "\u2588".repeat(w));
9956
+ const label = truncateVisible(step.label, Math.max(8, inner - maxBar - 8));
9957
+ lines.push(`${padRight(label, Math.min(18, inner - maxBar - 6))} ${bar} ${chalk6.dim(`${step.widthPct}%`)}`);
9958
+ }
9959
+ return lines;
9960
+ }
9961
+ function renderWaterfall(steps, inner) {
9962
+ const maxAbs = Math.max(...steps.map((s) => Math.abs(s.cumulative)), 1);
9963
+ const barW = Math.max(10, Math.min(28, inner - 28));
9964
+ const lines = [];
9965
+ for (const step of steps) {
9966
+ const fill = Math.max(1, Math.round(Math.abs(step.cumulative) / maxAbs * barW));
9967
+ const bar = step.delta >= 0 ? chalk6.hex("#22c55e")("\u2588".repeat(fill)) : chalk6.hex("#ef4444")("\u2588".repeat(fill));
9968
+ const deltaStr = step.delta > 0 ? `+${step.delta}` : step.delta < 0 ? `${step.delta}` : `${step.delta}`;
9969
+ const deltaPainted = step.delta > 0 ? chalk6.hex("#22c55e")(deltaStr.padStart(5)) : step.delta < 0 ? chalk6.hex("#ef4444")(deltaStr.padStart(5)) : chalk6.dim(deltaStr.padStart(5));
9970
+ const label = padRight(truncateVisible(step.label, 14), 14);
9971
+ lines.push(`${label} ${deltaPainted} ${bar} ${chalk6.dim(`\u2192 ${step.cumulative}`)}`);
9972
+ }
9973
+ return lines;
9974
+ }
9975
+ function renderLayerStack(layers, inner) {
9976
+ const lines = [];
9977
+ for (let i = 0; i < layers.length; i++) {
9978
+ const layer = layers[i];
9979
+ const marker2 = layer.highlight ? paint("accent", "\u25C6") : chalk6.dim("\u25C7");
9980
+ const text = layer.highlight ? bold(layer.label) : chalk6.dim(layer.label);
9981
+ lines.push(`${marker2} ${truncateVisible(text, inner - 4)}`);
9982
+ if (i < layers.length - 1) {
9983
+ lines.push(chalk6.dim(" \u2502"));
9984
+ }
9985
+ }
9986
+ return lines;
9987
+ }
9988
+ function renderLevers(levers, inner) {
9989
+ const cell = Math.floor((inner - 9) / 2);
9990
+ const lines = [];
9991
+ lines.push(chalk6.dim("\u250C" + "\u2500".repeat(Math.max(8, cell)) + "\u2510 \u250C" + "\u2500".repeat(Math.max(8, cell)) + "\u2510"));
9992
+ for (let i = 0; i < levers.length; i += 2) {
9993
+ const a = padRight(truncateVisible(levers[i] ?? "", cell - 2), cell - 2);
9994
+ const b = padRight(truncateVisible(levers[i + 1] ?? "", cell - 2), cell - 2);
9995
+ lines.push(
9996
+ `${paint("accent", "\u2502")} ${a} ${paint("accent", "\u2502")} ${paint("accent", "\u2502")} ${b} ${paint("accent", "\u2502")}`
9997
+ );
9998
+ }
9999
+ lines.push(chalk6.dim("\u2514" + "\u2500".repeat(Math.max(8, cell)) + "\u2518 \u2514" + "\u2500".repeat(Math.max(8, cell)) + "\u2518"));
10000
+ return lines;
10001
+ }
10002
+ function renderGauge(score, inner, status) {
10003
+ const st = status ?? (score >= 80 ? "green" : score >= 60 ? "yellow" : "red");
10004
+ const bar = scoreBar(score, st === "neutral" ? "yellow" : st, Math.min(28, inner - 12));
10005
+ return [`${statusDot(st)} ${bar} ${bold(String(Math.round(score)))}`];
10006
+ }
10007
+ function renderSplit(bars, inner) {
10008
+ if (bars.length < 2) return renderBars(bars, inner);
10009
+ const total = bars.reduce((s, b) => s + b.value, 0) || 100;
10010
+ const width = Math.max(16, Math.min(40, inner - 4));
10011
+ let used = 0;
10012
+ const parts = [];
10013
+ for (let i = 0; i < bars.length; i++) {
10014
+ const b = bars[i];
10015
+ const w = i === bars.length - 1 ? width - used : Math.max(1, Math.round(b.value / total * width));
10016
+ used += w;
10017
+ parts.push(tonePaint(b.tone)("\u2588".repeat(w)));
10018
+ }
10019
+ const legend = bars.map((b) => `${tonePaint(b.tone)("\u25CF")} ${b.label} ${chalk6.dim(`${Math.round(b.value)}%`)}`).join(" ");
10020
+ return [parts.join(""), truncateVisible(legend, inner)];
10021
+ }
10022
+ function renderVisual(visual, inner) {
10023
+ const lines = [];
10024
+ switch (visual.kind) {
10025
+ case "bars":
10026
+ if (visual.bars?.length) lines.push(...renderBars(visual.bars, inner));
10027
+ break;
10028
+ case "funnel":
10029
+ if (visual.funnel?.length) lines.push(...renderFunnel(visual.funnel, inner));
10030
+ break;
10031
+ case "waterfall":
10032
+ if (visual.waterfall?.length) lines.push(...renderWaterfall(visual.waterfall, inner));
10033
+ break;
10034
+ case "layer_stack":
10035
+ if (visual.layers?.length) lines.push(...renderLayerStack(visual.layers, inner));
10036
+ break;
10037
+ case "levers":
10038
+ if (visual.levers?.length) lines.push(...renderLevers(visual.levers, inner));
10039
+ break;
10040
+ case "gauge":
10041
+ lines.push(...renderGauge(visual.gauge ?? 50, inner));
10042
+ if (visual.bars?.length) lines.push(...renderBars(visual.bars, inner));
10043
+ break;
10044
+ case "split":
10045
+ if (visual.bars?.length) lines.push(...renderSplit(visual.bars, inner));
10046
+ break;
10047
+ case "none":
10048
+ default:
10049
+ break;
10050
+ }
10051
+ if (visual.caption) {
10052
+ lines.push(chalk6.dim(truncateVisible(visual.caption, inner)));
10053
+ }
10054
+ return lines;
10055
+ }
10056
+ function kindBadge(explainer) {
10057
+ if (explainer.kind === "vital") return badge("VITAL", "accent");
10058
+ return badge("SAAS", "info");
10059
+ }
10060
+ function statusToTone(status) {
10061
+ if (status === "green") return "success";
10062
+ if (status === "yellow") return "warning";
10063
+ if (status === "red") return "error";
10064
+ return "muted";
10065
+ }
10066
+ function pushWrapped(out, text, inner, indent = "") {
10067
+ for (const w of wrapWords(text, inner - indent.length)) {
10068
+ out.push(indent + w);
10069
+ }
10070
+ }
10071
+ function buildSlideContent(explainer, opts = {}) {
10072
+ const width = slideCardWidth();
10073
+ const inner = width - 4;
10074
+ const lines = [];
10075
+ const title = opts.titleOverride ?? (explainer ? explainer.label : "Metrics");
10076
+ if (explainer) {
10077
+ const headerBits = [
10078
+ kindBadge(explainer),
10079
+ chalk6.dim(explainer.group)
10080
+ ];
10081
+ if (opts.index != null && opts.total != null) {
10082
+ headerBits.push(chalk6.dim(`slide ${opts.index}/${opts.total}`));
10083
+ }
10084
+ lines.push(headerBits.join(chalk6.dim(" \xB7 ")));
10085
+ lines.push(chalk6.dim(explainer.tagline));
10086
+ lines.push("");
10087
+ if (opts.live) {
10088
+ const live = opts.live;
10089
+ const tone = statusToTone(live.status);
10090
+ const liveLine = `${statusDot(live.status)} ${bold("Your reading:")} ${bold(live.formatted)} ` + badge(String(live.status), tone);
10091
+ lines.push(truncateVisible(liveLine, inner));
10092
+ if (live.dollarLine) {
10093
+ lines.push(chalk6.dim(` $ ${live.dollarLine}`));
10094
+ }
10095
+ if (live.benchmarkNote) {
10096
+ lines.push(chalk6.dim(` ${live.benchmarkNote}`));
10097
+ }
10098
+ lines.push("");
10099
+ } else {
10100
+ const hint = explainer.benchmarkHint?.(opts.motion);
10101
+ if (hint) {
10102
+ lines.push(chalk6.dim(`Benchmark \xB7 ${hint}`));
10103
+ lines.push("");
10104
+ }
10105
+ }
10106
+ const visual = opts.visualOverride ?? explainer.visual;
10107
+ const visLines = renderVisual(visual, inner);
10108
+ if (visLines.length) {
10109
+ lines.push(...visLines);
10110
+ lines.push("");
10111
+ }
10112
+ lines.push(sectionHeading("What it means"));
10113
+ pushWrapped(lines, explainer.meaning, inner, " ");
10114
+ lines.push("");
10115
+ if (!opts.skipFormula) {
10116
+ lines.push(sectionHeading("How it's calculated"));
10117
+ pushWrapped(lines, explainer.how_computed, inner, " ");
10118
+ for (const f of explainer.formula_lines) {
10119
+ lines.push(paint("accent", ` ${f}`));
10120
+ }
10121
+ lines.push("");
10122
+ }
10123
+ if (opts.deepdive) {
10124
+ lines.push(sectionHeading("Deep dive"));
10125
+ pushWrapped(lines, explainer.expert_read, inner, " ");
10126
+ lines.push("");
10127
+ for (const bullet of explainer.deepdive) {
10128
+ pushWrapped(lines, `\xB7 ${bullet}`, inner, " ");
10129
+ }
10130
+ if (explainer.play_id) {
10131
+ lines.push("");
10132
+ lines.push(
10133
+ chalk6.dim(" Play: ") + paint("accent", explainer.play_id)
10134
+ );
10135
+ }
10136
+ lines.push("");
10137
+ }
10138
+ } else if (opts.visualOverride) {
10139
+ const visLines = renderVisual(opts.visualOverride, inner);
10140
+ if (visLines.length) {
10141
+ lines.push(...visLines);
10142
+ lines.push("");
10143
+ }
10144
+ }
10145
+ if (opts.extraLines?.length) {
10146
+ for (const line of opts.extraLines) {
10147
+ if (line === "") lines.push("");
10148
+ else pushWrapped(lines, line, inner);
10149
+ }
10150
+ }
10151
+ return { title, lines, width, inner };
10152
+ }
10153
+ function renderMetricSlide(explainer, opts = {}) {
10154
+ const { title, lines, width, inner } = buildSlideContent(explainer, opts);
10155
+ const border = (s) => paint("border", s);
10156
+ const termW = termWidth();
10157
+ const outerPad = " ".repeat(Math.max(0, Math.floor((termW - width) / 2)));
10158
+ const out = [];
10159
+ out.push("");
10160
+ out.push(`${outerPad}${border(`\u256D${"\u2500".repeat(width - 2)}\u256E`)}`);
10161
+ out.push(
10162
+ `${outerPad}${border("\u2502 ")}${padRight(sectionHeading(title), inner)}${border(" \u2502")}`
10163
+ );
10164
+ out.push(`${outerPad}${border(`\u251C${"\u2500".repeat(width - 2)}\u2524`)}`);
10165
+ for (const row of lines) {
10166
+ out.push(
10167
+ `${outerPad}${border("\u2502 ")}${padRight(truncateVisible(row, inner), inner)}${border(" \u2502")}`
10168
+ );
10169
+ }
10170
+ const footer = opts.footer ?? (opts.deepdive ? `\u23CE next \xB7 b back \xB7 q quit` : `\u23CE next \xB7 /deepdive more \xB7 b back \xB7 q quit`);
10171
+ out.push(`${outerPad}${border(`\u251C${"\u2500".repeat(width - 2)}\u2524`)}`);
10172
+ out.push(
10173
+ `${outerPad}${border("\u2502 ")}${padRight(chalk6.dim(truncateVisible(footer, inner)), inner)}${border(" \u2502")}`
10174
+ );
10175
+ out.push(`${outerPad}${border(`\u2570${"\u2500".repeat(width - 2)}\u256F`)}`);
10176
+ out.push("");
10177
+ if (opts.asLines) return out;
10178
+ for (const line of out) console.log(line);
10179
+ }
10180
+ function progressDots(index, total) {
10181
+ const parts = [];
10182
+ for (let i = 1; i <= total; i++) {
10183
+ parts.push(i === index ? paint("accent", "\u25CF") : chalk6.dim("\u25CB"));
10184
+ }
10185
+ return parts.join("");
10186
+ }
10187
+ function printExplainerCatalogLine(explainer) {
10188
+ const kind = explainer.kind === "vital" ? paint("accent", "vital") : chalk6.dim("saas ");
10189
+ console.log(
10190
+ ` ${kind} ${bold(explainer.id.padEnd(20))} ${chalk6.dim(explainer.label)} \u2014 ${chalk6.dim(explainer.tagline)}`
10191
+ );
10192
+ }
10193
+ function printGuideCatalogLine(slide) {
10194
+ console.log(
10195
+ ` ${paint("accent", "how ")} ${bold(slide.id.padEnd(20))} ${chalk6.dim(slide.label)} \u2014 ${chalk6.dim(slide.tagline)}`
10196
+ );
10197
+ }
10198
+ function printDeepdiveHint(metricId, label) {
10199
+ const name = label ?? metricId;
10200
+ console.log(
10201
+ " " + chalk6.dim("How this number works: ") + paint("accent", `/deepdive ${metricId}`) + chalk6.dim(` \u2014 ${name}`)
10202
+ );
10203
+ console.log();
10204
+ }
10205
+ var init_slides = __esm({
10206
+ "src/ui/slides.ts"() {
10207
+ "use strict";
10208
+ init_theme();
10209
+ init_layout();
10210
+ }
10211
+ });
10212
+
10213
+ // src/ui/banner.ts
10214
+ import chalk7 from "chalk";
9866
10215
  function renderLogo() {
9867
- return LOGO_LINES.map((line, i) => chalk6.hex(GRADIENT[i % GRADIENT.length])(line));
10216
+ return LOGO_LINES.map((line, i) => chalk7.hex(GRADIENT[i % GRADIENT.length])(line));
9868
10217
  }
9869
10218
  function printCenteredLogo() {
9870
10219
  const width = termWidth();
@@ -9890,7 +10239,7 @@ function printReplHeader(version) {
9890
10239
  const gap = Math.max(0, innerW - versionTag.length);
9891
10240
  const gapL = Math.floor(gap / 2);
9892
10241
  console.log(
9893
- outerPad + paint("border", `\u256D${"\u2500".repeat(gapL)}`) + chalk6.dim(versionTag) + paint("border", `${"\u2500".repeat(gap - gapL)}\u256E`)
10242
+ outerPad + paint("border", `\u256D${"\u2500".repeat(gapL)}`) + chalk7.dim(versionTag) + paint("border", `${"\u2500".repeat(gap - gapL)}\u256E`)
9894
10243
  );
9895
10244
  console.log();
9896
10245
  }
@@ -10434,7 +10783,7 @@ __export(upgrade_exports, {
10434
10783
  resolveUpgradeReason: () => resolveUpgradeReason,
10435
10784
  runUpgradeFlow: () => runUpgradeFlow
10436
10785
  });
10437
- import chalk7 from "chalk";
10786
+ import chalk8 from "chalk";
10438
10787
  function checkoutUrlFor(purpose) {
10439
10788
  return purpose === "upgrade" ? getUpgradeUrl() : getCheckoutUrl();
10440
10789
  }
@@ -10448,25 +10797,25 @@ function printLicenseBlocked(context) {
10448
10797
  const lic = checkLicense();
10449
10798
  console.log();
10450
10799
  if (isTrialCutoff(lic)) {
10451
- console.log(" " + chalk7.yellow(randomBlockedNudge()));
10800
+ console.log(" " + chalk8.yellow(randomBlockedNudge()));
10452
10801
  } else {
10453
- console.log(chalk7.red(` A license is required for ${context}.`));
10802
+ console.log(chalk8.red(` A license is required for ${context}.`));
10454
10803
  console.log(
10455
- " " + chalk7.dim("Type ") + paint("accent", "/upgrade") + chalk7.dim(" or ") + paint("accent", "/checkout") + chalk7.dim(" to get a license.")
10804
+ " " + chalk8.dim("Type ") + paint("accent", "/activate") + chalk8.dim(" to paste a key, or ") + paint("accent", "/checkout") + chalk8.dim(" to sign up.")
10456
10805
  );
10457
10806
  }
10458
10807
  console.log();
10459
10808
  }
10460
10809
  function printGraceNudge(lic) {
10461
10810
  if (!lic.shouldNudgeUpgrade || lic.daysUntilLockout === void 0) return;
10462
- console.log(" " + chalk7.yellow(randomGraceNudge(lic.daysUntilLockout)));
10811
+ console.log(" " + chalk8.yellow(randomGraceNudge(lic.daysUntilLockout)));
10463
10812
  console.log();
10464
10813
  }
10465
10814
  function printActiveTrialNudge(lic) {
10466
10815
  if (!lic.shouldNudgeUpgrade || lic.trialPhase !== "active") return;
10467
10816
  const daysLeft = lic.trialDaysRemaining;
10468
10817
  if (daysLeft === void 0 || daysLeft <= 0) return;
10469
- console.log(" " + chalk7.yellow(randomActiveTrialNudge(daysLeft)));
10818
+ console.log(" " + chalk8.yellow(randomActiveTrialNudge(daysLeft)));
10470
10819
  console.log();
10471
10820
  }
10472
10821
  function printTrialNudge(lic) {
@@ -10487,7 +10836,7 @@ function subtitleFor(reason) {
10487
10836
  }
10488
10837
  async function promptOpenCheckout(ctx, purpose = "signup") {
10489
10838
  const url = checkoutUrlFor(purpose);
10490
- console.log(" " + chalk7.dim(url));
10839
+ console.log(" " + chalk8.dim(url));
10491
10840
  if (!process.stdin.isTTY || process.env.NTRP_NO_BROWSER_OPEN === "1") {
10492
10841
  console.log();
10493
10842
  return;
@@ -10498,14 +10847,14 @@ async function promptOpenCheckout(ctx, purpose = "signup") {
10498
10847
  await session.askPressEnter("Open checkout in your browser");
10499
10848
  try {
10500
10849
  await openInBrowser(url);
10501
- console.log(" " + chalk7.green("\u2713 Browser opened"));
10850
+ console.log(" " + chalk8.green("\u2713 Browser opened"));
10502
10851
  console.log(
10503
- " " + chalk7.dim(
10852
+ " " + chalk8.dim(
10504
10853
  purpose === "upgrade" ? "Complete checkout in your browser. Then paste your Pro key below." : "Complete signup in your browser. Then paste your key below."
10505
10854
  )
10506
10855
  );
10507
10856
  } catch {
10508
- console.log(" " + chalk7.yellow("Could not open the browser. Copy the URL above."));
10857
+ console.log(" " + chalk8.yellow("Could not open the browser. Copy the URL above."));
10509
10858
  }
10510
10859
  console.log();
10511
10860
  } finally {
@@ -10515,18 +10864,18 @@ async function promptOpenCheckout(ctx, purpose = "signup") {
10515
10864
  async function openCheckoutInBrowser() {
10516
10865
  const url = getCheckoutUrl();
10517
10866
  console.log();
10518
- console.log(" " + chalk7.dim(url));
10867
+ console.log(" " + chalk8.dim(url));
10519
10868
  if (!process.stdin.isTTY) {
10520
10869
  console.log();
10521
10870
  return;
10522
10871
  }
10523
10872
  try {
10524
10873
  await openInBrowser(url);
10525
- console.log(" " + chalk7.green("\u2713 Browser opened"));
10874
+ console.log(" " + chalk8.green("\u2713 Browser opened"));
10526
10875
  } catch {
10527
- console.log(" " + chalk7.yellow("Could not open the browser. Copy the URL above."));
10876
+ console.log(" " + chalk8.yellow("Could not open the browser. Copy the URL above."));
10528
10877
  }
10529
- console.log(" " + chalk7.dim("After signup, paste your key with /activate or /upgrade."));
10878
+ console.log(" " + chalk8.dim("After signup, paste your key with /activate or /upgrade."));
10530
10879
  console.log();
10531
10880
  }
10532
10881
  async function promptForLicenseKey(ctx, purpose = "signup") {
@@ -10538,13 +10887,13 @@ async function promptForLicenseKey(ctx, purpose = "signup") {
10538
10887
  key = await session.askSecret("Paste your license key", { confirm: false });
10539
10888
  } catch (err) {
10540
10889
  if (err instanceof Error && err.message === "Cancelled") {
10541
- console.log(" " + chalk7.dim("Activation cancelled."));
10890
+ console.log(" " + chalk8.dim("Activation cancelled."));
10542
10891
  return false;
10543
10892
  }
10544
10893
  throw err;
10545
10894
  }
10546
10895
  if (!key.trim()) {
10547
- console.log(" " + chalk7.red("A license key is required."));
10896
+ console.log(" " + chalk8.red("A license key is required."));
10548
10897
  continue;
10549
10898
  }
10550
10899
  let result;
@@ -10552,21 +10901,21 @@ async function promptForLicenseKey(ctx, purpose = "signup") {
10552
10901
  result = await activateLicenseKey(key.trim());
10553
10902
  } catch (err) {
10554
10903
  const message = err instanceof Error ? err.message : "License activation failed";
10555
- console.log(" " + chalk7.red(message));
10556
- console.log(" " + chalk7.dim("Check your network connection and try again."));
10904
+ console.log(" " + chalk8.red(message));
10905
+ console.log(" " + chalk8.dim("Check your network connection and try again."));
10557
10906
  console.log();
10558
10907
  continue;
10559
10908
  }
10560
10909
  if (!result.valid) {
10561
- console.log(" " + chalk7.red(result.message));
10910
+ console.log(" " + chalk8.red(result.message));
10562
10911
  console.log(
10563
- " " + chalk7.dim(`Use the key from your purchase email, or try again: ${checkoutUrlFor(purpose)}`)
10912
+ " " + chalk8.dim(`Use the key from your purchase email, or try again: ${checkoutUrlFor(purpose)}`)
10564
10913
  );
10565
10914
  console.log();
10566
10915
  continue;
10567
10916
  }
10568
10917
  console.log();
10569
- console.log(chalk7.green(` \u2713 ${randomProActivatedLine()}`));
10918
+ console.log(chalk8.green(` \u2713 ${randomProActivatedLine()}`));
10570
10919
  console.log();
10571
10920
  return true;
10572
10921
  }
@@ -10578,10 +10927,10 @@ async function runUpgradeFlow(ctx, reason) {
10578
10927
  const lic = checkLicense();
10579
10928
  printCenteredLogo();
10580
10929
  console.log(" " + bold(headlineFor(reason, lic)));
10581
- console.log(" " + chalk7.dim(subtitleFor(reason)));
10930
+ console.log(" " + chalk8.dim(subtitleFor(reason)));
10582
10931
  console.log();
10583
10932
  await promptOpenCheckout(ctx, "upgrade");
10584
- console.log(" " + chalk7.dim("Paste your license key when it arrives by email."));
10933
+ console.log(" " + chalk8.dim("Paste your license key when it arrives by email."));
10585
10934
  console.log();
10586
10935
  return promptForLicenseKey(ctx, "upgrade");
10587
10936
  }
@@ -10609,7 +10958,7 @@ var init_upgrade = __esm({
10609
10958
  });
10610
10959
 
10611
10960
  // src/license/activation.ts
10612
- import chalk8 from "chalk";
10961
+ import chalk9 from "chalk";
10613
10962
  function hasValidLicense() {
10614
10963
  return checkLicense().valid;
10615
10964
  }
@@ -10617,10 +10966,10 @@ async function ensureLicenseActivated(ctx, options = {}) {
10617
10966
  if (hasValidLicense()) return false;
10618
10967
  if (!process.stdin.isTTY) {
10619
10968
  console.error();
10620
- console.error(chalk8.red(" A license key is required."));
10621
- console.error(chalk8.dim(` Sign up: ${getCheckoutUrl()}`));
10622
- console.error(chalk8.dim(" Then type: ntrp activate <key>"));
10623
- console.error(chalk8.dim(" Or set NTRP_LICENSE_KEY for headless use."));
10969
+ console.error(chalk9.red(" A license key is required."));
10970
+ console.error(chalk9.dim(` Sign up: ${getCheckoutUrl()}`));
10971
+ console.error(chalk9.dim(" Then type: ntrp activate <key>"));
10972
+ console.error(chalk9.dim(" Or set NTRP_LICENSE_KEY for headless use."));
10624
10973
  console.error();
10625
10974
  process.exit(1);
10626
10975
  }
@@ -10637,9 +10986,9 @@ async function ensureLicenseActivated(ctx, options = {}) {
10637
10986
  }
10638
10987
  printCenteredLogo();
10639
10988
  console.log(" " + bold("Welcome to NTRP"));
10640
- console.log(" " + chalk8.dim(TAGLINE));
10641
- console.log(" " + chalk8.dim("Paste a trial key or a Pro key. If you do not have a key, NTRP opens signup."));
10642
- console.log(" " + chalk8.dim("Activating accepts the NTRP license (LICENSE in the install, or ntrp.sonnechasser.com)."));
10989
+ console.log(" " + chalk9.dim(TAGLINE));
10990
+ console.log(" " + chalk9.dim("Paste a trial key or a Pro key. If you do not have a key, NTRP opens signup."));
10991
+ console.log(" " + chalk9.dim("Activating accepts the NTRP license (LICENSE in the install, or ntrp.sonnechasser.com)."));
10643
10992
  console.log();
10644
10993
  await promptOpenCheckout(ctx);
10645
10994
  const activated = await promptForLicenseKey(ctx);
@@ -10651,12 +11000,14 @@ async function ensureLicenseActivated(ctx, options = {}) {
10651
11000
  return true;
10652
11001
  }
10653
11002
  function exitActivationCancelled() {
10654
- console.log(" " + chalk8.dim("No license activated. Type ") + chalk8.cyan("ntrp") + chalk8.dim(" to try again."));
11003
+ console.log(" " + chalk9.dim("No license activated. Type ") + chalk9.cyan("ntrp") + chalk9.dim(" to try again."));
10655
11004
  console.log();
10656
11005
  process.exit(130);
10657
11006
  }
10658
11007
  function printActivationCancelledStay() {
10659
- console.log(" " + chalk8.dim("No license activated. Type ") + chalk8.cyan("/checkout") + chalk8.dim(" to continue."));
11008
+ console.log(
11009
+ " " + chalk9.dim("No license activated. Type ") + chalk9.cyan("/activate") + chalk9.dim(" to paste a key. Type ") + chalk9.cyan("/checkout") + chalk9.dim(" if you need to sign up.")
11010
+ );
10660
11011
  console.log();
10661
11012
  }
10662
11013
  var init_activation = __esm({
@@ -11976,326 +12327,12 @@ var init_guide_slides = __esm({
11976
12327
  }
11977
12328
  });
11978
12329
 
11979
- // src/ui/slides.ts
11980
- import chalk9 from "chalk";
11981
- function liveFromVital(vs) {
11982
- const dollarLine = vs.dollar_value != null && vs.dollar_value > 0 ? `$${vs.dollar_value >= 1e6 ? `${(vs.dollar_value / 1e6).toFixed(1)}M` : vs.dollar_value >= 1e3 ? `${(vs.dollar_value / 1e3).toFixed(0)}K` : vs.dollar_value.toFixed(0)} ${vs.dollar_label ?? ""}`.trim() : void 0;
11983
- return {
11984
- formatted: String(Math.round(vs.score)),
11985
- status: vs.status,
11986
- dollarLine
11987
- };
11988
- }
11989
- function liveFromMetric(m) {
11990
- return {
11991
- formatted: m.formatted,
11992
- status: m.status === "neutral" ? "neutral" : m.status,
11993
- benchmarkNote: m.benchmark_note
11994
- };
11995
- }
11996
- function clearSlideScreen() {
11997
- if (process.stdout.isTTY) {
11998
- process.stdout.write("\x1B[2J\x1B[H");
11999
- }
12000
- }
12001
- function slideCardWidth() {
12002
- return resolveCardWidth({ min: 64, max: 100, margin: 4 });
12003
- }
12004
- function tonePaint(tone = "accent") {
12005
- switch (tone) {
12006
- case "green":
12007
- return chalk9.hex("#22c55e");
12008
- case "yellow":
12009
- return chalk9.hex("#eab308");
12010
- case "red":
12011
- return chalk9.hex("#ef4444");
12012
- case "neutral":
12013
- return chalk9.dim;
12014
- default:
12015
- return (t) => paint("accent", t);
12016
- }
12017
- }
12018
- function renderBarRow(bar, barWidth, labelW) {
12019
- const fill = Math.max(0, Math.min(barWidth, Math.round(bar.value / 100 * barWidth)));
12020
- const body = "\u2588".repeat(fill) + "\u2591".repeat(barWidth - fill);
12021
- const colored = tonePaint(bar.tone)(body);
12022
- const label = padRight(truncateVisible(bar.label, labelW), labelW);
12023
- const pct = String(Math.round(bar.value)).padStart(3);
12024
- return `${label} ${colored} ${chalk9.dim(pct)}`;
12025
- }
12026
- function renderBars(bars, inner) {
12027
- const labelW = Math.min(18, Math.max(...bars.map((b) => visibleWidth(b.label)), 8));
12028
- const barWidth = Math.max(8, Math.min(28, inner - labelW - 6));
12029
- return bars.map((b) => renderBarRow(b, barWidth, labelW));
12030
- }
12031
- function renderFunnel(steps, inner) {
12032
- const maxBar = Math.max(12, Math.min(40, inner - 22));
12033
- const lines = [];
12034
- for (const step of steps) {
12035
- const w = Math.max(2, Math.round(step.widthPct / 100 * maxBar));
12036
- const bar = paint("accent", "\u2588".repeat(w));
12037
- const label = truncateVisible(step.label, Math.max(8, inner - maxBar - 8));
12038
- lines.push(`${padRight(label, Math.min(18, inner - maxBar - 6))} ${bar} ${chalk9.dim(`${step.widthPct}%`)}`);
12039
- }
12040
- return lines;
12041
- }
12042
- function renderWaterfall(steps, inner) {
12043
- const maxAbs = Math.max(...steps.map((s) => Math.abs(s.cumulative)), 1);
12044
- const barW = Math.max(10, Math.min(28, inner - 28));
12045
- const lines = [];
12046
- for (const step of steps) {
12047
- const fill = Math.max(1, Math.round(Math.abs(step.cumulative) / maxAbs * barW));
12048
- const bar = step.delta >= 0 ? chalk9.hex("#22c55e")("\u2588".repeat(fill)) : chalk9.hex("#ef4444")("\u2588".repeat(fill));
12049
- const deltaStr = step.delta > 0 ? `+${step.delta}` : step.delta < 0 ? `${step.delta}` : `${step.delta}`;
12050
- const deltaPainted = step.delta > 0 ? chalk9.hex("#22c55e")(deltaStr.padStart(5)) : step.delta < 0 ? chalk9.hex("#ef4444")(deltaStr.padStart(5)) : chalk9.dim(deltaStr.padStart(5));
12051
- const label = padRight(truncateVisible(step.label, 14), 14);
12052
- lines.push(`${label} ${deltaPainted} ${bar} ${chalk9.dim(`\u2192 ${step.cumulative}`)}`);
12053
- }
12054
- return lines;
12055
- }
12056
- function renderLayerStack(layers, inner) {
12057
- const lines = [];
12058
- for (let i = 0; i < layers.length; i++) {
12059
- const layer = layers[i];
12060
- const marker2 = layer.highlight ? paint("accent", "\u25C6") : chalk9.dim("\u25C7");
12061
- const text = layer.highlight ? bold(layer.label) : chalk9.dim(layer.label);
12062
- lines.push(`${marker2} ${truncateVisible(text, inner - 4)}`);
12063
- if (i < layers.length - 1) {
12064
- lines.push(chalk9.dim(" \u2502"));
12065
- }
12066
- }
12067
- return lines;
12068
- }
12069
- function renderLevers(levers, inner) {
12070
- const cell = Math.floor((inner - 9) / 2);
12071
- const lines = [];
12072
- lines.push(chalk9.dim("\u250C" + "\u2500".repeat(Math.max(8, cell)) + "\u2510 \u250C" + "\u2500".repeat(Math.max(8, cell)) + "\u2510"));
12073
- for (let i = 0; i < levers.length; i += 2) {
12074
- const a = padRight(truncateVisible(levers[i] ?? "", cell - 2), cell - 2);
12075
- const b = padRight(truncateVisible(levers[i + 1] ?? "", cell - 2), cell - 2);
12076
- lines.push(
12077
- `${paint("accent", "\u2502")} ${a} ${paint("accent", "\u2502")} ${paint("accent", "\u2502")} ${b} ${paint("accent", "\u2502")}`
12078
- );
12079
- }
12080
- lines.push(chalk9.dim("\u2514" + "\u2500".repeat(Math.max(8, cell)) + "\u2518 \u2514" + "\u2500".repeat(Math.max(8, cell)) + "\u2518"));
12081
- return lines;
12082
- }
12083
- function renderGauge(score, inner, status) {
12084
- const st = status ?? (score >= 80 ? "green" : score >= 60 ? "yellow" : "red");
12085
- const bar = scoreBar(score, st === "neutral" ? "yellow" : st, Math.min(28, inner - 12));
12086
- return [`${statusDot(st)} ${bar} ${bold(String(Math.round(score)))}`];
12087
- }
12088
- function renderSplit(bars, inner) {
12089
- if (bars.length < 2) return renderBars(bars, inner);
12090
- const total = bars.reduce((s, b) => s + b.value, 0) || 100;
12091
- const width = Math.max(16, Math.min(40, inner - 4));
12092
- let used = 0;
12093
- const parts = [];
12094
- for (let i = 0; i < bars.length; i++) {
12095
- const b = bars[i];
12096
- const w = i === bars.length - 1 ? width - used : Math.max(1, Math.round(b.value / total * width));
12097
- used += w;
12098
- parts.push(tonePaint(b.tone)("\u2588".repeat(w)));
12099
- }
12100
- const legend = bars.map((b) => `${tonePaint(b.tone)("\u25CF")} ${b.label} ${chalk9.dim(`${Math.round(b.value)}%`)}`).join(" ");
12101
- return [parts.join(""), truncateVisible(legend, inner)];
12102
- }
12103
- function renderVisual(visual, inner) {
12104
- const lines = [];
12105
- switch (visual.kind) {
12106
- case "bars":
12107
- if (visual.bars?.length) lines.push(...renderBars(visual.bars, inner));
12108
- break;
12109
- case "funnel":
12110
- if (visual.funnel?.length) lines.push(...renderFunnel(visual.funnel, inner));
12111
- break;
12112
- case "waterfall":
12113
- if (visual.waterfall?.length) lines.push(...renderWaterfall(visual.waterfall, inner));
12114
- break;
12115
- case "layer_stack":
12116
- if (visual.layers?.length) lines.push(...renderLayerStack(visual.layers, inner));
12117
- break;
12118
- case "levers":
12119
- if (visual.levers?.length) lines.push(...renderLevers(visual.levers, inner));
12120
- break;
12121
- case "gauge":
12122
- lines.push(...renderGauge(visual.gauge ?? 50, inner));
12123
- if (visual.bars?.length) lines.push(...renderBars(visual.bars, inner));
12124
- break;
12125
- case "split":
12126
- if (visual.bars?.length) lines.push(...renderSplit(visual.bars, inner));
12127
- break;
12128
- case "none":
12129
- default:
12130
- break;
12131
- }
12132
- if (visual.caption) {
12133
- lines.push(chalk9.dim(truncateVisible(visual.caption, inner)));
12134
- }
12135
- return lines;
12136
- }
12137
- function kindBadge(explainer) {
12138
- if (explainer.kind === "vital") return badge("VITAL", "accent");
12139
- return badge("SAAS", "info");
12140
- }
12141
- function statusToTone(status) {
12142
- if (status === "green") return "success";
12143
- if (status === "yellow") return "warning";
12144
- if (status === "red") return "error";
12145
- return "muted";
12146
- }
12147
- function pushWrapped(out, text, inner, indent = "") {
12148
- for (const w of wrapWords(text, inner - indent.length)) {
12149
- out.push(indent + w);
12150
- }
12151
- }
12152
- function buildSlideContent(explainer, opts = {}) {
12153
- const width = slideCardWidth();
12154
- const inner = width - 4;
12155
- const lines = [];
12156
- const title = opts.titleOverride ?? (explainer ? explainer.label : "Metrics");
12157
- if (explainer) {
12158
- const headerBits = [
12159
- kindBadge(explainer),
12160
- chalk9.dim(explainer.group)
12161
- ];
12162
- if (opts.index != null && opts.total != null) {
12163
- headerBits.push(chalk9.dim(`slide ${opts.index}/${opts.total}`));
12164
- }
12165
- lines.push(headerBits.join(chalk9.dim(" \xB7 ")));
12166
- lines.push(chalk9.dim(explainer.tagline));
12167
- lines.push("");
12168
- if (opts.live) {
12169
- const live = opts.live;
12170
- const tone = statusToTone(live.status);
12171
- const liveLine = `${statusDot(live.status)} ${bold("Your reading:")} ${bold(live.formatted)} ` + badge(String(live.status), tone);
12172
- lines.push(truncateVisible(liveLine, inner));
12173
- if (live.dollarLine) {
12174
- lines.push(chalk9.dim(` $ ${live.dollarLine}`));
12175
- }
12176
- if (live.benchmarkNote) {
12177
- lines.push(chalk9.dim(` ${live.benchmarkNote}`));
12178
- }
12179
- lines.push("");
12180
- } else {
12181
- const hint = explainer.benchmarkHint?.(opts.motion);
12182
- if (hint) {
12183
- lines.push(chalk9.dim(`Benchmark \xB7 ${hint}`));
12184
- lines.push("");
12185
- }
12186
- }
12187
- const visual = opts.visualOverride ?? explainer.visual;
12188
- const visLines = renderVisual(visual, inner);
12189
- if (visLines.length) {
12190
- lines.push(...visLines);
12191
- lines.push("");
12192
- }
12193
- lines.push(sectionHeading("What it means"));
12194
- pushWrapped(lines, explainer.meaning, inner, " ");
12195
- lines.push("");
12196
- if (!opts.skipFormula) {
12197
- lines.push(sectionHeading("How it's calculated"));
12198
- pushWrapped(lines, explainer.how_computed, inner, " ");
12199
- for (const f of explainer.formula_lines) {
12200
- lines.push(paint("accent", ` ${f}`));
12201
- }
12202
- lines.push("");
12203
- }
12204
- if (opts.deepdive) {
12205
- lines.push(sectionHeading("Deep dive"));
12206
- pushWrapped(lines, explainer.expert_read, inner, " ");
12207
- lines.push("");
12208
- for (const bullet of explainer.deepdive) {
12209
- pushWrapped(lines, `\xB7 ${bullet}`, inner, " ");
12210
- }
12211
- if (explainer.play_id) {
12212
- lines.push("");
12213
- lines.push(
12214
- chalk9.dim(" Play: ") + paint("accent", explainer.play_id)
12215
- );
12216
- }
12217
- lines.push("");
12218
- }
12219
- } else if (opts.visualOverride) {
12220
- const visLines = renderVisual(opts.visualOverride, inner);
12221
- if (visLines.length) {
12222
- lines.push(...visLines);
12223
- lines.push("");
12224
- }
12225
- }
12226
- if (opts.extraLines?.length) {
12227
- for (const line of opts.extraLines) {
12228
- if (line === "") lines.push("");
12229
- else pushWrapped(lines, line, inner);
12230
- }
12231
- }
12232
- return { title, lines, width, inner };
12233
- }
12234
- function renderMetricSlide(explainer, opts = {}) {
12235
- const { title, lines, width, inner } = buildSlideContent(explainer, opts);
12236
- const border = (s) => paint("border", s);
12237
- const termW = termWidth();
12238
- const outerPad = " ".repeat(Math.max(0, Math.floor((termW - width) / 2)));
12239
- const out = [];
12240
- out.push("");
12241
- out.push(`${outerPad}${border(`\u256D${"\u2500".repeat(width - 2)}\u256E`)}`);
12242
- out.push(
12243
- `${outerPad}${border("\u2502 ")}${padRight(sectionHeading(title), inner)}${border(" \u2502")}`
12244
- );
12245
- out.push(`${outerPad}${border(`\u251C${"\u2500".repeat(width - 2)}\u2524`)}`);
12246
- for (const row of lines) {
12247
- out.push(
12248
- `${outerPad}${border("\u2502 ")}${padRight(truncateVisible(row, inner), inner)}${border(" \u2502")}`
12249
- );
12250
- }
12251
- const footer = opts.footer ?? (opts.deepdive ? `\u23CE next \xB7 b back \xB7 q quit` : `\u23CE next \xB7 /deepdive more \xB7 b back \xB7 q quit`);
12252
- out.push(`${outerPad}${border(`\u251C${"\u2500".repeat(width - 2)}\u2524`)}`);
12253
- out.push(
12254
- `${outerPad}${border("\u2502 ")}${padRight(chalk9.dim(truncateVisible(footer, inner)), inner)}${border(" \u2502")}`
12255
- );
12256
- out.push(`${outerPad}${border(`\u2570${"\u2500".repeat(width - 2)}\u256F`)}`);
12257
- out.push("");
12258
- if (opts.asLines) return out;
12259
- for (const line of out) console.log(line);
12260
- }
12261
- function progressDots(index, total) {
12262
- const parts = [];
12263
- for (let i = 1; i <= total; i++) {
12264
- parts.push(i === index ? paint("accent", "\u25CF") : chalk9.dim("\u25CB"));
12265
- }
12266
- return parts.join("");
12267
- }
12268
- function printExplainerCatalogLine(explainer) {
12269
- const kind = explainer.kind === "vital" ? paint("accent", "vital") : chalk9.dim("saas ");
12270
- console.log(
12271
- ` ${kind} ${bold(explainer.id.padEnd(20))} ${chalk9.dim(explainer.label)} \u2014 ${chalk9.dim(explainer.tagline)}`
12272
- );
12273
- }
12274
- function printGuideCatalogLine(slide) {
12275
- console.log(
12276
- ` ${paint("accent", "how ")} ${bold(slide.id.padEnd(20))} ${chalk9.dim(slide.label)} \u2014 ${chalk9.dim(slide.tagline)}`
12277
- );
12278
- }
12279
- function printDeepdiveHint(metricId, label) {
12280
- const name = label ?? metricId;
12281
- console.log(
12282
- " " + chalk9.dim("How this number works: ") + paint("accent", `/deepdive ${metricId}`) + chalk9.dim(` \u2014 ${name}`)
12283
- );
12284
- console.log();
12285
- }
12286
- var init_slides = __esm({
12287
- "src/ui/slides.ts"() {
12288
- "use strict";
12289
- init_theme();
12290
- init_layout();
12291
- }
12292
- });
12293
-
12294
12330
  // src/conversation/metric-tour.ts
12295
12331
  var metric_tour_exports = {};
12296
12332
  __export(metric_tour_exports, {
12297
12333
  METRICS_TOUR_MILESTONE_ID: () => METRICS_TOUR_MILESTONE_ID,
12298
12334
  describeTourDeck: () => describeTourDeck,
12335
+ firstRunTourDefaultChoice: () => firstRunTourDefaultChoice,
12299
12336
  getDeepdiveNudge: () => getDeepdiveNudge,
12300
12337
  hasAnalysisForDeepdiveNudge: () => hasAnalysisForDeepdiveNudge,
12301
12338
  hasCompletedMetricsTour: () => hasCompletedMetricsTour,
@@ -12343,6 +12380,7 @@ function hasAnalysisForDeepdiveNudge(ctx) {
12343
12380
  }
12344
12381
  }
12345
12382
  function getDeepdiveNudge(ctx) {
12383
+ if (!hasValidLicense()) return null;
12346
12384
  if (hasCompletedMetricsTour() || hasSeenDeepdiveHomeNudge()) return null;
12347
12385
  if (!hasAnalysisForDeepdiveNudge(ctx)) return null;
12348
12386
  return {
@@ -12622,6 +12660,9 @@ function printGuideCard(slideId, opts = {}) {
12622
12660
  });
12623
12661
  return true;
12624
12662
  }
12663
+ function firstRunTourDefaultChoice() {
12664
+ return loadProgress().milestones_unlocked.includes(METRICS_TOUR_MILESTONE_ID) ? "skip" : "tour";
12665
+ }
12625
12666
  async function offerFirstRunTour(ctx) {
12626
12667
  if (hasCompletedMetricsTour()) return false;
12627
12668
  console.log();
@@ -12629,6 +12670,10 @@ async function offerFirstRunTour(ctx) {
12629
12670
  console.log(
12630
12671
  " " + chalk10.dim("SaaS numbers, five vitals, then how to talk to NTRP and ship work to Claude.")
12631
12672
  );
12673
+ const tourDefault = firstRunTourDefaultChoice();
12674
+ if (tourDefault === "skip") {
12675
+ console.log(" " + chalk10.dim("You have taken this tour before."));
12676
+ }
12632
12677
  console.log();
12633
12678
  const session = createPromptSession(ctx.rl, ctx);
12634
12679
  try {
@@ -12646,7 +12691,7 @@ async function offerFirstRunTour(ctx) {
12646
12691
  description: "Re-open anytime with /deepdive or /deepdive guide"
12647
12692
  }
12648
12693
  ],
12649
- { default: "tour" }
12694
+ { default: tourDefault }
12650
12695
  );
12651
12696
  if (choice === "skip") {
12652
12697
  markMetricsTourSkipped();
@@ -12671,6 +12716,7 @@ var init_metric_tour = __esm({
12671
12716
  init_prompts();
12672
12717
  init_store();
12673
12718
  init_progress();
12719
+ init_activation();
12674
12720
  init_profile();
12675
12721
  init_metric_definitions();
12676
12722
  init_guide_slides();
@@ -15284,7 +15330,7 @@ var init_explore_mode = __esm({
15284
15330
 
15285
15331
  // src/conversation/recommended-action.ts
15286
15332
  function resolveRecommendedAction(ctx) {
15287
- if (!hasValidLicense()) return { submit: "/checkout", hint: "/checkout" };
15333
+ if (!hasValidLicense()) return { submit: "/activate", hint: "/activate" };
15288
15334
  const phase = resolveConversationPhase(ctx);
15289
15335
  switch (phase) {
15290
15336
  case "explore":
@@ -15298,6 +15344,8 @@ function resolveRecommendedAction(ctx) {
15298
15344
  return { submit: "yes", hint: "yes" };
15299
15345
  case "strategize":
15300
15346
  return ctx.strategistState?.step === "objective_confirm" ? { submit: "yes", hint: "yes" } : null;
15347
+ case "think":
15348
+ return null;
15301
15349
  default:
15302
15350
  return null;
15303
15351
  }
@@ -15332,6 +15380,9 @@ function resolveConversationPhase(ctx) {
15332
15380
  if (ctx.strategistState && ctx.strategistState.step !== "awaiting_analysis" && ctx.strategistState.step !== "awaiting_connect") {
15333
15381
  return "strategize";
15334
15382
  }
15383
+ if (ctx.thinkState?.step === "active") {
15384
+ return "think";
15385
+ }
15335
15386
  if (isAnalysisReady(ctx)) return "explore";
15336
15387
  const scope = ctx.scope;
15337
15388
  if (scope?.confirmed_at) {
@@ -15345,6 +15396,9 @@ function consumeOrientEmptyEnterCoach(ctx) {
15345
15396
  if (resolveConversationPhase(ctx) !== "orient") return null;
15346
15397
  if (ctx.orientEmptyEnterSeen) return null;
15347
15398
  ctx.orientEmptyEnterSeen = true;
15399
+ if (!hasValidLicense()) {
15400
+ return "Type /activate to paste a key. Type /checkout if you need to sign up.";
15401
+ }
15348
15402
  return "Type a question, type use demo data, or type /deepdive. Enter alone does not start a step here.";
15349
15403
  }
15350
15404
  function formatPhaseLabel(phase) {
@@ -15353,6 +15407,8 @@ function formatPhaseLabel(phase) {
15353
15407
  return "setup";
15354
15408
  case "explore":
15355
15409
  return "ready to ask";
15410
+ case "think":
15411
+ return "thinking together";
15356
15412
  default:
15357
15413
  return phase.replace(/_/g, " ");
15358
15414
  }
@@ -15371,8 +15427,14 @@ function buildConversationPrompt(ctx) {
15371
15427
  const modeTag = mode === "brief" ? "brief" : "deep";
15372
15428
  const stack = canUseReplAi(ctx) ? formatActiveStackShort(ctx) : "no engine";
15373
15429
  const strategyWait = ctx.strategistState?.step === "awaiting_connect" ? chalk11.dim(" \xB7 strategy after /connect") : "";
15430
+ const thinkWait = ctx.thinkState?.step === "awaiting_connect" ? chalk11.dim(" \xB7 think after /connect") : "";
15431
+ const enterHint2 = action ? chalk11.dim(` \xB7 \u23CE ${action.hint}`) : "";
15432
+ return paint("accent", `ask${scope} \u203A `) + chalk11.dim(`${modeTag} \xB7 ${stack}`) + strategyWait + thinkWait + enterHint2 + " ";
15433
+ }
15434
+ if (phase === "think") {
15435
+ const stack = canUseReplAi(ctx) ? formatActiveStackShort(ctx) : "no engine";
15374
15436
  const enterHint2 = action ? chalk11.dim(` \xB7 \u23CE ${action.hint}`) : "";
15375
- return paint("accent", `ask${scope} \u203A `) + chalk11.dim(`${modeTag} \xB7 ${stack}`) + strategyWait + enterHint2 + " ";
15437
+ return paint("accent", `think${scope} \u203A `) + chalk11.dim(stack) + enterHint2 + " ";
15376
15438
  }
15377
15439
  const enterHint = action ? chalk11.dim(`\u23CE ${action.hint} `) : "";
15378
15440
  return paint("accent", `${label.replace(" \u203A", "")}${scope} \u203A `) + enterHint;
@@ -15405,6 +15467,7 @@ var init_phase = __esm({
15405
15467
  init_explore_mode();
15406
15468
  init_session_state();
15407
15469
  init_theme();
15470
+ init_activation();
15408
15471
  init_recommended_action();
15409
15472
  PROMPT_LABELS = {
15410
15473
  orient: "\u203A",
@@ -15412,6 +15475,7 @@ var init_phase = __esm({
15412
15475
  awaiting_data: "data \u203A",
15413
15476
  compute: "\u2026",
15414
15477
  explore: "ask \u203A",
15478
+ think: "think \u203A",
15415
15479
  strategize: "strategy \u203A",
15416
15480
  deliver: "ship \u203A"
15417
15481
  };
@@ -19738,9 +19802,11 @@ var inbox_setup_exports = {};
19738
19802
  __export(inbox_setup_exports, {
19739
19803
  maybeOfferInboxOnProduction: () => maybeOfferInboxOnProduction,
19740
19804
  offerInboxSkillSetup: () => offerInboxSkillSetup,
19805
+ reuseInboxFolderIfPresent: () => reuseInboxFolderIfPresent,
19741
19806
  shouldOfferInboxSkillSetup: () => shouldOfferInboxSkillSetup
19742
19807
  });
19743
19808
  import chalk19 from "chalk";
19809
+ import { existsSync as existsSync22 } from "fs";
19744
19810
  function markDemoOffered() {
19745
19811
  setConfigValue("ai-inbox-nudge-seen", "true");
19746
19812
  }
@@ -19769,6 +19835,23 @@ function printSkipHint(beat) {
19769
19835
  " " + chalk19.dim("Skipped. NTRP will not ask again. Type ") + setCmd + chalk19.dim(" then ") + skillCmd + chalk19.dim(" at any time.")
19770
19836
  );
19771
19837
  }
19838
+ async function reuseInboxFolderIfPresent(session, beat, folderPath = defaultAiInboxDir()) {
19839
+ if (getAiInboxDir()) return false;
19840
+ if (!existsSync22(folderPath)) return false;
19841
+ console.log(" " + chalk19.dim("Pickup folder still on disk: ") + folderPath);
19842
+ const reuse = await session.confirm("Reuse this pickup folder?", true);
19843
+ if (!reuse) return false;
19844
+ const resolved = setAiInboxDir(folderPath);
19845
+ markDemoOffered();
19846
+ if (beat === "production") markProductionOffered();
19847
+ console.log();
19848
+ console.log(" " + paint("accent", "Inbox ready") + chalk19.dim(" ") + resolved);
19849
+ console.log(
19850
+ " " + chalk19.dim("Folder reused. Type ") + paint("accent", "/inbox skill") + chalk19.dim(" to print the finder again.")
19851
+ );
19852
+ console.log();
19853
+ return true;
19854
+ }
19772
19855
  async function offerInboxSkillSetup(session, opts = {}) {
19773
19856
  const beat = opts.beat ?? "production";
19774
19857
  if (!shouldOfferInboxSkillSetup(beat)) return;
@@ -19783,6 +19866,7 @@ async function offerInboxSkillSetup(session, opts = {}) {
19783
19866
  console.log(" " + chalk19.dim("You skipped this during demo."));
19784
19867
  }
19785
19868
  console.log();
19869
+ if (await reuseInboxFolderIfPresent(session, beat)) return;
19786
19870
  const want = await session.confirm("Set a pickup folder for Claude, ChatGPT, or Cursor?", true);
19787
19871
  if (!want) {
19788
19872
  if (beat === "demo") markDemoOffered();
@@ -19853,7 +19937,7 @@ __export(ingest_exports, {
19853
19937
  handler: () => handler2
19854
19938
  });
19855
19939
  import chalk20 from "chalk";
19856
- import { readFileSync as readFileSync19, existsSync as existsSync22 } from "fs";
19940
+ import { readFileSync as readFileSync19, existsSync as existsSync23 } from "fs";
19857
19941
  import { basename as basename6 } from "path";
19858
19942
  async function handler2(args, ctx) {
19859
19943
  const { positional, flags } = parseArgs2(args, [
@@ -19877,7 +19961,7 @@ async function handler2(args, ctx) {
19877
19961
  console.error(chalk20.dim(" /ingest --demo [--scenario <name>]"));
19878
19962
  process.exit(1);
19879
19963
  }
19880
- if (!existsSync22(file)) {
19964
+ if (!existsSync23(file)) {
19881
19965
  console.error(chalk20.red(` File not found: ${file}`));
19882
19966
  process.exit(1);
19883
19967
  }
@@ -20505,13 +20589,21 @@ function buildFreshNlTools() {
20505
20589
  if (isWebRetrievalEnabled()) tools.push(WEB_SEARCH_TOOL);
20506
20590
  return tools;
20507
20591
  }
20592
+ function buildThinkTools() {
20593
+ const tools = [
20594
+ ...AGENTIC_TOOLS,
20595
+ ...THINK_CHANNEL_TOOLS
20596
+ ];
20597
+ if (isWebRetrievalEnabled()) tools.push(WEB_SEARCH_TOOL);
20598
+ return tools;
20599
+ }
20508
20600
  function allRegisteredToolSchemas() {
20509
- return [...AGENTIC_TOOLS, ...CONVERSATION_TOOLS, WEB_SEARCH_TOOL];
20601
+ return [...AGENTIC_TOOLS, ...CONVERSATION_TOOLS, ...THINK_CHANNEL_TOOLS, WEB_SEARCH_TOOL];
20510
20602
  }
20511
20603
  function getToolSchema(name) {
20512
20604
  return allRegisteredToolSchemas().find((t) => t.name === name);
20513
20605
  }
20514
- var WEB_SEARCH_TOOL, CONVERSATION_TOOLS, AGENTIC_TOOLS;
20606
+ var WEB_SEARCH_TOOL, CONVERSATION_TOOLS, THINK_CHANNEL_TOOLS, AGENTIC_TOOLS;
20515
20607
  var init_tool_schemas = __esm({
20516
20608
  "src/ai/tool-schemas.ts"() {
20517
20609
  "use strict";
@@ -20588,6 +20680,64 @@ var init_tool_schemas = __esm({
20588
20680
  }
20589
20681
  }
20590
20682
  ];
20683
+ THINK_CHANNEL_TOOLS = [
20684
+ {
20685
+ name: "draft_handoff",
20686
+ description: "Draft a handoff prompt combining analysis numbers and conversation thread.",
20687
+ parameters: {
20688
+ type: "object",
20689
+ properties: {
20690
+ target: {
20691
+ type: "string",
20692
+ enum: ["deck", "asana", "clay", "plan"],
20693
+ description: "Deliverable type. Defaults to plan."
20694
+ }
20695
+ }
20696
+ }
20697
+ },
20698
+ {
20699
+ name: "draft_strategy",
20700
+ description: "Hand off to the strategist brain from the think channel when the user is ready to commit to a plan. Do not improvise a multi-week roadmap inline \u2014 call this instead.",
20701
+ parameters: {
20702
+ type: "object",
20703
+ properties: {
20704
+ objective: {
20705
+ type: "string",
20706
+ maxLength: 2e3,
20707
+ description: "The measurable objective to plan toward, in the user's terms."
20708
+ }
20709
+ },
20710
+ required: ["objective"]
20711
+ }
20712
+ },
20713
+ {
20714
+ name: "update_think_scratch",
20715
+ description: "Update the think-channel working scratch: open questions, challenged assumptions, and working hypotheses. Pass only the arrays you want to replace; omitted fields stay unchanged. Call when the conversation advances a question, surfaces a challenged assumption, or forms a hypothesis.",
20716
+ parameters: {
20717
+ type: "object",
20718
+ properties: {
20719
+ open_questions: {
20720
+ type: "array",
20721
+ items: { type: "string", maxLength: 500 },
20722
+ maxItems: 12,
20723
+ description: "Current open questions (replaces the list when provided)."
20724
+ },
20725
+ challenged_assumptions: {
20726
+ type: "array",
20727
+ items: { type: "string", maxLength: 500 },
20728
+ maxItems: 12,
20729
+ description: "Assumptions that have been pressure-tested (replaces when provided)."
20730
+ },
20731
+ working_hypotheses: {
20732
+ type: "array",
20733
+ items: { type: "string", maxLength: 500 },
20734
+ maxItems: 12,
20735
+ description: "Working hypotheses under consideration (replaces when provided)."
20736
+ }
20737
+ }
20738
+ }
20739
+ }
20740
+ ];
20591
20741
  AGENTIC_TOOLS = [
20592
20742
  {
20593
20743
  name: "get_health_summary",
@@ -21754,6 +21904,7 @@ async function handleDraftStrategy(input) {
21754
21904
  if (!objective) return { error: "objective is required." };
21755
21905
  if (!isAnalysisReady2(ctx)) {
21756
21906
  ctx.strategistState = { step: "awaiting_analysis", objective, origin: "ai" };
21907
+ if (ctx.thinkState) ctx.thinkState = void 0;
21757
21908
  saveSessionState2(ctx);
21758
21909
  return {
21759
21910
  queued: true,
@@ -21762,6 +21913,7 @@ async function handleDraftStrategy(input) {
21762
21913
  };
21763
21914
  }
21764
21915
  ctx.strategistState = { step: "objective_confirm", objective, origin: "ai" };
21916
+ if (ctx.thinkState) ctx.thinkState = void 0;
21765
21917
  saveSessionState2(ctx);
21766
21918
  return {
21767
21919
  launched: true,
@@ -21769,6 +21921,32 @@ async function handleDraftStrategy(input) {
21769
21921
  note: "Strategist handoff armed. After your reply the user sees an objective confirmation card and the engine runs a full grounding/backcast/stress-test session. Keep your reply to one or two sentences introducing the handoff \u2014 do NOT write the plan yourself."
21770
21922
  };
21771
21923
  }
21924
+ async function handleUpdateThinkScratch(input) {
21925
+ const { getAgentContext: getAgentContext2 } = await Promise.resolve().then(() => (init_agent_context(), agent_context_exports));
21926
+ const { saveSessionState: saveSessionState2 } = await Promise.resolve().then(() => (init_context2(), context_exports));
21927
+ const ctx = getAgentContext2();
21928
+ if (!ctx) return { error: "No active session context." };
21929
+ if (!ctx.thinkState || ctx.thinkState.step !== "active") {
21930
+ return { error: "Think channel is not active." };
21931
+ }
21932
+ const asStringList = (value) => {
21933
+ if (!Array.isArray(value)) return void 0;
21934
+ return value.filter((v) => typeof v === "string").map((s) => s.trim()).filter(Boolean).slice(0, 12);
21935
+ };
21936
+ const open = asStringList(input.open_questions);
21937
+ const challenged = asStringList(input.challenged_assumptions);
21938
+ const hypotheses = asStringList(input.working_hypotheses);
21939
+ if (open) ctx.thinkState.open_questions = open;
21940
+ if (challenged) ctx.thinkState.challenged_assumptions = challenged;
21941
+ if (hypotheses) ctx.thinkState.working_hypotheses = hypotheses;
21942
+ saveSessionState2(ctx);
21943
+ return {
21944
+ updated: true,
21945
+ open_questions: ctx.thinkState.open_questions ?? [],
21946
+ challenged_assumptions: ctx.thinkState.challenged_assumptions ?? [],
21947
+ working_hypotheses: ctx.thinkState.working_hypotheses ?? []
21948
+ };
21949
+ }
21772
21950
  async function handleGetSessionBrief(input) {
21773
21951
  const raw = typeof input.session_id === "string" ? input.session_id.trim() : "";
21774
21952
  if (!raw) return { error: "session_id is required." };
@@ -21783,9 +21961,9 @@ async function handleGetSessionBrief(input) {
21783
21961
  if (!target) {
21784
21962
  return { error: `No session matching "${raw}".` };
21785
21963
  }
21786
- const { existsSync: existsSync33, readFileSync: readFileSync24 } = await import("fs");
21964
+ const { existsSync: existsSync34, readFileSync: readFileSync24 } = await import("fs");
21787
21965
  const briefPath = contextDocPathForSession2(target.id);
21788
- if (!existsSync33(briefPath)) {
21966
+ if (!existsSync34(briefPath)) {
21789
21967
  return {
21790
21968
  session_id: target.id,
21791
21969
  error: "No context brief on disk for this session (created before brief storage existed).",
@@ -21818,8 +21996,8 @@ function boundResultJson(resultJson) {
21818
21996
  }
21819
21997
  async function executeToolCall(name, input, ctx, policy = {}) {
21820
21998
  const start = Date.now();
21821
- const handler49 = HANDLERS[name];
21822
- if (!handler49) {
21999
+ const handler50 = HANDLERS[name];
22000
+ if (!handler50) {
21823
22001
  const stopNote = policy.guard?.recordUnknownTool(name) ?? null;
21824
22002
  const resultJson2 = JSON.stringify(
21825
22003
  stopNote ? { error: `Unknown tool '${name}'`, guidance: stopNote } : { error: `Unknown tool '${name}'` }
@@ -21850,7 +22028,7 @@ async function executeToolCall(name, input, ctx, policy = {}) {
21850
22028
  auditDenied(name, input, resultJson2, start);
21851
22029
  return resultJson2;
21852
22030
  }
21853
- const rawResult = await handler49(input, ctx);
22031
+ const rawResult = await handler50(input, ctx);
21854
22032
  const safeResult = stripPII(rawResult);
21855
22033
  const withGuidance = loopVerdict.verdict === "warn" && safeResult && typeof safeResult === "object" && !Array.isArray(safeResult) ? { ...safeResult, loop_warning: loopVerdict.note } : safeResult;
21856
22034
  const resultJson = boundResultJson(JSON.stringify(withGuidance));
@@ -21894,7 +22072,8 @@ var init_tool_handlers = __esm({
21894
22072
  audit_data_gaps: (_, __) => handleAuditDataGaps(),
21895
22073
  run_compute: (_, __) => handleRunCompute(),
21896
22074
  draft_handoff: (input, _) => handleDraftHandoff(input),
21897
- draft_strategy: (input, _) => handleDraftStrategy(input)
22075
+ draft_strategy: (input, _) => handleDraftStrategy(input),
22076
+ update_think_scratch: (input, _) => handleUpdateThinkScratch(input)
21898
22077
  };
21899
22078
  }
21900
22079
  });
@@ -22043,8 +22222,171 @@ var init_thread = __esm({
22043
22222
  }
22044
22223
  });
22045
22224
 
22046
- // src/ai/agentic-loop.ts
22225
+ // src/ai/think-prompt.ts
22047
22226
  function companyContextSection2() {
22227
+ const block = buildCompanyProfileBlock();
22228
+ return block ? `COMPANY CONTEXT:
22229
+ ${block}
22230
+
22231
+ ` : "";
22232
+ }
22233
+ function operatorSection2() {
22234
+ const block = buildOperatorBlock();
22235
+ return block ? `${block}
22236
+
22237
+ ` : "";
22238
+ }
22239
+ function buildScratchBlock(state2) {
22240
+ if (!state2) return "";
22241
+ const lines = [];
22242
+ if (state2.seed) lines.push(`Seed topic: ${state2.seed}`);
22243
+ if (state2.open_questions?.length) {
22244
+ lines.push("Open questions:");
22245
+ for (const q of state2.open_questions) lines.push(`- ${q}`);
22246
+ }
22247
+ if (state2.challenged_assumptions?.length) {
22248
+ lines.push("Challenged assumptions:");
22249
+ for (const a of state2.challenged_assumptions) lines.push(`- ${a}`);
22250
+ }
22251
+ if (state2.working_hypotheses?.length) {
22252
+ lines.push("Working hypotheses:");
22253
+ for (const h of state2.working_hypotheses) lines.push(`- ${h}`);
22254
+ }
22255
+ if (lines.length === 0) return "";
22256
+ return `
22257
+ THINK SCRATCH (session working memory \u2014 update via update_think_scratch):
22258
+ ${lines.join("\n")}
22259
+ `;
22260
+ }
22261
+ function buildThinkWithMeSystemPrompt(opts = {}) {
22262
+ const sessionBlock = opts.sessionContext ? `
22263
+ PREVIOUS SESSION CONTEXT:
22264
+ The user resumed an earlier session. Here is what they were investigating before:
22265
+ ${opts.sessionContext}
22266
+ Treat this as already-established background. Pick up where it left off \u2014 do not re-introduce it as if it were new.
22267
+
22268
+ ` : "";
22269
+ const memorySection = opts.memoryBlock ? `
22270
+ WHAT YOU ALREADY KNOW ABOUT THIS BUSINESS (durable memory):
22271
+ ${opts.memoryBlock}
22272
+ Reference this naturally. Do not re-derive things you already know; build on them.
22273
+
22274
+ ` : "";
22275
+ const analysisSection = opts.analysisBlock ? `
22276
+ SESSION ANALYSIS CONTEXT:
22277
+ ${opts.analysisBlock}
22278
+ Use get_revenue_metrics and get_revenue_metrics_timeseries when the user asks about SaaS metrics, retention, or period trends.
22279
+
22280
+ ` : "";
22281
+ const artifactSection = opts.sessionArtifact ? `
22282
+ COMPLETED SESSION ANALYSIS:
22283
+ ${opts.sessionArtifact}
22284
+ Cite numbers from here; call tools when you need a new cut or to pressure-test a claim.
22285
+
22286
+ ` : "";
22287
+ const conversationSection = opts.conversationBlock ? `
22288
+ CONVERSATION STATE:
22289
+ ${opts.conversationBlock}
22290
+
22291
+ ` : "";
22292
+ const scratchSection = buildScratchBlock(opts.thinkState);
22293
+ const socraticCraft = `HOW YOU THINK WITH THE USER (socratic partner \u2014 not a search box, not a strategist):
22294
+ - You are a thinking partner. Prefer sharp questions that unlock the user's idea over dumping answers.
22295
+ - Protect imagination: give "what if" space before the smell-test \u2014 do not kill creativity in the first sentence.
22296
+ - Steelman the user's position before you attack it; then deliver one hard pushback grounded in evidence when possible.
22297
+ - Ground claims about THIS pipeline in tool results. Label speculation explicitly ("hypothesis:", "speculation:").
22298
+ - Each turn should ADVANCE the thread: a new question, a challenge, a synthesis, or a fork \u2014 never rehash.
22299
+ - If the question is ambiguous, ask at most ONE clarifying question. Otherwise choose a fork and state it.
22300
+ - Never invent a multi-week roadmap inline. When they want commitment, call draft_strategy with a crisp objective.
22301
+ - Keep open_questions, challenged_assumptions, and working_hypotheses current via update_think_scratch.
22302
+ - You have continuity via prior think-channel messages. Never repeat an angle already covered unless asked.`;
22303
+ const jobSection = `YOUR JOB (THINK CHANNEL \u2014 always deep):
22304
+ - Decide whether you need tools, a direct answer, or both. Do not re-call a tool whose result you already have.
22305
+ - Lead with the answer or the question that matters most, then structure.
22306
+ - When you use numbers, include dollar values where available and lead with financial impact.
22307
+ - Descriptive exploration stays in this channel; plan-of-attack questions hand off via draft_strategy.
22308
+ - After a successful draft_strategy tool result: reply with at most 1\u20132 sentences introducing the handoff. Do not write the plan.`;
22309
+ const formattingSection = `
22310
+ FORMATTING (your answer is rendered in a terminal via a small markdown renderer):
22311
+ - Use **bold** for every dollar figure, score, play name, and person name.
22312
+ - Use *italics* for conversational asides and your closing follow-up question.
22313
+ - Use ### for section headings \u2014 never # or ##. The renderer flattens depth.
22314
+ - For multi-point answers, prefer a one-line lead + bullet list over long paragraph blocks.
22315
+ - Keep paragraphs to 3-4 sentences.
22316
+ - Prefer short tables (\u22643 columns, \u22645 rows, cells \u226430 chars).
22317
+ - End with a dim horizontal rule (---) followed by one italicized follow-up question or fork.
22318
+
22319
+ ${USER_VISIBLE_STE_BLOCK}
22320
+ `;
22321
+ const commandSection = `PRESET COMMANDS (slash commands the user can type \u2014 you may SUGGEST these; you cannot run them):
22322
+ ${buildCommandCatalogBlock()}
22323
+
22324
+ COMMAND SUGGESTION RULES:
22325
+ - Suggest at most ONE command when it adds capability beyond your answer (e.g. \`/strategy\`, \`/handoff\`).
22326
+ - Never claim a command was run. Never invent flags.
22327
+ - Type \`done\` or \`cancel\` leaves the think channel back to ask \u203A.`;
22328
+ const stable = `You are a world-class GTM operating partner in a dedicated THINK WITH ME channel. The user wants collaborative exploration \u2014 imagination, pressure-testing, and evidence \u2014 not a slide deck and not a finished strategy plan.
22329
+
22330
+ ${companyContextSection2()}${operatorSection2()}${socraticCraft}
22331
+
22332
+ ANALYST INSTINCT (judgment a CEO pays for \u2014 apply by default):
22333
+ ${ANALYST_INSTINCT_BLOCK}
22334
+
22335
+ ${jobSection}
22336
+
22337
+ EXECUTION BIAS (how you work):
22338
+ ${EXECUTION_BIAS_BLOCK}
22339
+
22340
+ GTM ENGINEERING (how recommendations become systems):
22341
+ ${GTM_ENGINEERING_BLOCK}
22342
+
22343
+ OUTPUT DOCTRINE (how answers are structured for recall):
22344
+ ${PYRAMID_OUTPUT_BLOCK}
22345
+
22346
+ ${USER_VISIBLE_STE_BLOCK}
22347
+
22348
+ CONTEXT:
22349
+ The user's health scores and top divergences were included as JSON at the start of this conversation. Use them, the think-channel history, and SESSION STATE as background and as hints for which tools to call.
22350
+
22351
+ VITAL SIGNS EXPLAINED (with dollar translations):
22352
+ ${VITAL_SIGNS_BLOCK}
22353
+
22354
+ PLAYBOOK \u2014 name a play when it helps the user act (not a full program):
22355
+ ${buildPlaybookBlock()}
22356
+
22357
+ ${commandSection}
22358
+ ${formattingSection}
22359
+ OUTPUT RULES:
22360
+ - Respond in plain text markdown (not JSON). You do NOT need to emit the findings schema.
22361
+ - Include specific numbers from tool results, never guess.
22362
+ - When you have enough information, answer or ask \u2014 don't call tools you don't need.
22363
+
22364
+ SAFETY & EVIDENCE (non-negotiable):
22365
+ ${SAFETY_BLOCK}`;
22366
+ const dynamicSections = [
22367
+ sessionBlock,
22368
+ memorySection,
22369
+ analysisSection,
22370
+ artifactSection,
22371
+ conversationSection,
22372
+ scratchSection
22373
+ ].map((s) => s.trim()).filter(Boolean);
22374
+ const dynamic = [
22375
+ "SESSION STATE (current \u2014 changes as the session progresses):",
22376
+ ...dynamicSections,
22377
+ buildRuntimeBlock()
22378
+ ].join("\n\n");
22379
+ return { stable, dynamic };
22380
+ }
22381
+ var init_think_prompt = __esm({
22382
+ "src/ai/think-prompt.ts"() {
22383
+ "use strict";
22384
+ init_prompt_parts();
22385
+ }
22386
+ });
22387
+
22388
+ // src/ai/agentic-loop.ts
22389
+ function companyContextSection3() {
22048
22390
  const block = buildCompanyProfileBlock();
22049
22391
  if (!block) return "";
22050
22392
  return `COMPANY CONTEXT (use this to make every answer specific to the business \u2014 use industry-appropriate language, anchor dollar figures to their deal size):
@@ -22052,7 +22394,7 @@ ${block}
22052
22394
 
22053
22395
  `;
22054
22396
  }
22055
- function operatorSection2() {
22397
+ function operatorSection3() {
22056
22398
  const block = buildOperatorBlock();
22057
22399
  if (!block) return "";
22058
22400
  return `${block}
@@ -22062,7 +22404,7 @@ function operatorSection2() {
22062
22404
  function buildSystemPrompt() {
22063
22405
  const stable = `You are an expert GTM health investigator. You have tools to query a local database of CRM and pipeline data. Your job is to investigate the health scores you've been given and discover the specific root causes behind any problems.
22064
22406
 
22065
- ${companyContextSection2()}${operatorSection2()}INVESTIGATION APPROACH:
22407
+ ${companyContextSection3()}${operatorSection3()}INVESTIGATION APPROACH:
22066
22408
  1. Start by examining the health summary to understand the overall picture
22067
22409
  2. Drill into the lowest-scoring vital signs using get_vital_sign_detail
22068
22410
  3. Check divergences to find segments that are significantly worse than average
@@ -22251,7 +22593,7 @@ ${buildPlaybookBlock()}
22251
22593
  ${commandSection}`;
22252
22594
  const stable = `You are a world-class GTM operating partner \u2014 the kind of analyst a CEO keeps on speed dial. You are exceptionally well-read, rigorous, and commercially sharp, and you have tools to query a local database of this company's CRM and pipeline data. The user is having an ongoing, free-form conversation with you about their go-to-market health and SaaS metrics.
22253
22595
 
22254
- ${companyContextSection2()}${operatorSection2()}${conversationRules}
22596
+ ${companyContextSection3()}${operatorSection3()}${conversationRules}
22255
22597
 
22256
22598
  ${analystSection}
22257
22599
 
@@ -22297,20 +22639,27 @@ async function* agenticFindings(computeResult, divergences, options) {
22297
22639
  assertReplAi(options.ctx);
22298
22640
  const mode = options.mode ?? "investigation";
22299
22641
  const experiment = options.experiment ?? "production";
22300
- const responseMode = experiment === "baseline" || experiment === "a" || experiment === "b" ? "deep" : options.responseMode ?? (options.sessionArtifact ? "brief" : "deep");
22301
- const useTools = mode === "investigation" || responseMode === "deep";
22642
+ const responseMode = mode === "think" ? "deep" : experiment === "baseline" || experiment === "a" || experiment === "b" ? "deep" : options.responseMode ?? (options.sessionArtifact ? "brief" : "deep");
22643
+ const useTools = mode === "investigation" || mode === "think" || responseMode === "deep";
22302
22644
  const maxTokens = mode === "fresh" && responseMode === "brief" ? BRIEF_MAX_TOKENS : DEEP_MAX_TOKENS;
22303
22645
  const surface = mode === "fresh" ? responseMode === "brief" ? "agentic_fresh_brief" : "agentic_investigation" : "agentic_investigation";
22304
22646
  const llmCfg = loadLlmConfig();
22305
22647
  const tier = tierForSurface(surface, llmCfg.tier);
22306
- const systemPrompt = mode === "fresh" ? buildFreshNlSystemPrompt(
22648
+ const systemPrompt = mode === "think" ? buildThinkWithMeSystemPrompt({
22649
+ sessionContext: options.sessionContext,
22650
+ memoryBlock: options.memoryBlock,
22651
+ analysisBlock: options.analysisBlock,
22652
+ conversationBlock: options.conversationBlock,
22653
+ sessionArtifact: options.sessionArtifact,
22654
+ thinkState: options.ctx.thinkState
22655
+ }) : mode === "fresh" ? buildFreshNlSystemPrompt(
22307
22656
  options.sessionContext,
22308
22657
  options.memoryBlock,
22309
22658
  options.analysisBlock,
22310
22659
  options.conversationBlock,
22311
22660
  { responseMode, sessionArtifact: options.sessionArtifact, experiment }
22312
22661
  ) : buildSystemPrompt();
22313
- const tools = useTools ? mode === "fresh" ? buildFreshNlTools() : buildInvestigationTools() : [];
22662
+ const tools = useTools ? mode === "think" ? buildThinkTools() : mode === "fresh" ? buildFreshNlTools() : buildInvestigationTools() : [];
22314
22663
  const toolCtx = { computeResult, divergences };
22315
22664
  if (options.includeMetrics) {
22316
22665
  try {
@@ -22322,7 +22671,8 @@ async function* agenticFindings(computeResult, divergences, options) {
22322
22671
  const initialContext = buildInitialContext(computeResult, divergences, options.userQuestion);
22323
22672
  const priorRaw = options.priorMessages ?? [];
22324
22673
  const priorMessages = priorRaw.length > 0 && typeof priorRaw[0] === "object" && priorRaw[0] !== null && "content" in priorRaw[0] ? normalizeThread(priorRaw) : priorRaw;
22325
- const messages = mode === "fresh" && priorMessages.length > 0 && options.userQuestion ? [...priorMessages, { role: "user", content: options.userQuestion }] : [{ role: "user", content: initialContext }];
22674
+ const conversational = mode === "fresh" || mode === "think";
22675
+ const messages = conversational && priorMessages.length > 0 && options.userQuestion ? [...priorMessages, { role: "user", content: options.userQuestion }] : [{ role: "user", content: initialContext }];
22326
22676
  let lastMeta = { provider_used: "anthropic", model_used: "unknown" };
22327
22677
  const loopGuard = new ToolLoopGuard();
22328
22678
  const allowedTools = new Set(tools.map((t) => t.name));
@@ -22352,7 +22702,7 @@ async function* agenticFindings(computeResult, divergences, options) {
22352
22702
  const response = await callLlm(messages, maxTokens, true);
22353
22703
  if (response.tool_calls.length === 0) {
22354
22704
  const fullText = response.text;
22355
- if (mode === "fresh") {
22705
+ if (conversational) {
22356
22706
  const findings3 = parseFindings(fullText);
22357
22707
  if (findings3.length > 0) {
22358
22708
  for (const finding of findings3) yield { type: "finding", finding };
@@ -22400,7 +22750,7 @@ async function* agenticFindings(computeResult, divergences, options) {
22400
22750
  });
22401
22751
  }
22402
22752
  }
22403
- if (mode === "fresh") {
22753
+ if (conversational) {
22404
22754
  messages.push({
22405
22755
  role: "user",
22406
22756
  content: "You've reached the tool budget. Please answer the user's question now with what you've learned."
@@ -22476,6 +22826,7 @@ var init_agentic_loop = __esm({
22476
22826
  init_thread();
22477
22827
  init_untrusted();
22478
22828
  init_prompt_parts();
22829
+ init_think_prompt();
22479
22830
  MAX_ITERATIONS = 10;
22480
22831
  INVESTIGATION_EVIDENCE_NUDGE_AFTER = 5;
22481
22832
  BRIEF_MAX_TOKENS = 768;
@@ -24192,7 +24543,7 @@ __export(new_exports, {
24192
24543
  handler: () => handler6
24193
24544
  });
24194
24545
  import chalk25 from "chalk";
24195
- import { existsSync as existsSync23 } from "fs";
24546
+ import { existsSync as existsSync24 } from "fs";
24196
24547
  import { basename as basename7 } from "path";
24197
24548
  async function handler6(args, ctx) {
24198
24549
  const { positional, flags } = parseArgs2(args, ["demo", "empty", "list-scenarios", "regen-taxonomy"]);
@@ -24214,7 +24565,7 @@ async function handler6(args, ctx) {
24214
24565
  console.error(chalk25.red(" Usage: /new <file.csv> | --demo [--scenario <name>] | --empty [--lens health|metrics]"));
24215
24566
  return;
24216
24567
  }
24217
- if (source.kind === "file" && !existsSync23(source.path)) {
24568
+ if (source.kind === "file" && !existsSync24(source.path)) {
24218
24569
  console.error(chalk25.red(` File not found: ${source.path}`));
24219
24570
  return;
24220
24571
  }
@@ -24441,7 +24792,7 @@ __export(end_exports, {
24441
24792
  handler: () => handler7
24442
24793
  });
24443
24794
  import chalk26 from "chalk";
24444
- import { existsSync as existsSync24 } from "fs";
24795
+ import { existsSync as existsSync25 } from "fs";
24445
24796
  async function handler7(args, ctx) {
24446
24797
  if (args.length > 0) {
24447
24798
  console.error(chalk26.red(" Usage: /end"));
@@ -24478,10 +24829,10 @@ async function handler7(args, ctx) {
24478
24829
  if (summary) {
24479
24830
  console.log(" " + chalk26.dim(summary));
24480
24831
  }
24481
- if (existsSync24(transcriptPathForSession(endedId))) {
24832
+ if (existsSync25(transcriptPathForSession(endedId))) {
24482
24833
  console.log(" " + chalk26.dim("Transcript: ") + chalk26.dim(transcriptPathForSession(endedId)));
24483
24834
  }
24484
- if (existsSync24(contextDocPathForSession(endedId))) {
24835
+ if (existsSync25(contextDocPathForSession(endedId))) {
24485
24836
  console.log(" " + chalk26.dim("Context brief: ") + chalk26.dim(contextDocPathForSession(endedId)));
24486
24837
  }
24487
24838
  console.log();
@@ -24503,7 +24854,7 @@ __export(session_exports, {
24503
24854
  });
24504
24855
  import chalk27 from "chalk";
24505
24856
  import { join as join23 } from "path";
24506
- import { existsSync as existsSync25 } from "fs";
24857
+ import { existsSync as existsSync26 } from "fs";
24507
24858
  async function handler8(args, ctx) {
24508
24859
  const sub = args[0];
24509
24860
  if (!sub) return listSessionsView(ctx);
@@ -24610,6 +24961,7 @@ async function pickUp(idArg, ctx) {
24610
24961
  sessionName: session.name,
24611
24962
  messages: [...session.messages],
24612
24963
  conversation: session.thread ? [...session.thread] : [],
24964
+ thinkConversation: session.think_thread ? [...session.think_thread] : [],
24613
24965
  resumedSessionSummary: session.summary,
24614
24966
  stage: session.stage ?? (session.messages.length > 0 ? "analyzed" : "new"),
24615
24967
  dataset: session.dataset,
@@ -24619,6 +24971,7 @@ async function pickUp(idArg, ctx) {
24619
24971
  attachments: session.attachments,
24620
24972
  llm: session.llm ? { ...session.llm } : void 0,
24621
24973
  strategistState: session.strategist,
24974
+ thinkState: session.think,
24622
24975
  pendingAsk: session.pending_ask
24623
24976
  });
24624
24977
  ctx.datasetPath = datasetPathForSession(target.id);
@@ -24640,8 +24993,14 @@ async function pickUp(idArg, ctx) {
24640
24993
  " " + chalk27.yellow("Resuming mid-strategy") + (objective ? chalk27.dim(`: "${objective}"`) : "") + chalk27.dim(" \u2014 say ") + chalk27.cyan("yes") + chalk27.dim(" to continue or ") + chalk27.cyan("cancel") + chalk27.dim(" to drop it.")
24641
24994
  );
24642
24995
  }
24996
+ if (session.think && session.think.step === "active") {
24997
+ const seed = session.think.seed;
24998
+ console.log(
24999
+ " " + chalk27.yellow("Resuming think channel") + (seed ? chalk27.dim(`: "${seed}"`) : "") + chalk27.dim(" \u2014 keep exploring or type ") + chalk27.cyan("done") + chalk27.dim(" / ") + chalk27.cyan("cancel") + chalk27.dim(" to leave.")
25000
+ );
25001
+ }
24643
25002
  const contextPath = contextDocPathForSession(target.id);
24644
- if (existsSync25(contextPath)) {
25003
+ if (existsSync26(contextPath)) {
24645
25004
  console.log(" " + chalk27.dim("Context brief: ") + chalk27.dim(contextPath));
24646
25005
  }
24647
25006
  console.log();
@@ -27144,7 +27503,7 @@ var init_strategist = __esm({
27144
27503
  });
27145
27504
 
27146
27505
  // src/ai/strategist-prompt.ts
27147
- function companyContextSection3() {
27506
+ function companyContextSection4() {
27148
27507
  const block = buildCompanyProfileBlock();
27149
27508
  if (!block) return "";
27150
27509
  return `COMPANY CONTEXT (ground every constraint, timeline, and dollar figure in this business):
@@ -27152,7 +27511,7 @@ ${block}
27152
27511
 
27153
27512
  `;
27154
27513
  }
27155
- function operatorSection3() {
27514
+ function operatorSection4() {
27156
27515
  const block = buildOperatorBlock();
27157
27516
  if (!block) return "";
27158
27517
  return `${block}
@@ -27164,7 +27523,7 @@ function buildStrategistSystemPrompt(todayIso) {
27164
27523
 
27165
27524
  Today's date is ${todayIso}. All milestone and check dates must be real future calendar dates computed from today.
27166
27525
 
27167
- ${companyContextSection3()}${operatorSection3()}HOW YOU THINK (the strategist method \u2014 reverse operator thinking):
27526
+ ${companyContextSection4()}${operatorSection4()}HOW YOU THINK (the strategist method \u2014 reverse operator thinking):
27168
27527
  1. DEFINE THE DESTINATION. A strategy starts from a measurable objective, not from a list of problems.
27169
27528
  2. GROUND IN VERIFIED REALITY. Every number you use must come from a tool call or provided context. If you didn't verify it, it is an assumption and must be labeled as one.
27170
27529
  3. BACKCAST THE DEPENDENCY CHAIN. Work backwards from the objective: what must be true immediately before it holds? And before that? Sequence by dependency, not by severity.
@@ -30053,13 +30412,36 @@ __export(activate_exports, {
30053
30412
  handler: () => handler23
30054
30413
  });
30055
30414
  import chalk45 from "chalk";
30415
+ async function afterLicenseSuccess(ctx) {
30416
+ if (ctx.oneShot) return;
30417
+ const { resumeSetupAfterLicense: resumeSetupAfterLicense2 } = await Promise.resolve().then(() => (init_first_run(), first_run_exports));
30418
+ await resumeSetupAfterLicense2(ctx);
30419
+ }
30056
30420
  async function handler23(args, ctx) {
30057
30421
  const { positional } = parseArgs2(args);
30058
30422
  const key = positional[0];
30059
30423
  if (!key) {
30060
- console.error(chalk45.red("\n Usage: /activate <key>"));
30061
- console.error(chalk45.dim(" Or type /upgrade for checkout + paste flow.\n"));
30062
- if (ctx.oneShot) process.exit(1);
30424
+ if (ctx.oneShot || !process.stdin.isTTY) {
30425
+ console.error(chalk45.red("\n Usage: /activate <key>"));
30426
+ console.error(chalk45.dim(" Or type /activate in ntrp to paste a key.\n"));
30427
+ if (ctx.oneShot) process.exit(1);
30428
+ return;
30429
+ }
30430
+ if (hasValidLicense()) {
30431
+ console.log();
30432
+ console.log(chalk45.green(" A license is already active."));
30433
+ console.log();
30434
+ await afterLicenseSuccess(ctx);
30435
+ return;
30436
+ }
30437
+ console.log();
30438
+ console.log(
30439
+ " " + chalk45.dim("Paste a trial key or a Pro key. Type ") + paint("accent", "/checkout") + chalk45.dim(" if you need to sign up.")
30440
+ );
30441
+ console.log();
30442
+ const activated = await promptForLicenseKey(ctx);
30443
+ if (!activated) return;
30444
+ await afterLicenseSuccess(ctx);
30063
30445
  return;
30064
30446
  }
30065
30447
  try {
@@ -30074,10 +30456,7 @@ async function handler23(args, ctx) {
30074
30456
  console.log(chalk45.green(`
30075
30457
  License activated: ${result.message}
30076
30458
  `));
30077
- if (!ctx.oneShot) {
30078
- const { replayPendingBlockedLine: replayPendingBlockedLine2 } = await Promise.resolve().then(() => (init_dispatch(), dispatch_exports));
30079
- await replayPendingBlockedLine2(ctx);
30080
- }
30459
+ await afterLicenseSuccess(ctx);
30081
30460
  } catch (err) {
30082
30461
  const message = err instanceof Error ? err.message : "License activation failed";
30083
30462
  console.error(chalk45.red(`
@@ -30092,6 +30471,9 @@ var init_activate = __esm({
30092
30471
  "use strict";
30093
30472
  init_verify();
30094
30473
  init_argparse();
30474
+ init_activation();
30475
+ init_upgrade();
30476
+ init_theme();
30095
30477
  }
30096
30478
  });
30097
30479
 
@@ -30130,8 +30512,8 @@ async function handler24(args, ctx) {
30130
30512
  return;
30131
30513
  }
30132
30514
  if (!ctx.oneShot) {
30133
- const { replayPendingBlockedLine: replayPendingBlockedLine2 } = await Promise.resolve().then(() => (init_dispatch(), dispatch_exports));
30134
- await replayPendingBlockedLine2(ctx);
30515
+ const { resumeSetupAfterLicense: resumeSetupAfterLicense2 } = await Promise.resolve().then(() => (init_first_run(), first_run_exports));
30516
+ await resumeSetupAfterLicense2(ctx);
30135
30517
  }
30136
30518
  }
30137
30519
  var init_upgrade2 = __esm({
@@ -30159,7 +30541,7 @@ var init_checkout = __esm({
30159
30541
  });
30160
30542
 
30161
30543
  // src/services/setup.ts
30162
- import { existsSync as existsSync26, mkdirSync as mkdirSync17, readFileSync as readFileSync20, writeFileSync as writeFileSync19 } from "fs";
30544
+ import { existsSync as existsSync27, mkdirSync as mkdirSync17, readFileSync as readFileSync20, writeFileSync as writeFileSync19 } from "fs";
30163
30545
  import { join as join29 } from "path";
30164
30546
  function setupCheck() {
30165
30547
  const home = ntrpHome();
@@ -32157,7 +32539,7 @@ __export(sessions_exports, {
32157
32539
  handler: () => handler35
32158
32540
  });
32159
32541
  import chalk61 from "chalk";
32160
- import { existsSync as existsSync27 } from "fs";
32542
+ import { existsSync as existsSync28 } from "fs";
32161
32543
  async function handler35(args, _ctx) {
32162
32544
  const sub = args[0] ?? "list";
32163
32545
  if (sub === "list" || !args[0]) {
@@ -32264,12 +32646,12 @@ function showSession(idArg) {
32264
32646
  console.log();
32265
32647
  const transcriptPath = transcriptPathForSession(session.id);
32266
32648
  const contextPath = contextDocPathForSession(session.id);
32267
- if (existsSync27(transcriptPath) || existsSync27(contextPath)) {
32649
+ if (existsSync28(transcriptPath) || existsSync28(contextPath)) {
32268
32650
  console.log(" " + chalk61.dim("\u2500".repeat(40)));
32269
- if (existsSync27(contextPath)) {
32651
+ if (existsSync28(contextPath)) {
32270
32652
  console.log(" " + chalk61.dim("Context brief: ") + chalk61.dim(contextPath));
32271
32653
  }
32272
- if (existsSync27(transcriptPath)) {
32654
+ if (existsSync28(transcriptPath)) {
32273
32655
  console.log(" " + chalk61.dim("Full transcript: ") + chalk61.dim(transcriptPath));
32274
32656
  }
32275
32657
  console.log();
@@ -32549,39 +32931,368 @@ var init_privacy_notice = __esm({
32549
32931
  }
32550
32932
  });
32551
32933
 
32934
+ // src/services/think.ts
32935
+ var think_exports = {};
32936
+ __export(think_exports, {
32937
+ runThinkTurn: () => runThinkTurn
32938
+ });
32939
+ import chalk65 from "chalk";
32940
+ async function runThinkTurn(input, ctx) {
32941
+ assertReplAi(ctx);
32942
+ let snapshot = ctx.snapshot.computeResult;
32943
+ if (!snapshot) {
32944
+ const metricsFirst = prefersMetricsFirstContext(ctx);
32945
+ const spinner2 = makeSpinner(metricsFirst ? "Loading session context\u2026" : "Computing vital signs\u2026");
32946
+ try {
32947
+ snapshot = await computeFullHealth();
32948
+ ctx.snapshot.computeResult = snapshot;
32949
+ const divInput = snapshot.segments.map((s) => ({
32950
+ segmentId: s.segment.id,
32951
+ segmentName: s.segment.name,
32952
+ result: s.result
32953
+ }));
32954
+ ctx.snapshot.divergences = detectDivergences(snapshot.aggregate, divInput).divergences;
32955
+ spinner2.succeed(metricsFirst ? "Session context ready" : "Health snapshot ready");
32956
+ } catch (err) {
32957
+ spinner2.fail("Could not compute health snapshot");
32958
+ console.error(" " + chalk65.red(String(err.message ?? err)));
32959
+ console.log(" " + chalk65.dim("Run ") + paint("accent", "/new") + chalk65.dim(" \u2192 pick Demo to load sample data."));
32960
+ console.log();
32961
+ return;
32962
+ }
32963
+ }
32964
+ console.log();
32965
+ const memoryBlock = await buildMemoryBlock(input).catch(() => "");
32966
+ const spinner = makeSpinner("Thinking with you\u2026");
32967
+ let lastAnswer = "";
32968
+ let rawHistory = [];
32969
+ const toolsUsed = [];
32970
+ setAgentContext(ctx);
32971
+ try {
32972
+ const analysisBlock = buildAnalysisBlock(ctx);
32973
+ const conversationBlock = getConversationPhaseBlock(ctx);
32974
+ const bundle = await loadSessionAnalysisBundle();
32975
+ const sessionArtifact = hasAnyAnalysis(bundle) ? buildExploreContextBlock(bundle, ctx) : "";
32976
+ for await (const event of agenticFindings(snapshot, ctx.snapshot.divergences, {
32977
+ mode: "think",
32978
+ userQuestion: input,
32979
+ sessionContext: ctx.resumedSessionSummary,
32980
+ includeMetrics: true,
32981
+ analysisBlock,
32982
+ conversationBlock,
32983
+ sessionArtifact,
32984
+ priorMessages: ctx.thinkConversation,
32985
+ memoryBlock,
32986
+ ctx
32987
+ })) {
32988
+ switch (event.type) {
32989
+ case "tool_call":
32990
+ toolsUsed.push(event.name);
32991
+ spinner.text = `Querying ${event.name}\u2026`;
32992
+ break;
32993
+ case "thinking":
32994
+ spinner.stop();
32995
+ console.log(" " + chalk65.dim.italic(event.text));
32996
+ spinner.start("Thinking with you\u2026");
32997
+ break;
32998
+ case "answer":
32999
+ spinner.stop();
33000
+ lastAnswer = event.text;
33001
+ printMarkdown(event.text, { indent: 2 });
33002
+ break;
33003
+ case "finding":
33004
+ spinner.stop();
33005
+ printFindingInline2(event.finding);
33006
+ break;
33007
+ case "done":
33008
+ spinner.stop();
33009
+ rawHistory = event.conversation_history;
33010
+ break;
33011
+ }
33012
+ }
33013
+ } catch (err) {
33014
+ spinner.fail("Error while thinking");
33015
+ console.error(" " + chalk65.red(String(err.message ?? err)));
33016
+ console.log();
33017
+ return;
33018
+ } finally {
33019
+ setAgentContext(null);
33020
+ }
33021
+ if (rawHistory.length > 0) {
33022
+ ctx.thinkConversation = distillThread(rawHistory);
33023
+ }
33024
+ if (!lastAnswer) {
33025
+ console.log(" " + chalk65.dim("(no answer returned)"));
33026
+ } else {
33027
+ recordMessage(ctx, "agent", lastAnswer);
33028
+ saveSessionState(ctx);
33029
+ creditNlAnswer(ctx, Math.floor(ctx.messages.length / 2));
33030
+ recordAnalysis({
33031
+ question: `[think] ${input}`,
33032
+ answer: lastAnswer,
33033
+ tools: toolsUsed,
33034
+ session_id: ctx.sessionId
33035
+ });
33036
+ ctx.lastExchange = { question: input, answer: lastAnswer };
33037
+ }
33038
+ console.log();
33039
+ return lastAnswer ? extractSummary2(lastAnswer) : void 0;
33040
+ }
33041
+ function extractSummary2(text) {
33042
+ const plain = text.replace(/#{1,6}\s+/g, "").replace(/\*\*([^*]+)\*\*/g, "$1").replace(/\*([^*]+)\*/g, "$1").replace(/`([^`]+)`/g, "$1").replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/^[-*]\s+/gm, "").trim();
33043
+ const sentenceMatch = plain.match(/^(.+?[.!?])(?:\s|$)/);
33044
+ const sentence = sentenceMatch ? sentenceMatch[1] : plain.split("\n")[0];
33045
+ if (sentence.length <= 60) return sentence;
33046
+ return sentence.slice(0, 60).replace(/\s+\S*$/, "") + "\u2026";
33047
+ }
33048
+ function printFindingInline2(finding) {
33049
+ const sev = finding.severity;
33050
+ console.log();
33051
+ console.log(
33052
+ " " + severityPaint(sev)(sev.toUpperCase()) + " " + (finding.finding ?? "").slice(0, 120)
33053
+ );
33054
+ }
33055
+ var init_think = __esm({
33056
+ "src/services/think.ts"() {
33057
+ "use strict";
33058
+ init_spinner();
33059
+ init_context2();
33060
+ init_phase();
33061
+ init_agent_context();
33062
+ init_agentic_loop();
33063
+ init_thread();
33064
+ init_store2();
33065
+ init_health_score();
33066
+ init_divergence();
33067
+ init_repl_api();
33068
+ init_theme();
33069
+ init_markdown();
33070
+ init_session_analysis();
33071
+ init_time_bank();
33072
+ }
33073
+ });
33074
+
33075
+ // src/conversation/think-flow.ts
33076
+ var think_flow_exports = {};
33077
+ __export(think_flow_exports, {
33078
+ clearThinkFlow: () => clearThinkFlow,
33079
+ extractThinkSeed: () => extractThinkSeed,
33080
+ handleThinkFlow: () => handleThinkFlow,
33081
+ isThinkIntent: () => isThinkIntent,
33082
+ queueThinkForAnalysis: () => queueThinkForAnalysis,
33083
+ resumeThinkAfterCompute: () => resumeThinkAfterCompute,
33084
+ resumeThinkAfterConnect: () => resumeThinkAfterConnect,
33085
+ startThinkFlow: () => startThinkFlow
33086
+ });
33087
+ import chalk66 from "chalk";
33088
+ function isThinkIntent(input) {
33089
+ const line = input.trim();
33090
+ if (!line) return false;
33091
+ if (isShipIntent(line)) return false;
33092
+ if (isStrategistIntent(line)) return false;
33093
+ return THINK_INTENT_RE.test(line);
33094
+ }
33095
+ function extractThinkSeed(input) {
33096
+ const cleaned = input.trim().replace(/^(hey|ok|okay|please|can you|could you|help me|let'?s|i want to|i'?d like to)\s+/i, "").replace(/^(think\s+with\s+me|pressure[- ]?test|dig\s+into|think\s+through)\s*(about|on|around|this|:)?\s*/i, "").replace(/^(what\s+am\s+i\s+missing\s*(about|on|with|here)?)\s*/i, "").trim();
33097
+ return cleaned.length >= 4 ? cleaned : input.trim();
33098
+ }
33099
+ function queueThinkForAnalysis(ctx, opts) {
33100
+ ctx.thinkState = {
33101
+ step: "awaiting_analysis",
33102
+ seed: opts.seed,
33103
+ origin: opts.origin,
33104
+ started_at: (/* @__PURE__ */ new Date()).toISOString()
33105
+ };
33106
+ saveSessionState(ctx);
33107
+ console.log();
33108
+ console.log(
33109
+ " " + chalk66.dim("Think session queued. NTRP opens the channel after analysis.")
33110
+ );
33111
+ if (opts.origin !== "nl") {
33112
+ console.log(
33113
+ " " + chalk66.dim("Type what to look at. Paste a CSV path. Or type ") + chalk66.cyan("use demo data") + chalk66.dim(".")
33114
+ );
33115
+ }
33116
+ console.log();
33117
+ }
33118
+ function printChannelIntro(seed) {
33119
+ console.log();
33120
+ console.log(" " + paint("accent", "Think with me"));
33121
+ console.log(
33122
+ " " + chalk66.dim(
33123
+ "Socratic channel \u2014 explore, challenge assumptions, pull evidence. Type "
33124
+ ) + chalk66.cyan("done") + chalk66.dim(" or ") + chalk66.cyan("cancel") + chalk66.dim(" to return to ask \u203A.")
33125
+ );
33126
+ if (seed) {
33127
+ console.log(" " + chalk66.dim("Seed: ") + seed);
33128
+ }
33129
+ console.log();
33130
+ }
33131
+ function armKeylessThink(ctx, opts) {
33132
+ ctx.thinkState = {
33133
+ step: "awaiting_connect",
33134
+ seed: opts.seed,
33135
+ origin: opts.origin,
33136
+ started_at: (/* @__PURE__ */ new Date()).toISOString()
33137
+ };
33138
+ saveSessionState(ctx);
33139
+ console.log();
33140
+ console.log(" " + chalk66.dim("Think channel needs an AI key."));
33141
+ console.log(
33142
+ " " + chalk66.dim("Type ") + paint("accent", "/connect") + chalk66.dim(" and paste a key. Seed kept \u2014 the channel opens after connect.")
33143
+ );
33144
+ console.log();
33145
+ }
33146
+ async function startThinkFlow(ctx, opts) {
33147
+ if (!isAnalysisReady(ctx)) {
33148
+ queueThinkForAnalysis(ctx, opts);
33149
+ return "Think queued";
33150
+ }
33151
+ if (!canUseReplAi(ctx)) {
33152
+ armKeylessThink(ctx, opts);
33153
+ return "Think awaiting connect";
33154
+ }
33155
+ const seed = opts.seed?.trim() || void 0;
33156
+ ctx.thinkState = {
33157
+ step: "active",
33158
+ seed,
33159
+ origin: opts.origin,
33160
+ started_at: (/* @__PURE__ */ new Date()).toISOString(),
33161
+ open_questions: [],
33162
+ challenged_assumptions: [],
33163
+ working_hypotheses: []
33164
+ };
33165
+ if (ctx.thinkConversation.length === 0 && seed) {
33166
+ }
33167
+ saveSessionState(ctx);
33168
+ printChannelIntro(seed);
33169
+ recordMessage(ctx, "agent", seed ? `Think channel opened: ${seed}` : "Think channel opened");
33170
+ if (seed) {
33171
+ recordMessage(ctx, "user", seed);
33172
+ const { runThinkTurn: runThinkTurn2 } = await Promise.resolve().then(() => (init_think(), think_exports));
33173
+ await runThinkTurn2(seed, ctx);
33174
+ }
33175
+ return "Think channel open";
33176
+ }
33177
+ async function resumeThinkAfterCompute(ctx) {
33178
+ const state2 = ctx.thinkState;
33179
+ if (!state2 || state2.step !== "awaiting_analysis") return;
33180
+ if (ctx.strategistState && ctx.strategistState.step !== "awaiting_analysis" && ctx.strategistState.step !== "awaiting_connect") {
33181
+ return;
33182
+ }
33183
+ if (ctx.strategistState?.step === "awaiting_analysis") return;
33184
+ console.log();
33185
+ console.log(" " + paint("accent", "Analysis is ready. The think channel continues."));
33186
+ await startThinkFlow(ctx, {
33187
+ seed: state2.seed,
33188
+ origin: state2.origin ?? "nl"
33189
+ });
33190
+ }
33191
+ async function resumeThinkAfterConnect(ctx) {
33192
+ const state2 = ctx.thinkState;
33193
+ if (!state2 || state2.step !== "awaiting_connect") return false;
33194
+ if (!canUseReplAi(ctx)) return false;
33195
+ console.log();
33196
+ console.log(" " + paint("accent", "Key connected. Opening the think channel."));
33197
+ await startThinkFlow(ctx, {
33198
+ seed: state2.seed,
33199
+ origin: state2.origin ?? "nl"
33200
+ });
33201
+ return true;
33202
+ }
33203
+ function clearThinkFlow(ctx, reason) {
33204
+ ctx.thinkState = void 0;
33205
+ saveSessionState(ctx);
33206
+ if (reason === "handoff") return;
33207
+ console.log();
33208
+ console.log(
33209
+ " " + chalk66.dim(
33210
+ reason === "done" ? "Think channel closed. Back to ask \u203A." : "Think session cancelled. Continue exploration."
33211
+ )
33212
+ );
33213
+ console.log();
33214
+ }
33215
+ async function handleThinkFlow(input, ctx) {
33216
+ const state2 = ctx.thinkState;
33217
+ if (!state2 || state2.step !== "active") return;
33218
+ const line = input.trim();
33219
+ recordMessage(ctx, "user", line);
33220
+ if (CANCEL_RE2.test(line) || DONE_RE.test(line)) {
33221
+ clearThinkFlow(ctx, CANCEL_RE2.test(line) ? "cancel" : "done");
33222
+ recordMessage(ctx, "agent", "Think channel closed");
33223
+ return "Think closed";
33224
+ }
33225
+ if (isStrategistIntent(line)) {
33226
+ clearThinkFlow(ctx, "handoff");
33227
+ const summary = await startStrategistFlow(ctx, {
33228
+ seed: extractObjectiveSeed(line),
33229
+ origin: "nl"
33230
+ }) ?? void 0;
33231
+ return summary ?? "Handed off to strategist";
33232
+ }
33233
+ if (!canUseReplAi(ctx)) {
33234
+ armKeylessThink(ctx, { seed: state2.seed ?? line, origin: state2.origin ?? "nl" });
33235
+ return "Think awaiting connect";
33236
+ }
33237
+ const { runThinkTurn: runThinkTurn2 } = await Promise.resolve().then(() => (init_think(), think_exports));
33238
+ await runThinkTurn2(line, ctx);
33239
+ if (ctx.strategistState && ctx.strategistState.step !== "awaiting_analysis" && ctx.strategistState.step !== "awaiting_connect") {
33240
+ clearThinkFlow(ctx, "handoff");
33241
+ const { promptQueuedAiStrategist: promptQueuedAiStrategist2 } = await Promise.resolve().then(() => (init_strategist_flow(), strategist_flow_exports));
33242
+ promptQueuedAiStrategist2(ctx);
33243
+ }
33244
+ return "Think turn";
33245
+ }
33246
+ var THINK_INTENT_RE, CANCEL_RE2, DONE_RE;
33247
+ var init_think_flow = __esm({
33248
+ "src/conversation/think-flow.ts"() {
33249
+ "use strict";
33250
+ init_context2();
33251
+ init_repl_api();
33252
+ init_theme();
33253
+ init_handoff_draft();
33254
+ init_strategist_flow();
33255
+ THINK_INTENT_RE = /\b(think\s+with\s+me|pressure[- ]?test|what\s+am\s+i\s+missing|challenge\s+(my\s+)?(assumption|thinking|hypothesis)|let'?s\s+(dig|explore|think|pressure)|dig\s+into|steelman|devil'?s\s+advocate|think\s+through|brainstorm\s+(with\s+me|this)|socratic)\b/i;
33256
+ CANCEL_RE2 = /^(cancel|stop|quit|abort|never\s?mind|nevermind|forget it)\s*[.!]?\s*$/i;
33257
+ DONE_RE = /^(done|enough|enough for now|that'?s enough|leave|exit think)\s*[.!]?\s*$/i;
33258
+ }
33259
+ });
33260
+
32552
33261
  // src/commands/connect.ts
32553
33262
  var connect_exports2 = {};
32554
33263
  __export(connect_exports2, {
32555
33264
  handler: () => handler39
32556
33265
  });
32557
- import chalk65 from "chalk";
33266
+ import chalk67 from "chalk";
32558
33267
  function usage2() {
32559
- console.log(chalk65.dim(" Paste a key inside ntrp. Type /connect and press Enter."));
32560
- console.log(chalk65.dim(" Scripts: ntrp connect --key <key>"));
32561
- console.log(chalk65.dim(" Named provider: /connect anthropic (or ollama, no key)"));
32562
- console.log(chalk65.dim(" Custom endpoint (scripts): --base-url <url> [--id <name>]"));
33268
+ console.log(chalk67.dim(" Paste a key inside ntrp. Type /connect and press Enter."));
33269
+ console.log(chalk67.dim(" Scripts: ntrp connect --key <key>"));
33270
+ console.log(chalk67.dim(" Named provider: /connect anthropic (or ollama, no key)"));
33271
+ console.log(chalk67.dim(" Custom endpoint (scripts): --base-url <url> [--id <name>]"));
32563
33272
  }
32564
33273
  function printOutcome(outcome, ctx) {
32565
33274
  console.log();
32566
33275
  const [headline, ...rest] = describeConnectOutcome(outcome);
32567
- console.log(" " + paint("success", "\u2713") + " " + chalk65.bold(headline ?? ""));
33276
+ console.log(" " + paint("success", "\u2713") + " " + chalk67.bold(headline ?? ""));
32568
33277
  for (const line of rest) {
32569
- console.log(" " + chalk65.dim(line));
33278
+ console.log(" " + chalk67.dim(line));
32570
33279
  }
32571
33280
  console.log();
32572
- console.log(" " + chalk65.dim(`Using ${formatActiveStack(ctx)}`));
32573
- console.log(" " + chalk65.dim("Type a question to try it. Type /provider to switch providers."));
33281
+ console.log(" " + chalk67.dim(`Using ${formatActiveStack(ctx)}`));
33282
+ console.log(" " + chalk67.dim("Type a question to try it. Type /provider to switch providers."));
32574
33283
  console.log();
32575
- console.log(" " + chalk65.dim("What leaves this machine"));
33284
+ console.log(" " + chalk67.dim("What leaves this machine"));
32576
33285
  for (const line of PRIVACY_NOTICE_LINES.slice(0, 8)) {
32577
- console.log(" " + chalk65.dim(line));
33286
+ console.log(" " + chalk67.dim(line));
32578
33287
  }
32579
- console.log(" " + chalk65.dim("Type /privacy to read the full notice."));
33288
+ console.log(" " + chalk67.dim("Type /privacy to read the full notice."));
32580
33289
  console.log();
32581
33290
  }
32582
33291
  async function replayAfterConnect(ctx) {
32583
33292
  const { resumeStrategistAfterConnect: resumeStrategistAfterConnect2 } = await Promise.resolve().then(() => (init_strategist_flow(), strategist_flow_exports));
32584
33293
  if (await resumeStrategistAfterConnect2(ctx)) return;
33294
+ const { resumeThinkAfterConnect: resumeThinkAfterConnect2 } = await Promise.resolve().then(() => (init_think_flow(), think_flow_exports));
33295
+ if (await resumeThinkAfterConnect2(ctx)) return;
32585
33296
  if (!ctx.pendingAsk?.text) return;
32586
33297
  const { isAnalysisReady: isAnalysisReady2 } = await Promise.resolve().then(() => (init_context2(), context_exports));
32587
33298
  if (!isAnalysisReady2(ctx)) return;
@@ -32591,14 +33302,14 @@ async function replayAfterConnect(ctx) {
32591
33302
  function printError(err, ctx) {
32592
33303
  const message = err instanceof Error ? err.message : String(err);
32593
33304
  console.log();
32594
- console.log(" " + chalk65.red(message));
33305
+ console.log(" " + chalk67.red(message));
32595
33306
  console.log();
32596
33307
  if (ctx.oneShot) process.exit(1);
32597
33308
  }
32598
33309
  async function promptKey(session, label, opts = {}) {
32599
33310
  console.log();
32600
33311
  console.log(
32601
- " " + chalk65.dim("Paste once, press Enter. Stored in ") + paint("accent", "~/.ntrp/config.json") + chalk65.dim(" only.")
33312
+ " " + chalk67.dim("Paste once, press Enter. Stored in ") + paint("accent", "~/.ntrp/config.json") + chalk67.dim(" only.")
32602
33313
  );
32603
33314
  return session.askSecret(label, { confirm: false, allowEmpty: opts.allowEmpty });
32604
33315
  }
@@ -32631,7 +33342,7 @@ async function handler39(args, ctx) {
32631
33342
  if (baseUrl && !forcedSpec) {
32632
33343
  const id = customId ?? forcedProvider ?? hostToId(baseUrl);
32633
33344
  for (const warning of customEndpointWarnings(baseUrl)) {
32634
- console.log(" " + chalk65.yellow(warning));
33345
+ console.log(" " + chalk67.yellow(warning));
32635
33346
  }
32636
33347
  let key2 = inlineKey;
32637
33348
  if (!key2 && !ctx.oneShot && process.stdin.isTTY) {
@@ -32642,7 +33353,7 @@ async function handler39(args, ctx) {
32642
33353
  true
32643
33354
  );
32644
33355
  if (!proceed) {
32645
- console.log(" " + chalk65.dim("Cancelled."));
33356
+ console.log(" " + chalk67.dim("Cancelled."));
32646
33357
  console.log();
32647
33358
  return;
32648
33359
  }
@@ -32650,7 +33361,7 @@ async function handler39(args, ctx) {
32650
33361
  if (needsKey) key2 = await promptKey(session2, `API key for ${id}`);
32651
33362
  } catch (err) {
32652
33363
  if (err instanceof Error && err.message === "Cancelled") {
32653
- console.log(" " + chalk65.dim("Cancelled."));
33364
+ console.log(" " + chalk67.dim("Cancelled."));
32654
33365
  console.log();
32655
33366
  return;
32656
33367
  }
@@ -32673,11 +33384,11 @@ async function handler39(args, ctx) {
32673
33384
  }
32674
33385
  if (forcedProvider && !forcedSpec) {
32675
33386
  console.log();
32676
- console.log(" " + chalk65.red(`Unknown provider: ${forcedProvider}`));
33387
+ console.log(" " + chalk67.red(`Unknown provider: ${forcedProvider}`));
32677
33388
  console.log(
32678
- " " + chalk65.dim("Built-ins: anthropic, openai, google, groq, mistral, deepseek, xai, openrouter, together, fireworks, ollama")
33389
+ " " + chalk67.dim("Built-ins: anthropic, openai, google, groq, mistral, deepseek, xai, openrouter, together, fireworks, ollama")
32679
33390
  );
32680
- console.log(" " + chalk65.dim(`Custom endpoint: /connect --base-url <url> --id ${forcedProvider}`));
33391
+ console.log(" " + chalk67.dim(`Custom endpoint: /connect --base-url <url> --id ${forcedProvider}`));
32681
33392
  console.log();
32682
33393
  if (ctx.oneShot) process.exit(1);
32683
33394
  return;
@@ -32700,7 +33411,7 @@ async function handler39(args, ctx) {
32700
33411
  } catch (err) {
32701
33412
  session.close();
32702
33413
  if (err instanceof Error && err.message === "Cancelled") {
32703
- console.log(" " + chalk65.dim("Cancelled."));
33414
+ console.log(" " + chalk67.dim("Cancelled."));
32704
33415
  console.log();
32705
33416
  return;
32706
33417
  }
@@ -32708,7 +33419,7 @@ async function handler39(args, ctx) {
32708
33419
  }
32709
33420
  if (!key) {
32710
33421
  session.close();
32711
- console.log(" " + chalk65.dim("No key pasted \u2014 cancelled. Run ") + paint("accent", "/connect") + chalk65.dim(" when you have one."));
33422
+ console.log(" " + chalk67.dim("No key pasted \u2014 cancelled. Run ") + paint("accent", "/connect") + chalk67.dim(" when you have one."));
32712
33423
  console.log();
32713
33424
  return;
32714
33425
  }
@@ -32738,7 +33449,7 @@ async function handler39(args, ctx) {
32738
33449
  } catch (err) {
32739
33450
  spinner.stop();
32740
33451
  if (err instanceof ConnectCancelled) {
32741
- console.log(" " + chalk65.dim("Cancelled."));
33452
+ console.log(" " + chalk67.dim("Cancelled."));
32742
33453
  console.log();
32743
33454
  } else {
32744
33455
  printError(err, ctx);
@@ -32774,7 +33485,7 @@ var provider_exports = {};
32774
33485
  __export(provider_exports, {
32775
33486
  handler: () => handler40
32776
33487
  });
32777
- import chalk66 from "chalk";
33488
+ import chalk68 from "chalk";
32778
33489
  async function handler40(args, ctx) {
32779
33490
  const { positional, flags } = parseArgs2(args, ["default"]);
32780
33491
  const sub = positional[0]?.toLowerCase();
@@ -32787,7 +33498,7 @@ async function handler40(args, ctx) {
32787
33498
  if (!ctx.oneShot) saveSessionState(ctx);
32788
33499
  console.log();
32789
33500
  console.log(" " + paint("success", "\u2713") + " Session engine reset \u2014 using config defaults.");
32790
- console.log(" " + chalk66.dim(`Default: ${loadLlmConfig().primary}`));
33501
+ console.log(" " + chalk68.dim(`Default: ${loadLlmConfig().primary}`));
32791
33502
  console.log();
32792
33503
  return;
32793
33504
  }
@@ -32800,7 +33511,7 @@ async function handler40(args, ctx) {
32800
33511
  setConfigValue("llm-auto-failover", session.autoFailover ? "on" : "off");
32801
33512
  }
32802
33513
  console.log();
32803
- console.log(" " + paint("success", "\u2713") + ` Saved ${chalk66.bold(active)} as default engine.`);
33514
+ console.log(" " + paint("success", "\u2713") + ` Saved ${chalk68.bold(active)} as default engine.`);
32804
33515
  console.log();
32805
33516
  return;
32806
33517
  }
@@ -32819,28 +33530,28 @@ async function handler40(args, ctx) {
32819
33530
  }
32820
33531
  console.log();
32821
33532
  console.log(
32822
- " " + paint("success", "\u2713") + ` Auto-failover ${session.autoFailover ? chalk66.bold("on") : chalk66.bold("off")} for this session.`
33533
+ " " + paint("success", "\u2713") + ` Auto-failover ${session.autoFailover ? chalk68.bold("on") : chalk68.bold("off")} for this session.`
32823
33534
  );
32824
- if (persist) console.log(" " + chalk66.dim("Also saved as config default."));
33535
+ if (persist) console.log(" " + chalk68.dim("Also saved as config default."));
32825
33536
  console.log();
32826
33537
  return;
32827
33538
  }
32828
33539
  const spec = getProviderSpec(sub);
32829
33540
  if (!spec || RESERVED.has(sub)) {
32830
33541
  console.log();
32831
- console.log(" " + chalk66.red(`Unknown engine: ${sub}`));
32832
- console.log(" " + chalk66.dim("Usage: /provider [<id>|list|reset|save|failover on|off]"));
32833
- console.log(" " + chalk66.dim("Connected: ") + (availableEngineLabels().join(", ") || chalk66.dim("none")));
32834
- console.log(" " + chalk66.dim("Add one with ") + paint("accent", "/connect"));
33542
+ console.log(" " + chalk68.red(`Unknown engine: ${sub}`));
33543
+ console.log(" " + chalk68.dim("Usage: /provider [<id>|list|reset|save|failover on|off]"));
33544
+ console.log(" " + chalk68.dim("Connected: ") + (availableEngineLabels().join(", ") || chalk68.dim("none")));
33545
+ console.log(" " + chalk68.dim("Add one with ") + paint("accent", "/connect"));
32835
33546
  console.log();
32836
33547
  return;
32837
33548
  }
32838
33549
  const provider = spec.id;
32839
33550
  if (!hasProviderKey(provider)) {
32840
33551
  console.log();
32841
- console.log(" " + chalk66.red(`${spec.label} is not connected.`));
33552
+ console.log(" " + chalk68.red(`${spec.label} is not connected.`));
32842
33553
  console.log(
32843
- " " + chalk66.dim("Type ") + paint("accent", `/connect ${provider}`) + chalk66.dim(" (or ") + paint("accent", `/config set ${spec.key_config_name}`) + chalk66.dim(").")
33554
+ " " + chalk68.dim("Type ") + paint("accent", `/connect ${provider}`) + chalk68.dim(" (or ") + paint("accent", `/config set ${spec.key_config_name}`) + chalk68.dim(").")
32844
33555
  );
32845
33556
  console.log();
32846
33557
  return;
@@ -32848,11 +33559,11 @@ async function handler40(args, ctx) {
32848
33559
  ensureLlmSession(ctx).provider = provider;
32849
33560
  if (!ctx.oneShot) saveSessionState(ctx);
32850
33561
  console.log();
32851
- console.log(" " + paint("success", "\u2713") + ` Active engine: ${chalk66.bold(provider)}`);
32852
- console.log(" " + chalk66.dim(`Stack: ${formatActiveStack(ctx)}`));
33562
+ console.log(" " + paint("success", "\u2713") + ` Active engine: ${chalk68.bold(provider)}`);
33563
+ console.log(" " + chalk68.dim(`Stack: ${formatActiveStack(ctx)}`));
32853
33564
  const others = availableEngineLabels().filter((p) => p !== provider);
32854
33565
  if (others.length > 0) {
32855
- console.log(" " + chalk66.dim(`Also available: ${others.join(", ")}`));
33566
+ console.log(" " + chalk68.dim(`Also available: ${others.join(", ")}`));
32856
33567
  }
32857
33568
  console.log();
32858
33569
  }
@@ -32863,30 +33574,30 @@ function printStatus(ctx) {
32863
33574
  const autoFailover = resolveAutoFailoverEnabled(ctx);
32864
33575
  const engines = countAvailableEngines();
32865
33576
  console.log();
32866
- console.log(chalk66.bold(" LLM engines"));
33577
+ console.log(chalk68.bold(" LLM engines"));
32867
33578
  console.log(` Connected: ${engines} engine${engines === 1 ? "" : "s"}`);
32868
33579
  const configured = listProviderSpecs().filter((s) => hasProviderKey(s.id));
32869
33580
  for (const s of configured) {
32870
33581
  const marker2 = s.id === active ? paint("accent", " \u25BA active") : "";
32871
- console.log(` ${paint("success", "\u2713")} ${s.id}${s.custom ? chalk66.dim(" (custom)") : ""}${marker2}`);
33582
+ console.log(` ${paint("success", "\u2713")} ${s.id}${s.custom ? chalk68.dim(" (custom)") : ""}${marker2}`);
32872
33583
  }
32873
33584
  if (configured.length === 0) {
32874
- console.log(" " + chalk66.dim("none \u2014 run /connect and paste any provider key"));
33585
+ console.log(" " + chalk68.dim("none \u2014 run /connect and paste any provider key"));
32875
33586
  }
32876
33587
  console.log();
32877
- console.log(chalk66.bold(" Active stack"));
33588
+ console.log(chalk68.bold(" Active stack"));
32878
33589
  console.log(` ${formatActiveStack(ctx)}`);
32879
33590
  if (sessionOverride) {
32880
- console.log(chalk66.dim(" (session override \u2014 /provider reset to use default)"));
33591
+ console.log(chalk68.dim(" (session override \u2014 /provider reset to use default)"));
32881
33592
  } else {
32882
- console.log(chalk66.dim(` (config default: ${cfg.primary})`));
33593
+ console.log(chalk68.dim(` (config default: ${cfg.primary})`));
32883
33594
  }
32884
33595
  console.log();
32885
- console.log(` Auto-failover: ${autoFailover ? paint("success", "on") : chalk66.dim("off")}`);
32886
- console.log(chalk66.dim(` /provider <id> \u2014 switch engine (${configured.map((s) => s.id).join(", ") || "none connected"})`));
32887
- console.log(chalk66.dim(" /provider failover on|off \u2014 rate-limit safety net"));
32888
- console.log(chalk66.dim(" /provider save \u2014 persist active engine to config"));
32889
- console.log(chalk66.dim(" /connect \u2014 add another provider (any API key)"));
33596
+ console.log(` Auto-failover: ${autoFailover ? paint("success", "on") : chalk68.dim("off")}`);
33597
+ console.log(chalk68.dim(` /provider <id> \u2014 switch engine (${configured.map((s) => s.id).join(", ") || "none connected"})`));
33598
+ console.log(chalk68.dim(" /provider failover on|off \u2014 rate-limit safety net"));
33599
+ console.log(chalk68.dim(" /provider save \u2014 persist active engine to config"));
33600
+ console.log(chalk68.dim(" /connect \u2014 add another provider (any API key)"));
32890
33601
  console.log();
32891
33602
  }
32892
33603
  var RESERVED;
@@ -32909,7 +33620,7 @@ var tier_exports = {};
32909
33620
  __export(tier_exports, {
32910
33621
  handler: () => handler41
32911
33622
  });
32912
- import chalk67 from "chalk";
33623
+ import chalk69 from "chalk";
32913
33624
  async function handler41(args, ctx) {
32914
33625
  const { positional, flags } = parseArgs2(args, ["default"]);
32915
33626
  const sub = positional[0]?.toLowerCase();
@@ -32919,8 +33630,8 @@ async function handler41(args, ctx) {
32919
33630
  }
32920
33631
  if (!TIERS.includes(sub)) {
32921
33632
  console.log();
32922
- console.log(" " + chalk67.red(`Unknown tier: ${sub}`));
32923
- console.log(" " + chalk67.dim("Usage: /tier [high|medium|low|list] [--default]"));
33633
+ console.log(" " + chalk69.red(`Unknown tier: ${sub}`));
33634
+ console.log(" " + chalk69.dim("Usage: /tier [high|medium|low|list] [--default]"));
32924
33635
  console.log();
32925
33636
  return;
32926
33637
  }
@@ -32934,9 +33645,9 @@ async function handler41(args, ctx) {
32934
33645
  }
32935
33646
  console.log();
32936
33647
  console.log(
32937
- " " + paint("success", "\u2713") + ` Inference tier set to ${chalk67.bold(tier.toUpperCase())}` + (persist ? chalk67.dim(" (saved as default)") : chalk67.dim(" (this session)"))
33648
+ " " + paint("success", "\u2713") + ` Inference tier set to ${chalk69.bold(tier.toUpperCase())}` + (persist ? chalk69.dim(" (saved as default)") : chalk69.dim(" (this session)"))
32938
33649
  );
32939
- console.log(" " + chalk67.dim(`Stack: ${formatActiveStack(ctx)}`));
33650
+ console.log(" " + chalk69.dim(`Stack: ${formatActiveStack(ctx)}`));
32940
33651
  console.log();
32941
33652
  }
32942
33653
  function printCatalog(ctx) {
@@ -32945,37 +33656,37 @@ function printCatalog(ctx) {
32945
33656
  const sessionTier = ctx.llm?.tier;
32946
33657
  const providers = getAvailableProviders();
32947
33658
  console.log();
32948
- console.log(chalk67.bold(" Inference settings"));
33659
+ console.log(chalk69.bold(" Inference settings"));
32949
33660
  console.log(` Active: ${paint("accent", formatActiveStack(ctx))}`);
32950
33661
  if (sessionTier) {
32951
- console.log(chalk67.dim(" (session tier override)"));
33662
+ console.log(chalk69.dim(" (session tier override)"));
32952
33663
  } else {
32953
- console.log(chalk67.dim(` Config default tier: ${cfg.tier.toUpperCase()}`));
33664
+ console.log(chalk69.dim(` Config default tier: ${cfg.tier.toUpperCase()}`));
32954
33665
  }
32955
33666
  console.log();
32956
33667
  if (providers.length === 0) {
32957
- console.log(" " + chalk67.dim("No engines connected \u2014 run /connect and paste any provider key."));
33668
+ console.log(" " + chalk69.dim("No engines connected \u2014 run /connect and paste any provider key."));
32958
33669
  console.log();
32959
33670
  }
32960
33671
  for (const tier of TIERS) {
32961
- console.log(chalk67.bold(` ${tier.toUpperCase()}`));
33672
+ console.log(chalk69.bold(` ${tier.toUpperCase()}`));
32962
33673
  for (const provider of providers) {
32963
33674
  const modelId = resolveModelSafe(provider, tier);
32964
33675
  if (!modelId) {
32965
- console.log(` ${provider}/${chalk67.dim("no models \u2014 /model refresh")}`);
33676
+ console.log(` ${provider}/${chalk69.dim("no models \u2014 /model refresh")}`);
32966
33677
  continue;
32967
33678
  }
32968
33679
  const isActive = provider === active.provider && tier === active.tier && modelId === active.modelId;
32969
33680
  const marker2 = isActive ? paint("accent", "\u25BA ") : " ";
32970
33681
  const discovered = !!getProviderModels(provider);
32971
- const source = discovered ? "" : chalk67.dim(" [bundled fallback]");
33682
+ const source = discovered ? "" : chalk69.dim(" [bundled fallback]");
32972
33683
  console.log(`${marker2}${provider}/${modelId}${source}`);
32973
33684
  }
32974
33685
  console.log();
32975
33686
  }
32976
- console.log(chalk67.dim(" /tier high|medium|low \u2014 set tier for this session"));
32977
- console.log(chalk67.dim(" /tier high --default \u2014 also save as config default"));
32978
- console.log(chalk67.dim(" /provider <id> \u2014 switch engine \xB7 /model list \u2014 browse models"));
33687
+ console.log(chalk69.dim(" /tier high|medium|low \u2014 set tier for this session"));
33688
+ console.log(chalk69.dim(" /tier high --default \u2014 also save as config default"));
33689
+ console.log(chalk69.dim(" /provider <id> \u2014 switch engine \xB7 /model list \u2014 browse models"));
32979
33690
  console.log();
32980
33691
  }
32981
33692
  var TIERS;
@@ -32999,7 +33710,7 @@ var model_exports = {};
32999
33710
  __export(model_exports, {
33000
33711
  handler: () => handler42
33001
33712
  });
33002
- import chalk68 from "chalk";
33713
+ import chalk70 from "chalk";
33003
33714
  async function handler42(args, ctx) {
33004
33715
  const { positional, flags } = parseArgs2(args, ["default", "all"]);
33005
33716
  const sub = positional[0]?.toLowerCase();
@@ -33018,7 +33729,7 @@ async function handler42(args, ctx) {
33018
33729
  if (!ctx.oneShot) saveSessionState(ctx);
33019
33730
  console.log();
33020
33731
  console.log(" " + paint("success", "\u2713") + " Model override cleared \u2014 using tier defaults.");
33021
- console.log(" " + chalk68.dim(`Stack: ${formatActiveStack(ctx)}`));
33732
+ console.log(" " + chalk70.dim(`Stack: ${formatActiveStack(ctx)}`));
33022
33733
  console.log();
33023
33734
  return;
33024
33735
  }
@@ -33026,7 +33737,7 @@ async function handler42(args, ctx) {
33026
33737
  const modelId = positional[1];
33027
33738
  if (!modelId) {
33028
33739
  console.log();
33029
- console.log(" " + chalk68.red("Usage: /model set <model-id> [--default]"));
33740
+ console.log(" " + chalk70.red("Usage: /model set <model-id> [--default]"));
33030
33741
  console.log();
33031
33742
  return;
33032
33743
  }
@@ -33034,7 +33745,7 @@ async function handler42(args, ctx) {
33034
33745
  const providerErr = validateModelForProvider(modelId, active);
33035
33746
  if (providerErr) {
33036
33747
  console.log();
33037
- console.log(" " + chalk68.red(providerErr));
33748
+ console.log(" " + chalk70.red(providerErr));
33038
33749
  console.log();
33039
33750
  return;
33040
33751
  }
@@ -33043,11 +33754,11 @@ async function handler42(args, ctx) {
33043
33754
  if (cache2 && !known) {
33044
33755
  console.log();
33045
33756
  console.log(
33046
- " " + chalk68.yellow("\u26A0") + ` ${modelId} isn't in ${active}'s discovered list (` + paint("accent", "/model list") + `) \u2014 saving anyway.`
33757
+ " " + chalk70.yellow("\u26A0") + ` ${modelId} isn't in ${active}'s discovered list (` + paint("accent", "/model list") + `) \u2014 saving anyway.`
33047
33758
  );
33048
33759
  } else if (!cache2) {
33049
33760
  console.log();
33050
- console.log(" " + chalk68.yellow("\u26A0") + ` No discovered models for ${active} yet (` + paint("accent", "/model refresh") + `) \u2014 saving anyway.`);
33761
+ console.log(" " + chalk70.yellow("\u26A0") + ` No discovered models for ${active} yet (` + paint("accent", "/model refresh") + `) \u2014 saving anyway.`);
33051
33762
  }
33052
33763
  const persist = getBool(flags, "default");
33053
33764
  if (persist) {
@@ -33058,25 +33769,25 @@ async function handler42(args, ctx) {
33058
33769
  }
33059
33770
  console.log();
33060
33771
  console.log(
33061
- " " + paint("success", "\u2713") + ` Model: ${chalk68.bold(modelId)}` + (persist ? chalk68.dim(" (saved as default)") : chalk68.dim(" (this session)"))
33772
+ " " + paint("success", "\u2713") + ` Model: ${chalk70.bold(modelId)}` + (persist ? chalk70.dim(" (saved as default)") : chalk70.dim(" (this session)"))
33062
33773
  );
33063
- console.log(" " + chalk68.dim(`Stack: ${formatActiveStack(ctx)}`));
33774
+ console.log(" " + chalk70.dim(`Stack: ${formatActiveStack(ctx)}`));
33064
33775
  console.log();
33065
33776
  return;
33066
33777
  }
33067
33778
  const sessionOverride = ctx.llm?.modelOverride;
33068
33779
  const globalOverride = getConfigValue("llm-model-override");
33069
33780
  console.log();
33070
- console.log(chalk68.bold(" Model"));
33781
+ console.log(chalk70.bold(" Model"));
33071
33782
  if (sessionOverride) {
33072
33783
  console.log(` Session override: ${paint("accent", sessionOverride)}`);
33073
33784
  } else if (globalOverride) {
33074
33785
  console.log(` Config default: ${paint("accent", globalOverride)}`);
33075
33786
  } else {
33076
- console.log(" " + chalk68.dim("No override \u2014 tier defaults apply."));
33787
+ console.log(" " + chalk70.dim("No override \u2014 tier defaults apply."));
33077
33788
  }
33078
33789
  console.log(` Active stack: ${formatActiveStack(ctx)}`);
33079
- console.log(chalk68.dim(" /model list \xB7 /model set <id> \xB7 /model refresh \xB7 /model clear"));
33790
+ console.log(chalk70.dim(" /model list \xB7 /model set <id> \xB7 /model refresh \xB7 /model clear"));
33080
33791
  console.log();
33081
33792
  }
33082
33793
  function tierMarkers(cache2, modelId) {
@@ -33087,28 +33798,28 @@ function printModelList(ctx, showAll) {
33087
33798
  const active = resolveActiveProvider(ctx);
33088
33799
  const cache2 = getProviderModels(active);
33089
33800
  console.log();
33090
- console.log(chalk68.bold(` Models \u2014 ${active}`));
33801
+ console.log(chalk70.bold(` Models \u2014 ${active}`));
33091
33802
  if (!cache2) {
33092
- console.log(" " + chalk68.dim("Nothing discovered yet."));
33093
- console.log(" " + chalk68.dim("Run ") + paint("accent", "/model refresh") + chalk68.dim(" (or ") + paint("accent", "/connect") + chalk68.dim(" to add the provider)."));
33803
+ console.log(" " + chalk70.dim("Nothing discovered yet."));
33804
+ console.log(" " + chalk70.dim("Run ") + paint("accent", "/model refresh") + chalk70.dim(" (or ") + paint("accent", "/connect") + chalk70.dim(" to add the provider)."));
33094
33805
  console.log();
33095
33806
  return;
33096
33807
  }
33097
33808
  const fetchedAt = cache2.fetched_at.slice(0, 10);
33098
- console.log(" " + chalk68.dim(`${cache2.models.length} chat models \xB7 discovered ${fetchedAt} \xB7 /model refresh to update`));
33809
+ console.log(" " + chalk70.dim(`${cache2.models.length} chat models \xB7 discovered ${fetchedAt} \xB7 /model refresh to update`));
33099
33810
  console.log();
33100
33811
  const models = showAll ? cache2.models : cache2.models.slice(0, LIST_LIMIT);
33101
33812
  const noTools = new Set(cache2.quirks?.no_tools ?? []);
33102
33813
  for (const m of models) {
33103
- const name = m.display_name && m.display_name !== m.id ? chalk68.dim(` \u2014 ${m.display_name}`) : "";
33104
- const quirk = noTools.has(m.id) ? chalk68.yellow(" [no tools]") : "";
33814
+ const name = m.display_name && m.display_name !== m.id ? chalk70.dim(` \u2014 ${m.display_name}`) : "";
33815
+ const quirk = noTools.has(m.id) ? chalk70.yellow(" [no tools]") : "";
33105
33816
  console.log(` ${m.id}${name}${tierMarkers(cache2, m.id)}${quirk}`);
33106
33817
  }
33107
33818
  if (!showAll && cache2.models.length > models.length) {
33108
- console.log(" " + chalk68.dim(`\u2026 and ${cache2.models.length - models.length} more (/model list --all)`));
33819
+ console.log(" " + chalk70.dim(`\u2026 and ${cache2.models.length - models.length} more (/model list --all)`));
33109
33820
  }
33110
33821
  console.log();
33111
- console.log(" " + chalk68.dim("/model set <id> \u2014 pin one for this session (--default to persist)"));
33822
+ console.log(" " + chalk70.dim("/model set <id> \u2014 pin one for this session (--default to persist)"));
33112
33823
  console.log();
33113
33824
  }
33114
33825
  async function refreshModels(ctx) {
@@ -33117,13 +33828,13 @@ async function refreshModels(ctx) {
33117
33828
  const entry = await refreshProviderModels(active, { force: true });
33118
33829
  if (!entry) {
33119
33830
  spinner.fail(`Couldn't reach ${active} to refresh models.`);
33120
- console.log(" " + chalk68.dim("Check your connection and key, then retry. Cached models remain in use."));
33831
+ console.log(" " + chalk70.dim("Check your connection and key, then retry. Cached models remain in use."));
33121
33832
  console.log();
33122
33833
  return;
33123
33834
  }
33124
33835
  spinner.succeed(`${active}: ${entry.models.length} chat models discovered.`);
33125
- console.log(" " + chalk68.dim(`high ${entry.tier_stack.high} \xB7 medium ${entry.tier_stack.medium} \xB7 low ${entry.tier_stack.low}`));
33126
- console.log(" " + chalk68.dim(`Stack: ${formatActiveStack(ctx)}`));
33836
+ console.log(" " + chalk70.dim(`high ${entry.tier_stack.high} \xB7 medium ${entry.tier_stack.medium} \xB7 low ${entry.tier_stack.low}`));
33837
+ console.log(" " + chalk70.dim(`Stack: ${formatActiveStack(ctx)}`));
33127
33838
  console.log();
33128
33839
  }
33129
33840
  var LIST_LIMIT;
@@ -33143,27 +33854,20 @@ var init_model = __esm({
33143
33854
  });
33144
33855
 
33145
33856
  // src/config/update-check.ts
33146
- var update_check_exports = {};
33147
- __export(update_check_exports, {
33148
- invalidateUpdateCheckCache: () => invalidateUpdateCheckCache,
33149
- isCacheFresh: () => isCacheFresh,
33150
- loadUpdateCheckCache: () => loadUpdateCheckCache,
33151
- saveUpdateCheckCache: () => saveUpdateCheckCache
33152
- });
33153
- import { existsSync as existsSync28, mkdirSync as mkdirSync18, readFileSync as readFileSync21, unlinkSync as unlinkSync5, writeFileSync as writeFileSync20 } from "fs";
33857
+ import { existsSync as existsSync29, mkdirSync as mkdirSync18, readFileSync as readFileSync21, unlinkSync as unlinkSync5, writeFileSync as writeFileSync20 } from "fs";
33154
33858
  import { join as join33 } from "path";
33155
33859
  function cachePath2() {
33156
33860
  return join33(ntrpHome(), "update-check.json");
33157
33861
  }
33158
33862
  function ensureDir7() {
33159
33863
  const dir = ntrpHome();
33160
- if (!existsSync28(dir)) {
33864
+ if (!existsSync29(dir)) {
33161
33865
  mkdirSync18(dir, { recursive: true });
33162
33866
  }
33163
33867
  }
33164
33868
  function loadUpdateCheckCache() {
33165
33869
  const path = cachePath2();
33166
- if (!existsSync28(path)) return null;
33870
+ if (!existsSync29(path)) return null;
33167
33871
  try {
33168
33872
  const parsed = JSON.parse(readFileSync21(path, "utf-8"));
33169
33873
  if (!parsed || typeof parsed !== "object" || typeof parsed.lastCheck !== "number" || typeof parsed.latestVersion !== "string") {
@@ -33184,7 +33888,7 @@ function isCacheFresh(cache2, ttlMs = CACHE_TTL_MS2) {
33184
33888
  }
33185
33889
  function invalidateUpdateCheckCache() {
33186
33890
  const path = cachePath2();
33187
- if (existsSync28(path)) {
33891
+ if (existsSync29(path)) {
33188
33892
  unlinkSync5(path);
33189
33893
  }
33190
33894
  }
@@ -33198,7 +33902,7 @@ var init_update_check = __esm({
33198
33902
  });
33199
33903
 
33200
33904
  // src/version.ts
33201
- import { existsSync as existsSync29, readFileSync as readFileSync22 } from "fs";
33905
+ import { existsSync as existsSync30, readFileSync as readFileSync22 } from "fs";
33202
33906
  import { dirname as dirname6, join as join34 } from "path";
33203
33907
  import { fileURLToPath } from "url";
33204
33908
  function getInstalledVersion() {
@@ -33206,7 +33910,7 @@ function getInstalledVersion() {
33206
33910
  const start = dirname6(fileURLToPath(import.meta.url));
33207
33911
  for (const rel of ["../package.json", "../../package.json"]) {
33208
33912
  const path = join34(start, rel);
33209
- if (!existsSync29(path)) continue;
33913
+ if (!existsSync30(path)) continue;
33210
33914
  try {
33211
33915
  const pkg = JSON.parse(readFileSync22(path, "utf-8"));
33212
33916
  if (typeof pkg.version === "string" && pkg.version.length > 0) {
@@ -33230,10 +33934,13 @@ var init_version = __esm({
33230
33934
  var registry_exports = {};
33231
33935
  __export(registry_exports, {
33232
33936
  NPM_PACKAGE: () => NPM_PACKAGE,
33937
+ applyUpdateCheckResult: () => applyUpdateCheckResult,
33233
33938
  checkForUpdate: () => checkForUpdate,
33234
33939
  fetchLatestVersion: () => fetchLatestVersion,
33235
33940
  formatUpdateNudge: () => formatUpdateNudge,
33236
- isNewerVersion: () => isNewerVersion
33941
+ hydrateUpdateAvailableFromCache: () => hydrateUpdateAvailableFromCache,
33942
+ isNewerVersion: () => isNewerVersion,
33943
+ startBackgroundUpdateCheck: () => startBackgroundUpdateCheck
33237
33944
  });
33238
33945
  function registryUrl() {
33239
33946
  return process.env.NTRP_REGISTRY_URL ?? "https://registry.npmjs.org/@sonnechasser/ntrp/latest";
@@ -33252,7 +33959,27 @@ function isNewerVersion(latest, current) {
33252
33959
  return lPatch > cPatch;
33253
33960
  }
33254
33961
  function formatUpdateNudge(current, latest) {
33255
- return `\u26A1 NTRP v${latest} available (you're on v${current}) \u2014 type /update to upgrade`;
33962
+ return `\u26A1 NTRP v${latest} available (running v${current}) \u2014 type /update`;
33963
+ }
33964
+ function hydrateUpdateAvailableFromCache(current) {
33965
+ const cached2 = loadUpdateCheckCache();
33966
+ if (!cached2?.latestVersion) return void 0;
33967
+ if (!isNewerVersion(cached2.latestVersion, current)) return void 0;
33968
+ return { current, latest: cached2.latestVersion };
33969
+ }
33970
+ function applyUpdateCheckResult(ctx, result) {
33971
+ if (result?.updateAvailable) {
33972
+ ctx.updateAvailable = { current: result.current, latest: result.latest };
33973
+ return;
33974
+ }
33975
+ if (result && !result.updateAvailable) {
33976
+ ctx.updateAvailable = void 0;
33977
+ }
33978
+ }
33979
+ function startBackgroundUpdateCheck(ctx) {
33980
+ const pending = checkForUpdate({ force: true, timeoutMs: 5e3 });
33981
+ ctx.pendingUpdateCheck = pending;
33982
+ void pending.then((result) => applyUpdateCheckResult(ctx, result)).catch(() => void 0);
33256
33983
  }
33257
33984
  async function fetchLatestVersion(timeoutMs = 5e3) {
33258
33985
  try {
@@ -33299,18 +34026,83 @@ var init_registry = __esm({
33299
34026
  }
33300
34027
  });
33301
34028
 
34029
+ // src/update/relaunch.ts
34030
+ var relaunch_exports = {};
34031
+ __export(relaunch_exports, {
34032
+ JUST_UPDATED_ENV: () => JUST_UPDATED_ENV,
34033
+ consumeJustUpdatedEnv: () => consumeJustUpdatedEnv,
34034
+ encodeJustUpdated: () => encodeJustUpdated,
34035
+ relaunchIntoHome: () => relaunchIntoHome,
34036
+ updateRestartSummary: () => updateRestartSummary
34037
+ });
34038
+ import { spawnSync } from "child_process";
34039
+ function encodeJustUpdated(fromVersion, toVersion) {
34040
+ return `${fromVersion}\u2192${toVersion}`;
34041
+ }
34042
+ function consumeJustUpdatedEnv() {
34043
+ const raw = process.env[JUST_UPDATED_ENV];
34044
+ if (!raw) return null;
34045
+ delete process.env[JUST_UPDATED_ENV];
34046
+ const sep5 = raw.includes("\u2192") ? "\u2192" : "->";
34047
+ const idx = raw.indexOf(sep5);
34048
+ if (idx <= 0) return null;
34049
+ const from = raw.slice(0, idx);
34050
+ const to = raw.slice(idx + sep5.length);
34051
+ if (!from || !to) return null;
34052
+ return { from, to };
34053
+ }
34054
+ function updateRestartSummary(toVersion) {
34055
+ return `Restart NTRP to use v${toVersion}`;
34056
+ }
34057
+ async function relaunchIntoHome(opts) {
34058
+ const { stopSessionTranscript: stopSessionTranscript2 } = await Promise.resolve().then(() => (init_transcript(), transcript_exports));
34059
+ const { close: close2 } = await Promise.resolve().then(() => (init_connection(), connection_exports));
34060
+ stopSessionTranscript2();
34061
+ await close2();
34062
+ try {
34063
+ opts.rl?.pause();
34064
+ } catch {
34065
+ }
34066
+ const result = spawnSync(process.execPath, process.argv.slice(1), {
34067
+ stdio: "inherit",
34068
+ env: {
34069
+ ...process.env,
34070
+ [JUST_UPDATED_ENV]: encodeJustUpdated(opts.fromVersion, opts.toVersion)
34071
+ }
34072
+ });
34073
+ if (result.error) {
34074
+ try {
34075
+ opts.rl?.resume();
34076
+ } catch {
34077
+ }
34078
+ return "failed";
34079
+ }
34080
+ process.exit(result.status ?? 0);
34081
+ return "failed";
34082
+ }
34083
+ var JUST_UPDATED_ENV;
34084
+ var init_relaunch = __esm({
34085
+ "src/update/relaunch.ts"() {
34086
+ "use strict";
34087
+ JUST_UPDATED_ENV = "NTRP_JUST_UPDATED";
34088
+ }
34089
+ });
34090
+
33302
34091
  // src/commands/update.ts
33303
34092
  var update_exports = {};
33304
34093
  __export(update_exports, {
33305
34094
  handler: () => handler43
33306
34095
  });
33307
- import { spawnSync } from "child_process";
33308
- import chalk69 from "chalk";
34096
+ import { spawnSync as spawnSync2 } from "child_process";
34097
+ import chalk71 from "chalk";
33309
34098
  function tailLines(text, count = 5) {
33310
34099
  return text.split("\n").map((line) => line.trimEnd()).filter((line) => line.length > 0).slice(-count).join("\n");
33311
34100
  }
33312
34101
  function runGlobalInstall() {
33313
- const result = spawnSync(
34102
+ if (process.env.NTRP_UPDATE_NPM_STUB === "1") {
34103
+ return { ok: true, output: "stub" };
34104
+ }
34105
+ const result = spawnSync2(
33314
34106
  "npm",
33315
34107
  ["install", "-g", `${NPM_PACKAGE}@latest`],
33316
34108
  {
@@ -33321,19 +34113,19 @@ function runGlobalInstall() {
33321
34113
  const output = [result.stdout, result.stderr].filter(Boolean).join("\n");
33322
34114
  return { ok: result.status === 0, output };
33323
34115
  }
33324
- async function handler43(_args, _ctx) {
34116
+ async function handler43(_args, ctx) {
33325
34117
  const current = getInstalledVersion();
33326
34118
  const latest = await fetchLatestVersion(1e4);
33327
34119
  if (!latest) {
33328
34120
  console.log();
33329
- console.log(chalk69.yellow(" Could not reach the npm registry."));
33330
- console.log(chalk69.dim(` Try manually: npm install -g ${NPM_PACKAGE}`));
34121
+ console.log(chalk71.yellow(" Could not reach the npm registry."));
34122
+ console.log(chalk71.dim(` Try manually: npm install -g ${NPM_PACKAGE}`));
33331
34123
  console.log();
33332
34124
  return;
33333
34125
  }
33334
34126
  if (!isNewerVersion(latest, current)) {
33335
34127
  console.log();
33336
- console.log(chalk69.green(` \u2713 You are on the latest version (v${current})`));
34128
+ console.log(chalk71.green(` \u2713 You are on the latest version (v${current})`));
33337
34129
  console.log();
33338
34130
  return;
33339
34131
  }
@@ -33342,24 +34134,39 @@ async function handler43(_args, _ctx) {
33342
34134
  const { ok, output } = runGlobalInstall();
33343
34135
  if (ok) {
33344
34136
  invalidateUpdateCheckCache();
33345
- console.log(chalk69.green(` \u2713 Updated! Restart NTRP to use v${latest}`));
34137
+ if (ctx.oneShot) {
34138
+ console.log(chalk71.green(` \u2713 Updated! ${updateRestartSummary(latest)}`));
34139
+ console.log();
34140
+ return;
34141
+ }
33346
34142
  console.log();
34143
+ const failed = await relaunchIntoHome({
34144
+ fromVersion: current,
34145
+ toVersion: latest,
34146
+ rl: ctx.rl
34147
+ });
34148
+ if (failed) {
34149
+ const restart = updateRestartSummary(latest);
34150
+ console.log(chalk71.green(` \u2713 Updated! ${restart}`));
34151
+ console.log();
34152
+ return restart;
34153
+ }
33347
34154
  return;
33348
34155
  }
33349
34156
  const lower = output.toLowerCase();
33350
34157
  if (lower.includes("eacces") || lower.includes("permission denied") || lower.includes("eperm")) {
33351
- console.log(chalk69.red(` Could not install ${NPM_PACKAGE} (permission denied).`));
33352
- console.log(chalk69.dim(` Try: sudo npm install -g ${NPM_PACKAGE}`));
33353
- console.log(chalk69.dim(` Or fix npm global permissions: ${PERMISSIONS_URL}`));
34158
+ console.log(chalk71.red(` Could not install ${NPM_PACKAGE} (permission denied).`));
34159
+ console.log(chalk71.dim(` Try: sudo npm install -g ${NPM_PACKAGE}`));
34160
+ console.log(chalk71.dim(` Or fix npm global permissions: ${PERMISSIONS_URL}`));
33354
34161
  console.log();
33355
34162
  return;
33356
34163
  }
33357
34164
  const detail = tailLines(output);
33358
- console.log(chalk69.red(` Could not install ${NPM_PACKAGE}.`));
34165
+ console.log(chalk71.red(` Could not install ${NPM_PACKAGE}.`));
33359
34166
  if (detail) {
33360
- console.log(chalk69.dim(` ${detail.split("\n").join("\n ")}`));
34167
+ console.log(chalk71.dim(` ${detail.split("\n").join("\n ")}`));
33361
34168
  }
33362
- console.log(chalk69.dim(` Try manually: npm install -g ${NPM_PACKAGE}`));
34169
+ console.log(chalk71.dim(` Try manually: npm install -g ${NPM_PACKAGE}`));
33363
34170
  console.log();
33364
34171
  }
33365
34172
  var PERMISSIONS_URL;
@@ -33368,16 +34175,17 @@ var init_update = __esm({
33368
34175
  "use strict";
33369
34176
  init_update_check();
33370
34177
  init_registry();
34178
+ init_relaunch();
33371
34179
  init_version();
33372
34180
  PERMISSIONS_URL = "https://docs.npmjs.com/resolving-eacces-permissions-errors-when-installing-packages-globally";
33373
34181
  }
33374
34182
  });
33375
34183
 
33376
34184
  // src/output/progress-report.ts
33377
- import chalk70 from "chalk";
34185
+ import chalk72 from "chalk";
33378
34186
  function printCard(title, rows) {
33379
34187
  const inner = CARD_W - 4;
33380
- const border = chalk70.dim;
34188
+ const border = chalk72.dim;
33381
34189
  console.log();
33382
34190
  console.log(` ${border(`\u256D${"\u2500".repeat(CARD_W - 2)}\u256E`)}`);
33383
34191
  console.log(` ${border("\u2502 ")}${padRight(sectionHeading(title), inner)}${border(" \u2502")}`);
@@ -33393,7 +34201,7 @@ function formatTokens(n) {
33393
34201
  return String(n);
33394
34202
  }
33395
34203
  function sparkline(values) {
33396
- if (values.length === 0) return chalk70.dim("(no activity yet)");
34204
+ if (values.length === 0) return chalk72.dim("(no activity yet)");
33397
34205
  const max = Math.max(...values, 1);
33398
34206
  const blocks = ["\u2581", "\u2582", "\u2583", "\u2584", "\u2585", "\u2586", "\u2587", "\u2588"];
33399
34207
  return values.map((v) => {
@@ -33402,7 +34210,7 @@ function sparkline(values) {
33402
34210
  }).join("");
33403
34211
  }
33404
34212
  function formatMemberSince(iso) {
33405
- if (!iso) return chalk70.dim("\u2014");
34213
+ if (!iso) return chalk72.dim("\u2014");
33406
34214
  const d = new Date(iso);
33407
34215
  return d.toLocaleDateString(void 0, { month: "short", day: "numeric", year: "numeric" });
33408
34216
  }
@@ -33424,25 +34232,25 @@ function renderProgressReport() {
33424
34232
  const nextLabel = bank.next_milestone ? `${formatHoursLabel(bank.total_hours)} \u2192 ${formatHoursLabel(bank.next_milestone.hours)}` : `${formatHoursLabel(bank.total_hours)} saved`;
33425
34233
  const bar = inlineBar(bank.progress_pct, 18);
33426
34234
  printCard("Progress", [
33427
- `${chalk70.dim("Hours saved")} ${paint("accent", formatHoursLabel(bank.total_hours))} ${bar}`,
33428
- `${chalk70.dim("Next milestone")} ${bank.next_milestone ? paint("accent", bank.next_milestone.title) : chalk70.dim("all complete")}`,
33429
- `${chalk70.dim("Member since")} ${formatMemberSince(usage4.first_active_at)}`,
33430
- `${chalk70.dim("Last active")} ${formatMemberSince(usage4.last_active_at)}`
34235
+ `${chalk72.dim("Hours saved")} ${paint("accent", formatHoursLabel(bank.total_hours))} ${bar}`,
34236
+ `${chalk72.dim("Next milestone")} ${bank.next_milestone ? paint("accent", bank.next_milestone.title) : chalk72.dim("all complete")}`,
34237
+ `${chalk72.dim("Member since")} ${formatMemberSince(usage4.first_active_at)}`,
34238
+ `${chalk72.dim("Last active")} ${formatMemberSince(usage4.last_active_at)}`
33431
34239
  ]);
33432
34240
  if (bank.perspective_line) {
33433
- console.log(` ${chalk70.dim(bank.perspective_line)}`);
34241
+ console.log(` ${chalk72.dim(bank.perspective_line)}`);
33434
34242
  }
33435
34243
  printCard("Activity", [
33436
- `${chalk70.dim("Sessions")} ${chalk70.bold(String(summary.total_sessions_on_disk))} total \xB7 ${summary.sessions_with_work} with analysis \xB7 ${usage4.sessions_closed} closed`,
33437
- `${chalk70.dim("Diagnoses")} ${chalk70.bold(String(usage4.diagnoses))}`,
33438
- `${chalk70.dim("Metrics runs")} ${chalk70.bold(String(usage4.metrics_runs))}`,
33439
- `${chalk70.dim("Deliverables")} ${chalk70.bold(String(usage4.deliverables))}`,
33440
- `${chalk70.dim("AI exchanges")} ${chalk70.bold(String(usage4.nl_exchanges))}`
34244
+ `${chalk72.dim("Sessions")} ${chalk72.bold(String(summary.total_sessions_on_disk))} total \xB7 ${summary.sessions_with_work} with analysis \xB7 ${usage4.sessions_closed} closed`,
34245
+ `${chalk72.dim("Diagnoses")} ${chalk72.bold(String(usage4.diagnoses))}`,
34246
+ `${chalk72.dim("Metrics runs")} ${chalk72.bold(String(usage4.metrics_runs))}`,
34247
+ `${chalk72.dim("Deliverables")} ${chalk72.bold(String(usage4.deliverables))}`,
34248
+ `${chalk72.dim("AI exchanges")} ${chalk72.bold(String(usage4.nl_exchanges))}`
33441
34249
  ]);
33442
34250
  const totalTokens = usage4.input_tokens + usage4.output_tokens;
33443
34251
  printCard("AI usage", [
33444
- `${chalk70.dim("LLM calls")} ${chalk70.bold(String(usage4.llm_calls))}`,
33445
- `${chalk70.dim("Tokens")} ${chalk70.bold(formatTokens(totalTokens))} in+out (${formatTokens(usage4.input_tokens)} in \xB7 ${formatTokens(usage4.output_tokens)} out)`
34252
+ `${chalk72.dim("LLM calls")} ${chalk72.bold(String(usage4.llm_calls))}`,
34253
+ `${chalk72.dim("Tokens")} ${chalk72.bold(formatTokens(totalTokens))} in+out (${formatTokens(usage4.input_tokens)} in \xB7 ${formatTokens(usage4.output_tokens)} out)`
33446
34254
  ]);
33447
34255
  const weeks = [...usage4.weekly].sort((a, b) => a.week.localeCompare(b.week)).slice(-8);
33448
34256
  const weekHours = weeks.map((w) => w.minutes_saved / 60);
@@ -33451,25 +34259,25 @@ function renderProgressReport() {
33451
34259
  console.log(` ${sectionHeading("Weekly hours saved")}`);
33452
34260
  console.log(` ${sparkline(weekHours)}`);
33453
34261
  if (weeks.length > 0) {
33454
- console.log(` ${chalk70.dim(weekLabels.join(" "))}`);
34262
+ console.log(` ${chalk72.dim(weekLabels.join(" "))}`);
33455
34263
  }
33456
34264
  console.log();
33457
34265
  console.log(` ${sectionHeading("Onboarding")}`);
33458
34266
  for (const m of ACTIVITY_MILESTONES) {
33459
34267
  const unlocked = state2.milestones_unlocked.includes(m.id);
33460
- const mark = unlocked ? badge("DONE", "success") : chalk70.dim("\u25CB");
33461
- console.log(` ${mark} ${chalk70.dim(m.title.padEnd(16))} ${unlocked ? chalk70.dim(m.message) : chalk70.dim("Type /deepdive")}`);
34268
+ const mark = unlocked ? badge("DONE", "success") : chalk72.dim("\u25CB");
34269
+ console.log(` ${mark} ${chalk72.dim(m.title.padEnd(16))} ${unlocked ? chalk72.dim(m.message) : chalk72.dim("Type /deepdive")}`);
33462
34270
  }
33463
34271
  console.log();
33464
34272
  console.log(` ${sectionHeading("Milestones")}`);
33465
34273
  for (const m of TIME_MILESTONES) {
33466
34274
  const unlocked = state2.milestones_unlocked.includes(m.id);
33467
34275
  const pct = Math.min(100, bank.total_hours / m.hours * 100);
33468
- const mark = unlocked ? badge("DONE", "success") : bank.total_hours >= m.hours * 0.85 ? badge("NEAR", "warning") : chalk70.dim("\u25CB");
34276
+ const mark = unlocked ? badge("DONE", "success") : bank.total_hours >= m.hours * 0.85 ? badge("NEAR", "warning") : chalk72.dim("\u25CB");
33469
34277
  const barW = 12;
33470
- const mBar = unlocked ? chalk70.hex("#22c55e")("\u2588".repeat(barW)) : scoreBar(pct, bank.total_hours >= m.hours ? "green" : pct >= 50 ? "yellow" : "red", barW);
34278
+ const mBar = unlocked ? chalk72.hex("#22c55e")("\u2588".repeat(barW)) : scoreBar(pct, bank.total_hours >= m.hours ? "green" : pct >= 50 ? "yellow" : "red", barW);
33471
34279
  const label = `${m.title}`.padEnd(16);
33472
- console.log(` ${mark} ${chalk70.dim(label)} ${mBar} ${chalk70.dim(`${m.hours}h`)}`);
34280
+ console.log(` ${mark} ${chalk72.dim(label)} ${mBar} ${chalk72.dim(`${m.hours}h`)}`);
33473
34281
  }
33474
34282
  console.log();
33475
34283
  }
@@ -33493,15 +34301,15 @@ var progress_exports = {};
33493
34301
  __export(progress_exports, {
33494
34302
  handler: () => handler44
33495
34303
  });
33496
- import chalk71 from "chalk";
34304
+ import chalk73 from "chalk";
33497
34305
  function printProgressResetPreamble() {
33498
34306
  console.log();
33499
- console.log(" " + chalk71.yellow.bold("This will permanently remove:"));
33500
- console.log(" " + chalk71.dim(" \u2022 Hours saved and milestone unlocks"));
33501
- console.log(" " + chalk71.dim(" \u2022 Usage counters and weekly activity totals"));
33502
- console.log(" " + chalk71.dim(" \u2022 Credit history used to prevent duplicates"));
34307
+ console.log(" " + chalk73.yellow.bold("This will permanently remove:"));
34308
+ console.log(" " + chalk73.dim(" \u2022 Hours saved and milestone unlocks"));
34309
+ console.log(" " + chalk73.dim(" \u2022 Usage counters and weekly activity totals"));
34310
+ console.log(" " + chalk73.dim(" \u2022 Credit history used to prevent duplicates"));
33503
34311
  console.log();
33504
- console.log(" " + chalk71.dim("Kept: install identity (install.json)"));
34312
+ console.log(" " + chalk73.dim("Kept: install identity (install.json)"));
33505
34313
  console.log();
33506
34314
  }
33507
34315
  function showProgress() {
@@ -33519,7 +34327,7 @@ async function handleReset(ctx, confirmedFlag) {
33519
34327
  const bank = getTimeBankSummary();
33520
34328
  if (bank.total_minutes <= 0) {
33521
34329
  console.log();
33522
- console.log(" " + chalk71.dim("No progress to reset."));
34330
+ console.log(" " + chalk73.dim("No progress to reset."));
33523
34331
  console.log();
33524
34332
  return "No progress to reset";
33525
34333
  }
@@ -33536,7 +34344,7 @@ async function handleReset(ctx, confirmedFlag) {
33536
34344
  }
33537
34345
  resetProgress();
33538
34346
  console.log();
33539
- console.log(" " + paint("accent", "\u2713 Progress reset") + chalk71.dim(" \u2014 hours and milestones are cleared."));
34347
+ console.log(" " + paint("accent", "\u2713 Progress reset") + chalk73.dim(" \u2014 hours and milestones are cleared."));
33540
34348
  console.log();
33541
34349
  return "Progress reset";
33542
34350
  }
@@ -33548,7 +34356,7 @@ async function handler44(args, ctx) {
33548
34356
  }
33549
34357
  if (sub && sub !== "reset") {
33550
34358
  console.log();
33551
- console.log(" " + chalk71.dim("Unknown subcommand. Type ") + paint("accent", "/progress") + chalk71.dim(" or ") + paint("accent", "/progress reset") + chalk71.dim("."));
34359
+ console.log(" " + chalk73.dim("Unknown subcommand. Type ") + paint("accent", "/progress") + chalk73.dim(" or ") + paint("accent", "/progress reset") + chalk73.dim("."));
33552
34360
  console.log();
33553
34361
  return;
33554
34362
  }
@@ -33571,7 +34379,7 @@ var deepdive_exports = {};
33571
34379
  __export(deepdive_exports, {
33572
34380
  handler: () => handler45
33573
34381
  });
33574
- import chalk72 from "chalk";
34382
+ import chalk74 from "chalk";
33575
34383
  function printCatalog2() {
33576
34384
  console.log();
33577
34385
  console.log(" " + sectionHeading("Vital signs"));
@@ -33581,7 +34389,7 @@ function printCatalog2() {
33581
34389
  console.log();
33582
34390
  console.log(" " + sectionHeading("SaaS metrics"));
33583
34391
  console.log(
33584
- " " + chalk72.dim("Core tour: ") + CORE_DECK_IDS.filter((id) => getMetricExplainer(id)?.kind === "saas").map((id) => paint("accent", id)).join(chalk72.dim(" \xB7 "))
34392
+ " " + chalk74.dim("Core tour: ") + CORE_DECK_IDS.filter((id) => getMetricExplainer(id)?.kind === "saas").map((id) => paint("accent", id)).join(chalk74.dim(" \xB7 "))
33585
34393
  );
33586
34394
  console.log();
33587
34395
  for (const e of listMetricExplainers("saas")) {
@@ -33590,7 +34398,7 @@ function printCatalog2() {
33590
34398
  console.log();
33591
34399
  console.log(" " + sectionHeading("How to use NTRP"));
33592
34400
  console.log(
33593
- " " + chalk72.dim("After vitals in the tour: ") + GUIDE_DECK_IDS.map((id) => paint("accent", id)).join(chalk72.dim(" \xB7 ")) + chalk72.dim(" \xB7 ") + paint("accent", "/deepdive guide")
34401
+ " " + chalk74.dim("After vitals in the tour: ") + GUIDE_DECK_IDS.map((id) => paint("accent", id)).join(chalk74.dim(" \xB7 ")) + chalk74.dim(" \xB7 ") + paint("accent", "/deepdive guide")
33594
34402
  );
33595
34403
  console.log();
33596
34404
  for (const s of listGuideSlides()) {
@@ -33598,14 +34406,14 @@ function printCatalog2() {
33598
34406
  }
33599
34407
  console.log();
33600
34408
  console.log(
33601
- " " + chalk72.dim("Usage: ") + paint("accent", "/deepdive") + chalk72.dim(" \xB7 ") + paint("accent", "/deepdive <metric>") + chalk72.dim(" \xB7 ") + paint("accent", "/deepdive guide") + chalk72.dim(" \xB7 ") + paint("accent", "/deepdive list")
34409
+ " " + chalk74.dim("Usage: ") + paint("accent", "/deepdive") + chalk74.dim(" \xB7 ") + paint("accent", "/deepdive <metric>") + chalk74.dim(" \xB7 ") + paint("accent", "/deepdive guide") + chalk74.dim(" \xB7 ") + paint("accent", "/deepdive list")
33602
34410
  );
33603
34411
  console.log();
33604
34412
  }
33605
34413
  function printUnknown(query) {
33606
34414
  console.log();
33607
34415
  console.log(
33608
- " " + chalk72.dim("Unknown slide ") + bold(query) + chalk72.dim(" \u2014 try ") + paint("accent", "/deepdive list") + chalk72.dim(" or ") + paint("accent", "/deepdive guide") + chalk72.dim(".")
34416
+ " " + chalk74.dim("Unknown slide ") + bold(query) + chalk74.dim(" \u2014 try ") + paint("accent", "/deepdive list") + chalk74.dim(" or ") + paint("accent", "/deepdive guide") + chalk74.dim(".")
33609
34417
  );
33610
34418
  console.log();
33611
34419
  }
@@ -33674,22 +34482,90 @@ var init_deepdive = __esm({
33674
34482
  }
33675
34483
  });
33676
34484
 
34485
+ // src/commands/thinkwithme.ts
34486
+ var thinkwithme_exports = {};
34487
+ __export(thinkwithme_exports, {
34488
+ handler: () => handler46
34489
+ });
34490
+ import chalk75 from "chalk";
34491
+ async function handler46(args, ctx) {
34492
+ const seedRaw = args.join(" ").trim();
34493
+ const seed = seedRaw ? extractThinkSeed(seedRaw) : void 0;
34494
+ if (ctx.oneShot) {
34495
+ await runOneShot(ctx, seed);
34496
+ return;
34497
+ }
34498
+ await startThinkFlow(ctx, { seed, origin: "command" });
34499
+ }
34500
+ async function runOneShot(ctx, seed) {
34501
+ if (!seed) {
34502
+ console.log();
34503
+ console.log(
34504
+ " " + chalk75.dim("Usage: ") + paint("accent", "ntrp thinkwithme <topic>") + chalk75.dim(" \u2014 or open the REPL and type ") + chalk75.cyan("/thinkwithme") + chalk75.dim(".")
34505
+ );
34506
+ console.log();
34507
+ return;
34508
+ }
34509
+ if (!isAnalysisReady(ctx)) {
34510
+ console.log();
34511
+ console.log(
34512
+ " " + chalk75.dim("No analysis yet. Run ") + chalk75.cyan("ntrp demo --scenario hidden_crisis --no-profile") + chalk75.dim(" then ") + chalk75.cyan("ntrp diagnose") + chalk75.dim(", or use the interactive REPL.")
34513
+ );
34514
+ console.log();
34515
+ process.exitCode = 1;
34516
+ return;
34517
+ }
34518
+ if (!canUseReplAi(ctx)) {
34519
+ console.log();
34520
+ console.log(
34521
+ " " + chalk75.dim("Connect an AI key first: ") + chalk75.cyan("ntrp connect --key <key>")
34522
+ );
34523
+ console.log();
34524
+ process.exitCode = 1;
34525
+ return;
34526
+ }
34527
+ ctx.thinkState = {
34528
+ step: "active",
34529
+ seed,
34530
+ origin: "command",
34531
+ started_at: (/* @__PURE__ */ new Date()).toISOString(),
34532
+ open_questions: [],
34533
+ challenged_assumptions: [],
34534
+ working_hypotheses: []
34535
+ };
34536
+ console.log();
34537
+ console.log(" " + paint("accent", "Think with me"));
34538
+ console.log(" " + chalk75.dim("Seed: ") + seed);
34539
+ console.log();
34540
+ const { runThinkTurn: runThinkTurn2 } = await Promise.resolve().then(() => (init_think(), think_exports));
34541
+ await runThinkTurn2(seed, ctx);
34542
+ }
34543
+ var init_thinkwithme = __esm({
34544
+ "src/commands/thinkwithme.ts"() {
34545
+ "use strict";
34546
+ init_context2();
34547
+ init_repl_api();
34548
+ init_theme();
34549
+ init_think_flow();
34550
+ }
34551
+ });
34552
+
33677
34553
  // src/commands/exports.ts
33678
34554
  var exports_exports = {};
33679
34555
  __export(exports_exports, {
33680
- handler: () => handler46
34556
+ handler: () => handler47
33681
34557
  });
33682
- import chalk73 from "chalk";
33683
- import { existsSync as existsSync30 } from "fs";
34558
+ import chalk76 from "chalk";
34559
+ import { existsSync as existsSync31 } from "fs";
33684
34560
  import { join as join35 } from "path";
33685
34561
  function usage3() {
33686
- console.log(chalk73.dim(" Usage:"));
33687
- console.log(chalk73.dim(" /exports list [kind]"));
33688
- console.log(chalk73.dim(" /exports open"));
33689
- console.log(chalk73.dim(" /exports move <id|filename> <dest-dir>"));
33690
- console.log(chalk73.dim(" /inbox show | set <path> | skill | clear"));
34562
+ console.log(chalk76.dim(" Usage:"));
34563
+ console.log(chalk76.dim(" /exports list [kind]"));
34564
+ console.log(chalk76.dim(" /exports open"));
34565
+ console.log(chalk76.dim(" /exports move <id|filename> <dest-dir>"));
34566
+ console.log(chalk76.dim(" /inbox show | set <path> | skill | clear"));
33691
34567
  }
33692
- async function handler46(args, ctx) {
34568
+ async function handler47(args, ctx) {
33693
34569
  const sub = (args[0] ?? "").toLowerCase();
33694
34570
  if (!sub) {
33695
34571
  printInboxShow();
@@ -33716,7 +34592,7 @@ async function handler46(args, ctx) {
33716
34592
  return await runInboxSet(args.slice(1), ctx);
33717
34593
  case "clear":
33718
34594
  clearAiInboxDir();
33719
- console.log(" " + chalk73.dim("AI inbox cleared. Files on disk were kept."));
34595
+ console.log(" " + chalk76.dim("AI inbox cleared. Files on disk were kept."));
33720
34596
  return "AI inbox cleared";
33721
34597
  default:
33722
34598
  if (!["help", "-h", "--help"].includes(sub)) {
@@ -33732,40 +34608,40 @@ function printInboxShow() {
33732
34608
  const inbox = getAiInboxDir();
33733
34609
  console.log();
33734
34610
  console.log(" " + bold("Exports"));
33735
- console.log(" " + chalk73.dim("Archive: ") + archive);
33736
- console.log(" " + chalk73.dim("Index: ") + archiveIndexPath());
34611
+ console.log(" " + chalk76.dim("Archive: ") + archive);
34612
+ console.log(" " + chalk76.dim("Index: ") + archiveIndexPath());
33737
34613
  if (inbox) {
33738
34614
  console.log(" " + paint("accent", "AI inbox: ") + inbox);
33739
34615
  const latest = inboxLatestHandoffPath();
33740
- if (latest) console.log(" " + chalk73.dim("Latest handoff: ") + latest);
33741
- console.log(" " + chalk73.dim("Finder skill: ") + join35(inbox, "SKILL.md"));
33742
- console.log(" " + chalk73.dim("Reprint: ") + paint("accent", "/inbox skill"));
34616
+ if (latest) console.log(" " + chalk76.dim("Latest handoff: ") + latest);
34617
+ console.log(" " + chalk76.dim("Finder skill: ") + join35(inbox, "SKILL.md"));
34618
+ console.log(" " + chalk76.dim("Reprint: ") + paint("accent", "/inbox skill"));
33743
34619
  } else {
33744
- console.log(" " + chalk73.dim("AI inbox: (not set). Type ") + paint("accent", "/inbox set <folder>"));
34620
+ console.log(" " + chalk76.dim("AI inbox: (not set). Type ") + paint("accent", "/inbox set <folder>"));
33745
34621
  }
33746
34622
  const archLatest = archiveLatestHandoffPath();
33747
34623
  if (archLatest) {
33748
- console.log(" " + chalk73.dim("Archive latest: ") + archLatest);
34624
+ console.log(" " + chalk76.dim("Archive latest: ") + archLatest);
33749
34625
  }
33750
34626
  console.log();
33751
34627
  }
33752
34628
  function printOpen() {
33753
34629
  console.log();
33754
34630
  console.log(" " + bold("Open these paths"));
33755
- console.log(" " + chalk73.dim("INDEX: ") + archiveIndexPath());
34631
+ console.log(" " + chalk76.dim("INDEX: ") + archiveIndexPath());
33756
34632
  const arch = archiveLatestHandoffPath();
33757
- if (arch) console.log(" " + chalk73.dim("Latest handoff: ") + arch);
34633
+ if (arch) console.log(" " + chalk76.dim("Latest handoff: ") + arch);
33758
34634
  const inbox = getAiInboxDir();
33759
34635
  if (inbox) {
33760
- console.log(" " + chalk73.dim("AI inbox: ") + inbox);
34636
+ console.log(" " + chalk76.dim("AI inbox: ") + inbox);
33761
34637
  const latest = inboxLatestHandoffPath();
33762
- if (latest) console.log(" " + chalk73.dim("Inbox latest: ") + latest);
33763
- console.log(" " + chalk73.dim("Pickup skill: ") + join35(inbox, "latest-pickup.md"));
33764
- console.log(" " + chalk73.dim("Finder skill: ") + join35(inbox, "SKILL.md"));
34638
+ if (latest) console.log(" " + chalk76.dim("Inbox latest: ") + latest);
34639
+ console.log(" " + chalk76.dim("Pickup skill: ") + join35(inbox, "latest-pickup.md"));
34640
+ console.log(" " + chalk76.dim("Finder skill: ") + join35(inbox, "SKILL.md"));
33765
34641
  } else {
33766
- console.log(" " + chalk73.dim("AI inbox is not set. Type ") + paint("accent", "/inbox set <folder>"));
34642
+ console.log(" " + chalk76.dim("AI inbox is not set. Type ") + paint("accent", "/inbox set <folder>"));
33767
34643
  const loc = handoffLocations();
33768
- console.log(" " + chalk73.dim("Finder skill: ") + loc.archiveSkill);
34644
+ console.log(" " + chalk76.dim("Finder skill: ") + loc.archiveSkill);
33769
34645
  }
33770
34646
  console.log();
33771
34647
  }
@@ -33773,17 +34649,17 @@ function printList(kind) {
33773
34649
  const items = listExports({ limit: 20, kind: kind || void 0 });
33774
34650
  console.log(" " + bold(kind ? `Recent exports (${kind})` : "Recent exports"));
33775
34651
  if (items.length === 0) {
33776
- console.log(" " + chalk73.dim("None yet. Type /handoff prompt deck to write a handoff."));
34652
+ console.log(" " + chalk76.dim("None yet. Type /handoff prompt deck to write a handoff."));
33777
34653
  console.log();
33778
34654
  return;
33779
34655
  }
33780
34656
  for (const e of items) {
33781
- const title = e.title ? chalk73.dim(` \u2014 ${e.title}`) : "";
33782
- console.log(` ${paint("accent", e.id)} ${e.kind} ${chalk73.dim(e.at)}${title}`);
34657
+ const title = e.title ? chalk76.dim(` \u2014 ${e.title}`) : "";
34658
+ console.log(` ${paint("accent", e.id)} ${e.kind} ${chalk76.dim(e.at)}${title}`);
33783
34659
  console.log(` ${e.path}`);
33784
- if (e.inbox_path) console.log(` ${chalk73.dim("inbox:")} ${e.inbox_path}`);
34660
+ if (e.inbox_path) console.log(` ${chalk76.dim("inbox:")} ${e.inbox_path}`);
33785
34661
  if (e.previous_paths && e.previous_paths.length > 0) {
33786
- console.log(` ${chalk73.dim("was:")} ${e.previous_paths[e.previous_paths.length - 1]}`);
34662
+ console.log(` ${chalk76.dim("was:")} ${e.previous_paths[e.previous_paths.length - 1]}`);
33787
34663
  }
33788
34664
  }
33789
34665
  console.log();
@@ -33791,8 +34667,8 @@ function printList(kind) {
33791
34667
  async function runInboxSet(args, ctx) {
33792
34668
  const pathArg = args.join(" ").trim();
33793
34669
  if (!pathArg) {
33794
- console.error(chalk73.red(" Usage: /inbox set <path>"));
33795
- console.error(chalk73.dim(" Example: /inbox set ~/Documents/Claude/ntrp-inbox"));
34670
+ console.error(chalk76.red(" Usage: /inbox set <path>"));
34671
+ console.error(chalk76.dim(" Example: /inbox set ~/Documents/Claude/ntrp-inbox"));
33796
34672
  if (ctx.oneShot) process.exit(1);
33797
34673
  return;
33798
34674
  }
@@ -33806,25 +34682,25 @@ async function runInboxSet(args, ctx) {
33806
34682
  true
33807
34683
  );
33808
34684
  if (!ok) {
33809
- console.log(" " + chalk73.dim("Cancelled."));
34685
+ console.log(" " + chalk76.dim("Cancelled."));
33810
34686
  return;
33811
34687
  }
33812
34688
  } finally {
33813
34689
  prompts.close();
33814
34690
  }
33815
34691
  } else {
33816
- console.log(" " + chalk73.yellow(`Inbox is outside ~/.ntrp: ${resolved}`));
33817
- console.log(" " + chalk73.dim("Handoffs with analysis text will be written here."));
34692
+ console.log(" " + chalk76.yellow(`Inbox is outside ~/.ntrp: ${resolved}`));
34693
+ console.log(" " + chalk76.dim("Handoffs with analysis text will be written here."));
33818
34694
  }
33819
34695
  }
33820
34696
  const setTo = setAiInboxDir(pathArg);
33821
34697
  const n = syncRecentToInbox(10);
33822
34698
  console.log();
33823
34699
  console.log(" " + paint("accent", "AI inbox set"));
33824
- console.log(" " + chalk73.dim(setTo));
33825
- console.log(" " + chalk73.dim("Point Claude Desktop or another desktop AI at this folder."));
34700
+ console.log(" " + chalk76.dim(setTo));
34701
+ console.log(" " + chalk76.dim("Point Claude Desktop or another desktop AI at this folder."));
33826
34702
  if (n > 0) {
33827
- console.log(" " + chalk73.dim(`Synced ${n} recent export${n === 1 ? "" : "s"} into the inbox.`));
34703
+ console.log(" " + chalk76.dim(`Synced ${n} recent export${n === 1 ? "" : "s"} into the inbox.`));
33828
34704
  }
33829
34705
  printStandingSkill();
33830
34706
  return `AI inbox \u2192 ${setTo}`;
@@ -33833,28 +34709,28 @@ function runMove(args, ctx) {
33833
34709
  const idOrName = args[0];
33834
34710
  const dest = args.slice(1).join(" ").trim();
33835
34711
  if (!idOrName || !dest) {
33836
- console.error(chalk73.red(" Usage: /exports move <id|filename> <dest-dir>"));
34712
+ console.error(chalk76.red(" Usage: /exports move <id|filename> <dest-dir>"));
33837
34713
  if (ctx.oneShot) process.exit(1);
33838
34714
  return;
33839
34715
  }
33840
34716
  try {
33841
34717
  const destDir = resolveUserPath(dest);
33842
- if (!existsSync30(destDir)) {
34718
+ if (!existsSync31(destDir)) {
33843
34719
  }
33844
34720
  const event = moveExport(idOrName, destDir);
33845
34721
  console.log();
33846
34722
  console.log(" " + paint("accent", "Moved export"));
33847
34723
  for (const line of formatExportLocationLines(event)) {
33848
- console.log(" " + chalk73.dim(line));
34724
+ console.log(" " + chalk76.dim(line));
33849
34725
  }
33850
34726
  if (event.previous_paths?.length) {
33851
- console.log(" " + chalk73.dim("Was: ") + event.previous_paths[event.previous_paths.length - 1]);
34727
+ console.log(" " + chalk76.dim("Was: ") + event.previous_paths[event.previous_paths.length - 1]);
33852
34728
  }
33853
- console.log(" " + chalk73.dim(`Trail recorded in ${archiveIndexPath()}`));
34729
+ console.log(" " + chalk76.dim(`Trail recorded in ${archiveIndexPath()}`));
33854
34730
  console.log();
33855
34731
  return `Moved to ${event.path}`;
33856
34732
  } catch (err) {
33857
- console.error(chalk73.red(` ${err instanceof Error ? err.message : String(err)}`));
34733
+ console.error(chalk76.red(` ${err instanceof Error ? err.message : String(err)}`));
33858
34734
  if (ctx.oneShot) process.exit(1);
33859
34735
  }
33860
34736
  }
@@ -33873,9 +34749,9 @@ var init_exports = __esm({
33873
34749
  // src/commands/privacy.ts
33874
34750
  var privacy_exports = {};
33875
34751
  __export(privacy_exports, {
33876
- handler: () => handler47
34752
+ handler: () => handler48
33877
34753
  });
33878
- async function handler47(_args, _ctx) {
34754
+ async function handler48(_args, _ctx) {
33879
34755
  console.log();
33880
34756
  console.log(" " + bold("What leaves this machine"));
33881
34757
  for (const line of PRIVACY_NOTICE_LINES) {
@@ -33980,10 +34856,10 @@ async function resolveHandler(name) {
33980
34856
  try {
33981
34857
  const mod = await importHandler(runtimePath);
33982
34858
  if (!mod) return null;
33983
- const handler49 = mod.handler;
33984
- if (typeof handler49 !== "function") return null;
33985
- entry.handler = handler49;
33986
- return handler49;
34859
+ const handler50 = mod.handler;
34860
+ if (typeof handler50 !== "function") return null;
34861
+ entry.handler = handler50;
34862
+ return handler50;
33987
34863
  } catch (err) {
33988
34864
  console.error(`Failed to load handler for /${name}:`, err);
33989
34865
  return null;
@@ -34083,6 +34959,8 @@ async function importHandler(runtimePath) {
34083
34959
  return Promise.resolve().then(() => (init_progress2(), progress_exports));
34084
34960
  case "../commands/deepdive.js":
34085
34961
  return Promise.resolve().then(() => (init_deepdive(), deepdive_exports));
34962
+ case "../commands/thinkwithme.js":
34963
+ return Promise.resolve().then(() => (init_thinkwithme(), thinkwithme_exports));
34086
34964
  case "../commands/exports.js":
34087
34965
  return Promise.resolve().then(() => (init_exports(), exports_exports));
34088
34966
  case "../commands/privacy.js":
@@ -34549,6 +35427,21 @@ Bare \`/deepdive\` runs the full onboarding tour. Type \`/deepdive guide\` to ju
34549
35427
  Type \`/deepdive handoff\` for the ship-to-Claude slide. Type \`/deepdive <metric>\` to jump to one metric card.
34550
35428
  Type \`/deepdive list\` to print the catalog. Works without an AI key. Re-run anytime from the homescreen.
34551
35429
  Live values overlay when an analysis exists.`
35430
+ },
35431
+ {
35432
+ name: "thinkwithme",
35433
+ raw: `---
35434
+ name: thinkwithme
35435
+ description: Socratic co-thinking channel \u2014 explore and pressure-test
35436
+ section: Navigation
35437
+ args: [topic]
35438
+ handler: ../commands/thinkwithme.ts
35439
+ ---
35440
+
35441
+ Open a dedicated \`think \u203A\` channel to explore ideas, challenge assumptions, and pull evidence from your data.
35442
+ Bare \`/thinkwithme\` enters the channel. Type \`/thinkwithme <topic>\` to seed the first turn.
35443
+ Requires an analysis and an AI key (\`/connect\`). Type \`done\` or \`cancel\` to return to ask \u203A.
35444
+ When you are ready to commit to a plan, say so or the partner can hand off to \`/strategy\`.`
34552
35445
  },
34553
35446
  {
34554
35447
  name: "status",
@@ -34787,11 +35680,11 @@ Cross-provider IDs are rejected. Type \`/provider\` first to switch.`
34787
35680
  name: activate
34788
35681
  description: Enter a license key
34789
35682
  section: Settings
34790
- args: <license>
35683
+ args: [license]
34791
35684
  handler: ../commands/activate.ts
34792
35685
  ---
34793
35686
 
34794
- Activate NTRP with the key from your purchase email. Most commands need a valid license.`
35687
+ Activate NTRP with the key from your purchase email. Type \`/activate\` with no key to paste. Most commands need a valid license.`
34795
35688
  },
34796
35689
  {
34797
35690
  name: "upgrade",
@@ -34836,7 +35729,7 @@ Remaining nuances merge into a custom_context paragraph that flows into all AI s
34836
35729
  });
34837
35730
 
34838
35731
  // src/ai/prompt-parts.ts
34839
- import { existsSync as existsSync31, readFileSync as readFileSync23 } from "fs";
35732
+ import { existsSync as existsSync32, readFileSync as readFileSync23 } from "fs";
34840
35733
  import { join as join36 } from "path";
34841
35734
  function buildCompanyProfileBlock() {
34842
35735
  const p = loadProfile();
@@ -34857,7 +35750,7 @@ function buildCompanyProfileBlock() {
34857
35750
  function loadAnalystFile() {
34858
35751
  const path = join36(ntrpHome(), ANALYST_FILE_NAME);
34859
35752
  try {
34860
- if (!existsSync31(path)) return null;
35753
+ if (!existsSync32(path)) return null;
34861
35754
  const raw = sanitizeExternalText(readFileSync23(path, "utf-8").trim());
34862
35755
  if (!raw) return null;
34863
35756
  if (raw.length <= ANALYST_FILE_MAX_CHARS) return raw;
@@ -35271,11 +36164,11 @@ __export(compute_exports2, {
35271
36164
  isComputeIntent: () => isComputeIntent,
35272
36165
  runConversationCompute: () => runConversationCompute
35273
36166
  });
35274
- import chalk74 from "chalk";
36167
+ import chalk77 from "chalk";
35275
36168
  async function runConversationCompute(ctx) {
35276
36169
  const lens = ctx.scope?.primary_lens ?? ctx.analysis.primary;
35277
36170
  ctx.computeInProgress = true;
35278
- const willAnswer = Boolean(ctx.pendingAsk?.text) && !ctx.strategistState;
36171
+ const willAnswer = Boolean(ctx.pendingAsk?.text) && !ctx.strategistState && ctx.thinkState?.step !== "awaiting_analysis";
35279
36172
  try {
35280
36173
  if (lens === "revenue_metrics") {
35281
36174
  const { runMetricsAnalysis: runMetricsAnalysis2, extractHeadlineMetrics: extractHeadlineMetrics2 } = await Promise.resolve().then(() => (init_metrics_analysis(), metrics_analysis_exports));
@@ -35303,6 +36196,7 @@ async function runConversationCompute(ctx) {
35303
36196
  interactive: !willAnswer
35304
36197
  });
35305
36198
  await resumeQueuedStrategist(ctx);
36199
+ await resumeQueuedThink(ctx);
35306
36200
  await closeComputeTurn(ctx, willAnswer, "revenue_metrics");
35307
36201
  creditGapCompute(ctx);
35308
36202
  creditMetricsComplete(ctx, false);
@@ -35322,11 +36216,12 @@ async function runConversationCompute(ctx) {
35322
36216
  invalidateGapAudit(ctx);
35323
36217
  saveSessionState(ctx);
35324
36218
  await resumeQueuedStrategist(ctx);
36219
+ await resumeQueuedThink(ctx);
35325
36220
  await closeComputeTurn(ctx, willAnswer, "gtm_health");
35326
36221
  creditGapCompute(ctx);
35327
36222
  return typeof summary === "string" ? summary : "Health analysis ready";
35328
36223
  } catch (err) {
35329
- console.error(" " + chalk74.red(String(err.message ?? err)));
36224
+ console.error(" " + chalk77.red(String(err.message ?? err)));
35330
36225
  return;
35331
36226
  } finally {
35332
36227
  ctx.computeInProgress = false;
@@ -35339,9 +36234,16 @@ async function resumeQueuedStrategist(ctx) {
35339
36234
  const { resumeStrategistAfterCompute: resumeStrategistAfterCompute2 } = await Promise.resolve().then(() => (init_strategist_flow(), strategist_flow_exports));
35340
36235
  await resumeStrategistAfterCompute2(ctx);
35341
36236
  }
36237
+ async function resumeQueuedThink(ctx) {
36238
+ if (ctx.thinkState?.step !== "awaiting_analysis") return;
36239
+ ctx.computeInProgress = false;
36240
+ const { resumeThinkAfterCompute: resumeThinkAfterCompute2 } = await Promise.resolve().then(() => (init_think_flow(), think_flow_exports));
36241
+ await resumeThinkAfterCompute2(ctx);
36242
+ }
35342
36243
  async function resumePendingAskAfterCompute(ctx) {
35343
36244
  if (!ctx.pendingAsk?.text) return false;
35344
36245
  if (ctx.strategistState) return false;
36246
+ if (ctx.thinkState?.step === "active" || ctx.thinkState?.step === "awaiting_analysis") return false;
35345
36247
  const { resumePendingAsk: resumePendingAsk2 } = await Promise.resolve().then(() => (init_pending_ask(), pending_ask_exports));
35346
36248
  return resumePendingAsk2(ctx);
35347
36249
  }
@@ -35375,10 +36277,10 @@ __export(ingest_chat_exports, {
35375
36277
  loadDemoFromChat: () => loadDemoFromChat,
35376
36278
  looksLikeFilePath: () => looksLikeFilePath
35377
36279
  });
35378
- import { existsSync as existsSync32 } from "fs";
36280
+ import { existsSync as existsSync33 } from "fs";
35379
36281
  import { basename as basename9, resolve as resolve9 } from "path";
35380
36282
  import { homedir as homedir8 } from "os";
35381
- import chalk75 from "chalk";
36283
+ import chalk78 from "chalk";
35382
36284
  function extractFilePath(input) {
35383
36285
  const trimmed = input.trim();
35384
36286
  const patterns = [
@@ -35395,11 +36297,11 @@ function extractFilePath(input) {
35395
36297
  const m = trimmed.match(re);
35396
36298
  if (m?.[1]) {
35397
36299
  const p = expandPath(m[1]);
35398
- if (existsSync32(p)) return p;
36300
+ if (existsSync33(p)) return p;
35399
36301
  }
35400
36302
  if (!m?.[1] && re.test(trimmed) && trimmed.toLowerCase().endsWith(".csv")) {
35401
36303
  const p = expandPath(trimmed.replace(/^["']|["']$/g, ""));
35402
- if (existsSync32(p)) return p;
36304
+ if (existsSync33(p)) return p;
35403
36305
  }
35404
36306
  }
35405
36307
  return null;
@@ -35413,7 +36315,7 @@ function looksLikeFilePath(input) {
35413
36315
  }
35414
36316
  async function ingestFromChat(ctx, filePath) {
35415
36317
  if (!ctx.rl) {
35416
- console.log(" " + chalk75.red("Ingest confirm requires interactive mode."));
36318
+ console.log(" " + chalk78.red("Ingest confirm requires interactive mode."));
35417
36319
  return false;
35418
36320
  }
35419
36321
  const name = basename9(filePath);
@@ -35421,7 +36323,7 @@ async function ingestFromChat(ctx, filePath) {
35421
36323
  try {
35422
36324
  const ok = await prompts.confirm(`Ingest ${name} as CRM export?`, true);
35423
36325
  if (!ok) {
35424
- console.log(" " + chalk75.dim("Ingest cancelled."));
36326
+ console.log(" " + chalk78.dim("Ingest cancelled."));
35425
36327
  return false;
35426
36328
  }
35427
36329
  } finally {
@@ -35449,7 +36351,7 @@ async function ingestFromChat(ctx, filePath) {
35449
36351
  true
35450
36352
  );
35451
36353
  if (useAi) {
35452
- console.log(" " + chalk75.dim("AI column mapping is not wired to ingest yet \u2014 trying standard ingest."));
36354
+ console.log(" " + chalk78.dim("AI column mapping is not wired to ingest yet \u2014 trying standard ingest."));
35453
36355
  }
35454
36356
  } finally {
35455
36357
  prompts2.close();
@@ -35476,7 +36378,7 @@ async function ingestFromChat(ctx, filePath) {
35476
36378
  invalidateGapAudit(ctx);
35477
36379
  saveSessionState(ctx);
35478
36380
  console.log();
35479
- console.log(" " + paint("accent", "\u2713 Data loaded") + chalk75.dim(` \u2014 ${name}`));
36381
+ console.log(" " + paint("accent", "\u2713 Data loaded") + chalk78.dim(` \u2014 ${name}`));
35480
36382
  recordMessage(ctx, "user", `[ingested ${name}]`);
35481
36383
  recordMessage(ctx, "agent", `Loaded ${name}. Checking what we can analyze\u2026`);
35482
36384
  const audit = await refreshGapAudit(ctx);
@@ -35484,7 +36386,7 @@ async function ingestFromChat(ctx, filePath) {
35484
36386
  if (audit.can_compute && ctx.scope?.confirmed_at) {
35485
36387
  if (ctx.pendingAsk) {
35486
36388
  console.log();
35487
- console.log(" " + chalk75.dim("Computing so I can answer\u2026"));
36389
+ console.log(" " + chalk78.dim("Computing so I can answer\u2026"));
35488
36390
  await runConversationCompute(ctx);
35489
36391
  return true;
35490
36392
  }
@@ -35532,7 +36434,7 @@ async function loadDemoFromChat(ctx, scenario, opts = {}) {
35532
36434
  const { getScenario: getScenario2 } = await Promise.resolve().then(() => (init_scenarios(), scenarios_exports));
35533
36435
  const s = getScenario2(chosen);
35534
36436
  console.log();
35535
- console.log(" " + paint("accent", "Fitting ") + s.label + chalk75.dim(" \u2014 " + s.hook));
36437
+ console.log(" " + paint("accent", "Fitting ") + s.label + chalk78.dim(" \u2014 " + s.hook));
35536
36438
  }
35537
36439
  const { handler: demo } = await Promise.resolve().then(() => (init_generate(), generate_exports));
35538
36440
  const args = ["--no-profile", "--brief"];
@@ -35568,7 +36470,7 @@ async function loadDemoFromChat(ctx, scenario, opts = {}) {
35568
36470
  const shouldAuto = opts.autoCompute || Boolean(ctx.pendingAsk && audit.can_compute && ctx.scope?.confirmed_at);
35569
36471
  if (shouldAuto && audit.can_compute) {
35570
36472
  console.log();
35571
- console.log(" " + chalk75.dim("Computing so I can answer\u2026"));
36473
+ console.log(" " + chalk78.dim("Computing so I can answer\u2026"));
35572
36474
  await runConversationCompute(ctx);
35573
36475
  return true;
35574
36476
  }
@@ -35680,13 +36582,13 @@ __export(demo_fit_exports, {
35680
36582
  resolveDemoScenarioForLoad: () => resolveDemoScenarioForLoad,
35681
36583
  runDemoFitQuiz: () => runDemoFitQuiz
35682
36584
  });
35683
- import chalk76 from "chalk";
36585
+ import chalk79 from "chalk";
35684
36586
  async function runDemoFitQuiz(session, opts = {}) {
35685
36587
  if (opts.intro !== false) {
35686
36588
  console.log();
35687
36589
  console.log(" " + bold("Fit a sample book of business"));
35688
36590
  console.log(
35689
- " " + chalk76.dim(
36591
+ " " + chalk79.dim(
35690
36592
  "No API key needed. Two questions about how you sell, then you pick which of seven sample pipelines feels closest."
35691
36593
  )
35692
36594
  );
@@ -35704,8 +36606,8 @@ async function runDemoFitQuiz(session, opts = {}) {
35704
36606
  );
35705
36607
  const recommended = inferDemoScenario({ salesMotion: motion, dealBand });
35706
36608
  console.log();
35707
- console.log(" " + chalk76.dim("Recommended: ") + paint("accent", getScenario(recommended.scenario).label));
35708
- console.log(" " + chalk76.dim(recommended.reason));
36609
+ console.log(" " + chalk79.dim("Recommended: ") + paint("accent", getScenario(recommended.scenario).label));
36610
+ console.log(" " + chalk79.dim(recommended.reason));
35709
36611
  const scenario = await session.choose(
35710
36612
  "Which of these sample books feels closest to the one you manage?",
35711
36613
  scenarioMenuChoices(),
@@ -35725,8 +36627,8 @@ async function offerFittedDemoAfterOnboard(session, ctx, profile) {
35725
36627
  const s = getScenario(fit.scenario);
35726
36628
  console.log();
35727
36629
  console.log(" " + bold("A sample pipeline that looks like you"));
35728
- console.log(" " + paint("accent", s.label) + chalk76.dim(" \u2014 " + s.hook));
35729
- console.log(" " + chalk76.dim(fit.reason));
36630
+ console.log(" " + paint("accent", s.label) + chalk79.dim(" \u2014 " + s.hook));
36631
+ console.log(" " + chalk79.dim(fit.reason));
35730
36632
  console.log();
35731
36633
  const action = await session.choose(
35732
36634
  "Try NTRP on that book of business?",
@@ -35783,8 +36685,8 @@ async function resolveDemoScenarioForLoad(ctx, opts = {}) {
35783
36685
  if (!opts.forceQuiz && isProfileConfigured(profile) && profile) {
35784
36686
  const fit = await resolveProfileFit(profile, ctx);
35785
36687
  console.log();
35786
- console.log(" " + chalk76.dim("Recommended: ") + paint("accent", getScenario(fit.scenario).label));
35787
- console.log(" " + chalk76.dim(fit.reason));
36688
+ console.log(" " + chalk79.dim("Recommended: ") + paint("accent", getScenario(fit.scenario).label));
36689
+ console.log(" " + chalk79.dim(fit.reason));
35788
36690
  const scenario = await session.choose(
35789
36691
  "Which sample book of business?",
35790
36692
  scenarioMenuChoices(),
@@ -35844,10 +36746,11 @@ __export(first_run_exports, {
35844
36746
  loadFirstRunDemo: () => loadFirstRunDemo,
35845
36747
  markFirstRunCompleted: () => markFirstRunCompleted,
35846
36748
  printFirstRunChip: () => printFirstRunChip,
36749
+ resumeSetupAfterLicense: () => resumeSetupAfterLicense,
35847
36750
  runFirstRunFork: () => runFirstRunFork,
35848
36751
  shouldOfferFirstRunFork: () => shouldOfferFirstRunFork
35849
36752
  });
35850
- import chalk77 from "chalk";
36753
+ import chalk80 from "chalk";
35851
36754
  function hasCompletedFirstRun() {
35852
36755
  return Boolean(getConfigValue(FIRST_RUN_KEY));
35853
36756
  }
@@ -35873,7 +36776,7 @@ async function runFirstRunFork(ctx, options = {}) {
35873
36776
  if (!options.skipBrand) printCenteredLogo();
35874
36777
  console.log();
35875
36778
  console.log(" " + bold("Welcome to NTRP"));
35876
- console.log(" " + chalk77.dim(TAGLINE));
36779
+ console.log(" " + chalk80.dim(TAGLINE));
35877
36780
  console.log();
35878
36781
  try {
35879
36782
  const { offerFirstRunTour: offerFirstRunTour2 } = await Promise.resolve().then(() => (init_metric_tour(), metric_tour_exports));
@@ -35911,18 +36814,18 @@ async function runFirstRunFork(ctx, options = {}) {
35911
36814
  await offerInboxSkillSetup2(session, { beat: "demo" });
35912
36815
  const s = getScenario(picked.scenario);
35913
36816
  console.log();
35914
- console.log(" " + paint("accent", "Loading demo\u2026") + chalk77.dim(" " + s.label + " \u2014 " + s.hook));
36817
+ console.log(" " + paint("accent", "Loading demo\u2026") + chalk80.dim(" " + s.label + " \u2014 " + s.hook));
35915
36818
  console.log();
35916
36819
  markFirstRunCompleted();
35917
36820
  return { choice: "demo", scenario: picked.scenario };
35918
36821
  }
35919
36822
  if (choice === "onboard") {
35920
- console.log(" " + chalk77.dim("Starting guided setup \u2014 key first, then your company profile."));
36823
+ console.log(" " + chalk80.dim("Starting guided setup \u2014 key first, then your company profile."));
35921
36824
  console.log();
35922
36825
  markFirstRunCompleted();
35923
36826
  return { choice: "onboard" };
35924
36827
  }
35925
- console.log(" " + chalk77.dim("Type what you want to look at."));
36828
+ console.log(" " + chalk80.dim("Type what you want to look at."));
35926
36829
  console.log();
35927
36830
  markFirstRunCompleted();
35928
36831
  return { choice: "skip" };
@@ -35932,7 +36835,7 @@ async function runFirstRunFork(ctx, options = {}) {
35932
36835
  }
35933
36836
  function printFirstRunChip() {
35934
36837
  console.log(
35935
- " " + chalk77.dim("No profile yet \u2014 ask a question, type ") + chalk77.cyan("use demo data") + chalk77.dim(", or ") + paint("accent", "/onboard") + chalk77.dim(" to calibrate.")
36838
+ " " + chalk80.dim("No profile yet \u2014 ask a question, type ") + chalk80.cyan("use demo data") + chalk80.dim(", or ") + paint("accent", "/onboard") + chalk80.dim(" to calibrate.")
35936
36839
  );
35937
36840
  console.log();
35938
36841
  }
@@ -35948,9 +36851,6 @@ async function completeInteractiveSetup(ctx, options = {}) {
35948
36851
  await loadFirstRunDemo(ctx, fork.scenario);
35949
36852
  }
35950
36853
  }
35951
- if (!isProfileConfigured()) {
35952
- printFirstRunChip();
35953
- }
35954
36854
  } catch (err) {
35955
36855
  if (err instanceof GlobalReplCommandError) {
35956
36856
  if (err.command === "exit") {
@@ -35966,14 +36866,22 @@ async function completeInteractiveSetup(ctx, options = {}) {
35966
36866
  await runGlobalAdminCommand2(err.command, `/${err.command}`, ctx);
35967
36867
  }
35968
36868
  markFirstRunCompleted();
35969
- if (!isProfileConfigured()) {
35970
- printFirstRunChip();
35971
- }
35972
36869
  return;
35973
36870
  }
35974
36871
  throw err;
35975
36872
  }
35976
36873
  }
36874
+ async function resumeSetupAfterLicense(ctx) {
36875
+ if (!hasValidLicense()) return false;
36876
+ if (!isProfileConfigured() && shouldOfferFirstRunFork()) {
36877
+ ctx.pendingBlockedLine = void 0;
36878
+ await completeInteractiveSetup(ctx, { skipBrand: true });
36879
+ return true;
36880
+ }
36881
+ const { replayPendingBlockedLine: replayPendingBlockedLine2 } = await Promise.resolve().then(() => (init_dispatch(), dispatch_exports));
36882
+ await replayPendingBlockedLine2(ctx);
36883
+ return false;
36884
+ }
35977
36885
  async function loadFirstRunDemo(ctx, scenario) {
35978
36886
  const { handler: demo } = await Promise.resolve().then(() => (init_generate(), generate_exports));
35979
36887
  const ok = await demo(["--no-profile", "--scenario", scenario, "--brief"], ctx);
@@ -36007,6 +36915,7 @@ var init_first_run = __esm({
36007
36915
  init_scenarios();
36008
36916
  init_repl_globals();
36009
36917
  init_global_admin();
36918
+ init_activation();
36010
36919
  FIRST_RUN_KEY = "first-run-completed";
36011
36920
  }
36012
36921
  });
@@ -36014,24 +36923,24 @@ var init_first_run = __esm({
36014
36923
  // src/commands/scratch.ts
36015
36924
  var scratch_exports = {};
36016
36925
  __export(scratch_exports, {
36017
- handler: () => handler48
36926
+ handler: () => handler49
36018
36927
  });
36019
- import chalk78 from "chalk";
36928
+ import chalk81 from "chalk";
36020
36929
  function printScratchPreamble(includeProgress) {
36021
36930
  console.log();
36022
- console.log(" " + chalk78.yellow.bold("This will permanently remove:"));
36023
- console.log(" " + chalk78.dim(" \u2022 API key and all config.json settings"));
36024
- console.log(" " + chalk78.dim(" \u2022 Company profile (you'll re-onboard on next use)"));
36025
- console.log(" " + chalk78.dim(" \u2022 All sessions and datasets"));
36026
- console.log(" " + chalk78.dim(" \u2022 Demo taxonomy cache"));
36931
+ console.log(" " + chalk81.yellow.bold("This will permanently remove:"));
36932
+ console.log(" " + chalk81.dim(" \u2022 API key and all config.json settings"));
36933
+ console.log(" " + chalk81.dim(" \u2022 Company profile (you will set up again in this session)"));
36934
+ console.log(" " + chalk81.dim(" \u2022 All sessions and datasets"));
36935
+ console.log(" " + chalk81.dim(" \u2022 Demo taxonomy cache"));
36027
36936
  if (includeProgress) {
36028
- console.log(" " + chalk78.dim(" \u2022 Progress (hours saved) and install identity"));
36937
+ console.log(" " + chalk81.dim(" \u2022 Progress (hours saved) and install identity"));
36029
36938
  }
36030
36939
  console.log();
36031
36940
  if (includeProgress) {
36032
- console.log(" " + chalk78.dim("Preserved: memory, strategies, wins, knowledge, exports, audit"));
36941
+ console.log(" " + chalk81.dim("Preserved: memory, strategies, wins, knowledge, exports, audit"));
36033
36942
  } else {
36034
- console.log(" " + chalk78.dim("Preserved: progress (hours saved), memory, strategies, wins, knowledge, exports, audit"));
36943
+ console.log(" " + chalk81.dim("Preserved: progress (hours saved), memory, strategies, wins, knowledge, exports, audit"));
36035
36944
  }
36036
36945
  console.log();
36037
36946
  }
@@ -36052,8 +36961,9 @@ function resetContextAfterScratch(ctx) {
36052
36961
  ctx.deliverIntent = false;
36053
36962
  ctx.computeInProgress = false;
36054
36963
  ctx.lastExchange = void 0;
36964
+ ctx.pendingBlockedLine = void 0;
36055
36965
  }
36056
- async function handler48(args, ctx) {
36966
+ async function handler49(args, ctx) {
36057
36967
  const { flags } = parseArgs2(args, ["confirm", "include-progress"]);
36058
36968
  const confirmedFlag = getBool(flags, "confirm");
36059
36969
  const includeProgress = getBool(flags, "include-progress");
@@ -36071,18 +36981,17 @@ async function handler48(args, ctx) {
36071
36981
  resetContextAfterScratch(ctx);
36072
36982
  await rotateToFreshSession(ctx);
36073
36983
  await initSchema();
36074
- console.log();
36075
- const detail = includeProgress ? " \u2014 local config, data, and progress wiped." : " \u2014 local config and data wiped.";
36076
- console.log(" " + paint("accent", "\u2713 Scratch complete") + chalk78.dim(detail));
36077
- console.log();
36078
36984
  if (ctx.oneShot) {
36985
+ console.log();
36986
+ const detail = includeProgress ? " \u2014 local config, data, and progress wiped." : " \u2014 local config and data wiped.";
36987
+ console.log(" " + paint("accent", "\u2713 Scratch complete") + chalk81.dim(detail));
36988
+ console.log();
36079
36989
  console.log(
36080
- " " + chalk78.dim("Run ") + paint("accent", "ntrp") + chalk78.dim(" interactively to complete onboarding.\n")
36990
+ " " + chalk81.dim("Run ") + paint("accent", "ntrp") + chalk81.dim(" interactively to complete onboarding.\n")
36081
36991
  );
36082
36992
  return "Scratch complete";
36083
36993
  }
36084
- console.log(" " + chalk78.dim("Starting onboarding..."));
36085
- console.log();
36994
+ clearSlideScreen();
36086
36995
  const shown = await ensureLicenseActivated(ctx, { exitOnCancel: false });
36087
36996
  if (!hasValidLicense()) {
36088
36997
  return "Scratch complete \u2014 license required";
@@ -36100,6 +37009,7 @@ var init_scratch = __esm({
36100
37009
  init_scratch_wipe();
36101
37010
  init_schema();
36102
37011
  init_theme();
37012
+ init_slides();
36103
37013
  init_activation();
36104
37014
  }
36105
37015
  });
@@ -36115,16 +37025,16 @@ async function runGlobalAdminCommand(command, line, ctx) {
36115
37025
  const args = tokens.slice(1);
36116
37026
  switch (command) {
36117
37027
  case "scratch": {
36118
- const { handler: handler49 } = await Promise.resolve().then(() => (init_scratch(), scratch_exports));
36119
- return handler49(args, ctx);
37028
+ const { handler: handler50 } = await Promise.resolve().then(() => (init_scratch(), scratch_exports));
37029
+ return handler50(args, ctx);
36120
37030
  }
36121
37031
  case "cleanup": {
36122
- const { handler: handler49 } = await Promise.resolve().then(() => (init_cleanup(), cleanup_exports));
36123
- return handler49(args, ctx);
37032
+ const { handler: handler50 } = await Promise.resolve().then(() => (init_cleanup(), cleanup_exports));
37033
+ return handler50(args, ctx);
36124
37034
  }
36125
37035
  case "deactivate-demo": {
36126
- const { handler: handler49 } = await Promise.resolve().then(() => (init_deactivate_demo(), deactivate_demo_exports));
36127
- return handler49(args, ctx);
37036
+ const { handler: handler50 } = await Promise.resolve().then(() => (init_deactivate_demo(), deactivate_demo_exports));
37037
+ return handler50(args, ctx);
36128
37038
  }
36129
37039
  default:
36130
37040
  return void 0;
@@ -36151,8 +37061,13 @@ function resolvePostAction(input) {
36151
37061
  if (cancelled || isCancelledSummary(summary)) return "none";
36152
37062
  if (command === "onboard" && !ctx.replStarted) return "none";
36153
37063
  if (HOME_COMMANDS.has(command)) return "home";
37064
+ if (command === "update" && isUpdateRestartFallback(summary)) return "home";
36154
37065
  return "none";
36155
37066
  }
37067
+ function isUpdateRestartFallback(summary) {
37068
+ if (!summary) return false;
37069
+ return /^Restart NTRP to use v/.test(summary);
37070
+ }
36156
37071
  var HOME_COMMANDS;
36157
37072
  var init_post_action = __esm({
36158
37073
  "src/cli/post-action.ts"() {
@@ -36203,13 +37118,17 @@ var router_exports = {};
36203
37118
  __export(router_exports, {
36204
37119
  conversationRouter: () => conversationRouter
36205
37120
  });
36206
- import chalk79 from "chalk";
37121
+ import chalk82 from "chalk";
36207
37122
  function popModalState(ctx) {
36208
37123
  const popped = [];
36209
37124
  if (ctx.strategistState) {
36210
37125
  ctx.strategistState = void 0;
36211
37126
  popped.push("strategy session");
36212
37127
  }
37128
+ if (ctx.thinkState) {
37129
+ ctx.thinkState = void 0;
37130
+ popped.push("think channel");
37131
+ }
36213
37132
  if (ctx.deliverIntent) {
36214
37133
  ctx.deliverIntent = false;
36215
37134
  popped.push("handoff draft");
@@ -36233,7 +37152,7 @@ async function conversationRouter(input, ctx) {
36233
37152
  if (FRESH_START_RE.test(line)) {
36234
37153
  console.log();
36235
37154
  console.log(
36236
- " " + chalk79.dim("Start a fresh analysis? This keeps prior sessions \u2014 say ") + chalk79.cyan("yes") + chalk79.dim(" to confirm or ") + chalk79.cyan("/home") + chalk79.dim(" for the dashboard.")
37155
+ " " + chalk82.dim("Start a fresh analysis? This keeps prior sessions \u2014 say ") + chalk82.cyan("yes") + chalk82.dim(" to confirm or ") + chalk82.cyan("/home") + chalk82.dim(" for the dashboard.")
36237
37156
  );
36238
37157
  console.log();
36239
37158
  return { handled: true };
@@ -36247,7 +37166,7 @@ async function conversationRouter(input, ctx) {
36247
37166
  const backTo = formatPhaseLabel(resolveConversationPhase(ctx));
36248
37167
  console.log();
36249
37168
  console.log(
36250
- " " + chalk79.dim(`Cancelled \u2014 dropped ${popped.join(" and ")}. Back to `) + chalk79.cyan(backTo) + chalk79.dim(".")
37169
+ " " + chalk82.dim(`Cancelled \u2014 dropped ${popped.join(" and ")}. Back to `) + chalk82.cyan(backTo) + chalk82.dim(".")
36251
37170
  );
36252
37171
  console.log();
36253
37172
  return { handled: true, summary: "Cancelled" };
@@ -36282,6 +37201,10 @@ async function conversationRouter(input, ctx) {
36282
37201
  const summary = await handleStrategizeFlow(line, ctx) ?? void 0;
36283
37202
  return { handled: true, summary };
36284
37203
  }
37204
+ if (phase === "think") {
37205
+ const summary = await handleThinkFlow(line, ctx) ?? void 0;
37206
+ return { handled: true, summary };
37207
+ }
36285
37208
  if (isStrategistIntent(line)) {
36286
37209
  if (phase === "explore" || isAnalysisReady(ctx)) {
36287
37210
  const summary = await startStrategistFlow(ctx, { seed: extractObjectiveSeed(line), origin: "nl" }) ?? void 0;
@@ -36291,6 +37214,15 @@ async function conversationRouter(input, ctx) {
36291
37214
  queueStrategistForAnalysis(ctx, { seed: extractObjectiveSeed(line), origin: "nl" });
36292
37215
  }
36293
37216
  }
37217
+ if (isThinkIntent(line)) {
37218
+ if (phase === "explore" || isAnalysisReady(ctx)) {
37219
+ const summary = await startThinkFlow(ctx, { seed: extractThinkSeed(line), origin: "nl" }) ?? void 0;
37220
+ return { handled: true, summary };
37221
+ }
37222
+ if (phase === "orient" || phase === "scope" || phase === "awaiting_data") {
37223
+ queueThinkForAnalysis(ctx, { seed: extractThinkSeed(line), origin: "nl" });
37224
+ }
37225
+ }
36294
37226
  if (isShipIntent(line) && (phase === "explore" || isAnalysisReady(ctx))) {
36295
37227
  ctx.deliverIntent = true;
36296
37228
  const summary = await handleDeliverFlow(line, ctx) ?? void 0;
@@ -36307,7 +37239,7 @@ async function conversationRouter(input, ctx) {
36307
37239
  }
36308
37240
  if (phase === "compute") {
36309
37241
  console.log();
36310
- console.log(" " + chalk79.dim("Analysis running \u2014 wait for it to finish before typing another question."));
37242
+ console.log(" " + chalk82.dim("Analysis running \u2014 wait for it to finish before typing another question."));
36311
37243
  console.log();
36312
37244
  return { handled: true };
36313
37245
  }
@@ -36341,6 +37273,7 @@ var init_router = __esm({
36341
37273
  init_orchestrator();
36342
37274
  init_handoff_draft();
36343
37275
  init_strategist_flow();
37276
+ init_think_flow();
36344
37277
  init_context2();
36345
37278
  init_demo();
36346
37279
  FRESH_START_RE = /\b(start (over|fresh)|new analysis|start again|reset session)\b/i;
@@ -36354,7 +37287,7 @@ __export(dispatch_exports, {
36354
37287
  dispatch: () => dispatch,
36355
37288
  replayPendingBlockedLine: () => replayPendingBlockedLine
36356
37289
  });
36357
- import chalk80 from "chalk";
37290
+ import chalk83 from "chalk";
36358
37291
  function printLicenseRequired(command) {
36359
37292
  printLicenseBlocked(command);
36360
37293
  }
@@ -36372,7 +37305,7 @@ async function replayPendingBlockedLine(ctx) {
36372
37305
  if (!hasValidLicense()) return false;
36373
37306
  ctx.pendingBlockedLine = void 0;
36374
37307
  console.log();
36375
- console.log(" " + chalk80.dim("Picking up where you left off\u2026"));
37308
+ console.log(" " + chalk83.dim("Picking up where you left off\u2026"));
36376
37309
  console.log();
36377
37310
  await dispatch(line, ctx);
36378
37311
  return true;
@@ -36442,7 +37375,7 @@ async function dispatch(input, ctx) {
36442
37375
  if (tokens.length === 1) {
36443
37376
  if (/^\d$/.test(first)) {
36444
37377
  console.log(
36445
- " " + chalk80.dim("Looks like a menu pick \u2014 run ") + paint("accent", "/new") + chalk80.dim(" to start (pick Demo, then choose your analysis type).")
37378
+ " " + chalk83.dim("Looks like a menu pick \u2014 run ") + paint("accent", "/new") + chalk83.dim(" to start (pick Demo, then choose your analysis type).")
36446
37379
  );
36447
37380
  return { kind: "handled" };
36448
37381
  }
@@ -36465,22 +37398,22 @@ async function dispatch(input, ctx) {
36465
37398
  return { kind: "handled", summary };
36466
37399
  }
36467
37400
  console.log(
36468
- " " + chalk80.dim("Not in Q&A yet. Confirm the scope, load data, and run analysis first. Type ") + paint("accent", "/home") + chalk80.dim(" for status.")
37401
+ " " + chalk83.dim("Not in Q&A yet. Confirm the scope, load data, and run analysis first. Type ") + paint("accent", "/home") + chalk83.dim(" for status.")
36469
37402
  );
36470
37403
  return { kind: "handled" };
36471
37404
  }
36472
37405
  console.log(
36473
- " " + chalk80.dim("Natural-language questions run inside ntrp. Start with ") + paint("accent", "ntrp") + chalk80.dim(" and type a question after analysis.")
37406
+ " " + chalk83.dim("Natural-language questions run inside ntrp. Start with ") + paint("accent", "ntrp") + chalk83.dim(" and type a question after analysis.")
36474
37407
  );
36475
37408
  return { kind: "handled" };
36476
37409
  }
36477
37410
  async function runSlashCommand(name, args, ctx) {
36478
- const handler49 = await resolveHandler(name);
36479
- if (!handler49) {
36480
- console.error(chalk80.red(` Unknown command: /${name}`));
37411
+ const handler50 = await resolveHandler(name);
37412
+ if (!handler50) {
37413
+ console.error(chalk83.red(` Unknown command: /${name}`));
36481
37414
  return void 0;
36482
37415
  }
36483
- const result = await handler49(args, ctx);
37416
+ const result = await handler50(args, ctx);
36484
37417
  return result ?? void 0;
36485
37418
  }
36486
37419
  async function runNaturalLanguage2(input, ctx) {
@@ -36514,7 +37447,7 @@ var init_inline_suggestion = __esm({
36514
37447
  });
36515
37448
 
36516
37449
  // src/conversation/loop-guard.ts
36517
- import chalk81 from "chalk";
37450
+ import chalk84 from "chalk";
36518
37451
  function createLoopGuardState() {
36519
37452
  return { phase: null, stuckTurns: 0 };
36520
37453
  }
@@ -36546,10 +37479,10 @@ function printLoopEscalation(phase) {
36546
37479
  if (!guide) return;
36547
37480
  console.log();
36548
37481
  console.log(
36549
- " " + chalk81.yellow("We seem to be going in circles \u2014 you're in ") + paint("accent", guide.mode) + chalk81.yellow(" mode.")
37482
+ " " + chalk84.yellow("We seem to be going in circles \u2014 you're in ") + paint("accent", guide.mode) + chalk84.yellow(" mode.")
36550
37483
  );
36551
- console.log(" " + chalk81.dim("Right now I can only accept: ") + guide.accepts);
36552
- console.log(" " + chalk81.dim("To leave: ") + guide.leave);
37484
+ console.log(" " + chalk84.dim("Right now I can only accept: ") + guide.accepts);
37485
+ console.log(" " + chalk84.dim("To leave: ") + guide.leave);
36553
37486
  console.log();
36554
37487
  }
36555
37488
  var LOOP_GUARD_THRESHOLD, MODAL_PHASES, PHASE_GUIDES;
@@ -36592,7 +37525,7 @@ __export(welcome_exports, {
36592
37525
  printWelcome: () => printWelcome,
36593
37526
  resolveWelcomeNextAction: () => resolveWelcomeNextAction
36594
37527
  });
36595
- import chalk82 from "chalk";
37528
+ import chalk85 from "chalk";
36596
37529
  function formatHomeEntityCounts(counts) {
36597
37530
  const parts = [];
36598
37531
  const people = counts.people ?? 0;
@@ -36605,11 +37538,26 @@ function formatHomeEntityCounts(counts) {
36605
37538
  if (acts > 0) parts.push(`${acts} ${acts === 1 ? "activity" : "activities"}`);
36606
37539
  return parts.join(" \xB7 ");
36607
37540
  }
36608
- function formatEmptyDataHomeHint(savedSessionCount) {
37541
+ function formatEmptyDataHomeHint(savedSessionCount, opts = {}) {
37542
+ const onboard = opts.includeOnboard === true ? chalk85.dim(", or ") + paint("accent", "/onboard") + chalk85.dim(" to calibrate") : "";
36609
37543
  if (savedSessionCount > 0) {
36610
- return chalk82.dim("Type ") + paint("accent", "use demo data") + chalk82.dim(" to load a sample. Type ") + paint("accent", "/session") + chalk82.dim(" to open a saved session");
37544
+ return chalk85.dim("Type ") + paint("accent", "use demo data") + chalk85.dim(" to load a sample") + onboard + chalk85.dim(". Type ") + paint("accent", "/session") + chalk85.dim(" to open a saved session");
37545
+ }
37546
+ return chalk85.dim("Type ") + paint("accent", "use demo data") + chalk85.dim(" to load a sample pipeline") + onboard;
37547
+ }
37548
+ function ntrpStatusRow(version, update) {
37549
+ if (update && isNewerVersion(update.latest, version)) {
37550
+ return {
37551
+ label: "ntrp",
37552
+ state: badge("UPDATE", "warning"),
37553
+ detail: `v${update.latest} \xB7 type /update`
37554
+ };
36611
37555
  }
36612
- return chalk82.dim("Type ") + paint("accent", "use demo data") + chalk82.dim(" to load a sample pipeline");
37556
+ return {
37557
+ label: "ntrp",
37558
+ state: chalk85.dim(`v${version}`),
37559
+ detail: ""
37560
+ };
36613
37561
  }
36614
37562
  function resolveSessionSummary(input) {
36615
37563
  if (input.scope?.intent_summary?.trim()) return input.scope.intent_summary.trim();
@@ -36644,19 +37592,19 @@ function sessionSummaryText(s) {
36644
37592
  summary: s.summary,
36645
37593
  dataset: s.dataset
36646
37594
  });
36647
- return summary === NO_SUMMARY ? chalk82.dim(summary) : summary;
37595
+ return summary === NO_SUMMARY ? chalk85.dim(summary) : summary;
36648
37596
  }
36649
37597
  function formatLastSessionLine(s, colW, ctx, opts) {
36650
37598
  const phase = sessionPhaseLabel(s, ctx);
36651
- const current = opts?.markCurrent && s.id === ctx?.sessionId ? chalk82.dim(" \xB7 current") : "";
36652
- const meta = `${formatSessionId(s.id, s.name)} ${chalk82.dim("\xB7")} ${chalk82.dim(lensBadgeLabel(s.analysis))} ${chalk82.dim("\xB7")} ${paint("accent", phase)} ${chalk82.dim("\xB7")} ${sessionSummaryText(s)}${current}`;
37599
+ const current = opts?.markCurrent && s.id === ctx?.sessionId ? chalk85.dim(" \xB7 current") : "";
37600
+ const meta = `${formatSessionId(s.id, s.name)} ${chalk85.dim("\xB7")} ${chalk85.dim(lensBadgeLabel(s.analysis))} ${chalk85.dim("\xB7")} ${paint("accent", phase)} ${chalk85.dim("\xB7")} ${sessionSummaryText(s)}${current}`;
36653
37601
  return truncateVisible(` ${meta}`, colW);
36654
37602
  }
36655
37603
  function formatActiveSessionLine(s, colW, ctx, opts) {
36656
37604
  const indent = " ";
36657
37605
  const idPart = formatSessionId(s.id, s.name);
36658
- const status = chalk82.dim(` \xB7 ${sessionStatusSuffix(s)}`);
36659
- const current = opts?.markCurrent && s.id === ctx?.sessionId ? chalk82.dim(" \xB7 current") : "";
37606
+ const status = chalk85.dim(` \xB7 ${sessionStatusSuffix(s)}`);
37607
+ const current = opts?.markCurrent && s.id === ctx?.sessionId ? chalk85.dim(" \xB7 current") : "";
36660
37608
  const suffix = `${status}${current}`;
36661
37609
  const summaryBudget = Math.max(8, colW - visibleWidth(indent) - visibleWidth(idPart) - visibleWidth(suffix) - 2);
36662
37610
  const summaryPart = truncateVisible(sessionSummaryText(s), summaryBudget);
@@ -36665,7 +37613,7 @@ function formatActiveSessionLine(s, colW, ctx, opts) {
36665
37613
  function resolveWelcomeNextAction(input) {
36666
37614
  const { profileReady, hasData, ctx, unfinishedCount, licenseValid } = input;
36667
37615
  if (!licenseValid) {
36668
- return { label: "Next:", command: "/checkout", detail: "signup or paste a key" };
37616
+ return { label: "Next:", command: "/activate", detail: "paste a trial or Pro key" };
36669
37617
  }
36670
37618
  if (!profileReady && !hasData) {
36671
37619
  return { label: "Try:", command: "", detail: 'type what you want to investigate (e.g. "pipeline health")' };
@@ -36697,13 +37645,13 @@ function buildSystemLines(colW, statusRows, recent) {
36697
37645
  lines.push(sectionHeading("System"));
36698
37646
  const labelW = Math.max(...statusRows.map((r) => r.label.length), "last used".length);
36699
37647
  for (const item of statusRows) {
36700
- const label = chalk82.dim(padRight(item.label, labelW));
37648
+ const label = chalk85.dim(padRight(item.label, labelW));
36701
37649
  const state2 = padRight(item.state, 10);
36702
37650
  const detailW = Math.max(1, colW - labelW - 13);
36703
- lines.push(`${label} ${state2} ${chalk82.dim(truncateVisible(item.detail, detailW))}`);
37651
+ lines.push(`${label} ${state2} ${chalk85.dim(truncateVisible(item.detail, detailW))}`);
36704
37652
  }
36705
37653
  if (recent) {
36706
- lines.push(`${chalk82.dim(padRight("last used", labelW))} ${chalk82.dim(recent)}`);
37654
+ lines.push(`${chalk85.dim(padRight("last used", labelW))} ${chalk85.dim(recent)}`);
36707
37655
  }
36708
37656
  return lines;
36709
37657
  }
@@ -36711,10 +37659,10 @@ function buildLastSessionLines(colW, ctx, lastSession, nextAction, emptyDataHint
36711
37659
  const lines = [""];
36712
37660
  lines.push(sectionHeading("Last Session"));
36713
37661
  if (!lastSession) {
36714
- lines.push(` ${chalk82.dim("(none)")}`);
37662
+ lines.push(` ${chalk85.dim("(none)")}`);
36715
37663
  lines.push(
36716
37664
  truncateVisible(
36717
- ` ${nextAction.command ? actionHint(nextAction.label, nextAction.command, nextAction.detail) : `${chalk82.dim(nextAction.label)} ${chalk82.dim(nextAction.detail)}`}`,
37665
+ ` ${nextAction.command ? actionHint(nextAction.label, nextAction.command, nextAction.detail) : `${chalk85.dim(nextAction.label)} ${chalk85.dim(nextAction.detail)}`}`,
36718
37666
  colW
36719
37667
  )
36720
37668
  );
@@ -36728,7 +37676,7 @@ function buildLastSessionLines(colW, ctx, lastSession, nextAction, emptyDataHint
36728
37676
  if (!isCurrent) {
36729
37677
  lines.push(
36730
37678
  truncateVisible(
36731
- ` ${chalk82.dim("Resume:")} ${paint("accent", `/session ${lastSession.id.slice(-4)}`)}`,
37679
+ ` ${chalk85.dim("Resume:")} ${paint("accent", `/session ${lastSession.id.slice(-4)}`)}`,
36732
37680
  colW
36733
37681
  )
36734
37682
  );
@@ -36737,7 +37685,7 @@ function buildLastSessionLines(colW, ctx, lastSession, nextAction, emptyDataHint
36737
37685
  truncateVisible(` ${actionHint(nextAction.label, nextAction.command, nextAction.detail)}`, colW)
36738
37686
  );
36739
37687
  } else {
36740
- lines.push(truncateVisible(` ${chalk82.dim(nextAction.label)} ${chalk82.dim(nextAction.detail)}`, colW));
37688
+ lines.push(truncateVisible(` ${chalk85.dim(nextAction.label)} ${chalk85.dim(nextAction.detail)}`, colW));
36741
37689
  }
36742
37690
  if (isCurrent && emptyDataHint) {
36743
37691
  lines.push(truncateVisible(` ${emptyDataHint}`, colW));
@@ -36748,18 +37696,20 @@ function buildActiveSessionsLines(colW, ctx, activeSessions) {
36748
37696
  const lines = [""];
36749
37697
  lines.push(sectionHeading("Active Sessions"));
36750
37698
  if (activeSessions.length === 0) {
36751
- lines.push(` ${chalk82.dim("(none in progress)")}`);
37699
+ lines.push(` ${chalk85.dim("(none in progress)")}`);
36752
37700
  return lines;
36753
37701
  }
36754
37702
  for (const s of activeSessions.slice(0, 5)) {
36755
37703
  lines.push(formatActiveSessionLine(s, colW, ctx, { markCurrent: true }));
36756
37704
  }
36757
37705
  if (activeSessions.length > 5) {
36758
- lines.push(` ${chalk82.dim(`+${activeSessions.length - 5} more \xB7 `)}${paint("accent", "/session")}`);
37706
+ lines.push(` ${chalk85.dim(`+${activeSessions.length - 5} more \xB7 `)}${paint("accent", "/session")}`);
36759
37707
  }
36760
37708
  return lines;
36761
37709
  }
36762
37710
  async function printWelcome(ctx, version) {
37711
+ const updateForPaint = ctx.updateAvailable;
37712
+ ctx.updateHomePaintedLatest = updateForPaint?.latest;
36763
37713
  const width = termWidth();
36764
37714
  const cardW = resolveCardWidth({ min: 72, max: CARD_MAX_W, margin: CARD_SIDE_MARGIN * 2 });
36765
37715
  const innerW = cardW - 2;
@@ -36810,13 +37760,13 @@ async function printWelcome(ctx, version) {
36810
37760
  const { countAvailableEngines: countAvailableEngines2, formatActiveStack: formatActiveStack2 } = await Promise.resolve().then(() => (init_session_state(), session_state_exports));
36811
37761
  const engineCount = countAvailableEngines2();
36812
37762
  const llmDetail = engineCount === 0 ? "paste a key. Type /connect" : formatActiveStack2(ctx);
36813
- const llmState = engineCount > 0 ? badge("READY", "success") : chalk82.dim("\u2014");
37763
+ const llmState = engineCount > 0 ? badge("READY", "success") : chalk85.dim("\u2014");
36814
37764
  const license = checkLicense();
36815
37765
  let licenseState;
36816
37766
  let licenseDetail;
36817
37767
  if (!license.valid) {
36818
37768
  licenseState = badge("NOT SET", "warning");
36819
- licenseDetail = "type /checkout";
37769
+ licenseDetail = "type /activate";
36820
37770
  } else if (license.edition === "trial" && license.trialPhase === "grace") {
36821
37771
  licenseState = badge("GRACE", "warning");
36822
37772
  licenseDetail = `${license.daysUntilLockout ?? 0} day${license.daysUntilLockout === 1 ? "" : "s"} left on trial`;
@@ -36832,6 +37782,7 @@ async function printWelcome(ctx, version) {
36832
37782
  licenseDetail = license.message;
36833
37783
  }
36834
37784
  const statusRows = [
37785
+ ntrpStatusRow(version, updateForPaint),
36835
37786
  {
36836
37787
  label: "license",
36837
37788
  state: licenseState,
@@ -36860,7 +37811,7 @@ async function printWelcome(ctx, version) {
36860
37811
  unfinishedCount: unfinishedSessions.length,
36861
37812
  licenseValid: license.valid
36862
37813
  });
36863
- const emptyDataHint = !hasData ? formatEmptyDataHomeHint(savedSessions.length) : null;
37814
+ const emptyDataHint = !hasData && license.valid ? formatEmptyDataHomeHint(savedSessions.length, { includeOnboard: !profileReady }) : null;
36864
37815
  const colW = useWideLayout ? leftW : contentW;
36865
37816
  const rightColW = useWideLayout ? rightW : contentW;
36866
37817
  const systemLines = buildSystemLines(colW, statusRows, recent);
@@ -36874,14 +37825,14 @@ async function printWelcome(ctx, version) {
36874
37825
  const logoOffset = " ".repeat(Math.max(0, Math.floor((cardW - maxLogoW) / 2)));
36875
37826
  for (const line of logo) push(logoOffset + line);
36876
37827
  const taglineOffset = " ".repeat(Math.max(0, Math.floor((cardW - visibleWidth(TAGLINE)) / 2)));
36877
- push(taglineOffset + chalk82.dim(TAGLINE));
37828
+ push(taglineOffset + chalk85.dim(TAGLINE));
36878
37829
  push("");
36879
37830
  }
36880
37831
  const versionTag = ` v${version} `;
36881
37832
  const gap = Math.max(0, innerW - versionTag.length);
36882
37833
  const gapL = Math.floor(gap / 2);
36883
37834
  push(
36884
- border(`\u256D${"\u2500".repeat(gapL)}`) + chalk82.dim(versionTag) + border(`${"\u2500".repeat(gap - gapL)}\u256E`)
37835
+ border(`\u256D${"\u2500".repeat(gapL)}`) + chalk85.dim(versionTag) + border(`${"\u2500".repeat(gap - gapL)}\u256E`)
36885
37836
  );
36886
37837
  if (useWideLayout) {
36887
37838
  const leftLines = systemLines;
@@ -36908,21 +37859,21 @@ async function printWelcome(ctx, version) {
36908
37859
  push(border(`\u2570${"\u2500".repeat(innerW)}\u256F`));
36909
37860
  push(
36910
37861
  truncateVisible(
36911
- ` ${paint("accent", "/help")}${chalk82.dim(" commands \xB7 ")}${paint("accent", "/deepdive")}${chalk82.dim(" tour \xB7 ")}${paint("accent", "/progress")}${chalk82.dim(" hours \xB7 ")}${paint("accent", "/session")}${chalk82.dim(" resume")}`,
37862
+ license.valid ? ` ${paint("accent", "/help")}${chalk85.dim(" commands \xB7 ")}${paint("accent", "/deepdive")}${chalk85.dim(" tour \xB7 ")}${paint("accent", "/progress")}${chalk85.dim(" hours \xB7 ")}${paint("accent", "/session")}${chalk85.dim(" resume")}` : ` ${paint("accent", "/help")}${chalk85.dim(" commands \xB7 ")}${paint("accent", "/activate")}${chalk85.dim(" paste a key \xB7 ")}${paint("accent", "/checkout")}${chalk85.dim(" signup \xB7 ")}${paint("accent", "/progress")}${chalk85.dim(" hours")}`,
36912
37863
  cardW
36913
37864
  )
36914
37865
  );
36915
37866
  if (strategyNudge) {
36916
37867
  push(
36917
37868
  truncateVisible(
36918
- ` ${paint("warning", "\u2691")} ${chalk82.dim(strategyNudge.text)} ${chalk82.dim("\xB7")} ${paint("accent", strategyNudge.command)}`,
37869
+ ` ${paint("warning", "\u2691")} ${chalk85.dim(strategyNudge.text)} ${chalk85.dim("\xB7")} ${paint("accent", strategyNudge.command)}`,
36919
37870
  cardW
36920
37871
  )
36921
37872
  );
36922
37873
  } else if (deepdiveNudge) {
36923
37874
  push(
36924
37875
  truncateVisible(
36925
- ` ${paint("warning", "\u2691")} ${chalk82.dim(deepdiveNudge.text)} ${chalk82.dim("\xB7")} ${paint("accent", deepdiveNudge.command)}`,
37876
+ ` ${paint("warning", "\u2691")} ${chalk85.dim(deepdiveNudge.text)} ${chalk85.dim("\xB7")} ${paint("accent", deepdiveNudge.command)}`,
36926
37877
  cardW
36927
37878
  )
36928
37879
  );
@@ -36945,6 +37896,7 @@ var init_welcome = __esm({
36945
37896
  init_verify();
36946
37897
  init_queries();
36947
37898
  init_schema();
37899
+ init_registry();
36948
37900
  NO_SUMMARY = "(no summary)";
36949
37901
  CARD_MAX_W = 128;
36950
37902
  CARD_SIDE_MARGIN = 6;
@@ -37003,6 +37955,21 @@ var init_deepdive_complete = __esm({
37003
37955
  }
37004
37956
  });
37005
37957
 
37958
+ // src/conversation/thinkwithme-complete.ts
37959
+ function thinkwithmeGhostSuffix(line) {
37960
+ if (!/^\/?thinkwithme/i.test(line)) return null;
37961
+ if (/\s/.test(line)) return null;
37962
+ const full = line.startsWith("/") ? "/thinkwithme" : "thinkwithme";
37963
+ if (full.toLowerCase() === line.toLowerCase()) return null;
37964
+ if (!full.toLowerCase().startsWith(line.toLowerCase())) return null;
37965
+ return full.slice(line.length);
37966
+ }
37967
+ var init_thinkwithme_complete = __esm({
37968
+ "src/conversation/thinkwithme-complete.ts"() {
37969
+ "use strict";
37970
+ }
37971
+ });
37972
+
37006
37973
  // src/cli/repl.ts
37007
37974
  var repl_exports = {};
37008
37975
  __export(repl_exports, {
@@ -37014,7 +37981,7 @@ __export(repl_exports, {
37014
37981
  });
37015
37982
  import { createInterface as createInterface2 } from "readline/promises";
37016
37983
  import { clearLine as clearLine2, cursorTo as cursorTo2 } from "readline";
37017
- import chalk83 from "chalk";
37984
+ import chalk86 from "chalk";
37018
37985
  import { join as join37 } from "path";
37019
37986
  function buildPrompt(ctx) {
37020
37987
  return buildConversationPrompt(ctx);
@@ -37047,6 +38014,9 @@ function inlineCommandSuggestion(line) {
37047
38014
  if (/^\/deepdive(\s|$)/i.test(line)) {
37048
38015
  return deepdiveGhostSuffix(line);
37049
38016
  }
38017
+ if (/^\/thinkwithme/i.test(line)) {
38018
+ return thinkwithmeGhostSuffix(line);
38019
+ }
37050
38020
  if (/\s/.test(line)) return null;
37051
38021
  const matches = commandCompletionCandidates().filter((command) => command.startsWith(line));
37052
38022
  if (matches.length === 0) return null;
@@ -37098,12 +38068,12 @@ function renderInlineSuggestion(rl, prompt, ctx) {
37098
38068
  suggestionPainted = suffix !== null;
37099
38069
  clearLine2(process.stdout, 0);
37100
38070
  cursorTo2(process.stdout, 0);
37101
- process.stdout.write(prompt + line + (suffix ? chalk83.dim(suffix) : ""));
38071
+ process.stdout.write(prompt + line + (suffix ? chalk86.dim(suffix) : ""));
37102
38072
  cursorTo2(process.stdout, promptWidth + cursor);
37103
38073
  }
37104
38074
  function appendTurnLine(current, promptLabel, currentSummary) {
37105
- const currentLine = currentSummary ? `${promptLabel} ${current} ${chalk83.white("\u2192")} ${currentSummary}` : `${promptLabel} ${current}`;
37106
- console.log(" " + chalk83.dim(currentLine));
38075
+ const currentLine = currentSummary ? `${promptLabel} ${current} ${chalk86.white("\u2192")} ${currentSummary}` : `${promptLabel} ${current}`;
38076
+ console.log(" " + chalk86.dim(currentLine));
37107
38077
  console.log();
37108
38078
  }
37109
38079
  async function goHome(ctx, version, history, opts) {
@@ -37113,7 +38083,7 @@ async function goHome(ctx, version, history, opts) {
37113
38083
  process.stdout.write("\x1B[2J\x1B[H");
37114
38084
  if (opts?.banner) {
37115
38085
  console.log();
37116
- console.log(" " + paint("accent", "\u2713") + " " + chalk83.dim(opts.banner));
38086
+ console.log(" " + paint("accent", "\u2713") + " " + chalk86.dim(opts.banner));
37117
38087
  }
37118
38088
  await printWelcome(ctx, version);
37119
38089
  }
@@ -37136,11 +38106,11 @@ async function handleDispatchResult(result, ctx, version, history) {
37136
38106
  case "unknown":
37137
38107
  if (result.suggestion) {
37138
38108
  console.log(
37139
- " " + chalk83.red(`Unknown command: ${result.token}.`) + chalk83.dim(" Did you mean ") + paint("accent", result.suggestion) + chalk83.dim("?")
38109
+ " " + chalk86.red(`Unknown command: ${result.token}.`) + chalk86.dim(" Did you mean ") + paint("accent", result.suggestion) + chalk86.dim("?")
37140
38110
  );
37141
38111
  } else {
37142
38112
  console.log(
37143
- " " + chalk83.red(`Unknown command: ${result.token}`) + chalk83.dim(" Type ") + paint("accent", "/help") + chalk83.dim(" to see available commands.")
38113
+ " " + chalk86.red(`Unknown command: ${result.token}`) + chalk86.dim(" Type ") + paint("accent", "/help") + chalk86.dim(" to see available commands.")
37144
38114
  );
37145
38115
  }
37146
38116
  break;
@@ -37164,14 +38134,14 @@ async function runRepl(ctx, version) {
37164
38134
  });
37165
38135
  ctx.rl = rl;
37166
38136
  console.log();
37167
- console.log(" " + chalk83.dim("What do you want to look at?"));
38137
+ console.log(" " + chalk86.dim("What do you want to look at?"));
37168
38138
  console.log();
37169
38139
  if (ctx.pendingUpdateCheck) {
37170
38140
  void ctx.pendingUpdateCheck.then((result) => {
37171
- if (result?.updateAvailable) {
37172
- console.log(` ${formatUpdateNudge(result.current, result.latest)}`);
37173
- console.log();
37174
- }
38141
+ if (!result?.updateAvailable) return;
38142
+ if (result.latest === ctx.updateHomePaintedLatest) return;
38143
+ console.log(` ${formatUpdateNudge(result.current, result.latest)}`);
38144
+ console.log();
37175
38145
  });
37176
38146
  }
37177
38147
  let pendingSuggestionRender = null;
@@ -37206,7 +38176,7 @@ async function runRepl(ctx, version) {
37206
38176
  return;
37207
38177
  }
37208
38178
  sigintPrimed = true;
37209
- console.log("\n " + chalk83.dim("Type /exit to quit, or press Ctrl+C again."));
38179
+ console.log("\n " + chalk86.dim("Type /exit to quit, or press Ctrl+C again."));
37210
38180
  };
37211
38181
  rl.on("SIGINT", sigintHandler);
37212
38182
  function shutdownRepl() {
@@ -37242,7 +38212,7 @@ async function runRepl(ctx, version) {
37242
38212
  if (!typed && !enterAction) {
37243
38213
  clearGhostRowAfterSubmit();
37244
38214
  const coach = consumeOrientEmptyEnterCoach(ctx);
37245
- if (coach) console.log(" " + chalk83.dim(coach));
38215
+ if (coach) console.log(" " + chalk86.dim(coach));
37246
38216
  continue;
37247
38217
  }
37248
38218
  const line = typed || enterAction.submit;
@@ -37293,9 +38263,9 @@ async function runRepl(ctx, version) {
37293
38263
  ctx.wizardDepth = 0;
37294
38264
  ctx.secretInputActive = false;
37295
38265
  if (err instanceof Error && err.message === "Cancelled") {
37296
- console.log(" " + chalk83.dim("Cancelled."));
38266
+ console.log(" " + chalk86.dim("Cancelled."));
37297
38267
  } else {
37298
- console.error(" " + chalk83.red("Error: " + String(err.message ?? err)));
38268
+ console.error(" " + chalk86.red("Error: " + String(err.message ?? err)));
37299
38269
  }
37300
38270
  }
37301
38271
  }
@@ -37321,10 +38291,10 @@ async function runRepl(ctx, version) {
37321
38291
  await closeSession(ctx);
37322
38292
  }
37323
38293
  if (isTranscriptActive(ctx.sessionId)) {
37324
- console.log(" " + chalk83.dim("Transcript: ") + chalk83.dim(transcriptPathForSession(ctx.sessionId)));
37325
- console.log(" " + chalk83.dim("Context brief: ") + chalk83.dim(contextDocPathForSession(ctx.sessionId)));
38294
+ console.log(" " + chalk86.dim("Transcript: ") + chalk86.dim(transcriptPathForSession(ctx.sessionId)));
38295
+ console.log(" " + chalk86.dim("Context brief: ") + chalk86.dim(contextDocPathForSession(ctx.sessionId)));
37326
38296
  }
37327
- console.log(" " + chalk83.dim(randomGoodbye()));
38297
+ console.log(" " + chalk86.dim(randomGoodbye()));
37328
38298
  }
37329
38299
  function printHelpOneShot() {
37330
38300
  printHelp();
@@ -37332,12 +38302,12 @@ function printHelpOneShot() {
37332
38302
  function printHelp() {
37333
38303
  console.log();
37334
38304
  console.log(" " + sectionHeading("Conversation"));
37335
- console.log(" " + chalk83.dim("Type the question. You do not need a slash command."));
37336
- console.log(" " + chalk83.dim("Paste a CSV path or type ") + paint("accent", '"use demo data"') + chalk83.dim(" to load data."));
37337
- console.log(" " + chalk83.dim("After analysis, type questions in English."));
37338
- console.log(" " + chalk83.dim("Type ") + paint("accent", '"how should we fix this?"') + chalk83.dim(" to make a strategy."));
37339
- console.log(" " + chalk83.dim("Type ") + paint("accent", '"ship a board deck"') + chalk83.dim(" to write a handoff."));
37340
- console.log(" " + chalk83.dim("The ") + paint("accent", "ask \u203A") + chalk83.dim(" prompt shows brief or deep. Brief is the default after analysis."));
38305
+ console.log(" " + chalk86.dim("Type the question. You do not need a slash command."));
38306
+ console.log(" " + chalk86.dim("Paste a CSV path or type ") + paint("accent", '"use demo data"') + chalk86.dim(" to load data."));
38307
+ console.log(" " + chalk86.dim("After analysis, type questions in English."));
38308
+ console.log(" " + chalk86.dim("Type ") + paint("accent", '"how should we fix this?"') + chalk86.dim(" to make a strategy."));
38309
+ console.log(" " + chalk86.dim("Type ") + paint("accent", '"ship a board deck"') + chalk86.dim(" to write a handoff."));
38310
+ console.log(" " + chalk86.dim("The ") + paint("accent", "ask \u203A") + chalk86.dim(" prompt shows brief or deep. Brief is the default after analysis."));
37341
38311
  console.log();
37342
38312
  console.log(" " + sectionHeading("Shortcuts"));
37343
38313
  const shortcuts = [
@@ -37353,6 +38323,7 @@ function printHelp() {
37353
38323
  ["/end", "Close the session"],
37354
38324
  ["/recap", "Write a recap"],
37355
38325
  ["/connect", "Connect a key"],
38326
+ ["/activate", "Paste a license key"],
37356
38327
  ["/upgrade", "Change to Pro"],
37357
38328
  ["/checkout", "Open signup"],
37358
38329
  ["/update", "Install the latest version"],
@@ -37361,11 +38332,11 @@ function printHelp() {
37361
38332
  ];
37362
38333
  const maxW = Math.max(...shortcuts.map(([c]) => c.length)) + 2;
37363
38334
  for (const [cmd, desc] of shortcuts) {
37364
- console.log(` ${paint("accent", padRight(cmd, maxW))} ${chalk83.dim(desc)}`);
38335
+ console.log(` ${paint("accent", padRight(cmd, maxW))} ${chalk86.dim(desc)}`);
37365
38336
  }
37366
38337
  console.log();
37367
38338
  console.log(" " + sectionHeading("Teach NTRP"));
37368
- console.log(" " + chalk83.dim("NTRP learns your business over time. There are three ways to teach it:"));
38339
+ console.log(" " + chalk86.dim("NTRP learns your business over time. There are three ways to teach it:"));
37369
38340
  const teach = [
37370
38341
  ["/remember <fact>", "Store a fact, a decision, or a preference"],
37371
38342
  ["/recall [topic]", "Show what NTRP stores about your business"],
@@ -37374,13 +38345,13 @@ function printHelp() {
37374
38345
  ];
37375
38346
  const teachMaxW = Math.max(...teach.map(([c]) => c.length)) + 2;
37376
38347
  for (const [cmd, desc] of teach) {
37377
- console.log(` ${paint("accent", padRight(cmd, teachMaxW))} ${chalk83.dim(desc)}`);
38348
+ console.log(` ${paint("accent", padRight(cmd, teachMaxW))} ${chalk86.dim(desc)}`);
37378
38349
  }
37379
- console.log(" " + chalk83.dim("When a key is connected, NTRP stores a small number of facts when you close a session."));
38350
+ console.log(" " + chalk86.dim("When a key is connected, NTRP stores a small number of facts when you close a session."));
37380
38351
  console.log();
37381
- console.log(" " + chalk83.dim("Factory reset: type ") + paint("accent", "/scratch") + chalk83.dim("."));
38352
+ console.log(" " + chalk86.dim("Factory reset: type ") + paint("accent", "/scratch") + chalk86.dim("."));
37382
38353
  console.log();
37383
- console.log(" " + chalk83.dim("These commands also work: ") + paint("accent", "/new") + chalk83.dim(", ") + paint("accent", "/diagnose") + chalk83.dim(", ") + paint("accent", "/metrics") + chalk83.dim(", ") + paint("accent", "/session") + chalk83.dim("."));
38354
+ console.log(" " + chalk86.dim("These commands also work: ") + paint("accent", "/new") + chalk86.dim(", ") + paint("accent", "/diagnose") + chalk86.dim(", ") + paint("accent", "/metrics") + chalk86.dim(", ") + paint("accent", "/session") + chalk86.dim("."));
37384
38355
  console.log();
37385
38356
  }
37386
38357
  var REPL_BUILTINS, ANSI_PATTERN, GOODBYES, GHOST_HINTS, ghostHintTurn, activeGhostHint, suggestionPainted;
@@ -37408,6 +38379,7 @@ var init_repl = __esm({
37408
38379
  init_welcome();
37409
38380
  init_registry();
37410
38381
  init_deepdive_complete();
38382
+ init_thinkwithme_complete();
37411
38383
  init_inline_suggestion();
37412
38384
  REPL_BUILTINS = [
37413
38385
  "/help",
@@ -37490,7 +38462,7 @@ init_emit();
37490
38462
  init_errors2();
37491
38463
  init_types2();
37492
38464
  init_version();
37493
- import chalk84 from "chalk";
38465
+ import chalk87 from "chalk";
37494
38466
  var VERSION = getInstalledVersion();
37495
38467
  function exitIfVersionFlag(argv) {
37496
38468
  const rest = argv.slice(2).filter((a) => a === "--version" || a === "-v");
@@ -37525,7 +38497,7 @@ async function main() {
37525
38497
  quiet: args.globals.quiet
37526
38498
  });
37527
38499
  if (!ctx.execution.color) {
37528
- chalk84.level = 0;
38500
+ chalk87.level = 0;
37529
38501
  }
37530
38502
  if (args.globals.stdin) {
37531
38503
  args.input = (await readStdin()).trim();
@@ -37538,16 +38510,16 @@ async function main() {
37538
38510
  if (isStructuredOutput(ctx.execution)) {
37539
38511
  emitError(cmd || "ntrp", new NtrpError("license_invalid", lic2.message, 3 /* Auth */));
37540
38512
  }
37541
- console.error(chalk84.red(`
38513
+ console.error(chalk87.red(`
37542
38514
  ${lic2.message}`));
37543
- console.error(chalk84.dim(" Trial's over \u2014 /upgrade and paste your key.\n"));
38515
+ console.error(chalk87.dim(" Trial's over \u2014 /upgrade and paste your key.\n"));
37544
38516
  process.exit(1);
37545
38517
  }
37546
38518
  }
37547
38519
  const PROFILE_HINT_SKIP = /* @__PURE__ */ new Set(["onboard", "setup", "config", "connect", "activate", "help", "home", "exit", "quit", "clear", "profile", "progress", "deepdive"]);
37548
38520
  if (!isProfileConfigured() && !PROFILE_HINT_SKIP.has(cmd) && !ctx.execution.quiet) {
37549
38521
  console.error(
37550
- " " + chalk84.dim("Tip: run ") + paint("accent", "ntrp") + chalk84.dim(" interactively to set up your company profile for richer answers.")
38522
+ " " + chalk87.dim("Tip: run ") + paint("accent", "ntrp") + chalk87.dim(" interactively to set up your company profile for richer answers.")
37551
38523
  );
37552
38524
  }
37553
38525
  const result = await dispatch(args.input, ctx);
@@ -37559,12 +38531,12 @@ async function main() {
37559
38531
  }
37560
38532
  if (result.suggestion) {
37561
38533
  console.error(
37562
- chalk84.red(` Unknown command: ${result.token}.`) + chalk84.dim(" Did you mean ") + paint("accent", result.suggestion) + chalk84.dim("?")
38534
+ chalk87.red(` Unknown command: ${result.token}.`) + chalk87.dim(" Did you mean ") + paint("accent", result.suggestion) + chalk87.dim("?")
37563
38535
  );
37564
38536
  } else {
37565
- console.error(chalk84.red(` Unknown command: ${result.token}`));
38537
+ console.error(chalk87.red(` Unknown command: ${result.token}`));
37566
38538
  }
37567
- console.error(chalk84.dim(" Run 'ntrp' for the interactive prompt."));
38539
+ console.error(chalk87.dim(" Run 'ntrp' for the interactive prompt."));
37568
38540
  process.exit(1);
37569
38541
  break;
37570
38542
  case "help":
@@ -37597,28 +38569,22 @@ async function main() {
37597
38569
  ctx.datasetPath = datasetPathForSession2(ctx.sessionId);
37598
38570
  await setActiveDbPath2(ctx.datasetPath);
37599
38571
  const { completeInteractiveSetup: completeInteractiveSetup2 } = await Promise.resolve().then(() => (init_first_run(), first_run_exports));
37600
- await completeInteractiveSetup2(ctx, { skipBrand: showedActivation });
37601
- const {
37602
- isCacheFresh: isCacheFresh2,
37603
- loadUpdateCheckCache: loadUpdateCheckCache2
37604
- } = await Promise.resolve().then(() => (init_update_check(), update_check_exports));
37605
38572
  const {
37606
- checkForUpdate: checkForUpdate2,
37607
- formatUpdateNudge: formatUpdateNudge2,
37608
- isNewerVersion: isNewerVersion2
38573
+ hydrateUpdateAvailableFromCache: hydrateUpdateAvailableFromCache2,
38574
+ startBackgroundUpdateCheck: startBackgroundUpdateCheck2
37609
38575
  } = await Promise.resolve().then(() => (init_registry(), registry_exports));
37610
- const currentVersion = getInstalledVersion();
37611
- const cachedUpdate = loadUpdateCheckCache2();
37612
- if (isCacheFresh2(cachedUpdate)) {
37613
- if (cachedUpdate.latestVersion && isNewerVersion2(cachedUpdate.latestVersion, currentVersion)) {
37614
- console.log(formatUpdateNudge2(currentVersion, cachedUpdate.latestVersion));
37615
- }
37616
- } else {
37617
- ctx.pendingUpdateCheck = checkForUpdate2({ timeoutMs: 200 });
37618
- }
38576
+ const { consumeJustUpdatedEnv: consumeJustUpdatedEnv2 } = await Promise.resolve().then(() => (init_relaunch(), relaunch_exports));
38577
+ ctx.updateAvailable = hydrateUpdateAvailableFromCache2(VERSION);
38578
+ startBackgroundUpdateCheck2(ctx);
38579
+ await completeInteractiveSetup2(ctx, { skipBrand: showedActivation });
37619
38580
  const { startSessionTranscript: startSessionTranscript2, stopSessionTranscript: stopSessionTranscript2 } = await Promise.resolve().then(() => (init_transcript(), transcript_exports));
37620
38581
  startSessionTranscript2(ctx);
37621
38582
  const { printWelcome: printWelcome2 } = await Promise.resolve().then(() => (init_welcome(), welcome_exports));
38583
+ const justUpdated = consumeJustUpdatedEnv2();
38584
+ if (justUpdated) {
38585
+ console.log();
38586
+ console.log(" " + paint("accent", "\u2713") + " " + chalk87.dim(`Now running v${justUpdated.to}`));
38587
+ }
37622
38588
  await printWelcome2(ctx, VERSION);
37623
38589
  await runRepl(ctx, VERSION);
37624
38590
  stopSessionTranscript2();