negotium 0.1.21 → 0.1.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent-helpers.js +199 -203
- package/dist/agent-helpers.js.map +10 -10
- package/dist/cron.js +249 -223
- package/dist/cron.js.map +12 -12
- package/dist/hosted-agent.js +249 -253
- package/dist/hosted-agent.js.map +11 -11
- package/dist/main.js +409 -398
- package/dist/main.js.map +14 -14
- package/dist/runtime/scripts/browser-webauthn-policy.mjs +37 -0
- package/dist/runtime/scripts/mcp-patchright-http.mjs +8 -3
- package/dist/runtime/src/agents/claude-provider.ts +11 -5
- package/dist/runtime/src/agents/maestro-provider.ts +4 -1
- package/dist/runtime/src/agents/vault-tool-policy.ts +28 -4
- package/dist/runtime/src/platform/mcp-config.ts +2 -1
- package/dist/runtime/src/platform/playwright/manager.ts +18 -0
- package/dist/runtime/src/prompts/sessions/channel-system.md +1 -1
- package/dist/runtime/src/prompts/sessions/topic-system.md +1 -1
- package/dist/runtime/src/version.ts +1 -1
- package/dist/types/packages/core/src/agents/claude-provider.d.ts +1 -1
- package/dist/types/packages/core/src/agents/vault-tool-policy.d.ts +2 -1
- package/dist/types/packages/core/src/version.d.ts +1 -1
- package/package.json +1 -1
package/dist/cron.js
CHANGED
|
@@ -1831,202 +1831,15 @@ var init_sensitive_path = __esm(() => {
|
|
|
1831
1831
|
];
|
|
1832
1832
|
});
|
|
1833
1833
|
|
|
1834
|
-
// ../../packages/core/src/
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
return
|
|
1838
|
-
}
|
|
1839
|
-
function aad(userId, key) {
|
|
1840
|
-
return Buffer.from(`${userId}\x00${key.toUpperCase()}`, "utf8");
|
|
1841
|
-
}
|
|
1842
|
-
function isEncryptedVaultValue(value) {
|
|
1843
|
-
return value.startsWith(ENVELOPE_PREFIX);
|
|
1844
|
-
}
|
|
1845
|
-
function encryptVaultValue(userId, key, value, masterKey = VAULT_MASTER_KEY) {
|
|
1846
|
-
const iv = randomBytes3(IV_BYTES);
|
|
1847
|
-
const cipher = createCipheriv("aes-256-gcm", encryptionKey(masterKey), iv);
|
|
1848
|
-
cipher.setAAD(aad(userId, key));
|
|
1849
|
-
const ciphertext = Buffer.concat([cipher.update(value, "utf8"), cipher.final()]);
|
|
1850
|
-
const tag = cipher.getAuthTag();
|
|
1851
|
-
return `${ENVELOPE_PREFIX}${iv.toString("base64url")}.${ciphertext.toString("base64url")}.${tag.toString("base64url")}`;
|
|
1852
|
-
}
|
|
1853
|
-
function decryptVaultValue(userId, key, storedValue, masterKey = VAULT_MASTER_KEY) {
|
|
1854
|
-
if (!isEncryptedVaultValue(storedValue)) {
|
|
1855
|
-
return { value: storedValue, legacyPlaintext: true };
|
|
1856
|
-
}
|
|
1857
|
-
const encoded = storedValue.slice(ENVELOPE_PREFIX.length);
|
|
1858
|
-
const [ivPart, ciphertextPart, tagPart, ...extra] = encoded.split(".");
|
|
1859
|
-
if (!ivPart || ciphertextPart === undefined || !tagPart || extra.length > 0) {
|
|
1860
|
-
throw new Error("Invalid encrypted vault value");
|
|
1861
|
-
}
|
|
1862
|
-
const iv = Buffer.from(ivPart, "base64url");
|
|
1863
|
-
const ciphertext = Buffer.from(ciphertextPart, "base64url");
|
|
1864
|
-
const tag = Buffer.from(tagPart, "base64url");
|
|
1865
|
-
if (iv.length !== IV_BYTES || tag.length !== 16) {
|
|
1866
|
-
throw new Error("Invalid encrypted vault value");
|
|
1867
|
-
}
|
|
1868
|
-
const decipher = createDecipheriv("aes-256-gcm", encryptionKey(masterKey), iv);
|
|
1869
|
-
decipher.setAAD(aad(userId, key));
|
|
1870
|
-
decipher.setAuthTag(tag);
|
|
1871
|
-
const plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
|
|
1872
|
-
return { value: plaintext.toString("utf8"), legacyPlaintext: false };
|
|
1873
|
-
}
|
|
1874
|
-
var ENVELOPE_PREFIX = "otium-vault:v1:", IV_BYTES = 12, KEY_BYTES = 32;
|
|
1875
|
-
var init_vault_crypto = __esm(() => {
|
|
1876
|
-
init_config();
|
|
1877
|
-
});
|
|
1878
|
-
|
|
1879
|
-
// ../../packages/core/src/storage/vault.ts
|
|
1880
|
-
import { chmodSync as chmodSync2, mkdirSync as mkdirSync7 } from "fs";
|
|
1881
|
-
import { join as join9 } from "path";
|
|
1882
|
-
function initializeVaultDatabase(database) {
|
|
1883
|
-
database.exec("PRAGMA journal_mode = WAL");
|
|
1884
|
-
database.exec("PRAGMA busy_timeout = 5000");
|
|
1885
|
-
database.exec(`
|
|
1886
|
-
CREATE TABLE IF NOT EXISTS vault (
|
|
1887
|
-
user_id TEXT NOT NULL,
|
|
1888
|
-
key TEXT NOT NULL,
|
|
1889
|
-
value TEXT NOT NULL,
|
|
1890
|
-
description TEXT NOT NULL DEFAULT '',
|
|
1891
|
-
PRIMARY KEY (user_id, key)
|
|
1892
|
-
)
|
|
1893
|
-
`);
|
|
1894
|
-
{
|
|
1895
|
-
const cols = database.prepare("PRAGMA table_info(vault)").all();
|
|
1896
|
-
const uid = cols.find((c) => c.name === "user_id");
|
|
1897
|
-
if (uid && uid.type.toUpperCase() === "INTEGER") {
|
|
1898
|
-
database.exec("BEGIN");
|
|
1899
|
-
database.exec(`
|
|
1900
|
-
CREATE TABLE vault_migrated (
|
|
1901
|
-
user_id TEXT NOT NULL,
|
|
1902
|
-
key TEXT NOT NULL,
|
|
1903
|
-
value TEXT NOT NULL,
|
|
1904
|
-
description TEXT NOT NULL DEFAULT '',
|
|
1905
|
-
PRIMARY KEY (user_id, key)
|
|
1906
|
-
)
|
|
1907
|
-
`);
|
|
1908
|
-
database.exec("INSERT INTO vault_migrated SELECT CAST(user_id AS TEXT), key, value, description FROM vault");
|
|
1909
|
-
database.exec("DROP TABLE vault");
|
|
1910
|
-
database.exec("ALTER TABLE vault_migrated RENAME TO vault");
|
|
1911
|
-
database.exec("COMMIT");
|
|
1912
|
-
}
|
|
1913
|
-
}
|
|
1914
|
-
}
|
|
1915
|
-
function openVaultDatabase(dataDir) {
|
|
1916
|
-
const path = join9(dataDir, "vault.db");
|
|
1917
|
-
mkdirSync7(dataDir, { recursive: true });
|
|
1918
|
-
const database = new Database(path, { create: true });
|
|
1919
|
-
chmodSync2(path, 384);
|
|
1920
|
-
initializeVaultDatabase(database);
|
|
1921
|
-
return database;
|
|
1922
|
-
}
|
|
1923
|
-
function activeVaultDatabase() {
|
|
1924
|
-
if (!vaultDb)
|
|
1925
|
-
vaultDb = openVaultDatabase(DATA_DIR);
|
|
1926
|
-
return vaultDb;
|
|
1927
|
-
}
|
|
1928
|
-
function normalizeVaultKey(key) {
|
|
1929
|
-
return key.trim().toUpperCase();
|
|
1930
|
-
}
|
|
1931
|
-
function decryptRow(userId, key, storedValue) {
|
|
1932
|
-
const database = activeVaultDatabase();
|
|
1933
|
-
const decoded = decryptVaultValue(userId, key, storedValue, vaultMasterKey);
|
|
1934
|
-
if (decoded.legacyPlaintext) {
|
|
1935
|
-
database.prepare("UPDATE vault SET value = ? WHERE user_id = ? AND key = ? AND value = ?").run(encryptVaultValue(userId, key, decoded.value, vaultMasterKey), userId, key, storedValue);
|
|
1936
|
-
}
|
|
1937
|
-
return decoded.value;
|
|
1938
|
-
}
|
|
1939
|
-
function vaultListWithValues(userId) {
|
|
1940
|
-
const rows = activeVaultDatabase().prepare("SELECT key, description, value FROM vault WHERE user_id = ? ORDER BY key").all(userId);
|
|
1941
|
-
return rows.map((row) => ({
|
|
1942
|
-
key: row.key,
|
|
1943
|
-
description: row.description,
|
|
1944
|
-
value: decryptRow(userId, row.key, row.value)
|
|
1945
|
-
}));
|
|
1946
|
-
}
|
|
1947
|
-
function vaultList(userId) {
|
|
1948
|
-
return activeVaultDatabase().prepare("SELECT key, description FROM vault WHERE user_id = ? ORDER BY key").all(userId);
|
|
1949
|
-
}
|
|
1950
|
-
function vaultSubstituteDetailed(userId, text) {
|
|
1951
|
-
const entries = new Map(vaultListWithValues(userId).map((entry) => [entry.key, entry.value]));
|
|
1952
|
-
const usedKeys = new Set;
|
|
1953
|
-
const substituted = text.replace(/\{\{([^}]+)\}\}/g, (match, rawKey) => {
|
|
1954
|
-
const key = normalizeVaultKey(rawKey);
|
|
1955
|
-
const value = entries.get(key);
|
|
1956
|
-
if (value === undefined)
|
|
1957
|
-
return match;
|
|
1958
|
-
usedKeys.add(key);
|
|
1959
|
-
return value;
|
|
1960
|
-
});
|
|
1961
|
-
return { text: substituted, usedKeys: [...usedKeys] };
|
|
1962
|
-
}
|
|
1963
|
-
function valueReferencesVaultKey(userId, value) {
|
|
1964
|
-
const keys = new Set(vaultList(userId).map((entry) => entry.key));
|
|
1965
|
-
const visit = (candidate) => {
|
|
1966
|
-
if (typeof candidate === "string") {
|
|
1967
|
-
for (const match of candidate.matchAll(/\{\{([^}]+)\}\}/g)) {
|
|
1968
|
-
if (keys.has(normalizeVaultKey(match[1] ?? "")))
|
|
1969
|
-
return true;
|
|
1970
|
-
}
|
|
1971
|
-
return false;
|
|
1972
|
-
}
|
|
1973
|
-
if (Array.isArray(candidate))
|
|
1974
|
-
return candidate.some(visit);
|
|
1975
|
-
if (candidate && typeof candidate === "object") {
|
|
1976
|
-
return Object.values(candidate).some(visit);
|
|
1977
|
-
}
|
|
1978
|
-
return false;
|
|
1979
|
-
};
|
|
1980
|
-
return visit(value);
|
|
1981
|
-
}
|
|
1982
|
-
function encodedSecretForms(value) {
|
|
1983
|
-
const forms = new Set([
|
|
1984
|
-
value,
|
|
1985
|
-
encodeURIComponent(value),
|
|
1986
|
-
Buffer.from(value, "utf8").toString("base64"),
|
|
1987
|
-
Buffer.from(value, "utf8").toString("base64url"),
|
|
1988
|
-
Buffer.from(value, "utf8").toString("hex")
|
|
1989
|
-
]);
|
|
1990
|
-
forms.delete("");
|
|
1991
|
-
return [...forms].sort((a, b) => b.length - a.length);
|
|
1834
|
+
// ../../packages/core/src/agents/vault-tool-policy.ts
|
|
1835
|
+
function leafToolName(toolName) {
|
|
1836
|
+
const parts = toolName.split("__");
|
|
1837
|
+
return parts.at(-1) ?? toolName;
|
|
1992
1838
|
}
|
|
1993
|
-
function
|
|
1994
|
-
const
|
|
1995
|
-
|
|
1996
|
-
return text;
|
|
1997
|
-
const candidatesByFirstCharacter = new Map;
|
|
1998
|
-
for (const candidate of candidates) {
|
|
1999
|
-
const first = candidate.form[0];
|
|
2000
|
-
if (!first)
|
|
2001
|
-
continue;
|
|
2002
|
-
const bucket = candidatesByFirstCharacter.get(first) ?? [];
|
|
2003
|
-
bucket.push(candidate);
|
|
2004
|
-
candidatesByFirstCharacter.set(first, bucket);
|
|
2005
|
-
}
|
|
2006
|
-
let redacted = "";
|
|
2007
|
-
let offset = 0;
|
|
2008
|
-
while (offset < text.length) {
|
|
2009
|
-
const match = candidatesByFirstCharacter.get(text[offset] ?? "")?.find((candidate) => text.startsWith(candidate.form, offset));
|
|
2010
|
-
if (!match) {
|
|
2011
|
-
redacted += text[offset];
|
|
2012
|
-
offset += 1;
|
|
2013
|
-
continue;
|
|
2014
|
-
}
|
|
2015
|
-
redacted += `[REDACTED:${match.key}]`;
|
|
2016
|
-
offset += match.form.length;
|
|
2017
|
-
}
|
|
2018
|
-
return redacted;
|
|
1839
|
+
function shouldSubstituteVaultToolInput(toolName) {
|
|
1840
|
+
const leaf = leafToolName(toolName);
|
|
1841
|
+
return leaf.startsWith("browser_") || DIRECT_VAULT_EXECUTION_TOOLS.has(leaf);
|
|
2019
1842
|
}
|
|
2020
|
-
var vaultDb, vaultMasterKey, VAULT_VALUE_MAX_BYTES;
|
|
2021
|
-
var init_vault = __esm(async () => {
|
|
2022
|
-
init_config();
|
|
2023
|
-
await init_sqlite();
|
|
2024
|
-
init_vault_crypto();
|
|
2025
|
-
vaultMasterKey = VAULT_MASTER_KEY;
|
|
2026
|
-
VAULT_VALUE_MAX_BYTES = 64 * 1024;
|
|
2027
|
-
});
|
|
2028
|
-
|
|
2029
|
-
// ../../packages/core/src/agents/vault-tool-policy.ts
|
|
2030
1843
|
function createVaultToolPolicy(host) {
|
|
2031
1844
|
function isVaultBrokerTool(toolName) {
|
|
2032
1845
|
return toolName.includes("vault_run") || toolName.includes("vault_http_request");
|
|
@@ -2046,21 +1859,24 @@ function createVaultToolPolicy(host) {
|
|
|
2046
1859
|
return false;
|
|
2047
1860
|
}
|
|
2048
1861
|
function shouldRedirectVaultTool(userId, toolName, input) {
|
|
2049
|
-
return
|
|
1862
|
+
return false;
|
|
2050
1863
|
}
|
|
2051
1864
|
return { isVaultBrokerTool, referencesRuntimeSecretStorage, shouldRedirectVaultTool };
|
|
2052
1865
|
}
|
|
2053
|
-
var SENSITIVE_RUNTIME_NAMES, defaultVaultToolPolicy, isVaultBrokerTool, referencesRuntimeSecretStorage, shouldRedirectVaultTool;
|
|
2054
|
-
var init_vault_tool_policy = __esm(
|
|
1866
|
+
var SENSITIVE_RUNTIME_NAMES, DIRECT_VAULT_EXECUTION_TOOLS, defaultVaultToolPolicy, isVaultBrokerTool, referencesRuntimeSecretStorage, shouldRedirectVaultTool;
|
|
1867
|
+
var init_vault_tool_policy = __esm(() => {
|
|
2055
1868
|
init_sensitive_path();
|
|
2056
|
-
await init_vault();
|
|
2057
1869
|
SENSITIVE_RUNTIME_NAMES = [
|
|
2058
1870
|
"vault.db",
|
|
2059
1871
|
"vault-master-key",
|
|
2060
1872
|
"runtime-mcp-secret",
|
|
2061
1873
|
"sessions.db"
|
|
2062
1874
|
];
|
|
2063
|
-
|
|
1875
|
+
DIRECT_VAULT_EXECUTION_TOOLS = new Set(["Bash", "WebFetch"]);
|
|
1876
|
+
defaultVaultToolPolicy = createVaultToolPolicy({
|
|
1877
|
+
isSensitivePath,
|
|
1878
|
+
valueReferencesVaultKey: () => false
|
|
1879
|
+
});
|
|
2064
1880
|
isVaultBrokerTool = defaultVaultToolPolicy.isVaultBrokerTool;
|
|
2065
1881
|
referencesRuntimeSecretStorage = defaultVaultToolPolicy.referencesRuntimeSecretStorage;
|
|
2066
1882
|
shouldRedirectVaultTool = defaultVaultToolPolicy.shouldRedirectVaultTool;
|
|
@@ -2156,7 +1972,7 @@ var init_context = () => {};
|
|
|
2156
1972
|
|
|
2157
1973
|
// ../../packages/core/src/platform/background-bash/manager.ts
|
|
2158
1974
|
import { execFileSync as execFileSync3, spawn } from "child_process";
|
|
2159
|
-
import { randomBytes as
|
|
1975
|
+
import { randomBytes as randomBytes3 } from "crypto";
|
|
2160
1976
|
function makeBgBashKey(_userId, _topic) {
|
|
2161
1977
|
return "runtime";
|
|
2162
1978
|
}
|
|
@@ -2173,8 +1989,8 @@ function createBackgroundBashManager(options = {}) {
|
|
|
2173
1989
|
const usedPorts = new Set;
|
|
2174
1990
|
const spawning = new Map;
|
|
2175
1991
|
const knownContexts = new Map;
|
|
2176
|
-
const runtimeCapability = options.capability ??
|
|
2177
|
-
const runtimeServerId = options.serverId ??
|
|
1992
|
+
const runtimeCapability = options.capability ?? randomBytes3(32).toString("hex");
|
|
1993
|
+
const runtimeServerId = options.serverId ?? randomBytes3(16).toString("hex");
|
|
2178
1994
|
const serverFile = options.serverFile ?? BACKGROUND_BASH_SERVER;
|
|
2179
1995
|
const basePort = options.basePort ?? BG_BASH_BASE_PORT;
|
|
2180
1996
|
const maxPort = options.maxPort ?? BG_BASH_MAX_PORT;
|
|
@@ -2851,7 +2667,9 @@ var init_mcp_config = __esm(() => {
|
|
|
2851
2667
|
vault: {
|
|
2852
2668
|
...commonRuntimeMcpPolicy("vault"),
|
|
2853
2669
|
build({ userId, agent }) {
|
|
2854
|
-
const args = [`--user-id=${userId}
|
|
2670
|
+
const args = [`--user-id=${userId}`];
|
|
2671
|
+
if (agent !== "codex")
|
|
2672
|
+
args.push("--list-only=true");
|
|
2855
2673
|
return buildStdioMcpServer(agent, VAULT_SERVER, args);
|
|
2856
2674
|
}
|
|
2857
2675
|
}
|
|
@@ -2864,6 +2682,179 @@ var init_mcp_config = __esm(() => {
|
|
|
2864
2682
|
nodeMcpEntries = [];
|
|
2865
2683
|
});
|
|
2866
2684
|
|
|
2685
|
+
// ../../packages/core/src/storage/vault-crypto.ts
|
|
2686
|
+
import { createCipheriv, createDecipheriv, createHash, randomBytes as randomBytes4 } from "crypto";
|
|
2687
|
+
function encryptionKey(masterKey = VAULT_MASTER_KEY) {
|
|
2688
|
+
return createHash("sha256").update("otium-vault-value-v1\x00", "utf8").update(masterKey, "utf8").digest().subarray(0, KEY_BYTES);
|
|
2689
|
+
}
|
|
2690
|
+
function aad(userId, key) {
|
|
2691
|
+
return Buffer.from(`${userId}\x00${key.toUpperCase()}`, "utf8");
|
|
2692
|
+
}
|
|
2693
|
+
function isEncryptedVaultValue(value) {
|
|
2694
|
+
return value.startsWith(ENVELOPE_PREFIX);
|
|
2695
|
+
}
|
|
2696
|
+
function encryptVaultValue(userId, key, value, masterKey = VAULT_MASTER_KEY) {
|
|
2697
|
+
const iv = randomBytes4(IV_BYTES);
|
|
2698
|
+
const cipher = createCipheriv("aes-256-gcm", encryptionKey(masterKey), iv);
|
|
2699
|
+
cipher.setAAD(aad(userId, key));
|
|
2700
|
+
const ciphertext = Buffer.concat([cipher.update(value, "utf8"), cipher.final()]);
|
|
2701
|
+
const tag = cipher.getAuthTag();
|
|
2702
|
+
return `${ENVELOPE_PREFIX}${iv.toString("base64url")}.${ciphertext.toString("base64url")}.${tag.toString("base64url")}`;
|
|
2703
|
+
}
|
|
2704
|
+
function decryptVaultValue(userId, key, storedValue, masterKey = VAULT_MASTER_KEY) {
|
|
2705
|
+
if (!isEncryptedVaultValue(storedValue)) {
|
|
2706
|
+
return { value: storedValue, legacyPlaintext: true };
|
|
2707
|
+
}
|
|
2708
|
+
const encoded = storedValue.slice(ENVELOPE_PREFIX.length);
|
|
2709
|
+
const [ivPart, ciphertextPart, tagPart, ...extra] = encoded.split(".");
|
|
2710
|
+
if (!ivPart || ciphertextPart === undefined || !tagPart || extra.length > 0) {
|
|
2711
|
+
throw new Error("Invalid encrypted vault value");
|
|
2712
|
+
}
|
|
2713
|
+
const iv = Buffer.from(ivPart, "base64url");
|
|
2714
|
+
const ciphertext = Buffer.from(ciphertextPart, "base64url");
|
|
2715
|
+
const tag = Buffer.from(tagPart, "base64url");
|
|
2716
|
+
if (iv.length !== IV_BYTES || tag.length !== 16) {
|
|
2717
|
+
throw new Error("Invalid encrypted vault value");
|
|
2718
|
+
}
|
|
2719
|
+
const decipher = createDecipheriv("aes-256-gcm", encryptionKey(masterKey), iv);
|
|
2720
|
+
decipher.setAAD(aad(userId, key));
|
|
2721
|
+
decipher.setAuthTag(tag);
|
|
2722
|
+
const plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
|
|
2723
|
+
return { value: plaintext.toString("utf8"), legacyPlaintext: false };
|
|
2724
|
+
}
|
|
2725
|
+
var ENVELOPE_PREFIX = "otium-vault:v1:", IV_BYTES = 12, KEY_BYTES = 32;
|
|
2726
|
+
var init_vault_crypto = __esm(() => {
|
|
2727
|
+
init_config();
|
|
2728
|
+
});
|
|
2729
|
+
|
|
2730
|
+
// ../../packages/core/src/storage/vault.ts
|
|
2731
|
+
import { chmodSync as chmodSync2, mkdirSync as mkdirSync7 } from "fs";
|
|
2732
|
+
import { join as join9 } from "path";
|
|
2733
|
+
function initializeVaultDatabase(database) {
|
|
2734
|
+
database.exec("PRAGMA journal_mode = WAL");
|
|
2735
|
+
database.exec("PRAGMA busy_timeout = 5000");
|
|
2736
|
+
database.exec(`
|
|
2737
|
+
CREATE TABLE IF NOT EXISTS vault (
|
|
2738
|
+
user_id TEXT NOT NULL,
|
|
2739
|
+
key TEXT NOT NULL,
|
|
2740
|
+
value TEXT NOT NULL,
|
|
2741
|
+
description TEXT NOT NULL DEFAULT '',
|
|
2742
|
+
PRIMARY KEY (user_id, key)
|
|
2743
|
+
)
|
|
2744
|
+
`);
|
|
2745
|
+
{
|
|
2746
|
+
const cols = database.prepare("PRAGMA table_info(vault)").all();
|
|
2747
|
+
const uid = cols.find((c) => c.name === "user_id");
|
|
2748
|
+
if (uid && uid.type.toUpperCase() === "INTEGER") {
|
|
2749
|
+
database.exec("BEGIN");
|
|
2750
|
+
database.exec(`
|
|
2751
|
+
CREATE TABLE vault_migrated (
|
|
2752
|
+
user_id TEXT NOT NULL,
|
|
2753
|
+
key TEXT NOT NULL,
|
|
2754
|
+
value TEXT NOT NULL,
|
|
2755
|
+
description TEXT NOT NULL DEFAULT '',
|
|
2756
|
+
PRIMARY KEY (user_id, key)
|
|
2757
|
+
)
|
|
2758
|
+
`);
|
|
2759
|
+
database.exec("INSERT INTO vault_migrated SELECT CAST(user_id AS TEXT), key, value, description FROM vault");
|
|
2760
|
+
database.exec("DROP TABLE vault");
|
|
2761
|
+
database.exec("ALTER TABLE vault_migrated RENAME TO vault");
|
|
2762
|
+
database.exec("COMMIT");
|
|
2763
|
+
}
|
|
2764
|
+
}
|
|
2765
|
+
}
|
|
2766
|
+
function openVaultDatabase(dataDir) {
|
|
2767
|
+
const path = join9(dataDir, "vault.db");
|
|
2768
|
+
mkdirSync7(dataDir, { recursive: true });
|
|
2769
|
+
const database = new Database(path, { create: true });
|
|
2770
|
+
chmodSync2(path, 384);
|
|
2771
|
+
initializeVaultDatabase(database);
|
|
2772
|
+
return database;
|
|
2773
|
+
}
|
|
2774
|
+
function activeVaultDatabase() {
|
|
2775
|
+
if (!vaultDb)
|
|
2776
|
+
vaultDb = openVaultDatabase(DATA_DIR);
|
|
2777
|
+
return vaultDb;
|
|
2778
|
+
}
|
|
2779
|
+
function normalizeVaultKey(key) {
|
|
2780
|
+
return key.trim().toUpperCase();
|
|
2781
|
+
}
|
|
2782
|
+
function decryptRow(userId, key, storedValue) {
|
|
2783
|
+
const database = activeVaultDatabase();
|
|
2784
|
+
const decoded = decryptVaultValue(userId, key, storedValue, vaultMasterKey);
|
|
2785
|
+
if (decoded.legacyPlaintext) {
|
|
2786
|
+
database.prepare("UPDATE vault SET value = ? WHERE user_id = ? AND key = ? AND value = ?").run(encryptVaultValue(userId, key, decoded.value, vaultMasterKey), userId, key, storedValue);
|
|
2787
|
+
}
|
|
2788
|
+
return decoded.value;
|
|
2789
|
+
}
|
|
2790
|
+
function vaultListWithValues(userId) {
|
|
2791
|
+
const rows = activeVaultDatabase().prepare("SELECT key, description, value FROM vault WHERE user_id = ? ORDER BY key").all(userId);
|
|
2792
|
+
return rows.map((row) => ({
|
|
2793
|
+
key: row.key,
|
|
2794
|
+
description: row.description,
|
|
2795
|
+
value: decryptRow(userId, row.key, row.value)
|
|
2796
|
+
}));
|
|
2797
|
+
}
|
|
2798
|
+
function vaultSubstituteDetailed(userId, text) {
|
|
2799
|
+
const entries = new Map(vaultListWithValues(userId).map((entry) => [entry.key, entry.value]));
|
|
2800
|
+
const usedKeys = new Set;
|
|
2801
|
+
const substituted = text.replace(/\{\{([^}]+)\}\}/g, (match, rawKey) => {
|
|
2802
|
+
const key = normalizeVaultKey(rawKey);
|
|
2803
|
+
const value = entries.get(key);
|
|
2804
|
+
if (value === undefined)
|
|
2805
|
+
return match;
|
|
2806
|
+
usedKeys.add(key);
|
|
2807
|
+
return value;
|
|
2808
|
+
});
|
|
2809
|
+
return { text: substituted, usedKeys: [...usedKeys] };
|
|
2810
|
+
}
|
|
2811
|
+
function encodedSecretForms(value) {
|
|
2812
|
+
const forms = new Set([
|
|
2813
|
+
value,
|
|
2814
|
+
encodeURIComponent(value),
|
|
2815
|
+
Buffer.from(value, "utf8").toString("base64"),
|
|
2816
|
+
Buffer.from(value, "utf8").toString("base64url"),
|
|
2817
|
+
Buffer.from(value, "utf8").toString("hex")
|
|
2818
|
+
]);
|
|
2819
|
+
forms.delete("");
|
|
2820
|
+
return [...forms].sort((a, b) => b.length - a.length);
|
|
2821
|
+
}
|
|
2822
|
+
function redactVaultSecrets(userId, text) {
|
|
2823
|
+
const candidates = vaultListWithValues(userId).flatMap((entry) => encodedSecretForms(entry.value).map((form) => ({ form, key: entry.key }))).sort((a, b) => b.form.length - a.form.length || a.key.localeCompare(b.key));
|
|
2824
|
+
if (candidates.length === 0)
|
|
2825
|
+
return text;
|
|
2826
|
+
const candidatesByFirstCharacter = new Map;
|
|
2827
|
+
for (const candidate of candidates) {
|
|
2828
|
+
const first = candidate.form[0];
|
|
2829
|
+
if (!first)
|
|
2830
|
+
continue;
|
|
2831
|
+
const bucket = candidatesByFirstCharacter.get(first) ?? [];
|
|
2832
|
+
bucket.push(candidate);
|
|
2833
|
+
candidatesByFirstCharacter.set(first, bucket);
|
|
2834
|
+
}
|
|
2835
|
+
let redacted = "";
|
|
2836
|
+
let offset = 0;
|
|
2837
|
+
while (offset < text.length) {
|
|
2838
|
+
const match = candidatesByFirstCharacter.get(text[offset] ?? "")?.find((candidate) => text.startsWith(candidate.form, offset));
|
|
2839
|
+
if (!match) {
|
|
2840
|
+
redacted += text[offset];
|
|
2841
|
+
offset += 1;
|
|
2842
|
+
continue;
|
|
2843
|
+
}
|
|
2844
|
+
redacted += `[REDACTED:${match.key}]`;
|
|
2845
|
+
offset += match.form.length;
|
|
2846
|
+
}
|
|
2847
|
+
return redacted;
|
|
2848
|
+
}
|
|
2849
|
+
var vaultDb, vaultMasterKey, VAULT_VALUE_MAX_BYTES;
|
|
2850
|
+
var init_vault = __esm(async () => {
|
|
2851
|
+
init_config();
|
|
2852
|
+
await init_sqlite();
|
|
2853
|
+
init_vault_crypto();
|
|
2854
|
+
vaultMasterKey = VAULT_MASTER_KEY;
|
|
2855
|
+
VAULT_VALUE_MAX_BYTES = 64 * 1024;
|
|
2856
|
+
});
|
|
2857
|
+
|
|
2867
2858
|
// ../../packages/core/src/agents/execution-host.ts
|
|
2868
2859
|
import { AsyncLocalStorage } from "async_hooks";
|
|
2869
2860
|
function activeHost() {
|
|
@@ -2895,7 +2886,7 @@ function hostedCodexAuthFilePath() {
|
|
|
2895
2886
|
}
|
|
2896
2887
|
var defaultHost, hostRegistrations, scopedHost;
|
|
2897
2888
|
var init_execution_host = __esm(async () => {
|
|
2898
|
-
|
|
2889
|
+
init_vault_tool_policy();
|
|
2899
2890
|
init_config();
|
|
2900
2891
|
init_mcp_config();
|
|
2901
2892
|
await init_vault();
|
|
@@ -2997,7 +2988,9 @@ var DEFAULT_CONTEXT_WARNING_RATIO = 0.8;
|
|
|
2997
2988
|
import { spawn as spawn2 } from "child_process";
|
|
2998
2989
|
import { existsSync as existsSync8, readFileSync as readFileSync6 } from "fs";
|
|
2999
2990
|
import { query } from "@anthropic-ai/claude-agent-sdk";
|
|
3000
|
-
function substituteClaudeToolInput(userId, input) {
|
|
2991
|
+
function substituteClaudeToolInput(userId, toolName, input) {
|
|
2992
|
+
if (!shouldSubstituteVaultToolInput(toolName))
|
|
2993
|
+
return input;
|
|
3001
2994
|
return deepMapStrings(input, (value) => substituteHostedSecrets(userId, value));
|
|
3002
2995
|
}
|
|
3003
2996
|
function buildClaudeDisallowedTools(extra = undefined) {
|
|
@@ -3230,7 +3223,7 @@ async function* claudeProvider(opts) {
|
|
|
3230
3223
|
};
|
|
3231
3224
|
}
|
|
3232
3225
|
const userId = opts.userId ?? "";
|
|
3233
|
-
const withVault = substituteClaudeToolInput(userId, tool_input);
|
|
3226
|
+
const withVault = substituteClaudeToolInput(userId, tool_name, tool_input);
|
|
3234
3227
|
if (JSON.stringify(withVault) === JSON.stringify(tool_input)) {
|
|
3235
3228
|
return { continue: true };
|
|
3236
3229
|
}
|
|
@@ -3447,6 +3440,7 @@ var CLAUDE_DEFAULT_DISALLOWED_TOOLS, CLAUDE_NATIVE_AGENT_TOOLS, CLAUDE_IMAGE_MAX
|
|
|
3447
3440
|
var init_claude_provider = __esm(async () => {
|
|
3448
3441
|
init_claude_registry();
|
|
3449
3442
|
await init_execution_host();
|
|
3443
|
+
init_vault_tool_policy();
|
|
3450
3444
|
init_file_events();
|
|
3451
3445
|
init_logger();
|
|
3452
3446
|
CLAUDE_DEFAULT_DISALLOWED_TOOLS = [
|
|
@@ -3469,7 +3463,7 @@ var init_claude_provider = __esm(async () => {
|
|
|
3469
3463
|
});
|
|
3470
3464
|
|
|
3471
3465
|
// ../../packages/core/src/version.ts
|
|
3472
|
-
var NEGOTIUM_VERSION = "0.1.
|
|
3466
|
+
var NEGOTIUM_VERSION = "0.1.23";
|
|
3473
3467
|
|
|
3474
3468
|
// ../../packages/core/src/agents/codex-native-multi-agent.ts
|
|
3475
3469
|
import { spawn as spawn3 } from "child_process";
|
|
@@ -4107,10 +4101,12 @@ function buildMaestroDisallowedTools(callerDisallowedTools = []) {
|
|
|
4107
4101
|
function buildVaultHook(userId) {
|
|
4108
4102
|
return {
|
|
4109
4103
|
name: "vault-guard",
|
|
4110
|
-
pre({ input }) {
|
|
4104
|
+
pre({ toolName, input }) {
|
|
4111
4105
|
if (referencesHostedSecretStorage(input)) {
|
|
4112
4106
|
return { decision: "block", error: "Runtime secret storage access is not permitted" };
|
|
4113
4107
|
}
|
|
4108
|
+
if (!shouldSubstituteVaultToolInput(toolName))
|
|
4109
|
+
return { decision: "allow" };
|
|
4114
4110
|
const substituted = deepMapStrings(input, (value) => substituteHostedSecrets(userId, value));
|
|
4115
4111
|
return JSON.stringify(substituted) === JSON.stringify(input) ? { decision: "allow" } : { decision: "modify", input: substituted };
|
|
4116
4112
|
},
|
|
@@ -4168,6 +4164,7 @@ var MAESTRO_DEFAULT_MAX_TOKENS = 32768, PROVIDER_ASK_USER_TOOL = "AskUserQuestio
|
|
|
4168
4164
|
var init_maestro_provider = __esm(async () => {
|
|
4169
4165
|
init_maestro_bootstrap_env();
|
|
4170
4166
|
await init_execution_host();
|
|
4167
|
+
init_vault_tool_policy();
|
|
4171
4168
|
MAESTRO_NATIVE_TASK_TOOLS = [
|
|
4172
4169
|
"TaskCreate",
|
|
4173
4170
|
"TaskUpdate",
|
|
@@ -5808,6 +5805,39 @@ var init_browser_profiles = __esm(async () => {
|
|
|
5808
5805
|
`);
|
|
5809
5806
|
});
|
|
5810
5807
|
|
|
5808
|
+
// ../../packages/core/src/storage/runtime-process-leases.ts
|
|
5809
|
+
function rowToLease2(row) {
|
|
5810
|
+
return {
|
|
5811
|
+
role: row.role,
|
|
5812
|
+
ownerId: row.owner_id,
|
|
5813
|
+
pid: Number(row.pid),
|
|
5814
|
+
startedAt: Number(row.started_at),
|
|
5815
|
+
heartbeatAt: Number(row.heartbeat_at)
|
|
5816
|
+
};
|
|
5817
|
+
}
|
|
5818
|
+
function getRuntimeProcessLease(role, now = Date.now(), staleMs = PROCESS_LEASE_STALE_MS) {
|
|
5819
|
+
const row = db.query("SELECT * FROM runtime_process_leases WHERE role = ?").get(role);
|
|
5820
|
+
if (!row)
|
|
5821
|
+
return null;
|
|
5822
|
+
const lease = rowToLease2(row);
|
|
5823
|
+
return now - lease.heartbeatAt <= staleMs ? lease : null;
|
|
5824
|
+
}
|
|
5825
|
+
var PROCESS_LEASE_STALE_MS = 5000;
|
|
5826
|
+
var init_runtime_process_leases = __esm(async () => {
|
|
5827
|
+
await init_forum_db();
|
|
5828
|
+
await init_runtime_leases();
|
|
5829
|
+
db.exec(`
|
|
5830
|
+
CREATE TABLE IF NOT EXISTS runtime_process_leases (
|
|
5831
|
+
role TEXT PRIMARY KEY,
|
|
5832
|
+
owner_id TEXT NOT NULL UNIQUE,
|
|
5833
|
+
pid INTEGER NOT NULL,
|
|
5834
|
+
started_at INTEGER NOT NULL,
|
|
5835
|
+
heartbeat_at INTEGER NOT NULL
|
|
5836
|
+
)
|
|
5837
|
+
`);
|
|
5838
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_runtime_process_leases_heartbeat ON runtime_process_leases(heartbeat_at)");
|
|
5839
|
+
});
|
|
5840
|
+
|
|
5811
5841
|
// ../../packages/core/src/platform/playwright/manager.ts
|
|
5812
5842
|
import { execFileSync as execFileSync4, spawn as spawn4 } from "child_process";
|
|
5813
5843
|
import { createHash as createHash2, randomBytes as randomBytes5 } from "crypto";
|
|
@@ -6069,7 +6099,13 @@ function selectOrphanBrowserPids(procs, liveUserDataDirs, profileRoot, selfPid)
|
|
|
6069
6099
|
}
|
|
6070
6100
|
return out;
|
|
6071
6101
|
}
|
|
6102
|
+
function isBrowserJanitorOwner(leaseOwnerPid, selfPid) {
|
|
6103
|
+
return leaseOwnerPid === selfPid;
|
|
6104
|
+
}
|
|
6072
6105
|
function reapOrphanBrowsers() {
|
|
6106
|
+
const daemonLease = getRuntimeProcessLease("node-daemon", Date.now(), Number.POSITIVE_INFINITY);
|
|
6107
|
+
if (!isBrowserJanitorOwner(daemonLease?.pid ?? null, process.pid))
|
|
6108
|
+
return;
|
|
6073
6109
|
const profileRoot = resolve5(BROWSER_PROFILES_DIR);
|
|
6074
6110
|
let pids;
|
|
6075
6111
|
try {
|
|
@@ -6338,6 +6374,7 @@ var init_manager2 = __esm(async () => {
|
|
|
6338
6374
|
init_config();
|
|
6339
6375
|
init_logger();
|
|
6340
6376
|
await init_browser_profiles();
|
|
6377
|
+
await init_runtime_process_leases();
|
|
6341
6378
|
BASE_PORT = PLAYWRIGHT_BASE_PORT;
|
|
6342
6379
|
MAX_PORT = PLAYWRIGHT_MAX_PORT;
|
|
6343
6380
|
MAX_IDLE_MS = 2 * 60 * 60 * 1000;
|
|
@@ -12107,20 +12144,7 @@ init_mcp_config();
|
|
|
12107
12144
|
|
|
12108
12145
|
// ../../packages/core/src/platform/modules.ts
|
|
12109
12146
|
init_logger();
|
|
12110
|
-
|
|
12111
|
-
// ../../packages/core/src/storage/runtime-process-leases.ts
|
|
12112
|
-
await init_forum_db();
|
|
12113
|
-
await init_runtime_leases();
|
|
12114
|
-
db.exec(`
|
|
12115
|
-
CREATE TABLE IF NOT EXISTS runtime_process_leases (
|
|
12116
|
-
role TEXT PRIMARY KEY,
|
|
12117
|
-
owner_id TEXT NOT NULL UNIQUE,
|
|
12118
|
-
pid INTEGER NOT NULL,
|
|
12119
|
-
started_at INTEGER NOT NULL,
|
|
12120
|
-
heartbeat_at INTEGER NOT NULL
|
|
12121
|
-
)
|
|
12122
|
-
`);
|
|
12123
|
-
db.exec("CREATE INDEX IF NOT EXISTS idx_runtime_process_leases_heartbeat ON runtime_process_leases(heartbeat_at)");
|
|
12147
|
+
await init_runtime_process_leases();
|
|
12124
12148
|
|
|
12125
12149
|
// ../../packages/core/src/index.ts
|
|
12126
12150
|
await init_manager2();
|
|
@@ -12256,6 +12280,7 @@ init_session_inbox_path();
|
|
|
12256
12280
|
init_types2();
|
|
12257
12281
|
await init_api_messages();
|
|
12258
12282
|
await init_runtime_leases();
|
|
12283
|
+
await init_runtime_process_leases();
|
|
12259
12284
|
await init_self_schedules();
|
|
12260
12285
|
await init_session_asks();
|
|
12261
12286
|
var topicWorkerBusy = new Set;
|
|
@@ -12270,6 +12295,7 @@ await init_app_settings();
|
|
|
12270
12295
|
await init_forum_db();
|
|
12271
12296
|
await init_runtime_events();
|
|
12272
12297
|
await init_runtime_leases();
|
|
12298
|
+
await init_runtime_process_leases();
|
|
12273
12299
|
await init_session_asks();
|
|
12274
12300
|
await init_vault();
|
|
12275
12301
|
await init_derive();
|
|
@@ -13930,4 +13956,4 @@ export {
|
|
|
13930
13956
|
CRON_CONTEXT_RETAIN_TURNS
|
|
13931
13957
|
};
|
|
13932
13958
|
|
|
13933
|
-
//# debugId=
|
|
13959
|
+
//# debugId=9CE363245A572F6F64756E2164756E21
|