threadnote 1.4.0 → 1.4.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.
- package/dist/mcp_server.cjs +123 -18
- package/dist/threadnote.cjs +25 -20
- package/package.json +1 -1
package/dist/mcp_server.cjs
CHANGED
|
@@ -35689,6 +35689,9 @@ function commandResultFromExecFileCallback(params) {
|
|
|
35689
35689
|
function defaultCommandTimeoutMs() {
|
|
35690
35690
|
return positiveIntegerFromEnv("THREADNOTE_COMMAND_TIMEOUT_MS") ?? 10 * 60 * 1e3;
|
|
35691
35691
|
}
|
|
35692
|
+
function reindexWaitTimeoutMs() {
|
|
35693
|
+
return positiveIntegerFromEnv("THREADNOTE_REINDEX_TIMEOUT_MS") ?? 12e4;
|
|
35694
|
+
}
|
|
35692
35695
|
function defaultCommandMaxOutputBytes() {
|
|
35693
35696
|
return positiveIntegerFromEnv("THREADNOTE_COMMAND_MAX_OUTPUT_BYTES") ?? 5 * 1024 * 1024;
|
|
35694
35697
|
}
|
|
@@ -35712,6 +35715,57 @@ async function sleep(ms) {
|
|
|
35712
35715
|
setTimeout(resolvePromise, ms);
|
|
35713
35716
|
});
|
|
35714
35717
|
}
|
|
35718
|
+
function compareVersions(a, b) {
|
|
35719
|
+
const left = parseVersion(a);
|
|
35720
|
+
const right = parseVersion(b);
|
|
35721
|
+
for (let index = 0; index < 3; index += 1) {
|
|
35722
|
+
const difference = left.numbers[index] - right.numbers[index];
|
|
35723
|
+
if (difference !== 0) {
|
|
35724
|
+
return difference;
|
|
35725
|
+
}
|
|
35726
|
+
}
|
|
35727
|
+
const rankDelta = suffixRank(left.suffix) - suffixRank(right.suffix);
|
|
35728
|
+
if (rankDelta !== 0) {
|
|
35729
|
+
return rankDelta;
|
|
35730
|
+
}
|
|
35731
|
+
if (left.suffix === right.suffix) {
|
|
35732
|
+
return 0;
|
|
35733
|
+
}
|
|
35734
|
+
return (left.suffix ?? "").localeCompare(right.suffix ?? "");
|
|
35735
|
+
}
|
|
35736
|
+
function suffixRank(suffix) {
|
|
35737
|
+
if (suffix === void 0) {
|
|
35738
|
+
return 0;
|
|
35739
|
+
}
|
|
35740
|
+
return /^post/i.test(suffix) ? 1 : -1;
|
|
35741
|
+
}
|
|
35742
|
+
function parseVersion(version2) {
|
|
35743
|
+
const normalized = version2.trim().replace(/^v/, "").split("+", 1)[0];
|
|
35744
|
+
const core = normalized.match(/^\d+(?:\.\d+){0,2}/)?.[0] ?? "";
|
|
35745
|
+
const rawSuffix = normalized.slice(core.length).replace(/^[-_.]/, "");
|
|
35746
|
+
const suffix = core.length > 0 && rawSuffix.length > 0 ? rawSuffix : void 0;
|
|
35747
|
+
const parts = core.split(".");
|
|
35748
|
+
return {
|
|
35749
|
+
numbers: [
|
|
35750
|
+
safeVersionNumber(Number.parseInt(parts[0] ?? "", 10)),
|
|
35751
|
+
safeVersionNumber(Number.parseInt(parts[1] ?? "", 10)),
|
|
35752
|
+
safeVersionNumber(Number.parseInt(parts[2] ?? "", 10))
|
|
35753
|
+
],
|
|
35754
|
+
suffix
|
|
35755
|
+
};
|
|
35756
|
+
}
|
|
35757
|
+
function safeVersionNumber(value) {
|
|
35758
|
+
return typeof value === "number" && Number.isInteger(value) && value >= 0 ? value : 0;
|
|
35759
|
+
}
|
|
35760
|
+
function formatStaleVersionNotice(runningVersion, diskVersion) {
|
|
35761
|
+
if (runningVersion === void 0 || diskVersion === void 0) {
|
|
35762
|
+
return void 0;
|
|
35763
|
+
}
|
|
35764
|
+
if (compareVersions(diskVersion, runningVersion) <= 0) {
|
|
35765
|
+
return void 0;
|
|
35766
|
+
}
|
|
35767
|
+
return `threadnote ${diskVersion} is installed but this MCP server is still running ${runningVersion}. Reconnect the threadnote MCP server (e.g. /mcp) to load the update.`;
|
|
35768
|
+
}
|
|
35715
35769
|
async function ensureDirectory(path, dryRun) {
|
|
35716
35770
|
if (dryRun) {
|
|
35717
35771
|
console.log(`Would create directory: ${path}`);
|
|
@@ -36215,6 +36269,20 @@ function shellQuote(value) {
|
|
|
36215
36269
|
}
|
|
36216
36270
|
return `'${value.replaceAll("'", `'"'"'`)}'`;
|
|
36217
36271
|
}
|
|
36272
|
+
function toolRoot() {
|
|
36273
|
+
if ((0, import_node_fs.existsSync)((0, import_node_path.join)(__dirname, "package.json"))) {
|
|
36274
|
+
return __dirname;
|
|
36275
|
+
}
|
|
36276
|
+
return (0, import_node_path.resolve)(__dirname, "..");
|
|
36277
|
+
}
|
|
36278
|
+
async function currentPackageVersion() {
|
|
36279
|
+
const rawPackage = await (0, import_promises.readFile)((0, import_node_path.join)(toolRoot(), "package.json"), "utf8");
|
|
36280
|
+
const parsed = JSON.parse(rawPackage);
|
|
36281
|
+
if (!isJsonObject(parsed) || typeof parsed.version !== "string") {
|
|
36282
|
+
throw new Error("Could not read current threadnote package version.");
|
|
36283
|
+
}
|
|
36284
|
+
return parsed.version;
|
|
36285
|
+
}
|
|
36218
36286
|
function errorMessage(err) {
|
|
36219
36287
|
return err instanceof Error ? err.message : String(err);
|
|
36220
36288
|
}
|
|
@@ -36290,7 +36358,7 @@ function readStringArray(object3, key) {
|
|
|
36290
36358
|
|
|
36291
36359
|
// src/runtime.ts
|
|
36292
36360
|
function withIdentity(config2, args) {
|
|
36293
|
-
return [...args, "--account", config2.account, "--user", config2.user
|
|
36361
|
+
return [...args, "--account", config2.account, "--user", config2.user];
|
|
36294
36362
|
}
|
|
36295
36363
|
|
|
36296
36364
|
// src/index_repair.ts
|
|
@@ -36334,7 +36402,11 @@ async function repairStaleRecallIndex(config2, ov, options = {}) {
|
|
|
36334
36402
|
const result = await runCommand(
|
|
36335
36403
|
ov,
|
|
36336
36404
|
withIdentity(config2, ["reindex", target.uri, "--mode", "semantic_and_vectors", "--wait", "true"]),
|
|
36337
|
-
|
|
36405
|
+
// Bound the wait: `ov reindex` has no --timeout, so a stuck/poisoned
|
|
36406
|
+
// semantic queue would block each target for the full 10-min command
|
|
36407
|
+
// timeout. A timed-out target counts as a failure and trips the
|
|
36408
|
+
// consecutive-failure stop instead of hanging the whole repair.
|
|
36409
|
+
{ allowFailure: true, timeoutMs: reindexWaitTimeoutMs() }
|
|
36338
36410
|
);
|
|
36339
36411
|
if (result.exitCode === 0) {
|
|
36340
36412
|
consecutiveFailures = 0;
|
|
@@ -38580,7 +38652,7 @@ async function refreshMemoryIndex(config2, ov, uri, options = {}) {
|
|
|
38580
38652
|
const result = await runCommand(
|
|
38581
38653
|
ov,
|
|
38582
38654
|
withIdentity(config2, ["reindex", uri, "--mode", "vectors_only", "--wait", "true"]),
|
|
38583
|
-
{ allowFailure: true }
|
|
38655
|
+
{ allowFailure: true, timeoutMs: reindexWaitTimeoutMs() }
|
|
38584
38656
|
);
|
|
38585
38657
|
if (result.exitCode === 0) {
|
|
38586
38658
|
if (options.quiet !== true && result.stdout.trim()) {
|
|
@@ -39260,8 +39332,36 @@ function formatPlanSection(title, lines) {
|
|
|
39260
39332
|
}
|
|
39261
39333
|
|
|
39262
39334
|
// src/mcp_server.ts
|
|
39335
|
+
var mcpStartupVersion;
|
|
39336
|
+
var staleNoticeCache;
|
|
39337
|
+
var STALE_NOTICE_TTL_MS = 6e4;
|
|
39338
|
+
async function staleVersionNotice() {
|
|
39339
|
+
if (mcpStartupVersion === void 0) {
|
|
39340
|
+
return void 0;
|
|
39341
|
+
}
|
|
39342
|
+
const nowMs = Date.now();
|
|
39343
|
+
if (staleNoticeCache && nowMs - staleNoticeCache.checkedAtMs < STALE_NOTICE_TTL_MS) {
|
|
39344
|
+
return staleNoticeCache.notice;
|
|
39345
|
+
}
|
|
39346
|
+
let notice;
|
|
39347
|
+
try {
|
|
39348
|
+
notice = formatStaleVersionNotice(mcpStartupVersion, await currentPackageVersion());
|
|
39349
|
+
} catch {
|
|
39350
|
+
notice = void 0;
|
|
39351
|
+
}
|
|
39352
|
+
staleNoticeCache = { checkedAtMs: nowMs, notice };
|
|
39353
|
+
return notice;
|
|
39354
|
+
}
|
|
39355
|
+
async function withStaleVersionNotice(result) {
|
|
39356
|
+
const notice = await staleVersionNotice();
|
|
39357
|
+
if (notice === void 0) {
|
|
39358
|
+
return result;
|
|
39359
|
+
}
|
|
39360
|
+
return { ...result, content: [...result.content ?? [], { type: "text", text: `\u26A0 ${notice}` }] };
|
|
39361
|
+
}
|
|
39263
39362
|
async function main() {
|
|
39264
39363
|
const config2 = getRuntimeConfig();
|
|
39364
|
+
mcpStartupVersion = await currentPackageVersion().catch(() => void 0);
|
|
39265
39365
|
const server = new McpServer(
|
|
39266
39366
|
{ name: "threadnote-local-adapter", version: "0.2.0" },
|
|
39267
39367
|
{
|
|
@@ -39459,7 +39559,7 @@ function registerTools(server, config2) {
|
|
|
39459
39559
|
description: "Check OpenViking server health through the CLI.",
|
|
39460
39560
|
inputSchema: {}
|
|
39461
39561
|
},
|
|
39462
|
-
async () => runOpenVikingMcpTool(config2, "health", {})
|
|
39562
|
+
async () => withStaleVersionNotice(await runOpenVikingMcpTool(config2, "health", {}))
|
|
39463
39563
|
);
|
|
39464
39564
|
registerOpenVikingParityTools(server, config2);
|
|
39465
39565
|
server.registerTool(
|
|
@@ -39952,14 +40052,16 @@ function registerSearchTool(server, config2, name, description) {
|
|
|
39952
40052
|
if (!checkedUri.ok) {
|
|
39953
40053
|
return checkedUri.error;
|
|
39954
40054
|
}
|
|
39955
|
-
return
|
|
39956
|
-
|
|
39957
|
-
|
|
39958
|
-
|
|
39959
|
-
|
|
39960
|
-
|
|
39961
|
-
|
|
39962
|
-
|
|
40055
|
+
return withStaleVersionNotice(
|
|
40056
|
+
await runRecallTool(config2, {
|
|
40057
|
+
callerCwd,
|
|
40058
|
+
query: checkedQuery.value,
|
|
40059
|
+
pinnedUri: checkedUri.value,
|
|
40060
|
+
nodeLimit,
|
|
40061
|
+
includeArchived: includeArchived === true,
|
|
40062
|
+
threshold: threshold === void 0 ? void 0 : String(threshold)
|
|
40063
|
+
})
|
|
40064
|
+
);
|
|
39963
40065
|
}
|
|
39964
40066
|
);
|
|
39965
40067
|
}
|
|
@@ -40187,11 +40289,13 @@ function registerStoreTool(server, config2, name, description) {
|
|
|
40187
40289
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
40188
40290
|
topic: normalizeOptionalMetadata2(topic)
|
|
40189
40291
|
};
|
|
40190
|
-
return
|
|
40191
|
-
|
|
40192
|
-
|
|
40193
|
-
|
|
40194
|
-
|
|
40292
|
+
return withStaleVersionNotice(
|
|
40293
|
+
await writeDurableMemory(config2, {
|
|
40294
|
+
bodyText: checkedText.value,
|
|
40295
|
+
metadata,
|
|
40296
|
+
replaceUri: checkedReplaceUri.value
|
|
40297
|
+
})
|
|
40298
|
+
);
|
|
40195
40299
|
}
|
|
40196
40300
|
);
|
|
40197
40301
|
}
|
|
@@ -40814,8 +40918,9 @@ async function runOpenVikingMcpTool(config2, toolName, args) {
|
|
|
40814
40918
|
const transport = new StreamableHTTPClientTransport(new URL(config2.openVikingMcpUrl), {
|
|
40815
40919
|
requestInit: {
|
|
40816
40920
|
headers: {
|
|
40921
|
+
// OpenViking 0.4.x dropped agent_id as an identity input; only
|
|
40922
|
+
// account + user are honored (mirrors withIdentity in runtime.ts).
|
|
40817
40923
|
"X-OpenViking-Account": config2.account,
|
|
40818
|
-
"X-OpenViking-Agent": config2.agentId,
|
|
40819
40924
|
"X-OpenViking-User": config2.user
|
|
40820
40925
|
}
|
|
40821
40926
|
}
|
package/dist/threadnote.cjs
CHANGED
|
@@ -3835,6 +3835,9 @@ function commandResultFromExecFileCallback(params) {
|
|
|
3835
3835
|
function defaultCommandTimeoutMs() {
|
|
3836
3836
|
return positiveIntegerFromEnv("THREADNOTE_COMMAND_TIMEOUT_MS") ?? 10 * 60 * 1e3;
|
|
3837
3837
|
}
|
|
3838
|
+
function reindexWaitTimeoutMs() {
|
|
3839
|
+
return positiveIntegerFromEnv("THREADNOTE_REINDEX_TIMEOUT_MS") ?? 12e4;
|
|
3840
|
+
}
|
|
3838
3841
|
function defaultCommandMaxOutputBytes() {
|
|
3839
3842
|
return positiveIntegerFromEnv("THREADNOTE_COMMAND_MAX_OUTPUT_BYTES") ?? 5 * 1024 * 1024;
|
|
3840
3843
|
}
|
|
@@ -4580,6 +4583,14 @@ function toolRoot() {
|
|
|
4580
4583
|
}
|
|
4581
4584
|
return (0, import_node_path2.resolve)(__dirname, "..");
|
|
4582
4585
|
}
|
|
4586
|
+
async function currentPackageVersion() {
|
|
4587
|
+
const rawPackage = await (0, import_promises.readFile)((0, import_node_path2.join)(toolRoot(), "package.json"), "utf8");
|
|
4588
|
+
const parsed = JSON.parse(rawPackage);
|
|
4589
|
+
if (!isJsonObject(parsed) || typeof parsed.version !== "string") {
|
|
4590
|
+
throw new Error("Could not read current threadnote package version.");
|
|
4591
|
+
}
|
|
4592
|
+
return parsed.version;
|
|
4593
|
+
}
|
|
4583
4594
|
function errorMessage(err) {
|
|
4584
4595
|
return err instanceof Error ? err.message : String(err);
|
|
4585
4596
|
}
|
|
@@ -7548,7 +7559,7 @@ function openVikingServerArgs(config) {
|
|
|
7548
7559
|
return ["--config", (0, import_node_path4.join)(config.agentContextHome, "ov.conf"), "--host", config.host, "--port", String(config.port)];
|
|
7549
7560
|
}
|
|
7550
7561
|
function withIdentity(config, args) {
|
|
7551
|
-
return [...args, "--account", config.account, "--user", config.user
|
|
7562
|
+
return [...args, "--account", config.account, "--user", config.user];
|
|
7552
7563
|
}
|
|
7553
7564
|
function renderTemplate(template, config, extras = {}) {
|
|
7554
7565
|
let rendered = template.replaceAll("{{THREADNOTE_HOME}}", config.agentContextHome).replaceAll("{{OPENVIKING_ACCOUNT}}", config.account).replaceAll("{{OPENVIKING_AGENT_ID}}", config.agentId).replaceAll("{{OPENVIKING_HOST}}", config.host).replaceAll("{{OPENVIKING_PORT}}", String(config.port)).replaceAll("{{OPENVIKING_USER}}", config.user);
|
|
@@ -7602,7 +7613,11 @@ async function repairStaleRecallIndex(config, ov, options = {}) {
|
|
|
7602
7613
|
const result = await runCommand(
|
|
7603
7614
|
ov,
|
|
7604
7615
|
withIdentity(config, ["reindex", target.uri, "--mode", "semantic_and_vectors", "--wait", "true"]),
|
|
7605
|
-
|
|
7616
|
+
// Bound the wait: `ov reindex` has no --timeout, so a stuck/poisoned
|
|
7617
|
+
// semantic queue would block each target for the full 10-min command
|
|
7618
|
+
// timeout. A timed-out target counts as a failure and trips the
|
|
7619
|
+
// consecutive-failure stop instead of hanging the whole repair.
|
|
7620
|
+
{ allowFailure: true, timeoutMs: reindexWaitTimeoutMs() }
|
|
7606
7621
|
);
|
|
7607
7622
|
if (result.exitCode === 0) {
|
|
7608
7623
|
consecutiveFailures = 0;
|
|
@@ -10905,7 +10920,7 @@ async function refreshMemoryIndex(config, ov, uri, options = {}) {
|
|
|
10905
10920
|
const result = await runCommand(
|
|
10906
10921
|
ov,
|
|
10907
10922
|
withIdentity(config, ["reindex", uri, "--mode", "vectors_only", "--wait", "true"]),
|
|
10908
|
-
{ allowFailure: true }
|
|
10923
|
+
{ allowFailure: true, timeoutMs: reindexWaitTimeoutMs() }
|
|
10909
10924
|
);
|
|
10910
10925
|
if (result.exitCode === 0) {
|
|
10911
10926
|
if (options.quiet !== true && result.stdout.trim()) {
|
|
@@ -13423,14 +13438,6 @@ async function getUpdateInfo(config, options) {
|
|
|
13423
13438
|
registry: options.registry
|
|
13424
13439
|
};
|
|
13425
13440
|
}
|
|
13426
|
-
async function currentPackageVersion() {
|
|
13427
|
-
const rawPackage = await (0, import_promises10.readFile)((0, import_node_path13.join)(toolRoot(), "package.json"), "utf8");
|
|
13428
|
-
const parsed = JSON.parse(rawPackage);
|
|
13429
|
-
if (!isJsonObject(parsed) || typeof parsed.version !== "string") {
|
|
13430
|
-
throw new Error("Could not read current threadnote package version.");
|
|
13431
|
-
}
|
|
13432
|
-
return parsed.version;
|
|
13433
|
-
}
|
|
13434
13441
|
async function fetchLatestVersion2(registry) {
|
|
13435
13442
|
const url = new URL(`${NPM_PACKAGE_NAME}/latest`, normalizeRegistry(registry));
|
|
13436
13443
|
const controller = new AbortController();
|
|
@@ -14256,22 +14263,20 @@ async function recallShapeCheck(config) {
|
|
|
14256
14263
|
if (result.exitCode !== 0) {
|
|
14257
14264
|
return { name: "recall shape", status: "warn", detail: "search failed; run threadnote repair" };
|
|
14258
14265
|
}
|
|
14259
|
-
|
|
14266
|
+
const start = result.stdout.search(/^\{/m);
|
|
14267
|
+
let envelope;
|
|
14260
14268
|
try {
|
|
14261
|
-
parsed = JSON.parse(result.stdout.
|
|
14269
|
+
const parsed = start >= 0 ? JSON.parse(result.stdout.slice(start)) : void 0;
|
|
14270
|
+
envelope = isJsonObject(parsed) ? parsed.result : void 0;
|
|
14262
14271
|
} catch {
|
|
14263
|
-
|
|
14264
|
-
name: "recall shape",
|
|
14265
|
-
status: "warn",
|
|
14266
|
-
detail: "search output is not JSON; recall may silently return nothing"
|
|
14267
|
-
};
|
|
14272
|
+
envelope = void 0;
|
|
14268
14273
|
}
|
|
14269
14274
|
const buckets = ["memories", "resources", "skills"];
|
|
14270
|
-
if (!isJsonObject(
|
|
14275
|
+
if (!isJsonObject(envelope) || !buckets.some((key) => Array.isArray(envelope[key]))) {
|
|
14271
14276
|
return {
|
|
14272
14277
|
name: "recall shape",
|
|
14273
14278
|
status: "warn",
|
|
14274
|
-
detail: `search JSON missing ${buckets.join("
|
|
14279
|
+
detail: `search JSON missing the result.{${buckets.join(",")}} buckets recall parsing depends on`
|
|
14275
14280
|
};
|
|
14276
14281
|
}
|
|
14277
14282
|
return { name: "recall shape", status: "ok", detail: "memories/resources/skills buckets present" };
|