negotium 0.3.13 → 0.4.0
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/README.md +2 -6
- package/dist/agent-helpers.js +328 -185
- package/dist/agent-helpers.js.map +9 -8
- package/dist/{chunk-0ynjwr50.js → chunk-zq2tcq4k.js} +12 -29
- package/dist/{chunk-0ynjwr50.js.map → chunk-zq2tcq4k.js.map} +4 -4
- package/dist/hosted-agent.js +207 -64
- package/dist/hosted-agent.js.map +8 -7
- package/dist/main.js +753 -886
- package/dist/main.js.map +13 -13
- package/dist/mcp-factories.js +300 -468
- package/dist/mcp-factories.js.map +9 -10
- package/dist/registry.js +3 -3
- package/dist/registry.js.map +2 -2
- package/dist/rollout.js +1 -1
- package/dist/runtime/src/agents/codex-provider.ts +33 -8
- package/dist/runtime/src/agents/codex-vault-hook-bridge.ts +192 -0
- package/dist/runtime/src/agents/codex-vault-hook.mjs +48 -0
- package/dist/runtime/src/agents/execution-host.ts +1 -14
- package/dist/runtime/src/agents/public-helpers.ts +0 -9
- package/dist/runtime/src/agents/vault-tool-policy.ts +9 -51
- package/dist/runtime/src/mcp/factories/index.ts +1 -8
- package/dist/runtime/src/mcp/factories/vault.ts +6 -104
- package/dist/runtime/src/mcp/vault-server.ts +4 -20
- package/dist/runtime/src/prompts/sessions/_shared-tools.md +1 -1
- package/dist/runtime/src/version.ts +1 -1
- package/dist/types/packages/core/src/agents/codex-vault-hook-bridge.d.ts +27 -0
- package/dist/types/packages/core/src/agents/execution-host.d.ts +0 -2
- package/dist/types/packages/core/src/agents/public-helpers.d.ts +0 -1
- package/dist/types/packages/core/src/agents/vault-tool-policy.d.ts +1 -14
- package/dist/types/packages/core/src/mcp/factories/index.d.ts +1 -3
- package/dist/types/packages/core/src/mcp/factories/vault.d.ts +4 -13
- package/dist/types/packages/core/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/dist/runtime/src/mcp/factories/vault-host.ts +0 -8
- package/dist/runtime/src/mcp/vault-http.ts +0 -235
- package/dist/runtime/src/mcp/vault-run.ts +0 -154
- package/dist/types/packages/core/src/mcp/factories/vault-host.d.ts +0 -7
- package/dist/types/packages/core/src/mcp/vault-http.d.ts +0 -23
- package/dist/types/packages/core/src/mcp/vault-run.d.ts +0 -19
package/dist/mcp-factories.js
CHANGED
|
@@ -1017,10 +1017,10 @@ var init_claude_registry = __esm(() => {
|
|
|
1017
1017
|
});
|
|
1018
1018
|
|
|
1019
1019
|
// ../../packages/core/src/version.ts
|
|
1020
|
-
var NEGOTIUM_VERSION = "0.
|
|
1020
|
+
var NEGOTIUM_VERSION = "0.4.0";
|
|
1021
1021
|
|
|
1022
1022
|
// ../../packages/core/src/agents/codex-native-multi-agent.ts
|
|
1023
|
-
import { spawn
|
|
1023
|
+
import { spawn } from "child_process";
|
|
1024
1024
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
1025
1025
|
import {
|
|
1026
1026
|
chmodSync as chmodSync3,
|
|
@@ -1088,7 +1088,7 @@ function bundledCodexModelCachePath(authFilePath) {
|
|
|
1088
1088
|
return join5(dirname4(authFilePath), NEGOTIUM_MODEL_CACHE);
|
|
1089
1089
|
}
|
|
1090
1090
|
async function bootstrapCodexModelCache(codexHome, cachePath) {
|
|
1091
|
-
const child =
|
|
1091
|
+
const child = spawn(process.execPath, [codexCliScriptPath(), "app-server", "--stdio"], {
|
|
1092
1092
|
env: { ...process.env, CODEX_HOME: codexHome },
|
|
1093
1093
|
stdio: ["pipe", "pipe", "pipe"]
|
|
1094
1094
|
});
|
|
@@ -1287,30 +1287,21 @@ function shouldSubstituteVaultToolInput(toolName) {
|
|
|
1287
1287
|
const leaf = leafToolName(toolName);
|
|
1288
1288
|
return leaf.startsWith("browser_") || DIRECT_VAULT_EXECUTION_TOOLS.has(leaf);
|
|
1289
1289
|
}
|
|
1290
|
-
function
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
const lower = value2.toLowerCase();
|
|
1297
|
-
if (SENSITIVE_RUNTIME_NAMES.some((name) => lower.includes(name)))
|
|
1298
|
-
return true;
|
|
1299
|
-
return value2.startsWith("/") && host.isSensitivePath(value2);
|
|
1300
|
-
}
|
|
1301
|
-
if (Array.isArray(value2))
|
|
1302
|
-
return value2.some(referencesRuntimeSecretStorage);
|
|
1303
|
-
if (value2 && typeof value2 === "object") {
|
|
1304
|
-
return Object.values(value2).some(referencesRuntimeSecretStorage);
|
|
1305
|
-
}
|
|
1306
|
-
return false;
|
|
1290
|
+
function referencesRuntimeSecretStorage(value2) {
|
|
1291
|
+
if (typeof value2 === "string") {
|
|
1292
|
+
const lower = value2.toLowerCase();
|
|
1293
|
+
if (SENSITIVE_RUNTIME_NAMES.some((name) => lower.includes(name)))
|
|
1294
|
+
return true;
|
|
1295
|
+
return value2.startsWith("/") && isSensitivePath(value2);
|
|
1307
1296
|
}
|
|
1308
|
-
|
|
1309
|
-
return
|
|
1297
|
+
if (Array.isArray(value2))
|
|
1298
|
+
return value2.some(referencesRuntimeSecretStorage);
|
|
1299
|
+
if (value2 && typeof value2 === "object") {
|
|
1300
|
+
return Object.values(value2).some(referencesRuntimeSecretStorage);
|
|
1310
1301
|
}
|
|
1311
|
-
return
|
|
1302
|
+
return false;
|
|
1312
1303
|
}
|
|
1313
|
-
var SENSITIVE_RUNTIME_NAMES, DIRECT_VAULT_EXECUTION_TOOLS
|
|
1304
|
+
var SENSITIVE_RUNTIME_NAMES, DIRECT_VAULT_EXECUTION_TOOLS;
|
|
1314
1305
|
var init_vault_tool_policy = __esm(() => {
|
|
1315
1306
|
init_sensitive_path();
|
|
1316
1307
|
SENSITIVE_RUNTIME_NAMES = [
|
|
@@ -1320,13 +1311,6 @@ var init_vault_tool_policy = __esm(() => {
|
|
|
1320
1311
|
"sessions.db"
|
|
1321
1312
|
];
|
|
1322
1313
|
DIRECT_VAULT_EXECUTION_TOOLS = new Set(["Bash", "WebFetch"]);
|
|
1323
|
-
defaultVaultToolPolicy = createVaultToolPolicy({
|
|
1324
|
-
isSensitivePath,
|
|
1325
|
-
valueReferencesVaultKey: () => false
|
|
1326
|
-
});
|
|
1327
|
-
isVaultBrokerTool = defaultVaultToolPolicy.isVaultBrokerTool;
|
|
1328
|
-
referencesRuntimeSecretStorage = defaultVaultToolPolicy.referencesRuntimeSecretStorage;
|
|
1329
|
-
shouldRedirectVaultTool = defaultVaultToolPolicy.shouldRedirectVaultTool;
|
|
1330
1314
|
});
|
|
1331
1315
|
|
|
1332
1316
|
// ../../packages/core/src/mcp/canonical-bridge-config.ts
|
|
@@ -1489,7 +1473,7 @@ function deriveBgBashContextCapability(runtimeCapability, userId, topic) {
|
|
|
1489
1473
|
var init_context = () => {};
|
|
1490
1474
|
|
|
1491
1475
|
// ../../packages/core/src/platform/background-bash/manager.ts
|
|
1492
|
-
import { execFileSync as execFileSync2, spawn as
|
|
1476
|
+
import { execFileSync as execFileSync2, spawn as spawn2 } from "child_process";
|
|
1493
1477
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
1494
1478
|
function makeBgBashKey(_userId, _topic) {
|
|
1495
1479
|
return "runtime";
|
|
@@ -1516,7 +1500,7 @@ function createBackgroundBashManager(options = {}) {
|
|
|
1516
1500
|
const now = options.now ?? Date.now;
|
|
1517
1501
|
const wait = options.delay ?? delay;
|
|
1518
1502
|
const portPids = options.portPids ?? defaultPortPids;
|
|
1519
|
-
const spawnImpl = options.spawn ?? ((command, args, spawnOptions) =>
|
|
1503
|
+
const spawnImpl = options.spawn ?? ((command, args, spawnOptions) => spawn2(command, [...args], spawnOptions));
|
|
1520
1504
|
function contextKey(userId, topic) {
|
|
1521
1505
|
return `${userId}\x00${topic}`;
|
|
1522
1506
|
}
|
|
@@ -2688,7 +2672,6 @@ var init_execution_host = __esm(async () => {
|
|
|
2688
2672
|
redactVaultSecrets,
|
|
2689
2673
|
substituteVaultSecrets: (userId, value2) => vaultSubstituteDetailed(userId, value2).text,
|
|
2690
2674
|
referencesRuntimeSecretStorage,
|
|
2691
|
-
shouldRedirectVaultTool,
|
|
2692
2675
|
claudeCodeExecutablePath: () => CLAUDE_EXECUTABLE,
|
|
2693
2676
|
codexAuthFilePath
|
|
2694
2677
|
};
|
|
@@ -3231,7 +3214,7 @@ var init_codex = __esm(async () => {
|
|
|
3231
3214
|
});
|
|
3232
3215
|
|
|
3233
3216
|
// ../../packages/core/src/agents/codex-app-server.ts
|
|
3234
|
-
import { spawn as
|
|
3217
|
+
import { spawn as spawn3 } from "child_process";
|
|
3235
3218
|
function createCodexAppServerForker(host) {
|
|
3236
3219
|
return async (parentThreadId) => {
|
|
3237
3220
|
const child = host.spawnServer();
|
|
@@ -3335,7 +3318,7 @@ var init_codex_app_server = __esm(async () => {
|
|
|
3335
3318
|
await init_codex();
|
|
3336
3319
|
forkCodexThread = createCodexAppServerForker({
|
|
3337
3320
|
spawnServer() {
|
|
3338
|
-
return
|
|
3321
|
+
return spawn3(process.execPath, [codexCliScriptPath(), "app-server", "--stdio"], {
|
|
3339
3322
|
env: { ...process.env, CODEX_HOME: hostedCodexHomePath() },
|
|
3340
3323
|
stdio: ["pipe", "pipe", "pipe"]
|
|
3341
3324
|
});
|
|
@@ -6265,7 +6248,7 @@ var init_browser_profiles = __esm(async () => {
|
|
|
6265
6248
|
});
|
|
6266
6249
|
|
|
6267
6250
|
// ../../packages/core/src/platform/playwright/manager.ts
|
|
6268
|
-
import { execFileSync as execFileSync4, spawn as
|
|
6251
|
+
import { execFileSync as execFileSync4, spawn as spawn5 } from "child_process";
|
|
6269
6252
|
import { createHash as createHash3, randomBytes as randomBytes6, timingSafeEqual as timingSafeEqual3 } from "crypto";
|
|
6270
6253
|
import {
|
|
6271
6254
|
cpSync,
|
|
@@ -6625,7 +6608,7 @@ async function spawnPlaywright(instanceKey, ownerId, reservedPort, browserBin =
|
|
|
6625
6608
|
}
|
|
6626
6609
|
let proc;
|
|
6627
6610
|
try {
|
|
6628
|
-
proc =
|
|
6611
|
+
proc = spawn5(spawnSpec.command, spawnSpec.args, {
|
|
6629
6612
|
stdio: ["ignore", "ignore", "pipe"],
|
|
6630
6613
|
detached: false,
|
|
6631
6614
|
env: childEnv
|
|
@@ -7939,7 +7922,7 @@ __export(exports_claude_provider, {
|
|
|
7939
7922
|
claudeBuiltInTools: () => claudeBuiltInTools,
|
|
7940
7923
|
buildClaudeDisallowedTools: () => buildClaudeDisallowedTools
|
|
7941
7924
|
});
|
|
7942
|
-
import { spawn as
|
|
7925
|
+
import { spawn as spawn6 } from "child_process";
|
|
7943
7926
|
import { existsSync as existsSync16, readFileSync as readFileSync14 } from "fs";
|
|
7944
7927
|
import { query } from "@anthropic-ai/claude-agent-sdk";
|
|
7945
7928
|
function claudeBuiltInTools(opts) {
|
|
@@ -8031,7 +8014,7 @@ function signalProcessTree2(pid, signal) {
|
|
|
8031
8014
|
}
|
|
8032
8015
|
}
|
|
8033
8016
|
function spawnClaudeCodeProcessWithTreeKill(options) {
|
|
8034
|
-
const child =
|
|
8017
|
+
const child = spawn6(options.command, options.args, {
|
|
8035
8018
|
cwd: options.cwd,
|
|
8036
8019
|
detached: true,
|
|
8037
8020
|
env: options.env,
|
|
@@ -8640,9 +8623,163 @@ var init_codex_tree_kill = __esm(() => {
|
|
|
8640
8623
|
killOwnedCodexTreesForShutdown = manager.killOwnedTreesForShutdown;
|
|
8641
8624
|
});
|
|
8642
8625
|
|
|
8626
|
+
// ../../packages/core/src/agents/codex-vault-hook-bridge.ts
|
|
8627
|
+
import { randomBytes as randomBytes7 } from "crypto";
|
|
8628
|
+
import { existsSync as existsSync17 } from "fs";
|
|
8629
|
+
import { chmod, mkdtemp, rm, writeFile } from "fs/promises";
|
|
8630
|
+
import { createServer as createServer3 } from "net";
|
|
8631
|
+
import { tmpdir as tmpdir3 } from "os";
|
|
8632
|
+
import { dirname as dirname12, join as join17, resolve as resolve11 } from "path";
|
|
8633
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
8634
|
+
function evaluateCodexVaultPreToolUse(input, userId, operations) {
|
|
8635
|
+
if (operations.referencesSensitiveStorage(input.tool_input)) {
|
|
8636
|
+
return {
|
|
8637
|
+
hookSpecificOutput: {
|
|
8638
|
+
hookEventName: "PreToolUse",
|
|
8639
|
+
permissionDecision: "deny",
|
|
8640
|
+
permissionDecisionReason: SENSITIVE_STORAGE_DENIAL
|
|
8641
|
+
}
|
|
8642
|
+
};
|
|
8643
|
+
}
|
|
8644
|
+
if (!shouldSubstituteVaultToolInput(input.tool_name))
|
|
8645
|
+
return {};
|
|
8646
|
+
const updatedInput = deepMapStrings2(input.tool_input, (value2) => operations.substitute(userId, value2));
|
|
8647
|
+
if (JSON.stringify(updatedInput) === JSON.stringify(input.tool_input))
|
|
8648
|
+
return {};
|
|
8649
|
+
return {
|
|
8650
|
+
hookSpecificOutput: {
|
|
8651
|
+
hookEventName: "PreToolUse",
|
|
8652
|
+
permissionDecision: "allow",
|
|
8653
|
+
updatedInput
|
|
8654
|
+
}
|
|
8655
|
+
};
|
|
8656
|
+
}
|
|
8657
|
+
function shellQuote(value2) {
|
|
8658
|
+
return `'${value2.replaceAll("'", `'"'"'`)}'`;
|
|
8659
|
+
}
|
|
8660
|
+
function hookClientPath() {
|
|
8661
|
+
const moduleDir = dirname12(fileURLToPath2(import.meta.url));
|
|
8662
|
+
const adjacent = resolve11(moduleDir, "codex-vault-hook.mjs");
|
|
8663
|
+
if (existsSync17(adjacent))
|
|
8664
|
+
return adjacent;
|
|
8665
|
+
const packaged = resolve11(moduleDir, "runtime/src/agents/codex-vault-hook.mjs");
|
|
8666
|
+
if (existsSync17(packaged))
|
|
8667
|
+
return packaged;
|
|
8668
|
+
throw new Error("Codex Vault hook client is missing from this installation");
|
|
8669
|
+
}
|
|
8670
|
+
function privateCodexWrapper(codexScript) {
|
|
8671
|
+
return [
|
|
8672
|
+
"#!/bin/sh",
|
|
8673
|
+
'if [ "$1" = "exec" ]; then',
|
|
8674
|
+
" shift",
|
|
8675
|
+
` exec ${shellQuote(process.execPath)} ${shellQuote(codexScript)} exec --dangerously-bypass-hook-trust "$@"`,
|
|
8676
|
+
"fi",
|
|
8677
|
+
`exec ${shellQuote(process.execPath)} ${shellQuote(codexScript)} "$@"`,
|
|
8678
|
+
""
|
|
8679
|
+
].join(`
|
|
8680
|
+
`);
|
|
8681
|
+
}
|
|
8682
|
+
async function createCodexVaultHookBridge(userId) {
|
|
8683
|
+
const root = await mkdtemp(join17(tmpdir3(), "negotium-codex-vault-"));
|
|
8684
|
+
await chmod(root, 448);
|
|
8685
|
+
const socketPath = join17(root, "hook.sock");
|
|
8686
|
+
const wrapperPath = join17(root, "codex-with-hooks");
|
|
8687
|
+
const token = randomBytes7(32).toString("hex");
|
|
8688
|
+
const connections = new Set;
|
|
8689
|
+
const server = createServer3((socket) => {
|
|
8690
|
+
connections.add(socket);
|
|
8691
|
+
socket.once("close", () => connections.delete(socket));
|
|
8692
|
+
socket.setEncoding("utf8");
|
|
8693
|
+
let request = "";
|
|
8694
|
+
let handled = false;
|
|
8695
|
+
const handleRequest = () => {
|
|
8696
|
+
if (handled)
|
|
8697
|
+
return;
|
|
8698
|
+
handled = true;
|
|
8699
|
+
try {
|
|
8700
|
+
const parsed = JSON.parse(request.trimEnd());
|
|
8701
|
+
if (parsed.token !== token)
|
|
8702
|
+
throw new Error("invalid hook capability");
|
|
8703
|
+
if (!parsed.input || typeof parsed.input !== "object" || typeof parsed.input.tool_name !== "string") {
|
|
8704
|
+
throw new Error("invalid PreToolUse payload");
|
|
8705
|
+
}
|
|
8706
|
+
const output = evaluateCodexVaultPreToolUse(parsed.input, userId, {
|
|
8707
|
+
referencesSensitiveStorage: referencesHostedSecretStorage,
|
|
8708
|
+
substitute: substituteHostedSecrets
|
|
8709
|
+
});
|
|
8710
|
+
socket.end(JSON.stringify({ ok: true, output }));
|
|
8711
|
+
} catch (error) {
|
|
8712
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
8713
|
+
socket.end(JSON.stringify({ ok: false, error: message }));
|
|
8714
|
+
}
|
|
8715
|
+
};
|
|
8716
|
+
socket.on("data", (chunk) => {
|
|
8717
|
+
request += chunk;
|
|
8718
|
+
if (Buffer.byteLength(request) > MAX_HOOK_REQUEST_BYTES)
|
|
8719
|
+
socket.destroy();
|
|
8720
|
+
else if (request.endsWith(`
|
|
8721
|
+
`))
|
|
8722
|
+
handleRequest();
|
|
8723
|
+
});
|
|
8724
|
+
socket.on("end", handleRequest);
|
|
8725
|
+
});
|
|
8726
|
+
try {
|
|
8727
|
+
await new Promise((resolveListen, reject) => {
|
|
8728
|
+
server.once("error", reject);
|
|
8729
|
+
server.listen(socketPath, () => {
|
|
8730
|
+
server.off("error", reject);
|
|
8731
|
+
resolveListen();
|
|
8732
|
+
});
|
|
8733
|
+
});
|
|
8734
|
+
await chmod(socketPath, 384);
|
|
8735
|
+
await writeFile(wrapperPath, privateCodexWrapper(codexCliScriptPath()), { mode: 448 });
|
|
8736
|
+
const command = [
|
|
8737
|
+
shellQuote(process.execPath),
|
|
8738
|
+
shellQuote(hookClientPath()),
|
|
8739
|
+
shellQuote(socketPath),
|
|
8740
|
+
shellQuote(token)
|
|
8741
|
+
].join(" ");
|
|
8742
|
+
return {
|
|
8743
|
+
codexPathOverride: wrapperPath,
|
|
8744
|
+
hooks: {
|
|
8745
|
+
PreToolUse: [
|
|
8746
|
+
{
|
|
8747
|
+
matcher: "*",
|
|
8748
|
+
hooks: [
|
|
8749
|
+
{
|
|
8750
|
+
type: "command",
|
|
8751
|
+
command,
|
|
8752
|
+
timeout: 30,
|
|
8753
|
+
statusMessage: "Resolving Vault placeholders"
|
|
8754
|
+
}
|
|
8755
|
+
]
|
|
8756
|
+
}
|
|
8757
|
+
]
|
|
8758
|
+
},
|
|
8759
|
+
async close() {
|
|
8760
|
+
for (const socket of connections)
|
|
8761
|
+
socket.destroy();
|
|
8762
|
+
await new Promise((resolveClose) => server.close(() => resolveClose()));
|
|
8763
|
+
await rm(root, { recursive: true, force: true });
|
|
8764
|
+
}
|
|
8765
|
+
};
|
|
8766
|
+
} catch (error) {
|
|
8767
|
+
server.close();
|
|
8768
|
+
await rm(root, { recursive: true, force: true });
|
|
8769
|
+
throw error;
|
|
8770
|
+
}
|
|
8771
|
+
}
|
|
8772
|
+
var MAX_HOOK_REQUEST_BYTES, SENSITIVE_STORAGE_DENIAL = "Runtime secret storage access is not permitted";
|
|
8773
|
+
var init_codex_vault_hook_bridge = __esm(async () => {
|
|
8774
|
+
init_codex_native_multi_agent();
|
|
8775
|
+
await init_execution_host();
|
|
8776
|
+
init_vault_tool_policy();
|
|
8777
|
+
MAX_HOOK_REQUEST_BYTES = 1024 * 1024;
|
|
8778
|
+
});
|
|
8779
|
+
|
|
8643
8780
|
// ../../packages/core/src/agents/tool-format.ts
|
|
8644
8781
|
import { readFileSync as readFileSync15, statSync as statSync5 } from "fs";
|
|
8645
|
-
import { isAbsolute as isAbsolute2, resolve as
|
|
8782
|
+
import { isAbsolute as isAbsolute2, resolve as resolve12 } from "path";
|
|
8646
8783
|
import { diffLines as computeLineDiff } from "diff";
|
|
8647
8784
|
function summarizeDisplayText(value2) {
|
|
8648
8785
|
const normalized = value2.replace(/\s+/g, " ").trim();
|
|
@@ -8966,7 +9103,7 @@ function sourceStartLine(input, before, after, cwd) {
|
|
|
8966
9103
|
const rawPath = input.file_path ?? input.path;
|
|
8967
9104
|
if (typeof rawPath !== "string" || !rawPath.trim())
|
|
8968
9105
|
return 1;
|
|
8969
|
-
const path = isAbsolute2(rawPath) ? rawPath :
|
|
9106
|
+
const path = isAbsolute2(rawPath) ? rawPath : resolve12(cwd ?? process.cwd(), rawPath);
|
|
8970
9107
|
try {
|
|
8971
9108
|
if (statSync5(path).size > TOOL_DIFF_SOURCE_MAX_BYTES)
|
|
8972
9109
|
return 1;
|
|
@@ -9164,9 +9301,9 @@ __export(exports_codex_provider, {
|
|
|
9164
9301
|
codexProvider: () => codexProvider
|
|
9165
9302
|
});
|
|
9166
9303
|
import { execFileSync as execFileSync6 } from "child_process";
|
|
9167
|
-
import { existsSync as
|
|
9304
|
+
import { existsSync as existsSync18, readFileSync as readFileSync16, realpathSync as realpathSync4, statSync as statSync6 } from "fs";
|
|
9168
9305
|
import { homedir as homedir6 } from "os";
|
|
9169
|
-
import { dirname as
|
|
9306
|
+
import { dirname as dirname13, isAbsolute as isAbsolute3, join as join18, relative as relative2, resolve as resolve13 } from "path";
|
|
9170
9307
|
import { Codex } from "@openai/codex-sdk";
|
|
9171
9308
|
function sameCodexUsage(usage, total) {
|
|
9172
9309
|
return usage.input_tokens === total.inputTokens && usage.output_tokens === total.outputTokens && (usage.cached_input_tokens ?? 0) === total.cachedInputTokens && (usage.cache_write_input_tokens ?? 0) === total.cacheWriteInputTokens;
|
|
@@ -9194,8 +9331,8 @@ function codexMcpServerName(name) {
|
|
|
9194
9331
|
return CODEX_MCP_SERVER_NAME_OVERRIDES[name] ?? name;
|
|
9195
9332
|
}
|
|
9196
9333
|
function globalCodexMcpServerNames(authFilePath) {
|
|
9197
|
-
const configPath =
|
|
9198
|
-
if (!
|
|
9334
|
+
const configPath = join18(dirname13(authFilePath), "config.toml");
|
|
9335
|
+
if (!existsSync18(configPath))
|
|
9199
9336
|
return [];
|
|
9200
9337
|
try {
|
|
9201
9338
|
const names = new Set;
|
|
@@ -9290,13 +9427,13 @@ function summarizeMcpToolCallResult(item) {
|
|
|
9290
9427
|
}
|
|
9291
9428
|
function canonicalPath(path) {
|
|
9292
9429
|
try {
|
|
9293
|
-
return realpathSync4(
|
|
9430
|
+
return realpathSync4(resolve13(path));
|
|
9294
9431
|
} catch {
|
|
9295
|
-
return
|
|
9432
|
+
return resolve13(path);
|
|
9296
9433
|
}
|
|
9297
9434
|
}
|
|
9298
9435
|
function textFile(path, maxBytes = CODEX_DIFF_FILE_LIMIT) {
|
|
9299
|
-
if (!
|
|
9436
|
+
if (!existsSync18(path))
|
|
9300
9437
|
return null;
|
|
9301
9438
|
try {
|
|
9302
9439
|
const byteLimit = Math.min(CODEX_DIFF_FILE_LIMIT, Math.max(0, maxBytes));
|
|
@@ -9336,7 +9473,7 @@ class CodexFilePreviewTracker {
|
|
|
9336
9473
|
const code = record.slice(0, 2);
|
|
9337
9474
|
const path = record.slice(3);
|
|
9338
9475
|
const remainingBytes = CODEX_DIFF_BASELINE_BYTE_LIMIT - loadedBytes;
|
|
9339
|
-
const content = loadedFiles < CODEX_DIFF_BASELINE_FILE_LIMIT && remainingBytes > 0 ? textFile(
|
|
9476
|
+
const content = loadedFiles < CODEX_DIFF_BASELINE_FILE_LIMIT && remainingBytes > 0 ? textFile(resolve13(this.#root, path), remainingBytes) : undefined;
|
|
9340
9477
|
this.#baseline.set(path, content);
|
|
9341
9478
|
if (typeof content === "string") {
|
|
9342
9479
|
loadedFiles += 1;
|
|
@@ -9349,7 +9486,7 @@ class CodexFilePreviewTracker {
|
|
|
9349
9486
|
preview(path, succeeded) {
|
|
9350
9487
|
if (!this.#root || !this.#baselineAvailable || !succeeded)
|
|
9351
9488
|
return {};
|
|
9352
|
-
const absolute = canonicalPath(isAbsolute3(path) ? path :
|
|
9489
|
+
const absolute = canonicalPath(isAbsolute3(path) ? path : resolve13(this.#cwd, path));
|
|
9353
9490
|
const relativePath = relative2(this.#root, absolute);
|
|
9354
9491
|
if (!relativePath || relativePath.startsWith("..") || isAbsolute3(relativePath))
|
|
9355
9492
|
return {};
|
|
@@ -9384,7 +9521,7 @@ class CodexFilePreviewTracker {
|
|
|
9384
9521
|
}
|
|
9385
9522
|
}
|
|
9386
9523
|
async function fileChangeEvents(item, previews, cwd, threadId, consumedPatchCallIds) {
|
|
9387
|
-
const expectedPaths = item.changes.map((change) => isAbsolute3(change.path) ? change.path :
|
|
9524
|
+
const expectedPaths = item.changes.map((change) => isAbsolute3(change.path) ? change.path : resolve13(cwd, change.path));
|
|
9388
9525
|
let nativePreview;
|
|
9389
9526
|
if (threadId && item.status === "completed") {
|
|
9390
9527
|
await new Promise((resolveDelay) => setTimeout(resolveDelay, 20));
|
|
@@ -9508,7 +9645,7 @@ async function* codexProvider(opts) {
|
|
|
9508
9645
|
const filePreviews = new CodexFilePreviewTracker(opts.cwd);
|
|
9509
9646
|
const consumedPatchCallIds = new Set(opts.sessionId ? readCodexPatchCallIds(opts.sessionId) : []);
|
|
9510
9647
|
const codexAuthPath = hostedCodexAuthFilePath();
|
|
9511
|
-
if (!
|
|
9648
|
+
if (!existsSync18(codexAuthPath)) {
|
|
9512
9649
|
yield {
|
|
9513
9650
|
type: "error",
|
|
9514
9651
|
content: `Codex auth file not found at ${codexAuthPath}. Run \`codex login\` to authenticate.`
|
|
@@ -9547,21 +9684,30 @@ async function* codexProvider(opts) {
|
|
|
9547
9684
|
model: opts.model ?? "(sdk default)",
|
|
9548
9685
|
effort: opts.effort ?? "(off)",
|
|
9549
9686
|
cwd: opts.cwd,
|
|
9550
|
-
cwdExists:
|
|
9687
|
+
cwdExists: existsSync18(opts.cwd),
|
|
9551
9688
|
resume: Boolean(opts.sessionId),
|
|
9552
9689
|
mcpServerCount: Object.keys(codexMcpServers).length
|
|
9553
9690
|
}, "codexProvider: starting turn");
|
|
9554
9691
|
const hostedCodexHome = hostedCodexHomePath();
|
|
9555
|
-
const inheritedCodexHome = process.env.CODEX_HOME ||
|
|
9556
|
-
const codexEnvironment = scopedBrowserCapability ||
|
|
9692
|
+
const inheritedCodexHome = process.env.CODEX_HOME || join18(homedir6(), ".codex");
|
|
9693
|
+
const codexEnvironment = scopedBrowserCapability || resolve13(hostedCodexHome) !== resolve13(inheritedCodexHome) ? {
|
|
9557
9694
|
...Object.fromEntries(Object.entries(process.env).filter((entry) => typeof entry[1] === "string")),
|
|
9558
9695
|
CODEX_HOME: hostedCodexHome,
|
|
9559
9696
|
...scopedBrowserCapability ? { [CODEX_BROWSER_CAPABILITY_ENV]: scopedBrowserCapability } : {}
|
|
9560
9697
|
} : undefined;
|
|
9698
|
+
let vaultHook;
|
|
9699
|
+
try {
|
|
9700
|
+
vaultHook = await createCodexVaultHookBridge(opts.vaultUserId ?? opts.userId ?? "");
|
|
9701
|
+
} catch (err) {
|
|
9702
|
+
yield { type: "error", content: `Failed to initialize Codex Vault hooks: ${errMsg(err)}` };
|
|
9703
|
+
return;
|
|
9704
|
+
}
|
|
9561
9705
|
const codex = new Codex({
|
|
9706
|
+
codexPathOverride: vaultHook.codexPathOverride,
|
|
9562
9707
|
...codexEnvironment ? { env: codexEnvironment } : {},
|
|
9563
9708
|
config: {
|
|
9564
|
-
features: { multi_agent: false, multi_agent_v2: false, enable_fanout: false },
|
|
9709
|
+
features: { hooks: true, multi_agent: false, multi_agent_v2: false, enable_fanout: false },
|
|
9710
|
+
hooks: vaultHook.hooks,
|
|
9565
9711
|
model_catalog_json: codexModelCatalogPath,
|
|
9566
9712
|
mcp_servers: codexMcpServers,
|
|
9567
9713
|
...opts.toolPolicy ? { sandbox_permissions: [] } : {}
|
|
@@ -9665,7 +9811,7 @@ async function* codexProvider(opts) {
|
|
|
9665
9811
|
if (!item)
|
|
9666
9812
|
break;
|
|
9667
9813
|
if (item.type === "command_execution") {
|
|
9668
|
-
const command = String(item.command ?? "");
|
|
9814
|
+
const command = redactHostedSecrets(opts.vaultUserId ?? opts.userId ?? "", String(item.command ?? ""));
|
|
9669
9815
|
yield {
|
|
9670
9816
|
type: "tool_use",
|
|
9671
9817
|
name: "Bash",
|
|
@@ -9673,10 +9819,11 @@ async function* codexProvider(opts) {
|
|
|
9673
9819
|
toolUseId: String(item.id ?? "")
|
|
9674
9820
|
};
|
|
9675
9821
|
} else if (item.type === "mcp_tool_call") {
|
|
9822
|
+
const input = item.arguments && typeof item.arguments === "object" ? item.arguments : {};
|
|
9676
9823
|
yield {
|
|
9677
9824
|
type: "tool_use",
|
|
9678
9825
|
name: String(item.tool ?? "unknown"),
|
|
9679
|
-
input:
|
|
9826
|
+
input: deepMapStrings2(input, (value2) => redactHostedSecrets(opts.vaultUserId ?? opts.userId ?? "", value2)),
|
|
9680
9827
|
toolUseId: String(item.id ?? "")
|
|
9681
9828
|
};
|
|
9682
9829
|
}
|
|
@@ -9719,7 +9866,7 @@ async function* codexProvider(opts) {
|
|
|
9719
9866
|
yield {
|
|
9720
9867
|
type: "tool_result",
|
|
9721
9868
|
toolUseId: String(item.id ?? ""),
|
|
9722
|
-
content: summarizeMcpToolCallResult(item),
|
|
9869
|
+
content: redactHostedSecrets(opts.vaultUserId ?? opts.userId ?? "", summarizeMcpToolCallResult(item)),
|
|
9723
9870
|
...isError ? { isError: true } : {}
|
|
9724
9871
|
};
|
|
9725
9872
|
} else if (item.type === "command_execution") {
|
|
@@ -9727,7 +9874,7 @@ async function* codexProvider(opts) {
|
|
|
9727
9874
|
yield {
|
|
9728
9875
|
type: "tool_result",
|
|
9729
9876
|
toolUseId: String(item.id ?? ""),
|
|
9730
|
-
content: String(item.aggregated_output ?? "").slice(0, 200),
|
|
9877
|
+
content: redactHostedSecrets(opts.vaultUserId ?? opts.userId ?? "", String(item.aggregated_output ?? "").slice(0, 200)),
|
|
9731
9878
|
...isError ? { isError: true } : {}
|
|
9732
9879
|
};
|
|
9733
9880
|
} else if (item.type === "file_change") {
|
|
@@ -9824,12 +9971,14 @@ async function* codexProvider(opts) {
|
|
|
9824
9971
|
abortSignal?.removeEventListener("abort", onAbortKill);
|
|
9825
9972
|
if (trackedPids.pids.length > 0)
|
|
9826
9973
|
unregisterOwnedCodexPids(trackedPids.pids);
|
|
9974
|
+
await vaultHook.close();
|
|
9827
9975
|
}
|
|
9828
9976
|
}
|
|
9829
9977
|
var CODEX_MCP_SERVER_NAME_OVERRIDES, CODEX_DIFF_FILE_LIMIT, CODEX_DIFF_BASELINE_FILE_LIMIT = 200, CODEX_DIFF_BASELINE_BYTE_LIMIT, CODEX_STARTUP_TIMEOUT_MS = 90000;
|
|
9830
9978
|
var init_codex_provider = __esm(async () => {
|
|
9831
9979
|
init_codex_native_multi_agent();
|
|
9832
9980
|
init_codex_tree_kill();
|
|
9981
|
+
await init_codex_vault_hook_bridge();
|
|
9833
9982
|
await init_execution_host();
|
|
9834
9983
|
await init_codex();
|
|
9835
9984
|
init_tool_format();
|
|
@@ -9857,7 +10006,7 @@ __export(exports_maestro_provider, {
|
|
|
9857
10006
|
buildMaestroToolHooks: () => buildMaestroToolHooks,
|
|
9858
10007
|
buildMaestroDisallowedTools: () => buildMaestroDisallowedTools
|
|
9859
10008
|
});
|
|
9860
|
-
import { resolve as
|
|
10009
|
+
import { resolve as resolve14 } from "path";
|
|
9861
10010
|
import { maestroProvider as sdkMaestroProvider, setMcpResolver } from "maestro-agent-sdk";
|
|
9862
10011
|
function buildMaestroDisallowedTools(callerDisallowedTools = [], toolPolicy) {
|
|
9863
10012
|
return [
|
|
@@ -9991,13 +10140,13 @@ var init_maestro_provider = __esm(async () => {
|
|
|
9991
10140
|
"ToolSearch",
|
|
9992
10141
|
...DEFAULT_MAESTRO_DISALLOWED_TOOLS
|
|
9993
10142
|
];
|
|
9994
|
-
MAESTRO_TOOL_OUTPUT_DIR =
|
|
10143
|
+
MAESTRO_TOOL_OUTPUT_DIR = resolve14(RUN_DIR, "maestro-tool-outputs");
|
|
9995
10144
|
});
|
|
9996
10145
|
|
|
9997
10146
|
// ../../packages/core/src/agents/index.ts
|
|
9998
|
-
import { existsSync as
|
|
10147
|
+
import { existsSync as existsSync19 } from "fs";
|
|
9999
10148
|
import { homedir as homedir7 } from "os";
|
|
10000
|
-
import { join as
|
|
10149
|
+
import { join as join19 } from "path";
|
|
10001
10150
|
async function* dispatchAgent(opts) {
|
|
10002
10151
|
switch (opts.agent) {
|
|
10003
10152
|
case "claude": {
|
|
@@ -10031,11 +10180,11 @@ async function resolveSessionFileMissing(agent, sessionId, cwd) {
|
|
|
10031
10180
|
switch (agent) {
|
|
10032
10181
|
case "claude": {
|
|
10033
10182
|
const encodedCwd = encodeClaudeCwd(cwd);
|
|
10034
|
-
const path =
|
|
10035
|
-
return !
|
|
10183
|
+
const path = join19(homedir7(), ".claude", "projects", encodedCwd, `${sessionId}.jsonl`);
|
|
10184
|
+
return !existsSync19(path);
|
|
10036
10185
|
}
|
|
10037
10186
|
case "codex": {
|
|
10038
|
-
const sessionsDir =
|
|
10187
|
+
const sessionsDir = join19(hostedCodexHomePath(), "sessions");
|
|
10039
10188
|
const glob = new Bun.Glob(`**/rollout-*-${sessionId}.jsonl`);
|
|
10040
10189
|
for await (const _rel of glob.scan({ cwd: sessionsDir, onlyFiles: true })) {
|
|
10041
10190
|
return false;
|
|
@@ -10044,7 +10193,7 @@ async function resolveSessionFileMissing(agent, sessionId, cwd) {
|
|
|
10044
10193
|
}
|
|
10045
10194
|
case "maestro": {
|
|
10046
10195
|
const { hasActiveMaestroSession, maestroSessionPath: maestroSessionPath2 } = await import("maestro-agent-sdk");
|
|
10047
|
-
return !
|
|
10196
|
+
return !existsSync19(maestroSessionPath2(sessionId)) && !hasActiveMaestroSession(sessionId);
|
|
10048
10197
|
}
|
|
10049
10198
|
default: {
|
|
10050
10199
|
const _exhaustive = agent;
|
|
@@ -10116,9 +10265,9 @@ var init_agents = __esm(async () => {
|
|
|
10116
10265
|
|
|
10117
10266
|
// ../../packages/core/src/prompts/builders.ts
|
|
10118
10267
|
import { readFileSync as readFileSync17 } from "fs";
|
|
10119
|
-
import { resolve as
|
|
10268
|
+
import { resolve as resolve15 } from "path";
|
|
10120
10269
|
function loadPrompt(filename, dir = SESSIONS_DIR) {
|
|
10121
|
-
const raw = readFileSync17(
|
|
10270
|
+
const raw = readFileSync17(resolve15(dir, filename), "utf-8");
|
|
10122
10271
|
return raw.replace(/\{\{RESOURCES_DIR\}\}/g, RESOURCES_DIR);
|
|
10123
10272
|
}
|
|
10124
10273
|
function replaceVars(template, vars) {
|
|
@@ -10167,7 +10316,7 @@ function visualDesignGuide() {
|
|
|
10167
10316
|
return _visualDesignGuide;
|
|
10168
10317
|
}
|
|
10169
10318
|
function loadAgentPrompt(filename) {
|
|
10170
|
-
const raw = readFileSync17(
|
|
10319
|
+
const raw = readFileSync17(resolve15(AGENTS_PROMPTS_DIR, filename), "utf-8");
|
|
10171
10320
|
const match = raw.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
10172
10321
|
if (!match)
|
|
10173
10322
|
throw new Error(`Agent prompt ${filename} is missing frontmatter`);
|
|
@@ -10482,8 +10631,8 @@ var init_builders = __esm(() => {
|
|
|
10482
10631
|
init_model_catalog();
|
|
10483
10632
|
init_config();
|
|
10484
10633
|
init_logger();
|
|
10485
|
-
PROMPTS_DIR =
|
|
10486
|
-
SESSIONS_DIR =
|
|
10634
|
+
PROMPTS_DIR = resolve15(PROJECT_ROOT, "src/prompts");
|
|
10635
|
+
SESSIONS_DIR = resolve15(PROMPTS_DIR, "sessions");
|
|
10487
10636
|
defaultPromptBuilders = createPromptBuilders();
|
|
10488
10637
|
buildTopicSystemPrompt = defaultPromptBuilders.buildTopicSystemPrompt;
|
|
10489
10638
|
buildChannelSystemPrompt = defaultPromptBuilders.buildChannelSystemPrompt;
|
|
@@ -10559,9 +10708,9 @@ var init_api_topic_brief = __esm(async () => {
|
|
|
10559
10708
|
});
|
|
10560
10709
|
|
|
10561
10710
|
// ../../packages/core/src/storage/wiki.ts
|
|
10562
|
-
import { basename as basename3, dirname as
|
|
10711
|
+
import { basename as basename3, dirname as dirname14, join as join20 } from "path";
|
|
10563
10712
|
function getSharedWikiDir(workspaceDir = resolveStorageWorkspaceDir()) {
|
|
10564
|
-
return workspaceDir === resolveStorageWorkspaceDir() ? resolveStorageSharedWikiDir() :
|
|
10713
|
+
return workspaceDir === resolveStorageWorkspaceDir() ? resolveStorageSharedWikiDir() : join20(workspaceDir, "wiki");
|
|
10565
10714
|
}
|
|
10566
10715
|
var init_wiki = __esm(async () => {
|
|
10567
10716
|
await init_storage_host();
|
|
@@ -10569,8 +10718,8 @@ var init_wiki = __esm(async () => {
|
|
|
10569
10718
|
|
|
10570
10719
|
// ../../packages/core/src/agents/archiver.ts
|
|
10571
10720
|
import { randomUUID as randomUUID9 } from "crypto";
|
|
10572
|
-
import { existsSync as
|
|
10573
|
-
import { join as
|
|
10721
|
+
import { existsSync as existsSync20, readdirSync as readdirSync5, readFileSync as readFileSync18, statSync as statSync7 } from "fs";
|
|
10722
|
+
import { join as join21 } from "path";
|
|
10574
10723
|
function resolveMemoryLanguage() {
|
|
10575
10724
|
const override = process.env.NEGOTIUM_MEMORY_LANG?.trim();
|
|
10576
10725
|
return override && override.length > 0 ? override : resolveOutputLanguage();
|
|
@@ -10821,10 +10970,10 @@ function distillOneLine(summaryMd) {
|
|
|
10821
10970
|
return "";
|
|
10822
10971
|
}
|
|
10823
10972
|
function findSummaryFile(storage, topicTitle, date, sinceMs, topicId) {
|
|
10824
|
-
const dir =
|
|
10973
|
+
const dir = join21(storage.getWikiDir(), "summaries");
|
|
10825
10974
|
if (!storage.fileExists(dir))
|
|
10826
10975
|
return null;
|
|
10827
|
-
const predicted =
|
|
10976
|
+
const predicted = join21(dir, wikiSummaryFilename(date, topicTitle, topicId));
|
|
10828
10977
|
if (storage.fileExists(predicted) && storage.fileModifiedAt(predicted) >= sinceMs)
|
|
10829
10978
|
return predicted;
|
|
10830
10979
|
let best = null;
|
|
@@ -10832,7 +10981,7 @@ function findSummaryFile(storage, topicTitle, date, sinceMs, topicId) {
|
|
|
10832
10981
|
if (!f.startsWith(`${date}-`) || !isTopicSummaryFile(f, topicId ?? "", topicTitle)) {
|
|
10833
10982
|
continue;
|
|
10834
10983
|
}
|
|
10835
|
-
const p =
|
|
10984
|
+
const p = join21(dir, f);
|
|
10836
10985
|
try {
|
|
10837
10986
|
const m = storage.fileModifiedAt(p);
|
|
10838
10987
|
if (m >= sinceMs && (!best || m > best.mtime))
|
|
@@ -10913,7 +11062,7 @@ var init_archiver = __esm(async () => {
|
|
|
10913
11062
|
defaultArchiverRuntime = createArchiverRuntime({
|
|
10914
11063
|
storage: {
|
|
10915
11064
|
getWikiDir: getSharedWikiDir,
|
|
10916
|
-
fileExists:
|
|
11065
|
+
fileExists: existsSync20,
|
|
10917
11066
|
listDirectory: readdirSync5,
|
|
10918
11067
|
readTextFile: (path) => readFileSync18(path, "utf-8"),
|
|
10919
11068
|
fileSize: (path) => statSync7(path).size,
|
|
@@ -11036,13 +11185,13 @@ function formatTopicArchiveTranscriptRecord(row, topicTitle, index) {
|
|
|
11036
11185
|
|
|
11037
11186
|
// ../../packages/core/src/storage/topic-archive.ts
|
|
11038
11187
|
import { mkdirSync as mkdirSync13, writeFileSync as writeFileSync11 } from "fs";
|
|
11039
|
-
import { join as
|
|
11188
|
+
import { join as join22 } from "path";
|
|
11040
11189
|
function archiveTopicMessages(topicId, topicTitle, options = {}) {
|
|
11041
11190
|
const rows = options.afterRowid !== undefined ? getMessagesForTopicAfterRowid(topicId, options.afterRowid) : getAllMessagesForTopic(topicId);
|
|
11042
11191
|
if (rows.length === 0)
|
|
11043
11192
|
return null;
|
|
11044
11193
|
const safeTopic = sanitizeTopicName(topicTitle, true);
|
|
11045
|
-
const archiveDir =
|
|
11194
|
+
const archiveDir = join22(getSharedWikiDir(), "archive");
|
|
11046
11195
|
mkdirSync13(archiveDir, { recursive: true });
|
|
11047
11196
|
const date = new Date().toISOString().slice(0, 10);
|
|
11048
11197
|
const reasonSuffix = options.reason && options.reason !== "delete" ? `_${options.reason}` : "";
|
|
@@ -11055,7 +11204,7 @@ function archiveTopicMessages(topicId, topicTitle, options = {}) {
|
|
|
11055
11204
|
let path;
|
|
11056
11205
|
while (true) {
|
|
11057
11206
|
filename = `${safeTopic}_${date}${reasonSuffix}${counter === 1 ? "" : `_${counter}`}.jsonl`;
|
|
11058
|
-
path =
|
|
11207
|
+
path = join22(archiveDir, filename);
|
|
11059
11208
|
try {
|
|
11060
11209
|
writeFileSync11(path, body, { flag: "wx" });
|
|
11061
11210
|
break;
|
|
@@ -11100,7 +11249,7 @@ function archiveConversationEvents(topicId, topicTitle, userId, options = {}) {
|
|
|
11100
11249
|
const entries = readRawConversation(userId, topicTitle);
|
|
11101
11250
|
if (entries.length === 0)
|
|
11102
11251
|
return null;
|
|
11103
|
-
const archiveDir =
|
|
11252
|
+
const archiveDir = join22(getSharedWikiDir(), "archive");
|
|
11104
11253
|
mkdirSync13(archiveDir, { recursive: true });
|
|
11105
11254
|
const safeTopic = sanitizeTopicName(topicTitle, true);
|
|
11106
11255
|
const date = new Date().toISOString().slice(0, 10);
|
|
@@ -11128,7 +11277,7 @@ function archiveConversationEvents(topicId, topicTitle, userId, options = {}) {
|
|
|
11128
11277
|
let counter = 1;
|
|
11129
11278
|
while (true) {
|
|
11130
11279
|
const suffix = counter === 1 ? "" : `_${counter}`;
|
|
11131
|
-
const path =
|
|
11280
|
+
const path = join22(archiveDir, `${safeTopic}_${date}${reasonSuffix}_events${suffix}.jsonl`);
|
|
11132
11281
|
try {
|
|
11133
11282
|
writeFileSync11(path, body, { flag: "wx" });
|
|
11134
11283
|
logger.info({ topicId, topicTitle, archive: path, eventCount: entries.length }, "archiveConversationEvents: archived raw conversation events");
|
|
@@ -11447,7 +11596,7 @@ var init_idle_archiver = __esm(async () => {
|
|
|
11447
11596
|
|
|
11448
11597
|
// ../../packages/core/src/agents/topic-cleanup.ts
|
|
11449
11598
|
import { mkdirSync as mkdirSync14, renameSync as renameSync8, unlinkSync as unlinkSync13, writeFileSync as writeFileSync12 } from "fs";
|
|
11450
|
-
import { dirname as
|
|
11599
|
+
import { dirname as dirname15 } from "path";
|
|
11451
11600
|
function collectSessionIdsByAgent(entries, extraSessions = []) {
|
|
11452
11601
|
const out = new Map;
|
|
11453
11602
|
for (const e of entries) {
|
|
@@ -11513,7 +11662,7 @@ function createTopicLogMaintenance(host) {
|
|
|
11513
11662
|
const path = runtimeHost.activeConversationPath(opts.userId, opts.topicName);
|
|
11514
11663
|
const tempPath = `${path}.${process.pid}.${Date.now()}.tmp`;
|
|
11515
11664
|
try {
|
|
11516
|
-
mkdirSync14(
|
|
11665
|
+
mkdirSync14(dirname15(path), { recursive: true });
|
|
11517
11666
|
writeFileSync12(tempPath, retained.length > 0 ? `${retained.map((entry) => JSON.stringify(entry)).join(`
|
|
11518
11667
|
`)}
|
|
11519
11668
|
` : "", { flag: "wx" });
|
|
@@ -11676,8 +11825,8 @@ var init_usage_alert = __esm(() => {
|
|
|
11676
11825
|
// ../../packages/core/src/topics/session.ts
|
|
11677
11826
|
import { randomUUID as randomUUID10 } from "crypto";
|
|
11678
11827
|
import { mkdtempSync as mkdtempSync2, rmSync as rmSync4, writeFileSync as writeFileSync13 } from "fs";
|
|
11679
|
-
import { tmpdir as
|
|
11680
|
-
import { join as
|
|
11828
|
+
import { tmpdir as tmpdir4 } from "os";
|
|
11829
|
+
import { join as join23 } from "path";
|
|
11681
11830
|
function previousCompactedSummary(entries) {
|
|
11682
11831
|
for (let index = entries.length - 2;index >= 0; index -= 1) {
|
|
11683
11832
|
const request = entries[index]?.event;
|
|
@@ -11807,7 +11956,7 @@ function formatCompactElapsed(startedAt) {
|
|
|
11807
11956
|
async function summarizeTopicContext(request) {
|
|
11808
11957
|
const startedAt = Date.now();
|
|
11809
11958
|
const sessionIds = [];
|
|
11810
|
-
const compactCwd = mkdtempSync2(
|
|
11959
|
+
const compactCwd = mkdtempSync2(join23(tmpdir4(), "negotium-compact-"));
|
|
11811
11960
|
const abortController = new AbortController;
|
|
11812
11961
|
const relayAbort = () => abortController.abort(request.signal?.reason);
|
|
11813
11962
|
if (request.signal?.aborted)
|
|
@@ -11834,7 +11983,7 @@ async function summarizeTopicContext(request) {
|
|
|
11834
11983
|
let error = "";
|
|
11835
11984
|
let toolViolation = false;
|
|
11836
11985
|
let compactionLogCalls = 0;
|
|
11837
|
-
const compactionLogPath =
|
|
11986
|
+
const compactionLogPath = join23(compactCwd, "conversation.log");
|
|
11838
11987
|
try {
|
|
11839
11988
|
const compactionMcp = useCompactionLog ? {
|
|
11840
11989
|
compact_log: {
|
|
@@ -12453,14 +12602,14 @@ var init_derive = __esm(async () => {
|
|
|
12453
12602
|
});
|
|
12454
12603
|
|
|
12455
12604
|
// ../../packages/core/src/query/session-inbox-path.ts
|
|
12456
|
-
import { join as
|
|
12605
|
+
import { join as join24 } from "path";
|
|
12457
12606
|
function sessionInboxPath(userId, topicId) {
|
|
12458
12607
|
const key = Buffer.from(topicId, "utf8").toString("base64url");
|
|
12459
|
-
return
|
|
12608
|
+
return join24(SESSION_INBOX_DIR, userId, `${TOPIC_ID_FILE_PREFIX}${key}${JSONL_SUFFIX}`);
|
|
12460
12609
|
}
|
|
12461
12610
|
function scheduledSessionInboxPath(userId, topicId) {
|
|
12462
12611
|
const key = Buffer.from(topicId, "utf8").toString("base64url");
|
|
12463
|
-
return
|
|
12612
|
+
return join24(SESSION_INBOX_DIR, userId, `${TOPIC_ID_FILE_PREFIX}${key}${SCHEDULE_SUFFIX}`);
|
|
12464
12613
|
}
|
|
12465
12614
|
var TOPIC_ID_FILE_PREFIX = "topic-id-", JSONL_SUFFIX = ".jsonl", SCHEDULE_SUFFIX = ".schedule";
|
|
12466
12615
|
var init_session_inbox_path = __esm(() => {
|
|
@@ -12469,13 +12618,13 @@ var init_session_inbox_path = __esm(() => {
|
|
|
12469
12618
|
|
|
12470
12619
|
// ../../packages/core/src/query/session-inbox-cleanup.ts
|
|
12471
12620
|
import { unlinkSync as unlinkSync15 } from "fs";
|
|
12472
|
-
import { basename as basename4, join as
|
|
12621
|
+
import { basename as basename4, join as join25 } from "path";
|
|
12473
12622
|
function cleanupSessionInboxFiles(userId, topicId, legacyTopicTitle) {
|
|
12474
12623
|
const live = sessionInboxPath(userId, topicId);
|
|
12475
12624
|
const scheduled = scheduledSessionInboxPath(userId, topicId);
|
|
12476
12625
|
const candidates = new Set([live, `${live}.processing`, scheduled, `${scheduled}.processing`]);
|
|
12477
12626
|
if (legacyTopicTitle && legacyTopicTitle !== "." && legacyTopicTitle !== ".." && basename4(legacyTopicTitle) === legacyTopicTitle) {
|
|
12478
|
-
const legacyBase =
|
|
12627
|
+
const legacyBase = join25(SESSION_INBOX_DIR, userId, legacyTopicTitle);
|
|
12479
12628
|
for (const suffix of [".jsonl", ".jsonl.processing", ".schedule", ".schedule.processing"]) {
|
|
12480
12629
|
candidates.add(`${legacyBase}${suffix}`);
|
|
12481
12630
|
}
|
|
@@ -12501,16 +12650,16 @@ var init_session_inbox_cleanup = __esm(() => {
|
|
|
12501
12650
|
|
|
12502
12651
|
// ../../packages/core/src/query/state.ts
|
|
12503
12652
|
import { mkdirSync as mkdirSync16, renameSync as renameSync9, unlinkSync as unlinkSync16, writeFileSync as writeFileSync14 } from "fs";
|
|
12504
|
-
import { basename as basename5, join as
|
|
12653
|
+
import { basename as basename5, join as join26 } from "path";
|
|
12505
12654
|
function createQueryStateStore(options) {
|
|
12506
12655
|
const sanitize = options.sanitizeTopicId ?? sanitizeId;
|
|
12507
|
-
const queryStateDirPath = (userId) =>
|
|
12508
|
-
const queryStateFile = (userId, topicId) =>
|
|
12656
|
+
const queryStateDirPath = (userId) => join26(options.usersLogDir, String(userId), "active-queries");
|
|
12657
|
+
const queryStateFile = (userId, topicId) => join26(queryStateDirPath(userId), `${sanitize(topicId)}.json`);
|
|
12509
12658
|
const legacyQueryStateFile = (userId, topicName) => {
|
|
12510
12659
|
if (!topicName || topicName === "." || topicName === ".." || basename5(topicName) !== topicName) {
|
|
12511
12660
|
return null;
|
|
12512
12661
|
}
|
|
12513
|
-
return
|
|
12662
|
+
return join26(queryStateDirPath(userId), `${topicName}.json`);
|
|
12514
12663
|
};
|
|
12515
12664
|
return {
|
|
12516
12665
|
write(userId, topicId, topicName, task) {
|
|
@@ -12671,30 +12820,30 @@ import {
|
|
|
12671
12820
|
unlinkSync as unlinkSync17,
|
|
12672
12821
|
writeFileSync as writeFileSync15
|
|
12673
12822
|
} from "fs";
|
|
12674
|
-
import { dirname as
|
|
12823
|
+
import { dirname as dirname16, join as join27 } from "path";
|
|
12675
12824
|
function pendingAskDir(userId) {
|
|
12676
12825
|
const rawUserId = String(userId);
|
|
12677
12826
|
const safeUserId = /^[A-Za-z0-9][A-Za-z0-9_.@-]{0,255}$/.test(rawUserId) && !rawUserId.includes("..") ? rawUserId : `sha256-${createHash5("sha256").update(rawUserId).digest("hex")}`;
|
|
12678
|
-
return
|
|
12827
|
+
return join27(resolveStorageSessionAsksDir(), safeUserId);
|
|
12679
12828
|
}
|
|
12680
12829
|
function encodeAskKey(key) {
|
|
12681
12830
|
return JSON.stringify([key.from, key.to]);
|
|
12682
12831
|
}
|
|
12683
12832
|
function pendingAskPath(key) {
|
|
12684
12833
|
const digest = createHash5("sha256").update(encodeAskKey(key)).digest("hex");
|
|
12685
|
-
return
|
|
12834
|
+
return join27(pendingAskDir(key.userId), `${ASK_FILENAME_PREFIX}${digest}.pending`);
|
|
12686
12835
|
}
|
|
12687
12836
|
function v2PendingAskPath(key) {
|
|
12688
12837
|
const encoded = Buffer.from(encodeAskKey(key), "utf8").toString("base64url");
|
|
12689
|
-
return
|
|
12838
|
+
return join27(pendingAskDir(key.userId), `${V2_ASK_FILENAME_PREFIX}${encoded}.pending`);
|
|
12690
12839
|
}
|
|
12691
12840
|
function legacyPendingAskPath(key) {
|
|
12692
12841
|
if (key.from.includes("/") || key.from.includes("\\") || key.to.includes("/") || key.to.includes("\\") || key.from.includes("\x00") || key.to.includes("\x00")) {
|
|
12693
12842
|
return null;
|
|
12694
12843
|
}
|
|
12695
12844
|
const dir = pendingAskDir(key.userId);
|
|
12696
|
-
const candidate =
|
|
12697
|
-
return
|
|
12845
|
+
const candidate = join27(dir, `${key.from}___${key.to}.pending`);
|
|
12846
|
+
return dirname16(candidate) === dir ? candidate : null;
|
|
12698
12847
|
}
|
|
12699
12848
|
function parsePendingAskFilename(fileName) {
|
|
12700
12849
|
if (!fileName.endsWith(".pending"))
|
|
@@ -12934,7 +13083,7 @@ function listPendingAsksForCaller(args) {
|
|
|
12934
13083
|
const parsed = isV3 ? { from: args.from, to: "" } : parsePendingAskFilename(fileName);
|
|
12935
13084
|
if (!parsed)
|
|
12936
13085
|
continue;
|
|
12937
|
-
const path =
|
|
13086
|
+
const path = join27(dir, fileName);
|
|
12938
13087
|
const record = readPendingAskFile(path, {
|
|
12939
13088
|
userId: args.userId,
|
|
12940
13089
|
from: parsed.from,
|
|
@@ -12976,7 +13125,7 @@ function deletePendingAsksForTopic(args) {
|
|
|
12976
13125
|
}
|
|
12977
13126
|
let deleted = 0;
|
|
12978
13127
|
for (const fileName of files) {
|
|
12979
|
-
const path =
|
|
13128
|
+
const path = join27(dir, fileName);
|
|
12980
13129
|
const parsed = parsePendingAskFilename(fileName);
|
|
12981
13130
|
const record = readPendingAskFile(path, {
|
|
12982
13131
|
userId: args.userId,
|
|
@@ -13414,7 +13563,7 @@ var init_self_schedules = __esm(async () => {
|
|
|
13414
13563
|
// ../../packages/core/src/storage/token-stats.ts
|
|
13415
13564
|
import { createHash as createHash6 } from "crypto";
|
|
13416
13565
|
import { mkdirSync as mkdirSync18, writeFileSync as writeFileSync16 } from "fs";
|
|
13417
|
-
import { join as
|
|
13566
|
+
import { join as join28 } from "path";
|
|
13418
13567
|
function emptyBucket() {
|
|
13419
13568
|
return {
|
|
13420
13569
|
inputTokens: 0,
|
|
@@ -13433,7 +13582,7 @@ function queriesPath(userId) {
|
|
|
13433
13582
|
const fileId = tokenStatsFileId(userId);
|
|
13434
13583
|
const logDir = resolveStorageLogDir();
|
|
13435
13584
|
mkdirSync18(logDir, { recursive: true });
|
|
13436
|
-
return
|
|
13585
|
+
return join28(logDir, `token-queries-${fileId}.jsonl`);
|
|
13437
13586
|
}
|
|
13438
13587
|
function loadRecords(userId) {
|
|
13439
13588
|
try {
|
|
@@ -13835,7 +13984,7 @@ var init_lifecycle = __esm(async () => {
|
|
|
13835
13984
|
// ../../packages/core/src/runtime/attachments.ts
|
|
13836
13985
|
import { randomUUID as randomUUID13 } from "crypto";
|
|
13837
13986
|
import { copyFileSync as copyFileSync2, mkdirSync as mkdirSync19, writeFileSync as writeFileSync17 } from "fs";
|
|
13838
|
-
import { basename as basename6, join as
|
|
13987
|
+
import { basename as basename6, join as join29 } from "path";
|
|
13839
13988
|
function workspaceCwdFor(topicId) {
|
|
13840
13989
|
return resolveTopicWorkspaceDir(topicId);
|
|
13841
13990
|
}
|
|
@@ -13848,7 +13997,7 @@ function materializePromptAttachments(topicId, queryId, attachmentIds) {
|
|
|
13848
13997
|
if (!attachmentIds?.length)
|
|
13849
13998
|
return [];
|
|
13850
13999
|
const out = [];
|
|
13851
|
-
const destDir =
|
|
14000
|
+
const destDir = join29(workspaceCwdFor(topicId), "attachments", queryId);
|
|
13852
14001
|
for (const rawId of attachmentIds) {
|
|
13853
14002
|
if (typeof rawId !== "string")
|
|
13854
14003
|
continue;
|
|
@@ -13865,7 +14014,7 @@ function materializePromptAttachments(topicId, queryId, attachmentIds) {
|
|
|
13865
14014
|
mkdirSync19(destDir, { recursive: true });
|
|
13866
14015
|
const index = String(out.length + 1).padStart(2, "0");
|
|
13867
14016
|
const safeName = safeAttachmentFilename(attachment.filename, fileId);
|
|
13868
|
-
const destPath =
|
|
14017
|
+
const destPath = join29(destDir, `${index}-${fileId.slice(0, 8)}-${safeName}`);
|
|
13869
14018
|
copyFileSync2(sourcePath, destPath);
|
|
13870
14019
|
out.push({
|
|
13871
14020
|
id: attachment.id,
|
|
@@ -13895,10 +14044,10 @@ function promptWithAttachments(prompt, attachments) {
|
|
|
13895
14044
|
return composeAttachmentPrompt(prompt, attachments.map(({ filename, path }) => attachmentPromptLine(filename, path)));
|
|
13896
14045
|
}
|
|
13897
14046
|
function ingestAttachment(args) {
|
|
13898
|
-
const destDir =
|
|
14047
|
+
const destDir = join29(UPLOADS_DIR, args.topicId);
|
|
13899
14048
|
mkdirSync19(destDir, { recursive: true });
|
|
13900
14049
|
const safeName = safeAttachmentFilename(args.filename, "upload");
|
|
13901
|
-
const destPath =
|
|
14050
|
+
const destPath = join29(destDir, `${Date.now()}-${randomUUID13().slice(0, 8)}-${safeName}`);
|
|
13902
14051
|
if (args.sourcePath !== undefined) {
|
|
13903
14052
|
copyFileSync2(args.sourcePath, destPath);
|
|
13904
14053
|
} else if (args.bytes !== undefined) {
|
|
@@ -14073,12 +14222,12 @@ var init_errors = __esm(() => {
|
|
|
14073
14222
|
|
|
14074
14223
|
// ../../packages/core/src/runtime/event-heartbeat.ts
|
|
14075
14224
|
function nextOrHeartbeat(pending, intervalMs) {
|
|
14076
|
-
return new Promise((
|
|
14077
|
-
const timer = setTimeout(() =>
|
|
14225
|
+
return new Promise((resolve16, reject) => {
|
|
14226
|
+
const timer = setTimeout(() => resolve16({ kind: "heartbeat" }), intervalMs);
|
|
14078
14227
|
timer.unref?.();
|
|
14079
14228
|
pending.then((result) => {
|
|
14080
14229
|
clearTimeout(timer);
|
|
14081
|
-
|
|
14230
|
+
resolve16({ kind: "event", result });
|
|
14082
14231
|
}, (error) => {
|
|
14083
14232
|
clearTimeout(timer);
|
|
14084
14233
|
reject(error);
|
|
@@ -14616,8 +14765,8 @@ function createAskUserRuntime(host) {
|
|
|
14616
14765
|
return errorResult(`Error: failed to persist ask_user_question: ${error instanceof Error ? error.message : String(error)}`);
|
|
14617
14766
|
}
|
|
14618
14767
|
let resolveAnswer;
|
|
14619
|
-
const promise = new Promise((
|
|
14620
|
-
resolveAnswer =
|
|
14768
|
+
const promise = new Promise((resolve16) => {
|
|
14769
|
+
resolveAnswer = resolve16;
|
|
14621
14770
|
});
|
|
14622
14771
|
pendingAsks2.set(message.id, {
|
|
14623
14772
|
topicId: ctx.topicId,
|
|
@@ -14945,7 +15094,7 @@ var init_visual_html = __esm(() => {
|
|
|
14945
15094
|
|
|
14946
15095
|
// ../../packages/core/src/runtime/visuals.ts
|
|
14947
15096
|
import { realpathSync as realpathSync5 } from "fs";
|
|
14948
|
-
import { isAbsolute as isAbsolute4, resolve as
|
|
15097
|
+
import { isAbsolute as isAbsolute4, resolve as resolve16 } from "path";
|
|
14949
15098
|
function activeVisualHtmlForPrompt(html) {
|
|
14950
15099
|
if (html.length <= ACTIVE_VISUAL_PROMPT_MAX_CHARS) {
|
|
14951
15100
|
return { html, omittedChars: 0 };
|
|
@@ -14996,8 +15145,8 @@ function topicAllowsVisualFileId(topicId, fileId) {
|
|
|
14996
15145
|
return topicHasAttachmentFileId(topicId, fileId) || topicHasVisualFileId(topicId, fileId);
|
|
14997
15146
|
}
|
|
14998
15147
|
function isPathInside(baseDir, filePath) {
|
|
14999
|
-
const base =
|
|
15000
|
-
const normalized =
|
|
15148
|
+
const base = resolve16(baseDir);
|
|
15149
|
+
const normalized = resolve16(filePath);
|
|
15001
15150
|
try {
|
|
15002
15151
|
const realBase = realpathSync5(base);
|
|
15003
15152
|
const real = realpathSync5(normalized);
|
|
@@ -15059,7 +15208,7 @@ function resolveVisualMediaInput(topicId, input) {
|
|
|
15059
15208
|
}
|
|
15060
15209
|
const rawPath = input.file_path.trim();
|
|
15061
15210
|
const cwd = workspaceCwdFor(topicId);
|
|
15062
|
-
const candidate = isAbsolute4(rawPath) ? rawPath :
|
|
15211
|
+
const candidate = isAbsolute4(rawPath) ? rawPath : resolve16(cwd, rawPath);
|
|
15063
15212
|
if (!isPathInside(cwd, candidate)) {
|
|
15064
15213
|
return { error: "file_path must be inside the topic workspace" };
|
|
15065
15214
|
}
|
|
@@ -15097,7 +15246,7 @@ var init_visuals = __esm(async () => {
|
|
|
15097
15246
|
// ../../packages/core/src/runtime/turn-event-stream.ts
|
|
15098
15247
|
import { randomUUID as randomUUID15 } from "crypto";
|
|
15099
15248
|
import { realpathSync as realpathSync6, statSync as statSync9 } from "fs";
|
|
15100
|
-
import { isAbsolute as isAbsolute5, resolve as
|
|
15249
|
+
import { isAbsolute as isAbsolute5, resolve as resolve17 } from "path";
|
|
15101
15250
|
function sessionEventMatchesCurrentExecution(topicId, queryId, agent, model) {
|
|
15102
15251
|
if (getRoomQuery(topicId)?.queryId !== queryId)
|
|
15103
15252
|
return false;
|
|
@@ -15450,7 +15599,7 @@ ${JSON.stringify(event.input ?? {})}`);
|
|
|
15450
15599
|
case "file":
|
|
15451
15600
|
if (!silent && peerBridge) {
|
|
15452
15601
|
const cwd = workspaceCwdFor(topicId);
|
|
15453
|
-
const path = isAbsolute5(event.path) ? event.path :
|
|
15602
|
+
const path = isAbsolute5(event.path) ? event.path : resolve17(cwd, event.path);
|
|
15454
15603
|
if (!isPathInside(cwd, path)) {
|
|
15455
15604
|
logger.warn({ topicId, path }, "peer output file is outside the topic workspace");
|
|
15456
15605
|
break;
|
|
@@ -15732,15 +15881,15 @@ var init_turn_session = __esm(async () => {
|
|
|
15732
15881
|
});
|
|
15733
15882
|
|
|
15734
15883
|
// ../../packages/core/src/storage/app-settings.ts
|
|
15735
|
-
import { existsSync as
|
|
15736
|
-
import { dirname as
|
|
15884
|
+
import { existsSync as existsSync21, mkdirSync as mkdirSync20, readFileSync as readFileSync20, writeFileSync as writeFileSync18 } from "fs";
|
|
15885
|
+
import { dirname as dirname17, join as join30 } from "path";
|
|
15737
15886
|
function settingsFile() {
|
|
15738
|
-
return
|
|
15887
|
+
return join30(resolveStorageDataDir(), "otium-settings.json");
|
|
15739
15888
|
}
|
|
15740
15889
|
function getGlobalAiName() {
|
|
15741
15890
|
const path = settingsFile();
|
|
15742
15891
|
try {
|
|
15743
|
-
if (
|
|
15892
|
+
if (existsSync21(path)) {
|
|
15744
15893
|
const data = JSON.parse(readFileSync20(path, "utf8"));
|
|
15745
15894
|
if (typeof data.aiName === "string" && data.aiName.trim()) {
|
|
15746
15895
|
return data.aiName.trim();
|
|
@@ -15829,8 +15978,8 @@ __export(exports_turn_runner, {
|
|
|
15829
15978
|
AGENT_DISPLAY_NAME: () => AGENT_DISPLAY_NAME
|
|
15830
15979
|
});
|
|
15831
15980
|
import { randomUUID as randomUUID16 } from "crypto";
|
|
15832
|
-
import { existsSync as
|
|
15833
|
-
import { join as
|
|
15981
|
+
import { existsSync as existsSync22, mkdirSync as mkdirSync21, readdirSync as readdirSync7, statSync as statSync10 } from "fs";
|
|
15982
|
+
import { join as join31 } from "path";
|
|
15834
15983
|
function withDefaultPlaywright(configuredMcp, isManager) {
|
|
15835
15984
|
if (isManager)
|
|
15836
15985
|
return configuredMcp;
|
|
@@ -15885,8 +16034,8 @@ function appendAskReplyMessage(topicId, text2, agentType) {
|
|
|
15885
16034
|
return message;
|
|
15886
16035
|
}
|
|
15887
16036
|
function resolveWikiMirrorPath(directory, preferredFilename, matchesLegacyId, matchesTitle, preferExact = true) {
|
|
15888
|
-
const preferred =
|
|
15889
|
-
if (preferExact &&
|
|
16037
|
+
const preferred = join31(directory, preferredFilename);
|
|
16038
|
+
if (preferExact && existsSync22(preferred))
|
|
15890
16039
|
return preferred;
|
|
15891
16040
|
let newestLegacyId = null;
|
|
15892
16041
|
let newestTitle = null;
|
|
@@ -15896,7 +16045,7 @@ function resolveWikiMirrorPath(directory, preferredFilename, matchesLegacyId, ma
|
|
|
15896
16045
|
const legacyIdMatch = !titleMatch && matchesLegacyId(filename);
|
|
15897
16046
|
if (!titleMatch && !legacyIdMatch)
|
|
15898
16047
|
continue;
|
|
15899
|
-
const path =
|
|
16048
|
+
const path = join31(directory, filename);
|
|
15900
16049
|
const mtimeMs = statSync10(path).mtimeMs;
|
|
15901
16050
|
if (titleMatch) {
|
|
15902
16051
|
if (!newestTitle || mtimeMs > newestTitle.mtimeMs) {
|
|
@@ -15910,10 +16059,10 @@ function resolveWikiMirrorPath(directory, preferredFilename, matchesLegacyId, ma
|
|
|
15910
16059
|
return newestTitle?.path ?? newestLegacyId?.path ?? preferred;
|
|
15911
16060
|
}
|
|
15912
16061
|
function resolveWikiMemoryMirror(wikiDir, topicId, topicTitle) {
|
|
15913
|
-
const briefFile = resolveWikiMirrorPath(
|
|
15914
|
-
const hasBriefFile =
|
|
15915
|
-
const latestSummaryCandidate = resolveWikiMirrorPath(
|
|
15916
|
-
const latestSummaryFile =
|
|
16062
|
+
const briefFile = resolveWikiMirrorPath(join31(wikiDir, "topic"), `${wikiBriefStorageKey(topicTitle, topicId)}.md`, (filename) => isTopicBriefFile(filename, topicId), (filename) => isTopicBriefFile(filename, topicId, topicTitle));
|
|
16063
|
+
const hasBriefFile = existsSync22(briefFile) && statSync10(briefFile).isFile();
|
|
16064
|
+
const latestSummaryCandidate = resolveWikiMirrorPath(join31(wikiDir, "summaries"), `__missing__-${wikiSummaryFilename("0000-00-00", topicTitle, topicId)}`, (filename) => isTopicSummaryFile(filename, topicId), (filename) => isTopicSummaryFile(filename, topicId, topicTitle), false);
|
|
16065
|
+
const latestSummaryFile = existsSync22(latestSummaryCandidate) && statSync10(latestSummaryCandidate).isFile() ? latestSummaryCandidate : null;
|
|
15917
16066
|
return { briefFile, hasBriefFile, latestSummaryFile };
|
|
15918
16067
|
}
|
|
15919
16068
|
async function streamAgentEvents(topicId, topicTitle, queryId, events, control, agentType, model, effort, userId, retryableSessionExpired = true, onSessionId, execution) {
|
|
@@ -17109,9 +17258,9 @@ __export(exports_auth_check, {
|
|
|
17109
17258
|
checkAgentAuth: () => checkAgentAuth
|
|
17110
17259
|
});
|
|
17111
17260
|
import { execFileSync as execFileSync7 } from "child_process";
|
|
17112
|
-
import { existsSync as
|
|
17261
|
+
import { existsSync as existsSync23 } from "fs";
|
|
17113
17262
|
import { homedir as homedir8, platform } from "os";
|
|
17114
|
-
import { join as
|
|
17263
|
+
import { join as join32 } from "path";
|
|
17115
17264
|
function hasMaestroCredential(host, key, userId) {
|
|
17116
17265
|
if (userId && host.getVaultValue(userId, key)?.trim())
|
|
17117
17266
|
return true;
|
|
@@ -17131,7 +17280,7 @@ function checkAgentAuth(agent, host = defaultAgentAuthHost, userId) {
|
|
|
17131
17280
|
case "claude": {
|
|
17132
17281
|
if (host.environment.ANTHROPIC_API_KEY)
|
|
17133
17282
|
return { ok: true };
|
|
17134
|
-
const path =
|
|
17283
|
+
const path = join32(host.homeDirectory(), ".claude", ".credentials.json");
|
|
17135
17284
|
if (host.operatingSystem() === "darwin") {
|
|
17136
17285
|
if (host.hasMacOsCredential("Claude Code-credentials") || host.exists(path)) {
|
|
17137
17286
|
return { ok: true };
|
|
@@ -17182,7 +17331,7 @@ var init_auth_check = __esm(async () => {
|
|
|
17182
17331
|
await init_vault();
|
|
17183
17332
|
defaultAgentAuthHost = {
|
|
17184
17333
|
codexAuthFilePath,
|
|
17185
|
-
exists:
|
|
17334
|
+
exists: existsSync23,
|
|
17186
17335
|
environment: process.env,
|
|
17187
17336
|
homeDirectory: homedir8,
|
|
17188
17337
|
operatingSystem: platform,
|
|
@@ -18133,280 +18282,6 @@ Available: ${available.join(", ") || "none"}`
|
|
|
18133
18282
|
}
|
|
18134
18283
|
return Object.freeze({ listTargets, getTopics, validateTarget });
|
|
18135
18284
|
}
|
|
18136
|
-
// ../../packages/core/src/mcp/vault-http.ts
|
|
18137
|
-
var SAFE_RESPONSE_HEADERS = new Set([
|
|
18138
|
-
"content-type",
|
|
18139
|
-
"content-length",
|
|
18140
|
-
"location",
|
|
18141
|
-
"retry-after",
|
|
18142
|
-
"x-ratelimit-limit",
|
|
18143
|
-
"x-ratelimit-remaining",
|
|
18144
|
-
"x-ratelimit-reset"
|
|
18145
|
-
]);
|
|
18146
|
-
var FORBIDDEN_REQUEST_HEADERS = new Set([
|
|
18147
|
-
"connection",
|
|
18148
|
-
"content-length",
|
|
18149
|
-
"host",
|
|
18150
|
-
"proxy-authorization",
|
|
18151
|
-
"transfer-encoding"
|
|
18152
|
-
]);
|
|
18153
|
-
function substituteObject(userId, values, host) {
|
|
18154
|
-
const used = new Set;
|
|
18155
|
-
const substituted = {};
|
|
18156
|
-
for (const [key, value2] of Object.entries(values)) {
|
|
18157
|
-
if (FORBIDDEN_REQUEST_HEADERS.has(key.toLowerCase())) {
|
|
18158
|
-
throw new Error(`Header "${key}" is not allowed`);
|
|
18159
|
-
}
|
|
18160
|
-
const result = host.substitute(userId, value2);
|
|
18161
|
-
for (const usedKey of result.usedKeys)
|
|
18162
|
-
used.add(usedKey);
|
|
18163
|
-
substituted[key] = result.text;
|
|
18164
|
-
}
|
|
18165
|
-
return { values: substituted, usedKeys: [...used] };
|
|
18166
|
-
}
|
|
18167
|
-
function safeResponseHeaders(userId, headers, host) {
|
|
18168
|
-
const output = {};
|
|
18169
|
-
for (const [key, value2] of headers.entries()) {
|
|
18170
|
-
if (!SAFE_RESPONSE_HEADERS.has(key.toLowerCase()))
|
|
18171
|
-
continue;
|
|
18172
|
-
output[key] = host.redact(userId, value2);
|
|
18173
|
-
}
|
|
18174
|
-
return output;
|
|
18175
|
-
}
|
|
18176
|
-
async function readBoundedBody(response, maxBytes) {
|
|
18177
|
-
if (!response.body)
|
|
18178
|
-
return { bytes: new Uint8Array, truncated: false };
|
|
18179
|
-
const reader = response.body.getReader();
|
|
18180
|
-
const chunks = [];
|
|
18181
|
-
let keptBytes = 0;
|
|
18182
|
-
let truncated = false;
|
|
18183
|
-
try {
|
|
18184
|
-
while (true) {
|
|
18185
|
-
const next = await reader.read();
|
|
18186
|
-
if (next.done)
|
|
18187
|
-
break;
|
|
18188
|
-
const remaining = maxBytes - keptBytes;
|
|
18189
|
-
if (remaining <= 0) {
|
|
18190
|
-
truncated = true;
|
|
18191
|
-
await reader.cancel();
|
|
18192
|
-
break;
|
|
18193
|
-
}
|
|
18194
|
-
const visible = next.value.subarray(0, remaining);
|
|
18195
|
-
chunks.push(visible);
|
|
18196
|
-
keptBytes += visible.byteLength;
|
|
18197
|
-
if (visible.byteLength < next.value.byteLength) {
|
|
18198
|
-
truncated = true;
|
|
18199
|
-
await reader.cancel();
|
|
18200
|
-
break;
|
|
18201
|
-
}
|
|
18202
|
-
}
|
|
18203
|
-
} finally {
|
|
18204
|
-
reader.releaseLock();
|
|
18205
|
-
}
|
|
18206
|
-
const bytes = new Uint8Array(keptBytes);
|
|
18207
|
-
let offset = 0;
|
|
18208
|
-
for (const chunk of chunks) {
|
|
18209
|
-
bytes.set(chunk, offset);
|
|
18210
|
-
offset += chunk.byteLength;
|
|
18211
|
-
}
|
|
18212
|
-
return { bytes, truncated };
|
|
18213
|
-
}
|
|
18214
|
-
async function executeVaultHttpRequest(userId, request, host, fetchImpl = fetch) {
|
|
18215
|
-
let parsedUrl;
|
|
18216
|
-
try {
|
|
18217
|
-
parsedUrl = new URL(request.url);
|
|
18218
|
-
} catch {
|
|
18219
|
-
return { ok: false, error: "url must be an absolute HTTPS URL" };
|
|
18220
|
-
}
|
|
18221
|
-
if (parsedUrl.protocol !== "https:") {
|
|
18222
|
-
return {
|
|
18223
|
-
ok: false,
|
|
18224
|
-
error: "Vault credentials may only be sent over HTTPS"
|
|
18225
|
-
};
|
|
18226
|
-
}
|
|
18227
|
-
if (parsedUrl.username || parsedUrl.password || /\{\{[^}]+\}\}/.test(request.url)) {
|
|
18228
|
-
return {
|
|
18229
|
-
ok: false,
|
|
18230
|
-
error: "Keep Vault placeholders out of URLs; put credentials in headers or body"
|
|
18231
|
-
};
|
|
18232
|
-
}
|
|
18233
|
-
let headers;
|
|
18234
|
-
let headerKeys;
|
|
18235
|
-
try {
|
|
18236
|
-
const substituted = substituteObject(userId, request.headers ?? {}, host);
|
|
18237
|
-
headers = substituted.values;
|
|
18238
|
-
headerKeys = substituted.usedKeys;
|
|
18239
|
-
} catch (error) {
|
|
18240
|
-
return {
|
|
18241
|
-
ok: false,
|
|
18242
|
-
error: error instanceof Error ? error.message : String(error)
|
|
18243
|
-
};
|
|
18244
|
-
}
|
|
18245
|
-
const bodyResult = request.body === undefined ? { text: undefined, usedKeys: [] } : host.substitute(userId, request.body);
|
|
18246
|
-
const usedKeys = [...new Set([...headerKeys, ...bodyResult.usedKeys])].sort();
|
|
18247
|
-
if (usedKeys.length === 0) {
|
|
18248
|
-
return {
|
|
18249
|
-
ok: false,
|
|
18250
|
-
error: "No valid Vault placeholder was found in headers or body"
|
|
18251
|
-
};
|
|
18252
|
-
}
|
|
18253
|
-
if (request.method === "GET" && request.body !== undefined) {
|
|
18254
|
-
return {
|
|
18255
|
-
ok: false,
|
|
18256
|
-
error: "GET requests cannot include a credential-bearing body"
|
|
18257
|
-
};
|
|
18258
|
-
}
|
|
18259
|
-
const controller = new AbortController;
|
|
18260
|
-
const timeoutMs = Math.min(Math.max(request.timeoutMs ?? 30000, 1000), 120000);
|
|
18261
|
-
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
18262
|
-
const startedAt = Date.now();
|
|
18263
|
-
try {
|
|
18264
|
-
const response = await fetchImpl(parsedUrl, {
|
|
18265
|
-
method: request.method,
|
|
18266
|
-
headers,
|
|
18267
|
-
body: request.method === "GET" ? undefined : bodyResult.text,
|
|
18268
|
-
redirect: "manual",
|
|
18269
|
-
signal: controller.signal
|
|
18270
|
-
});
|
|
18271
|
-
const maxBytes = Math.min(Math.max(request.maxResponseBytes ?? 256 * 1024, 1024), 1024 * 1024);
|
|
18272
|
-
const { bytes, truncated } = await readBoundedBody(response, maxBytes);
|
|
18273
|
-
const contentType = response.headers.get("content-type")?.toLowerCase() ?? "";
|
|
18274
|
-
const textual = contentType.startsWith("text/") || contentType.includes("json") || contentType.includes("xml") || contentType.includes("javascript") || contentType === "";
|
|
18275
|
-
const body = textual ? host.redact(userId, new TextDecoder().decode(bytes)) : `[binary response omitted: ${bytes.byteLength} bytes, ${contentType || "unknown content type"}]`;
|
|
18276
|
-
host.log?.("info", {
|
|
18277
|
-
userId,
|
|
18278
|
-
vaultKeys: usedKeys,
|
|
18279
|
-
host: parsedUrl.hostname,
|
|
18280
|
-
method: request.method,
|
|
18281
|
-
status: response.status,
|
|
18282
|
-
durationMs: Date.now() - startedAt
|
|
18283
|
-
}, "vault credential used");
|
|
18284
|
-
return {
|
|
18285
|
-
ok: response.ok,
|
|
18286
|
-
status: response.status,
|
|
18287
|
-
statusText: response.statusText,
|
|
18288
|
-
headers: safeResponseHeaders(userId, response.headers, host),
|
|
18289
|
-
body,
|
|
18290
|
-
truncated
|
|
18291
|
-
};
|
|
18292
|
-
} catch (error) {
|
|
18293
|
-
const raw = error instanceof Error ? error.message : String(error);
|
|
18294
|
-
host.log?.("warn", {
|
|
18295
|
-
userId,
|
|
18296
|
-
vaultKeys: usedKeys,
|
|
18297
|
-
host: parsedUrl.hostname,
|
|
18298
|
-
method: request.method,
|
|
18299
|
-
durationMs: Date.now() - startedAt
|
|
18300
|
-
}, "vault credential request failed");
|
|
18301
|
-
return { ok: false, error: host.redact(userId, raw) };
|
|
18302
|
-
} finally {
|
|
18303
|
-
clearTimeout(timeout);
|
|
18304
|
-
}
|
|
18305
|
-
}
|
|
18306
|
-
// ../../packages/core/src/mcp/vault-run.ts
|
|
18307
|
-
import { spawn } from "child_process";
|
|
18308
|
-
function appendBounded(chunks, chunk, state, maxBytes) {
|
|
18309
|
-
if (state.bytes >= maxBytes) {
|
|
18310
|
-
state.truncated = true;
|
|
18311
|
-
return;
|
|
18312
|
-
}
|
|
18313
|
-
const remaining = maxBytes - state.bytes;
|
|
18314
|
-
const visible = chunk.subarray(0, remaining);
|
|
18315
|
-
chunks.push(visible);
|
|
18316
|
-
state.bytes += visible.byteLength;
|
|
18317
|
-
if (visible.byteLength < chunk.byteLength)
|
|
18318
|
-
state.truncated = true;
|
|
18319
|
-
}
|
|
18320
|
-
async function executeVaultRun(userId, request, host) {
|
|
18321
|
-
const substitution = host.substitute(userId, request.command);
|
|
18322
|
-
if (substitution.usedKeys.length === 0) {
|
|
18323
|
-
return {
|
|
18324
|
-
ok: false,
|
|
18325
|
-
exitCode: null,
|
|
18326
|
-
signal: null,
|
|
18327
|
-
stdout: "",
|
|
18328
|
-
stderr: "",
|
|
18329
|
-
truncated: false,
|
|
18330
|
-
usedKeys: [],
|
|
18331
|
-
error: "No valid Vault placeholder was found in command"
|
|
18332
|
-
};
|
|
18333
|
-
}
|
|
18334
|
-
const timeoutMs = Math.min(Math.max(request.timeoutMs ?? 120000, 1000), 600000);
|
|
18335
|
-
const maxOutputBytes = Math.min(Math.max(request.maxOutputBytes ?? 512 * 1024, 1024), 2 * 1024 * 1024);
|
|
18336
|
-
const stdoutChunks = [];
|
|
18337
|
-
const stderrChunks = [];
|
|
18338
|
-
const stdoutState = { bytes: 0, truncated: false };
|
|
18339
|
-
const stderrState = { bytes: 0, truncated: false };
|
|
18340
|
-
const startedAt = Date.now();
|
|
18341
|
-
return await new Promise((resolve) => {
|
|
18342
|
-
const child = spawn(process.env.SHELL || "/bin/sh", ["-s"], {
|
|
18343
|
-
cwd: request.cwd,
|
|
18344
|
-
detached: true,
|
|
18345
|
-
env: process.env,
|
|
18346
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
18347
|
-
});
|
|
18348
|
-
let settled = false;
|
|
18349
|
-
let timedOut = false;
|
|
18350
|
-
const signalTree = (signal) => {
|
|
18351
|
-
if (!child.pid)
|
|
18352
|
-
return;
|
|
18353
|
-
try {
|
|
18354
|
-
process.kill(-child.pid, signal);
|
|
18355
|
-
} catch {
|
|
18356
|
-
try {
|
|
18357
|
-
child.kill(signal);
|
|
18358
|
-
} catch {}
|
|
18359
|
-
}
|
|
18360
|
-
};
|
|
18361
|
-
const finish = (result) => {
|
|
18362
|
-
if (settled)
|
|
18363
|
-
return;
|
|
18364
|
-
settled = true;
|
|
18365
|
-
clearTimeout(timeout);
|
|
18366
|
-
host.log?.("info", {
|
|
18367
|
-
userId,
|
|
18368
|
-
vaultKeys: substitution.usedKeys,
|
|
18369
|
-
exitCode: result.exitCode,
|
|
18370
|
-
signal: result.signal,
|
|
18371
|
-
durationMs: Date.now() - startedAt,
|
|
18372
|
-
timedOut
|
|
18373
|
-
}, "vault credential command used");
|
|
18374
|
-
resolve({ ...result, usedKeys: substitution.usedKeys });
|
|
18375
|
-
};
|
|
18376
|
-
child.stdout.on("data", (chunk) => appendBounded(stdoutChunks, chunk, stdoutState, maxOutputBytes));
|
|
18377
|
-
child.stderr.on("data", (chunk) => appendBounded(stderrChunks, chunk, stderrState, maxOutputBytes));
|
|
18378
|
-
child.once("error", (error) => {
|
|
18379
|
-
finish({
|
|
18380
|
-
ok: false,
|
|
18381
|
-
exitCode: null,
|
|
18382
|
-
signal: null,
|
|
18383
|
-
stdout: "",
|
|
18384
|
-
stderr: "",
|
|
18385
|
-
truncated: false,
|
|
18386
|
-
error: host.redact(userId, error.message)
|
|
18387
|
-
});
|
|
18388
|
-
});
|
|
18389
|
-
child.once("close", (exitCode, signal) => {
|
|
18390
|
-
signalTree("SIGTERM");
|
|
18391
|
-
const stdout = host.redact(userId, Buffer.concat(stdoutChunks).toString("utf8"));
|
|
18392
|
-
const stderr = host.redact(userId, Buffer.concat(stderrChunks).toString("utf8"));
|
|
18393
|
-
finish({
|
|
18394
|
-
ok: !timedOut && exitCode === 0,
|
|
18395
|
-
exitCode,
|
|
18396
|
-
signal,
|
|
18397
|
-
stdout,
|
|
18398
|
-
stderr,
|
|
18399
|
-
truncated: stdoutState.truncated || stderrState.truncated,
|
|
18400
|
-
...timedOut ? { error: `Command timed out after ${timeoutMs}ms` } : {}
|
|
18401
|
-
});
|
|
18402
|
-
});
|
|
18403
|
-
const timeout = setTimeout(() => {
|
|
18404
|
-
timedOut = true;
|
|
18405
|
-
signalTree("SIGKILL");
|
|
18406
|
-
}, timeoutMs);
|
|
18407
|
-
child.stdin.end(substitution.text);
|
|
18408
|
-
});
|
|
18409
|
-
}
|
|
18410
18285
|
// ../../packages/core/src/mcp/wiki-server.ts
|
|
18411
18286
|
import { AsyncLocalStorage } from "async_hooks";
|
|
18412
18287
|
import { randomUUID } from "crypto";
|
|
@@ -20334,7 +20209,7 @@ init_maestro_registry();
|
|
|
20334
20209
|
init_config();
|
|
20335
20210
|
init_jsonl();
|
|
20336
20211
|
init_mcp_helpers();
|
|
20337
|
-
import { spawn as
|
|
20212
|
+
import { spawn as spawn4 } from "child_process";
|
|
20338
20213
|
import { existsSync as existsSync10, readdirSync as readdirSync3 } from "fs";
|
|
20339
20214
|
import { join as join11 } from "path";
|
|
20340
20215
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
@@ -20353,7 +20228,7 @@ function signalProcessTree(child, signal) {
|
|
|
20353
20228
|
}
|
|
20354
20229
|
function spawnCapture(cmd, args, timeoutMs, signal, env) {
|
|
20355
20230
|
return new Promise((resolve8, reject) => {
|
|
20356
|
-
const child =
|
|
20231
|
+
const child = spawn4(cmd, args, {
|
|
20357
20232
|
env: env ?? process.env,
|
|
20358
20233
|
stdio: ["ignore", "pipe", "pipe"],
|
|
20359
20234
|
detached: process.platform !== "win32"
|
|
@@ -21450,14 +21325,11 @@ function createTokenStatsMcpServer(context, host = defaultTokenStatsMcpHost) {
|
|
|
21450
21325
|
return server;
|
|
21451
21326
|
}
|
|
21452
21327
|
// ../../packages/core/src/mcp/factories/vault.ts
|
|
21453
|
-
import { McpServer as McpServer8 } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
21454
|
-
import { z as z9 } from "zod";
|
|
21455
21328
|
init_mcp_helpers();
|
|
21456
|
-
|
|
21329
|
+
import { McpServer as McpServer8 } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
21330
|
+
function createVaultMcpServer(context, host) {
|
|
21457
21331
|
const server = new McpServer8({ name: "vault", version: "1.0.0" });
|
|
21458
|
-
|
|
21459
|
-
const http = executors.http ?? executeVaultHttpRequest;
|
|
21460
|
-
server.tool("vault_list", context.httpOnly ? "List the user's Vault keys and descriptions without exposing values. Use vault_http_request for HTTPS APIs that need a credential." : "List the user's Vault keys and descriptions without exposing values. Use vault_http_request for APIs and vault_run for shell/CLI work that needs a credential.", {}, () => {
|
|
21332
|
+
server.tool("vault_list", "List the user's Vault keys and descriptions without exposing values. Use {{KEY}} placeholders directly in supported transient tool inputs.", {}, () => {
|
|
21461
21333
|
if (!context.userId)
|
|
21462
21334
|
return mcpOk("(vault unavailable: no user context)");
|
|
21463
21335
|
const entries = host.list(context.userId);
|
|
@@ -21468,51 +21340,11 @@ function createVaultMcpServer(context, host, executors = {}) {
|
|
|
21468
21340
|
${lines.join(`
|
|
21469
21341
|
`)}`);
|
|
21470
21342
|
});
|
|
21471
|
-
if (!context.listOnly && !context.httpOnly) {
|
|
21472
|
-
server.tool("vault_run", "Run a shell command containing {{KEY}} references inside Otium's credential broker. Expanded command input never reaches the model/provider, and stdout/stderr are redacted before return. Prefer vault_http_request for HTTP APIs.", {
|
|
21473
|
-
command: z9.string().min(1).max(64 * 1024),
|
|
21474
|
-
timeout_ms: z9.number().int().min(1000).max(600000).optional(),
|
|
21475
|
-
max_output_bytes: z9.number().int().min(1024).max(2 * 1024 * 1024).optional()
|
|
21476
|
-
}, async ({ command, timeout_ms, max_output_bytes }) => {
|
|
21477
|
-
if (!context.userId)
|
|
21478
|
-
return mcpError("Vault unavailable: no user context");
|
|
21479
|
-
const result = await run(context.userId, {
|
|
21480
|
-
command,
|
|
21481
|
-
timeoutMs: timeout_ms,
|
|
21482
|
-
maxOutputBytes: max_output_bytes,
|
|
21483
|
-
cwd: context.cwd
|
|
21484
|
-
}, host);
|
|
21485
|
-
return result.error && result.exitCode === null ? mcpError(result.error) : mcpOk(JSON.stringify(result, null, 2));
|
|
21486
|
-
});
|
|
21487
|
-
}
|
|
21488
|
-
if (!context.listOnly)
|
|
21489
|
-
server.tool("vault_http_request", "Make an HTTPS request with {{KEY}} references resolved inside Otium. Put secrets in headers or body, never in the URL. The expanded request is not returned; the response is redacted before the model sees it.", {
|
|
21490
|
-
method: z9.enum(["GET", "POST", "PUT", "PATCH", "DELETE"]).default("GET"),
|
|
21491
|
-
url: z9.string().url().describe("Absolute HTTPS URL without Vault placeholders"),
|
|
21492
|
-
headers: z9.record(z9.string(), z9.string()).optional(),
|
|
21493
|
-
body: z9.string().optional(),
|
|
21494
|
-
timeout_ms: z9.number().int().min(1000).max(120000).optional(),
|
|
21495
|
-
max_response_bytes: z9.number().int().min(1024).max(1024 * 1024).optional()
|
|
21496
|
-
}, async ({ method, url, headers, body, timeout_ms, max_response_bytes }) => {
|
|
21497
|
-
if (!context.userId)
|
|
21498
|
-
return mcpError("Vault unavailable: no user context");
|
|
21499
|
-
const result = await http(context.userId, {
|
|
21500
|
-
method,
|
|
21501
|
-
url,
|
|
21502
|
-
headers,
|
|
21503
|
-
body,
|
|
21504
|
-
timeoutMs: timeout_ms,
|
|
21505
|
-
maxResponseBytes: max_response_bytes
|
|
21506
|
-
}, host);
|
|
21507
|
-
return result.error ? mcpError(result.error) : mcpOk(JSON.stringify(result, null, 2));
|
|
21508
|
-
});
|
|
21509
21343
|
return server;
|
|
21510
21344
|
}
|
|
21511
21345
|
export {
|
|
21512
21346
|
protectMcpStdio,
|
|
21513
21347
|
parseSessionCommContext,
|
|
21514
|
-
executeVaultRun,
|
|
21515
|
-
executeVaultHttpRequest,
|
|
21516
21348
|
defaultTokenStatsMcpHost,
|
|
21517
21349
|
defaultTaskMcpHost,
|
|
21518
21350
|
defaultSystemHealthMcpHost,
|
|
@@ -21529,4 +21361,4 @@ export {
|
|
|
21529
21361
|
createAgentHealthMcpServer
|
|
21530
21362
|
};
|
|
21531
21363
|
|
|
21532
|
-
//# debugId=
|
|
21364
|
+
//# debugId=3C9958DCA4DDE01364756E2164756E21
|