squadrant 0.20.1 → 0.20.3

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 CHANGED
@@ -145,6 +145,10 @@ function getDefaultConfig() {
145
145
  // Audit C2: OFF by design — cmux hibernation is global-only and would
146
146
  // hibernate the captain. See the field doc above.
147
147
  cmuxAgentHibernation: false,
148
+ // #667: fresh installs ship native delivery for both proven agents.
149
+ // Existing configs without the block still resolve to "off" (the
150
+ // resolver fallback is the safety net).
151
+ controlChannel: { claude: "on", opencode: "on" },
148
152
  crewRouting: {
149
153
  rules: [
150
154
  { tier: "extreme", match: "redesign|architect|rewrite|from scratch|deep reasoning", agent: "claude", model: "opus" },
@@ -11887,6 +11891,7 @@ var init_api_key_approval = __esm({
11887
11891
  var OpencodeHttpChannel;
11888
11892
  var init_http_channel = __esm({
11889
11893
  "packages/agents/dist/opencode/http-channel.js"() {
11894
+ init_dist2();
11890
11895
  OpencodeHttpChannel = class {
11891
11896
  name = "opencode-http";
11892
11897
  agent = "opencode";
@@ -11895,12 +11900,16 @@ var init_http_channel = __esm({
11895
11900
  fetchImpl;
11896
11901
  portFor;
11897
11902
  sessionFor;
11903
+ directoryFor;
11904
+ createdAfterFor;
11898
11905
  timeoutMs;
11899
11906
  log;
11900
11907
  constructor(deps) {
11901
11908
  this.fetchImpl = deps.fetchImpl ?? fetch;
11902
11909
  this.portFor = deps.portFor;
11903
11910
  this.sessionFor = deps.sessionFor;
11911
+ this.directoryFor = deps.directoryFor;
11912
+ this.createdAfterFor = deps.createdAfterFor;
11904
11913
  this.timeoutMs = deps.timeoutMs ?? 5e3;
11905
11914
  this.log = deps.log;
11906
11915
  }
@@ -11953,11 +11962,24 @@ var init_http_channel = __esm({
11953
11962
  * are tried. This is a capability probe, NOT a version comparison — the honest
11954
11963
  * check is "does this route answer", and neither path is a promised-stable
11955
11964
  * contract. Re-run the smoke suite when opencode is upgraded.
11965
+ *
11966
+ * #787: when the crew's directory is known, resolve by EXACT directory
11967
+ * (realpath-normalized) and never fall back to the project-wide newest.
11968
+ * GET /session is project-scoped (shared by every worktree of the repo), so
11969
+ * "newest" can be a sibling crew's — prompt_async at that id would run the
11970
+ * message in the wrong session.
11971
+ *
11972
+ * #789: opencode creates a session lazily (nothing exists until the first turn),
11973
+ * so a reused worktree dir can hold a prior crew's session. When the crew's
11974
+ * createdAt is known, also require the candidate to have been created at/after
11975
+ * it — otherwise a send resolves a stale session the live TUI is not showing.
11956
11976
  */
11957
11977
  async resolveSession(taskId, port) {
11958
11978
  const cached = this.sessionByTask.get(taskId);
11959
11979
  if (cached)
11960
11980
  return cached;
11981
+ const directory = this.directoryFor?.(taskId);
11982
+ const createdAfterMs = this.createdAfterFor?.(taskId);
11961
11983
  for (const path39 of ["/session?", "/api/session?"]) {
11962
11984
  let res;
11963
11985
  try {
@@ -11975,11 +11997,11 @@ var init_http_channel = __esm({
11975
11997
  }
11976
11998
  if (!Array.isArray(sessions) || sessions.length === 0)
11977
11999
  continue;
11978
- const newest = sessions.reduce((a, b) => (b.time?.updated ?? 0) > (a.time?.updated ?? 0) ? b : a);
11979
- if (!newest?.id)
12000
+ const resolved = directory ? newestSessionInDirectory(sessions, directory, createdAfterMs) : sessions.reduce((a, b) => (b.time?.updated ?? 0) > (a.time?.updated ?? 0) ? b : a).id;
12001
+ if (!resolved)
11980
12002
  continue;
11981
- this.sessionByTask.set(taskId, newest.id);
11982
- return newest.id;
12003
+ this.sessionByTask.set(taskId, resolved);
12004
+ return resolved;
11983
12005
  }
11984
12006
  return void 0;
11985
12007
  }
@@ -16024,6 +16046,14 @@ async function runCrewSend2(project, name, message, opts) {
16024
16046
  const controlChannels = [
16025
16047
  new OpencodeHttpChannel({
16026
16048
  portFor: (taskId) => tasks.find((t) => t.id === taskId)?.serverPort,
16049
+ // #787: scope resolution to the crew's own worktree (TaskRecord.cwd).
16050
+ // opencode's GET /session is project-scoped, so without this the channel
16051
+ // can target a newer sibling crew's / the captain's session.
16052
+ directoryFor: (taskId) => tasks.find((t) => t.id === taskId)?.cwd,
16053
+ // #789: opencode creates sessions lazily, so a reused worktree dir can hold
16054
+ // a prior crew's session. Gate on the crew's createdAt so a stale session
16055
+ // the live TUI is not showing is never selected.
16056
+ createdAfterFor: (taskId) => tasks.find((t) => t.id === taskId)?.createdAt,
16027
16057
  log: (m) => console.error(chalk10.dim(m))
16028
16058
  }),
16029
16059
  new ClaudePeerChannel({