@karajan-family/code 4.21.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/LICENSE +661 -0
- package/README.md +98 -0
- package/bin/karajan-mcp.js +2 -0
- package/bin/kj-rag-mcp.js +75 -0
- package/bin/kj-tail +361 -0
- package/bin/kj.js +2 -0
- package/docs/README.es.md +80 -0
- package/docs/karajan-code-logo-small.png +0 -0
- package/library/logical-clocks-lamport.md +40 -0
- package/package.json +140 -0
- package/packages/ai-trash/README.md +37 -0
- package/packages/ai-trash/bin/kj-trash.js +10 -0
- package/packages/ai-trash/package.json +43 -0
- package/packages/ai-trash/src/cli.js +200 -0
- package/packages/ai-trash/src/destructive-parser.js +74 -0
- package/packages/ai-trash/src/git-snapshot.js +128 -0
- package/packages/ai-trash/src/hook.js +137 -0
- package/packages/ai-trash/src/index.js +14 -0
- package/packages/ai-trash/src/install.js +73 -0
- package/packages/ai-trash/src/logger.js +60 -0
- package/packages/ai-trash/src/manifest.js +91 -0
- package/packages/ai-trash/src/permissions.js +26 -0
- package/packages/ai-trash/src/snapshot.js +66 -0
- package/packages/ai-trash/src/ulid.js +66 -0
- package/packages/hu-board/README.md +69 -0
- package/packages/hu-board/package.json +28 -0
- package/packages/hu-board/public/app.js +259 -0
- package/packages/hu-board/public/index.html +77 -0
- package/packages/hu-board/public/pipeline.css +132 -0
- package/packages/hu-board/public/pipeline.html +48 -0
- package/packages/hu-board/public/pipeline.js +200 -0
- package/packages/hu-board/public/rag.html +21 -0
- package/packages/hu-board/public/rag.js +39 -0
- package/packages/hu-board/public/styles.css +973 -0
- package/packages/hu-board/public/utils/api.js +139 -0
- package/packages/hu-board/public/utils/board-view.js +473 -0
- package/packages/hu-board/public/utils/command-launcher.js +213 -0
- package/packages/hu-board/public/utils/config-editor.js +181 -0
- package/packages/hu-board/public/utils/dashboard-view.js +103 -0
- package/packages/hu-board/public/utils/formatters.js +300 -0
- package/packages/hu-board/public/utils/graph-view.js +216 -0
- package/packages/hu-board/public/utils/hu-actions.js +224 -0
- package/packages/hu-board/public/utils/init-listeners.js +180 -0
- package/packages/hu-board/public/utils/log-panel.js +222 -0
- package/packages/hu-board/public/utils/modals.js +309 -0
- package/packages/hu-board/public/utils/plan-rollup-view.js +53 -0
- package/packages/hu-board/public/utils/preflight-view.js +89 -0
- package/packages/hu-board/public/utils/project-actions.js +143 -0
- package/packages/hu-board/public/utils/project-picker-view.js +139 -0
- package/packages/hu-board/public/utils/run-launcher.js +169 -0
- package/packages/hu-board/public/utils/server-push.js +252 -0
- package/packages/hu-board/public/utils/sessions-view.js +199 -0
- package/packages/hu-board/public/utils/story-detail-view.js +324 -0
- package/packages/hu-board/public/utils/story-edit-form.js +271 -0
- package/packages/hu-board/public/wiki.html +32 -0
- package/packages/hu-board/public/wiki.js +53 -0
- package/packages/hu-board/src/auth.js +92 -0
- package/packages/hu-board/src/boot-info.js +16 -0
- package/packages/hu-board/src/cleanup-zombies.js +145 -0
- package/packages/hu-board/src/command-runner.js +133 -0
- package/packages/hu-board/src/config-yaml.js +531 -0
- package/packages/hu-board/src/db.js +963 -0
- package/packages/hu-board/src/ephemeral-cleaner.js +196 -0
- package/packages/hu-board/src/event-bus.js +58 -0
- package/packages/hu-board/src/format.js +207 -0
- package/packages/hu-board/src/hu-zombie-reaper.js +103 -0
- package/packages/hu-board/src/journal-parser.js +180 -0
- package/packages/hu-board/src/plan-mutations.js +424 -0
- package/packages/hu-board/src/preflight.js +286 -0
- package/packages/hu-board/src/routes/api.js +1374 -0
- package/packages/hu-board/src/routes/pipeline.js +45 -0
- package/packages/hu-board/src/routes/rag.js +42 -0
- package/packages/hu-board/src/routes/wiki.js +43 -0
- package/packages/hu-board/src/run-tracker.js +121 -0
- package/packages/hu-board/src/server.js +438 -0
- package/packages/hu-board/src/sync.js +732 -0
- package/packages/hu-board/src/token-store.js +56 -0
- package/packages/hu-board/src/zombie-reaper.js +206 -0
- package/scripts/ai-attribution-guard.yml +84 -0
- package/scripts/audit-test-diet.mjs +151 -0
- package/scripts/build-sea.mjs +150 -0
- package/scripts/diet-baseline.mjs +170 -0
- package/scripts/dual-publish.mjs +67 -0
- package/scripts/esbuild-sea.config.mjs +273 -0
- package/scripts/git-hooks/post-merge +18 -0
- package/scripts/install-binary.ps1 +174 -0
- package/scripts/install-binary.sh +159 -0
- package/scripts/install-guard-all-repos.sh +85 -0
- package/scripts/install-kj.sh +193 -0
- package/scripts/install.js +901 -0
- package/scripts/install.sh +7 -0
- package/scripts/postinstall.js +117 -0
- package/scripts/protect-all-repos.sh +88 -0
- package/scripts/quickstart-gate.mjs +97 -0
- package/scripts/regen-arch-stats.sh +71 -0
- package/scripts/setup-multi-instance.sh +150 -0
- package/scripts/verify-pack.mjs +278 -0
- package/src/activity-log.js +59 -0
- package/src/agents/agy-agent.js +62 -0
- package/src/agents/aider-agent.js +78 -0
- package/src/agents/availability.js +52 -0
- package/src/agents/base-agent.js +134 -0
- package/src/agents/claude-agent.js +413 -0
- package/src/agents/codex-agent.js +112 -0
- package/src/agents/copilot-agent.js +65 -0
- package/src/agents/gemini-agent.js +85 -0
- package/src/agents/host-agent.js +38 -0
- package/src/agents/index.js +59 -0
- package/src/agents/kimi-agent.js +45 -0
- package/src/agents/model-registry.js +137 -0
- package/src/agents/opencode-agent.js +72 -0
- package/src/agents/qwen-agent.js +20 -0
- package/src/agents/resolve-bin.js +73 -0
- package/src/audit/agent-readiness.js +259 -0
- package/src/audit/ai-slop-findings.js +102 -0
- package/src/audit/audit-fallback.js +66 -0
- package/src/audit/audit-history-display.js +61 -0
- package/src/audit/audit-history.js +102 -0
- package/src/audit/basal-cost.js +281 -0
- package/src/audit/circular-deps.js +144 -0
- package/src/audit/dead-exports.js +186 -0
- package/src/audit/deterministic-summary.js +327 -0
- package/src/audit/harness-scorecard.js +100 -0
- package/src/audit/harness-section.js +81 -0
- package/src/audit/infra-findings.js +100 -0
- package/src/audit/injection-findings.js +114 -0
- package/src/audit/issue-filter.js +133 -0
- package/src/audit/osv-findings.js +167 -0
- package/src/audit/plan-adherence.js +224 -0
- package/src/audit/semgrep-findings.js +129 -0
- package/src/audit/sonar-findings.js +93 -0
- package/src/audit/webperf-input.js +133 -0
- package/src/autonomy/arbiter-role.js +71 -0
- package/src/autonomy/arbiter.js +22 -0
- package/src/autonomy/decider.js +18 -0
- package/src/autonomy/decision-resolver.js +58 -0
- package/src/autonomy/outcome-report.js +55 -0
- package/src/autonomy/policy.js +41 -0
- package/src/autonomy/stage-ask.js +30 -0
- package/src/bootstrap.js +276 -0
- package/src/brain/agent-error-classifier.js +116 -0
- package/src/brain/decision-tracker.js +125 -0
- package/src/brain/decisor.js +243 -0
- package/src/brain/solomon-consult.js +171 -0
- package/src/brain/standby-scheduler.js +8 -0
- package/src/brain/standby-store.js +12 -0
- package/src/brain/with-brain-recovery.js +235 -0
- package/src/budget/comparison.js +96 -0
- package/src/canvas/parse-md.js +238 -0
- package/src/canvas/schema.js +101 -0
- package/src/canvas/to-flat.js +85 -0
- package/src/canvas/validate.js +163 -0
- package/src/checks/ai-surface.js +79 -0
- package/src/checks/ai-trash.js +34 -0
- package/src/checks/binaries.js +207 -0
- package/src/checks/ci.js +105 -0
- package/src/checks/config-files.js +217 -0
- package/src/checks/dir-setup.js +103 -0
- package/src/checks/guarantee-level.js +38 -0
- package/src/checks/hardware.js +150 -0
- package/src/checks/harness-scorecard.js +41 -0
- package/src/checks/mcp-health.js +169 -0
- package/src/checks/method.js +73 -0
- package/src/checks/native-build.js +67 -0
- package/src/checks/node.js +70 -0
- package/src/checks/ollama.js +41 -0
- package/src/checks/orphans.js +77 -0
- package/src/checks/ports.js +188 -0
- package/src/checks/project-checks.js +245 -0
- package/src/checks/qmd.js +41 -0
- package/src/checks/rag-hooks.js +54 -0
- package/src/checks/release-check.js +102 -0
- package/src/checks/rtk.js +36 -0
- package/src/checks/runner.js +326 -0
- package/src/checks/skills.js +53 -0
- package/src/checks/sonar.js +67 -0
- package/src/checks/squeezr.js +36 -0
- package/src/checks/system.js +53 -0
- package/src/checks/tokens.js +172 -0
- package/src/checks/types.js +103 -0
- package/src/ci/dispatch.js +99 -0
- package/src/ci/index.js +3 -0
- package/src/ci/pr-diff.js +26 -0
- package/src/ci/repo.js +45 -0
- package/src/cli/_shared.js +30 -0
- package/src/cli/advanced-commands.js +61 -0
- package/src/cli/register-meta.js +772 -0
- package/src/cli/register-pipeline.js +335 -0
- package/src/cli/register-plan.js +224 -0
- package/src/cli/register-roles-skills.js +54 -0
- package/src/cli/register-sonar.js +28 -0
- package/src/cli/register-standby.js +26 -0
- package/src/cli.js +155 -0
- package/src/commands/advanced.js +31 -0
- package/src/commands/agent-run.js +63 -0
- package/src/commands/agents.js +105 -0
- package/src/commands/architect.js +123 -0
- package/src/commands/audit.js +430 -0
- package/src/commands/autorun.js +49 -0
- package/src/commands/board.js +458 -0
- package/src/commands/check.js +40 -0
- package/src/commands/clean.js +145 -0
- package/src/commands/code.js +45 -0
- package/src/commands/config.js +74 -0
- package/src/commands/discover.js +105 -0
- package/src/commands/doctor.js +251 -0
- package/src/commands/env.js +207 -0
- package/src/commands/harden.js +203 -0
- package/src/commands/hu.js +210 -0
- package/src/commands/identity.js +60 -0
- package/src/commands/init.js +950 -0
- package/src/commands/install-tools.js +432 -0
- package/src/commands/mutate.js +94 -0
- package/src/commands/ollama.js +44 -0
- package/src/commands/onboard.js +45 -0
- package/src/commands/plan/_shared.js +55 -0
- package/src/commands/plan/add-hu.js +23 -0
- package/src/commands/plan/delete.js +9 -0
- package/src/commands/plan/fix.js +99 -0
- package/src/commands/plan/generate.js +532 -0
- package/src/commands/plan/index.js +13 -0
- package/src/commands/plan/list.js +21 -0
- package/src/commands/plan/migrate-result.js +41 -0
- package/src/commands/plan/ready.js +46 -0
- package/src/commands/plan/remove-hu.js +17 -0
- package/src/commands/plan/share.js +85 -0
- package/src/commands/plan/show.js +81 -0
- package/src/commands/plan/unshare.js +41 -0
- package/src/commands/plan/validate.js +20 -0
- package/src/commands/plan.js +17 -0
- package/src/commands/policy.js +164 -0
- package/src/commands/privacy.js +45 -0
- package/src/commands/qmd.js +86 -0
- package/src/commands/rag-mcp.js +18 -0
- package/src/commands/rag.js +173 -0
- package/src/commands/report-issue.js +77 -0
- package/src/commands/report.js +469 -0
- package/src/commands/researcher.js +54 -0
- package/src/commands/resume.js +68 -0
- package/src/commands/review-gate.js +355 -0
- package/src/commands/review.js +89 -0
- package/src/commands/roles.js +116 -0
- package/src/commands/run.js +185 -0
- package/src/commands/scan.js +18 -0
- package/src/commands/skills.js +86 -0
- package/src/commands/sonar.js +53 -0
- package/src/commands/standby.js +117 -0
- package/src/commands/start.js +121 -0
- package/src/commands/status.js +36 -0
- package/src/commands/sync.js +103 -0
- package/src/commands/telemetry.js +70 -0
- package/src/commands/tournament.js +85 -0
- package/src/commands/triage.js +78 -0
- package/src/commands/undo.js +62 -0
- package/src/commands/watch.js +46 -0
- package/src/commands/webperf.js +162 -0
- package/src/commands/worktree.js +76 -0
- package/src/config/defaults.js +270 -0
- package/src/config/loader.js +204 -0
- package/src/config/overrides.js +220 -0
- package/src/config/role-resolver.js +171 -0
- package/src/config/schema.js +299 -0
- package/src/config/test-harness.js +78 -0
- package/src/config.js +34 -0
- package/src/domains/domain-loader.js +245 -0
- package/src/domains/domain-registry.js +140 -0
- package/src/domains/domain-synthesizer.js +129 -0
- package/src/environment/adr.js +45 -0
- package/src/environment/board-access.js +97 -0
- package/src/environment/board-select.js +59 -0
- package/src/environment/briefs.js +129 -0
- package/src/environment/issue-report.js +72 -0
- package/src/environment/mcp-wiring.js +44 -0
- package/src/environment/playbook.js +127 -0
- package/src/git/automation.js +334 -0
- package/src/git/hu-automation.js +171 -0
- package/src/git/hu-snapshot.js +10 -0
- package/src/golden/asserter.js +92 -0
- package/src/golden/loader.js +52 -0
- package/src/golden/runner.js +92 -0
- package/src/golden/schema.js +41 -0
- package/src/guards/intent-guard.js +161 -0
- package/src/guards/output-guard.js +149 -0
- package/src/guards/perf-guard.js +126 -0
- package/src/guards/policy-guard.js +90 -0
- package/src/guards/policy-resolver.js +85 -0
- package/src/guards/secret-redactor.js +71 -0
- package/src/harden/advisory.js +203 -0
- package/src/harden/alternatives.js +50 -0
- package/src/harden/check.js +81 -0
- package/src/harden/config-engine.js +128 -0
- package/src/harden/config-templates.js +122 -0
- package/src/harden/guidelines-engine.js +48 -0
- package/src/harden/guidelines-templates.js +36 -0
- package/src/harden/harden-engine.js +80 -0
- package/src/harden/harness-hooks.js +107 -0
- package/src/harden/hook-commands.js +25 -0
- package/src/harden/hook-templates.js +183 -0
- package/src/harden/interactive.js +76 -0
- package/src/harden/sentinel-hooks.js +721 -0
- package/src/harden/stack-roots.js +105 -0
- package/src/harden/test-on-push.js +38 -0
- package/src/harden/workflow-engine.js +116 -0
- package/src/harden/workflow-templates.js +285 -0
- package/src/hu/acceptance-runner.js +138 -0
- package/src/hu/auto-generator.js +358 -0
- package/src/hu/graph.js +71 -0
- package/src/hu/lazy-planner.js +109 -0
- package/src/hu/model-router.js +108 -0
- package/src/hu/parallel-executor.js +94 -0
- package/src/hu/split-validator.js +143 -0
- package/src/hu/splitting-detector.js +158 -0
- package/src/hu/splitting-generator.js +175 -0
- package/src/hu/store.js +392 -0
- package/src/hu/worktree-bootstrap.js +59 -0
- package/src/identity/bootstrap.js +48 -0
- package/src/identity/compare.js +38 -0
- package/src/identity/detect.js +51 -0
- package/src/identity/store.js +66 -0
- package/src/infrastructure/command-runner.js +44 -0
- package/src/infrastructure/environment.js +38 -0
- package/src/infrastructure/file-system-service.js +63 -0
- package/src/infrastructure/mocks.js +182 -0
- package/src/lang/chunk-go.js +94 -0
- package/src/lang/chunk-java.js +90 -0
- package/src/lang/chunk-python.js +88 -0
- package/src/lang/chunk-rust.js +102 -0
- package/src/lang/go.js +14 -0
- package/src/lang/java.js +16 -0
- package/src/lang/js.js +8 -0
- package/src/lang/python.js +14 -0
- package/src/lang/registry.js +79 -0
- package/src/lang/rust.js +14 -0
- package/src/lang/tree-sitter-loader.js +45 -0
- package/src/mcp/direct-role-runner.js +112 -0
- package/src/mcp/error-classifiers.js +66 -0
- package/src/mcp/handlers/direct-handlers.js +486 -0
- package/src/mcp/handlers/hu-handlers.js +93 -0
- package/src/mcp/handlers/management-handlers.js +265 -0
- package/src/mcp/handlers/rag-handler.js +52 -0
- package/src/mcp/handlers/run-handler.js +313 -0
- package/src/mcp/orphan-guard.js +131 -0
- package/src/mcp/preflight.js +47 -0
- package/src/mcp/progress.js +149 -0
- package/src/mcp/response-compressor.js +81 -0
- package/src/mcp/run-kj.js +135 -0
- package/src/mcp/server-handlers.js +79 -0
- package/src/mcp/server.js +66 -0
- package/src/mcp/shared-helpers.js +297 -0
- package/src/mcp/sovereignty-guard.js +112 -0
- package/src/mcp/suggest-handler.js +92 -0
- package/src/mcp/tool-arg-normalizers.js +16 -0
- package/src/mcp/tools.js +432 -0
- package/src/mutate/diff-scope.js +105 -0
- package/src/mutate/reviewer-signal.js +76 -0
- package/src/mutate/runner.js +72 -0
- package/src/mutate/tool-registry.js +90 -0
- package/src/onboarder/cache.js +24 -0
- package/src/onboarder/collectors/framework-multilang.js +64 -0
- package/src/onboarder/collectors/index.js +136 -0
- package/src/orchestrator/agent-fallback.js +81 -0
- package/src/orchestrator/brain-coordinator.js +186 -0
- package/src/orchestrator/ci-integration.js +139 -0
- package/src/orchestrator/config-init.js +510 -0
- package/src/orchestrator/direct-actions.js +217 -0
- package/src/orchestrator/drivers/error-recovery.js +287 -0
- package/src/orchestrator/drivers/init-context.js +227 -0
- package/src/orchestrator/drivers/iteration-loop.js +380 -0
- package/src/orchestrator/drivers/iteration-phases/coder-and-refactorer.js +69 -0
- package/src/orchestrator/drivers/iteration-phases/guards.js +84 -0
- package/src/orchestrator/drivers/iteration-phases/handle-approved.js +29 -0
- package/src/orchestrator/drivers/iteration-phases/quality-gates.js +114 -0
- package/src/orchestrator/drivers/iteration-phases/reviewer-gate.js +60 -0
- package/src/orchestrator/drivers/post-loop.js +383 -0
- package/src/orchestrator/drivers/pre-loop-phases/auto-hu-batch.js +136 -0
- package/src/orchestrator/drivers/pre-loop-phases/config-deprecations.js +47 -0
- package/src/orchestrator/drivers/pre-loop-phases/ensure-addyosmani-skills.js +84 -0
- package/src/orchestrator/drivers/pre-loop-phases/inject-loaded-plan.js +391 -0
- package/src/orchestrator/drivers/pre-loop.js +507 -0
- package/src/orchestrator/drivers/run-hu-batch.js +427 -0
- package/src/orchestrator/feedback-enrichment.js +140 -0
- package/src/orchestrator/feedback-queue.js +151 -0
- package/src/orchestrator/flow-control.js +170 -0
- package/src/orchestrator/flow-runner.js +364 -0
- package/src/orchestrator/fs-leak-detector.js +210 -0
- package/src/orchestrator/hu-scheduler.js +114 -0
- package/src/orchestrator/hu-sub-pipeline.js +616 -0
- package/src/orchestrator/integrations.js +81 -0
- package/src/orchestrator/iteration-gate.js +73 -0
- package/src/orchestrator/iteration-stages.js +9 -0
- package/src/orchestrator/parallel-limiter.js +74 -0
- package/src/orchestrator/pipeline-context.js +72 -0
- package/src/orchestrator/post-loop-stages.js +468 -0
- package/src/orchestrator/pre-loop-stages.js +11 -0
- package/src/orchestrator/preflight-checks.js +462 -0
- package/src/orchestrator/repair/repair-detector.js +117 -0
- package/src/orchestrator/repair/repair-runner.js +142 -0
- package/src/orchestrator/reviewer-fallback.js +45 -0
- package/src/orchestrator/role-output-compressor.js +189 -0
- package/src/orchestrator/session-journal.js +308 -0
- package/src/orchestrator/solomon-escalation.js +305 -0
- package/src/orchestrator/solomon-rules.js +212 -0
- package/src/orchestrator/stages/architect-stage.js +172 -0
- package/src/orchestrator/stages/coder-stage.js +480 -0
- package/src/orchestrator/stages/domain-curator-stage.js +82 -0
- package/src/orchestrator/stages/hu-reviewer-phases/detect-and-apply-splits.js +127 -0
- package/src/orchestrator/stages/hu-reviewer-stage.js +394 -0
- package/src/orchestrator/stages/perf-stage.js +140 -0
- package/src/orchestrator/stages/planner-stage.js +85 -0
- package/src/orchestrator/stages/rag-context-stage.js +77 -0
- package/src/orchestrator/stages/rag-preload-decisor.js +58 -0
- package/src/orchestrator/stages/research-stage.js +69 -0
- package/src/orchestrator/stages/reviewer-stage.js +422 -0
- package/src/orchestrator/stages/sonar-stage.js +421 -0
- package/src/orchestrator/stages/stage-classes.js +84 -0
- package/src/orchestrator/stages/stage-executor.js +155 -0
- package/src/orchestrator/stages/tdd-discipline-stage.js +56 -0
- package/src/orchestrator/stages/tool-judge-stage.js +53 -0
- package/src/orchestrator/stages/triage-stage.js +172 -0
- package/src/orchestrator/standby.js +71 -0
- package/src/orchestrator/verification-gate.js +183 -0
- package/src/orchestrator.js +22 -0
- package/src/plan/adr-generator.js +170 -0
- package/src/plan/adr-loader.js +60 -0
- package/src/plan/plan-executor.js +100 -0
- package/src/plan/plan-fixer.js +192 -0
- package/src/plan/plan-hu-ops.js +16 -0
- package/src/plan/plan-id.js +4 -0
- package/src/plan/plan-migrate-result.js +24 -0
- package/src/plan/plan-reviewer.js +236 -0
- package/src/plan/plan-schema.js +334 -0
- package/src/plan/plan-store.js +260 -0
- package/src/plan/plan-structural-pass.js +122 -0
- package/src/plan/plan-validation.js +4 -0
- package/src/plan/preflight-hu.js +105 -0
- package/src/plan/spec-detector.js +61 -0
- package/src/plan/tests-synthesizer.js +131 -0
- package/src/planning-game/adapter.js +108 -0
- package/src/planning-game/architect-adrs.js +45 -0
- package/src/planning-game/client.js +108 -0
- package/src/planning-game/decomposition.js +87 -0
- package/src/planning-game/pipeline-adapter.js +251 -0
- package/src/plugins/loader.js +67 -0
- package/src/policy/add.js +111 -0
- package/src/policy/decisions.js +42 -0
- package/src/policy/engine.js +82 -0
- package/src/policy/exceptions.js +60 -0
- package/src/privacy/onboarding.js +35 -0
- package/src/privacy/scan.js +120 -0
- package/src/prompts/arbiter.js +38 -0
- package/src/prompts/architect.js +103 -0
- package/src/prompts/audit.js +474 -0
- package/src/prompts/coder.js +287 -0
- package/src/prompts/diff-clip.js +27 -0
- package/src/prompts/discover.js +222 -0
- package/src/prompts/hu-reviewer.js +219 -0
- package/src/prompts/planner.js +312 -0
- package/src/prompts/prompt-layout.js +80 -0
- package/src/prompts/prompt-resolver.js +120 -0
- package/src/prompts/reviewer.js +75 -0
- package/src/prompts/rtk-snippet.js +25 -0
- package/src/prompts/spec-reviewer.js +66 -0
- package/src/prompts/split-signal.js +82 -0
- package/src/prompts/start-decision.js +52 -0
- package/src/prompts/tool-correctness-judge.js +31 -0
- package/src/prompts/triage.js +57 -0
- package/src/rag/auto-update.js +72 -0
- package/src/rag/chunker-ast.js +56 -0
- package/src/rag/chunker.js +132 -0
- package/src/rag/embedder.js +2 -0
- package/src/rag/embedders/_cloud-base.js +2 -0
- package/src/rag/embedders/cohere.js +2 -0
- package/src/rag/embedders/factory.js +2 -0
- package/src/rag/embedders/mistral.js +2 -0
- package/src/rag/embedders/onnx.js +2 -0
- package/src/rag/embedders/openai.js +2 -0
- package/src/rag/embedders/voyage.js +2 -0
- package/src/rag/eval.js +61 -0
- package/src/rag/governed-embedder.js +39 -0
- package/src/rag/indexer.js +199 -0
- package/src/rag/library.js +62 -0
- package/src/rag/ollama-capability.js +59 -0
- package/src/rag/ollama-manager.js +98 -0
- package/src/rag/onnx-fallback.js +69 -0
- package/src/rag/rerank.js +4 -0
- package/src/rag/retriever.js +2 -0
- package/src/rag/vec-store.js +17 -0
- package/src/rag/watcher.js +62 -0
- package/src/rag/where-parser.js +4 -0
- package/src/repeat-detector.js +88 -0
- package/src/review/card-first.js +99 -0
- package/src/review/card-verify.js +83 -0
- package/src/review/diff-generator.js +112 -0
- package/src/review/gate-gitignore.js +77 -0
- package/src/review/git-stash-helper.js +104 -0
- package/src/review/mutation-pregate.js +48 -0
- package/src/review/one-shot-review.js +122 -0
- package/src/review/parser.js +80 -0
- package/src/review/policy-gate.js +26 -0
- package/src/review/profiles.js +66 -0
- package/src/review/reviewer-fallback.js +125 -0
- package/src/review/schema.js +31 -0
- package/src/review/scope-filter.js +152 -0
- package/src/review/snapshot-diff.js +122 -0
- package/src/review/solomon-arbitration.js +113 -0
- package/src/review/sonar-pregate.js +63 -0
- package/src/review/tdd-discipline.js +90 -0
- package/src/review/tdd-policy.js +69 -0
- package/src/review/tests-with-code.js +33 -0
- package/src/review/verdict-store.js +87 -0
- package/src/review/workspace.js +21 -0
- package/src/roles/agent-role.js +194 -0
- package/src/roles/architect-role.js +77 -0
- package/src/roles/audit-role.js +258 -0
- package/src/roles/base-role.js +165 -0
- package/src/roles/coder-role.js +107 -0
- package/src/roles/commiter-role.js +110 -0
- package/src/roles/discover-role.js +81 -0
- package/src/roles/domain-curator-role.js +141 -0
- package/src/roles/hu-reviewer-role.js +64 -0
- package/src/roles/impeccable-role.js +85 -0
- package/src/roles/index.js +18 -0
- package/src/roles/karajan-brain-role.js +134 -0
- package/src/roles/onboarder-role.js +61 -0
- package/src/roles/perf-role.js +122 -0
- package/src/roles/planner-role.js +151 -0
- package/src/roles/refactorer-role.js +30 -0
- package/src/roles/repairer-role.js +181 -0
- package/src/roles/researcher-role.js +70 -0
- package/src/roles/reviewer-role.js +104 -0
- package/src/roles/security-role.js +73 -0
- package/src/roles/solomon-role.js +265 -0
- package/src/roles/sonar-role.js +70 -0
- package/src/roles/spec-reviewer-role.js +106 -0
- package/src/roles/tester-role.js +235 -0
- package/src/roles/tool-correctness-judge-role.js +78 -0
- package/src/roles/triage-role.js +99 -0
- package/src/session/journal/decisions-writer.js +200 -0
- package/src/session/journal/iteration-logger.js +194 -0
- package/src/session/journal/summary-writer.js +320 -0
- package/src/session/journal/tree-writer.js +164 -0
- package/src/session/journal/write-all.js +89 -0
- package/src/session/mutators.js +339 -0
- package/src/session/runtime-overrides.js +59 -0
- package/src/session/store.js +106 -0
- package/src/session-cleanup.js +116 -0
- package/src/skills/addyosmani-catalog.js +315 -0
- package/src/skills/addyosmani-role-map.js +139 -0
- package/src/skills/openskills-client.js +157 -0
- package/src/skills/semantic-detector.js +167 -0
- package/src/skills/skill-detector.js +385 -0
- package/src/skills/skill-loader.js +219 -0
- package/src/skills/skills-cache.js +128 -0
- package/src/sonar/api.js +128 -0
- package/src/sonar/cloud-scanner.js +78 -0
- package/src/sonar/config-resolver.js +88 -0
- package/src/sonar/credentials.js +60 -0
- package/src/sonar/discovery.js +124 -0
- package/src/sonar/enforcer.js +19 -0
- package/src/sonar/issue-filter.js +12 -0
- package/src/sonar/manager.js +181 -0
- package/src/sonar/project-key.js +120 -0
- package/src/sonar/scanner.js +307 -0
- package/src/sonar/token-bootstrap.js +205 -0
- package/src/sonar/token-recovery.js +67 -0
- package/src/spec-review/refine-loop.js +58 -0
- package/src/spec-review/run-spec-review.js +119 -0
- package/src/start/assessment.js +74 -0
- package/src/start/maturity.js +73 -0
- package/src/start/start-decider-role.js +79 -0
- package/src/start/sweep.js +157 -0
- package/src/sync/apply-canvas-patch.js +55 -0
- package/src/sync/detect-drift.js +113 -0
- package/src/tournament/crown.js +88 -0
- package/src/tournament/judge.js +150 -0
- package/src/tournament/run.js +142 -0
- package/src/tournament/scoreboard.js +124 -0
- package/src/tracker-bootstrap.js +44 -0
- package/src/types/agent.js +55 -0
- package/src/types/config.js +114 -0
- package/src/types/hu.js +47 -0
- package/src/types/index.js +38 -0
- package/src/types/policy.js +43 -0
- package/src/types/session.js +75 -0
- package/src/types/solomon.js +87 -0
- package/src/types/stage.js +68 -0
- package/src/utils/agent-detect.js +93 -0
- package/src/utils/ai-trash.js +48 -0
- package/src/utils/async-lock.js +31 -0
- package/src/utils/atomic-write.js +6 -0
- package/src/utils/banner.js +66 -0
- package/src/utils/binary-sources.js +70 -0
- package/src/utils/board-prompt-bridge.js +108 -0
- package/src/utils/budget.js +229 -0
- package/src/utils/cli-ask-question.js +93 -0
- package/src/utils/cli-progress.js +220 -0
- package/src/utils/cli-run-log.js +83 -0
- package/src/utils/cwd-confirm.js +39 -0
- package/src/utils/derive-project-name-from-cwd.js +119 -0
- package/src/utils/display/event-handlers.js +403 -0
- package/src/utils/display/formatters.js +132 -0
- package/src/utils/display/header.js +47 -0
- package/src/utils/display/resume-hint.js +41 -0
- package/src/utils/display/session-summary.js +118 -0
- package/src/utils/display/solomon.js +42 -0
- package/src/utils/display/spec-findings.js +44 -0
- package/src/utils/doc-links.js +29 -0
- package/src/utils/docker-install.js +34 -0
- package/src/utils/escape-regexp.js +15 -0
- package/src/utils/events.js +35 -0
- package/src/utils/fs.js +19 -0
- package/src/utils/garbage-collector.js +481 -0
- package/src/utils/git.js +279 -0
- package/src/utils/home-migration.js +87 -0
- package/src/utils/injection-guard.js +186 -0
- package/src/utils/install-hints.js +180 -0
- package/src/utils/json-extract.js +64 -0
- package/src/utils/locale.js +59 -0
- package/src/utils/logger.js +96 -0
- package/src/utils/managed-markers.js +93 -0
- package/src/utils/manifest-sniff.js +82 -0
- package/src/utils/messages.js +61 -0
- package/src/utils/model-selector.js +107 -0
- package/src/utils/os-detect.js +79 -0
- package/src/utils/paths.js +13 -0
- package/src/utils/pending-user-action.js +95 -0
- package/src/utils/port-check.js +6 -0
- package/src/utils/port-occupant.js +96 -0
- package/src/utils/pricing.js +29 -0
- package/src/utils/process.js +4 -0
- package/src/utils/project-detect.js +160 -0
- package/src/utils/prompt-project-name.js +35 -0
- package/src/utils/provider-env.js +116 -0
- package/src/utils/qmd-collection.js +72 -0
- package/src/utils/qmd-detect.js +18 -0
- package/src/utils/qmd-install.js +37 -0
- package/src/utils/quota-simulator.js +56 -0
- package/src/utils/rate-limit-detector.js +181 -0
- package/src/utils/repo-cleaner.js +79 -0
- package/src/utils/retry.js +88 -0
- package/src/utils/role-assigner.js +137 -0
- package/src/utils/role-env.js +58 -0
- package/src/utils/rtk-detect.js +18 -0
- package/src/utils/rtk-install.js +38 -0
- package/src/utils/rtk-wrapper.js +87 -0
- package/src/utils/run-context.js +75 -0
- package/src/utils/run-log.js +217 -0
- package/src/utils/run-registry.js +9 -0
- package/src/utils/shared-paths.js +12 -0
- package/src/utils/squeezr-detect.js +21 -0
- package/src/utils/squeezr-install.js +37 -0
- package/src/utils/stack-detect.js +135 -0
- package/src/utils/stall-detector.js +159 -0
- package/src/utils/status-dashboard.js +254 -0
- package/src/utils/task-file.js +109 -0
- package/src/utils/telemetry.js +124 -0
- package/src/utils/templates-root.js +61 -0
- package/src/utils/tool-call-extractor.js +56 -0
- package/src/utils/tool-governor.js +116 -0
- package/src/utils/tool-installer.js +93 -0
- package/src/utils/update-check.js +280 -0
- package/src/utils/vector-store-orphans.js +89 -0
- package/src/utils/welcome.js +47 -0
- package/src/utils/with-timeout.js +42 -0
- package/src/utils/wizard.js +47 -0
- package/src/webperf/cwv-gate.js +94 -0
- package/src/webperf/devtools-detect.js +112 -0
- package/src/webperf/scanner.js +209 -0
- package/src/webperf/webperf-role-integration.js +66 -0
- package/templates/coder-rules.md +45 -0
- package/templates/docker-compose.sonar.yml +60 -0
- package/templates/domains/example-dental.md +57 -0
- package/templates/kj.config.yml +128 -0
- package/templates/review-rules.md +17 -0
- package/templates/roles/architect/anthropic.md +74 -0
- package/templates/roles/architect/default.md +72 -0
- package/templates/roles/architect/google.md +61 -0
- package/templates/roles/architect/openai.md +60 -0
- package/templates/roles/architect/opencode.md +59 -0
- package/templates/roles/architect.md +76 -0
- package/templates/roles/audit.md +68 -0
- package/templates/roles/coder/anthropic.md +81 -0
- package/templates/roles/coder/default.md +78 -0
- package/templates/roles/coder/google.md +87 -0
- package/templates/roles/coder/openai.md +68 -0
- package/templates/roles/coder/opencode.md +58 -0
- package/templates/roles/coder.md +152 -0
- package/templates/roles/commiter.md +44 -0
- package/templates/roles/discover.md +167 -0
- package/templates/roles/domain-curator.md +52 -0
- package/templates/roles/hu-reviewer.md +236 -0
- package/templates/roles/impeccable-design.md +87 -0
- package/templates/roles/impeccable.md +125 -0
- package/templates/roles/karajan-brain.md +95 -0
- package/templates/roles/onboarder.md +45 -0
- package/templates/roles/planner/anthropic.md +59 -0
- package/templates/roles/planner/default.md +57 -0
- package/templates/roles/planner/google.md +75 -0
- package/templates/roles/planner/openai.md +55 -0
- package/templates/roles/planner/opencode.md +62 -0
- package/templates/roles/planner.md +61 -0
- package/templates/roles/refactorer.md +48 -0
- package/templates/roles/repairer.md +103 -0
- package/templates/roles/researcher.md +41 -0
- package/templates/roles/reviewer/anthropic.md +61 -0
- package/templates/roles/reviewer/default.md +62 -0
- package/templates/roles/reviewer/google.md +63 -0
- package/templates/roles/reviewer/openai.md +57 -0
- package/templates/roles/reviewer/opencode.md +42 -0
- package/templates/roles/reviewer-paranoid.md +38 -0
- package/templates/roles/reviewer-relaxed.md +34 -0
- package/templates/roles/reviewer-strict.md +37 -0
- package/templates/roles/reviewer.md +62 -0
- package/templates/roles/security.md +54 -0
- package/templates/roles/solomon/anthropic.md +71 -0
- package/templates/roles/solomon/default.md +83 -0
- package/templates/roles/solomon/google.md +61 -0
- package/templates/roles/solomon/openai.md +53 -0
- package/templates/roles/solomon/opencode.md +55 -0
- package/templates/roles/solomon.md +83 -0
- package/templates/roles/sonar.md +49 -0
- package/templates/roles/spec-reviewer.md +47 -0
- package/templates/roles/tester.md +50 -0
- package/templates/roles/triage.md +69 -0
- package/templates/skills/kj-architect.md +45 -0
- package/templates/skills/kj-audit.md +63 -0
- package/templates/skills/kj-board.md +16 -0
- package/templates/skills/kj-code.md +51 -0
- package/templates/skills/kj-csv-transform.md +40 -0
- package/templates/skills/kj-data-report.md +44 -0
- package/templates/skills/kj-discover.md +24 -0
- package/templates/skills/kj-rag-query.md +50 -0
- package/templates/skills/kj-review.md +47 -0
- package/templates/skills/kj-run.md +73 -0
- package/templates/skills/kj-security.md +49 -0
- package/templates/skills/kj-sonar.md +41 -0
- package/templates/skills/kj-sql-analysis.md +40 -0
- package/templates/skills/kj-test.md +40 -0
- package/templates/workflows/automerge.yml +30 -0
- package/templates/workflows/houston-override.yml +46 -0
- package/templates/workflows/kj-ci-gateway.yml +58 -0
- package/vendor/tree-sitter-grammars/README.md +21 -0
- package/vendor/tree-sitter-grammars/go.wasm +0 -0
- package/vendor/tree-sitter-grammars/java.wasm +0 -0
- package/vendor/tree-sitter-grammars/python.wasm +0 -0
- package/vendor/tree-sitter-grammars/rust.wasm +0 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Load SonarQube credentials from ~/.karajan/sonar-credentials.json.
|
|
3
|
+
*
|
|
4
|
+
* File format (any subset):
|
|
5
|
+
* {
|
|
6
|
+
* "user": "admin",
|
|
7
|
+
* "password": "your-password",
|
|
8
|
+
* "token": "squ_..."
|
|
9
|
+
* }
|
|
10
|
+
*
|
|
11
|
+
* Returns { user, password, token } with each field null when missing.
|
|
12
|
+
*
|
|
13
|
+
* The `token` field is consumed by resolveSonarTokenAsync as the
|
|
14
|
+
* lowest-priority fallback. Until v2.7.5 it was not extracted here, which
|
|
15
|
+
* meant a token persisted to the credentials file by `kj init` was never
|
|
16
|
+
* actually used at scan time — Karajan would silently fall back to the
|
|
17
|
+
* stale token in kj.config.yml or fail with a 401.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import fs from "node:fs/promises";
|
|
21
|
+
import path from "node:path";
|
|
22
|
+
import { getKarajanHome } from "../utils/paths.js";
|
|
23
|
+
|
|
24
|
+
const CREDENTIALS_FILENAME = "sonar-credentials.json";
|
|
25
|
+
|
|
26
|
+
export async function loadSonarCredentials() {
|
|
27
|
+
try {
|
|
28
|
+
const filePath = path.join(getKarajanHome(), CREDENTIALS_FILENAME);
|
|
29
|
+
const raw = await fs.readFile(filePath, "utf8");
|
|
30
|
+
const data = JSON.parse(raw);
|
|
31
|
+
return {
|
|
32
|
+
user: data.user || null,
|
|
33
|
+
password: data.password || null,
|
|
34
|
+
token: data.token || null
|
|
35
|
+
};
|
|
36
|
+
} catch { /* credentials file may not exist */
|
|
37
|
+
return { user: null, password: null, token: null };
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function credentialsPath() {
|
|
42
|
+
return path.join(getKarajanHome(), CREDENTIALS_FILENAME);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Save a generated token to ~/.karajan/sonar-credentials.json so it persists across sessions.
|
|
47
|
+
* Merges with existing credentials (preserves user/password if present).
|
|
48
|
+
*/
|
|
49
|
+
export async function saveSonarToken(token) {
|
|
50
|
+
const filePath = path.join(getKarajanHome(), CREDENTIALS_FILENAME);
|
|
51
|
+
let existing = {};
|
|
52
|
+
try {
|
|
53
|
+
const raw = await fs.readFile(filePath, "utf8");
|
|
54
|
+
existing = JSON.parse(raw);
|
|
55
|
+
} catch { /* file may not exist */ }
|
|
56
|
+
existing.token = token;
|
|
57
|
+
const dir = getKarajanHome();
|
|
58
|
+
await fs.mkdir(dir, { recursive: true });
|
|
59
|
+
await fs.writeFile(filePath, JSON.stringify(existing, null, 2), { encoding: "utf8", mode: 0o600 });
|
|
60
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Discover running SonarQube containers regardless of the user's
|
|
3
|
+
* config. The point: never bother the user about port 9000 being
|
|
4
|
+
* "occupied by an unknown process" — if there's a Sonar already up
|
|
5
|
+
* somewhere, just point at it and move on.
|
|
6
|
+
*
|
|
7
|
+
* The previous preflight check insisted on owning port 9000 by name
|
|
8
|
+
* (`karajan-sonarqube`). If you happened to have a `sonarqube` from
|
|
9
|
+
* another project running on 9000 (or had pulled a different image
|
|
10
|
+
* tag), we'd error out asking the user to "stop the conflicting
|
|
11
|
+
* process". That's busywork — Sonar is Sonar; reuse what's there.
|
|
12
|
+
*
|
|
13
|
+
* The discovery strategy:
|
|
14
|
+
* 1. List Docker containers whose image looks like sonarqube
|
|
15
|
+
* (image-name regex / ancestor filter — covers `sonarqube`,
|
|
16
|
+
* `sonarqube:community`, `sonarqube:lts`, `sonarqube:9.9`, …).
|
|
17
|
+
* 2. Parse the published host port (`0.0.0.0:9001->9000/tcp`).
|
|
18
|
+
* 3. Optionally HTTP-probe to confirm it's actually serving
|
|
19
|
+
* `/api/system/status` so a misnamed image can't hijack us.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { runCommand } from "../utils/process.js";
|
|
23
|
+
import { isSonarReachable } from "./manager.js";
|
|
24
|
+
import { escapeRegExp } from "../utils/escape-regexp.js";
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @typedef {Object} DiscoveredSonar
|
|
28
|
+
* @property {boolean} found
|
|
29
|
+
* @property {string} [containerName]
|
|
30
|
+
* @property {string} [image]
|
|
31
|
+
* @property {number} [port] - host port (what we connect to)
|
|
32
|
+
* @property {string} [host] - http://localhost:<port>
|
|
33
|
+
* @property {boolean} [reachable] - true after a successful HTTP probe
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Parse the Ports column from `docker ps`. Looks for any host binding
|
|
38
|
+
* that maps to the container's `internalPort` (default 9000).
|
|
39
|
+
* Examples:
|
|
40
|
+
* "0.0.0.0:9000->9000/tcp" → 9000
|
|
41
|
+
* "127.0.0.1:9001->9000/tcp" → 9001
|
|
42
|
+
* "9000/tcp" → null (no host binding)
|
|
43
|
+
* "0.0.0.0:9000->9000/tcp, 9092/tcp" → 9000
|
|
44
|
+
*
|
|
45
|
+
* @param {string} portsStr
|
|
46
|
+
* @param {number} [internalPort=9000]
|
|
47
|
+
* @returns {number|null}
|
|
48
|
+
*/
|
|
49
|
+
export function extractHostPort(portsStr, internalPort = 9000) {
|
|
50
|
+
if (!portsStr) return null;
|
|
51
|
+
const re = new RegExp(
|
|
52
|
+
`(?:0\\.0\\.0\\.0|127\\.0\\.0\\.1|::|\\[::\\]):(\\d+)\\s*->\\s*${escapeRegExp(internalPort)}\\/tcp`,
|
|
53
|
+
"g"
|
|
54
|
+
);
|
|
55
|
+
const matches = [...portsStr.matchAll(re)];
|
|
56
|
+
if (matches.length === 0) return null;
|
|
57
|
+
// Prefer the smallest port number (likeliest the "main" binding);
|
|
58
|
+
// arbitrary but deterministic.
|
|
59
|
+
return Math.min(...matches.map((m) => Number(m[1])));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Run `docker ps` with a list-of-images filter and parse the result.
|
|
64
|
+
* Returns the FIRST container with a usable host port, or null.
|
|
65
|
+
*
|
|
66
|
+
* @returns {Promise<DiscoveredSonar|null>}
|
|
67
|
+
*/
|
|
68
|
+
async function dockerPsForSonar() {
|
|
69
|
+
// List all running containers with their image so we can image-match
|
|
70
|
+
// ourselves. Cheap (single docker call) and tolerant of image tags.
|
|
71
|
+
const res = await runCommand("docker", [
|
|
72
|
+
"ps",
|
|
73
|
+
"--format", "{{.ID}}|{{.Names}}|{{.Image}}|{{.Ports}}",
|
|
74
|
+
]);
|
|
75
|
+
if (res.exitCode !== 0 || !res.stdout?.trim()) return null;
|
|
76
|
+
|
|
77
|
+
const lines = res.stdout.trim().split("\n");
|
|
78
|
+
for (const line of lines) {
|
|
79
|
+
const [, name, image, ports] = line.split("|");
|
|
80
|
+
if (!image) continue;
|
|
81
|
+
if (!/sonarqube/i.test(image)) continue;
|
|
82
|
+
const port = extractHostPort(ports, 9000);
|
|
83
|
+
if (!port) continue;
|
|
84
|
+
return {
|
|
85
|
+
found: true,
|
|
86
|
+
containerName: name,
|
|
87
|
+
image,
|
|
88
|
+
port,
|
|
89
|
+
host: `http://localhost:${port}`,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Public entry point: find a usable, reachable Sonar.
|
|
97
|
+
*
|
|
98
|
+
* `probe`: when true (default) HTTP-pings `/api/system/status` to
|
|
99
|
+
* confirm the container is actually serving Sonar. Tests can disable
|
|
100
|
+
* the probe for hermetic mocking.
|
|
101
|
+
*
|
|
102
|
+
* @param {object} [opts]
|
|
103
|
+
* @param {boolean} [opts.probe=true]
|
|
104
|
+
* @param {number} [opts.healthcheckSeconds=5]
|
|
105
|
+
* @returns {Promise<DiscoveredSonar>}
|
|
106
|
+
*/
|
|
107
|
+
export async function discoverRunningSonar(opts = {}) {
|
|
108
|
+
const { probe = true, healthcheckSeconds = 5 } = opts;
|
|
109
|
+
let candidate;
|
|
110
|
+
try {
|
|
111
|
+
candidate = await dockerPsForSonar();
|
|
112
|
+
} catch {
|
|
113
|
+
candidate = null;
|
|
114
|
+
}
|
|
115
|
+
if (!candidate) return { found: false };
|
|
116
|
+
if (!probe) return { ...candidate, reachable: true };
|
|
117
|
+
let reachable;
|
|
118
|
+
try {
|
|
119
|
+
reachable = await isSonarReachable(candidate.host, healthcheckSeconds);
|
|
120
|
+
} catch {
|
|
121
|
+
reachable = false;
|
|
122
|
+
}
|
|
123
|
+
return { ...candidate, reachable };
|
|
124
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export function shouldBlockByProfile({ gateStatus, profile = "pragmatic" }) {
|
|
2
|
+
if (profile === "paranoid") {
|
|
3
|
+
return gateStatus !== "OK";
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
return gateStatus === "ERROR";
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function summarizeIssues(issues) {
|
|
10
|
+
const bySeverity = issues.reduce((acc, issue) => {
|
|
11
|
+
const severity = issue.severity || "UNKNOWN";
|
|
12
|
+
acc[severity] = (acc[severity] || 0) + 1;
|
|
13
|
+
return acc;
|
|
14
|
+
}, {});
|
|
15
|
+
|
|
16
|
+
return Object.entries(bySeverity)
|
|
17
|
+
.map(([severity, count]) => `${severity}: ${count}`)
|
|
18
|
+
.join(", ");
|
|
19
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// @deprecated — moved to src/audit/issue-filter.js (v2.17.0). This shim
|
|
2
|
+
// re-exports the generalised filter so existing imports keep working. All
|
|
3
|
+
// Sonar-specific behaviour (default `tool="sonar"`, legacy
|
|
4
|
+
// `// karajan-sonar-ignore: <rule>` markers) is preserved by the new module.
|
|
5
|
+
//
|
|
6
|
+
// New code should import from "../audit/issue-filter.js" directly.
|
|
7
|
+
|
|
8
|
+
export {
|
|
9
|
+
filterFalsePositives,
|
|
10
|
+
hasInlineIgnore,
|
|
11
|
+
DEFAULT_FALSE_POSITIVES,
|
|
12
|
+
} from "../audit/issue-filter.js";
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import { ensureDir } from "../utils/fs.js";
|
|
3
|
+
import { runCommand } from "../utils/process.js";
|
|
4
|
+
import { getKarajanHome, getSonarComposePath } from "../utils/paths.js";
|
|
5
|
+
import { loadConfig } from "../config.js";
|
|
6
|
+
|
|
7
|
+
const KARAJAN_HOME = getKarajanHome();
|
|
8
|
+
const COMPOSE_PATH = getSonarComposePath();
|
|
9
|
+
|
|
10
|
+
function normalizeSonarConfig(sonarqube = {}) {
|
|
11
|
+
const timeouts = sonarqube.timeouts || {};
|
|
12
|
+
return {
|
|
13
|
+
host: sonarqube.host || "http://localhost:9000",
|
|
14
|
+
external: sonarqube.external === true,
|
|
15
|
+
containerName: sonarqube.container_name || "karajan-sonarqube",
|
|
16
|
+
network: sonarqube.network || "karajan_sonar_net",
|
|
17
|
+
volumes: {
|
|
18
|
+
data: sonarqube?.volumes?.data || "karajan_sonar_data",
|
|
19
|
+
logs: sonarqube?.volumes?.logs || "karajan_sonar_logs",
|
|
20
|
+
extensions: sonarqube?.volumes?.extensions || "karajan_sonar_extensions"
|
|
21
|
+
},
|
|
22
|
+
timeouts: {
|
|
23
|
+
healthcheckSeconds: Number(timeouts.healthcheck_seconds) > 0 ? Number(timeouts.healthcheck_seconds) : 5,
|
|
24
|
+
composeUpMs: Number(timeouts.compose_up_ms) > 0 ? Number(timeouts.compose_up_ms) : 5 * 60 * 1000,
|
|
25
|
+
composeControlMs: Number(timeouts.compose_control_ms) > 0 ? Number(timeouts.compose_control_ms) : 2 * 60 * 1000,
|
|
26
|
+
logsMs: Number(timeouts.logs_ms) > 0 ? Number(timeouts.logs_ms) : 30 * 1000
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function buildComposeTemplate(sonarConfig) {
|
|
32
|
+
return `services:
|
|
33
|
+
sonarqube:
|
|
34
|
+
image: sonarqube:community
|
|
35
|
+
container_name: ${sonarConfig.containerName}
|
|
36
|
+
ports:
|
|
37
|
+
- "9000:9000"
|
|
38
|
+
volumes:
|
|
39
|
+
- ${sonarConfig.volumes.data}:/opt/sonarqube/data
|
|
40
|
+
- ${sonarConfig.volumes.logs}:/opt/sonarqube/logs
|
|
41
|
+
- ${sonarConfig.volumes.extensions}:/opt/sonarqube/extensions
|
|
42
|
+
environment:
|
|
43
|
+
- SONAR_ES_BOOTSTRAP_CHECKS_DISABLE=true
|
|
44
|
+
networks:
|
|
45
|
+
- ${sonarConfig.network}
|
|
46
|
+
restart: unless-stopped
|
|
47
|
+
|
|
48
|
+
volumes:
|
|
49
|
+
${sonarConfig.volumes.data}:
|
|
50
|
+
${sonarConfig.volumes.logs}:
|
|
51
|
+
${sonarConfig.volumes.extensions}:
|
|
52
|
+
|
|
53
|
+
networks:
|
|
54
|
+
${sonarConfig.network}:
|
|
55
|
+
name: ${sonarConfig.network}
|
|
56
|
+
`;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export async function ensureComposeFile(sonarqube = null) {
|
|
60
|
+
const sonarConfig = sonarqube ? normalizeSonarConfig(sonarqube) : normalizeSonarConfig((await loadConfig()).config.sonarqube);
|
|
61
|
+
const composeTemplate = buildComposeTemplate(sonarConfig);
|
|
62
|
+
await ensureDir(KARAJAN_HOME);
|
|
63
|
+
await fs.writeFile(COMPOSE_PATH, composeTemplate, "utf8");
|
|
64
|
+
return COMPOSE_PATH;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export async function isSonarReachable(host, healthcheckSeconds = 5) {
|
|
68
|
+
const timeout = Number(healthcheckSeconds) > 0 ? String(Number(healthcheckSeconds)) : "5";
|
|
69
|
+
const res = await runCommand("curl", ["-s", "-o", "/dev/null", "-w", "%{http_code}", "--max-time", timeout, `${host}/api/system/status`]);
|
|
70
|
+
return res.exitCode === 0 && res.stdout.trim().startsWith("2");
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export async function sonarUp(hostOverride = null) {
|
|
74
|
+
const { config } = await loadConfig();
|
|
75
|
+
const sonarConfig = normalizeSonarConfig(config.sonarqube);
|
|
76
|
+
const host = hostOverride || sonarConfig.host;
|
|
77
|
+
|
|
78
|
+
if (await isSonarReachable(host, sonarConfig.timeouts.healthcheckSeconds)) {
|
|
79
|
+
return { exitCode: 0, stdout: `SonarQube already reachable at ${host}, skipping container start.`, stderr: "" };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (sonarConfig.external) {
|
|
83
|
+
return {
|
|
84
|
+
exitCode: 1,
|
|
85
|
+
stdout: "",
|
|
86
|
+
stderr: `Configured external SonarQube is not reachable at ${host}.`
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Discover-before-spawn (v2.7.5): if there's already a SonarQube
|
|
91
|
+
// container running anywhere — even under a different name on a
|
|
92
|
+
// different port — reuse it instead of spinning up a second one.
|
|
93
|
+
// Avoids the user accidentally accumulating Sonar containers across
|
|
94
|
+
// projects, and matches what the port preflight check already does.
|
|
95
|
+
const { discoverRunningSonar } = await import("./discovery.js");
|
|
96
|
+
const discovered = await discoverRunningSonar({
|
|
97
|
+
healthcheckSeconds: sonarConfig.timeouts.healthcheckSeconds,
|
|
98
|
+
});
|
|
99
|
+
if (discovered.found && discovered.reachable) {
|
|
100
|
+
return {
|
|
101
|
+
exitCode: 0,
|
|
102
|
+
stdout: `Reusing existing SonarQube container "${discovered.containerName}" at ${discovered.host} (skipping container start).`,
|
|
103
|
+
stderr: "",
|
|
104
|
+
reusedHost: discovered.host,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const compose = await ensureComposeFile(config.sonarqube);
|
|
109
|
+
return runCommand("docker", ["compose", "-f", compose, "up", "-d"], { timeout: sonarConfig.timeouts.composeUpMs });
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export async function sonarDown() {
|
|
113
|
+
const { config } = await loadConfig();
|
|
114
|
+
const sonarConfig = normalizeSonarConfig(config.sonarqube);
|
|
115
|
+
if (sonarConfig.external) {
|
|
116
|
+
return { exitCode: 0, stdout: "sonarqube.external=true, skipping Docker stop.", stderr: "" };
|
|
117
|
+
}
|
|
118
|
+
const compose = await ensureComposeFile(config.sonarqube);
|
|
119
|
+
return runCommand("docker", ["compose", "-f", compose, "stop"], { timeout: sonarConfig.timeouts.composeControlMs });
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export async function sonarStatus() {
|
|
123
|
+
const { config } = await loadConfig();
|
|
124
|
+
const sonarConfig = normalizeSonarConfig(config.sonarqube);
|
|
125
|
+
const host = sonarConfig.host;
|
|
126
|
+
|
|
127
|
+
if (sonarConfig.external) {
|
|
128
|
+
if (await isSonarReachable(host, sonarConfig.timeouts.healthcheckSeconds)) {
|
|
129
|
+
return { exitCode: 0, stdout: `external SonarQube running at ${host}`, stderr: "" };
|
|
130
|
+
}
|
|
131
|
+
return { exitCode: 1, stdout: "", stderr: `external SonarQube is not reachable at ${host}` };
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const containerRes = await runCommand("docker", ["ps", "--filter", `name=${sonarConfig.containerName}`, "--format", "{{.Status}}"]);
|
|
135
|
+
if (containerRes.stdout?.trim()) return containerRes;
|
|
136
|
+
|
|
137
|
+
if (await isSonarReachable(host, sonarConfig.timeouts.healthcheckSeconds)) {
|
|
138
|
+
return { exitCode: 0, stdout: `external SonarQube running at ${host}`, stderr: "" };
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return containerRes;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export async function sonarLogs() {
|
|
145
|
+
const { config } = await loadConfig();
|
|
146
|
+
const sonarConfig = normalizeSonarConfig(config.sonarqube);
|
|
147
|
+
if (sonarConfig.external) {
|
|
148
|
+
return { exitCode: 1, stdout: "", stderr: "sonarqube.external=true, Docker logs are not available." };
|
|
149
|
+
}
|
|
150
|
+
return runCommand("docker", ["logs", "--tail", "100", sonarConfig.containerName], { timeout: sonarConfig.timeouts.logsMs });
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const MIN_MAP_COUNT = 262144;
|
|
154
|
+
|
|
155
|
+
export async function checkVmMaxMapCount(platform) {
|
|
156
|
+
if (platform === "darwin" || platform === "win32") {
|
|
157
|
+
return { ok: true, reason: "vm.max_map_count check not required on this platform" };
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const res = await runCommand("sysctl", ["vm.max_map_count"]);
|
|
161
|
+
if (res.exitCode !== 0) {
|
|
162
|
+
return {
|
|
163
|
+
ok: false,
|
|
164
|
+
reason: "Could not read vm.max_map_count",
|
|
165
|
+
fix: `sudo sysctl -w vm.max_map_count=${MIN_MAP_COUNT}`
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const match = /=\s*(\d+)/.exec(res.stdout);
|
|
170
|
+
const current = match ? Number(match[1]) : 0;
|
|
171
|
+
|
|
172
|
+
if (current >= MIN_MAP_COUNT) {
|
|
173
|
+
return { ok: true, reason: `vm.max_map_count = ${current}` };
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return {
|
|
177
|
+
ok: false,
|
|
178
|
+
reason: `vm.max_map_count = ${current} (needs >= ${MIN_MAP_COUNT})`,
|
|
179
|
+
fix: `sudo sysctl -w vm.max_map_count=${MIN_MAP_COUNT} && echo "vm.max_map_count=${MIN_MAP_COUNT}" | sudo tee -a /etc/sysctl.conf`
|
|
180
|
+
};
|
|
181
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
import { runCommand } from "../utils/process.js";
|
|
3
|
+
|
|
4
|
+
function slug(value) {
|
|
5
|
+
return String(value || "")
|
|
6
|
+
.toLowerCase()
|
|
7
|
+
.replaceAll(/[^a-z0-9._:-]+/g, "-")
|
|
8
|
+
.replaceAll(/-{2,}/g, "-")
|
|
9
|
+
.replaceAll(/(^-+)|(-+$)/g, "");
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function normalizeProjectKey(value) {
|
|
13
|
+
const out = slug(value);
|
|
14
|
+
if (!out) return "kj-default";
|
|
15
|
+
return /[a-z]/.test(out) ? out : `kj-${out}`;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function digest(input) {
|
|
19
|
+
return crypto.createHash("sha1").update(String(input)).digest("hex").slice(0, 12);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function parseScpLikeRemote(remoteUrl) {
|
|
23
|
+
// Example: git@github.com:owner/repo.git
|
|
24
|
+
const match = /^(?:[^@]+@)?([^:]+):(.+)$/.exec(String(remoteUrl || "").trim());
|
|
25
|
+
if (!match) return null;
|
|
26
|
+
return { host: match[1], path: match[2] };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function parseUrlLikeRemote(remoteUrl) {
|
|
30
|
+
try {
|
|
31
|
+
const parsed = new URL(String(remoteUrl || "").trim());
|
|
32
|
+
return { host: parsed.hostname, path: parsed.pathname.replace(/^\/+/, "") };
|
|
33
|
+
} catch { /* not a valid URL */
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function canonicalRepoId(remoteUrl) {
|
|
39
|
+
const raw = String(remoteUrl || "").trim();
|
|
40
|
+
if (!raw) return null;
|
|
41
|
+
|
|
42
|
+
const parsed = raw.includes("://") ? parseUrlLikeRemote(raw) : (parseScpLikeRemote(raw) || parseUrlLikeRemote(raw));
|
|
43
|
+
if (!parsed) return null;
|
|
44
|
+
|
|
45
|
+
const host = String(parsed.host || "").trim().toLowerCase();
|
|
46
|
+
const cleanPath = String(parsed.path || "")
|
|
47
|
+
.trim()
|
|
48
|
+
.replaceAll(/(^\/+)|(\/+$)/g, "")
|
|
49
|
+
.replace(/\.git$/i, "")
|
|
50
|
+
.toLowerCase();
|
|
51
|
+
const segments = cleanPath.split("/").filter(Boolean);
|
|
52
|
+
if (!host || segments.length < 2) return null;
|
|
53
|
+
|
|
54
|
+
// Keep full repository path (owner/subgroups/repo) to avoid collisions in nested groups.
|
|
55
|
+
return `${host}/${segments.join("/")}`;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export async function resolveSonarProjectKey(config, options = {}) {
|
|
59
|
+
const explicit = String(
|
|
60
|
+
options.projectKey || process.env.KJ_SONAR_PROJECT_KEY || config?.sonarqube?.project_key || ""
|
|
61
|
+
).trim();
|
|
62
|
+
if (explicit) {
|
|
63
|
+
return normalizeProjectKey(explicit);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const remote = await runCommand("git", ["config", "--get", "remote.origin.url"]);
|
|
67
|
+
const remoteUrl = String(remote.stdout || "").trim();
|
|
68
|
+
if (remote.exitCode !== 0 || !remoteUrl) {
|
|
69
|
+
throw new Error(
|
|
70
|
+
"Missing git remote.origin.url. Configure remote origin or set sonarqube.project_key explicitly."
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const repoId = canonicalRepoId(remoteUrl);
|
|
75
|
+
if (!repoId) {
|
|
76
|
+
throw new Error(
|
|
77
|
+
"Unable to parse git remote.origin.url. Use a valid SSH/HTTPS remote or set sonarqube.project_key explicitly."
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const repo = slug(repoId.split("/").pop());
|
|
82
|
+
return normalizeProjectKey(`kj-${repo}-${digest(repoId)}`);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Non-throwing predicate: can a Sonar project key be resolved for `config`?
|
|
87
|
+
*
|
|
88
|
+
* Used by callers (audit collector, run-loop SonarStage) that want to skip
|
|
89
|
+
* the Sonar work cleanly instead of letting `resolveSonarProjectKey` throw
|
|
90
|
+
* "Missing git remote.origin.url" deep inside the scanner. The scanner's
|
|
91
|
+
* thrown error is fine for an explicit `kj sonar` call (the user asked
|
|
92
|
+
* for it), but for implicit pipeline gates it produces a noisy "Sonar
|
|
93
|
+
* scan failed" loop in fresh /tmp/... repos.
|
|
94
|
+
*
|
|
95
|
+
* Returns true when EITHER:
|
|
96
|
+
* - an explicit `project_key` is set (env var, config, or per-call option),
|
|
97
|
+
* - OR `git config --get remote.origin.url` succeeds with a non-empty value.
|
|
98
|
+
*
|
|
99
|
+
* Side-effect-free apart from the git probe.
|
|
100
|
+
*
|
|
101
|
+
* @param {object} config
|
|
102
|
+
* @param {object} [options]
|
|
103
|
+
* @param {string} [options.projectKey]
|
|
104
|
+
* @returns {Promise<boolean>}
|
|
105
|
+
*/
|
|
106
|
+
export async function canResolveSonarProjectKey(config, options = {}) {
|
|
107
|
+
const explicit = String(
|
|
108
|
+
options.projectKey || process.env.KJ_SONAR_PROJECT_KEY || config?.sonarqube?.project_key || ""
|
|
109
|
+
).trim();
|
|
110
|
+
if (explicit) return true;
|
|
111
|
+
// try/catch (instead of `.catch(...)`) tolerates two legitimate test
|
|
112
|
+
// realities: a runCommand mock that returns undefined, and a real
|
|
113
|
+
// promise rejection from a missing git binary. Either way we treat
|
|
114
|
+
// it as "no remote available" and let the caller skip Sonar cleanly.
|
|
115
|
+
let remote;
|
|
116
|
+
try { remote = await runCommand("git", ["config", "--get", "remote.origin.url"]); }
|
|
117
|
+
catch { return false; }
|
|
118
|
+
if (!remote) return false;
|
|
119
|
+
return remote.exitCode === 0 && String(remote.stdout || "").trim().length > 0;
|
|
120
|
+
}
|