threadnote 1.4.3 → 1.4.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/config/post-update-migrations.json +0 -15
- package/dist/threadnote.cjs +30 -226
- package/docs/index.html +2 -2
- package/docs/troubleshooting.md +9 -11
- package/package.json +1 -1
|
@@ -18,21 +18,6 @@
|
|
|
18
18
|
"If Threadnote reported any original files were still being processed, rerun the printed threadnote forget <uri> command later."
|
|
19
19
|
],
|
|
20
20
|
"requiresLegacyHandoffs": true
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
"id": "ov-semantic-poison-hotfix-2734",
|
|
24
|
-
"introducedIn": "1.4.3",
|
|
25
|
-
"title": "Patch OpenViking against the semantic-queue poison loop (#2734)",
|
|
26
|
-
"description": [
|
|
27
|
-
"OpenViking 0.4.x can deadlock its semantic queue: a memory file reindexed with mode=semantic_and_vectors enqueues a directory-level semantic message whose URI is a file; the processor lists it, fails, and the message re-enqueues forever (it is AGFS-persisted, so it survives a server restart).",
|
|
28
|
-
"This patches the installed OpenViking to skip non-directory/missing memory URIs (upstream fix PR #2735) and restarts the server so any stuck message drains on the next dequeue.",
|
|
29
|
-
"It is a no-op when the installed OpenViking already includes the fix, a backup of the original file is kept, and the patched file is compile-checked before it is written."
|
|
30
|
-
],
|
|
31
|
-
"commandArgs": ["repair-semantic-queue", "--apply"],
|
|
32
|
-
"instructions": [
|
|
33
|
-
"If the semantic queue was stuck it should now drain. Verify with: ov observer queue",
|
|
34
|
-
"This is a temporary local patch; it is superseded automatically once Threadnote pins an OpenViking release that includes the fix. Re-run manually any time with: threadnote repair-semantic-queue --apply"
|
|
35
|
-
]
|
|
36
21
|
}
|
|
37
22
|
]
|
|
38
23
|
}
|
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.4.
|
|
3397
|
+
var DEFAULT_OPENVIKING_VERSION = "0.4.5";
|
|
3398
3398
|
var OPENVIKING_TOOL_PYTHON = "3.12";
|
|
3399
3399
|
var DEFAULT_ACCOUNT = "local";
|
|
3400
3400
|
var DEFAULT_AGENT_ID = "threadnote";
|
|
@@ -15009,199 +15009,6 @@ function parsePackageManager(value) {
|
|
|
15009
15009
|
throw new Error(`Invalid package manager: ${value}`);
|
|
15010
15010
|
}
|
|
15011
15011
|
|
|
15012
|
-
// src/semantic_queue_repair.ts
|
|
15013
|
-
var import_node_fs8 = require("node:fs");
|
|
15014
|
-
var import_promises14 = require("node:fs/promises");
|
|
15015
|
-
var import_node_os7 = require("node:os");
|
|
15016
|
-
var import_node_path15 = require("node:path");
|
|
15017
|
-
var HOTFIX_MARKER = "THREADNOTE-HOTFIX-2734";
|
|
15018
|
-
var ENV_OVERRIDE = "THREADNOTE_OPENVIKING_SEMANTIC_PROCESSOR";
|
|
15019
|
-
function patchSemanticProcessorSource(source) {
|
|
15020
|
-
if (source.includes(HOTFIX_MARKER)) {
|
|
15021
|
-
return { status: "already-fixed" };
|
|
15022
|
-
}
|
|
15023
|
-
const lines = source.split("\n");
|
|
15024
|
-
const defIndex = lines.findIndex((line) => /^\s*async def _process_memory_directory\b/.test(line));
|
|
15025
|
-
if (defIndex < 0) {
|
|
15026
|
-
return { status: "no-anchor" };
|
|
15027
|
-
}
|
|
15028
|
-
const lsPattern = /^(\s+)entries = await viking_fs\.ls\(dir_uri\b/;
|
|
15029
|
-
let lsIndex = -1;
|
|
15030
|
-
let lsIndent = "";
|
|
15031
|
-
for (let i = defIndex + 1; i < lines.length; i += 1) {
|
|
15032
|
-
const match = lsPattern.exec(lines[i]);
|
|
15033
|
-
if (match) {
|
|
15034
|
-
lsIndex = i;
|
|
15035
|
-
lsIndent = match[1];
|
|
15036
|
-
break;
|
|
15037
|
-
}
|
|
15038
|
-
if (/^\s*async def \w/.test(lines[i])) {
|
|
15039
|
-
break;
|
|
15040
|
-
}
|
|
15041
|
-
}
|
|
15042
|
-
if (lsIndex < 0) {
|
|
15043
|
-
return { status: "no-anchor" };
|
|
15044
|
-
}
|
|
15045
|
-
if (lines.slice(defIndex, lsIndex).some((line) => line.includes("viking_fs.stat(dir_uri"))) {
|
|
15046
|
-
return { status: "already-fixed" };
|
|
15047
|
-
}
|
|
15048
|
-
let tryIndex = -1;
|
|
15049
|
-
let base = "";
|
|
15050
|
-
for (let j = lsIndex - 1; j > defIndex; j -= 1) {
|
|
15051
|
-
const text = lines[j];
|
|
15052
|
-
if (text.trim() === "" || text.trimStart().startsWith("#")) {
|
|
15053
|
-
continue;
|
|
15054
|
-
}
|
|
15055
|
-
const match = /^(\s*)try:\s*$/.exec(text);
|
|
15056
|
-
if (match && match[1].length < lsIndent.length) {
|
|
15057
|
-
tryIndex = j;
|
|
15058
|
-
base = match[1];
|
|
15059
|
-
}
|
|
15060
|
-
break;
|
|
15061
|
-
}
|
|
15062
|
-
if (tryIndex < 0) {
|
|
15063
|
-
return { status: "no-anchor" };
|
|
15064
|
-
}
|
|
15065
|
-
const unit = " ".repeat(lsIndent.length - base.length);
|
|
15066
|
-
const at = (level, text) => `${base}${unit.repeat(level)}${text}`;
|
|
15067
|
-
const guard = [
|
|
15068
|
-
at(0, `# ${HOTFIX_MARKER}: skip non-directory / missing memory URIs so a memory file`),
|
|
15069
|
-
at(0, "# reindexed with mode=semantic_and_vectors cannot poison the semantic queue."),
|
|
15070
|
-
at(0, "# Temporary local hot-fix; superseded once OpenViking ships upstream PR #2735."),
|
|
15071
|
-
at(0, "try:"),
|
|
15072
|
-
at(1, "_tn_dir_stat = await viking_fs.stat(dir_uri, ctx=ctx)"),
|
|
15073
|
-
at(0, "except Exception as _tn_err:"),
|
|
15074
|
-
at(1, 'if isinstance(_tn_err, FileNotFoundError) or "not found" in str(_tn_err).lower():'),
|
|
15075
|
-
at(2, "_mark_done()"),
|
|
15076
|
-
at(2, "return"),
|
|
15077
|
-
at(1, "_tn_dir_stat = None"),
|
|
15078
|
-
at(0, 'if _tn_dir_stat is not None and not _tn_dir_stat.get("isDir", _tn_dir_stat.get("is_dir", False)):'),
|
|
15079
|
-
at(1, "_mark_done()"),
|
|
15080
|
-
at(1, "return")
|
|
15081
|
-
];
|
|
15082
|
-
const patched = [...lines.slice(0, tryIndex), ...guard, ...lines.slice(tryIndex)].join("\n");
|
|
15083
|
-
return { status: "patched", source: patched };
|
|
15084
|
-
}
|
|
15085
|
-
async function semanticProcessorCandidates(root) {
|
|
15086
|
-
const lib = (0, import_node_path15.join)(root, "lib");
|
|
15087
|
-
if (!(0, import_node_fs8.existsSync)(lib)) {
|
|
15088
|
-
return [];
|
|
15089
|
-
}
|
|
15090
|
-
let entries;
|
|
15091
|
-
try {
|
|
15092
|
-
entries = await (0, import_promises14.readdir)(lib);
|
|
15093
|
-
} catch {
|
|
15094
|
-
return [];
|
|
15095
|
-
}
|
|
15096
|
-
return entries.filter((name) => name.startsWith("python")).map((name) => (0, import_node_path15.join)(lib, name, "site-packages", "openviking", "storage", "queuefs", "semantic_processor.py"));
|
|
15097
|
-
}
|
|
15098
|
-
async function locateSemanticProcessorPath() {
|
|
15099
|
-
const override = process.env[ENV_OVERRIDE]?.trim();
|
|
15100
|
-
if (override) {
|
|
15101
|
-
const resolved = expandPath(override);
|
|
15102
|
-
if ((0, import_node_fs8.existsSync)(resolved)) {
|
|
15103
|
-
return resolved;
|
|
15104
|
-
}
|
|
15105
|
-
}
|
|
15106
|
-
const roots = [];
|
|
15107
|
-
const server = await findOpenVikingServer();
|
|
15108
|
-
if (server) {
|
|
15109
|
-
roots.push((0, import_node_path15.dirname)((0, import_node_path15.dirname)(server)));
|
|
15110
|
-
}
|
|
15111
|
-
roots.push((0, import_node_path15.join)((0, import_node_os7.homedir)(), ".local", "share", "uv", "tools", "openviking"));
|
|
15112
|
-
roots.push((0, import_node_path15.join)((0, import_node_os7.homedir)(), ".local", "pipx", "venvs", "openviking"));
|
|
15113
|
-
for (const root of roots) {
|
|
15114
|
-
for (const candidate of await semanticProcessorCandidates(root)) {
|
|
15115
|
-
if ((0, import_node_fs8.existsSync)(candidate)) {
|
|
15116
|
-
return candidate;
|
|
15117
|
-
}
|
|
15118
|
-
}
|
|
15119
|
-
}
|
|
15120
|
-
if (server) {
|
|
15121
|
-
const venvPython = (0, import_node_path15.join)((0, import_node_path15.dirname)(server), process.platform === "win32" ? "python.exe" : "python3");
|
|
15122
|
-
if ((0, import_node_fs8.existsSync)(venvPython)) {
|
|
15123
|
-
const result = await runCommand(
|
|
15124
|
-
venvPython,
|
|
15125
|
-
[
|
|
15126
|
-
"-c",
|
|
15127
|
-
'import openviking, os; print(os.path.join(os.path.dirname(openviking.__file__), "storage", "queuefs", "semantic_processor.py"))'
|
|
15128
|
-
],
|
|
15129
|
-
{ allowFailure: true }
|
|
15130
|
-
);
|
|
15131
|
-
const path2 = result.stdout.trim();
|
|
15132
|
-
if (result.exitCode === 0 && path2 && (0, import_node_fs8.existsSync)(path2)) {
|
|
15133
|
-
return path2;
|
|
15134
|
-
}
|
|
15135
|
-
}
|
|
15136
|
-
}
|
|
15137
|
-
return void 0;
|
|
15138
|
-
}
|
|
15139
|
-
async function assertPatchedSourceCompiles(source) {
|
|
15140
|
-
const python = await findExecutable(["python3", "python"]);
|
|
15141
|
-
if (!python) {
|
|
15142
|
-
console.warn("WARN python3 not found; skipping compile validation of the patched OpenViking source.");
|
|
15143
|
-
return;
|
|
15144
|
-
}
|
|
15145
|
-
const dir = await (0, import_promises14.mkdtemp)((0, import_node_path15.join)((0, import_node_os7.tmpdir)(), "threadnote-ov-patch-"));
|
|
15146
|
-
const file = (0, import_node_path15.join)(dir, "semantic_processor_patched.py");
|
|
15147
|
-
try {
|
|
15148
|
-
await (0, import_promises14.writeFile)(file, source, "utf8");
|
|
15149
|
-
const result = await runCommand(python, ["-m", "py_compile", file], { allowFailure: true });
|
|
15150
|
-
if (result.exitCode !== 0) {
|
|
15151
|
-
throw new Error(`patched OpenViking source failed to compile: ${result.stderr.trim() || result.stdout.trim()}`);
|
|
15152
|
-
}
|
|
15153
|
-
} finally {
|
|
15154
|
-
await (0, import_promises14.rm)(dir, { force: true, recursive: true });
|
|
15155
|
-
}
|
|
15156
|
-
}
|
|
15157
|
-
async function runRepairSemanticQueue(config, options) {
|
|
15158
|
-
const apply = options.apply === true && options.dryRun !== true;
|
|
15159
|
-
const path2 = await locateSemanticProcessorPath();
|
|
15160
|
-
if (!path2) {
|
|
15161
|
-
console.error(
|
|
15162
|
-
`Could not locate the installed OpenViking semantic_processor.py. Set ${ENV_OVERRIDE}=/path/to/openviking/storage/queuefs/semantic_processor.py and retry.`
|
|
15163
|
-
);
|
|
15164
|
-
process.exitCode = 1;
|
|
15165
|
-
return;
|
|
15166
|
-
}
|
|
15167
|
-
console.log(`OpenViking semantic processor: ${path2}`);
|
|
15168
|
-
let original;
|
|
15169
|
-
try {
|
|
15170
|
-
original = await (0, import_promises14.readFile)(path2, "utf8");
|
|
15171
|
-
} catch (err) {
|
|
15172
|
-
console.error(`Could not read ${path2}: ${errorMessage(err)}`);
|
|
15173
|
-
process.exitCode = 1;
|
|
15174
|
-
return;
|
|
15175
|
-
}
|
|
15176
|
-
const result = patchSemanticProcessorSource(original);
|
|
15177
|
-
if (result.status === "already-fixed") {
|
|
15178
|
-
console.log("OpenViking already guards non-directory memory URIs (#2734/#2735); nothing to patch.");
|
|
15179
|
-
return;
|
|
15180
|
-
}
|
|
15181
|
-
if (result.status === "no-anchor") {
|
|
15182
|
-
console.warn(
|
|
15183
|
-
"WARN Could not find the _process_memory_directory ls(dir_uri) anchor; this OpenViking layout is unexpected, so no changes were made."
|
|
15184
|
-
);
|
|
15185
|
-
return;
|
|
15186
|
-
}
|
|
15187
|
-
if (!apply) {
|
|
15188
|
-
console.log("Dry run: would patch OpenViking to skip non-directory/missing memory URIs, then restart the server.");
|
|
15189
|
-
console.log("Re-run with --apply to perform it.");
|
|
15190
|
-
return;
|
|
15191
|
-
}
|
|
15192
|
-
await assertPatchedSourceCompiles(result.source);
|
|
15193
|
-
const backup = `${path2}.threadnote-bak`;
|
|
15194
|
-
if (!(0, import_node_fs8.existsSync)(backup)) {
|
|
15195
|
-
await (0, import_promises14.copyFile)(path2, backup);
|
|
15196
|
-
}
|
|
15197
|
-
await (0, import_promises14.writeFile)(path2, result.source, "utf8");
|
|
15198
|
-
console.log(`Patched OpenViking semantic processor (backup: ${backup}).`);
|
|
15199
|
-
console.log("Restarting the OpenViking server so the patch loads and any stuck message drains...");
|
|
15200
|
-
await runStop(config, {});
|
|
15201
|
-
await runStart(config, {});
|
|
15202
|
-
console.log("Done. A stuck semantic message drains on the next dequeue; verify with: ov observer queue");
|
|
15203
|
-
}
|
|
15204
|
-
|
|
15205
15012
|
// src/version_command.ts
|
|
15206
15013
|
async function runVersion(config, options) {
|
|
15207
15014
|
const currentVersion = await currentPackageVersion();
|
|
@@ -15245,9 +15052,9 @@ function printWhatsNew(whatsNew) {
|
|
|
15245
15052
|
// src/manager.ts
|
|
15246
15053
|
var import_node_http2 = require("node:http");
|
|
15247
15054
|
var import_node_crypto2 = require("node:crypto");
|
|
15248
|
-
var
|
|
15249
|
-
var
|
|
15250
|
-
var
|
|
15055
|
+
var import_promises14 = require("node:fs/promises");
|
|
15056
|
+
var import_node_os7 = require("node:os");
|
|
15057
|
+
var import_node_path15 = require("node:path");
|
|
15251
15058
|
var STATIC_FILES = {
|
|
15252
15059
|
"/": { contentType: "text/html; charset=utf-8", path: "index.html" },
|
|
15253
15060
|
"/index.html": { contentType: "text/html; charset=utf-8", path: "index.html" },
|
|
@@ -15318,18 +15125,18 @@ async function readManagedMemory(config, uri) {
|
|
|
15318
15125
|
if (!path2) {
|
|
15319
15126
|
throw new Error(`Manager can only read current-user memory URIs: ${uri}`);
|
|
15320
15127
|
}
|
|
15321
|
-
const [content, pathStat] = await Promise.all([(0,
|
|
15322
|
-
const relativePath = (0,
|
|
15128
|
+
const [content, pathStat] = await Promise.all([(0, import_promises14.readFile)(path2, "utf8"), (0, import_promises14.stat)(path2)]);
|
|
15129
|
+
const relativePath = (0, import_node_path15.relative)(localMemoriesRoot(config), path2).split(import_node_path15.sep).join("/");
|
|
15323
15130
|
const record = parseMemoryDocument(uri, content);
|
|
15324
15131
|
return {
|
|
15325
15132
|
content,
|
|
15326
15133
|
node: {
|
|
15327
15134
|
isDir: false,
|
|
15328
15135
|
isShared: isInSharedNamespace(config, uri),
|
|
15329
|
-
isSystem: isSystemMemoryName(path2.split(
|
|
15136
|
+
isSystem: isSystemMemoryName(path2.split(import_node_path15.sep).at(-1) ?? ""),
|
|
15330
15137
|
metadata: record?.metadata,
|
|
15331
15138
|
modTime: pathStat.mtime.toISOString(),
|
|
15332
|
-
name: path2.split(
|
|
15139
|
+
name: path2.split(import_node_path15.sep).at(-1) ?? uri,
|
|
15333
15140
|
relativePath,
|
|
15334
15141
|
sharedTeam: sharedTeamNameForUri(config, uri),
|
|
15335
15142
|
size: pathStat.size,
|
|
@@ -15617,7 +15424,7 @@ async function handleRequest(context, request, response) {
|
|
|
15617
15424
|
}
|
|
15618
15425
|
async function serveStatic(context, url, response) {
|
|
15619
15426
|
const file = STATIC_FILES[url.pathname] ?? STATIC_FILES["/"];
|
|
15620
|
-
const content = await (0,
|
|
15427
|
+
const content = await (0, import_promises14.readFile)((0, import_node_path15.join)(toolRoot(), file.root ?? "manager", file.path));
|
|
15621
15428
|
const headers = { "content-type": file.contentType };
|
|
15622
15429
|
if (file.root !== "docs") {
|
|
15623
15430
|
headers["cache-control"] = "no-store";
|
|
@@ -15626,11 +15433,11 @@ async function serveStatic(context, url, response) {
|
|
|
15626
15433
|
response.end(content);
|
|
15627
15434
|
}
|
|
15628
15435
|
async function readTree(config, path2, uri, relativePath, options = {}) {
|
|
15629
|
-
const pathStat = await (0,
|
|
15436
|
+
const pathStat = await (0, import_promises14.stat)(path2);
|
|
15630
15437
|
const name = relativePath ? relativePath.split("/").at(-1) ?? relativePath : options.rootName ?? "memories";
|
|
15631
15438
|
const isDir = pathStat.isDirectory();
|
|
15632
15439
|
if (!isDir) {
|
|
15633
|
-
const record = options.parseMemoryDocuments === false ? void 0 : parseMemoryDocument(uri, await (0,
|
|
15440
|
+
const record = options.parseMemoryDocuments === false ? void 0 : parseMemoryDocument(uri, await (0, import_promises14.readFile)(path2, "utf8").catch(() => ""));
|
|
15634
15441
|
return {
|
|
15635
15442
|
isDir: false,
|
|
15636
15443
|
isShared: isInSharedNamespace(config, uri),
|
|
@@ -15644,13 +15451,13 @@ async function readTree(config, path2, uri, relativePath, options = {}) {
|
|
|
15644
15451
|
uri
|
|
15645
15452
|
};
|
|
15646
15453
|
}
|
|
15647
|
-
const entries = await (0,
|
|
15454
|
+
const entries = await (0, import_promises14.readdir)(path2, { withFileTypes: true });
|
|
15648
15455
|
const children = await Promise.all(
|
|
15649
15456
|
entries.sort(
|
|
15650
15457
|
(left, right) => Number(right.isDirectory()) - Number(left.isDirectory()) || left.name.localeCompare(right.name)
|
|
15651
15458
|
).map((entry) => {
|
|
15652
15459
|
const childRelative = relativePath ? `${relativePath}/${entry.name}` : entry.name;
|
|
15653
|
-
return readTree(config, (0,
|
|
15460
|
+
return readTree(config, (0, import_node_path15.join)(path2, entry.name), `${uri}/${entry.name}`, childRelative, options);
|
|
15654
15461
|
})
|
|
15655
15462
|
);
|
|
15656
15463
|
return {
|
|
@@ -15824,27 +15631,27 @@ async function removeManagedFolder(config, uri) {
|
|
|
15824
15631
|
if (!path2) {
|
|
15825
15632
|
throw new Error(`Manager can only remove current-user memory folders: ${uri}`);
|
|
15826
15633
|
}
|
|
15827
|
-
const pathStat = await (0,
|
|
15634
|
+
const pathStat = await (0, import_promises14.stat)(path2);
|
|
15828
15635
|
if (!pathStat.isDirectory()) {
|
|
15829
15636
|
throw new Error(`Not a folder: ${uri}`);
|
|
15830
15637
|
}
|
|
15831
|
-
const relativePath = (0,
|
|
15832
|
-
if (!relativePath || relativePath.startsWith("..") || relativePath.split(
|
|
15638
|
+
const relativePath = (0, import_node_path15.relative)(localMemoriesRoot(config), path2);
|
|
15639
|
+
if (!relativePath || relativePath.startsWith("..") || relativePath.split(import_node_path15.sep).includes("..")) {
|
|
15833
15640
|
throw new Error("Refusing to remove a folder outside the memories tree.");
|
|
15834
15641
|
}
|
|
15835
15642
|
const fileUris = await fileUrisUnderFolder(config, path2);
|
|
15836
15643
|
for (const fileUri of fileUris) {
|
|
15837
15644
|
await runForget(config, fileUri, {});
|
|
15838
15645
|
}
|
|
15839
|
-
await (0,
|
|
15646
|
+
await (0, import_promises14.rm)(path2, { force: true, recursive: true });
|
|
15840
15647
|
console.log(`Removed folder: ${uri}`);
|
|
15841
15648
|
console.log(`Forgot ${fileUris.length} file${fileUris.length === 1 ? "" : "s"}.`);
|
|
15842
15649
|
}
|
|
15843
15650
|
async function fileUrisUnderFolder(config, folderPath) {
|
|
15844
|
-
const entries = await (0,
|
|
15651
|
+
const entries = await (0, import_promises14.readdir)(folderPath, { withFileTypes: true });
|
|
15845
15652
|
const uris = [];
|
|
15846
15653
|
for (const entry of entries.sort((left, right) => left.name.localeCompare(right.name))) {
|
|
15847
|
-
const path2 = (0,
|
|
15654
|
+
const path2 = (0, import_node_path15.join)(folderPath, entry.name);
|
|
15848
15655
|
if (entry.isDirectory()) {
|
|
15849
15656
|
uris.push(...await fileUrisUnderFolder(config, path2));
|
|
15850
15657
|
} else if (entry.isFile()) {
|
|
@@ -15942,11 +15749,11 @@ async function runConsolidationAgent(agent, sources) {
|
|
|
15942
15749
|
throw new Error(`${agent} executable was not found.`);
|
|
15943
15750
|
}
|
|
15944
15751
|
const prompt = consolidationPrompt(sources);
|
|
15945
|
-
const stagingDir = await (0,
|
|
15946
|
-
const promptPath = (0,
|
|
15752
|
+
const stagingDir = await (0, import_promises14.mkdtemp)((0, import_node_path15.join)((0, import_node_os7.tmpdir)(), "threadnote-consolidate-"));
|
|
15753
|
+
const promptPath = (0, import_node_path15.join)(stagingDir, "prompt.txt");
|
|
15947
15754
|
try {
|
|
15948
|
-
await (0,
|
|
15949
|
-
await (0,
|
|
15755
|
+
await (0, import_promises14.writeFile)(promptPath, prompt, { encoding: "utf8", mode: 384 });
|
|
15756
|
+
await (0, import_promises14.chmod)(promptPath, 384);
|
|
15950
15757
|
const script = consolidationAgentScript(agent, executable);
|
|
15951
15758
|
const result = await runCommand("sh", ["-lc", script, "threadnote-consolidate", promptPath], {
|
|
15952
15759
|
allowFailure: true,
|
|
@@ -15962,7 +15769,7 @@ async function runConsolidationAgent(agent, sources) {
|
|
|
15962
15769
|
}
|
|
15963
15770
|
return draft;
|
|
15964
15771
|
} finally {
|
|
15965
|
-
await (0,
|
|
15772
|
+
await (0, import_promises14.rm)(stagingDir, { force: true, recursive: true });
|
|
15966
15773
|
}
|
|
15967
15774
|
}
|
|
15968
15775
|
function consolidationAgentScript(agent, executable) {
|
|
@@ -16100,10 +15907,10 @@ function memoryDirectoryUri2(config, kind, status, projectSegment) {
|
|
|
16100
15907
|
}
|
|
16101
15908
|
}
|
|
16102
15909
|
function localMemoriesRoot(config) {
|
|
16103
|
-
return (0,
|
|
15910
|
+
return (0, import_node_path15.join)(config.agentContextHome, "data", "viking", config.account, "user", uriSegment(config.user), "memories");
|
|
16104
15911
|
}
|
|
16105
15912
|
function localResourcesRoot(config) {
|
|
16106
|
-
return (0,
|
|
15913
|
+
return (0, import_node_path15.join)(config.agentContextHome, "data", "viking", config.account, "resources");
|
|
16107
15914
|
}
|
|
16108
15915
|
function localPathForMemoryUri(config, uri) {
|
|
16109
15916
|
const prefix = `viking://user/${uriSegment(config.user)}/memories`;
|
|
@@ -16115,17 +15922,17 @@ function localPathForMemoryUri(config, uri) {
|
|
|
16115
15922
|
if (segments.some((segment) => segment === "." || segment === "..")) {
|
|
16116
15923
|
return void 0;
|
|
16117
15924
|
}
|
|
16118
|
-
return (0,
|
|
15925
|
+
return (0, import_node_path15.join)(localMemoriesRoot(config), ...segments);
|
|
16119
15926
|
}
|
|
16120
15927
|
function isMissingPathError(err) {
|
|
16121
15928
|
return typeof err === "object" && err !== null && "code" in err && err.code === "ENOENT";
|
|
16122
15929
|
}
|
|
16123
15930
|
function localPathToMemoryUri(config, path2) {
|
|
16124
|
-
const relativePath = (0,
|
|
16125
|
-
if (!relativePath || relativePath.startsWith("..") || relativePath.split(
|
|
15931
|
+
const relativePath = (0, import_node_path15.relative)(localMemoriesRoot(config), path2);
|
|
15932
|
+
if (!relativePath || relativePath.startsWith("..") || relativePath.split(import_node_path15.sep).includes("..")) {
|
|
16126
15933
|
throw new Error(`Path is outside the memories tree: ${path2}`);
|
|
16127
15934
|
}
|
|
16128
|
-
return `viking://user/${uriSegment(config.user)}/memories/${relativePath.split(
|
|
15935
|
+
return `viking://user/${uriSegment(config.user)}/memories/${relativePath.split(import_node_path15.sep).join("/")}`;
|
|
16129
15936
|
}
|
|
16130
15937
|
async function ensurePersonalDirectoryChain2(config, ov, directoryUri) {
|
|
16131
15938
|
const prefix = "viking://";
|
|
@@ -16365,9 +16172,6 @@ async function main() {
|
|
|
16365
16172
|
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) => {
|
|
16366
16173
|
await runMigrateLifecycle(getRuntimeConfig(program2), options);
|
|
16367
16174
|
});
|
|
16368
|
-
program2.command("repair-semantic-queue").description("Patch the installed OpenViking to drain/avoid the semantic-queue poison loop (#2734)").option("--apply", "Apply the patch and restart the server; without this, prints a dry run").option("--dry-run", "Print what would change without patching or restarting").action(async (options) => {
|
|
16369
|
-
await runRepairSemanticQueue(getRuntimeConfig(program2), options);
|
|
16370
|
-
});
|
|
16371
16175
|
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) => {
|
|
16372
16176
|
await runRecall(getRuntimeConfig(program2), options);
|
|
16373
16177
|
});
|
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.4.
|
|
1150
|
+
<span class="out-strong">OK openviking 0.4.5 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.4.
|
|
1654
|
+
threadnote · AGPL-3.0-or-later · built on OpenViking 0.4.5 · 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/troubleshooting.md
CHANGED
|
@@ -102,28 +102,26 @@ Symptom: agents hang or `remember`/`handoff` get very slow, and `~/.openviking/l
|
|
|
102
102
|
RuntimeError: Failed to list memory directory viking://user/.../memories/.../<name>.md: Directory not found
|
|
103
103
|
```
|
|
104
104
|
|
|
105
|
-
A memory _file_ got enqueued for directory-level semantic processing; OpenViking
|
|
106
|
-
|
|
107
|
-
queue — a non-zero `Errors`/`Requeued` on the `Semantic` row is the signature:
|
|
105
|
+
A memory _file_ got enqueued for directory-level semantic processing; older OpenViking releases listed it as a
|
|
106
|
+
directory, failed, and re-enqueued the message forever. The entry is AGFS-persisted, so it survives a server restart.
|
|
107
|
+
Check the queue — a non-zero `Errors`/`Requeued` on the `Semantic` row is the signature:
|
|
108
108
|
|
|
109
109
|
```bash
|
|
110
110
|
ov observer queue
|
|
111
111
|
```
|
|
112
112
|
|
|
113
|
-
|
|
113
|
+
This is fixed upstream in OpenViking 0.4.5. Update Threadnote so it upgrades the pinned OpenViking install and restarts
|
|
114
|
+
the server:
|
|
114
115
|
|
|
115
116
|
```bash
|
|
116
|
-
threadnote
|
|
117
|
+
threadnote update
|
|
117
118
|
```
|
|
118
119
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
patch** — `threadnote update` also offers it as a post-update step, and it is superseded automatically once Threadnote
|
|
122
|
-
pins an OpenViking release containing the fix. To revert manually:
|
|
120
|
+
If Threadnote is already current but OpenViking is still older than 0.4.5, force a reinstall of the pinned OpenViking
|
|
121
|
+
tool:
|
|
123
122
|
|
|
124
123
|
```bash
|
|
125
|
-
|
|
126
|
-
threadnote stop && threadnote start
|
|
124
|
+
threadnote install --force
|
|
127
125
|
```
|
|
128
126
|
|
|
129
127
|
## Port Already In Use
|