openmausbot 0.1.70 → 0.1.71
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/{index-D1RGhLUK.js → index-CJtyBonr.js} +1 -1
- package/dist/assets/index-CYLdYtYp.css +1 -0
- package/dist/assets/index-Di4ovwu5.js +289 -0
- package/dist/index.html +2 -2
- package/dist-server/container-mcp.js +4 -2
- package/dist-server/drivers/agents-proxy.js +202 -16
- package/dist-server/drivers/pi-mcp-extension.ts +1 -1
- package/dist-server/index.js +2258 -834
- package/dist-server/local-computer.js +2 -1
- package/dist-server/mcp-gate.js +543 -0
- package/dist-server/mcp-server.js +38 -0
- package/dist-server/openmausbot.js +416 -130
- package/dist-server/pair-cli.js +416 -130
- package/dist-server/proxy-paths.js +1 -0
- package/dist-server/server/agent-tool-policy.js +29 -0
- package/dist-server/server/bot-package.js +55 -2
- package/dist-server/server/browser-live.js +12 -7
- package/dist-server/server/config.js +40 -4
- package/dist-server/server/drivers/acp/core.js +2 -0
- package/dist-server/server/drivers/acp/cursor.js +1 -1
- package/dist-server/server/drivers/acp/grok.js +5 -1
- package/dist-server/server/drivers/agents-proxy.js +195 -16
- package/dist-server/server/drivers/boxagent.js +1 -1
- package/dist-server/server/drivers/claude.js +288 -17
- package/dist-server/server/drivers/codex.js +13 -4
- package/dist-server/server/drivers/pi.js +1 -1
- package/dist-server/server/harness/bus.js +1 -1
- package/dist-server/server/index.js +520 -193
- package/dist-server/server/local-computer.js +1 -1
- package/dist-server/server/mcp-gate-config.js +56 -0
- package/dist-server/server/mcp-gate.js +227 -0
- package/dist-server/server/mcp-trim.js +182 -0
- package/dist-server/server/memory-journal.js +440 -0
- package/dist-server/server/memory-store.js +308 -0
- package/dist-server/server/message-db.js +90 -3
- package/dist-server/server/package-export.js +25 -0
- package/dist-server/server/peer-approval.js +1 -1
- package/dist-server/server/proxy-paths.js +1 -0
- package/dist-server/server/redact.js +15 -0
- package/dist-server/server/resume-recovery.js +46 -0
- package/dist-server/server/screen-frame-gate.js +9 -6
- package/dist-server/server/skill-library.js +5 -5
- package/dist-server/server/store.js +7 -3
- package/dist-server/server/system-prompt.js +13 -1
- package/dist-server/server/team-backup.js +35 -0
- package/dist-server/server/tool-summary.js +39 -0
- package/dist-server/server/tts/speech-text.js +3 -1
- package/dist-server/server/turn-context.js +18 -0
- package/dist-server/server/workspace.js +321 -22
- package/dist-server/shared/approval-mode.js +1 -1
- package/dist-server/shared/team-backup.js +13 -2
- package/dist-server/vps-container-mcp.js +4 -2
- package/package.json +1 -1
- package/skills/create-verification-skill/SKILL.md +2 -3
- package/dist/assets/index-B2F__IRS.css +0 -1
- package/dist/assets/index-CLj3t5Ba.js +0 -280
|
@@ -17,6 +17,7 @@ var SPAWNED_PROXIES = {
|
|
|
17
17
|
agents: resolveProxy("drivers/agents-proxy"),
|
|
18
18
|
dweb: resolveProxy("drivers/dweb-proxy"),
|
|
19
19
|
connectors: resolveProxy("connector-proxy"),
|
|
20
|
+
mcpGate: resolveProxy("mcp-gate"),
|
|
20
21
|
phone: resolveProxy("drivers/phone-proxy"),
|
|
21
22
|
// Loaded by the external `pi` process via `-e`, not by this server — but
|
|
22
23
|
// resolved through the same single source of truth so the packaged layout
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/** Reviewed local reads exposed by the built-in agents MCP integration.
|
|
2
|
+
* This exact catalog supplies MCP tool metadata only; names, prefixes, or
|
|
3
|
+
* third-party annotations alone must never grant read access.
|
|
4
|
+
* Session recall keeps its own-bot scope and may record a deduplicated access
|
|
5
|
+
* disclosure in a room; it does not edit recalled messages or launch work.
|
|
6
|
+
*/
|
|
7
|
+
export const READ_ONLY_AGENT_TOOL_NAMES = new Set([
|
|
8
|
+
"list_bots",
|
|
9
|
+
"list_rooms",
|
|
10
|
+
"list_threads",
|
|
11
|
+
"check_delegation",
|
|
12
|
+
"wait_delegation",
|
|
13
|
+
"session_search",
|
|
14
|
+
"session_read",
|
|
15
|
+
"list_routines",
|
|
16
|
+
"skills_list",
|
|
17
|
+
]);
|
|
18
|
+
const READ_ONLY_ANNOTATIONS = Object.freeze({
|
|
19
|
+
readOnlyHint: true,
|
|
20
|
+
destructiveHint: false,
|
|
21
|
+
idempotentHint: true,
|
|
22
|
+
openWorldHint: false,
|
|
23
|
+
});
|
|
24
|
+
export function isReadOnlyAgentTool(name) {
|
|
25
|
+
return READ_ONLY_AGENT_TOOL_NAMES.has(name);
|
|
26
|
+
}
|
|
27
|
+
export function agentToolAnnotations(name) {
|
|
28
|
+
return isReadOnlyAgentTool(name) ? READ_ONLY_ANNOTATIONS : undefined;
|
|
29
|
+
}
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
|
|
3
3
|
import { schemaIssue } from "./schema.js";
|
|
4
|
+
import { isSkillName, parseSkillMd, SKILL_FILE_MAX_BYTES } from "./skills.js";
|
|
4
5
|
import { BOT_PROFILE_LIMITS } from "../shared/bot-profile.js";
|
|
5
6
|
export const BOT_PACKAGE_FORMAT = "openmaus.package";
|
|
6
7
|
export const BOT_PACKAGE_VERSION = 1;
|
|
7
8
|
export const BOTMRR_MARKDOWN_VERSION = 1;
|
|
9
|
+
export const BOT_PACKAGE_SKILLS_VERSION = 1;
|
|
10
|
+
export const BOT_PACKAGE_MAX_SKILLS = 20;
|
|
11
|
+
const BOT_PACKAGE_MARKDOWN_MAX_BYTES = 1_000_000;
|
|
8
12
|
const COLORS = [
|
|
9
13
|
"green",
|
|
10
14
|
"blue",
|
|
@@ -27,6 +31,24 @@ const key = requiredText(64).regex(/^[a-z0-9][a-z0-9_-]*$/, {
|
|
|
27
31
|
message: "may only contain lowercase letters, numbers, - and _",
|
|
28
32
|
});
|
|
29
33
|
const MAX_DATE_MS = 8_640_000_000_000_000;
|
|
34
|
+
const skillName = requiredText(64).refine(isSkillName, {
|
|
35
|
+
message: "must be a lowercase skill name",
|
|
36
|
+
});
|
|
37
|
+
const portableSource = optionalText(2_000).refine((value) => value === undefined || !/^(?:[a-z]:[\\/]|[\\/]|\\\\|file:)/i.test(value), { message: "must not be an absolute path" });
|
|
38
|
+
const skillInstructions = z
|
|
39
|
+
.string({ error: "must be text" })
|
|
40
|
+
.min(1, { message: "is required" })
|
|
41
|
+
.max(SKILL_FILE_MAX_BYTES, { message: "is too long" })
|
|
42
|
+
.refine((value) => Buffer.byteLength(value, "utf8") <= SKILL_FILE_MAX_BYTES, { message: "is too large" })
|
|
43
|
+
.refine((value) => /^---\r?\n/.test(value), { message: "must start with SKILL.md frontmatter" });
|
|
44
|
+
const portableSkillSchema = z.object({
|
|
45
|
+
name: skillName,
|
|
46
|
+
description: requiredText(1_024),
|
|
47
|
+
source: portableSource,
|
|
48
|
+
license: optionalText(200),
|
|
49
|
+
compatibility: optionalText(200),
|
|
50
|
+
instructions: skillInstructions,
|
|
51
|
+
});
|
|
30
52
|
const CLOCK_TIME = /^([01]\d|2[0-3]):[0-5]\d$/;
|
|
31
53
|
const intervalWeekdays = z.array(z.number().int().min(0).max(6)).min(1).max(7).refine((weekdays) => new Set(weekdays).size === weekdays.length, "must contain unique weekdays");
|
|
32
54
|
const intervalWindow = z.object({
|
|
@@ -113,6 +135,7 @@ const packageSchema = z.object({
|
|
|
113
135
|
mascotBody: optionalText(40),
|
|
114
136
|
}),
|
|
115
137
|
playbooks: z.array(key).max(40).optional(),
|
|
138
|
+
skills: z.array(skillName).max(BOT_PACKAGE_MAX_SKILLS).optional(),
|
|
116
139
|
})).min(1).max(200),
|
|
117
140
|
chiefOfStaff: key.optional(),
|
|
118
141
|
rooms: z.array(z.object({
|
|
@@ -144,6 +167,10 @@ const packageSchema = z.object({
|
|
|
144
167
|
triggers: z.array(requiredText(100)).min(1).max(30),
|
|
145
168
|
instructions: requiredText(24_000),
|
|
146
169
|
})).max(80).optional(),
|
|
170
|
+
skills: z.object({
|
|
171
|
+
version: z.literal(BOT_PACKAGE_SKILLS_VERSION),
|
|
172
|
+
entries: z.array(portableSkillSchema).min(1).max(BOT_PACKAGE_MAX_SKILLS),
|
|
173
|
+
}).optional(),
|
|
147
174
|
examples: z.array(z.object({
|
|
148
175
|
title: requiredText(120),
|
|
149
176
|
input: requiredText(4_000),
|
|
@@ -158,7 +185,7 @@ export function isBotPackage(value) {
|
|
|
158
185
|
value.format === BOT_PACKAGE_FORMAT;
|
|
159
186
|
}
|
|
160
187
|
function markdownDocument(markdown) {
|
|
161
|
-
if (Buffer.byteLength(markdown) >
|
|
188
|
+
if (Buffer.byteLength(markdown) > BOT_PACKAGE_MARKDOWN_MAX_BYTES)
|
|
162
189
|
throw new Error("The bot playbook is too large");
|
|
163
190
|
const frontmatter = markdown.match(/^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/);
|
|
164
191
|
if (!frontmatter)
|
|
@@ -206,6 +233,7 @@ export function parseBotPackage(value) {
|
|
|
206
233
|
};
|
|
207
234
|
const agents = unique(pkg.agents.map((agent) => agent.key), "agent");
|
|
208
235
|
const playbooks = unique((pkg.playbooks ?? []).map((playbook) => playbook.key), "playbook");
|
|
236
|
+
const skills = unique((pkg.skills?.entries ?? []).map((skill) => skill.name), "skill");
|
|
209
237
|
unique((pkg.rooms ?? []).map((room) => room.key), "room");
|
|
210
238
|
unique((pkg.routines ?? []).map((routine) => routine.key), "routine");
|
|
211
239
|
if (pkg.chiefOfStaff && !agents.has(pkg.chiefOfStaff)) {
|
|
@@ -216,6 +244,28 @@ export function parseBotPackage(value) {
|
|
|
216
244
|
if (!playbooks.has(playbook))
|
|
217
245
|
throw new Error(`Agent ${agent.key} references unknown playbook: ${playbook}`);
|
|
218
246
|
}
|
|
247
|
+
const assignedSkills = unique(agent.skills ?? [], `skill in agent ${agent.key}`);
|
|
248
|
+
for (const skill of assignedSkills) {
|
|
249
|
+
if (!skills.has(skill))
|
|
250
|
+
throw new Error(`Agent ${agent.key} references unknown skill: ${skill}`);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
const referencedSkills = new Set(pkg.agents.flatMap((agent) => agent.skills ?? []));
|
|
254
|
+
for (const skill of pkg.skills?.entries ?? []) {
|
|
255
|
+
const parsed = parseSkillMd(skill.instructions);
|
|
256
|
+
if ("error" in parsed)
|
|
257
|
+
throw new Error(`Skill ${skill.name} is invalid: ${parsed.error}`);
|
|
258
|
+
if (parsed.name !== skill.name)
|
|
259
|
+
throw new Error(`Skill ${skill.name} does not match its SKILL.md name`);
|
|
260
|
+
if (parsed.description !== skill.description)
|
|
261
|
+
throw new Error(`Skill ${skill.name} does not match its description`);
|
|
262
|
+
for (const field of ["license", "compatibility"]) {
|
|
263
|
+
if (skill[field] !== undefined && skill[field] !== parsed[field]) {
|
|
264
|
+
throw new Error(`Skill ${skill.name} does not match its ${field}`);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
if (!referencedSkills.has(skill.name))
|
|
268
|
+
throw new Error(`Skill ${skill.name} is not referenced by an agent`);
|
|
219
269
|
}
|
|
220
270
|
for (const room of pkg.rooms ?? []) {
|
|
221
271
|
const members = unique(room.members, `member in room ${room.key}`);
|
|
@@ -301,7 +351,10 @@ export function renderBotPackageMarkdown(document) {
|
|
|
301
351
|
const connections = pkg.requirements.apps.length
|
|
302
352
|
? pkg.requirements.apps.map((app) => `- **${app.label}${app.optional ? " (optional)" : ""}:** ${app.reason}`).join("\n")
|
|
303
353
|
: "- No connected apps are required.";
|
|
304
|
-
|
|
354
|
+
const markdown = `---\n${frontmatter}\n---\n\n# ${pkg.name}\n\n${pkg.tagline}\n\n> **Give this file to your Chief of Staff.** It is the complete team blueprint. Any agent system can run it; OpenMausBot can also install it directly.\n\n## Activation\n\nYou are the Chief of Staff for this blueprint. Read the whole document before acting. Confirm the user's goal and any missing inputs, then create or delegate to the specialist roles below. Preserve their names, ownership, boundaries, shared-room rules, and playbooks. If your platform cannot literally spawn agents, perform the roles one at a time and keep their outputs clearly separated.\n\nNever request pasted passwords or secret keys. Use the platform's normal connection flow. Do not send messages, publish content, spend money, delete data, or enable a schedule without the user's explicit approval. All routines start paused.\n\n## Mission\n\n${pkg.summary}\n\n## Outcomes\n\n${list(pkg.outcomes)}\n\n## Connections\n\n${connections}\n\n## Team\n\n${agents}\n\n## Chief of Staff\n\nThe Chief of Staff role is \`${pkg.chiefOfStaff ?? pkg.agents[0].key}\`. This role owns delegation, synthesis, conflict resolution, and the final answer to the user.\n${rooms ? `\n## Shared rooms\n\n${rooms}\n` : ""}${routines ? `\n## Suggested routines\n\n${routines}\n` : ""}${playbooks ? `\n## Playbooks\n\n${playbooks}\n` : ""}${examples ? `\n## Example job\n\n${examples}\n` : ""}\n## Completion rule\n\nReturn one clear result to the user, distinguish evidence from inference, cite source links when the work uses external material, and state what still needs human approval or a connected app.\n`;
|
|
355
|
+
if (Buffer.byteLength(markdown) > BOT_PACKAGE_MARKDOWN_MAX_BYTES)
|
|
356
|
+
throw new Error("The bot playbook is too large");
|
|
357
|
+
return markdown;
|
|
305
358
|
}
|
|
306
359
|
export function packageAgentAsMember(agent) {
|
|
307
360
|
return {
|
|
@@ -7,6 +7,9 @@ const execute = promisify(execFile);
|
|
|
7
7
|
const MAX_FRAME = 3 * 1024 * 1024;
|
|
8
8
|
const MAX_BUFFER = 4 * 1024 * 1024;
|
|
9
9
|
const HEARTBEAT_MS = 10_000;
|
|
10
|
+
// The native press resolver supplies the virtual key codes and Enter/Tab text
|
|
11
|
+
// that its raw input_keyboard relay omits. Keep unknown keys literal.
|
|
12
|
+
const DISCRETE_KEYS = new Set(["Backspace", "Enter", "Tab", "Escape", "Delete", "ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight", "Home", "End", "PageUp", "PageDown"]);
|
|
10
13
|
export class BrowserLiveError extends Error {
|
|
11
14
|
status;
|
|
12
15
|
constructor(message, status = 400) { super(message); this.name = "BrowserLiveError"; this.status = status; }
|
|
@@ -308,17 +311,20 @@ export class BrowserLive {
|
|
|
308
311
|
throw new BrowserLiveError("The browser stream is not connected.", 409);
|
|
309
312
|
let command;
|
|
310
313
|
const { type, eventType, ...fields } = message;
|
|
314
|
+
const key = String(fields.code || fields.key);
|
|
311
315
|
const shortcut = Number(fields.modifiers) > 0 && !["Alt", "Control", "Meta", "Shift"].includes(String(fields.key))
|
|
312
316
|
&& !(fields.modifiers === 8 && text(fields.key, 64) && [...fields.key].length === 1);
|
|
313
|
-
|
|
314
|
-
|
|
317
|
+
// press already released the key. Match raw held keys, not the modifiers
|
|
318
|
+
// on keyUp: they may have changed, or blur may flush releases with zero.
|
|
319
|
+
if (type === "input_keyboard" && eventType === "keyUp" && !viewer.pressedKeys.has(key))
|
|
320
|
+
return;
|
|
315
321
|
if (type === "input_mouse")
|
|
316
322
|
command = { action: "input_mouse", type: eventType, ...fields };
|
|
317
323
|
else if (eventType === "char")
|
|
318
324
|
command = { action: "keyboard", subaction: "insertText", text: fields.text };
|
|
319
|
-
else if (eventType === "keyDown" && shortcut) {
|
|
320
|
-
//
|
|
321
|
-
//
|
|
325
|
+
else if (eventType === "keyDown" && (shortcut || DISCRETE_KEYS.has(String(fields.key)))) {
|
|
326
|
+
// press resolves virtual key codes, required text and modifiers, and
|
|
327
|
+
// acknowledges the complete key-down/up pair before hand-back.
|
|
322
328
|
const modifiers = fields.modifiers;
|
|
323
329
|
const chord = [[1, "Alt"], [2, "Control"], [4, "Meta"], [8, "Shift"]];
|
|
324
330
|
command = { action: "press", key: [...chord.filter(([bit]) => modifiers & bit).map(([, key]) => key), fields.key].join("+") };
|
|
@@ -326,7 +332,6 @@ export class BrowserLive {
|
|
|
326
332
|
else
|
|
327
333
|
command = { action: "input_keyboard", type: eventType, key: fields.key,
|
|
328
334
|
...(fields.code === undefined ? {} : { code: fields.code }), ...(fields.text === undefined ? {} : { text: fields.text }) };
|
|
329
|
-
const key = String(fields.code || fields.key);
|
|
330
335
|
if (command.action === "input_keyboard" && eventType === "keyDown") {
|
|
331
336
|
if (viewer.pressedKeys.size >= 64 && !viewer.pressedKeys.has(key))
|
|
332
337
|
throw new BrowserLiveError("Too many keys are held. Restart the browser before continuing.", 409);
|
|
@@ -354,7 +359,7 @@ export class BrowserLive {
|
|
|
354
359
|
}
|
|
355
360
|
if (object(JSON.parse(Buffer.concat(chunks).toString("utf8")))?.success !== true)
|
|
356
361
|
throw new Error("input failed");
|
|
357
|
-
if (command.action === "input_keyboard" && eventType === "keyUp")
|
|
362
|
+
if (command.action === "press" || (command.action === "input_keyboard" && eventType === "keyUp"))
|
|
358
363
|
viewer.pressedKeys.delete(key);
|
|
359
364
|
if (type === "input_mouse" && eventType === "mouseReleased")
|
|
360
365
|
viewer.pressedButtons.delete(String(fields.button));
|
|
@@ -195,9 +195,13 @@ const browserProfilesSchema = z.array(browserProfileSchema).max(20).superRefine(
|
|
|
195
195
|
});
|
|
196
196
|
});
|
|
197
197
|
});
|
|
198
|
+
// Deliberately non-strict: an unknown flag (such as `skillRecorder`, the
|
|
199
|
+
// pre-rename name a stale client may still PATCH) is dropped as a no-op
|
|
200
|
+
// instead of failing the whole stored config or the request.
|
|
198
201
|
const featureConfigSchema = z.object({
|
|
199
|
-
/**
|
|
200
|
-
|
|
202
|
+
/** Bots may draft skills (skill_manage, /learn) for your review. Off unless
|
|
203
|
+
* explicitly enabled. */
|
|
204
|
+
skillAuthoring: z.boolean().optional(),
|
|
201
205
|
/** Show each tool run in the transcript. Off unless explicitly enabled. */
|
|
202
206
|
showToolCalls: z.boolean().optional(),
|
|
203
207
|
/** Experimental built-in browser. Off until explicitly enabled; each bot
|
|
@@ -378,8 +382,8 @@ export function localVmMode(cfg) {
|
|
|
378
382
|
export function localVmMaxInstances(cfg) {
|
|
379
383
|
return cfg.localVm?.maxInstances ?? DEFAULT_LOCAL_VM_MAX_INSTANCES;
|
|
380
384
|
}
|
|
381
|
-
export function
|
|
382
|
-
return cfg.features?.
|
|
385
|
+
export function skillAuthoringEnabled(cfg) {
|
|
386
|
+
return cfg.features?.skillAuthoring === true;
|
|
383
387
|
}
|
|
384
388
|
export function showToolCallsEnabled(cfg) {
|
|
385
389
|
return cfg.features?.showToolCalls === true;
|
|
@@ -407,6 +411,38 @@ export function ensureDirs() {
|
|
|
407
411
|
}
|
|
408
412
|
for (const dir of [DATA_DIR, EVENTS_DIR, NATIVE_DIR])
|
|
409
413
|
mkdirSync(dir, { recursive: true });
|
|
414
|
+
migrateLegacyFeatureFlags();
|
|
415
|
+
}
|
|
416
|
+
/** `features.skillRecorder` became `features.skillAuthoring` when the Teach a
|
|
417
|
+
* skill recorder was removed. featureConfigSchema is non-strict, so
|
|
418
|
+
* parseStoredConfig would silently drop the old key (reading the opt-in as
|
|
419
|
+
* off) while saveConfig's raw section merge would carry it on disk forever.
|
|
420
|
+
* Rewrite it once, here, before the server's single loadConfig() at boot: an
|
|
421
|
+
* explicit `skillAuthoring` already on disk wins over the legacy key, and a
|
|
422
|
+
* file without the legacy key is left untouched. */
|
|
423
|
+
function migrateLegacyFeatureFlags() {
|
|
424
|
+
const p = join(DATA_DIR, "config.json");
|
|
425
|
+
try {
|
|
426
|
+
if (!existsSync(p))
|
|
427
|
+
return;
|
|
428
|
+
const disk = jsonObjectSchema.safeParse(parseJson(readFileSync(p, "utf8")));
|
|
429
|
+
if (!disk.success)
|
|
430
|
+
return;
|
|
431
|
+
const features = jsonObjectSchema.safeParse(disk.data.features);
|
|
432
|
+
if (!features.success || !Object.hasOwn(features.data, "skillRecorder"))
|
|
433
|
+
return;
|
|
434
|
+
const next = { ...features.data };
|
|
435
|
+
if (!Object.hasOwn(next, "skillAuthoring"))
|
|
436
|
+
next.skillAuthoring = next.skillRecorder === true;
|
|
437
|
+
delete next.skillRecorder;
|
|
438
|
+
writeFileAtomic(p, JSON.stringify({ ...disk.data, features: next }, null, 2), { mode: 0o600 });
|
|
439
|
+
console.log(`[config] features.skillRecorder renamed to features.skillAuthoring (${String(next.skillAuthoring)})`);
|
|
440
|
+
}
|
|
441
|
+
catch (error) {
|
|
442
|
+
// A readable but unwritable config would otherwise lose the opt-in on
|
|
443
|
+
// every boot with no trace: parseStoredConfig drops the legacy key.
|
|
444
|
+
console.error(`[config] could not rename features.skillRecorder: ${error instanceof Error ? error.message : String(error)}`);
|
|
445
|
+
}
|
|
410
446
|
}
|
|
411
447
|
export function loadConfig() {
|
|
412
448
|
let cfg = {};
|
|
@@ -35,6 +35,7 @@ import { supportsApprovalMode } from "../../../shared/approval-mode.js";
|
|
|
35
35
|
// packaged server dir entirely. See server/proxy-paths.ts.
|
|
36
36
|
const COMPUTER_PROXY_PATH = SPAWNED_PROXIES.computer;
|
|
37
37
|
import { appendNative } from "../native.js";
|
|
38
|
+
import { commandSummary } from "../../tool-summary.js";
|
|
38
39
|
import { SPAWNED_PROXIES } from "../../proxy-paths.js";
|
|
39
40
|
const envOr = (key, fallback) => Number(process.env[key] ?? fallback);
|
|
40
41
|
const INIT_TIMEOUT = envOr("OPENMAUS_ACP_INIT_TIMEOUT_MS", 300_000);
|
|
@@ -568,6 +569,7 @@ export function createAcpDriver(support) {
|
|
|
568
569
|
itemType: "tool",
|
|
569
570
|
itemId: u.toolCallId,
|
|
570
571
|
title: String(u.rawInput?.command ?? u.title ?? "tool").slice(0, 80),
|
|
572
|
+
summary: commandSummary(u.rawInput),
|
|
571
573
|
});
|
|
572
574
|
break;
|
|
573
575
|
}
|
|
@@ -177,7 +177,7 @@ export function decodeCursorModelText(text) {
|
|
|
177
177
|
const line = raw.trim();
|
|
178
178
|
if (!line || line.startsWith("#") || /^available\s+models?\b/i.test(line) || /^models?\b/i.test(line))
|
|
179
179
|
continue;
|
|
180
|
-
const stripped = line.replace(/^[\s
|
|
180
|
+
const stripped = line.replace(/^[\s*•-]+\s*/, "");
|
|
181
181
|
const parts = stripped.split(/\s+[—–|:]\s+|\s+-\s+|\s{2,}/);
|
|
182
182
|
const id = (parts[0] ?? "").trim();
|
|
183
183
|
const rawLabel = parts.slice(1).join(" ").trim();
|
|
@@ -208,9 +208,13 @@ const support = {
|
|
|
208
208
|
// and BEFORE `stdio` (`grok agent -m slug stdio`). Putting -m first is
|
|
209
209
|
// accepted as a TUI option and then ignored, so ACP session/new keeps
|
|
210
210
|
// [models].default (grok-4.6) and oMLX never sees a request.
|
|
211
|
+
// Auto selects Grok's native classifier; if its feature gate is disabled,
|
|
212
|
+
// residual requests still ask. Never replace it with bypassPermissions.
|
|
213
|
+
// Verified: grok 1.0.3 --help and xai-org/grok-build@37949780,
|
|
214
|
+
// crates/codegen/xai-grok-pager-bin/src/main.rs:1259-1273.
|
|
211
215
|
spawnArgs: (config, turn) => [
|
|
212
216
|
"--permission-mode",
|
|
213
|
-
config.fullAuto ? "bypassPermissions" : "default",
|
|
217
|
+
config.fullAuto ? "bypassPermissions" : turn.approvalMode === "auto" ? "auto" : "default",
|
|
214
218
|
"agent",
|
|
215
219
|
...(turn.model ? ["-m", turn.model] : []),
|
|
216
220
|
// long form on purpose: `--effort` is documented as an alias, and an
|