@sonnechasser/ntrp 0.2.3 → 0.3.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/ai/guardrails-smoke.js +19902 -0
- package/dist/ai/guardrails-smoke.js.map +1 -0
- package/dist/conversation/loop-guard-smoke.js +20096 -0
- package/dist/conversation/loop-guard-smoke.js.map +1 -0
- package/dist/demo/whimsy-smoke.js +1 -0
- package/dist/demo/whimsy-smoke.js.map +1 -1
- package/dist/index.js +16036 -14175
- package/dist/index.js.map +1 -1
- package/dist/investigation/verbosity-cli.js +9928 -8525
- package/dist/investigation/verbosity-cli.js.map +1 -1
- package/dist/mcp/server.js +10582 -9174
- package/dist/mcp/server.js.map +1 -1
- package/dist/services/transcript-smoke.js +897 -0
- package/dist/services/transcript-smoke.js.map +1 -0
- package/dist/strategist/strategist-smoke.js +181 -83
- package/dist/strategist/strategist-smoke.js.map +1 -1
- package/dist/whimsy/time-bank-smoke.js +13279 -11733
- package/dist/whimsy/time-bank-smoke.js.map +1 -1
- package/package.json +5 -2
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
process.noDeprecation = true;
|
|
2
3
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
4
|
var __esm = (fn, res) => function __init() {
|
|
4
5
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
@@ -18,9 +19,45 @@ var init_context = __esm({
|
|
|
18
19
|
}
|
|
19
20
|
});
|
|
20
21
|
|
|
22
|
+
// src/output/formatters.ts
|
|
23
|
+
var init_formatters = __esm({
|
|
24
|
+
"src/output/formatters.ts"() {
|
|
25
|
+
"use strict";
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// src/services/terminal-capture.ts
|
|
30
|
+
var init_terminal_capture = __esm({
|
|
31
|
+
"src/services/terminal-capture.ts"() {
|
|
32
|
+
"use strict";
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// src/services/context-doc.ts
|
|
37
|
+
import { writeFileSync } from "fs";
|
|
38
|
+
var init_context_doc = __esm({
|
|
39
|
+
"src/services/context-doc.ts"() {
|
|
40
|
+
"use strict";
|
|
41
|
+
init_context2();
|
|
42
|
+
init_formatters();
|
|
43
|
+
init_terminal_capture();
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// src/services/transcript.ts
|
|
48
|
+
import { existsSync, readFileSync, writeFileSync as writeFileSync2, rmSync } from "fs";
|
|
49
|
+
import { join } from "path";
|
|
50
|
+
var init_transcript = __esm({
|
|
51
|
+
"src/services/transcript.ts"() {
|
|
52
|
+
"use strict";
|
|
53
|
+
init_context2();
|
|
54
|
+
init_terminal_capture();
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
|
|
21
58
|
// src/cli/context.ts
|
|
22
|
-
import { basename, join, resolve, sep } from "path";
|
|
23
|
-
import { existsSync, mkdirSync, writeFileSync, readFileSync, readdirSync, statSync, rmSync } from "fs";
|
|
59
|
+
import { basename, join as join2, resolve, sep } from "path";
|
|
60
|
+
import { existsSync as existsSync2, mkdirSync, writeFileSync as writeFileSync3, readFileSync as readFileSync2, readdirSync, statSync, rmSync as rmSync2 } from "fs";
|
|
24
61
|
import { homedir } from "os";
|
|
25
62
|
import { randomUUID } from "crypto";
|
|
26
63
|
function isAnalysisReady(ctx) {
|
|
@@ -32,24 +69,28 @@ function isAnalysisReady(ctx) {
|
|
|
32
69
|
function defaultSessionAnalysis(primary = "gtm_health") {
|
|
33
70
|
return { primary, completed: [] };
|
|
34
71
|
}
|
|
72
|
+
var STALE_SESSION_MS;
|
|
35
73
|
var init_context2 = __esm({
|
|
36
74
|
"src/cli/context.ts"() {
|
|
37
75
|
"use strict";
|
|
38
76
|
init_thread_compat();
|
|
39
77
|
init_context();
|
|
78
|
+
init_context_doc();
|
|
79
|
+
init_transcript();
|
|
80
|
+
STALE_SESSION_MS = 14 * 24 * 60 * 60 * 1e3;
|
|
40
81
|
}
|
|
41
82
|
});
|
|
42
83
|
|
|
43
84
|
// src/config/store.ts
|
|
44
|
-
import { readFileSync as
|
|
85
|
+
import { readFileSync as readFileSync3, writeFileSync as writeFileSync4, existsSync as existsSync3, mkdirSync as mkdirSync2 } from "fs";
|
|
45
86
|
import { homedir as homedir2 } from "os";
|
|
46
|
-
import { join as
|
|
87
|
+
import { join as join3, resolve as resolve2 } from "path";
|
|
47
88
|
function ntrpHome() {
|
|
48
89
|
return NTRP_DIR;
|
|
49
90
|
}
|
|
50
91
|
function getMemoryDir() {
|
|
51
|
-
const dir =
|
|
52
|
-
if (!
|
|
92
|
+
const dir = join3(NTRP_DIR, "memory");
|
|
93
|
+
if (!existsSync3(dir)) {
|
|
53
94
|
mkdirSync2(dir, { recursive: true });
|
|
54
95
|
}
|
|
55
96
|
return dir;
|
|
@@ -58,43 +99,36 @@ var NTRP_DIR, CONFIG_PATH;
|
|
|
58
99
|
var init_store = __esm({
|
|
59
100
|
"src/config/store.ts"() {
|
|
60
101
|
"use strict";
|
|
61
|
-
NTRP_DIR = process.env.NTRP_HOME ? resolve2(process.env.NTRP_HOME) :
|
|
62
|
-
CONFIG_PATH =
|
|
102
|
+
NTRP_DIR = process.env.NTRP_HOME ? resolve2(process.env.NTRP_HOME) : join3(homedir2(), ".ntrp");
|
|
103
|
+
CONFIG_PATH = join3(NTRP_DIR, "config.json");
|
|
63
104
|
}
|
|
64
105
|
});
|
|
65
106
|
|
|
66
107
|
// src/config/profile.ts
|
|
67
|
-
import { readFileSync as
|
|
68
|
-
import { join as
|
|
108
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync5, existsSync as existsSync4, mkdirSync as mkdirSync3 } from "fs";
|
|
109
|
+
import { join as join4 } from "path";
|
|
69
110
|
var NTRP_DIR2, PROFILE_PATH;
|
|
70
111
|
var init_profile = __esm({
|
|
71
112
|
"src/config/profile.ts"() {
|
|
72
113
|
"use strict";
|
|
73
114
|
init_store();
|
|
74
115
|
NTRP_DIR2 = ntrpHome();
|
|
75
|
-
PROFILE_PATH =
|
|
116
|
+
PROFILE_PATH = join4(NTRP_DIR2, "profile.json");
|
|
76
117
|
}
|
|
77
118
|
});
|
|
78
119
|
|
|
79
120
|
// src/db/connection.ts
|
|
80
|
-
import { dirname, join as
|
|
121
|
+
import { dirname, join as join5, resolve as resolve3 } from "path";
|
|
81
122
|
var NTRP_DIR3, DEFAULT_DB_PATH, DB_PATH_PINNED;
|
|
82
123
|
var init_connection = __esm({
|
|
83
124
|
"src/db/connection.ts"() {
|
|
84
125
|
"use strict";
|
|
85
|
-
NTRP_DIR3 = process.env.NTRP_HOME ? resolve3(process.env.NTRP_HOME) :
|
|
86
|
-
DEFAULT_DB_PATH = process.env.NTRP_DB_PATH ? resolve3(process.env.NTRP_DB_PATH) :
|
|
126
|
+
NTRP_DIR3 = process.env.NTRP_HOME ? resolve3(process.env.NTRP_HOME) : join5(process.env.HOME ?? "", ".ntrp");
|
|
127
|
+
DEFAULT_DB_PATH = process.env.NTRP_DB_PATH ? resolve3(process.env.NTRP_DB_PATH) : join5(NTRP_DIR3, "ntrp.duckdb");
|
|
87
128
|
DB_PATH_PINNED = !!process.env.NTRP_DB_PATH;
|
|
88
129
|
}
|
|
89
130
|
});
|
|
90
131
|
|
|
91
|
-
// src/output/formatters.ts
|
|
92
|
-
var init_formatters = __esm({
|
|
93
|
-
"src/output/formatters.ts"() {
|
|
94
|
-
"use strict";
|
|
95
|
-
}
|
|
96
|
-
});
|
|
97
|
-
|
|
98
132
|
// src/db/queries.ts
|
|
99
133
|
var init_queries = __esm({
|
|
100
134
|
"src/db/queries.ts"() {
|
|
@@ -449,6 +483,14 @@ var init_insights = __esm({
|
|
|
449
483
|
}
|
|
450
484
|
});
|
|
451
485
|
|
|
486
|
+
// src/ai/explore-mode.ts
|
|
487
|
+
var init_explore_mode = __esm({
|
|
488
|
+
"src/ai/explore-mode.ts"() {
|
|
489
|
+
"use strict";
|
|
490
|
+
init_context2();
|
|
491
|
+
}
|
|
492
|
+
});
|
|
493
|
+
|
|
452
494
|
// src/ai/llm/models-cache.ts
|
|
453
495
|
var CACHE_TTL_MS;
|
|
454
496
|
var init_models_cache = __esm({
|
|
@@ -579,6 +621,8 @@ var init_phase = __esm({
|
|
|
579
621
|
"src/conversation/phase.ts"() {
|
|
580
622
|
"use strict";
|
|
581
623
|
init_context2();
|
|
624
|
+
init_repl_api();
|
|
625
|
+
init_explore_mode();
|
|
582
626
|
init_session_state();
|
|
583
627
|
init_theme();
|
|
584
628
|
}
|
|
@@ -598,8 +642,8 @@ var init_gap_audit = __esm({
|
|
|
598
642
|
});
|
|
599
643
|
|
|
600
644
|
// src/strategies/library.ts
|
|
601
|
-
import { writeFileSync as
|
|
602
|
-
import { join as
|
|
645
|
+
import { writeFileSync as writeFileSync6 } from "fs";
|
|
646
|
+
import { join as join6 } from "path";
|
|
603
647
|
import { stringify as stringifyYaml } from "yaml";
|
|
604
648
|
var init_library = __esm({
|
|
605
649
|
"src/strategies/library.ts"() {
|
|
@@ -641,10 +685,17 @@ var init_strategist = __esm({
|
|
|
641
685
|
}
|
|
642
686
|
});
|
|
643
687
|
|
|
688
|
+
// src/ai/llm/types.ts
|
|
689
|
+
var init_types2 = __esm({
|
|
690
|
+
"src/ai/llm/types.ts"() {
|
|
691
|
+
"use strict";
|
|
692
|
+
}
|
|
693
|
+
});
|
|
694
|
+
|
|
644
695
|
// src/config/install.ts
|
|
645
696
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
646
|
-
import { existsSync as
|
|
647
|
-
import { join as
|
|
697
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync5, unlinkSync, writeFileSync as writeFileSync7 } from "fs";
|
|
698
|
+
import { join as join7 } from "path";
|
|
648
699
|
var init_install = __esm({
|
|
649
700
|
"src/config/install.ts"() {
|
|
650
701
|
"use strict";
|
|
@@ -653,8 +704,8 @@ var init_install = __esm({
|
|
|
653
704
|
});
|
|
654
705
|
|
|
655
706
|
// src/config/progress-migrate.ts
|
|
656
|
-
import { existsSync as
|
|
657
|
-
import { join as
|
|
707
|
+
import { existsSync as existsSync6, readFileSync as readFileSync6, renameSync, writeFileSync as writeFileSync8 } from "fs";
|
|
708
|
+
import { join as join8 } from "path";
|
|
658
709
|
var init_progress_migrate = __esm({
|
|
659
710
|
"src/config/progress-migrate.ts"() {
|
|
660
711
|
"use strict";
|
|
@@ -670,8 +721,8 @@ var init_usage_backfill = __esm({
|
|
|
670
721
|
});
|
|
671
722
|
|
|
672
723
|
// src/config/progress.ts
|
|
673
|
-
import { existsSync as
|
|
674
|
-
import { join as
|
|
724
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync5, readFileSync as readFileSync7, unlinkSync as unlinkSync2, writeFileSync as writeFileSync9 } from "fs";
|
|
725
|
+
import { join as join9 } from "path";
|
|
675
726
|
var init_progress = __esm({
|
|
676
727
|
"src/config/progress.ts"() {
|
|
677
728
|
"use strict";
|
|
@@ -690,13 +741,6 @@ var init_usage_stats = __esm({
|
|
|
690
741
|
}
|
|
691
742
|
});
|
|
692
743
|
|
|
693
|
-
// src/ai/llm/types.ts
|
|
694
|
-
var init_types2 = __esm({
|
|
695
|
-
"src/ai/llm/types.ts"() {
|
|
696
|
-
"use strict";
|
|
697
|
-
}
|
|
698
|
-
});
|
|
699
|
-
|
|
700
744
|
// src/ai/llm/errors.ts
|
|
701
745
|
var init_errors2 = __esm({
|
|
702
746
|
"src/ai/llm/errors.ts"() {
|
|
@@ -711,6 +755,7 @@ var init_anthropic = __esm({
|
|
|
711
755
|
"src/ai/llm/adapters/anthropic.ts"() {
|
|
712
756
|
"use strict";
|
|
713
757
|
init_errors2();
|
|
758
|
+
init_types2();
|
|
714
759
|
}
|
|
715
760
|
});
|
|
716
761
|
|
|
@@ -720,6 +765,7 @@ var init_openai_compat = __esm({
|
|
|
720
765
|
"src/ai/llm/adapters/openai-compat.ts"() {
|
|
721
766
|
"use strict";
|
|
722
767
|
init_errors2();
|
|
768
|
+
init_types2();
|
|
723
769
|
}
|
|
724
770
|
});
|
|
725
771
|
|
|
@@ -805,12 +851,26 @@ var init_tool_schemas = __esm({
|
|
|
805
851
|
|
|
806
852
|
// src/ai/privacy.ts
|
|
807
853
|
import { homedir as homedir3 } from "os";
|
|
808
|
-
import { join as
|
|
854
|
+
import { join as join10 } from "path";
|
|
809
855
|
var AUDIT_DIR;
|
|
810
856
|
var init_privacy = __esm({
|
|
811
857
|
"src/ai/privacy.ts"() {
|
|
812
858
|
"use strict";
|
|
813
|
-
AUDIT_DIR =
|
|
859
|
+
AUDIT_DIR = join10(homedir3(), ".ntrp", "audit");
|
|
860
|
+
}
|
|
861
|
+
});
|
|
862
|
+
|
|
863
|
+
// src/ai/untrusted.ts
|
|
864
|
+
var UNTRUSTED_MARKER_NAME, UNTRUSTED_MARKER_END_NAME, MARKER_SPOOF_PATTERN;
|
|
865
|
+
var init_untrusted = __esm({
|
|
866
|
+
"src/ai/untrusted.ts"() {
|
|
867
|
+
"use strict";
|
|
868
|
+
UNTRUSTED_MARKER_NAME = "EXTERNAL_UNTRUSTED_CONTENT";
|
|
869
|
+
UNTRUSTED_MARKER_END_NAME = "END_EXTERNAL_UNTRUSTED_CONTENT";
|
|
870
|
+
MARKER_SPOOF_PATTERN = new RegExp(
|
|
871
|
+
`<{2,}\\s*/?\\s*(?:${UNTRUSTED_MARKER_NAME}|${UNTRUSTED_MARKER_END_NAME})[^>]*>{2,}`,
|
|
872
|
+
"gi"
|
|
873
|
+
);
|
|
814
874
|
}
|
|
815
875
|
});
|
|
816
876
|
|
|
@@ -821,20 +881,40 @@ var init_tool_handlers = __esm({
|
|
|
821
881
|
init_connection();
|
|
822
882
|
init_privacy();
|
|
823
883
|
init_web_search();
|
|
884
|
+
init_untrusted();
|
|
885
|
+
}
|
|
886
|
+
});
|
|
887
|
+
|
|
888
|
+
// src/ai/loop-guard.ts
|
|
889
|
+
var init_loop_guard = __esm({
|
|
890
|
+
"src/ai/loop-guard.ts"() {
|
|
891
|
+
"use strict";
|
|
892
|
+
}
|
|
893
|
+
});
|
|
894
|
+
|
|
895
|
+
// src/ai/thread.ts
|
|
896
|
+
var PRUNED_TOOL_RESULT;
|
|
897
|
+
var init_thread = __esm({
|
|
898
|
+
"src/ai/thread.ts"() {
|
|
899
|
+
"use strict";
|
|
900
|
+
PRUNED_TOOL_RESULT = JSON.stringify({
|
|
901
|
+
pruned: true,
|
|
902
|
+
note: "Old tool result cleared to free context \u2014 call the tool again if you still need it."
|
|
903
|
+
});
|
|
824
904
|
}
|
|
825
905
|
});
|
|
826
906
|
|
|
827
907
|
// src/data/playbook.ts
|
|
828
|
-
import { existsSync as
|
|
829
|
-
import { join as
|
|
908
|
+
import { existsSync as existsSync8, readFileSync as readFileSync8, appendFileSync } from "fs";
|
|
909
|
+
import { join as join11 } from "path";
|
|
830
910
|
function playsPath() {
|
|
831
|
-
return
|
|
911
|
+
return join11(getMemoryDir(), PLAYS_FILE);
|
|
832
912
|
}
|
|
833
913
|
function getCustomPlays() {
|
|
834
914
|
const path = playsPath();
|
|
835
|
-
if (!
|
|
915
|
+
if (!existsSync8(path)) return [];
|
|
836
916
|
const out = [];
|
|
837
|
-
for (const line of
|
|
917
|
+
for (const line of readFileSync8(path, "utf-8").split("\n")) {
|
|
838
918
|
const trimmed = line.trim();
|
|
839
919
|
if (!trimmed) continue;
|
|
840
920
|
try {
|
|
@@ -880,80 +960,80 @@ var init_playbook = __esm({
|
|
|
880
960
|
name: "Multi-Thread Your Deals",
|
|
881
961
|
trigger_vital_sign: "thread_depth",
|
|
882
962
|
trigger_condition: "thread_depth score < 2 (most deals have \u22641 active contact)",
|
|
883
|
-
why: "Single-threaded deals die when your one contact goes dark, changes roles, or loses budget authority. Every deal needs at least 2 active contacts to survive.",
|
|
963
|
+
why: "Single-threaded deals die when your one contact goes dark, changes roles, or loses budget authority. Every deal needs at least 2 active contacts to survive \u2014 and late-stage single-threading is a leading indicator of a slipped quarter.",
|
|
884
964
|
steps: [
|
|
885
|
-
"Pull
|
|
886
|
-
"
|
|
887
|
-
"
|
|
888
|
-
"
|
|
889
|
-
"
|
|
965
|
+
"Pull single-threaded deals weighted by amount \u2014 one exposed mega-deal outranks ten small ones",
|
|
966
|
+
"Enrich the buying committee for each: map champion, economic buyer, and technical evaluator (enrichment waterfall or manual research)",
|
|
967
|
+
"Multi-thread through the existing contact first \u2014 a warm internal referral beats a cold second thread",
|
|
968
|
+
"Log every new contact with a role against the opportunity so thread depth is measured, not remembered",
|
|
969
|
+
"Install the mechanism: an alert when any deal past mid-stage has one active contact, and a job-change signal on champions so you hear about departures before the deal goes quiet"
|
|
890
970
|
],
|
|
891
|
-
tools_that_help: ["
|
|
892
|
-
expected_outcome: "Thread depth score rises above threshold; single-threaded deal count drops by 50%+ within 2 weeks"
|
|
971
|
+
tools_that_help: ["Buying-committee enrichment (waterfall)", "Job-change signal tracking", "CRM contact roles", "Single-thread alerts"],
|
|
972
|
+
expected_outcome: "Thread depth score rises above threshold; single-threaded deal count drops by 50%+ within 2 weeks; zero late-stage deals with one thread"
|
|
893
973
|
},
|
|
894
974
|
{
|
|
895
975
|
id: "clean-dead-pipeline",
|
|
896
976
|
name: "Clean Dead Pipeline",
|
|
897
977
|
trigger_vital_sign: "freshness",
|
|
898
978
|
trigger_condition: "freshness score < 60",
|
|
899
|
-
why: "Stale accounts and zombie deals inflate your pipeline number but deliver zero revenue. They
|
|
979
|
+
why: "Stale accounts and zombie deals inflate your pipeline number but deliver zero revenue. They corrupt the forecast, and they hide the real coverage math \u2014 you can't fix what the CRM is lying about. Clearing them is also the cheapest pipeline you'll ever source: those records are already paid for.",
|
|
900
980
|
steps: [
|
|
901
|
-
"
|
|
902
|
-
"
|
|
903
|
-
"
|
|
904
|
-
"
|
|
905
|
-
"
|
|
981
|
+
"Split the stale pool into saveable vs already-dead: contacted-recently-enough-to-revive vs fiction to clear",
|
|
982
|
+
"Saveable deals: contact within 48 hours with a specific reason to talk, or move to Closed Lost \u2014 inaction is the worst choice",
|
|
983
|
+
"Dead-but-paid-for records: route into a signal-triggered reactivation track (funding, hiring, job-change, site-visit triggers) instead of deleting them",
|
|
984
|
+
"Stale organizations: re-verify ICP fit before re-working; archive what no longer fits so reps stop fishing in dead water",
|
|
985
|
+
"Install the mechanism: a stale-deal alert at N quiet days (calibrated to this motion's cycle), a weekly 15-minute hygiene scrub, and enrichment refresh on records that go quiet"
|
|
906
986
|
],
|
|
907
|
-
tools_that_help: ["CRM bulk update", "
|
|
908
|
-
expected_outcome: "Freshness score jumps 20+ points;
|
|
987
|
+
tools_that_help: ["CRM bulk update", "Signal-based reactivation triggers", "Enrichment refresh (waterfall)", "Pipeline hygiene cadence"],
|
|
988
|
+
expected_outcome: "Freshness score jumps 20+ points; forecast reflects reality; reactivation track produces meetings at a fraction of cold-acquisition cost"
|
|
909
989
|
},
|
|
910
990
|
{
|
|
911
991
|
id: "fix-handoff-gap",
|
|
912
992
|
name: "Fix the Handoff Gap",
|
|
913
993
|
trigger_vital_sign: "drop_rate",
|
|
914
994
|
trigger_condition: "drop_rate score indicates >30% of marketing leads not reaching sales",
|
|
915
|
-
why: "Every lead that marketing generates but sales never sees is wasted budget and lost revenue. The marketing\u2192sales handoff is the #1 leak in most GTM motions.",
|
|
995
|
+
why: "Every lead that marketing generates but sales never sees is wasted budget and lost revenue. The marketing\u2192sales handoff is the #1 leak in most GTM motions \u2014 and it is almost always a systems failure (routing, sync, dead queues), not a people failure.",
|
|
916
996
|
steps: [
|
|
917
|
-
"Audit the
|
|
918
|
-
"
|
|
919
|
-
"
|
|
920
|
-
"
|
|
921
|
-
"
|
|
997
|
+
"Audit the leak by source: which lead sources exist only in marketing systems and never reach the CRM or a rep queue? The leak usually concentrates in one or two sources",
|
|
998
|
+
"Trace the routing path end-to-end: assignment rules, territory coverage, inactive-rep queues, and the marketing\u2192CRM sync itself \u2014 find where records fall on the floor",
|
|
999
|
+
"Fix the pipes: repair routing gaps, reassign orphaned queues, and dedupe/enrich records so routing has the fields it needs to route",
|
|
1000
|
+
"Set the SLA and instrument it: time-to-first-touch on handed-off leads, with a report someone owns",
|
|
1001
|
+
"Install the mechanism: an automated weekly marketing-only-leads report and an alert when any source's handoff rate degrades \u2014 so the leak can't quietly reopen"
|
|
922
1002
|
],
|
|
923
|
-
tools_that_help: ["Lead routing audit", "SLA dashboard", "
|
|
924
|
-
expected_outcome: "Drop rate improves 15+ points; marketing-only lead count drops by 60
|
|
1003
|
+
tools_that_help: ["Lead routing audit", "Enrichment waterfall (routing fields)", "SLA dashboard", "Handoff-degradation alerts"],
|
|
1004
|
+
expected_outcome: "Drop rate improves 15+ points; marketing-only lead count drops by 60%+; time-to-first-touch inside SLA"
|
|
925
1005
|
},
|
|
926
1006
|
{
|
|
927
1007
|
id: "retarget-effort",
|
|
928
1008
|
name: "Retarget Misdirected Effort",
|
|
929
1009
|
trigger_vital_sign: "signal_to_noise",
|
|
930
1010
|
trigger_condition: "signal_to_noise score < 50% (majority of activities not linked to pipeline)",
|
|
931
|
-
why: "When reps spend more than half their time on activities unconnected to open pipeline, they're burning hours that could be closing deals.
|
|
1011
|
+
why: "When reps spend more than half their time on activities unconnected to open pipeline, they're burning hours that could be closing deals. Persistent noise is a targeting-system problem \u2014 reps fish in the pond they can see because the account lists are stale \u2014 not a coaching problem.",
|
|
932
1012
|
steps: [
|
|
933
|
-
"
|
|
934
|
-
"
|
|
935
|
-
"
|
|
936
|
-
"Set
|
|
937
|
-
"
|
|
1013
|
+
"Cut noisy activity by rep and account status: dead accounts, closed deals, unlinked admin \u2014 name what dominates",
|
|
1014
|
+
"Fix the pond, not the fishing: rebuild rep focus lists from ICP fit and live signals (intent, hiring, funding, usage) instead of memory",
|
|
1015
|
+
"Route signals to reps in the channel they already work in, so the next action is the scored account, not the familiar one",
|
|
1016
|
+
"Set the ratio target and instrument it: 80% of weekly activities touch open pipeline or scored accounts, on a per-rep report",
|
|
1017
|
+
"Automate or delete the noise-generating busywork (logging, list building, manual research) so the time actually moves to pipeline"
|
|
938
1018
|
],
|
|
939
|
-
tools_that_help: ["Activity reports by rep", "
|
|
940
|
-
expected_outcome: "Signal-to-noise ratio improves to 70%+; rep
|
|
1019
|
+
tools_that_help: ["Activity reports by rep", "ICP/propensity scoring", "Signal routing to rep channels", "Enrichment automation"],
|
|
1020
|
+
expected_outcome: "Signal-to-noise ratio improves to 70%+; rep hours shift measurably from dead accounts to scored pipeline"
|
|
941
1021
|
},
|
|
942
1022
|
{
|
|
943
1023
|
id: "unstick-pipeline",
|
|
944
1024
|
name: "Unstick the Pipeline",
|
|
945
1025
|
trigger_vital_sign: "flow_rate",
|
|
946
1026
|
trigger_condition: "flow_rate score < 50 (high average deal age or many stuck deals)",
|
|
947
|
-
why: "Stuck deals block revenue and demoralize reps. A deal that hasn't moved in 14+ days is either dead or needs intervention \u2014
|
|
1027
|
+
why: "Stuck deals block revenue and demoralize reps. A deal that hasn't moved in 14+ days (calibrate to this motion's cycle) is either dead or needs intervention \u2014 and stuck deals with past-due close dates are a forecast-credibility problem before they're a revenue problem.",
|
|
948
1028
|
steps: [
|
|
949
|
-
"Pull stuck deals sorted by amount
|
|
950
|
-
"For each stuck deal:
|
|
951
|
-
"Create a specific next action with a deadline for each
|
|
952
|
-
"
|
|
953
|
-
"
|
|
1029
|
+
"Pull stuck deals sorted by amount, and find the stage where they cluster \u2014 there is usually one stage where deals go to die",
|
|
1030
|
+
"For each stuck deal: name the blocker (no next step, waiting on prospect, internal approval, missing stakeholder) \u2014 'stuck' is a symptom, the blocker is the work",
|
|
1031
|
+
"Create a specific next action with a deadline for each; deals with no plausible next action get triaged to Closed Lost so the forecast tells the truth",
|
|
1032
|
+
"Fix the stage, not just the deals: add exit criteria and a required-next-step field to the stage where deals cluster",
|
|
1033
|
+
"Install the mechanism: an aging alert at the motion-calibrated threshold and automatic manager escalation past 2x median stage duration"
|
|
954
1034
|
],
|
|
955
|
-
tools_that_help: ["Deal inspection reports", "
|
|
956
|
-
expected_outcome: "Flow rate score improves 15+ points; stuck deal count drops by 40%+ within 2 weeks"
|
|
1035
|
+
tools_that_help: ["Deal inspection reports", "Stage exit criteria", "Aging alerts", "Manager escalation workflow"],
|
|
1036
|
+
expected_outcome: "Flow rate score improves 15+ points; stuck deal count drops by 40%+ within 2 weeks; the die-stage conversion measurably improves"
|
|
957
1037
|
},
|
|
958
1038
|
{
|
|
959
1039
|
id: "reduce-logo-churn",
|
|
@@ -1069,6 +1149,17 @@ var init_playbook = __esm({
|
|
|
1069
1149
|
}
|
|
1070
1150
|
});
|
|
1071
1151
|
|
|
1152
|
+
// src/memory/play-outcomes.ts
|
|
1153
|
+
import { existsSync as existsSync9, readFileSync as readFileSync9, appendFileSync as appendFileSync2 } from "fs";
|
|
1154
|
+
import { join as join12 } from "path";
|
|
1155
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
1156
|
+
var init_play_outcomes = __esm({
|
|
1157
|
+
"src/memory/play-outcomes.ts"() {
|
|
1158
|
+
"use strict";
|
|
1159
|
+
init_store();
|
|
1160
|
+
}
|
|
1161
|
+
});
|
|
1162
|
+
|
|
1072
1163
|
// src/workflows/registry.ts
|
|
1073
1164
|
var init_registry = __esm({
|
|
1074
1165
|
"src/workflows/registry.ts"() {
|
|
@@ -1077,11 +1168,15 @@ var init_registry = __esm({
|
|
|
1077
1168
|
});
|
|
1078
1169
|
|
|
1079
1170
|
// src/ai/prompt-parts.ts
|
|
1171
|
+
import { existsSync as existsSync10, readFileSync as readFileSync10 } from "fs";
|
|
1172
|
+
import { join as join13 } from "path";
|
|
1080
1173
|
var init_prompt_parts = __esm({
|
|
1081
1174
|
"src/ai/prompt-parts.ts"() {
|
|
1082
1175
|
"use strict";
|
|
1083
1176
|
init_profile();
|
|
1177
|
+
init_store();
|
|
1084
1178
|
init_playbook();
|
|
1179
|
+
init_play_outcomes();
|
|
1085
1180
|
init_registry();
|
|
1086
1181
|
}
|
|
1087
1182
|
});
|
|
@@ -1458,6 +1553,7 @@ var init_strategist_validate = __esm({
|
|
|
1458
1553
|
var init_strategist2 = __esm({
|
|
1459
1554
|
"src/ai/strategist.ts"() {
|
|
1460
1555
|
"use strict";
|
|
1556
|
+
init_types2();
|
|
1461
1557
|
init_failover();
|
|
1462
1558
|
init_surfaces();
|
|
1463
1559
|
init_llm_config();
|
|
@@ -1465,6 +1561,8 @@ var init_strategist2 = __esm({
|
|
|
1465
1561
|
init_tool_schemas();
|
|
1466
1562
|
init_web_search();
|
|
1467
1563
|
init_tool_handlers();
|
|
1564
|
+
init_loop_guard();
|
|
1565
|
+
init_thread();
|
|
1468
1566
|
init_strategist_prompt();
|
|
1469
1567
|
init_strategist_validate();
|
|
1470
1568
|
}
|