sequant 2.9.0 → 2.11.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 (209) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/README.md +20 -5
  4. package/dist/bin/cli.js +143 -18
  5. package/dist/marketplace/external_plugins/sequant/.claude-plugin/plugin.json +1 -1
  6. package/dist/marketplace/external_plugins/sequant/.mcp.json +1 -1
  7. package/dist/marketplace/external_plugins/sequant/README.md +56 -2
  8. package/dist/marketplace/external_plugins/sequant/hooks/parallel-marker.sh +50 -0
  9. package/dist/marketplace/external_plugins/sequant/hooks/post-tool.sh +20 -7
  10. package/dist/marketplace/external_plugins/sequant/hooks/pre-tool.sh +75 -10
  11. package/dist/marketplace/external_plugins/sequant/skills/_shared/references/trust-model.md +18 -0
  12. package/dist/marketplace/external_plugins/sequant/skills/assess/SKILL.md +215 -390
  13. package/dist/marketplace/external_plugins/sequant/skills/assess/references/predicted-collision-detection.md +1 -1
  14. package/dist/marketplace/external_plugins/sequant/skills/docs/SKILL.md +4 -4
  15. package/dist/marketplace/external_plugins/sequant/skills/exec/SKILL.md +26 -6
  16. package/dist/marketplace/external_plugins/sequant/skills/fullsolve/SKILL.md +3 -1
  17. package/dist/marketplace/external_plugins/sequant/skills/loop/SKILL.md +38 -2
  18. package/dist/marketplace/external_plugins/sequant/skills/merger/SKILL.md +2 -2
  19. package/dist/marketplace/external_plugins/sequant/skills/qa/SKILL.md +337 -57
  20. package/dist/marketplace/external_plugins/sequant/skills/qa/references/anti-pattern-detection.md +6 -6
  21. package/dist/marketplace/external_plugins/sequant/skills/qa/references/call-site-review.md +2 -2
  22. package/dist/marketplace/external_plugins/sequant/skills/qa/references/code-review-checklist.md +2 -2
  23. package/dist/marketplace/external_plugins/sequant/skills/qa/references/fixtures/injection-issue-body.md +36 -0
  24. package/dist/marketplace/external_plugins/sequant/skills/qa/references/quality-gates.md +21 -7
  25. package/dist/marketplace/external_plugins/sequant/skills/qa/references/testing-requirements.md +1 -1
  26. package/dist/marketplace/external_plugins/sequant/skills/qa/scripts/quality-checks.sh +11 -11
  27. package/dist/marketplace/external_plugins/sequant/skills/release/SKILL.md +1 -1
  28. package/dist/marketplace/external_plugins/sequant/skills/setup/SKILL.md +5 -5
  29. package/dist/marketplace/external_plugins/sequant/skills/spec/SKILL.md +2 -0
  30. package/dist/marketplace/external_plugins/sequant/skills/test/SKILL.md +1 -1
  31. package/dist/src/commands/assess-render.d.ts +23 -0
  32. package/dist/src/commands/assess-render.js +60 -0
  33. package/dist/src/commands/doctor.js +8 -13
  34. package/dist/src/commands/init.js +13 -1
  35. package/dist/src/commands/locks.d.ts +20 -1
  36. package/dist/src/commands/locks.js +208 -4
  37. package/dist/src/commands/logs.js +14 -5
  38. package/dist/src/commands/merge.js +154 -2
  39. package/dist/src/commands/ready-tui-adapter.js +6 -1
  40. package/dist/src/commands/ready.d.ts +31 -3
  41. package/dist/src/commands/ready.js +53 -13
  42. package/dist/src/commands/resume.d.ts +113 -0
  43. package/dist/src/commands/resume.js +193 -0
  44. package/dist/src/commands/run-display.js +38 -4
  45. package/dist/src/commands/run-flags.d.ts +42 -1
  46. package/dist/src/commands/run-flags.js +53 -1
  47. package/dist/src/commands/run-progress.js +26 -1
  48. package/dist/src/commands/run.js +11 -10
  49. package/dist/src/commands/state.js +7 -0
  50. package/dist/src/commands/status.d.ts +9 -0
  51. package/dist/src/commands/status.js +24 -1
  52. package/dist/src/commands/sync.js +90 -19
  53. package/dist/src/commands/update.js +28 -5
  54. package/dist/src/commands/worktree.d.ts +31 -0
  55. package/dist/src/commands/worktree.js +95 -0
  56. package/dist/src/lib/ac-parser.d.ts +14 -0
  57. package/dist/src/lib/ac-parser.js +99 -5
  58. package/dist/src/lib/assess/index.d.ts +10 -0
  59. package/dist/src/lib/assess/index.js +9 -0
  60. package/dist/src/lib/assess/renderer.d.ts +64 -0
  61. package/dist/src/lib/assess/renderer.js +481 -0
  62. package/dist/src/lib/assess/types.d.ts +224 -0
  63. package/dist/src/lib/assess/types.js +241 -0
  64. package/dist/src/lib/ci/outputs.d.ts +15 -2
  65. package/dist/src/lib/ci/outputs.js +17 -5
  66. package/dist/src/lib/cli-flags.d.ts +56 -0
  67. package/dist/src/lib/cli-flags.js +89 -0
  68. package/dist/src/lib/cli-ui/run-renderer-types.d.ts +23 -7
  69. package/dist/src/lib/cli-ui/run-renderer.d.ts +10 -0
  70. package/dist/src/lib/cli-ui/run-renderer.js +69 -1
  71. package/dist/src/lib/errors.d.ts +78 -6
  72. package/dist/src/lib/errors.js +133 -15
  73. package/dist/src/lib/locks/checkout-lock.d.ts +193 -0
  74. package/dist/src/lib/locks/checkout-lock.js +389 -0
  75. package/dist/src/lib/locks/index.d.ts +7 -4
  76. package/dist/src/lib/locks/index.js +5 -3
  77. package/dist/src/lib/locks/lock-manager.d.ts +101 -3
  78. package/dist/src/lib/locks/lock-manager.js +277 -8
  79. package/dist/src/lib/locks/types.d.ts +106 -3
  80. package/dist/src/lib/locks/types.js +44 -0
  81. package/dist/src/lib/mcp-config.d.ts +45 -0
  82. package/dist/src/lib/mcp-config.js +77 -1
  83. package/dist/src/lib/merge-check/combined-branch-test.d.ts +21 -2
  84. package/dist/src/lib/merge-check/combined-branch-test.js +233 -110
  85. package/dist/src/lib/merge-check/command-result.d.ts +36 -0
  86. package/dist/src/lib/merge-check/command-result.js +56 -0
  87. package/dist/src/lib/merge-check/index.d.ts +4 -0
  88. package/dist/src/lib/merge-check/index.js +1 -1
  89. package/dist/src/lib/merge-check/report.js +5 -1
  90. package/dist/src/lib/merge-check/types.d.ts +9 -0
  91. package/dist/src/lib/merge-check/watch.d.ts +121 -0
  92. package/dist/src/lib/merge-check/watch.js +215 -0
  93. package/dist/src/lib/qa/infra-blocked-ci.d.ts +90 -0
  94. package/dist/src/lib/qa/infra-blocked-ci.js +80 -0
  95. package/dist/src/lib/settings.d.ts +87 -0
  96. package/dist/src/lib/settings.js +106 -8
  97. package/dist/src/lib/shutdown.d.ts +42 -2
  98. package/dist/src/lib/shutdown.js +75 -5
  99. package/dist/src/lib/skills-check.d.ts +26 -0
  100. package/dist/src/lib/skills-check.js +31 -0
  101. package/dist/src/lib/stacks.d.ts +110 -1
  102. package/dist/src/lib/stacks.js +244 -5
  103. package/dist/src/lib/templates.d.ts +74 -0
  104. package/dist/src/lib/templates.js +171 -16
  105. package/dist/src/lib/test-tautology-detector.d.ts +10 -2
  106. package/dist/src/lib/test-tautology-detector.js +213 -12
  107. package/dist/src/lib/version-check.d.ts +31 -0
  108. package/dist/src/lib/version-check.js +45 -2
  109. package/dist/src/lib/workflow/batch-executor.d.ts +125 -6
  110. package/dist/src/lib/workflow/batch-executor.js +552 -60
  111. package/dist/src/lib/workflow/chain-resume.d.ts +13 -11
  112. package/dist/src/lib/workflow/chain-resume.js +24 -20
  113. package/dist/src/lib/workflow/completed-status.d.ts +52 -0
  114. package/dist/src/lib/workflow/completed-status.js +57 -0
  115. package/dist/src/lib/workflow/config-resolver.d.ts +51 -0
  116. package/dist/src/lib/workflow/config-resolver.js +143 -2
  117. package/dist/src/lib/workflow/drivers/agent-driver.d.ts +22 -0
  118. package/dist/src/lib/workflow/drivers/aider.d.ts +2 -0
  119. package/dist/src/lib/workflow/drivers/aider.js +2 -0
  120. package/dist/src/lib/workflow/drivers/claude-code.d.ts +14 -0
  121. package/dist/src/lib/workflow/drivers/claude-code.js +25 -2
  122. package/dist/src/lib/workflow/effort-escalation.d.ts +73 -0
  123. package/dist/src/lib/workflow/effort-escalation.js +82 -0
  124. package/dist/src/lib/workflow/error-classifier.d.ts +4 -1
  125. package/dist/src/lib/workflow/error-classifier.js +4 -0
  126. package/dist/src/lib/workflow/git-diff-utils.d.ts +35 -3
  127. package/dist/src/lib/workflow/git-diff-utils.js +77 -4
  128. package/dist/src/lib/workflow/heartbeat.d.ts +38 -0
  129. package/dist/src/lib/workflow/heartbeat.js +90 -0
  130. package/dist/src/lib/workflow/log-writer.d.ts +54 -2
  131. package/dist/src/lib/workflow/log-writer.js +95 -6
  132. package/dist/src/lib/workflow/metrics-schema.d.ts +52 -9
  133. package/dist/src/lib/workflow/metrics-schema.js +33 -0
  134. package/dist/src/lib/workflow/metrics-writer.d.ts +11 -0
  135. package/dist/src/lib/workflow/phase-detection.d.ts +12 -0
  136. package/dist/src/lib/workflow/phase-detection.js +5 -1
  137. package/dist/src/lib/workflow/phase-executor.d.ts +203 -14
  138. package/dist/src/lib/workflow/phase-executor.js +467 -52
  139. package/dist/src/lib/workflow/phase-registry.js +2 -1
  140. package/dist/src/lib/workflow/platforms/github.d.ts +64 -0
  141. package/dist/src/lib/workflow/platforms/github.js +152 -0
  142. package/dist/src/lib/workflow/qa-cache.d.ts +6 -1
  143. package/dist/src/lib/workflow/qa-cache.js +22 -9
  144. package/dist/src/lib/workflow/ready-gate.d.ts +45 -4
  145. package/dist/src/lib/workflow/ready-gate.js +49 -12
  146. package/dist/src/lib/workflow/run-log-schema.d.ts +69 -0
  147. package/dist/src/lib/workflow/run-log-schema.js +78 -2
  148. package/dist/src/lib/workflow/run-orchestrator.d.ts +19 -0
  149. package/dist/src/lib/workflow/run-orchestrator.js +168 -20
  150. package/dist/src/lib/workflow/skills-preflight.d.ts +89 -0
  151. package/dist/src/lib/workflow/skills-preflight.js +112 -0
  152. package/dist/src/lib/workflow/spec-recommendation.d.ts +71 -0
  153. package/dist/src/lib/workflow/spec-recommendation.js +142 -0
  154. package/dist/src/lib/workflow/state-cleanup.js +9 -2
  155. package/dist/src/lib/workflow/state-manager.d.ts +33 -0
  156. package/dist/src/lib/workflow/state-manager.js +83 -0
  157. package/dist/src/lib/workflow/state-schema.d.ts +26 -0
  158. package/dist/src/lib/workflow/state-schema.js +47 -0
  159. package/dist/src/lib/workflow/types.d.ts +190 -4
  160. package/dist/src/lib/workflow/types.js +1 -0
  161. package/dist/src/lib/workflow/worktree-manager.d.ts +36 -3
  162. package/dist/src/lib/workflow/worktree-manager.js +111 -24
  163. package/dist/src/lib/workflow/worktree-resolver.d.ts +73 -0
  164. package/dist/src/lib/workflow/worktree-resolver.js +126 -0
  165. package/dist/src/mcp/tools/run.d.ts +9 -1
  166. package/dist/src/mcp/tools/run.js +20 -1
  167. package/dist/src/mcp/tools/status.js +6 -0
  168. package/dist/src/ui/tui/ElapsedTimer.d.ts +12 -3
  169. package/dist/src/ui/tui/ElapsedTimer.js +12 -10
  170. package/dist/src/ui/tui/IssueBox.js +10 -2
  171. package/dist/src/ui/tui/row-cap.js +2 -1
  172. package/dist/src/ui/tui/theme.d.ts +7 -0
  173. package/dist/src/ui/tui/theme.js +9 -0
  174. package/package.json +10 -8
  175. package/templates/hooks/parallel-marker.sh +50 -0
  176. package/templates/hooks/post-tool.sh +20 -7
  177. package/templates/hooks/pre-tool.sh +303 -10
  178. package/templates/scripts/cleanup-worktree.sh +217 -33
  179. package/templates/scripts/new-feature.sh +289 -35
  180. package/templates/skills/_shared/references/subagent-types.md +7 -18
  181. package/templates/skills/_shared/references/trust-model.md +18 -0
  182. package/templates/skills/assess/SKILL.md +220 -391
  183. package/templates/skills/assess/references/predicted-collision-detection.md +1 -1
  184. package/templates/skills/docs/SKILL.md +4 -4
  185. package/templates/skills/exec/SKILL.md +87 -13
  186. package/templates/skills/fullsolve/SKILL.md +130 -22
  187. package/templates/skills/loop/SKILL.md +94 -13
  188. package/templates/skills/merger/SKILL.md +100 -12
  189. package/templates/skills/qa/SKILL.md +396 -63
  190. package/templates/skills/qa/references/anti-pattern-detection.md +6 -6
  191. package/templates/skills/qa/references/call-site-review.md +2 -2
  192. package/templates/skills/qa/references/code-review-checklist.md +2 -2
  193. package/templates/skills/qa/references/fixtures/injection-issue-body.md +36 -0
  194. package/templates/skills/qa/references/quality-gates.md +21 -7
  195. package/templates/skills/qa/references/testing-requirements.md +1 -1
  196. package/templates/skills/qa/scripts/quality-checks.sh +11 -11
  197. package/templates/skills/release/SKILL.md +80 -1
  198. package/templates/skills/setup/SKILL.md +5 -5
  199. package/templates/skills/spec/SKILL.md +33 -15
  200. package/templates/skills/spec/references/recommended-workflow.md +14 -1
  201. package/templates/skills/test/SKILL.md +1 -1
  202. package/templates/skills/testgen/SKILL.md +23 -6
  203. package/dist/src/lib/phase-spinner.d.ts +0 -146
  204. package/dist/src/lib/phase-spinner.js +0 -255
  205. package/dist/src/lib/workflow/pr-operations.d.ts +0 -86
  206. package/dist/src/lib/workflow/pr-operations.js +0 -326
  207. package/dist/src/lib/workflow/run-summary.d.ts +0 -36
  208. package/dist/src/lib/workflow/run-summary.js +0 -142
  209. package/templates/agents/sequant-explorer.md +0 -24
