threadnote 1.3.3 → 1.4.0
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 +9 -14
- package/dist/threadnote.cjs +104 -41
- package/docs/agent-instructions.md +2 -2
- package/docs/index.html +2 -2
- package/docs/migration.md +6 -0
- package/package.json +1 -1
package/dist/mcp_server.cjs
CHANGED
|
@@ -39359,7 +39359,7 @@ function registerTools(server, config2) {
|
|
|
39359
39359
|
}
|
|
39360
39360
|
},
|
|
39361
39361
|
async ({ recursive, uri }) => {
|
|
39362
|
-
const checkedUri = requiredVikingUri(uri, "forget", "viking://
|
|
39362
|
+
const checkedUri = requiredVikingUri(uri, "forget", "viking://user/you/memories/example.md");
|
|
39363
39363
|
if (!checkedUri.ok) {
|
|
39364
39364
|
return checkedUri.error;
|
|
39365
39365
|
}
|
|
@@ -39603,8 +39603,6 @@ function registerOpenVikingParityTools(server, config2) {
|
|
|
39603
39603
|
limit: external_exports.number().int().positive().max(1e3).optional().describe("Maximum result count"),
|
|
39604
39604
|
minScore: external_exports.number().min(0).max(1).optional().describe("Minimum score threshold"),
|
|
39605
39605
|
min_score: external_exports.number().min(0).max(1).optional().describe("Minimum score threshold"),
|
|
39606
|
-
peerId: external_exports.string().optional().describe("Optional native peer id"),
|
|
39607
|
-
peer_id: external_exports.string().optional().describe("Optional native peer id"),
|
|
39608
39606
|
query: external_exports.string().optional().describe("Required search query"),
|
|
39609
39607
|
sessionId: external_exports.string().optional().describe("Optional native session id"),
|
|
39610
39608
|
session_id: external_exports.string().optional().describe("Optional native session id"),
|
|
@@ -40081,7 +40079,7 @@ async function collectExactMemoryMatches(config2, query, includeArchived, projec
|
|
|
40081
40079
|
return collectExactMatches(terms, scopes, async (term, scope) => {
|
|
40082
40080
|
const result = await runCommand(
|
|
40083
40081
|
ov,
|
|
40084
|
-
|
|
40082
|
+
withIdentity(config2, ["grep", term, "--uri", scope, "--node-limit", "5", "--output", "json"]),
|
|
40085
40083
|
{ allowFailure: true }
|
|
40086
40084
|
);
|
|
40087
40085
|
return result.exitCode === 0 ? result.stdout : void 0;
|
|
@@ -40099,7 +40097,7 @@ function registerReadTool(server, config2, name, description) {
|
|
|
40099
40097
|
}
|
|
40100
40098
|
},
|
|
40101
40099
|
async ({ uri, uris }) => {
|
|
40102
|
-
const checkedUris = requiredVikingUriList(uris ?? uri, name, "viking://
|
|
40100
|
+
const checkedUris = requiredVikingUriList(uris ?? uri, name, "viking://user/you/memories/.abstract.md");
|
|
40103
40101
|
if (!checkedUris.ok) {
|
|
40104
40102
|
return checkedUris.error;
|
|
40105
40103
|
}
|
|
@@ -40526,11 +40524,11 @@ async function writeSharedMemoryReplacement(config2, ov, params, targetUri) {
|
|
|
40526
40524
|
return { content: [{ type: "text", text: messages.join("\n") }] };
|
|
40527
40525
|
}
|
|
40528
40526
|
async function vikingResourceExists2(ov, config2, uri) {
|
|
40529
|
-
const stat2 = await runCommand(ov,
|
|
40527
|
+
const stat2 = await runCommand(ov, withIdentity(config2, ["stat", uri]), { allowFailure: true });
|
|
40530
40528
|
return stat2.exitCode === 0;
|
|
40531
40529
|
}
|
|
40532
40530
|
async function removeVikingResourceWithRetry(ov, config2, uri, recursive = false) {
|
|
40533
|
-
const args =
|
|
40531
|
+
const args = withIdentity(config2, ["rm", uri, ...recursive ? ["--recursive"] : []]);
|
|
40534
40532
|
for (let attempt = 0; attempt < 4; attempt += 1) {
|
|
40535
40533
|
const result = await runCommand(ov, args, { allowFailure: true });
|
|
40536
40534
|
if (result.exitCode === 0) {
|
|
@@ -40570,13 +40568,13 @@ ${stdout2}`.toLowerCase();
|
|
|
40570
40568
|
}
|
|
40571
40569
|
async function ensureMemoryDirectory(ov, config2, directoryUri) {
|
|
40572
40570
|
for (const uri of vikingDirectoryChain(directoryUri)) {
|
|
40573
|
-
const statResult = await runCommand(ov,
|
|
40571
|
+
const statResult = await runCommand(ov, withIdentity(config2, ["stat", uri]), { allowFailure: true });
|
|
40574
40572
|
if (statResult.exitCode === 0) {
|
|
40575
40573
|
continue;
|
|
40576
40574
|
}
|
|
40577
40575
|
await runCommand(
|
|
40578
40576
|
ov,
|
|
40579
|
-
|
|
40577
|
+
withIdentity(config2, ["mkdir", uri, "--description", "Threadnote lifecycle-aware local memories."])
|
|
40580
40578
|
);
|
|
40581
40579
|
}
|
|
40582
40580
|
}
|
|
@@ -40793,7 +40791,7 @@ ${text}`);
|
|
|
40793
40791
|
async function runOpenVikingCliReadTool(config2, uri) {
|
|
40794
40792
|
try {
|
|
40795
40793
|
const ov = await requiredOpenVikingCli2();
|
|
40796
|
-
const result = await runCommand(ov,
|
|
40794
|
+
const result = await runCommand(ov, withIdentity(config2, ["read", uri]));
|
|
40797
40795
|
const text = [result.stdout.trim(), result.stderr.trim()].filter(Boolean).join("\n");
|
|
40798
40796
|
return { content: [{ type: "text", text: text || "OK" }] };
|
|
40799
40797
|
} catch (err) {
|
|
@@ -40803,7 +40801,7 @@ async function runOpenVikingCliReadTool(config2, uri) {
|
|
|
40803
40801
|
async function runOpenVikingTool(config2, args) {
|
|
40804
40802
|
try {
|
|
40805
40803
|
const ov = await requiredOpenVikingCli2();
|
|
40806
|
-
const result = await runCommand(ov,
|
|
40804
|
+
const result = await runCommand(ov, withIdentity(config2, args));
|
|
40807
40805
|
const text = [result.stdout.trim(), result.stderr.trim()].filter(Boolean).join("\n");
|
|
40808
40806
|
return { content: [{ type: "text", text: text || "OK" }] };
|
|
40809
40807
|
} catch (err) {
|
|
@@ -41048,9 +41046,6 @@ function shareArtifactToolHeader(team, syncedTeams, warnings) {
|
|
|
41048
41046
|
}
|
|
41049
41047
|
return lines;
|
|
41050
41048
|
}
|
|
41051
|
-
function withIdentity2(config2, args) {
|
|
41052
|
-
return [...args, "--account", config2.account, "--user", config2.user, "--agent-id", config2.agentId];
|
|
41053
|
-
}
|
|
41054
41049
|
async function requiredOpenVikingCli2() {
|
|
41055
41050
|
const command2 = await findOpenVikingCli();
|
|
41056
41051
|
if (!command2) {
|
package/dist/threadnote.cjs
CHANGED
|
@@ -3394,7 +3394,7 @@ var program = new Command();
|
|
|
3394
3394
|
// src/constants.ts
|
|
3395
3395
|
var DEFAULT_HOST = "127.0.0.1";
|
|
3396
3396
|
var DEFAULT_PORT = 1933;
|
|
3397
|
-
var DEFAULT_OPENVIKING_VERSION = "0.
|
|
3397
|
+
var DEFAULT_OPENVIKING_VERSION = "0.4.4";
|
|
3398
3398
|
var OPENVIKING_TOOL_PYTHON = "3.12";
|
|
3399
3399
|
var DEFAULT_ACCOUNT = "local";
|
|
3400
3400
|
var DEFAULT_AGENT_ID = "threadnote";
|
|
@@ -3412,6 +3412,7 @@ var USER_INSTRUCTIONS_START_MARKER = "<!-- BEGIN THREADNOTE USER INSTRUCTIONS --
|
|
|
3412
3412
|
var USER_INSTRUCTIONS_END_MARKER = "<!-- END THREADNOTE USER INSTRUCTIONS -->";
|
|
3413
3413
|
var USER_MANIFEST_NAME = "seed-manifest.yaml";
|
|
3414
3414
|
var SEED_STATE_FILE = "seed-state.json";
|
|
3415
|
+
var SEED_WATCH_INTERVAL_ENV = "THREADNOTE_SEED_WATCH_INTERVAL";
|
|
3415
3416
|
var USER_AGENT_INSTRUCTION_TARGETS = [
|
|
3416
3417
|
{ kind: "block", label: "codex user instructions", path: "~/.codex/AGENTS.md" },
|
|
3417
3418
|
{ kind: "block", label: "claude user instructions", path: "~/.claude/CLAUDE.md" },
|
|
@@ -3915,24 +3916,34 @@ function compareVersions(a, b) {
|
|
|
3915
3916
|
return difference;
|
|
3916
3917
|
}
|
|
3917
3918
|
}
|
|
3918
|
-
|
|
3919
|
-
|
|
3919
|
+
const rankDelta = suffixRank(left.suffix) - suffixRank(right.suffix);
|
|
3920
|
+
if (rankDelta !== 0) {
|
|
3921
|
+
return rankDelta;
|
|
3920
3922
|
}
|
|
3921
|
-
if (left.
|
|
3922
|
-
return
|
|
3923
|
+
if (left.suffix === right.suffix) {
|
|
3924
|
+
return 0;
|
|
3923
3925
|
}
|
|
3924
|
-
|
|
3925
|
-
|
|
3926
|
+
return (left.suffix ?? "").localeCompare(right.suffix ?? "");
|
|
3927
|
+
}
|
|
3928
|
+
function suffixRank(suffix) {
|
|
3929
|
+
if (suffix === void 0) {
|
|
3930
|
+
return 0;
|
|
3926
3931
|
}
|
|
3927
|
-
return
|
|
3932
|
+
return /^post/i.test(suffix) ? 1 : -1;
|
|
3928
3933
|
}
|
|
3929
3934
|
function parseVersion(version) {
|
|
3930
|
-
const normalized = version.trim().replace(/^v/, "");
|
|
3931
|
-
const
|
|
3932
|
-
const
|
|
3935
|
+
const normalized = version.trim().replace(/^v/, "").split("+", 1)[0];
|
|
3936
|
+
const core = normalized.match(/^\d+(?:\.\d+){0,2}/)?.[0] ?? "";
|
|
3937
|
+
const rawSuffix = normalized.slice(core.length).replace(/^[-_.]/, "");
|
|
3938
|
+
const suffix = core.length > 0 && rawSuffix.length > 0 ? rawSuffix : void 0;
|
|
3939
|
+
const parts = core.split(".");
|
|
3933
3940
|
return {
|
|
3934
|
-
numbers: [
|
|
3935
|
-
|
|
3941
|
+
numbers: [
|
|
3942
|
+
safeVersionNumber(Number.parseInt(parts[0] ?? "", 10)),
|
|
3943
|
+
safeVersionNumber(Number.parseInt(parts[1] ?? "", 10)),
|
|
3944
|
+
safeVersionNumber(Number.parseInt(parts[2] ?? "", 10))
|
|
3945
|
+
],
|
|
3946
|
+
suffix
|
|
3936
3947
|
};
|
|
3937
3948
|
}
|
|
3938
3949
|
function safeVersionNumber(value) {
|
|
@@ -12254,7 +12265,7 @@ async function checkForThreadnoteUpdate(args) {
|
|
|
12254
12265
|
}
|
|
12255
12266
|
const cached = await readUpdateCache(args.cachePath);
|
|
12256
12267
|
if (cached && isCacheFresh(cached)) {
|
|
12257
|
-
return
|
|
12268
|
+
return toUpdateCheckResult(args.currentVersion, cached.latestVersion);
|
|
12258
12269
|
}
|
|
12259
12270
|
const fresh = await fetchLatestVersion();
|
|
12260
12271
|
if (fresh) {
|
|
@@ -12263,10 +12274,10 @@ async function checkForThreadnoteUpdate(args) {
|
|
|
12263
12274
|
latestVersion: fresh,
|
|
12264
12275
|
version: 1
|
|
12265
12276
|
});
|
|
12266
|
-
return
|
|
12277
|
+
return toUpdateCheckResult(args.currentVersion, fresh);
|
|
12267
12278
|
}
|
|
12268
12279
|
if (cached) {
|
|
12269
|
-
return
|
|
12280
|
+
return toUpdateCheckResult(args.currentVersion, cached.latestVersion);
|
|
12270
12281
|
}
|
|
12271
12282
|
return void 0;
|
|
12272
12283
|
}
|
|
@@ -12284,27 +12295,13 @@ function spawnDetachedAutoUpdate() {
|
|
|
12284
12295
|
} catch {
|
|
12285
12296
|
}
|
|
12286
12297
|
}
|
|
12287
|
-
function
|
|
12298
|
+
function toUpdateCheckResult(currentVersion, latestVersion) {
|
|
12288
12299
|
return {
|
|
12289
12300
|
currentVersion,
|
|
12290
12301
|
latestVersion,
|
|
12291
|
-
outdated:
|
|
12302
|
+
outdated: compareVersions(latestVersion, currentVersion) > 0
|
|
12292
12303
|
};
|
|
12293
12304
|
}
|
|
12294
|
-
function isNewerVersion(candidate, baseline) {
|
|
12295
|
-
const candidateParts = parseVersion2(candidate);
|
|
12296
|
-
const baselineParts = parseVersion2(baseline);
|
|
12297
|
-
for (let index = 0; index < 3; index += 1) {
|
|
12298
|
-
if (candidateParts[index] !== baselineParts[index]) {
|
|
12299
|
-
return candidateParts[index] > baselineParts[index];
|
|
12300
|
-
}
|
|
12301
|
-
}
|
|
12302
|
-
return false;
|
|
12303
|
-
}
|
|
12304
|
-
function parseVersion2(value) {
|
|
12305
|
-
const parts = value.split(".").map((part) => parseInt(part, 10));
|
|
12306
|
-
return [parts[0] || 0, parts[1] || 0, parts[2] || 0];
|
|
12307
|
-
}
|
|
12308
12305
|
function isCacheFresh(cache) {
|
|
12309
12306
|
const checkedAt = new Date(cache.checkedAt).getTime();
|
|
12310
12307
|
return Number.isFinite(checkedAt) && Date.now() - checkedAt < CACHE_TTL_MS;
|
|
@@ -12584,10 +12581,24 @@ async function emitUpdateBannerIfOutdated(config) {
|
|
|
12584
12581
|
// src/seeding.ts
|
|
12585
12582
|
var import_promises9 = require("node:fs/promises");
|
|
12586
12583
|
var import_node_path12 = require("node:path");
|
|
12584
|
+
function parseSeedWatchIntervalMinutes(rawValue) {
|
|
12585
|
+
if (rawValue === void 0) {
|
|
12586
|
+
return void 0;
|
|
12587
|
+
}
|
|
12588
|
+
const minutes = Number.parseInt(rawValue.trim(), 10);
|
|
12589
|
+
return Number.isInteger(minutes) && minutes > 0 ? minutes : void 0;
|
|
12590
|
+
}
|
|
12591
|
+
function seedWatchArgs(params) {
|
|
12592
|
+
if (params.watchIntervalMinutes === void 0 || !params.importedOriginal || params.redactionProne) {
|
|
12593
|
+
return [];
|
|
12594
|
+
}
|
|
12595
|
+
return ["--watch-interval", String(params.watchIntervalMinutes)];
|
|
12596
|
+
}
|
|
12587
12597
|
async function runSeed(config, options) {
|
|
12588
12598
|
const manifest = await readSeedManifest(config.manifestPath);
|
|
12589
12599
|
const ignorePatterns = await loadIgnorePatterns();
|
|
12590
12600
|
const ov = await openVikingCliForMode(options.dryRun === true);
|
|
12601
|
+
const watchIntervalMinutes = parseSeedWatchIntervalMinutes(process.env[SEED_WATCH_INTERVAL_ENV]);
|
|
12591
12602
|
const statePath = (0, import_node_path12.join)(config.agentContextHome, SEED_STATE_FILE);
|
|
12592
12603
|
const state = options.force === true ? { files: {}, version: 1 } : await readSeedState(statePath);
|
|
12593
12604
|
const projects = filterProjects(manifest.projects, options.only);
|
|
@@ -12620,6 +12631,11 @@ async function runSeed(config, options) {
|
|
|
12620
12631
|
candidate.destinationUri,
|
|
12621
12632
|
"--reason",
|
|
12622
12633
|
seedResourceReason(candidate),
|
|
12634
|
+
...seedWatchArgs({
|
|
12635
|
+
watchIntervalMinutes,
|
|
12636
|
+
importedOriginal: importPath === candidate.filePath,
|
|
12637
|
+
redactionProne: shouldRedactPath(candidate.relativePath)
|
|
12638
|
+
}),
|
|
12623
12639
|
"--wait"
|
|
12624
12640
|
]);
|
|
12625
12641
|
await maybeRun(options.dryRun === true, ov, args);
|
|
@@ -13701,6 +13717,8 @@ async function collectDoctorChecks(config, options = {}) {
|
|
|
13701
13717
|
checks.push(await commandCheck("python3", ["--version"]));
|
|
13702
13718
|
checks.push(await openVikingServerCheck());
|
|
13703
13719
|
checks.push(await openVikingCliCheck());
|
|
13720
|
+
checks.push(await openVikingVersionCheck(config));
|
|
13721
|
+
checks.push(await recallShapeCheck(config));
|
|
13704
13722
|
checks.push(await localEmbeddingCheck());
|
|
13705
13723
|
checks.push(await pythonSystemCertificatesCheck());
|
|
13706
13724
|
checks.push(await firstCommandCheck("python installer", ["pipx", "uv", "pip3"], ["--version"]));
|
|
@@ -13962,21 +13980,13 @@ async function configureOpenVikingCliLanguage(config, dryRun) {
|
|
|
13962
13980
|
if (!ov) {
|
|
13963
13981
|
return;
|
|
13964
13982
|
}
|
|
13965
|
-
const installedVersion = dryRun ? void 0 : await
|
|
13983
|
+
const installedVersion = dryRun ? void 0 : await readOpenVikingCliVersion(ov);
|
|
13966
13984
|
const effectiveVersion = installedVersion ?? config.openVikingVersion;
|
|
13967
13985
|
if (compareVersions(effectiveVersion, "0.3.23") < 0) {
|
|
13968
13986
|
return;
|
|
13969
13987
|
}
|
|
13970
13988
|
await maybeRun(dryRun, ov, ["language", "en"], { allowFailure: true });
|
|
13971
13989
|
}
|
|
13972
|
-
async function readOpenVikingCliVersion2(ov) {
|
|
13973
|
-
const result = await runCommand(ov, ["version"], { allowFailure: true });
|
|
13974
|
-
if (result.exitCode !== 0) {
|
|
13975
|
-
return void 0;
|
|
13976
|
-
}
|
|
13977
|
-
const match = result.stdout.match(/^\s*CLI:\s*(\S+)/m);
|
|
13978
|
-
return match ? match[1] : void 0;
|
|
13979
|
-
}
|
|
13980
13990
|
async function findOpenVikingServer() {
|
|
13981
13991
|
const onPath = await findExecutable([OPENVIKING_SERVER_COMMAND]);
|
|
13982
13992
|
if (onPath) {
|
|
@@ -14213,6 +14223,59 @@ async function openVikingCliCheck() {
|
|
|
14213
14223
|
detail: result.exitCode === 0 ? detail : firstLine(result.stderr || result.stdout) || detail
|
|
14214
14224
|
};
|
|
14215
14225
|
}
|
|
14226
|
+
async function openVikingVersionCheck(config) {
|
|
14227
|
+
const executable = await findOpenVikingCli();
|
|
14228
|
+
const pinned = config.openVikingVersion;
|
|
14229
|
+
if (!executable) {
|
|
14230
|
+
return { name: "openviking version", status: "warn", detail: `CLI not found; pinned ${pinned}` };
|
|
14231
|
+
}
|
|
14232
|
+
const installed = await readOpenVikingCliVersion(executable);
|
|
14233
|
+
if (!installed) {
|
|
14234
|
+
return {
|
|
14235
|
+
name: "openviking version",
|
|
14236
|
+
status: "warn",
|
|
14237
|
+
detail: `could not detect via \`${executable} version\`; pinned ${pinned}`
|
|
14238
|
+
};
|
|
14239
|
+
}
|
|
14240
|
+
if (compareVersions(installed, pinned) < 0) {
|
|
14241
|
+
return {
|
|
14242
|
+
name: "openviking version",
|
|
14243
|
+
status: "warn",
|
|
14244
|
+
detail: `installed ${installed} is older than pinned ${pinned}; run \`threadnote repair\` or \`threadnote update\` to upgrade`
|
|
14245
|
+
};
|
|
14246
|
+
}
|
|
14247
|
+
return { name: "openviking version", status: "ok", detail: `${installed} (pinned ${pinned})` };
|
|
14248
|
+
}
|
|
14249
|
+
async function recallShapeCheck(config) {
|
|
14250
|
+
const executable = await findOpenVikingCli();
|
|
14251
|
+
if (!executable) {
|
|
14252
|
+
return { name: "recall shape", status: "warn", detail: "CLI not found" };
|
|
14253
|
+
}
|
|
14254
|
+
const args = withIdentity(config, ["find", "threadnote", "--node-limit", "1", "--output", "json"]);
|
|
14255
|
+
const result = await runCommand(executable, args, { allowFailure: true });
|
|
14256
|
+
if (result.exitCode !== 0) {
|
|
14257
|
+
return { name: "recall shape", status: "warn", detail: "search failed; run threadnote repair" };
|
|
14258
|
+
}
|
|
14259
|
+
let parsed;
|
|
14260
|
+
try {
|
|
14261
|
+
parsed = JSON.parse(result.stdout.trim());
|
|
14262
|
+
} catch {
|
|
14263
|
+
return {
|
|
14264
|
+
name: "recall shape",
|
|
14265
|
+
status: "warn",
|
|
14266
|
+
detail: "search output is not JSON; recall may silently return nothing"
|
|
14267
|
+
};
|
|
14268
|
+
}
|
|
14269
|
+
const buckets = ["memories", "resources", "skills"];
|
|
14270
|
+
if (!isJsonObject(parsed) || !buckets.some((key) => Array.isArray(parsed[key]))) {
|
|
14271
|
+
return {
|
|
14272
|
+
name: "recall shape",
|
|
14273
|
+
status: "warn",
|
|
14274
|
+
detail: `search JSON missing ${buckets.join("/")} buckets; recall parsing is out of sync with this OpenViking`
|
|
14275
|
+
};
|
|
14276
|
+
}
|
|
14277
|
+
return { name: "recall shape", status: "ok", detail: "memories/resources/skills buckets present" };
|
|
14278
|
+
}
|
|
14216
14279
|
async function localEmbeddingCheck() {
|
|
14217
14280
|
const serverPath = await findOpenVikingServer();
|
|
14218
14281
|
if (!serverPath) {
|
|
@@ -193,8 +193,8 @@ Use these only when MCP tools are not available:
|
|
|
193
193
|
threadnote start
|
|
194
194
|
threadnote recall --query "last handoff for this branch"
|
|
195
195
|
threadnote recall --query "durable feature knowledge for this branch"
|
|
196
|
-
threadnote read viking://
|
|
197
|
-
threadnote list viking://
|
|
196
|
+
threadnote read viking://user/example/memories/.abstract.md
|
|
197
|
+
threadnote list viking://user/example/memories --all --recursive
|
|
198
198
|
threadnote remember --kind durable --project example --topic workflow --text "Durable engineering note..."
|
|
199
199
|
threadnote remember --kind durable --project example --topic active-issue --text "Feature knowledge..."
|
|
200
200
|
threadnote remember --replace viking://user/example/memories/durable/projects/example/workflow.md --text "Updated durable engineering note..."
|
package/docs/index.html
CHANGED
|
@@ -1147,7 +1147,7 @@
|
|
|
1147
1147
|
<span class="out">--user`, which fails on PEP 668 setups.</span>
|
|
1148
1148
|
<span class="out">Install uv now? [Y/n] </span><span class="out-strong">Y</span>
|
|
1149
1149
|
<span class="out">Installing uv via Homebrew…</span>
|
|
1150
|
-
<span class="out-strong">OK openviking 0.
|
|
1150
|
+
<span class="out-strong">OK openviking 0.4.4 ready · server healthy</span></pre>
|
|
1151
1151
|
</div>
|
|
1152
1152
|
<p class="muted" style="margin-top: 0.75rem; font-size: 0.9rem">
|
|
1153
1153
|
Or manually: <code>npm install -g threadnote && threadnote install</code>. On a fresh macOS / modern
|
|
@@ -1651,7 +1651,7 @@ threadnote doctor --dry-run</code></pre>
|
|
|
1651
1651
|
</div>
|
|
1652
1652
|
|
|
1653
1653
|
<p class="colophon">
|
|
1654
|
-
threadnote · AGPL-3.0-or-later · built on OpenViking 0.
|
|
1654
|
+
threadnote · AGPL-3.0-or-later · built on OpenViking 0.4.4 · use <span class="kbd">↑</span>
|
|
1655
1655
|
<span class="kbd">↓</span> / <span class="kbd">j</span> <span class="kbd">k</span> to navigate
|
|
1656
1656
|
</p>
|
|
1657
1657
|
</div>
|
package/docs/migration.md
CHANGED
|
@@ -108,6 +108,12 @@ paths.
|
|
|
108
108
|
threadnote seed
|
|
109
109
|
```
|
|
110
110
|
|
|
111
|
+
Seeded docs refresh on the next `threadnote seed`/`repair`, which re-runs the
|
|
112
|
+
secret scan. To let OpenViking auto-refresh them between runs, opt in with
|
|
113
|
+
`THREADNOTE_SEED_WATCH_INTERVAL=<minutes> threadnote seed`. Watches attach
|
|
114
|
+
only to original, non-redaction-prone files, since an OpenViking-managed
|
|
115
|
+
refresh re-ingests the file without Threadnote's per-import secret scan.
|
|
116
|
+
|
|
111
117
|
7. Inspect and seed shared skills:
|
|
112
118
|
|
|
113
119
|
```bash
|