@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,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config-file templates for `kj harden` (KJC-TSK-0556).
|
|
3
|
+
*
|
|
4
|
+
* Each entry is seeded only when absent (project rule: never overwrite an
|
|
5
|
+
* existing file); on re-run a kj:managed block is refreshed in place. JSON
|
|
6
|
+
* formats carry no comment syntax, so they are seed-only (no marker).
|
|
7
|
+
*
|
|
8
|
+
* The eslint ES2025 deprecated-API blacklist lands in a follow-up slice.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
export const EDITORCONFIG_BODY = [
|
|
12
|
+
"root = true",
|
|
13
|
+
"",
|
|
14
|
+
"[*]",
|
|
15
|
+
"charset = utf-8",
|
|
16
|
+
"end_of_line = lf",
|
|
17
|
+
"insert_final_newline = true",
|
|
18
|
+
"trim_trailing_whitespace = true",
|
|
19
|
+
"indent_style = space",
|
|
20
|
+
"indent_size = 2",
|
|
21
|
+
].join("\n");
|
|
22
|
+
|
|
23
|
+
export const PRETTIER_BODY = JSON.stringify(
|
|
24
|
+
{ printWidth: 110, singleQuote: false, trailingComma: "es5", semi: true },
|
|
25
|
+
null,
|
|
26
|
+
2
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
export const COMMITLINT_BODY = [
|
|
30
|
+
"// Conventional Commits — header <=100 chars, lowercase subject.",
|
|
31
|
+
"export default {",
|
|
32
|
+
' extends: ["@commitlint/config-conventional"],',
|
|
33
|
+
" rules: {",
|
|
34
|
+
' "header-max-length": [2, "always", 100],',
|
|
35
|
+
' "subject-case": [2, "never", ["sentence-case", "start-case", "pascal-case", "upper-case"]],',
|
|
36
|
+
" },",
|
|
37
|
+
"};",
|
|
38
|
+
].join("\n");
|
|
39
|
+
|
|
40
|
+
// Self-contained flat config (no plugin deps) banning APIs deprecated under
|
|
41
|
+
// an ES2025 target — mirrors the Karajan standard. Seeded only when the
|
|
42
|
+
// project has no eslint config of its own.
|
|
43
|
+
export const ESLINT_BODY = [
|
|
44
|
+
"export default [",
|
|
45
|
+
" {",
|
|
46
|
+
' files: ["**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"],',
|
|
47
|
+
' languageOptions: { ecmaVersion: 2025, sourceType: "module" },',
|
|
48
|
+
" rules: {",
|
|
49
|
+
' "no-var": "error",',
|
|
50
|
+
' "no-eval": "error",',
|
|
51
|
+
' "no-new-func": "error",',
|
|
52
|
+
' "no-restricted-globals": [',
|
|
53
|
+
' "error",',
|
|
54
|
+
' { name: "alert", message: "Use the app modal, not alert()." },',
|
|
55
|
+
' { name: "confirm", message: "Use the app modal, not confirm()." },',
|
|
56
|
+
' { name: "prompt", message: "Use the app modal, not prompt()." },',
|
|
57
|
+
' { name: "escape", message: "Use encodeURIComponent()." },',
|
|
58
|
+
' { name: "unescape", message: "Use decodeURIComponent()." },',
|
|
59
|
+
' { name: "event", message: "Use the handler parameter, not window.event." },',
|
|
60
|
+
" ],",
|
|
61
|
+
' "no-restricted-properties": [',
|
|
62
|
+
' "error",',
|
|
63
|
+
' { object: "document", property: "write", message: "Use DOM nodes / Blob URLs, not document.write." },',
|
|
64
|
+
' { object: "document", property: "writeln", message: "Use DOM nodes, not document.writeln." },',
|
|
65
|
+
' { property: "substr", message: "Use slice() or substring(), not substr()." },',
|
|
66
|
+
" ],",
|
|
67
|
+
" },",
|
|
68
|
+
" },",
|
|
69
|
+
"];",
|
|
70
|
+
].join("\n");
|
|
71
|
+
|
|
72
|
+
// Ruff covers lint + format for Python; `UP` (pyupgrade) is the analogue of
|
|
73
|
+
// the ES2025 deprecated-API ban — it rewrites legacy idioms to modern Python.
|
|
74
|
+
export const RUFF_BODY = [
|
|
75
|
+
"line-length = 110",
|
|
76
|
+
'target-version = "py312"',
|
|
77
|
+
"",
|
|
78
|
+
"[lint]",
|
|
79
|
+
'select = ["E", "F", "I", "UP", "B", "SIM"]',
|
|
80
|
+
].join("\n");
|
|
81
|
+
|
|
82
|
+
export const GOLANGCI_BODY = [
|
|
83
|
+
"linters:",
|
|
84
|
+
" enable:",
|
|
85
|
+
" - govet",
|
|
86
|
+
" - staticcheck",
|
|
87
|
+
" - revive",
|
|
88
|
+
" - ineffassign",
|
|
89
|
+
" - gofmt",
|
|
90
|
+
].join("\n");
|
|
91
|
+
|
|
92
|
+
/** Language-agnostic configs (every stack gets these). */
|
|
93
|
+
export const UNIVERSAL_CONFIGS = [
|
|
94
|
+
{ file: ".editorconfig", blockId: "editorconfig", style: "hash", body: EDITORCONFIG_BODY },
|
|
95
|
+
{ file: "commitlint.config.js", blockId: "commitlint", style: "slash", body: COMMITLINT_BODY },
|
|
96
|
+
];
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* `json:true` ⇒ seed-only (no comment syntax for a marker). `requires` names
|
|
100
|
+
* the tool the config is for: absent from the project ⇒ the config is omitted
|
|
101
|
+
* with the install command in the report (KJC-BUG-0137) — a config without its
|
|
102
|
+
* tool is decorative, and kj never generates a demand it didn't satisfy.
|
|
103
|
+
*/
|
|
104
|
+
export const JS_CONFIGS = [
|
|
105
|
+
{ file: "eslint.config.js", blockId: "eslint", style: "slash", body: ESLINT_BODY, requires: "eslint" },
|
|
106
|
+
{ file: ".prettierrc.json", json: true, body: PRETTIER_BODY, requires: "prettier" },
|
|
107
|
+
];
|
|
108
|
+
export const PY_CONFIGS = [{ file: "ruff.toml", blockId: "ruff", style: "hash", body: RUFF_BODY }];
|
|
109
|
+
export const GO_CONFIGS = [{ file: ".golangci.yml", blockId: "golangci", style: "hash", body: GOLANGCI_BODY }];
|
|
110
|
+
|
|
111
|
+
// PHPStan static analysis — the PHP analogue of ruff/golangci.
|
|
112
|
+
export const PHPSTAN_BODY = ["parameters:", " level: 6", " paths:", " - src", " - tests"].join("\n");
|
|
113
|
+
export const PHP_CONFIGS = [{ file: "phpstan.neon", blockId: "phpstan", style: "hash", body: PHPSTAN_BODY }];
|
|
114
|
+
|
|
115
|
+
/** Lint/format configs by detected language. Unknown ⇒ universal only. */
|
|
116
|
+
export const CONFIGS_BY_LANGUAGE = {
|
|
117
|
+
javascript: JS_CONFIGS,
|
|
118
|
+
typescript: JS_CONFIGS,
|
|
119
|
+
python: PY_CONFIGS,
|
|
120
|
+
go: GO_CONFIGS,
|
|
121
|
+
php: PHP_CONFIGS,
|
|
122
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* guidelines-engine — seeds AI-agent guideline files for `kj harden`
|
|
3
|
+
* (KJC-TSK-0559), absorbing dev-hooks' generate_guidelines without an external
|
|
4
|
+
* MCP. Writes a kj:managed block into AGENTS.md and CLAUDE.md, preserving any
|
|
5
|
+
* content the user keeps outside the markers. Idempotent.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
9
|
+
import { join } from "node:path";
|
|
10
|
+
|
|
11
|
+
import { upsertManagedBlock } from "../utils/managed-markers.js";
|
|
12
|
+
import { GUIDELINES_BODY } from "./guidelines-templates.js";
|
|
13
|
+
|
|
14
|
+
const BLOCK_VERSION = 1;
|
|
15
|
+
const TARGETS = ["AGENTS.md", "CLAUDE.md"];
|
|
16
|
+
const DH_START = "<!-- @manufosela/dev-git-hooks:start -->";
|
|
17
|
+
const DH_END = "<!-- @manufosela/dev-git-hooks:end -->";
|
|
18
|
+
|
|
19
|
+
/** Remove a legacy dev-hooks managed block, preserving everything else. */
|
|
20
|
+
export function stripDevHooksBlock(source) {
|
|
21
|
+
const s = source.indexOf(DH_START);
|
|
22
|
+
if (s === -1) return { content: source, migrated: false };
|
|
23
|
+
const e = source.indexOf(DH_END, s);
|
|
24
|
+
if (e === -1) return { content: source, migrated: false };
|
|
25
|
+
const before = source.slice(0, s).replace(/\n+$/, "");
|
|
26
|
+
const after = source.slice(e + DH_END.length).replace(/^\n+/, "");
|
|
27
|
+
const joiner = before && after ? "\n\n" : "";
|
|
28
|
+
return { content: `${before}${joiner}${after}`, migrated: true };
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function installGuidelines({ projectDir = process.cwd(), dryRun = false } = {}) {
|
|
32
|
+
const results = [];
|
|
33
|
+
for (const file of TARGETS) {
|
|
34
|
+
const target = join(projectDir, file);
|
|
35
|
+
const raw = existsSync(target) ? readFileSync(target, "utf8") : "";
|
|
36
|
+
const { content: source, migrated } = stripDevHooksBlock(raw);
|
|
37
|
+
const { content, action } = upsertManagedBlock({
|
|
38
|
+
source,
|
|
39
|
+
blockId: "guidelines",
|
|
40
|
+
version: BLOCK_VERSION,
|
|
41
|
+
body: GUIDELINES_BODY,
|
|
42
|
+
style: "html",
|
|
43
|
+
});
|
|
44
|
+
if (!dryRun && (migrated || action !== "unchanged")) writeFileSync(target, content);
|
|
45
|
+
results.push({ file, action: migrated ? "migrated" : action });
|
|
46
|
+
}
|
|
47
|
+
return { dryRun, guidelines: results };
|
|
48
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Distilled AI-agent guidelines for `kj harden` (KJC-TSK-0559).
|
|
3
|
+
*
|
|
4
|
+
* A compact, high-signal rule set seeded into AGENTS.md / CLAUDE.md inside a
|
|
5
|
+
* kj:managed block, so it preserves whatever the user wrote outside it. Kept
|
|
6
|
+
* deliberately short — these rules enter the agent's context on every run, so
|
|
7
|
+
* bloat dilutes the signal. Distilled from the dev-toolkit guidelines.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export const GUIDELINES_BODY = [
|
|
11
|
+
"# Project guidelines (kj harden)",
|
|
12
|
+
"",
|
|
13
|
+
"## Code",
|
|
14
|
+
"- SOLID, DRY, KISS, YAGNI. `const` by default; arrow callbacks; template literals.",
|
|
15
|
+
"- ES2025 target: never `var`, `document.write`, `alert`/`confirm`/`prompt`, `escape`/`unescape`, `substr`.",
|
|
16
|
+
" Prefer modern APIs (`structuredClone`, `Object.groupBy`, `Array.at`/`findLast`/`toSorted`, optional chaining, `??`).",
|
|
17
|
+
"- ES modules (`import`/`export`), never `require` in new code. Names in English, descriptive.",
|
|
18
|
+
"- No silent fallbacks: the system works or fails loudly. Validate and sanitize all input.",
|
|
19
|
+
"",
|
|
20
|
+
"## Commits & PRs",
|
|
21
|
+
"- Conventional Commits (`feat:`/`fix:`/`refactor:`/`docs:`/`test:`/`chore:`). Header <=100 chars, lowercase subject.",
|
|
22
|
+
'- Never attribute commits or PRs to AI (no `Co-Authored-By`, no "generated by").',
|
|
23
|
+
"- Atomic PRs: one purpose, small (~150 LOC). Each PR compiles and passes its tests on its own.",
|
|
24
|
+
"",
|
|
25
|
+
"## Testing",
|
|
26
|
+
"- Test-first. Run the tests after each meaningful change. Never skip tests.",
|
|
27
|
+
"",
|
|
28
|
+
"## Security",
|
|
29
|
+
"- Never commit secrets, keys or tokens. Parameterized queries; sanitize output against XSS.",
|
|
30
|
+
"",
|
|
31
|
+
"## UI/UX",
|
|
32
|
+
"- No native `alert`/`confirm`/`prompt` — use the app's modal system. Loading states; accessible; mobile-first.",
|
|
33
|
+
"",
|
|
34
|
+
"## Files",
|
|
35
|
+
"- Edit existing files in place; never overwrite a whole file to make a small change.",
|
|
36
|
+
].join("\n");
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* harden-engine — installs kj-managed git hooks idempotently (KJC-TSK-0555).
|
|
3
|
+
*
|
|
4
|
+
* Hooks live under `.karajan/hooks/` and are activated via `core.hooksPath`,
|
|
5
|
+
* so harden never fights husky/simple-git-hooks nor touches `.git/hooks/`.
|
|
6
|
+
* Each hook is a shebang + a kj:managed block; re-running is a no-op and any
|
|
7
|
+
* content outside the block is preserved.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
11
|
+
import { join } from "node:path";
|
|
12
|
+
|
|
13
|
+
import { upsertManagedBlock } from "../utils/managed-markers.js";
|
|
14
|
+
import { runCommand } from "../utils/process.js";
|
|
15
|
+
import { hookBody, PROFILE_HOOKS, SHEBANG } from "./hook-templates.js";
|
|
16
|
+
|
|
17
|
+
const BLOCK_VERSION = 1;
|
|
18
|
+
const HOOKS_DIR = join(".karajan", "hooks");
|
|
19
|
+
const HOOK_PREAMBLE = `${SHEBANG}\nset -e\n`;
|
|
20
|
+
|
|
21
|
+
export function isGitRepo(projectDir) {
|
|
22
|
+
return existsSync(join(projectDir, ".git"));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Install (or refresh) the profile's hooks under `.karajan/hooks/` and point
|
|
27
|
+
* `core.hooksPath` there. Idempotent. `dryRun` computes actions without
|
|
28
|
+
* touching disk or git config. `cmds` supplies stack-aware lint/format/test
|
|
29
|
+
* commands (npm-script defaults). Returns a per-hook action report.
|
|
30
|
+
*/
|
|
31
|
+
export async function installHooks({
|
|
32
|
+
projectDir = process.cwd(),
|
|
33
|
+
profile = "standard",
|
|
34
|
+
cmds = {},
|
|
35
|
+
dryRun = false,
|
|
36
|
+
baseBranch = null,
|
|
37
|
+
} = {}) {
|
|
38
|
+
if (!isGitRepo(projectDir)) throw new Error(`Not a git repository: ${projectDir}`);
|
|
39
|
+
const hooks = PROFILE_HOOKS[profile];
|
|
40
|
+
if (!hooks) throw new Error(`Unknown harden profile: ${profile}`);
|
|
41
|
+
|
|
42
|
+
// KJC-TSK-0645: setting a repo-local hooksPath ECLIPSES the machine's
|
|
43
|
+
// global hooks dir — personal guards (AI-attribution commit-msg, protected
|
|
44
|
+
// branch pre-push) would silently stop applying here. Detect the previous
|
|
45
|
+
// global dir and have every generated hook chain to it. `~` is emitted as
|
|
46
|
+
// `$HOME` so the committed hook stays portable across machines (the -x
|
|
47
|
+
// guard silences it where the dir doesn't exist).
|
|
48
|
+
let globalHooksDir = null;
|
|
49
|
+
const globalCfg = await runCommand("git", ["config", "--global", "core.hooksPath"], { cwd: projectDir });
|
|
50
|
+
const rawGlobal = globalCfg.exitCode === 0 ? globalCfg.stdout.trim() : "";
|
|
51
|
+
if (rawGlobal && rawGlobal !== HOOKS_DIR) {
|
|
52
|
+
globalHooksDir = rawGlobal.startsWith("~") ? `$HOME${rawGlobal.slice(1)}` : rawGlobal;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const absHooksDir = join(projectDir, HOOKS_DIR);
|
|
56
|
+
const results = [];
|
|
57
|
+
for (const hook of hooks) {
|
|
58
|
+
const target = join(absHooksDir, hook);
|
|
59
|
+
const source = existsSync(target) ? readFileSync(target, "utf8") : HOOK_PREAMBLE;
|
|
60
|
+
const { content, action } = upsertManagedBlock({
|
|
61
|
+
source,
|
|
62
|
+
blockId: `hook:${hook}`,
|
|
63
|
+
version: BLOCK_VERSION,
|
|
64
|
+
body: hookBody(hook, cmds, { globalHooksDir, baseBranch }),
|
|
65
|
+
style: "hash",
|
|
66
|
+
});
|
|
67
|
+
results.push({ hook, target, action });
|
|
68
|
+
if (!dryRun && action !== "unchanged") {
|
|
69
|
+
mkdirSync(absHooksDir, { recursive: true });
|
|
70
|
+
writeFileSync(target, content);
|
|
71
|
+
chmodSync(target, 0o755);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (!dryRun) {
|
|
76
|
+
await runCommand("git", ["config", "core.hooksPath", HOOKS_DIR], { cwd: projectDir });
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return { profile, hooksPath: HOOKS_DIR, dryRun, hooks: results };
|
|
80
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* harness-hooks — the TOOL gate (KJC-TSK-0710, from proposal KJC-PRP-0013).
|
|
3
|
+
* Field case 2026-08-02: text rules were not enough — the environment must
|
|
4
|
+
* impose them AT TOOL TIME. `kj harden` writes a PreToolUse script and wires
|
|
5
|
+
* it into the project's `.claude/settings.json` (merged, never clobbered):
|
|
6
|
+
* Write over an existing file blocks ("use Edit", KJ_ALLOW_WRITE=1 escapes);
|
|
7
|
+
* Bash that reserializes whole JSON files blocks (KJ_ALLOW_REWRITE=1).
|
|
8
|
+
* Claude-only v1 — the abstraction arrives with the second host that
|
|
9
|
+
* supports tool hooks.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
13
|
+
import { join } from "node:path";
|
|
14
|
+
|
|
15
|
+
const SCRIPT_BODY = `#!/usr/bin/env node
|
|
16
|
+
// kj tool gate (KJC-TSK-0710) — managed by \`kj harden\`. Exit 2 blocks the
|
|
17
|
+
// tool call (stderr explains why); anything unexpected fails OPEN (exit 0)
|
|
18
|
+
// so a gate bug never bricks the session.
|
|
19
|
+
import { existsSync } from "node:fs";
|
|
20
|
+
let raw = "";
|
|
21
|
+
process.stdin.on("data", (d) => { raw += d; });
|
|
22
|
+
process.stdin.on("end", () => {
|
|
23
|
+
try {
|
|
24
|
+
const { tool_name: tool, tool_input: input = {} } = JSON.parse(raw);
|
|
25
|
+
if (tool === "Write" && process.env.KJ_ALLOW_WRITE !== "1") {
|
|
26
|
+
if (input.file_path && existsSync(input.file_path)) {
|
|
27
|
+
console.error("kj tool gate: Write over an EXISTING file destroys unseen changes — use Edit for targeted changes (KJ_ALLOW_WRITE=1 to override consciously).");
|
|
28
|
+
process.exit(2);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
if (tool === "Bash" && process.env.KJ_ALLOW_REWRITE !== "1") {
|
|
32
|
+
const cmd = String(input.command || "");
|
|
33
|
+
const writes = /open\\s*\\([^)]*["'][wa]["']|>\\s*\\S+\\.json\\b/.test(cmd);
|
|
34
|
+
if (/json\\.dumps?\\s*\\(/.test(cmd) && writes) {
|
|
35
|
+
console.error("kj tool gate: reserializing a whole JSON file makes the diff unreviewable — make targeted edits instead (KJ_ALLOW_REWRITE=1 to override consciously).");
|
|
36
|
+
process.exit(2);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
} catch { /* fail open */ }
|
|
40
|
+
process.exit(0);
|
|
41
|
+
});
|
|
42
|
+
`;
|
|
43
|
+
|
|
44
|
+
/** Write a managed hook script under .karajan/harness/ and return its path. */
|
|
45
|
+
export function writeHarnessScript(projectDir, name, body) {
|
|
46
|
+
const dir = join(projectDir, ".karajan", "harness");
|
|
47
|
+
mkdirSync(dir, { recursive: true });
|
|
48
|
+
const abs = join(dir, name);
|
|
49
|
+
writeFileSync(abs, body, { mode: 0o755 });
|
|
50
|
+
return abs;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Merge hook entries into .claude/settings.json. Preserve, never clobber:
|
|
55
|
+
* invalid JSON or a hook event with an unexpected (non-array) shape is the
|
|
56
|
+
* user's business — the file is left alone and the caller wires manually.
|
|
57
|
+
* entries: [{ event, matcher?, script }] where script is a .karajan/harness
|
|
58
|
+
* basename; an entry is present when that script already appears under the
|
|
59
|
+
* same event (and matcher, when given).
|
|
60
|
+
*/
|
|
61
|
+
export function mergeClaudeHooks({ projectDir, logger = console, entries }) {
|
|
62
|
+
const settingsPath = join(projectDir, ".claude", "settings.json");
|
|
63
|
+
let settings = {};
|
|
64
|
+
if (existsSync(settingsPath)) {
|
|
65
|
+
try {
|
|
66
|
+
settings = JSON.parse(readFileSync(settingsPath, "utf8"));
|
|
67
|
+
} catch {
|
|
68
|
+
logger.warn?.(`kj harden: ${settingsPath} is not valid JSON — leaving it untouched (hook scripts written, wire them manually)`);
|
|
69
|
+
return { wired: false };
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
settings.hooks = settings.hooks || {};
|
|
73
|
+
for (const { event } of entries) {
|
|
74
|
+
if (event in settings.hooks && !Array.isArray(settings.hooks[event])) {
|
|
75
|
+
logger.warn?.(`kj harden: ${settingsPath} has a non-array hooks.${event} — leaving it untouched (hook scripts written, wire them manually)`);
|
|
76
|
+
return { wired: false };
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
for (const { event, matcher, script } of entries) {
|
|
80
|
+
const list = Array.isArray(settings.hooks[event]) ? settings.hooks[event] : [];
|
|
81
|
+
const present = list.some(
|
|
82
|
+
(e) => JSON.stringify(e).includes(script) && (matcher === undefined || e?.matcher === matcher),
|
|
83
|
+
);
|
|
84
|
+
if (!present) {
|
|
85
|
+
const cmd = { type: "command", command: `node ${join(".karajan", "harness", script)}` };
|
|
86
|
+
list.push(matcher === undefined ? { hooks: [cmd] } : { matcher, hooks: [cmd] });
|
|
87
|
+
}
|
|
88
|
+
settings.hooks[event] = list;
|
|
89
|
+
}
|
|
90
|
+
mkdirSync(join(projectDir, ".claude"), { recursive: true });
|
|
91
|
+
writeFileSync(settingsPath, `${JSON.stringify(settings, null, 2)}\n`);
|
|
92
|
+
return { wired: true };
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** Write the script and merge the PreToolUse entries into .claude/settings.json. */
|
|
96
|
+
export function installHarnessHooks({ projectDir = process.cwd(), logger = console } = {}) {
|
|
97
|
+
const scriptAbs = writeHarnessScript(projectDir, "pretooluse.mjs", SCRIPT_BODY);
|
|
98
|
+
const { wired } = mergeClaudeHooks({
|
|
99
|
+
projectDir,
|
|
100
|
+
logger,
|
|
101
|
+
entries: [
|
|
102
|
+
{ event: "PreToolUse", matcher: "Write", script: "pretooluse.mjs" },
|
|
103
|
+
{ event: "PreToolUse", matcher: "Bash", script: "pretooluse.mjs" },
|
|
104
|
+
],
|
|
105
|
+
});
|
|
106
|
+
return { script: scriptAbs, wired };
|
|
107
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Native lint/format/test commands per language for `kj harden` hooks
|
|
3
|
+
* (KJC-TSK-0562).
|
|
4
|
+
*
|
|
5
|
+
* The installed hooks call the project's OWN toolchain, never npm by default,
|
|
6
|
+
* so hardening a Go/Python repo never drags Node onto a contributor's machine.
|
|
7
|
+
* JavaScript/TypeScript is built from package.json scripts by the caller (its
|
|
8
|
+
* commands depend on what the project defines). Unknown language ⇒ no commands,
|
|
9
|
+
* leaving only the universal POSIX-shell checks.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
export const COMMANDS_BY_LANGUAGE = {
|
|
13
|
+
python: { lint: "ruff check .", format: "ruff format --check .", test: "pytest" },
|
|
14
|
+
go: { lint: "go vet ./...", format: 'test -z "$(gofmt -l .)"', test: "go test ./..." },
|
|
15
|
+
php: {
|
|
16
|
+
lint: "vendor/bin/phpstan analyse --no-progress",
|
|
17
|
+
format: "vendor/bin/php-cs-fixer fix --dry-run --diff",
|
|
18
|
+
test: "vendor/bin/phpunit",
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/** Native commands for a language, or {} when JS/TS or unknown. */
|
|
23
|
+
export function commandsForLanguage(language) {
|
|
24
|
+
return COMMANDS_BY_LANGUAGE[language] ?? {};
|
|
25
|
+
}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook bodies + profile→hooks mapping for `kj harden` (KJC-TSK-0555, 0562).
|
|
3
|
+
*
|
|
4
|
+
* A body is the MANAGED portion only; harden-engine adds the shebang and the
|
|
5
|
+
* kj:managed markers around it. Pure POSIX sh — the universal checks (commit
|
|
6
|
+
* format, AI-attribution) need no toolchain, and lint/format/test lines call
|
|
7
|
+
* the project's NATIVE commands (from `cmds`), only when present. No npm/Node
|
|
8
|
+
* is imposed on non-JS repos. See docs/specs/quality-harness.md §5.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const CONVENTIONAL_TYPES = "feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert";
|
|
12
|
+
const AI_ATTRIBUTION = "co-authored-by:.*(claude|gpt|copilot|gemini)|(generated|written) (by|with) .*(claude|gpt|copilot)";
|
|
13
|
+
|
|
14
|
+
export const SHEBANG = "#!/usr/bin/env sh";
|
|
15
|
+
|
|
16
|
+
/** Hooks enabled per profile. */
|
|
17
|
+
export const PROFILE_HOOKS = {
|
|
18
|
+
minimal: ["commit-msg"],
|
|
19
|
+
standard: ["pre-commit", "prepare-commit-msg", "commit-msg", "pre-push", "post-merge"],
|
|
20
|
+
strict: ["pre-commit", "prepare-commit-msg", "commit-msg", "pre-push", "post-merge"],
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/** Build the managed body for a single hook. */
|
|
24
|
+
// KJC-TSK-0645: `core.hooksPath .karajan/hooks` eclipses the user's global
|
|
25
|
+
// hooks dir, silently disabling personal guards. When a previous global dir
|
|
26
|
+
// is known, every generated hook ends by chaining its namesake there —
|
|
27
|
+
// guarded, so machines without it are unaffected.
|
|
28
|
+
function chainToGlobal(hook, globalHooksDir) {
|
|
29
|
+
if (!globalHooksDir) return [];
|
|
30
|
+
return [
|
|
31
|
+
"# Chain the machine's previous global hook (kj harden keeps it active).",
|
|
32
|
+
`if [ -x "${globalHooksDir}/${hook}" ]; then`,
|
|
33
|
+
` "${globalHooksDir}/${hook}" "$@"; rc=$?`,
|
|
34
|
+
' [ "$rc" -eq 0 ] || exit "$rc"',
|
|
35
|
+
"fi",
|
|
36
|
+
];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// KJC-TSK-0648: branch-first, enforced. The first external session of the
|
|
40
|
+
// v4 environment committed on local main following literal instructions —
|
|
41
|
+
// the playbook now orders "branch first" and this guard backs it up.
|
|
42
|
+
function baseBranchGuard(baseBranch) {
|
|
43
|
+
if (!baseBranch) return [];
|
|
44
|
+
return [
|
|
45
|
+
"# Branch-first guard — the base branch only moves via PR.",
|
|
46
|
+
'if [ "$KJ_ALLOW_BASE_COMMIT" != "1" ]; then',
|
|
47
|
+
' current_branch=$(git symbolic-ref --short HEAD 2>/dev/null || echo "")',
|
|
48
|
+
` if [ "$current_branch" = "${baseBranch}" ]; then`,
|
|
49
|
+
` echo 'kj harden: direct commits on ${baseBranch} are not allowed — create a branch and open a PR (KJ_ALLOW_BASE_COMMIT=1 to override)'; exit 1`,
|
|
50
|
+
" fi",
|
|
51
|
+
"fi",
|
|
52
|
+
];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// IDN-C (KJC-TSK-0764, ADR 0005): identity lock at tier B — the declared clone
|
|
56
|
+
// identity (.karajan/identity.local.yml) governs authorship on commit and the
|
|
57
|
+
// gh session on push, on ANY host. Undeclared = advisory only (old clones keep
|
|
58
|
+
// working); the fail-closed default is the Sentinel's (IDN-B).
|
|
59
|
+
function identityGuard(hook) {
|
|
60
|
+
const head = [
|
|
61
|
+
"# Identity lock (IDN-C, ADR 0005) — this clone's declared identity governs.",
|
|
62
|
+
'if [ "$KJ_ALLOW_IDENTITY" != "1" ] && [ -f .karajan/identity.local.yml ]; then',
|
|
63
|
+
];
|
|
64
|
+
const tail = [
|
|
65
|
+
"elif [ ! -f .karajan/identity.local.yml ]; then",
|
|
66
|
+
" echo 'kj harden: no identity declared for this clone — run kj identity set (advisory)'",
|
|
67
|
+
"fi",
|
|
68
|
+
];
|
|
69
|
+
if (hook === "pre-commit") {
|
|
70
|
+
return [
|
|
71
|
+
...head,
|
|
72
|
+
" kj_declared_email=$(sed -n 's/^git_email:[[:space:]]*//p' .karajan/identity.local.yml | head -n1)",
|
|
73
|
+
" kj_author=$(git var GIT_AUTHOR_IDENT | sed 's/.*<\\(.*\\)>.*/\\1/')",
|
|
74
|
+
" kj_committer=$(git var GIT_COMMITTER_IDENT | sed 's/.*<\\(.*\\)>.*/\\1/')",
|
|
75
|
+
' if [ -n "$kj_declared_email" ] && { [ "$kj_author" != "$kj_declared_email" ] || [ "$kj_committer" != "$kj_declared_email" ]; }; then',
|
|
76
|
+
' echo "kj harden: identity lock — committing as $kj_author / $kj_committer but this clone is declared as $kj_declared_email (kj identity show; KJ_ALLOW_IDENTITY=1 to override)"; exit 1',
|
|
77
|
+
" fi",
|
|
78
|
+
...tail,
|
|
79
|
+
];
|
|
80
|
+
}
|
|
81
|
+
return [
|
|
82
|
+
...head,
|
|
83
|
+
" kj_declared_gh=$(sed -n 's/^gh_user:[[:space:]]*//p' .karajan/identity.local.yml | head -n1)",
|
|
84
|
+
' kj_hosts="${GH_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/gh}/hosts.yml"',
|
|
85
|
+
" kj_active_gh=$(awk '/^github.com:/{f=1;next} f&&/^[^[:space:]]/{f=0} f&&/^[[:space:]]*user:/{sub(/^[[:space:]]*user:[[:space:]]*/,\"\");print;exit}' \"$kj_hosts\" 2>/dev/null)",
|
|
86
|
+
' if [ -n "$kj_declared_gh" ] && [ "$kj_active_gh" != "$kj_declared_gh" ]; then',
|
|
87
|
+
' echo "kj harden: identity lock — gh session is ${kj_active_gh:-none} but this clone is declared as $kj_declared_gh — run: gh auth switch --user $kj_declared_gh (KJ_ALLOW_IDENTITY=1 to override)"; exit 1',
|
|
88
|
+
" fi",
|
|
89
|
+
...tail,
|
|
90
|
+
];
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function hookBody(hook, cmds = {}, { globalHooksDir = null, baseBranch = null } = {}) {
|
|
94
|
+
const chain = chainToGlobal(hook, globalHooksDir);
|
|
95
|
+
switch (hook) {
|
|
96
|
+
case "pre-commit": {
|
|
97
|
+
const lines = [...baseBranchGuard(baseBranch), ...identityGuard("pre-commit"), "# Lint + format the working tree with the project's native tools."];
|
|
98
|
+
if (cmds.lint) lines.push(`${cmds.lint} || { echo 'kj harden: lint failed'; exit 1; }`);
|
|
99
|
+
if (cmds.format) lines.push(`${cmds.format} || { echo 'kj harden: format check failed'; exit 1; }`);
|
|
100
|
+
if (!cmds.lint && !cmds.format) lines.push("# (no lint/format command detected for this stack)");
|
|
101
|
+
lines.push(
|
|
102
|
+
"# v4 review gate (ENV-C1, opt-in via `kj review --install-gate`):",
|
|
103
|
+
"# a staged diff only enters with a recorded cross-AI approved verdict.",
|
|
104
|
+
"if [ -f .karajan/review-gate ]; then",
|
|
105
|
+
" if ! command -v kj >/dev/null 2>&1; then",
|
|
106
|
+
" echo 'kj: review gate is enabled but kj is not installed — see karajancode.com/docs/getting-started/installation'; exit 1",
|
|
107
|
+
" fi",
|
|
108
|
+
" kj review --check || { echo 'kj: no approved cross-AI verdict for the staged diff — run `kj review --staged`'; exit 1; }",
|
|
109
|
+
"fi"
|
|
110
|
+
);
|
|
111
|
+
return [...lines, ...chain].join("\n");
|
|
112
|
+
}
|
|
113
|
+
case "commit-msg":
|
|
114
|
+
// Pure POSIX — Conventional Commits header, length cap, AI-attribution.
|
|
115
|
+
return [
|
|
116
|
+
'msg_file="$1"',
|
|
117
|
+
'header=$(head -n1 "$msg_file")',
|
|
118
|
+
`if ! printf '%s' "$header" | grep -qE '^(${CONVENTIONAL_TYPES})(\\([a-z0-9._-]+\\))?!?: .+'; then`,
|
|
119
|
+
" echo 'kj harden: commit header must follow Conventional Commits (type: subject)'; exit 1",
|
|
120
|
+
"fi",
|
|
121
|
+
'if [ "${#header}" -gt 100 ]; then echo \'kj harden: commit header exceeds 100 chars\'; exit 1; fi',
|
|
122
|
+
`if grep -qiE '${AI_ATTRIBUTION}' "$msg_file"; then`,
|
|
123
|
+
" echo 'kj harden: AI attribution is not allowed in commit messages'; exit 1",
|
|
124
|
+
"fi",
|
|
125
|
+
...chain,
|
|
126
|
+
].join("\n");
|
|
127
|
+
case "pre-push": {
|
|
128
|
+
const lines = [
|
|
129
|
+
"# Identity guard — never push without a configured git identity.",
|
|
130
|
+
'if [ -z "$(git config user.email)" ] || [ -z "$(git config user.name)" ]; then',
|
|
131
|
+
" echo 'kj harden: git user.name/user.email not set — refusing to push'; exit 1",
|
|
132
|
+
"fi",
|
|
133
|
+
'echo "kj harden: pushing as $(git config user.name) <$(git config user.email)>"',
|
|
134
|
+
...identityGuard("pre-push"),
|
|
135
|
+
"# Run the test suite before pushing.",
|
|
136
|
+
];
|
|
137
|
+
if (cmds.test) lines.push(`${cmds.test} || { echo 'kj harden: tests failed'; exit 1; }`);
|
|
138
|
+
else lines.push("# (no test command detected for this stack)");
|
|
139
|
+
return [...lines, ...chain].join("\n");
|
|
140
|
+
}
|
|
141
|
+
case "prepare-commit-msg":
|
|
142
|
+
// KJC-TSK-0692 (MG-F): the branch already carries the card ref
|
|
143
|
+
// (validated by the card-first gate) — the subject inherits it
|
|
144
|
+
// automatically. A convention that enforces itself needs no adoption.
|
|
145
|
+
return [
|
|
146
|
+
'msg_file="$1"',
|
|
147
|
+
'branch=$(git symbolic-ref --short HEAD 2>/dev/null || echo "")',
|
|
148
|
+
"# POSIX-safe extraction (no grep -o): the ref is the leading",
|
|
149
|
+
"# card-shaped token of the branch's last segment (feat/REF-desc).",
|
|
150
|
+
"seg=$(printf '%s' \"$branch\" | tr '[:upper:]' '[:lower:]'); seg=\"${seg##*/}\"",
|
|
151
|
+
String.raw`ref=$(printf '%s' "$seg" | sed -nE 's/^([a-z][a-z0-9]{1,9}(-[a-z][a-z0-9]{1,9})*-[0-9]{1,6})(-.*)?$/\1/p')`,
|
|
152
|
+
'header=$(head -n1 "$msg_file")',
|
|
153
|
+
'if [ -n "$ref" ] && [ -n "$header" ]; then',
|
|
154
|
+
' case "$header" in',
|
|
155
|
+
" Merge*|fixup!*|squash!*) ;;",
|
|
156
|
+
" *)",
|
|
157
|
+
" # Boundary match — a header mentioning KJW-TSK-00011 must not",
|
|
158
|
+
" # suppress the KJW-TSK-0001 stamp. $ref is [a-z0-9-] only by",
|
|
159
|
+
" # construction (sed extraction above), safe inside the ERE.",
|
|
160
|
+
' if ! printf \'%s\' "$header" | grep -qiE "(^|[^a-zA-Z0-9-])$ref([^a-zA-Z0-9-]|$)"; then',
|
|
161
|
+
" stamp=$(printf '%s' \"$ref\" | tr '[:lower:]' '[:upper:]')",
|
|
162
|
+
' new_header="$header ($stamp)"',
|
|
163
|
+
' if [ "${#new_header}" -le 100 ]; then',
|
|
164
|
+
String.raw` { printf '%s\n' "$new_header"; tail -n +2 "$msg_file"; } > "$msg_file.kjtmp" && mv "$msg_file.kjtmp" "$msg_file"`,
|
|
165
|
+
" fi",
|
|
166
|
+
" fi",
|
|
167
|
+
" ;;",
|
|
168
|
+
" esac",
|
|
169
|
+
"fi",
|
|
170
|
+
...chain,
|
|
171
|
+
].join("\n");
|
|
172
|
+
case "post-merge":
|
|
173
|
+
return [
|
|
174
|
+
"# Refresh the local RAG index so retrieval never serves stale code.",
|
|
175
|
+
"if command -v kj >/dev/null 2>&1; then",
|
|
176
|
+
" kj rag index --since auto >/dev/null 2>&1 || true",
|
|
177
|
+
"fi",
|
|
178
|
+
...chain,
|
|
179
|
+
].join("\n");
|
|
180
|
+
default:
|
|
181
|
+
throw new Error(`Unknown hook: ${hook}`);
|
|
182
|
+
}
|
|
183
|
+
}
|