@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
@@ -1369,6 +1369,26 @@ function buildSessionContextDoc(file, opts = {}) {
1369
1369
  if (file.strategist.origin) lines.push(`- Origin: ${file.strategist.origin}`);
1370
1370
  lines.push("");
1371
1371
  }
1372
+ if (file.think) {
1373
+ lines.push("## Think (in flight)");
1374
+ lines.push("");
1375
+ lines.push(`- Step: ${file.think.step}`);
1376
+ if (file.think.seed) lines.push(`- Seed: ${file.think.seed}`);
1377
+ if (file.think.origin) lines.push(`- Origin: ${file.think.origin}`);
1378
+ if (file.think.open_questions?.length) {
1379
+ lines.push("- Open questions:");
1380
+ for (const q of file.think.open_questions) lines.push(` - ${q}`);
1381
+ }
1382
+ if (file.think.challenged_assumptions?.length) {
1383
+ lines.push("- Challenged assumptions:");
1384
+ for (const a of file.think.challenged_assumptions) lines.push(` - ${a}`);
1385
+ }
1386
+ if (file.think.working_hypotheses?.length) {
1387
+ lines.push("- Working hypotheses:");
1388
+ for (const h of file.think.working_hypotheses) lines.push(` - ${h}`);
1389
+ }
1390
+ lines.push("");
1391
+ }
1372
1392
  lines.push("## Deliverables");
1373
1393
  lines.push("");
