sequant 2.2.0 → 2.4.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.
Files changed (156) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/README.md +81 -5
  4. package/dist/bin/cli.js +140 -13
  5. package/dist/src/commands/abort.d.ts +36 -0
  6. package/dist/src/commands/abort.js +138 -0
  7. package/dist/src/commands/doctor.d.ts +25 -0
  8. package/dist/src/commands/doctor.js +36 -1
  9. package/dist/src/commands/locks.d.ts +67 -0
  10. package/dist/src/commands/locks.js +290 -0
  11. package/dist/src/commands/merge.js +11 -0
  12. package/dist/src/commands/prompt.d.ts +46 -0
  13. package/dist/src/commands/prompt.js +273 -0
  14. package/dist/src/commands/run-display.d.ts +11 -2
  15. package/dist/src/commands/run-display.js +62 -28
  16. package/dist/src/commands/run-progress.d.ts +42 -0
  17. package/dist/src/commands/run-progress.js +93 -0
  18. package/dist/src/commands/run.js +90 -18
  19. package/dist/src/commands/stats.d.ts +2 -0
  20. package/dist/src/commands/stats.js +94 -8
  21. package/dist/src/commands/status.js +12 -0
  22. package/dist/src/commands/watch.d.ts +18 -0
  23. package/dist/src/commands/watch.js +211 -0
  24. package/dist/src/lib/ac-linter.d.ts +1 -1
  25. package/dist/src/lib/ac-linter.js +81 -0
  26. package/dist/src/lib/assess-collision-detect.d.ts +91 -0
  27. package/dist/src/lib/assess-collision-detect.js +217 -0
  28. package/dist/src/lib/assess-comment-parser.d.ts +59 -1
  29. package/dist/src/lib/assess-comment-parser.js +124 -2
  30. package/dist/src/lib/cli-ui/format.d.ts +19 -0
  31. package/dist/src/lib/cli-ui/format.js +34 -0
  32. package/dist/src/lib/cli-ui/run-renderer-types.d.ts +220 -0
  33. package/dist/src/lib/cli-ui/run-renderer-types.js +7 -0
  34. package/dist/src/lib/cli-ui/run-renderer.d.ts +265 -0
  35. package/dist/src/lib/cli-ui/run-renderer.js +1390 -0
  36. package/dist/src/lib/cli-ui/scrollback-harness.d.ts +112 -0
  37. package/dist/src/lib/cli-ui/scrollback-harness.js +294 -0
  38. package/dist/src/lib/heuristics/behavior-rule-detector.d.ts +94 -0
  39. package/dist/src/lib/heuristics/behavior-rule-detector.js +467 -0
  40. package/dist/src/lib/locks/index.d.ts +7 -0
  41. package/dist/src/lib/locks/index.js +5 -0
  42. package/dist/src/lib/locks/lock-manager.d.ts +168 -0
  43. package/dist/src/lib/locks/lock-manager.js +433 -0
  44. package/dist/src/lib/locks/types.d.ts +59 -0
  45. package/dist/src/lib/locks/types.js +31 -0
  46. package/dist/src/lib/merge-check/types.js +1 -1
  47. package/dist/src/lib/qa/markdown-only-ci.d.ts +46 -0
  48. package/dist/src/lib/qa/markdown-only-ci.js +74 -0
  49. package/dist/src/lib/relay/activation.d.ts +60 -0
  50. package/dist/src/lib/relay/activation.js +122 -0
  51. package/dist/src/lib/relay/archive.d.ts +34 -0
  52. package/dist/src/lib/relay/archive.js +112 -0
  53. package/dist/src/lib/relay/frame.d.ts +20 -0
  54. package/dist/src/lib/relay/frame.js +76 -0
  55. package/dist/src/lib/relay/index.d.ts +13 -0
  56. package/dist/src/lib/relay/index.js +13 -0
  57. package/dist/src/lib/relay/paths.d.ts +43 -0
  58. package/dist/src/lib/relay/paths.js +59 -0
  59. package/dist/src/lib/relay/pid.d.ts +34 -0
  60. package/dist/src/lib/relay/pid.js +72 -0
  61. package/dist/src/lib/relay/reader.d.ts +35 -0
  62. package/dist/src/lib/relay/reader.js +115 -0
  63. package/dist/src/lib/relay/types.d.ts +70 -0
  64. package/dist/src/lib/relay/types.js +85 -0
  65. package/dist/src/lib/relay/writer.d.ts +48 -0
  66. package/dist/src/lib/relay/writer.js +113 -0
  67. package/dist/src/lib/settings.d.ts +31 -1
  68. package/dist/src/lib/settings.js +18 -3
  69. package/dist/src/lib/version-check.d.ts +60 -5
  70. package/dist/src/lib/version-check.js +97 -9
  71. package/dist/src/lib/workflow/batch-executor.d.ts +20 -1
  72. package/dist/src/lib/workflow/batch-executor.js +274 -185
  73. package/dist/src/lib/workflow/config-resolver.js +4 -0
  74. package/dist/src/lib/workflow/drivers/agent-driver.d.ts +48 -1
  75. package/dist/src/lib/workflow/drivers/aider.d.ts +7 -1
  76. package/dist/src/lib/workflow/drivers/aider.js +9 -0
  77. package/dist/src/lib/workflow/drivers/claude-code.d.ts +17 -1
  78. package/dist/src/lib/workflow/drivers/claude-code.js +51 -2
  79. package/dist/src/lib/workflow/drivers/index.d.ts +1 -1
  80. package/dist/src/lib/workflow/event-emitter.d.ts +157 -0
  81. package/dist/src/lib/workflow/event-emitter.js +102 -0
  82. package/dist/src/lib/workflow/heartbeat.d.ts +71 -0
  83. package/dist/src/lib/workflow/heartbeat.js +194 -0
  84. package/dist/src/lib/workflow/notice.d.ts +32 -0
  85. package/dist/src/lib/workflow/notice.js +38 -0
  86. package/dist/src/lib/workflow/phase-executor.d.ts +58 -16
  87. package/dist/src/lib/workflow/phase-executor.js +244 -130
  88. package/dist/src/lib/workflow/phase-mapper.d.ts +27 -13
  89. package/dist/src/lib/workflow/phase-mapper.js +70 -51
  90. package/dist/src/lib/workflow/phase-registry.d.ts +127 -0
  91. package/dist/src/lib/workflow/phase-registry.js +233 -0
  92. package/dist/src/lib/workflow/platforms/github.d.ts +1 -1
  93. package/dist/src/lib/workflow/platforms/github.js +20 -3
  94. package/dist/src/lib/workflow/pr-status.d.ts +18 -2
  95. package/dist/src/lib/workflow/pr-status.js +41 -9
  96. package/dist/src/lib/workflow/qa-stagnation.d.ts +117 -0
  97. package/dist/src/lib/workflow/qa-stagnation.js +179 -0
  98. package/dist/src/lib/workflow/run-log-schema.d.ts +5 -55
  99. package/dist/src/lib/workflow/run-orchestrator.d.ts +70 -1
  100. package/dist/src/lib/workflow/run-orchestrator.js +464 -25
  101. package/dist/src/lib/workflow/run-reflect.js +1 -1
  102. package/dist/src/lib/workflow/run-state.d.ts +71 -0
  103. package/dist/src/lib/workflow/run-state.js +14 -0
  104. package/dist/src/lib/workflow/state-cleanup.d.ts +13 -5
  105. package/dist/src/lib/workflow/state-cleanup.js +17 -5
  106. package/dist/src/lib/workflow/state-manager.d.ts +31 -2
  107. package/dist/src/lib/workflow/state-manager.js +64 -1
  108. package/dist/src/lib/workflow/state-schema.d.ts +82 -35
  109. package/dist/src/lib/workflow/state-schema.js +63 -4
  110. package/dist/src/lib/workflow/types.d.ts +139 -16
  111. package/dist/src/lib/workflow/types.js +18 -13
  112. package/dist/src/lib/workflow/worktree-manager.d.ts +8 -1
  113. package/dist/src/lib/workflow/worktree-manager.js +15 -6
  114. package/dist/src/mcp/tools/run.d.ts +44 -0
  115. package/dist/src/mcp/tools/run.js +104 -13
  116. package/dist/src/ui/tui/App.d.ts +14 -0
  117. package/dist/src/ui/tui/App.js +41 -0
  118. package/dist/src/ui/tui/ElapsedTimer.d.ts +10 -0
  119. package/dist/src/ui/tui/ElapsedTimer.js +31 -0
  120. package/dist/src/ui/tui/Header.d.ts +6 -0
  121. package/dist/src/ui/tui/Header.js +15 -0
  122. package/dist/src/ui/tui/IssueBox.d.ts +16 -0
  123. package/dist/src/ui/tui/IssueBox.js +68 -0
  124. package/dist/src/ui/tui/Spinner.d.ts +9 -0
  125. package/dist/src/ui/tui/Spinner.js +18 -0
  126. package/dist/src/ui/tui/index.d.ts +15 -0
  127. package/dist/src/ui/tui/index.js +29 -0
  128. package/dist/src/ui/tui/theme.d.ts +29 -0
  129. package/dist/src/ui/tui/theme.js +52 -0
  130. package/dist/src/ui/tui/truncate.d.ts +11 -0
  131. package/dist/src/ui/tui/truncate.js +31 -0
  132. package/package.json +14 -6
  133. package/templates/agents/sequant-explorer.md +1 -0
  134. package/templates/agents/sequant-qa-checker.md +2 -1
  135. package/templates/agents/sequant-testgen.md +1 -0
  136. package/templates/hooks/post-tool.sh +92 -0
  137. package/templates/hooks/pre-tool.sh +18 -9
  138. package/templates/hooks/relay-check.sh +107 -0
  139. package/templates/relay/frame.txt +11 -0
  140. package/templates/scripts/cleanup-worktree.sh +25 -3
  141. package/templates/scripts/new-feature.sh +6 -0
  142. package/templates/skills/_shared/references/behavior-rule-detection.md +205 -0
  143. package/templates/skills/_shared/references/subagent-types.md +21 -8
  144. package/templates/skills/assess/SKILL.md +122 -68
  145. package/templates/skills/assess/references/predicted-collision-detection.md +109 -0
  146. package/templates/skills/docs/SKILL.md +141 -22
  147. package/templates/skills/exec/SKILL.md +10 -8
  148. package/templates/skills/fullsolve/SKILL.md +79 -5
  149. package/templates/skills/loop/SKILL.md +28 -0
  150. package/templates/skills/merger/SKILL.md +621 -0
  151. package/templates/skills/qa/SKILL.md +727 -8
  152. package/templates/skills/setup/SKILL.md +12 -6
  153. package/templates/skills/spec/SKILL.md +52 -0
  154. package/templates/skills/spec/references/parallel-groups.md +7 -0
  155. package/templates/skills/spec/references/recommended-workflow.md +4 -2
  156. package/templates/skills/testgen/SKILL.md +24 -17
