supipowers 1.5.2 → 2.0.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 (340) hide show
  1. package/README.md +14 -8
  2. package/bin/install.mjs +20 -5
  3. package/bin/install.ts +95 -0
  4. package/package.json +8 -4
  5. package/skills/context-mode/SKILL.md +17 -10
  6. package/skills/harness/SKILL.md +94 -0
  7. package/skills/ui-design/SKILL.md +63 -0
  8. package/skills/ui-design/sub-agent-templates/component-builder.md +29 -0
  9. package/skills/ui-design/sub-agent-templates/design-critic.md +46 -0
  10. package/skills/ui-design/sub-agent-templates/pencil/component-builder.md +29 -0
  11. package/skills/ui-design/sub-agent-templates/pencil/design-critic.md +42 -0
  12. package/skills/ui-design/sub-agent-templates/pencil/section-assembler.md +27 -0
  13. package/skills/ui-design/sub-agent-templates/section-assembler.md +27 -0
  14. package/skills/ultraplan-discover/SKILL.md +96 -0
  15. package/skills/ultraplan-intake/SKILL.md +89 -0
  16. package/skills/ultraplan-research/SKILL.md +129 -0
  17. package/skills/ultraplan-review/SKILL.md +86 -0
  18. package/skills/ultraplan-review-scope/SKILL.md +111 -0
  19. package/skills/ultraplan-review-structure/SKILL.md +120 -0
  20. package/skills/ultraplan-review-tdd/SKILL.md +142 -0
  21. package/skills/ultraplan-scout/SKILL.md +110 -0
  22. package/skills/ultraplan-synthesize/SKILL.md +124 -0
  23. package/src/{quality/ai-session.ts → ai/final-message.ts} +27 -0
  24. package/src/ai/schema-text.ts +129 -0
  25. package/src/ai/structured-output.ts +274 -0
  26. package/src/ai/template.ts +27 -0
  27. package/src/bootstrap.ts +63 -28
  28. package/src/commands/agents.ts +149 -45
  29. package/src/commands/ai-review.ts +251 -30
  30. package/src/commands/clear.ts +434 -0
  31. package/src/commands/commit.ts +1 -0
  32. package/src/commands/config.ts +242 -44
  33. package/src/commands/context.ts +55 -28
  34. package/src/commands/doctor.ts +234 -6
  35. package/src/commands/fix-pr.ts +306 -131
  36. package/src/commands/generate.ts +111 -21
  37. package/src/commands/memory.ts +192 -0
  38. package/src/commands/model-picker.ts +28 -21
  39. package/src/commands/model.ts +19 -9
  40. package/src/commands/optimize-context.ts +408 -29
  41. package/src/commands/plan.ts +2 -0
  42. package/src/commands/qa.ts +312 -137
  43. package/src/commands/release.ts +259 -76
  44. package/src/commands/review.ts +293 -59
  45. package/src/commands/status.ts +200 -13
  46. package/src/commands/supi.ts +3 -35
  47. package/src/commands/ui-design.ts +394 -0
  48. package/src/commands/ultraplan.ts +1518 -0
  49. package/src/commands/update.ts +86 -0
  50. package/src/config/defaults.ts +62 -0
  51. package/src/config/loader.ts +448 -60
  52. package/src/config/schema.ts +108 -2
  53. package/src/context/optimizer.ts +25 -33
  54. package/src/context/rule-renderer.ts +223 -0
  55. package/src/context/savings.ts +258 -0
  56. package/src/context/startup-check.ts +380 -0
  57. package/src/context/startup-optimizer.ts +355 -0
  58. package/src/context/tokenignore.ts +146 -0
  59. package/src/context-mode/cache-handle.ts +49 -0
  60. package/src/context-mode/cache-preview.ts +71 -0
  61. package/src/context-mode/cache-store.ts +738 -0
  62. package/src/context-mode/compressor.ts +131 -26
  63. package/src/context-mode/dedup.ts +108 -0
  64. package/src/context-mode/detector.ts +35 -4
  65. package/src/context-mode/event-extractor.ts +14 -12
  66. package/src/context-mode/event-store.ts +91 -36
  67. package/src/context-mode/hooks.ts +798 -56
  68. package/src/context-mode/knowledge/store.ts +255 -11
  69. package/src/context-mode/memory-store.ts +325 -0
  70. package/src/context-mode/metrics-recorder.ts +158 -0
  71. package/src/context-mode/metrics-store.ts +765 -0
  72. package/src/context-mode/model.ts +24 -0
  73. package/src/context-mode/processor-keys.ts +29 -0
  74. package/src/context-mode/processors/build.ts +66 -0
  75. package/src/context-mode/processors/docker.ts +57 -0
  76. package/src/context-mode/processors/git.ts +111 -0
  77. package/src/context-mode/processors/json.ts +112 -0
  78. package/src/context-mode/processors/k8s.ts +67 -0
  79. package/src/context-mode/processors/lint.ts +67 -0
  80. package/src/context-mode/processors/log.ts +86 -0
  81. package/src/context-mode/processors/registry.ts +116 -0
  82. package/src/context-mode/processors/test-runner.ts +102 -0
  83. package/src/context-mode/processors/types.ts +20 -0
  84. package/src/context-mode/repomap.ts +400 -0
  85. package/src/context-mode/routing.ts +97 -24
  86. package/src/context-mode/sandbox/runners.ts +5 -1
  87. package/src/context-mode/snapshot-builder.ts +106 -11
  88. package/src/context-mode/source-hash.ts +173 -0
  89. package/src/context-mode/tool-name.ts +11 -0
  90. package/src/context-mode/tools.ts +654 -22
  91. package/src/context-mode/web/fetcher.ts +31 -12
  92. package/src/debug/logger.ts +2 -1
  93. package/src/deps/registry.ts +1 -1
  94. package/src/discipline/failure-summarizer.ts +170 -0
  95. package/src/discipline/failure-taxonomy.ts +131 -0
  96. package/src/discipline/workflow-invariants.ts +125 -0
  97. package/src/discovery/index.ts +31 -0
  98. package/src/discovery/lsp.ts +87 -0
  99. package/src/discovery/rank.ts +144 -0
  100. package/src/discovery/sources.ts +89 -0
  101. package/src/discovery/workflow.ts +87 -0
  102. package/src/docs/contracts.ts +39 -0
  103. package/src/docs/drift.ts +117 -87
  104. package/src/fix-pr/assessment.ts +200 -0
  105. package/src/fix-pr/contracts.ts +47 -0
  106. package/src/fix-pr/fetch-comments.ts +80 -0
  107. package/src/fix-pr/prompt-builder.ts +58 -40
  108. package/src/fix-pr/scripts/exec.ts +34 -0
  109. package/src/fix-pr/scripts/trigger-review.ts +106 -0
  110. package/src/fix-pr/scripts/wait-and-check.ts +108 -0
  111. package/src/fix-pr/types.ts +4 -0
  112. package/src/git/branch-finish.ts +5 -0
  113. package/src/git/commit-contract.ts +83 -0
  114. package/src/git/commit.ts +121 -184
  115. package/src/git/status.ts +62 -8
  116. package/src/harness/anti_slop/architecture-parser.ts +210 -0
  117. package/src/harness/anti_slop/backend-factory.ts +30 -0
  118. package/src/harness/anti_slop/backend.ts +140 -0
  119. package/src/harness/anti_slop/desloppify-adapter.ts +319 -0
  120. package/src/harness/anti_slop/fallow-adapter.ts +305 -0
  121. package/src/harness/anti_slop/installer.ts +227 -0
  122. package/src/harness/anti_slop/queue.ts +216 -0
  123. package/src/harness/anti_slop/recommend.ts +84 -0
  124. package/src/harness/anti_slop/score.ts +180 -0
  125. package/src/harness/anti_slop/synthetic-edit-test.ts +128 -0
  126. package/src/harness/artifacts/agents-md.ts +88 -0
  127. package/src/harness/artifacts/checks-wiring.ts +57 -0
  128. package/src/harness/artifacts/docs-tree.ts +79 -0
  129. package/src/harness/artifacts/lint-configs.ts +136 -0
  130. package/src/harness/artifacts/review-agents.ts +67 -0
  131. package/src/harness/bare-entry.ts +108 -0
  132. package/src/harness/command.ts +1010 -0
  133. package/src/harness/default-agents/design.md +23 -0
  134. package/src/harness/default-agents/discover.md +18 -0
  135. package/src/harness/default-agents/implement.md +24 -0
  136. package/src/harness/default-agents/plan.md +19 -0
  137. package/src/harness/default-agents/research.md +21 -0
  138. package/src/harness/default-agents/validate.md +22 -0
  139. package/src/harness/gc/reporter.ts +28 -0
  140. package/src/harness/gc/runner.ts +136 -0
  141. package/src/harness/hooks/layer-context-inject.ts +155 -0
  142. package/src/harness/hooks/post-session-sweep.ts +130 -0
  143. package/src/harness/hooks/pre-edit-dupe-probe.ts +224 -0
  144. package/src/harness/hooks/register.ts +118 -0
  145. package/src/harness/model.ts +117 -0
  146. package/src/harness/pipeline.ts +348 -0
  147. package/src/harness/project-paths.ts +235 -0
  148. package/src/harness/stage-runner.ts +107 -0
  149. package/src/harness/stages/design.ts +386 -0
  150. package/src/harness/stages/discover.ts +454 -0
  151. package/src/harness/stages/implement.ts +162 -0
  152. package/src/harness/stages/plan.ts +335 -0
  153. package/src/harness/stages/research.ts +263 -0
  154. package/src/harness/stages/validate.ts +684 -0
  155. package/src/harness/storage.ts +467 -0
  156. package/src/harness/tools.ts +426 -0
  157. package/src/lsp/bridge.ts +56 -95
  158. package/src/lsp/capabilities.ts +108 -0
  159. package/src/lsp/contracts.ts +35 -0
  160. package/src/lsp/detector.ts +8 -12
  161. package/src/markdown-frontmatter.ts +68 -0
  162. package/src/mempalace/bridge.ts +129 -0
  163. package/src/mempalace/config.ts +75 -0
  164. package/src/mempalace/format.ts +163 -0
  165. package/src/mempalace/hooks.ts +370 -0
  166. package/src/mempalace/installer-helper.ts +194 -0
  167. package/src/mempalace/python/mempalace_bridge.py +440 -0
  168. package/src/mempalace/runtime.ts +565 -0
  169. package/src/mempalace/schema.ts +264 -0
  170. package/src/mempalace/session-summary.ts +198 -0
  171. package/src/mempalace/tool.ts +186 -0
  172. package/src/mempalace/uv.ts +256 -0
  173. package/src/migrate/runner.ts +354 -0
  174. package/src/planning/approval-flow.ts +206 -9
  175. package/src/planning/plan-writer-prompt.ts +4 -3
  176. package/src/planning/planning-ask-tool.ts +39 -0
  177. package/src/planning/render-markdown.ts +74 -0
  178. package/src/planning/spec.ts +42 -0
  179. package/src/planning/system-prompt.ts +11 -8
  180. package/src/planning/validate.ts +84 -0
  181. package/src/platform/omp.ts +15 -2
  182. package/src/platform/system-prompt.ts +37 -0
  183. package/src/platform/test-utils.ts +3 -0
  184. package/src/platform/types.ts +6 -1
  185. package/src/qa/config.ts +12 -6
  186. package/src/qa/detect-app-type.ts +13 -6
  187. package/src/qa/matrix.ts +12 -6
  188. package/src/qa/prompt-builder.ts +28 -30
  189. package/src/qa/scripts/dev-server-utils.ts +72 -0
  190. package/src/qa/scripts/run-e2e-tests.ts +226 -0
  191. package/src/qa/scripts/start-dev-server.ts +138 -0
  192. package/src/qa/scripts/stop-dev-server.ts +77 -0
  193. package/src/qa/session.ts +13 -7
  194. package/src/quality/ai-setup.ts +27 -25
  195. package/src/quality/contracts.ts +34 -0
  196. package/src/quality/gates/ai-review.ts +20 -58
  197. package/src/quality/gates/command.ts +249 -46
  198. package/src/quality/review-gates.ts +18 -2
  199. package/src/quality/runner.ts +63 -22
  200. package/src/quality/schemas.ts +37 -2
  201. package/src/quality/setup.ts +96 -16
  202. package/src/release/changelog.ts +1 -1
  203. package/src/release/channels/custom.ts +13 -3
  204. package/src/release/channels/types.ts +5 -0
  205. package/src/release/contracts.ts +90 -0
  206. package/src/release/executor.ts +122 -45
  207. package/src/release/prompt.ts +18 -2
  208. package/src/release/targets.ts +86 -0
  209. package/src/release/version.ts +96 -71
  210. package/src/review/agent-loader.ts +298 -127
  211. package/src/review/fixer.ts +10 -6
  212. package/src/review/multi-agent-runner.ts +115 -14
  213. package/src/review/output.ts +12 -139
  214. package/src/review/runner.ts +12 -6
  215. package/src/review/scope.ts +144 -24
  216. package/src/review/types.ts +11 -20
  217. package/src/review/validator.ts +12 -6
  218. package/src/storage/fix-pr-sessions.ts +21 -14
  219. package/src/storage/plans.ts +14 -5
  220. package/src/storage/qa-sessions.ts +25 -19
  221. package/src/storage/reliability-metrics.ts +180 -0
  222. package/src/storage/reports.ts +8 -7
  223. package/src/storage/review-sessions.ts +55 -20
  224. package/src/tool-catalog/active-tool-controller.ts +164 -0
  225. package/src/tool-catalog/active-tool-planner.ts +212 -0
  226. package/src/tool-catalog/tool-groups.ts +102 -0
  227. package/src/types.ts +1401 -5
  228. package/src/ui-design/backend-adapter.ts +78 -0
  229. package/src/ui-design/backends/local-html.ts +82 -0
  230. package/src/ui-design/backends/pencil-mcp.ts +111 -0
  231. package/src/ui-design/components-scanner.ts +124 -0
  232. package/src/ui-design/config.ts +55 -0
  233. package/src/ui-design/pen-scanner.ts +95 -0
  234. package/src/ui-design/pen-selector.ts +72 -0
  235. package/src/ui-design/prompt-builder.ts +73 -0
  236. package/src/ui-design/scanner.ts +136 -0
  237. package/src/ui-design/session.ts +974 -0
  238. package/src/ui-design/system-prompt.ts +312 -0
  239. package/src/ui-design/tokens-scanner.ts +181 -0
  240. package/src/ui-design/types.ts +96 -0
  241. package/src/ultraplan/agent-catalog.ts +522 -0
  242. package/src/ultraplan/authoring/agent-catalog.ts +310 -0
  243. package/src/ultraplan/authoring/authoring-tools.ts +552 -0
  244. package/src/ultraplan/authoring/command-handlers.ts +339 -0
  245. package/src/ultraplan/authoring/markdown.ts +510 -0
  246. package/src/ultraplan/authoring/model.ts +162 -0
  247. package/src/ultraplan/authoring/pipeline.ts +319 -0
  248. package/src/ultraplan/authoring/stage-runner.ts +141 -0
  249. package/src/ultraplan/authoring/stages/approve.ts +249 -0
  250. package/src/ultraplan/authoring/stages/discover.ts +289 -0
  251. package/src/ultraplan/authoring/stages/intake.ts +203 -0
  252. package/src/ultraplan/authoring/stages/research.ts +399 -0
  253. package/src/ultraplan/authoring/stages/review.ts +333 -0
  254. package/src/ultraplan/authoring/stages/scout.ts +188 -0
  255. package/src/ultraplan/authoring/stages/synthesize.ts +348 -0
  256. package/src/ultraplan/authoring/storage.ts +594 -0
  257. package/src/ultraplan/authoring/synth-gate.ts +165 -0
  258. package/src/ultraplan/authoring-draft.ts +653 -0
  259. package/src/ultraplan/authoring-persist.ts +180 -0
  260. package/src/ultraplan/authoring-tool.ts +608 -0
  261. package/src/ultraplan/authoring-wizard.ts +587 -0
  262. package/src/ultraplan/batch/merge.ts +98 -0
  263. package/src/ultraplan/batch/planner.ts +150 -0
  264. package/src/ultraplan/batch/presenter.ts +97 -0
  265. package/src/ultraplan/batch/storage.ts +420 -0
  266. package/src/ultraplan/batch/supervisor.ts +317 -0
  267. package/src/ultraplan/batch/worker.ts +26 -0
  268. package/src/ultraplan/batch/worktree.ts +110 -0
  269. package/src/ultraplan/contracts.ts +1593 -0
  270. package/src/ultraplan/default-agents/authoring/discoverer.md +12 -0
  271. package/src/ultraplan/default-agents/authoring/intake.md +12 -0
  272. package/src/ultraplan/default-agents/authoring/planner.md +12 -0
  273. package/src/ultraplan/default-agents/authoring/researcher.md +12 -0
  274. package/src/ultraplan/default-agents/authoring/scope-checker.md +12 -0
  275. package/src/ultraplan/default-agents/authoring/scout.md +12 -0
  276. package/src/ultraplan/default-agents/authoring/structure-checker.md +12 -0
  277. package/src/ultraplan/default-agents/authoring/tdd-checker.md +12 -0
  278. package/src/ultraplan/default-agents/backend-domain-reviewer.md +10 -0
  279. package/src/ultraplan/default-agents/backend-executor.md +10 -0
  280. package/src/ultraplan/default-agents/backend-stack-reviewer.md +10 -0
  281. package/src/ultraplan/default-agents/backend-tester.md +10 -0
  282. package/src/ultraplan/default-agents/frontend-domain-reviewer.md +10 -0
  283. package/src/ultraplan/default-agents/frontend-executor.md +10 -0
  284. package/src/ultraplan/default-agents/frontend-stack-reviewer.md +10 -0
  285. package/src/ultraplan/default-agents/frontend-tester.md +10 -0
  286. package/src/ultraplan/default-agents/infrastructure-domain-reviewer.md +10 -0
  287. package/src/ultraplan/default-agents/infrastructure-executor.md +10 -0
  288. package/src/ultraplan/default-agents/infrastructure-stack-reviewer.md +10 -0
  289. package/src/ultraplan/default-agents/infrastructure-tester.md +10 -0
  290. package/src/ultraplan/execution/contract.ts +71 -0
  291. package/src/ultraplan/execution/policy.ts +217 -0
  292. package/src/ultraplan/execution/runtime-tools.ts +107 -0
  293. package/src/ultraplan/execution/session-runner.ts +281 -0
  294. package/src/ultraplan/next-router.ts +85 -0
  295. package/src/ultraplan/presenter.ts +359 -0
  296. package/src/ultraplan/project-paths.ts +342 -0
  297. package/src/ultraplan/runtime/active-execution.ts +72 -0
  298. package/src/ultraplan/runtime/apply-mutation.ts +416 -0
  299. package/src/ultraplan/runtime/blockers.ts +243 -0
  300. package/src/ultraplan/runtime/hook-bridge.ts +486 -0
  301. package/src/ultraplan/runtime/launch-context.ts +207 -0
  302. package/src/ultraplan/runtime/migration.ts +524 -0
  303. package/src/ultraplan/runtime/normalize.ts +281 -0
  304. package/src/ultraplan/runtime/proof.ts +260 -0
  305. package/src/ultraplan/runtime/reducer.ts +416 -0
  306. package/src/ultraplan/runtime/repair.ts +251 -0
  307. package/src/ultraplan/runtime/tracker-storage.ts +368 -0
  308. package/src/ultraplan/session-selection.ts +291 -0
  309. package/src/ultraplan/storage.ts +374 -0
  310. package/src/utils/editor.ts +38 -0
  311. package/src/utils/executable.ts +80 -0
  312. package/src/utils/paths.ts +1 -20
  313. package/src/utils/shell.ts +31 -0
  314. package/src/visual/companion.ts +2 -1
  315. package/src/visual/scripts/frame-template.html +60 -0
  316. package/src/visual/scripts/index.js +59 -13
  317. package/src/visual/scripts/package.json +3 -0
  318. package/src/visual/start-server.ts +2 -1
  319. package/src/workspace/git-scope.ts +64 -0
  320. package/src/workspace/locks.ts +23 -0
  321. package/src/workspace/package-manager.ts +117 -0
  322. package/src/workspace/path-mapping.ts +75 -0
  323. package/src/workspace/project-slug.ts +92 -0
  324. package/src/workspace/repo-root.ts +137 -0
  325. package/src/workspace/selector.ts +115 -0
  326. package/src/workspace/state-paths.ts +118 -0
  327. package/src/workspace/targets.ts +313 -0
  328. package/src/fix-pr/scripts/diff-comments.sh +0 -33
  329. package/src/fix-pr/scripts/fetch-pr-comments.sh +0 -25
  330. package/src/fix-pr/scripts/trigger-review.sh +0 -36
  331. package/src/fix-pr/scripts/wait-and-check.sh +0 -37
  332. package/src/qa/scripts/detect-app-type.sh +0 -68
  333. package/src/qa/scripts/discover-routes.sh +0 -143
  334. package/src/qa/scripts/run-e2e-tests.sh +0 -131
  335. package/src/qa/scripts/start-dev-server.sh +0 -46
  336. package/src/qa/scripts/stop-dev-server.sh +0 -36
  337. package/src/review/prompts/fix-output-schema.md +0 -18
  338. package/src/review/prompts/review-output-schema.md +0 -38
  339. package/src/review/template.ts +0 -15
  340. /package/src/{review → ai}/prompts/invalid-output-retry.md +0 -0
