@sonnechasser/ntrp 2.2.2 → 2.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.
package/dist/index.js CHANGED
@@ -1584,7 +1584,7 @@ function printGuideCatalogLine(slide) {
1584
1584
  function printDeepdiveHint(metricId, label) {
1585
1585
  const name = label ?? metricId;
1586
1586
  console.log(
1587
- " " + chalk3.dim("How this number works: ") + paint("accent", `/tour ${metricId}`) + chalk3.dim(` \u2014 ${name}`)
1587
+ " " + chalk3.dim(`Ask what ${name.toLowerCase()} means \u2014 or `) + paint("accent", `/tour ${metricId}`) + chalk3.dim(" for the card")
1588
1588
  );
1589
1589
  console.log();
1590
1590
  }
@@ -1987,6 +1987,23 @@ function printHealthSummary(result, _pipelineMetrics) {
1987
1987
  VITAL_SIGN_LABELS[result.gating_vital_sign]
1988
1988
  );
1989
1989
  }
1990
+ function printHealthLine(result) {
1991
+ const score = `${chalk4.bold(String(Math.round(result.overall_score)))}${chalk4.dim("/100")}`;
1992
+ const gloss = voiceHealthGloss(result.overall_status);
1993
+ const parts = [
1994
+ `${chalk4.dim("Health")} ${score} ${statusBadge(result.overall_status)}${gloss ? chalk4.dim(` ${gloss}`) : ""}`,
1995
+ `${chalk4.dim("held back by")} ${paint("accent", VITAL_SIGN_LABELS[result.gating_vital_sign])}`
1996
+ ];
1997
+ if (result.total_value_at_risk != null && result.total_value_at_risk > 0) {
1998
+ parts.push(`${paint("success", formatCurrency(result.total_value_at_risk))} ${chalk4.dim("total at risk")}`);
1999
+ }
2000
+ console.log();
2001
+ console.log(" " + parts.join(chalk4.dim(" \xB7 ")));
2002
+ printDeepdiveHint(
2003
+ result.gating_vital_sign,
2004
+ VITAL_SIGN_LABELS[result.gating_vital_sign]
2005
+ );
2006
+ }
1990
2007
  function printVitalSigns(vitals) {
1991
2008
  console.log();
1992
2009
  printHeading("Vital Signs");
@@ -16931,7 +16948,7 @@ function consumeOrientEmptyEnterCoach(ctx) {
16931
16948
  if (!hasValidLicense()) {
16932
16949
  return "Type /activate to paste a key. Type /checkout if you need to sign up.";
16933
16950
  }
16934
- return "Type a question, type use demo data, or type /tour. Enter alone does not start a step here.";
16951
+ return "Type a question, or type use demo data. Enter alone does not start a step here.";
16935
16952
  }
16936
16953
  function formatPhaseLabel(phase) {
16937
16954
  switch (phase) {
@@ -17555,7 +17572,10 @@ function buildExploreTeachingGhosts(ctx, staticExplore) {
17555
17572
  if (cached2 && cached2.length > 0) {
17556
17573
  const ghosts = asksToGhostHints(cached2);
17557
17574
  const gating = ctx.snapshot.computeResult?.aggregate.gating_vital_sign;
17558
- if (gating) ghosts.push(`try /tour ${gating}`);
17575
+ if (gating) {
17576
+ const label = (VITAL_SIGN_LABELS[gating] ?? gating).toLowerCase();
17577
+ ghosts.push(`try "why is ${label} red?"`);
17578
+ }
17559
17579
  ghosts.push('try "how should we fix this?"');
17560
17580
  return dedupeGhosts(ghosts);
17561
17581
  }
@@ -17566,7 +17586,11 @@ function buildExploreTeachingGhosts(ctx, staticExplore) {
17566
17586
  });
17567
17587
  return dedupeGhosts([
17568
17588
  ...asksToGhostHints(asks),
17569
- `try /tour ${health.gating_vital_sign}`,
17589
+ (() => {
17590
+ const g = health.gating_vital_sign;
17591
+ const label = (VITAL_SIGN_LABELS[g] ?? g).toLowerCase();
17592
+ return `try "why is ${label} red?"`;
17593
+ })(),
17570
17594
  'try "how should we fix this?"'
17571
17595
  ]);
17572
17596
  }
@@ -18334,7 +18358,24 @@ function listMetricExplainers(kind) {
18334
18358
  function getCoreDeckExplainers() {
18335
18359
  return CORE_DECK_IDS.map((id) => BY_ID.get(id)).filter(Boolean);
18336
18360
  }
18337
- var VITALS, SAAS, METRIC_DEFINITIONS, CORE_DECK_IDS, BY_ID, ALIAS_INDEX, SAAS_METRIC_IDS, GATING_LAYER_VISUAL;
18361
+ function buildVitalSignsPromptBlock() {
18362
+ return VITAL_IDS.map((id) => {
18363
+ const m = getMetricExplainer(id);
18364
+ if (!m) {
18365
+ throw new Error(`buildVitalSignsPromptBlock: missing explainer for ${id}`);
18366
+ }
18367
+ if (!m.dollar_label) {
18368
+ throw new Error(`buildVitalSignsPromptBlock: missing dollar_label for ${id}`);
18369
+ }
18370
+ return [
18371
+ `- ${m.id}: ${m.tagline}`,
18372
+ ` Teach: ${m.meaning}`,
18373
+ ` Expert read: ${m.expert_read}`,
18374
+ ` Dollar label: ${m.dollar_label}`
18375
+ ].join("\n");
18376
+ }).join("\n");
18377
+ }
18378
+ var VITALS, SAAS, METRIC_DEFINITIONS, CORE_DECK_IDS, BY_ID, ALIAS_INDEX, VITAL_IDS, SAAS_METRIC_IDS, GATING_LAYER_VISUAL;
18338
18379
  var init_metric_definitions = __esm({
18339
18380
  "src/data/metric-definitions.ts"() {
18340
18381
  "use strict";
@@ -19141,6 +19182,13 @@ var init_metric_definitions = __esm({
19141
19182
  idx.set("thread-depth", "thread_depth");
19142
19183
  return idx;
19143
19184
  })();
19185
+ VITAL_IDS = [
19186
+ "freshness",
19187
+ "flow_rate",
19188
+ "drop_rate",
19189
+ "signal_to_noise",
19190
+ "thread_depth"
19191
+ ];
19144
19192
  SAAS_METRIC_IDS = SAAS.map((m) => m.id);
19145
19193
  GATING_LAYER_VISUAL = {
19146
19194
  kind: "layer_stack",
@@ -25903,8 +25951,8 @@ var init_ghost_hints = __esm({
25903
25951
  PHASE_GHOST_HINTS = {
25904
25952
  orient: [
25905
25953
  'try "pipeline health"',
25906
- "try /tour",
25907
- "try /tour guide",
25954
+ 'try "how healthy is the pipeline?"',
25955
+ 'try "what should I do next?"',
25908
25956
  'try "is our retention real for the board?"',
25909
25957
  'try "what is the most expensive problem to solve?"',
25910
25958
  'try "board deck on Q3"'
@@ -25921,7 +25969,7 @@ var init_ghost_hints = __esm({
25921
25969
  'try "how should we fix this?"',
25922
25970
  'try "which segment is weakest?"',
25923
25971
  'try "what is ARR?"',
25924
- "try /tour freshness",
25972
+ 'try "why is freshness red?"',
25925
25973
  'try "ship a board deck"'
25926
25974
  ]
25927
25975
  };
@@ -36716,7 +36764,7 @@ async function handler19(args, ctx) {
36716
36764
  console.log(chalk51.dim(` Trigger: ${triggerLabel} \u2014 ${play.trigger_condition}`));
36717
36765
  if (play.trigger_vital_sign) {
36718
36766
  console.log(
36719
- chalk51.dim(" How this number works: ") + paint("accent", `/tour ${play.trigger_vital_sign}`)
36767
+ chalk51.dim(" Ask what ") + chalk51.dim(play.trigger_vital_sign.replace(/_/g, " ")) + chalk51.dim(" means \u2014 or ") + paint("accent", `/tour ${play.trigger_vital_sign}`) + chalk51.dim(" for the card")
36720
36768
  );
36721
36769
  }
36722
36770
  console.log();
@@ -40446,7 +40494,8 @@ function getDeepdiveNudge(ctx) {
40446
40494
  if (hasCompletedMetricsTour() || hasSeenDeepdiveHomeNudge()) return null;
40447
40495
  if (!hasAnalysisForDeepdiveNudge(ctx)) return null;
40448
40496
  return {
40449
- text: "Tour \u2014 how we think about the numbers, and how to use NTRP",
40497
+ text: "Ask how healthy the pipeline looks",
40498
+ tip: "Or /tour for the numbers deck",
40450
40499
  command: "/tour"
40451
40500
  };
40452
40501
  }
@@ -43034,6 +43083,7 @@ var init_prompt_parts = __esm({
43034
43083
  init_profile();
43035
43084
  init_store();
43036
43085
  init_gtm_counsel();
43086
+ init_metric_definitions();
43037
43087
  init_playbook();
43038
43088
  init_play_outcomes();
43039
43089
  init_registry2();
@@ -43070,16 +43120,7 @@ Restraint matters: NTRP is a stethoscope, not a surgeon. Observe, connect, and r
43070
43120
  - Observe, connect, recommend \u2014 never execute CRM changes, send email, or claim an action was taken unless a tool result in this conversation confirms it.
43071
43121
  - Weak or empty tool result: vary the arguments or approach once before concluding; if it's still empty, say what you'd need rather than filling the gap with plausible-sounding numbers.
43072
43122
  - Never fabricate CRM records, people, companies, or dollar amounts.`;
43073
- VITAL_SIGNS_BLOCK = `- freshness: Data recency. Low = stale contacts, zombie deals. Dollar value = pipeline at risk from stale accounts.
43074
- Expert read: cut by owner and by stage first \u2014 freshness reds concentrate on people or process, rarely evenly. In a long-cycle enterprise motion 30 quiet days can be normal cadence; in a velocity motion it's a dead deal. A sudden cliff usually means a broken integration or a departed rep, not gradual decay. False positive to check: bulk-imported records nobody has touched yet.
43075
- - flow_rate: Deal velocity. Low = stuck pipeline, slow progression. Dollar value = amount stuck in pipeline.
43076
- Expert read: cut by stage-age, not just deal-age \u2014 find the stage where deals go to die (usually one). Compare stuck-deal age to this company's own median cycle, not a generic norm. Stuck + past-due close dates together signal happy-ears forecasting, a credibility problem before it's a revenue problem.
43077
- - drop_rate: Handoff retention. Low = leads vanishing between marketing and sales. Dollar value = estimated lost revenue at handoff.
43078
- Expert read: this is almost always a systems failure \u2014 routing rules, unassigned territories, dead rep queues, or a sync gap between marketing and CRM \u2014 not lazy reps. First cut by lead source; the leak usually concentrates in one or two sources. The cheapest pipeline this business can buy is the leads it already paid for.
43079
- - signal_to_noise: Activity efficiency. Low = effort aimed at dead ends. Dollar value = cost of misdirected effort.
43080
- Expert read: cut by rep and by account status \u2014 noise usually means reps fishing in the pond they can see (dead accounts they know) because targeting and account lists are stale. Persistent noise is a coverage-model problem, not a coaching problem. Check whether activity is logged against closed or unlinked records \u2014 often a hygiene artifact.
43081
- - thread_depth: Deal resilience. Low = single-threaded deals, fragile pipeline. Dollar value = amount in single-threaded deals.
43082
- Expert read: weight by deal size \u2014 one single-threaded mega-deal outweighs ten small ones. Single-threading late in the cycle is far more dangerous than early. In enterprise motions, thread depth is a leading indicator of slipped quarters: champions change jobs, and there's no second door in.`;
43123
+ VITAL_SIGNS_BLOCK = buildVitalSignsPromptBlock();
43083
43124
  PLAYBOOK_BLOCK = `- "Multi-Thread Your Deals" (id: multi-thread-deals) \u2014 when thread_depth is low
43084
43125
  - "Clean Dead Pipeline" (id: clean-dead-pipeline) \u2014 when freshness is low
43085
43126
  - "Fix the Handoff Gap" (id: fix-handoff-gap) \u2014 when drop_rate is high and the source\u2192owner path is unknown
@@ -45677,12 +45718,69 @@ var init_explore_expand = __esm({
45677
45718
  }
45678
45719
  });
45679
45720
 
45721
+ // src/conversation/health-chat.ts
45722
+ var health_chat_exports = {};
45723
+ __export(health_chat_exports, {
45724
+ isHealthChatPhase: () => isHealthChatPhase,
45725
+ isHealthIntent: () => isHealthIntent,
45726
+ tryHealthChatReadout: () => tryHealthChatReadout
45727
+ });
45728
+ import chalk94 from "chalk";
45729
+ function isHealthIntent(line) {
45730
+ const text = line.trim();
45731
+ if (!text) return false;
45732
+ if (/^(tour|\/tour|deepdive|\/deepdive)\b/i.test(text)) return false;
45733
+ return HEALTH_INTENT_RE.test(text);
45734
+ }
45735
+ function isHealthChatPhase(ctx) {
45736
+ const phase = resolveConversationPhase(ctx);
45737
+ return phase === "explore" || phase === "orient" && isAnalysisReady(ctx);
45738
+ }
45739
+ function tryHealthChatReadout(ctx, line) {
45740
+ if (!isHealthIntent(line)) return false;
45741
+ if (!isHealthChatPhase(ctx)) return false;
45742
+ const aggregate = ctx.snapshot.computeResult?.aggregate;
45743
+ if (!aggregate) {
45744
+ console.log();
45745
+ console.log(
45746
+ " " + chalk94.dim(
45747
+ "No health reading in this session yet. Run analysis first, then ask again."
45748
+ )
45749
+ );
45750
+ console.log();
45751
+ recordMessage(ctx, "user", line);
45752
+ recordMessage(ctx, "agent", "No health reading yet");
45753
+ saveSessionState(ctx);
45754
+ return true;
45755
+ }
45756
+ printHealthLine(aggregate);
45757
+ printVitalSigns(aggregate.vital_signs);
45758
+ recordMessage(ctx, "user", line);
45759
+ recordMessage(
45760
+ ctx,
45761
+ "agent",
45762
+ `Health ${Math.round(aggregate.overall_score)}/100 \xB7 gating ${aggregate.gating_vital_sign}`
45763
+ );
45764
+ saveSessionState(ctx);
45765
+ return true;
45766
+ }
45767
+ var HEALTH_INTENT_RE;
45768
+ var init_health_chat = __esm({
45769
+ "src/conversation/health-chat.ts"() {
45770
+ "use strict";
45771
+ init_context2();
45772
+ init_terminal();
45773
+ init_phase();
45774
+ HEALTH_INTENT_RE = /\b((how|how'?s|how is)\s+(healthy|the\s+pipeline|our\s+pipeline|pipeline\s+health)|pipeline\s+health|show\s+vitals|vital\s+signs?|where\s+are\s+we\s+red|where'?s\s+the\s+red|health\s+check|how\s+healthy)\b/i;
45775
+ }
45776
+ });
45777
+
45680
45778
  // src/conversation/router.ts
45681
45779
  var router_exports = {};
45682
45780
  __export(router_exports, {
45683
45781
  conversationRouter: () => conversationRouter
45684
45782
  });
45685
- import chalk94 from "chalk";
45783
+ import chalk95 from "chalk";
45686
45784
  function popModalState(ctx) {
45687
45785
  const popped = [];
45688
45786
  if (ctx.strategistState) {
@@ -45715,7 +45813,7 @@ function handleBackNavigation(ctx, line) {
45715
45813
  }
45716
45814
  if (phase === "scope") {
45717
45815
  console.log();
45718
- console.log(" " + chalk94.dim("What should we focus on instead?"));
45816
+ console.log(" " + chalk95.dim("What should we focus on instead?"));
45719
45817
  ctx.scope = void 0;
45720
45818
  clearPendingAsk(ctx);
45721
45819
  saveSessionState(ctx);
@@ -45735,7 +45833,7 @@ function handleBackNavigation(ctx, line) {
45735
45833
  printScopeProposal(ctx);
45736
45834
  if (hadData || hadAnalysis) {
45737
45835
  console.log(
45738
- " " + chalk94.dim(
45836
+ " " + chalk95.dim(
45739
45837
  "Focus gate rewound \u2014 loaded data and any analysis stay. `b` does not unload demo data or undo compute."
45740
45838
  )
45741
45839
  );
@@ -45751,7 +45849,7 @@ function handleBackNavigation(ctx, line) {
45751
45849
  recordMessage(ctx, "user", line);
45752
45850
  recordMessage(ctx, "agent", "Strategy objective adjust (back)");
45753
45851
  console.log();
45754
- console.log(" " + chalk94.dim("What is the objective? State a finish line."));
45852
+ console.log(" " + chalk95.dim("What is the objective? State a finish line."));
45755
45853
  console.log();
45756
45854
  return { handled: true, summary: "Awaiting objective" };
45757
45855
  }
@@ -45763,7 +45861,7 @@ function handleBackNavigation(ctx, line) {
45763
45861
  const backTo = formatPhaseLabel(resolveConversationPhase(ctx));
45764
45862
  console.log();
45765
45863
  console.log(
45766
- " " + chalk94.dim(`Back \u2014 dropped ${popped.join(" and ")}. At `) + chalk94.cyan(backTo) + chalk94.dim(".")
45864
+ " " + chalk95.dim(`Back \u2014 dropped ${popped.join(" and ")}. At `) + chalk95.cyan(backTo) + chalk95.dim(".")
45767
45865
  );
45768
45866
  console.log();
45769
45867
  return { handled: true, summary: "Back" };
@@ -45777,7 +45875,7 @@ function handleBackNavigation(ctx, line) {
45777
45875
  const backTo = formatPhaseLabel(resolveConversationPhase(ctx));
45778
45876
  console.log();
45779
45877
  console.log(
45780
- " " + chalk94.dim(`Back \u2014 dropped ${popped.join(" and ")}. At `) + chalk94.cyan(backTo) + chalk94.dim(".")
45878
+ " " + chalk95.dim(`Back \u2014 dropped ${popped.join(" and ")}. At `) + chalk95.cyan(backTo) + chalk95.dim(".")
45781
45879
  );
45782
45880
  console.log();
45783
45881
  return { handled: true, summary: "Back" };
@@ -45821,7 +45919,7 @@ async function conversationRouter(input, ctx) {
45821
45919
  if (!ok) {
45822
45920
  console.log();
45823
45921
  console.log(
45824
- " " + chalk94.dim("Staying on this session. Type ") + chalk94.cyan("/home") + chalk94.dim(" for the dashboard.")
45922
+ " " + chalk95.dim("Staying on this session. Type ") + chalk95.cyan("/home") + chalk95.dim(" for the dashboard.")
45825
45923
  );
45826
45924
  console.log();
45827
45925
  return { handled: true };
@@ -45836,7 +45934,7 @@ async function conversationRouter(input, ctx) {
45836
45934
  }
45837
45935
  console.log();
45838
45936
  console.log(
45839
- " " + chalk94.dim("Start a fresh analysis with ") + chalk94.cyan("/new") + chalk94.dim(" \u2014 or ") + chalk94.cyan("/home") + chalk94.dim(" for the dashboard.")
45937
+ " " + chalk95.dim("Start a fresh analysis with ") + chalk95.cyan("/new") + chalk95.dim(" \u2014 or ") + chalk95.cyan("/home") + chalk95.dim(" for the dashboard.")
45840
45938
  );
45841
45939
  console.log();
45842
45940
  return { handled: true };
@@ -45850,7 +45948,7 @@ async function conversationRouter(input, ctx) {
45850
45948
  const backTo = formatPhaseLabel(resolveConversationPhase(ctx));
45851
45949
  console.log();
45852
45950
  console.log(
45853
- " " + chalk94.dim(`Cancelled \u2014 dropped ${popped.join(" and ")}. Back to `) + chalk94.cyan(backTo) + chalk94.dim(".")
45951
+ " " + chalk95.dim(`Cancelled \u2014 dropped ${popped.join(" and ")}. Back to `) + chalk95.cyan(backTo) + chalk95.dim(".")
45854
45952
  );
45855
45953
  console.log();
45856
45954
  return { handled: true, summary: "Cancelled" };
@@ -45894,6 +45992,12 @@ async function conversationRouter(input, ctx) {
45894
45992
  const summary = await handleKeepGoingLine(ctx, line) ?? void 0;
45895
45993
  return { handled: true, summary };
45896
45994
  }
45995
+ if (phase === "explore" || phase === "orient" && isAnalysisReady(ctx)) {
45996
+ const { tryHealthChatReadout: tryHealthChatReadout2 } = await Promise.resolve().then(() => (init_health_chat(), health_chat_exports));
45997
+ if (tryHealthChatReadout2(ctx, line)) {
45998
+ return { handled: true, summary: "Pipeline health" };
45999
+ }
46000
+ }
45897
46001
  if (phase === "think") {
45898
46002
  const summary = await handleThinkFlow(line, ctx) ?? void 0;
45899
46003
  return { handled: true, summary };
@@ -45932,7 +46036,7 @@ async function conversationRouter(input, ctx) {
45932
46036
  }
45933
46037
  if (phase === "compute") {
45934
46038
  console.log();
45935
- console.log(" " + chalk94.dim("Analysis running \u2014 wait for it to finish before typing another question."));
46039
+ console.log(" " + chalk95.dim("Analysis running \u2014 wait for it to finish before typing another question."));
45936
46040
  console.log();
45937
46041
  return { handled: true };
45938
46042
  }
@@ -45988,7 +46092,7 @@ __export(dispatch_exports, {
45988
46092
  dispatch: () => dispatch,
45989
46093
  replayPendingBlockedLine: () => replayPendingBlockedLine
45990
46094
  });
45991
- import chalk95 from "chalk";
46095
+ import chalk96 from "chalk";
45992
46096
  function printLicenseRequired(command) {
45993
46097
  printLicenseBlocked(command);
45994
46098
  }
@@ -46006,7 +46110,7 @@ async function replayPendingBlockedLine(ctx) {
46006
46110
  if (!hasValidLicense()) return false;
46007
46111
  ctx.pendingBlockedLine = void 0;
46008
46112
  console.log();
46009
- console.log(" " + chalk95.dim("Picking up where you left off\u2026"));
46113
+ console.log(" " + chalk96.dim("Picking up where you left off\u2026"));
46010
46114
  console.log();
46011
46115
  await dispatch(line, ctx);
46012
46116
  return true;
@@ -46076,7 +46180,7 @@ async function dispatch(input, ctx) {
46076
46180
  if (tokens.length === 1) {
46077
46181
  if (/^\d$/.test(first)) {
46078
46182
  console.log(
46079
- " " + chalk95.dim("Looks like a menu pick \u2014 run ") + paint("accent", "/new") + chalk95.dim(" to start (pick Demo, then choose your analysis type).")
46183
+ " " + chalk96.dim("Looks like a menu pick \u2014 run ") + paint("accent", "/new") + chalk96.dim(" to start (pick Demo, then choose your analysis type).")
46080
46184
  );
46081
46185
  return { kind: "handled" };
46082
46186
  }
@@ -46099,19 +46203,19 @@ async function dispatch(input, ctx) {
46099
46203
  return { kind: "handled", summary };
46100
46204
  }
46101
46205
  console.log(
46102
- " " + chalk95.dim("Not in Q&A yet. Confirm the scope, load data, and run analysis first. Type ") + paint("accent", "/home") + chalk95.dim(" for status.")
46206
+ " " + chalk96.dim("Not in Q&A yet. Confirm the scope, load data, and run analysis first. Type ") + paint("accent", "/home") + chalk96.dim(" for status.")
46103
46207
  );
46104
46208
  return { kind: "handled" };
46105
46209
  }
46106
46210
  console.log(
46107
- " " + chalk95.dim("Natural-language questions run inside ntrp. Start with ") + paint("accent", "ntrp") + chalk95.dim(" and type a question after analysis.")
46211
+ " " + chalk96.dim("Natural-language questions run inside ntrp. Start with ") + paint("accent", "ntrp") + chalk96.dim(" and type a question after analysis.")
46108
46212
  );
46109
46213
  return { kind: "handled" };
46110
46214
  }
46111
46215
  async function runSlashCommand(name, args, ctx) {
46112
46216
  const handler54 = await resolveHandler(name);
46113
46217
  if (!handler54) {
46114
- console.error(chalk95.red(` Unknown command: /${name}`));
46218
+ console.error(chalk96.red(` Unknown command: /${name}`));
46115
46219
  return void 0;
46116
46220
  }
46117
46221
  const result = await handler54(args, ctx);
@@ -46148,7 +46252,7 @@ var init_inline_suggestion = __esm({
46148
46252
  });
46149
46253
 
46150
46254
  // src/conversation/loop-guard.ts
46151
- import chalk96 from "chalk";
46255
+ import chalk97 from "chalk";
46152
46256
  function createLoopGuardState() {
46153
46257
  return { phase: null, stuckTurns: 0 };
46154
46258
  }
@@ -46180,10 +46284,10 @@ function printLoopEscalation(phase) {
46180
46284
  if (!guide) return;
46181
46285
  console.log();
46182
46286
  console.log(
46183
- " " + chalk96.yellow("We seem to be going in circles \u2014 you're in ") + paint("accent", guide.mode) + chalk96.yellow(" mode.")
46287
+ " " + chalk97.yellow("We seem to be going in circles \u2014 you're in ") + paint("accent", guide.mode) + chalk97.yellow(" mode.")
46184
46288
  );
46185
- console.log(" " + chalk96.dim("Right now I can only accept: ") + guide.accepts);
46186
- console.log(" " + chalk96.dim("To leave: ") + guide.leave);
46289
+ console.log(" " + chalk97.dim("Right now I can only accept: ") + guide.accepts);
46290
+ console.log(" " + chalk97.dim("To leave: ") + guide.leave);
46187
46291
  console.log();
46188
46292
  }
46189
46293
  var LOOP_GUARD_THRESHOLD, MODAL_PHASES, PHASE_GUIDES;
@@ -46227,7 +46331,7 @@ __export(welcome_exports, {
46227
46331
  resolveWelcomeNextAction: () => resolveWelcomeNextAction,
46228
46332
  staleProcessHomeNotice: () => staleProcessHomeNotice
46229
46333
  });
46230
- import chalk97 from "chalk";
46334
+ import chalk98 from "chalk";
46231
46335
  function formatHomeEntityCounts(counts) {
46232
46336
  const parts = [];
46233
46337
  const people = counts.people ?? 0;
@@ -46241,11 +46345,11 @@ function formatHomeEntityCounts(counts) {
46241
46345
  return parts.join(" \xB7 ");
46242
46346
  }
46243
46347
  function formatEmptyDataHomeHint(savedSessionCount, opts = {}) {
46244
- const onboard = opts.includeOnboard === true ? chalk97.dim(", or ") + paint("accent", "/onboard") + chalk97.dim(" to calibrate") : "";
46348
+ const onboard = opts.includeOnboard === true ? chalk98.dim(", or ") + paint("accent", "/onboard") + chalk98.dim(" to calibrate") : "";
46245
46349
  if (savedSessionCount > 0) {
46246
- return chalk97.dim("Drop a CSV or type ") + paint("accent", "use demo data") + chalk97.dim(" to load a sample") + onboard + chalk97.dim(". Type ") + paint("accent", "/session") + chalk97.dim(" to open a saved session");
46350
+ return chalk98.dim("Drop a CSV or type ") + paint("accent", "use demo data") + chalk98.dim(" to load a sample") + onboard + chalk98.dim(". Type ") + paint("accent", "/session") + chalk98.dim(" to open a saved session");
46247
46351
  }
46248
- return chalk97.dim("Drop a CSV or type ") + paint("accent", "use demo data") + chalk97.dim(" to load a sample pipeline") + onboard;
46352
+ return chalk98.dim("Drop a CSV or type ") + paint("accent", "use demo data") + chalk98.dim(" to load a sample pipeline") + onboard;
46249
46353
  }
46250
46354
  function staleProcessHomeNotice() {
46251
46355
  const running = getInstalledVersion();
@@ -46287,19 +46391,19 @@ function sessionSummaryText(s) {
46287
46391
  summary: s.summary,
46288
46392
  dataset: s.dataset
46289
46393
  });
46290
- return summary === NO_SUMMARY ? chalk97.dim(summary) : summary;
46394
+ return summary === NO_SUMMARY ? chalk98.dim(summary) : summary;
46291
46395
  }
46292
46396
  function formatLastSessionLine(s, colW, ctx, opts) {
46293
46397
  const phase = sessionPhaseLabel(s, ctx);
46294
- const current = opts?.markCurrent && s.id === ctx?.sessionId ? chalk97.dim(" \xB7 current") : "";
46295
- const meta = `${formatSessionId(s.id, s.name)} ${chalk97.dim("\xB7")} ${chalk97.dim(lensBadgeLabel(s.analysis))} ${chalk97.dim("\xB7")} ${paint("accent", phase)} ${chalk97.dim("\xB7")} ${sessionSummaryText(s)}${current}`;
46398
+ const current = opts?.markCurrent && s.id === ctx?.sessionId ? chalk98.dim(" \xB7 current") : "";
46399
+ const meta = `${formatSessionId(s.id, s.name)} ${chalk98.dim("\xB7")} ${chalk98.dim(lensBadgeLabel(s.analysis))} ${chalk98.dim("\xB7")} ${paint("accent", phase)} ${chalk98.dim("\xB7")} ${sessionSummaryText(s)}${current}`;
46296
46400
  return truncateVisible(` ${meta}`, colW);
46297
46401
  }
46298
46402
  function formatActiveSessionLine(s, colW, ctx, opts) {
46299
46403
  const indent = " ";
46300
46404
  const idPart = formatSessionId(s.id, s.name);
46301
- const status = chalk97.dim(` \xB7 ${sessionStatusSuffix(s)}`);
46302
- const current = opts?.markCurrent && s.id === ctx?.sessionId ? chalk97.dim(" \xB7 current") : "";
46405
+ const status = chalk98.dim(` \xB7 ${sessionStatusSuffix(s)}`);
46406
+ const current = opts?.markCurrent && s.id === ctx?.sessionId ? chalk98.dim(" \xB7 current") : "";
46303
46407
  const suffix = `${status}${current}`;
46304
46408
  const summaryBudget = Math.max(8, colW - visibleWidth(indent) - visibleWidth(idPart) - visibleWidth(suffix) - 2);
46305
46409
  const summaryPart = truncateVisible(sessionSummaryText(s), summaryBudget);
@@ -46340,13 +46444,13 @@ function buildSystemLines(colW, statusRows, recent) {
46340
46444
  lines.push(sectionHeading("System"));
46341
46445
  const labelW = Math.max(...statusRows.map((r) => r.label.length), "last used".length);
46342
46446
  for (const item of statusRows) {
46343
- const label = chalk97.dim(padRight(item.label, labelW));
46447
+ const label = chalk98.dim(padRight(item.label, labelW));
46344
46448
  const state2 = padRight(item.state, 10);
46345
46449
  const detailW = Math.max(1, colW - labelW - 13);
46346
- lines.push(`${label} ${state2} ${chalk97.dim(truncateVisible(item.detail, detailW))}`);
46450
+ lines.push(`${label} ${state2} ${chalk98.dim(truncateVisible(item.detail, detailW))}`);
46347
46451
  }
46348
46452
  if (recent) {
46349
- lines.push(`${chalk97.dim(padRight("last used", labelW))} ${chalk97.dim(recent)}`);
46453
+ lines.push(`${chalk98.dim(padRight("last used", labelW))} ${chalk98.dim(recent)}`);
46350
46454
  }
46351
46455
  return lines;
46352
46456
  }
@@ -46354,10 +46458,10 @@ function buildLastSessionLines(colW, ctx, lastSession, nextAction, emptyDataHint
46354
46458
  const lines = [""];
46355
46459
  lines.push(sectionHeading("Last Session"));
46356
46460
  if (!lastSession) {
46357
- lines.push(` ${chalk97.dim("(none)")}`);
46461
+ lines.push(` ${chalk98.dim("(none)")}`);
46358
46462
  lines.push(
46359
46463
  truncateVisible(
46360
- ` ${nextAction.command ? actionHint(nextAction.label, nextAction.command, nextAction.detail) : `${chalk97.dim(nextAction.label)} ${chalk97.dim(nextAction.detail)}`}`,
46464
+ ` ${nextAction.command ? actionHint(nextAction.label, nextAction.command, nextAction.detail) : `${chalk98.dim(nextAction.label)} ${chalk98.dim(nextAction.detail)}`}`,
46361
46465
  colW
46362
46466
  )
46363
46467
  );
@@ -46371,7 +46475,7 @@ function buildLastSessionLines(colW, ctx, lastSession, nextAction, emptyDataHint
46371
46475
  if (!isCurrent) {
46372
46476
  lines.push(
46373
46477
  truncateVisible(
46374
- ` ${chalk97.dim("Resume:")} ${paint("accent", `/session ${lastSession.id.slice(-4)}`)}`,
46478
+ ` ${chalk98.dim("Resume:")} ${paint("accent", `/session ${lastSession.id.slice(-4)}`)}`,
46375
46479
  colW
46376
46480
  )
46377
46481
  );
@@ -46380,7 +46484,7 @@ function buildLastSessionLines(colW, ctx, lastSession, nextAction, emptyDataHint
46380
46484
  truncateVisible(` ${actionHint(nextAction.label, nextAction.command, nextAction.detail)}`, colW)
46381
46485
  );
46382
46486
  } else {
46383
- lines.push(truncateVisible(` ${chalk97.dim(nextAction.label)} ${chalk97.dim(nextAction.detail)}`, colW));
46487
+ lines.push(truncateVisible(` ${chalk98.dim(nextAction.label)} ${chalk98.dim(nextAction.detail)}`, colW));
46384
46488
  }
46385
46489
  if (isCurrent && emptyDataHint) {
46386
46490
  lines.push(truncateVisible(` ${emptyDataHint}`, colW));
@@ -46391,14 +46495,14 @@ function buildActiveSessionsLines(colW, ctx, activeSessions) {
46391
46495
  const lines = [""];
46392
46496
  lines.push(sectionHeading("Active Sessions"));
46393
46497
  if (activeSessions.length === 0) {
46394
- lines.push(` ${chalk97.dim("(none in progress)")}`);
46498
+ lines.push(` ${chalk98.dim("(none in progress)")}`);
46395
46499
  return lines;
46396
46500
  }
46397
46501
  for (const s of activeSessions.slice(0, 5)) {
46398
46502
  lines.push(formatActiveSessionLine(s, colW, ctx, { markCurrent: true }));
46399
46503
  }
46400
46504
  if (activeSessions.length > 5) {
46401
- lines.push(` ${chalk97.dim(`+${activeSessions.length - 5} more \xB7 `)}${paint("accent", "/session")}`);
46505
+ lines.push(` ${chalk98.dim(`+${activeSessions.length - 5} more \xB7 `)}${paint("accent", "/session")}`);
46402
46506
  }
46403
46507
  return lines;
46404
46508
  }
@@ -46486,7 +46590,7 @@ async function printWelcome(ctx, version) {
46486
46590
  const gap = Math.max(0, innerW - versionTag.length);
46487
46591
  const gapL = Math.floor(gap / 2);
46488
46592
  push(
46489
- border(`\u256D${"\u2500".repeat(gapL)}`) + chalk97.dim(versionTag) + border(`${"\u2500".repeat(gap - gapL)}\u256E`)
46593
+ border(`\u256D${"\u2500".repeat(gapL)}`) + chalk98.dim(versionTag) + border(`${"\u2500".repeat(gap - gapL)}\u256E`)
46490
46594
  );
46491
46595
  if (useWideLayout) {
46492
46596
  const leftLines = systemLines;
@@ -46513,7 +46617,7 @@ async function printWelcome(ctx, version) {
46513
46617
  push(border(`\u2570${"\u2500".repeat(innerW)}\u256F`));
46514
46618
  push(
46515
46619
  truncateVisible(
46516
- license.valid ? ` ${paint("accent", "/help")}${chalk97.dim(" commands \xB7 ")}${paint("accent", "/tour")}${chalk97.dim(" tour \xB7 ")}${paint("accent", "/progress")}${chalk97.dim(" hours \xB7 ")}${paint("accent", "/session")}${chalk97.dim(" resume")}` : ` ${paint("accent", "/help")}${chalk97.dim(" commands \xB7 ")}${paint("accent", "/activate")}${chalk97.dim(" paste a key \xB7 ")}${paint("accent", "/checkout")}${chalk97.dim(" signup \xB7 ")}${paint("accent", "/progress")}${chalk97.dim(" hours")}`,
46620
+ license.valid ? ` ${paint("accent", "/help")}${chalk98.dim(" commands \xB7 ")}${paint("accent", "/tour")}${chalk98.dim(" tour \xB7 ")}${paint("accent", "/progress")}${chalk98.dim(" hours \xB7 ")}${paint("accent", "/session")}${chalk98.dim(" resume")}` : ` ${paint("accent", "/help")}${chalk98.dim(" commands \xB7 ")}${paint("accent", "/activate")}${chalk98.dim(" paste a key \xB7 ")}${paint("accent", "/checkout")}${chalk98.dim(" signup \xB7 ")}${paint("accent", "/progress")}${chalk98.dim(" hours")}`,
46517
46621
  cardW
46518
46622
  )
46519
46623
  );
@@ -46524,14 +46628,15 @@ async function printWelcome(ctx, version) {
46524
46628
  if (strategyNudge) {
46525
46629
  push(
46526
46630
  truncateVisible(
46527
- ` ${paint("warning", "\u2691")} ${chalk97.dim(strategyNudge.text)} ${chalk97.dim("\xB7")} ${paint("accent", strategyNudge.command)}`,
46631
+ ` ${paint("warning", "\u2691")} ${chalk98.dim(strategyNudge.text)} ${chalk98.dim("\xB7")} ${paint("accent", strategyNudge.command)}`,
46528
46632
  cardW
46529
46633
  )
46530
46634
  );
46531
46635
  } else if (deepdiveNudge) {
46636
+ const tip = deepdiveNudge.tip ?? deepdiveNudge.command;
46532
46637
  push(
46533
46638
  truncateVisible(
46534
- ` ${paint("warning", "\u2691")} ${chalk97.dim(deepdiveNudge.text)} ${chalk97.dim("\xB7")} ${paint("accent", deepdiveNudge.command)}`,
46639
+ tip ? ` ${paint("warning", "\u2691")} ${chalk98.dim(deepdiveNudge.text)} ${chalk98.dim("\xB7")} ${chalk98.dim(tip)}` : ` ${paint("warning", "\u2691")} ${chalk98.dim(deepdiveNudge.text)}`,
46535
46640
  cardW
46536
46641
  )
46537
46642
  );
@@ -46539,7 +46644,7 @@ async function printWelcome(ctx, version) {
46539
46644
  } else if (voiceNudge) {
46540
46645
  push(
46541
46646
  truncateVisible(
46542
- ` ${paint("warning", "\u2691")} ${chalk97.dim(voiceNudge.text)} ${chalk97.dim("\xB7")} ${paint("accent", voiceNudge.command)}`,
46647
+ ` ${paint("warning", "\u2691")} ${chalk98.dim(voiceNudge.text)} ${chalk98.dim("\xB7")} ${paint("accent", voiceNudge.command)}`,
46543
46648
  cardW
46544
46649
  )
46545
46650
  );
@@ -46727,7 +46832,7 @@ __export(repl_exports, {
46727
46832
  });
46728
46833
  import { createInterface as createInterface2 } from "readline/promises";
46729
46834
  import { clearLine as clearLine2, cursorTo as cursorTo2 } from "readline";
46730
- import chalk98 from "chalk";
46835
+ import chalk99 from "chalk";
46731
46836
  import { join as join42 } from "path";
46732
46837
  function buildPrompt(ctx) {
46733
46838
  return buildConversationPrompt(ctx);
@@ -46819,12 +46924,12 @@ function renderInlineSuggestion(rl, prompt, ctx) {
46819
46924
  suggestionPainted = suffix !== null;
46820
46925
  clearLine2(process.stdout, 0);
46821
46926
  cursorTo2(process.stdout, 0);
46822
- process.stdout.write(prompt + line + (suffix ? chalk98.dim(suffix) : ""));
46927
+ process.stdout.write(prompt + line + (suffix ? chalk99.dim(suffix) : ""));
46823
46928
  cursorTo2(process.stdout, promptWidth + cursor);
46824
46929
  }
46825
46930
  function appendTurnLine(current, promptLabel, currentSummary) {
46826
- const currentLine = currentSummary ? `${promptLabel} ${current} ${chalk98.white("\u2192")} ${currentSummary}` : `${promptLabel} ${current}`;
46827
- console.log(" " + chalk98.dim(currentLine));
46931
+ const currentLine = currentSummary ? `${promptLabel} ${current} ${chalk99.white("\u2192")} ${currentSummary}` : `${promptLabel} ${current}`;
46932
+ console.log(" " + chalk99.dim(currentLine));
46828
46933
  console.log();
46829
46934
  }
46830
46935
  async function goHome(ctx, version, history, opts) {
@@ -46834,7 +46939,7 @@ async function goHome(ctx, version, history, opts) {
46834
46939
  clearTerminalHome();
46835
46940
  if (opts?.banner) {
46836
46941
  console.log();
46837
- console.log(" " + paint("accent", "\u2713") + " " + chalk98.dim(opts.banner));
46942
+ console.log(" " + paint("accent", "\u2713") + " " + chalk99.dim(opts.banner));
46838
46943
  }
46839
46944
  await printWelcome(ctx, version);
46840
46945
  }
@@ -46857,11 +46962,11 @@ async function handleDispatchResult(result, ctx, version, history) {
46857
46962
  case "unknown":
46858
46963
  if (result.suggestion) {
46859
46964
  console.log(
46860
- " " + chalk98.red(`Unknown command: ${result.token}.`) + chalk98.dim(" Did you mean ") + paint("accent", result.suggestion) + chalk98.dim("?")
46965
+ " " + chalk99.red(`Unknown command: ${result.token}.`) + chalk99.dim(" Did you mean ") + paint("accent", result.suggestion) + chalk99.dim("?")
46861
46966
  );
46862
46967
  } else {
46863
46968
  console.log(
46864
- " " + chalk98.red(`Unknown command: ${result.token}`) + chalk98.dim(" Type ") + paint("accent", "/help") + chalk98.dim(" to see available commands.")
46969
+ " " + chalk99.red(`Unknown command: ${result.token}`) + chalk99.dim(" Type ") + paint("accent", "/help") + chalk99.dim(" to see available commands.")
46865
46970
  );
46866
46971
  }
46867
46972
  break;
@@ -46885,7 +46990,7 @@ async function runRepl(ctx, version) {
46885
46990
  });
46886
46991
  ctx.rl = rl;
46887
46992
  console.log();
46888
- console.log(" " + chalk98.dim("What do you want to look at?"));
46993
+ console.log(" " + chalk99.dim("What do you want to look at?"));
46889
46994
  console.log();
46890
46995
  if (ctx.pendingUpdateCheck) {
46891
46996
  void ctx.pendingUpdateCheck.then((result) => {
@@ -46927,7 +47032,7 @@ async function runRepl(ctx, version) {
46927
47032
  return;
46928
47033
  }
46929
47034
  sigintPrimed = true;
46930
- console.log("\n " + chalk98.dim("Type /exit to quit, or press Ctrl+C again."));
47035
+ console.log("\n " + chalk99.dim("Type /exit to quit, or press Ctrl+C again."));
46931
47036
  };
46932
47037
  rl.on("SIGINT", sigintHandler);
46933
47038
  function shutdownRepl() {
@@ -46964,7 +47069,7 @@ async function runRepl(ctx, version) {
46964
47069
  if (!typed && !enterAction) {
46965
47070
  clearGhostRowAfterSubmit();
46966
47071
  const coach = consumeOrientEmptyEnterCoach(ctx);
46967
- if (coach) console.log(" " + chalk98.dim(coach));
47072
+ if (coach) console.log(" " + chalk99.dim(coach));
46968
47073
  continue;
46969
47074
  }
46970
47075
  const line = typed || enterAction.submit;
@@ -47015,11 +47120,11 @@ async function runRepl(ctx, version) {
47015
47120
  ctx.wizardDepth = 0;
47016
47121
  ctx.secretInputActive = false;
47017
47122
  if (err instanceof Error && err.message === "Cancelled") {
47018
- console.log(" " + chalk98.dim("Cancelled."));
47123
+ console.log(" " + chalk99.dim("Cancelled."));
47019
47124
  } else {
47020
47125
  const { tryRecoverLlmAuthFailure: tryRecoverLlmAuthFailure2 } = await Promise.resolve().then(() => (init_auth_recovery(), auth_recovery_exports));
47021
47126
  if (!await tryRecoverLlmAuthFailure2(ctx, err)) {
47022
- console.error(" " + chalk98.red("Error: " + String(err.message ?? err)));
47127
+ console.error(" " + chalk99.red("Error: " + String(err.message ?? err)));
47023
47128
  }
47024
47129
  }
47025
47130
  }
@@ -47046,10 +47151,10 @@ async function runRepl(ctx, version) {
47046
47151
  await closeSession(ctx);
47047
47152
  }
47048
47153
  if (isTranscriptActive(ctx.sessionId)) {
47049
- console.log(" " + chalk98.dim("Transcript: ") + chalk98.dim(transcriptPathForSession(ctx.sessionId)));
47050
- console.log(" " + chalk98.dim("Context brief: ") + chalk98.dim(contextDocPathForSession(ctx.sessionId)));
47154
+ console.log(" " + chalk99.dim("Transcript: ") + chalk99.dim(transcriptPathForSession(ctx.sessionId)));
47155
+ console.log(" " + chalk99.dim("Context brief: ") + chalk99.dim(contextDocPathForSession(ctx.sessionId)));
47051
47156
  }
47052
- console.log(" " + chalk98.dim(randomGoodbye()));
47157
+ console.log(" " + chalk99.dim(randomGoodbye()));
47053
47158
  }
47054
47159
  function printHelpOneShot() {
47055
47160
  printHelp();
@@ -47057,43 +47162,43 @@ function printHelpOneShot() {
47057
47162
  function printHelp() {
47058
47163
  console.log();
47059
47164
  console.log(" " + sectionHeading("Conversation"));
47060
- console.log(" " + chalk98.dim("Type the question. You do not need a slash command."));
47061
- console.log(" " + chalk98.dim("Paste a CSV path or type ") + paint("accent", '"use demo data"') + chalk98.dim(" to load data."));
47062
- console.log(" " + chalk98.dim("After analysis, type questions in English."));
47063
- console.log(" " + chalk98.dim("Type ") + paint("accent", '"how should we fix this?"') + chalk98.dim(" to make a strategy. Type ") + paint("accent", "keep going") + chalk98.dim(" at confirm to keep working until the plan is ready."));
47064
- console.log(" " + chalk98.dim("Type ") + paint("accent", '"ship a board deck"') + chalk98.dim(" to write a handoff."));
47065
- console.log(" " + chalk98.dim("The ") + paint("accent", "\u203A") + chalk98.dim(" prompt shows brief or deep after analysis. Brief is the default."));
47165
+ console.log(" " + chalk99.dim("Type the question. You do not need a slash command."));
47166
+ console.log(" " + chalk99.dim("Paste a CSV path or type ") + paint("accent", '"use demo data"') + chalk99.dim(" to load data."));
47167
+ console.log(" " + chalk99.dim("After analysis, type questions in English."));
47168
+ console.log(" " + chalk99.dim("Type ") + paint("accent", '"how should we fix this?"') + chalk99.dim(" to make a strategy. Type ") + paint("accent", "keep going") + chalk99.dim(" at confirm to keep working until the plan is ready."));
47169
+ console.log(" " + chalk99.dim("Type ") + paint("accent", '"ship a board deck"') + chalk99.dim(" to write a handoff."));
47170
+ console.log(" " + chalk99.dim("The ") + paint("accent", "\u203A") + chalk99.dim(" prompt shows brief or deep after analysis. Brief is the default."));
47066
47171
  console.log();
47067
47172
  console.log(" " + sectionHeading("Keys"));
47068
47173
  console.log(
47069
- " " + paint("accent", "\u23CE") + chalk98.dim(
47174
+ " " + paint("accent", "\u23CE") + chalk99.dim(
47070
47175
  " Accepts the default. At the main prompt it runs the armed action (yes, use demo data, go ahead, /connect, /update, keep going)."
47071
47176
  )
47072
47177
  );
47073
47178
  console.log(
47074
- " " + chalk98.dim(
47179
+ " " + chalk99.dim(
47075
47180
  " On yes/no questions and menus it accepts yes (or the recommended option). Type something else to decline or pick another path."
47076
47181
  )
47077
47182
  );
47078
47183
  console.log(
47079
- " " + paint("accent", "b") + chalk98.dim(" / ") + paint("accent", "back") + chalk98.dim(" Steps back one confirm gate, or leaves a modal. Does not unload data or undo compute.")
47184
+ " " + paint("accent", "b") + chalk99.dim(" / ") + paint("accent", "back") + chalk99.dim(" Steps back one confirm gate, or leaves a modal. Does not unload data or undo compute.")
47080
47185
  );
47081
47186
  console.log(
47082
- " " + chalk98.dim("On ") + paint("accent", "/settings") + chalk98.dim(" menus, ") + paint("accent", "b") + chalk98.dim(" leaves the hub (same as Done).")
47187
+ " " + chalk99.dim("On ") + paint("accent", "/settings") + chalk99.dim(" menus, ") + paint("accent", "b") + chalk99.dim(" leaves the hub (same as Done).")
47083
47188
  );
47084
47189
  console.log(
47085
- " " + paint("accent", "more") + chalk98.dim(" Shows the full strategy brief after the short summary.")
47190
+ " " + paint("accent", "more") + chalk99.dim(" Shows the full strategy brief after the short summary.")
47086
47191
  );
47087
47192
  console.log(
47088
- " " + paint("accent", "expand") + chalk98.dim(
47193
+ " " + paint("accent", "expand") + chalk99.dim(
47089
47194
  " After a short Q&A answer, shows more reasoning for that same answer. With no last answer, expands the strategy brief when one is on screen."
47090
47195
  )
47091
47196
  );
47092
47197
  console.log(
47093
- " " + paint("accent", "cancel") + chalk98.dim(" Drops the current modal overlay (strategy, think, ship, unconfirmed scope).")
47198
+ " " + paint("accent", "cancel") + chalk99.dim(" Drops the current modal overlay (strategy, think, ship, unconfirmed scope).")
47094
47199
  );
47095
47200
  console.log(
47096
- " " + chalk98.dim("On ") + paint("accent", "/tour") + chalk98.dim(" slides, ") + paint("accent", "b") + chalk98.dim(" moves to the previous slide.")
47201
+ " " + chalk99.dim("On ") + paint("accent", "/tour") + chalk99.dim(" slides, ") + paint("accent", "b") + chalk99.dim(" moves to the previous slide.")
47097
47202
  );
47098
47203
  console.log();
47099
47204
  console.log(" " + sectionHeading("Shortcuts"));
@@ -47121,11 +47226,11 @@ function printHelp() {
47121
47226
  ];
47122
47227
  const maxW = Math.max(...shortcuts.map(([c]) => c.length)) + 2;
47123
47228
  for (const [cmd, desc] of shortcuts) {
47124
- console.log(` ${paint("accent", padRight(cmd, maxW))} ${chalk98.dim(desc)}`);
47229
+ console.log(` ${paint("accent", padRight(cmd, maxW))} ${chalk99.dim(desc)}`);
47125
47230
  }
47126
47231
  console.log();
47127
47232
  console.log(" " + sectionHeading("Teach NTRP"));
47128
- console.log(" " + chalk98.dim("NTRP learns your business over time. There are three ways to teach it:"));
47233
+ console.log(" " + chalk99.dim("NTRP learns your business over time. There are three ways to teach it:"));
47129
47234
  const teach = [
47130
47235
  ["/remember <fact>", "Store a fact, a decision, or a preference"],
47131
47236
  ["/recall [topic]", "Show what NTRP stores about your business"],
@@ -47134,13 +47239,13 @@ function printHelp() {
47134
47239
  ];
47135
47240
  const teachMaxW = Math.max(...teach.map(([c]) => c.length)) + 2;
47136
47241
  for (const [cmd, desc] of teach) {
47137
- console.log(` ${paint("accent", padRight(cmd, teachMaxW))} ${chalk98.dim(desc)}`);
47242
+ console.log(` ${paint("accent", padRight(cmd, teachMaxW))} ${chalk99.dim(desc)}`);
47138
47243
  }
47139
- console.log(" " + chalk98.dim("When a key is connected, NTRP stores a small number of facts when you close a session."));
47244
+ console.log(" " + chalk99.dim("When a key is connected, NTRP stores a small number of facts when you close a session."));
47140
47245
  console.log();
47141
- console.log(" " + chalk98.dim("Factory reset: type ") + paint("accent", "/scratch") + chalk98.dim("."));
47246
+ console.log(" " + chalk99.dim("Factory reset: type ") + paint("accent", "/scratch") + chalk99.dim("."));
47142
47247
  console.log();
47143
- console.log(" " + chalk98.dim("These commands also work: ") + paint("accent", "/new") + chalk98.dim(", ") + paint("accent", "/diagnose") + chalk98.dim(", ") + paint("accent", "/metrics") + chalk98.dim(", ") + paint("accent", "/session") + chalk98.dim("."));
47248
+ console.log(" " + chalk99.dim("These commands also work: ") + paint("accent", "/new") + chalk99.dim(", ") + paint("accent", "/diagnose") + chalk99.dim(", ") + paint("accent", "/metrics") + chalk99.dim(", ") + paint("accent", "/session") + chalk99.dim("."));
47144
47249
  console.log();
47145
47250
  }
47146
47251
  var REPL_BUILTINS, ANSI_PATTERN, GOODBYES, GHOST_HINTS, ghostHintTurn, activeGhostHint, suggestionPainted;
@@ -47240,7 +47345,7 @@ init_errors();
47240
47345
  init_diagnostics();
47241
47346
  init_types();
47242
47347
  init_version();
47243
- import chalk99 from "chalk";
47348
+ import chalk100 from "chalk";
47244
47349
  var VERSION = getInstalledVersion();
47245
47350
  function exitIfVersionFlag(argv) {
47246
47351
  const rest = argv.slice(2).filter((a) => a === "--version" || a === "-v");
@@ -47278,7 +47383,7 @@ async function main() {
47278
47383
  debug: args.globals.debug
47279
47384
  });
47280
47385
  if (!ctx.execution.color) {
47281
- chalk99.level = 0;
47386
+ chalk100.level = 0;
47282
47387
  }
47283
47388
  fatalReporting = {
47284
47389
  command: firstToken(args.input) || "ntrp",
@@ -47295,16 +47400,16 @@ async function main() {
47295
47400
  if (isStructuredOutput(ctx.execution)) {
47296
47401
  emitError(cmd || "ntrp", new NtrpError("license_invalid", lic.message, 3 /* Auth */));
47297
47402
  }
47298
- console.error(chalk99.red(`
47403
+ console.error(chalk100.red(`
47299
47404
  ${lic.message}`));
47300
- console.error(chalk99.dim(" Trial's over \u2014 /upgrade and paste your key.\n"));
47405
+ console.error(chalk100.dim(" Trial's over \u2014 /upgrade and paste your key.\n"));
47301
47406
  process.exit(1);
47302
47407
  }
47303
47408
  }
47304
47409
  const PROFILE_HINT_SKIP = /* @__PURE__ */ new Set(["onboard", "setup", "config", "connect", "activate", "help", "home", "exit", "quit", "clear", "profile", "progress", "deepdive", "tour", "settings", "voice", "logs"]);
47305
47410
  if (!isProfileConfigured() && !PROFILE_HINT_SKIP.has(cmd) && !ctx.execution.quiet) {
47306
47411
  console.error(
47307
- " " + chalk99.dim("Tip: run ") + paint("accent", "ntrp") + chalk99.dim(" interactively to set up your company profile for richer answers.")
47412
+ " " + chalk100.dim("Tip: run ") + paint("accent", "ntrp") + chalk100.dim(" interactively to set up your company profile for richer answers.")
47308
47413
  );
47309
47414
  }
47310
47415
  const result = await dispatch(args.input, ctx);
@@ -47316,12 +47421,12 @@ async function main() {
47316
47421
  }
47317
47422
  if (result.suggestion) {
47318
47423
  console.error(
47319
- chalk99.red(` Unknown command: ${result.token}.`) + chalk99.dim(" Did you mean ") + paint("accent", result.suggestion) + chalk99.dim("?")
47424
+ chalk100.red(` Unknown command: ${result.token}.`) + chalk100.dim(" Did you mean ") + paint("accent", result.suggestion) + chalk100.dim("?")
47320
47425
  );
47321
47426
  } else {
47322
- console.error(chalk99.red(` Unknown command: ${result.token}`));
47427
+ console.error(chalk100.red(` Unknown command: ${result.token}`));
47323
47428
  }
47324
- console.error(chalk99.dim(" Run 'ntrp' for the interactive prompt."));
47429
+ console.error(chalk100.dim(" Run 'ntrp' for the interactive prompt."));
47325
47430
  process.exit(1);
47326
47431
  break;
47327
47432
  case "help":
@@ -47374,7 +47479,7 @@ async function main() {
47374
47479
  if (justUpdated) {
47375
47480
  clearTerminalHome();
47376
47481
  console.log();
47377
- console.log(" " + paint("accent", "\u2713") + " " + chalk99.dim(`Now running v${justUpdated.to}`));
47482
+ console.log(" " + paint("accent", "\u2713") + " " + chalk100.dim(`Now running v${justUpdated.to}`));
47378
47483
  }
47379
47484
  await printWelcome2(ctx, VERSION);
47380
47485
  await runRepl(ctx, VERSION);
@@ -47388,9 +47493,9 @@ async function die(err, scope) {
47388
47493
  if (fatalReporting.structured) {
47389
47494
  emitError(fatalReporting.command, err);
47390
47495
  }
47391
- console.error(chalk99.red(` ${describeError(err)}`));
47496
+ console.error(chalk100.red(` ${describeError(err)}`));
47392
47497
  if (!(err instanceof NtrpError) && err instanceof Error && err.stack) {
47393
- console.error(chalk99.dim(err.stack.split("\n").slice(1).join("\n")));
47498
+ console.error(chalk100.dim(err.stack.split("\n").slice(1).join("\n")));
47394
47499
  }
47395
47500
  process.exit(err instanceof NtrpError ? err.exitCode : 1 /* RuntimeError */);
47396
47501
  }
@@ -1088,7 +1088,7 @@ import chalk3 from "chalk";
1088
1088
  function printDeepdiveHint(metricId, label) {
1089
1089
  const name = label ?? metricId;
1090
1090
  console.log(
1091
- " " + chalk3.dim("How this number works: ") + paint("accent", `/tour ${metricId}`) + chalk3.dim(` \u2014 ${name}`)
1091
+ " " + chalk3.dim(`Ask what ${name.toLowerCase()} means \u2014 or `) + paint("accent", `/tour ${metricId}`) + chalk3.dim(" for the card")
1092
1092
  );
1093
1093
  console.log();
1094
1094
  }
@@ -12978,7 +12978,24 @@ function listMetricExplainers(kind) {
12978
12978
  if (!kind) return METRIC_DEFINITIONS.slice();
12979
12979
  return METRIC_DEFINITIONS.filter((m) => m.kind === kind);
12980
12980
  }
12981
- var VITALS, SAAS, METRIC_DEFINITIONS, BY_ID, ALIAS_INDEX, SAAS_METRIC_IDS;
12981
+ function buildVitalSignsPromptBlock() {
12982
+ return VITAL_IDS.map((id) => {
12983
+ const m = getMetricExplainer(id);
12984
+ if (!m) {
12985
+ throw new Error(`buildVitalSignsPromptBlock: missing explainer for ${id}`);
12986
+ }
12987
+ if (!m.dollar_label) {
12988
+ throw new Error(`buildVitalSignsPromptBlock: missing dollar_label for ${id}`);
12989
+ }
12990
+ return [
12991
+ `- ${m.id}: ${m.tagline}`,
12992
+ ` Teach: ${m.meaning}`,
12993
+ ` Expert read: ${m.expert_read}`,
12994
+ ` Dollar label: ${m.dollar_label}`
12995
+ ].join("\n");
12996
+ }).join("\n");
12997
+ }
12998
+ var VITALS, SAAS, METRIC_DEFINITIONS, BY_ID, ALIAS_INDEX, VITAL_IDS, SAAS_METRIC_IDS;
12982
12999
  var init_metric_definitions = __esm({
12983
13000
  "src/data/metric-definitions.ts"() {
12984
13001
  "use strict";
@@ -13772,6 +13789,13 @@ var init_metric_definitions = __esm({
13772
13789
  idx.set("thread-depth", "thread_depth");
13773
13790
  return idx;
13774
13791
  })();
13792
+ VITAL_IDS = [
13793
+ "freshness",
13794
+ "flow_rate",
13795
+ "drop_rate",
13796
+ "signal_to_noise",
13797
+ "thread_depth"
13798
+ ];
13775
13799
  SAAS_METRIC_IDS = SAAS.map((m) => m.id);
13776
13800
  }
13777
13801
  });
@@ -15288,6 +15312,7 @@ var init_prompt_parts = __esm({
15288
15312
  init_profile();
15289
15313
  init_store();
15290
15314
  init_gtm_counsel();
15315
+ init_metric_definitions();
15291
15316
  init_playbook();
15292
15317
  init_play_outcomes();
15293
15318
  init_registry();
@@ -15324,16 +15349,7 @@ Restraint matters: NTRP is a stethoscope, not a surgeon. Observe, connect, and r
15324
15349
  - Observe, connect, recommend \u2014 never execute CRM changes, send email, or claim an action was taken unless a tool result in this conversation confirms it.
15325
15350
  - Weak or empty tool result: vary the arguments or approach once before concluding; if it's still empty, say what you'd need rather than filling the gap with plausible-sounding numbers.
15326
15351
  - Never fabricate CRM records, people, companies, or dollar amounts.`;
15327
- VITAL_SIGNS_BLOCK = `- freshness: Data recency. Low = stale contacts, zombie deals. Dollar value = pipeline at risk from stale accounts.
15328
- Expert read: cut by owner and by stage first \u2014 freshness reds concentrate on people or process, rarely evenly. In a long-cycle enterprise motion 30 quiet days can be normal cadence; in a velocity motion it's a dead deal. A sudden cliff usually means a broken integration or a departed rep, not gradual decay. False positive to check: bulk-imported records nobody has touched yet.
15329
- - flow_rate: Deal velocity. Low = stuck pipeline, slow progression. Dollar value = amount stuck in pipeline.
15330
- Expert read: cut by stage-age, not just deal-age \u2014 find the stage where deals go to die (usually one). Compare stuck-deal age to this company's own median cycle, not a generic norm. Stuck + past-due close dates together signal happy-ears forecasting, a credibility problem before it's a revenue problem.
15331
- - drop_rate: Handoff retention. Low = leads vanishing between marketing and sales. Dollar value = estimated lost revenue at handoff.
15332
- Expert read: this is almost always a systems failure \u2014 routing rules, unassigned territories, dead rep queues, or a sync gap between marketing and CRM \u2014 not lazy reps. First cut by lead source; the leak usually concentrates in one or two sources. The cheapest pipeline this business can buy is the leads it already paid for.
15333
- - signal_to_noise: Activity efficiency. Low = effort aimed at dead ends. Dollar value = cost of misdirected effort.
15334
- Expert read: cut by rep and by account status \u2014 noise usually means reps fishing in the pond they can see (dead accounts they know) because targeting and account lists are stale. Persistent noise is a coverage-model problem, not a coaching problem. Check whether activity is logged against closed or unlinked records \u2014 often a hygiene artifact.
15335
- - thread_depth: Deal resilience. Low = single-threaded deals, fragile pipeline. Dollar value = amount in single-threaded deals.
15336
- Expert read: weight by deal size \u2014 one single-threaded mega-deal outweighs ten small ones. Single-threading late in the cycle is far more dangerous than early. In enterprise motions, thread depth is a leading indicator of slipped quarters: champions change jobs, and there's no second door in.`;
15352
+ VITAL_SIGNS_BLOCK = buildVitalSignsPromptBlock();
15337
15353
  PLAYBOOK_BLOCK = `- "Multi-Thread Your Deals" (id: multi-thread-deals) \u2014 when thread_depth is low
15338
15354
  - "Clean Dead Pipeline" (id: clean-dead-pipeline) \u2014 when freshness is low
15339
15355
  - "Fix the Handoff Gap" (id: fix-handoff-gap) \u2014 when drop_rate is high and the source\u2192owner path is unknown
@@ -18778,7 +18794,7 @@ function consumeOrientEmptyEnterCoach(ctx) {
18778
18794
  if (!hasValidLicense()) {
18779
18795
  return "Type /activate to paste a key. Type /checkout if you need to sign up.";
18780
18796
  }
18781
- return "Type a question, type use demo data, or type /tour. Enter alone does not start a step here.";
18797
+ return "Type a question, or type use demo data. Enter alone does not start a step here.";
18782
18798
  }
18783
18799
  function formatPhaseLabel(phase) {
18784
18800
  switch (phase) {
@@ -19698,7 +19714,10 @@ function buildExploreTeachingGhosts(ctx, staticExplore) {
19698
19714
  if (cached2 && cached2.length > 0) {
19699
19715
  const ghosts = asksToGhostHints(cached2);
19700
19716
  const gating = ctx.snapshot.computeResult?.aggregate.gating_vital_sign;
19701
- if (gating) ghosts.push(`try /tour ${gating}`);
19717
+ if (gating) {
19718
+ const label = (VITAL_SIGN_LABELS[gating] ?? gating).toLowerCase();
19719
+ ghosts.push(`try "why is ${label} red?"`);
19720
+ }
19702
19721
  ghosts.push('try "how should we fix this?"');
19703
19722
  return dedupeGhosts(ghosts);
19704
19723
  }
@@ -19709,7 +19728,11 @@ function buildExploreTeachingGhosts(ctx, staticExplore) {
19709
19728
  });
19710
19729
  return dedupeGhosts([
19711
19730
  ...asksToGhostHints(asks),
19712
- `try /tour ${health.gating_vital_sign}`,
19731
+ (() => {
19732
+ const g = health.gating_vital_sign;
19733
+ const label = (VITAL_SIGN_LABELS[g] ?? g).toLowerCase();
19734
+ return `try "why is ${label} red?"`;
19735
+ })(),
19713
19736
  'try "how should we fix this?"'
19714
19737
  ]);
19715
19738
  }
@@ -24648,8 +24671,8 @@ var init_ghost_hints = __esm({
24648
24671
  PHASE_GHOST_HINTS = {
24649
24672
  orient: [
24650
24673
  'try "pipeline health"',
24651
- "try /tour",
24652
- "try /tour guide",
24674
+ 'try "how healthy is the pipeline?"',
24675
+ 'try "what should I do next?"',
24653
24676
  'try "is our retention real for the board?"',
24654
24677
  'try "what is the most expensive problem to solve?"',
24655
24678
  'try "board deck on Q3"'
@@ -24666,7 +24689,7 @@ var init_ghost_hints = __esm({
24666
24689
  'try "how should we fix this?"',
24667
24690
  'try "which segment is weakest?"',
24668
24691
  'try "what is ARR?"',
24669
- "try /tour freshness",
24692
+ 'try "why is freshness red?"',
24670
24693
  'try "ship a board deck"'
24671
24694
  ]
24672
24695
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sonnechasser/ntrp",
3
- "version": "2.2.2",
3
+ "version": "2.4.0",
4
4
  "description": "GTM Health Diagnostic CLI — local pipeline analysis tool",
5
5
  "homepage": "https://ntrp.sonnechasser.com",
6
6
  "repository": {