squadrant 0.14.0 → 0.14.2

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
@@ -1601,11 +1601,11 @@ var init_session_freshness = __esm({
1601
1601
  });
1602
1602
 
1603
1603
  // packages/core/dist/crew-protocol.js
1604
- function isTurnAccepted(preSendScreen, afterScreen, config) {
1605
- if (config?.splashMarker) {
1606
- return !afterScreen.includes(config.splashMarker);
1607
- }
1608
- return afterScreen !== preSendScreen;
1604
+ function normalizeForSplashMatch(text) {
1605
+ return text.toLowerCase().replace(/…/g, "...").replace(/\s+/g, " ").trim();
1606
+ }
1607
+ function screenHasSplashMarker(screen, marker) {
1608
+ return normalizeForSplashMatch(screen).includes(normalizeForSplashMatch(marker));
1609
1609
  }
1610
1610
  function buildCompletionProtocol(taskId, project) {
1611
1611
  return [
@@ -2643,10 +2643,16 @@ ${buildCompletionProtocol(rec.id, input.project)}`, preLaunchScreen);
2643
2643
  const opencodeResult = await deps.sendFirstTurn(pane2, `${firstTurnTask}
2644
2644
 
2645
2645
  ${buildCompletionProtocol(rec.id, input.project)}`, preLaunchScreen, {
2646
- // #235: confirm-on-delivery — sendFirstTurnWhenReady polls until "Ask
2647
- // anything…" leaves the screen, re-sending every ~3s to cover slow boots
2646
+ // #235: confirm-on-delivery — sendFirstTurnWhenReady polls until the idle
2647
+ // splash leaves the screen, re-sending every ~3s to cover slow boots
2648
2648
  // without duplicating the task. See crew-pane.ts SPLASH_MAX_CHECKS/EVERY_N.
2649
- splashMarker: "Ask anything\u2026"
2649
+ // #499: match a stable substring ("ask anything", case/whitespace/ellipsis
2650
+ // -insensitive via screenHasSplashMarker) rather than the exact wording —
2651
+ // opencode's real placeholder rotates through example prompts and uses
2652
+ // three ASCII dots ("Ask anything...") or a longer command hint ("Ask
2653
+ // anything, / for commands, @ for context..."), never the literal
2654
+ // "Ask anything…" (U+2026) this used to hardcode, which never matched.
2655
+ splashMarker: "Ask anything"
2650
2656
  });
2651
2657
  if (!opencodeResult.delivered) {
2652
2658
  process.stderr.write(`\u26A0\uFE0F First turn not delivered for crew '${name}' \u2014 use 'squadrant crew send ${input.project} ${name}' to re-send the task.
@@ -4153,7 +4159,7 @@ async function sendFirstTurnWhenReady(runtime, pane, task, preLaunchScreen, acce
4153
4159
  let stable = false;
4154
4160
  for (let i = 0; i < maxPolls && !stable; i++) {
4155
4161
  const screen = await runtime.readPaneScreen(pane) ?? "";
4156
- const ready = acceptanceConfig?.splashMarker ? true : hasCCInputBox(screen) && classifyStartupSurface(screen) === "idle";
4162
+ const ready = acceptanceConfig?.splashMarker ? screenHasSplashMarker(screen, acceptanceConfig.splashMarker) : hasCCInputBox(screen) && classifyStartupSurface(screen) === "idle";
4157
4163
  if (screen.length > 0 && screen === previousScreen && screen !== preLaunchScreen && ready) {
4158
4164
  stable = true;
4159
4165
  } else {
@@ -4163,11 +4169,14 @@ async function sendFirstTurnWhenReady(runtime, pane, task, preLaunchScreen, acce
4163
4169
  }
4164
4170
  const preSendScreen = await runtime.readPaneScreen(pane) ?? "";
4165
4171
  if (acceptanceConfig?.splashMarker) {
4172
+ let sawSplash = screenHasSplashMarker(preSendScreen, acceptanceConfig.splashMarker);
4166
4173
  await runtime.sendToPane(pane, task);
4167
4174
  for (let check2 = 0; check2 < SPLASH_MAX_CHECKS; check2++) {
4168
4175
  await new Promise((r) => setTimeout(r, POST_SEND_CHECK_MS));
4169
4176
  const afterScreen = await runtime.readPaneScreen(pane) ?? "";
4170
- if (isTurnAccepted(preSendScreen, afterScreen, acceptanceConfig)) {
4177
+ if (screenHasSplashMarker(afterScreen, acceptanceConfig.splashMarker)) {
4178
+ sawSplash = true;
4179
+ } else if (sawSplash) {
4171
4180
  return { delivered: true };
4172
4181
  }
4173
4182
  if ((check2 + 1) % SPLASH_RESEND_EVERY_N === 0 && check2 < SPLASH_MAX_CHECKS - 1) {
@@ -8571,7 +8580,11 @@ function collect(snap) {
8571
8580
  env.vaults.hub.state,
8572
8581
  ...env.vaults.spokes.map((s) => s.state),
8573
8582
  env.config.parseable.state,
8574
- env.config.sessions.state,
8583
+ // Template-hash drift (env.config.sessions.state) is demoted to soft/info:
8584
+ // projects registered but idle/never-launched legitimately sit on older
8585
+ // template versions, so drift alone is not actionable trouble. Its own
8586
+ // status still renders in the Environment tab; it just no longer rolls up
8587
+ // into envT/overall/masterClass.
8575
8588
  ...env.config.projectPaths.map((p) => p.state)
8576
8589
  ];
8577
8590
  const daemonStates = [];
@@ -8591,7 +8604,8 @@ function collect(snap) {
8591
8604
  undelivered++;
8592
8605
  }
8593
8606
  for (const p of snap.daemon.tier2.projects) {
8594
- if (p.delivery.behind > 0)
8607
+ const captain = snap.daemon.tier1.find((c) => c.kind === "captain" && c.project === p.project);
8608
+ if (captain?.state === "alive" && p.delivery.behind > 0)
8595
8609
  projStates.push("stale");
8596
8610
  if (p.store.corruptCount > 0)
8597
8611
  projStates.push("gone");