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
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schema for `/assess` rendered output (#823).
|
|
3
|
+
*
|
|
4
|
+
* The `/assess` skill produces judgment (triage verdicts); this schema is the
|
|
5
|
+
* contract it hands to the renderer, which produces geometry. Splitting the two
|
|
6
|
+
* is the point of #823: the model stopped emitting the output block at all, and
|
|
7
|
+
* when it did emit one the columns drifted, because deterministic formatting was
|
|
8
|
+
* being done by hand in a prompt.
|
|
9
|
+
*
|
|
10
|
+
* Modeled on `src/lib/scope/types.ts` (the in-repo precedent for a zod schema
|
|
11
|
+
* module). Deliberately carries no rendering logic — see `./renderer.ts`.
|
|
12
|
+
*/
|
|
13
|
+
import { z } from "zod";
|
|
14
|
+
/**
|
|
15
|
+
* The fixed action vocabulary from `skills/assess/SKILL.md`. Every assessed
|
|
16
|
+
* issue gets exactly one.
|
|
17
|
+
*/
|
|
18
|
+
export declare const AssessActionSchema: z.ZodEnum<{
|
|
19
|
+
PROCEED: "PROCEED";
|
|
20
|
+
CLOSE: "CLOSE";
|
|
21
|
+
MERGE: "MERGE";
|
|
22
|
+
REWRITE: "REWRITE";
|
|
23
|
+
CLARIFY: "CLARIFY";
|
|
24
|
+
PARK: "PARK";
|
|
25
|
+
}>;
|
|
26
|
+
export type AssessAction = z.infer<typeof AssessActionSchema>;
|
|
27
|
+
/**
|
|
28
|
+
* A `sequant` invocation. `args` excludes the command prefix — the renderer
|
|
29
|
+
* prepends the single resolved `commandPrefix` so one assessment can never mix
|
|
30
|
+
* `sequant` and `npx sequant` (Commands Block Rule #9).
|
|
31
|
+
*/
|
|
32
|
+
export declare const AssessCommandSchema: z.ZodObject<{
|
|
33
|
+
args: z.ZodString;
|
|
34
|
+
comment: z.ZodOptional<z.ZodString>;
|
|
35
|
+
}, z.core.$strict>;
|
|
36
|
+
export type AssessCommand = z.infer<typeof AssessCommandSchema>;
|
|
37
|
+
/**
|
|
38
|
+
* A `Cleanup:` entry. These are `git`/`gh` commands, not `sequant` ones, so
|
|
39
|
+
* they carry no prefix and are emitted verbatim.
|
|
40
|
+
*/
|
|
41
|
+
export declare const AssessCleanupSchema: z.ZodObject<{
|
|
42
|
+
command: z.ZodString;
|
|
43
|
+
reason: z.ZodOptional<z.ZodString>;
|
|
44
|
+
}, z.core.$strict>;
|
|
45
|
+
export type AssessCleanup = z.infer<typeof AssessCleanupSchema>;
|
|
46
|
+
/** A `Flags:` entry — one distinct flag plus its one-line justification. */
|
|
47
|
+
export declare const AssessFlagSchema: z.ZodObject<{
|
|
48
|
+
flag: z.ZodString;
|
|
49
|
+
reason: z.ZodString;
|
|
50
|
+
}, z.core.$strict>;
|
|
51
|
+
export type AssessFlag = z.infer<typeof AssessFlagSchema>;
|
|
52
|
+
/**
|
|
53
|
+
* A `Considered:` entry — a flag or topology (`--chain`, `--testgen`,
|
|
54
|
+
* `--security-review`, …) whose trigger was evaluated and **not** met, plus the
|
|
55
|
+
* one-line reason it was not applied. Restores the why-not reasoning the
|
|
56
|
+
* original `/solve` format carried ("Also consider:") that the v3.0 redesign
|
|
57
|
+
* dropped and #522 only partially restored.
|
|
58
|
+
*/
|
|
59
|
+
export declare const AssessConsideredSchema: z.ZodObject<{
|
|
60
|
+
flag: z.ZodString;
|
|
61
|
+
reason: z.ZodString;
|
|
62
|
+
}, z.core.$strict>;
|
|
63
|
+
export type AssessConsidered = z.infer<typeof AssessConsideredSchema>;
|
|
64
|
+
/**
|
|
65
|
+
* A `⚠` warning. In batch mode `issue` scopes it to a row (`⚠ #458 ...`); in a
|
|
66
|
+
* posted single-mode comment the number is dropped because the comment is
|
|
67
|
+
* already scoped to that issue.
|
|
68
|
+
*/
|
|
69
|
+
export declare const AssessWarningSchema: z.ZodObject<{
|
|
70
|
+
issue: z.ZodOptional<z.ZodNumber>;
|
|
71
|
+
text: z.ZodString;
|
|
72
|
+
}, z.core.$strict>;
|
|
73
|
+
export type AssessWarning = z.infer<typeof AssessWarningSchema>;
|
|
74
|
+
/**
|
|
75
|
+
* One assessed issue. Batch mode consumes the table fields; single mode
|
|
76
|
+
* consumes the detail fields. Cross-field requirements are enforced per-mode in
|
|
77
|
+
* {@link AssessResultSchema}'s refinement rather than by making fields
|
|
78
|
+
* unconditionally required, so a batch payload is not forced to carry titles it
|
|
79
|
+
* never renders.
|
|
80
|
+
*/
|
|
81
|
+
export declare const AssessIssueSchema: z.ZodObject<{
|
|
82
|
+
number: z.ZodNumber;
|
|
83
|
+
action: z.ZodEnum<{
|
|
84
|
+
PROCEED: "PROCEED";
|
|
85
|
+
CLOSE: "CLOSE";
|
|
86
|
+
MERGE: "MERGE";
|
|
87
|
+
REWRITE: "REWRITE";
|
|
88
|
+
CLARIFY: "CLARIFY";
|
|
89
|
+
PARK: "PARK";
|
|
90
|
+
}>;
|
|
91
|
+
reason: z.ZodString;
|
|
92
|
+
run: z.ZodOptional<z.ZodString>;
|
|
93
|
+
acCount: z.ZodOptional<z.ZodNumber>;
|
|
94
|
+
phases: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
95
|
+
qualityLoop: z.ZodOptional<z.ZodBoolean>;
|
|
96
|
+
title: z.ZodOptional<z.ZodString>;
|
|
97
|
+
state: z.ZodOptional<z.ZodString>;
|
|
98
|
+
labels: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
99
|
+
command: z.ZodOptional<z.ZodObject<{
|
|
100
|
+
args: z.ZodString;
|
|
101
|
+
comment: z.ZodOptional<z.ZodString>;
|
|
102
|
+
}, z.core.$strict>>;
|
|
103
|
+
supersession: z.ZodOptional<z.ZodString>;
|
|
104
|
+
warnings: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
105
|
+
flags: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
106
|
+
flag: z.ZodString;
|
|
107
|
+
reason: z.ZodString;
|
|
108
|
+
}, z.core.$strict>>>;
|
|
109
|
+
considered: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
110
|
+
flag: z.ZodString;
|
|
111
|
+
reason: z.ZodString;
|
|
112
|
+
}, z.core.$strict>>>;
|
|
113
|
+
cleanup: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
114
|
+
command: z.ZodString;
|
|
115
|
+
reason: z.ZodOptional<z.ZodString>;
|
|
116
|
+
}, z.core.$strict>>>;
|
|
117
|
+
mergeTarget: z.ZodOptional<z.ZodNumber>;
|
|
118
|
+
scopeSelf: z.ZodOptional<z.ZodString>;
|
|
119
|
+
scopeTarget: z.ZodOptional<z.ZodString>;
|
|
120
|
+
need: z.ZodOptional<z.ZodString>;
|
|
121
|
+
needDetail: z.ZodOptional<z.ZodString>;
|
|
122
|
+
resumeAfter: z.ZodOptional<z.ZodString>;
|
|
123
|
+
}, z.core.$strict>;
|
|
124
|
+
export type AssessIssue = z.infer<typeof AssessIssueSchema>;
|
|
125
|
+
/** `Chain:` suggestion — an alternative execution topology, never auto-applied. */
|
|
126
|
+
export declare const AssessChainSchema: z.ZodObject<{
|
|
127
|
+
args: z.ZodString;
|
|
128
|
+
reason: z.ZodString;
|
|
129
|
+
}, z.core.$strict>;
|
|
130
|
+
export type AssessChain = z.infer<typeof AssessChainSchema>;
|
|
131
|
+
/**
|
|
132
|
+
* The complete payload the `/assess` skill hands to the renderer.
|
|
133
|
+
*
|
|
134
|
+
* `.strict()` throughout is deliberate: a typo'd key is a silent data-loss bug
|
|
135
|
+
* in a hand-built JSON payload, and naming the unknown key is exactly the
|
|
136
|
+
* actionable error AC-2 asks for.
|
|
137
|
+
*/
|
|
138
|
+
export declare const AssessResultSchema: z.ZodObject<{
|
|
139
|
+
mode: z.ZodEnum<{
|
|
140
|
+
single: "single";
|
|
141
|
+
batch: "batch";
|
|
142
|
+
}>;
|
|
143
|
+
commandPrefix: z.ZodString;
|
|
144
|
+
issues: z.ZodArray<z.ZodObject<{
|
|
145
|
+
number: z.ZodNumber;
|
|
146
|
+
action: z.ZodEnum<{
|
|
147
|
+
PROCEED: "PROCEED";
|
|
148
|
+
CLOSE: "CLOSE";
|
|
149
|
+
MERGE: "MERGE";
|
|
150
|
+
REWRITE: "REWRITE";
|
|
151
|
+
CLARIFY: "CLARIFY";
|
|
152
|
+
PARK: "PARK";
|
|
153
|
+
}>;
|
|
154
|
+
reason: z.ZodString;
|
|
155
|
+
run: z.ZodOptional<z.ZodString>;
|
|
156
|
+
acCount: z.ZodOptional<z.ZodNumber>;
|
|
157
|
+
phases: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
158
|
+
qualityLoop: z.ZodOptional<z.ZodBoolean>;
|
|
159
|
+
title: z.ZodOptional<z.ZodString>;
|
|
160
|
+
state: z.ZodOptional<z.ZodString>;
|
|
161
|
+
labels: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
162
|
+
command: z.ZodOptional<z.ZodObject<{
|
|
163
|
+
args: z.ZodString;
|
|
164
|
+
comment: z.ZodOptional<z.ZodString>;
|
|
165
|
+
}, z.core.$strict>>;
|
|
166
|
+
supersession: z.ZodOptional<z.ZodString>;
|
|
167
|
+
warnings: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
168
|
+
flags: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
169
|
+
flag: z.ZodString;
|
|
170
|
+
reason: z.ZodString;
|
|
171
|
+
}, z.core.$strict>>>;
|
|
172
|
+
considered: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
173
|
+
flag: z.ZodString;
|
|
174
|
+
reason: z.ZodString;
|
|
175
|
+
}, z.core.$strict>>>;
|
|
176
|
+
cleanup: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
177
|
+
command: z.ZodString;
|
|
178
|
+
reason: z.ZodOptional<z.ZodString>;
|
|
179
|
+
}, z.core.$strict>>>;
|
|
180
|
+
mergeTarget: z.ZodOptional<z.ZodNumber>;
|
|
181
|
+
scopeSelf: z.ZodOptional<z.ZodString>;
|
|
182
|
+
scopeTarget: z.ZodOptional<z.ZodString>;
|
|
183
|
+
need: z.ZodOptional<z.ZodString>;
|
|
184
|
+
needDetail: z.ZodOptional<z.ZodString>;
|
|
185
|
+
resumeAfter: z.ZodOptional<z.ZodString>;
|
|
186
|
+
}, z.core.$strict>>;
|
|
187
|
+
commands: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
188
|
+
args: z.ZodString;
|
|
189
|
+
comment: z.ZodOptional<z.ZodString>;
|
|
190
|
+
}, z.core.$strict>>>;
|
|
191
|
+
orders: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
192
|
+
warnings: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
193
|
+
issue: z.ZodOptional<z.ZodNumber>;
|
|
194
|
+
text: z.ZodString;
|
|
195
|
+
}, z.core.$strict>>>;
|
|
196
|
+
chain: z.ZodOptional<z.ZodObject<{
|
|
197
|
+
args: z.ZodString;
|
|
198
|
+
reason: z.ZodString;
|
|
199
|
+
}, z.core.$strict>>;
|
|
200
|
+
flags: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
201
|
+
flag: z.ZodString;
|
|
202
|
+
reason: z.ZodString;
|
|
203
|
+
}, z.core.$strict>>>;
|
|
204
|
+
considered: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
205
|
+
flag: z.ZodString;
|
|
206
|
+
reason: z.ZodString;
|
|
207
|
+
}, z.core.$strict>>>;
|
|
208
|
+
cleanup: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
209
|
+
command: z.ZodString;
|
|
210
|
+
reason: z.ZodOptional<z.ZodString>;
|
|
211
|
+
}, z.core.$strict>>>;
|
|
212
|
+
}, z.core.$strict>;
|
|
213
|
+
export type AssessResult = z.infer<typeof AssessResultSchema>;
|
|
214
|
+
/** Raised by {@link parseAssessResult} when validation fails. */
|
|
215
|
+
export declare class AssessResultValidationError extends Error {
|
|
216
|
+
readonly problems: string[];
|
|
217
|
+
constructor(message: string, problems: string[]);
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Validate an untrusted payload against {@link AssessResultSchema}.
|
|
221
|
+
*
|
|
222
|
+
* @throws {AssessResultValidationError} naming every offending field.
|
|
223
|
+
*/
|
|
224
|
+
export declare function parseAssessResult(input: unknown): AssessResult;
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schema for `/assess` rendered output (#823).
|
|
3
|
+
*
|
|
4
|
+
* The `/assess` skill produces judgment (triage verdicts); this schema is the
|
|
5
|
+
* contract it hands to the renderer, which produces geometry. Splitting the two
|
|
6
|
+
* is the point of #823: the model stopped emitting the output block at all, and
|
|
7
|
+
* when it did emit one the columns drifted, because deterministic formatting was
|
|
8
|
+
* being done by hand in a prompt.
|
|
9
|
+
*
|
|
10
|
+
* Modeled on `src/lib/scope/types.ts` (the in-repo precedent for a zod schema
|
|
11
|
+
* module). Deliberately carries no rendering logic — see `./renderer.ts`.
|
|
12
|
+
*/
|
|
13
|
+
import { z } from "zod";
|
|
14
|
+
/**
|
|
15
|
+
* The fixed action vocabulary from `skills/assess/SKILL.md`. Every assessed
|
|
16
|
+
* issue gets exactly one.
|
|
17
|
+
*/
|
|
18
|
+
export const AssessActionSchema = z.enum([
|
|
19
|
+
"PROCEED",
|
|
20
|
+
"CLOSE",
|
|
21
|
+
"MERGE",
|
|
22
|
+
"REWRITE",
|
|
23
|
+
"CLARIFY",
|
|
24
|
+
"PARK",
|
|
25
|
+
]);
|
|
26
|
+
/**
|
|
27
|
+
* A `sequant` invocation. `args` excludes the command prefix — the renderer
|
|
28
|
+
* prepends the single resolved `commandPrefix` so one assessment can never mix
|
|
29
|
+
* `sequant` and `npx sequant` (Commands Block Rule #9).
|
|
30
|
+
*/
|
|
31
|
+
export const AssessCommandSchema = z
|
|
32
|
+
.object({
|
|
33
|
+
/** Everything after the prefix, e.g. `run 820 819 -Q`. */
|
|
34
|
+
args: z.string().min(1),
|
|
35
|
+
/** Trailing `# ...` annotation, e.g. `resume`, `restart`, `fresh start`. */
|
|
36
|
+
comment: z.string().optional(),
|
|
37
|
+
})
|
|
38
|
+
.strict();
|
|
39
|
+
/**
|
|
40
|
+
* A `Cleanup:` entry. These are `git`/`gh` commands, not `sequant` ones, so
|
|
41
|
+
* they carry no prefix and are emitted verbatim.
|
|
42
|
+
*/
|
|
43
|
+
export const AssessCleanupSchema = z
|
|
44
|
+
.object({
|
|
45
|
+
command: z.string().min(1),
|
|
46
|
+
reason: z.string().optional(),
|
|
47
|
+
})
|
|
48
|
+
.strict();
|
|
49
|
+
/** A `Flags:` entry — one distinct flag plus its one-line justification. */
|
|
50
|
+
export const AssessFlagSchema = z
|
|
51
|
+
.object({
|
|
52
|
+
flag: z.string().min(1),
|
|
53
|
+
reason: z.string().min(1),
|
|
54
|
+
})
|
|
55
|
+
.strict();
|
|
56
|
+
/**
|
|
57
|
+
* A `Considered:` entry — a flag or topology (`--chain`, `--testgen`,
|
|
58
|
+
* `--security-review`, …) whose trigger was evaluated and **not** met, plus the
|
|
59
|
+
* one-line reason it was not applied. Restores the why-not reasoning the
|
|
60
|
+
* original `/solve` format carried ("Also consider:") that the v3.0 redesign
|
|
61
|
+
* dropped and #522 only partially restored.
|
|
62
|
+
*/
|
|
63
|
+
export const AssessConsideredSchema = AssessFlagSchema;
|
|
64
|
+
/**
|
|
65
|
+
* A `⚠` warning. In batch mode `issue` scopes it to a row (`⚠ #458 ...`); in a
|
|
66
|
+
* posted single-mode comment the number is dropped because the comment is
|
|
67
|
+
* already scoped to that issue.
|
|
68
|
+
*/
|
|
69
|
+
export const AssessWarningSchema = z
|
|
70
|
+
.object({
|
|
71
|
+
issue: z.number().int().positive().optional(),
|
|
72
|
+
text: z.string().min(1),
|
|
73
|
+
})
|
|
74
|
+
.strict();
|
|
75
|
+
/**
|
|
76
|
+
* One assessed issue. Batch mode consumes the table fields; single mode
|
|
77
|
+
* consumes the detail fields. Cross-field requirements are enforced per-mode in
|
|
78
|
+
* {@link AssessResultSchema}'s refinement rather than by making fields
|
|
79
|
+
* unconditionally required, so a batch payload is not forced to carry titles it
|
|
80
|
+
* never renders.
|
|
81
|
+
*/
|
|
82
|
+
export const AssessIssueSchema = z
|
|
83
|
+
.object({
|
|
84
|
+
number: z.number().int().positive(),
|
|
85
|
+
action: AssessActionSchema,
|
|
86
|
+
/** Short `Reason` column text. The only column the renderer truncates. */
|
|
87
|
+
reason: z.string().min(1),
|
|
88
|
+
/** `Run` column value — a workflow (`spec → exec → qa`) or a symbol (`‖`). */
|
|
89
|
+
run: z.string().min(1).optional(),
|
|
90
|
+
/** Drives the conditional `ACs` column; omit when the issue has no checkbox ACs. */
|
|
91
|
+
acCount: z.number().int().nonnegative().optional(),
|
|
92
|
+
/** Resolved workflow, recorded in the HTML marker regardless of shorthand flags. */
|
|
93
|
+
phases: z.array(z.string().min(1)).optional(),
|
|
94
|
+
qualityLoop: z.boolean().optional(),
|
|
95
|
+
// --- single mode / posted comment ---
|
|
96
|
+
title: z.string().min(1).optional(),
|
|
97
|
+
state: z.string().min(1).optional(),
|
|
98
|
+
labels: z.array(z.string().min(1)).optional(),
|
|
99
|
+
/** This issue's own single-issue invocation (PROCEED / REWRITE). */
|
|
100
|
+
command: AssessCommandSchema.optional(),
|
|
101
|
+
/** `buildSupersessionHeader(priors)` output, emitted above the verdict line. */
|
|
102
|
+
supersession: z.string().min(1).optional(),
|
|
103
|
+
/** Per-issue warnings with the leading `#N` already dropped. */
|
|
104
|
+
warnings: z.array(z.string().min(1)).optional(),
|
|
105
|
+
flags: z.array(AssessFlagSchema).optional(),
|
|
106
|
+
/** Flags evaluated but not applied, each with its why-not reason. */
|
|
107
|
+
considered: z.array(AssessConsideredSchema).optional(),
|
|
108
|
+
cleanup: z.array(AssessCleanupSchema).optional(),
|
|
109
|
+
// --- verdict-specific ---
|
|
110
|
+
/** MERGE: the issue absorbing this one. */
|
|
111
|
+
mergeTarget: z.number().int().positive().optional(),
|
|
112
|
+
/** MERGE: this issue's scope summary. */
|
|
113
|
+
scopeSelf: z.string().min(1).optional(),
|
|
114
|
+
/** MERGE: the target's scope summary. */
|
|
115
|
+
scopeTarget: z.string().min(1).optional(),
|
|
116
|
+
/** CLARIFY: the specific information required. */
|
|
117
|
+
need: z.string().min(1).optional(),
|
|
118
|
+
/** CLARIFY: why the gap blocks work. */
|
|
119
|
+
needDetail: z.string().min(1).optional(),
|
|
120
|
+
/** PARK: the condition that unblocks this issue. */
|
|
121
|
+
resumeAfter: z.string().min(1).optional(),
|
|
122
|
+
})
|
|
123
|
+
.strict();
|
|
124
|
+
/** `Chain:` suggestion — an alternative execution topology, never auto-applied. */
|
|
125
|
+
export const AssessChainSchema = z
|
|
126
|
+
.object({
|
|
127
|
+
args: z.string().min(1),
|
|
128
|
+
reason: z.string().min(1),
|
|
129
|
+
})
|
|
130
|
+
.strict();
|
|
131
|
+
/**
|
|
132
|
+
* The complete payload the `/assess` skill hands to the renderer.
|
|
133
|
+
*
|
|
134
|
+
* `.strict()` throughout is deliberate: a typo'd key is a silent data-loss bug
|
|
135
|
+
* in a hand-built JSON payload, and naming the unknown key is exactly the
|
|
136
|
+
* actionable error AC-2 asks for.
|
|
137
|
+
*/
|
|
138
|
+
export const AssessResultSchema = z
|
|
139
|
+
.object({
|
|
140
|
+
mode: z.enum(["batch", "single"]),
|
|
141
|
+
/** Resolved in the skill's Step-1 probe: `sequant` or `npx sequant`. */
|
|
142
|
+
commandPrefix: z.string().min(1),
|
|
143
|
+
issues: z.array(AssessIssueSchema).min(1),
|
|
144
|
+
// --- batch-only sections ---
|
|
145
|
+
commands: z.array(AssessCommandSchema).optional(),
|
|
146
|
+
/** `Order:` annotations, each carrying dependency reasoning. */
|
|
147
|
+
orders: z.array(z.string().min(1)).optional(),
|
|
148
|
+
warnings: z.array(AssessWarningSchema).optional(),
|
|
149
|
+
chain: AssessChainSchema.optional(),
|
|
150
|
+
flags: z.array(AssessFlagSchema).optional(),
|
|
151
|
+
/** Flags evaluated but not applied, each with its why-not reason. */
|
|
152
|
+
considered: z.array(AssessConsideredSchema).optional(),
|
|
153
|
+
cleanup: z.array(AssessCleanupSchema).optional(),
|
|
154
|
+
})
|
|
155
|
+
.strict()
|
|
156
|
+
.superRefine((result, ctx) => {
|
|
157
|
+
if (result.mode === "batch") {
|
|
158
|
+
result.issues.forEach((issue, i) => {
|
|
159
|
+
if (!issue.run) {
|
|
160
|
+
ctx.addIssue({
|
|
161
|
+
code: "custom",
|
|
162
|
+
path: ["issues", i, "run"],
|
|
163
|
+
message: `batch mode requires a Run column value for issue #${issue.number}`,
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
if (result.issues.length !== 1) {
|
|
170
|
+
ctx.addIssue({
|
|
171
|
+
code: "custom",
|
|
172
|
+
path: ["issues"],
|
|
173
|
+
message: `single mode renders exactly one issue, received ${result.issues.length}`,
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
result.issues.forEach((issue, i) => {
|
|
177
|
+
for (const field of ["title", "state"]) {
|
|
178
|
+
if (!issue[field]) {
|
|
179
|
+
ctx.addIssue({
|
|
180
|
+
code: "custom",
|
|
181
|
+
path: ["issues", i, field],
|
|
182
|
+
message: `single mode requires ${field} for the #${issue.number} header line`,
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
if (issue.action === "MERGE" && issue.mergeTarget === undefined) {
|
|
187
|
+
ctx.addIssue({
|
|
188
|
+
code: "custom",
|
|
189
|
+
path: ["issues", i, "mergeTarget"],
|
|
190
|
+
message: "MERGE requires the target issue number",
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
if (issue.action === "PARK" && !issue.resumeAfter) {
|
|
194
|
+
ctx.addIssue({
|
|
195
|
+
code: "custom",
|
|
196
|
+
path: ["issues", i, "resumeAfter"],
|
|
197
|
+
message: "PARK requires a resume condition",
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
if (issue.action === "CLARIFY" && !issue.need) {
|
|
201
|
+
ctx.addIssue({
|
|
202
|
+
code: "custom",
|
|
203
|
+
path: ["issues", i, "need"],
|
|
204
|
+
message: "CLARIFY requires the specific information needed",
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
/** Raised by {@link parseAssessResult} when validation fails. */
|
|
210
|
+
export class AssessResultValidationError extends Error {
|
|
211
|
+
problems;
|
|
212
|
+
constructor(message, problems) {
|
|
213
|
+
super(message);
|
|
214
|
+
this.problems = problems;
|
|
215
|
+
this.name = "AssessResultValidationError";
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Render a zod path as a readable field reference: `issues[2].action`.
|
|
220
|
+
*/
|
|
221
|
+
function formatPath(path) {
|
|
222
|
+
if (path.length === 0)
|
|
223
|
+
return "(root)";
|
|
224
|
+
return path.reduce((acc, segment) => {
|
|
225
|
+
if (typeof segment === "number")
|
|
226
|
+
return `${acc}[${segment}]`;
|
|
227
|
+
return acc === "" ? String(segment) : `${acc}.${String(segment)}`;
|
|
228
|
+
}, "");
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Validate an untrusted payload against {@link AssessResultSchema}.
|
|
232
|
+
*
|
|
233
|
+
* @throws {AssessResultValidationError} naming every offending field.
|
|
234
|
+
*/
|
|
235
|
+
export function parseAssessResult(input) {
|
|
236
|
+
const result = AssessResultSchema.safeParse(input);
|
|
237
|
+
if (result.success)
|
|
238
|
+
return result.data;
|
|
239
|
+
const problems = result.error.issues.map((issue) => `${formatPath(issue.path)}: ${issue.message}`);
|
|
240
|
+
throw new AssessResultValidationError(`Invalid AssessResult:\n ${problems.join("\n ")}`, problems);
|
|
241
|
+
}
|
|
@@ -22,12 +22,28 @@
|
|
|
22
22
|
* users to ignore the warning.
|
|
23
23
|
*/
|
|
24
24
|
export declare const EXCLUDED_PATHS: ReadonlySet<string>;
|
|
25
|
+
/**
|
|
26
|
+
* Markdown H1/H2 section headings whose bodies are background/citation prose,
|
|
27
|
+
* not statements of intent-to-modify. A path named *only* under one of these
|
|
28
|
+
* is a reference to existing code, not a file the issue will touch — so the
|
|
29
|
+
* whole section is stripped before path extraction.
|
|
30
|
+
*
|
|
31
|
+
* Match is case-insensitive and prefix-based, so `## Motivation — concrete
|
|
32
|
+
* recent miss` and `## Additional context (see #533)` both match. This is the
|
|
33
|
+
* cheap version of the #556 proximity-weighting mitigation (#769): exclude
|
|
34
|
+
* background sections wholesale rather than scoring per-path distance to AC
|
|
35
|
+
* bullets. "A path appears only in background" ⟺ "the path is absent from the
|
|
36
|
+
* foreground", so stripping these sections up front subsumes per-path tagging.
|
|
37
|
+
*/
|
|
38
|
+
export declare const BACKGROUND_SECTIONS: ReadonlySet<string>;
|
|
25
39
|
/**
|
|
26
40
|
* Extract the set of file paths an issue body identifies as
|
|
27
41
|
* targets-of-modification.
|
|
28
42
|
*
|
|
29
43
|
* Strategy:
|
|
30
|
-
* 1. Strip fenced code blocks and HTML comments (AC-5 guard)
|
|
44
|
+
* 1. Strip fenced code blocks and HTML comments (AC-5 guard), then strip
|
|
45
|
+
* background/citation sections (#769) so a path named only under
|
|
46
|
+
* `## References`, `## Context`, etc. isn't counted as a target.
|
|
31
47
|
* 2. Pull every backtick-quoted path matching the source-tree regex,
|
|
32
48
|
* normalizing skill-mirror paths to their canonical bare form.
|
|
33
49
|
* 3. If the body mentions "3-dir sync", also pull bare
|
|
@@ -71,7 +87,8 @@ export declare function detectFileCollisions(issuePaths: Map<number, Set<string>
|
|
|
71
87
|
* - `chainSuggestion` — emitted only when ≥3 issues collide on the same
|
|
72
88
|
* file (AC-4); suggest-only, never auto-applied. Annotated with the
|
|
73
89
|
* historical chain-mode success rate at length≥3 (1/6 = 17%, per #604
|
|
74
|
-
* forensics
|
|
90
|
+
* forensics — the entire sample predates the #748/#749 fixes) so users
|
|
91
|
+
* can weigh chain mode against the parallel default.
|
|
75
92
|
*/
|
|
76
93
|
export interface CollisionAnnotations {
|
|
77
94
|
orderLines: string[];
|
|
@@ -27,6 +27,26 @@ export const EXCLUDED_PATHS = new Set([
|
|
|
27
27
|
"yarn.lock",
|
|
28
28
|
"pnpm-lock.yaml",
|
|
29
29
|
]);
|
|
30
|
+
/**
|
|
31
|
+
* Markdown H1/H2 section headings whose bodies are background/citation prose,
|
|
32
|
+
* not statements of intent-to-modify. A path named *only* under one of these
|
|
33
|
+
* is a reference to existing code, not a file the issue will touch — so the
|
|
34
|
+
* whole section is stripped before path extraction.
|
|
35
|
+
*
|
|
36
|
+
* Match is case-insensitive and prefix-based, so `## Motivation — concrete
|
|
37
|
+
* recent miss` and `## Additional context (see #533)` both match. This is the
|
|
38
|
+
* cheap version of the #556 proximity-weighting mitigation (#769): exclude
|
|
39
|
+
* background sections wholesale rather than scoring per-path distance to AC
|
|
40
|
+
* bullets. "A path appears only in background" ⟺ "the path is absent from the
|
|
41
|
+
* foreground", so stripping these sections up front subsumes per-path tagging.
|
|
42
|
+
*/
|
|
43
|
+
export const BACKGROUND_SECTIONS = new Set([
|
|
44
|
+
"references",
|
|
45
|
+
"context",
|
|
46
|
+
"motivation",
|
|
47
|
+
"additional context",
|
|
48
|
+
"see also",
|
|
49
|
+
]);
|
|
30
50
|
/**
|
|
31
51
|
* Slash-command names recognized as references to a skill's SKILL.md.
|
|
32
52
|
* Used by the slash-command-skill derivation rule when an issue body
|
|
@@ -83,10 +103,52 @@ const THREE_DIR_SYNC_PATTERN = /3[- ]dir(?:ectory)?\s+sync|across\s+all\s+three\
|
|
|
83
103
|
* single-backtick wrapper, so this gives us the "paths quoted as code in
|
|
84
104
|
* prose count, paths inside a code block don't" behavior the AC-5 guard
|
|
85
105
|
* specifies.
|
|
106
|
+
*
|
|
107
|
+
* Do NOT unify this with `dependency-markers.ts:stripCodeAndComments`, which
|
|
108
|
+
* looks nearly identical but additionally strips inline spans. The two have
|
|
109
|
+
* opposite requirements for the same syntax: there a backticked marker is a
|
|
110
|
+
* documentation example to discard, here a backticked path is the entire
|
|
111
|
+
* signal. Adding its inline-span strip to this function would delete every
|
|
112
|
+
* path PATH_REGEX is looking for and silently return an empty set.
|
|
86
113
|
*/
|
|
87
114
|
function stripCodeBlocksAndComments(body) {
|
|
88
115
|
return body.replace(/```[\s\S]*?```/g, "").replace(/<!--[\s\S]*?-->/g, "");
|
|
89
116
|
}
|
|
117
|
+
/**
|
|
118
|
+
* Remove background/citation sections (see `BACKGROUND_SECTIONS`) so a path
|
|
119
|
+
* named only as a reference — under `## References`, `## Context`, etc. — is
|
|
120
|
+
* not counted as a modification target (#769).
|
|
121
|
+
*
|
|
122
|
+
* A section runs from its H1/H2 heading to the next H1/H2 heading (or EOF);
|
|
123
|
+
* `###`+ subsections belong to their parent section and are dropped with it.
|
|
124
|
+
* Only H1/H2 headings toggle sections — a `### Detail` inside a stripped
|
|
125
|
+
* `## Additional context` must not resurrect the rest of the section.
|
|
126
|
+
*
|
|
127
|
+
* Run this *after* `stripCodeBlocksAndComments` so a fenced block containing a
|
|
128
|
+
* `## `-prefixed line can't be misread as a real heading.
|
|
129
|
+
*/
|
|
130
|
+
function stripBackgroundSections(body) {
|
|
131
|
+
const kept = [];
|
|
132
|
+
let stripping = false;
|
|
133
|
+
for (const line of body.split("\n")) {
|
|
134
|
+
const heading = line.match(/^(#{1,6})\s+(.*)$/);
|
|
135
|
+
if (heading && heading[1].length <= 2) {
|
|
136
|
+
const text = heading[2].trim().toLowerCase();
|
|
137
|
+
stripping = false;
|
|
138
|
+
for (const section of BACKGROUND_SECTIONS) {
|
|
139
|
+
if (text.startsWith(section)) {
|
|
140
|
+
stripping = true;
|
|
141
|
+
break;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
if (stripping)
|
|
145
|
+
continue; // drop the heading line itself
|
|
146
|
+
}
|
|
147
|
+
if (!stripping)
|
|
148
|
+
kept.push(line);
|
|
149
|
+
}
|
|
150
|
+
return kept.join("\n");
|
|
151
|
+
}
|
|
90
152
|
/**
|
|
91
153
|
* Collapse a fully-qualified skill-mirror path to its canonical bare form.
|
|
92
154
|
*
|
|
@@ -109,7 +171,9 @@ function normalizeSkillMirrorPath(path) {
|
|
|
109
171
|
* targets-of-modification.
|
|
110
172
|
*
|
|
111
173
|
* Strategy:
|
|
112
|
-
* 1. Strip fenced code blocks and HTML comments (AC-5 guard)
|
|
174
|
+
* 1. Strip fenced code blocks and HTML comments (AC-5 guard), then strip
|
|
175
|
+
* background/citation sections (#769) so a path named only under
|
|
176
|
+
* `## References`, `## Context`, etc. isn't counted as a target.
|
|
113
177
|
* 2. Pull every backtick-quoted path matching the source-tree regex,
|
|
114
178
|
* normalizing skill-mirror paths to their canonical bare form.
|
|
115
179
|
* 3. If the body mentions "3-dir sync", also pull bare
|
|
@@ -125,7 +189,7 @@ function normalizeSkillMirrorPath(path) {
|
|
|
125
189
|
*/
|
|
126
190
|
export function extractPathsFromIssueBody(body) {
|
|
127
191
|
const paths = new Set();
|
|
128
|
-
const cleaned = stripCodeBlocksAndComments(body);
|
|
192
|
+
const cleaned = stripBackgroundSections(stripCodeBlocksAndComments(body));
|
|
129
193
|
for (const m of cleaned.matchAll(PATH_REGEX)) {
|
|
130
194
|
paths.add(normalizeSkillMirrorPath(m[1]));
|
|
131
195
|
}
|
|
@@ -208,9 +272,9 @@ export function formatCollisionAnnotations(results) {
|
|
|
208
272
|
if (r.issues.length >= 3 && !chainSuggestion) {
|
|
209
273
|
const ids = r.issues.join(" ");
|
|
210
274
|
chainSuggestion =
|
|
211
|
-
`Chain: npx sequant run ${ids} --chain
|
|
275
|
+
`Chain: npx sequant run ${ids} --chain -Q ` +
|
|
212
276
|
`# alternative — ${r.issues.length} issues modify ${r.file} ` +
|
|
213
|
-
`(chain length≥3 historically 1/6 = 17
|
|
277
|
+
`(chain length≥3 historically 1/6 = 17%, predates the #748/#749 fixes; see docs/reference/chain-mode-analysis-2026-05.md)`;
|
|
214
278
|
}
|
|
215
279
|
}
|
|
216
280
|
return { orderLines, warnings, chainSuggestion };
|
|
@@ -12,8 +12,15 @@ import type { ActionOutputs } from "./types.js";
|
|
|
12
12
|
export declare function formatOutputs(result: IssueResult): ActionOutputs;
|
|
13
13
|
/**
|
|
14
14
|
* Format multiple issue results into combined outputs.
|
|
15
|
+
*
|
|
16
|
+
* @param wallClockDurationSeconds - The run's wall-clock duration, computed by
|
|
17
|
+
* whoever brackets the run (the orchestrator surfaces it as
|
|
18
|
+
* `RunResult.wallClockDurationSeconds`). It is a required argument rather than
|
|
19
|
+
* something derived here because the per-issue durations this function receives
|
|
20
|
+
* cannot express it: under `--parallel` they overlap, so summing them
|
|
21
|
+
* double-counts and over-reports by roughly the concurrency factor (#867).
|
|
15
22
|
*/
|
|
16
|
-
export declare function formatMultiOutputs(results: IssueResult[]): ActionOutputs;
|
|
23
|
+
export declare function formatMultiOutputs(results: IssueResult[], wallClockDurationSeconds: number): ActionOutputs;
|
|
17
24
|
/**
|
|
18
25
|
* Generate shell commands to set GitHub Actions outputs.
|
|
19
26
|
* Each output is written to $GITHUB_OUTPUT file.
|
|
@@ -21,5 +28,11 @@ export declare function formatMultiOutputs(results: IssueResult[]): ActionOutput
|
|
|
21
28
|
export declare function outputCommands(outputs: ActionOutputs): string[];
|
|
22
29
|
/**
|
|
23
30
|
* Generate a GitHub Actions step summary (Markdown).
|
|
31
|
+
*
|
|
32
|
+
* @param wallClockDurationSeconds - The run's wall-clock duration. Required for
|
|
33
|
+
* the same reason as in {@link formatMultiOutputs}: the per-issue durations
|
|
34
|
+
* below overlap under `--parallel`, so the "Total duration" line cannot be
|
|
35
|
+
* derived by summing them (#867). Per-*phase* durations in the tables are
|
|
36
|
+
* unaffected — phases within an issue run sequentially.
|
|
24
37
|
*/
|
|
25
|
-
export declare function formatSummary(results: IssueResult[]): string;
|
|
38
|
+
export declare function formatSummary(results: IssueResult[], wallClockDurationSeconds: number): string;
|