@@ -28,16 +28,71 @@ export declare function getCachePath(): string;
28
28
  */
29
29
  export declare function getCurrentVersion(): string;
30
30
  /**
31
- * Check if running from a local node_modules install (vs npx cache)
31
+ * Check if running from a global install (npm root -g).
32
+ *
33
+ * On POSIX, npm's global root convention puts packages under
34
+ * `<prefix>/lib/node_modules/` (e.g. `/usr/local/lib/node_modules`,
35
+ * `/opt/homebrew/lib/node_modules`, `~/.nvm/versions/node/<v>/lib/node_modules`).
36
+ *
37
+ * On Windows, the default global root is `%AppData%\npm\node_modules\` —
38
+ * sometimes nested under `Roaming\` depending on the npm/Node installer —
39
+ * with no `lib\` segment. Both variants are matched here.
40
+ *
41
+ * Project-local installs live under `<project>/node_modules/` and don't match
42
+ * either pattern.
43
+ */
44
+ export declare function isGlobalInstall(installPath?: string): boolean;
45
+ /**
46
+ * Check if running from a local node_modules install (vs npx cache or global).
32
47
  *
33
48
  * Local installs are in: <project>/node_modules/sequant/
34
49
  * npx installs are in: ~/.npm/_npx/<hash>/node_modules/sequant/
50
+ * Global installs are in: <prefix>/lib/node_modules/sequant/
51
+ *
52
+ * Only project-local installs return true — npx and globals are excluded so
53
+ * neither receives the project-local "use npm update sequant" warning.
54
+ */
55
+ export declare function isLocalNodeModulesInstall(installPath?: string): boolean;
56
+ /**
57
+ * Walk up from the given directory to find the directory containing
58
+ * sequant's package.json. Returns null if not found.
59
+ *
60
+ * Mirrors the walk-up in getCurrentVersion() so callers can reason about
61
+ * the install root (the directory that actually holds sequant's package.json),
62
+ * which is needed to distinguish between e.g. project-local installs and the
63
+ * pathological $HOME/node_modules/sequant case.
64
+ *
65
+ * @internal Exported for testability and reuse in bin/cli.ts. Not a stable
66
+ * public API — may change without a major version bump.
67
+ */
68
+ export declare function getInstallRoot(startDir?: string): string | null;
69
+ /**
70
+ * Check whether sequant is installed in $HOME/node_modules/sequant exactly.
71
+ *
72
+ * This is a known footgun: a stray `npm install sequant` run from $HOME
73
+ * leaves a package.json + node_modules/ at the home root, and Node's module
74
+ * resolution then walks up from any home subdirectory to that stale install
75
+ * before falling back to the npx cache. The result is that `npx sequant`
76
+ * silently runs the home-stray copy instead of the latest version.
77
+ *
78
+ * Project-local installs (anywhere else under node_modules/), global installs,
79
+ * and the npx cache all return false.
80
+ *
81
+ * `installRoot` is accepted as a parameter for testability.
82
+ */
83
+ export declare function isHomeStrayInstall(installRoot?: string | null): boolean;
84
+ /**
85
+ * Render the home-stray warning string for a given install root.
86
+ *
87
+ * Extracted from bin/cli.ts so the rendered output can be asserted in unit
88
+ * tests; the predicate (isHomeStrayInstall) and the emission are then both
89
+ * covered without spawning a child process. Returns the warning text without
90
+ * any chalk styling — the caller decides whether to colorize.
35
91
  *
36
- * This matters because:
37
- * - Local installs should be updated with: npm update sequant
38
- * - npx installs should be updated with: npx sequant@latest
92
+ * @internal Exported for the bin/cli.ts caller and unit tests. Not a stable
93
+ * public API may change without a major version bump.
39
94
  */
