@sonnechasser/ntrp 0.2.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -13580,12 +13580,41 @@ function buildPlaybookBlock() {
13580
13580
  Learned plays (added from this team's experience and ingested case studies \u2014 recommend these when they fit):
13581
13581
  ${learned}`;
13582
13582
  }
13583
- var ANALYST_INSTINCT_BLOCK, VITAL_SIGNS_BLOCK, PLAYBOOK_BLOCK, METRICS_BLOCK, FINDINGS_SCHEMA_BLOCK;
13583
+ function buildCommandCatalogBlock() {
13584
+ const GROUP_ANALYSIS = "Analysis & data";
13585
+ const GROUP_SESSION = "Session, memory & outputs";
13586
+ const GROUP_SETTINGS = "Settings & providers";
13587
+ const groupOrder = [GROUP_ANALYSIS, GROUP_SESSION, GROUP_SETTINGS];
13588
+ const groupFor = (section) => {
13589
+ if (section === "Hidden" || section === "Getting Started") return GROUP_ANALYSIS;
13590
+ if (section === "Settings") return GROUP_SETTINGS;
13591
+ return GROUP_SESSION;
13592
+ };
13593
+ const groups = new Map(groupOrder.map((label) => [label, []]));
13594
+ for (const meta of listWorkflows(true)) {
13595
+ if (meta.name === "ask") continue;
13596
+ if (meta.section === "Admin") continue;
13597
+ groups.get(groupFor(meta.section)).push(formatCatalogLine(meta));
13598
+ }
13599
+ groups.get(GROUP_SESSION).push(
13600
+ "- /help \u2014 Show the shortcut list",
13601
+ "- /home \u2014 Show the welcome dashboard and current session status"
13602
+ );
13603
+ return groupOrder.filter((label) => groups.get(label).length > 0).map((label) => `${label}:
13604
+ ${groups.get(label).join("\n")}`).join("\n\n");
13605
+ }
13606
+ function formatCatalogLine(meta) {
13607
+ const args = meta.args?.trim() ? ` ${meta.args.trim()}` : "";
13608
+ const note = DESTRUCTIVE_COMMAND_NOTES[meta.name] ? ` (${DESTRUCTIVE_COMMAND_NOTES[meta.name]})` : "";
13609
+ return `- /${meta.name}${args} \u2014 ${meta.description}${note}`;
13610
+ }
13611
+ var ANALYST_INSTINCT_BLOCK, VITAL_SIGNS_BLOCK, PLAYBOOK_BLOCK, DESTRUCTIVE_COMMAND_NOTES, METRICS_BLOCK, FINDINGS_SCHEMA_BLOCK;
13584
13612
  var init_prompt_parts = __esm({
13585
13613
  "src/ai/prompt-parts.ts"() {
13586
13614
  "use strict";
13587
13615
  init_profile();
13588
13616
  init_playbook();
13617
+ init_registry2();
13589
13618
  ANALYST_INSTINCT_BLOCK = `A search box returns numbers; a world-class analyst returns insight. The instincts below are what separate the two. Bring them PROACTIVELY \u2014 surface the connection, the chain, and the priority without waiting to be asked, because the user often doesn't know to ask.
13590
13619
 
13591
13620
  - ROOT CAUSE OVER SYMPTOM LIST. GTM problems are rarely independent \u2014 they're usually one failure wearing several masks. When two or more vital signs are red or yellow, your first instinct is to ask "is this the same underlying problem showing up in different places?" and, when it is, name the single cause. (Classic shape: a broken lead handoff starves reps of new pipeline \u2192 they work only what they can already see \u2192 everything else ages into stale, zombie deals \u2192 the forecast inflates with deals nobody is touching \u2192 the quarter is quietly at risk. One cause, four symptoms.)
@@ -13608,6 +13637,9 @@ Restraint matters: NTRP is a stethoscope, not a surgeon. Observe, connect, and r
13608
13637
  - "Fix the Handoff Gap" (id: fix-handoff-gap) \u2014 when drop_rate is high
13609
13638
  - "Retarget Misdirected Effort" (id: retarget-effort) \u2014 when signal_to_noise is low
13610
13639
  - "Unstick the Pipeline" (id: unstick-pipeline) \u2014 when flow_rate is low`;
13640
+ DESTRUCTIVE_COMMAND_NOTES = {
13641
+ reset: "destructive \u2014 wipes all data, requires --force"
13642
+ };
13611
13643
  METRICS_BLOCK = `Revenue metrics measure GTM output \u2014 the standard SaaS metrics:
13612
13644
  - ARR: Total closed-won revenue. New ARR + Expansion ARR = growth; Churned + Contraction = leakage.
13613
13645
  - NRR (Net Revenue Retention): >100% means growing from existing customers. Best-in-class: 110%+.
@@ -15584,15 +15616,18 @@ function inferHandoffTarget(input) {
15584
15616
  return "plan";
15585
15617
  }
15586
15618
  function isShipIntent(input) {
15587
- return /\b(handoff|ship|deliver|board memo|export|turn this into|write.?up|action plan)\b/i.test(
15588
- input.trim()
15589
- );
15619
+ const line = input.trim();
15620
+ if (/\?\s*$/.test(line) || QUESTION_LEAD_RE.test(line)) return false;
15621
+ return SHIP_INTENT_RE.test(line);
15590
15622
  }
15623
+ var QUESTION_LEAD_RE, SHIP_INTENT_RE;
15591
15624
  var init_handoff_draft = __esm({
15592
15625
  "src/conversation/handoff-draft.ts"() {
15593
15626
  "use strict";
15594
15627
  init_profile();
15595
15628
  init_session_analysis();
15629
+ QUESTION_LEAD_RE = /^\s*(what|why|how|when|where|who|which|is|are|was|were|do|does|did|explain|tell me|help me understand)\b/i;
15630
+ SHIP_INTENT_RE = /\b(ship|export|deliver|write[- ]?up|board memo|action plan|turn (this|it|that) into|(draft|create|make|build|prepare|generate|send)\s+(me\s+)?(a\s+|the\s+)?hand[- ]?off|hand[- ]?off\s+(prompt|doc|document|plan))\b/i;
15596
15631
  }
15597
15632
  });
15598
15633
 
@@ -16154,6 +16189,16 @@ FORMATTING (brief mode \u2014 scannable, not chunky):
16154
16189
  - No ### headings, no tables, no --- footer, no closing "want me to dig deeper?" question.
16155
16190
  - Single-point answers can stay one sentence \u2014 don't force bullets when one line is enough.
16156
16191
  `;
16192
+ const commandStyleRule = responseMode === "brief" ? '- Style in brief mode: a suggestion is at most ONE short trailing line after your answer (e.g. "`/segment compare enterprise smb` gives the full side-by-side.") \u2014 no heading, no footer.' : "- Style: weave the suggestion naturally into your close \u2014 one sentence with the exact invocation in `inline code`.";
16193
+ const commandSection = `PRESET COMMANDS (slash commands the user can type at the prompt \u2014 you may SUGGEST these; you have no ability to run them):
16194
+ ${buildCommandCatalogBlock()}
16195
+
16196
+ COMMAND SUGGESTION RULES (suggest-only):
16197
+ - Evaluate whether the user's question overlaps a preset command's capability. Answer the question yourself first, from tools and context; suggest a command only when it adds capability beyond your answer \u2014 writing files, opening a wizard, running a heavier analysis, or changing settings.
16198
+ - If the message is primarily a request to DO what a command does (e.g. "export this to my notes"), say plainly that you don't execute commands and give the exact invocation to type, e.g. \`/handoff notes\`.
16199
+ - Never claim a command was run. Never invent flags \u2014 use only the documented arguments above. At most ONE command suggestion per answer; most answers need none.
16200
+ - Only suggest a command that can work right now given the session state you know (e.g. no \`/diagnose\` or \`/export\` before data or a diagnosis exists).
16201
+ ${commandStyleRule}`;
16157
16202
  const outputRules = responseMode === "brief" ? `OUTPUT RULES:
16158
16203
  - Respond in plain text markdown (not JSON). Lead sentence + bullets when helpful \u2014 never a dense paragraph wall.
16159
16204
  - Pull numbers from the completed session analysis or conversation history \u2014 never guess.
@@ -16177,6 +16222,8 @@ ${VITAL_SIGNS_BLOCK}
16177
16222
 
16178
16223
  PLAYBOOK \u2014 recommend these plays when appropriate:
16179
16224
  ${buildPlaybookBlock()}
16225
+
16226
+ ${commandSection}
16180
16227
  ${formattingSection}
16181
16228
  ${outputRules}`;
16182
16229
  }
@@ -26633,10 +26680,10 @@ function randomGoodbye() {
26633
26680
  return GOODBYES[Math.floor(Math.random() * GOODBYES.length)] ?? "Bye.";
26634
26681
  }
26635
26682
  function commandCompletionCandidates() {
26636
- return [
26683
+ return [.../* @__PURE__ */ new Set([
26637
26684
  ...REPL_BUILTINS,
26638
- ...listCommandNames(false).map((name) => `/${name}`)
26639
- ];
26685
+ ...listCommandNames(true).map((name) => `/${name}`)
26686
+ ])];
26640
26687
  }
26641
26688
  function completeCommand(line) {
26642
26689
  const firstToken2 = line.split(/\s/, 1)[0] ?? "";
@@ -26648,17 +26695,35 @@ function completeCommand(line) {
26648
26695
  function inlineCommandSuggestion(line) {
26649
26696
  if (!line.startsWith("/") || /\s/.test(line)) return null;
26650
26697
  const matches = commandCompletionCandidates().filter((command) => command.startsWith(line));
26651
- if (matches.length !== 1 || matches[0] === line) return null;
26652
- return matches[0].slice(line.length);
26698
+ if (matches.length === 0) return null;
26699
+ if (matches.length === 1) {
26700
+ return matches[0] === line ? null : matches[0].slice(line.length);
26701
+ }
26702
+ let common = matches[0];
26703
+ for (const match of matches) {
26704
+ let i = 0;
26705
+ while (i < common.length && i < match.length && common[i] === match[i]) i++;
26706
+ common = common.slice(0, i);
26707
+ }
26708
+ return common.length > line.length ? common.slice(line.length) : null;
26653
26709
  }
26654
26710
  function renderInlineSuggestion(rl, prompt) {
26655
26711
  const line = rl.line;
26656
26712
  const cursor = rl.cursor;
26657
26713
  const suffix = cursor === line.length ? inlineCommandSuggestion(line) : null;
26714
+ const promptWidth = visibleLength(prompt);
26715
+ const columns = process.stdout.columns ?? 80;
26716
+ const fitsOneRow = promptWidth + line.length + (suffix?.length ?? 0) < columns;
26717
+ const shouldPaint = (suffix !== null || suggestionPainted) && fitsOneRow;
26718
+ if (!shouldPaint) {
26719
+ suggestionPainted = false;
26720
+ return;
26721
+ }
26722
+ suggestionPainted = suffix !== null;
26658
26723
  clearLine2(process.stdout, 0);
26659
26724
  cursorTo2(process.stdout, 0);
26660
26725
  process.stdout.write(prompt + line + (suffix ? chalk68.dim(suffix) : ""));
26661
- cursorTo2(process.stdout, visibleLength(prompt) + cursor);
26726
+ cursorTo2(process.stdout, promptWidth + cursor);
26662
26727
  }
26663
26728
  function appendTurnLine(current, promptLabel, currentSummary) {
26664
26729
  const currentLine = currentSummary ? `${promptLabel} ${current} ${chalk68.white("\u2192")} ${currentSummary}` : `${promptLabel} ${current}`;
@@ -26885,7 +26950,7 @@ function printHelp() {
26885
26950
  console.log(" " + chalk68.dim("Power-user commands (") + paint("accent", "/new") + chalk68.dim(", ") + paint("accent", "/diagnose") + chalk68.dim(", ") + paint("accent", "/metrics") + chalk68.dim(") remain available."));
26886
26951
  console.log();
26887
26952
  }
26888
- var REPL_BUILTINS, ANSI_PATTERN, GOODBYES;
26953
+ var REPL_BUILTINS, ANSI_PATTERN, GOODBYES, suggestionPainted;
26889
26954
  var init_repl = __esm({
26890
26955
  "src/cli/repl.ts"() {
26891
26956
  "use strict";
@@ -26945,6 +27010,7 @@ var init_repl = __esm({
26945
27010
  "May your pipeline stay hydrated.",
26946
27011
  "Don't let the zombie deals bite."
26947
27012
  ];
27013
+ suggestionPainted = false;
26948
27014
  }
26949
27015
  });
26950
27016