@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,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Golden tasks subprocess runner (KJC-TSK-0374). Spawns `kj run` in
|
|
3
|
+
* a sandbox dir, reads back summary.md, evaluates the schema's
|
|
4
|
+
* filesystem-dependent assertions (expected_test_files, allowed_loc_range),
|
|
5
|
+
* and merges them with `assertFromSummary` into a single result.
|
|
6
|
+
*
|
|
7
|
+
* The kj subprocess + diff calls are injected so unit tests can drive
|
|
8
|
+
* the runner without spawning anything (real e2e is opt-in via PR-3b).
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import fs from "node:fs/promises";
|
|
12
|
+
import path from "node:path";
|
|
13
|
+
import { runCommand as defaultRun } from "../utils/process.js";
|
|
14
|
+
import { parseSummary, assertFromSummary } from "./asserter.js";
|
|
15
|
+
|
|
16
|
+
async function findLatestSummary(workDir) {
|
|
17
|
+
const journalRoot = path.join(workDir, ".karajan", "sessions");
|
|
18
|
+
const sessions = await fs.readdir(journalRoot).catch(() => []);
|
|
19
|
+
if (sessions.length === 0) return null;
|
|
20
|
+
const stats = await Promise.all(sessions.map(async (id) => {
|
|
21
|
+
const file = path.join(journalRoot, id, "summary.md");
|
|
22
|
+
const stat = await fs.stat(file).catch(() => null);
|
|
23
|
+
return stat ? { file, mtimeMs: stat.mtimeMs } : null;
|
|
24
|
+
}));
|
|
25
|
+
const valid = stats.filter(Boolean).sort((a, b) => b.mtimeMs - a.mtimeMs);
|
|
26
|
+
return valid[0]?.file ?? null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async function findMissingTestFiles(workDir, paths) {
|
|
30
|
+
const checks = await Promise.all(paths.map(async (rel) =>
|
|
31
|
+
[rel, await fs.stat(path.join(workDir, rel)).then(() => true).catch(() => false)]));
|
|
32
|
+
return checks.filter(([, ok]) => !ok).map(([rel]) => rel);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async function totalLocSince(workDir, baseSha, run) {
|
|
36
|
+
const res = await run("git", ["diff", "--numstat", `${baseSha}..HEAD`], { cwd: workDir }).catch(() => null);
|
|
37
|
+
if (!res || res.exitCode !== 0) return null;
|
|
38
|
+
return String(res.stdout || "").split("\n").filter(Boolean)
|
|
39
|
+
.map((l) => l.split("\t")).filter(([a]) => a !== "-")
|
|
40
|
+
.reduce((sum, [a]) => sum + Number(a || 0), 0);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export async function runGoldenTask(task, opts = {}) {
|
|
44
|
+
const run = opts.run || defaultRun;
|
|
45
|
+
const fsApi = opts.fs || fs;
|
|
46
|
+
const workDir = opts.workDir;
|
|
47
|
+
if (!workDir) throw new Error("runGoldenTask requires opts.workDir");
|
|
48
|
+
|
|
49
|
+
const baseSha = opts.baseSha || null;
|
|
50
|
+
const kjResult = await run("kj", ["run", task.prompt, "-y"], {
|
|
51
|
+
cwd: workDir,
|
|
52
|
+
timeout: (task.timeout_minutes || 30) * 60_000,
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const summaryPath = opts.summaryPath || await findLatestSummary(workDir);
|
|
56
|
+
if (!summaryPath) {
|
|
57
|
+
return { ok: false, kjExit: kjResult?.exitCode ?? -1, failures: [{
|
|
58
|
+
kind: "no_summary", expected: "summary.md", actual: null,
|
|
59
|
+
message: "kj run finished without producing a summary.md",
|
|
60
|
+
}] };
|
|
61
|
+
}
|
|
62
|
+
const content = await fsApi.readFile(summaryPath, "utf8");
|
|
63
|
+
const parsed = parseSummary(content);
|
|
64
|
+
const summaryAssertion = assertFromSummary(task, parsed);
|
|
65
|
+
|
|
66
|
+
const failures = [...summaryAssertion.failures];
|
|
67
|
+
|
|
68
|
+
if (Array.isArray(task.expected_test_files) && task.expected_test_files.length > 0) {
|
|
69
|
+
const missing = await findMissingTestFiles(workDir, task.expected_test_files);
|
|
70
|
+
if (missing.length > 0) {
|
|
71
|
+
failures.push({ kind: "test_files_missing", expected: task.expected_test_files, actual: missing,
|
|
72
|
+
message: `expected test files not produced: ${missing.join(", ")}` });
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (baseSha) {
|
|
77
|
+
const loc = await totalLocSince(workDir, baseSha, run);
|
|
78
|
+
const [min, max] = task.allowed_loc_range;
|
|
79
|
+
if (loc !== null && (loc < min || loc > max)) {
|
|
80
|
+
failures.push({ kind: "loc_out_of_range", expected: `${min}..${max}`, actual: loc,
|
|
81
|
+
message: `LOC added (${loc}) is outside the allowed range [${min}, ${max}]` });
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
ok: failures.length === 0,
|
|
87
|
+
kjExit: kjResult?.exitCode ?? null,
|
|
88
|
+
summaryPath,
|
|
89
|
+
parsed,
|
|
90
|
+
failures,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Golden tasks regression suite — schema (KJC-TSK-0374). Pure data,
|
|
3
|
+
* no I/O. See docs/golden-tasks.md (PR-3) for the full spec.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import * as v from "valibot";
|
|
7
|
+
|
|
8
|
+
const NonEmptyString = v.pipe(v.string(), v.minLength(1));
|
|
9
|
+
const Percent = v.pipe(v.number(), v.minValue(0), v.maxValue(100));
|
|
10
|
+
|
|
11
|
+
const NonNegInt = v.pipe(v.number(), v.integer(), v.minValue(0));
|
|
12
|
+
const LocRangeSchema = v.pipe(v.array(NonNegInt), v.length(2),
|
|
13
|
+
v.check((arr) => arr[0] <= arr[1], "allowed_loc_range: min must be <= max"));
|
|
14
|
+
|
|
15
|
+
const GoldenTaskSchema = v.looseObject({
|
|
16
|
+
id: v.pipe(NonEmptyString, v.regex(/^[a-z0-9_-]+$/, "id must be lowercase a-z0-9_-")),
|
|
17
|
+
title: NonEmptyString,
|
|
18
|
+
prompt: NonEmptyString,
|
|
19
|
+
description: v.optional(v.string()),
|
|
20
|
+
timeout_minutes: v.optional(v.pipe(v.number(), v.integer(), v.minValue(1)), 30),
|
|
21
|
+
expected_commits_min: NonNegInt,
|
|
22
|
+
expected_audit_status: v.picklist(["pass", "warning", "fail"]),
|
|
23
|
+
expected_test_files: v.array(NonEmptyString),
|
|
24
|
+
allowed_loc_range: LocRangeSchema,
|
|
25
|
+
expected_plan_adherence_min: v.optional(Percent),
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
/** @typedef {import("valibot").InferOutput<typeof GoldenTaskSchema>} GoldenTask */
|
|
29
|
+
|
|
30
|
+
export function parseGoldenTask(raw) {
|
|
31
|
+
return v.parse(GoldenTaskSchema, raw);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function safeParseGoldenTask(raw) {
|
|
35
|
+
const result = v.safeParse(GoldenTaskSchema, raw);
|
|
36
|
+
if (result.success) return { ok: true, task: result.output };
|
|
37
|
+
return { ok: false, issues: result.issues.map((iss) => ({
|
|
38
|
+
path: (iss.path || []).map((p) => p.key).join("."),
|
|
39
|
+
message: iss.message,
|
|
40
|
+
})) };
|
|
41
|
+
}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { VALID_TASK_TYPES } from "./policy-resolver.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Built-in intent patterns for deterministic pre-triage classification.
|
|
5
|
+
* Each pattern maps keywords/regex to a taskType + complexity level.
|
|
6
|
+
* Evaluated top-down; first match with confidence >= threshold wins.
|
|
7
|
+
*/
|
|
8
|
+
const INTENT_PATTERNS = [
|
|
9
|
+
// No-code tasks (data analysis, document generation, SQL queries, CSV transforms)
|
|
10
|
+
// Placed before audit so specific multi-word patterns win over single-word "analizar"/"analyze"
|
|
11
|
+
{
|
|
12
|
+
id: "no-code",
|
|
13
|
+
keywords: [
|
|
14
|
+
"generate report", "create document", "analyze data", "transform csv",
|
|
15
|
+
"sql query", "sql queries", "generate queries", "data analysis", "process data",
|
|
16
|
+
"export to", "import from", "convert data", "parse file",
|
|
17
|
+
"generar informe", "crear documento", "analizar datos", "transformar csv",
|
|
18
|
+
"consulta sql", "generar consultas", "analisis de datos", "procesar datos",
|
|
19
|
+
"exportar a", "importar de", "convertir datos", "parsear fichero",
|
|
20
|
+
],
|
|
21
|
+
taskType: "no-code",
|
|
22
|
+
level: "simple",
|
|
23
|
+
confidence: 0.9,
|
|
24
|
+
message: "No-code task detected — TDD and SonarQube disabled, coder generates non-code output",
|
|
25
|
+
},
|
|
26
|
+
// Audit / analysis tasks (no code changes, read-only analysis)
|
|
27
|
+
{
|
|
28
|
+
id: "audit",
|
|
29
|
+
keywords: ["audit", "review", "analyze", "check", "verify", "inspect", "scan", "auditar", "revisar", "analizar", "comprobar", "verificar", "inspeccionar"],
|
|
30
|
+
taskType: "audit",
|
|
31
|
+
level: "simple",
|
|
32
|
+
confidence: 0.9,
|
|
33
|
+
message: "Audit/analysis task detected — skipping coder and reviewer",
|
|
34
|
+
},
|
|
35
|
+
// Documentation-only tasks
|
|
36
|
+
{
|
|
37
|
+
id: "doc-readme",
|
|
38
|
+
keywords: ["readme", "docs", "documentation", "jsdoc", "typedoc", "changelog"],
|
|
39
|
+
taskType: "doc",
|
|
40
|
+
level: "trivial",
|
|
41
|
+
confidence: 0.95,
|
|
42
|
+
message: "Documentation-only task detected",
|
|
43
|
+
},
|
|
44
|
+
// Test-only tasks
|
|
45
|
+
{
|
|
46
|
+
id: "add-tests",
|
|
47
|
+
keywords: ["add test", "write test", "missing test", "test coverage", "add spec", "write spec", "unit test", "integration test"],
|
|
48
|
+
taskType: "add-tests",
|
|
49
|
+
level: "simple",
|
|
50
|
+
confidence: 0.9,
|
|
51
|
+
message: "Test-addition task detected",
|
|
52
|
+
},
|
|
53
|
+
// Refactoring tasks
|
|
54
|
+
{
|
|
55
|
+
id: "refactor",
|
|
56
|
+
keywords: ["refactor", "rename", "extract method", "extract function", "clean up", "cleanup", "reorganize", "restructure", "simplify"],
|
|
57
|
+
taskType: "refactor",
|
|
58
|
+
level: "simple",
|
|
59
|
+
confidence: 0.85,
|
|
60
|
+
message: "Refactoring task detected",
|
|
61
|
+
},
|
|
62
|
+
// Infrastructure / DevOps tasks
|
|
63
|
+
{
|
|
64
|
+
id: "infra-devops",
|
|
65
|
+
keywords: ["ci/cd", "pipeline", "dockerfile", "docker-compose", "kubernetes", "k8s", "terraform", "deploy", "nginx", "github actions", "gitlab ci"],
|
|
66
|
+
taskType: "infra",
|
|
67
|
+
level: "simple",
|
|
68
|
+
confidence: 0.85,
|
|
69
|
+
message: "Infrastructure/DevOps task detected",
|
|
70
|
+
},
|
|
71
|
+
// Trivial fixes (typos, comments, formatting)
|
|
72
|
+
{
|
|
73
|
+
id: "trivial-fix",
|
|
74
|
+
keywords: ["typo", "fix typo", "spelling", "comment", "fix comment", "formatting", "lint", "fix lint", "whitespace"],
|
|
75
|
+
taskType: "sw",
|
|
76
|
+
level: "trivial",
|
|
77
|
+
confidence: 0.9,
|
|
78
|
+
message: "Trivial fix detected",
|
|
79
|
+
},
|
|
80
|
+
// Frontend / UI tasks (sets hasFrontend flag for impeccable role activation)
|
|
81
|
+
{
|
|
82
|
+
id: "frontend-ui",
|
|
83
|
+
keywords: ["html", "css", "ui", "landing", "component", "responsive", "accessibility", "a11y", "frontend", "design", "layout", "styling", "dark mode", "animation"],
|
|
84
|
+
taskType: "sw",
|
|
85
|
+
level: "simple",
|
|
86
|
+
confidence: 0.8,
|
|
87
|
+
message: "Frontend/UI task detected",
|
|
88
|
+
hasFrontend: true,
|
|
89
|
+
},
|
|
90
|
+
];
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Compile custom intent patterns from config.guards.intent.patterns
|
|
94
|
+
* Custom patterns are evaluated BEFORE built-in ones.
|
|
95
|
+
*/
|
|
96
|
+
export function compileIntentPatterns(configGuards) {
|
|
97
|
+
const custom = Array.isArray(configGuards?.intent?.patterns)
|
|
98
|
+
? configGuards.intent.patterns.map(p => ({
|
|
99
|
+
id: p.id || "custom-intent",
|
|
100
|
+
keywords: Array.isArray(p.keywords) ? p.keywords : [],
|
|
101
|
+
taskType: VALID_TASK_TYPES.has(p.taskType) ? p.taskType : "sw",
|
|
102
|
+
level: p.level || "simple",
|
|
103
|
+
confidence: typeof p.confidence === "number" ? p.confidence : 0.85,
|
|
104
|
+
message: p.message || "Custom intent pattern matched",
|
|
105
|
+
}))
|
|
106
|
+
: [];
|
|
107
|
+
|
|
108
|
+
return [...custom, ...INTENT_PATTERNS];
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Check if a task description matches any of the keywords.
|
|
113
|
+
* Returns true if at least one keyword (case-insensitive substring) appears in the task.
|
|
114
|
+
*/
|
|
115
|
+
function matchesKeywords(task, keywords) {
|
|
116
|
+
const lower = task.toLowerCase();
|
|
117
|
+
for (const kw of keywords) {
|
|
118
|
+
if (lower.includes(kw.toLowerCase())) {
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Classify a task description using deterministic keyword patterns.
|
|
127
|
+
*
|
|
128
|
+
* Returns:
|
|
129
|
+
* { classified: true, taskType, level, confidence, patternId, message }
|
|
130
|
+
* or { classified: false } if no pattern matches above threshold
|
|
131
|
+
*/
|
|
132
|
+
export function classifyIntent(task, config = {}) {
|
|
133
|
+
if (!task || typeof task !== "string") {
|
|
134
|
+
return { classified: false };
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const configGuards = config?.guards || {};
|
|
138
|
+
const threshold = configGuards?.intent?.confidence_threshold ?? 0.85;
|
|
139
|
+
const patterns = compileIntentPatterns(configGuards);
|
|
140
|
+
|
|
141
|
+
for (const pattern of patterns) {
|
|
142
|
+
if (!matchesKeywords(task, pattern.keywords)) continue;
|
|
143
|
+
|
|
144
|
+
if (pattern.confidence >= threshold) {
|
|
145
|
+
const result = {
|
|
146
|
+
classified: true,
|
|
147
|
+
taskType: pattern.taskType,
|
|
148
|
+
level: pattern.level,
|
|
149
|
+
confidence: pattern.confidence,
|
|
150
|
+
patternId: pattern.id,
|
|
151
|
+
message: pattern.message,
|
|
152
|
+
};
|
|
153
|
+
if (pattern.hasFrontend) result.hasFrontend = true;
|
|
154
|
+
return result;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return { classified: false };
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export { INTENT_PATTERNS };
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
// Built-in destructive patterns
|
|
2
|
+
const DESTRUCTIVE_PATTERNS = [
|
|
3
|
+
{ id: "rm-rf", pattern: /rm\s+(-[a-zA-Z]*f[a-zA-Z]*\s+|--force\s+)*-[a-zA-Z]*r/, severity: "critical", message: "Recursive file deletion detected" },
|
|
4
|
+
{ id: "drop-table", pattern: /DROP\s+(TABLE|DATABASE|SCHEMA)/i, severity: "critical", message: "SQL destructive operation detected" },
|
|
5
|
+
{ id: "git-reset-hard", pattern: /git\s+reset\s+--hard/i, severity: "critical", message: "Hard git reset detected" },
|
|
6
|
+
{ id: "git-push-force", pattern: /git\s+push\s+.*--force/i, severity: "critical", message: "Force push detected" },
|
|
7
|
+
{ id: "truncate-table", pattern: /TRUNCATE\s+TABLE/i, severity: "critical", message: "SQL truncate detected" },
|
|
8
|
+
{ id: "format-disk", pattern: /mkfs\.|fdisk|dd\s+if=/, severity: "critical", message: "Disk format operation detected" },
|
|
9
|
+
];
|
|
10
|
+
|
|
11
|
+
// Built-in credential patterns (ALL critical — secrets must NEVER be committed)
|
|
12
|
+
const CREDENTIAL_PATTERNS = [
|
|
13
|
+
{ id: "aws-key", pattern: /AKIA[0-9A-Z]{16}/, severity: "critical", message: "AWS access key exposed" },
|
|
14
|
+
{ id: "private-key", pattern: /-----BEGIN\s+(RSA\s+)?PRIVATE\s+KEY-----/, severity: "critical", message: "Private key exposed" },
|
|
15
|
+
{ id: "generic-secret", pattern: /(password|secret|token|api_key|apikey)\s*[:=]\s*["'][^"']{8,}["']/i, severity: "critical", message: "Hardcoded secret detected. Use .env file + process.env instead" },
|
|
16
|
+
{ id: "github-token", pattern: /gh[pousr]_[A-Za-z0-9_]{36,}/, severity: "critical", message: "GitHub token exposed" },
|
|
17
|
+
{ id: "npm-token", pattern: /npm_[A-Za-z0-9]{36,}/, severity: "critical", message: "npm token exposed" },
|
|
18
|
+
{ id: "openai-key", pattern: /sk-[A-Za-z0-9]{20,}/, severity: "critical", message: "OpenAI API key exposed" },
|
|
19
|
+
{ id: "anthropic-key", pattern: /sk-ant-[A-Za-z0-9_-]{20,}/, severity: "critical", message: "Anthropic API key exposed" },
|
|
20
|
+
{ id: "stripe-key", pattern: /sk_live_[A-Za-z0-9]{20,}/, severity: "critical", message: "Stripe secret key exposed" },
|
|
21
|
+
{ id: "stripe-test", pattern: /sk_test_[A-Za-z0-9]{20,}/, severity: "critical", message: "Stripe test key exposed. Use .env even for test keys" },
|
|
22
|
+
{ id: "google-api-key", pattern: /AIza[A-Za-z0-9_-]{35}/, severity: "critical", message: "Google API key exposed" },
|
|
23
|
+
{ id: "firebase-key", pattern: /"apiKey"\s*:\s*"AIza[A-Za-z0-9_-]{35}"/, severity: "critical", message: "Firebase API key hardcoded. Use .env file" },
|
|
24
|
+
{ id: "slack-token", pattern: /xox[bpors]-[A-Za-z0-9-]{10,}/, severity: "critical", message: "Slack token exposed" },
|
|
25
|
+
{ id: "jwt-secret", pattern: /jwt[_-]?secret\s*[:=]\s*["'][^"']{8,}["']/i, severity: "critical", message: "JWT secret hardcoded. Use .env file" },
|
|
26
|
+
{ id: "database-url", pattern: /(mongodb|postgres|mysql|redis):\/\/[^"'\s]+:[^"'\s]+@/i, severity: "critical", message: "Database URL with credentials exposed. Use .env file" },
|
|
27
|
+
{ id: "hardcoded-key-assignment", pattern: /(?:const|let|var)\s+\w*(?:key|secret|token|password)\w*\s*=\s*["'][A-Za-z0-9_-]{16,}["']/i, severity: "critical", message: "Hardcoded key in variable. Use process.env or .env file" },
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
// Default protected files (block if these appear in added/modified lines)
|
|
31
|
+
const DEFAULT_PROTECTED_FILES = [
|
|
32
|
+
".env",
|
|
33
|
+
".env.local",
|
|
34
|
+
".env.production",
|
|
35
|
+
"serviceAccountKey.json",
|
|
36
|
+
"credentials.json",
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
export function compilePatterns(configGuards) {
|
|
40
|
+
const customPatterns = Array.isArray(configGuards?.output?.patterns)
|
|
41
|
+
? configGuards.output.patterns.map(p => ({
|
|
42
|
+
id: p.id || "custom",
|
|
43
|
+
pattern: typeof p.pattern === "string" ? new RegExp(p.pattern, p.flags || "") : p.pattern,
|
|
44
|
+
severity: p.severity || "warning",
|
|
45
|
+
message: p.message || "Custom pattern matched",
|
|
46
|
+
}))
|
|
47
|
+
: [];
|
|
48
|
+
|
|
49
|
+
return [...DESTRUCTIVE_PATTERNS, ...CREDENTIAL_PATTERNS, ...customPatterns];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function compileProtectedFiles(configGuards) {
|
|
53
|
+
const custom = Array.isArray(configGuards?.output?.protected_files)
|
|
54
|
+
? configGuards.output.protected_files
|
|
55
|
+
: [];
|
|
56
|
+
return [...new Set([...DEFAULT_PROTECTED_FILES, ...custom])];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Parse a unified diff to extract only added lines (lines starting with +, not ++)
|
|
61
|
+
*/
|
|
62
|
+
export function extractAddedLines(diff) {
|
|
63
|
+
if (!diff) return [];
|
|
64
|
+
const results = [];
|
|
65
|
+
let currentFile = null;
|
|
66
|
+
let lineNum = 0;
|
|
67
|
+
|
|
68
|
+
for (const line of diff.split("\n")) {
|
|
69
|
+
if (line.startsWith("+++ b/")) {
|
|
70
|
+
currentFile = line.slice(6);
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
if (line.startsWith("@@ ")) {
|
|
74
|
+
const match = /@@ -\d+(?:,\d+)? \+(\d+)/.exec(line);
|
|
75
|
+
lineNum = match ? Number.parseInt(match[1], 10) - 1 : 0;
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (line.startsWith("+") && !line.startsWith("+++")) {
|
|
79
|
+
lineNum += 1;
|
|
80
|
+
results.push({ file: currentFile, line: lineNum, content: line.slice(1) });
|
|
81
|
+
} else if (!line.startsWith("-")) {
|
|
82
|
+
lineNum += 1;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return results;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Check if any modified files are in the protected list
|
|
90
|
+
*/
|
|
91
|
+
export function checkProtectedFiles(diff, protectedFiles) {
|
|
92
|
+
const violations = [];
|
|
93
|
+
const modifiedFiles = [];
|
|
94
|
+
|
|
95
|
+
for (const line of diff.split("\n")) {
|
|
96
|
+
if (line.startsWith("+++ b/")) {
|
|
97
|
+
modifiedFiles.push(line.slice(6));
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
for (const file of modifiedFiles) {
|
|
102
|
+
const basename = file.split("/").pop();
|
|
103
|
+
if (protectedFiles.some(pf => file === pf || file.endsWith(`/${pf}`) || basename === pf)) {
|
|
104
|
+
violations.push({
|
|
105
|
+
id: "protected-file",
|
|
106
|
+
severity: "critical",
|
|
107
|
+
file,
|
|
108
|
+
line: 0,
|
|
109
|
+
message: `Protected file modified: ${file}`,
|
|
110
|
+
matchedContent: "",
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return violations;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Scan a diff for pattern violations.
|
|
120
|
+
* Returns { pass: boolean, violations: Array<{id, severity, file, line, message, matchedContent}> }
|
|
121
|
+
*/
|
|
122
|
+
export function scanDiff(diff, config = {}) {
|
|
123
|
+
if (!diff || typeof diff !== "string") {
|
|
124
|
+
return { pass: true, violations: [] };
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const configGuards = config?.guards || {};
|
|
128
|
+
const patterns = compilePatterns(configGuards);
|
|
129
|
+
const protectedFiles = compileProtectedFiles(configGuards);
|
|
130
|
+
const addedLines = extractAddedLines(diff);
|
|
131
|
+
const violations = [];
|
|
132
|
+
|
|
133
|
+
// Check patterns against added lines
|
|
134
|
+
for (const { file, line, content } of addedLines) {
|
|
135
|
+
for (const { id, pattern, severity, message } of patterns) {
|
|
136
|
+
if (pattern.test(content)) {
|
|
137
|
+
violations.push({ id, severity, file, line, message, matchedContent: content.trim().slice(0, 200) });
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Check protected files
|
|
143
|
+
violations.push(...checkProtectedFiles(diff, protectedFiles));
|
|
144
|
+
|
|
145
|
+
const hasCritical = violations.some(v => v.severity === "critical");
|
|
146
|
+
return { pass: !hasCritical, violations };
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export { DESTRUCTIVE_PATTERNS, CREDENTIAL_PATTERNS, DEFAULT_PROTECTED_FILES };
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
const FRONTEND_EXTENSIONS = new Set([".html", ".htm", ".css", ".jsx", ".tsx", ".astro", ".vue", ".svelte"]);
|
|
2
|
+
|
|
3
|
+
// Built-in perf anti-patterns (applied to added lines in frontend files)
|
|
4
|
+
const PERF_PATTERNS = [
|
|
5
|
+
{ id: "img-no-dimensions", pattern: /<img\b(?![^>]*\bwidth\b)(?![^>]*\bheight\b)[^>]*>/i, severity: "warning", message: "Image without width/height attributes (causes CLS)" },
|
|
6
|
+
{ id: "img-no-lazy", pattern: /<img\b(?![^>]*\bloading\s*=)(?![^>]*\bfetchpriority\s*=)[^>]*>/i, severity: "info", message: "Image without loading=\"lazy\" or fetchpriority (consider lazy loading)" },
|
|
7
|
+
{ id: "script-no-defer", pattern: /<script\b(?![^>]*\b(?:defer|async)\b)(?![^>]*type\s*=\s*["']module["'])[^>]*src\s*=/i, severity: "warning", message: "External script without defer/async (render-blocking)" },
|
|
8
|
+
{ id: "font-no-display", pattern: /@font-face\s*\{(?![^}]*font-display)/i, severity: "warning", message: "@font-face without font-display (causes FOIT)" },
|
|
9
|
+
{ id: "css-import", pattern: /@import\s+(?:url\()?["'](?!.*\.module\.)/i, severity: "info", message: "CSS @import (causes sequential loading, prefer <link>)" },
|
|
10
|
+
{ id: "inline-style-large", pattern: /style\s*=\s*["'][^"']{200,}["']/i, severity: "warning", message: "Large inline style (>200 chars, consider external CSS)" },
|
|
11
|
+
{ id: "document-write", pattern: /document\.write\s*\(/, severity: "warning", message: "document.write() blocks parsing and degrades performance" },
|
|
12
|
+
];
|
|
13
|
+
|
|
14
|
+
// Patterns for package.json changes (heavy dependencies added)
|
|
15
|
+
const HEAVY_DEPS = [
|
|
16
|
+
{ id: "heavy-moment", pattern: /"moment"/, severity: "info", message: "moment.js added (consider dayjs or date-fns for smaller bundle)" },
|
|
17
|
+
{ id: "heavy-lodash", pattern: /"lodash"(?!\/)/, severity: "info", message: "Full lodash added (consider lodash-es or individual imports)" },
|
|
18
|
+
{ id: "heavy-jquery", pattern: /"jquery"/, severity: "info", message: "jQuery added (consider native DOM APIs)" },
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
function getExtension(filePath) {
|
|
22
|
+
if (!filePath) return "";
|
|
23
|
+
const dot = filePath.lastIndexOf(".");
|
|
24
|
+
return dot >= 0 ? filePath.slice(dot).toLowerCase() : "";
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Check if any modified file in the diff is a frontend file
|
|
29
|
+
*/
|
|
30
|
+
export function hasFrontendFiles(diff) {
|
|
31
|
+
if (!diff) return false;
|
|
32
|
+
for (const line of diff.split("\n")) {
|
|
33
|
+
if (line.startsWith("+++ b/")) {
|
|
34
|
+
const ext = getExtension(line.slice(6));
|
|
35
|
+
if (FRONTEND_EXTENSIONS.has(ext)) return true;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Extract added lines grouped by file from a unified diff
|
|
43
|
+
*/
|
|
44
|
+
function extractAddedLinesByFile(diff) {
|
|
45
|
+
const results = [];
|
|
46
|
+
let currentFile = null;
|
|
47
|
+
let lineNum = 0;
|
|
48
|
+
|
|
49
|
+
for (const line of diff.split("\n")) {
|
|
50
|
+
if (line.startsWith("+++ b/")) {
|
|
51
|
+
currentFile = line.slice(6);
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
if (line.startsWith("@@ ")) {
|
|
55
|
+
const match = /@@ -\d+(?:,\d+)? \+(\d+)/.exec(line);
|
|
56
|
+
lineNum = match ? Number.parseInt(match[1], 10) - 1 : 0;
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if (line.startsWith("+") && !line.startsWith("+++")) {
|
|
60
|
+
lineNum += 1;
|
|
61
|
+
results.push({ file: currentFile, line: lineNum, content: line.slice(1) });
|
|
62
|
+
} else if (!line.startsWith("-")) {
|
|
63
|
+
lineNum += 1;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return results;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Scan diff for frontend performance anti-patterns.
|
|
71
|
+
* Returns { pass: boolean, violations: [...], skipped: boolean }
|
|
72
|
+
*/
|
|
73
|
+
export function scanPerfDiff(diff, config = {}) {
|
|
74
|
+
if (!diff || typeof diff !== "string") {
|
|
75
|
+
return { pass: true, violations: [], skipped: true };
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (!hasFrontendFiles(diff)) {
|
|
79
|
+
return { pass: true, violations: [], skipped: true };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const customPatterns = Array.isArray(config?.guards?.perf?.patterns)
|
|
83
|
+
? config.guards.perf.patterns.map(p => ({
|
|
84
|
+
id: p.id || "custom-perf",
|
|
85
|
+
pattern: typeof p.pattern === "string" ? new RegExp(p.pattern, p.flags || "i") : p.pattern,
|
|
86
|
+
severity: p.severity || "warning",
|
|
87
|
+
message: p.message || "Custom perf pattern matched",
|
|
88
|
+
}))
|
|
89
|
+
: [];
|
|
90
|
+
|
|
91
|
+
const allPatterns = [...PERF_PATTERNS, ...customPatterns];
|
|
92
|
+
const addedLines = extractAddedLinesByFile(diff);
|
|
93
|
+
const violations = [];
|
|
94
|
+
|
|
95
|
+
for (const { file, line, content } of addedLines) {
|
|
96
|
+
const ext = getExtension(file);
|
|
97
|
+
const isFrontend = FRONTEND_EXTENSIONS.has(ext);
|
|
98
|
+
const isPackageJson = file?.endsWith("package.json");
|
|
99
|
+
|
|
100
|
+
if (isFrontend) {
|
|
101
|
+
for (const { id, pattern, severity, message } of allPatterns) {
|
|
102
|
+
if (pattern.test(content)) {
|
|
103
|
+
violations.push({ id, severity, file, line, message, matchedContent: content.trim().slice(0, 200) });
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (isPackageJson) {
|
|
109
|
+
for (const { id, pattern, severity, message } of HEAVY_DEPS) {
|
|
110
|
+
if (pattern.test(content)) {
|
|
111
|
+
violations.push({ id, severity, file, line, message, matchedContent: content.trim().slice(0, 200) });
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// perf-guard is advisory by default — only blocks on critical (none built-in are critical)
|
|
118
|
+
const blockOnWarning = Boolean(config?.guards?.perf?.block_on_warning);
|
|
119
|
+
const hasCritical = violations.some(v => v.severity === "critical");
|
|
120
|
+
const hasWarning = violations.some(v => v.severity === "warning");
|
|
121
|
+
const pass = !hasCritical && !(blockOnWarning && hasWarning);
|
|
122
|
+
|
|
123
|
+
return { pass, violations, skipped: false };
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export { PERF_PATTERNS, HEAVY_DEPS, FRONTEND_EXTENSIONS };
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Policy guard for kj_resume answers.
|
|
3
|
+
*
|
|
4
|
+
* Detects host-AI attempts to bypass pipeline policies (skip TDD, ignore
|
|
5
|
+
* reviewer, disable security, etc.) and rejects them with context-aware
|
|
6
|
+
* suggestions for valid alternatives.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const BYPASS_PATTERNS = [
|
|
10
|
+
{ regex: /\b(?:skip|omit|drop)\s+(?:the\s+)?(?:tests?|tdd|testing)\b/i, policy: "tdd" },
|
|
11
|
+
{ regex: /\bdisable\s+(?:the\s+)?(?:tests?|tdd|testing)\b/i, policy: "tdd" },
|
|
12
|
+
{ regex: /\b(?:don'?t|do\s+not|no\s+need\s+(?:for|to))\s+(?:run\s+)?tests?\b/i, policy: "tdd" },
|
|
13
|
+
{ regex: /\bcontinue\s+without\s+test/i, policy: "tdd" },
|
|
14
|
+
{ regex: /\bswitch\s+(?:to\s+)?(?:standard\s+)?methodology/i, policy: "tdd" },
|
|
15
|
+
{ regex: /\bswitch\s+methodology/i, policy: "tdd" },
|
|
16
|
+
{ regex: /\b(?:skip|ignore|bypass|disable)\s+(?:the\s+)?(?:review(?:er)?|code\s+review)\b/i, policy: "reviewer" },
|
|
17
|
+
{ regex: /\b(?:approve|pass)\s+without\s+review/i, policy: "reviewer" },
|
|
18
|
+
{ regex: /\bmark\s+as\s+approved\b/i, policy: "reviewer" },
|
|
19
|
+
{ regex: /\bjust\s+ship\s+it/i, policy: "reviewer" },
|
|
20
|
+
{ regex: /\bignore\s+(?:the\s+)?(?:review(?:er)?\s+)?feedback\b/i, policy: "reviewer" },
|
|
21
|
+
{ regex: /\b(?:skip|ignore|bypass|disable)\s+(?:the\s+)?(?:sonar|sonarqube|quality\s+gate)/i, policy: "sonar" },
|
|
22
|
+
{ regex: /\bignore\s+sonar\s+issues?\b/i, policy: "sonar" },
|
|
23
|
+
{ regex: /\b(?:skip|ignore|bypass|disable)\s+(?:the\s+)?security(?:\s+checks?)?\b/i, policy: "security" },
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
const SUGGESTIONS_BY_POLICY = {
|
|
27
|
+
tdd: [
|
|
28
|
+
"Provide specific guidance for the coder on how to fix the failing tests",
|
|
29
|
+
"Describe the expected behavior so the coder can write correct tests",
|
|
30
|
+
"Suggest a different approach to implement the feature that is easier to test",
|
|
31
|
+
],
|
|
32
|
+
reviewer: [
|
|
33
|
+
"Provide technical guidance to address the reviewer's feedback",
|
|
34
|
+
"Explain why the current approach is correct if you disagree with the review",
|
|
35
|
+
"Suggest alternative implementations that satisfy the reviewer's concerns",
|
|
36
|
+
],
|
|
37
|
+
sonar: [
|
|
38
|
+
"Provide guidance on how to resolve the SonarQube issues",
|
|
39
|
+
"Explain the code changes needed to satisfy quality gate requirements",
|
|
40
|
+
],
|
|
41
|
+
security: [
|
|
42
|
+
"Provide guidance on how to fix the security issues found",
|
|
43
|
+
"Explain the secure alternative for the flagged pattern",
|
|
44
|
+
],
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const CONTEXT_SUGGESTIONS = {
|
|
48
|
+
reviewer_fail_fast: [
|
|
49
|
+
"Provide specific technical guidance for the coder to address the reviewer's feedback",
|
|
50
|
+
"Suggest a different approach that resolves the reviewer's concerns",
|
|
51
|
+
],
|
|
52
|
+
max_iterations: [
|
|
53
|
+
"Provide focused guidance to help the coder converge on a solution",
|
|
54
|
+
"Narrow the scope: specify exactly which file/function to change and how",
|
|
55
|
+
"Continue with additional iterations by choosing option 1 or 2",
|
|
56
|
+
],
|
|
57
|
+
standby_exhausted: [
|
|
58
|
+
"Wait and retry — the provider may be temporarily overloaded",
|
|
59
|
+
"Continue to resume from where the pipeline left off",
|
|
60
|
+
],
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Validate a resume answer against pipeline policies.
|
|
65
|
+
*
|
|
66
|
+
* @param {string|null} answer - The resume answer from the host
|
|
67
|
+
* @param {string} [pauseContext] - The context of the pause (e.g. "reviewer_fail_fast")
|
|
68
|
+
* @returns {{ valid: boolean, reason?: string, suggestions?: string[] }}
|
|
69
|
+
*/
|
|
70
|
+
export function validatePolicyCompliance(answer, pauseContext) {
|
|
71
|
+
if (answer == null || answer === "") return { valid: true };
|
|
72
|
+
if (typeof answer !== "string") return { valid: true };
|
|
73
|
+
|
|
74
|
+
const text = answer.trim();
|
|
75
|
+
for (const { regex, policy } of BYPASS_PATTERNS) {
|
|
76
|
+
if (regex.test(text)) {
|
|
77
|
+
const suggestions = [
|
|
78
|
+
...(CONTEXT_SUGGESTIONS[pauseContext] || []),
|
|
79
|
+
...(SUGGESTIONS_BY_POLICY[policy] || []),
|
|
80
|
+
];
|
|
81
|
+
return {
|
|
82
|
+
valid: false,
|
|
83
|
+
reason: `Pipeline policy "${policy}" cannot be bypassed. Provide technical guidance instead.`,
|
|
84
|
+
suggestions: [...new Set(suggestions)],
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return { valid: true };
|
|
90
|
+
}
|