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.
@@ -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 (existsSync(resolve(packagedRuntime, "src")))
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 (existsSync(candidate))
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
- chmodSync(secretFile, 384);
271
+ chmodSync2(secretFile, 384);
219
272
  }
220
273
  return envValue;
221
274
  }
222
- if (existsSync(secretFile)) {
223
- const stored = readFileSync(secretFile, "utf-8").trim();
275
+ if (existsSync2(secretFile)) {
276
+ const stored = readFileSync2(secretFile, "utf-8").trim();
224
277
  if (stored) {
225
- chmodSync(secretFile, 384);
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 = readFileSync(secretFile, "utf-8").trim();
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
- chmodSync(secretFile, 384);
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 unlinkSync2 } from "fs";
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: unlinkSync2,
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 readFileSync3,
657
+ readFileSync as readFileSync4,
605
658
  renameSync as renameSync2,
606
659
  statSync as statSync2,
607
- unlinkSync as unlinkSync3,
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 readFileSync3(filePath, "utf-8").trim().split(`
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(readFileSync3(filePath, "utf-8"));
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
- unlinkSync3(tmpPath);
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 existsSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "fs";
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 = readFileSync4(join3(FIXTURES_DIR, "claude-attachments.jsonl"), "utf8");
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 existsSync4, mkdirSync as mkdirSync5, readdirSync as readdirSync2, renameSync as renameSync3, unlinkSync as unlinkSync4 } from "fs";
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 (!existsSync4(destPath)) {
921
- const sourcePath = readdirSync2(projectsRoot).map((d) => join4(projectsRoot, d, `${result.sessionId}.jsonl`)).find((p) => existsSync4(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
- unlinkSync4(path);
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.18";
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 chmodSync2,
1014
+ chmodSync as chmodSync3,
962
1015
  copyFileSync,
963
- existsSync as existsSync5,
1016
+ existsSync as existsSync6,
964
1017
  mkdtempSync,
965
- readFileSync as readFileSync5,
1018
+ readFileSync as readFileSync6,
966
1019
  renameSync as renameSync4,
967
1020
  rmSync,
968
- unlinkSync as unlinkSync5,
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(readFileSync5(packageJsonPath, "utf8"));
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 = readFileSync5(cachePath, "utf8");
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 (existsSync5(path) && readFileSync5(path, "utf8") === contents)
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
- chmodSync2(path, 384);
1068
+ chmodSync3(path, 384);
1016
1069
  } finally {
1017
1070
  try {
1018
- unlinkSync5(tempPath);
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 (!existsSync5(cachePath))
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
- chmodSync2(isolatedAuthPath, 384);
1167
+ chmodSync3(isolatedAuthPath, 384);
1115
1168
  const sourceConfigPath = join5(sourceHome, "config.toml");
1116
- if (existsSync5(sourceConfigPath)) {
1169
+ if (existsSync6(sourceConfigPath)) {
1117
1170
  const isolatedConfigPath = join5(isolatedHome, "config.toml");
1118
1171
  copyFileSync(sourceConfigPath, isolatedConfigPath);
1119
- chmodSync2(isolatedConfigPath, 384);
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 (!existsSync5(configuredCachePath)) {
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 (existsSync5(sharedCachePath)) {
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 (existsSync5(bundledCachePath)) {
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 chmodSync3, mkdirSync as mkdirSync6 } from "fs";
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
- chmodSync3(path, 384);
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 existsSync6, readFileSync as readFileSync6, realpathSync as realpathSync2, statSync as statSync3, unlinkSync as unlinkSync6 } from "fs";
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 = readFileSync6(join7(FIXTURES_DIR, "codex-shell.jsonl"), "utf8");
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(readFileSync6(path, "utf8"));
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(readFileSync6(path, "utf8"), expectedPaths, consumedCallIds, expectedCallId);
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(readFileSync6(path, "utf8"));
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(readFileSync6(path, "utf8"));
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(readFileSync6(path, "utf8"));
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 (!existsSync6(dir))
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 (!existsSync6(dir))
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
- unlinkSync6(fullPath);
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
- unlinkSync6(fullPath);
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 existsSync7, unlinkSync as unlinkSync7 } from "fs";
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 (!existsSync7(sessionsDir))
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
- unlinkSync7(path);
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 existsSync8, mkdirSync as mkdirSync7, readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "fs";
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 (!existsSync8(path))
3242
+ if (!existsSync9(path))
3243
3243
  return;
3244
3244
  try {
3245
- const firstLine = readFileSync7(path, "utf8").split(`
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 = existsSync8(maestroActiveSessionPath(options.parentSessionId));
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
- ...existsSync8(activePath) ? { cleanupPaths: [activePath] } : {}
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(existsSync8);
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 existsSync10, unlinkSync as unlinkSync8 } from "fs";
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: existsSync10,
5145
- unlink: unlinkSync8,
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 unlinkSync9 } from "fs";
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
- unlinkSync9(resolve8(userDataDir, f));
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 chmodSync4 } from "fs";
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
- chmodSync4(socketPath, 384);
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 existsSync11,
6118
+ existsSync as existsSync12,
6119
6119
  mkdirSync as mkdirSync9,
