@sonnechasser/ntrp 1.3.9 → 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.
- package/dist/index.js +1107 -324
- package/dist/mcp/server.js +797 -131
- package/package.json +2 -1
package/dist/mcp/server.js
CHANGED
|
@@ -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",
|
|
@@ -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",
|
|
@@ -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) {
|
|
@@ -13573,6 +13693,8 @@ function formatPhaseLabel(phase) {
|
|
|
13573
13693
|
return "setup";
|
|
13574
13694
|
case "explore":
|
|
13575
13695
|
return "ready to ask";
|
|
13696
|
+
case "think":
|
|
13697
|
+
return "thinking together";
|
|
13576
13698
|
default:
|
|
13577
13699
|
return phase.replace(/_/g, " ");
|
|
13578
13700
|
}
|
|
@@ -13591,8 +13713,14 @@ function buildConversationPrompt(ctx) {
|
|
|
13591
13713
|
const modeTag = mode === "brief" ? "brief" : "deep";
|
|
13592
13714
|
const stack = canUseReplAi(ctx) ? formatActiveStackShort(ctx) : "no engine";
|
|
13593
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") : "";
|
|
13594
13717
|
const enterHint2 = action ? chalk8.dim(` \xB7 \u23CE ${action.hint}`) : "";
|
|
13595
|
-
return paint("accent", `ask${scope} \u203A `) + chalk8.dim(`${modeTag} \xB7 ${stack}`) + strategyWait + enterHint2 + " ";
|
|
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";
|
|
13722
|
+
const enterHint2 = action ? chalk8.dim(` \xB7 \u23CE ${action.hint}`) : "";
|
|
13723
|
+
return paint("accent", `think${scope} \u203A `) + chalk8.dim(stack) + enterHint2 + " ";
|
|
13596
13724
|
}
|
|
13597
13725
|
const enterHint = action ? chalk8.dim(`\u23CE ${action.hint} `) : "";
|
|
13598
13726
|
return paint("accent", `${label.replace(" \u203A", "")}${scope} \u203A `) + enterHint;
|
|
@@ -13633,6 +13761,7 @@ var init_phase = __esm({
|
|
|
13633
13761
|
awaiting_data: "data \u203A",
|
|
13634
13762
|
compute: "\u2026",
|
|
13635
13763
|
explore: "ask \u203A",
|
|
13764
|
+
think: "think \u203A",
|
|
13636
13765
|
strategize: "strategy \u203A",
|
|
13637
13766
|
deliver: "ship \u203A"
|
|
13638
13767
|
};
|
|
@@ -18304,45 +18433,372 @@ var init_strategist_flow = __esm({
|
|
|
18304
18433
|
}
|
|
18305
18434
|
});
|
|
18306
18435
|
|
|
18307
|
-
// src/
|
|
18436
|
+
// src/services/think.ts
|
|
18437
|
+
var think_exports = {};
|
|
18438
|
+
__export(think_exports, {
|
|
18439
|
+
runThinkTurn: () => runThinkTurn
|
|
18440
|
+
});
|
|
18308
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";
|
|
18309
18765
|
function printGapCard(audit, opts = {}) {
|
|
18310
18766
|
console.log();
|
|
18311
18767
|
if (opts.skipSatisfied) {
|
|
18312
18768
|
if (audit.missing.length > 0) {
|
|
18313
|
-
console.log(" " +
|
|
18769
|
+
console.log(" " + chalk20.bold("Data check"));
|
|
18314
18770
|
}
|
|
18315
18771
|
} else if (audit.satisfied.length > 0) {
|
|
18316
18772
|
const bits = audit.satisfied.map((item) => item.detail);
|
|
18317
18773
|
console.log(
|
|
18318
|
-
" " +
|
|
18774
|
+
" " + chalk20.green("\u2713") + " " + chalk20.bold("Data check") + chalk20.dim(" \u2014 " + bits.join(" \xB7 "))
|
|
18319
18775
|
);
|
|
18320
18776
|
} else {
|
|
18321
|
-
console.log(" " +
|
|
18777
|
+
console.log(" " + chalk20.bold("Data check"));
|
|
18322
18778
|
}
|
|
18323
18779
|
for (const item of audit.missing) {
|
|
18324
|
-
console.log(" " +
|
|
18325
|
-
console.log(" " +
|
|
18780
|
+
console.log(" " + chalk20.red("\u2717") + " " + item.label + chalk20.dim(` \u2014 ${item.why}`));
|
|
18781
|
+
console.log(" " + chalk20.dim(item.suggestion));
|
|
18326
18782
|
}
|
|
18327
18783
|
if (audit.optional.length > 0) {
|
|
18328
18784
|
const heads = audit.optional.map((item) => item.detail.split(" \u2014 ")[0] ?? item.detail);
|
|
18329
18785
|
const joined = heads.join(" \xB7 ");
|
|
18330
18786
|
if (joined.length <= 100) {
|
|
18331
|
-
console.log(" " +
|
|
18787
|
+
console.log(" " + chalk20.yellow("~") + " " + chalk20.dim(joined));
|
|
18332
18788
|
} else {
|
|
18333
18789
|
for (const item of audit.optional) {
|
|
18334
|
-
console.log(" " +
|
|
18790
|
+
console.log(" " + chalk20.yellow("~") + " " + chalk20.dim(`${item.label}: ${item.detail}`));
|
|
18335
18791
|
}
|
|
18336
18792
|
}
|
|
18337
18793
|
}
|
|
18338
18794
|
console.log();
|
|
18339
18795
|
if (audit.can_compute) {
|
|
18340
18796
|
console.log(
|
|
18341
|
-
" " +
|
|
18797
|
+
" " + chalk20.dim("Ready to compute. Press ") + chalk20.cyan("\u23CE") + chalk20.dim(" or type ") + chalk20.cyan('"go ahead"')
|
|
18342
18798
|
);
|
|
18343
18799
|
} else if (audit.missing.length > 0) {
|
|
18344
18800
|
console.log(
|
|
18345
|
-
" " +
|
|
18801
|
+
" " + chalk20.dim("Load data. Paste a CSV path, or press ") + chalk20.cyan("\u23CE") + chalk20.dim(" to ") + chalk20.cyan("use demo data")
|
|
18346
18802
|
);
|
|
18347
18803
|
}
|
|
18348
18804
|
console.log();
|
|
@@ -18359,7 +18815,7 @@ __export(keyless_ask_exports, {
|
|
|
18359
18815
|
isKeylessVitalsAsk: () => isKeylessVitalsAsk,
|
|
18360
18816
|
tryKeylessAskAnswer: () => tryKeylessAskAnswer
|
|
18361
18817
|
});
|
|
18362
|
-
import
|
|
18818
|
+
import chalk21 from "chalk";
|
|
18363
18819
|
function isKeylessVitalsAsk(input) {
|
|
18364
18820
|
return KEYLESS_ASK_RE.test(input.trim());
|
|
18365
18821
|
}
|
|
@@ -18408,35 +18864,35 @@ async function tryKeylessAskAnswer(ctx, input, opts = {}) {
|
|
|
18408
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.`;
|
|
18409
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);
|
|
18410
18866
|
console.log();
|
|
18411
|
-
console.log(" " +
|
|
18867
|
+
console.log(" " + chalk21.bold(headline));
|
|
18412
18868
|
if (opts.fromResume) {
|
|
18413
18869
|
if (runners.length > 0) {
|
|
18414
18870
|
console.log(
|
|
18415
|
-
" " +
|
|
18871
|
+
" " + chalk21.dim("Next after that: ") + chalk21.dim(runners.map(formatRunnerBit).join(" \xB7 "))
|
|
18416
18872
|
);
|
|
18417
18873
|
}
|
|
18418
18874
|
} else {
|
|
18419
18875
|
console.log();
|
|
18420
18876
|
if (gating && gating.vital_sign !== primary.vital_sign) {
|
|
18421
18877
|
console.log(
|
|
18422
|
-
" " +
|
|
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.`)
|
|
18423
18879
|
);
|
|
18424
18880
|
}
|
|
18425
18881
|
if (runners.length > 0) {
|
|
18426
|
-
console.log(" " +
|
|
18882
|
+
console.log(" " + chalk21.dim("Also on the board:"));
|
|
18427
18883
|
for (const vs of runners) {
|
|
18428
|
-
console.log(" " +
|
|
18884
|
+
console.log(" " + chalk21.dim("\xB7 ") + formatVitalLine(vs));
|
|
18429
18885
|
}
|
|
18430
18886
|
}
|
|
18431
18887
|
if (aggregate.total_value_at_risk != null && aggregate.total_value_at_risk > 0) {
|
|
18432
18888
|
console.log(
|
|
18433
|
-
" " +
|
|
18889
|
+
" " + chalk21.dim("Total at risk: ") + chalk21.green(formatCurrency(aggregate.total_value_at_risk))
|
|
18434
18890
|
);
|
|
18435
18891
|
}
|
|
18436
18892
|
}
|
|
18437
18893
|
console.log();
|
|
18438
18894
|
console.log(
|
|
18439
|
-
" " +
|
|
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.")
|
|
18440
18896
|
);
|
|
18441
18897
|
console.log();
|
|
18442
18898
|
if (!opts.fromResume) {
|
|
@@ -18459,7 +18915,7 @@ var init_keyless_ask = __esm({
|
|
|
18459
18915
|
});
|
|
18460
18916
|
|
|
18461
18917
|
// src/conversation/keyless-definitions.ts
|
|
18462
|
-
import
|
|
18918
|
+
import chalk22 from "chalk";
|
|
18463
18919
|
function isPossessiveMetricAsk(input) {
|
|
18464
18920
|
return POSSESSIVE_RE.test(input.trim());
|
|
18465
18921
|
}
|
|
@@ -18512,9 +18968,9 @@ function tryKeylessDefinitionAnswer(ctx, input) {
|
|
|
18512
18968
|
const bench = explainer.benchmarkHint?.(motion);
|
|
18513
18969
|
console.log();
|
|
18514
18970
|
console.log(
|
|
18515
|
-
" " + sectionHeading(explainer.label) +
|
|
18971
|
+
" " + sectionHeading(explainer.label) + chalk22.dim(` \xB7 ${explainer.kind === "vital" ? "vital sign" : "SaaS metric"}`)
|
|
18516
18972
|
);
|
|
18517
|
-
console.log(" " +
|
|
18973
|
+
console.log(" " + chalk22.dim(explainer.tagline));
|
|
18518
18974
|
console.log();
|
|
18519
18975
|
console.log(" " + bold("Meaning"));
|
|
18520
18976
|
printWrapped2(explainer.meaning, " ");
|
|
@@ -18526,16 +18982,16 @@ function tryKeylessDefinitionAnswer(ctx, input) {
|
|
|
18526
18982
|
}
|
|
18527
18983
|
if (bench) {
|
|
18528
18984
|
console.log();
|
|
18529
|
-
console.log(" " +
|
|
18985
|
+
console.log(" " + chalk22.dim(`Benchmark \xB7 ${bench}`));
|
|
18530
18986
|
}
|
|
18531
18987
|
if (explainer.dollar_label) {
|
|
18532
18988
|
console.log(
|
|
18533
|
-
" " +
|
|
18989
|
+
" " + chalk22.dim(`Dollar translation \xB7 ${explainer.dollar_label}`)
|
|
18534
18990
|
);
|
|
18535
18991
|
}
|
|
18536
18992
|
console.log();
|
|
18537
18993
|
console.log(
|
|
18538
|
-
" " +
|
|
18994
|
+
" " + chalk22.dim("More: ") + paint("accent", `/deepdive ${explainer.id}`) + chalk22.dim(" \xB7 full tour: ") + paint("accent", "/deepdive")
|
|
18539
18995
|
);
|
|
18540
18996
|
console.log();
|
|
18541
18997
|
recordMessage(ctx, "user", input);
|
|
@@ -18565,7 +19021,7 @@ var init_keyless_definitions = __esm({
|
|
|
18565
19021
|
});
|
|
18566
19022
|
|
|
18567
19023
|
// src/conversation/orchestrator.ts
|
|
18568
|
-
import
|
|
19024
|
+
import chalk23 from "chalk";
|
|
18569
19025
|
async function handleExploreWithoutKey(ctx, input) {
|
|
18570
19026
|
if (isDefinitionAsk(input) && tryKeylessDefinitionAnswer(ctx, input)) {
|
|
18571
19027
|
return;
|
|
@@ -18595,7 +19051,7 @@ async function handleExploreWithoutKey(ctx, input) {
|
|
|
18595
19051
|
);
|
|
18596
19052
|
if (ctx.pendingAsk) {
|
|
18597
19053
|
console.log(
|
|
18598
|
-
" " +
|
|
19054
|
+
" " + chalk23.dim("Your question is stored. NTRP will answer it after you connect.")
|
|
18599
19055
|
);
|
|
18600
19056
|
}
|
|
18601
19057
|
if (ctx.gapAudit) {
|
|
@@ -18610,12 +19066,12 @@ async function handleExploreWithoutKey(ctx, input) {
|
|
|
18610
19066
|
return;
|
|
18611
19067
|
}
|
|
18612
19068
|
console.log();
|
|
18613
|
-
console.log(" " +
|
|
18614
|
-
console.log(" " +
|
|
18615
|
-
console.log(" " + paint("accent", "/deepdive") +
|
|
18616
|
-
console.log(" " + paint("accent", "/playbook") +
|
|
18617
|
-
console.log(" " +
|
|
18618
|
-
console.log(" " + paint("accent", "/handoff") +
|
|
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"));
|
|
18619
19075
|
console.log();
|
|
18620
19076
|
recordMessage(
|
|
18621
19077
|
ctx,
|
|
@@ -19270,7 +19726,7 @@ var nl_exports = {};
|
|
|
19270
19726
|
__export(nl_exports, {
|
|
19271
19727
|
runNaturalLanguage: () => runNaturalLanguage
|
|
19272
19728
|
});
|
|
19273
|
-
import
|
|
19729
|
+
import chalk24 from "chalk";
|
|
19274
19730
|
async function runNaturalLanguage(input, ctx) {
|
|
19275
19731
|
if (isSmokeProtocolTrigger(input)) {
|
|
19276
19732
|
recordMessage(ctx, "user", input);
|
|
@@ -19282,10 +19738,10 @@ async function runNaturalLanguage(input, ctx) {
|
|
|
19282
19738
|
printAnswer(result.answer);
|
|
19283
19739
|
recordMessage(ctx, "agent", result.answer);
|
|
19284
19740
|
console.log();
|
|
19285
|
-
return
|
|
19741
|
+
return extractSummary2(result.answer);
|
|
19286
19742
|
} catch (err) {
|
|
19287
19743
|
spinner2.fail("Smoke protocol failed");
|
|
19288
|
-
console.error(" " +
|
|
19744
|
+
console.error(" " + chalk24.red(String(err.message ?? err)));
|
|
19289
19745
|
console.log();
|
|
19290
19746
|
return;
|
|
19291
19747
|
}
|
|
@@ -19315,8 +19771,8 @@ async function runNaturalLanguage(input, ctx) {
|
|
|
19315
19771
|
spinner2.succeed(metricsFirst ? "Session context ready" : "Health snapshot ready");
|
|
19316
19772
|
} catch (err) {
|
|
19317
19773
|
spinner2.fail("Could not compute health snapshot");
|
|
19318
|
-
console.error(" " +
|
|
19319
|
-
console.log(" " +
|
|
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."));
|
|
19320
19776
|
console.log();
|
|
19321
19777
|
return;
|
|
19322
19778
|
}
|
|
@@ -19354,7 +19810,7 @@ async function runNaturalLanguage(input, ctx) {
|
|
|
19354
19810
|
break;
|
|
19355
19811
|
case "thinking":
|
|
19356
19812
|
spinner.stop();
|
|
19357
|
-
console.log(" " +
|
|
19813
|
+
console.log(" " + chalk24.dim.italic(event.text));
|
|
19358
19814
|
spinner.start("Thinking\u2026");
|
|
19359
19815
|
break;
|
|
19360
19816
|
case "answer":
|
|
@@ -19364,7 +19820,7 @@ async function runNaturalLanguage(input, ctx) {
|
|
|
19364
19820
|
break;
|
|
19365
19821
|
case "finding":
|
|
19366
19822
|
spinner.stop();
|
|
19367
|
-
|
|
19823
|
+
printFindingInline2(event.finding);
|
|
19368
19824
|
break;
|
|
19369
19825
|
case "done":
|
|
19370
19826
|
spinner.stop();
|
|
@@ -19374,7 +19830,7 @@ async function runNaturalLanguage(input, ctx) {
|
|
|
19374
19830
|
}
|
|
19375
19831
|
} catch (err) {
|
|
19376
19832
|
spinner.fail("Error while investigating");
|
|
19377
|
-
console.error(" " +
|
|
19833
|
+
console.error(" " + chalk24.red(String(err.message ?? err)));
|
|
19378
19834
|
console.log();
|
|
19379
19835
|
return;
|
|
19380
19836
|
} finally {
|
|
@@ -19384,7 +19840,7 @@ async function runNaturalLanguage(input, ctx) {
|
|
|
19384
19840
|
ctx.conversation = distillThread(rawHistory);
|
|
19385
19841
|
}
|
|
19386
19842
|
if (!lastAnswer) {
|
|
19387
|
-
console.log(" " +
|
|
19843
|
+
console.log(" " + chalk24.dim("(no answer returned)"));
|
|
19388
19844
|
} else {
|
|
19389
19845
|
recordMessage(ctx, "agent", lastAnswer);
|
|
19390
19846
|
if (ctx.pendingAsk) {
|
|
@@ -19400,12 +19856,12 @@ async function runNaturalLanguage(input, ctx) {
|
|
|
19400
19856
|
console.log();
|
|
19401
19857
|
const { promptQueuedAiStrategist: promptQueuedAiStrategist2 } = await Promise.resolve().then(() => (init_strategist_flow(), strategist_flow_exports));
|
|
19402
19858
|
promptQueuedAiStrategist2(ctx);
|
|
19403
|
-
return lastAnswer ?
|
|
19859
|
+
return lastAnswer ? extractSummary2(lastAnswer) : void 0;
|
|
19404
19860
|
}
|
|
19405
19861
|
function printAnswer(text) {
|
|
19406
19862
|
printMarkdown(text, { indent: 2 });
|
|
19407
19863
|
}
|
|
19408
|
-
function
|
|
19864
|
+
function extractSummary2(text) {
|
|
19409
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();
|
|
19410
19866
|
const sentenceMatch = plain.match(/^(.+?[.!?])(?:\s|$)/);
|
|
19411
19867
|
const sentence = sentenceMatch ? sentenceMatch[1] : plain.split("\n")[0];
|
|
@@ -19413,16 +19869,16 @@ function extractSummary(text) {
|
|
|
19413
19869
|
const truncated = sentence.slice(0, 60).replace(/\s+\S*$/, "");
|
|
19414
19870
|
return truncated + "\u2026";
|
|
19415
19871
|
}
|
|
19416
|
-
function
|
|
19872
|
+
function printFindingInline2(finding) {
|
|
19417
19873
|
const sev = finding.severity;
|
|
19418
19874
|
console.log();
|
|
19419
|
-
console.log(" " + severityPaint(sev)(`[${sev}]`) + " " +
|
|
19875
|
+
console.log(" " + severityPaint(sev)(`[${sev}]`) + " " + chalk24.bold(finding.segment));
|
|
19420
19876
|
printMarkdown(finding.finding, { indent: 2 });
|
|
19421
19877
|
const play = finding.recommended_plays?.[0];
|
|
19422
|
-
if (play) console.log(" " +
|
|
19878
|
+
if (play) console.log(" " + chalk24.dim("\u2192 " + play.play_name + " \u2014 " + play.rationale));
|
|
19423
19879
|
if (finding.recommended_focus) {
|
|
19424
19880
|
console.log(
|
|
19425
|
-
" " +
|
|
19881
|
+
" " + chalk24.dim("How this works: ") + paint("accent", `/deepdive ${finding.recommended_focus}`)
|
|
19426
19882
|
);
|
|
19427
19883
|
}
|
|
19428
19884
|
}
|
|
@@ -19458,12 +19914,12 @@ __export(demo_exports, {
|
|
|
19458
19914
|
printDemoDisabled: () => printDemoDisabled,
|
|
19459
19915
|
setDemoEnabled: () => setDemoEnabled
|
|
19460
19916
|
});
|
|
19461
|
-
import
|
|
19917
|
+
import chalk25 from "chalk";
|
|
19462
19918
|
function printDemoDisabled() {
|
|
19463
19919
|
console.log();
|
|
19464
|
-
console.log(" " +
|
|
19920
|
+
console.log(" " + chalk25.red(DEMO_DISABLED_MESSAGE));
|
|
19465
19921
|
console.log(
|
|
19466
|
-
" " +
|
|
19922
|
+
" " + chalk25.dim("Re-enable with ") + paint("accent", "/config set demo-enabled true") + chalk25.dim(".")
|
|
19467
19923
|
);
|
|
19468
19924
|
console.log();
|
|
19469
19925
|
}
|
|
@@ -22765,16 +23221,16 @@ var generate_exports = {};
|
|
|
22765
23221
|
__export(generate_exports, {
|
|
22766
23222
|
handler: () => handler2
|
|
22767
23223
|
});
|
|
22768
|
-
import
|
|
23224
|
+
import chalk26 from "chalk";
|
|
22769
23225
|
async function handler2(args, ctx) {
|
|
22770
23226
|
const { flags } = parseArgs(args, ["list-scenarios", "regen-taxonomy", "brief"]);
|
|
22771
23227
|
const quiet = ctx.execution.quiet;
|
|
22772
23228
|
const brief = getBool(flags, "brief");
|
|
22773
23229
|
if (getBool(flags, "list-scenarios")) {
|
|
22774
|
-
console.log(
|
|
23230
|
+
console.log(chalk26.bold("\n Available Scenarios:\n"));
|
|
22775
23231
|
for (const s of SCENARIO_LIST) {
|
|
22776
|
-
console.log(` ${
|
|
22777
|
-
console.log(` ${
|
|
23232
|
+
console.log(` ${chalk26.cyan(s.key.padEnd(20))} ${s.label}`);
|
|
23233
|
+
console.log(` ${chalk26.dim(" ".repeat(20))} ${s.description}
|
|
22778
23234
|
`);
|
|
22779
23235
|
}
|
|
22780
23236
|
return true;
|
|
@@ -22784,9 +23240,9 @@ async function handler2(args, ctx) {
|
|
|
22784
23240
|
const skipProfile = getFalse(flags, "profile");
|
|
22785
23241
|
if (!isProfileConfigured(profile) && !skipProfile) {
|
|
22786
23242
|
console.error();
|
|
22787
|
-
console.error(" " +
|
|
22788
|
-
console.error(" " +
|
|
22789
|
-
console.error(" " +
|
|
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."));
|
|
22790
23246
|
console.error();
|
|
22791
23247
|
markFailure(ctx);
|
|
22792
23248
|
return false;
|
|
@@ -22794,8 +23250,8 @@ async function handler2(args, ctx) {
|
|
|
22794
23250
|
const explicitScenario = getString(flags, "scenario", "s");
|
|
22795
23251
|
const resolvedScenario = resolveScenarioInput(explicitScenario);
|
|
22796
23252
|
if (resolvedScenario === null) {
|
|
22797
|
-
console.error(
|
|
22798
|
-
console.log(
|
|
23253
|
+
console.error(chalk26.red(` Unknown scenario: ${explicitScenario}`));
|
|
23254
|
+
console.log(chalk26.dim(` Valid: ${SCENARIO_LIST.map((s) => s.key).join(", ")}`));
|
|
22799
23255
|
markFailure(ctx);
|
|
22800
23256
|
return false;
|
|
22801
23257
|
}
|
|
@@ -22809,10 +23265,10 @@ async function handler2(args, ctx) {
|
|
|
22809
23265
|
const s = getScenario(scenario);
|
|
22810
23266
|
console.log();
|
|
22811
23267
|
if (brief) {
|
|
22812
|
-
console.log(" " + paint("accent", "\u2713 Demo: ") + bold(s.label) +
|
|
23268
|
+
console.log(" " + paint("accent", "\u2713 Demo: ") + bold(s.label) + chalk26.dim(" \u2014 " + s.hook));
|
|
22813
23269
|
} else {
|
|
22814
23270
|
console.log(" " + paint("accent", "\u2713 Scenario: ") + bold(s.label));
|
|
22815
|
-
console.log(" " +
|
|
23271
|
+
console.log(" " + chalk26.dim(s.story));
|
|
22816
23272
|
console.log();
|
|
22817
23273
|
}
|
|
22818
23274
|
}
|
|
@@ -22842,18 +23298,18 @@ async function handler2(args, ctx) {
|
|
|
22842
23298
|
if (brief) {
|
|
22843
23299
|
spinner.succeed(`Demo loaded \u2014 ${briefCounts(result.counts)}`);
|
|
22844
23300
|
} else {
|
|
22845
|
-
spinner.succeed(`Generated demo data for "${
|
|
23301
|
+
spinner.succeed(`Generated demo data for "${chalk26.cyan(scenario)}" scenario`);
|
|
22846
23302
|
console.log();
|
|
22847
23303
|
printEntityCounts(result.counts);
|
|
22848
23304
|
}
|
|
22849
23305
|
}
|
|
22850
23306
|
if (!quiet && !brief && ctx.analysis.primary !== "revenue_metrics") {
|
|
22851
|
-
console.log(
|
|
23307
|
+
console.log(chalk26.dim("\n Run /diagnose to compute vital signs.\n"));
|
|
22852
23308
|
}
|
|
22853
23309
|
}
|
|
22854
23310
|
} catch (err) {
|
|
22855
23311
|
if (spinner) spinner.fail("Generation failed");
|
|
22856
|
-
console.error(
|
|
23312
|
+
console.error(chalk26.red(String(err)));
|
|
22857
23313
|
markFailure(ctx);
|
|
22858
23314
|
return false;
|
|
22859
23315
|
}
|
|
@@ -22891,7 +23347,7 @@ async function loadOrBuildTaxonomy(profile, forceRegen, ctx) {
|
|
|
22891
23347
|
return taxonomy;
|
|
22892
23348
|
} catch (err) {
|
|
22893
23349
|
spinner.fail("Couldn't build market taxonomy \u2014 using generic data pools");
|
|
22894
|
-
console.log(" " +
|
|
23350
|
+
console.log(" " + chalk26.dim(String(err.message ?? err)));
|
|
22895
23351
|
return void 0;
|
|
22896
23352
|
}
|
|
22897
23353
|
}
|
|
@@ -22986,7 +23442,7 @@ __export(inbox_setup_exports, {
|
|
|
22986
23442
|
reuseInboxFolderIfPresent: () => reuseInboxFolderIfPresent,
|
|
22987
23443
|
shouldOfferInboxSkillSetup: () => shouldOfferInboxSkillSetup
|
|
22988
23444
|
});
|
|
22989
|
-
import
|
|
23445
|
+
import chalk27 from "chalk";
|
|
22990
23446
|
import { existsSync as existsSync22 } from "fs";
|
|
22991
23447
|
function markDemoOffered() {
|
|
22992
23448
|
setConfigValue("ai-inbox-nudge-seen", "true");
|
|
@@ -23008,27 +23464,27 @@ function printSkipHint(beat) {
|
|
|
23008
23464
|
const skillCmd = paint("accent", "/inbox skill");
|
|
23009
23465
|
if (beat === "demo") {
|
|
23010
23466
|
console.log(
|
|
23011
|
-
" " +
|
|
23467
|
+
" " + chalk27.dim("Skipped. NTRP will ask once when you load your own data. Or type ") + setCmd + chalk27.dim(" then ") + skillCmd
|
|
23012
23468
|
);
|
|
23013
23469
|
return;
|
|
23014
23470
|
}
|
|
23015
23471
|
console.log(
|
|
23016
|
-
" " +
|
|
23472
|
+
" " + chalk27.dim("Skipped. NTRP will not ask again. Type ") + setCmd + chalk27.dim(" then ") + skillCmd + chalk27.dim(" at any time.")
|
|
23017
23473
|
);
|
|
23018
23474
|
}
|
|
23019
23475
|
async function reuseInboxFolderIfPresent(session, beat, folderPath = defaultAiInboxDir()) {
|
|
23020
23476
|
if (getAiInboxDir()) return false;
|
|
23021
23477
|
if (!existsSync22(folderPath)) return false;
|
|
23022
|
-
console.log(" " +
|
|
23478
|
+
console.log(" " + chalk27.dim("Pickup folder still on disk: ") + folderPath);
|
|
23023
23479
|
const reuse = await session.confirm("Reuse this pickup folder?", true);
|
|
23024
23480
|
if (!reuse) return false;
|
|
23025
23481
|
const resolved = setAiInboxDir(folderPath);
|
|
23026
23482
|
markDemoOffered();
|
|
23027
23483
|
if (beat === "production") markProductionOffered();
|
|
23028
23484
|
console.log();
|
|
23029
|
-
console.log(" " + paint("accent", "Inbox ready") +
|
|
23485
|
+
console.log(" " + paint("accent", "Inbox ready") + chalk27.dim(" ") + resolved);
|
|
23030
23486
|
console.log(
|
|
23031
|
-
" " +
|
|
23487
|
+
" " + chalk27.dim("Folder reused. Type ") + paint("accent", "/inbox skill") + chalk27.dim(" to print the finder again.")
|
|
23032
23488
|
);
|
|
23033
23489
|
console.log();
|
|
23034
23490
|
return true;
|
|
@@ -23039,12 +23495,12 @@ async function offerInboxSkillSetup(session, opts = {}) {
|
|
|
23039
23495
|
console.log();
|
|
23040
23496
|
console.log(" " + bold("Teach Claude where handoffs live"));
|
|
23041
23497
|
console.log(
|
|
23042
|
-
" " +
|
|
23498
|
+
" " + chalk27.dim(
|
|
23043
23499
|
"Optional. NTRP copies every handoff into one folder. You paste instructions once; later /handoff just writes the file."
|
|
23044
23500
|
)
|
|
23045
23501
|
);
|
|
23046
23502
|
if (beat === "production" && getConfigValue("ai-inbox-nudge-seen") === "true") {
|
|
23047
|
-
console.log(" " +
|
|
23503
|
+
console.log(" " + chalk27.dim("You skipped this during demo."));
|
|
23048
23504
|
}
|
|
23049
23505
|
console.log();
|
|
23050
23506
|
if (await reuseInboxFolderIfPresent(session, beat)) return;
|
|
@@ -23075,16 +23531,16 @@ async function offerInboxSkillSetup(session, opts = {}) {
|
|
|
23075
23531
|
markDemoOffered();
|
|
23076
23532
|
if (beat === "production") markProductionOffered();
|
|
23077
23533
|
console.log();
|
|
23078
|
-
console.log(" " + paint("accent", "Inbox ready") +
|
|
23534
|
+
console.log(" " + paint("accent", "Inbox ready") + chalk27.dim(" ") + resolved);
|
|
23079
23535
|
if (n > 0) {
|
|
23080
|
-
console.log(" " +
|
|
23536
|
+
console.log(" " + chalk27.dim(`Synced ${n} recent export${n === 1 ? "" : "s"}.`));
|
|
23081
23537
|
}
|
|
23082
23538
|
console.log(
|
|
23083
|
-
" " +
|
|
23539
|
+
" " + chalk27.dim("Paste this skill into Claude once. Later, tell Claude to open the latest NTRP handoff.")
|
|
23084
23540
|
);
|
|
23085
23541
|
printStandingSkill();
|
|
23086
23542
|
await session.askPressEnter("Paste the skill into Claude. Then continue");
|
|
23087
|
-
console.log(" " +
|
|
23543
|
+
console.log(" " + chalk27.dim("Done. Later handoffs write to that folder. The skill is not printed again."));
|
|
23088
23544
|
console.log();
|
|
23089
23545
|
}
|
|
23090
23546
|
async function maybeOfferInboxOnProduction(ctx) {
|
|
@@ -23117,7 +23573,7 @@ var ingest_exports = {};
|
|
|
23117
23573
|
__export(ingest_exports, {
|
|
23118
23574
|
handler: () => handler3
|
|
23119
23575
|
});
|
|
23120
|
-
import
|
|
23576
|
+
import chalk28 from "chalk";
|
|
23121
23577
|
import { readFileSync as readFileSync20, existsSync as existsSync23 } from "fs";
|
|
23122
23578
|
import { basename as basename6 } from "path";
|
|
23123
23579
|
async function handler3(args, ctx) {
|
|
@@ -23138,21 +23594,21 @@ async function handler3(args, ctx) {
|
|
|
23138
23594
|
const source = getString(flags, "source", "s") ?? "salesforce";
|
|
23139
23595
|
const skipResolve = getBool(flags, "skip-resolve");
|
|
23140
23596
|
if (!file) {
|
|
23141
|
-
console.error(
|
|
23142
|
-
console.error(
|
|
23597
|
+
console.error(chalk28.red(" Usage: /ingest <file> [--source salesforce|hubspot|outreach]"));
|
|
23598
|
+
console.error(chalk28.dim(" /ingest --demo [--scenario <name>]"));
|
|
23143
23599
|
process.exit(1);
|
|
23144
23600
|
}
|
|
23145
23601
|
if (!existsSync23(file)) {
|
|
23146
|
-
console.error(
|
|
23602
|
+
console.error(chalk28.red(` File not found: ${file}`));
|
|
23147
23603
|
process.exit(1);
|
|
23148
23604
|
}
|
|
23149
23605
|
const profile = loadProfile();
|
|
23150
23606
|
const skipProfile = getFalse(flags, "profile");
|
|
23151
23607
|
if (!profile && !skipProfile) {
|
|
23152
23608
|
console.error();
|
|
23153
|
-
console.error(" " +
|
|
23154
|
-
console.error(" " +
|
|
23155
|
-
console.error(" " +
|
|
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."));
|
|
23156
23612
|
console.error();
|
|
23157
23613
|
process.exit(1);
|
|
23158
23614
|
}
|
|
@@ -23184,15 +23640,15 @@ async function handler3(args, ctx) {
|
|
|
23184
23640
|
row_count: result2.imported
|
|
23185
23641
|
});
|
|
23186
23642
|
spinner.succeed(
|
|
23187
|
-
`Imported ${
|
|
23643
|
+
`Imported ${chalk28.bold(result2.imported.toString())} revenue events from ${chalk28.dim(basename6(file))}`
|
|
23188
23644
|
);
|
|
23189
23645
|
if (result2.errors.length > 0) {
|
|
23190
|
-
console.log(
|
|
23646
|
+
console.log(chalk28.yellow(` ${result2.errors.length} rows skipped`));
|
|
23191
23647
|
}
|
|
23192
23648
|
if (ctx.analysis) {
|
|
23193
23649
|
ctx.analysis.data_source_type = "revenue_ledger";
|
|
23194
23650
|
}
|
|
23195
|
-
console.log(
|
|
23651
|
+
console.log(chalk28.dim(" Run ") + chalk28.cyan("/metrics") + chalk28.dim(" for SaaS metrics with ledger-backed retention."));
|
|
23196
23652
|
const { maybeOfferInboxOnProduction: maybeOfferInboxOnProduction3 } = await Promise.resolve().then(() => (init_inbox_setup(), inbox_setup_exports));
|
|
23197
23653
|
await maybeOfferInboxOnProduction3(ctx);
|
|
23198
23654
|
return `${result2.imported} revenue events from ${basename6(file)}`;
|
|
@@ -23201,7 +23657,7 @@ async function handler3(args, ctx) {
|
|
|
23201
23657
|
const detection = detectEntityType(headers, source);
|
|
23202
23658
|
if (!detection) {
|
|
23203
23659
|
spinner.fail(`Could not auto-detect entity type for source: ${source}`);
|
|
23204
|
-
console.log(
|
|
23660
|
+
console.log(chalk28.dim(" Headers found: " + headers.join(", ")));
|
|
23205
23661
|
process.exit(1);
|
|
23206
23662
|
}
|
|
23207
23663
|
spinner.text = `Importing ${rows.length} ${detection.entityType} rows...`;
|
|
@@ -23224,15 +23680,15 @@ async function handler3(args, ctx) {
|
|
|
23224
23680
|
row_count: result.imported
|
|
23225
23681
|
});
|
|
23226
23682
|
spinner.succeed(
|
|
23227
|
-
`Imported ${
|
|
23683
|
+
`Imported ${chalk28.bold(result.imported.toString())} ${detection.entityType} from ${chalk28.dim(basename6(file))} (${source})`
|
|
23228
23684
|
);
|
|
23229
23685
|
if (result.errors.length > 0) {
|
|
23230
|
-
console.log(
|
|
23686
|
+
console.log(chalk28.yellow(` ${result.errors.length} rows skipped`));
|
|
23231
23687
|
for (const err of result.errors.slice(0, 3)) {
|
|
23232
|
-
console.log(
|
|
23688
|
+
console.log(chalk28.dim(` - ${err}`));
|
|
23233
23689
|
}
|
|
23234
23690
|
if (result.errors.length > 3) {
|
|
23235
|
-
console.log(
|
|
23691
|
+
console.log(chalk28.dim(` ... and ${result.errors.length - 3} more`));
|
|
23236
23692
|
}
|
|
23237
23693
|
}
|
|
23238
23694
|
if (!skipResolve) {
|
|
@@ -23251,7 +23707,7 @@ async function handler3(args, ctx) {
|
|
|
23251
23707
|
return `${result.imported} ${detection.entityType} from ${basename6(file)}`;
|
|
23252
23708
|
} catch (err) {
|
|
23253
23709
|
spinner.fail("Import failed");
|
|
23254
|
-
console.error(
|
|
23710
|
+
console.error(chalk28.red(String(err)));
|
|
23255
23711
|
process.exit(1);
|
|
23256
23712
|
}
|
|
23257
23713
|
}
|
|
@@ -23363,13 +23819,13 @@ __export(demo_fit_exports, {
|
|
|
23363
23819
|
resolveDemoScenarioForLoad: () => resolveDemoScenarioForLoad,
|
|
23364
23820
|
runDemoFitQuiz: () => runDemoFitQuiz
|
|
23365
23821
|
});
|
|
23366
|
-
import
|
|
23822
|
+
import chalk29 from "chalk";
|
|
23367
23823
|
async function runDemoFitQuiz(session, opts = {}) {
|
|
23368
23824
|
if (opts.intro !== false) {
|
|
23369
23825
|
console.log();
|
|
23370
23826
|
console.log(" " + bold("Fit a sample book of business"));
|
|
23371
23827
|
console.log(
|
|
23372
|
-
" " +
|
|
23828
|
+
" " + chalk29.dim(
|
|
23373
23829
|
"No API key needed. Two questions about how you sell, then you pick which of seven sample pipelines feels closest."
|
|
23374
23830
|
)
|
|
23375
23831
|
);
|
|
@@ -23387,8 +23843,8 @@ async function runDemoFitQuiz(session, opts = {}) {
|
|
|
23387
23843
|
);
|
|
23388
23844
|
const recommended = inferDemoScenario({ salesMotion: motion, dealBand });
|
|
23389
23845
|
console.log();
|
|
23390
|
-
console.log(" " +
|
|
23391
|
-
console.log(" " +
|
|
23846
|
+
console.log(" " + chalk29.dim("Recommended: ") + paint("accent", getScenario(recommended.scenario).label));
|
|
23847
|
+
console.log(" " + chalk29.dim(recommended.reason));
|
|
23392
23848
|
const scenario = await session.choose(
|
|
23393
23849
|
"Which of these sample books feels closest to the one you manage?",
|
|
23394
23850
|
scenarioMenuChoices(),
|
|
@@ -23408,8 +23864,8 @@ async function offerFittedDemoAfterOnboard(session, ctx, profile) {
|
|
|
23408
23864
|
const s = getScenario(fit.scenario);
|
|
23409
23865
|
console.log();
|
|
23410
23866
|
console.log(" " + bold("A sample pipeline that looks like you"));
|
|
23411
|
-
console.log(" " + paint("accent", s.label) +
|
|
23412
|
-
console.log(" " +
|
|
23867
|
+
console.log(" " + paint("accent", s.label) + chalk29.dim(" \u2014 " + s.hook));
|
|
23868
|
+
console.log(" " + chalk29.dim(fit.reason));
|
|
23413
23869
|
console.log();
|
|
23414
23870
|
const action = await session.choose(
|
|
23415
23871
|
"Try NTRP on that book of business?",
|
|
@@ -23466,8 +23922,8 @@ async function resolveDemoScenarioForLoad(ctx, opts = {}) {
|
|
|
23466
23922
|
if (!opts.forceQuiz && isProfileConfigured(profile) && profile) {
|
|
23467
23923
|
const fit = await resolveProfileFit(profile, ctx);
|
|
23468
23924
|
console.log();
|
|
23469
|
-
console.log(" " +
|
|
23470
|
-
console.log(" " +
|
|
23925
|
+
console.log(" " + chalk29.dim("Recommended: ") + paint("accent", getScenario(fit.scenario).label));
|
|
23926
|
+
console.log(" " + chalk29.dim(fit.reason));
|
|
23471
23927
|
const scenario = await session.choose(
|
|
23472
23928
|
"Which sample book of business?",
|
|
23473
23929
|
scenarioMenuChoices(),
|
|
@@ -23531,7 +23987,7 @@ __export(ingest_chat_exports, {
|
|
|
23531
23987
|
import { existsSync as existsSync24 } from "fs";
|
|
23532
23988
|
import { basename as basename7, resolve as resolve9 } from "path";
|
|
23533
23989
|
import { homedir as homedir8 } from "os";
|
|
23534
|
-
import
|
|
23990
|
+
import chalk30 from "chalk";
|
|
23535
23991
|
function extractFilePath(input) {
|
|
23536
23992
|
const trimmed = input.trim();
|
|
23537
23993
|
const patterns = [
|
|
@@ -23566,7 +24022,7 @@ function looksLikeFilePath(input) {
|
|
|
23566
24022
|
}
|
|
23567
24023
|
async function ingestFromChat(ctx, filePath) {
|
|
23568
24024
|
if (!ctx.rl) {
|
|
23569
|
-
console.log(" " +
|
|
24025
|
+
console.log(" " + chalk30.red("Ingest confirm requires interactive mode."));
|
|
23570
24026
|
return false;
|
|
23571
24027
|
}
|
|
23572
24028
|
const name = basename7(filePath);
|
|
@@ -23574,7 +24030,7 @@ async function ingestFromChat(ctx, filePath) {
|
|
|
23574
24030
|
try {
|
|
23575
24031
|
const ok = await prompts.confirm(`Ingest ${name} as CRM export?`, true);
|
|
23576
24032
|
if (!ok) {
|
|
23577
|
-
console.log(" " +
|
|
24033
|
+
console.log(" " + chalk30.dim("Ingest cancelled."));
|
|
23578
24034
|
return false;
|
|
23579
24035
|
}
|
|
23580
24036
|
} finally {
|
|
@@ -23602,7 +24058,7 @@ async function ingestFromChat(ctx, filePath) {
|
|
|
23602
24058
|
true
|
|
23603
24059
|
);
|
|
23604
24060
|
if (useAi) {
|
|
23605
|
-
console.log(" " +
|
|
24061
|
+
console.log(" " + chalk30.dim("AI column mapping is not wired to ingest yet \u2014 trying standard ingest."));
|
|
23606
24062
|
}
|
|
23607
24063
|
} finally {
|
|
23608
24064
|
prompts2.close();
|
|
@@ -23629,7 +24085,7 @@ async function ingestFromChat(ctx, filePath) {
|
|
|
23629
24085
|
invalidateGapAudit(ctx);
|
|
23630
24086
|
saveSessionState(ctx);
|
|
23631
24087
|
console.log();
|
|
23632
|
-
console.log(" " + paint("accent", "\u2713 Data loaded") +
|
|
24088
|
+
console.log(" " + paint("accent", "\u2713 Data loaded") + chalk30.dim(` \u2014 ${name}`));
|
|
23633
24089
|
recordMessage(ctx, "user", `[ingested ${name}]`);
|
|
23634
24090
|
recordMessage(ctx, "agent", `Loaded ${name}. Checking what we can analyze\u2026`);
|
|
23635
24091
|
const audit = await refreshGapAudit(ctx);
|
|
@@ -23637,7 +24093,7 @@ async function ingestFromChat(ctx, filePath) {
|
|
|
23637
24093
|
if (audit.can_compute && ctx.scope?.confirmed_at) {
|
|
23638
24094
|
if (ctx.pendingAsk) {
|
|
23639
24095
|
console.log();
|
|
23640
|
-
console.log(" " +
|
|
24096
|
+
console.log(" " + chalk30.dim("Computing so I can answer\u2026"));
|
|
23641
24097
|
await runConversationCompute(ctx);
|
|
23642
24098
|
return true;
|
|
23643
24099
|
}
|
|
@@ -23685,7 +24141,7 @@ async function loadDemoFromChat(ctx, scenario, opts = {}) {
|
|
|
23685
24141
|
const { getScenario: getScenario2 } = await Promise.resolve().then(() => (init_scenarios(), scenarios_exports));
|
|
23686
24142
|
const s = getScenario2(chosen);
|
|
23687
24143
|
console.log();
|
|
23688
|
-
console.log(" " + paint("accent", "Fitting ") + s.label +
|
|
24144
|
+
console.log(" " + paint("accent", "Fitting ") + s.label + chalk30.dim(" \u2014 " + s.hook));
|
|
23689
24145
|
}
|
|
23690
24146
|
const { handler: demo } = await Promise.resolve().then(() => (init_generate(), generate_exports));
|
|
23691
24147
|
const args = ["--no-profile", "--brief"];
|
|
@@ -23721,7 +24177,7 @@ async function loadDemoFromChat(ctx, scenario, opts = {}) {
|
|
|
23721
24177
|
const shouldAuto = opts.autoCompute || Boolean(ctx.pendingAsk && audit.can_compute && ctx.scope?.confirmed_at);
|
|
23722
24178
|
if (shouldAuto && audit.can_compute) {
|
|
23723
24179
|
console.log();
|
|
23724
|
-
console.log(" " +
|
|
24180
|
+
console.log(" " + chalk30.dim("Computing so I can answer\u2026"));
|
|
23725
24181
|
await runConversationCompute(ctx);
|
|
23726
24182
|
return true;
|
|
23727
24183
|
}
|
|
@@ -23754,7 +24210,7 @@ __export(pending_ask_exports, {
|
|
|
23754
24210
|
queuePendingAsk: () => queuePendingAsk,
|
|
23755
24211
|
resumePendingAsk: () => resumePendingAsk
|
|
23756
24212
|
});
|
|
23757
|
-
import
|
|
24213
|
+
import chalk31 from "chalk";
|
|
23758
24214
|
function looksLikeQuestion(input) {
|
|
23759
24215
|
const text = input.trim();
|
|
23760
24216
|
if (!text) return false;
|
|
@@ -23790,7 +24246,7 @@ function printFocusChip(ctx) {
|
|
|
23790
24246
|
const period = ctx.scope.time_horizon ? ` \xB7 ${ctx.scope.time_horizon}` : "";
|
|
23791
24247
|
console.log();
|
|
23792
24248
|
console.log(
|
|
23793
|
-
" " +
|
|
24249
|
+
" " + chalk31.dim("Focus: ") + paint("accent", lens) + chalk31.dim(period) + chalk31.dim(" \u2014 type ") + chalk31.cyan("adjust") + chalk31.dim(" to change")
|
|
23794
24250
|
);
|
|
23795
24251
|
console.log();
|
|
23796
24252
|
}
|
|
@@ -23801,7 +24257,7 @@ async function resumePendingAsk(ctx) {
|
|
|
23801
24257
|
if (canUseReplAi(ctx)) {
|
|
23802
24258
|
console.log();
|
|
23803
24259
|
console.log(
|
|
23804
|
-
" " +
|
|
24260
|
+
" " + chalk31.dim(
|
|
23805
24261
|
pending.keylessAnswered ? "Picking up your question with the connected engine\u2026" : "Picking up your question\u2026"
|
|
23806
24262
|
)
|
|
23807
24263
|
);
|
|
@@ -23834,7 +24290,7 @@ async function offerDemoToAnswer(ctx) {
|
|
|
23834
24290
|
const go = await prompts.confirm("Use demo data to answer this?", true);
|
|
23835
24291
|
if (!go) {
|
|
23836
24292
|
console.log(
|
|
23837
|
-
" " +
|
|
24293
|
+
" " + chalk31.dim("Paste a CSV path when ready, or say ") + chalk31.cyan("use demo data") + chalk31.dim(".")
|
|
23838
24294
|
);
|
|
23839
24295
|
console.log();
|
|
23840
24296
|
return false;
|
|
@@ -23866,11 +24322,11 @@ __export(compute_exports2, {
|
|
|
23866
24322
|
isComputeIntent: () => isComputeIntent,
|
|
23867
24323
|
runConversationCompute: () => runConversationCompute
|
|
23868
24324
|
});
|
|
23869
|
-
import
|
|
24325
|
+
import chalk32 from "chalk";
|
|
23870
24326
|
async function runConversationCompute(ctx) {
|
|
23871
24327
|
const lens = ctx.scope?.primary_lens ?? ctx.analysis.primary;
|
|
23872
24328
|
ctx.computeInProgress = true;
|
|
23873
|
-
const willAnswer = Boolean(ctx.pendingAsk?.text) && !ctx.strategistState;
|
|
24329
|
+
const willAnswer = Boolean(ctx.pendingAsk?.text) && !ctx.strategistState && ctx.thinkState?.step !== "awaiting_analysis";
|
|
23874
24330
|
try {
|
|
23875
24331
|
if (lens === "revenue_metrics") {
|
|
23876
24332
|
const { runMetricsAnalysis: runMetricsAnalysis2, extractHeadlineMetrics: extractHeadlineMetrics2 } = await Promise.resolve().then(() => (init_metrics_analysis(), metrics_analysis_exports));
|
|
@@ -23898,6 +24354,7 @@ async function runConversationCompute(ctx) {
|
|
|
23898
24354
|
interactive: !willAnswer
|
|
23899
24355
|
});
|
|
23900
24356
|
await resumeQueuedStrategist(ctx);
|
|
24357
|
+
await resumeQueuedThink(ctx);
|
|
23901
24358
|
await closeComputeTurn(ctx, willAnswer, "revenue_metrics");
|
|
23902
24359
|
creditGapCompute(ctx);
|
|
23903
24360
|
creditMetricsComplete(ctx, false);
|
|
@@ -23917,11 +24374,12 @@ async function runConversationCompute(ctx) {
|
|
|
23917
24374
|
invalidateGapAudit(ctx);
|
|
23918
24375
|
saveSessionState(ctx);
|
|
23919
24376
|
await resumeQueuedStrategist(ctx);
|
|
24377
|
+
await resumeQueuedThink(ctx);
|
|
23920
24378
|
await closeComputeTurn(ctx, willAnswer, "gtm_health");
|
|
23921
24379
|
creditGapCompute(ctx);
|
|
23922
24380
|
return typeof summary === "string" ? summary : "Health analysis ready";
|
|
23923
24381
|
} catch (err) {
|
|
23924
|
-
console.error(" " +
|
|
24382
|
+
console.error(" " + chalk32.red(String(err.message ?? err)));
|
|
23925
24383
|
return;
|
|
23926
24384
|
} finally {
|
|
23927
24385
|
ctx.computeInProgress = false;
|
|
@@ -23934,9 +24392,16 @@ async function resumeQueuedStrategist(ctx) {
|
|
|
23934
24392
|
const { resumeStrategistAfterCompute: resumeStrategistAfterCompute2 } = await Promise.resolve().then(() => (init_strategist_flow(), strategist_flow_exports));
|
|
23935
24393
|
await resumeStrategistAfterCompute2(ctx);
|
|
23936
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
|
+
}
|
|
23937
24401
|
async function resumePendingAskAfterCompute(ctx) {
|
|
23938
24402
|
if (!ctx.pendingAsk?.text) return false;
|
|
23939
24403
|
if (ctx.strategistState) return false;
|
|
24404
|
+
if (ctx.thinkState?.step === "active" || ctx.thinkState?.step === "awaiting_analysis") return false;
|
|
23940
24405
|
const { resumePendingAsk: resumePendingAsk2 } = await Promise.resolve().then(() => (init_pending_ask(), pending_ask_exports));
|
|
23941
24406
|
return resumePendingAsk2(ctx);
|
|
23942
24407
|
}
|
|
@@ -24405,6 +24870,7 @@ async function handleDraftStrategy(input) {
|
|
|
24405
24870
|
if (!objective) return { error: "objective is required." };
|
|
24406
24871
|
if (!isAnalysisReady2(ctx)) {
|
|
24407
24872
|
ctx.strategistState = { step: "awaiting_analysis", objective, origin: "ai" };
|
|
24873
|
+
if (ctx.thinkState) ctx.thinkState = void 0;
|
|
24408
24874
|
saveSessionState2(ctx);
|
|
24409
24875
|
return {
|
|
24410
24876
|
queued: true,
|
|
@@ -24413,6 +24879,7 @@ async function handleDraftStrategy(input) {
|
|
|
24413
24879
|
};
|
|
24414
24880
|
}
|
|
24415
24881
|
ctx.strategistState = { step: "objective_confirm", objective, origin: "ai" };
|
|
24882
|
+
if (ctx.thinkState) ctx.thinkState = void 0;
|
|
24416
24883
|
saveSessionState2(ctx);
|
|
24417
24884
|
return {
|
|
24418
24885
|
launched: true,
|
|
@@ -24420,6 +24887,32 @@ async function handleDraftStrategy(input) {
|
|
|
24420
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."
|
|
24421
24888
|
};
|
|
24422
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
|
+
}
|
|
24423
24916
|
async function handleGetSessionBrief(input) {
|
|
24424
24917
|
const raw = typeof input.session_id === "string" ? input.session_id.trim() : "";
|
|
24425
24918
|
if (!raw) return { error: "session_id is required." };
|
|
@@ -24545,13 +25038,177 @@ var init_tool_handlers = __esm({
|
|
|
24545
25038
|
audit_data_gaps: (_, __) => handleAuditDataGaps(),
|
|
24546
25039
|
run_compute: (_, __) => handleRunCompute(),
|
|
24547
25040
|
draft_handoff: (input, _) => handleDraftHandoff(input),
|
|
24548
|
-
draft_strategy: (input, _) => handleDraftStrategy(input)
|
|
25041
|
+
draft_strategy: (input, _) => handleDraftStrategy(input),
|
|
25042
|
+
update_think_scratch: (input, _) => handleUpdateThinkScratch(input)
|
|
24549
25043
|
};
|
|
24550
25044
|
}
|
|
24551
25045
|
});
|
|
24552
25046
|
|
|
24553
|
-
// src/ai/
|
|
25047
|
+
// src/ai/think-prompt.ts
|
|
24554
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() {
|
|
24555
25212
|
const block = buildCompanyProfileBlock();
|
|
24556
25213
|
if (!block) return "";
|
|
24557
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):
|
|
@@ -24559,7 +25216,7 @@ ${block}
|
|
|
24559
25216
|
|
|
24560
25217
|
`;
|
|
24561
25218
|
}
|
|
24562
|
-
function
|
|
25219
|
+
function operatorSection4() {
|
|
24563
25220
|
const block = buildOperatorBlock();
|
|
24564
25221
|
if (!block) return "";
|
|
24565
25222
|
return `${block}
|
|
@@ -24569,7 +25226,7 @@ function operatorSection3() {
|
|
|
24569
25226
|
function buildSystemPrompt2() {
|
|
24570
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.
|
|
24571
25228
|
|
|
24572
|
-
${
|
|
25229
|
+
${companyContextSection4()}${operatorSection4()}INVESTIGATION APPROACH:
|
|
24573
25230
|
1. Start by examining the health summary to understand the overall picture
|
|
24574
25231
|
2. Drill into the lowest-scoring vital signs using get_vital_sign_detail
|
|
24575
25232
|
3. Check divergences to find segments that are significantly worse than average
|
|
@@ -24758,7 +25415,7 @@ ${buildPlaybookBlock()}
|
|
|
24758
25415
|
${commandSection}`;
|
|
24759
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.
|
|
24760
25417
|
|
|
24761
|
-
${
|
|
25418
|
+
${companyContextSection4()}${operatorSection4()}${conversationRules}
|
|
24762
25419
|
|
|
24763
25420
|
${analystSection}
|
|
24764
25421
|
|
|
@@ -24804,20 +25461,27 @@ async function* agenticFindings(computeResult, divergences, options) {
|
|
|
24804
25461
|
assertReplAi(options.ctx);
|
|
24805
25462
|
const mode = options.mode ?? "investigation";
|
|
24806
25463
|
const experiment = options.experiment ?? "production";
|
|
24807
|
-
const responseMode = experiment === "baseline" || experiment === "a" || experiment === "b" ? "deep" : options.responseMode ?? (options.sessionArtifact ? "brief" : "deep");
|
|
24808
|
-
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";
|
|
24809
25466
|
const maxTokens = mode === "fresh" && responseMode === "brief" ? BRIEF_MAX_TOKENS : DEEP_MAX_TOKENS;
|
|
24810
25467
|
const surface = mode === "fresh" ? responseMode === "brief" ? "agentic_fresh_brief" : "agentic_investigation" : "agentic_investigation";
|
|
24811
25468
|
const llmCfg = loadLlmConfig();
|
|
24812
25469
|
const tier = tierForSurface(surface, llmCfg.tier);
|
|
24813
|
-
const systemPrompt = mode === "
|
|
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(
|
|
24814
25478
|
options.sessionContext,
|
|
24815
25479
|
options.memoryBlock,
|
|
24816
25480
|
options.analysisBlock,
|
|
24817
25481
|
options.conversationBlock,
|
|
24818
25482
|
{ responseMode, sessionArtifact: options.sessionArtifact, experiment }
|
|
24819
25483
|
) : buildSystemPrompt2();
|
|
24820
|
-
const tools2 = useTools ? mode === "fresh" ? buildFreshNlTools() : buildInvestigationTools() : [];
|
|
25484
|
+
const tools2 = useTools ? mode === "think" ? buildThinkTools() : mode === "fresh" ? buildFreshNlTools() : buildInvestigationTools() : [];
|
|
24821
25485
|
const toolCtx = { computeResult, divergences };
|
|
24822
25486
|
if (options.includeMetrics) {
|
|
24823
25487
|
try {
|
|
@@ -24829,7 +25493,8 @@ async function* agenticFindings(computeResult, divergences, options) {
|
|
|
24829
25493
|
const initialContext = buildInitialContext(computeResult, divergences, options.userQuestion);
|
|
24830
25494
|
const priorRaw = options.priorMessages ?? [];
|
|
24831
25495
|
const priorMessages = priorRaw.length > 0 && typeof priorRaw[0] === "object" && priorRaw[0] !== null && "content" in priorRaw[0] ? normalizeThread(priorRaw) : priorRaw;
|
|
24832
|
-
const
|
|
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 }];
|
|
24833
25498
|
let lastMeta = { provider_used: "anthropic", model_used: "unknown" };
|
|
24834
25499
|
const loopGuard = new ToolLoopGuard();
|
|
24835
25500
|
const allowedTools = new Set(tools2.map((t) => t.name));
|
|
@@ -24859,7 +25524,7 @@ async function* agenticFindings(computeResult, divergences, options) {
|
|
|
24859
25524
|
const response = await callLlm(messages, maxTokens, true);
|
|
24860
25525
|
if (response.tool_calls.length === 0) {
|
|
24861
25526
|
const fullText = response.text;
|
|
24862
|
-
if (
|
|
25527
|
+
if (conversational) {
|
|
24863
25528
|
const findings3 = parseFindings(fullText);
|
|
24864
25529
|
if (findings3.length > 0) {
|
|
24865
25530
|
for (const finding of findings3) yield { type: "finding", finding };
|
|
@@ -24907,7 +25572,7 @@ async function* agenticFindings(computeResult, divergences, options) {
|
|
|
24907
25572
|
});
|
|
24908
25573
|
}
|
|
24909
25574
|
}
|
|
24910
|
-
if (
|
|
25575
|
+
if (conversational) {
|
|
24911
25576
|
messages.push({
|
|
24912
25577
|
role: "user",
|
|
24913
25578
|
content: "You've reached the tool budget. Please answer the user's question now with what you've learned."
|
|
@@ -24983,6 +25648,7 @@ var init_agentic_loop = __esm({
|
|
|
24983
25648
|
init_thread();
|
|
24984
25649
|
init_untrusted();
|
|
24985
25650
|
init_prompt_parts();
|
|
25651
|
+
init_think_prompt();
|
|
24986
25652
|
MAX_ITERATIONS = 10;
|
|
24987
25653
|
INVESTIGATION_EVIDENCE_NUDGE_AFTER = 5;
|
|
24988
25654
|
BRIEF_MAX_TOKENS = 768;
|