switchroom 0.14.87 → 0.14.89
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/cli/switchroom.js
CHANGED
|
@@ -49815,8 +49815,8 @@ var {
|
|
|
49815
49815
|
} = import__.default;
|
|
49816
49816
|
|
|
49817
49817
|
// src/build-info.ts
|
|
49818
|
-
var VERSION = "0.14.
|
|
49819
|
-
var COMMIT_SHA = "
|
|
49818
|
+
var VERSION = "0.14.89";
|
|
49819
|
+
var COMMIT_SHA = "125cbcc5";
|
|
49820
49820
|
|
|
49821
49821
|
// src/cli/agent.ts
|
|
49822
49822
|
init_source();
|
|
@@ -79037,7 +79037,7 @@ function registerNotionMcpLauncherCommand(program3) {
|
|
|
79037
79037
|
// src/cli/deliver-file.ts
|
|
79038
79038
|
init_client2();
|
|
79039
79039
|
import { readFileSync as readFileSync58, statSync as statSync28 } from "node:fs";
|
|
79040
|
-
import { basename as
|
|
79040
|
+
import { basename as basename7 } from "node:path";
|
|
79041
79041
|
|
|
79042
79042
|
// src/delivery/onedrive.ts
|
|
79043
79043
|
import { basename as basename5 } from "node:path";
|
|
@@ -79169,7 +79169,119 @@ async function deliverToOneDrive(args) {
|
|
|
79169
79169
|
return { itemId: item.id, link, folderPath: `Switchroom/${args.agentName}` };
|
|
79170
79170
|
}
|
|
79171
79171
|
|
|
79172
|
+
// src/delivery/gdrive.ts
|
|
79173
|
+
import { basename as basename6 } from "node:path";
|
|
79174
|
+
var DRIVE = "https://www.googleapis.com/drive/v3";
|
|
79175
|
+
var UPLOAD = "https://www.googleapis.com/upload/drive/v3";
|
|
79176
|
+
var FOLDER_MIME = "application/vnd.google-apps.folder";
|
|
79177
|
+
function authHeaders2(token) {
|
|
79178
|
+
return { Authorization: `Bearer ${token}`, Accept: "application/json" };
|
|
79179
|
+
}
|
|
79180
|
+
async function readBody2(resp) {
|
|
79181
|
+
try {
|
|
79182
|
+
const t = await resp.text();
|
|
79183
|
+
return t.length > 300 ? `${t.slice(0, 300)}\u2026` : t;
|
|
79184
|
+
} catch {
|
|
79185
|
+
return "";
|
|
79186
|
+
}
|
|
79187
|
+
}
|
|
79188
|
+
async function ensureFolder2(deps, name, parentId) {
|
|
79189
|
+
const f = deps.fetchImpl ?? fetch;
|
|
79190
|
+
const safeName = name.replace(/'/g, "\\'");
|
|
79191
|
+
const q = `name='${safeName}' and mimeType='${FOLDER_MIME}' and '${parentId}' in parents and trashed=false`;
|
|
79192
|
+
const listUrl = `${DRIVE}/files?q=${encodeURIComponent(q)}&fields=files(id,name)&spaces=drive`;
|
|
79193
|
+
const list2 = await f(listUrl, { headers: authHeaders2(deps.accessToken) });
|
|
79194
|
+
if (!list2.ok) {
|
|
79195
|
+
throw new Error(`Drive folder lookup failed: HTTP ${list2.status} \u2014 ${await readBody2(list2)}`);
|
|
79196
|
+
}
|
|
79197
|
+
const found = await list2.json();
|
|
79198
|
+
if (found.files && found.files.length > 0)
|
|
79199
|
+
return found.files[0];
|
|
79200
|
+
const created = await f(`${DRIVE}/files?fields=id,name`, {
|
|
79201
|
+
method: "POST",
|
|
79202
|
+
headers: { ...authHeaders2(deps.accessToken), "Content-Type": "application/json" },
|
|
79203
|
+
body: JSON.stringify({ name, mimeType: FOLDER_MIME, parents: [parentId] })
|
|
79204
|
+
});
|
|
79205
|
+
if (!created.ok) {
|
|
79206
|
+
throw new Error(`Drive folder create failed: HTTP ${created.status} \u2014 ${await readBody2(created)}`);
|
|
79207
|
+
}
|
|
79208
|
+
return await created.json();
|
|
79209
|
+
}
|
|
79210
|
+
async function ensureSwitchroomFolder2(deps, agentName) {
|
|
79211
|
+
const top = await ensureFolder2(deps, "Switchroom", "root");
|
|
79212
|
+
return ensureFolder2(deps, agentName, top.id);
|
|
79213
|
+
}
|
|
79214
|
+
async function uploadFile2(deps, parentId, filename, bytes, mimeType = "application/octet-stream") {
|
|
79215
|
+
const f = deps.fetchImpl ?? fetch;
|
|
79216
|
+
const boundary = "switchroom-deliver-boundary";
|
|
79217
|
+
const metadata = JSON.stringify({ name: filename, parents: [parentId] });
|
|
79218
|
+
const enc = new TextEncoder;
|
|
79219
|
+
const head = enc.encode(`--${boundary}\r
|
|
79220
|
+
Content-Type: application/json; charset=UTF-8\r
|
|
79221
|
+
\r
|
|
79222
|
+
${metadata}\r
|
|
79223
|
+
` + `--${boundary}\r
|
|
79224
|
+
Content-Type: ${mimeType}\r
|
|
79225
|
+
\r
|
|
79226
|
+
`);
|
|
79227
|
+
const tail = enc.encode(`\r
|
|
79228
|
+
--${boundary}--`);
|
|
79229
|
+
const body = new Uint8Array(head.length + bytes.length + tail.length);
|
|
79230
|
+
body.set(head, 0);
|
|
79231
|
+
body.set(bytes, head.length);
|
|
79232
|
+
body.set(tail, head.length + bytes.length);
|
|
79233
|
+
const resp = await f(`${UPLOAD}/files?uploadType=multipart&fields=id,name,webViewLink`, {
|
|
79234
|
+
method: "POST",
|
|
79235
|
+
headers: {
|
|
79236
|
+
Authorization: `Bearer ${deps.accessToken}`,
|
|
79237
|
+
"Content-Type": `multipart/related; boundary=${boundary}`
|
|
79238
|
+
},
|
|
79239
|
+
body
|
|
79240
|
+
});
|
|
79241
|
+
if (!resp.ok) {
|
|
79242
|
+
throw new Error(`Drive upload failed: HTTP ${resp.status} \u2014 ${await readBody2(resp)}`);
|
|
79243
|
+
}
|
|
79244
|
+
return await resp.json();
|
|
79245
|
+
}
|
|
79246
|
+
async function createShareLink2(deps, file, scopes = ["anyone"]) {
|
|
79247
|
+
const f = deps.fetchImpl ?? fetch;
|
|
79248
|
+
for (const type of scopes) {
|
|
79249
|
+
const resp = await f(`${DRIVE}/files/${file.id}/permissions`, {
|
|
79250
|
+
method: "POST",
|
|
79251
|
+
headers: { ...authHeaders2(deps.accessToken), "Content-Type": "application/json" },
|
|
79252
|
+
body: JSON.stringify(type === "domain" ? { role: "reader", type: "domain" } : { role: "reader", type: "anyone" })
|
|
79253
|
+
});
|
|
79254
|
+
if (resp.ok)
|
|
79255
|
+
break;
|
|
79256
|
+
}
|
|
79257
|
+
if (file.webViewLink)
|
|
79258
|
+
return file.webViewLink;
|
|
79259
|
+
const meta = await f(`${DRIVE}/files/${file.id}?fields=webViewLink`, {
|
|
79260
|
+
headers: authHeaders2(deps.accessToken)
|
|
79261
|
+
});
|
|
79262
|
+
if (meta.ok) {
|
|
79263
|
+
const j = await meta.json();
|
|
79264
|
+
if (j.webViewLink)
|
|
79265
|
+
return j.webViewLink;
|
|
79266
|
+
}
|
|
79267
|
+
throw new Error("Drive: could not resolve a webViewLink for the uploaded file");
|
|
79268
|
+
}
|
|
79269
|
+
async function deliverToGoogleDrive(args) {
|
|
79270
|
+
const deps = { accessToken: args.accessToken, fetchImpl: args.fetchImpl };
|
|
79271
|
+
const folder = await ensureSwitchroomFolder2(deps, args.agentName);
|
|
79272
|
+
const filename = basename6(args.localPath);
|
|
79273
|
+
const file = await uploadFile2(deps, folder.id, filename, args.bytes);
|
|
79274
|
+
const link = await createShareLink2(deps, file, args.linkScopes);
|
|
79275
|
+
return { itemId: file.id, link, folderPath: `Switchroom/${args.agentName}` };
|
|
79276
|
+
}
|
|
79277
|
+
|
|
79172
79278
|
// src/cli/deliver-file.ts
|
|
79279
|
+
function resolveGoogleLinkScopes(env2 = process.env) {
|
|
79280
|
+
const raw = (env2.SWITCHROOM_DELIVER_LINK_SCOPE ?? "").trim().toLowerCase();
|
|
79281
|
+
if (raw === "organization")
|
|
79282
|
+
return ["domain"];
|
|
79283
|
+
return ["anyone"];
|
|
79284
|
+
}
|
|
79173
79285
|
function resolveLinkScopes(env2 = process.env) {
|
|
79174
79286
|
const raw = (env2.SWITCHROOM_DELIVER_LINK_SCOPE ?? "").trim().toLowerCase();
|
|
79175
79287
|
if (raw === "organization")
|
|
@@ -79182,22 +79294,41 @@ function safeAgentName(name) {
|
|
|
79182
79294
|
const n = (name ?? "").trim();
|
|
79183
79295
|
return /^[a-z0-9][a-z0-9_-]{0,50}$/.test(n) ? n : "agent";
|
|
79184
79296
|
}
|
|
79185
|
-
async function
|
|
79297
|
+
async function brokerToken(provider) {
|
|
79186
79298
|
const client2 = new AuthBrokerClient;
|
|
79187
|
-
|
|
79188
|
-
|
|
79189
|
-
|
|
79190
|
-
|
|
79191
|
-
|
|
79299
|
+
try {
|
|
79300
|
+
const data = await client2.getCredentials(provider);
|
|
79301
|
+
const creds = data.credentials;
|
|
79302
|
+
const token = provider === "microsoft" ? creds?.microsoftOauth?.accessToken : creds?.googleOauth?.accessToken;
|
|
79303
|
+
return token ?? null;
|
|
79304
|
+
} catch {
|
|
79305
|
+
return null;
|
|
79306
|
+
} finally {
|
|
79307
|
+
await client2.close().catch(() => {});
|
|
79192
79308
|
}
|
|
79193
|
-
|
|
79309
|
+
}
|
|
79310
|
+
async function defaultResolveProvider() {
|
|
79311
|
+
const ms = await brokerToken("microsoft");
|
|
79312
|
+
if (ms) {
|
|
79313
|
+
return {
|
|
79314
|
+
name: "OneDrive",
|
|
79315
|
+
deliver: (a) => deliverToOneDrive({ ...a, accessToken: ms, linkScopes: resolveLinkScopes() })
|
|
79316
|
+
};
|
|
79317
|
+
}
|
|
79318
|
+
const g = await brokerToken("google");
|
|
79319
|
+
if (g) {
|
|
79320
|
+
return {
|
|
79321
|
+
name: "Google Drive",
|
|
79322
|
+
deliver: (a) => deliverToGoogleDrive({ ...a, accessToken: g, linkScopes: resolveGoogleLinkScopes() })
|
|
79323
|
+
};
|
|
79324
|
+
}
|
|
79325
|
+
return null;
|
|
79194
79326
|
}
|
|
79195
79327
|
async function runDeliverFile(localPath, deps = {}) {
|
|
79196
79328
|
const agentName = safeAgentName(deps.agentName ?? process.env.SWITCHROOM_AGENT_NAME);
|
|
79197
79329
|
const sizeOf = deps.fileSize ?? ((p) => statSync28(p).size);
|
|
79198
79330
|
const read = deps.readFile ?? ((p) => new Uint8Array(readFileSync58(p)));
|
|
79199
|
-
const
|
|
79200
|
-
const deliver = deps.deliver ?? ((a) => deliverToOneDrive({ ...a, linkScopes: resolveLinkScopes() }));
|
|
79331
|
+
const resolveProvider = deps.resolveProvider ?? defaultResolveProvider;
|
|
79201
79332
|
let size;
|
|
79202
79333
|
try {
|
|
79203
79334
|
size = sizeOf(localPath);
|
|
@@ -79207,28 +79338,26 @@ async function runDeliverFile(localPath, deps = {}) {
|
|
|
79207
79338
|
if (size === 0) {
|
|
79208
79339
|
return { ok: false, error: `file is empty: ${localPath}` };
|
|
79209
79340
|
}
|
|
79210
|
-
|
|
79211
|
-
|
|
79212
|
-
accessToken = await getToken("microsoft");
|
|
79213
|
-
} catch (err) {
|
|
79341
|
+
const provider = await resolveProvider();
|
|
79342
|
+
if (!provider) {
|
|
79214
79343
|
return {
|
|
79215
79344
|
ok: false,
|
|
79216
|
-
error: `no connected drive for delivery
|
|
79345
|
+
error: `no connected drive for delivery. Connect a Microsoft or Google ` + `account from the dashboard, or send the file directly with the ` + `reply tool (files: ["${localPath}"]) for files under 50MB.`
|
|
79217
79346
|
};
|
|
79218
79347
|
}
|
|
79219
79348
|
try {
|
|
79220
79349
|
const bytes = read(localPath);
|
|
79221
|
-
const out = await deliver({
|
|
79222
|
-
return { ok: true, link: out.link, folderPath: out.folderPath, filename:
|
|
79350
|
+
const out = await provider.deliver({ agentName, localPath, bytes });
|
|
79351
|
+
return { ok: true, provider: provider.name, link: out.link, folderPath: out.folderPath, filename: basename7(localPath) };
|
|
79223
79352
|
} catch (err) {
|
|
79224
|
-
return { ok: false, error: `upload failed: ${err.message}` };
|
|
79353
|
+
return { ok: false, provider: provider.name, error: `upload failed: ${err.message}` };
|
|
79225
79354
|
}
|
|
79226
79355
|
}
|
|
79227
79356
|
function registerDeliverFileCommand(program3) {
|
|
79228
79357
|
program3.command("deliver-file").description("Deliver a file you produced to the user: upload it to their Switchroom/<agent>/ folder on the connected drive and print a shareable link. Reply with that link \u2014 never a local container path.").argument("<path>", "absolute local path of the file to deliver").action(async (path7) => {
|
|
79229
79358
|
const res = await runDeliverFile(path7);
|
|
79230
79359
|
if (res.ok) {
|
|
79231
|
-
process.stdout.write(`Delivered ${res.filename} to the user's
|
|
79360
|
+
process.stdout.write(`Delivered ${res.filename} to the user's ${res.provider} \u2192 ${res.folderPath}/
|
|
79232
79361
|
` + `Share link (reply with this): ${res.link}
|
|
79233
79362
|
`);
|
|
79234
79363
|
return;
|
package/package.json
CHANGED
|
@@ -52889,11 +52889,11 @@ function sweepStaleTurnActiveMarker(stateDir, opts) {
|
|
|
52889
52889
|
}
|
|
52890
52890
|
|
|
52891
52891
|
// ../src/build-info.ts
|
|
52892
|
-
var VERSION = "0.14.
|
|
52893
|
-
var COMMIT_SHA = "
|
|
52894
|
-
var COMMIT_DATE = "2026-06-
|
|
52895
|
-
var LATEST_PR =
|
|
52896
|
-
var COMMITS_AHEAD_OF_TAG =
|
|
52892
|
+
var VERSION = "0.14.89";
|
|
52893
|
+
var COMMIT_SHA = "125cbcc5";
|
|
52894
|
+
var COMMIT_DATE = "2026-06-08T07:42:50+10:00";
|
|
52895
|
+
var LATEST_PR = null;
|
|
52896
|
+
var COMMITS_AHEAD_OF_TAG = 2;
|
|
52897
52897
|
|
|
52898
52898
|
// gateway/boot-version.ts
|
|
52899
52899
|
function formatRelativeAgo(iso) {
|