openmausbot 0.1.80 → 0.1.82
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-D6RZKWks.js → index-5HVwp5m2.js} +1 -1
- package/dist/assets/index-BLLsDK2F.js +309 -0
- package/dist/assets/index-CKysBq-V.css +1 -0
- package/dist/index.html +2 -2
- package/dist-server/container-mcp.js +41 -10
- package/dist-server/drivers/agents-proxy.js +50 -11
- package/dist-server/index.js +3525 -1296
- package/dist-server/openmausbot.js +412 -84
- package/dist-server/pair-cli.js +412 -84
- 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 +113 -19
- package/dist-server/server/drivers/acp/opencode-go.js +19 -0
- package/dist-server/server/drivers/agents-proxy.js +49 -11
- package/dist-server/server/drivers/chat-mcp-tools.js +6 -1
- package/dist-server/server/drivers/claude.js +33 -2
- package/dist-server/server/drivers/codex.js +93 -8
- 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 +1 -0
- package/dist-server/server/index.js +869 -226
- package/dist-server/server/local-vm-lease.js +4 -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/notify.js +8 -3
- package/dist-server/server/recall-disclosure.js +4 -0
- package/dist-server/server/recent-work.js +142 -0
- package/dist-server/server/request-auth.js +3 -1
- package/dist-server/server/routines.js +36 -1
- package/dist-server/server/screen-frame-gate.js +4 -94
- package/dist-server/server/sessions.js +22 -3
- package/dist-server/server/store.js +16 -1
- 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/turn-resources.js +7 -2
- 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-Cu8BkIfo.js +0 -305
- package/dist/assets/index-tfpeJAIG.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",
|
|
@@ -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
|
|
@@ -19634,16 +19668,84 @@ var init_redact = __esm({
|
|
|
19634
19668
|
}
|
|
19635
19669
|
});
|
|
19636
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
|
+
|
|
19637
19737
|
// server/drivers/native.ts
|
|
19638
19738
|
import { appendFileSync as appendFileSync3 } from "node:fs";
|
|
19639
19739
|
import { join as join12 } from "node:path";
|
|
19640
19740
|
function appendNative(threadId, entry) {
|
|
19741
|
+
const file2 = join12(NATIVE_DIR, `${threadId}.ndjson`);
|
|
19641
19742
|
try {
|
|
19642
19743
|
appendFileSync3(
|
|
19643
|
-
|
|
19744
|
+
file2,
|
|
19644
19745
|
JSON.stringify({ at: (/* @__PURE__ */ new Date()).toISOString(), ...entry, msg: redactSecrets(entry.msg) }) + "\n",
|
|
19645
19746
|
{ mode: 384 }
|
|
19646
19747
|
);
|
|
19748
|
+
capThreadLog(file2, currentThreadLogCap());
|
|
19647
19749
|
} catch {
|
|
19648
19750
|
}
|
|
19649
19751
|
}
|
|
@@ -19652,6 +19754,7 @@ var init_native = __esm({
|
|
|
19652
19754
|
"use strict";
|
|
19653
19755
|
init_config();
|
|
19654
19756
|
init_redact();
|
|
19757
|
+
init_thread_log_rotation();
|
|
19655
19758
|
}
|
|
19656
19759
|
});
|
|
19657
19760
|
|
|
@@ -19727,6 +19830,29 @@ import { basename as basename3, dirname as dirname5, isAbsolute, relative, resol
|
|
|
19727
19830
|
function skipSubscriptionAuthForLocalInject(model) {
|
|
19728
19831
|
return Boolean(decodeInjectId(model));
|
|
19729
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
|
+
}
|
|
19730
19856
|
async function readAcpImageBlocks(images) {
|
|
19731
19857
|
return Promise.all(images.map(async (image) => ({
|
|
19732
19858
|
type: "image",
|
|
@@ -19902,6 +20028,10 @@ function createAcpDriver(support11) {
|
|
|
19902
20028
|
}
|
|
19903
20029
|
for (const [name, server] of Object.entries(turn.integrations?.custom ?? {})) {
|
|
19904
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
|
+
}
|
|
19905
20035
|
servers.push({ name, command: server.command, args: server.args, env: acpEnv(server.env) });
|
|
19906
20036
|
}
|
|
19907
20037
|
return servers;
|
|
@@ -19924,7 +20054,7 @@ function createAcpDriver(support11) {
|
|
|
19924
20054
|
return { turnId };
|
|
19925
20055
|
}
|
|
19926
20056
|
const resolvedModel = support11.resolveTurnModel?.(turn.model, env);
|
|
19927
|
-
support11.applyTurnEnv?.(env, { model: resolvedModel, requestedModel: turn.model });
|
|
20057
|
+
support11.applyTurnEnv?.(env, { model: resolvedModel, requestedModel: turn.model, fullAuto: turnConfig.fullAuto === true });
|
|
19928
20058
|
const cliTurn = resolvedModel !== void 0 && resolvedModel !== turn.model ? { ...turn, model: resolvedModel } : turn;
|
|
19929
20059
|
const mcpServers = acpMcpServers(turn);
|
|
19930
20060
|
let launch;
|
|
@@ -19950,6 +20080,37 @@ function createAcpDriver(support11) {
|
|
|
19950
20080
|
const asks = /* @__PURE__ */ new Map();
|
|
19951
20081
|
let nextId = 1;
|
|
19952
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
|
+
};
|
|
19953
20114
|
let interruptTimer = null;
|
|
19954
20115
|
const rpcPending = /* @__PURE__ */ new Map();
|
|
19955
20116
|
const send = (obj) => {
|
|
@@ -19959,7 +20120,7 @@ function createAcpDriver(support11) {
|
|
|
19959
20120
|
}
|
|
19960
20121
|
appendNative(threadId, { dir: "out", source: SOURCE, msg: nativeLogMessage(obj) });
|
|
19961
20122
|
};
|
|
19962
|
-
const request = (method, params, timeoutMs) => new Promise((resolve12, reject) => {
|
|
20123
|
+
const request = (method, params, timeoutMs, receive) => new Promise((resolve12, reject) => {
|
|
19963
20124
|
const id = nextId++;
|
|
19964
20125
|
let timer = null;
|
|
19965
20126
|
if (timeoutMs) {
|
|
@@ -19969,7 +20130,16 @@ function createAcpDriver(support11) {
|
|
|
19969
20130
|
}, timeoutMs);
|
|
19970
20131
|
timer.unref?.();
|
|
19971
20132
|
}
|
|
19972
|
-
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
|
+
});
|
|
19973
20143
|
send({ jsonrpc: "2.0", id, method, params });
|
|
19974
20144
|
});
|
|
19975
20145
|
const stop = () => killCliTree(child);
|
|
@@ -20152,7 +20322,12 @@ function createAcpDriver(support11) {
|
|
|
20152
20322
|
const handleNotification = (msg) => {
|
|
20153
20323
|
if (msg.method !== "session/update") return;
|
|
20154
20324
|
const p = msg.params ?? {};
|
|
20155
|
-
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;
|
|
20156
20331
|
const u4 = p.update ?? {};
|
|
20157
20332
|
switch (u4.sessionUpdate) {
|
|
20158
20333
|
case "agent_message_chunk": {
|
|
@@ -20309,6 +20484,7 @@ function createAcpDriver(support11) {
|
|
|
20309
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.`
|
|
20310
20485
|
);
|
|
20311
20486
|
}
|
|
20487
|
+
const sessionServers = mcpServers.filter((server) => !("type" in server) || init?.agentCapabilities?.mcpCapabilities?.[server.type] === true);
|
|
20312
20488
|
const cursor3 = typeof turn.resumeCursor === "string" ? turn.resumeCursor : null;
|
|
20313
20489
|
if (!cursor3) sessionAllows.delete(threadId);
|
|
20314
20490
|
let sessionResult = null;
|
|
@@ -20316,16 +20492,23 @@ function createAcpDriver(support11) {
|
|
|
20316
20492
|
try {
|
|
20317
20493
|
sessionResult = await request(
|
|
20318
20494
|
support11.resumeMethod === "resume" ? "session/resume" : "session/load",
|
|
20319
|
-
{ sessionId: cursor3, cwd, mcpServers },
|
|
20320
|
-
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
|
+
}
|
|
20321
20503
|
);
|
|
20322
|
-
if (sessionResult) sessionId = cursor3;
|
|
20323
20504
|
} catch {
|
|
20324
20505
|
}
|
|
20325
20506
|
}
|
|
20326
20507
|
if (!sessionId) {
|
|
20327
|
-
sessionResult = await request("session/new", { cwd, mcpServers }, NEW_SESSION_TIMEOUT)
|
|
20328
|
-
|
|
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
|
+
});
|
|
20329
20512
|
if (!sessionId) throw new Error("session/new returned no sessionId");
|
|
20330
20513
|
}
|
|
20331
20514
|
let selectedModel = null;
|
|
@@ -20343,16 +20526,15 @@ function createAcpDriver(support11) {
|
|
|
20343
20526
|
try {
|
|
20344
20527
|
if (support11.selectModel) {
|
|
20345
20528
|
const { configId } = support11.selectModel;
|
|
20346
|
-
|
|
20347
|
-
selectedModel = currentOf(sessionResult);
|
|
20529
|
+
selectedModel = modelOf(sessionConfigResult);
|
|
20348
20530
|
if (cliTurn.model && cliTurn.model !== selectedModel) {
|
|
20349
|
-
|
|
20350
|
-
|
|
20351
|
-
|
|
20352
|
-
|
|
20353
|
-
|
|
20354
|
-
)
|
|
20531
|
+
sessionResult = await request(
|
|
20532
|
+
"session/set_config_option",
|
|
20533
|
+
{ sessionId, configId, value: cliTurn.model },
|
|
20534
|
+
INIT_TIMEOUT,
|
|
20535
|
+
receiveModelVariants
|
|
20355
20536
|
);
|
|
20537
|
+
selectedModel = modelOf(sessionConfigResult);
|
|
20356
20538
|
if (selectedModel !== cliTurn.model) {
|
|
20357
20539
|
throw new Error(
|
|
20358
20540
|
`${DRIVER_KIND8} did not switch to ${cliTurn.model} (still ${selectedModel ?? "unknown"})`
|
|
@@ -20370,16 +20552,34 @@ function createAcpDriver(support11) {
|
|
|
20370
20552
|
});
|
|
20371
20553
|
if (!selectedModel && cliTurn.model) selectedModel = cliTurn.model;
|
|
20372
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
|
+
}
|
|
20373
20567
|
} catch (error51) {
|
|
20374
20568
|
emitSessionStarted();
|
|
20375
20569
|
throw error51;
|
|
20376
20570
|
}
|
|
20377
20571
|
emitSessionStarted();
|
|
20378
|
-
state.promptSent = true;
|
|
20379
20572
|
const text4 = support11.buildPromptText ? support11.buildPromptText(turn) : turn.system ? `${turn.system}
|
|
20380
20573
|
|
|
20381
20574
|
${turn.text}` : turn.text;
|
|
20382
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;
|
|
20383
20583
|
const result = await request("session/prompt", {
|
|
20384
20584
|
sessionId,
|
|
20385
20585
|
prompt: [{ type: "text", text: text4 }, ...imageBlocks]
|
|
@@ -20458,6 +20658,7 @@ ${turn.text}` : turn.text;
|
|
|
20458
20658
|
images: support11.images !== false,
|
|
20459
20659
|
nativeImageInput: support11.images === true,
|
|
20460
20660
|
effortLevels: support11.effortLevels,
|
|
20661
|
+
modelVariants: support11.modelVariants === true,
|
|
20461
20662
|
// OpenMausBot supplies a per-bot approvalMode on every harness
|
|
20462
20663
|
// turn, which safely overrides a legacy instance fullAuto value.
|
|
20463
20664
|
// Direct adapter calls that omit it still fail closed in sendTurn.
|
|
@@ -22515,7 +22716,7 @@ var init_ask_question = __esm({
|
|
|
22515
22716
|
|
|
22516
22717
|
// server/drivers/claude.ts
|
|
22517
22718
|
import { createHash as createHash5, randomBytes as randomBytes2 } from "node:crypto";
|
|
22518
|
-
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";
|
|
22519
22720
|
import { createServer as createNetServer } from "node:net";
|
|
22520
22721
|
import { homedir as homedir9, tmpdir as tmpdir3 } from "node:os";
|
|
22521
22722
|
import { join as join18, dirname as dirname9, isAbsolute as isAbsolute4, normalize } from "node:path";
|
|
@@ -22579,6 +22780,13 @@ function claudeEnvironment(model, source = process.env, configDir, instanceEnvir
|
|
|
22579
22780
|
function inheritsUserConfig(env) {
|
|
22580
22781
|
return env.OMB_CLAUDE_INHERIT_USER_CONFIG === "1";
|
|
22581
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
|
+
}
|
|
22582
22790
|
function readClaudeAuthSettings(env, instanceEnvironment = {}) {
|
|
22583
22791
|
if (CLAUDE_ACCOUNT_ENV_KEYS.some((key) => instanceEnvironment[key])) return {};
|
|
22584
22792
|
try {
|
|
@@ -22697,7 +22905,7 @@ function readClaudeModelCatalog(env = process.env) {
|
|
|
22697
22905
|
function removePrivateTempDir(filePath) {
|
|
22698
22906
|
if (!filePath) return true;
|
|
22699
22907
|
try {
|
|
22700
|
-
|
|
22908
|
+
rmSync5(dirname9(filePath), { recursive: true, force: true, maxRetries: 3, retryDelay: 50 });
|
|
22701
22909
|
return true;
|
|
22702
22910
|
} catch {
|
|
22703
22911
|
return false;
|
|
@@ -23048,6 +23256,9 @@ var init_claude = __esm({
|
|
|
23048
23256
|
const { instanceId, config: config2 } = input;
|
|
23049
23257
|
const environment = (model) => claudeEnvironment(config2.managed ? void 0 : model, { ...process.env, ...input.environment }, config2.configDir, input.environment);
|
|
23050
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
|
+
}
|
|
23051
23262
|
let models2 = STATIC_CLAUDE_MODELS;
|
|
23052
23263
|
const refreshModels = async () => {
|
|
23053
23264
|
if (config2.managed) return;
|
|
@@ -23182,7 +23393,7 @@ var init_claude = __esm({
|
|
|
23182
23393
|
}
|
|
23183
23394
|
const isolated = !inheritsUserConfig(turnEnvironment);
|
|
23184
23395
|
if (isolated) {
|
|
23185
|
-
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");
|
|
23186
23397
|
if (claudeCliSupports(cliVersion, "--setting-sources")) args.push("--setting-sources", "project");
|
|
23187
23398
|
}
|
|
23188
23399
|
const compactWindow = autoCompactWindow(turnEnvironment);
|
|
@@ -23312,7 +23523,7 @@ var init_claude = __esm({
|
|
|
23312
23523
|
retryState.delete(threadId);
|
|
23313
23524
|
if (mcpConfigPath) {
|
|
23314
23525
|
try {
|
|
23315
|
-
|
|
23526
|
+
rmSync5(dirname9(mcpConfigPath), { recursive: true, force: true });
|
|
23316
23527
|
} catch {
|
|
23317
23528
|
}
|
|
23318
23529
|
}
|
|
@@ -23320,7 +23531,7 @@ var init_claude = __esm({
|
|
|
23320
23531
|
}
|
|
23321
23532
|
if (mcpConfigPath) {
|
|
23322
23533
|
try {
|
|
23323
|
-
|
|
23534
|
+
rmSync5(dirname9(mcpConfigPath), { recursive: true, force: true });
|
|
23324
23535
|
} catch {
|
|
23325
23536
|
}
|
|
23326
23537
|
}
|
|
@@ -23332,7 +23543,7 @@ var init_claude = __esm({
|
|
|
23332
23543
|
broker = void 0;
|
|
23333
23544
|
if (mcpConfigPath) {
|
|
23334
23545
|
try {
|
|
23335
|
-
|
|
23546
|
+
rmSync5(dirname9(mcpConfigPath), { recursive: true, force: true });
|
|
23336
23547
|
} catch {
|
|
23337
23548
|
}
|
|
23338
23549
|
mcpConfigPath = null;
|
|
@@ -23447,7 +23658,7 @@ var init_claude = __esm({
|
|
|
23447
23658
|
session.broker?.pause();
|
|
23448
23659
|
if (session.mcpConfigPath) {
|
|
23449
23660
|
try {
|
|
23450
|
-
|
|
23661
|
+
rmSync5(dirname9(session.mcpConfigPath), { recursive: true, force: true });
|
|
23451
23662
|
} catch {
|
|
23452
23663
|
}
|
|
23453
23664
|
session.mcpConfigPath = null;
|
|
@@ -23601,7 +23812,7 @@ var init_claude = __esm({
|
|
|
23601
23812
|
failedBroker?.close();
|
|
23602
23813
|
if (session.mcpConfigPath) {
|
|
23603
23814
|
try {
|
|
23604
|
-
|
|
23815
|
+
rmSync5(dirname9(session.mcpConfigPath), { recursive: true, force: true });
|
|
23605
23816
|
} catch {
|
|
23606
23817
|
}
|
|
23607
23818
|
session.mcpConfigPath = null;
|
|
@@ -23679,7 +23890,7 @@ var init_claude = __esm({
|
|
|
23679
23890
|
session.broker = void 0;
|
|
23680
23891
|
if (session.mcpConfigPath) {
|
|
23681
23892
|
try {
|
|
23682
|
-
|
|
23893
|
+
rmSync5(dirname9(session.mcpConfigPath), { recursive: true, force: true });
|
|
23683
23894
|
} catch {
|
|
23684
23895
|
}
|
|
23685
23896
|
session.mcpConfigPath = null;
|
|
@@ -23730,7 +23941,7 @@ var init_claude = __esm({
|
|
|
23730
23941
|
session.broker?.close();
|
|
23731
23942
|
if (session.mcpConfigPath) {
|
|
23732
23943
|
try {
|
|
23733
|
-
|
|
23944
|
+
rmSync5(dirname9(session.mcpConfigPath), { recursive: true, force: true });
|
|
23734
23945
|
} catch {
|
|
23735
23946
|
}
|
|
23736
23947
|
}
|
|
@@ -23771,7 +23982,8 @@ var init_claude = __esm({
|
|
|
23771
23982
|
cliVersionChecked = true;
|
|
23772
23983
|
const auth = await claudeAuthStatus(config2.cli, env);
|
|
23773
23984
|
const update = claudeCliUpdate(version2, config2.cli);
|
|
23774
|
-
|
|
23985
|
+
const warning = claudeInheritWarning(env);
|
|
23986
|
+
return { state: "available", version: version2, ...auth, ...update ? { update } : {}, ...warning ? { warning } : {}, billing: "subscription" };
|
|
23775
23987
|
};
|
|
23776
23988
|
const generateReview = (prompt, signal) => new Promise((resolve12, reject) => {
|
|
23777
23989
|
const child = spawnCli(
|
|
@@ -24757,7 +24969,8 @@ function decodeManagedCodex(raw) {
|
|
|
24757
24969
|
throw new Error("Invalid Company Codex configuration.");
|
|
24758
24970
|
}
|
|
24759
24971
|
const url2 = new URL(value.url);
|
|
24760
|
-
|
|
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.");
|
|
24761
24974
|
return { url: url2.href.replace(/\/$/, ""), models: value.models };
|
|
24762
24975
|
}
|
|
24763
24976
|
function managedCodexArgs(config2) {
|
|
@@ -24780,6 +24993,14 @@ function managedCodexArgs(config2) {
|
|
|
24780
24993
|
"shell_environment_policy.ignore_default_excludes=false"
|
|
24781
24994
|
];
|
|
24782
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
|
+
}
|
|
24783
25004
|
function grantedPermissions(raw) {
|
|
24784
25005
|
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return {};
|
|
24785
25006
|
return Object.fromEntries(
|
|
@@ -24979,23 +25200,43 @@ function codexNativeIncomingLogMessage(message2, sensitiveResponseIds) {
|
|
|
24979
25200
|
return message2;
|
|
24980
25201
|
}
|
|
24981
25202
|
function mountMcpServer(appServerArgs, env, name, server, preApproved = true) {
|
|
24982
|
-
Object.assign(env, server.env);
|
|
24983
25203
|
const prefix = `mcp_servers.${name}`;
|
|
24984
|
-
|
|
24985
|
-
"-c",
|
|
24986
|
-
|
|
24987
|
-
|
|
24988
|
-
|
|
24989
|
-
|
|
24990
|
-
|
|
24991
|
-
|
|
24992
|
-
|
|
24993
|
-
|
|
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
|
+
}
|
|
24994
25235
|
if (preApproved) {
|
|
24995
25236
|
appServerArgs.push("-c", `${prefix}.default_tools_approval_mode="auto"`);
|
|
24996
25237
|
}
|
|
24997
25238
|
}
|
|
24998
|
-
var DRIVER_KIND3, ASTRA_MODEL_ID, ASTRA_MIN_CODEX_VERSION, CodexRpcError, 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;
|
|
24999
25240
|
var init_codex = __esm({
|
|
25000
25241
|
"server/drivers/codex.ts"() {
|
|
25001
25242
|
"use strict";
|
|
@@ -25026,6 +25267,7 @@ var init_codex = __esm({
|
|
|
25026
25267
|
};
|
|
25027
25268
|
QUESTION_TIMEOUT_NOTE2 = "No answer was given \u2014 use your best judgment.";
|
|
25028
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();
|
|
25029
25271
|
plainRecord = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
25030
25272
|
containsControlCharacter = (value) => {
|
|
25031
25273
|
for (const character of value) {
|
|
@@ -25092,8 +25334,19 @@ var init_codex = __esm({
|
|
|
25092
25334
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
25093
25335
|
});
|
|
25094
25336
|
const sendTurn = async (turn) => {
|
|
25095
|
-
if (config2.managed
|
|
25096
|
-
|
|
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
|
+
}
|
|
25097
25350
|
}
|
|
25098
25351
|
let stopRequested = false;
|
|
25099
25352
|
let promptSubmitted = false;
|
|
@@ -25102,6 +25355,7 @@ var init_codex = __esm({
|
|
|
25102
25355
|
const { threadId } = turn;
|
|
25103
25356
|
const approvalMode = turn.approvalMode ?? (config2.fullAuto ? "full" : "ask");
|
|
25104
25357
|
for (const [name, server] of Object.entries(turn.integrations?.custom ?? {})) {
|
|
25358
|
+
if ("url" in server) continue;
|
|
25105
25359
|
const reserved = Object.keys(server.env).find(isHarnessOwnedMcpEnvName);
|
|
25106
25360
|
if (reserved) {
|
|
25107
25361
|
throw new Error(`Custom MCP server \u201C${name}\u201D cannot set reserved environment variable \u201C${reserved}\u201D`);
|
|
@@ -25127,6 +25381,10 @@ var init_codex = __esm({
|
|
|
25127
25381
|
mountMcpServer(appServerArgs, env, "browser", turn.integrations.browser);
|
|
25128
25382
|
}
|
|
25129
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
|
+
}
|
|
25130
25388
|
mountMcpServer(appServerArgs, env, name, server, false);
|
|
25131
25389
|
}
|
|
25132
25390
|
if (turn.integrations?.phone) {
|
|
@@ -25271,6 +25529,18 @@ var init_codex = __esm({
|
|
|
25271
25529
|
}
|
|
25272
25530
|
return;
|
|
25273
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
|
+
}
|
|
25274
25544
|
const mcpTool = isLegacyMcpPermission ? String(params.message ?? "").match(/tool "([^"]+)"/)?.[1] : void 0;
|
|
25275
25545
|
const tool = mcpAppApproval ? mcpAppApproval.tool : isLegacyMcpPermission ? mcpTool ?? "mcp" : isAdditionalPermission ? "permissions" : method === "item/fileChange/requestApproval" || method === "applyPatchApproval" ? "edit" : isQuestion ? "ask_user" : "shell";
|
|
25276
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" };
|
|
@@ -33542,7 +33812,9 @@ async function mountChatTools(integrations, signal) {
|
|
|
33542
33812
|
const servers = [];
|
|
33543
33813
|
if (integrations?.agents) servers.push(["agents", integrations.agents]);
|
|
33544
33814
|
if (integrations?.composio) servers.push(["composio", integrations.composio]);
|
|
33545
|
-
|
|
33815
|
+
for (const [name, server] of Object.entries(integrations?.custom ?? {})) {
|
|
33816
|
+
if ("command" in server) servers.push([name, server]);
|
|
33817
|
+
}
|
|
33546
33818
|
if (servers.length > 32) throw new Error("MCP server count exceeds the 32-server limit");
|
|
33547
33819
|
const clients = [];
|
|
33548
33820
|
let closed = false;
|
|
@@ -35767,12 +36039,14 @@ function parseOpenCodeModelsOutput(stdout2) {
|
|
|
35767
36039
|
const name = typeof record3.name === "string" && record3.name.trim() ? record3.name.trim() : labelForModel(model);
|
|
35768
36040
|
const limit = record3.limit && typeof record3.limit === "object" && !Array.isArray(record3.limit) ? record3.limit : {};
|
|
35769
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;
|
|
35770
36043
|
seen.add(slug);
|
|
35771
36044
|
options.push({
|
|
35772
36045
|
id: slug,
|
|
35773
36046
|
label: `${providerLabel(provider)} \xB7 ${name}`,
|
|
35774
36047
|
...localModelRecord(record3) ? { custom: true, loaded: true } : {},
|
|
35775
|
-
...contextWindow ? { contextWindow } : {}
|
|
36048
|
+
...contextWindow ? { contextWindow } : {},
|
|
36049
|
+
...variants ? { variants } : {}
|
|
35776
36050
|
});
|
|
35777
36051
|
};
|
|
35778
36052
|
for (const line of stdout2.split(/\r?\n/u)) {
|
|
@@ -35979,8 +36253,31 @@ var init_opencode_go = __esm({
|
|
|
35979
36253
|
spawnArgs: () => ["acp"],
|
|
35980
36254
|
credentialEnv: ["OPENCODE_API_KEY"],
|
|
35981
36255
|
selectModel: { configId: "model" },
|
|
36256
|
+
modelVariants: true,
|
|
35982
36257
|
resolveTurnModel: (model, env) => model ? ensureOpenCodeInjectModel(normalizeLegacyOpenCodeModel(model, env), env) : model,
|
|
35983
36258
|
transformEnv: stripForeignProviderKeys,
|
|
36259
|
+
applyTurnEnv: (env, { fullAuto }) => {
|
|
36260
|
+
if (!fullAuto) return;
|
|
36261
|
+
env.OPENCODE_PERMISSION = JSON.stringify(Object.fromEntries([
|
|
36262
|
+
"*",
|
|
36263
|
+
"external_directory",
|
|
36264
|
+
"read",
|
|
36265
|
+
"edit",
|
|
36266
|
+
"bash",
|
|
36267
|
+
"glob",
|
|
36268
|
+
"grep",
|
|
36269
|
+
"list",
|
|
36270
|
+
"task",
|
|
36271
|
+
"lsp",
|
|
36272
|
+
"skill",
|
|
36273
|
+
"webfetch",
|
|
36274
|
+
"websearch",
|
|
36275
|
+
"codesearch",
|
|
36276
|
+
"todoread",
|
|
36277
|
+
"todowrite",
|
|
36278
|
+
"doom_loop"
|
|
36279
|
+
].map((permission) => [permission, "allow"])));
|
|
36280
|
+
},
|
|
35984
36281
|
pickAuthMethod: () => null,
|
|
35985
36282
|
authFailure: "continue",
|
|
35986
36283
|
isAuthenticated: async (env, config2) => Boolean(env.OPENCODE_API_KEY) || hasStoredOpenCodeAuth(env) || await canListOpenCodeModels(env, config2.cli),
|
|
@@ -43571,7 +43868,7 @@ var init_openai_compat = __esm({
|
|
|
43571
43868
|
});
|
|
43572
43869
|
|
|
43573
43870
|
// server/drivers/pi.ts
|
|
43574
|
-
import { chmodSync as chmodSync6, existsSync as existsSync17, mkdirSync as mkdirSync15, mkdtempSync as mkdtempSync3, readFileSync as readFileSync17, rmSync as
|
|
43871
|
+
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";
|
|
43575
43872
|
import { homedir as homedir21, tmpdir as tmpdir4 } from "node:os";
|
|
43576
43873
|
import { join as join30 } from "node:path";
|
|
43577
43874
|
function readPiPromptImages(turn) {
|
|
@@ -43907,7 +44204,7 @@ var init_pi = __esm({
|
|
|
43907
44204
|
writeFileSync12(join30(mcpTempDir, "mcp.json"), JSON.stringify({ mcpServers }), { mode: 384 });
|
|
43908
44205
|
} catch (err) {
|
|
43909
44206
|
try {
|
|
43910
|
-
|
|
44207
|
+
rmSync6(mcpTempDir, { recursive: true, force: true });
|
|
43911
44208
|
} catch {
|
|
43912
44209
|
}
|
|
43913
44210
|
throw err;
|
|
@@ -43928,7 +44225,7 @@ var init_pi = __esm({
|
|
|
43928
44225
|
} catch (err) {
|
|
43929
44226
|
if (mcpTempDir) {
|
|
43930
44227
|
try {
|
|
43931
|
-
|
|
44228
|
+
rmSync6(mcpTempDir, { recursive: true, force: true });
|
|
43932
44229
|
} catch {
|
|
43933
44230
|
}
|
|
43934
44231
|
}
|
|
@@ -43985,7 +44282,7 @@ var init_pi = __esm({
|
|
|
43985
44282
|
}
|
|
43986
44283
|
if (mcpTempDir) {
|
|
43987
44284
|
try {
|
|
43988
|
-
|
|
44285
|
+
rmSync6(mcpTempDir, { recursive: true, force: true });
|
|
43989
44286
|
} catch {
|
|
43990
44287
|
}
|
|
43991
44288
|
}
|
|
@@ -44998,7 +45295,7 @@ __export(browser_engine_exports, {
|
|
|
44998
45295
|
});
|
|
44999
45296
|
import { spawn as spawn8 } from "node:child_process";
|
|
45000
45297
|
import { createHash as createHash8, randomBytes as randomBytes3, randomUUID as randomUUID11 } from "node:crypto";
|
|
45001
|
-
import { chmodSync as chmodSync7, constants as constants2, copyFileSync, existsSync as existsSync18, mkdirSync as mkdirSync16, readFileSync as readFileSync20, readdirSync as readdirSync3, renameSync as
|
|
45298
|
+
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";
|
|
45002
45299
|
import { homedir as homedir23, tmpdir as tmpdir5 } from "node:os";
|
|
45003
45300
|
import { delimiter as delimiter6, dirname as dirname11, join as join35, resolve as resolve10 } from "node:path";
|
|
45004
45301
|
function browserRestoreKey(session) {
|
|
@@ -45116,7 +45413,7 @@ async function prepareBrowserSessionState(binaryPath, session, options = {}) {
|
|
|
45116
45413
|
const candidates = [".json.enc", ".json"].flatMap((suffix) => {
|
|
45117
45414
|
const path3 = join35(directory, `${session}-${session}${suffix}`);
|
|
45118
45415
|
try {
|
|
45119
|
-
const stat4 =
|
|
45416
|
+
const stat4 = statSync4(path3);
|
|
45120
45417
|
if (!stat4.isFile()) throw new Error("Saved browser state is not a file.");
|
|
45121
45418
|
return [{ path: path3, suffix, modified: stat4.mtimeMs }];
|
|
45122
45419
|
} catch (error51) {
|
|
@@ -45211,7 +45508,7 @@ async function installAgentBrowserBinary(options = {}) {
|
|
|
45211
45508
|
const staging = `${destination}.${randomBytes3(6).toString("hex")}.part`;
|
|
45212
45509
|
writeFileSync13(staging, body, { mode: 493 });
|
|
45213
45510
|
if (platform !== "win32") chmodSync7(staging, 493);
|
|
45214
|
-
|
|
45511
|
+
renameSync6(staging, destination);
|
|
45215
45512
|
return destination;
|
|
45216
45513
|
}
|
|
45217
45514
|
function ensureChrome(binaryPath, options = {}) {
|
|
@@ -45328,7 +45625,7 @@ function agentBrowserFrame(input) {
|
|
|
45328
45625
|
} catch {
|
|
45329
45626
|
fail(new Error("the browser reported a picture it did not write"));
|
|
45330
45627
|
} finally {
|
|
45331
|
-
|
|
45628
|
+
rmSync7(file2, { force: true });
|
|
45332
45629
|
}
|
|
45333
45630
|
};
|
|
45334
45631
|
child.on("error", (error51) => done(error51 instanceof Error ? error51 : new Error(String(error51))));
|
|
@@ -45347,7 +45644,7 @@ function describeBrowserEngine(status) {
|
|
|
45347
45644
|
}
|
|
45348
45645
|
function agentBrowserBinaryExists(dataDir = DATA_DIR) {
|
|
45349
45646
|
try {
|
|
45350
|
-
return
|
|
45647
|
+
return statSync4(pinnedBinaryPath(dataDir)).isFile();
|
|
45351
45648
|
} catch {
|
|
45352
45649
|
return false;
|
|
45353
45650
|
}
|
|
@@ -45410,7 +45707,7 @@ var init_browser_engine = __esm({
|
|
|
45410
45707
|
// server/cli.ts
|
|
45411
45708
|
var import_qrcode_terminal = __toESM(require_main(), 1);
|
|
45412
45709
|
import { spawn as spawn9 } from "node:child_process";
|
|
45413
|
-
import { closeSync as
|
|
45710
|
+
import { closeSync as closeSync5, existsSync as existsSync19, mkdirSync as mkdirSync17, openSync as openSync5, readFileSync as readFileSync21 } from "node:fs";
|
|
45414
45711
|
import { homedir as homedir24 } from "node:os";
|
|
45415
45712
|
import { dirname as dirname12, join as join36, resolve as resolve11 } from "node:path";
|
|
45416
45713
|
import { createInterface as createInterface2 } from "node:readline/promises";
|
|
@@ -48373,7 +48670,7 @@ async function runPhoneSetup(options, io, deps) {
|
|
|
48373
48670
|
const device = await io.choose("Use OpenMausBot on your phone?", [
|
|
48374
48671
|
"Skip for now",
|
|
48375
48672
|
"iPhone / iPad \u2014 native app or Safari",
|
|
48376
|
-
"Android \u2014
|
|
48673
|
+
"Android \u2014 app or browser"
|
|
48377
48674
|
], 0);
|
|
48378
48675
|
if (device === 0) return skip();
|
|
48379
48676
|
const phone = device === 1 ? "ios" : "android";
|
|
@@ -48436,7 +48733,7 @@ function phonePairingInstructions(phone, input) {
|
|
|
48436
48733
|
];
|
|
48437
48734
|
}
|
|
48438
48735
|
return [
|
|
48439
|
-
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,
|
|
48736
|
+
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.",
|
|
48440
48737
|
`Or open ${origin}/pair on your phone and enter the code.`,
|
|
48441
48738
|
"Choose Connect on the phone. Scanning a QR does not mean the phone is paired.",
|
|
48442
48739
|
"The code works once and expires after five minutes. This phone receives client access: chat and approvals, not settings or pairing administration."
|
|
@@ -48727,7 +49024,11 @@ function parseArgs(argv, env = process.env) {
|
|
|
48727
49024
|
options.domain = domain2;
|
|
48728
49025
|
} else if (arg === "--tunnel") options.tunnel = true;
|
|
48729
49026
|
else if (arg === "--client") options.client = true;
|
|
48730
|
-
else if (arg === "--
|
|
49027
|
+
else if (arg === "--phone") {
|
|
49028
|
+
const kind = value().toLowerCase();
|
|
49029
|
+
if (kind !== "ios" && kind !== "android") return { error: "--phone takes ios or android" };
|
|
49030
|
+
options.phone = kind;
|
|
49031
|
+
} else if (arg === "--no-pair") options.pair = false;
|
|
48731
49032
|
else if (arg === "--no-open") options.open = false;
|
|
48732
49033
|
else if (arg === "--local") options.local = true;
|
|
48733
49034
|
else if (arg === "--json") options.json = true;
|
|
@@ -48787,7 +49088,8 @@ var USAGE = `openmausbot \u2014 your team of AI bots, ready in a few steps
|
|
|
48787
49088
|
openmausbot start [the same options as serve]
|
|
48788
49089
|
openmausbot serve [--port 8799] [--data-dir DIR] [--label NAME]
|
|
48789
49090
|
[--public-url https://host] [--tailscale | --tunnel | --domain HOST] [--no-pair]
|
|
48790
|
-
openmausbot pair [--label NAME] [--client] [--
|
|
49091
|
+
openmausbot pair [--label NAME] [--client] [--phone ios|android]
|
|
49092
|
+
[--public-url https://host]
|
|
48791
49093
|
openmausbot sessions [revoke ID]
|
|
48792
49094
|
openmausbot status
|
|
48793
49095
|
openmausbot login [--email you@example.com]
|
|
@@ -48962,22 +49264,46 @@ async function showPhonePairing(options, origin, log) {
|
|
|
48962
49264
|
return false;
|
|
48963
49265
|
}
|
|
48964
49266
|
for (const line of phonePairingInstructions(options.phone ?? "ios", { origin, ready })) log(line);
|
|
48965
|
-
log(await mintPairing(options.port, { client: true, label: options.label ?? (options.phone === "android" ? "Android" : "iPhone / iPad"), publicUrl: origin }));
|
|
49267
|
+
log(await mintPairing(options.port, { client: true, label: options.label ?? (options.phone === "android" ? "Android" : "iPhone / iPad"), publicUrl: origin, phone: options.phone }));
|
|
48966
49268
|
log("Waiting for you to connect on the phone. Keep this terminal and the code private.");
|
|
48967
49269
|
return true;
|
|
48968
49270
|
}
|
|
48969
49271
|
function pairingBlock(input) {
|
|
48970
49272
|
const lines = [`pairing code: ${input.code}`, `expires: ${new Date(input.expiresAt).toLocaleTimeString()} (single use)`];
|
|
48971
|
-
if (input.url) {
|
|
48972
|
-
lines.push(`open or scan: ${input.url}`);
|
|
48973
|
-
lines.push("");
|
|
48974
|
-
lines.push(qrToString(input.url));
|
|
48975
|
-
} else {
|
|
49273
|
+
if (!input.url && !input.inviteUrl) {
|
|
48976
49274
|
lines.push(`open: /pair on the address you use for this server, and type the code`);
|
|
48977
49275
|
if (input.hint) lines.push(` (${input.hint})`);
|
|
49276
|
+
return lines.join("\n");
|
|
49277
|
+
}
|
|
49278
|
+
const scanInvite = input.phone === "android" && !!input.inviteUrl;
|
|
49279
|
+
if (input.url) lines.push(scanInvite ? `web browser: ${input.url}` : `open or scan: ${input.url}`);
|
|
49280
|
+
if (input.inviteUrl) lines.push(`phone app: ${input.inviteUrl}`);
|
|
49281
|
+
const target = scanInvite ? input.inviteUrl : input.url;
|
|
49282
|
+
if (target) {
|
|
49283
|
+
lines.push("");
|
|
49284
|
+
lines.push(qrToString(target));
|
|
49285
|
+
lines.push("");
|
|
49286
|
+
if (scanInvite) {
|
|
49287
|
+
lines.push(`Scan that in the OpenMausBot app. For a browser instead, open the web`);
|
|
49288
|
+
lines.push(`address above and type the code.`);
|
|
49289
|
+
} else if (input.phone === "android") {
|
|
49290
|
+
lines.push(`That QR opens the web app. The Android app needs the phone-app link,`);
|
|
49291
|
+
lines.push(`which this server cannot build without a public address: set`);
|
|
49292
|
+
lines.push(`OMB_PUBLIC_URL, or open the web address above and type the code.`);
|
|
49293
|
+
} else if (input.inviteUrl) {
|
|
49294
|
+
lines.push(`Scan that with Camera for the browser, or paste the phone-app link`);
|
|
49295
|
+
lines.push(`above into the OpenMausBot app.`);
|
|
49296
|
+
}
|
|
48978
49297
|
}
|
|
48979
49298
|
return lines.join("\n");
|
|
48980
49299
|
}
|
|
49300
|
+
function originOf(link) {
|
|
49301
|
+
try {
|
|
49302
|
+
return new URL(link).origin;
|
|
49303
|
+
} catch {
|
|
49304
|
+
return null;
|
|
49305
|
+
}
|
|
49306
|
+
}
|
|
48981
49307
|
function qrToString(text4) {
|
|
48982
49308
|
let out = "";
|
|
48983
49309
|
import_qrcode_terminal.default.generate(text4, { small: true }, (rendered) => {
|
|
@@ -48992,7 +49318,9 @@ async function mintPairing(port, options) {
|
|
|
48992
49318
|
const { status, body } = await api(port, "/api/auth/pairing", { method: "POST", body: JSON.stringify(request) });
|
|
48993
49319
|
if (status !== 200) throw new Error(`server refused to mint a pairing code: ${typeof body?.error === "string" ? body.error : status}`);
|
|
48994
49320
|
const url2 = options.publicUrl ? `${options.publicUrl}/pair#code=${body.code}` : typeof body.url === "string" ? body.url : null;
|
|
48995
|
-
|
|
49321
|
+
const address = options.publicUrl ?? (typeof body.url === "string" ? originOf(body.url) : null);
|
|
49322
|
+
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;
|
|
49323
|
+
return pairingBlock({ code: body.code, url: url2, inviteUrl: invite, expiresAt: body.expiresAt, hint: typeof body.hint === "string" ? body.hint : null, phone: options.phone });
|
|
48996
49324
|
}
|
|
48997
49325
|
async function runPair(options) {
|
|
48998
49326
|
if (!await serverUp(options.port)) {
|
|
@@ -49020,7 +49348,7 @@ async function runPair(options) {
|
|
|
49020
49348
|
}
|
|
49021
49349
|
const ui = defaultSetupIo();
|
|
49022
49350
|
try {
|
|
49023
|
-
const selected = await ui.choose("Which phone are you connecting?", ["iPhone / iPad \u2014 app or Safari", "Android \u2014
|
|
49351
|
+
const selected = await ui.choose("Which phone are you connecting?", ["iPhone / iPad \u2014 app or Safari", "Android \u2014 app or browser", "Cancel"], 0);
|
|
49024
49352
|
if (selected === 2) return 0;
|
|
49025
49353
|
launch = { ...launch, phone: selected === 0 ? "ios" : "android" };
|
|
49026
49354
|
return await showPhonePairing(launch, origin, ui.log) ? 0 : 1;
|
|
@@ -49030,7 +49358,7 @@ async function runPair(options) {
|
|
|
49030
49358
|
return 130;
|
|
49031
49359
|
}
|
|
49032
49360
|
}
|
|
49033
|
-
console.log(await mintPairing(options.port, { label: options.label, client: options.client, publicUrl: options.publicUrl }));
|
|
49361
|
+
console.log(await mintPairing(options.port, { label: options.label, client: options.client, publicUrl: options.publicUrl, phone: options.phone }));
|
|
49034
49362
|
if (options.client) console.log("(client scope: chat and approvals only; cannot change settings or pair others)");
|
|
49035
49363
|
return 0;
|
|
49036
49364
|
}
|
|
@@ -49354,7 +49682,7 @@ async function runServe(options, log = console.log) {
|
|
|
49354
49682
|
const logsDir = join36(options.dataDir, "logs");
|
|
49355
49683
|
mkdirSync17(logsDir, { recursive: true, mode: 448 });
|
|
49356
49684
|
logPath = join36(logsDir, `server-${Date.now()}-${process.pid}.log`);
|
|
49357
|
-
logFd =
|
|
49685
|
+
logFd = openSync5(logPath, "wx", 384);
|
|
49358
49686
|
log("\nStarting your workspace\u2026");
|
|
49359
49687
|
}
|
|
49360
49688
|
if (tailscale) {
|
|
@@ -49378,7 +49706,7 @@ async function runServe(options, log = console.log) {
|
|
|
49378
49706
|
}
|
|
49379
49707
|
throw error51;
|
|
49380
49708
|
} finally {
|
|
49381
|
-
if (logFd !== void 0)
|
|
49709
|
+
if (logFd !== void 0) closeSync5(logFd);
|
|
49382
49710
|
process.removeListener("SIGINT", cancelStartup);
|
|
49383
49711
|
process.removeListener("SIGTERM", cancelStartup);
|
|
49384
49712
|
}
|