1374
1394
  if (file.deliverables && file.deliverables.length > 0) {
@@ -8090,6 +8110,7 @@ function initContext(oneShot, execution) {
8090
8110
  snapshot: { computeResult: null, divergences: [] },
8091
8111
  messages: [],
8092
8112
  conversation: [],
8113
+ thinkConversation: [],
8093
8114
  stage: "new",
8094
8115
  deliverables: [],
8095
8116
  analysis: defaultSessionAnalysis(),
@@ -8110,12 +8131,14 @@ function buildSessionFileSnapshot(ctx) {
8110
8131
  if (ctx.dataset) file.dataset = ctx.dataset;
8111
8132
  if (ctx.deliverables.length > 0) file.deliverables = ctx.deliverables;
8112
8133
  if (ctx.conversation.length > 0) file.thread = ctx.conversation;
8134
+ if (ctx.thinkConversation.length > 0) file.think_thread = ctx.thinkConversation;
8113
8135
  if (ctx.resumedFromId) file.resumed_from = ctx.resumedFromId;
8114
8136
  if (ctx.analysis) file.analysis = ctx.analysis;
8115
8137
  if (ctx.scope) file.scope = ctx.scope;
8116
8138
  if (ctx.attachments && ctx.attachments.length > 0) file.attachments = ctx.attachments;
8117
8139
  if (ctx.llm && Object.keys(ctx.llm).length > 0) file.llm = ctx.llm;
8118
8140
  if (ctx.strategistState) file.strategist = ctx.strategistState;
8141
+ if (ctx.thinkState) file.think = ctx.thinkState;
8119
8142
  if (ctx.pendingAsk) file.pending_ask = ctx.pendingAsk;
8120
8143
  return file;
8121
8144
  }
@@ -8242,6 +8265,9 @@ function loadSessionFile(id) {
8242
8265
  if (session.thread?.length) {
8243
8266
  session.thread = normalizeThread(session.thread);
8244
8267
  }
8268
+ if (session.think_thread?.length) {
8269
+ session.think_thread = normalizeThread(session.think_thread);
8270
+ }
8245
8271
  return session;
8246
8272
  } catch {
8247
8273
  return null;
@@ -8444,6 +8470,9 @@ async function finalizeSession(ctx, stage) {
8444
8470
  if (ctx.conversation.length > 0) {
8445
8471
  file.thread = ctx.conversation;
8446
8472
  }
8473
+ if (ctx.thinkConversation.length > 0) {
8474
+ file.think_thread = ctx.thinkConversation;
8475
+ }
8447
8476
  if (ctx.analysis) {
8448
8477
  file.analysis = ctx.analysis;
8449
8478
  }
@@ -8459,6 +8488,9 @@ async function finalizeSession(ctx, stage) {
8459
8488
  if (ctx.strategistState) {
8460
8489
  file.strategist = ctx.strategistState;
8461
8490
  }
8491
+ if (ctx.thinkState) {
8492
+ file.think = ctx.thinkState;
8493
+ }
8462
8494
  if (ctx.pendingAsk) {
8463
8495
  file.pending_ask = ctx.pendingAsk;
8464
8496
  }
@@ -8520,6 +8552,7 @@ function resetContextForSwitch(ctx, opts) {
8520
8552
  ctx.sessionName = opts.sessionName;
8521
8553
  ctx.messages = opts.messages;
8522
8554
  ctx.conversation = opts.conversation ?? [];
8555
+ ctx.thinkConversation = opts.thinkConversation ?? [];
8523
8556
  ctx.resumedFromId = opts.resumedFromId;
8524
8557
  ctx.resumedSessionSummary = opts.resumedSessionSummary;
8525
8558
  ctx.stage = opts.stage ?? "new";
@@ -8530,6 +8563,7 @@ function resetContextForSwitch(ctx, opts) {
8530
8563
  ctx.attachments = opts.attachments ?? [];
8531
8564
  ctx.llm = opts.llm;
8532
8565
  ctx.strategistState = opts.strategistState;
8566
+ ctx.thinkState = opts.thinkState;
8533
8567
  ctx.pendingAsk = opts.pendingAsk;
8534
8568
  ctx.gapAudit = void 0;
8535
8569
  ctx.deliverIntent = false;
@@ -10215,6 +10249,21 @@ Bare \`/deepdive\` runs the full onboarding tour. Type \`/deepdive guide\` to ju
10215
10249
  Type \`/deepdive handoff\` for the ship-to-Claude slide. Type \`/deepdive <metric>\` to jump to one metric card.
10216
10250
  Type \`/deepdive list\` to print the catalog. Works without an AI key. Re-run anytime from the homescreen.
10217
10251
  Live values overlay when an analysis exists.`
10252
+ },
10253
+ {
10254
+ name: "thinkwithme",
10255
+ raw: `---
10256
+ name: thinkwithme
10257
+ description: Socratic co-thinking channel \u2014 explore and pressure-test
10258
+ section: Navigation
10259
+ args: [topic]
10260
+ handler: ../commands/thinkwithme.ts
10261
+ ---
10262
+
10263
+ Open a dedicated \`think \u203A\` channel to explore ideas, challenge assumptions, and pull evidence from your data.
10264
+ Bare \`/thinkwithme\` enters the channel. Type \`/thinkwithme <topic>\` to seed the first turn.
10265
+ Requires an analysis and an AI key (\`/connect\`). Type \`done\` or \`cancel\` to return to ask \u203A.
10266
+ When you are ready to commit to a plan, say so or the partner can hand off to \`/strategy\`.`
10218
10267
  },
10219
10268
  {
10220
10269
  name: "status",
@@ -10453,11 +10502,11 @@ Cross-provider IDs are rejected. Type \`/provider\` first to switch.`
10453
10502
  name: activate
10454
10503
  description: Enter a license key
10455
10504
  section: Settings
10456
- args: <license>
10505
+ args: [license]
10457
10506
  handler: ../commands/activate.ts
10458
10507
  ---
10459
10508
 
10460
- Activate NTRP with the key from your purchase email. Most commands need a valid license.`
10509
+ Activate NTRP with the key from your purchase email. Type \`/activate\` with no key to paste. Most commands need a valid license.`
10461
10510
  },
10462
10511
  {
10463
10512
  name: "upgrade",
@@ -11041,13 +11090,21 @@ function buildFreshNlTools() {
11041
11090
  if (isWebRetrievalEnabled()) tools2.push(WEB_SEARCH_TOOL);
11042
11091
  return tools2;
11043
11092
  }
11093
+ function buildThinkTools() {
11094
+ const tools2 = [
11095
+ ...AGENTIC_TOOLS,
11096
+ ...THINK_CHANNEL_TOOLS
11097
+ ];
11098
+ if (isWebRetrievalEnabled()) tools2.push(WEB_SEARCH_TOOL);
11099
+ return tools2;
11100
+ }
11044
11101
  function allRegisteredToolSchemas() {
11045
- return [...AGENTIC_TOOLS, ...CONVERSATION_TOOLS, WEB_SEARCH_TOOL];
11102
+ return [...AGENTIC_TOOLS, ...CONVERSATION_TOOLS, ...THINK_CHANNEL_TOOLS, WEB_SEARCH_TOOL];
11046
11103
  }
11047
11104
  function getToolSchema(name) {
11048
11105
  return allRegisteredToolSchemas().find((t) => t.name === name);
11049
11106
  }
11050
- var WEB_SEARCH_TOOL, CONVERSATION_TOOLS, AGENTIC_TOOLS;
11107
+ var WEB_SEARCH_TOOL, CONVERSATION_TOOLS, THINK_CHANNEL_TOOLS, AGENTIC_TOOLS;
11051
11108
  var init_tool_schemas = __esm({
11052
11109
  "src/ai/tool-schemas.ts"() {
11053
11110
  "use strict";
@@ -11124,6 +11181,64 @@ var init_tool_schemas = __esm({
11124
11181
  }
11125
11182
  }
11126
11183
  ];
11184
+ THINK_CHANNEL_TOOLS = [
11185
+ {
11186
+ name: "draft_handoff",
11187
+ description: "Draft a handoff prompt combining analysis numbers and conversation thread.",
11188
+ parameters: {
11189
+ type: "object",
11190
+ properties: {
11191
+ target: {
11192
+ type: "string",
11193
+ enum: ["deck", "asana", "clay", "plan"],
11194
+ description: "Deliverable type. Defaults to plan."
11195
+ }
11196
+ }
11197
+ }
11198
+ },
11199
+ {
11200
+ name: "draft_strategy",
11201
+ 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.",
11202
+ parameters: {
11203
+ type: "object",
11204
+ properties: {
11205
+ objective: {
11206
+ type: "string",
11207
+ maxLength: 2e3,
11208
+ description: "The measurable objective to plan toward, in the user's terms."
11209
+ }
11210
+ },
11211
+ required: ["objective"]
11212
+ }
11213
+ },
11214
+ {
11215
+ name: "update_think_scratch",
11216
+ 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.",
11217
+ parameters: {
11218
+ type: "object",
11219
+ properties: {
11220
+ open_questions: {
11221
+ type: "array",
11222
+ items: { type: "string", maxLength: 500 },
11223
+ maxItems: 12,
11224
+ description: "Current open questions (replaces the list when provided)."
11225
+ },
11226
+ challenged_assumptions: {
11227
+ type: "array",
11228
+ items: { type: "string", maxLength: 500 },
11229
+ maxItems: 12,
11230
+ description: "Assumptions that have been pressure-tested (replaces when provided)."
11231
+ },
11232
+ working_hypotheses: {
11233
+ type: "array",
11234
+ items: { type: "string", maxLength: 500 },
11235
+ maxItems: 12,
11236
+ description: "Working hypotheses under consideration (replaces when provided)."
11237
+ }
11238
+ }
11239
+ }
11240
+ }
11241
+ ];
11127
11242
  AGENTIC_TOOLS = [
11128
11243
  {
11129
11244
  name: "get_health_summary",
@@ -13501,7 +13616,7 @@ var init_activation = __esm({
13501
13616
 
13502
13617
  // src/conversation/recommended-action.ts
13503
13618
  function resolveRecommendedAction(ctx) {
13504
- if (!hasValidLicense()) return { submit: "/checkout", hint: "/checkout" };
13619
+ if (!hasValidLicense()) return { submit: "/activate", hint: "/activate" };
13505
13620
  const phase = resolveConversationPhase(ctx);
13506
13621
  switch (phase) {
13507
13622
  case "explore":
@@ -13515,6 +13630,8 @@ function resolveRecommendedAction(ctx) {
13515
13630
  return { submit: "yes", hint: "yes" };
13516
13631
  case "strategize":
13517
13632
  return ctx.strategistState?.step === "objective_confirm" ? { submit: "yes", hint: "yes" } : null;
13633
+ case "think":
13634
+ return null;
13518
13635
  default:
13519
13636
  return null;
13520
13637
  }
@@ -13549,6 +13666,9 @@ function resolveConversationPhase(ctx) {
13549
13666
  if (ctx.strategistState && ctx.strategistState.step !== "awaiting_analysis" && ctx.strategistState.step !== "awaiting_connect") {
13550
13667
  return "strategize";
13551
13668
  }
13669
+ if (ctx.thinkState?.step === "active") {
13670
+ return "think";
13671
+ }
13552
13672
  if (isAnalysisReady(ctx)) return "explore";
13553
13673
  const scope = ctx.scope;
13554
13674
  if (scope?.confirmed_at) {
@@ -13562,6 +13682,9 @@ function consumeOrientEmptyEnterCoach(ctx) {
13562
13682
  if (resolveConversationPhase(ctx) !== "orient") return null;
13563
13683
  if (ctx.orientEmptyEnterSeen) return null;
13564
13684
  ctx.orientEmptyEnterSeen = true;
13685
+ if (!hasValidLicense()) {
13686
+ return "Type /activate to paste a key. Type /checkout if you need to sign up.";
13687
+ }
13565
13688
  return "Type a question, type use demo data, or type /deepdive. Enter alone does not start a step here.";
13566
13689
  }
13567
13690
  function formatPhaseLabel(phase) {
@@ -13570,6 +13693,8 @@ function formatPhaseLabel(phase) {
13570
13693
  return "setup";
13571
13694
  case "explore":
13572
13695
  return "ready to ask";
13696
+ case "think":
13697
+ return "thinking together";
13573
13698
  default:
13574
13699
  return phase.replace(/_/g, " ");
13575
13700
  }
@@ -13588,8 +13713,14 @@ function buildConversationPrompt(ctx) {
13588
13713
  const modeTag = mode === "brief" ? "brief" : "deep";
13589
13714
  const stack = canUseReplAi(ctx) ? formatActiveStackShort(ctx) : "no engine";
13590
13715
  const strategyWait = ctx.strategistState?.step === "awaiting_connect" ? chalk8.dim(" \xB7 strategy after /connect") : "";
13716
+ const thinkWait = ctx.thinkState?.step === "awaiting_connect" ? chalk8.dim(" \xB7 think after /connect") : "";
13717
+ const enterHint2 = action ? chalk8.dim(` \xB7 \u23CE ${action.hint}`) : "";
13718
+ return paint("accent", `ask${scope} \u203A `) + chalk8.dim(`${modeTag} \xB7 ${stack}`) + strategyWait + thinkWait + enterHint2 + " ";
13719
+ }
13720
+ if (phase === "think") {
13721
+ const stack = canUseReplAi(ctx) ? formatActiveStackShort(ctx) : "no engine";
13591
13722
  const enterHint2 = action ? chalk8.dim(` \xB7 \u23CE ${action.hint}`) : "";
13592
- return paint("accent", `ask${scope} \u203A `) + chalk8.dim(`${modeTag} \xB7 ${stack}`) + strategyWait + enterHint2 + " ";
13723
+ return paint("accent", `think${scope} \u203A `) + chalk8.dim(stack) + enterHint2 + " ";
13593
13724
  }
13594
13725
  const enterHint = action ? chalk8.dim(`\u23CE ${action.hint} `) : "";
13595
13726
  return paint("accent", `${label.replace(" \u203A", "")}${scope} \u203A `) + enterHint;
@@ -13622,6 +13753,7 @@ var init_phase = __esm({
13622
13753
  init_explore_mode();
13623
13754
  init_session_state();
13624
13755
  init_theme();
13756
+ init_activation();
13625
13757
  init_recommended_action();
13626
13758
  PROMPT_LABELS = {
13627
13759
  orient: "\u203A",
@@ -13629,6 +13761,7 @@ var init_phase = __esm({
13629
13761
  awaiting_data: "data \u203A",
13630
13762
  compute: "\u2026",
13631
13763
  explore: "ask \u203A",
13764
+ think: "think \u203A",
13632
13765
  strategize: "strategy \u203A",
13633
13766
  deliver: "ship \u203A"
13634
13767
  };
@@ -18300,45 +18433,372 @@ var init_strategist_flow = __esm({
18300
18433
  }
18301
18434
  });
18302
18435
 
18303
- // src/conversation/gap-card.ts
18436
+ // src/services/think.ts
18437
+ var think_exports = {};
18438
+ __export(think_exports, {
18439
+ runThinkTurn: () => runThinkTurn
18440
+ });
18304
18441
  import chalk18 from "chalk";
18442
+ async function runThinkTurn(input, ctx) {
18443
+ assertReplAi(ctx);
18444
+ let snapshot = ctx.snapshot.computeResult;
18445
+ if (!snapshot) {
18446
+ const metricsFirst = prefersMetricsFirstContext(ctx);
18447
+ const spinner2 = makeSpinner(metricsFirst ? "Loading session context\u2026" : "Computing vital signs\u2026");
18448
+ try {
18449
+ snapshot = await computeFullHealth();
18450
+ ctx.snapshot.computeResult = snapshot;
18451
+ const divInput = snapshot.segments.map((s) => ({
18452
+ segmentId: s.segment.id,
18453
+ segmentName: s.segment.name,
18454
+ result: s.result
18455
+ }));
18456
+ ctx.snapshot.divergences = detectDivergences(snapshot.aggregate, divInput).divergences;
18457
+ spinner2.succeed(metricsFirst ? "Session context ready" : "Health snapshot ready");
18458
+ } catch (err) {
18459
+ spinner2.fail("Could not compute health snapshot");
18460
+ console.error(" " + chalk18.red(String(err.message ?? err)));
18461
+ console.log(" " + chalk18.dim("Run ") + paint("accent", "/new") + chalk18.dim(" \u2192 pick Demo to load sample data."));
18462
+ console.log();
18463
+ return;
18464
+ }
18465
+ }
18466
+ console.log();
18467
+ const memoryBlock = await buildMemoryBlock(input).catch(() => "");
18468
+ const spinner = makeSpinner("Thinking with you\u2026");
18469
+ let lastAnswer = "";
18470
+ let rawHistory = [];
18471
+ const toolsUsed = [];
18472
+ setAgentContext(ctx);
18473
+ try {
18474
+ const analysisBlock = buildAnalysisBlock(ctx);
18475
+ const conversationBlock = getConversationPhaseBlock(ctx);
18476
+ const bundle = await loadSessionAnalysisBundle();
18477
+ const sessionArtifact = hasAnyAnalysis(bundle) ? buildExploreContextBlock(bundle, ctx) : "";
18478
+ for await (const event of agenticFindings(snapshot, ctx.snapshot.divergences, {
18479
+ mode: "think",
18480
+ userQuestion: input,
18481
+ sessionContext: ctx.resumedSessionSummary,
18482
+ includeMetrics: true,
18483
+ analysisBlock,
18484
+ conversationBlock,
18485
+ sessionArtifact,
18486
+ priorMessages: ctx.thinkConversation,
18487
+ memoryBlock,
18488
+ ctx
18489
+ })) {
18490
+ switch (event.type) {
18491
+ case "tool_call":
18492
+ toolsUsed.push(event.name);
18493
+ spinner.text = `Querying ${event.name}\u2026`;
18494
+ break;
18495
+ case "thinking":
18496
+ spinner.stop();
18497
+ console.log(" " + chalk18.dim.italic(event.text));
18498
+ spinner.start("Thinking with you\u2026");
18499
+ break;
18500
+ case "answer":
18501
+ spinner.stop();
18502
+ lastAnswer = event.text;
18503
+ printMarkdown(event.text, { indent: 2 });
18504
+ break;
18505
+ case "finding":
18506
+ spinner.stop();
18507
+ printFindingInline(event.finding);
18508
+ break;
18509
+ case "done":
18510
+ spinner.stop();
18511
+ rawHistory = event.conversation_history;
18512
+ break;
18513
+ }
18514
+ }
18515
+ } catch (err) {
18516
+ spinner.fail("Error while thinking");
18517
+ console.error(" " + chalk18.red(String(err.message ?? err)));
18518
+ console.log();
18519
+ return;
18520
+ } finally {
18521
+ setAgentContext(null);
18522
+ }
18523
+ if (rawHistory.length > 0) {
18524
+ ctx.thinkConversation = distillThread(rawHistory);
18525
+ }
18526
+ if (!lastAnswer) {
18527
+ console.log(" " + chalk18.dim("(no answer returned)"));
18528
+ } else {
18529
+ recordMessage(ctx, "agent", lastAnswer);
18530
+ saveSessionState(ctx);
18531
+ creditNlAnswer(ctx, Math.floor(ctx.messages.length / 2));
18532
+ recordAnalysis({
18533
+ question: `[think] ${input}`,
18534
+ answer: lastAnswer,
18535
+ tools: toolsUsed,
18536
+ session_id: ctx.sessionId
18537
+ });
18538
+ ctx.lastExchange = { question: input, answer: lastAnswer };
18539
+ }
18540
+ console.log();
18541
+ return lastAnswer ? extractSummary(lastAnswer) : void 0;
18542
+ }
18543
+ function extractSummary(text) {
18544
+ const plain = text.replace(/#{1,6}\s+/g, "").replace(/\*\*([^*]+)\*\*/g, "$1").replace(/\*([^*]+)\*/g, "$1").replace(/`([^`]+)`/g, "$1").replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/^[-*]\s+/gm, "").trim();
18545
+ const sentenceMatch = plain.match(/^(.+?[.!?])(?:\s|$)/);
18546
+ const sentence = sentenceMatch ? sentenceMatch[1] : plain.split("\n")[0];
18547
+ if (sentence.length <= 60) return sentence;
18548
+ return sentence.slice(0, 60).replace(/\s+\S*$/, "") + "\u2026";
18549
+ }
18550
+ function printFindingInline(finding) {
18551
+ const sev = finding.severity;
18552
+ console.log();
18553
+ console.log(
18554
+ " " + severityPaint(sev)(sev.toUpperCase()) + " " + (finding.finding ?? "").slice(0, 120)
18555
+ );
18556
+ }
18557
+ var init_think = __esm({
18558
+ "src/services/think.ts"() {
18559
+ "use strict";
18560
+ init_spinner();
18561
+ init_context2();
18562
+ init_phase();
18563
+ init_agent_context();
18564
+ init_agentic_loop();
18565
+ init_thread();
18566
+ init_store2();
18567
+ init_health_score();
18568
+ init_divergence();
18569
+ init_repl_api();
18570
+ init_theme();
18571
+ init_markdown();
18572
+ init_session_analysis();
18573
+ init_time_bank();
18574
+ }
18575
+ });
18576
+
18577
+ // src/conversation/think-flow.ts
18578
+ var think_flow_exports = {};
18579
+ __export(think_flow_exports, {
18580
+ clearThinkFlow: () => clearThinkFlow,
18581
+ extractThinkSeed: () => extractThinkSeed,
18582
+ handleThinkFlow: () => handleThinkFlow,
18583
+ isThinkIntent: () => isThinkIntent,
18584
+ queueThinkForAnalysis: () => queueThinkForAnalysis,
18585
+ resumeThinkAfterCompute: () => resumeThinkAfterCompute,
18586
+ resumeThinkAfterConnect: () => resumeThinkAfterConnect,
18587
+ startThinkFlow: () => startThinkFlow
18588
+ });
18589
+ import chalk19 from "chalk";
18590
+ function isThinkIntent(input) {
18591
+ const line = input.trim();
18592
+ if (!line) return false;
18593
+ if (isShipIntent(line)) return false;
18594
+ if (isStrategistIntent(line)) return false;
18595
+ return THINK_INTENT_RE.test(line);
18596
+ }
18597
+ function extractThinkSeed(input) {
18598
+ 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();
18599
+ return cleaned.length >= 4 ? cleaned : input.trim();
18600
+ }
18601
+ function queueThinkForAnalysis(ctx, opts) {
18602
+ ctx.thinkState = {
18603
+ step: "awaiting_analysis",
18604
+ seed: opts.seed,
18605
+ origin: opts.origin,
18606
+ started_at: (/* @__PURE__ */ new Date()).toISOString()
18607
+ };
18608
+ saveSessionState(ctx);
18609
+ console.log();
18610
+ console.log(
18611
+ " " + chalk19.dim("Think session queued. NTRP opens the channel after analysis.")
18612
+ );
18613
+ if (opts.origin !== "nl") {
18614
+ console.log(
18615
+ " " + chalk19.dim("Type what to look at. Paste a CSV path. Or type ") + chalk19.cyan("use demo data") + chalk19.dim(".")
18616
+ );
18617
+ }
18618
+ console.log();
18619
+ }
18620
+ function printChannelIntro(seed) {
18621
+ console.log();
18622
+ console.log(" " + paint("accent", "Think with me"));
18623
+ console.log(
18624
+ " " + chalk19.dim(
18625
+ "Socratic channel \u2014 explore, challenge assumptions, pull evidence. Type "
18626
+ ) + chalk19.cyan("done") + chalk19.dim(" or ") + chalk19.cyan("cancel") + chalk19.dim(" to return to ask \u203A.")
18627
+ );
18628
+ if (seed) {
18629
+ console.log(" " + chalk19.dim("Seed: ") + seed);
18630
+ }
18631
+ console.log();
18632
+ }
18633
+ function armKeylessThink(ctx, opts) {
18634
+ ctx.thinkState = {
18635
+ step: "awaiting_connect",
18636
+ seed: opts.seed,
18637
+ origin: opts.origin,
18638
+ started_at: (/* @__PURE__ */ new Date()).toISOString()
18639
+ };
18640
+ saveSessionState(ctx);
18641
+ console.log();
18642
+ console.log(" " + chalk19.dim("Think channel needs an AI key."));
18643
+ console.log(
18644
+ " " + chalk19.dim("Type ") + paint("accent", "/connect") + chalk19.dim(" and paste a key. Seed kept \u2014 the channel opens after connect.")
18645
+ );
18646
+ console.log();
18647
+ }
18648
+ async function startThinkFlow(ctx, opts) {
18649
+ if (!isAnalysisReady(ctx)) {
18650
+ queueThinkForAnalysis(ctx, opts);
18651
+ return "Think queued";
18652
+ }
18653
+ if (!canUseReplAi(ctx)) {
18654
+ armKeylessThink(ctx, opts);
18655
+ return "Think awaiting connect";
18656
+ }
18657
+ const seed = opts.seed?.trim() || void 0;
18658
+ ctx.thinkState = {
18659
+ step: "active",
18660
+ seed,
18661
+ origin: opts.origin,
18662
+ started_at: (/* @__PURE__ */ new Date()).toISOString(),
18663
+ open_questions: [],
18664
+ challenged_assumptions: [],
18665
+ working_hypotheses: []
18666
+ };
18667
+ if (ctx.thinkConversation.length === 0 && seed) {
18668
+ }
18669
+ saveSessionState(ctx);
18670
+ printChannelIntro(seed);
18671
+ recordMessage(ctx, "agent", seed ? `Think channel opened: ${seed}` : "Think channel opened");
18672
+ if (seed) {
18673
+ recordMessage(ctx, "user", seed);
18674
+ const { runThinkTurn: runThinkTurn2 } = await Promise.resolve().then(() => (init_think(), think_exports));
18675
+ await runThinkTurn2(seed, ctx);
18676
+ }
18677
+ return "Think channel open";
18678
+ }
18679
+ async function resumeThinkAfterCompute(ctx) {
18680
+ const state2 = ctx.thinkState;
18681
+ if (!state2 || state2.step !== "awaiting_analysis") return;
18682
+ if (ctx.strategistState && ctx.strategistState.step !== "awaiting_analysis" && ctx.strategistState.step !== "awaiting_connect") {
18683
+ return;
18684
+ }
18685
+ if (ctx.strategistState?.step === "awaiting_analysis") return;
18686
+ console.log();
18687
+ console.log(" " + paint("accent", "Analysis is ready. The think channel continues."));
18688
+ await startThinkFlow(ctx, {
18689
+ seed: state2.seed,
18690
+ origin: state2.origin ?? "nl"
18691
+ });
18692
+ }
18693
+ async function resumeThinkAfterConnect(ctx) {
18694
+ const state2 = ctx.thinkState;
18695
+ if (!state2 || state2.step !== "awaiting_connect") return false;
18696
+ if (!canUseReplAi(ctx)) return false;
18697
+ console.log();
18698
+ console.log(" " + paint("accent", "Key connected. Opening the think channel."));
18699
+ await startThinkFlow(ctx, {
18700
+ seed: state2.seed,
18701
+ origin: state2.origin ?? "nl"
18702
+ });
18703
+ return true;
18704
+ }
18705
+ function clearThinkFlow(ctx, reason) {
18706
+ ctx.thinkState = void 0;
18707
+ saveSessionState(ctx);
18708
+ if (reason === "handoff") return;
18709
+ console.log();
18710
+ console.log(
18711
+ " " + chalk19.dim(
18712
+ reason === "done" ? "Think channel closed. Back to ask \u203A." : "Think session cancelled. Continue exploration."
18713
+ )
18714
+ );
18715
+ console.log();
18716
+ }
18717
+ async function handleThinkFlow(input, ctx) {
18718
+ const state2 = ctx.thinkState;
18719
+ if (!state2 || state2.step !== "active") return;
18720
+ const line = input.trim();
18721
+ recordMessage(ctx, "user", line);
18722
+ if (CANCEL_RE2.test(line) || DONE_RE.test(line)) {
18723
+ clearThinkFlow(ctx, CANCEL_RE2.test(line) ? "cancel" : "done");
18724
+ recordMessage(ctx, "agent", "Think channel closed");
18725
+ return "Think closed";
18726
+ }
18727
+ if (isStrategistIntent(line)) {
18728
+ clearThinkFlow(ctx, "handoff");
18729
+ const summary = await startStrategistFlow(ctx, {
18730
+ seed: extractObjectiveSeed(line),
18731
+ origin: "nl"
18732
+ }) ?? void 0;
18733
+ return summary ?? "Handed off to strategist";
18734
+ }
18735
+ if (!canUseReplAi(ctx)) {
18736
+ armKeylessThink(ctx, { seed: state2.seed ?? line, origin: state2.origin ?? "nl" });
18737
+ return "Think awaiting connect";
18738
+ }
18739
+ const { runThinkTurn: runThinkTurn2 } = await Promise.resolve().then(() => (init_think(), think_exports));
18740
+ await runThinkTurn2(line, ctx);
18741
+ if (ctx.strategistState && ctx.strategistState.step !== "awaiting_analysis" && ctx.strategistState.step !== "awaiting_connect") {
18742
+ clearThinkFlow(ctx, "handoff");
18743
+ const { promptQueuedAiStrategist: promptQueuedAiStrategist2 } = await Promise.resolve().then(() => (init_strategist_flow(), strategist_flow_exports));
18744
+ promptQueuedAiStrategist2(ctx);
18745
+ }
18746
+ return "Think turn";
18747
+ }
18748
+ var THINK_INTENT_RE, CANCEL_RE2, DONE_RE;
18749
+ var init_think_flow = __esm({
18750
+ "src/conversation/think-flow.ts"() {
18751
+ "use strict";
18752
+ init_context2();
18753
+ init_repl_api();
18754
+ init_theme();
18755
+ init_handoff_draft();
18756
+ init_strategist_flow();
18757
+ 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;
18758
+ CANCEL_RE2 = /^(cancel|stop|quit|abort|never\s?mind|nevermind|forget it)\s*[.!]?\s*$/i;
18759
+ DONE_RE = /^(done|enough|enough for now|that'?s enough|leave|exit think)\s*[.!]?\s*$/i;
18760
+ }
18761
+ });
18762
+
18763
+ // src/conversation/gap-card.ts
18764
+ import chalk20 from "chalk";
18305
18765
  function printGapCard(audit, opts = {}) {
18306
18766
  console.log();
18307
18767
  if (opts.skipSatisfied) {
18308
18768
  if (audit.missing.length > 0) {
18309
- console.log(" " + chalk18.bold("Data check"));
18769
+ console.log(" " + chalk20.bold("Data check"));
18310
18770
  }
18311
18771
  } else if (audit.satisfied.length > 0) {
18312
18772
  const bits = audit.satisfied.map((item) => item.detail);
18313
18773
  console.log(
18314
- " " + chalk18.green("\u2713") + " " + chalk18.bold("Data check") + chalk18.dim(" \u2014 " + bits.join(" \xB7 "))
18774
+ " " + chalk20.green("\u2713") + " " + chalk20.bold("Data check") + chalk20.dim(" \u2014 " + bits.join(" \xB7 "))
18315
18775
  );
18316
18776
  } else {
18317
- console.log(" " + chalk18.bold("Data check"));
18777
+ console.log(" " + chalk20.bold("Data check"));
18318
18778
  }
18319
18779
  for (const item of audit.missing) {
18320
- console.log(" " + chalk18.red("\u2717") + " " + item.label + chalk18.dim(` \u2014 ${item.why}`));
18321
- console.log(" " + chalk18.dim(item.suggestion));
18780
+ console.log(" " + chalk20.red("\u2717") + " " + item.label + chalk20.dim(` \u2014 ${item.why}`));
18781
+ console.log(" " + chalk20.dim(item.suggestion));
18322
18782
  }
18323
18783
  if (audit.optional.length > 0) {
18324
18784
  const heads = audit.optional.map((item) => item.detail.split(" \u2014 ")[0] ?? item.detail);
18325
18785
  const joined = heads.join(" \xB7 ");
18326
18786
  if (joined.length <= 100) {
18327
- console.log(" " + chalk18.yellow("~") + " " + chalk18.dim(joined));
18787
+ console.log(" " + chalk20.yellow("~") + " " + chalk20.dim(joined));
18328
18788
  } else {
18329
18789
  for (const item of audit.optional) {
18330
- console.log(" " + chalk18.yellow("~") + " " + chalk18.dim(`${item.label}: ${item.detail}`));
18790
+ console.log(" " + chalk20.yellow("~") + " " + chalk20.dim(`${item.label}: ${item.detail}`));
18331
18791
  }
18332
18792
  }
18333
18793
  }
18334
18794
  console.log();
18335
18795
  if (audit.can_compute) {
18336
18796
  console.log(
18337
- " " + chalk18.dim("Ready to compute. Press ") + chalk18.cyan("\u23CE") + chalk18.dim(" or type ") + chalk18.cyan('"go ahead"')
18797
+ " " + chalk20.dim("Ready to compute. Press ") + chalk20.cyan("\u23CE") + chalk20.dim(" or type ") + chalk20.cyan('"go ahead"')
18338
18798
  );
18339
18799
  } else if (audit.missing.length > 0) {
18340
18800
  console.log(
18341
- " " + chalk18.dim("Load data. Paste a CSV path, or press ") + chalk18.cyan("\u23CE") + chalk18.dim(" to ") + chalk18.cyan("use demo data")
18801
+ " " + chalk20.dim("Load data. Paste a CSV path, or press ") + chalk20.cyan("\u23CE") + chalk20.dim(" to ") + chalk20.cyan("use demo data")
18342
18802
  );
18343
18803
  }
18344
18804
  console.log();
@@ -18355,7 +18815,7 @@ __export(keyless_ask_exports, {
18355
18815
  isKeylessVitalsAsk: () => isKeylessVitalsAsk,
18356
18816
  tryKeylessAskAnswer: () => tryKeylessAskAnswer
18357
18817
  });
18358
- import chalk19 from "chalk";
18818
+ import chalk21 from "chalk";
18359
18819
  function isKeylessVitalsAsk(input) {
18360
18820
  return KEYLESS_ASK_RE.test(input.trim());
18361
18821
  }
@@ -18404,35 +18864,35 @@ async function tryKeylessAskAnswer(ctx, input, opts = {}) {
18404
18864
  const headline = dollarBit ? `${label} \u2014 ${dollarBit} \u2014 is the most expensive problem to solve right now.` : `${label} (score ${Math.round(primary.score)}, ${primary.status}) is the problem to fix first.`;
18405
18865
  const runners = [...aggregate.vital_signs].filter((v) => v.vital_sign !== primary.vital_sign && (v.dollar_value ?? 0) > 0).sort((a, b) => (b.dollar_value ?? 0) - (a.dollar_value ?? 0)).slice(0, 2);
18406
18866
  console.log();
18407
- console.log(" " + chalk19.bold(headline));
18867
+ console.log(" " + chalk21.bold(headline));
18408
18868
  if (opts.fromResume) {
18409
18869
  if (runners.length > 0) {
18410
18870
  console.log(
18411
- " " + chalk19.dim("Next after that: ") + chalk19.dim(runners.map(formatRunnerBit).join(" \xB7 "))
18871
+ " " + chalk21.dim("Next after that: ") + chalk21.dim(runners.map(formatRunnerBit).join(" \xB7 "))
18412
18872
  );
18413
18873
  }
18414
18874
  } else {
18415
18875
  console.log();
18416
18876
  if (gating && gating.vital_sign !== primary.vital_sign) {
18417
18877
  console.log(
18418
- " " + chalk19.dim("Gating vital: ") + paint("accent", VITAL_SIGN_LABELS[gating.vital_sign]) + chalk19.dim(` (score ${Math.round(gating.score)}) \u2014 it bounds what you can trust downstream.`)
18878
+ " " + chalk21.dim("Gating vital: ") + paint("accent", VITAL_SIGN_LABELS[gating.vital_sign]) + chalk21.dim(` (score ${Math.round(gating.score)}) \u2014 it bounds what you can trust downstream.`)
18419
18879
  );
18420
18880
  }
18421
18881
  if (runners.length > 0) {
18422
- console.log(" " + chalk19.dim("Also on the board:"));
18882
+ console.log(" " + chalk21.dim("Also on the board:"));
18423
18883
  for (const vs of runners) {
18424
- console.log(" " + chalk19.dim("\xB7 ") + formatVitalLine(vs));
18884
+ console.log(" " + chalk21.dim("\xB7 ") + formatVitalLine(vs));
18425
18885
  }
18426
18886
  }
18427
18887
  if (aggregate.total_value_at_risk != null && aggregate.total_value_at_risk > 0) {
18428
18888
  console.log(
18429
- " " + chalk19.dim("Total at risk: ") + chalk19.green(formatCurrency(aggregate.total_value_at_risk))
18889
+ " " + chalk21.dim("Total at risk: ") + chalk21.green(formatCurrency(aggregate.total_value_at_risk))
18430
18890
  );
18431
18891
  }
18432
18892
  }
18433
18893
  console.log();
18434
18894
  console.log(
18435
- " " + chalk19.dim("Press ") + paint("accent", "\u23CE") + chalk19.dim(" to connect a key (") + paint("accent", "/connect") + chalk19.dim(") for the why and the plan. NTRP will finish this question after you connect.")
18895
+ " " + chalk21.dim("Press ") + paint("accent", "\u23CE") + chalk21.dim(" to connect a key (") + paint("accent", "/connect") + chalk21.dim(") for the why and the plan. NTRP will finish this question after you connect.")
18436
18896
  );
18437
18897
  console.log();
18438
18898
  if (!opts.fromResume) {
@@ -18455,7 +18915,7 @@ var init_keyless_ask = __esm({
18455
18915
  });
18456
18916
 
18457
18917
  // src/conversation/keyless-definitions.ts
18458
- import chalk20 from "chalk";
18918
+ import chalk22 from "chalk";
18459
18919
  function isPossessiveMetricAsk(input) {
18460
18920
  return POSSESSIVE_RE.test(input.trim());
18461
18921
  }
@@ -18508,9 +18968,9 @@ function tryKeylessDefinitionAnswer(ctx, input) {
18508
18968
  const bench = explainer.benchmarkHint?.(motion);
18509
18969
  console.log();
18510
18970
  console.log(
18511
- " " + sectionHeading(explainer.label) + chalk20.dim(` \xB7 ${explainer.kind === "vital" ? "vital sign" : "SaaS metric"}`)
18971
+ " " + sectionHeading(explainer.label) + chalk22.dim(` \xB7 ${explainer.kind === "vital" ? "vital sign" : "SaaS metric"}`)
18512
18972
  );
18513
- console.log(" " + chalk20.dim(explainer.tagline));
18973
+ console.log(" " + chalk22.dim(explainer.tagline));
18514
18974
  console.log();
18515
18975
  console.log(" " + bold("Meaning"));
18516
18976
  printWrapped2(explainer.meaning, " ");
@@ -18522,16 +18982,16 @@ function tryKeylessDefinitionAnswer(ctx, input) {
18522
18982
  }
18523
18983
  if (bench) {
18524
18984
  console.log();
18525
- console.log(" " + chalk20.dim(`Benchmark \xB7 ${bench}`));
18985
+ console.log(" " + chalk22.dim(`Benchmark \xB7 ${bench}`));
18526
18986
  }
18527
18987
  if (explainer.dollar_label) {
18528
18988
  console.log(
18529
- " " + chalk20.dim(`Dollar translation \xB7 ${explainer.dollar_label}`)
18989
+ " " + chalk22.dim(`Dollar translation \xB7 ${explainer.dollar_label}`)
18530
18990
  );
18531
18991
  }
18532
18992
  console.log();
18533
18993
  console.log(
18534
- " " + chalk20.dim("More: ") + paint("accent", `/deepdive ${explainer.id}`) + chalk20.dim(" \xB7 full tour: ") + paint("accent", "/deepdive")
18994
+ " " + chalk22.dim("More: ") + paint("accent", `/deepdive ${explainer.id}`) + chalk22.dim(" \xB7 full tour: ") + paint("accent", "/deepdive")
18535
18995
  );
18536
18996
  console.log();
18537
18997
  recordMessage(ctx, "user", input);
@@ -18561,7 +19021,7 @@ var init_keyless_definitions = __esm({
18561
19021
  });
18562
19022
 
18563
19023
  // src/conversation/orchestrator.ts
18564
- import chalk21 from "chalk";
19024
+ import chalk23 from "chalk";
18565
19025
  async function handleExploreWithoutKey(ctx, input) {
18566
19026
  if (isDefinitionAsk(input) && tryKeylessDefinitionAnswer(ctx, input)) {
18567
19027
  return;
@@ -18591,7 +19051,7 @@ async function handleExploreWithoutKey(ctx, input) {
18591
19051
  );
18592
19052
  if (ctx.pendingAsk) {
18593
19053
  console.log(
18594
- " " + chalk21.dim("Your question is stored. NTRP will answer it after you connect.")
19054
+ " " + chalk23.dim("Your question is stored. NTRP will answer it after you connect.")
18595
19055
  );
18596
19056
  }
18597
19057
  if (ctx.gapAudit) {
@@ -18606,12 +19066,12 @@ async function handleExploreWithoutKey(ctx, input) {
18606
19066
  return;
18607
19067
  }
18608
19068
  console.log();
18609
- console.log(" " + chalk21.yellow("No key is connected. Q&A stays off until you type ") + paint("accent", "/connect") + chalk21.yellow("."));
18610
- console.log(" " + chalk21.dim("These commands work without a key:"));
18611
- console.log(" " + paint("accent", "/deepdive") + chalk21.dim(" slides for numbers and how to use NTRP"));
18612
- console.log(" " + paint("accent", "/playbook") + chalk21.dim(" recommended plays from your computed vitals"));
18613
- console.log(" " + chalk21.cyan('"how should we fix this?"') + chalk21.dim(" a simple plan. No AI."));
18614
- console.log(" " + paint("accent", "/handoff") + chalk21.dim(" write this analysis for another tool"));
19069
+ console.log(" " + chalk23.yellow("No key is connected. Q&A stays off until you type ") + paint("accent", "/connect") + chalk23.yellow("."));
19070
+ console.log(" " + chalk23.dim("These commands work without a key:"));
19071
+ console.log(" " + paint("accent", "/deepdive") + chalk23.dim(" slides for numbers and how to use NTRP"));
19072
+ console.log(" " + paint("accent", "/playbook") + chalk23.dim(" recommended plays from your computed vitals"));
19073
+ console.log(" " + chalk23.cyan('"how should we fix this?"') + chalk23.dim(" a simple plan. No AI."));
19074
+ console.log(" " + paint("accent", "/handoff") + chalk23.dim(" write this analysis for another tool"));
18615
19075
  console.log();
18616
19076
  recordMessage(
18617
19077
  ctx,
@@ -19266,7 +19726,7 @@ var nl_exports = {};
19266
19726
  __export(nl_exports, {
19267
19727
  runNaturalLanguage: () => runNaturalLanguage
19268
19728
  });
19269
- import chalk22 from "chalk";
19729
+ import chalk24 from "chalk";
19270
19730
  async function runNaturalLanguage(input, ctx) {
19271
19731
  if (isSmokeProtocolTrigger(input)) {
19272
19732
  recordMessage(ctx, "user", input);
@@ -19278,10 +19738,10 @@ async function runNaturalLanguage(input, ctx) {
19278
19738
  printAnswer(result.answer);
19279
19739
  recordMessage(ctx, "agent", result.answer);
19280
19740
  console.log();
19281
- return extractSummary(result.answer);
19741
+ return extractSummary2(result.answer);
19282
19742
  } catch (err) {
19283
19743
  spinner2.fail("Smoke protocol failed");
19284
- console.error(" " + chalk22.red(String(err.message ?? err)));
19744
+ console.error(" " + chalk24.red(String(err.message ?? err)));
19285
19745
  console.log();
19286
19746
  return;
19287
19747
  }
@@ -19311,8 +19771,8 @@ async function runNaturalLanguage(input, ctx) {
19311
19771
  spinner2.succeed(metricsFirst ? "Session context ready" : "Health snapshot ready");
19312
19772
  } catch (err) {
19313
19773
  spinner2.fail("Could not compute health snapshot");
19314
- console.error(" " + chalk22.red(String(err.message ?? err)));
19315
- console.log(" " + chalk22.dim("Run ") + paint("accent", "/new") + chalk22.dim(" \u2192 pick Demo to load sample data."));
19774
+ console.error(" " + chalk24.red(String(err.message ?? err)));
19775
+ console.log(" " + chalk24.dim("Run ") + paint("accent", "/new") + chalk24.dim(" \u2192 pick Demo to load sample data."));
19316
19776
  console.log();
19317
19777
  return;
19318
19778
  }
@@ -19350,7 +19810,7 @@ async function runNaturalLanguage(input, ctx) {
19350
19810
  break;
19351
19811
  case "thinking":
19352
19812
  spinner.stop();
19353
- console.log(" " + chalk22.dim.italic(event.text));
19813
+ console.log(" " + chalk24.dim.italic(event.text));
19354
19814
  spinner.start("Thinking\u2026");
19355
19815
  break;
19356
19816
  case "answer":
@@ -19360,7 +19820,7 @@ async function runNaturalLanguage(input, ctx) {
19360
19820
  break;
19361
19821
  case "finding":
19362
19822
  spinner.stop();
19363
- printFindingInline(event.finding);
19823
+ printFindingInline2(event.finding);
19364
19824
  break;
19365
19825
  case "done":
19366
19826
  spinner.stop();
@@ -19370,7 +19830,7 @@ async function runNaturalLanguage(input, ctx) {
19370
19830
  }
19371
19831
  } catch (err) {
19372
19832
  spinner.fail("Error while investigating");
19373
- console.error(" " + chalk22.red(String(err.message ?? err)));
19833
+ console.error(" " + chalk24.red(String(err.message ?? err)));
19374
19834
  console.log();
19375
19835
  return;
19376
19836
  } finally {
@@ -19380,7 +19840,7 @@ async function runNaturalLanguage(input, ctx) {
19380
19840
  ctx.conversation = distillThread(rawHistory);
19381
19841
  }
19382
19842
  if (!lastAnswer) {
19383
- console.log(" " + chalk22.dim("(no answer returned)"));
19843
+ console.log(" " + chalk24.dim("(no answer returned)"));
19384
19844
  } else {
19385
19845
  recordMessage(ctx, "agent", lastAnswer);
19386
19846
  if (ctx.pendingAsk) {
@@ -19396,12 +19856,12 @@ async function runNaturalLanguage(input, ctx) {
19396
19856
  console.log();
19397
19857
  const { promptQueuedAiStrategist: promptQueuedAiStrategist2 } = await Promise.resolve().then(() => (init_strategist_flow(), strategist_flow_exports));
19398
19858
  promptQueuedAiStrategist2(ctx);
19399
- return lastAnswer ? extractSummary(lastAnswer) : void 0;
19859
+ return lastAnswer ? extractSummary2(lastAnswer) : void 0;
19400
19860
  }
19401
19861
  function printAnswer(text) {
19402
19862
  printMarkdown(text, { indent: 2 });
19403
19863
  }
19404
- function extractSummary(text) {
19864
+ function extractSummary2(text) {
19405
19865
  const plain = text.replace(/#{1,6}\s+/g, "").replace(/\*\*([^*]+)\*\*/g, "$1").replace(/\*([^*]+)\*/g, "$1").replace(/`([^`]+)`/g, "$1").replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/^[-*]\s+/gm, "").trim();
19406
19866
  const sentenceMatch = plain.match(/^(.+?[.!?])(?:\s|$)/);
19407
19867
  const sentence = sentenceMatch ? sentenceMatch[1] : plain.split("\n")[0];
@@ -19409,16 +19869,16 @@ function extractSummary(text) {
19409
19869
  const truncated = sentence.slice(0, 60).replace(/\s+\S*$/, "");
19410
19870
  return truncated + "\u2026";
19411
19871
  }
19412
- function printFindingInline(finding) {
19872
+ function printFindingInline2(finding) {
19413
19873
  const sev = finding.severity;
19414
19874
  console.log();
19415
- console.log(" " + severityPaint(sev)(`[${sev}]`) + " " + chalk22.bold(finding.segment));
19875
+ console.log(" " + severityPaint(sev)(`[${sev}]`) + " " + chalk24.bold(finding.segment));
19416
19876
  printMarkdown(finding.finding, { indent: 2 });
19417
19877
  const play = finding.recommended_plays?.[0];
19418
- if (play) console.log(" " + chalk22.dim("\u2192 " + play.play_name + " \u2014 " + play.rationale));
19878
+ if (play) console.log(" " + chalk24.dim("\u2192 " + play.play_name + " \u2014 " + play.rationale));
19419
19879
  if (finding.recommended_focus) {
19420
19880
  console.log(
19421
- " " + chalk22.dim("How this works: ") + paint("accent", `/deepdive ${finding.recommended_focus}`)
19881
+ " " + chalk24.dim("How this works: ") + paint("accent", `/deepdive ${finding.recommended_focus}`)
19422
19882
  );
19423
19883
  }
19424
19884
  }
@@ -19454,12 +19914,12 @@ __export(demo_exports, {
19454
19914
  printDemoDisabled: () => printDemoDisabled,
19455
19915
  setDemoEnabled: () => setDemoEnabled
19456
19916
  });
19457
- import chalk23 from "chalk";
19917
+ import chalk25 from "chalk";
19458
19918
  function printDemoDisabled() {
19459
19919
  console.log();
19460
- console.log(" " + chalk23.red(DEMO_DISABLED_MESSAGE));
19920
+ console.log(" " + chalk25.red(DEMO_DISABLED_MESSAGE));
19461
19921
  console.log(
19462
- " " + chalk23.dim("Re-enable with ") + paint("accent", "/config set demo-enabled true") + chalk23.dim(".")
19922
+ " " + chalk25.dim("Re-enable with ") + paint("accent", "/config set demo-enabled true") + chalk25.dim(".")
19463
19923
  );
19464
19924
  console.log();
19465
19925
  }
@@ -22761,16 +23221,16 @@ var generate_exports = {};
22761
23221
  __export(generate_exports, {
22762
23222
  handler: () => handler2
22763
23223
  });
22764
- import chalk24 from "chalk";
23224
+ import chalk26 from "chalk";
22765
23225
  async function handler2(args, ctx) {
22766
23226
  const { flags } = parseArgs(args, ["list-scenarios", "regen-taxonomy", "brief"]);
22767
23227
  const quiet = ctx.execution.quiet;
22768
23228
  const brief = getBool(flags, "brief");
22769
23229
  if (getBool(flags, "list-scenarios")) {
22770
- console.log(chalk24.bold("\n Available Scenarios:\n"));
23230
+ console.log(chalk26.bold("\n Available Scenarios:\n"));
22771
23231
  for (const s of SCENARIO_LIST) {
22772
- console.log(` ${chalk24.cyan(s.key.padEnd(20))} ${s.label}`);
22773
- console.log(` ${chalk24.dim(" ".repeat(20))} ${s.description}
23232
+ console.log(` ${chalk26.cyan(s.key.padEnd(20))} ${s.label}`);
23233
+ console.log(` ${chalk26.dim(" ".repeat(20))} ${s.description}
22774
23234
  `);
22775
23235
  }
22776
23236
  return true;
@@ -22780,9 +23240,9 @@ async function handler2(args, ctx) {
22780
23240
  const skipProfile = getFalse(flags, "profile");
22781
23241
  if (!isProfileConfigured(profile) && !skipProfile) {
22782
23242
  console.error();
22783
- console.error(" " + chalk24.red("No company profile found."));
22784
- console.error(" " + chalk24.dim("Run ") + paint("accent", "/onboard") + chalk24.dim(" first for a richer demo,"));
22785
- console.error(" " + chalk24.dim("or pass ") + paint("accent", "--no-profile") + chalk24.dim(" to skip."));
23243
+ console.error(" " + chalk26.red("No company profile found."));
23244
+ console.error(" " + chalk26.dim("Run ") + paint("accent", "/onboard") + chalk26.dim(" first for a richer demo,"));
23245
+ console.error(" " + chalk26.dim("or pass ") + paint("accent", "--no-profile") + chalk26.dim(" to skip."));
22786
23246
  console.error();
22787
23247
  markFailure(ctx);
22788
23248
  return false;
@@ -22790,8 +23250,8 @@ async function handler2(args, ctx) {
22790
23250
  const explicitScenario = getString(flags, "scenario", "s");
22791
23251
  const resolvedScenario = resolveScenarioInput(explicitScenario);
22792
23252
  if (resolvedScenario === null) {
22793
- console.error(chalk24.red(` Unknown scenario: ${explicitScenario}`));
22794
- console.log(chalk24.dim(` Valid: ${SCENARIO_LIST.map((s) => s.key).join(", ")}`));
23253
+ console.error(chalk26.red(` Unknown scenario: ${explicitScenario}`));
23254
+ console.log(chalk26.dim(` Valid: ${SCENARIO_LIST.map((s) => s.key).join(", ")}`));
22795
23255
  markFailure(ctx);
22796
23256
  return false;
22797
23257
  }
@@ -22805,10 +23265,10 @@ async function handler2(args, ctx) {
22805
23265
  const s = getScenario(scenario);
22806
23266
  console.log();
22807
23267
  if (brief) {
22808
- console.log(" " + paint("accent", "\u2713 Demo: ") + bold(s.label) + chalk24.dim(" \u2014 " + s.hook));
23268
+ console.log(" " + paint("accent", "\u2713 Demo: ") + bold(s.label) + chalk26.dim(" \u2014 " + s.hook));
22809
23269
  } else {
22810
23270
  console.log(" " + paint("accent", "\u2713 Scenario: ") + bold(s.label));
22811
- console.log(" " + chalk24.dim(s.story));
23271
+ console.log(" " + chalk26.dim(s.story));
22812
23272
  console.log();
22813
23273
  }
22814
23274
  }
@@ -22838,18 +23298,18 @@ async function handler2(args, ctx) {
22838
23298
  if (brief) {
22839
23299
  spinner.succeed(`Demo loaded \u2014 ${briefCounts(result.counts)}`);
22840
23300
  } else {
22841
- spinner.succeed(`Generated demo data for "${chalk24.cyan(scenario)}" scenario`);
23301
+ spinner.succeed(`Generated demo data for "${chalk26.cyan(scenario)}" scenario`);
22842
23302
  console.log();
22843
23303
  printEntityCounts(result.counts);
22844
23304
  }
22845
23305
  }
22846
23306
  if (!quiet && !brief && ctx.analysis.primary !== "revenue_metrics") {
22847
- console.log(chalk24.dim("\n Run /diagnose to compute vital signs.\n"));
23307
+ console.log(chalk26.dim("\n Run /diagnose to compute vital signs.\n"));
22848
23308
  }
22849
23309
  }
22850
23310
  } catch (err) {
22851
23311
  if (spinner) spinner.fail("Generation failed");
22852
- console.error(chalk24.red(String(err)));
23312
+ console.error(chalk26.red(String(err)));
22853
23313
  markFailure(ctx);
22854
23314
  return false;
22855
23315
  }
@@ -22887,7 +23347,7 @@ async function loadOrBuildTaxonomy(profile, forceRegen, ctx) {
22887
23347
  return taxonomy;
22888
23348
  } catch (err) {
22889
23349
  spinner.fail("Couldn't build market taxonomy \u2014 using generic data pools");
22890
- console.log(" " + chalk24.dim(String(err.message ?? err)));
23350
+ console.log(" " + chalk26.dim(String(err.message ?? err)));
22891
23351
  return void 0;
22892
23352
  }
22893
23353
  }
@@ -22979,9 +23439,11 @@ var inbox_setup_exports = {};
22979
23439
  __export(inbox_setup_exports, {
22980
23440
  maybeOfferInboxOnProduction: () => maybeOfferInboxOnProduction,
22981
23441
  offerInboxSkillSetup: () => offerInboxSkillSetup,
23442
+ reuseInboxFolderIfPresent: () => reuseInboxFolderIfPresent,
22982
23443
  shouldOfferInboxSkillSetup: () => shouldOfferInboxSkillSetup
22983
23444
  });
22984
- import chalk25 from "chalk";
23445
+ import chalk27 from "chalk";
23446
+ import { existsSync as existsSync22 } from "fs";
22985
23447
  function markDemoOffered() {
22986
23448
  setConfigValue("ai-inbox-nudge-seen", "true");
22987
23449
  }
@@ -23002,28 +23464,46 @@ function printSkipHint(beat) {
23002
23464
  const skillCmd = paint("accent", "/inbox skill");
23003
23465
  if (beat === "demo") {
23004
23466
  console.log(
23005
- " " + chalk25.dim("Skipped. NTRP will ask once when you load your own data. Or type ") + setCmd + chalk25.dim(" then ") + skillCmd
23467
+ " " + chalk27.dim("Skipped. NTRP will ask once when you load your own data. Or type ") + setCmd + chalk27.dim(" then ") + skillCmd
23006
23468
  );
23007
23469
  return;
23008
23470
  }
23009
23471
  console.log(
23010
- " " + chalk25.dim("Skipped. NTRP will not ask again. Type ") + setCmd + chalk25.dim(" then ") + skillCmd + chalk25.dim(" at any time.")
23472
+ " " + chalk27.dim("Skipped. NTRP will not ask again. Type ") + setCmd + chalk27.dim(" then ") + skillCmd + chalk27.dim(" at any time.")
23011
23473
  );
23012
23474
  }
23475
+ async function reuseInboxFolderIfPresent(session, beat, folderPath = defaultAiInboxDir()) {
23476
+ if (getAiInboxDir()) return false;
23477
+ if (!existsSync22(folderPath)) return false;
23478
+ console.log(" " + chalk27.dim("Pickup folder still on disk: ") + folderPath);
23479
+ const reuse = await session.confirm("Reuse this pickup folder?", true);
23480
+ if (!reuse) return false;
23481
+ const resolved = setAiInboxDir(folderPath);
23482
+ markDemoOffered();
23483
+ if (beat === "production") markProductionOffered();
23484
+ console.log();
23485
+ console.log(" " + paint("accent", "Inbox ready") + chalk27.dim(" ") + resolved);
23486
+ console.log(
23487
+ " " + chalk27.dim("Folder reused. Type ") + paint("accent", "/inbox skill") + chalk27.dim(" to print the finder again.")
23488
+ );
23489
+ console.log();
23490
+ return true;
23491
+ }
23013
23492
  async function offerInboxSkillSetup(session, opts = {}) {
23014
23493
  const beat = opts.beat ?? "production";
23015
23494
  if (!shouldOfferInboxSkillSetup(beat)) return;
23016
23495
  console.log();
23017
23496
  console.log(" " + bold("Teach Claude where handoffs live"));
23018
23497
  console.log(
23019
- " " + chalk25.dim(
23498
+ " " + chalk27.dim(
23020
23499
  "Optional. NTRP copies every handoff into one folder. You paste instructions once; later /handoff just writes the file."
23021
23500
  )
23022
23501
  );
23023
23502
  if (beat === "production" && getConfigValue("ai-inbox-nudge-seen") === "true") {
23024
- console.log(" " + chalk25.dim("You skipped this during demo."));
23503
+ console.log(" " + chalk27.dim("You skipped this during demo."));
23025
23504
  }
23026
23505
  console.log();
23506
+ if (await reuseInboxFolderIfPresent(session, beat)) return;
23027
23507
  const want = await session.confirm("Set a pickup folder for Claude, ChatGPT, or Cursor?", true);
23028
23508
  if (!want) {
23029
23509
  if (beat === "demo") markDemoOffered();
@@ -23051,16 +23531,16 @@ async function offerInboxSkillSetup(session, opts = {}) {
23051
23531
  markDemoOffered();
23052
23532
  if (beat === "production") markProductionOffered();
23053
23533
  console.log();
23054
- console.log(" " + paint("accent", "Inbox ready") + chalk25.dim(" ") + resolved);
23534
+ console.log(" " + paint("accent", "Inbox ready") + chalk27.dim(" ") + resolved);
23055
23535
  if (n > 0) {
23056
- console.log(" " + chalk25.dim(`Synced ${n} recent export${n === 1 ? "" : "s"}.`));
23536
+ console.log(" " + chalk27.dim(`Synced ${n} recent export${n === 1 ? "" : "s"}.`));
23057
23537
  }
23058
23538
  console.log(
23059
- " " + chalk25.dim("Paste this skill into Claude once. Later, tell Claude to open the latest NTRP handoff.")
23539
+ " " + chalk27.dim("Paste this skill into Claude once. Later, tell Claude to open the latest NTRP handoff.")
23060
23540
  );
23061
23541
  printStandingSkill();
23062
23542
  await session.askPressEnter("Paste the skill into Claude. Then continue");
23063
- console.log(" " + chalk25.dim("Done. Later handoffs write to that folder. The skill is not printed again."));
23543
+ console.log(" " + chalk27.dim("Done. Later handoffs write to that folder. The skill is not printed again."));
23064
23544
  console.log();
23065
23545
  }
23066
23546
  async function maybeOfferInboxOnProduction(ctx) {
@@ -23093,8 +23573,8 @@ var ingest_exports = {};
23093
23573
  __export(ingest_exports, {
23094
23574
  handler: () => handler3
23095
23575
  });
23096
- import chalk26 from "chalk";
23097
- import { readFileSync as readFileSync20, existsSync as existsSync22 } from "fs";
23576
+ import chalk28 from "chalk";
23577
+ import { readFileSync as readFileSync20, existsSync as existsSync23 } from "fs";
23098
23578
  import { basename as basename6 } from "path";
23099
23579
  async function handler3(args, ctx) {
23100
23580
  const { positional, flags } = parseArgs(args, [
@@ -23114,21 +23594,21 @@ async function handler3(args, ctx) {
23114
23594
  const source = getString(flags, "source", "s") ?? "salesforce";
23115
23595
  const skipResolve = getBool(flags, "skip-resolve");
23116
23596
  if (!file) {
23117
- console.error(chalk26.red(" Usage: /ingest <file> [--source salesforce|hubspot|outreach]"));
23118
- console.error(chalk26.dim(" /ingest --demo [--scenario <name>]"));
23597
+ console.error(chalk28.red(" Usage: /ingest <file> [--source salesforce|hubspot|outreach]"));
23598
+ console.error(chalk28.dim(" /ingest --demo [--scenario <name>]"));
23119
23599
  process.exit(1);
23120
23600
  }
23121
- if (!existsSync22(file)) {
23122
- console.error(chalk26.red(` File not found: ${file}`));
23601
+ if (!existsSync23(file)) {
23602
+ console.error(chalk28.red(` File not found: ${file}`));
23123
23603
  process.exit(1);
23124
23604
  }
23125
23605
  const profile = loadProfile();
23126
23606
  const skipProfile = getFalse(flags, "profile");
23127
23607
  if (!profile && !skipProfile) {
23128
23608
  console.error();
23129
- console.error(" " + chalk26.red("No company profile found."));
23130
- console.error(" " + chalk26.dim("Run ") + paint("accent", "/onboard") + chalk26.dim(" first for better column mapping,"));
23131
- console.error(" " + chalk26.dim("or pass ") + paint("accent", "--no-profile") + chalk26.dim(" to skip."));
23609
+ console.error(" " + chalk28.red("No company profile found."));
23610
+ console.error(" " + chalk28.dim("Run ") + paint("accent", "/onboard") + chalk28.dim(" first for better column mapping,"));
23611
+ console.error(" " + chalk28.dim("or pass ") + paint("accent", "--no-profile") + chalk28.dim(" to skip."));
23132
23612
  console.error();
23133
23613
  process.exit(1);
23134
23614
  }
@@ -23160,15 +23640,15 @@ async function handler3(args, ctx) {
23160
23640
  row_count: result2.imported
23161
23641
  });
23162
23642
  spinner.succeed(
23163
- `Imported ${chalk26.bold(result2.imported.toString())} revenue events from ${chalk26.dim(basename6(file))}`
23643
+ `Imported ${chalk28.bold(result2.imported.toString())} revenue events from ${chalk28.dim(basename6(file))}`
23164
23644
  );
23165
23645
  if (result2.errors.length > 0) {
23166
- console.log(chalk26.yellow(` ${result2.errors.length} rows skipped`));
23646
+ console.log(chalk28.yellow(` ${result2.errors.length} rows skipped`));
23167
23647
  }
23168
23648
  if (ctx.analysis) {
23169
23649
  ctx.analysis.data_source_type = "revenue_ledger";
23170
23650
  }
23171
- console.log(chalk26.dim(" Run ") + chalk26.cyan("/metrics") + chalk26.dim(" for SaaS metrics with ledger-backed retention."));
23651
+ console.log(chalk28.dim(" Run ") + chalk28.cyan("/metrics") + chalk28.dim(" for SaaS metrics with ledger-backed retention."));
23172
23652
  const { maybeOfferInboxOnProduction: maybeOfferInboxOnProduction3 } = await Promise.resolve().then(() => (init_inbox_setup(), inbox_setup_exports));
23173
23653
  await maybeOfferInboxOnProduction3(ctx);
23174
23654
  return `${result2.imported} revenue events from ${basename6(file)}`;
@@ -23177,7 +23657,7 @@ async function handler3(args, ctx) {
23177
23657
  const detection = detectEntityType(headers, source);
23178
23658
  if (!detection) {
23179
23659
  spinner.fail(`Could not auto-detect entity type for source: ${source}`);
23180
- console.log(chalk26.dim(" Headers found: " + headers.join(", ")));
23660
+ console.log(chalk28.dim(" Headers found: " + headers.join(", ")));
23181
23661
  process.exit(1);
23182
23662
  }
23183
23663
  spinner.text = `Importing ${rows.length} ${detection.entityType} rows...`;
@@ -23200,15 +23680,15 @@ async function handler3(args, ctx) {
23200
23680
  row_count: result.imported
23201
23681
  });
23202
23682
  spinner.succeed(
23203
- `Imported ${chalk26.bold(result.imported.toString())} ${detection.entityType} from ${chalk26.dim(basename6(file))} (${source})`
23683
+ `Imported ${chalk28.bold(result.imported.toString())} ${detection.entityType} from ${chalk28.dim(basename6(file))} (${source})`
23204
23684
  );
23205
23685
  if (result.errors.length > 0) {
23206
- console.log(chalk26.yellow(` ${result.errors.length} rows skipped`));
23686
+ console.log(chalk28.yellow(` ${result.errors.length} rows skipped`));
23207
23687
  for (const err of result.errors.slice(0, 3)) {
23208
- console.log(chalk26.dim(` - ${err}`));
23688
+ console.log(chalk28.dim(` - ${err}`));
23209
23689
  }
23210
23690
  if (result.errors.length > 3) {
23211
- console.log(chalk26.dim(` ... and ${result.errors.length - 3} more`));
23691
+ console.log(chalk28.dim(` ... and ${result.errors.length - 3} more`));
23212
23692
  }
23213
23693
  }
23214
23694
  if (!skipResolve) {
@@ -23227,7 +23707,7 @@ async function handler3(args, ctx) {
23227
23707
  return `${result.imported} ${detection.entityType} from ${basename6(file)}`;
23228
23708
  } catch (err) {
23229
23709
  spinner.fail("Import failed");
23230
- console.error(chalk26.red(String(err)));
23710
+ console.error(chalk28.red(String(err)));
23231
23711
  process.exit(1);
23232
23712
  }
23233
23713
  }
@@ -23339,13 +23819,13 @@ __export(demo_fit_exports, {
23339
23819
  resolveDemoScenarioForLoad: () => resolveDemoScenarioForLoad,
23340
23820
  runDemoFitQuiz: () => runDemoFitQuiz
23341
23821
  });
23342
- import chalk27 from "chalk";
23822
+ import chalk29 from "chalk";
23343
23823
  async function runDemoFitQuiz(session, opts = {}) {
23344
23824
  if (opts.intro !== false) {
23345
23825
  console.log();
23346
23826
  console.log(" " + bold("Fit a sample book of business"));
23347
23827
  console.log(
23348
- " " + chalk27.dim(
23828
+ " " + chalk29.dim(
23349
23829
  "No API key needed. Two questions about how you sell, then you pick which of seven sample pipelines feels closest."
23350
23830
  )
23351
23831
  );
@@ -23363,8 +23843,8 @@ async function runDemoFitQuiz(session, opts = {}) {
23363
23843
  );
23364
23844
  const recommended = inferDemoScenario({ salesMotion: motion, dealBand });
23365
23845
  console.log();
23366
- console.log(" " + chalk27.dim("Recommended: ") + paint("accent", getScenario(recommended.scenario).label));
23367
- console.log(" " + chalk27.dim(recommended.reason));
23846
+ console.log(" " + chalk29.dim("Recommended: ") + paint("accent", getScenario(recommended.scenario).label));
23847
+ console.log(" " + chalk29.dim(recommended.reason));
23368
23848
  const scenario = await session.choose(
23369
23849
  "Which of these sample books feels closest to the one you manage?",
23370
23850
  scenarioMenuChoices(),
@@ -23384,8 +23864,8 @@ async function offerFittedDemoAfterOnboard(session, ctx, profile) {
23384
23864
  const s = getScenario(fit.scenario);
23385
23865
  console.log();
23386
23866
  console.log(" " + bold("A sample pipeline that looks like you"));
23387
- console.log(" " + paint("accent", s.label) + chalk27.dim(" \u2014 " + s.hook));
23388
- console.log(" " + chalk27.dim(fit.reason));
23867
+ console.log(" " + paint("accent", s.label) + chalk29.dim(" \u2014 " + s.hook));
23868
+ console.log(" " + chalk29.dim(fit.reason));
23389
23869
  console.log();
23390
23870
  const action = await session.choose(
23391
23871
  "Try NTRP on that book of business?",
@@ -23442,8 +23922,8 @@ async function resolveDemoScenarioForLoad(ctx, opts = {}) {
23442
23922
  if (!opts.forceQuiz && isProfileConfigured(profile) && profile) {
23443
23923
  const fit = await resolveProfileFit(profile, ctx);
23444
23924
  console.log();
23445
- console.log(" " + chalk27.dim("Recommended: ") + paint("accent", getScenario(fit.scenario).label));
23446
- console.log(" " + chalk27.dim(fit.reason));
23925
+ console.log(" " + chalk29.dim("Recommended: ") + paint("accent", getScenario(fit.scenario).label));
23926
+ console.log(" " + chalk29.dim(fit.reason));
23447
23927
  const scenario = await session.choose(
23448
23928
  "Which sample book of business?",
23449
23929
  scenarioMenuChoices(),
@@ -23504,10 +23984,10 @@ __export(ingest_chat_exports, {
23504
23984
  loadDemoFromChat: () => loadDemoFromChat,
23505
23985
  looksLikeFilePath: () => looksLikeFilePath
23506
23986
  });
23507
- import { existsSync as existsSync23 } from "fs";
23987
+ import { existsSync as existsSync24 } from "fs";
23508
23988
  import { basename as basename7, resolve as resolve9 } from "path";
23509
23989
  import { homedir as homedir8 } from "os";
23510
- import chalk28 from "chalk";
23990
+ import chalk30 from "chalk";
23511
23991
  function extractFilePath(input) {
23512
23992
  const trimmed = input.trim();
23513
23993
  const patterns = [
@@ -23524,11 +24004,11 @@ function extractFilePath(input) {
23524
24004
  const m = trimmed.match(re);
23525
24005
  if (m?.[1]) {
23526
24006
  const p = expandPath(m[1]);
23527
- if (existsSync23(p)) return p;
24007
+ if (existsSync24(p)) return p;
23528
24008
  }
23529
24009
  if (!m?.[1] && re.test(trimmed) && trimmed.toLowerCase().endsWith(".csv")) {
23530
24010
  const p = expandPath(trimmed.replace(/^["']|["']$/g, ""));
23531
- if (existsSync23(p)) return p;
24011
+ if (existsSync24(p)) return p;
23532
24012
  }
23533
24013
  }
23534
24014
  return null;
@@ -23542,7 +24022,7 @@ function looksLikeFilePath(input) {
23542
24022
  }
23543
24023
  async function ingestFromChat(ctx, filePath) {
23544
24024
  if (!ctx.rl) {
23545
- console.log(" " + chalk28.red("Ingest confirm requires interactive mode."));
24025
+ console.log(" " + chalk30.red("Ingest confirm requires interactive mode."));
23546
24026
  return false;
23547
24027
  }
23548
24028
  const name = basename7(filePath);
@@ -23550,7 +24030,7 @@ async function ingestFromChat(ctx, filePath) {
23550
24030
  try {
23551
24031
  const ok = await prompts.confirm(`Ingest ${name} as CRM export?`, true);
23552
24032
  if (!ok) {
23553
- console.log(" " + chalk28.dim("Ingest cancelled."));
24033
+ console.log(" " + chalk30.dim("Ingest cancelled."));
23554
24034
  return false;
23555
24035
  }
23556
24036
  } finally {
@@ -23578,7 +24058,7 @@ async function ingestFromChat(ctx, filePath) {
23578
24058
  true
23579
24059
  );
23580
24060
  if (useAi) {
23581
- console.log(" " + chalk28.dim("AI column mapping is not wired to ingest yet \u2014 trying standard ingest."));
24061
+ console.log(" " + chalk30.dim("AI column mapping is not wired to ingest yet \u2014 trying standard ingest."));
23582
24062
  }
23583
24063
  } finally {
23584
24064
  prompts2.close();
@@ -23605,7 +24085,7 @@ async function ingestFromChat(ctx, filePath) {
23605
24085
  invalidateGapAudit(ctx);
23606
24086
  saveSessionState(ctx);
23607
24087
  console.log();
23608
- console.log(" " + paint("accent", "\u2713 Data loaded") + chalk28.dim(` \u2014 ${name}`));
24088
+ console.log(" " + paint("accent", "\u2713 Data loaded") + chalk30.dim(` \u2014 ${name}`));
23609
24089
  recordMessage(ctx, "user", `[ingested ${name}]`);
23610
24090
  recordMessage(ctx, "agent", `Loaded ${name}. Checking what we can analyze\u2026`);
23611
24091
  const audit = await refreshGapAudit(ctx);
@@ -23613,7 +24093,7 @@ async function ingestFromChat(ctx, filePath) {
23613
24093
  if (audit.can_compute && ctx.scope?.confirmed_at) {
23614
24094
  if (ctx.pendingAsk) {
23615
24095
  console.log();
23616
- console.log(" " + chalk28.dim("Computing so I can answer\u2026"));
24096
+ console.log(" " + chalk30.dim("Computing so I can answer\u2026"));
23617
24097
  await runConversationCompute(ctx);
23618
24098
  return true;
23619
24099
  }
@@ -23661,7 +24141,7 @@ async function loadDemoFromChat(ctx, scenario, opts = {}) {
23661
24141
  const { getScenario: getScenario2 } = await Promise.resolve().then(() => (init_scenarios(), scenarios_exports));
23662
24142
  const s = getScenario2(chosen);
23663
24143
  console.log();
23664
- console.log(" " + paint("accent", "Fitting ") + s.label + chalk28.dim(" \u2014 " + s.hook));
24144
+ console.log(" " + paint("accent", "Fitting ") + s.label + chalk30.dim(" \u2014 " + s.hook));
23665
24145
  }
23666
24146
  const { handler: demo } = await Promise.resolve().then(() => (init_generate(), generate_exports));
23667
24147
  const args = ["--no-profile", "--brief"];
@@ -23697,7 +24177,7 @@ async function loadDemoFromChat(ctx, scenario, opts = {}) {
23697
24177
  const shouldAuto = opts.autoCompute || Boolean(ctx.pendingAsk && audit.can_compute && ctx.scope?.confirmed_at);
23698
24178
  if (shouldAuto && audit.can_compute) {
23699
24179
  console.log();
23700
- console.log(" " + chalk28.dim("Computing so I can answer\u2026"));
24180
+ console.log(" " + chalk30.dim("Computing so I can answer\u2026"));
23701
24181
  await runConversationCompute(ctx);
23702
24182
  return true;
23703
24183
  }
@@ -23730,7 +24210,7 @@ __export(pending_ask_exports, {
23730
24210
  queuePendingAsk: () => queuePendingAsk,
23731
24211
  resumePendingAsk: () => resumePendingAsk
23732
24212
  });
23733
- import chalk29 from "chalk";
24213
+ import chalk31 from "chalk";
23734
24214
  function looksLikeQuestion(input) {
23735
24215
  const text = input.trim();
23736
24216
  if (!text) return false;
@@ -23766,7 +24246,7 @@ function printFocusChip(ctx) {
23766
24246
  const period = ctx.scope.time_horizon ? ` \xB7 ${ctx.scope.time_horizon}` : "";
23767
24247
  console.log();
23768
24248
  console.log(
23769
- " " + chalk29.dim("Focus: ") + paint("accent", lens) + chalk29.dim(period) + chalk29.dim(" \u2014 type ") + chalk29.cyan("adjust") + chalk29.dim(" to change")
24249
+ " " + chalk31.dim("Focus: ") + paint("accent", lens) + chalk31.dim(period) + chalk31.dim(" \u2014 type ") + chalk31.cyan("adjust") + chalk31.dim(" to change")
23770
24250
  );
23771
24251
  console.log();
23772
24252
  }
@@ -23777,7 +24257,7 @@ async function resumePendingAsk(ctx) {
23777
24257
  if (canUseReplAi(ctx)) {
23778
24258
  console.log();
23779
24259
  console.log(
23780
- " " + chalk29.dim(
24260
+ " " + chalk31.dim(
23781
24261
  pending.keylessAnswered ? "Picking up your question with the connected engine\u2026" : "Picking up your question\u2026"
23782
24262
  )
23783
24263
  );
@@ -23810,7 +24290,7 @@ async function offerDemoToAnswer(ctx) {
23810
24290
  const go = await prompts.confirm("Use demo data to answer this?", true);
23811
24291
  if (!go) {
23812
24292
  console.log(
23813
- " " + chalk29.dim("Paste a CSV path when ready, or say ") + chalk29.cyan("use demo data") + chalk29.dim(".")
24293
+ " " + chalk31.dim("Paste a CSV path when ready, or say ") + chalk31.cyan("use demo data") + chalk31.dim(".")
23814
24294
  );
23815
24295
  console.log();
23816
24296
  return false;
@@ -23842,11 +24322,11 @@ __export(compute_exports2, {
23842
24322
  isComputeIntent: () => isComputeIntent,
23843
24323
  runConversationCompute: () => runConversationCompute
23844
24324
  });
23845
- import chalk30 from "chalk";
24325
+ import chalk32 from "chalk";
23846
24326
  async function runConversationCompute(ctx) {
23847
24327
  const lens = ctx.scope?.primary_lens ?? ctx.analysis.primary;
23848
24328
  ctx.computeInProgress = true;
23849
- const willAnswer = Boolean(ctx.pendingAsk?.text) && !ctx.strategistState;
24329
+ const willAnswer = Boolean(ctx.pendingAsk?.text) && !ctx.strategistState && ctx.thinkState?.step !== "awaiting_analysis";
23850
24330
  try {
23851
24331
  if (lens === "revenue_metrics") {
23852
24332
  const { runMetricsAnalysis: runMetricsAnalysis2, extractHeadlineMetrics: extractHeadlineMetrics2 } = await Promise.resolve().then(() => (init_metrics_analysis(), metrics_analysis_exports));
@@ -23874,6 +24354,7 @@ async function runConversationCompute(ctx) {
23874
24354
  interactive: !willAnswer
23875
24355
  });
23876
24356
  await resumeQueuedStrategist(ctx);
24357
+ await resumeQueuedThink(ctx);
23877
24358
  await closeComputeTurn(ctx, willAnswer, "revenue_metrics");
23878
24359
  creditGapCompute(ctx);
23879
24360
  creditMetricsComplete(ctx, false);
@@ -23893,11 +24374,12 @@ async function runConversationCompute(ctx) {
23893
24374
  invalidateGapAudit(ctx);
23894
24375
  saveSessionState(ctx);
23895
24376
  await resumeQueuedStrategist(ctx);
24377
+ await resumeQueuedThink(ctx);
23896
24378
  await closeComputeTurn(ctx, willAnswer, "gtm_health");
23897
24379
  creditGapCompute(ctx);
23898
24380
  return typeof summary === "string" ? summary : "Health analysis ready";
23899
24381
  } catch (err) {
23900
- console.error(" " + chalk30.red(String(err.message ?? err)));
24382
+ console.error(" " + chalk32.red(String(err.message ?? err)));
23901
24383
  return;
23902
24384
  } finally {
23903
24385
  ctx.computeInProgress = false;
@@ -23910,9 +24392,16 @@ async function resumeQueuedStrategist(ctx) {
23910
24392
  const { resumeStrategistAfterCompute: resumeStrategistAfterCompute2 } = await Promise.resolve().then(() => (init_strategist_flow(), strategist_flow_exports));
23911
24393
  await resumeStrategistAfterCompute2(ctx);
23912
24394
  }
24395
+ async function resumeQueuedThink(ctx) {
24396
+ if (ctx.thinkState?.step !== "awaiting_analysis") return;
24397
+ ctx.computeInProgress = false;
24398
+ const { resumeThinkAfterCompute: resumeThinkAfterCompute2 } = await Promise.resolve().then(() => (init_think_flow(), think_flow_exports));
24399
+ await resumeThinkAfterCompute2(ctx);
24400
+ }
23913
24401
  async function resumePendingAskAfterCompute(ctx) {
23914
24402
  if (!ctx.pendingAsk?.text) return false;
23915
24403
  if (ctx.strategistState) return false;
24404
+ if (ctx.thinkState?.step === "active" || ctx.thinkState?.step === "awaiting_analysis") return false;
23916
24405
  const { resumePendingAsk: resumePendingAsk2 } = await Promise.resolve().then(() => (init_pending_ask(), pending_ask_exports));
23917
24406
  return resumePendingAsk2(ctx);
23918
24407
  }
@@ -24381,6 +24870,7 @@ async function handleDraftStrategy(input) {
24381
24870
  if (!objective) return { error: "objective is required." };
24382
24871
  if (!isAnalysisReady2(ctx)) {
24383
24872
  ctx.strategistState = { step: "awaiting_analysis", objective, origin: "ai" };
24873
+ if (ctx.thinkState) ctx.thinkState = void 0;
24384
24874
  saveSessionState2(ctx);
24385
24875
  return {
24386
24876
  queued: true,
@@ -24389,6 +24879,7 @@ async function handleDraftStrategy(input) {
24389
24879
  };
24390
24880
  }
24391
24881
  ctx.strategistState = { step: "objective_confirm", objective, origin: "ai" };
24882
+ if (ctx.thinkState) ctx.thinkState = void 0;
24392
24883
  saveSessionState2(ctx);
24393
24884
  return {
24394
24885
  launched: true,
@@ -24396,6 +24887,32 @@ async function handleDraftStrategy(input) {
24396
24887
  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."
24397
24888
  };
24398
24889
  }
24890
+ async function handleUpdateThinkScratch(input) {
24891
+ const { getAgentContext: getAgentContext2 } = await Promise.resolve().then(() => (init_agent_context(), agent_context_exports));
24892
+ const { saveSessionState: saveSessionState2 } = await Promise.resolve().then(() => (init_context2(), context_exports));
24893
+ const ctx = getAgentContext2();
24894
+ if (!ctx) return { error: "No active session context." };
24895
+ if (!ctx.thinkState || ctx.thinkState.step !== "active") {
24896
+ return { error: "Think channel is not active." };
24897
+ }
24898
+ const asStringList = (value) => {
24899
+ if (!Array.isArray(value)) return void 0;
24900
+ return value.filter((v) => typeof v === "string").map((s) => s.trim()).filter(Boolean).slice(0, 12);
24901
+ };
24902
+ const open = asStringList(input.open_questions);
24903
+ const challenged = asStringList(input.challenged_assumptions);
24904
+ const hypotheses = asStringList(input.working_hypotheses);
24905
+ if (open) ctx.thinkState.open_questions = open;
24906
+ if (challenged) ctx.thinkState.challenged_assumptions = challenged;
24907
+ if (hypotheses) ctx.thinkState.working_hypotheses = hypotheses;
24908
+ saveSessionState2(ctx);
24909
+ return {
24910
+ updated: true,
24911
+ open_questions: ctx.thinkState.open_questions ?? [],
24912
+ challenged_assumptions: ctx.thinkState.challenged_assumptions ?? [],
24913
+ working_hypotheses: ctx.thinkState.working_hypotheses ?? []
24914
+ };
24915
+ }
24399
24916
  async function handleGetSessionBrief(input) {
24400
24917
  const raw = typeof input.session_id === "string" ? input.session_id.trim() : "";
24401
24918
  if (!raw) return { error: "session_id is required." };
@@ -24410,9 +24927,9 @@ async function handleGetSessionBrief(input) {
24410
24927
  if (!target) {
24411
24928
  return { error: `No session matching "${raw}".` };
24412
24929
  }
24413
- const { existsSync: existsSync26, readFileSync: readFileSync23 } = await import("fs");
24930
+ const { existsSync: existsSync27, readFileSync: readFileSync23 } = await import("fs");
24414
24931
  const briefPath = contextDocPathForSession2(target.id);
24415
- if (!existsSync26(briefPath)) {
24932
+ if (!existsSync27(briefPath)) {
24416
24933
  return {
24417
24934
  session_id: target.id,
24418
24935
  error: "No context brief on disk for this session (created before brief storage existed).",
@@ -24521,13 +25038,177 @@ var init_tool_handlers = __esm({
24521
25038
  audit_data_gaps: (_, __) => handleAuditDataGaps(),
24522
25039
  run_compute: (_, __) => handleRunCompute(),
24523
25040
  draft_handoff: (input, _) => handleDraftHandoff(input),
24524
- draft_strategy: (input, _) => handleDraftStrategy(input)
25041
+ draft_strategy: (input, _) => handleDraftStrategy(input),
25042
+ update_think_scratch: (input, _) => handleUpdateThinkScratch(input)
24525
25043
  };
24526
25044
  }
24527
25045
  });
24528
25046
 
24529
- // src/ai/agentic-loop.ts
25047
+ // src/ai/think-prompt.ts
24530
25048
  function companyContextSection3() {
25049
+ const block = buildCompanyProfileBlock();
25050
+ return block ? `COMPANY CONTEXT:
25051
+ ${block}
25052
+
25053
+ ` : "";
25054
+ }
25055
+ function operatorSection3() {
25056
+ const block = buildOperatorBlock();
25057
+ return block ? `${block}
25058
+
25059
+ ` : "";
25060
+ }
25061
+ function buildScratchBlock(state2) {
25062
+ if (!state2) return "";
25063
+ const lines = [];
25064
+ if (state2.seed) lines.push(`Seed topic: ${state2.seed}`);
25065
+ if (state2.open_questions?.length) {
25066
+ lines.push("Open questions:");
25067
+ for (const q of state2.open_questions) lines.push(`- ${q}`);
25068
+ }
25069
+ if (state2.challenged_assumptions?.length) {
25070
+ lines.push("Challenged assumptions:");
25071
+ for (const a of state2.challenged_assumptions) lines.push(`- ${a}`);
25072
+ }
25073
+ if (state2.working_hypotheses?.length) {
25074
+ lines.push("Working hypotheses:");
25075
+ for (const h of state2.working_hypotheses) lines.push(`- ${h}`);
25076
+ }
25077
+ if (lines.length === 0) return "";
25078
+ return `
25079
+ THINK SCRATCH (session working memory \u2014 update via update_think_scratch):
25080
+ ${lines.join("\n")}
25081
+ `;
25082
+ }
25083
+ function buildThinkWithMeSystemPrompt(opts = {}) {
25084
+ const sessionBlock = opts.sessionContext ? `
25085
+ PREVIOUS SESSION CONTEXT:
25086
+ The user resumed an earlier session. Here is what they were investigating before:
25087
+ ${opts.sessionContext}
25088
+ Treat this as already-established background. Pick up where it left off \u2014 do not re-introduce it as if it were new.
25089
+
25090
+ ` : "";
25091
+ const memorySection = opts.memoryBlock ? `
25092
+ WHAT YOU ALREADY KNOW ABOUT THIS BUSINESS (durable memory):
25093
+ ${opts.memoryBlock}
25094
+ Reference this naturally. Do not re-derive things you already know; build on them.
25095
+
25096
+ ` : "";
25097
+ const analysisSection = opts.analysisBlock ? `
25098
+ SESSION ANALYSIS CONTEXT:
25099
+ ${opts.analysisBlock}
25100
+ Use get_revenue_metrics and get_revenue_metrics_timeseries when the user asks about SaaS metrics, retention, or period trends.
25101
+
25102
+ ` : "";
25103
+ const artifactSection = opts.sessionArtifact ? `
25104
+ COMPLETED SESSION ANALYSIS:
25105
+ ${opts.sessionArtifact}
25106
+ Cite numbers from here; call tools when you need a new cut or to pressure-test a claim.
25107
+
25108
+ ` : "";
25109
+ const conversationSection = opts.conversationBlock ? `
25110
+ CONVERSATION STATE:
25111
+ ${opts.conversationBlock}
25112
+
25113
+ ` : "";
25114
+ const scratchSection = buildScratchBlock(opts.thinkState);
25115
+ const socraticCraft = `HOW YOU THINK WITH THE USER (socratic partner \u2014 not a search box, not a strategist):
25116
+ - You are a thinking partner. Prefer sharp questions that unlock the user's idea over dumping answers.
25117
+ - Protect imagination: give "what if" space before the smell-test \u2014 do not kill creativity in the first sentence.
25118
+ - Steelman the user's position before you attack it; then deliver one hard pushback grounded in evidence when possible.
25119
+ - Ground claims about THIS pipeline in tool results. Label speculation explicitly ("hypothesis:", "speculation:").
25120
+ - Each turn should ADVANCE the thread: a new question, a challenge, a synthesis, or a fork \u2014 never rehash.
25121
+ - If the question is ambiguous, ask at most ONE clarifying question. Otherwise choose a fork and state it.
25122
+ - Never invent a multi-week roadmap inline. When they want commitment, call draft_strategy with a crisp objective.
25123
+ - Keep open_questions, challenged_assumptions, and working_hypotheses current via update_think_scratch.
25124
+ - You have continuity via prior think-channel messages. Never repeat an angle already covered unless asked.`;
25125
+ const jobSection = `YOUR JOB (THINK CHANNEL \u2014 always deep):
25126
+ - Decide whether you need tools, a direct answer, or both. Do not re-call a tool whose result you already have.
25127
+ - Lead with the answer or the question that matters most, then structure.
25128
+ - When you use numbers, include dollar values where available and lead with financial impact.
25129
+ - Descriptive exploration stays in this channel; plan-of-attack questions hand off via draft_strategy.
25130
+ - After a successful draft_strategy tool result: reply with at most 1\u20132 sentences introducing the handoff. Do not write the plan.`;
25131
+ const formattingSection = `
25132
+ FORMATTING (your answer is rendered in a terminal via a small markdown renderer):
25133
+ - Use **bold** for every dollar figure, score, play name, and person name.
25134
+ - Use *italics* for conversational asides and your closing follow-up question.
25135
+ - Use ### for section headings \u2014 never # or ##. The renderer flattens depth.
25136
+ - For multi-point answers, prefer a one-line lead + bullet list over long paragraph blocks.
25137
+ - Keep paragraphs to 3-4 sentences.
25138
+ - Prefer short tables (\u22643 columns, \u22645 rows, cells \u226430 chars).
25139
+ - End with a dim horizontal rule (---) followed by one italicized follow-up question or fork.
25140
+
25141
+ ${USER_VISIBLE_STE_BLOCK}
25142
+ `;
25143
+ const commandSection = `PRESET COMMANDS (slash commands the user can type \u2014 you may SUGGEST these; you cannot run them):
25144
+ ${buildCommandCatalogBlock()}
25145
+
25146
+ COMMAND SUGGESTION RULES:
25147
+ - Suggest at most ONE command when it adds capability beyond your answer (e.g. \`/strategy\`, \`/handoff\`).
25148
+ - Never claim a command was run. Never invent flags.
25149
+ - Type \`done\` or \`cancel\` leaves the think channel back to ask \u203A.`;
25150
+ 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.
25151
+
25152
+ ${companyContextSection3()}${operatorSection3()}${socraticCraft}
25153
+
25154
+ ANALYST INSTINCT (judgment a CEO pays for \u2014 apply by default):
25155
+ ${ANALYST_INSTINCT_BLOCK}
25156
+
25157
+ ${jobSection}
25158
+
25159
+ EXECUTION BIAS (how you work):
25160
+ ${EXECUTION_BIAS_BLOCK}
25161
+
25162
+ GTM ENGINEERING (how recommendations become systems):
25163
+ ${GTM_ENGINEERING_BLOCK}
25164
+
25165
+ OUTPUT DOCTRINE (how answers are structured for recall):
25166
+ ${PYRAMID_OUTPUT_BLOCK}
25167
+
25168
+ ${USER_VISIBLE_STE_BLOCK}
25169
+
25170
+ CONTEXT:
25171
+ 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.
25172
+
25173
+ VITAL SIGNS EXPLAINED (with dollar translations):
25174
+ ${VITAL_SIGNS_BLOCK}
25175
+
25176
+ PLAYBOOK \u2014 name a play when it helps the user act (not a full program):
25177
+ ${buildPlaybookBlock()}
25178
+
25179
+ ${commandSection}
25180
+ ${formattingSection}
25181
+ OUTPUT RULES:
25182
+ - Respond in plain text markdown (not JSON). You do NOT need to emit the findings schema.
25183
+ - Include specific numbers from tool results, never guess.
25184
+ - When you have enough information, answer or ask \u2014 don't call tools you don't need.
25185
+
25186
+ SAFETY & EVIDENCE (non-negotiable):
25187
+ ${SAFETY_BLOCK}`;
25188
+ const dynamicSections = [
25189
+ sessionBlock,
25190
+ memorySection,
25191
+ analysisSection,
25192
+ artifactSection,
25193
+ conversationSection,
25194
+ scratchSection
25195
+ ].map((s) => s.trim()).filter(Boolean);
25196
+ const dynamic = [
25197
+ "SESSION STATE (current \u2014 changes as the session progresses):",
25198
+ ...dynamicSections,
25199
+ buildRuntimeBlock()
25200
+ ].join("\n\n");
25201
+ return { stable, dynamic };
25202
+ }
25203
+ var init_think_prompt = __esm({
25204
+ "src/ai/think-prompt.ts"() {
25205
+ "use strict";
25206
+ init_prompt_parts();
25207
+ }
25208
+ });
25209
+
25210
+ // src/ai/agentic-loop.ts
25211
+ function companyContextSection4() {
24531
25212
  const block = buildCompanyProfileBlock();
24532
25213
  if (!block) return "";
24533
25214
  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):
@@ -24535,7 +25216,7 @@ ${block}
24535
25216
 
24536
25217
  `;
24537
25218
  }
24538
- function operatorSection3() {
25219
+ function operatorSection4() {
24539
25220
  const block = buildOperatorBlock();
24540
25221
  if (!block) return "";
24541
25222
  return `${block}
@@ -24545,7 +25226,7 @@ function operatorSection3() {
24545
25226
  function buildSystemPrompt2() {
24546
25227
  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.
24547
25228
 
24548
- ${companyContextSection3()}${operatorSection3()}INVESTIGATION APPROACH:
25229
+ ${companyContextSection4()}${operatorSection4()}INVESTIGATION APPROACH:
24549
25230
  1. Start by examining the health summary to understand the overall picture
24550
25231
  2. Drill into the lowest-scoring vital signs using get_vital_sign_detail
24551
25232
  3. Check divergences to find segments that are significantly worse than average
@@ -24734,7 +25415,7 @@ ${buildPlaybookBlock()}
24734
25415
  ${commandSection}`;
24735
25416
  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.
24736
25417
 
24737
- ${companyContextSection3()}${operatorSection3()}${conversationRules}
25418
+ ${companyContextSection4()}${operatorSection4()}${conversationRules}
24738
25419
 
24739
25420
  ${analystSection}
24740
25421
 
@@ -24780,20 +25461,27 @@ async function* agenticFindings(computeResult, divergences, options) {
24780
25461
  assertReplAi(options.ctx);
24781
25462
  const mode = options.mode ?? "investigation";
24782
25463
  const experiment = options.experiment ?? "production";
24783
- const responseMode = experiment === "baseline" || experiment === "a" || experiment === "b" ? "deep" : options.responseMode ?? (options.sessionArtifact ? "brief" : "deep");
24784
- const useTools = mode === "investigation" || responseMode === "deep";
25464
+ const responseMode = mode === "think" ? "deep" : experiment === "baseline" || experiment === "a" || experiment === "b" ? "deep" : options.responseMode ?? (options.sessionArtifact ? "brief" : "deep");
25465
+ const useTools = mode === "investigation" || mode === "think" || responseMode === "deep";
24785
25466
  const maxTokens = mode === "fresh" && responseMode === "brief" ? BRIEF_MAX_TOKENS : DEEP_MAX_TOKENS;
24786
25467
  const surface = mode === "fresh" ? responseMode === "brief" ? "agentic_fresh_brief" : "agentic_investigation" : "agentic_investigation";
24787
25468
  const llmCfg = loadLlmConfig();
24788
25469
  const tier = tierForSurface(surface, llmCfg.tier);
24789
- const systemPrompt = mode === "fresh" ? buildFreshNlSystemPrompt(
25470
+ const systemPrompt = mode === "think" ? buildThinkWithMeSystemPrompt({
25471
+ sessionContext: options.sessionContext,
25472
+ memoryBlock: options.memoryBlock,
25473
+ analysisBlock: options.analysisBlock,
25474
+ conversationBlock: options.conversationBlock,
25475
+ sessionArtifact: options.sessionArtifact,
25476
+ thinkState: options.ctx.thinkState
25477
+ }) : mode === "fresh" ? buildFreshNlSystemPrompt(
24790
25478
  options.sessionContext,
24791
25479
  options.memoryBlock,
24792
25480
  options.analysisBlock,
24793
25481
  options.conversationBlock,
24794
25482
  { responseMode, sessionArtifact: options.sessionArtifact, experiment }
24795
25483
  ) : buildSystemPrompt2();
24796
- const tools2 = useTools ? mode === "fresh" ? buildFreshNlTools() : buildInvestigationTools() : [];
25484
+ const tools2 = useTools ? mode === "think" ? buildThinkTools() : mode === "fresh" ? buildFreshNlTools() : buildInvestigationTools() : [];
24797
25485
  const toolCtx = { computeResult, divergences };
24798
25486
  if (options.includeMetrics) {
24799
25487
  try {
@@ -24805,7 +25493,8 @@ async function* agenticFindings(computeResult, divergences, options) {
24805
25493
  const initialContext = buildInitialContext(computeResult, divergences, options.userQuestion);
24806
25494
  const priorRaw = options.priorMessages ?? [];
24807
25495
  const priorMessages = priorRaw.length > 0 && typeof priorRaw[0] === "object" && priorRaw[0] !== null && "content" in priorRaw[0] ? normalizeThread(priorRaw) : priorRaw;
24808
- const messages = mode === "fresh" && priorMessages.length > 0 && options.userQuestion ? [...priorMessages, { role: "user", content: options.userQuestion }] : [{ role: "user", content: initialContext }];
25496
+ const conversational = mode === "fresh" || mode === "think";
25497
+ const messages = conversational && priorMessages.length > 0 && options.userQuestion ? [...priorMessages, { role: "user", content: options.userQuestion }] : [{ role: "user", content: initialContext }];
24809
25498
  let lastMeta = { provider_used: "anthropic", model_used: "unknown" };
24810
25499
  const loopGuard = new ToolLoopGuard();
24811
25500
  const allowedTools = new Set(tools2.map((t) => t.name));
@@ -24835,7 +25524,7 @@ async function* agenticFindings(computeResult, divergences, options) {
24835
25524
  const response = await callLlm(messages, maxTokens, true);
24836
25525
  if (response.tool_calls.length === 0) {
24837
25526
  const fullText = response.text;
24838
- if (mode === "fresh") {
25527
+ if (conversational) {
24839
25528
  const findings3 = parseFindings(fullText);
24840
25529
  if (findings3.length > 0) {
24841
25530
  for (const finding of findings3) yield { type: "finding", finding };
@@ -24883,7 +25572,7 @@ async function* agenticFindings(computeResult, divergences, options) {
24883
25572
  });
24884
25573
  }
24885
25574
  }
24886
- if (mode === "fresh") {
25575
+ if (conversational) {
24887
25576
  messages.push({
24888
25577
  role: "user",
24889
25578
  content: "You've reached the tool budget. Please answer the user's question now with what you've learned."
@@ -24959,6 +25648,7 @@ var init_agentic_loop = __esm({
24959
25648
  init_thread();
24960
25649
  init_untrusted();
24961
25650
  init_prompt_parts();
25651
+ init_think_prompt();
24962
25652
  MAX_ITERATIONS = 10;
24963
25653
  INVESTIGATION_EVIDENCE_NUDGE_AFTER = 5;
24964
25654
  BRIEF_MAX_TOKENS = 768;
@@ -25207,7 +25897,7 @@ var init_ask = __esm({
25207
25897
  });
25208
25898
 
25209
25899
  // src/services/setup.ts
25210
- import { existsSync as existsSync24, mkdirSync as mkdirSync14, readFileSync as readFileSync21, writeFileSync as writeFileSync16 } from "fs";
25900
+ import { existsSync as existsSync25, mkdirSync as mkdirSync14, readFileSync as readFileSync21, writeFileSync as writeFileSync16 } from "fs";
25211
25901
  import { join as join25 } from "path";
25212
25902
  function setupCheck() {
25213
25903
  const home = ntrpHome();
@@ -25266,7 +25956,7 @@ var init_setup = __esm({
25266
25956
  });
25267
25957
 
25268
25958
  // src/version.ts
25269
- import { existsSync as existsSync25, readFileSync as readFileSync22 } from "fs";
25959
+ import { existsSync as existsSync26, readFileSync as readFileSync22 } from "fs";
25270
25960
  import { dirname as dirname5, join as join26 } from "path";
25271
25961
  import { fileURLToPath } from "url";
25272
25962
  function getInstalledVersion() {
@@ -25274,7 +25964,7 @@ function getInstalledVersion() {
25274
25964
  const start = dirname5(fileURLToPath(import.meta.url));
25275
25965
  for (const rel of ["../package.json", "../../package.json"]) {
25276
25966
  const path = join26(start, rel);
25277
- if (!existsSync25(path)) continue;
25967
+ if (!existsSync26(path)) continue;
25278
25968
  try {
25279
25969
  const pkg = JSON.parse(readFileSync22(path, "utf-8"));
25280
25970
  if (typeof pkg.version === "string" && pkg.version.length > 0) {