@sonnechasser/ntrp 1.4.1 → 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 +300 -190
- package/dist/mcp/server.js +140 -114
- 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 });
|
|
@@ -9887,11 +9899,15 @@ function resolveCardWidth(opts = {}) {
|
|
|
9887
9899
|
const usable = Math.max(20, termWidth() - margin);
|
|
9888
9900
|
return Math.max(Math.min(min, usable), Math.min(usable, max));
|
|
9889
9901
|
}
|
|
9890
|
-
|
|
9902
|
+
function clearTerminalHome() {
|
|
9903
|
+
process.stdout.write(TERMINAL_HOME_CLEAR);
|
|
9904
|
+
}
|
|
9905
|
+
var ANSI_RE, TERMINAL_HOME_CLEAR;
|
|
9891
9906
|
var init_layout = __esm({
|
|
9892
9907
|
"src/ui/layout.ts"() {
|
|
9893
9908
|
"use strict";
|
|
9894
9909
|
ANSI_RE = /\u001b\[[0-9;]*m/g;
|
|
9910
|
+
TERMINAL_HOME_CLEAR = "\x1B[2J\x1B[H";
|
|
9895
9911
|
}
|
|
9896
9912
|
});
|
|
9897
9913
|
|
|
@@ -12332,11 +12348,11 @@ var init_guide_slides = __esm({
|
|
|
12332
12348
|
};
|
|
12333
12349
|
HANDOFF = {
|
|
12334
12350
|
id: "handoff",
|
|
12335
|
-
label: "Ship work to
|
|
12336
|
-
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.",
|
|
12337
12353
|
visual: {
|
|
12338
12354
|
kind: "layer_stack",
|
|
12339
|
-
caption: "You and
|
|
12355
|
+
caption: "You and your AI find and open the file. NTRP only writes.",
|
|
12340
12356
|
layers: [
|
|
12341
12357
|
{ label: "Set a pickup folder (demo, onboard, or /inbox set)" },
|
|
12342
12358
|
{ label: "Paste the finder skill once (/inbox skill)", highlight: true },
|
|
@@ -12345,18 +12361,18 @@ var init_guide_slides = __esm({
|
|
|
12345
12361
|
]
|
|
12346
12362
|
},
|
|
12347
12363
|
lines: [
|
|
12348
|
-
'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.',
|
|
12349
12365
|
"",
|
|
12350
|
-
"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.",
|
|
12351
12367
|
"",
|
|
12352
|
-
'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.',
|
|
12353
12369
|
"",
|
|
12354
|
-
"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."
|
|
12355
12371
|
],
|
|
12356
12372
|
deepdive: [
|
|
12357
12373
|
"Inbox copies: latest-handoff.md, latest-pickup.md, SKILL.md, INDEX.md. Dated files also live under ~/.ntrp/exports/.",
|
|
12358
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.",
|
|
12359
|
-
"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.",
|
|
12360
12376
|
"Type /end to close a session. NTRP writes a transcript plus a 1-page context brief under ~/.ntrp/sessions/."
|
|
12361
12377
|
]
|
|
12362
12378
|
};
|
|
@@ -12552,7 +12568,7 @@ function paintIntro(opts) {
|
|
|
12552
12568
|
"",
|
|
12553
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.",
|
|
12554
12570
|
"",
|
|
12555
|
-
"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.",
|
|
12556
12572
|
"",
|
|
12557
12573
|
chalk10.dim("No AI key needed for this tour. Press Enter to advance; type /deepdive (or d) on any slide for more.")
|
|
12558
12574
|
],
|
|
@@ -12572,7 +12588,7 @@ function paintClose(opts) {
|
|
|
12572
12588
|
` ${paint("accent", "/diagnose")} \u2014 five vital signs + dollars at risk`,
|
|
12573
12589
|
` ${paint("accent", "/metrics")} \u2014 SaaS scorecard (ARR, NRR, coverage\u2026)`,
|
|
12574
12590
|
` ${paint("accent", "/deepdive")} \u2014 replay this tour \xB7 ${paint("accent", "/deepdive guide")} how-to only`,
|
|
12575
|
-
` ${paint("accent", "/handoff")} \u2014 ship a file; teach
|
|
12591
|
+
` ${paint("accent", "/handoff")} \u2014 ship a file; teach the inbox once (/inbox skill)`,
|
|
12576
12592
|
` ${paint("accent", "/strategy")} \u2014 measurable plan \xB7 ${paint("accent", "/help")} shortcuts`,
|
|
12577
12593
|
"",
|
|
12578
12594
|
"Fourteen more SaaS metrics live behind /deepdive list \u2014 including unit economics that unlock when spend data lands.",
|
|
@@ -12740,7 +12756,7 @@ async function offerFirstRunTour(ctx) {
|
|
|
12740
12756
|
console.log();
|
|
12741
12757
|
console.log(" " + bold("Onboarding tour") + chalk10.dim(" \u2014 ~3 minutes, no AI key required"));
|
|
12742
12758
|
console.log(
|
|
12743
|
-
" " + 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.")
|
|
12744
12760
|
);
|
|
12745
12761
|
const tourDefault = firstRunTourDefaultChoice();
|
|
12746
12762
|
if (tourDefault === "skip") {
|
|
@@ -16233,7 +16249,7 @@ __export(play_outcomes_exports, {
|
|
|
16233
16249
|
listPlayOutcomes: () => listPlayOutcomes,
|
|
16234
16250
|
recordPlayOutcomes: () => recordPlayOutcomes
|
|
16235
16251
|
});
|
|
16236
|
-
import { existsSync as
|
|
16252
|
+
import { existsSync as existsSync21, readFileSync as readFileSync17, appendFileSync as appendFileSync6 } from "fs";
|
|
16237
16253
|
import { join as join21 } from "path";
|
|
16238
16254
|
import { randomUUID as randomUUID7 } from "crypto";
|
|
16239
16255
|
function outcomesPath() {
|
|
@@ -16241,7 +16257,7 @@ function outcomesPath() {
|
|
|
16241
16257
|
}
|
|
16242
16258
|
function listPlayOutcomes() {
|
|
16243
16259
|
const path = outcomesPath();
|
|
16244
|
-
if (!
|
|
16260
|
+
if (!existsSync21(path)) return [];
|
|
16245
16261
|
const out = [];
|
|
16246
16262
|
for (const line of readFileSync17(path, "utf-8").split("\n")) {
|
|
16247
16263
|
const trimmed = line.trim();
|
|
@@ -19234,7 +19250,7 @@ var init_markdown = __esm({
|
|
|
19234
19250
|
import chalk16 from "chalk";
|
|
19235
19251
|
function formatLlmAttribution(meta) {
|
|
19236
19252
|
if (!meta.model_used) return null;
|
|
19237
|
-
const provider = meta.provider_used ?? "
|
|
19253
|
+
const provider = meta.provider_used ?? "unknown";
|
|
19238
19254
|
let line = `via ${formatModelLabel(provider, meta.model_used)}`;
|
|
19239
19255
|
if (meta.failover) {
|
|
19240
19256
|
line += " (auto-failover)";
|
|
@@ -19710,16 +19726,16 @@ var init_terminal = __esm({
|
|
|
19710
19726
|
});
|
|
19711
19727
|
|
|
19712
19728
|
// src/demo/taxonomy-cache.ts
|
|
19713
|
-
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";
|
|
19714
19730
|
import { homedir as homedir7 } from "os";
|
|
19715
19731
|
import { join as join22 } from "path";
|
|
19716
19732
|
function ensureDir6() {
|
|
19717
|
-
if (!
|
|
19733
|
+
if (!existsSync22(NTRP_DIR4)) {
|
|
19718
19734
|
mkdirSync12(NTRP_DIR4, { recursive: true });
|
|
19719
19735
|
}
|
|
19720
19736
|
}
|
|
19721
19737
|
function loadCachedTaxonomy(profile) {
|
|
19722
|
-
if (!
|
|
19738
|
+
if (!existsSync22(TAXONOMY_PATH)) return null;
|
|
19723
19739
|
try {
|
|
19724
19740
|
const parsed = JSON.parse(readFileSync18(TAXONOMY_PATH, "utf-8"));
|
|
19725
19741
|
if (!parsed || typeof parsed !== "object") return null;
|
|
@@ -19734,7 +19750,7 @@ function saveCachedTaxonomy(taxonomy) {
|
|
|
19734
19750
|
writeFileSync14(TAXONOMY_PATH, JSON.stringify(taxonomy, null, 2) + "\n");
|
|
19735
19751
|
}
|
|
19736
19752
|
function invalidateTaxonomy() {
|
|
19737
|
-
if (
|
|
19753
|
+
if (existsSync22(TAXONOMY_PATH)) {
|
|
19738
19754
|
try {
|
|
19739
19755
|
unlinkSync4(TAXONOMY_PATH);
|
|
19740
19756
|
} catch {
|
|
@@ -20204,7 +20220,7 @@ __export(inbox_setup_exports, {
|
|
|
20204
20220
|
shouldOfferInboxSkillSetup: () => shouldOfferInboxSkillSetup
|
|
20205
20221
|
});
|
|
20206
20222
|
import chalk19 from "chalk";
|
|
20207
|
-
import { existsSync as
|
|
20223
|
+
import { existsSync as existsSync23 } from "fs";
|
|
20208
20224
|
function markDemoOffered() {
|
|
20209
20225
|
setConfigValue("ai-inbox-nudge-seen", "true");
|
|
20210
20226
|
}
|
|
@@ -20221,7 +20237,7 @@ function shouldOfferInboxSkillSetup(beat) {
|
|
|
20221
20237
|
return !hasProductionOffered();
|
|
20222
20238
|
}
|
|
20223
20239
|
function printSkipHint(beat) {
|
|
20224
|
-
const setCmd = paint("accent",
|
|
20240
|
+
const setCmd = paint("accent", `/inbox set ${defaultAiInboxDirDisplay()}`);
|
|
20225
20241
|
const skillCmd = paint("accent", "/inbox skill");
|
|
20226
20242
|
if (beat === "demo") {
|
|
20227
20243
|
console.log(
|
|
@@ -20233,13 +20249,15 @@ function printSkipHint(beat) {
|
|
|
20233
20249
|
" " + chalk19.dim("Skipped. NTRP will not ask again. Type ") + setCmd + chalk19.dim(" then ") + skillCmd + chalk19.dim(" at any time.")
|
|
20234
20250
|
);
|
|
20235
20251
|
}
|
|
20236
|
-
async function reuseInboxFolderIfPresent(session, beat, folderPath
|
|
20252
|
+
async function reuseInboxFolderIfPresent(session, beat, folderPath) {
|
|
20237
20253
|
if (getAiInboxDir()) return false;
|
|
20238
|
-
|
|
20239
|
-
|
|
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);
|
|
20240
20258
|
const reuse = await session.confirm("Reuse this pickup folder?", true);
|
|
20241
20259
|
if (!reuse) return false;
|
|
20242
|
-
const resolved = setAiInboxDir(
|
|
20260
|
+
const resolved = setAiInboxDir(existing);
|
|
20243
20261
|
markDemoOffered();
|
|
20244
20262
|
if (beat === "production") markProductionOffered();
|
|
20245
20263
|
console.log();
|
|
@@ -20254,7 +20272,7 @@ async function offerInboxSkillSetup(session, opts = {}) {
|
|
|
20254
20272
|
const beat = opts.beat ?? "production";
|
|
20255
20273
|
if (!shouldOfferInboxSkillSetup(beat)) return;
|
|
20256
20274
|
console.log();
|
|
20257
|
-
console.log(" " + bold("Teach
|
|
20275
|
+
console.log(" " + bold("Teach your AI where handoffs live"));
|
|
20258
20276
|
console.log(
|
|
20259
20277
|
" " + chalk19.dim(
|
|
20260
20278
|
"Optional. NTRP copies every handoff into one folder. You paste instructions once; later /handoff just writes the file."
|
|
@@ -20265,7 +20283,10 @@ async function offerInboxSkillSetup(session, opts = {}) {
|
|
|
20265
20283
|
}
|
|
20266
20284
|
console.log();
|
|
20267
20285
|
if (await reuseInboxFolderIfPresent(session, beat)) return;
|
|
20268
|
-
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
|
+
);
|
|
20269
20290
|
if (!want) {
|
|
20270
20291
|
if (beat === "demo") markDemoOffered();
|
|
20271
20292
|
else markProductionOffered();
|
|
@@ -20297,10 +20318,12 @@ async function offerInboxSkillSetup(session, opts = {}) {
|
|
|
20297
20318
|
console.log(" " + chalk19.dim(`Synced ${n} recent export${n === 1 ? "" : "s"}.`));
|
|
20298
20319
|
}
|
|
20299
20320
|
console.log(
|
|
20300
|
-
" " + chalk19.dim(
|
|
20321
|
+
" " + chalk19.dim(
|
|
20322
|
+
"Paste this skill into your desktop AI once. Later, tell it to open the latest NTRP handoff."
|
|
20323
|
+
)
|
|
20301
20324
|
);
|
|
20302
20325
|
printStandingSkill();
|
|
20303
|
-
await session.askPressEnter("Paste the skill into
|
|
20326
|
+
await session.askPressEnter("Paste the skill into your AI. Then continue");
|
|
20304
20327
|
console.log(" " + chalk19.dim("Done. Later handoffs write to that folder. The skill is not printed again."));
|
|
20305
20328
|
console.log();
|
|
20306
20329
|
}
|
|
@@ -20335,7 +20358,7 @@ __export(ingest_exports, {
|
|
|
20335
20358
|
handler: () => handler2
|
|
20336
20359
|
});
|
|
20337
20360
|
import chalk20 from "chalk";
|
|
20338
|
-
import { readFileSync as readFileSync19, existsSync as
|
|
20361
|
+
import { readFileSync as readFileSync19, existsSync as existsSync24 } from "fs";
|
|
20339
20362
|
import { basename as basename6 } from "path";
|
|
20340
20363
|
async function handler2(args, ctx) {
|
|
20341
20364
|
const { positional, flags } = parseArgs2(args, [
|
|
@@ -20359,7 +20382,7 @@ async function handler2(args, ctx) {
|
|
|
20359
20382
|
console.error(chalk20.dim(" /ingest --demo [--scenario <name>]"));
|
|
20360
20383
|
process.exit(1);
|
|
20361
20384
|
}
|
|
20362
|
-
if (!
|
|
20385
|
+
if (!existsSync24(file)) {
|
|
20363
20386
|
console.error(chalk20.red(` File not found: ${file}`));
|
|
20364
20387
|
process.exit(1);
|
|
20365
20388
|
}
|
|
@@ -20947,7 +20970,7 @@ function buildUserMessage(input) {
|
|
|
20947
20970
|
async function* streamFindings(input, ctx) {
|
|
20948
20971
|
assertReplAi(ctx);
|
|
20949
20972
|
const userMessage = buildUserMessage(input);
|
|
20950
|
-
let meta = { model_used: "unknown", provider_used: "
|
|
20973
|
+
let meta = { model_used: "unknown", provider_used: "unknown", failover: false };
|
|
20951
20974
|
const scanner = new StreamingJsonArrayParser();
|
|
20952
20975
|
let streamed = 0;
|
|
20953
20976
|
for await (const event of streamWithFailover(
|
|
@@ -22445,9 +22468,9 @@ async function handleGetSessionBrief(input) {
|
|
|
22445
22468
|
if (!target) {
|
|
22446
22469
|
return { error: `No session matching "${raw}".` };
|
|
22447
22470
|
}
|
|
22448
|
-
const { existsSync:
|
|
22471
|
+
const { existsSync: existsSync36, readFileSync: readFileSync24 } = await import("fs");
|
|
22449
22472
|
const briefPath = contextDocPathForSession2(target.id);
|
|
22450
|
-
if (!
|
|
22473
|
+
if (!existsSync36(briefPath)) {
|
|
22451
22474
|
return {
|
|
22452
22475
|
session_id: target.id,
|
|
22453
22476
|
error: "No context brief on disk for this session (created before brief storage existed).",
|
|
@@ -23162,7 +23185,7 @@ async function* agenticFindings(computeResult, divergences, options) {
|
|
|
23162
23185
|
const priorMessages = priorRaw.length > 0 && typeof priorRaw[0] === "object" && priorRaw[0] !== null && "content" in priorRaw[0] ? normalizeThread(priorRaw) : priorRaw;
|
|
23163
23186
|
const conversational = mode === "fresh" || mode === "think";
|
|
23164
23187
|
const messages = conversational && priorMessages.length > 0 && options.userQuestion ? [...priorMessages, { role: "user", content: options.userQuestion }] : [{ role: "user", content: initialContext }];
|
|
23165
|
-
let lastMeta = { provider_used: "
|
|
23188
|
+
let lastMeta = { provider_used: "unknown", model_used: "unknown" };
|
|
23166
23189
|
const loopGuard = new ToolLoopGuard();
|
|
23167
23190
|
const allowedTools = new Set(tools.map((t) => t.name));
|
|
23168
23191
|
async function callLlm(msgs, tokens, withTools) {
|
|
@@ -25128,7 +25151,7 @@ __export(new_exports, {
|
|
|
25128
25151
|
handler: () => handler6
|
|
25129
25152
|
});
|
|
25130
25153
|
import chalk26 from "chalk";
|
|
25131
|
-
import { existsSync as
|
|
25154
|
+
import { existsSync as existsSync25 } from "fs";
|
|
25132
25155
|
import { basename as basename7 } from "path";
|
|
25133
25156
|
async function handler6(args, ctx) {
|
|
25134
25157
|
const { positional, flags } = parseArgs2(args, ["demo", "empty", "list-scenarios", "regen-taxonomy"]);
|
|
@@ -25150,7 +25173,7 @@ async function handler6(args, ctx) {
|
|
|
25150
25173
|
console.error(chalk26.red(" Usage: /new <file.csv> | --demo [--scenario <name>] | --empty [--lens health|metrics]"));
|
|
25151
25174
|
return;
|
|
25152
25175
|
}
|
|
25153
|
-
if (source.kind === "file" && !
|
|
25176
|
+
if (source.kind === "file" && !existsSync25(source.path)) {
|
|
25154
25177
|
console.error(chalk26.red(` File not found: ${source.path}`));
|
|
25155
25178
|
return;
|
|
25156
25179
|
}
|
|
@@ -25377,7 +25400,7 @@ __export(end_exports, {
|
|
|
25377
25400
|
handler: () => handler7
|
|
25378
25401
|
});
|
|
25379
25402
|
import chalk27 from "chalk";
|
|
25380
|
-
import { existsSync as
|
|
25403
|
+
import { existsSync as existsSync26 } from "fs";
|
|
25381
25404
|
async function handler7(args, ctx) {
|
|
25382
25405
|
if (args.length > 0) {
|
|
25383
25406
|
console.error(chalk27.red(" Usage: /end"));
|
|
@@ -25414,10 +25437,10 @@ async function handler7(args, ctx) {
|
|
|
25414
25437
|
if (summary) {
|
|
25415
25438
|
console.log(" " + chalk27.dim(summary));
|
|
25416
25439
|
}
|
|
25417
|
-
if (
|
|
25440
|
+
if (existsSync26(transcriptPathForSession(endedId))) {
|
|
25418
25441
|
console.log(" " + chalk27.dim("Transcript: ") + chalk27.dim(transcriptPathForSession(endedId)));
|
|
25419
25442
|
}
|
|
25420
|
-
if (
|
|
25443
|
+
if (existsSync26(contextDocPathForSession(endedId))) {
|
|
25421
25444
|
console.log(" " + chalk27.dim("Context brief: ") + chalk27.dim(contextDocPathForSession(endedId)));
|
|
25422
25445
|
}
|
|
25423
25446
|
console.log();
|
|
@@ -25439,7 +25462,7 @@ __export(session_exports, {
|
|
|
25439
25462
|
});
|
|
25440
25463
|
import chalk28 from "chalk";
|
|
25441
25464
|
import { join as join23 } from "path";
|
|
25442
|
-
import { existsSync as
|
|
25465
|
+
import { existsSync as existsSync27 } from "fs";
|
|
25443
25466
|
async function handler8(args, ctx) {
|
|
25444
25467
|
const sub = args[0];
|
|
25445
25468
|
if (!sub) return listSessionsView(ctx);
|
|
@@ -25585,7 +25608,7 @@ async function pickUp(idArg, ctx) {
|
|
|
25585
25608
|
);
|
|
25586
25609
|
}
|
|
25587
25610
|
const contextPath = contextDocPathForSession(target.id);
|
|
25588
|
-
if (
|
|
25611
|
+
if (existsSync27(contextPath)) {
|
|
25589
25612
|
console.log(" " + chalk28.dim("Context brief: ") + chalk28.dim(contextPath));
|
|
25590
25613
|
}
|
|
25591
25614
|
console.log();
|
|
@@ -28795,7 +28818,7 @@ async function* strategistPlanSession(options) {
|
|
|
28795
28818
|
})
|
|
28796
28819
|
}
|
|
28797
28820
|
];
|
|
28798
|
-
let lastMeta = { provider_used: "
|
|
28821
|
+
let lastMeta = { provider_used: "unknown", model_used: "unknown" };
|
|
28799
28822
|
const loopGuard = new ToolLoopGuard();
|
|
28800
28823
|
const allowedTools = new Set(tools.map((t) => t.name));
|
|
28801
28824
|
const callLlm = async (surface, withTools, maxTokens = STAGE_MAX_TOKENS) => {
|
|
@@ -31127,7 +31150,7 @@ var init_checkout = __esm({
|
|
|
31127
31150
|
});
|
|
31128
31151
|
|
|
31129
31152
|
// src/services/setup.ts
|
|
31130
|
-
import { existsSync as
|
|
31153
|
+
import { existsSync as existsSync28, mkdirSync as mkdirSync17, readFileSync as readFileSync20, writeFileSync as writeFileSync19 } from "fs";
|
|
31131
31154
|
import { join as join29 } from "path";
|
|
31132
31155
|
function setupCheck() {
|
|
31133
31156
|
const home = ntrpHome();
|
|
@@ -31830,7 +31853,7 @@ async function handleDeliverFlow(input, ctx) {
|
|
|
31830
31853
|
}
|
|
31831
31854
|
console.log();
|
|
31832
31855
|
console.log(" " + chalk52.bold("Deliverable preview"));
|
|
31833
|
-
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."));
|
|
31834
31857
|
console.log(" " + chalk52.dim("\u2500".repeat(56)));
|
|
31835
31858
|
const preview = draft.markdown.split("\n").slice(0, 12);
|
|
31836
31859
|
for (const l of preview) {
|
|
@@ -33130,7 +33153,7 @@ __export(sessions_exports, {
|
|
|
33130
33153
|
handler: () => handler35
|
|
33131
33154
|
});
|
|
33132
33155
|
import chalk62 from "chalk";
|
|
33133
|
-
import { existsSync as
|
|
33156
|
+
import { existsSync as existsSync29 } from "fs";
|
|
33134
33157
|
async function handler35(args, _ctx) {
|
|
33135
33158
|
const sub = args[0] ?? "list";
|
|
33136
33159
|
if (sub === "list" || !args[0]) {
|
|
@@ -33237,12 +33260,12 @@ function showSession(idArg) {
|
|
|
33237
33260
|
console.log();
|
|
33238
33261
|
const transcriptPath = transcriptPathForSession(session.id);
|
|
33239
33262
|
const contextPath = contextDocPathForSession(session.id);
|
|
33240
|
-
if (
|
|
33263
|
+
if (existsSync29(transcriptPath) || existsSync29(contextPath)) {
|
|
33241
33264
|
console.log(" " + chalk62.dim("\u2500".repeat(40)));
|
|
33242
|
-
if (
|
|
33265
|
+
if (existsSync29(contextPath)) {
|
|
33243
33266
|
console.log(" " + chalk62.dim("Context brief: ") + chalk62.dim(contextPath));
|
|
33244
33267
|
}
|
|
33245
|
-
if (
|
|
33268
|
+
if (existsSync29(transcriptPath)) {
|
|
33246
33269
|
console.log(" " + chalk62.dim("Full transcript: ") + chalk62.dim(transcriptPath));
|
|
33247
33270
|
}
|
|
33248
33271
|
console.log();
|
|
@@ -33514,7 +33537,7 @@ var init_privacy_notice = __esm({
|
|
|
33514
33537
|
"Computed scores and dollar aggregates still go to the provider you connected.",
|
|
33515
33538
|
"If you turn on web retrieval, named-account queries are refused. Generic GTM terms may go to Tavily or Brave.",
|
|
33516
33539
|
"A custom --base-url receives the same tokenized payload.",
|
|
33517
|
-
"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.",
|
|
33518
33541
|
"Keys stay in ~/.ntrp/config.json on this machine (mode 600).",
|
|
33519
33542
|
"NTRP is a diagnostic. It does not change CRM records or send email.",
|
|
33520
33543
|
"Type /privacy to read this notice again."
|
|
@@ -34578,20 +34601,20 @@ var init_model = __esm({
|
|
|
34578
34601
|
});
|
|
34579
34602
|
|
|
34580
34603
|
// src/config/update-check.ts
|
|
34581
|
-
import { existsSync as
|
|
34604
|
+
import { existsSync as existsSync30, mkdirSync as mkdirSync18, readFileSync as readFileSync21, unlinkSync as unlinkSync5, writeFileSync as writeFileSync20 } from "fs";
|
|
34582
34605
|
import { join as join33 } from "path";
|
|
34583
34606
|
function cachePath2() {
|
|
34584
34607
|
return join33(ntrpHome(), "update-check.json");
|
|
34585
34608
|
}
|
|
34586
34609
|
function ensureDir7() {
|
|
34587
34610
|
const dir = ntrpHome();
|
|
34588
|
-
if (!
|
|
34611
|
+
if (!existsSync30(dir)) {
|
|
34589
34612
|
mkdirSync18(dir, { recursive: true });
|
|
34590
34613
|
}
|
|
34591
34614
|
}
|
|
34592
34615
|
function loadUpdateCheckCache() {
|
|
34593
34616
|
const path = cachePath2();
|
|
34594
|
-
if (!
|
|
34617
|
+
if (!existsSync30(path)) return null;
|
|
34595
34618
|
try {
|
|
34596
34619
|
const parsed = JSON.parse(readFileSync21(path, "utf-8"));
|
|
34597
34620
|
if (!parsed || typeof parsed !== "object" || typeof parsed.lastCheck !== "number" || typeof parsed.latestVersion !== "string") {
|
|
@@ -34612,7 +34635,7 @@ function isCacheFresh(cache2, ttlMs = CACHE_TTL_MS2) {
|
|
|
34612
34635
|
}
|
|
34613
34636
|
function invalidateUpdateCheckCache() {
|
|
34614
34637
|
const path = cachePath2();
|
|
34615
|
-
if (
|
|
34638
|
+
if (existsSync30(path)) {
|
|
34616
34639
|
unlinkSync5(path);
|
|
34617
34640
|
}
|
|
34618
34641
|
}
|
|
@@ -34626,25 +34649,32 @@ var init_update_check = __esm({
|
|
|
34626
34649
|
});
|
|
34627
34650
|
|
|
34628
34651
|
// src/version.ts
|
|
34629
|
-
import { existsSync as
|
|
34652
|
+
import { existsSync as existsSync31, readFileSync as readFileSync22 } from "fs";
|
|
34630
34653
|
import { dirname as dirname6, join as join34 } from "path";
|
|
34631
34654
|
import { fileURLToPath } from "url";
|
|
34655
|
+
function readVersionFromPackageJson(packageJsonPath) {
|
|
34656
|
+
if (!existsSync31(packageJsonPath)) return null;
|
|
34657
|
+
try {
|
|
34658
|
+
const pkg = JSON.parse(readFileSync22(packageJsonPath, "utf-8"));
|
|
34659
|
+
if (typeof pkg.version === "string" && pkg.version.length > 0) return pkg.version;
|
|
34660
|
+
} catch {
|
|
34661
|
+
}
|
|
34662
|
+
return null;
|
|
34663
|
+
}
|
|
34664
|
+
function readVersionNearEntry(entryPath) {
|
|
34665
|
+
const start = dirname6(entryPath);
|
|
34666
|
+
for (const rel of [join34(start, "..", "package.json"), join34(start, "../..", "package.json")]) {
|
|
34667
|
+
const version = readVersionFromPackageJson(rel);
|
|
34668
|
+
if (version) return version;
|
|
34669
|
+
}
|
|
34670
|
+
return null;
|
|
34671
|
+
}
|
|
34672
|
+
function readInstalledVersionFromDisk() {
|
|
34673
|
+
return readVersionNearEntry(fileURLToPath(import.meta.url));
|
|
34674
|
+
}
|
|
34632
34675
|
function getInstalledVersion() {
|
|
34633
34676
|
if (cachedVersion) return cachedVersion;
|
|
34634
|
-
|
|
34635
|
-
for (const rel of ["../package.json", "../../package.json"]) {
|
|
34636
|
-
const path = join34(start, rel);
|
|
34637
|
-
if (!existsSync30(path)) continue;
|
|
34638
|
-
try {
|
|
34639
|
-
const pkg = JSON.parse(readFileSync22(path, "utf-8"));
|
|
34640
|
-
if (typeof pkg.version === "string" && pkg.version.length > 0) {
|
|
34641
|
-
cachedVersion = pkg.version;
|
|
34642
|
-
return cachedVersion;
|
|
34643
|
-
}
|
|
34644
|
-
} catch {
|
|
34645
|
-
}
|
|
34646
|
-
}
|
|
34647
|
-
cachedVersion = "0.0.0";
|
|
34677
|
+
cachedVersion = readInstalledVersionFromDisk() ?? "0.0.0";
|
|
34648
34678
|
return cachedVersion;
|
|
34649
34679
|
}
|
|
34650
34680
|
var cachedVersion;
|
|
@@ -34756,9 +34786,16 @@ __export(relaunch_exports, {
|
|
|
34756
34786
|
JUST_UPDATED_ENV: () => JUST_UPDATED_ENV,
|
|
34757
34787
|
consumeJustUpdatedEnv: () => consumeJustUpdatedEnv,
|
|
34758
34788
|
encodeJustUpdated: () => encodeJustUpdated,
|
|
34789
|
+
reclaimStdinAfterFailedRelaunch: () => reclaimStdinAfterFailedRelaunch,
|
|
34790
|
+
relaunchArgv: () => relaunchArgv,
|
|
34759
34791
|
relaunchIntoHome: () => relaunchIntoHome,
|
|
34792
|
+
releaseStdinForRelaunch: () => releaseStdinForRelaunch,
|
|
34793
|
+
resolveRelaunchEntry: () => resolveRelaunchEntry,
|
|
34760
34794
|
updateRestartSummary: () => updateRestartSummary
|
|
34761
34795
|
});
|
|
34796
|
+
import { existsSync as existsSync32 } from "fs";
|
|
34797
|
+
import { join as join35 } from "path";
|
|
34798
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
34762
34799
|
import { spawnSync } from "child_process";
|
|
34763
34800
|
function encodeJustUpdated(fromVersion, toVersion) {
|
|
34764
34801
|
return `${fromVersion}\u2192${toVersion}`;
|
|
@@ -34778,16 +34815,53 @@ function consumeJustUpdatedEnv() {
|
|
|
34778
34815
|
function updateRestartSummary(toVersion) {
|
|
34779
34816
|
return `Restart NTRP to use v${toVersion}`;
|
|
34780
34817
|
}
|
|
34818
|
+
function npmGlobalEntry() {
|
|
34819
|
+
const listed = spawnSync("npm", ["root", "-g"], { encoding: "utf-8" });
|
|
34820
|
+
if (listed.status !== 0) return null;
|
|
34821
|
+
const entry = join35(listed.stdout.trim(), NPM_PACKAGE, "dist/index.js");
|
|
34822
|
+
return existsSync32(entry) ? entry : null;
|
|
34823
|
+
}
|
|
34824
|
+
function thisBundleEntry() {
|
|
34825
|
+
return fileURLToPath2(import.meta.url);
|
|
34826
|
+
}
|
|
34827
|
+
function resolveRelaunchEntry(toVersion) {
|
|
34828
|
+
const candidates = [thisBundleEntry(), npmGlobalEntry(), process.argv[1]].filter(
|
|
34829
|
+
(p) => Boolean(p)
|
|
34830
|
+
);
|
|
34831
|
+
for (const entry of candidates) {
|
|
34832
|
+
if (!existsSync32(entry)) continue;
|
|
34833
|
+
if (readVersionNearEntry(entry) === toVersion) return entry;
|
|
34834
|
+
}
|
|
34835
|
+
return candidates.find((p) => existsSync32(p)) ?? thisBundleEntry();
|
|
34836
|
+
}
|
|
34837
|
+
function relaunchArgv(toVersion) {
|
|
34838
|
+
return [resolveRelaunchEntry(toVersion)];
|
|
34839
|
+
}
|
|
34840
|
+
function releaseStdinForRelaunch(rl) {
|
|
34841
|
+
try {
|
|
34842
|
+
if (process.stdin.isTTY && process.stdin.isRaw === true) {
|
|
34843
|
+
process.stdin.setRawMode(false);
|
|
34844
|
+
}
|
|
34845
|
+
} catch {
|
|
34846
|
+
}
|
|
34847
|
+
try {
|
|
34848
|
+
rl?.pause();
|
|
34849
|
+
} catch {
|
|
34850
|
+
}
|
|
34851
|
+
}
|
|
34852
|
+
function reclaimStdinAfterFailedRelaunch(rl) {
|
|
34853
|
+
try {
|
|
34854
|
+
rl?.resume();
|
|
34855
|
+
} catch {
|
|
34856
|
+
}
|
|
34857
|
+
}
|
|
34781
34858
|
async function relaunchIntoHome(opts) {
|
|
34782
34859
|
const { stopSessionTranscript: stopSessionTranscript2 } = await Promise.resolve().then(() => (init_transcript(), transcript_exports));
|
|
34783
34860
|
const { close: close2 } = await Promise.resolve().then(() => (init_connection(), connection_exports));
|
|
34784
34861
|
stopSessionTranscript2();
|
|
34785
34862
|
await close2();
|
|
34786
|
-
|
|
34787
|
-
|
|
34788
|
-
} catch {
|
|
34789
|
-
}
|
|
34790
|
-
const result = spawnSync(process.execPath, process.argv.slice(1), {
|
|
34863
|
+
releaseStdinForRelaunch(opts.rl);
|
|
34864
|
+
const result = spawnSync(process.execPath, relaunchArgv(opts.toVersion), {
|
|
34791
34865
|
stdio: "inherit",
|
|
34792
34866
|
env: {
|
|
34793
34867
|
...process.env,
|
|
@@ -34795,10 +34869,7 @@ async function relaunchIntoHome(opts) {
|
|
|
34795
34869
|
}
|
|
34796
34870
|
});
|
|
34797
34871
|
if (result.error) {
|
|
34798
|
-
|
|
34799
|
-
opts.rl?.resume();
|
|
34800
|
-
} catch {
|
|
34801
|
-
}
|
|
34872
|
+
reclaimStdinAfterFailedRelaunch(opts.rl);
|
|
34802
34873
|
return "failed";
|
|
34803
34874
|
}
|
|
34804
34875
|
process.exit(result.status ?? 0);
|
|
@@ -34808,6 +34879,8 @@ var JUST_UPDATED_ENV;
|
|
|
34808
34879
|
var init_relaunch = __esm({
|
|
34809
34880
|
"src/update/relaunch.ts"() {
|
|
34810
34881
|
"use strict";
|
|
34882
|
+
init_version();
|
|
34883
|
+
init_registry();
|
|
34811
34884
|
JUST_UPDATED_ENV = "NTRP_JUST_UPDATED";
|
|
34812
34885
|
}
|
|
34813
34886
|
});
|
|
@@ -34864,6 +34937,7 @@ async function handler44(_args, ctx) {
|
|
|
34864
34937
|
return;
|
|
34865
34938
|
}
|
|
34866
34939
|
console.log();
|
|
34940
|
+
console.log(chalk73.dim(` Starting v${latest}\u2026`));
|
|
34867
34941
|
const failed = await relaunchIntoHome({
|
|
34868
34942
|
fromVersion: current,
|
|
34869
34943
|
toVersion: latest,
|
|
@@ -34872,6 +34946,7 @@ async function handler44(_args, ctx) {
|
|
|
34872
34946
|
if (failed) {
|
|
34873
34947
|
const restart = updateRestartSummary(latest);
|
|
34874
34948
|
console.log(chalk73.green(` \u2713 Updated! ${restart}`));
|
|
34949
|
+
console.log(chalk73.dim(" Type /exit, then ntrp. This window is still the old process."));
|
|
34875
34950
|
console.log();
|
|
34876
34951
|
return restart;
|
|
34877
34952
|
}
|
|
@@ -35280,8 +35355,8 @@ __export(exports_exports, {
|
|
|
35280
35355
|
handler: () => handler48
|
|
35281
35356
|
});
|
|
35282
35357
|
import chalk78 from "chalk";
|
|
35283
|
-
import { existsSync as
|
|
35284
|
-
import { join as
|
|
35358
|
+
import { existsSync as existsSync33 } from "fs";
|
|
35359
|
+
import { join as join36 } from "path";
|
|
35285
35360
|
function usage4() {
|
|
35286
35361
|
console.log(chalk78.dim(" Usage:"));
|
|
35287
35362
|
console.log(chalk78.dim(" /exports list [kind]"));
|
|
@@ -35338,7 +35413,7 @@ function printInboxShow() {
|
|
|
35338
35413
|
console.log(" " + paint("accent", "AI inbox: ") + inbox);
|
|
35339
35414
|
const latest = inboxLatestHandoffPath();
|
|
35340
35415
|
if (latest) console.log(" " + chalk78.dim("Latest handoff: ") + latest);
|
|
35341
|
-
console.log(" " + chalk78.dim("Finder skill: ") +
|
|
35416
|
+
console.log(" " + chalk78.dim("Finder skill: ") + join36(inbox, "SKILL.md"));
|
|
35342
35417
|
console.log(" " + chalk78.dim("Reprint: ") + paint("accent", "/inbox skill"));
|
|
35343
35418
|
} else {
|
|
35344
35419
|
console.log(" " + chalk78.dim("AI inbox: (not set). Type ") + paint("accent", "/inbox set <folder>"));
|
|
@@ -35360,8 +35435,8 @@ function printOpen() {
|
|
|
35360
35435
|
console.log(" " + chalk78.dim("AI inbox: ") + inbox);
|
|
35361
35436
|
const latest = inboxLatestHandoffPath();
|
|
35362
35437
|
if (latest) console.log(" " + chalk78.dim("Inbox latest: ") + latest);
|
|
35363
|
-
console.log(" " + chalk78.dim("Pickup skill: ") +
|
|
35364
|
-
console.log(" " + chalk78.dim("Finder skill: ") +
|
|
35438
|
+
console.log(" " + chalk78.dim("Pickup skill: ") + join36(inbox, "latest-pickup.md"));
|
|
35439
|
+
console.log(" " + chalk78.dim("Finder skill: ") + join36(inbox, "SKILL.md"));
|
|
35365
35440
|
} else {
|
|
35366
35441
|
console.log(" " + chalk78.dim("AI inbox is not set. Type ") + paint("accent", "/inbox set <folder>"));
|
|
35367
35442
|
const loc = handoffLocations();
|
|
@@ -35392,7 +35467,7 @@ async function runInboxSet(args, ctx) {
|
|
|
35392
35467
|
const pathArg = args.join(" ").trim();
|
|
35393
35468
|
if (!pathArg) {
|
|
35394
35469
|
console.error(chalk78.red(" Usage: /inbox set <path>"));
|
|
35395
|
-
console.error(chalk78.dim(" Example: /inbox set ~/Documents/
|
|
35470
|
+
console.error(chalk78.dim(" Example: /inbox set ~/Documents/ntrp-inbox"));
|
|
35396
35471
|
if (ctx.oneShot) process.exit(1);
|
|
35397
35472
|
return;
|
|
35398
35473
|
}
|
|
@@ -35422,7 +35497,7 @@ async function runInboxSet(args, ctx) {
|
|
|
35422
35497
|
console.log();
|
|
35423
35498
|
console.log(" " + paint("accent", "AI inbox set"));
|
|
35424
35499
|
console.log(" " + chalk78.dim(setTo));
|
|
35425
|
-
console.log(" " + chalk78.dim("Point Claude
|
|
35500
|
+
console.log(" " + chalk78.dim("Point Claude, ChatGPT, Cursor, or another desktop AI at this folder."));
|
|
35426
35501
|
if (n > 0) {
|
|
35427
35502
|
console.log(" " + chalk78.dim(`Synced ${n} recent export${n === 1 ? "" : "s"} into the inbox.`));
|
|
35428
35503
|
}
|
|
@@ -35439,7 +35514,7 @@ function runMove(args, ctx) {
|
|
|
35439
35514
|
}
|
|
35440
35515
|
try {
|
|
35441
35516
|
const destDir = resolveUserPath(dest);
|
|
35442
|
-
if (!
|
|
35517
|
+
if (!existsSync33(destDir)) {
|
|
35443
35518
|
}
|
|
35444
35519
|
const event = moveExport(idOrName, destDir);
|
|
35445
35520
|
console.log();
|
|
@@ -35792,12 +35867,12 @@ args: [show|set <path>|skill|clear]
|
|
|
35792
35867
|
handler: ../commands/exports.ts
|
|
35793
35868
|
---
|
|
35794
35869
|
|
|
35795
|
-
Set a folder that
|
|
35870
|
+
Set a folder that any desktop AI can read (Claude, ChatGPT, Cursor, \u2026).
|
|
35796
35871
|
NTRP copies each handoff to that folder.
|
|
35797
35872
|
NTRP overwrites \`latest-handoff.md\` and \`latest-handoff-deck.md\`. The app then finds the newest file.
|
|
35798
35873
|
NTRP also writes \`SKILL.md\`. That file holds finder instructions with your paths.
|
|
35799
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.
|
|
35800
|
-
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.
|
|
35801
35876
|
\`INDEX.md\` in that folder links to the archive.
|
|
35802
35877
|
A path outside ~/.ntrp needs a confirm. Handoffs carry analysis text.
|
|
35803
35878
|
\`clear\` does not delete files. It only removes the config pointer.`
|
|
@@ -36148,9 +36223,9 @@ args: [<metric>|guide|list|tour]
|
|
|
36148
36223
|
handler: ../commands/deepdive.ts
|
|
36149
36224
|
---
|
|
36150
36225
|
|
|
36151
|
-
CLI slide deck: SaaS refresher, five vital signs (definition, formula, visual, dollar translation), then a how-to section (talk, ask, ship to
|
|
36152
|
-
Bare \`/deepdive\` runs the full onboarding tour. Type \`/deepdive guide\` to jump to how to use NTRP (includes teaching
|
|
36153
|
-
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.
|
|
36154
36229
|
Type \`/deepdive list\` to print the catalog. Works without an AI key. Re-run anytime from the homescreen.
|
|
36155
36230
|
Live values overlay when an analysis exists.`
|
|
36156
36231
|
},
|
|
@@ -36471,8 +36546,8 @@ Remaining nuances merge into a custom_context paragraph that flows into all AI s
|
|
|
36471
36546
|
});
|
|
36472
36547
|
|
|
36473
36548
|
// src/ai/prompt-parts.ts
|
|
36474
|
-
import { existsSync as
|
|
36475
|
-
import { join as
|
|
36549
|
+
import { existsSync as existsSync34, readFileSync as readFileSync23 } from "fs";
|
|
36550
|
+
import { join as join37 } from "path";
|
|
36476
36551
|
function buildCompanyProfileBlock() {
|
|
36477
36552
|
const p = loadProfile();
|
|
36478
36553
|
if (!p) return "";
|
|
@@ -36490,9 +36565,9 @@ function buildCompanyProfileBlock() {
|
|
|
36490
36565
|
return lines.join("\n");
|
|
36491
36566
|
}
|
|
36492
36567
|
function loadAnalystFile() {
|
|
36493
|
-
const path =
|
|
36568
|
+
const path = join37(ntrpHome(), ANALYST_FILE_NAME);
|
|
36494
36569
|
try {
|
|
36495
|
-
if (!
|
|
36570
|
+
if (!existsSync34(path)) return null;
|
|
36496
36571
|
const raw = sanitizeExternalText(readFileSync23(path, "utf-8").trim());
|
|
36497
36572
|
if (!raw) return null;
|
|
36498
36573
|
if (raw.length <= ANALYST_FILE_MAX_CHARS) return raw;
|
|
@@ -36998,7 +37073,7 @@ __export(ingest_chat_exports, {
|
|
|
36998
37073
|
loadDemoFromChat: () => loadDemoFromChat,
|
|
36999
37074
|
looksLikeFilePath: () => looksLikeFilePath
|
|
37000
37075
|
});
|
|
37001
|
-
import { existsSync as
|
|
37076
|
+
import { existsSync as existsSync35 } from "fs";
|
|
37002
37077
|
import { basename as basename9, resolve as resolve9 } from "path";
|
|
37003
37078
|
import { homedir as homedir8 } from "os";
|
|
37004
37079
|
import chalk80 from "chalk";
|
|
@@ -37018,11 +37093,11 @@ function extractFilePath(input) {
|
|
|
37018
37093
|
const m = trimmed.match(re);
|
|
37019
37094
|
if (m?.[1]) {
|
|
37020
37095
|
const p = expandPath(m[1]);
|
|
37021
|
-
if (
|
|
37096
|
+
if (existsSync35(p)) return p;
|
|
37022
37097
|
}
|
|
37023
37098
|
if (!m?.[1] && re.test(trimmed) && trimmed.toLowerCase().endsWith(".csv")) {
|
|
37024
37099
|
const p = expandPath(trimmed.replace(/^["']|["']$/g, ""));
|
|
37025
|
-
if (
|
|
37100
|
+
if (existsSync35(p)) return p;
|
|
37026
37101
|
}
|
|
37027
37102
|
}
|
|
37028
37103
|
return null;
|
|
@@ -38264,7 +38339,8 @@ __export(welcome_exports, {
|
|
|
38264
38339
|
formatEmptyDataHomeHint: () => formatEmptyDataHomeHint,
|
|
38265
38340
|
formatHomeEntityCounts: () => formatHomeEntityCounts,
|
|
38266
38341
|
printWelcome: () => printWelcome,
|
|
38267
|
-
resolveWelcomeNextAction: () => resolveWelcomeNextAction
|
|
38342
|
+
resolveWelcomeNextAction: () => resolveWelcomeNextAction,
|
|
38343
|
+
staleProcessHomeNotice: () => staleProcessHomeNotice
|
|
38268
38344
|
});
|
|
38269
38345
|
import chalk87 from "chalk";
|
|
38270
38346
|
function formatHomeEntityCounts(counts) {
|
|
@@ -38287,19 +38363,41 @@ function formatEmptyDataHomeHint(savedSessionCount, opts = {}) {
|
|
|
38287
38363
|
return chalk87.dim("Type ") + paint("accent", "use demo data") + chalk87.dim(" to load a sample pipeline") + onboard;
|
|
38288
38364
|
}
|
|
38289
38365
|
function ntrpStatusRow(version, update) {
|
|
38366
|
+
const disk = readInstalledVersionFromDisk();
|
|
38290
38367
|
if (update && isNewerVersion(update.latest, version)) {
|
|
38368
|
+
if (disk && !isNewerVersion(update.latest, disk)) {
|
|
38369
|
+
return {
|
|
38370
|
+
label: "ntrp",
|
|
38371
|
+
state: badge("RESTART", "warning"),
|
|
38372
|
+
detail: `v${disk} installed \xB7 type /exit`
|
|
38373
|
+
};
|
|
38374
|
+
}
|
|
38291
38375
|
return {
|
|
38292
38376
|
label: "ntrp",
|
|
38293
38377
|
state: badge("UPDATE", "warning"),
|
|
38294
38378
|
detail: `v${update.latest} \xB7 type /update`
|
|
38295
38379
|
};
|
|
38296
38380
|
}
|
|
38381
|
+
if (disk && isNewerVersion(disk, getInstalledVersion())) {
|
|
38382
|
+
return {
|
|
38383
|
+
label: "ntrp",
|
|
38384
|
+
state: badge("RESTART", "warning"),
|
|
38385
|
+
detail: `v${disk} installed \xB7 type /exit`
|
|
38386
|
+
};
|
|
38387
|
+
}
|
|
38297
38388
|
return {
|
|
38298
38389
|
label: "ntrp",
|
|
38299
38390
|
state: chalk87.dim(`v${version}`),
|
|
38300
38391
|
detail: ""
|
|
38301
38392
|
};
|
|
38302
38393
|
}
|
|
38394
|
+
function staleProcessHomeNotice() {
|
|
38395
|
+
const running = getInstalledVersion();
|
|
38396
|
+
const disk = readInstalledVersionFromDisk();
|
|
38397
|
+
if (!disk || disk === running) return null;
|
|
38398
|
+
if (!isNewerVersion(disk, running)) return null;
|
|
38399
|
+
return `This window is still v${running}. Type /exit, then ntrp (v${disk} is installed).`;
|
|
38400
|
+
}
|
|
38303
38401
|
function resolveSessionSummary(input) {
|
|
38304
38402
|
if (input.scope?.intent_summary?.trim()) return input.scope.intent_summary.trim();
|
|
38305
38403
|
if (input.summary?.trim()) return input.summary.trim();
|
|
@@ -38612,6 +38710,10 @@ async function printWelcome(ctx, version) {
|
|
|
38612
38710
|
cardW
|
|
38613
38711
|
)
|
|
38614
38712
|
);
|
|
38713
|
+
const stale = staleProcessHomeNotice();
|
|
38714
|
+
if (stale) {
|
|
38715
|
+
push(truncateVisible(` ${paint("warning", "\u2691")} ${stale}`, cardW));
|
|
38716
|
+
}
|
|
38615
38717
|
if (strategyNudge) {
|
|
38616
38718
|
push(
|
|
38617
38719
|
truncateVisible(
|
|
@@ -38654,6 +38756,7 @@ var init_welcome = __esm({
|
|
|
38654
38756
|
init_queries();
|
|
38655
38757
|
init_schema();
|
|
38656
38758
|
init_registry();
|
|
38759
|
+
init_version();
|
|
38657
38760
|
NO_SUMMARY = "(no summary)";
|
|
38658
38761
|
CARD_MAX_W = 128;
|
|
38659
38762
|
CARD_SIDE_MARGIN = 6;
|
|
@@ -38818,7 +38921,7 @@ __export(repl_exports, {
|
|
|
38818
38921
|
import { createInterface as createInterface2 } from "readline/promises";
|
|
38819
38922
|
import { clearLine as clearLine2, cursorTo as cursorTo2 } from "readline";
|
|
38820
38923
|
import chalk88 from "chalk";
|
|
38821
|
-
import { join as
|
|
38924
|
+
import { join as join38 } from "path";
|
|
38822
38925
|
function buildPrompt(ctx) {
|
|
38823
38926
|
return buildConversationPrompt(ctx);
|
|
38824
38927
|
}
|
|
@@ -38921,7 +39024,7 @@ async function goHome(ctx, version, history, opts) {
|
|
|
38921
39024
|
ctx.wizardDepth = 0;
|
|
38922
39025
|
ctx.secretInputActive = false;
|
|
38923
39026
|
history.length = 0;
|
|
38924
|
-
|
|
39027
|
+
clearTerminalHome();
|
|
38925
39028
|
if (opts?.banner) {
|
|
38926
39029
|
console.log();
|
|
38927
39030
|
console.log(" " + paint("accent", "\u2713") + " " + chalk88.dim(opts.banner));
|
|
@@ -39183,7 +39286,7 @@ function printHelp() {
|
|
|
39183
39286
|
["/remember <fact>", "Store a fact, a decision, or a preference"],
|
|
39184
39287
|
["/recall [topic]", "Show what NTRP stores about your business"],
|
|
39185
39288
|
["/rate good|bad <note>", "Correct the last answer. A bad note becomes a calibration"],
|
|
39186
|
-
[`${
|
|
39289
|
+
[`${join38(ntrpHome(), ANALYST_FILE_NAME)}`, "Standing operator instructions (tone, priorities, house rules)"]
|
|
39187
39290
|
];
|
|
39188
39291
|
const teachMaxW = Math.max(...teach.map(([c]) => c.length)) + 2;
|
|
39189
39292
|
for (const [cmd, desc] of teach) {
|
|
@@ -39301,6 +39404,7 @@ init_activation();
|
|
|
39301
39404
|
init_gate2();
|
|
39302
39405
|
init_profile();
|
|
39303
39406
|
init_theme();
|
|
39407
|
+
init_layout();
|
|
39304
39408
|
init_emit();
|
|
39305
39409
|
init_errors2();
|
|
39306
39410
|
init_types2();
|
|
@@ -39348,13 +39452,13 @@ async function main() {
|
|
|
39348
39452
|
if (args.oneShot) {
|
|
39349
39453
|
const cmd = firstToken(args.input);
|
|
39350
39454
|
if (!UNGATED.has(cmd)) {
|
|
39351
|
-
const
|
|
39352
|
-
if (!
|
|
39455
|
+
const lic = await refreshLicenseOnline();
|
|
39456
|
+
if (!lic.valid) {
|
|
39353
39457
|
if (isStructuredOutput(ctx.execution)) {
|
|
39354
|
-
emitError(cmd || "ntrp", new NtrpError("license_invalid",
|
|
39458
|
+
emitError(cmd || "ntrp", new NtrpError("license_invalid", lic.message, 3 /* Auth */));
|
|
39355
39459
|
}
|
|
39356
39460
|
console.error(chalk89.red(`
|
|
39357
|
-
${
|
|
39461
|
+
${lic.message}`));
|
|
39358
39462
|
console.error(chalk89.dim(" Trial's over \u2014 /upgrade and paste your key.\n"));
|
|
39359
39463
|
process.exit(1);
|
|
39360
39464
|
}
|
|
@@ -39400,31 +39504,37 @@ async function main() {
|
|
|
39400
39504
|
}
|
|
39401
39505
|
return DB_COMMANDS.has(cmd);
|
|
39402
39506
|
}
|
|
39403
|
-
const
|
|
39404
|
-
const
|
|
39405
|
-
|
|
39406
|
-
|
|
39407
|
-
|
|
39507
|
+
const { consumeJustUpdatedEnv: consumeJustUpdatedEnv2 } = await Promise.resolve().then(() => (init_relaunch(), relaunch_exports));
|
|
39508
|
+
const justUpdated = consumeJustUpdatedEnv2();
|
|
39509
|
+
let showedActivation = false;
|
|
39510
|
+
if (!justUpdated) {
|
|
39511
|
+
showedActivation = await ensureLicenseActivated(ctx);
|
|
39512
|
+
const lic = await refreshLicenseOnline();
|
|
39513
|
+
if (lic.shouldNudgeUpgrade) {
|
|
39514
|
+
const { printTrialNudge: printTrialNudge2 } = await Promise.resolve().then(() => (init_upgrade(), upgrade_exports));
|
|
39515
|
+
printTrialNudge2(lic);
|
|
39516
|
+
}
|
|
39408
39517
|
}
|
|
39409
39518
|
void Promise.resolve().then(() => (init_discovery(), discovery_exports)).then((m) => m.refreshStaleProviderCaches()).catch(() => void 0);
|
|
39410
39519
|
const { setActiveDbPath: setActiveDbPath2 } = await Promise.resolve().then(() => (init_connection(), connection_exports));
|
|
39411
39520
|
const { datasetPathForSession: datasetPathForSession2 } = await Promise.resolve().then(() => (init_context2(), context_exports));
|
|
39412
39521
|
ctx.datasetPath = datasetPathForSession2(ctx.sessionId);
|
|
39413
39522
|
await setActiveDbPath2(ctx.datasetPath);
|
|
39414
|
-
const { completeInteractiveSetup: completeInteractiveSetup2 } = await Promise.resolve().then(() => (init_first_run(), first_run_exports));
|
|
39415
39523
|
const {
|
|
39416
39524
|
hydrateUpdateAvailableFromCache: hydrateUpdateAvailableFromCache2,
|
|
39417
39525
|
startBackgroundUpdateCheck: startBackgroundUpdateCheck2
|
|
39418
39526
|
} = await Promise.resolve().then(() => (init_registry(), registry_exports));
|
|
39419
|
-
const { consumeJustUpdatedEnv: consumeJustUpdatedEnv2 } = await Promise.resolve().then(() => (init_relaunch(), relaunch_exports));
|
|
39420
39527
|
ctx.updateAvailable = hydrateUpdateAvailableFromCache2(VERSION);
|
|
39421
39528
|
startBackgroundUpdateCheck2(ctx);
|
|
39422
|
-
|
|
39529
|
+
if (!justUpdated) {
|
|
39530
|
+
const { completeInteractiveSetup: completeInteractiveSetup2 } = await Promise.resolve().then(() => (init_first_run(), first_run_exports));
|
|
39531
|
+
await completeInteractiveSetup2(ctx, { skipBrand: showedActivation });
|
|
39532
|
+
}
|
|
39423
39533
|
const { startSessionTranscript: startSessionTranscript2, stopSessionTranscript: stopSessionTranscript2 } = await Promise.resolve().then(() => (init_transcript(), transcript_exports));
|
|
39424
39534
|
startSessionTranscript2(ctx);
|
|
39425
39535
|
const { printWelcome: printWelcome2 } = await Promise.resolve().then(() => (init_welcome(), welcome_exports));
|
|
39426
|
-
const justUpdated = consumeJustUpdatedEnv2();
|
|
39427
39536
|
if (justUpdated) {
|
|
39537
|
+
clearTerminalHome();
|
|
39428
39538
|
console.log();
|
|
39429
39539
|
console.log(" " + paint("accent", "\u2713") + " " + chalk89.dim(`Now running v${justUpdated.to}`));
|
|
39430
39540
|
}
|