threadnote 0.7.2 → 0.7.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.
Files changed (2) hide show
  1. package/dist/threadnote.cjs +100 -50
  2. package/package.json +1 -1
@@ -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.12";
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 compareVersions(args.currentVersion, cached.latestVersion);
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 compareVersions(args.currentVersion, fresh);
9323
+ return compareVersions2(args.currentVersion, fresh);
9292
9324
  }
9293
9325
  if (cached) {
9294
- return compareVersions(args.currentVersion, cached.latestVersion);
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 compareVersions(currentVersion, latestVersion) {
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 = parseVersion(candidate);
9321
- const baselineParts = parseVersion(baseline);
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 parseVersion(value) {
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
- compareVersions2(info.currentVersion, info.latestVersion) > 0 ? "Current version is newer than npm latest." : "Threadnote is up to date."
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,16 @@ 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, {
10128
+ dryRun: options.dryRun === true,
10129
+ interactive,
10130
+ yes: options.yes === true
10131
+ });
10094
10132
  await runApplicablePostUpdateMigrations(config, {
10095
10133
  dryRun: options.dryRun === true,
10096
10134
  fromVersion: options.fromVersion,
10097
- interactive: process.stdin.isTTY === true && process.stdout.isTTY === true,
10135
+ interactive,
10098
10136
  markHandled: true,
10099
10137
  toVersion: options.toVersion,
10100
10138
  yes: options.yes === true
@@ -10102,6 +10140,8 @@ async function runPostUpdate(config, options) {
10102
10140
  }
10103
10141
  async function maybeRunPostUpdateAfterRepair(config, options) {
10104
10142
  const toVersion = await currentPackageVersion();
10143
+ const interactive = process.stdin.isTTY === true && process.stdout.isTTY === true;
10144
+ await ensurePinnedOpenVikingInstalled(config, { dryRun: options.dryRun, interactive, yes: false });
10105
10145
  const state = await readPostUpdateState(config);
10106
10146
  const migrations = await applicablePostUpdateMigrations(config, {
10107
10147
  fromVersion: "0.0.0",
@@ -10114,7 +10154,7 @@ async function maybeRunPostUpdateAfterRepair(config, options) {
10114
10154
  console.log("");
10115
10155
  console.log("Repair found package post-update migrations.");
10116
10156
  console.log("This also covers updates launched by older Threadnote versions that only knew how to run repair.");
10117
- if (process.stdin.isTTY !== true || process.stdout.isTTY !== true) {
10157
+ if (!interactive) {
10118
10158
  console.log(
10119
10159
  "This process is non-interactive, so Threadnote will print the manual migration command instead of prompting."
10120
10160
  );
@@ -10123,12 +10163,48 @@ async function maybeRunPostUpdateAfterRepair(config, options) {
10123
10163
  await runApplicablePostUpdateMigrations(config, {
10124
10164
  dryRun: options.dryRun,
10125
10165
  fromVersion: "0.0.0",
10126
- interactive: process.stdin.isTTY === true && process.stdout.isTTY === true,
10166
+ interactive,
10127
10167
  markHandled: true,
10128
10168
  toVersion,
10129
10169
  yes: false
10130
10170
  });
10131
10171
  }
10172
+ async function ensurePinnedOpenVikingInstalled(config, options) {
10173
+ const ov = await findExecutable(["ov", "openviking"]);
10174
+ if (!ov) {
10175
+ return;
10176
+ }
10177
+ const installedVersion = await readOpenVikingCliVersion(ov);
10178
+ if (!installedVersion) {
10179
+ console.log(`Could not detect OpenViking CLI version via \`${ov} version\`; skipping pinned-version check.`);
10180
+ return;
10181
+ }
10182
+ const pinned = config.openVikingVersion;
10183
+ if (compareVersions(installedVersion, pinned) >= 0) {
10184
+ return;
10185
+ }
10186
+ console.log("");
10187
+ console.log(`OpenViking ${installedVersion} is older than the pinned version ${pinned}.`);
10188
+ console.log(
10189
+ "Upgrading picks up upstream fixes for share-sync reliability (reindex lock acquisition, ov wait timeout)."
10190
+ );
10191
+ const threadnoteCommand = currentThreadnoteCommand() ?? await findExecutable([NPM_PACKAGE_NAME]) ?? NPM_PACKAGE_NAME;
10192
+ const installArgs = ["install", "--force", "--no-start"];
10193
+ const accepted = options.dryRun || options.yes || options.interactive && await confirmPostUpdateMigration(`Upgrade OpenViking to ${pinned} now? [Y/n] `, true);
10194
+ if (!accepted) {
10195
+ console.log(`Skipped. Run manually later: ${formatMigrationCommand(threadnoteCommand, installArgs)}`);
10196
+ return;
10197
+ }
10198
+ await maybeRun(options.dryRun, threadnoteCommand, installArgs);
10199
+ }
10200
+ async function readOpenVikingCliVersion(ov) {
10201
+ const result = await runCommand(ov, ["version"], { allowFailure: true });
10202
+ if (result.exitCode !== 0) {
10203
+ return void 0;
10204
+ }
10205
+ const match = result.stdout.match(/^\s*CLI:\s*(\S+)/m);
10206
+ return match ? match[1] : void 0;
10207
+ }
10132
10208
  async function getUpdateInfo(config, options) {
10133
10209
  const currentVersion = await currentPackageVersion();
10134
10210
  const cached = options.preferFresh ? void 0 : await readFreshCache(config, options.registry);
@@ -10138,7 +10214,7 @@ async function getUpdateInfo(config, options) {
10138
10214
  }
10139
10215
  return {
10140
10216
  currentVersion,
10141
- isUpdateAvailable: compareVersions2(currentVersion, latestVersion) < 0,
10217
+ isUpdateAvailable: compareVersions(currentVersion, latestVersion) < 0,
10142
10218
  latestVersion,
10143
10219
  registry: options.registry
10144
10220
  };
@@ -10248,10 +10324,10 @@ async function applicablePostUpdateMigrations(config, options) {
10248
10324
  if (handled.has(migration.id)) {
10249
10325
  continue;
10250
10326
  }
10251
- if (compareVersions2(options.fromVersion, migration.introducedIn) >= 0) {
10327
+ if (compareVersions(options.fromVersion, migration.introducedIn) >= 0) {
10252
10328
  continue;
10253
10329
  }
10254
- if (compareVersions2(migration.introducedIn, options.toVersion) > 0) {
10330
+ if (compareVersions(migration.introducedIn, options.toVersion) > 0) {
10255
10331
  continue;
10256
10332
  }
10257
10333
  if (migration.requiresLegacyHandoffs === true && !await hasLegacyLifecycleHandoffCandidates(config)) {
@@ -10300,10 +10376,13 @@ function printPostUpdateMigration(migration) {
10300
10376
  console.log(`- ${line}`);
10301
10377
  }
10302
10378
  }
10303
- async function confirmPostUpdateMigration(prompt) {
10379
+ async function confirmPostUpdateMigration(prompt, defaultYes = false) {
10304
10380
  const readline = (0, import_promises10.createInterface)({ input: import_node_process.stdin, output: import_node_process.stdout });
10305
10381
  try {
10306
10382
  const answer = (await readline.question(prompt)).trim().toLowerCase();
10383
+ if (answer === "") {
10384
+ return defaultYes;
10385
+ }
10307
10386
  return answer === "y" || answer === "yes";
10308
10387
  } finally {
10309
10388
  readline.close();
@@ -10419,38 +10498,6 @@ function updateRegistry() {
10419
10498
  function isUpdateNotificationDisabled() {
10420
10499
  return process.env.CI !== void 0 || process.env.NO_UPDATE_NOTIFIER !== void 0 || process.env.THREADNOTE_NO_UPDATE_CHECK !== void 0;
10421
10500
  }
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
10501
 
10455
10502
  // src/lifecycle.ts
10456
10503
  async function runDoctor(config, options) {
@@ -10498,7 +10545,10 @@ async function runInstall(config, options) {
10498
10545
  console.log(`OpenViking server already installed: ${serverPath}`);
10499
10546
  const localEmbeddingMissing = await hasLocalEmbeddingDependency(serverPath) === false;
10500
10547
  const pythonSystemCertificatesMissing = await hasPythonSystemCertificatesPatch(serverPath) === false;
10501
- if (localEmbeddingMissing) {
10548
+ if (options.force === true) {
10549
+ console.log(`Reinstalling OpenViking at pinned version ${config.openVikingVersion} (--force).`);
10550
+ await runInstallCommands(config, options.packageManager, true, dryRun);
10551
+ } else if (localEmbeddingMissing) {
10502
10552
  const repairReasons = [];
10503
10553
  repairReasons.push("local embedding extra is missing");
10504
10554
  if (pythonSystemCertificatesMissing) {
@@ -11414,7 +11464,7 @@ async function main() {
11414
11464
  await runDoctor(config, options);
11415
11465
  await maybeNotifyUpdate(config, { dryRun: options.dryRun === true });
11416
11466
  });
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(
11467
+ 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
11468
  "--with-hooks",
11419
11469
  "Also install agent-side hooks (Claude PreCompact + SessionStart) for deterministic handoff snapshots and context preload"
11420
11470
  ).action(async (options) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "threadnote",
3
- "version": "0.7.2",
3
+ "version": "0.7.3",
4
4
  "type": "commonjs",
5
5
  "main": "dist/threadnote.cjs",
6
6
  "description": "Shared local context and handoffs for development agents",