@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,180 @@
|
|
|
1
|
+
// Platform-aware install hints for external tools that `kj audit` /
|
|
2
|
+
// `kj webperf` use (semgrep, osv-scanner, lighthouse).
|
|
3
|
+
//
|
|
4
|
+
// `kj doctor` calls these to render hint strings ("Install with:
|
|
5
|
+
// pipx install semgrep") that match what's actually available on the
|
|
6
|
+
// user's machine, rather than a generic "see docs" message. The same
|
|
7
|
+
// metadata drives `kj install-tools` (HU2) — it decides which package
|
|
8
|
+
// manager to invoke per tool.
|
|
9
|
+
//
|
|
10
|
+
// We probe each package manager once with `which`/`where`-style checks
|
|
11
|
+
// and cache the result for the lifetime of the process.
|
|
12
|
+
|
|
13
|
+
import { execFile } from "node:child_process";
|
|
14
|
+
import { promisify } from "node:util";
|
|
15
|
+
|
|
16
|
+
const execFileAsync = promisify(execFile);
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @typedef {"pipx"|"brew"|"go"|"npm"|"pip"|"apt"|"dnf"|"choco"|"scoop"|"docker"} PackageManager
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
/** @type {Record<PackageManager, boolean>|null} */
|
|
23
|
+
let cachedAvailability = null;
|
|
24
|
+
|
|
25
|
+
const PROBES = [
|
|
26
|
+
["pipx", ["--version"]],
|
|
27
|
+
["brew", ["--version"]],
|
|
28
|
+
["go", ["version"]],
|
|
29
|
+
["npm", ["--version"]],
|
|
30
|
+
["pip", ["--version"]],
|
|
31
|
+
["apt", ["--version"]],
|
|
32
|
+
["dnf", ["--version"]],
|
|
33
|
+
["choco", ["--version"]],
|
|
34
|
+
["scoop", ["--version"]],
|
|
35
|
+
["docker", ["--version"]],
|
|
36
|
+
];
|
|
37
|
+
|
|
38
|
+
async function probeOne(bin, args) {
|
|
39
|
+
try {
|
|
40
|
+
await execFileAsync(bin, args, { timeout: 3000 });
|
|
41
|
+
return true;
|
|
42
|
+
} catch {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Detect which package managers are reachable on PATH. Cached on first
|
|
49
|
+
* call. Exported for tests; production callers go through getInstallHint.
|
|
50
|
+
*/
|
|
51
|
+
export async function detectPackageManagers() {
|
|
52
|
+
if (cachedAvailability) return cachedAvailability;
|
|
53
|
+
const entries = await Promise.all(
|
|
54
|
+
PROBES.map(async ([bin, args]) => [bin, await probeOne(bin, args)]),
|
|
55
|
+
);
|
|
56
|
+
cachedAvailability = Object.fromEntries(entries);
|
|
57
|
+
return cachedAvailability;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Test helper — reset the cache between unit cases. */
|
|
61
|
+
export function resetPackageManagerCache() {
|
|
62
|
+
cachedAvailability = null;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Returns the install command for a tool, preferring the highest-priority
|
|
67
|
+
* package manager available on the current system.
|
|
68
|
+
*
|
|
69
|
+
* The order encodes our recommendation when multiple managers can install
|
|
70
|
+
* the same tool. We prefer isolated installs (pipx, brew) over global
|
|
71
|
+
* `pip install` so we don't pollute the user's site-packages.
|
|
72
|
+
*
|
|
73
|
+
* @param {"semgrep"|"osv-scanner"|"lighthouse"|"docker"} tool
|
|
74
|
+
* @param {Record<PackageManager, boolean>} [available] — pre-computed availability; if omitted, detects.
|
|
75
|
+
* @returns {Promise<{ command: string|null, manager: PackageManager|null, manualUrl: string }>}
|
|
76
|
+
*/
|
|
77
|
+
export async function getInstallHint(tool, available = null) {
|
|
78
|
+
const avail = available || (await detectPackageManagers());
|
|
79
|
+
const candidates = INSTALL_CANDIDATES[tool] || [];
|
|
80
|
+
for (const { manager, command } of candidates) {
|
|
81
|
+
if (avail[manager]) return { command, manager, manualUrl: MANUAL_URLS[tool] };
|
|
82
|
+
}
|
|
83
|
+
// Nothing matched — suggest a recipe that actually works on this system.
|
|
84
|
+
// KJC-BUG-0120 (issue #1256): distro-aware fallbacks first (PEP 668 makes
|
|
85
|
+
// the generic pip bootstrap fail on Debian/Ubuntu); these are display-only
|
|
86
|
+
// (manager: null), never auto-run — sudo stays in the user's hands.
|
|
87
|
+
for (const { when, command } of DISTRO_FALLBACKS[tool] || []) {
|
|
88
|
+
if (avail[when]) return { command, manager: null, manualUrl: MANUAL_URLS[tool] };
|
|
89
|
+
}
|
|
90
|
+
const first = candidates[0];
|
|
91
|
+
return {
|
|
92
|
+
command: first ? first.command : null,
|
|
93
|
+
manager: null,
|
|
94
|
+
manualUrl: MANUAL_URLS[tool],
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const DISTRO_FALLBACKS = {
|
|
99
|
+
semgrep: [
|
|
100
|
+
{ when: "apt", command: "sudo apt update && sudo apt install -y pipx && pipx install semgrep" },
|
|
101
|
+
{ when: "dnf", command: "sudo dnf install -y pipx && pipx install semgrep" },
|
|
102
|
+
],
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
const INSTALL_CANDIDATES = {
|
|
106
|
+
semgrep: [
|
|
107
|
+
{ manager: "pipx", command: "pipx install semgrep" },
|
|
108
|
+
{ manager: "brew", command: "brew install semgrep" },
|
|
109
|
+
{ manager: "pip", command: "pip install semgrep" },
|
|
110
|
+
],
|
|
111
|
+
"osv-scanner": [
|
|
112
|
+
// The module root has no main package — the binary lives in the cmd/
|
|
113
|
+
// subpackage, and since v2 the module path carries the /v2 suffix.
|
|
114
|
+
// `go install github.com/google/osv-scanner@latest` resolves the module
|
|
115
|
+
// (v1.x) but fails with "does not contain package" (KJC-BUG-0105).
|
|
116
|
+
{ manager: "go", command: "go install github.com/google/osv-scanner/v2/cmd/osv-scanner@latest" },
|
|
117
|
+
{ manager: "brew", command: "brew install osv-scanner" },
|
|
118
|
+
],
|
|
119
|
+
lighthouse: [
|
|
120
|
+
{ manager: "npm", command: "npm install -g lighthouse" },
|
|
121
|
+
],
|
|
122
|
+
docker: [
|
|
123
|
+
// Docker Desktop / Engine cannot be installed by a package manager
|
|
124
|
+
// reliably across platforms — always point users to the official docs.
|
|
125
|
+
// Listing brew anyway as a hint for macOS users.
|
|
126
|
+
{ manager: "brew", command: "brew install --cask docker" },
|
|
127
|
+
],
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
const MANUAL_URLS = {
|
|
131
|
+
semgrep: "https://semgrep.dev/docs/getting-started",
|
|
132
|
+
"osv-scanner": "https://google.github.io/osv-scanner/installation/",
|
|
133
|
+
lighthouse: "https://github.com/GoogleChrome/lighthouse#using-the-cli",
|
|
134
|
+
docker: "https://docs.docker.com/get-docker/",
|
|
135
|
+
git: "https://git-scm.com/downloads",
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
// git is a `kj doctor` *required* tool. Unlike the audit tools it is installed
|
|
139
|
+
// through the OS package manager, and on Linux that needs root — so the plan
|
|
140
|
+
// carries a `needsSudo` flag and the caller runs those through the interactive
|
|
141
|
+
// (tty-inherited) path, where sudo prompts the user directly and kj never sees
|
|
142
|
+
// the password. brew/scoop/choco install at user scope, no sudo.
|
|
143
|
+
const GIT_CANDIDATES = [
|
|
144
|
+
{ manager: "brew", command: "brew install git", needsSudo: false },
|
|
145
|
+
{ manager: "apt", command: "sudo apt-get install -y git", needsSudo: true },
|
|
146
|
+
{ manager: "dnf", command: "sudo dnf install -y git", needsSudo: true },
|
|
147
|
+
{ manager: "choco", command: "choco install git -y", needsSudo: false },
|
|
148
|
+
{ manager: "scoop", command: "scoop install git", needsSudo: false },
|
|
149
|
+
];
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Pick a git install plan for the current machine. Returns a manual plan
|
|
153
|
+
* (command null + URL) when no supported package manager is present.
|
|
154
|
+
*
|
|
155
|
+
* @param {Record<PackageManager, boolean>} available
|
|
156
|
+
* @returns {{ command: string|null, manager: PackageManager|null, needsSudo: boolean, manualUrl: string }}
|
|
157
|
+
*/
|
|
158
|
+
export function gitInstallPlan(available = {}) {
|
|
159
|
+
for (const { manager, command, needsSudo } of GIT_CANDIDATES) {
|
|
160
|
+
if (available[manager]) return { command, manager, needsSudo, manualUrl: MANUAL_URLS.git };
|
|
161
|
+
}
|
|
162
|
+
return { command: null, manager: null, needsSudo: false, manualUrl: MANUAL_URLS.git };
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Tools whose hint depends on the project stack. lighthouse is only
|
|
167
|
+
* relevant for frontend projects; suppressing the hint elsewhere keeps
|
|
168
|
+
* `kj doctor` output free of irrelevant noise.
|
|
169
|
+
*
|
|
170
|
+
* @param {string} tool
|
|
171
|
+
* @param {Object} stack — shape returned by detectProjectStack()
|
|
172
|
+
*/
|
|
173
|
+
export function appliesToStack(tool, stack) {
|
|
174
|
+
if (tool === "lighthouse") {
|
|
175
|
+
if (!stack) return false;
|
|
176
|
+
return Boolean(stack.isFrontend || stack.isFullstack);
|
|
177
|
+
}
|
|
178
|
+
// semgrep, osv-scanner, docker, sonar — always relevant.
|
|
179
|
+
return true;
|
|
180
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Robust JSON extraction from agent output.
|
|
3
|
+
* Extracts the first complete JSON object from a string,
|
|
4
|
+
* ignoring any trailing text that would cause parse errors.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Extract the first valid JSON object from a raw string.
|
|
9
|
+
* Handles cases where agents output valid JSON followed by extra text.
|
|
10
|
+
* @param {string} raw - Raw agent output.
|
|
11
|
+
* @returns {object|null} Parsed JSON object, or null if no valid JSON found.
|
|
12
|
+
*/
|
|
13
|
+
export function extractFirstJson(raw) {
|
|
14
|
+
if (!raw) return null;
|
|
15
|
+
const str = typeof raw === "string" ? raw.trim() : String(raw).trim();
|
|
16
|
+
if (!str) return null;
|
|
17
|
+
|
|
18
|
+
// Fast path: try parsing the whole string first
|
|
19
|
+
try {
|
|
20
|
+
return JSON.parse(str);
|
|
21
|
+
} catch { /* fall through to extraction */ }
|
|
22
|
+
|
|
23
|
+
// Find the first '{' and match to its closing '}'
|
|
24
|
+
const start = str.indexOf("{");
|
|
25
|
+
if (start === -1) return null;
|
|
26
|
+
|
|
27
|
+
let depth = 0;
|
|
28
|
+
let inString = false;
|
|
29
|
+
let escaped = false;
|
|
30
|
+
|
|
31
|
+
for (let i = start; i < str.length; i++) {
|
|
32
|
+
const ch = str[i];
|
|
33
|
+
|
|
34
|
+
if (escaped) {
|
|
35
|
+
escaped = false;
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (ch === "\\") {
|
|
40
|
+
escaped = true;
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (ch === '"') {
|
|
45
|
+
inString = !inString;
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (inString) continue;
|
|
50
|
+
|
|
51
|
+
if (ch === "{") depth++;
|
|
52
|
+
if (ch === "}") depth--;
|
|
53
|
+
|
|
54
|
+
if (depth === 0) {
|
|
55
|
+
try {
|
|
56
|
+
return JSON.parse(str.substring(start, i + 1));
|
|
57
|
+
} catch { /* matched braces but not valid JSON */
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OS locale detection and language instruction generation for i18n support.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export const SUPPORTED_LANGUAGES = {
|
|
6
|
+
en: "English",
|
|
7
|
+
es: "Español"
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
const LANG_ENV_VARS = ["LANG", "LANGUAGE", "LC_ALL", "LC_MESSAGES"];
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Detect the 2-letter language code from OS environment variables.
|
|
14
|
+
* Checks LANG, LANGUAGE, LC_ALL, LC_MESSAGES in order.
|
|
15
|
+
* @returns {string} 2-letter language code (e.g. "en", "es")
|
|
16
|
+
*/
|
|
17
|
+
export function detectOsLocale() {
|
|
18
|
+
for (const envVar of LANG_ENV_VARS) {
|
|
19
|
+
const value = process.env[envVar];
|
|
20
|
+
if (value) {
|
|
21
|
+
const code = extractLangCode(value);
|
|
22
|
+
if (code) return code;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return "en";
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Extract a 2-letter language code from a locale string.
|
|
30
|
+
* Handles formats like "es_ES.UTF-8", "en_US", "es", "C.UTF-8".
|
|
31
|
+
* @param {string} locale
|
|
32
|
+
* @returns {string|null}
|
|
33
|
+
*/
|
|
34
|
+
function extractLangCode(locale) {
|
|
35
|
+
const trimmed = locale.trim();
|
|
36
|
+
if (!trimmed || trimmed === "C" || trimmed === "POSIX") return null;
|
|
37
|
+
// Match first 2 lowercase letters before _, ., or end
|
|
38
|
+
const match = /^([a-z]{2})(?:[_.-]|$)/i.exec(trimmed);
|
|
39
|
+
if (match) return match[1].toLowerCase();
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Get a prompt instruction string for the given language.
|
|
45
|
+
* Returns empty string for English (agents default to English).
|
|
46
|
+
* @param {string} lang - 2-letter language code
|
|
47
|
+
* @returns {string}
|
|
48
|
+
*/
|
|
49
|
+
export function getLanguageInstruction(lang) {
|
|
50
|
+
if (!lang || lang === "en") return "";
|
|
51
|
+
const languageName = SUPPORTED_LANGUAGES[lang];
|
|
52
|
+
if (lang === "es") {
|
|
53
|
+
return "IMPORTANT: Respond in Spanish. All output, explanations, and feedback must be in Spanish.";
|
|
54
|
+
}
|
|
55
|
+
if (languageName) {
|
|
56
|
+
return `IMPORTANT: Respond in ${languageName}. All output must be in ${languageName}.`;
|
|
57
|
+
}
|
|
58
|
+
return `IMPORTANT: Respond in ${lang}. All output must be in ${lang}.`;
|
|
59
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { EventEmitter } from "node:events";
|
|
2
|
+
|
|
3
|
+
const LEVELS = ["debug", "info", "warn", "error"];
|
|
4
|
+
|
|
5
|
+
const ANSI = {
|
|
6
|
+
reset: "\x1b[0m",
|
|
7
|
+
dim: "\x1b[2m",
|
|
8
|
+
cyan: "\x1b[36m",
|
|
9
|
+
yellow: "\x1b[33m",
|
|
10
|
+
red: "\x1b[31m",
|
|
11
|
+
gray: "\x1b[90m"
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const LEVEL_COLORS = {
|
|
15
|
+
debug: ANSI.gray,
|
|
16
|
+
info: ANSI.cyan,
|
|
17
|
+
warn: ANSI.yellow,
|
|
18
|
+
error: ANSI.red
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
function timestamp() {
|
|
22
|
+
const now = new Date();
|
|
23
|
+
const h = String(now.getHours()).padStart(2, "0");
|
|
24
|
+
const m = String(now.getMinutes()).padStart(2, "0");
|
|
25
|
+
const s = String(now.getSeconds()).padStart(2, "0");
|
|
26
|
+
const ms = String(now.getMilliseconds()).padStart(3, "0");
|
|
27
|
+
return `${h}:${m}:${s}.${ms}`;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function formatContext(ctx) {
|
|
31
|
+
const parts = [];
|
|
32
|
+
if (ctx.iteration !== undefined) parts.push(`iter=${ctx.iteration}`);
|
|
33
|
+
if (ctx.stage) parts.push(`stage=${ctx.stage}`);
|
|
34
|
+
return parts.length ? `[${parts.join(" ")}] ` : "";
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function createLogger(level = "info", mode = "cli") {
|
|
38
|
+
const min = LEVELS.indexOf(level);
|
|
39
|
+
const minIdx = min === -1 ? 1 : min;
|
|
40
|
+
const emitter = new EventEmitter();
|
|
41
|
+
let context = {};
|
|
42
|
+
|
|
43
|
+
function canLog(target) {
|
|
44
|
+
return LEVELS.indexOf(target) >= minIdx;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function emit(lvl, args) {
|
|
48
|
+
const entry = {
|
|
49
|
+
level: lvl,
|
|
50
|
+
timestamp: new Date().toISOString(),
|
|
51
|
+
context: { ...context },
|
|
52
|
+
message: args.map((a) => (typeof a === "string" ? a : JSON.stringify(a))).join(" ")
|
|
53
|
+
};
|
|
54
|
+
emitter.emit("log", entry);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function log(lvl, ...args) {
|
|
58
|
+
if (!canLog(lvl)) return;
|
|
59
|
+
emit(lvl, args);
|
|
60
|
+
if (mode === "silent") return;
|
|
61
|
+
if (mode === "mcp") return;
|
|
62
|
+
const color = LEVEL_COLORS[lvl] || "";
|
|
63
|
+
const ts = `${ANSI.dim}${timestamp()}${ANSI.reset}`;
|
|
64
|
+
const prefix = `${color}[${lvl}]${ANSI.reset}`;
|
|
65
|
+
const ctx = formatContext(context);
|
|
66
|
+
let stream = console.log;
|
|
67
|
+
if (lvl === "error") {
|
|
68
|
+
stream = console.error;
|
|
69
|
+
} else if (lvl === "warn") {
|
|
70
|
+
stream = console.warn;
|
|
71
|
+
}
|
|
72
|
+
stream(`${ts} ${prefix} ${ctx}${args.map((a) => (typeof a === "string" ? a : JSON.stringify(a))).join(" ")}`);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
debug: (...args) => log("debug", ...args),
|
|
77
|
+
info: (...args) => log("info", ...args),
|
|
78
|
+
warn: (...args) => log("warn", ...args),
|
|
79
|
+
error: (...args) => log("error", ...args),
|
|
80
|
+
setContext(ctx) {
|
|
81
|
+
context = { ...context, ...ctx };
|
|
82
|
+
},
|
|
83
|
+
resetContext() {
|
|
84
|
+
context = {};
|
|
85
|
+
},
|
|
86
|
+
onLog(callback) {
|
|
87
|
+
emitter.on("log", callback);
|
|
88
|
+
},
|
|
89
|
+
offLog(callback) {
|
|
90
|
+
emitter.off("log", callback);
|
|
91
|
+
},
|
|
92
|
+
get mode() {
|
|
93
|
+
return mode;
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Managed-markers — idempotent file-block scaffolding for `kj harden`
|
|
3
|
+
* (KJC-TSK-0555, design in docs/specs/quality-harness.md §4).
|
|
4
|
+
*
|
|
5
|
+
* harden owns ONLY the content between a pair of markers; everything else in
|
|
6
|
+
* the file is preserved verbatim. Re-running with the same input is a no-op.
|
|
7
|
+
* Generalises the `KJC-TSK-0455` marker already used by the post-merge hook
|
|
8
|
+
* installer, and honours the project rule "never overwrite existing files".
|
|
9
|
+
*
|
|
10
|
+
* Block shape (comment syntax varies by file type):
|
|
11
|
+
* # >>> kj:managed:<id> v<N> >>> (do not edit: regenerated by kj harden)
|
|
12
|
+
* …managed body…
|
|
13
|
+
* # <<< kj:managed:<id> <<<
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const DEFAULT_NOTE = "do not edit: regenerated by kj harden";
|
|
17
|
+
|
|
18
|
+
/** Wrap marker payload text in the comment syntax for a given style. */
|
|
19
|
+
const COMMENT = {
|
|
20
|
+
hash: (text) => `# ${text}`,
|
|
21
|
+
slash: (text) => `// ${text}`,
|
|
22
|
+
html: (text) => `<!-- ${text} -->`,
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/** Pick a comment style from a file path. Defaults to hash (shell/yaml/conf). */
|
|
26
|
+
export function commentStyleFor(filePath = "") {
|
|
27
|
+
if (/\.(md|markdown|mdx)$/i.test(filePath)) return "html";
|
|
28
|
+
if (/\.(m?[jt]sx?|c[jt]s)$/i.test(filePath)) return "slash";
|
|
29
|
+
return "hash";
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const openPayload = (blockId, version) => `>>> kj:managed:${blockId} v${version} >>>`;
|
|
33
|
+
const closePayload = (blockId) => `<<< kj:managed:${blockId} <<<`;
|
|
34
|
+
|
|
35
|
+
/** Render the full managed block (open marker + body + close marker). */
|
|
36
|
+
export function buildManagedBlock({ blockId, version, body, style = "hash", note = DEFAULT_NOTE }) {
|
|
37
|
+
const comment = COMMENT[style] ?? COMMENT.hash;
|
|
38
|
+
const open = comment(`${openPayload(blockId, version)} (${note})`);
|
|
39
|
+
const close = comment(closePayload(blockId));
|
|
40
|
+
return `${open}\n${body}\n${close}`;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Locate a managed block by id in `source`, regardless of comment style or
|
|
45
|
+
* version. Returns line indices and the detected version, or { found:false }.
|
|
46
|
+
*/
|
|
47
|
+
export function findManagedBlock(source = "", blockId) {
|
|
48
|
+
const lines = source.split("\n");
|
|
49
|
+
const openTag = `>>> kj:managed:${blockId} v`;
|
|
50
|
+
const closeTag = `<<< kj:managed:${blockId} <<<`;
|
|
51
|
+
let startLine = -1;
|
|
52
|
+
let version = null;
|
|
53
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
54
|
+
const at = lines[i].indexOf(openTag);
|
|
55
|
+
if (at === -1) continue;
|
|
56
|
+
const rest = lines[i].slice(at + openTag.length);
|
|
57
|
+
const end = rest.indexOf(" >>>");
|
|
58
|
+
const digits = end === -1 ? "" : rest.slice(0, end);
|
|
59
|
+
if (/^\d+$/.test(digits)) {
|
|
60
|
+
startLine = i;
|
|
61
|
+
version = Number(digits);
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (startLine === -1) return { found: false };
|
|
66
|
+
for (let i = startLine + 1; i < lines.length; i += 1) {
|
|
67
|
+
if (lines[i].includes(closeTag)) return { found: true, startLine, endLine: i, version };
|
|
68
|
+
}
|
|
69
|
+
return { found: false, malformed: true, startLine };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Insert or update the managed block for `blockId` in `source`, preserving all
|
|
74
|
+
* content outside the markers. Idempotent: identical input → action "unchanged".
|
|
75
|
+
*
|
|
76
|
+
* @returns {{content: string, action: "inserted"|"updated"|"unchanged", previousVersion: number|null}}
|
|
77
|
+
*/
|
|
78
|
+
export function upsertManagedBlock({ source = "", blockId, version, body, style = "hash", note }) {
|
|
79
|
+
const block = buildManagedBlock({ blockId, version, body, style, note });
|
|
80
|
+
const existing = findManagedBlock(source, blockId);
|
|
81
|
+
|
|
82
|
+
if (!existing.found) {
|
|
83
|
+
const base = source === "" ? "" : source.replace(/\n*$/, "\n");
|
|
84
|
+
return { content: `${base}${block}\n`, action: "inserted", previousVersion: null };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const lines = source.split("\n");
|
|
88
|
+
const before = lines.slice(0, existing.startLine);
|
|
89
|
+
const after = lines.slice(existing.endLine + 1);
|
|
90
|
+
const content = [...before, ...block.split("\n"), ...after].join("\n");
|
|
91
|
+
if (content === source) return { content, action: "unchanged", previousVersion: existing.version };
|
|
92
|
+
return { content, action: "updated", previousVersion: existing.version };
|
|
93
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// KJC-TSK-0476 — Multi-stack manifest sniffer. Sin libs externas: JSON.parse
|
|
2
|
+
// para package.json, regex para TOML y go.mod. Lo consumen audit (basal-cost)
|
|
3
|
+
// y, vía PR-D, el onboarder.
|
|
4
|
+
import fs from "node:fs/promises";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
|
|
7
|
+
async function readMaybe(file) {
|
|
8
|
+
try { return await fs.readFile(file, "utf8"); } catch { return null; }
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
async function sniffNode(dir) {
|
|
12
|
+
const raw = await readMaybe(path.join(dir, "package.json"));
|
|
13
|
+
if (!raw) return null;
|
|
14
|
+
try {
|
|
15
|
+
const pkg = JSON.parse(raw);
|
|
16
|
+
return { stack: "node", manifest: "package.json", name: pkg.name || null,
|
|
17
|
+
deps: Object.keys(pkg.dependencies || {}).length,
|
|
18
|
+
devDeps: Object.keys(pkg.devDependencies || {}).length };
|
|
19
|
+
} catch {
|
|
20
|
+
return { stack: "node", manifest: "package.json", name: null, deps: 0, devDeps: 0, malformed: true };
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Cuerpo TOML de `[section]` hasta el siguiente `\n[` o EOF. Lookahead con `/m`
|
|
25
|
+
// cambia el significado de `$` y producía capturas vacías.
|
|
26
|
+
function tomlSection(toml, section) {
|
|
27
|
+
const i = toml.indexOf(`[${section}]`);
|
|
28
|
+
if (i === -1) return "";
|
|
29
|
+
const rest = toml.slice(i + section.length + 2);
|
|
30
|
+
const n = rest.search(/\n\[/);
|
|
31
|
+
return n === -1 ? rest : rest.slice(0, n);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const DEP_LINE_RE = /^\s*[A-Za-z0-9_-]+\s*=/;
|
|
35
|
+
const countDepLines = (block, excludePython) => block.split("\n")
|
|
36
|
+
.filter((l) => DEP_LINE_RE.test(l) && !(excludePython && /^\s*python\s*=/.test(l))).length;
|
|
37
|
+
|
|
38
|
+
async function sniffPython(dir) {
|
|
39
|
+
const py = await readMaybe(path.join(dir, "pyproject.toml"));
|
|
40
|
+
if (py) {
|
|
41
|
+
const name = /^name\s*=\s*["']([^"']+)["']/m.exec(py)?.[1] || null;
|
|
42
|
+
const projectDeps = /\[project\][\s\S]*?dependencies\s*=\s*\[([^\]]*)\]/m.exec(py)?.[1] || "";
|
|
43
|
+
const projectCount = projectDeps.split(",").map((s) => s.trim()).filter(Boolean).length;
|
|
44
|
+
const poetryCount = countDepLines(tomlSection(py, "tool.poetry.dependencies"), true);
|
|
45
|
+
return { stack: "python", manifest: "pyproject.toml", name, deps: projectCount + poetryCount, devDeps: 0 };
|
|
46
|
+
}
|
|
47
|
+
const req = await readMaybe(path.join(dir, "requirements.txt"));
|
|
48
|
+
if (!req) return null;
|
|
49
|
+
const lines = req.split("\n").map((l) => l.replace(/#.*$/, "").trim()).filter(Boolean);
|
|
50
|
+
return { stack: "python", manifest: "requirements.txt", name: null, deps: lines.length, devDeps: 0 };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function sniffRust(dir) {
|
|
54
|
+
const toml = await readMaybe(path.join(dir, "Cargo.toml"));
|
|
55
|
+
if (!toml) return null;
|
|
56
|
+
return { stack: "rust", manifest: "Cargo.toml",
|
|
57
|
+
name: /^name\s*=\s*["']([^"']+)["']/m.exec(toml)?.[1] || null,
|
|
58
|
+
deps: countDepLines(tomlSection(toml, "dependencies")),
|
|
59
|
+
devDeps: countDepLines(tomlSection(toml, "dev-dependencies")) };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async function sniffGo(dir) {
|
|
63
|
+
const mod = await readMaybe(path.join(dir, "go.mod"));
|
|
64
|
+
if (!mod) return null;
|
|
65
|
+
const block = /require\s*\(([\s\S]*?)\)/m.exec(mod)?.[1] || "";
|
|
66
|
+
const blockCount = block.split("\n").filter((l) => /\S/.test(l) && !l.trim().startsWith("//")).length;
|
|
67
|
+
const singleCount = mod.split("\n").filter((l) => /^require\s+\S+\s+\S+/.test(l)).length;
|
|
68
|
+
return { stack: "go", manifest: "go.mod",
|
|
69
|
+
name: /^module\s+(\S+)/m.exec(mod)?.[1] || null,
|
|
70
|
+
deps: blockCount + singleCount, devDeps: 0 };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export async function sniffManifests(dir) {
|
|
74
|
+
const r = await Promise.all([sniffNode(dir), sniffPython(dir), sniffRust(dir), sniffGo(dir)]);
|
|
75
|
+
return r.filter(Boolean);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function summariseStack(manifests) {
|
|
79
|
+
if (!manifests.length) return { primary: null, multi: false, manifests: [] };
|
|
80
|
+
const ranked = [...manifests].sort((a, b) => (b.deps + b.devDeps) - (a.deps + a.devDeps));
|
|
81
|
+
return { primary: ranked[0].stack, multi: manifests.length > 1, manifests };
|
|
82
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Centralized message catalog for pipeline UI strings.
|
|
3
|
+
* Supports i18n by resolving messages for the configured language.
|
|
4
|
+
* Falls back to English when a key or language is missing.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const MESSAGES = {
|
|
8
|
+
en: {
|
|
9
|
+
triage_decompose: "Triage recommends decomposing this task into {count} subtasks:",
|
|
10
|
+
triage_create_cards: "Create these as linked cards in Planning Game (parent: {cardId})?",
|
|
11
|
+
triage_sequential: "Each subtask will block the next one (sequential chain).",
|
|
12
|
+
triage_reply: "Reply: yes / no",
|
|
13
|
+
solomon_conflict: "--- Conflict: {stage} ---",
|
|
14
|
+
solomon_feedback: "Reviewer feedback:",
|
|
15
|
+
solomon_reason: "Solomon could not resolve the conflict:",
|
|
16
|
+
solomon_options: "Options:\n 1. Accept coder's work as-is\n 2. Retry with reviewer's feedback\n 3. Stop the session",
|
|
17
|
+
solomon_proceed: "How should we proceed?",
|
|
18
|
+
checkpoint_continue: "Continue for {minutes} more minutes?",
|
|
19
|
+
checkpoint_options: "1. Continue 5 more minutes\n2. Continue until done (no more checkpoints)\n3. Continue for N minutes (reply with the number)\n4. Stop now",
|
|
20
|
+
preflight_passed: "Preflight passed — all checks OK",
|
|
21
|
+
pipeline_iteration: "Iteration {current}/{max}",
|
|
22
|
+
},
|
|
23
|
+
es: {
|
|
24
|
+
triage_decompose: "Triage recomienda descomponer esta tarea en {count} subtareas:",
|
|
25
|
+
triage_create_cards: "¿Crear estas como cards vinculadas en Planning Game (padre: {cardId})?",
|
|
26
|
+
triage_sequential: "Cada subtarea bloqueará la siguiente (cadena secuencial).",
|
|
27
|
+
triage_reply: "Responde: sí / no",
|
|
28
|
+
solomon_conflict: "--- Conflicto: {stage} ---",
|
|
29
|
+
solomon_feedback: "Feedback del reviewer:",
|
|
30
|
+
solomon_reason: "Solomon no pudo resolver el conflicto:",
|
|
31
|
+
solomon_options: "Opciones:\n 1. Aceptar el trabajo del coder tal cual\n 2. Reintentar con el feedback del reviewer\n 3. Parar la sesión",
|
|
32
|
+
solomon_proceed: "¿Cómo procedemos?",
|
|
33
|
+
checkpoint_continue: "¿Continuar {minutes} minutos más?",
|
|
34
|
+
checkpoint_options: "1. Continuar (5 min)\n2. Continuar hasta terminar\n3. Tiempo personalizado\n4. Parar",
|
|
35
|
+
preflight_passed: "Preflight superado — todas las comprobaciones OK",
|
|
36
|
+
pipeline_iteration: "Iteración {current}/{max}",
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Resolve a message template by key and language, interpolating parameters.
|
|
42
|
+
* Falls back to English, then to the raw key if not found.
|
|
43
|
+
*
|
|
44
|
+
* @param {string} key - Message key (e.g. "solomon_conflict")
|
|
45
|
+
* @param {string} [lang="en"] - 2-letter language code
|
|
46
|
+
* @param {object} [params={}] - Interpolation values (e.g. {stage: "reviewer"})
|
|
47
|
+
* @returns {string}
|
|
48
|
+
*/
|
|
49
|
+
export function msg(key, lang = "en", params = {}) {
|
|
50
|
+
const template = MESSAGES[lang]?.[key] || MESSAGES.en[key] || key;
|
|
51
|
+
return template.replaceAll(/\{(\w+)\}/g, (_, k) => params[k] ?? `{${k}}`);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Extract the language code from a Karajan config object.
|
|
56
|
+
* @param {object} [config] - Karajan config
|
|
57
|
+
* @returns {string} 2-letter language code
|
|
58
|
+
*/
|
|
59
|
+
export function getLang(config) {
|
|
60
|
+
return config?.language || "en";
|
|
61
|
+
}
|