squad-kit 0.7.2 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.8.0] — 2026-05-03
11
+
12
+ ### What's new
13
+
14
+ - Generate page shows provider rate limits: countdown, auto-retry banner,
15
+ and rerun when the planner aborts over the wait cap.
16
+ - Planner emits richer `rate_limit` stream events (`retrying` vs `aborted`,
17
+ cap seconds, provider, short error snippet). CLI `new-plan` only shows the
18
+ “waiting to retry” spinner for the retrying phase.
19
+ - Run SSE ends a rate-limit abort with `done` (partial) only — no extra
20
+ `error` line repeating the same message.
21
+
22
+ ### Bug fixes
23
+
24
+ - Jira issue search called deprecated `/rest/api/3/search` (Atlassian returns
25
+ HTTP 410). Search now uses `/rest/api/3/search/jql` with clearer 410 errors
26
+ if an old client hits removed endpoints.
27
+
10
28
  ## [0.7.2] — 2026-04-28
11
29
 
12
30
  ### Bug fixes
package/dist/cli.js CHANGED
@@ -1685,7 +1685,7 @@ var JiraClient = class {
1685
1685
  const esc = q.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
1686
1686
  jql = `text ~ "${esc}" order by updated DESC`;
1687
1687
  }
1688
- const url = `${this.baseUrl}/rest/api/3/search?jql=${encodeURIComponent(jql)}&fields=summary,status,issuetype&maxResults=${limit}`;
1688
+ const url = `${this.baseUrl}/rest/api/3/search/jql?jql=${encodeURIComponent(jql)}&fields=summary,status,issuetype&maxResults=${limit}`;
1689
1689
  let res;
1690
1690
  try {
1691
1691
  res = await fetch(url, { headers: this.headers() });
@@ -1734,6 +1734,13 @@ var JiraClient = class {
1734
1734
  if (status === 429) {
1735
1735
  return new TrackerError(`Jira rate limit hit (HTTP 429). Wait a minute and retry.`, "rate-limited", status);
1736
1736
  }
1737
+ if (status === 410) {
1738
+ return new TrackerError(
1739
+ id === "search" ? `Jira search endpoint has been removed by Atlassian (HTTP 410). squad-kit must call /rest/api/3/search/jql instead \u2014 upgrade squad-kit to a version that includes this fix.` : `Jira endpoint has been removed by Atlassian (HTTP 410). Upgrade squad-kit to a version that calls the current Jira Cloud REST API.`,
1740
+ "other",
1741
+ status
1742
+ );
1743
+ }
1737
1744
  return new TrackerError(
1738
1745
  id === "search" ? `Jira search failed (HTTP ${status}).` : `Jira request failed (HTTP ${status}).`,
1739
1746
  "other",
@@ -4103,12 +4110,26 @@ async function runPlanner(input5) {
4103
4110
  let retrySkippedReason;
4104
4111
  if (response.stopReason === "error" && response.errorKind === "rate_limit") {
4105
4112
  const asked = response.retryAfterSec;
4113
+ const emitRateLimit = (phase, waitSec) => {
4114
+ bus.emit({
4115
+ kind: "rate_limit",
4116
+ runId,
4117
+ turn: iterations,
4118
+ retryAfterSec: response.retryAfterSec,
4119
+ waitSec,
4120
+ capSec: MAX_RATE_LIMIT_RETRY_SEC,
4121
+ phase,
4122
+ provider: input5.provider.name,
4123
+ rawBody: (response.rawError ?? "").slice(0, 200)
4124
+ });
4125
+ };
4106
4126
  if (asked !== void 0 && asked > MAX_RATE_LIMIT_RETRY_SEC) {
4127
+ emitRateLimit("aborted", asked);
4107
4128
  retrySkippedReason = "retry_after_too_long";
4108
4129
  } else {
4109
4130
  const waitSec = Math.min(asked ?? 10, MAX_RATE_LIMIT_RETRY_SEC);
4131
+ emitRateLimit("retrying", waitSec);
4110
4132
  input5.onRateLimit?.(waitSec);
4111
- bus.emit({ kind: "rate_limit", runId, turn: iterations, waitSec });
4112
4133
  try {
4113
4134
  await sleepWithAbort(waitSec * 1e3, sleepFn, input5.abort);
4114
4135
  } catch (e) {
@@ -4888,9 +4909,11 @@ async function emitViaApi(story, paths, config2, opts) {
4888
4909
  sessionSpinner.current = spinner("thinking\u2026");
4889
4910
  break;
4890
4911
  case "rate_limit":
4891
- sessionSpinner.current?.stop();
4892
- warning(`${planner.provider} rate limit hit \u2014 retrying in ${e.waitSec}s`);
4893
- sessionSpinner.current = spinner("waiting for rate limit to reset\u2026");
4912
+ if (e.phase === "retrying") {
4913
+ sessionSpinner.current?.stop();
4914
+ warning(`${e.provider} rate limit hit \u2014 retrying in ${e.waitSec}s`);
4915
+ sessionSpinner.current = spinner("waiting for rate limit to reset\u2026");
4916
+ }
4894
4917
  break;
4895
4918
  case "usage":
4896
4919
  break;
@@ -6566,7 +6589,11 @@ function mountRunsApi(app, opts) {
6566
6589
  });
6567
6590
  } catch (err) {
6568
6591
  const durationMs = Date.now() - startedAt;
6569
- bus.emit({ kind: "error", runId, message: err.message });
6592
+ const last = eventBuffer[eventBuffer.length - 1];
6593
+ const isRateLimitAbort = last?.kind === "rate_limit" && last.phase === "aborted";
6594
+ if (!isRateLimitAbort) {
6595
+ bus.emit({ kind: "error", runId, message: err.message });
6596
+ }
6570
6597
  bus.emit({
6571
6598
  kind: "done",
6572
6599
  runId,