threadnote 1.1.1 → 1.1.2

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.
@@ -36134,7 +36134,13 @@ function recallSnippet(value) {
36134
36134
  const oneLine = value.replace(/\s+/g, " ").trim();
36135
36135
  return oneLine.length > 180 ? `${oneLine.slice(0, 180)}\u2026` : oneLine;
36136
36136
  }
36137
- function parseRecallHits(output) {
36137
+ function isArchivedMemoryUri(uri) {
36138
+ const documentUri = uri.replace(/#.*$/, "");
36139
+ return /^viking:\/\/user\/[^/]+\/memories\/(?:durable|handoffs|incidents|preferences|smoke)\/archived(?:\/|$)/.test(
36140
+ documentUri
36141
+ );
36142
+ }
36143
+ function parseRecallHits(output, options = {}) {
36138
36144
  const start = output.search(/^\{/m);
36139
36145
  if (start < 0) {
36140
36146
  return [];
@@ -36155,6 +36161,9 @@ function parseRecallHits(output) {
36155
36161
  if (!isJsonObject(item) || typeof item.uri !== "string" || isSummarySidecarUri(item.uri)) {
36156
36162
  continue;
36157
36163
  }
36164
+ if (options.includeArchived !== true && isArchivedMemoryUri(item.uri)) {
36165
+ continue;
36166
+ }
36158
36167
  hits.push({
36159
36168
  contextType: typeof item.context_type === "string" ? item.context_type : "result",
36160
36169
  score: typeof item.score === "number" ? item.score : 0,
@@ -38417,7 +38426,7 @@ function registerSearchTool(server, config2, name, description) {
38417
38426
  uri: external_exports.string().optional().describe("Optional viking:// subtree to search"),
38418
38427
  callerCwd: external_exports.string().optional().describe("Optional absolute caller workspace path used to resolve this/current branch queries"),
38419
38428
  nodeLimit: external_exports.number().int().positive().max(100).optional().describe("Maximum result count"),
38420
- includeArchived: external_exports.boolean().optional().describe("Include archived memories in exact memory/resource matches"),
38429
+ includeArchived: external_exports.boolean().optional().describe("Include archived memories in recall results"),
38421
38430
  threshold: external_exports.number().min(0).max(1).optional().describe(
38422
38431
  "Minimum relevance score 0-1 (default 0.5); lower it (toward 0) to broaden when a recall comes back empty"
38423
38432
  )
@@ -38473,14 +38482,20 @@ async function runRecallTool(config2, params) {
38473
38482
  const limitArgs = params.nodeLimit ? ["--node-limit", String(params.nodeLimit)] : [];
38474
38483
  const threshold = params.threshold ?? RECALL_SCORE_THRESHOLD;
38475
38484
  const pinnedArgs = params.pinnedUri ? ["--uri", params.pinnedUri] : [];
38476
- const base = await recallSearchHits(config2, ["search", query, ...pinnedArgs, ...limitArgs], threshold);
38485
+ const base = await recallSearchHits(
38486
+ config2,
38487
+ ["search", query, ...pinnedArgs, ...limitArgs],
38488
+ threshold,
38489
+ params.includeArchived
38490
+ );
38477
38491
  const passes = [base.hits];
38478
38492
  const seededUri = project ? trimTrailingSlash(project.uri) : void 0;
38479
38493
  if (seededUri?.startsWith("viking://") && seededUri !== params.pinnedUri) {
38480
38494
  const seeded = await recallSearchHits(
38481
38495
  config2,
38482
38496
  ["search", params.query, "--uri", seededUri, ...limitArgs],
38483
- threshold
38497
+ threshold,
38498
+ params.includeArchived
38484
38499
  );
38485
38500
  passes.push(seeded.hits);
38486
38501
  }
@@ -38514,7 +38529,7 @@ async function runRecallTool(config2, params) {
38514
38529
  const onlyErrorNote = !base.ok && !semanticSection && sections.length === 1;
38515
38530
  return { content: [{ type: "text", text: sections.join("\n\n") }], isError: onlyErrorNote || void 0 };
38516
38531
  }
38517
- async function recallSearchHits(config2, searchArgs, threshold) {
38532
+ async function recallSearchHits(config2, searchArgs, threshold, includeArchived) {
38518
38533
  let result = await runOpenVikingTool(config2, [
38519
38534
  ...searchArgs,
38520
38535
  "--threshold",
@@ -38532,7 +38547,7 @@ async function recallSearchHits(config2, searchArgs, threshold) {
38532
38547
  if (result.isError === true) {
38533
38548
  return { errorText: text.trim(), hits: [], ok: false };
38534
38549
  }
38535
- return { errorText: "", hits: parseRecallHits(text), ok: true };
38550
+ return { errorText: "", hits: parseRecallHits(text, { includeArchived }), ok: true };
38536
38551
  }
38537
38552
  async function recallHygieneHintsSection(config2, recallText) {
38538
38553
  const uris = activePersonalMemoryUrisFromText(recallText, config2.user);
@@ -3473,6 +3473,7 @@ var {
3473
3473
  var DEFAULT_HOST = "127.0.0.1";
3474
3474
  var DEFAULT_PORT = 1933;
3475
3475
  var DEFAULT_OPENVIKING_VERSION = "0.3.24";
3476
+ var OPENVIKING_TOOL_PYTHON = "3.12";
3476
3477
  var DEFAULT_ACCOUNT = "local";
3477
3478
  var DEFAULT_AGENT_ID = "threadnote";
3478
3479
  var OPENVIKING_PACKAGE_NAME = "openviking[local-embed]";
@@ -4315,7 +4316,13 @@ function recallSnippet(value) {
4315
4316
  const oneLine = value.replace(/\s+/g, " ").trim();
4316
4317
  return oneLine.length > 180 ? `${oneLine.slice(0, 180)}\u2026` : oneLine;
4317
4318
  }
4318
- function parseRecallHits(output2) {
4319
+ function isArchivedMemoryUri(uri) {
4320
+ const documentUri = uri.replace(/#.*$/, "");
4321
+ return /^viking:\/\/user\/[^/]+\/memories\/(?:durable|handoffs|incidents|preferences|smoke)\/archived(?:\/|$)/.test(
4322
+ documentUri
4323
+ );
4324
+ }
4325
+ function parseRecallHits(output2, options = {}) {
4319
4326
  const start = output2.search(/^\{/m);
4320
4327
  if (start < 0) {
4321
4328
  return [];
@@ -4336,6 +4343,9 @@ function parseRecallHits(output2) {
4336
4343
  if (!isJsonObject(item) || typeof item.uri !== "string" || isSummarySidecarUri(item.uri)) {
4337
4344
  continue;
4338
4345
  }
4346
+ if (options.includeArchived !== true && isArchivedMemoryUri(item.uri)) {
4347
+ continue;
4348
+ }
4339
4349
  hits.push({
4340
4350
  contextType: typeof item.context_type === "string" ? item.context_type : "result",
4341
4351
  score: typeof item.score === "number" ? item.score : 0,
@@ -9960,14 +9970,17 @@ async function runRecall(config, options) {
9960
9970
  if (inferredUri) {
9961
9971
  console.log(`Recall scope: ${inferredUri}`);
9962
9972
  }
9963
- const passes = [await recallSearchHits(config, ov, searchArgs(inferredUri), { dryRun })];
9973
+ const includeArchived = options.includeArchived === true;
9974
+ const passes = [
9975
+ await recallSearchHits(config, ov, searchArgs(inferredUri), { dryRun, includeArchived })
9976
+ ];
9964
9977
  if (options.project && project) {
9965
9978
  const projectMemoryUri = `viking://user/${uriSegment(config.user)}/memories/durable/projects/${uriSegment(project.name)}`;
9966
- passes.push(await recallSearchHits(config, ov, searchArgs(projectMemoryUri), { dryRun }));
9979
+ passes.push(await recallSearchHits(config, ov, searchArgs(projectMemoryUri), { dryRun, includeArchived }));
9967
9980
  }
9968
9981
  const seededUri = project ? trimTrailingSlash(project.uri) : void 0;
9969
9982
  if (seededUri?.startsWith("viking://") && seededUri !== inferredUri && !options.uri && options.inferScope !== false) {
9970
- passes.push(await recallSearchHits(config, ov, searchArgs(seededUri), { dryRun }));
9983
+ passes.push(await recallSearchHits(config, ov, searchArgs(seededUri), { dryRun, includeArchived }));
9971
9984
  }
9972
9985
  const recallOutputs = [];
9973
9986
  const semanticSection = formatRecallHits(mergeRecallHits(passes), nodeLimit ?? 12);
@@ -9978,7 +9991,7 @@ ${semanticSection}`);
9978
9991
  }
9979
9992
  const exactOutput = await printExactMemoryMatches(config, ov, query, {
9980
9993
  dryRun,
9981
- includeArchived: options.includeArchived === true,
9994
+ includeArchived,
9982
9995
  project
9983
9996
  });
9984
9997
  if (exactOutput) {
@@ -10002,7 +10015,7 @@ async function recallSearchHits(config, ov, args, options) {
10002
10015
  console.log(`WARN recall search failed: ${result.stderr.trim() || result.stdout.trim() || "ov search error"}`);
10003
10016
  return [];
10004
10017
  }
10005
- return parseRecallHits(result.stdout);
10018
+ return parseRecallHits(result.stdout, { includeArchived: options.includeArchived });
10006
10019
  }
10007
10020
  function stripAdvancedSearchFlags(args) {
10008
10021
  const stripped = [];
@@ -12442,6 +12455,14 @@ async function runInstall(config, options) {
12442
12455
  serverInstallRan = true;
12443
12456
  }
12444
12457
  const resolvedServerPath = serverInstallRan ? await findOpenVikingServer() : serverPath;
12458
+ if (serverInstallRan && !resolvedServerPath && !dryRun) {
12459
+ const message = `OpenViking install ran but ${OPENVIKING_SERVER_COMMAND} was not found on PATH, in the uv tool bin dir, or ~/.local/bin. Re-run \`threadnote install --force\` (it streams the full build), then \`threadnote doctor\`.`;
12460
+ if (options.requireServerBinary === false) {
12461
+ console.warn(`WARN ${message}`);
12462
+ } else {
12463
+ throw new Error(message);
12464
+ }
12465
+ }
12445
12466
  if (resolvedServerPath && !dryRun) {
12446
12467
  await maybePrintOpenVikingPathHint(resolvedServerPath);
12447
12468
  }
@@ -12478,6 +12499,7 @@ async function runRepair(config, options) {
12478
12499
  packageManager: options.packageManager,
12479
12500
  printNextSteps: false,
12480
12501
  repairInvalidConfigs: true,
12502
+ requireServerBinary: false,
12481
12503
  start: false
12482
12504
  });
12483
12505
  await repairManifest(config, dryRun);
@@ -12832,7 +12854,11 @@ async function openVikingServerCheck() {
12832
12854
  const name = OPENVIKING_SERVER_COMMAND;
12833
12855
  const executable = await findOpenVikingServer();
12834
12856
  if (!executable) {
12835
- return { name, status: "fail", detail: "missing; install will fetch it via uv or pipx" };
12857
+ return {
12858
+ name,
12859
+ status: "fail",
12860
+ detail: "missing; run `threadnote install` to fetch it via uv or pipx (local-embed may compile from source on first install)"
12861
+ };
12836
12862
  }
12837
12863
  const result = await runCommand(executable, ["--help"], { allowFailure: true });
12838
12864
  const onPath = await findExecutable([OPENVIKING_SERVER_COMMAND]);
@@ -13066,7 +13092,36 @@ async function runInstallCommands(config, preferred, force, dryRun) {
13066
13092
  }
13067
13093
  const installCommands = await getInstallCommands(config, manager, force);
13068
13094
  for (const installCommand of installCommands) {
13069
- await maybeRun(dryRun, installCommand.executable, installCommand.args);
13095
+ if (dryRun) {
13096
+ await maybeRun(true, installCommand.executable, installCommand.args);
13097
+ continue;
13098
+ }
13099
+ console.log(`Running: ${formatShellCommand(installCommand.executable, installCommand.args)}`);
13100
+ const exitCode = await runInteractive(installCommand.executable, installCommand.args);
13101
+ if (exitCode !== 0) {
13102
+ printOpenVikingInstallFailureHelp(installCommand);
13103
+ throw new Error(`${formatShellCommand(installCommand.executable, installCommand.args)} exited with ${exitCode}.`);
13104
+ }
13105
+ }
13106
+ }
13107
+ function printOpenVikingInstallFailureHelp(failedCommand) {
13108
+ console.error("");
13109
+ console.error("OpenViking install did not complete.");
13110
+ console.error(
13111
+ "openviking[local-embed] includes llama-cpp-python, which compiles from source when no prebuilt wheel matches your Python/platform \u2014 that build can run 10-20 minutes and is memory-heavy, so it may be killed by the OS (out of memory) or look stuck."
13112
+ );
13113
+ console.error("Re-run it directly to see full output without any wrapper timeout:");
13114
+ console.error(` ${formatShellCommand(failedCommand.executable, failedCommand.args)}`);
13115
+ console.error("Cap memory use during the compile with: CMAKE_BUILD_PARALLEL_LEVEL=2 <command above>");
13116
+ if (failedCommand.executable === "uv") {
13117
+ if (failedCommand.args.includes("--python")) {
13118
+ console.error(
13119
+ "If uv could not fetch a managed CPython (offline or restricted network), drop the version pin and retry: THREADNOTE_OPENVIKING_PYTHON= threadnote install --force"
13120
+ );
13121
+ }
13122
+ console.error("If it was killed mid-build, clear the partial install first, then retry:");
13123
+ console.error(" uv cache clean");
13124
+ console.error(' rm -rf "$(uv tool dir)/openviking"');
13070
13125
  }
13071
13126
  }
13072
13127
  async function offerToInstallUv() {
@@ -13147,12 +13202,33 @@ async function getPythonSystemCertificatesInstallCommand(serverPath) {
13147
13202
  }
13148
13203
  return { executable: pythonPath, args: ["-m", "pip", "install", PYTHON_SYSTEM_CERTS_PACKAGE] };
13149
13204
  }
13205
+ function localEmbedWheelIndexUrl() {
13206
+ const override = process.env.THREADNOTE_LLAMA_WHEEL_INDEX;
13207
+ if (override !== void 0) {
13208
+ return override.trim() === "" ? void 0 : override.trim();
13209
+ }
13210
+ const base = "https://abetlen.github.io/llama-cpp-python/whl";
13211
+ return (0, import_node_os6.platform)() === "darwin" ? `${base}/metal` : `${base}/cpu`;
13212
+ }
13213
+ function openVikingToolPython() {
13214
+ const override = process.env.THREADNOTE_OPENVIKING_PYTHON;
13215
+ if (override !== void 0) {
13216
+ return override.trim() === "" ? void 0 : override.trim();
13217
+ }
13218
+ return OPENVIKING_TOOL_PYTHON;
13219
+ }
13150
13220
  async function getInstallCommands(config, preferred, force) {
13151
13221
  const packageSpec = `${OPENVIKING_PACKAGE_NAME}==${config.openVikingVersion}`;
13222
+ const wheelIndex = localEmbedWheelIndexUrl();
13152
13223
  const manager = preferred ?? await detectPackageManager();
13153
13224
  if (manager === "pipx") {
13225
+ const installArgs = force ? ["install", "--force"] : ["install"];
13226
+ if (wheelIndex) {
13227
+ installArgs.push("--pip-args", `--extra-index-url ${wheelIndex}`);
13228
+ }
13229
+ installArgs.push(packageSpec);
13154
13230
  return [
13155
- { executable: "pipx", args: force ? ["install", "--force", packageSpec] : ["install", packageSpec] },
13231
+ { executable: "pipx", args: installArgs },
13156
13232
  {
13157
13233
  executable: "pipx",
13158
13234
  args: force ? ["inject", "--force", "openviking", PYTHON_SYSTEM_CERTS_PACKAGE] : ["inject", "openviking", PYTHON_SYSTEM_CERTS_PACKAGE]
@@ -13160,7 +13236,16 @@ async function getInstallCommands(config, preferred, force) {
13160
13236
  ];
13161
13237
  }
13162
13238
  if (manager === "uv") {
13163
- const uvArgs = ["tool", "install", "--native-tls", "--with", PYTHON_SYSTEM_CERTS_PACKAGE];
13239
+ const toolPython = openVikingToolPython();
13240
+ const uvArgs = [
13241
+ "tool",
13242
+ "install",
13243
+ "--native-tls",
13244
+ ...toolPython ? ["--python", toolPython] : [],
13245
+ "--with",
13246
+ PYTHON_SYSTEM_CERTS_PACKAGE,
13247
+ ...wheelIndex ? ["--extra-index-url", wheelIndex] : []
13248
+ ];
13164
13249
  return [
13165
13250
  {
13166
13251
  executable: "uv",
@@ -13172,6 +13257,9 @@ async function getInstallCommands(config, preferred, force) {
13172
13257
  if (force) {
13173
13258
  pipArgs.push("--upgrade", "--force-reinstall");
13174
13259
  }
13260
+ if (wheelIndex) {
13261
+ pipArgs.push("--extra-index-url", wheelIndex);
13262
+ }
13175
13263
  pipArgs.push(PYTHON_SYSTEM_CERTS_PACKAGE);
13176
13264
  pipArgs.push(packageSpec);
13177
13265
  return [{ executable: "python3", args: pipArgs }];
@@ -14690,7 +14778,7 @@ async function main() {
14690
14778
  program2.command("migrate-lifecycle").description("Move clear legacy handoff memories into lifecycle-aware archive paths").option("--apply", "Perform the migration; without this, prints a dry run").option("--dry-run", "Print migration actions without writing or removing memories").option("--limit <count>", "Maximum number of legacy handoffs to migrate").action(async (options) => {
14691
14779
  await runMigrateLifecycle(getRuntimeConfig(program2), options);
14692
14780
  });
14693
- program2.command("recall").description("Search shared OpenViking context").requiredOption("--query <query>", "Search query").option("--dry-run", "Print ov command without searching").option("--include-archived", "Include archived memories in exact memory/resource matches").option("-n, --node-limit <count>", "Maximum number of search results").option("--no-infer-scope", "Disable query-based scope inference").option("--project <name>", "Prioritize a project: add a scoped pass over its memories alongside the global search").option("--threshold <score>", "Minimum relevance score 0-1 (default 0.45); lower to broaden when recall is empty").option("--uri <uri>", "Restrict search to a viking:// URI").action(async (options) => {
14781
+ program2.command("recall").description("Search shared OpenViking context").requiredOption("--query <query>", "Search query").option("--dry-run", "Print ov command without searching").option("--include-archived", "Include archived memories in recall results").option("-n, --node-limit <count>", "Maximum number of search results").option("--no-infer-scope", "Disable query-based scope inference").option("--project <name>", "Prioritize a project: add a scoped pass over its memories alongside the global search").option("--threshold <score>", "Minimum relevance score 0-1 (default 0.45); lower to broaden when recall is empty").option("--uri <uri>", "Restrict search to a viking:// URI").action(async (options) => {
14694
14782
  await runRecall(getRuntimeConfig(program2), options);
14695
14783
  });
14696
14784
  program2.command("compact").description("Plan or apply scoped memory hygiene for active personal memories").requiredOption("--project <name>", "Project/repo namespace to inspect").option("--apply", "Apply the compact plan; without this, prints a dry run").option("--dry-run", "Print the compact plan without changing anything").option("--kind <kind>", "durable, handoff, or incident", parseCompactKind).option("--topic <name>", "Stable topic name to inspect").action(async (options) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "threadnote",
3
- "version": "1.1.1",
3
+ "version": "1.1.2",
4
4
  "type": "commonjs",
5
5
  "main": "dist/threadnote.cjs",
6
6
  "description": "Shared local context and handoffs for development agents",