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.
@@ -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 rec = readCaptainAddress(stateRoot, project);
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,