@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/index.js
CHANGED
|
@@ -849,13 +849,21 @@ var init_theme = __esm({
|
|
|
849
849
|
});
|
|
850
850
|
|
|
851
851
|
// src/services/handoff-skill.ts
|
|
852
|
-
import { mkdirSync as mkdirSync3 } from "fs";
|
|
852
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync3 } from "fs";
|
|
853
853
|
import { basename as basename2, join as join2 } from "path";
|
|
854
854
|
import { homedir as homedir3 } from "os";
|
|
855
855
|
import chalk2 from "chalk";
|
|
856
|
-
function
|
|
856
|
+
function legacyAiInboxDir() {
|
|
857
857
|
return join2(homedir3(), "Documents", "Claude", "ntrp-inbox");
|
|
858
858
|
}
|
|
859
|
+
function defaultAiInboxDirDisplay() {
|
|
860
|
+
return "~/Documents/ntrp-inbox";
|
|
861
|
+
}
|
|
862
|
+
function defaultAiInboxDir() {
|
|
863
|
+
const legacy = legacyAiInboxDir();
|
|
864
|
+
if (existsSync2(legacy)) return legacy;
|
|
865
|
+
return join2(homedir3(), "Documents", "ntrp-inbox");
|
|
866
|
+
}
|
|
859
867
|
function handoffLocations() {
|
|
860
868
|
const archiveRoot = getExportsDir();
|
|
861
869
|
const archiveLatestDir = join2(archiveRoot, "latest");
|
|
@@ -948,7 +956,7 @@ function filenamePattern(ctx) {
|
|
|
948
956
|
return `${datePrefix}*${ext}`;
|
|
949
957
|
}
|
|
950
958
|
function buildStandingSkillMarkdown(loc = handoffLocations()) {
|
|
951
|
-
const inboxBlock = loc.inboxDir ? `Inbox (preferred \u2014 point Claude
|
|
959
|
+
const inboxBlock = loc.inboxDir ? `Inbox (preferred \u2014 point Claude, ChatGPT, Cursor, or another desktop AI at this folder):
|
|
952
960
|
\`${loc.inboxDir}\`
|
|
953
961
|
|
|
954
962
|
Start with:
|
|
@@ -1071,7 +1079,9 @@ function maybePrintAiInboxNudge() {
|
|
|
1071
1079
|
if (getConfigValue("ai-inbox-nudge-seen") === "true") return;
|
|
1072
1080
|
setConfigValue("ai-inbox-nudge-seen", "true");
|
|
1073
1081
|
console.log(
|
|
1074
|
-
" " + chalk2.dim(
|
|
1082
|
+
" " + chalk2.dim(
|
|
1083
|
+
`Set a pickup folder. Type /inbox set ${defaultAiInboxDirDisplay()} then /inbox skill`
|
|
1084
|
+
)
|
|
1075
1085
|
);
|
|
1076
1086
|
}
|
|
1077
1087
|
function printHandoffDelivered(event, opts = {}) {
|
|
@@ -1091,7 +1101,9 @@ function printStandingSkill() {
|
|
|
1091
1101
|
console.log();
|
|
1092
1102
|
console.log(" " + bold("NTRP handoff finder skill"));
|
|
1093
1103
|
console.log(
|
|
1094
|
-
" " + chalk2.dim(
|
|
1104
|
+
" " + chalk2.dim(
|
|
1105
|
+
"Paste this skill once into your desktop AI (Claude, ChatGPT, Cursor, \u2026). Later handoffs do not print it again."
|
|
1106
|
+
)
|
|
1095
1107
|
);
|
|
1096
1108
|
printPlainBlock(buildStandingSkillMarkdown(loc));
|
|
1097
1109
|
console.log(" " + chalk2.dim("Written: ") + (loc.inboxSkill ?? loc.archiveSkill));
|
|
@@ -1144,7 +1156,7 @@ import {
|
|
|
1144
1156
|
appendFileSync,
|
|
1145
1157
|
copyFileSync,
|
|
1146
1158
|
cpSync,
|
|
1147
|
-
existsSync as
|
|
1159
|
+
existsSync as existsSync3,
|
|
1148
1160
|
mkdirSync as mkdirSync4,
|
|
1149
1161
|
readFileSync as readFileSync2,
|
|
1150
1162
|
readdirSync,
|
|
@@ -1165,13 +1177,13 @@ function ensureExportsLayout(root = getExportsDir()) {
|
|
|
1165
1177
|
mkdirSync4(join3(root, sub), { recursive: true });
|
|
1166
1178
|
}
|
|
1167
1179
|
const readme = join3(root, "README.md");
|
|
1168
|
-
if (!
|
|
1180
|
+
if (!existsSync3(readme)) {
|
|
1169
1181
|
writeFileSync3(readme, ARCHIVE_README, "utf-8");
|
|
1170
1182
|
}
|
|
1171
|
-
if (!
|
|
1183
|
+
if (!existsSync3(join3(root, "INDEX.md"))) {
|
|
1172
1184
|
writeFileSync3(join3(root, "INDEX.md"), "# NTRP exports\n\n_No exports yet._\n", "utf-8");
|
|
1173
1185
|
}
|
|
1174
|
-
if (!
|
|
1186
|
+
if (!existsSync3(join3(root, "manifest.jsonl"))) {
|
|
1175
1187
|
writeFileSync3(join3(root, "manifest.jsonl"), "", "utf-8");
|
|
1176
1188
|
}
|
|
1177
1189
|
return root;
|
|
@@ -1205,7 +1217,7 @@ function ensureInboxLayout(inbox) {
|
|
|
1205
1217
|
mkdirSync4(join3(inbox, "archive"), { recursive: true });
|
|
1206
1218
|
const readme = join3(inbox, "README.md");
|
|
1207
1219
|
writeFileSync3(readme, buildInboxReadme(), "utf-8");
|
|
1208
|
-
if (!
|
|
1220
|
+
if (!existsSync3(join3(inbox, "INDEX.md"))) {
|
|
1209
1221
|
writeFileSync3(join3(inbox, "INDEX.md"), "# NTRP AI inbox\n\n_No exports synced yet._\n", "utf-8");
|
|
1210
1222
|
}
|
|
1211
1223
|
}
|
|
@@ -1214,7 +1226,7 @@ function manifestPath(root = getExportsDir()) {
|
|
|
1214
1226
|
}
|
|
1215
1227
|
function readManifestEvents(root = getExportsDir()) {
|
|
1216
1228
|
const path = manifestPath(root);
|
|
1217
|
-
if (!
|
|
1229
|
+
if (!existsSync3(path)) return [];
|
|
1218
1230
|
const text = readFileSync2(path, "utf-8");
|
|
1219
1231
|
const events = [];
|
|
1220
1232
|
for (const line of text.split("\n")) {
|
|
@@ -1269,7 +1281,7 @@ function updateArchiveLatest(kind, sourcePath, root) {
|
|
|
1269
1281
|
}
|
|
1270
1282
|
function copyPath(src, dest) {
|
|
1271
1283
|
mkdirSync4(dirname2(dest), { recursive: true });
|
|
1272
|
-
if (
|
|
1284
|
+
if (existsSync3(dest)) {
|
|
1273
1285
|
rmSync(dest, { recursive: true, force: true });
|
|
1274
1286
|
}
|
|
1275
1287
|
const st = statSync(src);
|
|
@@ -1289,7 +1301,7 @@ function regenerateIndex(root = getExportsDir()) {
|
|
|
1289
1301
|
const withHistory = items.filter((e) => (e.previous_paths?.length ?? 0) > 0);
|
|
1290
1302
|
const latestDir = join3(root, "latest");
|
|
1291
1303
|
const latestLines = [];
|
|
1292
|
-
if (
|
|
1304
|
+
if (existsSync3(latestDir)) {
|
|
1293
1305
|
for (const name of readdirSync(latestDir).sort()) {
|
|
1294
1306
|
latestLines.push(`- \`latest/${name}\` \u2192 \`${join3(latestDir, name)}\``);
|
|
1295
1307
|
}
|
|
@@ -1299,7 +1311,7 @@ function regenerateIndex(root = getExportsDir()) {
|
|
|
1299
1311
|
"",
|
|
1300
1312
|
`Archive root: \`${root}\``,
|
|
1301
1313
|
"",
|
|
1302
|
-
"Set an inbox with `/onboard` or `/inbox set`. Paste `SKILL.md` once into
|
|
1314
|
+
"Set an inbox with `/onboard` or `/inbox set`. Paste `SKILL.md` once into your desktop AI. Later handoffs overwrite `latest-handoff.md`.",
|
|
1303
1315
|
"",
|
|
1304
1316
|
"## Latest pointers",
|
|
1305
1317
|
""
|
|
@@ -1349,18 +1361,18 @@ function regenerateInboxIndex(inbox) {
|
|
|
1349
1361
|
const lines = [
|
|
1350
1362
|
"# NTRP AI inbox",
|
|
1351
1363
|
"",
|
|
1352
|
-
"Start here. Install `SKILL.md` once in
|
|
1364
|
+
"Start here. Install `SKILL.md` once in your desktop AI. Newest prompt: `latest-handoff.md`. Catalog: `INDEX.md`.",
|
|
1353
1365
|
"",
|
|
1354
1366
|
`Canonical archive: \`${archiveRoot}\` (see \`${join3(archiveRoot, "INDEX.md")}\`).`,
|
|
1355
1367
|
"",
|
|
1356
1368
|
"## Latest pointers",
|
|
1357
1369
|
""
|
|
1358
1370
|
];
|
|
1359
|
-
if (
|
|
1371
|
+
if (existsSync3(join3(inbox, "SKILL.md"))) {
|
|
1360
1372
|
lines.push("- [`SKILL.md`](./SKILL.md) \u2014 standing finder. Paste once into your agent.");
|
|
1361
1373
|
}
|
|
1362
1374
|
const latestNames = readdirSync(inbox).filter((n) => n.startsWith("latest-")).sort();
|
|
1363
|
-
if (latestNames.length === 0 && !
|
|
1375
|
+
if (latestNames.length === 0 && !existsSync3(join3(inbox, "SKILL.md"))) {
|
|
1364
1376
|
lines.push("_None yet. Run a handoff after `/inbox set`._");
|
|
1365
1377
|
} else {
|
|
1366
1378
|
for (const name of latestNames) {
|
|
@@ -1388,7 +1400,7 @@ This folder is the landing folder for NTRP handoffs. Desktop AI tools read files
|
|
|
1388
1400
|
|
|
1389
1401
|
## Start here
|
|
1390
1402
|
|
|
1391
|
-
1. Install \`SKILL.md\` once in Claude, ChatGPT, or
|
|
1403
|
+
1. Install \`SKILL.md\` once in Claude, ChatGPT, Cursor, or another desktop AI. Then tell the agent to open the latest NTRP handoff.
|
|
1392
1404
|
2. The newest prompt is \`latest-handoff.md\` (or \`latest-handoff-deck.md\` and similar).
|
|
1393
1405
|
3. \`latest-pickup.md\` names the file that was just written.
|
|
1394
1406
|
|
|
@@ -1406,7 +1418,7 @@ Set the folder with \`/inbox set <path>\`. Print the skill with \`/inbox skill\`
|
|
|
1406
1418
|
`;
|
|
1407
1419
|
}
|
|
1408
1420
|
function pruneInboxArchive(archiveDir, keep = INBOX_ARCHIVE_KEEP) {
|
|
1409
|
-
if (!
|
|
1421
|
+
if (!existsSync3(archiveDir)) return;
|
|
1410
1422
|
const entries2 = readdirSync(archiveDir).map((name) => {
|
|
1411
1423
|
const p = join3(archiveDir, name);
|
|
1412
1424
|
try {
|
|
@@ -1422,7 +1434,7 @@ function pruneInboxArchive(archiveDir, keep = INBOX_ARCHIVE_KEEP) {
|
|
|
1422
1434
|
function syncAiInbox(entry) {
|
|
1423
1435
|
const inbox = getAiInboxDir();
|
|
1424
1436
|
if (!inbox) return null;
|
|
1425
|
-
if (!
|
|
1437
|
+
if (!existsSync3(entry.path)) return null;
|
|
1426
1438
|
ensureInboxLayout(inbox);
|
|
1427
1439
|
const archiveDir = join3(inbox, "archive");
|
|
1428
1440
|
mkdirSync4(archiveDir, { recursive: true });
|
|
@@ -1446,7 +1458,7 @@ function syncRecentToInbox(limit = 10) {
|
|
|
1446
1458
|
const items = listExports({ limit });
|
|
1447
1459
|
let n = 0;
|
|
1448
1460
|
for (const item of items) {
|
|
1449
|
-
if (!
|
|
1461
|
+
if (!existsSync3(item.path)) continue;
|
|
1450
1462
|
const inboxPath = syncAiInbox(item);
|
|
1451
1463
|
if (inboxPath) {
|
|
1452
1464
|
appendManifestEvent({
|
|
@@ -1460,14 +1472,14 @@ function syncRecentToInbox(limit = 10) {
|
|
|
1460
1472
|
}
|
|
1461
1473
|
regenerateInboxIndex(inbox);
|
|
1462
1474
|
regenerateIndex();
|
|
1463
|
-
const newest = items.find((e) =>
|
|
1475
|
+
const newest = items.find((e) => existsSync3(e.path));
|
|
1464
1476
|
if (newest) persistHandoffSkillFiles(newest);
|
|
1465
1477
|
return n;
|
|
1466
1478
|
}
|
|
1467
1479
|
function recordExportWrite(opts) {
|
|
1468
1480
|
const root = ensureExportsLayout();
|
|
1469
1481
|
const path = resolve3(opts.path);
|
|
1470
|
-
if (!
|
|
1482
|
+
if (!existsSync3(path)) {
|
|
1471
1483
|
throw new Error(`Export path does not exist: ${path}`);
|
|
1472
1484
|
}
|
|
1473
1485
|
updateArchiveLatest(opts.kind, path, root);
|
|
@@ -1492,14 +1504,14 @@ function moveExport(idOrPath, destDir) {
|
|
|
1492
1504
|
if (!item) {
|
|
1493
1505
|
throw new Error(`No export matching "${idOrPath}". Try /exports list.`);
|
|
1494
1506
|
}
|
|
1495
|
-
if (!
|
|
1507
|
+
if (!existsSync3(item.path)) {
|
|
1496
1508
|
throw new Error(`Export file missing on disk: ${item.path}`);
|
|
1497
1509
|
}
|
|
1498
1510
|
const destRoot = resolveUserPath(destDir);
|
|
1499
1511
|
mkdirSync4(destRoot, { recursive: true });
|
|
1500
1512
|
const name = basename3(item.path);
|
|
1501
1513
|
let destPath = join3(destRoot, name);
|
|
1502
|
-
if (
|
|
1514
|
+
if (existsSync3(destPath)) {
|
|
1503
1515
|
destPath = join3(destRoot, `${exportStamp()}-${name}`);
|
|
1504
1516
|
}
|
|
1505
1517
|
renameSync(item.path, destPath);
|
|
@@ -1527,13 +1539,13 @@ function archiveIndexPath() {
|
|
|
1527
1539
|
}
|
|
1528
1540
|
function archiveLatestHandoffPath() {
|
|
1529
1541
|
const p = join3(ensureExportsLayout(), "latest", "handoff.md");
|
|
1530
|
-
return
|
|
1542
|
+
return existsSync3(p) ? p : null;
|
|
1531
1543
|
}
|
|
1532
1544
|
function inboxLatestHandoffPath() {
|
|
1533
1545
|
const inbox = getAiInboxDir();
|
|
1534
1546
|
if (!inbox) return null;
|
|
1535
1547
|
const p = join3(inbox, "latest-handoff.md");
|
|
1536
|
-
return
|
|
1548
|
+
return existsSync3(p) ? p : null;
|
|
1537
1549
|
}
|
|
1538
1550
|
function formatExportLocationLines(event) {
|
|
1539
1551
|
const lines = [`Archive: ${event.path}`];
|
|
@@ -1575,10 +1587,10 @@ This archive stores handoffs, reports, notes, CSV receipts, and publish packages
|
|
|
1575
1587
|
Set a dedicated inbox for desktop AI instead of this folder:
|
|
1576
1588
|
|
|
1577
1589
|
\`\`\`
|
|
1578
|
-
/inbox set ~/Documents/
|
|
1590
|
+
/inbox set ~/Documents/ntrp-inbox
|
|
1579
1591
|
\`\`\`
|
|
1580
1592
|
|
|
1581
|
-
After \`/inbox set\` or the optional \`/onboard\` step, paste \`latest/SKILL.md\` once into
|
|
1593
|
+
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.
|
|
1582
1594
|
`;
|
|
1583
1595
|
}
|
|
1584
1596
|
});
|
|
@@ -1808,7 +1820,7 @@ __export(transcript_exports, {
|
|
|
1808
1820
|
startSessionTranscript: () => startSessionTranscript,
|
|
1809
1821
|
stopSessionTranscript: () => stopSessionTranscript
|
|
1810
1822
|
});
|
|
1811
|
-
import { existsSync as
|
|
1823
|
+
import { existsSync as existsSync4, readFileSync as readFileSync3, writeFileSync as writeFileSync5, rmSync as rmSync2 } from "fs";
|
|
1812
1824
|
import { join as join4 } from "path";
|
|
1813
1825
|
function startSessionTranscript(ctx) {
|
|
1814
1826
|
if (ctx.oneShot || state) return;
|
|
@@ -1819,7 +1831,7 @@ function startSessionTranscript(ctx) {
|
|
|
1819
1831
|
function rebindSessionTranscript(ctx) {
|
|
1820
1832
|
if (!state || state.sessionId === ctx.sessionId) return;
|
|
1821
1833
|
const priorJson = join4(getSessionsDir(), `${state.sessionId}.json`);
|
|
1822
|
-
if (
|
|
1834
|
+
if (existsSync4(priorJson)) {
|
|
1823
1835
|
finalizeCurrentFile("switched session");
|
|
1824
1836
|
} else {
|
|
1825
1837
|
discardSessionTranscript(state.sessionId);
|
|
@@ -1893,7 +1905,7 @@ function removeTees() {
|
|
|
1893
1905
|
function createState(sessionId) {
|
|
1894
1906
|
const filePath = transcriptPathForSession(sessionId);
|
|
1895
1907
|
let base = "";
|
|
1896
|
-
if (
|
|
1908
|
+
if (existsSync4(filePath)) {
|
|
1897
1909
|
try {
|
|
1898
1910
|
base = readFileSync3(filePath, "utf-8").trimEnd() + "\n";
|
|
1899
1911
|
} catch {
|
|
@@ -2012,12 +2024,12 @@ __export(connection_exports, {
|
|
|
2012
2024
|
run: () => run,
|
|
2013
2025
|
setActiveDbPath: () => setActiveDbPath
|
|
2014
2026
|
});
|
|
2015
|
-
import { mkdirSync as mkdirSync5, existsSync as
|
|
2027
|
+
import { mkdirSync as mkdirSync5, existsSync as existsSync5, rmSync as rmSync3 } from "fs";
|
|
2016
2028
|
import { dirname as dirname3, join as join5, resolve as resolve4 } from "path";
|
|
2017
2029
|
function ensureDir2() {
|
|
2018
2030
|
secureNtrpHome();
|
|
2019
2031
|
const dir = dirname3(activeDbPath);
|
|
2020
|
-
if (!
|
|
2032
|
+
if (!existsSync5(dir)) {
|
|
2021
2033
|
mkdirSync5(dir, { recursive: true, mode: 448 });
|
|
2022
2034
|
}
|
|
2023
2035
|
}
|
|
@@ -3285,14 +3297,14 @@ CREATE INDEX IF NOT EXISTS idx_health_readings_batch ON health_readings(upload_b
|
|
|
3285
3297
|
|
|
3286
3298
|
// src/config/install.ts
|
|
3287
3299
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
3288
|
-
import { existsSync as
|
|
3300
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync6, readFileSync as readFileSync4, unlinkSync, writeFileSync as writeFileSync6 } from "fs";
|
|
3289
3301
|
import { join as join6 } from "path";
|
|
3290
3302
|
function installPath() {
|
|
3291
3303
|
return join6(ntrpHome(), "install.json");
|
|
3292
3304
|
}
|
|
3293
3305
|
function ensureDir3() {
|
|
3294
3306
|
const dir = ntrpHome();
|
|
3295
|
-
if (!
|
|
3307
|
+
if (!existsSync6(dir)) {
|
|
3296
3308
|
mkdirSync6(dir, { recursive: true });
|
|
3297
3309
|
}
|
|
3298
3310
|
}
|
|
@@ -3304,7 +3316,7 @@ function isValidInstall(value) {
|
|
|
3304
3316
|
function ensureInstall() {
|
|
3305
3317
|
if (cachedInstall) return cachedInstall;
|
|
3306
3318
|
const path = installPath();
|
|
3307
|
-
if (
|
|
3319
|
+
if (existsSync6(path)) {
|
|
3308
3320
|
try {
|
|
3309
3321
|
const parsed = JSON.parse(readFileSync4(path, "utf-8"));
|
|
3310
3322
|
if (isValidInstall(parsed)) {
|
|
@@ -3340,7 +3352,7 @@ var init_install = __esm({
|
|
|
3340
3352
|
});
|
|
3341
3353
|
|
|
3342
3354
|
// src/config/progress-migrate.ts
|
|
3343
|
-
import { existsSync as
|
|
3355
|
+
import { existsSync as existsSync7, readFileSync as readFileSync5, renameSync as renameSync2, writeFileSync as writeFileSync7 } from "fs";
|
|
3344
3356
|
import { join as join7 } from "path";
|
|
3345
3357
|
function legacyStatePath() {
|
|
3346
3358
|
return join7(ntrpHome(), "state.json");
|
|
@@ -3357,9 +3369,9 @@ function isValidLegacyState(value) {
|
|
|
3357
3369
|
return s.schema_version === 1 && typeof s.total_minutes_saved === "number" && Array.isArray(s.credits) && Array.isArray(s.milestones_unlocked);
|
|
3358
3370
|
}
|
|
3359
3371
|
function migrateLegacyStateIfNeeded(installId) {
|
|
3360
|
-
if (
|
|
3372
|
+
if (existsSync7(progressPath())) return null;
|
|
3361
3373
|
const legacyPath = legacyStatePath();
|
|
3362
|
-
if (!
|
|
3374
|
+
if (!existsSync7(legacyPath)) return null;
|
|
3363
3375
|
try {
|
|
3364
3376
|
const parsed = JSON.parse(readFileSync5(legacyPath, "utf-8"));
|
|
3365
3377
|
if (!isValidLegacyState(parsed)) return null;
|
|
@@ -3476,7 +3488,7 @@ var init_usage_backfill = __esm({
|
|
|
3476
3488
|
});
|
|
3477
3489
|
|
|
3478
3490
|
// src/config/progress.ts
|
|
3479
|
-
import { existsSync as
|
|
3491
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync7, readFileSync as readFileSync6, unlinkSync as unlinkSync2, writeFileSync as writeFileSync8 } from "fs";
|
|
3480
3492
|
import { join as join8 } from "path";
|
|
3481
3493
|
function progressPath2() {
|
|
3482
3494
|
return join8(ntrpHome(), "progress.json");
|
|
@@ -3489,7 +3501,7 @@ function legacyStateBackupPath2() {
|
|
|
3489
3501
|
}
|
|
3490
3502
|
function ensureDir4() {
|
|
3491
3503
|
const dir = ntrpHome();
|
|
3492
|
-
if (!
|
|
3504
|
+
if (!existsSync8(dir)) {
|
|
3493
3505
|
mkdirSync7(dir, { recursive: true });
|
|
3494
3506
|
}
|
|
3495
3507
|
}
|
|
@@ -3520,7 +3532,7 @@ function reconcileInstallId(state2) {
|
|
|
3520
3532
|
}
|
|
3521
3533
|
function readProgressFile() {
|
|
3522
3534
|
const path = progressPath2();
|
|
3523
|
-
if (!
|
|
3535
|
+
if (!existsSync8(path)) return { state: null, changed: false };
|
|
3524
3536
|
try {
|
|
3525
3537
|
const parsed = JSON.parse(readFileSync6(path, "utf-8"));
|
|
3526
3538
|
if (!isValidProgress(parsed)) return { state: null, changed: false };
|
|
@@ -3568,7 +3580,7 @@ function saveProgress(state2) {
|
|
|
3568
3580
|
function wipeProgressFiles() {
|
|
3569
3581
|
installMismatchWarned = false;
|
|
3570
3582
|
for (const path of [progressPath2(), legacyStatePath2(), legacyStateBackupPath2()]) {
|
|
3571
|
-
if (
|
|
3583
|
+
if (existsSync8(path)) {
|
|
3572
3584
|
unlinkSync2(path);
|
|
3573
3585
|
}
|
|
3574
3586
|
}
|
|
@@ -4283,7 +4295,7 @@ __export(providers_exports, {
|
|
|
4283
4295
|
resetProvidersCache: () => resetProvidersCache,
|
|
4284
4296
|
saveCustomProvider: () => saveCustomProvider
|
|
4285
4297
|
});
|
|
4286
|
-
import { existsSync as
|
|
4298
|
+
import { existsSync as existsSync9, readFileSync as readFileSync7 } from "fs";
|
|
4287
4299
|
import { join as join9 } from "path";
|
|
4288
4300
|
function providersPath() {
|
|
4289
4301
|
return join9(ntrpHome(), "providers.json");
|
|
@@ -4291,7 +4303,7 @@ function providersPath() {
|
|
|
4291
4303
|
function loadCustomProviders() {
|
|
4292
4304
|
if (cachedEntries) return cachedEntries;
|
|
4293
4305
|
const path = providersPath();
|
|
4294
|
-
if (!
|
|
4306
|
+
if (!existsSync9(path)) {
|
|
4295
4307
|
cachedEntries = [];
|
|
4296
4308
|
return cachedEntries;
|
|
4297
4309
|
}
|
|
@@ -5080,7 +5092,7 @@ var init_openai_compat = __esm({
|
|
|
5080
5092
|
});
|
|
5081
5093
|
|
|
5082
5094
|
// src/ai/llm/models-cache.ts
|
|
5083
|
-
import { existsSync as
|
|
5095
|
+
import { existsSync as existsSync10, readFileSync as readFileSync8, writeFileSync as writeFileSync9 } from "fs";
|
|
5084
5096
|
import { join as join10 } from "path";
|
|
5085
5097
|
function cachePath() {
|
|
5086
5098
|
return join10(ntrpHome(), "models.json");
|
|
@@ -5088,7 +5100,7 @@ function cachePath() {
|
|
|
5088
5100
|
function loadFile() {
|
|
5089
5101
|
if (cached) return cached;
|
|
5090
5102
|
const path = cachePath();
|
|
5091
|
-
if (!
|
|
5103
|
+
if (!existsSync10(path)) {
|
|
5092
5104
|
cached = { version: 1, providers: {} };
|
|
5093
5105
|
return cached;
|
|
5094
5106
|
}
|
|
@@ -5765,7 +5777,7 @@ __export(pseudonymize_exports, {
|
|
|
5765
5777
|
wipePrivacyStore: () => wipePrivacyStore
|
|
5766
5778
|
});
|
|
5767
5779
|
import { createHmac, randomBytes } from "crypto";
|
|
5768
|
-
import { existsSync as
|
|
5780
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync8, readFileSync as readFileSync10, rmSync as rmSync4, chmodSync as chmodSync2 } from "fs";
|
|
5769
5781
|
import { join as join11 } from "path";
|
|
5770
5782
|
function privacyDir() {
|
|
5771
5783
|
return join11(ntrpHome(), "privacy");
|
|
@@ -5784,7 +5796,7 @@ function chmodQuiet2(path, mode) {
|
|
|
5784
5796
|
}
|
|
5785
5797
|
function ensurePrivacyDir() {
|
|
5786
5798
|
const dir = privacyDir();
|
|
5787
|
-
if (!
|
|
5799
|
+
if (!existsSync11(dir)) {
|
|
5788
5800
|
mkdirSync8(dir, { recursive: true, mode: 448 });
|
|
5789
5801
|
}
|
|
5790
5802
|
chmodQuiet2(dir, 448);
|
|
@@ -5821,7 +5833,7 @@ function rebuildIndexes() {
|
|
|
5821
5833
|
function loadSecret() {
|
|
5822
5834
|
ensurePrivacyDir();
|
|
5823
5835
|
const path = secretPath();
|
|
5824
|
-
if (
|
|
5836
|
+
if (existsSync11(path)) {
|
|
5825
5837
|
const raw = readFileSync10(path);
|
|
5826
5838
|
const buf = raw.length >= 32 ? raw.subarray(0, 32) : Buffer.from(raw.toString("utf-8").trim(), "hex");
|
|
5827
5839
|
if (buf.length >= 16) return buf.length === 32 ? buf : Buffer.concat([buf], 32);
|
|
@@ -5835,7 +5847,7 @@ function loadLexicon() {
|
|
|
5835
5847
|
ensurePrivacyDir();
|
|
5836
5848
|
secret = loadSecret();
|
|
5837
5849
|
entries = [];
|
|
5838
|
-
if (
|
|
5850
|
+
if (existsSync11(lexiconPath())) {
|
|
5839
5851
|
try {
|
|
5840
5852
|
const parsed = JSON.parse(readFileSync10(lexiconPath(), "utf-8"));
|
|
5841
5853
|
if (parsed?.version === 1 && Array.isArray(parsed.entries)) {
|
|
@@ -6127,7 +6139,7 @@ function wipePrivacyStore() {
|
|
|
6127
6139
|
loaded = false;
|
|
6128
6140
|
dirty = false;
|
|
6129
6141
|
const dir = privacyDir();
|
|
6130
|
-
if (
|
|
6142
|
+
if (existsSync11(dir)) {
|
|
6131
6143
|
rmSync4(dir, { recursive: true, force: true });
|
|
6132
6144
|
}
|
|
6133
6145
|
}
|
|
@@ -6267,10 +6279,10 @@ var init_pseudonymize = __esm({
|
|
|
6267
6279
|
});
|
|
6268
6280
|
|
|
6269
6281
|
// src/config/profile.ts
|
|
6270
|
-
import { readFileSync as readFileSync11, writeFileSync as writeFileSync10, existsSync as
|
|
6282
|
+
import { readFileSync as readFileSync11, writeFileSync as writeFileSync10, existsSync as existsSync12, mkdirSync as mkdirSync9 } from "fs";
|
|
6271
6283
|
import { join as join12 } from "path";
|
|
6272
6284
|
function ensureDir5() {
|
|
6273
|
-
if (!
|
|
6285
|
+
if (!existsSync12(NTRP_DIR3)) {
|
|
6274
6286
|
mkdirSync9(NTRP_DIR3, { recursive: true });
|
|
6275
6287
|
}
|
|
6276
6288
|
}
|
|
@@ -6278,14 +6290,14 @@ function profilePath() {
|
|
|
6278
6290
|
return PROFILE_PATH;
|
|
6279
6291
|
}
|
|
6280
6292
|
function profileExists() {
|
|
6281
|
-
return
|
|
6293
|
+
return existsSync12(PROFILE_PATH);
|
|
6282
6294
|
}
|
|
6283
6295
|
function isProfileConfigured(profile = loadProfile()) {
|
|
6284
6296
|
if (!profile) return false;
|
|
6285
6297
|
return profile.company_name.trim().length > 0;
|
|
6286
6298
|
}
|
|
6287
6299
|
function loadProfile() {
|
|
6288
|
-
if (!
|
|
6300
|
+
if (!existsSync12(PROFILE_PATH)) return null;
|
|
6289
6301
|
try {
|
|
6290
6302
|
const parsed = JSON.parse(readFileSync11(PROFILE_PATH, "utf-8"));
|
|
6291
6303
|
if (!parsed || typeof parsed !== "object") return null;
|
|
@@ -6341,7 +6353,7 @@ __export(lexicon_seed_exports, {
|
|
|
6341
6353
|
seedOperatorIdentity: () => seedOperatorIdentity,
|
|
6342
6354
|
wipePrivacyStore: () => wipePrivacyStore2
|
|
6343
6355
|
});
|
|
6344
|
-
import { existsSync as
|
|
6356
|
+
import { existsSync as existsSync13 } from "fs";
|
|
6345
6357
|
function invalidateLexiconSeed() {
|
|
6346
6358
|
dbSeedGeneration = -1;
|
|
6347
6359
|
}
|
|
@@ -6403,7 +6415,7 @@ function seedOperatorIdentity(name, url) {
|
|
|
6403
6415
|
}
|
|
6404
6416
|
async function seedFromDuckDB() {
|
|
6405
6417
|
const dbPath = getActiveDbPath();
|
|
6406
|
-
if (!
|
|
6418
|
+
if (!existsSync13(dbPath)) return;
|
|
6407
6419
|
const { all: all2, getConnectionGeneration: getConnectionGeneration2 } = await Promise.resolve().then(() => (init_connection(), connection_exports));
|
|
6408
6420
|
const gen = getConnectionGeneration2();
|
|
6409
6421
|
if (dbSeedGeneration !== -1 && gen === dbSeedGeneration) return;
|
|
@@ -6816,7 +6828,7 @@ async function llmCompleteText(surface, system, userMessage, max_tokens, ctx) {
|
|
|
6816
6828
|
}
|
|
6817
6829
|
async function llmStreamText(surface, system, userMessage, max_tokens, ctx) {
|
|
6818
6830
|
let fullText = "";
|
|
6819
|
-
let meta = { model_used: "unknown", provider_used: "
|
|
6831
|
+
let meta = { model_used: "unknown", provider_used: "unknown", failover: false };
|
|
6820
6832
|
for await (const event of streamWithFailover(
|
|
6821
6833
|
{
|
|
6822
6834
|
surface,
|
|
@@ -7120,7 +7132,7 @@ var init_errors2 = __esm({
|
|
|
7120
7132
|
|
|
7121
7133
|
// src/strategies/readers.ts
|
|
7122
7134
|
import { createHash } from "crypto";
|
|
7123
|
-
import { existsSync as
|
|
7135
|
+
import { existsSync as existsSync14, readFileSync as readFileSync12 } from "fs";
|
|
7124
7136
|
import { extname, resolve as resolve5 } from "path";
|
|
7125
7137
|
import { parse as parseYaml } from "yaml";
|
|
7126
7138
|
import { PDFParse } from "pdf-parse";
|
|
@@ -7130,7 +7142,7 @@ async function readStrategyFile(pathOrDash) {
|
|
|
7130
7142
|
return createDocument("stdin", null, text2, {});
|
|
7131
7143
|
}
|
|
7132
7144
|
const sourcePath = resolve5(pathOrDash);
|
|
7133
|
-
if (!
|
|
7145
|
+
if (!existsSync14(sourcePath)) {
|
|
7134
7146
|
throw new NtrpError("strategy_file_not_found", `Strategy file not found: ${pathOrDash}`, 2 /* Usage */);
|
|
7135
7147
|
}
|
|
7136
7148
|
const ext = extname(sourcePath).toLowerCase();
|
|
@@ -7199,7 +7211,7 @@ var init_readers = __esm({
|
|
|
7199
7211
|
});
|
|
7200
7212
|
|
|
7201
7213
|
// src/memory/knowledge.ts
|
|
7202
|
-
import { existsSync as
|
|
7214
|
+
import { existsSync as existsSync15, readFileSync as readFileSync13, appendFileSync as appendFileSync2, readdirSync as readdirSync2 } from "fs";
|
|
7203
7215
|
import { join as join13 } from "path";
|
|
7204
7216
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
7205
7217
|
function knowledgePath() {
|
|
@@ -7207,7 +7219,7 @@ function knowledgePath() {
|
|
|
7207
7219
|
}
|
|
7208
7220
|
function loadKnowledgeChunks() {
|
|
7209
7221
|
const path = knowledgePath();
|
|
7210
|
-
if (!
|
|
7222
|
+
if (!existsSync15(path)) return [];
|
|
7211
7223
|
const out = [];
|
|
7212
7224
|
for (const line of readFileSync13(path, "utf-8").split("\n")) {
|
|
7213
7225
|
const trimmed = line.trim();
|
|
@@ -7298,7 +7310,7 @@ var init_knowledge = __esm({
|
|
|
7298
7310
|
});
|
|
7299
7311
|
|
|
7300
7312
|
// src/ai/privacy.ts
|
|
7301
|
-
import { existsSync as
|
|
7313
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync10, appendFileSync as appendFileSync3 } from "fs";
|
|
7302
7314
|
import { homedir as homedir4 } from "os";
|
|
7303
7315
|
import { join as join14 } from "path";
|
|
7304
7316
|
function scrubSensitiveText(text) {
|
|
@@ -7319,7 +7331,7 @@ function stripPII(obj) {
|
|
|
7319
7331
|
return out;
|
|
7320
7332
|
}
|
|
7321
7333
|
function ensureAuditDir() {
|
|
7322
|
-
if (!
|
|
7334
|
+
if (!existsSync16(AUDIT_DIR)) {
|
|
7323
7335
|
mkdirSync10(AUDIT_DIR, { recursive: true });
|
|
7324
7336
|
}
|
|
7325
7337
|
}
|
|
@@ -7435,14 +7447,14 @@ __export(playbook_exports, {
|
|
|
7435
7447
|
matchTriggeredPlays: () => matchTriggeredPlays,
|
|
7436
7448
|
withKnownRecommendedPlays: () => withKnownRecommendedPlays
|
|
7437
7449
|
});
|
|
7438
|
-
import { existsSync as
|
|
7450
|
+
import { existsSync as existsSync17, readFileSync as readFileSync14, appendFileSync as appendFileSync4 } from "fs";
|
|
7439
7451
|
import { join as join15 } from "path";
|
|
7440
7452
|
function playsPath() {
|
|
7441
7453
|
return join15(getMemoryDir(), PLAYS_FILE);
|
|
7442
7454
|
}
|
|
7443
7455
|
function getCustomPlays() {
|
|
7444
7456
|
const path = playsPath();
|
|
7445
|
-
if (!
|
|
7457
|
+
if (!existsSync17(path)) return [];
|
|
7446
7458
|
const out = [];
|
|
7447
7459
|
for (const line of readFileSync14(path, "utf-8").split("\n")) {
|
|
7448
7460
|
const trimmed = line.trim();
|
|
@@ -8330,7 +8342,7 @@ __export(store_exports2, {
|
|
|
8330
8342
|
rewriteJsonl: () => rewriteJsonl,
|
|
8331
8343
|
scrubText: () => scrubText
|
|
8332
8344
|
});
|
|
8333
|
-
import { existsSync as
|
|
8345
|
+
import { existsSync as existsSync18, readFileSync as readFileSync15, appendFileSync as appendFileSync5, readdirSync as readdirSync4, writeFileSync as writeFileSync12 } from "fs";
|
|
8334
8346
|
import { join as join18 } from "path";
|
|
8335
8347
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
8336
8348
|
function memPath(file) {
|
|
@@ -8338,7 +8350,7 @@ function memPath(file) {
|
|
|
8338
8350
|
}
|
|
8339
8351
|
function readJsonl(file) {
|
|
8340
8352
|
const path = memPath(file);
|
|
8341
|
-
if (!
|
|
8353
|
+
if (!existsSync18(path)) return [];
|
|
8342
8354
|
const out = [];
|
|
8343
8355
|
for (const line of readFileSync15(path, "utf-8").split("\n")) {
|
|
8344
8356
|
const trimmed = line.trim();
|
|
@@ -8717,7 +8729,7 @@ __export(context_exports, {
|
|
|
8717
8729
|
transcriptPathForSession: () => transcriptPathForSession
|
|
8718
8730
|
});
|
|
8719
8731
|
import { basename as basename5, join as join19, resolve as resolve7, sep as sep4 } from "path";
|
|
8720
|
-
import { existsSync as
|
|
8732
|
+
import { existsSync as existsSync19, mkdirSync as mkdirSync11, writeFileSync as writeFileSync13, readFileSync as readFileSync16, readdirSync as readdirSync5, statSync as statSync3, rmSync as rmSync5 } from "fs";
|
|
8721
8733
|
import { homedir as homedir6 } from "os";
|
|
8722
8734
|
import { randomUUID as randomUUID6 } from "crypto";
|
|
8723
8735
|
function isSessionStale(s) {
|
|
@@ -8736,14 +8748,14 @@ function ntrpHomeDir() {
|
|
|
8736
8748
|
}
|
|
8737
8749
|
function getSessionsDir() {
|
|
8738
8750
|
const dir = join19(ntrpHomeDir(), "sessions");
|
|
8739
|
-
if (!
|
|
8751
|
+
if (!existsSync19(dir)) {
|
|
8740
8752
|
mkdirSync11(dir, { recursive: true });
|
|
8741
8753
|
}
|
|
8742
8754
|
return dir;
|
|
8743
8755
|
}
|
|
8744
8756
|
function getDatasetsDir() {
|
|
8745
8757
|
const dir = join19(ntrpHomeDir(), "datasets");
|
|
8746
|
-
if (!
|
|
8758
|
+
if (!existsSync19(dir)) {
|
|
8747
8759
|
mkdirSync11(dir, { recursive: true });
|
|
8748
8760
|
}
|
|
8749
8761
|
return dir;
|
|
@@ -9754,7 +9766,7 @@ var init_admin_confirm = __esm({
|
|
|
9754
9766
|
});
|
|
9755
9767
|
|
|
9756
9768
|
// src/services/scratch-wipe.ts
|
|
9757
|
-
import { existsSync as
|
|
9769
|
+
import { existsSync as existsSync20, rmSync as rmSync6, unlinkSync as unlinkSync3 } from "fs";
|
|
9758
9770
|
import { join as join20 } from "path";
|
|
9759
9771
|
async function performScratchWipe(opts = {}) {
|
|
9760
9772
|
const home = ntrpHome();
|
|
@@ -9784,7 +9796,7 @@ async function performScratchWipe(opts = {}) {
|
|
|
9784
9796
|
);
|
|
9785
9797
|
}
|
|
9786
9798
|
for (const { path, kind } of targets) {
|
|
9787
|
-
if (!
|
|
9799
|
+
if (!existsSync20(path)) continue;
|
|
9788
9800
|
try {
|
|
9789
9801
|
if (kind === "dir") {
|
|
9790
9802
|
rmSync6(path, { recursive: true, force: true });
|
|
@@ -12336,11 +12348,11 @@ var init_guide_slides = __esm({
|
|
|
12336
12348
|
};
|
|
12337
12349
|
HANDOFF = {
|
|
12338
12350
|
id: "handoff",
|
|
12339
|
-
label: "Ship work to
|
|
12340
|
-
tagline: "Teach the inbox once. Later, tell
|
|
12351
|
+
label: "Ship work to your AI",
|
|
12352
|
+
tagline: "Teach the inbox once. Later, tell your AI to pick it up.",
|
|
12341
12353
|
visual: {
|
|
12342
12354
|
kind: "layer_stack",
|
|
12343
|
-
caption: "You and
|
|
12355
|
+
caption: "You and your AI find and open the file. NTRP only writes.",
|
|
12344
12356
|
layers: [
|
|
12345
12357
|
{ label: "Set a pickup folder (demo, onboard, or /inbox set)" },
|
|
12346
12358
|
{ label: "Paste the finder skill once (/inbox skill)", highlight: true },
|
|
@@ -12349,18 +12361,18 @@ var init_guide_slides = __esm({
|
|
|
12349
12361
|
]
|
|
12350
12362
|
},
|
|
12351
12363
|
lines: [
|
|
12352
|
-
'Type "ship a board deck" or type /handoff. Files land in ~/Documents/
|
|
12364
|
+
'Type "ship a board deck" or type /handoff. Files land in ~/Documents/ntrp-inbox by default. Type /inbox set to change the folder.',
|
|
12353
12365
|
"",
|
|
12354
|
-
"During demo or company setup, or any time, type /inbox skill. Paste a standing finder into Claude, ChatGPT, or
|
|
12366
|
+
"During demo or company setup, or any time, type /inbox skill. Paste a standing finder into Claude, ChatGPT, Cursor, or another desktop AI once. That skill tells the tool to follow latest-handoff.md and INDEX.md.",
|
|
12355
12367
|
"",
|
|
12356
|
-
'After that, each /handoff prints "Handoff ready". You will not get a paste block every write. Tell
|
|
12368
|
+
'After that, each /handoff prints "Handoff ready". You will not get a paste block every write. Tell your AI: pick up the latest NTRP handoff.',
|
|
12357
12369
|
"",
|
|
12358
|
-
"If you skipped this step, NTRP asks once when you load your own data. Skip then, and type /inbox set ~/Documents/
|
|
12370
|
+
"If you skipped this step, NTRP asks once when you load your own data. Skip then, and type /inbox set ~/Documents/ntrp-inbox. Then type /inbox skill. Type /handoff skill to reprint the same finder."
|
|
12359
12371
|
],
|
|
12360
12372
|
deepdive: [
|
|
12361
12373
|
"Inbox copies: latest-handoff.md, latest-pickup.md, SKILL.md, INDEX.md. Dated files also live under ~/.ntrp/exports/.",
|
|
12362
12374
|
"Type /exports to list writes. Type /inbox show to print the folder and the latest pointer. Type /handoff --print to show the prompt body in the terminal.",
|
|
12363
|
-
"Audience-framed Metric definitions append to decks and reports.
|
|
12375
|
+
"Audience-framed Metric definitions append to decks and reports. Your AI then has the same glossary you walked.",
|
|
12364
12376
|
"Type /end to close a session. NTRP writes a transcript plus a 1-page context brief under ~/.ntrp/sessions/."
|
|
12365
12377
|
]
|
|
12366
12378
|
};
|
|
@@ -12556,7 +12568,7 @@ function paintIntro(opts) {
|
|
|
12556
12568
|
"",
|
|
12557
12569
|
"Vital signs (after) \u2014 Freshness, Flow Rate, Drop Rate, Signal:Noise, Thread Depth \u2014 NTRP's own ontology. Each has a dollar translation. Scores gate in layer order: first red wins.",
|
|
12558
12570
|
"",
|
|
12559
|
-
"How to use NTRP (after vitals) \u2014 talk in English, ask without a key, ship a handoff to
|
|
12571
|
+
"How to use NTRP (after vitals) \u2014 talk in English, ask without a key, ship a handoff to your AI once, stay in the diagnose \u2192 plan loop.",
|
|
12560
12572
|
"",
|
|
12561
12573
|
chalk10.dim("No AI key needed for this tour. Press Enter to advance; type /deepdive (or d) on any slide for more.")
|
|
12562
12574
|
],
|
|
@@ -12576,7 +12588,7 @@ function paintClose(opts) {
|
|
|
12576
12588
|
` ${paint("accent", "/diagnose")} \u2014 five vital signs + dollars at risk`,
|
|
12577
12589
|
` ${paint("accent", "/metrics")} \u2014 SaaS scorecard (ARR, NRR, coverage\u2026)`,
|
|
12578
12590
|
` ${paint("accent", "/deepdive")} \u2014 replay this tour \xB7 ${paint("accent", "/deepdive guide")} how-to only`,
|
|
12579
|
-
` ${paint("accent", "/handoff")} \u2014 ship a file; teach
|
|
12591
|
+
` ${paint("accent", "/handoff")} \u2014 ship a file; teach the inbox once (/inbox skill)`,
|
|
12580
12592
|
` ${paint("accent", "/strategy")} \u2014 measurable plan \xB7 ${paint("accent", "/help")} shortcuts`,
|
|
12581
12593
|
"",
|
|
12582
12594
|
"Fourteen more SaaS metrics live behind /deepdive list \u2014 including unit economics that unlock when spend data lands.",
|
|
@@ -12744,7 +12756,7 @@ async function offerFirstRunTour(ctx) {
|
|
|
12744
12756
|
console.log();
|
|
12745
12757
|
console.log(" " + bold("Onboarding tour") + chalk10.dim(" \u2014 ~3 minutes, no AI key required"));
|
|
12746
12758
|
console.log(
|
|
12747
|
-
" " + chalk10.dim("SaaS numbers, five vitals, then how to talk to NTRP and ship work to
|
|
12759
|
+
" " + chalk10.dim("SaaS numbers, five vitals, then how to talk to NTRP and ship work to your AI.")
|
|
12748
12760
|
);
|
|
12749
12761
|
const tourDefault = firstRunTourDefaultChoice();
|
|
12750
12762
|
if (tourDefault === "skip") {
|
|
@@ -16237,7 +16249,7 @@ __export(play_outcomes_exports, {
|
|
|
16237
16249
|
listPlayOutcomes: () => listPlayOutcomes,
|
|
16238
16250
|
recordPlayOutcomes: () => recordPlayOutcomes
|
|
16239
16251
|
});
|
|
16240
|
-
import { existsSync as
|
|
16252
|
+
import { existsSync as existsSync21, readFileSync as readFileSync17, appendFileSync as appendFileSync6 } from "fs";
|
|
16241
16253
|
import { join as join21 } from "path";
|
|
16242
16254
|
import { randomUUID as randomUUID7 } from "crypto";
|
|
16243
16255
|
function outcomesPath() {
|
|
@@ -16245,7 +16257,7 @@ function outcomesPath() {
|
|
|
16245
16257
|
}
|
|
16246
16258
|
function listPlayOutcomes() {
|
|
16247
16259
|
const path = outcomesPath();
|
|
16248
|
-
if (!
|
|
16260
|
+
if (!existsSync21(path)) return [];
|
|
16249
16261
|
const out = [];
|
|
16250
16262
|
for (const line of readFileSync17(path, "utf-8").split("\n")) {
|
|
16251
16263
|
const trimmed = line.trim();
|
|
@@ -19238,7 +19250,7 @@ var init_markdown = __esm({
|
|
|
19238
19250
|
import chalk16 from "chalk";
|
|
19239
19251
|
function formatLlmAttribution(meta) {
|
|
19240
19252
|
if (!meta.model_used) return null;
|
|
19241
|
-
const provider = meta.provider_used ?? "
|
|
19253
|
+
const provider = meta.provider_used ?? "unknown";
|
|
19242
19254
|
let line = `via ${formatModelLabel(provider, meta.model_used)}`;
|
|
19243
19255
|
if (meta.failover) {
|
|
19244
19256
|
line += " (auto-failover)";
|
|
@@ -19714,16 +19726,16 @@ var init_terminal = __esm({
|
|
|
19714
19726
|
});
|
|
19715
19727
|
|
|
19716
19728
|
// src/demo/taxonomy-cache.ts
|
|
19717
|
-
import { readFileSync as readFileSync18, writeFileSync as writeFileSync14, existsSync as
|
|
19729
|
+
import { readFileSync as readFileSync18, writeFileSync as writeFileSync14, existsSync as existsSync22, mkdirSync as mkdirSync12, unlinkSync as unlinkSync4 } from "fs";
|
|
19718
19730
|
import { homedir as homedir7 } from "os";
|
|
19719
19731
|
import { join as join22 } from "path";
|
|
19720
19732
|
function ensureDir6() {
|
|
19721
|
-
if (!
|
|
19733
|
+
if (!existsSync22(NTRP_DIR4)) {
|
|
19722
19734
|
mkdirSync12(NTRP_DIR4, { recursive: true });
|
|
19723
19735
|
}
|
|
19724
19736
|
}
|
|
19725
19737
|
function loadCachedTaxonomy(profile) {
|
|
19726
|
-
if (!
|
|
19738
|
+
if (!existsSync22(TAXONOMY_PATH)) return null;
|
|
19727
19739
|
try {
|
|
19728
19740
|
const parsed = JSON.parse(readFileSync18(TAXONOMY_PATH, "utf-8"));
|
|
19729
19741
|
if (!parsed || typeof parsed !== "object") return null;
|
|
@@ -19738,7 +19750,7 @@ function saveCachedTaxonomy(taxonomy) {
|
|
|
19738
19750
|
writeFileSync14(TAXONOMY_PATH, JSON.stringify(taxonomy, null, 2) + "\n");
|
|
19739
19751
|
}
|
|
19740
19752
|
function invalidateTaxonomy() {
|
|
19741
|
-
if (
|
|
19753
|
+
if (existsSync22(TAXONOMY_PATH)) {
|
|
19742
19754
|
try {
|
|
19743
19755
|
unlinkSync4(TAXONOMY_PATH);
|
|
19744
19756
|
} catch {
|
|
@@ -20208,7 +20220,7 @@ __export(inbox_setup_exports, {
|
|
|
20208
20220
|
shouldOfferInboxSkillSetup: () => shouldOfferInboxSkillSetup
|
|
20209
20221
|
});
|
|
20210
20222
|
import chalk19 from "chalk";
|
|
20211
|
-
import { existsSync as
|
|
20223
|
+
import { existsSync as existsSync23 } from "fs";
|
|
20212
20224
|
function markDemoOffered() {
|
|
20213
20225
|
setConfigValue("ai-inbox-nudge-seen", "true");
|
|
20214
20226
|
}
|
|
@@ -20225,7 +20237,7 @@ function shouldOfferInboxSkillSetup(beat) {
|
|
|
20225
20237
|
return !hasProductionOffered();
|
|
20226
20238
|
}
|
|
20227
20239
|
function printSkipHint(beat) {
|
|
20228
|
-
const setCmd = paint("accent",
|
|
20240
|
+
const setCmd = paint("accent", `/inbox set ${defaultAiInboxDirDisplay()}`);
|
|
20229
20241
|
const skillCmd = paint("accent", "/inbox skill");
|
|
20230
20242
|
if (beat === "demo") {
|
|
20231
20243
|
console.log(
|
|
@@ -20237,13 +20249,15 @@ function printSkipHint(beat) {
|
|
|
20237
20249
|
" " + chalk19.dim("Skipped. NTRP will not ask again. Type ") + setCmd + chalk19.dim(" then ") + skillCmd + chalk19.dim(" at any time.")
|
|
20238
20250
|
);
|
|
20239
20251
|
}
|
|
20240
|
-
async function reuseInboxFolderIfPresent(session, beat, folderPath
|
|
20252
|
+
async function reuseInboxFolderIfPresent(session, beat, folderPath) {
|
|
20241
20253
|
if (getAiInboxDir()) return false;
|
|
20242
|
-
|
|
20243
|
-
|
|
20254
|
+
const candidates = folderPath ? [folderPath] : [.../* @__PURE__ */ new Set([defaultAiInboxDir(), legacyAiInboxDir()])];
|
|
20255
|
+
const existing = candidates.find((p) => existsSync23(p));
|
|
20256
|
+
if (!existing) return false;
|
|
20257
|
+
console.log(" " + chalk19.dim("Pickup folder still on disk: ") + existing);
|
|
20244
20258
|
const reuse = await session.confirm("Reuse this pickup folder?", true);
|
|
20245
20259
|
if (!reuse) return false;
|
|
20246
|
-
const resolved = setAiInboxDir(
|
|
20260
|
+
const resolved = setAiInboxDir(existing);
|
|
20247
20261
|
markDemoOffered();
|
|
20248
20262
|
if (beat === "production") markProductionOffered();
|
|
20249
20263
|
console.log();
|
|
@@ -20258,7 +20272,7 @@ async function offerInboxSkillSetup(session, opts = {}) {
|
|
|
20258
20272
|
const beat = opts.beat ?? "production";
|
|
20259
20273
|
if (!shouldOfferInboxSkillSetup(beat)) return;
|
|
20260
20274
|
console.log();
|
|
20261
|
-
console.log(" " + bold("Teach
|
|
20275
|
+
console.log(" " + bold("Teach your AI where handoffs live"));
|
|
20262
20276
|
console.log(
|
|
20263
20277
|
" " + chalk19.dim(
|
|
20264
20278
|
"Optional. NTRP copies every handoff into one folder. You paste instructions once; later /handoff just writes the file."
|
|
@@ -20269,7 +20283,10 @@ async function offerInboxSkillSetup(session, opts = {}) {
|
|
|
20269
20283
|
}
|
|
20270
20284
|
console.log();
|
|
20271
20285
|
if (await reuseInboxFolderIfPresent(session, beat)) return;
|
|
20272
|
-
const want = await session.confirm(
|
|
20286
|
+
const want = await session.confirm(
|
|
20287
|
+
"Set a pickup folder for Claude, ChatGPT, Cursor, or another desktop AI?",
|
|
20288
|
+
true
|
|
20289
|
+
);
|
|
20273
20290
|
if (!want) {
|
|
20274
20291
|
if (beat === "demo") markDemoOffered();
|
|
20275
20292
|
else markProductionOffered();
|
|
@@ -20301,10 +20318,12 @@ async function offerInboxSkillSetup(session, opts = {}) {
|
|
|
20301
20318
|
console.log(" " + chalk19.dim(`Synced ${n} recent export${n === 1 ? "" : "s"}.`));
|
|
20302
20319
|
}
|
|
20303
20320
|
console.log(
|
|
20304
|
-
" " + chalk19.dim(
|
|
20321
|
+
" " + chalk19.dim(
|
|
20322
|
+
"Paste this skill into your desktop AI once. Later, tell it to open the latest NTRP handoff."
|
|
20323
|
+
)
|
|
20305
20324
|
);
|
|
20306
20325
|
printStandingSkill();
|
|
20307
|
-
await session.askPressEnter("Paste the skill into
|
|
20326
|
+
await session.askPressEnter("Paste the skill into your AI. Then continue");
|
|
20308
20327
|
console.log(" " + chalk19.dim("Done. Later handoffs write to that folder. The skill is not printed again."));
|
|
20309
20328
|
console.log();
|
|
20310
20329
|
}
|
|
@@ -20339,7 +20358,7 @@ __export(ingest_exports, {
|
|
|
20339
20358
|
handler: () => handler2
|
|
20340
20359
|
});
|
|
20341
20360
|
import chalk20 from "chalk";
|
|
20342
|
-
import { readFileSync as readFileSync19, existsSync as
|
|
20361
|
+
import { readFileSync as readFileSync19, existsSync as existsSync24 } from "fs";
|
|
20343
20362
|
import { basename as basename6 } from "path";
|
|
20344
20363
|
async function handler2(args, ctx) {
|
|
20345
20364
|
const { positional, flags } = parseArgs2(args, [
|
|
@@ -20363,7 +20382,7 @@ async function handler2(args, ctx) {
|
|
|
20363
20382
|
console.error(chalk20.dim(" /ingest --demo [--scenario <name>]"));
|
|
20364
20383
|
process.exit(1);
|
|
20365
20384
|
}
|
|
20366
|
-
if (!
|
|
20385
|
+
if (!existsSync24(file)) {
|
|
20367
20386
|
console.error(chalk20.red(` File not found: ${file}`));
|
|
20368
20387
|
process.exit(1);
|
|
20369
20388
|
}
|
|
@@ -20951,7 +20970,7 @@ function buildUserMessage(input) {
|
|
|
20951
20970
|
async function* streamFindings(input, ctx) {
|
|
20952
20971
|
assertReplAi(ctx);
|
|
20953
20972
|
const userMessage = buildUserMessage(input);
|
|
20954
|
-
let meta = { model_used: "unknown", provider_used: "
|
|
20973
|
+
let meta = { model_used: "unknown", provider_used: "unknown", failover: false };
|
|
20955
20974
|
const scanner = new StreamingJsonArrayParser();
|
|
20956
20975
|
let streamed = 0;
|
|
20957
20976
|
for await (const event of streamWithFailover(
|
|
@@ -22449,9 +22468,9 @@ async function handleGetSessionBrief(input) {
|
|
|
22449
22468
|
if (!target) {
|
|
22450
22469
|
return { error: `No session matching "${raw}".` };
|
|
22451
22470
|
}
|
|
22452
|
-
const { existsSync:
|
|
22471
|
+
const { existsSync: existsSync36, readFileSync: readFileSync24 } = await import("fs");
|
|
22453
22472
|
const briefPath = contextDocPathForSession2(target.id);
|
|
22454
|
-
if (!
|
|
22473
|
+
if (!existsSync36(briefPath)) {
|
|
22455
22474
|
return {
|
|
22456
22475
|
session_id: target.id,
|
|
22457
22476
|
error: "No context brief on disk for this session (created before brief storage existed).",
|
|
@@ -23166,7 +23185,7 @@ async function* agenticFindings(computeResult, divergences, options) {
|
|
|
23166
23185
|
const priorMessages = priorRaw.length > 0 && typeof priorRaw[0] === "object" && priorRaw[0] !== null && "content" in priorRaw[0] ? normalizeThread(priorRaw) : priorRaw;
|
|
23167
23186
|
const conversational = mode === "fresh" || mode === "think";
|
|
23168
23187
|
const messages = conversational && priorMessages.length > 0 && options.userQuestion ? [...priorMessages, { role: "user", content: options.userQuestion }] : [{ role: "user", content: initialContext }];
|
|
23169
|
-
let lastMeta = { provider_used: "
|
|
23188
|
+
let lastMeta = { provider_used: "unknown", model_used: "unknown" };
|
|
23170
23189
|
const loopGuard = new ToolLoopGuard();
|
|
23171
23190
|
const allowedTools = new Set(tools.map((t) => t.name));
|
|
23172
23191
|
async function callLlm(msgs, tokens, withTools) {
|
|
@@ -25132,7 +25151,7 @@ __export(new_exports, {
|
|
|
25132
25151
|
handler: () => handler6
|
|
25133
25152
|
});
|
|
25134
25153
|
import chalk26 from "chalk";
|
|
25135
|
-
import { existsSync as
|
|
25154
|
+
import { existsSync as existsSync25 } from "fs";
|
|
25136
25155
|
import { basename as basename7 } from "path";
|
|
25137
25156
|
async function handler6(args, ctx) {
|
|
25138
25157
|
const { positional, flags } = parseArgs2(args, ["demo", "empty", "list-scenarios", "regen-taxonomy"]);
|
|
@@ -25154,7 +25173,7 @@ async function handler6(args, ctx) {
|
|
|
25154
25173
|
console.error(chalk26.red(" Usage: /new <file.csv> | --demo [--scenario <name>] | --empty [--lens health|metrics]"));
|
|
25155
25174
|
return;
|
|
25156
25175
|
}
|
|
25157
|
-
if (source.kind === "file" && !
|
|
25176
|
+
if (source.kind === "file" && !existsSync25(source.path)) {
|
|
25158
25177
|
console.error(chalk26.red(` File not found: ${source.path}`));
|
|
25159
25178
|
return;
|
|
25160
25179
|
}
|
|
@@ -25381,7 +25400,7 @@ __export(end_exports, {
|
|
|
25381
25400
|
handler: () => handler7
|
|
25382
25401
|
});
|
|
25383
25402
|
import chalk27 from "chalk";
|
|
25384
|
-
import { existsSync as
|
|
25403
|
+
import { existsSync as existsSync26 } from "fs";
|
|
25385
25404
|
async function handler7(args, ctx) {
|
|
25386
25405
|
if (args.length > 0) {
|
|
25387
25406
|
console.error(chalk27.red(" Usage: /end"));
|
|
@@ -25418,10 +25437,10 @@ async function handler7(args, ctx) {
|
|
|
25418
25437
|
if (summary) {
|
|
25419
25438
|
console.log(" " + chalk27.dim(summary));
|
|
25420
25439
|
}
|
|
25421
|
-
if (
|
|
25440
|
+
if (existsSync26(transcriptPathForSession(endedId))) {
|
|
25422
25441
|
console.log(" " + chalk27.dim("Transcript: ") + chalk27.dim(transcriptPathForSession(endedId)));
|
|
25423
25442
|
}
|
|
25424
|
-
if (
|
|
25443
|
+
if (existsSync26(contextDocPathForSession(endedId))) {
|
|
25425
25444
|
console.log(" " + chalk27.dim("Context brief: ") + chalk27.dim(contextDocPathForSession(endedId)));
|
|
25426
25445
|
}
|
|
25427
25446
|
console.log();
|
|
@@ -25443,7 +25462,7 @@ __export(session_exports, {
|
|
|
25443
25462
|
});
|
|
25444
25463
|
import chalk28 from "chalk";
|
|
25445
25464
|
import { join as join23 } from "path";
|
|
25446
|
-
import { existsSync as
|
|
25465
|
+
import { existsSync as existsSync27 } from "fs";
|
|
25447
25466
|
async function handler8(args, ctx) {
|
|
25448
25467
|
const sub = args[0];
|
|
25449
25468
|
if (!sub) return listSessionsView(ctx);
|
|
@@ -25589,7 +25608,7 @@ async function pickUp(idArg, ctx) {
|
|
|
25589
25608
|
);
|
|
25590
25609
|
}
|
|
25591
25610
|
const contextPath = contextDocPathForSession(target.id);
|
|
25592
|
-
if (
|
|
25611
|
+
if (existsSync27(contextPath)) {
|
|
25593
25612
|
console.log(" " + chalk28.dim("Context brief: ") + chalk28.dim(contextPath));
|
|
25594
25613
|
}
|
|
25595
25614
|
console.log();
|
|
@@ -28799,7 +28818,7 @@ async function* strategistPlanSession(options) {
|
|
|
28799
28818
|
})
|
|
28800
28819
|
}
|
|
28801
28820
|
];
|
|
28802
|
-
let lastMeta = { provider_used: "
|
|
28821
|
+
let lastMeta = { provider_used: "unknown", model_used: "unknown" };
|
|
28803
28822
|
const loopGuard = new ToolLoopGuard();
|
|
28804
28823
|
const allowedTools = new Set(tools.map((t) => t.name));
|
|
28805
28824
|
const callLlm = async (surface, withTools, maxTokens = STAGE_MAX_TOKENS) => {
|
|
@@ -31131,7 +31150,7 @@ var init_checkout = __esm({
|
|
|
31131
31150
|
});
|
|
31132
31151
|
|
|
31133
31152
|
// src/services/setup.ts
|
|
31134
|
-
import { existsSync as
|
|
31153
|
+
import { existsSync as existsSync28, mkdirSync as mkdirSync17, readFileSync as readFileSync20, writeFileSync as writeFileSync19 } from "fs";
|
|
31135
31154
|
import { join as join29 } from "path";
|
|
31136
31155
|
function setupCheck() {
|
|
31137
31156
|
const home = ntrpHome();
|
|
@@ -31834,7 +31853,7 @@ async function handleDeliverFlow(input, ctx) {
|
|
|
31834
31853
|
}
|
|
31835
31854
|
console.log();
|
|
31836
31855
|
console.log(" " + chalk52.bold("Deliverable preview"));
|
|
31837
|
-
console.log(" " + chalk52.dim("NTRP writes the file to your inbox after you confirm. If you set the inbox during demo or company setup,
|
|
31856
|
+
console.log(" " + chalk52.dim("NTRP writes the file to your inbox after you confirm. If you set the inbox during demo or company setup, your AI can find the folder."));
|
|
31838
31857
|
console.log(" " + chalk52.dim("\u2500".repeat(56)));
|
|
31839
31858
|
const preview = draft.markdown.split("\n").slice(0, 12);
|
|
31840
31859
|
for (const l of preview) {
|
|
@@ -33134,7 +33153,7 @@ __export(sessions_exports, {
|
|
|
33134
33153
|
handler: () => handler35
|
|
33135
33154
|
});
|
|
33136
33155
|
import chalk62 from "chalk";
|
|
33137
|
-
import { existsSync as
|
|
33156
|
+
import { existsSync as existsSync29 } from "fs";
|
|
33138
33157
|
async function handler35(args, _ctx) {
|
|
33139
33158
|
const sub = args[0] ?? "list";
|
|
33140
33159
|
if (sub === "list" || !args[0]) {
|
|
@@ -33241,12 +33260,12 @@ function showSession(idArg) {
|
|
|
33241
33260
|
console.log();
|
|
33242
33261
|
const transcriptPath = transcriptPathForSession(session.id);
|
|
33243
33262
|
const contextPath = contextDocPathForSession(session.id);
|
|
33244
|
-
if (
|
|
33263
|
+
if (existsSync29(transcriptPath) || existsSync29(contextPath)) {
|
|
33245
33264
|
console.log(" " + chalk62.dim("\u2500".repeat(40)));
|
|
33246
|
-
if (
|
|
33265
|
+
if (existsSync29(contextPath)) {
|
|
33247
33266
|
console.log(" " + chalk62.dim("Context brief: ") + chalk62.dim(contextPath));
|
|
33248
33267
|
}
|
|
33249
|
-
if (
|
|
33268
|
+
if (existsSync29(transcriptPath)) {
|
|
33250
33269
|
console.log(" " + chalk62.dim("Full transcript: ") + chalk62.dim(transcriptPath));
|
|
33251
33270
|
}
|
|
33252
33271
|
console.log();
|
|
@@ -33518,7 +33537,7 @@ var init_privacy_notice = __esm({
|
|
|
33518
33537
|
"Computed scores and dollar aggregates still go to the provider you connected.",
|
|
33519
33538
|
"If you turn on web retrieval, named-account queries are refused. Generic GTM terms may go to Tavily or Brave.",
|
|
33520
33539
|
"A custom --base-url receives the same tokenized payload.",
|
|
33521
|
-
"MCP hosts (for example Claude Desktop) see tokens, not account names. Use the CLI to read real names.",
|
|
33540
|
+
"MCP hosts (for example Claude Desktop or Cursor) see tokens, not account names. Use the CLI to read real names.",
|
|
33522
33541
|
"Keys stay in ~/.ntrp/config.json on this machine (mode 600).",
|
|
33523
33542
|
"NTRP is a diagnostic. It does not change CRM records or send email.",
|
|
33524
33543
|
"Type /privacy to read this notice again."
|
|
@@ -34582,20 +34601,20 @@ var init_model = __esm({
|
|
|
34582
34601
|
});
|
|
34583
34602
|
|
|
34584
34603
|
// src/config/update-check.ts
|
|
34585
|
-
import { existsSync as
|
|
34604
|
+
import { existsSync as existsSync30, mkdirSync as mkdirSync18, readFileSync as readFileSync21, unlinkSync as unlinkSync5, writeFileSync as writeFileSync20 } from "fs";
|
|
34586
34605
|
import { join as join33 } from "path";
|
|
34587
34606
|
function cachePath2() {
|
|
34588
34607
|
return join33(ntrpHome(), "update-check.json");
|
|
34589
34608
|
}
|
|
34590
34609
|
function ensureDir7() {
|
|
34591
34610
|
const dir = ntrpHome();
|
|
34592
|
-
if (!
|
|
34611
|
+
if (!existsSync30(dir)) {
|
|
34593
34612
|
mkdirSync18(dir, { recursive: true });
|
|
34594
34613
|
}
|
|
34595
34614
|
}
|
|
34596
34615
|
function loadUpdateCheckCache() {
|
|
34597
34616
|
const path = cachePath2();
|
|
34598
|
-
if (!
|
|
34617
|
+
if (!existsSync30(path)) return null;
|
|
34599
34618
|
try {
|
|
34600
34619
|
const parsed = JSON.parse(readFileSync21(path, "utf-8"));
|
|
34601
34620
|
if (!parsed || typeof parsed !== "object" || typeof parsed.lastCheck !== "number" || typeof parsed.latestVersion !== "string") {
|
|
@@ -34616,7 +34635,7 @@ function isCacheFresh(cache2, ttlMs = CACHE_TTL_MS2) {
|
|
|
34616
34635
|
}
|
|
34617
34636
|
function invalidateUpdateCheckCache() {
|
|
34618
34637
|
const path = cachePath2();
|
|
34619
|
-
if (
|
|
34638
|
+
if (existsSync30(path)) {
|
|
34620
34639
|
unlinkSync5(path);
|
|
34621
34640
|
}
|
|
34622
34641
|
}
|
|
@@ -34630,11 +34649,11 @@ var init_update_check = __esm({
|
|
|
34630
34649
|
});
|
|
34631
34650
|
|
|
34632
34651
|
// src/version.ts
|
|
34633
|
-
import { existsSync as
|
|
34652
|
+
import { existsSync as existsSync31, readFileSync as readFileSync22 } from "fs";
|
|
34634
34653
|
import { dirname as dirname6, join as join34 } from "path";
|
|
34635
34654
|
import { fileURLToPath } from "url";
|
|
34636
34655
|
function readVersionFromPackageJson(packageJsonPath) {
|
|
34637
|
-
if (!
|
|
34656
|
+
if (!existsSync31(packageJsonPath)) return null;
|
|
34638
34657
|
try {
|
|
34639
34658
|
const pkg = JSON.parse(readFileSync22(packageJsonPath, "utf-8"));
|
|
34640
34659
|
if (typeof pkg.version === "string" && pkg.version.length > 0) return pkg.version;
|
|
@@ -34774,7 +34793,7 @@ __export(relaunch_exports, {
|
|
|
34774
34793
|
resolveRelaunchEntry: () => resolveRelaunchEntry,
|
|
34775
34794
|
updateRestartSummary: () => updateRestartSummary
|
|
34776
34795
|
});
|
|
34777
|
-
import { existsSync as
|
|
34796
|
+
import { existsSync as existsSync32 } from "fs";
|
|
34778
34797
|
import { join as join35 } from "path";
|
|
34779
34798
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
34780
34799
|
import { spawnSync } from "child_process";
|
|
@@ -34800,7 +34819,7 @@ function npmGlobalEntry() {
|
|
|
34800
34819
|
const listed = spawnSync("npm", ["root", "-g"], { encoding: "utf-8" });
|
|
34801
34820
|
if (listed.status !== 0) return null;
|
|
34802
34821
|
const entry = join35(listed.stdout.trim(), NPM_PACKAGE, "dist/index.js");
|
|
34803
|
-
return
|
|
34822
|
+
return existsSync32(entry) ? entry : null;
|
|
34804
34823
|
}
|
|
34805
34824
|
function thisBundleEntry() {
|
|
34806
34825
|
return fileURLToPath2(import.meta.url);
|
|
@@ -34810,10 +34829,10 @@ function resolveRelaunchEntry(toVersion) {
|
|
|
34810
34829
|
(p) => Boolean(p)
|
|
34811
34830
|
);
|
|
34812
34831
|
for (const entry of candidates) {
|
|
34813
|
-
if (!
|
|
34832
|
+
if (!existsSync32(entry)) continue;
|
|
34814
34833
|
if (readVersionNearEntry(entry) === toVersion) return entry;
|
|
34815
34834
|
}
|
|
34816
|
-
return candidates.find((p) =>
|
|
34835
|
+
return candidates.find((p) => existsSync32(p)) ?? thisBundleEntry();
|
|
34817
34836
|
}
|
|
34818
34837
|
function relaunchArgv(toVersion) {
|
|
34819
34838
|
return [resolveRelaunchEntry(toVersion)];
|
|
@@ -35336,7 +35355,7 @@ __export(exports_exports, {
|
|
|
35336
35355
|
handler: () => handler48
|
|
35337
35356
|
});
|
|
35338
35357
|
import chalk78 from "chalk";
|
|
35339
|
-
import { existsSync as
|
|
35358
|
+
import { existsSync as existsSync33 } from "fs";
|
|
35340
35359
|
import { join as join36 } from "path";
|
|
35341
35360
|
function usage4() {
|
|
35342
35361
|
console.log(chalk78.dim(" Usage:"));
|
|
@@ -35448,7 +35467,7 @@ async function runInboxSet(args, ctx) {
|
|
|
35448
35467
|
const pathArg = args.join(" ").trim();
|
|
35449
35468
|
if (!pathArg) {
|
|
35450
35469
|
console.error(chalk78.red(" Usage: /inbox set <path>"));
|
|
35451
|
-
console.error(chalk78.dim(" Example: /inbox set ~/Documents/
|
|
35470
|
+
console.error(chalk78.dim(" Example: /inbox set ~/Documents/ntrp-inbox"));
|
|
35452
35471
|
if (ctx.oneShot) process.exit(1);
|
|
35453
35472
|
return;
|
|
35454
35473
|
}
|
|
@@ -35478,7 +35497,7 @@ async function runInboxSet(args, ctx) {
|
|
|
35478
35497
|
console.log();
|
|
35479
35498
|
console.log(" " + paint("accent", "AI inbox set"));
|
|
35480
35499
|
console.log(" " + chalk78.dim(setTo));
|
|
35481
|
-
console.log(" " + chalk78.dim("Point Claude
|
|
35500
|
+
console.log(" " + chalk78.dim("Point Claude, ChatGPT, Cursor, or another desktop AI at this folder."));
|
|
35482
35501
|
if (n > 0) {
|
|
35483
35502
|
console.log(" " + chalk78.dim(`Synced ${n} recent export${n === 1 ? "" : "s"} into the inbox.`));
|
|
35484
35503
|
}
|
|
@@ -35495,7 +35514,7 @@ function runMove(args, ctx) {
|
|
|
35495
35514
|
}
|
|
35496
35515
|
try {
|
|
35497
35516
|
const destDir = resolveUserPath(dest);
|
|
35498
|
-
if (!
|
|
35517
|
+
if (!existsSync33(destDir)) {
|
|
35499
35518
|
}
|
|
35500
35519
|
const event = moveExport(idOrName, destDir);
|
|
35501
35520
|
console.log();
|
|
@@ -35848,12 +35867,12 @@ args: [show|set <path>|skill|clear]
|
|
|
35848
35867
|
handler: ../commands/exports.ts
|
|
35849
35868
|
---
|
|
35850
35869
|
|
|
35851
|
-
Set a folder that
|
|
35870
|
+
Set a folder that any desktop AI can read (Claude, ChatGPT, Cursor, \u2026).
|
|
35852
35871
|
NTRP copies each handoff to that folder.
|
|
35853
35872
|
NTRP overwrites \`latest-handoff.md\` and \`latest-handoff-deck.md\`. The app then finds the newest file.
|
|
35854
35873
|
NTRP also writes \`SKILL.md\`. That file holds finder instructions with your paths.
|
|
35855
35874
|
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.
|
|
35856
|
-
Paste that skill once into Claude, ChatGPT, or
|
|
35875
|
+
Paste that skill once into Claude, ChatGPT, Cursor, or another desktop AI. Later handoffs need no new paste.
|
|
35857
35876
|
\`INDEX.md\` in that folder links to the archive.
|
|
35858
35877
|
A path outside ~/.ntrp needs a confirm. Handoffs carry analysis text.
|
|
35859
35878
|
\`clear\` does not delete files. It only removes the config pointer.`
|
|
@@ -36204,9 +36223,9 @@ args: [<metric>|guide|list|tour]
|
|
|
36204
36223
|
handler: ../commands/deepdive.ts
|
|
36205
36224
|
---
|
|
36206
36225
|
|
|
36207
|
-
CLI slide deck: SaaS refresher, five vital signs (definition, formula, visual, dollar translation), then a how-to section (talk, ask, ship to
|
|
36208
|
-
Bare \`/deepdive\` runs the full onboarding tour. Type \`/deepdive guide\` to jump to how to use NTRP (includes teaching
|
|
36209
|
-
Type \`/deepdive handoff\` for the ship-to-
|
|
36226
|
+
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).
|
|
36227
|
+
Bare \`/deepdive\` runs the full onboarding tour. Type \`/deepdive guide\` to jump to how to use NTRP (includes teaching the inbox once).
|
|
36228
|
+
Type \`/deepdive handoff\` for the ship-to-AI slide. Type \`/deepdive <metric>\` to jump to one metric card.
|
|
36210
36229
|
Type \`/deepdive list\` to print the catalog. Works without an AI key. Re-run anytime from the homescreen.
|
|
36211
36230
|
Live values overlay when an analysis exists.`
|
|
36212
36231
|
},
|
|
@@ -36527,7 +36546,7 @@ Remaining nuances merge into a custom_context paragraph that flows into all AI s
|
|
|
36527
36546
|
});
|
|
36528
36547
|
|
|
36529
36548
|
// src/ai/prompt-parts.ts
|
|
36530
|
-
import { existsSync as
|
|
36549
|
+
import { existsSync as existsSync34, readFileSync as readFileSync23 } from "fs";
|
|
36531
36550
|
import { join as join37 } from "path";
|
|
36532
36551
|
function buildCompanyProfileBlock() {
|
|
36533
36552
|
const p = loadProfile();
|
|
@@ -36548,7 +36567,7 @@ function buildCompanyProfileBlock() {
|
|
|
36548
36567
|
function loadAnalystFile() {
|
|
36549
36568
|
const path = join37(ntrpHome(), ANALYST_FILE_NAME);
|
|
36550
36569
|
try {
|
|
36551
|
-
if (!
|
|
36570
|
+
if (!existsSync34(path)) return null;
|
|
36552
36571
|
const raw = sanitizeExternalText(readFileSync23(path, "utf-8").trim());
|
|
36553
36572
|
if (!raw) return null;
|
|
36554
36573
|
if (raw.length <= ANALYST_FILE_MAX_CHARS) return raw;
|
|
@@ -37054,7 +37073,7 @@ __export(ingest_chat_exports, {
|
|
|
37054
37073
|
loadDemoFromChat: () => loadDemoFromChat,
|
|
37055
37074
|
looksLikeFilePath: () => looksLikeFilePath
|
|
37056
37075
|
});
|
|
37057
|
-
import { existsSync as
|
|
37076
|
+
import { existsSync as existsSync35 } from "fs";
|
|
37058
37077
|
import { basename as basename9, resolve as resolve9 } from "path";
|
|
37059
37078
|
import { homedir as homedir8 } from "os";
|
|
37060
37079
|
import chalk80 from "chalk";
|
|
@@ -37074,11 +37093,11 @@ function extractFilePath(input) {
|
|
|
37074
37093
|
const m = trimmed.match(re);
|
|
37075
37094
|
if (m?.[1]) {
|
|
37076
37095
|
const p = expandPath(m[1]);
|
|
37077
|
-
if (
|
|
37096
|
+
if (existsSync35(p)) return p;
|
|
37078
37097
|
}
|
|
37079
37098
|
if (!m?.[1] && re.test(trimmed) && trimmed.toLowerCase().endsWith(".csv")) {
|
|
37080
37099
|
const p = expandPath(trimmed.replace(/^["']|["']$/g, ""));
|
|
37081
|
-
if (
|
|
37100
|
+
if (existsSync35(p)) return p;
|
|
37082
37101
|
}
|
|
37083
37102
|
}
|
|
37084
37103
|
return null;
|