@tablation/crew 0.100.2 → 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 +41 -7
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -19476,12 +19476,12 @@ async function runOnePassUnguarded(o) {
|
|
|
19476
19476
|
live.delete(role);
|
|
19477
19477
|
continue;
|
|
19478
19478
|
}
|
|
19479
|
-
|
|
19480
|
-
let ready = () => {
|
|
19479
|
+
let settle = () => {
|
|
19481
19480
|
};
|
|
19482
19481
|
const settled = new Promise((resolve7) => {
|
|
19483
|
-
|
|
19482
|
+
settle = resolve7;
|
|
19484
19483
|
});
|
|
19484
|
+
const ready = (tookTicket2) => settle(tookTicket2);
|
|
19485
19485
|
const run2 = spawn9(role, decision, ctx, { ready }).then(() => {
|
|
19486
19486
|
breaker.recordSuccess(role);
|
|
19487
19487
|
clearShipAttention(o.state, `role_parked:${role}`);
|
|
@@ -19527,18 +19527,20 @@ async function runOnePassUnguarded(o) {
|
|
|
19527
19527
|
}
|
|
19528
19528
|
}).finally(() => {
|
|
19529
19529
|
lock.release();
|
|
19530
|
-
|
|
19530
|
+
settle(void 0);
|
|
19531
19531
|
});
|
|
19532
19532
|
if (o.inFlight) {
|
|
19533
19533
|
const set = o.inFlight;
|
|
19534
19534
|
set.add(run2);
|
|
19535
19535
|
void run2.finally(() => set.delete(run2));
|
|
19536
19536
|
}
|
|
19537
|
+
const reported = TICKET_ROLES.has(role) ? await settled : true;
|
|
19538
|
+
const tookTicket = reported !== false;
|
|
19539
|
+
if (tookTicket) started.push(role);
|
|
19537
19540
|
if (roleCap(role) <= 1) {
|
|
19538
19541
|
live.delete(role);
|
|
19539
19542
|
continue;
|
|
19540
19543
|
}
|
|
19541
|
-
const tookTicket = await settled;
|
|
19542
19544
|
if (tookTicket && count + 1 < roleCap(role)) live.set(role, count + 1);
|
|
19543
19545
|
else live.delete(role);
|
|
19544
19546
|
}
|
|
@@ -19768,6 +19770,8 @@ async function runRoleAgentLocked(role, decision, ctx, hooks, held) {
|
|
|
19768
19770
|
);
|
|
19769
19771
|
return;
|
|
19770
19772
|
}
|
|
19773
|
+
} else {
|
|
19774
|
+
hooks?.ready(true);
|
|
19771
19775
|
}
|
|
19772
19776
|
}
|
|
19773
19777
|
const plan = planAgentRun({
|
|
@@ -19969,6 +19973,7 @@ async function execute(h, args, streaming, after) {
|
|
|
19969
19973
|
var isPeriscopePath = (p) => p === "/periscopes" || p.startsWith("/periscopes/");
|
|
19970
19974
|
async function handlePeriscopes(h, q) {
|
|
19971
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");
|
|
19972
19977
|
const down = /^\/periscopes\/([^/]+)\/down$/.exec(q.path);
|
|
19973
19978
|
const isUp = q.path === "/periscopes" && q.method === "POST";
|
|
19974
19979
|
const isList = q.path === "/periscopes" && q.method === "GET";
|
|
@@ -19985,6 +19990,7 @@ async function handlePeriscopes(h, q) {
|
|
|
19985
19990
|
const named = q.query.get("route") ?? void 0;
|
|
19986
19991
|
const candidates2 = named === void 0 ? h.routes.filter((r) => r.hostPeriscopes) : [pickRoute(h, named)];
|
|
19987
19992
|
const rows = [];
|
|
19993
|
+
const hosting = [];
|
|
19988
19994
|
for (const c of candidates2) {
|
|
19989
19995
|
if ("status" in c) return c;
|
|
19990
19996
|
const denied2 = await member(c.workspaceId);
|
|
@@ -19997,12 +20003,21 @@ async function handlePeriscopes(h, q) {
|
|
|
19997
20003
|
if (r.code !== 0) return err(failureStatus(r), cliMessage(r));
|
|
19998
20004
|
try {
|
|
19999
20005
|
const list = JSON.parse(r.stdout);
|
|
20000
|
-
|
|
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
|
+
});
|
|
20001
20016
|
} catch {
|
|
20002
20017
|
return err(502, "the list command did not answer JSON");
|
|
20003
20018
|
}
|
|
20004
20019
|
}
|
|
20005
|
-
return reply(200, { periscopes: rows });
|
|
20020
|
+
return reply(200, { periscopes: rows, hosting });
|
|
20006
20021
|
}
|
|
20007
20022
|
const b = q.body;
|
|
20008
20023
|
if (!b) return err(400, "body must be a small JSON object");
|
|
@@ -20132,6 +20147,7 @@ var ControlAuth = class {
|
|
|
20132
20147
|
async verifyIn(token, workspaceId) {
|
|
20133
20148
|
if (!token) return "unauthorized";
|
|
20134
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";
|
|
20135
20151
|
const now = (this.o.now ?? Date.now)();
|
|
20136
20152
|
const id = `${workspaceId}:${createHash9("sha256").update(token).digest("hex")}`;
|
|
20137
20153
|
const hit = this.cache.get(id);
|
|
@@ -20461,6 +20477,9 @@ async function startControlServer(deps) {
|
|
|
20461
20477
|
if (!deps.periscopeMcp) return send(res, err2(404, "not found"));
|
|
20462
20478
|
return await deps.periscopeMcp(req, res, decodeURIComponent(mcp[1]));
|
|
20463
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
|
+
}
|
|
20464
20483
|
const m = /^Bearer (.+)$/.exec(req.headers.authorization ?? "");
|
|
20465
20484
|
const verdict = await deps.auth.verify(m?.[1]?.trim() ?? "");
|
|
20466
20485
|
if (verdict === "unauthorized") return send(res, err2(401, "invalid or revoked key"));
|
|
@@ -22975,6 +22994,10 @@ ${cu.tail.trimEnd()}
|
|
|
22975
22994
|
return [];
|
|
22976
22995
|
}
|
|
22977
22996
|
}),
|
|
22997
|
+
workspaceSecrets: (ws) => {
|
|
22998
|
+
const sec = readPersistedTunnel(cfg.ship.stateDir, ws)?.mcpSecret;
|
|
22999
|
+
return sec ? [sec] : [];
|
|
23000
|
+
},
|
|
22978
23001
|
userAgent: cfg.ship.userAgent
|
|
22979
23002
|
});
|
|
22980
23003
|
const controlServer = await startControlServer({
|
|
@@ -22988,6 +23011,17 @@ ${cu.tail.trimEnd()}
|
|
|
22988
23011
|
maxPeriscopes: cfg.ship.maxPeriscopes,
|
|
22989
23012
|
run: runCrew,
|
|
22990
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
|
+
},
|
|
22991
23025
|
mcp: {
|
|
22992
23026
|
onUp: async (r, done) => {
|
|
22993
23027
|
const id = typeof done.ticketRecordId === "string" ? done.ticketRecordId : "";
|
package/package.json
CHANGED