openmausbot 0.1.79 → 0.1.81
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -5
- package/dist/assets/index-CKysBq-V.css +1 -0
- package/dist/assets/{index-C2Je5jdF.js → index-oLMljotU.js} +1 -1
- package/dist/assets/index-peLFiSH8.js +307 -0
- package/dist/index.html +2 -2
- package/dist-server/container-mcp.js +41 -10
- package/dist-server/drivers/agents-proxy.js +71 -17
- package/dist-server/index.js +4104 -1505
- package/dist-server/openmausbot.js +554 -163
- package/dist-server/pair-cli.js +554 -163
- package/dist-server/server/box-delete-journal.js +471 -0
- package/dist-server/server/box.js +345 -75
- package/dist-server/server/cli-phone-setup.js +2 -2
- package/dist-server/server/cli.js +84 -12
- package/dist-server/server/config.js +48 -18
- package/dist-server/server/container-computer.js +7 -0
- package/dist-server/server/contracts.js +5 -0
- package/dist-server/server/default-model-selection.js +1 -0
- package/dist-server/server/drivers/acp/core.js +112 -18
- package/dist-server/server/drivers/acp/opencode-go.js +6 -0
- package/dist-server/server/drivers/agents-proxy.js +76 -13
- package/dist-server/server/drivers/chat-mcp-tools.js +6 -1
- package/dist-server/server/drivers/claude.js +87 -63
- package/dist-server/server/drivers/codex.js +248 -51
- package/dist-server/server/drivers/native.js +6 -1
- package/dist-server/server/harness/bus.js +4 -0
- package/dist-server/server/harness/registry.js +3 -2
- package/dist-server/server/index.js +1007 -222
- package/dist-server/server/local-vm-lease.js +4 -0
- package/dist-server/server/managed-desktop.js +205 -0
- package/dist-server/server/mcp-http.js +337 -0
- package/dist-server/server/mcp-probe.js +67 -18
- package/dist-server/server/mcp-registry.js +153 -58
- package/dist-server/server/member-turn.js +13 -0
- package/dist-server/server/message-db.js +74 -8
- package/dist-server/server/model-context-window.js +20 -0
- package/dist-server/server/recall-disclosure.js +4 -0
- package/dist-server/server/recent-work.js +142 -0
- package/dist-server/server/redact.js +1 -0
- package/dist-server/server/request-auth.js +3 -1
- package/dist-server/server/room-handoffs.js +16 -6
- package/dist-server/server/routines.js +17 -0
- package/dist-server/server/screen-frame-gate.js +4 -94
- package/dist-server/server/sessions.js +22 -3
- package/dist-server/server/store.js +29 -2
- package/dist-server/server/surface.js +41 -19
- package/dist-server/server/team-setup-requests.js +1 -1
- package/dist-server/server/thread-log-rotation.js +104 -0
- package/dist-server/server/tts/fish.js +155 -0
- package/dist-server/server/tts/index.js +25 -3
- package/dist-server/server/vps-computer.js +26 -4
- package/dist-server/server/vps-ssh.js +88 -0
- package/dist-server/server/workspace-backup.js +11 -0
- package/dist-server/server/workspace.js +2 -1
- package/dist-server/shared/credential-request.js +10 -0
- package/dist-server/shared/tool-surface.js +62 -0
- package/dist-server/vps-container-mcp.js +41 -10
- package/package.json +1 -1
- package/dist/assets/index-D_TFZLlo.js +0 -305
- package/dist/assets/index-Pbb6Ao0s.css +0 -1
|
@@ -17569,6 +17569,9 @@ var init_image_generation = __esm({
|
|
|
17569
17569
|
});
|
|
17570
17570
|
|
|
17571
17571
|
// server/contracts.ts
|
|
17572
|
+
function isModelVariant(value) {
|
|
17573
|
+
return typeof value === "string" && value.length > 0 && value.length <= 256 && value.trim() === value && !new RegExp("\\p{Cc}", "u").test(value);
|
|
17574
|
+
}
|
|
17572
17575
|
var EFFORT_LEVELS, eventCounter, newEventId, newId;
|
|
17573
17576
|
var init_contracts = __esm({
|
|
17574
17577
|
"server/contracts.ts"() {
|
|
@@ -17584,21 +17587,31 @@ var init_contracts = __esm({
|
|
|
17584
17587
|
function isHarnessOwnedMcpEnvName(name) {
|
|
17585
17588
|
return name === "ELECTRON_RUN_AS_NODE" || name.startsWith("OMB_") || name.startsWith("OGB_");
|
|
17586
17589
|
}
|
|
17587
|
-
var MAX_ARGS,
|
|
17590
|
+
var MAX_ARGS, stdioEntrySchema, stdioMutationSchema, remoteEntrySchema, remoteMutationSchema;
|
|
17588
17591
|
var init_mcp_registry = __esm({
|
|
17589
17592
|
"server/mcp-registry.ts"() {
|
|
17590
17593
|
"use strict";
|
|
17591
17594
|
init_zod();
|
|
17592
17595
|
MAX_ARGS = 64;
|
|
17593
|
-
|
|
17596
|
+
stdioEntrySchema = external_exports.object({
|
|
17594
17597
|
command: external_exports.string().trim().min(1).max(1024),
|
|
17595
17598
|
args: external_exports.array(external_exports.string().max(4096)).max(MAX_ARGS).optional(),
|
|
17596
17599
|
env: external_exports.record(external_exports.string(), external_exports.string().max(16384)).optional(),
|
|
17597
17600
|
enabled: external_exports.boolean().optional()
|
|
17598
17601
|
}).strict();
|
|
17599
|
-
|
|
17602
|
+
stdioMutationSchema = stdioEntrySchema.extend({
|
|
17600
17603
|
env: external_exports.record(external_exports.string(), external_exports.union([external_exports.string().max(16384), external_exports.literal(true)])).optional()
|
|
17601
17604
|
});
|
|
17605
|
+
remoteEntrySchema = external_exports.object({
|
|
17606
|
+
/** Streamable HTTP unless the entry says the older SSE transport. */
|
|
17607
|
+
type: external_exports.enum(["http", "sse"]).optional(),
|
|
17608
|
+
url: external_exports.string().trim().min(1).max(2048),
|
|
17609
|
+
headers: external_exports.record(external_exports.string(), external_exports.string().max(16384)).optional(),
|
|
17610
|
+
enabled: external_exports.boolean().optional()
|
|
17611
|
+
}).strict();
|
|
17612
|
+
remoteMutationSchema = remoteEntrySchema.extend({
|
|
17613
|
+
headers: external_exports.record(external_exports.string(), external_exports.union([external_exports.string().max(16384), external_exports.literal(true)])).optional()
|
|
17614
|
+
});
|
|
17602
17615
|
}
|
|
17603
17616
|
});
|
|
17604
17617
|
|
|
@@ -17775,6 +17788,7 @@ function loadConfig() {
|
|
|
17775
17788
|
if (process.env.OPENCODE_API_KEY !== void 0) cfg.opencodeGo.apiKey = process.env.OPENCODE_API_KEY;
|
|
17776
17789
|
cfg.tts = { ...cfg.tts };
|
|
17777
17790
|
if (process.env.OMB_TTS_KEY !== void 0) cfg.tts.key = process.env.OMB_TTS_KEY;
|
|
17791
|
+
if (process.env.OMB_FISH_AUDIO_API_KEY !== void 0) cfg.tts.fishKey = process.env.OMB_FISH_AUDIO_API_KEY;
|
|
17778
17792
|
cfg.imageGen = { ...cfg.imageGen };
|
|
17779
17793
|
if (process.env.OMB_OPENAI_IMAGE_KEY !== void 0) cfg.imageGen.key = process.env.OMB_OPENAI_IMAGE_KEY;
|
|
17780
17794
|
if (process.env.OMB_CUSTOM_IMAGE_KEY !== void 0) cfg.imageGen.customApiKey = process.env.OMB_CUSTOM_IMAGE_KEY;
|
|
@@ -17923,7 +17937,7 @@ function instanceConfigs(cfg) {
|
|
|
17923
17937
|
}
|
|
17924
17938
|
return map3;
|
|
17925
17939
|
}
|
|
17926
|
-
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;
|
|
17940
|
+
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_THREAD_EVENT_LOG_BYTES, MAX_THREAD_EVENT_LOG_BYTES, 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;
|
|
17927
17941
|
var init_config = __esm({
|
|
17928
17942
|
"server/config.ts"() {
|
|
17929
17943
|
"use strict";
|
|
@@ -17940,6 +17954,8 @@ var init_config = __esm({
|
|
|
17940
17954
|
MIN_ROOM_TURN_TIMEOUT_MINUTES = 1;
|
|
17941
17955
|
MAX_ROOM_TURN_TIMEOUT_MINUTES = 1440;
|
|
17942
17956
|
MAX_CONCURRENT_BOT_THREADS = 10;
|
|
17957
|
+
MIN_THREAD_EVENT_LOG_BYTES = 256 * 1024;
|
|
17958
|
+
MAX_THREAD_EVENT_LOG_BYTES = 4 * 1024 * 1024 * 1024;
|
|
17943
17959
|
MIN_LOCAL_VM_MAX_INSTANCES = 1;
|
|
17944
17960
|
MAX_LOCAL_VM_MAX_INSTANCES = 4;
|
|
17945
17961
|
vpsConfigSchema = external_exports.object({
|
|
@@ -17999,7 +18015,11 @@ var init_config = __esm({
|
|
|
17999
18015
|
/** Opt-in computer sharing (a desktop lending folders, a terminal or
|
|
18000
18016
|
* computer control to a workspace). Off until explicitly enabled; there is
|
|
18001
18017
|
* no Settings toggle — see sharedComputersEnabled. */
|
|
18002
|
-
sharedComputers: external_exports.boolean().optional()
|
|
18018
|
+
sharedComputers: external_exports.boolean().optional(),
|
|
18019
|
+
/** Claude bots also load the MCP servers and connectors from this
|
|
18020
|
+
* machine's own Claude Code setup (Plugins → MCP servers switch). Off by
|
|
18021
|
+
* default: each extra tool costs tokens on every model call. */
|
|
18022
|
+
claudeUserMcp: external_exports.boolean().optional()
|
|
18003
18023
|
});
|
|
18004
18024
|
onboardingConfigSchema = external_exports.object({
|
|
18005
18025
|
/** ISO timestamp of finishing (or skipping to the end of) the welcome flow. */
|
|
@@ -18021,8 +18041,12 @@ var init_config = __esm({
|
|
|
18021
18041
|
defaultModelSelectionSchema = external_exports.object({
|
|
18022
18042
|
instanceId: external_exports.string().trim().min(1),
|
|
18023
18043
|
model: external_exports.string().trim().min(1),
|
|
18024
|
-
effort: external_exports.enum(EFFORT_LEVELS).optional()
|
|
18025
|
-
|
|
18044
|
+
effort: external_exports.enum(EFFORT_LEVELS).optional(),
|
|
18045
|
+
variant: external_exports.string().refine(isModelVariant, "invalid model variant").optional()
|
|
18046
|
+
}).refine(
|
|
18047
|
+
(selection) => selection.variant === void 0 || selection.effort === void 0,
|
|
18048
|
+
"choose either a model variant or an effort level"
|
|
18049
|
+
);
|
|
18026
18050
|
appConfigSchema = external_exports.object({
|
|
18027
18051
|
/** Verified by the dedicated domain endpoint, never a generic config patch. */
|
|
18028
18052
|
customDomain: external_exports.string().optional(),
|
|
@@ -18071,13 +18095,16 @@ var init_config = __esm({
|
|
|
18071
18095
|
/** Optional OpenCode key; persisted write-only and passed only to its child. */
|
|
18072
18096
|
opencodeGo: external_exports.object({ apiKey: optionalText }).optional(),
|
|
18073
18097
|
/** Voice settings and the selected voice id. `provider` picks the
|
|
18074
|
-
* engine: "elevenlabs" (default; needs
|
|
18075
|
-
* built-in voices, no key), or
|
|
18076
|
-
* Chatterbox server; `baseUrl`
|
|
18098
|
+
* engine: "elevenlabs" (default; needs `key`), "fish" (needs its own
|
|
18099
|
+
* `fishKey`), "system" (the Mac's built-in voices, no key), or
|
|
18100
|
+
* "chatterbox" (a local OpenAI-compatible Chatterbox server; `baseUrl`
|
|
18101
|
+
* and `model` are settings, not secrets). Cloud keys stay separate so
|
|
18102
|
+
* switching providers never overwrites or misuses the other key. */
|
|
18077
18103
|
tts: external_exports.object({
|
|
18078
18104
|
key: optionalText,
|
|
18105
|
+
fishKey: optionalText,
|
|
18079
18106
|
voice: optionalText,
|
|
18080
|
-
provider: external_exports.enum(["elevenlabs", "system", "chatterbox"]).optional(),
|
|
18107
|
+
provider: external_exports.enum(["elevenlabs", "fish", "system", "chatterbox"]).optional(),
|
|
18081
18108
|
baseUrl: external_exports.string().trim().max(2048).refine((value) => !value || /^https?:\/\//i.test(value), "the Chatterbox server address must start with http:// or https://").optional(),
|
|
18082
18109
|
model: optionalText
|
|
18083
18110
|
}).optional(),
|
|
@@ -18106,7 +18133,12 @@ var init_config = __esm({
|
|
|
18106
18133
|
* system language. Unknown tags degrade to English in the renderer. */
|
|
18107
18134
|
language: optionalText,
|
|
18108
18135
|
rooms: roomConfigSchema.optional(),
|
|
18109
|
-
threads: external_exports.object({
|
|
18136
|
+
threads: external_exports.object({
|
|
18137
|
+
maxConcurrentPerBot: external_exports.number().int().min(1).max(MAX_CONCURRENT_BOT_THREADS),
|
|
18138
|
+
/** Cap each per-thread events/ and native/ NDJSON log at this many
|
|
18139
|
+
* bytes; absent (the default) keeps today's unbounded growth (#1280). */
|
|
18140
|
+
eventLogMaxBytes: external_exports.number().int().min(MIN_THREAD_EVENT_LOG_BYTES).max(MAX_THREAD_EVENT_LOG_BYTES).optional()
|
|
18141
|
+
}).strict().optional(),
|
|
18110
18142
|
localVm: localVmConfigSchema.optional(),
|
|
18111
18143
|
features: featureConfigSchema.optional(),
|
|
18112
18144
|
onboarding: onboardingConfigSchema.optional(),
|
|
@@ -18136,6 +18168,7 @@ var init_config = __esm({
|
|
|
18136
18168
|
"BOX_TOKEN",
|
|
18137
18169
|
"OPENCODE_API_KEY",
|
|
18138
18170
|
"OMB_TTS_KEY",
|
|
18171
|
+
"OMB_FISH_AUDIO_API_KEY",
|
|
18139
18172
|
"OMB_OPENAI_IMAGE_KEY",
|
|
18140
18173
|
"OMB_CUSTOM_IMAGE_KEY",
|
|
18141
18174
|
"COMPOSIO_API_KEY",
|
|
@@ -19049,7 +19082,7 @@ var init_registry = __esm({
|
|
|
19049
19082
|
this.npmPresent = options.npmAvailable ?? npmAvailable;
|
|
19050
19083
|
this.driversByKind = new Map(drivers.map((d) => [d.driverKind, d]));
|
|
19051
19084
|
}
|
|
19052
|
-
async load(configs) {
|
|
19085
|
+
async load(configs, decorate) {
|
|
19053
19086
|
for (const [instanceId, entry] of Object.entries(configs)) {
|
|
19054
19087
|
await this.dispose(instanceId);
|
|
19055
19088
|
const driver = this.driversByKind.get(entry.driver);
|
|
@@ -19078,7 +19111,7 @@ var init_registry = __esm({
|
|
|
19078
19111
|
enabled: entry.enabled ?? true,
|
|
19079
19112
|
config: config2
|
|
19080
19113
|
});
|
|
19081
|
-
this.byId.set(instanceId, { instanceId, live });
|
|
19114
|
+
this.byId.set(instanceId, { instanceId, live: decorate ? decorate(live) : live });
|
|
19082
19115
|
} catch (e) {
|
|
19083
19116
|
this.byId.set(instanceId, {
|
|
19084
19117
|
instanceId,
|
|
@@ -19212,6 +19245,7 @@ var init_registry = __esm({
|
|
|
19212
19245
|
browserMcp: inst.adapter.capabilities.browserMcp === true,
|
|
19213
19246
|
images: inst.adapter.capabilities.images === true,
|
|
19214
19247
|
effortLevels: inst.adapter.capabilities.effortLevels,
|
|
19248
|
+
modelVariants: inst.adapter.capabilities.modelVariants === true,
|
|
19215
19249
|
queueing: inst.adapter.capabilities.queueing === true,
|
|
19216
19250
|
localComputerMcp: inst.adapter.capabilities.localComputerMcp === true,
|
|
19217
19251
|
approvalReview: inst.reviewPermission !== void 0
|
|
@@ -19600,6 +19634,8 @@ var init_redact = __esm({
|
|
|
19600
19634
|
REDACTION_MARKER = /^«redacted \d+ chars»$/;
|
|
19601
19635
|
mask = (value) => REDACTION_MARKER.test(value) ? value : `\xABredacted ${value.length} chars\xBB`;
|
|
19602
19636
|
KEY_PREFIXES = [
|
|
19637
|
+
/\bom[dg]_[A-Za-z0-9_-]{43}(?![A-Za-z0-9_-])/g,
|
|
19638
|
+
// desktop device and model-only credentials
|
|
19603
19639
|
/\bsk-(?:ant-|proj-|live-|test-)?[A-Za-z0-9_-]{16,}/g,
|
|
19604
19640
|
// anthropic / openai / stripe
|
|
19605
19641
|
/\bxai-[A-Za-z0-9_-]{20,}/g,
|
|
@@ -19632,16 +19668,84 @@ var init_redact = __esm({
|
|
|
19632
19668
|
}
|
|
19633
19669
|
});
|
|
19634
19670
|
|
|
19671
|
+
// server/thread-log-rotation.ts
|
|
19672
|
+
import { closeSync as closeSync4, fstatSync, openSync as openSync4, readSync as readSync2, renameSync as renameSync5, rmSync as rmSync4, statSync as statSync3, writeSync } from "node:fs";
|
|
19673
|
+
function currentThreadLogCap() {
|
|
19674
|
+
try {
|
|
19675
|
+
return capProvider();
|
|
19676
|
+
} catch {
|
|
19677
|
+
return null;
|
|
19678
|
+
}
|
|
19679
|
+
}
|
|
19680
|
+
function capThreadLog(file2, maxBytes) {
|
|
19681
|
+
if (typeof maxBytes !== "number" || !Number.isFinite(maxBytes) || maxBytes <= 0) return;
|
|
19682
|
+
let size;
|
|
19683
|
+
try {
|
|
19684
|
+
size = statSync3(file2).size;
|
|
19685
|
+
} catch {
|
|
19686
|
+
return;
|
|
19687
|
+
}
|
|
19688
|
+
if (size <= maxBytes) return;
|
|
19689
|
+
trimToTail(file2, Math.max(1, Math.floor(maxBytes / 2)));
|
|
19690
|
+
}
|
|
19691
|
+
function trimToTail(file2, keepBytes) {
|
|
19692
|
+
const staging = `${file2}.trim`;
|
|
19693
|
+
try {
|
|
19694
|
+
const source = openSync4(file2, "r");
|
|
19695
|
+
try {
|
|
19696
|
+
const size = fstatSync(source).size;
|
|
19697
|
+
const start = Math.max(0, size - keepBytes);
|
|
19698
|
+
const window = Buffer.allocUnsafe(size - start);
|
|
19699
|
+
let filled = 0;
|
|
19700
|
+
while (filled < window.length) {
|
|
19701
|
+
const count = readSync2(source, window, filled, window.length - filled, start + filled);
|
|
19702
|
+
if (count === 0) return;
|
|
19703
|
+
filled += count;
|
|
19704
|
+
}
|
|
19705
|
+
const firstNewline = window.indexOf(10);
|
|
19706
|
+
if (firstNewline === -1 || firstNewline + 1 >= window.length) return;
|
|
19707
|
+
const target = openSync4(staging, "w", 384);
|
|
19708
|
+
try {
|
|
19709
|
+
let written = firstNewline + 1;
|
|
19710
|
+
while (written < window.length) {
|
|
19711
|
+
const count = writeSync(target, window, written, window.length - written);
|
|
19712
|
+
if (count === 0) throw new Error(`no progress writing ${staging}`);
|
|
19713
|
+
written += count;
|
|
19714
|
+
}
|
|
19715
|
+
} finally {
|
|
19716
|
+
closeSync4(target);
|
|
19717
|
+
}
|
|
19718
|
+
} finally {
|
|
19719
|
+
closeSync4(source);
|
|
19720
|
+
}
|
|
19721
|
+
renameSync5(staging, file2);
|
|
19722
|
+
} catch {
|
|
19723
|
+
try {
|
|
19724
|
+
rmSync4(staging, { force: true });
|
|
19725
|
+
} catch {
|
|
19726
|
+
}
|
|
19727
|
+
}
|
|
19728
|
+
}
|
|
19729
|
+
var capProvider;
|
|
19730
|
+
var init_thread_log_rotation = __esm({
|
|
19731
|
+
"server/thread-log-rotation.ts"() {
|
|
19732
|
+
"use strict";
|
|
19733
|
+
capProvider = () => null;
|
|
19734
|
+
}
|
|
19735
|
+
});
|
|
19736
|
+
|
|
19635
19737
|
// server/drivers/native.ts
|
|
19636
19738
|
import { appendFileSync as appendFileSync3 } from "node:fs";
|
|
19637
19739
|
import { join as join12 } from "node:path";
|
|
19638
19740
|
function appendNative(threadId, entry) {
|
|
19741
|
+
const file2 = join12(NATIVE_DIR, `${threadId}.ndjson`);
|
|
19639
19742
|
try {
|
|
19640
19743
|
appendFileSync3(
|
|
19641
|
-
|
|
19744
|
+
file2,
|
|
19642
19745
|
JSON.stringify({ at: (/* @__PURE__ */ new Date()).toISOString(), ...entry, msg: redactSecrets(entry.msg) }) + "\n",
|
|
19643
19746
|
{ mode: 384 }
|
|
19644
19747
|
);
|
|
19748
|
+
capThreadLog(file2, currentThreadLogCap());
|
|
19645
19749
|
} catch {
|
|
19646
19750
|
}
|
|
19647
19751
|
}
|
|
@@ -19650,6 +19754,7 @@ var init_native = __esm({
|
|
|
19650
19754
|
"use strict";
|
|
19651
19755
|
init_config();
|
|
19652
19756
|
init_redact();
|
|
19757
|
+
init_thread_log_rotation();
|
|
19653
19758
|
}
|
|
19654
19759
|
});
|
|
19655
19760
|
|
|
@@ -19725,6 +19830,29 @@ import { basename as basename3, dirname as dirname5, isAbsolute, relative, resol
|
|
|
19725
19830
|
function skipSubscriptionAuthForLocalInject(model) {
|
|
19726
19831
|
return Boolean(decodeInjectId(model));
|
|
19727
19832
|
}
|
|
19833
|
+
function acpVariantOption(result) {
|
|
19834
|
+
const option = (Array.isArray(result?.configOptions) ? result.configOptions : []).find(
|
|
19835
|
+
(entry) => entry?.type === "select" && typeof entry.id === "string" && (entry.id === "effort" || entry.category === "thought_level")
|
|
19836
|
+
);
|
|
19837
|
+
if (!option) return;
|
|
19838
|
+
const options = [];
|
|
19839
|
+
const seen = /* @__PURE__ */ new Set();
|
|
19840
|
+
const collect = (entries) => {
|
|
19841
|
+
if (!Array.isArray(entries)) return;
|
|
19842
|
+
for (const entry of entries) {
|
|
19843
|
+
if (typeof entry?.value === "string" && !seen.has(entry.value)) {
|
|
19844
|
+
seen.add(entry.value);
|
|
19845
|
+
options.push({ id: entry.value, label: typeof entry.name === "string" ? entry.name : entry.value });
|
|
19846
|
+
} else if (Array.isArray(entry?.options)) collect(entry.options);
|
|
19847
|
+
}
|
|
19848
|
+
};
|
|
19849
|
+
collect(option.options);
|
|
19850
|
+
return {
|
|
19851
|
+
configId: option.id,
|
|
19852
|
+
options,
|
|
19853
|
+
...typeof option.currentValue === "string" ? { currentValue: option.currentValue } : {}
|
|
19854
|
+
};
|
|
19855
|
+
}
|
|
19728
19856
|
async function readAcpImageBlocks(images) {
|
|
19729
19857
|
return Promise.all(images.map(async (image) => ({
|
|
19730
19858
|
type: "image",
|
|
@@ -19900,6 +20028,10 @@ function createAcpDriver(support11) {
|
|
|
19900
20028
|
}
|
|
19901
20029
|
for (const [name, server] of Object.entries(turn.integrations?.custom ?? {})) {
|
|
19902
20030
|
if (servers.some((existing) => existing.name === name)) continue;
|
|
20031
|
+
if ("url" in server) {
|
|
20032
|
+
servers.push({ type: server.type, name, url: server.url, headers: acpEnv(server.headers) });
|
|
20033
|
+
continue;
|
|
20034
|
+
}
|
|
19903
20035
|
servers.push({ name, command: server.command, args: server.args, env: acpEnv(server.env) });
|
|
19904
20036
|
}
|
|
19905
20037
|
return servers;
|
|
@@ -19948,6 +20080,37 @@ function createAcpDriver(support11) {
|
|
|
19948
20080
|
const asks = /* @__PURE__ */ new Map();
|
|
19949
20081
|
let nextId = 1;
|
|
19950
20082
|
let sessionId = null;
|
|
20083
|
+
let sessionConfigResult = null;
|
|
20084
|
+
const modelOf = (result) => {
|
|
20085
|
+
const option = (Array.isArray(result?.configOptions) ? result.configOptions : []).find(
|
|
20086
|
+
(entry) => entry?.id === (support11.selectModel?.configId ?? "model")
|
|
20087
|
+
);
|
|
20088
|
+
return typeof option?.currentValue === "string" ? option.currentValue : null;
|
|
20089
|
+
};
|
|
20090
|
+
const receiveModelVariants = (result) => {
|
|
20091
|
+
sessionConfigResult = result;
|
|
20092
|
+
if (!support11.modelVariants) return;
|
|
20093
|
+
const nativeModel = modelOf(result) ?? cliTurn.model;
|
|
20094
|
+
if (!nativeModel) return;
|
|
20095
|
+
const option = acpVariantOption(result);
|
|
20096
|
+
emit({
|
|
20097
|
+
...base2(threadId, turnId),
|
|
20098
|
+
type: "session.model-variants",
|
|
20099
|
+
model: nativeModel === cliTurn.model ? turn.model ?? nativeModel : nativeModel,
|
|
20100
|
+
variants: {
|
|
20101
|
+
options: option?.options ?? [],
|
|
20102
|
+
...option?.currentValue !== void 0 ? { currentValue: option.currentValue } : {}
|
|
20103
|
+
}
|
|
20104
|
+
});
|
|
20105
|
+
};
|
|
20106
|
+
const requestedVariantOption = () => {
|
|
20107
|
+
if (!support11.modelVariants) throw new Error(`${support11.displayName} does not support model variants`);
|
|
20108
|
+
const option = acpVariantOption(sessionConfigResult);
|
|
20109
|
+
if (!option || !option.options.some((entry) => entry.id === turn.variant)) {
|
|
20110
|
+
throw new Error(`${support11.displayName} does not advertise variant ${turn.variant} for this model`);
|
|
20111
|
+
}
|
|
20112
|
+
return option;
|
|
20113
|
+
};
|
|
19951
20114
|
let interruptTimer = null;
|
|
19952
20115
|
const rpcPending = /* @__PURE__ */ new Map();
|
|
19953
20116
|
const send = (obj) => {
|
|
@@ -19957,7 +20120,7 @@ function createAcpDriver(support11) {
|
|
|
19957
20120
|
}
|
|
19958
20121
|
appendNative(threadId, { dir: "out", source: SOURCE, msg: nativeLogMessage(obj) });
|
|
19959
20122
|
};
|
|
19960
|
-
const request = (method, params, timeoutMs) => new Promise((resolve12, reject) => {
|
|
20123
|
+
const request = (method, params, timeoutMs, receive) => new Promise((resolve12, reject) => {
|
|
19961
20124
|
const id = nextId++;
|
|
19962
20125
|
let timer = null;
|
|
19963
20126
|
if (timeoutMs) {
|
|
@@ -19967,7 +20130,16 @@ function createAcpDriver(support11) {
|
|
|
19967
20130
|
}, timeoutMs);
|
|
19968
20131
|
timer.unref?.();
|
|
19969
20132
|
}
|
|
19970
|
-
rpcPending.set(id, {
|
|
20133
|
+
rpcPending.set(id, {
|
|
20134
|
+
// Consume configuration in wire order: an update following this
|
|
20135
|
+
// response may arrive before the awaiting continuation resumes.
|
|
20136
|
+
resolve: (result) => {
|
|
20137
|
+
receive?.(result);
|
|
20138
|
+
resolve12(result);
|
|
20139
|
+
},
|
|
20140
|
+
reject,
|
|
20141
|
+
timer
|
|
20142
|
+
});
|
|
19971
20143
|
send({ jsonrpc: "2.0", id, method, params });
|
|
19972
20144
|
});
|
|
19973
20145
|
const stop = () => killCliTree(child);
|
|
@@ -20150,7 +20322,12 @@ function createAcpDriver(support11) {
|
|
|
20150
20322
|
const handleNotification = (msg) => {
|
|
20151
20323
|
if (msg.method !== "session/update") return;
|
|
20152
20324
|
const p = msg.params ?? {};
|
|
20153
|
-
if (
|
|
20325
|
+
if (p._meta?.isReplay === true) return;
|
|
20326
|
+
if (support11.modelVariants && p.update?.sessionUpdate === "config_option_update") {
|
|
20327
|
+
if (!state.settled && sessionId && p.sessionId === sessionId) receiveModelVariants(p.update);
|
|
20328
|
+
return;
|
|
20329
|
+
}
|
|
20330
|
+
if (!state.promptSent) return;
|
|
20154
20331
|
const u4 = p.update ?? {};
|
|
20155
20332
|
switch (u4.sessionUpdate) {
|
|
20156
20333
|
case "agent_message_chunk": {
|
|
@@ -20307,6 +20484,7 @@ function createAcpDriver(support11) {
|
|
|
20307
20484
|
`${support11.displayName} is configured for image attachments, but this installed runtime does not advertise ACP image input. Update the ${support11.displayName} CLI or send the message without an image.`
|
|
20308
20485
|
);
|
|
20309
20486
|
}
|
|
20487
|
+
const sessionServers = mcpServers.filter((server) => !("type" in server) || init?.agentCapabilities?.mcpCapabilities?.[server.type] === true);
|
|
20310
20488
|
const cursor3 = typeof turn.resumeCursor === "string" ? turn.resumeCursor : null;
|
|
20311
20489
|
if (!cursor3) sessionAllows.delete(threadId);
|
|
20312
20490
|
let sessionResult = null;
|
|
@@ -20314,16 +20492,23 @@ function createAcpDriver(support11) {
|
|
|
20314
20492
|
try {
|
|
20315
20493
|
sessionResult = await request(
|
|
20316
20494
|
support11.resumeMethod === "resume" ? "session/resume" : "session/load",
|
|
20317
|
-
{ sessionId: cursor3, cwd, mcpServers },
|
|
20318
|
-
LOAD_SESSION_TIMEOUT
|
|
20495
|
+
{ sessionId: cursor3, cwd, mcpServers: sessionServers },
|
|
20496
|
+
LOAD_SESSION_TIMEOUT,
|
|
20497
|
+
(result2) => {
|
|
20498
|
+
if (result2) {
|
|
20499
|
+
sessionId = cursor3;
|
|
20500
|
+
receiveModelVariants(result2);
|
|
20501
|
+
}
|
|
20502
|
+
}
|
|
20319
20503
|
);
|
|
20320
|
-
if (sessionResult) sessionId = cursor3;
|
|
20321
20504
|
} catch {
|
|
20322
20505
|
}
|
|
20323
20506
|
}
|
|
20324
20507
|
if (!sessionId) {
|
|
20325
|
-
sessionResult = await request("session/new", { cwd, mcpServers }, NEW_SESSION_TIMEOUT)
|
|
20326
|
-
|
|
20508
|
+
sessionResult = await request("session/new", { cwd, mcpServers: sessionServers }, NEW_SESSION_TIMEOUT, (result2) => {
|
|
20509
|
+
sessionId = typeof result2?.sessionId === "string" ? result2.sessionId : null;
|
|
20510
|
+
receiveModelVariants(result2);
|
|
20511
|
+
});
|
|
20327
20512
|
if (!sessionId) throw new Error("session/new returned no sessionId");
|
|
20328
20513
|
}
|
|
20329
20514
|
let selectedModel = null;
|
|
@@ -20341,16 +20526,15 @@ function createAcpDriver(support11) {
|
|
|
20341
20526
|
try {
|
|
20342
20527
|
if (support11.selectModel) {
|
|
20343
20528
|
const { configId } = support11.selectModel;
|
|
20344
|
-
|
|
20345
|
-
selectedModel = currentOf(sessionResult);
|
|
20529
|
+
selectedModel = modelOf(sessionConfigResult);
|
|
20346
20530
|
if (cliTurn.model && cliTurn.model !== selectedModel) {
|
|
20347
|
-
|
|
20348
|
-
|
|
20349
|
-
|
|
20350
|
-
|
|
20351
|
-
|
|
20352
|
-
)
|
|
20531
|
+
sessionResult = await request(
|
|
20532
|
+
"session/set_config_option",
|
|
20533
|
+
{ sessionId, configId, value: cliTurn.model },
|
|
20534
|
+
INIT_TIMEOUT,
|
|
20535
|
+
receiveModelVariants
|
|
20353
20536
|
);
|
|
20537
|
+
selectedModel = modelOf(sessionConfigResult);
|
|
20354
20538
|
if (selectedModel !== cliTurn.model) {
|
|
20355
20539
|
throw new Error(
|
|
20356
20540
|
`${DRIVER_KIND8} did not switch to ${cliTurn.model} (still ${selectedModel ?? "unknown"})`
|
|
@@ -20368,16 +20552,34 @@ function createAcpDriver(support11) {
|
|
|
20368
20552
|
});
|
|
20369
20553
|
if (!selectedModel && cliTurn.model) selectedModel = cliTurn.model;
|
|
20370
20554
|
}
|
|
20555
|
+
if (turn.variant !== void 0) {
|
|
20556
|
+
const option = requestedVariantOption();
|
|
20557
|
+
await request(
|
|
20558
|
+
"session/set_config_option",
|
|
20559
|
+
{ sessionId, configId: option.configId, value: turn.variant },
|
|
20560
|
+
SESSION_CONFIG_TIMEOUT,
|
|
20561
|
+
receiveModelVariants
|
|
20562
|
+
);
|
|
20563
|
+
if (requestedVariantOption().currentValue !== turn.variant) {
|
|
20564
|
+
throw new Error(`${support11.displayName} did not apply variant ${turn.variant}`);
|
|
20565
|
+
}
|
|
20566
|
+
}
|
|
20371
20567
|
} catch (error51) {
|
|
20372
20568
|
emitSessionStarted();
|
|
20373
20569
|
throw error51;
|
|
20374
20570
|
}
|
|
20375
20571
|
emitSessionStarted();
|
|
20376
|
-
state.promptSent = true;
|
|
20377
20572
|
const text4 = support11.buildPromptText ? support11.buildPromptText(turn) : turn.system ? `${turn.system}
|
|
20378
20573
|
|
|
20379
20574
|
${turn.text}` : turn.text;
|
|
20380
20575
|
const imageBlocks = support11.images === true && runtimeAcceptsImages ? await readAcpImageBlocks(images) : [];
|
|
20576
|
+
if (support11.modelVariants && cliTurn.model && modelOf(sessionConfigResult) !== cliTurn.model) {
|
|
20577
|
+
throw new Error(`${support11.displayName} changed model before the prompt`);
|
|
20578
|
+
}
|
|
20579
|
+
if (turn.variant !== void 0 && requestedVariantOption().currentValue !== turn.variant) {
|
|
20580
|
+
throw new Error(`${support11.displayName} changed variant before the prompt`);
|
|
20581
|
+
}
|
|
20582
|
+
state.promptSent = true;
|
|
20381
20583
|
const result = await request("session/prompt", {
|
|
20382
20584
|
sessionId,
|
|
20383
20585
|
prompt: [{ type: "text", text: text4 }, ...imageBlocks]
|
|
@@ -20456,6 +20658,7 @@ ${turn.text}` : turn.text;
|
|
|
20456
20658
|
images: support11.images !== false,
|
|
20457
20659
|
nativeImageInput: support11.images === true,
|
|
20458
20660
|
effortLevels: support11.effortLevels,
|
|
20661
|
+
modelVariants: support11.modelVariants === true,
|
|
20459
20662
|
// OpenMausBot supplies a per-bot approvalMode on every harness
|
|
20460
20663
|
// turn, which safely overrides a legacy instance fullAuto value.
|
|
20461
20664
|
// Direct adapter calls that omit it still fail closed in sendTurn.
|
|
@@ -22513,7 +22716,7 @@ var init_ask_question = __esm({
|
|
|
22513
22716
|
|
|
22514
22717
|
// server/drivers/claude.ts
|
|
22515
22718
|
import { createHash as createHash5, randomBytes as randomBytes2 } from "node:crypto";
|
|
22516
|
-
import { chmodSync as chmodSync4, mkdtempSync as mkdtempSync2, readFileSync as readFileSync7, rmSync as
|
|
22719
|
+
import { chmodSync as chmodSync4, mkdtempSync as mkdtempSync2, readFileSync as readFileSync7, rmSync as rmSync5, unlinkSync as unlinkSync3, writeFileSync as writeFileSync5 } from "node:fs";
|
|
22517
22720
|
import { createServer as createNetServer } from "node:net";
|
|
22518
22721
|
import { homedir as homedir9, tmpdir as tmpdir3 } from "node:os";
|
|
22519
22722
|
import { join as join18, dirname as dirname9, isAbsolute as isAbsolute4, normalize } from "node:path";
|
|
@@ -22577,6 +22780,13 @@ function claudeEnvironment(model, source = process.env, configDir, instanceEnvir
|
|
|
22577
22780
|
function inheritsUserConfig(env) {
|
|
22578
22781
|
return env.OMB_CLAUDE_INHERIT_USER_CONFIG === "1";
|
|
22579
22782
|
}
|
|
22783
|
+
function claudeInheritWarning(env) {
|
|
22784
|
+
if (!inheritsUserConfig(env)) return void 0;
|
|
22785
|
+
return {
|
|
22786
|
+
title: "Bots inherit this machine's Claude Code setup",
|
|
22787
|
+
message: "OMB_CLAUDE_INHERIT_USER_CONFIG=1 is set on the OpenMausBot process, so every Claude bot also loads this computer's own MCP servers, connectors, skills, hooks and personal CLAUDE.md on every turn \u2014 often thousands of extra tokens per model call, and tools nobody gave the bot. Unless a bot genuinely needs a server from your user-scope Claude config, remove the variable and restart; add the server under Settings \u2192 MCP servers or the bot project's .mcp.json instead."
|
|
22788
|
+
};
|
|
22789
|
+
}
|
|
22580
22790
|
function readClaudeAuthSettings(env, instanceEnvironment = {}) {
|
|
22581
22791
|
if (CLAUDE_ACCOUNT_ENV_KEYS.some((key) => instanceEnvironment[key])) return {};
|
|
22582
22792
|
try {
|
|
@@ -22637,21 +22847,17 @@ function claudeCliUpdate(version2, cli) {
|
|
|
22637
22847
|
if (!parsed || versionAtLeast(parsed, CLAUDE_CONTEXT_CONTROL_MIN_VERSION)) return void 0;
|
|
22638
22848
|
const floor = CLAUDE_CONTEXT_CONTROL_MIN_VERSION.join(".");
|
|
22639
22849
|
const missing = Object.keys(CLAUDE_FLAG_FLOORS).filter((flag) => !claudeCliSupports(parsed, flag));
|
|
22850
|
+
const effects = [
|
|
22851
|
+
...missing.includes("--autocompact") ? ["no compaction window picked by OpenMausBot"] : [],
|
|
22852
|
+
...missing.includes("--setting-sources") ? ["bots still see this machine's own Claude Code setup"] : [],
|
|
22853
|
+
...missing.includes("--system-prompt-snapshot") ? ["coordinated resumed turns cannot refresh stale system prompts"] : []
|
|
22854
|
+
];
|
|
22640
22855
|
return {
|
|
22641
22856
|
title: "Update Claude Code for context controls",
|
|
22642
|
-
message: `Claude Code ${parsed.join(".")} predates ${floor}, so bots run without ${missing.join(", ")}:
|
|
22857
|
+
message: `Claude Code ${parsed.join(".")} predates ${floor}, so bots run without ${missing.join(", ")}: ${effects.join("; ")}. Update it, then refresh Engines.`,
|
|
22643
22858
|
command: cli === "claude" ? "claude update" : `${cli} update`
|
|
22644
22859
|
};
|
|
22645
22860
|
}
|
|
22646
|
-
function claudeCliHelpSupportsFlag(help, flag) {
|
|
22647
|
-
if (!help) return false;
|
|
22648
|
-
const escaped = flag.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
22649
|
-
return new RegExp(`^\\s*${escaped}\\b`, "m").test(help);
|
|
22650
|
-
}
|
|
22651
|
-
function claudeAutoCompactSupported(version2, help) {
|
|
22652
|
-
if (help !== null) return claudeCliHelpSupportsFlag(help, "--autocompact");
|
|
22653
|
-
return claudeCliSupports(version2, "--autocompact");
|
|
22654
|
-
}
|
|
22655
22861
|
async function resolveClaudeTurnModel(model, env) {
|
|
22656
22862
|
if (!model || decodeInjectId(model) || STATIC_CLAUDE_MODELS.options.some((option) => option.id === model)) {
|
|
22657
22863
|
return model;
|
|
@@ -22699,7 +22905,7 @@ function readClaudeModelCatalog(env = process.env) {
|
|
|
22699
22905
|
function removePrivateTempDir(filePath) {
|
|
22700
22906
|
if (!filePath) return true;
|
|
22701
22907
|
try {
|
|
22702
|
-
|
|
22908
|
+
rmSync5(dirname9(filePath), { recursive: true, force: true, maxRetries: 3, retryDelay: 50 });
|
|
22703
22909
|
return true;
|
|
22704
22910
|
} catch {
|
|
22705
22911
|
return false;
|
|
@@ -22914,6 +23120,7 @@ function decodeConfig2(raw) {
|
|
|
22914
23120
|
return {
|
|
22915
23121
|
cli: typeof o.cli === "string" ? o.cli : "claude",
|
|
22916
23122
|
...configDir ? { configDir } : {},
|
|
23123
|
+
...o.managed === true ? { managed: true } : {},
|
|
22917
23124
|
permissionMode: mode ?? "acceptEdits",
|
|
22918
23125
|
...tools !== void 0 ? { tools } : {},
|
|
22919
23126
|
...disallowedTools !== void 0 ? { disallowedTools } : {}
|
|
@@ -23003,9 +23210,12 @@ var init_claude = __esm({
|
|
|
23003
23210
|
CLAUDE_FLAG_FLOORS = {
|
|
23004
23211
|
"--strict-mcp-config": [1, 0, 60],
|
|
23005
23212
|
"--setting-sources": [1, 0, 122],
|
|
23006
|
-
"--autocompact": [2, 1, 122]
|
|
23213
|
+
"--autocompact": [2, 1, 122],
|
|
23214
|
+
// 2.1.267 is the first CLI that accepts it; below that the recorded prompt
|
|
23215
|
+
// simply is not refreshed, which is the pre-existing behaviour.
|
|
23216
|
+
"--system-prompt-snapshot": [2, 1, 267]
|
|
23007
23217
|
};
|
|
23008
|
-
CLAUDE_CONTEXT_CONTROL_MIN_VERSION = CLAUDE_FLAG_FLOORS["--
|
|
23218
|
+
CLAUDE_CONTEXT_CONTROL_MIN_VERSION = CLAUDE_FLAG_FLOORS["--system-prompt-snapshot"];
|
|
23009
23219
|
DRIVER_KIND2 = "claudeAgent";
|
|
23010
23220
|
STATIC_CLAUDE_MODELS = {
|
|
23011
23221
|
default: "claude-sonnet-5",
|
|
@@ -23044,10 +23254,14 @@ var init_claude = __esm({
|
|
|
23044
23254
|
defaultConfig: () => decodeConfig2({}),
|
|
23045
23255
|
async create(input) {
|
|
23046
23256
|
const { instanceId, config: config2 } = input;
|
|
23047
|
-
const environment = (model) => claudeEnvironment(model, { ...process.env, ...input.environment }, config2.configDir, input.environment);
|
|
23257
|
+
const environment = (model) => claudeEnvironment(config2.managed ? void 0 : model, { ...process.env, ...input.environment }, config2.configDir, input.environment);
|
|
23048
23258
|
const catalogEnv = environment();
|
|
23259
|
+
if (inheritsUserConfig(catalogEnv)) {
|
|
23260
|
+
console.error(`claude (${instanceId}): OMB_CLAUDE_INHERIT_USER_CONFIG=1 \u2014 bots inherit this machine's Claude Code MCP servers, skills, hooks and CLAUDE.md on every turn; remove it unless a bot needs a user-scope server`);
|
|
23261
|
+
}
|
|
23049
23262
|
let models2 = STATIC_CLAUDE_MODELS;
|
|
23050
23263
|
const refreshModels = async () => {
|
|
23264
|
+
if (config2.managed) return;
|
|
23051
23265
|
try {
|
|
23052
23266
|
const resolved = await mergeLocalInject(readClaudeModelCatalog(catalogEnv), catalogEnv);
|
|
23053
23267
|
if (resolved.options.length) models2 = resolved;
|
|
@@ -23056,8 +23270,15 @@ var init_claude = __esm({
|
|
|
23056
23270
|
};
|
|
23057
23271
|
await refreshModels();
|
|
23058
23272
|
let cliVersion = null;
|
|
23059
|
-
let
|
|
23060
|
-
|
|
23273
|
+
let cliVersionChecked = false;
|
|
23274
|
+
const readCliVersion = (env) => new Promise((resolve12) => {
|
|
23275
|
+
execCli(
|
|
23276
|
+
config2.cli,
|
|
23277
|
+
["--version"],
|
|
23278
|
+
{ timeout: 8e3, env },
|
|
23279
|
+
(err, stdout2) => resolve12(err ? null : stdout2.trim() || null)
|
|
23280
|
+
);
|
|
23281
|
+
});
|
|
23061
23282
|
const listeners = /* @__PURE__ */ new Set();
|
|
23062
23283
|
const active = /* @__PURE__ */ new Map();
|
|
23063
23284
|
const sessions = /* @__PURE__ */ new Map();
|
|
@@ -23124,6 +23345,9 @@ var init_claude = __esm({
|
|
|
23124
23345
|
});
|
|
23125
23346
|
const retryState = /* @__PURE__ */ new Map();
|
|
23126
23347
|
const sendTurn = async (turn, logicalTurnId) => {
|
|
23348
|
+
if (config2.managed && (!turn.model || turn.model.includes("::") || !config2.configDir || !input.environment.ANTHROPIC_API_KEY || !input.environment.ANTHROPIC_BASE_URL)) {
|
|
23349
|
+
throw new Error("Company model access is unavailable. Reconnect your organization; personal billing will not be used.");
|
|
23350
|
+
}
|
|
23127
23351
|
const { threadId, botId } = turn;
|
|
23128
23352
|
const relaunch = logicalTurnId !== void 0;
|
|
23129
23353
|
if (active.has(threadId) && !relaunch) throw new Error("a turn is already running on this thread");
|
|
@@ -23160,17 +23384,27 @@ var init_claude = __esm({
|
|
|
23160
23384
|
args.push("--disallowedTools", config2.disallowedTools.join(","));
|
|
23161
23385
|
}
|
|
23162
23386
|
const turnEnvironment = environment();
|
|
23387
|
+
if (turn.refreshSystemPrompt && !cliVersionChecked) {
|
|
23388
|
+
const version2 = await readCliVersion(turnEnvironment);
|
|
23389
|
+
if (version2) {
|
|
23390
|
+
cliVersion = parseClaudeCliVersion(version2);
|
|
23391
|
+
cliVersionChecked = true;
|
|
23392
|
+
}
|
|
23393
|
+
}
|
|
23163
23394
|
const isolated = !inheritsUserConfig(turnEnvironment);
|
|
23164
23395
|
if (isolated) {
|
|
23165
|
-
if (claudeCliSupports(cliVersion, "--strict-mcp-config")) args.push("--strict-mcp-config");
|
|
23396
|
+
if (!turn.mcpFromUserConfig && claudeCliSupports(cliVersion, "--strict-mcp-config")) args.push("--strict-mcp-config");
|
|
23166
23397
|
if (claudeCliSupports(cliVersion, "--setting-sources")) args.push("--setting-sources", "project");
|
|
23167
23398
|
}
|
|
23168
23399
|
const compactWindow = autoCompactWindow(turnEnvironment);
|
|
23169
|
-
if (compactWindow &&
|
|
23400
|
+
if (compactWindow && claudeCliSupports(cliVersion, "--autocompact")) {
|
|
23170
23401
|
args.push("--autocompact", compactWindow);
|
|
23171
23402
|
}
|
|
23172
|
-
|
|
23173
|
-
|
|
23403
|
+
if (turn.refreshSystemPrompt && cliVersionChecked && claudeCliSupports(cliVersion, "--system-prompt-snapshot")) {
|
|
23404
|
+
args.push("--system-prompt-snapshot", "off");
|
|
23405
|
+
}
|
|
23406
|
+
const turnModel = config2.managed ? turn.model : await resolveClaudeTurnModel(turn.model, turnEnvironment);
|
|
23407
|
+
const injected = config2.managed ? { model: turnModel ?? null, injected: false } : applyClaudeInject({ ...turnEnvironment }, turnModel);
|
|
23174
23408
|
if (injected.model) args.push("--model", injected.model);
|
|
23175
23409
|
if (turn.effort) args.push("--effort", turn.effort);
|
|
23176
23410
|
let systemPromptPath = null;
|
|
@@ -23289,7 +23523,7 @@ var init_claude = __esm({
|
|
|
23289
23523
|
retryState.delete(threadId);
|
|
23290
23524
|
if (mcpConfigPath) {
|
|
23291
23525
|
try {
|
|
23292
|
-
|
|
23526
|
+
rmSync5(dirname9(mcpConfigPath), { recursive: true, force: true });
|
|
23293
23527
|
} catch {
|
|
23294
23528
|
}
|
|
23295
23529
|
}
|
|
@@ -23297,7 +23531,7 @@ var init_claude = __esm({
|
|
|
23297
23531
|
}
|
|
23298
23532
|
if (mcpConfigPath) {
|
|
23299
23533
|
try {
|
|
23300
|
-
|
|
23534
|
+
rmSync5(dirname9(mcpConfigPath), { recursive: true, force: true });
|
|
23301
23535
|
} catch {
|
|
23302
23536
|
}
|
|
23303
23537
|
}
|
|
@@ -23309,7 +23543,7 @@ var init_claude = __esm({
|
|
|
23309
23543
|
broker = void 0;
|
|
23310
23544
|
if (mcpConfigPath) {
|
|
23311
23545
|
try {
|
|
23312
|
-
|
|
23546
|
+
rmSync5(dirname9(mcpConfigPath), { recursive: true, force: true });
|
|
23313
23547
|
} catch {
|
|
23314
23548
|
}
|
|
23315
23549
|
mcpConfigPath = null;
|
|
@@ -23424,7 +23658,7 @@ var init_claude = __esm({
|
|
|
23424
23658
|
session.broker?.pause();
|
|
23425
23659
|
if (session.mcpConfigPath) {
|
|
23426
23660
|
try {
|
|
23427
|
-
|
|
23661
|
+
rmSync5(dirname9(session.mcpConfigPath), { recursive: true, force: true });
|
|
23428
23662
|
} catch {
|
|
23429
23663
|
}
|
|
23430
23664
|
session.mcpConfigPath = null;
|
|
@@ -23506,7 +23740,10 @@ var init_claude = __esm({
|
|
|
23506
23740
|
type: "thread.token-usage.updated",
|
|
23507
23741
|
input: (msg.usage.input_tokens || 0) + (msg.usage.cache_read_input_tokens || 0),
|
|
23508
23742
|
output: msg.usage.output_tokens || 0,
|
|
23509
|
-
...typeof msg.usage.cache_read_input_tokens === "number" ? { cachedInput: msg.usage.cache_read_input_tokens } : {}
|
|
23743
|
+
...typeof msg.usage.cache_read_input_tokens === "number" ? { cachedInput: msg.usage.cache_read_input_tokens } : {},
|
|
23744
|
+
// one assistant message = one model call, and its prompt is
|
|
23745
|
+
// everything in the window: fresh text, cache reads and writes
|
|
23746
|
+
contextTokens: (msg.usage.input_tokens || 0) + (msg.usage.cache_read_input_tokens || 0) + (msg.usage.cache_creation_input_tokens || 0)
|
|
23510
23747
|
});
|
|
23511
23748
|
}
|
|
23512
23749
|
break;
|
|
@@ -23575,7 +23812,7 @@ var init_claude = __esm({
|
|
|
23575
23812
|
failedBroker?.close();
|
|
23576
23813
|
if (session.mcpConfigPath) {
|
|
23577
23814
|
try {
|
|
23578
|
-
|
|
23815
|
+
rmSync5(dirname9(session.mcpConfigPath), { recursive: true, force: true });
|
|
23579
23816
|
} catch {
|
|
23580
23817
|
}
|
|
23581
23818
|
session.mcpConfigPath = null;
|
|
@@ -23653,7 +23890,7 @@ var init_claude = __esm({
|
|
|
23653
23890
|
session.broker = void 0;
|
|
23654
23891
|
if (session.mcpConfigPath) {
|
|
23655
23892
|
try {
|
|
23656
|
-
|
|
23893
|
+
rmSync5(dirname9(session.mcpConfigPath), { recursive: true, force: true });
|
|
23657
23894
|
} catch {
|
|
23658
23895
|
}
|
|
23659
23896
|
session.mcpConfigPath = null;
|
|
@@ -23704,7 +23941,7 @@ var init_claude = __esm({
|
|
|
23704
23941
|
session.broker?.close();
|
|
23705
23942
|
if (session.mcpConfigPath) {
|
|
23706
23943
|
try {
|
|
23707
|
-
|
|
23944
|
+
rmSync5(dirname9(session.mcpConfigPath), { recursive: true, force: true });
|
|
23708
23945
|
} catch {
|
|
23709
23946
|
}
|
|
23710
23947
|
}
|
|
@@ -23739,38 +23976,14 @@ var init_claude = __esm({
|
|
|
23739
23976
|
} });
|
|
23740
23977
|
const snapshot = async () => {
|
|
23741
23978
|
const env = environment();
|
|
23742
|
-
const version2 = await
|
|
23743
|
-
execCli(
|
|
23744
|
-
config2.cli,
|
|
23745
|
-
["--version"],
|
|
23746
|
-
{ timeout: 8e3, env },
|
|
23747
|
-
(err, stdout2) => resolve12(err ? null : stdout2.trim())
|
|
23748
|
-
);
|
|
23749
|
-
});
|
|
23979
|
+
const version2 = await readCliVersion(env);
|
|
23750
23980
|
if (!version2) return { state: "unavailable", reason: `\`${config2.cli}\` CLI not found` };
|
|
23751
23981
|
cliVersion = parseClaudeCliVersion(version2);
|
|
23752
|
-
|
|
23753
|
-
cliHelp = await new Promise((resolve12) => {
|
|
23754
|
-
execCli(
|
|
23755
|
-
config2.cli,
|
|
23756
|
-
["--help"],
|
|
23757
|
-
{ timeout: 8e3, env },
|
|
23758
|
-
(err, stdout2) => resolve12(err ? null : stdout2)
|
|
23759
|
-
);
|
|
23760
|
-
});
|
|
23761
|
-
cliHelpVersion = version2;
|
|
23762
|
-
}
|
|
23763
|
-
const features = cliHelp !== null ? { autocompact: claudeCliHelpSupportsFlag(cliHelp, "--autocompact") } : void 0;
|
|
23982
|
+
cliVersionChecked = true;
|
|
23764
23983
|
const auth = await claudeAuthStatus(config2.cli, env);
|
|
23765
23984
|
const update = claudeCliUpdate(version2, config2.cli);
|
|
23766
|
-
|
|
23767
|
-
|
|
23768
|
-
version: version2,
|
|
23769
|
-
...auth,
|
|
23770
|
-
...update ? { update } : {},
|
|
23771
|
-
...features ? { features } : {},
|
|
23772
|
-
billing: "subscription"
|
|
23773
|
-
};
|
|
23985
|
+
const warning = claudeInheritWarning(env);
|
|
23986
|
+
return { state: "available", version: version2, ...auth, ...update ? { update } : {}, ...warning ? { warning } : {}, billing: "subscription" };
|
|
23774
23987
|
};
|
|
23775
23988
|
const generateReview = (prompt, signal) => new Promise((resolve12, reject) => {
|
|
23776
23989
|
const child = spawnCli(
|
|
@@ -24709,6 +24922,9 @@ var init_codex_identity = __esm({
|
|
|
24709
24922
|
// server/drivers/codex.ts
|
|
24710
24923
|
import { existsSync as existsSync10 } from "node:fs";
|
|
24711
24924
|
import { homedir as homedir13 } from "node:os";
|
|
24925
|
+
function missingNativeCodexThread(error51, cursor3) {
|
|
24926
|
+
return error51 instanceof CodexRpcError && error51.code === -32600 && error51.message === `no rollout found for thread id ${cursor3}`;
|
|
24927
|
+
}
|
|
24712
24928
|
function codexPredatesAstra(version2) {
|
|
24713
24929
|
const value = version2.trim();
|
|
24714
24930
|
const match = /\bcodex-cli\s+v?(\d+)\.(\d+)\.(\d+)(?:[-+][0-9a-z.-]+)?(?![\d.])\b/i.exec(value) ?? /^v?(\d+)\.(\d+)\.(\d+)(?:[-+][0-9a-z.-]+)?$/i.exec(value);
|
|
@@ -24743,9 +24959,48 @@ function decodeConfig3(raw) {
|
|
|
24743
24959
|
const o = raw ?? {};
|
|
24744
24960
|
return {
|
|
24745
24961
|
cli: typeof o.cli === "string" ? o.cli : "codex",
|
|
24746
|
-
fullAuto: o.fullAuto === true
|
|
24962
|
+
fullAuto: o.fullAuto === true,
|
|
24963
|
+
...o.managed && typeof o.managed === "object" ? { managed: decodeManagedCodex(o.managed) } : {}
|
|
24747
24964
|
};
|
|
24748
24965
|
}
|
|
24966
|
+
function decodeManagedCodex(raw) {
|
|
24967
|
+
const value = raw;
|
|
24968
|
+
if (typeof value.url !== "string" || !Array.isArray(value.models) || !value.models.length || value.models.some((model) => typeof model !== "string" || !/^[\w][\w./+-]*$/.test(model))) {
|
|
24969
|
+
throw new Error("Invalid Company Codex configuration.");
|
|
24970
|
+
}
|
|
24971
|
+
const url2 = new URL(value.url);
|
|
24972
|
+
const loopback = url2.hostname === "localhost" || url2.hostname === "[::1]" || /^127(?:\.\d{1,3}){3}$/.test(url2.hostname);
|
|
24973
|
+
if (url2.username || url2.password || url2.search || url2.hash || url2.protocol !== "https:" && !(url2.protocol === "http:" && loopback)) throw new Error("Invalid Company Codex endpoint.");
|
|
24974
|
+
return { url: url2.href.replace(/\/$/, ""), models: value.models };
|
|
24975
|
+
}
|
|
24976
|
+
function managedCodexArgs(config2) {
|
|
24977
|
+
return [
|
|
24978
|
+
"-c",
|
|
24979
|
+
'model_provider="openmaus_company"',
|
|
24980
|
+
"-c",
|
|
24981
|
+
'model_providers.openmaus_company.name="Company"',
|
|
24982
|
+
"-c",
|
|
24983
|
+
`model_providers.openmaus_company.base_url=${JSON.stringify(config2.url)}`,
|
|
24984
|
+
"-c",
|
|
24985
|
+
'model_providers.openmaus_company.env_key="OPENMAUSBOT_COMPANY_API_KEY"',
|
|
24986
|
+
"-c",
|
|
24987
|
+
'model_providers.openmaus_company.wire_api="responses"',
|
|
24988
|
+
"-c",
|
|
24989
|
+
"model_providers.openmaus_company.requires_openai_auth=false",
|
|
24990
|
+
"-c",
|
|
24991
|
+
'cli_auth_credentials_store="ephemeral"',
|
|
24992
|
+
"-c",
|
|
24993
|
+
"shell_environment_policy.ignore_default_excludes=false"
|
|
24994
|
+
];
|
|
24995
|
+
}
|
|
24996
|
+
function noteSkippedSseServer(name) {
|
|
24997
|
+
if (skippedSseServers.has(name)) return;
|
|
24998
|
+
skippedSseServers.add(name);
|
|
24999
|
+
console.error(`codex: MCP server ${JSON.stringify(name)} uses the SSE transport, which codex does not speak \u2014 it is available to Claude bots only`);
|
|
25000
|
+
}
|
|
25001
|
+
function tomlInlineTable(entries) {
|
|
25002
|
+
return `{ ${Object.entries(entries).map(([key, value]) => `${JSON.stringify(key)} = ${JSON.stringify(value)}`).join(", ")} }`;
|
|
25003
|
+
}
|
|
24749
25004
|
function grantedPermissions(raw) {
|
|
24750
25005
|
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return {};
|
|
24751
25006
|
return Object.fromEntries(
|
|
@@ -24945,23 +25200,43 @@ function codexNativeIncomingLogMessage(message2, sensitiveResponseIds) {
|
|
|
24945
25200
|
return message2;
|
|
24946
25201
|
}
|
|
24947
25202
|
function mountMcpServer(appServerArgs, env, name, server, preApproved = true) {
|
|
24948
|
-
Object.assign(env, server.env);
|
|
24949
25203
|
const prefix = `mcp_servers.${name}`;
|
|
24950
|
-
|
|
24951
|
-
"-c",
|
|
24952
|
-
|
|
24953
|
-
|
|
24954
|
-
|
|
24955
|
-
|
|
24956
|
-
|
|
24957
|
-
|
|
24958
|
-
|
|
24959
|
-
|
|
25204
|
+
if ("url" in server) {
|
|
25205
|
+
appServerArgs.push("-c", `${prefix}.url=${JSON.stringify(server.url)}`);
|
|
25206
|
+
const stem = `OMB_MCP_HEADER_${name.toUpperCase().replace(/[^A-Z0-9]/g, "_")}`;
|
|
25207
|
+
const variables = {};
|
|
25208
|
+
Object.entries(server.headers).forEach(([header, value], index) => {
|
|
25209
|
+
const bearer = header.toLowerCase() === "authorization" ? /^Bearer\s+(\S+)$/i.exec(value) : null;
|
|
25210
|
+
if (bearer) {
|
|
25211
|
+
env[`${stem}_BEARER`] = bearer[1];
|
|
25212
|
+
appServerArgs.push("-c", `${prefix}.bearer_token_env_var=${JSON.stringify(`${stem}_BEARER`)}`);
|
|
25213
|
+
return;
|
|
25214
|
+
}
|
|
25215
|
+
const variable = `${stem}_${index}`;
|
|
25216
|
+
env[variable] = value;
|
|
25217
|
+
variables[header] = variable;
|
|
25218
|
+
});
|
|
25219
|
+
if (Object.keys(variables).length) {
|
|
25220
|
+
appServerArgs.push("-c", `${prefix}.env_http_headers=${tomlInlineTable(variables)}`);
|
|
25221
|
+
}
|
|
25222
|
+
} else {
|
|
25223
|
+
Object.assign(env, server.env);
|
|
25224
|
+
appServerArgs.push(
|
|
25225
|
+
"-c",
|
|
25226
|
+
`${prefix}.command=${JSON.stringify(server.command)}`,
|
|
25227
|
+
"-c",
|
|
25228
|
+
`${prefix}.args=${JSON.stringify(server.args)}`,
|
|
25229
|
+
// Values stay in the child environment; argv contains names only so
|
|
25230
|
+
// credentials never appear in process listings or diagnostics.
|
|
25231
|
+
"-c",
|
|
25232
|
+
`${prefix}.env_vars=${JSON.stringify(Object.keys(server.env))}`
|
|
25233
|
+
);
|
|
25234
|
+
}
|
|
24960
25235
|
if (preApproved) {
|
|
24961
25236
|
appServerArgs.push("-c", `${prefix}.default_tools_approval_mode="auto"`);
|
|
24962
25237
|
}
|
|
24963
25238
|
}
|
|
24964
|
-
var DRIVER_KIND3, ASTRA_MODEL_ID, ASTRA_MIN_CODEX_VERSION, QUESTION_TIMEOUT_NOTE2, DENY_TIMEOUT_NOTE2, plainRecord, containsControlCharacter, CodexDriver;
|
|
25239
|
+
var DRIVER_KIND3, ASTRA_MODEL_ID, ASTRA_MIN_CODEX_VERSION, CodexRpcError, QUESTION_TIMEOUT_NOTE2, DENY_TIMEOUT_NOTE2, skippedSseServers, plainRecord, containsControlCharacter, CodexDriver;
|
|
24965
25240
|
var init_codex = __esm({
|
|
24966
25241
|
"server/drivers/codex.ts"() {
|
|
24967
25242
|
"use strict";
|
|
@@ -24978,12 +25253,21 @@ var init_codex = __esm({
|
|
|
24978
25253
|
init_codex_instructions();
|
|
24979
25254
|
init_codex_device_auth();
|
|
24980
25255
|
init_codex_identity();
|
|
25256
|
+
init_resume_recovery();
|
|
24981
25257
|
init_codex_catalog();
|
|
24982
25258
|
DRIVER_KIND3 = "codex";
|
|
24983
25259
|
ASTRA_MODEL_ID = "gpt-6-astra";
|
|
24984
25260
|
ASTRA_MIN_CODEX_VERSION = [0, 153, 1];
|
|
25261
|
+
CodexRpcError = class extends Error {
|
|
25262
|
+
code;
|
|
25263
|
+
constructor(error51) {
|
|
25264
|
+
super(error51.message ?? JSON.stringify(error51));
|
|
25265
|
+
this.code = error51.code;
|
|
25266
|
+
}
|
|
25267
|
+
};
|
|
24985
25268
|
QUESTION_TIMEOUT_NOTE2 = "No answer was given \u2014 use your best judgment.";
|
|
24986
25269
|
DENY_TIMEOUT_NOTE2 = "OpenMausBot: nobody answered this permission request in time. Skip this action and finish what you can without it.";
|
|
25270
|
+
skippedSseServers = /* @__PURE__ */ new Set();
|
|
24987
25271
|
plainRecord = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
24988
25272
|
containsControlCharacter = (value) => {
|
|
24989
25273
|
for (const character of value) {
|
|
@@ -25022,8 +25306,9 @@ var init_codex = __esm({
|
|
|
25022
25306
|
return env;
|
|
25023
25307
|
};
|
|
25024
25308
|
const catalogEnv = childEnv();
|
|
25025
|
-
let models2 = STATIC_CODEX_MODELS;
|
|
25309
|
+
let models2 = config2.managed ? { default: config2.managed.models[0], options: config2.managed.models.map((id) => ({ id, label: id })) } : STATIC_CODEX_MODELS;
|
|
25026
25310
|
const refreshModels = async () => {
|
|
25311
|
+
if (config2.managed) return;
|
|
25027
25312
|
try {
|
|
25028
25313
|
const resolved = await readCodexModelCatalog(catalogEnv, fetch, config2.cli);
|
|
25029
25314
|
if (resolved.options.length) models2 = resolved;
|
|
@@ -25049,11 +25334,28 @@ var init_codex = __esm({
|
|
|
25049
25334
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
25050
25335
|
});
|
|
25051
25336
|
const sendTurn = async (turn) => {
|
|
25337
|
+
if (config2.managed) {
|
|
25338
|
+
if (!turn.model) {
|
|
25339
|
+
throw new Error("Company model access is unavailable: no model is selected. Reconnect your organization; personal billing will not be used.");
|
|
25340
|
+
}
|
|
25341
|
+
if (!config2.managed.models.includes(turn.model)) {
|
|
25342
|
+
throw new Error("Company model access is unavailable: " + turn.model + " is not approved for your organization. Reconnect your organization; personal billing will not be used.");
|
|
25343
|
+
}
|
|
25344
|
+
if (!input.environment.OPENMAUSBOT_COMPANY_API_KEY) {
|
|
25345
|
+
throw new Error("Company model access is unavailable: OPENMAUSBOT_COMPANY_API_KEY is missing. Reconnect your organization; personal billing will not be used.");
|
|
25346
|
+
}
|
|
25347
|
+
if (!input.environment.CODEX_HOME) {
|
|
25348
|
+
throw new Error("Company model access is unavailable: CODEX_HOME is missing. Reconnect your organization; personal billing will not be used.");
|
|
25349
|
+
}
|
|
25350
|
+
}
|
|
25052
25351
|
let stopRequested = false;
|
|
25352
|
+
let promptSubmitted = false;
|
|
25353
|
+
let recoveredMissingSession = false;
|
|
25053
25354
|
const stopSignal = new AbortController();
|
|
25054
25355
|
const { threadId } = turn;
|
|
25055
25356
|
const approvalMode = turn.approvalMode ?? (config2.fullAuto ? "full" : "ask");
|
|
25056
25357
|
for (const [name, server] of Object.entries(turn.integrations?.custom ?? {})) {
|
|
25358
|
+
if ("url" in server) continue;
|
|
25057
25359
|
const reserved = Object.keys(server.env).find(isHarnessOwnedMcpEnvName);
|
|
25058
25360
|
if (reserved) {
|
|
25059
25361
|
throw new Error(`Custom MCP server \u201C${name}\u201D cannot set reserved environment variable \u201C${reserved}\u201D`);
|
|
@@ -25065,7 +25367,7 @@ var init_codex = __esm({
|
|
|
25065
25367
|
const retryScale = Number(process.env.FAKE_CODEX_RETRY_SCALE ?? "1");
|
|
25066
25368
|
const launchAttempt = async (attempt) => {
|
|
25067
25369
|
const env = childEnv();
|
|
25068
|
-
const appServerArgs = ["app-server", ...codexLocalProviderArgs(env, turn.model)];
|
|
25370
|
+
const appServerArgs = ["app-server", ...config2.managed ? managedCodexArgs(config2.managed) : codexLocalProviderArgs(env, turn.model)];
|
|
25069
25371
|
if (turn.integrations?.composio) {
|
|
25070
25372
|
mountMcpServer(appServerArgs, env, "openmausbot_connectors", turn.integrations.composio);
|
|
25071
25373
|
}
|
|
@@ -25079,6 +25381,10 @@ var init_codex = __esm({
|
|
|
25079
25381
|
mountMcpServer(appServerArgs, env, "browser", turn.integrations.browser);
|
|
25080
25382
|
}
|
|
25081
25383
|
for (const [name, server] of Object.entries(turn.integrations?.custom ?? {})) {
|
|
25384
|
+
if ("url" in server && server.type === "sse") {
|
|
25385
|
+
noteSkippedSseServer(name);
|
|
25386
|
+
continue;
|
|
25387
|
+
}
|
|
25082
25388
|
mountMcpServer(appServerArgs, env, name, server, false);
|
|
25083
25389
|
}
|
|
25084
25390
|
if (turn.integrations?.phone) {
|
|
@@ -25111,9 +25417,12 @@ var init_codex = __esm({
|
|
|
25111
25417
|
lastError: "",
|
|
25112
25418
|
lastText: "",
|
|
25113
25419
|
sawStreamDelta: false,
|
|
25114
|
-
// codex reports token usage as a running
|
|
25115
|
-
// wants this turn's figure
|
|
25116
|
-
|
|
25420
|
+
// codex reports token usage as a running total for this app-server
|
|
25421
|
+
// process. The harness wants this turn's figure: the total minus
|
|
25422
|
+
// whatever the process already carried before turn/start (a resumed
|
|
25423
|
+
// thread may restore earlier usage), banked on settle.
|
|
25424
|
+
usage: void 0,
|
|
25425
|
+
usageBaseline: void 0
|
|
25117
25426
|
};
|
|
25118
25427
|
const asks = /* @__PURE__ */ new Map();
|
|
25119
25428
|
let nextId = 1;
|
|
@@ -25140,6 +25449,12 @@ var init_codex = __esm({
|
|
|
25140
25449
|
rpcPending.set(id, {
|
|
25141
25450
|
resolve: (v) => {
|
|
25142
25451
|
clearTimeout(timer);
|
|
25452
|
+
if (method === "thread/start" || method === "thread/resume") {
|
|
25453
|
+
const returnedId = v?.thread?.id;
|
|
25454
|
+
const requestedId = method === "thread/resume" && params && typeof params === "object" && "threadId" in params ? params.threadId : null;
|
|
25455
|
+
if (typeof returnedId === "string" && returnedId) codexThreadId = returnedId;
|
|
25456
|
+
else if (typeof requestedId === "string" && requestedId) codexThreadId = requestedId;
|
|
25457
|
+
}
|
|
25143
25458
|
if (method === "turn/start") {
|
|
25144
25459
|
if (typeof v?.turn?.id !== "string" || !v.turn.id) {
|
|
25145
25460
|
reject(new Error("Codex did not return a native turn id"));
|
|
@@ -25214,6 +25529,18 @@ var init_codex = __esm({
|
|
|
25214
25529
|
}
|
|
25215
25530
|
return;
|
|
25216
25531
|
}
|
|
25532
|
+
if (isQuestion && (!Array.isArray(params.questions) || params.questions.length !== 1)) {
|
|
25533
|
+
const bundled = Array.isArray(params.questions) && params.questions.length > 1;
|
|
25534
|
+
send({
|
|
25535
|
+
jsonrpc: "2.0",
|
|
25536
|
+
id: msg.id,
|
|
25537
|
+
error: {
|
|
25538
|
+
code: -32602,
|
|
25539
|
+
message: bundled ? `ask supports one question per call; this request bundled ${params.questions.length}. Split it into separate asks, one question each.` : Array.isArray(params.questions) ? "ask supports one question per call; this request sent none." : "ask supports one question per call; params.questions must be an array with exactly one question."
|
|
25540
|
+
}
|
|
25541
|
+
});
|
|
25542
|
+
return;
|
|
25543
|
+
}
|
|
25217
25544
|
const mcpTool = isLegacyMcpPermission ? String(params.message ?? "").match(/tool "([^"]+)"/)?.[1] : void 0;
|
|
25218
25545
|
const tool = mcpAppApproval ? mcpAppApproval.tool : isLegacyMcpPermission ? mcpTool ?? "mcp" : isAdditionalPermission ? "permissions" : method === "item/fileChange/requestApproval" || method === "applyPatchApproval" ? "edit" : isQuestion ? "ask_user" : "shell";
|
|
25219
25546
|
const permissionResult = (allow) => isMcpPermission ? allow ? mcpAppApproval?.allowResult ?? { action: "accept", content: {} } : { action: "decline" } : isAdditionalPermission ? { permissions: allow ? grantedPermissions(params.permissions) : {}, scope: "turn" } : { decision: allow ? legacy ? "approved" : "accept" : legacy ? "denied" : "decline" };
|
|
@@ -25268,6 +25595,11 @@ var init_codex = __esm({
|
|
|
25268
25595
|
const connectionError = msg.method === "error" && !("threadId" in p) && !("turnId" in p);
|
|
25269
25596
|
if (!connectionError) {
|
|
25270
25597
|
if (!codexThreadId || p.threadId !== codexThreadId) return;
|
|
25598
|
+
if (!codexTurnId && msg.method === "thread/tokenUsage/updated" && p.tokenUsage?.total) {
|
|
25599
|
+
const t2 = p.tokenUsage.total;
|
|
25600
|
+
state.usageBaseline = { input: t2.inputTokens ?? 0, output: t2.outputTokens ?? 0, cachedInput: t2.cachedInputTokens ?? 0 };
|
|
25601
|
+
return;
|
|
25602
|
+
}
|
|
25271
25603
|
if (!codexTurnId) {
|
|
25272
25604
|
if (startingNativeTurn) {
|
|
25273
25605
|
if (earlyNotifications.length >= 1024) {
|
|
@@ -25351,22 +25683,35 @@ var init_codex = __esm({
|
|
|
25351
25683
|
break;
|
|
25352
25684
|
}
|
|
25353
25685
|
case "thread/tokenUsage/updated": {
|
|
25354
|
-
const
|
|
25355
|
-
|
|
25686
|
+
const t2 = p.tokenUsage?.total;
|
|
25687
|
+
const last = p.tokenUsage?.last;
|
|
25688
|
+
const shape = (u4) => ({
|
|
25689
|
+
input: u4.inputTokens ?? 0,
|
|
25690
|
+
output: u4.outputTokens ?? 0,
|
|
25691
|
+
cachedInput: u4.cachedInputTokens ?? 0
|
|
25692
|
+
});
|
|
25693
|
+
if (t2) {
|
|
25694
|
+
const b = state.usageBaseline ?? { input: 0, output: 0, cachedInput: 0 };
|
|
25695
|
+
const now = shape(t2);
|
|
25356
25696
|
state.usage = {
|
|
25357
|
-
input:
|
|
25358
|
-
output:
|
|
25359
|
-
...typeof
|
|
25697
|
+
input: Math.max(0, now.input - b.input),
|
|
25698
|
+
output: Math.max(0, now.output - b.output),
|
|
25699
|
+
...typeof t2.cachedInputTokens === "number" ? { cachedInput: Math.max(0, now.cachedInput - b.cachedInput) } : {}
|
|
25360
25700
|
};
|
|
25701
|
+
} else if (last) {
|
|
25702
|
+
state.usage = { input: last.inputTokens ?? 0, output: last.outputTokens ?? 0, ...typeof last.cachedInputTokens === "number" ? { cachedInput: last.cachedInputTokens } : {} };
|
|
25361
25703
|
}
|
|
25362
|
-
const t2 = p.tokenUsage?.total;
|
|
25363
25704
|
if (t2) {
|
|
25705
|
+
const window = p.tokenUsage?.modelContextWindow;
|
|
25364
25706
|
emit({
|
|
25365
25707
|
...base2(threadId, turnId),
|
|
25366
25708
|
type: "thread.token-usage.updated",
|
|
25367
25709
|
input: t2.inputTokens ?? 0,
|
|
25368
25710
|
output: t2.outputTokens ?? 0,
|
|
25369
|
-
...typeof t2.cachedInputTokens === "number" ? { cachedInput: t2.cachedInputTokens } : {}
|
|
25711
|
+
...typeof t2.cachedInputTokens === "number" ? { cachedInput: t2.cachedInputTokens } : {},
|
|
25712
|
+
// the last call's prompt is what fills the window
|
|
25713
|
+
...last && typeof last.inputTokens === "number" ? { contextTokens: last.inputTokens } : {},
|
|
25714
|
+
...typeof window === "number" && window > 0 ? { contextWindow: window } : {}
|
|
25370
25715
|
});
|
|
25371
25716
|
}
|
|
25372
25717
|
break;
|
|
@@ -25420,7 +25765,7 @@ var init_codex = __esm({
|
|
|
25420
25765
|
const pend = rpcPending.get(msg.id);
|
|
25421
25766
|
if (pend) {
|
|
25422
25767
|
rpcPending.delete(msg.id);
|
|
25423
|
-
if (msg.error) pend.reject(new
|
|
25768
|
+
if (msg.error) pend.reject(new CodexRpcError(msg.error));
|
|
25424
25769
|
else pend.resolve(msg.result);
|
|
25425
25770
|
}
|
|
25426
25771
|
} else if (msg.id !== void 0 && msg.method) {
|
|
@@ -25451,7 +25796,7 @@ var init_codex = __esm({
|
|
|
25451
25796
|
}
|
|
25452
25797
|
const recentStderr = stderrSinceOutput.trim();
|
|
25453
25798
|
const hadStreamedOutput = codexTurnId !== null || state.sawStreamDelta;
|
|
25454
|
-
const verdict = classifyError({ exitCode: code, stderr: recentStderr
|
|
25799
|
+
const verdict = signal !== null ? { transient: false, reason: "interrupted" } : classifyError({ exitCode: code, stderr: recentStderr });
|
|
25455
25800
|
if (!stopRequested && codexTurnId === null && earlyNotifications.length === 0 && verdict.transient && attempt < RETRY_MAX_ATTEMPTS - 1) {
|
|
25456
25801
|
const delayMs = computeBackoff(attempt);
|
|
25457
25802
|
attempt++;
|
|
@@ -25518,30 +25863,39 @@ var init_codex = __esm({
|
|
|
25518
25863
|
autoAcceptPermissions = approvalMode === "full";
|
|
25519
25864
|
const cursor3 = typeof turn.resumeCursor === "string" ? turn.resumeCursor : null;
|
|
25520
25865
|
let startedModel = null;
|
|
25866
|
+
let resumedNativeThread = false;
|
|
25867
|
+
let promptText = turn.text;
|
|
25521
25868
|
if (cursor3) {
|
|
25869
|
+
const resumeThread = () => request("thread/resume", {
|
|
25870
|
+
threadId: cursor3,
|
|
25871
|
+
developerInstructions,
|
|
25872
|
+
...approvalParams.thread
|
|
25873
|
+
});
|
|
25522
25874
|
try {
|
|
25523
|
-
|
|
25524
|
-
|
|
25525
|
-
|
|
25526
|
-
|
|
25527
|
-
|
|
25528
|
-
codexThreadId = resumed?.thread?.id ?? cursor3;
|
|
25529
|
-
} catch (error51) {
|
|
25530
|
-
if (approvalParams.fallback && permissionProfileUnsupported(error51)) {
|
|
25875
|
+
let resumed;
|
|
25876
|
+
try {
|
|
25877
|
+
resumed = await resumeThread();
|
|
25878
|
+
} catch (error51) {
|
|
25879
|
+
if (!approvalParams.fallback || !permissionProfileUnsupported(error51)) throw error51;
|
|
25531
25880
|
approvalParams = approvalParams.fallback;
|
|
25532
|
-
|
|
25533
|
-
threadId: cursor3,
|
|
25534
|
-
developerInstructions,
|
|
25535
|
-
...approvalParams.thread
|
|
25536
|
-
});
|
|
25537
|
-
codexThreadId = resumed?.thread?.id ?? cursor3;
|
|
25538
|
-
} else {
|
|
25539
|
-
throw error51;
|
|
25881
|
+
resumed = await resumeThread();
|
|
25540
25882
|
}
|
|
25883
|
+
codexThreadId = resumed?.thread?.id ?? cursor3;
|
|
25884
|
+
resumedNativeThread = true;
|
|
25885
|
+
} catch (error51) {
|
|
25886
|
+
const failure = classifyResumeFailure({
|
|
25887
|
+
attempted: true,
|
|
25888
|
+
rejected: error51 instanceof CodexRpcError,
|
|
25889
|
+
promptSubmitted,
|
|
25890
|
+
producedOutput: state.sawStreamDelta
|
|
25891
|
+
});
|
|
25892
|
+
if (!config2.managed || recoveredMissingSession || stopRequested || state.settled || !turn.recoveryText?.trim() || !missingNativeCodexThread(error51, cursor3) || !mayReplay(failure)) throw error51;
|
|
25893
|
+
recoveredMissingSession = true;
|
|
25894
|
+
promptText = recoveryPromptFor({ recoveryText: turn.recoveryText, currentText: turn.text, failure }).text;
|
|
25541
25895
|
}
|
|
25542
25896
|
}
|
|
25543
25897
|
if (!codexThreadId) {
|
|
25544
|
-
const selection = decodeCodexSelection(turn.model);
|
|
25898
|
+
const selection = config2.managed ? { model: turn.model, modelProvider: "openmaus_company" } : decodeCodexSelection(turn.model);
|
|
25545
25899
|
const startThread = () => request("thread/start", {
|
|
25546
25900
|
developerInstructions,
|
|
25547
25901
|
cwd: turn.cwd ?? homedir13(),
|
|
@@ -25562,14 +25916,14 @@ var init_codex = __esm({
|
|
|
25562
25916
|
startedModel = started?.model ?? null;
|
|
25563
25917
|
}
|
|
25564
25918
|
if (!codexThreadId) throw new Error("Codex did not return a native thread id");
|
|
25565
|
-
await syncCodexInstructions(threadId, codexThreadId, developerInstructions,
|
|
25919
|
+
await syncCodexInstructions(threadId, codexThreadId, developerInstructions, resumedNativeThread, request);
|
|
25566
25920
|
emit({ ...base2(threadId, turnId), type: "session.started", sessionId: codexThreadId, model: startedModel ?? turn.model ?? null });
|
|
25567
|
-
const promptText = turn.text;
|
|
25568
25921
|
const turnInput = [
|
|
25569
25922
|
...promptText ? [{ type: "text", text: promptText }] : [],
|
|
25570
25923
|
...(turn.images ?? []).map((image) => ({ type: "localImage", path: image.path }))
|
|
25571
25924
|
];
|
|
25572
25925
|
const startTurn = () => {
|
|
25926
|
+
promptSubmitted = true;
|
|
25573
25927
|
startingNativeTurn = true;
|
|
25574
25928
|
return request("turn/start", {
|
|
25575
25929
|
threadId: codexThreadId,
|
|
@@ -25599,7 +25953,7 @@ var init_codex = __esm({
|
|
|
25599
25953
|
const message2 = e instanceof Error ? e.message : String(e);
|
|
25600
25954
|
const needsAuth = /(?:\b401\b|unauthorized|missing bearer|authentication required)/i.test(message2);
|
|
25601
25955
|
const verdict = classifyError(failure);
|
|
25602
|
-
if (!state.settled && !abandoned && !needsAuth && verdict.transient && attempt < RETRY_MAX_ATTEMPTS - 1 && state.sawStreamDelta === false) {
|
|
25956
|
+
if (!state.settled && !abandoned && !recoveredMissingSession && !stopRequested && !needsAuth && verdict.transient && attempt < RETRY_MAX_ATTEMPTS - 1 && state.sawStreamDelta === false) {
|
|
25603
25957
|
const delayMs = computeBackoff(attempt);
|
|
25604
25958
|
attempt++;
|
|
25605
25959
|
emit({
|
|
@@ -25649,6 +26003,7 @@ var init_codex = __esm({
|
|
|
25649
26003
|
);
|
|
25650
26004
|
});
|
|
25651
26005
|
if (!version2) return { state: "unavailable", reason: `\`${config2.cli}\` CLI not found` };
|
|
26006
|
+
if (config2.managed) return { state: "available", version: version2, authenticated: Boolean(input.environment.OPENMAUSBOT_COMPANY_API_KEY && input.environment.CODEX_HOME), billing: "metered" };
|
|
25652
26007
|
const authenticated = await new Promise((resolve12) => {
|
|
25653
26008
|
execCli(
|
|
25654
26009
|
config2.cli,
|
|
@@ -33457,7 +33812,9 @@ async function mountChatTools(integrations, signal) {
|
|
|
33457
33812
|
const servers = [];
|
|
33458
33813
|
if (integrations?.agents) servers.push(["agents", integrations.agents]);
|
|
33459
33814
|
if (integrations?.composio) servers.push(["composio", integrations.composio]);
|
|
33460
|
-
|
|
33815
|
+
for (const [name, server] of Object.entries(integrations?.custom ?? {})) {
|
|
33816
|
+
if ("command" in server) servers.push([name, server]);
|
|
33817
|
+
}
|
|
33461
33818
|
if (servers.length > 32) throw new Error("MCP server count exceeds the 32-server limit");
|
|
33462
33819
|
const clients = [];
|
|
33463
33820
|
let closed = false;
|
|
@@ -35682,12 +36039,14 @@ function parseOpenCodeModelsOutput(stdout2) {
|
|
|
35682
36039
|
const name = typeof record3.name === "string" && record3.name.trim() ? record3.name.trim() : labelForModel(model);
|
|
35683
36040
|
const limit = record3.limit && typeof record3.limit === "object" && !Array.isArray(record3.limit) ? record3.limit : {};
|
|
35684
36041
|
const contextWindow = typeof limit.context === "number" && Number.isFinite(limit.context) && limit.context > 0 ? Math.floor(limit.context) : void 0;
|
|
36042
|
+
const variants = record3.variants && typeof record3.variants === "object" && !Array.isArray(record3.variants) ? Object.entries(record3.variants).filter(([, settings2]) => settings2 && typeof settings2 === "object" && !Array.isArray(settings2) && settings2.disabled !== true).map(([id]) => ({ id, label: labelForModel(id) })) : void 0;
|
|
35685
36043
|
seen.add(slug);
|
|
35686
36044
|
options.push({
|
|
35687
36045
|
id: slug,
|
|
35688
36046
|
label: `${providerLabel(provider)} \xB7 ${name}`,
|
|
35689
36047
|
...localModelRecord(record3) ? { custom: true, loaded: true } : {},
|
|
35690
|
-
...contextWindow ? { contextWindow } : {}
|
|
36048
|
+
...contextWindow ? { contextWindow } : {},
|
|
36049
|
+
...variants ? { variants } : {}
|
|
35691
36050
|
});
|
|
35692
36051
|
};
|
|
35693
36052
|
for (const line of stdout2.split(/\r?\n/u)) {
|
|
@@ -35894,6 +36253,7 @@ var init_opencode_go = __esm({
|
|
|
35894
36253
|
spawnArgs: () => ["acp"],
|
|
35895
36254
|
credentialEnv: ["OPENCODE_API_KEY"],
|
|
35896
36255
|
selectModel: { configId: "model" },
|
|
36256
|
+
modelVariants: true,
|
|
35897
36257
|
resolveTurnModel: (model, env) => model ? ensureOpenCodeInjectModel(normalizeLegacyOpenCodeModel(model, env), env) : model,
|
|
35898
36258
|
transformEnv: stripForeignProviderKeys,
|
|
35899
36259
|
pickAuthMethod: () => null,
|
|
@@ -43486,7 +43846,7 @@ var init_openai_compat = __esm({
|
|
|
43486
43846
|
});
|
|
43487
43847
|
|
|
43488
43848
|
// server/drivers/pi.ts
|
|
43489
|
-
import { chmodSync as chmodSync6, existsSync as existsSync17, mkdirSync as mkdirSync15, mkdtempSync as mkdtempSync3, readFileSync as readFileSync17, rmSync as
|
|
43849
|
+
import { chmodSync as chmodSync6, existsSync as existsSync17, mkdirSync as mkdirSync15, mkdtempSync as mkdtempSync3, readFileSync as readFileSync17, rmSync as rmSync6, writeFileSync as writeFileSync12 } from "node:fs";
|
|
43490
43850
|
import { homedir as homedir21, tmpdir as tmpdir4 } from "node:os";
|
|
43491
43851
|
import { join as join30 } from "node:path";
|
|
43492
43852
|
function readPiPromptImages(turn) {
|
|
@@ -43822,7 +44182,7 @@ var init_pi = __esm({
|
|
|
43822
44182
|
writeFileSync12(join30(mcpTempDir, "mcp.json"), JSON.stringify({ mcpServers }), { mode: 384 });
|
|
43823
44183
|
} catch (err) {
|
|
43824
44184
|
try {
|
|
43825
|
-
|
|
44185
|
+
rmSync6(mcpTempDir, { recursive: true, force: true });
|
|
43826
44186
|
} catch {
|
|
43827
44187
|
}
|
|
43828
44188
|
throw err;
|
|
@@ -43843,7 +44203,7 @@ var init_pi = __esm({
|
|
|
43843
44203
|
} catch (err) {
|
|
43844
44204
|
if (mcpTempDir) {
|
|
43845
44205
|
try {
|
|
43846
|
-
|
|
44206
|
+
rmSync6(mcpTempDir, { recursive: true, force: true });
|
|
43847
44207
|
} catch {
|
|
43848
44208
|
}
|
|
43849
44209
|
}
|
|
@@ -43900,7 +44260,7 @@ var init_pi = __esm({
|
|
|
43900
44260
|
}
|
|
43901
44261
|
if (mcpTempDir) {
|
|
43902
44262
|
try {
|
|
43903
|
-
|
|
44263
|
+
rmSync6(mcpTempDir, { recursive: true, force: true });
|
|
43904
44264
|
} catch {
|
|
43905
44265
|
}
|
|
43906
44266
|
}
|
|
@@ -44913,7 +45273,7 @@ __export(browser_engine_exports, {
|
|
|
44913
45273
|
});
|
|
44914
45274
|
import { spawn as spawn8 } from "node:child_process";
|
|
44915
45275
|
import { createHash as createHash8, randomBytes as randomBytes3, randomUUID as randomUUID11 } from "node:crypto";
|
|
44916
|
-
import { chmodSync as chmodSync7, constants as constants2, copyFileSync, existsSync as existsSync18, mkdirSync as mkdirSync16, readFileSync as readFileSync20, readdirSync as readdirSync3, renameSync as
|
|
45276
|
+
import { chmodSync as chmodSync7, constants as constants2, copyFileSync, existsSync as existsSync18, mkdirSync as mkdirSync16, readFileSync as readFileSync20, readdirSync as readdirSync3, renameSync as renameSync6, rmSync as rmSync7, statSync as statSync4, unlinkSync as unlinkSync4, writeFileSync as writeFileSync13 } from "node:fs";
|
|
44917
45277
|
import { homedir as homedir23, tmpdir as tmpdir5 } from "node:os";
|
|
44918
45278
|
import { delimiter as delimiter6, dirname as dirname11, join as join35, resolve as resolve10 } from "node:path";
|
|
44919
45279
|
function browserRestoreKey(session) {
|
|
@@ -45031,7 +45391,7 @@ async function prepareBrowserSessionState(binaryPath, session, options = {}) {
|
|
|
45031
45391
|
const candidates = [".json.enc", ".json"].flatMap((suffix) => {
|
|
45032
45392
|
const path3 = join35(directory, `${session}-${session}${suffix}`);
|
|
45033
45393
|
try {
|
|
45034
|
-
const stat4 =
|
|
45394
|
+
const stat4 = statSync4(path3);
|
|
45035
45395
|
if (!stat4.isFile()) throw new Error("Saved browser state is not a file.");
|
|
45036
45396
|
return [{ path: path3, suffix, modified: stat4.mtimeMs }];
|
|
45037
45397
|
} catch (error51) {
|
|
@@ -45126,7 +45486,7 @@ async function installAgentBrowserBinary(options = {}) {
|
|
|
45126
45486
|
const staging = `${destination}.${randomBytes3(6).toString("hex")}.part`;
|
|
45127
45487
|
writeFileSync13(staging, body, { mode: 493 });
|
|
45128
45488
|
if (platform !== "win32") chmodSync7(staging, 493);
|
|
45129
|
-
|
|
45489
|
+
renameSync6(staging, destination);
|
|
45130
45490
|
return destination;
|
|
45131
45491
|
}
|
|
45132
45492
|
function ensureChrome(binaryPath, options = {}) {
|
|
@@ -45243,7 +45603,7 @@ function agentBrowserFrame(input) {
|
|
|
45243
45603
|
} catch {
|
|
45244
45604
|
fail(new Error("the browser reported a picture it did not write"));
|
|
45245
45605
|
} finally {
|
|
45246
|
-
|
|
45606
|
+
rmSync7(file2, { force: true });
|
|
45247
45607
|
}
|
|
45248
45608
|
};
|
|
45249
45609
|
child.on("error", (error51) => done(error51 instanceof Error ? error51 : new Error(String(error51))));
|
|
@@ -45262,7 +45622,7 @@ function describeBrowserEngine(status) {
|
|
|
45262
45622
|
}
|
|
45263
45623
|
function agentBrowserBinaryExists(dataDir = DATA_DIR) {
|
|
45264
45624
|
try {
|
|
45265
|
-
return
|
|
45625
|
+
return statSync4(pinnedBinaryPath(dataDir)).isFile();
|
|
45266
45626
|
} catch {
|
|
45267
45627
|
return false;
|
|
45268
45628
|
}
|
|
@@ -45325,7 +45685,7 @@ var init_browser_engine = __esm({
|
|
|
45325
45685
|
// server/cli.ts
|
|
45326
45686
|
var import_qrcode_terminal = __toESM(require_main(), 1);
|
|
45327
45687
|
import { spawn as spawn9 } from "node:child_process";
|
|
45328
|
-
import { closeSync as
|
|
45688
|
+
import { closeSync as closeSync5, existsSync as existsSync19, mkdirSync as mkdirSync17, openSync as openSync5, readFileSync as readFileSync21 } from "node:fs";
|
|
45329
45689
|
import { homedir as homedir24 } from "node:os";
|
|
45330
45690
|
import { dirname as dirname12, join as join36, resolve as resolve11 } from "node:path";
|
|
45331
45691
|
import { createInterface as createInterface2 } from "node:readline/promises";
|
|
@@ -48288,7 +48648,7 @@ async function runPhoneSetup(options, io, deps) {
|
|
|
48288
48648
|
const device = await io.choose("Use OpenMausBot on your phone?", [
|
|
48289
48649
|
"Skip for now",
|
|
48290
48650
|
"iPhone / iPad \u2014 native app or Safari",
|
|
48291
|
-
"Android \u2014
|
|
48651
|
+
"Android \u2014 app or browser"
|
|
48292
48652
|
], 0);
|
|
48293
48653
|
if (device === 0) return skip();
|
|
48294
48654
|
const phone = device === 1 ? "ios" : "android";
|
|
@@ -48351,7 +48711,7 @@ function phonePairingInstructions(phone, input) {
|
|
|
48351
48711
|
];
|
|
48352
48712
|
}
|
|
48353
48713
|
return [
|
|
48354
|
-
phone === "ios" ? "On iPhone or iPad, scan the QR with Camera to open Safari. If you already have the OpenMausBot iOS app, use its pairing scanner or paste the full pairing link there." : "On Android,
|
|
48714
|
+
phone === "ios" ? "On iPhone or iPad, scan the QR with Camera to open Safari. If you already have the OpenMausBot iOS app, use its pairing scanner or paste the full pairing link there." : "On Android, open the OpenMausBot app and scan the QR with its pairing scanner. The QR is an app link, so Camera will not open it in a browser.",
|
|
48355
48715
|
`Or open ${origin}/pair on your phone and enter the code.`,
|
|
48356
48716
|
"Choose Connect on the phone. Scanning a QR does not mean the phone is paired.",
|
|
48357
48717
|
"The code works once and expires after five minutes. This phone receives client access: chat and approvals, not settings or pairing administration."
|
|
@@ -48642,7 +49002,11 @@ function parseArgs(argv, env = process.env) {
|
|
|
48642
49002
|
options.domain = domain2;
|
|
48643
49003
|
} else if (arg === "--tunnel") options.tunnel = true;
|
|
48644
49004
|
else if (arg === "--client") options.client = true;
|
|
48645
|
-
else if (arg === "--
|
|
49005
|
+
else if (arg === "--phone") {
|
|
49006
|
+
const kind = value().toLowerCase();
|
|
49007
|
+
if (kind !== "ios" && kind !== "android") return { error: "--phone takes ios or android" };
|
|
49008
|
+
options.phone = kind;
|
|
49009
|
+
} else if (arg === "--no-pair") options.pair = false;
|
|
48646
49010
|
else if (arg === "--no-open") options.open = false;
|
|
48647
49011
|
else if (arg === "--local") options.local = true;
|
|
48648
49012
|
else if (arg === "--json") options.json = true;
|
|
@@ -48702,7 +49066,8 @@ var USAGE = `openmausbot \u2014 your team of AI bots, ready in a few steps
|
|
|
48702
49066
|
openmausbot start [the same options as serve]
|
|
48703
49067
|
openmausbot serve [--port 8799] [--data-dir DIR] [--label NAME]
|
|
48704
49068
|
[--public-url https://host] [--tailscale | --tunnel | --domain HOST] [--no-pair]
|
|
48705
|
-
openmausbot pair [--label NAME] [--client] [--
|
|
49069
|
+
openmausbot pair [--label NAME] [--client] [--phone ios|android]
|
|
49070
|
+
[--public-url https://host]
|
|
48706
49071
|
openmausbot sessions [revoke ID]
|
|
48707
49072
|
openmausbot status
|
|
48708
49073
|
openmausbot login [--email you@example.com]
|
|
@@ -48877,22 +49242,46 @@ async function showPhonePairing(options, origin, log) {
|
|
|
48877
49242
|
return false;
|
|
48878
49243
|
}
|
|
48879
49244
|
for (const line of phonePairingInstructions(options.phone ?? "ios", { origin, ready })) log(line);
|
|
48880
|
-
log(await mintPairing(options.port, { client: true, label: options.label ?? (options.phone === "android" ? "Android" : "iPhone / iPad"), publicUrl: origin }));
|
|
49245
|
+
log(await mintPairing(options.port, { client: true, label: options.label ?? (options.phone === "android" ? "Android" : "iPhone / iPad"), publicUrl: origin, phone: options.phone }));
|
|
48881
49246
|
log("Waiting for you to connect on the phone. Keep this terminal and the code private.");
|
|
48882
49247
|
return true;
|
|
48883
49248
|
}
|
|
48884
49249
|
function pairingBlock(input) {
|
|
48885
49250
|
const lines = [`pairing code: ${input.code}`, `expires: ${new Date(input.expiresAt).toLocaleTimeString()} (single use)`];
|
|
48886
|
-
if (input.url) {
|
|
48887
|
-
lines.push(`open or scan: ${input.url}`);
|
|
48888
|
-
lines.push("");
|
|
48889
|
-
lines.push(qrToString(input.url));
|
|
48890
|
-
} else {
|
|
49251
|
+
if (!input.url && !input.inviteUrl) {
|
|
48891
49252
|
lines.push(`open: /pair on the address you use for this server, and type the code`);
|
|
48892
49253
|
if (input.hint) lines.push(` (${input.hint})`);
|
|
49254
|
+
return lines.join("\n");
|
|
49255
|
+
}
|
|
49256
|
+
const scanInvite = input.phone === "android" && !!input.inviteUrl;
|
|
49257
|
+
if (input.url) lines.push(scanInvite ? `web browser: ${input.url}` : `open or scan: ${input.url}`);
|
|
49258
|
+
if (input.inviteUrl) lines.push(`phone app: ${input.inviteUrl}`);
|
|
49259
|
+
const target = scanInvite ? input.inviteUrl : input.url;
|
|
49260
|
+
if (target) {
|
|
49261
|
+
lines.push("");
|
|
49262
|
+
lines.push(qrToString(target));
|
|
49263
|
+
lines.push("");
|
|
49264
|
+
if (scanInvite) {
|
|
49265
|
+
lines.push(`Scan that in the OpenMausBot app. For a browser instead, open the web`);
|
|
49266
|
+
lines.push(`address above and type the code.`);
|
|
49267
|
+
} else if (input.phone === "android") {
|
|
49268
|
+
lines.push(`That QR opens the web app. The Android app needs the phone-app link,`);
|
|
49269
|
+
lines.push(`which this server cannot build without a public address: set`);
|
|
49270
|
+
lines.push(`OMB_PUBLIC_URL, or open the web address above and type the code.`);
|
|
49271
|
+
} else if (input.inviteUrl) {
|
|
49272
|
+
lines.push(`Scan that with Camera for the browser, or paste the phone-app link`);
|
|
49273
|
+
lines.push(`above into the OpenMausBot app.`);
|
|
49274
|
+
}
|
|
48893
49275
|
}
|
|
48894
49276
|
return lines.join("\n");
|
|
48895
49277
|
}
|
|
49278
|
+
function originOf(link) {
|
|
49279
|
+
try {
|
|
49280
|
+
return new URL(link).origin;
|
|
49281
|
+
} catch {
|
|
49282
|
+
return null;
|
|
49283
|
+
}
|
|
49284
|
+
}
|
|
48896
49285
|
function qrToString(text4) {
|
|
48897
49286
|
let out = "";
|
|
48898
49287
|
import_qrcode_terminal.default.generate(text4, { small: true }, (rendered) => {
|
|
@@ -48907,7 +49296,9 @@ async function mintPairing(port, options) {
|
|
|
48907
49296
|
const { status, body } = await api(port, "/api/auth/pairing", { method: "POST", body: JSON.stringify(request) });
|
|
48908
49297
|
if (status !== 200) throw new Error(`server refused to mint a pairing code: ${typeof body?.error === "string" ? body.error : status}`);
|
|
48909
49298
|
const url2 = options.publicUrl ? `${options.publicUrl}/pair#code=${body.code}` : typeof body.url === "string" ? body.url : null;
|
|
48910
|
-
|
|
49299
|
+
const address = options.publicUrl ?? (typeof body.url === "string" ? originOf(body.url) : null);
|
|
49300
|
+
const invite = typeof body.credential === "string" && address ? `openmausbot://pair?address=${encodeURIComponent(address)}&token=${encodeURIComponent(body.credential)}${typeof body.serverName === "string" ? `&name=${encodeURIComponent(body.serverName)}` : ""}` : typeof body.inviteUrl === "string" ? body.inviteUrl : null;
|
|
49301
|
+
return pairingBlock({ code: body.code, url: url2, inviteUrl: invite, expiresAt: body.expiresAt, hint: typeof body.hint === "string" ? body.hint : null, phone: options.phone });
|
|
48911
49302
|
}
|
|
48912
49303
|
async function runPair(options) {
|
|
48913
49304
|
if (!await serverUp(options.port)) {
|
|
@@ -48935,7 +49326,7 @@ async function runPair(options) {
|
|
|
48935
49326
|
}
|
|
48936
49327
|
const ui = defaultSetupIo();
|
|
48937
49328
|
try {
|
|
48938
|
-
const selected = await ui.choose("Which phone are you connecting?", ["iPhone / iPad \u2014 app or Safari", "Android \u2014
|
|
49329
|
+
const selected = await ui.choose("Which phone are you connecting?", ["iPhone / iPad \u2014 app or Safari", "Android \u2014 app or browser", "Cancel"], 0);
|
|
48939
49330
|
if (selected === 2) return 0;
|
|
48940
49331
|
launch = { ...launch, phone: selected === 0 ? "ios" : "android" };
|
|
48941
49332
|
return await showPhonePairing(launch, origin, ui.log) ? 0 : 1;
|
|
@@ -48945,7 +49336,7 @@ async function runPair(options) {
|
|
|
48945
49336
|
return 130;
|
|
48946
49337
|
}
|
|
48947
49338
|
}
|
|
48948
|
-
console.log(await mintPairing(options.port, { label: options.label, client: options.client, publicUrl: options.publicUrl }));
|
|
49339
|
+
console.log(await mintPairing(options.port, { label: options.label, client: options.client, publicUrl: options.publicUrl, phone: options.phone }));
|
|
48949
49340
|
if (options.client) console.log("(client scope: chat and approvals only; cannot change settings or pair others)");
|
|
48950
49341
|
return 0;
|
|
48951
49342
|
}
|
|
@@ -49269,7 +49660,7 @@ async function runServe(options, log = console.log) {
|
|
|
49269
49660
|
const logsDir = join36(options.dataDir, "logs");
|
|
49270
49661
|
mkdirSync17(logsDir, { recursive: true, mode: 448 });
|
|
49271
49662
|
logPath = join36(logsDir, `server-${Date.now()}-${process.pid}.log`);
|
|
49272
|
-
logFd =
|
|
49663
|
+
logFd = openSync5(logPath, "wx", 384);
|
|
49273
49664
|
log("\nStarting your workspace\u2026");
|
|
49274
49665
|
}
|
|
49275
49666
|
if (tailscale) {
|
|
@@ -49293,7 +49684,7 @@ async function runServe(options, log = console.log) {
|
|
|
49293
49684
|
}
|
|
49294
49685
|
throw error51;
|
|
49295
49686
|
} finally {
|
|
49296
|
-
if (logFd !== void 0)
|
|
49687
|
+
if (logFd !== void 0) closeSync5(logFd);
|
|
49297
49688
|
process.removeListener("SIGINT", cancelStartup);
|
|
49298
49689
|
process.removeListener("SIGTERM", cancelStartup);
|
|
49299
49690
|
}
|