openmausbot 0.1.92 → 0.1.93
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/{DesktopViewer-Do6lBa4C.js → DesktopViewer-CKNR3SEW.js} +1 -1
- package/dist/assets/{abnfDiagram-O67JEVCF-Cd3X7Hxc.js → abnfDiagram-O67JEVCF-Ckrm1I1X.js} +1 -1
- package/dist/assets/{arc-DIYc7Ymx.js → arc-BBdBuCgB.js} +1 -1
- package/dist/assets/{architectureDiagram-NJMV4G6O-DBmRGVyP.js → architectureDiagram-NJMV4G6O-CDdA3Hjs.js} +1 -1
- package/dist/assets/{blockDiagram-BEXU5L5S-CPFePSEE.js → blockDiagram-BEXU5L5S-AUrsx1YR.js} +1 -1
- package/dist/assets/{c4Diagram-YGBWAQC7-DD_DO1qy.js → c4Diagram-YGBWAQC7-BEqQ0Unh.js} +1 -1
- package/dist/assets/channel-BU94VpxE.js +1 -0
- package/dist/assets/{chunk-2Q5K7J3B-BNEeNSjX.js → chunk-2Q5K7J3B-CEEuvd4C.js} +1 -1
- package/dist/assets/{chunk-3FUC2YCW-BbinLaqH.js → chunk-3FUC2YCW-DyANCiHl.js} +2 -2
- package/dist/assets/{chunk-5VM5RSS4-BBgYrgDR.js → chunk-5VM5RSS4-Dx_Slpw9.js} +1 -1
- package/dist/assets/{chunk-GTNCS2PH-ezXj-kA-.js → chunk-GTNCS2PH-Dl7h7iiD.js} +1 -1
- package/dist/assets/{chunk-GWA4HPMP-9FxZ3diV.js → chunk-GWA4HPMP-BLx07SPb.js} +1 -1
- package/dist/assets/{chunk-JWPE2WC7-CO-40JpI.js → chunk-JWPE2WC7-BMxDj3n7.js} +1 -1
- package/dist/assets/{chunk-NETBCI7D-BEhjslYE.js → chunk-NETBCI7D-CN66PT4H.js} +1 -1
- package/dist/assets/{chunk-WEXAMYUT-CNeq4n7_.js → chunk-WEXAMYUT-6HwhsDKw.js} +1 -1
- package/dist/assets/{chunk-XXDRQBXY-OsCY7KSi.js → chunk-XXDRQBXY-gWnLt7SN.js} +1 -1
- package/dist/assets/{classDiagram-v2-NBCMYWYE-CloRUEtk.js → classDiagram-v2-NBCMYWYE-CMS5l2ea.js} +1 -1
- package/dist/assets/{cose-bilkent-JH36ORCC-D1BGZhp4.js → cose-bilkent-JH36ORCC-CV7sQwIG.js} +1 -1
- package/dist/assets/{cynefin-OW5HDTMX-CUf4T2CN.js → cynefin-OW5HDTMX-CSyl-7vl.js} +1 -1
- package/dist/assets/{cynefinDiagram-VND7K2PF-DPEZrFGA.js → cynefinDiagram-VND7K2PF-BCLKL6az.js} +1 -1
- package/dist/assets/{dagre-6A5THRUB-bDe6GIv5.js → dagre-6A5THRUB-DiaZs6S1.js} +1 -1
- package/dist/assets/{diagram-22UHCM2B-CdcUQz55.js → diagram-22UHCM2B-BeTtmt3I.js} +1 -1
- package/dist/assets/{diagram-3UASUU5V-BZpqGg7c.js → diagram-3UASUU5V-CsdBG-QQ.js} +1 -1
- package/dist/assets/{diagram-ATOU4E4O-DvGM6ugp.js → diagram-ATOU4E4O-BczvdbR1.js} +1 -1
- package/dist/assets/{diagram-CDSNMT55-DSTmMm0s.js → diagram-CDSNMT55-DHTTTMhi.js} +1 -1
- package/dist/assets/{diagram-MLGK6HIB-15cucnMn.js → diagram-MLGK6HIB-RTjHyd8z.js} +1 -1
- package/dist/assets/{diagram-MPIPVDR6-tMbuaE6n.js → diagram-MPIPVDR6-BDenHEH_.js} +1 -1
- package/dist/assets/{ebnfDiagram-ZINNZB2B-BYxYzjHI.js → ebnfDiagram-ZINNZB2B-BSiRSbtL.js} +1 -1
- package/dist/assets/{elk-276RUBZZ-v6bj852W.js → elk-276RUBZZ-BCAElss-.js} +1 -1
- package/dist/assets/{erDiagram-OPXOYQCR-5lBBlnd2.js → erDiagram-OPXOYQCR-C4_1ZPJe.js} +1 -1
- package/dist/assets/{flowDiagram-KWPJA3E3-CZyl1zIj.js → flowDiagram-KWPJA3E3-Bcb4Z75S.js} +1 -1
- package/dist/assets/{ganttDiagram-FUAMR5RP-BiAI-ltZ.js → ganttDiagram-FUAMR5RP-BiPOzxzb.js} +1 -1
- package/dist/assets/{gitGraphDiagram-X574FWY7-BAZISkj3.js → gitGraphDiagram-X574FWY7-B1wtF3ZS.js} +1 -1
- package/dist/assets/index-Biji-bfL.css +1 -0
- package/dist/assets/{index-DGBaEXrM.js → index-BkYwilkG.js} +1 -1
- package/dist/assets/index-DZlhoES0.js +597 -0
- package/dist/assets/{infoDiagram-VRGFBTTK-B6ooOy-Z.js → infoDiagram-VRGFBTTK-A19No71U.js} +1 -1
- package/dist/assets/{ishikawaDiagram-OU5B5YK6-BZ9ksi-B.js → ishikawaDiagram-OU5B5YK6-BQsqJ_cV.js} +1 -1
- package/dist/assets/{journeyDiagram-ZHPQQLJL-DWqlzIEe.js → journeyDiagram-ZHPQQLJL-DAO0pVan.js} +1 -1
- package/dist/assets/{kanban-definition-PNTS6WVX-JX6piDwL.js → kanban-definition-PNTS6WVX-NepmKEe2.js} +1 -1
- package/dist/assets/{linear-CmOWzX0P.js → linear-bq1PTDTW.js} +1 -1
- package/dist/assets/{mermaid.core-CF1zwoQ-.js → mermaid.core-s4LTbQle.js} +5 -5
- package/dist/assets/{mindmap-definition-NLK3R4M7-CGh2K4fW.js → mindmap-definition-NLK3R4M7-LtdbgHFH.js} +1 -1
- package/dist/assets/{pegDiagram-GJSIUBJH-CDwYN0s7.js → pegDiagram-GJSIUBJH-tdbaCxiK.js} +1 -1
- package/dist/assets/{pieDiagram-5QR66LMP-1rfjJocB.js → pieDiagram-5QR66LMP-DvkbpW8l.js} +1 -1
- package/dist/assets/{quadrantDiagram-O4NWA36T-tKPvPiok.js → quadrantDiagram-O4NWA36T-Do4KaH-E.js} +1 -1
- package/dist/assets/{railroadDiagram-XR7U4H2S-BHLm5vXR.js → railroadDiagram-XR7U4H2S-BQWULOAs.js} +1 -1
- package/dist/assets/{requirementDiagram-PLB6GJNP-CB45STp7.js → requirementDiagram-PLB6GJNP-w9kei1FU.js} +1 -1
- package/dist/assets/{sankeyDiagram-IPEJSGJF-55QA_huC.js → sankeyDiagram-IPEJSGJF-D2gRy0e8.js} +1 -1
- package/dist/assets/{sequenceDiagram-PO4LG4MO-BckFmQHn.js → sequenceDiagram-PO4LG4MO-a2sO5_Eo.js} +1 -1
- package/dist/assets/{sizeCapture-INFHLROL-BFCOJF11.js → sizeCapture-INFHLROL-CiPJmFEB.js} +1 -1
- package/dist/assets/{stateDiagram-v2-GCMORJYK-CZvmiVVN.js → stateDiagram-v2-GCMORJYK-DAkUUlL7.js} +1 -1
- package/dist/assets/{swimlanes-2SLR337P-BpDUCEKy.js → swimlanes-2SLR337P-DANf2R8Y.js} +1 -1
- package/dist/assets/swimlanesDiagram-TC7HE7FX-CdHxG8aM.js +8 -0
- package/dist/assets/{timeline-definition-EJHVYXUP-BpxHq6IK.js → timeline-definition-EJHVYXUP-BKpQmzrT.js} +1 -1
- package/dist/assets/{usecaseDiagram-POWQR4AR-Cj66vm02.js → usecaseDiagram-POWQR4AR-BtI7qLN-.js} +1 -1
- package/dist/assets/{vennDiagram-UO4OBE2U-C9nRkWE_.js → vennDiagram-UO4OBE2U-gXJXrAG_.js} +1 -1
- package/dist/assets/{wardleyDiagram-VNRHLVJA-D-me_nWj.js → wardleyDiagram-VNRHLVJA-GU8Po5-n.js} +1 -1
- package/dist/assets/{xychartDiagram-PMCCYNJV-Dc_fL4mk.js → xychartDiagram-PMCCYNJV-BF4J30g6.js} +1 -1
- package/dist/index.html +2 -2
- package/dist-server/companion/src/routes.js +24 -1
- package/dist-server/container-mcp.js +6 -1
- package/dist-server/drivers/agents-proxy.js +2 -0
- package/dist-server/index.js +1722 -906
- package/dist-server/local-computer-proxy.js +5 -1
- package/dist-server/mcp-gate.js +5 -1
- package/dist-server/openmausbot.js +763 -93
- package/dist-server/pair-cli.js +763 -93
- package/dist-server/server/boat.js +3 -3
- package/dist-server/server/cloud-owner.js +1 -1
- package/dist-server/server/computer-control.js +6 -0
- package/dist-server/server/config.js +14 -1
- package/dist-server/server/container-computer.js +43 -32
- package/dist-server/server/digest.js +12 -2
- package/dist-server/server/drivers/acp/core.js +172 -12
- package/dist-server/server/drivers/acp/cursor.js +13 -1
- package/dist-server/server/drivers/acp/quiet-status.js +257 -0
- package/dist-server/server/drivers/acp/qwen.js +18 -0
- package/dist-server/server/drivers/builtIn.js +2 -0
- package/dist-server/server/drivers/cerebras.js +108 -0
- package/dist-server/server/drivers/chat-mcp-tools.js +20 -3
- package/dist-server/server/drivers/claude.js +17 -3
- package/dist-server/server/drivers/openai-chat.js +26 -2
- package/dist-server/server/drivers/prompt-split.js +2 -0
- package/dist-server/server/env-path.js +6 -2
- package/dist-server/server/index.js +210 -57
- package/dist-server/server/local-vm-stop-reason.js +26 -0
- package/dist-server/server/provider-key-check.js +2 -1
- package/dist-server/server/routes/desktop-viewer.js +50 -6
- package/dist-server/server/routines.js +6 -3
- package/dist-server/server/store.js +54 -0
- package/dist-server/server/vps-computer.js +1 -1
- package/dist-server/server/workspace-backup.js +22 -0
- package/dist-server/server/workspace.js +1 -1
- package/dist-server/shared/approval-mode.js +1 -1
- package/dist-server/shared/redact.js +1 -0
- package/dist-server/shared/tool-name.js +22 -0
- package/dist-server/vps-container-mcp.js +6 -1
- package/dist-server/workspace-backup.worker.js +14 -0
- package/package.json +1 -1
- package/dist/assets/channel-Dtk5Mtic.js +0 -1
- package/dist/assets/index-Cdmjrl28.css +0 -1
- package/dist/assets/index-DR7YPMkW.js +0 -597
- package/dist/assets/swimlanesDiagram-TC7HE7FX-M0GYW9Y3.js +0 -8
|
@@ -1140,6 +1140,8 @@ var init_redact = __esm({
|
|
|
1140
1140
|
// xai (grok)
|
|
1141
1141
|
/\bgsk_[A-Za-z0-9]{40,}/g,
|
|
1142
1142
|
// groq
|
|
1143
|
+
/\bcsk-[A-Za-z0-9]{32,}/g,
|
|
1144
|
+
// cerebras
|
|
1143
1145
|
/\bhf_[A-Za-z0-9]{30,}/g,
|
|
1144
1146
|
// hugging face
|
|
1145
1147
|
/\b(?:ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9]{20,}/g,
|
|
@@ -17575,7 +17577,7 @@ function defaultSetupIo(input = process.stdin, output = process.stdout) {
|
|
|
17575
17577
|
`);
|
|
17576
17578
|
};
|
|
17577
17579
|
const rich = () => output.isTTY === true && process.env.TERM !== "dumb" && process.env.NO_COLOR === void 0 && (output.columns ?? 80) >= 30 && (output.rows ?? 24) >= 8;
|
|
17578
|
-
const
|
|
17580
|
+
const run3 = (prompt) => {
|
|
17579
17581
|
if (!input.isTTY || !input.setRawMode) throw new Error("Setup needs an interactive terminal.");
|
|
17580
17582
|
const raw = input.isRaw === true;
|
|
17581
17583
|
const flowing = input.readableFlowing === true;
|
|
@@ -17636,14 +17638,14 @@ function defaultSetupIo(input = process.stdin, output = process.stdout) {
|
|
|
17636
17638
|
}
|
|
17637
17639
|
})();
|
|
17638
17640
|
};
|
|
17639
|
-
const ask = (question) =>
|
|
17640
|
-
const secret = (question) =>
|
|
17641
|
+
const ask = (question) => run3((context) => rich() ? text2({ ...context, message: displayText(question) }) : plainText(displayText(question), false, context));
|
|
17642
|
+
const secret = (question) => run3((context) => rich() ? password({ ...context, message: displayText(question), mask: "*" }) : plainText(displayText(question), true, context));
|
|
17641
17643
|
const choose = async (question, options, defaultIndex = 0) => {
|
|
17642
17644
|
if (!options.length) throw new Error("There are no choices available.");
|
|
17643
17645
|
if (!Number.isInteger(defaultIndex) || defaultIndex < 0 || defaultIndex >= options.length) {
|
|
17644
17646
|
throw new Error("The default choice is not available.");
|
|
17645
17647
|
}
|
|
17646
|
-
if (rich()) return
|
|
17648
|
+
if (rich()) return run3((context) => select({
|
|
17647
17649
|
...context,
|
|
17648
17650
|
message: displayText(question),
|
|
17649
17651
|
options: options.map((label, value) => ({ value, label: displayText(label) })),
|
|
@@ -17671,7 +17673,7 @@ function defaultSetupIo(input = process.stdin, output = process.stdout) {
|
|
|
17671
17673
|
}
|
|
17672
17674
|
};
|
|
17673
17675
|
const confirm2 = async (question, defaultYes = false) => {
|
|
17674
|
-
if (rich()) return
|
|
17676
|
+
if (rich()) return run3((context) => confirm({ ...context, message: displayText(question), initialValue: defaultYes }));
|
|
17675
17677
|
for (; ; ) {
|
|
17676
17678
|
const answer = (await ask(`${question} ${defaultYes ? "[Y/n]" : "[y/N]"}: `)).trim();
|
|
17677
17679
|
if (!answer) return defaultYes;
|
|
@@ -18627,8 +18629,8 @@ var init_new_bot_defaults = __esm({
|
|
|
18627
18629
|
}
|
|
18628
18630
|
}
|
|
18629
18631
|
if (value.type === "interval" && value.window) {
|
|
18630
|
-
const
|
|
18631
|
-
if (
|
|
18632
|
+
const minutes2 = (time3) => Number(time3.slice(0, 2)) * 60 + Number(time3.slice(3));
|
|
18633
|
+
if (minutes2(value.window.end) - minutes2(value.window.start) < value.everyMinutes) {
|
|
18632
18634
|
ctx.addIssue({ code: "custom", message: "The interval must fit inside its time window" });
|
|
18633
18635
|
}
|
|
18634
18636
|
}
|
|
@@ -19078,6 +19080,8 @@ function loadConfig() {
|
|
|
19078
19080
|
}
|
|
19079
19081
|
cfg.mistral = { ...cfg.mistral };
|
|
19080
19082
|
if (process.env.MISTRAL_API_KEY !== void 0) cfg.mistral.key = process.env.MISTRAL_API_KEY;
|
|
19083
|
+
cfg.cerebras = { ...cfg.cerebras };
|
|
19084
|
+
if (process.env.CEREBRAS_API_KEY !== void 0) cfg.cerebras.key = process.env.CEREBRAS_API_KEY;
|
|
19081
19085
|
cfg.xai = { ...cfg.xai };
|
|
19082
19086
|
if (process.env.XAI_API_KEY !== void 0) cfg.xai.key = process.env.XAI_API_KEY;
|
|
19083
19087
|
cfg.anthropic = { ...cfg.anthropic };
|
|
@@ -19138,7 +19142,7 @@ function saveConfig(patch, options = {}) {
|
|
|
19138
19142
|
const before = configSaveListeners.size ? structuredClone(disk) : disk;
|
|
19139
19143
|
const storedProfiles = storedBrowserProfilesSchema.safeParse(disk.browserProfiles);
|
|
19140
19144
|
if (storedProfiles.success) disk.browserProfiles = storedProfiles.data;
|
|
19141
|
-
for (const key of ["xai", "anthropic", "mistral", "openai", "openrouter", "openaiCompat", "composio", "box", "opencodeGo", "tts", "decider", "imageGen", "profile", "rooms", "threads", "context", "memory", "localVm", "features", "cloudOverflow", "budgets", "billing", "decisions", "onboarding", "browserEngine", "newBots"]) {
|
|
19145
|
+
for (const key of ["xai", "anthropic", "mistral", "cerebras", "openai", "openrouter", "openaiCompat", "composio", "box", "opencodeGo", "tts", "decider", "imageGen", "profile", "rooms", "threads", "context", "memory", "localVm", "features", "cloudOverflow", "budgets", "billing", "decisions", "onboarding", "browserEngine", "newBots"]) {
|
|
19142
19146
|
const section = checkedPatch[key];
|
|
19143
19147
|
if (!section) continue;
|
|
19144
19148
|
const current = jsonObjectSchema.safeParse(disk[key]);
|
|
@@ -19251,6 +19255,8 @@ function instanceOwnsRouting(cfg, entry, routingDefaults) {
|
|
|
19251
19255
|
return own(config2.key) || own(entry.environment?.OPENAI_COMPAT_API_KEY) || own(entry.environment?.[compatKeyEnv]) || own(config2.apiKeyEnv) && config2.apiKeyEnv !== compatKeyEnv || ownUrl(routingDefaults?.url || cfg.openaiCompat?.url || process.env.OPENAI_COMPAT_URL || "https://openrouter.ai/api/v1");
|
|
19252
19256
|
case "mistral":
|
|
19253
19257
|
return own(entry.environment?.MISTRAL_API_KEY) || ownUrl("https://api.mistral.ai/v1");
|
|
19258
|
+
case "cerebras":
|
|
19259
|
+
return own(entry.environment?.CEREBRAS_API_KEY) || ownUrl("https://api.cerebras.ai/v1");
|
|
19254
19260
|
case "grok":
|
|
19255
19261
|
return own(entry.environment?.XAI_API_KEY) || own(config2.apiKeyEnv) && config2.apiKeyEnv !== "XAI_API_KEY" || ownUrl("https://api.x.ai/v1", cfg.xai?.url);
|
|
19256
19262
|
default:
|
|
@@ -19260,6 +19266,7 @@ function instanceOwnsRouting(cfg, entry, routingDefaults) {
|
|
|
19260
19266
|
function injectedEnvironment(cfg, instanceId, driver) {
|
|
19261
19267
|
const environment = /* @__PURE__ */ new Map();
|
|
19262
19268
|
if (driver === "mistral" && cfg.mistral?.key) environment.set("MISTRAL_API_KEY", cfg.mistral.key);
|
|
19269
|
+
if (driver === "cerebras" && cfg.cerebras?.key) environment.set("CEREBRAS_API_KEY", cfg.cerebras.key);
|
|
19263
19270
|
if (driver === "grok" && cfg.xai?.key) environment.set("XAI_API_KEY", cfg.xai.key);
|
|
19264
19271
|
const anthropicHere = driver === "claudeAgent" && Boolean(cfg.anthropic?.key) && (cfg.anthropic?.everyClaudeBot === false ? instanceId === CLAUDE_API_INSTANCE : instanceId !== CLAUDE_API_INSTANCE);
|
|
19265
19272
|
if (anthropicHere) environment.set("ANTHROPIC_API_KEY", cfg.anthropic.key);
|
|
@@ -19292,6 +19299,7 @@ function instanceConfigs(cfg) {
|
|
|
19292
19299
|
computer: { driver: "boxAgent" },
|
|
19293
19300
|
openaiCompat: { driver: "openai-compat" },
|
|
19294
19301
|
mistral: { driver: "mistral" },
|
|
19302
|
+
cerebras: { driver: "cerebras" },
|
|
19295
19303
|
...API_KEY_FLEET,
|
|
19296
19304
|
qwen: { driver: "qwenAgent" },
|
|
19297
19305
|
hermes: { driver: "hermesAgent" },
|
|
@@ -19307,6 +19315,7 @@ function instanceConfigs(cfg) {
|
|
|
19307
19315
|
cursor: { driver: "cursorAgent" },
|
|
19308
19316
|
openaiCompat: { driver: "openai-compat" },
|
|
19309
19317
|
mistral: { driver: "mistral" },
|
|
19318
|
+
cerebras: { driver: "cerebras" },
|
|
19310
19319
|
...API_KEY_FLEET,
|
|
19311
19320
|
...CUSTOM_ONLY
|
|
19312
19321
|
};
|
|
@@ -19573,6 +19582,7 @@ var init_config = __esm({
|
|
|
19573
19582
|
phone: external_exports.enum(["ios", "android"]).optional()
|
|
19574
19583
|
}).optional(),
|
|
19575
19584
|
mistral: external_exports.object({ key: optionalText }).optional(),
|
|
19585
|
+
cerebras: external_exports.object({ key: optionalText }).optional(),
|
|
19576
19586
|
xai: external_exports.object({ key: optionalText, url: optionalText }).optional(),
|
|
19577
19587
|
/** Anthropic API key for Claude Code billed per token, handed only to
|
|
19578
19588
|
* Claude instances; `url` only for a proxy or a test double. Never a
|
|
@@ -19720,6 +19730,7 @@ var init_config = __esm({
|
|
|
19720
19730
|
WORKSPACE_CREDENTIAL_ENV = [
|
|
19721
19731
|
"XAI_API_KEY",
|
|
19722
19732
|
"MISTRAL_API_KEY",
|
|
19733
|
+
"CEREBRAS_API_KEY",
|
|
19723
19734
|
"OMB_ANTHROPIC_API_KEY",
|
|
19724
19735
|
"OMB_ANTHROPIC_API_URL",
|
|
19725
19736
|
"OMB_HOSTED_MODEL_TOKEN",
|
|
@@ -19763,6 +19774,7 @@ var init_config = __esm({
|
|
|
19763
19774
|
"OPENCODE_API_KEY",
|
|
19764
19775
|
"XAI_API_KEY",
|
|
19765
19776
|
"MISTRAL_API_KEY",
|
|
19777
|
+
"CEREBRAS_API_KEY",
|
|
19766
19778
|
"CURSOR_API_KEY",
|
|
19767
19779
|
"CURSOR_AUTH_TOKEN"
|
|
19768
19780
|
];
|
|
@@ -20241,6 +20253,8 @@ function windowsKnownDirs() {
|
|
|
20241
20253
|
// x.ai installer
|
|
20242
20254
|
join11(localAppData, "agy", "bin"),
|
|
20243
20255
|
// Antigravity installer
|
|
20256
|
+
// Cursor installer: cursor-agent.* and its `agent` copies (MOCA-272)
|
|
20257
|
+
join11(localAppData, "cursor-agent"),
|
|
20244
20258
|
join11(home, ".local", "bin"),
|
|
20245
20259
|
// claude native installer
|
|
20246
20260
|
join11(home, ".claude", "local"),
|
|
@@ -20248,7 +20262,9 @@ function windowsKnownDirs() {
|
|
|
20248
20262
|
// Factory droid installer (%USERPROFILE%\bin)
|
|
20249
20263
|
join11(home, ".bun", "bin"),
|
|
20250
20264
|
join11(home, ".deno", "bin"),
|
|
20251
|
-
join11(home, "go", "bin")
|
|
20265
|
+
join11(home, "go", "bin"),
|
|
20266
|
+
join11(process.env.ProgramFiles ?? "C:\\Program Files", "Docker", "Docker", "resources", "bin")
|
|
20267
|
+
// Docker Desktop installer
|
|
20252
20268
|
];
|
|
20253
20269
|
}
|
|
20254
20270
|
function registerPathDir(dir) {
|
|
@@ -20518,12 +20534,12 @@ function killCliTree(child, timeoutMs = 5e3) {
|
|
|
20518
20534
|
const pid = child.pid;
|
|
20519
20535
|
if (!pid) return Promise.resolve(true);
|
|
20520
20536
|
if (!Number.isInteger(pid) || pid <= 1 || pid === process.pid) return Promise.resolve(false);
|
|
20521
|
-
const
|
|
20522
|
-
stopping.set(child,
|
|
20523
|
-
void
|
|
20537
|
+
const run3 = stopCliTree(child, pid, Number.isFinite(timeoutMs) ? Math.max(0, timeoutMs) : 5e3);
|
|
20538
|
+
stopping.set(child, run3);
|
|
20539
|
+
void run3.then((stopped) => {
|
|
20524
20540
|
if (!stopped) stopping.delete(child);
|
|
20525
20541
|
});
|
|
20526
|
-
return
|
|
20542
|
+
return run3;
|
|
20527
20543
|
}
|
|
20528
20544
|
async function stopCliTree(child, pid, timeoutMs) {
|
|
20529
20545
|
const exited = () => child.exitCode !== null || child.signalCode !== null;
|
|
@@ -20636,9 +20652,9 @@ function installNpmEngine(pkg, options = {}) {
|
|
|
20636
20652
|
const key = `${options.baseDir ?? DATA_DIR} ${pkg}`;
|
|
20637
20653
|
const existing = running.get(key);
|
|
20638
20654
|
if (existing) return existing;
|
|
20639
|
-
const
|
|
20640
|
-
running.set(key,
|
|
20641
|
-
return
|
|
20655
|
+
const run3 = installOnce(pkg, options).finally(() => running.delete(key));
|
|
20656
|
+
running.set(key, run3);
|
|
20657
|
+
return run3;
|
|
20642
20658
|
}
|
|
20643
20659
|
async function installOnce(pkg, options) {
|
|
20644
20660
|
const prefix = enginesPrefix(options.baseDir);
|
|
@@ -21307,7 +21323,9 @@ function readPromptSplitReceipt(scope, key) {
|
|
|
21307
21323
|
return {
|
|
21308
21324
|
stable: record3.stable,
|
|
21309
21325
|
volatile: record3.volatile,
|
|
21310
|
-
...typeof record3.turnsSinceFull === "number" ? { turnsSinceFull: record3.turnsSinceFull } : {}
|
|
21326
|
+
...typeof record3.turnsSinceFull === "number" ? { turnsSinceFull: record3.turnsSinceFull } : {},
|
|
21327
|
+
...typeof record3.lastUsed === "number" && record3.lastUsed > 0 ? { lastUsed: record3.lastUsed } : {},
|
|
21328
|
+
...typeof record3.peakUsed === "number" && record3.peakUsed > 0 ? { peakUsed: record3.peakUsed } : {}
|
|
21311
21329
|
};
|
|
21312
21330
|
}
|
|
21313
21331
|
}
|
|
@@ -21349,6 +21367,205 @@ var init_prompt_split = __esm({
|
|
|
21349
21367
|
}
|
|
21350
21368
|
});
|
|
21351
21369
|
|
|
21370
|
+
// server/drivers/acp/quiet-status.ts
|
|
21371
|
+
import { execFile as execFile4 } from "node:child_process";
|
|
21372
|
+
import { closeSync as closeSync4, fstatSync, openSync as openSync4, readSync as readSync2 } from "node:fs";
|
|
21373
|
+
function parseQwenLogLine(line) {
|
|
21374
|
+
if (line.includes("[RETRY]") && /\bAttempt \d+ failed\b/.test(line)) {
|
|
21375
|
+
const attempt = /\bAttempt (\d+) failed/.exec(line);
|
|
21376
|
+
const status = /\bwith status (\d{3})\b/.exec(line);
|
|
21377
|
+
const explicit = /explicit delay of (\d+)\s*ms/.exec(line);
|
|
21378
|
+
const seconds = /Retrying in (\d+)\s*s\b/.exec(line);
|
|
21379
|
+
return {
|
|
21380
|
+
kind: "retry",
|
|
21381
|
+
attempt: attempt ? Number(attempt[1]) : null,
|
|
21382
|
+
status: status ? Number(status[1]) : null,
|
|
21383
|
+
delayMs: explicit ? Number(explicit[1]) : seconds ? Number(seconds[1]) * 1e3 : null
|
|
21384
|
+
};
|
|
21385
|
+
}
|
|
21386
|
+
if (/\[compaction\] hard-tier rescue triggered|Reactive compression|tryCompress/.test(line) && !/succeeded|failed|skipped|stopped/.test(line)) {
|
|
21387
|
+
return { kind: "compressing" };
|
|
21388
|
+
}
|
|
21389
|
+
const gate = /\[compaction\] cheap-gate NOOP: effectiveTokens=(\d+), auto=(\d+)/.exec(line);
|
|
21390
|
+
if (gate) return { kind: "context", tokens: Number(gate[1]), threshold: Number(gate[2]) };
|
|
21391
|
+
return null;
|
|
21392
|
+
}
|
|
21393
|
+
function psTimeMs(raw) {
|
|
21394
|
+
const m2 = /^(?:(\d+)-)?(?:(\d+):)?(\d+):(\d+(?:\.\d+)?)$/.exec(raw.trim());
|
|
21395
|
+
if (!m2) return null;
|
|
21396
|
+
const [, d, h2, min, s2] = m2;
|
|
21397
|
+
return ((Number(d ?? 0) * 24 + Number(h2 ?? 0)) * 60 + Number(min)) * 6e4 + Number(s2) * 1e3;
|
|
21398
|
+
}
|
|
21399
|
+
function treePids(rows, root) {
|
|
21400
|
+
const kids = /* @__PURE__ */ new Map();
|
|
21401
|
+
for (const r2 of rows) {
|
|
21402
|
+
const list = kids.get(r2.ppid);
|
|
21403
|
+
if (list) list.push(r2.pid);
|
|
21404
|
+
else kids.set(r2.ppid, [r2.pid]);
|
|
21405
|
+
}
|
|
21406
|
+
const out = [];
|
|
21407
|
+
const queue = [root];
|
|
21408
|
+
while (queue.length && out.length < 512) {
|
|
21409
|
+
const pid = queue.shift();
|
|
21410
|
+
if (out.includes(pid)) continue;
|
|
21411
|
+
out.push(pid);
|
|
21412
|
+
queue.push(...kids.get(pid) ?? []);
|
|
21413
|
+
}
|
|
21414
|
+
return out;
|
|
21415
|
+
}
|
|
21416
|
+
async function samplePosix(root) {
|
|
21417
|
+
const table2 = await run2("ps", ["-A", "-o", "pid=,ppid=,time="]);
|
|
21418
|
+
if (table2 === null) return { cpuMs: null, connections: null };
|
|
21419
|
+
const rows = [];
|
|
21420
|
+
for (const line of table2.split("\n")) {
|
|
21421
|
+
const [pid, ppid, time3] = line.trim().split(/\s+/);
|
|
21422
|
+
if (!pid || !ppid || !time3) continue;
|
|
21423
|
+
rows.push({ pid: Number(pid), ppid: Number(ppid), cpuMs: psTimeMs(time3) });
|
|
21424
|
+
}
|
|
21425
|
+
const pids = treePids(rows, root);
|
|
21426
|
+
if (!rows.some((r2) => r2.pid === root)) return { cpuMs: null, connections: null };
|
|
21427
|
+
let cpuMs = 0;
|
|
21428
|
+
for (const r2 of rows) if (pids.includes(r2.pid)) cpuMs += r2.cpuMs ?? 0;
|
|
21429
|
+
const lsof = await run2("lsof", ["-nP", "-a", "-p", pids.join(","), "-iTCP", "-sTCP:ESTABLISHED", "-Fn"]);
|
|
21430
|
+
const connections = lsof === null ? null : lsof.split("\n").filter((l) => l.startsWith("n")).length;
|
|
21431
|
+
return { cpuMs, connections };
|
|
21432
|
+
}
|
|
21433
|
+
async function sampleWindows(root) {
|
|
21434
|
+
const script = `$ErrorActionPreference='SilentlyContinue';$all=Get-CimInstance Win32_Process|Select-Object ProcessId,ParentProcessId,KernelModeTime,UserModeTime;$ids=@(${root});$q=@(${root});while($q.Count){$p=$q[0];$q=@($q|Select-Object -Skip 1);foreach($c in $all|Where-Object{$_.ParentProcessId -eq $p}){if($ids -notcontains $c.ProcessId){$ids+=$c.ProcessId;$q+=$c.ProcessId}}};$cpu=($all|Where-Object{$ids -contains $_.ProcessId}|ForEach-Object{[double]$_.KernelModeTime+[double]$_.UserModeTime}|Measure-Object -Sum).Sum/10000;$n=@(Get-NetTCPConnection -State Established|Where-Object{$ids -contains $_.OwningProcess}).Count;Write-Output "$cpu $n"`;
|
|
21435
|
+
const out = await run2("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", script], 8e3);
|
|
21436
|
+
const [cpu, n3] = (out ?? "").trim().split(/\s+/);
|
|
21437
|
+
const cpuMs = Number(cpu);
|
|
21438
|
+
const connections = Number(n3);
|
|
21439
|
+
return {
|
|
21440
|
+
cpuMs: cpu !== void 0 && Number.isFinite(cpuMs) ? cpuMs : null,
|
|
21441
|
+
connections: n3 !== void 0 && Number.isFinite(connections) ? connections : null
|
|
21442
|
+
};
|
|
21443
|
+
}
|
|
21444
|
+
function sampleProcessTree(pid) {
|
|
21445
|
+
return (process.platform === "win32" ? sampleWindows(pid) : samplePosix(pid)).catch(() => ({ cpuMs: null, connections: null }));
|
|
21446
|
+
}
|
|
21447
|
+
function classifyQuiet(input) {
|
|
21448
|
+
const { logged, sample, previous } = input;
|
|
21449
|
+
if (logged?.kind === "retry") return { kind: "retrying", status: logged.status, delayMs: logged.delayMs, attempt: logged.attempt };
|
|
21450
|
+
if (logged?.kind === "compressing") return { kind: "compressing" };
|
|
21451
|
+
const nearFullContext = input.context !== null && input.context.threshold > 0 && input.context.tokens >= input.context.threshold * 0.9;
|
|
21452
|
+
if (sample.connections !== null && sample.connections > 0) return { kind: "waiting-model", nearFullContext };
|
|
21453
|
+
const cpuDelta = sample.cpuMs !== null && previous?.cpuMs != null ? sample.cpuMs - previous.cpuMs : null;
|
|
21454
|
+
if (cpuDelta !== null && input.sinceMs > 0 && cpuDelta > BUSY_CPU_MS_PER_MIN * (input.sinceMs / 6e4)) return { kind: "busy" };
|
|
21455
|
+
if (sample.connections === 0 && cpuDelta !== null) return { kind: "no-signs" };
|
|
21456
|
+
return { kind: "unknown" };
|
|
21457
|
+
}
|
|
21458
|
+
function quietKey(state) {
|
|
21459
|
+
if (state.kind === "retrying") return `retrying:${state.attempt ?? "?"}:${state.status ?? "?"}`;
|
|
21460
|
+
if (state.kind === "waiting-model") return `waiting-model:${state.nearFullContext}`;
|
|
21461
|
+
return state.kind;
|
|
21462
|
+
}
|
|
21463
|
+
function describeQuiet(name, state, quietMs, stopAfterMs) {
|
|
21464
|
+
const quiet = minutes(quietMs);
|
|
21465
|
+
switch (state.kind) {
|
|
21466
|
+
case "retrying": {
|
|
21467
|
+
const why = state.status === 429 ? "hit a rate limit (HTTP 429)" : state.status !== null && state.status >= 500 ? `got a server error from its model provider (HTTP ${state.status})` : state.status !== null ? `got an error from its model provider (HTTP ${state.status})` : "had a failed model request";
|
|
21468
|
+
const next = state.delayMs !== null ? ` Next try in ${Math.max(1, Math.round(state.delayMs / 1e3))} s.` : "";
|
|
21469
|
+
const attempt = state.attempt !== null ? ` (attempt ${state.attempt + 1})` : "";
|
|
21470
|
+
return `${name} ${why} and is retrying${attempt}.${next} It is still working.`;
|
|
21471
|
+
}
|
|
21472
|
+
case "compressing":
|
|
21473
|
+
return `${name} is compressing its conversation history to make room. This can take a few minutes; it is still working.`;
|
|
21474
|
+
case "waiting-model":
|
|
21475
|
+
return state.nearFullContext ? `${name} is waiting on its model: no reply for ${quiet}, but its request is still open. Its history is nearly full, so it may be compressing it.` : `${name} is waiting on its model: no reply for ${quiet}, but its request is still open. Slow models and rate limits look like this.`;
|
|
21476
|
+
case "busy":
|
|
21477
|
+
return `${name} is busy on this computer but has sent nothing for ${quiet}.`;
|
|
21478
|
+
case "between-requests":
|
|
21479
|
+
return `${name} has sent nothing for ${quiet} and has no request open to its model right now. It may be waiting before a retry. Still waiting; press Stop to end the turn.`;
|
|
21480
|
+
case "no-signs":
|
|
21481
|
+
return `${name} has sent nothing for ${quiet}, has no open request to its model, and is not using the CPU. It may be stuck. Press Stop to end the turn; otherwise it is stopped after ${minutes(stopAfterMs)} of silence.`;
|
|
21482
|
+
case "unknown":
|
|
21483
|
+
return `${name} has sent nothing for ${quiet}. Still waiting; press Stop to end the turn.`;
|
|
21484
|
+
}
|
|
21485
|
+
}
|
|
21486
|
+
function lastSeenPhrase(state) {
|
|
21487
|
+
switch (state.kind) {
|
|
21488
|
+
case "retrying":
|
|
21489
|
+
return "retrying a failed model request";
|
|
21490
|
+
case "compressing":
|
|
21491
|
+
return "compressing its history";
|
|
21492
|
+
case "waiting-model":
|
|
21493
|
+
return "waiting on its model with a request open";
|
|
21494
|
+
case "busy":
|
|
21495
|
+
return "busy on this computer";
|
|
21496
|
+
case "between-requests":
|
|
21497
|
+
return "no request open to its model";
|
|
21498
|
+
case "no-signs":
|
|
21499
|
+
return "no open request and no CPU use";
|
|
21500
|
+
case "unknown":
|
|
21501
|
+
return "no readable process state";
|
|
21502
|
+
}
|
|
21503
|
+
}
|
|
21504
|
+
var LogTail, run2, BUSY_CPU_MS_PER_MIN, minutes;
|
|
21505
|
+
var init_quiet_status = __esm({
|
|
21506
|
+
"server/drivers/acp/quiet-status.ts"() {
|
|
21507
|
+
"use strict";
|
|
21508
|
+
LogTail = class {
|
|
21509
|
+
offset = null;
|
|
21510
|
+
partial = "";
|
|
21511
|
+
path;
|
|
21512
|
+
maxBytes;
|
|
21513
|
+
constructor(path3, maxBytes = 256 * 1024) {
|
|
21514
|
+
this.path = path3;
|
|
21515
|
+
this.maxBytes = maxBytes;
|
|
21516
|
+
}
|
|
21517
|
+
read() {
|
|
21518
|
+
let fd;
|
|
21519
|
+
try {
|
|
21520
|
+
fd = openSync4(this.path, "r");
|
|
21521
|
+
} catch {
|
|
21522
|
+
if (this.offset === null) this.offset = 0;
|
|
21523
|
+
return [];
|
|
21524
|
+
}
|
|
21525
|
+
try {
|
|
21526
|
+
const size = fstatSync(fd).size;
|
|
21527
|
+
if (this.offset === null) {
|
|
21528
|
+
this.offset = size;
|
|
21529
|
+
return [];
|
|
21530
|
+
}
|
|
21531
|
+
if (size < this.offset) {
|
|
21532
|
+
this.offset = 0;
|
|
21533
|
+
this.partial = "";
|
|
21534
|
+
}
|
|
21535
|
+
if (size === this.offset) return [];
|
|
21536
|
+
const start = Math.max(this.offset, size - this.maxBytes);
|
|
21537
|
+
if (start > this.offset) this.partial = "";
|
|
21538
|
+
const buf = Buffer.alloc(size - start);
|
|
21539
|
+
readSync2(fd, buf, 0, buf.length, start);
|
|
21540
|
+
this.offset = size;
|
|
21541
|
+
const text4 = this.partial + buf.toString("utf8");
|
|
21542
|
+
const lines = text4.split(/\r?\n/);
|
|
21543
|
+
this.partial = lines.pop() ?? "";
|
|
21544
|
+
return lines.filter((l) => l.trim());
|
|
21545
|
+
} catch {
|
|
21546
|
+
return [];
|
|
21547
|
+
} finally {
|
|
21548
|
+
try {
|
|
21549
|
+
closeSync4(fd);
|
|
21550
|
+
} catch {
|
|
21551
|
+
}
|
|
21552
|
+
}
|
|
21553
|
+
}
|
|
21554
|
+
};
|
|
21555
|
+
run2 = (file2, args, timeoutMs = 4e3) => new Promise((resolve14) => {
|
|
21556
|
+
execFile4(file2, args, { timeout: timeoutMs, maxBuffer: 4 * 1024 * 1024, windowsHide: true }, (err, stdout2) => {
|
|
21557
|
+
if (err && !(typeof stdout2 === "string" && err.code === 1)) resolve14(null);
|
|
21558
|
+
else resolve14(String(stdout2));
|
|
21559
|
+
});
|
|
21560
|
+
});
|
|
21561
|
+
BUSY_CPU_MS_PER_MIN = 3e3;
|
|
21562
|
+
minutes = (ms) => {
|
|
21563
|
+
if (ms < 9e4) return `${Math.max(1, Math.round(ms / 1e3))} s`;
|
|
21564
|
+
return `${Math.round(ms / 6e4)} min`;
|
|
21565
|
+
};
|
|
21566
|
+
}
|
|
21567
|
+
});
|
|
21568
|
+
|
|
21352
21569
|
// shared/approval-mode.ts
|
|
21353
21570
|
function supportsApprovalMode(driverKind, mode) {
|
|
21354
21571
|
if (mode === "custom") return driverKind === "codex";
|
|
@@ -21366,7 +21583,8 @@ function supportsApprovalMode(driverKind, mode) {
|
|
|
21366
21583
|
"openai-compat",
|
|
21367
21584
|
"grok",
|
|
21368
21585
|
"minimax",
|
|
21369
|
-
"mistral"
|
|
21586
|
+
"mistral",
|
|
21587
|
+
"cerebras"
|
|
21370
21588
|
].includes(driverKind ?? "");
|
|
21371
21589
|
}
|
|
21372
21590
|
var init_approval_mode = __esm({
|
|
@@ -21601,7 +21819,7 @@ var init_ask_question = __esm({
|
|
|
21601
21819
|
});
|
|
21602
21820
|
|
|
21603
21821
|
// server/thread-log-rotation.ts
|
|
21604
|
-
import { closeSync as
|
|
21822
|
+
import { closeSync as closeSync5, fstatSync as fstatSync2, openSync as openSync5, readSync as readSync3, renameSync as renameSync5, rmSync as rmSync5, statSync as statSync3, writeSync } from "node:fs";
|
|
21605
21823
|
function currentThreadLogCap() {
|
|
21606
21824
|
try {
|
|
21607
21825
|
return capProvider();
|
|
@@ -21623,20 +21841,20 @@ function capThreadLog(file2, maxBytes) {
|
|
|
21623
21841
|
function trimToTail(file2, keepBytes) {
|
|
21624
21842
|
const staging = `${file2}.trim`;
|
|
21625
21843
|
try {
|
|
21626
|
-
const source =
|
|
21844
|
+
const source = openSync5(file2, "r");
|
|
21627
21845
|
try {
|
|
21628
|
-
const size =
|
|
21846
|
+
const size = fstatSync2(source).size;
|
|
21629
21847
|
const start = Math.max(0, size - keepBytes);
|
|
21630
21848
|
const window = Buffer.allocUnsafe(size - start);
|
|
21631
21849
|
let filled = 0;
|
|
21632
21850
|
while (filled < window.length) {
|
|
21633
|
-
const count =
|
|
21851
|
+
const count = readSync3(source, window, filled, window.length - filled, start + filled);
|
|
21634
21852
|
if (count === 0) return;
|
|
21635
21853
|
filled += count;
|
|
21636
21854
|
}
|
|
21637
21855
|
const firstNewline = window.indexOf(10);
|
|
21638
21856
|
if (firstNewline === -1 || firstNewline + 1 >= window.length) return;
|
|
21639
|
-
const target =
|
|
21857
|
+
const target = openSync5(staging, "w", 384);
|
|
21640
21858
|
try {
|
|
21641
21859
|
let written = firstNewline + 1;
|
|
21642
21860
|
while (written < window.length) {
|
|
@@ -21645,10 +21863,10 @@ function trimToTail(file2, keepBytes) {
|
|
|
21645
21863
|
written += count;
|
|
21646
21864
|
}
|
|
21647
21865
|
} finally {
|
|
21648
|
-
|
|
21866
|
+
closeSync5(target);
|
|
21649
21867
|
}
|
|
21650
21868
|
} finally {
|
|
21651
|
-
|
|
21869
|
+
closeSync5(source);
|
|
21652
21870
|
}
|
|
21653
21871
|
renameSync5(staging, file2);
|
|
21654
21872
|
} catch {
|
|
@@ -22104,7 +22322,7 @@ function createAcpDriver(support11) {
|
|
|
22104
22322
|
}
|
|
22105
22323
|
const DRIVER_KIND8 = support11.driverKind;
|
|
22106
22324
|
const SOURCE = support11.nativeSource;
|
|
22107
|
-
const
|
|
22325
|
+
const decodeConfig9 = decodeAcpConfig(support11.defaultCli);
|
|
22108
22326
|
const DENY_TIMEOUT_NOTE3 = "OpenMausBot: nobody answered this permission request in time. Skip this action and finish what you can without it.";
|
|
22109
22327
|
return {
|
|
22110
22328
|
driverKind: DRIVER_KIND8,
|
|
@@ -22115,8 +22333,8 @@ function createAcpDriver(support11) {
|
|
|
22115
22333
|
},
|
|
22116
22334
|
install: support11.install,
|
|
22117
22335
|
models: support11.models,
|
|
22118
|
-
decodeConfig:
|
|
22119
|
-
defaultConfig: () =>
|
|
22336
|
+
decodeConfig: decodeConfig9,
|
|
22337
|
+
defaultConfig: () => decodeConfig9({}),
|
|
22120
22338
|
async create(input) {
|
|
22121
22339
|
const { instanceId, config: config2 } = input;
|
|
22122
22340
|
const childEnv = (activeConfig = config2) => {
|
|
@@ -22268,11 +22486,85 @@ function createAcpDriver(support11) {
|
|
|
22268
22486
|
}
|
|
22269
22487
|
return servers;
|
|
22270
22488
|
};
|
|
22489
|
+
const startQuietWatch = (threadId, session, current) => {
|
|
22490
|
+
const noticeAfterMs = envOr("OMB_ACP_QUIET_NOTICE_MS", 6e4);
|
|
22491
|
+
const tickMs = envOr("OMB_ACP_QUIET_TICK_MS", 15e3);
|
|
22492
|
+
const logPath = support11.statusLog && session.sessionId ? support11.statusLog.path(session.env, session.sessionId) : null;
|
|
22493
|
+
const tail2 = logPath ? new LogTail(logPath) : null;
|
|
22494
|
+
tail2?.read();
|
|
22495
|
+
let logged = null;
|
|
22496
|
+
let context = null;
|
|
22497
|
+
let previous = null;
|
|
22498
|
+
let previousAt = 0;
|
|
22499
|
+
let shownKey = null;
|
|
22500
|
+
let noSignsSince = null;
|
|
22501
|
+
let notices = 0;
|
|
22502
|
+
let probing = false;
|
|
22503
|
+
let state = null;
|
|
22504
|
+
const tick = async () => {
|
|
22505
|
+
if (probing || current.state.settled || session.current !== current) return;
|
|
22506
|
+
const now = Date.now();
|
|
22507
|
+
for (const line of tail2?.read() ?? []) {
|
|
22508
|
+
session.acp.touch();
|
|
22509
|
+
const signal = support11.statusLog.parse(line);
|
|
22510
|
+
if (signal?.kind === "context") context = { tokens: signal.tokens, threshold: signal.threshold };
|
|
22511
|
+
else if (signal) logged = { signal, at: now };
|
|
22512
|
+
}
|
|
22513
|
+
const quietMs = now - session.acp.lastInboundAt;
|
|
22514
|
+
if (quietMs < noticeAfterMs || current.asks.size || current.runningTools.size) {
|
|
22515
|
+
if (quietMs < noticeAfterMs) logged = null;
|
|
22516
|
+
previous = null;
|
|
22517
|
+
shownKey = null;
|
|
22518
|
+
noSignsSince = null;
|
|
22519
|
+
state = null;
|
|
22520
|
+
return;
|
|
22521
|
+
}
|
|
22522
|
+
if (logged?.signal.kind === "retry" && now - logged.at > (logged.signal.delayMs ?? 6e4) + 12e4) logged = null;
|
|
22523
|
+
probing = true;
|
|
22524
|
+
const sample = session.child.pid ? await sampleProcessTree(session.child.pid) : { cpuMs: null, connections: null };
|
|
22525
|
+
probing = false;
|
|
22526
|
+
if (current.state.settled || session.current !== current) return;
|
|
22527
|
+
let next = classifyQuiet({
|
|
22528
|
+
logged: logged?.signal ?? null,
|
|
22529
|
+
context,
|
|
22530
|
+
sample,
|
|
22531
|
+
previous,
|
|
22532
|
+
sinceMs: previous ? now - previousAt : 0
|
|
22533
|
+
});
|
|
22534
|
+
const first = previous === null;
|
|
22535
|
+
previous = sample;
|
|
22536
|
+
previousAt = now;
|
|
22537
|
+
if (first && next.kind === "unknown") return;
|
|
22538
|
+
if (next.kind === "no-signs") {
|
|
22539
|
+
noSignsSince ??= now;
|
|
22540
|
+
if (now - noSignsSince < envOr("OMB_ACP_STUCK_AFTER_MS", 18e4)) next = { kind: "between-requests" };
|
|
22541
|
+
} else {
|
|
22542
|
+
noSignsSince = null;
|
|
22543
|
+
}
|
|
22544
|
+
state = next;
|
|
22545
|
+
const key = quietKey(next);
|
|
22546
|
+
if (key === shownKey || notices >= 12) return;
|
|
22547
|
+
shownKey = key;
|
|
22548
|
+
notices += 1;
|
|
22549
|
+
emit({
|
|
22550
|
+
...base2(threadId, current.turnId),
|
|
22551
|
+
type: "runtime.notice",
|
|
22552
|
+
message: describeQuiet(support11.displayName, next, quietMs, promptIdleTimeoutMs())
|
|
22553
|
+
});
|
|
22554
|
+
};
|
|
22555
|
+
const timer = setInterval(() => {
|
|
22556
|
+
void tick();
|
|
22557
|
+
}, tickMs);
|
|
22558
|
+
timer.unref?.();
|
|
22559
|
+
current.stopQuietWatch = () => clearInterval(timer);
|
|
22560
|
+
return { lastState: () => state };
|
|
22561
|
+
};
|
|
22271
22562
|
const settle = (threadId, session, ok, stopReason) => {
|
|
22272
22563
|
const current = session.current;
|
|
22273
22564
|
if (!current || current.state.settled) return;
|
|
22274
22565
|
current.state.settled = true;
|
|
22275
22566
|
current.acknowledge();
|
|
22567
|
+
current.stopQuietWatch?.();
|
|
22276
22568
|
if (current.interruptTimer) clearTimeout(current.interruptTimer);
|
|
22277
22569
|
for (const finish of current.asks.values()) finish("cancel", "system");
|
|
22278
22570
|
session.acp.failAll(new Error("turn settled"));
|
|
@@ -22337,7 +22629,7 @@ function createAcpDriver(support11) {
|
|
|
22337
22629
|
return;
|
|
22338
22630
|
}
|
|
22339
22631
|
rpcPending.delete(id);
|
|
22340
|
-
const error51 = new Error(idleMessage ?? `${method} stopped responding`);
|
|
22632
|
+
const error51 = new Error((typeof idleMessage === "function" ? idleMessage() : idleMessage) ?? `${method} stopped responding`);
|
|
22341
22633
|
Object.assign(error51, { acpPromptStall: true });
|
|
22342
22634
|
reject(error51);
|
|
22343
22635
|
}, idleMs);
|
|
@@ -22361,9 +22653,16 @@ function createAcpDriver(support11) {
|
|
|
22361
22653
|
});
|
|
22362
22654
|
send({ jsonrpc: "2.0", id, method, params });
|
|
22363
22655
|
});
|
|
22656
|
+
let lastInboundAt = Date.now();
|
|
22364
22657
|
const acp = {
|
|
22365
22658
|
send,
|
|
22366
22659
|
request,
|
|
22660
|
+
get lastInboundAt() {
|
|
22661
|
+
return lastInboundAt;
|
|
22662
|
+
},
|
|
22663
|
+
touch: () => {
|
|
22664
|
+
for (const p2 of rpcPending.values()) p2.armIdle();
|
|
22665
|
+
},
|
|
22367
22666
|
failAll: (error51) => {
|
|
22368
22667
|
for (const p2 of rpcPending.values()) {
|
|
22369
22668
|
if (p2.timer) clearTimeout(p2.timer);
|
|
@@ -22615,12 +22914,23 @@ function createAcpDriver(support11) {
|
|
|
22615
22914
|
}
|
|
22616
22915
|
break;
|
|
22617
22916
|
}
|
|
22917
|
+
case "usage_update": {
|
|
22918
|
+
const used = u4.used ?? u4.usage?.used;
|
|
22919
|
+
if (typeof used !== "number" || !(used > 0)) break;
|
|
22920
|
+
if (current.state.usagePeak !== null && used < current.state.usagePeak * ACP_COMPACTION_COLLAPSE_RATIO) {
|
|
22921
|
+
current.state.usageCompacted = true;
|
|
22922
|
+
}
|
|
22923
|
+
if (current.state.usagePeak === null || used > current.state.usagePeak) current.state.usagePeak = used;
|
|
22924
|
+
current.state.usageLast = used;
|
|
22925
|
+
break;
|
|
22926
|
+
}
|
|
22618
22927
|
}
|
|
22619
22928
|
};
|
|
22620
22929
|
const session = {
|
|
22621
22930
|
child,
|
|
22622
22931
|
acp,
|
|
22623
22932
|
launch,
|
|
22933
|
+
env,
|
|
22624
22934
|
cwd,
|
|
22625
22935
|
contractKey,
|
|
22626
22936
|
sessionKey: null,
|
|
@@ -22650,6 +22960,7 @@ function createAcpDriver(support11) {
|
|
|
22650
22960
|
continue;
|
|
22651
22961
|
}
|
|
22652
22962
|
appendNative(threadId, { dir: "in", source: SOURCE, msg: nativeLogMessage(msg) });
|
|
22963
|
+
lastInboundAt = Date.now();
|
|
22653
22964
|
for (const p2 of rpcPending.values()) p2.armIdle();
|
|
22654
22965
|
if (msg.id !== void 0 && (msg.result !== void 0 || msg.error !== void 0)) {
|
|
22655
22966
|
const pend = rpcPending.get(msg.id);
|
|
@@ -22784,7 +23095,7 @@ function createAcpDriver(support11) {
|
|
|
22784
23095
|
sessions.set(threadId, session);
|
|
22785
23096
|
}
|
|
22786
23097
|
const request = (method, params, timeoutMs, receive, idleMs, idleMessage) => session.acp.request(method, params, timeoutMs, receive, idleMs, idleMessage);
|
|
22787
|
-
const state = { settled: false, promptSent: false, text: "", producedItem: false, startupActivity: false, stopped: false };
|
|
23098
|
+
const state = { settled: false, promptSent: false, text: "", producedItem: false, startupActivity: false, stopped: false, usagePeak: null, usageLast: null, usageCompacted: false };
|
|
22788
23099
|
let acknowledge = () => {
|
|
22789
23100
|
};
|
|
22790
23101
|
let rejectStartup = (_error) => {
|
|
@@ -22845,6 +23156,7 @@ function createAcpDriver(support11) {
|
|
|
22845
23156
|
asks,
|
|
22846
23157
|
runningTools: /* @__PURE__ */ new Set(),
|
|
22847
23158
|
interruptTimer: null,
|
|
23159
|
+
stopQuietWatch: null,
|
|
22848
23160
|
flushAssistantText,
|
|
22849
23161
|
receiveModelVariants
|
|
22850
23162
|
};
|
|
@@ -22869,6 +23181,7 @@ function createAcpDriver(support11) {
|
|
|
22869
23181
|
emit({ ...base2(threadId, turnId), type: "turn.started" });
|
|
22870
23182
|
session.current = current;
|
|
22871
23183
|
(async () => {
|
|
23184
|
+
let pendingSplitReceipt = null;
|
|
22872
23185
|
try {
|
|
22873
23186
|
const handshake = async () => {
|
|
22874
23187
|
for (const child of retiring.get(threadId) ?? []) {
|
|
@@ -23071,20 +23384,21 @@ ${fallback}` : null;
|
|
|
23071
23384
|
emitSessionStarted();
|
|
23072
23385
|
const halves = promptHalves(turn);
|
|
23073
23386
|
let promptInput = promptTurn;
|
|
23074
|
-
let pendingSplitReceipt = null;
|
|
23075
23387
|
if (halves.stable !== null) {
|
|
23076
23388
|
const receiptKey = JSON.stringify([threadId, sessionId]);
|
|
23389
|
+
const previousReceipt = readPromptSplitReceipt(DRIVER_KIND8, receiptKey);
|
|
23390
|
+
state.usagePeak = previousReceipt?.peakUsed ?? previousReceipt?.lastUsed ?? null;
|
|
23077
23391
|
const composed = splitSessionPrompt(
|
|
23078
23392
|
halves.stable,
|
|
23079
23393
|
halves.volatile,
|
|
23080
|
-
|
|
23394
|
+
previousReceipt,
|
|
23081
23395
|
promptTurn.system,
|
|
23082
23396
|
promptTurn.text,
|
|
23083
23397
|
Boolean(turn.mentionTurn),
|
|
23084
23398
|
ACP_PROMPT_RE_ANCHOR_TURNS
|
|
23085
23399
|
);
|
|
23086
23400
|
promptInput = { ...promptTurn, system: "", text: composed.text };
|
|
23087
|
-
pendingSplitReceipt = { key: receiptKey, receipt: composed.receipt };
|
|
23401
|
+
pendingSplitReceipt = { key: receiptKey, receipt: composed.receipt, previous: previousReceipt };
|
|
23088
23402
|
}
|
|
23089
23403
|
const text4 = support11.buildPromptText ? support11.buildPromptText(promptInput) : promptInput.system ? `${promptInput.system}
|
|
23090
23404
|
|
|
@@ -23100,16 +23414,34 @@ ${promptInput.text}` : promptInput.text;
|
|
|
23100
23414
|
state.promptSent = true;
|
|
23101
23415
|
acknowledge();
|
|
23102
23416
|
const promptIdleMs = promptIdleTimeoutMs();
|
|
23417
|
+
const quiet = startQuietWatch(threadId, session, current);
|
|
23103
23418
|
const result = await request(
|
|
23104
23419
|
"session/prompt",
|
|
23105
23420
|
{ sessionId, prompt: [{ type: "text", text: text4 }, ...imageBlocks] },
|
|
23106
23421
|
void 0,
|
|
23107
23422
|
void 0,
|
|
23108
23423
|
promptIdleMs,
|
|
23109
|
-
|
|
23424
|
+
() => {
|
|
23425
|
+
const last = quiet.lastState();
|
|
23426
|
+
return `${DRIVER_KIND8} sent nothing for ${formatQuietLimit(promptIdleMs)} with no tool running, so the turn was stopped as stuck${last ? ` (last seen: ${lastSeenPhrase(last)})` : ""}. Send the message again to retry. On a self-hosted server, OPENMAUS_ACP_PROMPT_IDLE_TIMEOUT_MS sets this limit (0 turns it off).`;
|
|
23427
|
+
}
|
|
23110
23428
|
);
|
|
23111
23429
|
if (pendingSplitReceipt) {
|
|
23112
|
-
|
|
23430
|
+
if (state.usageCompacted) {
|
|
23431
|
+
deletePromptSplitReceipt(DRIVER_KIND8, pendingSplitReceipt.key);
|
|
23432
|
+
} else {
|
|
23433
|
+
const previousLastUsed = typeof pendingSplitReceipt.previous?.lastUsed === "number" ? pendingSplitReceipt.previous.lastUsed : void 0;
|
|
23434
|
+
const lastUsed = state.usageLast ?? previousLastUsed;
|
|
23435
|
+
writePromptSplitReceipt(
|
|
23436
|
+
DRIVER_KIND8,
|
|
23437
|
+
pendingSplitReceipt.key,
|
|
23438
|
+
{
|
|
23439
|
+
...pendingSplitReceipt.receipt,
|
|
23440
|
+
...lastUsed === void 0 ? {} : { lastUsed },
|
|
23441
|
+
...state.usagePeak === null ? {} : { peakUsed: state.usagePeak }
|
|
23442
|
+
}
|
|
23443
|
+
);
|
|
23444
|
+
}
|
|
23113
23445
|
}
|
|
23114
23446
|
const usage = result?.usage ?? result?._meta ?? {};
|
|
23115
23447
|
if (typeof usage.inputTokens === "number" || typeof usage.outputTokens === "number") {
|
|
@@ -23138,6 +23470,9 @@ ${promptInput.text}` : promptInput.text;
|
|
|
23138
23470
|
settle(threadId, session, false, reason ?? "failed");
|
|
23139
23471
|
}
|
|
23140
23472
|
} catch (e) {
|
|
23473
|
+
if (pendingSplitReceipt && state.promptSent && state.usageCompacted) {
|
|
23474
|
+
deletePromptSplitReceipt(DRIVER_KIND8, pendingSplitReceipt.key);
|
|
23475
|
+
}
|
|
23141
23476
|
if (!state.settled) {
|
|
23142
23477
|
const message3 = e instanceof Error ? e.message : String(e);
|
|
23143
23478
|
const code = support11.classifyError?.(e);
|
|
@@ -23264,7 +23599,7 @@ ${promptInput.text}` : promptInput.text;
|
|
|
23264
23599
|
}
|
|
23265
23600
|
};
|
|
23266
23601
|
}
|
|
23267
|
-
var ACCOUNT_ERROR_CODES, isAccountError, envOr, INIT_TIMEOUT, SESSION_CONFIG_TIMEOUT, NEW_SESSION_TIMEOUT, LOAD_SESSION_TIMEOUT, ACP_PROMPT_RE_ANCHOR_TURNS, promptIdleTimeoutMs, CLIENT_FILE_MAX_BYTES, TOOL_LOG_TEXT_LIMIT;
|
|
23602
|
+
var ACCOUNT_ERROR_CODES, isAccountError, envOr, INIT_TIMEOUT, SESSION_CONFIG_TIMEOUT, NEW_SESSION_TIMEOUT, LOAD_SESSION_TIMEOUT, ACP_PROMPT_RE_ANCHOR_TURNS, ACP_COMPACTION_COLLAPSE_RATIO, DEFAULT_ACP_PROMPT_IDLE_MS, promptIdleTimeoutMs, formatQuietLimit, CLIENT_FILE_MAX_BYTES, TOOL_LOG_TEXT_LIMIT;
|
|
23268
23603
|
var init_core3 = __esm({
|
|
23269
23604
|
"server/drivers/acp/core.ts"() {
|
|
23270
23605
|
"use strict";
|
|
@@ -23272,6 +23607,7 @@ var init_core3 = __esm({
|
|
|
23272
23607
|
init_local_inject();
|
|
23273
23608
|
init_prompt_split();
|
|
23274
23609
|
init_procs();
|
|
23610
|
+
init_quiet_status();
|
|
23275
23611
|
init_contracts();
|
|
23276
23612
|
init_env_path();
|
|
23277
23613
|
init_approval_mode();
|
|
@@ -23297,12 +23633,15 @@ var init_core3 = __esm({
|
|
|
23297
23633
|
NEW_SESSION_TIMEOUT = envOr("OPENMAUS_ACP_NEW_SESSION_TIMEOUT_MS", 3e5);
|
|
23298
23634
|
LOAD_SESSION_TIMEOUT = envOr("OPENMAUS_ACP_LOAD_SESSION_TIMEOUT_MS", 12e4);
|
|
23299
23635
|
ACP_PROMPT_RE_ANCHOR_TURNS = 8;
|
|
23636
|
+
ACP_COMPACTION_COLLAPSE_RATIO = 0.6;
|
|
23637
|
+
DEFAULT_ACP_PROMPT_IDLE_MS = 15 * 6e4;
|
|
23300
23638
|
promptIdleTimeoutMs = () => {
|
|
23301
23639
|
const raw = process.env.OPENMAUS_ACP_PROMPT_IDLE_TIMEOUT_MS;
|
|
23302
|
-
if (raw === void 0) return
|
|
23640
|
+
if (raw === void 0) return DEFAULT_ACP_PROMPT_IDLE_MS;
|
|
23303
23641
|
const ms = Number(raw);
|
|
23304
23642
|
return Number.isFinite(ms) && ms > 0 ? ms : 0;
|
|
23305
23643
|
};
|
|
23644
|
+
formatQuietLimit = (ms) => ms >= 12e4 && ms % 6e4 === 0 ? `${ms / 6e4} min` : `${Math.round(ms / 1e3)} s`;
|
|
23306
23645
|
CLIENT_FILE_MAX_BYTES = 8 * 1024 * 1024;
|
|
23307
23646
|
TOOL_LOG_TEXT_LIMIT = 64e3;
|
|
23308
23647
|
}
|
|
@@ -24909,10 +25248,10 @@ var init_boatagent = __esm({
|
|
|
24909
25248
|
if (runPromptId) {
|
|
24910
25249
|
const status = await api2(`/boxes/${boxId}/prompts/${runPromptId}`).catch(() => null);
|
|
24911
25250
|
appendNative(threadId, { dir: "in", source: "box.prompt.status", msg: status });
|
|
24912
|
-
const
|
|
24913
|
-
const state = String(
|
|
25251
|
+
const run3 = status?.promptRun ?? status?.prompt ?? status ?? {};
|
|
25252
|
+
const state = String(run3?.status ?? "");
|
|
24914
25253
|
if (/completed|succeeded|done|finished/i.test(state)) {
|
|
24915
|
-
const result =
|
|
25254
|
+
const result = run3?.result ?? run3?.output ?? lastText;
|
|
24916
25255
|
if (typeof result === "string" && result.trim() && result !== lastText) {
|
|
24917
25256
|
ingest(result);
|
|
24918
25257
|
}
|
|
@@ -24923,7 +25262,7 @@ var init_boatagent = __esm({
|
|
|
24923
25262
|
return await finishRun(true, null);
|
|
24924
25263
|
}
|
|
24925
25264
|
if (/failed|error|cancelled|interrupted/i.test(state)) {
|
|
24926
|
-
const runError = [
|
|
25265
|
+
const runError = [run3?.error, run3?.failureReason, run3?.message].find((v2) => typeof v2 === "string" && v2.trim());
|
|
24927
25266
|
if (problem || runError || /failed|error/i.test(state)) throw new Error(problem ?? runError ?? `the box run ${state}`);
|
|
24928
25267
|
return await finishRun(false, state);
|
|
24929
25268
|
}
|
|
@@ -25427,9 +25766,9 @@ import { chmodSync as chmodSync4, mkdirSync as mkdirSync10, mkdtempSync as mkdte
|
|
|
25427
25766
|
import { createServer as createNetServer } from "node:net";
|
|
25428
25767
|
import { homedir as homedir9, tmpdir as tmpdir3 } from "node:os";
|
|
25429
25768
|
import { join as join22, dirname as dirname10, isAbsolute as isAbsolute5, normalize } from "node:path";
|
|
25430
|
-
function claudeAuthStatus(cli, env,
|
|
25769
|
+
function claudeAuthStatus(cli, env, run3 = execCli) {
|
|
25431
25770
|
return new Promise((resolve14) => {
|
|
25432
|
-
|
|
25771
|
+
run3(cli, ["auth", "status", "--json"], { timeout: 8e3, maxBuffer: 65536, env }, (_error, stdout2) => {
|
|
25433
25772
|
try {
|
|
25434
25773
|
const status = JSON.parse(stdout2);
|
|
25435
25774
|
if (!status || typeof status !== "object" || !("loggedIn" in status) || status.loggedIn !== true) {
|
|
@@ -26089,6 +26428,8 @@ var init_claude = __esm({
|
|
|
26089
26428
|
await refreshModels();
|
|
26090
26429
|
let cliVersion = null;
|
|
26091
26430
|
let cliVersionChecked = false;
|
|
26431
|
+
let cliHasAutocompact = null;
|
|
26432
|
+
let cliHelpVersion = null;
|
|
26092
26433
|
const readCliVersion = (env) => new Promise((resolve14) => {
|
|
26093
26434
|
execCli(
|
|
26094
26435
|
config2.cli,
|
|
@@ -26227,7 +26568,7 @@ var init_claude = __esm({
|
|
|
26227
26568
|
if (claudeCliSupports(cliVersion, "--setting-sources")) args.push("--setting-sources", "project");
|
|
26228
26569
|
}
|
|
26229
26570
|
const compactWindow = autoCompactWindow(turnEnvironment);
|
|
26230
|
-
if (compactWindow &&
|
|
26571
|
+
if (compactWindow && cliHasAutocompact === true) {
|
|
26231
26572
|
args.push("--autocompact", compactWindow);
|
|
26232
26573
|
}
|
|
26233
26574
|
if (turn.refreshSystemPrompt && cliVersionChecked && claudeCliSupports(cliVersion, "--system-prompt-snapshot")) {
|
|
@@ -26950,6 +27291,13 @@ var init_claude = __esm({
|
|
|
26950
27291
|
if (!version2) return { state: "unavailable", reason: `\`${config2.cli}\` CLI not found` };
|
|
26951
27292
|
cliVersion = parseClaudeCliVersion(version2);
|
|
26952
27293
|
cliVersionChecked = true;
|
|
27294
|
+
if (version2 !== cliHelpVersion) {
|
|
27295
|
+
const help = await new Promise((resolve14) => {
|
|
27296
|
+
execCli(config2.cli, ["--help"], { timeout: 8e3, env }, (err, stdout2) => resolve14(err ? null : stdout2));
|
|
27297
|
+
});
|
|
27298
|
+
cliHasAutocompact = help === null ? null : /^\s*--autocompact\b/m.test(help);
|
|
27299
|
+
cliHelpVersion = version2;
|
|
27300
|
+
}
|
|
26953
27301
|
const update = claudeCliUpdate(version2, config2.cli);
|
|
26954
27302
|
const warning = claudeInheritWarning(env);
|
|
26955
27303
|
if (config2.requireApiKey) {
|
|
@@ -27184,11 +27532,11 @@ var init_codex_mcp_names = __esm({
|
|
|
27184
27532
|
// server/environment.ts
|
|
27185
27533
|
import { randomUUID as randomUUID11 } from "node:crypto";
|
|
27186
27534
|
import {
|
|
27187
|
-
closeSync as
|
|
27535
|
+
closeSync as closeSync6,
|
|
27188
27536
|
fsyncSync as fsyncSync3,
|
|
27189
27537
|
linkSync as linkSync2,
|
|
27190
27538
|
mkdirSync as mkdirSync11,
|
|
27191
|
-
openSync as
|
|
27539
|
+
openSync as openSync6,
|
|
27192
27540
|
readFileSync as readFileSync10,
|
|
27193
27541
|
unlinkSync as unlinkSync4,
|
|
27194
27542
|
writeFileSync as writeFileSync6
|
|
@@ -27223,10 +27571,10 @@ function loadEnvironmentId(dataDir) {
|
|
|
27223
27571
|
const temporaryFile = join24(directory, `.environment-id.${process.pid}.${randomUUID11()}.tmp`);
|
|
27224
27572
|
let descriptor;
|
|
27225
27573
|
try {
|
|
27226
|
-
descriptor =
|
|
27574
|
+
descriptor = openSync6(temporaryFile, "wx", 384);
|
|
27227
27575
|
writeFileSync6(descriptor, id + "\n", "utf8");
|
|
27228
27576
|
fsyncSync3(descriptor);
|
|
27229
|
-
|
|
27577
|
+
closeSync6(descriptor);
|
|
27230
27578
|
descriptor = void 0;
|
|
27231
27579
|
try {
|
|
27232
27580
|
linkSync2(temporaryFile, file2);
|
|
@@ -27238,7 +27586,7 @@ function loadEnvironmentId(dataDir) {
|
|
|
27238
27586
|
throw new Error(`The environment identity at ${file2} disappeared while it was being created.`);
|
|
27239
27587
|
}
|
|
27240
27588
|
} finally {
|
|
27241
|
-
if (descriptor !== void 0)
|
|
27589
|
+
if (descriptor !== void 0) closeSync6(descriptor);
|
|
27242
27590
|
try {
|
|
27243
27591
|
unlinkSync4(temporaryFile);
|
|
27244
27592
|
} catch {
|
|
@@ -28234,7 +28582,7 @@ var init_webapi = __esm({
|
|
|
28234
28582
|
|
|
28235
28583
|
// server/drivers/chatgpt-plan-auth.ts
|
|
28236
28584
|
import { createHash as createHash9, randomBytes as randomBytes3, randomUUID as randomUUID12, timingSafeEqual } from "node:crypto";
|
|
28237
|
-
import { chmodSync as chmodSync5, closeSync as
|
|
28585
|
+
import { chmodSync as chmodSync5, closeSync as closeSync7, lstatSync as lstatSync2, mkdirSync as mkdirSync12, openSync as openSync7, readFileSync as readFileSync11, unlinkSync as unlinkSync5, writeFileSync as writeFileSync7 } from "node:fs";
|
|
28238
28586
|
import { createServer as createServer2 } from "node:http";
|
|
28239
28587
|
import { dirname as dirname12, isAbsolute as isAbsolute6, join as join25 } from "node:path";
|
|
28240
28588
|
import { setTimeout as delay } from "node:timers/promises";
|
|
@@ -28267,7 +28615,7 @@ async function locked(directory, operation) {
|
|
|
28267
28615
|
let fd;
|
|
28268
28616
|
for (; ; ) {
|
|
28269
28617
|
try {
|
|
28270
|
-
fd =
|
|
28618
|
+
fd = openSync7(path3, "wx", 384);
|
|
28271
28619
|
break;
|
|
28272
28620
|
} catch (error51) {
|
|
28273
28621
|
if (error51.code !== "EEXIST") throw new Error("ChatGPT credentials could not be locked safely.");
|
|
@@ -28279,7 +28627,7 @@ async function locked(directory, operation) {
|
|
|
28279
28627
|
writeFileSync7(fd, String(process.pid));
|
|
28280
28628
|
return await operation();
|
|
28281
28629
|
} finally {
|
|
28282
|
-
|
|
28630
|
+
closeSync7(fd);
|
|
28283
28631
|
unlinkSync5(path3);
|
|
28284
28632
|
}
|
|
28285
28633
|
}
|
|
@@ -39571,7 +39919,7 @@ var init_boat = __esm({
|
|
|
39571
39919
|
'for name in chrome google-chrome chromium chromium-browser; do pid=$(pgrep -o -x "$name" 2>/dev/null || true); [ -z "$pid" ] || kill -TERM "$pid" 2>/dev/null || true; done',
|
|
39572
39920
|
"for i in 1 2 3 4 5 6 7 8; do if ! pgrep -x chrome >/dev/null 2>&1 && ! pgrep -x google-chrome >/dev/null 2>&1 && ! pgrep -x chromium >/dev/null 2>&1 && ! pgrep -x chromium-browser >/dev/null 2>&1; then break; fi; sleep 0.25; done"
|
|
39573
39921
|
].join("; ");
|
|
39574
|
-
INCLUDED_BOAT_UNAVAILABLE = "
|
|
39922
|
+
INCLUDED_BOAT_UNAVAILABLE = "The cloud computers included with your Cloud plan aren't available right now. Try again later.";
|
|
39575
39923
|
PANEL_PATH = "/tmp/ogb-panel.jpg";
|
|
39576
39924
|
PANEL_FRAME_WIDTH = 1920;
|
|
39577
39925
|
PANEL_FRAME_QUALITY = 85;
|
|
@@ -39788,6 +40136,13 @@ function boundedText(value) {
|
|
|
39788
40136
|
return `${bytes.subarray(0, end).toString()}
|
|
39789
40137
|
[MCP result truncated at 50KB; request less output.]`;
|
|
39790
40138
|
}
|
|
40139
|
+
function omitBlankDefaults(builtInBrowser, tool2, args) {
|
|
40140
|
+
if (!builtInBrowser || !object3(args)) return;
|
|
40141
|
+
for (const field of BUILT_IN_BROWSER_BLANK_MEANS_OMITTED[tool2] ?? []) {
|
|
40142
|
+
const value = args[field];
|
|
40143
|
+
if (typeof value === "string" && !value.trim()) delete args[field];
|
|
40144
|
+
}
|
|
40145
|
+
}
|
|
39791
40146
|
async function mountChatTools(integrations, signal, computerUse = false) {
|
|
39792
40147
|
const servers = [];
|
|
39793
40148
|
if (computerUse && integrations?.computer) servers.push(["computer", integrations.computer]);
|
|
@@ -39824,11 +40179,11 @@ async function mountChatTools(integrations, signal, computerUse = false) {
|
|
|
39824
40179
|
if (signal.aborted || closed) throw aborted2();
|
|
39825
40180
|
const client = "boxId" in descriptor ? new ChatBoatClient(descriptor) : new ChatMcpClient(descriptor, computerUse);
|
|
39826
40181
|
clients.push(client);
|
|
39827
|
-
return { name, client, tools: await client.tools(signal) };
|
|
40182
|
+
return { name, client, builtInBrowser: descriptor === integrations?.browser, tools: await client.tools(signal) };
|
|
39828
40183
|
}));
|
|
39829
40184
|
for (const mount of mounts) {
|
|
39830
40185
|
if (mount.status === "rejected") throw mount.reason;
|
|
39831
|
-
const { name: server, client, tools } = mount.value;
|
|
40186
|
+
const { name: server, client, builtInBrowser, tools } = mount.value;
|
|
39832
40187
|
const originalNames = /* @__PURE__ */ new Set();
|
|
39833
40188
|
for (const tool2 of tools) {
|
|
39834
40189
|
if (!object3(tool2) || typeof tool2.name !== "string" || !tool2.name.trim() || originalNames.has(tool2.name)) throw new Error("MCP server advertised an invalid or duplicate tool name");
|
|
@@ -39854,7 +40209,7 @@ async function mountChatTools(integrations, signal, computerUse = false) {
|
|
|
39854
40209
|
const suffix = `_${index}`;
|
|
39855
40210
|
name = base2.slice(0, 64 - suffix.length) + suffix;
|
|
39856
40211
|
}
|
|
39857
|
-
registered.set(name, { client, name: tool2.name, schema: schema4 });
|
|
40212
|
+
registered.set(name, { client, builtInBrowser, name: tool2.name, schema: schema4 });
|
|
39858
40213
|
definitions.push({ type: "function", function: { name, description, parameters } });
|
|
39859
40214
|
if (Buffer.byteLength(JSON.stringify(definitions)) > CATALOG_BYTES) throw new Error("MCP tool catalog exceeds the 1MB limit");
|
|
39860
40215
|
}
|
|
@@ -39868,6 +40223,7 @@ async function mountChatTools(integrations, signal, computerUse = false) {
|
|
|
39868
40223
|
if (closed || signal.aborted) throw new ChatToolSessionError("MCP session closed");
|
|
39869
40224
|
const tool2 = registered.get(name);
|
|
39870
40225
|
if (!tool2) throw new Error("The requested tool was not advertised for this turn");
|
|
40226
|
+
omitBlankDefaults(tool2.builtInBrowser, tool2.name, args);
|
|
39871
40227
|
if (!object3(args) || !tool2.schema(args)) throw new Error("Tool arguments do not match the advertised input schema; use its required fields and types");
|
|
39872
40228
|
};
|
|
39873
40229
|
return {
|
|
@@ -39908,7 +40264,7 @@ async function mountChatTools(integrations, signal, computerUse = false) {
|
|
|
39908
40264
|
}
|
|
39909
40265
|
};
|
|
39910
40266
|
}
|
|
39911
|
-
var import_ajv, import__, import_ajv_formats, ChatToolSessionError, STARTUP_MS, CALL_MS, FRAME_BYTES, OUTPUT_BYTES, TOOL_COUNT, MAX_PAGES, SCHEMA_BYTES, CATALOG_BYTES, MAX_FRAMES, ChatMcpClient, validatorOptions;
|
|
40267
|
+
var import_ajv, import__, import_ajv_formats, ChatToolSessionError, STARTUP_MS, CALL_MS, FRAME_BYTES, OUTPUT_BYTES, TOOL_COUNT, MAX_PAGES, SCHEMA_BYTES, CATALOG_BYTES, MAX_FRAMES, ChatMcpClient, validatorOptions, BUILT_IN_BROWSER_BLANK_MEANS_OMITTED;
|
|
39912
40268
|
var init_chat_mcp_tools = __esm({
|
|
39913
40269
|
"server/drivers/chat-mcp-tools.ts"() {
|
|
39914
40270
|
"use strict";
|
|
@@ -40104,6 +40460,9 @@ var init_chat_mcp_tools = __esm({
|
|
|
40104
40460
|
strictTypes: false,
|
|
40105
40461
|
strictTuples: false
|
|
40106
40462
|
};
|
|
40463
|
+
BUILT_IN_BROWSER_BLANK_MEANS_OMITTED = {
|
|
40464
|
+
agent_browser_read: ["url"]
|
|
40465
|
+
};
|
|
40107
40466
|
}
|
|
40108
40467
|
});
|
|
40109
40468
|
|
|
@@ -40289,6 +40648,11 @@ function providerError(json2) {
|
|
|
40289
40648
|
}
|
|
40290
40649
|
return null;
|
|
40291
40650
|
}
|
|
40651
|
+
function announcesAction(text4) {
|
|
40652
|
+
const reply = text4.trim();
|
|
40653
|
+
if (!reply || reply.length > 400 || reply.includes("?")) return false;
|
|
40654
|
+
return /(?:[:\u2014\u2013]|\.\.\.|\u2026)$/.test(reply) || /^(?:checking|let me|i'll|i will|i'm going to|i am going to|opening|pulling|looking|searching|navigating|reading|fetching|loading|now (?:i'll|let me|opening|checking|pulling|reading))\b/i.test(reply);
|
|
40655
|
+
}
|
|
40292
40656
|
function rejectsToolsParameter(status, body) {
|
|
40293
40657
|
if (status !== 400 && status !== 422) return false;
|
|
40294
40658
|
let envelope;
|
|
@@ -40487,6 +40851,7 @@ function createOpenAIChatRuntime(options) {
|
|
|
40487
40851
|
if (idleTimer) clearTimeout(idleTimer);
|
|
40488
40852
|
}
|
|
40489
40853
|
};
|
|
40854
|
+
const seesImages = (turn) => options.imageInput?.(turn.model || options.models().default) ?? true;
|
|
40490
40855
|
const messagesFor = (turn) => {
|
|
40491
40856
|
const halves = promptHalves(turn);
|
|
40492
40857
|
const note = halves.stable !== null ? volatileContextNote(halves.volatile, false) : "";
|
|
@@ -40498,7 +40863,9 @@ function createOpenAIChatRuntime(options) {
|
|
|
40498
40863
|
role: message3.role,
|
|
40499
40864
|
content: message3.text
|
|
40500
40865
|
})),
|
|
40501
|
-
{ role: "user", content: options.computerUse ? chatUserContent(userTurn) : userTurn.text
|
|
40866
|
+
{ role: "user", content: !options.computerUse ? userTurn.text : seesImages(turn) ? chatUserContent(userTurn) : userTurn.images?.length ? `${userTurn.text}
|
|
40867
|
+
|
|
40868
|
+
${TEXT_ONLY_ATTACHMENT_NOTE}` : userTurn.text }
|
|
40502
40869
|
];
|
|
40503
40870
|
};
|
|
40504
40871
|
const sendTurn = async (turn) => {
|
|
@@ -40589,6 +40956,7 @@ function createOpenAIChatRuntime(options) {
|
|
|
40589
40956
|
let toolFailed = false;
|
|
40590
40957
|
const denials = [];
|
|
40591
40958
|
const seenCalls = /* @__PURE__ */ new Set();
|
|
40959
|
+
let nudged = false;
|
|
40592
40960
|
try {
|
|
40593
40961
|
tools = await mountChatTools(options.tools === false ? void 0 : turn.integrations, abort.signal, options.computerUse);
|
|
40594
40962
|
let optionalQuestionOnly = options.tools !== false && tools.definitions.length === 0;
|
|
@@ -40664,6 +41032,11 @@ function createOpenAIChatRuntime(options) {
|
|
|
40664
41032
|
if (completion.finishReason && completion.finishReason !== "stop") {
|
|
40665
41033
|
throw new ChatProtocolError(`provider did not finish the response (${completion.finishReason})`);
|
|
40666
41034
|
}
|
|
41035
|
+
if (options.nudgeAnnouncedAction && !nudged && tools.definitions.length && announcesAction(completion.text)) {
|
|
41036
|
+
nudged = true;
|
|
41037
|
+
messages.push({ role: "assistant", content: completion.text }, { role: "user", content: NUDGE_ANNOUNCED_ACTION });
|
|
41038
|
+
continue;
|
|
41039
|
+
}
|
|
40667
41040
|
if (toolFailed) {
|
|
40668
41041
|
stopReason = "tool_error";
|
|
40669
41042
|
throw new ChatProtocolError("One or more tool operations failed or were denied. See the tool results; the final response is not an execution receipt.");
|
|
@@ -40681,7 +41054,7 @@ function createOpenAIChatRuntime(options) {
|
|
|
40681
41054
|
role: "assistant",
|
|
40682
41055
|
content: completion.text || null,
|
|
40683
41056
|
tool_calls: completion.toolCalls,
|
|
40684
|
-
...completion.protocolReasoning && !reasoningReplayRejected.has(model) ? { reasoning_content: completion.protocolReasoning } : {},
|
|
41057
|
+
...completion.protocolReasoning && !reasoningReplayRejected.has(model) ? { [options.reasoningReplayField ?? "reasoning_content"]: completion.protocolReasoning } : {},
|
|
40685
41058
|
...completion.protocolReasoningDetails.length ? { reasoning_details: completion.protocolReasoningDetails } : {}
|
|
40686
41059
|
});
|
|
40687
41060
|
const screenshotParts = [];
|
|
@@ -40739,6 +41112,11 @@ function createOpenAIChatRuntime(options) {
|
|
|
40739
41112
|
started = true;
|
|
40740
41113
|
if (allowed) {
|
|
40741
41114
|
result = await tools.execute(call.function.name, args, abort.signal);
|
|
41115
|
+
if (result.images?.length && !seesImages(turn)) {
|
|
41116
|
+
const { images: _dropped, ...rest } = result;
|
|
41117
|
+
result = { ...rest, text: `${rest.text}
|
|
41118
|
+
${TEXT_ONLY_SCREENSHOT_NOTE}` };
|
|
41119
|
+
}
|
|
40742
41120
|
if (result.images?.length) {
|
|
40743
41121
|
try {
|
|
40744
41122
|
assertImageTransport(options.apiUrl);
|
|
@@ -40881,7 +41259,7 @@ function createOpenAIChatRuntime(options) {
|
|
|
40881
41259
|
}
|
|
40882
41260
|
};
|
|
40883
41261
|
}
|
|
40884
|
-
var usageFrom, asError, UnsupportedChatToolsError, UnsupportedReasoningReplayError;
|
|
41262
|
+
var usageFrom, asError, UnsupportedChatToolsError, NUDGE_ANNOUNCED_ACTION, TEXT_ONLY_ATTACHMENT_NOTE, TEXT_ONLY_SCREENSHOT_NOTE, UnsupportedReasoningReplayError;
|
|
40885
41263
|
var init_openai_chat = __esm({
|
|
40886
41264
|
"server/drivers/openai-chat.ts"() {
|
|
40887
41265
|
"use strict";
|
|
@@ -40900,6 +41278,9 @@ var init_openai_chat = __esm({
|
|
|
40900
41278
|
asError = (value) => value instanceof Error ? value : new Error(String(value));
|
|
40901
41279
|
UnsupportedChatToolsError = class extends Error {
|
|
40902
41280
|
};
|
|
41281
|
+
NUDGE_ANNOUNCED_ACTION = "You said what you would do next but called no tool. Do it now with your tools, or reply with your final answer if nothing is left to do.";
|
|
41282
|
+
TEXT_ONLY_ATTACHMENT_NOTE = "[The person attached image(s), but this model cannot see images. Say so if the request depends on them.]";
|
|
41283
|
+
TEXT_ONLY_SCREENSHOT_NOTE = "[Screenshot not shown: this model cannot see images. Read the page with a snapshot or a text tool instead.]";
|
|
40903
41284
|
UnsupportedReasoningReplayError = class extends Error {
|
|
40904
41285
|
};
|
|
40905
41286
|
}
|
|
@@ -41934,8 +42315,15 @@ function resolveCursorAcpModelId(available, wanted) {
|
|
|
41934
42315
|
const base2 = (id) => id.split("[")[0].trim().toLowerCase();
|
|
41935
42316
|
const exact = ids.find((m2) => m2.modelId.toLowerCase() === want);
|
|
41936
42317
|
if (exact) return exact.modelId;
|
|
41937
|
-
const
|
|
42318
|
+
const isFast = (id) => /[[,]\s*fast\s*=\s*true\s*[\],]/i.test(id);
|
|
42319
|
+
const sameBase = ids.filter((m2) => base2(m2.modelId) === want);
|
|
42320
|
+
const byBase = sameBase.find((m2) => !isFast(m2.modelId)) ?? sameBase[0];
|
|
41938
42321
|
if (byBase) return byBase.modelId;
|
|
42322
|
+
if (want.endsWith("-fast")) {
|
|
42323
|
+
const stem = want.slice(0, -"-fast".length);
|
|
42324
|
+
const fast = ids.find((m2) => base2(m2.modelId) === stem && isFast(m2.modelId));
|
|
42325
|
+
if (fast) return fast.modelId;
|
|
42326
|
+
}
|
|
41939
42327
|
const byName = ids.find((m2) => (m2.name ?? "").trim().toLowerCase() === want);
|
|
41940
42328
|
if (byName) return byName.modelId;
|
|
41941
42329
|
if (want === "auto" || want === "default") {
|
|
@@ -42084,27 +42472,27 @@ function decodeCursorAuthText(text4) {
|
|
|
42084
42472
|
if (/login successful|logged in|signed in|authenticated/.test(normalized)) return true;
|
|
42085
42473
|
return null;
|
|
42086
42474
|
}
|
|
42087
|
-
function execText(
|
|
42475
|
+
function execText(run3, cli, args, env) {
|
|
42088
42476
|
return new Promise((resolve14) => {
|
|
42089
|
-
|
|
42477
|
+
run3(cli, args, { timeout: EXEC_TIMEOUT_MS, env }, (err, stdout2) => {
|
|
42090
42478
|
if (err) return resolve14(null);
|
|
42091
42479
|
resolve14(String(stdout2 ?? ""));
|
|
42092
42480
|
});
|
|
42093
42481
|
});
|
|
42094
42482
|
}
|
|
42095
|
-
async function probeCursorAuth(cli, env,
|
|
42483
|
+
async function probeCursorAuth(cli, env, run3 = execCli) {
|
|
42096
42484
|
if (nonBlank2(env.CURSOR_API_KEY) || nonBlank2(env.CURSOR_AUTH_TOKEN)) return true;
|
|
42097
42485
|
for (const args of [["status", "--format", "json"], ["status"]]) {
|
|
42098
|
-
const stdout2 = await execText(
|
|
42486
|
+
const stdout2 = await execText(run3, cli, [...args], env);
|
|
42099
42487
|
if (stdout2 == null) continue;
|
|
42100
42488
|
const decoded = decodeCursorAuthStatus(firstJsonValue(stdout2)) ?? decodeCursorAuthText(stdout2);
|
|
42101
42489
|
if (decoded !== null) return decoded;
|
|
42102
42490
|
}
|
|
42103
42491
|
return false;
|
|
42104
42492
|
}
|
|
42105
|
-
async function fetchCursorModels(cli, env,
|
|
42493
|
+
async function fetchCursorModels(cli, env, run3 = execCli) {
|
|
42106
42494
|
for (const args of [["models"], ["--list-models"]]) {
|
|
42107
|
-
const stdout2 = await execText(
|
|
42495
|
+
const stdout2 = await execText(run3, cli, [...args], env);
|
|
42108
42496
|
if (stdout2 == null) continue;
|
|
42109
42497
|
const fromText = decodeCursorModelText(stdout2);
|
|
42110
42498
|
if (fromText) return fromText;
|
|
@@ -42127,8 +42515,8 @@ function classifyCursorError(error51) {
|
|
|
42127
42515
|
}
|
|
42128
42516
|
return void 0;
|
|
42129
42517
|
}
|
|
42130
|
-
function createCursorAgentDriver(
|
|
42131
|
-
return createAcpDriver(support6(
|
|
42518
|
+
function createCursorAgentDriver(run3 = execCli) {
|
|
42519
|
+
return createAcpDriver(support6(run3));
|
|
42132
42520
|
}
|
|
42133
42521
|
var STATIC_CURSOR_MODELS, SLUG3, EXEC_TIMEOUT_MS, nonBlank2, support6, CursorAgentDriver;
|
|
42134
42522
|
var init_cursor = __esm({
|
|
@@ -42150,7 +42538,7 @@ var init_cursor = __esm({
|
|
|
42150
42538
|
SLUG3 = /^[a-z0-9][a-z0-9._:+-]*$/i;
|
|
42151
42539
|
EXEC_TIMEOUT_MS = 8e3;
|
|
42152
42540
|
nonBlank2 = (value) => Boolean(value?.trim());
|
|
42153
|
-
support6 = (
|
|
42541
|
+
support6 = (run3) => ({
|
|
42154
42542
|
driverKind: "cursorAgent",
|
|
42155
42543
|
displayName: "Cursor",
|
|
42156
42544
|
models: STATIC_CURSOR_MODELS,
|
|
@@ -42177,13 +42565,13 @@ var init_cursor = __esm({
|
|
|
42177
42565
|
"acp"
|
|
42178
42566
|
],
|
|
42179
42567
|
credentialEnv: ["CURSOR_API_KEY", "CURSOR_AUTH_TOKEN"],
|
|
42180
|
-
resolveModels: (environment, config2) => fetchCursorModels(config2.cli || "cursor-agent", environment,
|
|
42568
|
+
resolveModels: (environment, config2) => fetchCursorModels(config2.cli || "cursor-agent", environment, run3),
|
|
42181
42569
|
// Prefer the advertised ACP method. An already-signed-in CLI should accept
|
|
42182
42570
|
// cursor_login without a browser; a missing method rides the ambient login
|
|
42183
42571
|
// (CURSOR_API_KEY / `cursor-agent login`) instead of failing the turn.
|
|
42184
42572
|
pickAuthMethod: (methods) => methods.some((m2) => m2.id === "cursor_login") ? "cursor_login" : null,
|
|
42185
42573
|
authFailure: "continue",
|
|
42186
|
-
isAuthenticated: (env, config2) => probeCursorAuth(config2.cli || "cursor-agent", env,
|
|
42574
|
+
isAuthenticated: (env, config2) => probeCursorAuth(config2.cli || "cursor-agent", env, run3),
|
|
42187
42575
|
classifyError: classifyCursorError,
|
|
42188
42576
|
async configureSession({ request, sessionId, turn, sessionModels }) {
|
|
42189
42577
|
if (!turn.model) return;
|
|
@@ -42266,7 +42654,7 @@ var init_attachments = __esm({
|
|
|
42266
42654
|
});
|
|
42267
42655
|
|
|
42268
42656
|
// server/drivers/acp/opencode-go.ts
|
|
42269
|
-
import { execFile as
|
|
42657
|
+
import { execFile as execFile5 } from "node:child_process";
|
|
42270
42658
|
import { existsSync as existsSync15, mkdirSync as mkdirSync19, readFileSync as readFileSync21, statSync as statSync5, writeFileSync as writeFileSync13 } from "node:fs";
|
|
42271
42659
|
import { homedir as homedir16 } from "node:os";
|
|
42272
42660
|
import { dirname as dirname14, isAbsolute as isAbsolute9, join as join38, relative as relative2, resolve as resolvePath, sep } from "node:path";
|
|
@@ -42411,7 +42799,7 @@ function runOpenCodeModelsVerbose(cli, environment) {
|
|
|
42411
42799
|
function runGit(directory, args) {
|
|
42412
42800
|
const env = Object.fromEntries(Object.entries(process.env).filter(([key]) => !key.startsWith("GIT_")));
|
|
42413
42801
|
return new Promise((resolveRun, rejectRun) => {
|
|
42414
|
-
|
|
42802
|
+
execFile5("git", [
|
|
42415
42803
|
"-c",
|
|
42416
42804
|
"user.name=OpenMaus",
|
|
42417
42805
|
"-c",
|
|
@@ -43094,6 +43482,12 @@ function resolveQwenTurnModel(model, env) {
|
|
|
43094
43482
|
if (!matches.length) throw new Error("This Qwen model is no longer configured. Refresh models and select it again.");
|
|
43095
43483
|
return matches[0].id;
|
|
43096
43484
|
}
|
|
43485
|
+
function qwenDebugLogPath(env, sessionId) {
|
|
43486
|
+
const off = ["", "0", "false", "off", "no"].includes((env.QWEN_DEBUG_LOG_FILE ?? "").trim().toLowerCase());
|
|
43487
|
+
if (off || !/^[\w-]{1,128}$/.test(sessionId)) return null;
|
|
43488
|
+
const base2 = env.QWEN_RUNTIME_DIR || env.QWEN_HOME || harnessHome("qwen", env);
|
|
43489
|
+
return join39(base2, "debug", `${sessionId}.txt`);
|
|
43490
|
+
}
|
|
43097
43491
|
function qwenApprovalArgs(fullAuto, approvalMode) {
|
|
43098
43492
|
if (fullAuto) return ["--yolo"];
|
|
43099
43493
|
if (approvalMode === "auto") return ["--approval-mode", "auto"];
|
|
@@ -43106,6 +43500,7 @@ var init_qwen = __esm({
|
|
|
43106
43500
|
"use strict";
|
|
43107
43501
|
init_contracts();
|
|
43108
43502
|
init_env_path();
|
|
43503
|
+
init_quiet_status();
|
|
43109
43504
|
init_local_inject();
|
|
43110
43505
|
init_core3();
|
|
43111
43506
|
EMPTY = { default: "", options: [] };
|
|
@@ -43140,7 +43535,14 @@ var init_qwen = __esm({
|
|
|
43140
43535
|
isAuthenticated: () => true,
|
|
43141
43536
|
buildPromptText: (turn) => turn.system ? `${turn.system}
|
|
43142
43537
|
|
|
43143
|
-
${turn.text}` : turn.text
|
|
43538
|
+
${turn.text}` : turn.text,
|
|
43539
|
+
// Qwen says nothing over ACP while it retries a rate limit or compresses
|
|
43540
|
+
// its history, but its debug log does. Turn the log on (unless the person
|
|
43541
|
+
// turned it off) and read it while a prompt is quiet.
|
|
43542
|
+
transformEnv: (env) => {
|
|
43543
|
+
if (env.QWEN_DEBUG_LOG_FILE === void 0) env.QWEN_DEBUG_LOG_FILE = "1";
|
|
43544
|
+
},
|
|
43545
|
+
statusLog: { path: qwenDebugLogPath, parse: parseQwenLogLine }
|
|
43144
43546
|
};
|
|
43145
43547
|
QwenAgentDriver = createAcpDriver(support8);
|
|
43146
43548
|
}
|
|
@@ -51506,6 +51908,120 @@ var init_mistral = __esm({
|
|
|
51506
51908
|
}
|
|
51507
51909
|
});
|
|
51508
51910
|
|
|
51911
|
+
// server/drivers/cerebras.ts
|
|
51912
|
+
function decodeConfig8(raw) {
|
|
51913
|
+
const config2 = configSchema2.parse(raw ?? {});
|
|
51914
|
+
config2.url = config2.url.replace(/\/+$/, "");
|
|
51915
|
+
const url2 = new URL(config2.url);
|
|
51916
|
+
if (url2.protocol !== "https:" && !(url2.protocol === "http:" && ["localhost", "127.0.0.1", "[::1]"].includes(url2.hostname))) {
|
|
51917
|
+
throw new Error("Cerebras requires HTTPS, except for a local test endpoint.");
|
|
51918
|
+
}
|
|
51919
|
+
return config2;
|
|
51920
|
+
}
|
|
51921
|
+
var DEFAULT_URL3, DEFAULT_MODELS3, configSchema2, modelCard2, TEXT_ONLY_MODELS, CerebrasDriver;
|
|
51922
|
+
var init_cerebras = __esm({
|
|
51923
|
+
"server/drivers/cerebras.ts"() {
|
|
51924
|
+
"use strict";
|
|
51925
|
+
init_zod();
|
|
51926
|
+
init_openai_chat();
|
|
51927
|
+
DEFAULT_URL3 = "https://api.cerebras.ai/v1";
|
|
51928
|
+
DEFAULT_MODELS3 = {
|
|
51929
|
+
default: "gpt-oss-120b",
|
|
51930
|
+
options: [
|
|
51931
|
+
{ id: "gpt-oss-120b", label: "GPT OSS 120B", contextWindow: 65536 },
|
|
51932
|
+
{ id: "qwen-3.8-27b", label: "Qwen3.8 27B", contextWindow: 65536 }
|
|
51933
|
+
]
|
|
51934
|
+
};
|
|
51935
|
+
configSchema2 = external_exports.object({
|
|
51936
|
+
url: external_exports.string().trim().url().default(DEFAULT_URL3),
|
|
51937
|
+
model: external_exports.string().trim().min(1).optional(),
|
|
51938
|
+
tools: external_exports.boolean().optional()
|
|
51939
|
+
});
|
|
51940
|
+
modelCard2 = external_exports.object({ id: external_exports.string().min(1) });
|
|
51941
|
+
TEXT_ONLY_MODELS = /^(?:gpt-oss|llama3\.1-8b|llama-3\.3-70b)/i;
|
|
51942
|
+
CerebrasDriver = {
|
|
51943
|
+
driverKind: "cerebras",
|
|
51944
|
+
metadata: { displayName: "Cerebras (API)", supportsMultipleInstances: true, access: "api" },
|
|
51945
|
+
models: DEFAULT_MODELS3,
|
|
51946
|
+
install: {
|
|
51947
|
+
docsUrl: "https://cloud.cerebras.ai/",
|
|
51948
|
+
settings: "connections",
|
|
51949
|
+
signInCommand: "Save a Cerebras API key in Settings \u2192 Connections, or set CEREBRAS_API_KEY on the server."
|
|
51950
|
+
},
|
|
51951
|
+
decodeConfig: decodeConfig8,
|
|
51952
|
+
defaultConfig: () => decodeConfig8({}),
|
|
51953
|
+
async create(input) {
|
|
51954
|
+
const { config: config2 } = input;
|
|
51955
|
+
const apiKey = (input.environment.CEREBRAS_API_KEY ?? process.env.CEREBRAS_API_KEY ?? "").trim();
|
|
51956
|
+
const known = new Map(DEFAULT_MODELS3.options.map((option) => [option.id, option]));
|
|
51957
|
+
const withConfiguredModel = (options) => {
|
|
51958
|
+
const preferred = config2.model ?? DEFAULT_MODELS3.default;
|
|
51959
|
+
if (config2.model && !options.some((option) => option.id === config2.model)) {
|
|
51960
|
+
options = [{ id: config2.model, label: config2.model }, ...options];
|
|
51961
|
+
}
|
|
51962
|
+
return { default: options.some((option) => option.id === preferred) ? preferred : options[0].id, options };
|
|
51963
|
+
};
|
|
51964
|
+
let catalog2 = withConfiguredModel(DEFAULT_MODELS3.options);
|
|
51965
|
+
const refreshModels = async () => {
|
|
51966
|
+
if (!apiKey) return;
|
|
51967
|
+
try {
|
|
51968
|
+
const response = await fetch(`${config2.url}/models`, {
|
|
51969
|
+
headers: { authorization: `Bearer ${apiKey}` },
|
|
51970
|
+
redirect: "error",
|
|
51971
|
+
signal: AbortSignal.timeout(8e3)
|
|
51972
|
+
});
|
|
51973
|
+
if (!response.ok) return;
|
|
51974
|
+
const json2 = await response.json();
|
|
51975
|
+
const rows = Array.isArray(json2) ? json2 : external_exports.object({ data: external_exports.array(external_exports.unknown()) }).parse(json2).data;
|
|
51976
|
+
const options = [];
|
|
51977
|
+
const seen = /* @__PURE__ */ new Set();
|
|
51978
|
+
for (const row of rows) {
|
|
51979
|
+
const parsed = modelCard2.safeParse(row);
|
|
51980
|
+
if (!parsed.success || !parsed.data.id.trim() || seen.has(parsed.data.id)) continue;
|
|
51981
|
+
seen.add(parsed.data.id);
|
|
51982
|
+
options.push(known.get(parsed.data.id) ?? { id: parsed.data.id, label: parsed.data.id });
|
|
51983
|
+
}
|
|
51984
|
+
if (options.length) catalog2 = withConfiguredModel(options);
|
|
51985
|
+
} catch {
|
|
51986
|
+
}
|
|
51987
|
+
};
|
|
51988
|
+
if (apiKey) void refreshModels();
|
|
51989
|
+
return createOpenAIChatRuntime({
|
|
51990
|
+
input,
|
|
51991
|
+
driverKind: "cerebras",
|
|
51992
|
+
apiKey,
|
|
51993
|
+
apiUrl: config2.url,
|
|
51994
|
+
tools: config2.tools,
|
|
51995
|
+
models: () => catalog2,
|
|
51996
|
+
refreshModels,
|
|
51997
|
+
reasoning: true,
|
|
51998
|
+
reasoningReplayField: "reasoning",
|
|
51999
|
+
computerUse: true,
|
|
52000
|
+
imageInput: (model) => !TEXT_ONLY_MODELS.test(model),
|
|
52001
|
+
nudgeAnnouncedAction: true,
|
|
52002
|
+
requestBody: (model, messages, stream) => ({
|
|
52003
|
+
model,
|
|
52004
|
+
messages,
|
|
52005
|
+
stream,
|
|
52006
|
+
...stream ? { stream_options: { include_usage: true } } : {}
|
|
52007
|
+
}),
|
|
52008
|
+
httpErrorLabel: "Cerebras",
|
|
52009
|
+
missingKeyError: "Save a Cerebras API key in Settings \u2192 Connections, or set CEREBRAS_API_KEY.",
|
|
52010
|
+
unavailableReason: "No Cerebras API key \u2014 open Settings \u2192 Connections.",
|
|
52011
|
+
timeoutMs: 18e4,
|
|
52012
|
+
billing: "metered",
|
|
52013
|
+
includeUsageInCompleted: true,
|
|
52014
|
+
nativeLog: {
|
|
52015
|
+
source: "cerebras.chat.completions",
|
|
52016
|
+
outgoing: (_turn, messages, model) => ({ model, messageCount: messages.length }),
|
|
52017
|
+
incoming: ({ text: text4, reasoning, usage }) => ({ textLength: text4.length, reasoningLength: reasoning.length, usage })
|
|
52018
|
+
}
|
|
52019
|
+
});
|
|
52020
|
+
}
|
|
52021
|
+
};
|
|
52022
|
+
}
|
|
52023
|
+
});
|
|
52024
|
+
|
|
51509
52025
|
// server/drivers/minimax.ts
|
|
51510
52026
|
import { readFileSync as readFileSync25 } from "node:fs";
|
|
51511
52027
|
import { homedir as homedir19 } from "node:os";
|
|
@@ -51517,14 +52033,14 @@ function normalizedApiUrl(value) {
|
|
|
51517
52033
|
function loadLocalMiniMaxConfig(home = homedir19()) {
|
|
51518
52034
|
try {
|
|
51519
52035
|
const raw = localConfigSchema.parse(JSON.parse(readFileSync25(join42(home, ".mmx", "config.json"), "utf8")));
|
|
51520
|
-
const configuredUrl = raw.base_url?.trim() ? raw.base_url : raw.region === "cn" ? CN_URL :
|
|
52036
|
+
const configuredUrl = raw.base_url?.trim() ? raw.base_url : raw.region === "cn" ? CN_URL : DEFAULT_URL4;
|
|
51521
52037
|
return {
|
|
51522
52038
|
apiKey: raw.api_key?.trim() ?? "",
|
|
51523
52039
|
url: normalizedApiUrl(configuredUrl),
|
|
51524
52040
|
defaultModel: raw.default_text_model?.trim() ?? ""
|
|
51525
52041
|
};
|
|
51526
52042
|
} catch {
|
|
51527
|
-
return { apiKey: "", url:
|
|
52043
|
+
return { apiKey: "", url: DEFAULT_URL4, defaultModel: "" };
|
|
51528
52044
|
}
|
|
51529
52045
|
}
|
|
51530
52046
|
function decodeMinimaxConfig(raw) {
|
|
@@ -51534,10 +52050,10 @@ function decodeMinimaxConfig(raw) {
|
|
|
51534
52050
|
const config2 = parsed.success ? parsed.data : {};
|
|
51535
52051
|
return {
|
|
51536
52052
|
...tools !== void 0 ? { tools } : {},
|
|
51537
|
-
url: normalizedApiUrl(config2.url?.trim() || process.env.MINIMAX_BASE_URL?.trim() ||
|
|
52053
|
+
url: normalizedApiUrl(config2.url?.trim() || process.env.MINIMAX_BASE_URL?.trim() || DEFAULT_URL4)
|
|
51538
52054
|
};
|
|
51539
52055
|
}
|
|
51540
|
-
var DRIVER_KIND7, API_KEY_ENV,
|
|
52056
|
+
var DRIVER_KIND7, API_KEY_ENV, DEFAULT_URL4, CN_URL, MODELS4, localConfigSchema, driverConfigSchema, MinimaxDriver;
|
|
51541
52057
|
var init_minimax = __esm({
|
|
51542
52058
|
"server/drivers/minimax.ts"() {
|
|
51543
52059
|
"use strict";
|
|
@@ -51545,7 +52061,7 @@ var init_minimax = __esm({
|
|
|
51545
52061
|
init_openai_chat();
|
|
51546
52062
|
DRIVER_KIND7 = "minimax";
|
|
51547
52063
|
API_KEY_ENV = "MINIMAX_API_KEY";
|
|
51548
|
-
|
|
52064
|
+
DEFAULT_URL4 = "https://api.minimax.io/v1";
|
|
51549
52065
|
CN_URL = "https://api.minimaxi.com/v1";
|
|
51550
52066
|
MODELS4 = {
|
|
51551
52067
|
default: "MiniMax-M3",
|
|
@@ -51583,7 +52099,7 @@ var init_minimax = __esm({
|
|
|
51583
52099
|
async create(input) {
|
|
51584
52100
|
const local = loadLocalMiniMaxConfig();
|
|
51585
52101
|
const apiKey = input.environment[API_KEY_ENV]?.trim() || process.env[API_KEY_ENV]?.trim() || local.apiKey;
|
|
51586
|
-
const apiUrl = input.config.url ===
|
|
52102
|
+
const apiUrl = input.config.url === DEFAULT_URL4 && local.url !== DEFAULT_URL4 ? local.url : input.config.url;
|
|
51587
52103
|
const models2 = local.defaultModel && MODELS4.options.some((model) => model.id === local.defaultModel) ? { ...MODELS4, default: local.defaultModel } : MODELS4;
|
|
51588
52104
|
return createOpenAIChatRuntime({
|
|
51589
52105
|
input,
|
|
@@ -51640,6 +52156,7 @@ var init_builtIn = __esm({
|
|
|
51640
52156
|
init_openai_compat();
|
|
51641
52157
|
init_pi();
|
|
51642
52158
|
init_mistral();
|
|
52159
|
+
init_cerebras();
|
|
51643
52160
|
init_minimax();
|
|
51644
52161
|
BUILT_IN_DRIVERS = [
|
|
51645
52162
|
GrokDriver,
|
|
@@ -51659,7 +52176,8 @@ var init_builtIn = __esm({
|
|
|
51659
52176
|
AntigravityDriver,
|
|
51660
52177
|
BoatAgentDriver,
|
|
51661
52178
|
MinimaxDriver,
|
|
51662
|
-
MistralDriver
|
|
52179
|
+
MistralDriver,
|
|
52180
|
+
CerebrasDriver
|
|
51663
52181
|
];
|
|
51664
52182
|
}
|
|
51665
52183
|
});
|
|
@@ -52280,7 +52798,7 @@ async function closeBrowserSession(binaryPath, env, timeoutMs = 15e3) {
|
|
|
52280
52798
|
const closeEnv = Object.fromEntries(Object.entries(env).filter(([key]) => !key.startsWith("AGENT_BROWSER_") || ["AGENT_BROWSER_SESSION", "AGENT_BROWSER_SOCKET_DIR", "AGENT_BROWSER_NAMESPACE", "AGENT_BROWSER_ENCRYPTION_KEY", "AGENT_BROWSER_RESTORE", "AGENT_BROWSER_RESTORE_SAVE"].includes(key)));
|
|
52281
52799
|
closeEnv.AGENT_BROWSER_CONFIG = configPath;
|
|
52282
52800
|
const deadline = Date.now() + timeoutMs;
|
|
52283
|
-
const
|
|
52801
|
+
const run3 = (args, capture = false) => new Promise((done) => {
|
|
52284
52802
|
let settled = false;
|
|
52285
52803
|
let output = "";
|
|
52286
52804
|
const finish = (ok) => {
|
|
@@ -52327,9 +52845,9 @@ async function closeBrowserSession(binaryPath, env, timeoutMs = 15e3) {
|
|
|
52327
52845
|
finish(code === 0);
|
|
52328
52846
|
});
|
|
52329
52847
|
});
|
|
52330
|
-
if (!(await
|
|
52848
|
+
if (!(await run3(["close"])).ok) return false;
|
|
52331
52849
|
while (Date.now() < deadline) {
|
|
52332
|
-
const status = await
|
|
52850
|
+
const status = await run3(["session", "list", "--json"], true);
|
|
52333
52851
|
if (!status.ok) return false;
|
|
52334
52852
|
try {
|
|
52335
52853
|
const result = JSON.parse(status.output);
|
|
@@ -52720,7 +53238,7 @@ var init_browser_engine = __esm({
|
|
|
52720
53238
|
var import_qrcode_terminal = __toESM(require_main(), 1);
|
|
52721
53239
|
import { spawn as spawn9 } from "node:child_process";
|
|
52722
53240
|
import { randomBytes as randomBytes5 } from "node:crypto";
|
|
52723
|
-
import { closeSync as
|
|
53241
|
+
import { closeSync as closeSync8, existsSync as existsSync19, mkdirSync as mkdirSync24, openSync as openSync8, readFileSync as readFileSync28 } from "node:fs";
|
|
52724
53242
|
import { homedir as homedir21 } from "node:os";
|
|
52725
53243
|
import { dirname as dirname16, join as join47, resolve as resolve13 } from "node:path";
|
|
52726
53244
|
import { createInterface as createInterface2 } from "node:readline/promises";
|
|
@@ -52763,15 +53281,30 @@ var validClientInstance = (value) => {
|
|
|
52763
53281
|
return input !== null && CLIENT_INSTANCE.test(input);
|
|
52764
53282
|
};
|
|
52765
53283
|
var boundedSecret = (value, maximum = 8192) => typeof value === "string" && value.length >= 20 && value.length <= maximum && /^\S+$/.test(value) ? value : null;
|
|
53284
|
+
var MAX_RETRY_AFTER_MS = 24 * 60 * 60 * 1e3;
|
|
52766
53285
|
var ControlPlaneError = class extends Error {
|
|
52767
|
-
constructor(code, status = 0, requestId = "") {
|
|
53286
|
+
constructor(code, status = 0, requestId = "", retryAfterMs = 0) {
|
|
52768
53287
|
super(code);
|
|
52769
53288
|
this.name = "ControlPlaneError";
|
|
52770
53289
|
this.code = code;
|
|
52771
53290
|
this.status = status;
|
|
52772
53291
|
this.requestId = REQUEST_ID.test(requestId) ? requestId : "";
|
|
53292
|
+
this.retryAfterMs = Number.isSafeInteger(retryAfterMs) && retryAfterMs > 0 ? Math.min(retryAfterMs, MAX_RETRY_AFTER_MS) : 0;
|
|
52773
53293
|
}
|
|
52774
53294
|
};
|
|
53295
|
+
function retryAfterMilliseconds(value) {
|
|
53296
|
+
const input = stringValue(value)?.trim() ?? "";
|
|
53297
|
+
if (!/^[0-9]{1,6}$/.test(input)) return 0;
|
|
53298
|
+
return Math.min(Number(input) * 1e3, MAX_RETRY_AFTER_MS);
|
|
53299
|
+
}
|
|
53300
|
+
var ENDPOINT_STATUSES = /* @__PURE__ */ new Set([
|
|
53301
|
+
"pending",
|
|
53302
|
+
"provisioning",
|
|
53303
|
+
"ready",
|
|
53304
|
+
"deleting",
|
|
53305
|
+
"deleted",
|
|
53306
|
+
"error"
|
|
53307
|
+
]);
|
|
52775
53308
|
function statusErrorCode(status) {
|
|
52776
53309
|
if (status === 400 || status === 422) return "invalid_request";
|
|
52777
53310
|
if (status === 401) return "unauthorized";
|
|
@@ -52883,7 +53416,8 @@ function createControlPlaneClient({
|
|
|
52883
53416
|
throw new ControlPlaneError(
|
|
52884
53417
|
code ?? statusErrorCode(response.status),
|
|
52885
53418
|
response.status,
|
|
52886
|
-
response.headers.get("x-request-id") ?? ""
|
|
53419
|
+
response.headers.get("x-request-id") ?? "",
|
|
53420
|
+
retryAfterMilliseconds(response.headers.get("retry-after"))
|
|
52887
53421
|
);
|
|
52888
53422
|
}
|
|
52889
53423
|
if (!allowEmpty && !plainObject(payload)) {
|
|
@@ -53004,6 +53538,25 @@ function createControlPlaneClient({
|
|
|
53004
53538
|
if (!endpoint || !connectorToken) throw new ControlPlaneError("invalid_response");
|
|
53005
53539
|
return { endpoint, connectorToken };
|
|
53006
53540
|
},
|
|
53541
|
+
/** The server's view of this installation's endpoint, or null when it
|
|
53542
|
+
* has none (never allocated, or removed by owner cleanup or idle
|
|
53543
|
+
* reclaim). Never returns or requests a connector token. */
|
|
53544
|
+
async getEndpoint(installationCredential) {
|
|
53545
|
+
if (typeof installationCredential !== "string" || !INSTALLATION_CREDENTIAL.test(installationCredential)) {
|
|
53546
|
+
throw new ControlPlaneError("signed_out", 401);
|
|
53547
|
+
}
|
|
53548
|
+
const { payload } = await request("/v1/installations/self/endpoint", {
|
|
53549
|
+
token: installationCredential
|
|
53550
|
+
});
|
|
53551
|
+
if (payload.endpoint === null) return null;
|
|
53552
|
+
const endpoint = validatedEndpoint(payload.endpoint);
|
|
53553
|
+
if (!endpoint) throw new ControlPlaneError("invalid_response");
|
|
53554
|
+
const status = stringValue(plainObject(payload.endpoint)?.status);
|
|
53555
|
+
return {
|
|
53556
|
+
url: endpoint.url,
|
|
53557
|
+
status: status !== null && ENDPOINT_STATUSES.has(status) ? status : "unknown"
|
|
53558
|
+
};
|
|
53559
|
+
},
|
|
53007
53560
|
async deleteEndpoint(installationCredential) {
|
|
53008
53561
|
if (typeof installationCredential !== "string" || !INSTALLATION_CREDENTIAL.test(installationCredential)) {
|
|
53009
53562
|
throw new ControlPlaneError("signed_out", 401);
|
|
@@ -53651,6 +54204,26 @@ var UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]
|
|
|
53651
54204
|
var INSTALLATION_ID2 = UUID;
|
|
53652
54205
|
var INSTALLATION_CREDENTIAL2 = /^omb_install_[A-Za-z0-9_-]{22}\.[A-Za-z0-9_-]{43}$/;
|
|
53653
54206
|
var DEFAULT_HEALTH_CACHE_MS = 3e4;
|
|
54207
|
+
var DEFAULT_AUTO_RETRY_BASE_MS = 10 * 6e4;
|
|
54208
|
+
var DEFAULT_AUTO_RETRY_MAX_MS = 6 * 60 * 6e4;
|
|
54209
|
+
var DEFAULT_ENDPOINT_CHECK_INTERVAL_MS = 15 * 6e4;
|
|
54210
|
+
var DEFAULT_FIRST_ENDPOINT_CHECK_MS = 2 * 6e4;
|
|
54211
|
+
var AUTO_RETRY_CODES = /* @__PURE__ */ new Set([
|
|
54212
|
+
"endpoint_capacity",
|
|
54213
|
+
"endpoint_unavailable",
|
|
54214
|
+
"endpoint_busy",
|
|
54215
|
+
"network_unavailable",
|
|
54216
|
+
"control_plane_unavailable",
|
|
54217
|
+
"internal_error",
|
|
54218
|
+
"rate_limited",
|
|
54219
|
+
"credential_rotation_rate_limited"
|
|
54220
|
+
]);
|
|
54221
|
+
var ENDPOINT_NEEDS_RECONCILE = /* @__PURE__ */ new Set(["deleting", "deleted", "error"]);
|
|
54222
|
+
var defaultSetTimer = (callback, milliseconds) => {
|
|
54223
|
+
const timer = setTimeout(callback, milliseconds);
|
|
54224
|
+
timer.unref?.();
|
|
54225
|
+
return timer;
|
|
54226
|
+
};
|
|
53654
54227
|
var ownString = (document, field) => typeof document?.[field] === "string" ? document[field] : "";
|
|
53655
54228
|
function resolveCompanionControlPlaneURL({
|
|
53656
54229
|
isPackaged,
|
|
@@ -53747,6 +54320,7 @@ var FRIENDLY_MESSAGES = Object.freeze({
|
|
|
53747
54320
|
installation_limit_reached: "This account has reached its computer limit. Remove an old computer and try again.",
|
|
53748
54321
|
installation_exists: "This computer is already connected. Try again to recover it.",
|
|
53749
54322
|
endpoint_busy: "The secure connection is still being prepared. Try again in a moment.",
|
|
54323
|
+
endpoint_capacity: "Secure HTTPS links are temporarily full. Pair on this Wi-Fi or with Tailscale for now; we'll retry automatically.",
|
|
53750
54324
|
endpoint_unavailable: "The secure connection service could not finish setup. Local Wi-Fi and Tailscale pairing still work. If this keeps happening, contact support with the error reference.",
|
|
53751
54325
|
endpoint_cleanup_pending: "The secure connection is still being removed. Try signing out again shortly.",
|
|
53752
54326
|
control_plane_unavailable: "Secure access is not available right now. Local pairing still works.",
|
|
@@ -53790,7 +54364,19 @@ function createCompanionAccountService({
|
|
|
53790
54364
|
managedConnectionState = () => ({ status: "stopped", ready: false }),
|
|
53791
54365
|
companionIsOn = () => false,
|
|
53792
54366
|
now = Date.now,
|
|
53793
|
-
healthCacheMs = DEFAULT_HEALTH_CACHE_MS
|
|
54367
|
+
healthCacheMs = DEFAULT_HEALTH_CACHE_MS,
|
|
54368
|
+
// Background recovery is opt-in: the desktop app enables it, one-shot CLI
|
|
54369
|
+
// commands do not. When on, retryable setup failures are retried with
|
|
54370
|
+
// backoff, and a saved address whose server endpoint was removed (idle
|
|
54371
|
+
// reclaim) is re-provisioned without a new sign-in.
|
|
54372
|
+
autoRecover = false,
|
|
54373
|
+
setTimer = defaultSetTimer,
|
|
54374
|
+
clearTimer = clearTimeout,
|
|
54375
|
+
random = Math.random,
|
|
54376
|
+
autoRetryBaseMs = DEFAULT_AUTO_RETRY_BASE_MS,
|
|
54377
|
+
autoRetryMaxMs = DEFAULT_AUTO_RETRY_MAX_MS,
|
|
54378
|
+
endpointCheckIntervalMs = DEFAULT_ENDPOINT_CHECK_INTERVAL_MS,
|
|
54379
|
+
firstEndpointCheckMs = DEFAULT_FIRST_ENDPOINT_CHECK_MS
|
|
53794
54380
|
} = {}) {
|
|
53795
54381
|
const configured = Boolean(client);
|
|
53796
54382
|
let healthy = false;
|
|
@@ -53798,6 +54384,11 @@ function createCompanionAccountService({
|
|
|
53798
54384
|
let healthProbe = null;
|
|
53799
54385
|
let phase = null;
|
|
53800
54386
|
let transition = Promise.resolve();
|
|
54387
|
+
let autoRetryTimer = null;
|
|
54388
|
+
let autoRetryAttempt = 0;
|
|
54389
|
+
let watchdogTimer = null;
|
|
54390
|
+
let lastEndpointCheck = null;
|
|
54391
|
+
let disposed = false;
|
|
53801
54392
|
const serialize = (work) => {
|
|
53802
54393
|
const next = transition.then(work, work);
|
|
53803
54394
|
transition = next.then(
|
|
@@ -53809,6 +54400,34 @@ function createCompanionAccountService({
|
|
|
53809
54400
|
return next;
|
|
53810
54401
|
};
|
|
53811
54402
|
const credentials = () => readCredentials?.() ?? {};
|
|
54403
|
+
const cancelAutoRetry = () => {
|
|
54404
|
+
if (autoRetryTimer !== null) clearTimer(autoRetryTimer);
|
|
54405
|
+
autoRetryTimer = null;
|
|
54406
|
+
};
|
|
54407
|
+
const resetAutoRetry = () => {
|
|
54408
|
+
cancelAutoRetry();
|
|
54409
|
+
autoRetryAttempt = 0;
|
|
54410
|
+
};
|
|
54411
|
+
let retryFromTimer = () => Promise.resolve();
|
|
54412
|
+
const scheduleAutoRetry = (error51) => {
|
|
54413
|
+
if (!autoRecover || disposed || !configured) return;
|
|
54414
|
+
if (!(error51 instanceof ControlPlaneError) || !AUTO_RETRY_CODES.has(error51.code)) return;
|
|
54415
|
+
const document = credentials();
|
|
54416
|
+
if (!storedAccount(document) || companionAccountCleanupPending(document)) return;
|
|
54417
|
+
cancelAutoRetry();
|
|
54418
|
+
const backoff = Math.min(
|
|
54419
|
+
autoRetryMaxMs,
|
|
54420
|
+
autoRetryBaseMs * 2 ** Math.min(autoRetryAttempt, 20)
|
|
54421
|
+
);
|
|
54422
|
+
const jittered = Math.round(backoff * (0.8 + 0.4 * random()));
|
|
54423
|
+
const delay2 = Math.min(autoRetryMaxMs, Math.max(jittered, error51.retryAfterMs ?? 0));
|
|
54424
|
+
autoRetryAttempt += 1;
|
|
54425
|
+
autoRetryTimer = setTimer(() => {
|
|
54426
|
+
autoRetryTimer = null;
|
|
54427
|
+
void retryFromTimer().catch(() => {
|
|
54428
|
+
});
|
|
54429
|
+
}, delay2);
|
|
54430
|
+
};
|
|
53812
54431
|
const probeControlPlane = async ({ force = false } = {}) => {
|
|
53813
54432
|
if (!configured) return false;
|
|
53814
54433
|
const checkedAt = now();
|
|
@@ -54002,6 +54621,7 @@ function createCompanionAccountService({
|
|
|
54002
54621
|
});
|
|
54003
54622
|
throw error51;
|
|
54004
54623
|
}
|
|
54624
|
+
resetAutoRetry();
|
|
54005
54625
|
const connection = await activatePersistedEndpoint();
|
|
54006
54626
|
phase = null;
|
|
54007
54627
|
if (companionIsOn() && connection && ["unavailable", "error"].includes(connection.status)) {
|
|
@@ -54086,6 +54706,7 @@ function createCompanionAccountService({
|
|
|
54086
54706
|
email: authenticatedPersisted ? verified.user.email : previous?.email ?? email3,
|
|
54087
54707
|
expiredSessionIsSignedOut: authenticatedPersisted
|
|
54088
54708
|
});
|
|
54709
|
+
if (authenticatedPersisted) scheduleAutoRetry(error51);
|
|
54089
54710
|
return settledState();
|
|
54090
54711
|
}
|
|
54091
54712
|
});
|
|
@@ -54115,11 +54736,48 @@ function createCompanionAccountService({
|
|
|
54115
54736
|
});
|
|
54116
54737
|
} catch (error51) {
|
|
54117
54738
|
failAction(error51, { email: account.email, expiredSessionIsSignedOut: true });
|
|
54739
|
+
scheduleAutoRetry(error51);
|
|
54118
54740
|
return settledState();
|
|
54119
54741
|
}
|
|
54120
54742
|
};
|
|
54121
54743
|
const retry = () => serialize(retryWork);
|
|
54744
|
+
retryFromTimer = retry;
|
|
54745
|
+
const reconcileIfEndpointGone = async () => {
|
|
54746
|
+
const document = credentials();
|
|
54747
|
+
const account = storedAccount(document);
|
|
54748
|
+
const access2 = managedCompanionTunnelAccess(document);
|
|
54749
|
+
if (!account || !access2 || !account.installationCredential || companionAccountCleanupPending(document) || typeof client.getEndpoint !== "function") {
|
|
54750
|
+
return null;
|
|
54751
|
+
}
|
|
54752
|
+
lastEndpointCheck = now();
|
|
54753
|
+
let endpoint;
|
|
54754
|
+
try {
|
|
54755
|
+
endpoint = await client.getEndpoint(account.installationCredential);
|
|
54756
|
+
} catch {
|
|
54757
|
+
return null;
|
|
54758
|
+
}
|
|
54759
|
+
if (endpoint && endpoint.url === access2.endpoint && !ENDPOINT_NEEDS_RECONCILE.has(endpoint.status)) {
|
|
54760
|
+
return null;
|
|
54761
|
+
}
|
|
54762
|
+
return retryWork();
|
|
54763
|
+
};
|
|
54764
|
+
const watchdogTick = () => {
|
|
54765
|
+
watchdogTimer = null;
|
|
54766
|
+
if (disposed) return;
|
|
54767
|
+
watchdogTimer = setTimer(watchdogTick, endpointCheckIntervalMs);
|
|
54768
|
+
if (!companionIsOn() || autoRetryTimer !== null) return;
|
|
54769
|
+
const connection = managedConnectionState?.() ?? {};
|
|
54770
|
+
if (!["retrying", "error"].includes(connection.status)) return;
|
|
54771
|
+
if (lastEndpointCheck !== null && now() - lastEndpointCheck < endpointCheckIntervalMs) return;
|
|
54772
|
+
void serialize(reconcileIfEndpointGone).catch(() => {
|
|
54773
|
+
});
|
|
54774
|
+
};
|
|
54775
|
+
const startWatchdog = () => {
|
|
54776
|
+
if (!autoRecover || disposed || !configured || watchdogTimer !== null) return;
|
|
54777
|
+
watchdogTimer = setTimer(watchdogTick, firstEndpointCheckMs);
|
|
54778
|
+
};
|
|
54122
54779
|
const signOut = () => serialize(async () => {
|
|
54780
|
+
resetAutoRetry();
|
|
54123
54781
|
if (!storedAccount(credentials())) {
|
|
54124
54782
|
await clearAfterCleanup();
|
|
54125
54783
|
return settledState();
|
|
@@ -54138,14 +54796,25 @@ function createCompanionAccountService({
|
|
|
54138
54796
|
});
|
|
54139
54797
|
const restore = () => serialize(async () => {
|
|
54140
54798
|
if (!configured) return settledState();
|
|
54799
|
+
startWatchdog();
|
|
54141
54800
|
if (!await probeControlPlane({ force: true })) return settledState();
|
|
54142
54801
|
if (companionAccountCleanupPending(credentials())) return retryWork();
|
|
54143
54802
|
await ensureClientIdentity();
|
|
54144
54803
|
const account = storedAccount(credentials());
|
|
54145
54804
|
if (account && !managedCompanionTunnelAccess(credentials())) return retryWork();
|
|
54805
|
+
if (autoRecover && account && companionIsOn()) {
|
|
54806
|
+
const reconciled = await reconcileIfEndpointGone();
|
|
54807
|
+
if (reconciled) return reconciled;
|
|
54808
|
+
}
|
|
54146
54809
|
phase = null;
|
|
54147
54810
|
return settledState();
|
|
54148
54811
|
});
|
|
54812
|
+
const dispose = () => {
|
|
54813
|
+
disposed = true;
|
|
54814
|
+
cancelAutoRetry();
|
|
54815
|
+
if (watchdogTimer !== null) clearTimer(watchdogTimer);
|
|
54816
|
+
watchdogTimer = null;
|
|
54817
|
+
};
|
|
54149
54818
|
return Object.freeze({
|
|
54150
54819
|
state: async () => {
|
|
54151
54820
|
await probeControlPlane();
|
|
@@ -54155,7 +54824,8 @@ function createCompanionAccountService({
|
|
|
54155
54824
|
verifyCode,
|
|
54156
54825
|
retry,
|
|
54157
54826
|
signOut,
|
|
54158
|
-
restore
|
|
54827
|
+
restore,
|
|
54828
|
+
dispose
|
|
54159
54829
|
});
|
|
54160
54830
|
}
|
|
54161
54831
|
|
|
@@ -54273,7 +54943,7 @@ function isSecretParameter(name) {
|
|
|
54273
54943
|
return isSecretName2(bare) || /^(?:auth|sig|signature|pass|pwd|code)$/i.test(bare);
|
|
54274
54944
|
}
|
|
54275
54945
|
function keyLikeSegment(segment) {
|
|
54276
|
-
return (segment.match(/[A-Za-z0-9]{16,}/g) ?? []).some((
|
|
54946
|
+
return (segment.match(/[A-Za-z0-9]{16,}/g) ?? []).some((run3) => /\d/.test(run3) && /[A-Za-z]/.test(run3));
|
|
54277
54947
|
}
|
|
54278
54948
|
function maskUrlSecrets(text4) {
|
|
54279
54949
|
return text4.replace(/\b([a-z][\w+.-]*:\/\/)([^\s/?#]*)([^\s?#]*)([^\s]*)/gi, (_all, scheme, authority, path3, rest) => {
|
|
@@ -56932,7 +57602,7 @@ async function runServe(options, log = console.log) {
|
|
|
56932
57602
|
const logsDir = join47(options.dataDir, "logs");
|
|
56933
57603
|
mkdirSync24(logsDir, { recursive: true, mode: 448 });
|
|
56934
57604
|
logPath = join47(logsDir, `server-${Date.now()}-${process.pid}.log`);
|
|
56935
|
-
logFd =
|
|
57605
|
+
logFd = openSync8(logPath, "wx", 384);
|
|
56936
57606
|
log("\nStarting your workspace\u2026");
|
|
56937
57607
|
}
|
|
56938
57608
|
if (tailscale) {
|
|
@@ -56963,7 +57633,7 @@ async function runServe(options, log = console.log) {
|
|
|
56963
57633
|
}
|
|
56964
57634
|
throw error51;
|
|
56965
57635
|
} finally {
|
|
56966
|
-
if (logFd !== void 0)
|
|
57636
|
+
if (logFd !== void 0) closeSync8(logFd);
|
|
56967
57637
|
process.removeListener("SIGINT", cancelStartup);
|
|
56968
57638
|
process.removeListener("SIGTERM", cancelStartup);
|
|
56969
57639
|
}
|