6120
- readFileSync as readFileSync9,
6120
+ readFileSync as readFileSync10,
6121
6121
  rmSync as rmSync2,
6122
- unlinkSync as unlinkSync10,
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 = existsSync11(target);
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
- unlinkSync10(join13(managerHost.portsDir, portFileName(instanceKey)));
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 (!existsSync11(srcDir)) {
6707
+ if (!existsSync12(srcDir)) {
6708
6708
  return { copied: false, srcDir, dstDir, reason: "src-missing" };
6709
6709
  }
6710
6710
  try {
6711
- if (existsSync11(dstDir)) {
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
- unlinkSync10(resolve10(dstDir, f));
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 existsSync12,
7280
+ existsSync as existsSync13,
7281
7281
  mkdirSync as mkdirSync10,
7282
- readFileSync as readFileSync10,
7282
+ readFileSync as readFileSync11,
7283
7283
  renameSync as renameSync5,
7284
- unlinkSync as unlinkSync11,
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 existsSync12(getActiveConversationPath(userId, topicName));
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 (existsSync12(activePath)) {
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 (!existsSync12(path))
7335
+ if (!existsSync13(path))
7336
7336
  return out;
7337
7337
  let raw;
7338
7338
  try {
7339
- raw = readFileSync10(path, "utf8");
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(existsSync12(activePath) ? activePath : getConversationPath(userId, topicName));
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
- unlinkSync11(tempPath);
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 existsSync13, mkdirSync as mkdirSync11, readFileSync as readFileSync11, renameSync as renameSync6, statSync as statSync4, writeFileSync as writeFileSync9 } from "fs";
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 (!existsSync13(path))
7533
+ if (!existsSync14(path))
7534
7534
  return [];
7535
7535
  try {
7536
- const parsed = JSON.parse(readFileSync11(path, "utf-8"));
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 existsSync14, readFileSync as readFileSync12 } from "fs";
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: readFileSync12(attachment.path).toString("base64")
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 && !existsSync14(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 readFileSync13, statSync as statSync5 } from "fs";
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 = readFileSync13(path, "utf8").replace(/\r\n?/g, `
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 existsSync15, readFileSync as readFileSync14, realpathSync as realpathSync4, statSync as statSync6 } from "fs";
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 (!existsSync15(configPath))
9046
+ if (!existsSync16(configPath))
9047
9047
  return [];
9048
9048
  try {
9049
9049
  const names = new Set;
9050
- for (const line of readFileSync14(configPath, "utf8").split(`
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 (!existsSync15(path))
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 = readFileSync14(path);
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 (!existsSync15(codexAuthPath)) {
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: existsSync15(opts.cwd),
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 existsSync16 } from "fs";
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 !existsSync16(path);
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 !existsSync16(maestroSessionPath2(sessionId)) && !hasActiveMaestroSession(sessionId);
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 readFileSync15 } from "fs";
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 = readFileSync15(resolve14(dir, filename), "utf-8");
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 = readFileSync15(resolve14(AGENTS_PROMPTS_DIR, filename), "utf-8");
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 existsSync17, readdirSync as readdirSync5, readFileSync as readFileSync16, statSync as statSync7 } from "fs";
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: existsSync17,
10768
+ fileExists: existsSync18,
10769
10769
  listDirectory: readdirSync5,
10770
- readTextFile: (path) => readFileSync16(path, "utf-8"),
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 unlinkSync12, writeFileSync as writeFileSync11 } from "fs";
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
- unlinkSync12(tempPath);
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
- unlinkSync12(path);
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 unlinkSync13 } from "fs";
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
- unlinkSync13(path);
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 unlinkSync14 } from "fs";
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
- unlinkSync14(path);
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 unlinkSync15, writeFileSync as writeFileSync13 } from "fs";
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
- unlinkSync15(path);
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 readFileSync17,
12527
+ readFileSync as readFileSync18,
12528
12528
  statSync as statSync8,
