negotium 0.1.21 → 0.1.22

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/cron.js CHANGED
@@ -1831,201 +1831,6 @@ var init_sensitive_path = __esm(() => {
1831
1831
  ];
1832
1832
  });
1833
1833
 
1834
- // ../../packages/core/src/storage/vault-crypto.ts
1835
- import { createCipheriv, createDecipheriv, createHash, randomBytes as randomBytes3 } from "crypto";
1836
- function encryptionKey(masterKey = VAULT_MASTER_KEY) {
1837
- return createHash("sha256").update("otium-vault-value-v1\x00", "utf8").update(masterKey, "utf8").digest().subarray(0, KEY_BYTES);
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);
1992
- }
1993
- function redactVaultSecrets(userId, text) {
1994
- 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));
1995
- if (candidates.length === 0)
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;
2019
- }
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
1834
  // ../../packages/core/src/agents/vault-tool-policy.ts
2030
1835
  function createVaultToolPolicy(host) {
2031
1836
  function isVaultBrokerTool(toolName) {
@@ -2046,21 +1851,23 @@ function createVaultToolPolicy(host) {
2046
1851
  return false;
2047
1852
  }
2048
1853
  function shouldRedirectVaultTool(userId, toolName, input) {
2049
- return !isVaultBrokerTool(toolName) && host.valueReferencesVaultKey(userId, input);
1854
+ return false;
2050
1855
  }
2051
1856
  return { isVaultBrokerTool, referencesRuntimeSecretStorage, shouldRedirectVaultTool };
2052
1857
  }
2053
1858
  var SENSITIVE_RUNTIME_NAMES, defaultVaultToolPolicy, isVaultBrokerTool, referencesRuntimeSecretStorage, shouldRedirectVaultTool;
2054
- var init_vault_tool_policy = __esm(async () => {
1859
+ var init_vault_tool_policy = __esm(() => {
2055
1860
  init_sensitive_path();
2056
- await init_vault();
2057
1861
  SENSITIVE_RUNTIME_NAMES = [
2058
1862
  "vault.db",
2059
1863
  "vault-master-key",
2060
1864
  "runtime-mcp-secret",
2061
1865
  "sessions.db"
2062
1866
  ];
2063
- defaultVaultToolPolicy = createVaultToolPolicy({ isSensitivePath, valueReferencesVaultKey });
1867
+ defaultVaultToolPolicy = createVaultToolPolicy({
1868
+ isSensitivePath,
1869
+ valueReferencesVaultKey: () => false
1870
+ });
2064
1871
  isVaultBrokerTool = defaultVaultToolPolicy.isVaultBrokerTool;
2065
1872
  referencesRuntimeSecretStorage = defaultVaultToolPolicy.referencesRuntimeSecretStorage;
2066
1873
  shouldRedirectVaultTool = defaultVaultToolPolicy.shouldRedirectVaultTool;
@@ -2156,7 +1963,7 @@ var init_context = () => {};
2156
1963
 
2157
1964
  // ../../packages/core/src/platform/background-bash/manager.ts
2158
1965
  import { execFileSync as execFileSync3, spawn } from "child_process";
2159
- import { randomBytes as randomBytes4 } from "crypto";
1966
+ import { randomBytes as randomBytes3 } from "crypto";
2160
1967
  function makeBgBashKey(_userId, _topic) {
2161
1968
  return "runtime";
2162
1969
  }
@@ -2173,8 +1980,8 @@ function createBackgroundBashManager(options = {}) {
2173
1980
  const usedPorts = new Set;
2174
1981
  const spawning = new Map;
2175
1982
  const knownContexts = new Map;
2176
- const runtimeCapability = options.capability ?? randomBytes4(32).toString("hex");
2177
- const runtimeServerId = options.serverId ?? randomBytes4(16).toString("hex");
1983
+ const runtimeCapability = options.capability ?? randomBytes3(32).toString("hex");
1984
+ const runtimeServerId = options.serverId ?? randomBytes3(16).toString("hex");
2178
1985
  const serverFile = options.serverFile ?? BACKGROUND_BASH_SERVER;
2179
1986
  const basePort = options.basePort ?? BG_BASH_BASE_PORT;
2180
1987
  const maxPort = options.maxPort ?? BG_BASH_MAX_PORT;
@@ -2851,7 +2658,9 @@ var init_mcp_config = __esm(() => {
2851
2658
  vault: {
2852
2659
  ...commonRuntimeMcpPolicy("vault"),
2853
2660
  build({ userId, agent }) {
2854
- const args = [`--user-id=${userId}`, "--list-only=true"];
2661
+ const args = [`--user-id=${userId}`];
2662
+ if (agent !== "codex")
2663
+ args.push("--list-only=true");
2855
2664
  return buildStdioMcpServer(agent, VAULT_SERVER, args);
2856
2665
  }
2857
2666
  }
@@ -2864,6 +2673,179 @@ var init_mcp_config = __esm(() => {
2864
2673
  nodeMcpEntries = [];
2865
2674
  });
2866
2675
 
2676
+ // ../../packages/core/src/storage/vault-crypto.ts
2677
+ import { createCipheriv, createDecipheriv, createHash, randomBytes as randomBytes4 } from "crypto";
2678
+ function encryptionKey(masterKey = VAULT_MASTER_KEY) {
2679
+ return createHash("sha256").update("otium-vault-value-v1\x00", "utf8").update(masterKey, "utf8").digest().subarray(0, KEY_BYTES);
2680
+ }
2681
+ function aad(userId, key) {
2682
+ return Buffer.from(`${userId}\x00${key.toUpperCase()}`, "utf8");
2683
+ }
2684
+ function isEncryptedVaultValue(value) {
2685
+ return value.startsWith(ENVELOPE_PREFIX);
2686
+ }
2687
+ function encryptVaultValue(userId, key, value, masterKey = VAULT_MASTER_KEY) {
2688
+ const iv = randomBytes4(IV_BYTES);
2689
+ const cipher = createCipheriv("aes-256-gcm", encryptionKey(masterKey), iv);
2690
+ cipher.setAAD(aad(userId, key));
2691
+ const ciphertext = Buffer.concat([cipher.update(value, "utf8"), cipher.final()]);
2692
+ const tag = cipher.getAuthTag();
2693
+ return `${ENVELOPE_PREFIX}${iv.toString("base64url")}.${ciphertext.toString("base64url")}.${tag.toString("base64url")}`;
2694
+ }
2695
+ function decryptVaultValue(userId, key, storedValue, masterKey = VAULT_MASTER_KEY) {
2696
+ if (!isEncryptedVaultValue(storedValue)) {
2697
+ return { value: storedValue, legacyPlaintext: true };
2698
+ }
2699
+ const encoded = storedValue.slice(ENVELOPE_PREFIX.length);
2700
+ const [ivPart, ciphertextPart, tagPart, ...extra] = encoded.split(".");
2701
+ if (!ivPart || ciphertextPart === undefined || !tagPart || extra.length > 0) {
2702
+ throw new Error("Invalid encrypted vault value");
2703
+ }
2704
+ const iv = Buffer.from(ivPart, "base64url");
2705
+ const ciphertext = Buffer.from(ciphertextPart, "base64url");
2706
+ const tag = Buffer.from(tagPart, "base64url");
2707
+ if (iv.length !== IV_BYTES || tag.length !== 16) {
2708
+ throw new Error("Invalid encrypted vault value");
2709
+ }
2710
+ const decipher = createDecipheriv("aes-256-gcm", encryptionKey(masterKey), iv);
2711
+ decipher.setAAD(aad(userId, key));
2712
+ decipher.setAuthTag(tag);
2713
+ const plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
2714
+ return { value: plaintext.toString("utf8"), legacyPlaintext: false };
2715
+ }
2716
+ var ENVELOPE_PREFIX = "otium-vault:v1:", IV_BYTES = 12, KEY_BYTES = 32;
2717
+ var init_vault_crypto = __esm(() => {
2718
+ init_config();
2719
+ });
2720
+
2721
+ // ../../packages/core/src/storage/vault.ts
2722
+ import { chmodSync as chmodSync2, mkdirSync as mkdirSync7 } from "fs";
2723
+ import { join as join9 } from "path";
2724
+ function initializeVaultDatabase(database) {
2725
+ database.exec("PRAGMA journal_mode = WAL");
2726
+ database.exec("PRAGMA busy_timeout = 5000");
2727
+ database.exec(`
2728
+ CREATE TABLE IF NOT EXISTS vault (
2729
+ user_id TEXT NOT NULL,
2730
+ key TEXT NOT NULL,
2731
+ value TEXT NOT NULL,
2732
+ description TEXT NOT NULL DEFAULT '',
2733
+ PRIMARY KEY (user_id, key)
2734
+ )
2735
+ `);
2736
+ {
2737
+ const cols = database.prepare("PRAGMA table_info(vault)").all();
2738
+ const uid = cols.find((c) => c.name === "user_id");
2739
+ if (uid && uid.type.toUpperCase() === "INTEGER") {
2740
+ database.exec("BEGIN");
2741
+ database.exec(`
2742
+ CREATE TABLE vault_migrated (
2743
+ user_id TEXT NOT NULL,
2744
+ key TEXT NOT NULL,
2745
+ value TEXT NOT NULL,
2746
+ description TEXT NOT NULL DEFAULT '',
2747
+ PRIMARY KEY (user_id, key)
2748
+ )
2749
+ `);
2750
+ database.exec("INSERT INTO vault_migrated SELECT CAST(user_id AS TEXT), key, value, description FROM vault");
2751
+ database.exec("DROP TABLE vault");
2752
+ database.exec("ALTER TABLE vault_migrated RENAME TO vault");
2753
+ database.exec("COMMIT");
2754
+ }
2755
+ }
2756
+ }
2757
+ function openVaultDatabase(dataDir) {
2758
+ const path = join9(dataDir, "vault.db");
2759
+ mkdirSync7(dataDir, { recursive: true });
2760
+ const database = new Database(path, { create: true });
2761
+ chmodSync2(path, 384);
2762
+ initializeVaultDatabase(database);
2763
+ return database;
2764
+ }
2765
+ function activeVaultDatabase() {
2766
+ if (!vaultDb)
2767
+ vaultDb = openVaultDatabase(DATA_DIR);
2768
+ return vaultDb;
2769
+ }
2770
+ function normalizeVaultKey(key) {
2771
+ return key.trim().toUpperCase();
2772
+ }
2773
+ function decryptRow(userId, key, storedValue) {
2774
+ const database = activeVaultDatabase();
2775
+ const decoded = decryptVaultValue(userId, key, storedValue, vaultMasterKey);
2776
+ if (decoded.legacyPlaintext) {
2777
+ database.prepare("UPDATE vault SET value = ? WHERE user_id = ? AND key = ? AND value = ?").run(encryptVaultValue(userId, key, decoded.value, vaultMasterKey), userId, key, storedValue);
2778
+ }
2779
+ return decoded.value;
2780
+ }
2781
+ function vaultListWithValues(userId) {
2782
+ const rows = activeVaultDatabase().prepare("SELECT key, description, value FROM vault WHERE user_id = ? ORDER BY key").all(userId);
2783
+ return rows.map((row) => ({
2784
+ key: row.key,
2785
+ description: row.description,
2786
+ value: decryptRow(userId, row.key, row.value)
2787
+ }));
2788
+ }
2789
+ function vaultSubstituteDetailed(userId, text) {
2790
+ const entries = new Map(vaultListWithValues(userId).map((entry) => [entry.key, entry.value]));
2791
+ const usedKeys = new Set;
2792
+ const substituted = text.replace(/\{\{([^}]+)\}\}/g, (match, rawKey) => {
2793
+ const key = normalizeVaultKey(rawKey);
2794
+ const value = entries.get(key);
2795
+ if (value === undefined)
2796
+ return match;
2797
+ usedKeys.add(key);
2798
+ return value;
2799
+ });
2800
+ return { text: substituted, usedKeys: [...usedKeys] };
2801
+ }
2802
+ function encodedSecretForms(value) {
2803
+ const forms = new Set([
2804
+ value,
2805
+ encodeURIComponent(value),
2806
+ Buffer.from(value, "utf8").toString("base64"),
2807
+ Buffer.from(value, "utf8").toString("base64url"),
2808
+ Buffer.from(value, "utf8").toString("hex")
2809
+ ]);
2810
+ forms.delete("");
2811
+ return [...forms].sort((a, b) => b.length - a.length);
2812
+ }
2813
+ function redactVaultSecrets(userId, text) {
2814
+ 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));
2815
+ if (candidates.length === 0)
2816
+ return text;
2817
+ const candidatesByFirstCharacter = new Map;
2818
+ for (const candidate of candidates) {
2819
+ const first = candidate.form[0];
2820
+ if (!first)
2821
+ continue;
2822
+ const bucket = candidatesByFirstCharacter.get(first) ?? [];
2823
+ bucket.push(candidate);
2824
+ candidatesByFirstCharacter.set(first, bucket);
2825
+ }
2826
+ let redacted = "";
2827
+ let offset = 0;
2828
+ while (offset < text.length) {
2829
+ const match = candidatesByFirstCharacter.get(text[offset] ?? "")?.find((candidate) => text.startsWith(candidate.form, offset));
2830
+ if (!match) {
2831
+ redacted += text[offset];
2832
+ offset += 1;
2833
+ continue;
2834
+ }
2835
+ redacted += `[REDACTED:${match.key}]`;
2836
+ offset += match.form.length;
2837
+ }
2838
+ return redacted;
2839
+ }
2840
+ var vaultDb, vaultMasterKey, VAULT_VALUE_MAX_BYTES;
2841
+ var init_vault = __esm(async () => {
2842
+ init_config();
2843
+ await init_sqlite();
2844
+ init_vault_crypto();
2845
+ vaultMasterKey = VAULT_MASTER_KEY;
2846
+ VAULT_VALUE_MAX_BYTES = 64 * 1024;
2847
+ });
2848
+
2867
2849
  // ../../packages/core/src/agents/execution-host.ts
2868
2850
  import { AsyncLocalStorage } from "async_hooks";
2869
2851
  function activeHost() {
@@ -2895,7 +2877,7 @@ function hostedCodexAuthFilePath() {
2895
2877
  }
2896
2878
  var defaultHost, hostRegistrations, scopedHost;
2897
2879
  var init_execution_host = __esm(async () => {
2898
- await init_vault_tool_policy();
2880
+ init_vault_tool_policy();
2899
2881
  init_config();
2900
2882
  init_mcp_config();
2901
2883
  await init_vault();
@@ -3469,7 +3451,7 @@ var init_claude_provider = __esm(async () => {
3469
3451
  });
3470
3452
 
3471
3453
  // ../../packages/core/src/version.ts
3472
- var NEGOTIUM_VERSION = "0.1.21";
3454
+ var NEGOTIUM_VERSION = "0.1.22";
3473
3455
 
3474
3456
  // ../../packages/core/src/agents/codex-native-multi-agent.ts
3475
3457
  import { spawn as spawn3 } from "child_process";
@@ -5808,6 +5790,39 @@ var init_browser_profiles = __esm(async () => {
5808
5790
  `);
5809
5791
  });
5810
5792
 
5793
+ // ../../packages/core/src/storage/runtime-process-leases.ts
5794
+ function rowToLease2(row) {
5795
+ return {
5796
+ role: row.role,
5797
+ ownerId: row.owner_id,
5798
+ pid: Number(row.pid),
5799
+ startedAt: Number(row.started_at),
5800
+ heartbeatAt: Number(row.heartbeat_at)
5801
+ };
5802
+ }
5803
+ function getRuntimeProcessLease(role, now = Date.now(), staleMs = PROCESS_LEASE_STALE_MS) {
5804
+ const row = db.query("SELECT * FROM runtime_process_leases WHERE role = ?").get(role);
5805
+ if (!row)
5806
+ return null;
5807
+ const lease = rowToLease2(row);
5808
+ return now - lease.heartbeatAt <= staleMs ? lease : null;
5809
+ }
5810
+ var PROCESS_LEASE_STALE_MS = 5000;
5811
+ var init_runtime_process_leases = __esm(async () => {
5812
+ await init_forum_db();
5813
+ await init_runtime_leases();
5814
+ db.exec(`
5815
+ CREATE TABLE IF NOT EXISTS runtime_process_leases (
5816
+ role TEXT PRIMARY KEY,
5817
+ owner_id TEXT NOT NULL UNIQUE,
5818
+ pid INTEGER NOT NULL,
5819
+ started_at INTEGER NOT NULL,
5820
+ heartbeat_at INTEGER NOT NULL
5821
+ )
5822
+ `);
5823
+ db.exec("CREATE INDEX IF NOT EXISTS idx_runtime_process_leases_heartbeat ON runtime_process_leases(heartbeat_at)");
5824
+ });
5825
+
5811
5826
  // ../../packages/core/src/platform/playwright/manager.ts
5812
5827
  import { execFileSync as execFileSync4, spawn as spawn4 } from "child_process";
5813
5828
  import { createHash as createHash2, randomBytes as randomBytes5 } from "crypto";
@@ -6069,7 +6084,13 @@ function selectOrphanBrowserPids(procs, liveUserDataDirs, profileRoot, selfPid)
6069
6084
  }
6070
6085
  return out;
6071
6086
  }
6087
+ function isBrowserJanitorOwner(leaseOwnerPid, selfPid) {
6088
+ return leaseOwnerPid === selfPid;
6089
+ }
6072
6090
  function reapOrphanBrowsers() {
6091
+ const daemonLease = getRuntimeProcessLease("node-daemon", Date.now(), Number.POSITIVE_INFINITY);
6092
+ if (!isBrowserJanitorOwner(daemonLease?.pid ?? null, process.pid))
6093
+ return;
6073
6094
  const profileRoot = resolve5(BROWSER_PROFILES_DIR);
6074
6095
  let pids;
6075
6096
  try {
@@ -6338,6 +6359,7 @@ var init_manager2 = __esm(async () => {
6338
6359
  init_config();
6339
6360
  init_logger();
6340
6361
  await init_browser_profiles();
6362
+ await init_runtime_process_leases();
6341
6363
  BASE_PORT = PLAYWRIGHT_BASE_PORT;
6342
6364
  MAX_PORT = PLAYWRIGHT_MAX_PORT;
6343
6365
  MAX_IDLE_MS = 2 * 60 * 60 * 1000;
@@ -12107,20 +12129,7 @@ init_mcp_config();
12107
12129
 
12108
12130
  // ../../packages/core/src/platform/modules.ts
12109
12131
  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)");
12132
+ await init_runtime_process_leases();
12124
12133
 
12125
12134
  // ../../packages/core/src/index.ts
12126
12135
  await init_manager2();
@@ -12256,6 +12265,7 @@ init_session_inbox_path();
12256
12265
  init_types2();
12257
12266
  await init_api_messages();
12258
12267
  await init_runtime_leases();
12268
+ await init_runtime_process_leases();
12259
12269
  await init_self_schedules();
12260
12270
  await init_session_asks();
12261
12271
  var topicWorkerBusy = new Set;
@@ -12270,6 +12280,7 @@ await init_app_settings();
12270
12280
  await init_forum_db();
12271
12281
  await init_runtime_events();
12272
12282
  await init_runtime_leases();
12283
+ await init_runtime_process_leases();
12273
12284
  await init_session_asks();
12274
12285
  await init_vault();
12275
12286
  await init_derive();
@@ -13930,4 +13941,4 @@ export {
13930
13941
  CRON_CONTEXT_RETAIN_TURNS
13931
13942
  };
13932
13943
 
13933
- //# debugId=85C745F136B1D17364756E2164756E21
13944
+ //# debugId=B45862ECC407392D64756E2164756E21