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/mcp-factories.js
CHANGED
|
@@ -29,6 +29,59 @@ var init_types = __esm(() => {
|
|
|
29
29
|
MAESTRO_EFFORT_VALUES = ["low", "medium", "high", "xhigh", "max"];
|
|
30
30
|
});
|
|
31
31
|
|
|
32
|
+
// ../../packages/core/src/storage/sqlite.ts
|
|
33
|
+
var isBun, Database;
|
|
34
|
+
var init_sqlite = __esm(async () => {
|
|
35
|
+
isBun = typeof process.versions.bun === "string";
|
|
36
|
+
if (isBun) {
|
|
37
|
+
({ Database } = await import("bun:sqlite"));
|
|
38
|
+
} else {
|
|
39
|
+
const nodeSqliteSpecifier = ["node", "sqlite"].join(":");
|
|
40
|
+
const { DatabaseSync } = await import(nodeSqliteSpecifier);
|
|
41
|
+
|
|
42
|
+
class NodeDatabase {
|
|
43
|
+
#db;
|
|
44
|
+
constructor(path, options = {}) {
|
|
45
|
+
this.#db = options.readonly ? new DatabaseSync(path, { readOnly: true }) : new DatabaseSync(path);
|
|
46
|
+
}
|
|
47
|
+
query(sql) {
|
|
48
|
+
return this.#db.prepare(sql);
|
|
49
|
+
}
|
|
50
|
+
prepare(sql) {
|
|
51
|
+
return this.#db.prepare(sql);
|
|
52
|
+
}
|
|
53
|
+
exec(sql) {
|
|
54
|
+
this.#db.exec(sql);
|
|
55
|
+
}
|
|
56
|
+
run(sql, ...params) {
|
|
57
|
+
return this.#db.prepare(sql).run(...params);
|
|
58
|
+
}
|
|
59
|
+
transaction(fn) {
|
|
60
|
+
const run = (begin) => (...args) => {
|
|
61
|
+
this.#db.exec(begin);
|
|
62
|
+
try {
|
|
63
|
+
const result = fn(...args);
|
|
64
|
+
this.#db.exec("COMMIT");
|
|
65
|
+
return result;
|
|
66
|
+
} catch (err) {
|
|
67
|
+
this.#db.exec("ROLLBACK");
|
|
68
|
+
throw err;
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
const tx = run("BEGIN");
|
|
72
|
+
tx.deferred = run("BEGIN DEFERRED");
|
|
73
|
+
tx.immediate = run("BEGIN IMMEDIATE");
|
|
74
|
+
tx.exclusive = run("BEGIN EXCLUSIVE");
|
|
75
|
+
return tx;
|
|
76
|
+
}
|
|
77
|
+
close() {
|
|
78
|
+
this.#db.close();
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
Database = NodeDatabase;
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
|
|
32
85
|
// ../../packages/core/src/platform/config-helpers.ts
|
|
33
86
|
function readEnvText(env, key) {
|
|
34
87
|
const value2 = env[key]?.trim();
|
|
@@ -72,11 +125,11 @@ import { execFileSync } from "child_process";
|
|
|
72
125
|
import { randomBytes } from "crypto";
|
|
73
126
|
import {
|
|
74
127
|
accessSync,
|
|
75
|
-
chmodSync,
|
|
128
|
+
chmodSync as chmodSync2,
|
|
76
129
|
constants,
|
|
77
|
-
existsSync,
|
|
130
|
+
existsSync as existsSync2,
|
|
78
131
|
mkdirSync,
|
|
79
|
-
readFileSync,
|
|
132
|
+
readFileSync as readFileSync2,
|
|
80
133
|
writeFileSync
|
|
81
134
|
} from "fs";
|
|
82
135
|
import { createRequire } from "module";
|
|
@@ -93,7 +146,7 @@ function resolveAgentEnv(envKey, fallback, legacyEnvKey) {
|
|
|
93
146
|
function resolveProjectRoot() {
|
|
94
147
|
const moduleDir = dirname(fileURLToPath(import.meta.url));
|
|
95
148
|
const packagedRuntime = resolve(moduleDir, "runtime");
|
|
96
|
-
if (
|
|
149
|
+
if (existsSync2(resolve(packagedRuntime, "src")))
|
|
97
150
|
return packagedRuntime;
|
|
98
151
|
return resolve(moduleDir, "../..");
|
|
99
152
|
}
|
|
@@ -101,7 +154,7 @@ function resolveDependencyBin(name) {
|
|
|
101
154
|
let dir = PROJECT_ROOT;
|
|
102
155
|
while (true) {
|
|
103
156
|
const candidate = resolve(dir, "node_modules", ".bin", name);
|
|
104
|
-
if (
|
|
157
|
+
if (existsSync2(candidate))
|
|
105
158
|
return candidate;
|
|
106
159
|
const parent = dirname(dir);
|
|
107
160
|
if (parent === dir)
|
|
@@ -215,14 +268,14 @@ function loadOrCreateLocalSecret(envKey, filename, options = {}) {
|
|
|
215
268
|
if (options.persistEnvValue) {
|
|
216
269
|
writeFileSync(secretFile, `${envValue}
|
|
217
270
|
`, { mode: 384 });
|
|
218
|
-
|
|
271
|
+
chmodSync2(secretFile, 384);
|
|
219
272
|
}
|
|
220
273
|
return envValue;
|
|
221
274
|
}
|
|
222
|
-
if (
|
|
223
|
-
const stored =
|
|
275
|
+
if (existsSync2(secretFile)) {
|
|
276
|
+
const stored = readFileSync2(secretFile, "utf-8").trim();
|
|
224
277
|
if (stored) {
|
|
225
|
-
|
|
278
|
+
chmodSync2(secretFile, 384);
|
|
226
279
|
return stored;
|
|
227
280
|
}
|
|
228
281
|
}
|
|
@@ -234,10 +287,10 @@ function loadOrCreateLocalSecret(envKey, filename, options = {}) {
|
|
|
234
287
|
} catch (error) {
|
|
235
288
|
if (error.code !== "EEXIST")
|
|
236
289
|
throw error;
|
|
237
|
-
const stored =
|
|
290
|
+
const stored = readFileSync2(secretFile, "utf-8").trim();
|
|
238
291
|
if (!stored)
|
|
239
292
|
throw new Error(`Secret file exists but is empty: ${secretFile}`);
|
|
240
|
-
|
|
293
|
+
chmodSync2(secretFile, 384);
|
|
241
294
|
return stored;
|
|
242
295
|
}
|
|
243
296
|
}
|
|
@@ -569,7 +622,7 @@ var init_shared = __esm(() => {
|
|
|
569
622
|
});
|
|
570
623
|
|
|
571
624
|
// ../../packages/core/src/platform/file-utils.ts
|
|
572
|
-
import { unlinkSync as
|
|
625
|
+
import { unlinkSync as unlinkSync3 } from "fs";
|
|
573
626
|
function createSafeUnlink(host) {
|
|
574
627
|
return (path, warnLabel) => {
|
|
575
628
|
try {
|
|
@@ -589,7 +642,7 @@ var defaultSafeUnlink;
|
|
|
589
642
|
var init_file_utils = __esm(() => {
|
|
590
643
|
init_logger();
|
|
591
644
|
defaultSafeUnlink = createSafeUnlink({
|
|
592
|
-
unlink:
|
|
645
|
+
unlink: unlinkSync3,
|
|
593
646
|
warn: (context, message) => logger.warn(context, message)
|
|
594
647
|
});
|
|
595
648
|
});
|
|
@@ -601,15 +654,15 @@ import {
|
|
|
601
654
|
fsyncSync,
|
|
602
655
|
mkdirSync as mkdirSync4,
|
|
603
656
|
openSync as openSync2,
|
|
604
|
-
readFileSync as
|
|
657
|
+
readFileSync as readFileSync4,
|
|
605
658
|
renameSync as renameSync2,
|
|
606
659
|
statSync as statSync2,
|
|
607
|
-
unlinkSync as
|
|
660
|
+
unlinkSync as unlinkSync4,
|
|
608
661
|
writeFileSync as writeFileSync3
|
|
609
662
|
} from "fs";
|
|
610
663
|
import { dirname as dirname3 } from "path";
|
|
611
664
|
function readJsonlLines(filePath) {
|
|
612
|
-
return
|
|
665
|
+
return readFileSync4(filePath, "utf-8").trim().split(`
|
|
613
666
|
`).filter(Boolean);
|
|
614
667
|
}
|
|
615
668
|
function parseJsonlText(raw) {
|
|
@@ -618,7 +671,7 @@ function parseJsonlText(raw) {
|
|
|
618
671
|
}
|
|
619
672
|
function readJsonFile(filePath) {
|
|
620
673
|
try {
|
|
621
|
-
return JSON.parse(
|
|
674
|
+
return JSON.parse(readFileSync4(filePath, "utf-8"));
|
|
622
675
|
} catch {
|
|
623
676
|
return null;
|
|
624
677
|
}
|
|
@@ -708,7 +761,7 @@ function writeJsonlFile(filePath, entries) {
|
|
|
708
761
|
} catch {}
|
|
709
762
|
}
|
|
710
763
|
try {
|
|
711
|
-
|
|
764
|
+
unlinkSync4(tmpPath);
|
|
712
765
|
} catch {}
|
|
713
766
|
throw err;
|
|
714
767
|
}
|
|
@@ -744,13 +797,13 @@ var init_jsonl = __esm(() => {
|
|
|
744
797
|
|
|
745
798
|
// ../../packages/core/src/agents/rollout/claude.ts
|
|
746
799
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
747
|
-
import { existsSync as
|
|
800
|
+
import { existsSync as existsSync4, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
|
|
748
801
|
import { homedir as homedir2 } from "os";
|
|
749
802
|
import { join as join3 } from "path";
|
|
750
803
|
function loadClaudeAttachments() {
|
|
751
804
|
if (_attachmentsCache)
|
|
752
805
|
return _attachmentsCache;
|
|
753
|
-
const raw =
|
|
806
|
+
const raw = readFileSync5(join3(FIXTURES_DIR, "claude-attachments.jsonl"), "utf8");
|
|
754
807
|
const lines = parseJsonlText(raw);
|
|
755
808
|
if (lines.length < 2) {
|
|
756
809
|
throw new Error(`loadClaudeAttachments: expected >=2 entries in claude-attachments.jsonl, got ${lines.length}`);
|
|
@@ -865,7 +918,7 @@ var init_claude = __esm(() => {
|
|
|
865
918
|
});
|
|
866
919
|
|
|
867
920
|
// ../../packages/core/src/agents/claude-registry.ts
|
|
868
|
-
import { existsSync as
|
|
921
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync5, readdirSync as readdirSync2, renameSync as renameSync3, unlinkSync as unlinkSync5 } from "fs";
|
|
869
922
|
import { homedir as homedir3 } from "os";
|
|
870
923
|
import { join as join4 } from "path";
|
|
871
924
|
var ALIAS_MAP, VALID_ALIASES, VALID_EFFORTS, claudeRegistry, claudeRegistryOperations;
|
|
@@ -917,8 +970,8 @@ var init_claude_registry = __esm(() => {
|
|
|
917
970
|
const projectsRoot = join4(homedir3(), ".claude", "projects");
|
|
918
971
|
const destDir = join4(projectsRoot, encodeClaudeCwd(cwd));
|
|
919
972
|
const destPath = join4(destDir, `${result.sessionId}.jsonl`);
|
|
920
|
-
if (!
|
|
921
|
-
const sourcePath = readdirSync2(projectsRoot).map((d) => join4(projectsRoot, d, `${result.sessionId}.jsonl`)).find((p) =>
|
|
973
|
+
if (!existsSync5(destPath)) {
|
|
974
|
+
const sourcePath = readdirSync2(projectsRoot).map((d) => join4(projectsRoot, d, `${result.sessionId}.jsonl`)).find((p) => existsSync5(p));
|
|
922
975
|
if (!sourcePath) {
|
|
923
976
|
throw new Error(`claude forkSession: fork rollout ${result.sessionId}.jsonl not found under ${projectsRoot}`);
|
|
924
977
|
}
|
|
@@ -936,7 +989,7 @@ var init_claude_registry = __esm(() => {
|
|
|
936
989
|
for (const sid of sessionIds) {
|
|
937
990
|
const path = join4(projectsDir, `${sid}.jsonl`);
|
|
938
991
|
try {
|
|
939
|
-
|
|
992
|
+
unlinkSync5(path);
|
|
940
993
|
} catch (e) {
|
|
941
994
|
if (e?.code !== "ENOENT") {
|
|
942
995
|
logger.warn({ err: e, path }, "claude cleanupRollouts: unlink failed");
|
|
@@ -952,27 +1005,27 @@ var init_claude_registry = __esm(() => {
|
|
|
952
1005
|
});
|
|
953
1006
|
|
|
954
1007
|
// ../../packages/core/src/version.ts
|
|
955
|
-
var NEGOTIUM_VERSION = "0.2.
|
|
1008
|
+
var NEGOTIUM_VERSION = "0.2.19";
|
|
956
1009
|
|
|
957
1010
|
// ../../packages/core/src/agents/codex-native-multi-agent.ts
|
|
958
1011
|
import { spawn as spawn2 } from "child_process";
|
|
959
1012
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
960
1013
|
import {
|
|
961
|
-
chmodSync as
|
|
1014
|
+
chmodSync as chmodSync3,
|
|
962
1015
|
copyFileSync,
|
|
963
|
-
existsSync as
|
|
1016
|
+
existsSync as existsSync6,
|
|
964
1017
|
mkdtempSync,
|
|
965
|
-
readFileSync as
|
|
1018
|
+
readFileSync as readFileSync6,
|
|
966
1019
|
renameSync as renameSync4,
|
|
967
1020
|
rmSync,
|
|
968
|
-
unlinkSync as
|
|
1021
|
+
unlinkSync as unlinkSync6,
|
|
969
1022
|
writeFileSync as writeFileSync5
|
|
970
1023
|
} from "fs";
|
|
971
1024
|
import { createRequire as createRequire2 } from "module";
|
|
972
1025
|
import { tmpdir } from "os";
|
|
973
1026
|
import { dirname as dirname4, join as join5 } from "path";
|
|
974
1027
|
function readPackageVersion(packageJsonPath) {
|
|
975
|
-
const parsed = JSON.parse(
|
|
1028
|
+
const parsed = JSON.parse(readFileSync6(packageJsonPath, "utf8"));
|
|
976
1029
|
if (typeof parsed.version !== "string" || !parsed.version.trim()) {
|
|
977
1030
|
throw new Error(`Codex package has no valid version: ${packageJsonPath}`);
|
|
978
1031
|
}
|
|
@@ -994,7 +1047,7 @@ function parseCodexModelCache(contents, sourcePath) {
|
|
|
994
1047
|
return parsed;
|
|
995
1048
|
}
|
|
996
1049
|
function readCodexModelCache(cachePath) {
|
|
997
|
-
const contents =
|
|
1050
|
+
const contents = readFileSync6(cachePath, "utf8");
|
|
998
1051
|
return { contents, parsed: parseCodexModelCache(contents, cachePath) };
|
|
999
1052
|
}
|
|
1000
1053
|
function readCompatibleCodexModelCache(cachePath) {
|
|
@@ -1006,16 +1059,16 @@ function readCompatibleCodexModelCache(cachePath) {
|
|
|
1006
1059
|
return cache;
|
|
1007
1060
|
}
|
|
1008
1061
|
function writePrivateFileAtomic(path, contents) {
|
|
1009
|
-
if (
|
|
1062
|
+
if (existsSync6(path) && readFileSync6(path, "utf8") === contents)
|
|
1010
1063
|
return;
|
|
1011
1064
|
const tempPath = `${path}.${process.pid}.${randomUUID3()}.tmp`;
|
|
1012
1065
|
try {
|
|
1013
1066
|
writeFileSync5(tempPath, contents, { encoding: "utf8", mode: 384 });
|
|
1014
1067
|
renameSync4(tempPath, path);
|
|
1015
|
-
|
|
1068
|
+
chmodSync3(path, 384);
|
|
1016
1069
|
} finally {
|
|
1017
1070
|
try {
|
|
1018
|
-
|
|
1071
|
+
unlinkSync6(tempPath);
|
|
1019
1072
|
} catch {}
|
|
1020
1073
|
}
|
|
1021
1074
|
}
|
|
@@ -1043,7 +1096,7 @@ async function bootstrapCodexModelCache(codexHome, cachePath) {
|
|
|
1043
1096
|
} catch {}
|
|
1044
1097
|
if (error)
|
|
1045
1098
|
reject(error);
|
|
1046
|
-
else if (!
|
|
1099
|
+
else if (!existsSync6(cachePath))
|
|
1047
1100
|
reject(new Error("Codex did not create its model cache"));
|
|
1048
1101
|
else
|
|
1049
1102
|
resolve4();
|
|
@@ -1111,12 +1164,12 @@ async function bootstrapIsolatedCodexModelCache(authFilePath, bootstrap) {
|
|
|
1111
1164
|
try {
|
|
1112
1165
|
const isolatedAuthPath = join5(isolatedHome, "auth.json");
|
|
1113
1166
|
copyFileSync(authFilePath, isolatedAuthPath);
|
|
1114
|
-
|
|
1167
|
+
chmodSync3(isolatedAuthPath, 384);
|
|
1115
1168
|
const sourceConfigPath = join5(sourceHome, "config.toml");
|
|
1116
|
-
if (
|
|
1169
|
+
if (existsSync6(sourceConfigPath)) {
|
|
1117
1170
|
const isolatedConfigPath = join5(isolatedHome, "config.toml");
|
|
1118
1171
|
copyFileSync(sourceConfigPath, isolatedConfigPath);
|
|
1119
|
-
|
|
1172
|
+
chmodSync3(isolatedConfigPath, 384);
|
|
1120
1173
|
}
|
|
1121
1174
|
await bootstrap(isolatedHome, isolatedCachePath);
|
|
1122
1175
|
return readCompatibleCodexModelCache(isolatedCachePath).contents;
|
|
@@ -1128,7 +1181,7 @@ async function ensureCodexModelCache(authFilePath, bootstrap = bootstrapCodexMod
|
|
|
1128
1181
|
const codexHome = dirname4(authFilePath);
|
|
1129
1182
|
const configuredCachePath = process.env.NEGOTIUM_CODEX_MODELS_CACHE_FILE;
|
|
1130
1183
|
if (configuredCachePath) {
|
|
1131
|
-
if (!
|
|
1184
|
+
if (!existsSync6(configuredCachePath)) {
|
|
1132
1185
|
throw new Error(`Configured Codex model cache does not exist: ${configuredCachePath}`);
|
|
1133
1186
|
}
|
|
1134
1187
|
readCompatibleCodexModelCache(configuredCachePath);
|
|
@@ -1136,14 +1189,14 @@ async function ensureCodexModelCache(authFilePath, bootstrap = bootstrapCodexMod
|
|
|
1136
1189
|
}
|
|
1137
1190
|
const bundledCachePath = bundledCodexModelCachePath(authFilePath);
|
|
1138
1191
|
const sharedCachePath = join5(codexHome, "models_cache.json");
|
|
1139
|
-
if (
|
|
1192
|
+
if (existsSync6(sharedCachePath)) {
|
|
1140
1193
|
try {
|
|
1141
1194
|
const shared = readCompatibleCodexModelCache(sharedCachePath);
|
|
1142
1195
|
writePrivateFileAtomic(bundledCachePath, shared.contents);
|
|
1143
1196
|
return bundledCachePath;
|
|
1144
1197
|
} catch {}
|
|
1145
1198
|
}
|
|
1146
|
-
if (
|
|
1199
|
+
if (existsSync6(bundledCachePath)) {
|
|
1147
1200
|
try {
|
|
1148
1201
|
readCompatibleCodexModelCache(bundledCachePath);
|
|
1149
1202
|
return bundledCachePath;
|
|
@@ -2188,59 +2241,6 @@ var init_mcp_config = __esm(() => {
|
|
|
2188
2241
|
nodeMcpEntries = [];
|
|
2189
2242
|
});
|
|
2190
2243
|
|
|
2191
|
-
// ../../packages/core/src/storage/sqlite.ts
|
|
2192
|
-
var isBun, Database;
|
|
2193
|
-
var init_sqlite = __esm(async () => {
|
|
2194
|
-
isBun = typeof process.versions.bun === "string";
|
|
2195
|
-
if (isBun) {
|
|
2196
|
-
({ Database } = await import("bun:sqlite"));
|
|
2197
|
-
} else {
|
|
2198
|
-
const nodeSqliteSpecifier = ["node", "sqlite"].join(":");
|
|
2199
|
-
const { DatabaseSync } = await import(nodeSqliteSpecifier);
|
|
2200
|
-
|
|
2201
|
-
class NodeDatabase {
|
|
2202
|
-
#db;
|
|
2203
|
-
constructor(path, options = {}) {
|
|
2204
|
-
this.#db = options.readonly ? new DatabaseSync(path, { readOnly: true }) : new DatabaseSync(path);
|
|
2205
|
-
}
|
|
2206
|
-
query(sql) {
|
|
2207
|
-
return this.#db.prepare(sql);
|
|
2208
|
-
}
|
|
2209
|
-
prepare(sql) {
|
|
2210
|
-
return this.#db.prepare(sql);
|
|
2211
|
-
}
|
|
2212
|
-
exec(sql) {
|
|
2213
|
-
this.#db.exec(sql);
|
|
2214
|
-
}
|
|
2215
|
-
run(sql, ...params) {
|
|
2216
|
-
return this.#db.prepare(sql).run(...params);
|
|
2217
|
-
}
|
|
2218
|
-
transaction(fn) {
|
|
2219
|
-
const run = (begin) => (...args) => {
|
|
2220
|
-
this.#db.exec(begin);
|
|
2221
|
-
try {
|
|
2222
|
-
const result = fn(...args);
|
|
2223
|
-
this.#db.exec("COMMIT");
|
|
2224
|
-
return result;
|
|
2225
|
-
} catch (err) {
|
|
2226
|
-
this.#db.exec("ROLLBACK");
|
|
2227
|
-
throw err;
|
|
2228
|
-
}
|
|
2229
|
-
};
|
|
2230
|
-
const tx = run("BEGIN");
|
|
2231
|
-
tx.deferred = run("BEGIN DEFERRED");
|
|
2232
|
-
tx.immediate = run("BEGIN IMMEDIATE");
|
|
2233
|
-
tx.exclusive = run("BEGIN EXCLUSIVE");
|
|
2234
|
-
return tx;
|
|
2235
|
-
}
|
|
2236
|
-
close() {
|
|
2237
|
-
this.#db.close();
|
|
2238
|
-
}
|
|
2239
|
-
}
|
|
2240
|
-
Database = NodeDatabase;
|
|
2241
|
-
}
|
|
2242
|
-
});
|
|
2243
|
-
|
|
2244
2244
|
// ../../packages/core/src/storage/vault-crypto-core.ts
|
|
2245
2245
|
import { createCipheriv, createDecipheriv, createHash as createHash2, randomBytes as randomBytes3 } from "crypto";
|
|
2246
2246
|
function encryptionKey(masterKey) {
|
|
@@ -2297,7 +2297,7 @@ var init_vault_crypto = __esm(() => {
|
|
|
2297
2297
|
});
|
|
2298
2298
|
|
|
2299
2299
|
// ../../packages/core/src/storage/vault.ts
|
|
2300
|
-
import { chmodSync as
|
|
2300
|
+
import { chmodSync as chmodSync4, mkdirSync as mkdirSync6 } from "fs";
|
|
2301
2301
|
import { join as join6 } from "path";
|
|
2302
2302
|
function initializeVaultDatabase(database) {
|
|
2303
2303
|
database.exec("PRAGMA journal_mode = WAL");
|
|
@@ -2337,7 +2337,7 @@ function openVaultDatabase(dataDir) {
|
|
|
2337
2337
|
const path = join6(vaultDir, "vault.db");
|
|
2338
2338
|
mkdirSync6(vaultDir, { recursive: true, mode: 448 });
|
|
2339
2339
|
const database = new Database(path, { create: true });
|
|
2340
|
-
|
|
2340
|
+
chmodSync4(path, 384);
|
|
2341
2341
|
initializeVaultDatabase(database);
|
|
2342
2342
|
return database;
|
|
2343
2343
|
}
|
|
@@ -2498,7 +2498,7 @@ var init_execution_host = __esm(async () => {
|
|
|
2498
2498
|
|
|
2499
2499
|
// ../../packages/core/src/agents/rollout/codex.ts
|
|
2500
2500
|
import { randomBytes as randomBytes4 } from "crypto";
|
|
2501
|
-
import { existsSync as
|
|
2501
|
+
import { existsSync as existsSync7, readFileSync as readFileSync7, realpathSync as realpathSync2, statSync as statSync3, unlinkSync as unlinkSync7 } from "fs";
|
|
2502
2502
|
import { basename as basename2, dirname as dirname6, join as join7, resolve as resolve5 } from "path";
|
|
2503
2503
|
function codexSessionsDir() {
|
|
2504
2504
|
return join7(hostedCodexHomePath(), "sessions");
|
|
@@ -2506,7 +2506,7 @@ function codexSessionsDir() {
|
|
|
2506
2506
|
function loadCodexShell() {
|
|
2507
2507
|
if (_shellCache)
|
|
2508
2508
|
return _shellCache;
|
|
2509
|
-
const raw =
|
|
2509
|
+
const raw = readFileSync7(join7(FIXTURES_DIR, "codex-shell.jsonl"), "utf8");
|
|
2510
2510
|
const lines = parseJsonlText(raw);
|
|
2511
2511
|
if (lines.length < 5) {
|
|
2512
2512
|
throw new Error(`loadCodexShell: expected >=5 entries in codex-shell.jsonl, got ${lines.length}`);
|
|
@@ -2692,7 +2692,7 @@ function readCodexPatchCallIds(threadId) {
|
|
|
2692
2692
|
if (!path)
|
|
2693
2693
|
return [];
|
|
2694
2694
|
try {
|
|
2695
|
-
return extractCodexPatchCallIds(
|
|
2695
|
+
return extractCodexPatchCallIds(readFileSync7(path, "utf8"));
|
|
2696
2696
|
} catch (error) {
|
|
2697
2697
|
logger.debug({ error, threadId }, "codex patch ids: rollout read failed");
|
|
2698
2698
|
return [];
|
|
@@ -2703,7 +2703,7 @@ function readLatestCodexPatchPreview(threadId, expectedPaths, consumedCallIds =
|
|
|
2703
2703
|
if (!path)
|
|
2704
2704
|
return;
|
|
2705
2705
|
try {
|
|
2706
|
-
return extractLatestCodexPatchPreview(
|
|
2706
|
+
return extractLatestCodexPatchPreview(readFileSync7(path, "utf8"), expectedPaths, consumedCallIds, expectedCallId);
|
|
2707
2707
|
} catch (error) {
|
|
2708
2708
|
logger.debug({ error, threadId }, "codex patch preview: rollout read failed");
|
|
2709
2709
|
return;
|
|
@@ -2761,7 +2761,7 @@ function readLatestCodexContextUsage(threadId) {
|
|
|
2761
2761
|
if (!path)
|
|
2762
2762
|
return;
|
|
2763
2763
|
try {
|
|
2764
|
-
return extractLatestCodexContextUsage(
|
|
2764
|
+
return extractLatestCodexContextUsage(readFileSync7(path, "utf8"));
|
|
2765
2765
|
} catch (error) {
|
|
2766
2766
|
logger.debug({ error, threadId }, "codex context usage: rollout read failed");
|
|
2767
2767
|
return;
|
|
@@ -2772,7 +2772,7 @@ function readLatestCodexTokenTotals(threadId) {
|
|
|
2772
2772
|
if (!path)
|
|
2773
2773
|
return;
|
|
2774
2774
|
try {
|
|
2775
|
-
return extractLatestCodexTokenTotals(
|
|
2775
|
+
return extractLatestCodexTokenTotals(readFileSync7(path, "utf8"));
|
|
2776
2776
|
} catch (error) {
|
|
2777
2777
|
logger.debug({ error, threadId }, "codex token totals: rollout read failed");
|
|
2778
2778
|
return;
|
|
@@ -2783,7 +2783,7 @@ function migrateCodexRolloutNativeMultiAgentMetadata(threadId) {
|
|
|
2783
2783
|
if (!path)
|
|
2784
2784
|
return false;
|
|
2785
2785
|
try {
|
|
2786
|
-
const entries = parseJsonlText(
|
|
2786
|
+
const entries = parseJsonlText(readFileSync7(path, "utf8"));
|
|
2787
2787
|
let changed = false;
|
|
2788
2788
|
for (const entry of entries) {
|
|
2789
2789
|
if (entry.type !== "session_meta" && entry.type !== "turn_context")
|
|
@@ -2813,7 +2813,7 @@ function latestCodexRolloutPath(threadId) {
|
|
|
2813
2813
|
if (buckets) {
|
|
2814
2814
|
for (const bucket of buckets) {
|
|
2815
2815
|
const dir = join7(sessionsDir, bucket);
|
|
2816
|
-
if (!
|
|
2816
|
+
if (!existsSync7(dir))
|
|
2817
2817
|
continue;
|
|
2818
2818
|
const glob = new Bun.Glob(`rollout-*-${threadId}.jsonl`);
|
|
2819
2819
|
for (const rel of glob.scanSync({ cwd: dir, onlyFiles: true })) {
|
|
@@ -2946,14 +2946,14 @@ function sweepPriorRolloutsForThread(threadId) {
|
|
|
2946
2946
|
}
|
|
2947
2947
|
for (const bucket of buckets) {
|
|
2948
2948
|
const dir = join7(sessionsDir, bucket);
|
|
2949
|
-
if (!
|
|
2949
|
+
if (!existsSync7(dir))
|
|
2950
2950
|
continue;
|
|
2951
2951
|
try {
|
|
2952
2952
|
const glob = new Bun.Glob(`rollout-*-${threadId}.jsonl`);
|
|
2953
2953
|
for (const rel of glob.scanSync({ cwd: dir, onlyFiles: true })) {
|
|
2954
2954
|
const fullPath = join7(dir, rel);
|
|
2955
2955
|
try {
|
|
2956
|
-
|
|
2956
|
+
unlinkSync7(fullPath);
|
|
2957
2957
|
} catch (e) {
|
|
2958
2958
|
if (e?.code !== "ENOENT") {
|
|
2959
2959
|
logger.warn({ err: e, path: fullPath }, "writeCodexRollout: prior-rollout unlink failed (continuing)");
|
|
@@ -2971,7 +2971,7 @@ function sweepPriorRolloutsFullTree(threadId, sessionsDir) {
|
|
|
2971
2971
|
for (const rel of glob.scanSync({ cwd: sessionsDir, onlyFiles: true })) {
|
|
2972
2972
|
const fullPath = join7(sessionsDir, rel);
|
|
2973
2973
|
try {
|
|
2974
|
-
|
|
2974
|
+
unlinkSync7(fullPath);
|
|
2975
2975
|
} catch (e) {
|
|
2976
2976
|
if (e?.code !== "ENOENT") {
|
|
2977
2977
|
logger.warn({ err: e, path: fullPath }, "writeCodexRollout: prior-rollout unlink failed (continuing)");
|
|
@@ -3148,7 +3148,7 @@ var init_codex_app_server = __esm(async () => {
|
|
|
3148
3148
|
});
|
|
3149
3149
|
|
|
3150
3150
|
// ../../packages/core/src/agents/codex-registry.ts
|
|
3151
|
-
import { existsSync as
|
|
3151
|
+
import { existsSync as existsSync8, unlinkSync as unlinkSync8 } from "fs";
|
|
3152
3152
|
import { join as join8 } from "path";
|
|
3153
3153
|
var VALID_EFFORTS2, codexRegistry, codexRegistryOperations;
|
|
3154
3154
|
var init_codex_registry = __esm(async () => {
|
|
@@ -3195,7 +3195,7 @@ var init_codex_registry = __esm(async () => {
|
|
|
3195
3195
|
if (sessionIds.length === 0)
|
|
3196
3196
|
return;
|
|
3197
3197
|
const sessionsDir = join8(hostedCodexHomePath(), "sessions");
|
|
3198
|
-
if (!
|
|
3198
|
+
if (!existsSync8(sessionsDir))
|
|
3199
3199
|
return;
|
|
3200
3200
|
const failures = [];
|
|
3201
3201
|
for (const tid of sessionIds) {
|
|
@@ -3204,7 +3204,7 @@ var init_codex_registry = __esm(async () => {
|
|
|
3204
3204
|
for await (const rel of glob.scan({ cwd: sessionsDir, onlyFiles: true })) {
|
|
3205
3205
|
const path = join8(sessionsDir, rel);
|
|
3206
3206
|
try {
|
|
3207
|
-
|
|
3207
|
+
unlinkSync8(path);
|
|
3208
3208
|
} catch (e) {
|
|
3209
3209
|
if (e?.code !== "ENOENT") {
|
|
3210
3210
|
logger.warn({ err: e, path }, "codex cleanupRollouts: unlink failed");
|
|
@@ -3226,7 +3226,7 @@ var init_codex_registry = __esm(async () => {
|
|
|
3226
3226
|
|
|
3227
3227
|
// ../../packages/core/src/agents/maestro-registry.ts
|
|
3228
3228
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
3229
|
-
import { existsSync as
|
|
3229
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync7, readFileSync as readFileSync8, writeFileSync as writeFileSync6 } from "fs";
|
|
3230
3230
|
import { homedir as homedir4 } from "os";
|
|
3231
3231
|
import { join as join9, resolve as resolve6 } from "path";
|
|
3232
3232
|
function maestroSessionsDir() {
|
|
@@ -3239,10 +3239,10 @@ function maestroActiveSessionPath(sessionId) {
|
|
|
3239
3239
|
return join9(maestroSessionsDir(), `${sessionId}.active.jsonl`);
|
|
3240
3240
|
}
|
|
3241
3241
|
function existingCreatedAt(path) {
|
|
3242
|
-
if (!
|
|
3242
|
+
if (!existsSync9(path))
|
|
3243
3243
|
return;
|
|
3244
3244
|
try {
|
|
3245
|
-
const firstLine =
|
|
3245
|
+
const firstLine = readFileSync8(path, "utf8").split(`
|
|
3246
3246
|
`, 1)[0];
|
|
3247
3247
|
const parsed = JSON.parse(firstLine);
|
|
3248
3248
|
return typeof parsed._meta?.createdAt === "string" ? parsed._meta.createdAt : undefined;
|
|
@@ -3323,7 +3323,7 @@ var init_maestro_registry = __esm(() => {
|
|
|
3323
3323
|
if (!parentMessages) {
|
|
3324
3324
|
throw new Error(`Maestro parent session not found: ${options.parentSessionId}`);
|
|
3325
3325
|
}
|
|
3326
|
-
const parentHasActiveProjection =
|
|
3326
|
+
const parentHasActiveProjection = existsSync9(maestroActiveSessionPath(options.parentSessionId));
|
|
3327
3327
|
const fork = forkSessionAt({
|
|
3328
3328
|
parentSessionId: options.parentSessionId,
|
|
3329
3329
|
messageIndex: parentMessages.length,
|
|
@@ -3338,7 +3338,7 @@ var init_maestro_registry = __esm(() => {
|
|
|
3338
3338
|
return {
|
|
3339
3339
|
forkId: fork.sessionId,
|
|
3340
3340
|
rolloutPath: fork.rolloutPath,
|
|
3341
|
-
...
|
|
3341
|
+
...existsSync9(activePath) ? { cleanupPaths: [activePath] } : {}
|
|
3342
3342
|
};
|
|
3343
3343
|
},
|
|
3344
3344
|
async cleanupRollouts(options) {
|
|
@@ -3350,7 +3350,7 @@ var init_maestro_registry = __esm(() => {
|
|
|
3350
3350
|
const remaining = [
|
|
3351
3351
|
maestroSessionPath(sessionId),
|
|
3352
3352
|
maestroActiveSessionPath(sessionId)
|
|
3353
|
-
].filter(
|
|
3353
|
+
].filter(existsSync9);
|
|
3354
3354
|
if (remaining.length > 0) {
|
|
3355
3355
|
throw new Error(`Maestro session files remain after cleanup: ${remaining.join(", ")}`);
|
|
3356
3356
|
}
|
|
@@ -5104,7 +5104,7 @@ var init_registry = __esm(async () => {
|
|
|
5104
5104
|
});
|
|
5105
5105
|
|
|
5106
5106
|
// ../../packages/core/src/agents/fork.ts
|
|
5107
|
-
import { existsSync as
|
|
5107
|
+
import { existsSync as existsSync11, unlinkSync as unlinkSync9 } from "fs";
|
|
5108
5108
|
function createAgentForkHelpers(host) {
|
|
5109
5109
|
return {
|
|
5110
5110
|
async forkAgentSession(options) {
|
|
@@ -5141,8 +5141,8 @@ var init_fork = __esm(async () => {
|
|
|
5141
5141
|
await init_registry();
|
|
5142
5142
|
defaultForkHelpers = createAgentForkHelpers({
|
|
5143
5143
|
forkSession: (agent, options) => getRegistryOperations(agent).forkSession(options),
|
|
5144
|
-
exists:
|
|
5145
|
-
unlink:
|
|
5144
|
+
exists: existsSync11,
|
|
5145
|
+
unlink: unlinkSync9,
|
|
5146
5146
|
warn: (details, message) => logger.warn(details, message)
|
|
5147
5147
|
});
|
|
5148
5148
|
});
|
|
@@ -5541,7 +5541,7 @@ var init_runtime_process_leases = __esm(async () => {
|
|
|
5541
5541
|
|
|
5542
5542
|
// ../../packages/core/src/platform/playwright/browser-processes.ts
|
|
5543
5543
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
5544
|
-
import { readdirSync as readdirSync4, unlinkSync as
|
|
5544
|
+
import { readdirSync as readdirSync4, unlinkSync as unlinkSync10 } from "fs";
|
|
5545
5545
|
import { createServer } from "net";
|
|
5546
5546
|
import { resolve as resolve8, sep } from "path";
|
|
5547
5547
|
function isPortInUse(port) {
|
|
@@ -5670,7 +5670,7 @@ function cleanSingletonFiles(userDataDir) {
|
|
|
5670
5670
|
for (const f of files) {
|
|
5671
5671
|
if (f.startsWith("Singleton")) {
|
|
5672
5672
|
try {
|
|
5673
|
-
|
|
5673
|
+
unlinkSync10(resolve8(userDataDir, f));
|
|
5674
5674
|
logger.info({ file: f, userDataDir }, "Removed stale Singleton file");
|
|
5675
5675
|
} catch (e) {
|
|
5676
5676
|
logger.warn({ err: e, file: f }, "Failed to remove stale Chrome Singleton file");
|
|
@@ -5811,7 +5811,7 @@ var init_vault_public = __esm(async () => {
|
|
|
5811
5811
|
|
|
5812
5812
|
// ../../packages/core/src/platform/playwright/vault-broker.ts
|
|
5813
5813
|
import { randomBytes as randomBytes5, timingSafeEqual as timingSafeEqual2 } from "crypto";
|
|
5814
|
-
import { chmodSync as
|
|
5814
|
+
import { chmodSync as chmodSync5 } from "fs";
|
|
5815
5815
|
import { createServer as createServer2 } from "net";
|
|
5816
5816
|
import { tmpdir as tmpdir2 } from "os";
|
|
5817
5817
|
import { join as join12 } from "path";
|
|
@@ -6007,7 +6007,7 @@ async function createBrowserVaultBroker(userId) {
|
|
|
6007
6007
|
server.once("error", reject);
|
|
6008
6008
|
server.listen(socketPath, resolveListen);
|
|
6009
6009
|
});
|
|
6010
|
-
|
|
6010
|
+
chmodSync5(socketPath, 384);
|
|
6011
6011
|
let closed = false;
|
|
6012
6012
|
return {
|
|
6013
6013
|
socketPath,
|
|
@@ -6115,11 +6115,11 @@ import { execFileSync as execFileSync4, spawn as spawn6 } from "child_process";
|
|
|
6115
6115
|
import { createHash as createHash3, randomBytes as randomBytes6, timingSafeEqual as timingSafeEqual3 } from "crypto";
|
|
6116
6116
|
import {
|
|
6117
6117
|
cpSync,
|
|
6118
|
-
existsSync as
|
|
6118
|
+
existsSync as existsSync12,
|
|
6119
6119
|
mkdirSync as mkdirSync9,
|
|
6120
|
-
readFileSync as
|
|
6120
|
+
readFileSync as readFileSync10,
|
|
6121
6121
|
rmSync as rmSync2,
|
|
6122
|
-
unlinkSync as
|
|
6122
|
+
unlinkSync as unlinkSync11,
|
|
6123
6123
|
writeFileSync as writeFileSync7
|
|
6124
6124
|
} from "fs";
|
|
6125
6125
|
import { dirname as dirname8, join as join13, resolve as resolve10 } from "path";
|
|
@@ -6129,7 +6129,7 @@ function removeDefaultProfileDataDir(userDataDir) {
|
|
|
6129
6129
|
if (dirname8(target) !== root) {
|
|
6130
6130
|
throw new Error(`Refusing to delete browser profile outside managed root: ${target}`);
|
|
6131
6131
|
}
|
|
6132
|
-
const existed =
|
|
6132
|
+
const existed = existsSync12(target);
|
|
6133
6133
|
rmSync2(target, { recursive: true, force: true });
|
|
6134
6134
|
return existed;
|
|
6135
6135
|
}
|
|
@@ -6219,7 +6219,7 @@ function writePortFile(instanceKey, port) {
|
|
|
6219
6219
|
}
|
|
6220
6220
|
function deletePortFile(instanceKey) {
|
|
6221
6221
|
try {
|
|
6222
|
-
|
|
6222
|
+
unlinkSync11(join13(managerHost.portsDir, portFileName(instanceKey)));
|
|
6223
6223
|
} catch (e) {
|
|
6224
6224
|
if (e.code === "ENOENT")
|
|
6225
6225
|
return;
|
|
@@ -6704,11 +6704,11 @@ async function cloneProfileForChild(opts) {
|
|
|
6704
6704
|
killInstance(dstKey);
|
|
6705
6705
|
await delay(500);
|
|
6706
6706
|
}
|
|
6707
|
-
if (!
|
|
6707
|
+
if (!existsSync12(srcDir)) {
|
|
6708
6708
|
return { copied: false, srcDir, dstDir, reason: "src-missing" };
|
|
6709
6709
|
}
|
|
6710
6710
|
try {
|
|
6711
|
-
if (
|
|
6711
|
+
if (existsSync12(dstDir)) {
|
|
6712
6712
|
rmSync2(dstDir, { recursive: true, force: true });
|
|
6713
6713
|
}
|
|
6714
6714
|
mkdirSync9(dirname8(dstDir), { recursive: true });
|
|
@@ -6729,7 +6729,7 @@ async function cloneProfileForChild(opts) {
|
|
|
6729
6729
|
cleanSingletonFiles(dstDir);
|
|
6730
6730
|
for (const f of ["DevToolsActivePort", "LOCK"]) {
|
|
6731
6731
|
try {
|
|
6732
|
-
|
|
6732
|
+
unlinkSync11(resolve10(dstDir, f));
|
|
6733
6733
|
} catch {}
|
|
6734
6734
|
}
|
|
6735
6735
|
logger.info({ srcKey, dstKey, srcDir, dstDir }, "Cloned Playwright profile for child topic");
|
|
@@ -7277,11 +7277,11 @@ var init_api_topic_config = __esm(async () => {
|
|
|
7277
7277
|
|
|
7278
7278
|
// ../../packages/core/src/storage/conversations.ts
|
|
7279
7279
|
import {
|
|
7280
|
-
existsSync as
|
|
7280
|
+
existsSync as existsSync13,
|
|
7281
7281
|
mkdirSync as mkdirSync10,
|
|
7282
|
-
readFileSync as
|
|
7282
|
+
readFileSync as readFileSync11,
|
|
7283
7283
|
renameSync as renameSync5,
|
|
7284
|
-
unlinkSync as
|
|
7284
|
+
unlinkSync as unlinkSync12,
|
|
7285
7285
|
writeFileSync as writeFileSync8
|
|
7286
7286
|
} from "fs";
|
|
7287
7287
|
import { dirname as dirname9, join as join14 } from "path";
|
|
@@ -7300,7 +7300,7 @@ function getActiveConversationPath(userId, topicName) {
|
|
|
7300
7300
|
return rawPath.endsWith(".jsonl") ? `${rawPath.slice(0, -".jsonl".length)}.active.jsonl` : `${rawPath}.active`;
|
|
7301
7301
|
}
|
|
7302
7302
|
function hasActiveConversation(userId, topicName) {
|
|
7303
|
-
return
|
|
7303
|
+
return existsSync13(getActiveConversationPath(userId, topicName));
|
|
7304
7304
|
}
|
|
7305
7305
|
function appendConversationEvent(userId, topicName, agent, event) {
|
|
7306
7306
|
try {
|
|
@@ -7322,7 +7322,7 @@ function appendConversationEventStrict(userId, topicName, agent, event) {
|
|
|
7322
7322
|
mkdirSync10(dirname9(path), { recursive: true });
|
|
7323
7323
|
appendJsonlLine(path, line);
|
|
7324
7324
|
const activePath = getActiveConversationPath(userId, topicName);
|
|
7325
|
-
if (
|
|
7325
|
+
if (existsSync13(activePath)) {
|
|
7326
7326
|
try {
|
|
7327
7327
|
appendJsonlLine(activePath, line);
|
|
7328
7328
|
} catch (cause) {
|
|
@@ -7332,11 +7332,11 @@ function appendConversationEventStrict(userId, topicName, agent, event) {
|
|
|
7332
7332
|
}
|
|
7333
7333
|
function readConversationPath(path) {
|
|
7334
7334
|
const out = [];
|
|
7335
|
-
if (!
|
|
7335
|
+
if (!existsSync13(path))
|
|
7336
7336
|
return out;
|
|
7337
7337
|
let raw;
|
|
7338
7338
|
try {
|
|
7339
|
-
raw =
|
|
7339
|
+
raw = readFileSync11(path, "utf8");
|
|
7340
7340
|
} catch (err) {
|
|
7341
7341
|
logger.warn({ err, path }, "readConversation: read failed");
|
|
7342
7342
|
return out;
|
|
@@ -7355,7 +7355,7 @@ function readConversationPath(path) {
|
|
|
7355
7355
|
}
|
|
7356
7356
|
function readConversation(userId, topicName) {
|
|
7357
7357
|
const activePath = getActiveConversationPath(userId, topicName);
|
|
7358
|
-
return readConversationPath(
|
|
7358
|
+
return readConversationPath(existsSync13(activePath) ? activePath : getConversationPath(userId, topicName));
|
|
7359
7359
|
}
|
|
7360
7360
|
function readRawConversation(userId, topicName) {
|
|
7361
7361
|
return readConversationPath(getConversationPath(userId, topicName));
|
|
@@ -7376,7 +7376,7 @@ function replaceConversationPathStrict(path, entries) {
|
|
|
7376
7376
|
renameSync5(tempPath, path);
|
|
7377
7377
|
} catch (error) {
|
|
7378
7378
|
try {
|
|
7379
|
-
|
|
7379
|
+
unlinkSync12(tempPath);
|
|
7380
7380
|
} catch {}
|
|
7381
7381
|
throw error;
|
|
7382
7382
|
}
|
|
@@ -7513,7 +7513,7 @@ RULES:
|
|
|
7513
7513
|
- Keep the entire summary under 1500 words.`, CHARS_PER_TEXT_TOKEN = 3.5, CHARS_PER_CJK_TOKEN = 0.9;
|
|
7514
7514
|
|
|
7515
7515
|
// ../../packages/core/src/storage/tasks.ts
|
|
7516
|
-
import { existsSync as
|
|
7516
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync11, readFileSync as readFileSync12, renameSync as renameSync6, statSync as statSync4, writeFileSync as writeFileSync9 } from "fs";
|
|
7517
7517
|
import { dirname as dirname10, join as join15 } from "path";
|
|
7518
7518
|
function safeTaskScopeKey(scopeKey) {
|
|
7519
7519
|
const safe = sanitizeFileName(scopeKey);
|
|
@@ -7530,10 +7530,10 @@ function getTaskFilePath(userId, scopeKey) {
|
|
|
7530
7530
|
}
|
|
7531
7531
|
function readTasks(userId, scopeKey) {
|
|
7532
7532
|
const path = getTaskFilePath(userId, scopeKey);
|
|
7533
|
-
if (!
|
|
7533
|
+
if (!existsSync14(path))
|
|
7534
7534
|
return [];
|
|
7535
7535
|
try {
|
|
7536
|
-
const parsed = JSON.parse(
|
|
7536
|
+
const parsed = JSON.parse(readFileSync12(path, "utf-8"));
|
|
7537
7537
|
return Array.isArray(parsed?.tasks) ? parsed.tasks : [];
|
|
7538
7538
|
} catch (e) {
|
|
7539
7539
|
logger.warn({ err: e, path }, "tasks: failed to read task store");
|
|
@@ -7788,7 +7788,7 @@ __export(exports_claude_provider, {
|
|
|
7788
7788
|
buildClaudeDisallowedTools: () => buildClaudeDisallowedTools
|
|
7789
7789
|
});
|
|
7790
7790
|
import { spawn as spawn7 } from "child_process";
|
|
7791
|
-
import { existsSync as
|
|
7791
|
+
import { existsSync as existsSync15, readFileSync as readFileSync13 } from "fs";
|
|
7792
7792
|
import { query } from "@anthropic-ai/claude-agent-sdk";
|
|
7793
7793
|
function claudeBuiltInTools(opts) {
|
|
7794
7794
|
return opts.toolPolicy ? [] : undefined;
|
|
@@ -7841,7 +7841,7 @@ function buildClaudePrompt(opts) {
|
|
|
7841
7841
|
source: {
|
|
7842
7842
|
type: "base64",
|
|
7843
7843
|
media_type: attachment.mimeType,
|
|
7844
|
-
data:
|
|
7844
|
+
data: readFileSync13(attachment.path).toString("base64")
|
|
7845
7845
|
}
|
|
7846
7846
|
});
|
|
7847
7847
|
} catch (err) {
|
|
@@ -7969,7 +7969,7 @@ function isAbortError(err) {
|
|
|
7969
7969
|
}
|
|
7970
7970
|
async function* claudeProvider(opts) {
|
|
7971
7971
|
const claudeExecutable = hostedClaudeCodeExecutablePath();
|
|
7972
|
-
if (claudeExecutable && !
|
|
7972
|
+
if (claudeExecutable && !existsSync15(claudeExecutable)) {
|
|
7973
7973
|
yield {
|
|
7974
7974
|
type: "error",
|
|
7975
7975
|
content: `Claude CLI not found at ${claudeExecutable}. Install Claude Code or configure the executable path.`
|
|
@@ -8489,7 +8489,7 @@ var init_codex_tree_kill = __esm(() => {
|
|
|
8489
8489
|
});
|
|
8490
8490
|
|
|
8491
8491
|
// ../../packages/core/src/agents/tool-format.ts
|
|
8492
|
-
import { readFileSync as
|
|
8492
|
+
import { readFileSync as readFileSync14, statSync as statSync5 } from "fs";
|
|
8493
8493
|
import { isAbsolute as isAbsolute2, resolve as resolve11 } from "path";
|
|
8494
8494
|
import { diffLines as computeLineDiff } from "diff";
|
|
8495
8495
|
function summarizeDisplayText(value2) {
|
|
@@ -8818,7 +8818,7 @@ function sourceStartLine(input, before, after, cwd) {
|
|
|
8818
8818
|
try {
|
|
8819
8819
|
if (statSync5(path).size > TOOL_DIFF_SOURCE_MAX_BYTES)
|
|
8820
8820
|
return 1;
|
|
8821
|
-
const source =
|
|
8821
|
+
const source = readFileSync14(path, "utf8").replace(/\r\n?/g, `
|
|
8822
8822
|
`);
|
|
8823
8823
|
for (const candidate of [before, after].filter(Boolean)) {
|
|
8824
8824
|
const index = source.indexOf(candidate);
|
|
@@ -9012,7 +9012,7 @@ __export(exports_codex_provider, {
|
|
|
9012
9012
|
codexProvider: () => codexProvider
|
|
9013
9013
|
});
|
|
9014
9014
|
import { execFileSync as execFileSync6 } from "child_process";
|
|
9015
|
-
import { existsSync as
|
|
9015
|
+
import { existsSync as existsSync16, readFileSync as readFileSync15, realpathSync as realpathSync4, statSync as statSync6 } from "fs";
|
|
9016
9016
|
import { homedir as homedir6 } from "os";
|
|
9017
9017
|
import { dirname as dirname11, isAbsolute as isAbsolute3, join as join16, relative as relative2, resolve as resolve12 } from "path";
|
|
9018
9018
|
import { Codex } from "@openai/codex-sdk";
|
|
@@ -9043,11 +9043,11 @@ function codexMcpServerName(name) {
|
|
|
9043
9043
|
}
|
|
9044
9044
|
function globalCodexMcpServerNames(authFilePath) {
|
|
9045
9045
|
const configPath = join16(dirname11(authFilePath), "config.toml");
|
|
9046
|
-
if (!
|
|
9046
|
+
if (!existsSync16(configPath))
|
|
9047
9047
|
return [];
|
|
9048
9048
|
try {
|
|
9049
9049
|
const names = new Set;
|
|
9050
|
-
for (const line of
|
|
9050
|
+
for (const line of readFileSync15(configPath, "utf8").split(`
|
|
9051
9051
|
`)) {
|
|
9052
9052
|
const match = line.match(/^\s*\[\s*mcp_servers\.((?:"(?:\\.|[^"])*")|(?:'[^']*')|[^.\]\s]+)(?:[.\]])/);
|
|
9053
9053
|
const raw = match?.[1];
|
|
@@ -9144,13 +9144,13 @@ function canonicalPath(path) {
|
|
|
9144
9144
|
}
|
|
9145
9145
|
}
|
|
9146
9146
|
function textFile(path, maxBytes = CODEX_DIFF_FILE_LIMIT) {
|
|
9147
|
-
if (!
|
|
9147
|
+
if (!existsSync16(path))
|
|
9148
9148
|
return null;
|
|
9149
9149
|
try {
|
|
9150
9150
|
const byteLimit = Math.min(CODEX_DIFF_FILE_LIMIT, Math.max(0, maxBytes));
|
|
9151
9151
|
if (statSync6(path).size > byteLimit)
|
|
9152
9152
|
return;
|
|
9153
|
-
const content =
|
|
9153
|
+
const content = readFileSync15(path);
|
|
9154
9154
|
if (content.byteLength > byteLimit || content.includes(0))
|
|
9155
9155
|
return;
|
|
9156
9156
|
return content.toString("utf8");
|
|
@@ -9356,7 +9356,7 @@ async function* codexProvider(opts) {
|
|
|
9356
9356
|
const filePreviews = new CodexFilePreviewTracker(opts.cwd);
|
|
9357
9357
|
const consumedPatchCallIds = new Set(opts.sessionId ? readCodexPatchCallIds(opts.sessionId) : []);
|
|
9358
9358
|
const codexAuthPath = hostedCodexAuthFilePath();
|
|
9359
|
-
if (!
|
|
9359
|
+
if (!existsSync16(codexAuthPath)) {
|
|
9360
9360
|
yield {
|
|
9361
9361
|
type: "error",
|
|
9362
9362
|
content: `Codex auth file not found at ${codexAuthPath}. Run \`codex login\` to authenticate.`
|
|
@@ -9395,7 +9395,7 @@ async function* codexProvider(opts) {
|
|
|
9395
9395
|
model: opts.model ?? "(sdk default)",
|
|
9396
9396
|
effort: opts.effort ?? "(off)",
|
|
9397
9397
|
cwd: opts.cwd,
|
|
9398
|
-
cwdExists:
|
|
9398
|
+
cwdExists: existsSync16(opts.cwd),
|
|
9399
9399
|
resume: Boolean(opts.sessionId),
|
|
9400
9400
|
mcpServerCount: Object.keys(codexMcpServers).length
|
|
9401
9401
|
}, "codexProvider: starting turn");
|
|
@@ -9847,7 +9847,7 @@ var init_maestro_provider = __esm(async () => {
|
|
|
9847
9847
|
});
|
|
9848
9848
|
|
|
9849
9849
|
// ../../packages/core/src/agents/index.ts
|
|
9850
|
-
import { existsSync as
|
|
9850
|
+
import { existsSync as existsSync17 } from "fs";
|
|
9851
9851
|
import { homedir as homedir7 } from "os";
|
|
9852
9852
|
import { join as join17 } from "path";
|
|
9853
9853
|
async function* dispatchAgent(opts) {
|
|
@@ -9884,7 +9884,7 @@ async function resolveSessionFileMissing(agent, sessionId, cwd) {
|
|
|
9884
9884
|
case "claude": {
|
|
9885
9885
|
const encodedCwd = encodeClaudeCwd(cwd);
|
|
9886
9886
|
const path = join17(homedir7(), ".claude", "projects", encodedCwd, `${sessionId}.jsonl`);
|
|
9887
|
-
return !
|
|
9887
|
+
return !existsSync17(path);
|
|
9888
9888
|
}
|
|
9889
9889
|
case "codex": {
|
|
9890
9890
|
const sessionsDir = join17(hostedCodexHomePath(), "sessions");
|
|
@@ -9896,7 +9896,7 @@ async function resolveSessionFileMissing(agent, sessionId, cwd) {
|
|
|
9896
9896
|
}
|
|
9897
9897
|
case "maestro": {
|
|
9898
9898
|
const { hasActiveMaestroSession, maestroSessionPath: maestroSessionPath2 } = await import("maestro-agent-sdk");
|
|
9899
|
-
return !
|
|
9899
|
+
return !existsSync17(maestroSessionPath2(sessionId)) && !hasActiveMaestroSession(sessionId);
|
|
9900
9900
|
}
|
|
9901
9901
|
default: {
|
|
9902
9902
|
const _exhaustive = agent;
|
|
@@ -9969,10 +9969,10 @@ var init_agents = __esm(async () => {
|
|
|
9969
9969
|
});
|
|
9970
9970
|
|
|
9971
9971
|
// ../../packages/core/src/prompts/builders.ts
|
|
9972
|
-
import { readFileSync as
|
|
9972
|
+
import { readFileSync as readFileSync16 } from "fs";
|
|
9973
9973
|
import { resolve as resolve14 } from "path";
|
|
9974
9974
|
function loadPrompt(filename, dir = SESSIONS_DIR) {
|
|
9975
|
-
const raw =
|
|
9975
|
+
const raw = readFileSync16(resolve14(dir, filename), "utf-8");
|
|
9976
9976
|
return raw.replace(/\{\{RESOURCES_DIR\}\}/g, RESOURCES_DIR);
|
|
9977
9977
|
}
|
|
9978
9978
|
function replaceVars(template, vars) {
|
|
@@ -10021,7 +10021,7 @@ function visualDesignGuide() {
|
|
|
10021
10021
|
return _visualDesignGuide;
|
|
10022
10022
|
}
|
|
10023
10023
|
function loadAgentPrompt(filename) {
|
|
10024
|
-
const raw =
|
|
10024
|
+
const raw = readFileSync16(resolve14(AGENTS_PROMPTS_DIR, filename), "utf-8");
|
|
10025
10025
|
const match = raw.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
10026
10026
|
if (!match)
|
|
10027
10027
|
throw new Error(`Agent prompt ${filename} is missing frontmatter`);
|
|
@@ -10420,7 +10420,7 @@ var init_wiki = __esm(async () => {
|
|
|
10420
10420
|
|
|
10421
10421
|
// ../../packages/core/src/agents/archiver.ts
|
|
10422
10422
|
import { randomUUID as randomUUID9 } from "crypto";
|
|
10423
|
-
import { existsSync as
|
|
10423
|
+
import { existsSync as existsSync18, readdirSync as readdirSync5, readFileSync as readFileSync17, statSync as statSync7 } from "fs";
|
|
10424
10424
|
import { join as join19 } from "path";
|
|
10425
10425
|
function resolveMemoryLanguage() {
|
|
10426
10426
|
const override = process.env.NEGOTIUM_MEMORY_LANG?.trim();
|
|
@@ -10765,9 +10765,9 @@ var init_archiver = __esm(async () => {
|
|
|
10765
10765
|
defaultArchiverRuntime = createArchiverRuntime({
|
|
10766
10766
|
storage: {
|
|
10767
10767
|
getWikiDir: getSharedWikiDir,
|
|
10768
|
-
fileExists:
|
|
10768
|
+
fileExists: existsSync18,
|
|
10769
10769
|
listDirectory: readdirSync5,
|
|
10770
|
-
readTextFile: (path) =>
|
|
10770
|
+
readTextFile: (path) => readFileSync17(path, "utf-8"),
|
|
10771
10771
|
fileSize: (path) => statSync7(path).size,
|
|
10772
10772
|
fileModifiedAt: (path) => statSync7(path).mtimeMs,
|
|
10773
10773
|
getGeneralTopicId: (userId) => ensurePersonalGeneral(userId).id,
|
|
@@ -11304,7 +11304,7 @@ var init_idle_archiver = __esm(async () => {
|
|
|
11304
11304
|
});
|
|
11305
11305
|
|
|
11306
11306
|
// ../../packages/core/src/agents/topic-cleanup.ts
|
|
11307
|
-
import { mkdirSync as mkdirSync13, renameSync as renameSync7, unlinkSync as
|
|
11307
|
+
import { mkdirSync as mkdirSync13, renameSync as renameSync7, unlinkSync as unlinkSync13, writeFileSync as writeFileSync11 } from "fs";
|
|
11308
11308
|
import { dirname as dirname13 } from "path";
|
|
11309
11309
|
function collectSessionIdsByAgent(entries, extraSessions = []) {
|
|
11310
11310
|
const out = new Map;
|
|
@@ -11378,7 +11378,7 @@ function createTopicLogMaintenance(host) {
|
|
|
11378
11378
|
renameSync7(tempPath, path);
|
|
11379
11379
|
} catch (e) {
|
|
11380
11380
|
try {
|
|
11381
|
-
|
|
11381
|
+
unlinkSync13(tempPath);
|
|
11382
11382
|
} catch {}
|
|
11383
11383
|
runtimeHost.warn({ err: e, path }, "rotateTopicLogs: conversation replacement failed");
|
|
11384
11384
|
return {
|
|
@@ -11408,7 +11408,7 @@ function createTopicLogMaintenance(host) {
|
|
|
11408
11408
|
runtimeHost.rawConversationPath(userId, topicName)
|
|
11409
11409
|
]) {
|
|
11410
11410
|
try {
|
|
11411
|
-
|
|
11411
|
+
unlinkSync13(path);
|
|
11412
11412
|
} catch (e) {
|
|
11413
11413
|
if (e?.code !== "ENOENT") {
|
|
11414
11414
|
runtimeHost.warn({ err: e, path }, "purgeTopicLogs: conversation log unlink failed");
|
|
@@ -11960,7 +11960,7 @@ __export(exports_derive, {
|
|
|
11960
11960
|
TopicDeriveBusyError: () => TopicDeriveBusyError
|
|
11961
11961
|
});
|
|
11962
11962
|
import { createHash as createHash4, randomUUID as randomUUID11 } from "crypto";
|
|
11963
|
-
import { mkdirSync as mkdirSync14, rmSync as rmSync5, unlinkSync as
|
|
11963
|
+
import { mkdirSync as mkdirSync14, rmSync as rmSync5, unlinkSync as unlinkSync14 } from "fs";
|
|
11964
11964
|
function getTopics() {
|
|
11965
11965
|
return listTopics().filter((topic) => !isLegacySharedGeneral(topic.id));
|
|
11966
11966
|
}
|
|
@@ -12255,7 +12255,7 @@ async function createDerivedTopicImpl(topic, sourceTopicId, userId, copyHistory,
|
|
|
12255
12255
|
getConversationPath(userId, derived.title)
|
|
12256
12256
|
]) {
|
|
12257
12257
|
try {
|
|
12258
|
-
|
|
12258
|
+
unlinkSync14(path);
|
|
12259
12259
|
} catch {}
|
|
12260
12260
|
}
|
|
12261
12261
|
}
|
|
@@ -12327,7 +12327,7 @@ var init_session_inbox_path = __esm(() => {
|
|
|
12327
12327
|
});
|
|
12328
12328
|
|
|
12329
12329
|
// ../../packages/core/src/query/session-inbox-cleanup.ts
|
|
12330
|
-
import { unlinkSync as
|
|
12330
|
+
import { unlinkSync as unlinkSync15 } from "fs";
|
|
12331
12331
|
import { basename as basename4, join as join23 } from "path";
|
|
12332
12332
|
function cleanupSessionInboxFiles(userId, topicId, legacyTopicTitle) {
|
|
12333
12333
|
const live = sessionInboxPath(userId, topicId);
|
|
@@ -12342,7 +12342,7 @@ function cleanupSessionInboxFiles(userId, topicId, legacyTopicTitle) {
|
|
|
12342
12342
|
let deleted = 0;
|
|
12343
12343
|
for (const path of candidates) {
|
|
12344
12344
|
try {
|
|
12345
|
-
|
|
12345
|
+
unlinkSync15(path);
|
|
12346
12346
|
deleted++;
|
|
12347
12347
|
} catch (err) {
|
|
12348
12348
|
if (err?.code !== "ENOENT") {
|
|
@@ -12359,7 +12359,7 @@ var init_session_inbox_cleanup = __esm(() => {
|
|
|
12359
12359
|
});
|
|
12360
12360
|
|
|
12361
12361
|
// ../../packages/core/src/query/state.ts
|
|
12362
|
-
import { mkdirSync as mkdirSync15, renameSync as renameSync8, unlinkSync as
|
|
12362
|
+
import { mkdirSync as mkdirSync15, renameSync as renameSync8, unlinkSync as unlinkSync16, writeFileSync as writeFileSync13 } from "fs";
|
|
12363
12363
|
import { basename as basename5, join as join24 } from "path";
|
|
12364
12364
|
function createQueryStateStore(options) {
|
|
12365
12365
|
const sanitize = options.sanitizeTopicId ?? sanitizeId;
|
|
@@ -12390,7 +12390,7 @@ function createQueryStateStore(options) {
|
|
|
12390
12390
|
].filter((path) => Boolean(path));
|
|
12391
12391
|
for (const path of new Set(paths)) {
|
|
12392
12392
|
try {
|
|
12393
|
-
|
|
12393
|
+
unlinkSync16(path);
|
|
12394
12394
|
} catch (error) {
|
|
12395
12395
|
if (error?.code !== "ENOENT") {
|
|
12396
12396
|
options.logger?.warn({ err: error, userId, topicId, path }, "Failed to clear query state file");
|
|
@@ -12524,9 +12524,9 @@ import {
|
|
|
12524
12524
|
mkdirSync as mkdirSync16,
|
|
12525
12525
|
openSync as openSync3,
|
|
12526
12526
|
readdirSync as readdirSync6,
|
|
12527
|
-
readFileSync as
|
|
12527
|
+
readFileSync as readFileSync18,
|
|
12528
12528
|
statSync as statSync8,
|
|
12529
|
-
unlinkSync as
|
|
12529
|
+
unlinkSync as unlinkSync17,
|
|
12530
12530
|
writeFileSync as writeFileSync14
|
|
12531
12531
|
} from "fs";
|
|
12532
12532
|
import { dirname as dirname14, join as join25 } from "path";
|
|
@@ -12573,7 +12573,7 @@ function parsePendingAskFilename(fileName) {
|
|
|
12573
12573
|
}
|
|
12574
12574
|
function readPendingAskFile(path, fallback) {
|
|
12575
12575
|
try {
|
|
12576
|
-
const raw =
|
|
12576
|
+
const raw = readFileSync18(path, "utf8").trim();
|
|
12577
12577
|
if (!raw)
|
|
12578
12578
|
return null;
|
|
12579
12579
|
if (!raw.startsWith("{")) {
|
|
@@ -12662,7 +12662,7 @@ function readPendingAsk(key) {
|
|
|
12662
12662
|
const next = migrated ? legacy : readPendingAskFile(canonicalPath2, key);
|
|
12663
12663
|
if (next && next.from === key.from && next.to === key.to) {
|
|
12664
12664
|
try {
|
|
12665
|
-
|
|
12665
|
+
unlinkSync17(compatibilityPath);
|
|
12666
12666
|
} catch {}
|
|
12667
12667
|
return { path: canonicalPath2, record: next };
|
|
12668
12668
|
}
|
|
@@ -12677,7 +12677,7 @@ function createPendingAsk(args) {
|
|
|
12677
12677
|
}
|
|
12678
12678
|
if (migrated) {
|
|
12679
12679
|
try {
|
|
12680
|
-
|
|
12680
|
+
unlinkSync17(migrated.path);
|
|
12681
12681
|
} catch {
|
|
12682
12682
|
return { ok: false, existing: migrated.record, stale: true };
|
|
12683
12683
|
}
|
|
@@ -12709,7 +12709,7 @@ function createPendingAsk(args) {
|
|
|
12709
12709
|
if (!isStale(existing, path))
|
|
12710
12710
|
return { ok: false, existing, stale: false };
|
|
12711
12711
|
try {
|
|
12712
|
-
|
|
12712
|
+
unlinkSync17(path);
|
|
12713
12713
|
} catch {
|
|
12714
12714
|
return { ok: false, existing, stale: true };
|
|
12715
12715
|
}
|
|
@@ -12735,7 +12735,7 @@ function markPendingAskState(args) {
|
|
|
12735
12735
|
writePendingAsk(next);
|
|
12736
12736
|
if (pending.path !== pendingAskPath(next)) {
|
|
12737
12737
|
try {
|
|
12738
|
-
|
|
12738
|
+
unlinkSync17(pending.path);
|
|
12739
12739
|
} catch {}
|
|
12740
12740
|
}
|
|
12741
12741
|
return next;
|
|
@@ -12747,7 +12747,7 @@ function clearPendingAsk(args) {
|
|
|
12747
12747
|
if (args.requestId && record && record.requestId !== args.requestId)
|
|
12748
12748
|
return false;
|
|
12749
12749
|
try {
|
|
12750
|
-
|
|
12750
|
+
unlinkSync17(path);
|
|
12751
12751
|
return true;
|
|
12752
12752
|
} catch {
|
|
12753
12753
|
return false;
|
|
@@ -12802,7 +12802,7 @@ function listPendingAsksForCaller(args) {
|
|
|
12802
12802
|
continue;
|
|
12803
12803
|
if (isStale(record, path)) {
|
|
12804
12804
|
try {
|
|
12805
|
-
|
|
12805
|
+
unlinkSync17(path);
|
|
12806
12806
|
} catch {}
|
|
12807
12807
|
continue;
|
|
12808
12808
|
}
|
|
@@ -12811,12 +12811,12 @@ function listPendingAsksForCaller(args) {
|
|
|
12811
12811
|
continue;
|
|
12812
12812
|
if (path !== canonical.path) {
|
|
12813
12813
|
try {
|
|
12814
|
-
|
|
12814
|
+
unlinkSync17(path);
|
|
12815
12815
|
} catch {}
|
|
12816
12816
|
}
|
|
12817
12817
|
if (isStale(canonical.record, canonical.path)) {
|
|
12818
12818
|
try {
|
|
12819
|
-
|
|
12819
|
+
unlinkSync17(canonical.path);
|
|
12820
12820
|
} catch {}
|
|
12821
12821
|
continue;
|
|
12822
12822
|
}
|
|
@@ -12846,7 +12846,7 @@ function deletePendingAsksForTopic(args) {
|
|
|
12846
12846
|
if (from !== args.topicName && to !== args.topicName)
|
|
12847
12847
|
continue;
|
|
12848
12848
|
try {
|
|
12849
|
-
|
|
12849
|
+
unlinkSync17(path);
|
|
12850
12850
|
deleted++;
|
|
12851
12851
|
} catch {}
|
|
12852
12852
|
}
|
|
@@ -15506,7 +15506,7 @@ var init_turn_session = __esm(async () => {
|
|
|
15506
15506
|
});
|
|
15507
15507
|
|
|
15508
15508
|
// ../../packages/core/src/storage/app-settings.ts
|
|
15509
|
-
import { existsSync as
|
|
15509
|
+
import { existsSync as existsSync19, mkdirSync as mkdirSync19, readFileSync as readFileSync19, writeFileSync as writeFileSync16 } from "fs";
|
|
15510
15510
|
import { dirname as dirname15, join as join28 } from "path";
|
|
15511
15511
|
function settingsFile() {
|
|
15512
15512
|
return join28(resolveStorageDataDir(), "otium-settings.json");
|
|
@@ -15518,8 +15518,8 @@ function ensureSettingsLoaded() {
|
|
|
15518
15518
|
loadedSettingsFile = path;
|
|
15519
15519
|
aiName = DEFAULT_AI_NAME;
|
|
15520
15520
|
try {
|
|
15521
|
-
if (
|
|
15522
|
-
const data = JSON.parse(
|
|
15521
|
+
if (existsSync19(path)) {
|
|
15522
|
+
const data = JSON.parse(readFileSync19(path, "utf8"));
|
|
15523
15523
|
if (typeof data.aiName === "string" && data.aiName.trim()) {
|
|
15524
15524
|
aiName = data.aiName.trim();
|
|
15525
15525
|
}
|
|
@@ -15612,7 +15612,7 @@ __export(exports_turn_runner, {
|
|
|
15612
15612
|
AGENT_DISPLAY_NAME: () => AGENT_DISPLAY_NAME
|
|
15613
15613
|
});
|
|
15614
15614
|
import { randomUUID as randomUUID16 } from "crypto";
|
|
15615
|
-
import { existsSync as
|
|
15615
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync20, readdirSync as readdirSync7, statSync as statSync10 } from "fs";
|
|
15616
15616
|
import { join as join29 } from "path";
|
|
15617
15617
|
function withDefaultPlaywright(configuredMcp, isManager) {
|
|
15618
15618
|
if (isManager)
|
|
@@ -15669,7 +15669,7 @@ function appendAskReplyMessage(topicId, text2, agentType) {
|
|
|
15669
15669
|
}
|
|
15670
15670
|
function resolveWikiMirrorPath(directory, preferredFilename, matchesLegacyId, matchesTitle, preferExact = true) {
|
|
15671
15671
|
const preferred = join29(directory, preferredFilename);
|
|
15672
|
-
if (preferExact &&
|
|
15672
|
+
if (preferExact && existsSync20(preferred))
|
|
15673
15673
|
return preferred;
|
|
15674
15674
|
let newestLegacyId = null;
|
|
15675
15675
|
let newestTitle = null;
|
|
@@ -15694,9 +15694,9 @@ function resolveWikiMirrorPath(directory, preferredFilename, matchesLegacyId, ma
|
|
|
15694
15694
|
}
|
|
15695
15695
|
function resolveWikiMemoryMirror(wikiDir, topicId, topicTitle) {
|
|
15696
15696
|
const briefFile = resolveWikiMirrorPath(join29(wikiDir, "topic"), `${wikiBriefStorageKey(topicTitle, topicId)}.md`, (filename) => isTopicBriefFile(filename, topicId), (filename) => isTopicBriefFile(filename, topicId, topicTitle));
|
|
15697
|
-
const hasBriefFile =
|
|
15697
|
+
const hasBriefFile = existsSync20(briefFile) && statSync10(briefFile).isFile();
|
|
15698
15698
|
const latestSummaryCandidate = resolveWikiMirrorPath(join29(wikiDir, "summaries"), `__missing__-${wikiSummaryFilename("0000-00-00", topicTitle, topicId)}`, (filename) => isTopicSummaryFile(filename, topicId), (filename) => isTopicSummaryFile(filename, topicId, topicTitle), false);
|
|
15699
|
-
const latestSummaryFile =
|
|
15699
|
+
const latestSummaryFile = existsSync20(latestSummaryCandidate) && statSync10(latestSummaryCandidate).isFile() ? latestSummaryCandidate : null;
|
|
15700
15700
|
return { briefFile, hasBriefFile, latestSummaryFile };
|
|
15701
15701
|
}
|
|
15702
15702
|
async function streamAgentEvents(topicId, topicTitle, queryId, events, control, agentType, model, effort, userId, retryableSessionExpired = true, onSessionId, execution) {
|
|
@@ -16892,7 +16892,7 @@ __export(exports_auth_check, {
|
|
|
16892
16892
|
checkAgentAuth: () => checkAgentAuth
|
|
16893
16893
|
});
|
|
16894
16894
|
import { execFileSync as execFileSync7 } from "child_process";
|
|
16895
|
-
import { existsSync as
|
|
16895
|
+
import { existsSync as existsSync21 } from "fs";
|
|
16896
16896
|
import { homedir as homedir8, platform } from "os";
|
|
16897
16897
|
import { join as join30 } from "path";
|
|
16898
16898
|
function hasMaestroCredential(host, key, userId) {
|
|
@@ -16965,7 +16965,7 @@ var init_auth_check = __esm(async () => {
|
|
|
16965
16965
|
await init_vault();
|
|
16966
16966
|
defaultAgentAuthHost = {
|
|
16967
16967
|
codexAuthFilePath,
|
|
16968
|
-
exists:
|
|
16968
|
+
exists: existsSync21,
|
|
16969
16969
|
environment: process.env,
|
|
16970
16970
|
homeDirectory: homedir8,
|
|
16971
16971
|
operatingSystem: platform,
|
|
@@ -18196,25 +18196,238 @@ import { AsyncLocalStorage } from "async_hooks";
|
|
|
18196
18196
|
import { randomUUID } from "crypto";
|
|
18197
18197
|
import {
|
|
18198
18198
|
closeSync,
|
|
18199
|
-
existsSync as
|
|
18199
|
+
existsSync as existsSync3,
|
|
18200
18200
|
mkdirSync as mkdirSync2,
|
|
18201
18201
|
openSync,
|
|
18202
18202
|
readdirSync,
|
|
18203
|
-
readFileSync as
|
|
18203
|
+
readFileSync as readFileSync3,
|
|
18204
18204
|
renameSync,
|
|
18205
18205
|
statSync,
|
|
18206
|
-
unlinkSync,
|
|
18206
|
+
unlinkSync as unlinkSync2,
|
|
18207
18207
|
writeFileSync as writeFileSync2
|
|
18208
18208
|
} from "fs";
|
|
18209
18209
|
import { basename, dirname as dirname2, join as join2, relative, resolve as resolve2 } from "path";
|
|
18210
|
-
init_config();
|
|
18211
|
-
init_wiki_summary_names();
|
|
18212
18210
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
18213
18211
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
18214
18212
|
import {
|
|
18215
18213
|
CallToolRequestSchema,
|
|
18216
18214
|
ListToolsRequestSchema
|
|
18217
18215
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
18216
|
+
|
|
18217
|
+
// ../../packages/core/src/mcp/wiki-search-index.ts
|
|
18218
|
+
await init_sqlite();
|
|
18219
|
+
import { chmodSync, existsSync, readFileSync, unlinkSync } from "fs";
|
|
18220
|
+
var SEARCH_INDEX_SCHEMA_VERSION = 3;
|
|
18221
|
+
function documentId(source) {
|
|
18222
|
+
return `${source.kind}:${source.key}`;
|
|
18223
|
+
}
|
|
18224
|
+
function ensureSchema(database) {
|
|
18225
|
+
const version = database.query("PRAGMA user_version").get()?.user_version;
|
|
18226
|
+
if (version !== 0 && version !== SEARCH_INDEX_SCHEMA_VERSION) {
|
|
18227
|
+
throw new Error(`Unsupported wiki search index schema: ${version}`);
|
|
18228
|
+
}
|
|
18229
|
+
database.exec(`
|
|
18230
|
+
CREATE TABLE IF NOT EXISTS wiki_search_documents (
|
|
18231
|
+
id TEXT PRIMARY KEY,
|
|
18232
|
+
kind TEXT NOT NULL,
|
|
18233
|
+
key TEXT NOT NULL,
|
|
18234
|
+
path TEXT NOT NULL,
|
|
18235
|
+
mtime_ms REAL NOT NULL,
|
|
18236
|
+
size INTEGER NOT NULL,
|
|
18237
|
+
title TEXT NOT NULL,
|
|
18238
|
+
text TEXT NOT NULL,
|
|
18239
|
+
date TEXT,
|
|
18240
|
+
family TEXT
|
|
18241
|
+
);
|
|
18242
|
+
CREATE UNIQUE INDEX IF NOT EXISTS wiki_search_documents_kind_key
|
|
18243
|
+
ON wiki_search_documents(kind, key);
|
|
18244
|
+
CREATE INDEX IF NOT EXISTS wiki_search_documents_kind_date
|
|
18245
|
+
ON wiki_search_documents(kind, date);
|
|
18246
|
+
CREATE INDEX IF NOT EXISTS wiki_search_documents_kind_family_date
|
|
18247
|
+
ON wiki_search_documents(kind, family, date);
|
|
18248
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS wiki_search_fts USING fts5(
|
|
18249
|
+
document_id UNINDEXED,
|
|
18250
|
+
kind UNINDEXED,
|
|
18251
|
+
tokens,
|
|
18252
|
+
tokenize = 'unicode61'
|
|
18253
|
+
);
|
|
18254
|
+
PRAGMA user_version = ${SEARCH_INDEX_SCHEMA_VERSION};
|
|
18255
|
+
`);
|
|
18256
|
+
}
|
|
18257
|
+
|
|
18258
|
+
class WikiSearchIndex {
|
|
18259
|
+
path;
|
|
18260
|
+
#database;
|
|
18261
|
+
constructor(path) {
|
|
18262
|
+
this.path = path;
|
|
18263
|
+
this.#database = new Database(path, { create: true });
|
|
18264
|
+
try {
|
|
18265
|
+
this.#database.exec("PRAGMA foreign_keys = ON; PRAGMA journal_mode = DELETE;");
|
|
18266
|
+
ensureSchema(this.#database);
|
|
18267
|
+
chmodSync(path, 384);
|
|
18268
|
+
} catch (error) {
|
|
18269
|
+
this.#database.close();
|
|
18270
|
+
throw error;
|
|
18271
|
+
}
|
|
18272
|
+
}
|
|
18273
|
+
close() {
|
|
18274
|
+
this.#database.close();
|
|
18275
|
+
}
|
|
18276
|
+
upsert(source, document) {
|
|
18277
|
+
const id = documentId(source);
|
|
18278
|
+
const apply = this.#database.transaction(() => {
|
|
18279
|
+
this.#database.query("DELETE FROM wiki_search_fts WHERE document_id = ?").run(id);
|
|
18280
|
+
this.#database.query("DELETE FROM wiki_search_documents WHERE id = ?").run(id);
|
|
18281
|
+
this.#database.query(`
|
|
18282
|
+
INSERT INTO wiki_search_documents
|
|
18283
|
+
(id, kind, key, path, mtime_ms, size, title, text, date, family)
|
|
18284
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
18285
|
+
`).run(id, source.kind, source.key, source.path, source.mtimeMs, source.size, document.title, document.text, document.date ?? null, document.family ?? null);
|
|
18286
|
+
this.#database.query("INSERT INTO wiki_search_fts(document_id, kind, tokens) VALUES (?, ?, ?)").run(id, source.kind, document.tokens.join(" "));
|
|
18287
|
+
});
|
|
18288
|
+
apply.immediate();
|
|
18289
|
+
}
|
|
18290
|
+
sync(sources, prepare) {
|
|
18291
|
+
const result = { added: 0, updated: 0, removed: 0 };
|
|
18292
|
+
const existingRows = this.#database.query("SELECT id, path, mtime_ms, size FROM wiki_search_documents ORDER BY id").all();
|
|
18293
|
+
const existing = new Map(existingRows.map((row) => [row.id, row]));
|
|
18294
|
+
const present = new Set;
|
|
18295
|
+
const changed = [];
|
|
18296
|
+
for (const source of sources) {
|
|
18297
|
+
const id = documentId(source);
|
|
18298
|
+
present.add(id);
|
|
18299
|
+
const stored = existing.get(id);
|
|
18300
|
+
if (stored && stored.path === source.path && stored.mtime_ms === source.mtimeMs && stored.size === source.size) {
|
|
18301
|
+
continue;
|
|
18302
|
+
}
|
|
18303
|
+
try {
|
|
18304
|
+
const text = readFileSync(source.path, "utf-8");
|
|
18305
|
+
changed.push({ source, document: prepare(source, text), added: !stored });
|
|
18306
|
+
} catch {}
|
|
18307
|
+
}
|
|
18308
|
+
const removed = existingRows.filter((row) => !present.has(row.id));
|
|
18309
|
+
const apply = this.#database.transaction(() => {
|
|
18310
|
+
const deleteTerms = this.#database.query("DELETE FROM wiki_search_fts WHERE document_id = ?");
|
|
18311
|
+
const deleteDocument = this.#database.query("DELETE FROM wiki_search_documents WHERE id = ?");
|
|
18312
|
+
const insertDocument = this.#database.query(`
|
|
18313
|
+
INSERT INTO wiki_search_documents
|
|
18314
|
+
(id, kind, key, path, mtime_ms, size, title, text, date, family)
|
|
18315
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
18316
|
+
`);
|
|
18317
|
+
const insertTerms = this.#database.query(`
|
|
18318
|
+
INSERT INTO wiki_search_fts(document_id, kind, tokens)
|
|
18319
|
+
VALUES (?, ?, ?)
|
|
18320
|
+
`);
|
|
18321
|
+
for (const row of removed) {
|
|
18322
|
+
deleteTerms.run(row.id);
|
|
18323
|
+
deleteDocument.run(row.id);
|
|
18324
|
+
result.removed += 1;
|
|
18325
|
+
}
|
|
18326
|
+
for (const { source, document, added } of changed) {
|
|
18327
|
+
const id = documentId(source);
|
|
18328
|
+
deleteTerms.run(id);
|
|
18329
|
+
deleteDocument.run(id);
|
|
18330
|
+
insertDocument.run(id, source.kind, source.key, source.path, source.mtimeMs, source.size, document.title, document.text, document.date ?? null, document.family ?? null);
|
|
18331
|
+
insertTerms.run(id, source.kind, document.tokens.join(" "));
|
|
18332
|
+
if (added)
|
|
18333
|
+
result.added += 1;
|
|
18334
|
+
else
|
|
18335
|
+
result.updated += 1;
|
|
18336
|
+
}
|
|
18337
|
+
});
|
|
18338
|
+
apply.immediate();
|
|
18339
|
+
return result;
|
|
18340
|
+
}
|
|
18341
|
+
metadata(kinds) {
|
|
18342
|
+
if (kinds.length === 0)
|
|
18343
|
+
return [];
|
|
18344
|
+
const placeholders = kinds.map(() => "?").join(", ");
|
|
18345
|
+
const rows = this.#database.query(`SELECT id, kind, key, title, date
|
|
18346
|
+
FROM wiki_search_documents
|
|
18347
|
+
WHERE kind IN (${placeholders})`).all(...kinds);
|
|
18348
|
+
return rows.map((row) => ({
|
|
18349
|
+
id: row.id,
|
|
18350
|
+
kind: row.kind,
|
|
18351
|
+
key: row.key,
|
|
18352
|
+
title: row.title,
|
|
18353
|
+
...row.date ? { date: row.date } : {}
|
|
18354
|
+
}));
|
|
18355
|
+
}
|
|
18356
|
+
summaryMetadataByDate(query) {
|
|
18357
|
+
const conditions = ["kind = 'summary'", "date IS NOT NULL"];
|
|
18358
|
+
const parameters = [];
|
|
18359
|
+
if (query.year && query.month) {
|
|
18360
|
+
const month = Number(query.month);
|
|
18361
|
+
const nextYear = month === 12 ? String(Number(query.year) + 1) : query.year;
|
|
18362
|
+
const nextMonth = String(month === 12 ? 1 : month + 1).padStart(2, "0");
|
|
18363
|
+
conditions.push("date >= ?", "date < ?");
|
|
18364
|
+
parameters.push(`${query.year}-${query.month}-01`, `${nextYear}-${nextMonth}-01`);
|
|
18365
|
+
} else if (query.year) {
|
|
18366
|
+
conditions.push("date >= ?", "date < ?");
|
|
18367
|
+
parameters.push(`${query.year}-01-01`, `${Number(query.year) + 1}-01-01`);
|
|
18368
|
+
} else if (query.month) {
|
|
18369
|
+
conditions.push("substr(date, 6, 2) = ?");
|
|
18370
|
+
parameters.push(query.month);
|
|
18371
|
+
}
|
|
18372
|
+
parameters.push(query.limit);
|
|
18373
|
+
const rows = this.#database.query(`SELECT id, kind, key, title, date
|
|
18374
|
+
FROM wiki_search_documents
|
|
18375
|
+
WHERE ${conditions.join(" AND ")}
|
|
18376
|
+
ORDER BY date ${query.direction === "oldest" ? "ASC" : "DESC"}, key ASC
|
|
18377
|
+
LIMIT ?`).all(...parameters);
|
|
18378
|
+
return rows.map((row) => ({
|
|
18379
|
+
id: row.id,
|
|
18380
|
+
kind: row.kind,
|
|
18381
|
+
key: row.key,
|
|
18382
|
+
title: row.title,
|
|
18383
|
+
...row.date ? { date: row.date } : {}
|
|
18384
|
+
}));
|
|
18385
|
+
}
|
|
18386
|
+
matchingDocumentIds(kinds, terms) {
|
|
18387
|
+
if (kinds.length === 0 || terms.length === 0)
|
|
18388
|
+
return new Set;
|
|
18389
|
+
const kindPlaceholders = kinds.map(() => "?").join(", ");
|
|
18390
|
+
const match = terms.map((term) => `"${term.replaceAll('"', '""')}"`).join(" OR ");
|
|
18391
|
+
const rows = this.#database.query(`SELECT DISTINCT document_id
|
|
18392
|
+
FROM wiki_search_fts
|
|
18393
|
+
WHERE wiki_search_fts MATCH ? AND kind IN (${kindPlaceholders})`).all(match, ...kinds);
|
|
18394
|
+
return new Set(rows.map((row) => row.document_id));
|
|
18395
|
+
}
|
|
18396
|
+
documents(ids) {
|
|
18397
|
+
if (ids.size === 0)
|
|
18398
|
+
return [];
|
|
18399
|
+
const values = [...ids];
|
|
18400
|
+
const rows = [];
|
|
18401
|
+
for (let offset = 0;offset < values.length; offset += 500) {
|
|
18402
|
+
const chunk = values.slice(offset, offset + 500);
|
|
18403
|
+
const placeholders = chunk.map(() => "?").join(", ");
|
|
18404
|
+
rows.push(...this.#database.query(`SELECT id, kind, key, path, title, text, date
|
|
18405
|
+
FROM wiki_search_documents
|
|
18406
|
+
WHERE id IN (${placeholders})`).all(...chunk));
|
|
18407
|
+
}
|
|
18408
|
+
return rows.map((row) => ({
|
|
18409
|
+
id: row.id,
|
|
18410
|
+
kind: row.kind,
|
|
18411
|
+
key: row.key,
|
|
18412
|
+
path: row.path,
|
|
18413
|
+
title: row.title,
|
|
18414
|
+
text: row.text,
|
|
18415
|
+
tokens: [],
|
|
18416
|
+
...row.date ? { date: row.date } : {}
|
|
18417
|
+
}));
|
|
18418
|
+
}
|
|
18419
|
+
}
|
|
18420
|
+
function resetCorruptWikiSearchIndex(path) {
|
|
18421
|
+
for (const candidate of [path, `${path}-journal`, `${path}-wal`, `${path}-shm`]) {
|
|
18422
|
+
if (!existsSync(candidate))
|
|
18423
|
+
continue;
|
|
18424
|
+
unlinkSync(candidate);
|
|
18425
|
+
}
|
|
18426
|
+
}
|
|
18427
|
+
|
|
18428
|
+
// ../../packages/core/src/mcp/wiki-server.ts
|
|
18429
|
+
init_config();
|
|
18430
|
+
init_wiki_summary_names();
|
|
18218
18431
|
var wikiRuntime = new AsyncLocalStorage;
|
|
18219
18432
|
function runtime() {
|
|
18220
18433
|
const current = wikiRuntime.getStore();
|
|
@@ -18241,15 +18454,15 @@ function acquireRecoveryGuard(lockPath) {
|
|
|
18241
18454
|
} catch (error) {
|
|
18242
18455
|
closeSync(fd);
|
|
18243
18456
|
try {
|
|
18244
|
-
|
|
18457
|
+
unlinkSync2(guardPath);
|
|
18245
18458
|
} catch {}
|
|
18246
18459
|
throw error;
|
|
18247
18460
|
}
|
|
18248
18461
|
return () => {
|
|
18249
18462
|
closeSync(fd);
|
|
18250
18463
|
try {
|
|
18251
|
-
if (
|
|
18252
|
-
|
|
18464
|
+
if (readFileSync3(guardPath, "utf-8") === ownerToken)
|
|
18465
|
+
unlinkSync2(guardPath);
|
|
18253
18466
|
} catch {}
|
|
18254
18467
|
};
|
|
18255
18468
|
} catch (error) {
|
|
@@ -18274,7 +18487,7 @@ function acquireFileLock(path) {
|
|
|
18274
18487
|
} catch (error) {
|
|
18275
18488
|
closeSync(fd);
|
|
18276
18489
|
try {
|
|
18277
|
-
|
|
18490
|
+
unlinkSync2(lockPath);
|
|
18278
18491
|
} catch {}
|
|
18279
18492
|
throw error;
|
|
18280
18493
|
}
|
|
@@ -18282,8 +18495,8 @@ function acquireFileLock(path) {
|
|
|
18282
18495
|
closeSync(fd);
|
|
18283
18496
|
const releaseGuard = acquireRecoveryGuard(lockPath);
|
|
18284
18497
|
try {
|
|
18285
|
-
if (
|
|
18286
|
-
|
|
18498
|
+
if (readFileSync3(lockPath, "utf-8") === ownerToken)
|
|
18499
|
+
unlinkSync2(lockPath);
|
|
18287
18500
|
} catch {} finally {
|
|
18288
18501
|
releaseGuard();
|
|
18289
18502
|
}
|
|
@@ -18294,9 +18507,9 @@ function acquireFileLock(path) {
|
|
|
18294
18507
|
const releaseGuard = acquireRecoveryGuard(lockPath);
|
|
18295
18508
|
try {
|
|
18296
18509
|
try {
|
|
18297
|
-
const staleToken =
|
|
18298
|
-
if (Date.now() - statSync(lockPath).mtimeMs > FILE_LOCK_STALE_MS &&
|
|
18299
|
-
|
|
18510
|
+
const staleToken = readFileSync3(lockPath, "utf-8");
|
|
18511
|
+
if (Date.now() - statSync(lockPath).mtimeMs > FILE_LOCK_STALE_MS && readFileSync3(lockPath, "utf-8") === staleToken) {
|
|
18512
|
+
unlinkSync2(lockPath);
|
|
18300
18513
|
continue;
|
|
18301
18514
|
}
|
|
18302
18515
|
} catch {
|
|
@@ -18319,7 +18532,7 @@ function atomicWriteFile(path, content) {
|
|
|
18319
18532
|
renameSync(temporaryPath, path);
|
|
18320
18533
|
} catch (error) {
|
|
18321
18534
|
try {
|
|
18322
|
-
|
|
18535
|
+
unlinkSync2(temporaryPath);
|
|
18323
18536
|
} catch {}
|
|
18324
18537
|
throw error;
|
|
18325
18538
|
}
|
|
@@ -18506,10 +18719,91 @@ function trigramSimilarity(left, right) {
|
|
|
18506
18719
|
overlap += 1;
|
|
18507
18720
|
return 2 * overlap / (a.size + b.size);
|
|
18508
18721
|
}
|
|
18722
|
+
var WIKI_SEARCH_INDEX_FILENAME = ".wiki-search-index.sqlite";
|
|
18723
|
+
function openWikiSearchIndex() {
|
|
18724
|
+
const path = resolve2(runtime().wikiDir, WIKI_SEARCH_INDEX_FILENAME);
|
|
18725
|
+
try {
|
|
18726
|
+
return new WikiSearchIndex(path);
|
|
18727
|
+
} catch (error) {
|
|
18728
|
+
if (!/malformed|not a database|schema/i.test(String(error)))
|
|
18729
|
+
return;
|
|
18730
|
+
try {
|
|
18731
|
+
resetCorruptWikiSearchIndex(path);
|
|
18732
|
+
return new WikiSearchIndex(path);
|
|
18733
|
+
} catch {
|
|
18734
|
+
return;
|
|
18735
|
+
}
|
|
18736
|
+
}
|
|
18737
|
+
}
|
|
18738
|
+
function prepareWikiSearchDocument(kind, key, text) {
|
|
18739
|
+
const titleLine = text.split(`
|
|
18740
|
+
`).find((line) => /^#+\s*/.test(line)) ?? "";
|
|
18741
|
+
const title = titleLine ? titleLine.replace(/^#+\s*/, "") : basename(key);
|
|
18742
|
+
return {
|
|
18743
|
+
title,
|
|
18744
|
+
text,
|
|
18745
|
+
tokens: canonicalSearchTokens(`${key} ${title} ${text}`),
|
|
18746
|
+
...kind === "summary" && /^\d{4}-\d{2}-\d{2}/.test(key) ? { date: key.slice(0, 10), family: summaryTopicIdentity(key) } : {}
|
|
18747
|
+
};
|
|
18748
|
+
}
|
|
18749
|
+
function indexWikiSearchDocument(kind, key, text) {
|
|
18750
|
+
const root = kind === "article" ? runtime().articlesDir : runtime().summariesDir;
|
|
18751
|
+
const path = resolve2(root, `${key}.md`);
|
|
18752
|
+
const index = openWikiSearchIndex();
|
|
18753
|
+
if (!index)
|
|
18754
|
+
return false;
|
|
18755
|
+
try {
|
|
18756
|
+
const stat = statSync(path);
|
|
18757
|
+
index.upsert({ kind, key, path, mtimeMs: stat.mtimeMs, size: stat.size }, prepareWikiSearchDocument(kind, key, text));
|
|
18758
|
+
return true;
|
|
18759
|
+
} catch {
|
|
18760
|
+
return false;
|
|
18761
|
+
} finally {
|
|
18762
|
+
index.close();
|
|
18763
|
+
}
|
|
18764
|
+
}
|
|
18765
|
+
var WIKI_INDEX_FILENAMES = {
|
|
18766
|
+
article: "article-index.md",
|
|
18767
|
+
summary: "summary-index.md",
|
|
18768
|
+
topic: "topic-index.md",
|
|
18769
|
+
skill: "skill-index.md"
|
|
18770
|
+
};
|
|
18771
|
+
var WIKI_INDEX_NAMESPACES = {
|
|
18772
|
+
article: "articles",
|
|
18773
|
+
summary: "summaries",
|
|
18774
|
+
topic: "topic",
|
|
18775
|
+
skill: "skills"
|
|
18776
|
+
};
|
|
18777
|
+
function wikiIndexPath(kind) {
|
|
18778
|
+
return resolve2(runtime().wikiDir, WIKI_INDEX_FILENAMES[kind]);
|
|
18779
|
+
}
|
|
18780
|
+
var MAX_INDEX_DESCRIPTION_LENGTH = 400;
|
|
18781
|
+
function normalizeIndexDescription(raw) {
|
|
18782
|
+
const description = raw.replaceAll(/\s+/g, " ").trim();
|
|
18783
|
+
if (!description)
|
|
18784
|
+
return { error: "A non-empty one-line description is required." };
|
|
18785
|
+
if (description.length > MAX_INDEX_DESCRIPTION_LENGTH) {
|
|
18786
|
+
return {
|
|
18787
|
+
error: `Description must be at most ${MAX_INDEX_DESCRIPTION_LENGTH} characters (got ${description.length}).`
|
|
18788
|
+
};
|
|
18789
|
+
}
|
|
18790
|
+
return { description };
|
|
18791
|
+
}
|
|
18792
|
+
function normalizeWikiSlug(raw) {
|
|
18793
|
+
const slug = raw.trim().replace(/\.md$/i, "").replace(/^\/+/, "");
|
|
18794
|
+
if (!slug)
|
|
18795
|
+
return { error: "A non-empty slug is required." };
|
|
18796
|
+
if (/[[\]|\\]/.test(slug))
|
|
18797
|
+
return { error: "Slug must not contain [ ] | or backslashes." };
|
|
18798
|
+
if (slug.split("/").some((segment) => segment === "" || segment === "." || segment === "..")) {
|
|
18799
|
+
return { error: "Slug must not contain empty or relative path segments." };
|
|
18800
|
+
}
|
|
18801
|
+
return { slug };
|
|
18802
|
+
}
|
|
18509
18803
|
function parseWikiIndex(path) {
|
|
18510
18804
|
let text;
|
|
18511
18805
|
try {
|
|
18512
|
-
text =
|
|
18806
|
+
text = readFileSync3(path, "utf-8");
|
|
18513
18807
|
} catch {
|
|
18514
18808
|
return [];
|
|
18515
18809
|
}
|
|
@@ -18663,7 +18957,7 @@ function wikiQuery(args) {
|
|
|
18663
18957
|
continue;
|
|
18664
18958
|
const fp = join2(sub, f.name);
|
|
18665
18959
|
try {
|
|
18666
|
-
const text =
|
|
18960
|
+
const text = readFileSync3(fp, "utf-8");
|
|
18667
18961
|
const key = `${entry.name}/${f.name.replace(/\.md$/i, "")}`;
|
|
18668
18962
|
scored.push({
|
|
18669
18963
|
kind: label === "articles" ? "article" : "skill",
|
|
@@ -18684,7 +18978,7 @@ function wikiQuery(args) {
|
|
|
18684
18978
|
}
|
|
18685
18979
|
const fp = join2(dir, entry.name);
|
|
18686
18980
|
try {
|
|
18687
|
-
const text =
|
|
18981
|
+
const text = readFileSync3(fp, "utf-8");
|
|
18688
18982
|
const key = entry.name.replace(/\.md$/i, "");
|
|
18689
18983
|
const resultKind = label === "articles" ? "article" : label === "topic" ? "topic" : label === "summaries" ? "summary" : "skill";
|
|
18690
18984
|
scored.push({
|
|
@@ -18798,14 +19092,45 @@ function wikiQuery(args) {
|
|
|
18798
19092
|
return 0;
|
|
18799
19093
|
return score;
|
|
18800
19094
|
}
|
|
18801
|
-
|
|
18802
|
-
|
|
19095
|
+
const bodyKinds = [
|
|
19096
|
+
...kind === "all" || kind === "article" ? ["article"] : [],
|
|
19097
|
+
...kind === "all" || kind === "summary" ? ["summary"] : []
|
|
19098
|
+
];
|
|
19099
|
+
if (bodyKinds.length > 0) {
|
|
19100
|
+
const searchIndex = openWikiSearchIndex();
|
|
19101
|
+
if (searchIndex) {
|
|
19102
|
+
try {
|
|
19103
|
+
const terms = canonicalSearchTokens(normalizedQuery);
|
|
19104
|
+
const ids = searchIndex.matchingDocumentIds(bodyKinds, terms);
|
|
19105
|
+
if (temporalDirection && bodyKinds.includes("summary")) {
|
|
19106
|
+
for (const item of searchIndex.summaryMetadataByDate({
|
|
19107
|
+
direction: temporalDirection === "newest" ? "latest" : "oldest",
|
|
19108
|
+
limit
|
|
19109
|
+
})) {
|
|
19110
|
+
ids.add(item.id);
|
|
19111
|
+
}
|
|
19112
|
+
}
|
|
19113
|
+
for (const document of searchIndex.documents(ids)) {
|
|
19114
|
+
scored.push({
|
|
19115
|
+
kind: document.kind,
|
|
19116
|
+
key: document.key,
|
|
19117
|
+
keyScore: scoreIndexKey(question, document.key),
|
|
19118
|
+
score: scoreMatch(document.text, document.key, document.kind),
|
|
19119
|
+
path: `${document.kind === "article" ? "articles" : "summaries"}/${document.key}.md`,
|
|
19120
|
+
text: document.text,
|
|
19121
|
+
title: document.title,
|
|
19122
|
+
...document.date ? { date: document.date } : {}
|
|
19123
|
+
});
|
|
19124
|
+
}
|
|
19125
|
+
} catch {} finally {
|
|
19126
|
+
searchIndex.close();
|
|
19127
|
+
}
|
|
19128
|
+
}
|
|
19129
|
+
}
|
|
18803
19130
|
if (kind === "all" && runtime().surface === "all")
|
|
18804
19131
|
scan(runtime().skillsDir, "skills");
|
|
18805
19132
|
if (kind === "all" || kind === "topic")
|
|
18806
19133
|
scan(runtime().topicsDir, "topic");
|
|
18807
|
-
if (kind === "all" || kind === "summary")
|
|
18808
|
-
scan(runtime().summariesDir, "summaries");
|
|
18809
19134
|
const merged = new Map;
|
|
18810
19135
|
for (const { candidate, keyScore, score } of indexCandidates) {
|
|
18811
19136
|
merged.set(`${candidate.kind}:${candidate.key}`, {
|
|
@@ -18937,7 +19262,7 @@ function wikiTopicBrief(args) {
|
|
|
18937
19262
|
const topicKey = wikiSummarySlug(rawTopic.replace(/^topic\//, "").replace(/\.md$/i, ""));
|
|
18938
19263
|
const filePath = resolve2(runtime().topicsDir, `${topicKey}.md`);
|
|
18939
19264
|
try {
|
|
18940
|
-
const content =
|
|
19265
|
+
const content = readFileSync3(filePath, "utf-8");
|
|
18941
19266
|
return {
|
|
18942
19267
|
content: [{ type: "text", text: `# Topic Brief: ${topicKey}
|
|
18943
19268
|
|
|
@@ -18989,7 +19314,7 @@ Adopted topic memory: ${memoryKey}` }]
|
|
|
18989
19314
|
return { content: [{ type: "text", text: "Invalid wiki document key." }], isError: true };
|
|
18990
19315
|
}
|
|
18991
19316
|
try {
|
|
18992
|
-
const content =
|
|
19317
|
+
const content = readFileSync3(filePath, "utf-8");
|
|
18993
19318
|
return {
|
|
18994
19319
|
content: [{ type: "text", text: `# Wiki ${kind}: ${key}
|
|
18995
19320
|
|
|
@@ -19009,18 +19334,18 @@ function wikiLastConversation(args) {
|
|
|
19009
19334
|
const name = slugify(topicNameFrom(rawTopic));
|
|
19010
19335
|
const archiveDir = resolve2(runtime().archiveDir, name);
|
|
19011
19336
|
try {
|
|
19012
|
-
let files =
|
|
19337
|
+
let files = existsSync3(archiveDir) ? readdirSync(archiveDir).filter((f) => f.endsWith(".jsonl")).sort().reverse() : [];
|
|
19013
19338
|
if (files.length === 0) {
|
|
19014
|
-
files =
|
|
19339
|
+
files = existsSync3(runtime().archiveDir) ? readdirSync(runtime().archiveDir).filter((f) => f.startsWith(name) && f.endsWith(".jsonl")).sort().reverse() : [];
|
|
19015
19340
|
}
|
|
19016
19341
|
if (files.length === 0) {
|
|
19017
19342
|
return {
|
|
19018
19343
|
content: [{ type: "text", text: `No archive found for topic: ${rawTopic}` }]
|
|
19019
19344
|
};
|
|
19020
19345
|
}
|
|
19021
|
-
const actualPath = files[0].includes("/") ? files[0] : resolve2(
|
|
19346
|
+
const actualPath = files[0].includes("/") ? files[0] : resolve2(existsSync3(archiveDir) && readdirSync(archiveDir).includes(files[0]) ? archiveDir : runtime().archiveDir, files[0]);
|
|
19022
19347
|
try {
|
|
19023
|
-
const raw =
|
|
19348
|
+
const raw = readFileSync3(actualPath, "utf-8");
|
|
19024
19349
|
const lines = raw.trim().split(`
|
|
19025
19350
|
`).filter(Boolean);
|
|
19026
19351
|
const turns2 = [];
|
|
@@ -19093,7 +19418,7 @@ function skillQuery(args) {
|
|
|
19093
19418
|
continue;
|
|
19094
19419
|
const skillFile = resolve2(runtime().skillsDir, entry.name, "skill.md");
|
|
19095
19420
|
try {
|
|
19096
|
-
const text =
|
|
19421
|
+
const text = readFileSync3(skillFile, "utf-8");
|
|
19097
19422
|
const lower = text.toLowerCase();
|
|
19098
19423
|
let score = 0;
|
|
19099
19424
|
for (const w of query.split(/\s+/).filter(Boolean)) {
|
|
@@ -19164,7 +19489,7 @@ ${fresh.join(`
|
|
|
19164
19489
|
const skillPath = resolve2(skillDir, "skill.md");
|
|
19165
19490
|
let finalContent = content;
|
|
19166
19491
|
try {
|
|
19167
|
-
const existing =
|
|
19492
|
+
const existing = readFileSync3(skillPath, "utf-8");
|
|
19168
19493
|
finalContent = mergeGotchas(content, extractGotchas(existing));
|
|
19169
19494
|
} catch {}
|
|
19170
19495
|
writeFileSync2(skillPath, finalContent, "utf-8");
|
|
@@ -19177,15 +19502,7 @@ ${fresh.join(`
|
|
|
19177
19502
|
]
|
|
19178
19503
|
};
|
|
19179
19504
|
}
|
|
19180
|
-
function
|
|
19181
|
-
const rawTopic = safeExt(args, ["topic", "topicName"], "");
|
|
19182
|
-
const content = safeExt(args, ["content", "text", "body"], "");
|
|
19183
|
-
if (!rawTopic)
|
|
19184
|
-
return { content: [{ type: "text", text: "Missing topic." }] };
|
|
19185
|
-
if (!content)
|
|
19186
|
-
return { content: [{ type: "text", text: "Missing content." }] };
|
|
19187
|
-
const now = new Date;
|
|
19188
|
-
const dateStr = now.toISOString().slice(0, 10);
|
|
19505
|
+
function writeSummaryDocument(rawTopic, content, dateStr) {
|
|
19189
19506
|
const topicId = runtime().topicId;
|
|
19190
19507
|
const fileSlug = wikiBriefStorageKey(rawTopic, topicId);
|
|
19191
19508
|
ensureDir(runtime().summariesDir);
|
|
@@ -19212,7 +19529,7 @@ function saveWikiEntry(args) {
|
|
|
19212
19529
|
if (topicId && setTopicBrief) {
|
|
19213
19530
|
try {
|
|
19214
19531
|
const briefPath = resolve2(runtime().topicsDir, `${fileSlug}.md`);
|
|
19215
|
-
let briefMd =
|
|
19532
|
+
let briefMd = existsSync3(briefPath) ? readFileSync3(briefPath, "utf-8") : undefined;
|
|
19216
19533
|
if (briefMd === undefined && getTopicBrief && !getTopicBrief(fileSlug)?.briefMd) {
|
|
19217
19534
|
const legacy = getTopicBrief(topicId)?.briefMd;
|
|
19218
19535
|
if (legacy)
|
|
@@ -19226,28 +19543,14 @@ function saveWikiEntry(args) {
|
|
|
19226
19543
|
sqliteUpdated = true;
|
|
19227
19544
|
} catch {}
|
|
19228
19545
|
}
|
|
19229
|
-
return {
|
|
19230
|
-
content: [
|
|
19231
|
-
{
|
|
19232
|
-
type: "text",
|
|
19233
|
-
text: `Saved summary: summaries/${summaryName}` + (sqliteUpdated ? `
|
|
19234
|
-
SQLite latest-summary also updated.` : "")
|
|
19235
|
-
}
|
|
19236
|
-
]
|
|
19237
|
-
};
|
|
19546
|
+
return { slug: summaryName.replace(/\.md$/i, ""), sqliteUpdated };
|
|
19238
19547
|
}
|
|
19239
|
-
function
|
|
19240
|
-
const rawTopic = safeExt(args, ["topic", "topicName"], "");
|
|
19241
|
-
const content = safeExt(args, ["content", "brief", "text", "body"], "");
|
|
19242
|
-
if (!rawTopic)
|
|
19243
|
-
return { content: [{ type: "text", text: "Missing topic." }] };
|
|
19244
|
-
if (!content)
|
|
19245
|
-
return { content: [{ type: "text", text: "Missing content." }] };
|
|
19548
|
+
function writeTopicDocument(rawTopic, content) {
|
|
19246
19549
|
const topicId = runtime().topicId;
|
|
19247
19550
|
const fileSlug = wikiBriefStorageKey(rawTopic, topicId);
|
|
19248
19551
|
const briefPath = resolve2(runtime().topicsDir, `${fileSlug}.md`);
|
|
19249
19552
|
ensureDir(dirname2(briefPath));
|
|
19250
|
-
const existed =
|
|
19553
|
+
const existed = existsSync3(briefPath);
|
|
19251
19554
|
writeFileSync2(briefPath, content, "utf-8");
|
|
19252
19555
|
const setTopicBrief = runtime().host.setTopicBrief;
|
|
19253
19556
|
let sqliteUpdated = false;
|
|
@@ -19257,68 +19560,228 @@ function saveTopicBrief(args) {
|
|
|
19257
19560
|
sqliteUpdated = true;
|
|
19258
19561
|
} catch {}
|
|
19259
19562
|
}
|
|
19563
|
+
return { slug: fileSlug, existed, sqliteUpdated };
|
|
19564
|
+
}
|
|
19565
|
+
function writeArticleDocument(slug, content) {
|
|
19566
|
+
const articlePath = resolve2(runtime().articlesDir, `${slug}.md`);
|
|
19567
|
+
ensureDir(dirname2(articlePath));
|
|
19568
|
+
const existed = existsSync3(articlePath);
|
|
19569
|
+
atomicWriteFile(articlePath, content);
|
|
19570
|
+
return { existed };
|
|
19571
|
+
}
|
|
19572
|
+
function wikiWrite(args) {
|
|
19573
|
+
const rawKind = safeExt(args, ["kind", "type"], "");
|
|
19574
|
+
const content = safeExt(args, ["content", "text", "body", "brief"], "");
|
|
19575
|
+
const rawDescription = safeExt(args, ["description", "desc"], "");
|
|
19576
|
+
const rawTopic = safeExt(args, ["topic", "topicName"], "");
|
|
19577
|
+
const rawSlug = safeExt(args, ["slug", "id"], "");
|
|
19578
|
+
const section = safeExt(args, ["section", "category"], undefined);
|
|
19579
|
+
const rawDate = safeExt(args, ["date", "created"], undefined);
|
|
19580
|
+
if (rawKind !== "summary" && rawKind !== "article" && rawKind !== "topic") {
|
|
19581
|
+
return {
|
|
19582
|
+
content: [{ type: "text", text: 'kind must be one of "summary", "article", "topic".' }],
|
|
19583
|
+
isError: true
|
|
19584
|
+
};
|
|
19585
|
+
}
|
|
19586
|
+
if (!content.trim()) {
|
|
19587
|
+
return { content: [{ type: "text", text: "Missing content." }], isError: true };
|
|
19588
|
+
}
|
|
19589
|
+
const descriptionResult = normalizeIndexDescription(rawDescription);
|
|
19590
|
+
if ("error" in descriptionResult) {
|
|
19591
|
+
return { content: [{ type: "text", text: descriptionResult.error }], isError: true };
|
|
19592
|
+
}
|
|
19593
|
+
const { description } = descriptionResult;
|
|
19594
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
19595
|
+
if (rawKind === "article") {
|
|
19596
|
+
const slugResult = normalizeWikiSlug(rawSlug);
|
|
19597
|
+
if ("error" in slugResult) {
|
|
19598
|
+
return { content: [{ type: "text", text: slugResult.error }], isError: true };
|
|
19599
|
+
}
|
|
19600
|
+
if (!section?.trim()) {
|
|
19601
|
+
return {
|
|
19602
|
+
content: [
|
|
19603
|
+
{ type: "text", text: "An article requires a section so the catalog stays navigable." }
|
|
19604
|
+
],
|
|
19605
|
+
isError: true
|
|
19606
|
+
};
|
|
19607
|
+
}
|
|
19608
|
+
const { existed } = writeArticleDocument(slugResult.slug, content);
|
|
19609
|
+
const link2 = indexRowOrPartialWrite("article", {
|
|
19610
|
+
kind: "article",
|
|
19611
|
+
slug: slugResult.slug,
|
|
19612
|
+
description,
|
|
19613
|
+
date: rawDate ?? today,
|
|
19614
|
+
section: section.trim()
|
|
19615
|
+
});
|
|
19616
|
+
if (typeof link2 !== "string")
|
|
19617
|
+
return link2;
|
|
19618
|
+
const searched = indexWikiSearchDocument("article", slugResult.slug, content);
|
|
19619
|
+
return {
|
|
19620
|
+
content: [
|
|
19621
|
+
{
|
|
19622
|
+
type: "text",
|
|
19623
|
+
text: `Saved article: articles/${slugResult.slug}.md (${existed ? "updated" : "created"})
|
|
19624
|
+
Indexed: ${link2}` + (searched ? "" : `
|
|
19625
|
+
${SEARCH_CACHE_SKIPPED_NOTE}`)
|
|
19626
|
+
}
|
|
19627
|
+
]
|
|
19628
|
+
};
|
|
19629
|
+
}
|
|
19630
|
+
const topic = rawTopic.trim();
|
|
19631
|
+
if (!topic) {
|
|
19632
|
+
return { content: [{ type: "text", text: "Missing topic." }], isError: true };
|
|
19633
|
+
}
|
|
19634
|
+
if (rawKind === "summary") {
|
|
19635
|
+
const dateStr = rawDate ?? today;
|
|
19636
|
+
const written2 = writeSummaryDocument(topic, content, dateStr);
|
|
19637
|
+
const link2 = indexRowOrPartialWrite("summary", {
|
|
19638
|
+
kind: "summary",
|
|
19639
|
+
slug: written2.slug,
|
|
19640
|
+
description,
|
|
19641
|
+
date: dateStr
|
|
19642
|
+
});
|
|
19643
|
+
if (typeof link2 !== "string")
|
|
19644
|
+
return link2;
|
|
19645
|
+
const searched = indexWikiSearchDocument("summary", written2.slug, content);
|
|
19646
|
+
return {
|
|
19647
|
+
content: [
|
|
19648
|
+
{
|
|
19649
|
+
type: "text",
|
|
19650
|
+
text: `Saved summary: summaries/${written2.slug}.md
|
|
19651
|
+
Indexed: ${link2}` + (written2.sqliteUpdated ? `
|
|
19652
|
+
SQLite latest-summary also updated.` : "") + (searched ? "" : `
|
|
19653
|
+
${SEARCH_CACHE_SKIPPED_NOTE}`)
|
|
19654
|
+
}
|
|
19655
|
+
]
|
|
19656
|
+
};
|
|
19657
|
+
}
|
|
19658
|
+
const written = writeTopicDocument(topic, content);
|
|
19659
|
+
const link = indexRowOrPartialWrite("topic", {
|
|
19660
|
+
kind: "topic",
|
|
19661
|
+
slug: written.slug,
|
|
19662
|
+
description,
|
|
19663
|
+
date: rawDate ?? today
|
|
19664
|
+
});
|
|
19665
|
+
if (typeof link !== "string")
|
|
19666
|
+
return link;
|
|
19260
19667
|
return {
|
|
19261
19668
|
content: [
|
|
19262
19669
|
{
|
|
19263
19670
|
type: "text",
|
|
19264
|
-
text: `Saved brief: topic/${
|
|
19671
|
+
text: `Saved brief: topic/${written.slug}.md (${written.existed ? "updated" : "created"})
|
|
19672
|
+
Indexed: ${link}` + (written.sqliteUpdated ? `
|
|
19265
19673
|
SQLite brief also updated.` : "")
|
|
19266
19674
|
}
|
|
19267
19675
|
]
|
|
19268
19676
|
};
|
|
19269
19677
|
}
|
|
19270
|
-
function
|
|
19271
|
-
const
|
|
19272
|
-
|
|
19273
|
-
|
|
19274
|
-
|
|
19275
|
-
|
|
19276
|
-
|
|
19277
|
-
|
|
19278
|
-
|
|
19279
|
-
|
|
19280
|
-
const
|
|
19281
|
-
|
|
19282
|
-
|
|
19283
|
-
|
|
19284
|
-
|
|
19285
|
-
|
|
19286
|
-
|
|
19678
|
+
function collectIndexableDocuments() {
|
|
19679
|
+
const sources = [];
|
|
19680
|
+
function add(kind, key, path) {
|
|
19681
|
+
try {
|
|
19682
|
+
const stat = statSync(path);
|
|
19683
|
+
if (!stat.isFile())
|
|
19684
|
+
return;
|
|
19685
|
+
sources.push({ kind, key, path, mtimeMs: stat.mtimeMs, size: stat.size });
|
|
19686
|
+
} catch {}
|
|
19687
|
+
}
|
|
19688
|
+
for (const [root, kind, allowSubdirectories] of [
|
|
19689
|
+
[runtime().articlesDir, "article", true],
|
|
19690
|
+
[runtime().summariesDir, "summary", false]
|
|
19691
|
+
]) {
|
|
19692
|
+
let entries;
|
|
19693
|
+
try {
|
|
19694
|
+
entries = readdirSync(root, { withFileTypes: true });
|
|
19695
|
+
} catch {
|
|
19696
|
+
continue;
|
|
19697
|
+
}
|
|
19698
|
+
for (const entry of entries) {
|
|
19699
|
+
if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
19700
|
+
add(kind, entry.name.replace(/\.md$/i, ""), join2(root, entry.name));
|
|
19701
|
+
continue;
|
|
19702
|
+
}
|
|
19703
|
+
if (!entry.isDirectory() || !allowSubdirectories)
|
|
19704
|
+
continue;
|
|
19705
|
+
let nested;
|
|
19706
|
+
try {
|
|
19707
|
+
nested = readdirSync(join2(root, entry.name), { withFileTypes: true });
|
|
19708
|
+
} catch {
|
|
19709
|
+
continue;
|
|
19710
|
+
}
|
|
19711
|
+
for (const file of nested) {
|
|
19712
|
+
if (!file.isFile() || !file.name.endsWith(".md"))
|
|
19713
|
+
continue;
|
|
19714
|
+
add(kind, `${entry.name}/${file.name.replace(/\.md$/i, "")}`, join2(root, entry.name, file.name));
|
|
19715
|
+
}
|
|
19716
|
+
}
|
|
19717
|
+
}
|
|
19718
|
+
return sources;
|
|
19719
|
+
}
|
|
19720
|
+
function wikiReindex() {
|
|
19721
|
+
const documents = collectIndexableDocuments();
|
|
19722
|
+
const index = openWikiSearchIndex();
|
|
19723
|
+
if (!index) {
|
|
19724
|
+
return {
|
|
19725
|
+
content: [{ type: "text", text: "Could not open the wiki search index." }],
|
|
19726
|
+
isError: true
|
|
19727
|
+
};
|
|
19728
|
+
}
|
|
19729
|
+
let synced;
|
|
19730
|
+
try {
|
|
19731
|
+
synced = index.sync(documents, (source, text) => prepareWikiSearchDocument(source.kind, source.key, text));
|
|
19732
|
+
} catch (error) {
|
|
19733
|
+
return {
|
|
19734
|
+
content: [{ type: "text", text: `Failed to rebuild the search index: ${String(error)}` }],
|
|
19735
|
+
isError: true
|
|
19736
|
+
};
|
|
19737
|
+
} finally {
|
|
19738
|
+
index.close();
|
|
19739
|
+
}
|
|
19740
|
+
const lines = [
|
|
19741
|
+
`Search index: ${synced.added} added, ${synced.updated} updated, ${synced.removed} removed (${documents.length} documents).`
|
|
19742
|
+
];
|
|
19743
|
+
for (const kind of ["article", "summary"]) {
|
|
19744
|
+
const rows = new Set(parseWikiIndex(wikiIndexPath(kind)).filter((candidate) => candidate.kind === kind).map((candidate) => candidate.key));
|
|
19745
|
+
const keys = documents.filter((source) => source.kind === kind).map((source) => source.key);
|
|
19746
|
+
const unindexed = keys.filter((key) => !rows.has(key));
|
|
19747
|
+
const tombstones = [...rows].filter((key) => !keys.includes(key));
|
|
19748
|
+
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(", ")}` : ""));
|
|
19749
|
+
}
|
|
19750
|
+
return { content: [{ type: "text", text: lines.join(`
|
|
19751
|
+
`) }] };
|
|
19752
|
+
}
|
|
19753
|
+
var SEARCH_CACHE_SKIPPED_NOTE = "Body-search cache was not updated; catalog retrieval still works. Run wiki_reindex to refill it.";
|
|
19754
|
+
function indexRowOrPartialWrite(label, options) {
|
|
19755
|
+
try {
|
|
19756
|
+
return upsertIndexRow(options);
|
|
19757
|
+
} catch (error) {
|
|
19758
|
+
return {
|
|
19759
|
+
content: [
|
|
19760
|
+
{
|
|
19761
|
+
type: "text",
|
|
19762
|
+
text: `Wrote the ${label} document but failed to index it (${String(error)}). Retry the same wiki_write call: both writes are idempotent.`
|
|
19763
|
+
}
|
|
19764
|
+
],
|
|
19765
|
+
isError: true
|
|
19766
|
+
};
|
|
19767
|
+
}
|
|
19768
|
+
}
|
|
19769
|
+
function upsertIndexRow(options) {
|
|
19770
|
+
const { kind, slug, description, date, section } = options;
|
|
19771
|
+
const indexPath = wikiIndexPath(kind);
|
|
19287
19772
|
ensureDir(dirname2(indexPath));
|
|
19288
19773
|
const releaseLock = acquireFileLock(indexPath);
|
|
19289
19774
|
try {
|
|
19290
19775
|
let index;
|
|
19291
19776
|
try {
|
|
19292
|
-
index =
|
|
19777
|
+
index = readFileSync3(indexPath, "utf-8");
|
|
19293
19778
|
} catch {
|
|
19294
19779
|
index = "";
|
|
19295
19780
|
}
|
|
19296
19781
|
const lines = index.split(`
|
|
19297
19782
|
`);
|
|
19298
|
-
const
|
|
19299
|
-
|
|
19300
|
-
case "summary":
|
|
19301
|
-
return `- [[summaries/${slug}]] ${desc} (${dateStr})`;
|
|
19302
|
-
case "topic":
|
|
19303
|
-
return `- [[topic/${slug}]] ${desc} (${dateStr})`;
|
|
19304
|
-
case "skill":
|
|
19305
|
-
return `- [[skills/${slug}]] ${desc} (${dateStr})`;
|
|
19306
|
-
default:
|
|
19307
|
-
return `- [[articles/${slug}]] ${desc} (${dateStr})`;
|
|
19308
|
-
}
|
|
19309
|
-
})();
|
|
19310
|
-
const target = (() => {
|
|
19311
|
-
switch (kind) {
|
|
19312
|
-
case "summary":
|
|
19313
|
-
return `summaries/${slug}`;
|
|
19314
|
-
case "topic":
|
|
19315
|
-
return `topic/${slug}`;
|
|
19316
|
-
case "skill":
|
|
19317
|
-
return `skills/${slug}`;
|
|
19318
|
-
default:
|
|
19319
|
-
return `articles/${slug}`;
|
|
19320
|
-
}
|
|
19321
|
-
})();
|
|
19783
|
+
const target = `${WIKI_INDEX_NAMESPACES[kind]}/${slug}`;
|
|
19784
|
+
const link = `- [[${target}]] ${description} (${date})`;
|
|
19322
19785
|
const slugPattern = `[[${target}]]`;
|
|
19323
19786
|
let replaced = false;
|
|
19324
19787
|
for (let i = lines.length - 1;i >= 0; i--) {
|
|
@@ -19356,11 +19819,63 @@ function indexUpsert(args) {
|
|
|
19356
19819
|
}
|
|
19357
19820
|
atomicWriteFile(indexPath, lines.join(`
|
|
19358
19821
|
`));
|
|
19359
|
-
return
|
|
19822
|
+
return link;
|
|
19360
19823
|
} finally {
|
|
19361
19824
|
releaseLock();
|
|
19362
19825
|
}
|
|
19363
19826
|
}
|
|
19827
|
+
function wikiDocumentExists(kind, slug) {
|
|
19828
|
+
const root = kind === "article" ? runtime().articlesDir : kind === "summary" ? runtime().summariesDir : kind === "topic" ? runtime().topicsDir : runtime().skillsDir;
|
|
19829
|
+
const filePath = resolve2(root, `${slug}.md`);
|
|
19830
|
+
if (relative(root, filePath).startsWith(".."))
|
|
19831
|
+
return false;
|
|
19832
|
+
try {
|
|
19833
|
+
return statSync(filePath).isFile();
|
|
19834
|
+
} catch {
|
|
19835
|
+
return false;
|
|
19836
|
+
}
|
|
19837
|
+
}
|
|
19838
|
+
function indexUpsert(args) {
|
|
19839
|
+
const rawSlug = safeExt(args, ["slug", "id"], "");
|
|
19840
|
+
const rawDescription = safeExt(args, ["description", "desc", "text"], "");
|
|
19841
|
+
const rawKind = safeExt(args, ["kind", "type"], "article");
|
|
19842
|
+
const section = safeExt(args, ["section", "category"], undefined);
|
|
19843
|
+
const date = safeExt(args, ["date", "created"], undefined);
|
|
19844
|
+
if (!(rawKind in WIKI_INDEX_FILENAMES)) {
|
|
19845
|
+
return {
|
|
19846
|
+
content: [{ type: "text", text: `Unsupported kind: ${rawKind}` }],
|
|
19847
|
+
isError: true
|
|
19848
|
+
};
|
|
19849
|
+
}
|
|
19850
|
+
const kind = rawKind;
|
|
19851
|
+
const slugResult = normalizeWikiSlug(rawSlug);
|
|
19852
|
+
if ("error" in slugResult) {
|
|
19853
|
+
return { content: [{ type: "text", text: slugResult.error }], isError: true };
|
|
19854
|
+
}
|
|
19855
|
+
const descriptionResult = normalizeIndexDescription(rawDescription);
|
|
19856
|
+
if ("error" in descriptionResult) {
|
|
19857
|
+
return { content: [{ type: "text", text: descriptionResult.error }], isError: true };
|
|
19858
|
+
}
|
|
19859
|
+
if (kind !== "topic" && !wikiDocumentExists(kind, slugResult.slug)) {
|
|
19860
|
+
return {
|
|
19861
|
+
content: [
|
|
19862
|
+
{
|
|
19863
|
+
type: "text",
|
|
19864
|
+
text: `No ${kind} document named ${slugResult.slug}. Use wiki_write to create the document and its catalog row together.`
|
|
19865
|
+
}
|
|
19866
|
+
],
|
|
19867
|
+
isError: true
|
|
19868
|
+
};
|
|
19869
|
+
}
|
|
19870
|
+
const link = upsertIndexRow({
|
|
19871
|
+
kind,
|
|
19872
|
+
slug: slugResult.slug,
|
|
19873
|
+
description: descriptionResult.description,
|
|
19874
|
+
date: date ?? new Date().toISOString().slice(0, 10),
|
|
19875
|
+
section
|
|
19876
|
+
});
|
|
19877
|
+
return { content: [{ type: "text", text: `Index updated: ${link}` }] };
|
|
19878
|
+
}
|
|
19364
19879
|
var WIKI_TOOLS = [
|
|
19365
19880
|
{
|
|
19366
19881
|
name: "wiki_query",
|
|
@@ -19442,35 +19957,46 @@ var WIKI_TOOLS = [
|
|
|
19442
19957
|
}
|
|
19443
19958
|
},
|
|
19444
19959
|
{
|
|
19445
|
-
name: "
|
|
19446
|
-
description: "
|
|
19960
|
+
name: "wiki_write",
|
|
19961
|
+
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.",
|
|
19447
19962
|
inputSchema: {
|
|
19448
19963
|
type: "object",
|
|
19449
19964
|
properties: {
|
|
19450
|
-
|
|
19451
|
-
|
|
19965
|
+
kind: {
|
|
19966
|
+
type: "string",
|
|
19967
|
+
enum: ["summary", "article", "topic"],
|
|
19968
|
+
description: "Which document to write"
|
|
19969
|
+
},
|
|
19970
|
+
content: { type: "string", description: "Document body in markdown" },
|
|
19971
|
+
description: {
|
|
19972
|
+
type: "string",
|
|
19973
|
+
description: "Single-line catalog description; required so the index stays useful"
|
|
19974
|
+
},
|
|
19975
|
+
topic: {
|
|
19976
|
+
type: "string",
|
|
19977
|
+
description: "Topic name; required for kind=summary and kind=topic"
|
|
19978
|
+
},
|
|
19979
|
+
slug: {
|
|
19980
|
+
type: "string",
|
|
19981
|
+
description: "Article slug in kebab-case; required for kind=article"
|
|
19982
|
+
},
|
|
19983
|
+
section: {
|
|
19984
|
+
type: "string",
|
|
19985
|
+
description: "H2 catalog section; required for kind=article"
|
|
19986
|
+
},
|
|
19987
|
+
date: { type: "string", description: "Override entry date YYYY-MM-DD (default: today)" }
|
|
19452
19988
|
},
|
|
19453
|
-
required: ["
|
|
19989
|
+
required: ["kind", "content", "description"]
|
|
19454
19990
|
}
|
|
19455
19991
|
},
|
|
19456
19992
|
{
|
|
19457
|
-
name: "
|
|
19458
|
-
description: "
|
|
19459
|
-
inputSchema: {
|
|
19460
|
-
type: "object",
|
|
19461
|
-
properties: {
|
|
19462
|
-
topic: { type: "string", description: "Topic name of the session" },
|
|
19463
|
-
content: {
|
|
19464
|
-
type: "string",
|
|
19465
|
-
description: "Full accumulated topic brief in markdown (persona layer + recent work)"
|
|
19466
|
-
}
|
|
19467
|
-
},
|
|
19468
|
-
required: ["topic", "content"]
|
|
19469
|
-
}
|
|
19993
|
+
name: "wiki_reindex",
|
|
19994
|
+
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.",
|
|
19995
|
+
inputSchema: { type: "object", properties: {} }
|
|
19470
19996
|
},
|
|
19471
19997
|
{
|
|
19472
19998
|
name: "index_upsert",
|
|
19473
|
-
description: "
|
|
19999
|
+
description: "Correct the description or section of an entry that already exists. Cannot create an entry \u2014 use wiki_write for that.",
|
|
19474
20000
|
inputSchema: {
|
|
19475
20001
|
type: "object",
|
|
19476
20002
|
properties: {
|
|
@@ -19574,8 +20100,8 @@ function createWikiMcpServer(context, host) {
|
|
|
19574
20100
|
wiki_last_conversation: wikiLastConversation,
|
|
19575
20101
|
skill_query: skillQuery,
|
|
19576
20102
|
skill_save: skillSave,
|
|
19577
|
-
|
|
19578
|
-
|
|
20103
|
+
wiki_write: wikiWrite,
|
|
20104
|
+
wiki_reindex: wikiReindex,
|
|
19579
20105
|
index_upsert: indexUpsert
|
|
19580
20106
|
};
|
|
19581
20107
|
const handler = tools.some((tool) => tool.name === name) ? handlers[name] : undefined;
|
|
@@ -19593,7 +20119,7 @@ init_jsonl();
|
|
|
19593
20119
|
init_mcp_helpers();
|
|
19594
20120
|
await init_codex_registry();
|
|
19595
20121
|
import { spawn as spawn5 } from "child_process";
|
|
19596
|
-
import { existsSync as
|
|
20122
|
+
import { existsSync as existsSync10, readdirSync as readdirSync3 } from "fs";
|
|
19597
20123
|
import { join as join10 } from "path";
|
|
19598
20124
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
19599
20125
|
import { z } from "zod";
|
|
@@ -19848,7 +20374,7 @@ ${results.every((result) => result.ok) ? "All agents healthy" : "Some agents fai
|
|
|
19848
20374
|
if (!context.userId)
|
|
19849
20375
|
return mcpOk("\uC2E4\uD589 \uC911\uC778 \uCFFC\uB9AC \uC870\uD68C \uBD88\uAC00 (user context \uC5C6\uC74C)");
|
|
19850
20376
|
const stateDir = join10(USERS_LOG_DIR, context.userId, "active-queries");
|
|
19851
|
-
if (!
|
|
20377
|
+
if (!existsSync10(stateDir))
|
|
19852
20378
|
return mcpOk("\uC2E4\uD589 \uC911\uC778 \uCFFC\uB9AC \uC5C6\uC74C");
|
|
19853
20379
|
let files;
|
|
19854
20380
|
try {
|
|
@@ -19885,7 +20411,7 @@ ${lines.join(`
|
|
|
19885
20411
|
}
|
|
19886
20412
|
// ../../packages/core/src/mcp/factories/compaction-log.ts
|
|
19887
20413
|
init_mcp_helpers();
|
|
19888
|
-
import { readFileSync as
|
|
20414
|
+
import { readFileSync as readFileSync9, realpathSync as realpathSync3 } from "fs";
|
|
19889
20415
|
import { McpServer as McpServer2 } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
19890
20416
|
import { z as z2 } from "zod";
|
|
19891
20417
|
var DEFAULT_MAX_CALLS = 12;
|
|
@@ -19918,7 +20444,7 @@ function createCompactionLogMcpServer(context) {
|
|
|
19918
20444
|
if (!context.filePath)
|
|
19919
20445
|
throw new Error("compaction-log MCP requires filePath");
|
|
19920
20446
|
const filePath = realpathSync3(context.filePath);
|
|
19921
|
-
const lines =
|
|
20447
|
+
const lines = readFileSync9(filePath, "utf8").split(`
|
|
19922
20448
|
`);
|
|
19923
20449
|
const maxCalls = positiveInt(context.maxCalls, DEFAULT_MAX_CALLS);
|
|
19924
20450
|
const maxTotalBytes = positiveInt(context.maxTotalBytes, DEFAULT_MAX_TOTAL_BYTES);
|
|
@@ -20511,4 +21037,4 @@ export {
|
|
|
20511
21037
|
createAgentHealthMcpServer
|
|
20512
21038
|
};
|
|
20513
21039
|
|
|
20514
|
-
//# debugId=
|
|
21040
|
+
//# debugId=1EA78260283E3CD164756E2164756E21
|