squadrant 0.26.2 → 0.26.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
@@ -5590,9 +5590,13 @@ async function runCrewSpawn(input, config, deps) {
5590
5590
  await deps.runtime.sendToPane(pane2, `cd ${shellQuote(spawnCwd)} && ${envPrefix}${routerPrefix} ${niceCrewCommand(cliCommand2)}`);
5591
5591
  const preLaunchScreen = await deps.runtime.readPaneScreen(pane2) ?? "";
5592
5592
  const claudeFirstTurn = spillOversizedFirstTurn(firstTurnTask, rec.id);
5593
- const sendPromise = deps.sendFirstTurn(pane2, `${claudeFirstTurn}
5593
+ const peerBrief = `${firstTurnTask}
5594
5594
 
5595
- ${buildCompletionProtocol(rec.id, input.project)}`, preLaunchScreen);
5595
+ ${buildCompletionProtocol(rec.id, input.project)}`;
5596
+ const peerResult = deps.sendFirstTurnPeer ? await deps.sendFirstTurnPeer({ pane: pane2, taskId: rec.id, project: input.project, messagingSocketPath, message: peerBrief }).catch(() => ({ kind: "fallback" })) : { kind: "fallback" };
5597
+ const sendPromise = peerResult.kind === "fallback" ? deps.sendFirstTurn(pane2, `${claudeFirstTurn}
5598
+
5599
+ ${buildCompletionProtocol(rec.id, input.project)}`, preLaunchScreen) : Promise.resolve({ delivered: peerResult.kind === "delivered" });
5596
5600
  let agentNotStarted = false;
5597
5601
  const scrapeDelivered = sendPromise.then((r) => {
5598
5602
  agentNotStarted = !!r.agentNotStarted;
@@ -9817,6 +9821,30 @@ async function runCrewAnswer(project, name, option, runtime, workspaceId, deps,
9817
9821
  if (!crew) {
9818
9822
  throw new Error(`Crew '${name}' not found for ${project}. Run 'squadrant crew list ${project}'.`);
9819
9823
  }
9824
+ const match = runtime.findDialog && runtime.answerDialog ? await deps.dialogMatch?.() : void 0;
9825
+ if (match) {
9826
+ const dialog = await runtime.findDialog(match).catch(() => void 0);
9827
+ if (dialog) {
9828
+ const log2 = deps.log ?? (() => {
9829
+ });
9830
+ const options2 = dialog.options.map((o) => ({ ...o, highlighted: false }));
9831
+ let target2;
9832
+ try {
9833
+ target2 = resolveOption(options2, option);
9834
+ if (opts?.expect && !target2.label.toLowerCase().includes(opts.expect.toLowerCase()))
9835
+ target2 = void 0;
9836
+ } catch {
9837
+ target2 = void 0;
9838
+ }
9839
+ if (target2) {
9840
+ log2(`\u2192 answering ${target2.index}. "${target2.label}" via the runtime (no keystrokes)`);
9841
+ const ok2 = await runtime.answerDialog(dialog, opts?.text ? { text: opts.text } : { label: target2.label }).catch(() => false);
9842
+ if (ok2)
9843
+ return { selected: target2, closed: true };
9844
+ }
9845
+ log2("runtime answer not applied \u2014 falling back to keystrokes");
9846
+ }
9847
+ }
9820
9848
  const modal = await deps.readModalOptions(crew);
9821
9849
  if (!modal || modal.options.length === 0) {
9822
9850
  throw new Error(`Crew '${name}' has no interactive option prompt visible right now \u2014 nothing to answer. Read its screen with 'squadrant crew read ${project} ${name}' to check its state.`);
@@ -10196,6 +10224,58 @@ var init_source = __esm({
10196
10224
  }
10197
10225
  });
10198
10226
 
10227
+ // packages/core/dist/peer-first-turn.js
10228
+ function screenShowsTrustPanel(screen) {
10229
+ return /do you trust the files in this folder|is this a project you created or one you trust|is this a project you trust/i.test(screen);
10230
+ }
10231
+ function trustPanelAcceptKeys(screen) {
10232
+ return /❯\s*(\d\.\s*)?No\b/.test(screen) ? ["Down", "Enter"] : ["Enter"];
10233
+ }
10234
+ async function deliverFirstTurnViaPeer(message, deps) {
10235
+ const pollMs = deps.pollMs ?? DEFAULT_POLL_MS2;
10236
+ const deadline = deps.now() + (deps.readyTimeoutMs ?? DEFAULT_READY_TIMEOUT_MS);
10237
+ let lastTrustAnswer = -Infinity;
10238
+ for (; ; ) {
10239
+ if (deps.statusOf()?.status === "idle")
10240
+ break;
10241
+ if (deps.now() >= deadline)
10242
+ return { kind: "fallback" };
10243
+ if (!deps.statusOf() && deps.now() - lastTrustAnswer >= TRUST_ANSWER_COOLDOWN_MS) {
10244
+ const screen = await deps.readScreen().catch(() => "");
10245
+ if (screenShowsTrustPanel(screen)) {
10246
+ lastTrustAnswer = deps.now();
10247
+ for (const key of trustPanelAcceptKeys(screen))
10248
+ await deps.pressKey(key).catch(() => {
10249
+ });
10250
+ }
10251
+ }
10252
+ await deps.sleep(pollMs);
10253
+ }
10254
+ const outcome = await deps.send(message);
10255
+ if (fallsBackToPane(outcome))
10256
+ return { kind: "fallback" };
10257
+ if (outcome.status === "accepted" && outcome.confirmed)
10258
+ return { kind: "delivered" };
10259
+ const confirmDeadline = deps.now() + (deps.confirmGraceMs ?? DEFAULT_CONFIRM_GRACE_MS);
10260
+ for (; ; ) {
10261
+ if (await deps.isConfirmed().catch(() => false))
10262
+ return { kind: "delivered" };
10263
+ if (deps.now() >= confirmDeadline)
10264
+ return { kind: "unconfirmed" };
10265
+ await deps.sleep(pollMs);
10266
+ }
10267
+ }
10268
+ var DEFAULT_READY_TIMEOUT_MS, DEFAULT_POLL_MS2, DEFAULT_CONFIRM_GRACE_MS, TRUST_ANSWER_COOLDOWN_MS;
10269
+ var init_peer_first_turn = __esm({
10270
+ "packages/core/dist/peer-first-turn.js"() {
10271
+ init_control_channel();
10272
+ DEFAULT_READY_TIMEOUT_MS = 9e4;
10273
+ DEFAULT_POLL_MS2 = 250;
10274
+ DEFAULT_CONFIRM_GRACE_MS = 1e4;
10275
+ TRUST_ANSWER_COOLDOWN_MS = 5e3;
10276
+ }
10277
+ });
10278
+
10199
10279
  // packages/core/dist/knowledge/paths.js
10200
10280
  import path14 from "path";
10201
10281
  function kbDir(hubVault, kb) {
@@ -13915,6 +13995,7 @@ __export(dist_exports2, {
13915
13995
  defaultIsPidAlive: () => defaultIsPidAlive,
13916
13996
  defaultListenError: () => defaultListenError,
13917
13997
  defaultWorkRoot: () => defaultWorkRoot,
13998
+ deliverFirstTurnViaPeer: () => deliverFirstTurnViaPeer,
13918
13999
  deliverStartupPrompt: () => deliverStartupPrompt,
13919
14000
  deliverToCaptain: () => deliverToCaptain,
13920
14001
  deliverable: () => deliverable,
@@ -14096,6 +14177,7 @@ __export(dist_exports2, {
14096
14177
  saveState: () => saveState,
14097
14178
  screenHasSplashMarker: () => screenHasSplashMarker,
14098
14179
  screenHash: () => screenHash,
14180
+ screenShowsTrustPanel: () => screenShowsTrustPanel,
14099
14181
  searchRules: () => searchRules,
14100
14182
  selectPromptHits: () => selectPromptHits,
14101
14183
  sendRequest: () => sendRequest,
@@ -14121,6 +14203,7 @@ __export(dist_exports2, {
14121
14203
  toControlEvent: () => toControlEvent,
14122
14204
  topicKey: () => topicKey,
14123
14205
  topicName: () => topicName,
14206
+ trustPanelAcceptKeys: () => trustPanelAcceptKeys,
14124
14207
  tryAcquireDaemonLock: () => tryAcquireDaemonLock,
14125
14208
  usageFromJson: () => usageFromJson,
14126
14209
  validateKb: () => validateKb,
@@ -14183,6 +14266,7 @@ var init_dist2 = __esm({
14183
14266
  init_conformance();
14184
14267
  init_source();
14185
14268
  init_control_channel();
14269
+ init_peer_first_turn();
14186
14270
  init_captain_channel();
14187
14271
  init_captain_record();
14188
14272
  init_opencode_session();
@@ -17582,6 +17666,15 @@ async function cmuxHasInputGuards() {
17582
17666
  inputGuardsCache = major > 0 || minor >= 65;
17583
17667
  return inputGuardsCache;
17584
17668
  }
17669
+ function feedSessionOf(item) {
17670
+ const parts = item.workstream_id?.split(":");
17671
+ if (parts?.[0] !== "cmux-feed-v1" || !parts[2])
17672
+ return void 0;
17673
+ return Buffer.from(parts[2], "base64").toString("utf-8");
17674
+ }
17675
+ async function feedRpc(method, params) {
17676
+ return JSON.parse(await cmux(["rpc", method, JSON.stringify(params)]));
17677
+ }
17585
17678
  function parseList(output) {
17586
17679
  let parsed;
17587
17680
  try {
@@ -18005,6 +18098,26 @@ function createCmuxDriver() {
18005
18098
  await cmux(["send-key", "--workspace", wsId, "--surface", surfaceId, "Enter"]);
18006
18099
  return { workspaceId: wsId, surfaceId, title: opts.title };
18007
18100
  },
18101
+ // #916: cmux >= 0.65 `surface.input_state` reads the render grid (incl. faint
18102
+ // spans) without touching the pane. The RPC needs a surface UUID, and an
18103
+ // unknown ref would silently fall back to the focused surface, so resolve the
18104
+ // ref through the tree first. Anything unexpected → undefined (old path).
18105
+ async inputState(pane) {
18106
+ try {
18107
+ if (!await cmuxHasInputGuards())
18108
+ return void 0;
18109
+ const tree = JSON.parse(await cmux(["tree", "--workspace", pane.workspaceId, "--json", "--id-format", "both"]));
18110
+ const id = tree.windows?.flatMap((w) => w.workspaces ?? []).flatMap((w) => w.panes ?? []).flatMap((p) => p.surfaces ?? []).find((s) => s.ref === pane.surfaceId)?.id;
18111
+ if (!id)
18112
+ return void 0;
18113
+ const r = JSON.parse(await cmux(["rpc", "surface.input_state", JSON.stringify({ surface_id: id })]));
18114
+ if (r.agent !== true)
18115
+ return "unknown";
18116
+ return r.state === "empty" || r.state === "draft" || r.state === "dialog" ? r.state : "unknown";
18117
+ } catch {
18118
+ return void 0;
18119
+ }
18120
+ },
18008
18121
  async sendToSurface(surface, text, opts) {
18009
18122
  const ws = surface.workspaceId;
18010
18123
  const sf = surface.surfaceId;
@@ -18031,6 +18144,17 @@ function createCmuxDriver() {
18031
18144
  `);
18032
18145
  }
18033
18146
  };
18147
+ if (opts?.agent !== "opencode") {
18148
+ const state = await this.inputState?.(surface);
18149
+ if (state === "draft")
18150
+ throw new DeferDelivery(null, "draft");
18151
+ if (state === "dialog")
18152
+ throw new DeferDelivery(null, "modal");
18153
+ if (state === "empty") {
18154
+ await deliver();
18155
+ return;
18156
+ }
18157
+ }
18034
18158
  let screen = "";
18035
18159
  try {
18036
18160
  screen = await cmux(["read-screen", "--workspace", ws, "--surface", sf]);
@@ -18109,6 +18233,39 @@ function createCmuxDriver() {
18109
18233
  args.push("--focus", "true");
18110
18234
  await cmux(args);
18111
18235
  },
18236
+ // Feed-backed structured answer (#918). cmux >= 0.65 only; any miss
18237
+ // (old cmux, no matching item, unsupported shape) is undefined so the
18238
+ // caller keeps the keystroke path.
18239
+ async findDialog(match) {
18240
+ if (!await cmuxHasInputGuards())
18241
+ return void 0;
18242
+ let items;
18243
+ try {
18244
+ items = (await feedRpc("feed.list", { pending_only: true })).items ?? [];
18245
+ } catch {
18246
+ return void 0;
18247
+ }
18248
+ const mine = items.filter((i) => match.agentSessionId ? feedSessionOf(i) === match.agentSessionId : !!match.cwd && i.cwd === match.cwd);
18249
+ if (mine.length !== 1 || !mine[0].request_id)
18250
+ return void 0;
18251
+ const item = mine[0];
18252
+ if (item.kind !== "question" || item.questions?.length !== 1)
18253
+ return void 0;
18254
+ const labels = (item.questions[0].options ?? []).map((o) => o.label ?? "");
18255
+ if (labels.length === 0)
18256
+ return void 0;
18257
+ return {
18258
+ id: item.request_id,
18259
+ options: labels.map((label, i) => ({ index: i + 1, label }))
18260
+ };
18261
+ },
18262
+ async answerDialog(dialog, answer) {
18263
+ const reply = answer.text ?? answer.label;
18264
+ if (!reply)
18265
+ return false;
18266
+ const res = await feedRpc("feed.question.reply", { request_id: dialog.id, selections: [reply] });
18267
+ return res.delivered === true;
18268
+ },
18112
18269
  async showPatch(opts) {
18113
18270
  const args = ["diff", "-", "--workspace", opts.workspaceId, "--layout", opts.layout ?? "split"];
18114
18271
  if (opts.title)
@@ -19423,6 +19580,11 @@ async function readModalOptions(runtime, pane) {
19423
19580
  return parseModal(screen);
19424
19581
  }
19425
19582
  async function confirmedSendToPane(runtime, pane, message) {
19583
+ const native = await runtime.inputState?.(pane).catch(() => void 0);
19584
+ if (native === "dialog")
19585
+ return { delivered: false, blockedByModal: true };
19586
+ if (native === "draft")
19587
+ return { delivered: false };
19426
19588
  const preSendScreen = await runtime.readPaneScreen(pane) ?? "";
19427
19589
  if (hasModalOptionList2(preSendScreen)) {
19428
19590
  return { delivered: false, blockedByModal: true };
@@ -21040,9 +21202,9 @@ init_dist4();
21040
21202
  init_dist3();
21041
21203
  init_dist2();
21042
21204
  import { Command as Command10 } from "commander";
21043
- import chalk10 from "chalk";
21044
- import { createServer as createServer4, connect as netConnect } from "net";
21045
- import { randomUUID as randomUUID6 } from "crypto";
21205
+ import chalk11 from "chalk";
21206
+ import { createServer as createServer5, connect as netConnect3 } from "net";
21207
+ import { randomUUID as randomUUID8 } from "crypto";
21046
21208
 
21047
21209
  // packages/cli/src/commands/crew-control.ts
21048
21210
  init_dist2();
@@ -21800,6 +21962,131 @@ function addControlPlaneCrewCommands(crew) {
21800
21962
  var crewControlCommand = new Command9("crew").description("Dispatch and track crew via the squadrant control plane");
21801
21963
  addControlPlaneCrewCommands(crewControlCommand);
21802
21964
 
21965
+ // packages/cli/src/lib/first-turn-peer.ts
21966
+ init_dist3();
21967
+ init_dist2();
21968
+ import { randomUUID as randomUUID7 } from "crypto";
21969
+ import { connect as netConnect2 } from "net";
21970
+
21971
+ // packages/cli/src/lib/captain-channel-factory.ts
21972
+ init_dist3();
21973
+ init_dist2();
21974
+ import { createServer as createServer4, connect as netConnect } from "net";
21975
+ import fs28 from "fs";
21976
+ import { join as join28 } from "path";
21977
+ import { randomUUID as randomUUID6 } from "crypto";
21978
+ import chalk10 from "chalk";
21979
+ var shared;
21980
+ var registryEntryPath = () => join28(CLAUDE_SESSIONS_DIR, `${process.pid}.json`);
21981
+ function unregisterSenderIdentity() {
21982
+ try {
21983
+ fs28.unlinkSync(registryEntryPath());
21984
+ } catch {
21985
+ }
21986
+ }
21987
+ function registerSenderIdentity(socketPath2) {
21988
+ try {
21989
+ unregisterSenderIdentity();
21990
+ fs28.mkdirSync(CLAUDE_SESSIONS_DIR, { recursive: true });
21991
+ fs28.writeFileSync(
21992
+ registryEntryPath(),
21993
+ JSON.stringify({
21994
+ pid: process.pid,
21995
+ sessionId: randomUUID6(),
21996
+ name: "squadrantd",
21997
+ messagingSocketPath: socketPath2,
21998
+ kind: "daemon",
21999
+ peerProtocol: 1
22000
+ })
22001
+ );
22002
+ process.on("exit", unregisterSenderIdentity);
22003
+ } catch {
22004
+ }
22005
+ }
22006
+ async function sharedReceiptListener() {
22007
+ if (shared) return shared;
22008
+ ensureSocksDir();
22009
+ const socketPath2 = `${CC_SOCKS_DIR}/squadrantd-${process.pid}.sock`;
22010
+ const listener = new ClaudeReceiptListener({
22011
+ socketPath: socketPath2,
22012
+ createServer: (h) => createServer4(h),
22013
+ // A UDS path is not cleaned up when a process is killed, so our own leftover
22014
+ // must never be the reason we refuse to start.
22015
+ unlinkStale: (p) => {
22016
+ try {
22017
+ fs28.unlinkSync(p);
22018
+ } catch {
22019
+ }
22020
+ },
22021
+ log: (m) => console.error(chalk10.dim(m))
22022
+ });
22023
+ await listener.start();
22024
+ registerSenderIdentity(socketPath2);
22025
+ shared = listener;
22026
+ return shared;
22027
+ }
22028
+ function captainSessionIdFor(taskId) {
22029
+ return readClaudeStatusBySocketPath(captainSocketPath(taskId))?.sessionId;
22030
+ }
22031
+ async function buildCaptainChannel() {
22032
+ const receipts = await sharedReceiptListener();
22033
+ return new ClaudePeerChannel({
22034
+ // The port's taskId IS the project name for captains.
22035
+ socketPathFor: (taskId) => captainSocketPath(taskId),
22036
+ sessionIdFor: captainSessionIdFor,
22037
+ // Captains are identified in the registry by their cwd (the project path).
22038
+ // Resolve by the socket path squadrant chose at launch, NOT by cwd: a captain
22039
+ // in /tmp/x registers cwd "/private/tmp/x" on macOS, so cwd matching silently
22040
+ // missed and every captain ping reported accepted-unconfirmed.
22041
+ statusFor: (taskId) => readClaudeStatusBySocketPath(captainSocketPath(taskId)),
22042
+ wire: (p, e) => writeLine(p, e, { connect: (path46) => netConnect(path46) }),
22043
+ receipts,
22044
+ newMsgId: () => randomUUID6(),
22045
+ sleep: (ms) => new Promise((r) => setTimeout(r, ms)),
22046
+ log: (m) => console.error(chalk10.dim(m))
22047
+ });
22048
+ }
22049
+ async function buildCaptainChannels(opts) {
22050
+ const claude = await buildCaptainChannel();
22051
+ const opencode = new OpencodeHttpChannel({
22052
+ portFor: (project) => readCaptainAddress(opts.stateRoot, project)?.port,
22053
+ sessionFor: (project) => readCaptainAddress(opts.stateRoot, project)?.sessionId
22054
+ });
22055
+ return {
22056
+ channels: { claude, opencode },
22057
+ agentFor: (project) => resolveCaptainAgent(opts.stateRoot, project, opts.configAgent)
22058
+ };
22059
+ }
22060
+ function resolveCaptainAgent(stateRoot, project, configAgent) {
22061
+ return readCaptainAddress(stateRoot, project)?.agent ?? configAgent;
22062
+ }
22063
+
22064
+ // packages/cli/src/lib/first-turn-peer.ts
22065
+ async function sendClaudeFirstTurnViaPeer(runtime, o, getTaskRecord) {
22066
+ const receipts = await sharedReceiptListener();
22067
+ const channel = new ClaudePeerChannel({
22068
+ socketPathFor: () => o.messagingSocketPath,
22069
+ sessionIdFor: () => readClaudeStatusBySocketPath(o.messagingSocketPath)?.sessionId,
22070
+ statusFor: () => readClaudeStatusBySocketPath(o.messagingSocketPath),
22071
+ wire: (p, e) => writeLine(p, e, { connect: (path46) => netConnect2(path46) }),
22072
+ receipts,
22073
+ newMsgId: () => randomUUID7(),
22074
+ sleep: (ms) => new Promise((r) => setTimeout(r, ms)),
22075
+ // The UserPromptSubmit hook is the real receipt; don't hold spawn for the
22076
+ // default 4s inferred-flip window.
22077
+ confirmWindowMs: 1500
22078
+ });
22079
+ return deliverFirstTurnViaPeer(o.message, {
22080
+ statusOf: () => readClaudeStatusBySocketPath(o.messagingSocketPath),
22081
+ readScreen: async () => await runtime.readPaneScreen(o.pane) ?? "",
22082
+ pressKey: (key) => runtime.sendKeyToPane(o.pane, key),
22083
+ send: (m) => channel.send(o.taskId, m),
22084
+ isConfirmed: async () => !!(await getTaskRecord())?.firstTurnConfirmedAt,
22085
+ sleep: (ms) => new Promise((r) => setTimeout(r, ms)),
22086
+ now: () => Date.now()
22087
+ });
22088
+ }
22089
+
21803
22090
  // packages/cli/src/lib/model-guard.ts
21804
22091
  var ANTHROPIC_MODEL_PREFIX = "anthropic/";
21805
22092
  var BARE_CLAUDE_MODEL_PREFIX = "claude-";
@@ -21818,8 +22105,8 @@ function anthropicRefusalMessage(role, workspaceName, agentName, model) {
21818
22105
 
21819
22106
  // packages/cli/src/commands/crew.ts
21820
22107
  async function fetchRouterCredentials(project, backend, deps) {
21821
- const log = deps.log ?? ((m) => console.log(chalk10.dim(m)));
21822
- const warn = deps.warn ?? ((m) => console.error(chalk10.yellow(m)));
22108
+ const log = deps.log ?? ((m) => console.log(chalk11.dim(m)));
22109
+ const warn = deps.warn ?? ((m) => console.error(chalk11.yellow(m)));
21823
22110
  const creds = await deps.call(buildRouterCredentialsRequest(project, backend));
21824
22111
  if (creds.backend === "direct" && creds.apiKey) {
21825
22112
  const approve = deps.approveKey ?? ensureClaudeApiKeyApproved;
@@ -21855,6 +22142,11 @@ async function runCrewSpawn2(input) {
21855
22142
  writeOpencodeConfig: writePerCrewOpencodeConfig,
21856
22143
  writeRouterSettings,
21857
22144
  sendFirstTurn: (pane, firstTurn, preLaunchScreen, opts) => sendFirstTurnWhenReady(runtime, pane, firstTurn, preLaunchScreen, opts),
22145
+ // #917: claude crews get their first turn over the peer socket when the
22146
+ // claude control channel is `on`; anything else keeps the pane path.
22147
+ ...resolveControlChannelMode(config.defaults.controlChannel, "claude") === "on" ? {
22148
+ sendFirstTurnPeer: (o) => sendClaudeFirstTurnViaPeer(runtime, o, async () => await squadrantdCall(buildStatusRequest(o.project, o.taskId)).catch(() => void 0))
22149
+ } : {},
21858
22150
  getFreePort,
21859
22151
  sendCodexFirstTurn,
21860
22152
  // #466: wire delivery confirmation so the daemon stamps firstTurnConfirmedAt.
@@ -21867,25 +22159,25 @@ async function runCrewSpawn2(input) {
21867
22159
  getTaskRecord: async (p, id) => await squadrantdCall(buildStatusRequest(p, id)).catch(() => void 0),
21868
22160
  isAgentInstalled: (name) => commandExists(name),
21869
22161
  onRouteSkipped: (route, fallback) => console.log(
21870
- chalk10.dim(`routed: tier=${route.tier} \u2192 ${route.agent} (not installed) \u2192 ${fallback}`)
22162
+ chalk11.dim(`routed: tier=${route.tier} \u2192 ${route.agent} (not installed) \u2192 ${fallback}`)
21871
22163
  ),
21872
22164
  onRouted: (route) => console.log(
21873
- chalk10.dim(
22165
+ chalk11.dim(
21874
22166
  `routed: tier=${route.tier} \u2192 ${route.agent}${route.model ? `/${route.model}` : ""} (rule: "${route.matchedRule}")`
21875
22167
  )
21876
22168
  ),
21877
- onBaseResolved: (base) => console.log(chalk10.dim(`base: ${base}`)),
22169
+ onBaseResolved: (base) => console.log(chalk11.dim(`base: ${base}`)),
21878
22170
  // #627 item B: warn (don't block) when a fallback crew silently resolves to
21879
22171
  // an Anthropic model — less catastrophic than a captain on the same path,
21880
22172
  // and more often intentional, so it just needs to be visible.
21881
22173
  onBackendResolved: ({ backend }) => {
21882
- if (backend !== "native") console.log(chalk10.dim(`backend: ${backend}`));
22174
+ if (backend !== "native") console.log(chalk11.dim(`backend: ${backend}`));
21883
22175
  },
21884
22176
  onModelResolved: ({ agentName, model }) => {
21885
22177
  const effectiveModel = model ?? (agentName === "opencode" ? readGlobalOpencodeModel() : void 0);
21886
22178
  if (isBlockedFallback(agentName, effectiveModel)) {
21887
22179
  console.error(
21888
- chalk10.yellow(
22180
+ chalk11.yellow(
21889
22181
  ` \u26A0 ${anthropicFallbackMessage(agentName, effectiveModel)} (crew \u2014 not blocked; pass --model to pin a different provider)`
21890
22182
  )
21891
22183
  );
@@ -21899,8 +22191,8 @@ async function runCrewSend2(project, name, message, opts) {
21899
22191
  let tasks = [];
21900
22192
  const receipts = new ClaudeReceiptListener({
21901
22193
  socketPath: "/tmp/cc-socks/squadrantd.sock",
21902
- createServer: (h) => createServer4(h),
21903
- log: (m) => console.error(chalk10.dim(m))
22194
+ createServer: (h) => createServer5(h),
22195
+ log: (m) => console.error(chalk11.dim(m))
21904
22196
  });
21905
22197
  await receipts.start();
21906
22198
  const controlChannels = [
@@ -21914,17 +22206,17 @@ async function runCrewSend2(project, name, message, opts) {
21914
22206
  // a prior crew's session. Gate on the crew's createdAt so a stale session
21915
22207
  // the live TUI is not showing is never selected.
21916
22208
  createdAfterFor: (taskId) => tasks.find((t) => t.id === taskId)?.createdAt,
21917
- log: (m) => console.error(chalk10.dim(m))
22209
+ log: (m) => console.error(chalk11.dim(m))
21918
22210
  }),
21919
22211
  new ClaudePeerChannel({
21920
22212
  socketPathFor: (taskId) => tasks.find((t) => t.id === taskId)?.messagingSocketPath,
21921
22213
  sessionIdFor: (taskId) => tasks.find((t) => t.id === taskId)?.sessionId,
21922
22214
  statusFor: (taskId) => readClaudeStatus(tasks.find((t) => t.id === taskId)),
21923
- wire: (p, e) => writeLine(p, e, { connect: (path46) => netConnect(path46) }),
22215
+ wire: (p, e) => writeLine(p, e, { connect: (path46) => netConnect3(path46) }),
21924
22216
  receipts,
21925
- newMsgId: () => randomUUID6(),
22217
+ newMsgId: () => randomUUID8(),
21926
22218
  sleep: (ms) => new Promise((r) => setTimeout(r, ms)),
21927
- log: (m) => console.error(chalk10.dim(m))
22219
+ log: (m) => console.error(chalk11.dim(m))
21928
22220
  })
21929
22221
  ];
21930
22222
  try {
@@ -21940,7 +22232,7 @@ async function runCrewSend2(project, name, message, opts) {
21940
22232
  isBlockedByModal: (pane) => paneHasOpenModal(runtime, pane),
21941
22233
  controlChannels,
21942
22234
  controlChannelMode: (agent) => resolveControlChannelMode(cfg.defaults.controlChannel, agent),
21943
- onChannelLog: (m) => console.error(chalk10.dim(m))
22235
+ onChannelLog: (m) => console.error(chalk11.dim(m))
21944
22236
  }, opts);
21945
22237
  } finally {
21946
22238
  receipts.stop();
@@ -21976,7 +22268,14 @@ async function runCrewAnswer2(project, name, option, opts) {
21976
22268
  workspaceId,
21977
22269
  {
21978
22270
  readModalOptions: (pane) => readModalOptions(runtime, pane),
21979
- log: (m) => console.log(chalk10.dim(m))
22271
+ // #918: only claude has a structured answer path; others keep keystrokes.
22272
+ dialogMatch: async () => {
22273
+ const tasks = await squadrantdCall({ kind: "list", project }).catch(() => []);
22274
+ const t = resolveApproveTarget(tasks, name);
22275
+ if (!t || t.provider !== "claude" || !(t.sessionId || t.cwd)) return void 0;
22276
+ return { agentSessionId: t.sessionId, cwd: t.cwd };
22277
+ },
22278
+ log: (m) => console.log(chalk11.dim(m))
21980
22279
  },
21981
22280
  opts
21982
22281
  );
@@ -22014,9 +22313,9 @@ crewCommand.command("spawn").description(
22014
22313
  // into the isolated worktree root for relative-path access.
22015
22314
  ...opts.taskFile && opts.taskFile !== "-" ? { taskFile: opts.taskFile } : {}
22016
22315
  });
22017
- console.log(chalk10.green(`\u2714 Crew '${pane.title}' spawned (${pane.surfaceId})`));
22316
+ console.log(chalk11.green(`\u2714 Crew '${pane.title}' spawned (${pane.surfaceId})`));
22018
22317
  } catch (err) {
22019
- console.error(chalk10.red(err.message));
22318
+ console.error(chalk11.red(err.message));
22020
22319
  process.exit(1);
22021
22320
  }
22022
22321
  }
@@ -22025,7 +22324,7 @@ crewCommand.command("list").description("List live crew sessions for a project")
22025
22324
  try {
22026
22325
  const crews = await runCrewList2(project);
22027
22326
  if (crews.length === 0) {
22028
- console.log(chalk10.yellow(`No live crew sessions for ${project}.`));
22327
+ console.log(chalk11.yellow(`No live crew sessions for ${project}.`));
22029
22328
  return;
22030
22329
  }
22031
22330
  const tasks = await squadrantdCall({ kind: "list", project }).catch(() => []);
@@ -22056,7 +22355,7 @@ crewCommand.command("list").description("List live crew sessions for a project")
22056
22355
  }
22057
22356
  }
22058
22357
  } catch (err) {
22059
- console.error(chalk10.red(err.message));
22358
+ console.error(chalk11.red(err.message));
22060
22359
  process.exit(1);
22061
22360
  }
22062
22361
  });
@@ -22064,10 +22363,10 @@ crewCommand.command("send").description("Send a follow-up message to an existing
22064
22363
  try {
22065
22364
  const resolvedMessage = await resolveTextInput({ positional: message, filePath: opts.messageFile, label: "message" });
22066
22365
  const { reopened } = await runCrewSend2(project, name, resolvedMessage, opts);
22067
- if (reopened) console.log(chalk10.cyan(`\u21BB Task was terminal \u2014 reopened to working`));
22068
- console.log(chalk10.green(`\u2714 Sent to ${project}:${name}`));
22366
+ if (reopened) console.log(chalk11.cyan(`\u21BB Task was terminal \u2014 reopened to working`));
22367
+ console.log(chalk11.green(`\u2714 Sent to ${project}:${name}`));
22069
22368
  } catch (e) {
22070
- console.error(chalk10.red(e.message));
22369
+ console.error(chalk11.red(e.message));
22071
22370
  process.exit(1);
22072
22371
  }
22073
22372
  });
@@ -22077,12 +22376,12 @@ crewCommand.command("answer").description(
22077
22376
  try {
22078
22377
  const { selected, closed } = await runCrewAnswer2(project, name, option, opts);
22079
22378
  if (closed) {
22080
- console.log(chalk10.green(`\u2714 Answered ${project}:${name} with ${selected.index}. "${selected.label}" \u2014 prompt closed`));
22379
+ console.log(chalk11.green(`\u2714 Answered ${project}:${name} with ${selected.index}. "${selected.label}" \u2014 prompt closed`));
22081
22380
  } else {
22082
- console.log(chalk10.yellow(`\u26A0 Sent ${selected.index}. "${selected.label}" to ${project}:${name}, but the prompt still appears open \u2014 read it again with 'squadrant crew read ${project} ${name}'`));
22381
+ console.log(chalk11.yellow(`\u26A0 Sent ${selected.index}. "${selected.label}" to ${project}:${name}, but the prompt still appears open \u2014 read it again with 'squadrant crew read ${project} ${name}'`));
22083
22382
  }
22084
22383
  } catch (err) {
22085
- console.error(chalk10.red(err.message));
22384
+ console.error(chalk11.red(err.message));
22086
22385
  process.exit(1);
22087
22386
  }
22088
22387
  });
@@ -22092,16 +22391,16 @@ crewCommand.command("read").description("Read the current screen of a crew sessi
22092
22391
  const out = opts.full ? screen : tailLines(screen, Number(opts.lines ?? 40));
22093
22392
  console.log(out);
22094
22393
  } catch (err) {
22095
- console.error(chalk10.red(err.message));
22394
+ console.error(chalk11.red(err.message));
22096
22395
  process.exit(1);
22097
22396
  }
22098
22397
  });
22099
22398
  crewCommand.command("close").description("Shutdown a crew session (closes its tab)").argument("<project>", "Project name").argument("<name>", "Crew name").option("--force", "override an operator takeover (only when the operator told you to)", false).action(async (project, name, opts) => {
22100
22399
  try {
22101
22400
  await runCrewClose2(project, name, opts);
22102
- console.log(chalk10.green(`\u2714 Closed ${project}:${name}`));
22401
+ console.log(chalk11.green(`\u2714 Closed ${project}:${name}`));
22103
22402
  } catch (err) {
22104
- console.error(chalk10.red(err.message));
22403
+ console.error(chalk11.red(err.message));
22105
22404
  process.exit(1);
22106
22405
  }
22107
22406
  });
@@ -22110,7 +22409,7 @@ crewCommand.command("close").description("Shutdown a crew session (closes its ta
22110
22409
  init_dist();
22111
22410
  init_dist4();
22112
22411
  import { Command as Command11 } from "commander";
22113
- import chalk11 from "chalk";
22412
+ import chalk12 from "chalk";
22114
22413
  import { execFileSync as execFileSync10 } from "child_process";
22115
22414
  import readline2 from "readline";
22116
22415
  function resolveDiffTarget(tasks, crew, projectPath) {
@@ -22227,7 +22526,7 @@ async function openCrewDiff(project, proj, crew, opts, runtime, workspaceId) {
22227
22526
  const label = sources.length > 1 ? "staged or unstaged" : sources[0];
22228
22527
  console.log(`No ${label} changes on ${branchLabel}.`);
22229
22528
  } else {
22230
- console.log(chalk11.dim(`Opened ${opened} working-tree diff(s) (${sources.join(", ")}) for ${branchLabel}.`));
22529
+ console.log(chalk12.dim(`Opened ${opened} working-tree diff(s) (${sources.join(", ")}) for ${branchLabel}.`));
22231
22530
  }
22232
22531
  return;
22233
22532
  }
@@ -22250,7 +22549,7 @@ async function openCrewDiff(project, proj, crew, opts, runtime, workspaceId) {
22250
22549
  lastTurn: opts.lastTurn,
22251
22550
  source: "branch"
22252
22551
  });
22253
- console.log(chalk11.dim(`Opened ${branchLabel} vs ${base} in cmux diff.`));
22552
+ console.log(chalk12.dim(`Opened ${branchLabel} vs ${base} in cmux diff.`));
22254
22553
  }
22255
22554
  async function runDiff(project, crewArg, opts) {
22256
22555
  const config = loadConfig();
@@ -22271,7 +22570,7 @@ async function runDiff(project, crewArg, opts) {
22271
22570
  return;
22272
22571
  }
22273
22572
  await runtime.showPatch({ workspaceId, patch, title, layout: opts.layout, focus: opts.focus });
22274
- console.log(chalk11.dim(`Opened ${title} in cmux diff.`));
22573
+ console.log(chalk12.dim(`Opened ${title} in cmux diff.`));
22275
22574
  return;
22276
22575
  }
22277
22576
  let crew;
@@ -22307,10 +22606,10 @@ init_dist4();
22307
22606
  init_dist();
22308
22607
  init_dist2();
22309
22608
  import { Command as Command12 } from "commander";
22310
- import fs28 from "fs";
22609
+ import fs29 from "fs";
22311
22610
  import path32 from "path";
22312
22611
  import os17 from "os";
22313
- import chalk12 from "chalk";
22612
+ import chalk13 from "chalk";
22314
22613
  var TEMPLATES_DIR3 = path32.join(os17.homedir(), ".config", "squadrant", "templates");
22315
22614
  async function runSideSpawn2(input) {
22316
22615
  const config = loadConfig();
@@ -22344,7 +22643,7 @@ async function runSideSpawn2(input) {
22344
22643
  prompt: input.topic,
22345
22644
  workdir: spawnCwd,
22346
22645
  role: "side",
22347
- promptFile: fs28.existsSync(promptFile) ? promptFile : void 0,
22646
+ promptFile: fs29.existsSync(promptFile) ? promptFile : void 0,
22348
22647
  interactive: true,
22349
22648
  permissionMode: config.defaults.permissions?.crew ?? "auto",
22350
22649
  ...sideModel ? { model: sideModel } : {},
@@ -22399,9 +22698,9 @@ sideCommand.command("spawn").description(
22399
22698
  direction: opts.direction,
22400
22699
  agent: opts.agent
22401
22700
  });
22402
- console.log(chalk12.green(`\u2714 Side session '${pane.title}' spawned (${pane.surfaceId})`));
22701
+ console.log(chalk13.green(`\u2714 Side session '${pane.title}' spawned (${pane.surfaceId})`));
22403
22702
  } catch (err) {
22404
- console.error(chalk12.red(err.message));
22703
+ console.error(chalk13.red(err.message));
22405
22704
  process.exit(1);
22406
22705
  }
22407
22706
  }
@@ -22410,14 +22709,14 @@ sideCommand.command("list").description("List live side-sessions for a project")
22410
22709
  try {
22411
22710
  const sessions = await runSideList2(project);
22412
22711
  if (sessions.length === 0) {
22413
- console.log(chalk12.yellow(`No live side-sessions for ${project}.`));
22712
+ console.log(chalk13.yellow(`No live side-sessions for ${project}.`));
22414
22713
  return;
22415
22714
  }
22416
22715
  for (const s of sessions) {
22417
22716
  console.log(` ${s.name} (${s.surfaceId})`);
22418
22717
  }
22419
22718
  } catch (err) {
22420
- console.error(chalk12.red(err.message));
22719
+ console.error(chalk13.red(err.message));
22421
22720
  process.exit(1);
22422
22721
  }
22423
22722
  });
@@ -22430,9 +22729,9 @@ sideCommand.command("send").description("Send a follow-up message to an existing
22430
22729
  label: "message"
22431
22730
  });
22432
22731
  await runSideSend2(project, name, resolvedMessage);
22433
- console.log(chalk12.green(`\u2714 Sent to ${project}:${name}`));
22732
+ console.log(chalk13.green(`\u2714 Sent to ${project}:${name}`));
22434
22733
  } catch (err) {
22435
- console.error(chalk12.red(err.message));
22734
+ console.error(chalk13.red(err.message));
22436
22735
  process.exit(1);
22437
22736
  }
22438
22737
  }
@@ -22440,9 +22739,9 @@ sideCommand.command("send").description("Send a follow-up message to an existing
22440
22739
  sideCommand.command("close").description("Close a side-session (closes its tab)").argument("<project>", "Project name").argument("<name>", "Session name").action(async (project, name) => {
22441
22740
  try {
22442
22741
  await runSideClose2(project, name);
22443
- console.log(chalk12.green(`\u2714 Closed ${project}:${name}`));
22742
+ console.log(chalk13.green(`\u2714 Closed ${project}:${name}`));
22444
22743
  } catch (err) {
22445
- console.error(chalk12.red(err.message));
22744
+ console.error(chalk13.red(err.message));
22446
22745
  process.exit(1);
22447
22746
  }
22448
22747
  });
@@ -22452,7 +22751,7 @@ init_dist();
22452
22751
  init_dist4();
22453
22752
  import { Command as Command13 } from "commander";
22454
22753
  import { execSync as execSync10 } from "child_process";
22455
- import chalk14 from "chalk";
22754
+ import chalk15 from "chalk";
22456
22755
 
22457
22756
  // packages/web/dist/read-status.js
22458
22757
  function deriveState(tasks) {
@@ -22529,14 +22828,14 @@ async function readAllStatuses(deps) {
22529
22828
  }
22530
22829
 
22531
22830
  // packages/web/dist/render.js
22532
- import chalk13 from "chalk";
22831
+ import chalk14 from "chalk";
22533
22832
  var ICON = {
22534
- idle: chalk13.green,
22535
- busy: chalk13.cyan,
22536
- blocked: chalk13.yellow,
22537
- errored: chalk13.red,
22538
- offline: chalk13.dim,
22539
- unknown: chalk13.gray
22833
+ idle: chalk14.green,
22834
+ busy: chalk14.cyan,
22835
+ blocked: chalk14.yellow,
22836
+ errored: chalk14.red,
22837
+ offline: chalk14.dim,
22838
+ unknown: chalk14.gray
22540
22839
  };
22541
22840
  var ICON_CHAR = {
22542
22841
  idle: "\u25CF",
@@ -22579,10 +22878,10 @@ function renderDashboard(rows, opts) {
22579
22878
  const width = opts.width ?? 100;
22580
22879
  const lines = [];
22581
22880
  lines.push("");
22582
- lines.push(" " + chalk13.bold("\u{1F4CA} Squadrant Dashboard") + " " + chalk13.dim(opts.now));
22881
+ lines.push(" " + chalk14.bold("\u{1F4CA} Squadrant Dashboard") + " " + chalk14.dim(opts.now));
22583
22882
  lines.push("");
22584
22883
  if (rows.length === 0) {
22585
- lines.push(" " + chalk13.yellow("No projects registered. Add one with: squadrant projects add <name> <path>"));
22884
+ lines.push(" " + chalk14.yellow("No projects registered. Add one with: squadrant projects add <name> <path>"));
22586
22885
  lines.push("");
22587
22886
  return lines.join("\n");
22588
22887
  }
@@ -22593,21 +22892,21 @@ function renderDashboard(rows, opts) {
22593
22892
  const excerptW = Math.max(20, width - FIXED);
22594
22893
  for (const r of rows) {
22595
22894
  const icon = ICON[r.state](ICON_CHAR[r.state]);
22596
- const name = chalk13.cyan(pad(r.project, NAME_W));
22895
+ const name = chalk14.cyan(pad(r.project, NAME_W));
22597
22896
  const state = ICON[r.state](pad(r.state, STATE_W));
22598
22897
  const age = pad(formatAge(r.lastChecked, opts.now), AGE_W);
22599
- const excerpt = chalk13.dim(truncate(firstLine(r.excerpt), excerptW));
22898
+ const excerpt = chalk14.dim(truncate(firstLine(r.excerpt), excerptW));
22600
22899
  lines.push(` ${icon} ${name} ${state} ${age} \u2502 ${excerpt}`);
22601
22900
  }
22602
22901
  lines.push("");
22603
- lines.push(chalk13.dim(" Refreshes every 10s \xB7 Ctrl+C to exit"));
22902
+ lines.push(chalk14.dim(" Refreshes every 10s \xB7 Ctrl+C to exit"));
22604
22903
  lines.push("");
22605
22904
  return lines.join("\n");
22606
22905
  }
22607
22906
 
22608
22907
  // packages/web/dist/sync-hub.js
22609
22908
  init_dist();
22610
- import fs29 from "fs";
22909
+ import fs30 from "fs";
22611
22910
  import path33 from "path";
22612
22911
  function buildMirrorMarkdown(s) {
22613
22912
  const fenced = "```";
@@ -22634,8 +22933,8 @@ function buildMirrorMarkdown(s) {
22634
22933
  function syncHub(deps) {
22635
22934
  if (!deps.config.hubVault)
22636
22935
  return [];
22637
- const writeFile6 = deps.writeFile ?? ((p, c) => fs29.writeFileSync(p, c));
22638
- const mkdir6 = deps.mkdir ?? ((p) => fs29.mkdirSync(p, { recursive: true }));
22936
+ const writeFile6 = deps.writeFile ?? ((p, c) => fs30.writeFileSync(p, c));
22937
+ const mkdir6 = deps.mkdir ?? ((p) => fs30.mkdirSync(p, { recursive: true }));
22639
22938
  const projectsDir = path33.join(resolveHome(deps.config.hubVault), "projects");
22640
22939
  mkdir6(projectsDir);
22641
22940
  const out = [];
@@ -22654,8 +22953,8 @@ function syncHub(deps) {
22654
22953
 
22655
22954
  // packages/web/dist/web-server.js
22656
22955
  init_dist2();
22657
- import { createServer as createServer5 } from "http";
22658
- import { dirname as dirname7, join as join29 } from "path";
22956
+ import { createServer as createServer6 } from "http";
22957
+ import { dirname as dirname7, join as join30 } from "path";
22659
22958
 
22660
22959
  // packages/web/dist/snapshot-merge.js
22661
22960
  function mergeSnapshot(daemon, external, now) {
@@ -22665,7 +22964,7 @@ function mergeSnapshot(daemon, external, now) {
22665
22964
  // packages/web/dist/probes.js
22666
22965
  init_dist();
22667
22966
  init_dist();
22668
- import { join as join28 } from "path";
22967
+ import { join as join29 } from "path";
22669
22968
  import { homedir as homedir16 } from "os";
22670
22969
  import { existsSync as existsSync13, readFileSync as readFileSync20 } from "fs";
22671
22970
  import { execFile as execFile4 } from "child_process";
@@ -22703,7 +23002,7 @@ function vaultProbe(run, dir) {
22703
23002
  return { state: "unknown", detail: "no vault configured" };
22704
23003
  if (!run.pathExists(dir))
22705
23004
  return { state: "gone", detail: "vault directory missing" };
22706
- if (!run.pathExists(join28(dir, ".obsidian")))
23005
+ if (!run.pathExists(join29(dir, ".obsidian")))
22707
23006
  return { state: "gone", detail: "no .obsidian/ (not a vault)" };
22708
23007
  return { state: "alive" };
22709
23008
  } catch {
@@ -22771,10 +23070,10 @@ async function runExternalProbes(run, timeoutMs = DEFAULT_TIMEOUT_MS2) {
22771
23070
  const sessions = probeSessions(run);
22772
23071
  return { cmux: cmux2, agentClis, vaults, config: { parseable, projectPaths, sessions } };
22773
23072
  }
22774
- var SESSIONS_PATH = join28(homedir16(), ".config", "squadrant", "sessions.json");
23073
+ var SESSIONS_PATH = join29(homedir16(), ".config", "squadrant", "sessions.json");
22775
23074
  function onPath(cli) {
22776
23075
  const dirs = (process.env.PATH ?? "").split(":").filter(Boolean);
22777
- return dirs.some((d) => existsSync13(join28(d, cli)));
23076
+ return dirs.some((d) => existsSync13(join29(d, cli)));
22778
23077
  }
22779
23078
  function readSessionsHashes() {
22780
23079
  const raw = JSON.parse(readFileSync20(SESSIONS_PATH, "utf-8"));
@@ -23751,7 +24050,7 @@ async function startWebServer(opts) {
23751
24050
  const now = opts.now ?? (() => Date.now());
23752
24051
  const clients = /* @__PURE__ */ new Set();
23753
24052
  const logClients = /* @__PURE__ */ new Set();
23754
- const logPath2 = opts.logPath ?? join29(dirname7(opts.sockPath), "squadrantd.log");
24053
+ const logPath2 = opts.logPath ?? join30(dirname7(opts.sockPath), "squadrantd.log");
23755
24054
  const tailer = new LogTailer(logPath2);
23756
24055
  let latest = null;
23757
24056
  async function tick() {
@@ -23781,7 +24080,7 @@ async function startWebServer(opts) {
23781
24080
  }
23782
24081
  }
23783
24082
  }
23784
- const server = createServer5((req, res) => {
24083
+ const server = createServer6((req, res) => {
23785
24084
  if (req.method !== "GET") {
23786
24085
  res.writeHead(405).end();
23787
24086
  return;
@@ -23912,8 +24211,8 @@ async function runDashboardWeb(input) {
23912
24211
  sockPath: SOCK3,
23913
24212
  runners: defaultProbeRunners()
23914
24213
  });
23915
- console.log(chalk14.green(`\u2714 Squadrant system dashboard \u2192 http://127.0.0.1:${handle.port}`));
23916
- console.log(chalk14.dim(` polling the daemon every ${input.interval}s \xB7 localhost only \xB7 read-only \xB7 Ctrl-C to stop`));
24214
+ console.log(chalk15.green(`\u2714 Squadrant system dashboard \u2192 http://127.0.0.1:${handle.port}`));
24215
+ console.log(chalk15.dim(` polling the daemon every ${input.interval}s \xB7 localhost only \xB7 read-only \xB7 Ctrl-C to stop`));
23917
24216
  }
23918
24217
  var dashboardCommand = new Command13("dashboard").description("Live status grid of all projects (derived from daemon task state)").option("--once", "Print one snapshot and exit (used by --pane's refresh loop)").option("--pane", "Open a refreshing sidebar pane in the current cmux workspace").option("--web", "Serve the live system-health web dashboard on 127.0.0.1 (HTTP + SSE)").option("--port <port>", "Port for --web (default 7878)", (v2) => parseInt(v2, 10), 7878).option("--direction <dir>", "Pane split direction (right|left|up|down)", "right").option("--interval <seconds>", "Daemon poll interval for --web (default 5); refresh interval for --pane (default 10)", (v2) => parseInt(v2, 10)).action(async (opts) => {
23919
24218
  try {
@@ -23923,12 +24222,12 @@ var dashboardCommand = new Command13("dashboard").description("Live status grid
23923
24222
  }
23924
24223
  if (opts.pane) {
23925
24224
  const pane = await runDashboardPane({ direction: opts.direction, interval: opts.interval ?? 10 });
23926
- console.log(chalk14.green(`\u2714 Dashboard pane opened in ${pane.workspaceId} ${pane.surfaceId}`));
24225
+ console.log(chalk15.green(`\u2714 Dashboard pane opened in ${pane.workspaceId} ${pane.surfaceId}`));
23927
24226
  return;
23928
24227
  }
23929
24228
  await runDashboardOnce();
23930
24229
  } catch (err) {
23931
- console.error(chalk14.red(err.message));
24230
+ console.error(chalk15.red(err.message));
23932
24231
  process.exit(1);
23933
24232
  }
23934
24233
  });
@@ -23939,12 +24238,12 @@ dashboardCommand.command("sync-hub").description("Mirror each spoke status.md in
23939
24238
  return;
23940
24239
  }
23941
24240
  if (results.length === 0) {
23942
- console.log(chalk14.dim("\n No mirrors written (no projects with usable status.md, or hubVault unset).\n"));
24241
+ console.log(chalk15.dim("\n No mirrors written (no projects with usable status.md, or hubVault unset).\n"));
23943
24242
  return;
23944
24243
  }
23945
- console.log(chalk14.bold("\n \u{1F4CA} Hub mirror sync\n"));
24244
+ console.log(chalk15.bold("\n \u{1F4CA} Hub mirror sync\n"));
23946
24245
  for (const r of results) {
23947
- console.log(` ${chalk14.green("\u2714")} ${chalk14.cyan(r.project.padEnd(16))} \u2192 ${chalk14.dim(r.hubPath)}`);
24246
+ console.log(` ${chalk15.green("\u2714")} ${chalk15.cyan(r.project.padEnd(16))} \u2192 ${chalk15.dim(r.hubPath)}`);
23948
24247
  }
23949
24248
  console.log("");
23950
24249
  });
@@ -23956,10 +24255,10 @@ init_dist4();
23956
24255
  init_dist2();
23957
24256
  import { Command as Command14 } from "commander";
23958
24257
  import { execSync as execSync11, execFileSync as execFileSync11 } from "child_process";
23959
- import fs30 from "fs";
24258
+ import fs31 from "fs";
23960
24259
  import path34 from "path";
23961
24260
  import os18 from "os";
23962
- import chalk15 from "chalk";
24261
+ import chalk16 from "chalk";
23963
24262
 
23964
24263
  // packages/cli/src/commands/launch-interactive.ts
23965
24264
  import checkbox, { Separator } from "@inquirer/checkbox";
@@ -24086,20 +24385,20 @@ function resolveAnthropicRefusal(role, workspaceName, agentName, model, readOpen
24086
24385
  }
24087
24386
  function ensureCmuxReady(headless) {
24088
24387
  if (headless || isInsideCmux()) return;
24089
- console.log(chalk15.yellow("\n Not running inside cmux. Opening cmux app...\n"));
24388
+ console.log(chalk16.yellow("\n Not running inside cmux. Opening cmux app...\n"));
24090
24389
  execSync11(`open "${CMUX_APP}"`, { stdio: "inherit" });
24091
- console.log(chalk15.bold(" Run `squadrant launch` from inside a cmux workspace.\n"));
24390
+ console.log(chalk16.bold(" Run `squadrant launch` from inside a cmux workspace.\n"));
24092
24391
  process.exit(0);
24093
24392
  }
24094
24393
  var launchCommand = new Command14("launch").description(
24095
24394
  "Launch a project captain (with project arg) or all captains (--all). Use `squadrant command` for one-shot Command tasks."
24096
24395
  ).argument("[project]", "Project name to launch captain for").option("--fresh", "Start a new session instead of resuming the last one").option("--keep", "Resume the latest session even on a new day / after a template change").option("--all", "Launch all captain workspaces").option("--headless", "Skip the interactive cmux-app requirement (used by the daemon to boot captains without a terminal)").option("--agent <name>", "Override captain agent for this launch (claude|codex|gemini|opencode); takes precedence over defaults.roles.captain.agent").option("--model <name>", "Override captain model for this launch; takes precedence over defaults.roles.captain.model").option("--thinking <level>", `Override captain thinking level for this launch (${THINKING_LEVELS.join("|")}) \u2192 claude --effort; takes precedence over defaults.roles.captain.thinking`).option("--backend <mode>", "Override captain backend for this launch (native|direct|proxy); takes precedence over defaults.roles.captain.backend").action(async (project, opts) => {
24097
24396
  if (opts.fresh && opts.keep) {
24098
- console.error(chalk15.red("\n \u2718 --fresh and --keep are mutually exclusive\n"));
24397
+ console.error(chalk16.red("\n \u2718 --fresh and --keep are mutually exclusive\n"));
24099
24398
  process.exit(1);
24100
24399
  }
24101
24400
  if (opts.backend !== void 0 && !isBackendMode(opts.backend)) {
24102
- console.error(chalk15.red(`
24401
+ console.error(chalk16.red(`
24103
24402
  \u2718 Invalid --backend value '${opts.backend}'. Valid values: native, direct, proxy
24104
24403
  `));
24105
24404
  process.exit(1);
@@ -24109,7 +24408,7 @@ var launchCommand = new Command14("launch").description(
24109
24408
  try {
24110
24409
  thinkingOverride = opts.thinking ? parseThinkingLevel(opts.thinking) : void 0;
24111
24410
  } catch (err) {
24112
- console.error(chalk15.red(`
24411
+ console.error(chalk16.red(`
24113
24412
  \u2718 ${err.message}
24114
24413
  `));
24115
24414
  process.exit(1);
@@ -24134,7 +24433,7 @@ var launchCommand = new Command14("launch").description(
24134
24433
  const backend = resolveLaunchBackend({ backendOverride, agentName, roleConfig });
24135
24434
  const refusal = resolveAnthropicRefusal(role, workspaceName, agentName, model);
24136
24435
  if (refusal) {
24137
- console.error(chalk15.red(`
24436
+ console.error(chalk16.red(`
24138
24437
  \u2718 ${refusal}
24139
24438
  `));
24140
24439
  hadFailure = true;
@@ -24151,7 +24450,7 @@ var launchCommand = new Command14("launch").description(
24151
24450
  const stateRoot = path34.join(os18.homedir(), ".config", "squadrant", "state");
24152
24451
  const isOpencodeCaptain = role === "captain" && agentName === "opencode" && !!projectName;
24153
24452
  if (isOpencodeCaptain && !isOpencodeCaptainDir(cwd)) {
24154
- console.error(chalk15.red(`
24453
+ console.error(chalk16.red(`
24155
24454
  \u2718 '${projectName}' is not a git repo with a commit \u2014 an opencode captain needs a stable project identity. Run 'git commit' first.
24156
24455
  `));
24157
24456
  hadFailure = true;
@@ -24182,10 +24481,10 @@ var launchCommand = new Command14("launch").description(
24182
24481
  routerCredentials: (o) => fetchRouterCredentials(o.project, o.backend, { call: squadrantdCall }),
24183
24482
  writeRouterSettings
24184
24483
  },
24185
- warn: (m) => console.error(chalk15.yellow(` \u26A0 ${m}`))
24484
+ warn: (m) => console.error(chalk16.yellow(` \u26A0 ${m}`))
24186
24485
  });
24187
24486
  } catch (err) {
24188
- console.error(chalk15.red(` \u2718 ${err.message}`));
24487
+ console.error(chalk16.red(` \u2718 ${err.message}`));
24189
24488
  hadFailure = true;
24190
24489
  return;
24191
24490
  }
@@ -24225,7 +24524,7 @@ var launchCommand = new Command14("launch").description(
24225
24524
  route?.settingsPath
24226
24525
  );
24227
24526
  if (gateDecision?.warn) {
24228
- console.error(chalk15.yellow(` \u26A0 gate: ${gateDecision.reason} \u2014 launching opencode captain directly (P6-C safety fallback)`));
24527
+ console.error(chalk16.yellow(` \u26A0 gate: ${gateDecision.reason} \u2014 launching opencode captain directly (P6-C safety fallback)`));
24229
24528
  }
24230
24529
  const effectiveCmd = gateDecision?.wrap && captainBoot?.port ? buildOpencodeGateRunCommand({ port: captainBoot.port, sessionId: captainBoot.sessionId }) : baseCmd;
24231
24530
  const gatePrefix = route && Object.keys(route.env).length > 0 ? `${renderEnvAssignments(route.env)} ` : "";
@@ -24245,10 +24544,10 @@ var launchCommand = new Command14("launch").description(
24245
24544
  return null;
24246
24545
  }
24247
24546
  },
24248
- onFreshReason: (reason) => console.log(chalk15.cyan(` \u21BB ${reason}`)),
24249
- onStoppingStale: (name) => console.log(chalk15.yellow(` Closing stale workspace '${name}' for fresh start`)),
24547
+ onFreshReason: (reason) => console.log(chalk16.cyan(` \u21BB ${reason}`)),
24548
+ onStoppingStale: (name) => console.log(chalk16.yellow(` Closing stale workspace '${name}' for fresh start`)),
24250
24549
  onAlreadyExists: (name) => {
24251
- console.log(chalk15.yellow(` Workspace '${name}' already exists \u2014 switching to it`));
24550
+ console.log(chalk16.yellow(` Workspace '${name}' already exists \u2014 switching to it`));
24252
24551
  if (!projectName || !isOpencodeCaptain) return;
24253
24552
  const live = discoverLiveOpencodeServer({
24254
24553
  directory: realpathOrSelf(cwd),
@@ -24266,7 +24565,7 @@ var launchCommand = new Command14("launch").description(
24266
24565
  });
24267
24566
  },
24268
24567
  onCreated: (name) => {
24269
- console.log(chalk15.green(` \u2714 Workspace '${name}' created`));
24568
+ console.log(chalk16.green(` \u2714 Workspace '${name}' created`));
24270
24569
  if (!projectName) return;
24271
24570
  if (isOpencodeCaptain && captainPort) {
24272
24571
  writeCaptainAddress(stateRoot, projectName, {
@@ -24282,7 +24581,7 @@ var launchCommand = new Command14("launch").description(
24282
24581
  directory: realpathOrSelf(cwd),
24283
24582
  launchedAt,
24284
24583
  sessionId: opencodeResumeSessionId,
24285
- log: (m) => console.error(chalk15.yellow(` \u26A0 ${m}`))
24584
+ log: (m) => console.error(chalk16.yellow(` \u26A0 ${m}`))
24286
24585
  }).catch(() => {
24287
24586
  });
24288
24587
  } else if (role === "captain") {
@@ -24295,23 +24594,23 @@ var launchCommand = new Command14("launch").description(
24295
24594
  }
24296
24595
  });
24297
24596
  } catch (err) {
24298
- console.error(chalk15.red(` \u2718 Failed: ${err.message}`));
24597
+ console.error(chalk16.red(` \u2718 Failed: ${err.message}`));
24299
24598
  hadFailure = true;
24300
24599
  }
24301
24600
  }
24302
24601
  if (opts.all) {
24303
24602
  const hubPath = resolveHome(config.hubVault);
24304
- fs30.mkdirSync(hubPath, { recursive: true });
24305
- console.log(chalk15.bold("\nLaunching all captain workspaces\n"));
24603
+ fs31.mkdirSync(hubPath, { recursive: true });
24604
+ console.log(chalk16.bold("\nLaunching all captain workspaces\n"));
24306
24605
  for (const [name, proj] of Object.entries(config.projects)) {
24307
24606
  const projPath = resolveHome(proj.path);
24308
24607
  const spokePath = resolveHome(proj.spokeVault);
24309
- if (!fs30.existsSync(spokePath)) {
24608
+ if (!fs31.existsSync(spokePath)) {
24310
24609
  const spokeDriver = new WorkspaceRegistry({ obsidian: createObsidianDriver }).forProject(name, config);
24311
24610
  await ensureSpokeLayout(spokeDriver);
24312
- console.log(chalk15.cyan(` \u2714 Created spoke vault at ${spokePath}`));
24611
+ console.log(chalk16.cyan(` \u2714 Created spoke vault at ${spokePath}`));
24313
24612
  }
24314
- console.log(chalk15.bold(`
24613
+ console.log(chalk16.bold(`
24315
24614
  Captain: ${proj.captainName} (${name})`));
24316
24615
  await launchOne(proj.captainName, "captain", projPath, config.defaults.permissions?.captain || "auto", false, true, name);
24317
24616
  }
@@ -24319,7 +24618,7 @@ var launchCommand = new Command14("launch").description(
24319
24618
  } else if (!project) {
24320
24619
  if (!process.stdin.isTTY || !process.stdout.isTTY) {
24321
24620
  console.error(
24322
- chalk15.red(
24621
+ chalk16.red(
24323
24622
  "\n \u2718 Specify a project name, or pass --all to launch every captain.\n For one-shot Command tasks, use `squadrant command --task <briefing|learnings-review|wiki-aggregate>`.\n"
24324
24623
  )
24325
24624
  );
@@ -24334,22 +24633,22 @@ var launchCommand = new Command14("launch").description(
24334
24633
  }));
24335
24634
  const selected = await selectCaptainsInteractive(entries);
24336
24635
  if (selected.length === 0) {
24337
- console.log(chalk15.yellow("\n No captains selected.\n"));
24636
+ console.log(chalk16.yellow("\n No captains selected.\n"));
24338
24637
  return;
24339
24638
  }
24340
- console.log(chalk15.bold(`
24639
+ console.log(chalk16.bold(`
24341
24640
  Launching ${selected.length} captain workspace(s) in parallel
24342
24641
  `));
24343
24642
  await Promise.all(selected.map(async (name) => {
24344
24643
  const proj = config.projects[name];
24345
24644
  const projPath = resolveHome(proj.path);
24346
24645
  const spokePath = resolveHome(proj.spokeVault);
24347
- if (!fs30.existsSync(spokePath)) {
24646
+ if (!fs31.existsSync(spokePath)) {
24348
24647
  const spokeDriver = new WorkspaceRegistry({ obsidian: createObsidianDriver }).forProject(name, config);
24349
24648
  await ensureSpokeLayout(spokeDriver);
24350
- console.log(chalk15.cyan(` \u2714 Created spoke vault at ${spokePath}`));
24649
+ console.log(chalk16.cyan(` \u2714 Created spoke vault at ${spokePath}`));
24351
24650
  }
24352
- console.log(chalk15.bold(`
24651
+ console.log(chalk16.bold(`
24353
24652
  Captain: ${proj.captainName} (${name})`));
24354
24653
  await launchOne(proj.captainName, "captain", projPath, config.defaults.permissions?.captain || "auto", false, true, name);
24355
24654
  }));
@@ -24357,7 +24656,7 @@ Launching ${selected.length} captain workspace(s) in parallel
24357
24656
  } else {
24358
24657
  if (!config.projects[project]) {
24359
24658
  console.error(
24360
- chalk15.red(
24659
+ chalk16.red(
24361
24660
  `
24362
24661
  \u2718 Project '${project}' not found. Run 'squadrant projects list' to see registered projects.
24363
24662
  `
@@ -24368,13 +24667,13 @@ Launching ${selected.length} captain workspace(s) in parallel
24368
24667
  const proj = config.projects[project];
24369
24668
  const projPath = resolveHome(proj.path);
24370
24669
  const spokePath = resolveHome(proj.spokeVault);
24371
- if (!fs30.existsSync(spokePath)) {
24670
+ if (!fs31.existsSync(spokePath)) {
24372
24671
  const spokeDriver = new WorkspaceRegistry({ obsidian: createObsidianDriver }).forProject(project, config);
24373
24672
  await ensureSpokeLayout(spokeDriver);
24374
- console.log(chalk15.cyan(` \u2714 Created spoke vault at ${spokePath}`));
24673
+ console.log(chalk16.cyan(` \u2714 Created spoke vault at ${spokePath}`));
24375
24674
  }
24376
24675
  console.log(
24377
- chalk15.bold(
24676
+ chalk16.bold(
24378
24677
  `
24379
24678
  Launching captain workspace for '${project}' (${proj.captainName})
24380
24679
  `
@@ -24389,7 +24688,7 @@ Launching captain workspace for '${project}' (${proj.captainName})
24389
24688
  init_dist();
24390
24689
  init_dist4();
24391
24690
  import { Command as Command15 } from "commander";
24392
- import chalk16 from "chalk";
24691
+ import chalk17 from "chalk";
24393
24692
  init_dist();
24394
24693
  function nameVariants(name) {
24395
24694
  const stripped = name.replace(/^⚓\s+/, "").trim();
@@ -24402,17 +24701,17 @@ async function closeMatching(runtime, variants, label) {
24402
24701
  const failed = [];
24403
24702
  if (matches.length === 0) {
24404
24703
  console.log(
24405
- chalk16.yellow(` \u26A0 Workspace '${label}' not found \u2014 already closed?`)
24704
+ chalk17.yellow(` \u26A0 Workspace '${label}' not found \u2014 already closed?`)
24406
24705
  );
24407
24706
  return { closed, failed };
24408
24707
  }
24409
24708
  for (const ws of matches) {
24410
24709
  try {
24411
24710
  await runtime.stop(ws.id);
24412
- console.log(chalk16.green(` \u2714 Closed: ${ws.name}`));
24711
+ console.log(chalk17.green(` \u2714 Closed: ${ws.name}`));
24413
24712
  closed.push(ws.name);
24414
24713
  } catch {
24415
- console.log(chalk16.red(` \u2718 Failed to close: ${ws.name}`));
24714
+ console.log(chalk17.red(` \u2718 Failed to close: ${ws.name}`));
24416
24715
  failed.push(ws.name);
24417
24716
  }
24418
24717
  }
@@ -24434,11 +24733,11 @@ var shutdownCommand = new Command15("shutdown").description(
24434
24733
  const allVariants = /* @__PURE__ */ new Set([...captainVariants, ...commandVariants]);
24435
24734
  const squadrantWorkspaces = workspaces.filter((w) => allVariants.has(w.name));
24436
24735
  if (squadrantWorkspaces.length === 0) {
24437
- console.log(chalk16.yellow("\nNo squadrant workspaces found to close.\n"));
24736
+ console.log(chalk17.yellow("\nNo squadrant workspaces found to close.\n"));
24438
24737
  return;
24439
24738
  }
24440
24739
  console.log(
24441
- chalk16.bold(
24740
+ chalk17.bold(
24442
24741
  `
24443
24742
  Shutting down ${squadrantWorkspaces.length} workspace(s)...
24444
24743
  `
@@ -24458,9 +24757,9 @@ Shutting down ${squadrantWorkspaces.length} workspace(s)...
24458
24757
  for (const ws of squadrantWorkspaces) {
24459
24758
  try {
24460
24759
  await globalRuntime.stop(ws.id);
24461
- console.log(chalk16.green(` \u2714 Closed: ${ws.name}`));
24760
+ console.log(chalk17.green(` \u2714 Closed: ${ws.name}`));
24462
24761
  } catch {
24463
- console.log(chalk16.red(` \u2718 Failed to close: ${ws.name}`));
24762
+ console.log(chalk17.red(` \u2718 Failed to close: ${ws.name}`));
24464
24763
  }
24465
24764
  }
24466
24765
  console.log("");
@@ -24468,7 +24767,7 @@ Shutting down ${squadrantWorkspaces.length} workspace(s)...
24468
24767
  }
24469
24768
  if (!config.projects[project]) {
24470
24769
  console.error(
24471
- chalk16.red(
24770
+ chalk17.red(
24472
24771
  `
24473
24772
  \u2718 Project '${project}' not found. Run 'squadrant projects list' to see registered projects.
24474
24773
  `
@@ -24479,7 +24778,7 @@ Shutting down ${squadrantWorkspaces.length} workspace(s)...
24479
24778
  const captainName = config.projects[project].captainName;
24480
24779
  const runtime = runtimes.forProject(project, config);
24481
24780
  console.log(
24482
- chalk16.bold(`
24781
+ chalk17.bold(`
24483
24782
  Shutting down captain workspace for '${project}'...
24484
24783
  `)
24485
24784
  );
@@ -24504,24 +24803,24 @@ Shutting down captain workspace for '${project}'...
24504
24803
  // packages/cli/src/commands/feedback.ts
24505
24804
  init_dist();
24506
24805
  import { Command as Command16 } from "commander";
24507
- import fs31 from "fs";
24806
+ import fs32 from "fs";
24508
24807
  import os19 from "os";
24509
24808
  import path35 from "path";
24510
24809
  import { fileURLToPath as fileURLToPath3 } from "url";
24511
24810
  import { execSync as execSync12 } from "child_process";
24512
- import chalk17 from "chalk";
24811
+ import chalk18 from "chalk";
24513
24812
  var REPO_URL = "https://github.com/tu11aa/squadrant";
24514
24813
  function readPkgVersion() {
24515
24814
  try {
24516
24815
  const pkgPath = path35.join(path35.dirname(fileURLToPath3(import.meta.url)), "..", "package.json");
24517
- return JSON.parse(fs31.readFileSync(pkgPath, "utf-8")).version ?? "unknown";
24816
+ return JSON.parse(fs32.readFileSync(pkgPath, "utf-8")).version ?? "unknown";
24518
24817
  } catch {
24519
24818
  return "unknown";
24520
24819
  }
24521
24820
  }
24522
24821
  function readMetrics(metricsPath) {
24523
24822
  try {
24524
- return JSON.parse(fs31.readFileSync(metricsPath, "utf-8"));
24823
+ return JSON.parse(fs32.readFileSync(metricsPath, "utf-8"));
24525
24824
  } catch {
24526
24825
  return {};
24527
24826
  }
@@ -24563,15 +24862,15 @@ var feedbackCommand = new Command16("feedback").description("Open a pre-filled G
24563
24862
  const metrics = readMetrics(metricsPath);
24564
24863
  const version = readStamp(config) ?? readPkgVersion();
24565
24864
  const issueUrl = buildIssueUrl(metrics, version);
24566
- console.log(chalk17.bold("\nOpening feedback issue in browser...\n"));
24567
- console.log(chalk17.dim(` URL: ${issueUrl.substring(0, 80)}...
24865
+ console.log(chalk18.bold("\nOpening feedback issue in browser...\n"));
24866
+ console.log(chalk18.dim(` URL: ${issueUrl.substring(0, 80)}...
24568
24867
  `));
24569
24868
  try {
24570
24869
  execSync12(`open "${issueUrl}"`, { stdio: "ignore" });
24571
- console.log(chalk17.green(" \u2714 Browser opened\n"));
24870
+ console.log(chalk18.green(" \u2714 Browser opened\n"));
24572
24871
  } catch {
24573
- console.log(chalk17.yellow(" \u26A0 Could not open browser automatically."));
24574
- console.log(` Open manually: ${chalk17.cyan(issueUrl)}
24872
+ console.log(chalk18.yellow(" \u26A0 Could not open browser automatically."));
24873
+ console.log(` Open manually: ${chalk18.cyan(issueUrl)}
24575
24874
  `);
24576
24875
  }
24577
24876
  });
@@ -24581,7 +24880,7 @@ init_dist();
24581
24880
  init_dist();
24582
24881
  init_dist4();
24583
24882
  import { Command as Command17 } from "commander";
24584
- import chalk18 from "chalk";
24883
+ import chalk19 from "chalk";
24585
24884
  function getDateStr(yesterday) {
24586
24885
  return iso(daysAgo(yesterday ? 1 : 0));
24587
24886
  }
@@ -24600,7 +24899,7 @@ function formatStandup(standups, dateStr, raw) {
24600
24899
  const lines = [];
24601
24900
  const header = `Standup \u2014 ${dateStr}`;
24602
24901
  if (!raw) {
24603
- lines.push(chalk18.bold(`
24902
+ lines.push(chalk19.bold(`
24604
24903
  ${header}
24605
24904
  `));
24606
24905
  } else {
@@ -24610,12 +24909,12 @@ ${header}
24610
24909
  let hasBlockers = false;
24611
24910
  for (const s of standups) {
24612
24911
  if (!raw) {
24613
- lines.push(chalk18.cyan.bold(`## ${s.name}`));
24912
+ lines.push(chalk19.cyan.bold(`## ${s.name}`));
24614
24913
  } else {
24615
24914
  lines.push(`## ${s.name}`);
24616
24915
  }
24617
24916
  if (s.gitCommits.length > 0) {
24618
- lines.push(!raw ? chalk18.green("Done:") : "**Done:**");
24917
+ lines.push(!raw ? chalk19.green("Done:") : "**Done:**");
24619
24918
  for (const commit of s.gitCommits) {
24620
24919
  lines.push(` - ${commit}`);
24621
24920
  }
@@ -24627,7 +24926,7 @@ ${header}
24627
24926
  if (match) {
24628
24927
  const items = match[1].trim().split("\n").filter((l) => l.trim().startsWith("-"));
24629
24928
  if (items.length > 0 && section === "Tomorrow") {
24630
- lines.push(!raw ? chalk18.blue("Next:") : "**Next:**");
24929
+ lines.push(!raw ? chalk19.blue("Next:") : "**Next:**");
24631
24930
  for (const item of items) lines.push(` ${item.trim()}`);
24632
24931
  }
24633
24932
  }
@@ -24635,19 +24934,19 @@ ${header}
24635
24934
  }
24636
24935
  if (s.blockers.length > 0) {
24637
24936
  hasBlockers = true;
24638
- lines.push(!raw ? chalk18.red("Blocked:") : "**Blocked:**");
24937
+ lines.push(!raw ? chalk19.red("Blocked:") : "**Blocked:**");
24639
24938
  for (const b of s.blockers) {
24640
24939
  lines.push(` - ${b}`);
24641
24940
  }
24642
24941
  }
24643
24942
  if (s.gitCommits.length === 0 && !s.dailyLog) {
24644
- lines.push(!raw ? chalk18.dim(" (no activity)") : " (no activity)");
24943
+ lines.push(!raw ? chalk19.dim(" (no activity)") : " (no activity)");
24645
24944
  }
24646
24945
  lines.push("");
24647
24946
  }
24648
24947
  const totalCommits = standups.reduce((sum, s) => sum + s.gitCommits.length, 0);
24649
24948
  if (!raw) {
24650
- lines.push(chalk18.dim(`--- ${totalCommits} commits${hasBlockers ? ", HAS BLOCKERS" : ""} (task tracking: no data source \u2014 #630) ---
24949
+ lines.push(chalk19.dim(`--- ${totalCommits} commits${hasBlockers ? ", HAS BLOCKERS" : ""} (task tracking: no data source \u2014 #630) ---
24651
24950
  `));
24652
24951
  } else {
24653
24952
  lines.push(`---
@@ -24661,7 +24960,7 @@ var standupCommand = new Command17("standup").description("Generate daily standu
24661
24960
  const registry = new WorkspaceRegistry({ obsidian: createObsidianDriver });
24662
24961
  const projects = Object.entries(config.projects);
24663
24962
  if (projects.length === 0) {
24664
- console.log(chalk18.yellow("\nNo projects registered. Use: squadrant projects add <name> <path>\n"));
24963
+ console.log(chalk19.yellow("\nNo projects registered. Use: squadrant projects add <name> <path>\n"));
24665
24964
  return;
24666
24965
  }
24667
24966
  const dateStr = getDateStr(!!opts.yesterday);
@@ -24670,7 +24969,7 @@ var standupCommand = new Command17("standup").description("Generate daily standu
24670
24969
  if (opts.project) {
24671
24970
  const match = projects.find(([name]) => name === opts.project);
24672
24971
  if (!match) {
24673
- console.error(chalk18.red(`Project "${opts.project}" not found.`));
24972
+ console.error(chalk19.red(`Project "${opts.project}" not found.`));
24674
24973
  process.exit(1);
24675
24974
  }
24676
24975
  targets = [match];
@@ -24689,7 +24988,7 @@ init_dist();
24689
24988
  init_dist();
24690
24989
  init_dist4();
24691
24990
  import { Command as Command18 } from "commander";
24692
- import chalk19 from "chalk";
24991
+ import chalk20 from "chalk";
24693
24992
  function dedupe(items) {
24694
24993
  const seen = /* @__PURE__ */ new Set();
24695
24994
  const out = [];
@@ -24745,7 +25044,7 @@ function formatRetro(retros, fromStr, toStr, raw) {
24745
25044
  const lines = [];
24746
25045
  const header = `Retro \u2014 ${fromStr} \u2192 ${toStr}`;
24747
25046
  lines.push(raw ? `# ${header}
24748
- ` : chalk19.bold(`
25047
+ ` : chalk20.bold(`
24749
25048
  ${header}
24750
25049
  `));
24751
25050
  let totalCommits = 0;
@@ -24755,30 +25054,30 @@ ${header}
24755
25054
  totalCommits += r.commits.length;
24756
25055
  totalPRs += r.mergedPRs.length;
24757
25056
  totalShipped += r.shipped.length;
24758
- lines.push(raw ? `## ${r.name}` : chalk19.cyan.bold(`## ${r.name}`));
24759
- renderList(lines, r.shipped, raw, "Shipped", chalk19.green);
25057
+ lines.push(raw ? `## ${r.name}` : chalk20.cyan.bold(`## ${r.name}`));
25058
+ renderList(lines, r.shipped, raw, "Shipped", chalk20.green);
24760
25059
  if (r.mergedPRs.length > 0) {
24761
- lines.push(raw ? `**PRs merged:**` : chalk19.green("PRs merged:"));
25060
+ lines.push(raw ? `**PRs merged:**` : chalk20.green("PRs merged:"));
24762
25061
  for (const pr of r.mergedPRs) lines.push(` - ${pr}`);
24763
25062
  }
24764
- renderList(lines, r.inProgress, raw, "In Progress", chalk19.yellow);
24765
- renderList(lines, r.blocked, raw, "Blocked", chalk19.red);
24766
- renderList(lines, r.decisions, raw, "Key Decisions", chalk19.magenta);
25063
+ renderList(lines, r.inProgress, raw, "In Progress", chalk20.yellow);
25064
+ renderList(lines, r.blocked, raw, "Blocked", chalk20.red);
25065
+ renderList(lines, r.decisions, raw, "Key Decisions", chalk20.magenta);
24767
25066
  const metricBits = [
24768
25067
  `${r.commits.length} commits`,
24769
25068
  `${r.mergedPRs.length} PRs merged`,
24770
25069
  `${r.shipped.length} shipped`
24771
25070
  ];
24772
- lines.push(raw ? `*${metricBits.join(" \xB7 ")}*` : chalk19.dim(` ${metricBits.join(" \xB7 ")}`));
25071
+ lines.push(raw ? `*${metricBits.join(" \xB7 ")}*` : chalk20.dim(` ${metricBits.join(" \xB7 ")}`));
24773
25072
  if (r.shipped.length === 0 && r.commits.length === 0 && r.mergedPRs.length === 0 && r.inProgress.length === 0 && r.blocked.length === 0) {
24774
- lines.push(raw ? "_(no activity in this window)_" : chalk19.dim(" (no activity in this window)"));
25073
+ lines.push(raw ? "_(no activity in this window)_" : chalk20.dim(" (no activity in this window)"));
24775
25074
  }
24776
25075
  lines.push("");
24777
25076
  }
24778
25077
  const summary = `${totalShipped} items shipped \xB7 ${totalCommits} commits \xB7 ${totalPRs} PRs merged`;
24779
25078
  lines.push(raw ? `---
24780
25079
  *${summary}*
24781
- ` : chalk19.dim(`--- ${summary} ---
25080
+ ` : chalk20.dim(`--- ${summary} ---
24782
25081
  `));
24783
25082
  return lines.join("\n");
24784
25083
  }
@@ -24787,7 +25086,7 @@ var retroCommand = new Command18("retro").description("Generate a retro (weekly/
24787
25086
  const registry = new WorkspaceRegistry({ obsidian: createObsidianDriver });
24788
25087
  const projects = Object.entries(config.projects);
24789
25088
  if (projects.length === 0) {
24790
- console.log(chalk19.yellow("\nNo projects registered. Use: squadrant projects add <name> <path>\n"));
25089
+ console.log(chalk20.yellow("\nNo projects registered. Use: squadrant projects add <name> <path>\n"));
24791
25090
  return;
24792
25091
  }
24793
25092
  let windowDays = 7;
@@ -24804,7 +25103,7 @@ var retroCommand = new Command18("retro").description("Generate a retro (weekly/
24804
25103
  if (opts.project) {
24805
25104
  const match = projects.find(([name]) => name === opts.project);
24806
25105
  if (!match) {
24807
- console.error(chalk19.red(`Project "${opts.project}" not found.`));
25106
+ console.error(chalk20.red(`Project "${opts.project}" not found.`));
24808
25107
  process.exit(1);
24809
25108
  }
24810
25109
  targets = [match];
@@ -24824,7 +25123,7 @@ init_runtime2();
24824
25123
  init_dist();
24825
25124
  init_dist4();
24826
25125
  import { Command as Command19 } from "commander";
24827
- import chalk20 from "chalk";
25126
+ import chalk21 from "chalk";
24828
25127
  function buildRegistry2() {
24829
25128
  return new WorkspaceRegistry({
24830
25129
  obsidian: createObsidianDriver
@@ -24864,7 +25163,7 @@ workspaceCommand.command("read").description("Print the contents of a scope-rela
24864
25163
  const content = await driver.read(path46);
24865
25164
  process.stdout.write(content);
24866
25165
  } catch (err) {
24867
- console.error(chalk20.red(err.message));
25166
+ console.error(chalk21.red(err.message));
24868
25167
  process.exit(1);
24869
25168
  }
24870
25169
  });
@@ -24894,7 +25193,7 @@ workspaceCommand.command("write").description("Write content to a scope-relative
24894
25193
  const payload = rawContent === "-" ? await readStdin() : rawContent;
24895
25194
  await driver.write(path46, payload);
24896
25195
  } catch (err) {
24897
- console.error(chalk20.red(err.message));
25196
+ console.error(chalk21.red(err.message));
24898
25197
  process.exit(1);
24899
25198
  }
24900
25199
  });
@@ -24907,7 +25206,7 @@ workspaceCommand.command("list").description("List entries in a scope-relative d
24907
25206
  const entries = await driver.list(path46);
24908
25207
  for (const entry of entries) console.log(entry);
24909
25208
  } catch (err) {
24910
- console.error(chalk20.red(err.message));
25209
+ console.error(chalk21.red(err.message));
24911
25210
  process.exit(1);
24912
25211
  }
24913
25212
  });
@@ -24920,7 +25219,7 @@ workspaceCommand.command("exists").description("Exit 0 if path exists, 1 if not"
24920
25219
  const ok2 = await driver.exists(path46);
24921
25220
  process.exit(ok2 ? 0 : 1);
24922
25221
  } catch (err) {
24923
- console.error(chalk20.red(err.message));
25222
+ console.error(chalk21.red(err.message));
24924
25223
  process.exit(2);
24925
25224
  }
24926
25225
  });
@@ -24932,7 +25231,7 @@ workspaceCommand.command("mkdir").description("Recursively create a scope-relati
24932
25231
  const driver = resolveDriver(registry, config, projectTarget, !!opts.hub);
24933
25232
  await driver.mkdir(path46);
24934
25233
  } catch (err) {
24935
- console.error(chalk20.red(err.message));
25234
+ console.error(chalk21.red(err.message));
24936
25235
  process.exit(1);
24937
25236
  }
24938
25237
  });
@@ -24941,7 +25240,7 @@ workspaceCommand.command("mkdir").description("Recursively create a scope-relati
24941
25240
  init_dist();
24942
25241
  init_dist4();
24943
25242
  import { Command as Command20 } from "commander";
24944
- import chalk21 from "chalk";
25243
+ import chalk22 from "chalk";
24945
25244
  async function readStdin2() {
24946
25245
  const chunks = [];
24947
25246
  for await (const chunk of process.stdin) {
@@ -24957,7 +25256,7 @@ var notifyCommand = new Command20("notify").description("Send a message to the u
24957
25256
  if (!payload) throw new Error("Empty message");
24958
25257
  await registry.get(config).notify(payload);
24959
25258
  } catch (err) {
24960
- console.error(chalk21.red(err.message));
25259
+ console.error(chalk22.red(err.message));
24961
25260
  process.exit(1);
24962
25261
  }
24963
25262
  });
@@ -24968,8 +25267,8 @@ init_dist3();
24968
25267
  init_dist4();
24969
25268
  init_dist();
24970
25269
  import { Command as Command21 } from "commander";
24971
- import chalk22 from "chalk";
24972
- import fs32 from "fs";
25270
+ import chalk23 from "chalk";
25271
+ import fs33 from "fs";
24973
25272
  import path36 from "path";
24974
25273
  import { fileURLToPath as fileURLToPath4 } from "url";
24975
25274
  function parseScope(v2) {
@@ -24981,7 +25280,7 @@ function parseScope(v2) {
24981
25280
  function findPackageRoot3() {
24982
25281
  let dir = path36.dirname(fileURLToPath4(import.meta.url));
24983
25282
  while (dir !== "/" && dir !== "") {
24984
- if (fs32.existsSync(path36.join(dir, "package.json"))) return dir;
25283
+ if (fs33.existsSync(path36.join(dir, "package.json"))) return dir;
24985
25284
  dir = path36.dirname(dir);
24986
25285
  }
24987
25286
  return process.cwd();
@@ -25016,17 +25315,17 @@ async function runEmit(opts) {
25016
25315
  for (const dest of emitter.destinations(scope, projectRoot)) {
25017
25316
  const result = await emitter.emit(source, dest, { dryRun: opts.dryRun });
25018
25317
  if (opts.dryRun) {
25019
- console.log(chalk22.cyan(`[${emitter.name}] ${dest.path}`));
25318
+ console.log(chalk23.cyan(`[${emitter.name}] ${dest.path}`));
25020
25319
  console.log(result.diff ?? "(no diff)");
25021
25320
  } else if (result.written) {
25022
25321
  console.log(
25023
- chalk22.green(
25322
+ chalk23.green(
25024
25323
  `\u2714 ${emitter.name} \u2192 ${dest.path} (${result.bytesWritten} bytes)`
25025
25324
  )
25026
25325
  );
25027
25326
  emittedCount.written++;
25028
25327
  } else {
25029
- console.log(chalk22.gray(`- ${emitter.name} \u2192 ${dest.path} (skipped)`));
25328
+ console.log(chalk23.gray(`- ${emitter.name} \u2192 ${dest.path} (skipped)`));
25030
25329
  emittedCount.skipped++;
25031
25330
  }
25032
25331
  }
@@ -25049,14 +25348,14 @@ async function runEmit(opts) {
25049
25348
  `Unknown project '${projectName}'. Available: ${Object.keys(cfg.projects).join(", ") || "(none)"}`
25050
25349
  );
25051
25350
  }
25052
- console.error(chalk22.yellow(`\u26A0 unknown project: ${projectName}`));
25351
+ console.error(chalk23.yellow(`\u26A0 unknown project: ${projectName}`));
25053
25352
  continue;
25054
25353
  }
25055
25354
  const source = await readProjectLevelSource(
25056
25355
  createObsidianDriver({ root: proj.path })
25057
25356
  );
25058
25357
  if (!source) {
25059
- console.log(chalk22.gray(`- ${projectName}: no AGENTS.md, skipping`));
25358
+ console.log(chalk23.gray(`- ${projectName}: no AGENTS.md, skipping`));
25060
25359
  continue;
25061
25360
  }
25062
25361
  for (const name of targets) {
@@ -25066,7 +25365,7 @@ async function runEmit(opts) {
25066
25365
  }
25067
25366
  if (!opts.dryRun) {
25068
25367
  console.log(
25069
- chalk22.bold(
25368
+ chalk23.bold(
25070
25369
  `
25071
25370
  Projection complete \u2014 ${emittedCount.written} written, ${emittedCount.skipped} skipped.`
25072
25371
  )
@@ -25080,7 +25379,7 @@ projectionCommand.command("emit").description("Emit projections to disk").option
25080
25379
  try {
25081
25380
  await runEmit({ ...opts, dryRun: false });
25082
25381
  } catch (err) {
25083
- console.error(chalk22.red(err.message));
25382
+ console.error(chalk23.red(err.message));
25084
25383
  process.exit(1);
25085
25384
  }
25086
25385
  });
@@ -25088,7 +25387,7 @@ projectionCommand.command("diff").description("Preview changes without writing")
25088
25387
  try {
25089
25388
  await runEmit({ ...opts, dryRun: true });
25090
25389
  } catch (err) {
25091
- console.error(chalk22.red(err.message));
25390
+ console.error(chalk23.red(err.message));
25092
25391
  process.exit(1);
25093
25392
  }
25094
25393
  });
@@ -25098,7 +25397,7 @@ projectionCommand.command("list").description("List registered projection target
25098
25397
  const emitter = registry.get(name);
25099
25398
  const userDests = emitter.destinations("user").map((d) => d.path);
25100
25399
  const projectDests = emitter.destinations("project", "<project>").map((d) => d.path);
25101
- console.log(chalk22.bold(name));
25400
+ console.log(chalk23.bold(name));
25102
25401
  console.log(` user: ${userDests.join(", ") || "(none)"}`);
25103
25402
  console.log(` project: ${projectDests.join(", ") || "(none)"}`);
25104
25403
  }
@@ -25178,12 +25477,12 @@ init_dist();
25178
25477
  init_dist();
25179
25478
  init_dist2();
25180
25479
  import { Command as Command23 } from "commander";
25181
- import fs33 from "fs";
25480
+ import fs34 from "fs";
25182
25481
  import { fileURLToPath as fileURLToPath5 } from "url";
25183
- import { dirname as dirname8, join as join30 } from "path";
25184
- import chalk23 from "chalk";
25482
+ import { dirname as dirname8, join as join31 } from "path";
25483
+ import chalk24 from "chalk";
25185
25484
  function runConfigCheck(opts) {
25186
- const raw = JSON.parse(fs33.readFileSync(opts.configPath, "utf-8"));
25485
+ const raw = JSON.parse(fs34.readFileSync(opts.configPath, "utf-8"));
25187
25486
  const def = getDefaultConfig();
25188
25487
  const items = detectDrift(raw, def);
25189
25488
  let working = raw;
@@ -25236,14 +25535,14 @@ function runConfigSet(key, value, configPath = DEFAULT_CONFIG_PATH) {
25236
25535
  }
25237
25536
  function printRestartOutcome(outcome) {
25238
25537
  if (outcome === "skipped-not-running") {
25239
- console.log(chalk23.dim("(daemon not running \u2014 change applies on next start)"));
25538
+ console.log(chalk24.dim("(daemon not running \u2014 change applies on next start)"));
25240
25539
  } else if (outcome === "skipped-opt-out") {
25241
- console.log(chalk23.dim("(run 'squadrant heal daemon' to apply)"));
25540
+ console.log(chalk24.dim("(run 'squadrant heal daemon' to apply)"));
25242
25541
  }
25243
25542
  }
25244
25543
  function runConfigSetAction(opts) {
25245
25544
  runConfigSet(opts.key, opts.value, opts.configPath);
25246
- console.log(chalk23.green(`\u2714 set ${opts.key} = ${opts.value}`));
25545
+ console.log(chalk24.green(`\u2714 set ${opts.key} = ${opts.value}`));
25247
25546
  if (isDaemonCachedKey(opts.key)) {
25248
25547
  const doRestart = opts.doRestart ?? restartDaemonIfRunning;
25249
25548
  const outcome = doRestart({ reason: `config ${opts.key}`, noRestart: opts.noRestart });
@@ -25251,9 +25550,9 @@ function runConfigSetAction(opts) {
25251
25550
  }
25252
25551
  }
25253
25552
  var SEV_COLOR = {
25254
- info: chalk23.green,
25255
- advisory: chalk23.yellow,
25256
- warn: chalk23.red
25553
+ info: chalk24.green,
25554
+ advisory: chalk24.yellow,
25555
+ warn: chalk24.red
25257
25556
  };
25258
25557
  var KIND_GLYPH = {
25259
25558
  missing: "+",
@@ -25265,14 +25564,14 @@ function printItems(items) {
25265
25564
  for (const i of items) {
25266
25565
  const color = SEV_COLOR[i.severity] ?? ((s) => s);
25267
25566
  const detail = i.note ? ` (${i.note})` : i.suggested !== void 0 ? ` \u2192 ${JSON.stringify(i.suggested)}` : "";
25268
- console.log(" " + color(`${KIND_GLYPH[i.kind]} ${i.kind}: ${i.path}`) + chalk23.dim(detail));
25567
+ console.log(" " + color(`${KIND_GLYPH[i.kind]} ${i.kind}: ${i.path}`) + chalk24.dim(detail));
25269
25568
  }
25270
25569
  }
25271
25570
  var configCommand = new Command23("config").description("Inspect and reconcile squadrant config");
25272
25571
  configCommand.command("check").description("Detect config drift vs the current default schema").option("--fix", "Apply the safe tier (add missing, remove deprecated)", false).option("--accept", "Stamp the current version without changing config (dismiss advisories)", false).option("--json", "Output drift items as JSON", false).action((opts) => {
25273
25572
  const pkgVersion = readPkgVersion2();
25274
- if (!fs33.existsSync(DEFAULT_CONFIG_PATH)) {
25275
- console.log(chalk23.yellow("No config found \u2014 run `squadrant init` first."));
25573
+ if (!fs34.existsSync(DEFAULT_CONFIG_PATH)) {
25574
+ console.log(chalk24.yellow("No config found \u2014 run `squadrant init` first."));
25276
25575
  return;
25277
25576
  }
25278
25577
  const res = runConfigCheck({ configPath: DEFAULT_CONFIG_PATH, pkgVersion, fix: opts.fix, accept: opts.accept });
@@ -25281,21 +25580,21 @@ configCommand.command("check").description("Detect config drift vs the current d
25281
25580
  return;
25282
25581
  }
25283
25582
  if (res.items.length === 0) {
25284
- console.log(chalk23.green("\u2714 Config is in sync with the current schema."));
25583
+ console.log(chalk24.green("\u2714 Config is in sync with the current schema."));
25285
25584
  return;
25286
25585
  }
25287
- console.log(chalk23.bold("\nConfig drift:\n"));
25586
+ console.log(chalk24.bold("\nConfig drift:\n"));
25288
25587
  printItems(res.items);
25289
25588
  if (opts.fix && res.applied.length) {
25290
- console.log(chalk23.green(`
25589
+ console.log(chalk24.green(`
25291
25590
  \u2714 Applied ${res.applied.length} safe item(s): ${res.applied.join(", ")}`));
25292
25591
  }
25293
25592
  const judgment = res.remaining.filter((i) => i.kind === "changed-default" || i.kind === "invalid");
25294
25593
  if (judgment.length) {
25295
- console.log(chalk23.yellow(`
25594
+ console.log(chalk24.yellow(`
25296
25595
  ${judgment.length} item(s) need review \u2014 run the config-doctor skill, or \`squadrant config check --accept\` to keep your values.`));
25297
25596
  } else if (res.stamped) {
25298
- console.log(chalk23.green("\n\u2714 Config reconciled and stamped."));
25597
+ console.log(chalk24.green("\n\u2714 Config reconciled and stamped."));
25299
25598
  }
25300
25599
  });
25301
25600
  configCommand.command("get").description("Read a config value by dotted key (e.g. defaults.effort)").argument("<key>", "dotted config key").action((key) => {
@@ -25303,7 +25602,7 @@ configCommand.command("get").description("Read a config value by dotted key (e.g
25303
25602
  const value = runConfigGet(key);
25304
25603
  console.log(typeof value === "string" ? value : JSON.stringify(value));
25305
25604
  } catch (e) {
25306
- console.error(chalk23.red(e.message));
25605
+ console.error(chalk24.red(e.message));
25307
25606
  process.exit(1);
25308
25607
  }
25309
25608
  });
@@ -25311,22 +25610,22 @@ configCommand.command("set").description("Write a config value by dotted key (e.
25311
25610
  try {
25312
25611
  runConfigSetAction({ key, value, noRestart: opts.restart === false });
25313
25612
  } catch (e) {
25314
- console.error(chalk23.red(e.message));
25613
+ console.error(chalk24.red(e.message));
25315
25614
  process.exit(1);
25316
25615
  }
25317
25616
  });
25318
25617
  function readPkgVersion2() {
25319
- const pkgPath = join30(dirname8(fileURLToPath5(import.meta.url)), "..", "package.json");
25320
- return JSON.parse(fs33.readFileSync(pkgPath, "utf-8")).version;
25618
+ const pkgPath = join31(dirname8(fileURLToPath5(import.meta.url)), "..", "package.json");
25619
+ return JSON.parse(fs34.readFileSync(pkgPath, "utf-8")).version;
25321
25620
  }
25322
25621
 
25323
25622
  // packages/cli/src/commands/heal.ts
25324
25623
  init_dist();
25325
25624
  import { execFileSync as execFileSync12 } from "child_process";
25326
- import { join as join31 } from "path";
25625
+ import { join as join32 } from "path";
25327
25626
  import { homedir as homedir17 } from "os";
25328
25627
  import { Command as Command24 } from "commander";
25329
- import chalk24 from "chalk";
25628
+ import chalk25 from "chalk";
25330
25629
  init_dist2();
25331
25630
  init_dist2();
25332
25631
  init_dist4();
@@ -25384,11 +25683,11 @@ async function runHealStatus(opts) {
25384
25683
  return result.healthy ? 0 : 2;
25385
25684
  }
25386
25685
  if (result.healthy) {
25387
- stdout.write(chalk24.green("\u2714 all components healthy\n"));
25686
+ stdout.write(chalk25.green("\u2714 all components healthy\n"));
25388
25687
  for (const c of result.components) {
25389
25688
  if (c.kind === "delivery" && c.state === "stale") {
25390
- const glyph = chalk24.yellow("\u2022");
25391
- const stateColor2 = chalk24.yellow;
25689
+ const glyph = chalk25.yellow("\u2022");
25690
+ const stateColor2 = chalk25.yellow;
25392
25691
  stdout.write(` ${glyph} ${c.kind.padEnd(8)} ${c.ref.padEnd(16)} ${stateColor2(c.state.padEnd(8))} ${c.project}
25393
25692
  `);
25394
25693
  if (c.detail) {
@@ -25399,13 +25698,13 @@ async function runHealStatus(opts) {
25399
25698
  }
25400
25699
  return 0;
25401
25700
  }
25402
- stdout.write(chalk24.bold("Unhealthy components:\n\n"));
25701
+ stdout.write(chalk25.bold("Unhealthy components:\n\n"));
25403
25702
  for (const c of result.components) {
25404
25703
  const isUnhealthy = c.kind === "delivery" ? c.stuck === true : c.healCmd !== null;
25405
25704
  const isAdvisoryDelivery = c.kind === "delivery" && c.state === "stale" && c.stuck !== true;
25406
25705
  if (isUnhealthy || isAdvisoryDelivery) {
25407
- const glyph = c.state === "stale" || isAdvisoryDelivery ? chalk24.yellow("\u2022") : chalk24.red("\u2718");
25408
- const stateColor2 = c.state === "stale" || isAdvisoryDelivery ? chalk24.yellow : chalk24.red;
25706
+ const glyph = c.state === "stale" || isAdvisoryDelivery ? chalk25.yellow("\u2022") : chalk25.red("\u2718");
25707
+ const stateColor2 = c.state === "stale" || isAdvisoryDelivery ? chalk25.yellow : chalk25.red;
25409
25708
  stdout.write(` ${glyph} ${c.kind.padEnd(8)} ${c.ref.padEnd(16)} ${stateColor2(c.state.padEnd(8))} ${c.project}
25410
25709
  `);
25411
25710
  if (c.detail) {
@@ -25413,7 +25712,7 @@ async function runHealStatus(opts) {
25413
25712
  `);
25414
25713
  }
25415
25714
  if (c.healCmd) {
25416
- stdout.write(` heal: ${chalk24.cyan(c.healCmd)}
25715
+ stdout.write(` heal: ${chalk25.cyan(c.healCmd)}
25417
25716
  `);
25418
25717
  }
25419
25718
  }
@@ -25426,7 +25725,7 @@ async function runHealDaemon(opts) {
25426
25725
  try {
25427
25726
  const result = opts.ensureDaemon();
25428
25727
  const noteSuffix = result?.note ? ` (${result.note})` : "";
25429
- stdout.write(chalk24.green(`\u2714 daemon kickstart complete${noteSuffix}
25728
+ stdout.write(chalk25.green(`\u2714 daemon kickstart complete${noteSuffix}
25430
25729
  `));
25431
25730
  return 0;
25432
25731
  } catch (e) {
@@ -25481,12 +25780,12 @@ async function runHealCaptain(projects, deps) {
25481
25780
  for (const project of projects) {
25482
25781
  const resolved = resolveLiveCaptain(records, project, deps.isPidAlive);
25483
25782
  if (!resolved) {
25484
- stdout.write(` ${chalk24.yellow("\u2013")} ${project}: no live captain found \u2014 nothing to heal
25783
+ stdout.write(` ${chalk25.yellow("\u2013")} ${project}: no live captain found \u2014 nothing to heal
25485
25784
  `);
25486
25785
  continue;
25487
25786
  }
25488
25787
  if (entryMatchesResolved(deps.getEntry(project), resolved)) {
25489
- stdout.write(` ${chalk24.green("\u2714")} ${project}: already healthy (pid=${resolved.pid})
25788
+ stdout.write(` ${chalk25.green("\u2714")} ${project}: already healthy (pid=${resolved.pid})
25490
25789
  `);
25491
25790
  continue;
25492
25791
  }
@@ -25516,16 +25815,16 @@ async function runHealCaptain(projects, deps) {
25516
25815
  for (const { project, resolved } of targets) {
25517
25816
  if (stillMissingSet.has(project)) {
25518
25817
  stderr.write(
25519
- ` ${chalk24.red("\u2718")} ${project}: heal did not survive the daemon restart after one retry \u2014 pid=${resolved.pid} sessionId=${resolved.sessionId} may be racing the daemon's own periodic persist
25818
+ ` ${chalk25.red("\u2718")} ${project}: heal did not survive the daemon restart after one retry \u2014 pid=${resolved.pid} sessionId=${resolved.sessionId} may be racing the daemon's own periodic persist
25520
25819
  `
25521
25820
  );
25522
25821
  } else {
25523
- stdout.write(` ${chalk24.green("\u2714")} ${project}: re-adopted captain pid=${resolved.pid} sessionId=${resolved.sessionId}
25822
+ stdout.write(` ${chalk25.green("\u2714")} ${project}: re-adopted captain pid=${resolved.pid} sessionId=${resolved.sessionId}
25524
25823
  `);
25525
25824
  }
25526
25825
  }
25527
25826
  if (stillMissingSet.size > 0) return 1;
25528
- stdout.write(chalk24.green(`\u2714 healed ${targets.length} captain(s); daemon kickstarted
25827
+ stdout.write(chalk25.green(`\u2714 healed ${targets.length} captain(s); daemon kickstarted
25529
25828
  `));
25530
25829
  return 0;
25531
25830
  }
@@ -25563,8 +25862,8 @@ var healCommand = new Command24("heal").description("Targeted, idempotent remedi
25563
25862
  }
25564
25863
  const config = loadConfig();
25565
25864
  const projects = opts.all ? Object.keys(config.projects) : [project];
25566
- const stateRoot = join31(homedir17(), ".config", "squadrant", "state");
25567
- const registry = new LivenessRegistry({ path: join31(stateRoot, "liveness.json") });
25865
+ const stateRoot = join32(homedir17(), ".config", "squadrant", "state");
25866
+ const registry = new LivenessRegistry({ path: join32(stateRoot, "liveness.json") });
25568
25867
  registry.load();
25569
25868
  const code = await runHealCaptain(projects, {
25570
25869
  liveness: readCmuxLiveness,
@@ -25590,14 +25889,14 @@ var healCommand = new Command24("heal").description("Targeted, idempotent remedi
25590
25889
 
25591
25890
  // packages/cli/src/commands/group.ts
25592
25891
  import { Command as Command26 } from "commander";
25593
- import chalk26 from "chalk";
25892
+ import chalk27 from "chalk";
25594
25893
 
25595
25894
  // packages/cli/src/commands/dispatch.ts
25596
25895
  init_dist();
25597
25896
  init_dist2();
25598
25897
  import { Command as Command25 } from "commander";
25599
25898
  import { execSync as execSync13 } from "child_process";
25600
- import chalk25 from "chalk";
25899
+ import chalk26 from "chalk";
25601
25900
  async function runDispatch(toProject, task, opts) {
25602
25901
  const fromProject = resolveCurrentProject(loadConfig());
25603
25902
  if (!fromProject) {
@@ -25622,11 +25921,11 @@ async function runDispatch(toProject, task, opts) {
25622
25921
  async function dispatchAction(toProject, task, opts) {
25623
25922
  try {
25624
25923
  const result = await runDispatch(toProject, task, opts);
25625
- console.log(chalk25.green(`\u2714 Dispatched to '${toProject}' (task ${result.id.slice(0, 8)})`));
25626
- console.log(chalk25.dim(` originProject: ${result.originProject ?? "none"}`));
25627
- console.log(chalk25.dim(" You will be notified when the task settles (done/blocked/failed)."));
25924
+ console.log(chalk26.green(`\u2714 Dispatched to '${toProject}' (task ${result.id.slice(0, 8)})`));
25925
+ console.log(chalk26.dim(` originProject: ${result.originProject ?? "none"}`));
25926
+ console.log(chalk26.dim(" You will be notified when the task settles (done/blocked/failed)."));
25628
25927
  } catch (e) {
25629
- console.error(chalk25.red(`\u2718 ${e.message}`));
25928
+ console.error(chalk26.red(`\u2718 ${e.message}`));
25630
25929
  process.exit(1);
25631
25930
  }
25632
25931
  }
@@ -25636,7 +25935,7 @@ var dispatchCommand = new Command25("dispatch").description("Dispatch a task to
25636
25935
  init_dist2();
25637
25936
  var groupCommand = new Command26("group").description("Cross-project intra-group operations (Phase 1: dispatch)").addCommand(
25638
25937
  new Command26("dispatch").description("[DEPRECATED \u2014 use 'squadrant dispatch'] Dispatch a task to a sibling project in the same group").argument("<to-project>", "Target project name").argument("<task>", "Task description to dispatch").option("--provider <p>", "claude|opencode|codex", "claude").option("--mode <m>", "headless|interactive", "headless").option("--warmup-timeout <s>", "seconds to wait for target captain to boot (default: 120)", (v2) => parseInt(v2, 10) * 1e3).action(async (toProject, task, opts) => {
25639
- console.error(chalk26.yellow(
25938
+ console.error(chalk27.yellow(
25640
25939
  `\u26A0 'squadrant group dispatch' is deprecated \u2014 use 'squadrant dispatch <project> "<task>"' instead.`
25641
25940
  ));
25642
25941
  await dispatchAction(toProject, task, opts);
@@ -25652,101 +25951,6 @@ import { join as join33, dirname as dirname9 } from "path";
25652
25951
  import { homedir as homedir18 } from "os";
25653
25952
  import { Command as Command27 } from "commander";
25654
25953
  import chalk28 from "chalk";
25655
-
25656
- // packages/cli/src/lib/captain-channel-factory.ts
25657
- init_dist3();
25658
- init_dist2();
25659
- import { createServer as createServer6, connect as netConnect2 } from "net";
25660
- import fs34 from "fs";
25661
- import { join as join32 } from "path";
25662
- import { randomUUID as randomUUID7 } from "crypto";
25663
- import chalk27 from "chalk";
25664
- var shared;
25665
- var registryEntryPath = () => join32(CLAUDE_SESSIONS_DIR, `${process.pid}.json`);
25666
- function unregisterSenderIdentity() {
25667
- try {
25668
- fs34.unlinkSync(registryEntryPath());
25669
- } catch {
25670
- }
25671
- }
25672
- function registerSenderIdentity(socketPath2) {
25673
- try {
25674
- unregisterSenderIdentity();
25675
- fs34.mkdirSync(CLAUDE_SESSIONS_DIR, { recursive: true });
25676
- fs34.writeFileSync(
25677
- registryEntryPath(),
25678
- JSON.stringify({
25679
- pid: process.pid,
25680
- sessionId: randomUUID7(),
25681
- name: "squadrantd",
25682
- messagingSocketPath: socketPath2,
25683
- kind: "daemon",
25684
- peerProtocol: 1
25685
- })
25686
- );
25687
- process.on("exit", unregisterSenderIdentity);
25688
- } catch {
25689
- }
25690
- }
25691
- async function sharedReceiptListener() {
25692
- if (shared) return shared;
25693
- ensureSocksDir();
25694
- const socketPath2 = `${CC_SOCKS_DIR}/squadrantd-${process.pid}.sock`;
25695
- const listener = new ClaudeReceiptListener({
25696
- socketPath: socketPath2,
25697
- createServer: (h) => createServer6(h),
25698
- // A UDS path is not cleaned up when a process is killed, so our own leftover
25699
- // must never be the reason we refuse to start.
25700
- unlinkStale: (p) => {
25701
- try {
25702
- fs34.unlinkSync(p);
25703
- } catch {
25704
- }
25705
- },
25706
- log: (m) => console.error(chalk27.dim(m))
25707
- });
25708
- await listener.start();
25709
- registerSenderIdentity(socketPath2);
25710
- shared = listener;
25711
- return shared;
25712
- }
25713
- function captainSessionIdFor(taskId) {
25714
- return readClaudeStatusBySocketPath(captainSocketPath(taskId))?.sessionId;
25715
- }
25716
- async function buildCaptainChannel() {
25717
- const receipts = await sharedReceiptListener();
25718
- return new ClaudePeerChannel({
25719
- // The port's taskId IS the project name for captains.
25720
- socketPathFor: (taskId) => captainSocketPath(taskId),
25721
- sessionIdFor: captainSessionIdFor,
25722
- // Captains are identified in the registry by their cwd (the project path).
25723
- // Resolve by the socket path squadrant chose at launch, NOT by cwd: a captain
25724
- // in /tmp/x registers cwd "/private/tmp/x" on macOS, so cwd matching silently
25725
- // missed and every captain ping reported accepted-unconfirmed.
25726
- statusFor: (taskId) => readClaudeStatusBySocketPath(captainSocketPath(taskId)),
25727
- wire: (p, e) => writeLine(p, e, { connect: (path46) => netConnect2(path46) }),
25728
- receipts,
25729
- newMsgId: () => randomUUID7(),
25730
- sleep: (ms) => new Promise((r) => setTimeout(r, ms)),
25731
- log: (m) => console.error(chalk27.dim(m))
25732
- });
25733
- }
25734
- async function buildCaptainChannels(opts) {
25735
- const claude = await buildCaptainChannel();
25736
- const opencode = new OpencodeHttpChannel({
25737
- portFor: (project) => readCaptainAddress(opts.stateRoot, project)?.port,
25738
- sessionFor: (project) => readCaptainAddress(opts.stateRoot, project)?.sessionId
25739
- });
25740
- return {
25741
- channels: { claude, opencode },
25742
- agentFor: (project) => resolveCaptainAgent(opts.stateRoot, project, opts.configAgent)
25743
- };
25744
- }
25745
- function resolveCaptainAgent(stateRoot, project, configAgent) {
25746
- return readCaptainAddress(stateRoot, project)?.agent ?? configAgent;
25747
- }
25748
-
25749
- // packages/cli/src/commands/ping.ts
25750
25954
  function formatPingResult(project, outcome) {
25751
25955
  if (!outcome) return `\u2714 Pinged '${project}'`;
25752
25956
  switch (outcome.status) {