@@ -11,12 +11,18 @@ import type {
11
11
  ReviewAgentDefinition,
12
12
  ReviewAgentsConfig,
13
13
  } from "../types.js";
14
- import { normalizeLineEndings } from "../text.js";
14
+ import { parseMarkdownFrontmatter } from "../markdown-frontmatter.js";
15
+ import { resolvePackageManager } from "../workspace/package-manager.js";
16
+ import { resolveRepoRootFromFs } from "../workspace/repo-root.js";
17
+ import {
18
+ getRootStateDir,
19
+ getWorkspaceStateDir,
20
+ } from "../workspace/state-paths.js";
21
+ import { discoverWorkspaceTargets } from "../workspace/targets.js";
22
+ import { collectValidationErrors, formatValidationErrors } from "../ai/structured-output.js";
15
23
  import {
16
24
  ReviewAgentFrontmatterSchema,
17
25
  ReviewAgentsConfigSchema,
18
- collectReviewValidationErrors,
19
- formatReviewValidationErrors,
20
26
  } from "./types.js";
21
27
 
22
28
  const REVIEW_AGENTS_DIR = "review-agents";
@@ -29,9 +35,9 @@ const DEFAULT_AGENT_TEMPLATES: Record<string, string> = {
29
35
  };
30
36
 
