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/agent-helpers.js
CHANGED
|
@@ -69,30 +69,21 @@ function shouldSubstituteVaultToolInput(toolName) {
|
|
|
69
69
|
const leaf = leafToolName(toolName);
|
|
70
70
|
return leaf.startsWith("browser_") || DIRECT_VAULT_EXECUTION_TOOLS.has(leaf);
|
|
71
71
|
}
|
|
72
|
-
function
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
const lower = value.toLowerCase();
|
|
79
|
-
if (SENSITIVE_RUNTIME_NAMES.some((name) => lower.includes(name)))
|
|
80
|
-
return true;
|
|
81
|
-
return value.startsWith("/") && host.isSensitivePath(value);
|
|
82
|
-
}
|
|
83
|
-
if (Array.isArray(value))
|
|
84
|
-
return value.some(referencesRuntimeSecretStorage);
|
|
85
|
-
if (value && typeof value === "object") {
|
|
86
|
-
return Object.values(value).some(referencesRuntimeSecretStorage);
|
|
87
|
-
}
|
|
88
|
-
return false;
|
|
72
|
+
function referencesRuntimeSecretStorage(value) {
|
|
73
|
+
if (typeof value === "string") {
|
|
74
|
+
const lower = value.toLowerCase();
|
|
75
|
+
if (SENSITIVE_RUNTIME_NAMES.some((name) => lower.includes(name)))
|
|
76
|
+
return true;
|
|
77
|
+
return value.startsWith("/") && isSensitivePath(value);
|
|
89
78
|
}
|
|
90
|
-
|
|
91
|
-
return
|
|
79
|
+
if (Array.isArray(value))
|
|
80
|
+
return value.some(referencesRuntimeSecretStorage);
|
|
81
|
+
if (value && typeof value === "object") {
|
|
82
|
+
return Object.values(value).some(referencesRuntimeSecretStorage);
|
|
92
83
|
}
|
|
93
|
-
return
|
|
84
|
+
return false;
|
|
94
85
|
}
|
|
95
|
-
var SENSITIVE_RUNTIME_NAMES, DIRECT_VAULT_EXECUTION_TOOLS
|
|
86
|
+
var SENSITIVE_RUNTIME_NAMES, DIRECT_VAULT_EXECUTION_TOOLS;
|
|
96
87
|
var init_vault_tool_policy = __esm(() => {
|
|
97
88
|
init_sensitive_path();
|
|
98
89
|
SENSITIVE_RUNTIME_NAMES = [
|
|
@@ -102,13 +93,6 @@ var init_vault_tool_policy = __esm(() => {
|
|
|
102
93
|
"sessions.db"
|
|
103
94
|
];
|
|
104
95
|
DIRECT_VAULT_EXECUTION_TOOLS = new Set(["Bash", "WebFetch"]);
|
|
105
|
-
defaultVaultToolPolicy = createVaultToolPolicy({
|
|
106
|
-
isSensitivePath,
|
|
107
|
-
valueReferencesVaultKey: () => false
|
|
108
|
-
});
|
|
109
|
-
isVaultBrokerTool = defaultVaultToolPolicy.isVaultBrokerTool;
|
|
110
|
-
referencesRuntimeSecretStorage = defaultVaultToolPolicy.referencesRuntimeSecretStorage;
|
|
111
|
-
shouldRedirectVaultTool = defaultVaultToolPolicy.shouldRedirectVaultTool;
|
|
112
96
|
});
|
|
113
97
|
|
|
114
98
|
// ../../packages/core/src/platform/config-helpers.ts
|
|
@@ -1870,7 +1854,6 @@ var init_execution_host = __esm(async () => {
|
|
|
1870
1854
|
redactVaultSecrets,
|
|
1871
1855
|
substituteVaultSecrets: (userId, value) => vaultSubstituteDetailed(userId, value).text,
|
|
1872
1856
|
referencesRuntimeSecretStorage,
|
|
1873
|
-
shouldRedirectVaultTool,
|
|
1874
1857
|
claudeCodeExecutablePath: () => CLAUDE_EXECUTABLE,
|
|
1875
1858
|
codexAuthFilePath
|
|
1876
1859
|
};
|
|
@@ -2429,7 +2412,7 @@ var init_claude_registry = __esm(() => {
|
|
|
2429
2412
|
});
|
|
2430
2413
|
|
|
2431
2414
|
// ../../packages/core/src/version.ts
|
|
2432
|
-
var NEGOTIUM_VERSION = "0.
|
|
2415
|
+
var NEGOTIUM_VERSION = "0.4.0";
|
|
2433
2416
|
|
|
2434
2417
|
// ../../packages/core/src/agents/codex-native-multi-agent.ts
|
|
2435
2418
|
import { spawn as spawn2 } from "child_process";
|
|
@@ -4594,9 +4577,163 @@ var init_codex_tree_kill = __esm(() => {
|
|
|
4594
4577
|
killOwnedCodexTreesForShutdown = manager.killOwnedTreesForShutdown;
|
|
4595
4578
|
});
|
|
4596
4579
|
|
|
4580
|
+
// ../../packages/core/src/agents/codex-vault-hook-bridge.ts
|
|
4581
|
+
import { randomBytes as randomBytes5 } from "crypto";
|
|
4582
|
+
import { existsSync as existsSync11 } from "fs";
|
|
4583
|
+
import { chmod, mkdtemp, rm, writeFile } from "fs/promises";
|
|
4584
|
+
import { createServer } from "net";
|
|
4585
|
+
import { tmpdir as tmpdir2 } from "os";
|
|
4586
|
+
import { dirname as dirname9, join as join12, resolve as resolve7 } from "path";
|
|
4587
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
4588
|
+
function evaluateCodexVaultPreToolUse(input, userId, operations) {
|
|
4589
|
+
if (operations.referencesSensitiveStorage(input.tool_input)) {
|
|
4590
|
+
return {
|
|
4591
|
+
hookSpecificOutput: {
|
|
4592
|
+
hookEventName: "PreToolUse",
|
|
4593
|
+
permissionDecision: "deny",
|
|
4594
|
+
permissionDecisionReason: SENSITIVE_STORAGE_DENIAL
|
|
4595
|
+
}
|
|
4596
|
+
};
|
|
4597
|
+
}
|
|
4598
|
+
if (!shouldSubstituteVaultToolInput(input.tool_name))
|
|
4599
|
+
return {};
|
|
4600
|
+
const updatedInput = deepMapStrings(input.tool_input, (value) => operations.substitute(userId, value));
|
|
4601
|
+
if (JSON.stringify(updatedInput) === JSON.stringify(input.tool_input))
|
|
4602
|
+
return {};
|
|
4603
|
+
return {
|
|
4604
|
+
hookSpecificOutput: {
|
|
4605
|
+
hookEventName: "PreToolUse",
|
|
4606
|
+
permissionDecision: "allow",
|
|
4607
|
+
updatedInput
|
|
4608
|
+
}
|
|
4609
|
+
};
|
|
4610
|
+
}
|
|
4611
|
+
function shellQuote(value) {
|
|
4612
|
+
return `'${value.replaceAll("'", `'"'"'`)}'`;
|
|
4613
|
+
}
|
|
4614
|
+
function hookClientPath() {
|
|
4615
|
+
const moduleDir = dirname9(fileURLToPath2(import.meta.url));
|
|
4616
|
+
const adjacent = resolve7(moduleDir, "codex-vault-hook.mjs");
|
|
4617
|
+
if (existsSync11(adjacent))
|
|
4618
|
+
return adjacent;
|
|
4619
|
+
const packaged = resolve7(moduleDir, "runtime/src/agents/codex-vault-hook.mjs");
|
|
4620
|
+
if (existsSync11(packaged))
|
|
4621
|
+
return packaged;
|
|
4622
|
+
throw new Error("Codex Vault hook client is missing from this installation");
|
|
4623
|
+
}
|
|
4624
|
+
function privateCodexWrapper(codexScript) {
|
|
4625
|
+
return [
|
|
4626
|
+
"#!/bin/sh",
|
|
4627
|
+
'if [ "$1" = "exec" ]; then',
|
|
4628
|
+
" shift",
|
|
4629
|
+
` exec ${shellQuote(process.execPath)} ${shellQuote(codexScript)} exec --dangerously-bypass-hook-trust "$@"`,
|
|
4630
|
+
"fi",
|
|
4631
|
+
`exec ${shellQuote(process.execPath)} ${shellQuote(codexScript)} "$@"`,
|
|
4632
|
+
""
|
|
4633
|
+
].join(`
|
|
4634
|
+
`);
|
|
4635
|
+
}
|
|
4636
|
+
async function createCodexVaultHookBridge(userId) {
|
|
4637
|
+
const root = await mkdtemp(join12(tmpdir2(), "negotium-codex-vault-"));
|
|
4638
|
+
await chmod(root, 448);
|
|
4639
|
+
const socketPath = join12(root, "hook.sock");
|
|
4640
|
+
const wrapperPath = join12(root, "codex-with-hooks");
|
|
4641
|
+
const token = randomBytes5(32).toString("hex");
|
|
4642
|
+
const connections = new Set;
|
|
4643
|
+
const server = createServer((socket) => {
|
|
4644
|
+
connections.add(socket);
|
|
4645
|
+
socket.once("close", () => connections.delete(socket));
|
|
4646
|
+
socket.setEncoding("utf8");
|
|
4647
|
+
let request = "";
|
|
4648
|
+
let handled = false;
|
|
4649
|
+
const handleRequest = () => {
|
|
4650
|
+
if (handled)
|
|
4651
|
+
return;
|
|
4652
|
+
handled = true;
|
|
4653
|
+
try {
|
|
4654
|
+
const parsed = JSON.parse(request.trimEnd());
|
|
4655
|
+
if (parsed.token !== token)
|
|
4656
|
+
throw new Error("invalid hook capability");
|
|
4657
|
+
if (!parsed.input || typeof parsed.input !== "object" || typeof parsed.input.tool_name !== "string") {
|
|
4658
|
+
throw new Error("invalid PreToolUse payload");
|
|
4659
|
+
}
|
|
4660
|
+
const output = evaluateCodexVaultPreToolUse(parsed.input, userId, {
|
|
4661
|
+
referencesSensitiveStorage: referencesHostedSecretStorage,
|
|
4662
|
+
substitute: substituteHostedSecrets
|
|
4663
|
+
});
|
|
4664
|
+
socket.end(JSON.stringify({ ok: true, output }));
|
|
4665
|
+
} catch (error) {
|
|
4666
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
4667
|
+
socket.end(JSON.stringify({ ok: false, error: message }));
|
|
4668
|
+
}
|
|
4669
|
+
};
|
|
4670
|
+
socket.on("data", (chunk) => {
|
|
4671
|
+
request += chunk;
|
|
4672
|
+
if (Buffer.byteLength(request) > MAX_HOOK_REQUEST_BYTES)
|
|
4673
|
+
socket.destroy();
|
|
4674
|
+
else if (request.endsWith(`
|
|
4675
|
+
`))
|
|
4676
|
+
handleRequest();
|
|
4677
|
+
});
|
|
4678
|
+
socket.on("end", handleRequest);
|
|
4679
|
+
});
|
|
4680
|
+
try {
|
|
4681
|
+
await new Promise((resolveListen, reject) => {
|
|
4682
|
+
server.once("error", reject);
|
|
4683
|
+
server.listen(socketPath, () => {
|
|
4684
|
+
server.off("error", reject);
|
|
4685
|
+
resolveListen();
|
|
4686
|
+
});
|
|
4687
|
+
});
|
|
4688
|
+
await chmod(socketPath, 384);
|
|
4689
|
+
await writeFile(wrapperPath, privateCodexWrapper(codexCliScriptPath()), { mode: 448 });
|
|
4690
|
+
const command = [
|
|
4691
|
+
shellQuote(process.execPath),
|
|
4692
|
+
shellQuote(hookClientPath()),
|
|
4693
|
+
shellQuote(socketPath),
|
|
4694
|
+
shellQuote(token)
|
|
4695
|
+
].join(" ");
|
|
4696
|
+
return {
|
|
4697
|
+
codexPathOverride: wrapperPath,
|
|
4698
|
+
hooks: {
|
|
4699
|
+
PreToolUse: [
|
|
4700
|
+
{
|
|
4701
|
+
matcher: "*",
|
|
4702
|
+
hooks: [
|
|
4703
|
+
{
|
|
4704
|
+
type: "command",
|
|
4705
|
+
command,
|
|
4706
|
+
timeout: 30,
|
|
4707
|
+
statusMessage: "Resolving Vault placeholders"
|
|
4708
|
+
}
|
|
4709
|
+
]
|
|
4710
|
+
}
|
|
4711
|
+
]
|
|
4712
|
+
},
|
|
4713
|
+
async close() {
|
|
4714
|
+
for (const socket of connections)
|
|
4715
|
+
socket.destroy();
|
|
4716
|
+
await new Promise((resolveClose) => server.close(() => resolveClose()));
|
|
4717
|
+
await rm(root, { recursive: true, force: true });
|
|
4718
|
+
}
|
|
4719
|
+
};
|
|
4720
|
+
} catch (error) {
|
|
4721
|
+
server.close();
|
|
4722
|
+
await rm(root, { recursive: true, force: true });
|
|
4723
|
+
throw error;
|
|
4724
|
+
}
|
|
4725
|
+
}
|
|
4726
|
+
var MAX_HOOK_REQUEST_BYTES, SENSITIVE_STORAGE_DENIAL = "Runtime secret storage access is not permitted";
|
|
4727
|
+
var init_codex_vault_hook_bridge = __esm(async () => {
|
|
4728
|
+
init_codex_native_multi_agent();
|
|
4729
|
+
await init_execution_host();
|
|
4730
|
+
init_vault_tool_policy();
|
|
4731
|
+
MAX_HOOK_REQUEST_BYTES = 1024 * 1024;
|
|
4732
|
+
});
|
|
4733
|
+
|
|
4597
4734
|
// ../../packages/core/src/agents/tool-format.ts
|
|
4598
4735
|
import { readFileSync as readFileSync10, statSync as statSync4 } from "fs";
|
|
4599
|
-
import { isAbsolute, resolve as
|
|
4736
|
+
import { isAbsolute, resolve as resolve8 } from "path";
|
|
4600
4737
|
import { diffLines as computeLineDiff } from "diff";
|
|
4601
4738
|
function summarizeDisplayText(value) {
|
|
4602
4739
|
const normalized = value.replace(/\s+/g, " ").trim();
|
|
@@ -4920,7 +5057,7 @@ function sourceStartLine(input, before, after, cwd) {
|
|
|
4920
5057
|
const rawPath = input.file_path ?? input.path;
|
|
4921
5058
|
if (typeof rawPath !== "string" || !rawPath.trim())
|
|
4922
5059
|
return 1;
|
|
4923
|
-
const path = isAbsolute(rawPath) ? rawPath :
|
|
5060
|
+
const path = isAbsolute(rawPath) ? rawPath : resolve8(cwd ?? process.cwd(), rawPath);
|
|
4924
5061
|
try {
|
|
4925
5062
|
if (statSync4(path).size > TOOL_DIFF_SOURCE_MAX_BYTES)
|
|
4926
5063
|
return 1;
|
|
@@ -5118,9 +5255,9 @@ __export(exports_codex_provider, {
|
|
|
5118
5255
|
codexProvider: () => codexProvider
|
|
5119
5256
|
});
|
|
5120
5257
|
import { execFileSync as execFileSync4 } from "child_process";
|
|
5121
|
-
import { existsSync as
|
|
5258
|
+
import { existsSync as existsSync12, readFileSync as readFileSync11, realpathSync as realpathSync3, statSync as statSync5 } from "fs";
|
|
5122
5259
|
import { homedir as homedir6 } from "os";
|
|
5123
|
-
import { dirname as
|
|
5260
|
+
import { dirname as dirname10, isAbsolute as isAbsolute2, join as join13, relative, resolve as resolve9 } from "path";
|
|
5124
5261
|
import { Codex } from "@openai/codex-sdk";
|
|
5125
5262
|
function sameCodexUsage(usage, total) {
|
|
5126
5263
|
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;
|
|
@@ -5148,8 +5285,8 @@ function codexMcpServerName(name) {
|
|
|
5148
5285
|
return CODEX_MCP_SERVER_NAME_OVERRIDES[name] ?? name;
|
|
5149
5286
|
}
|
|
5150
5287
|
function globalCodexMcpServerNames(authFilePath) {
|
|
5151
|
-
const configPath =
|
|
5152
|
-
if (!
|
|
5288
|
+
const configPath = join13(dirname10(authFilePath), "config.toml");
|
|
5289
|
+
if (!existsSync12(configPath))
|
|
5153
5290
|
return [];
|
|
5154
5291
|
try {
|
|
5155
5292
|
const names = new Set;
|
|
@@ -5244,13 +5381,13 @@ function summarizeMcpToolCallResult(item) {
|
|
|
5244
5381
|
}
|
|
5245
5382
|
function canonicalPath(path) {
|
|
5246
5383
|
try {
|
|
5247
|
-
return realpathSync3(
|
|
5384
|
+
return realpathSync3(resolve9(path));
|
|
5248
5385
|
} catch {
|
|
5249
|
-
return
|
|
5386
|
+
return resolve9(path);
|
|
5250
5387
|
}
|
|
5251
5388
|
}
|
|
5252
5389
|
function textFile(path, maxBytes = CODEX_DIFF_FILE_LIMIT) {
|
|
5253
|
-
if (!
|
|
5390
|
+
if (!existsSync12(path))
|
|
5254
5391
|
return null;
|
|
5255
5392
|
try {
|
|
5256
5393
|
const byteLimit = Math.min(CODEX_DIFF_FILE_LIMIT, Math.max(0, maxBytes));
|
|
@@ -5290,7 +5427,7 @@ class CodexFilePreviewTracker {
|
|
|
5290
5427
|
const code = record.slice(0, 2);
|
|
5291
5428
|
const path = record.slice(3);
|
|
5292
5429
|
const remainingBytes = CODEX_DIFF_BASELINE_BYTE_LIMIT - loadedBytes;
|
|
5293
|
-
const content = loadedFiles < CODEX_DIFF_BASELINE_FILE_LIMIT && remainingBytes > 0 ? textFile(
|
|
5430
|
+
const content = loadedFiles < CODEX_DIFF_BASELINE_FILE_LIMIT && remainingBytes > 0 ? textFile(resolve9(this.#root, path), remainingBytes) : undefined;
|
|
5294
5431
|
this.#baseline.set(path, content);
|
|
5295
5432
|
if (typeof content === "string") {
|
|
5296
5433
|
loadedFiles += 1;
|
|
@@ -5303,7 +5440,7 @@ class CodexFilePreviewTracker {
|
|
|
5303
5440
|
preview(path, succeeded) {
|
|
5304
5441
|
if (!this.#root || !this.#baselineAvailable || !succeeded)
|
|
5305
5442
|
return {};
|
|
5306
|
-
const absolute = canonicalPath(isAbsolute2(path) ? path :
|
|
5443
|
+
const absolute = canonicalPath(isAbsolute2(path) ? path : resolve9(this.#cwd, path));
|
|
5307
5444
|
const relativePath = relative(this.#root, absolute);
|
|
5308
5445
|
if (!relativePath || relativePath.startsWith("..") || isAbsolute2(relativePath))
|
|
5309
5446
|
return {};
|
|
@@ -5338,7 +5475,7 @@ class CodexFilePreviewTracker {
|
|
|
5338
5475
|
}
|
|
5339
5476
|
}
|
|
5340
5477
|
async function fileChangeEvents(item, previews, cwd, threadId, consumedPatchCallIds) {
|
|
5341
|
-
const expectedPaths = item.changes.map((change) => isAbsolute2(change.path) ? change.path :
|
|
5478
|
+
const expectedPaths = item.changes.map((change) => isAbsolute2(change.path) ? change.path : resolve9(cwd, change.path));
|
|
5342
5479
|
let nativePreview;
|
|
5343
5480
|
if (threadId && item.status === "completed") {
|
|
5344
5481
|
await new Promise((resolveDelay) => setTimeout(resolveDelay, 20));
|
|
@@ -5462,7 +5599,7 @@ async function* codexProvider(opts) {
|
|
|
5462
5599
|
const filePreviews = new CodexFilePreviewTracker(opts.cwd);
|
|
5463
5600
|
const consumedPatchCallIds = new Set(opts.sessionId ? readCodexPatchCallIds(opts.sessionId) : []);
|
|
5464
5601
|
const codexAuthPath = hostedCodexAuthFilePath();
|
|
5465
|
-
if (!
|
|
5602
|
+
if (!existsSync12(codexAuthPath)) {
|
|
5466
5603
|
yield {
|
|
5467
5604
|
type: "error",
|
|
5468
5605
|
content: `Codex auth file not found at ${codexAuthPath}. Run \`codex login\` to authenticate.`
|
|
@@ -5501,21 +5638,30 @@ async function* codexProvider(opts) {
|
|
|
5501
5638
|
model: opts.model ?? "(sdk default)",
|
|
5502
5639
|
effort: opts.effort ?? "(off)",
|
|
5503
5640
|
cwd: opts.cwd,
|
|
5504
|
-
cwdExists:
|
|
5641
|
+
cwdExists: existsSync12(opts.cwd),
|
|
5505
5642
|
resume: Boolean(opts.sessionId),
|
|
5506
5643
|
mcpServerCount: Object.keys(codexMcpServers).length
|
|
5507
5644
|
}, "codexProvider: starting turn");
|
|
5508
5645
|
const hostedCodexHome = hostedCodexHomePath();
|
|
5509
|
-
const inheritedCodexHome = process.env.CODEX_HOME ||
|
|
5510
|
-
const codexEnvironment = scopedBrowserCapability ||
|
|
5646
|
+
const inheritedCodexHome = process.env.CODEX_HOME || join13(homedir6(), ".codex");
|
|
5647
|
+
const codexEnvironment = scopedBrowserCapability || resolve9(hostedCodexHome) !== resolve9(inheritedCodexHome) ? {
|
|
5511
5648
|
...Object.fromEntries(Object.entries(process.env).filter((entry) => typeof entry[1] === "string")),
|
|
5512
5649
|
CODEX_HOME: hostedCodexHome,
|
|
5513
5650
|
...scopedBrowserCapability ? { [CODEX_BROWSER_CAPABILITY_ENV]: scopedBrowserCapability } : {}
|
|
5514
5651
|
} : undefined;
|
|
5652
|
+
let vaultHook;
|
|
5653
|
+
try {
|
|
5654
|
+
vaultHook = await createCodexVaultHookBridge(opts.vaultUserId ?? opts.userId ?? "");
|
|
5655
|
+
} catch (err) {
|
|
5656
|
+
yield { type: "error", content: `Failed to initialize Codex Vault hooks: ${errMsg(err)}` };
|
|
5657
|
+
return;
|
|
5658
|
+
}
|
|
5515
5659
|
const codex = new Codex({
|
|
5660
|
+
codexPathOverride: vaultHook.codexPathOverride,
|
|
5516
5661
|
...codexEnvironment ? { env: codexEnvironment } : {},
|
|
5517
5662
|
config: {
|
|
5518
|
-
features: { multi_agent: false, multi_agent_v2: false, enable_fanout: false },
|
|
5663
|
+
features: { hooks: true, multi_agent: false, multi_agent_v2: false, enable_fanout: false },
|
|
5664
|
+
hooks: vaultHook.hooks,
|
|
5519
5665
|
model_catalog_json: codexModelCatalogPath,
|
|
5520
5666
|
mcp_servers: codexMcpServers,
|
|
5521
5667
|
...opts.toolPolicy ? { sandbox_permissions: [] } : {}
|
|
@@ -5619,7 +5765,7 @@ async function* codexProvider(opts) {
|
|
|
5619
5765
|
if (!item)
|
|
5620
5766
|
break;
|
|
5621
5767
|
if (item.type === "command_execution") {
|
|
5622
|
-
const command = String(item.command ?? "");
|
|
5768
|
+
const command = redactHostedSecrets(opts.vaultUserId ?? opts.userId ?? "", String(item.command ?? ""));
|
|
5623
5769
|
yield {
|
|
5624
5770
|
type: "tool_use",
|
|
5625
5771
|
name: "Bash",
|
|
@@ -5627,10 +5773,11 @@ async function* codexProvider(opts) {
|
|
|
5627
5773
|
toolUseId: String(item.id ?? "")
|
|
5628
5774
|
};
|
|
5629
5775
|
} else if (item.type === "mcp_tool_call") {
|
|
5776
|
+
const input = item.arguments && typeof item.arguments === "object" ? item.arguments : {};
|
|
5630
5777
|
yield {
|
|
5631
5778
|
type: "tool_use",
|
|
5632
5779
|
name: String(item.tool ?? "unknown"),
|
|
5633
|
-
input:
|
|
5780
|
+
input: deepMapStrings(input, (value) => redactHostedSecrets(opts.vaultUserId ?? opts.userId ?? "", value)),
|
|
5634
5781
|
toolUseId: String(item.id ?? "")
|
|
5635
5782
|
};
|
|
5636
5783
|
}
|
|
@@ -5673,7 +5820,7 @@ async function* codexProvider(opts) {
|
|
|
5673
5820
|
yield {
|
|
5674
5821
|
type: "tool_result",
|
|
5675
5822
|
toolUseId: String(item.id ?? ""),
|
|
5676
|
-
content: summarizeMcpToolCallResult(item),
|
|
5823
|
+
content: redactHostedSecrets(opts.vaultUserId ?? opts.userId ?? "", summarizeMcpToolCallResult(item)),
|
|
5677
5824
|
...isError ? { isError: true } : {}
|
|
5678
5825
|
};
|
|
5679
5826
|
} else if (item.type === "command_execution") {
|
|
@@ -5681,7 +5828,7 @@ async function* codexProvider(opts) {
|
|
|
5681
5828
|
yield {
|
|
5682
5829
|
type: "tool_result",
|
|
5683
5830
|
toolUseId: String(item.id ?? ""),
|
|
5684
|
-
content: String(item.aggregated_output ?? "").slice(0, 200),
|
|
5831
|
+
content: redactHostedSecrets(opts.vaultUserId ?? opts.userId ?? "", String(item.aggregated_output ?? "").slice(0, 200)),
|
|
5685
5832
|
...isError ? { isError: true } : {}
|
|
5686
5833
|
};
|
|
5687
5834
|
} else if (item.type === "file_change") {
|
|
@@ -5778,12 +5925,14 @@ async function* codexProvider(opts) {
|
|
|
5778
5925
|
abortSignal?.removeEventListener("abort", onAbortKill);
|
|
5779
5926
|
if (trackedPids.pids.length > 0)
|
|
5780
5927
|
unregisterOwnedCodexPids(trackedPids.pids);
|
|
5928
|
+
await vaultHook.close();
|
|
5781
5929
|
}
|
|
5782
5930
|
}
|
|
5783
5931
|
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;
|
|
5784
5932
|
var init_codex_provider = __esm(async () => {
|
|
5785
5933
|
init_codex_native_multi_agent();
|
|
5786
5934
|
init_codex_tree_kill();
|
|
5935
|
+
await init_codex_vault_hook_bridge();
|
|
5787
5936
|
await init_execution_host();
|
|
5788
5937
|
await init_codex();
|
|
5789
5938
|
init_tool_format();
|
|
@@ -5811,7 +5960,7 @@ __export(exports_maestro_provider, {
|
|
|
5811
5960
|
buildMaestroToolHooks: () => buildMaestroToolHooks,
|
|
5812
5961
|
buildMaestroDisallowedTools: () => buildMaestroDisallowedTools
|
|
5813
5962
|
});
|
|
5814
|
-
import { resolve as
|
|
5963
|
+
import { resolve as resolve10 } from "path";
|
|
5815
5964
|
import { maestroProvider as sdkMaestroProvider, setMcpResolver } from "maestro-agent-sdk";
|
|
5816
5965
|
function buildMaestroDisallowedTools(callerDisallowedTools = [], toolPolicy) {
|
|
5817
5966
|
return [
|
|
@@ -5945,13 +6094,13 @@ var init_maestro_provider = __esm(async () => {
|
|
|
5945
6094
|
"ToolSearch",
|
|
5946
6095
|
...DEFAULT_MAESTRO_DISALLOWED_TOOLS
|
|
5947
6096
|
];
|
|
5948
|
-
MAESTRO_TOOL_OUTPUT_DIR =
|
|
6097
|
+
MAESTRO_TOOL_OUTPUT_DIR = resolve10(RUN_DIR, "maestro-tool-outputs");
|
|
5949
6098
|
});
|
|
5950
6099
|
|
|
5951
6100
|
// ../../packages/core/src/agents/index.ts
|
|
5952
|
-
import { existsSync as
|
|
6101
|
+
import { existsSync as existsSync13 } from "fs";
|
|
5953
6102
|
import { homedir as homedir7 } from "os";
|
|
5954
|
-
import { join as
|
|
6103
|
+
import { join as join14 } from "path";
|
|
5955
6104
|
async function* dispatchAgent(opts) {
|
|
5956
6105
|
switch (opts.agent) {
|
|
5957
6106
|
case "claude": {
|
|
@@ -5985,11 +6134,11 @@ async function resolveSessionFileMissing(agent, sessionId, cwd) {
|
|
|
5985
6134
|
switch (agent) {
|
|
5986
6135
|
case "claude": {
|
|
5987
6136
|
const encodedCwd = encodeClaudeCwd(cwd);
|
|
5988
|
-
const path =
|
|
5989
|
-
return !
|
|
6137
|
+
const path = join14(homedir7(), ".claude", "projects", encodedCwd, `${sessionId}.jsonl`);
|
|
6138
|
+
return !existsSync13(path);
|
|
5990
6139
|
}
|
|
5991
6140
|
case "codex": {
|
|
5992
|
-
const sessionsDir =
|
|
6141
|
+
const sessionsDir = join14(hostedCodexHomePath(), "sessions");
|
|
5993
6142
|
const glob = new Bun.Glob(`**/rollout-*-${sessionId}.jsonl`);
|
|
5994
6143
|
for await (const _rel of glob.scan({ cwd: sessionsDir, onlyFiles: true })) {
|
|
5995
6144
|
return false;
|
|
@@ -5998,7 +6147,7 @@ async function resolveSessionFileMissing(agent, sessionId, cwd) {
|
|
|
5998
6147
|
}
|
|
5999
6148
|
case "maestro": {
|
|
6000
6149
|
const { hasActiveMaestroSession, maestroSessionPath: maestroSessionPath2 } = await import("maestro-agent-sdk");
|
|
6001
|
-
return !
|
|
6150
|
+
return !existsSync13(maestroSessionPath2(sessionId)) && !hasActiveMaestroSession(sessionId);
|
|
6002
6151
|
}
|
|
6003
6152
|
default: {
|
|
6004
6153
|
const _exhaustive = agent;
|
|
@@ -6526,9 +6675,9 @@ var init_model_catalog = __esm(() => {
|
|
|
6526
6675
|
|
|
6527
6676
|
// ../../packages/core/src/prompts/builders.ts
|
|
6528
6677
|
import { readFileSync as readFileSync12 } from "fs";
|
|
6529
|
-
import { resolve as
|
|
6678
|
+
import { resolve as resolve11 } from "path";
|
|
6530
6679
|
function loadPrompt(filename, dir = SESSIONS_DIR) {
|
|
6531
|
-
const raw = readFileSync12(
|
|
6680
|
+
const raw = readFileSync12(resolve11(dir, filename), "utf-8");
|
|
6532
6681
|
return raw.replace(/\{\{RESOURCES_DIR\}\}/g, RESOURCES_DIR);
|
|
6533
6682
|
}
|
|
6534
6683
|
function replaceVars(template, vars) {
|
|
@@ -6577,7 +6726,7 @@ function visualDesignGuide() {
|
|
|
6577
6726
|
return _visualDesignGuide;
|
|
6578
6727
|
}
|
|
6579
6728
|
function loadAgentPrompt(filename) {
|
|
6580
|
-
const raw = readFileSync12(
|
|
6729
|
+
const raw = readFileSync12(resolve11(AGENTS_PROMPTS_DIR, filename), "utf-8");
|
|
6581
6730
|
const match = raw.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
6582
6731
|
if (!match)
|
|
6583
6732
|
throw new Error(`Agent prompt ${filename} is missing frontmatter`);
|
|
@@ -6892,8 +7041,8 @@ var init_builders = __esm(() => {
|
|
|
6892
7041
|
init_model_catalog();
|
|
6893
7042
|
init_config();
|
|
6894
7043
|
init_logger();
|
|
6895
|
-
PROMPTS_DIR =
|
|
6896
|
-
SESSIONS_DIR =
|
|
7044
|
+
PROMPTS_DIR = resolve11(PROJECT_ROOT, "src/prompts");
|
|
7045
|
+
SESSIONS_DIR = resolve11(PROMPTS_DIR, "sessions");
|
|
6897
7046
|
defaultPromptBuilders = createPromptBuilders();
|
|
6898
7047
|
buildTopicSystemPrompt = defaultPromptBuilders.buildTopicSystemPrompt;
|
|
6899
7048
|
buildChannelSystemPrompt = defaultPromptBuilders.buildChannelSystemPrompt;
|
|
@@ -7244,9 +7393,9 @@ var init_api_topic_brief = __esm(async () => {
|
|
|
7244
7393
|
});
|
|
7245
7394
|
|
|
7246
7395
|
// ../../packages/core/src/storage/wiki.ts
|
|
7247
|
-
import { basename as basename2, dirname as
|
|
7396
|
+
import { basename as basename2, dirname as dirname11, join as join15 } from "path";
|
|
7248
7397
|
function getSharedWikiDir(workspaceDir = resolveStorageWorkspaceDir()) {
|
|
7249
|
-
return workspaceDir === resolveStorageWorkspaceDir() ? resolveStorageSharedWikiDir() :
|
|
7398
|
+
return workspaceDir === resolveStorageWorkspaceDir() ? resolveStorageSharedWikiDir() : join15(workspaceDir, "wiki");
|
|
7250
7399
|
}
|
|
7251
7400
|
var init_wiki = __esm(async () => {
|
|
7252
7401
|
await init_storage_host();
|
|
@@ -8080,8 +8229,8 @@ var init_personal_general = __esm(async () => {
|
|
|
8080
8229
|
|
|
8081
8230
|
// ../../packages/core/src/agents/archiver.ts
|
|
8082
8231
|
import { randomUUID as randomUUID6 } from "crypto";
|
|
8083
|
-
import { existsSync as
|
|
8084
|
-
import { join as
|
|
8232
|
+
import { existsSync as existsSync14, readdirSync as readdirSync2, readFileSync as readFileSync13, statSync as statSync6 } from "fs";
|
|
8233
|
+
import { join as join16 } from "path";
|
|
8085
8234
|
function resolveMemoryLanguage() {
|
|
8086
8235
|
const override = process.env.NEGOTIUM_MEMORY_LANG?.trim();
|
|
8087
8236
|
return override && override.length > 0 ? override : resolveOutputLanguage();
|
|
@@ -8332,10 +8481,10 @@ function distillOneLine(summaryMd) {
|
|
|
8332
8481
|
return "";
|
|
8333
8482
|
}
|
|
8334
8483
|
function findSummaryFile(storage, topicTitle, date, sinceMs, topicId) {
|
|
8335
|
-
const dir =
|
|
8484
|
+
const dir = join16(storage.getWikiDir(), "summaries");
|
|
8336
8485
|
if (!storage.fileExists(dir))
|
|
8337
8486
|
return null;
|
|
8338
|
-
const predicted =
|
|
8487
|
+
const predicted = join16(dir, wikiSummaryFilename(date, topicTitle, topicId));
|
|
8339
8488
|
if (storage.fileExists(predicted) && storage.fileModifiedAt(predicted) >= sinceMs)
|
|
8340
8489
|
return predicted;
|
|
8341
8490
|
let best = null;
|
|
@@ -8343,7 +8492,7 @@ function findSummaryFile(storage, topicTitle, date, sinceMs, topicId) {
|
|
|
8343
8492
|
if (!f.startsWith(`${date}-`) || !isTopicSummaryFile(f, topicId ?? "", topicTitle)) {
|
|
8344
8493
|
continue;
|
|
8345
8494
|
}
|
|
8346
|
-
const p =
|
|
8495
|
+
const p = join16(dir, f);
|
|
8347
8496
|
try {
|
|
8348
8497
|
const m = storage.fileModifiedAt(p);
|
|
8349
8498
|
if (m >= sinceMs && (!best || m > best.mtime))
|
|
@@ -8424,7 +8573,7 @@ var init_archiver = __esm(async () => {
|
|
|
8424
8573
|
defaultArchiverRuntime = createArchiverRuntime({
|
|
8425
8574
|
storage: {
|
|
8426
8575
|
getWikiDir: getSharedWikiDir,
|
|
8427
|
-
fileExists:
|
|
8576
|
+
fileExists: existsSync14,
|
|
8428
8577
|
listDirectory: readdirSync2,
|
|
8429
8578
|
readTextFile: (path) => readFileSync13(path, "utf-8"),
|
|
8430
8579
|
fileSize: (path) => statSync6(path).size,
|
|
@@ -8469,9 +8618,9 @@ __export(exports_auth_check, {
|
|
|
8469
8618
|
checkAgentAuth: () => checkAgentAuth
|
|
8470
8619
|
});
|
|
8471
8620
|
import { execFileSync as execFileSync5 } from "child_process";
|
|
8472
|
-
import { existsSync as
|
|
8621
|
+
import { existsSync as existsSync15 } from "fs";
|
|
8473
8622
|
import { homedir as homedir8, platform } from "os";
|
|
8474
|
-
import { join as
|
|
8623
|
+
import { join as join17 } from "path";
|
|
8475
8624
|
function hasMaestroCredential(host, key, userId) {
|
|
8476
8625
|
if (userId && host.getVaultValue(userId, key)?.trim())
|
|
8477
8626
|
return true;
|
|
@@ -8491,7 +8640,7 @@ function checkAgentAuth(agent, host = defaultAgentAuthHost, userId) {
|
|
|
8491
8640
|
case "claude": {
|
|
8492
8641
|
if (host.environment.ANTHROPIC_API_KEY)
|
|
8493
8642
|
return { ok: true };
|
|
8494
|
-
const path =
|
|
8643
|
+
const path = join17(host.homeDirectory(), ".claude", ".credentials.json");
|
|
8495
8644
|
if (host.operatingSystem() === "darwin") {
|
|
8496
8645
|
if (host.hasMacOsCredential("Claude Code-credentials") || host.exists(path)) {
|
|
8497
8646
|
return { ok: true };
|
|
@@ -8542,7 +8691,7 @@ var init_auth_check = __esm(async () => {
|
|
|
8542
8691
|
await init_vault();
|
|
8543
8692
|
defaultAgentAuthHost = {
|
|
8544
8693
|
codexAuthFilePath,
|
|
8545
|
-
exists:
|
|
8694
|
+
exists: existsSync15,
|
|
8546
8695
|
environment: process.env,
|
|
8547
8696
|
homeDirectory: homedir8,
|
|
8548
8697
|
operatingSystem: platform,
|
|
@@ -8559,7 +8708,7 @@ var init_auth_check = __esm(async () => {
|
|
|
8559
8708
|
});
|
|
8560
8709
|
|
|
8561
8710
|
// ../../packages/core/src/agents/fork.ts
|
|
8562
|
-
import { existsSync as
|
|
8711
|
+
import { existsSync as existsSync16, unlinkSync as unlinkSync8 } from "fs";
|
|
8563
8712
|
function createAgentForkHelpers(host) {
|
|
8564
8713
|
return {
|
|
8565
8714
|
async forkAgentSession(options) {
|
|
@@ -8596,7 +8745,7 @@ var init_fork = __esm(async () => {
|
|
|
8596
8745
|
init_logger();
|
|
8597
8746
|
defaultForkHelpers = createAgentForkHelpers({
|
|
8598
8747
|
forkSession: (agent, options) => getRegistryOperations(agent).forkSession(options),
|
|
8599
|
-
exists:
|
|
8748
|
+
exists: existsSync16,
|
|
8600
8749
|
unlink: unlinkSync8,
|
|
8601
8750
|
warn: (details, message) => logger.warn(details, message)
|
|
8602
8751
|
});
|
|
@@ -9252,13 +9401,13 @@ function formatTopicArchiveTranscriptRecord(row, topicTitle, index) {
|
|
|
9252
9401
|
|
|
9253
9402
|
// ../../packages/core/src/storage/topic-archive.ts
|
|
9254
9403
|
import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync8 } from "fs";
|
|
9255
|
-
import { join as
|
|
9404
|
+
import { join as join18 } from "path";
|
|
9256
9405
|
function archiveTopicMessages(topicId, topicTitle, options = {}) {
|
|
9257
9406
|
const rows = options.afterRowid !== undefined ? getMessagesForTopicAfterRowid(topicId, options.afterRowid) : getAllMessagesForTopic(topicId);
|
|
9258
9407
|
if (rows.length === 0)
|
|
9259
9408
|
return null;
|
|
9260
9409
|
const safeTopic = sanitizeTopicName(topicTitle, true);
|
|
9261
|
-
const archiveDir =
|
|
9410
|
+
const archiveDir = join18(getSharedWikiDir(), "archive");
|
|
9262
9411
|
mkdirSync10(archiveDir, { recursive: true });
|
|
9263
9412
|
const date = new Date().toISOString().slice(0, 10);
|
|
9264
9413
|
const reasonSuffix = options.reason && options.reason !== "delete" ? `_${options.reason}` : "";
|
|
@@ -9271,7 +9420,7 @@ function archiveTopicMessages(topicId, topicTitle, options = {}) {
|
|
|
9271
9420
|
let path;
|
|
9272
9421
|
while (true) {
|
|
9273
9422
|
filename = `${safeTopic}_${date}${reasonSuffix}${counter === 1 ? "" : `_${counter}`}.jsonl`;
|
|
9274
|
-
path =
|
|
9423
|
+
path = join18(archiveDir, filename);
|
|
9275
9424
|
try {
|
|
9276
9425
|
writeFileSync8(path, body, { flag: "wx" });
|
|
9277
9426
|
break;
|
|
@@ -9316,7 +9465,7 @@ function archiveConversationEvents(topicId, topicTitle, userId, options = {}) {
|
|
|
9316
9465
|
const entries = readRawConversation(userId, topicTitle);
|
|
9317
9466
|
if (entries.length === 0)
|
|
9318
9467
|
return null;
|
|
9319
|
-
const archiveDir =
|
|
9468
|
+
const archiveDir = join18(getSharedWikiDir(), "archive");
|
|
9320
9469
|
mkdirSync10(archiveDir, { recursive: true });
|
|
9321
9470
|
const safeTopic = sanitizeTopicName(topicTitle, true);
|
|
9322
9471
|
const date = new Date().toISOString().slice(0, 10);
|
|
@@ -9344,7 +9493,7 @@ function archiveConversationEvents(topicId, topicTitle, userId, options = {}) {
|
|
|
9344
9493
|
let counter = 1;
|
|
9345
9494
|
while (true) {
|
|
9346
9495
|
const suffix = counter === 1 ? "" : `_${counter}`;
|
|
9347
|
-
const path =
|
|
9496
|
+
const path = join18(archiveDir, `${safeTopic}_${date}${reasonSuffix}_events${suffix}.jsonl`);
|
|
9348
9497
|
try {
|
|
9349
9498
|
writeFileSync8(path, body, { flag: "wx" });
|
|
9350
9499
|
logger.info({ topicId, topicTitle, archive: path, eventCount: entries.length }, "archiveConversationEvents: archived raw conversation events");
|
|
@@ -10255,8 +10404,8 @@ function createAskUserRuntime(host) {
|
|
|
10255
10404
|
return errorResult(`Error: failed to persist ask_user_question: ${error instanceof Error ? error.message : String(error)}`);
|
|
10256
10405
|
}
|
|
10257
10406
|
let resolveAnswer;
|
|
10258
|
-
const promise = new Promise((
|
|
10259
|
-
resolveAnswer =
|
|
10407
|
+
const promise = new Promise((resolve12) => {
|
|
10408
|
+
resolveAnswer = resolve12;
|
|
10260
10409
|
});
|
|
10261
10410
|
pendingAsks.set(message.id, {
|
|
10262
10411
|
topicId: ctx.topicId,
|
|
@@ -10510,11 +10659,11 @@ var init_manager_utils = () => {};
|
|
|
10510
10659
|
// ../../packages/core/src/platform/playwright/browser-processes.ts
|
|
10511
10660
|
import { execFileSync as execFileSync6 } from "child_process";
|
|
10512
10661
|
import { readdirSync as readdirSync3, unlinkSync as unlinkSync10 } from "fs";
|
|
10513
|
-
import { createServer } from "net";
|
|
10514
|
-
import { resolve as
|
|
10662
|
+
import { createServer as createServer2 } from "net";
|
|
10663
|
+
import { resolve as resolve13, sep } from "path";
|
|
10515
10664
|
function isPortInUse(port) {
|
|
10516
10665
|
return new Promise((resolveProbe) => {
|
|
10517
|
-
const server =
|
|
10666
|
+
const server = createServer2();
|
|
10518
10667
|
let settled = false;
|
|
10519
10668
|
const finish = (occupied) => {
|
|
10520
10669
|
if (settled)
|
|
@@ -10544,8 +10693,8 @@ async function reserveAvailableLoopbackPort(minPort, maxPort, reservedPorts, pro
|
|
|
10544
10693
|
return null;
|
|
10545
10694
|
}
|
|
10546
10695
|
function killBrowserProcsForUserDataDir(userDataDir) {
|
|
10547
|
-
const target =
|
|
10548
|
-
const profileRoot =
|
|
10696
|
+
const target = resolve13(userDataDir);
|
|
10697
|
+
const profileRoot = resolve13(BROWSER_PROFILES_DIR);
|
|
10549
10698
|
if (target !== profileRoot && !target.startsWith(`${profileRoot}${sep}`))
|
|
10550
10699
|
return;
|
|
10551
10700
|
let pids;
|
|
@@ -10566,7 +10715,7 @@ function killBrowserProcsForUserDataDir(userDataDir) {
|
|
|
10566
10715
|
stdio: "pipe"
|
|
10567
10716
|
}).toString().trim();
|
|
10568
10717
|
const argDir = extractUserDataDirArg(cmdline);
|
|
10569
|
-
if (!argDir ||
|
|
10718
|
+
if (!argDir || resolve13(argDir) !== target)
|
|
10570
10719
|
continue;
|
|
10571
10720
|
killProcessTreeChildren(pidNum);
|
|
10572
10721
|
process.kill(pidNum, "SIGKILL");
|
|
@@ -10577,13 +10726,13 @@ function killBrowserProcsForUserDataDir(userDataDir) {
|
|
|
10577
10726
|
}
|
|
10578
10727
|
}
|
|
10579
10728
|
function selectOrphanBrowserPids(procs, liveUserDataDirs, profileRoot, selfPid) {
|
|
10580
|
-
const root =
|
|
10581
|
-
const live = new Set([...liveUserDataDirs].map((d) =>
|
|
10729
|
+
const root = resolve13(profileRoot);
|
|
10730
|
+
const live = new Set([...liveUserDataDirs].map((d) => resolve13(d)));
|
|
10582
10731
|
const out = [];
|
|
10583
10732
|
for (const { pid, userDataDir } of procs) {
|
|
10584
10733
|
if (pid === selfPid || !userDataDir)
|
|
10585
10734
|
continue;
|
|
10586
|
-
const dir =
|
|
10735
|
+
const dir = resolve13(userDataDir);
|
|
10587
10736
|
if (dir !== root && !dir.startsWith(`${root}${sep}`))
|
|
10588
10737
|
continue;
|
|
10589
10738
|
if (live.has(dir))
|
|
@@ -10599,7 +10748,7 @@ function reapOrphanBrowsers(liveUserDataDirs) {
|
|
|
10599
10748
|
const daemonLease = getRuntimeProcessLease("node-daemon", Date.now(), Number.POSITIVE_INFINITY);
|
|
10600
10749
|
if (!isBrowserJanitorOwner(daemonLease?.pid ?? null, process.pid))
|
|
10601
10750
|
return;
|
|
10602
|
-
const profileRoot =
|
|
10751
|
+
const profileRoot = resolve13(BROWSER_PROFILES_DIR);
|
|
10603
10752
|
let pids;
|
|
10604
10753
|
try {
|
|
10605
10754
|
pids = execFileSync6("pgrep", ["-f", "--", profileRoot], { stdio: "pipe" }).toString().trim();
|
|
@@ -10638,7 +10787,7 @@ function cleanSingletonFiles(userDataDir) {
|
|
|
10638
10787
|
for (const f of files) {
|
|
10639
10788
|
if (f.startsWith("Singleton")) {
|
|
10640
10789
|
try {
|
|
10641
|
-
unlinkSync10(
|
|
10790
|
+
unlinkSync10(resolve13(userDataDir, f));
|
|
10642
10791
|
logger.info({ file: f, userDataDir }, "Removed stale Singleton file");
|
|
10643
10792
|
} catch (e) {
|
|
10644
10793
|
logger.warn({ err: e, file: f }, "Failed to remove stale Chrome Singleton file");
|
|
@@ -10678,9 +10827,9 @@ var init_browser_processes = __esm(async () => {
|
|
|
10678
10827
|
|
|
10679
10828
|
// ../../packages/core/src/platform/playwright/headed-launch.ts
|
|
10680
10829
|
import { accessSync as accessSync2, constants as constants2 } from "fs";
|
|
10681
|
-
import { delimiter, isAbsolute as isAbsolute4, resolve as
|
|
10830
|
+
import { delimiter, isAbsolute as isAbsolute4, resolve as resolve14 } from "path";
|
|
10682
10831
|
function findExecutableOnPath(command, environment = process.env) {
|
|
10683
|
-
const candidates = isAbsolute4(command) ? [command] : (environment.PATH ?? "").split(delimiter).filter(Boolean).map((directory) =>
|
|
10832
|
+
const candidates = isAbsolute4(command) ? [command] : (environment.PATH ?? "").split(delimiter).filter(Boolean).map((directory) => resolve14(directory, command));
|
|
10684
10833
|
for (const candidate of candidates) {
|
|
10685
10834
|
try {
|
|
10686
10835
|
accessSync2(candidate, constants2.X_OK);
|
|
@@ -10778,11 +10927,11 @@ var init_vault_public = __esm(async () => {
|
|
|
10778
10927
|
});
|
|
10779
10928
|
|
|
10780
10929
|
// ../../packages/core/src/platform/playwright/vault-broker.ts
|
|
10781
|
-
import { randomBytes as
|
|
10930
|
+
import { randomBytes as randomBytes6, timingSafeEqual as timingSafeEqual2 } from "crypto";
|
|
10782
10931
|
import { chmodSync as chmodSync4 } from "fs";
|
|
10783
|
-
import { createServer as
|
|
10784
|
-
import { tmpdir as
|
|
10785
|
-
import { join as
|
|
10932
|
+
import { createServer as createServer3 } from "net";
|
|
10933
|
+
import { tmpdir as tmpdir3 } from "os";
|
|
10934
|
+
import { join as join19 } from "path";
|
|
10786
10935
|
function deepMapStrings2(value, transform) {
|
|
10787
10936
|
if (typeof value === "string")
|
|
10788
10937
|
return transform(value);
|
|
@@ -10868,8 +11017,8 @@ function authorized(actual, expected) {
|
|
|
10868
11017
|
return left.length === right.length && timingSafeEqual2(left, right);
|
|
10869
11018
|
}
|
|
10870
11019
|
async function createBrowserVaultBroker(userId) {
|
|
10871
|
-
const token =
|
|
10872
|
-
const socketPath =
|
|
11020
|
+
const token = randomBytes6(32).toString("hex");
|
|
11021
|
+
const socketPath = join19(process.platform === "win32" ? tmpdir3() : "/tmp", `negotium-browser-vault-${process.pid}-${randomBytes6(8).toString("hex")}.sock`);
|
|
10873
11022
|
const retainedForms = new Map;
|
|
10874
11023
|
const leases = new Map;
|
|
10875
11024
|
const sockets = new Set;
|
|
@@ -10908,7 +11057,7 @@ async function createBrowserVaultBroker(userId) {
|
|
|
10908
11057
|
return result.text;
|
|
10909
11058
|
});
|
|
10910
11059
|
const prepared = prepareInput(request.tool, substituted);
|
|
10911
|
-
const lease =
|
|
11060
|
+
const lease = randomBytes6(24).toString("hex");
|
|
10912
11061
|
leases.set(lease, { boundary: prepared.boundary, createdAt: Date.now() });
|
|
10913
11062
|
return {
|
|
10914
11063
|
id,
|
|
@@ -10940,7 +11089,7 @@ async function createBrowserVaultBroker(userId) {
|
|
|
10940
11089
|
}
|
|
10941
11090
|
return { id, ok: false, error: "unknown operation" };
|
|
10942
11091
|
};
|
|
10943
|
-
const server =
|
|
11092
|
+
const server = createServer3((socket) => {
|
|
10944
11093
|
sockets.add(socket);
|
|
10945
11094
|
let pending = "";
|
|
10946
11095
|
socket.setEncoding("utf8");
|
|
@@ -11068,24 +11217,24 @@ var init_browser_profiles = __esm(async () => {
|
|
|
11068
11217
|
|
|
11069
11218
|
// ../../packages/core/src/platform/playwright/manager.ts
|
|
11070
11219
|
import { execFileSync as execFileSync7, spawn as spawn5 } from "child_process";
|
|
11071
|
-
import { createHash as createHash4, randomBytes as
|
|
11220
|
+
import { createHash as createHash4, randomBytes as randomBytes7, timingSafeEqual as timingSafeEqual3 } from "crypto";
|
|
11072
11221
|
import {
|
|
11073
11222
|
cpSync,
|
|
11074
|
-
existsSync as
|
|
11223
|
+
existsSync as existsSync18,
|
|
11075
11224
|
mkdirSync as mkdirSync11,
|
|
11076
11225
|
readFileSync as readFileSync15,
|
|
11077
11226
|
rmSync as rmSync3,
|
|
11078
11227
|
unlinkSync as unlinkSync11,
|
|
11079
11228
|
writeFileSync as writeFileSync9
|
|
11080
11229
|
} from "fs";
|
|
11081
|
-
import { dirname as
|
|
11230
|
+
import { dirname as dirname12, join as join20, resolve as resolve15 } from "path";
|
|
11082
11231
|
function removeDefaultProfileDataDir(userDataDir) {
|
|
11083
|
-
const root =
|
|
11084
|
-
const target =
|
|
11085
|
-
if (
|
|
11232
|
+
const root = resolve15(BROWSER_PROFILES_DIR);
|
|
11233
|
+
const target = resolve15(userDataDir);
|
|
11234
|
+
if (dirname12(target) !== root) {
|
|
11086
11235
|
throw new Error(`Refusing to delete browser profile outside managed root: ${target}`);
|
|
11087
11236
|
}
|
|
11088
|
-
const existed =
|
|
11237
|
+
const existed = existsSync18(target);
|
|
11089
11238
|
rmSync3(target, { recursive: true, force: true });
|
|
11090
11239
|
return existed;
|
|
11091
11240
|
}
|
|
@@ -11168,14 +11317,14 @@ function portFileName(instanceKey) {
|
|
|
11168
11317
|
function writePortFile(instanceKey, port) {
|
|
11169
11318
|
try {
|
|
11170
11319
|
mkdirSync11(managerHost.portsDir, { recursive: true });
|
|
11171
|
-
writeFileSync9(
|
|
11320
|
+
writeFileSync9(join20(managerHost.portsDir, portFileName(instanceKey)), String(port));
|
|
11172
11321
|
} catch (e) {
|
|
11173
11322
|
logger.warn({ err: e, instanceKey, port }, "Failed to save playwright port file");
|
|
11174
11323
|
}
|
|
11175
11324
|
}
|
|
11176
11325
|
function deletePortFile(instanceKey) {
|
|
11177
11326
|
try {
|
|
11178
|
-
unlinkSync11(
|
|
11327
|
+
unlinkSync11(join20(managerHost.portsDir, portFileName(instanceKey)));
|
|
11179
11328
|
} catch (e) {
|
|
11180
11329
|
if (e.code === "ENOENT")
|
|
11181
11330
|
return;
|
|
@@ -11299,7 +11448,7 @@ function releasePort(port) {
|
|
|
11299
11448
|
usedPorts.delete(port);
|
|
11300
11449
|
}
|
|
11301
11450
|
function defaultProfileDir(_ownerId, profile) {
|
|
11302
|
-
return
|
|
11451
|
+
return resolve15(BROWSER_PROFILES_DIR, profile);
|
|
11303
11452
|
}
|
|
11304
11453
|
function resolveUserDataDir(instanceKey) {
|
|
11305
11454
|
return managerHost.resolveInstanceDataDir(instanceKey);
|
|
@@ -11391,8 +11540,8 @@ async function spawnPlaywright(instanceKey, ownerId, reservedPort, browserBin =
|
|
|
11391
11540
|
releasePort(port);
|
|
11392
11541
|
throw new Error("Browser.rs managed mode does not support authenticated egress proxies");
|
|
11393
11542
|
}
|
|
11394
|
-
const capability =
|
|
11395
|
-
const spawnNonce =
|
|
11543
|
+
const capability = randomBytes7(32).toString("hex");
|
|
11544
|
+
const spawnNonce = randomBytes7(32).toString("hex");
|
|
11396
11545
|
let vaultBroker;
|
|
11397
11546
|
try {
|
|
11398
11547
|
vaultBroker = await createBrowserVaultBroker(ownerId);
|
|
@@ -11660,14 +11809,14 @@ async function cloneProfileForChild(opts) {
|
|
|
11660
11809
|
killInstance(dstKey);
|
|
11661
11810
|
await delay(500);
|
|
11662
11811
|
}
|
|
11663
|
-
if (!
|
|
11812
|
+
if (!existsSync18(srcDir)) {
|
|
11664
11813
|
return { copied: false, srcDir, dstDir, reason: "src-missing" };
|
|
11665
11814
|
}
|
|
11666
11815
|
try {
|
|
11667
|
-
if (
|
|
11816
|
+
if (existsSync18(dstDir)) {
|
|
11668
11817
|
rmSync3(dstDir, { recursive: true, force: true });
|
|
11669
11818
|
}
|
|
11670
|
-
mkdirSync11(
|
|
11819
|
+
mkdirSync11(dirname12(dstDir), { recursive: true });
|
|
11671
11820
|
if (process.platform === "darwin") {
|
|
11672
11821
|
try {
|
|
11673
11822
|
execFileSync7("cp", ["-cR", srcDir, dstDir], { stdio: "pipe" });
|
|
@@ -11685,7 +11834,7 @@ async function cloneProfileForChild(opts) {
|
|
|
11685
11834
|
cleanSingletonFiles(dstDir);
|
|
11686
11835
|
for (const f of ["DevToolsActivePort", "LOCK"]) {
|
|
11687
11836
|
try {
|
|
11688
|
-
unlinkSync11(
|
|
11837
|
+
unlinkSync11(resolve15(dstDir, f));
|
|
11689
11838
|
} catch {}
|
|
11690
11839
|
}
|
|
11691
11840
|
logger.info({ srcKey, dstKey, srcDir, dstDir }, "Cloned Playwright profile for child topic");
|
|
@@ -11813,7 +11962,7 @@ RULES:
|
|
|
11813
11962
|
|
|
11814
11963
|
// ../../packages/core/src/agents/topic-cleanup.ts
|
|
11815
11964
|
import { mkdirSync as mkdirSync12, renameSync as renameSync6, unlinkSync as unlinkSync12, writeFileSync as writeFileSync10 } from "fs";
|
|
11816
|
-
import { dirname as
|
|
11965
|
+
import { dirname as dirname13 } from "path";
|
|
11817
11966
|
function collectSessionIdsByAgent(entries, extraSessions = []) {
|
|
11818
11967
|
const out = new Map;
|
|
11819
11968
|
for (const e of entries) {
|
|
@@ -11879,7 +12028,7 @@ function createTopicLogMaintenance(host) {
|
|
|
11879
12028
|
const path = runtimeHost.activeConversationPath(opts.userId, opts.topicName);
|
|
11880
12029
|
const tempPath = `${path}.${process.pid}.${Date.now()}.tmp`;
|
|
11881
12030
|
try {
|
|
11882
|
-
mkdirSync12(
|
|
12031
|
+
mkdirSync12(dirname13(path), { recursive: true });
|
|
11883
12032
|
writeFileSync10(tempPath, retained.length > 0 ? `${retained.map((entry) => JSON.stringify(entry)).join(`
|
|
11884
12033
|
`)}
|
|
11885
12034
|
` : "", { flag: "wx" });
|
|
@@ -12333,8 +12482,8 @@ var init_runtime_turn_requests = __esm(async () => {
|
|
|
12333
12482
|
// ../../packages/core/src/topics/session.ts
|
|
12334
12483
|
import { randomUUID as randomUUID11 } from "crypto";
|
|
12335
12484
|
import { mkdtempSync as mkdtempSync2, rmSync as rmSync4, writeFileSync as writeFileSync11 } from "fs";
|
|
12336
|
-
import { tmpdir as
|
|
12337
|
-
import { join as
|
|
12485
|
+
import { tmpdir as tmpdir4 } from "os";
|
|
12486
|
+
import { join as join21 } from "path";
|
|
12338
12487
|
function previousCompactedSummary(entries) {
|
|
12339
12488
|
for (let index = entries.length - 2;index >= 0; index -= 1) {
|
|
12340
12489
|
const request = entries[index]?.event;
|
|
@@ -12464,7 +12613,7 @@ function formatCompactElapsed(startedAt) {
|
|
|
12464
12613
|
async function summarizeTopicContext(request) {
|
|
12465
12614
|
const startedAt = Date.now();
|
|
12466
12615
|
const sessionIds = [];
|
|
12467
|
-
const compactCwd = mkdtempSync2(
|
|
12616
|
+
const compactCwd = mkdtempSync2(join21(tmpdir4(), "negotium-compact-"));
|
|
12468
12617
|
const abortController = new AbortController;
|
|
12469
12618
|
const relayAbort = () => abortController.abort(request.signal?.reason);
|
|
12470
12619
|
if (request.signal?.aborted)
|
|
@@ -12491,7 +12640,7 @@ async function summarizeTopicContext(request) {
|
|
|
12491
12640
|
let error = "";
|
|
12492
12641
|
let toolViolation = false;
|
|
12493
12642
|
let compactionLogCalls = 0;
|
|
12494
|
-
const compactionLogPath =
|
|
12643
|
+
const compactionLogPath = join21(compactCwd, "conversation.log");
|
|
12495
12644
|
try {
|
|
12496
12645
|
const compactionMcp = useCompactionLog ? {
|
|
12497
12646
|
compact_log: {
|
|
@@ -13110,14 +13259,14 @@ var init_derive = __esm(async () => {
|
|
|
13110
13259
|
});
|
|
13111
13260
|
|
|
13112
13261
|
// ../../packages/core/src/query/session-inbox-path.ts
|
|
13113
|
-
import { join as
|
|
13262
|
+
import { join as join22 } from "path";
|
|
13114
13263
|
function sessionInboxPath(userId, topicId) {
|
|
13115
13264
|
const key = Buffer.from(topicId, "utf8").toString("base64url");
|
|
13116
|
-
return
|
|
13265
|
+
return join22(SESSION_INBOX_DIR, userId, `${TOPIC_ID_FILE_PREFIX}${key}${JSONL_SUFFIX}`);
|
|
13117
13266
|
}
|
|
13118
13267
|
function scheduledSessionInboxPath(userId, topicId) {
|
|
13119
13268
|
const key = Buffer.from(topicId, "utf8").toString("base64url");
|
|
13120
|
-
return
|
|
13269
|
+
return join22(SESSION_INBOX_DIR, userId, `${TOPIC_ID_FILE_PREFIX}${key}${SCHEDULE_SUFFIX}`);
|
|
13121
13270
|
}
|
|
13122
13271
|
var TOPIC_ID_FILE_PREFIX = "topic-id-", JSONL_SUFFIX = ".jsonl", SCHEDULE_SUFFIX = ".schedule";
|
|
13123
13272
|
var init_session_inbox_path = __esm(() => {
|
|
@@ -13126,13 +13275,13 @@ var init_session_inbox_path = __esm(() => {
|
|
|
13126
13275
|
|
|
13127
13276
|
// ../../packages/core/src/query/session-inbox-cleanup.ts
|
|
13128
13277
|
import { unlinkSync as unlinkSync14 } from "fs";
|
|
13129
|
-
import { basename as basename3, join as
|
|
13278
|
+
import { basename as basename3, join as join23 } from "path";
|
|
13130
13279
|
function cleanupSessionInboxFiles(userId, topicId, legacyTopicTitle) {
|
|
13131
13280
|
const live = sessionInboxPath(userId, topicId);
|
|
13132
13281
|
const scheduled = scheduledSessionInboxPath(userId, topicId);
|
|
13133
13282
|
const candidates = new Set([live, `${live}.processing`, scheduled, `${scheduled}.processing`]);
|
|
13134
13283
|
if (legacyTopicTitle && legacyTopicTitle !== "." && legacyTopicTitle !== ".." && basename3(legacyTopicTitle) === legacyTopicTitle) {
|
|
13135
|
-
const legacyBase =
|
|
13284
|
+
const legacyBase = join23(SESSION_INBOX_DIR, userId, legacyTopicTitle);
|
|
13136
13285
|
for (const suffix of [".jsonl", ".jsonl.processing", ".schedule", ".schedule.processing"]) {
|
|
13137
13286
|
candidates.add(`${legacyBase}${suffix}`);
|
|
13138
13287
|
}
|
|
@@ -13158,16 +13307,16 @@ var init_session_inbox_cleanup = __esm(() => {
|
|
|
13158
13307
|
|
|
13159
13308
|
// ../../packages/core/src/query/state.ts
|
|
13160
13309
|
import { mkdirSync as mkdirSync14, renameSync as renameSync7, unlinkSync as unlinkSync15, writeFileSync as writeFileSync12 } from "fs";
|
|
13161
|
-
import { basename as basename4, join as
|
|
13310
|
+
import { basename as basename4, join as join24 } from "path";
|
|
13162
13311
|
function createQueryStateStore(options) {
|
|
13163
13312
|
const sanitize = options.sanitizeTopicId ?? sanitizeId;
|
|
13164
|
-
const queryStateDirPath = (userId) =>
|
|
13165
|
-
const queryStateFile = (userId, topicId) =>
|
|
13313
|
+
const queryStateDirPath = (userId) => join24(options.usersLogDir, String(userId), "active-queries");
|
|
13314
|
+
const queryStateFile = (userId, topicId) => join24(queryStateDirPath(userId), `${sanitize(topicId)}.json`);
|
|
13166
13315
|
const legacyQueryStateFile = (userId, topicName) => {
|
|
13167
13316
|
if (!topicName || topicName === "." || topicName === ".." || basename4(topicName) !== topicName) {
|
|
13168
13317
|
return null;
|
|
13169
13318
|
}
|
|
13170
|
-
return
|
|
13319
|
+
return join24(queryStateDirPath(userId), `${topicName}.json`);
|
|
13171
13320
|
};
|
|
13172
13321
|
return {
|
|
13173
13322
|
write(userId, topicId, topicName, task) {
|
|
@@ -13328,30 +13477,30 @@ import {
|
|
|
13328
13477
|
unlinkSync as unlinkSync16,
|
|
13329
13478
|
writeFileSync as writeFileSync13
|
|
13330
13479
|
} from "fs";
|
|
13331
|
-
import { dirname as
|
|
13480
|
+
import { dirname as dirname14, join as join25 } from "path";
|
|
13332
13481
|
function pendingAskDir(userId) {
|
|
13333
13482
|
const rawUserId = String(userId);
|
|
13334
13483
|
const safeUserId = /^[A-Za-z0-9][A-Za-z0-9_.@-]{0,255}$/.test(rawUserId) && !rawUserId.includes("..") ? rawUserId : `sha256-${createHash6("sha256").update(rawUserId).digest("hex")}`;
|
|
13335
|
-
return
|
|
13484
|
+
return join25(resolveStorageSessionAsksDir(), safeUserId);
|
|
13336
13485
|
}
|
|
13337
13486
|
function encodeAskKey(key) {
|
|
13338
13487
|
return JSON.stringify([key.from, key.to]);
|
|
13339
13488
|
}
|
|
13340
13489
|
function pendingAskPath(key) {
|
|
13341
13490
|
const digest = createHash6("sha256").update(encodeAskKey(key)).digest("hex");
|
|
13342
|
-
return
|
|
13491
|
+
return join25(pendingAskDir(key.userId), `${ASK_FILENAME_PREFIX}${digest}.pending`);
|
|
13343
13492
|
}
|
|
13344
13493
|
function v2PendingAskPath(key) {
|
|
13345
13494
|
const encoded = Buffer.from(encodeAskKey(key), "utf8").toString("base64url");
|
|
13346
|
-
return
|
|
13495
|
+
return join25(pendingAskDir(key.userId), `${V2_ASK_FILENAME_PREFIX}${encoded}.pending`);
|
|
13347
13496
|
}
|
|
13348
13497
|
function legacyPendingAskPath(key) {
|
|
13349
13498
|
if (key.from.includes("/") || key.from.includes("\\") || key.to.includes("/") || key.to.includes("\\") || key.from.includes("\x00") || key.to.includes("\x00")) {
|
|
13350
13499
|
return null;
|
|
13351
13500
|
}
|
|
13352
13501
|
const dir = pendingAskDir(key.userId);
|
|
13353
|
-
const candidate =
|
|
13354
|
-
return
|
|
13502
|
+
const candidate = join25(dir, `${key.from}___${key.to}.pending`);
|
|
13503
|
+
return dirname14(candidate) === dir ? candidate : null;
|
|
13355
13504
|
}
|
|
13356
13505
|
function parsePendingAskFilename(fileName) {
|
|
13357
13506
|
if (!fileName.endsWith(".pending"))
|
|
@@ -13591,7 +13740,7 @@ function listPendingAsksForCaller(args) {
|
|
|
13591
13740
|
const parsed = isV3 ? { from: args.from, to: "" } : parsePendingAskFilename(fileName);
|
|
13592
13741
|
if (!parsed)
|
|
13593
13742
|
continue;
|
|
13594
|
-
const path =
|
|
13743
|
+
const path = join25(dir, fileName);
|
|
13595
13744
|
const record = readPendingAskFile(path, {
|
|
13596
13745
|
userId: args.userId,
|
|
13597
13746
|
from: parsed.from,
|
|
@@ -13633,7 +13782,7 @@ function deletePendingAsksForTopic(args) {
|
|
|
13633
13782
|
}
|
|
13634
13783
|
let deleted = 0;
|
|
13635
13784
|
for (const fileName of files) {
|
|
13636
|
-
const path =
|
|
13785
|
+
const path = join25(dir, fileName);
|
|
13637
13786
|
const parsed = parsePendingAskFilename(fileName);
|
|
13638
13787
|
const record = readPendingAskFile(path, {
|
|
13639
13788
|
userId: args.userId,
|
|
@@ -14033,7 +14182,7 @@ body{font-family:system-ui,-apple-system,"Segoe UI",sans-serif;background:var(--
|
|
|
14033
14182
|
// ../../packages/core/src/storage/token-stats.ts
|
|
14034
14183
|
import { createHash as createHash7 } from "crypto";
|
|
14035
14184
|
import { mkdirSync as mkdirSync16, writeFileSync as writeFileSync14 } from "fs";
|
|
14036
|
-
import { join as
|
|
14185
|
+
import { join as join26 } from "path";
|
|
14037
14186
|
function tokenStatsFileId(userId) {
|
|
14038
14187
|
const rawUserId = String(userId);
|
|
14039
14188
|
return /^[A-Za-z0-9][A-Za-z0-9_.@-]{0,255}$/.test(rawUserId) && !rawUserId.includes("..") ? rawUserId : `sha256-${createHash7("sha256").update(rawUserId).digest("hex")}`;
|
|
@@ -14042,7 +14191,7 @@ function queriesPath(userId) {
|
|
|
14042
14191
|
const fileId = tokenStatsFileId(userId);
|
|
14043
14192
|
const logDir = resolveStorageLogDir();
|
|
14044
14193
|
mkdirSync16(logDir, { recursive: true });
|
|
14045
|
-
return
|
|
14194
|
+
return join26(logDir, `token-queries-${fileId}.jsonl`);
|
|
14046
14195
|
}
|
|
14047
14196
|
function estimateUsageCost(agent, model, usage) {
|
|
14048
14197
|
const prices = TOKEN_PRICES[`${agent}:${model}`];
|
|
@@ -14358,7 +14507,7 @@ var init_lifecycle = __esm(async () => {
|
|
|
14358
14507
|
// ../../packages/core/src/runtime/attachments.ts
|
|
14359
14508
|
import { randomUUID as randomUUID14 } from "crypto";
|
|
14360
14509
|
import { copyFileSync as copyFileSync2, mkdirSync as mkdirSync17, writeFileSync as writeFileSync15 } from "fs";
|
|
14361
|
-
import { basename as basename5, join as
|
|
14510
|
+
import { basename as basename5, join as join27 } from "path";
|
|
14362
14511
|
function workspaceCwdFor(topicId) {
|
|
14363
14512
|
return resolveTopicWorkspaceDir(topicId);
|
|
14364
14513
|
}
|
|
@@ -14371,7 +14520,7 @@ function materializePromptAttachments(topicId, queryId, attachmentIds) {
|
|
|
14371
14520
|
if (!attachmentIds?.length)
|
|
14372
14521
|
return [];
|
|
14373
14522
|
const out = [];
|
|
14374
|
-
const destDir =
|
|
14523
|
+
const destDir = join27(workspaceCwdFor(topicId), "attachments", queryId);
|
|
14375
14524
|
for (const rawId of attachmentIds) {
|
|
14376
14525
|
if (typeof rawId !== "string")
|
|
14377
14526
|
continue;
|
|
@@ -14388,7 +14537,7 @@ function materializePromptAttachments(topicId, queryId, attachmentIds) {
|
|
|
14388
14537
|
mkdirSync17(destDir, { recursive: true });
|
|
14389
14538
|
const index = String(out.length + 1).padStart(2, "0");
|
|
14390
14539
|
const safeName = safeAttachmentFilename(attachment.filename, fileId);
|
|
14391
|
-
const destPath =
|
|
14540
|
+
const destPath = join27(destDir, `${index}-${fileId.slice(0, 8)}-${safeName}`);
|
|
14392
14541
|
copyFileSync2(sourcePath, destPath);
|
|
14393
14542
|
out.push({
|
|
14394
14543
|
id: attachment.id,
|
|
@@ -14418,10 +14567,10 @@ function promptWithAttachments(prompt, attachments) {
|
|
|
14418
14567
|
return composeAttachmentPrompt(prompt, attachments.map(({ filename, path }) => attachmentPromptLine(filename, path)));
|
|
14419
14568
|
}
|
|
14420
14569
|
function ingestAttachment(args) {
|
|
14421
|
-
const destDir =
|
|
14570
|
+
const destDir = join27(UPLOADS_DIR, args.topicId);
|
|
14422
14571
|
mkdirSync17(destDir, { recursive: true });
|
|
14423
14572
|
const safeName = safeAttachmentFilename(args.filename, "upload");
|
|
14424
|
-
const destPath =
|
|
14573
|
+
const destPath = join27(destDir, `${Date.now()}-${randomUUID14().slice(0, 8)}-${safeName}`);
|
|
14425
14574
|
if (args.sourcePath !== undefined) {
|
|
14426
14575
|
copyFileSync2(args.sourcePath, destPath);
|
|
14427
14576
|
} else if (args.bytes !== undefined) {
|
|
@@ -14596,12 +14745,12 @@ var init_errors = __esm(() => {
|
|
|
14596
14745
|
|
|
14597
14746
|
// ../../packages/core/src/runtime/event-heartbeat.ts
|
|
14598
14747
|
function nextOrHeartbeat(pending, intervalMs) {
|
|
14599
|
-
return new Promise((
|
|
14600
|
-
const timer = setTimeout(() =>
|
|
14748
|
+
return new Promise((resolve16, reject) => {
|
|
14749
|
+
const timer = setTimeout(() => resolve16({ kind: "heartbeat" }), intervalMs);
|
|
14601
14750
|
timer.unref?.();
|
|
14602
14751
|
pending.then((result) => {
|
|
14603
14752
|
clearTimeout(timer);
|
|
14604
|
-
|
|
14753
|
+
resolve16({ kind: "event", result });
|
|
14605
14754
|
}, (error) => {
|
|
14606
14755
|
clearTimeout(timer);
|
|
14607
14756
|
reject(error);
|
|
@@ -14922,7 +15071,7 @@ var init_visual_html = __esm(() => {
|
|
|
14922
15071
|
|
|
14923
15072
|
// ../../packages/core/src/runtime/visuals.ts
|
|
14924
15073
|
import { realpathSync as realpathSync4 } from "fs";
|
|
14925
|
-
import { isAbsolute as isAbsolute5, resolve as
|
|
15074
|
+
import { isAbsolute as isAbsolute5, resolve as resolve16 } from "path";
|
|
14926
15075
|
function activeVisualHtmlForPrompt(html) {
|
|
14927
15076
|
if (html.length <= ACTIVE_VISUAL_PROMPT_MAX_CHARS) {
|
|
14928
15077
|
return { html, omittedChars: 0 };
|
|
@@ -14973,8 +15122,8 @@ function topicAllowsVisualFileId(topicId, fileId) {
|
|
|
14973
15122
|
return topicHasAttachmentFileId(topicId, fileId) || topicHasVisualFileId(topicId, fileId);
|
|
14974
15123
|
}
|
|
14975
15124
|
function isPathInside(baseDir, filePath) {
|
|
14976
|
-
const base =
|
|
14977
|
-
const normalized =
|
|
15125
|
+
const base = resolve16(baseDir);
|
|
15126
|
+
const normalized = resolve16(filePath);
|
|
14978
15127
|
try {
|
|
14979
15128
|
const realBase = realpathSync4(base);
|
|
14980
15129
|
const real = realpathSync4(normalized);
|
|
@@ -15036,7 +15185,7 @@ function resolveVisualMediaInput(topicId, input) {
|
|
|
15036
15185
|
}
|
|
15037
15186
|
const rawPath = input.file_path.trim();
|
|
15038
15187
|
const cwd = workspaceCwdFor(topicId);
|
|
15039
|
-
const candidate = isAbsolute5(rawPath) ? rawPath :
|
|
15188
|
+
const candidate = isAbsolute5(rawPath) ? rawPath : resolve16(cwd, rawPath);
|
|
15040
15189
|
if (!isPathInside(cwd, candidate)) {
|
|
15041
15190
|
return { error: "file_path must be inside the topic workspace" };
|
|
15042
15191
|
}
|
|
@@ -15074,7 +15223,7 @@ var init_visuals = __esm(async () => {
|
|
|
15074
15223
|
// ../../packages/core/src/runtime/turn-event-stream.ts
|
|
15075
15224
|
import { randomUUID as randomUUID15 } from "crypto";
|
|
15076
15225
|
import { realpathSync as realpathSync5, statSync as statSync9 } from "fs";
|
|
15077
|
-
import { isAbsolute as isAbsolute6, resolve as
|
|
15226
|
+
import { isAbsolute as isAbsolute6, resolve as resolve17 } from "path";
|
|
15078
15227
|
function sessionEventMatchesCurrentExecution(topicId, queryId, agent, model) {
|
|
15079
15228
|
if (getRoomQuery(topicId)?.queryId !== queryId)
|
|
15080
15229
|
return false;
|
|
@@ -15427,7 +15576,7 @@ ${JSON.stringify(event.input ?? {})}`);
|
|
|
15427
15576
|
case "file":
|
|
15428
15577
|
if (!silent && peerBridge) {
|
|
15429
15578
|
const cwd = workspaceCwdFor(topicId);
|
|
15430
|
-
const path = isAbsolute6(event.path) ? event.path :
|
|
15579
|
+
const path = isAbsolute6(event.path) ? event.path : resolve17(cwd, event.path);
|
|
15431
15580
|
if (!isPathInside(cwd, path)) {
|
|
15432
15581
|
logger.warn({ topicId, path }, "peer output file is outside the topic workspace");
|
|
15433
15582
|
break;
|
|
@@ -15709,15 +15858,15 @@ var init_turn_session = __esm(async () => {
|
|
|
15709
15858
|
});
|
|
15710
15859
|
|
|
15711
15860
|
// ../../packages/core/src/storage/app-settings.ts
|
|
15712
|
-
import { existsSync as
|
|
15713
|
-
import { dirname as
|
|
15861
|
+
import { existsSync as existsSync19, mkdirSync as mkdirSync18, readFileSync as readFileSync17, writeFileSync as writeFileSync16 } from "fs";
|
|
15862
|
+
import { dirname as dirname15, join as join28 } from "path";
|
|
15714
15863
|
function settingsFile() {
|
|
15715
|
-
return
|
|
15864
|
+
return join28(resolveStorageDataDir(), "otium-settings.json");
|
|
15716
15865
|
}
|
|
15717
15866
|
function getGlobalAiName() {
|
|
15718
15867
|
const path = settingsFile();
|
|
15719
15868
|
try {
|
|
15720
|
-
if (
|
|
15869
|
+
if (existsSync19(path)) {
|
|
15721
15870
|
const data = JSON.parse(readFileSync17(path, "utf8"));
|
|
15722
15871
|
if (typeof data.aiName === "string" && data.aiName.trim()) {
|
|
15723
15872
|
return data.aiName.trim();
|
|
@@ -15806,8 +15955,8 @@ __export(exports_turn_runner, {
|
|
|
15806
15955
|
AGENT_DISPLAY_NAME: () => AGENT_DISPLAY_NAME
|
|
15807
15956
|
});
|
|
15808
15957
|
import { randomUUID as randomUUID16 } from "crypto";
|
|
15809
|
-
import { existsSync as
|
|
15810
|
-
import { join as
|
|
15958
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync19, readdirSync as readdirSync5, statSync as statSync10 } from "fs";
|
|
15959
|
+
import { join as join29 } from "path";
|
|
15811
15960
|
function withDefaultPlaywright(configuredMcp, isManager) {
|
|
15812
15961
|
if (isManager)
|
|
15813
15962
|
return configuredMcp;
|
|
@@ -15862,8 +16011,8 @@ function appendAskReplyMessage(topicId, text2, agentType) {
|
|
|
15862
16011
|
return message;
|
|
15863
16012
|
}
|
|
15864
16013
|
function resolveWikiMirrorPath(directory, preferredFilename, matchesLegacyId, matchesTitle, preferExact = true) {
|
|
15865
|
-
const preferred =
|
|
15866
|
-
if (preferExact &&
|
|
16014
|
+
const preferred = join29(directory, preferredFilename);
|
|
16015
|
+
if (preferExact && existsSync20(preferred))
|
|
15867
16016
|
return preferred;
|
|
15868
16017
|
let newestLegacyId = null;
|
|
15869
16018
|
let newestTitle = null;
|
|
@@ -15873,7 +16022,7 @@ function resolveWikiMirrorPath(directory, preferredFilename, matchesLegacyId, ma
|
|
|
15873
16022
|
const legacyIdMatch = !titleMatch && matchesLegacyId(filename);
|
|
15874
16023
|
if (!titleMatch && !legacyIdMatch)
|
|
15875
16024
|
continue;
|
|
15876
|
-
const path =
|
|
16025
|
+
const path = join29(directory, filename);
|
|
15877
16026
|
const mtimeMs = statSync10(path).mtimeMs;
|
|
15878
16027
|
if (titleMatch) {
|
|
15879
16028
|
if (!newestTitle || mtimeMs > newestTitle.mtimeMs) {
|
|
@@ -15887,10 +16036,10 @@ function resolveWikiMirrorPath(directory, preferredFilename, matchesLegacyId, ma
|
|
|
15887
16036
|
return newestTitle?.path ?? newestLegacyId?.path ?? preferred;
|
|
15888
16037
|
}
|
|
15889
16038
|
function resolveWikiMemoryMirror(wikiDir, topicId, topicTitle) {
|
|
15890
|
-
const briefFile = resolveWikiMirrorPath(
|
|
15891
|
-
const hasBriefFile =
|
|
15892
|
-
const latestSummaryCandidate = resolveWikiMirrorPath(
|
|
15893
|
-
const latestSummaryFile =
|
|
16039
|
+
const briefFile = resolveWikiMirrorPath(join29(wikiDir, "topic"), `${wikiBriefStorageKey(topicTitle, topicId)}.md`, (filename) => isTopicBriefFile(filename, topicId), (filename) => isTopicBriefFile(filename, topicId, topicTitle));
|
|
16040
|
+
const hasBriefFile = existsSync20(briefFile) && statSync10(briefFile).isFile();
|
|
16041
|
+
const latestSummaryCandidate = resolveWikiMirrorPath(join29(wikiDir, "summaries"), `__missing__-${wikiSummaryFilename("0000-00-00", topicTitle, topicId)}`, (filename) => isTopicSummaryFile(filename, topicId), (filename) => isTopicSummaryFile(filename, topicId, topicTitle), false);
|
|
16042
|
+
const latestSummaryFile = existsSync20(latestSummaryCandidate) && statSync10(latestSummaryCandidate).isFile() ? latestSummaryCandidate : null;
|
|
15894
16043
|
return { briefFile, hasBriefFile, latestSummaryFile };
|
|
15895
16044
|
}
|
|
15896
16045
|
async function streamAgentEvents(topicId, topicTitle, queryId, events, control, agentType, model, effort, userId, retryableSessionExpired = true, onSessionId, execution) {
|
|
@@ -17924,8 +18073,8 @@ init_common();
|
|
|
17924
18073
|
import { z as z2 } from "zod";
|
|
17925
18074
|
|
|
17926
18075
|
// ../../packages/core/src/agents/mcp-tools/inline-assets.ts
|
|
17927
|
-
import { existsSync as
|
|
17928
|
-
import { extname, isAbsolute as isAbsolute3, resolve as
|
|
18076
|
+
import { existsSync as existsSync17, readFileSync as readFileSync14, statSync as statSync7 } from "fs";
|
|
18077
|
+
import { extname, isAbsolute as isAbsolute3, resolve as resolve12 } from "path";
|
|
17929
18078
|
var MIME_BY_EXT = {
|
|
17930
18079
|
".apng": "image/apng",
|
|
17931
18080
|
".avif": "image/avif",
|
|
@@ -17970,10 +18119,10 @@ function inlineLocalAssets(html, options) {
|
|
|
17970
18119
|
const relPath = stripSuffix(ref);
|
|
17971
18120
|
if (!relPath)
|
|
17972
18121
|
return null;
|
|
17973
|
-
const abs = isAbsolute3(relPath) ? relPath :
|
|
18122
|
+
const abs = isAbsolute3(relPath) ? relPath : resolve12(baseDir, relPath);
|
|
17974
18123
|
let bytes;
|
|
17975
18124
|
try {
|
|
17976
|
-
if (!
|
|
18125
|
+
if (!existsSync17(abs) || !statSync7(abs).isFile()) {
|
|
17977
18126
|
unresolved.push(ref);
|
|
17978
18127
|
cache.set(ref, null);
|
|
17979
18128
|
return null;
|
|
@@ -18930,7 +19079,6 @@ var otiumVisualToolDefinitions = [
|
|
|
18930
19079
|
await init_task_events();
|
|
18931
19080
|
init_tool_format();
|
|
18932
19081
|
await init_topic_cleanup();
|
|
18933
|
-
init_vault_tool_policy();
|
|
18934
19082
|
export {
|
|
18935
19083
|
withTaskSnapshots,
|
|
18936
19084
|
withCodexSpawnSerial,
|
|
@@ -18945,23 +19093,19 @@ export {
|
|
|
18945
19093
|
showMermaidTool,
|
|
18946
19094
|
showImageTool,
|
|
18947
19095
|
showHtmlTool,
|
|
18948
|
-
shouldRedirectVaultTool,
|
|
18949
19096
|
rotateTopicLogs,
|
|
18950
19097
|
resolveTaskEventScope,
|
|
18951
19098
|
registerOwnedCodexPids,
|
|
18952
|
-
referencesRuntimeSecretStorage,
|
|
18953
19099
|
purgeTopicLogs,
|
|
18954
19100
|
otiumVisualToolDefinitions,
|
|
18955
19101
|
normalizeAskUserQuestionInput,
|
|
18956
19102
|
normalizeAskUserChoices,
|
|
18957
19103
|
killOwnedCodexTreesForShutdown,
|
|
18958
19104
|
killCodexTrees,
|
|
18959
|
-
isVaultBrokerTool,
|
|
18960
19105
|
formatToolUse,
|
|
18961
19106
|
forkAgentSession,
|
|
18962
19107
|
findNewCodexChildren,
|
|
18963
19108
|
defaultAskUserDurabilityHost,
|
|
18964
|
-
createVaultToolPolicy,
|
|
18965
19109
|
createTopicLogMaintenance,
|
|
18966
19110
|
createSubagentLifecycle,
|
|
18967
19111
|
createSelfConfigToolDefinitionsForCore,
|
|
@@ -18982,9 +19126,8 @@ export {
|
|
|
18982
19126
|
archiveActiveTopicForMemory,
|
|
18983
19127
|
acquireCodexSpawnLock,
|
|
18984
19128
|
VISUALS_MCP_KEY,
|
|
18985
|
-
VAULT_BROKER_REDIRECT_ERROR,
|
|
18986
19129
|
MIN_MEMORY_ARCHIVE_EXCHANGES,
|
|
18987
19130
|
DEFAULT_SELF_CONFIG_PRODUCT
|
|
18988
19131
|
};
|
|
18989
19132
|
|
|
18990
|
-
//# debugId=
|
|
19133
|
+
//# debugId=0F776DB92A8B6B8F64756E2164756E21
|