sequant 2.8.0 → 2.10.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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +23 -4
- package/dist/bin/cli.js +99 -18
- package/dist/marketplace/external_plugins/sequant/.claude-plugin/plugin.json +1 -1
- package/dist/marketplace/external_plugins/sequant/.mcp.json +1 -1
- package/dist/marketplace/external_plugins/sequant/README.md +58 -2
- package/dist/marketplace/external_plugins/sequant/hooks/parallel-marker.sh +50 -0
- package/dist/marketplace/external_plugins/sequant/hooks/post-tool.sh +38 -10
- package/dist/marketplace/external_plugins/sequant/hooks/pre-tool.sh +405 -67
- package/dist/marketplace/external_plugins/sequant/skills/_shared/references/trust-model.md +18 -0
- package/dist/marketplace/external_plugins/sequant/skills/assess/SKILL.md +250 -344
- package/dist/marketplace/external_plugins/sequant/skills/assess/references/predicted-collision-detection.md +10 -7
- package/dist/marketplace/external_plugins/sequant/skills/docs/SKILL.md +4 -4
- package/dist/marketplace/external_plugins/sequant/skills/exec/SKILL.md +26 -6
- package/dist/marketplace/external_plugins/sequant/skills/fullsolve/SKILL.md +4 -2
- package/dist/marketplace/external_plugins/sequant/skills/loop/SKILL.md +38 -2
- package/dist/marketplace/external_plugins/sequant/skills/merger/SKILL.md +2 -2
- package/dist/marketplace/external_plugins/sequant/skills/qa/SKILL.md +337 -57
- package/dist/marketplace/external_plugins/sequant/skills/qa/references/anti-pattern-detection.md +6 -6
- package/dist/marketplace/external_plugins/sequant/skills/qa/references/call-site-review.md +2 -2
- package/dist/marketplace/external_plugins/sequant/skills/qa/references/code-review-checklist.md +2 -2
- package/dist/marketplace/external_plugins/sequant/skills/qa/references/fixtures/injection-issue-body.md +36 -0
- package/dist/marketplace/external_plugins/sequant/skills/qa/references/quality-gates.md +21 -7
- package/dist/marketplace/external_plugins/sequant/skills/qa/references/testing-requirements.md +1 -1
- package/dist/marketplace/external_plugins/sequant/skills/qa/scripts/quality-checks.sh +11 -11
- package/dist/marketplace/external_plugins/sequant/skills/reflect/SKILL.md +27 -13
- package/dist/marketplace/external_plugins/sequant/skills/reflect/references/documentation-tiers.md +80 -68
- package/dist/marketplace/external_plugins/sequant/skills/reflect/references/phase-reflection.md +31 -15
- package/dist/marketplace/external_plugins/sequant/skills/release/SKILL.md +11 -3
- package/dist/marketplace/external_plugins/sequant/skills/setup/SKILL.md +5 -5
- package/dist/marketplace/external_plugins/sequant/skills/spec/SKILL.md +2 -0
- package/dist/marketplace/external_plugins/sequant/skills/spec/references/verification-criteria.md +1 -1
- package/dist/marketplace/external_plugins/sequant/skills/test/SKILL.md +1 -1
- package/dist/src/commands/assess-render.d.ts +23 -0
- package/dist/src/commands/assess-render.js +60 -0
- package/dist/src/commands/doctor.js +8 -13
- package/dist/src/commands/init.js +13 -1
- package/dist/src/commands/locks.js +2 -0
- package/dist/src/commands/logs.js +20 -6
- package/dist/src/commands/merge.js +154 -2
- package/dist/src/commands/ready-tui-adapter.js +6 -1
- package/dist/src/commands/ready.d.ts +25 -3
- package/dist/src/commands/ready.js +39 -13
- package/dist/src/commands/resume.d.ts +113 -0
- package/dist/src/commands/resume.js +193 -0
- package/dist/src/commands/run-display.d.ts +20 -0
- package/dist/src/commands/run-display.js +117 -5
- package/dist/src/commands/run-flags.d.ts +42 -1
- package/dist/src/commands/run-flags.js +53 -1
- package/dist/src/commands/run-progress.js +26 -1
- package/dist/src/commands/run.js +11 -10
- package/dist/src/commands/state.js +7 -0
- package/dist/src/commands/stats.js +47 -0
- package/dist/src/commands/status.d.ts +9 -0
- package/dist/src/commands/status.js +24 -1
- package/dist/src/commands/sync.js +90 -19
- package/dist/src/commands/update.js +28 -5
- package/dist/src/lib/ac-parser.d.ts +14 -0
- package/dist/src/lib/ac-parser.js +99 -5
- package/dist/src/lib/assess/index.d.ts +10 -0
- package/dist/src/lib/assess/index.js +9 -0
- package/dist/src/lib/assess/renderer.d.ts +64 -0
- package/dist/src/lib/assess/renderer.js +481 -0
- package/dist/src/lib/assess/types.d.ts +224 -0
- package/dist/src/lib/assess/types.js +241 -0
- package/dist/src/lib/assess-collision-detect.d.ts +19 -2
- package/dist/src/lib/assess-collision-detect.js +68 -4
- package/dist/src/lib/ci/outputs.d.ts +15 -2
- package/dist/src/lib/ci/outputs.js +17 -5
- package/dist/src/lib/cli-flags.d.ts +33 -0
- package/dist/src/lib/cli-flags.js +46 -0
- package/dist/src/lib/cli-ui/run-renderer-types.d.ts +21 -7
- package/dist/src/lib/cli-ui/run-renderer.d.ts +10 -0
- package/dist/src/lib/cli-ui/run-renderer.js +79 -9
- package/dist/src/lib/errors.d.ts +84 -6
- package/dist/src/lib/errors.js +142 -17
- package/dist/src/lib/locks/index.d.ts +3 -3
- package/dist/src/lib/locks/index.js +2 -2
- package/dist/src/lib/locks/lock-manager.d.ts +20 -2
- package/dist/src/lib/locks/lock-manager.js +47 -3
- package/dist/src/lib/locks/types.d.ts +34 -3
- package/dist/src/lib/locks/types.js +16 -0
- package/dist/src/lib/manifest.js +1 -17
- package/dist/src/lib/mcp-config.d.ts +45 -0
- package/dist/src/lib/mcp-config.js +77 -1
- package/dist/src/lib/merge-check/combined-branch-test.d.ts +21 -2
- package/dist/src/lib/merge-check/combined-branch-test.js +233 -110
- package/dist/src/lib/merge-check/command-result.d.ts +36 -0
- package/dist/src/lib/merge-check/command-result.js +56 -0
- package/dist/src/lib/merge-check/index.d.ts +4 -0
- package/dist/src/lib/merge-check/index.js +1 -1
- package/dist/src/lib/merge-check/report.js +5 -1
- package/dist/src/lib/merge-check/types.d.ts +9 -0
- package/dist/src/lib/merge-check/watch.d.ts +121 -0
- package/dist/src/lib/merge-check/watch.js +215 -0
- package/dist/src/lib/qa/infra-blocked-ci.d.ts +90 -0
- package/dist/src/lib/qa/infra-blocked-ci.js +80 -0
- package/dist/src/lib/settings.d.ts +14 -0
- package/dist/src/lib/settings.js +61 -8
- package/dist/src/lib/shutdown.d.ts +42 -2
- package/dist/src/lib/shutdown.js +75 -5
- package/dist/src/lib/skills-check.d.ts +26 -0
- package/dist/src/lib/skills-check.js +31 -0
- package/dist/src/lib/stacks.d.ts +110 -1
- package/dist/src/lib/stacks.js +244 -5
- package/dist/src/lib/templates.d.ts +74 -0
- package/dist/src/lib/templates.js +171 -16
- package/dist/src/lib/test-tautology-detector.d.ts +9 -2
- package/dist/src/lib/test-tautology-detector.js +153 -12
- package/dist/src/lib/version-check.d.ts +31 -0
- package/dist/src/lib/version-check.js +46 -7
- package/dist/src/lib/workflow/batch-executor.d.ts +138 -6
- package/dist/src/lib/workflow/batch-executor.js +550 -54
- package/dist/src/lib/workflow/chain-preflight.d.ts +89 -0
- package/dist/src/lib/workflow/chain-preflight.js +199 -0
- package/dist/src/lib/workflow/chain-resume.d.ts +118 -0
- package/dist/src/lib/workflow/chain-resume.js +170 -0
- package/dist/src/lib/workflow/completed-status.d.ts +52 -0
- package/dist/src/lib/workflow/completed-status.js +57 -0
- package/dist/src/lib/workflow/config-resolver.d.ts +26 -0
- package/dist/src/lib/workflow/config-resolver.js +54 -2
- package/dist/src/lib/workflow/dependency-markers.d.ts +29 -0
- package/dist/src/lib/workflow/dependency-markers.js +79 -0
- package/dist/src/lib/workflow/drivers/agent-driver.d.ts +7 -0
- package/dist/src/lib/workflow/drivers/aider.d.ts +2 -0
- package/dist/src/lib/workflow/drivers/aider.js +2 -0
- package/dist/src/lib/workflow/drivers/claude-code.d.ts +21 -0
- package/dist/src/lib/workflow/drivers/claude-code.js +50 -8
- package/dist/src/lib/workflow/error-classifier.d.ts +9 -2
- package/dist/src/lib/workflow/error-classifier.js +14 -1
- package/dist/src/lib/workflow/git-diff-utils.d.ts +35 -3
- package/dist/src/lib/workflow/git-diff-utils.js +77 -4
- package/dist/src/lib/workflow/heartbeat.d.ts +38 -0
- package/dist/src/lib/workflow/heartbeat.js +90 -0
- package/dist/src/lib/workflow/log-writer.d.ts +44 -1
- package/dist/src/lib/workflow/log-writer.js +81 -14
- package/dist/src/lib/workflow/metrics-schema.d.ts +42 -3
- package/dist/src/lib/workflow/metrics-schema.js +16 -0
- package/dist/src/lib/workflow/metrics-writer.d.ts +2 -1
- package/dist/src/lib/workflow/phase-executor.d.ts +234 -13
- package/dist/src/lib/workflow/phase-executor.js +533 -56
- package/dist/src/lib/workflow/phase-registry.js +2 -1
- package/dist/src/lib/workflow/platforms/github.d.ts +64 -0
- package/dist/src/lib/workflow/platforms/github.js +152 -0
- package/dist/src/lib/workflow/qa-cache.d.ts +6 -1
- package/dist/src/lib/workflow/qa-cache.js +22 -9
- package/dist/src/lib/workflow/ready-gate.d.ts +17 -4
- package/dist/src/lib/workflow/ready-gate.js +25 -9
- package/dist/src/lib/workflow/run-log-schema.d.ts +37 -0
- package/dist/src/lib/workflow/run-log-schema.js +92 -2
- package/dist/src/lib/workflow/run-orchestrator.d.ts +33 -0
- package/dist/src/lib/workflow/run-orchestrator.js +429 -47
- package/dist/src/lib/workflow/skills-preflight.d.ts +89 -0
- package/dist/src/lib/workflow/skills-preflight.js +112 -0
- package/dist/src/lib/workflow/state-cleanup.js +9 -2
- package/dist/src/lib/workflow/state-manager.d.ts +33 -0
- package/dist/src/lib/workflow/state-manager.js +83 -0
- package/dist/src/lib/workflow/state-schema.d.ts +26 -0
- package/dist/src/lib/workflow/state-schema.js +47 -0
- package/dist/src/lib/workflow/status-derivation.d.ts +30 -0
- package/dist/src/lib/workflow/status-derivation.js +27 -0
- package/dist/src/lib/workflow/types.d.ts +149 -4
- package/dist/src/lib/workflow/types.js +1 -0
- package/dist/src/lib/workflow/worktree-manager.d.ts +70 -2
- package/dist/src/lib/workflow/worktree-manager.js +201 -52
- package/dist/src/mcp/tools/run.d.ts +11 -1
- package/dist/src/mcp/tools/run.js +22 -1
- package/dist/src/mcp/tools/status.js +6 -0
- package/dist/src/ui/tui/ElapsedTimer.d.ts +12 -3
- package/dist/src/ui/tui/ElapsedTimer.js +12 -10
- package/dist/src/ui/tui/IssueBox.js +10 -2
- package/dist/src/ui/tui/row-cap.js +2 -1
- package/dist/src/ui/tui/theme.d.ts +7 -0
- package/dist/src/ui/tui/theme.js +9 -0
- package/package.json +9 -10
- package/templates/hooks/parallel-marker.sh +50 -0
- package/templates/hooks/post-tool.sh +38 -10
- package/templates/hooks/pre-tool.sh +405 -67
- package/templates/scripts/cleanup-worktree.sh +282 -30
- package/templates/scripts/new-feature.sh +264 -16
- package/templates/skills/_shared/references/trust-model.md +18 -0
- package/templates/skills/assess/SKILL.md +250 -344
- package/templates/skills/assess/references/predicted-collision-detection.md +10 -7
- package/templates/skills/docs/SKILL.md +4 -4
- package/templates/skills/exec/SKILL.md +26 -6
- package/templates/skills/fullsolve/SKILL.md +4 -2
- package/templates/skills/loop/SKILL.md +38 -2
- package/templates/skills/merger/SKILL.md +2 -2
- package/templates/skills/qa/SKILL.md +337 -57
- package/templates/skills/qa/references/anti-pattern-detection.md +6 -6
- package/templates/skills/qa/references/call-site-review.md +2 -2
- package/templates/skills/qa/references/code-review-checklist.md +2 -2
- package/templates/skills/qa/references/fixtures/injection-issue-body.md +36 -0
- package/templates/skills/qa/references/quality-gates.md +21 -7
- package/templates/skills/qa/references/testing-requirements.md +1 -1
- package/templates/skills/qa/scripts/quality-checks.sh +11 -11
- package/templates/skills/reflect/SKILL.md +27 -13
- package/templates/skills/reflect/references/documentation-tiers.md +80 -68
- package/templates/skills/reflect/references/phase-reflection.md +31 -15
- package/templates/skills/release/SKILL.md +11 -3
- package/templates/skills/setup/SKILL.md +5 -5
- package/templates/skills/spec/SKILL.md +2 -0
- package/templates/skills/spec/references/verification-criteria.md +1 -1
- package/templates/skills/test/SKILL.md +1 -1
- package/dist/src/lib/phase-spinner.d.ts +0 -146
- package/dist/src/lib/phase-spinner.js +0 -255
- package/dist/src/lib/workflow/pr-operations.d.ts +0 -86
- package/dist/src/lib/workflow/pr-operations.js +0 -326
- package/dist/src/lib/workflow/run-summary.d.ts +0 -36
- package/dist/src/lib/workflow/run-summary.js +0 -142
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
{
|
|
9
9
|
"name": "sequant",
|
|
10
10
|
"description": "AI coding agent orchestrator for Claude Code — resolve GitHub issues end-to-end with isolated git worktrees, quality gates, and an MCP server. Includes 17 skills, workflow MCP tools, and pre/post-tool hooks.",
|
|
11
|
-
"version": "2.
|
|
11
|
+
"version": "2.10.0",
|
|
12
12
|
"author": {
|
|
13
13
|
"name": "sequant-io",
|
|
14
14
|
"email": "hello@sequant.io"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sequant",
|
|
3
3
|
"description": "AI coding agent orchestrator for Claude Code — resolve GitHub issues end-to-end with isolated git worktrees and quality gates, through spec → exec → qa phases.",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.10.0",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "sequant-io",
|
|
7
7
|
"email": "hello@sequant.io"
|
package/README.md
CHANGED
|
@@ -16,10 +16,24 @@ AI coding agents write code well, but leave you to run the workflow around it
|
|
|
16
16
|
|
|
17
17
|
See the [CHANGELOG](CHANGELOG.md) for release notes, or the [migration guide](CHANGELOG.md#migration-from-v1x) if upgrading from v1.x.
|
|
18
18
|
|
|
19
|
+
### What's new in 2.10
|
|
20
|
+
|
|
21
|
+
- **`--auto-wait <minutes>` rides out a rate-limit window** — opt in and a run whose limit window is hours out sleeps until it reopens and continues, instead of halting for a manual restart (#804). **Off by default**; the value is a *total* budget per issue, capped at 2 waits. Never waits on out-of-credits failures (credits are purchased, not waited out). The wait is in-process — for waits that must survive closing the terminal or a reboot, see halt-and-resume below; an exhausted `--auto-wait` budget still writes the halt record so `sequant resume` can pick up where it gave up. See [run-command.md](docs/reference/run-command.md#auto-wait-for-a-rate-limit-window).
|
|
22
|
+
- **Durable halt-and-resume + `sequant resume`** — a run that fails on an exhausted rate-limit window now writes a durable halt record (with its `resumeAt` time) and exits cleanly, releasing the per-issue lock. `sequant resume` re-enters after the window reopens, skipping completed phases and issues — safe to invoke from cron/launchd for unattended machines (recipes in [halt-and-resume.md](docs/reference/halt-and-resume.md)) (#892).
|
|
23
|
+
- **`--ready-gate` runs the post-QA ready gate inside `sequant run`** — opt in and, once an issue's standard phases succeed, `run` drives it through the same full-weight `qa → loop → qa` gate as `sequant ready` (to the configured `ready.policy`) **before** opening the PR, so the gate's fixes land in it. It automates the manual any-gaps/fix-gaps second look and **still stops at the human merge gate — it never merges** (#817). **Off by default**; without the flag the run path is unchanged (an `AC_MET_BUT_NOT_A_PLUS` verdict still breaks to PR per #749). Reuses `ready`'s policy, iteration cap, and stagnation guard — no new settings. See [run-command.md](docs/reference/run-command.md#ready-gate-post-qa-second-look).
|
|
24
|
+
- **`sequant merge --watch` waits for CI, then reports** — instead of polling checks by hand, `merge --watch` waits for each PR's CI checks to finish, then runs the merge-check and reports the result. It never merges (#818).
|
|
25
|
+
- **Stricter CLI contract for scripting** — malformed numeric flags (`--timeout 30m`, `--timeout abc`) are rejected with a clear error instead of silently coerced (#833, #845), and pre-flight rejections (uninitialized project, missing prerequisites) exit non-zero across `run`/`update`/`state`/`status`/`init` (#848). Runs terminated by a signal exit `128+signum` instead of `0` (#856).
|
|
26
|
+
|
|
27
|
+
### What's new in 2.9
|
|
28
|
+
|
|
29
|
+
- **`--chain` survives a failed link** — re-running a partially-completed chain resumes from its last good link, skipping the completed prefix and rebasing onto that committed tip instead of redoing hours of finished work (#760). A warn-by-default content pre-flight also runs before the first worktree is provisioned, flagging missing ACs, mis-ordered dependencies, predicted file overlaps, and closed issues; `--strict-preflight` makes any warning a hard stop (#762).
|
|
30
|
+
- **Rate limits stop burning hours** — a rate limit hit inside a phase now skips doomed cold-start retries, and the run summary labels the chain halt with its cause and how to resume, instead of cascading into a ~2h retry ladder (#761).
|
|
31
|
+
- **Stale plugin-cache warning** — `pre-tool.sh` now prints a once-per-day, network-free reminder (`claude plugin update sequant@sequant`) when a plugin-channel install has drifted behind the marketplace (#784, #788).
|
|
32
|
+
|
|
19
33
|
### What's new in 2.8
|
|
20
34
|
|
|
21
35
|
- **Clearer failures when an agent stops early** — phases that hit a turn cap now preserve their partial work and halt cleanly for resume instead of discarding it (#739, #733), and rate-limit/out-of-credits failures are named for what they are (with reset time and credit-purchase hints) rather than buried under generic retry noise (#732).
|
|
22
|
-
- **Runtime Node-version guard** — `sequant` checks the running Node against its `engines.node` floor (`>=22.
|
|
36
|
+
- **Runtime Node-version guard** — `sequant` checks the running Node against its `engines.node` floor (`>=22.13.0`) at startup and exits with a friendly upgrade message instead of crashing later on a Node-22-only API (#734).
|
|
23
37
|
- **`/assess` avoids npx version skew** — it now emits `sequant run …` when a global install is on `PATH` (and the unchanged `npx sequant run …` otherwise), so copy-pasted commands don't silently run a stale binary (#740).
|
|
24
38
|
|
|
25
39
|
### What's new in 2.7
|
|
@@ -42,14 +56,14 @@ See the [CHANGELOG](CHANGELOG.md) for release notes, or the [migration guide](CH
|
|
|
42
56
|
### Prerequisites
|
|
43
57
|
|
|
44
58
|
**An AI coding agent — one of:**
|
|
45
|
-
- [Claude Code](https://claude.ai/code) — default agent
|
|
59
|
+
- [Claude Code](https://claude.ai/code) — default agent. **Recommended: Claude Code ≥ 2.1.208.** The pre-tool hooks lean on Claude Code's native dangerous-`rm` analyzer (which fires even under `bypassPermissions`) instead of re-implementing catastrophic-delete detection; that analyzer's command-substitution coverage landed in 2.1.208. This is a recommendation, not an enforced floor — plugins cannot declare a minimum Claude Code version, so nothing gates install, and the pre-2.1.208 command-substitution gap (e.g. `echo "$(rm -rf ~)"`) is accepted rather than guarded.
|
|
46
60
|
- [Aider](https://aider.chat/) — alternative, via `--agent aider`
|
|
47
61
|
|
|
48
62
|
**Always required (both):**
|
|
49
63
|
- [GitHub CLI](https://cli.github.com/) — run `gh auth login`
|
|
50
64
|
- Git — for worktree-based isolation
|
|
51
65
|
|
|
52
|
-
**For the npm/CLI install path:** Node.js 22.
|
|
66
|
+
**For the npm/CLI install path:** Node.js 22.13+
|
|
53
67
|
|
|
54
68
|
**Optional MCP (Model Context Protocol) servers — enhanced features:**
|
|
55
69
|
- `chrome-devtools` — enables `/test` for browser-based UI testing
|
|
@@ -68,6 +82,8 @@ Pick the path that matches **where you run Sequant**:
|
|
|
68
82
|
/sequant:setup
|
|
69
83
|
```
|
|
70
84
|
|
|
85
|
+
> **Plugins do not auto-update.** Claude Code pins a plugin to the version you installed and never updates it on its own — even as new releases ship. To pick up a new version, run `claude plugin update sequant@sequant`, then restart Claude Code. Sequant's pre-tool hook warns once a day when your installed version falls behind the marketplace.
|
|
86
|
+
|
|
71
87
|
**Headless / CI (npm package)** — drive runs from the terminal or a CI job:
|
|
72
88
|
```bash
|
|
73
89
|
npm install sequant # or: pnpm add / yarn add / bun add sequant
|
|
@@ -75,6 +91,8 @@ npx sequant init # install skills into your project
|
|
|
75
91
|
npx sequant doctor # verify setup
|
|
76
92
|
```
|
|
77
93
|
|
|
94
|
+
> **Commit `.claude/skills/`.** It is a runtime dependency, not a cache: `sequant run` phase agents load skills from that directory only, so a checkout (or cleanup) that drops it breaks every run. `sequant run` pre-flights the directory and fails fast with the fix (`sequant sync`) if it is missing.
|
|
95
|
+
|
|
78
96
|
### Your first run
|
|
79
97
|
|
|
80
98
|
Inside Claude Code, solve an issue end-to-end:
|
|
@@ -228,7 +246,7 @@ Most work goes through a handful of top-level commands. The rest are either pipe
|
|
|
228
246
|
| `/assess <issues…>` | Triage one or more issues; emits a dashboard + ready-to-paste `run` commands (6-action vocabulary). |
|
|
229
247
|
| `npx sequant run <issues…>` | Headless equivalent of `/fullsolve`; batches run in parallel. Add `-Q` for the quality loop. |
|
|
230
248
|
| `/qa <issue>` | Code review + quality gate; posts findings as issue comments. |
|
|
231
|
-
| `npx sequant merge <issues…>` | Batch integration QA before merging. |
|
|
249
|
+
| `npx sequant merge <issues…>` | Batch integration QA before merging. Add `--watch` to wait for each PR's CI checks to finish (configurable `--interval`/`--timeout`), then run the checks and report — it never merges. |
|
|
232
250
|
|
|
233
251
|
### Pipeline internals
|
|
234
252
|
|
|
@@ -239,6 +257,7 @@ Most work goes through a handful of top-level commands. The rest are either pipe
|
|
|
239
257
|
| Command | What it does |
|
|
240
258
|
|---------|--------------|
|
|
241
259
|
| `sequant ready <issue>` | Post-resolve full-weight A+ QA gate; drives to merge-readiness, then stops at the human merge gate (never merges). |
|
|
260
|
+
| `sequant resume` | Re-enter runs halted on a rate-limit window once it reopens; no-op before `resumeAt`, so it is safe to schedule via cron/launchd. See [halt-and-resume.md](docs/reference/halt-and-resume.md). |
|
|
242
261
|
| `/merger` | Multi-issue merge coordination. |
|
|
243
262
|
| `/improve` | Codebase analysis and improvement discovery. |
|
|
244
263
|
| `/security-review` | Deep security analysis. |
|
package/dist/bin/cli.js
CHANGED
|
@@ -18,6 +18,7 @@ import { readFileSync } from "fs";
|
|
|
18
18
|
import { initCommand } from "../src/commands/init.js";
|
|
19
19
|
import { buildHomeStrayWarning, getInstallRoot, isHomeStrayInstall, isLocalNodeModulesInstall, } from "../src/lib/version-check.js";
|
|
20
20
|
import { configureUI, banner } from "../src/lib/cli-ui.js";
|
|
21
|
+
import { parseWholeNumber, parsePositiveSeconds, } from "../src/lib/cli-flags.js";
|
|
21
22
|
import { isCI, isStdoutTTY } from "../src/lib/tty.js";
|
|
22
23
|
import { detectPackageManagerSync, getPackageManagerCommands, } from "../src/lib/stacks.js";
|
|
23
24
|
// Read version from package.json dynamically
|
|
@@ -48,6 +49,7 @@ import { updateCommand } from "../src/commands/update.js";
|
|
|
48
49
|
import { doctorCommand } from "../src/commands/doctor.js";
|
|
49
50
|
import { statusCommand } from "../src/commands/status.js";
|
|
50
51
|
import { runCommand } from "../src/commands/run.js";
|
|
52
|
+
import { resumeCommand } from "../src/commands/resume.js";
|
|
51
53
|
import { logsCommand } from "../src/commands/logs.js";
|
|
52
54
|
import { statsCommand } from "../src/commands/stats.js";
|
|
53
55
|
import { dashboardCommand } from "../src/commands/dashboard.js";
|
|
@@ -60,6 +62,7 @@ import { locksListCommand, locksClearCommand, locksAcquireCommand, locksReleaseC
|
|
|
60
62
|
import { promptCommand } from "../src/commands/prompt.js";
|
|
61
63
|
import { watchCommand } from "../src/commands/watch.js";
|
|
62
64
|
import { abortCommand } from "../src/commands/abort.js";
|
|
65
|
+
import { assessRenderCommand } from "../src/commands/assess-render.js";
|
|
63
66
|
import { getManifest } from "../src/lib/manifest.js";
|
|
64
67
|
import { phaseRegistry } from "../src/lib/workflow/phase-registry.js";
|
|
65
68
|
/**
|
|
@@ -142,7 +145,7 @@ program
|
|
|
142
145
|
program
|
|
143
146
|
.command("sync")
|
|
144
147
|
.description("Sync skills and templates from the Sequant package (non-interactive)")
|
|
145
|
-
.option("-f, --force", "Sync even if versions match")
|
|
148
|
+
.option("-f, --force", "Sync even if versions match; also overwrites in-place customizations (e.g. the constitution)")
|
|
146
149
|
.option("-q, --quiet", "Suppress output")
|
|
147
150
|
.option("-d, --dry-run", "Show what sync would write without making changes (exits non-zero if work is pending)")
|
|
148
151
|
.action(syncCommand);
|
|
@@ -155,13 +158,13 @@ program
|
|
|
155
158
|
program
|
|
156
159
|
.command("status")
|
|
157
160
|
.description("Show Sequant version, configuration, and workflow state")
|
|
158
|
-
.argument("[issue]", "Issue number to show details for",
|
|
161
|
+
.argument("[issue]", "Issue number to show details for", parseWholeNumber("issue", { min: 1 }))
|
|
159
162
|
.option("--issues", "Show all tracked issues")
|
|
160
163
|
.option("--json", "Output as JSON")
|
|
161
164
|
.option("--rebuild", "Rebuild state from run logs")
|
|
162
165
|
.option("--cleanup", "Clean up stale/orphaned entries")
|
|
163
166
|
.option("--dry-run", "Preview cleanup without changes")
|
|
164
|
-
.option("--max-age <days>", "Remove entries older than N days",
|
|
167
|
+
.option("--max-age <days>", "Remove entries older than N days", parseWholeNumber("--max-age", { min: 1, unit: "days" }))
|
|
165
168
|
.option("--all", "Show all entries including expired; with --cleanup removes all orphaned")
|
|
166
169
|
.option("--offline", "Skip GitHub queries (pure local state)")
|
|
167
170
|
.action((issue, options) => {
|
|
@@ -179,7 +182,9 @@ program
|
|
|
179
182
|
.option("--sequential", "Stop on first issue failure (default: continue)")
|
|
180
183
|
.option("-d, --dry-run", "Preview without execution")
|
|
181
184
|
.option("-v, --verbose", "Verbose output with streaming")
|
|
182
|
-
|
|
185
|
+
// #833: `parseInt` here let `--timeout abc` reach `setTimeout` as `NaN`,
|
|
186
|
+
// which clamps to 0 and aborts every phase the moment it starts.
|
|
187
|
+
.option("--timeout <seconds>", "Timeout per phase in seconds", parsePositiveSeconds("--timeout"))
|
|
183
188
|
.option("--log-json", "Enable structured JSON logging (default: true)")
|
|
184
189
|
.option("--no-log", "Disable JSON logging for this run")
|
|
185
190
|
.option("--log-path <path>", "Custom log directory path")
|
|
@@ -189,25 +194,55 @@ program
|
|
|
189
194
|
// `runCommand` ORs `qualityLoopAlias` into `qualityLoop`. `-q` no longer maps
|
|
190
195
|
// to --quiet, which moved to `-s` to end the `-q`/`-Q` collision.
|
|
191
196
|
.addOption(new Option("-q, --quality-loop-alias", "Alias for -Q/--quality-loop").hideHelp())
|
|
192
|
-
|
|
197
|
+
// #833: a `NaN` bound makes `while (iteration < maxIterations)` in
|
|
198
|
+
// `batch-executor.ts` false on entry, so the issue silently runs zero phases.
|
|
199
|
+
.option("--max-iterations <n>", "Max iterations for quality loop (default: 3)", parseWholeNumber("--max-iterations", {
|
|
200
|
+
min: 1,
|
|
201
|
+
unit: "iterations",
|
|
202
|
+
unitSingular: "iteration",
|
|
203
|
+
}))
|
|
193
204
|
.option("--batch <issues>", 'Group of issues to run together (e.g., --batch "1 2" --batch "3")', (value, prev) => prev.concat([value]), [])
|
|
194
205
|
.option("--smart-tests", "Enable smart test detection (default)")
|
|
195
206
|
.option("--no-smart-tests", "Disable smart test detection")
|
|
196
207
|
.option("--testgen", "Run testgen phase after spec")
|
|
197
208
|
.option("--security-review", "Run security-review phase after spec")
|
|
198
209
|
.option("-s, --quiet", "Suppress version warnings and non-essential output (heartbeat-only)")
|
|
199
|
-
.option("--chain", "Chain issues: each
|
|
210
|
+
.option("--chain", "Chain issues: each successor is rebased onto the previous issue's committed work before it runs (implies --sequential)")
|
|
200
211
|
.option("--stacked", "Stack PRs: middle PRs target predecessor branch instead of main; first/last target main (implies --chain)")
|
|
201
|
-
|
|
212
|
+
// #795: deliberately a visible `.option()`, NOT `.hideHelp()` like
|
|
213
|
+
// `--experimental-tui` below. The two are different cases: `--qa-gate`
|
|
214
|
+
// shipped in #133 and was documented across four user-facing docs, so users
|
|
215
|
+
// need to find the deprecation notice; `--experimental-tui` was never
|
|
216
|
+
// advertised. A flag that still works but is absent from --help is the worst
|
|
217
|
+
// of both worlds — scripts keep passing it and nothing explains why to stop.
|
|
218
|
+
.option("--qa-gate", "DEPRECATED (#795): no-op, still accepted. --chain already halts on any failed issue, QA included")
|
|
219
|
+
.option("--strict-preflight", "Make --chain content pre-flight warnings (missing AC, dependency/overlap order, closed issues) fatal before any worktree is provisioned")
|
|
202
220
|
.option("--base <branch>", "Base branch for worktree creation (default: main or settings.run.defaultBase)")
|
|
203
221
|
.option("--no-mcp", "Disable MCP server injection in headless mode")
|
|
204
222
|
.option("--no-retry", "Disable automatic retry with MCP fallback (useful for debugging)")
|
|
223
|
+
.option("--auto-wait <minutes>", "Total minutes to wait for an exhausted rate-limit window to reopen instead of halting (default: 0, off)",
|
|
224
|
+
// #833: min 0 — #804 defines 0 as "off", so 0 is a meaningful value here
|
|
225
|
+
// and must keep parsing. `NaN` was silently coerced to 0 by
|
|
226
|
+
// `createAutoWaitLedger`, so `--auto-wait 30m` quietly bought 30 minutes.
|
|
227
|
+
parseWholeNumber("--auto-wait", {
|
|
228
|
+
min: 0,
|
|
229
|
+
unit: "minutes",
|
|
230
|
+
unitSingular: "minute",
|
|
231
|
+
}))
|
|
205
232
|
.option("--resume", "Resume from last completed phase (reads phase markers from GitHub)")
|
|
206
233
|
.option("--no-rebase", "Skip pre-PR rebase onto origin/main (use when you want to handle rebasing manually)")
|
|
207
234
|
.option("--no-pr", "Skip PR creation after successful QA (manual PR workflow)")
|
|
235
|
+
// #817: opt-in post-QA ready gate. Reuses the `sequant ready` engine and its
|
|
236
|
+
// bounds (policy from settings.ready.policy, iteration cap, stagnation guard,
|
|
237
|
+
// Non-Goals) — no new policy surface. Never merges; stops at the human gate.
|
|
238
|
+
.option("--ready-gate", "After phases succeed, run the post-QA ready gate (qa→loop→qa to the configured policy) — never merges, stops at the human merge gate")
|
|
208
239
|
.option("-f, --force", "Force re-execution of completed issues (bypass pre-flight state guard) and take over per-issue locks")
|
|
209
240
|
.option("--signal-other", "With --force, SIGTERM the prior PID holding the lock (same-host alive only)")
|
|
210
|
-
.option("--concurrency <n>", "Max concurrent issues in parallel mode (default: 3)",
|
|
241
|
+
.option("--concurrency <n>", "Max concurrent issues in parallel mode (default: 3)",
|
|
242
|
+
// #833: `run.ts` already rejects non-integers, but only after `parseInt`
|
|
243
|
+
// has silently turned `--concurrency 3x` into 3. Validating the raw string
|
|
244
|
+
// catches that; the downstream check stays as a programmatic backstop.
|
|
245
|
+
parseWholeNumber("--concurrency", { min: 1 }))
|
|
211
246
|
.option("--isolate-parallel", "Isolate parallel agent groups in separate worktrees (prevents file conflicts)")
|
|
212
247
|
.option("--reflect", "Analyze run results and suggest improvements")
|
|
213
248
|
.option("--agent <name>", 'Agent driver for phase execution (default: "claude-code")')
|
|
@@ -219,12 +254,26 @@ program
|
|
|
219
254
|
.addOption(new Option("--experimental-tui").hideHelp())
|
|
220
255
|
.option("--no-relay", "Disable interactive relay (#383); `sequant prompt` cannot reach this run")
|
|
221
256
|
.action(runCommand);
|
|
257
|
+
// Durable halt-and-resume re-entry (#892). Safe to invoke from cron/launchd:
|
|
258
|
+
// a no-op (exit 0) until a halted issue's `resumeAt` passes.
|
|
259
|
+
program
|
|
260
|
+
.command("resume")
|
|
261
|
+
.description("Re-enter runs halted on a rate-limit window (no-op until resumeAt; see docs/reference/halt-and-resume.md)")
|
|
262
|
+
.argument("[issues...]", "Issue numbers to resume (default: all halted)")
|
|
263
|
+
.option("-d, --dry-run", "Show what would be resumed without running")
|
|
264
|
+
// Arrow wrapper: commander passes the Command instance as a third
|
|
265
|
+
// positional, which must not land in resumeCommand's injectable deps param.
|
|
266
|
+
.action((issues, options) => resumeCommand(issues, options));
|
|
222
267
|
program
|
|
223
268
|
.command("prompt")
|
|
224
269
|
.description("Send a message into a running headless sequant session (#383)")
|
|
225
270
|
.argument("[args...]", '[<issue>] "<message>"')
|
|
226
271
|
.option("--type <type>", "Message type: query (default), directive, abort", "query")
|
|
227
|
-
.option("--wait <seconds>", "Block until a reply arrives or the timeout elapses (#645, Gap 4)",
|
|
272
|
+
.option("--wait <seconds>", "Block until a reply arrives or the timeout elapses (#645, Gap 4)", parseWholeNumber("--wait", {
|
|
273
|
+
min: 0,
|
|
274
|
+
unit: "seconds",
|
|
275
|
+
unitSingular: "second",
|
|
276
|
+
}))
|
|
228
277
|
.option("--json", "Output as JSON")
|
|
229
278
|
.action((args, options) => {
|
|
230
279
|
return promptCommand({
|
|
@@ -252,7 +301,15 @@ program
|
|
|
252
301
|
.description("Out-of-band abort: signal a running sequant session directly (#645)")
|
|
253
302
|
.argument("[issue]", "Issue number (auto-resolved when a single run is active)")
|
|
254
303
|
.option("--force", "Skip the SIGINT grace period; SIGTERM immediately")
|
|
255
|
-
.option("--grace <seconds>", "Seconds to wait after SIGINT before escalating (default: 10)",
|
|
304
|
+
.option("--grace <seconds>", "Seconds to wait after SIGINT before escalating (default: 10)",
|
|
305
|
+
// #833: min 0 — `--grace 0` means "escalate immediately" and is meaningful.
|
|
306
|
+
// `NaN` was worse than useless: `Math.max(0, NaN * 1000)` is `NaN`, so the
|
|
307
|
+
// grace period was skipped entirely and SIGTERM followed at once.
|
|
308
|
+
parseWholeNumber("--grace", {
|
|
309
|
+
min: 0,
|
|
310
|
+
unit: "seconds",
|
|
311
|
+
unitSingular: "second",
|
|
312
|
+
}))
|
|
256
313
|
.option("--json", "Output as JSON")
|
|
257
314
|
.action((issueArg, options) => {
|
|
258
315
|
const args = issueArg === undefined ? [] : [issueArg];
|
|
@@ -274,6 +331,9 @@ program
|
|
|
274
331
|
.option("--review", "Run Phase 1 + 2 + 3 AI briefing")
|
|
275
332
|
.option("--all", "Run all phases")
|
|
276
333
|
.option("--post", "Post report to GitHub as PR comments")
|
|
334
|
+
.option("--watch", "Poll each PR's CI checks until terminal, then run merge-check (never merges)")
|
|
335
|
+
.option("--interval <seconds>", "Watch poll interval in seconds (default 30)", parsePositiveSeconds("--interval"))
|
|
336
|
+
.option("--timeout <seconds>", "Watch give-up timeout in seconds (default 1800)", parsePositiveSeconds("--timeout"))
|
|
277
337
|
.option("--json", "Output as JSON")
|
|
278
338
|
.option("-v, --verbose", "Enable verbose output")
|
|
279
339
|
.action(mergeCommand);
|
|
@@ -282,13 +342,34 @@ program
|
|
|
282
342
|
.description("Post-resolve A+ QA gate — drive an issue to merge-readiness, then stop at the human merge gate (never merges)")
|
|
283
343
|
.argument("<issue>", "Issue number to drive to readiness")
|
|
284
344
|
.option("--policy <policy>", "Gate policy: 'ac' (default, stop at ACs met) or 'a-plus' (loop to READY_FOR_MERGE)")
|
|
285
|
-
.option("--max-iterations <n>", "Max QA passes before halting for human review (default: settings.run.maxIterations)",
|
|
286
|
-
|
|
287
|
-
|
|
345
|
+
.option("--max-iterations <n>", "Max QA passes before halting for human review (default: settings.run.maxIterations)",
|
|
346
|
+
// #833: `ready.ts` guards each of these three with `> 0`, so `NaN` already
|
|
347
|
+
// fell back to the default rather than reaching a timer. What it could not
|
|
348
|
+
// catch is the silent misparse — `--budget 10k` became 10, `--timeout 30m`
|
|
349
|
+
// became 30 seconds — and a fallback is not the same as telling the user.
|
|
350
|
+
parseWholeNumber("--max-iterations", {
|
|
351
|
+
min: 1,
|
|
352
|
+
unit: "iterations",
|
|
353
|
+
unitSingular: "iteration",
|
|
354
|
+
}))
|
|
355
|
+
.option("--budget <tokens>", "Token budget; halt cleanly with a 'needs human' message on exhaustion", parseWholeNumber("--budget", {
|
|
356
|
+
min: 1,
|
|
357
|
+
unit: "tokens",
|
|
358
|
+
unitSingular: "token",
|
|
359
|
+
}))
|
|
360
|
+
.option("--timeout <seconds>", "Timeout per phase in seconds", parsePositiveSeconds("--timeout"))
|
|
288
361
|
.option("--no-mcp", "Disable MCP server injection in headless mode")
|
|
289
362
|
.option("--json", "Output as JSON")
|
|
290
363
|
.option("-v, --verbose", "Enable verbose output")
|
|
291
364
|
.action((issue, options) => readyCommand(issue, options));
|
|
365
|
+
// #823: internal surface for the /assess skill, deliberately hidden from the
|
|
366
|
+
// top-level help — it takes a JSON payload no human hand-writes. `sequant
|
|
367
|
+
// assess-render --help` still works for debugging.
|
|
368
|
+
program
|
|
369
|
+
.command("assess-render", { hidden: true })
|
|
370
|
+
.description("(internal) Render an /assess AssessResult JSON payload to stdout")
|
|
371
|
+
.argument("<file>", "Path to an AssessResult JSON file")
|
|
372
|
+
.action(assessRenderCommand);
|
|
292
373
|
program
|
|
293
374
|
.command("conventions")
|
|
294
375
|
.description("View and manage codebase conventions")
|
|
@@ -300,9 +381,9 @@ program
|
|
|
300
381
|
.command("logs")
|
|
301
382
|
.description("View and analyze workflow run logs")
|
|
302
383
|
.option("-p, --path <path>", "Custom log directory path")
|
|
303
|
-
.option("-n, --last <n>", "Show last N runs",
|
|
384
|
+
.option("-n, --last <n>", "Show last N runs", parseWholeNumber("--last", { min: 1 }))
|
|
304
385
|
.option("--json", "Output as JSON")
|
|
305
|
-
.option("-i, --issue <number>", "Filter by issue number",
|
|
386
|
+
.option("-i, --issue <number>", "Filter by issue number", parseWholeNumber("--issue", { min: 1 }))
|
|
306
387
|
.option("--failed", "Show only failed runs")
|
|
307
388
|
.option("--rotate", "Rotate logs (delete oldest to meet thresholds)")
|
|
308
389
|
.option("-d, --dry-run", "Show what would be rotated without deleting")
|
|
@@ -321,7 +402,7 @@ program
|
|
|
321
402
|
program
|
|
322
403
|
.command("dashboard")
|
|
323
404
|
.description("Start visual workflow dashboard in browser")
|
|
324
|
-
.option("-p, --port <port>", "Port to run server on",
|
|
405
|
+
.option("-p, --port <port>", "Port to run server on", parseWholeNumber("--port", { min: 1 }))
|
|
325
406
|
.option("--no-open", "Don't automatically open browser")
|
|
326
407
|
.option("-v, --verbose", "Enable verbose logging")
|
|
327
408
|
.action(dashboardCommand);
|
|
@@ -329,7 +410,7 @@ program
|
|
|
329
410
|
.command("serve")
|
|
330
411
|
.description("Start MCP server for workflow orchestration")
|
|
331
412
|
.option("--transport <type>", "Transport type: stdio (default) or sse", "stdio")
|
|
332
|
-
.option("--port <port>", "Port for SSE transport (default: 3100)",
|
|
413
|
+
.option("--port <port>", "Port for SSE transport (default: 3100)", parseWholeNumber("--port", { min: 1 }))
|
|
333
414
|
.action(async (options) => {
|
|
334
415
|
const mod = await import("../src/commands/serve.js").catch(() => null);
|
|
335
416
|
if (!mod) {
|
|
@@ -363,7 +444,7 @@ stateCmd
|
|
|
363
444
|
.option("--json", "Output as JSON")
|
|
364
445
|
.option("-v, --verbose", "Enable verbose output")
|
|
365
446
|
.option("-d, --dry-run", "Preview cleanup without changes")
|
|
366
|
-
.option("--max-age <days>", "Remove entries older than N days",
|
|
447
|
+
.option("--max-age <days>", "Remove entries older than N days", parseWholeNumber("--max-age", { min: 1, unit: "days" }))
|
|
367
448
|
.option("--all", "Remove all orphaned entries (merged and abandoned)")
|
|
368
449
|
.action(stateCleanCommand);
|
|
369
450
|
// Per-issue concurrency locks (#625)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sequant",
|
|
3
3
|
"description": "AI coding agent orchestrator for Claude Code — resolve GitHub issues end-to-end with isolated git worktrees and quality gates, through spec → exec → qa phases.",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.10.0",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "sequant-io",
|
|
7
7
|
"email": "hello@sequant.io"
|
|
@@ -6,7 +6,7 @@ AI coding agent orchestrator for Claude Code — resolve GitHub issues end-to-en
|
|
|
6
6
|
|
|
7
7
|
- **Git** with a GitHub remote
|
|
8
8
|
- **GitHub CLI** (`gh`) authenticated (`gh auth status`)
|
|
9
|
-
- **Node.js 22.
|
|
9
|
+
- **Node.js 22.13+** (for MCP server via `npx`)
|
|
10
10
|
|
|
11
11
|
## Installation
|
|
12
12
|
|
|
@@ -20,6 +20,8 @@ Or browse in `/plugin > Discover`.
|
|
|
20
20
|
|
|
21
21
|
After installing, run `/sequant:setup` to configure your project.
|
|
22
22
|
|
|
23
|
+
> **Plugins do not auto-update.** Claude Code pins a plugin to the version you installed. To pick up a new release, run `claude plugin update sequant@sequant`, then restart Claude Code.
|
|
24
|
+
|
|
23
25
|
### npm (power users / CI)
|
|
24
26
|
|
|
25
27
|
```bash
|
|
@@ -29,7 +31,7 @@ sequant init
|
|
|
29
31
|
|
|
30
32
|
## What You Get
|
|
31
33
|
|
|
32
|
-
###
|
|
34
|
+
### 19 Workflow Skills
|
|
33
35
|
|
|
34
36
|
| Skill | Purpose |
|
|
35
37
|
|-------|---------|
|
|
@@ -49,6 +51,8 @@ sequant init
|
|
|
49
51
|
| `/security-review` | Deep security analysis |
|
|
50
52
|
| `/solve` | Generate the recommended workflow for one or more issues |
|
|
51
53
|
| `/merger` | Multi-issue integration and merge |
|
|
54
|
+
| `/release` | Version bump, git tag, GitHub release, npm publish |
|
|
55
|
+
| `/upstream` | Monitor Claude Code releases for breaking changes |
|
|
52
56
|
| `/setup` | Project initialization for plugin users |
|
|
53
57
|
|
|
54
58
|
### MCP Tools (automatic with plugin)
|
|
@@ -81,6 +85,58 @@ sequant ready # Boxed pre-flight: which issues are ready to run?
|
|
|
81
85
|
|
|
82
86
|
See the [`sequant ready` command reference](https://github.com/sequant-io/sequant/blob/main/docs/reference/ready-command.md) for the full pre-flight readiness check.
|
|
83
87
|
|
|
88
|
+
## Riding out a rate-limit window
|
|
89
|
+
|
|
90
|
+
By default, a rate limit whose window reopens hours from now halts the run, so a multi-hour job needs a manual restart. `--auto-wait <minutes>` opts into waiting instead:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
sequant run 42 --auto-wait 360 # wait up to 6 hours total for the window to reopen
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
- **Off by default** (`0`) — the halt behavior is unchanged unless you ask for the wait.
|
|
97
|
+
- The value is a **total** budget per issue, not per occurrence, capped at 2 waits.
|
|
98
|
+
- **Never waits on out-of-credits failures** — credits are purchased, not waited out. (These do carry a reset timestamp, so the gate is the error type, not the timestamp.)
|
|
99
|
+
- The wait is shown live and Ctrl-C ends it promptly.
|
|
100
|
+
- **In-process only: it does not survive closing the terminal** — for waits that must survive a closed terminal or reboot, use halt-and-resume below.
|
|
101
|
+
- Worktree and issue locks are held throughout — deliberate, since Claude rate limits are account-wide and no other run could progress during the window anyway.
|
|
102
|
+
|
|
103
|
+
Also settable as `run.autoWaitMinutes` or `SEQUANT_AUTO_WAIT_MINUTES`. Full details in the [run command reference](https://github.com/sequant-io/sequant/blob/main/docs/reference/run-command.md#auto-wait-for-a-rate-limit-window).
|
|
104
|
+
|
|
105
|
+
### Durable recovery: `sequant resume`
|
|
106
|
+
|
|
107
|
+
Without `--auto-wait` (or once its budget is exhausted), a run that fails on a waitable rate-limit window writes a durable halt record with its reset time and exits cleanly, releasing the per-issue lock. `sequant resume` re-enters after the window reopens, skipping completed phases and issues — safe to invoke repeatedly, so a single cron/launchd entry handles unattended machines. Recipes and full mechanics in the [halt-and-resume reference](https://github.com/sequant-io/sequant/blob/main/docs/reference/halt-and-resume.md).
|
|
108
|
+
|
|
109
|
+
## Wait for CI, then verify (`merge --watch`)
|
|
110
|
+
|
|
111
|
+
`sequant merge <issue> --watch` kills the "merge after green" polling loop: it waits for the PR's CI checks to finish before running merge-check, so the verdict is real the moment the command exits.
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
sequant merge 818 --watch # poll CI to terminal, then run merge-check
|
|
115
|
+
sequant merge 818 --watch --scan --post # composes with depth flags and --post
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
- **It never merges** — `--watch` only decides _when_ the existing report runs; the human merge gate stays.
|
|
119
|
+
- **Foreground only** — a plain poll loop, no daemon or OS notifications. Chain on the exit code to notify yourself.
|
|
120
|
+
- **Configurable** `--interval <seconds>` (default 30) and `--timeout <seconds>` (default 1800); a timeout exits with a distinct code (3).
|
|
121
|
+
- **Dispatch blocks short-circuit to BLOCKED** with the cause — merge conflicts (`CONFLICTING`), zero checks after a dispatch block, and a runner-never-started billing lockout — instead of polling until timeout.
|
|
122
|
+
|
|
123
|
+
Full details in the [merge command reference](https://github.com/sequant-io/sequant/blob/main/docs/reference/merge-command.md).
|
|
124
|
+
|
|
125
|
+
## Running the ready gate inside `run`
|
|
126
|
+
|
|
127
|
+
`--ready-gate` opts a `sequant run` into the same post-QA gate as `sequant ready`, without the second manual command — it automates the habitual any-gaps → fix-gaps second look:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
sequant run 42 --ready-gate # phases, then the gate, then a PR — never merges
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
- **Off by default** — without the flag the run path is unchanged.
|
|
134
|
+
- Once the standard phases pass, the gate runs a full-weight `qa → loop → qa` pass (to `ready.policy`) **before** the PR opens, so its fixes land in the PR.
|
|
135
|
+
- **It never merges.** The run stops at the human merge gate with the issue `waiting_for_human_merge` (threshold reached) or `blocked` (a guard halted it).
|
|
136
|
+
- Reuses `ready`'s policy, iteration cap, and stagnation guard — **no new settings**.
|
|
137
|
+
|
|
138
|
+
Full details in the [run command reference](https://github.com/sequant-io/sequant/blob/main/docs/reference/run-command.md#ready-gate-post-qa-second-look).
|
|
139
|
+
|
|
84
140
|
## Documentation
|
|
85
141
|
|
|
86
142
|
- [Getting Started](https://github.com/sequant-io/sequant/tree/main/docs/getting-started)
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Shared naming contract for /exec parallel-group marker files (#881).
|
|
3
|
+
#
|
|
4
|
+
# One writer (the /exec skill) and two readers (pre-tool.sh, post-tool.sh) must
|
|
5
|
+
# agree on (a) the marker filename and (b) how the owning project is identified.
|
|
6
|
+
# Before #881 the filename was a global constant, so a parallel group in ONE
|
|
7
|
+
# project silently redirected worktree enforcement for EVERY concurrent Claude
|
|
8
|
+
# session on the machine — the first matching marker in the shared temp dir won,
|
|
9
|
+
# regardless of which project wrote it. Keeping the scheme in this single sourced
|
|
10
|
+
# file is what stops the writer and the readers from drifting apart (AC-4).
|
|
11
|
+
#
|
|
12
|
+
# Marker filename: ${TMPDIR}/claude-parallel-<project-hash>-<group-id>.marker
|
|
13
|
+
# Marker contents: line 1 = worktree path, line 2 = owning project root.
|
|
14
|
+
|
|
15
|
+
# parallel_marker_project_root — the canonical identity of the current project,
|
|
16
|
+
# derived identically in skill-context and hook-context. CLAUDE_PROJECT_DIR is
|
|
17
|
+
# set by Claude Code for both the skill's shell and the hook's shell within the
|
|
18
|
+
# same session; the git-toplevel fallback resolves to the same worktree when it
|
|
19
|
+
# is unset. A mismatch here would silently re-introduce the cross-project
|
|
20
|
+
# collision this fix exists to close, so the two contexts MUST agree.
|
|
21
|
+
parallel_marker_project_root() {
|
|
22
|
+
if [[ -n "${CLAUDE_PROJECT_DIR:-}" ]]; then
|
|
23
|
+
printf '%s' "$CLAUDE_PROJECT_DIR"
|
|
24
|
+
else
|
|
25
|
+
git rev-parse --show-toplevel 2>/dev/null || printf '%s' "$PWD"
|
|
26
|
+
fi
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
# parallel_marker_hash — a stable per-project hash used in the marker filename so
|
|
30
|
+
# two projects running parallel groups at once cannot collide (AC-1). Reuses the
|
|
31
|
+
# md5-with-md5sum-fallback idiom already used for the per-file lock in
|
|
32
|
+
# pre-tool.sh. printf (no trailing newline) keeps writer and reader identical.
|
|
33
|
+
parallel_marker_hash() {
|
|
34
|
+
local root
|
|
35
|
+
root="$(parallel_marker_project_root)"
|
|
36
|
+
printf '%s' "$root" | md5 -q 2>/dev/null || printf '%s' "$root" | md5sum | cut -d' ' -f1
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
# parallel_marker_prefix — the ${TMPDIR}-anchored, project-scoped filename prefix
|
|
40
|
+
# that both the writer and the readers glob on (AC-2). Honors $TMPDIR (macOS's
|
|
41
|
+
# per-user temp) with a /tmp fallback, matching the hooks' own _TMPDIR.
|
|
42
|
+
parallel_marker_prefix() {
|
|
43
|
+
local tmp="${TMPDIR:-/tmp}"
|
|
44
|
+
printf '%s/claude-parallel-%s-' "$tmp" "$(parallel_marker_hash)"
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
# parallel_marker_path <group-id> — the full marker path for one group.
|
|
48
|
+
parallel_marker_path() {
|
|
49
|
+
printf '%s%s.marker' "$(parallel_marker_prefix)" "$1"
|
|
50
|
+
}
|
|
@@ -51,33 +51,61 @@ fi
|
|
|
51
51
|
|
|
52
52
|
_TMPDIR="${TMPDIR:-/tmp}"
|
|
53
53
|
|
|
54
|
-
#
|
|
55
|
-
|
|
54
|
+
# Log sink (#763 AC-5c: blocked-command history must survive to be a useful
|
|
55
|
+
# regression corpus, so $TMPDIR — which macOS purges — is a last resort only).
|
|
56
|
+
#
|
|
57
|
+
# This block MUST stay identical to the one in pre-tool.sh. The two hooks
|
|
58
|
+
# write the *same* claude-timing.log (START there, END here) and the same
|
|
59
|
+
# claude-quality.log, so any divergence silently splits every START/END pair
|
|
60
|
+
# across two files.
|
|
61
|
+
#
|
|
62
|
+
# Every candidate is absolute and lives outside the repo. A repo-local or
|
|
63
|
+
# relative path is wrong three times over: it resolves against the hook's cwd
|
|
64
|
+
# (which Claude Code does not pin), it yields one sink per directory instead
|
|
65
|
+
# of the single corpus AC-5 asks for, and — worst — creating it inside a repo
|
|
66
|
+
# makes `git status --porcelain` non-empty, which silently defeats pre-tool.sh's
|
|
67
|
+
# no-changes guard that reads exactly that output.
|
|
68
|
+
if [[ -n "${CLAUDE_PLUGIN_DATA:-}" ]]; then
|
|
56
69
|
_LOG_DIR="${CLAUDE_PLUGIN_DATA}/logs"
|
|
57
|
-
|
|
70
|
+
elif [[ -n "${HOME:-}" ]]; then
|
|
71
|
+
_LOG_DIR="${HOME}/.sequant/logs"
|
|
58
72
|
else
|
|
59
73
|
_LOG_DIR="${_TMPDIR}"
|
|
60
74
|
fi
|
|
75
|
+
mkdir -p "$_LOG_DIR" 2>/dev/null || _LOG_DIR="${_TMPDIR}"
|
|
61
76
|
|
|
62
77
|
TIMING_LOG="${_LOG_DIR}/claude-timing.log"
|
|
63
78
|
QUALITY_LOG="${_LOG_DIR}/claude-quality.log"
|
|
64
79
|
TESTS_LOG="${_LOG_DIR}/claude-tests.log"
|
|
65
|
-
|
|
80
|
+
|
|
81
|
+
# Parallel-group marker naming (#881). Source the shared helper next to this
|
|
82
|
+
# hook so the project-scoped prefix stays identical to the writer and pre-tool.sh.
|
|
83
|
+
_MARKER_HELPER="$(dirname "${BASH_SOURCE[0]:-$0}")/parallel-marker.sh"
|
|
84
|
+
if [[ -f "$_MARKER_HELPER" ]]; then
|
|
85
|
+
# shellcheck source=parallel-marker.sh disable=SC1091
|
|
86
|
+
source "$_MARKER_HELPER"
|
|
87
|
+
PARALLEL_MARKER_PREFIX="$(parallel_marker_prefix)"
|
|
88
|
+
else
|
|
89
|
+
PARALLEL_MARKER_PREFIX="${_TMPDIR}/claude-parallel-"
|
|
90
|
+
fi
|
|
66
91
|
|
|
67
92
|
# === AGENT ID DETECTION ===
|
|
68
|
-
# For parallel agents, detect group ID from marker files
|
|
69
|
-
#
|
|
93
|
+
# For parallel agents, detect group ID from marker files. The glob is scoped to
|
|
94
|
+
# the current project's marker prefix (#881) so a foreign project's marker never
|
|
95
|
+
# labels this session's timing rows.
|
|
70
96
|
AGENT_ID=""
|
|
71
97
|
IS_PARALLEL_AGENT="false"
|
|
98
|
+
_MARKER_BASE=$(basename "$PARALLEL_MARKER_PREFIX")
|
|
72
99
|
# Find marker files using find (works in both bash and zsh)
|
|
73
100
|
while IFS= read -r marker; do
|
|
74
101
|
if [[ -n "$marker" && -f "$marker" ]]; then
|
|
75
|
-
# Extract group ID
|
|
76
|
-
AGENT_ID=$(basename "$marker"
|
|
102
|
+
# Extract group ID: strip the project-scoped prefix and the suffix.
|
|
103
|
+
AGENT_ID=$(basename "$marker" .marker)
|
|
104
|
+
AGENT_ID=${AGENT_ID#"$_MARKER_BASE"}
|
|
77
105
|
IS_PARALLEL_AGENT="true"
|
|
78
106
|
break
|
|
79
107
|
fi
|
|
80
|
-
done < <(find "${_TMPDIR}" -maxdepth 1 -name "
|
|
108
|
+
done < <(find "${_TMPDIR}" -maxdepth 1 -name "${_MARKER_BASE}*.marker" 2>/dev/null)
|
|
81
109
|
|
|
82
110
|
# === TIMING END ===
|
|
83
111
|
# Include agent ID in log format if available (AC-4)
|
|
@@ -238,7 +266,7 @@ if [[ "${CLAUDE_HOOKS_COVERAGE:-}" == "true" ]]; then
|
|
|
238
266
|
COVERAGE_LOG="${_LOG_DIR}/claude-coverage.log"
|
|
239
267
|
|
|
240
268
|
# Get changed source files (excluding tests)
|
|
241
|
-
changed_files=$(git diff main...HEAD --name-only 2>/dev/null | grep -E '\.(ts|tsx|js|jsx)$' | grep -v -E '\.test\.|\.spec\.|__tests__' || true)
|
|
269
|
+
changed_files=$(git diff origin/main...HEAD --name-only 2>/dev/null | grep -E '\.(ts|tsx|js|jsx)$' | grep -v -E '\.test\.|\.spec\.|__tests__' || true)
|
|
242
270
|
|
|
243
271
|
if [[ -n "$changed_files" ]]; then
|
|
244
272
|
echo "$(date +%H:%M:%S) COVERAGE_ANALYSIS: Checking test coverage for changed files" >> "$QUALITY_LOG"
|