negotium 0.2.18 → 0.2.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent-helpers.js +367 -313
- package/dist/agent-helpers.js.map +18 -18
- package/dist/background-bash.js +3 -2
- package/dist/background-bash.js.map +3 -3
- package/dist/browser-runtime.js +60 -36
- package/dist/browser-runtime.js.map +6 -6
- package/dist/{chunk-fc58cqry.js → chunk-g2kqfdwm.js} +154 -24
- package/dist/{chunk-fc58cqry.js.map → chunk-g2kqfdwm.js.map} +7 -6
- package/dist/hosted-agent.js +183 -53
- package/dist/hosted-agent.js.map +8 -7
- package/dist/main.js +1395 -626
- package/dist/main.js.map +27 -26
- package/dist/mcp-factories.js +1204 -624
- package/dist/mcp-factories.js.map +21 -20
- package/dist/prompts.js +3 -2
- package/dist/prompts.js.map +3 -3
- package/dist/query-runtime.js +47 -26
- package/dist/query-runtime.js.map +4 -4
- package/dist/registry.js +3 -3
- package/dist/registry.js.map +2 -2
- package/dist/rollout.js +1 -1
- package/dist/runtime/src/agents/archiver.ts +4 -3
- package/dist/runtime/src/application/switch-topic-access-mode.ts +81 -8
- package/dist/runtime/src/bus.ts +19 -2
- package/dist/runtime/src/mcp/canonical-proxy-server.ts +13 -14
- package/dist/runtime/src/mcp/session-comm/runtime.ts +16 -0
- package/dist/runtime/src/mcp/wiki-search-index.ts +359 -0
- package/dist/runtime/src/mcp/wiki-server.ts +559 -98
- package/dist/runtime/src/platform/config.ts +13 -1
- package/dist/runtime/src/platform/mcp-config.ts +1 -1
- package/dist/runtime/src/prompts/agents/wiki-archiver.md +62 -47
- package/dist/runtime/src/runtime/ask-callbacks.ts +19 -11
- package/dist/runtime/src/runtime/background-sessions.ts +9 -7
- package/dist/runtime/src/runtime/visual-store.ts +31 -23
- package/dist/runtime/src/storage/api-topics.ts +26 -0
- package/dist/runtime/src/storage/browser-profiles.ts +16 -8
- package/dist/runtime/src/storage/runtime-events.ts +30 -20
- package/dist/runtime/src/storage/runtime-gateway-submissions.ts +24 -16
- package/dist/runtime/src/storage/runtime-turn-requests.ts +9 -1
- package/dist/runtime/src/storage/self-schedules.ts +32 -24
- package/dist/runtime/src/storage/storage-host.ts +105 -43
- package/dist/runtime/src/storage/vault.ts +12 -3
- package/dist/runtime/src/version.ts +1 -1
- package/dist/runtime-helpers.js +47 -26
- package/dist/runtime-helpers.js.map +4 -4
- package/dist/storage.js +76 -41
- package/dist/storage.js.map +4 -4
- package/dist/types/packages/core/src/agents/archiver.d.ts +1 -1
- package/dist/types/packages/core/src/mcp/wiki-search-index.d.ts +59 -0
- package/dist/types/packages/core/src/storage/api-topics.d.ts +15 -0
- package/dist/types/packages/core/src/storage/storage-host.d.ts +10 -0
- package/dist/types/packages/core/src/version.d.ts +1 -1
- package/dist/vault.js +140 -10
- package/dist/vault.js.map +6 -5
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -152,7 +152,7 @@ function browserRsMeetsMinimumVersion(candidate) {
|
|
|
152
152
|
try {
|
|
153
153
|
const output = execFileSync(candidate, ["--version"], {
|
|
154
154
|
encoding: "utf8",
|
|
155
|
-
timeout:
|
|
155
|
+
timeout: BROWSER_RS_VERSION_PROBE_TIMEOUT_MS,
|
|
156
156
|
stdio: ["ignore", "pipe", "ignore"]
|
|
157
157
|
}).trim();
|
|
158
158
|
const match = output.match(/^browser-rs (\d+)\.(\d+)\.(\d+)$/);
|
|
@@ -263,7 +263,7 @@ function resolveDefaultModel(agent, registryDefaultModel) {
|
|
|
263
263
|
function codexAuthFilePath() {
|
|
264
264
|
return process.env.NEGOTIUM_CODEX_AUTH_FILE || join(process.env.CODEX_HOME || join(homedir(), ".codex"), "auth.json");
|
|
265
265
|
}
|
|
266
|
-
var HOME, PROJECT_ROOT, STATE_DIR_ENV, STATE_DIR, WORKSPACE_DIR, TOPIC_WORKSPACE_DIR, SHARED_WIKI_DIR, CRON_WORKSPACE_DIR, BROWSER_DIR, BROWSER_PROFILES_DIR, BINARIES_DIR, SECRETS_DIR, DM_WORKSPACE_DIR, SESSION_WORKSPACE_DIR, CLAUDE_EXECUTABLE_ENV, CLAUDE_EXECUTABLE, DEFAULT_OUTPUT_LANGUAGE = "English", BROWSER_RS_VERSION = "v0.1.19", BROWSER_RS_MIN_SECURE_VERSION = "0.1.15", SNIPPETS_API_URL, BROWSER_RS_BIN, BASH_RS_VERSION = "v0.1.5", BASH_RS_BIN, PLAYWRIGHT_MCP_BIN, TSX_BIN, TSX_LOADER, TSCONFIG_PATH, SESSION_COMM_SERVER, TASK_SERVER, BROWSER_MCP_SSE_PROXY_SERVER, CANONICAL_MCP_PROXY_SERVER, WIKI_SERVER, TOKEN_STATS_SERVER, COMPACTION_LOG_SERVER, SYSTEM_HEALTH_SERVER, AGENT_HEALTH_SERVER, VAULT_SERVER, BG_BASH_BASE_PORT, BG_BASH_MAX_PORT, RUNTIME_MCP_SECRET, NODE_CONTROL_TOKEN, VAULT_MASTER_KEY, NEGOTIUM_PORT, hostname, DATA_DIR, LOG_DIR, UPLOADS_DIR, VAULT_DIR, SESSIONS_DB, DEBUG_FILE, USERS_LOG_DIR, RUN_DIR, PROGRESS_DIR, DM_CMD_DIR, DM_RESP_DIR, SESSION_INBOX_DIR, SESSION_ASKS_DIR, BASHRS_SPILL_ROOT, PLAYWRIGHT_BASE_PORT, PLAYWRIGHT_MAX_PORT, PLAYWRIGHT_PORTS_DIR, ACTIVE_QUERY_STALE_MS, AGENTS_PROMPTS_DIR, RESOURCES_DIR, FILE_TAG_REGEX, MODEL_SONNET = "claude-sonnet-5", MODEL_OPUS = "claude-opus-5", MODEL_FABLE = "claude-fable-5", FALLBACK_AGENT, SESSION_AGENT, GATEWAY_AGENT, FALLBACK_MODEL, SESSION_MODEL, GATEWAY_MODEL, FFMPEG_BIN, FFPROBE_BIN, PYTHON_BIN, FASTER_WHISPER_WRAPPER, WHISPER_MODEL, TESSERACT_BIN, PDFTOTEXT_BIN, _envMaxTellDepth, MAX_TELL_DEPTH;
|
|
266
|
+
var HOME, PROJECT_ROOT, STATE_DIR_ENV, STATE_DIR, WORKSPACE_DIR, TOPIC_WORKSPACE_DIR, SHARED_WIKI_DIR, CRON_WORKSPACE_DIR, BROWSER_DIR, BROWSER_PROFILES_DIR, BINARIES_DIR, SECRETS_DIR, DM_WORKSPACE_DIR, SESSION_WORKSPACE_DIR, CLAUDE_EXECUTABLE_ENV, CLAUDE_EXECUTABLE, DEFAULT_OUTPUT_LANGUAGE = "English", BROWSER_RS_VERSION = "v0.1.19", BROWSER_RS_MIN_SECURE_VERSION = "0.1.15", BROWSER_RS_VERSION_PROBE_TIMEOUT_MS = 15000, SNIPPETS_API_URL, BROWSER_RS_BIN, BASH_RS_VERSION = "v0.1.5", BASH_RS_BIN, PLAYWRIGHT_MCP_BIN, TSX_BIN, TSX_LOADER, TSCONFIG_PATH, SESSION_COMM_SERVER, TASK_SERVER, BROWSER_MCP_SSE_PROXY_SERVER, CANONICAL_MCP_PROXY_SERVER, WIKI_SERVER, TOKEN_STATS_SERVER, COMPACTION_LOG_SERVER, SYSTEM_HEALTH_SERVER, AGENT_HEALTH_SERVER, VAULT_SERVER, BG_BASH_BASE_PORT, BG_BASH_MAX_PORT, RUNTIME_MCP_SECRET, NODE_CONTROL_TOKEN, VAULT_MASTER_KEY, NEGOTIUM_PORT, hostname, DATA_DIR, LOG_DIR, UPLOADS_DIR, VAULT_DIR, SESSIONS_DB, DEBUG_FILE, USERS_LOG_DIR, RUN_DIR, PROGRESS_DIR, DM_CMD_DIR, DM_RESP_DIR, SESSION_INBOX_DIR, SESSION_ASKS_DIR, BASHRS_SPILL_ROOT, PLAYWRIGHT_BASE_PORT, PLAYWRIGHT_MAX_PORT, PLAYWRIGHT_PORTS_DIR, ACTIVE_QUERY_STALE_MS, AGENTS_PROMPTS_DIR, RESOURCES_DIR, FILE_TAG_REGEX, MODEL_SONNET = "claude-sonnet-5", MODEL_OPUS = "claude-opus-5", MODEL_FABLE = "claude-fable-5", FALLBACK_AGENT, SESSION_AGENT, GATEWAY_AGENT, FALLBACK_MODEL, SESSION_MODEL, GATEWAY_MODEL, FFMPEG_BIN, FFPROBE_BIN, PYTHON_BIN, FASTER_WHISPER_WRAPPER, WHISPER_MODEL, TESSERACT_BIN, PDFTOTEXT_BIN, _envMaxTellDepth, MAX_TELL_DEPTH;
|
|
267
267
|
var init_config = __esm(() => {
|
|
268
268
|
init_config_helpers();
|
|
269
269
|
init_logger();
|
|
@@ -421,6 +421,225 @@ var init_sqlite = __esm(async () => {
|
|
|
421
421
|
}
|
|
422
422
|
});
|
|
423
423
|
|
|
424
|
+
// ../../packages/core/src/storage/storage-host.ts
|
|
425
|
+
import { mkdirSync as mkdirSync2 } from "fs";
|
|
426
|
+
import { homedir as homedir2 } from "os";
|
|
427
|
+
import { dirname as dirname2, join as join2, resolve as resolve2 } from "path";
|
|
428
|
+
function storageState() {
|
|
429
|
+
const holder = globalThis;
|
|
430
|
+
const existing = holder[STORAGE_HOST_STATE];
|
|
431
|
+
if (existing)
|
|
432
|
+
return existing;
|
|
433
|
+
const created = {
|
|
434
|
+
configuredHost: {},
|
|
435
|
+
fallbackDatabase: null,
|
|
436
|
+
fallbackDatabasePath: null,
|
|
437
|
+
frames: [],
|
|
438
|
+
schemaInitializers: [],
|
|
439
|
+
initializedSchemas: new WeakMap,
|
|
440
|
+
initializingDatabases: new WeakSet
|
|
441
|
+
};
|
|
442
|
+
Object.defineProperty(holder, STORAGE_HOST_STATE, {
|
|
443
|
+
value: created,
|
|
444
|
+
enumerable: false,
|
|
445
|
+
writable: false,
|
|
446
|
+
configurable: false
|
|
447
|
+
});
|
|
448
|
+
return created;
|
|
449
|
+
}
|
|
450
|
+
function envPath(name, fallback) {
|
|
451
|
+
const value = process.env[name]?.trim();
|
|
452
|
+
return resolve2(value || fallback);
|
|
453
|
+
}
|
|
454
|
+
function defaultStateDir() {
|
|
455
|
+
return envPath("NEGOTIUM_STATE_DIR", join2(homedir2(), ".negotium"));
|
|
456
|
+
}
|
|
457
|
+
function defaultDataDir() {
|
|
458
|
+
return envPath("NEGOTIUM_DATA_DIR", join2(defaultStateDir(), "data"));
|
|
459
|
+
}
|
|
460
|
+
function defaultLogDir() {
|
|
461
|
+
return envPath("NEGOTIUM_LOG_DIR", join2(defaultStateDir(), "logs"));
|
|
462
|
+
}
|
|
463
|
+
function defaultWorkspaceDir() {
|
|
464
|
+
return envPath("NEGOTIUM_WORKSPACE_DIR", join2(defaultStateDir(), "workspace"));
|
|
465
|
+
}
|
|
466
|
+
function defaultSessionAsksDir() {
|
|
467
|
+
const runDir = envPath("NEGOTIUM_RUN_DIR", join2(defaultStateDir(), "runtime"));
|
|
468
|
+
return join2(runDir, "session-asks");
|
|
469
|
+
}
|
|
470
|
+
function defaultSessionsDatabasePath() {
|
|
471
|
+
return envPath("SESSIONS_DB_PATH", join2(resolveStorageDataDir(), "sessions.db"));
|
|
472
|
+
}
|
|
473
|
+
function isSqliteBusy(error) {
|
|
474
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
475
|
+
return /database is (?:locked|busy)|SQLITE_(?:BUSY|LOCKED)/i.test(message);
|
|
476
|
+
}
|
|
477
|
+
function execWithBusyRetry(database, sql, timeoutMs = SQLITE_INIT_TIMEOUT_MS) {
|
|
478
|
+
const deadline = Date.now() + timeoutMs;
|
|
479
|
+
while (true) {
|
|
480
|
+
try {
|
|
481
|
+
database.exec(sql);
|
|
482
|
+
return;
|
|
483
|
+
} catch (error) {
|
|
484
|
+
if (!isSqliteBusy(error) || Date.now() >= deadline)
|
|
485
|
+
throw error;
|
|
486
|
+
Atomics.wait(SQLITE_INIT_SLEEP, 0, 0, Math.min(SQLITE_INIT_RETRY_MS, deadline - Date.now()));
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
function initializeDatabase(database) {
|
|
491
|
+
database.exec("PRAGMA busy_timeout = 5000");
|
|
492
|
+
execWithBusyRetry(database, "PRAGMA journal_mode = WAL");
|
|
493
|
+
database.exec("PRAGMA foreign_keys = ON");
|
|
494
|
+
database.exec("PRAGMA wal_autocheckpoint = 1000");
|
|
495
|
+
try {
|
|
496
|
+
database.exec("PRAGMA wal_checkpoint(TRUNCATE)");
|
|
497
|
+
} catch {}
|
|
498
|
+
}
|
|
499
|
+
function defaultDatabase() {
|
|
500
|
+
const path = defaultSessionsDatabasePath();
|
|
501
|
+
const state = storageState();
|
|
502
|
+
if (state.fallbackDatabase && state.fallbackDatabasePath === path)
|
|
503
|
+
return state.fallbackDatabase;
|
|
504
|
+
if (state.fallbackDatabase)
|
|
505
|
+
state.fallbackDatabase.close();
|
|
506
|
+
mkdirSync2(dirname2(path), { recursive: true });
|
|
507
|
+
state.fallbackDatabase = new Database(path, { create: true });
|
|
508
|
+
state.fallbackDatabasePath = path;
|
|
509
|
+
initializeDatabase(state.fallbackDatabase);
|
|
510
|
+
return state.fallbackDatabase;
|
|
511
|
+
}
|
|
512
|
+
function resolveStorageDatabase() {
|
|
513
|
+
return storageState().configuredHost.database ?? defaultDatabase();
|
|
514
|
+
}
|
|
515
|
+
function resolveStorageDataDir() {
|
|
516
|
+
return storageState().configuredHost.dataDir ?? defaultDataDir();
|
|
517
|
+
}
|
|
518
|
+
function resolveStorageLogDir() {
|
|
519
|
+
return storageState().configuredHost.logDir ?? defaultLogDir();
|
|
520
|
+
}
|
|
521
|
+
function resolveStorageSessionAsksDir() {
|
|
522
|
+
return storageState().configuredHost.sessionAsksDir ?? defaultSessionAsksDir();
|
|
523
|
+
}
|
|
524
|
+
function resolveStorageWorkspaceDir() {
|
|
525
|
+
return storageState().configuredHost.workspaceDir ?? defaultWorkspaceDir();
|
|
526
|
+
}
|
|
527
|
+
function resolveStorageSharedWikiDir() {
|
|
528
|
+
return storageState().configuredHost.sharedWikiDir ?? join2(resolveStorageWorkspaceDir(), "wiki");
|
|
529
|
+
}
|
|
530
|
+
function resolveStorageUsersLogDir() {
|
|
531
|
+
return storageState().configuredHost.usersLogDir ?? join2(resolveStorageDataDir(), "users");
|
|
532
|
+
}
|
|
533
|
+
function normalizeStorageHostPatch(options) {
|
|
534
|
+
const patch = {};
|
|
535
|
+
if (options.database !== undefined) {
|
|
536
|
+
options.database.exec("PRAGMA foreign_keys = ON");
|
|
537
|
+
patch.database = options.database;
|
|
538
|
+
}
|
|
539
|
+
for (const key of STORAGE_PATH_KEYS) {
|
|
540
|
+
const value = options[key];
|
|
541
|
+
if (value === undefined)
|
|
542
|
+
continue;
|
|
543
|
+
if (!value.trim())
|
|
544
|
+
throw new TypeError(`${key} must not be empty`);
|
|
545
|
+
patch[key] = resolve2(value);
|
|
546
|
+
}
|
|
547
|
+
return Object.freeze(patch);
|
|
548
|
+
}
|
|
549
|
+
function refreshConfiguredHost() {
|
|
550
|
+
const state = storageState();
|
|
551
|
+
state.configuredHost = Object.freeze(Object.assign({}, ...state.frames.filter((frame) => frame.active).map((frame) => frame.patch)));
|
|
552
|
+
}
|
|
553
|
+
function configureStorageHost(options) {
|
|
554
|
+
const frame = { active: true, patch: normalizeStorageHostPatch(options) };
|
|
555
|
+
storageState().frames.push(frame);
|
|
556
|
+
refreshConfiguredHost();
|
|
557
|
+
return () => {
|
|
558
|
+
if (!frame.active)
|
|
559
|
+
return;
|
|
560
|
+
frame.active = false;
|
|
561
|
+
const frames = storageState().frames;
|
|
562
|
+
const index = frames.indexOf(frame);
|
|
563
|
+
if (index >= 0)
|
|
564
|
+
frames.splice(index, 1);
|
|
565
|
+
refreshConfiguredHost();
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
function resetStorageHost() {
|
|
569
|
+
const frames = storageState().frames;
|
|
570
|
+
for (const frame of frames)
|
|
571
|
+
frame.active = false;
|
|
572
|
+
frames.length = 0;
|
|
573
|
+
refreshConfiguredHost();
|
|
574
|
+
}
|
|
575
|
+
function closeStorageDatabase() {
|
|
576
|
+
const state = storageState();
|
|
577
|
+
if (!state.fallbackDatabase)
|
|
578
|
+
return;
|
|
579
|
+
state.fallbackDatabase.close();
|
|
580
|
+
state.fallbackDatabase = null;
|
|
581
|
+
state.fallbackDatabasePath = null;
|
|
582
|
+
}
|
|
583
|
+
function registerStorageSchemaInitializer(initialize, priority = 100) {
|
|
584
|
+
const initializers = storageState().schemaInitializers;
|
|
585
|
+
initializers.push({ initialize, priority });
|
|
586
|
+
initializers.sort((a, b) => a.priority - b.priority);
|
|
587
|
+
}
|
|
588
|
+
function ensureStorageSchemas(database = resolveStorageDatabase()) {
|
|
589
|
+
const state = storageState();
|
|
590
|
+
if (state.initializingDatabases.has(database))
|
|
591
|
+
return;
|
|
592
|
+
let initialized = state.initializedSchemas.get(database);
|
|
593
|
+
if (!initialized) {
|
|
594
|
+
initialized = new Set;
|
|
595
|
+
state.initializedSchemas.set(database, initialized);
|
|
596
|
+
}
|
|
597
|
+
state.initializingDatabases.add(database);
|
|
598
|
+
try {
|
|
599
|
+
for (const entry of state.schemaInitializers) {
|
|
600
|
+
if (initialized.has(entry.initialize))
|
|
601
|
+
continue;
|
|
602
|
+
initialized.add(entry.initialize);
|
|
603
|
+
try {
|
|
604
|
+
entry.initialize(database);
|
|
605
|
+
} catch (error) {
|
|
606
|
+
initialized.delete(entry.initialize);
|
|
607
|
+
throw error;
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
} finally {
|
|
611
|
+
state.initializingDatabases.delete(database);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
var STORAGE_HOST_STATE, SQLITE_INIT_RETRY_MS = 25, SQLITE_INIT_TIMEOUT_MS = 5000, SQLITE_INIT_SLEEP, STORAGE_PATH_KEYS, internalStorageDatabase, storageDatabase;
|
|
615
|
+
var init_storage_host = __esm(async () => {
|
|
616
|
+
await init_sqlite();
|
|
617
|
+
STORAGE_HOST_STATE = Symbol.for("negotium.storage-host.state.v1");
|
|
618
|
+
SQLITE_INIT_SLEEP = new Int32Array(new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT));
|
|
619
|
+
STORAGE_PATH_KEYS = [
|
|
620
|
+
"dataDir",
|
|
621
|
+
"logDir",
|
|
622
|
+
"sessionAsksDir",
|
|
623
|
+
"workspaceDir",
|
|
624
|
+
"sharedWikiDir",
|
|
625
|
+
"usersLogDir"
|
|
626
|
+
];
|
|
627
|
+
internalStorageDatabase = new Proxy({}, {
|
|
628
|
+
get(_target, property) {
|
|
629
|
+
const database = resolveStorageDatabase();
|
|
630
|
+
ensureStorageSchemas(database);
|
|
631
|
+
const value = Reflect.get(database, property, database);
|
|
632
|
+
return typeof value === "function" ? value.bind(database) : value;
|
|
633
|
+
},
|
|
634
|
+
set(_target, property, value) {
|
|
635
|
+
const database = resolveStorageDatabase();
|
|
636
|
+
ensureStorageSchemas(database);
|
|
637
|
+
return Reflect.set(database, property, value, database);
|
|
638
|
+
}
|
|
639
|
+
});
|
|
640
|
+
storageDatabase = internalStorageDatabase;
|
|
641
|
+
});
|
|
642
|
+
|
|
424
643
|
// ../../packages/core/src/storage/vault-crypto-core.ts
|
|
425
644
|
import { createCipheriv, createDecipheriv, createHash, randomBytes as randomBytes2 } from "crypto";
|
|
426
645
|
function encryptionKey(masterKey) {
|
|
@@ -477,8 +696,8 @@ var init_vault_crypto = __esm(() => {
|
|
|
477
696
|
});
|
|
478
697
|
|
|
479
698
|
// ../../packages/core/src/storage/vault.ts
|
|
480
|
-
import { chmodSync as chmodSync2, mkdirSync as
|
|
481
|
-
import { join as
|
|
699
|
+
import { chmodSync as chmodSync2, mkdirSync as mkdirSync3 } from "fs";
|
|
700
|
+
import { join as join3 } from "path";
|
|
482
701
|
function initializeVaultDatabase(database) {
|
|
483
702
|
database.exec("PRAGMA journal_mode = WAL");
|
|
484
703
|
database.exec("PRAGMA busy_timeout = 5000");
|
|
@@ -513,17 +732,18 @@ function initializeVaultDatabase(database) {
|
|
|
513
732
|
}
|
|
514
733
|
}
|
|
515
734
|
function openVaultDatabase(dataDir) {
|
|
516
|
-
const vaultDir =
|
|
517
|
-
const path =
|
|
518
|
-
|
|
735
|
+
const vaultDir = join3(dataDir, "vault");
|
|
736
|
+
const path = join3(vaultDir, "vault.db");
|
|
737
|
+
mkdirSync3(vaultDir, { recursive: true, mode: 448 });
|
|
519
738
|
const database = new Database(path, { create: true });
|
|
520
739
|
chmodSync2(path, 384);
|
|
521
740
|
initializeVaultDatabase(database);
|
|
522
741
|
return database;
|
|
523
742
|
}
|
|
524
743
|
function activeVaultDatabase() {
|
|
525
|
-
if (!vaultDb)
|
|
526
|
-
vaultDb = openVaultDatabase(
|
|
744
|
+
if (!vaultDb) {
|
|
745
|
+
vaultDb = openVaultDatabase(resolveStorageDataDir());
|
|
746
|
+
}
|
|
527
747
|
return vaultDb;
|
|
528
748
|
}
|
|
529
749
|
function configureVaultStorage(options) {
|
|
@@ -532,7 +752,7 @@ function configureVaultStorage(options) {
|
|
|
532
752
|
}
|
|
533
753
|
const previousDb = vaultDb;
|
|
534
754
|
const previousMasterKey = vaultMasterKey;
|
|
535
|
-
const configuredDb = options.database ?? openVaultDatabase(options.dataDir ??
|
|
755
|
+
const configuredDb = options.database ?? openVaultDatabase(options.dataDir ?? resolveStorageDataDir());
|
|
536
756
|
if (options.database)
|
|
537
757
|
initializeVaultDatabase(configuredDb);
|
|
538
758
|
vaultDb = configuredDb;
|
|
@@ -687,7 +907,10 @@ var vaultDb, vaultMasterKey, VAULT_KEY_PATTERN, VAULT_VALUE_MIN_BYTES = 4, VAULT
|
|
|
687
907
|
var init_vault = __esm(async () => {
|
|
688
908
|
init_config();
|
|
689
909
|
init_vault_crypto();
|
|
690
|
-
await
|
|
910
|
+
await __promiseAll([
|
|
911
|
+
init_sqlite(),
|
|
912
|
+
init_storage_host()
|
|
913
|
+
]);
|
|
691
914
|
vaultMasterKey = VAULT_MASTER_KEY;
|
|
692
915
|
VAULT_KEY_PATTERN = /^[A-Z][A-Z0-9_]{0,127}$/;
|
|
693
916
|
VAULT_VALUE_MAX_BYTES = 64 * 1024;
|
|
@@ -701,8 +924,8 @@ __export(exports_auth_check, {
|
|
|
701
924
|
});
|
|
702
925
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
703
926
|
import { existsSync as existsSync2 } from "fs";
|
|
704
|
-
import { homedir as
|
|
705
|
-
import { join as
|
|
927
|
+
import { homedir as homedir3, platform } from "os";
|
|
928
|
+
import { join as join4 } from "path";
|
|
706
929
|
function hasMaestroCredential(host, key, userId) {
|
|
707
930
|
if (userId && host.getVaultValue(userId, key)?.trim())
|
|
708
931
|
return true;
|
|
@@ -722,7 +945,7 @@ function checkAgentAuth(agent, host = defaultAgentAuthHost, userId) {
|
|
|
722
945
|
case "claude": {
|
|
723
946
|
if (host.environment.ANTHROPIC_API_KEY)
|
|
724
947
|
return { ok: true };
|
|
725
|
-
const path =
|
|
948
|
+
const path = join4(host.homeDirectory(), ".claude", ".credentials.json");
|
|
726
949
|
if (host.operatingSystem() === "darwin") {
|
|
727
950
|
if (host.hasMacOsCredential("Claude Code-credentials") || host.exists(path)) {
|
|
728
951
|
return { ok: true };
|
|
@@ -775,7 +998,7 @@ var init_auth_check = __esm(async () => {
|
|
|
775
998
|
codexAuthFilePath,
|
|
776
999
|
exists: existsSync2,
|
|
777
1000
|
environment: process.env,
|
|
778
|
-
homeDirectory:
|
|
1001
|
+
homeDirectory: homedir3,
|
|
779
1002
|
operatingSystem: platform,
|
|
780
1003
|
hasMacOsCredential(service) {
|
|
781
1004
|
try {
|
|
@@ -842,12 +1065,12 @@ function createCodexTreeManager(host, options = {}) {
|
|
|
842
1065
|
const previous = spawnChain;
|
|
843
1066
|
let release;
|
|
844
1067
|
let released = false;
|
|
845
|
-
spawnChain = new Promise((
|
|
1068
|
+
spawnChain = new Promise((resolve3) => {
|
|
846
1069
|
release = () => {
|
|
847
1070
|
if (released)
|
|
848
1071
|
return;
|
|
849
1072
|
released = true;
|
|
850
|
-
|
|
1073
|
+
resolve3();
|
|
851
1074
|
};
|
|
852
1075
|
});
|
|
853
1076
|
await previous;
|
|
@@ -954,7 +1177,7 @@ function createCodexTreeManager(host, options = {}) {
|
|
|
954
1177
|
return;
|
|
955
1178
|
const deadline = Date.now() + Math.max(0, graceMs);
|
|
956
1179
|
while (Date.now() < deadline && hasSurvivors(plan.targets)) {
|
|
957
|
-
await new Promise((
|
|
1180
|
+
await new Promise((resolve3) => setTimeout(resolve3, Math.min(100, Math.max(1, deadline - Date.now()))));
|
|
958
1181
|
}
|
|
959
1182
|
killStragglers(plan);
|
|
960
1183
|
}
|
|
@@ -1102,8 +1325,8 @@ function renderUserTurnBatch(messages) {
|
|
|
1102
1325
|
}
|
|
1103
1326
|
|
|
1104
1327
|
// ../../packages/core/src/agents/rollout/shared.ts
|
|
1105
|
-
import { mkdirSync as
|
|
1106
|
-
import { resolve as
|
|
1328
|
+
import { mkdirSync as mkdirSync4 } from "fs";
|
|
1329
|
+
import { resolve as resolve3 } from "path";
|
|
1107
1330
|
function clone(obj) {
|
|
1108
1331
|
return structuredClone(obj);
|
|
1109
1332
|
}
|
|
@@ -1113,7 +1336,7 @@ function assertUuidLike(label, value) {
|
|
|
1113
1336
|
}
|
|
1114
1337
|
}
|
|
1115
1338
|
function assertCwdInWorkspace(cwd) {
|
|
1116
|
-
const abs =
|
|
1339
|
+
const abs = resolve3(cwd);
|
|
1117
1340
|
const ok = trustedWorkspaceRoots.some((root) => abs === root || abs.startsWith(`${root}/`));
|
|
1118
1341
|
if (!ok) {
|
|
1119
1342
|
throw new Error(`rollout: cwd outside trusted workspace roots: ${cwd} (resolved=${abs})`);
|
|
@@ -1122,7 +1345,7 @@ function assertCwdInWorkspace(cwd) {
|
|
|
1122
1345
|
function ensureCwdExists(cwd) {
|
|
1123
1346
|
assertCwdInWorkspace(cwd);
|
|
1124
1347
|
try {
|
|
1125
|
-
|
|
1348
|
+
mkdirSync4(cwd, { recursive: true });
|
|
1126
1349
|
} catch (err) {
|
|
1127
1350
|
logger.warn({ err, cwd }, "rollout: ensureCwdExists failed \u2014 caller should pre-create cwd");
|
|
1128
1351
|
}
|
|
@@ -1243,8 +1466,8 @@ var init_shared = __esm(() => {
|
|
|
1243
1466
|
DM_WORKSPACE_DIR,
|
|
1244
1467
|
SESSION_WORKSPACE_DIR,
|
|
1245
1468
|
TOPIC_WORKSPACE_DIR
|
|
1246
|
-
].map((root) =>
|
|
1247
|
-
FIXTURES_DIR =
|
|
1469
|
+
].map((root) => resolve3(root));
|
|
1470
|
+
FIXTURES_DIR = resolve3(PROJECT_ROOT, "src", "agents", "fixtures");
|
|
1248
1471
|
UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
1249
1472
|
});
|
|
1250
1473
|
|
|
@@ -1279,7 +1502,7 @@ import {
|
|
|
1279
1502
|
appendFileSync,
|
|
1280
1503
|
closeSync,
|
|
1281
1504
|
fsyncSync,
|
|
1282
|
-
mkdirSync as
|
|
1505
|
+
mkdirSync as mkdirSync5,
|
|
1283
1506
|
openSync,
|
|
1284
1507
|
readFileSync as readFileSync2,
|
|
1285
1508
|
renameSync,
|
|
@@ -1287,7 +1510,7 @@ import {
|
|
|
1287
1510
|
unlinkSync as unlinkSync2,
|
|
1288
1511
|
writeFileSync as writeFileSync2
|
|
1289
1512
|
} from "fs";
|
|
1290
|
-
import { dirname as
|
|
1513
|
+
import { dirname as dirname3 } from "path";
|
|
1291
1514
|
function readJsonlLines(filePath) {
|
|
1292
1515
|
return readFileSync2(filePath, "utf-8").trim().split(`
|
|
1293
1516
|
`).filter(Boolean);
|
|
@@ -1335,7 +1558,7 @@ function appendJsonlEntry(filePath, entry) {
|
|
|
1335
1558
|
`);
|
|
1336
1559
|
}
|
|
1337
1560
|
function appendJsonlLine(filePath, line) {
|
|
1338
|
-
|
|
1561
|
+
mkdirSync5(dirname3(filePath), { recursive: true });
|
|
1339
1562
|
const lockPath = `${filePath}${LOCK_SUFFIX}`;
|
|
1340
1563
|
const payload = line.endsWith(`
|
|
1341
1564
|
`) ? line : `${line}
|
|
@@ -1366,8 +1589,8 @@ function appendJsonlLine(filePath, line) {
|
|
|
1366
1589
|
}
|
|
1367
1590
|
}
|
|
1368
1591
|
function writeJsonlFile(filePath, entries) {
|
|
1369
|
-
const dir =
|
|
1370
|
-
|
|
1592
|
+
const dir = dirname3(filePath);
|
|
1593
|
+
mkdirSync5(dir, { recursive: true });
|
|
1371
1594
|
const tmpPath = `${filePath}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
|
1372
1595
|
const payload = `${entries.map((e) => JSON.stringify(e)).join(`
|
|
1373
1596
|
`)}
|
|
@@ -1425,12 +1648,12 @@ var init_jsonl = __esm(() => {
|
|
|
1425
1648
|
// ../../packages/core/src/agents/rollout/claude.ts
|
|
1426
1649
|
import { randomUUID } from "crypto";
|
|
1427
1650
|
import { existsSync as existsSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
1428
|
-
import { homedir as
|
|
1429
|
-
import { join as
|
|
1651
|
+
import { homedir as homedir4 } from "os";
|
|
1652
|
+
import { join as join5 } from "path";
|
|
1430
1653
|
function loadClaudeAttachments() {
|
|
1431
1654
|
if (_attachmentsCache)
|
|
1432
1655
|
return _attachmentsCache;
|
|
1433
|
-
const raw = readFileSync3(
|
|
1656
|
+
const raw = readFileSync3(join5(FIXTURES_DIR, "claude-attachments.jsonl"), "utf8");
|
|
1434
1657
|
const lines = parseJsonlText(raw);
|
|
1435
1658
|
if (lines.length < 2) {
|
|
1436
1659
|
throw new Error(`loadClaudeAttachments: expected >=2 entries in claude-attachments.jsonl, got ${lines.length}`);
|
|
@@ -1531,8 +1754,8 @@ function writeClaudeRollout(opts) {
|
|
|
1531
1754
|
});
|
|
1532
1755
|
lastUuid = assistantUuid;
|
|
1533
1756
|
}
|
|
1534
|
-
const projectsDir =
|
|
1535
|
-
const path =
|
|
1757
|
+
const projectsDir = join5(homedir4(), ".claude", "projects", encodeClaudeCwd(opts.cwd));
|
|
1758
|
+
const path = join5(projectsDir, `${sessionId}.jsonl`);
|
|
1536
1759
|
writeJsonlFile(path, lines);
|
|
1537
1760
|
logger.info({ sessionId, path, pairs: pairs.length }, "writeClaudeRollout: synthetic rollout placed");
|
|
1538
1761
|
return { sessionId, rolloutPath: path };
|
|
@@ -1545,9 +1768,9 @@ var init_claude = __esm(() => {
|
|
|
1545
1768
|
});
|
|
1546
1769
|
|
|
1547
1770
|
// ../../packages/core/src/agents/claude-registry.ts
|
|
1548
|
-
import { existsSync as existsSync4, mkdirSync as
|
|
1549
|
-
import { homedir as
|
|
1550
|
-
import { join as
|
|
1771
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync6, readdirSync, renameSync as renameSync2, unlinkSync as unlinkSync3 } from "fs";
|
|
1772
|
+
import { homedir as homedir5 } from "os";
|
|
1773
|
+
import { join as join6 } from "path";
|
|
1551
1774
|
var ALIAS_MAP, VALID_ALIASES, VALID_EFFORTS, claudeRegistry, claudeRegistryOperations;
|
|
1552
1775
|
var init_claude_registry = __esm(() => {
|
|
1553
1776
|
init_claude();
|
|
@@ -1594,15 +1817,15 @@ var init_claude_registry = __esm(() => {
|
|
|
1594
1817
|
const result = await forkSession(parentSessionId, {
|
|
1595
1818
|
...title ? { title } : {}
|
|
1596
1819
|
});
|
|
1597
|
-
const projectsRoot =
|
|
1598
|
-
const destDir =
|
|
1599
|
-
const destPath =
|
|
1820
|
+
const projectsRoot = join6(homedir5(), ".claude", "projects");
|
|
1821
|
+
const destDir = join6(projectsRoot, encodeClaudeCwd(cwd));
|
|
1822
|
+
const destPath = join6(destDir, `${result.sessionId}.jsonl`);
|
|
1600
1823
|
if (!existsSync4(destPath)) {
|
|
1601
|
-
const sourcePath = readdirSync(projectsRoot).map((d) =>
|
|
1824
|
+
const sourcePath = readdirSync(projectsRoot).map((d) => join6(projectsRoot, d, `${result.sessionId}.jsonl`)).find((p) => existsSync4(p));
|
|
1602
1825
|
if (!sourcePath) {
|
|
1603
1826
|
throw new Error(`claude forkSession: fork rollout ${result.sessionId}.jsonl not found under ${projectsRoot}`);
|
|
1604
1827
|
}
|
|
1605
|
-
|
|
1828
|
+
mkdirSync6(destDir, { recursive: true });
|
|
1606
1829
|
renameSync2(sourcePath, destPath);
|
|
1607
1830
|
}
|
|
1608
1831
|
return {
|
|
@@ -1611,10 +1834,10 @@ var init_claude_registry = __esm(() => {
|
|
|
1611
1834
|
};
|
|
1612
1835
|
},
|
|
1613
1836
|
async cleanupRollouts({ cwd, sessionIds }) {
|
|
1614
|
-
const projectsDir =
|
|
1837
|
+
const projectsDir = join6(homedir5(), ".claude", "projects", encodeClaudeCwd(cwd));
|
|
1615
1838
|
const failures = [];
|
|
1616
1839
|
for (const sid of sessionIds) {
|
|
1617
|
-
const path =
|
|
1840
|
+
const path = join6(projectsDir, `${sid}.jsonl`);
|
|
1618
1841
|
try {
|
|
1619
1842
|
unlinkSync3(path);
|
|
1620
1843
|
} catch (e) {
|
|
@@ -1636,7 +1859,7 @@ var exports_version = {};
|
|
|
1636
1859
|
__export(exports_version, {
|
|
1637
1860
|
NEGOTIUM_VERSION: () => NEGOTIUM_VERSION
|
|
1638
1861
|
});
|
|
1639
|
-
var NEGOTIUM_VERSION = "0.2.
|
|
1862
|
+
var NEGOTIUM_VERSION = "0.2.20";
|
|
1640
1863
|
|
|
1641
1864
|
// ../../packages/core/src/agents/codex-native-multi-agent.ts
|
|
1642
1865
|
import { spawn } from "child_process";
|
|
@@ -1654,7 +1877,7 @@ import {
|
|
|
1654
1877
|
} from "fs";
|
|
1655
1878
|
import { createRequire as createRequire2 } from "module";
|
|
1656
1879
|
import { tmpdir } from "os";
|
|
1657
|
-
import { dirname as
|
|
1880
|
+
import { dirname as dirname4, join as join7 } from "path";
|
|
1658
1881
|
function readPackageVersion(packageJsonPath) {
|
|
1659
1882
|
const parsed = JSON.parse(readFileSync4(packageJsonPath, "utf8"));
|
|
1660
1883
|
if (typeof parsed.version !== "string" || !parsed.version.trim()) {
|
|
@@ -1663,7 +1886,7 @@ function readPackageVersion(packageJsonPath) {
|
|
|
1663
1886
|
return parsed.version;
|
|
1664
1887
|
}
|
|
1665
1888
|
function codexCliScriptPath() {
|
|
1666
|
-
return
|
|
1889
|
+
return join7(dirname4(bundledCodexPackagePath), "bin", "codex.js");
|
|
1667
1890
|
}
|
|
1668
1891
|
function parseCodexModelCache(contents, sourcePath) {
|
|
1669
1892
|
let parsed;
|
|
@@ -1704,14 +1927,14 @@ function writePrivateFileAtomic(path, contents) {
|
|
|
1704
1927
|
}
|
|
1705
1928
|
}
|
|
1706
1929
|
function bundledCodexModelCachePath(authFilePath) {
|
|
1707
|
-
return
|
|
1930
|
+
return join7(dirname4(authFilePath), NEGOTIUM_MODEL_CACHE);
|
|
1708
1931
|
}
|
|
1709
1932
|
async function bootstrapCodexModelCache(codexHome, cachePath) {
|
|
1710
1933
|
const child = spawn(process.execPath, [codexCliScriptPath(), "app-server", "--stdio"], {
|
|
1711
1934
|
env: { ...process.env, CODEX_HOME: codexHome },
|
|
1712
1935
|
stdio: ["pipe", "pipe", "pipe"]
|
|
1713
1936
|
});
|
|
1714
|
-
await new Promise((
|
|
1937
|
+
await new Promise((resolve4, reject) => {
|
|
1715
1938
|
let settled = false;
|
|
1716
1939
|
let stdoutBuffer = "";
|
|
1717
1940
|
let stderr = "";
|
|
@@ -1730,7 +1953,7 @@ async function bootstrapCodexModelCache(codexHome, cachePath) {
|
|
|
1730
1953
|
else if (!existsSync5(cachePath))
|
|
1731
1954
|
reject(new Error("Codex did not create its model cache"));
|
|
1732
1955
|
else
|
|
1733
|
-
|
|
1956
|
+
resolve4();
|
|
1734
1957
|
};
|
|
1735
1958
|
const send = (message) => {
|
|
1736
1959
|
child.stdin.write(`${JSON.stringify(message)}
|
|
@@ -1789,16 +2012,16 @@ async function bootstrapCodexModelCache(codexHome, cachePath) {
|
|
|
1789
2012
|
});
|
|
1790
2013
|
}
|
|
1791
2014
|
async function bootstrapIsolatedCodexModelCache(authFilePath, bootstrap) {
|
|
1792
|
-
const sourceHome =
|
|
1793
|
-
const isolatedHome = mkdtempSync(
|
|
1794
|
-
const isolatedCachePath =
|
|
2015
|
+
const sourceHome = dirname4(authFilePath);
|
|
2016
|
+
const isolatedHome = mkdtempSync(join7(tmpdir(), "negotium-codex-models-"));
|
|
2017
|
+
const isolatedCachePath = join7(isolatedHome, "models_cache.json");
|
|
1795
2018
|
try {
|
|
1796
|
-
const isolatedAuthPath =
|
|
2019
|
+
const isolatedAuthPath = join7(isolatedHome, "auth.json");
|
|
1797
2020
|
copyFileSync(authFilePath, isolatedAuthPath);
|
|
1798
2021
|
chmodSync3(isolatedAuthPath, 384);
|
|
1799
|
-
const sourceConfigPath =
|
|
2022
|
+
const sourceConfigPath = join7(sourceHome, "config.toml");
|
|
1800
2023
|
if (existsSync5(sourceConfigPath)) {
|
|
1801
|
-
const isolatedConfigPath =
|
|
2024
|
+
const isolatedConfigPath = join7(isolatedHome, "config.toml");
|
|
1802
2025
|
copyFileSync(sourceConfigPath, isolatedConfigPath);
|
|
1803
2026
|
chmodSync3(isolatedConfigPath, 384);
|
|
1804
2027
|
}
|
|
@@ -1809,7 +2032,7 @@ async function bootstrapIsolatedCodexModelCache(authFilePath, bootstrap) {
|
|
|
1809
2032
|
}
|
|
1810
2033
|
}
|
|
1811
2034
|
async function ensureCodexModelCache(authFilePath, bootstrap = bootstrapCodexModelCache) {
|
|
1812
|
-
const codexHome =
|
|
2035
|
+
const codexHome = dirname4(authFilePath);
|
|
1813
2036
|
const configuredCachePath = process.env.NEGOTIUM_CODEX_MODELS_CACHE_FILE;
|
|
1814
2037
|
if (configuredCachePath) {
|
|
1815
2038
|
if (!existsSync5(configuredCachePath)) {
|
|
@@ -1819,7 +2042,7 @@ async function ensureCodexModelCache(authFilePath, bootstrap = bootstrapCodexMod
|
|
|
1819
2042
|
return configuredCachePath;
|
|
1820
2043
|
}
|
|
1821
2044
|
const bundledCachePath = bundledCodexModelCachePath(authFilePath);
|
|
1822
|
-
const sharedCachePath =
|
|
2045
|
+
const sharedCachePath = join7(codexHome, "models_cache.json");
|
|
1823
2046
|
if (existsSync5(sharedCachePath)) {
|
|
1824
2047
|
try {
|
|
1825
2048
|
const shared = readCompatibleCodexModelCache(sharedCachePath);
|
|
@@ -1838,8 +2061,8 @@ async function ensureCodexModelCache(authFilePath, bootstrap = bootstrapCodexMod
|
|
|
1838
2061
|
return bundledCachePath;
|
|
1839
2062
|
}
|
|
1840
2063
|
function writeCodexCatalogWithNativeMultiAgentDisabled(authFilePath, sourcePath) {
|
|
1841
|
-
const codexHome =
|
|
1842
|
-
const outputPath =
|
|
2064
|
+
const codexHome = dirname4(authFilePath);
|
|
2065
|
+
const outputPath = join7(codexHome, NEGOTIUM_MODEL_CATALOG);
|
|
1843
2066
|
const parsed = readCodexModelCache(sourcePath).parsed;
|
|
1844
2067
|
const models = parsed.models.map((model, index) => {
|
|
1845
2068
|
if (!model || typeof model !== "object" || Array.isArray(model)) {
|
|
@@ -1866,9 +2089,9 @@ var init_codex_native_multi_agent = __esm(() => {
|
|
|
1866
2089
|
|
|
1867
2090
|
// ../../packages/core/src/security/sensitive-path.ts
|
|
1868
2091
|
import { realpathSync } from "fs";
|
|
1869
|
-
import { resolve as
|
|
2092
|
+
import { resolve as resolve4 } from "path";
|
|
1870
2093
|
function isSensitivePath(filePath) {
|
|
1871
|
-
const normalized =
|
|
2094
|
+
const normalized = resolve4(filePath);
|
|
1872
2095
|
if (SENSITIVE_PATH_PATTERNS.some((p) => p.test(normalized)))
|
|
1873
2096
|
return true;
|
|
1874
2097
|
try {
|
|
@@ -2388,12 +2611,12 @@ function createBackgroundBashManager(options = {}) {
|
|
|
2388
2611
|
usedPorts.clear();
|
|
2389
2612
|
knownContexts.clear();
|
|
2390
2613
|
const deadline = now() + 3000;
|
|
2391
|
-
await Promise.all(entries.map((instance) => new Promise((
|
|
2614
|
+
await Promise.all(entries.map((instance) => new Promise((resolve5) => {
|
|
2392
2615
|
if (instance.process.exitCode !== null || instance.process.killed)
|
|
2393
|
-
return
|
|
2394
|
-
instance.process.once("exit",
|
|
2395
|
-
instance.process.once("error",
|
|
2396
|
-
const timer = setTimeout(
|
|
2616
|
+
return resolve5();
|
|
2617
|
+
instance.process.once("exit", resolve5);
|
|
2618
|
+
instance.process.once("error", resolve5);
|
|
2619
|
+
const timer = setTimeout(resolve5, Math.max(0, deadline - now()));
|
|
2397
2620
|
timer.unref?.();
|
|
2398
2621
|
})));
|
|
2399
2622
|
}
|
|
@@ -3006,7 +3229,7 @@ var init_mcp_config = __esm(() => {
|
|
|
3006
3229
|
|
|
3007
3230
|
// ../../packages/core/src/agents/execution-host.ts
|
|
3008
3231
|
import { AsyncLocalStorage } from "async_hooks";
|
|
3009
|
-
import { dirname as
|
|
3232
|
+
import { dirname as dirname5 } from "path";
|
|
3010
3233
|
function activeHost() {
|
|
3011
3234
|
const scoped = scopedHost.getStore();
|
|
3012
3235
|
if (scoped)
|
|
@@ -3041,7 +3264,7 @@ function hostedCodexAuthFilePath() {
|
|
|
3041
3264
|
return activeHost().codexAuthFilePath();
|
|
3042
3265
|
}
|
|
3043
3266
|
function hostedCodexHomePath() {
|
|
3044
|
-
return
|
|
3267
|
+
return dirname5(hostedCodexAuthFilePath());
|
|
3045
3268
|
}
|
|
3046
3269
|
var defaultHost, hostRegistrations, scopedHost;
|
|
3047
3270
|
var init_execution_host = __esm(async () => {
|
|
@@ -3065,14 +3288,14 @@ var init_execution_host = __esm(async () => {
|
|
|
3065
3288
|
// ../../packages/core/src/agents/rollout/codex.ts
|
|
3066
3289
|
import { randomBytes as randomBytes4 } from "crypto";
|
|
3067
3290
|
import { existsSync as existsSync6, readFileSync as readFileSync5, realpathSync as realpathSync2, statSync as statSync2, unlinkSync as unlinkSync5 } from "fs";
|
|
3068
|
-
import { basename, dirname as
|
|
3291
|
+
import { basename, dirname as dirname6, join as join8, resolve as resolve5 } from "path";
|
|
3069
3292
|
function codexSessionsDir() {
|
|
3070
|
-
return
|
|
3293
|
+
return join8(hostedCodexHomePath(), "sessions");
|
|
3071
3294
|
}
|
|
3072
3295
|
function loadCodexShell() {
|
|
3073
3296
|
if (_shellCache)
|
|
3074
3297
|
return _shellCache;
|
|
3075
|
-
const raw = readFileSync5(
|
|
3298
|
+
const raw = readFileSync5(join8(FIXTURES_DIR, "codex-shell.jsonl"), "utf8");
|
|
3076
3299
|
const lines = parseJsonlText(raw);
|
|
3077
3300
|
if (lines.length < 5) {
|
|
3078
3301
|
throw new Error(`loadCodexShell: expected >=5 entries in codex-shell.jsonl, got ${lines.length}`);
|
|
@@ -3139,16 +3362,16 @@ function codexRolloutPath(threadId, fallback) {
|
|
|
3139
3362
|
const hh = String(createdAt.getHours()).padStart(2, "0");
|
|
3140
3363
|
const min = String(createdAt.getMinutes()).padStart(2, "0");
|
|
3141
3364
|
const ss = String(createdAt.getSeconds()).padStart(2, "0");
|
|
3142
|
-
const dir =
|
|
3143
|
-
return
|
|
3365
|
+
const dir = join8(codexSessionsDir(), yyyy, mm, dd);
|
|
3366
|
+
return join8(dir, `rollout-${yyyy}-${mm}-${dd}T${hh}-${min}-${ss}-${threadId}.jsonl`);
|
|
3144
3367
|
}
|
|
3145
3368
|
function canonicalFilePath(path) {
|
|
3146
|
-
const absolute =
|
|
3369
|
+
const absolute = resolve5(path);
|
|
3147
3370
|
try {
|
|
3148
3371
|
return realpathSync2(absolute);
|
|
3149
3372
|
} catch {
|
|
3150
3373
|
try {
|
|
3151
|
-
return
|
|
3374
|
+
return join8(realpathSync2(dirname6(absolute)), basename(absolute));
|
|
3152
3375
|
} catch {
|
|
3153
3376
|
return absolute;
|
|
3154
3377
|
}
|
|
@@ -3378,19 +3601,19 @@ function latestCodexRolloutPath(threadId) {
|
|
|
3378
3601
|
try {
|
|
3379
3602
|
if (buckets) {
|
|
3380
3603
|
for (const bucket of buckets) {
|
|
3381
|
-
const dir =
|
|
3604
|
+
const dir = join8(sessionsDir, bucket);
|
|
3382
3605
|
if (!existsSync6(dir))
|
|
3383
3606
|
continue;
|
|
3384
3607
|
const glob = new Bun.Glob(`rollout-*-${threadId}.jsonl`);
|
|
3385
3608
|
for (const rel of glob.scanSync({ cwd: dir, onlyFiles: true })) {
|
|
3386
|
-
candidates.push(
|
|
3609
|
+
candidates.push(join8(dir, rel));
|
|
3387
3610
|
}
|
|
3388
3611
|
}
|
|
3389
3612
|
}
|
|
3390
3613
|
if (candidates.length === 0) {
|
|
3391
3614
|
const glob = new Bun.Glob(`**/rollout-*-${threadId}.jsonl`);
|
|
3392
3615
|
for (const rel of glob.scanSync({ cwd: sessionsDir, onlyFiles: true })) {
|
|
3393
|
-
candidates.push(
|
|
3616
|
+
candidates.push(join8(sessionsDir, rel));
|
|
3394
3617
|
}
|
|
3395
3618
|
}
|
|
3396
3619
|
return candidates.sort((a, b) => statSync2(b).mtimeMs - statSync2(a).mtimeMs)[0];
|
|
@@ -3511,13 +3734,13 @@ function sweepPriorRolloutsForThread(threadId) {
|
|
|
3511
3734
|
return;
|
|
3512
3735
|
}
|
|
3513
3736
|
for (const bucket of buckets) {
|
|
3514
|
-
const dir =
|
|
3737
|
+
const dir = join8(sessionsDir, bucket);
|
|
3515
3738
|
if (!existsSync6(dir))
|
|
3516
3739
|
continue;
|
|
3517
3740
|
try {
|
|
3518
3741
|
const glob = new Bun.Glob(`rollout-*-${threadId}.jsonl`);
|
|
3519
3742
|
for (const rel of glob.scanSync({ cwd: dir, onlyFiles: true })) {
|
|
3520
|
-
const fullPath =
|
|
3743
|
+
const fullPath = join8(dir, rel);
|
|
3521
3744
|
try {
|
|
3522
3745
|
unlinkSync5(fullPath);
|
|
3523
3746
|
} catch (e) {
|
|
@@ -3535,7 +3758,7 @@ function sweepPriorRolloutsFullTree(threadId, sessionsDir) {
|
|
|
3535
3758
|
try {
|
|
3536
3759
|
const glob = new Bun.Glob(`**/rollout-*-${threadId}.jsonl`);
|
|
3537
3760
|
for (const rel of glob.scanSync({ cwd: sessionsDir, onlyFiles: true })) {
|
|
3538
|
-
const fullPath =
|
|
3761
|
+
const fullPath = join8(sessionsDir, rel);
|
|
3539
3762
|
try {
|
|
3540
3763
|
unlinkSync5(fullPath);
|
|
3541
3764
|
} catch (e) {
|
|
@@ -3601,7 +3824,7 @@ import { spawn as spawn3 } from "child_process";
|
|
|
3601
3824
|
function createCodexAppServerForker(host) {
|
|
3602
3825
|
return async (parentThreadId) => {
|
|
3603
3826
|
const child = host.spawnServer();
|
|
3604
|
-
return await new Promise((
|
|
3827
|
+
return await new Promise((resolve6, reject) => {
|
|
3605
3828
|
let settled = false;
|
|
3606
3829
|
let stdoutBuffer = "";
|
|
3607
3830
|
let stderr = "";
|
|
@@ -3618,7 +3841,7 @@ function createCodexAppServerForker(host) {
|
|
|
3618
3841
|
if (error)
|
|
3619
3842
|
reject(error);
|
|
3620
3843
|
else if (result)
|
|
3621
|
-
|
|
3844
|
+
resolve6(result);
|
|
3622
3845
|
else
|
|
3623
3846
|
reject(new Error("Codex thread fork returned no result"));
|
|
3624
3847
|
};
|
|
@@ -3715,7 +3938,7 @@ var init_codex_app_server = __esm(async () => {
|
|
|
3715
3938
|
|
|
3716
3939
|
// ../../packages/core/src/agents/codex-registry.ts
|
|
3717
3940
|
import { existsSync as existsSync7, unlinkSync as unlinkSync6 } from "fs";
|
|
3718
|
-
import { join as
|
|
3941
|
+
import { join as join9 } from "path";
|
|
3719
3942
|
var VALID_EFFORTS2, codexRegistry, codexRegistryOperations;
|
|
3720
3943
|
var init_codex_registry = __esm(async () => {
|
|
3721
3944
|
init_logger();
|
|
@@ -3760,7 +3983,7 @@ var init_codex_registry = __esm(async () => {
|
|
|
3760
3983
|
async cleanupRollouts({ sessionIds }) {
|
|
3761
3984
|
if (sessionIds.length === 0)
|
|
3762
3985
|
return;
|
|
3763
|
-
const sessionsDir =
|
|
3986
|
+
const sessionsDir = join9(hostedCodexHomePath(), "sessions");
|
|
3764
3987
|
if (!existsSync7(sessionsDir))
|
|
3765
3988
|
return;
|
|
3766
3989
|
const failures = [];
|
|
@@ -3768,7 +3991,7 @@ var init_codex_registry = __esm(async () => {
|
|
|
3768
3991
|
try {
|
|
3769
3992
|
const glob = new Bun.Glob(`**/rollout-*-${tid}.jsonl`);
|
|
3770
3993
|
for await (const rel of glob.scan({ cwd: sessionsDir, onlyFiles: true })) {
|
|
3771
|
-
const path =
|
|
3994
|
+
const path = join9(sessionsDir, rel);
|
|
3772
3995
|
try {
|
|
3773
3996
|
unlinkSync6(path);
|
|
3774
3997
|
} catch (e) {
|
|
@@ -3792,17 +4015,17 @@ var init_codex_registry = __esm(async () => {
|
|
|
3792
4015
|
|
|
3793
4016
|
// ../../packages/core/src/agents/maestro-registry.ts
|
|
3794
4017
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
3795
|
-
import { existsSync as existsSync8, mkdirSync as
|
|
3796
|
-
import { homedir as
|
|
3797
|
-
import { join as
|
|
4018
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync7, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
|
|
4019
|
+
import { homedir as homedir6 } from "os";
|
|
4020
|
+
import { join as join10, resolve as resolve6 } from "path";
|
|
3798
4021
|
function maestroSessionsDir() {
|
|
3799
|
-
return
|
|
4022
|
+
return join10(process.env.MAESTRO_DATA_DIR ? resolve6(process.env.MAESTRO_DATA_DIR) : join10(homedir6(), ".maestro"), "sessions");
|
|
3800
4023
|
}
|
|
3801
4024
|
function maestroSessionPath(sessionId) {
|
|
3802
|
-
return
|
|
4025
|
+
return join10(maestroSessionsDir(), `${sessionId}.jsonl`);
|
|
3803
4026
|
}
|
|
3804
4027
|
function maestroActiveSessionPath(sessionId) {
|
|
3805
|
-
return
|
|
4028
|
+
return join10(maestroSessionsDir(), `${sessionId}.active.jsonl`);
|
|
3806
4029
|
}
|
|
3807
4030
|
function existingCreatedAt(path) {
|
|
3808
4031
|
if (!existsSync8(path))
|
|
@@ -3824,7 +4047,7 @@ function writeRollout(options) {
|
|
|
3824
4047
|
assertUuidLike("sessionId", sessionId);
|
|
3825
4048
|
ensureCwdExists(options.cwd);
|
|
3826
4049
|
const path = maestroSessionPath(sessionId);
|
|
3827
|
-
|
|
4050
|
+
mkdirSync7(maestroSessionsDir(), { recursive: true });
|
|
3828
4051
|
const messages = extractChatPairs(options.entries).flatMap((pair) => [
|
|
3829
4052
|
{ role: "user", content: nonEmptyTurnText(pair.userText) },
|
|
3830
4053
|
{ role: "assistant", content: nonEmptyTurnText(pair.assistantText) }
|
|
@@ -4026,200 +4249,6 @@ function sanitizeId(id) {
|
|
|
4026
4249
|
return id.replace(/[^a-zA-Z0-9_-]/g, "_") || "_";
|
|
4027
4250
|
}
|
|
4028
4251
|
|
|
4029
|
-
// ../../packages/core/src/storage/storage-host.ts
|
|
4030
|
-
import { mkdirSync as mkdirSync7 } from "fs";
|
|
4031
|
-
import { homedir as homedir6 } from "os";
|
|
4032
|
-
import { dirname as dirname6, join as join10, resolve as resolve6 } from "path";
|
|
4033
|
-
function envPath(name, fallback) {
|
|
4034
|
-
const value = process.env[name]?.trim();
|
|
4035
|
-
return resolve6(value || fallback);
|
|
4036
|
-
}
|
|
4037
|
-
function defaultStateDir() {
|
|
4038
|
-
return envPath("NEGOTIUM_STATE_DIR", join10(homedir6(), ".negotium"));
|
|
4039
|
-
}
|
|
4040
|
-
function defaultDataDir() {
|
|
4041
|
-
return envPath("NEGOTIUM_DATA_DIR", join10(defaultStateDir(), "data"));
|
|
4042
|
-
}
|
|
4043
|
-
function defaultLogDir() {
|
|
4044
|
-
return envPath("NEGOTIUM_LOG_DIR", join10(defaultStateDir(), "logs"));
|
|
4045
|
-
}
|
|
4046
|
-
function defaultWorkspaceDir() {
|
|
4047
|
-
return envPath("NEGOTIUM_WORKSPACE_DIR", join10(defaultStateDir(), "workspace"));
|
|
4048
|
-
}
|
|
4049
|
-
function defaultSessionAsksDir() {
|
|
4050
|
-
const runDir = envPath("NEGOTIUM_RUN_DIR", join10(defaultStateDir(), "runtime"));
|
|
4051
|
-
return join10(runDir, "session-asks");
|
|
4052
|
-
}
|
|
4053
|
-
function defaultSessionsDatabasePath() {
|
|
4054
|
-
return envPath("SESSIONS_DB_PATH", join10(resolveStorageDataDir(), "sessions.db"));
|
|
4055
|
-
}
|
|
4056
|
-
function isSqliteBusy(error) {
|
|
4057
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
4058
|
-
return /database is (?:locked|busy)|SQLITE_(?:BUSY|LOCKED)/i.test(message);
|
|
4059
|
-
}
|
|
4060
|
-
function execWithBusyRetry(database, sql, timeoutMs = SQLITE_INIT_TIMEOUT_MS) {
|
|
4061
|
-
const deadline = Date.now() + timeoutMs;
|
|
4062
|
-
while (true) {
|
|
4063
|
-
try {
|
|
4064
|
-
database.exec(sql);
|
|
4065
|
-
return;
|
|
4066
|
-
} catch (error) {
|
|
4067
|
-
if (!isSqliteBusy(error) || Date.now() >= deadline)
|
|
4068
|
-
throw error;
|
|
4069
|
-
Atomics.wait(SQLITE_INIT_SLEEP, 0, 0, Math.min(SQLITE_INIT_RETRY_MS, deadline - Date.now()));
|
|
4070
|
-
}
|
|
4071
|
-
}
|
|
4072
|
-
}
|
|
4073
|
-
function initializeDatabase(database) {
|
|
4074
|
-
database.exec("PRAGMA busy_timeout = 5000");
|
|
4075
|
-
execWithBusyRetry(database, "PRAGMA journal_mode = WAL");
|
|
4076
|
-
database.exec("PRAGMA foreign_keys = ON");
|
|
4077
|
-
database.exec("PRAGMA wal_autocheckpoint = 1000");
|
|
4078
|
-
try {
|
|
4079
|
-
database.exec("PRAGMA wal_checkpoint(TRUNCATE)");
|
|
4080
|
-
} catch {}
|
|
4081
|
-
}
|
|
4082
|
-
function defaultDatabase() {
|
|
4083
|
-
const path = defaultSessionsDatabasePath();
|
|
4084
|
-
if (fallbackDatabase && fallbackDatabasePath === path)
|
|
4085
|
-
return fallbackDatabase;
|
|
4086
|
-
if (fallbackDatabase)
|
|
4087
|
-
fallbackDatabase.close();
|
|
4088
|
-
mkdirSync7(dirname6(path), { recursive: true });
|
|
4089
|
-
fallbackDatabase = new Database(path, { create: true });
|
|
4090
|
-
fallbackDatabasePath = path;
|
|
4091
|
-
initializeDatabase(fallbackDatabase);
|
|
4092
|
-
return fallbackDatabase;
|
|
4093
|
-
}
|
|
4094
|
-
function resolveStorageDatabase() {
|
|
4095
|
-
return configuredHost.database ?? defaultDatabase();
|
|
4096
|
-
}
|
|
4097
|
-
function resolveStorageDataDir() {
|
|
4098
|
-
return configuredHost.dataDir ?? defaultDataDir();
|
|
4099
|
-
}
|
|
4100
|
-
function resolveStorageLogDir() {
|
|
4101
|
-
return configuredHost.logDir ?? defaultLogDir();
|
|
4102
|
-
}
|
|
4103
|
-
function resolveStorageSessionAsksDir() {
|
|
4104
|
-
return configuredHost.sessionAsksDir ?? defaultSessionAsksDir();
|
|
4105
|
-
}
|
|
4106
|
-
function resolveStorageWorkspaceDir() {
|
|
4107
|
-
return configuredHost.workspaceDir ?? defaultWorkspaceDir();
|
|
4108
|
-
}
|
|
4109
|
-
function resolveStorageSharedWikiDir() {
|
|
4110
|
-
return configuredHost.sharedWikiDir ?? join10(resolveStorageWorkspaceDir(), "wiki");
|
|
4111
|
-
}
|
|
4112
|
-
function resolveStorageUsersLogDir() {
|
|
4113
|
-
return configuredHost.usersLogDir ?? join10(resolveStorageDataDir(), "users");
|
|
4114
|
-
}
|
|
4115
|
-
function normalizeStorageHostPatch(options) {
|
|
4116
|
-
const patch = {};
|
|
4117
|
-
if (options.database !== undefined) {
|
|
4118
|
-
options.database.exec("PRAGMA foreign_keys = ON");
|
|
4119
|
-
patch.database = options.database;
|
|
4120
|
-
}
|
|
4121
|
-
for (const key of STORAGE_PATH_KEYS) {
|
|
4122
|
-
const value = options[key];
|
|
4123
|
-
if (value === undefined)
|
|
4124
|
-
continue;
|
|
4125
|
-
if (!value.trim())
|
|
4126
|
-
throw new TypeError(`${key} must not be empty`);
|
|
4127
|
-
patch[key] = resolve6(value);
|
|
4128
|
-
}
|
|
4129
|
-
return Object.freeze(patch);
|
|
4130
|
-
}
|
|
4131
|
-
function refreshConfiguredHost() {
|
|
4132
|
-
configuredHost = Object.freeze(Object.assign({}, ...storageHostFrames.filter((frame) => frame.active).map((frame) => frame.patch)));
|
|
4133
|
-
}
|
|
4134
|
-
function configureStorageHost(options) {
|
|
4135
|
-
const frame = { active: true, patch: normalizeStorageHostPatch(options) };
|
|
4136
|
-
storageHostFrames.push(frame);
|
|
4137
|
-
refreshConfiguredHost();
|
|
4138
|
-
return () => {
|
|
4139
|
-
if (!frame.active)
|
|
4140
|
-
return;
|
|
4141
|
-
frame.active = false;
|
|
4142
|
-
const index = storageHostFrames.indexOf(frame);
|
|
4143
|
-
if (index >= 0)
|
|
4144
|
-
storageHostFrames.splice(index, 1);
|
|
4145
|
-
refreshConfiguredHost();
|
|
4146
|
-
};
|
|
4147
|
-
}
|
|
4148
|
-
function resetStorageHost() {
|
|
4149
|
-
for (const frame of storageHostFrames)
|
|
4150
|
-
frame.active = false;
|
|
4151
|
-
storageHostFrames.length = 0;
|
|
4152
|
-
refreshConfiguredHost();
|
|
4153
|
-
}
|
|
4154
|
-
function closeStorageDatabase() {
|
|
4155
|
-
if (!fallbackDatabase)
|
|
4156
|
-
return;
|
|
4157
|
-
fallbackDatabase.close();
|
|
4158
|
-
fallbackDatabase = null;
|
|
4159
|
-
fallbackDatabasePath = null;
|
|
4160
|
-
}
|
|
4161
|
-
function registerStorageSchemaInitializer(initialize, priority = 100) {
|
|
4162
|
-
schemaInitializers.push({ initialize, priority });
|
|
4163
|
-
schemaInitializers.sort((a, b) => a.priority - b.priority);
|
|
4164
|
-
}
|
|
4165
|
-
function ensureStorageSchemas(database = resolveStorageDatabase()) {
|
|
4166
|
-
if (initializingDatabases.has(database))
|
|
4167
|
-
return;
|
|
4168
|
-
let initialized = initializedSchemas.get(database);
|
|
4169
|
-
if (!initialized) {
|
|
4170
|
-
initialized = new Set;
|
|
4171
|
-
initializedSchemas.set(database, initialized);
|
|
4172
|
-
}
|
|
4173
|
-
initializingDatabases.add(database);
|
|
4174
|
-
try {
|
|
4175
|
-
for (const entry of schemaInitializers) {
|
|
4176
|
-
if (initialized.has(entry.initialize))
|
|
4177
|
-
continue;
|
|
4178
|
-
initialized.add(entry.initialize);
|
|
4179
|
-
try {
|
|
4180
|
-
entry.initialize(database);
|
|
4181
|
-
} catch (error) {
|
|
4182
|
-
initialized.delete(entry.initialize);
|
|
4183
|
-
throw error;
|
|
4184
|
-
}
|
|
4185
|
-
}
|
|
4186
|
-
} finally {
|
|
4187
|
-
initializingDatabases.delete(database);
|
|
4188
|
-
}
|
|
4189
|
-
}
|
|
4190
|
-
var configuredHost, fallbackDatabase = null, fallbackDatabasePath = null, storageHostFrames, schemaInitializers, initializedSchemas, initializingDatabases, SQLITE_INIT_RETRY_MS = 25, SQLITE_INIT_TIMEOUT_MS = 5000, SQLITE_INIT_SLEEP, STORAGE_PATH_KEYS, internalStorageDatabase, storageDatabase;
|
|
4191
|
-
var init_storage_host = __esm(async () => {
|
|
4192
|
-
await init_sqlite();
|
|
4193
|
-
configuredHost = {};
|
|
4194
|
-
storageHostFrames = [];
|
|
4195
|
-
schemaInitializers = [];
|
|
4196
|
-
initializedSchemas = new WeakMap;
|
|
4197
|
-
initializingDatabases = new WeakSet;
|
|
4198
|
-
SQLITE_INIT_SLEEP = new Int32Array(new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT));
|
|
4199
|
-
STORAGE_PATH_KEYS = [
|
|
4200
|
-
"dataDir",
|
|
4201
|
-
"logDir",
|
|
4202
|
-
"sessionAsksDir",
|
|
4203
|
-
"workspaceDir",
|
|
4204
|
-
"sharedWikiDir",
|
|
4205
|
-
"usersLogDir"
|
|
4206
|
-
];
|
|
4207
|
-
internalStorageDatabase = new Proxy({}, {
|
|
4208
|
-
get(_target, property) {
|
|
4209
|
-
const database = resolveStorageDatabase();
|
|
4210
|
-
ensureStorageSchemas(database);
|
|
4211
|
-
const value = Reflect.get(database, property, database);
|
|
4212
|
-
return typeof value === "function" ? value.bind(database) : value;
|
|
4213
|
-
},
|
|
4214
|
-
set(_target, property, value) {
|
|
4215
|
-
const database = resolveStorageDatabase();
|
|
4216
|
-
ensureStorageSchemas(database);
|
|
4217
|
-
return Reflect.set(database, property, value, database);
|
|
4218
|
-
}
|
|
4219
|
-
});
|
|
4220
|
-
storageDatabase = internalStorageDatabase;
|
|
4221
|
-
});
|
|
4222
|
-
|
|
4223
4252
|
// ../../packages/core/src/storage/tasks.ts
|
|
4224
4253
|
var exports_tasks = {};
|
|
4225
4254
|
__export(exports_tasks, {
|
|
@@ -6745,7 +6774,10 @@ function listRecentRuntimeEventsForTopic(topicId, limit = 300) {
|
|
|
6745
6774
|
}
|
|
6746
6775
|
var RUNTIME_EVENT_TYPES, types;
|
|
6747
6776
|
var init_runtime_events = __esm(async () => {
|
|
6748
|
-
await
|
|
6777
|
+
await __promiseAll([
|
|
6778
|
+
init_forum_db(),
|
|
6779
|
+
init_storage_host()
|
|
6780
|
+
]);
|
|
6749
6781
|
RUNTIME_EVENT_TYPES = [
|
|
6750
6782
|
"message",
|
|
6751
6783
|
"message-updated",
|
|
@@ -6754,26 +6786,28 @@ var init_runtime_events = __esm(async () => {
|
|
|
6754
6786
|
"topic-updated",
|
|
6755
6787
|
"topic-deleted"
|
|
6756
6788
|
];
|
|
6757
|
-
|
|
6758
|
-
|
|
6759
|
-
|
|
6760
|
-
|
|
6761
|
-
|
|
6762
|
-
event_type
|
|
6763
|
-
|
|
6764
|
-
|
|
6765
|
-
|
|
6766
|
-
|
|
6767
|
-
|
|
6768
|
-
|
|
6769
|
-
|
|
6770
|
-
|
|
6771
|
-
|
|
6772
|
-
|
|
6773
|
-
|
|
6774
|
-
|
|
6775
|
-
|
|
6776
|
-
|
|
6789
|
+
registerStorageSchemaInitializer((database) => {
|
|
6790
|
+
database.exec(`
|
|
6791
|
+
CREATE TABLE IF NOT EXISTS runtime_events (
|
|
6792
|
+
seq INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
6793
|
+
source_id TEXT NOT NULL,
|
|
6794
|
+
event_type TEXT NOT NULL CHECK (
|
|
6795
|
+
event_type IN (
|
|
6796
|
+
'message',
|
|
6797
|
+
'message-updated',
|
|
6798
|
+
'ai-status',
|
|
6799
|
+
'topic-created',
|
|
6800
|
+
'topic-updated',
|
|
6801
|
+
'topic-deleted'
|
|
6802
|
+
)
|
|
6803
|
+
),
|
|
6804
|
+
topic_id TEXT NOT NULL,
|
|
6805
|
+
payload_json TEXT NOT NULL,
|
|
6806
|
+
created_at TEXT NOT NULL
|
|
6807
|
+
)
|
|
6808
|
+
`);
|
|
6809
|
+
database.exec("CREATE INDEX IF NOT EXISTS idx_runtime_events_topic_seq ON runtime_events(topic_id, seq)");
|
|
6810
|
+
});
|
|
6777
6811
|
types = new Set(RUNTIME_EVENT_TYPES);
|
|
6778
6812
|
});
|
|
6779
6813
|
|
|
@@ -6934,18 +6968,19 @@ class SqliteRuntimeBus {
|
|
|
6934
6968
|
}
|
|
6935
6969
|
}
|
|
6936
6970
|
function runtimeBus() {
|
|
6971
|
+
if (!current)
|
|
6972
|
+
current = new SqliteRuntimeBus;
|
|
6937
6973
|
return current;
|
|
6938
6974
|
}
|
|
6939
6975
|
function setRuntimeBus(bus) {
|
|
6940
6976
|
current = bus;
|
|
6941
6977
|
}
|
|
6942
|
-
var current, WsHub;
|
|
6978
|
+
var current = null, WsHub;
|
|
6943
6979
|
var init_bus = __esm(async () => {
|
|
6944
6980
|
await init_runtime_events();
|
|
6945
|
-
current = new SqliteRuntimeBus;
|
|
6946
6981
|
WsHub = {
|
|
6947
6982
|
get() {
|
|
6948
|
-
return
|
|
6983
|
+
return runtimeBus();
|
|
6949
6984
|
}
|
|
6950
6985
|
};
|
|
6951
6986
|
});
|
|
@@ -7479,6 +7514,7 @@ var exports_api_topics = {};
|
|
|
7479
7514
|
__export(exports_api_topics, {
|
|
7480
7515
|
upsertTopic: () => upsertTopic,
|
|
7481
7516
|
setTopicSessionId: () => setTopicSessionId,
|
|
7517
|
+
setTopicAccessModes: () => setTopicAccessModes,
|
|
7482
7518
|
setApiTopicAgent: () => setApiTopicAgent,
|
|
7483
7519
|
revokeSubagentTellTarget: () => revokeSubagentTellTarget,
|
|
7484
7520
|
reparentTopicChildren: () => reparentTopicChildren,
|
|
@@ -7945,6 +7981,16 @@ function upsertTopic(t) {
|
|
|
7945
7981
|
}
|
|
7946
7982
|
})();
|
|
7947
7983
|
}
|
|
7984
|
+
function setTopicAccessModes(topicIds, accessMode) {
|
|
7985
|
+
if (topicIds.length === 0)
|
|
7986
|
+
return;
|
|
7987
|
+
const normalized = normalizeTopicAccessMode(accessMode);
|
|
7988
|
+
db.transaction(() => {
|
|
7989
|
+
const update = db.query("UPDATE api_topics SET access_mode = ? WHERE id = ?");
|
|
7990
|
+
for (const topicId of topicIds)
|
|
7991
|
+
update.run(normalized, topicId);
|
|
7992
|
+
})();
|
|
7993
|
+
}
|
|
7948
7994
|
function listTopics() {
|
|
7949
7995
|
const rows = db.query("SELECT * FROM api_topics ORDER BY last_message_at DESC").all();
|
|
7950
7996
|
const participants = getAllTopicParticipants();
|
|
@@ -9525,32 +9571,35 @@ var init_self_schedules = __esm(async () => {
|
|
|
9525
9571
|
await __promiseAll([
|
|
9526
9572
|
init_forum_db(),
|
|
9527
9573
|
init_runtime_leases(),
|
|
9528
|
-
init_runtime_topic_state()
|
|
9574
|
+
init_runtime_topic_state(),
|
|
9575
|
+
init_storage_host()
|
|
9529
9576
|
]);
|
|
9530
|
-
|
|
9531
|
-
|
|
9532
|
-
|
|
9533
|
-
|
|
9534
|
-
|
|
9535
|
-
|
|
9536
|
-
|
|
9537
|
-
|
|
9538
|
-
|
|
9539
|
-
|
|
9540
|
-
|
|
9541
|
-
|
|
9542
|
-
|
|
9543
|
-
|
|
9544
|
-
|
|
9545
|
-
|
|
9546
|
-
|
|
9547
|
-
|
|
9548
|
-
|
|
9549
|
-
|
|
9550
|
-
|
|
9551
|
-
|
|
9552
|
-
|
|
9553
|
-
|
|
9577
|
+
registerStorageSchemaInitializer((database) => {
|
|
9578
|
+
database.exec(`
|
|
9579
|
+
CREATE TABLE IF NOT EXISTS runtime_self_schedules (
|
|
9580
|
+
id TEXT PRIMARY KEY,
|
|
9581
|
+
topic_id TEXT NOT NULL,
|
|
9582
|
+
user_id TEXT NOT NULL,
|
|
9583
|
+
message TEXT NOT NULL,
|
|
9584
|
+
deliver_at INTEGER NOT NULL,
|
|
9585
|
+
created_at INTEGER NOT NULL,
|
|
9586
|
+
updated_at INTEGER NOT NULL,
|
|
9587
|
+
status TEXT NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'running')),
|
|
9588
|
+
claimed_by TEXT,
|
|
9589
|
+
claimed_at INTEGER,
|
|
9590
|
+
running_query_id TEXT
|
|
9591
|
+
)
|
|
9592
|
+
`);
|
|
9593
|
+
database.exec(`
|
|
9594
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_runtime_self_schedules_one_pending
|
|
9595
|
+
ON runtime_self_schedules(topic_id)
|
|
9596
|
+
WHERE status = 'pending'
|
|
9597
|
+
`);
|
|
9598
|
+
database.exec(`
|
|
9599
|
+
CREATE INDEX IF NOT EXISTS idx_runtime_self_schedules_due
|
|
9600
|
+
ON runtime_self_schedules(status, deliver_at)
|
|
9601
|
+
`);
|
|
9602
|
+
});
|
|
9554
9603
|
});
|
|
9555
9604
|
|
|
9556
9605
|
// ../../packages/core/src/topics/links.ts
|
|
@@ -10240,15 +10289,20 @@ function deleteBrowserProfile(ownerId, rawName) {
|
|
|
10240
10289
|
}
|
|
10241
10290
|
var DEFAULT_BROWSER_PROFILE = "default";
|
|
10242
10291
|
var init_browser_profiles = __esm(async () => {
|
|
10243
|
-
await
|
|
10244
|
-
|
|
10245
|
-
|
|
10246
|
-
|
|
10247
|
-
|
|
10248
|
-
|
|
10249
|
-
|
|
10250
|
-
|
|
10251
|
-
|
|
10292
|
+
await __promiseAll([
|
|
10293
|
+
init_forum_db(),
|
|
10294
|
+
init_storage_host()
|
|
10295
|
+
]);
|
|
10296
|
+
registerStorageSchemaInitializer((database) => {
|
|
10297
|
+
database.exec(`
|
|
10298
|
+
CREATE TABLE IF NOT EXISTS browser_profiles (
|
|
10299
|
+
owner_id TEXT NOT NULL,
|
|
10300
|
+
name TEXT NOT NULL,
|
|
10301
|
+
created_at TEXT NOT NULL,
|
|
10302
|
+
PRIMARY KEY (owner_id, name)
|
|
10303
|
+
)
|
|
10304
|
+
`);
|
|
10305
|
+
});
|
|
10252
10306
|
});
|
|
10253
10307
|
|
|
10254
10308
|
// ../../packages/core/src/platform/playwright/manager.ts
|
|
@@ -11977,9 +12031,9 @@ function formatArchiverBytes(bytes) {
|
|
|
11977
12031
|
function formatArchiverTool(name, input) {
|
|
11978
12032
|
const params = Object.entries(input).map(([key, value]) => {
|
|
11979
12033
|
const rendered = typeof value === "string" ? value : JSON.stringify(value);
|
|
11980
|
-
return `${key}: ${sessionText(rendered ?? "")}`;
|
|
12034
|
+
return `${key}: ${summarizeDisplayText(sessionText(rendered ?? ""))}`;
|
|
11981
12035
|
}).join(", ");
|
|
11982
|
-
return `${name}${params ? `(${params})` : ""}
|
|
12036
|
+
return summarizeDisplayText(`${name}${params ? `(${params})` : ""}`);
|
|
11983
12037
|
}
|
|
11984
12038
|
function createArchiverRuntime(host) {
|
|
11985
12039
|
const activeSessions = new Map;
|
|
@@ -12289,6 +12343,7 @@ function listActiveMemoryArchiverSessions(userId) {
|
|
|
12289
12343
|
}
|
|
12290
12344
|
var MAX_BRIEF_ENTRIES = 8, defaultArchiverRuntime;
|
|
12291
12345
|
var init_archiver = __esm(async () => {
|
|
12346
|
+
init_tool_format();
|
|
12292
12347
|
init_config();
|
|
12293
12348
|
init_logger();
|
|
12294
12349
|
init_builders();
|
|
@@ -13096,7 +13151,7 @@ function detailedToolStep(payload) {
|
|
|
13096
13151
|
const label = compactToolLabel(String(payload.label ?? name));
|
|
13097
13152
|
if (shortName === "ask_session" || shortName === "tell_session") {
|
|
13098
13153
|
const target = typeof input.to === "string" && input.to.trim() ? input.to.trim() : "session";
|
|
13099
|
-
const msg = typeof input.message === "string" ? text(input.message) : "";
|
|
13154
|
+
const msg = typeof input.message === "string" ? summarizeDisplayText(text(input.message)) : "";
|
|
13100
13155
|
const action = shortName === "ask_session" ? "Ask" : "Tell";
|
|
13101
13156
|
return `${action} ${target}${msg ? ` \u2014 ${msg}` : ""}`;
|
|
13102
13157
|
}
|
|
@@ -13122,22 +13177,22 @@ function detailedToolStep(payload) {
|
|
|
13122
13177
|
return `${action} file`;
|
|
13123
13178
|
}
|
|
13124
13179
|
if (shortName === "grep" || shortName === "glob") {
|
|
13125
|
-
const pattern = typeof input.pattern === "string" ? input.pattern : "";
|
|
13180
|
+
const pattern = typeof input.pattern === "string" ? summarizeDisplayText(text(input.pattern)) : "";
|
|
13126
13181
|
const action = shortName === "grep" ? "Grep" : "Glob";
|
|
13127
13182
|
if (pattern)
|
|
13128
|
-
return `${action} '${
|
|
13183
|
+
return `${action} '${pattern}'${path ? ` in ${path}` : ""}`;
|
|
13129
13184
|
if (path)
|
|
13130
13185
|
return `${action} ${path}`;
|
|
13131
13186
|
}
|
|
13132
13187
|
if (shortName === "bash") {
|
|
13133
|
-
const cmd = typeof input.command === "string" ? text(input.command) : "";
|
|
13188
|
+
const cmd = typeof input.command === "string" ? summarizeDisplayText(text(input.command)) : "";
|
|
13134
13189
|
return cmd ? `Bash: ${cmd}` : "Bash";
|
|
13135
13190
|
}
|
|
13136
13191
|
if (shortName === "webfetch" || shortName === "url_fetch") {
|
|
13137
|
-
const url = typeof input.url === "string" ? text(input.url) : "";
|
|
13192
|
+
const url = typeof input.url === "string" ? summarizeDisplayText(text(input.url)) : "";
|
|
13138
13193
|
return url ? `Fetch ${url}` : "WebFetch";
|
|
13139
13194
|
}
|
|
13140
|
-
return label;
|
|
13195
|
+
return summarizeDisplayText(label);
|
|
13141
13196
|
}
|
|
13142
13197
|
function backgroundSessionProgress(topicId, queryId) {
|
|
13143
13198
|
let status = "Running";
|
|
@@ -13165,7 +13220,7 @@ function backgroundSessionProgress(topicId, queryId) {
|
|
|
13165
13220
|
step = text(payload.content);
|
|
13166
13221
|
else if (kind === "tool_output") {
|
|
13167
13222
|
const toolName = toolNames.get(text(payload.toolUseId)) ?? "Tool";
|
|
13168
|
-
step = payload.isError ? `${toolName} failed: ${text(payload.content) || "unknown error"}` : `${toolName} result \xB7 ${byteSize(payload.content)}`;
|
|
13223
|
+
step = payload.isError ? `${toolName} failed: ${summarizeDisplayText(text(payload.content)) || "unknown error"}` : `${toolName} result \xB7 ${byteSize(payload.content)}`;
|
|
13169
13224
|
} else if (kind === "ai_done") {
|
|
13170
13225
|
const usage = payload.usage && typeof payload.usage === "object" ? payload.usage : undefined;
|
|
13171
13226
|
const input = typeof usage?.input === "number" ? usage.input.toLocaleString() : "";
|
|
@@ -13230,6 +13285,7 @@ function listBackgroundSessionsForUser(userId) {
|
|
|
13230
13285
|
}
|
|
13231
13286
|
var providers, transientSessions;
|
|
13232
13287
|
var init_background_sessions = __esm(async () => {
|
|
13288
|
+
init_tool_format();
|
|
13233
13289
|
init_background_session_policy();
|
|
13234
13290
|
await __promiseAll([
|
|
13235
13291
|
init_archiver(),
|
|
@@ -13535,10 +13591,11 @@ var init_runtime_turn_requests = __esm(async () => {
|
|
|
13535
13591
|
await __promiseAll([
|
|
13536
13592
|
init_forum_db(),
|
|
13537
13593
|
init_runtime_leases(),
|
|
13538
|
-
init_runtime_topic_state()
|
|
13594
|
+
init_runtime_topic_state(),
|
|
13595
|
+
init_storage_host()
|
|
13539
13596
|
]);
|
|
13540
13597
|
REQUEST_CLAIM_STALE_MS = TURN_LEASE_STALE_MS;
|
|
13541
|
-
ensureRuntimeUserTurnRequestsSchema(
|
|
13598
|
+
registerStorageSchemaInitializer((database) => ensureRuntimeUserTurnRequestsSchema(database));
|
|
13542
13599
|
});
|
|
13543
13600
|
|
|
13544
13601
|
// ../../packages/core/src/topics/session.ts
|
|
@@ -15800,19 +15857,22 @@ var pendingAsks, MAX_ASK_AGE_MS;
|
|
|
15800
15857
|
var init_ask_callbacks = __esm(async () => {
|
|
15801
15858
|
await __promiseAll([
|
|
15802
15859
|
init_forum_db(),
|
|
15803
|
-
init_session_asks()
|
|
15860
|
+
init_session_asks(),
|
|
15861
|
+
init_storage_host()
|
|
15804
15862
|
]);
|
|
15805
|
-
|
|
15806
|
-
|
|
15807
|
-
|
|
15808
|
-
|
|
15809
|
-
|
|
15810
|
-
|
|
15811
|
-
|
|
15812
|
-
|
|
15813
|
-
|
|
15814
|
-
|
|
15815
|
-
|
|
15863
|
+
registerStorageSchemaInitializer((database) => {
|
|
15864
|
+
database.exec(`
|
|
15865
|
+
CREATE TABLE IF NOT EXISTS remote_ask_callbacks (
|
|
15866
|
+
target_query_id TEXT PRIMARY KEY,
|
|
15867
|
+
request_id TEXT NOT NULL,
|
|
15868
|
+
node_name TEXT NOT NULL,
|
|
15869
|
+
node_cell_id TEXT NOT NULL,
|
|
15870
|
+
topic_id TEXT NOT NULL,
|
|
15871
|
+
user_id TEXT NOT NULL,
|
|
15872
|
+
created_at INTEGER NOT NULL
|
|
15873
|
+
)
|
|
15874
|
+
`);
|
|
15875
|
+
});
|
|
15816
15876
|
pendingAsks = new Map;
|
|
15817
15877
|
MAX_ASK_AGE_MS = PENDING_ASK_TTL_MS;
|
|
15818
15878
|
});
|
|
@@ -16034,30 +16094,35 @@ paint();document.body.appendChild(b)}
|
|
|
16034
16094
|
if(document.readyState==="loading")document.addEventListener("DOMContentLoaded",init);else init()})();
|
|
16035
16095
|
</script>`;
|
|
16036
16096
|
var init_visual_store = __esm(async () => {
|
|
16037
|
-
await
|
|
16038
|
-
|
|
16039
|
-
|
|
16040
|
-
|
|
16041
|
-
|
|
16042
|
-
|
|
16043
|
-
|
|
16044
|
-
|
|
16045
|
-
|
|
16046
|
-
|
|
16047
|
-
|
|
16048
|
-
|
|
16049
|
-
|
|
16050
|
-
|
|
16051
|
-
|
|
16052
|
-
|
|
16053
|
-
|
|
16054
|
-
|
|
16055
|
-
|
|
16056
|
-
|
|
16057
|
-
|
|
16058
|
-
|
|
16059
|
-
|
|
16060
|
-
|
|
16097
|
+
await __promiseAll([
|
|
16098
|
+
init_forum_db(),
|
|
16099
|
+
init_storage_host()
|
|
16100
|
+
]);
|
|
16101
|
+
registerStorageSchemaInitializer((database) => {
|
|
16102
|
+
database.exec(`
|
|
16103
|
+
CREATE TABLE IF NOT EXISTS api_topic_visuals (
|
|
16104
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
16105
|
+
topic_id TEXT NOT NULL,
|
|
16106
|
+
html TEXT NOT NULL,
|
|
16107
|
+
title TEXT,
|
|
16108
|
+
created_at INTEGER NOT NULL,
|
|
16109
|
+
kind TEXT NOT NULL DEFAULT 'html',
|
|
16110
|
+
source TEXT,
|
|
16111
|
+
file_id TEXT,
|
|
16112
|
+
mime_type TEXT,
|
|
16113
|
+
media_token TEXT
|
|
16114
|
+
);
|
|
16115
|
+
CREATE INDEX IF NOT EXISTS idx_api_topic_visuals_topic
|
|
16116
|
+
ON api_topic_visuals(topic_id, created_at DESC);
|
|
16117
|
+
|
|
16118
|
+
CREATE TABLE IF NOT EXISTS api_topic_visual_views (
|
|
16119
|
+
topic_id TEXT NOT NULL,
|
|
16120
|
+
user_id TEXT NOT NULL,
|
|
16121
|
+
visual_id INTEGER NOT NULL,
|
|
16122
|
+
PRIMARY KEY (topic_id, user_id)
|
|
16123
|
+
);
|
|
16124
|
+
`);
|
|
16125
|
+
});
|
|
16061
16126
|
for (const statement of [
|
|
16062
16127
|
"ALTER TABLE api_topic_visuals ADD COLUMN kind TEXT NOT NULL DEFAULT 'html'",
|
|
16063
16128
|
"ALTER TABLE api_topic_visuals ADD COLUMN source TEXT",
|
|
@@ -20168,20 +20233,26 @@ function recordRuntimeGatewaySubmission(submission) {
|
|
|
20168
20233
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(submission.clientMessageId, submission.requestId, submission.topicId, submission.messageId, submission.userId, submission.createdAt, submission.ackCursor, submission.messageCursor, submission.payloadHash ?? null);
|
|
20169
20234
|
}
|
|
20170
20235
|
var init_runtime_gateway_submissions = __esm(async () => {
|
|
20171
|
-
await
|
|
20172
|
-
|
|
20173
|
-
|
|
20174
|
-
|
|
20175
|
-
|
|
20176
|
-
|
|
20177
|
-
|
|
20178
|
-
|
|
20179
|
-
|
|
20180
|
-
|
|
20181
|
-
|
|
20182
|
-
|
|
20183
|
-
|
|
20184
|
-
|
|
20236
|
+
await __promiseAll([
|
|
20237
|
+
init_forum_db(),
|
|
20238
|
+
init_storage_host()
|
|
20239
|
+
]);
|
|
20240
|
+
registerStorageSchemaInitializer((database) => {
|
|
20241
|
+
database.exec(`
|
|
20242
|
+
CREATE TABLE IF NOT EXISTS runtime_gateway_submissions (
|
|
20243
|
+
client_message_id TEXT PRIMARY KEY,
|
|
20244
|
+
request_id TEXT NOT NULL UNIQUE,
|
|
20245
|
+
topic_id TEXT NOT NULL,
|
|
20246
|
+
message_id TEXT NOT NULL,
|
|
20247
|
+
user_id TEXT NOT NULL,
|
|
20248
|
+
created_at TEXT NOT NULL,
|
|
20249
|
+
ack_cursor INTEGER NOT NULL DEFAULT 0,
|
|
20250
|
+
message_cursor INTEGER NOT NULL DEFAULT 0,
|
|
20251
|
+
payload_hash TEXT
|
|
20252
|
+
)
|
|
20253
|
+
`);
|
|
20254
|
+
database.exec("CREATE INDEX IF NOT EXISTS idx_runtime_gateway_submissions_topic ON runtime_gateway_submissions(topic_id)");
|
|
20255
|
+
});
|
|
20185
20256
|
try {
|
|
20186
20257
|
db.exec("ALTER TABLE runtime_gateway_submissions ADD COLUMN ack_cursor INTEGER NOT NULL DEFAULT 0");
|
|
20187
20258
|
} catch {}
|
|
@@ -20191,7 +20262,6 @@ var init_runtime_gateway_submissions = __esm(async () => {
|
|
|
20191
20262
|
try {
|
|
20192
20263
|
db.exec("ALTER TABLE runtime_gateway_submissions ADD COLUMN message_cursor INTEGER NOT NULL DEFAULT 0");
|
|
20193
20264
|
} catch {}
|
|
20194
|
-
db.exec("CREATE INDEX IF NOT EXISTS idx_runtime_gateway_submissions_topic ON runtime_gateway_submissions(topic_id)");
|
|
20195
20265
|
});
|
|
20196
20266
|
|
|
20197
20267
|
// ../../packages/core/src/application/submit-runtime-gateway-turn.ts
|
|
@@ -20364,6 +20434,33 @@ var init_submit_user_message = __esm(async () => {
|
|
|
20364
20434
|
});
|
|
20365
20435
|
|
|
20366
20436
|
// ../../packages/core/src/application/switch-topic-access-mode.ts
|
|
20437
|
+
function collectSubagentDescendants(rootTopicId) {
|
|
20438
|
+
const all = listTopics();
|
|
20439
|
+
const childrenByParent = new Map;
|
|
20440
|
+
for (const topic of all) {
|
|
20441
|
+
if (!topic.isSubagent || !topic.parentTopicId)
|
|
20442
|
+
continue;
|
|
20443
|
+
const siblings = childrenByParent.get(topic.parentTopicId);
|
|
20444
|
+
if (siblings)
|
|
20445
|
+
siblings.push(topic);
|
|
20446
|
+
else
|
|
20447
|
+
childrenByParent.set(topic.parentTopicId, [topic]);
|
|
20448
|
+
}
|
|
20449
|
+
const descendants = [];
|
|
20450
|
+
const seen = new Set([rootTopicId]);
|
|
20451
|
+
const queue = [rootTopicId];
|
|
20452
|
+
while (queue.length > 0) {
|
|
20453
|
+
const parentId = queue.shift();
|
|
20454
|
+
for (const child of childrenByParent.get(parentId) ?? []) {
|
|
20455
|
+
if (seen.has(child.id))
|
|
20456
|
+
continue;
|
|
20457
|
+
seen.add(child.id);
|
|
20458
|
+
descendants.push(child);
|
|
20459
|
+
queue.push(child.id);
|
|
20460
|
+
}
|
|
20461
|
+
}
|
|
20462
|
+
return descendants;
|
|
20463
|
+
}
|
|
20367
20464
|
function switchTopicAccessMode(params) {
|
|
20368
20465
|
const topic = getTopic(params.topicId);
|
|
20369
20466
|
if (!topic)
|
|
@@ -20371,13 +20468,32 @@ function switchTopicAccessMode(params) {
|
|
|
20371
20468
|
const owner = topic.participants.some((participant) => participant.userId === params.userId && participant.role === "owner");
|
|
20372
20469
|
if (!owner)
|
|
20373
20470
|
return { ok: false, error: "Only topic owners can change privacy" };
|
|
20374
|
-
topic.
|
|
20375
|
-
|
|
20376
|
-
|
|
20471
|
+
if (topic.isSubagent) {
|
|
20472
|
+
return {
|
|
20473
|
+
ok: false,
|
|
20474
|
+
error: "Subagent rooms inherit privacy from their parent topic"
|
|
20475
|
+
};
|
|
20476
|
+
}
|
|
20477
|
+
const descendants = collectSubagentDescendants(topic.id);
|
|
20478
|
+
const changed = [topic, ...descendants].filter((candidate) => (candidate.accessMode ?? "private") !== params.accessMode);
|
|
20479
|
+
if (changed.length === 0) {
|
|
20480
|
+
return {
|
|
20481
|
+
ok: true,
|
|
20482
|
+
accessMode: params.accessMode,
|
|
20483
|
+
text: params.accessMode === "shared" ? `"${topic.title}" is already public to the connected Otium Hub.` : `"${topic.title}" is already private to this worker.`,
|
|
20484
|
+
topicIds: []
|
|
20485
|
+
};
|
|
20486
|
+
}
|
|
20487
|
+
setTopicAccessModes(changed.map((candidate) => candidate.id), params.accessMode);
|
|
20488
|
+
for (const candidate of changed)
|
|
20489
|
+
WsHub.get().broadcastTopicUpdated(candidate.id);
|
|
20490
|
+
const subagentCount = changed.filter((candidate) => candidate.id !== topic.id).length;
|
|
20491
|
+
const suffix = subagentCount > 0 ? ` (${subagentCount} subagent room${subagentCount === 1 ? "" : "s"} updated)` : "";
|
|
20377
20492
|
return {
|
|
20378
20493
|
ok: true,
|
|
20379
20494
|
accessMode: params.accessMode,
|
|
20380
|
-
|
|
20495
|
+
topicIds: changed.map((candidate) => candidate.id),
|
|
20496
|
+
text: (params.accessMode === "shared" ? `"${topic.title}" is public to the connected Otium Hub.` : `"${topic.title}" is private to this worker.`) + suffix
|
|
20381
20497
|
};
|
|
20382
20498
|
}
|
|
20383
20499
|
var init_switch_topic_access_mode = __esm(async () => {
|
|
@@ -24920,6 +25036,219 @@ var init_vault2 = __esm(() => {
|
|
|
24920
25036
|
init_mcp_helpers();
|
|
24921
25037
|
});
|
|
24922
25038
|
|
|
25039
|
+
// ../../packages/core/src/mcp/wiki-search-index.ts
|
|
25040
|
+
import { chmodSync as chmodSync5, existsSync as existsSync26, readFileSync as readFileSync22, unlinkSync as unlinkSync18 } from "fs";
|
|
25041
|
+
function documentId(source) {
|
|
25042
|
+
return `${source.kind}:${source.key}`;
|
|
25043
|
+
}
|
|
25044
|
+
function ensureSchema(database) {
|
|
25045
|
+
const version = database.query("PRAGMA user_version").get()?.user_version;
|
|
25046
|
+
if (version !== 0 && version !== SEARCH_INDEX_SCHEMA_VERSION) {
|
|
25047
|
+
throw new Error(`Unsupported wiki search index schema: ${version}`);
|
|
25048
|
+
}
|
|
25049
|
+
database.exec(`
|
|
25050
|
+
CREATE TABLE IF NOT EXISTS wiki_search_documents (
|
|
25051
|
+
id TEXT PRIMARY KEY,
|
|
25052
|
+
kind TEXT NOT NULL,
|
|
25053
|
+
key TEXT NOT NULL,
|
|
25054
|
+
path TEXT NOT NULL,
|
|
25055
|
+
mtime_ms REAL NOT NULL,
|
|
25056
|
+
size INTEGER NOT NULL,
|
|
25057
|
+
title TEXT NOT NULL,
|
|
25058
|
+
text TEXT NOT NULL,
|
|
25059
|
+
date TEXT,
|
|
25060
|
+
family TEXT
|
|
25061
|
+
);
|
|
25062
|
+
CREATE UNIQUE INDEX IF NOT EXISTS wiki_search_documents_kind_key
|
|
25063
|
+
ON wiki_search_documents(kind, key);
|
|
25064
|
+
CREATE INDEX IF NOT EXISTS wiki_search_documents_kind_date
|
|
25065
|
+
ON wiki_search_documents(kind, date);
|
|
25066
|
+
CREATE INDEX IF NOT EXISTS wiki_search_documents_kind_family_date
|
|
25067
|
+
ON wiki_search_documents(kind, family, date);
|
|
25068
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS wiki_search_fts USING fts5(
|
|
25069
|
+
document_id UNINDEXED,
|
|
25070
|
+
kind UNINDEXED,
|
|
25071
|
+
tokens,
|
|
25072
|
+
tokenize = 'unicode61'
|
|
25073
|
+
);
|
|
25074
|
+
PRAGMA user_version = ${SEARCH_INDEX_SCHEMA_VERSION};
|
|
25075
|
+
`);
|
|
25076
|
+
}
|
|
25077
|
+
|
|
25078
|
+
class WikiSearchIndex {
|
|
25079
|
+
path;
|
|
25080
|
+
#database;
|
|
25081
|
+
constructor(path) {
|
|
25082
|
+
this.path = path;
|
|
25083
|
+
this.#database = new Database(path, { create: true });
|
|
25084
|
+
try {
|
|
25085
|
+
this.#database.exec("PRAGMA foreign_keys = ON; PRAGMA journal_mode = DELETE;");
|
|
25086
|
+
ensureSchema(this.#database);
|
|
25087
|
+
chmodSync5(path, 384);
|
|
25088
|
+
} catch (error2) {
|
|
25089
|
+
this.#database.close();
|
|
25090
|
+
throw error2;
|
|
25091
|
+
}
|
|
25092
|
+
}
|
|
25093
|
+
close() {
|
|
25094
|
+
this.#database.close();
|
|
25095
|
+
}
|
|
25096
|
+
upsert(source, document) {
|
|
25097
|
+
const id = documentId(source);
|
|
25098
|
+
const apply = this.#database.transaction(() => {
|
|
25099
|
+
this.#database.query("DELETE FROM wiki_search_fts WHERE document_id = ?").run(id);
|
|
25100
|
+
this.#database.query("DELETE FROM wiki_search_documents WHERE id = ?").run(id);
|
|
25101
|
+
this.#database.query(`
|
|
25102
|
+
INSERT INTO wiki_search_documents
|
|
25103
|
+
(id, kind, key, path, mtime_ms, size, title, text, date, family)
|
|
25104
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
25105
|
+
`).run(id, source.kind, source.key, source.path, source.mtimeMs, source.size, document.title, document.text, document.date ?? null, document.family ?? null);
|
|
25106
|
+
this.#database.query("INSERT INTO wiki_search_fts(document_id, kind, tokens) VALUES (?, ?, ?)").run(id, source.kind, document.tokens.join(" "));
|
|
25107
|
+
});
|
|
25108
|
+
apply.immediate();
|
|
25109
|
+
}
|
|
25110
|
+
sync(sources, prepare) {
|
|
25111
|
+
const result = { added: 0, updated: 0, removed: 0 };
|
|
25112
|
+
const existingRows = this.#database.query("SELECT id, path, mtime_ms, size FROM wiki_search_documents ORDER BY id").all();
|
|
25113
|
+
const existing = new Map(existingRows.map((row) => [row.id, row]));
|
|
25114
|
+
const present = new Set;
|
|
25115
|
+
const changed = [];
|
|
25116
|
+
for (const source of sources) {
|
|
25117
|
+
const id = documentId(source);
|
|
25118
|
+
present.add(id);
|
|
25119
|
+
const stored = existing.get(id);
|
|
25120
|
+
if (stored && stored.path === source.path && stored.mtime_ms === source.mtimeMs && stored.size === source.size) {
|
|
25121
|
+
continue;
|
|
25122
|
+
}
|
|
25123
|
+
try {
|
|
25124
|
+
const text2 = readFileSync22(source.path, "utf-8");
|
|
25125
|
+
changed.push({ source, document: prepare(source, text2), added: !stored });
|
|
25126
|
+
} catch {}
|
|
25127
|
+
}
|
|
25128
|
+
const removed = existingRows.filter((row) => !present.has(row.id));
|
|
25129
|
+
const apply = this.#database.transaction(() => {
|
|
25130
|
+
const deleteTerms = this.#database.query("DELETE FROM wiki_search_fts WHERE document_id = ?");
|
|
25131
|
+
const deleteDocument = this.#database.query("DELETE FROM wiki_search_documents WHERE id = ?");
|
|
25132
|
+
const insertDocument = this.#database.query(`
|
|
25133
|
+
INSERT INTO wiki_search_documents
|
|
25134
|
+
(id, kind, key, path, mtime_ms, size, title, text, date, family)
|
|
25135
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
25136
|
+
`);
|
|
25137
|
+
const insertTerms = this.#database.query(`
|
|
25138
|
+
INSERT INTO wiki_search_fts(document_id, kind, tokens)
|
|
25139
|
+
VALUES (?, ?, ?)
|
|
25140
|
+
`);
|
|
25141
|
+
for (const row of removed) {
|
|
25142
|
+
deleteTerms.run(row.id);
|
|
25143
|
+
deleteDocument.run(row.id);
|
|
25144
|
+
result.removed += 1;
|
|
25145
|
+
}
|
|
25146
|
+
for (const { source, document, added } of changed) {
|
|
25147
|
+
const id = documentId(source);
|
|
25148
|
+
deleteTerms.run(id);
|
|
25149
|
+
deleteDocument.run(id);
|
|
25150
|
+
insertDocument.run(id, source.kind, source.key, source.path, source.mtimeMs, source.size, document.title, document.text, document.date ?? null, document.family ?? null);
|
|
25151
|
+
insertTerms.run(id, source.kind, document.tokens.join(" "));
|
|
25152
|
+
if (added)
|
|
25153
|
+
result.added += 1;
|
|
25154
|
+
else
|
|
25155
|
+
result.updated += 1;
|
|
25156
|
+
}
|
|
25157
|
+
});
|
|
25158
|
+
apply.immediate();
|
|
25159
|
+
return result;
|
|
25160
|
+
}
|
|
25161
|
+
metadata(kinds) {
|
|
25162
|
+
if (kinds.length === 0)
|
|
25163
|
+
return [];
|
|
25164
|
+
const placeholders = kinds.map(() => "?").join(", ");
|
|
25165
|
+
const rows = this.#database.query(`SELECT id, kind, key, title, date
|
|
25166
|
+
FROM wiki_search_documents
|
|
25167
|
+
WHERE kind IN (${placeholders})`).all(...kinds);
|
|
25168
|
+
return rows.map((row) => ({
|
|
25169
|
+
id: row.id,
|
|
25170
|
+
kind: row.kind,
|
|
25171
|
+
key: row.key,
|
|
25172
|
+
title: row.title,
|
|
25173
|
+
...row.date ? { date: row.date } : {}
|
|
25174
|
+
}));
|
|
25175
|
+
}
|
|
25176
|
+
summaryMetadataByDate(query2) {
|
|
25177
|
+
const conditions = ["kind = 'summary'", "date IS NOT NULL"];
|
|
25178
|
+
const parameters = [];
|
|
25179
|
+
if (query2.year && query2.month) {
|
|
25180
|
+
const month = Number(query2.month);
|
|
25181
|
+
const nextYear = month === 12 ? String(Number(query2.year) + 1) : query2.year;
|
|
25182
|
+
const nextMonth = String(month === 12 ? 1 : month + 1).padStart(2, "0");
|
|
25183
|
+
conditions.push("date >= ?", "date < ?");
|
|
25184
|
+
parameters.push(`${query2.year}-${query2.month}-01`, `${nextYear}-${nextMonth}-01`);
|
|
25185
|
+
} else if (query2.year) {
|
|
25186
|
+
conditions.push("date >= ?", "date < ?");
|
|
25187
|
+
parameters.push(`${query2.year}-01-01`, `${Number(query2.year) + 1}-01-01`);
|
|
25188
|
+
} else if (query2.month) {
|
|
25189
|
+
conditions.push("substr(date, 6, 2) = ?");
|
|
25190
|
+
parameters.push(query2.month);
|
|
25191
|
+
}
|
|
25192
|
+
parameters.push(query2.limit);
|
|
25193
|
+
const rows = this.#database.query(`SELECT id, kind, key, title, date
|
|
25194
|
+
FROM wiki_search_documents
|
|
25195
|
+
WHERE ${conditions.join(" AND ")}
|
|
25196
|
+
ORDER BY date ${query2.direction === "oldest" ? "ASC" : "DESC"}, key ASC
|
|
25197
|
+
LIMIT ?`).all(...parameters);
|
|
25198
|
+
return rows.map((row) => ({
|
|
25199
|
+
id: row.id,
|
|
25200
|
+
kind: row.kind,
|
|
25201
|
+
key: row.key,
|
|
25202
|
+
title: row.title,
|
|
25203
|
+
...row.date ? { date: row.date } : {}
|
|
25204
|
+
}));
|
|
25205
|
+
}
|
|
25206
|
+
matchingDocumentIds(kinds, terms) {
|
|
25207
|
+
if (kinds.length === 0 || terms.length === 0)
|
|
25208
|
+
return new Set;
|
|
25209
|
+
const kindPlaceholders = kinds.map(() => "?").join(", ");
|
|
25210
|
+
const match = terms.map((term) => `"${term.replaceAll('"', '""')}"`).join(" OR ");
|
|
25211
|
+
const rows = this.#database.query(`SELECT DISTINCT document_id
|
|
25212
|
+
FROM wiki_search_fts
|
|
25213
|
+
WHERE wiki_search_fts MATCH ? AND kind IN (${kindPlaceholders})`).all(match, ...kinds);
|
|
25214
|
+
return new Set(rows.map((row) => row.document_id));
|
|
25215
|
+
}
|
|
25216
|
+
documents(ids) {
|
|
25217
|
+
if (ids.size === 0)
|
|
25218
|
+
return [];
|
|
25219
|
+
const values = [...ids];
|
|
25220
|
+
const rows = [];
|
|
25221
|
+
for (let offset = 0;offset < values.length; offset += 500) {
|
|
25222
|
+
const chunk = values.slice(offset, offset + 500);
|
|
25223
|
+
const placeholders = chunk.map(() => "?").join(", ");
|
|
25224
|
+
rows.push(...this.#database.query(`SELECT id, kind, key, path, title, text, date
|
|
25225
|
+
FROM wiki_search_documents
|
|
25226
|
+
WHERE id IN (${placeholders})`).all(...chunk));
|
|
25227
|
+
}
|
|
25228
|
+
return rows.map((row) => ({
|
|
25229
|
+
id: row.id,
|
|
25230
|
+
kind: row.kind,
|
|
25231
|
+
key: row.key,
|
|
25232
|
+
path: row.path,
|
|
25233
|
+
title: row.title,
|
|
25234
|
+
text: row.text,
|
|
25235
|
+
tokens: [],
|
|
25236
|
+
...row.date ? { date: row.date } : {}
|
|
25237
|
+
}));
|
|
25238
|
+
}
|
|
25239
|
+
}
|
|
25240
|
+
function resetCorruptWikiSearchIndex(path) {
|
|
25241
|
+
for (const candidate of [path, `${path}-journal`, `${path}-wal`, `${path}-shm`]) {
|
|
25242
|
+
if (!existsSync26(candidate))
|
|
25243
|
+
continue;
|
|
25244
|
+
unlinkSync18(candidate);
|
|
25245
|
+
}
|
|
25246
|
+
}
|
|
25247
|
+
var SEARCH_INDEX_SCHEMA_VERSION = 3;
|
|
25248
|
+
var init_wiki_search_index = __esm(async () => {
|
|
25249
|
+
await init_sqlite();
|
|
25250
|
+
});
|
|
25251
|
+
|
|
24923
25252
|
// ../../packages/core/src/mcp/wiki-server.ts
|
|
24924
25253
|
var exports_wiki_server = {};
|
|
24925
25254
|
__export(exports_wiki_server, {
|
|
@@ -24930,14 +25259,14 @@ import { AsyncLocalStorage as AsyncLocalStorage3 } from "async_hooks";
|
|
|
24930
25259
|
import { randomUUID as randomUUID21 } from "crypto";
|
|
24931
25260
|
import {
|
|
24932
25261
|
closeSync as closeSync4,
|
|
24933
|
-
existsSync as
|
|
25262
|
+
existsSync as existsSync27,
|
|
24934
25263
|
mkdirSync as mkdirSync24,
|
|
24935
25264
|
openSync as openSync4,
|
|
24936
25265
|
readdirSync as readdirSync10,
|
|
24937
|
-
readFileSync as
|
|
25266
|
+
readFileSync as readFileSync23,
|
|
24938
25267
|
renameSync as renameSync11,
|
|
24939
25268
|
statSync as statSync15,
|
|
24940
|
-
unlinkSync as
|
|
25269
|
+
unlinkSync as unlinkSync19,
|
|
24941
25270
|
writeFileSync as writeFileSync17
|
|
24942
25271
|
} from "fs";
|
|
24943
25272
|
import { basename as basename7, dirname as dirname16, join as join36, relative as relative2, resolve as resolve17 } from "path";
|
|
@@ -24980,15 +25309,15 @@ function acquireRecoveryGuard(lockPath) {
|
|
|
24980
25309
|
} catch (error2) {
|
|
24981
25310
|
closeSync4(fd);
|
|
24982
25311
|
try {
|
|
24983
|
-
|
|
25312
|
+
unlinkSync19(guardPath);
|
|
24984
25313
|
} catch {}
|
|
24985
25314
|
throw error2;
|
|
24986
25315
|
}
|
|
24987
25316
|
return () => {
|
|
24988
25317
|
closeSync4(fd);
|
|
24989
25318
|
try {
|
|
24990
|
-
if (
|
|
24991
|
-
|
|
25319
|
+
if (readFileSync23(guardPath, "utf-8") === ownerToken)
|
|
25320
|
+
unlinkSync19(guardPath);
|
|
24992
25321
|
} catch {}
|
|
24993
25322
|
};
|
|
24994
25323
|
} catch (error2) {
|
|
@@ -25013,7 +25342,7 @@ function acquireFileLock(path) {
|
|
|
25013
25342
|
} catch (error2) {
|
|
25014
25343
|
closeSync4(fd);
|
|
25015
25344
|
try {
|
|
25016
|
-
|
|
25345
|
+
unlinkSync19(lockPath);
|
|
25017
25346
|
} catch {}
|
|
25018
25347
|
throw error2;
|
|
25019
25348
|
}
|
|
@@ -25021,8 +25350,8 @@ function acquireFileLock(path) {
|
|
|
25021
25350
|
closeSync4(fd);
|
|
25022
25351
|
const releaseGuard = acquireRecoveryGuard(lockPath);
|
|
25023
25352
|
try {
|
|
25024
|
-
if (
|
|
25025
|
-
|
|
25353
|
+
if (readFileSync23(lockPath, "utf-8") === ownerToken)
|
|
25354
|
+
unlinkSync19(lockPath);
|
|
25026
25355
|
} catch {} finally {
|
|
25027
25356
|
releaseGuard();
|
|
25028
25357
|
}
|
|
@@ -25033,9 +25362,9 @@ function acquireFileLock(path) {
|
|
|
25033
25362
|
const releaseGuard = acquireRecoveryGuard(lockPath);
|
|
25034
25363
|
try {
|
|
25035
25364
|
try {
|
|
25036
|
-
const staleToken =
|
|
25037
|
-
if (Date.now() - statSync15(lockPath).mtimeMs > FILE_LOCK_STALE_MS &&
|
|
25038
|
-
|
|
25365
|
+
const staleToken = readFileSync23(lockPath, "utf-8");
|
|
25366
|
+
if (Date.now() - statSync15(lockPath).mtimeMs > FILE_LOCK_STALE_MS && readFileSync23(lockPath, "utf-8") === staleToken) {
|
|
25367
|
+
unlinkSync19(lockPath);
|
|
25039
25368
|
continue;
|
|
25040
25369
|
}
|
|
25041
25370
|
} catch {
|
|
@@ -25058,7 +25387,7 @@ function atomicWriteFile(path, content) {
|
|
|
25058
25387
|
renameSync11(temporaryPath, path);
|
|
25059
25388
|
} catch (error2) {
|
|
25060
25389
|
try {
|
|
25061
|
-
|
|
25390
|
+
unlinkSync19(temporaryPath);
|
|
25062
25391
|
} catch {}
|
|
25063
25392
|
throw error2;
|
|
25064
25393
|
}
|
|
@@ -25174,10 +25503,77 @@ function trigramSimilarity(left, right) {
|
|
|
25174
25503
|
overlap += 1;
|
|
25175
25504
|
return 2 * overlap / (a.size + b.size);
|
|
25176
25505
|
}
|
|
25506
|
+
function openWikiSearchIndex() {
|
|
25507
|
+
const path = resolve17(runtime().wikiDir, WIKI_SEARCH_INDEX_FILENAME);
|
|
25508
|
+
try {
|
|
25509
|
+
return new WikiSearchIndex(path);
|
|
25510
|
+
} catch (error2) {
|
|
25511
|
+
if (!/malformed|not a database|schema/i.test(String(error2)))
|
|
25512
|
+
return;
|
|
25513
|
+
try {
|
|
25514
|
+
resetCorruptWikiSearchIndex(path);
|
|
25515
|
+
return new WikiSearchIndex(path);
|
|
25516
|
+
} catch {
|
|
25517
|
+
return;
|
|
25518
|
+
}
|
|
25519
|
+
}
|
|
25520
|
+
}
|
|
25521
|
+
function prepareWikiSearchDocument(kind, key, text2) {
|
|
25522
|
+
const titleLine = text2.split(`
|
|
25523
|
+
`).find((line) => /^#+\s*/.test(line)) ?? "";
|
|
25524
|
+
const title = titleLine ? titleLine.replace(/^#+\s*/, "") : basename7(key);
|
|
25525
|
+
return {
|
|
25526
|
+
title,
|
|
25527
|
+
text: text2,
|
|
25528
|
+
tokens: canonicalSearchTokens(`${key} ${title} ${text2}`),
|
|
25529
|
+
...kind === "summary" && /^\d{4}-\d{2}-\d{2}/.test(key) ? { date: key.slice(0, 10), family: summaryTopicIdentity(key) } : {}
|
|
25530
|
+
};
|
|
25531
|
+
}
|
|
25532
|
+
function indexWikiSearchDocument(kind, key, text2) {
|
|
25533
|
+
const root = kind === "article" ? runtime().articlesDir : runtime().summariesDir;
|
|
25534
|
+
const path = resolve17(root, `${key}.md`);
|
|
25535
|
+
const index = openWikiSearchIndex();
|
|
25536
|
+
if (!index)
|
|
25537
|
+
return false;
|
|
25538
|
+
try {
|
|
25539
|
+
const stat = statSync15(path);
|
|
25540
|
+
index.upsert({ kind, key, path, mtimeMs: stat.mtimeMs, size: stat.size }, prepareWikiSearchDocument(kind, key, text2));
|
|
25541
|
+
return true;
|
|
25542
|
+
} catch {
|
|
25543
|
+
return false;
|
|
25544
|
+
} finally {
|
|
25545
|
+
index.close();
|
|
25546
|
+
}
|
|
25547
|
+
}
|
|
25548
|
+
function wikiIndexPath(kind) {
|
|
25549
|
+
return resolve17(runtime().wikiDir, WIKI_INDEX_FILENAMES[kind]);
|
|
25550
|
+
}
|
|
25551
|
+
function normalizeIndexDescription(raw) {
|
|
25552
|
+
const description = raw.replaceAll(/\s+/g, " ").trim();
|
|
25553
|
+
if (!description)
|
|
25554
|
+
return { error: "A non-empty one-line description is required." };
|
|
25555
|
+
if (description.length > MAX_INDEX_DESCRIPTION_LENGTH) {
|
|
25556
|
+
return {
|
|
25557
|
+
error: `Description must be at most ${MAX_INDEX_DESCRIPTION_LENGTH} characters (got ${description.length}).`
|
|
25558
|
+
};
|
|
25559
|
+
}
|
|
25560
|
+
return { description };
|
|
25561
|
+
}
|
|
25562
|
+
function normalizeWikiSlug(raw) {
|
|
25563
|
+
const slug = raw.trim().replace(/\.md$/i, "").replace(/^\/+/, "");
|
|
25564
|
+
if (!slug)
|
|
25565
|
+
return { error: "A non-empty slug is required." };
|
|
25566
|
+
if (/[[\]|\\]/.test(slug))
|
|
25567
|
+
return { error: "Slug must not contain [ ] | or backslashes." };
|
|
25568
|
+
if (slug.split("/").some((segment) => segment === "" || segment === "." || segment === "..")) {
|
|
25569
|
+
return { error: "Slug must not contain empty or relative path segments." };
|
|
25570
|
+
}
|
|
25571
|
+
return { slug };
|
|
25572
|
+
}
|
|
25177
25573
|
function parseWikiIndex(path) {
|
|
25178
25574
|
let text2;
|
|
25179
25575
|
try {
|
|
25180
|
-
text2 =
|
|
25576
|
+
text2 = readFileSync23(path, "utf-8");
|
|
25181
25577
|
} catch {
|
|
25182
25578
|
return [];
|
|
25183
25579
|
}
|
|
@@ -25331,7 +25727,7 @@ function wikiQuery(args) {
|
|
|
25331
25727
|
continue;
|
|
25332
25728
|
const fp = join36(sub, f.name);
|
|
25333
25729
|
try {
|
|
25334
|
-
const text2 =
|
|
25730
|
+
const text2 = readFileSync23(fp, "utf-8");
|
|
25335
25731
|
const key = `${entry.name}/${f.name.replace(/\.md$/i, "")}`;
|
|
25336
25732
|
scored.push({
|
|
25337
25733
|
kind: label === "articles" ? "article" : "skill",
|
|
@@ -25352,7 +25748,7 @@ function wikiQuery(args) {
|
|
|
25352
25748
|
}
|
|
25353
25749
|
const fp = join36(dir, entry.name);
|
|
25354
25750
|
try {
|
|
25355
|
-
const text2 =
|
|
25751
|
+
const text2 = readFileSync23(fp, "utf-8");
|
|
25356
25752
|
const key = entry.name.replace(/\.md$/i, "");
|
|
25357
25753
|
const resultKind = label === "articles" ? "article" : label === "topic" ? "topic" : label === "summaries" ? "summary" : "skill";
|
|
25358
25754
|
scored.push({
|
|
@@ -25466,14 +25862,45 @@ function wikiQuery(args) {
|
|
|
25466
25862
|
return 0;
|
|
25467
25863
|
return score;
|
|
25468
25864
|
}
|
|
25469
|
-
|
|
25470
|
-
|
|
25865
|
+
const bodyKinds = [
|
|
25866
|
+
...kind === "all" || kind === "article" ? ["article"] : [],
|
|
25867
|
+
...kind === "all" || kind === "summary" ? ["summary"] : []
|
|
25868
|
+
];
|
|
25869
|
+
if (bodyKinds.length > 0) {
|
|
25870
|
+
const searchIndex = openWikiSearchIndex();
|
|
25871
|
+
if (searchIndex) {
|
|
25872
|
+
try {
|
|
25873
|
+
const terms = canonicalSearchTokens(normalizedQuery);
|
|
25874
|
+
const ids = searchIndex.matchingDocumentIds(bodyKinds, terms);
|
|
25875
|
+
if (temporalDirection && bodyKinds.includes("summary")) {
|
|
25876
|
+
for (const item of searchIndex.summaryMetadataByDate({
|
|
25877
|
+
direction: temporalDirection === "newest" ? "latest" : "oldest",
|
|
25878
|
+
limit
|
|
25879
|
+
})) {
|
|
25880
|
+
ids.add(item.id);
|
|
25881
|
+
}
|
|
25882
|
+
}
|
|
25883
|
+
for (const document of searchIndex.documents(ids)) {
|
|
25884
|
+
scored.push({
|
|
25885
|
+
kind: document.kind,
|
|
25886
|
+
key: document.key,
|
|
25887
|
+
keyScore: scoreIndexKey(question, document.key),
|
|
25888
|
+
score: scoreMatch(document.text, document.key, document.kind),
|
|
25889
|
+
path: `${document.kind === "article" ? "articles" : "summaries"}/${document.key}.md`,
|
|
25890
|
+
text: document.text,
|
|
25891
|
+
title: document.title,
|
|
25892
|
+
...document.date ? { date: document.date } : {}
|
|
25893
|
+
});
|
|
25894
|
+
}
|
|
25895
|
+
} catch {} finally {
|
|
25896
|
+
searchIndex.close();
|
|
25897
|
+
}
|
|
25898
|
+
}
|
|
25899
|
+
}
|
|
25471
25900
|
if (kind === "all" && runtime().surface === "all")
|
|
25472
25901
|
scan(runtime().skillsDir, "skills");
|
|
25473
25902
|
if (kind === "all" || kind === "topic")
|
|
25474
25903
|
scan(runtime().topicsDir, "topic");
|
|
25475
|
-
if (kind === "all" || kind === "summary")
|
|
25476
|
-
scan(runtime().summariesDir, "summaries");
|
|
25477
25904
|
const merged = new Map;
|
|
25478
25905
|
for (const { candidate, keyScore, score } of indexCandidates) {
|
|
25479
25906
|
merged.set(`${candidate.kind}:${candidate.key}`, {
|
|
@@ -25605,7 +26032,7 @@ function wikiTopicBrief(args) {
|
|
|
25605
26032
|
const topicKey = wikiSummarySlug(rawTopic.replace(/^topic\//, "").replace(/\.md$/i, ""));
|
|
25606
26033
|
const filePath = resolve17(runtime().topicsDir, `${topicKey}.md`);
|
|
25607
26034
|
try {
|
|
25608
|
-
const content =
|
|
26035
|
+
const content = readFileSync23(filePath, "utf-8");
|
|
25609
26036
|
return {
|
|
25610
26037
|
content: [{ type: "text", text: `# Topic Brief: ${topicKey}
|
|
25611
26038
|
|
|
@@ -25657,7 +26084,7 @@ Adopted topic memory: ${memoryKey}` }]
|
|
|
25657
26084
|
return { content: [{ type: "text", text: "Invalid wiki document key." }], isError: true };
|
|
25658
26085
|
}
|
|
25659
26086
|
try {
|
|
25660
|
-
const content =
|
|
26087
|
+
const content = readFileSync23(filePath, "utf-8");
|
|
25661
26088
|
return {
|
|
25662
26089
|
content: [{ type: "text", text: `# Wiki ${kind}: ${key}
|
|
25663
26090
|
|
|
@@ -25677,18 +26104,18 @@ function wikiLastConversation(args) {
|
|
|
25677
26104
|
const name = slugify(topicNameFrom(rawTopic));
|
|
25678
26105
|
const archiveDir = resolve17(runtime().archiveDir, name);
|
|
25679
26106
|
try {
|
|
25680
|
-
let files =
|
|
26107
|
+
let files = existsSync27(archiveDir) ? readdirSync10(archiveDir).filter((f) => f.endsWith(".jsonl")).sort().reverse() : [];
|
|
25681
26108
|
if (files.length === 0) {
|
|
25682
|
-
files =
|
|
26109
|
+
files = existsSync27(runtime().archiveDir) ? readdirSync10(runtime().archiveDir).filter((f) => f.startsWith(name) && f.endsWith(".jsonl")).sort().reverse() : [];
|
|
25683
26110
|
}
|
|
25684
26111
|
if (files.length === 0) {
|
|
25685
26112
|
return {
|
|
25686
26113
|
content: [{ type: "text", text: `No archive found for topic: ${rawTopic}` }]
|
|
25687
26114
|
};
|
|
25688
26115
|
}
|
|
25689
|
-
const actualPath = files[0].includes("/") ? files[0] : resolve17(
|
|
26116
|
+
const actualPath = files[0].includes("/") ? files[0] : resolve17(existsSync27(archiveDir) && readdirSync10(archiveDir).includes(files[0]) ? archiveDir : runtime().archiveDir, files[0]);
|
|
25690
26117
|
try {
|
|
25691
|
-
const raw =
|
|
26118
|
+
const raw = readFileSync23(actualPath, "utf-8");
|
|
25692
26119
|
const lines = raw.trim().split(`
|
|
25693
26120
|
`).filter(Boolean);
|
|
25694
26121
|
const turns2 = [];
|
|
@@ -25761,7 +26188,7 @@ function skillQuery(args) {
|
|
|
25761
26188
|
continue;
|
|
25762
26189
|
const skillFile = resolve17(runtime().skillsDir, entry.name, "skill.md");
|
|
25763
26190
|
try {
|
|
25764
|
-
const text2 =
|
|
26191
|
+
const text2 = readFileSync23(skillFile, "utf-8");
|
|
25765
26192
|
const lower = text2.toLowerCase();
|
|
25766
26193
|
let score = 0;
|
|
25767
26194
|
for (const w of query2.split(/\s+/).filter(Boolean)) {
|
|
@@ -25832,7 +26259,7 @@ ${fresh.join(`
|
|
|
25832
26259
|
const skillPath = resolve17(skillDir, "skill.md");
|
|
25833
26260
|
let finalContent = content;
|
|
25834
26261
|
try {
|
|
25835
|
-
const existing =
|
|
26262
|
+
const existing = readFileSync23(skillPath, "utf-8");
|
|
25836
26263
|
finalContent = mergeGotchas(content, extractGotchas(existing));
|
|
25837
26264
|
} catch {}
|
|
25838
26265
|
writeFileSync17(skillPath, finalContent, "utf-8");
|
|
@@ -25845,15 +26272,7 @@ ${fresh.join(`
|
|
|
25845
26272
|
]
|
|
25846
26273
|
};
|
|
25847
26274
|
}
|
|
25848
|
-
function
|
|
25849
|
-
const rawTopic = safeExt(args, ["topic", "topicName"], "");
|
|
25850
|
-
const content = safeExt(args, ["content", "text", "body"], "");
|
|
25851
|
-
if (!rawTopic)
|
|
25852
|
-
return { content: [{ type: "text", text: "Missing topic." }] };
|
|
25853
|
-
if (!content)
|
|
25854
|
-
return { content: [{ type: "text", text: "Missing content." }] };
|
|
25855
|
-
const now = new Date;
|
|
25856
|
-
const dateStr = now.toISOString().slice(0, 10);
|
|
26275
|
+
function writeSummaryDocument(rawTopic, content, dateStr) {
|
|
25857
26276
|
const topicId = runtime().topicId;
|
|
25858
26277
|
const fileSlug = wikiBriefStorageKey(rawTopic, topicId);
|
|
25859
26278
|
ensureDir(runtime().summariesDir);
|
|
@@ -25880,7 +26299,7 @@ function saveWikiEntry(args) {
|
|
|
25880
26299
|
if (topicId && setTopicBrief2) {
|
|
25881
26300
|
try {
|
|
25882
26301
|
const briefPath = resolve17(runtime().topicsDir, `${fileSlug}.md`);
|
|
25883
|
-
let briefMd =
|
|
26302
|
+
let briefMd = existsSync27(briefPath) ? readFileSync23(briefPath, "utf-8") : undefined;
|
|
25884
26303
|
if (briefMd === undefined && getTopicBrief2 && !getTopicBrief2(fileSlug)?.briefMd) {
|
|
25885
26304
|
const legacy = getTopicBrief2(topicId)?.briefMd;
|
|
25886
26305
|
if (legacy)
|
|
@@ -25894,28 +26313,14 @@ function saveWikiEntry(args) {
|
|
|
25894
26313
|
sqliteUpdated = true;
|
|
25895
26314
|
} catch {}
|
|
25896
26315
|
}
|
|
25897
|
-
return {
|
|
25898
|
-
content: [
|
|
25899
|
-
{
|
|
25900
|
-
type: "text",
|
|
25901
|
-
text: `Saved summary: summaries/${summaryName}` + (sqliteUpdated ? `
|
|
25902
|
-
SQLite latest-summary also updated.` : "")
|
|
25903
|
-
}
|
|
25904
|
-
]
|
|
25905
|
-
};
|
|
26316
|
+
return { slug: summaryName.replace(/\.md$/i, ""), sqliteUpdated };
|
|
25906
26317
|
}
|
|
25907
|
-
function
|
|
25908
|
-
const rawTopic = safeExt(args, ["topic", "topicName"], "");
|
|
25909
|
-
const content = safeExt(args, ["content", "brief", "text", "body"], "");
|
|
25910
|
-
if (!rawTopic)
|
|
25911
|
-
return { content: [{ type: "text", text: "Missing topic." }] };
|
|
25912
|
-
if (!content)
|
|
25913
|
-
return { content: [{ type: "text", text: "Missing content." }] };
|
|
26318
|
+
function writeTopicDocument(rawTopic, content) {
|
|
25914
26319
|
const topicId = runtime().topicId;
|
|
25915
26320
|
const fileSlug = wikiBriefStorageKey(rawTopic, topicId);
|
|
25916
26321
|
const briefPath = resolve17(runtime().topicsDir, `${fileSlug}.md`);
|
|
25917
26322
|
ensureDir(dirname16(briefPath));
|
|
25918
|
-
const existed =
|
|
26323
|
+
const existed = existsSync27(briefPath);
|
|
25919
26324
|
writeFileSync17(briefPath, content, "utf-8");
|
|
25920
26325
|
const setTopicBrief2 = runtime().host.setTopicBrief;
|
|
25921
26326
|
let sqliteUpdated = false;
|
|
@@ -25925,68 +26330,227 @@ function saveTopicBrief(args) {
|
|
|
25925
26330
|
sqliteUpdated = true;
|
|
25926
26331
|
} catch {}
|
|
25927
26332
|
}
|
|
26333
|
+
return { slug: fileSlug, existed, sqliteUpdated };
|
|
26334
|
+
}
|
|
26335
|
+
function writeArticleDocument(slug, content) {
|
|
26336
|
+
const articlePath = resolve17(runtime().articlesDir, `${slug}.md`);
|
|
26337
|
+
ensureDir(dirname16(articlePath));
|
|
26338
|
+
const existed = existsSync27(articlePath);
|
|
26339
|
+
atomicWriteFile(articlePath, content);
|
|
26340
|
+
return { existed };
|
|
26341
|
+
}
|
|
26342
|
+
function wikiWrite(args) {
|
|
26343
|
+
const rawKind = safeExt(args, ["kind", "type"], "");
|
|
26344
|
+
const content = safeExt(args, ["content", "text", "body", "brief"], "");
|
|
26345
|
+
const rawDescription = safeExt(args, ["description", "desc"], "");
|
|
26346
|
+
const rawTopic = safeExt(args, ["topic", "topicName"], "");
|
|
26347
|
+
const rawSlug = safeExt(args, ["slug", "id"], "");
|
|
26348
|
+
const section = safeExt(args, ["section", "category"], undefined);
|
|
26349
|
+
const rawDate = safeExt(args, ["date", "created"], undefined);
|
|
26350
|
+
if (rawKind !== "summary" && rawKind !== "article" && rawKind !== "topic") {
|
|
26351
|
+
return {
|
|
26352
|
+
content: [{ type: "text", text: 'kind must be one of "summary", "article", "topic".' }],
|
|
26353
|
+
isError: true
|
|
26354
|
+
};
|
|
26355
|
+
}
|
|
26356
|
+
if (!content.trim()) {
|
|
26357
|
+
return { content: [{ type: "text", text: "Missing content." }], isError: true };
|
|
26358
|
+
}
|
|
26359
|
+
const descriptionResult = normalizeIndexDescription(rawDescription);
|
|
26360
|
+
if ("error" in descriptionResult) {
|
|
26361
|
+
return { content: [{ type: "text", text: descriptionResult.error }], isError: true };
|
|
26362
|
+
}
|
|
26363
|
+
const { description } = descriptionResult;
|
|
26364
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
26365
|
+
if (rawKind === "article") {
|
|
26366
|
+
const slugResult = normalizeWikiSlug(rawSlug);
|
|
26367
|
+
if ("error" in slugResult) {
|
|
26368
|
+
return { content: [{ type: "text", text: slugResult.error }], isError: true };
|
|
26369
|
+
}
|
|
26370
|
+
if (!section?.trim()) {
|
|
26371
|
+
return {
|
|
26372
|
+
content: [
|
|
26373
|
+
{ type: "text", text: "An article requires a section so the catalog stays navigable." }
|
|
26374
|
+
],
|
|
26375
|
+
isError: true
|
|
26376
|
+
};
|
|
26377
|
+
}
|
|
26378
|
+
const { existed } = writeArticleDocument(slugResult.slug, content);
|
|
26379
|
+
const link2 = indexRowOrPartialWrite("article", {
|
|
26380
|
+
kind: "article",
|
|
26381
|
+
slug: slugResult.slug,
|
|
26382
|
+
description,
|
|
26383
|
+
date: rawDate ?? today,
|
|
26384
|
+
section: section.trim()
|
|
26385
|
+
});
|
|
26386
|
+
if (typeof link2 !== "string")
|
|
26387
|
+
return link2;
|
|
26388
|
+
const searched = indexWikiSearchDocument("article", slugResult.slug, content);
|
|
26389
|
+
return {
|
|
26390
|
+
content: [
|
|
26391
|
+
{
|
|
26392
|
+
type: "text",
|
|
26393
|
+
text: `Saved article: articles/${slugResult.slug}.md (${existed ? "updated" : "created"})
|
|
26394
|
+
Indexed: ${link2}` + (searched ? "" : `
|
|
26395
|
+
${SEARCH_CACHE_SKIPPED_NOTE}`)
|
|
26396
|
+
}
|
|
26397
|
+
]
|
|
26398
|
+
};
|
|
26399
|
+
}
|
|
26400
|
+
const topic = rawTopic.trim();
|
|
26401
|
+
if (!topic) {
|
|
26402
|
+
return { content: [{ type: "text", text: "Missing topic." }], isError: true };
|
|
26403
|
+
}
|
|
26404
|
+
if (rawKind === "summary") {
|
|
26405
|
+
const dateStr = rawDate ?? today;
|
|
26406
|
+
const written2 = writeSummaryDocument(topic, content, dateStr);
|
|
26407
|
+
const link2 = indexRowOrPartialWrite("summary", {
|
|
26408
|
+
kind: "summary",
|
|
26409
|
+
slug: written2.slug,
|
|
26410
|
+
description,
|
|
26411
|
+
date: dateStr
|
|
26412
|
+
});
|
|
26413
|
+
if (typeof link2 !== "string")
|
|
26414
|
+
return link2;
|
|
26415
|
+
const searched = indexWikiSearchDocument("summary", written2.slug, content);
|
|
26416
|
+
return {
|
|
26417
|
+
content: [
|
|
26418
|
+
{
|
|
26419
|
+
type: "text",
|
|
26420
|
+
text: `Saved summary: summaries/${written2.slug}.md
|
|
26421
|
+
Indexed: ${link2}` + (written2.sqliteUpdated ? `
|
|
26422
|
+
SQLite latest-summary also updated.` : "") + (searched ? "" : `
|
|
26423
|
+
${SEARCH_CACHE_SKIPPED_NOTE}`)
|
|
26424
|
+
}
|
|
26425
|
+
]
|
|
26426
|
+
};
|
|
26427
|
+
}
|
|
26428
|
+
const written = writeTopicDocument(topic, content);
|
|
26429
|
+
const link = indexRowOrPartialWrite("topic", {
|
|
26430
|
+
kind: "topic",
|
|
26431
|
+
slug: written.slug,
|
|
26432
|
+
description,
|
|
26433
|
+
date: rawDate ?? today
|
|
26434
|
+
});
|
|
26435
|
+
if (typeof link !== "string")
|
|
26436
|
+
return link;
|
|
25928
26437
|
return {
|
|
25929
26438
|
content: [
|
|
25930
26439
|
{
|
|
25931
26440
|
type: "text",
|
|
25932
|
-
text: `Saved brief: topic/${
|
|
26441
|
+
text: `Saved brief: topic/${written.slug}.md (${written.existed ? "updated" : "created"})
|
|
26442
|
+
Indexed: ${link}` + (written.sqliteUpdated ? `
|
|
25933
26443
|
SQLite brief also updated.` : "")
|
|
25934
26444
|
}
|
|
25935
26445
|
]
|
|
25936
26446
|
};
|
|
25937
26447
|
}
|
|
25938
|
-
function
|
|
25939
|
-
const
|
|
25940
|
-
|
|
25941
|
-
|
|
25942
|
-
|
|
25943
|
-
|
|
25944
|
-
|
|
25945
|
-
|
|
25946
|
-
|
|
25947
|
-
|
|
25948
|
-
const
|
|
25949
|
-
|
|
25950
|
-
|
|
25951
|
-
|
|
25952
|
-
|
|
25953
|
-
|
|
25954
|
-
|
|
26448
|
+
function collectIndexableDocuments() {
|
|
26449
|
+
const sources = [];
|
|
26450
|
+
function add(kind, key, path) {
|
|
26451
|
+
try {
|
|
26452
|
+
const stat = statSync15(path);
|
|
26453
|
+
if (!stat.isFile())
|
|
26454
|
+
return;
|
|
26455
|
+
sources.push({ kind, key, path, mtimeMs: stat.mtimeMs, size: stat.size });
|
|
26456
|
+
} catch {}
|
|
26457
|
+
}
|
|
26458
|
+
for (const [root, kind, allowSubdirectories] of [
|
|
26459
|
+
[runtime().articlesDir, "article", true],
|
|
26460
|
+
[runtime().summariesDir, "summary", false]
|
|
26461
|
+
]) {
|
|
26462
|
+
let entries;
|
|
26463
|
+
try {
|
|
26464
|
+
entries = readdirSync10(root, { withFileTypes: true });
|
|
26465
|
+
} catch {
|
|
26466
|
+
continue;
|
|
26467
|
+
}
|
|
26468
|
+
for (const entry of entries) {
|
|
26469
|
+
if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
26470
|
+
add(kind, entry.name.replace(/\.md$/i, ""), join36(root, entry.name));
|
|
26471
|
+
continue;
|
|
26472
|
+
}
|
|
26473
|
+
if (!entry.isDirectory() || !allowSubdirectories)
|
|
26474
|
+
continue;
|
|
26475
|
+
let nested;
|
|
26476
|
+
try {
|
|
26477
|
+
nested = readdirSync10(join36(root, entry.name), { withFileTypes: true });
|
|
26478
|
+
} catch {
|
|
26479
|
+
continue;
|
|
26480
|
+
}
|
|
26481
|
+
for (const file of nested) {
|
|
26482
|
+
if (!file.isFile() || !file.name.endsWith(".md"))
|
|
26483
|
+
continue;
|
|
26484
|
+
add(kind, `${entry.name}/${file.name.replace(/\.md$/i, "")}`, join36(root, entry.name, file.name));
|
|
26485
|
+
}
|
|
26486
|
+
}
|
|
26487
|
+
}
|
|
26488
|
+
return sources;
|
|
26489
|
+
}
|
|
26490
|
+
function wikiReindex() {
|
|
26491
|
+
const documents = collectIndexableDocuments();
|
|
26492
|
+
const index = openWikiSearchIndex();
|
|
26493
|
+
if (!index) {
|
|
26494
|
+
return {
|
|
26495
|
+
content: [{ type: "text", text: "Could not open the wiki search index." }],
|
|
26496
|
+
isError: true
|
|
26497
|
+
};
|
|
26498
|
+
}
|
|
26499
|
+
let synced;
|
|
26500
|
+
try {
|
|
26501
|
+
synced = index.sync(documents, (source, text2) => prepareWikiSearchDocument(source.kind, source.key, text2));
|
|
26502
|
+
} catch (error2) {
|
|
26503
|
+
return {
|
|
26504
|
+
content: [{ type: "text", text: `Failed to rebuild the search index: ${String(error2)}` }],
|
|
26505
|
+
isError: true
|
|
26506
|
+
};
|
|
26507
|
+
} finally {
|
|
26508
|
+
index.close();
|
|
26509
|
+
}
|
|
26510
|
+
const lines = [
|
|
26511
|
+
`Search index: ${synced.added} added, ${synced.updated} updated, ${synced.removed} removed (${documents.length} documents).`
|
|
26512
|
+
];
|
|
26513
|
+
for (const kind of ["article", "summary"]) {
|
|
26514
|
+
const rows = new Set(parseWikiIndex(wikiIndexPath(kind)).filter((candidate) => candidate.kind === kind).map((candidate) => candidate.key));
|
|
26515
|
+
const keys = documents.filter((source) => source.kind === kind).map((source) => source.key);
|
|
26516
|
+
const unindexed = keys.filter((key) => !rows.has(key));
|
|
26517
|
+
const tombstones = [...rows].filter((key) => !keys.includes(key));
|
|
26518
|
+
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(", ")}` : ""));
|
|
26519
|
+
}
|
|
26520
|
+
return { content: [{ type: "text", text: lines.join(`
|
|
26521
|
+
`) }] };
|
|
26522
|
+
}
|
|
26523
|
+
function indexRowOrPartialWrite(label, options) {
|
|
26524
|
+
try {
|
|
26525
|
+
return upsertIndexRow(options);
|
|
26526
|
+
} catch (error2) {
|
|
26527
|
+
return {
|
|
26528
|
+
content: [
|
|
26529
|
+
{
|
|
26530
|
+
type: "text",
|
|
26531
|
+
text: `Wrote the ${label} document but failed to index it (${String(error2)}). Retry the same wiki_write call: both writes are idempotent.`
|
|
26532
|
+
}
|
|
26533
|
+
],
|
|
26534
|
+
isError: true
|
|
26535
|
+
};
|
|
26536
|
+
}
|
|
26537
|
+
}
|
|
26538
|
+
function upsertIndexRow(options) {
|
|
26539
|
+
const { kind, slug, description, date, section } = options;
|
|
26540
|
+
const indexPath = wikiIndexPath(kind);
|
|
25955
26541
|
ensureDir(dirname16(indexPath));
|
|
25956
26542
|
const releaseLock = acquireFileLock(indexPath);
|
|
25957
26543
|
try {
|
|
25958
26544
|
let index;
|
|
25959
26545
|
try {
|
|
25960
|
-
index =
|
|
26546
|
+
index = readFileSync23(indexPath, "utf-8");
|
|
25961
26547
|
} catch {
|
|
25962
26548
|
index = "";
|
|
25963
26549
|
}
|
|
25964
26550
|
const lines = index.split(`
|
|
25965
26551
|
`);
|
|
25966
|
-
const
|
|
25967
|
-
|
|
25968
|
-
case "summary":
|
|
25969
|
-
return `- [[summaries/${slug}]] ${desc} (${dateStr})`;
|
|
25970
|
-
case "topic":
|
|
25971
|
-
return `- [[topic/${slug}]] ${desc} (${dateStr})`;
|
|
25972
|
-
case "skill":
|
|
25973
|
-
return `- [[skills/${slug}]] ${desc} (${dateStr})`;
|
|
25974
|
-
default:
|
|
25975
|
-
return `- [[articles/${slug}]] ${desc} (${dateStr})`;
|
|
25976
|
-
}
|
|
25977
|
-
})();
|
|
25978
|
-
const target = (() => {
|
|
25979
|
-
switch (kind) {
|
|
25980
|
-
case "summary":
|
|
25981
|
-
return `summaries/${slug}`;
|
|
25982
|
-
case "topic":
|
|
25983
|
-
return `topic/${slug}`;
|
|
25984
|
-
case "skill":
|
|
25985
|
-
return `skills/${slug}`;
|
|
25986
|
-
default:
|
|
25987
|
-
return `articles/${slug}`;
|
|
25988
|
-
}
|
|
25989
|
-
})();
|
|
26552
|
+
const target = `${WIKI_INDEX_NAMESPACES[kind]}/${slug}`;
|
|
26553
|
+
const link = `- [[${target}]] ${description} (${date})`;
|
|
25990
26554
|
const slugPattern = `[[${target}]]`;
|
|
25991
26555
|
let replaced = false;
|
|
25992
26556
|
for (let i = lines.length - 1;i >= 0; i--) {
|
|
@@ -26024,11 +26588,63 @@ function indexUpsert(args) {
|
|
|
26024
26588
|
}
|
|
26025
26589
|
atomicWriteFile(indexPath, lines.join(`
|
|
26026
26590
|
`));
|
|
26027
|
-
return
|
|
26591
|
+
return link;
|
|
26028
26592
|
} finally {
|
|
26029
26593
|
releaseLock();
|
|
26030
26594
|
}
|
|
26031
26595
|
}
|
|
26596
|
+
function wikiDocumentExists(kind, slug) {
|
|
26597
|
+
const root = kind === "article" ? runtime().articlesDir : kind === "summary" ? runtime().summariesDir : kind === "topic" ? runtime().topicsDir : runtime().skillsDir;
|
|
26598
|
+
const filePath = resolve17(root, `${slug}.md`);
|
|
26599
|
+
if (relative2(root, filePath).startsWith(".."))
|
|
26600
|
+
return false;
|
|
26601
|
+
try {
|
|
26602
|
+
return statSync15(filePath).isFile();
|
|
26603
|
+
} catch {
|
|
26604
|
+
return false;
|
|
26605
|
+
}
|
|
26606
|
+
}
|
|
26607
|
+
function indexUpsert(args) {
|
|
26608
|
+
const rawSlug = safeExt(args, ["slug", "id"], "");
|
|
26609
|
+
const rawDescription = safeExt(args, ["description", "desc", "text"], "");
|
|
26610
|
+
const rawKind = safeExt(args, ["kind", "type"], "article");
|
|
26611
|
+
const section = safeExt(args, ["section", "category"], undefined);
|
|
26612
|
+
const date = safeExt(args, ["date", "created"], undefined);
|
|
26613
|
+
if (!(rawKind in WIKI_INDEX_FILENAMES)) {
|
|
26614
|
+
return {
|
|
26615
|
+
content: [{ type: "text", text: `Unsupported kind: ${rawKind}` }],
|
|
26616
|
+
isError: true
|
|
26617
|
+
};
|
|
26618
|
+
}
|
|
26619
|
+
const kind = rawKind;
|
|
26620
|
+
const slugResult = normalizeWikiSlug(rawSlug);
|
|
26621
|
+
if ("error" in slugResult) {
|
|
26622
|
+
return { content: [{ type: "text", text: slugResult.error }], isError: true };
|
|
26623
|
+
}
|
|
26624
|
+
const descriptionResult = normalizeIndexDescription(rawDescription);
|
|
26625
|
+
if ("error" in descriptionResult) {
|
|
26626
|
+
return { content: [{ type: "text", text: descriptionResult.error }], isError: true };
|
|
26627
|
+
}
|
|
26628
|
+
if (kind !== "topic" && !wikiDocumentExists(kind, slugResult.slug)) {
|
|
26629
|
+
return {
|
|
26630
|
+
content: [
|
|
26631
|
+
{
|
|
26632
|
+
type: "text",
|
|
26633
|
+
text: `No ${kind} document named ${slugResult.slug}. Use wiki_write to create the document and its catalog row together.`
|
|
26634
|
+
}
|
|
26635
|
+
],
|
|
26636
|
+
isError: true
|
|
26637
|
+
};
|
|
26638
|
+
}
|
|
26639
|
+
const link = upsertIndexRow({
|
|
26640
|
+
kind,
|
|
26641
|
+
slug: slugResult.slug,
|
|
26642
|
+
description: descriptionResult.description,
|
|
26643
|
+
date: date ?? new Date().toISOString().slice(0, 10),
|
|
26644
|
+
section
|
|
26645
|
+
});
|
|
26646
|
+
return { content: [{ type: "text", text: `Index updated: ${link}` }] };
|
|
26647
|
+
}
|
|
26032
26648
|
function createWikiMcpServer(context, host2) {
|
|
26033
26649
|
const surface = context.surface ?? "all";
|
|
26034
26650
|
const wikiDir = resolve17(host2.wikiRoot);
|
|
@@ -26069,8 +26685,8 @@ function createWikiMcpServer(context, host2) {
|
|
|
26069
26685
|
wiki_last_conversation: wikiLastConversation,
|
|
26070
26686
|
skill_query: skillQuery,
|
|
26071
26687
|
skill_save: skillSave,
|
|
26072
|
-
|
|
26073
|
-
|
|
26688
|
+
wiki_write: wikiWrite,
|
|
26689
|
+
wiki_reindex: wikiReindex,
|
|
26074
26690
|
index_upsert: indexUpsert
|
|
26075
26691
|
};
|
|
26076
26692
|
const handler = tools.some((tool) => tool.name === name) ? handlers[name] : undefined;
|
|
@@ -26079,10 +26695,11 @@ function createWikiMcpServer(context, host2) {
|
|
|
26079
26695
|
});
|
|
26080
26696
|
return server;
|
|
26081
26697
|
}
|
|
26082
|
-
var wikiRuntime, FILE_LOCK_WAIT_MS = 10, FILE_LOCK_TIMEOUT_MS = 5000, FILE_LOCK_STALE_MS = 30000, lockWaitArray, SEARCH_STOP_WORDS, SEARCH_MONTHS, SEARCH_RECENCY_TERMS, WIKI_TOOLS, SKILL_TOOLS;
|
|
26083
|
-
var init_wiki_server = __esm(() => {
|
|
26698
|
+
var wikiRuntime, FILE_LOCK_WAIT_MS = 10, FILE_LOCK_TIMEOUT_MS = 5000, FILE_LOCK_STALE_MS = 30000, lockWaitArray, SEARCH_STOP_WORDS, SEARCH_MONTHS, SEARCH_RECENCY_TERMS, WIKI_SEARCH_INDEX_FILENAME = ".wiki-search-index.sqlite", WIKI_INDEX_FILENAMES, WIKI_INDEX_NAMESPACES, MAX_INDEX_DESCRIPTION_LENGTH = 400, SEARCH_CACHE_SKIPPED_NOTE = "Body-search cache was not updated; catalog retrieval still works. Run wiki_reindex to refill it.", WIKI_TOOLS, SKILL_TOOLS;
|
|
26699
|
+
var init_wiki_server = __esm(async () => {
|
|
26084
26700
|
init_config();
|
|
26085
26701
|
init_wiki_summary_names();
|
|
26702
|
+
await init_wiki_search_index();
|
|
26086
26703
|
wikiRuntime = new AsyncLocalStorage3;
|
|
26087
26704
|
lockWaitArray = new Int32Array(new SharedArrayBuffer(4));
|
|
26088
26705
|
SEARCH_STOP_WORDS = new Set([
|
|
@@ -26156,6 +26773,18 @@ var init_wiki_server = __esm(() => {
|
|
|
26156
26773
|
"\uCD5C\uCD08",
|
|
26157
26774
|
"\uC624\uB798\uB41C"
|
|
26158
26775
|
]);
|
|
26776
|
+
WIKI_INDEX_FILENAMES = {
|
|
26777
|
+
article: "article-index.md",
|
|
26778
|
+
summary: "summary-index.md",
|
|
26779
|
+
topic: "topic-index.md",
|
|
26780
|
+
skill: "skill-index.md"
|
|
26781
|
+
};
|
|
26782
|
+
WIKI_INDEX_NAMESPACES = {
|
|
26783
|
+
article: "articles",
|
|
26784
|
+
summary: "summaries",
|
|
26785
|
+
topic: "topic",
|
|
26786
|
+
skill: "skills"
|
|
26787
|
+
};
|
|
26159
26788
|
WIKI_TOOLS = [
|
|
26160
26789
|
{
|
|
26161
26790
|
name: "wiki_query",
|
|
@@ -26237,35 +26866,46 @@ var init_wiki_server = __esm(() => {
|
|
|
26237
26866
|
}
|
|
26238
26867
|
},
|
|
26239
26868
|
{
|
|
26240
|
-
name: "
|
|
26241
|
-
description: "
|
|
26869
|
+
name: "wiki_write",
|
|
26870
|
+
description: "Write a wiki document and its catalog row together. The only way to create a summary, article, or topic brief: summaries go to wiki/summaries/ + summary-index.md, articles to wiki/articles/ + article-index.md, briefs to wiki/topic/ + topic-index.md (also mirrored into SQLite for next-session injection). Never write wiki files by any other means.",
|
|
26242
26871
|
inputSchema: {
|
|
26243
26872
|
type: "object",
|
|
26244
26873
|
properties: {
|
|
26245
|
-
|
|
26246
|
-
|
|
26874
|
+
kind: {
|
|
26875
|
+
type: "string",
|
|
26876
|
+
enum: ["summary", "article", "topic"],
|
|
26877
|
+
description: "Which document to write"
|
|
26878
|
+
},
|
|
26879
|
+
content: { type: "string", description: "Document body in markdown" },
|
|
26880
|
+
description: {
|
|
26881
|
+
type: "string",
|
|
26882
|
+
description: "Single-line catalog description; required so the index stays useful"
|
|
26883
|
+
},
|
|
26884
|
+
topic: {
|
|
26885
|
+
type: "string",
|
|
26886
|
+
description: "Topic name; required for kind=summary and kind=topic"
|
|
26887
|
+
},
|
|
26888
|
+
slug: {
|
|
26889
|
+
type: "string",
|
|
26890
|
+
description: "Article slug in kebab-case; required for kind=article"
|
|
26891
|
+
},
|
|
26892
|
+
section: {
|
|
26893
|
+
type: "string",
|
|
26894
|
+
description: "H2 catalog section; required for kind=article"
|
|
26895
|
+
},
|
|
26896
|
+
date: { type: "string", description: "Override entry date YYYY-MM-DD (default: today)" }
|
|
26247
26897
|
},
|
|
26248
|
-
required: ["
|
|
26898
|
+
required: ["kind", "content", "description"]
|
|
26249
26899
|
}
|
|
26250
26900
|
},
|
|
26251
26901
|
{
|
|
26252
|
-
name: "
|
|
26253
|
-
description: "
|
|
26254
|
-
inputSchema: {
|
|
26255
|
-
type: "object",
|
|
26256
|
-
properties: {
|
|
26257
|
-
topic: { type: "string", description: "Topic name of the session" },
|
|
26258
|
-
content: {
|
|
26259
|
-
type: "string",
|
|
26260
|
-
description: "Full accumulated topic brief in markdown (persona layer + recent work)"
|
|
26261
|
-
}
|
|
26262
|
-
},
|
|
26263
|
-
required: ["topic", "content"]
|
|
26264
|
-
}
|
|
26902
|
+
name: "wiki_reindex",
|
|
26903
|
+
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.",
|
|
26904
|
+
inputSchema: { type: "object", properties: {} }
|
|
26265
26905
|
},
|
|
26266
26906
|
{
|
|
26267
26907
|
name: "index_upsert",
|
|
26268
|
-
description: "
|
|
26908
|
+
description: "Correct the description or section of an entry that already exists. Cannot create an entry \u2014 use wiki_write for that.",
|
|
26269
26909
|
inputSchema: {
|
|
26270
26910
|
type: "object",
|
|
26271
26911
|
properties: {
|
|
@@ -26342,12 +26982,12 @@ __export(exports_activity_log, {
|
|
|
26342
26982
|
readSentFilesForTopic: () => readSentFilesForTopic
|
|
26343
26983
|
});
|
|
26344
26984
|
import {
|
|
26345
|
-
existsSync as
|
|
26985
|
+
existsSync as existsSync28,
|
|
26346
26986
|
mkdirSync as mkdirSync25,
|
|
26347
26987
|
readdirSync as readdirSync11,
|
|
26348
26988
|
renameSync as renameSync12,
|
|
26349
26989
|
statSync as statSync16,
|
|
26350
|
-
unlinkSync as
|
|
26990
|
+
unlinkSync as unlinkSync20,
|
|
26351
26991
|
writeFileSync as writeFileSync18
|
|
26352
26992
|
} from "fs";
|
|
26353
26993
|
import { basename as basename8, join as join37 } from "path";
|
|
@@ -26400,7 +27040,7 @@ function rotateOldLogs() {
|
|
|
26400
27040
|
if (freed >= toFree)
|
|
26401
27041
|
break;
|
|
26402
27042
|
try {
|
|
26403
|
-
|
|
27043
|
+
unlinkSync20(join37(logDir, file.name));
|
|
26404
27044
|
freed += file.size;
|
|
26405
27045
|
logger.info({ file: file.name, sizeKB: (file.size / 1024).toFixed(0) }, "Rotated out old log");
|
|
26406
27046
|
} catch (e) {
|
|
@@ -26426,7 +27066,7 @@ function entryMatchesTopic(e, topicName) {
|
|
|
26426
27066
|
}
|
|
26427
27067
|
function readSentFilesForTopic(userId, topicName) {
|
|
26428
27068
|
const file = join37(resolveStorageUsersLogDir(), String(userId), "sent-files.jsonl");
|
|
26429
|
-
if (!
|
|
27069
|
+
if (!existsSync28(file))
|
|
26430
27070
|
return [];
|
|
26431
27071
|
try {
|
|
26432
27072
|
return readJsonlLines(file).map((line) => JSON.parse(line)).filter((e) => entryMatchesTopic(e, topicName));
|
|
@@ -26437,7 +27077,7 @@ function readSentFilesForTopic(userId, topicName) {
|
|
|
26437
27077
|
}
|
|
26438
27078
|
function removeSentFilesForTopic(userId, topicName) {
|
|
26439
27079
|
const file = join37(resolveStorageUsersLogDir(), String(userId), "sent-files.jsonl");
|
|
26440
|
-
if (!
|
|
27080
|
+
if (!existsSync28(file))
|
|
26441
27081
|
return;
|
|
26442
27082
|
try {
|
|
26443
27083
|
const remaining = readJsonlLines(file).filter((line) => {
|
|
@@ -26452,7 +27092,7 @@ function removeSentFilesForTopic(userId, topicName) {
|
|
|
26452
27092
|
`)}
|
|
26453
27093
|
`);
|
|
26454
27094
|
} else {
|
|
26455
|
-
|
|
27095
|
+
unlinkSync20(file);
|
|
26456
27096
|
}
|
|
26457
27097
|
} catch (e) {
|
|
26458
27098
|
logger.warn({ err: e, userId, topicName }, "Failed to remove sent-files for topic");
|
|
@@ -26985,6 +27625,7 @@ __export(exports_storage_public, {
|
|
|
26985
27625
|
setTopicAgentAndSession: () => setTopicAgentAndSession,
|
|
26986
27626
|
setTopicAgentAndClearSession: () => setTopicAgentAndClearSession,
|
|
26987
27627
|
setTopicAgent: () => setTopicAgent,
|
|
27628
|
+
setTopicAccessModes: () => setTopicAccessModes,
|
|
26988
27629
|
setSessionForTopic: () => setSessionForTopic,
|
|
26989
27630
|
setLastShownConfig: () => setLastShownConfig,
|
|
26990
27631
|
setGlobalAiName: () => setGlobalAiName,
|
|
@@ -27250,7 +27891,7 @@ async function buildHostedSurfaceServer(surface, context) {
|
|
|
27250
27891
|
case "wiki":
|
|
27251
27892
|
case "skills": {
|
|
27252
27893
|
const [{ createWikiMcpServer: createWikiMcpServer2 }, storage, { WORKSPACE_DIR: WORKSPACE_DIR2 }] = await Promise.all([
|
|
27253
|
-
|
|
27894
|
+
init_wiki_server().then(() => exports_wiki_server),
|
|
27254
27895
|
init_storage_public().then(() => exports_storage_public),
|
|
27255
27896
|
init_mcp_runtime_host().then(() => exports_mcp_runtime_host)
|
|
27256
27897
|
]);
|
|
@@ -27961,7 +28602,7 @@ var init_spec = __esm(() => {
|
|
|
27961
28602
|
});
|
|
27962
28603
|
|
|
27963
28604
|
// ../../packages/mcp-host/src/manifest.ts
|
|
27964
|
-
import { existsSync as
|
|
28605
|
+
import { existsSync as existsSync29, mkdirSync as mkdirSync26, readFileSync as readFileSync24, renameSync as renameSync13, writeFileSync as writeFileSync19 } from "fs";
|
|
27965
28606
|
import { dirname as dirname17 } from "path";
|
|
27966
28607
|
import { z as z14 } from "zod";
|
|
27967
28608
|
|
|
@@ -28006,11 +28647,11 @@ class McpManifest {
|
|
|
28006
28647
|
return this.entries.get(key)?.enabled ?? false;
|
|
28007
28648
|
}
|
|
28008
28649
|
load() {
|
|
28009
|
-
if (!
|
|
28650
|
+
if (!existsSync29(this.file))
|
|
28010
28651
|
return;
|
|
28011
28652
|
let parsed;
|
|
28012
28653
|
try {
|
|
28013
|
-
parsed = manifestFileSchema.parse(JSON.parse(
|
|
28654
|
+
parsed = manifestFileSchema.parse(JSON.parse(readFileSync24(this.file, "utf8")));
|
|
28014
28655
|
} catch (e) {
|
|
28015
28656
|
throw new Error(`Invalid MCP manifest at ${this.file}: ${e instanceof Error ? e.message : String(e)}`);
|
|
28016
28657
|
}
|
|
@@ -28060,9 +28701,9 @@ import { execFileSync as execFileSync8, spawn as spawn8 } from "child_process";
|
|
|
28060
28701
|
import {
|
|
28061
28702
|
mkdirSync as mkdirSync27,
|
|
28062
28703
|
readdirSync as readdirSync12,
|
|
28063
|
-
readFileSync as
|
|
28704
|
+
readFileSync as readFileSync25,
|
|
28064
28705
|
renameSync as renameSync14,
|
|
28065
|
-
unlinkSync as
|
|
28706
|
+
unlinkSync as unlinkSync21,
|
|
28066
28707
|
writeFileSync as writeFileSync20
|
|
28067
28708
|
} from "fs";
|
|
28068
28709
|
import { connect, createServer as createServer3 } from "net";
|
|
@@ -28368,7 +29009,7 @@ class McpHost {
|
|
|
28368
29009
|
if (file.includes(".tmp-"))
|
|
28369
29010
|
continue;
|
|
28370
29011
|
try {
|
|
28371
|
-
const port = Number.parseInt(
|
|
29012
|
+
const port = Number.parseInt(readFileSync25(join38(this.portsDir, file), "utf8").trim(), 10);
|
|
28372
29013
|
if (!Number.isNaN(port))
|
|
28373
29014
|
claims.set(file, port);
|
|
28374
29015
|
} catch {}
|
|
@@ -28388,7 +29029,7 @@ class McpHost {
|
|
|
28388
29029
|
}
|
|
28389
29030
|
deletePortFile(fileName) {
|
|
28390
29031
|
try {
|
|
28391
|
-
|
|
29032
|
+
unlinkSync21(join38(this.portsDir, fileName));
|
|
28392
29033
|
} catch {}
|
|
28393
29034
|
}
|
|
28394
29035
|
cleanupRunning(rkey, inst) {
|
|
@@ -28493,9 +29134,9 @@ var init_src3 = __esm(() => {
|
|
|
28493
29134
|
import { randomUUID as randomUUID24 } from "crypto";
|
|
28494
29135
|
import {
|
|
28495
29136
|
copyFileSync as copyFileSync4,
|
|
28496
|
-
existsSync as
|
|
29137
|
+
existsSync as existsSync30,
|
|
28497
29138
|
mkdirSync as mkdirSync28,
|
|
28498
|
-
readFileSync as
|
|
29139
|
+
readFileSync as readFileSync26,
|
|
28499
29140
|
rmSync as rmSync9,
|
|
28500
29141
|
statSync as statSync18,
|
|
28501
29142
|
writeFileSync as writeFileSync21
|
|
@@ -28531,7 +29172,7 @@ class NodeFileStore {
|
|
|
28531
29172
|
if (!FILE_ID_RE.test(fileId))
|
|
28532
29173
|
return null;
|
|
28533
29174
|
try {
|
|
28534
|
-
const parsed = JSON.parse(
|
|
29175
|
+
const parsed = JSON.parse(readFileSync26(this.#metadataPath(fileId), "utf8"));
|
|
28535
29176
|
if (typeof parsed.filename !== "string" || typeof parsed.mimeType !== "string" || typeof parsed.sizeBytes !== "number" || typeof parsed.savedName !== "string") {
|
|
28536
29177
|
return null;
|
|
28537
29178
|
}
|
|
@@ -28554,7 +29195,7 @@ class NodeFileStore {
|
|
|
28554
29195
|
hooks = {
|
|
28555
29196
|
resolveAttachmentByFileId: (fileId) => {
|
|
28556
29197
|
const metadata = this.#metadata(fileId);
|
|
28557
|
-
if (!metadata || !
|
|
29198
|
+
if (!metadata || !existsSync30(join39(this.uploadDir, metadata.savedName)))
|
|
28558
29199
|
return null;
|
|
28559
29200
|
return this.#attachment(fileId, metadata);
|
|
28560
29201
|
},
|
|
@@ -28563,7 +29204,7 @@ class NodeFileStore {
|
|
|
28563
29204
|
if (!metadata)
|
|
28564
29205
|
return null;
|
|
28565
29206
|
const path = join39(this.uploadDir, metadata.savedName);
|
|
28566
|
-
return
|
|
29207
|
+
return existsSync30(path) ? path : null;
|
|
28567
29208
|
},
|
|
28568
29209
|
storeLocalFileAsUpload: (absPath, access = {}) => this.store(absPath, access),
|
|
28569
29210
|
deleteFilesForTopic: (topicId) => this.deleteForTopic(topicId)
|
|
@@ -28606,7 +29247,7 @@ class NodeFileStore {
|
|
|
28606
29247
|
if (!allowed)
|
|
28607
29248
|
return null;
|
|
28608
29249
|
const path = join39(this.uploadDir, metadata.savedName);
|
|
28609
|
-
if (!
|
|
29250
|
+
if (!existsSync30(path))
|
|
28610
29251
|
return null;
|
|
28611
29252
|
return new Response(Bun.file(path), {
|
|
28612
29253
|
headers: {
|
|
@@ -28775,12 +29416,12 @@ function createPollingSseStream(req, options) {
|
|
|
28775
29416
|
// ../../packages/node/src/control.ts
|
|
28776
29417
|
import { randomUUID as randomUUID25, timingSafeEqual as timingSafeEqual4 } from "crypto";
|
|
28777
29418
|
import {
|
|
28778
|
-
chmodSync as
|
|
28779
|
-
existsSync as
|
|
29419
|
+
chmodSync as chmodSync6,
|
|
29420
|
+
existsSync as existsSync31,
|
|
28780
29421
|
mkdirSync as mkdirSync29,
|
|
28781
|
-
readFileSync as
|
|
29422
|
+
readFileSync as readFileSync27,
|
|
28782
29423
|
renameSync as renameSync15,
|
|
28783
|
-
unlinkSync as
|
|
29424
|
+
unlinkSync as unlinkSync22,
|
|
28784
29425
|
writeFileSync as writeFileSync22
|
|
28785
29426
|
} from "fs";
|
|
28786
29427
|
import { dirname as dirname18, resolve as resolve21 } from "path";
|
|
@@ -29287,16 +29928,16 @@ function writeNodeDaemonInfo(port, startedAt) {
|
|
|
29287
29928
|
const temporary = `${NODE_DAEMON_INFO_PATH}.${process.pid}.${randomUUID25()}.tmp`;
|
|
29288
29929
|
writeFileSync22(temporary, `${JSON.stringify(info, null, 2)}
|
|
29289
29930
|
`, { mode: 384 });
|
|
29290
|
-
|
|
29931
|
+
chmodSync6(temporary, 384);
|
|
29291
29932
|
renameSync15(temporary, NODE_DAEMON_INFO_PATH);
|
|
29292
|
-
|
|
29933
|
+
chmodSync6(NODE_DAEMON_INFO_PATH, 384);
|
|
29293
29934
|
return info;
|
|
29294
29935
|
}
|
|
29295
29936
|
function readNodeDaemonInfo() {
|
|
29296
|
-
if (!
|
|
29937
|
+
if (!existsSync31(NODE_DAEMON_INFO_PATH))
|
|
29297
29938
|
return null;
|
|
29298
29939
|
try {
|
|
29299
|
-
const value = JSON.parse(
|
|
29940
|
+
const value = JSON.parse(readFileSync27(NODE_DAEMON_INFO_PATH, "utf8"));
|
|
29300
29941
|
if (value?.schemaVersion !== 1 || value.stateDir !== STATE_DIR || !Number.isInteger(value.protocolVersion) || !Number.isInteger(value.pid) || !Number.isInteger(value.port) || value.port <= 0) {
|
|
29301
29942
|
return null;
|
|
29302
29943
|
}
|
|
@@ -29310,7 +29951,7 @@ function removeNodeDaemonInfo(expected) {
|
|
|
29310
29951
|
if (!current3 || current3.pid !== expected.pid || current3.port !== expected.port)
|
|
29311
29952
|
return;
|
|
29312
29953
|
try {
|
|
29313
|
-
|
|
29954
|
+
unlinkSync22(NODE_DAEMON_INFO_PATH);
|
|
29314
29955
|
} catch {}
|
|
29315
29956
|
}
|
|
29316
29957
|
async function fetchWithTimeout(url, init, timeoutMs) {
|
|
@@ -29584,7 +30225,7 @@ var init_schedule = __esm(() => {
|
|
|
29584
30225
|
|
|
29585
30226
|
// ../../packages/module-cron/src/scripts.ts
|
|
29586
30227
|
import { spawn as spawn9 } from "child_process";
|
|
29587
|
-
import { existsSync as
|
|
30228
|
+
import { existsSync as existsSync32, mkdirSync as mkdirSync30, readdirSync as readdirSync13 } from "fs";
|
|
29588
30229
|
import { resolve as resolve22, sep as sep2 } from "path";
|
|
29589
30230
|
function validateCronScriptName(script) {
|
|
29590
30231
|
if (!/^[A-Za-z0-9_][A-Za-z0-9_.-]*\.py$/.test(script) || script.includes("..") || script.includes("/") || script.includes("\\")) {
|
|
@@ -29607,7 +30248,7 @@ function listCronScripts() {
|
|
|
29607
30248
|
}
|
|
29608
30249
|
function cronScriptExists(script) {
|
|
29609
30250
|
try {
|
|
29610
|
-
return
|
|
30251
|
+
return existsSync32(resolveCronScriptPath(script));
|
|
29611
30252
|
} catch {
|
|
29612
30253
|
return false;
|
|
29613
30254
|
}
|
|
@@ -29639,7 +30280,7 @@ async function runCronPromptScript(options) {
|
|
|
29639
30280
|
if (options.signal?.aborted)
|
|
29640
30281
|
throw new CronScriptError("script run aborted");
|
|
29641
30282
|
const scriptPath = resolveCronScriptPath(options.script);
|
|
29642
|
-
if (!
|
|
30283
|
+
if (!existsSync32(scriptPath))
|
|
29643
30284
|
throw new CronScriptError(`cron script not found: ${options.script}`);
|
|
29644
30285
|
const timeoutMs = Math.max(5000, options.timeoutMs ?? DEFAULT_SCRIPT_TIMEOUT_MS);
|
|
29645
30286
|
const outputLimitBytes = Math.max(1024, options.outputLimitBytes ?? DEFAULT_OUTPUT_LIMIT_BYTES);
|
|
@@ -30840,7 +31481,7 @@ var init_scheduler = __esm(async () => {
|
|
|
30840
31481
|
});
|
|
30841
31482
|
|
|
30842
31483
|
// ../../packages/module-cron/src/module.ts
|
|
30843
|
-
import { existsSync as
|
|
31484
|
+
import { existsSync as existsSync33 } from "fs";
|
|
30844
31485
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
30845
31486
|
function envMs(name, fallback) {
|
|
30846
31487
|
const parsed = Number.parseInt(process.env[name] ?? "", 10);
|
|
@@ -30871,7 +31512,7 @@ function createCronModule(options = {}) {
|
|
|
30871
31512
|
if (event.type === "topic-deleted")
|
|
30872
31513
|
trackCleanup(resetCronTopicContext(event.topicId));
|
|
30873
31514
|
});
|
|
30874
|
-
const mcpServerFile = options.mcpServerFile ?? (
|
|
31515
|
+
const mcpServerFile = options.mcpServerFile ?? (existsSync33(SOURCE_MCP_SERVER_FILE) ? SOURCE_MCP_SERVER_FILE : PACKAGED_MCP_SERVER_FILE);
|
|
30875
31516
|
const unregisterMcp = host2.registerRuntimeMcpServer("cron-manager", {
|
|
30876
31517
|
scopes: ["forum", "manager"],
|
|
30877
31518
|
forumRequired: true,
|
|
@@ -31950,7 +32591,7 @@ function setTopics(state, topics, preferredTitle) {
|
|
|
31950
32591
|
activeTopicId: nextActive,
|
|
31951
32592
|
scrollOffset: nextActive === state.activeTopicId ? state.scrollOffset : 0,
|
|
31952
32593
|
askChoiceIndex: nextActive === state.activeTopicId ? state.askChoiceIndex : 0,
|
|
31953
|
-
topicPickerIndex: state.overlay === "topics" ? pickedTopicIndex : Math.max(0, orderedTopics.findIndex((topic) => topic.id === nextActive)),
|
|
32594
|
+
topicPickerIndex: state.overlay === "topics" || state.overlay === "confirm-share" ? pickedTopicIndex : Math.max(0, orderedTopics.findIndex((topic) => topic.id === nextActive)),
|
|
31954
32595
|
topicPickerBackgroundId: state.topicPickerBackgroundId
|
|
31955
32596
|
});
|
|
31956
32597
|
}
|
|
@@ -32369,7 +33010,7 @@ var init_context_usage = __esm(async () => {
|
|
|
32369
33010
|
|
|
32370
33011
|
// ../../adapters/terminal/src/path-suggest.ts
|
|
32371
33012
|
import { execFile as execFile3 } from "child_process";
|
|
32372
|
-
import { existsSync as
|
|
33013
|
+
import { existsSync as existsSync34, readdirSync as readdirSync14, statSync as statSync19 } from "fs";
|
|
32373
33014
|
import { homedir as homedir10 } from "os";
|
|
32374
33015
|
import { basename as basename11, dirname as dirname19, join as join40, sep as sep3 } from "path";
|
|
32375
33016
|
import { promisify as promisify3 } from "util";
|
|
@@ -32618,7 +33259,7 @@ function fragmentToAbsolutePath(frag) {
|
|
|
32618
33259
|
}
|
|
32619
33260
|
function fragmentResolves(frag) {
|
|
32620
33261
|
try {
|
|
32621
|
-
return
|
|
33262
|
+
return existsSync34(fragmentToAbsolutePath(frag));
|
|
32622
33263
|
} catch {
|
|
32623
33264
|
return false;
|
|
32624
33265
|
}
|
|
@@ -33612,14 +34253,16 @@ function subagentTreePrefix(topic, topics, rootTopicId) {
|
|
|
33612
34253
|
function topicPickerHints(topicPickerRoot) {
|
|
33613
34254
|
const exit = topicPickerRoot ? "Esc/Ctrl-C exit" : "Esc close \xB7 Ctrl-C exit; work continues";
|
|
33614
34255
|
const shortExit = topicPickerRoot ? "Esc/Ctrl-C exit" : "Esc close";
|
|
33615
|
-
|
|
34256
|
+
const candidates = [
|
|
34257
|
+
`\u2191\u2193 select \xB7 Enter open \xB7 type to filter \xB7 Ctrl-N new \xB7 Ctrl-D delete \xB7 Ctrl-P public/private \xB7 ${exit}`,
|
|
34258
|
+
`\u2191\u2193 select \xB7 Enter open \xB7 type to filter \xB7 Ctrl-N new \xB7 Ctrl-D delete \xB7 Ctrl-P public/private \xB7 ${shortExit}`,
|
|
33616
34259
|
`\u2191\u2193 select \xB7 Enter open \xB7 type to filter \xB7 Ctrl-N new \xB7 Ctrl-D delete \xB7 ${exit}`,
|
|
33617
|
-
`\u2191\u2193 select \xB7 Enter open \xB7 type to filter \xB7 Ctrl-N
|
|
33618
|
-
|
|
33619
|
-
"
|
|
33620
|
-
"
|
|
33621
|
-
"Ctrl-N/D"
|
|
34260
|
+
`\u2191\u2193 select \xB7 Enter open \xB7 type to filter \xB7 Ctrl-N/D/P \xB7 ${shortExit}`,
|
|
34261
|
+
"\u2191\u2193 \xB7 Enter \xB7 type to filter \xB7 Ctrl-N/D/P",
|
|
34262
|
+
"type to filter \xB7 Ctrl-N/D/P",
|
|
34263
|
+
"Ctrl-N/D/P"
|
|
33622
34264
|
];
|
|
34265
|
+
return [...new Set(candidates)].sort((a, b) => displayWidth(b) - displayWidth(a));
|
|
33623
34266
|
}
|
|
33624
34267
|
function topicOverlayCursor(state, width, bodyHeight) {
|
|
33625
34268
|
if (state.overlay !== "topics")
|
|
@@ -33975,6 +34618,34 @@ function conversationLines(state, width, height, animationFrame = 0, nowMs = ter
|
|
|
33975
34618
|
line(" Press y to delete or n to cancel.", { fg: theme.amber })
|
|
33976
34619
|
].slice(0, height);
|
|
33977
34620
|
}
|
|
34621
|
+
if (state.overlay === "confirm-share") {
|
|
34622
|
+
const topic = state.topics.find((candidate) => candidate.id === state.pendingShareTopicId);
|
|
34623
|
+
const subagents = (() => {
|
|
34624
|
+
if (!topic)
|
|
34625
|
+
return 0;
|
|
34626
|
+
const reached = new Set([topic.id]);
|
|
34627
|
+
for (;; ) {
|
|
34628
|
+
const next = state.topics.filter((candidate) => candidate.isSubagent && !reached.has(candidate.id) && candidate.parentTopicId !== undefined && reached.has(candidate.parentTopicId));
|
|
34629
|
+
if (next.length === 0)
|
|
34630
|
+
break;
|
|
34631
|
+
for (const candidate of next)
|
|
34632
|
+
reached.add(candidate.id);
|
|
34633
|
+
}
|
|
34634
|
+
return reached.size - 1;
|
|
34635
|
+
})();
|
|
34636
|
+
const scope = subagents > 0 ? ` Its ${subagents} subagent room${subagents === 1 ? "" : "s"} become public too.` : " Subagent rooms spawned from it will be public too.";
|
|
34637
|
+
return [
|
|
34638
|
+
line(""),
|
|
34639
|
+
line(` Make \u201C${topic?.title ?? "this topic"}\u201D public?`, {
|
|
34640
|
+
fg: theme.amber,
|
|
34641
|
+
bold: true
|
|
34642
|
+
}),
|
|
34643
|
+
line(""),
|
|
34644
|
+
line(" The transcript becomes visible to the connected Otium Hub."),
|
|
34645
|
+
line(scope),
|
|
34646
|
+
line(" Press y to publish or n to cancel.", { fg: theme.amber })
|
|
34647
|
+
].slice(0, height);
|
|
34648
|
+
}
|
|
33978
34649
|
const all = conversationContentLines(state, width, animationFrame, nowMs, includeTasks);
|
|
33979
34650
|
const { contentHeight, maxOffset, offset } = conversationViewport(all.length, height, state.scrollOffset);
|
|
33980
34651
|
const end = all.length - offset;
|
|
@@ -34242,6 +34913,9 @@ function footerHintText(state) {
|
|
|
34242
34913
|
}
|
|
34243
34914
|
return state.topicPickerRoot ? ["Esc/Ctrl-C exit ", "Esc exit "] : ["Esc close \xB7 Ctrl-C exit; work continues ", "Esc close \xB7 Ctrl-C exit ", "Esc "];
|
|
34244
34915
|
}
|
|
34916
|
+
if (state.overlay === "confirm-share") {
|
|
34917
|
+
return ["Y make public \xB7 N cancel ", "Y/N "];
|
|
34918
|
+
}
|
|
34245
34919
|
if (state.overlay === "background-session") {
|
|
34246
34920
|
return [
|
|
34247
34921
|
"wheel/PgUp/PgDn scroll \xB7 Esc back \xB7 read-only ",
|
|
@@ -37198,6 +37872,16 @@ class TerminalApp {
|
|
|
37198
37872
|
}
|
|
37199
37873
|
return;
|
|
37200
37874
|
}
|
|
37875
|
+
if (this.#state.overlay === "confirm-share") {
|
|
37876
|
+
const key = chunk.toLowerCase();
|
|
37877
|
+
if (CONFIRM_KEYS.has(key))
|
|
37878
|
+
this.#confirmTopicShare();
|
|
37879
|
+
else if (CANCEL_KEYS.has(key) || chunk === "\x1B") {
|
|
37880
|
+
this.#state = { ...this.#state, overlay: "topics", pendingShareTopicId: undefined };
|
|
37881
|
+
this.#queueRender();
|
|
37882
|
+
}
|
|
37883
|
+
return;
|
|
37884
|
+
}
|
|
37201
37885
|
if (this.#state.overlay === "background-session") {
|
|
37202
37886
|
if (chunk === "\x1B") {
|
|
37203
37887
|
this.#state = { ...this.#state, overlay: "topics" };
|
|
@@ -37506,6 +38190,22 @@ class TerminalApp {
|
|
|
37506
38190
|
this.#queueRender();
|
|
37507
38191
|
return;
|
|
37508
38192
|
}
|
|
38193
|
+
if (chunk === TOGGLE_ACCESS_MODE_KEY) {
|
|
38194
|
+
const topic = pickedTopic(this.#state);
|
|
38195
|
+
if (topic) {
|
|
38196
|
+
this.#requestAccessModeToggle(topic);
|
|
38197
|
+
return;
|
|
38198
|
+
}
|
|
38199
|
+
if (!this.#state.topicPickerBackgroundId)
|
|
38200
|
+
return;
|
|
38201
|
+
this.#state = {
|
|
38202
|
+
...this.#state,
|
|
38203
|
+
notice: "Background sessions are read-only",
|
|
38204
|
+
noticeLevel: "warn"
|
|
38205
|
+
};
|
|
38206
|
+
this.#queueRender();
|
|
38207
|
+
return;
|
|
38208
|
+
}
|
|
37509
38209
|
if (FILTER_BACKSPACE_KEYS.has(chunk)) {
|
|
37510
38210
|
if (this.#state.topicFilter.length === 0)
|
|
37511
38211
|
return;
|
|
@@ -37948,6 +38648,65 @@ class TerminalApp {
|
|
|
37948
38648
|
};
|
|
37949
38649
|
this.#queueRender();
|
|
37950
38650
|
}
|
|
38651
|
+
async#requestAccessModeToggle(topic) {
|
|
38652
|
+
if (topic.kind !== "agent") {
|
|
38653
|
+
this.#state = {
|
|
38654
|
+
...this.#state,
|
|
38655
|
+
notice: `${topic.kind === "manager" ? "Manager" : "Channel"} topics cannot be published`,
|
|
38656
|
+
noticeLevel: "warn"
|
|
38657
|
+
};
|
|
38658
|
+
this.#queueRender();
|
|
38659
|
+
return;
|
|
38660
|
+
}
|
|
38661
|
+
if (topic.isSubagent) {
|
|
38662
|
+
this.#state = {
|
|
38663
|
+
...this.#state,
|
|
38664
|
+
notice: "Subagent rooms inherit privacy from their parent topic",
|
|
38665
|
+
noticeLevel: "warn"
|
|
38666
|
+
};
|
|
38667
|
+
this.#queueRender();
|
|
38668
|
+
return;
|
|
38669
|
+
}
|
|
38670
|
+
if (topic.accessMode === "shared") {
|
|
38671
|
+
await this.#applyAccessMode(topic, "private");
|
|
38672
|
+
return;
|
|
38673
|
+
}
|
|
38674
|
+
this.#state = {
|
|
38675
|
+
...this.#state,
|
|
38676
|
+
overlay: "confirm-share",
|
|
38677
|
+
pendingShareTopicId: topic.id
|
|
38678
|
+
};
|
|
38679
|
+
this.#queueRender();
|
|
38680
|
+
}
|
|
38681
|
+
async#confirmTopicShare() {
|
|
38682
|
+
const topic = this.#state.topics.find((candidate) => candidate.id === this.#state.pendingShareTopicId);
|
|
38683
|
+
this.#state = { ...this.#state, overlay: "topics", pendingShareTopicId: undefined };
|
|
38684
|
+
if (!topic) {
|
|
38685
|
+
this.#state = {
|
|
38686
|
+
...this.#state,
|
|
38687
|
+
notice: "That topic no longer exists",
|
|
38688
|
+
noticeLevel: "warn"
|
|
38689
|
+
};
|
|
38690
|
+
this.#queueRender();
|
|
38691
|
+
return;
|
|
38692
|
+
}
|
|
38693
|
+
await this.#applyAccessMode(topic, "shared");
|
|
38694
|
+
}
|
|
38695
|
+
async#applyAccessMode(topic, accessMode) {
|
|
38696
|
+
this.#state = { ...this.#state, overlay: "topics" };
|
|
38697
|
+
try {
|
|
38698
|
+
const notice = await this.#client.setAccessMode(topic, accessMode);
|
|
38699
|
+
await this.#refreshTopics();
|
|
38700
|
+
this.#state = { ...this.#state, notice, noticeLevel: "success" };
|
|
38701
|
+
} catch (error2) {
|
|
38702
|
+
this.#state = {
|
|
38703
|
+
...this.#state,
|
|
38704
|
+
notice: error2 instanceof Error ? error2.message : String(error2),
|
|
38705
|
+
noticeLevel: "error"
|
|
38706
|
+
};
|
|
38707
|
+
}
|
|
38708
|
+
this.#queueRender();
|
|
38709
|
+
}
|
|
37951
38710
|
#requestTopicDelete(topic) {
|
|
37952
38711
|
if (!topic)
|
|
37953
38712
|
return;
|
|
@@ -38226,6 +38985,7 @@ class TerminalApp {
|
|
|
38226
38985
|
...this.#state,
|
|
38227
38986
|
overlay: null,
|
|
38228
38987
|
pendingDeleteTopicId: undefined,
|
|
38988
|
+
pendingShareTopicId: undefined,
|
|
38229
38989
|
creatingTopic: false,
|
|
38230
38990
|
notice: "Input cleared",
|
|
38231
38991
|
noticeLevel: "info"
|
|
@@ -38288,7 +39048,7 @@ class TerminalApp {
|
|
|
38288
39048
|
await this.#client.stop();
|
|
38289
39049
|
}
|
|
38290
39050
|
}
|
|
38291
|
-
var KITTY_KEYBOARD_PUSH = "\x1B[>1u", KITTY_KEYBOARD_POP = "\x1B[<u", CANVAS_RGB, ENTER_ALT_SCREEN, EXIT_ALT_SCREEN, ABORT_ENTER_ALT_SCREEN, NEW_TOPIC_KEY = "\x0E", DELETE_TOPIC_KEY = "\x04", FILTER_BACKSPACE_KEYS, CONFIRM_KEYS, CANCEL_KEYS, INPUT_CARRY_FLUSH_MS = 15;
|
|
39051
|
+
var KITTY_KEYBOARD_PUSH = "\x1B[>1u", KITTY_KEYBOARD_POP = "\x1B[<u", CANVAS_RGB, ENTER_ALT_SCREEN, EXIT_ALT_SCREEN, ABORT_ENTER_ALT_SCREEN, NEW_TOPIC_KEY = "\x0E", DELETE_TOPIC_KEY = "\x04", TOGGLE_ACCESS_MODE_KEY = "\x10", FILTER_BACKSPACE_KEYS, CONFIRM_KEYS, CANCEL_KEYS, INPUT_CARRY_FLUSH_MS = 15;
|
|
38292
39052
|
var init_app = __esm(async () => {
|
|
38293
39053
|
init_color_depth();
|
|
38294
39054
|
init_commands();
|
|
@@ -39312,7 +40072,7 @@ function renderOutbound(text2, maxLen = 4096) {
|
|
|
39312
40072
|
}
|
|
39313
40073
|
|
|
39314
40074
|
// ../../adapters/telegram/src/adapter.ts
|
|
39315
|
-
import { existsSync as
|
|
40075
|
+
import { existsSync as existsSync35 } from "fs";
|
|
39316
40076
|
import { basename as basename12, extname as extname5 } from "path";
|
|
39317
40077
|
function startTelegramAdapter(opts) {
|
|
39318
40078
|
const { client, forumChatId } = opts;
|
|
@@ -39800,7 +40560,7 @@ function startTelegramAdapter(opts) {
|
|
|
39800
40560
|
logger.warn({ path, chatId }, "telegram adapter: blocked sensitive file path");
|
|
39801
40561
|
return { ref: null, delivered: false, error: "path matches the sensitive-file blacklist" };
|
|
39802
40562
|
}
|
|
39803
|
-
if (!
|
|
40563
|
+
if (!existsSync35(path)) {
|
|
39804
40564
|
const sent = await client.sendMessage(chatId, `File: ${path}`, base).catch(() => null);
|
|
39805
40565
|
const messageId = sentMessageId(sent);
|
|
39806
40566
|
return {
|
|
@@ -40982,19 +41742,19 @@ __export(exports_join, {
|
|
|
40982
41742
|
});
|
|
40983
41743
|
import { createHash as createHash11, randomUUID as randomUUID27 } from "crypto";
|
|
40984
41744
|
import {
|
|
40985
|
-
chmodSync as
|
|
41745
|
+
chmodSync as chmodSync7,
|
|
40986
41746
|
closeSync as closeSync5,
|
|
40987
|
-
existsSync as
|
|
41747
|
+
existsSync as existsSync36,
|
|
40988
41748
|
fsyncSync as fsyncSync2,
|
|
40989
41749
|
linkSync,
|
|
40990
41750
|
lstatSync,
|
|
40991
41751
|
mkdirSync as mkdirSync32,
|
|
40992
41752
|
openSync as openSync5,
|
|
40993
|
-
readFileSync as
|
|
41753
|
+
readFileSync as readFileSync28,
|
|
40994
41754
|
renameSync as renameSync16,
|
|
40995
41755
|
rmSync as rmSync10,
|
|
40996
41756
|
statSync as statSync20,
|
|
40997
|
-
unlinkSync as
|
|
41757
|
+
unlinkSync as unlinkSync23,
|
|
40998
41758
|
writeFileSync as writeFileSync23
|
|
40999
41759
|
} from "fs";
|
|
41000
41760
|
import { dirname as dirname21, resolve as resolve23 } from "path";
|
|
@@ -41094,7 +41854,7 @@ function withJoinCredentialLock(operation) {
|
|
|
41094
41854
|
throw error2;
|
|
41095
41855
|
let current3 = null;
|
|
41096
41856
|
try {
|
|
41097
|
-
current3 = JSON.parse(
|
|
41857
|
+
current3 = JSON.parse(readFileSync28(ownerPath, "utf8"));
|
|
41098
41858
|
} catch {}
|
|
41099
41859
|
let ageMs;
|
|
41100
41860
|
try {
|
|
@@ -41124,7 +41884,7 @@ function withJoinCredentialLock(operation) {
|
|
|
41124
41884
|
return operation();
|
|
41125
41885
|
} finally {
|
|
41126
41886
|
try {
|
|
41127
|
-
const current3 = JSON.parse(
|
|
41887
|
+
const current3 = JSON.parse(readFileSync28(ownerPath, "utf8"));
|
|
41128
41888
|
if (current3.pid === owner.pid && current3.token === owner.token) {
|
|
41129
41889
|
rmSync10(lockPath, { recursive: true, force: true });
|
|
41130
41890
|
}
|
|
@@ -41147,9 +41907,9 @@ function joinCredentialDigest(join42) {
|
|
|
41147
41907
|
return createHash11("sha256").update(JSON.stringify(normalizedJoin(join42))).digest("base64url");
|
|
41148
41908
|
}
|
|
41149
41909
|
function readPersistedJoin(path = joinFilePath()) {
|
|
41150
|
-
if (!
|
|
41910
|
+
if (!existsSync36(path))
|
|
41151
41911
|
return null;
|
|
41152
|
-
const parsed = JSON.parse(
|
|
41912
|
+
const parsed = JSON.parse(readFileSync28(path, "utf-8"));
|
|
41153
41913
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
41154
41914
|
throw new Error("persisted join credentials are not a JSON object");
|
|
41155
41915
|
}
|
|
@@ -41168,7 +41928,7 @@ function saveJoinWhileLocked(join42, options = {}) {
|
|
|
41168
41928
|
const directory = dirname21(path);
|
|
41169
41929
|
const normalized = normalizedJoin(join42);
|
|
41170
41930
|
mkdirSync32(directory, { recursive: true });
|
|
41171
|
-
if (
|
|
41931
|
+
if (existsSync36(path)) {
|
|
41172
41932
|
if (lstatSync(path).isSymbolicLink()) {
|
|
41173
41933
|
throw new Error(`refusing to replace symlinked Otium join file at ${path}`);
|
|
41174
41934
|
}
|
|
@@ -41181,7 +41941,7 @@ function saveJoinWhileLocked(join42, options = {}) {
|
|
|
41181
41941
|
}
|
|
41182
41942
|
}
|
|
41183
41943
|
if (existing && joinsEqual(existing, normalized)) {
|
|
41184
|
-
|
|
41944
|
+
chmodSync7(path, 384);
|
|
41185
41945
|
const fileFd = openSync5(path, "r");
|
|
41186
41946
|
try {
|
|
41187
41947
|
fsyncSync2(fileFd);
|
|
@@ -41213,9 +41973,9 @@ function saveJoinWhileLocked(join42, options = {}) {
|
|
|
41213
41973
|
renameSync16(temporaryPath, path);
|
|
41214
41974
|
} else {
|
|
41215
41975
|
linkSync(temporaryPath, path);
|
|
41216
|
-
|
|
41976
|
+
unlinkSync23(temporaryPath);
|
|
41217
41977
|
}
|
|
41218
|
-
|
|
41978
|
+
chmodSync7(path, 384);
|
|
41219
41979
|
const directoryFd = openSync5(directory, "r");
|
|
41220
41980
|
try {
|
|
41221
41981
|
fsyncSync2(directoryFd);
|
|
@@ -41225,8 +41985,8 @@ function saveJoinWhileLocked(join42, options = {}) {
|
|
|
41225
41985
|
} catch (error2) {
|
|
41226
41986
|
if (fd !== undefined)
|
|
41227
41987
|
closeSync5(fd);
|
|
41228
|
-
if (
|
|
41229
|
-
|
|
41988
|
+
if (existsSync36(temporaryPath))
|
|
41989
|
+
unlinkSync23(temporaryPath);
|
|
41230
41990
|
throw error2;
|
|
41231
41991
|
}
|
|
41232
41992
|
return path;
|
|
@@ -41237,12 +41997,12 @@ function saveJoin(join42, options = {}) {
|
|
|
41237
41997
|
function removeJoin() {
|
|
41238
41998
|
return withJoinCredentialLock(() => {
|
|
41239
41999
|
const path = joinFilePath();
|
|
41240
|
-
if (!
|
|
42000
|
+
if (!existsSync36(path))
|
|
41241
42001
|
return false;
|
|
41242
42002
|
if (lstatSync(path).isSymbolicLink()) {
|
|
41243
42003
|
throw new Error(`refusing to remove symlinked Otium join file at ${path}`);
|
|
41244
42004
|
}
|
|
41245
|
-
|
|
42005
|
+
unlinkSync23(path);
|
|
41246
42006
|
const directoryFd = openSync5(dirname21(path), "r");
|
|
41247
42007
|
try {
|
|
41248
42008
|
fsyncSync2(directoryFd);
|
|
@@ -41269,10 +42029,10 @@ function loadJoin() {
|
|
|
41269
42029
|
logger.warn("otium: OTIUM_CENTRAL_URL, OTIUM_CELL_ID, OTIUM_CELL_SECRET must be set together \u2014 ignoring partial env");
|
|
41270
42030
|
}
|
|
41271
42031
|
const path = joinFilePath();
|
|
41272
|
-
if (!
|
|
42032
|
+
if (!existsSync36(path))
|
|
41273
42033
|
return null;
|
|
41274
42034
|
try {
|
|
41275
|
-
const parsed = JSON.parse(
|
|
42035
|
+
const parsed = JSON.parse(readFileSync28(path, "utf-8"));
|
|
41276
42036
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
41277
42037
|
return null;
|
|
41278
42038
|
return normalizeJoin(parsed);
|
|
@@ -41296,11 +42056,11 @@ var exports_join_status = {};
|
|
|
41296
42056
|
__export(exports_join_status, {
|
|
41297
42057
|
hasConfiguredOtiumJoin: () => hasConfiguredOtiumJoin
|
|
41298
42058
|
});
|
|
41299
|
-
import { existsSync as
|
|
42059
|
+
import { existsSync as existsSync37 } from "fs";
|
|
41300
42060
|
import { resolve as resolve24 } from "path";
|
|
41301
42061
|
function hasConfiguredOtiumJoin() {
|
|
41302
42062
|
const envJoin = Boolean(process.env.OTIUM_CENTRAL_URL?.trim() && process.env.OTIUM_CELL_ID?.trim() && process.env.OTIUM_CELL_SECRET?.trim());
|
|
41303
|
-
return envJoin ||
|
|
42063
|
+
return envJoin || existsSync37(resolve24(DATA_DIR, "otium-join.json"));
|
|
41304
42064
|
}
|
|
41305
42065
|
var init_join_status = __esm(() => {
|
|
41306
42066
|
init_config_public();
|
|
@@ -41528,8 +42288,7 @@ var init_canonical_mcp_bridge = __esm(async () => {
|
|
|
41528
42288
|
"wiki_read",
|
|
41529
42289
|
"wiki_topic_brief",
|
|
41530
42290
|
"wiki_last_conversation",
|
|
41531
|
-
"
|
|
41532
|
-
"save_topic_brief",
|
|
42291
|
+
"wiki_write",
|
|
41533
42292
|
"index_upsert"
|
|
41534
42293
|
])
|
|
41535
42294
|
};
|
|
@@ -43937,8 +44696,13 @@ function shareOtiumTopic(options) {
|
|
|
43937
44696
|
if (!owned.ok)
|
|
43938
44697
|
return owned;
|
|
43939
44698
|
if (!isTopicShared(owned.topic)) {
|
|
43940
|
-
|
|
43941
|
-
|
|
44699
|
+
const switched = switchTopicAccessMode({
|
|
44700
|
+
topicId: options.localTopicId,
|
|
44701
|
+
userId: options.userId,
|
|
44702
|
+
accessMode: "shared"
|
|
44703
|
+
});
|
|
44704
|
+
if (!switched.ok)
|
|
44705
|
+
return { ok: false, error: switched.error, status: 409 };
|
|
43942
44706
|
}
|
|
43943
44707
|
return bindOtiumTopic(options);
|
|
43944
44708
|
}
|
|
@@ -43948,8 +44712,13 @@ function setOtiumTopicPrivate(options) {
|
|
|
43948
44712
|
return owned;
|
|
43949
44713
|
const removedBindings = unbindSharedPeerSessionsForLocalTopic(options.localTopicId);
|
|
43950
44714
|
if (isTopicShared(owned.topic)) {
|
|
43951
|
-
|
|
43952
|
-
|
|
44715
|
+
const switched = switchTopicAccessMode({
|
|
44716
|
+
topicId: options.localTopicId,
|
|
44717
|
+
userId: options.userId,
|
|
44718
|
+
accessMode: "private"
|
|
44719
|
+
});
|
|
44720
|
+
if (!switched.ok)
|
|
44721
|
+
return { ok: false, error: switched.error, status: 409 };
|
|
43953
44722
|
}
|
|
43954
44723
|
return { ok: true, localTopicId: options.localTopicId, removedBindings };
|
|
43955
44724
|
}
|
|
@@ -43989,16 +44758,16 @@ import {
|
|
|
43989
44758
|
randomUUID as randomUUID31
|
|
43990
44759
|
} from "crypto";
|
|
43991
44760
|
import {
|
|
43992
|
-
chmodSync as
|
|
44761
|
+
chmodSync as chmodSync8,
|
|
43993
44762
|
closeSync as closeSync6,
|
|
43994
|
-
existsSync as
|
|
44763
|
+
existsSync as existsSync38,
|
|
43995
44764
|
fsyncSync as fsyncSync3,
|
|
43996
44765
|
linkSync as linkSync2,
|
|
43997
44766
|
mkdirSync as mkdirSync34,
|
|
43998
44767
|
openSync as openSync6,
|
|
43999
|
-
readFileSync as
|
|
44768
|
+
readFileSync as readFileSync29,
|
|
44000
44769
|
renameSync as renameSync17,
|
|
44001
|
-
unlinkSync as
|
|
44770
|
+
unlinkSync as unlinkSync24,
|
|
44002
44771
|
writeFileSync as writeFileSync24
|
|
44003
44772
|
} from "fs";
|
|
44004
44773
|
import { dirname as dirname22, resolve as resolve25 } from "path";
|
|
@@ -44026,10 +44795,10 @@ function pendingEnrollmentPath() {
|
|
|
44026
44795
|
}
|
|
44027
44796
|
function isEnrollmentPending(invite) {
|
|
44028
44797
|
const path = pendingEnrollmentPath();
|
|
44029
|
-
if (!
|
|
44798
|
+
if (!existsSync38(path))
|
|
44030
44799
|
return false;
|
|
44031
44800
|
try {
|
|
44032
|
-
const saved = JSON.parse(
|
|
44801
|
+
const saved = JSON.parse(readFileSync29(path, "utf8"));
|
|
44033
44802
|
return saved.central === invite.central && saved.token === invite.token;
|
|
44034
44803
|
} catch {
|
|
44035
44804
|
return false;
|
|
@@ -44037,8 +44806,8 @@ function isEnrollmentPending(invite) {
|
|
|
44037
44806
|
}
|
|
44038
44807
|
function loadOrCreatePending(invite, nodeName) {
|
|
44039
44808
|
const path = pendingEnrollmentPath();
|
|
44040
|
-
if (
|
|
44041
|
-
const saved = JSON.parse(
|
|
44809
|
+
if (existsSync38(path)) {
|
|
44810
|
+
const saved = JSON.parse(readFileSync29(path, "utf8"));
|
|
44042
44811
|
if (saved.central === invite.central && saved.token === invite.token)
|
|
44043
44812
|
return saved;
|
|
44044
44813
|
throw new Error(`another Otium enrollment is pending at ${path}`);
|
|
@@ -44062,8 +44831,8 @@ function loadOrCreatePending(invite, nodeName) {
|
|
|
44062
44831
|
closeSync6(fd);
|
|
44063
44832
|
fd = undefined;
|
|
44064
44833
|
linkSync2(temporaryPath, path);
|
|
44065
|
-
|
|
44066
|
-
|
|
44834
|
+
unlinkSync24(temporaryPath);
|
|
44835
|
+
chmodSync8(path, 384);
|
|
44067
44836
|
const directoryFd = openSync6(dirname22(path), "r");
|
|
44068
44837
|
try {
|
|
44069
44838
|
fsyncSync3(directoryFd);
|
|
@@ -44073,10 +44842,10 @@ function loadOrCreatePending(invite, nodeName) {
|
|
|
44073
44842
|
} catch (error2) {
|
|
44074
44843
|
if (fd !== undefined)
|
|
44075
44844
|
closeSync6(fd);
|
|
44076
|
-
if (
|
|
44077
|
-
|
|
44078
|
-
if (error2.code === "EEXIST" &&
|
|
44079
|
-
const saved = JSON.parse(
|
|
44845
|
+
if (existsSync38(temporaryPath))
|
|
44846
|
+
unlinkSync24(temporaryPath);
|
|
44847
|
+
if (error2.code === "EEXIST" && existsSync38(path)) {
|
|
44848
|
+
const saved = JSON.parse(readFileSync29(path, "utf8"));
|
|
44080
44849
|
if (saved.central === invite.central && saved.token === invite.token)
|
|
44081
44850
|
return saved;
|
|
44082
44851
|
}
|
|
@@ -44106,14 +44875,14 @@ function replacePendingEnrollment(pending2) {
|
|
|
44106
44875
|
} catch (error2) {
|
|
44107
44876
|
if (fd !== undefined)
|
|
44108
44877
|
closeSync6(fd);
|
|
44109
|
-
if (
|
|
44110
|
-
|
|
44878
|
+
if (existsSync38(temporaryPath))
|
|
44879
|
+
unlinkSync24(temporaryPath);
|
|
44111
44880
|
throw error2;
|
|
44112
44881
|
}
|
|
44113
44882
|
}
|
|
44114
44883
|
function recordClaimedCredential(pending2, join43) {
|
|
44115
44884
|
withJoinCredentialLock(() => {
|
|
44116
|
-
const current3 = JSON.parse(
|
|
44885
|
+
const current3 = JSON.parse(readFileSync29(pendingEnrollmentPath(), "utf8"));
|
|
44117
44886
|
if (current3.central !== pending2.central || current3.token !== pending2.token || current3.idempotencyKey !== pending2.idempotencyKey || current3.publicKey !== pending2.publicKey) {
|
|
44118
44887
|
throw new Error("pending Otium enrollment changed while its claim was in flight");
|
|
44119
44888
|
}
|
|
@@ -44192,7 +44961,7 @@ async function claimEnrollment(invite, nodeName) {
|
|
|
44192
44961
|
function commitEnrollment(join43, options = {}) {
|
|
44193
44962
|
return withJoinCredentialLock(() => {
|
|
44194
44963
|
const pendingPath = pendingEnrollmentPath();
|
|
44195
|
-
const pending2 =
|
|
44964
|
+
const pending2 = existsSync38(pendingPath) ? JSON.parse(readFileSync29(pendingPath, "utf8")) : null;
|
|
44196
44965
|
const digest = joinCredentialDigest(join43);
|
|
44197
44966
|
if (pending2 && (!pending2.claimed || pending2.claimed.digest !== digest || pending2.claimed.cellId !== join43.cellId)) {
|
|
44198
44967
|
throw new Error(`pending Otium enrollment at ${pendingPath} does not match these credentials`);
|
|
@@ -44203,7 +44972,7 @@ function commitEnrollment(join43, options = {}) {
|
|
|
44203
44972
|
}
|
|
44204
44973
|
if (!pending2)
|
|
44205
44974
|
return path;
|
|
44206
|
-
|
|
44975
|
+
unlinkSync24(pendingPath);
|
|
44207
44976
|
const directoryFd = openSync6(dirname22(pendingPath), "r");
|
|
44208
44977
|
try {
|
|
44209
44978
|
fsyncSync3(directoryFd);
|
|
@@ -46392,4 +47161,4 @@ switch (command) {
|
|
|
46392
47161
|
}
|
|
46393
47162
|
}
|
|
46394
47163
|
|
|
46395
|
-
//# debugId=
|
|
47164
|
+
//# debugId=69B455239128A0A264756E2164756E21
|