@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.
- package/dist/index.js +1727 -761
- package/dist/mcp/server.js +831 -141
- 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",
|
|
@@ -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:
|
|
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: "/
|
|
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", `
|
|
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/
|
|
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(" " +
|
|
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
|
-
" " +
|
|
18774
|
+
" " + chalk20.green("\u2713") + " " + chalk20.bold("Data check") + chalk20.dim(" \u2014 " + bits.join(" \xB7 "))
|
|
18315
18775
|
);
|
|
18316
18776
|
} else {
|
|
18317
|
-
console.log(" " +
|
|
18777
|
+
console.log(" " + chalk20.bold("Data check"));
|
|
18318
18778
|
}
|
|
18319
18779
|
for (const item of audit.missing) {
|
|
18320
|
-
console.log(" " +
|
|
18321
|
-
console.log(" " +
|
|
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(" " +
|
|
18787
|
+
console.log(" " + chalk20.yellow("~") + " " + chalk20.dim(joined));
|
|
18328
18788
|
} else {
|
|
18329
18789
|
for (const item of audit.optional) {
|
|
18330
|
-
console.log(" " +
|
|
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
|
-
" " +
|
|
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
|
-
" " +
|
|
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
|
|
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(" " +
|
|
18867
|
+
console.log(" " + chalk21.bold(headline));
|
|
18408
18868
|
if (opts.fromResume) {
|
|
18409
18869
|
if (runners.length > 0) {
|
|
18410
18870
|
console.log(
|
|
18411
|
-
" " +
|
|
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
|
-
" " +
|
|
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(" " +
|
|
18882
|
+
console.log(" " + chalk21.dim("Also on the board:"));
|
|
18423
18883
|
for (const vs of runners) {
|
|
18424
|
-
console.log(" " +
|
|
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
|
-
" " +
|
|
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
|
-
" " +
|
|
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
|
|
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) +
|
|
18971
|
+
" " + sectionHeading(explainer.label) + chalk22.dim(` \xB7 ${explainer.kind === "vital" ? "vital sign" : "SaaS metric"}`)
|
|
18512
18972
|
);
|
|
18513
|
-
console.log(" " +
|
|
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(" " +
|
|
18985
|
+
console.log(" " + chalk22.dim(`Benchmark \xB7 ${bench}`));
|
|
18526
18986
|
}
|
|
18527
18987
|
if (explainer.dollar_label) {
|
|
18528
18988
|
console.log(
|
|
18529
|
-
" " +
|
|
18989
|
+
" " + chalk22.dim(`Dollar translation \xB7 ${explainer.dollar_label}`)
|
|
18530
18990
|
);
|
|
18531
18991
|
}
|
|
18532
18992
|
console.log();
|
|
18533
18993
|
console.log(
|
|
18534
|
-
" " +
|
|
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
|
|
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
|
-
" " +
|
|
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(" " +
|
|
18610
|
-
console.log(" " +
|
|
18611
|
-
console.log(" " + paint("accent", "/deepdive") +
|
|
18612
|
-
console.log(" " + paint("accent", "/playbook") +
|
|
18613
|
-
console.log(" " +
|
|
18614
|
-
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"));
|
|
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
|
|
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
|
|
19741
|
+
return extractSummary2(result.answer);
|
|
19282
19742
|
} catch (err) {
|
|
19283
19743
|
spinner2.fail("Smoke protocol failed");
|
|
19284
|
-
console.error(" " +
|
|
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(" " +
|
|
19315
|
-
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."));
|
|
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(" " +
|
|
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
|
-
|
|
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(" " +
|
|
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(" " +
|
|
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 ?
|
|
19859
|
+
return lastAnswer ? extractSummary2(lastAnswer) : void 0;
|
|
19400
19860
|
}
|
|
19401
19861
|
function printAnswer(text) {
|
|
19402
19862
|
printMarkdown(text, { indent: 2 });
|
|
19403
19863
|
}
|
|
19404
|
-
function
|
|
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
|
|
19872
|
+
function printFindingInline2(finding) {
|
|
19413
19873
|
const sev = finding.severity;
|
|
19414
19874
|
console.log();
|
|
19415
|
-
console.log(" " + severityPaint(sev)(`[${sev}]`) + " " +
|
|
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(" " +
|
|
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
|
-
" " +
|
|
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
|
|
19917
|
+
import chalk25 from "chalk";
|
|
19458
19918
|
function printDemoDisabled() {
|
|
19459
19919
|
console.log();
|
|
19460
|
-
console.log(" " +
|
|
19920
|
+
console.log(" " + chalk25.red(DEMO_DISABLED_MESSAGE));
|
|
19461
19921
|
console.log(
|
|
19462
|
-
" " +
|
|
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
|
|
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(
|
|
23230
|
+
console.log(chalk26.bold("\n Available Scenarios:\n"));
|
|
22771
23231
|
for (const s of SCENARIO_LIST) {
|
|
22772
|
-
console.log(` ${
|
|
22773
|
-
console.log(` ${
|
|
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(" " +
|
|
22784
|
-
console.error(" " +
|
|
22785
|
-
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."));
|
|
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(
|
|
22794
|
-
console.log(
|
|
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) +
|
|
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(" " +
|
|
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 "${
|
|
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(
|
|
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(
|
|
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(" " +
|
|
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
|
|
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
|
-
" " +
|
|
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
|
-
" " +
|
|
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
|
-
" " +
|
|
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(" " +
|
|
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") +
|
|
23534
|
+
console.log(" " + paint("accent", "Inbox ready") + chalk27.dim(" ") + resolved);
|
|
23055
23535
|
if (n > 0) {
|
|
23056
|
-
console.log(" " +
|
|
23536
|
+
console.log(" " + chalk27.dim(`Synced ${n} recent export${n === 1 ? "" : "s"}.`));
|
|
23057
23537
|
}
|
|
23058
23538
|
console.log(
|
|
23059
|
-
" " +
|
|
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(" " +
|
|
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
|
|
23097
|
-
import { readFileSync as readFileSync20, existsSync as
|
|
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(
|
|
23118
|
-
console.error(
|
|
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 (!
|
|
23122
|
-
console.error(
|
|
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(" " +
|
|
23130
|
-
console.error(" " +
|
|
23131
|
-
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."));
|
|
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 ${
|
|
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(
|
|
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(
|
|
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(
|
|
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 ${
|
|
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(
|
|
23686
|
+
console.log(chalk28.yellow(` ${result.errors.length} rows skipped`));
|
|
23207
23687
|
for (const err of result.errors.slice(0, 3)) {
|
|
23208
|
-
console.log(
|
|
23688
|
+
console.log(chalk28.dim(` - ${err}`));
|
|
23209
23689
|
}
|
|
23210
23690
|
if (result.errors.length > 3) {
|
|
23211
|
-
console.log(
|
|
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(
|
|
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
|
|
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
|
-
" " +
|
|
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(" " +
|
|
23367
|
-
console.log(" " +
|
|
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) +
|
|
23388
|
-
console.log(" " +
|
|
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(" " +
|
|
23446
|
-
console.log(" " +
|
|
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
|
|
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
|
|
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 (
|
|
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 (
|
|
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(" " +
|
|
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(" " +
|
|
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(" " +
|
|
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") +
|
|
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(" " +
|
|
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 +
|
|
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(" " +
|
|
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
|
|
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
|
-
" " +
|
|
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
|
-
" " +
|
|
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
|
-
" " +
|
|
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
|
|
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(" " +
|
|
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:
|
|
24930
|
+
const { existsSync: existsSync27, readFileSync: readFileSync23 } = await import("fs");
|
|
24414
24931
|
const briefPath = contextDocPathForSession2(target.id);
|
|
24415
|
-
if (!
|
|
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/
|
|
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
|
|
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
|
-
${
|
|
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
|
-
${
|
|
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 === "
|
|
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
|
|
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 (
|
|
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 (
|
|
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
|
|
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
|
|
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 (!
|
|
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) {
|