openmausbot 0.1.56 → 0.1.57
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-B433sv8K.css +1 -0
- package/dist/assets/index-DSh8AIUy.js +264 -0
- package/dist/assets/{index-Dq2j4Ikr.js → index-jWqt5dmY.js} +1 -1
- package/dist/index.html +2 -2
- package/dist-server/companion/src/routes.js +6 -1
- package/dist-server/connector-proxy.js +31 -12
- package/dist-server/container-mcp.js +49 -31
- package/dist-server/drivers/agents-proxy.js +56 -2
- package/dist-server/index.js +1769 -338
- package/dist-server/server/auto-approve.js +24 -0
- package/dist-server/server/bot-folder.js +102 -0
- package/dist-server/server/bot-overview.js +206 -0
- package/dist-server/server/bot-package.js +5 -0
- package/dist-server/server/bot-profile.js +7 -0
- package/dist-server/server/connector-proxy.js +37 -16
- package/dist-server/server/container-computer.js +9 -2
- package/dist-server/server/drivers/agents-proxy.js +63 -2
- package/dist-server/server/drivers/antigravity-acp.js +61 -13
- package/dist-server/server/drivers/antigravity-runtime.js +47 -3
- package/dist-server/server/drivers/claude.js +7 -1
- package/dist-server/server/index.js +589 -103
- package/dist-server/server/mcp-bridge.js +73 -44
- package/dist-server/server/package-export.js +1 -0
- package/dist-server/server/profile-requests.js +332 -0
- package/dist-server/server/profile-revision.js +15 -0
- package/dist-server/server/profile-versions.js +154 -0
- package/dist-server/server/routine-requests.js +34 -1
- package/dist-server/server/routines.js +70 -2
- package/dist-server/server/setup-mode.js +63 -0
- package/dist-server/server/skill-fetch.js +67 -11
- package/dist-server/server/skills.js +1 -1
- package/dist-server/server/store.js +87 -7
- package/dist-server/server/system-prompt.js +49 -0
- package/dist-server/server/team-backup.js +2 -2
- package/dist-server/server/team-manifest.js +7 -0
- package/dist-server/shared/bot-profile.js +5 -1
- package/dist-server/shared/line-diff.js +42 -0
- package/dist-server/shared/profile-request.js +9 -0
- package/dist-server/shared/team-backup.js +4 -0
- package/dist-server/vps-container-mcp.js +49 -31
- package/package.json +1 -1
- package/dist/assets/index-CJBrtDbC.css +0 -1
- package/dist/assets/index-D0xt96rv.js +0 -263
|
@@ -127,6 +127,10 @@ export class AntigravityAcpClient {
|
|
|
127
127
|
diagnosticBuffer = "";
|
|
128
128
|
closed = false;
|
|
129
129
|
onAuthorizationUrl;
|
|
130
|
+
/** Settles once the runtime process is gone. On Windows a running
|
|
131
|
+
* executable pins its file and its directory, so an installer must not
|
|
132
|
+
* rename or delete either until this settles. */
|
|
133
|
+
exited;
|
|
130
134
|
constructor(runtime, profile, cwd, onAuthorizationUrl) {
|
|
131
135
|
this.onAuthorizationUrl = onAuthorizationUrl;
|
|
132
136
|
this.child = spawnCli(runtime.executablePath, process.platform === "linux" ? ["--uid="] : [], { cwd, env: profile.environment, stdio: ["pipe", "pipe", "pipe"] });
|
|
@@ -138,9 +142,14 @@ export class AntigravityAcpClient {
|
|
|
138
142
|
this.child.stderr.setEncoding("utf8");
|
|
139
143
|
this.child.stderr.on("data", (chunk) => this.consumeDiagnostics(chunk));
|
|
140
144
|
this.child.once("error", (error) => this.failAll(error));
|
|
141
|
-
this.
|
|
142
|
-
|
|
143
|
-
this.
|
|
145
|
+
this.exited = new Promise((resolve) => {
|
|
146
|
+
this.child.once("close", (code) => {
|
|
147
|
+
if (!this.closed)
|
|
148
|
+
this.failAll(new Error(`Antigravity ACP exited ${code ?? "unexpectedly"}.`));
|
|
149
|
+
resolve();
|
|
150
|
+
});
|
|
151
|
+
// Failed spawns also emit `close`. An `error` alone can instead mean
|
|
152
|
+
// a failed kill, and is not evidence that the runtime stopped.
|
|
144
153
|
});
|
|
145
154
|
}
|
|
146
155
|
consume(chunk) {
|
|
@@ -239,6 +248,22 @@ export class AntigravityAcpClient {
|
|
|
239
248
|
this.failAll(new Error("Antigravity ACP was closed."));
|
|
240
249
|
killCliTree(this.child);
|
|
241
250
|
}
|
|
251
|
+
/** Close, then wait (bounded) for the process to be gone. `killCliTree`
|
|
252
|
+
* on Windows asks taskkill and returns at once; the exit lands later. */
|
|
253
|
+
async closeAndWait(timeoutMs = 5_000) {
|
|
254
|
+
this.close();
|
|
255
|
+
let timer;
|
|
256
|
+
const timedOut = new Promise((resolve) => {
|
|
257
|
+
timer = setTimeout(() => resolve(false), timeoutMs);
|
|
258
|
+
timer.unref?.();
|
|
259
|
+
});
|
|
260
|
+
try {
|
|
261
|
+
return await Promise.race([this.exited.then(() => true), timedOut]);
|
|
262
|
+
}
|
|
263
|
+
finally {
|
|
264
|
+
clearTimeout(timer);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
242
267
|
}
|
|
243
268
|
export function parseAntigravityAuthorizationUrl(authorizationUrl) {
|
|
244
269
|
if (authorizationUrl.length > 16_384 || /\s/u.test(authorizationUrl)) {
|
|
@@ -407,26 +432,49 @@ export function isValidAntigravityInitializeResult(initialized, expectedVersion)
|
|
|
407
432
|
*/
|
|
408
433
|
export async function validateAntigravityRuntime(runtime, expectedVersion) {
|
|
409
434
|
const profileDirectory = await mkdtemp(join(tmpdir(), "openmaus-antigravity-verify-"));
|
|
435
|
+
let client;
|
|
436
|
+
let failed = false;
|
|
437
|
+
let failure;
|
|
410
438
|
try {
|
|
411
439
|
const profile = await prepareAntigravityProfile({
|
|
412
440
|
instanceId: `verify-${randomUUID()}`,
|
|
413
441
|
runtime,
|
|
414
442
|
profileDirectory,
|
|
415
443
|
});
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
throw new Error("The download did not identify as the expected Google Antigravity ACP release.");
|
|
421
|
-
}
|
|
444
|
+
client = new AntigravityAcpClient(runtime, profile, profileDirectory);
|
|
445
|
+
const initialized = await client.initialize();
|
|
446
|
+
if (!isValidAntigravityInitializeResult(initialized, expectedVersion)) {
|
|
447
|
+
throw new Error("The download did not identify as the expected Google Antigravity ACP release.");
|
|
422
448
|
}
|
|
423
|
-
|
|
424
|
-
|
|
449
|
+
}
|
|
450
|
+
catch (error) {
|
|
451
|
+
failed = true;
|
|
452
|
+
failure = error;
|
|
453
|
+
}
|
|
454
|
+
// The caller is about to rename the directory this executable runs from.
|
|
455
|
+
// Neither it nor the profile is safe to touch before confirmed close.
|
|
456
|
+
let stopped = !client;
|
|
457
|
+
try {
|
|
458
|
+
if (client) {
|
|
459
|
+
stopped = await client.closeAndWait();
|
|
460
|
+
if (!stopped)
|
|
461
|
+
throw new Error("Antigravity did not shut down after runtime verification.");
|
|
425
462
|
}
|
|
426
463
|
}
|
|
427
|
-
|
|
428
|
-
|
|
464
|
+
catch (error) {
|
|
465
|
+
if (!failed) {
|
|
466
|
+
failed = true;
|
|
467
|
+
failure = error;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
if (stopped) {
|
|
471
|
+
await rm(profileDirectory, { recursive: true, force: true, maxRetries: 4, retryDelay: 250 })
|
|
472
|
+
.catch((error) => {
|
|
473
|
+
console.warn(`antigravity: could not remove verification profile ${profileDirectory}: ${error instanceof Error ? error.message : String(error)}`);
|
|
474
|
+
});
|
|
429
475
|
}
|
|
476
|
+
if (failed)
|
|
477
|
+
throw failure;
|
|
430
478
|
}
|
|
431
479
|
/** One in-flight personal Google login per provider instance. */
|
|
432
480
|
export class AntigravityAuthController {
|
|
@@ -11,6 +11,33 @@ import { augmentedPath } from "../env-path.js";
|
|
|
11
11
|
import { resolveAntigravityReleaseAsset, } from "./antigravity-release.js";
|
|
12
12
|
const FREE_SPACE_MARGIN = 256 * 1024 * 1024;
|
|
13
13
|
const DOWNLOAD_TIMEOUT_MS = 45 * 60_000;
|
|
14
|
+
const STAGING_PREFIX = ".install-";
|
|
15
|
+
/** Windows refuses to rename or delete a file something still holds open,
|
|
16
|
+
* with EPERM/EBUSY/EACCES rather than a clear "in use": the runtime the
|
|
17
|
+
* validator just stopped (taskkill is asynchronous) or an antivirus scan of
|
|
18
|
+
* a brand-new executable. Retry briefly; persistent refusals still fail. */
|
|
19
|
+
export function transientWindowsFileError(error) {
|
|
20
|
+
const code = typeof error === "object" && error !== null ? Reflect.get(error, "code") : undefined;
|
|
21
|
+
return code === "EPERM" || code === "EBUSY" || code === "EACCES" || code === "ENOTEMPTY";
|
|
22
|
+
}
|
|
23
|
+
const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
24
|
+
/** Retry a filesystem step on the transient Windows refusals above, with
|
|
25
|
+
* growing delays (default: 8 tries, 0.25 s → 2 s, about 10 s in total).
|
|
26
|
+
* Anything else, and the final failure, surface unchanged. */
|
|
27
|
+
export async function retryOnWindowsFileLock(step, options = {}) {
|
|
28
|
+
const attempts = options.attempts ?? 8;
|
|
29
|
+
const sleep = options.sleep ?? wait;
|
|
30
|
+
for (let attempt = 1;; attempt += 1) {
|
|
31
|
+
try {
|
|
32
|
+
return await step();
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
if (attempt >= attempts || !transientWindowsFileError(error))
|
|
36
|
+
throw error;
|
|
37
|
+
await sleep(Math.min(2_000, (options.delayMs ?? 250) * 2 ** (attempt - 1)));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
14
41
|
const INSTALL_RECORD = ".install-complete.json";
|
|
15
42
|
export class AntigravitySetupError extends Error {
|
|
16
43
|
status = 409;
|
|
@@ -293,7 +320,10 @@ async function installOnce(options) {
|
|
|
293
320
|
// statfs is unavailable on a few filesystems. The bounded download and
|
|
294
321
|
// extraction checks still fail safely if the disk fills.
|
|
295
322
|
}
|
|
296
|
-
|
|
323
|
+
// Another app/server process may be installing into this versions folder.
|
|
324
|
+
// The in-memory coalescing map cannot protect its staging directory.
|
|
325
|
+
const staging = await mkdtemp(join(versions, `${STAGING_PREFIX}${randomUUID()}-`));
|
|
326
|
+
let failed = false;
|
|
297
327
|
try {
|
|
298
328
|
const archivePath = join(staging, "download.zip");
|
|
299
329
|
const runtimeDirectory = join(staging, "runtime");
|
|
@@ -364,7 +394,7 @@ async function installOnce(options) {
|
|
|
364
394
|
};
|
|
365
395
|
await writeFile(join(runtimeDirectory, INSTALL_RECORD), `${JSON.stringify(record)}\n`, { flag: "wx", mode: 0o600 });
|
|
366
396
|
try {
|
|
367
|
-
await rename(runtimeDirectory, destination);
|
|
397
|
+
await retryOnWindowsFileLock(() => rename(runtimeDirectory, destination));
|
|
368
398
|
}
|
|
369
399
|
catch (error) {
|
|
370
400
|
const winner = await completedRelease(destination, asset);
|
|
@@ -376,8 +406,22 @@ async function installOnce(options) {
|
|
|
376
406
|
throw new Error("The installed Antigravity runtime is incomplete.");
|
|
377
407
|
return installed;
|
|
378
408
|
}
|
|
409
|
+
catch (error) {
|
|
410
|
+
failed = true;
|
|
411
|
+
throw error;
|
|
412
|
+
}
|
|
379
413
|
finally {
|
|
380
|
-
|
|
414
|
+
// Cleanup must never replace the real error with its own: a user who
|
|
415
|
+
// saw "EPERM: unlink agy_acp_server.exe" was looking at this line, not
|
|
416
|
+
// at why the install failed. Only clean up this attempt's directory;
|
|
417
|
+
// if it stays locked, log and leave it without touching other attempts.
|
|
418
|
+
try {
|
|
419
|
+
await retryOnWindowsFileLock(() => rm(staging, { recursive: true, force: true }));
|
|
420
|
+
}
|
|
421
|
+
catch (cleanupError) {
|
|
422
|
+
const detail = cleanupError instanceof Error ? cleanupError.message : String(cleanupError);
|
|
423
|
+
console.warn(`antigravity: could not remove the install folder ${staging} (${detail})${failed ? "" : "; the install itself succeeded"}`);
|
|
424
|
+
}
|
|
381
425
|
}
|
|
382
426
|
}
|
|
383
427
|
/** Coalesce concurrent clicks so only one large Google artifact is fetched. */
|
|
@@ -774,7 +774,10 @@ export const ClaudeDriver = {
|
|
|
774
774
|
if (live.idleTimer)
|
|
775
775
|
clearTimeout(live.idleTimer);
|
|
776
776
|
live.turn = { turnId, settled: false, sawStreamDelta: false };
|
|
777
|
-
active.set(threadId, { stop: () =>
|
|
777
|
+
active.set(threadId, { stop: () => {
|
|
778
|
+
closeSession(threadId, "interrupted");
|
|
779
|
+
killCliTree(live.child);
|
|
780
|
+
}, turnId, broker: live.broker });
|
|
778
781
|
emit({ ...base(threadId, turnId), type: "turn.started" });
|
|
779
782
|
const written = await writeUser(live, threadId, promptMsg);
|
|
780
783
|
if (!written) {
|
|
@@ -1175,6 +1178,9 @@ export const ClaudeDriver = {
|
|
|
1175
1178
|
sessions.delete(threadId);
|
|
1176
1179
|
});
|
|
1177
1180
|
const stop = () => {
|
|
1181
|
+
// taskkill is asynchronous on Windows. Retire steering and approvals
|
|
1182
|
+
// now, before a still-connected child can submit more work.
|
|
1183
|
+
closeSession(threadId, "interrupted");
|
|
1178
1184
|
retry.cancelled = true;
|
|
1179
1185
|
retryAbort.abort();
|
|
1180
1186
|
killCliTree(child);
|