sequant 2.9.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 +14 -3
- package/dist/bin/cli.js +97 -17
- 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 +56 -2
- package/dist/marketplace/external_plugins/sequant/hooks/parallel-marker.sh +50 -0
- package/dist/marketplace/external_plugins/sequant/hooks/post-tool.sh +20 -7
- package/dist/marketplace/external_plugins/sequant/hooks/pre-tool.sh +75 -10
- package/dist/marketplace/external_plugins/sequant/skills/_shared/references/trust-model.md +18 -0
- package/dist/marketplace/external_plugins/sequant/skills/assess/SKILL.md +215 -390
- package/dist/marketplace/external_plugins/sequant/skills/assess/references/predicted-collision-detection.md +1 -1
- 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 +3 -1
- 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/release/SKILL.md +1 -1
- 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/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 +14 -5
- 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.js +37 -4
- 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/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/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 +62 -0
- package/dist/src/lib/errors.d.ts +78 -6
- package/dist/src/lib/errors.js +133 -15
- 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/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 +45 -2
- package/dist/src/lib/workflow/batch-executor.d.ts +125 -6
- package/dist/src/lib/workflow/batch-executor.js +477 -44
- package/dist/src/lib/workflow/chain-resume.d.ts +13 -11
- package/dist/src/lib/workflow/chain-resume.js +24 -20
- 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/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 +14 -0
- package/dist/src/lib/workflow/drivers/claude-code.js +20 -2
- 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 +75 -6
- package/dist/src/lib/workflow/metrics-schema.d.ts +3 -3
- package/dist/src/lib/workflow/phase-executor.d.ts +203 -14
- package/dist/src/lib/workflow/phase-executor.js +457 -52
- 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 +14 -0
- package/dist/src/lib/workflow/run-log-schema.js +47 -1
- package/dist/src/lib/workflow/run-orchestrator.d.ts +19 -0
- package/dist/src/lib/workflow/run-orchestrator.js +141 -20
- 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/types.d.ts +126 -4
- package/dist/src/lib/workflow/types.js +1 -0
- package/dist/src/lib/workflow/worktree-manager.d.ts +28 -2
- package/dist/src/lib/workflow/worktree-manager.js +102 -23
- package/dist/src/mcp/tools/run.d.ts +9 -1
- package/dist/src/mcp/tools/run.js +20 -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 +8 -7
- package/templates/hooks/parallel-marker.sh +50 -0
- package/templates/hooks/post-tool.sh +20 -7
- package/templates/hooks/pre-tool.sh +75 -10
- package/templates/scripts/cleanup-worktree.sh +182 -19
- package/templates/scripts/new-feature.sh +264 -16
- package/templates/skills/_shared/references/trust-model.md +18 -0
- package/templates/skills/assess/SKILL.md +215 -390
- package/templates/skills/assess/references/predicted-collision-detection.md +1 -1
- package/templates/skills/docs/SKILL.md +4 -4
- package/templates/skills/exec/SKILL.md +26 -6
- package/templates/skills/fullsolve/SKILL.md +3 -1
- 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/release/SKILL.md +1 -1
- package/templates/skills/setup/SKILL.md +5 -5
- package/templates/skills/spec/SKILL.md +2 -0
- 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
|
@@ -20,6 +20,36 @@
|
|
|
20
20
|
* shutdown.dispose();
|
|
21
21
|
* ```
|
|
22
22
|
*/
|
|
23
|
+
/**
|
|
24
|
+
* Why the process is shutting down, handed to every cleanup task so they can
|
|
25
|
+
* record the cause rather than silently persisting a truncated record (#856).
|
|
26
|
+
*/
|
|
27
|
+
export interface AbortContext {
|
|
28
|
+
/** Signal that triggered the shutdown, e.g. `SIGTERM`. */
|
|
29
|
+
signal: string;
|
|
30
|
+
/** Human-readable cause, from `describeSignalCause`. */
|
|
31
|
+
reason: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Conventional shell exit code for death-by-signal: `128 + signum`
|
|
35
|
+
* (SIGINT → 130, SIGTERM → 143). Falls back to 1 for anything unmapped.
|
|
36
|
+
*
|
|
37
|
+
* #856: this used to be a flat `0`. A run killed from outside therefore
|
|
38
|
+
* exited *successfully*, so nothing downstream — CI, a wrapping script, the
|
|
39
|
+
* user reading `$?` — could tell a completed run from a terminated one.
|
|
40
|
+
*/
|
|
41
|
+
export declare function exitCodeForSignal(signal: string): number;
|
|
42
|
+
/**
|
|
43
|
+
* Human-readable cause for a termination signal (#856, AC-4).
|
|
44
|
+
*
|
|
45
|
+
* SIGINT is the user pressing Ctrl+C — self-explanatory. SIGTERM is not:
|
|
46
|
+
* no interactive user sends it by hand, so it always means something else
|
|
47
|
+
* killed the run, and the user needs to be told that rather than left to
|
|
48
|
+
* infer it from truncated output. The known offender on macOS is Claude
|
|
49
|
+
* Code's `[bg-pty]` host-dead watchdog, which group-SIGKILLs a process tree
|
|
50
|
+
* containing the run; see `docs/incidents/856/`.
|
|
51
|
+
*/
|
|
52
|
+
export declare function describeSignalCause(signal: string): string;
|
|
23
53
|
/**
|
|
24
54
|
* Options for ShutdownManager
|
|
25
55
|
*/
|
|
@@ -46,6 +76,8 @@ export interface ShutdownManagerOptions {
|
|
|
46
76
|
export declare class ShutdownManager {
|
|
47
77
|
private cleanupTasks;
|
|
48
78
|
private _isShuttingDown;
|
|
79
|
+
/** Cause of the in-progress shutdown; null until a signal arrives (#856). */
|
|
80
|
+
private _abortContext;
|
|
49
81
|
/** Active abort controllers — supports concurrent phase execution (#404) */
|
|
50
82
|
private abortControllers;
|
|
51
83
|
private forceExitTimeout;
|
|
@@ -63,6 +95,12 @@ export declare class ShutdownManager {
|
|
|
63
95
|
* Alias for isShuttingDown (matches proposed API)
|
|
64
96
|
*/
|
|
65
97
|
get shuttingDown(): boolean;
|
|
98
|
+
/**
|
|
99
|
+
* Why the process is shutting down, or `null` if it isn't (#856).
|
|
100
|
+
* Lets code outside a cleanup task — e.g. a `finally` block that also
|
|
101
|
+
* finalizes state — record the same cause the cleanup tasks saw.
|
|
102
|
+
*/
|
|
103
|
+
get abortContext(): AbortContext | null;
|
|
66
104
|
/**
|
|
67
105
|
* Register an abort controller for a running phase.
|
|
68
106
|
*
|
|
@@ -91,9 +129,11 @@ export declare class ShutdownManager {
|
|
|
91
129
|
* This allows dependent cleanup to happen in correct order.
|
|
92
130
|
*
|
|
93
131
|
* @param name - Human-readable name for user feedback
|
|
94
|
-
* @param task - Async function to execute during cleanup
|
|
132
|
+
* @param task - Async function to execute during cleanup. Receives the
|
|
133
|
+
* `AbortContext` when the shutdown was signal-triggered, or `null` on a
|
|
134
|
+
* programmatic teardown. Tasks that don't care may ignore the argument.
|
|
95
135
|
*/
|
|
96
|
-
registerCleanup(name: string, task: () => Promise<void>): void;
|
|
136
|
+
registerCleanup(name: string, task: (abort: AbortContext | null) => Promise<void>): void;
|
|
97
137
|
/**
|
|
98
138
|
* Unregister a cleanup task by name
|
|
99
139
|
*
|
package/dist/src/lib/shutdown.js
CHANGED
|
@@ -21,6 +21,43 @@
|
|
|
21
21
|
* ```
|
|
22
22
|
*/
|
|
23
23
|
import chalk from "chalk";
|
|
24
|
+
/** POSIX signal numbers for the signals we install handlers for. */
|
|
25
|
+
const SIGNAL_NUMBERS = {
|
|
26
|
+
SIGINT: 2,
|
|
27
|
+
SIGTERM: 15,
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Conventional shell exit code for death-by-signal: `128 + signum`
|
|
31
|
+
* (SIGINT → 130, SIGTERM → 143). Falls back to 1 for anything unmapped.
|
|
32
|
+
*
|
|
33
|
+
* #856: this used to be a flat `0`. A run killed from outside therefore
|
|
34
|
+
* exited *successfully*, so nothing downstream — CI, a wrapping script, the
|
|
35
|
+
* user reading `$?` — could tell a completed run from a terminated one.
|
|
36
|
+
*/
|
|
37
|
+
export function exitCodeForSignal(signal) {
|
|
38
|
+
const num = SIGNAL_NUMBERS[signal];
|
|
39
|
+
return num === undefined ? 1 : 128 + num;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Human-readable cause for a termination signal (#856, AC-4).
|
|
43
|
+
*
|
|
44
|
+
* SIGINT is the user pressing Ctrl+C — self-explanatory. SIGTERM is not:
|
|
45
|
+
* no interactive user sends it by hand, so it always means something else
|
|
46
|
+
* killed the run, and the user needs to be told that rather than left to
|
|
47
|
+
* infer it from truncated output. The known offender on macOS is Claude
|
|
48
|
+
* Code's `[bg-pty]` host-dead watchdog, which group-SIGKILLs a process tree
|
|
49
|
+
* containing the run; see `docs/incidents/856/`.
|
|
50
|
+
*/
|
|
51
|
+
export function describeSignalCause(signal) {
|
|
52
|
+
switch (signal) {
|
|
53
|
+
case "SIGINT":
|
|
54
|
+
return "interrupted by user (Ctrl+C)";
|
|
55
|
+
case "SIGTERM":
|
|
56
|
+
return "terminated by an external SIGTERM (not sent by sequant)";
|
|
57
|
+
default:
|
|
58
|
+
return `terminated by ${signal}`;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
24
61
|
/**
|
|
25
62
|
* Manages graceful shutdown for sequant run
|
|
26
63
|
*
|
|
@@ -34,6 +71,8 @@ import chalk from "chalk";
|
|
|
34
71
|
export class ShutdownManager {
|
|
35
72
|
cleanupTasks = [];
|
|
36
73
|
_isShuttingDown = false;
|
|
74
|
+
/** Cause of the in-progress shutdown; null until a signal arrives (#856). */
|
|
75
|
+
_abortContext = null;
|
|
37
76
|
/** Active abort controllers — supports concurrent phase execution (#404) */
|
|
38
77
|
abortControllers = new Set();
|
|
39
78
|
forceExitTimeout;
|
|
@@ -67,6 +106,14 @@ export class ShutdownManager {
|
|
|
67
106
|
get shuttingDown() {
|
|
68
107
|
return this._isShuttingDown;
|
|
69
108
|
}
|
|
109
|
+
/**
|
|
110
|
+
* Why the process is shutting down, or `null` if it isn't (#856).
|
|
111
|
+
* Lets code outside a cleanup task — e.g. a `finally` block that also
|
|
112
|
+
* finalizes state — record the same cause the cleanup tasks saw.
|
|
113
|
+
*/
|
|
114
|
+
get abortContext() {
|
|
115
|
+
return this._abortContext;
|
|
116
|
+
}
|
|
70
117
|
/**
|
|
71
118
|
* Register an abort controller for a running phase.
|
|
72
119
|
*
|
|
@@ -104,7 +151,9 @@ export class ShutdownManager {
|
|
|
104
151
|
* This allows dependent cleanup to happen in correct order.
|
|
105
152
|
*
|
|
106
153
|
* @param name - Human-readable name for user feedback
|
|
107
|
-
* @param task - Async function to execute during cleanup
|
|
154
|
+
* @param task - Async function to execute during cleanup. Receives the
|
|
155
|
+
* `AbortContext` when the shutdown was signal-triggered, or `null` on a
|
|
156
|
+
* programmatic teardown. Tasks that don't care may ignore the argument.
|
|
108
157
|
*/
|
|
109
158
|
registerCleanup(name, task) {
|
|
110
159
|
this.cleanupTasks.push({ name, task });
|
|
@@ -138,6 +187,13 @@ export class ShutdownManager {
|
|
|
138
187
|
return;
|
|
139
188
|
}
|
|
140
189
|
this._isShuttingDown = true;
|
|
190
|
+
// #856 AC-4: name the cause up front. A truncated run whose last words
|
|
191
|
+
// were "shutting down gracefully" reads as an orderly stop; it isn't one.
|
|
192
|
+
const abort = {
|
|
193
|
+
signal,
|
|
194
|
+
reason: describeSignalCause(signal),
|
|
195
|
+
};
|
|
196
|
+
this._abortContext = abort;
|
|
141
197
|
this.output(chalk.yellow(`\n! Received ${signal}, shutting down gracefully...`));
|
|
142
198
|
// Abort all in-flight phases immediately
|
|
143
199
|
if (this.abortControllers.size > 0) {
|
|
@@ -157,7 +213,7 @@ export class ShutdownManager {
|
|
|
157
213
|
const tasksToRun = [...this.cleanupTasks].reverse();
|
|
158
214
|
for (const { name, task } of tasksToRun) {
|
|
159
215
|
try {
|
|
160
|
-
await task();
|
|
216
|
+
await task(abort);
|
|
161
217
|
this.output(chalk.green(`✓ ${name}`));
|
|
162
218
|
}
|
|
163
219
|
catch (err) {
|
|
@@ -166,9 +222,22 @@ export class ShutdownManager {
|
|
|
166
222
|
}
|
|
167
223
|
}
|
|
168
224
|
clearTimeout(forceExitTimer);
|
|
169
|
-
//
|
|
170
|
-
|
|
171
|
-
|
|
225
|
+
// #856 AC-4: report the abort AS an abort, with its cause and a non-zero
|
|
226
|
+
// exit code. The old banner ("Interrupted. Cleanup complete.") plus
|
|
227
|
+
// `exit(0)` made an externally-killed run indistinguishable from a
|
|
228
|
+
// successful one — and because this path exits the process, the normal
|
|
229
|
+
// `displaySummary` / `abortReason` rendering in run-display.ts is never
|
|
230
|
+
// reached, so this banner is the only thing the user sees.
|
|
231
|
+
const code = exitCodeForSignal(signal);
|
|
232
|
+
this.errorOutput(chalk.red(`\n✗ Run aborted — ${abort.reason}.`));
|
|
233
|
+
this.output(chalk.yellow(` Cleanup completed. No phase results beyond this point were recorded.`));
|
|
234
|
+
if (signal === "SIGTERM") {
|
|
235
|
+
this.output(chalk.gray(` sequant does not send itself SIGTERM. If this run was launched as a\n` +
|
|
236
|
+
` backgrounded task inside an interactive Claude Code session, see\n` +
|
|
237
|
+
` docs/incidents/856/ — relaunch from a plain terminal instead.`));
|
|
238
|
+
}
|
|
239
|
+
this.output(chalk.gray(` Exit code: ${code}`));
|
|
240
|
+
this.exit(code);
|
|
172
241
|
}
|
|
173
242
|
/**
|
|
174
243
|
* Remove signal handlers and clean up
|
|
@@ -181,6 +250,7 @@ export class ShutdownManager {
|
|
|
181
250
|
process.removeListener("SIGTERM", this.sigtermHandler);
|
|
182
251
|
this.cleanupTasks = [];
|
|
183
252
|
this.abortControllers.clear();
|
|
253
|
+
this._abortContext = null;
|
|
184
254
|
}
|
|
185
255
|
}
|
|
186
256
|
/**
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skills installation check — single source of truth for the
|
|
3
|
+
* `.claude/skills/<skill>/SKILL.md` layout.
|
|
4
|
+
*
|
|
5
|
+
* Shared by `doctor` (Checks 2+3) and the `run` pre-flight (#813) so the two
|
|
6
|
+
* cannot drift. The claude-code driver loads skills from project scope only
|
|
7
|
+
* (`settingSources: ["project"]`, see #19 AC-3 / #711), which makes
|
|
8
|
+
* `.claude/skills/` a hard runtime dependency: a phase prompt like
|
|
9
|
+
* "Run the /spec workflow" can never resolve without it.
|
|
10
|
+
*/
|
|
11
|
+
/** Directory (relative to a project root) that skills are resolved from. */
|
|
12
|
+
export declare const SKILLS_DIR = ".claude/skills";
|
|
13
|
+
export interface SkillsCheckResult {
|
|
14
|
+
/** True when the `.claude/skills/` directory exists. */
|
|
15
|
+
skillsDirExists: boolean;
|
|
16
|
+
/** Requested skills whose `SKILL.md` is missing, in input order. */
|
|
17
|
+
missingSkills: string[];
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Check that each requested skill is installed at
|
|
21
|
+
* `<cwd>/.claude/skills/<skill>/SKILL.md`.
|
|
22
|
+
*
|
|
23
|
+
* @param skills - Skill directory names to require (e.g. `["spec", "exec"]`).
|
|
24
|
+
* @param cwd - Project root to check under (default: `process.cwd()`).
|
|
25
|
+
*/
|
|
26
|
+
export declare function checkSkillsInstalled(skills: string[], cwd?: string): Promise<SkillsCheckResult>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skills installation check — single source of truth for the
|
|
3
|
+
* `.claude/skills/<skill>/SKILL.md` layout.
|
|
4
|
+
*
|
|
5
|
+
* Shared by `doctor` (Checks 2+3) and the `run` pre-flight (#813) so the two
|
|
6
|
+
* cannot drift. The claude-code driver loads skills from project scope only
|
|
7
|
+
* (`settingSources: ["project"]`, see #19 AC-3 / #711), which makes
|
|
8
|
+
* `.claude/skills/` a hard runtime dependency: a phase prompt like
|
|
9
|
+
* "Run the /spec workflow" can never resolve without it.
|
|
10
|
+
*/
|
|
11
|
+
import { join } from "path";
|
|
12
|
+
import { fileExists } from "./fs.js";
|
|
13
|
+
/** Directory (relative to a project root) that skills are resolved from. */
|
|
14
|
+
export const SKILLS_DIR = ".claude/skills";
|
|
15
|
+
/**
|
|
16
|
+
* Check that each requested skill is installed at
|
|
17
|
+
* `<cwd>/.claude/skills/<skill>/SKILL.md`.
|
|
18
|
+
*
|
|
19
|
+
* @param skills - Skill directory names to require (e.g. `["spec", "exec"]`).
|
|
20
|
+
* @param cwd - Project root to check under (default: `process.cwd()`).
|
|
21
|
+
*/
|
|
22
|
+
export async function checkSkillsInstalled(skills, cwd = process.cwd()) {
|
|
23
|
+
const skillsDirExists = await fileExists(join(cwd, SKILLS_DIR));
|
|
24
|
+
const missingSkills = [];
|
|
25
|
+
for (const skill of skills) {
|
|
26
|
+
if (!(await fileExists(join(cwd, SKILLS_DIR, skill, "SKILL.md")))) {
|
|
27
|
+
missingSkills.push(skill);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return { skillsDirExists, missingSkills };
|
|
31
|
+
}
|
package/dist/src/lib/stacks.d.ts
CHANGED
|
@@ -37,6 +37,7 @@ export interface PackageManagerConfig {
|
|
|
37
37
|
exec: string;
|
|
38
38
|
install: string;
|
|
39
39
|
installSilent: string;
|
|
40
|
+
ciInstall: string;
|
|
40
41
|
addPkg: string;
|
|
41
42
|
removePkg: string;
|
|
42
43
|
updatePkg: string;
|
|
@@ -56,12 +57,120 @@ export declare function detectPackageManager(): Promise<PackageManager | null>;
|
|
|
56
57
|
/**
|
|
57
58
|
* Synchronous version of detectPackageManager for use in startup code.
|
|
58
59
|
* Only checks JS lockfiles (not Python) since sequant is a Node.js tool.
|
|
60
|
+
*
|
|
61
|
+
* @param root Directory to look for lockfiles in. Defaults to the process cwd,
|
|
62
|
+
* which is what startup code wants; callers that operate on a specific
|
|
63
|
+
* repository (e.g. merge-check) must pass that repo's root instead.
|
|
64
|
+
*/
|
|
65
|
+
export declare function detectPackageManagerSync(root?: string): PackageManager;
|
|
66
|
+
/**
|
|
67
|
+
* Resolve the package manager for a directory, preferring a declared value and
|
|
68
|
+
* falling back to live lockfile detection.
|
|
69
|
+
*
|
|
70
|
+
* The declared value is a *snapshot* — the worktree manifest records whatever
|
|
71
|
+
* `sequant init` saw, so it is absent on manifest-less or pre-init trees. The
|
|
72
|
+
* old spelling at those call sites was `(declared as keyof typeof PM_CONFIG)
|
|
73
|
+
* || "npm"`, which assumed npm whenever the snapshot was missing while the
|
|
74
|
+
* shell provisioning path (`templates/scripts/new-feature.sh`, PM-aware since
|
|
75
|
+
* #847) detected live from the lockfile. On a pnpm/yarn/bun project without a
|
|
76
|
+
* manifest the two paths therefore disagreed about the project's package
|
|
77
|
+
* manager — the dual-producer drift class of #833. Detecting here makes the
|
|
78
|
+
* TypeScript path agree with the shell path by construction (#870).
|
|
79
|
+
*
|
|
80
|
+
* The own-property membership test also retires that unchecked cast: a
|
|
81
|
+
* declared value outside `PackageManager` (a hand-edited manifest, a future
|
|
82
|
+
* `"npm@10"` spelling) used to index `PM_CONFIG` to `undefined` and throw on
|
|
83
|
+
* the next property access. Such a value now routes to detection instead.
|
|
84
|
+
* Python managers (`pip`/`poetry`/`uv`) are `PM_CONFIG` keys, so a declared
|
|
85
|
+
* Python manager still wins over the JS-only detector.
|
|
86
|
+
*
|
|
87
|
+
* The test is `hasOwnProperty`, deliberately not `in`: `in` walks the
|
|
88
|
+
* prototype chain, so `"toString"`, `"constructor"`, and `"__proto__"` would
|
|
89
|
+
* all pass it and be returned as if they named a package manager. Indexing
|
|
90
|
+
* `PM_CONFIG` with one yields an inherited function (or `Object.prototype`)
|
|
91
|
+
* whose `ciInstall` is `undefined`, crashing the caller on `.split(" ")` —
|
|
92
|
+
* reintroducing the exact failure this guard exists to prevent.
|
|
93
|
+
*
|
|
94
|
+
* @param declared Package manager recorded in the manifest, if any
|
|
95
|
+
* @param root Directory whose lockfiles decide the fallback
|
|
59
96
|
*/
|
|
60
|
-
export declare function
|
|
97
|
+
export declare function resolvePackageManager(declared: string | undefined, root: string): PackageManager;
|
|
61
98
|
/**
|
|
62
99
|
* Get package manager command configuration
|
|
63
100
|
*/
|
|
64
101
|
export declare function getPackageManagerCommands(pm: PackageManager): PackageManagerConfig;
|
|
102
|
+
/**
|
|
103
|
+
* Frozen install understood by Yarn 1 (classic).
|
|
104
|
+
*
|
|
105
|
+
* Yarn 2+ (berry) renamed this flag to `--immutable`, which is what
|
|
106
|
+
* `PM_CONFIG.yarn.ciInstall` carries. Both yarn spellings therefore exist, and
|
|
107
|
+
* both must appear in `new-feature.sh`'s `pm_ci_install()` table — the drift
|
|
108
|
+
* guard in `__tests__/new-feature-frozen-install.integration.test.ts` asserts
|
|
109
|
+
* exactly that, which is why this is a named export rather than a literal
|
|
110
|
+
* buried in `resolvePackageManagerConfig` (#871).
|
|
111
|
+
*/
|
|
112
|
+
export declare const YARN_CLASSIC_CI_INSTALL = "yarn install --frozen-lockfile";
|
|
113
|
+
/**
|
|
114
|
+
* Detect whether a directory is a Yarn 1 (classic) or Yarn 2+ (berry) project.
|
|
115
|
+
*
|
|
116
|
+
* Yarn 1 and berry both use `yarn.lock`, so `detectPackageManagerSync` cannot
|
|
117
|
+
* tell them apart — it answers "yarn", and this answers "which yarn". They are
|
|
118
|
+
* separate axes on purpose: adding a `yarn1` member to `PackageManager` would
|
|
119
|
+
* leak a synthetic name into settings (`pmRun`), doctor output, and templates
|
|
120
|
+
* for what is, today, a one-flag difference.
|
|
121
|
+
*
|
|
122
|
+
* Signals, in order of authority. The ordering follows a single rule: **flag
|
|
123
|
+
* acceptance is decided by the yarn binary that runs, not by the lockfile it
|
|
124
|
+
* reads.** So a Corepack pin outranks the lockfile header — a yarn-1 lockfile
|
|
125
|
+
* under `packageManager: "yarn@4"` still gets berry's `--immutable`, because
|
|
126
|
+
* yarn 4 is what will execute and yarn 4 rejects `--frozen-lockfile`.
|
|
127
|
+
*
|
|
128
|
+
* 1. `packageManager: "yarn@<major>"` in `package.json` — Corepack pins the
|
|
129
|
+
* binary.
|
|
130
|
+
* 2. `.yarnrc.yml` — a berry-only config file; yarn 1 reads `.yarnrc`.
|
|
131
|
+
* 3. `yarn.lock` header — yarn 1 writes `# yarn lockfile v1`; berry writes
|
|
132
|
+
* `__metadata:` instead.
|
|
133
|
+
* 4. Nothing recognizable → berry, the pre-#871 assumption. Staying with it
|
|
134
|
+
* keeps a contentless or unreadable `yarn.lock` behaving exactly as it did
|
|
135
|
+
* before this function existed.
|
|
136
|
+
*
|
|
137
|
+
* Mirrored by `detect_yarn_major` in `templates/scripts/new-feature.sh` (#871).
|
|
138
|
+
*
|
|
139
|
+
* @internal Exported for testing — production code should go through
|
|
140
|
+
* {@link resolvePackageManagerConfig}, whose whole job is to apply this answer.
|
|
141
|
+
* The export exists so the cross-path agreement test can run this and the shell
|
|
142
|
+
* mirror against the same fixtures, which is the gate keeping the two in step.
|
|
143
|
+
*
|
|
144
|
+
* @param root Directory to inspect. Defaults to the process cwd.
|
|
145
|
+
* @returns 1 for Yarn 1 (classic), 2 for Yarn 2+ (berry)
|
|
146
|
+
*/
|
|
147
|
+
export declare function detectYarnMajor(root?: string): 1 | 2;
|
|
148
|
+
/**
|
|
149
|
+
* Package manager commands for `pm`, with directory-dependent commands resolved
|
|
150
|
+
* against `root`.
|
|
151
|
+
*
|
|
152
|
+
* A drop-in replacement for `PM_CONFIG[pm]` at every call site that knows which
|
|
153
|
+
* project directory it is acting on. `PM_CONFIG.yarn` is the berry baseline, so
|
|
154
|
+
* for a Yarn 1 project this substitutes every field whose berry spelling is
|
|
155
|
+
* wrong on classic — `ciInstall`, `exec`, and `updatePkg` (see
|
|
156
|
+
* {@link YARN_CLASSIC_OVERRIDES}). Every other package manager, and every
|
|
157
|
+
* major-agnostic yarn field, is returned untouched.
|
|
158
|
+
*
|
|
159
|
+
* Returning the whole config rather than one resolved string is what makes that
|
|
160
|
+
* cheap: call sites that thread a `PackageManagerConfig` onward — merge-check's
|
|
161
|
+
* combined-branch test reads `ciInstall` for three commands and two user-facing
|
|
162
|
+
* messages — stay correct with a single-line change, and each newly discovered
|
|
163
|
+
* classic/berry split is one entry in the overrides table rather than a new
|
|
164
|
+
* call-site edit.
|
|
165
|
+
*
|
|
166
|
+
* Resolve against the tree you are about to act on, not against wherever the
|
|
167
|
+
* process started: `root` decides the answer, and in merge-check the combined
|
|
168
|
+
* (post-merge) state can disagree with the pre-merge one.
|
|
169
|
+
*
|
|
170
|
+
* @param pm Package manager identity, e.g. from `detectPackageManagerSync`
|
|
171
|
+
* @param root Directory whose files decide the directory-dependent commands
|
|
172
|
+
*/
|
|
173
|
+
export declare function resolvePackageManagerConfig(pm: PackageManager, root: string): PackageManagerConfig;
|
|
65
174
|
export interface StackConfig {
|
|
66
175
|
name: string;
|
|
67
176
|
displayName: string;
|