squadrant 0.23.0 → 0.24.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/index.js +150 -142
- package/dist/index.js.map +1 -1
- package/dist/squadrantd.js +46 -25
- package/dist/squadrantd.js.map +1 -1
- package/package.json +1 -1
- package/plugin/skills/gate/SKILL.md +8 -0
- package/plugin/skills/set-gate/SKILL.md +66 -0
package/dist/squadrantd.js
CHANGED
|
@@ -4489,8 +4489,10 @@ async function resolveAndPersistOpencodeCaptain(opts) {
|
|
|
4489
4489
|
sleep: opts.sleep,
|
|
4490
4490
|
fetchImpl: opts.fetchImpl
|
|
4491
4491
|
});
|
|
4492
|
-
if (!sessionId)
|
|
4492
|
+
if (!sessionId) {
|
|
4493
|
+
opts.log?.(`opencode captain session resolution timed out for ${opts.project} (${opts.directory}) \u2014 captain.json has no session id yet; the daemon's own re-resolve fills it in once a session appears`);
|
|
4493
4494
|
return null;
|
|
4495
|
+
}
|
|
4494
4496
|
writeCaptainAddress(opts.stateRoot, opts.project, {
|
|
4495
4497
|
agent: "opencode",
|
|
4496
4498
|
port: opts.port,
|
|
@@ -4510,6 +4512,33 @@ var init_opencode_session = __esm({
|
|
|
4510
4512
|
function discoverCaptainSurface(surfaces, captainTitle) {
|
|
4511
4513
|
return surfaces.find((s) => s.title === captainTitle) ?? null;
|
|
4512
4514
|
}
|
|
4515
|
+
async function reresolveOpencodeAddress(rec) {
|
|
4516
|
+
const live = discoverLiveOpencodeServer({ directory: rec.directory, sessionId: rec.sessionId });
|
|
4517
|
+
const port = live?.port ?? rec.port;
|
|
4518
|
+
if (port === void 0)
|
|
4519
|
+
return null;
|
|
4520
|
+
const newest = newestSessionInDirectory(await listSessions(port), rec.directory, Date.parse(rec.launchedAt));
|
|
4521
|
+
const sessionId = newest ?? live?.sessionId ?? rec.sessionId;
|
|
4522
|
+
if (!sessionId || port === rec.port && sessionId === rec.sessionId)
|
|
4523
|
+
return null;
|
|
4524
|
+
return { port, sessionId };
|
|
4525
|
+
}
|
|
4526
|
+
async function healStaleOpencodeAddress(stateRoot, project, log, logPrefix) {
|
|
4527
|
+
const rec = readCaptainAddress(stateRoot, project);
|
|
4528
|
+
if (!rec)
|
|
4529
|
+
return false;
|
|
4530
|
+
const resolved = await reresolveOpencodeAddress(rec);
|
|
4531
|
+
if (!resolved)
|
|
4532
|
+
return false;
|
|
4533
|
+
const current = readCaptainAddress(stateRoot, project);
|
|
4534
|
+
if (!current || current.launchedAt !== rec.launchedAt) {
|
|
4535
|
+
log(`captain-channel ${project}: skipped stale-address heal \u2014 a newer launch record won the race`);
|
|
4536
|
+
return false;
|
|
4537
|
+
}
|
|
4538
|
+
writeCaptainAddress(stateRoot, project, { ...current, port: resolved.port, sessionId: resolved.sessionId });
|
|
4539
|
+
log(`captain-channel ${project}: ${logPrefix} \u2192 port ${resolved.port}`);
|
|
4540
|
+
return true;
|
|
4541
|
+
}
|
|
4513
4542
|
async function reapOrphanedCrews(store, project, isSurfaceAlive) {
|
|
4514
4543
|
let reaped = 0;
|
|
4515
4544
|
for (const r of store.list(project)) {
|
|
@@ -4734,27 +4763,7 @@ function createDelivery(ctx, daemonCmux, isSurfaceAlive) {
|
|
|
4734
4763
|
log(`captain-channel ${project}: threw, falling back to pane \u2014 ${e.message}`);
|
|
4735
4764
|
}
|
|
4736
4765
|
if (agent === "opencode" && mode !== "off") {
|
|
4737
|
-
const
|
|
4738
|
-
let healed = false;
|
|
4739
|
-
if (rec?.port) {
|
|
4740
|
-
const fresh = newestSessionInDirectory(await listSessions(rec.port), rec.directory, Date.parse(rec.launchedAt));
|
|
4741
|
-
if (fresh && fresh !== rec.sessionId) {
|
|
4742
|
-
writeCaptainAddress(stateRoot, project, { ...rec, sessionId: fresh });
|
|
4743
|
-
healed = true;
|
|
4744
|
-
}
|
|
4745
|
-
}
|
|
4746
|
-
if (!healed && rec) {
|
|
4747
|
-
const live = discoverLiveOpencodeServer({ directory: rec.directory, sessionId: rec.sessionId });
|
|
4748
|
-
if (live && (live.port !== rec.port || live.sessionId && live.sessionId !== rec.sessionId)) {
|
|
4749
|
-
writeCaptainAddress(stateRoot, project, {
|
|
4750
|
-
...rec,
|
|
4751
|
-
port: live.port,
|
|
4752
|
-
sessionId: live.sessionId ?? rec.sessionId
|
|
4753
|
-
});
|
|
4754
|
-
log(`captain-channel ${project}: re-resolved opencode address \u2192 port ${live.port}`);
|
|
4755
|
-
healed = true;
|
|
4756
|
-
}
|
|
4757
|
-
}
|
|
4766
|
+
const healed = await healStaleOpencodeAddress(stateRoot, project, log, "re-resolved opencode address");
|
|
4758
4767
|
if (healed) {
|
|
4759
4768
|
try {
|
|
4760
4769
|
const retry = await deliverToCaptain(project, text, { channel: picked, mode, log });
|
|
@@ -5612,11 +5621,15 @@ function parseCommand(text) {
|
|
|
5612
5621
|
}
|
|
5613
5622
|
return entry.build(args);
|
|
5614
5623
|
}
|
|
5615
|
-
var WRITABLE_CONFIG_KEYS, EFFORT_MODES, REGISTRY;
|
|
5624
|
+
var WRITABLE_CONFIG_KEYS, EFFORT_MODES, GATE_MODES2, CONFIG_VALUE_VALIDATORS, REGISTRY;
|
|
5616
5625
|
var init_commands = __esm({
|
|
5617
5626
|
"packages/core/dist/telegram/commands.js"() {
|
|
5618
|
-
WRITABLE_CONFIG_KEYS = ["defaults.effort"];
|
|
5627
|
+
WRITABLE_CONFIG_KEYS = ["defaults.effort", "defaults.gate.mode"];
|
|
5619
5628
|
EFFORT_MODES = /* @__PURE__ */ new Set(["max", "balance", "low"]);
|
|
5629
|
+
GATE_MODES2 = /* @__PURE__ */ new Set(["on", "off", "auto"]);
|
|
5630
|
+
CONFIG_VALUE_VALIDATORS = {
|
|
5631
|
+
"defaults.gate.mode": { valid: GATE_MODES2, usage: "usage: /config set defaults.gate.mode <on|off|auto>" }
|
|
5632
|
+
};
|
|
5620
5633
|
REGISTRY = {
|
|
5621
5634
|
status: { usage: "/status", build: () => ok("status", ["status"]) },
|
|
5622
5635
|
projects: { usage: "/projects", build: () => ok("projects", ["projects", "list"]) },
|
|
@@ -5663,6 +5676,10 @@ var init_commands = __esm({
|
|
|
5663
5676
|
message: `\u26D4 '${key}' is not writable over Telegram. Allowed: ${WRITABLE_CONFIG_KEYS.join(", ")}`
|
|
5664
5677
|
};
|
|
5665
5678
|
}
|
|
5679
|
+
const validator = CONFIG_VALUE_VALIDATORS[key];
|
|
5680
|
+
if (validator && !validator.valid.has(value)) {
|
|
5681
|
+
return usage("config", validator.usage);
|
|
5682
|
+
}
|
|
5666
5683
|
return ok("config", ["config", "set", key, value]);
|
|
5667
5684
|
}
|
|
5668
5685
|
return usage("config", "usage: /config get <key> | /config set <key> <value>");
|
|
@@ -8160,7 +8177,7 @@ var init_permission_gate = __esm({
|
|
|
8160
8177
|
});
|
|
8161
8178
|
|
|
8162
8179
|
// packages/core/dist/auto-gate.js
|
|
8163
|
-
import { createAutoGate, projectGateConfig } from "@squadrant-ai/auto-gate";
|
|
8180
|
+
import { createAutoGate, projectGateConfig, resolveApiKey } from "@squadrant-ai/auto-gate";
|
|
8164
8181
|
function gateForProjection(config) {
|
|
8165
8182
|
const gate = config.defaults.gate;
|
|
8166
8183
|
if (!gate)
|
|
@@ -8174,6 +8191,9 @@ function gateForProjection(config) {
|
|
|
8174
8191
|
out.deny = gate.deny;
|
|
8175
8192
|
return out;
|
|
8176
8193
|
}
|
|
8194
|
+
function hasAutoGateCredential(env = process.env, home) {
|
|
8195
|
+
return Boolean(resolveApiKey({ env, ...home !== void 0 ? { home } : {} }));
|
|
8196
|
+
}
|
|
8177
8197
|
function createSquadrantAutoGate(deps) {
|
|
8178
8198
|
const env = deps.env ?? process.env;
|
|
8179
8199
|
const taskId = env.SQUADRANT_CREW_TASK_ID;
|
|
@@ -9148,6 +9168,7 @@ __export(dist_exports, {
|
|
|
9148
9168
|
freshTrace: () => freshTrace,
|
|
9149
9169
|
gateCacheKey: () => gateCacheKey,
|
|
9150
9170
|
getDaemonPid: () => getDaemonPid,
|
|
9171
|
+
hasAutoGateCredential: () => hasAutoGateCredential,
|
|
9151
9172
|
hasModalOptionList: () => hasModalOptionList,
|
|
9152
9173
|
healCmdFor: () => healCmdFor,
|
|
9153
9174
|
inboundBody: () => inboundBody,
|