squadrant 0.13.0 → 0.13.1

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
@@ -622,8 +622,41 @@ function resolveWorktreeBase(repoRoot, fallback = "develop") {
622
622
  return fallback;
623
623
  }
624
624
  function addWorktree(spec) {
625
- const wt = worktreePath(spec.repoRoot, spec.worktreeDir, spec.project, spec.name);
626
- execFileSync2("git", ["-C", spec.repoRoot, "worktree", "add", wt, "-b", crewBranch(spec.name), spec.base], { stdio: "pipe" });
625
+ const originalBranch = crewBranch(spec.name);
626
+ let targetName = spec.name;
627
+ let targetBranch = originalBranch;
628
+ let branchExists = false;
629
+ try {
630
+ execFileSync2("git", ["-C", spec.repoRoot, "show-ref", "--verify", "--quiet", `refs/heads/${originalBranch}`], { stdio: "pipe" });
631
+ branchExists = true;
632
+ } catch {
633
+ }
634
+ if (branchExists) {
635
+ const log = execFileSync2("git", ["-C", spec.repoRoot, "log", "--oneline", `${spec.base}..${originalBranch}`], { stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
636
+ if (!log) {
637
+ execFileSync2("git", ["-C", spec.repoRoot, "branch", "-D", originalBranch], { stdio: "pipe" });
638
+ } else {
639
+ let suffix = 2;
640
+ while (true) {
641
+ const candidate = `${spec.name}-${suffix}`;
642
+ const candidateBranch = crewBranch(candidate);
643
+ let candidateExists = false;
644
+ try {
645
+ execFileSync2("git", ["-C", spec.repoRoot, "show-ref", "--verify", "--quiet", `refs/heads/${candidateBranch}`], { stdio: "pipe" });
646
+ candidateExists = true;
647
+ } catch {
648
+ }
649
+ if (!candidateExists) {
650
+ targetName = candidate;
651
+ targetBranch = candidateBranch;
652
+ break;
653
+ }
654
+ suffix++;
655
+ }
656
+ }
657
+ }
658
+ const wt = worktreePath(spec.repoRoot, spec.worktreeDir, spec.project, targetName);
659
+ execFileSync2("git", ["-C", spec.repoRoot, "worktree", "add", wt, "-b", targetBranch, spec.base], { stdio: "pipe" });
627
660
  return wt;
628
661
  }
629
662
  function removeWorktree(repoRoot, wtPath) {
@@ -3911,13 +3944,18 @@ var init_native_hook_source = __esm({
3911
3944
  import net from "net";
3912
3945
  async function settleInputBox(runtime, pane) {
3913
3946
  let prev = await runtime.readPaneScreen(pane) ?? "";
3947
+ let sawContent = parseDraftFromScreen(prev) !== "" && parseDraftFromScreen(prev) !== null;
3914
3948
  for (let i = 0; i < SETTLE_MAX_POLLS; i++) {
3915
3949
  await new Promise((r) => setTimeout(r, SETTLE_POLL_MS));
3916
3950
  const cur = await runtime.readPaneScreen(pane) ?? "";
3951
+ const draft = parseDraftFromScreen(cur);
3952
+ if (draft !== "" && draft !== null)
3953
+ sawContent = true;
3917
3954
  if (cur === prev)
3918
- return;
3955
+ return sawContent;
3919
3956
  prev = cur;
3920
3957
  }
3958
+ return sawContent;
3921
3959
  }
3922
3960
  function getFreePort() {
3923
3961
  return new Promise((resolve3, reject) => {
@@ -3955,17 +3993,26 @@ async function resolveCaptainWorkspace(project) {
3955
3993
  async function confirmedSendToPane(runtime, pane, message) {
3956
3994
  const preSendScreen = await runtime.readPaneScreen(pane) ?? "";
3957
3995
  await runtime.pasteToPane(pane, message);
3958
- await settleInputBox(runtime, pane);
3996
+ let sawDraft = await settleInputBox(runtime, pane);
3959
3997
  await runtime.sendKeyToPane(pane, "Enter");
3998
+ let repasted = false;
3960
3999
  for (let attempt = 0; attempt < SUBMIT_RETRY_LIMIT; attempt++) {
3961
4000
  await new Promise((r) => setTimeout(r, POST_SEND_CHECK_MS));
3962
4001
  const afterScreen = await runtime.readPaneScreen(pane) ?? "";
3963
4002
  const draft = parseDraftFromScreen(afterScreen);
3964
- if (draft === "")
4003
+ if (draft !== "" && draft !== null)
4004
+ sawDraft = true;
4005
+ if (draft === "" && sawDraft)
3965
4006
  return;
3966
4007
  if (draft === null && afterScreen !== preSendScreen)
3967
4008
  return;
3968
- await settleInputBox(runtime, pane);
4009
+ const settled = await settleInputBox(runtime, pane);
4010
+ if (settled)
4011
+ sawDraft = true;
4012
+ if (!sawDraft && !repasted) {
4013
+ repasted = true;
4014
+ await runtime.pasteToPane(pane, message);
4015
+ }
3969
4016
  await runtime.sendKeyToPane(pane, "Enter");
3970
4017
  }
3971
4018
  }
@@ -3999,18 +4046,27 @@ async function sendFirstTurnWhenReady(runtime, pane, task, preLaunchScreen, acce
3999
4046
  return;
4000
4047
  }
4001
4048
  await runtime.pasteToPane(pane, task);
4002
- await settleInputBox(runtime, pane);
4049
+ let sawDraft = await settleInputBox(runtime, pane);
4003
4050
  await runtime.sendKeyToPane(pane, "Enter");
4004
4051
  const retryLimit = acceptanceConfig?.retryLimit ?? SUBMIT_RETRY_LIMIT;
4052
+ let repasted = false;
4005
4053
  for (let attempt = 0; attempt < retryLimit; attempt++) {
4006
4054
  await new Promise((r) => setTimeout(r, POST_SEND_CHECK_MS));
4007
4055
  const afterScreen = await runtime.readPaneScreen(pane) ?? "";
4008
4056
  const draft = parseDraftFromScreen(afterScreen);
4009
- if (draft === "")
4057
+ if (draft !== "" && draft !== null)
4058
+ sawDraft = true;
4059
+ if (draft === "" && sawDraft)
4010
4060
  return;
4011
4061
  if (draft === null && afterScreen !== preSendScreen)
4012
4062
  return;
4013
- await settleInputBox(runtime, pane);
4063
+ const settled = await settleInputBox(runtime, pane);
4064
+ if (settled)
4065
+ sawDraft = true;
4066
+ if (!sawDraft && !repasted) {
4067
+ repasted = true;
4068
+ await runtime.pasteToPane(pane, task);
4069
+ }
4014
4070
  await runtime.sendKeyToPane(pane, "Enter");
4015
4071
  }
4016
4072
  }
@@ -5806,8 +5862,13 @@ function classifyPaneTail(tail) {
5806
5862
  if (c != null && ERROR_BANNER_RE.some((re) => re.test(c)))
5807
5863
  errLine = c;
5808
5864
  }
5809
- if (errLine)
5865
+ if (errLine) {
5866
+ const isRetrying = cleaned.some((c) => c != null && RETRYING_RE.test(c));
5867
+ const isExhausted = cleaned.some((c) => c != null && EXHAUSTED_RE.test(c));
5868
+ if (isRetrying && !isExhausted)
5869
+ return null;
5810
5870
  return { kind: "error", text: errLine.slice(0, 200) };
5871
+ }
5811
5872
  return null;
5812
5873
  }
5813
5874
  function stripChrome(raw) {
@@ -5824,7 +5885,7 @@ function stripChrome(raw) {
5824
5885
  return null;
5825
5886
  return trimmed;
5826
5887
  }
5827
- var ERROR_BANNER_RE, OPTION_RE, PICKER_FOOTER_RE, PURE_CHROME_RE, STATUS_LINE_RE;
5888
+ var ERROR_BANNER_RE, RETRYING_RE, EXHAUSTED_RE, OPTION_RE, PICKER_FOOTER_RE, PURE_CHROME_RE, STATUS_LINE_RE;
5828
5889
  var init_pane_classifier = __esm({
5829
5890
  "packages/agents/dist/interactive/pane-classifier.js"() {
5830
5891
  init_claude2();
@@ -5837,6 +5898,8 @@ var init_pane_classifier = __esm({
5837
5898
  /\bretr(?:y|ies)\s+(?:exhausted|limit\s+(?:reached|exceeded))\b/i,
5838
5899
  /\bmaximum\s+retries\b/i
5839
5900
  ];
5901
+ RETRYING_RE = /\bRetrying\b|\battempt\s+\d+\s*\/\s*\d+/i;
5902
+ EXHAUSTED_RE = /\bretr(?:y|ies)\s+(?:exhausted|limit\s+(?:reached|exceeded))\b|\bmaximum\s+retries\b/i;
5840
5903
  OPTION_RE = /^[❯>›]?\s*(\d+)\.\s+(.*\S)\s*$/;
5841
5904
  PICKER_FOOTER_RE = /↑↓\s*select|enter\s+submit|esc\s+dismiss/i;
5842
5905
  PURE_CHROME_RE = /^[\s─━│┃╭╮╰╯┌┐└┘├┤┬┴┼═║╔╗╚╝╠╣╦╩╬▁▂▃▄▅▆▇█▔▏▕]+$/;