threadnote 0.7.2 → 0.7.4
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/threadnote.cjs +158 -50
- package/package.json +1 -1
package/dist/threadnote.cjs
CHANGED
|
@@ -3472,7 +3472,7 @@ var {
|
|
|
3472
3472
|
// src/constants.ts
|
|
3473
3473
|
var DEFAULT_HOST = "127.0.0.1";
|
|
3474
3474
|
var DEFAULT_PORT = 1933;
|
|
3475
|
-
var DEFAULT_OPENVIKING_VERSION = "0.3.
|
|
3475
|
+
var DEFAULT_OPENVIKING_VERSION = "0.3.21";
|
|
3476
3476
|
var DEFAULT_ACCOUNT = "local";
|
|
3477
3477
|
var DEFAULT_AGENT_ID = "threadnote";
|
|
3478
3478
|
var OPENVIKING_PACKAGE_NAME = "openviking[local-embed]";
|
|
@@ -3747,6 +3747,38 @@ async function sleep(ms) {
|
|
|
3747
3747
|
setTimeout(resolvePromise, ms);
|
|
3748
3748
|
});
|
|
3749
3749
|
}
|
|
3750
|
+
function compareVersions(a, b) {
|
|
3751
|
+
const left = parseVersion(a);
|
|
3752
|
+
const right = parseVersion(b);
|
|
3753
|
+
for (let index = 0; index < 3; index += 1) {
|
|
3754
|
+
const difference = left.numbers[index] - right.numbers[index];
|
|
3755
|
+
if (difference !== 0) {
|
|
3756
|
+
return difference;
|
|
3757
|
+
}
|
|
3758
|
+
}
|
|
3759
|
+
if (left.prerelease === right.prerelease) {
|
|
3760
|
+
return 0;
|
|
3761
|
+
}
|
|
3762
|
+
if (left.prerelease === void 0) {
|
|
3763
|
+
return 1;
|
|
3764
|
+
}
|
|
3765
|
+
if (right.prerelease === void 0) {
|
|
3766
|
+
return -1;
|
|
3767
|
+
}
|
|
3768
|
+
return left.prerelease.localeCompare(right.prerelease);
|
|
3769
|
+
}
|
|
3770
|
+
function parseVersion(version) {
|
|
3771
|
+
const normalized = version.trim().replace(/^v/, "");
|
|
3772
|
+
const [core2, prerelease] = normalized.split("-", 2);
|
|
3773
|
+
const parts = core2.split(".").map((part) => Number(part));
|
|
3774
|
+
return {
|
|
3775
|
+
numbers: [safeVersionNumber(parts[0]), safeVersionNumber(parts[1]), safeVersionNumber(parts[2])],
|
|
3776
|
+
prerelease
|
|
3777
|
+
};
|
|
3778
|
+
}
|
|
3779
|
+
function safeVersionNumber(value) {
|
|
3780
|
+
return typeof value === "number" && Number.isInteger(value) && value >= 0 ? value : 0;
|
|
3781
|
+
}
|
|
3750
3782
|
async function readHttpStatus(url, timeoutMs) {
|
|
3751
3783
|
return new Promise((resolvePromise) => {
|
|
3752
3784
|
const request = (0, import_node_http.get)(url, (response) => {
|
|
@@ -9279,7 +9311,7 @@ async function checkForThreadnoteUpdate(args) {
|
|
|
9279
9311
|
}
|
|
9280
9312
|
const cached = await readUpdateCache(args.cachePath);
|
|
9281
9313
|
if (cached && isCacheFresh(cached)) {
|
|
9282
|
-
return
|
|
9314
|
+
return compareVersions2(args.currentVersion, cached.latestVersion);
|
|
9283
9315
|
}
|
|
9284
9316
|
const fresh = await fetchLatestVersion();
|
|
9285
9317
|
if (fresh) {
|
|
@@ -9288,10 +9320,10 @@ async function checkForThreadnoteUpdate(args) {
|
|
|
9288
9320
|
latestVersion: fresh,
|
|
9289
9321
|
version: 1
|
|
9290
9322
|
});
|
|
9291
|
-
return
|
|
9323
|
+
return compareVersions2(args.currentVersion, fresh);
|
|
9292
9324
|
}
|
|
9293
9325
|
if (cached) {
|
|
9294
|
-
return
|
|
9326
|
+
return compareVersions2(args.currentVersion, cached.latestVersion);
|
|
9295
9327
|
}
|
|
9296
9328
|
return void 0;
|
|
9297
9329
|
}
|
|
@@ -9309,7 +9341,7 @@ function spawnDetachedAutoUpdate() {
|
|
|
9309
9341
|
} catch {
|
|
9310
9342
|
}
|
|
9311
9343
|
}
|
|
9312
|
-
function
|
|
9344
|
+
function compareVersions2(currentVersion, latestVersion) {
|
|
9313
9345
|
return {
|
|
9314
9346
|
currentVersion,
|
|
9315
9347
|
latestVersion,
|
|
@@ -9317,8 +9349,8 @@ function compareVersions(currentVersion, latestVersion) {
|
|
|
9317
9349
|
};
|
|
9318
9350
|
}
|
|
9319
9351
|
function isNewerVersion(candidate, baseline) {
|
|
9320
|
-
const candidateParts =
|
|
9321
|
-
const baselineParts =
|
|
9352
|
+
const candidateParts = parseVersion2(candidate);
|
|
9353
|
+
const baselineParts = parseVersion2(baseline);
|
|
9322
9354
|
for (let index = 0; index < 3; index += 1) {
|
|
9323
9355
|
if (candidateParts[index] !== baselineParts[index]) {
|
|
9324
9356
|
return candidateParts[index] > baselineParts[index];
|
|
@@ -9326,7 +9358,7 @@ function isNewerVersion(candidate, baseline) {
|
|
|
9326
9358
|
}
|
|
9327
9359
|
return false;
|
|
9328
9360
|
}
|
|
9329
|
-
function
|
|
9361
|
+
function parseVersion2(value) {
|
|
9330
9362
|
const parts = value.split(".").map((part) => parseInt(part, 10));
|
|
9331
9363
|
return [parts[0] || 0, parts[1] || 0, parts[2] || 0];
|
|
9332
9364
|
}
|
|
@@ -10044,7 +10076,7 @@ async function runUpdate(config, options) {
|
|
|
10044
10076
|
console.log(`Update available. Run: threadnote update`);
|
|
10045
10077
|
} else {
|
|
10046
10078
|
console.log(
|
|
10047
|
-
|
|
10079
|
+
compareVersions(info.currentVersion, info.latestVersion) > 0 ? "Current version is newer than npm latest." : "Threadnote is up to date."
|
|
10048
10080
|
);
|
|
10049
10081
|
}
|
|
10050
10082
|
return;
|
|
@@ -10091,10 +10123,12 @@ async function runPostUpdate(config, options) {
|
|
|
10091
10123
|
if (!options.fromVersion || !options.toVersion) {
|
|
10092
10124
|
throw new Error("Provide --from-version and --to-version for post-update.");
|
|
10093
10125
|
}
|
|
10126
|
+
const interactive = process.stdin.isTTY === true && process.stdout.isTTY === true;
|
|
10127
|
+
await ensurePinnedOpenVikingInstalled(config, { dryRun: options.dryRun === true });
|
|
10094
10128
|
await runApplicablePostUpdateMigrations(config, {
|
|
10095
10129
|
dryRun: options.dryRun === true,
|
|
10096
10130
|
fromVersion: options.fromVersion,
|
|
10097
|
-
interactive
|
|
10131
|
+
interactive,
|
|
10098
10132
|
markHandled: true,
|
|
10099
10133
|
toVersion: options.toVersion,
|
|
10100
10134
|
yes: options.yes === true
|
|
@@ -10102,6 +10136,8 @@ async function runPostUpdate(config, options) {
|
|
|
10102
10136
|
}
|
|
10103
10137
|
async function maybeRunPostUpdateAfterRepair(config, options) {
|
|
10104
10138
|
const toVersion = await currentPackageVersion();
|
|
10139
|
+
const interactive = process.stdin.isTTY === true && process.stdout.isTTY === true;
|
|
10140
|
+
await ensurePinnedOpenVikingInstalled(config, { dryRun: options.dryRun });
|
|
10105
10141
|
const state = await readPostUpdateState(config);
|
|
10106
10142
|
const migrations = await applicablePostUpdateMigrations(config, {
|
|
10107
10143
|
fromVersion: "0.0.0",
|
|
@@ -10114,7 +10150,7 @@ async function maybeRunPostUpdateAfterRepair(config, options) {
|
|
|
10114
10150
|
console.log("");
|
|
10115
10151
|
console.log("Repair found package post-update migrations.");
|
|
10116
10152
|
console.log("This also covers updates launched by older Threadnote versions that only knew how to run repair.");
|
|
10117
|
-
if (
|
|
10153
|
+
if (!interactive) {
|
|
10118
10154
|
console.log(
|
|
10119
10155
|
"This process is non-interactive, so Threadnote will print the manual migration command instead of prompting."
|
|
10120
10156
|
);
|
|
@@ -10123,12 +10159,110 @@ async function maybeRunPostUpdateAfterRepair(config, options) {
|
|
|
10123
10159
|
await runApplicablePostUpdateMigrations(config, {
|
|
10124
10160
|
dryRun: options.dryRun,
|
|
10125
10161
|
fromVersion: "0.0.0",
|
|
10126
|
-
interactive
|
|
10162
|
+
interactive,
|
|
10127
10163
|
markHandled: true,
|
|
10128
10164
|
toVersion,
|
|
10129
10165
|
yes: false
|
|
10130
10166
|
});
|
|
10131
10167
|
}
|
|
10168
|
+
async function ensurePinnedOpenVikingInstalled(config, options) {
|
|
10169
|
+
const ov = await findExecutable(["ov", "openviking"]);
|
|
10170
|
+
if (!ov) {
|
|
10171
|
+
return;
|
|
10172
|
+
}
|
|
10173
|
+
const installedVersion = await readOpenVikingCliVersion(ov);
|
|
10174
|
+
if (!installedVersion) {
|
|
10175
|
+
console.log(`Could not detect OpenViking CLI version via \`${ov} version\`; skipping pinned-version check.`);
|
|
10176
|
+
return;
|
|
10177
|
+
}
|
|
10178
|
+
const pinned = config.openVikingVersion;
|
|
10179
|
+
if (compareVersions(installedVersion, pinned) >= 0) {
|
|
10180
|
+
return;
|
|
10181
|
+
}
|
|
10182
|
+
console.log("");
|
|
10183
|
+
console.log(`Upgrading OpenViking ${installedVersion} -> ${pinned} (pinned by Threadnote).`);
|
|
10184
|
+
console.log("Picks up upstream fixes for share-sync reliability (reindex lock acquisition, ov wait timeout).");
|
|
10185
|
+
const wasRunning = await isOpenVikingHealthy(config);
|
|
10186
|
+
const usingLaunchd = await isLaunchAgentInstalled();
|
|
10187
|
+
const threadnoteCommand = currentThreadnoteCommand() ?? await findExecutable([NPM_PACKAGE_NAME]) ?? NPM_PACKAGE_NAME;
|
|
10188
|
+
await maybeRun(options.dryRun, threadnoteCommand, ["install", "--force", "--no-start"]);
|
|
10189
|
+
if (options.dryRun) {
|
|
10190
|
+
if (wasRunning || usingLaunchd) {
|
|
10191
|
+
console.log("Would restart OpenViking server so the new binary takes effect.");
|
|
10192
|
+
}
|
|
10193
|
+
return;
|
|
10194
|
+
}
|
|
10195
|
+
if (!wasRunning && !usingLaunchd) {
|
|
10196
|
+
return;
|
|
10197
|
+
}
|
|
10198
|
+
console.log("Restarting OpenViking server so the new binary takes effect.");
|
|
10199
|
+
if (usingLaunchd) {
|
|
10200
|
+
const launchAgentPath = launchAgentPlistPath();
|
|
10201
|
+
await runCommand("launchctl", ["unload", launchAgentPath], { allowFailure: true });
|
|
10202
|
+
await runCommand("launchctl", ["load", launchAgentPath], { allowFailure: true });
|
|
10203
|
+
} else {
|
|
10204
|
+
await maybeRun(false, threadnoteCommand, ["stop"]);
|
|
10205
|
+
await maybeRun(false, threadnoteCommand, ["start"]);
|
|
10206
|
+
}
|
|
10207
|
+
const healthyAfter = await waitForOpenVikingHealthy(config, 1e4);
|
|
10208
|
+
if (!healthyAfter) {
|
|
10209
|
+
console.log(
|
|
10210
|
+
`Warning: OpenViking did not return to healthy at ${openVikingHealthEndpoint(config)} within 10s after the restart.`
|
|
10211
|
+
);
|
|
10212
|
+
console.log("Check the server log or run: threadnote start");
|
|
10213
|
+
}
|
|
10214
|
+
}
|
|
10215
|
+
function openVikingHealthEndpoint(config) {
|
|
10216
|
+
return `http://${config.host}:${config.port}/health`;
|
|
10217
|
+
}
|
|
10218
|
+
async function isOpenVikingHealthy(config) {
|
|
10219
|
+
const controller = new AbortController();
|
|
10220
|
+
const timer = setTimeout(() => {
|
|
10221
|
+
controller.abort();
|
|
10222
|
+
}, 800);
|
|
10223
|
+
try {
|
|
10224
|
+
const response = await fetch(openVikingHealthEndpoint(config), { signal: controller.signal });
|
|
10225
|
+
return response.ok;
|
|
10226
|
+
} catch (_err) {
|
|
10227
|
+
return false;
|
|
10228
|
+
} finally {
|
|
10229
|
+
clearTimeout(timer);
|
|
10230
|
+
}
|
|
10231
|
+
}
|
|
10232
|
+
async function waitForOpenVikingHealthy(config, timeoutMs) {
|
|
10233
|
+
const deadline = Date.now() + timeoutMs;
|
|
10234
|
+
while (Date.now() < deadline) {
|
|
10235
|
+
if (await isOpenVikingHealthy(config)) {
|
|
10236
|
+
return true;
|
|
10237
|
+
}
|
|
10238
|
+
await new Promise((resolvePromise) => {
|
|
10239
|
+
setTimeout(resolvePromise, 500);
|
|
10240
|
+
});
|
|
10241
|
+
}
|
|
10242
|
+
return isOpenVikingHealthy(config);
|
|
10243
|
+
}
|
|
10244
|
+
function launchAgentPlistPath() {
|
|
10245
|
+
return (0, import_node_path10.join)((0, import_node_os5.homedir)(), "Library", "LaunchAgents", "io.threadnote.openviking.plist");
|
|
10246
|
+
}
|
|
10247
|
+
async function isLaunchAgentInstalled() {
|
|
10248
|
+
if (process.platform !== "darwin") {
|
|
10249
|
+
return false;
|
|
10250
|
+
}
|
|
10251
|
+
try {
|
|
10252
|
+
await (0, import_promises9.access)(launchAgentPlistPath(), import_node_fs5.constants.F_OK);
|
|
10253
|
+
return true;
|
|
10254
|
+
} catch (_err) {
|
|
10255
|
+
return false;
|
|
10256
|
+
}
|
|
10257
|
+
}
|
|
10258
|
+
async function readOpenVikingCliVersion(ov) {
|
|
10259
|
+
const result = await runCommand(ov, ["version"], { allowFailure: true });
|
|
10260
|
+
if (result.exitCode !== 0) {
|
|
10261
|
+
return void 0;
|
|
10262
|
+
}
|
|
10263
|
+
const match = result.stdout.match(/^\s*CLI:\s*(\S+)/m);
|
|
10264
|
+
return match ? match[1] : void 0;
|
|
10265
|
+
}
|
|
10132
10266
|
async function getUpdateInfo(config, options) {
|
|
10133
10267
|
const currentVersion = await currentPackageVersion();
|
|
10134
10268
|
const cached = options.preferFresh ? void 0 : await readFreshCache(config, options.registry);
|
|
@@ -10138,7 +10272,7 @@ async function getUpdateInfo(config, options) {
|
|
|
10138
10272
|
}
|
|
10139
10273
|
return {
|
|
10140
10274
|
currentVersion,
|
|
10141
|
-
isUpdateAvailable:
|
|
10275
|
+
isUpdateAvailable: compareVersions(currentVersion, latestVersion) < 0,
|
|
10142
10276
|
latestVersion,
|
|
10143
10277
|
registry: options.registry
|
|
10144
10278
|
};
|
|
@@ -10248,10 +10382,10 @@ async function applicablePostUpdateMigrations(config, options) {
|
|
|
10248
10382
|
if (handled.has(migration.id)) {
|
|
10249
10383
|
continue;
|
|
10250
10384
|
}
|
|
10251
|
-
if (
|
|
10385
|
+
if (compareVersions(options.fromVersion, migration.introducedIn) >= 0) {
|
|
10252
10386
|
continue;
|
|
10253
10387
|
}
|
|
10254
|
-
if (
|
|
10388
|
+
if (compareVersions(migration.introducedIn, options.toVersion) > 0) {
|
|
10255
10389
|
continue;
|
|
10256
10390
|
}
|
|
10257
10391
|
if (migration.requiresLegacyHandoffs === true && !await hasLegacyLifecycleHandoffCandidates(config)) {
|
|
@@ -10300,10 +10434,13 @@ function printPostUpdateMigration(migration) {
|
|
|
10300
10434
|
console.log(`- ${line}`);
|
|
10301
10435
|
}
|
|
10302
10436
|
}
|
|
10303
|
-
async function confirmPostUpdateMigration(prompt) {
|
|
10437
|
+
async function confirmPostUpdateMigration(prompt, defaultYes = false) {
|
|
10304
10438
|
const readline = (0, import_promises10.createInterface)({ input: import_node_process.stdin, output: import_node_process.stdout });
|
|
10305
10439
|
try {
|
|
10306
10440
|
const answer = (await readline.question(prompt)).trim().toLowerCase();
|
|
10441
|
+
if (answer === "") {
|
|
10442
|
+
return defaultYes;
|
|
10443
|
+
}
|
|
10307
10444
|
return answer === "y" || answer === "yes";
|
|
10308
10445
|
} finally {
|
|
10309
10446
|
readline.close();
|
|
@@ -10419,38 +10556,6 @@ function updateRegistry() {
|
|
|
10419
10556
|
function isUpdateNotificationDisabled() {
|
|
10420
10557
|
return process.env.CI !== void 0 || process.env.NO_UPDATE_NOTIFIER !== void 0 || process.env.THREADNOTE_NO_UPDATE_CHECK !== void 0;
|
|
10421
10558
|
}
|
|
10422
|
-
function compareVersions2(currentVersion, latestVersion) {
|
|
10423
|
-
const current = parseVersion2(currentVersion);
|
|
10424
|
-
const latest = parseVersion2(latestVersion);
|
|
10425
|
-
for (let index = 0; index < 3; index += 1) {
|
|
10426
|
-
const difference = current.numbers[index] - latest.numbers[index];
|
|
10427
|
-
if (difference !== 0) {
|
|
10428
|
-
return difference;
|
|
10429
|
-
}
|
|
10430
|
-
}
|
|
10431
|
-
if (current.prerelease === latest.prerelease) {
|
|
10432
|
-
return 0;
|
|
10433
|
-
}
|
|
10434
|
-
if (current.prerelease === void 0) {
|
|
10435
|
-
return 1;
|
|
10436
|
-
}
|
|
10437
|
-
if (latest.prerelease === void 0) {
|
|
10438
|
-
return -1;
|
|
10439
|
-
}
|
|
10440
|
-
return current.prerelease.localeCompare(latest.prerelease);
|
|
10441
|
-
}
|
|
10442
|
-
function parseVersion2(version) {
|
|
10443
|
-
const normalized = version.trim().replace(/^v/, "");
|
|
10444
|
-
const [core2, prerelease] = normalized.split("-", 2);
|
|
10445
|
-
const parts = core2.split(".").map((part) => Number(part));
|
|
10446
|
-
return {
|
|
10447
|
-
numbers: [safeVersionNumber(parts[0]), safeVersionNumber(parts[1]), safeVersionNumber(parts[2])],
|
|
10448
|
-
prerelease
|
|
10449
|
-
};
|
|
10450
|
-
}
|
|
10451
|
-
function safeVersionNumber(value) {
|
|
10452
|
-
return typeof value === "number" && Number.isInteger(value) && value >= 0 ? value : 0;
|
|
10453
|
-
}
|
|
10454
10559
|
|
|
10455
10560
|
// src/lifecycle.ts
|
|
10456
10561
|
async function runDoctor(config, options) {
|
|
@@ -10498,7 +10603,10 @@ async function runInstall(config, options) {
|
|
|
10498
10603
|
console.log(`OpenViking server already installed: ${serverPath}`);
|
|
10499
10604
|
const localEmbeddingMissing = await hasLocalEmbeddingDependency(serverPath) === false;
|
|
10500
10605
|
const pythonSystemCertificatesMissing = await hasPythonSystemCertificatesPatch(serverPath) === false;
|
|
10501
|
-
if (
|
|
10606
|
+
if (options.force === true) {
|
|
10607
|
+
console.log(`Reinstalling OpenViking at pinned version ${config.openVikingVersion} (--force).`);
|
|
10608
|
+
await runInstallCommands(config, options.packageManager, true, dryRun);
|
|
10609
|
+
} else if (localEmbeddingMissing) {
|
|
10502
10610
|
const repairReasons = [];
|
|
10503
10611
|
repairReasons.push("local embedding extra is missing");
|
|
10504
10612
|
if (pythonSystemCertificatesMissing) {
|
|
@@ -11414,7 +11522,7 @@ async function main() {
|
|
|
11414
11522
|
await runDoctor(config, options);
|
|
11415
11523
|
await maybeNotifyUpdate(config, { dryRun: options.dryRun === true });
|
|
11416
11524
|
});
|
|
11417
|
-
program2.command("install").description("Install OpenViking, local config files, command shim, and user-level agent instructions").option("--dry-run", "Print the actions without making changes").option("--no-start", "Do not start OpenViking or check server health after installing").option("--package-manager <manager>", "uv, pipx, or pip", parsePackageManager).option(
|
|
11525
|
+
program2.command("install").description("Install OpenViking, local config files, command shim, and user-level agent instructions").option("--dry-run", "Print the actions without making changes").option("--force", "Reinstall OpenViking at the pinned version even if a working install is already present").option("--no-start", "Do not start OpenViking or check server health after installing").option("--package-manager <manager>", "uv, pipx, or pip", parsePackageManager).option(
|
|
11418
11526
|
"--with-hooks",
|
|
11419
11527
|
"Also install agent-side hooks (Claude PreCompact + SessionStart) for deterministic handoff snapshots and context preload"
|
|
11420
11528
|
).action(async (options) => {
|