40
- export declare function isLocalNodeModulesInstall(): boolean;
95
+ export declare function buildHomeStrayWarning(installRoot: string): string;
41
96
  /**
42
97
  * Read the version cache
43
98
  */
@@ -5,6 +5,7 @@
5
5
  * with the latest version on npm.
6
6
  */
7
7
  import fs from "fs";
8
+ import os from "os";
8
9
  import path from "path";
9
10
  import { fileURLToPath } from "url";
10
11
  import { detectPackageManagerSync, getPackageManagerCommands, } from "./stacks.js";
@@ -56,23 +57,110 @@ export function getCurrentVersion() {
56
57
  }
57
58
  }
58
59
  /**
59
- * Check if running from a local node_modules install (vs npx cache)
60
+ * Check if running from a global install (npm root -g).
61
+ *
62
+ * On POSIX, npm's global root convention puts packages under
63
+ * `<prefix>/lib/node_modules/` (e.g. `/usr/local/lib/node_modules`,
64
+ * `/opt/homebrew/lib/node_modules`, `~/.nvm/versions/node/<v>/lib/node_modules`).
65
+ *
66
+ * On Windows, the default global root is `%AppData%\npm\node_modules\` —
67
+ * sometimes nested under `Roaming\` depending on the npm/Node installer —
68
+ * with no `lib\` segment. Both variants are matched here.
69
+ *
70
+ * Project-local installs live under `<project>/node_modules/` and don't match
71
+ * either pattern.
72
+ */
73
+ export function isGlobalInstall(installPath = __dirname) {
74
+ const normalizedPath = installPath.replace(/\\/g, "/");
75
+ return (normalizedPath.includes("/lib/node_modules/sequant") ||
76
+ /\/AppData\/(Roaming\/)?npm\/node_modules\/sequant/.test(normalizedPath));
77
+ }
78
+ /**
79
+ * Check if running from a local node_modules install (vs npx cache or global).
60
80
  *
61
81
  * Local installs are in: <project>/node_modules/sequant/
62
82
  * npx installs are in: ~/.npm/_npx/<hash>/node_modules/sequant/
83
+ * Global installs are in: <prefix>/lib/node_modules/sequant/
63
84
  *
64
- * This matters because:
65
- * - Local installs should be updated with: npm update sequant
66
- * - npx installs should be updated with: npx sequant@latest
85
+ * Only project-local installs return true — npx and globals are excluded so
86
+ * neither receives the project-local "use npm update sequant" warning.
67
87
  */