@@ -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
+ }
@@ -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;
@@ -18,10 +18,17 @@ export function formatOutputs(result) {
18
18
  }
19
19
  /**
20
20
  * Format multiple issue results into combined outputs.
21
+ *
22
+ * @param wallClockDurationSeconds - The run's wall-clock duration, computed by
23
+ * whoever brackets the run (the orchestrator surfaces it as
24
+ * `RunResult.wallClockDurationSeconds`). It is a required argument rather than
25
+ * something derived here because the per-issue durations this function receives
26
+ * cannot express it: under `--parallel` they overlap, so summing them
27
+ * double-counts and over-reports by roughly the concurrency factor (#867).
21
28
  */
22
- export function formatMultiOutputs(results) {
29
+ export function formatMultiOutputs(results, wallClockDurationSeconds) {
23
30
  const allSuccess = results.every((r) => r.success);
24
- const totalDuration = results.reduce((sum, r) => sum + (r.durationSeconds ?? 0), 0);
31
+ const totalDuration = wallClockDurationSeconds;
25
32
  const prUrls = results
26
33
  .map((r) => r.prUrl)
27
34
  .filter(Boolean)
@@ -54,8 +61,14 @@ export function outputCommands(outputs) {
54
61
  }
55
62
  /**
56
63
  * Generate a GitHub Actions step summary (Markdown).
64
+ *
65
+ * @param wallClockDurationSeconds - The run's wall-clock duration. Required for
66
+ * the same reason as in {@link formatMultiOutputs}: the per-issue durations
67
+ * below overlap under `--parallel`, so the "Total duration" line cannot be
68
+ * derived by summing them (#867). Per-*phase* durations in the tables are
69
+ * unaffected — phases within an issue run sequentially.
57
70
  */
58
- export function formatSummary(results) {
71
+ export function formatSummary(results, wallClockDurationSeconds) {
59
72
  const lines = [];
60
73
  lines.push("## Sequant Workflow Results\n");
61
74
  for (const result of results) {
@@ -78,7 +91,6 @@ export function formatSummary(results) {
78
91
  }
79
92
  lines.push("");
80
93
  }
81
- const total = results.reduce((sum, r) => sum + (r.durationSeconds ?? 0), 0);
82
- lines.push(`**Total duration:** ${total}s`);
94
+ lines.push(`**Total duration:** ${wallClockDurationSeconds}s`);
83
95
  return lines.join("\n");
84
96
  }
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Commander argument coercions for numeric CLI flags.
3
+ *
4
+ * Lives here rather than inline in `bin/cli.ts` so it can be unit-tested
5
+ * directly — `bin/cli.ts` calls `program.parse()` at import time and cannot be
6
+ * imported from a test.
7
+ *
8
+ * @module
9
+ */
10
+ /** Error-text shaping for a numeric flag. Affects messages only, not parsing. */
11
+ export interface WholeNumberOptions {
12
+ /** Smallest accepted value. Use 0 where 0 is a meaningful "off" setting. */
13
+ min: number;
14
+ /** Plural unit, e.g. `"seconds"`. Omit for a flag that reads better bare. */
15
+ unit?: string;
16
+ /** Singular unit, used when `min` is 1 ("at least 1 second"). */
17
+ unitSingular?: string;
18
+ }
19
+ /**
20
+ * Build a commander coercion for a whole-number flag.
21
+ *
22
+ * A bare `parseInt` is unsafe for these: `parseInt("abc", 10)` is `NaN`, which
23
+ * is not nullish and so survives a `?? default`, and `parseInt("30m", 10)`
24
+ * silently yields `30` — the user asked for 30 minutes and got 30 seconds.
25
+ * Requiring the whole string to be digits rejects both instead of accepting a
26
+ * value that is unusable or quietly wrong (#818, #833).
27
+ */
28
+ export declare function parseWholeNumber(flag: string, opts: WholeNumberOptions): (value: string) => number;
29
+ /**
30
+ * A positive-integer *seconds* flag — the #831 shape, preserved verbatim so the
31
+ * `merge --watch` messages this originally shipped with do not change.
32
+ */
33
+ export declare function parsePositiveSeconds(flag: string): (value: string) => number;
34
+ /**
35
+ * Build a commander coercion for a `--models`/`--efforts`-shaped flag (#914).
36
+ *
37
+ * Validates the spec via `config-resolver.ts`'s `parsePhaseSpec` — a bare
38
+ * value applies to every phase, a comma list of `phase=value` pairs applies
39
+ * per phase, and a malformed spec (empty segment, mixed bare/pair form, or
40
+ * an unrecognized phase name) fails fast here rather than reaching
41
+ * `resolvePhasePolicies` silently. On success, returns the ORIGINAL raw spec
42
+ * string unchanged (not the parsed map) — `RunOptions.models`/`.efforts`
43
+ * stay plain strings, and `resolvePhasePolicies` re-parses for real when
44
+ * building `ExecutionConfig.phasePolicies`, so parsing has exactly one
45
+ * source of truth even though it runs twice.
46
+ *
47
+ * `allowedValues`, when given, additionally rejects any resolved value not
48
+ * in the set — used for `--efforts` (closed enum: `settings.ts:EFFORT_LEVELS`)
49
+ * so a typo like `--efforts exec=mediu` fails at the CLI boundary the same
50
+ * way it already does when set via `settings.json`, instead of only
51
+ * surfacing once the value reaches the SDK. `--models` passes no
52
+ * `allowedValues` — model aliases/IDs are intentionally unvalidated (they
53
+ * churn independently of sequant releases; the SDK errors clearly on a bad
54
+ * one).
55
+ */
56
+ export declare function parsePhaseSpecFlag(flag: string, phaseNames: string[], allowedValues?: readonly string[]): (value: string) => string;
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Commander argument coercions for numeric CLI flags.
3
+ *
4
+ * Lives here rather than inline in `bin/cli.ts` so it can be unit-tested
5
+ * directly — `bin/cli.ts` calls `program.parse()` at import time and cannot be
6
+ * imported from a test.
7
+ *
8
+ * @module
9
+ */
10
+ import { InvalidArgumentError } from "commander";
11
+ import { parsePhaseSpec } from "./workflow/config-resolver.js";
12
+ /**
13
+ * Build a commander coercion for a whole-number flag.
14
+ *
15
+ * A bare `parseInt` is unsafe for these: `parseInt("abc", 10)` is `NaN`, which
16
+ * is not nullish and so survives a `?? default`, and `parseInt("30m", 10)`
17
+ * silently yields `30` — the user asked for 30 minutes and got 30 seconds.
18
+ * Requiring the whole string to be digits rejects both instead of accepting a
19
+ * value that is unusable or quietly wrong (#818, #833).
20
+ */
21
+ export function parseWholeNumber(flag, opts) {
22
+ const { min, unit, unitSingular } = opts;
23
+ const ofUnit = unit ? ` of ${unit}` : "";
24
+ const minUnit = min === 1 ? (unitSingular ?? unit) : unit;
25
+ const minSuffix = minUnit ? ` ${minUnit}` : "";
26
+ return (value) => {
27
+ if (!/^\d+$/.test(value.trim())) {
28
+ throw new InvalidArgumentError(`${flag} expects a whole number${ofUnit} (got '${value}').`);
29
+ }
30
+ const parsed = Number(value);
31
+ if (!Number.isSafeInteger(parsed) || parsed < min) {
32
+ throw new InvalidArgumentError(`${flag} must be at least ${min}${minSuffix} (got '${value}').`);
33
+ }
34
+ return parsed;
35
+ };
36
+ }
37
+ /**
38
+ * A positive-integer *seconds* flag — the #831 shape, preserved verbatim so the
39
+ * `merge --watch` messages this originally shipped with do not change.
40
+ */
41
+ export function parsePositiveSeconds(flag) {
42
+ return parseWholeNumber(flag, {
43
+ min: 1,
44
+ unit: "seconds",
45
+ unitSingular: "second",
46
+ });
47
+ }
48
+ /**
49
+ * Build a commander coercion for a `--models`/`--efforts`-shaped flag (#914).
50
+ *
51
+ * Validates the spec via `config-resolver.ts`'s `parsePhaseSpec` — a bare
52
+ * value applies to every phase, a comma list of `phase=value` pairs applies
53
+ * per phase, and a malformed spec (empty segment, mixed bare/pair form, or
54
+ * an unrecognized phase name) fails fast here rather than reaching
55
+ * `resolvePhasePolicies` silently. On success, returns the ORIGINAL raw spec
56
+ * string unchanged (not the parsed map) — `RunOptions.models`/`.efforts`
57
+ * stay plain strings, and `resolvePhasePolicies` re-parses for real when
58
+ * building `ExecutionConfig.phasePolicies`, so parsing has exactly one
59
+ * source of truth even though it runs twice.
60
+ *
61
+ * `allowedValues`, when given, additionally rejects any resolved value not
62
+ * in the set — used for `--efforts` (closed enum: `settings.ts:EFFORT_LEVELS`)
63
+ * so a typo like `--efforts exec=mediu` fails at the CLI boundary the same
64
+ * way it already does when set via `settings.json`, instead of only
65
+ * surfacing once the value reaches the SDK. `--models` passes no
66
+ * `allowedValues` — model aliases/IDs are intentionally unvalidated (they
67
+ * churn independently of sequant releases; the SDK errors clearly on a bad
68
+ * one).
69
+ */
70
+ export function parsePhaseSpecFlag(flag, phaseNames, allowedValues) {
71
+ return (value) => {
72
+ let parsed;
73
+ try {
74
+ parsed = parsePhaseSpec(value, phaseNames);
75
+ }
76
+ catch (error) {
77
+ const message = error instanceof Error ? error.message : String(error);
78
+ throw new InvalidArgumentError(`${flag}: ${message}`);
79
+ }
80
+ if (allowedValues) {
81
+ for (const v of Object.values(parsed)) {
82
+ if (!allowedValues.includes(v)) {
83
+ throw new InvalidArgumentError(`${flag}: '${v}' is not one of ${allowedValues.join("|")}.`);
84
+ }
85
+ }
86
+ }
87
+ return value;
88
+ };
89
+ }