openmausbot 0.1.73 → 0.1.74
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/assets/index-BRLHsQ5g.js +298 -0
- package/dist/assets/index-ByLQ7a3F.css +1 -0
- package/dist/assets/{index-BYbK7ber.js → index-CwoQdM0z.js} +1 -1
- package/dist/index.html +2 -2
- package/dist-server/container-mcp.js +9 -0
- package/dist-server/index.js +592 -453
- package/dist-server/mcp-gate.js +58 -16
- package/dist-server/openmausbot.js +186 -64
- package/dist-server/pair-cli.js +186 -64
- package/dist-server/server/auto-approve.js +30 -206
- package/dist-server/server/channel-queue.js +20 -2
- package/dist-server/server/config.js +36 -1
- package/dist-server/server/drivers/acp/core.js +56 -3
- package/dist-server/server/drivers/acp/grok.js +3 -1
- package/dist-server/server/drivers/antigravity-acp.js +5 -4
- package/dist-server/server/drivers/antigravity.js +9 -4
- package/dist-server/server/drivers/claude.js +54 -11
- package/dist-server/server/drivers/codex.js +22 -11
- package/dist-server/server/engine-install.js +9 -5
- package/dist-server/server/index.js +185 -223
- package/dist-server/server/message-db.js +70 -3
- package/dist-server/server/procs.js +82 -23
- package/dist-server/server/routines.js +67 -8
- package/dist-server/server/steer-queue.js +27 -7
- package/dist-server/server/team-manifest.js +1 -1
- package/dist-server/server/webhooks.js +4 -1
- package/dist-server/server/workspace-backup.js +24 -9
- package/dist-server/shared/approval-mode.js +11 -10
- package/dist-server/vps-container-mcp.js +9 -0
- package/package.json +1 -1
- package/dist/assets/index-BLJ7byG3.js +0 -296
- package/dist/assets/index-De2TRLxu.css +0 -1
- package/dist-server/server/auto-review.js +0 -79
package/dist-server/pair-cli.js
CHANGED
|
@@ -17782,7 +17782,7 @@ function saveConfig(patch, options = {}) {
|
|
|
17782
17782
|
const checkedPatch = appConfigSchema.partial().parse(patch);
|
|
17783
17783
|
const storedProfiles = storedBrowserProfilesSchema.safeParse(disk.browserProfiles);
|
|
17784
17784
|
if (storedProfiles.success) disk.browserProfiles = storedProfiles.data;
|
|
17785
|
-
for (const key of ["xai", "anthropic", "openaiCompat", "composio", "box", "opencodeGo", "tts", "imageGen", "profile", "rooms", "threads", "localVm", "features", "budgets", "billing"]) {
|
|
17785
|
+
for (const key of ["xai", "anthropic", "openaiCompat", "composio", "box", "opencodeGo", "tts", "imageGen", "profile", "rooms", "threads", "localVm", "features", "budgets", "billing", "onboarding"]) {
|
|
17786
17786
|
const section = checkedPatch[key];
|
|
17787
17787
|
if (!section) continue;
|
|
17788
17788
|
const current = jsonObjectSchema.safeParse(disk[key]);
|
|
@@ -17905,7 +17905,7 @@ function instanceConfigs(cfg) {
|
|
|
17905
17905
|
}
|
|
17906
17906
|
return map3;
|
|
17907
17907
|
}
|
|
17908
|
-
var optionalText, SSH_ALIAS, LEGACY_BROWSER_PROFILE_ID, BROWSER_PROFILE_ID, MIN_ROOM_TURN_TIMEOUT_MINUTES, MAX_ROOM_TURN_TIMEOUT_MINUTES, MAX_CONCURRENT_BOT_THREADS, MIN_LOCAL_VM_MAX_INSTANCES, MAX_LOCAL_VM_MAX_INSTANCES, vpsConfigSchema, roomConfigSchema, localVmConfigSchema, browserProfileSchema, legacyBrowserProfileSchema, legacyBrowserProfilesSchema, storedBrowserProfilesSchema, browserProfilesSchema, featureConfigSchema, instanceConfigSchema, instanceConfigMapSchema, defaultModelSelectionSchema, appConfigSchema, storedAppConfigSchema, appConfigPatchSchema, jsonObjectSchema, DATA_DIR, LEGACY_DATA_DIR, EVENTS_DIR, NATIVE_DIR, WORKSPACE_CREDENTIAL_ENV, PROVIDER_CREDENTIAL_ENV;
|
|
17908
|
+
var optionalText, SSH_ALIAS, LEGACY_BROWSER_PROFILE_ID, BROWSER_PROFILE_ID, MIN_ROOM_TURN_TIMEOUT_MINUTES, MAX_ROOM_TURN_TIMEOUT_MINUTES, MAX_CONCURRENT_BOT_THREADS, MIN_LOCAL_VM_MAX_INSTANCES, MAX_LOCAL_VM_MAX_INSTANCES, vpsConfigSchema, roomConfigSchema, localVmConfigSchema, browserProfileSchema, legacyBrowserProfileSchema, legacyBrowserProfilesSchema, storedBrowserProfilesSchema, browserProfilesSchema, featureConfigSchema, onboardingConfigSchema, instanceConfigSchema, instanceConfigMapSchema, defaultModelSelectionSchema, appConfigSchema, storedAppConfigSchema, appConfigPatchSchema, jsonObjectSchema, DATA_DIR, LEGACY_DATA_DIR, EVENTS_DIR, NATIVE_DIR, WORKSPACE_CREDENTIAL_ENV, PROVIDER_CREDENTIAL_ENV;
|
|
17909
17909
|
var init_config = __esm({
|
|
17910
17910
|
"server/config.ts"() {
|
|
17911
17911
|
"use strict";
|
|
@@ -17979,6 +17979,14 @@ var init_config = __esm({
|
|
|
17979
17979
|
* also has its own switch. */
|
|
17980
17980
|
browser: external_exports.boolean().optional()
|
|
17981
17981
|
});
|
|
17982
|
+
onboardingConfigSchema = external_exports.object({
|
|
17983
|
+
/** ISO timestamp of finishing (or skipping to the end of) the welcome flow. */
|
|
17984
|
+
completedAt: external_exports.string().trim().max(40).optional(),
|
|
17985
|
+
/** Which welcome flow was completed; a newer flow may re-show itself. */
|
|
17986
|
+
version: external_exports.number().int().min(0).max(1e3).optional(),
|
|
17987
|
+
reelSeen: external_exports.boolean().optional(),
|
|
17988
|
+
hintsSeen: external_exports.array(external_exports.string().trim().min(1).max(60)).max(100).optional()
|
|
17989
|
+
}).strict();
|
|
17982
17990
|
instanceConfigSchema = external_exports.object({
|
|
17983
17991
|
driver: external_exports.string().min(1),
|
|
17984
17992
|
displayName: optionalText,
|
|
@@ -18072,6 +18080,7 @@ var init_config = __esm({
|
|
|
18072
18080
|
threads: external_exports.object({ maxConcurrentPerBot: external_exports.number().int().min(1).max(MAX_CONCURRENT_BOT_THREADS) }).strict().optional(),
|
|
18073
18081
|
localVm: localVmConfigSchema.optional(),
|
|
18074
18082
|
features: featureConfigSchema.optional(),
|
|
18083
|
+
onboarding: onboardingConfigSchema.optional(),
|
|
18075
18084
|
browserProfiles: browserProfilesSchema.optional(),
|
|
18076
18085
|
instances: instanceConfigMapSchema.optional(),
|
|
18077
18086
|
/** User-configured MCP servers, mounted into every capable engine. Kept
|
|
@@ -18728,6 +18737,7 @@ function spawnCli(cli, args, opts) {
|
|
|
18728
18737
|
// win32: taskkill /T does the reaping instead (see killCliTree)
|
|
18729
18738
|
...process.platform === "win32" ? { windowsHide: true } : { detached: true }
|
|
18730
18739
|
});
|
|
18740
|
+
if (process.platform !== "win32") cliGroups.add(child);
|
|
18731
18741
|
child.stdin?.on("error", () => {
|
|
18732
18742
|
});
|
|
18733
18743
|
return child;
|
|
@@ -18760,8 +18770,59 @@ function describeSpawnFailure(err, cli) {
|
|
|
18760
18770
|
return { message: `spawn failed: ${err.message}`, setup: false };
|
|
18761
18771
|
}
|
|
18762
18772
|
function killCliTree(child, timeoutMs = 5e3) {
|
|
18773
|
+
const existing = stopping.get(child);
|
|
18774
|
+
if (existing) return existing;
|
|
18763
18775
|
const pid = child.pid;
|
|
18764
|
-
if (!pid
|
|
18776
|
+
if (!pid) return Promise.resolve(true);
|
|
18777
|
+
if (!Number.isInteger(pid) || pid <= 1 || pid === process.pid) return Promise.resolve(false);
|
|
18778
|
+
const run3 = stopCliTree(child, pid, Number.isFinite(timeoutMs) ? Math.max(0, timeoutMs) : 5e3);
|
|
18779
|
+
stopping.set(child, run3);
|
|
18780
|
+
void run3.then((stopped) => {
|
|
18781
|
+
if (!stopped) stopping.delete(child);
|
|
18782
|
+
});
|
|
18783
|
+
return run3;
|
|
18784
|
+
}
|
|
18785
|
+
async function stopCliTree(child, pid, timeoutMs) {
|
|
18786
|
+
const exited = () => child.exitCode !== null || child.signalCode !== null;
|
|
18787
|
+
if (process.platform !== "win32") {
|
|
18788
|
+
const group = cliGroups.has(child);
|
|
18789
|
+
const settled = () => {
|
|
18790
|
+
if (!exited()) return false;
|
|
18791
|
+
if (!group) return true;
|
|
18792
|
+
try {
|
|
18793
|
+
process.kill(-pid, 0);
|
|
18794
|
+
return false;
|
|
18795
|
+
} catch (error51) {
|
|
18796
|
+
return error51.code === "ESRCH";
|
|
18797
|
+
}
|
|
18798
|
+
};
|
|
18799
|
+
const signal = (value) => {
|
|
18800
|
+
try {
|
|
18801
|
+
if (group) process.kill(-pid, value);
|
|
18802
|
+
else child.kill(value);
|
|
18803
|
+
} catch {
|
|
18804
|
+
try {
|
|
18805
|
+
child.kill(value);
|
|
18806
|
+
} catch {
|
|
18807
|
+
}
|
|
18808
|
+
}
|
|
18809
|
+
};
|
|
18810
|
+
const wait2 = async (ms) => {
|
|
18811
|
+
const deadline = Date.now() + ms;
|
|
18812
|
+
while (!settled()) {
|
|
18813
|
+
const remaining = deadline - Date.now();
|
|
18814
|
+
if (remaining <= 0) return false;
|
|
18815
|
+
await new Promise((resolve13) => setTimeout(resolve13, Math.min(25, remaining)));
|
|
18816
|
+
}
|
|
18817
|
+
return true;
|
|
18818
|
+
};
|
|
18819
|
+
if (settled()) return true;
|
|
18820
|
+
signal("SIGTERM");
|
|
18821
|
+
if (await wait2(timeoutMs)) return true;
|
|
18822
|
+
signal("SIGKILL");
|
|
18823
|
+
return wait2(1e3);
|
|
18824
|
+
}
|
|
18825
|
+
if (exited()) return true;
|
|
18765
18826
|
return new Promise((resolve13) => {
|
|
18766
18827
|
let timer;
|
|
18767
18828
|
const done = (stopped) => {
|
|
@@ -18773,35 +18834,26 @@ function killCliTree(child, timeoutMs = 5e3) {
|
|
|
18773
18834
|
child.once("close", closed);
|
|
18774
18835
|
timer = setTimeout(() => done(false), timeoutMs);
|
|
18775
18836
|
timer.unref?.();
|
|
18776
|
-
|
|
18777
|
-
|
|
18778
|
-
if (!err) return;
|
|
18779
|
-
try {
|
|
18780
|
-
child.kill();
|
|
18781
|
-
} catch {
|
|
18782
|
-
}
|
|
18783
|
-
});
|
|
18784
|
-
return;
|
|
18785
|
-
}
|
|
18786
|
-
try {
|
|
18787
|
-
process.kill(-pid, "SIGTERM");
|
|
18788
|
-
} catch {
|
|
18837
|
+
execFile3("taskkill", ["/PID", String(pid), "/T", "/F"], { windowsHide: true }, (err) => {
|
|
18838
|
+
if (!err) return;
|
|
18789
18839
|
try {
|
|
18790
|
-
child.kill(
|
|
18840
|
+
child.kill();
|
|
18791
18841
|
} catch {
|
|
18792
18842
|
}
|
|
18793
|
-
}
|
|
18843
|
+
});
|
|
18794
18844
|
});
|
|
18795
18845
|
}
|
|
18796
18846
|
function brokerSocketPath(dataDir, tag) {
|
|
18797
18847
|
return process.platform === "win32" ? `\\\\.\\pipe\\openmausbot-perm-${process.pid}-${tag}` : join10(dataDir, `perm-${tag}.sock`);
|
|
18798
18848
|
}
|
|
18799
|
-
var WINDOWS_SAFE_COMMAND_LINE_CHARS;
|
|
18849
|
+
var WINDOWS_SAFE_COMMAND_LINE_CHARS, cliGroups, stopping;
|
|
18800
18850
|
var init_procs = __esm({
|
|
18801
18851
|
"server/procs.ts"() {
|
|
18802
18852
|
"use strict";
|
|
18803
18853
|
init_env_path();
|
|
18804
18854
|
WINDOWS_SAFE_COMMAND_LINE_CHARS = 3e4;
|
|
18855
|
+
cliGroups = /* @__PURE__ */ new WeakSet();
|
|
18856
|
+
stopping = /* @__PURE__ */ new WeakMap();
|
|
18805
18857
|
}
|
|
18806
18858
|
});
|
|
18807
18859
|
|
|
@@ -18888,19 +18940,19 @@ function runNpm(args, env, cwd, timeoutMs) {
|
|
|
18888
18940
|
let timedOut = false;
|
|
18889
18941
|
const timer = setTimeout(() => {
|
|
18890
18942
|
timedOut = true;
|
|
18891
|
-
void killCliTree(child)
|
|
18943
|
+
void killCliTree(child).then((stopped) => {
|
|
18944
|
+
rejectRun(new Error(stopped ? "The install took too long and was stopped. Check the server's network connection and try again." : "The install took too long, but npm could not be confirmed stopped. Ask the server administrator to stop the install process before trying again."));
|
|
18945
|
+
});
|
|
18892
18946
|
}, timeoutMs);
|
|
18893
18947
|
timer.unref();
|
|
18894
18948
|
child.once("error", (error51) => {
|
|
18949
|
+
if (timedOut) return;
|
|
18895
18950
|
clearTimeout(timer);
|
|
18896
18951
|
rejectRun(new Error(error51.code === "ENOENT" ? "npm is not installed on this server. Install Node.js with npm for the user running OpenMausBot, then try again." : "npm could not start on this server. Check that Node.js is installed for the user running OpenMausBot."));
|
|
18897
18952
|
});
|
|
18898
18953
|
child.once("close", (code) => {
|
|
18899
18954
|
clearTimeout(timer);
|
|
18900
|
-
if (timedOut)
|
|
18901
|
-
rejectRun(new Error("The install took too long and was stopped. Check the server's network connection and try again."));
|
|
18902
|
-
return;
|
|
18903
|
-
}
|
|
18955
|
+
if (timedOut) return;
|
|
18904
18956
|
resolveRun({ code, output });
|
|
18905
18957
|
});
|
|
18906
18958
|
});
|
|
@@ -19515,6 +19567,7 @@ var init_container_computer = __esm({
|
|
|
19515
19567
|
// shared/approval-mode.ts
|
|
19516
19568
|
function supportsApprovalMode(driverKind, mode) {
|
|
19517
19569
|
if (mode === "custom") return driverKind === "codex";
|
|
19570
|
+
if (mode === "edits") return ["claudeAgent", "grokAgent", "antigravityAgent"].includes(driverKind ?? "");
|
|
19518
19571
|
if (mode !== "full") return true;
|
|
19519
19572
|
return ["codex", "claudeAgent", "antigravityAgent", "cursorAgent", "grokAgent", "opencodeGo"].includes(driverKind ?? "");
|
|
19520
19573
|
}
|
|
@@ -19712,6 +19765,20 @@ function decodeAcpConfig(defaultCli) {
|
|
|
19712
19765
|
};
|
|
19713
19766
|
};
|
|
19714
19767
|
}
|
|
19768
|
+
function sessionOperationKey(toolCall) {
|
|
19769
|
+
const rawInput = toolCall?.rawInput;
|
|
19770
|
+
const command = typeof rawInput?.command === "string" ? rawInput.command : void 0;
|
|
19771
|
+
const hasInput = rawInput && typeof rawInput === "object" && Object.keys(rawInput).length > 0;
|
|
19772
|
+
if (!command && !hasInput) return null;
|
|
19773
|
+
const stable = (value) => Array.isArray(value) ? value.map(stable) : value && typeof value === "object" ? Object.fromEntries(Object.keys(value).sort().map((key) => [key, stable(value[key])])) : value;
|
|
19774
|
+
return JSON.stringify(stable({
|
|
19775
|
+
kind: toolCall?.kind,
|
|
19776
|
+
title: toolCall?.title,
|
|
19777
|
+
command,
|
|
19778
|
+
input: rawInput,
|
|
19779
|
+
locations: toolCall?.locations
|
|
19780
|
+
}));
|
|
19781
|
+
}
|
|
19715
19782
|
function createAcpDriver(support11) {
|
|
19716
19783
|
const DRIVER_KIND8 = support11.driverKind;
|
|
19717
19784
|
const SOURCE = support11.nativeSource;
|
|
@@ -19755,6 +19822,7 @@ function createAcpDriver(support11) {
|
|
|
19755
19822
|
if (support11.resolveModelsOnCreate !== false) await refreshModels();
|
|
19756
19823
|
const listeners = /* @__PURE__ */ new Set();
|
|
19757
19824
|
const active = /* @__PURE__ */ new Map();
|
|
19825
|
+
const sessionAllows = /* @__PURE__ */ new Map();
|
|
19758
19826
|
const emit = (event) => {
|
|
19759
19827
|
for (const listener of listeners) listener(event);
|
|
19760
19828
|
};
|
|
@@ -20004,6 +20072,7 @@ function createAcpDriver(support11) {
|
|
|
20004
20072
|
flushAssistantText();
|
|
20005
20073
|
const options = Array.isArray(params.options) ? params.options : [];
|
|
20006
20074
|
const optionFor = (want) => options.find((o) => o.kind === `${want}_once` && typeof o.optionId === "string")?.optionId ?? options.find((o) => String(o.kind ?? "").startsWith(want) && typeof o.optionId === "string")?.optionId ?? null;
|
|
20075
|
+
const optionAlways = options.find((o) => o.kind === "allow_always" && typeof o.optionId === "string")?.optionId ?? null;
|
|
20007
20076
|
const cancelled = { outcome: { outcome: "cancelled" } };
|
|
20008
20077
|
const missing = (want) => emit({
|
|
20009
20078
|
...base2(threadId, turnId),
|
|
@@ -20022,15 +20091,28 @@ function createAcpDriver(support11) {
|
|
|
20022
20091
|
});
|
|
20023
20092
|
}
|
|
20024
20093
|
const kind = String(toolCall.kind ?? "");
|
|
20094
|
+
const operationKey = isQuestion || controlsHost ? null : sessionOperationKey(toolCall);
|
|
20095
|
+
if (operationKey && sessionAllows.get(threadId)?.has(operationKey)) {
|
|
20096
|
+
const allow = optionFor("allow");
|
|
20097
|
+
if (allow) {
|
|
20098
|
+
return send({ jsonrpc: "2.0", id: msg.id, result: { outcome: { outcome: "selected", optionId: allow } } });
|
|
20099
|
+
}
|
|
20100
|
+
}
|
|
20025
20101
|
const tool = kind === "execute" ? "shell" : kind === "edit" ? "edit" : kind || "tool";
|
|
20026
20102
|
const summary = String(toolCall.rawInput?.command ?? toolCall.title ?? tool).slice(0, 200);
|
|
20027
20103
|
const requestId = newId();
|
|
20028
|
-
const finish = (behavior, source = "user", message2) => {
|
|
20104
|
+
const finish = (behavior, source = "user", message2, always) => {
|
|
20029
20105
|
if (!asks.delete(requestId)) return;
|
|
20030
20106
|
clearTimeout(timer);
|
|
20031
20107
|
const want = behavior === "allow" ? "allow" : "reject";
|
|
20108
|
+
const forSession = want === "allow" && always === true && !isQuestion && !controlsHost;
|
|
20032
20109
|
const named = isQuestion && behavior === "answer" ? options.filter((option) => option.optionId === message2 || option.name?.trim() === message2) : [];
|
|
20033
|
-
const optionId = behavior === "cancel" ? null : isQuestion ? named.length === 1 && typeof named[0].optionId === "string" ? named[0].optionId : null : optionFor(want);
|
|
20110
|
+
const optionId = behavior === "cancel" ? null : isQuestion ? named.length === 1 && typeof named[0].optionId === "string" ? named[0].optionId : null : forSession ? optionAlways ?? optionFor("allow") : optionFor(want);
|
|
20111
|
+
if (forSession && !optionAlways && optionId && operationKey) {
|
|
20112
|
+
const remembered = sessionAllows.get(threadId) ?? /* @__PURE__ */ new Set();
|
|
20113
|
+
remembered.add(operationKey);
|
|
20114
|
+
sessionAllows.set(threadId, remembered);
|
|
20115
|
+
}
|
|
20034
20116
|
if (behavior !== "cancel" && !optionId) missing(isQuestion ? "matching answer" : want);
|
|
20035
20117
|
send({
|
|
20036
20118
|
jsonrpc: "2.0",
|
|
@@ -20060,7 +20142,9 @@ function createAcpDriver(support11) {
|
|
|
20060
20142
|
tool,
|
|
20061
20143
|
summary,
|
|
20062
20144
|
choices: isQuestion ? options.flatMap((option) => typeof option.name === "string" && option.name.trim() ? [option.name.trim()] : []) : void 0,
|
|
20063
|
-
approvalScope: controlsHost ? "local-computer" : void 0
|
|
20145
|
+
approvalScope: controlsHost ? "local-computer" : void 0,
|
|
20146
|
+
// the driver can honor a session-wide allow either way
|
|
20147
|
+
allowSession: !isQuestion && !controlsHost ? true : void 0
|
|
20064
20148
|
});
|
|
20065
20149
|
};
|
|
20066
20150
|
const handleNotification = (msg) => {
|
|
@@ -20222,6 +20306,7 @@ function createAcpDriver(support11) {
|
|
|
20222
20306
|
);
|
|
20223
20307
|
}
|
|
20224
20308
|
const cursor3 = typeof turn.resumeCursor === "string" ? turn.resumeCursor : null;
|
|
20309
|
+
if (!cursor3) sessionAllows.delete(threadId);
|
|
20225
20310
|
let sessionResult = null;
|
|
20226
20311
|
if (cursor3) {
|
|
20227
20312
|
try {
|
|
@@ -20380,7 +20465,7 @@ ${turn.text}` : turn.text;
|
|
|
20380
20465
|
const turn = active.get(threadId);
|
|
20381
20466
|
const finish = turn?.asks.get(requestId);
|
|
20382
20467
|
if (!finish) return "unavailable";
|
|
20383
|
-
finish(decision.behavior, "user", decision.message);
|
|
20468
|
+
finish(decision.behavior, "user", decision.message, decision.always === true);
|
|
20384
20469
|
return decision.behavior === "allow" ? "allowed-once" : decision.behavior === "answer" ? "answered" : "rejected";
|
|
20385
20470
|
},
|
|
20386
20471
|
hasSession: (threadId) => active.has(threadId),
|
|
@@ -20715,6 +20800,7 @@ var init_antigravity_acp = __esm({
|
|
|
20715
20800
|
startupDiagnosticBytes = 0;
|
|
20716
20801
|
nativeStartupHint;
|
|
20717
20802
|
closed = false;
|
|
20803
|
+
stopping;
|
|
20718
20804
|
onAuthorizationUrl;
|
|
20719
20805
|
/** Settles once the runtime process is gone. On Windows a running
|
|
20720
20806
|
* executable pins its file and its directory, so an installer must not
|
|
@@ -20839,10 +20925,10 @@ var init_antigravity_acp = __esm({
|
|
|
20839
20925
|
if (this.closed) return;
|
|
20840
20926
|
this.closed = true;
|
|
20841
20927
|
this.failAll(new Error("Antigravity ACP was closed."));
|
|
20842
|
-
killCliTree(this.child);
|
|
20928
|
+
this.stopping = killCliTree(this.child);
|
|
20843
20929
|
}
|
|
20844
|
-
/**
|
|
20845
|
-
async closeAndWait(timeoutMs =
|
|
20930
|
+
/** Allow the shared 5s TERM grace and 1s force-stop verification to finish. */
|
|
20931
|
+
async closeAndWait(timeoutMs = 7e3) {
|
|
20846
20932
|
this.close();
|
|
20847
20933
|
let timer;
|
|
20848
20934
|
const timedOut = new Promise((resolve13) => {
|
|
@@ -20850,7 +20936,7 @@ var init_antigravity_acp = __esm({
|
|
|
20850
20936
|
timer.unref?.();
|
|
20851
20937
|
});
|
|
20852
20938
|
try {
|
|
20853
|
-
return await Promise.race([this.
|
|
20939
|
+
return await Promise.race([this.stopping, timedOut]);
|
|
20854
20940
|
} finally {
|
|
20855
20941
|
clearTimeout(timer);
|
|
20856
20942
|
}
|
|
@@ -21373,8 +21459,9 @@ var init_antigravity_runtime = __esm({
|
|
|
21373
21459
|
});
|
|
21374
21460
|
|
|
21375
21461
|
// server/drivers/antigravity.ts
|
|
21376
|
-
function antigravityPermissionMode(fullAuto) {
|
|
21377
|
-
|
|
21462
|
+
function antigravityPermissionMode(fullAuto, approvalMode) {
|
|
21463
|
+
if (fullAuto) return "yolo";
|
|
21464
|
+
return approvalMode === "edits" ? "auto_edit" : "default";
|
|
21378
21465
|
}
|
|
21379
21466
|
var STATIC_ANTIGRAVITY_MODELS, managedAsset, support, AcpAntigravityDriver, AntigravityDriver;
|
|
21380
21467
|
var init_antigravity = __esm({
|
|
@@ -21458,8 +21545,8 @@ var init_antigravity = __esm({
|
|
|
21458
21545
|
return { state: "unavailable", reason: error51 instanceof Error ? error51.message : String(error51) };
|
|
21459
21546
|
}
|
|
21460
21547
|
},
|
|
21461
|
-
configureSession: async ({ request, sessionId, config: config2 }) => {
|
|
21462
|
-
const wanted = antigravityPermissionMode(config2.fullAuto);
|
|
21548
|
+
configureSession: async ({ request, sessionId, config: config2, turn }) => {
|
|
21549
|
+
const wanted = antigravityPermissionMode(config2.fullAuto, turn.approvalMode);
|
|
21463
21550
|
const result = await request("session/set_config_option", {
|
|
21464
21551
|
sessionId,
|
|
21465
21552
|
configId: "mode",
|
|
@@ -22505,11 +22592,11 @@ async function createPermissionBroker(opts) {
|
|
|
22505
22592
|
continue;
|
|
22506
22593
|
}
|
|
22507
22594
|
const ask = { id: askId, kind, tool: msg.tool ?? "tool", input: msg.input ?? {}, at: Date.now() };
|
|
22508
|
-
const finish = (behavior, message2, source) => {
|
|
22595
|
+
const finish = (behavior, message2, source, always) => {
|
|
22509
22596
|
if (!pending.delete(askId)) return;
|
|
22510
22597
|
clearTimeout(timer);
|
|
22511
22598
|
try {
|
|
22512
|
-
conn.write(JSON.stringify({ t: "answer", id: askId, behavior, message: message2 }) + "\n");
|
|
22599
|
+
conn.write(JSON.stringify({ t: "answer", id: askId, behavior, message: message2, ...always ? { always: true } : {} }) + "\n");
|
|
22513
22600
|
} catch {
|
|
22514
22601
|
}
|
|
22515
22602
|
opts.onResolve({ ...ask, behavior, source });
|
|
@@ -22579,11 +22666,11 @@ async function createPermissionBroker(opts) {
|
|
|
22579
22666
|
}
|
|
22580
22667
|
};
|
|
22581
22668
|
return {
|
|
22582
|
-
answer(askId, behavior, message2) {
|
|
22669
|
+
answer(askId, behavior, message2, always) {
|
|
22583
22670
|
const p = pending.get(askId);
|
|
22584
22671
|
if (!p) return false;
|
|
22585
22672
|
if (p.ask.kind === "question" ? behavior !== "answer" : behavior === "answer") return false;
|
|
22586
|
-
p.finish(behavior, message2, "user");
|
|
22673
|
+
p.finish(behavior, message2, "user", always && behavior === "allow");
|
|
22587
22674
|
return true;
|
|
22588
22675
|
},
|
|
22589
22676
|
pause() {
|
|
@@ -22785,6 +22872,11 @@ var init_claude = __esm({
|
|
|
22785
22872
|
const configuredIdleMinimum = Number(process.env.OMB_CLAUDE_SESSION_IDLE_MIN_MS);
|
|
22786
22873
|
const sessionIdleMinimum = Number.isFinite(configuredIdleMinimum) && configuredIdleMinimum > 0 ? configuredIdleMinimum : 1e4;
|
|
22787
22874
|
const SESSION_IDLE_MS = Math.max(sessionIdleMinimum, Number(process.env.OMB_CLAUDE_SESSION_IDLE_MS) || 10 * 6e4);
|
|
22875
|
+
const stopSession = (session) => {
|
|
22876
|
+
void killCliTree(session.child).then((stopped) => {
|
|
22877
|
+
if (stopped) void session.finishClose?.();
|
|
22878
|
+
});
|
|
22879
|
+
};
|
|
22788
22880
|
const closeSession = (threadId, why) => {
|
|
22789
22881
|
const s = sessions.get(threadId);
|
|
22790
22882
|
if (!s || s.closing) return;
|
|
@@ -22799,7 +22891,7 @@ var init_claude = __esm({
|
|
|
22799
22891
|
} catch {
|
|
22800
22892
|
}
|
|
22801
22893
|
const kill = setTimeout(() => {
|
|
22802
|
-
|
|
22894
|
+
stopSession(s);
|
|
22803
22895
|
}, 5e3);
|
|
22804
22896
|
kill.unref?.();
|
|
22805
22897
|
};
|
|
@@ -22842,7 +22934,7 @@ var init_claude = __esm({
|
|
|
22842
22934
|
const sendTurn = async (turn) => {
|
|
22843
22935
|
const { threadId } = turn;
|
|
22844
22936
|
if (active.has(threadId)) throw new Error("a turn is already running on this thread");
|
|
22845
|
-
const permissionMode = turn.approvalMode === void 0 ? config2.permissionMode : turn.approvalMode === "full" ? "bypassPermissions" : turn.approvalMode === "auto" ? "auto" : "default";
|
|
22937
|
+
const permissionMode = turn.approvalMode === void 0 ? config2.permissionMode : turn.approvalMode === "full" ? "bypassPermissions" : turn.approvalMode === "auto" ? "auto" : turn.approvalMode === "edits" ? "acceptEdits" : "default";
|
|
22846
22938
|
const controlsHost = turn.integrations?.localComputer?.scope === "local-computer";
|
|
22847
22939
|
if (controlsHost && permissionMode === "bypassPermissions" && turn.approvalMode !== "full") {
|
|
22848
22940
|
throw new Error("local computer control requires the interactive approval broker");
|
|
@@ -22987,7 +23079,7 @@ var init_claude = __esm({
|
|
|
22987
23079
|
live.turn = { turnId, settled: false, sawStreamDelta: false };
|
|
22988
23080
|
active.set(threadId, { stop: () => {
|
|
22989
23081
|
closeSession(threadId, "interrupted");
|
|
22990
|
-
|
|
23082
|
+
stopSession(live);
|
|
22991
23083
|
}, turnId, broker: live.broker });
|
|
22992
23084
|
emit({ ...base2(threadId, turnId), type: "turn.started" });
|
|
22993
23085
|
const volatile = turn.systemVolatile ?? "";
|
|
@@ -23046,6 +23138,8 @@ var init_claude = __esm({
|
|
|
23046
23138
|
onAsk: (ask) => {
|
|
23047
23139
|
const eventTurnId = sessions.get(threadId)?.turn?.turnId ?? turnId;
|
|
23048
23140
|
askTools.set(ask.id, typeof ask.tool === "string" ? ask.tool : void 0);
|
|
23141
|
+
const nativeMode = sessions.get(threadId)?.nativePermissionMode ?? null;
|
|
23142
|
+
const nativeReview = permissionMode === "auto" && nativeMode !== null ? nativeMode === "auto" ? "active" : "inactive" : void 0;
|
|
23049
23143
|
emit({
|
|
23050
23144
|
...base2(threadId, eventTurnId),
|
|
23051
23145
|
type: "request.opened",
|
|
@@ -23053,6 +23147,10 @@ var init_claude = __esm({
|
|
|
23053
23147
|
requestType: ask.kind,
|
|
23054
23148
|
tool: ask.tool,
|
|
23055
23149
|
summary: askSummary(ask),
|
|
23150
|
+
nativeReview,
|
|
23151
|
+
// the proxy hands Claude its own suggested rules on `always`;
|
|
23152
|
+
// host control stays one action at a time
|
|
23153
|
+
allowSession: ask.kind === "permission" && !(controlsHost && typeof ask.tool === "string" && ask.tool.startsWith("mcp__computer")) ? true : void 0,
|
|
23056
23154
|
approvalScope: typeof ask.tool === "string" && controlsHost && ask.tool.startsWith("mcp__computer") ? "local-computer" : void 0,
|
|
23057
23155
|
choices: Array.isArray(ask.input?.choices) ? ask.input.choices.slice(0, 5) : void 0
|
|
23058
23156
|
});
|
|
@@ -23103,6 +23201,7 @@ var init_claude = __esm({
|
|
|
23103
23201
|
volatile: turn.systemVolatile ?? "",
|
|
23104
23202
|
sessionId: sessionId ?? newSessionId,
|
|
23105
23203
|
sawInit: false,
|
|
23204
|
+
nativePermissionMode: null,
|
|
23106
23205
|
turn: { turnId, settled: false, sawStreamDelta: false },
|
|
23107
23206
|
idleTimer: null,
|
|
23108
23207
|
closing: false,
|
|
@@ -23132,6 +23231,7 @@ var init_claude = __esm({
|
|
|
23132
23231
|
};
|
|
23133
23232
|
const currentTurnId = () => session.turn?.turnId ?? turnId;
|
|
23134
23233
|
const handleLine = (line) => {
|
|
23234
|
+
if (session.closing) return;
|
|
23135
23235
|
let o;
|
|
23136
23236
|
try {
|
|
23137
23237
|
o = JSON.parse(line);
|
|
@@ -23143,6 +23243,7 @@ var init_claude = __esm({
|
|
|
23143
23243
|
case "system":
|
|
23144
23244
|
if (o.subtype === "init") {
|
|
23145
23245
|
session.sawInit = true;
|
|
23246
|
+
session.nativePermissionMode = typeof o.permissionMode === "string" ? o.permissionMode : null;
|
|
23146
23247
|
if (typeof o.session_id === "string") session.sessionId = o.session_id;
|
|
23147
23248
|
emit({ ...base2(threadId, currentTurnId()), type: "session.started", sessionId: o.session_id, model: o.model });
|
|
23148
23249
|
} else if (o.subtype === "thinking_tokens") {
|
|
@@ -23241,7 +23342,17 @@ var init_claude = __esm({
|
|
|
23241
23342
|
emit({ ...base2(threadId, currentTurnId()), type: "runtime.error", ...describeSpawnFailure(e, config2.cli) });
|
|
23242
23343
|
settle(false, "spawn_error");
|
|
23243
23344
|
});
|
|
23244
|
-
|
|
23345
|
+
let closeFinalized = false;
|
|
23346
|
+
const finalizeClose = async (code) => {
|
|
23347
|
+
if (closeFinalized) return;
|
|
23348
|
+
if (!await killCliTree(child, 0)) {
|
|
23349
|
+
session.broker?.close();
|
|
23350
|
+
session.broker = void 0;
|
|
23351
|
+
emit({ ...base2(threadId, currentTurnId()), type: "runtime.error", message: "Claude could not be confirmed stopped; its helper processes may still be running." });
|
|
23352
|
+
return;
|
|
23353
|
+
}
|
|
23354
|
+
if (closeFinalized) return;
|
|
23355
|
+
closeFinalized = true;
|
|
23245
23356
|
if (session.turn && !session.turn.settled) {
|
|
23246
23357
|
const message2 = `claude exited ${code} before result${session.stderr ? `: ${session.stderr.trim().slice(-300)}` : ""}`;
|
|
23247
23358
|
const verdict = classifyError({ exitCode: code, stderr: message2 });
|
|
@@ -23377,12 +23488,16 @@ var init_claude = __esm({
|
|
|
23377
23488
|
}
|
|
23378
23489
|
removePrivateTempDir(session.systemPromptPath);
|
|
23379
23490
|
if (sessions.get(threadId) === session) sessions.delete(threadId);
|
|
23491
|
+
};
|
|
23492
|
+
child.on("close", (code) => {
|
|
23493
|
+
session.finishClose = () => finalizeClose(code);
|
|
23494
|
+
void session.finishClose();
|
|
23380
23495
|
});
|
|
23381
23496
|
const stop = () => {
|
|
23382
23497
|
closeSession(threadId, "interrupted");
|
|
23383
23498
|
retry.cancelled = true;
|
|
23384
23499
|
retryAbort.abort();
|
|
23385
|
-
|
|
23500
|
+
stopSession(session);
|
|
23386
23501
|
};
|
|
23387
23502
|
active.set(threadId, { stop, turnId, broker });
|
|
23388
23503
|
emit({ ...base2(threadId, turnId), type: "turn.started" });
|
|
@@ -23508,7 +23623,7 @@ var init_claude = __esm({
|
|
|
23508
23623
|
const broker = sessions.get(threadId)?.broker ?? active.get(threadId)?.broker;
|
|
23509
23624
|
if (!broker) return "unavailable";
|
|
23510
23625
|
const behavior = decision.behavior === "answer" ? "answer" : decision.behavior;
|
|
23511
|
-
if (!broker.answer(requestId, behavior, decision.message)) return "unavailable";
|
|
23626
|
+
if (!broker.answer(requestId, behavior, decision.message, decision.always)) return "unavailable";
|
|
23512
23627
|
return behavior === "allow" ? "allowed-once" : behavior === "answer" ? "answered" : "rejected";
|
|
23513
23628
|
},
|
|
23514
23629
|
hasSession: (threadId) => active.has(threadId),
|
|
@@ -24820,11 +24935,17 @@ var init_codex = __esm({
|
|
|
24820
24935
|
});
|
|
24821
24936
|
send({ jsonrpc: "2.0", id, method, params });
|
|
24822
24937
|
});
|
|
24823
|
-
let
|
|
24824
|
-
const terminate = () =>
|
|
24825
|
-
|
|
24938
|
+
let stopping2;
|
|
24939
|
+
const terminate = () => stopping2 ??= killCliTree(child).then((stopped) => {
|
|
24940
|
+
if (!stopped) stopping2 = void 0;
|
|
24941
|
+
return stopped;
|
|
24942
|
+
});
|
|
24943
|
+
let completeStoppedTurn;
|
|
24944
|
+
const stop = async () => {
|
|
24826
24945
|
stopRequested = true;
|
|
24827
|
-
|
|
24946
|
+
const stopped = await terminate();
|
|
24947
|
+
if (stopped) completeStoppedTurn?.();
|
|
24948
|
+
return stopped;
|
|
24828
24949
|
};
|
|
24829
24950
|
const settle = async (ok, stopReason) => {
|
|
24830
24951
|
if (state.settled) return;
|
|
@@ -24837,12 +24958,9 @@ var init_codex = __esm({
|
|
|
24837
24958
|
active.delete(threadId);
|
|
24838
24959
|
emit({ ...base2(threadId, turnId), type: "turn.completed", ok, stopReason, cost: null, ...state.usage ? { usage: state.usage } : {} });
|
|
24839
24960
|
};
|
|
24840
|
-
|
|
24841
|
-
|
|
24842
|
-
} else {
|
|
24961
|
+
completeStoppedTurn = complete;
|
|
24962
|
+
if (!await stop()) {
|
|
24843
24963
|
emit({ ...base2(threadId, turnId), type: "runtime.error", message: "codex did not shut down after termination was requested" });
|
|
24844
|
-
if (child.exitCode !== null || child.signalCode !== null) complete();
|
|
24845
|
-
else child.once("close", complete);
|
|
24846
24964
|
}
|
|
24847
24965
|
};
|
|
24848
24966
|
const controlsHost = turn.integrations?.localComputer?.scope === "local-computer";
|
|
@@ -25081,6 +25199,10 @@ var init_codex = __esm({
|
|
|
25081
25199
|
});
|
|
25082
25200
|
child.on("close", (code) => {
|
|
25083
25201
|
if (abandoned) return;
|
|
25202
|
+
if (state.settled) {
|
|
25203
|
+
void stop();
|
|
25204
|
+
return;
|
|
25205
|
+
}
|
|
25084
25206
|
if (!state.settled) {
|
|
25085
25207
|
emit({
|
|
25086
25208
|
...base2(threadId, turnId),
|
|
@@ -25808,7 +25930,7 @@ var init_grok2 = __esm({
|
|
|
25808
25930
|
// crates/codegen/xai-grok-pager-bin/src/main.rs:1259-1273.
|
|
25809
25931
|
spawnArgs: (config2, turn) => [
|
|
25810
25932
|
"--permission-mode",
|
|
25811
|
-
config2.fullAuto ? "bypassPermissions" : turn.approvalMode === "auto" ? "auto" : "default",
|
|
25933
|
+
config2.fullAuto ? "bypassPermissions" : turn.approvalMode === "auto" ? "auto" : turn.approvalMode === "edits" ? "acceptEdits" : "default",
|
|
25812
25934
|
"agent",
|
|
25813
25935
|
...turn.model ? ["-m", turn.model] : [],
|
|
25814
25936
|
// long form on purpose: `--effort` is documented as an alias, and an
|
|
@@ -40317,9 +40439,9 @@ async function runServe(options, log = console.log) {
|
|
|
40317
40439
|
});
|
|
40318
40440
|
let tunnel = null;
|
|
40319
40441
|
let caddy = null;
|
|
40320
|
-
let
|
|
40442
|
+
let stopping2 = null;
|
|
40321
40443
|
const stop = () => {
|
|
40322
|
-
|
|
40444
|
+
stopping2 ??= (async () => {
|
|
40323
40445
|
if (tunnel) await tunnel.stop().catch(() => void 0);
|
|
40324
40446
|
if (caddy) await caddy.stop().catch(() => void 0);
|
|
40325
40447
|
if (tailscaleServing && tailscale) await tailscaleServeOff(tailscale).catch(() => void 0);
|
|
@@ -40332,7 +40454,7 @@ async function runServe(options, log = console.log) {
|
|
|
40332
40454
|
}
|
|
40333
40455
|
if (plan) cleanupTunnelOrigin(plan.origin);
|
|
40334
40456
|
})();
|
|
40335
|
-
return
|
|
40457
|
+
return stopping2;
|
|
40336
40458
|
};
|
|
40337
40459
|
const onSignal = () => {
|
|
40338
40460
|
void stop();
|
|
@@ -40341,7 +40463,7 @@ async function runServe(options, log = console.log) {
|
|
|
40341
40463
|
process.on("SIGTERM", onSignal);
|
|
40342
40464
|
try {
|
|
40343
40465
|
const deadline = Date.now() + 6e4;
|
|
40344
|
-
while (Date.now() < deadline && exited === null && !
|
|
40466
|
+
while (Date.now() < deadline && exited === null && !stopping2) {
|
|
40345
40467
|
if (await serverUp(options.port, child.pid)) break;
|
|
40346
40468
|
await new Promise((r2) => setTimeout(r2, 250));
|
|
40347
40469
|
}
|
|
@@ -40349,19 +40471,19 @@ async function runServe(options, log = console.log) {
|
|
|
40349
40471
|
if (exited !== 0) log(`OpenMausBot could not start.${logPath ? ` Details: ${logPath}` : " See the output above."}`);
|
|
40350
40472
|
return exited;
|
|
40351
40473
|
}
|
|
40352
|
-
if (
|
|
40474
|
+
if (stopping2) return await childExit;
|
|
40353
40475
|
if (!await serverUp(options.port, child.pid)) {
|
|
40354
40476
|
console.error(`OpenMausBot did not become ready within a minute.${logPath ? ` Details: ${logPath}` : " See its output above."}`);
|
|
40355
40477
|
await stop();
|
|
40356
40478
|
return 1;
|
|
40357
40479
|
}
|
|
40358
|
-
if (
|
|
40480
|
+
if (stopping2 || exited !== null) return await childExit;
|
|
40359
40481
|
if (options.domain && caddyBinary) {
|
|
40360
40482
|
try {
|
|
40361
40483
|
caddy = await startCaddy({ binary: caddyBinary, dataDir: options.dataDir, domain: options.domain, appPort: options.port, webhookPort: Number(env.OMB_WEBHOOK_PORT), log });
|
|
40362
40484
|
log(`https: Caddy serves ${publicUrl} \u2192 http://127.0.0.1:${options.port}; it gets the certificate from Let's Encrypt once DNS for ${options.domain} points at this machine`);
|
|
40363
40485
|
void caddy.exited.then((code) => {
|
|
40364
|
-
if (!
|
|
40486
|
+
if (!stopping2) log(`caddy: stopped (exit ${code ?? "signal"}); ${publicUrl} is no longer served. Stop and start the server again.`);
|
|
40365
40487
|
});
|
|
40366
40488
|
} catch (error51) {
|
|
40367
40489
|
console.error(`--domain: ${message(error51)}`);
|
|
@@ -40404,7 +40526,7 @@ async function runServe(options, log = console.log) {
|
|
|
40404
40526
|
]);
|
|
40405
40527
|
if (timer) clearTimeout(timer);
|
|
40406
40528
|
}
|
|
40407
|
-
if (!
|
|
40529
|
+
if (!stopping2 && exited === null) await showPhonePairing(options, publicUrl, log);
|
|
40408
40530
|
} else if (options.pair && !options.guided) {
|
|
40409
40531
|
log("");
|
|
40410
40532
|
log(await mintPairing(options.port, { label: options.label ? `${options.label} owner` : void 0, client: options.client, publicUrl: publicUrl ?? void 0 }));
|