31
37
  const DEFAULT_REVIEW_AGENTS_CONFIG: ReviewAgentConfig[] = [
32
- { name: "security", enabled: true, data: "security.md", model: null },
33
- { name: "correctness", enabled: true, data: "correctness.md", model: null },
34
- { name: "maintainability", enabled: true, data: "maintainability.md", model: null },
38
+ { name: "security", enabled: true, data: "security.md", model: null, thinkingLevel: "low" },
39
+ { name: "correctness", enabled: true, data: "correctness.md", model: null, thinkingLevel: "low" },
40
+ { name: "maintainability", enabled: true, data: "maintainability.md", model: null, thinkingLevel: "low" },
35
41
  ];
36
42
 
37
43
  export interface LoadedReviewAgents {
@@ -41,19 +47,51 @@ export interface LoadedReviewAgents {
41
47
  agents: ConfiguredReviewAgent[];
42
48
  }
43
49
 
44
- function buildDefaultConfigText(): string {
50
+ export interface ReviewAgentLoadOptions {
51
+ repoRoot?: string;
52
+ workspaceRelativeDir?: string | null;
53
+ }
54
+
55
+ export interface ResolvedReviewAgentContext {
56
+ repoRoot: string;
57
+ workspaceRelativeDir: string | null;
58
+ }
59
+
60
+ const CONFIG_HEADER = [
61
+ "# Review Agents Configuration",
62
+ "#",
63
+ "# Options:",
64
+ "# name: string - agent identifier (kebab-case)",
65
+ "# enabled: boolean - true | false",
66
+ "# data: string - markdown file name in the agents directory",
67
+ "# model: string - model id (e.g. \"anthropic/claude-sonnet-4-20250514\") or null to inherit",
68
+ "# thinkingLevel: string - off | minimal | low | medium | high | xhigh | null to inherit",
69
+ "# peerCoordination: boolean - opt this agent into IRC peer coordination (multi-agent reviews only); omit or set false to disable",
70
+ "#",
71
+ ].join("\n");
72
+
73
+ function serializeConfigYaml(agents: ReviewAgentConfig[]): string {
45
74
  return [
75
+ CONFIG_HEADER,
76
+ "",
46
77
  "agents:",
47
- ...DEFAULT_REVIEW_AGENTS_CONFIG.flatMap((agent) => [
48
- ` - name: ${agent.name}`,
49
- ` enabled: ${agent.enabled}`,
50
- ` data: ${agent.data}`,
51
- " model: null",
78
+ ...agents.flatMap((a, i) => [
79
+ ...(i > 0 ? [""] : []),
80
+ ` - name: ${a.name}`,
81
+ ` enabled: ${a.enabled}`,
82
+ ` data: ${a.data}`,
83
+ ` model: ${a.model ?? "null"}`,
84
+ ` thinkingLevel: ${a.thinkingLevel ?? "null"}`,
85
+ ...(a.peerCoordination === true ? [` peerCoordination: true`] : []),
52
86
  ]),
53
87
  "",
54
88
  ].join("\n");
55
89
  }
56
90
 
91
+ function buildDefaultConfigText(): string {
92
+ return serializeConfigYaml(DEFAULT_REVIEW_AGENTS_CONFIG);
93
+ }
94
+
57
95
  function writeIfMissing(filePath: string, content: string): void {
58
96
  if (fs.existsSync(filePath)) {
59
97
  return;
@@ -62,8 +100,60 @@ function writeIfMissing(filePath: string, content: string): void {
62
100
  fs.writeFileSync(filePath, content);
63
101
  }
64
102
 
103
+ /**
104
+ * Migrate pre-existing config.yml files:
105
+ * - adds the comment header if missing
106
+ * - backfills thinkingLevel on agents that lack it
107
+ */
108
+ function migrateConfigIfNeeded(configPath: string): void {
109
+ if (!fs.existsSync(configPath)) return;
110
+
111
+ const raw = fs.readFileSync(configPath, "utf-8");
112
+ if (raw.startsWith("# Review Agents Configuration")) return;
113
+
114
+ // Parse the bare YAML by hand — we only need name/enabled/data/model/thinkingLevel.
115
+ // The file is small and always has the same shape.
116
+ const agents: ReviewAgentConfig[] = [];
117
+ let current: Partial<ReviewAgentConfig> | null = null;
118
+
119
+ for (const line of raw.split("\n")) {
120
+ const trimmed = line.trim();
121
+ if (trimmed.startsWith("- name:")) {
122
+ if (current?.name) agents.push(current as ReviewAgentConfig);
123
+ current = { name: trimmed.slice("- name:".length).trim() };
124
+ } else if (current && trimmed.startsWith("enabled:")) {
125
+ current.enabled = trimmed.slice("enabled:".length).trim() === "true";
126
+ } else if (current && trimmed.startsWith("data:")) {
127
+ current.data = trimmed.slice("data:".length).trim();
128
+ } else if (current && trimmed.startsWith("model:")) {
129
+ const val = trimmed.slice("model:".length).trim();
130
+ current.model = val === "null" ? null : val;
131
+ } else if (current && trimmed.startsWith("thinkingLevel:")) {
132
+ const val = trimmed.slice("thinkingLevel:".length).trim();
133
+ current.thinkingLevel = val === "null" ? null : (val as any);
134
+ } else if (current && trimmed.startsWith("peerCoordination:")) {
135
+ const val = trimmed.slice("peerCoordination:".length).trim();
136
+ if (val === "true") {
137
+ current.peerCoordination = true;
138
+ } else if (val === "false") {
139
+ current.peerCoordination = false;
140
+ }
141
+ }
142
+ }
143
+ if (current?.name) agents.push(current as ReviewAgentConfig);
144
+
145
+ // Backfill thinkingLevel for agents that didn't have it
146
+ for (const agent of agents) {
147
+ if (agent.thinkingLevel === undefined) {
148
+ agent.thinkingLevel = null;
149
+ }
150
+ }
151
+
152
+ fs.writeFileSync(configPath, serializeConfigYaml(agents));
153
+ }
154
+
65
155
  function validateReviewAgentsConfig(data: unknown): ReviewAgentsConfig {
66
- const errors = formatReviewValidationErrors(collectReviewValidationErrors(ReviewAgentsConfigSchema, data));
156
+ const errors = formatValidationErrors(collectValidationErrors(ReviewAgentsConfigSchema, data));
67
157
  if (errors.length > 0) {
68
158
  throw new Error(`Invalid review-agents config: ${errors.join("; ")}`);
69
159
  }
@@ -77,57 +167,27 @@ async function importYamlFile(filePath: string): Promise<unknown> {
77
167
  return imported.default;
78
168
  }
79
169
 
80
- function parseFrontmatter(frontmatter: string, filePath: string): ReviewAgentDefinition {
81
- const metadata: Record<string, unknown> = {};
82
-
83
- for (const line of frontmatter.split("\n")) {
84
- const trimmed = line.trim();
85
- if (!trimmed) {
86
- continue;
87
- }
88
-
89
- const separator = trimmed.indexOf(":");
90
- if (separator === -1) {
91
- continue;
92
- }
93
-
94
- const key = trimmed.slice(0, separator).trim();
95
- const value = trimmed.slice(separator + 1).trim();
96
- metadata[key] = value;
97
- }
98
-
99
- const errors = formatReviewValidationErrors(
100
- collectReviewValidationErrors(ReviewAgentFrontmatterSchema, metadata),
170
+ export function parseReviewAgentMarkdown(content: string, filePath: string): ReviewAgentDefinition {
171
+ const { frontmatter, body } = parseMarkdownFrontmatter(content, filePath);
172
+ const errors = formatValidationErrors(
173
+ collectValidationErrors(ReviewAgentFrontmatterSchema, frontmatter),
101
174
  );
102
175
  if (errors.length > 0) {
103
176
  throw new Error(`Invalid agent frontmatter in ${filePath}: ${errors.join("; ")}`);
104
177
  }
105
178
 
106
- return {
107
- name: String(metadata.name),
108
- description: String(metadata.description),
109
- focus: typeof metadata.focus === "string" ? metadata.focus : null,
110
- prompt: "",
111
- filePath,
179
+ const parsed = frontmatter as {
180
+ name: string;
181
+ description: string;
182
+ focus?: string;
112
183
  };
113
- }
114
-
115
- export function parseReviewAgentMarkdown(content: string, filePath: string): ReviewAgentDefinition {
116
- const normalized = normalizeLineEndings(content);
117
- const match = normalized.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
118
- if (!match) {
119
- throw new Error(`Review agent file ${filePath} is missing YAML frontmatter.`);
120
- }
121
-
122
- const definition = parseFrontmatter(match[1], filePath);
123
- const prompt = match[2]?.trim();
124
- if (!prompt) {
125
- throw new Error(`Review agent file ${filePath} has an empty prompt body.`);
126
- }
127
184
 
128
185
  return {
129
- ...definition,
130
- prompt,
186
+ name: parsed.name,
187
+ description: parsed.description,
188
+ focus: parsed.focus ?? null,
189
+ prompt: body,
190
+ filePath,
131
191
  };
132
192
  }
133
193
 
@@ -139,36 +199,71 @@ export function getReviewAgentsConfigPath(paths: PlatformPaths, cwd: string): st
139
199
  return path.join(getReviewAgentsDir(paths, cwd), CONFIG_FILE);
140
200
  }
141
201
 
142
- export function ensureDefaultReviewAgents(paths: PlatformPaths, cwd: string): void {
143
- const agentsDir = getReviewAgentsDir(paths, cwd);
144
- fs.mkdirSync(agentsDir, { recursive: true });
202
+ export function getRootReviewAgentsDir(paths: PlatformPaths, repoRoot: string): string {
203
+ return path.join(getRootStateDir(paths, repoRoot), REVIEW_AGENTS_DIR);
204
+ }
145
205
 
146
- // Default agent markdown files are installed globally only.
147
- writeIfMissing(getReviewAgentsConfigPath(paths, cwd), buildDefaultConfigText());
206
+ export function getRootReviewAgentsConfigPath(paths: PlatformPaths, repoRoot: string): string {
207
+ return path.join(getRootReviewAgentsDir(paths, repoRoot), CONFIG_FILE);
148
208
  }
149
209
 
150
- export async function loadReviewAgentsConfig(paths: PlatformPaths, cwd: string): Promise<ReviewAgentsConfig> {
151
- ensureGlobalDefaultReviewAgents(paths);
152
- ensureDefaultReviewAgents(paths, cwd);
153
- return validateReviewAgentsConfig(await importYamlFile(getReviewAgentsConfigPath(paths, cwd)));
210
+ export function getWorkspaceReviewAgentsDir(
211
+ paths: PlatformPaths,
212
+ repoRoot: string,
213
+ workspaceRelativeDir: string,
214
+ ): string {
215
+ return path.join(getWorkspaceStateDir(paths, repoRoot, workspaceRelativeDir), REVIEW_AGENTS_DIR);
154
216
  }
155
217
 
156
- export async function loadReviewAgents(paths: PlatformPaths, cwd: string): Promise<LoadedReviewAgents> {
157
- const agentsDir = getReviewAgentsDir(paths, cwd);
158
- const configPath = getReviewAgentsConfigPath(paths, cwd);
159
- const globalAgentsDir = getGlobalReviewAgentsDir(paths);
160
- const config = await loadReviewAgentsConfig(paths, cwd);
218
+ export function getWorkspaceReviewAgentsConfigPath(
219
+ paths: PlatformPaths,
220
+ repoRoot: string,
221
+ workspaceRelativeDir: string,
222
+ ): string {
223
+ return path.join(getWorkspaceReviewAgentsDir(paths, repoRoot, workspaceRelativeDir), CONFIG_FILE);
224
+ }
225
+
226
+
227
+ export function resolveReviewAgentContext(
228
+ cwd: string,
229
+ options?: ReviewAgentLoadOptions,
230
+ ): ResolvedReviewAgentContext {
231
+ const repoRoot = options?.repoRoot ?? resolveRepoRootFromFs(cwd);
232
+ const explicitWorkspaceRelativeDir = options?.workspaceRelativeDir;
233
+ if (explicitWorkspaceRelativeDir !== undefined) {
234
+ return {
235
+ repoRoot,
236
+ workspaceRelativeDir: explicitWorkspaceRelativeDir && explicitWorkspaceRelativeDir !== "."
237
+ ? explicitWorkspaceRelativeDir
238
+ : null,
239
+ };
240
+ }
161
241
 
162
- const agents = config.agents
242
+ const packageManager = resolvePackageManager(repoRoot);
243
+ const workspaceTarget = discoverWorkspaceTargets(repoRoot, packageManager.id)
244
+ .filter((target) => cwd === target.packageDir || cwd.startsWith(`${target.packageDir}${path.sep}`))
245
+ .sort((left, right) => right.packageDir.length - left.packageDir.length)[0];
246
+
247
+ return {
248
+ repoRoot,
249
+ workspaceRelativeDir: workspaceTarget?.kind === "workspace" ? workspaceTarget.relativeDir : null,
250
+ };
251
+ }
252
+
253
+ function loadAgentsFromConfig(
254
+ config: ReviewAgentsConfig,
255
+ lookupDirs: string[],
256
+ missingScopeLabel: string,
257
+ scope?: ConfiguredReviewAgent["scope"],
258
+ ): ConfiguredReviewAgent[] {
259
+ return config.agents
163
260
  .filter((agent) => agent.enabled)
164
261
  .map((agent) => {
165
- const projectFilePath = path.join(agentsDir, agent.data);
166
- const globalFilePath = path.join(globalAgentsDir, agent.data);
167
- const filePath = fs.existsSync(projectFilePath) ? projectFilePath : globalFilePath;
168
- if (!fs.existsSync(filePath)) {
169
- throw new Error(
170
- `Configured review agent file does not exist in project or global scope: ${agent.data}`
171
- );
262
+ const filePath = lookupDirs
263
+ .map((dir) => path.join(dir, agent.data))
264
+ .find((candidatePath) => fs.existsSync(candidatePath));
265
+ if (!filePath) {
266
+ throw new Error(`Configured review agent file does not exist in ${missingScopeLabel}: ${agent.data}`);
172
267
  }
173
268
 
174
269
  const definition = parseReviewAgentMarkdown(fs.readFileSync(filePath, "utf-8"), filePath);
@@ -183,8 +278,56 @@ export async function loadReviewAgents(paths: PlatformPaths, cwd: string): Promi
183
278
  enabled: agent.enabled,
184
279
  data: agent.data,
185
280
  model: agent.model,
281
+ thinkingLevel: agent.thinkingLevel ?? null,
282
+ ...(agent.peerCoordination === true ? { peerCoordination: true } : {}),
283
+ ...(scope ? { scope } : {}),
186
284
  } satisfies ConfiguredReviewAgent;
187
285
  });
286
+ }
287
+
288
+ function mergeAgentLayers(
289
+ lowerAgents: ConfiguredReviewAgent[],
290
+ higherAgents: ConfiguredReviewAgent[],
291
+ higherConfig: ReviewAgentsConfig,
292
+ ): ConfiguredReviewAgent[] {
293
+ const higherConfigNames = new Set(higherConfig.agents.map((agent) => agent.name));
294
+ return [
295
+ ...lowerAgents.filter((agent) => !higherConfigNames.has(agent.name)),
296
+ ...higherAgents,
297
+ ];
298
+ }
299
+
300
+ export function ensureDefaultReviewAgents(paths: PlatformPaths, cwd: string): void {
301
+ const agentsDir = getReviewAgentsDir(paths, cwd);
302
+ fs.mkdirSync(agentsDir, { recursive: true });
303
+
304
+ // Default agent markdown files are installed globally only.
305
+ writeIfMissing(getReviewAgentsConfigPath(paths, cwd), buildDefaultConfigText());
306
+ migrateConfigIfNeeded(getReviewAgentsConfigPath(paths, cwd));
307
+ }
308
+
309
+ export async function loadReviewAgentsConfig(
310
+ paths: PlatformPaths,
311
+ cwd: string,
312
+ options?: ReviewAgentLoadOptions,
313
+ ): Promise<ReviewAgentsConfig> {
314
+ const context = resolveReviewAgentContext(cwd, options);
315
+ ensureGlobalDefaultReviewAgents(paths);
316
+ ensureDefaultReviewAgents(paths, context.repoRoot);
317
+ return validateReviewAgentsConfig(await importYamlFile(getRootReviewAgentsConfigPath(paths, context.repoRoot)));
318
+ }
319
+
320
+ export async function loadReviewAgents(
321
+ paths: PlatformPaths,
322
+ cwd: string,
323
+ options?: ReviewAgentLoadOptions,
324
+ ): Promise<LoadedReviewAgents> {
325
+ const context = resolveReviewAgentContext(cwd, options);
326
+ const agentsDir = getRootReviewAgentsDir(paths, context.repoRoot);
327
+ const configPath = getRootReviewAgentsConfigPath(paths, context.repoRoot);
328
+ const globalAgentsDir = getGlobalReviewAgentsDir(paths);
329
+ const config = await loadReviewAgentsConfig(paths, cwd, context);
330
+ const agents = loadAgentsFromConfig(config, [agentsDir, globalAgentsDir], "root or global scope");
188
331
 
189
332
  return {
190
333
  agentsDir,
@@ -213,6 +356,7 @@ export function ensureGlobalDefaultReviewAgents(paths: PlatformPaths): void {
213
356
  }
214
357
 
215
358
  writeIfMissing(getGlobalReviewAgentsConfigPath(paths), buildDefaultConfigText());
359
+ migrateConfigIfNeeded(getGlobalReviewAgentsConfigPath(paths));
216
360
  }
217
361
 
218
362
  export async function loadGlobalReviewAgentsConfig(paths: PlatformPaths): Promise<ReviewAgentsConfig> {
@@ -224,30 +368,64 @@ export async function loadGlobalReviewAgents(paths: PlatformPaths): Promise<Load
224
368
  const agentsDir = getGlobalReviewAgentsDir(paths);
225
369
  const configPath = getGlobalReviewAgentsConfigPath(paths);
226
370
  const config = await loadGlobalReviewAgentsConfig(paths);
371
+ const agents = loadAgentsFromConfig(config, [agentsDir], "global scope", "global");
227
372
 
228
- const agents = config.agents
229
- .filter((agent) => agent.enabled)
230
- .map((agent) => {
231
- const filePath = path.join(agentsDir, agent.data);
232
- if (!fs.existsSync(filePath)) {
233
- throw new Error(`Configured review agent file does not exist: ${filePath}`);
234
- }
373
+ return {
374
+ agentsDir,
375
+ configPath,
376
+ config,
377
+ agents,
378
+ };
379
+ }
235
380
 
236
- const definition = parseReviewAgentMarkdown(fs.readFileSync(filePath, "utf-8"), filePath);
237
- if (definition.name !== agent.name) {
238
- throw new Error(
239
- `Configured agent name "${agent.name}" does not match frontmatter name "${definition.name}" in ${filePath}.`,
240
- );
241
- }
381
+ async function loadWorkspaceReviewAgentsConfig(
382
+ paths: PlatformPaths,
383
+ cwd: string,
384
+ options: ReviewAgentLoadOptions,
385
+ ): Promise<ReviewAgentsConfig> {
386
+ const context = resolveReviewAgentContext(cwd, options);
387
+ if (!context.workspaceRelativeDir) {
388
+ return { agents: [] };
389
+ }
242
390
 
243
- return {
244
- ...definition,
245
- enabled: agent.enabled,
246
- data: agent.data,
247
- model: agent.model,
248
- scope: "global" as const,
249
- } satisfies ConfiguredReviewAgent;
250
- });
391
+ const configPath = getWorkspaceReviewAgentsConfigPath(
392
+ paths,
393
+ context.repoRoot,
394
+ context.workspaceRelativeDir,
395
+ );
396
+ if (!fs.existsSync(configPath)) {
397
+ return { agents: [] };
398
+ }
399
+
400
+ migrateConfigIfNeeded(configPath);
401
+ return validateReviewAgentsConfig(await importYamlFile(configPath));
402
+ }
403
+
404
+ async function loadWorkspaceReviewAgents(
405
+ paths: PlatformPaths,
406
+ cwd: string,
407
+ options: ReviewAgentLoadOptions,
408
+ ): Promise<LoadedReviewAgents | null> {
409
+ const context = resolveReviewAgentContext(cwd, options);
410
+ if (!context.workspaceRelativeDir) {
411
+ return null;
412
+ }
413
+
414
+ const agentsDir = getWorkspaceReviewAgentsDir(paths, context.repoRoot, context.workspaceRelativeDir);
415
+ const configPath = getWorkspaceReviewAgentsConfigPath(
416
+ paths,
417
+ context.repoRoot,
418
+ context.workspaceRelativeDir,
419
+ );
420
+ const rootAgentsDir = getRootReviewAgentsDir(paths, context.repoRoot);
421
+ const globalAgentsDir = getGlobalReviewAgentsDir(paths);
422
+ const config = await loadWorkspaceReviewAgentsConfig(paths, cwd, context);
423
+ const agents = loadAgentsFromConfig(
424
+ config,
425
+ [agentsDir, rootAgentsDir, globalAgentsDir],
426
+ "workspace, root, or global scope",
427
+ "workspace",
428
+ );
251
429
 
252
430
  return {
253
431
  agentsDir,
@@ -257,31 +435,34 @@ export async function loadGlobalReviewAgents(paths: PlatformPaths): Promise<Load
257
435
  };
258
436
  }
259
437
 
260
- // ── Merged Loading (Global + Project) ──────────────────────
438
+ // ── Merged Loading (Global + Root + Workspace) ───────────────
261
439
 
262
440
  export async function loadMergedReviewAgents(
263
441
  paths: PlatformPaths,
264
442
  cwd: string,
443
+ options?: ReviewAgentLoadOptions,
265
444
  ): Promise<LoadedReviewAgents> {
445
+ const context = resolveReviewAgentContext(cwd, options);
266
446
  const globalResult = await loadGlobalReviewAgents(paths);
267
- const projectResult = await loadReviewAgents(paths, cwd);
268
-
269
- // Project config is authoritative: any agent named in the project config
270
- // (enabled or disabled) shadows the global version with the same name.
271
- const projectConfigNames = new Set(projectResult.config.agents.map((a) => a.name));
272
- const uniqueGlobalAgents = globalResult.agents.filter((a) => !projectConfigNames.has(a.name));
273
-
274
- // Tag project agents with scope
275
- const projectAgents = projectResult.agents.map((agent) => ({
276
- ...agent,
277
- scope: "project" as const,
278
- }));
447
+ const rootResult = await loadReviewAgents(paths, cwd, context);
448
+ const rootAgents = rootResult.agents.map((agent) => ({ ...agent, scope: "root" as const }));
449
+ const mergedRootAgents = mergeAgentLayers(globalResult.agents, rootAgents, rootResult.config);
450
+
451
+ const workspaceResult = await loadWorkspaceReviewAgents(paths, cwd, context);
452
+ if (!workspaceResult) {
453
+ return {
454
+ agentsDir: rootResult.agentsDir,
455
+ configPath: rootResult.configPath,
456
+ config: rootResult.config,
457
+ agents: mergedRootAgents,
458
+ };
459
+ }
279
460
 
280
461
  return {
281
- agentsDir: projectResult.agentsDir,
282
- configPath: projectResult.configPath,
283
- config: projectResult.config,
284
- agents: [...uniqueGlobalAgents, ...projectAgents],
462
+ agentsDir: workspaceResult.agentsDir,
463
+ configPath: workspaceResult.configPath,
464
+ config: workspaceResult.config,
465
+ agents: mergeAgentLayers(mergedRootAgents, workspaceResult.agents, workspaceResult.config),
285
466
  };
286
467
  }
287
468
 
@@ -321,15 +502,5 @@ export async function addAgentToConfig(
321
502
  config.agents.push(agent);
322
503
  }
323
504
 
324
- const text = [
325
- "agents:",
326
- ...config.agents.flatMap((a) => [
327
- ` - name: ${a.name}`,
328
- ` enabled: ${a.enabled}`,
329
- ` data: ${a.data}`,
330
- ` model: ${a.model ?? "null"}`,
331
- ]),
332
- "",
333
- ].join("\n");
334
- fs.writeFileSync(configPath, text);
505
+ fs.writeFileSync(configPath, serializeConfigYaml(config.agents));
335
506
  }
@@ -1,5 +1,4 @@
1
1
  import fixFindingsPrompt from "./prompts/fix-findings.md" with { type: "text" };
2
- import fixOutputSchemaPrompt from "./prompts/fix-output-schema.md" with { type: "text" };
3
2
  import type {
4
3
  GateExecutionContext,
5
4
  ReviewFinding,
@@ -8,9 +7,12 @@ import type {
8
7
  ReviewOutput,
9
8
  ReviewScope,
10
9
  } from "../types.js";
11
- import { parseStructuredOutput, runWithOutputValidation } from "./output.js";
10
+ import { parseStructuredOutput, runWithOutputValidation, type ReliabilityReporter } from "../ai/structured-output.js";
11
+ import { renderSchemaText } from "../ai/schema-text.js";
12
12
  import { ReviewFixOutputSchema } from "./types.js";
13
- import { renderReviewTemplate } from "./template.js";
13
+ import { renderTemplate } from "../ai/template.js";
14
+
15
+ const REVIEW_FIX_OUTPUT_SCHEMA_TEXT = renderSchemaText(ReviewFixOutputSchema);
14
16
 
15
17
  export interface ReviewFixInput {
16
18
  cwd: string;
@@ -20,6 +22,7 @@ export interface ReviewFixInput {
20
22
  model?: string;
21
23
  thinkingLevel?: string | null;
22
24
  timeoutMs?: number;
25
+ reliability?: ReliabilityReporter;
23
26
  }
24
27
 
25
28
  export interface ReviewFixRunResult {
@@ -127,10 +130,10 @@ function normalizeFixOutput(
127
130
  }
128
131
 
129
132
  export function buildFixPrompt(scope: ReviewScope, findings: ReviewFinding[]): string {
130
- return renderReviewTemplate(fixFindingsPrompt, {
133
+ return renderTemplate(fixFindingsPrompt, {
131
134
  scope,
132
135
  findingsJson: JSON.stringify(findings, null, 2),
133
- fixOutputSchema: fixOutputSchemaPrompt.trim(),
136
+ fixOutputSchema: REVIEW_FIX_OUTPUT_SCHEMA_TEXT,
134
137
  });
135
138
  }
136
139
 
@@ -158,13 +161,14 @@ export async function runAutoFix(input: ReviewFixInput): Promise<ReviewFixRunRes
158
161
  const result = await runWithOutputValidation(input.createAgentSession, {
159
162
  cwd: input.cwd,
160
163
  prompt: buildFixPrompt(input.scope, fixableFindings),
161
- schema: fixOutputSchemaPrompt.trim(),
164
+ schema: REVIEW_FIX_OUTPUT_SCHEMA_TEXT,
162
165
  parse(raw) {
163
166
  return parseStructuredOutput<ReviewFixOutput>(raw, ReviewFixOutputSchema);
164
167
  },
165
168
  model: input.model,
166
169
  thinkingLevel: input.thinkingLevel ?? null,
167
170
  timeoutMs: input.timeoutMs ?? 180_000,
171
+ reliability: input.reliability,
168
172
  });
169
173
 
170
174
  if (result.status === "blocked") {