@tablation/crew 0.100.3 → 0.101.0
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.js +32 -2
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -19973,6 +19973,7 @@ async function execute(h, args, streaming, after) {
|
|
|
19973
19973
|
var isPeriscopePath = (p) => p === "/periscopes" || p.startsWith("/periscopes/");
|
|
19974
19974
|
async function handlePeriscopes(h, q) {
|
|
19975
19975
|
if (!h || !h.routes.some((r) => r.hostPeriscopes)) return err(404, "not found");
|
|
19976
|
+
if (!q.token) return err(401, "a bearer token is required");
|
|
19976
19977
|
const down = /^\/periscopes\/([^/]+)\/down$/.exec(q.path);
|
|
19977
19978
|
const isUp = q.path === "/periscopes" && q.method === "POST";
|
|
19978
19979
|
const isList = q.path === "/periscopes" && q.method === "GET";
|
|
@@ -19989,6 +19990,7 @@ async function handlePeriscopes(h, q) {
|
|
|
19989
19990
|
const named = q.query.get("route") ?? void 0;
|
|
19990
19991
|
const candidates2 = named === void 0 ? h.routes.filter((r) => r.hostPeriscopes) : [pickRoute(h, named)];
|
|
19991
19992
|
const rows = [];
|
|
19993
|
+
const hosting = [];
|
|
19992
19994
|
for (const c of candidates2) {
|
|
19993
19995
|
if ("status" in c) return c;
|
|
19994
19996
|
const denied2 = await member(c.workspaceId);
|
|
@@ -20001,12 +20003,21 @@ async function handlePeriscopes(h, q) {
|
|
|
20001
20003
|
if (r.code !== 0) return err(failureStatus(r), cliMessage(r));
|
|
20002
20004
|
try {
|
|
20003
20005
|
const list = JSON.parse(r.stdout);
|
|
20004
|
-
|
|
20006
|
+
const mine = Array.isArray(list) ? list : [];
|
|
20007
|
+
for (const e of mine) rows.push({ route: c.route, ...e });
|
|
20008
|
+
hosting.push({
|
|
20009
|
+
route: c.route,
|
|
20010
|
+
workspaceId: c.workspaceId,
|
|
20011
|
+
previewHostSet: !!h.previewHost,
|
|
20012
|
+
maxPeriscopes: h.maxPeriscopes,
|
|
20013
|
+
live: mine.length,
|
|
20014
|
+
repos: h.previewRepos?.(c.route) ?? []
|
|
20015
|
+
});
|
|
20005
20016
|
} catch {
|
|
20006
20017
|
return err(502, "the list command did not answer JSON");
|
|
20007
20018
|
}
|
|
20008
20019
|
}
|
|
20009
|
-
return reply(200, { periscopes: rows });
|
|
20020
|
+
return reply(200, { periscopes: rows, hosting });
|
|
20010
20021
|
}
|
|
20011
20022
|
const b = q.body;
|
|
20012
20023
|
if (!b) return err(400, "body must be a small JSON object");
|
|
@@ -20136,6 +20147,7 @@ var ControlAuth = class {
|
|
|
20136
20147
|
async verifyIn(token, workspaceId) {
|
|
20137
20148
|
if (!token) return "unauthorized";
|
|
20138
20149
|
for (const k of this.o.shipKeys()) if (k && secretsMatch(token, k)) return "ok";
|
|
20150
|
+
for (const k of this.o.workspaceSecrets?.(workspaceId) ?? []) if (k && secretsMatch(token, k)) return "ok";
|
|
20139
20151
|
const now = (this.o.now ?? Date.now)();
|
|
20140
20152
|
const id = `${workspaceId}:${createHash9("sha256").update(token).digest("hex")}`;
|
|
20141
20153
|
const hit = this.cache.get(id);
|
|
@@ -20465,6 +20477,9 @@ async function startControlServer(deps) {
|
|
|
20465
20477
|
if (!deps.periscopeMcp) return send(res, err2(404, "not found"));
|
|
20466
20478
|
return await deps.periscopeMcp(req, res, decodeURIComponent(mcp[1]));
|
|
20467
20479
|
}
|
|
20480
|
+
if (isPeriscopePath(new URL(req.url ?? "/", "http://ship").pathname.replace(/\/+$/, "") || "/")) {
|
|
20481
|
+
return await send(res, await route(deps, req.method ?? "GET", new URL(req.url ?? "/", "http://ship"), req, abort.signal));
|
|
20482
|
+
}
|
|
20468
20483
|
const m = /^Bearer (.+)$/.exec(req.headers.authorization ?? "");
|
|
20469
20484
|
const verdict = await deps.auth.verify(m?.[1]?.trim() ?? "");
|
|
20470
20485
|
if (verdict === "unauthorized") return send(res, err2(401, "invalid or revoked key"));
|
|
@@ -22979,6 +22994,10 @@ ${cu.tail.trimEnd()}
|
|
|
22979
22994
|
return [];
|
|
22980
22995
|
}
|
|
22981
22996
|
}),
|
|
22997
|
+
workspaceSecrets: (ws) => {
|
|
22998
|
+
const sec = readPersistedTunnel(cfg.ship.stateDir, ws)?.mcpSecret;
|
|
22999
|
+
return sec ? [sec] : [];
|
|
23000
|
+
},
|
|
22982
23001
|
userAgent: cfg.ship.userAgent
|
|
22983
23002
|
});
|
|
22984
23003
|
const controlServer = await startControlServer({
|
|
@@ -22992,6 +23011,17 @@ ${cu.tail.trimEnd()}
|
|
|
22992
23011
|
maxPeriscopes: cfg.ship.maxPeriscopes,
|
|
22993
23012
|
run: runCrew,
|
|
22994
23013
|
verifyIn: (token, ws) => controlAuth.verifyIn(token, ws),
|
|
23014
|
+
previewRepos: (routeName) => {
|
|
23015
|
+
const r = controlRoutes.find((x) => x.route === routeName);
|
|
23016
|
+
if (!r) return [];
|
|
23017
|
+
return reposOf(r).filter((t) => {
|
|
23018
|
+
try {
|
|
23019
|
+
return !!loadRepoConfig(t.dir)?.hooks.preview;
|
|
23020
|
+
} catch {
|
|
23021
|
+
return false;
|
|
23022
|
+
}
|
|
23023
|
+
}).map((t) => t.name);
|
|
23024
|
+
},
|
|
22995
23025
|
mcp: {
|
|
22996
23026
|
onUp: async (r, done) => {
|
|
22997
23027
|
const id = typeof done.ticketRecordId === "string" ? done.ticketRecordId : "";
|
package/package.json
CHANGED