@sonnechasser/ntrp 1.4.2 → 1.4.3
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 +167 -148
- package/dist/mcp/server.js +120 -101
- package/package.json +1 -1
package/dist/mcp/server.js
CHANGED
|
@@ -685,13 +685,21 @@ var init_theme = __esm({
|
|
|
685
685
|
});
|
|
686
686
|
|
|
687
687
|
// src/services/handoff-skill.ts
|
|
688
|
-
import { mkdirSync as mkdirSync3 } from "fs";
|
|
688
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync3 } from "fs";
|
|
689
689
|
import { basename, join as join2 } from "path";
|
|
690
690
|
import { homedir as homedir3 } from "os";
|
|
691
691
|
import chalk2 from "chalk";
|
|
692
|
-
function
|
|
692
|
+
function legacyAiInboxDir() {
|
|
693
693
|
return join2(homedir3(), "Documents", "Claude", "ntrp-inbox");
|
|
694
694
|
}
|
|
695
|
+
function defaultAiInboxDirDisplay() {
|
|
696
|
+
return "~/Documents/ntrp-inbox";
|
|
697
|
+
}
|
|
698
|
+
function defaultAiInboxDir() {
|
|
699
|
+
const legacy = legacyAiInboxDir();
|
|
700
|
+
if (existsSync2(legacy)) return legacy;
|
|
701
|
+
return join2(homedir3(), "Documents", "ntrp-inbox");
|
|
702
|
+
}
|
|
695
703
|
function handoffLocations() {
|
|
696
704
|
const archiveRoot = getExportsDir();
|
|
697
705
|
const archiveLatestDir = join2(archiveRoot, "latest");
|
|
@@ -784,7 +792,7 @@ function filenamePattern(ctx) {
|
|
|
784
792
|
return `${datePrefix}*${ext}`;
|
|
785
793
|
}
|
|
786
794
|
function buildStandingSkillMarkdown(loc = handoffLocations()) {
|
|
787
|
-
const inboxBlock = loc.inboxDir ? `Inbox (preferred \u2014 point Claude
|
|
795
|
+
const inboxBlock = loc.inboxDir ? `Inbox (preferred \u2014 point Claude, ChatGPT, Cursor, or another desktop AI at this folder):
|
|
788
796
|
\`${loc.inboxDir}\`
|
|
789
797
|
|
|
790
798
|
Start with:
|
|
@@ -907,7 +915,9 @@ function maybePrintAiInboxNudge() {
|
|
|
907
915
|
if (getConfigValue("ai-inbox-nudge-seen") === "true") return;
|
|
908
916
|
setConfigValue("ai-inbox-nudge-seen", "true");
|
|
909
917
|
console.log(
|
|
910
|
-
" " + chalk2.dim(
|
|
918
|
+
" " + chalk2.dim(
|
|
919
|
+
`Set a pickup folder. Type /inbox set ${defaultAiInboxDirDisplay()} then /inbox skill`
|
|
920
|
+
)
|
|
911
921
|
);
|
|
912
922
|
}
|
|
913
923
|
function printStandingSkill() {
|
|
@@ -916,7 +926,9 @@ function printStandingSkill() {
|
|
|
916
926
|
console.log();
|
|
917
927
|
console.log(" " + bold("NTRP handoff finder skill"));
|
|
918
928
|
console.log(
|
|
919
|
-
" " + chalk2.dim(
|
|
929
|
+
" " + chalk2.dim(
|
|
930
|
+
"Paste this skill once into your desktop AI (Claude, ChatGPT, Cursor, \u2026). Later handoffs do not print it again."
|
|
931
|
+
)
|
|
920
932
|
);
|
|
921
933
|
printPlainBlock(buildStandingSkillMarkdown(loc));
|
|
922
934
|
console.log(" " + chalk2.dim("Written: ") + (loc.inboxSkill ?? loc.archiveSkill));
|
|
@@ -944,7 +956,7 @@ import {
|
|
|
944
956
|
appendFileSync,
|
|
945
957
|
copyFileSync,
|
|
946
958
|
cpSync,
|
|
947
|
-
existsSync as
|
|
959
|
+
existsSync as existsSync3,
|
|
948
960
|
mkdirSync as mkdirSync4,
|
|
949
961
|
readFileSync as readFileSync2,
|
|
950
962
|
readdirSync,
|
|
@@ -962,13 +974,13 @@ function ensureExportsLayout(root = getExportsDir()) {
|
|
|
962
974
|
mkdirSync4(join3(root, sub), { recursive: true });
|
|
963
975
|
}
|
|
964
976
|
const readme = join3(root, "README.md");
|
|
965
|
-
if (!
|
|
977
|
+
if (!existsSync3(readme)) {
|
|
966
978
|
writeFileSync3(readme, ARCHIVE_README, "utf-8");
|
|
967
979
|
}
|
|
968
|
-
if (!
|
|
980
|
+
if (!existsSync3(join3(root, "INDEX.md"))) {
|
|
969
981
|
writeFileSync3(join3(root, "INDEX.md"), "# NTRP exports\n\n_No exports yet._\n", "utf-8");
|
|
970
982
|
}
|
|
971
|
-
if (!
|
|
983
|
+
if (!existsSync3(join3(root, "manifest.jsonl"))) {
|
|
972
984
|
writeFileSync3(join3(root, "manifest.jsonl"), "", "utf-8");
|
|
973
985
|
}
|
|
974
986
|
return root;
|
|
@@ -990,7 +1002,7 @@ function ensureInboxLayout(inbox) {
|
|
|
990
1002
|
mkdirSync4(join3(inbox, "archive"), { recursive: true });
|
|
991
1003
|
const readme = join3(inbox, "README.md");
|
|
992
1004
|
writeFileSync3(readme, buildInboxReadme(), "utf-8");
|
|
993
|
-
if (!
|
|
1005
|
+
if (!existsSync3(join3(inbox, "INDEX.md"))) {
|
|
994
1006
|
writeFileSync3(join3(inbox, "INDEX.md"), "# NTRP AI inbox\n\n_No exports synced yet._\n", "utf-8");
|
|
995
1007
|
}
|
|
996
1008
|
}
|
|
@@ -999,7 +1011,7 @@ function manifestPath(root = getExportsDir()) {
|
|
|
999
1011
|
}
|
|
1000
1012
|
function readManifestEvents(root = getExportsDir()) {
|
|
1001
1013
|
const path = manifestPath(root);
|
|
1002
|
-
if (!
|
|
1014
|
+
if (!existsSync3(path)) return [];
|
|
1003
1015
|
const text = readFileSync2(path, "utf-8");
|
|
1004
1016
|
const events = [];
|
|
1005
1017
|
for (const line of text.split("\n")) {
|
|
@@ -1033,7 +1045,7 @@ function listExports(opts = {}) {
|
|
|
1033
1045
|
}
|
|
1034
1046
|
function copyPath(src, dest) {
|
|
1035
1047
|
mkdirSync4(dirname2(dest), { recursive: true });
|
|
1036
|
-
if (
|
|
1048
|
+
if (existsSync3(dest)) {
|
|
1037
1049
|
rmSync(dest, { recursive: true, force: true });
|
|
1038
1050
|
}
|
|
1039
1051
|
const st = statSync(src);
|
|
@@ -1053,7 +1065,7 @@ function regenerateIndex(root = getExportsDir()) {
|
|
|
1053
1065
|
const withHistory = items.filter((e) => (e.previous_paths?.length ?? 0) > 0);
|
|
1054
1066
|
const latestDir = join3(root, "latest");
|
|
1055
1067
|
const latestLines = [];
|
|
1056
|
-
if (
|
|
1068
|
+
if (existsSync3(latestDir)) {
|
|
1057
1069
|
for (const name of readdirSync(latestDir).sort()) {
|
|
1058
1070
|
latestLines.push(`- \`latest/${name}\` \u2192 \`${join3(latestDir, name)}\``);
|
|
1059
1071
|
}
|
|
@@ -1063,7 +1075,7 @@ function regenerateIndex(root = getExportsDir()) {
|
|
|
1063
1075
|
"",
|
|
1064
1076
|
`Archive root: \`${root}\``,
|
|
1065
1077
|
"",
|
|
1066
|
-
"Set an inbox with `/onboard` or `/inbox set`. Paste `SKILL.md` once into
|
|
1078
|
+
"Set an inbox with `/onboard` or `/inbox set`. Paste `SKILL.md` once into your desktop AI. Later handoffs overwrite `latest-handoff.md`.",
|
|
1067
1079
|
"",
|
|
1068
1080
|
"## Latest pointers",
|
|
1069
1081
|
""
|
|
@@ -1113,18 +1125,18 @@ function regenerateInboxIndex(inbox) {
|
|
|
1113
1125
|
const lines = [
|
|
1114
1126
|
"# NTRP AI inbox",
|
|
1115
1127
|
"",
|
|
1116
|
-
"Start here. Install `SKILL.md` once in
|
|
1128
|
+
"Start here. Install `SKILL.md` once in your desktop AI. Newest prompt: `latest-handoff.md`. Catalog: `INDEX.md`.",
|
|
1117
1129
|
"",
|
|
1118
1130
|
`Canonical archive: \`${archiveRoot}\` (see \`${join3(archiveRoot, "INDEX.md")}\`).`,
|
|
1119
1131
|
"",
|
|
1120
1132
|
"## Latest pointers",
|
|
1121
1133
|
""
|
|
1122
1134
|
];
|
|
1123
|
-
if (
|
|
1135
|
+
if (existsSync3(join3(inbox, "SKILL.md"))) {
|
|
1124
1136
|
lines.push("- [`SKILL.md`](./SKILL.md) \u2014 standing finder. Paste once into your agent.");
|
|
1125
1137
|
}
|
|
1126
1138
|
const latestNames = readdirSync(inbox).filter((n) => n.startsWith("latest-")).sort();
|
|
1127
|
-
if (latestNames.length === 0 && !
|
|
1139
|
+
if (latestNames.length === 0 && !existsSync3(join3(inbox, "SKILL.md"))) {
|
|
1128
1140
|
lines.push("_None yet. Run a handoff after `/inbox set`._");
|
|
1129
1141
|
} else {
|
|
1130
1142
|
for (const name of latestNames) {
|
|
@@ -1152,7 +1164,7 @@ This folder is the landing folder for NTRP handoffs. Desktop AI tools read files
|
|
|
1152
1164
|
|
|
1153
1165
|
## Start here
|
|
1154
1166
|
|
|
1155
|
-
1. Install \`SKILL.md\` once in Claude, ChatGPT, or
|
|
1167
|
+
1. Install \`SKILL.md\` once in Claude, ChatGPT, Cursor, or another desktop AI. Then tell the agent to open the latest NTRP handoff.
|
|
1156
1168
|
2. The newest prompt is \`latest-handoff.md\` (or \`latest-handoff-deck.md\` and similar).
|
|
1157
1169
|
3. \`latest-pickup.md\` names the file that was just written.
|
|
1158
1170
|
|
|
@@ -1170,7 +1182,7 @@ Set the folder with \`/inbox set <path>\`. Print the skill with \`/inbox skill\`
|
|
|
1170
1182
|
`;
|
|
1171
1183
|
}
|
|
1172
1184
|
function pruneInboxArchive(archiveDir, keep = INBOX_ARCHIVE_KEEP) {
|
|
1173
|
-
if (!
|
|
1185
|
+
if (!existsSync3(archiveDir)) return;
|
|
1174
1186
|
const entries2 = readdirSync(archiveDir).map((name) => {
|
|
1175
1187
|
const p = join3(archiveDir, name);
|
|
1176
1188
|
try {
|
|
@@ -1186,7 +1198,7 @@ function pruneInboxArchive(archiveDir, keep = INBOX_ARCHIVE_KEEP) {
|
|
|
1186
1198
|
function syncAiInbox(entry) {
|
|
1187
1199
|
const inbox = getAiInboxDir();
|
|
1188
1200
|
if (!inbox) return null;
|
|
1189
|
-
if (!
|
|
1201
|
+
if (!existsSync3(entry.path)) return null;
|
|
1190
1202
|
ensureInboxLayout(inbox);
|
|
1191
1203
|
const archiveDir = join3(inbox, "archive");
|
|
1192
1204
|
mkdirSync4(archiveDir, { recursive: true });
|
|
@@ -1210,7 +1222,7 @@ function syncRecentToInbox(limit = 10) {
|
|
|
1210
1222
|
const items = listExports({ limit });
|
|
1211
1223
|
let n = 0;
|
|
1212
1224
|
for (const item of items) {
|
|
1213
|
-
if (!
|
|
1225
|
+
if (!existsSync3(item.path)) continue;
|
|
1214
1226
|
const inboxPath = syncAiInbox(item);
|
|
1215
1227
|
if (inboxPath) {
|
|
1216
1228
|
appendManifestEvent({
|
|
@@ -1224,7 +1236,7 @@ function syncRecentToInbox(limit = 10) {
|
|
|
1224
1236
|
}
|
|
1225
1237
|
regenerateInboxIndex(inbox);
|
|
1226
1238
|
regenerateIndex();
|
|
1227
|
-
const newest = items.find((e) =>
|
|
1239
|
+
const newest = items.find((e) => existsSync3(e.path));
|
|
1228
1240
|
if (newest) persistHandoffSkillFiles(newest);
|
|
1229
1241
|
return n;
|
|
1230
1242
|
}
|
|
@@ -1259,10 +1271,10 @@ This archive stores handoffs, reports, notes, CSV receipts, and publish packages
|
|
|
1259
1271
|
Set a dedicated inbox for desktop AI instead of this folder:
|
|
1260
1272
|
|
|
1261
1273
|
\`\`\`
|
|
1262
|
-
/inbox set ~/Documents/
|
|
1274
|
+
/inbox set ~/Documents/ntrp-inbox
|
|
1263
1275
|
\`\`\`
|
|
1264
1276
|
|
|
1265
|
-
After \`/inbox set\` or the optional \`/onboard\` step, paste \`latest/SKILL.md\` once into
|
|
1277
|
+
After \`/inbox set\` or the optional \`/onboard\` step, paste \`latest/SKILL.md\` once into your desktop AI. Later \`/handoff\` overwrites \`latest-handoff.md\`. The skill is not printed again.
|
|
1266
1278
|
`;
|
|
1267
1279
|
}
|
|
1268
1280
|
});
|
|
@@ -1481,12 +1493,12 @@ var init_context_doc = __esm({
|
|
|
1481
1493
|
});
|
|
1482
1494
|
|
|
1483
1495
|
// src/services/transcript.ts
|
|
1484
|
-
import { existsSync as
|
|
1496
|
+
import { existsSync as existsSync4, readFileSync as readFileSync3, writeFileSync as writeFileSync5, rmSync as rmSync2 } from "fs";
|
|
1485
1497
|
import { join as join4 } from "path";
|
|
1486
1498
|
function rebindSessionTranscript(ctx) {
|
|
1487
1499
|
if (!state || state.sessionId === ctx.sessionId) return;
|
|
1488
1500
|
const priorJson = join4(getSessionsDir(), `${state.sessionId}.json`);
|
|
1489
|
-
if (
|
|
1501
|
+
if (existsSync4(priorJson)) {
|
|
1490
1502
|
finalizeCurrentFile("switched session");
|
|
1491
1503
|
} else {
|
|
1492
1504
|
discardSessionTranscript(state.sessionId);
|
|
@@ -1507,7 +1519,7 @@ function discardSessionTranscript(sessionId) {
|
|
|
1507
1519
|
function createState(sessionId) {
|
|
1508
1520
|
const filePath = transcriptPathForSession(sessionId);
|
|
1509
1521
|
let base = "";
|
|
1510
|
-
if (
|
|
1522
|
+
if (existsSync4(filePath)) {
|
|
1511
1523
|
try {
|
|
1512
1524
|
base = readFileSync3(filePath, "utf-8").trimEnd() + "\n";
|
|
1513
1525
|
} catch {
|
|
@@ -1608,12 +1620,12 @@ __export(connection_exports, {
|
|
|
1608
1620
|
run: () => run,
|
|
1609
1621
|
setActiveDbPath: () => setActiveDbPath
|
|
1610
1622
|
});
|
|
1611
|
-
import { mkdirSync as mkdirSync5, existsSync as
|
|
1623
|
+
import { mkdirSync as mkdirSync5, existsSync as existsSync5, rmSync as rmSync3 } from "fs";
|
|
1612
1624
|
import { dirname as dirname3, join as join5, resolve as resolve4 } from "path";
|
|
1613
1625
|
function ensureDir2() {
|
|
1614
1626
|
secureNtrpHome();
|
|
1615
1627
|
const dir = dirname3(activeDbPath);
|
|
1616
|
-
if (!
|
|
1628
|
+
if (!existsSync5(dir)) {
|
|
1617
1629
|
mkdirSync5(dir, { recursive: true, mode: 448 });
|
|
1618
1630
|
}
|
|
1619
1631
|
}
|
|
@@ -2881,14 +2893,14 @@ CREATE INDEX IF NOT EXISTS idx_health_readings_batch ON health_readings(upload_b
|
|
|
2881
2893
|
|
|
2882
2894
|
// src/config/install.ts
|
|
2883
2895
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
2884
|
-
import { existsSync as
|
|
2896
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync6, readFileSync as readFileSync4, unlinkSync, writeFileSync as writeFileSync6 } from "fs";
|
|
2885
2897
|
import { join as join6 } from "path";
|
|
2886
2898
|
function installPath() {
|
|
2887
2899
|
return join6(ntrpHome(), "install.json");
|
|
2888
2900
|
}
|
|
2889
2901
|
function ensureDir3() {
|
|
2890
2902
|
const dir = ntrpHome();
|
|
2891
|
-
if (!
|
|
2903
|
+
if (!existsSync6(dir)) {
|
|
2892
2904
|
mkdirSync6(dir, { recursive: true });
|
|
2893
2905
|
}
|
|
2894
2906
|
}
|
|
@@ -2900,7 +2912,7 @@ function isValidInstall(value) {
|
|
|
2900
2912
|
function ensureInstall() {
|
|
2901
2913
|
if (cachedInstall) return cachedInstall;
|
|
2902
2914
|
const path = installPath();
|
|
2903
|
-
if (
|
|
2915
|
+
if (existsSync6(path)) {
|
|
2904
2916
|
try {
|
|
2905
2917
|
const parsed = JSON.parse(readFileSync4(path, "utf-8"));
|
|
2906
2918
|
if (isValidInstall(parsed)) {
|
|
@@ -2933,7 +2945,7 @@ var init_install = __esm({
|
|
|
2933
2945
|
});
|
|
2934
2946
|
|
|
2935
2947
|
// src/config/progress-migrate.ts
|
|
2936
|
-
import { existsSync as
|
|
2948
|
+
import { existsSync as existsSync7, readFileSync as readFileSync5, renameSync as renameSync2, writeFileSync as writeFileSync7 } from "fs";
|
|
2937
2949
|
import { join as join7 } from "path";
|
|
2938
2950
|
function legacyStatePath() {
|
|
2939
2951
|
return join7(ntrpHome(), "state.json");
|
|
@@ -2950,9 +2962,9 @@ function isValidLegacyState(value) {
|
|
|
2950
2962
|
return s.schema_version === 1 && typeof s.total_minutes_saved === "number" && Array.isArray(s.credits) && Array.isArray(s.milestones_unlocked);
|
|
2951
2963
|
}
|
|
2952
2964
|
function migrateLegacyStateIfNeeded(installId) {
|
|
2953
|
-
if (
|
|
2965
|
+
if (existsSync7(progressPath())) return null;
|
|
2954
2966
|
const legacyPath = legacyStatePath();
|
|
2955
|
-
if (!
|
|
2967
|
+
if (!existsSync7(legacyPath)) return null;
|
|
2956
2968
|
try {
|
|
2957
2969
|
const parsed = JSON.parse(readFileSync5(legacyPath, "utf-8"));
|
|
2958
2970
|
if (!isValidLegacyState(parsed)) return null;
|
|
@@ -3069,14 +3081,14 @@ var init_usage_backfill = __esm({
|
|
|
3069
3081
|
});
|
|
3070
3082
|
|
|
3071
3083
|
// src/config/progress.ts
|
|
3072
|
-
import { existsSync as
|
|
3084
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync7, readFileSync as readFileSync6, unlinkSync as unlinkSync2, writeFileSync as writeFileSync8 } from "fs";
|
|
3073
3085
|
import { join as join8 } from "path";
|
|
3074
3086
|
function progressPath2() {
|
|
3075
3087
|
return join8(ntrpHome(), "progress.json");
|
|
3076
3088
|
}
|
|
3077
3089
|
function ensureDir4() {
|
|
3078
3090
|
const dir = ntrpHome();
|
|
3079
|
-
if (!
|
|
3091
|
+
if (!existsSync8(dir)) {
|
|
3080
3092
|
mkdirSync7(dir, { recursive: true });
|
|
3081
3093
|
}
|
|
3082
3094
|
}
|
|
@@ -3107,7 +3119,7 @@ function reconcileInstallId(state2) {
|
|
|
3107
3119
|
}
|
|
3108
3120
|
function readProgressFile() {
|
|
3109
3121
|
const path = progressPath2();
|
|
3110
|
-
if (!
|
|
3122
|
+
if (!existsSync8(path)) return { state: null, changed: false };
|
|
3111
3123
|
try {
|
|
3112
3124
|
const parsed = JSON.parse(readFileSync6(path, "utf-8"));
|
|
3113
3125
|
if (!isValidProgress(parsed)) return { state: null, changed: false };
|
|
@@ -3828,7 +3840,7 @@ var init_time_bank = __esm({
|
|
|
3828
3840
|
});
|
|
3829
3841
|
|
|
3830
3842
|
// src/ai/llm/providers.ts
|
|
3831
|
-
import { existsSync as
|
|
3843
|
+
import { existsSync as existsSync9, readFileSync as readFileSync7 } from "fs";
|
|
3832
3844
|
import { join as join9 } from "path";
|
|
3833
3845
|
function providersPath() {
|
|
3834
3846
|
return join9(ntrpHome(), "providers.json");
|
|
@@ -3836,7 +3848,7 @@ function providersPath() {
|
|
|
3836
3848
|
function loadCustomProviders() {
|
|
3837
3849
|
if (cachedEntries) return cachedEntries;
|
|
3838
3850
|
const path = providersPath();
|
|
3839
|
-
if (!
|
|
3851
|
+
if (!existsSync9(path)) {
|
|
3840
3852
|
cachedEntries = [];
|
|
3841
3853
|
return cachedEntries;
|
|
3842
3854
|
}
|
|
@@ -4602,7 +4614,7 @@ var init_openai_compat = __esm({
|
|
|
4602
4614
|
});
|
|
4603
4615
|
|
|
4604
4616
|
// src/ai/llm/models-cache.ts
|
|
4605
|
-
import { existsSync as
|
|
4617
|
+
import { existsSync as existsSync10, readFileSync as readFileSync8, writeFileSync as writeFileSync9 } from "fs";
|
|
4606
4618
|
import { join as join10 } from "path";
|
|
4607
4619
|
function cachePath() {
|
|
4608
4620
|
return join10(ntrpHome(), "models.json");
|
|
@@ -4610,7 +4622,7 @@ function cachePath() {
|
|
|
4610
4622
|
function loadFile() {
|
|
4611
4623
|
if (cached) return cached;
|
|
4612
4624
|
const path = cachePath();
|
|
4613
|
-
if (!
|
|
4625
|
+
if (!existsSync10(path)) {
|
|
4614
4626
|
cached = { version: 1, providers: {} };
|
|
4615
4627
|
return cached;
|
|
4616
4628
|
}
|
|
@@ -5228,7 +5240,7 @@ __export(pseudonymize_exports, {
|
|
|
5228
5240
|
wipePrivacyStore: () => wipePrivacyStore
|
|
5229
5241
|
});
|
|
5230
5242
|
import { createHmac, randomBytes } from "crypto";
|
|
5231
|
-
import { existsSync as
|
|
5243
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync8, readFileSync as readFileSync10, rmSync as rmSync4, chmodSync as chmodSync2 } from "fs";
|
|
5232
5244
|
import { join as join11 } from "path";
|
|
5233
5245
|
function privacyDir() {
|
|
5234
5246
|
return join11(ntrpHome(), "privacy");
|
|
@@ -5247,7 +5259,7 @@ function chmodQuiet2(path, mode) {
|
|
|
5247
5259
|
}
|
|
5248
5260
|
function ensurePrivacyDir() {
|
|
5249
5261
|
const dir = privacyDir();
|
|
5250
|
-
if (!
|
|
5262
|
+
if (!existsSync11(dir)) {
|
|
5251
5263
|
mkdirSync8(dir, { recursive: true, mode: 448 });
|
|
5252
5264
|
}
|
|
5253
5265
|
chmodQuiet2(dir, 448);
|
|
@@ -5284,7 +5296,7 @@ function rebuildIndexes() {
|
|
|
5284
5296
|
function loadSecret() {
|
|
5285
5297
|
ensurePrivacyDir();
|
|
5286
5298
|
const path = secretPath();
|
|
5287
|
-
if (
|
|
5299
|
+
if (existsSync11(path)) {
|
|
5288
5300
|
const raw = readFileSync10(path);
|
|
5289
5301
|
const buf = raw.length >= 32 ? raw.subarray(0, 32) : Buffer.from(raw.toString("utf-8").trim(), "hex");
|
|
5290
5302
|
if (buf.length >= 16) return buf.length === 32 ? buf : Buffer.concat([buf], 32);
|
|
@@ -5298,7 +5310,7 @@ function loadLexicon() {
|
|
|
5298
5310
|
ensurePrivacyDir();
|
|
5299
5311
|
secret = loadSecret();
|
|
5300
5312
|
entries = [];
|
|
5301
|
-
if (
|
|
5313
|
+
if (existsSync11(lexiconPath())) {
|
|
5302
5314
|
try {
|
|
5303
5315
|
const parsed = JSON.parse(readFileSync10(lexiconPath(), "utf-8"));
|
|
5304
5316
|
if (parsed?.version === 1 && Array.isArray(parsed.entries)) {
|
|
@@ -5590,7 +5602,7 @@ function wipePrivacyStore() {
|
|
|
5590
5602
|
loaded = false;
|
|
5591
5603
|
dirty = false;
|
|
5592
5604
|
const dir = privacyDir();
|
|
5593
|
-
if (
|
|
5605
|
+
if (existsSync11(dir)) {
|
|
5594
5606
|
rmSync4(dir, { recursive: true, force: true });
|
|
5595
5607
|
}
|
|
5596
5608
|
}
|
|
@@ -5730,20 +5742,20 @@ var init_pseudonymize = __esm({
|
|
|
5730
5742
|
});
|
|
5731
5743
|
|
|
5732
5744
|
// src/config/profile.ts
|
|
5733
|
-
import { readFileSync as readFileSync11, writeFileSync as writeFileSync10, existsSync as
|
|
5745
|
+
import { readFileSync as readFileSync11, writeFileSync as writeFileSync10, existsSync as existsSync12, mkdirSync as mkdirSync9 } from "fs";
|
|
5734
5746
|
import { join as join12 } from "path";
|
|
5735
5747
|
function profilePath() {
|
|
5736
5748
|
return PROFILE_PATH;
|
|
5737
5749
|
}
|
|
5738
5750
|
function profileExists() {
|
|
5739
|
-
return
|
|
5751
|
+
return existsSync12(PROFILE_PATH);
|
|
5740
5752
|
}
|
|
5741
5753
|
function isProfileConfigured(profile = loadProfile()) {
|
|
5742
5754
|
if (!profile) return false;
|
|
5743
5755
|
return profile.company_name.trim().length > 0;
|
|
5744
5756
|
}
|
|
5745
5757
|
function loadProfile() {
|
|
5746
|
-
if (!
|
|
5758
|
+
if (!existsSync12(PROFILE_PATH)) return null;
|
|
5747
5759
|
try {
|
|
5748
5760
|
const parsed = JSON.parse(readFileSync11(PROFILE_PATH, "utf-8"));
|
|
5749
5761
|
if (!parsed || typeof parsed !== "object") return null;
|
|
@@ -5770,7 +5782,7 @@ __export(lexicon_seed_exports, {
|
|
|
5770
5782
|
seedOperatorIdentity: () => seedOperatorIdentity,
|
|
5771
5783
|
wipePrivacyStore: () => wipePrivacyStore2
|
|
5772
5784
|
});
|
|
5773
|
-
import { existsSync as
|
|
5785
|
+
import { existsSync as existsSync13 } from "fs";
|
|
5774
5786
|
function invalidateLexiconSeed() {
|
|
5775
5787
|
dbSeedGeneration = -1;
|
|
5776
5788
|
}
|
|
@@ -5832,7 +5844,7 @@ function seedOperatorIdentity(name, url) {
|
|
|
5832
5844
|
}
|
|
5833
5845
|
async function seedFromDuckDB() {
|
|
5834
5846
|
const dbPath = getActiveDbPath();
|
|
5835
|
-
if (!
|
|
5847
|
+
if (!existsSync13(dbPath)) return;
|
|
5836
5848
|
const { all: all2, getConnectionGeneration: getConnectionGeneration2 } = await Promise.resolve().then(() => (init_connection(), connection_exports));
|
|
5837
5849
|
const gen = getConnectionGeneration2();
|
|
5838
5850
|
if (dbSeedGeneration !== -1 && gen === dbSeedGeneration) return;
|
|
@@ -6511,7 +6523,7 @@ var init_errors2 = __esm({
|
|
|
6511
6523
|
|
|
6512
6524
|
// src/strategies/readers.ts
|
|
6513
6525
|
import { createHash } from "crypto";
|
|
6514
|
-
import { existsSync as
|
|
6526
|
+
import { existsSync as existsSync14, readFileSync as readFileSync12 } from "fs";
|
|
6515
6527
|
import { extname, resolve as resolve5 } from "path";
|
|
6516
6528
|
import { parse as parseYaml } from "yaml";
|
|
6517
6529
|
import { PDFParse } from "pdf-parse";
|
|
@@ -6521,7 +6533,7 @@ async function readStrategyFile(pathOrDash) {
|
|
|
6521
6533
|
return createDocument("stdin", null, text2, {});
|
|
6522
6534
|
}
|
|
6523
6535
|
const sourcePath = resolve5(pathOrDash);
|
|
6524
|
-
if (!
|
|
6536
|
+
if (!existsSync14(sourcePath)) {
|
|
6525
6537
|
throw new NtrpError("strategy_file_not_found", `Strategy file not found: ${pathOrDash}`, 2 /* Usage */);
|
|
6526
6538
|
}
|
|
6527
6539
|
const ext = extname(sourcePath).toLowerCase();
|
|
@@ -6590,7 +6602,7 @@ var init_readers = __esm({
|
|
|
6590
6602
|
});
|
|
6591
6603
|
|
|
6592
6604
|
// src/memory/knowledge.ts
|
|
6593
|
-
import { existsSync as
|
|
6605
|
+
import { existsSync as existsSync15, readFileSync as readFileSync13, appendFileSync as appendFileSync2, readdirSync as readdirSync2 } from "fs";
|
|
6594
6606
|
import { join as join13 } from "path";
|
|
6595
6607
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
6596
6608
|
function knowledgePath() {
|
|
@@ -6598,7 +6610,7 @@ function knowledgePath() {
|
|
|
6598
6610
|
}
|
|
6599
6611
|
function loadKnowledgeChunks() {
|
|
6600
6612
|
const path = knowledgePath();
|
|
6601
|
-
if (!
|
|
6613
|
+
if (!existsSync15(path)) return [];
|
|
6602
6614
|
const out = [];
|
|
6603
6615
|
for (const line of readFileSync13(path, "utf-8").split("\n")) {
|
|
6604
6616
|
const trimmed = line.trim();
|
|
@@ -6621,7 +6633,7 @@ var init_knowledge = __esm({
|
|
|
6621
6633
|
});
|
|
6622
6634
|
|
|
6623
6635
|
// src/ai/privacy.ts
|
|
6624
|
-
import { existsSync as
|
|
6636
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync10, appendFileSync as appendFileSync3 } from "fs";
|
|
6625
6637
|
import { homedir as homedir4 } from "os";
|
|
6626
6638
|
import { join as join14 } from "path";
|
|
6627
6639
|
function scrubSensitiveText(text) {
|
|
@@ -6642,7 +6654,7 @@ function stripPII(obj) {
|
|
|
6642
6654
|
return out;
|
|
6643
6655
|
}
|
|
6644
6656
|
function ensureAuditDir() {
|
|
6645
|
-
if (!
|
|
6657
|
+
if (!existsSync16(AUDIT_DIR)) {
|
|
6646
6658
|
mkdirSync10(AUDIT_DIR, { recursive: true });
|
|
6647
6659
|
}
|
|
6648
6660
|
}
|
|
@@ -6758,14 +6770,14 @@ __export(playbook_exports, {
|
|
|
6758
6770
|
matchTriggeredPlays: () => matchTriggeredPlays,
|
|
6759
6771
|
withKnownRecommendedPlays: () => withKnownRecommendedPlays
|
|
6760
6772
|
});
|
|
6761
|
-
import { existsSync as
|
|
6773
|
+
import { existsSync as existsSync17, readFileSync as readFileSync14, appendFileSync as appendFileSync4 } from "fs";
|
|
6762
6774
|
import { join as join15 } from "path";
|
|
6763
6775
|
function playsPath() {
|
|
6764
6776
|
return join15(getMemoryDir(), PLAYS_FILE);
|
|
6765
6777
|
}
|
|
6766
6778
|
function getCustomPlays() {
|
|
6767
6779
|
const path = playsPath();
|
|
6768
|
-
if (!
|
|
6780
|
+
if (!existsSync17(path)) return [];
|
|
6769
6781
|
const out = [];
|
|
6770
6782
|
for (const line of readFileSync14(path, "utf-8").split("\n")) {
|
|
6771
6783
|
const trimmed = line.trim();
|
|
@@ -7653,7 +7665,7 @@ __export(store_exports2, {
|
|
|
7653
7665
|
rewriteJsonl: () => rewriteJsonl,
|
|
7654
7666
|
scrubText: () => scrubText
|
|
7655
7667
|
});
|
|
7656
|
-
import { existsSync as
|
|
7668
|
+
import { existsSync as existsSync18, readFileSync as readFileSync15, appendFileSync as appendFileSync5, readdirSync as readdirSync4, writeFileSync as writeFileSync12 } from "fs";
|
|
7657
7669
|
import { join as join18 } from "path";
|
|
7658
7670
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
7659
7671
|
function memPath(file) {
|
|
@@ -7661,7 +7673,7 @@ function memPath(file) {
|
|
|
7661
7673
|
}
|
|
7662
7674
|
function readJsonl(file) {
|
|
7663
7675
|
const path = memPath(file);
|
|
7664
|
-
if (!
|
|
7676
|
+
if (!existsSync18(path)) return [];
|
|
7665
7677
|
const out = [];
|
|
7666
7678
|
for (const line of readFileSync15(path, "utf-8").split("\n")) {
|
|
7667
7679
|
const trimmed = line.trim();
|
|
@@ -8040,7 +8052,7 @@ __export(context_exports, {
|
|
|
8040
8052
|
transcriptPathForSession: () => transcriptPathForSession
|
|
8041
8053
|
});
|
|
8042
8054
|
import { basename as basename4, join as join19, resolve as resolve7, sep as sep4 } from "path";
|
|
8043
|
-
import { existsSync as
|
|
8055
|
+
import { existsSync as existsSync19, mkdirSync as mkdirSync11, writeFileSync as writeFileSync13, readFileSync as readFileSync16, readdirSync as readdirSync5, statSync as statSync3, rmSync as rmSync5 } from "fs";
|
|
8044
8056
|
import { homedir as homedir6 } from "os";
|
|
8045
8057
|
import { randomUUID as randomUUID6 } from "crypto";
|
|
8046
8058
|
function isSessionStale(s) {
|
|
@@ -8059,14 +8071,14 @@ function ntrpHomeDir() {
|
|
|
8059
8071
|
}
|
|
8060
8072
|
function getSessionsDir() {
|
|
8061
8073
|
const dir = join19(ntrpHomeDir(), "sessions");
|
|
8062
|
-
if (!
|
|
8074
|
+
if (!existsSync19(dir)) {
|
|
8063
8075
|
mkdirSync11(dir, { recursive: true });
|
|
8064
8076
|
}
|
|
8065
8077
|
return dir;
|
|
8066
8078
|
}
|
|
8067
8079
|
function getDatasetsDir() {
|
|
8068
8080
|
const dir = join19(ntrpHomeDir(), "datasets");
|
|
8069
|
-
if (!
|
|
8081
|
+
if (!existsSync19(dir)) {
|
|
8070
8082
|
mkdirSync11(dir, { recursive: true });
|
|
8071
8083
|
}
|
|
8072
8084
|
return dir;
|
|
@@ -9659,7 +9671,7 @@ __export(play_outcomes_exports, {
|
|
|
9659
9671
|
listPlayOutcomes: () => listPlayOutcomes,
|
|
9660
9672
|
recordPlayOutcomes: () => recordPlayOutcomes
|
|
9661
9673
|
});
|
|
9662
|
-
import { existsSync as
|
|
9674
|
+
import { existsSync as existsSync20, readFileSync as readFileSync17, appendFileSync as appendFileSync6 } from "fs";
|
|
9663
9675
|
import { join as join20 } from "path";
|
|
9664
9676
|
import { randomUUID as randomUUID7 } from "crypto";
|
|
9665
9677
|
function outcomesPath() {
|
|
@@ -9667,7 +9679,7 @@ function outcomesPath() {
|
|
|
9667
9679
|
}
|
|
9668
9680
|
function listPlayOutcomes() {
|
|
9669
9681
|
const path = outcomesPath();
|
|
9670
|
-
if (!
|
|
9682
|
+
if (!existsSync20(path)) return [];
|
|
9671
9683
|
const out = [];
|
|
9672
9684
|
for (const line of readFileSync17(path, "utf-8").split("\n")) {
|
|
9673
9685
|
const trimmed = line.trim();
|
|
@@ -9888,12 +9900,12 @@ args: [show|set <path>|skill|clear]
|
|
|
9888
9900
|
handler: ../commands/exports.ts
|
|
9889
9901
|
---
|
|
9890
9902
|
|
|
9891
|
-
Set a folder that
|
|
9903
|
+
Set a folder that any desktop AI can read (Claude, ChatGPT, Cursor, \u2026).
|
|
9892
9904
|
NTRP copies each handoff to that folder.
|
|
9893
9905
|
NTRP overwrites \`latest-handoff.md\` and \`latest-handoff-deck.md\`. The app then finds the newest file.
|
|
9894
9906
|
NTRP also writes \`SKILL.md\`. That file holds finder instructions with your paths.
|
|
9895
9907
|
Demo setup offers this once. Loading your own data (CSV ingest or \`/onboard\`) asks again if the folder is not set. Skip on that production step and NTRP will not ask again. Type \`/inbox skill\` or \`/handoff skill\` to print the finder. Type \`/inbox set\` at any time.
|
|
9896
|
-
Paste that skill once into Claude, ChatGPT, or
|
|
9908
|
+
Paste that skill once into Claude, ChatGPT, Cursor, or another desktop AI. Later handoffs need no new paste.
|
|
9897
9909
|
\`INDEX.md\` in that folder links to the archive.
|
|
9898
9910
|
A path outside ~/.ntrp needs a confirm. Handoffs carry analysis text.
|
|
9899
9911
|
\`clear\` does not delete files. It only removes the config pointer.`
|
|
@@ -10244,9 +10256,9 @@ args: [<metric>|guide|list|tour]
|
|
|
10244
10256
|
handler: ../commands/deepdive.ts
|
|
10245
10257
|
---
|
|
10246
10258
|
|
|
10247
|
-
CLI slide deck: SaaS refresher, five vital signs (definition, formula, visual, dollar translation), then a how-to section (talk, ask, ship to
|
|
10248
|
-
Bare \`/deepdive\` runs the full onboarding tour. Type \`/deepdive guide\` to jump to how to use NTRP (includes teaching
|
|
10249
|
-
Type \`/deepdive handoff\` for the ship-to-
|
|
10259
|
+
CLI slide deck: SaaS refresher, five vital signs (definition, formula, visual, dollar translation), then a how-to section (talk, ask, ship to your AI, loop).
|
|
10260
|
+
Bare \`/deepdive\` runs the full onboarding tour. Type \`/deepdive guide\` to jump to how to use NTRP (includes teaching the inbox once).
|
|
10261
|
+
Type \`/deepdive handoff\` for the ship-to-AI slide. Type \`/deepdive <metric>\` to jump to one metric card.
|
|
10250
10262
|
Type \`/deepdive list\` to print the catalog. Works without an AI key. Re-run anytime from the homescreen.
|
|
10251
10263
|
Live values overlay when an analysis exists.`
|
|
10252
10264
|
},
|
|
@@ -10567,7 +10579,7 @@ Remaining nuances merge into a custom_context paragraph that flows into all AI s
|
|
|
10567
10579
|
});
|
|
10568
10580
|
|
|
10569
10581
|
// src/ai/prompt-parts.ts
|
|
10570
|
-
import { existsSync as
|
|
10582
|
+
import { existsSync as existsSync21, readFileSync as readFileSync18 } from "fs";
|
|
10571
10583
|
import { join as join21 } from "path";
|
|
10572
10584
|
function buildCompanyProfileBlock() {
|
|
10573
10585
|
const p = loadProfile();
|
|
@@ -10588,7 +10600,7 @@ function buildCompanyProfileBlock() {
|
|
|
10588
10600
|
function loadAnalystFile() {
|
|
10589
10601
|
const path = join21(ntrpHome(), ANALYST_FILE_NAME);
|
|
10590
10602
|
try {
|
|
10591
|
-
if (!
|
|
10603
|
+
if (!existsSync21(path)) return null;
|
|
10592
10604
|
const raw = sanitizeExternalText(readFileSync18(path, "utf-8").trim());
|
|
10593
10605
|
if (!raw) return null;
|
|
10594
10606
|
if (raw.length <= ANALYST_FILE_MAX_CHARS) return raw;
|
|
@@ -11110,7 +11122,7 @@ function buildUserMessage(input) {
|
|
|
11110
11122
|
async function* streamFindings(input, ctx) {
|
|
11111
11123
|
assertReplAi(ctx);
|
|
11112
11124
|
const userMessage = buildUserMessage(input);
|
|
11113
|
-
let meta = { model_used: "unknown", provider_used: "
|
|
11125
|
+
let meta = { model_used: "unknown", provider_used: "unknown", failover: false };
|
|
11114
11126
|
const scanner = new StreamingJsonArrayParser();
|
|
11115
11127
|
let streamed = 0;
|
|
11116
11128
|
for await (const event of streamWithFailover(
|
|
@@ -14683,7 +14695,7 @@ var init_markdown = __esm({
|
|
|
14683
14695
|
import chalk11 from "chalk";
|
|
14684
14696
|
function formatLlmAttribution(meta) {
|
|
14685
14697
|
if (!meta.model_used) return null;
|
|
14686
|
-
const provider = meta.provider_used ?? "
|
|
14698
|
+
const provider = meta.provider_used ?? "unknown";
|
|
14687
14699
|
let line = `via ${formatModelLabel(provider, meta.model_used)}`;
|
|
14688
14700
|
if (meta.failover) {
|
|
14689
14701
|
line += " (auto-failover)";
|
|
@@ -18015,7 +18027,7 @@ async function* strategistPlanSession(options) {
|
|
|
18015
18027
|
})
|
|
18016
18028
|
}
|
|
18017
18029
|
];
|
|
18018
|
-
let lastMeta = { provider_used: "
|
|
18030
|
+
let lastMeta = { provider_used: "unknown", model_used: "unknown" };
|
|
18019
18031
|
const loopGuard = new ToolLoopGuard();
|
|
18020
18032
|
const allowedTools = new Set(tools2.map((t) => t.name));
|
|
18021
18033
|
const callLlm = async (surface, withTools, maxTokens = STAGE_MAX_TOKENS) => {
|
|
@@ -23276,16 +23288,16 @@ var init_scenario_fit = __esm({
|
|
|
23276
23288
|
});
|
|
23277
23289
|
|
|
23278
23290
|
// src/demo/taxonomy-cache.ts
|
|
23279
|
-
import { readFileSync as readFileSync19, writeFileSync as writeFileSync15, existsSync as
|
|
23291
|
+
import { readFileSync as readFileSync19, writeFileSync as writeFileSync15, existsSync as existsSync22, mkdirSync as mkdirSync13, unlinkSync as unlinkSync3 } from "fs";
|
|
23280
23292
|
import { homedir as homedir7 } from "os";
|
|
23281
23293
|
import { join as join24 } from "path";
|
|
23282
23294
|
function ensureDir5() {
|
|
23283
|
-
if (!
|
|
23295
|
+
if (!existsSync22(NTRP_DIR4)) {
|
|
23284
23296
|
mkdirSync13(NTRP_DIR4, { recursive: true });
|
|
23285
23297
|
}
|
|
23286
23298
|
}
|
|
23287
23299
|
function loadCachedTaxonomy(profile) {
|
|
23288
|
-
if (!
|
|
23300
|
+
if (!existsSync22(TAXONOMY_PATH)) return null;
|
|
23289
23301
|
try {
|
|
23290
23302
|
const parsed = JSON.parse(readFileSync19(TAXONOMY_PATH, "utf-8"));
|
|
23291
23303
|
if (!parsed || typeof parsed !== "object") return null;
|
|
@@ -23762,7 +23774,7 @@ __export(inbox_setup_exports, {
|
|
|
23762
23774
|
shouldOfferInboxSkillSetup: () => shouldOfferInboxSkillSetup
|
|
23763
23775
|
});
|
|
23764
23776
|
import chalk27 from "chalk";
|
|
23765
|
-
import { existsSync as
|
|
23777
|
+
import { existsSync as existsSync23 } from "fs";
|
|
23766
23778
|
function markDemoOffered() {
|
|
23767
23779
|
setConfigValue("ai-inbox-nudge-seen", "true");
|
|
23768
23780
|
}
|
|
@@ -23779,7 +23791,7 @@ function shouldOfferInboxSkillSetup(beat) {
|
|
|
23779
23791
|
return !hasProductionOffered();
|
|
23780
23792
|
}
|
|
23781
23793
|
function printSkipHint(beat) {
|
|
23782
|
-
const setCmd = paint("accent",
|
|
23794
|
+
const setCmd = paint("accent", `/inbox set ${defaultAiInboxDirDisplay()}`);
|
|
23783
23795
|
const skillCmd = paint("accent", "/inbox skill");
|
|
23784
23796
|
if (beat === "demo") {
|
|
23785
23797
|
console.log(
|
|
@@ -23791,13 +23803,15 @@ function printSkipHint(beat) {
|
|
|
23791
23803
|
" " + chalk27.dim("Skipped. NTRP will not ask again. Type ") + setCmd + chalk27.dim(" then ") + skillCmd + chalk27.dim(" at any time.")
|
|
23792
23804
|
);
|
|
23793
23805
|
}
|
|
23794
|
-
async function reuseInboxFolderIfPresent(session, beat, folderPath
|
|
23806
|
+
async function reuseInboxFolderIfPresent(session, beat, folderPath) {
|
|
23795
23807
|
if (getAiInboxDir()) return false;
|
|
23796
|
-
|
|
23797
|
-
|
|
23808
|
+
const candidates = folderPath ? [folderPath] : [.../* @__PURE__ */ new Set([defaultAiInboxDir(), legacyAiInboxDir()])];
|
|
23809
|
+
const existing = candidates.find((p) => existsSync23(p));
|
|
23810
|
+
if (!existing) return false;
|
|
23811
|
+
console.log(" " + chalk27.dim("Pickup folder still on disk: ") + existing);
|
|
23798
23812
|
const reuse = await session.confirm("Reuse this pickup folder?", true);
|
|
23799
23813
|
if (!reuse) return false;
|
|
23800
|
-
const resolved = setAiInboxDir(
|
|
23814
|
+
const resolved = setAiInboxDir(existing);
|
|
23801
23815
|
markDemoOffered();
|
|
23802
23816
|
if (beat === "production") markProductionOffered();
|
|
23803
23817
|
console.log();
|
|
@@ -23812,7 +23826,7 @@ async function offerInboxSkillSetup(session, opts = {}) {
|
|
|
23812
23826
|
const beat = opts.beat ?? "production";
|
|
23813
23827
|
if (!shouldOfferInboxSkillSetup(beat)) return;
|
|
23814
23828
|
console.log();
|
|
23815
|
-
console.log(" " + bold("Teach
|
|
23829
|
+
console.log(" " + bold("Teach your AI where handoffs live"));
|
|
23816
23830
|
console.log(
|
|
23817
23831
|
" " + chalk27.dim(
|
|
23818
23832
|
"Optional. NTRP copies every handoff into one folder. You paste instructions once; later /handoff just writes the file."
|
|
@@ -23823,7 +23837,10 @@ async function offerInboxSkillSetup(session, opts = {}) {
|
|
|
23823
23837
|
}
|
|
23824
23838
|
console.log();
|
|
23825
23839
|
if (await reuseInboxFolderIfPresent(session, beat)) return;
|
|
23826
|
-
const want = await session.confirm(
|
|
23840
|
+
const want = await session.confirm(
|
|
23841
|
+
"Set a pickup folder for Claude, ChatGPT, Cursor, or another desktop AI?",
|
|
23842
|
+
true
|
|
23843
|
+
);
|
|
23827
23844
|
if (!want) {
|
|
23828
23845
|
if (beat === "demo") markDemoOffered();
|
|
23829
23846
|
else markProductionOffered();
|
|
@@ -23855,10 +23872,12 @@ async function offerInboxSkillSetup(session, opts = {}) {
|
|
|
23855
23872
|
console.log(" " + chalk27.dim(`Synced ${n} recent export${n === 1 ? "" : "s"}.`));
|
|
23856
23873
|
}
|
|
23857
23874
|
console.log(
|
|
23858
|
-
" " + chalk27.dim(
|
|
23875
|
+
" " + chalk27.dim(
|
|
23876
|
+
"Paste this skill into your desktop AI once. Later, tell it to open the latest NTRP handoff."
|
|
23877
|
+
)
|
|
23859
23878
|
);
|
|
23860
23879
|
printStandingSkill();
|
|
23861
|
-
await session.askPressEnter("Paste the skill into
|
|
23880
|
+
await session.askPressEnter("Paste the skill into your AI. Then continue");
|
|
23862
23881
|
console.log(" " + chalk27.dim("Done. Later handoffs write to that folder. The skill is not printed again."));
|
|
23863
23882
|
console.log();
|
|
23864
23883
|
}
|
|
@@ -23893,7 +23912,7 @@ __export(ingest_exports, {
|
|
|
23893
23912
|
handler: () => handler3
|
|
23894
23913
|
});
|
|
23895
23914
|
import chalk28 from "chalk";
|
|
23896
|
-
import { readFileSync as readFileSync20, existsSync as
|
|
23915
|
+
import { readFileSync as readFileSync20, existsSync as existsSync24 } from "fs";
|
|
23897
23916
|
import { basename as basename6 } from "path";
|
|
23898
23917
|
async function handler3(args, ctx) {
|
|
23899
23918
|
const { positional, flags } = parseArgs(args, [
|
|
@@ -23917,7 +23936,7 @@ async function handler3(args, ctx) {
|
|
|
23917
23936
|
console.error(chalk28.dim(" /ingest --demo [--scenario <name>]"));
|
|
23918
23937
|
process.exit(1);
|
|
23919
23938
|
}
|
|
23920
|
-
if (!
|
|
23939
|
+
if (!existsSync24(file)) {
|
|
23921
23940
|
console.error(chalk28.red(` File not found: ${file}`));
|
|
23922
23941
|
process.exit(1);
|
|
23923
23942
|
}
|
|
@@ -24303,7 +24322,7 @@ __export(ingest_chat_exports, {
|
|
|
24303
24322
|
loadDemoFromChat: () => loadDemoFromChat,
|
|
24304
24323
|
looksLikeFilePath: () => looksLikeFilePath
|
|
24305
24324
|
});
|
|
24306
|
-
import { existsSync as
|
|
24325
|
+
import { existsSync as existsSync25 } from "fs";
|
|
24307
24326
|
import { basename as basename7, resolve as resolve9 } from "path";
|
|
24308
24327
|
import { homedir as homedir8 } from "os";
|
|
24309
24328
|
import chalk30 from "chalk";
|
|
@@ -24323,11 +24342,11 @@ function extractFilePath(input) {
|
|
|
24323
24342
|
const m = trimmed.match(re);
|
|
24324
24343
|
if (m?.[1]) {
|
|
24325
24344
|
const p = expandPath(m[1]);
|
|
24326
|
-
if (
|
|
24345
|
+
if (existsSync25(p)) return p;
|
|
24327
24346
|
}
|
|
24328
24347
|
if (!m?.[1] && re.test(trimmed) && trimmed.toLowerCase().endsWith(".csv")) {
|
|
24329
24348
|
const p = expandPath(trimmed.replace(/^["']|["']$/g, ""));
|
|
24330
|
-
if (
|
|
24349
|
+
if (existsSync25(p)) return p;
|
|
24331
24350
|
}
|
|
24332
24351
|
}
|
|
24333
24352
|
return null;
|
|
@@ -25246,9 +25265,9 @@ async function handleGetSessionBrief(input) {
|
|
|
25246
25265
|
if (!target) {
|
|
25247
25266
|
return { error: `No session matching "${raw}".` };
|
|
25248
25267
|
}
|
|
25249
|
-
const { existsSync:
|
|
25268
|
+
const { existsSync: existsSync28, readFileSync: readFileSync23 } = await import("fs");
|
|
25250
25269
|
const briefPath = contextDocPathForSession2(target.id);
|
|
25251
|
-
if (!
|
|
25270
|
+
if (!existsSync28(briefPath)) {
|
|
25252
25271
|
return {
|
|
25253
25272
|
session_id: target.id,
|
|
25254
25273
|
error: "No context brief on disk for this session (created before brief storage existed).",
|
|
@@ -25819,7 +25838,7 @@ async function* agenticFindings(computeResult, divergences, options) {
|
|
|
25819
25838
|
const priorMessages = priorRaw.length > 0 && typeof priorRaw[0] === "object" && priorRaw[0] !== null && "content" in priorRaw[0] ? normalizeThread(priorRaw) : priorRaw;
|
|
25820
25839
|
const conversational = mode === "fresh" || mode === "think";
|
|
25821
25840
|
const messages = conversational && priorMessages.length > 0 && options.userQuestion ? [...priorMessages, { role: "user", content: options.userQuestion }] : [{ role: "user", content: initialContext }];
|
|
25822
|
-
let lastMeta = { provider_used: "
|
|
25841
|
+
let lastMeta = { provider_used: "unknown", model_used: "unknown" };
|
|
25823
25842
|
const loopGuard = new ToolLoopGuard();
|
|
25824
25843
|
const allowedTools = new Set(tools2.map((t) => t.name));
|
|
25825
25844
|
async function callLlm(msgs, tokens, withTools) {
|
|
@@ -26220,7 +26239,7 @@ var init_ask = __esm({
|
|
|
26220
26239
|
});
|
|
26221
26240
|
|
|
26222
26241
|
// src/services/setup.ts
|
|
26223
|
-
import { existsSync as
|
|
26242
|
+
import { existsSync as existsSync26, mkdirSync as mkdirSync14, readFileSync as readFileSync21, writeFileSync as writeFileSync16 } from "fs";
|
|
26224
26243
|
import { join as join25 } from "path";
|
|
26225
26244
|
function setupCheck() {
|
|
26226
26245
|
const home = ntrpHome();
|
|
@@ -26279,11 +26298,11 @@ var init_setup = __esm({
|
|
|
26279
26298
|
});
|
|
26280
26299
|
|
|
26281
26300
|
// src/version.ts
|
|
26282
|
-
import { existsSync as
|
|
26301
|
+
import { existsSync as existsSync27, readFileSync as readFileSync22 } from "fs";
|
|
26283
26302
|
import { dirname as dirname5, join as join26 } from "path";
|
|
26284
26303
|
import { fileURLToPath } from "url";
|
|
26285
26304
|
function readVersionFromPackageJson(packageJsonPath) {
|
|
26286
|
-
if (!
|
|
26305
|
+
if (!existsSync27(packageJsonPath)) return null;
|
|
26287
26306
|
try {
|
|
26288
26307
|
const pkg = JSON.parse(readFileSync22(packageJsonPath, "utf-8"));
|
|
26289
26308
|
if (typeof pkg.version === "string" && pkg.version.length > 0) return pkg.version;
|