12529
- unlinkSync as unlinkSync16,
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 = readFileSync17(path, "utf8").trim();
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
- unlinkSync16(compatibilityPath);
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
- unlinkSync16(migrated.path);
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
- unlinkSync16(path);
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
- unlinkSync16(pending.path);
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
- unlinkSync16(path);
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
- unlinkSync16(path);
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
- unlinkSync16(path);
12814
+ unlinkSync17(path);
12815
12815
  } catch {}
12816
12816
  }
12817
12817
  if (isStale(canonical.record, canonical.path)) {
12818
12818
  try {
12819
- unlinkSync16(canonical.path);
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
- unlinkSync16(path);
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 existsSync18, mkdirSync as mkdirSync19, readFileSync as readFileSync18, writeFileSync as writeFileSync16 } from "fs";
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 (existsSync18(path)) {
15522
- const data = JSON.parse(readFileSync18(path, "utf8"));
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 existsSync19, mkdirSync as mkdirSync20, readdirSync as readdirSync7, statSync as statSync10 } from "fs";
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 && existsSync19(preferred))
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 = existsSync19(briefFile) && statSync10(briefFile).isFile();
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 = existsSync19(latestSummaryCandidate) && statSync10(latestSummaryCandidate).isFile() ? latestSummaryCandidate : null;
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 existsSync20 } from "fs";
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: existsSync20,
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 existsSync2,
18199
+ existsSync as existsSync3,
18200
18200
  mkdirSync as mkdirSync2,
18201
18201
  openSync,
18202
18202
  readdirSync,
18203
- readFileSync as readFileSync2,
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
- unlinkSync(guardPath);
18457
+ unlinkSync2(guardPath);
18245
18458
  } catch {}
18246
18459
  throw error;
18247
18460
  }