68
- export function isLocalNodeModulesInstall() {
69
- // Check if our path contains node_modules/sequant but NOT in .npm/_npx
70
- const normalizedPath = __dirname.replace(/\\/g, "/");
71
- // Running from local node_modules (not npx cache)
88
+ export function isLocalNodeModulesInstall(installPath = __dirname) {
89
+ const normalizedPath = installPath.replace(/\\/g, "/");
72
90
  const inNodeModules = normalizedPath.includes("/node_modules/sequant");
73
91
  const inNpxCache = normalizedPath.includes("/.npm/_npx/") ||
74
92
  normalizedPath.includes("\\.npm\\_npx\\");
75
- return inNodeModules && !inNpxCache;
93
+ return inNodeModules && !inNpxCache && !isGlobalInstall(normalizedPath);
94
+ }
95
+ /**
96
+ * Walk up from the given directory to find the directory containing
97
+ * sequant's package.json. Returns null if not found.
98
+ *
99
+ * Mirrors the walk-up in getCurrentVersion() so callers can reason about
100
+ * the install root (the directory that actually holds sequant's package.json),
101
+ * which is needed to distinguish between e.g. project-local installs and the
102
+ * pathological $HOME/node_modules/sequant case.
103
+ *
104
+ * @internal Exported for testability and reuse in bin/cli.ts. Not a stable
105
+ * public API — may change without a major version bump.
106
+ */
107
+ export function getInstallRoot(startDir = __dirname) {
108
+ let dir = startDir;
109
+ while (dir !== path.dirname(dir)) {
110
+ const candidate = path.resolve(dir, "package.json");
111
+ try {
112
+ const content = fs.readFileSync(candidate, "utf8");
113
+ const pkg = JSON.parse(content);
114
+ if (pkg.name === "sequant") {
115
+ return dir;
116
+ }
117
+ }
118
+ catch {
119
+ // Not found, continue searching
120
+ }
121
+ dir = path.dirname(dir);
122
+ }
123
+ return null;
124
+ }
125
+ /**
126
+ * Check whether sequant is installed in $HOME/node_modules/sequant exactly.
127
+ *
128
+ * This is a known footgun: a stray `npm install sequant` run from $HOME
129
+ * leaves a package.json + node_modules/ at the home root, and Node's module
130
+ * resolution then walks up from any home subdirectory to that stale install
131
+ * before falling back to the npx cache. The result is that `npx sequant`
132
+ * silently runs the home-stray copy instead of the latest version.
133
+ *
134
+ * Project-local installs (anywhere else under node_modules/), global installs,
135
+ * and the npx cache all return false.
136
+ *
137
+ * `installRoot` is accepted as a parameter for testability.
138
+ */
139
+ export function isHomeStrayInstall(installRoot = getInstallRoot()) {
140
+ if (!installRoot)
141
+ return false;
142
+ const expected = path.join(os.homedir(), "node_modules", "sequant");
143
+ return path.resolve(installRoot) === path.resolve(expected);
144
+ }
145
+ /**
146
+ * Render the home-stray warning string for a given install root.
147
+ *
148
+ * Extracted from bin/cli.ts so the rendered output can be asserted in unit
149
+ * tests; the predicate (isHomeStrayInstall) and the emission are then both
150
+ * covered without spawning a child process. Returns the warning text without
151
+ * any chalk styling — the caller decides whether to colorize.
152
+ *
153
+ * @internal Exported for the bin/cli.ts caller and unit tests. Not a stable
154
+ * public API — may change without a major version bump.
155
+ */
156
+ export function buildHomeStrayWarning(installRoot) {
157
+ const parent = path.dirname(installRoot);
158
+ return (`! Sequant is running from ${installRoot} — this pollutes\n` +
159
+ ` resolution for every subdirectory of your home directory.\n\n` +
160
+ ` If accidental (usually is — one stray \`npm install sequant\` from ~ does it):\n` +
161
+ ` remove ${parent}\n` +
162
+ ` remove $HOME/package.json and $HOME/package-lock.json\n\n` +
163
+ ` If intentional: use \`npm install -g sequant\` or the Claude Code plugin.\n`);
76
164
  }
77
165
  /**
78
166
  * Read the version cache
@@ -7,7 +7,7 @@
7
7
  * (including quality-loop retries, checkpoint commits, rebasing, and PR
8
8
  * creation).
9
9
  */
10
- import { PhaseResult, IssueResult, type RunOptions, type IssueExecutionContext, type BatchExecutionContext } from "./types.js";
10
+ import { ExecutionConfig, PhaseResult, IssueResult, type RunOptions, type IssueExecutionContext, type BatchExecutionContext, type ProgressCallback } from "./types.js";
11
11
  export type { RunOptions, ProgressCallback, IssueExecutionContext, BatchExecutionContext, } from "./types.js";
12
12
  /**
13
13
  * Emit a structured progress line to stderr for MCP progress notifications.
@@ -19,6 +19,16 @@ export type { RunOptions, ProgressCallback, IssueExecutionContext, BatchExecutio
19
19
  * @param event - Phase lifecycle event: "start", "complete", or "failed"
20
20
  * @param extra - Optional fields: durationSeconds (on complete), error (on failed)
21
21
  */
22
+ /**
23
+ * Wrap an `ExecutionConfig` with an `onActivity` hook that re-emits each
24
+ * agent-output ping as a `"activity"` progress event for the dashboard (#543).
25
+ *
26
+ * Returns the input config unchanged when no `onProgress` callback is set,
27
+ * so non-TUI runs pay no overhead.
28
+ *
29
+ * @internal Exported for testing only
30
+ */
31
+ export declare function withActivityHook(base: ExecutionConfig, issueNumber: number, phase: string, onProgress: ProgressCallback | undefined): ExecutionConfig;
22
32
  /**
23
33
  * Build enriched prompt context for the /loop phase from a failed phase result (#488).
24
34
  * Passes QA verdict, failed ACs, and error directly so the /loop skill doesn't need
@@ -30,7 +40,16 @@ export declare function buildLoopContext(failedResult: PhaseResult): string;
30
40
  export declare function emitProgressLine(issue: number, phase: string, event?: "start" | "complete" | "failed", extra?: {
31
41
  durationSeconds?: number;
32
42
  error?: string;
43
+ iteration?: number;
33
44
  }): void;
45
+ /**
46
+ * Emit the current run's UUID on stderr so MCP callers can look up the exact
47
+ * log file produced by this subprocess instead of relying on a fuzzy time
48
+ * filter (#631). Gated on `SEQUANT_ORCHESTRATOR` so CLI users see nothing.
49
+ *
50
+ * Must be called before `emitProgressLine` to satisfy AC-1.
51
+ */
52
+ export declare function emitRunIdLine(runId: string): void;
34
53
  export declare function getIssueInfo(issueNumber: number): Promise<{
35
54
  title: string;
36
55
  labels: string[];