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
|
@@ -7,9 +7,11 @@ import { spawnSync } from "child_process";
|
|
|
7
7
|
import { getManifest, updateManifest, getPackageVersion, } from "../lib/manifest.js";
|
|
8
8
|
import { computeTemplateChanges } from "../lib/templates.js";
|
|
9
9
|
import { getConfig, saveConfig } from "../lib/config.js";
|
|
10
|
-
import { getStackConfig, PM_CONFIG, getPackageManagerCommands, } from "../lib/stacks.js";
|
|
10
|
+
import { getStackConfig, PM_CONFIG, getPackageManagerCommands, resolvePackageManager, } from "../lib/stacks.js";
|
|
11
11
|
import { writeFile } from "../lib/fs.js";
|
|
12
|
+
import { chmod } from "fs/promises";
|
|
12
13
|
import { isStdinTTY, isCI, getNonInteractiveReason } from "../lib/tty.js";
|
|
14
|
+
import { syncSequantMcpPin } from "../lib/mcp-config.js";
|
|
13
15
|
/**
|
|
14
16
|
* True when `update` must not prompt: stdin is not a terminal (piped input) or
|
|
15
17
|
* we are running in a recognized CI environment. CI is checked explicitly
|
|
@@ -41,8 +43,18 @@ export async function updateCommand(options) {
|
|
|
41
43
|
const manifest = await getManifest();
|
|
42
44
|
if (!manifest) {
|
|
43
45
|
console.log(chalk.red("❌ Sequant is not initialized. Run `sequant init` first."));
|
|
46
|
+
process.exitCode = 1;
|
|
44
47
|
return;
|
|
45
48
|
}
|
|
49
|
+
// Resolved once for the whole command. The manifest's packageManager is a
|
|
50
|
+
// snapshot taken at `sequant init`, so it is absent on pre-1.3.0 installs —
|
|
51
|
+
// exactly the population the PM_RUN backfill below exists to serve. The
|
|
52
|
+
// three sites that used to spell this `(manifest.packageManager as keyof
|
|
53
|
+
// typeof PM_CONFIG) || "npm"` therefore assumed npm for those installs, and
|
|
54
|
+
// wrote an npm PM_RUN token into a pnpm/yarn/bun project's config (#870).
|
|
55
|
+
// The root is the cwd because `update` operates on the project in place,
|
|
56
|
+
// the same directory `getManifest` and `syncSequantMcpPin` read.
|
|
57
|
+
const pm = resolvePackageManager(manifest.packageManager, process.cwd());
|
|
46
58
|
const packageVersion = getPackageVersion();
|
|
47
59
|
console.log(chalk.gray(`Current version: ${manifest.version}`));
|
|
48
60
|
console.log(chalk.gray(`Stack: ${manifest.stack}`));
|
|
@@ -64,7 +76,6 @@ export async function updateCommand(options) {
|
|
|
64
76
|
console.log(chalk.gray(`Dev URL: ${tokens.DEV_URL || "(not set)"}\n`));
|
|
65
77
|
// Add PM_RUN if missing (for existing installs before v1.3.0)
|
|
66
78
|
if (!tokens.PM_RUN) {
|
|
67
|
-
const pm = manifest.packageManager || "npm";
|
|
68
79
|
const pmConfig = getPackageManagerCommands(pm);
|
|
69
80
|
tokens.PM_RUN = pmConfig.run;
|
|
70
81
|
config.tokens = tokens;
|
|
@@ -78,7 +89,6 @@ export async function updateCommand(options) {
|
|
|
78
89
|
const stackConfig = getStackConfig(manifest.stack);
|
|
79
90
|
const defaultDevUrl = stackConfig.devUrl;
|
|
80
91
|
// Get package manager run command
|
|
81
|
-
const pm = manifest.packageManager || "npm";
|
|
82
92
|
const pmConfig = getPackageManagerCommands(pm);
|
|
83
93
|
if (options.force || options.yes) {
|
|
84
94
|
tokens = { DEV_URL: defaultDevUrl, PM_RUN: pmConfig.run };
|
|
@@ -116,6 +126,16 @@ export async function updateCommand(options) {
|
|
|
116
126
|
console.log(chalk.green("✔ Configuration saved\n"));
|
|
117
127
|
}
|
|
118
128
|
}
|
|
129
|
+
// Re-pin the project .mcp.json MCP server to the installed version (#793).
|
|
130
|
+
// Independent of template changes: a version-only upgrade leaves every
|
|
131
|
+
// template unchanged (so the flow would short-circuit at "Everything is up to
|
|
132
|
+
// date" below) but should still refresh the pin so the MCP server tracks the
|
|
133
|
+
// release the user just updated to. Runs here, before that short-circuit.
|
|
134
|
+
const mcpPin = syncSequantMcpPin(process.cwd(), { dryRun: options.dryRun });
|
|
135
|
+
if (mcpPin.updated) {
|
|
136
|
+
const verb = options.dryRun ? "Would update" : "Updated";
|
|
137
|
+
console.log(chalk.blue(`${verb} .mcp.json MCP pin: ${mcpPin.from} → ${mcpPin.to}`));
|
|
138
|
+
}
|
|
119
139
|
// Compute changes using the shared, variable-aware comparison.
|
|
120
140
|
// Templates are rendered (PROJECT_NAME, STACK_NOTES, etc.) before diffing,
|
|
121
141
|
// and in-place-customizable files (constitution) are protected as overrides.
|
|
@@ -202,6 +222,11 @@ export async function updateCommand(options) {
|
|
|
202
222
|
let updated = 0;
|
|
203
223
|
for (const file of applySet) {
|
|
204
224
|
await writeFile(file.path, file.rendered);
|
|
225
|
+
// Shell scripts (hooks, scripts/dev) need the exec bit, matching the
|
|
226
|
+
// copyTemplates write path.
|
|
227
|
+
if (file.path.endsWith(".sh")) {
|
|
228
|
+
await chmod(file.path, 0o755);
|
|
229
|
+
}
|
|
205
230
|
updated++;
|
|
206
231
|
}
|
|
207
232
|
// Update manifest
|
|
@@ -210,8 +235,6 @@ export async function updateCommand(options) {
|
|
|
210
235
|
// Check if package.json was updated and run install
|
|
211
236
|
const packageJsonUpdated = applySet.some((f) => f.path === "package.json" || f.path.endsWith("/package.json"));
|
|
212
237
|
if (packageJsonUpdated) {
|
|
213
|
-
// Use detected package manager or default to npm
|
|
214
|
-
const pm = manifest.packageManager || "npm";
|
|
215
238
|
const pmConfig = PM_CONFIG[pm];
|
|
216
239
|
console.log(chalk.blue(`\npackage.json updated, running ${pmConfig.install}...`));
|
|
217
240
|
const [cmd, ...args] = pmConfig.install.split(" ");
|
|
@@ -6,6 +6,12 @@
|
|
|
6
6
|
* Also supports alternate formats: `- [ ] **B2:** Description`
|
|
7
7
|
* And bold-wrapped format: `- [ ] **AC-1: Description**`
|
|
8
8
|
*
|
|
9
|
+
* Bare checkbox items (`- [ ] Some requirement`, no ID prefix) are also
|
|
10
|
+
* honored, but ONLY under an explicit `## Acceptance Criteria` heading, where
|
|
11
|
+
* they receive synthesized stable IDs. Human-authored issues rarely prefix
|
|
12
|
+
* their ACs with IDs, so without this every hand-written issue parsed to zero
|
|
13
|
+
* ACs — blinding every downstream AC consumer (#850).
|
|
14
|
+
*
|
|
9
15
|
* @example
|
|
10
16
|
* ```typescript
|
|
11
17
|
* import { parseAcceptanceCriteria } from './ac-parser';
|
|
@@ -39,8 +45,16 @@ export declare function inferVerificationMethod(description: string): ACVerifica
|
|
|
39
45
|
* - `- [ ] **AC-1:** Description`
|
|
40
46
|
* - `- [ ] **B2:** Description`
|
|
41
47
|
* - `- [ ] **AC-1: Description**` (bold wraps ID + description)
|
|
48
|
+
* - `- [ ] **AC-1** Description` (bold ID, no colon)
|
|
49
|
+
* - `- [ ] **AC-1**: Description` (colon outside the bold)
|
|
42
50
|
* - `- [ ] AC-1: Description`
|
|
43
51
|
*
|
|
52
|
+
* Bare checkbox items without an ID prefix (`- [ ] Some requirement`) are also
|
|
53
|
+
* parsed, but ONLY under an explicit `## Acceptance Criteria` heading, where
|
|
54
|
+
* they receive synthesized stable IDs (`AC-1`, `AC-2`, ...). This keeps
|
|
55
|
+
* unrelated checklists elsewhere in the body (Open Questions, Test Plan) from
|
|
56
|
+
* being misread as ACs, while letting ordinary human-written issues parse.
|
|
57
|
+
*
|
|
44
58
|
* @param issueBody - The full GitHub issue body markdown
|
|
45
59
|
* @returns Array of parsed acceptance criteria
|
|
46
60
|
*/
|
|
@@ -6,6 +6,12 @@
|
|
|
6
6
|
* Also supports alternate formats: `- [ ] **B2:** Description`
|
|
7
7
|
* And bold-wrapped format: `- [ ] **AC-1: Description**`
|
|
8
8
|
*
|
|
9
|
+
* Bare checkbox items (`- [ ] Some requirement`, no ID prefix) are also
|
|
10
|
+
* honored, but ONLY under an explicit `## Acceptance Criteria` heading, where
|
|
11
|
+
* they receive synthesized stable IDs. Human-authored issues rarely prefix
|
|
12
|
+
* their ACs with IDs, so without this every hand-written issue parsed to zero
|
|
13
|
+
* ACs — blinding every downstream AC consumer (#850).
|
|
14
|
+
*
|
|
9
15
|
* @example
|
|
10
16
|
* ```typescript
|
|
11
17
|
* import { parseAcceptanceCriteria } from './ac-parser';
|
|
@@ -33,6 +39,9 @@ import { createAcceptanceCriterion, createAcceptanceCriteria, } from "./workflow
|
|
|
33
39
|
* - `- [ ] **B2:** Description`
|
|
34
40
|
* - `- [ ] **AC1:** Description`
|
|
35
41
|
* - `- [ ] **AC-1: Description**` (bold wraps ID + description)
|
|
42
|
+
* - `- [ ] **AC-1** Description` (bold ID, no colon)
|
|
43
|
+
* - `- [ ] **AC-1**: Description` (colon outside the bold)
|
|
44
|
+
* - `- [ ] AC-1: Description`
|
|
36
45
|
*/
|
|
37
46
|
const AC_PATTERNS = [
|
|
38
47
|
// Pattern 1: `- [ ] **AC-1:** Description` or `- [x] **AC-1:** Description`
|
|
@@ -43,7 +52,41 @@ const AC_PATTERNS = [
|
|
|
43
52
|
/^-\s*\[[x\s]\]\s*\*\*([A-Za-z]+-?\d+):\s*(.+?)\*\*\s*(.*)$/gim,
|
|
44
53
|
// Pattern 4: `- [ ] AC-1: Description` (no bold)
|
|
45
54
|
/^-\s*\[[x\s]\]\s*([A-Za-z]+-?\d+):\s*(.+)$/gim,
|
|
55
|
+
// Pattern 5: `- [ ] **AC-1** Description` / `- [ ] **AC-1**: Description` (#808)
|
|
56
|
+
//
|
|
57
|
+
// The colon-less form is a very common authoring style, and before this
|
|
58
|
+
// pattern existed it matched nothing at all — an issue written this way
|
|
59
|
+
// parsed as ZERO acceptance criteria, silently, with no warning anywhere
|
|
60
|
+
// downstream (#803's five ACs were written exactly like this).
|
|
61
|
+
//
|
|
62
|
+
// The trailing `:?` also absorbs a colon placed *outside* the bold, which
|
|
63
|
+
// would otherwise land in the description as a leading ": ".
|
|
64
|
+
//
|
|
65
|
+
// Deliberately requires the bold markers. A bare `- [ ] AC1 something` is
|
|
66
|
+
// ambiguous against ordinary checklist prose, so widening that far would
|
|
67
|
+
// trade a silent miss for silent false positives. The `\d+` at the end of
|
|
68
|
+
// the ID keeps non-identifier bold labels (`**Note**`, `**Verify**`) out.
|
|
69
|
+
/^-\s*\[[x\s]\]\s*\*\*([A-Za-z]+-?\d+)\*\*:?\s*(.+)$/gim,
|
|
46
70
|
];
|
|
71
|
+
/**
|
|
72
|
+
* Matches an `## Acceptance Criteria` heading (any level, case-insensitive).
|
|
73
|
+
*
|
|
74
|
+
* Real issues vary the casing — #703 uses `## Acceptance criteria` (lowercase
|
|
75
|
+
* "criteria") — so the match must be case-insensitive. The trailing `\b` lets
|
|
76
|
+
* a suffix follow ("Acceptance Criteria (v2)") without demanding an exact end.
|
|
77
|
+
*/
|
|
78
|
+
const AC_HEADING_RE = /^#{1,6}\s+acceptance\s+criteria\b/i;
|
|
79
|
+
/**
|
|
80
|
+
* Matches any markdown ATX heading. Used to detect when the AC section ends —
|
|
81
|
+
* the next heading of any level closes it, mirroring `parseNonGoals` in
|
|
82
|
+
* `ready-gate.ts`.
|
|
83
|
+
*/
|
|
84
|
+
const HEADING_RE = /^#{1,6}\s+/;
|
|
85
|
+
/**
|
|
86
|
+
* Matches a bare checkbox item with no ID prefix: `- [ ] Some requirement`.
|
|
87
|
+
* Honored only inside the AC section (see {@link parseAcceptanceCriteria}).
|
|
88
|
+
*/
|
|
89
|
+
const BARE_CHECKBOX_RE = /^-\s*\[[x\s]\]\s*(.+)$/i;
|
|
47
90
|
/**
|
|
48
91
|
* Keywords that suggest verification method
|
|
49
92
|
*/
|
|
@@ -122,22 +165,73 @@ function parseACLine(line) {
|
|
|
122
165
|
* - `- [ ] **AC-1:** Description`
|
|
123
166
|
* - `- [ ] **B2:** Description`
|
|
124
167
|
* - `- [ ] **AC-1: Description**` (bold wraps ID + description)
|
|
168
|
+
* - `- [ ] **AC-1** Description` (bold ID, no colon)
|
|
169
|
+
* - `- [ ] **AC-1**: Description` (colon outside the bold)
|
|
125
170
|
* - `- [ ] AC-1: Description`
|
|
126
171
|
*
|
|
172
|
+
* Bare checkbox items without an ID prefix (`- [ ] Some requirement`) are also
|
|
173
|
+
* parsed, but ONLY under an explicit `## Acceptance Criteria` heading, where
|
|
174
|
+
* they receive synthesized stable IDs (`AC-1`, `AC-2`, ...). This keeps
|
|
175
|
+
* unrelated checklists elsewhere in the body (Open Questions, Test Plan) from
|
|
176
|
+
* being misread as ACs, while letting ordinary human-written issues parse.
|
|
177
|
+
*
|
|
127
178
|
* @param issueBody - The full GitHub issue body markdown
|
|
128
179
|
* @returns Array of parsed acceptance criteria
|
|
129
180
|
*/
|
|
130
181
|
export function parseAcceptanceCriteria(issueBody) {
|
|
131
182
|
const criteria = [];
|
|
132
183
|
const seenIds = new Set();
|
|
133
|
-
|
|
184
|
+
const push = (id, description) => {
|
|
185
|
+
if (seenIds.has(id))
|
|
186
|
+
return;
|
|
187
|
+
seenIds.add(id);
|
|
188
|
+
criteria.push(createAcceptanceCriterion(id, description, inferVerificationMethod(description)));
|
|
189
|
+
};
|
|
190
|
+
// Split into lines and process each. `inAcSection` tracks whether the
|
|
191
|
+
// current line falls under an `## Acceptance Criteria` heading; it toggles on
|
|
192
|
+
// every heading and closes at the next heading of any level (same boundary
|
|
193
|
+
// rule as `parseNonGoals` in ready-gate.ts). `bareCount` numbers synthesized
|
|
194
|
+
// IDs for bare checkboxes in appearance order.
|
|
134
195
|
const lines = issueBody.split("\n");
|
|
196
|
+
let inAcSection = false;
|
|
197
|
+
let bareCount = 0;
|
|
198
|
+
// Pre-scan for explicit IDs anywhere in the body. Synthesis must skip IDs
|
|
199
|
+
// owned by explicit markers even when the marker appears on a LATER line —
|
|
200
|
+
// otherwise a bare checkbox listed before `**AC-1:**` under the same heading
|
|
201
|
+
// synthesizes AC-1 first and the author's explicit AC-1 is silently dropped
|
|
202
|
+
// by the first-occurrence dedupe.
|
|
203
|
+
const explicitIds = new Set();
|
|
135
204
|
for (const line of lines) {
|
|
136
205
|
const parsed = parseACLine(line);
|
|
137
|
-
if (parsed
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
206
|
+
if (parsed)
|
|
207
|
+
explicitIds.add(parsed.id);
|
|
208
|
+
}
|
|
209
|
+
for (const line of lines) {
|
|
210
|
+
if (HEADING_RE.test(line)) {
|
|
211
|
+
inAcSection = AC_HEADING_RE.test(line);
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
// Existing ID-prefixed patterns run on every line, regardless of section,
|
|
215
|
+
// so previously-parsable issues are unaffected (AC-4).
|
|
216
|
+
const parsed = parseACLine(line);
|
|
217
|
+
if (parsed) {
|
|
218
|
+
push(parsed.id, parsed.description);
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
// Bare-checkbox fallback: only inside the AC section (AC-1/AC-2).
|
|
222
|
+
if (inAcSection) {
|
|
223
|
+
const bare = line.match(BARE_CHECKBOX_RE);
|
|
224
|
+
const description = bare?.[1].trim();
|
|
225
|
+
if (description) {
|
|
226
|
+
// Synthesize `AC-<n>`, skipping any ID already taken by an explicit
|
|
227
|
+
// marker — before OR after this line — so a synthesized ID can never
|
|
228
|
+
// collide with (and be silently dropped against) a hand-written one.
|
|
229
|
+
let id;
|
|
230
|
+
do {
|
|
231
|
+
id = `AC-${++bareCount}`;
|
|
232
|
+
} while (seenIds.has(id) || explicitIds.has(id));
|
|
233
|
+
push(id, description);
|
|
234
|
+
}
|
|
141
235
|
}
|
|
142
236
|
}
|
|
143
237
|
return criteria;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic rendering for `/assess` output (#823).
|
|
3
|
+
*
|
|
4
|
+
* `types.ts` owns the contract, `renderer.ts` owns the geometry. Neither touches
|
|
5
|
+
* TTY state, ANSI, or I/O — see the header comment in `renderer.ts` for why that
|
|
6
|
+
* rules out the `cli-ui.ts` helpers.
|
|
7
|
+
*/
|
|
8
|
+
export { AssessActionSchema, AssessChainSchema, AssessCleanupSchema, AssessCommandSchema, AssessFlagSchema, AssessIssueSchema, AssessResultSchema, AssessResultValidationError, AssessWarningSchema, parseAssessResult, } from "./types.js";
|
|
9
|
+
export type { AssessAction, AssessChain, AssessCleanup, AssessCommand, AssessFlag, AssessIssue, AssessResult, AssessWarning, } from "./types.js";
|
|
10
|
+
export { GEOMETRY, render, renderBatch, renderSingle } from "./renderer.js";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic rendering for `/assess` output (#823).
|
|
3
|
+
*
|
|
4
|
+
* `types.ts` owns the contract, `renderer.ts` owns the geometry. Neither touches
|
|
5
|
+
* TTY state, ANSI, or I/O — see the header comment in `renderer.ts` for why that
|
|
6
|
+
* rules out the `cli-ui.ts` helpers.
|
|
7
|
+
*/
|
|
8
|
+
export { AssessActionSchema, AssessChainSchema, AssessCleanupSchema, AssessCommandSchema, AssessFlagSchema, AssessIssueSchema, AssessResultSchema, AssessResultValidationError, AssessWarningSchema, parseAssessResult, } from "./types.js";
|
|
9
|
+
export { GEOMETRY, render, renderBatch, renderSingle } from "./renderer.js";
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic renderer for `/assess` output (#823).
|
|
3
|
+
*
|
|
4
|
+
* ## Why this module exists
|
|
5
|
+
*
|
|
6
|
+
* `/assess` was asked to hand-draw an aligned ASCII dashboard inside a prompt.
|
|
7
|
+
* It did two things wrong, both recurring: it silently substituted a prose
|
|
8
|
+
* summary for the block entirely, and when it did draw the table the columns
|
|
9
|
+
* drifted (every worked example in `SKILL.md` had its header offset from its own
|
|
10
|
+
* data rows). Both are the same root cause — deterministic formatting done by
|
|
11
|
+
* hand. This module takes the arithmetic away from the model. The model keeps
|
|
12
|
+
* the judgment; a tool call, which is observable in the transcript, produces the
|
|
13
|
+
* geometry.
|
|
14
|
+
*
|
|
15
|
+
* ## Why not `cli-ui.ts`
|
|
16
|
+
*
|
|
17
|
+
* Its `table()` / `box()` / `divider()` / `sectionHeader()` helpers are the
|
|
18
|
+
* obvious first instinct and the wrong tool. They emit ANSI via `chalk`, gate on
|
|
19
|
+
* `config.isTTY` / `config.jsonMode` (so they silently degrade when stdout is a
|
|
20
|
+
* pipe — which it always is here, since this runs from a Bash call), and
|
|
21
|
+
* `table()` delegates to `cli-table3`'s bordered grid. This output lands in a
|
|
22
|
+
* chat transcript *and* is posted to GitHub, then re-parsed by
|
|
23
|
+
* `assess-comment-parser.ts`. It must be byte-stable, ANSI-free, and
|
|
24
|
+
* copy-pasteable.
|
|
25
|
+
*
|
|
26
|
+
* The only thing shared with the terminal UI is the `string-width` dependency.
|
|
27
|
+
* The module is otherwise modeled on `src/lib/cli-ui/format.ts`: pure
|
|
28
|
+
* deterministic string formatting, no TTY state, no I/O.
|
|
29
|
+
*/
|
|
30
|
+
import type { AssessResult } from "./types.js";
|
|
31
|
+
/** Column at which the `Reason` field starts, given whether `ACs` is shown. */
|
|
32
|
+
declare function reasonCol(withAcs: boolean): number;
|
|
33
|
+
/** Width of the `Reason` field — whatever is left before {@link RUN_COL}. */
|
|
34
|
+
declare function reasonWidth(withAcs: boolean): number;
|
|
35
|
+
/**
|
|
36
|
+
* Render the batch dashboard: table → `Commands:` → annotations → markers.
|
|
37
|
+
*
|
|
38
|
+
* Every section is conditional (Section Visibility Rules). A section that has no
|
|
39
|
+
* content takes its adjacent separator with it, so an all-clear batch renders as
|
|
40
|
+
* table → separator → commands → separator → markers and nothing else.
|
|
41
|
+
*/
|
|
42
|
+
export declare function renderBatch(result: AssessResult): string;
|
|
43
|
+
/**
|
|
44
|
+
* Render the single-issue assessment for one verdict.
|
|
45
|
+
*
|
|
46
|
+
* PROCEED and REWRITE templates define a `⚠` region between two trailing
|
|
47
|
+
* separators. CLOSE / CLARIFY / PARK / MERGE do not, so a carried warning
|
|
48
|
+
* becomes its own separator-delimited block immediately above the markers — the
|
|
49
|
+
* one case where a posted comment extends a slot-less template.
|
|
50
|
+
*/
|
|
51
|
+
export declare function renderSingle(result: AssessResult): string;
|
|
52
|
+
/** Dispatch on `mode`. The entry point the CLI subcommand calls. */
|
|
53
|
+
export declare function render(result: AssessResult): string;
|
|
54
|
+
/**
|
|
55
|
+
* Geometry constants, exported for tests and for documenting the layout.
|
|
56
|
+
* Consumers should treat these as read-only.
|
|
57
|
+
*/
|
|
58
|
+
export declare const GEOMETRY: {
|
|
59
|
+
readonly RUN_COL: 47;
|
|
60
|
+
readonly SEPARATOR_WIDTH: 64;
|
|
61
|
+
readonly reasonCol: typeof reasonCol;
|
|
62
|
+
readonly reasonWidth: typeof reasonWidth;
|
|
63
|
+
};
|
|
64
|
+
export {};
|