@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,315 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* addyosmani/agent-skills catalog provider (KJC-TSK-0327).
|
|
3
|
+
*
|
|
4
|
+
* Fetches and caches the addyosmani/agent-skills repository (20+ process
|
|
5
|
+
* skills: TDD, code-review, security, performance, git-workflow, debugging,
|
|
6
|
+
* CI/CD, docs, spec-driven, planning...) and exposes them as a first-class
|
|
7
|
+
* skill source for Karajan's pipeline.
|
|
8
|
+
*
|
|
9
|
+
* This catalog is ORTHOGONAL to the OpenSkills marketplace (which hosts stack
|
|
10
|
+
* skills like astro, react, prisma, python-data). Together they cover:
|
|
11
|
+
* - addyosmani → lifecycle/process skills mapped per role
|
|
12
|
+
* - OpenSkills → stack/framework skills detected from task + deps
|
|
13
|
+
* - local skills → project-specific skills under .claude/skills
|
|
14
|
+
*
|
|
15
|
+
* Lifecycle:
|
|
16
|
+
* 1. ensureCatalog() – clone (depth=1) on first use
|
|
17
|
+
* 2. refreshIfStale() – git pull when older than TTL (default 7d)
|
|
18
|
+
* 3. loadSkillBySlug() – read /skills/<slug>/SKILL.md from disk
|
|
19
|
+
* 4. listAvailableSlugs() – enumerate the /skills/ directory
|
|
20
|
+
*
|
|
21
|
+
* Degradation contract: when git is missing, the network is unreachable, or
|
|
22
|
+
* the catalog directory is malformed, every exported function returns safe
|
|
23
|
+
* empty values and logs a warning. The pipeline NEVER blocks on this module.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import fs from "node:fs/promises";
|
|
27
|
+
import path from "node:path";
|
|
28
|
+
import { runCommand } from "../utils/process.js";
|
|
29
|
+
import { getKarajanHome } from "../utils/paths.js";
|
|
30
|
+
|
|
31
|
+
const REPO_URL = "https://github.com/addyosmani/agent-skills.git";
|
|
32
|
+
const CATALOG_DIR_NAME = "agent-skills";
|
|
33
|
+
const SKILLS_SUBDIR = "skills";
|
|
34
|
+
const SKILL_FILE = "SKILL.md";
|
|
35
|
+
const DEFAULT_REFRESH_MS = 7 * 24 * 60 * 60 * 1000; // 7 days
|
|
36
|
+
const META_FILENAME = ".karajan-catalog-meta.json";
|
|
37
|
+
|
|
38
|
+
const FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Absolute path to the cached catalog inside ~/.karajan/.
|
|
42
|
+
* @returns {string}
|
|
43
|
+
*/
|
|
44
|
+
export function getCatalogRoot() {
|
|
45
|
+
return path.join(getKarajanHome(), CATALOG_DIR_NAME);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function getSkillsRoot() {
|
|
49
|
+
return path.join(getCatalogRoot(), SKILLS_SUBDIR);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function getMetaPath() {
|
|
53
|
+
return path.join(getCatalogRoot(), META_FILENAME);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async function pathExists(p) {
|
|
57
|
+
try {
|
|
58
|
+
await fs.access(p);
|
|
59
|
+
return true;
|
|
60
|
+
} catch {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async function readMeta() {
|
|
66
|
+
try {
|
|
67
|
+
const raw = await fs.readFile(getMetaPath(), "utf8");
|
|
68
|
+
return JSON.parse(raw);
|
|
69
|
+
} catch {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async function writeMeta(meta) {
|
|
75
|
+
await fs.mkdir(getCatalogRoot(), { recursive: true });
|
|
76
|
+
await fs.writeFile(getMetaPath(), JSON.stringify(meta, null, 2), "utf8");
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Check whether `git` is on PATH. Cached per-process.
|
|
81
|
+
* @returns {Promise<boolean>}
|
|
82
|
+
*/
|
|
83
|
+
let _gitAvailable = null;
|
|
84
|
+
export async function isGitAvailable() {
|
|
85
|
+
if (_gitAvailable !== null) return _gitAvailable;
|
|
86
|
+
try {
|
|
87
|
+
const result = await runCommand("git", ["--version"], { timeout: 5_000 });
|
|
88
|
+
_gitAvailable = result.exitCode === 0;
|
|
89
|
+
} catch {
|
|
90
|
+
_gitAvailable = false;
|
|
91
|
+
}
|
|
92
|
+
return _gitAvailable;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Internal: reset the cached probe (tests use this to re-evaluate git presence).
|
|
96
|
+
export function __resetGitProbe() {
|
|
97
|
+
_gitAvailable = null;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Clone the addyosmani/agent-skills repo (shallow) if it does not already
|
|
102
|
+
* exist locally. No-op when it is already present.
|
|
103
|
+
*
|
|
104
|
+
* @param {{ repoUrl?: string, logger?: object }} [opts]
|
|
105
|
+
* @returns {Promise<{ok: boolean, path?: string, error?: string, skipped?: boolean}>}
|
|
106
|
+
*/
|
|
107
|
+
export async function ensureCatalog(opts = {}) {
|
|
108
|
+
const { repoUrl = REPO_URL, logger } = opts;
|
|
109
|
+
const root = getCatalogRoot();
|
|
110
|
+
|
|
111
|
+
if (await pathExists(path.join(root, ".git"))) {
|
|
112
|
+
return { ok: true, path: root, skipped: true };
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (!(await isGitAvailable())) {
|
|
116
|
+
logger?.warn?.("addyosmani-catalog: git not available — skipping catalog bootstrap");
|
|
117
|
+
return { ok: false, error: "git not available" };
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
await fs.mkdir(path.dirname(root), { recursive: true });
|
|
121
|
+
|
|
122
|
+
const result = await runCommand(
|
|
123
|
+
"git",
|
|
124
|
+
["clone", "--depth", "1", repoUrl, root],
|
|
125
|
+
{ timeout: 120_000 }
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
if (result.exitCode !== 0) {
|
|
129
|
+
const stderr = (result.stderr || "").trim();
|
|
130
|
+
logger?.warn?.(`addyosmani-catalog: clone failed — ${stderr}`);
|
|
131
|
+
return { ok: false, error: stderr || `clone failed (exit ${result.exitCode})` };
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
await writeMeta({
|
|
135
|
+
repoUrl,
|
|
136
|
+
clonedAt: new Date().toISOString(),
|
|
137
|
+
lastPullAt: new Date().toISOString(),
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
return { ok: true, path: root };
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Refresh the catalog via `git pull` when the cached copy is older than
|
|
145
|
+
* `refreshMs`. When the catalog does not exist yet, delegates to
|
|
146
|
+
* ensureCatalog().
|
|
147
|
+
*
|
|
148
|
+
* @param {{ refreshMs?: number, repoUrl?: string, force?: boolean, logger?: object }} [opts]
|
|
149
|
+
* @returns {Promise<{ok: boolean, action: "cloned"|"pulled"|"reset"|"fresh"|"skipped", error?: string}>}
|
|
150
|
+
*/
|
|
151
|
+
export async function refreshIfStale(opts = {}) {
|
|
152
|
+
const { refreshMs = DEFAULT_REFRESH_MS, repoUrl = REPO_URL, force = false, logger } = opts;
|
|
153
|
+
const root = getCatalogRoot();
|
|
154
|
+
|
|
155
|
+
if (!(await pathExists(path.join(root, ".git")))) {
|
|
156
|
+
const cloneResult = await ensureCatalog({ repoUrl, logger });
|
|
157
|
+
return cloneResult.ok
|
|
158
|
+
? { ok: true, action: "cloned" }
|
|
159
|
+
: { ok: false, action: "skipped", error: cloneResult.error };
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const meta = await readMeta();
|
|
163
|
+
const lastPull = meta?.lastPullAt ? Date.parse(meta.lastPullAt) : 0;
|
|
164
|
+
const age = Date.now() - (Number.isFinite(lastPull) ? lastPull : 0);
|
|
165
|
+
if (!force && age < refreshMs) {
|
|
166
|
+
return { ok: true, action: "fresh" };
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (!(await isGitAvailable())) {
|
|
170
|
+
logger?.warn?.("addyosmani-catalog: git unavailable — using stale cache");
|
|
171
|
+
return { ok: true, action: "skipped" };
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const pullResult = await runCommand(
|
|
175
|
+
"git",
|
|
176
|
+
["-C", root, "pull", "--ff-only", "--depth", "1"],
|
|
177
|
+
{ timeout: 60_000 }
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
let action = "pulled";
|
|
181
|
+
if (pullResult.exitCode !== 0) {
|
|
182
|
+
// The cached catalog is read-only (we never commit to it), so a
|
|
183
|
+
// non-fast-forward result is virtually always upstream rewriting
|
|
184
|
+
// history with `git push --force` — see KJC-BUG-0033 / N3-2 (the
|
|
185
|
+
// user hit this on 2026-05-07 when addyosmani force-pushed his
|
|
186
|
+
// skills repo). Recover by fetching shallow and hard-resetting to
|
|
187
|
+
// FETCH_HEAD: there's nothing local to lose.
|
|
188
|
+
const fetchResult = await runCommand(
|
|
189
|
+
"git",
|
|
190
|
+
["-C", root, "fetch", "--depth", "1", "origin", "HEAD"],
|
|
191
|
+
{ timeout: 60_000 }
|
|
192
|
+
);
|
|
193
|
+
const resetResult = fetchResult.exitCode === 0
|
|
194
|
+
? await runCommand("git", ["-C", root, "reset", "--hard", "FETCH_HEAD"], { timeout: 30_000 })
|
|
195
|
+
: { exitCode: fetchResult.exitCode, stderr: fetchResult.stderr };
|
|
196
|
+
|
|
197
|
+
if (resetResult.exitCode !== 0) {
|
|
198
|
+
const pullErr = (pullResult.stderr || "").trim();
|
|
199
|
+
const recoveryErr = (resetResult.stderr || "").trim();
|
|
200
|
+
const combined = recoveryErr ? `${pullErr} | recovery: ${recoveryErr}` : pullErr;
|
|
201
|
+
logger?.warn?.(`addyosmani-catalog: git pull failed — ${combined} (keeping stale cache)`);
|
|
202
|
+
return { ok: false, action: "skipped", error: combined };
|
|
203
|
+
}
|
|
204
|
+
action = "reset";
|
|
205
|
+
logger?.info?.("addyosmani-catalog: ff-only failed, recovered via fetch+reset (upstream force-pushed)");
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
await writeMeta({
|
|
209
|
+
...(meta || {}),
|
|
210
|
+
repoUrl,
|
|
211
|
+
lastPullAt: new Date().toISOString(),
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
return { ok: true, action };
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Parse YAML frontmatter for name + description (we intentionally avoid a
|
|
219
|
+
* YAML dep — a tiny regex is enough for the fields we care about and stays
|
|
220
|
+
* compatible with addyosmani's SKILL.md format).
|
|
221
|
+
*
|
|
222
|
+
* @param {string} raw
|
|
223
|
+
* @returns {{name: string|null, description: string|null, body: string}}
|
|
224
|
+
*/
|
|
225
|
+
export function parseFrontmatter(raw) {
|
|
226
|
+
if (!raw) return { name: null, description: null, body: "" };
|
|
227
|
+
const match = raw.match(FRONTMATTER_RE);
|
|
228
|
+
if (!match) {
|
|
229
|
+
return { name: null, description: null, body: raw };
|
|
230
|
+
}
|
|
231
|
+
const frontmatter = match[1];
|
|
232
|
+
const body = match[2] || "";
|
|
233
|
+
|
|
234
|
+
const nameMatch = frontmatter.match(/^name:\s*(.+)$/m);
|
|
235
|
+
const descMatch = frontmatter.match(/^description:\s*(.+)$/m);
|
|
236
|
+
|
|
237
|
+
return {
|
|
238
|
+
name: nameMatch ? stripQuotes(nameMatch[1]) : null,
|
|
239
|
+
description: descMatch ? stripQuotes(descMatch[1]) : null,
|
|
240
|
+
body,
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function stripQuotes(value) {
|
|
245
|
+
const trimmed = value.trim();
|
|
246
|
+
if ((trimmed.startsWith('"') && trimmed.endsWith('"'))
|
|
247
|
+
|| (trimmed.startsWith("'") && trimmed.endsWith("'"))) {
|
|
248
|
+
return trimmed.slice(1, -1);
|
|
249
|
+
}
|
|
250
|
+
return trimmed;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Enumerate available skill slugs under /skills/.
|
|
255
|
+
*
|
|
256
|
+
* @returns {Promise<string[]>}
|
|
257
|
+
*/
|
|
258
|
+
export async function listAvailableSlugs() {
|
|
259
|
+
const root = getSkillsRoot();
|
|
260
|
+
let entries;
|
|
261
|
+
try {
|
|
262
|
+
entries = await fs.readdir(root, { withFileTypes: true });
|
|
263
|
+
} catch {
|
|
264
|
+
return [];
|
|
265
|
+
}
|
|
266
|
+
return entries
|
|
267
|
+
.filter((e) => e.isDirectory())
|
|
268
|
+
.map((e) => e.name)
|
|
269
|
+
.filter((name) => !name.startsWith("."))
|
|
270
|
+
.sort();
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Load a skill by its slug. Returns null when the slug is not present or the
|
|
275
|
+
* SKILL.md file is missing/unreadable.
|
|
276
|
+
*
|
|
277
|
+
* @param {string} slug
|
|
278
|
+
* @returns {Promise<{slug: string, name: string, description: string|null, content: string, path: string}|null>}
|
|
279
|
+
*/
|
|
280
|
+
export async function loadSkillBySlug(slug) {
|
|
281
|
+
if (!slug || typeof slug !== "string") return null;
|
|
282
|
+
const safeSlug = slug.trim().replaceAll(/[^A-Za-z0-9._-]/g, "");
|
|
283
|
+
if (!safeSlug) return null;
|
|
284
|
+
|
|
285
|
+
const skillPath = path.join(getSkillsRoot(), safeSlug, SKILL_FILE);
|
|
286
|
+
let raw;
|
|
287
|
+
try {
|
|
288
|
+
raw = await fs.readFile(skillPath, "utf8");
|
|
289
|
+
} catch {
|
|
290
|
+
return null;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const parsed = parseFrontmatter(raw);
|
|
294
|
+
return {
|
|
295
|
+
slug: safeSlug,
|
|
296
|
+
name: parsed.name || safeSlug,
|
|
297
|
+
description: parsed.description,
|
|
298
|
+
content: raw,
|
|
299
|
+
path: skillPath,
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Load multiple skills by slug in parallel. Silently drops missing entries.
|
|
305
|
+
*
|
|
306
|
+
* @param {string[]} slugs
|
|
307
|
+
* @returns {Promise<Array<{slug: string, name: string, description: string|null, content: string, path: string}>>}
|
|
308
|
+
*/
|
|
309
|
+
export async function loadSkillsBySlugs(slugs = []) {
|
|
310
|
+
if (!Array.isArray(slugs) || slugs.length === 0) return [];
|
|
311
|
+
const results = await Promise.all(slugs.map((s) => loadSkillBySlug(s)));
|
|
312
|
+
return results.filter(Boolean);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
export { DEFAULT_REFRESH_MS, REPO_URL };
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Role → addyosmani/agent-skills slug mapping (KJC-TSK-0327).
|
|
3
|
+
*
|
|
4
|
+
* The addyosmani catalog is process-oriented (not stack-oriented), so the
|
|
5
|
+
* natural keying is by Karajan role: reviewer wants code-review workflows,
|
|
6
|
+
* tester wants TDD, security wants hardening, etc.
|
|
7
|
+
*
|
|
8
|
+
* Task-text triggers complement the role map: e.g. a task that mentions
|
|
9
|
+
* "performance" or "Core Web Vitals" pulls in performance-optimization,
|
|
10
|
+
* regardless of which role is running.
|
|
11
|
+
*
|
|
12
|
+
* Every slug listed here MUST exist in the upstream repo at:
|
|
13
|
+
* https://github.com/addyosmani/agent-skills/tree/main/skills/<slug>
|
|
14
|
+
* If upstream renames or removes a slug, loadSkillBySlug() degrades silently
|
|
15
|
+
* (returns null) and the pipeline continues without blocking.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Role → array of upstream slugs.
|
|
20
|
+
* Keep slugs lowercase-hyphenated, matching addyosmani's directory names.
|
|
21
|
+
*/
|
|
22
|
+
export const ROLE_TO_ADDYOSMANI_SLUGS = {
|
|
23
|
+
// The coder role benefits from broad process context: how to iterate,
|
|
24
|
+
// how to engineer context, and how to debug when things break.
|
|
25
|
+
coder: [
|
|
26
|
+
"incremental-implementation",
|
|
27
|
+
"source-driven-development",
|
|
28
|
+
"context-engineering",
|
|
29
|
+
"debugging-and-error-recovery",
|
|
30
|
+
],
|
|
31
|
+
|
|
32
|
+
// Reviewer wants the review + simplification workflows.
|
|
33
|
+
reviewer: [
|
|
34
|
+
"code-review-and-quality",
|
|
35
|
+
"code-simplification",
|
|
36
|
+
],
|
|
37
|
+
|
|
38
|
+
// Tester focuses on TDD and browser verification.
|
|
39
|
+
tester: [
|
|
40
|
+
"test-driven-development",
|
|
41
|
+
"browser-testing-with-devtools",
|
|
42
|
+
],
|
|
43
|
+
|
|
44
|
+
// Security role uses the dedicated hardening workflow.
|
|
45
|
+
security: [
|
|
46
|
+
"security-and-hardening",
|
|
47
|
+
],
|
|
48
|
+
|
|
49
|
+
// Architect covers spec-driven, API design and planning skills.
|
|
50
|
+
architect: [
|
|
51
|
+
"spec-driven-development",
|
|
52
|
+
"api-and-interface-design",
|
|
53
|
+
"planning-and-task-breakdown",
|
|
54
|
+
],
|
|
55
|
+
|
|
56
|
+
// Planner overlaps with architect but leans on task breakdown and spec.
|
|
57
|
+
planner: [
|
|
58
|
+
"planning-and-task-breakdown",
|
|
59
|
+
"spec-driven-development",
|
|
60
|
+
],
|
|
61
|
+
|
|
62
|
+
// Researcher / discover benefit from the idea-refine workflow.
|
|
63
|
+
researcher: [
|
|
64
|
+
"idea-refine",
|
|
65
|
+
],
|
|
66
|
+
discover: [
|
|
67
|
+
"idea-refine",
|
|
68
|
+
],
|
|
69
|
+
|
|
70
|
+
// Impeccable (UI/UX audit) uses the frontend engineering workflow.
|
|
71
|
+
impeccable: [
|
|
72
|
+
"frontend-ui-engineering",
|
|
73
|
+
],
|
|
74
|
+
|
|
75
|
+
// Refactorer uses simplification and debugging workflows.
|
|
76
|
+
refactorer: [
|
|
77
|
+
"code-simplification",
|
|
78
|
+
"debugging-and-error-recovery",
|
|
79
|
+
],
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Task-text patterns → addyosmani slug. These are applied in addition to the
|
|
84
|
+
* role map, so a reviewer task that mentions "performance" also pulls in the
|
|
85
|
+
* performance-optimization skill.
|
|
86
|
+
*/
|
|
87
|
+
export const TASK_PATTERN_TO_SLUG = [
|
|
88
|
+
{ pattern: /\bperformance\b|\bcore\s+web\s+vitals\b|\blcp\b|\bcls\b|\binp\b/i, slug: "performance-optimization" },
|
|
89
|
+
{ pattern: /\bsecurity\b|\bhardening\b|\bauth(entication|orization)?\b|\bxss\b|\bcsrf\b|\binjection\b/i, slug: "security-and-hardening" },
|
|
90
|
+
{ pattern: /\btdd\b|\btest[- ]driven\b/i, slug: "test-driven-development" },
|
|
91
|
+
{ pattern: /\bfrontend\b|\bui\b|\bux\b|\bcss\b|\bresponsive\b/i, slug: "frontend-ui-engineering" },
|
|
92
|
+
// Accessibility (a11y / WCAG / ARIA / screen reader / keyboard nav).
|
|
93
|
+
// No dedicated addyosmani skill exists yet for a11y; until one ships,
|
|
94
|
+
// route to frontend-ui-engineering — the closest authoritative source
|
|
95
|
+
// for WCAG-aware UI work. When upstream ships an a11y skill, change
|
|
96
|
+
// only the `slug` field here.
|
|
97
|
+
{ pattern: /\baccessibility\b|\ba11y\b|\bwcag\b|\baria\b|\bscreen[\s-]?reader\b|\bkeyboard[\s-]?nav(igation)?\b/i, slug: "frontend-ui-engineering" },
|
|
98
|
+
{ pattern: /\bapi\b|\bendpoint\b|\binterface\s+design\b|\bopenapi\b|\brest\b|\bgraphql\b/i, slug: "api-and-interface-design" },
|
|
99
|
+
{ pattern: /\bci\b|\bcd\b|\bci\/cd\b|\bpipeline\b|\bgithub\s+actions\b|\bworkflow\b/i, slug: "ci-cd-and-automation" },
|
|
100
|
+
{ pattern: /\bgit\b|\bcommit\b|\bbranch\b|\bmerge\b|\bversioning\b|\bsemver\b/i, slug: "git-workflow-and-versioning" },
|
|
101
|
+
{ pattern: /\bdebug\b|\berror\s+recovery\b|\bstack\s+trace\b/i, slug: "debugging-and-error-recovery" },
|
|
102
|
+
{ pattern: /\bdeprecat|\bmigrat/i, slug: "deprecation-and-migration" },
|
|
103
|
+
{ pattern: /\bdocs?\b|\badr\b|\breadme\b|\bdocumentation\b/i, slug: "documentation-and-adrs" },
|
|
104
|
+
{ pattern: /\brelease\b|\blaunch\b|\bship\b/i, slug: "shipping-and-launch" },
|
|
105
|
+
{ pattern: /\bspec\b|\bspecification\b|\bprd\b/i, slug: "spec-driven-development" },
|
|
106
|
+
{ pattern: /\bidea\b|\brefine\b|\bdiscover/i, slug: "idea-refine" },
|
|
107
|
+
{ pattern: /\bbrowser\s+test|\bdevtools\b|\bchrome\s+devtools\b/i, slug: "browser-testing-with-devtools" },
|
|
108
|
+
];
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Resolve the set of addyosmani slugs that apply to a given (role, task)
|
|
112
|
+
* tuple. Returns a deduped array preserving role-first ordering (so role
|
|
113
|
+
* skills appear before task-inferred ones in the prompt).
|
|
114
|
+
*
|
|
115
|
+
* @param {{role?: string|null, task?: string|null}} args
|
|
116
|
+
* @returns {string[]}
|
|
117
|
+
*/
|
|
118
|
+
export function resolveAddyosmaniSlugs({ role = null, task = null } = {}) {
|
|
119
|
+
const out = [];
|
|
120
|
+
const seen = new Set();
|
|
121
|
+
|
|
122
|
+
const push = (slug) => {
|
|
123
|
+
if (!slug || seen.has(slug)) return;
|
|
124
|
+
seen.add(slug);
|
|
125
|
+
out.push(slug);
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
if (role && ROLE_TO_ADDYOSMANI_SLUGS[role]) {
|
|
129
|
+
for (const slug of ROLE_TO_ADDYOSMANI_SLUGS[role]) push(slug);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (task && typeof task === "string") {
|
|
133
|
+
for (const { pattern, slug } of TASK_PATTERN_TO_SLUG) {
|
|
134
|
+
if (pattern.test(task)) push(slug);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return out;
|
|
139
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenSkills CLI client.
|
|
3
|
+
* Wraps `npx openskills` commands for installing, removing, listing, and reading skills.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { runCommand } from "../utils/process.js";
|
|
7
|
+
|
|
8
|
+
const NPX = "npx";
|
|
9
|
+
const PKG = "openskills";
|
|
10
|
+
|
|
11
|
+
function buildCwd(projectDir) {
|
|
12
|
+
return projectDir || process.cwd();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Check whether the openskills CLI is available.
|
|
17
|
+
* @returns {Promise<boolean>}
|
|
18
|
+
*/
|
|
19
|
+
export async function isOpenSkillsAvailable() {
|
|
20
|
+
try {
|
|
21
|
+
const result = await runCommand(NPX, [PKG, "--version"], {
|
|
22
|
+
timeout: 15_000
|
|
23
|
+
});
|
|
24
|
+
return result.exitCode === 0;
|
|
25
|
+
} catch { /* openskills CLI not available */
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Install a skill from a marketplace name, GitHub URL, or local path.
|
|
32
|
+
* @param {string} source - Skill source identifier.
|
|
33
|
+
* @param {object} opts
|
|
34
|
+
* @param {string} [opts.projectDir] - Working directory.
|
|
35
|
+
* @param {boolean} [opts.global] - Install globally (~/.agent/skills/).
|
|
36
|
+
* @returns {Promise<{ok: boolean, name?: string, error?: string}>}
|
|
37
|
+
*/
|
|
38
|
+
export async function installSkill(source, { projectDir, global: isGlobal } = {}) {
|
|
39
|
+
if (!source) {
|
|
40
|
+
return { ok: false, error: "source is required for install" };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const args = [PKG, "install", source];
|
|
44
|
+
if (isGlobal) args.push("--global");
|
|
45
|
+
|
|
46
|
+
const result = await runCommand(NPX, args, {
|
|
47
|
+
cwd: buildCwd(projectDir),
|
|
48
|
+
timeout: 60_000
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
if (result.exitCode !== 0) {
|
|
52
|
+
const stderr = (result.stderr || "").trim();
|
|
53
|
+
return { ok: false, error: stderr || `install failed (exit ${result.exitCode})` };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Try to extract the skill name from stdout
|
|
57
|
+
const output = (result.stdout || "").trim();
|
|
58
|
+
const nameMatch = output.match(/installed\s+(?:skill\s+)?["']?([^\s"']+)["']?/i)
|
|
59
|
+
|| output.match(/([^\s/]+)\s*$/);
|
|
60
|
+
const name = nameMatch ? nameMatch[1] : source;
|
|
61
|
+
|
|
62
|
+
return { ok: true, name };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Remove an installed skill by name.
|
|
67
|
+
* @param {string} name - Skill name.
|
|
68
|
+
* @param {object} opts
|
|
69
|
+
* @param {string} [opts.projectDir] - Working directory.
|
|
70
|
+
* @returns {Promise<{ok: boolean, error?: string}>}
|
|
71
|
+
*/
|
|
72
|
+
export async function removeSkill(name, { projectDir } = {}) {
|
|
73
|
+
if (!name) {
|
|
74
|
+
return { ok: false, error: "name is required for remove" };
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const result = await runCommand(NPX, [PKG, "remove", name], {
|
|
78
|
+
cwd: buildCwd(projectDir),
|
|
79
|
+
timeout: 30_000
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
if (result.exitCode !== 0) {
|
|
83
|
+
const stderr = (result.stderr || "").trim();
|
|
84
|
+
return { ok: false, error: stderr || `remove failed (exit ${result.exitCode})` };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return { ok: true };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* List installed skills.
|
|
92
|
+
* @param {object} opts
|
|
93
|
+
* @param {string} [opts.projectDir] - Working directory.
|
|
94
|
+
* @returns {Promise<{ok: boolean, skills?: Array<{name: string, source?: string, scope?: string}>, error?: string}>}
|
|
95
|
+
*/
|
|
96
|
+
export async function listSkills({ projectDir } = {}) {
|
|
97
|
+
const result = await runCommand(NPX, [PKG, "list", "--json"], {
|
|
98
|
+
cwd: buildCwd(projectDir),
|
|
99
|
+
timeout: 30_000
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
if (result.exitCode !== 0) {
|
|
103
|
+
// Fallback: try without --json
|
|
104
|
+
const fallback = await runCommand(NPX, [PKG, "list"], {
|
|
105
|
+
cwd: buildCwd(projectDir),
|
|
106
|
+
timeout: 30_000
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
if (fallback.exitCode !== 0) {
|
|
110
|
+
const stderr = (fallback.stderr || "").trim();
|
|
111
|
+
return { ok: false, error: stderr || `list failed (exit ${fallback.exitCode})` };
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Parse text output: each line is a skill name
|
|
115
|
+
const lines = (fallback.stdout || "").split("\n").map(l => l.trim()).filter(Boolean);
|
|
116
|
+
const skills = lines.map(line => ({ name: line }));
|
|
117
|
+
return { ok: true, skills };
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Parse JSON output
|
|
121
|
+
const stdout = (result.stdout || "").trim();
|
|
122
|
+
try {
|
|
123
|
+
const parsed = JSON.parse(stdout);
|
|
124
|
+
const skills = Array.isArray(parsed) ? parsed : (parsed.skills || []);
|
|
125
|
+
return { ok: true, skills };
|
|
126
|
+
} catch {
|
|
127
|
+
// If JSON parse fails, treat as text
|
|
128
|
+
const lines = stdout.split("\n").map(l => l.trim()).filter(Boolean);
|
|
129
|
+
const skills = lines.map(line => ({ name: line }));
|
|
130
|
+
return { ok: true, skills };
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Read a skill's content by name.
|
|
136
|
+
* @param {string} name - Skill name.
|
|
137
|
+
* @param {object} opts
|
|
138
|
+
* @param {string} [opts.projectDir] - Working directory.
|
|
139
|
+
* @returns {Promise<{ok: boolean, content?: string, error?: string}>}
|
|
140
|
+
*/
|
|
141
|
+
export async function readSkill(name, { projectDir } = {}) {
|
|
142
|
+
if (!name) {
|
|
143
|
+
return { ok: false, error: "name is required for read" };
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const result = await runCommand(NPX, [PKG, "read", name], {
|
|
147
|
+
cwd: buildCwd(projectDir),
|
|
148
|
+
timeout: 30_000
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
if (result.exitCode !== 0) {
|
|
152
|
+
const stderr = (result.stderr || "").trim();
|
|
153
|
+
return { ok: false, error: stderr || `read failed (exit ${result.exitCode})` };
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return { ok: true, content: (result.stdout || "").trim() };
|
|
157
|
+
}
|