usebeeline 0.0.107 → 0.0.109
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/usebeeline.mjs +616 -99
- package/package.json +1 -1
package/dist/usebeeline.mjs
CHANGED
|
@@ -3989,7 +3989,7 @@ import { constants as fsConstants2 } from "node:fs";
|
|
|
3989
3989
|
import { access, chmod as chmod5, lstat as lstat3, mkdir as mkdir15, open, readFile as readFile10, rename as rename4, rm as rm6, symlink as symlink3, writeFile as writeFile10 } from "node:fs/promises";
|
|
3990
3990
|
import { spawn as spawn6 } from "node:child_process";
|
|
3991
3991
|
import { homedir as homedir9 } from "node:os";
|
|
3992
|
-
import { dirname as dirname11, join as
|
|
3992
|
+
import { dirname as dirname11, join as join10, resolve as resolve22 } from "node:path";
|
|
3993
3993
|
function anchorLayout(rawLibDir) {
|
|
3994
3994
|
const libDir = resolve22(rawLibDir);
|
|
3995
3995
|
const segments = libDir.split(/[/\\]/);
|
|
@@ -4039,7 +4039,7 @@ function hostPlatformKey() {
|
|
|
4039
4039
|
return `${os}-${arch}`;
|
|
4040
4040
|
}
|
|
4041
4041
|
function bundleJsonCandidates(bundleDir) {
|
|
4042
|
-
return [
|
|
4042
|
+
return [join10(bundleDir, "lib", "beeline", "bundle.json"), join10(bundleDir, "bundle.json")];
|
|
4043
4043
|
}
|
|
4044
4044
|
async function readBundleJson(bundleDir) {
|
|
4045
4045
|
let raw;
|
|
@@ -4063,7 +4063,7 @@ async function readBundleJson(bundleDir) {
|
|
|
4063
4063
|
}
|
|
4064
4064
|
}
|
|
4065
4065
|
function updateStatePath(layout) {
|
|
4066
|
-
return
|
|
4066
|
+
return join10(layout.releasesRoot, ".state", "update-state.json");
|
|
4067
4067
|
}
|
|
4068
4068
|
async function readUpdateState(layout) {
|
|
4069
4069
|
try {
|
|
@@ -4073,7 +4073,7 @@ async function readUpdateState(layout) {
|
|
|
4073
4073
|
}
|
|
4074
4074
|
}
|
|
4075
4075
|
async function writeUpdateState(layout, state) {
|
|
4076
|
-
await mkdir15(
|
|
4076
|
+
await mkdir15(join10(layout.releasesRoot, ".state"), { recursive: true });
|
|
4077
4077
|
await writeFile10(updateStatePath(layout), `${JSON.stringify(state, null, 2)}
|
|
4078
4078
|
`, "utf8");
|
|
4079
4079
|
}
|
|
@@ -4155,7 +4155,7 @@ function run(command, args, timeoutMs) {
|
|
|
4155
4155
|
});
|
|
4156
4156
|
}
|
|
4157
4157
|
function entrypointCandidates(bundleDir) {
|
|
4158
|
-
return [
|
|
4158
|
+
return [join10(bundleDir, BUNDLE_ENTRYPOINT), join10(bundleDir, "beeline-cli.mjs")];
|
|
4159
4159
|
}
|
|
4160
4160
|
async function resolveBundleEntrypoint(bundleDir) {
|
|
4161
4161
|
for (const candidate of entrypointCandidates(bundleDir)) {
|
|
@@ -4177,8 +4177,8 @@ async function stageRelease(layout, manifestUrl, published, opts = {}) {
|
|
|
4177
4177
|
const fetchImpl = opts.fetchImpl ?? fetch;
|
|
4178
4178
|
const log2 = opts.logger ?? ((line) => console.log(`[body] self-update: ${line}`));
|
|
4179
4179
|
const releaseId = sanitizeReleaseId(published.commit ?? published.version ?? `release-${Date.now()}`);
|
|
4180
|
-
const releaseDir =
|
|
4181
|
-
const okMarker =
|
|
4180
|
+
const releaseDir = join10(layout.releasesRoot, releaseId);
|
|
4181
|
+
const okMarker = join10(releaseDir, ".stage-ok");
|
|
4182
4182
|
let previouslyVerified = false;
|
|
4183
4183
|
try {
|
|
4184
4184
|
const recorded = await readFile10(okMarker, "utf8");
|
|
@@ -4188,7 +4188,7 @@ async function stageRelease(layout, manifestUrl, published, opts = {}) {
|
|
|
4188
4188
|
} catch {
|
|
4189
4189
|
}
|
|
4190
4190
|
await mkdir15(releaseDir, { recursive: true });
|
|
4191
|
-
const tempArchive =
|
|
4191
|
+
const tempArchive = join10(layout.releasesRoot, `.download-${releaseId}-${process.pid}.tar.gz`);
|
|
4192
4192
|
try {
|
|
4193
4193
|
log2(`downloading ${published.file}`);
|
|
4194
4194
|
const response = await fetchImpl(archiveUrlFor(manifestUrl, published.file), {
|
|
@@ -4228,13 +4228,13 @@ async function stageRelease(layout, manifestUrl, published, opts = {}) {
|
|
|
4228
4228
|
throw new Error(`extracting bundle failed: ${extract2.stderr}`);
|
|
4229
4229
|
for (const relative3 of requiredBundlePaths()) {
|
|
4230
4230
|
try {
|
|
4231
|
-
await access(
|
|
4231
|
+
await access(join10(releaseDir, relative3), fsConstants2.F_OK);
|
|
4232
4232
|
} catch {
|
|
4233
4233
|
throw new Error(`staged bundle is missing ${relative3}`);
|
|
4234
4234
|
}
|
|
4235
4235
|
}
|
|
4236
4236
|
if (opts.smokeTestCli !== false) {
|
|
4237
|
-
const probe = await run(process.execPath, [
|
|
4237
|
+
const probe = await run(process.execPath, [join10(releaseDir, BUNDLE_ENTRYPOINT), "--version"], 6e4);
|
|
4238
4238
|
if (probe.status !== 0) {
|
|
4239
4239
|
throw new Error(`staged bundle failed its startup smoke test (--version exited ${probe.status})${probe.stderr ? `: ${probe.stderr.trim()}` : ""}`);
|
|
4240
4240
|
}
|
|
@@ -4272,8 +4272,8 @@ async function replaceFile(path, contents, mode) {
|
|
|
4272
4272
|
await rename4(temp, path);
|
|
4273
4273
|
}
|
|
4274
4274
|
async function activateRelease(layout, releaseId) {
|
|
4275
|
-
const releaseDir =
|
|
4276
|
-
await access(
|
|
4275
|
+
const releaseDir = join10(layout.releasesRoot, releaseId);
|
|
4276
|
+
await access(join10(releaseDir, BUNDLE_ENTRYPOINT), fsConstants2.F_OK);
|
|
4277
4277
|
await mkdir15(layout.releasesRoot, { recursive: true });
|
|
4278
4278
|
await mkdir15(layout.binDir, { recursive: true });
|
|
4279
4279
|
let previousReleaseId = await activeReleaseId(layout);
|
|
@@ -4281,12 +4281,12 @@ async function activateRelease(layout, releaseId) {
|
|
|
4281
4281
|
if (kind === "directory") {
|
|
4282
4282
|
const legacyIdentity = await readBundleJson(layout.libDir);
|
|
4283
4283
|
const legacyId = sanitizeReleaseId(legacyIdentity?.commit ?? legacyIdentity?.version ?? `legacy-${Date.now()}`);
|
|
4284
|
-
const legacyDir =
|
|
4284
|
+
const legacyDir = join10(layout.releasesRoot, legacyId);
|
|
4285
4285
|
try {
|
|
4286
4286
|
await access(legacyDir, fsConstants2.F_OK);
|
|
4287
4287
|
previousReleaseId = `${legacyId}-${Date.now()}`;
|
|
4288
|
-
await rename4(layout.libDir,
|
|
4289
|
-
await normalizeLegacyBundleShape(
|
|
4288
|
+
await rename4(layout.libDir, join10(layout.releasesRoot, previousReleaseId));
|
|
4289
|
+
await normalizeLegacyBundleShape(join10(layout.releasesRoot, previousReleaseId));
|
|
4290
4290
|
} catch {
|
|
4291
4291
|
await rename4(layout.libDir, legacyDir);
|
|
4292
4292
|
await normalizeLegacyBundleShape(legacyDir);
|
|
@@ -4295,18 +4295,18 @@ async function activateRelease(layout, releaseId) {
|
|
|
4295
4295
|
}
|
|
4296
4296
|
const tempLink = `${layout.libDir}.new-${process.pid}`;
|
|
4297
4297
|
await rm6(tempLink, { force: true });
|
|
4298
|
-
await symlink3(
|
|
4298
|
+
await symlink3(join10("beeline-releases", releaseId), tempLink);
|
|
4299
4299
|
await rename4(tempLink, layout.libDir);
|
|
4300
4300
|
await fsyncDir(dirname11(layout.libDir));
|
|
4301
4301
|
await writeBinForwarders(layout, releaseDir);
|
|
4302
4302
|
return { previousReleaseId };
|
|
4303
4303
|
}
|
|
4304
4304
|
async function normalizeLegacyBundleShape(bundleDir) {
|
|
4305
|
-
const innerLib =
|
|
4305
|
+
const innerLib = join10(bundleDir, "lib", "beeline");
|
|
4306
4306
|
let anyFlat = false;
|
|
4307
4307
|
for (const name of LEGACY_FLAT_BUNDLE_FILES) {
|
|
4308
4308
|
try {
|
|
4309
|
-
await access(
|
|
4309
|
+
await access(join10(bundleDir, name), fsConstants2.F_OK);
|
|
4310
4310
|
anyFlat = true;
|
|
4311
4311
|
break;
|
|
4312
4312
|
} catch {
|
|
@@ -4317,11 +4317,11 @@ async function normalizeLegacyBundleShape(bundleDir) {
|
|
|
4317
4317
|
await mkdir15(innerLib, { recursive: true });
|
|
4318
4318
|
for (const name of LEGACY_FLAT_BUNDLE_FILES) {
|
|
4319
4319
|
try {
|
|
4320
|
-
await access(
|
|
4320
|
+
await access(join10(innerLib, name), fsConstants2.F_OK);
|
|
4321
4321
|
continue;
|
|
4322
4322
|
} catch {
|
|
4323
4323
|
}
|
|
4324
|
-
await rename4(
|
|
4324
|
+
await rename4(join10(bundleDir, name), join10(innerLib, name)).catch(() => void 0);
|
|
4325
4325
|
}
|
|
4326
4326
|
}
|
|
4327
4327
|
async function writeBinForwarders(layout, activeBundleRoot) {
|
|
@@ -4330,13 +4330,13 @@ async function writeBinForwarders(layout, activeBundleRoot) {
|
|
|
4330
4330
|
...Object.entries(FORWARDER_ALIASES).map(([alias, tool]) => [alias, tool])
|
|
4331
4331
|
];
|
|
4332
4332
|
for (const [name, tool] of entries) {
|
|
4333
|
-
const target =
|
|
4333
|
+
const target = join10(activeBundleRoot, "bin", tool);
|
|
4334
4334
|
try {
|
|
4335
4335
|
await access(target, fsConstants2.X_OK);
|
|
4336
4336
|
} catch {
|
|
4337
4337
|
continue;
|
|
4338
4338
|
}
|
|
4339
|
-
await replaceFile(
|
|
4339
|
+
await replaceFile(join10(layout.binDir, name), forwarderScript(tool), 493);
|
|
4340
4340
|
}
|
|
4341
4341
|
}
|
|
4342
4342
|
async function repairInstallForwarders(layout, opts = {}) {
|
|
@@ -4345,7 +4345,7 @@ async function repairInstallForwarders(layout, opts = {}) {
|
|
|
4345
4345
|
const forwarderHealthy = async (name, tool) => {
|
|
4346
4346
|
let current;
|
|
4347
4347
|
try {
|
|
4348
|
-
current = await readFile10(
|
|
4348
|
+
current = await readFile10(join10(layout.binDir, name), "utf8");
|
|
4349
4349
|
} catch {
|
|
4350
4350
|
current = void 0;
|
|
4351
4351
|
}
|
|
@@ -4364,19 +4364,19 @@ async function repairInstallForwarders(layout, opts = {}) {
|
|
|
4364
4364
|
return true;
|
|
4365
4365
|
}
|
|
4366
4366
|
async function rollbackToPreviousRelease(layout, previousReleaseId) {
|
|
4367
|
-
const releaseDir =
|
|
4367
|
+
const releaseDir = join10(layout.releasesRoot, previousReleaseId);
|
|
4368
4368
|
const entrypoint = await resolveBundleEntrypoint(releaseDir);
|
|
4369
4369
|
if (!entrypoint) {
|
|
4370
4370
|
throw new Error(`release ${previousReleaseId} has no runnable CLI entrypoint`);
|
|
4371
4371
|
}
|
|
4372
4372
|
const tempLink = `${layout.libDir}.rollback-${process.pid}`;
|
|
4373
4373
|
await rm6(tempLink, { force: true });
|
|
4374
|
-
await symlink3(
|
|
4374
|
+
await symlink3(join10("beeline-releases", previousReleaseId), tempLink);
|
|
4375
4375
|
await rename4(tempLink, layout.libDir);
|
|
4376
4376
|
await fsyncDir(dirname11(layout.libDir));
|
|
4377
4377
|
}
|
|
4378
4378
|
function updateAttemptPath(layout) {
|
|
4379
|
-
return
|
|
4379
|
+
return join10(layout.releasesRoot, ".state", "update-attempt.json");
|
|
4380
4380
|
}
|
|
4381
4381
|
async function readUpdateAttempt(layout) {
|
|
4382
4382
|
try {
|
|
@@ -4390,7 +4390,7 @@ async function readUpdateAttempt(layout) {
|
|
|
4390
4390
|
}
|
|
4391
4391
|
}
|
|
4392
4392
|
async function writeUpdateAttempt(layout, record3) {
|
|
4393
|
-
await mkdir15(
|
|
4393
|
+
await mkdir15(join10(layout.releasesRoot, ".state"), { recursive: true });
|
|
4394
4394
|
const path = updateAttemptPath(layout);
|
|
4395
4395
|
const staged = `${path}.${process.pid}.tmp`;
|
|
4396
4396
|
await writeFile10(staged, `${JSON.stringify(record3, null, 2)}
|
|
@@ -8156,9 +8156,390 @@ async function syncAgentModelCatalog(input) {
|
|
|
8156
8156
|
}
|
|
8157
8157
|
}
|
|
8158
8158
|
|
|
8159
|
+
// apps/body/dist/connector-google.js
|
|
8160
|
+
import { readFileSync as readFileSync3 } from "node:fs";
|
|
8161
|
+
import { join as join2 } from "node:path";
|
|
8162
|
+
|
|
8163
|
+
// apps/body/dist/google-workspace-client.js
|
|
8164
|
+
function credentialsTokenSource(credentials) {
|
|
8165
|
+
return {
|
|
8166
|
+
accessToken: () => Promise.resolve(credentials.accessToken),
|
|
8167
|
+
accountEmail: credentials.accountEmail ? () => credentials.accountEmail : void 0
|
|
8168
|
+
};
|
|
8169
|
+
}
|
|
8170
|
+
var defaultGoogleApiTransport = {
|
|
8171
|
+
async request(method, url, body, headers) {
|
|
8172
|
+
const response = await fetch(url, {
|
|
8173
|
+
method,
|
|
8174
|
+
headers: {
|
|
8175
|
+
"content-type": "application/json",
|
|
8176
|
+
...headers
|
|
8177
|
+
},
|
|
8178
|
+
...body !== void 0 ? { body: JSON.stringify(body) } : {}
|
|
8179
|
+
});
|
|
8180
|
+
let json = null;
|
|
8181
|
+
const text2 = await response.text();
|
|
8182
|
+
if (text2) {
|
|
8183
|
+
try {
|
|
8184
|
+
json = JSON.parse(text2);
|
|
8185
|
+
} catch {
|
|
8186
|
+
json = { raw: text2 };
|
|
8187
|
+
}
|
|
8188
|
+
}
|
|
8189
|
+
return { status: response.status, json };
|
|
8190
|
+
}
|
|
8191
|
+
};
|
|
8192
|
+
var GoogleApiError = class extends Error {
|
|
8193
|
+
status;
|
|
8194
|
+
detail;
|
|
8195
|
+
constructor(status, detail) {
|
|
8196
|
+
super(`Google API ${status}: ${detail}`);
|
|
8197
|
+
this.status = status;
|
|
8198
|
+
this.detail = detail;
|
|
8199
|
+
}
|
|
8200
|
+
};
|
|
8201
|
+
var MAX_RESULTS = 25;
|
|
8202
|
+
function assertOk(status, json) {
|
|
8203
|
+
if (status >= 200 && status < 300)
|
|
8204
|
+
return;
|
|
8205
|
+
const detail = json && typeof json === "object" && "error" in json ? JSON.stringify(json.error) : `HTTP ${status}`;
|
|
8206
|
+
throw new GoogleApiError(status, detail);
|
|
8207
|
+
}
|
|
8208
|
+
function rfc822(input) {
|
|
8209
|
+
return `To: ${input.to}\r
|
|
8210
|
+
Subject: ${input.subject}\r
|
|
8211
|
+
Content-Type: text/plain; charset="UTF-8"\r
|
|
8212
|
+
\r
|
|
8213
|
+
${input.body}`;
|
|
8214
|
+
}
|
|
8215
|
+
function googleWorkspaceClient(tokenSource, transport = defaultGoogleApiTransport) {
|
|
8216
|
+
const authorized = {
|
|
8217
|
+
async request(method, url, body) {
|
|
8218
|
+
const token = await tokenSource.accessToken();
|
|
8219
|
+
const response = await transport.request(method, url, body, {
|
|
8220
|
+
authorization: `Bearer ${token}`
|
|
8221
|
+
});
|
|
8222
|
+
if (response.status === 401) {
|
|
8223
|
+
throw new GoogleApiError(401, "access token rejected; reconnect the Google tool");
|
|
8224
|
+
}
|
|
8225
|
+
return response;
|
|
8226
|
+
}
|
|
8227
|
+
};
|
|
8228
|
+
const gmailFetch = async (path) => {
|
|
8229
|
+
const { status, json } = await authorized.request("GET", `https://gmail.googleapis.com/gmail/v1/users/me${path}`);
|
|
8230
|
+
assertOk(status, json);
|
|
8231
|
+
return json;
|
|
8232
|
+
};
|
|
8233
|
+
return {
|
|
8234
|
+
gmail: {
|
|
8235
|
+
async listMessages(query) {
|
|
8236
|
+
const params = new URLSearchParams({ maxResults: String(MAX_RESULTS) });
|
|
8237
|
+
if (query)
|
|
8238
|
+
params.set("q", query);
|
|
8239
|
+
const { status, json } = await authorized.request("GET", `https://gmail.googleapis.com/gmail/v1/users/me/messages?${params}`);
|
|
8240
|
+
assertOk(status, json);
|
|
8241
|
+
const messages = json.messages ?? [];
|
|
8242
|
+
return messages.map((entry) => ({ id: entry.id, snippet: entry.snippet }));
|
|
8243
|
+
},
|
|
8244
|
+
async getMessage(id) {
|
|
8245
|
+
const message = await gmailFetch(`/messages/${encodeURIComponent(id)}?format=metadata`);
|
|
8246
|
+
const snippet = typeof message.snippet === "string" ? message.snippet : void 0;
|
|
8247
|
+
const payload = message.payload;
|
|
8248
|
+
const subject = payload?.headers?.find((header) => header.name === "Subject")?.value;
|
|
8249
|
+
const bodyText = payload?.body?.data !== void 0 ? Buffer.from(payload.body.data, "base64url").toString("utf8") : void 0;
|
|
8250
|
+
return { id, snippet: subject ?? snippet, body: bodyText };
|
|
8251
|
+
},
|
|
8252
|
+
async createDraft(input) {
|
|
8253
|
+
const { status, json } = await authorized.request("POST", "https://gmail.googleapis.com/gmail/v1/users/me/drafts", { message: { raw: Buffer.from(rfc822(input), "utf8").toString("base64url") } });
|
|
8254
|
+
assertOk(status, json);
|
|
8255
|
+
return { id: String(json.id) };
|
|
8256
|
+
},
|
|
8257
|
+
async sendMessage(input) {
|
|
8258
|
+
const raw = Buffer.from(rfc822(input), "utf8").toString("base64url");
|
|
8259
|
+
const { status, json } = await authorized.request("POST", "https://gmail.googleapis.com/gmail/v1/users/me/messages/send", { raw });
|
|
8260
|
+
assertOk(status, json);
|
|
8261
|
+
return { id: String(json.id) };
|
|
8262
|
+
}
|
|
8263
|
+
},
|
|
8264
|
+
calendar: {
|
|
8265
|
+
async listEvents(input) {
|
|
8266
|
+
const params = new URLSearchParams({
|
|
8267
|
+
maxResults: String(input?.maxResults ?? MAX_RESULTS),
|
|
8268
|
+
singleEvents: "true",
|
|
8269
|
+
orderBy: "startTime",
|
|
8270
|
+
timeMin: (/* @__PURE__ */ new Date()).toISOString()
|
|
8271
|
+
});
|
|
8272
|
+
const { status, json } = await authorized.request("GET", `https://www.googleapis.com/calendar/v3/calendars/primary/events?${params}`);
|
|
8273
|
+
assertOk(status, json);
|
|
8274
|
+
const events = json.items ?? [];
|
|
8275
|
+
return events.map((event) => ({
|
|
8276
|
+
id: String(event.id),
|
|
8277
|
+
summary: typeof event.summary === "string" ? event.summary : void 0,
|
|
8278
|
+
start: event.start?.dateTime,
|
|
8279
|
+
end: event.end?.dateTime
|
|
8280
|
+
}));
|
|
8281
|
+
},
|
|
8282
|
+
async createEvent(input) {
|
|
8283
|
+
const { status, json } = await authorized.request("POST", `https://www.googleapis.com/calendar/v3/calendars/${encodeURIComponent(input.calendarId ?? "primary")}/events`, {
|
|
8284
|
+
summary: input.summary,
|
|
8285
|
+
...input.description ? { description: input.description } : {},
|
|
8286
|
+
start: { dateTime: input.start },
|
|
8287
|
+
end: { dateTime: input.end }
|
|
8288
|
+
});
|
|
8289
|
+
assertOk(status, json);
|
|
8290
|
+
const event = json;
|
|
8291
|
+
return { id: event.id, ...event.htmlLink ? { htmlLink: event.htmlLink } : {} };
|
|
8292
|
+
}
|
|
8293
|
+
},
|
|
8294
|
+
drive: {
|
|
8295
|
+
async searchFiles(query) {
|
|
8296
|
+
const params = new URLSearchParams({
|
|
8297
|
+
q: `name contains '${query.replace(/'/g, "\\'")}' and trashed = false`,
|
|
8298
|
+
pageSize: String(MAX_RESULTS),
|
|
8299
|
+
fields: "files(id,name,mimeType)"
|
|
8300
|
+
});
|
|
8301
|
+
const { status, json } = await authorized.request("GET", `https://www.googleapis.com/drive/v3/files?${params}`);
|
|
8302
|
+
assertOk(status, json);
|
|
8303
|
+
return (json.files ?? []).map((file) => ({
|
|
8304
|
+
id: String(file.id),
|
|
8305
|
+
name: typeof file.name === "string" ? file.name : void 0,
|
|
8306
|
+
mimeType: typeof file.mimeType === "string" ? file.mimeType : void 0
|
|
8307
|
+
}));
|
|
8308
|
+
},
|
|
8309
|
+
async readFile(fileId) {
|
|
8310
|
+
const meta = await authorized.request("GET", `https://www.googleapis.com/drive/v3/files/${encodeURIComponent(fileId)}?fields=id,name`);
|
|
8311
|
+
assertOk(meta.status, meta.json);
|
|
8312
|
+
const content = await authorized.request("GET", `https://www.googleapis.com/drive/v3/files/${encodeURIComponent(fileId)}?alt=media`);
|
|
8313
|
+
assertOk(content.status, content.json);
|
|
8314
|
+
const body = content.json;
|
|
8315
|
+
return {
|
|
8316
|
+
id: fileId,
|
|
8317
|
+
name: meta.json.name,
|
|
8318
|
+
content: body.raw ?? JSON.stringify(content.json)
|
|
8319
|
+
};
|
|
8320
|
+
}
|
|
8321
|
+
},
|
|
8322
|
+
youtube: {
|
|
8323
|
+
async listPlaylists(mine = true) {
|
|
8324
|
+
const params = new URLSearchParams({
|
|
8325
|
+
part: "snippet",
|
|
8326
|
+
maxResults: String(MAX_RESULTS),
|
|
8327
|
+
...mine ? { mine: "true" } : {}
|
|
8328
|
+
});
|
|
8329
|
+
const { status, json } = await authorized.request("GET", `https://www.googleapis.com/youtube/v3/playlists?${params}`);
|
|
8330
|
+
assertOk(status, json);
|
|
8331
|
+
return (json.items ?? []).map((item) => ({
|
|
8332
|
+
id: String(item.id),
|
|
8333
|
+
title: item.snippet?.title
|
|
8334
|
+
}));
|
|
8335
|
+
},
|
|
8336
|
+
async listPlaylistItems(playlistId) {
|
|
8337
|
+
const params = new URLSearchParams({
|
|
8338
|
+
part: "snippet",
|
|
8339
|
+
maxResults: String(MAX_RESULTS),
|
|
8340
|
+
playlistId
|
|
8341
|
+
});
|
|
8342
|
+
const { status, json } = await authorized.request("GET", `https://www.googleapis.com/youtube/v3/playlistItems?${params}`);
|
|
8343
|
+
assertOk(status, json);
|
|
8344
|
+
return (json.items ?? []).map((item) => ({
|
|
8345
|
+
videoId: String(item.snippet?.resourceId?.videoId ?? item.id),
|
|
8346
|
+
title: item.snippet?.title
|
|
8347
|
+
}));
|
|
8348
|
+
},
|
|
8349
|
+
async getTranscript(videoId) {
|
|
8350
|
+
const params = new URLSearchParams({ lang: "en", v: videoId });
|
|
8351
|
+
const { status, json } = await authorized.request("GET", `https://video.google.com/timedtext?${params}`);
|
|
8352
|
+
if (status < 200 || status >= 300) {
|
|
8353
|
+
throw new GoogleApiError(status, `no caption track could be fetched for ${videoId} (timedtext ${status})`);
|
|
8354
|
+
}
|
|
8355
|
+
const raw = json.raw ?? "";
|
|
8356
|
+
const transcript = raw.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
8357
|
+
if (!transcript) {
|
|
8358
|
+
throw new GoogleApiError(404, `video ${videoId} has no fetchable captions`);
|
|
8359
|
+
}
|
|
8360
|
+
return { videoId, transcript };
|
|
8361
|
+
}
|
|
8362
|
+
},
|
|
8363
|
+
async verify() {
|
|
8364
|
+
try {
|
|
8365
|
+
const { status, json } = await authorized.request("GET", "https://www.googleapis.com/oauth2/v3/userinfo");
|
|
8366
|
+
if (status === 401)
|
|
8367
|
+
return { ok: false, reason: "Google rejected the access token" };
|
|
8368
|
+
assertOk(status, json);
|
|
8369
|
+
const email = json.email;
|
|
8370
|
+
return { ok: true, ...email ? { account: email } : {} };
|
|
8371
|
+
} catch (error) {
|
|
8372
|
+
return {
|
|
8373
|
+
ok: false,
|
|
8374
|
+
reason: error instanceof Error ? error.message : String(error)
|
|
8375
|
+
};
|
|
8376
|
+
}
|
|
8377
|
+
}
|
|
8378
|
+
};
|
|
8379
|
+
}
|
|
8380
|
+
|
|
8381
|
+
// apps/body/dist/connector-google.js
|
|
8382
|
+
var GOOGLE_TOOL_SCOPES = {
|
|
8383
|
+
"google-gmail": [
|
|
8384
|
+
"https://www.googleapis.com/auth/gmail.send",
|
|
8385
|
+
"https://www.googleapis.com/auth/gmail.readonly",
|
|
8386
|
+
"https://www.googleapis.com/auth/gmail.compose"
|
|
8387
|
+
],
|
|
8388
|
+
"google-calendar": ["https://www.googleapis.com/auth/calendar.events", "https://www.googleapis.com/auth/calendar.readonly"],
|
|
8389
|
+
"google-drive": ["https://www.googleapis.com/auth/drive.readonly"],
|
|
8390
|
+
"google-youtube": ["https://www.googleapis.com/auth/youtube.readonly"]
|
|
8391
|
+
};
|
|
8392
|
+
function isGoogleToolConnectorType(type) {
|
|
8393
|
+
return type in GOOGLE_TOOL_SCOPES;
|
|
8394
|
+
}
|
|
8395
|
+
async function readGoogleCredentialsFromVault(mcp) {
|
|
8396
|
+
if (!mcp)
|
|
8397
|
+
return { source: "unavailable", reason: "no Trusty Squire connector is paired" };
|
|
8398
|
+
let raw;
|
|
8399
|
+
try {
|
|
8400
|
+
raw = await mcp.call("google_oauth_credentials", {});
|
|
8401
|
+
} catch (error) {
|
|
8402
|
+
return {
|
|
8403
|
+
source: "unavailable",
|
|
8404
|
+
reason: `Squire has no Google OAuth grant on record yet (connect your Google account in Squire first: ${describe(error)})`
|
|
8405
|
+
};
|
|
8406
|
+
}
|
|
8407
|
+
const record3 = raw && typeof raw === "object" ? raw : {};
|
|
8408
|
+
const inner = record3.credentials && typeof record3.credentials === "object" ? record3.credentials : record3;
|
|
8409
|
+
const accessToken = inner.accessToken ?? inner.access_token;
|
|
8410
|
+
if (!accessToken || typeof accessToken !== "string") {
|
|
8411
|
+
return { source: "unavailable", reason: "Squire returned a Google grant without an access token" };
|
|
8412
|
+
}
|
|
8413
|
+
return {
|
|
8414
|
+
source: "squire",
|
|
8415
|
+
credentials: {
|
|
8416
|
+
accessToken,
|
|
8417
|
+
refreshToken: typeof record3.refreshToken === "string" ? record3.refreshToken : typeof record3.refresh_token === "string" ? record3.refresh_token : void 0,
|
|
8418
|
+
expiresAt: typeof record3.expiresAt === "number" ? record3.expiresAt : void 0,
|
|
8419
|
+
accountEmail: typeof record3.accountEmail === "string" ? record3.accountEmail : typeof record3.email === "string" ? record3.email : void 0
|
|
8420
|
+
}
|
|
8421
|
+
};
|
|
8422
|
+
}
|
|
8423
|
+
function manualGoogleCredentialsSearchPaths(home) {
|
|
8424
|
+
return [join2(home, "google-credentials.json")];
|
|
8425
|
+
}
|
|
8426
|
+
function loadManualGoogleCredentials(home, env = process.env) {
|
|
8427
|
+
if (env.BEELINE_GOOGLE_ACCESS_TOKEN) {
|
|
8428
|
+
return {
|
|
8429
|
+
source: "manual",
|
|
8430
|
+
credentials: { accessToken: env.BEELINE_GOOGLE_ACCESS_TOKEN }
|
|
8431
|
+
};
|
|
8432
|
+
}
|
|
8433
|
+
for (const path of manualGoogleCredentialsSearchPaths(home)) {
|
|
8434
|
+
try {
|
|
8435
|
+
const parsed = JSON.parse(readFileSync3(path, "utf8"));
|
|
8436
|
+
if (typeof parsed.accessToken === "string" || typeof parsed.access_token === "string") {
|
|
8437
|
+
return {
|
|
8438
|
+
source: "manual",
|
|
8439
|
+
credentials: {
|
|
8440
|
+
accessToken: parsed.accessToken ?? parsed.access_token,
|
|
8441
|
+
refreshToken: typeof parsed.refreshToken === "string" ? parsed.refreshToken : void 0,
|
|
8442
|
+
accountEmail: typeof parsed.accountEmail === "string" ? parsed.accountEmail : void 0
|
|
8443
|
+
}
|
|
8444
|
+
};
|
|
8445
|
+
}
|
|
8446
|
+
} catch {
|
|
8447
|
+
}
|
|
8448
|
+
}
|
|
8449
|
+
return {
|
|
8450
|
+
source: "manual-missing",
|
|
8451
|
+
reason: `no Google credentials found. Put a google-credentials.json (OAuth access token) at ${manualGoogleCredentialsSearchPaths(home)[0]} or connect your Google account in Trusty Squire first.`
|
|
8452
|
+
};
|
|
8453
|
+
}
|
|
8454
|
+
var step = (label, status, extra) => ({
|
|
8455
|
+
label,
|
|
8456
|
+
status,
|
|
8457
|
+
...extra
|
|
8458
|
+
});
|
|
8459
|
+
function outputTail(text2, maxChars = 800) {
|
|
8460
|
+
const trimmed = text2.trim();
|
|
8461
|
+
return trimmed.length <= maxChars ? trimmed : `\u2026${trimmed.slice(-maxChars)}`;
|
|
8462
|
+
}
|
|
8463
|
+
async function installGoogleTool(options) {
|
|
8464
|
+
const steps = [step("helper reached", "done")];
|
|
8465
|
+
const emit = () => options.onProgress?.([...steps]);
|
|
8466
|
+
const push = (next) => {
|
|
8467
|
+
steps.push(next);
|
|
8468
|
+
emit();
|
|
8469
|
+
};
|
|
8470
|
+
const fail = (label, reason, output) => {
|
|
8471
|
+
push(step(label, "failed", { reason, ...output ? { output } : {} }));
|
|
8472
|
+
return { status: "error", steps, errorMessage: reason };
|
|
8473
|
+
};
|
|
8474
|
+
emit();
|
|
8475
|
+
if (!isGoogleToolConnectorType(options.connectorType)) {
|
|
8476
|
+
return fail("connector type", `${options.connectorType} is not a Google tool connector`);
|
|
8477
|
+
}
|
|
8478
|
+
push(step("Google credentials resolved", "running", { output: "resolving\u2026" }));
|
|
8479
|
+
const resolved = options.resolvedCredentials ? await options.resolvedCredentials : options.resolveCredentials ? await options.resolveCredentials() : await (async () => {
|
|
8480
|
+
const oneClick = await readGoogleCredentialsFromVault(options.squire);
|
|
8481
|
+
return oneClick.source === "squire" ? { ...oneClick } : { ...loadManualGoogleCredentials(options.home, options.env) };
|
|
8482
|
+
})();
|
|
8483
|
+
if (!("credentials" in resolved)) {
|
|
8484
|
+
const reason = resolved.reason;
|
|
8485
|
+
steps[1] = step("Google credentials resolved", "failed", { reason, output: outputTail(reason) });
|
|
8486
|
+
emit();
|
|
8487
|
+
return { status: "error", steps, errorMessage: reason };
|
|
8488
|
+
}
|
|
8489
|
+
steps[1] = step("Google credentials resolved", "done", {
|
|
8490
|
+
output: resolved.source === "squire" ? "one-click: read the Google grant from Trusty Squire" : "manual: local google-credentials.json"
|
|
8491
|
+
});
|
|
8492
|
+
emit();
|
|
8493
|
+
const client = options.client ?? googleWorkspaceClient(credentialsTokenSource(resolved.credentials));
|
|
8494
|
+
push(step("authorized with Google", "running", { output: "verifying the grant with Google\u2026" }));
|
|
8495
|
+
const verify = await client.verify();
|
|
8496
|
+
if (!verify.ok) {
|
|
8497
|
+
return fail("authorized with Google", verify.reason, outputTail(verify.reason));
|
|
8498
|
+
}
|
|
8499
|
+
steps[2] = step("authorized with Google", "done", {
|
|
8500
|
+
...verify.account ? { output: `signed in as ${verify.account}` } : {}
|
|
8501
|
+
});
|
|
8502
|
+
emit();
|
|
8503
|
+
push(step("tools enabled", "done", {
|
|
8504
|
+
output: `${GOOGLE_TOOL_SCOPES[options.connectorType].length} Google scopes granted`
|
|
8505
|
+
}));
|
|
8506
|
+
return {
|
|
8507
|
+
status: "connected",
|
|
8508
|
+
steps,
|
|
8509
|
+
...verify.account ? { signedInAs: verify.account } : {}
|
|
8510
|
+
};
|
|
8511
|
+
}
|
|
8512
|
+
function describe(error) {
|
|
8513
|
+
return error instanceof Error ? error.message : String(error);
|
|
8514
|
+
}
|
|
8515
|
+
|
|
8159
8516
|
// apps/body/dist/connector-squire.js
|
|
8160
8517
|
import { execFile, spawn as spawn2 } from "node:child_process";
|
|
8161
|
-
var
|
|
8518
|
+
var SQUIRE_MCP_NAME = "@trusty-squire/mcp";
|
|
8519
|
+
var SQUIRE_CONNECT_PACKAGE = `${SQUIRE_MCP_NAME}@latest`;
|
|
8520
|
+
var activeConnectSession;
|
|
8521
|
+
function isProcessAlive(pid) {
|
|
8522
|
+
if (pid === void 0 || pid <= 0)
|
|
8523
|
+
return false;
|
|
8524
|
+
try {
|
|
8525
|
+
process.kill(pid, 0);
|
|
8526
|
+
return true;
|
|
8527
|
+
} catch (error) {
|
|
8528
|
+
return error?.code === "EPERM";
|
|
8529
|
+
}
|
|
8530
|
+
}
|
|
8531
|
+
function releaseSquireConnectSession(log2) {
|
|
8532
|
+
const claim = activeConnectSession;
|
|
8533
|
+
activeConnectSession = void 0;
|
|
8534
|
+
if (!claim)
|
|
8535
|
+
return;
|
|
8536
|
+
if (isProcessAlive(claim.pid)) {
|
|
8537
|
+
log2?.(`released trusty-squire connect session claim (pid ${String(claim.pid)} still live \u2014 a fresh connect owns the browser now)`);
|
|
8538
|
+
claim.abort();
|
|
8539
|
+
} else {
|
|
8540
|
+
log2?.("cleared dead trusty-squire connect session claim (owner process gone)");
|
|
8541
|
+
}
|
|
8542
|
+
}
|
|
8162
8543
|
var defaultShellRunner = (command, args) => new Promise((resolve31) => {
|
|
8163
8544
|
execFile(command, [...args], { timeout: 12e4, maxBuffer: 4 * 1024 * 1024, encoding: "utf8" }, (error, stdout6, stderr) => {
|
|
8164
8545
|
const code = error?.code;
|
|
@@ -8180,7 +8561,7 @@ var defaultStreamedRunner = (command, args) => new Promise((resolve31) => {
|
|
|
8180
8561
|
const safetyTimer = setTimeout(() => {
|
|
8181
8562
|
if (!resolved) {
|
|
8182
8563
|
resolved = true;
|
|
8183
|
-
resolve31({ stdout: stdout6, stderr, signIn: void 0, abort: () => {
|
|
8564
|
+
resolve31({ stdout: stdout6, stderr, pid: child.pid ?? void 0, signIn: void 0, abort: () => {
|
|
8184
8565
|
} });
|
|
8185
8566
|
}
|
|
8186
8567
|
child.kill();
|
|
@@ -8189,6 +8570,12 @@ var defaultStreamedRunner = (command, args) => new Promise((resolve31) => {
|
|
|
8189
8570
|
clearTimeout(safetyTimer);
|
|
8190
8571
|
child.kill();
|
|
8191
8572
|
};
|
|
8573
|
+
const claim = {
|
|
8574
|
+
pid: child.pid ?? void 0,
|
|
8575
|
+
claimedAt: Date.now(),
|
|
8576
|
+
abort
|
|
8577
|
+
};
|
|
8578
|
+
activeConnectSession = claim;
|
|
8192
8579
|
const finish = (result) => {
|
|
8193
8580
|
if (!resolved) {
|
|
8194
8581
|
resolved = true;
|
|
@@ -8213,15 +8600,15 @@ ${stderr}`;
|
|
|
8213
8600
|
checkOutput();
|
|
8214
8601
|
});
|
|
8215
8602
|
child.on("close", () => {
|
|
8216
|
-
finish({ stdout: stdout6, stderr, signIn: void 0, abort: () => {
|
|
8603
|
+
finish({ stdout: stdout6, stderr, pid: child.pid ?? void 0, signIn: void 0, abort: () => {
|
|
8217
8604
|
} });
|
|
8218
8605
|
});
|
|
8219
8606
|
child.on("error", () => {
|
|
8220
|
-
finish({ stdout: stdout6, stderr, signIn: void 0, abort: () => {
|
|
8607
|
+
finish({ stdout: stdout6, stderr, pid: child.pid ?? void 0, signIn: void 0, abort: () => {
|
|
8221
8608
|
} });
|
|
8222
8609
|
});
|
|
8223
8610
|
});
|
|
8224
|
-
var
|
|
8611
|
+
var step2 = (label, status, reason) => ({
|
|
8225
8612
|
label,
|
|
8226
8613
|
status,
|
|
8227
8614
|
...reason ? { reason } : {}
|
|
@@ -8238,32 +8625,76 @@ function parseConnectOutput(output) {
|
|
|
8238
8625
|
}
|
|
8239
8626
|
return { method: "streamed-page", url };
|
|
8240
8627
|
}
|
|
8241
|
-
async function installedSquireVersion(run2) {
|
|
8242
|
-
const probe = await run2("npx", [
|
|
8628
|
+
async function installedSquireVersion(run2, spec = SQUIRE_CONNECT_PACKAGE, preferOnline = false) {
|
|
8629
|
+
const probe = await run2("npx", [
|
|
8630
|
+
...preferOnline ? ["--prefer-online"] : [],
|
|
8631
|
+
"-y",
|
|
8632
|
+
spec,
|
|
8633
|
+
"--version"
|
|
8634
|
+
]);
|
|
8243
8635
|
const version = probe.stdout.match(/\d+\.\d+\.\d+[^\s]*/)?.[0];
|
|
8244
8636
|
return version;
|
|
8245
8637
|
}
|
|
8638
|
+
async function currentSquireRelease(run2) {
|
|
8639
|
+
const probe = await run2("npm", ["view", SQUIRE_MCP_NAME, "version"]);
|
|
8640
|
+
if (probe.code !== 0)
|
|
8641
|
+
return void 0;
|
|
8642
|
+
return probe.stdout.match(/\d+\.\d+\.\d+[^\s]*/)?.[0];
|
|
8643
|
+
}
|
|
8644
|
+
async function resolveSquireConnectSpec(run2) {
|
|
8645
|
+
const currentRelease = await currentSquireRelease(run2);
|
|
8646
|
+
const first = await installedSquireVersion(run2);
|
|
8647
|
+
if (currentRelease === void 0 || first === currentRelease) {
|
|
8648
|
+
return {
|
|
8649
|
+
npxArgs: ["-y", SQUIRE_CONNECT_PACKAGE],
|
|
8650
|
+
...first !== void 0 ? { resolvedVersion: first } : {},
|
|
8651
|
+
...currentRelease !== void 0 ? { currentRelease } : {},
|
|
8652
|
+
reResolved: false
|
|
8653
|
+
};
|
|
8654
|
+
}
|
|
8655
|
+
const fresh = await installedSquireVersion(run2, SQUIRE_CONNECT_PACKAGE, true);
|
|
8656
|
+
if (fresh === currentRelease) {
|
|
8657
|
+
return {
|
|
8658
|
+
npxArgs: ["--prefer-online", "-y", SQUIRE_CONNECT_PACKAGE],
|
|
8659
|
+
resolvedVersion: fresh,
|
|
8660
|
+
currentRelease,
|
|
8661
|
+
reResolved: true
|
|
8662
|
+
};
|
|
8663
|
+
}
|
|
8664
|
+
return {
|
|
8665
|
+
npxArgs: ["-y", `${SQUIRE_MCP_NAME}@${currentRelease}`],
|
|
8666
|
+
...fresh !== void 0 ? { resolvedVersion: fresh } : {},
|
|
8667
|
+
currentRelease,
|
|
8668
|
+
reResolved: true
|
|
8669
|
+
};
|
|
8670
|
+
}
|
|
8246
8671
|
function parseSignedInAs(output) {
|
|
8247
8672
|
return output.match(/signed in as ([^\s,;]+)/i)?.[1];
|
|
8248
8673
|
}
|
|
8249
8674
|
async function installSquire(options) {
|
|
8250
8675
|
const run2 = options.run ?? defaultShellRunner;
|
|
8251
8676
|
const streamRun = options.streamRun ?? defaultStreamedRunner;
|
|
8252
|
-
const
|
|
8677
|
+
const log2 = options.log ?? (() => {
|
|
8678
|
+
});
|
|
8679
|
+
const steps = [step2("helper reached", "done")];
|
|
8253
8680
|
const emit = () => options.onProgress?.([...steps]);
|
|
8254
8681
|
const push = (next) => {
|
|
8255
8682
|
steps.push(next);
|
|
8256
8683
|
emit();
|
|
8257
8684
|
};
|
|
8258
8685
|
const fail = (reason) => {
|
|
8259
|
-
steps.push(
|
|
8686
|
+
steps.push(step2("waiting for sign-in", "pending"));
|
|
8260
8687
|
emit();
|
|
8261
8688
|
return { status: "error", steps, errorMessage: reason };
|
|
8262
8689
|
};
|
|
8263
8690
|
emit();
|
|
8691
|
+
releaseSquireConnectSession(log2);
|
|
8692
|
+
const resolution = await resolveSquireConnectSpec(run2);
|
|
8693
|
+
if (resolution.reResolved) {
|
|
8694
|
+
log2(`trusty-squire stale copy ${resolution.resolvedVersion ?? "unknown"} re-resolved against current release ${resolution.currentRelease}`);
|
|
8695
|
+
}
|
|
8264
8696
|
const install = await streamRun("npx", [
|
|
8265
|
-
|
|
8266
|
-
SQUIRE_CONNECT_PACKAGE,
|
|
8697
|
+
...resolution.npxArgs,
|
|
8267
8698
|
"connect",
|
|
8268
8699
|
"--force-relogin=google",
|
|
8269
8700
|
"--target=codex",
|
|
@@ -8271,18 +8702,18 @@ async function installSquire(options) {
|
|
|
8271
8702
|
]);
|
|
8272
8703
|
if (!install.signIn) {
|
|
8273
8704
|
const stderr = install.stderr.trim();
|
|
8274
|
-
push(
|
|
8705
|
+
push(step2("trusty-squire installed", "failed", stderr || "connect printed no sign-in URL"));
|
|
8275
8706
|
return fail(stderr || "the trusty-squire connect command printed no sign-in surface");
|
|
8276
8707
|
}
|
|
8277
|
-
const version =
|
|
8278
|
-
push(
|
|
8708
|
+
const version = resolution.resolvedVersion;
|
|
8709
|
+
push(step2(`trusty-squire${version ? ` ${version}` : ""} installed`, "done"));
|
|
8279
8710
|
const signIn = install.signIn;
|
|
8280
8711
|
const signedInAs = parseSignedInAs(`${install.stdout}
|
|
8281
8712
|
${install.stderr}`);
|
|
8282
|
-
push(
|
|
8713
|
+
push(step2("waiting for sign-in", "done"));
|
|
8283
8714
|
const pair = await pairSquire(options.mcp, options.workspaceId);
|
|
8284
8715
|
if (!pair.ok) {
|
|
8285
|
-
push(
|
|
8716
|
+
push(step2("paired to workspace", "failed", pair.reason));
|
|
8286
8717
|
return {
|
|
8287
8718
|
status: "installing",
|
|
8288
8719
|
steps,
|
|
@@ -8291,7 +8722,7 @@ ${install.stderr}`);
|
|
|
8291
8722
|
...signedInAs ? { signedInAs } : {}
|
|
8292
8723
|
};
|
|
8293
8724
|
}
|
|
8294
|
-
push(
|
|
8725
|
+
push(step2("paired to workspace", "done"));
|
|
8295
8726
|
return {
|
|
8296
8727
|
status: "connected",
|
|
8297
8728
|
steps,
|
|
@@ -8431,9 +8862,10 @@ var StdioSquireMcpClient = class {
|
|
|
8431
8862
|
}
|
|
8432
8863
|
initialize() {
|
|
8433
8864
|
const child = (this.options.spawn ?? spawn3)(this.options.command ?? "npx", [
|
|
8434
|
-
// `@
|
|
8435
|
-
//
|
|
8436
|
-
|
|
8865
|
+
// `@latest`: the current release, never a source-level version pin
|
|
8866
|
+
// (captain). Only the vault MCP server the agent spawns; the connect
|
|
8867
|
+
// install path verifies freshness itself (connector-squire.ts).
|
|
8868
|
+
...this.options.args ?? ["-y", "@trusty-squire/mcp@latest"]
|
|
8437
8869
|
]);
|
|
8438
8870
|
this.child = child;
|
|
8439
8871
|
this.buffer = "";
|
|
@@ -8523,6 +8955,8 @@ var ConnectorAssignmentLoop = class {
|
|
|
8523
8955
|
intervalMs;
|
|
8524
8956
|
log;
|
|
8525
8957
|
install;
|
|
8958
|
+
installGoogle;
|
|
8959
|
+
googleHomeDir;
|
|
8526
8960
|
readVaultFn;
|
|
8527
8961
|
revokeGrantsFn;
|
|
8528
8962
|
schedule;
|
|
@@ -8540,6 +8974,13 @@ var ConnectorAssignmentLoop = class {
|
|
|
8540
8974
|
this.log = options.log ?? (() => {
|
|
8541
8975
|
});
|
|
8542
8976
|
this.install = options.install ?? installSquire;
|
|
8977
|
+
this.installGoogle = options.installGoogle ?? ((connectorType, onProgress, sharedCredentials) => installGoogleTool({
|
|
8978
|
+
connectorType,
|
|
8979
|
+
home: this.googleHome(),
|
|
8980
|
+
onProgress,
|
|
8981
|
+
resolvedCredentials: sharedCredentials ? sharedCredentials() : this.resolveGoogleCredentials()
|
|
8982
|
+
}));
|
|
8983
|
+
this.googleHomeDir = options.googleHome ?? process.env.BEELINE_AGENT_HOME ?? process.cwd();
|
|
8543
8984
|
this.readVaultFn = options.readVault ?? readVault;
|
|
8544
8985
|
this.revokeGrantsFn = options.revokeGrants ?? revokeGrants;
|
|
8545
8986
|
this.schedule = options.schedule ?? ((fn, ms) => {
|
|
@@ -8577,44 +9018,120 @@ var ConnectorAssignmentLoop = class {
|
|
|
8577
9018
|
const result = await this.api.execute("getConnectorAssignments", { agentId: this.agentId });
|
|
8578
9019
|
assignments = result.assignments;
|
|
8579
9020
|
} catch (error) {
|
|
8580
|
-
this.log(`connector assignments unavailable: ${
|
|
9021
|
+
this.log(`connector assignments unavailable: ${describe2(error)}`);
|
|
8581
9022
|
return;
|
|
8582
9023
|
}
|
|
9024
|
+
let googleBatch;
|
|
8583
9025
|
for (const assignment of assignments) {
|
|
8584
9026
|
const key = `${assignment.kind}:${assignment.connectorId}`;
|
|
8585
9027
|
if (assignment.kind === "uninstall")
|
|
8586
9028
|
continue;
|
|
9029
|
+
if (assignment.kind === "install" && isGoogleToolConnectorType(assignment.connectorType)) {
|
|
9030
|
+
if (this.inFlight.has(key))
|
|
9031
|
+
continue;
|
|
9032
|
+
this.inFlight.add(key);
|
|
9033
|
+
(googleBatch ??= []).push(assignment);
|
|
9034
|
+
continue;
|
|
9035
|
+
}
|
|
8587
9036
|
if (this.inFlight.has(key))
|
|
8588
9037
|
continue;
|
|
8589
9038
|
this.inFlight.add(key);
|
|
8590
|
-
void this.handle(assignment).catch((error) => this.log(`connector assignment ${key} failed: ${
|
|
9039
|
+
void this.handle(assignment).catch((error) => this.log(`connector assignment ${key} failed: ${describe2(error)}`)).finally(() => this.inFlight.delete(key));
|
|
8591
9040
|
}
|
|
9041
|
+
if (googleBatch)
|
|
9042
|
+
this.flushGoogleBatch(googleBatch);
|
|
9043
|
+
}
|
|
9044
|
+
flushGoogleBatch(batch) {
|
|
9045
|
+
const keys = batch.map((a2) => `${a2.kind}:${a2.connectorId}`);
|
|
9046
|
+
void this.runGoogleBatch(batch).catch((error) => this.log(`google connector installs failed: ${describe2(error)}`)).finally(() => {
|
|
9047
|
+
for (const key of keys)
|
|
9048
|
+
this.inFlight.delete(key);
|
|
9049
|
+
});
|
|
9050
|
+
}
|
|
9051
|
+
/** The Google tool connectors ride ONE grant: every install in the batch
|
|
9052
|
+
* shares one credential resolution (the single Google consent) and the
|
|
9053
|
+
* installs run one at a time. Each tool still verifies and fails
|
|
9054
|
+
* independently — a grant that cannot serve one tool's scope refuses that
|
|
9055
|
+
* tool alone, never its siblings. */
|
|
9056
|
+
async runGoogleBatch(batch) {
|
|
9057
|
+
let shared;
|
|
9058
|
+
const sharedCredentials = () => shared ??= this.resolveGoogleCredentials();
|
|
9059
|
+
for (const assignment of batch) {
|
|
9060
|
+
await this.runGoogleInstall(assignment.connectorId, assignment.connectorType, sharedCredentials);
|
|
9061
|
+
}
|
|
9062
|
+
}
|
|
9063
|
+
/** The ONE grant resolution shared by every Google tool install of a
|
|
9064
|
+
* drain: the Squire one-click vault path first, then the manual
|
|
9065
|
+
* credentials path. Never rejects — a failure resolves as an unusable
|
|
9066
|
+
* grant each install reports through its own steps. */
|
|
9067
|
+
resolveGoogleCredentials() {
|
|
9068
|
+
return (async () => {
|
|
9069
|
+
try {
|
|
9070
|
+
const oneClick = await readGoogleCredentialsFromVault(this.squire());
|
|
9071
|
+
if (oneClick.source === "squire")
|
|
9072
|
+
return oneClick;
|
|
9073
|
+
} catch (error) {
|
|
9074
|
+
this.log(`google one-click grant lookup failed: ${describe2(error)}`);
|
|
9075
|
+
}
|
|
9076
|
+
return loadManualGoogleCredentials(this.googleHome(), process.env);
|
|
9077
|
+
})();
|
|
8592
9078
|
}
|
|
8593
9079
|
squire() {
|
|
8594
9080
|
this.mcp ??= defaultSquireMcpClient();
|
|
8595
9081
|
return this.mcp;
|
|
8596
9082
|
}
|
|
8597
9083
|
async handle(assignment) {
|
|
8598
|
-
if (assignment.kind === "install")
|
|
9084
|
+
if (assignment.kind === "install") {
|
|
8599
9085
|
await this.runInstall(assignment.connectorId);
|
|
8600
|
-
else if (assignment.kind === "sync")
|
|
9086
|
+
} else if (assignment.kind === "sync")
|
|
8601
9087
|
await this.runSync();
|
|
8602
9088
|
else if (assignment.kind === "revoke-grants")
|
|
8603
9089
|
await this.runRevoke(assignment.connectorId, assignment.reference);
|
|
8604
9090
|
}
|
|
9091
|
+
/** Google tool connectors keep their manual credentials next to the runtime. */
|
|
9092
|
+
googleHome() {
|
|
9093
|
+
return this.googleHomeDir;
|
|
9094
|
+
}
|
|
9095
|
+
/** Install one Google tool connector (Gmail/Calendar/Drive/YouTube),
|
|
9096
|
+
* riding the drain's shared grant resolution. */
|
|
9097
|
+
async runGoogleInstall(connectorId, connectorType, sharedCredentials) {
|
|
9098
|
+
const report = async (steps) => {
|
|
9099
|
+
try {
|
|
9100
|
+
await this.api.execute("postConnectorStatus", { agentId: this.agentId, connectorId, steps });
|
|
9101
|
+
} catch (error) {
|
|
9102
|
+
this.log(`step report failed: ${describe2(error)}`);
|
|
9103
|
+
}
|
|
9104
|
+
};
|
|
9105
|
+
const result = await this.installGoogle(connectorType, report, sharedCredentials);
|
|
9106
|
+
if (result.status === "error") {
|
|
9107
|
+
await this.api.execute("postConnectorStatus", {
|
|
9108
|
+
agentId: this.agentId,
|
|
9109
|
+
connectorId,
|
|
9110
|
+
steps: result.steps,
|
|
9111
|
+
errorMessage: result.errorMessage
|
|
9112
|
+
});
|
|
9113
|
+
return;
|
|
9114
|
+
}
|
|
9115
|
+
await this.api.execute("installConnector", {
|
|
9116
|
+
agentId: this.agentId,
|
|
9117
|
+
connectorId,
|
|
9118
|
+
...result.signedInAs ? { signedInAs: result.signedInAs } : {}
|
|
9119
|
+
});
|
|
9120
|
+
}
|
|
8605
9121
|
/** Install Trusty Squire, reporting every step as it settles. */
|
|
8606
9122
|
async runInstall(connectorId) {
|
|
8607
9123
|
const report = async (steps) => {
|
|
8608
9124
|
try {
|
|
8609
9125
|
await this.api.execute("postConnectorStatus", { agentId: this.agentId, connectorId, steps });
|
|
8610
9126
|
} catch (error) {
|
|
8611
|
-
this.log(`step report failed: ${
|
|
9127
|
+
this.log(`step report failed: ${describe2(error)}`);
|
|
8612
9128
|
}
|
|
8613
9129
|
};
|
|
8614
9130
|
const result = await this.install({
|
|
8615
9131
|
workspaceId: this.agentId,
|
|
8616
9132
|
mcp: this.squire(),
|
|
8617
|
-
onProgress: report
|
|
9133
|
+
onProgress: report,
|
|
9134
|
+
log: (message) => this.log(`[trusty-squire] ${message}`)
|
|
8618
9135
|
});
|
|
8619
9136
|
if (result.status === "error") {
|
|
8620
9137
|
await this.api.execute("postConnectorStatus", {
|
|
@@ -8659,7 +9176,7 @@ var ConnectorAssignmentLoop = class {
|
|
|
8659
9176
|
await this.api.execute("postConnectorVault", { agentId: this.agentId, connections });
|
|
8660
9177
|
}
|
|
8661
9178
|
};
|
|
8662
|
-
function
|
|
9179
|
+
function describe2(error) {
|
|
8663
9180
|
return error instanceof Error ? error.message : String(error);
|
|
8664
9181
|
}
|
|
8665
9182
|
|
|
@@ -13109,7 +13626,7 @@ function alphabet(letters) {
|
|
|
13109
13626
|
};
|
|
13110
13627
|
}
|
|
13111
13628
|
// @__NO_SIDE_EFFECTS__
|
|
13112
|
-
function
|
|
13629
|
+
function join3(separator = "") {
|
|
13113
13630
|
astr("join", separator);
|
|
13114
13631
|
return {
|
|
13115
13632
|
encode: (from) => {
|
|
@@ -13239,8 +13756,8 @@ var base64 = hasBase64Builtin ? {
|
|
|
13239
13756
|
decode(s) {
|
|
13240
13757
|
return decodeBase64Builtin(s, false);
|
|
13241
13758
|
}
|
|
13242
|
-
} : /* @__PURE__ */ chain(/* @__PURE__ */ radix2(6), /* @__PURE__ */ alphabet("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"), /* @__PURE__ */ padding(6), /* @__PURE__ */
|
|
13243
|
-
var BECH_ALPHABET = /* @__PURE__ */ chain(/* @__PURE__ */ alphabet("qpzry9x8gf2tvdw0s3jn54khce6mua7l"), /* @__PURE__ */
|
|
13759
|
+
} : /* @__PURE__ */ chain(/* @__PURE__ */ radix2(6), /* @__PURE__ */ alphabet("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"), /* @__PURE__ */ padding(6), /* @__PURE__ */ join3(""));
|
|
13760
|
+
var BECH_ALPHABET = /* @__PURE__ */ chain(/* @__PURE__ */ alphabet("qpzry9x8gf2tvdw0s3jn54khce6mua7l"), /* @__PURE__ */ join3(""));
|
|
13244
13761
|
var POLYMOD_GENERATORS = [996825010, 642813549, 513874426, 1027748829, 705979059];
|
|
13245
13762
|
function bech32Polymod(pre) {
|
|
13246
13763
|
const b = pre >> 25;
|
|
@@ -16845,13 +17362,13 @@ var NegentropyStorageVector = class {
|
|
|
16845
17362
|
let count = last - first;
|
|
16846
17363
|
while (count > 0) {
|
|
16847
17364
|
let it = first;
|
|
16848
|
-
let
|
|
16849
|
-
it +=
|
|
17365
|
+
let step3 = Math.floor(count / 2);
|
|
17366
|
+
it += step3;
|
|
16850
17367
|
if (cmp(arr[it])) {
|
|
16851
17368
|
first = ++it;
|
|
16852
|
-
count -=
|
|
17369
|
+
count -= step3 + 1;
|
|
16853
17370
|
} else {
|
|
16854
|
-
count =
|
|
17371
|
+
count = step3;
|
|
16855
17372
|
}
|
|
16856
17373
|
}
|
|
16857
17374
|
return first;
|
|
@@ -18656,13 +19173,13 @@ function captureConnectionUsage(recorder, turn, calls) {
|
|
|
18656
19173
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
18657
19174
|
import { mkdir as mkdir3, writeFile as writeFile4 } from "node:fs/promises";
|
|
18658
19175
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
18659
|
-
import { dirname as dirname5, join as
|
|
19176
|
+
import { dirname as dirname5, join as join4 } from "node:path";
|
|
18660
19177
|
var CommandExecutionContext = class {
|
|
18661
19178
|
generationId = randomUUID2();
|
|
18662
19179
|
path;
|
|
18663
19180
|
current;
|
|
18664
19181
|
constructor(root) {
|
|
18665
|
-
this.path =
|
|
19182
|
+
this.path = join4(root ?? tmpdir2(), `beeline-command-${this.generationId}.json`);
|
|
18666
19183
|
}
|
|
18667
19184
|
async enter(command) {
|
|
18668
19185
|
this.current = command;
|
|
@@ -18823,18 +19340,18 @@ import { execFile as execFile5 } from "node:child_process";
|
|
|
18823
19340
|
import { createHash as createHash5 } from "node:crypto";
|
|
18824
19341
|
import { mkdir as mkdir12 } from "node:fs/promises";
|
|
18825
19342
|
import { homedir as homedir7 } from "node:os";
|
|
18826
|
-
import { join as
|
|
19343
|
+
import { join as join9 } from "node:path";
|
|
18827
19344
|
import { promisify as promisify3 } from "node:util";
|
|
18828
19345
|
|
|
18829
19346
|
// apps/body/dist/agent-home.js
|
|
18830
|
-
import { existsSync as existsSync3, readFileSync as
|
|
19347
|
+
import { existsSync as existsSync3, readFileSync as readFileSync5 } from "node:fs";
|
|
18831
19348
|
import { createHash as createHash3, randomUUID as randomUUID3 } from "node:crypto";
|
|
18832
19349
|
import { chmod as chmod2, copyFile, lstat, mkdir as mkdir5, readFile as readFile6, readdir as readdir2, realpath, rename as rename2, rm as rm2, symlink, unlink, writeFile as writeFile6 } from "node:fs/promises";
|
|
18833
19350
|
import { homedir as homedir5 } from "node:os";
|
|
18834
|
-
import { basename as basename3, dirname as dirname6, join as
|
|
19351
|
+
import { basename as basename3, dirname as dirname6, join as join5, relative as relative2, resolve as resolve13, sep } from "node:path";
|
|
18835
19352
|
|
|
18836
19353
|
// apps/body/dist/beeline-skill.js
|
|
18837
|
-
import { readFileSync as
|
|
19354
|
+
import { readFileSync as readFileSync4 } from "node:fs";
|
|
18838
19355
|
import { resolve as resolve11 } from "node:path";
|
|
18839
19356
|
|
|
18840
19357
|
// packages/api-contract/dist/agent-pairing-code.js
|
|
@@ -18898,7 +19415,7 @@ function beelineCapabilityContextForHarness(agentCommand, repository, directMess
|
|
|
18898
19415
|
...harnessHonorsSessionSystemPrompt(agentCommand) ? {} : { compatibilityTurnPrefix: primer }
|
|
18899
19416
|
};
|
|
18900
19417
|
}
|
|
18901
|
-
function runningBeelineReleaseId(env = process.env, read = (path) =>
|
|
19418
|
+
function runningBeelineReleaseId(env = process.env, read = (path) => readFileSync4(path, "utf8")) {
|
|
18902
19419
|
try {
|
|
18903
19420
|
const lib = env.BEELINE_LIB_DIR;
|
|
18904
19421
|
if (!lib)
|
|
@@ -19018,7 +19535,7 @@ Then take exactly one action:
|
|
|
19018
19535
|
}
|
|
19019
19536
|
|
|
19020
19537
|
// apps/body/dist/external-mcp-capabilities.js
|
|
19021
|
-
var SQUIRE_MCP_VERSION = "
|
|
19538
|
+
var SQUIRE_MCP_VERSION = "latest";
|
|
19022
19539
|
var SQUIRE_MCP_PACKAGE = `@trusty-squire/mcp@${SQUIRE_MCP_VERSION}`;
|
|
19023
19540
|
function isTrustySquireMcpLaunch(command, args = []) {
|
|
19024
19541
|
return [command, ...args].some((value) => {
|
|
@@ -19704,7 +20221,7 @@ async function provisionAgentSkillsAndMcp(root, operatorHome, skillReleaseId, fa
|
|
|
19704
20221
|
try {
|
|
19705
20222
|
const source = resolve13(operatorHome, config.toml);
|
|
19706
20223
|
const target = resolve13(root, config.dir, "config.toml");
|
|
19707
|
-
const mcpSection = existsSync3(source) ? filteredHarnessMcpToml(
|
|
20224
|
+
const mcpSection = existsSync3(source) ? filteredHarnessMcpToml(readFileSync5(source, "utf8")) : void 0;
|
|
19708
20225
|
const section = config.dir === "codex" ? [CODEX_ROOM_AGENT_LOCKDOWN_TOML, CODEX_ROOM_WEB_SEARCH_TOML, mcpSection].filter(Boolean).join("\n") : mcpSection;
|
|
19709
20226
|
if (!section) {
|
|
19710
20227
|
await unlink(target).catch(() => void 0);
|
|
@@ -19724,7 +20241,7 @@ async function provisionAgentSkillsAndMcp(root, operatorHome, skillReleaseId, fa
|
|
|
19724
20241
|
const source = resolve13(operatorHome, ".config", "goose", name);
|
|
19725
20242
|
const target = resolve13(gooseConfigDir, name);
|
|
19726
20243
|
if (existsSync3(source)) {
|
|
19727
|
-
await writeIsolatedHarnessFile(target,
|
|
20244
|
+
await writeIsolatedHarnessFile(target, readFileSync5(source, "utf8"));
|
|
19728
20245
|
} else {
|
|
19729
20246
|
await unlink(target).catch(() => void 0);
|
|
19730
20247
|
}
|
|
@@ -19795,7 +20312,7 @@ async function provisionPiCustomModelConfig(root, operatorHome, failClosed, open
|
|
|
19795
20312
|
if (resolvedSource !== source) {
|
|
19796
20313
|
throw new AgentHomeSecurityError(`Pi custom model config resolves through a link: ${source}`);
|
|
19797
20314
|
}
|
|
19798
|
-
const sourceValue = JSON.parse(
|
|
20315
|
+
const sourceValue = JSON.parse(readFileSync5(resolvedSource, "utf8"));
|
|
19799
20316
|
await writeIsolatedHarnessFile(target, `${JSON.stringify(withOpenRouterModelRouting(sourceValue, pin), null, 2)}
|
|
19800
20317
|
`);
|
|
19801
20318
|
} catch (error) {
|
|
@@ -19807,7 +20324,7 @@ async function provisionPiCustomModelConfig(root, operatorHome, failClosed, open
|
|
|
19807
20324
|
}
|
|
19808
20325
|
function readClaudeUserScopeMcpServers(path) {
|
|
19809
20326
|
try {
|
|
19810
|
-
const parsed = JSON.parse(
|
|
20327
|
+
const parsed = JSON.parse(readFileSync5(path, "utf8"));
|
|
19811
20328
|
if (parsed && typeof parsed.mcpServers === "object" && parsed.mcpServers !== null) {
|
|
19812
20329
|
return Object.fromEntries(Object.entries(parsed.mcpServers).filter(([name, value]) => {
|
|
19813
20330
|
if (name === "squire")
|
|
@@ -19872,8 +20389,8 @@ async function planManagedSkills(managedSkills, sharedSkills, optionalShares) {
|
|
|
19872
20389
|
try {
|
|
19873
20390
|
const tree = [];
|
|
19874
20391
|
await walkSafeSkillTree(shared.source, shared.source, {
|
|
19875
|
-
directory: async (rel) => void tree.push(`d ${
|
|
19876
|
-
file: async (rel, realPath) => void tree.push(`f ${
|
|
20392
|
+
directory: async (rel) => void tree.push(`d ${join5(shared.name, rel)}`),
|
|
20393
|
+
file: async (rel, realPath) => void tree.push(`f ${join5(shared.name, rel)} ${sha2563(await readFile6(realPath))}`)
|
|
19877
20394
|
});
|
|
19878
20395
|
entries.push({ kind: "shared", name: shared.name, source: shared.source });
|
|
19879
20396
|
lines.push(...tree);
|
|
@@ -19893,7 +20410,7 @@ async function materializedSkillManifest(target) {
|
|
|
19893
20410
|
const visit = async (directory, prefix) => {
|
|
19894
20411
|
for (const entry of await readdir2(directory)) {
|
|
19895
20412
|
const path = resolve13(directory, entry);
|
|
19896
|
-
const rel = prefix ?
|
|
20413
|
+
const rel = prefix ? join5(prefix, entry) : entry;
|
|
19897
20414
|
const entryStats = await lstat(path);
|
|
19898
20415
|
if (entryStats.isSymbolicLink())
|
|
19899
20416
|
return false;
|
|
@@ -20061,7 +20578,7 @@ async function walkSafeSkillTree(source, sourceRoot, visitor, rel = "") {
|
|
|
20061
20578
|
for (const entry of await readdir2(resolvedSource)) {
|
|
20062
20579
|
if (entry === "." || entry === "..")
|
|
20063
20580
|
throw new Error("invalid shared skill entry");
|
|
20064
|
-
await walkSafeSkillTree(resolve13(source, entry), sourceRoot, visitor, rel ?
|
|
20581
|
+
await walkSafeSkillTree(resolve13(source, entry), sourceRoot, visitor, rel ? join5(rel, entry) : entry);
|
|
20065
20582
|
}
|
|
20066
20583
|
return;
|
|
20067
20584
|
}
|
|
@@ -20134,7 +20651,7 @@ function harnessStateDirsFromEnv(env) {
|
|
|
20134
20651
|
|
|
20135
20652
|
// apps/body/dist/attachment-delivery.js
|
|
20136
20653
|
import { mkdir as mkdir6, writeFile as writeFile7 } from "node:fs/promises";
|
|
20137
|
-
import { basename as basename4, extname, join as
|
|
20654
|
+
import { basename as basename4, extname, join as join6 } from "node:path";
|
|
20138
20655
|
var MAX_ATTACHMENT_BYTES = 25 * 1024 * 1024;
|
|
20139
20656
|
var MEDIA_TTL_HOURS = 24;
|
|
20140
20657
|
var EXPIRED_REASON = `expired: attachments are kept for ${MEDIA_TTL_HOURS} hours and these bytes are past that window`;
|
|
@@ -20178,7 +20695,7 @@ async function deliverAttachments(attachments, dir, fetchImpl = fetch) {
|
|
|
20178
20695
|
const bytes = Buffer.from(await response.arrayBuffer());
|
|
20179
20696
|
if (bytes.length > MAX_ATTACHMENT_BYTES)
|
|
20180
20697
|
return tooLarge(bytes.length);
|
|
20181
|
-
const path =
|
|
20698
|
+
const path = join6(dir, safeFileName(attachment, index, taken));
|
|
20182
20699
|
await writeFile7(path, bytes);
|
|
20183
20700
|
const mimeType = attachment.mimeType ?? response.headers.get("content-type") ?? "";
|
|
20184
20701
|
if (!mimeType.startsWith("image/"))
|
|
@@ -21685,7 +22202,7 @@ process.exit(result.status ?? 1);
|
|
|
21685
22202
|
import { createHash as createHash4, randomUUID as randomUUID4 } from "node:crypto";
|
|
21686
22203
|
import { constants as fsConstants } from "node:fs";
|
|
21687
22204
|
import { chmod as chmod4, copyFile as copyFile2, link, lstat as lstat2, mkdir as mkdir10, readdir as readdir5, readFile as readFile8, readlink, rename as rename3, rm as rm4, stat as stat2, symlink as symlink2, utimes } from "node:fs/promises";
|
|
21688
|
-
import { dirname as dirname7, join as
|
|
22205
|
+
import { dirname as dirname7, join as join7, resolve as resolve19 } from "node:path";
|
|
21689
22206
|
var STORE_FORMAT = "v1";
|
|
21690
22207
|
var STAGING_PREFIX = ".beeline-warm-";
|
|
21691
22208
|
var STAGING_SWEEP_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -21773,7 +22290,7 @@ async function seedWarmNodeModules(input) {
|
|
|
21773
22290
|
for (const target of placed) {
|
|
21774
22291
|
await rm4(target, { recursive: true, force: true }).catch(() => void 0);
|
|
21775
22292
|
}
|
|
21776
|
-
return { reason: "failed", key: plan.key, detail:
|
|
22293
|
+
return { reason: "failed", key: plan.key, detail: describe3(error) };
|
|
21777
22294
|
} finally {
|
|
21778
22295
|
await rm4(staging, { recursive: true, force: true }).catch(() => void 0);
|
|
21779
22296
|
}
|
|
@@ -21816,7 +22333,7 @@ async function harvestWarmNodeModules(input) {
|
|
|
21816
22333
|
} catch (error) {
|
|
21817
22334
|
if (await pathExists(entry))
|
|
21818
22335
|
return { reason: "already-warm", key: plan.key };
|
|
21819
|
-
return { reason: "failed", key: plan.key, detail:
|
|
22336
|
+
return { reason: "failed", key: plan.key, detail: describe3(error) };
|
|
21820
22337
|
} finally {
|
|
21821
22338
|
await rm4(staging, { recursive: true, force: true }).catch(() => void 0);
|
|
21822
22339
|
}
|
|
@@ -21825,7 +22342,7 @@ async function stagedTreeIsPublishable(worktreePath, staging, key) {
|
|
|
21825
22342
|
const settled = await readWarmPlan(worktreePath);
|
|
21826
22343
|
if (isPlanRefusal(settled) || settled.key !== key)
|
|
21827
22344
|
return false;
|
|
21828
|
-
const hidden =
|
|
22345
|
+
const hidden = join7("node_modules", ".package-lock.json");
|
|
21829
22346
|
const [copied, current] = await Promise.all([
|
|
21830
22347
|
readFile8(resolve19(staging, hidden)).catch(() => void 0),
|
|
21831
22348
|
readFile8(resolve19(worktreePath, hidden)).catch(() => void 0)
|
|
@@ -21863,7 +22380,7 @@ async function missingInstalledPackages(worktreePath, treeRoot = worktreePath) {
|
|
|
21863
22380
|
return missing.sort();
|
|
21864
22381
|
}
|
|
21865
22382
|
async function isInstalledPackage(path) {
|
|
21866
|
-
return stat2(
|
|
22383
|
+
return stat2(join7(path, "package.json")).then((info) => info.isFile(), () => false);
|
|
21867
22384
|
}
|
|
21868
22385
|
var INTEGRITY_READ_CONCURRENCY = 64;
|
|
21869
22386
|
async function mapWithLimit(values, limit, visit) {
|
|
@@ -21897,8 +22414,8 @@ function isContainedTreePath(value) {
|
|
|
21897
22414
|
async function cloneTree(source, target, file, topLevel = true) {
|
|
21898
22415
|
await mkdir10(target, { recursive: true, mode: 493 });
|
|
21899
22416
|
for (const entry of await readdir5(source, { withFileTypes: true })) {
|
|
21900
|
-
const from =
|
|
21901
|
-
const to =
|
|
22417
|
+
const from = join7(source, entry.name);
|
|
22418
|
+
const to = join7(target, entry.name);
|
|
21902
22419
|
if (entry.isSymbolicLink()) {
|
|
21903
22420
|
await symlink2(await readlink(from), to);
|
|
21904
22421
|
continue;
|
|
@@ -21928,13 +22445,13 @@ async function pruneWarmStore(storeRoot, keep) {
|
|
|
21928
22445
|
const names = (await readdir5(storeRoot).catch(() => [])).filter((name) => !name.startsWith(STAGING_PREFIX));
|
|
21929
22446
|
const entries = [];
|
|
21930
22447
|
for (const name of names) {
|
|
21931
|
-
const info = await lstat2(
|
|
22448
|
+
const info = await lstat2(join7(storeRoot, name)).catch(() => void 0);
|
|
21932
22449
|
if (info?.isDirectory())
|
|
21933
22450
|
entries.push({ name, usedAt: info.mtimeMs });
|
|
21934
22451
|
}
|
|
21935
22452
|
const dropped = entries.sort((a2, b) => b.usedAt - a2.usedAt || a2.name.localeCompare(b.name)).slice(keep);
|
|
21936
22453
|
for (const entry of dropped) {
|
|
21937
|
-
await rm4(
|
|
22454
|
+
await rm4(join7(storeRoot, entry.name), { recursive: true, force: true }).catch(() => void 0);
|
|
21938
22455
|
}
|
|
21939
22456
|
return dropped.map((entry) => entry.name);
|
|
21940
22457
|
}
|
|
@@ -21943,7 +22460,7 @@ async function sweepStaleStaging(storeRoot, now2) {
|
|
|
21943
22460
|
for (const name of entries) {
|
|
21944
22461
|
if (!name.startsWith(STAGING_PREFIX))
|
|
21945
22462
|
continue;
|
|
21946
|
-
const path =
|
|
22463
|
+
const path = join7(storeRoot, name);
|
|
21947
22464
|
const info = await lstat2(path).catch(() => void 0);
|
|
21948
22465
|
if (!info || now2 - info.mtimeMs < STAGING_SWEEP_MS)
|
|
21949
22466
|
continue;
|
|
@@ -21959,14 +22476,14 @@ async function deviceOf(path) {
|
|
|
21959
22476
|
async function isDirectory(path) {
|
|
21960
22477
|
return stat2(path).then((info) => info.isDirectory(), () => false);
|
|
21961
22478
|
}
|
|
21962
|
-
function
|
|
22479
|
+
function describe3(error) {
|
|
21963
22480
|
return error instanceof Error ? error.message : String(error);
|
|
21964
22481
|
}
|
|
21965
22482
|
|
|
21966
22483
|
// apps/body/dist/monolith-room-turn.js
|
|
21967
22484
|
import { mkdir as mkdir11 } from "node:fs/promises";
|
|
21968
22485
|
import { homedir as homedir6 } from "node:os";
|
|
21969
|
-
import { join as
|
|
22486
|
+
import { join as join8 } from "node:path";
|
|
21970
22487
|
|
|
21971
22488
|
// packages/api-contract/dist/scheduled-prompts.js
|
|
21972
22489
|
var SCHEDULE_SCHEDULER_NAME = "Beeline Scheduler";
|
|
@@ -22169,7 +22686,7 @@ var MonolithRoomTurnLoop = class {
|
|
|
22169
22686
|
const cached = this.deliveredAttachments.get(item.id);
|
|
22170
22687
|
if (cached)
|
|
22171
22688
|
return cached;
|
|
22172
|
-
const delivered = await deliverAttachments(item.attachments,
|
|
22689
|
+
const delivered = await deliverAttachments(item.attachments, join8(this.attachmentDir, item.id.replace(/[^\w-]/g, "_")), this.options.fetchImpl);
|
|
22173
22690
|
this.deliveredAttachments.set(item.id, withoutImageData(delivered));
|
|
22174
22691
|
return delivered;
|
|
22175
22692
|
}
|
|
@@ -22265,7 +22782,7 @@ var MonolithRoomTurnLoop = class {
|
|
|
22265
22782
|
}, selection);
|
|
22266
22783
|
const operatorHome = this.options.config.operatorHome ?? homedir6();
|
|
22267
22784
|
const { stateDirs, tmpDir } = harnessStateDirsFromEnv(agentEnv);
|
|
22268
|
-
this.attachmentDir = tmpDir ?
|
|
22785
|
+
this.attachmentDir = tmpDir ? join8(tmpDir, "beeline-attachments") : void 0;
|
|
22269
22786
|
this.sessionScratchDir = tmpDir;
|
|
22270
22787
|
this.sessionStateDirs = stateDirs;
|
|
22271
22788
|
const homeStateDirs = harnessHomeStateDirs(command, agentEnv.HOME ?? operatorHome);
|
|
@@ -23168,7 +23685,7 @@ var MonolithCornerTurnLoop = class {
|
|
|
23168
23685
|
}, selection);
|
|
23169
23686
|
const operatorHome = this.options.config.operatorHome ?? homedir7();
|
|
23170
23687
|
const { stateDirs, tmpDir } = harnessStateDirsFromEnv(agentEnv);
|
|
23171
|
-
this.attachmentDir = tmpDir ?
|
|
23688
|
+
this.attachmentDir = tmpDir ? join9(tmpDir, "beeline-attachments") : void 0;
|
|
23172
23689
|
this.sessionScratchDir = tmpDir;
|
|
23173
23690
|
const homeStateDirs = harnessHomeStateDirs(command, agentEnv.HOME ?? operatorHome);
|
|
23174
23691
|
await Promise.all(homeStateDirs.map((dir) => mkdir12(dir, { recursive: true })));
|
|
@@ -23389,7 +23906,7 @@ var MonolithCornerTurnLoop = class {
|
|
|
23389
23906
|
const [conversation, roster, delivered] = await trace.measure("context-fetch", () => Promise.all([
|
|
23390
23907
|
api.execute("getRoomConversation", { roomId: cornerId, limit: 200 }),
|
|
23391
23908
|
this.roster(),
|
|
23392
|
-
this.attachmentDir && attachments.length ? deliverAttachments(attachments,
|
|
23909
|
+
this.attachmentDir && attachments.length ? deliverAttachments(attachments, join9(this.attachmentDir, requestId.replace(/[^\w-]/g, "_")), this.options.fetchImpl) : Promise.resolve([])
|
|
23393
23910
|
]));
|
|
23394
23911
|
const names = new Map(roster.members.map((member) => [member.identityId, member.name]));
|
|
23395
23912
|
const requestedBy = requester && !requester.name && names.get(requester.pubkey) ? { ...requester, name: names.get(requester.pubkey) } : requester;
|
|
@@ -27195,7 +27712,7 @@ async function runUpdateFunctionalProbe(input) {
|
|
|
27195
27712
|
|
|
27196
27713
|
// apps/body/dist/current-release-probe.js
|
|
27197
27714
|
import { spawn as spawn9 } from "node:child_process";
|
|
27198
|
-
import { dirname as dirname16, join as
|
|
27715
|
+
import { dirname as dirname16, join as join11 } from "node:path";
|
|
27199
27716
|
init_self_update();
|
|
27200
27717
|
var CURRENT_RELEASE_PROBE_TIMEOUT_MS = 12e4;
|
|
27201
27718
|
var UPDATE_PROBE_COMMAND = "update-probe";
|
|
@@ -27238,7 +27755,7 @@ function outcomeFromReport(report) {
|
|
|
27238
27755
|
}
|
|
27239
27756
|
}
|
|
27240
27757
|
async function probeReleaseInSubprocess(input) {
|
|
27241
|
-
const bundleDir =
|
|
27758
|
+
const bundleDir = join11(input.layout.releasesRoot, input.releaseId);
|
|
27242
27759
|
const entrypoint = await resolveBundleEntrypoint(bundleDir);
|
|
27243
27760
|
if (!entrypoint) {
|
|
27244
27761
|
return { kind: "unavailable", reason: `release ${input.releaseId} has no runnable CLI entrypoint` };
|
|
@@ -27301,7 +27818,7 @@ async function runUpdateProbeCommand(args, options = {}) {
|
|
|
27301
27818
|
const runtime = await readRuntimeRecord(configPath);
|
|
27302
27819
|
const agent = runtimeAgentCommand(runtime);
|
|
27303
27820
|
const config = loadBodyConfig({
|
|
27304
|
-
workspaceRoot:
|
|
27821
|
+
workspaceRoot: join11(dirname16(configPath), "workspace"),
|
|
27305
27822
|
llmEnvFile: runtime.llmEnvFile,
|
|
27306
27823
|
env: { ...env, BUZZ_AGENT_BIN: agent.command, BUZZ_DEV_MCP_BIN: runtime.mcpBinary },
|
|
27307
27824
|
agent
|
|
@@ -27327,7 +27844,7 @@ async function runUpdateProbeCommand(args, options = {}) {
|
|
|
27327
27844
|
sandboxRequired: runtime.sandbox !== "off",
|
|
27328
27845
|
sandboxUnavailableDetail: sandbox.advisory,
|
|
27329
27846
|
// The successor's probe still holds `<runtimeDir>/update-functional-probe`.
|
|
27330
|
-
probeRoot:
|
|
27847
|
+
probeRoot: join11(runtimeDir, "current-release-probe")
|
|
27331
27848
|
}));
|
|
27332
27849
|
const report = outcome.kind === "served" ? { probe: "served" } : outcome.kind === "refused" ? { probe: "refused", status: outcome.status, reason: outcome.reason } : outcome.kind === "sandbox-unavailable" ? { probe: "sandbox-unavailable", reason: outcome.reason } : { probe: "failed", reason: outcome.reason };
|
|
27333
27850
|
write(JSON.stringify(report));
|