negotium 0.3.14 → 0.4.1
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 +333 -187
- 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 +214 -65
- package/dist/hosted-agent.js.map +8 -7
- package/dist/main.js +712 -895
- package/dist/main.js.map +10 -11
- package/dist/mcp-factories.js +305 -470
- 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 +40 -9
- package/dist/runtime/src/agents/codex-vault-hook-bridge.ts +198 -0
- package/dist/runtime/src/agents/codex-vault-hook.mjs +50 -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 +28 -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 +2 -2
- 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.1";
|
|
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, socketPath, token) {
|
|
4625
|
+
return [
|
|
4626
|
+
"#!/bin/sh",
|
|
4627
|
+
`export ${HOOK_SOCKET_ENV}=${shellQuote(socketPath)}`,
|
|
4628
|
+
`export ${HOOK_TOKEN_ENV}=${shellQuote(token)}`,
|
|
4629
|
+
'if [ "$1" = "exec" ]; then',
|
|
4630
|
+
" shift",
|
|
4631
|
+
` exec ${shellQuote(process.execPath)} ${shellQuote(codexScript)} exec --dangerously-bypass-hook-trust "$@"`,
|
|
4632
|
+
"fi",
|
|
4633
|
+
`exec ${shellQuote(process.execPath)} ${shellQuote(codexScript)} "$@"`,
|
|
4634
|
+
""
|
|
4635
|
+
].join(`
|
|
4636
|
+
`);
|
|
4637
|
+
}
|
|
4638
|
+
async function createCodexVaultHookBridge(userId) {
|
|
4639
|
+
const root = await mkdtemp(join12(tmpdir2(), "negotium-codex-vault-"));
|
|
4640
|
+
await chmod(root, 448);
|
|
4641
|
+
const socketPath = join12(root, "hook.sock");
|
|
4642
|
+
const wrapperPath = join12(root, "codex-with-hooks");
|
|
4643
|
+
const token = randomBytes5(32).toString("hex");
|
|
4644
|
+
const connections = new Set;
|
|
4645
|
+
const server = createServer((socket) => {
|
|
4646
|
+
connections.add(socket);
|
|
4647
|
+
socket.once("close", () => connections.delete(socket));
|
|
4648
|
+
socket.setEncoding("utf8");
|
|
4649
|
+
let request = "";
|
|
4650
|
+
let handled = false;
|
|
4651
|
+
const handleRequest = () => {
|
|
4652
|
+
if (handled)
|
|
4653
|
+
return;
|
|
4654
|
+
handled = true;
|
|
4655
|
+
try {
|
|
4656
|
+
const parsed = JSON.parse(request.trimEnd());
|
|
4657
|
+
if (parsed.token !== token)
|
|
4658
|
+
throw new Error("invalid hook capability");
|
|
4659
|
+
if (!parsed.input || typeof parsed.input !== "object" || typeof parsed.input.tool_name !== "string") {
|
|
4660
|
+
throw new Error("invalid PreToolUse payload");
|
|
4661
|
+
}
|
|
4662
|
+
const output = evaluateCodexVaultPreToolUse(parsed.input, userId, {
|
|
4663
|
+
referencesSensitiveStorage: referencesHostedSecretStorage,
|
|
4664
|
+
substitute: substituteHostedSecrets
|
|
4665
|
+
});
|
|
4666
|
+
socket.end(JSON.stringify({ ok: true, output }));
|
|
4667
|
+
} catch (error) {
|
|
4668
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
4669
|
+
socket.end(JSON.stringify({ ok: false, error: message }));
|
|
4670
|
+
}
|
|
4671
|
+
};
|
|
4672
|
+
socket.on("data", (chunk) => {
|
|
4673
|
+
request += chunk;
|
|
4674
|
+
if (Buffer.byteLength(request) > MAX_HOOK_REQUEST_BYTES)
|
|
4675
|
+
socket.destroy();
|
|
4676
|
+
else if (request.endsWith(`
|
|
4677
|
+
`))
|
|
4678
|
+
handleRequest();
|
|
4679
|
+
});
|
|
4680
|
+
socket.on("end", handleRequest);
|
|
4681
|
+
});
|
|
4682
|
+
try {
|
|
4683
|
+
await new Promise((resolveListen, reject) => {
|
|
4684
|
+
server.once("error", reject);
|
|
4685
|
+
server.listen(socketPath, () => {
|
|
4686
|
+
server.off("error", reject);
|
|
4687
|
+
resolveListen();
|
|
4688
|
+
});
|
|
4689
|
+
});
|
|
4690
|
+
await chmod(socketPath, 384);
|
|
4691
|
+
await writeFile(wrapperPath, privateCodexWrapper(codexCliScriptPath(), socketPath, token), {
|
|
4692
|
+
mode: 448
|
|
4693
|
+
});
|
|
4694
|
+
const command = [shellQuote(process.execPath), shellQuote(hookClientPath())].join(" ");
|
|
4695
|
+
return {
|
|
4696
|
+
codexPathOverride: wrapperPath,
|
|
4697
|
+
environment: { [HOOK_SOCKET_ENV]: socketPath, [HOOK_TOKEN_ENV]: token },
|
|
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", HOOK_SOCKET_ENV = "NEGOTIUM_CODEX_VAULT_HOOK_SOCKET", HOOK_TOKEN_ENV = "NEGOTIUM_CODEX_VAULT_HOOK_TOKEN";
|
|
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") {
|
|
@@ -5690,7 +5837,10 @@ async function* codexProvider(opts) {
|
|
|
5690
5837
|
yield fileEvent;
|
|
5691
5838
|
}
|
|
5692
5839
|
} else if (item.type === "error") {
|
|
5693
|
-
|
|
5840
|
+
const message = String(item.message ?? "");
|
|
5841
|
+
if (message !== CODEX_HOOK_TRUST_BYPASS_NOTICE) {
|
|
5842
|
+
yield { type: "error", content: message };
|
|
5843
|
+
}
|
|
5694
5844
|
}
|
|
5695
5845
|
break;
|
|
5696
5846
|
}
|
|
@@ -5778,12 +5928,14 @@ async function* codexProvider(opts) {
|
|
|
5778
5928
|
abortSignal?.removeEventListener("abort", onAbortKill);
|
|
5779
5929
|
if (trackedPids.pids.length > 0)
|
|
5780
5930
|
unregisterOwnedCodexPids(trackedPids.pids);
|
|
5931
|
+
await vaultHook.close();
|
|
5781
5932
|
}
|
|
5782
5933
|
}
|
|
5783
|
-
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;
|
|
5934
|
+
var CODEX_HOOK_TRUST_BYPASS_NOTICE = "`--dangerously-bypass-hook-trust` is enabled. Enabled hooks may run without review for this invocation.", 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
5935
|
var init_codex_provider = __esm(async () => {
|
|
5785
5936
|
init_codex_native_multi_agent();
|
|
5786
5937
|
init_codex_tree_kill();
|
|
5938
|
+
await init_codex_vault_hook_bridge();
|
|
5787
5939
|
await init_execution_host();
|
|
5788
5940
|
await init_codex();
|
|
5789
5941
|
init_tool_format();
|
|
@@ -5811,7 +5963,7 @@ __export(exports_maestro_provider, {
|
|
|
5811
5963
|
buildMaestroToolHooks: () => buildMaestroToolHooks,
|
|
5812
5964
|
buildMaestroDisallowedTools: () => buildMaestroDisallowedTools
|
|
5813
5965
|
});
|
|
5814
|
-
import { resolve as
|
|
5966
|
+
import { resolve as resolve10 } from "path";
|
|
5815
5967
|
import { maestroProvider as sdkMaestroProvider, setMcpResolver } from "maestro-agent-sdk";
|
|
5816
5968
|
function buildMaestroDisallowedTools(callerDisallowedTools = [], toolPolicy) {
|
|
5817
5969
|
return [
|
|
@@ -5945,13 +6097,13 @@ var init_maestro_provider = __esm(async () => {
|
|
|
5945
6097
|
"ToolSearch",
|
|
5946
6098
|
...DEFAULT_MAESTRO_DISALLOWED_TOOLS
|
|
5947
6099
|
];
|
|
5948
|
-
MAESTRO_TOOL_OUTPUT_DIR =
|
|
6100
|
+
MAESTRO_TOOL_OUTPUT_DIR = resolve10(RUN_DIR, "maestro-tool-outputs");
|
|
5949
6101
|
});
|
|
5950
6102
|
|
|
5951
6103
|
// ../../packages/core/src/agents/index.ts
|
|
5952
|
-
import { existsSync as
|
|
6104
|
+
import { existsSync as existsSync13 } from "fs";
|
|
5953
6105
|
import { homedir as homedir7 } from "os";
|
|
5954
|
-
import { join as
|
|
6106
|
+
import { join as join14 } from "path";
|
|
5955
6107
|
async function* dispatchAgent(opts) {
|
|
5956
6108
|
switch (opts.agent) {
|
|
5957
6109
|
case "claude": {
|
|
@@ -5985,11 +6137,11 @@ async function resolveSessionFileMissing(agent, sessionId, cwd) {
|
|
|
5985
6137
|
switch (agent) {
|
|
5986
6138
|
case "claude": {
|
|
5987
6139
|
const encodedCwd = encodeClaudeCwd(cwd);
|
|
5988
|
-
const path =
|
|
5989
|
-
return !
|
|
6140
|
+
const path = join14(homedir7(), ".claude", "projects", encodedCwd, `${sessionId}.jsonl`);
|
|
6141
|
+
return !existsSync13(path);
|
|
5990
6142
|
}
|
|
5991
6143
|
case "codex": {
|
|
5992
|
-
const sessionsDir =
|
|
6144
|
+
const sessionsDir = join14(hostedCodexHomePath(), "sessions");
|
|
5993
6145
|
const glob = new Bun.Glob(`**/rollout-*-${sessionId}.jsonl`);
|
|
5994
6146
|
for await (const _rel of glob.scan({ cwd: sessionsDir, onlyFiles: true })) {
|
|
5995
6147
|
return false;
|
|
@@ -5998,7 +6150,7 @@ async function resolveSessionFileMissing(agent, sessionId, cwd) {
|
|
|
5998
6150
|
}
|
|
5999
6151
|
case "maestro": {
|
|
6000
6152
|
const { hasActiveMaestroSession, maestroSessionPath: maestroSessionPath2 } = await import("maestro-agent-sdk");
|
|
6001
|
-
return !
|
|
6153
|
+
return !existsSync13(maestroSessionPath2(sessionId)) && !hasActiveMaestroSession(sessionId);
|
|
6002
6154
|
}
|
|
6003
6155
|
default: {
|
|
6004
6156
|
const _exhaustive = agent;
|
|
@@ -6526,9 +6678,9 @@ var init_model_catalog = __esm(() => {
|
|
|
6526
6678
|
|
|
6527
6679
|
// ../../packages/core/src/prompts/builders.ts
|
|
6528
6680
|
import { readFileSync as readFileSync12 } from "fs";
|
|
6529
|
-
import { resolve as
|
|
6681
|
+
import { resolve as resolve11 } from "path";
|
|
6530
6682
|
function loadPrompt(filename, dir = SESSIONS_DIR) {
|
|
6531
|
-
const raw = readFileSync12(
|
|
6683
|
+
const raw = readFileSync12(resolve11(dir, filename), "utf-8");
|
|
6532
6684
|
return raw.replace(/\{\{RESOURCES_DIR\}\}/g, RESOURCES_DIR);
|
|
6533
6685
|
}
|
|
6534
6686
|
function replaceVars(template, vars) {
|
|
@@ -6577,7 +6729,7 @@ function visualDesignGuide() {
|
|
|
6577
6729
|
return _visualDesignGuide;
|
|
6578
6730
|
}
|
|
6579
6731
|
function loadAgentPrompt(filename) {
|
|
6580
|
-
const raw = readFileSync12(
|
|
6732
|
+
const raw = readFileSync12(resolve11(AGENTS_PROMPTS_DIR, filename), "utf-8");
|
|
6581
6733
|
const match = raw.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
6582
6734
|
if (!match)
|
|
6583
6735
|
throw new Error(`Agent prompt ${filename} is missing frontmatter`);
|
|
@@ -6892,8 +7044,8 @@ var init_builders = __esm(() => {
|
|
|
6892
7044
|
init_model_catalog();
|
|
6893
7045
|
init_config();
|
|
6894
7046
|
init_logger();
|
|
6895
|
-
PROMPTS_DIR =
|
|
6896
|
-
SESSIONS_DIR =
|
|
7047
|
+
PROMPTS_DIR = resolve11(PROJECT_ROOT, "src/prompts");
|
|
7048
|
+
SESSIONS_DIR = resolve11(PROMPTS_DIR, "sessions");
|
|
6897
7049
|
defaultPromptBuilders = createPromptBuilders();
|
|
6898
7050
|
buildTopicSystemPrompt = defaultPromptBuilders.buildTopicSystemPrompt;
|
|
6899
7051
|
buildChannelSystemPrompt = defaultPromptBuilders.buildChannelSystemPrompt;
|
|
@@ -7244,9 +7396,9 @@ var init_api_topic_brief = __esm(async () => {
|
|
|
7244
7396
|
});
|
|
7245
7397
|
|
|
7246
7398
|
// ../../packages/core/src/storage/wiki.ts
|
|
7247
|
-
import { basename as basename2, dirname as
|
|
7399
|
+
import { basename as basename2, dirname as dirname11, join as join15 } from "path";
|
|
7248
7400
|
function getSharedWikiDir(workspaceDir = resolveStorageWorkspaceDir()) {
|
|
7249
|
-
return workspaceDir === resolveStorageWorkspaceDir() ? resolveStorageSharedWikiDir() :
|
|
7401
|
+
return workspaceDir === resolveStorageWorkspaceDir() ? resolveStorageSharedWikiDir() : join15(workspaceDir, "wiki");
|
|
7250
7402
|
}
|
|
7251
7403
|
var init_wiki = __esm(async () => {
|
|
7252
7404
|
await init_storage_host();
|
|
@@ -8080,8 +8232,8 @@ var init_personal_general = __esm(async () => {
|
|
|
8080
8232
|
|
|
8081
8233
|
// ../../packages/core/src/agents/archiver.ts
|
|
8082
8234
|
import { randomUUID as randomUUID6 } from "crypto";
|
|
8083
|
-
import { existsSync as
|
|
8084
|
-
import { join as
|
|
8235
|
+
import { existsSync as existsSync14, readdirSync as readdirSync2, readFileSync as readFileSync13, statSync as statSync6 } from "fs";
|
|
8236
|
+
import { join as join16 } from "path";
|
|
8085
8237
|
function resolveMemoryLanguage() {
|
|
8086
8238
|
const override = process.env.NEGOTIUM_MEMORY_LANG?.trim();
|
|
8087
8239
|
return override && override.length > 0 ? override : resolveOutputLanguage();
|
|
@@ -8332,10 +8484,10 @@ function distillOneLine(summaryMd) {
|
|
|
8332
8484
|
return "";
|
|
8333
8485
|
}
|
|
8334
8486
|
function findSummaryFile(storage, topicTitle, date, sinceMs, topicId) {
|
|
8335
|
-
const dir =
|
|
8487
|
+
const dir = join16(storage.getWikiDir(), "summaries");
|
|
8336
8488
|
if (!storage.fileExists(dir))
|
|
8337
8489
|
return null;
|
|
8338
|
-
const predicted =
|
|
8490
|
+
const predicted = join16(dir, wikiSummaryFilename(date, topicTitle, topicId));
|
|
8339
8491
|
if (storage.fileExists(predicted) && storage.fileModifiedAt(predicted) >= sinceMs)
|
|
8340
8492
|
return predicted;
|
|
8341
8493
|
let best = null;
|
|
@@ -8343,7 +8495,7 @@ function findSummaryFile(storage, topicTitle, date, sinceMs, topicId) {
|
|
|
8343
8495
|
if (!f.startsWith(`${date}-`) || !isTopicSummaryFile(f, topicId ?? "", topicTitle)) {
|
|
8344
8496
|
continue;
|
|
8345
8497
|
}
|
|
8346
|
-
const p =
|
|
8498
|
+
const p = join16(dir, f);
|
|
8347
8499
|
try {
|
|
8348
8500
|
const m = storage.fileModifiedAt(p);
|
|
8349
8501
|
if (m >= sinceMs && (!best || m > best.mtime))
|
|
@@ -8424,7 +8576,7 @@ var init_archiver = __esm(async () => {
|
|
|
8424
8576
|
defaultArchiverRuntime = createArchiverRuntime({
|
|
8425
8577
|
storage: {
|
|
8426
8578
|
getWikiDir: getSharedWikiDir,
|
|
8427
|
-
fileExists:
|
|
8579
|
+
fileExists: existsSync14,
|
|
8428
8580
|
listDirectory: readdirSync2,
|
|
8429
8581
|
readTextFile: (path) => readFileSync13(path, "utf-8"),
|
|
8430
8582
|
fileSize: (path) => statSync6(path).size,
|
|
@@ -8469,9 +8621,9 @@ __export(exports_auth_check, {
|
|
|
8469
8621
|
checkAgentAuth: () => checkAgentAuth
|
|
8470
8622
|
});
|
|
8471
8623
|
import { execFileSync as execFileSync5 } from "child_process";
|
|
8472
|
-
import { existsSync as
|
|
8624
|
+
import { existsSync as existsSync15 } from "fs";
|
|
8473
8625
|
import { homedir as homedir8, platform } from "os";
|
|
8474
|
-
import { join as
|
|
8626
|
+
import { join as join17 } from "path";
|
|
8475
8627
|
function hasMaestroCredential(host, key, userId) {
|
|
8476
8628
|
if (userId && host.getVaultValue(userId, key)?.trim())
|
|
8477
8629
|
return true;
|
|
@@ -8491,7 +8643,7 @@ function checkAgentAuth(agent, host = defaultAgentAuthHost, userId) {
|
|
|
8491
8643
|
case "claude": {
|
|
8492
8644
|
if (host.environment.ANTHROPIC_API_KEY)
|
|
8493
8645
|
return { ok: true };
|
|
8494
|
-
const path =
|
|
8646
|
+
const path = join17(host.homeDirectory(), ".claude", ".credentials.json");
|
|
8495
8647
|
if (host.operatingSystem() === "darwin") {
|
|
8496
8648
|
if (host.hasMacOsCredential("Claude Code-credentials") || host.exists(path)) {
|
|
8497
8649
|
return { ok: true };
|
|
@@ -8542,7 +8694,7 @@ var init_auth_check = __esm(async () => {
|
|
|
8542
8694
|
await init_vault();
|
|
8543
8695
|
defaultAgentAuthHost = {
|
|
8544
8696
|
codexAuthFilePath,
|
|
8545
|
-
exists:
|
|
8697
|
+
exists: existsSync15,
|
|
8546
8698
|
environment: process.env,
|
|
8547
8699
|
homeDirectory: homedir8,
|
|
8548
8700
|
operatingSystem: platform,
|
|
@@ -8559,7 +8711,7 @@ var init_auth_check = __esm(async () => {
|
|
|
8559
8711
|
});
|
|
8560
8712
|
|
|
8561
8713
|
// ../../packages/core/src/agents/fork.ts
|
|
8562
|
-
import { existsSync as
|
|
8714
|
+
import { existsSync as existsSync16, unlinkSync as unlinkSync8 } from "fs";
|
|
8563
8715
|
function createAgentForkHelpers(host) {
|
|
8564
8716
|
return {
|
|
8565
8717
|
async forkAgentSession(options) {
|
|
@@ -8596,7 +8748,7 @@ var init_fork = __esm(async () => {
|
|
|
8596
8748
|
init_logger();
|
|
8597
8749
|
defaultForkHelpers = createAgentForkHelpers({
|
|
8598
8750
|
forkSession: (agent, options) => getRegistryOperations(agent).forkSession(options),
|
|
8599
|
-
exists:
|
|
8751
|
+
exists: existsSync16,
|
|
8600
8752
|
unlink: unlinkSync8,
|
|
8601
8753
|
warn: (details, message) => logger.warn(details, message)
|
|
8602
8754
|
});
|
|
@@ -9252,13 +9404,13 @@ function formatTopicArchiveTranscriptRecord(row, topicTitle, index) {
|
|
|
9252
9404
|
|
|
9253
9405
|
// ../../packages/core/src/storage/topic-archive.ts
|
|
9254
9406
|
import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync8 } from "fs";
|
|
9255
|
-
import { join as
|
|
9407
|
+
import { join as join18 } from "path";
|
|
9256
9408
|
function archiveTopicMessages(topicId, topicTitle, options = {}) {
|
|
9257
9409
|
const rows = options.afterRowid !== undefined ? getMessagesForTopicAfterRowid(topicId, options.afterRowid) : getAllMessagesForTopic(topicId);
|
|
9258
9410
|
if (rows.length === 0)
|
|
9259
9411
|
return null;
|
|
9260
9412
|
const safeTopic = sanitizeTopicName(topicTitle, true);
|
|
9261
|
-
const archiveDir =
|
|
9413
|
+
const archiveDir = join18(getSharedWikiDir(), "archive");
|
|
9262
9414
|
mkdirSync10(archiveDir, { recursive: true });
|
|
9263
9415
|
const date = new Date().toISOString().slice(0, 10);
|
|
9264
9416
|
const reasonSuffix = options.reason && options.reason !== "delete" ? `_${options.reason}` : "";
|
|
@@ -9271,7 +9423,7 @@ function archiveTopicMessages(topicId, topicTitle, options = {}) {
|
|
|
9271
9423
|
let path;
|
|
9272
9424
|
while (true) {
|
|
9273
9425
|
filename = `${safeTopic}_${date}${reasonSuffix}${counter === 1 ? "" : `_${counter}`}.jsonl`;
|
|
9274
|
-
path =
|
|
9426
|
+
path = join18(archiveDir, filename);
|
|
9275
9427
|
try {
|
|
9276
9428
|
writeFileSync8(path, body, { flag: "wx" });
|
|
9277
9429
|
break;
|
|
@@ -9316,7 +9468,7 @@ function archiveConversationEvents(topicId, topicTitle, userId, options = {}) {
|
|
|
9316
9468
|
const entries = readRawConversation(userId, topicTitle);
|
|
9317
9469
|
if (entries.length === 0)
|
|
9318
9470
|
return null;
|
|
9319
|
-
const archiveDir =
|
|
9471
|
+
const archiveDir = join18(getSharedWikiDir(), "archive");
|
|
9320
9472
|
mkdirSync10(archiveDir, { recursive: true });
|
|
9321
9473
|
const safeTopic = sanitizeTopicName(topicTitle, true);
|
|
9322
9474
|
const date = new Date().toISOString().slice(0, 10);
|
|
@@ -9344,7 +9496,7 @@ function archiveConversationEvents(topicId, topicTitle, userId, options = {}) {
|
|
|
9344
9496
|
let counter = 1;
|
|
9345
9497
|
while (true) {
|
|
9346
9498
|
const suffix = counter === 1 ? "" : `_${counter}`;
|
|
9347
|
-
const path =
|
|
9499
|
+
const path = join18(archiveDir, `${safeTopic}_${date}${reasonSuffix}_events${suffix}.jsonl`);
|
|
9348
9500
|
try {
|
|
9349
9501
|
writeFileSync8(path, body, { flag: "wx" });
|
|
9350
9502
|
logger.info({ topicId, topicTitle, archive: path, eventCount: entries.length }, "archiveConversationEvents: archived raw conversation events");
|
|
@@ -10255,8 +10407,8 @@ function createAskUserRuntime(host) {
|
|
|
10255
10407
|
return errorResult(`Error: failed to persist ask_user_question: ${error instanceof Error ? error.message : String(error)}`);
|
|
10256
10408
|
}
|
|
10257
10409
|
let resolveAnswer;
|
|
10258
|
-
const promise = new Promise((
|
|
10259
|
-
resolveAnswer =
|
|
10410
|
+
const promise = new Promise((resolve12) => {
|
|
10411
|
+
resolveAnswer = resolve12;
|
|
10260
10412
|
});
|
|
10261
10413
|
pendingAsks.set(message.id, {
|
|
10262
10414
|
topicId: ctx.topicId,
|
|
@@ -10510,11 +10662,11 @@ var init_manager_utils = () => {};
|
|
|
10510
10662
|
// ../../packages/core/src/platform/playwright/browser-processes.ts
|
|
10511
10663
|
import { execFileSync as execFileSync6 } from "child_process";
|
|
10512
10664
|
import { readdirSync as readdirSync3, unlinkSync as unlinkSync10 } from "fs";
|
|
10513
|
-
import { createServer } from "net";
|
|
10514
|
-
import { resolve as
|
|
10665
|
+
import { createServer as createServer2 } from "net";
|
|
10666
|
+
import { resolve as resolve13, sep } from "path";
|
|
10515
10667
|
function isPortInUse(port) {
|
|
10516
10668
|
return new Promise((resolveProbe) => {
|
|
10517
|
-
const server =
|
|
10669
|
+
const server = createServer2();
|
|
10518
10670
|
let settled = false;
|
|
10519
10671
|
const finish = (occupied) => {
|
|
10520
10672
|
if (settled)
|
|
@@ -10544,8 +10696,8 @@ async function reserveAvailableLoopbackPort(minPort, maxPort, reservedPorts, pro
|
|
|
10544
10696
|
return null;
|
|
10545
10697
|
}
|
|
10546
10698
|
function killBrowserProcsForUserDataDir(userDataDir) {
|
|
10547
|
-
const target =
|
|
10548
|
-
const profileRoot =
|
|
10699
|
+
const target = resolve13(userDataDir);
|
|
10700
|
+
const profileRoot = resolve13(BROWSER_PROFILES_DIR);
|
|
10549
10701
|
if (target !== profileRoot && !target.startsWith(`${profileRoot}${sep}`))
|
|
10550
10702
|
return;
|
|
10551
10703
|
let pids;
|
|
@@ -10566,7 +10718,7 @@ function killBrowserProcsForUserDataDir(userDataDir) {
|
|
|
10566
10718
|
stdio: "pipe"
|
|
10567
10719
|
}).toString().trim();
|
|
10568
10720
|
const argDir = extractUserDataDirArg(cmdline);
|
|
10569
|
-
if (!argDir ||
|
|
10721
|
+
if (!argDir || resolve13(argDir) !== target)
|
|
10570
10722
|
continue;
|
|
10571
10723
|
killProcessTreeChildren(pidNum);
|
|
10572
10724
|
process.kill(pidNum, "SIGKILL");
|
|
@@ -10577,13 +10729,13 @@ function killBrowserProcsForUserDataDir(userDataDir) {
|
|
|
10577
10729
|
}
|
|
10578
10730
|
}
|
|
10579
10731
|
function selectOrphanBrowserPids(procs, liveUserDataDirs, profileRoot, selfPid) {
|
|
10580
|
-
const root =
|
|
10581
|
-
const live = new Set([...liveUserDataDirs].map((d) =>
|
|
10732
|
+
const root = resolve13(profileRoot);
|
|
10733
|
+
const live = new Set([...liveUserDataDirs].map((d) => resolve13(d)));
|
|
10582
10734
|
const out = [];
|
|
10583
10735
|
for (const { pid, userDataDir } of procs) {
|
|
10584
10736
|
if (pid === selfPid || !userDataDir)
|
|
10585
10737
|
continue;
|
|
10586
|
-
const dir =
|
|
10738
|
+
const dir = resolve13(userDataDir);
|
|
10587
10739
|
if (dir !== root && !dir.startsWith(`${root}${sep}`))
|
|
10588
10740
|
continue;
|
|
10589
10741
|
if (live.has(dir))
|
|
@@ -10599,7 +10751,7 @@ function reapOrphanBrowsers(liveUserDataDirs) {
|
|
|
10599
10751
|
const daemonLease = getRuntimeProcessLease("node-daemon", Date.now(), Number.POSITIVE_INFINITY);
|
|
10600
10752
|
if (!isBrowserJanitorOwner(daemonLease?.pid ?? null, process.pid))
|
|
10601
10753
|
return;
|
|
10602
|
-
const profileRoot =
|
|
10754
|
+
const profileRoot = resolve13(BROWSER_PROFILES_DIR);
|
|
10603
10755
|
let pids;
|
|
10604
10756
|
try {
|
|
10605
10757
|
pids = execFileSync6("pgrep", ["-f", "--", profileRoot], { stdio: "pipe" }).toString().trim();
|
|
@@ -10638,7 +10790,7 @@ function cleanSingletonFiles(userDataDir) {
|
|
|
10638
10790
|
for (const f of files) {
|
|
10639
10791
|
if (f.startsWith("Singleton")) {
|
|
10640
10792
|
try {
|
|
10641
|
-
unlinkSync10(
|
|
10793
|
+
unlinkSync10(resolve13(userDataDir, f));
|
|
10642
10794
|
logger.info({ file: f, userDataDir }, "Removed stale Singleton file");
|
|
10643
10795
|
} catch (e) {
|
|
10644
10796
|
logger.warn({ err: e, file: f }, "Failed to remove stale Chrome Singleton file");
|
|
@@ -10678,9 +10830,9 @@ var init_browser_processes = __esm(async () => {
|
|
|
10678
10830
|
|
|
10679
10831
|
// ../../packages/core/src/platform/playwright/headed-launch.ts
|
|
10680
10832
|
import { accessSync as accessSync2, constants as constants2 } from "fs";
|
|
10681
|
-
import { delimiter, isAbsolute as isAbsolute4, resolve as
|
|
10833
|
+
import { delimiter, isAbsolute as isAbsolute4, resolve as resolve14 } from "path";
|
|
10682
10834
|
function findExecutableOnPath(command, environment = process.env) {
|
|
10683
|
-
const candidates = isAbsolute4(command) ? [command] : (environment.PATH ?? "").split(delimiter).filter(Boolean).map((directory) =>
|
|
10835
|
+
const candidates = isAbsolute4(command) ? [command] : (environment.PATH ?? "").split(delimiter).filter(Boolean).map((directory) => resolve14(directory, command));
|
|
10684
10836
|
for (const candidate of candidates) {
|
|
10685
10837
|
try {
|
|
10686
10838
|
accessSync2(candidate, constants2.X_OK);
|
|
@@ -10778,11 +10930,11 @@ var init_vault_public = __esm(async () => {
|
|
|
10778
10930
|
});
|
|
10779
10931
|
|
|
10780
10932
|
// ../../packages/core/src/platform/playwright/vault-broker.ts
|
|
10781
|
-
import { randomBytes as
|
|
10933
|
+
import { randomBytes as randomBytes6, timingSafeEqual as timingSafeEqual2 } from "crypto";
|
|
10782
10934
|
import { chmodSync as chmodSync4 } from "fs";
|
|
10783
|
-
import { createServer as
|
|
10784
|
-
import { tmpdir as
|
|
10785
|
-
import { join as
|
|
10935
|
+
import { createServer as createServer3 } from "net";
|
|
10936
|
+
import { tmpdir as tmpdir3 } from "os";
|
|
10937
|
+
import { join as join19 } from "path";
|
|
10786
10938
|
function deepMapStrings2(value, transform) {
|
|
10787
10939
|
if (typeof value === "string")
|
|
10788
10940
|
return transform(value);
|
|
@@ -10868,8 +11020,8 @@ function authorized(actual, expected) {
|
|
|
10868
11020
|
return left.length === right.length && timingSafeEqual2(left, right);
|
|
10869
11021
|
}
|
|
10870
11022
|
async function createBrowserVaultBroker(userId) {
|
|
10871
|
-
const token =
|
|
10872
|
-
const socketPath =
|
|
11023
|
+
const token = randomBytes6(32).toString("hex");
|
|
11024
|
+
const socketPath = join19(process.platform === "win32" ? tmpdir3() : "/tmp", `negotium-browser-vault-${process.pid}-${randomBytes6(8).toString("hex")}.sock`);
|
|
10873
11025
|
const retainedForms = new Map;
|
|
10874
11026
|
const leases = new Map;
|
|
10875
11027
|
const sockets = new Set;
|
|
@@ -10908,7 +11060,7 @@ async function createBrowserVaultBroker(userId) {
|
|
|
10908
11060
|
return result.text;
|
|
10909
11061
|
});
|
|
10910
11062
|
const prepared = prepareInput(request.tool, substituted);
|
|
10911
|
-
const lease =
|
|
11063
|
+
const lease = randomBytes6(24).toString("hex");
|
|
10912
11064
|
leases.set(lease, { boundary: prepared.boundary, createdAt: Date.now() });
|
|
10913
11065
|
return {
|
|
10914
11066
|
id,
|
|
@@ -10940,7 +11092,7 @@ async function createBrowserVaultBroker(userId) {
|
|
|
10940
11092
|
}
|
|
10941
11093
|
return { id, ok: false, error: "unknown operation" };
|
|
10942
11094
|
};
|
|
10943
|
-
const server =
|
|
11095
|
+
const server = createServer3((socket) => {
|
|
10944
11096
|
sockets.add(socket);
|
|
10945
11097
|
let pending = "";
|
|
10946
11098
|
socket.setEncoding("utf8");
|
|
@@ -11068,24 +11220,24 @@ var init_browser_profiles = __esm(async () => {
|
|
|
11068
11220
|
|
|
11069
11221
|
// ../../packages/core/src/platform/playwright/manager.ts
|
|
11070
11222
|
import { execFileSync as execFileSync7, spawn as spawn5 } from "child_process";
|
|
11071
|
-
import { createHash as createHash4, randomBytes as
|
|
11223
|
+
import { createHash as createHash4, randomBytes as randomBytes7, timingSafeEqual as timingSafeEqual3 } from "crypto";
|
|
11072
11224
|
import {
|
|
11073
11225
|
cpSync,
|
|
11074
|
-
existsSync as
|
|
11226
|
+
existsSync as existsSync18,
|
|
11075
11227
|
mkdirSync as mkdirSync11,
|
|
11076
11228
|
readFileSync as readFileSync15,
|
|
11077
11229
|
rmSync as rmSync3,
|
|
11078
11230
|
unlinkSync as unlinkSync11,
|
|
11079
11231
|
writeFileSync as writeFileSync9
|
|
11080
11232
|
} from "fs";
|
|
11081
|
-
import { dirname as
|
|
11233
|
+
import { dirname as dirname12, join as join20, resolve as resolve15 } from "path";
|
|
11082
11234
|
function removeDefaultProfileDataDir(userDataDir) {
|
|
11083
|
-
const root =
|
|
11084
|
-
const target =
|
|
11085
|
-
if (
|
|
11235
|
+
const root = resolve15(BROWSER_PROFILES_DIR);
|
|
11236
|
+
const target = resolve15(userDataDir);
|
|
11237
|
+
if (dirname12(target) !== root) {
|
|
11086
11238
|
throw new Error(`Refusing to delete browser profile outside managed root: ${target}`);
|
|
11087
11239
|
}
|
|
11088
|
-
const existed =
|
|
11240
|
+
const existed = existsSync18(target);
|
|
11089
11241
|
rmSync3(target, { recursive: true, force: true });
|
|
11090
11242
|
return existed;
|
|
11091
11243
|
}
|
|
@@ -11168,14 +11320,14 @@ function portFileName(instanceKey) {
|
|
|
11168
11320
|
function writePortFile(instanceKey, port) {
|
|
11169
11321
|
try {
|
|
11170
11322
|
mkdirSync11(managerHost.portsDir, { recursive: true });
|
|
11171
|
-
writeFileSync9(
|
|
11323
|
+
writeFileSync9(join20(managerHost.portsDir, portFileName(instanceKey)), String(port));
|
|
11172
11324
|
} catch (e) {
|
|
11173
11325
|
logger.warn({ err: e, instanceKey, port }, "Failed to save playwright port file");
|
|
11174
11326
|
}
|
|
11175
11327
|
}
|
|
11176
11328
|
function deletePortFile(instanceKey) {
|
|
11177
11329
|
try {
|
|
11178
|
-
unlinkSync11(
|
|
11330
|
+
unlinkSync11(join20(managerHost.portsDir, portFileName(instanceKey)));
|
|
11179
11331
|
} catch (e) {
|
|
11180
11332
|
if (e.code === "ENOENT")
|
|
11181
11333
|
return;
|
|
@@ -11299,7 +11451,7 @@ function releasePort(port) {
|
|
|
11299
11451
|
usedPorts.delete(port);
|
|
11300
11452
|
}
|
|
11301
11453
|
function defaultProfileDir(_ownerId, profile) {
|
|
11302
|
-
return
|
|
11454
|
+
return resolve15(BROWSER_PROFILES_DIR, profile);
|
|
11303
11455
|
}
|
|
11304
11456
|
function resolveUserDataDir(instanceKey) {
|
|
11305
11457
|
return managerHost.resolveInstanceDataDir(instanceKey);
|
|
@@ -11391,8 +11543,8 @@ async function spawnPlaywright(instanceKey, ownerId, reservedPort, browserBin =
|
|
|
11391
11543
|
releasePort(port);
|
|
11392
11544
|
throw new Error("Browser.rs managed mode does not support authenticated egress proxies");
|
|
11393
11545
|
}
|
|
11394
|
-
const capability =
|
|
11395
|
-
const spawnNonce =
|
|
11546
|
+
const capability = randomBytes7(32).toString("hex");
|
|
11547
|
+
const spawnNonce = randomBytes7(32).toString("hex");
|
|
11396
11548
|
let vaultBroker;
|
|
11397
11549
|
try {
|
|
11398
11550
|
vaultBroker = await createBrowserVaultBroker(ownerId);
|
|
@@ -11660,14 +11812,14 @@ async function cloneProfileForChild(opts) {
|
|
|
11660
11812
|
killInstance(dstKey);
|
|
11661
11813
|
await delay(500);
|
|
11662
11814
|
}
|
|
11663
|
-
if (!
|
|
11815
|
+
if (!existsSync18(srcDir)) {
|
|
11664
11816
|
return { copied: false, srcDir, dstDir, reason: "src-missing" };
|
|
11665
11817
|
}
|
|
11666
11818
|
try {
|
|
11667
|
-
if (
|
|
11819
|
+
if (existsSync18(dstDir)) {
|
|
11668
11820
|
rmSync3(dstDir, { recursive: true, force: true });
|
|
11669
11821
|
}
|
|
11670
|
-
mkdirSync11(
|
|
11822
|
+
mkdirSync11(dirname12(dstDir), { recursive: true });
|
|
11671
11823
|
if (process.platform === "darwin") {
|
|
11672
11824
|
try {
|
|
11673
11825
|
execFileSync7("cp", ["-cR", srcDir, dstDir], { stdio: "pipe" });
|
|
@@ -11685,7 +11837,7 @@ async function cloneProfileForChild(opts) {
|
|
|
11685
11837
|
cleanSingletonFiles(dstDir);
|
|
11686
11838
|
for (const f of ["DevToolsActivePort", "LOCK"]) {
|
|
11687
11839
|
try {
|
|
11688
|
-
unlinkSync11(
|
|
11840
|
+
unlinkSync11(resolve15(dstDir, f));
|
|
11689
11841
|
} catch {}
|
|
11690
11842
|
}
|
|
11691
11843
|
logger.info({ srcKey, dstKey, srcDir, dstDir }, "Cloned Playwright profile for child topic");
|
|
@@ -11813,7 +11965,7 @@ RULES:
|
|
|
11813
11965
|
|
|
11814
11966
|
// ../../packages/core/src/agents/topic-cleanup.ts
|
|
11815
11967
|
import { mkdirSync as mkdirSync12, renameSync as renameSync6, unlinkSync as unlinkSync12, writeFileSync as writeFileSync10 } from "fs";
|
|
11816
|
-
import { dirname as
|
|
11968
|
+
import { dirname as dirname13 } from "path";
|
|
11817
11969
|
function collectSessionIdsByAgent(entries, extraSessions = []) {
|
|
11818
11970
|
const out = new Map;
|
|
11819
11971
|
for (const e of entries) {
|
|
@@ -11879,7 +12031,7 @@ function createTopicLogMaintenance(host) {
|
|
|
11879
12031
|
const path = runtimeHost.activeConversationPath(opts.userId, opts.topicName);
|
|
11880
12032
|
const tempPath = `${path}.${process.pid}.${Date.now()}.tmp`;
|
|
11881
12033
|
try {
|
|
11882
|
-
mkdirSync12(
|
|
12034
|
+
mkdirSync12(dirname13(path), { recursive: true });
|
|
11883
12035
|
writeFileSync10(tempPath, retained.length > 0 ? `${retained.map((entry) => JSON.stringify(entry)).join(`
|
|
11884
12036
|
`)}
|
|
11885
12037
|
` : "", { flag: "wx" });
|
|
@@ -12333,8 +12485,8 @@ var init_runtime_turn_requests = __esm(async () => {
|
|
|
12333
12485
|
// ../../packages/core/src/topics/session.ts
|
|
12334
12486
|
import { randomUUID as randomUUID11 } from "crypto";
|
|
12335
12487
|
import { mkdtempSync as mkdtempSync2, rmSync as rmSync4, writeFileSync as writeFileSync11 } from "fs";
|
|
12336
|
-
import { tmpdir as
|
|
12337
|
-
import { join as
|
|
12488
|
+
import { tmpdir as tmpdir4 } from "os";
|
|
12489
|
+
import { join as join21 } from "path";
|
|
12338
12490
|
function previousCompactedSummary(entries) {
|
|
12339
12491
|
for (let index = entries.length - 2;index >= 0; index -= 1) {
|
|
12340
12492
|
const request = entries[index]?.event;
|
|
@@ -12464,7 +12616,7 @@ function formatCompactElapsed(startedAt) {
|
|
|
12464
12616
|
async function summarizeTopicContext(request) {
|
|
12465
12617
|
const startedAt = Date.now();
|
|
12466
12618
|
const sessionIds = [];
|
|
12467
|
-
const compactCwd = mkdtempSync2(
|
|
12619
|
+
const compactCwd = mkdtempSync2(join21(tmpdir4(), "negotium-compact-"));
|
|
12468
12620
|
const abortController = new AbortController;
|
|
12469
12621
|
const relayAbort = () => abortController.abort(request.signal?.reason);
|
|
12470
12622
|
if (request.signal?.aborted)
|
|
@@ -12491,7 +12643,7 @@ async function summarizeTopicContext(request) {
|
|
|
12491
12643
|
let error = "";
|
|
12492
12644
|
let toolViolation = false;
|
|
12493
12645
|
let compactionLogCalls = 0;
|
|
12494
|
-
const compactionLogPath =
|
|
12646
|
+
const compactionLogPath = join21(compactCwd, "conversation.log");
|
|
12495
12647
|
try {
|
|
12496
12648
|
const compactionMcp = useCompactionLog ? {
|
|
12497
12649
|
compact_log: {
|
|
@@ -13110,14 +13262,14 @@ var init_derive = __esm(async () => {
|
|
|
13110
13262
|
});
|
|
13111
13263
|
|
|
13112
13264
|
// ../../packages/core/src/query/session-inbox-path.ts
|
|
13113
|
-
import { join as
|
|
13265
|
+
import { join as join22 } from "path";
|
|
13114
13266
|
function sessionInboxPath(userId, topicId) {
|
|
13115
13267
|
const key = Buffer.from(topicId, "utf8").toString("base64url");
|
|
13116
|
-
return
|
|
13268
|
+
return join22(SESSION_INBOX_DIR, userId, `${TOPIC_ID_FILE_PREFIX}${key}${JSONL_SUFFIX}`);
|
|
13117
13269
|
}
|
|
13118
13270
|
function scheduledSessionInboxPath(userId, topicId) {
|
|
13119
13271
|
const key = Buffer.from(topicId, "utf8").toString("base64url");
|
|
13120
|
-
return
|
|
13272
|
+
return join22(SESSION_INBOX_DIR, userId, `${TOPIC_ID_FILE_PREFIX}${key}${SCHEDULE_SUFFIX}`);
|
|
13121
13273
|
}
|
|
13122
13274
|
var TOPIC_ID_FILE_PREFIX = "topic-id-", JSONL_SUFFIX = ".jsonl", SCHEDULE_SUFFIX = ".schedule";
|
|
13123
13275
|
var init_session_inbox_path = __esm(() => {
|
|
@@ -13126,13 +13278,13 @@ var init_session_inbox_path = __esm(() => {
|
|
|
13126
13278
|
|
|
13127
13279
|
// ../../packages/core/src/query/session-inbox-cleanup.ts
|
|
13128
13280
|
import { unlinkSync as unlinkSync14 } from "fs";
|
|
13129
|
-
import { basename as basename3, join as
|
|
13281
|
+
import { basename as basename3, join as join23 } from "path";
|
|
13130
13282
|
function cleanupSessionInboxFiles(userId, topicId, legacyTopicTitle) {
|
|
13131
13283
|
const live = sessionInboxPath(userId, topicId);
|
|
13132
13284
|
const scheduled = scheduledSessionInboxPath(userId, topicId);
|
|
13133
13285
|
const candidates = new Set([live, `${live}.processing`, scheduled, `${scheduled}.processing`]);
|
|
13134
13286
|
if (legacyTopicTitle && legacyTopicTitle !== "." && legacyTopicTitle !== ".." && basename3(legacyTopicTitle) === legacyTopicTitle) {
|
|
13135
|
-
const legacyBase =
|
|
13287
|
+
const legacyBase = join23(SESSION_INBOX_DIR, userId, legacyTopicTitle);
|
|
13136
13288
|
for (const suffix of [".jsonl", ".jsonl.processing", ".schedule", ".schedule.processing"]) {
|
|
13137
13289
|
candidates.add(`${legacyBase}${suffix}`);
|
|
13138
13290
|
}
|
|
@@ -13158,16 +13310,16 @@ var init_session_inbox_cleanup = __esm(() => {
|
|
|
13158
13310
|
|
|
13159
13311
|
// ../../packages/core/src/query/state.ts
|
|
13160
13312
|
import { mkdirSync as mkdirSync14, renameSync as renameSync7, unlinkSync as unlinkSync15, writeFileSync as writeFileSync12 } from "fs";
|
|
13161
|
-
import { basename as basename4, join as
|
|
13313
|
+
import { basename as basename4, join as join24 } from "path";
|
|
13162
13314
|
function createQueryStateStore(options) {
|
|
13163
13315
|
const sanitize = options.sanitizeTopicId ?? sanitizeId;
|
|
13164
|
-
const queryStateDirPath = (userId) =>
|
|
13165
|
-
const queryStateFile = (userId, topicId) =>
|
|
13316
|
+
const queryStateDirPath = (userId) => join24(options.usersLogDir, String(userId), "active-queries");
|
|
13317
|
+
const queryStateFile = (userId, topicId) => join24(queryStateDirPath(userId), `${sanitize(topicId)}.json`);
|
|
13166
13318
|
const legacyQueryStateFile = (userId, topicName) => {
|
|
13167
13319
|
if (!topicName || topicName === "." || topicName === ".." || basename4(topicName) !== topicName) {
|
|
13168
13320
|
return null;
|
|
13169
13321
|
}
|
|
13170
|
-
return
|
|
13322
|
+
return join24(queryStateDirPath(userId), `${topicName}.json`);
|
|
13171
13323
|
};
|
|
13172
13324
|
return {
|
|
13173
13325
|
write(userId, topicId, topicName, task) {
|
|
@@ -13328,30 +13480,30 @@ import {
|
|
|
13328
13480
|
unlinkSync as unlinkSync16,
|
|
13329
13481
|
writeFileSync as writeFileSync13
|
|
13330
13482
|
} from "fs";
|
|
13331
|
-
import { dirname as
|
|
13483
|
+
import { dirname as dirname14, join as join25 } from "path";
|
|
13332
13484
|
function pendingAskDir(userId) {
|
|
13333
13485
|
const rawUserId = String(userId);
|
|
13334
13486
|
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
|
|
13487
|
+
return join25(resolveStorageSessionAsksDir(), safeUserId);
|
|
13336
13488
|
}
|
|
13337
13489
|
function encodeAskKey(key) {
|
|
13338
13490
|
return JSON.stringify([key.from, key.to]);
|
|
13339
13491
|
}
|
|
13340
13492
|
function pendingAskPath(key) {
|
|
13341
13493
|
const digest = createHash6("sha256").update(encodeAskKey(key)).digest("hex");
|
|
13342
|
-
return
|
|
13494
|
+
return join25(pendingAskDir(key.userId), `${ASK_FILENAME_PREFIX}${digest}.pending`);
|
|
13343
13495
|
}
|
|
13344
13496
|
function v2PendingAskPath(key) {
|
|
13345
13497
|
const encoded = Buffer.from(encodeAskKey(key), "utf8").toString("base64url");
|
|
13346
|
-
return
|
|
13498
|
+
return join25(pendingAskDir(key.userId), `${V2_ASK_FILENAME_PREFIX}${encoded}.pending`);
|
|
13347
13499
|
}
|
|
13348
13500
|
function legacyPendingAskPath(key) {
|
|
13349
13501
|
if (key.from.includes("/") || key.from.includes("\\") || key.to.includes("/") || key.to.includes("\\") || key.from.includes("\x00") || key.to.includes("\x00")) {
|
|
13350
13502
|
return null;
|
|
13351
13503
|
}
|
|
13352
13504
|
const dir = pendingAskDir(key.userId);
|
|
13353
|
-
const candidate =
|
|
13354
|
-
return
|
|
13505
|
+
const candidate = join25(dir, `${key.from}___${key.to}.pending`);
|
|
13506
|
+
return dirname14(candidate) === dir ? candidate : null;
|
|
13355
13507
|
}
|
|
13356
13508
|
function parsePendingAskFilename(fileName) {
|
|
13357
13509
|
if (!fileName.endsWith(".pending"))
|
|
@@ -13591,7 +13743,7 @@ function listPendingAsksForCaller(args) {
|
|
|
13591
13743
|
const parsed = isV3 ? { from: args.from, to: "" } : parsePendingAskFilename(fileName);
|
|
13592
13744
|
if (!parsed)
|
|
13593
13745
|
continue;
|
|
13594
|
-
const path =
|
|
13746
|
+
const path = join25(dir, fileName);
|
|
13595
13747
|
const record = readPendingAskFile(path, {
|
|
13596
13748
|
userId: args.userId,
|
|
13597
13749
|
from: parsed.from,
|
|
@@ -13633,7 +13785,7 @@ function deletePendingAsksForTopic(args) {
|
|
|
13633
13785
|
}
|
|
13634
13786
|
let deleted = 0;
|
|
13635
13787
|
for (const fileName of files) {
|
|
13636
|
-
const path =
|
|
13788
|
+
const path = join25(dir, fileName);
|
|
13637
13789
|
const parsed = parsePendingAskFilename(fileName);
|
|
13638
13790
|
const record = readPendingAskFile(path, {
|
|
13639
13791
|
userId: args.userId,
|
|
@@ -14033,7 +14185,7 @@ body{font-family:system-ui,-apple-system,"Segoe UI",sans-serif;background:var(--
|
|
|
14033
14185
|
// ../../packages/core/src/storage/token-stats.ts
|
|
14034
14186
|
import { createHash as createHash7 } from "crypto";
|
|
14035
14187
|
import { mkdirSync as mkdirSync16, writeFileSync as writeFileSync14 } from "fs";
|
|
14036
|
-
import { join as
|
|
14188
|
+
import { join as join26 } from "path";
|
|
14037
14189
|
function tokenStatsFileId(userId) {
|
|
14038
14190
|
const rawUserId = String(userId);
|
|
14039
14191
|
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 +14194,7 @@ function queriesPath(userId) {
|
|
|
14042
14194
|
const fileId = tokenStatsFileId(userId);
|
|
14043
14195
|
const logDir = resolveStorageLogDir();
|
|
14044
14196
|
mkdirSync16(logDir, { recursive: true });
|
|
14045
|
-
return
|
|
14197
|
+
return join26(logDir, `token-queries-${fileId}.jsonl`);
|
|
14046
14198
|
}
|
|
14047
14199
|
function estimateUsageCost(agent, model, usage) {
|
|
14048
14200
|
const prices = TOKEN_PRICES[`${agent}:${model}`];
|
|
@@ -14358,7 +14510,7 @@ var init_lifecycle = __esm(async () => {
|
|
|
14358
14510
|
// ../../packages/core/src/runtime/attachments.ts
|
|
14359
14511
|
import { randomUUID as randomUUID14 } from "crypto";
|
|
14360
14512
|
import { copyFileSync as copyFileSync2, mkdirSync as mkdirSync17, writeFileSync as writeFileSync15 } from "fs";
|
|
14361
|
-
import { basename as basename5, join as
|
|
14513
|
+
import { basename as basename5, join as join27 } from "path";
|
|
14362
14514
|
function workspaceCwdFor(topicId) {
|
|
14363
14515
|
return resolveTopicWorkspaceDir(topicId);
|
|
14364
14516
|
}
|
|
@@ -14371,7 +14523,7 @@ function materializePromptAttachments(topicId, queryId, attachmentIds) {
|
|
|
14371
14523
|
if (!attachmentIds?.length)
|
|
14372
14524
|
return [];
|
|
14373
14525
|
const out = [];
|
|
14374
|
-
const destDir =
|
|
14526
|
+
const destDir = join27(workspaceCwdFor(topicId), "attachments", queryId);
|
|
14375
14527
|
for (const rawId of attachmentIds) {
|
|
14376
14528
|
if (typeof rawId !== "string")
|
|
14377
14529
|
continue;
|
|
@@ -14388,7 +14540,7 @@ function materializePromptAttachments(topicId, queryId, attachmentIds) {
|
|
|
14388
14540
|
mkdirSync17(destDir, { recursive: true });
|
|
14389
14541
|
const index = String(out.length + 1).padStart(2, "0");
|
|
14390
14542
|
const safeName = safeAttachmentFilename(attachment.filename, fileId);
|
|
14391
|
-
const destPath =
|
|
14543
|
+
const destPath = join27(destDir, `${index}-${fileId.slice(0, 8)}-${safeName}`);
|
|
14392
14544
|
copyFileSync2(sourcePath, destPath);
|
|
14393
14545
|
out.push({
|
|
14394
14546
|
id: attachment.id,
|
|
@@ -14418,10 +14570,10 @@ function promptWithAttachments(prompt, attachments) {
|
|
|
14418
14570
|
return composeAttachmentPrompt(prompt, attachments.map(({ filename, path }) => attachmentPromptLine(filename, path)));
|
|
14419
14571
|
}
|
|
14420
14572
|
function ingestAttachment(args) {
|
|
14421
|
-
const destDir =
|
|
14573
|
+
const destDir = join27(UPLOADS_DIR, args.topicId);
|
|
14422
14574
|
mkdirSync17(destDir, { recursive: true });
|
|
14423
14575
|
const safeName = safeAttachmentFilename(args.filename, "upload");
|
|
14424
|
-
const destPath =
|
|
14576
|
+
const destPath = join27(destDir, `${Date.now()}-${randomUUID14().slice(0, 8)}-${safeName}`);
|
|
14425
14577
|
if (args.sourcePath !== undefined) {
|
|
14426
14578
|
copyFileSync2(args.sourcePath, destPath);
|
|
14427
14579
|
} else if (args.bytes !== undefined) {
|
|
@@ -14596,12 +14748,12 @@ var init_errors = __esm(() => {
|
|
|
14596
14748
|
|
|
14597
14749
|
// ../../packages/core/src/runtime/event-heartbeat.ts
|
|
14598
14750
|
function nextOrHeartbeat(pending, intervalMs) {
|
|
14599
|
-
return new Promise((
|
|
14600
|
-
const timer = setTimeout(() =>
|
|
14751
|
+
return new Promise((resolve16, reject) => {
|
|
14752
|
+
const timer = setTimeout(() => resolve16({ kind: "heartbeat" }), intervalMs);
|
|
14601
14753
|
timer.unref?.();
|
|
14602
14754
|
pending.then((result) => {
|
|
14603
14755
|
clearTimeout(timer);
|
|
14604
|
-
|
|
14756
|
+
resolve16({ kind: "event", result });
|
|
14605
14757
|
}, (error) => {
|
|
14606
14758
|
clearTimeout(timer);
|
|
14607
14759
|
reject(error);
|
|
@@ -14922,7 +15074,7 @@ var init_visual_html = __esm(() => {
|
|
|
14922
15074
|
|
|
14923
15075
|
// ../../packages/core/src/runtime/visuals.ts
|
|
14924
15076
|
import { realpathSync as realpathSync4 } from "fs";
|
|
14925
|
-
import { isAbsolute as isAbsolute5, resolve as
|
|
15077
|
+
import { isAbsolute as isAbsolute5, resolve as resolve16 } from "path";
|
|
14926
15078
|
function activeVisualHtmlForPrompt(html) {
|
|
14927
15079
|
if (html.length <= ACTIVE_VISUAL_PROMPT_MAX_CHARS) {
|
|
14928
15080
|
return { html, omittedChars: 0 };
|
|
@@ -14973,8 +15125,8 @@ function topicAllowsVisualFileId(topicId, fileId) {
|
|
|
14973
15125
|
return topicHasAttachmentFileId(topicId, fileId) || topicHasVisualFileId(topicId, fileId);
|
|
14974
15126
|
}
|
|
14975
15127
|
function isPathInside(baseDir, filePath) {
|
|
14976
|
-
const base =
|
|
14977
|
-
const normalized =
|
|
15128
|
+
const base = resolve16(baseDir);
|
|
15129
|
+
const normalized = resolve16(filePath);
|
|
14978
15130
|
try {
|
|
14979
15131
|
const realBase = realpathSync4(base);
|
|
14980
15132
|
const real = realpathSync4(normalized);
|
|
@@ -15036,7 +15188,7 @@ function resolveVisualMediaInput(topicId, input) {
|
|
|
15036
15188
|
}
|
|
15037
15189
|
const rawPath = input.file_path.trim();
|
|
15038
15190
|
const cwd = workspaceCwdFor(topicId);
|
|
15039
|
-
const candidate = isAbsolute5(rawPath) ? rawPath :
|
|
15191
|
+
const candidate = isAbsolute5(rawPath) ? rawPath : resolve16(cwd, rawPath);
|
|
15040
15192
|
if (!isPathInside(cwd, candidate)) {
|
|
15041
15193
|
return { error: "file_path must be inside the topic workspace" };
|
|
15042
15194
|
}
|
|
@@ -15074,7 +15226,7 @@ var init_visuals = __esm(async () => {
|
|
|
15074
15226
|
// ../../packages/core/src/runtime/turn-event-stream.ts
|
|
15075
15227
|
import { randomUUID as randomUUID15 } from "crypto";
|
|
15076
15228
|
import { realpathSync as realpathSync5, statSync as statSync9 } from "fs";
|
|
15077
|
-
import { isAbsolute as isAbsolute6, resolve as
|
|
15229
|
+
import { isAbsolute as isAbsolute6, resolve as resolve17 } from "path";
|
|
15078
15230
|
function sessionEventMatchesCurrentExecution(topicId, queryId, agent, model) {
|
|
15079
15231
|
if (getRoomQuery(topicId)?.queryId !== queryId)
|
|
15080
15232
|
return false;
|
|
@@ -15427,7 +15579,7 @@ ${JSON.stringify(event.input ?? {})}`);
|
|
|
15427
15579
|
case "file":
|
|
15428
15580
|
if (!silent && peerBridge) {
|
|
15429
15581
|
const cwd = workspaceCwdFor(topicId);
|
|
15430
|
-
const path = isAbsolute6(event.path) ? event.path :
|
|
15582
|
+
const path = isAbsolute6(event.path) ? event.path : resolve17(cwd, event.path);
|
|
15431
15583
|
if (!isPathInside(cwd, path)) {
|
|
15432
15584
|
logger.warn({ topicId, path }, "peer output file is outside the topic workspace");
|
|
15433
15585
|
break;
|
|
@@ -15709,15 +15861,15 @@ var init_turn_session = __esm(async () => {
|
|
|
15709
15861
|
});
|
|
15710
15862
|
|
|
15711
15863
|
// ../../packages/core/src/storage/app-settings.ts
|
|
15712
|
-
import { existsSync as
|
|
15713
|
-
import { dirname as
|
|
15864
|
+
import { existsSync as existsSync19, mkdirSync as mkdirSync18, readFileSync as readFileSync17, writeFileSync as writeFileSync16 } from "fs";
|
|
15865
|
+
import { dirname as dirname15, join as join28 } from "path";
|
|
15714
15866
|
function settingsFile() {
|
|
15715
|
-
return
|
|
15867
|
+
return join28(resolveStorageDataDir(), "otium-settings.json");
|
|
15716
15868
|
}
|
|
15717
15869
|
function getGlobalAiName() {
|
|
15718
15870
|
const path = settingsFile();
|
|
15719
15871
|
try {
|
|
15720
|
-
if (
|
|
15872
|
+
if (existsSync19(path)) {
|
|
15721
15873
|
const data = JSON.parse(readFileSync17(path, "utf8"));
|
|
15722
15874
|
if (typeof data.aiName === "string" && data.aiName.trim()) {
|
|
15723
15875
|
return data.aiName.trim();
|
|
@@ -15806,8 +15958,8 @@ __export(exports_turn_runner, {
|
|
|
15806
15958
|
AGENT_DISPLAY_NAME: () => AGENT_DISPLAY_NAME
|
|
15807
15959
|
});
|
|
15808
15960
|
import { randomUUID as randomUUID16 } from "crypto";
|
|
15809
|
-
import { existsSync as
|
|
15810
|
-
import { join as
|
|
15961
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync19, readdirSync as readdirSync5, statSync as statSync10 } from "fs";
|
|
15962
|
+
import { join as join29 } from "path";
|
|
15811
15963
|
function withDefaultPlaywright(configuredMcp, isManager) {
|
|
15812
15964
|
if (isManager)
|
|
15813
15965
|
return configuredMcp;
|
|
@@ -15862,8 +16014,8 @@ function appendAskReplyMessage(topicId, text2, agentType) {
|
|
|
15862
16014
|
return message;
|
|
15863
16015
|
}
|
|
15864
16016
|
function resolveWikiMirrorPath(directory, preferredFilename, matchesLegacyId, matchesTitle, preferExact = true) {
|
|
15865
|
-
const preferred =
|
|
15866
|
-
if (preferExact &&
|
|
16017
|
+
const preferred = join29(directory, preferredFilename);
|
|
16018
|
+
if (preferExact && existsSync20(preferred))
|
|
15867
16019
|
return preferred;
|
|
15868
16020
|
let newestLegacyId = null;
|
|
15869
16021
|
let newestTitle = null;
|
|
@@ -15873,7 +16025,7 @@ function resolveWikiMirrorPath(directory, preferredFilename, matchesLegacyId, ma
|
|
|
15873
16025
|
const legacyIdMatch = !titleMatch && matchesLegacyId(filename);
|
|
15874
16026
|
if (!titleMatch && !legacyIdMatch)
|
|
15875
16027
|
continue;
|
|
15876
|
-
const path =
|
|
16028
|
+
const path = join29(directory, filename);
|
|
15877
16029
|
const mtimeMs = statSync10(path).mtimeMs;
|
|
15878
16030
|
if (titleMatch) {
|
|
15879
16031
|
if (!newestTitle || mtimeMs > newestTitle.mtimeMs) {
|
|
@@ -15887,10 +16039,10 @@ function resolveWikiMirrorPath(directory, preferredFilename, matchesLegacyId, ma
|
|
|
15887
16039
|
return newestTitle?.path ?? newestLegacyId?.path ?? preferred;
|
|
15888
16040
|
}
|
|
15889
16041
|
function resolveWikiMemoryMirror(wikiDir, topicId, topicTitle) {
|
|
15890
|
-
const briefFile = resolveWikiMirrorPath(
|
|
15891
|
-
const hasBriefFile =
|
|
15892
|
-
const latestSummaryCandidate = resolveWikiMirrorPath(
|
|
15893
|
-
const latestSummaryFile =
|
|
16042
|
+
const briefFile = resolveWikiMirrorPath(join29(wikiDir, "topic"), `${wikiBriefStorageKey(topicTitle, topicId)}.md`, (filename) => isTopicBriefFile(filename, topicId), (filename) => isTopicBriefFile(filename, topicId, topicTitle));
|
|
16043
|
+
const hasBriefFile = existsSync20(briefFile) && statSync10(briefFile).isFile();
|
|
16044
|
+
const latestSummaryCandidate = resolveWikiMirrorPath(join29(wikiDir, "summaries"), `__missing__-${wikiSummaryFilename("0000-00-00", topicTitle, topicId)}`, (filename) => isTopicSummaryFile(filename, topicId), (filename) => isTopicSummaryFile(filename, topicId, topicTitle), false);
|
|
16045
|
+
const latestSummaryFile = existsSync20(latestSummaryCandidate) && statSync10(latestSummaryCandidate).isFile() ? latestSummaryCandidate : null;
|
|
15894
16046
|
return { briefFile, hasBriefFile, latestSummaryFile };
|
|
15895
16047
|
}
|
|
15896
16048
|
async function streamAgentEvents(topicId, topicTitle, queryId, events, control, agentType, model, effort, userId, retryableSessionExpired = true, onSessionId, execution) {
|
|
@@ -17924,8 +18076,8 @@ init_common();
|
|
|
17924
18076
|
import { z as z2 } from "zod";
|
|
17925
18077
|
|
|
17926
18078
|
// ../../packages/core/src/agents/mcp-tools/inline-assets.ts
|
|
17927
|
-
import { existsSync as
|
|
17928
|
-
import { extname, isAbsolute as isAbsolute3, resolve as
|
|
18079
|
+
import { existsSync as existsSync17, readFileSync as readFileSync14, statSync as statSync7 } from "fs";
|
|
18080
|
+
import { extname, isAbsolute as isAbsolute3, resolve as resolve12 } from "path";
|
|
17929
18081
|
var MIME_BY_EXT = {
|
|
17930
18082
|
".apng": "image/apng",
|
|
17931
18083
|
".avif": "image/avif",
|
|
@@ -17970,10 +18122,10 @@ function inlineLocalAssets(html, options) {
|
|
|
17970
18122
|
const relPath = stripSuffix(ref);
|
|
17971
18123
|
if (!relPath)
|
|
17972
18124
|
return null;
|
|
17973
|
-
const abs = isAbsolute3(relPath) ? relPath :
|
|
18125
|
+
const abs = isAbsolute3(relPath) ? relPath : resolve12(baseDir, relPath);
|
|
17974
18126
|
let bytes;
|
|
17975
18127
|
try {
|
|
17976
|
-
if (!
|
|
18128
|
+
if (!existsSync17(abs) || !statSync7(abs).isFile()) {
|
|
17977
18129
|
unresolved.push(ref);
|
|
17978
18130
|
cache.set(ref, null);
|
|
17979
18131
|
return null;
|
|
@@ -18930,7 +19082,6 @@ var otiumVisualToolDefinitions = [
|
|
|
18930
19082
|
await init_task_events();
|
|
18931
19083
|
init_tool_format();
|
|
18932
19084
|
await init_topic_cleanup();
|
|
18933
|
-
init_vault_tool_policy();
|
|
18934
19085
|
export {
|
|
18935
19086
|
withTaskSnapshots,
|
|
18936
19087
|
withCodexSpawnSerial,
|
|
@@ -18945,23 +19096,19 @@ export {
|
|
|
18945
19096
|
showMermaidTool,
|
|
18946
19097
|
showImageTool,
|
|
18947
19098
|
showHtmlTool,
|
|
18948
|
-
shouldRedirectVaultTool,
|
|
18949
19099
|
rotateTopicLogs,
|
|
18950
19100
|
resolveTaskEventScope,
|
|
18951
19101
|
registerOwnedCodexPids,
|
|
18952
|
-
referencesRuntimeSecretStorage,
|
|
18953
19102
|
purgeTopicLogs,
|
|
18954
19103
|
otiumVisualToolDefinitions,
|
|
18955
19104
|
normalizeAskUserQuestionInput,
|
|
18956
19105
|
normalizeAskUserChoices,
|
|
18957
19106
|
killOwnedCodexTreesForShutdown,
|
|
18958
19107
|
killCodexTrees,
|
|
18959
|
-
isVaultBrokerTool,
|
|
18960
19108
|
formatToolUse,
|
|
18961
19109
|
forkAgentSession,
|
|
18962
19110
|
findNewCodexChildren,
|
|
18963
19111
|
defaultAskUserDurabilityHost,
|
|
18964
|
-
createVaultToolPolicy,
|
|
18965
19112
|
createTopicLogMaintenance,
|
|
18966
19113
|
createSubagentLifecycle,
|
|
18967
19114
|
createSelfConfigToolDefinitionsForCore,
|
|
@@ -18982,9 +19129,8 @@ export {
|
|
|
18982
19129
|
archiveActiveTopicForMemory,
|
|
18983
19130
|
acquireCodexSpawnLock,
|
|
18984
19131
|
VISUALS_MCP_KEY,
|
|
18985
|
-
VAULT_BROKER_REDIRECT_ERROR,
|
|
18986
19132
|
MIN_MEMORY_ARCHIVE_EXCHANGES,
|
|
18987
19133
|
DEFAULT_SELF_CONFIG_PRODUCT
|
|
18988
19134
|
};
|
|
18989
19135
|
|
|
18990
|
-
//# debugId=
|
|
19136
|
+
//# debugId=0CE166A02CA7806164756E2164756E21
|