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.
- package/README.md +14 -8
- package/bin/install.mjs +20 -5
- package/bin/install.ts +95 -0
- package/package.json +8 -4
- package/skills/context-mode/SKILL.md +17 -10
- package/skills/harness/SKILL.md +94 -0
- package/skills/ui-design/SKILL.md +63 -0
- package/skills/ui-design/sub-agent-templates/component-builder.md +29 -0
- package/skills/ui-design/sub-agent-templates/design-critic.md +46 -0
- package/skills/ui-design/sub-agent-templates/pencil/component-builder.md +29 -0
- package/skills/ui-design/sub-agent-templates/pencil/design-critic.md +42 -0
- package/skills/ui-design/sub-agent-templates/pencil/section-assembler.md +27 -0
- package/skills/ui-design/sub-agent-templates/section-assembler.md +27 -0
- package/skills/ultraplan-discover/SKILL.md +96 -0
- package/skills/ultraplan-intake/SKILL.md +89 -0
- package/skills/ultraplan-research/SKILL.md +129 -0
- package/skills/ultraplan-review/SKILL.md +86 -0
- package/skills/ultraplan-review-scope/SKILL.md +111 -0
- package/skills/ultraplan-review-structure/SKILL.md +120 -0
- package/skills/ultraplan-review-tdd/SKILL.md +142 -0
- package/skills/ultraplan-scout/SKILL.md +110 -0
- package/skills/ultraplan-synthesize/SKILL.md +124 -0
- package/src/{quality/ai-session.ts → ai/final-message.ts} +27 -0
- package/src/ai/schema-text.ts +129 -0
- package/src/ai/structured-output.ts +274 -0
- package/src/ai/template.ts +27 -0
- package/src/bootstrap.ts +63 -28
- package/src/commands/agents.ts +149 -45
- package/src/commands/ai-review.ts +251 -30
- package/src/commands/clear.ts +434 -0
- package/src/commands/commit.ts +1 -0
- package/src/commands/config.ts +242 -44
- package/src/commands/context.ts +55 -28
- package/src/commands/doctor.ts +234 -6
- package/src/commands/fix-pr.ts +306 -131
- package/src/commands/generate.ts +111 -21
- package/src/commands/memory.ts +192 -0
- package/src/commands/model-picker.ts +28 -21
- package/src/commands/model.ts +19 -9
- package/src/commands/optimize-context.ts +408 -29
- package/src/commands/plan.ts +2 -0
- package/src/commands/qa.ts +312 -137
- package/src/commands/release.ts +259 -76
- package/src/commands/review.ts +293 -59
- package/src/commands/status.ts +200 -13
- package/src/commands/supi.ts +3 -35
- package/src/commands/ui-design.ts +394 -0
- package/src/commands/ultraplan.ts +1518 -0
- package/src/commands/update.ts +86 -0
- package/src/config/defaults.ts +62 -0
- package/src/config/loader.ts +448 -60
- package/src/config/schema.ts +108 -2
- package/src/context/optimizer.ts +25 -33
- package/src/context/rule-renderer.ts +223 -0
- package/src/context/savings.ts +258 -0
- package/src/context/startup-check.ts +380 -0
- package/src/context/startup-optimizer.ts +355 -0
- package/src/context/tokenignore.ts +146 -0
- package/src/context-mode/cache-handle.ts +49 -0
- package/src/context-mode/cache-preview.ts +71 -0
- package/src/context-mode/cache-store.ts +738 -0
- package/src/context-mode/compressor.ts +131 -26
- package/src/context-mode/dedup.ts +108 -0
- package/src/context-mode/detector.ts +35 -4
- package/src/context-mode/event-extractor.ts +14 -12
- package/src/context-mode/event-store.ts +91 -36
- package/src/context-mode/hooks.ts +798 -56
- package/src/context-mode/knowledge/store.ts +255 -11
- package/src/context-mode/memory-store.ts +325 -0
- package/src/context-mode/metrics-recorder.ts +158 -0
- package/src/context-mode/metrics-store.ts +765 -0
- package/src/context-mode/model.ts +24 -0
- package/src/context-mode/processor-keys.ts +29 -0
- package/src/context-mode/processors/build.ts +66 -0
- package/src/context-mode/processors/docker.ts +57 -0
- package/src/context-mode/processors/git.ts +111 -0
- package/src/context-mode/processors/json.ts +112 -0
- package/src/context-mode/processors/k8s.ts +67 -0
- package/src/context-mode/processors/lint.ts +67 -0
- package/src/context-mode/processors/log.ts +86 -0
- package/src/context-mode/processors/registry.ts +116 -0
- package/src/context-mode/processors/test-runner.ts +102 -0
- package/src/context-mode/processors/types.ts +20 -0
- package/src/context-mode/repomap.ts +400 -0
- package/src/context-mode/routing.ts +97 -24
- package/src/context-mode/sandbox/runners.ts +5 -1
- package/src/context-mode/snapshot-builder.ts +106 -11
- package/src/context-mode/source-hash.ts +173 -0
- package/src/context-mode/tool-name.ts +11 -0
- package/src/context-mode/tools.ts +654 -22
- package/src/context-mode/web/fetcher.ts +31 -12
- package/src/debug/logger.ts +2 -1
- package/src/deps/registry.ts +1 -1
- package/src/discipline/failure-summarizer.ts +170 -0
- package/src/discipline/failure-taxonomy.ts +131 -0
- package/src/discipline/workflow-invariants.ts +125 -0
- package/src/discovery/index.ts +31 -0
- package/src/discovery/lsp.ts +87 -0
- package/src/discovery/rank.ts +144 -0
- package/src/discovery/sources.ts +89 -0
- package/src/discovery/workflow.ts +87 -0
- package/src/docs/contracts.ts +39 -0
- package/src/docs/drift.ts +117 -87
- package/src/fix-pr/assessment.ts +200 -0
- package/src/fix-pr/contracts.ts +47 -0
- package/src/fix-pr/fetch-comments.ts +80 -0
- package/src/fix-pr/prompt-builder.ts +58 -40
- package/src/fix-pr/scripts/exec.ts +34 -0
- package/src/fix-pr/scripts/trigger-review.ts +106 -0
- package/src/fix-pr/scripts/wait-and-check.ts +108 -0
- package/src/fix-pr/types.ts +4 -0
- package/src/git/branch-finish.ts +5 -0
- package/src/git/commit-contract.ts +83 -0
- package/src/git/commit.ts +121 -184
- package/src/git/status.ts +62 -8
- package/src/harness/anti_slop/architecture-parser.ts +210 -0
- package/src/harness/anti_slop/backend-factory.ts +30 -0
- package/src/harness/anti_slop/backend.ts +140 -0
- package/src/harness/anti_slop/desloppify-adapter.ts +319 -0
- package/src/harness/anti_slop/fallow-adapter.ts +305 -0
- package/src/harness/anti_slop/installer.ts +227 -0
- package/src/harness/anti_slop/queue.ts +216 -0
- package/src/harness/anti_slop/recommend.ts +84 -0
- package/src/harness/anti_slop/score.ts +180 -0
- package/src/harness/anti_slop/synthetic-edit-test.ts +128 -0
- package/src/harness/artifacts/agents-md.ts +88 -0
- package/src/harness/artifacts/checks-wiring.ts +57 -0
- package/src/harness/artifacts/docs-tree.ts +79 -0
- package/src/harness/artifacts/lint-configs.ts +136 -0
- package/src/harness/artifacts/review-agents.ts +67 -0
- package/src/harness/bare-entry.ts +108 -0
- package/src/harness/command.ts +1010 -0
- package/src/harness/default-agents/design.md +23 -0
- package/src/harness/default-agents/discover.md +18 -0
- package/src/harness/default-agents/implement.md +24 -0
- package/src/harness/default-agents/plan.md +19 -0
- package/src/harness/default-agents/research.md +21 -0
- package/src/harness/default-agents/validate.md +22 -0
- package/src/harness/gc/reporter.ts +28 -0
- package/src/harness/gc/runner.ts +136 -0
- package/src/harness/hooks/layer-context-inject.ts +155 -0
- package/src/harness/hooks/post-session-sweep.ts +130 -0
- package/src/harness/hooks/pre-edit-dupe-probe.ts +224 -0
- package/src/harness/hooks/register.ts +118 -0
- package/src/harness/model.ts +117 -0
- package/src/harness/pipeline.ts +348 -0
- package/src/harness/project-paths.ts +235 -0
- package/src/harness/stage-runner.ts +107 -0
- package/src/harness/stages/design.ts +386 -0
- package/src/harness/stages/discover.ts +454 -0
- package/src/harness/stages/implement.ts +162 -0
- package/src/harness/stages/plan.ts +335 -0
- package/src/harness/stages/research.ts +263 -0
- package/src/harness/stages/validate.ts +684 -0
- package/src/harness/storage.ts +467 -0
- package/src/harness/tools.ts +426 -0
- package/src/lsp/bridge.ts +56 -95
- package/src/lsp/capabilities.ts +108 -0
- package/src/lsp/contracts.ts +35 -0
- package/src/lsp/detector.ts +8 -12
- package/src/markdown-frontmatter.ts +68 -0
- package/src/mempalace/bridge.ts +129 -0
- package/src/mempalace/config.ts +75 -0
- package/src/mempalace/format.ts +163 -0
- package/src/mempalace/hooks.ts +370 -0
- package/src/mempalace/installer-helper.ts +194 -0
- package/src/mempalace/python/mempalace_bridge.py +440 -0
- package/src/mempalace/runtime.ts +565 -0
- package/src/mempalace/schema.ts +264 -0
- package/src/mempalace/session-summary.ts +198 -0
- package/src/mempalace/tool.ts +186 -0
- package/src/mempalace/uv.ts +256 -0
- package/src/migrate/runner.ts +354 -0
- package/src/planning/approval-flow.ts +206 -9
- package/src/planning/plan-writer-prompt.ts +4 -3
- package/src/planning/planning-ask-tool.ts +39 -0
- package/src/planning/render-markdown.ts +74 -0
- package/src/planning/spec.ts +42 -0
- package/src/planning/system-prompt.ts +11 -8
- package/src/planning/validate.ts +84 -0
- package/src/platform/omp.ts +15 -2
- package/src/platform/system-prompt.ts +37 -0
- package/src/platform/test-utils.ts +3 -0
- package/src/platform/types.ts +6 -1
- package/src/qa/config.ts +12 -6
- package/src/qa/detect-app-type.ts +13 -6
- package/src/qa/matrix.ts +12 -6
- package/src/qa/prompt-builder.ts +28 -30
- package/src/qa/scripts/dev-server-utils.ts +72 -0
- package/src/qa/scripts/run-e2e-tests.ts +226 -0
- package/src/qa/scripts/start-dev-server.ts +138 -0
- package/src/qa/scripts/stop-dev-server.ts +77 -0
- package/src/qa/session.ts +13 -7
- package/src/quality/ai-setup.ts +27 -25
- package/src/quality/contracts.ts +34 -0
- package/src/quality/gates/ai-review.ts +20 -58
- package/src/quality/gates/command.ts +249 -46
- package/src/quality/review-gates.ts +18 -2
- package/src/quality/runner.ts +63 -22
- package/src/quality/schemas.ts +37 -2
- package/src/quality/setup.ts +96 -16
- package/src/release/changelog.ts +1 -1
- package/src/release/channels/custom.ts +13 -3
- package/src/release/channels/types.ts +5 -0
- package/src/release/contracts.ts +90 -0
- package/src/release/executor.ts +122 -45
- package/src/release/prompt.ts +18 -2
- package/src/release/targets.ts +86 -0
- package/src/release/version.ts +96 -71
- package/src/review/agent-loader.ts +298 -127
- package/src/review/fixer.ts +10 -6
- package/src/review/multi-agent-runner.ts +115 -14
- package/src/review/output.ts +12 -139
- package/src/review/runner.ts +12 -6
- package/src/review/scope.ts +144 -24
- package/src/review/types.ts +11 -20
- package/src/review/validator.ts +12 -6
- package/src/storage/fix-pr-sessions.ts +21 -14
- package/src/storage/plans.ts +14 -5
- package/src/storage/qa-sessions.ts +25 -19
- package/src/storage/reliability-metrics.ts +180 -0
- package/src/storage/reports.ts +8 -7
- package/src/storage/review-sessions.ts +55 -20
- package/src/tool-catalog/active-tool-controller.ts +164 -0
- package/src/tool-catalog/active-tool-planner.ts +212 -0
- package/src/tool-catalog/tool-groups.ts +102 -0
- package/src/types.ts +1401 -5
- package/src/ui-design/backend-adapter.ts +78 -0
- package/src/ui-design/backends/local-html.ts +82 -0
- package/src/ui-design/backends/pencil-mcp.ts +111 -0
- package/src/ui-design/components-scanner.ts +124 -0
- package/src/ui-design/config.ts +55 -0
- package/src/ui-design/pen-scanner.ts +95 -0
- package/src/ui-design/pen-selector.ts +72 -0
- package/src/ui-design/prompt-builder.ts +73 -0
- package/src/ui-design/scanner.ts +136 -0
- package/src/ui-design/session.ts +974 -0
- package/src/ui-design/system-prompt.ts +312 -0
- package/src/ui-design/tokens-scanner.ts +181 -0
- package/src/ui-design/types.ts +96 -0
- package/src/ultraplan/agent-catalog.ts +522 -0
- package/src/ultraplan/authoring/agent-catalog.ts +310 -0
- package/src/ultraplan/authoring/authoring-tools.ts +552 -0
- package/src/ultraplan/authoring/command-handlers.ts +339 -0
- package/src/ultraplan/authoring/markdown.ts +510 -0
- package/src/ultraplan/authoring/model.ts +162 -0
- package/src/ultraplan/authoring/pipeline.ts +319 -0
- package/src/ultraplan/authoring/stage-runner.ts +141 -0
- package/src/ultraplan/authoring/stages/approve.ts +249 -0
- package/src/ultraplan/authoring/stages/discover.ts +289 -0
- package/src/ultraplan/authoring/stages/intake.ts +203 -0
- package/src/ultraplan/authoring/stages/research.ts +399 -0
- package/src/ultraplan/authoring/stages/review.ts +333 -0
- package/src/ultraplan/authoring/stages/scout.ts +188 -0
- package/src/ultraplan/authoring/stages/synthesize.ts +348 -0
- package/src/ultraplan/authoring/storage.ts +594 -0
- package/src/ultraplan/authoring/synth-gate.ts +165 -0
- package/src/ultraplan/authoring-draft.ts +653 -0
- package/src/ultraplan/authoring-persist.ts +180 -0
- package/src/ultraplan/authoring-tool.ts +608 -0
- package/src/ultraplan/authoring-wizard.ts +587 -0
- package/src/ultraplan/batch/merge.ts +98 -0
- package/src/ultraplan/batch/planner.ts +150 -0
- package/src/ultraplan/batch/presenter.ts +97 -0
- package/src/ultraplan/batch/storage.ts +420 -0
- package/src/ultraplan/batch/supervisor.ts +317 -0
- package/src/ultraplan/batch/worker.ts +26 -0
- package/src/ultraplan/batch/worktree.ts +110 -0
- package/src/ultraplan/contracts.ts +1593 -0
- package/src/ultraplan/default-agents/authoring/discoverer.md +12 -0
- package/src/ultraplan/default-agents/authoring/intake.md +12 -0
- package/src/ultraplan/default-agents/authoring/planner.md +12 -0
- package/src/ultraplan/default-agents/authoring/researcher.md +12 -0
- package/src/ultraplan/default-agents/authoring/scope-checker.md +12 -0
- package/src/ultraplan/default-agents/authoring/scout.md +12 -0
- package/src/ultraplan/default-agents/authoring/structure-checker.md +12 -0
- package/src/ultraplan/default-agents/authoring/tdd-checker.md +12 -0
- package/src/ultraplan/default-agents/backend-domain-reviewer.md +10 -0
- package/src/ultraplan/default-agents/backend-executor.md +10 -0
- package/src/ultraplan/default-agents/backend-stack-reviewer.md +10 -0
- package/src/ultraplan/default-agents/backend-tester.md +10 -0
- package/src/ultraplan/default-agents/frontend-domain-reviewer.md +10 -0
- package/src/ultraplan/default-agents/frontend-executor.md +10 -0
- package/src/ultraplan/default-agents/frontend-stack-reviewer.md +10 -0
- package/src/ultraplan/default-agents/frontend-tester.md +10 -0
- package/src/ultraplan/default-agents/infrastructure-domain-reviewer.md +10 -0
- package/src/ultraplan/default-agents/infrastructure-executor.md +10 -0
- package/src/ultraplan/default-agents/infrastructure-stack-reviewer.md +10 -0
- package/src/ultraplan/default-agents/infrastructure-tester.md +10 -0
- package/src/ultraplan/execution/contract.ts +71 -0
- package/src/ultraplan/execution/policy.ts +217 -0
- package/src/ultraplan/execution/runtime-tools.ts +107 -0
- package/src/ultraplan/execution/session-runner.ts +281 -0
- package/src/ultraplan/next-router.ts +85 -0
- package/src/ultraplan/presenter.ts +359 -0
- package/src/ultraplan/project-paths.ts +342 -0
- package/src/ultraplan/runtime/active-execution.ts +72 -0
- package/src/ultraplan/runtime/apply-mutation.ts +416 -0
- package/src/ultraplan/runtime/blockers.ts +243 -0
- package/src/ultraplan/runtime/hook-bridge.ts +486 -0
- package/src/ultraplan/runtime/launch-context.ts +207 -0
- package/src/ultraplan/runtime/migration.ts +524 -0
- package/src/ultraplan/runtime/normalize.ts +281 -0
- package/src/ultraplan/runtime/proof.ts +260 -0
- package/src/ultraplan/runtime/reducer.ts +416 -0
- package/src/ultraplan/runtime/repair.ts +251 -0
- package/src/ultraplan/runtime/tracker-storage.ts +368 -0
- package/src/ultraplan/session-selection.ts +291 -0
- package/src/ultraplan/storage.ts +374 -0
- package/src/utils/editor.ts +38 -0
- package/src/utils/executable.ts +80 -0
- package/src/utils/paths.ts +1 -20
- package/src/utils/shell.ts +31 -0
- package/src/visual/companion.ts +2 -1
- package/src/visual/scripts/frame-template.html +60 -0
- package/src/visual/scripts/index.js +59 -13
- package/src/visual/scripts/package.json +3 -0
- package/src/visual/start-server.ts +2 -1
- package/src/workspace/git-scope.ts +64 -0
- package/src/workspace/locks.ts +23 -0
- package/src/workspace/package-manager.ts +117 -0
- package/src/workspace/path-mapping.ts +75 -0
- package/src/workspace/project-slug.ts +92 -0
- package/src/workspace/repo-root.ts +137 -0
- package/src/workspace/selector.ts +115 -0
- package/src/workspace/state-paths.ts +118 -0
- package/src/workspace/targets.ts +313 -0
- package/src/fix-pr/scripts/diff-comments.sh +0 -33
- package/src/fix-pr/scripts/fetch-pr-comments.sh +0 -25
- package/src/fix-pr/scripts/trigger-review.sh +0 -36
- package/src/fix-pr/scripts/wait-and-check.sh +0 -37
- package/src/qa/scripts/detect-app-type.sh +0 -68
- package/src/qa/scripts/discover-routes.sh +0 -143
- package/src/qa/scripts/run-e2e-tests.sh +0 -131
- package/src/qa/scripts/start-dev-server.sh +0 -46
- package/src/qa/scripts/stop-dev-server.sh +0 -36
- package/src/review/prompts/fix-output-schema.md +0 -18
- package/src/review/prompts/review-output-schema.md +0 -38
- package/src/review/template.ts +0 -15
- /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 {
|
|
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
|
-
|
|
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
|
-
...
|
|
48
|
-
|
|
49
|
-
`
|
|
50
|
-
`
|
|
51
|
-
|
|
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 =
|
|
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
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
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
|
-
|
|
107
|
-
name:
|
|
108
|
-
description:
|
|
109
|
-
focus
|
|
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
|
-
|
|
130
|
-
|
|
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
|
|
143
|
-
|
|
144
|
-
|
|
202
|
+
export function getRootReviewAgentsDir(paths: PlatformPaths, repoRoot: string): string {
|
|
203
|
+
return path.join(getRootStateDir(paths, repoRoot), REVIEW_AGENTS_DIR);
|
|
204
|
+
}
|
|
145
205
|
|
|
146
|
-
|
|
147
|
-
|
|
206
|
+
export function getRootReviewAgentsConfigPath(paths: PlatformPaths, repoRoot: string): string {
|
|
207
|
+
return path.join(getRootReviewAgentsDir(paths, repoRoot), CONFIG_FILE);
|
|
148
208
|
}
|
|
149
209
|
|
|
150
|
-
export
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
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
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
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
|
|
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
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
if (!
|
|
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
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
373
|
+
return {
|
|
374
|
+
agentsDir,
|
|
375
|
+
configPath,
|
|
376
|
+
config,
|
|
377
|
+
agents,
|
|
378
|
+
};
|
|
379
|
+
}
|
|
235
380
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
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
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
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 +
|
|
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
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
const
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
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:
|
|
282
|
-
configPath:
|
|
283
|
-
config:
|
|
284
|
-
agents:
|
|
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
|
-
|
|
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
|
}
|
package/src/review/fixer.ts
CHANGED
|
@@ -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 "
|
|
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 {
|
|
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
|
|
133
|
+
return renderTemplate(fixFindingsPrompt, {
|
|
131
134
|
scope,
|
|
132
135
|
findingsJson: JSON.stringify(findings, null, 2),
|
|
133
|
-
fixOutputSchema:
|
|
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:
|
|
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") {
|