negotium 0.2.18 → 0.2.19
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/agent-helpers.js +2 -2
- package/dist/agent-helpers.js.map +4 -4
- package/dist/chunk-fc58cqry.js.map +1 -1
- package/dist/hosted-agent.js +2 -2
- package/dist/hosted-agent.js.map +3 -3
- package/dist/main.js +726 -203
- package/dist/main.js.map +9 -8
- package/dist/mcp-factories.js +847 -321
- package/dist/mcp-factories.js.map +9 -8
- package/dist/registry.js +2 -2
- package/dist/registry.js.map +2 -2
- package/dist/runtime/src/agents/archiver.ts +1 -1
- package/dist/runtime/src/mcp/canonical-proxy-server.ts +13 -14
- package/dist/runtime/src/mcp/wiki-search-index.ts +359 -0
- package/dist/runtime/src/mcp/wiki-server.ts +559 -98
- package/dist/runtime/src/platform/mcp-config.ts +1 -1
- package/dist/runtime/src/prompts/agents/wiki-archiver.md +62 -47
- package/dist/runtime/src/version.ts +1 -1
- package/dist/types/packages/core/src/agents/archiver.d.ts +1 -1
- package/dist/types/packages/core/src/mcp/wiki-search-index.d.ts +59 -0
- package/dist/types/packages/core/src/version.d.ts +1 -1
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -1636,7 +1636,7 @@ var exports_version = {};
|
|
|
1636
1636
|
__export(exports_version, {
|
|
1637
1637
|
NEGOTIUM_VERSION: () => NEGOTIUM_VERSION
|
|
1638
1638
|
});
|
|
1639
|
-
var NEGOTIUM_VERSION = "0.2.
|
|
1639
|
+
var NEGOTIUM_VERSION = "0.2.19";
|
|
1640
1640
|
|
|
1641
1641
|
// ../../packages/core/src/agents/codex-native-multi-agent.ts
|
|
1642
1642
|
import { spawn } from "child_process";
|
|
@@ -24920,6 +24920,219 @@ var init_vault2 = __esm(() => {
|
|
|
24920
24920
|
init_mcp_helpers();
|
|
24921
24921
|
});
|
|
24922
24922
|
|
|
24923
|
+
// ../../packages/core/src/mcp/wiki-search-index.ts
|
|
24924
|
+
import { chmodSync as chmodSync5, existsSync as existsSync26, readFileSync as readFileSync22, unlinkSync as unlinkSync18 } from "fs";
|
|
24925
|
+
function documentId(source) {
|
|
24926
|
+
return `${source.kind}:${source.key}`;
|
|
24927
|
+
}
|
|
24928
|
+
function ensureSchema(database) {
|
|
24929
|
+
const version = database.query("PRAGMA user_version").get()?.user_version;
|
|
24930
|
+
if (version !== 0 && version !== SEARCH_INDEX_SCHEMA_VERSION) {
|
|
24931
|
+
throw new Error(`Unsupported wiki search index schema: ${version}`);
|
|
24932
|
+
}
|
|
24933
|
+
database.exec(`
|
|
24934
|
+
CREATE TABLE IF NOT EXISTS wiki_search_documents (
|
|
24935
|
+
id TEXT PRIMARY KEY,
|
|
24936
|
+
kind TEXT NOT NULL,
|
|
24937
|
+
key TEXT NOT NULL,
|
|
24938
|
+
path TEXT NOT NULL,
|
|
24939
|
+
mtime_ms REAL NOT NULL,
|
|
24940
|
+
size INTEGER NOT NULL,
|
|
24941
|
+
title TEXT NOT NULL,
|
|
24942
|
+
text TEXT NOT NULL,
|
|
24943
|
+
date TEXT,
|
|
24944
|
+
family TEXT
|
|
24945
|
+
);
|
|
24946
|
+
CREATE UNIQUE INDEX IF NOT EXISTS wiki_search_documents_kind_key
|
|
24947
|
+
ON wiki_search_documents(kind, key);
|
|
24948
|
+
CREATE INDEX IF NOT EXISTS wiki_search_documents_kind_date
|
|
24949
|
+
ON wiki_search_documents(kind, date);
|
|
24950
|
+
CREATE INDEX IF NOT EXISTS wiki_search_documents_kind_family_date
|
|
24951
|
+
ON wiki_search_documents(kind, family, date);
|
|
24952
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS wiki_search_fts USING fts5(
|
|
24953
|
+
document_id UNINDEXED,
|
|
24954
|
+
kind UNINDEXED,
|
|
24955
|
+
tokens,
|
|
24956
|
+
tokenize = 'unicode61'
|
|
24957
|
+
);
|
|
24958
|
+
PRAGMA user_version = ${SEARCH_INDEX_SCHEMA_VERSION};
|
|
24959
|
+
`);
|
|
24960
|
+
}
|
|
24961
|
+
|
|
24962
|
+
class WikiSearchIndex {
|
|
24963
|
+
path;
|
|
24964
|
+
#database;
|
|
24965
|
+
constructor(path) {
|
|
24966
|
+
this.path = path;
|
|
24967
|
+
this.#database = new Database(path, { create: true });
|
|
24968
|
+
try {
|
|
24969
|
+
this.#database.exec("PRAGMA foreign_keys = ON; PRAGMA journal_mode = DELETE;");
|
|
24970
|
+
ensureSchema(this.#database);
|
|
24971
|
+
chmodSync5(path, 384);
|
|
24972
|
+
} catch (error2) {
|
|
24973
|
+
this.#database.close();
|
|
24974
|
+
throw error2;
|
|
24975
|
+
}
|
|
24976
|
+
}
|
|
24977
|
+
close() {
|
|
24978
|
+
this.#database.close();
|
|
24979
|
+
}
|
|
24980
|
+
upsert(source, document) {
|
|
24981
|
+
const id = documentId(source);
|
|
24982
|
+
const apply = this.#database.transaction(() => {
|
|
24983
|
+
this.#database.query("DELETE FROM wiki_search_fts WHERE document_id = ?").run(id);
|
|
24984
|
+
this.#database.query("DELETE FROM wiki_search_documents WHERE id = ?").run(id);
|
|
24985
|
+
this.#database.query(`
|
|
24986
|
+
INSERT INTO wiki_search_documents
|
|
24987
|
+
(id, kind, key, path, mtime_ms, size, title, text, date, family)
|
|
24988
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
24989
|
+
`).run(id, source.kind, source.key, source.path, source.mtimeMs, source.size, document.title, document.text, document.date ?? null, document.family ?? null);
|
|
24990
|
+
this.#database.query("INSERT INTO wiki_search_fts(document_id, kind, tokens) VALUES (?, ?, ?)").run(id, source.kind, document.tokens.join(" "));
|
|
24991
|
+
});
|
|
24992
|
+
apply.immediate();
|
|
24993
|
+
}
|
|
24994
|
+
sync(sources, prepare) {
|
|
24995
|
+
const result = { added: 0, updated: 0, removed: 0 };
|
|
24996
|
+
const existingRows = this.#database.query("SELECT id, path, mtime_ms, size FROM wiki_search_documents ORDER BY id").all();
|
|
24997
|
+
const existing = new Map(existingRows.map((row) => [row.id, row]));
|
|
24998
|
+
const present = new Set;
|
|
24999
|
+
const changed = [];
|
|
25000
|
+
for (const source of sources) {
|
|
25001
|
+
const id = documentId(source);
|
|
25002
|
+
present.add(id);
|
|
25003
|
+
const stored = existing.get(id);
|
|
25004
|
+
if (stored && stored.path === source.path && stored.mtime_ms === source.mtimeMs && stored.size === source.size) {
|
|
25005
|
+
continue;
|
|
25006
|
+
}
|
|
25007
|
+
try {
|
|
25008
|
+
const text2 = readFileSync22(source.path, "utf-8");
|
|
25009
|
+
changed.push({ source, document: prepare(source, text2), added: !stored });
|
|
25010
|
+
} catch {}
|
|
25011
|
+
}
|
|
25012
|
+
const removed = existingRows.filter((row) => !present.has(row.id));
|
|
25013
|
+
const apply = this.#database.transaction(() => {
|
|
25014
|
+
const deleteTerms = this.#database.query("DELETE FROM wiki_search_fts WHERE document_id = ?");
|
|
25015
|
+
const deleteDocument = this.#database.query("DELETE FROM wiki_search_documents WHERE id = ?");
|
|
25016
|
+
const insertDocument = this.#database.query(`
|
|
25017
|
+
INSERT INTO wiki_search_documents
|
|
25018
|
+
(id, kind, key, path, mtime_ms, size, title, text, date, family)
|
|
25019
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
25020
|
+
`);
|
|
25021
|
+
const insertTerms = this.#database.query(`
|
|
25022
|
+
INSERT INTO wiki_search_fts(document_id, kind, tokens)
|
|
25023
|
+
VALUES (?, ?, ?)
|
|
25024
|
+
`);
|
|
25025
|
+
for (const row of removed) {
|
|
25026
|
+
deleteTerms.run(row.id);
|
|
25027
|
+
deleteDocument.run(row.id);
|
|
25028
|
+
result.removed += 1;
|
|
25029
|
+
}
|
|
25030
|
+
for (const { source, document, added } of changed) {
|
|
25031
|
+
const id = documentId(source);
|
|
25032
|
+
deleteTerms.run(id);
|
|
25033
|
+
deleteDocument.run(id);
|
|
25034
|
+
insertDocument.run(id, source.kind, source.key, source.path, source.mtimeMs, source.size, document.title, document.text, document.date ?? null, document.family ?? null);
|
|
25035
|
+
insertTerms.run(id, source.kind, document.tokens.join(" "));
|
|
25036
|
+
if (added)
|
|
25037
|
+
result.added += 1;
|
|
25038
|
+
else
|
|
25039
|
+
result.updated += 1;
|
|
25040
|
+
}
|
|
25041
|
+
});
|
|
25042
|
+
apply.immediate();
|
|
25043
|
+
return result;
|
|
25044
|
+
}
|
|
25045
|
+
metadata(kinds) {
|
|
25046
|
+
if (kinds.length === 0)
|
|
25047
|
+
return [];
|
|
25048
|
+
const placeholders = kinds.map(() => "?").join(", ");
|
|
25049
|
+
const rows = this.#database.query(`SELECT id, kind, key, title, date
|
|
25050
|
+
FROM wiki_search_documents
|
|
25051
|
+
WHERE kind IN (${placeholders})`).all(...kinds);
|
|
25052
|
+
return rows.map((row) => ({
|
|
25053
|
+
id: row.id,
|
|
25054
|
+
kind: row.kind,
|
|
25055
|
+
key: row.key,
|
|
25056
|
+
title: row.title,
|
|
25057
|
+
...row.date ? { date: row.date } : {}
|
|
25058
|
+
}));
|
|
25059
|
+
}
|
|
25060
|
+
summaryMetadataByDate(query2) {
|
|
25061
|
+
const conditions = ["kind = 'summary'", "date IS NOT NULL"];
|
|
25062
|
+
const parameters = [];
|
|
25063
|
+
if (query2.year && query2.month) {
|
|
25064
|
+
const month = Number(query2.month);
|
|
25065
|
+
const nextYear = month === 12 ? String(Number(query2.year) + 1) : query2.year;
|
|
25066
|
+
const nextMonth = String(month === 12 ? 1 : month + 1).padStart(2, "0");
|
|
25067
|
+
conditions.push("date >= ?", "date < ?");
|
|
25068
|
+
parameters.push(`${query2.year}-${query2.month}-01`, `${nextYear}-${nextMonth}-01`);
|
|
25069
|
+
} else if (query2.year) {
|
|
25070
|
+
conditions.push("date >= ?", "date < ?");
|
|
25071
|
+
parameters.push(`${query2.year}-01-01`, `${Number(query2.year) + 1}-01-01`);
|
|
25072
|
+
} else if (query2.month) {
|
|
25073
|
+
conditions.push("substr(date, 6, 2) = ?");
|
|
25074
|
+
parameters.push(query2.month);
|
|
25075
|
+
}
|
|
25076
|
+
parameters.push(query2.limit);
|
|
25077
|
+
const rows = this.#database.query(`SELECT id, kind, key, title, date
|
|
25078
|
+
FROM wiki_search_documents
|
|
25079
|
+
WHERE ${conditions.join(" AND ")}
|
|
25080
|
+
ORDER BY date ${query2.direction === "oldest" ? "ASC" : "DESC"}, key ASC
|
|
25081
|
+
LIMIT ?`).all(...parameters);
|
|
25082
|
+
return rows.map((row) => ({
|
|
25083
|
+
id: row.id,
|
|
25084
|
+
kind: row.kind,
|
|
25085
|
+
key: row.key,
|
|
25086
|
+
title: row.title,
|
|
25087
|
+
...row.date ? { date: row.date } : {}
|
|
25088
|
+
}));
|
|
25089
|
+
}
|
|
25090
|
+
matchingDocumentIds(kinds, terms) {
|
|
25091
|
+
if (kinds.length === 0 || terms.length === 0)
|
|
25092
|
+
return new Set;
|
|
25093
|
+
const kindPlaceholders = kinds.map(() => "?").join(", ");
|
|
25094
|
+
const match = terms.map((term) => `"${term.replaceAll('"', '""')}"`).join(" OR ");
|
|
25095
|
+
const rows = this.#database.query(`SELECT DISTINCT document_id
|
|
25096
|
+
FROM wiki_search_fts
|
|
25097
|
+
WHERE wiki_search_fts MATCH ? AND kind IN (${kindPlaceholders})`).all(match, ...kinds);
|
|
25098
|
+
return new Set(rows.map((row) => row.document_id));
|
|
25099
|
+
}
|
|
25100
|
+
documents(ids) {
|
|
25101
|
+
if (ids.size === 0)
|
|
25102
|
+
return [];
|
|
25103
|
+
const values = [...ids];
|
|
25104
|
+
const rows = [];
|
|
25105
|
+
for (let offset = 0;offset < values.length; offset += 500) {
|
|
25106
|
+
const chunk = values.slice(offset, offset + 500);
|
|
25107
|
+
const placeholders = chunk.map(() => "?").join(", ");
|
|
25108
|
+
rows.push(...this.#database.query(`SELECT id, kind, key, path, title, text, date
|
|
25109
|
+
FROM wiki_search_documents
|
|
25110
|
+
WHERE id IN (${placeholders})`).all(...chunk));
|
|
25111
|
+
}
|
|
25112
|
+
return rows.map((row) => ({
|
|
25113
|
+
id: row.id,
|
|
25114
|
+
kind: row.kind,
|
|
25115
|
+
key: row.key,
|
|
25116
|
+
path: row.path,
|
|
25117
|
+
title: row.title,
|
|
25118
|
+
text: row.text,
|
|
25119
|
+
tokens: [],
|
|
25120
|
+
...row.date ? { date: row.date } : {}
|
|
25121
|
+
}));
|
|
25122
|
+
}
|
|
25123
|
+
}
|
|
25124
|
+
function resetCorruptWikiSearchIndex(path) {
|
|
25125
|
+
for (const candidate of [path, `${path}-journal`, `${path}-wal`, `${path}-shm`]) {
|
|
25126
|
+
if (!existsSync26(candidate))
|
|
25127
|
+
continue;
|
|
25128
|
+
unlinkSync18(candidate);
|
|
25129
|
+
}
|
|
25130
|
+
}
|
|
25131
|
+
var SEARCH_INDEX_SCHEMA_VERSION = 3;
|
|
25132
|
+
var init_wiki_search_index = __esm(async () => {
|
|
25133
|
+
await init_sqlite();
|
|
25134
|
+
});
|
|
25135
|
+
|
|
24923
25136
|
// ../../packages/core/src/mcp/wiki-server.ts
|
|
24924
25137
|
var exports_wiki_server = {};
|
|
24925
25138
|
__export(exports_wiki_server, {
|
|
@@ -24930,14 +25143,14 @@ import { AsyncLocalStorage as AsyncLocalStorage3 } from "async_hooks";
|
|
|
24930
25143
|
import { randomUUID as randomUUID21 } from "crypto";
|
|
24931
25144
|
import {
|
|
24932
25145
|
closeSync as closeSync4,
|
|
24933
|
-
existsSync as
|
|
25146
|
+
existsSync as existsSync27,
|
|
24934
25147
|
mkdirSync as mkdirSync24,
|
|
24935
25148
|
openSync as openSync4,
|
|
24936
25149
|
readdirSync as readdirSync10,
|
|
24937
|
-
readFileSync as
|
|
25150
|
+
readFileSync as readFileSync23,
|
|
24938
25151
|
renameSync as renameSync11,
|
|
24939
25152
|
statSync as statSync15,
|
|
24940
|
-
unlinkSync as
|
|
25153
|
+
unlinkSync as unlinkSync19,
|
|
24941
25154
|
writeFileSync as writeFileSync17
|
|
24942
25155
|
} from "fs";
|
|
24943
25156
|
import { basename as basename7, dirname as dirname16, join as join36, relative as relative2, resolve as resolve17 } from "path";
|
|
@@ -24980,15 +25193,15 @@ function acquireRecoveryGuard(lockPath) {
|
|
|
24980
25193
|
} catch (error2) {
|
|
24981
25194
|
closeSync4(fd);
|
|
24982
25195
|
try {
|
|
24983
|
-
|
|
25196
|
+
unlinkSync19(guardPath);
|
|
24984
25197
|
} catch {}
|
|
24985
25198
|
throw error2;
|
|
24986
25199
|
}
|
|
24987
25200
|
return () => {
|
|
24988
25201
|
closeSync4(fd);
|
|
24989
25202
|
try {
|
|
24990
|
-
if (
|
|
24991
|
-
|
|
25203
|
+
if (readFileSync23(guardPath, "utf-8") === ownerToken)
|
|
25204
|
+
unlinkSync19(guardPath);
|
|
24992
25205
|
} catch {}
|
|
24993
25206
|
};
|
|
24994
25207
|
} catch (error2) {
|
|
@@ -25013,7 +25226,7 @@ function acquireFileLock(path) {
|
|
|
25013
25226
|
} catch (error2) {
|
|
25014
25227
|
closeSync4(fd);
|
|
25015
25228
|
try {
|
|
25016
|
-
|
|
25229
|
+
unlinkSync19(lockPath);
|
|
25017
25230
|
} catch {}
|
|
25018
25231
|
throw error2;
|
|
25019
25232
|
}
|
|
@@ -25021,8 +25234,8 @@ function acquireFileLock(path) {
|
|
|
25021
25234
|
closeSync4(fd);
|
|
25022
25235
|
const releaseGuard = acquireRecoveryGuard(lockPath);
|
|
25023
25236
|
try {
|
|
25024
|
-
if (
|
|
25025
|
-
|
|
25237
|
+
if (readFileSync23(lockPath, "utf-8") === ownerToken)
|
|
25238
|
+
unlinkSync19(lockPath);
|
|
25026
25239
|
} catch {} finally {
|
|
25027
25240
|
releaseGuard();
|
|
25028
25241
|
}
|
|
@@ -25033,9 +25246,9 @@ function acquireFileLock(path) {
|
|
|
25033
25246
|
const releaseGuard = acquireRecoveryGuard(lockPath);
|
|
25034
25247
|
try {
|
|
25035
25248
|
try {
|
|
25036
|
-
const staleToken =
|
|
25037
|
-
if (Date.now() - statSync15(lockPath).mtimeMs > FILE_LOCK_STALE_MS &&
|
|
25038
|
-
|
|
25249
|
+
const staleToken = readFileSync23(lockPath, "utf-8");
|
|
25250
|
+
if (Date.now() - statSync15(lockPath).mtimeMs > FILE_LOCK_STALE_MS && readFileSync23(lockPath, "utf-8") === staleToken) {
|
|
25251
|
+
unlinkSync19(lockPath);
|
|
25039
25252
|
continue;
|
|
25040
25253
|
}
|
|
25041
25254
|
} catch {
|
|
@@ -25058,7 +25271,7 @@ function atomicWriteFile(path, content) {
|
|
|
25058
25271
|
renameSync11(temporaryPath, path);
|
|
25059
25272
|
} catch (error2) {
|
|
25060
25273
|
try {
|
|
25061
|
-
|
|
25274
|
+
unlinkSync19(temporaryPath);
|
|
25062
25275
|
} catch {}
|
|
25063
25276
|
throw error2;
|
|
25064
25277
|
}
|
|
@@ -25174,10 +25387,77 @@ function trigramSimilarity(left, right) {
|
|
|
25174
25387
|
overlap += 1;
|
|
25175
25388
|
return 2 * overlap / (a.size + b.size);
|
|
25176
25389
|
}
|
|
25390
|
+
function openWikiSearchIndex() {
|
|
25391
|
+
const path = resolve17(runtime().wikiDir, WIKI_SEARCH_INDEX_FILENAME);
|
|
25392
|
+
try {
|
|
25393
|
+
return new WikiSearchIndex(path);
|
|
25394
|
+
} catch (error2) {
|
|
25395
|
+
if (!/malformed|not a database|schema/i.test(String(error2)))
|
|
25396
|
+
return;
|
|
25397
|
+
try {
|
|
25398
|
+
resetCorruptWikiSearchIndex(path);
|
|
25399
|
+
return new WikiSearchIndex(path);
|
|
25400
|
+
} catch {
|
|
25401
|
+
return;
|
|
25402
|
+
}
|
|
25403
|
+
}
|
|
25404
|
+
}
|
|
25405
|
+
function prepareWikiSearchDocument(kind, key, text2) {
|
|
25406
|
+
const titleLine = text2.split(`
|
|
25407
|
+
`).find((line) => /^#+\s*/.test(line)) ?? "";
|
|
25408
|
+
const title = titleLine ? titleLine.replace(/^#+\s*/, "") : basename7(key);
|
|
25409
|
+
return {
|
|
25410
|
+
title,
|
|
25411
|
+
text: text2,
|
|
25412
|
+
tokens: canonicalSearchTokens(`${key} ${title} ${text2}`),
|
|
25413
|
+
...kind === "summary" && /^\d{4}-\d{2}-\d{2}/.test(key) ? { date: key.slice(0, 10), family: summaryTopicIdentity(key) } : {}
|
|
25414
|
+
};
|
|
25415
|
+
}
|
|
25416
|
+
function indexWikiSearchDocument(kind, key, text2) {
|
|
25417
|
+
const root = kind === "article" ? runtime().articlesDir : runtime().summariesDir;
|
|
25418
|
+
const path = resolve17(root, `${key}.md`);
|
|
25419
|
+
const index = openWikiSearchIndex();
|
|
25420
|
+
if (!index)
|
|
25421
|
+
return false;
|
|
25422
|
+
try {
|
|
25423
|
+
const stat = statSync15(path);
|
|
25424
|
+
index.upsert({ kind, key, path, mtimeMs: stat.mtimeMs, size: stat.size }, prepareWikiSearchDocument(kind, key, text2));
|
|
25425
|
+
return true;
|
|
25426
|
+
} catch {
|
|
25427
|
+
return false;
|
|
25428
|
+
} finally {
|
|
25429
|
+
index.close();
|
|
25430
|
+
}
|
|
25431
|
+
}
|
|
25432
|
+
function wikiIndexPath(kind) {
|
|
25433
|
+
return resolve17(runtime().wikiDir, WIKI_INDEX_FILENAMES[kind]);
|
|
25434
|
+
}
|
|
25435
|
+
function normalizeIndexDescription(raw) {
|
|
25436
|
+
const description = raw.replaceAll(/\s+/g, " ").trim();
|
|
25437
|
+
if (!description)
|
|
25438
|
+
return { error: "A non-empty one-line description is required." };
|
|
25439
|
+
if (description.length > MAX_INDEX_DESCRIPTION_LENGTH) {
|
|
25440
|
+
return {
|
|
25441
|
+
error: `Description must be at most ${MAX_INDEX_DESCRIPTION_LENGTH} characters (got ${description.length}).`
|
|
25442
|
+
};
|
|
25443
|
+
}
|
|
25444
|
+
return { description };
|
|
25445
|
+
}
|
|
25446
|
+
function normalizeWikiSlug(raw) {
|
|
25447
|
+
const slug = raw.trim().replace(/\.md$/i, "").replace(/^\/+/, "");
|
|
25448
|
+
if (!slug)
|
|
25449
|
+
return { error: "A non-empty slug is required." };
|
|
25450
|
+
if (/[[\]|\\]/.test(slug))
|
|
25451
|
+
return { error: "Slug must not contain [ ] | or backslashes." };
|
|
25452
|
+
if (slug.split("/").some((segment) => segment === "" || segment === "." || segment === "..")) {
|
|
25453
|
+
return { error: "Slug must not contain empty or relative path segments." };
|
|
25454
|
+
}
|
|
25455
|
+
return { slug };
|
|
25456
|
+
}
|
|
25177
25457
|
function parseWikiIndex(path) {
|
|
25178
25458
|
let text2;
|
|
25179
25459
|
try {
|
|
25180
|
-
text2 =
|
|
25460
|
+
text2 = readFileSync23(path, "utf-8");
|
|
25181
25461
|
} catch {
|
|
25182
25462
|
return [];
|
|
25183
25463
|
}
|
|
@@ -25331,7 +25611,7 @@ function wikiQuery(args) {
|
|
|
25331
25611
|
continue;
|
|
25332
25612
|
const fp = join36(sub, f.name);
|
|
25333
25613
|
try {
|
|
25334
|
-
const text2 =
|
|
25614
|
+
const text2 = readFileSync23(fp, "utf-8");
|
|
25335
25615
|
const key = `${entry.name}/${f.name.replace(/\.md$/i, "")}`;
|
|
25336
25616
|
scored.push({
|
|
25337
25617
|
kind: label === "articles" ? "article" : "skill",
|
|
@@ -25352,7 +25632,7 @@ function wikiQuery(args) {
|
|
|
25352
25632
|
}
|
|
25353
25633
|
const fp = join36(dir, entry.name);
|
|
25354
25634
|
try {
|
|
25355
|
-
const text2 =
|
|
25635
|
+
const text2 = readFileSync23(fp, "utf-8");
|
|
25356
25636
|
const key = entry.name.replace(/\.md$/i, "");
|
|
25357
25637
|
const resultKind = label === "articles" ? "article" : label === "topic" ? "topic" : label === "summaries" ? "summary" : "skill";
|
|
25358
25638
|
scored.push({
|
|
@@ -25466,14 +25746,45 @@ function wikiQuery(args) {
|
|
|
25466
25746
|
return 0;
|
|
25467
25747
|
return score;
|
|
25468
25748
|
}
|
|
25469
|
-
|
|
25470
|
-
|
|
25749
|
+
const bodyKinds = [
|
|
25750
|
+
...kind === "all" || kind === "article" ? ["article"] : [],
|
|
25751
|
+
...kind === "all" || kind === "summary" ? ["summary"] : []
|
|
25752
|
+
];
|
|
25753
|
+
if (bodyKinds.length > 0) {
|
|
25754
|
+
const searchIndex = openWikiSearchIndex();
|
|
25755
|
+
if (searchIndex) {
|
|
25756
|
+
try {
|
|
25757
|
+
const terms = canonicalSearchTokens(normalizedQuery);
|
|
25758
|
+
const ids = searchIndex.matchingDocumentIds(bodyKinds, terms);
|
|
25759
|
+
if (temporalDirection && bodyKinds.includes("summary")) {
|
|
25760
|
+
for (const item of searchIndex.summaryMetadataByDate({
|
|
25761
|
+
direction: temporalDirection === "newest" ? "latest" : "oldest",
|
|
25762
|
+
limit
|
|
25763
|
+
})) {
|
|
25764
|
+
ids.add(item.id);
|
|
25765
|
+
}
|
|
25766
|
+
}
|
|
25767
|
+
for (const document of searchIndex.documents(ids)) {
|
|
25768
|
+
scored.push({
|
|
25769
|
+
kind: document.kind,
|
|
25770
|
+
key: document.key,
|
|
25771
|
+
keyScore: scoreIndexKey(question, document.key),
|
|
25772
|
+
score: scoreMatch(document.text, document.key, document.kind),
|
|
25773
|
+
path: `${document.kind === "article" ? "articles" : "summaries"}/${document.key}.md`,
|
|
25774
|
+
text: document.text,
|
|
25775
|
+
title: document.title,
|
|
25776
|
+
...document.date ? { date: document.date } : {}
|
|
25777
|
+
});
|
|
25778
|
+
}
|
|
25779
|
+
} catch {} finally {
|
|
25780
|
+
searchIndex.close();
|
|
25781
|
+
}
|
|
25782
|
+
}
|
|
25783
|
+
}
|
|
25471
25784
|
if (kind === "all" && runtime().surface === "all")
|
|
25472
25785
|
scan(runtime().skillsDir, "skills");
|
|
25473
25786
|
if (kind === "all" || kind === "topic")
|
|
25474
25787
|
scan(runtime().topicsDir, "topic");
|
|
25475
|
-
if (kind === "all" || kind === "summary")
|
|
25476
|
-
scan(runtime().summariesDir, "summaries");
|
|
25477
25788
|
const merged = new Map;
|
|
25478
25789
|
for (const { candidate, keyScore, score } of indexCandidates) {
|
|
25479
25790
|
merged.set(`${candidate.kind}:${candidate.key}`, {
|
|
@@ -25605,7 +25916,7 @@ function wikiTopicBrief(args) {
|
|
|
25605
25916
|
const topicKey = wikiSummarySlug(rawTopic.replace(/^topic\//, "").replace(/\.md$/i, ""));
|
|
25606
25917
|
const filePath = resolve17(runtime().topicsDir, `${topicKey}.md`);
|
|
25607
25918
|
try {
|
|
25608
|
-
const content =
|
|
25919
|
+
const content = readFileSync23(filePath, "utf-8");
|
|
25609
25920
|
return {
|
|
25610
25921
|
content: [{ type: "text", text: `# Topic Brief: ${topicKey}
|
|
25611
25922
|
|
|
@@ -25657,7 +25968,7 @@ Adopted topic memory: ${memoryKey}` }]
|
|
|
25657
25968
|
return { content: [{ type: "text", text: "Invalid wiki document key." }], isError: true };
|
|
25658
25969
|
}
|
|
25659
25970
|
try {
|
|
25660
|
-
const content =
|
|
25971
|
+
const content = readFileSync23(filePath, "utf-8");
|
|
25661
25972
|
return {
|
|
25662
25973
|
content: [{ type: "text", text: `# Wiki ${kind}: ${key}
|
|
25663
25974
|
|
|
@@ -25677,18 +25988,18 @@ function wikiLastConversation(args) {
|
|
|
25677
25988
|
const name = slugify(topicNameFrom(rawTopic));
|
|
25678
25989
|
const archiveDir = resolve17(runtime().archiveDir, name);
|
|
25679
25990
|
try {
|
|
25680
|
-
let files =
|
|
25991
|
+
let files = existsSync27(archiveDir) ? readdirSync10(archiveDir).filter((f) => f.endsWith(".jsonl")).sort().reverse() : [];
|
|
25681
25992
|
if (files.length === 0) {
|
|
25682
|
-
files =
|
|
25993
|
+
files = existsSync27(runtime().archiveDir) ? readdirSync10(runtime().archiveDir).filter((f) => f.startsWith(name) && f.endsWith(".jsonl")).sort().reverse() : [];
|
|
25683
25994
|
}
|
|
25684
25995
|
if (files.length === 0) {
|
|
25685
25996
|
return {
|
|
25686
25997
|
content: [{ type: "text", text: `No archive found for topic: ${rawTopic}` }]
|
|
25687
25998
|
};
|
|
25688
25999
|
}
|
|
25689
|
-
const actualPath = files[0].includes("/") ? files[0] : resolve17(
|
|
26000
|
+
const actualPath = files[0].includes("/") ? files[0] : resolve17(existsSync27(archiveDir) && readdirSync10(archiveDir).includes(files[0]) ? archiveDir : runtime().archiveDir, files[0]);
|
|
25690
26001
|
try {
|
|
25691
|
-
const raw =
|
|
26002
|
+
const raw = readFileSync23(actualPath, "utf-8");
|
|
25692
26003
|
const lines = raw.trim().split(`
|
|
25693
26004
|
`).filter(Boolean);
|
|
25694
26005
|
const turns2 = [];
|
|
@@ -25761,7 +26072,7 @@ function skillQuery(args) {
|
|
|
25761
26072
|
continue;
|
|
25762
26073
|
const skillFile = resolve17(runtime().skillsDir, entry.name, "skill.md");
|
|
25763
26074
|
try {
|
|
25764
|
-
const text2 =
|
|
26075
|
+
const text2 = readFileSync23(skillFile, "utf-8");
|
|
25765
26076
|
const lower = text2.toLowerCase();
|
|
25766
26077
|
let score = 0;
|
|
25767
26078
|
for (const w of query2.split(/\s+/).filter(Boolean)) {
|
|
@@ -25832,7 +26143,7 @@ ${fresh.join(`
|
|
|
25832
26143
|
const skillPath = resolve17(skillDir, "skill.md");
|
|
25833
26144
|
let finalContent = content;
|
|
25834
26145
|
try {
|
|
25835
|
-
const existing =
|
|
26146
|
+
const existing = readFileSync23(skillPath, "utf-8");
|
|
25836
26147
|
finalContent = mergeGotchas(content, extractGotchas(existing));
|
|
25837
26148
|
} catch {}
|
|
25838
26149
|
writeFileSync17(skillPath, finalContent, "utf-8");
|
|
@@ -25845,15 +26156,7 @@ ${fresh.join(`
|
|
|
25845
26156
|
]
|
|
25846
26157
|
};
|
|
25847
26158
|
}
|
|
25848
|
-
function
|
|
25849
|
-
const rawTopic = safeExt(args, ["topic", "topicName"], "");
|
|
25850
|
-
const content = safeExt(args, ["content", "text", "body"], "");
|
|
25851
|
-
if (!rawTopic)
|
|
25852
|
-
return { content: [{ type: "text", text: "Missing topic." }] };
|
|
25853
|
-
if (!content)
|
|
25854
|
-
return { content: [{ type: "text", text: "Missing content." }] };
|
|
25855
|
-
const now = new Date;
|
|
25856
|
-
const dateStr = now.toISOString().slice(0, 10);
|
|
26159
|
+
function writeSummaryDocument(rawTopic, content, dateStr) {
|
|
25857
26160
|
const topicId = runtime().topicId;
|
|
25858
26161
|
const fileSlug = wikiBriefStorageKey(rawTopic, topicId);
|
|
25859
26162
|
ensureDir(runtime().summariesDir);
|
|
@@ -25880,7 +26183,7 @@ function saveWikiEntry(args) {
|
|
|
25880
26183
|
if (topicId && setTopicBrief2) {
|
|
25881
26184
|
try {
|
|
25882
26185
|
const briefPath = resolve17(runtime().topicsDir, `${fileSlug}.md`);
|
|
25883
|
-
let briefMd =
|
|
26186
|
+
let briefMd = existsSync27(briefPath) ? readFileSync23(briefPath, "utf-8") : undefined;
|
|
25884
26187
|
if (briefMd === undefined && getTopicBrief2 && !getTopicBrief2(fileSlug)?.briefMd) {
|
|
25885
26188
|
const legacy = getTopicBrief2(topicId)?.briefMd;
|
|
25886
26189
|
if (legacy)
|
|
@@ -25894,28 +26197,14 @@ function saveWikiEntry(args) {
|
|
|
25894
26197
|
sqliteUpdated = true;
|
|
25895
26198
|
} catch {}
|
|
25896
26199
|
}
|
|
25897
|
-
return {
|
|
25898
|
-
content: [
|
|
25899
|
-
{
|
|
25900
|
-
type: "text",
|
|
25901
|
-
text: `Saved summary: summaries/${summaryName}` + (sqliteUpdated ? `
|
|
25902
|
-
SQLite latest-summary also updated.` : "")
|
|
25903
|
-
}
|
|
25904
|
-
]
|
|
25905
|
-
};
|
|
26200
|
+
return { slug: summaryName.replace(/\.md$/i, ""), sqliteUpdated };
|
|
25906
26201
|
}
|
|
25907
|
-
function
|
|
25908
|
-
const rawTopic = safeExt(args, ["topic", "topicName"], "");
|
|
25909
|
-
const content = safeExt(args, ["content", "brief", "text", "body"], "");
|
|
25910
|
-
if (!rawTopic)
|
|
25911
|
-
return { content: [{ type: "text", text: "Missing topic." }] };
|
|
25912
|
-
if (!content)
|
|
25913
|
-
return { content: [{ type: "text", text: "Missing content." }] };
|
|
26202
|
+
function writeTopicDocument(rawTopic, content) {
|
|
25914
26203
|
const topicId = runtime().topicId;
|
|
25915
26204
|
const fileSlug = wikiBriefStorageKey(rawTopic, topicId);
|
|
25916
26205
|
const briefPath = resolve17(runtime().topicsDir, `${fileSlug}.md`);
|
|
25917
26206
|
ensureDir(dirname16(briefPath));
|
|
25918
|
-
const existed =
|
|
26207
|
+
const existed = existsSync27(briefPath);
|
|
25919
26208
|
writeFileSync17(briefPath, content, "utf-8");
|
|
25920
26209
|
const setTopicBrief2 = runtime().host.setTopicBrief;
|
|
25921
26210
|
let sqliteUpdated = false;
|
|
@@ -25925,68 +26214,227 @@ function saveTopicBrief(args) {
|
|
|
25925
26214
|
sqliteUpdated = true;
|
|
25926
26215
|
} catch {}
|
|
25927
26216
|
}
|
|
26217
|
+
return { slug: fileSlug, existed, sqliteUpdated };
|
|
26218
|
+
}
|
|
26219
|
+
function writeArticleDocument(slug, content) {
|
|
26220
|
+
const articlePath = resolve17(runtime().articlesDir, `${slug}.md`);
|
|
26221
|
+
ensureDir(dirname16(articlePath));
|
|
26222
|
+
const existed = existsSync27(articlePath);
|
|
26223
|
+
atomicWriteFile(articlePath, content);
|
|
26224
|
+
return { existed };
|
|
26225
|
+
}
|
|
26226
|
+
function wikiWrite(args) {
|
|
26227
|
+
const rawKind = safeExt(args, ["kind", "type"], "");
|
|
26228
|
+
const content = safeExt(args, ["content", "text", "body", "brief"], "");
|
|
26229
|
+
const rawDescription = safeExt(args, ["description", "desc"], "");
|
|
26230
|
+
const rawTopic = safeExt(args, ["topic", "topicName"], "");
|
|
26231
|
+
const rawSlug = safeExt(args, ["slug", "id"], "");
|
|
26232
|
+
const section = safeExt(args, ["section", "category"], undefined);
|
|
26233
|
+
const rawDate = safeExt(args, ["date", "created"], undefined);
|
|
26234
|
+
if (rawKind !== "summary" && rawKind !== "article" && rawKind !== "topic") {
|
|
26235
|
+
return {
|
|
26236
|
+
content: [{ type: "text", text: 'kind must be one of "summary", "article", "topic".' }],
|
|
26237
|
+
isError: true
|
|
26238
|
+
};
|
|
26239
|
+
}
|
|
26240
|
+
if (!content.trim()) {
|
|
26241
|
+
return { content: [{ type: "text", text: "Missing content." }], isError: true };
|
|
26242
|
+
}
|
|
26243
|
+
const descriptionResult = normalizeIndexDescription(rawDescription);
|
|
26244
|
+
if ("error" in descriptionResult) {
|
|
26245
|
+
return { content: [{ type: "text", text: descriptionResult.error }], isError: true };
|
|
26246
|
+
}
|
|
26247
|
+
const { description } = descriptionResult;
|
|
26248
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
26249
|
+
if (rawKind === "article") {
|
|
26250
|
+
const slugResult = normalizeWikiSlug(rawSlug);
|
|
26251
|
+
if ("error" in slugResult) {
|
|
26252
|
+
return { content: [{ type: "text", text: slugResult.error }], isError: true };
|
|
26253
|
+
}
|
|
26254
|
+
if (!section?.trim()) {
|
|
26255
|
+
return {
|
|
26256
|
+
content: [
|
|
26257
|
+
{ type: "text", text: "An article requires a section so the catalog stays navigable." }
|
|
26258
|
+
],
|
|
26259
|
+
isError: true
|
|
26260
|
+
};
|
|
26261
|
+
}
|
|
26262
|
+
const { existed } = writeArticleDocument(slugResult.slug, content);
|
|
26263
|
+
const link2 = indexRowOrPartialWrite("article", {
|
|
26264
|
+
kind: "article",
|
|
26265
|
+
slug: slugResult.slug,
|
|
26266
|
+
description,
|
|
26267
|
+
date: rawDate ?? today,
|
|
26268
|
+
section: section.trim()
|
|
26269
|
+
});
|
|
26270
|
+
if (typeof link2 !== "string")
|
|
26271
|
+
return link2;
|
|
26272
|
+
const searched = indexWikiSearchDocument("article", slugResult.slug, content);
|
|
26273
|
+
return {
|
|
26274
|
+
content: [
|
|
26275
|
+
{
|
|
26276
|
+
type: "text",
|
|
26277
|
+
text: `Saved article: articles/${slugResult.slug}.md (${existed ? "updated" : "created"})
|
|
26278
|
+
Indexed: ${link2}` + (searched ? "" : `
|
|
26279
|
+
${SEARCH_CACHE_SKIPPED_NOTE}`)
|
|
26280
|
+
}
|
|
26281
|
+
]
|
|
26282
|
+
};
|
|
26283
|
+
}
|
|
26284
|
+
const topic = rawTopic.trim();
|
|
26285
|
+
if (!topic) {
|
|
26286
|
+
return { content: [{ type: "text", text: "Missing topic." }], isError: true };
|
|
26287
|
+
}
|
|
26288
|
+
if (rawKind === "summary") {
|
|
26289
|
+
const dateStr = rawDate ?? today;
|
|
26290
|
+
const written2 = writeSummaryDocument(topic, content, dateStr);
|
|
26291
|
+
const link2 = indexRowOrPartialWrite("summary", {
|
|
26292
|
+
kind: "summary",
|
|
26293
|
+
slug: written2.slug,
|
|
26294
|
+
description,
|
|
26295
|
+
date: dateStr
|
|
26296
|
+
});
|
|
26297
|
+
if (typeof link2 !== "string")
|
|
26298
|
+
return link2;
|
|
26299
|
+
const searched = indexWikiSearchDocument("summary", written2.slug, content);
|
|
26300
|
+
return {
|
|
26301
|
+
content: [
|
|
26302
|
+
{
|
|
26303
|
+
type: "text",
|
|
26304
|
+
text: `Saved summary: summaries/${written2.slug}.md
|
|
26305
|
+
Indexed: ${link2}` + (written2.sqliteUpdated ? `
|
|
26306
|
+
SQLite latest-summary also updated.` : "") + (searched ? "" : `
|
|
26307
|
+
${SEARCH_CACHE_SKIPPED_NOTE}`)
|
|
26308
|
+
}
|
|
26309
|
+
]
|
|
26310
|
+
};
|
|
26311
|
+
}
|
|
26312
|
+
const written = writeTopicDocument(topic, content);
|
|
26313
|
+
const link = indexRowOrPartialWrite("topic", {
|
|
26314
|
+
kind: "topic",
|
|
26315
|
+
slug: written.slug,
|
|
26316
|
+
description,
|
|
26317
|
+
date: rawDate ?? today
|
|
26318
|
+
});
|
|
26319
|
+
if (typeof link !== "string")
|
|
26320
|
+
return link;
|
|
25928
26321
|
return {
|
|
25929
26322
|
content: [
|
|
25930
26323
|
{
|
|
25931
26324
|
type: "text",
|
|
25932
|
-
text: `Saved brief: topic/${
|
|
26325
|
+
text: `Saved brief: topic/${written.slug}.md (${written.existed ? "updated" : "created"})
|
|
26326
|
+
Indexed: ${link}` + (written.sqliteUpdated ? `
|
|
25933
26327
|
SQLite brief also updated.` : "")
|
|
25934
26328
|
}
|
|
25935
26329
|
]
|
|
25936
26330
|
};
|
|
25937
26331
|
}
|
|
25938
|
-
function
|
|
25939
|
-
const
|
|
25940
|
-
|
|
25941
|
-
|
|
25942
|
-
|
|
25943
|
-
|
|
25944
|
-
|
|
25945
|
-
|
|
25946
|
-
|
|
25947
|
-
|
|
25948
|
-
const
|
|
25949
|
-
|
|
25950
|
-
|
|
25951
|
-
|
|
25952
|
-
|
|
25953
|
-
|
|
25954
|
-
|
|
26332
|
+
function collectIndexableDocuments() {
|
|
26333
|
+
const sources = [];
|
|
26334
|
+
function add(kind, key, path) {
|
|
26335
|
+
try {
|
|
26336
|
+
const stat = statSync15(path);
|
|
26337
|
+
if (!stat.isFile())
|
|
26338
|
+
return;
|
|
26339
|
+
sources.push({ kind, key, path, mtimeMs: stat.mtimeMs, size: stat.size });
|
|
26340
|
+
} catch {}
|
|
26341
|
+
}
|
|
26342
|
+
for (const [root, kind, allowSubdirectories] of [
|
|
26343
|
+
[runtime().articlesDir, "article", true],
|
|
26344
|
+
[runtime().summariesDir, "summary", false]
|
|
26345
|
+
]) {
|
|
26346
|
+
let entries;
|
|
26347
|
+
try {
|
|
26348
|
+
entries = readdirSync10(root, { withFileTypes: true });
|
|
26349
|
+
} catch {
|
|
26350
|
+
continue;
|
|
26351
|
+
}
|
|
26352
|
+
for (const entry of entries) {
|
|
26353
|
+
if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
26354
|
+
add(kind, entry.name.replace(/\.md$/i, ""), join36(root, entry.name));
|
|
26355
|
+
continue;
|
|
26356
|
+
}
|
|
26357
|
+
if (!entry.isDirectory() || !allowSubdirectories)
|
|
26358
|
+
continue;
|
|
26359
|
+
let nested;
|
|
26360
|
+
try {
|
|
26361
|
+
nested = readdirSync10(join36(root, entry.name), { withFileTypes: true });
|
|
26362
|
+
} catch {
|
|
26363
|
+
continue;
|
|
26364
|
+
}
|
|
26365
|
+
for (const file of nested) {
|
|
26366
|
+
if (!file.isFile() || !file.name.endsWith(".md"))
|
|
26367
|
+
continue;
|
|
26368
|
+
add(kind, `${entry.name}/${file.name.replace(/\.md$/i, "")}`, join36(root, entry.name, file.name));
|
|
26369
|
+
}
|
|
26370
|
+
}
|
|
26371
|
+
}
|
|
26372
|
+
return sources;
|
|
26373
|
+
}
|
|
26374
|
+
function wikiReindex() {
|
|
26375
|
+
const documents = collectIndexableDocuments();
|
|
26376
|
+
const index = openWikiSearchIndex();
|
|
26377
|
+
if (!index) {
|
|
26378
|
+
return {
|
|
26379
|
+
content: [{ type: "text", text: "Could not open the wiki search index." }],
|
|
26380
|
+
isError: true
|
|
26381
|
+
};
|
|
26382
|
+
}
|
|
26383
|
+
let synced;
|
|
26384
|
+
try {
|
|
26385
|
+
synced = index.sync(documents, (source, text2) => prepareWikiSearchDocument(source.kind, source.key, text2));
|
|
26386
|
+
} catch (error2) {
|
|
26387
|
+
return {
|
|
26388
|
+
content: [{ type: "text", text: `Failed to rebuild the search index: ${String(error2)}` }],
|
|
26389
|
+
isError: true
|
|
26390
|
+
};
|
|
26391
|
+
} finally {
|
|
26392
|
+
index.close();
|
|
26393
|
+
}
|
|
26394
|
+
const lines = [
|
|
26395
|
+
`Search index: ${synced.added} added, ${synced.updated} updated, ${synced.removed} removed (${documents.length} documents).`
|
|
26396
|
+
];
|
|
26397
|
+
for (const kind of ["article", "summary"]) {
|
|
26398
|
+
const rows = new Set(parseWikiIndex(wikiIndexPath(kind)).filter((candidate) => candidate.kind === kind).map((candidate) => candidate.key));
|
|
26399
|
+
const keys = documents.filter((source) => source.kind === kind).map((source) => source.key);
|
|
26400
|
+
const unindexed = keys.filter((key) => !rows.has(key));
|
|
26401
|
+
const tombstones = [...rows].filter((key) => !keys.includes(key));
|
|
26402
|
+
lines.push(`${WIKI_INDEX_FILENAMES[kind]}: ${rows.size} rows for ${keys.length} documents` + (unindexed.length > 0 ? `; missing rows: ${unindexed.join(", ")}` : "") + (tombstones.length > 0 ? `; tombstones: ${tombstones.join(", ")}` : ""));
|
|
26403
|
+
}
|
|
26404
|
+
return { content: [{ type: "text", text: lines.join(`
|
|
26405
|
+
`) }] };
|
|
26406
|
+
}
|
|
26407
|
+
function indexRowOrPartialWrite(label, options) {
|
|
26408
|
+
try {
|
|
26409
|
+
return upsertIndexRow(options);
|
|
26410
|
+
} catch (error2) {
|
|
26411
|
+
return {
|
|
26412
|
+
content: [
|
|
26413
|
+
{
|
|
26414
|
+
type: "text",
|
|
26415
|
+
text: `Wrote the ${label} document but failed to index it (${String(error2)}). Retry the same wiki_write call: both writes are idempotent.`
|
|
26416
|
+
}
|
|
26417
|
+
],
|
|
26418
|
+
isError: true
|
|
26419
|
+
};
|
|
26420
|
+
}
|
|
26421
|
+
}
|
|
26422
|
+
function upsertIndexRow(options) {
|
|
26423
|
+
const { kind, slug, description, date, section } = options;
|
|
26424
|
+
const indexPath = wikiIndexPath(kind);
|
|
25955
26425
|
ensureDir(dirname16(indexPath));
|
|
25956
26426
|
const releaseLock = acquireFileLock(indexPath);
|
|
25957
26427
|
try {
|
|
25958
26428
|
let index;
|
|
25959
26429
|
try {
|
|
25960
|
-
index =
|
|
26430
|
+
index = readFileSync23(indexPath, "utf-8");
|
|
25961
26431
|
} catch {
|
|
25962
26432
|
index = "";
|
|
25963
26433
|
}
|
|
25964
26434
|
const lines = index.split(`
|
|
25965
26435
|
`);
|
|
25966
|
-
const
|
|
25967
|
-
|
|
25968
|
-
case "summary":
|
|
25969
|
-
return `- [[summaries/${slug}]] ${desc} (${dateStr})`;
|
|
25970
|
-
case "topic":
|
|
25971
|
-
return `- [[topic/${slug}]] ${desc} (${dateStr})`;
|
|
25972
|
-
case "skill":
|
|
25973
|
-
return `- [[skills/${slug}]] ${desc} (${dateStr})`;
|
|
25974
|
-
default:
|
|
25975
|
-
return `- [[articles/${slug}]] ${desc} (${dateStr})`;
|
|
25976
|
-
}
|
|
25977
|
-
})();
|
|
25978
|
-
const target = (() => {
|
|
25979
|
-
switch (kind) {
|
|
25980
|
-
case "summary":
|
|
25981
|
-
return `summaries/${slug}`;
|
|
25982
|
-
case "topic":
|
|
25983
|
-
return `topic/${slug}`;
|
|
25984
|
-
case "skill":
|
|
25985
|
-
return `skills/${slug}`;
|
|
25986
|
-
default:
|
|
25987
|
-
return `articles/${slug}`;
|
|
25988
|
-
}
|
|
25989
|
-
})();
|
|
26436
|
+
const target = `${WIKI_INDEX_NAMESPACES[kind]}/${slug}`;
|
|
26437
|
+
const link = `- [[${target}]] ${description} (${date})`;
|
|
25990
26438
|
const slugPattern = `[[${target}]]`;
|
|
25991
26439
|
let replaced = false;
|
|
25992
26440
|
for (let i = lines.length - 1;i >= 0; i--) {
|
|
@@ -26024,11 +26472,63 @@ function indexUpsert(args) {
|
|
|
26024
26472
|
}
|
|
26025
26473
|
atomicWriteFile(indexPath, lines.join(`
|
|
26026
26474
|
`));
|
|
26027
|
-
return
|
|
26475
|
+
return link;
|
|
26028
26476
|
} finally {
|
|
26029
26477
|
releaseLock();
|
|
26030
26478
|
}
|
|
26031
26479
|
}
|
|
26480
|
+
function wikiDocumentExists(kind, slug) {
|
|
26481
|
+
const root = kind === "article" ? runtime().articlesDir : kind === "summary" ? runtime().summariesDir : kind === "topic" ? runtime().topicsDir : runtime().skillsDir;
|
|
26482
|
+
const filePath = resolve17(root, `${slug}.md`);
|
|
26483
|
+
if (relative2(root, filePath).startsWith(".."))
|
|
26484
|
+
return false;
|
|
26485
|
+
try {
|
|
26486
|
+
return statSync15(filePath).isFile();
|
|
26487
|
+
} catch {
|
|
26488
|
+
return false;
|
|
26489
|
+
}
|
|
26490
|
+
}
|
|
26491
|
+
function indexUpsert(args) {
|
|
26492
|
+
const rawSlug = safeExt(args, ["slug", "id"], "");
|
|
26493
|
+
const rawDescription = safeExt(args, ["description", "desc", "text"], "");
|
|
26494
|
+
const rawKind = safeExt(args, ["kind", "type"], "article");
|
|
26495
|
+
const section = safeExt(args, ["section", "category"], undefined);
|
|
26496
|
+
const date = safeExt(args, ["date", "created"], undefined);
|
|
26497
|
+
if (!(rawKind in WIKI_INDEX_FILENAMES)) {
|
|
26498
|
+
return {
|
|
26499
|
+
content: [{ type: "text", text: `Unsupported kind: ${rawKind}` }],
|
|
26500
|
+
isError: true
|
|
26501
|
+
};
|
|
26502
|
+
}
|
|
26503
|
+
const kind = rawKind;
|
|
26504
|
+
const slugResult = normalizeWikiSlug(rawSlug);
|
|
26505
|
+
if ("error" in slugResult) {
|
|
26506
|
+
return { content: [{ type: "text", text: slugResult.error }], isError: true };
|
|
26507
|
+
}
|
|
26508
|
+
const descriptionResult = normalizeIndexDescription(rawDescription);
|
|
26509
|
+
if ("error" in descriptionResult) {
|
|
26510
|
+
return { content: [{ type: "text", text: descriptionResult.error }], isError: true };
|
|
26511
|
+
}
|
|
26512
|
+
if (kind !== "topic" && !wikiDocumentExists(kind, slugResult.slug)) {
|
|
26513
|
+
return {
|
|
26514
|
+
content: [
|
|
26515
|
+
{
|
|
26516
|
+
type: "text",
|
|
26517
|
+
text: `No ${kind} document named ${slugResult.slug}. Use wiki_write to create the document and its catalog row together.`
|
|
26518
|
+
}
|
|
26519
|
+
],
|
|
26520
|
+
isError: true
|
|
26521
|
+
};
|
|
26522
|
+
}
|
|
26523
|
+
const link = upsertIndexRow({
|
|
26524
|
+
kind,
|
|
26525
|
+
slug: slugResult.slug,
|
|
26526
|
+
description: descriptionResult.description,
|
|
26527
|
+
date: date ?? new Date().toISOString().slice(0, 10),
|
|
26528
|
+
section
|
|
26529
|
+
});
|
|
26530
|
+
return { content: [{ type: "text", text: `Index updated: ${link}` }] };
|
|
26531
|
+
}
|
|
26032
26532
|
function createWikiMcpServer(context, host2) {
|
|
26033
26533
|
const surface = context.surface ?? "all";
|
|
26034
26534
|
const wikiDir = resolve17(host2.wikiRoot);
|
|
@@ -26069,8 +26569,8 @@ function createWikiMcpServer(context, host2) {
|
|
|
26069
26569
|
wiki_last_conversation: wikiLastConversation,
|
|
26070
26570
|
skill_query: skillQuery,
|
|
26071
26571
|
skill_save: skillSave,
|
|
26072
|
-
|
|
26073
|
-
|
|
26572
|
+
wiki_write: wikiWrite,
|
|
26573
|
+
wiki_reindex: wikiReindex,
|
|
26074
26574
|
index_upsert: indexUpsert
|
|
26075
26575
|
};
|
|
26076
26576
|
const handler = tools.some((tool) => tool.name === name) ? handlers[name] : undefined;
|
|
@@ -26079,10 +26579,11 @@ function createWikiMcpServer(context, host2) {
|
|
|
26079
26579
|
});
|
|
26080
26580
|
return server;
|
|
26081
26581
|
}
|
|
26082
|
-
var wikiRuntime, FILE_LOCK_WAIT_MS = 10, FILE_LOCK_TIMEOUT_MS = 5000, FILE_LOCK_STALE_MS = 30000, lockWaitArray, SEARCH_STOP_WORDS, SEARCH_MONTHS, SEARCH_RECENCY_TERMS, WIKI_TOOLS, SKILL_TOOLS;
|
|
26083
|
-
var init_wiki_server = __esm(() => {
|
|
26582
|
+
var wikiRuntime, FILE_LOCK_WAIT_MS = 10, FILE_LOCK_TIMEOUT_MS = 5000, FILE_LOCK_STALE_MS = 30000, lockWaitArray, SEARCH_STOP_WORDS, SEARCH_MONTHS, SEARCH_RECENCY_TERMS, WIKI_SEARCH_INDEX_FILENAME = ".wiki-search-index.sqlite", WIKI_INDEX_FILENAMES, WIKI_INDEX_NAMESPACES, MAX_INDEX_DESCRIPTION_LENGTH = 400, SEARCH_CACHE_SKIPPED_NOTE = "Body-search cache was not updated; catalog retrieval still works. Run wiki_reindex to refill it.", WIKI_TOOLS, SKILL_TOOLS;
|
|
26583
|
+
var init_wiki_server = __esm(async () => {
|
|
26084
26584
|
init_config();
|
|
26085
26585
|
init_wiki_summary_names();
|
|
26586
|
+
await init_wiki_search_index();
|
|
26086
26587
|
wikiRuntime = new AsyncLocalStorage3;
|
|
26087
26588
|
lockWaitArray = new Int32Array(new SharedArrayBuffer(4));
|
|
26088
26589
|
SEARCH_STOP_WORDS = new Set([
|
|
@@ -26156,6 +26657,18 @@ var init_wiki_server = __esm(() => {
|
|
|
26156
26657
|
"\uCD5C\uCD08",
|
|
26157
26658
|
"\uC624\uB798\uB41C"
|
|
26158
26659
|
]);
|
|
26660
|
+
WIKI_INDEX_FILENAMES = {
|
|
26661
|
+
article: "article-index.md",
|
|
26662
|
+
summary: "summary-index.md",
|
|
26663
|
+
topic: "topic-index.md",
|
|
26664
|
+
skill: "skill-index.md"
|
|
26665
|
+
};
|
|
26666
|
+
WIKI_INDEX_NAMESPACES = {
|
|
26667
|
+
article: "articles",
|
|
26668
|
+
summary: "summaries",
|
|
26669
|
+
topic: "topic",
|
|
26670
|
+
skill: "skills"
|
|
26671
|
+
};
|
|
26159
26672
|
WIKI_TOOLS = [
|
|
26160
26673
|
{
|
|
26161
26674
|
name: "wiki_query",
|
|
@@ -26237,35 +26750,46 @@ var init_wiki_server = __esm(() => {
|
|
|
26237
26750
|
}
|
|
26238
26751
|
},
|
|
26239
26752
|
{
|
|
26240
|
-
name: "
|
|
26241
|
-
description: "
|
|
26753
|
+
name: "wiki_write",
|
|
26754
|
+
description: "Write a wiki document and its catalog row together. The only way to create a summary, article, or topic brief: summaries go to wiki/summaries/ + summary-index.md, articles to wiki/articles/ + article-index.md, briefs to wiki/topic/ + topic-index.md (also mirrored into SQLite for next-session injection). Never write wiki files by any other means.",
|
|
26242
26755
|
inputSchema: {
|
|
26243
26756
|
type: "object",
|
|
26244
26757
|
properties: {
|
|
26245
|
-
|
|
26246
|
-
|
|
26758
|
+
kind: {
|
|
26759
|
+
type: "string",
|
|
26760
|
+
enum: ["summary", "article", "topic"],
|
|
26761
|
+
description: "Which document to write"
|
|
26762
|
+
},
|
|
26763
|
+
content: { type: "string", description: "Document body in markdown" },
|
|
26764
|
+
description: {
|
|
26765
|
+
type: "string",
|
|
26766
|
+
description: "Single-line catalog description; required so the index stays useful"
|
|
26767
|
+
},
|
|
26768
|
+
topic: {
|
|
26769
|
+
type: "string",
|
|
26770
|
+
description: "Topic name; required for kind=summary and kind=topic"
|
|
26771
|
+
},
|
|
26772
|
+
slug: {
|
|
26773
|
+
type: "string",
|
|
26774
|
+
description: "Article slug in kebab-case; required for kind=article"
|
|
26775
|
+
},
|
|
26776
|
+
section: {
|
|
26777
|
+
type: "string",
|
|
26778
|
+
description: "H2 catalog section; required for kind=article"
|
|
26779
|
+
},
|
|
26780
|
+
date: { type: "string", description: "Override entry date YYYY-MM-DD (default: today)" }
|
|
26247
26781
|
},
|
|
26248
|
-
required: ["
|
|
26782
|
+
required: ["kind", "content", "description"]
|
|
26249
26783
|
}
|
|
26250
26784
|
},
|
|
26251
26785
|
{
|
|
26252
|
-
name: "
|
|
26253
|
-
description: "
|
|
26254
|
-
inputSchema: {
|
|
26255
|
-
type: "object",
|
|
26256
|
-
properties: {
|
|
26257
|
-
topic: { type: "string", description: "Topic name of the session" },
|
|
26258
|
-
content: {
|
|
26259
|
-
type: "string",
|
|
26260
|
-
description: "Full accumulated topic brief in markdown (persona layer + recent work)"
|
|
26261
|
-
}
|
|
26262
|
-
},
|
|
26263
|
-
required: ["topic", "content"]
|
|
26264
|
-
}
|
|
26786
|
+
name: "wiki_reindex",
|
|
26787
|
+
description: "Rebuild the derived body-search cache from the documents on disk and report catalog gaps. Run this once after adding documents outside wiki_write; retrieval itself never scans the wiki.",
|
|
26788
|
+
inputSchema: { type: "object", properties: {} }
|
|
26265
26789
|
},
|
|
26266
26790
|
{
|
|
26267
26791
|
name: "index_upsert",
|
|
26268
|
-
description: "
|
|
26792
|
+
description: "Correct the description or section of an entry that already exists. Cannot create an entry \u2014 use wiki_write for that.",
|
|
26269
26793
|
inputSchema: {
|
|
26270
26794
|
type: "object",
|
|
26271
26795
|
properties: {
|
|
@@ -26342,12 +26866,12 @@ __export(exports_activity_log, {
|
|
|
26342
26866
|
readSentFilesForTopic: () => readSentFilesForTopic
|
|
26343
26867
|
});
|
|
26344
26868
|
import {
|
|
26345
|
-
existsSync as
|
|
26869
|
+
existsSync as existsSync28,
|
|
26346
26870
|
mkdirSync as mkdirSync25,
|
|
26347
26871
|
readdirSync as readdirSync11,
|
|
26348
26872
|
renameSync as renameSync12,
|
|
26349
26873
|
statSync as statSync16,
|
|
26350
|
-
unlinkSync as
|
|
26874
|
+
unlinkSync as unlinkSync20,
|
|
26351
26875
|
writeFileSync as writeFileSync18
|
|
26352
26876
|
} from "fs";
|
|
26353
26877
|
import { basename as basename8, join as join37 } from "path";
|
|
@@ -26400,7 +26924,7 @@ function rotateOldLogs() {
|
|
|
26400
26924
|
if (freed >= toFree)
|
|
26401
26925
|
break;
|
|
26402
26926
|
try {
|
|
26403
|
-
|
|
26927
|
+
unlinkSync20(join37(logDir, file.name));
|
|
26404
26928
|
freed += file.size;
|
|
26405
26929
|
logger.info({ file: file.name, sizeKB: (file.size / 1024).toFixed(0) }, "Rotated out old log");
|
|
26406
26930
|
} catch (e) {
|
|
@@ -26426,7 +26950,7 @@ function entryMatchesTopic(e, topicName) {
|
|
|
26426
26950
|
}
|
|
26427
26951
|
function readSentFilesForTopic(userId, topicName) {
|
|
26428
26952
|
const file = join37(resolveStorageUsersLogDir(), String(userId), "sent-files.jsonl");
|
|
26429
|
-
if (!
|
|
26953
|
+
if (!existsSync28(file))
|
|
26430
26954
|
return [];
|
|
26431
26955
|
try {
|
|
26432
26956
|
return readJsonlLines(file).map((line) => JSON.parse(line)).filter((e) => entryMatchesTopic(e, topicName));
|
|
@@ -26437,7 +26961,7 @@ function readSentFilesForTopic(userId, topicName) {
|
|
|
26437
26961
|
}
|
|
26438
26962
|
function removeSentFilesForTopic(userId, topicName) {
|
|
26439
26963
|
const file = join37(resolveStorageUsersLogDir(), String(userId), "sent-files.jsonl");
|
|
26440
|
-
if (!
|
|
26964
|
+
if (!existsSync28(file))
|
|
26441
26965
|
return;
|
|
26442
26966
|
try {
|
|
26443
26967
|
const remaining = readJsonlLines(file).filter((line) => {
|
|
@@ -26452,7 +26976,7 @@ function removeSentFilesForTopic(userId, topicName) {
|
|
|
26452
26976
|
`)}
|
|
26453
26977
|
`);
|
|
26454
26978
|
} else {
|
|
26455
|
-
|
|
26979
|
+
unlinkSync20(file);
|
|
26456
26980
|
}
|
|
26457
26981
|
} catch (e) {
|
|
26458
26982
|
logger.warn({ err: e, userId, topicName }, "Failed to remove sent-files for topic");
|
|
@@ -27250,7 +27774,7 @@ async function buildHostedSurfaceServer(surface, context) {
|
|
|
27250
27774
|
case "wiki":
|
|
27251
27775
|
case "skills": {
|
|
27252
27776
|
const [{ createWikiMcpServer: createWikiMcpServer2 }, storage, { WORKSPACE_DIR: WORKSPACE_DIR2 }] = await Promise.all([
|
|
27253
|
-
|
|
27777
|
+
init_wiki_server().then(() => exports_wiki_server),
|
|
27254
27778
|
init_storage_public().then(() => exports_storage_public),
|
|
27255
27779
|
init_mcp_runtime_host().then(() => exports_mcp_runtime_host)
|
|
27256
27780
|
]);
|
|
@@ -27961,7 +28485,7 @@ var init_spec = __esm(() => {
|
|
|
27961
28485
|
});
|
|
27962
28486
|
|
|
27963
28487
|
// ../../packages/mcp-host/src/manifest.ts
|
|
27964
|
-
import { existsSync as
|
|
28488
|
+
import { existsSync as existsSync29, mkdirSync as mkdirSync26, readFileSync as readFileSync24, renameSync as renameSync13, writeFileSync as writeFileSync19 } from "fs";
|
|
27965
28489
|
import { dirname as dirname17 } from "path";
|
|
27966
28490
|
import { z as z14 } from "zod";
|
|
27967
28491
|
|
|
@@ -28006,11 +28530,11 @@ class McpManifest {
|
|
|
28006
28530
|
return this.entries.get(key)?.enabled ?? false;
|
|
28007
28531
|
}
|
|
28008
28532
|
load() {
|
|
28009
|
-
if (!
|
|
28533
|
+
if (!existsSync29(this.file))
|
|
28010
28534
|
return;
|
|
28011
28535
|
let parsed;
|
|
28012
28536
|
try {
|
|
28013
|
-
parsed = manifestFileSchema.parse(JSON.parse(
|
|
28537
|
+
parsed = manifestFileSchema.parse(JSON.parse(readFileSync24(this.file, "utf8")));
|
|
28014
28538
|
} catch (e) {
|
|
28015
28539
|
throw new Error(`Invalid MCP manifest at ${this.file}: ${e instanceof Error ? e.message : String(e)}`);
|
|
28016
28540
|
}
|
|
@@ -28060,9 +28584,9 @@ import { execFileSync as execFileSync8, spawn as spawn8 } from "child_process";
|
|
|
28060
28584
|
import {
|
|
28061
28585
|
mkdirSync as mkdirSync27,
|
|
28062
28586
|
readdirSync as readdirSync12,
|
|
28063
|
-
readFileSync as
|
|
28587
|
+
readFileSync as readFileSync25,
|
|
28064
28588
|
renameSync as renameSync14,
|
|
28065
|
-
unlinkSync as
|
|
28589
|
+
unlinkSync as unlinkSync21,
|
|
28066
28590
|
writeFileSync as writeFileSync20
|
|
28067
28591
|
} from "fs";
|
|
28068
28592
|
import { connect, createServer as createServer3 } from "net";
|
|
@@ -28368,7 +28892,7 @@ class McpHost {
|
|
|
28368
28892
|
if (file.includes(".tmp-"))
|
|
28369
28893
|
continue;
|
|
28370
28894
|
try {
|
|
28371
|
-
const port = Number.parseInt(
|
|
28895
|
+
const port = Number.parseInt(readFileSync25(join38(this.portsDir, file), "utf8").trim(), 10);
|
|
28372
28896
|
if (!Number.isNaN(port))
|
|
28373
28897
|
claims.set(file, port);
|
|
28374
28898
|
} catch {}
|
|
@@ -28388,7 +28912,7 @@ class McpHost {
|
|
|
28388
28912
|
}
|
|
28389
28913
|
deletePortFile(fileName) {
|
|
28390
28914
|
try {
|
|
28391
|
-
|
|
28915
|
+
unlinkSync21(join38(this.portsDir, fileName));
|
|
28392
28916
|
} catch {}
|
|
28393
28917
|
}
|
|
28394
28918
|
cleanupRunning(rkey, inst) {
|
|
@@ -28493,9 +29017,9 @@ var init_src3 = __esm(() => {
|
|
|
28493
29017
|
import { randomUUID as randomUUID24 } from "crypto";
|
|
28494
29018
|
import {
|
|
28495
29019
|
copyFileSync as copyFileSync4,
|
|
28496
|
-
existsSync as
|
|
29020
|
+
existsSync as existsSync30,
|
|
28497
29021
|
mkdirSync as mkdirSync28,
|
|
28498
|
-
readFileSync as
|
|
29022
|
+
readFileSync as readFileSync26,
|
|
28499
29023
|
rmSync as rmSync9,
|
|
28500
29024
|
statSync as statSync18,
|
|
28501
29025
|
writeFileSync as writeFileSync21
|
|
@@ -28531,7 +29055,7 @@ class NodeFileStore {
|
|
|
28531
29055
|
if (!FILE_ID_RE.test(fileId))
|
|
28532
29056
|
return null;
|
|
28533
29057
|
try {
|
|
28534
|
-
const parsed = JSON.parse(
|
|
29058
|
+
const parsed = JSON.parse(readFileSync26(this.#metadataPath(fileId), "utf8"));
|
|
28535
29059
|
if (typeof parsed.filename !== "string" || typeof parsed.mimeType !== "string" || typeof parsed.sizeBytes !== "number" || typeof parsed.savedName !== "string") {
|
|
28536
29060
|
return null;
|
|
28537
29061
|
}
|
|
@@ -28554,7 +29078,7 @@ class NodeFileStore {
|
|
|
28554
29078
|
hooks = {
|
|
28555
29079
|
resolveAttachmentByFileId: (fileId) => {
|
|
28556
29080
|
const metadata = this.#metadata(fileId);
|
|
28557
|
-
if (!metadata || !
|
|
29081
|
+
if (!metadata || !existsSync30(join39(this.uploadDir, metadata.savedName)))
|
|
28558
29082
|
return null;
|
|
28559
29083
|
return this.#attachment(fileId, metadata);
|
|
28560
29084
|
},
|
|
@@ -28563,7 +29087,7 @@ class NodeFileStore {
|
|
|
28563
29087
|
if (!metadata)
|
|
28564
29088
|
return null;
|
|
28565
29089
|
const path = join39(this.uploadDir, metadata.savedName);
|
|
28566
|
-
return
|
|
29090
|
+
return existsSync30(path) ? path : null;
|
|
28567
29091
|
},
|
|
28568
29092
|
storeLocalFileAsUpload: (absPath, access = {}) => this.store(absPath, access),
|
|
28569
29093
|
deleteFilesForTopic: (topicId) => this.deleteForTopic(topicId)
|
|
@@ -28606,7 +29130,7 @@ class NodeFileStore {
|
|
|
28606
29130
|
if (!allowed)
|
|
28607
29131
|
return null;
|
|
28608
29132
|
const path = join39(this.uploadDir, metadata.savedName);
|
|
28609
|
-
if (!
|
|
29133
|
+
if (!existsSync30(path))
|
|
28610
29134
|
return null;
|
|
28611
29135
|
return new Response(Bun.file(path), {
|
|
28612
29136
|
headers: {
|
|
@@ -28775,12 +29299,12 @@ function createPollingSseStream(req, options) {
|
|
|
28775
29299
|
// ../../packages/node/src/control.ts
|
|
28776
29300
|
import { randomUUID as randomUUID25, timingSafeEqual as timingSafeEqual4 } from "crypto";
|
|
28777
29301
|
import {
|
|
28778
|
-
chmodSync as
|
|
28779
|
-
existsSync as
|
|
29302
|
+
chmodSync as chmodSync6,
|
|
29303
|
+
existsSync as existsSync31,
|
|
28780
29304
|
mkdirSync as mkdirSync29,
|
|
28781
|
-
readFileSync as
|
|
29305
|
+
readFileSync as readFileSync27,
|
|
28782
29306
|
renameSync as renameSync15,
|
|
28783
|
-
unlinkSync as
|
|
29307
|
+
unlinkSync as unlinkSync22,
|
|
28784
29308
|
writeFileSync as writeFileSync22
|
|
28785
29309
|
} from "fs";
|
|
28786
29310
|
import { dirname as dirname18, resolve as resolve21 } from "path";
|
|
@@ -29287,16 +29811,16 @@ function writeNodeDaemonInfo(port, startedAt) {
|
|
|
29287
29811
|
const temporary = `${NODE_DAEMON_INFO_PATH}.${process.pid}.${randomUUID25()}.tmp`;
|
|
29288
29812
|
writeFileSync22(temporary, `${JSON.stringify(info, null, 2)}
|
|
29289
29813
|
`, { mode: 384 });
|
|
29290
|
-
|
|
29814
|
+
chmodSync6(temporary, 384);
|
|
29291
29815
|
renameSync15(temporary, NODE_DAEMON_INFO_PATH);
|
|
29292
|
-
|
|
29816
|
+
chmodSync6(NODE_DAEMON_INFO_PATH, 384);
|
|
29293
29817
|
return info;
|
|
29294
29818
|
}
|
|
29295
29819
|
function readNodeDaemonInfo() {
|
|
29296
|
-
if (!
|
|
29820
|
+
if (!existsSync31(NODE_DAEMON_INFO_PATH))
|
|
29297
29821
|
return null;
|
|
29298
29822
|
try {
|
|
29299
|
-
const value = JSON.parse(
|
|
29823
|
+
const value = JSON.parse(readFileSync27(NODE_DAEMON_INFO_PATH, "utf8"));
|
|
29300
29824
|
if (value?.schemaVersion !== 1 || value.stateDir !== STATE_DIR || !Number.isInteger(value.protocolVersion) || !Number.isInteger(value.pid) || !Number.isInteger(value.port) || value.port <= 0) {
|
|
29301
29825
|
return null;
|
|
29302
29826
|
}
|
|
@@ -29310,7 +29834,7 @@ function removeNodeDaemonInfo(expected) {
|
|
|
29310
29834
|
if (!current3 || current3.pid !== expected.pid || current3.port !== expected.port)
|
|
29311
29835
|
return;
|
|
29312
29836
|
try {
|
|
29313
|
-
|
|
29837
|
+
unlinkSync22(NODE_DAEMON_INFO_PATH);
|
|
29314
29838
|
} catch {}
|
|
29315
29839
|
}
|
|
29316
29840
|
async function fetchWithTimeout(url, init, timeoutMs) {
|
|
@@ -29584,7 +30108,7 @@ var init_schedule = __esm(() => {
|
|
|
29584
30108
|
|
|
29585
30109
|
// ../../packages/module-cron/src/scripts.ts
|
|
29586
30110
|
import { spawn as spawn9 } from "child_process";
|
|
29587
|
-
import { existsSync as
|
|
30111
|
+
import { existsSync as existsSync32, mkdirSync as mkdirSync30, readdirSync as readdirSync13 } from "fs";
|
|
29588
30112
|
import { resolve as resolve22, sep as sep2 } from "path";
|
|
29589
30113
|
function validateCronScriptName(script) {
|
|
29590
30114
|
if (!/^[A-Za-z0-9_][A-Za-z0-9_.-]*\.py$/.test(script) || script.includes("..") || script.includes("/") || script.includes("\\")) {
|
|
@@ -29607,7 +30131,7 @@ function listCronScripts() {
|
|
|
29607
30131
|
}
|
|
29608
30132
|
function cronScriptExists(script) {
|
|
29609
30133
|
try {
|
|
29610
|
-
return
|
|
30134
|
+
return existsSync32(resolveCronScriptPath(script));
|
|
29611
30135
|
} catch {
|
|
29612
30136
|
return false;
|
|
29613
30137
|
}
|
|
@@ -29639,7 +30163,7 @@ async function runCronPromptScript(options) {
|
|
|
29639
30163
|
if (options.signal?.aborted)
|
|
29640
30164
|
throw new CronScriptError("script run aborted");
|
|
29641
30165
|
const scriptPath = resolveCronScriptPath(options.script);
|
|
29642
|
-
if (!
|
|
30166
|
+
if (!existsSync32(scriptPath))
|
|
29643
30167
|
throw new CronScriptError(`cron script not found: ${options.script}`);
|
|
29644
30168
|
const timeoutMs = Math.max(5000, options.timeoutMs ?? DEFAULT_SCRIPT_TIMEOUT_MS);
|
|
29645
30169
|
const outputLimitBytes = Math.max(1024, options.outputLimitBytes ?? DEFAULT_OUTPUT_LIMIT_BYTES);
|
|
@@ -30840,7 +31364,7 @@ var init_scheduler = __esm(async () => {
|
|
|
30840
31364
|
});
|
|
30841
31365
|
|
|
30842
31366
|
// ../../packages/module-cron/src/module.ts
|
|
30843
|
-
import { existsSync as
|
|
31367
|
+
import { existsSync as existsSync33 } from "fs";
|
|
30844
31368
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
30845
31369
|
function envMs(name, fallback) {
|
|
30846
31370
|
const parsed = Number.parseInt(process.env[name] ?? "", 10);
|
|
@@ -30871,7 +31395,7 @@ function createCronModule(options = {}) {
|
|
|
30871
31395
|
if (event.type === "topic-deleted")
|
|
30872
31396
|
trackCleanup(resetCronTopicContext(event.topicId));
|
|
30873
31397
|
});
|
|
30874
|
-
const mcpServerFile = options.mcpServerFile ?? (
|
|
31398
|
+
const mcpServerFile = options.mcpServerFile ?? (existsSync33(SOURCE_MCP_SERVER_FILE) ? SOURCE_MCP_SERVER_FILE : PACKAGED_MCP_SERVER_FILE);
|
|
30875
31399
|
const unregisterMcp = host2.registerRuntimeMcpServer("cron-manager", {
|
|
30876
31400
|
scopes: ["forum", "manager"],
|
|
30877
31401
|
forumRequired: true,
|
|
@@ -32369,7 +32893,7 @@ var init_context_usage = __esm(async () => {
|
|
|
32369
32893
|
|
|
32370
32894
|
// ../../adapters/terminal/src/path-suggest.ts
|
|
32371
32895
|
import { execFile as execFile3 } from "child_process";
|
|
32372
|
-
import { existsSync as
|
|
32896
|
+
import { existsSync as existsSync34, readdirSync as readdirSync14, statSync as statSync19 } from "fs";
|
|
32373
32897
|
import { homedir as homedir10 } from "os";
|
|
32374
32898
|
import { basename as basename11, dirname as dirname19, join as join40, sep as sep3 } from "path";
|
|
32375
32899
|
import { promisify as promisify3 } from "util";
|
|
@@ -32618,7 +33142,7 @@ function fragmentToAbsolutePath(frag) {
|
|
|
32618
33142
|
}
|
|
32619
33143
|
function fragmentResolves(frag) {
|
|
32620
33144
|
try {
|
|
32621
|
-
return
|
|
33145
|
+
return existsSync34(fragmentToAbsolutePath(frag));
|
|
32622
33146
|
} catch {
|
|
32623
33147
|
return false;
|
|
32624
33148
|
}
|
|
@@ -39312,7 +39836,7 @@ function renderOutbound(text2, maxLen = 4096) {
|
|
|
39312
39836
|
}
|
|
39313
39837
|
|
|
39314
39838
|
// ../../adapters/telegram/src/adapter.ts
|
|
39315
|
-
import { existsSync as
|
|
39839
|
+
import { existsSync as existsSync35 } from "fs";
|
|
39316
39840
|
import { basename as basename12, extname as extname5 } from "path";
|
|
39317
39841
|
function startTelegramAdapter(opts) {
|
|
39318
39842
|
const { client, forumChatId } = opts;
|
|
@@ -39800,7 +40324,7 @@ function startTelegramAdapter(opts) {
|
|
|
39800
40324
|
logger.warn({ path, chatId }, "telegram adapter: blocked sensitive file path");
|
|
39801
40325
|
return { ref: null, delivered: false, error: "path matches the sensitive-file blacklist" };
|
|
39802
40326
|
}
|
|
39803
|
-
if (!
|
|
40327
|
+
if (!existsSync35(path)) {
|
|
39804
40328
|
const sent = await client.sendMessage(chatId, `File: ${path}`, base).catch(() => null);
|
|
39805
40329
|
const messageId = sentMessageId(sent);
|
|
39806
40330
|
return {
|
|
@@ -40982,19 +41506,19 @@ __export(exports_join, {
|
|
|
40982
41506
|
});
|
|
40983
41507
|
import { createHash as createHash11, randomUUID as randomUUID27 } from "crypto";
|
|
40984
41508
|
import {
|
|
40985
|
-
chmodSync as
|
|
41509
|
+
chmodSync as chmodSync7,
|
|
40986
41510
|
closeSync as closeSync5,
|
|
40987
|
-
existsSync as
|
|
41511
|
+
existsSync as existsSync36,
|
|
40988
41512
|
fsyncSync as fsyncSync2,
|
|
40989
41513
|
linkSync,
|
|
40990
41514
|
lstatSync,
|
|
40991
41515
|
mkdirSync as mkdirSync32,
|
|
40992
41516
|
openSync as openSync5,
|
|
40993
|
-
readFileSync as
|
|
41517
|
+
readFileSync as readFileSync28,
|
|
40994
41518
|
renameSync as renameSync16,
|
|
40995
41519
|
rmSync as rmSync10,
|
|
40996
41520
|
statSync as statSync20,
|
|
40997
|
-
unlinkSync as
|
|
41521
|
+
unlinkSync as unlinkSync23,
|
|
40998
41522
|
writeFileSync as writeFileSync23
|
|
40999
41523
|
} from "fs";
|
|
41000
41524
|
import { dirname as dirname21, resolve as resolve23 } from "path";
|
|
@@ -41094,7 +41618,7 @@ function withJoinCredentialLock(operation) {
|
|
|
41094
41618
|
throw error2;
|
|
41095
41619
|
let current3 = null;
|
|
41096
41620
|
try {
|
|
41097
|
-
current3 = JSON.parse(
|
|
41621
|
+
current3 = JSON.parse(readFileSync28(ownerPath, "utf8"));
|
|
41098
41622
|
} catch {}
|
|
41099
41623
|
let ageMs;
|
|
41100
41624
|
try {
|
|
@@ -41124,7 +41648,7 @@ function withJoinCredentialLock(operation) {
|
|
|
41124
41648
|
return operation();
|
|
41125
41649
|
} finally {
|
|
41126
41650
|
try {
|
|
41127
|
-
const current3 = JSON.parse(
|
|
41651
|
+
const current3 = JSON.parse(readFileSync28(ownerPath, "utf8"));
|
|
41128
41652
|
if (current3.pid === owner.pid && current3.token === owner.token) {
|
|
41129
41653
|
rmSync10(lockPath, { recursive: true, force: true });
|
|
41130
41654
|
}
|
|
@@ -41147,9 +41671,9 @@ function joinCredentialDigest(join42) {
|
|
|
41147
41671
|
return createHash11("sha256").update(JSON.stringify(normalizedJoin(join42))).digest("base64url");
|
|
41148
41672
|
}
|
|
41149
41673
|
function readPersistedJoin(path = joinFilePath()) {
|
|
41150
|
-
if (!
|
|
41674
|
+
if (!existsSync36(path))
|
|
41151
41675
|
return null;
|
|
41152
|
-
const parsed = JSON.parse(
|
|
41676
|
+
const parsed = JSON.parse(readFileSync28(path, "utf-8"));
|
|
41153
41677
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
41154
41678
|
throw new Error("persisted join credentials are not a JSON object");
|
|
41155
41679
|
}
|
|
@@ -41168,7 +41692,7 @@ function saveJoinWhileLocked(join42, options = {}) {
|
|
|
41168
41692
|
const directory = dirname21(path);
|
|
41169
41693
|
const normalized = normalizedJoin(join42);
|
|
41170
41694
|
mkdirSync32(directory, { recursive: true });
|
|
41171
|
-
if (
|
|
41695
|
+
if (existsSync36(path)) {
|
|
41172
41696
|
if (lstatSync(path).isSymbolicLink()) {
|
|
41173
41697
|
throw new Error(`refusing to replace symlinked Otium join file at ${path}`);
|
|
41174
41698
|
}
|
|
@@ -41181,7 +41705,7 @@ function saveJoinWhileLocked(join42, options = {}) {
|
|
|
41181
41705
|
}
|
|
41182
41706
|
}
|
|
41183
41707
|
if (existing && joinsEqual(existing, normalized)) {
|
|
41184
|
-
|
|
41708
|
+
chmodSync7(path, 384);
|
|
41185
41709
|
const fileFd = openSync5(path, "r");
|
|
41186
41710
|
try {
|
|
41187
41711
|
fsyncSync2(fileFd);
|
|
@@ -41213,9 +41737,9 @@ function saveJoinWhileLocked(join42, options = {}) {
|
|
|
41213
41737
|
renameSync16(temporaryPath, path);
|
|
41214
41738
|
} else {
|
|
41215
41739
|
linkSync(temporaryPath, path);
|
|
41216
|
-
|
|
41740
|
+
unlinkSync23(temporaryPath);
|
|
41217
41741
|
}
|
|
41218
|
-
|
|
41742
|
+
chmodSync7(path, 384);
|
|
41219
41743
|
const directoryFd = openSync5(directory, "r");
|
|
41220
41744
|
try {
|
|
41221
41745
|
fsyncSync2(directoryFd);
|
|
@@ -41225,8 +41749,8 @@ function saveJoinWhileLocked(join42, options = {}) {
|
|
|
41225
41749
|
} catch (error2) {
|
|
41226
41750
|
if (fd !== undefined)
|
|
41227
41751
|
closeSync5(fd);
|
|
41228
|
-
if (
|
|
41229
|
-
|
|
41752
|
+
if (existsSync36(temporaryPath))
|
|
41753
|
+
unlinkSync23(temporaryPath);
|
|
41230
41754
|
throw error2;
|
|
41231
41755
|
}
|
|
41232
41756
|
return path;
|
|
@@ -41237,12 +41761,12 @@ function saveJoin(join42, options = {}) {
|
|
|
41237
41761
|
function removeJoin() {
|
|
41238
41762
|
return withJoinCredentialLock(() => {
|
|
41239
41763
|
const path = joinFilePath();
|
|
41240
|
-
if (!
|
|
41764
|
+
if (!existsSync36(path))
|
|
41241
41765
|
return false;
|
|
41242
41766
|
if (lstatSync(path).isSymbolicLink()) {
|
|
41243
41767
|
throw new Error(`refusing to remove symlinked Otium join file at ${path}`);
|
|
41244
41768
|
}
|
|
41245
|
-
|
|
41769
|
+
unlinkSync23(path);
|
|
41246
41770
|
const directoryFd = openSync5(dirname21(path), "r");
|
|
41247
41771
|
try {
|
|
41248
41772
|
fsyncSync2(directoryFd);
|
|
@@ -41269,10 +41793,10 @@ function loadJoin() {
|
|
|
41269
41793
|
logger.warn("otium: OTIUM_CENTRAL_URL, OTIUM_CELL_ID, OTIUM_CELL_SECRET must be set together \u2014 ignoring partial env");
|
|
41270
41794
|
}
|
|
41271
41795
|
const path = joinFilePath();
|
|
41272
|
-
if (!
|
|
41796
|
+
if (!existsSync36(path))
|
|
41273
41797
|
return null;
|
|
41274
41798
|
try {
|
|
41275
|
-
const parsed = JSON.parse(
|
|
41799
|
+
const parsed = JSON.parse(readFileSync28(path, "utf-8"));
|
|
41276
41800
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
41277
41801
|
return null;
|
|
41278
41802
|
return normalizeJoin(parsed);
|
|
@@ -41296,11 +41820,11 @@ var exports_join_status = {};
|
|
|
41296
41820
|
__export(exports_join_status, {
|
|
41297
41821
|
hasConfiguredOtiumJoin: () => hasConfiguredOtiumJoin
|
|
41298
41822
|
});
|
|
41299
|
-
import { existsSync as
|
|
41823
|
+
import { existsSync as existsSync37 } from "fs";
|
|
41300
41824
|
import { resolve as resolve24 } from "path";
|
|
41301
41825
|
function hasConfiguredOtiumJoin() {
|
|
41302
41826
|
const envJoin = Boolean(process.env.OTIUM_CENTRAL_URL?.trim() && process.env.OTIUM_CELL_ID?.trim() && process.env.OTIUM_CELL_SECRET?.trim());
|
|
41303
|
-
return envJoin ||
|
|
41827
|
+
return envJoin || existsSync37(resolve24(DATA_DIR, "otium-join.json"));
|
|
41304
41828
|
}
|
|
41305
41829
|
var init_join_status = __esm(() => {
|
|
41306
41830
|
init_config_public();
|
|
@@ -41528,8 +42052,7 @@ var init_canonical_mcp_bridge = __esm(async () => {
|
|
|
41528
42052
|
"wiki_read",
|
|
41529
42053
|
"wiki_topic_brief",
|
|
41530
42054
|
"wiki_last_conversation",
|
|
41531
|
-
"
|
|
41532
|
-
"save_topic_brief",
|
|
42055
|
+
"wiki_write",
|
|
41533
42056
|
"index_upsert"
|
|
41534
42057
|
])
|
|
41535
42058
|
};
|
|
@@ -43989,16 +44512,16 @@ import {
|
|
|
43989
44512
|
randomUUID as randomUUID31
|
|
43990
44513
|
} from "crypto";
|
|
43991
44514
|
import {
|
|
43992
|
-
chmodSync as
|
|
44515
|
+
chmodSync as chmodSync8,
|
|
43993
44516
|
closeSync as closeSync6,
|
|
43994
|
-
existsSync as
|
|
44517
|
+
existsSync as existsSync38,
|
|
43995
44518
|
fsyncSync as fsyncSync3,
|
|
43996
44519
|
linkSync as linkSync2,
|
|
43997
44520
|
mkdirSync as mkdirSync34,
|
|
43998
44521
|
openSync as openSync6,
|
|
43999
|
-
readFileSync as
|
|
44522
|
+
readFileSync as readFileSync29,
|
|
44000
44523
|
renameSync as renameSync17,
|
|
44001
|
-
unlinkSync as
|
|
44524
|
+
unlinkSync as unlinkSync24,
|
|
44002
44525
|
writeFileSync as writeFileSync24
|
|
44003
44526
|
} from "fs";
|
|
44004
44527
|
import { dirname as dirname22, resolve as resolve25 } from "path";
|
|
@@ -44026,10 +44549,10 @@ function pendingEnrollmentPath() {
|
|
|
44026
44549
|
}
|
|
44027
44550
|
function isEnrollmentPending(invite) {
|
|
44028
44551
|
const path = pendingEnrollmentPath();
|
|
44029
|
-
if (!
|
|
44552
|
+
if (!existsSync38(path))
|
|
44030
44553
|
return false;
|
|
44031
44554
|
try {
|
|
44032
|
-
const saved = JSON.parse(
|
|
44555
|
+
const saved = JSON.parse(readFileSync29(path, "utf8"));
|
|
44033
44556
|
return saved.central === invite.central && saved.token === invite.token;
|
|
44034
44557
|
} catch {
|
|
44035
44558
|
return false;
|
|
@@ -44037,8 +44560,8 @@ function isEnrollmentPending(invite) {
|
|
|
44037
44560
|
}
|
|
44038
44561
|
function loadOrCreatePending(invite, nodeName) {
|
|
44039
44562
|
const path = pendingEnrollmentPath();
|
|
44040
|
-
if (
|
|
44041
|
-
const saved = JSON.parse(
|
|
44563
|
+
if (existsSync38(path)) {
|
|
44564
|
+
const saved = JSON.parse(readFileSync29(path, "utf8"));
|
|
44042
44565
|
if (saved.central === invite.central && saved.token === invite.token)
|
|
44043
44566
|
return saved;
|
|
44044
44567
|
throw new Error(`another Otium enrollment is pending at ${path}`);
|
|
@@ -44062,8 +44585,8 @@ function loadOrCreatePending(invite, nodeName) {
|
|
|
44062
44585
|
closeSync6(fd);
|
|
44063
44586
|
fd = undefined;
|
|
44064
44587
|
linkSync2(temporaryPath, path);
|
|
44065
|
-
|
|
44066
|
-
|
|
44588
|
+
unlinkSync24(temporaryPath);
|
|
44589
|
+
chmodSync8(path, 384);
|
|
44067
44590
|
const directoryFd = openSync6(dirname22(path), "r");
|
|
44068
44591
|
try {
|
|
44069
44592
|
fsyncSync3(directoryFd);
|
|
@@ -44073,10 +44596,10 @@ function loadOrCreatePending(invite, nodeName) {
|
|
|
44073
44596
|
} catch (error2) {
|
|
44074
44597
|
if (fd !== undefined)
|
|
44075
44598
|
closeSync6(fd);
|
|
44076
|
-
if (
|
|
44077
|
-
|
|
44078
|
-
if (error2.code === "EEXIST" &&
|
|
44079
|
-
const saved = JSON.parse(
|
|
44599
|
+
if (existsSync38(temporaryPath))
|
|
44600
|
+
unlinkSync24(temporaryPath);
|
|
44601
|
+
if (error2.code === "EEXIST" && existsSync38(path)) {
|
|
44602
|
+
const saved = JSON.parse(readFileSync29(path, "utf8"));
|
|
44080
44603
|
if (saved.central === invite.central && saved.token === invite.token)
|
|
44081
44604
|
return saved;
|
|
44082
44605
|
}
|
|
@@ -44106,14 +44629,14 @@ function replacePendingEnrollment(pending2) {
|
|
|
44106
44629
|
} catch (error2) {
|
|
44107
44630
|
if (fd !== undefined)
|
|
44108
44631
|
closeSync6(fd);
|
|
44109
|
-
if (
|
|
44110
|
-
|
|
44632
|
+
if (existsSync38(temporaryPath))
|
|
44633
|
+
unlinkSync24(temporaryPath);
|
|
44111
44634
|
throw error2;
|
|
44112
44635
|
}
|
|
44113
44636
|
}
|
|
44114
44637
|
function recordClaimedCredential(pending2, join43) {
|
|
44115
44638
|
withJoinCredentialLock(() => {
|
|
44116
|
-
const current3 = JSON.parse(
|
|
44639
|
+
const current3 = JSON.parse(readFileSync29(pendingEnrollmentPath(), "utf8"));
|
|
44117
44640
|
if (current3.central !== pending2.central || current3.token !== pending2.token || current3.idempotencyKey !== pending2.idempotencyKey || current3.publicKey !== pending2.publicKey) {
|
|
44118
44641
|
throw new Error("pending Otium enrollment changed while its claim was in flight");
|
|
44119
44642
|
}
|
|
@@ -44192,7 +44715,7 @@ async function claimEnrollment(invite, nodeName) {
|
|
|
44192
44715
|
function commitEnrollment(join43, options = {}) {
|
|
44193
44716
|
return withJoinCredentialLock(() => {
|
|
44194
44717
|
const pendingPath = pendingEnrollmentPath();
|
|
44195
|
-
const pending2 =
|
|
44718
|
+
const pending2 = existsSync38(pendingPath) ? JSON.parse(readFileSync29(pendingPath, "utf8")) : null;
|
|
44196
44719
|
const digest = joinCredentialDigest(join43);
|
|
44197
44720
|
if (pending2 && (!pending2.claimed || pending2.claimed.digest !== digest || pending2.claimed.cellId !== join43.cellId)) {
|
|
44198
44721
|
throw new Error(`pending Otium enrollment at ${pendingPath} does not match these credentials`);
|
|
@@ -44203,7 +44726,7 @@ function commitEnrollment(join43, options = {}) {
|
|
|
44203
44726
|
}
|
|
44204
44727
|
if (!pending2)
|
|
44205
44728
|
return path;
|
|
44206
|
-
|
|
44729
|
+
unlinkSync24(pendingPath);
|
|
44207
44730
|
const directoryFd = openSync6(dirname22(pendingPath), "r");
|
|
44208
44731
|
try {
|
|
44209
44732
|
fsyncSync3(directoryFd);
|
|
@@ -46392,4 +46915,4 @@ switch (command) {
|
|
|
46392
46915
|
}
|
|
46393
46916
|
}
|
|
46394
46917
|
|
|
46395
|
-
//# debugId=
|
|
46918
|
+
//# debugId=1F2F931DB2BD421464756E2164756E21
|