18248
18461
  return () => {
18249
18462
  closeSync(fd);
18250
18463
  try {
18251
- if (readFileSync2(guardPath, "utf-8") === ownerToken)
18252
- unlinkSync(guardPath);
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
- unlinkSync(lockPath);
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 (readFileSync2(lockPath, "utf-8") === ownerToken)
18286
- unlinkSync(lockPath);
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 = readFileSync2(lockPath, "utf-8");
18298
- if (Date.now() - statSync(lockPath).mtimeMs > FILE_LOCK_STALE_MS && readFileSync2(lockPath, "utf-8") === staleToken) {
18299
- unlinkSync(lockPath);
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
- unlinkSync(temporaryPath);
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 = readFileSync2(path, "utf-8");
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 = readFileSync2(fp, "utf-8");
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 = readFileSync2(fp, "utf-8");
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
- if (kind === "all" || kind === "article")
18802
- scan(runtime().articlesDir, "articles");
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 = readFileSync2(filePath, "utf-8");
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 = readFileSync2(filePath, "utf-8");
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 = existsSync2(archiveDir) ? readdirSync(archiveDir).filter((f) => f.endsWith(".jsonl")).sort().reverse() : [];
19337
+ let files = existsSync3(archiveDir) ? readdirSync(archiveDir).filter((f) => f.endsWith(".jsonl")).sort().reverse() : [];
19013
19338
  if (files.length === 0) {
19014
- files = existsSync2(runtime().archiveDir) ? readdirSync(runtime().archiveDir).filter((f) => f.startsWith(name) && f.endsWith(".jsonl")).sort().reverse() : [];
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(existsSync2(archiveDir) && readdirSync(archiveDir).includes(files[0]) ? archiveDir : runtime().archiveDir, files[0]);
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 = readFileSync2(actualPath, "utf-8");
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 = readFileSync2(skillFile, "utf-8");
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 = readFileSync2(skillPath, "utf-8");
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 saveWikiEntry(args) {
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 = existsSync2(briefPath) ? readFileSync2(briefPath, "utf-8") : undefined;
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 saveTopicBrief(args) {
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 = existsSync2(briefPath);
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/${fileSlug}.md (${existed ? "updated" : "created"})` + (sqliteUpdated ? `
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 indexUpsert(args) {
19271
- const slug = safeExt(args, ["slug", "id"], "");
19272
- const desc = safeExt(args, ["description", "desc", "text"], "");
19273
- const kind = safeExt(args, ["kind", "type"], "article");
19274
- const section = safeExt(args, ["section", "category"], undefined);
19275
- const date = safeExt(args, ["date", "created"], undefined);
19276
- if (!slug)
19277
- return { content: [{ type: "text", text: "Missing slug." }] };
19278
- const today = new Date().toISOString().slice(0, 10);
19279
- const dateStr = date ?? today;
19280
- const indexPath = (() => {
19281
- if (kind === "topic")
19282
- return resolve2(runtime().wikiDir, "topic-index.md");
19283
- if (kind === "skill")
19284
- return resolve2(runtime().wikiDir, "skill-index.md");
19285
- return resolve2(runtime().wikiDir, "article-index.md");
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 = readFileSync2(indexPath, "utf-8");
19777
+ index = readFileSync3(indexPath, "utf-8");
19293
19778
  } catch {
19294
19779
  index = "";
19295
19780
  }
19296
19781
  const lines = index.split(`
19297
19782
  `);
19298
- const link = (() => {
19299
- switch (kind) {
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 { content: [{ type: "text", text: `Index updated: ${link}` }] };
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: "save_wiki_entry",
19446
- description: "Save a session summary directly to wiki/summaries/.",
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
- topic: { type: "string", description: "Topic name of the session" },
19451
- content: { type: "string", description: "Session summary in markdown" }
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: ["topic", "content"]
19989
+ required: ["kind", "content", "description"]
19454
19990
  }
19455
19991
  },
19456
19992
  {
19457
- name: "save_topic_brief",
19458
- description: "Write the accumulated persona/topic brief to wiki/topic/<topic>.md and mirror it into SQLite for next-session injection. Call this AFTER save_wiki_entry (archive \u2192 summary \u2192 brief order).",
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: "Upsert an entry in wiki/article-index.md, topic-index.md, or skill-index.md.",
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
- save_wiki_entry: saveWikiEntry,
19578
- save_topic_brief: saveTopicBrief,
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 existsSync9, readdirSync as readdirSync3 } from "fs";
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 (!existsSync9(stateDir))
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 readFileSync8, realpathSync as realpathSync3 } from "fs";
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 = readFileSync8(filePath, "utf8").split(`
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=AE60D4AF576C043E64756E2164756E21
21040
+ //# debugId=1EA78260283E3CD164756E2164756E21