karajan-code 4.70.4 → 5.0.1
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 +2 -2
- package/package.json +6 -14
- package/packages/hu-board/package.json +1 -1
- package/packages/hu-board/public/app.js +4 -18
- package/packages/hu-board/public/index.html +5 -2
- package/packages/hu-board/public/styles.css +26 -0
- package/packages/hu-board/public/utils/api.js +0 -74
- package/packages/hu-board/public/utils/board-tour.js +62 -0
- package/packages/hu-board/public/utils/board-view.js +49 -144
- package/packages/hu-board/public/utils/command-launcher.js +8 -70
- package/packages/hu-board/public/utils/formatters.js +10 -0
- package/packages/hu-board/public/utils/governance-view.js +13 -1
- package/packages/hu-board/public/utils/hu-actions.js +17 -68
- package/packages/hu-board/public/utils/init-listeners.js +7 -8
- package/packages/hu-board/public/utils/log-panel.js +3 -16
- package/packages/hu-board/public/utils/maggle-mode.js +2 -12
- package/packages/hu-board/public/utils/modals.js +7 -0
- package/packages/hu-board/public/utils/project-picker-view.js +1 -1
- package/packages/hu-board/public/utils/server-push.js +3 -22
- package/packages/hu-board/public/utils/shared-board-notice.js +33 -0
- package/packages/hu-board/public/utils/story-detail-view.js +5 -19
- package/packages/hu-board/src/cleanup-zombies.js +0 -1
- package/packages/hu-board/src/command-runner.js +36 -25
- package/packages/hu-board/src/db-connection.js +282 -0
- package/packages/hu-board/src/db-paths.js +113 -0
- package/packages/hu-board/src/db-queries.js +188 -0
- package/packages/hu-board/src/db-tombstones.js +51 -0
- package/packages/hu-board/src/db.js +28 -619
- package/packages/hu-board/src/ephemeral-cleaner.js +2 -3
- package/packages/hu-board/src/hu-zombie-reaper.js +5 -1
- package/packages/hu-board/src/plan-mutations.js +3 -153
- package/packages/hu-board/src/plans-service.js +55 -0
- package/packages/hu-board/src/routes/api/commands.js +122 -0
- package/packages/hu-board/src/routes/api/plans.js +55 -0
- package/packages/hu-board/src/routes/api/projects.js +267 -0
- package/packages/hu-board/src/routes/api/prompts.js +135 -0
- package/packages/hu-board/src/routes/api/sessions.js +95 -0
- package/packages/hu-board/src/routes/api/stories.js +183 -0
- package/packages/hu-board/src/routes/api/system.js +241 -0
- package/packages/hu-board/src/routes/api/tombstones.js +38 -0
- package/packages/hu-board/src/routes/api.js +24 -1371
- package/packages/hu-board/src/routes/governance.js +23 -1
- package/packages/hu-board/src/routes/lanes.js +40 -0
- package/packages/hu-board/src/routes/rag.js +4 -3
- package/packages/hu-board/src/server.js +20 -34
- package/packages/hu-board/src/sync-files.js +318 -0
- package/packages/hu-board/src/sync-project.js +99 -0
- package/packages/hu-board/src/sync.js +22 -566
- package/packages/hu-board/src/zombie-reaper.js +1 -1
- package/scripts/dual-publish.mjs +19 -3
- package/scripts/postinstall.js +15 -2
- package/scripts/verify-pack-mcp.mjs +11 -7
- package/scripts/verify-pack.mjs +4 -4
- package/src/audit/audit-history.js +3 -2
- package/src/audit/dead-exports.js +68 -59
- package/src/audit/deterministic-summary.js +33 -13
- package/src/audit/npm-signatures.js +41 -0
- package/src/audit/sbom.js +35 -0
- package/src/checks/agent-token.js +112 -0
- package/src/checks/dir-setup.js +34 -1
- package/src/checks/native-build.js +21 -39
- package/src/checks/runner.js +128 -142
- package/src/cli/advanced-commands.js +6 -6
- package/src/cli/register-meta.js +42 -82
- package/src/cli/register-pipeline.js +8 -143
- package/src/cli/register-plan.js +9 -100
- package/src/cli/register-roles-skills.js +1 -1
- package/src/cli/retired-commands.js +49 -0
- package/src/cli.js +18 -5
- package/src/commands/agent-run.js +40 -26
- package/src/commands/audit.js +127 -124
- package/src/commands/board.js +5 -9
- package/src/commands/check.js +29 -16
- package/src/commands/doctor.js +2 -0
- package/src/commands/env.js +176 -150
- package/src/commands/go.js +71 -53
- package/src/commands/harden.js +90 -81
- package/src/commands/hu-start.js +52 -0
- package/src/commands/hu.js +288 -221
- package/src/commands/identity.js +111 -78
- package/src/commands/init-atril.js +47 -0
- package/src/commands/init.js +11 -40
- package/src/commands/install-tools.js +70 -85
- package/src/commands/main-guard.js +78 -0
- package/src/commands/policy.js +226 -184
- package/src/commands/qmd.js +27 -21
- package/src/commands/rag.js +121 -55
- package/src/commands/review-gate.js +421 -341
- package/src/commands/skills.js +4 -1
- package/src/commands/start.js +4 -5
- package/src/commands/steward.js +96 -47
- package/src/commands/tournament.js +46 -37
- package/src/commands/worktree.js +107 -26
- package/src/config/defaults.js +1 -0
- package/src/config/loader.js +34 -17
- package/src/config/role-resolver.js +1 -0
- package/src/config/schema.js +1 -0
- package/src/config/secrets.js +36 -0
- package/src/config.js +1 -0
- package/src/environment/adr.js +16 -2
- package/src/git/karajan-label.js +20 -8
- package/src/guards/main-guard.js +54 -0
- package/src/harden/hook-templates.js +16 -1
- package/src/harden/sentinel/posttooluse.mjs +18 -6
- package/src/harden/sentinel/pretooluse-sentinel.mjs +64 -36
- package/src/harden/sentinel/sentinel-lib.mjs +129 -26
- package/src/harden/sentinel/sentinel-shell.mjs +5 -16
- package/src/harden/sentinel/sessionstart.mjs +3 -2
- package/src/harden/sentinel/stop.mjs +5 -4
- package/src/harden/workflow-templates.js +1 -1
- package/src/hu/board-lookup.js +29 -0
- package/src/hu/gh-identity.js +23 -0
- package/src/hu/github-board.js +4 -2
- package/src/hu/lane-prune.js +83 -13
- package/src/hu/lane-setup.js +65 -0
- package/src/hu/lanes.js +66 -0
- package/src/hu/team-board-mirror.js +3 -2
- package/src/infrastructure/command-runner.js +1 -1
- package/src/infrastructure/file-system-service.js +1 -1
- package/src/mcp/handlers/direct-handlers.js +2 -292
- package/src/mcp/handlers/hu-handlers.js +1 -35
- package/src/mcp/handlers/management-handlers.js +2 -42
- package/src/mcp/handlers/rag-handler.js +9 -1
- package/src/mcp/server-handlers.js +16 -22
- package/src/mcp/tools.js +1 -196
- package/src/plan/lane-plans.js +54 -0
- package/src/plan/plan-store.js +7 -4
- package/src/policy/add.js +26 -12
- package/src/policy/adr-number-check.js +31 -0
- package/src/prompts/audit.js +299 -339
- package/src/prompts/card-context.js +10 -5
- package/src/prompts/reviewer.js +5 -2
- package/src/rag/auto-update.js +71 -44
- package/src/rag/bootstrap-index.js +46 -54
- package/src/rag/indexer.js +9 -4
- package/src/rag/migrate.js +1 -1
- package/src/rag/onnx-fallback.js +2 -2
- package/src/rag/pid-lease.js +181 -0
- package/src/rag/project-store.js +2 -12
- package/src/review/card-first.js +57 -46
- package/src/review/gate-gitignore.js +23 -4
- package/src/review/gate-hook.js +12 -4
- package/src/review/one-shot-review.js +45 -35
- package/src/review/publish-pr.js +14 -2
- package/src/review/repo-docs.js +73 -0
- package/src/review/repo-stack.js +59 -0
- package/src/review/reviewer-fallback.js +19 -4
- package/src/review/seal-commit.js +29 -0
- package/src/review/sonar-pregate.js +59 -44
- package/src/review/third-party-review.js +90 -16
- package/src/review/third-party-size.js +43 -0
- package/src/review/third-party-skills.js +54 -0
- package/src/review/verify-pr.js +1 -24
- package/src/roles/audit-role.js +106 -125
- package/src/skills/atril-cli.js +19 -1
- package/src/skills/atril-skills.js +5 -4
- package/src/skills/skills-search.js +72 -0
- package/src/skills/translate.js +62 -0
- package/src/sonar/scanner.js +116 -101
- package/src/steward/invariants.js +5 -4
- package/src/steward/phantom-sweep.js +66 -0
- package/src/tournament/judge.js +60 -53
- package/src/utils/gh-account.js +37 -0
- package/src/utils/git.js +0 -13
- package/src/utils/home-migration.js +7 -1
- package/src/utils/main-checkout.js +53 -0
- package/src/utils/qmd-collection.js +3 -1
- package/src/utils/welcome.js +3 -3
- package/templates/{skills → atril/commands}/kj-architect.md +5 -0
- package/templates/{skills → atril/commands}/kj-audit.md +5 -0
- package/templates/{skills → atril/commands}/kj-board.md +5 -0
- package/templates/{skills → atril/commands}/kj-code.md +5 -0
- package/templates/{skills → atril/commands}/kj-csv-transform.md +5 -0
- package/templates/{skills → atril/commands}/kj-data-report.md +5 -0
- package/templates/{skills → atril/commands}/kj-discover.md +5 -0
- package/templates/{skills → atril/commands}/kj-rag-query.md +5 -0
- package/templates/{skills → atril/commands}/kj-review.md +5 -0
- package/templates/{skills → atril/commands}/kj-security.md +5 -0
- package/templates/{skills → atril/commands}/kj-sonar.md +5 -0
- package/templates/{skills → atril/commands}/kj-sql-analysis.md +5 -0
- package/templates/{skills → atril/commands}/kj-test.md +5 -0
- package/packages/hu-board/public/utils/run-launcher.js +0 -169
- package/packages/hu-board/src/run-tracker.js +0 -121
- package/src/activity-log.js +0 -59
- package/src/agents/host-agent.js +0 -38
- package/src/agents/model-registry.js +0 -142
- package/src/audit/plan-adherence.js +0 -224
- package/src/autonomy/arbiter-role.js +0 -71
- package/src/autonomy/arbiter.js +0 -22
- package/src/autonomy/decider.js +0 -18
- package/src/autonomy/decision-resolver.js +0 -58
- package/src/autonomy/outcome-report.js +0 -55
- package/src/autonomy/stage-ask.js +0 -30
- package/src/brain/decision-tracker.js +0 -125
- package/src/brain/decisor.js +0 -243
- package/src/brain/solomon-consult.js +0 -171
- package/src/brain/standby-scheduler.js +0 -8
- package/src/budget/comparison.js +0 -96
- package/src/canvas/parse-md.js +0 -238
- package/src/canvas/schema.js +0 -101
- package/src/canvas/to-flat.js +0 -85
- package/src/canvas/validate.js +0 -163
- package/src/ci/dispatch.js +0 -99
- package/src/ci/index.js +0 -3
- package/src/ci/pr-diff.js +0 -26
- package/src/cli/register-standby.js +0 -26
- package/src/commands/architect.js +0 -111
- package/src/commands/autorun.js +0 -49
- package/src/commands/researcher.js +0 -54
- package/src/commands/resume.js +0 -72
- package/src/commands/review.js +0 -89
- package/src/commands/run.js +0 -185
- package/src/commands/standby.js +0 -117
- package/src/commands/status.js +0 -36
- package/src/commands/triage.js +0 -78
- package/src/commands/undo.js +0 -62
- package/src/domains/domain-loader.js +0 -245
- package/src/domains/domain-registry.js +0 -140
- package/src/domains/domain-synthesizer.js +0 -129
- package/src/git/automation.js +0 -433
- package/src/git/coder-commit-guard.js +0 -40
- package/src/git/hu-automation.js +0 -243
- package/src/git/hu-snapshot.js +0 -10
- package/src/git/symlink-targets.js +0 -57
- package/src/golden/asserter.js +0 -92
- package/src/golden/loader.js +0 -52
- package/src/golden/runner.js +0 -92
- package/src/golden/schema.js +0 -41
- package/src/guards/duplicate-members.js +0 -86
- package/src/guards/intent-guard.js +0 -161
- package/src/guards/perf-guard.js +0 -126
- package/src/guards/policy-guard.js +0 -90
- package/src/guards/policy-resolver.js +0 -85
- package/src/guards/secret-redactor.js +0 -71
- package/src/hu/acceptance-runner.js +0 -138
- package/src/hu/lazy-planner.js +0 -109
- package/src/hu/parallel-executor.js +0 -94
- package/src/hu/routing-metrics.js +0 -17
- package/src/hu/split-validator.js +0 -143
- package/src/hu/splitting-detector.js +0 -158
- package/src/hu/splitting-generator.js +0 -175
- package/src/hu/store.js +0 -394
- package/src/infrastructure/mocks.js +0 -182
- package/src/mcp/handlers/run-handler.js +0 -318
- package/src/mcp/sovereignty-guard.js +0 -113
- package/src/mcp/tool-arg-normalizers.js +0 -16
- package/src/mutate/reviewer-signal.js +0 -76
- package/src/orchestrator/agent-fallback.js +0 -81
- package/src/orchestrator/brain-coordinator.js +0 -186
- package/src/orchestrator/ci-integration.js +0 -139
- package/src/orchestrator/config-init.js +0 -426
- package/src/orchestrator/direct-actions.js +0 -217
- package/src/orchestrator/drivers/error-recovery.js +0 -287
- package/src/orchestrator/drivers/init-context.js +0 -238
- package/src/orchestrator/drivers/iteration-loop.js +0 -382
- package/src/orchestrator/drivers/iteration-phases/coder-and-refactorer.js +0 -69
- package/src/orchestrator/drivers/iteration-phases/guards.js +0 -91
- package/src/orchestrator/drivers/iteration-phases/handle-approved.js +0 -29
- package/src/orchestrator/drivers/iteration-phases/quality-gates.js +0 -125
- package/src/orchestrator/drivers/iteration-phases/reviewer-gate.js +0 -62
- package/src/orchestrator/drivers/post-loop.js +0 -404
- package/src/orchestrator/drivers/pre-loop-phases/auto-hu-batch.js +0 -137
- package/src/orchestrator/drivers/pre-loop-phases/config-deprecations.js +0 -47
- package/src/orchestrator/drivers/pre-loop-phases/ensure-addyosmani-skills.js +0 -84
- package/src/orchestrator/drivers/pre-loop-phases/inject-loaded-plan.js +0 -393
- package/src/orchestrator/drivers/pre-loop.js +0 -524
- package/src/orchestrator/drivers/run-hu-batch.js +0 -468
- package/src/orchestrator/feedback-enrichment.js +0 -140
- package/src/orchestrator/feedback-queue.js +0 -151
- package/src/orchestrator/flow-control.js +0 -170
- package/src/orchestrator/flow-runner.js +0 -365
- package/src/orchestrator/fs-leak-detector.js +0 -228
- package/src/orchestrator/hu-scheduler.js +0 -114
- package/src/orchestrator/hu-sub-pipeline.js +0 -642
- package/src/orchestrator/iteration-gate.js +0 -73
- package/src/orchestrator/iteration-stages.js +0 -9
- package/src/orchestrator/parallel-limiter.js +0 -74
- package/src/orchestrator/pipeline-context.js +0 -72
- package/src/orchestrator/post-loop-stages.js +0 -468
- package/src/orchestrator/pre-loop-stages.js +0 -11
- package/src/orchestrator/preflight-checks.js +0 -487
- package/src/orchestrator/repair/repair-detector.js +0 -117
- package/src/orchestrator/repair/repair-runner.js +0 -142
- package/src/orchestrator/reviewer-fallback.js +0 -45
- package/src/orchestrator/role-output-compressor.js +0 -189
- package/src/orchestrator/session-journal.js +0 -308
- package/src/orchestrator/solomon-escalation.js +0 -331
- package/src/orchestrator/solomon-rules.js +0 -212
- package/src/orchestrator/stages/acceptance-coverage-stage.js +0 -47
- package/src/orchestrator/stages/architect-stage.js +0 -172
- package/src/orchestrator/stages/coder-stage.js +0 -506
- package/src/orchestrator/stages/domain-curator-stage.js +0 -82
- package/src/orchestrator/stages/format-stage.js +0 -61
- package/src/orchestrator/stages/hu-reviewer-phases/detect-and-apply-splits.js +0 -127
- package/src/orchestrator/stages/hu-reviewer-stage.js +0 -419
- package/src/orchestrator/stages/perf-stage.js +0 -140
- package/src/orchestrator/stages/planner-stage.js +0 -85
- package/src/orchestrator/stages/rag-context-stage.js +0 -80
- package/src/orchestrator/stages/rag-preload-decisor.js +0 -58
- package/src/orchestrator/stages/research-stage.js +0 -69
- package/src/orchestrator/stages/reviewer-stage.js +0 -431
- package/src/orchestrator/stages/sonar-stage.js +0 -439
- package/src/orchestrator/stages/stage-classes.js +0 -84
- package/src/orchestrator/stages/stage-executor.js +0 -155
- package/src/orchestrator/stages/suite-green-stage.js +0 -62
- package/src/orchestrator/stages/tdd-discipline-stage.js +0 -56
- package/src/orchestrator/stages/tool-judge-stage.js +0 -53
- package/src/orchestrator/stages/triage-stage.js +0 -172
- package/src/orchestrator/standby.js +0 -71
- package/src/orchestrator/verification-gate.js +0 -183
- package/src/orchestrator.js +0 -22
- package/src/plan/adr-generator.js +0 -170
- package/src/plan/adr-loader.js +0 -60
- package/src/plan/plan-executor.js +0 -100
- package/src/plan/plan-validation.js +0 -4
- package/src/prompts/acceptance-coverage.js +0 -32
- package/src/prompts/arbiter.js +0 -38
- package/src/prompts/architect.js +0 -103
- package/src/prompts/hu-reviewer.js +0 -244
- package/src/prompts/tool-correctness-judge.js +0 -31
- package/src/prompts/triage.js +0 -57
- package/src/rag/embedder.js +0 -2
- package/src/rag/embedders/_cloud-base.js +0 -2
- package/src/rag/embedders/cohere.js +0 -2
- package/src/rag/embedders/mistral.js +0 -2
- package/src/rag/embedders/onnx.js +0 -2
- package/src/rag/embedders/openai.js +0 -2
- package/src/rag/embedders/voyage.js +0 -2
- package/src/rag/rerank.js +0 -4
- package/src/rag/where-parser.js +0 -4
- package/src/repeat-detector.js +0 -88
- package/src/review/diff-generator.js +0 -112
- package/src/review/git-stash-helper.js +0 -104
- package/src/review/schema.js +0 -31
- package/src/review/scope-filter.js +0 -152
- package/src/review/snapshot-diff.js +0 -122
- package/src/review/tdd-discipline.js +0 -90
- package/src/review/tdd-policy.js +0 -69
- package/src/roles/acceptance-coverage-role.js +0 -78
- package/src/roles/architect-role.js +0 -77
- package/src/roles/coder-role.js +0 -113
- package/src/roles/commiter-role.js +0 -113
- package/src/roles/domain-curator-role.js +0 -134
- package/src/roles/hu-reviewer-role.js +0 -64
- package/src/roles/impeccable-role.js +0 -85
- package/src/roles/index.js +0 -18
- package/src/roles/karajan-brain-role.js +0 -134
- package/src/roles/perf-role.js +0 -122
- package/src/roles/planner-role.js +0 -151
- package/src/roles/refactorer-role.js +0 -30
- package/src/roles/repairer-role.js +0 -181
- package/src/roles/researcher-role.js +0 -70
- package/src/roles/reviewer-role.js +0 -115
- package/src/roles/security-role.js +0 -73
- package/src/roles/solomon-role.js +0 -271
- package/src/roles/sonar-role.js +0 -72
- package/src/roles/tester-role.js +0 -235
- package/src/roles/tool-correctness-judge-role.js +0 -78
- package/src/roles/triage-role.js +0 -99
- package/src/session/journal/decisions-writer.js +0 -200
- package/src/session/journal/iteration-logger.js +0 -194
- package/src/session/journal/summary-writer.js +0 -320
- package/src/session/journal/tree-writer.js +0 -164
- package/src/session/journal/write-all.js +0 -89
- package/src/session-cleanup.js +0 -116
- package/src/skills/semantic-detector.js +0 -167
- package/src/skills/skill-detector.js +0 -385
- package/src/sonar/cloud-scanner.js +0 -78
- package/src/tracker-bootstrap.js +0 -44
- package/src/types/index.js +0 -38
- package/src/types/policy.js +0 -43
- package/src/types/solomon.js +0 -87
- package/src/utils/async-lock.js +0 -31
- package/src/utils/budget.js +0 -229
- package/src/utils/cwd-confirm.js +0 -39
- package/src/utils/display/event-handlers.js +0 -403
- package/src/utils/display/formatters.js +0 -132
- package/src/utils/display/header.js +0 -47
- package/src/utils/display/session-summary.js +0 -118
- package/src/utils/display/solomon.js +0 -42
- package/src/utils/pricing.js +0 -29
- package/src/utils/quota-simulator.js +0 -56
- package/src/utils/role-assigner.js +0 -137
- package/src/utils/rtk-wrapper.js +0 -87
- package/src/utils/run-registry.js +0 -9
- package/src/utils/status-dashboard.js +0 -254
- package/src/utils/tool-call-extractor.js +0 -56
- package/src/webperf/devtools-detect.js +0 -112
- package/src/webperf/webperf-role-integration.js +0 -66
- package/templates/skills/kj-run.md +0 -73
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import { AgentRole } from "./agent-role.js";
|
|
2
|
-
import { extractFirstJson } from "../utils/json-extract.js";
|
|
3
|
-
|
|
4
|
-
const SUBAGENT_PREAMBLE = [
|
|
5
|
-
"IMPORTANT: You are running as a Karajan sub-agent.",
|
|
6
|
-
"Do NOT ask about using Karajan, do NOT mention Karajan, do NOT suggest orchestration.",
|
|
7
|
-
"Do NOT use any MCP tools. Focus only on researching the codebase."
|
|
8
|
-
].join(" ");
|
|
9
|
-
|
|
10
|
-
const EMPTY_RESEARCH = {
|
|
11
|
-
affected_files: [], patterns: [], constraints: [],
|
|
12
|
-
prior_decisions: [], risks: [], test_coverage: ""
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
export class ResearcherRole extends AgentRole {
|
|
16
|
-
constructor(opts) {
|
|
17
|
-
super({ ...opts, name: "researcher" });
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
async buildPrompt({ task }) {
|
|
21
|
-
const sections = [SUBAGENT_PREAMBLE];
|
|
22
|
-
if (this.instructions) sections.push(this.instructions);
|
|
23
|
-
sections.push(
|
|
24
|
-
"Investigate the codebase for the following task.",
|
|
25
|
-
"Identify affected files, patterns, constraints, prior decisions, risks, and test coverage.",
|
|
26
|
-
"Return a single valid JSON object with your findings and nothing else.",
|
|
27
|
-
'{"affected_files":[string],"patterns":[string],"constraints":[string],"prior_decisions":[string],"risks":[string],"test_coverage":string}',
|
|
28
|
-
`## Task\n${task}`
|
|
29
|
-
);
|
|
30
|
-
return { prompt: sections.join("\n\n") };
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
parseOutput(raw) { return extractFirstJson(raw); }
|
|
34
|
-
|
|
35
|
-
buildSuccessResult(parsed, provider) {
|
|
36
|
-
return {
|
|
37
|
-
affected_files: parsed.affected_files || [],
|
|
38
|
-
patterns: parsed.patterns || [],
|
|
39
|
-
constraints: parsed.constraints || [],
|
|
40
|
-
prior_decisions: parsed.prior_decisions || [],
|
|
41
|
-
risks: parsed.risks || [],
|
|
42
|
-
test_coverage: parsed.test_coverage || "",
|
|
43
|
-
provider
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
buildSummary(parsed) {
|
|
48
|
-
const files = parsed.affected_files?.length || 0;
|
|
49
|
-
const risks = parsed.risks?.length || 0;
|
|
50
|
-
const patterns = parsed.patterns?.length || 0;
|
|
51
|
-
const parts = [];
|
|
52
|
-
if (files) parts.push(`${files} file${files === 1 ? "" : "s"}`);
|
|
53
|
-
if (risks) parts.push(`${risks} risk${risks === 1 ? "" : "s"}`);
|
|
54
|
-
if (patterns) parts.push(`${patterns} pattern${patterns === 1 ? "" : "s"}`);
|
|
55
|
-
return parts.length ? `Research complete: ${parts.join(", ")} identified` : "Research complete";
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
handleParseNull(agentResult, provider) {
|
|
59
|
-
return {
|
|
60
|
-
ok: true,
|
|
61
|
-
result: { ...EMPTY_RESEARCH, raw: agentResult.output, provider },
|
|
62
|
-
summary: "Research complete (unstructured output)",
|
|
63
|
-
usage: agentResult.usage
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
handleParseError(_err, agentResult, provider) {
|
|
68
|
-
return this.handleParseNull(agentResult, provider);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
import { createHash } from "node:crypto";
|
|
2
|
-
|
|
3
|
-
import { AgentRole } from "./agent-role.js";
|
|
4
|
-
import { buildRtkInstructions } from "../prompts/rtk-snippet.js";
|
|
5
|
-
import { extractFirstJson } from "../utils/json-extract.js";
|
|
6
|
-
import { reportUnparseableVerdict } from "../review/unparseable-verdict.js";
|
|
7
|
-
import { section, buildPromptLayout, joinLayout, STABLE, VOLATILE } from "../prompts/prompt-layout.js";
|
|
8
|
-
import { clipDiff } from "../prompts/diff-clip.js";
|
|
9
|
-
import { buildSplitSignal } from "../prompts/split-signal.js";
|
|
10
|
-
import { isMutationReviewEnabled, buildReviewerMutationSignal } from "../mutate/reviewer-signal.js";
|
|
11
|
-
|
|
12
|
-
const SUBAGENT_PREAMBLE = [
|
|
13
|
-
"IMPORTANT: You are running as a Karajan sub-agent.",
|
|
14
|
-
"Do NOT ask about using Karajan, do NOT mention Karajan, do NOT suggest orchestration.",
|
|
15
|
-
"Do NOT use any MCP tools. Focus only on reviewing the code."
|
|
16
|
-
].join(" ");
|
|
17
|
-
|
|
18
|
-
export class ReviewerRole extends AgentRole {
|
|
19
|
-
constructor(opts) {
|
|
20
|
-
super({ ...opts, name: "reviewer" });
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
get agentMethod() { return "reviewTask"; }
|
|
24
|
-
|
|
25
|
-
extractInput(input) {
|
|
26
|
-
if (typeof input === "string") return { task: input, diff: "", reviewRules: null, onOutput: null };
|
|
27
|
-
return {
|
|
28
|
-
task: input?.task || this.context?.task || "",
|
|
29
|
-
diff: input?.diff || "",
|
|
30
|
-
reviewRules: input?.reviewRules || null,
|
|
31
|
-
onOutput: input?.onOutput || null
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// Φ1-E (KJC-PCS-0057): stable block (preamble, instructions, mode,
|
|
36
|
-
// schema, contexts, rtk, review rules) first; task + diff — different
|
|
37
|
-
// on every review — last. The buckets ride along so ClaudeAgent can
|
|
38
|
-
// ship the stable block via --append-system-prompt (Φ1-D).
|
|
39
|
-
async buildPrompt({ task, diff, reviewRules }) {
|
|
40
|
-
// Opt-in (KJ_REVIEW_MUTATION): null when off/clean → prompt stays identical.
|
|
41
|
-
const mutationSignal = await buildReviewerMutationSignal({
|
|
42
|
-
enabled: isMutationReviewEnabled(),
|
|
43
|
-
projectDir: this.config?.projectDir,
|
|
44
|
-
});
|
|
45
|
-
// KJC-BUG-0134: a clip is declared as kj's own, outside the diff body.
|
|
46
|
-
const { body: clippedDiff, note: clipNote } = clipDiff(diff || "");
|
|
47
|
-
// KJC-BUG-0138: moved-lines correlation, computed on the FULL diff.
|
|
48
|
-
const splitSignal = buildSplitSignal(diff || "");
|
|
49
|
-
const layout = buildPromptLayout([
|
|
50
|
-
section(SUBAGENT_PREAMBLE, STABLE),
|
|
51
|
-
section(this.instructions, STABLE),
|
|
52
|
-
section(`You are a code reviewer in ${this.config?.review_mode || "standard"} mode.`, STABLE),
|
|
53
|
-
section("Return only one valid JSON object and nothing else.", STABLE),
|
|
54
|
-
section("JSON schema:", STABLE),
|
|
55
|
-
section('{"approved":boolean,"blocking_issues":[{"id":string,"severity":"critical|high|medium|low","file":string,"line":number,"description":string,"suggested_fix":string}],"non_blocking_suggestions":[string],"summary":string,"confidence":number}', STABLE),
|
|
56
|
-
section(this.config?.productContext ? `## Product Context\n${this.config.productContext}` : null, STABLE),
|
|
57
|
-
section(this.config?.domainContext ? `## Domain Context\n${this.config.domainContext}` : null, STABLE),
|
|
58
|
-
section(buildRtkInstructions({ rtkAvailable: Boolean(this.config?.rtk?.available) }), STABLE),
|
|
59
|
-
section(reviewRules ? `Review rules:\n${reviewRules}` : null, STABLE),
|
|
60
|
-
section(`Task context:\n${task}`, VOLATILE),
|
|
61
|
-
section(`Git diff:\n${clippedDiff}`, VOLATILE),
|
|
62
|
-
section(clipNote, VOLATILE),
|
|
63
|
-
section(splitSignal, VOLATILE),
|
|
64
|
-
section(mutationSignal, VOLATILE),
|
|
65
|
-
]);
|
|
66
|
-
return { prompt: joinLayout(layout), stablePrompt: layout.stable, volatilePrompt: layout.volatile };
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
parseOutput(raw) {
|
|
70
|
-
const parsed = extractFirstJson(raw);
|
|
71
|
-
if (!parsed) throw new Error("Failed to parse reviewer output: no JSON found");
|
|
72
|
-
// KJC-BUG-0284 (#1982): a reviewer wrapped its verdict in the role envelope
|
|
73
|
-
// {ok, result: {approved…}, summary}; the envelope is not the verdict.
|
|
74
|
-
const verdict = typeof parsed.approved !== "boolean" && typeof parsed.result?.approved === "boolean"
|
|
75
|
-
? { ...parsed.result, summary: parsed.result.summary ?? parsed.summary }
|
|
76
|
-
: parsed;
|
|
77
|
-
if (typeof verdict.approved !== "boolean") throw new Error("Failed to parse reviewer output: no boolean approved");
|
|
78
|
-
return verdict;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
buildSuccessResult(parsed, provider, agentResult) {
|
|
82
|
-
return {
|
|
83
|
-
...agentResult,
|
|
84
|
-
approved: parsed.approved,
|
|
85
|
-
blocking_issues: parsed.blocking_issues || [],
|
|
86
|
-
non_blocking_suggestions: parsed.non_blocking_suggestions || [],
|
|
87
|
-
confidence: parsed.confidence ?? null,
|
|
88
|
-
raw_summary: parsed.summary || ""
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
buildSummary(parsed) {
|
|
93
|
-
const blockingIssues = parsed.blocking_issues || [];
|
|
94
|
-
return parsed.approved
|
|
95
|
-
? `Approved: ${parsed.summary || "no issues found"}`
|
|
96
|
-
: `Rejected: ${blockingIssues.length} blocking issue(s) — ${parsed.summary || ""}`;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// KJC-BUG-0284 (#1982): an unreadable answer is the reviewer's failure, not
|
|
100
|
-
// the coder's. Returned as ok=false so the retry and the fallback reviewer
|
|
101
|
-
// engage (reviewer-fallback.js); the raw answer is saved for inspection.
|
|
102
|
-
// Before, it came back as a PARSE_ERROR rejection: the coder read it as a
|
|
103
|
-
// defect of its code and one run went in circles for twenty minutes.
|
|
104
|
-
async handleParseError(err, agentResult, provider) {
|
|
105
|
-
const output = agentResult?.output;
|
|
106
|
-
const hash = createHash("sha256").update(String(output ?? "")).digest("hex").slice(0, 12);
|
|
107
|
-
const error = await reportUnparseableVerdict({ projectDir: this.config?.projectDir ?? process.cwd(), reviewer: provider, output, hash });
|
|
108
|
-
return {
|
|
109
|
-
ok: false,
|
|
110
|
-
result: { ...agentResult, error: `${err.message}\n${error}`, provider },
|
|
111
|
-
summary: `Reviewer output parse error: ${err.message}`,
|
|
112
|
-
usage: agentResult?.usage
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
}
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import { AgentRole } from "./agent-role.js";
|
|
2
|
-
import { extractFirstJson } from "../utils/json-extract.js";
|
|
3
|
-
import { loadAvailableSkills, buildSkillSection } from "../skills/skill-loader.js";
|
|
4
|
-
|
|
5
|
-
const SUBAGENT_PREAMBLE = [
|
|
6
|
-
"IMPORTANT: You are running as a Karajan sub-agent.",
|
|
7
|
-
"Do NOT ask about using Karajan, do NOT mention Karajan, do NOT suggest orchestration.",
|
|
8
|
-
"Do NOT use any MCP tools. Focus only on auditing code for security vulnerabilities."
|
|
9
|
-
].join(" ");
|
|
10
|
-
|
|
11
|
-
export class SecurityRole extends AgentRole {
|
|
12
|
-
constructor(opts) {
|
|
13
|
-
super({ ...opts, name: "security" });
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
async buildPrompt({ task, diff }) {
|
|
17
|
-
const sections = [SUBAGENT_PREAMBLE];
|
|
18
|
-
if (this.instructions) sections.push(this.instructions);
|
|
19
|
-
sections.push(
|
|
20
|
-
"You are a security auditor. Analyze the code changes for vulnerabilities.",
|
|
21
|
-
"Check for: OWASP top 10, exposed secrets/API keys, hardcoded credentials, command injection, XSS, SQL injection, path traversal, prototype pollution, insecure dependencies.",
|
|
22
|
-
"Return a single valid JSON object with your findings and nothing else.",
|
|
23
|
-
'{"vulnerabilities":[{"severity":"critical|high|medium|low","category":string,"file":string,"line":number,"description":string,"fix_suggestion":string}],"verdict":"pass"|"fail"}',
|
|
24
|
-
`## Task\n${task}`
|
|
25
|
-
);
|
|
26
|
-
if (diff) sections.push(`## Git diff to audit\n${diff}`);
|
|
27
|
-
|
|
28
|
-
// Inject security-relevant skills (owasp-*, security-*, sast-*) filtered
|
|
29
|
-
// by role=security.
|
|
30
|
-
const projectDir = this.config?.projectDir || process.cwd();
|
|
31
|
-
const skills = await loadAvailableSkills(projectDir);
|
|
32
|
-
const skillSection = buildSkillSection(skills, {
|
|
33
|
-
provider: this._resolvedProvider || (typeof this.resolveProvider === "function" ? this.resolveProvider() : null),
|
|
34
|
-
role: "security",
|
|
35
|
-
});
|
|
36
|
-
if (skillSection) sections.push(skillSection);
|
|
37
|
-
|
|
38
|
-
return { prompt: sections.join("\n\n") };
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
extractInput(input) {
|
|
42
|
-
if (typeof input === "string") return { task: input, diff: null };
|
|
43
|
-
return { task: input?.task || this.context?.task || "", diff: input?.diff || null, onOutput: input?.onOutput || null };
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
parseOutput(raw) { return extractFirstJson(raw); }
|
|
47
|
-
|
|
48
|
-
isSuccessful(parsed) {
|
|
49
|
-
const verdict = parsed.verdict || (parsed.vulnerabilities?.length ? "fail" : "pass");
|
|
50
|
-
return verdict === "pass";
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
buildSuccessResult(parsed, provider) {
|
|
54
|
-
const verdict = parsed.verdict || (parsed.vulnerabilities?.length ? "fail" : "pass");
|
|
55
|
-
return { vulnerabilities: parsed.vulnerabilities || [], verdict, provider };
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
buildSummary(parsed) {
|
|
59
|
-
const verdict = parsed.verdict || (parsed.vulnerabilities?.length ? "fail" : "pass");
|
|
60
|
-
const vulns = parsed.vulnerabilities || [];
|
|
61
|
-
if (!vulns.length) return `Verdict: ${verdict}; No vulnerabilities found`;
|
|
62
|
-
|
|
63
|
-
const bySeverity = {};
|
|
64
|
-
for (const v of vulns) bySeverity[v.severity || "unknown"] = (bySeverity[v.severity || "unknown"] || 0) + 1;
|
|
65
|
-
|
|
66
|
-
const order = { critical: 0, high: 1, medium: 2, low: 3 };
|
|
67
|
-
const parts = Object.entries(bySeverity)
|
|
68
|
-
.sort(([a], [b]) => (order[a] ?? 4) - (order[b] ?? 4))
|
|
69
|
-
.map(([sev, count]) => `${count} ${sev}`);
|
|
70
|
-
|
|
71
|
-
return `Verdict: ${verdict}; ${parts.join(", ")}`;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
@@ -1,271 +0,0 @@
|
|
|
1
|
-
import { BaseRole } from "./base-role.js";
|
|
2
|
-
import { createAgent as defaultCreateAgent } from "../agents/index.js";
|
|
3
|
-
import { extractFirstJson } from "../utils/json-extract.js";
|
|
4
|
-
import { withBrainRecovery } from "../brain/with-brain-recovery.js";
|
|
5
|
-
|
|
6
|
-
const SUBAGENT_PREAMBLE = [
|
|
7
|
-
"IMPORTANT: You are running as a Karajan sub-agent.",
|
|
8
|
-
"Do NOT ask about using Karajan, do NOT mention Karajan, do NOT suggest orchestration.",
|
|
9
|
-
"Do NOT use any MCP tools. Focus only on resolving the conflict between agents."
|
|
10
|
-
].join(" ");
|
|
11
|
-
|
|
12
|
-
function resolveProvider(config) {
|
|
13
|
-
return (
|
|
14
|
-
config?.roles?.solomon?.provider ||
|
|
15
|
-
config?.roles?.coder?.provider ||
|
|
16
|
-
"claude"
|
|
17
|
-
);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function formatHistory(history) {
|
|
21
|
-
if (!history || history.length === 0) return "No previous interactions recorded.";
|
|
22
|
-
|
|
23
|
-
return history
|
|
24
|
-
.map((entry, i) => {
|
|
25
|
-
const agent = entry.agent || "unknown";
|
|
26
|
-
const feedback = entry.feedback || entry.message || "(no feedback)";
|
|
27
|
-
return `### Interaction ${i + 1} [${agent}]\n${feedback}`;
|
|
28
|
-
})
|
|
29
|
-
.join("\n\n");
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function buildPrompt({ conflict, task, instructions }) {
|
|
33
|
-
const sections = [SUBAGENT_PREAMBLE];
|
|
34
|
-
|
|
35
|
-
if (instructions) {
|
|
36
|
-
sections.push(instructions);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
sections.push(
|
|
40
|
-
"You are Solomon, the autonomous pipeline boss in a multi-agent AI coding orchestrator.",
|
|
41
|
-
"You are activated whenever ANYTHING deviates from normal flow: rate limits, agent failures, conflicts, max iterations, quality gate issues.",
|
|
42
|
-
"",
|
|
43
|
-
"## Core principle",
|
|
44
|
-
"The pipeline NEVER skips a quality stage (review, tests, sonar, security) without exhausting alternatives first.",
|
|
45
|
-
"NEVER approve skipping a stage as your first option. Follow the recovery hierarchy below.",
|
|
46
|
-
"",
|
|
47
|
-
"## ABSOLUTE RULE: Security issues from reviewer are NEVER overridable",
|
|
48
|
-
"If the reviewer's blocking_issues contain security-related issues (categories: authentication, authorization, injection, XSS, CSRF, exposed secrets/credentials, cryptography, session management, input validation), you MUST:",
|
|
49
|
-
"- Set ruling to \"continue\" (NOT \"approve\")",
|
|
50
|
-
"- Return the reviewer feedback to the coder for fixing",
|
|
51
|
-
"- NEVER approve or skip security issues regardless of task complexity or deadline",
|
|
52
|
-
"This rule overrides all other rules including the recovery hierarchy.",
|
|
53
|
-
"",
|
|
54
|
-
"## Recovery hierarchy (STRICT ORDER — follow top to bottom)",
|
|
55
|
-
"When a stage fails or an agent is unavailable:",
|
|
56
|
-
"1. **wait** — If there is a known cooldown (cooldownUntil), and it is less than 10 minutes, WAIT. Set ruling to 'approve_with_conditions' with condition 'wait for cooldown' and set waitUntil.",
|
|
57
|
-
"2. **retry_with_alternative** — Try the same stage with a DIFFERENT agent. The pipeline has multiple agents (claude, codex, gemini). Set ruling to 'approve_with_conditions' with condition specifying the alternative agent.",
|
|
58
|
-
"3. **evaluate_risk** — Only if no alternatives are available, evaluate the risk of skipping. Consider: task complexity, what the stage would catch, security implications.",
|
|
59
|
-
" - If risk is LOW (trivial task, no security impact, style-only review): approve with a clear justification.",
|
|
60
|
-
" - If risk is HIGH (complex task, security changes, new dependencies): escalate_human.",
|
|
61
|
-
"4. **escalate_human** — When you cannot resolve it safely. Always prefer this over blindly approving.",
|
|
62
|
-
"",
|
|
63
|
-
"## Quality hierarchy",
|
|
64
|
-
"Security > Correctness > Tests > Architecture > Maintainability > Style",
|
|
65
|
-
"- Green tests are sacred. Never dismiss a failing test.",
|
|
66
|
-
"- Style preferences NEVER block approval.",
|
|
67
|
-
"- Sonar INFO/MINOR issues are always dismissable.",
|
|
68
|
-
"- Sonar BLOCKER/CRITICAL must be fixed unless they are proven false positives.",
|
|
69
|
-
"",
|
|
70
|
-
"## Classification rules",
|
|
71
|
-
"For each issue, classify as:",
|
|
72
|
-
"1. **critical** (security, correctness, tests broken) — action: must_fix",
|
|
73
|
-
"2. **important** (architecture, maintainability) — action: should_fix",
|
|
74
|
-
"3. **style** (naming, formatting, preferences, false positives) — action: dismiss",
|
|
75
|
-
"",
|
|
76
|
-
"## Ruling options",
|
|
77
|
-
'1. **approve** — FORBIDDEN when a quality stage (review, tests, sonar, security) was skipped or failed. You MUST try alternatives first (wait for cooldown, use different agent). Only allowed when all stages completed successfully and remaining issues are style/false positives.',
|
|
78
|
-
'2. **approve_with_conditions** — Fixable issues or recovery actions needed. Include exact conditions (wait, retry with alternative agent, specific fix instructions). Set extraIterations and/or alternativeAgent.',
|
|
79
|
-
'3. **escalate_human** — Cannot resolve safely. Critical issues, ambiguous requirements, architecture decisions, high-risk skip.',
|
|
80
|
-
'4. **create_subtask** — A prerequisite task must be completed first.',
|
|
81
|
-
"",
|
|
82
|
-
"Return a single valid JSON object with your ruling and nothing else.",
|
|
83
|
-
'JSON schema: {"ruling":"approve"|"approve_with_conditions"|"escalate_human"|"create_subtask","classification":[{"issue":string,"category":"critical"|"important"|"style","action":"must_fix"|"should_fix"|"dismiss"}],"conditions":[string],"dismissed":[string],"escalate":boolean,"escalate_reason":string|null,"extraIterations":number|null,"alternativeAgent":string|null,"waitUntil":string|null,"subtask":{"title":string,"description":string,"reason":string}|null}',
|
|
84
|
-
"When ruling is approve_with_conditions, set extraIterations (1-5) and/or alternativeAgent (claude|codex|gemini) as appropriate."
|
|
85
|
-
);
|
|
86
|
-
|
|
87
|
-
const stage = conflict?.stage || "unknown";
|
|
88
|
-
const iterationCount = conflict?.iterationCount ?? "?";
|
|
89
|
-
const maxIterations = conflict?.maxIterations ?? "?";
|
|
90
|
-
|
|
91
|
-
const isFirstRejection = conflict?.isFirstRejection ?? false;
|
|
92
|
-
const isRepeat = conflict?.isRepeat ?? false;
|
|
93
|
-
|
|
94
|
-
const budgetUsd = conflict?.budget_usd;
|
|
95
|
-
const budgetLine = typeof budgetUsd === "number" ? `Budget spent so far: $${budgetUsd.toFixed(2)}` : "";
|
|
96
|
-
|
|
97
|
-
sections.push(
|
|
98
|
-
`## Conflict context`,
|
|
99
|
-
`Stage: ${stage}`,
|
|
100
|
-
`Iterations exhausted: ${iterationCount}/${maxIterations}`,
|
|
101
|
-
`isFirstRejection: ${isFirstRejection}`,
|
|
102
|
-
`isRepeat: ${isRepeat}`,
|
|
103
|
-
budgetLine,
|
|
104
|
-
"",
|
|
105
|
-
"## Budget awareness",
|
|
106
|
-
"Consider the cost-benefit ratio when deciding. If significant budget has been spent with little progress,",
|
|
107
|
-
"prefer approving the current work or escalating to human. If progress is good and budget is low,",
|
|
108
|
-
"prefer continuing with conditions. Never waste budget on style-only iterations."
|
|
109
|
-
);
|
|
110
|
-
|
|
111
|
-
if (conflict?.previousSolomonRulings?.length > 0) {
|
|
112
|
-
const rulingLines = conflict.previousSolomonRulings.map((r, idx) =>
|
|
113
|
-
`${idx + 1}. Stage: ${r.conflictStage}, Ruling: ${r.ruling}${r.alternativeAgent ? `, agent: ${r.alternativeAgent}` : ""}${r.error ? ` (FAILED: ${r.error})` : ""}`
|
|
114
|
-
).join("\n");
|
|
115
|
-
sections.push(
|
|
116
|
-
"## Your previous rulings in this session (DO NOT repeat failed strategies)",
|
|
117
|
-
rulingLines,
|
|
118
|
-
"If a previous ruling failed (e.g., alternative agent also rate-limited), do NOT suggest the same strategy again. Escalate or try a different approach."
|
|
119
|
-
);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// Rate limit specific instruction
|
|
123
|
-
if (stage?.includes("rate_limit")) {
|
|
124
|
-
const rateLimitedAgent = conflict?.history?.[0]?.feedback?.match(/Agent "(\w+)"/)?.[1] || "unknown";
|
|
125
|
-
sections.push(
|
|
126
|
-
"## CRITICAL: Agent rate-limited",
|
|
127
|
-
`Agent "${rateLimitedAgent}" is rate-limited. You MUST NOT approve skipping this stage.`,
|
|
128
|
-
"Your ONLY valid options are:",
|
|
129
|
-
`1. approve_with_conditions + alternativeAgent: pick a different agent (available: claude, codex, gemini — NOT "${rateLimitedAgent}")`,
|
|
130
|
-
"2. approve_with_conditions + waitUntil: if cooldown is known and <10min",
|
|
131
|
-
"3. escalate_human: if no alternatives work",
|
|
132
|
-
`DO NOT set ruling to "approve". The stage MUST be completed by some agent.`
|
|
133
|
-
);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
if (conflict?.issueCategories) {
|
|
137
|
-
sections.push(`## Issue categories\n${JSON.stringify(conflict.issueCategories, null, 2)}`);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
if (conflict?.blockingIssues?.length) {
|
|
141
|
-
const issueList = conflict.blockingIssues
|
|
142
|
-
.map((issue, i) => `${i + 1}. [${issue.severity || "unknown"}] ${issue.description || issue}`)
|
|
143
|
-
.join("\n");
|
|
144
|
-
sections.push(`## Blocking issues\n${issueList}`);
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// KJC-BUG-0414 (#2606): taking a symlink's target out of the commit leaves the link dangling.
|
|
148
|
-
if (conflict?.symlinkTargets?.length) {
|
|
149
|
-
const links = conflict.symlinkTargets.map(({ link, target }) => `- ${link} -> ${target}`).join("\n");
|
|
150
|
-
sections.push(`## Symlinks in this change\n${links}\nEach target stays in the commit: never propose unstaging, removing or restoring it, or the link is committed dangling.`);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
if (task) {
|
|
154
|
-
sections.push(`## Original task\n${task}`);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
if (conflict?.diff) {
|
|
158
|
-
sections.push(`## Current diff\n${conflict.diff}`);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
sections.push(`## Agent interaction history\n${formatHistory(conflict?.history)}`);
|
|
162
|
-
|
|
163
|
-
return sections.join("\n\n");
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
function parseSolomonOutput(raw) {
|
|
167
|
-
return extractFirstJson(raw);
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
function buildSummary(parsed) {
|
|
171
|
-
const ruling = parsed.ruling || "unknown";
|
|
172
|
-
const conditions = parsed.conditions || [];
|
|
173
|
-
const dismissed = parsed.dismissed || [];
|
|
174
|
-
const subtask = parsed.subtask || null;
|
|
175
|
-
|
|
176
|
-
if (ruling === "approve") {
|
|
177
|
-
const parts = ["Approved"];
|
|
178
|
-
if (dismissed.length > 0) parts.push(`${dismissed.length} dismissed`);
|
|
179
|
-
return parts.join("; ");
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
if (ruling === "approve_with_conditions") {
|
|
183
|
-
const parts = [`Approved with ${conditions.length} condition${conditions.length === 1 ? "" : "s"}`];
|
|
184
|
-
if (dismissed.length > 0) parts.push(`${dismissed.length} dismissed`);
|
|
185
|
-
return parts.join("; ");
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
if (ruling === "escalate_human") {
|
|
189
|
-
return `Escalated to human: ${parsed.escalate_reason || "ambiguous conflict"}`;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
if (ruling === "create_subtask") {
|
|
193
|
-
return `Subtask created: ${subtask?.title || "unnamed subtask"}`;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
return `Solomon ruling: ${ruling}`;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
export class SolomonRole extends BaseRole {
|
|
200
|
-
constructor({ config, logger, emitter = null, createAgentFn = null }) {
|
|
201
|
-
super({ name: "solomon", config, logger, emitter });
|
|
202
|
-
this._createAgent = createAgentFn || defaultCreateAgent;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
async execute(input) {
|
|
206
|
-
const conflict = input?.conflict || {};
|
|
207
|
-
|
|
208
|
-
const provider = resolveProvider(this.config);
|
|
209
|
-
const agent = this._createAgent(provider, this.config, this.logger);
|
|
210
|
-
|
|
211
|
-
const prompt = buildPrompt({
|
|
212
|
-
conflict,
|
|
213
|
-
task: this.context?.task || "",
|
|
214
|
-
instructions: this.instructions
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
// KJC-TSK-0413 step C: Solomon es BaseRole (no AgentRole) — wrap explícito.
|
|
218
|
-
const result = await withBrainRecovery({
|
|
219
|
-
agent, taskArgs: { prompt, role: "solomon" }, role: "solomon", provider,
|
|
220
|
-
emitter: this.emitter, logger: this.logger,
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
if (!result.ok) {
|
|
224
|
-
const recoveryNote = result.recovery?.class ? ` [${result.recovery.class}]` : "";
|
|
225
|
-
return {
|
|
226
|
-
ok: false,
|
|
227
|
-
result: {
|
|
228
|
-
error: result.error || result.output || `Solomon arbitration failed${recoveryNote}`,
|
|
229
|
-
provider, recovery: result.recovery, action: result.action,
|
|
230
|
-
},
|
|
231
|
-
summary: `Solomon failed${recoveryNote}: ${result.recovery?.message || result.error || "unknown error"}`
|
|
232
|
-
};
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
try {
|
|
236
|
-
const parsed = parseSolomonOutput(result.output);
|
|
237
|
-
if (!parsed) {
|
|
238
|
-
return {
|
|
239
|
-
ok: false,
|
|
240
|
-
result: { error: "Failed to parse Solomon output: no JSON found", provider },
|
|
241
|
-
summary: "Solomon output parse error: no JSON found"
|
|
242
|
-
};
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
const ruling = parsed.ruling || "approve";
|
|
246
|
-
const escalate = Boolean(parsed.escalate);
|
|
247
|
-
const ok = ruling !== "escalate_human";
|
|
248
|
-
|
|
249
|
-
return {
|
|
250
|
-
ok,
|
|
251
|
-
result: {
|
|
252
|
-
ruling,
|
|
253
|
-
classification: parsed.classification || [],
|
|
254
|
-
conditions: parsed.conditions || [],
|
|
255
|
-
dismissed: parsed.dismissed || [],
|
|
256
|
-
escalate,
|
|
257
|
-
escalate_reason: parsed.escalate_reason || null,
|
|
258
|
-
subtask: parsed.subtask || null,
|
|
259
|
-
provider
|
|
260
|
-
},
|
|
261
|
-
summary: buildSummary(parsed)
|
|
262
|
-
};
|
|
263
|
-
} catch (err) {
|
|
264
|
-
return {
|
|
265
|
-
ok: false,
|
|
266
|
-
result: { error: `Failed to parse Solomon output: ${err.message}`, provider },
|
|
267
|
-
summary: `Solomon output parse error: ${err.message}`
|
|
268
|
-
};
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
}
|
package/src/roles/sonar-role.js
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import { BaseRole } from "./base-role.js";
|
|
2
|
-
import { indexedFilesFrom, runSonarScan } from "../sonar/scanner.js";
|
|
3
|
-
import { getQualityGateStatus, getOpenIssues } from "../sonar/api.js";
|
|
4
|
-
import { shouldBlockByProfile, summarizeIssues } from "../sonar/enforcer.js";
|
|
5
|
-
|
|
6
|
-
function normalizeIssues(rawIssues) {
|
|
7
|
-
return rawIssues.map((issue) => ({
|
|
8
|
-
severity: issue.severity || "UNKNOWN",
|
|
9
|
-
type: issue.type || "UNKNOWN",
|
|
10
|
-
file: issue.component || "",
|
|
11
|
-
line: issue.line || 0,
|
|
12
|
-
rule: issue.rule || "",
|
|
13
|
-
message: issue.message || ""
|
|
14
|
-
}));
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export class SonarRole extends BaseRole {
|
|
18
|
-
constructor({ config, logger, emitter = null }) {
|
|
19
|
-
super({ name: "sonar", config, logger, emitter });
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
async execute(_input) {
|
|
23
|
-
// KJC-TSK-0839: verbose, so the scanner names every file it indexed.
|
|
24
|
-
const scan = await runSonarScan(this.config, null, { verbose: true });
|
|
25
|
-
|
|
26
|
-
if (!scan.ok) {
|
|
27
|
-
return {
|
|
28
|
-
ok: false,
|
|
29
|
-
result: {
|
|
30
|
-
projectKey: scan.projectKey || null,
|
|
31
|
-
gateStatus: null,
|
|
32
|
-
issues: [],
|
|
33
|
-
openIssuesTotal: 0,
|
|
34
|
-
issuesSummary: "",
|
|
35
|
-
blocking: false,
|
|
36
|
-
error: scan.stderr || scan.stdout || "Scan failed"
|
|
37
|
-
},
|
|
38
|
-
summary: `Sonar scan failed: ${scan.stderr || scan.stdout || "unknown error"}`
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const gate = await getQualityGateStatus(this.config, scan.projectKey);
|
|
43
|
-
const openIssues = await getOpenIssues(this.config, scan.projectKey);
|
|
44
|
-
const issues = normalizeIssues(openIssues.issues || []);
|
|
45
|
-
const issuesSummary = summarizeIssues(openIssues.issues || []);
|
|
46
|
-
|
|
47
|
-
const profile = this.config.sonarqube?.enforcement_profile || "pragmatic";
|
|
48
|
-
const blocking = shouldBlockByProfile({
|
|
49
|
-
gateStatus: gate.status,
|
|
50
|
-
profile
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
return {
|
|
54
|
-
ok: !blocking,
|
|
55
|
-
result: {
|
|
56
|
-
projectKey: scan.projectKey,
|
|
57
|
-
indexedFiles: [...indexedFilesFrom(scan.stdout)],
|
|
58
|
-
gateStatus: gate.status,
|
|
59
|
-
conditions: gate.conditions || [],
|
|
60
|
-
issues,
|
|
61
|
-
openIssuesTotal: openIssues.total || 0,
|
|
62
|
-
issuesSummary,
|
|
63
|
-
blocking
|
|
64
|
-
},
|
|
65
|
-
summary: (() => {
|
|
66
|
-
const issuesPart = issuesSummary ? ` (${issuesSummary})` : "";
|
|
67
|
-
const blockingPart = blocking ? " [BLOCKING]" : "";
|
|
68
|
-
return `Quality gate: ${gate.status}; Issues: ${openIssues.total || 0}${issuesPart}${blockingPart}`;
|
|
69
|
-
})()
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
}
|