karajan-code 4.70.3 → 5.0.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/README.md +2 -2
- package/package.json +6 -14
- package/packages/hu-board/package.json +1 -1
- package/packages/hu-board/public/app.js +4 -18
- package/packages/hu-board/public/index.html +5 -2
- package/packages/hu-board/public/styles.css +26 -0
- package/packages/hu-board/public/utils/api.js +0 -74
- package/packages/hu-board/public/utils/board-tour.js +62 -0
- package/packages/hu-board/public/utils/board-view.js +49 -144
- package/packages/hu-board/public/utils/command-launcher.js +8 -70
- package/packages/hu-board/public/utils/formatters.js +10 -0
- package/packages/hu-board/public/utils/governance-view.js +13 -1
- package/packages/hu-board/public/utils/hu-actions.js +17 -68
- package/packages/hu-board/public/utils/init-listeners.js +7 -8
- package/packages/hu-board/public/utils/log-panel.js +3 -16
- package/packages/hu-board/public/utils/maggle-mode.js +2 -12
- package/packages/hu-board/public/utils/modals.js +7 -0
- package/packages/hu-board/public/utils/project-picker-view.js +1 -1
- package/packages/hu-board/public/utils/server-push.js +3 -22
- package/packages/hu-board/public/utils/shared-board-notice.js +33 -0
- package/packages/hu-board/public/utils/story-detail-view.js +5 -19
- package/packages/hu-board/src/cleanup-zombies.js +0 -1
- package/packages/hu-board/src/command-runner.js +36 -25
- package/packages/hu-board/src/db-connection.js +282 -0
- package/packages/hu-board/src/db-paths.js +113 -0
- package/packages/hu-board/src/db-queries.js +188 -0
- package/packages/hu-board/src/db-tombstones.js +51 -0
- package/packages/hu-board/src/db.js +28 -619
- package/packages/hu-board/src/ephemeral-cleaner.js +2 -3
- package/packages/hu-board/src/hu-zombie-reaper.js +5 -1
- package/packages/hu-board/src/plan-mutations.js +3 -153
- package/packages/hu-board/src/plans-service.js +55 -0
- package/packages/hu-board/src/routes/api/commands.js +122 -0
- package/packages/hu-board/src/routes/api/plans.js +55 -0
- package/packages/hu-board/src/routes/api/projects.js +267 -0
- package/packages/hu-board/src/routes/api/prompts.js +135 -0
- package/packages/hu-board/src/routes/api/sessions.js +95 -0
- package/packages/hu-board/src/routes/api/stories.js +183 -0
- package/packages/hu-board/src/routes/api/system.js +241 -0
- package/packages/hu-board/src/routes/api/tombstones.js +38 -0
- package/packages/hu-board/src/routes/api.js +24 -1371
- package/packages/hu-board/src/routes/governance.js +23 -1
- package/packages/hu-board/src/routes/lanes.js +40 -0
- package/packages/hu-board/src/routes/rag.js +4 -3
- package/packages/hu-board/src/server.js +20 -34
- package/packages/hu-board/src/sync-files.js +318 -0
- package/packages/hu-board/src/sync-project.js +99 -0
- package/packages/hu-board/src/sync.js +22 -566
- package/packages/hu-board/src/zombie-reaper.js +1 -1
- package/scripts/dual-publish.mjs +19 -3
- package/scripts/postinstall.js +15 -2
- package/scripts/verify-pack-mcp.mjs +11 -7
- package/scripts/verify-pack.mjs +4 -4
- package/src/audit/audit-history.js +3 -2
- package/src/audit/dead-exports.js +68 -59
- package/src/audit/deterministic-summary.js +33 -13
- package/src/audit/npm-signatures.js +41 -0
- package/src/audit/sbom.js +35 -0
- package/src/checks/agent-token.js +112 -0
- package/src/checks/ai-surface.js +9 -7
- package/src/checks/config-files.js +8 -7
- package/src/checks/dir-setup.js +34 -1
- package/src/checks/native-build.js +21 -39
- package/src/checks/runner.js +128 -142
- package/src/cli/advanced-commands.js +6 -6
- package/src/cli/register-meta.js +42 -82
- package/src/cli/register-pipeline.js +8 -140
- package/src/cli/register-plan.js +9 -100
- package/src/cli/retired-commands.js +49 -0
- package/src/cli.js +18 -5
- package/src/commands/agent-run.js +40 -26
- package/src/commands/audit.js +127 -124
- package/src/commands/board.js +5 -9
- package/src/commands/check.js +29 -16
- package/src/commands/doctor.js +2 -0
- package/src/commands/env.js +176 -148
- package/src/commands/go.js +76 -55
- package/src/commands/harden.js +105 -86
- package/src/commands/hu-start.js +52 -0
- package/src/commands/hu.js +288 -221
- package/src/commands/identity.js +111 -78
- package/src/commands/init-atril.js +47 -0
- package/src/commands/init.js +11 -40
- package/src/commands/install-tools.js +70 -85
- package/src/commands/main-guard.js +78 -0
- package/src/commands/policy.js +226 -184
- package/src/commands/qmd.js +27 -21
- package/src/commands/rag.js +75 -48
- package/src/commands/review-gate.js +422 -339
- package/src/commands/start.js +4 -5
- package/src/commands/steward.js +96 -47
- package/src/commands/tournament.js +46 -37
- package/src/commands/worktree.js +94 -25
- package/src/config/loader.js +34 -17
- package/src/config/overrides.js +2 -1
- package/src/config/secrets.js +36 -0
- package/src/config.js +1 -0
- package/src/environment/adr.js +16 -2
- package/src/environment/board-access.js +11 -9
- package/src/git/karajan-label.js +20 -8
- package/src/guards/main-guard.js +54 -0
- package/src/harden/branch-protection.js +36 -3
- package/src/harden/hook-templates.js +16 -1
- package/src/harden/sentinel/posttooluse.mjs +18 -6
- package/src/harden/sentinel/pretooluse-sentinel.mjs +81 -35
- package/src/harden/sentinel/sentinel-lib.mjs +149 -23
- package/src/harden/sentinel/sentinel-shell.mjs +64 -0
- package/src/harden/sentinel/sessionstart.mjs +3 -2
- package/src/harden/sentinel/stop.mjs +5 -4
- package/src/harden/workflow-engine.js +12 -1
- package/src/harden/workflow-templates.js +1 -1
- package/src/hu/board-lookup.js +29 -0
- package/src/hu/gh-identity.js +23 -0
- package/src/hu/github-board.js +4 -2
- package/src/hu/lane-prune.js +15 -7
- package/src/hu/lane-setup.js +65 -0
- package/src/hu/lanes.js +66 -0
- package/src/hu/team-board-mirror.js +3 -2
- package/src/infrastructure/command-runner.js +1 -1
- package/src/infrastructure/file-system-service.js +1 -1
- package/src/mcp/handlers/direct-handlers.js +2 -292
- package/src/mcp/handlers/hu-handlers.js +44 -55
- package/src/mcp/handlers/management-handlers.js +2 -42
- package/src/mcp/server-handlers.js +16 -22
- package/src/mcp/tools.js +5 -200
- package/src/plan/lane-plans.js +54 -0
- package/src/plan/plan-store.js +7 -4
- package/src/policy/add.js +26 -12
- package/src/policy/adr-number-check.js +31 -0
- package/src/prompts/audit.js +299 -339
- package/src/prompts/card-context.js +10 -5
- package/src/prompts/reviewer.js +5 -2
- package/src/rag/auto-update.js +56 -43
- package/src/rag/bootstrap-index.js +28 -54
- package/src/rag/migrate.js +1 -1
- package/src/rag/onnx-fallback.js +2 -2
- package/src/rag/pid-lease.js +70 -0
- package/src/rag/project-store.js +2 -12
- package/src/review/card-first.js +57 -46
- package/src/review/dual-review.js +5 -4
- package/src/review/gate-gitignore.js +23 -4
- package/src/review/gate-hook.js +47 -0
- package/src/review/one-shot-review.js +51 -37
- package/src/review/publish-pr.js +18 -3
- package/src/review/repo-docs.js +73 -0
- package/src/review/repo-stack.js +59 -0
- package/src/review/reviewer-fallback.js +34 -3
- package/src/review/seal-commit.js +29 -0
- package/src/review/sonar-pregate.js +59 -44
- package/src/review/third-party-review.js +90 -16
- package/src/review/third-party-size.js +43 -0
- package/src/review/third-party-skills.js +54 -0
- package/src/review/verify-pr.js +2 -26
- package/src/roles/audit-role.js +106 -125
- package/src/skills/atril-skills.js +5 -4
- package/src/sonar/scanner.js +116 -101
- package/src/steward/invariants.js +5 -4
- package/src/steward/phantom-sweep.js +66 -0
- package/src/tournament/judge.js +60 -53
- package/src/utils/agent-home.js +33 -0
- package/src/utils/gh-account.js +37 -0
- package/src/utils/git.js +0 -13
- package/src/utils/home-migration.js +7 -1
- package/src/utils/main-checkout.js +53 -0
- package/src/utils/qmd-collection.js +3 -1
- package/src/utils/welcome.js +3 -3
- package/templates/{skills → atril/commands}/kj-architect.md +5 -0
- package/templates/{skills → atril/commands}/kj-audit.md +5 -0
- package/templates/{skills → atril/commands}/kj-board.md +5 -0
- package/templates/{skills → atril/commands}/kj-code.md +5 -0
- package/templates/{skills → atril/commands}/kj-csv-transform.md +5 -0
- package/templates/{skills → atril/commands}/kj-data-report.md +5 -0
- package/templates/{skills → atril/commands}/kj-discover.md +5 -0
- package/templates/{skills → atril/commands}/kj-rag-query.md +5 -0
- package/templates/{skills → atril/commands}/kj-review.md +5 -0
- package/templates/{skills → atril/commands}/kj-security.md +5 -0
- package/templates/{skills → atril/commands}/kj-sonar.md +5 -0
- package/templates/{skills → atril/commands}/kj-sql-analysis.md +5 -0
- package/templates/{skills → atril/commands}/kj-test.md +5 -0
- package/packages/hu-board/public/utils/run-launcher.js +0 -169
- package/packages/hu-board/src/run-tracker.js +0 -121
- package/src/activity-log.js +0 -59
- package/src/agents/host-agent.js +0 -38
- package/src/agents/model-registry.js +0 -142
- package/src/audit/plan-adherence.js +0 -224
- package/src/autonomy/arbiter-role.js +0 -71
- package/src/autonomy/arbiter.js +0 -22
- package/src/autonomy/decider.js +0 -18
- package/src/autonomy/decision-resolver.js +0 -58
- package/src/autonomy/outcome-report.js +0 -55
- package/src/autonomy/stage-ask.js +0 -30
- package/src/brain/decision-tracker.js +0 -125
- package/src/brain/decisor.js +0 -243
- package/src/brain/solomon-consult.js +0 -171
- package/src/brain/standby-scheduler.js +0 -8
- package/src/budget/comparison.js +0 -96
- package/src/canvas/parse-md.js +0 -238
- package/src/canvas/schema.js +0 -101
- package/src/canvas/to-flat.js +0 -85
- package/src/canvas/validate.js +0 -163
- package/src/ci/dispatch.js +0 -99
- package/src/ci/index.js +0 -3
- package/src/ci/pr-diff.js +0 -26
- package/src/cli/register-standby.js +0 -26
- package/src/commands/architect.js +0 -111
- package/src/commands/autorun.js +0 -49
- package/src/commands/researcher.js +0 -54
- package/src/commands/resume.js +0 -72
- package/src/commands/review.js +0 -89
- package/src/commands/run.js +0 -185
- package/src/commands/standby.js +0 -117
- package/src/commands/status.js +0 -36
- package/src/commands/triage.js +0 -78
- package/src/commands/undo.js +0 -62
- package/src/domains/domain-loader.js +0 -245
- package/src/domains/domain-registry.js +0 -140
- package/src/domains/domain-synthesizer.js +0 -129
- package/src/git/automation.js +0 -433
- package/src/git/coder-commit-guard.js +0 -40
- package/src/git/hu-automation.js +0 -243
- package/src/git/hu-snapshot.js +0 -10
- package/src/git/symlink-targets.js +0 -57
- package/src/golden/asserter.js +0 -92
- package/src/golden/loader.js +0 -52
- package/src/golden/runner.js +0 -92
- package/src/golden/schema.js +0 -41
- package/src/guards/duplicate-members.js +0 -86
- package/src/guards/intent-guard.js +0 -161
- package/src/guards/perf-guard.js +0 -126
- package/src/guards/policy-guard.js +0 -90
- package/src/guards/policy-resolver.js +0 -85
- package/src/guards/secret-redactor.js +0 -71
- package/src/hu/acceptance-runner.js +0 -138
- package/src/hu/lazy-planner.js +0 -109
- package/src/hu/parallel-executor.js +0 -94
- package/src/hu/routing-metrics.js +0 -17
- package/src/hu/split-validator.js +0 -143
- package/src/hu/splitting-detector.js +0 -158
- package/src/hu/splitting-generator.js +0 -175
- package/src/hu/store.js +0 -394
- package/src/infrastructure/mocks.js +0 -182
- package/src/mcp/handlers/run-handler.js +0 -318
- package/src/mcp/sovereignty-guard.js +0 -113
- package/src/mcp/tool-arg-normalizers.js +0 -16
- package/src/mutate/reviewer-signal.js +0 -76
- package/src/orchestrator/agent-fallback.js +0 -81
- package/src/orchestrator/brain-coordinator.js +0 -186
- package/src/orchestrator/ci-integration.js +0 -139
- package/src/orchestrator/config-init.js +0 -426
- package/src/orchestrator/direct-actions.js +0 -217
- package/src/orchestrator/drivers/error-recovery.js +0 -287
- package/src/orchestrator/drivers/init-context.js +0 -238
- package/src/orchestrator/drivers/iteration-loop.js +0 -382
- package/src/orchestrator/drivers/iteration-phases/coder-and-refactorer.js +0 -69
- package/src/orchestrator/drivers/iteration-phases/guards.js +0 -91
- package/src/orchestrator/drivers/iteration-phases/handle-approved.js +0 -29
- package/src/orchestrator/drivers/iteration-phases/quality-gates.js +0 -125
- package/src/orchestrator/drivers/iteration-phases/reviewer-gate.js +0 -62
- package/src/orchestrator/drivers/post-loop.js +0 -404
- package/src/orchestrator/drivers/pre-loop-phases/auto-hu-batch.js +0 -137
- package/src/orchestrator/drivers/pre-loop-phases/config-deprecations.js +0 -47
- package/src/orchestrator/drivers/pre-loop-phases/ensure-addyosmani-skills.js +0 -84
- package/src/orchestrator/drivers/pre-loop-phases/inject-loaded-plan.js +0 -393
- package/src/orchestrator/drivers/pre-loop.js +0 -524
- package/src/orchestrator/drivers/run-hu-batch.js +0 -468
- package/src/orchestrator/feedback-enrichment.js +0 -140
- package/src/orchestrator/feedback-queue.js +0 -151
- package/src/orchestrator/flow-control.js +0 -170
- package/src/orchestrator/flow-runner.js +0 -365
- package/src/orchestrator/fs-leak-detector.js +0 -228
- package/src/orchestrator/hu-scheduler.js +0 -114
- package/src/orchestrator/hu-sub-pipeline.js +0 -642
- package/src/orchestrator/iteration-gate.js +0 -73
- package/src/orchestrator/iteration-stages.js +0 -9
- package/src/orchestrator/parallel-limiter.js +0 -74
- package/src/orchestrator/pipeline-context.js +0 -72
- package/src/orchestrator/post-loop-stages.js +0 -468
- package/src/orchestrator/pre-loop-stages.js +0 -11
- package/src/orchestrator/preflight-checks.js +0 -487
- package/src/orchestrator/repair/repair-detector.js +0 -117
- package/src/orchestrator/repair/repair-runner.js +0 -142
- package/src/orchestrator/reviewer-fallback.js +0 -45
- package/src/orchestrator/role-output-compressor.js +0 -189
- package/src/orchestrator/session-journal.js +0 -308
- package/src/orchestrator/solomon-escalation.js +0 -331
- package/src/orchestrator/solomon-rules.js +0 -212
- package/src/orchestrator/stages/acceptance-coverage-stage.js +0 -47
- package/src/orchestrator/stages/architect-stage.js +0 -172
- package/src/orchestrator/stages/coder-stage.js +0 -506
- package/src/orchestrator/stages/domain-curator-stage.js +0 -82
- package/src/orchestrator/stages/format-stage.js +0 -61
- package/src/orchestrator/stages/hu-reviewer-phases/detect-and-apply-splits.js +0 -127
- package/src/orchestrator/stages/hu-reviewer-stage.js +0 -419
- package/src/orchestrator/stages/perf-stage.js +0 -140
- package/src/orchestrator/stages/planner-stage.js +0 -85
- package/src/orchestrator/stages/rag-context-stage.js +0 -80
- package/src/orchestrator/stages/rag-preload-decisor.js +0 -58
- package/src/orchestrator/stages/research-stage.js +0 -69
- package/src/orchestrator/stages/reviewer-stage.js +0 -431
- package/src/orchestrator/stages/sonar-stage.js +0 -439
- package/src/orchestrator/stages/stage-classes.js +0 -84
- package/src/orchestrator/stages/stage-executor.js +0 -155
- package/src/orchestrator/stages/suite-green-stage.js +0 -62
- package/src/orchestrator/stages/tdd-discipline-stage.js +0 -56
- package/src/orchestrator/stages/tool-judge-stage.js +0 -53
- package/src/orchestrator/stages/triage-stage.js +0 -172
- package/src/orchestrator/standby.js +0 -71
- package/src/orchestrator/verification-gate.js +0 -183
- package/src/orchestrator.js +0 -22
- package/src/plan/adr-generator.js +0 -170
- package/src/plan/adr-loader.js +0 -60
- package/src/plan/plan-executor.js +0 -100
- package/src/plan/plan-validation.js +0 -4
- package/src/prompts/acceptance-coverage.js +0 -32
- package/src/prompts/arbiter.js +0 -38
- package/src/prompts/architect.js +0 -103
- package/src/prompts/hu-reviewer.js +0 -244
- package/src/prompts/tool-correctness-judge.js +0 -31
- package/src/prompts/triage.js +0 -57
- package/src/rag/embedder.js +0 -2
- package/src/rag/embedders/_cloud-base.js +0 -2
- package/src/rag/embedders/cohere.js +0 -2
- package/src/rag/embedders/mistral.js +0 -2
- package/src/rag/embedders/onnx.js +0 -2
- package/src/rag/embedders/openai.js +0 -2
- package/src/rag/embedders/voyage.js +0 -2
- package/src/rag/rerank.js +0 -4
- package/src/rag/where-parser.js +0 -4
- package/src/repeat-detector.js +0 -88
- package/src/review/diff-generator.js +0 -112
- package/src/review/git-stash-helper.js +0 -104
- package/src/review/schema.js +0 -31
- package/src/review/scope-filter.js +0 -152
- package/src/review/snapshot-diff.js +0 -122
- package/src/review/tdd-discipline.js +0 -90
- package/src/review/tdd-policy.js +0 -69
- package/src/roles/acceptance-coverage-role.js +0 -78
- package/src/roles/architect-role.js +0 -77
- package/src/roles/coder-role.js +0 -113
- package/src/roles/commiter-role.js +0 -113
- package/src/roles/domain-curator-role.js +0 -134
- package/src/roles/hu-reviewer-role.js +0 -64
- package/src/roles/impeccable-role.js +0 -85
- package/src/roles/index.js +0 -18
- package/src/roles/karajan-brain-role.js +0 -134
- package/src/roles/perf-role.js +0 -122
- package/src/roles/planner-role.js +0 -151
- package/src/roles/refactorer-role.js +0 -30
- package/src/roles/repairer-role.js +0 -181
- package/src/roles/researcher-role.js +0 -70
- package/src/roles/reviewer-role.js +0 -115
- package/src/roles/security-role.js +0 -73
- package/src/roles/solomon-role.js +0 -271
- package/src/roles/sonar-role.js +0 -72
- package/src/roles/tester-role.js +0 -235
- package/src/roles/tool-correctness-judge-role.js +0 -78
- package/src/roles/triage-role.js +0 -99
- package/src/session/journal/decisions-writer.js +0 -200
- package/src/session/journal/iteration-logger.js +0 -194
- package/src/session/journal/summary-writer.js +0 -320
- package/src/session/journal/tree-writer.js +0 -164
- package/src/session/journal/write-all.js +0 -89
- package/src/session-cleanup.js +0 -116
- package/src/skills/semantic-detector.js +0 -167
- package/src/skills/skill-detector.js +0 -385
- package/src/sonar/cloud-scanner.js +0 -78
- package/src/tracker-bootstrap.js +0 -44
- package/src/types/index.js +0 -38
- package/src/types/policy.js +0 -43
- package/src/types/solomon.js +0 -87
- package/src/utils/async-lock.js +0 -31
- package/src/utils/budget.js +0 -229
- package/src/utils/cwd-confirm.js +0 -39
- package/src/utils/display/event-handlers.js +0 -403
- package/src/utils/display/formatters.js +0 -132
- package/src/utils/display/header.js +0 -47
- package/src/utils/display/session-summary.js +0 -118
- package/src/utils/display/solomon.js +0 -42
- package/src/utils/pricing.js +0 -29
- package/src/utils/quota-simulator.js +0 -56
- package/src/utils/role-assigner.js +0 -137
- package/src/utils/rtk-wrapper.js +0 -87
- package/src/utils/run-registry.js +0 -9
- package/src/utils/status-dashboard.js +0 -254
- package/src/utils/tool-call-extractor.js +0 -56
- package/src/webperf/devtools-detect.js +0 -112
- package/src/webperf/webperf-role-integration.js +0 -66
- package/templates/skills/kj-run.md +0 -73
|
@@ -18,6 +18,7 @@ import { getConfigPath } from "../config.js";
|
|
|
18
18
|
import { resolveRoleMdPath, loadFirstExisting } from "../roles/base-role.js";
|
|
19
19
|
import { withDocLink } from "../utils/doc-links.js";
|
|
20
20
|
import { STRATEGY } from "./types.js";
|
|
21
|
+
import { codexHome } from "../utils/agent-home.js";
|
|
21
22
|
|
|
22
23
|
/**
|
|
23
24
|
* kj.config.yml presence check.
|
|
@@ -218,16 +219,16 @@ function createStaleMcpPathCheck() {
|
|
|
218
219
|
}
|
|
219
220
|
|
|
220
221
|
/**
|
|
221
|
-
* Codex config (
|
|
222
|
+
* Codex config ($CODEX_HOME/config.toml, ~/.codex by default) validity.
|
|
223
|
+
* KJC-TSK-1344: the account CODEX_HOME selects is the one whose config counts.
|
|
222
224
|
*/
|
|
223
|
-
function createCodexConfigCheck() {
|
|
225
|
+
export function createCodexConfigCheck({ env = process.env, home = os.homedir() } = {}) {
|
|
226
|
+
const codexTomlPath = path.join(codexHome({ home, env }), "config.toml");
|
|
224
227
|
return {
|
|
225
228
|
name: "agent-config:codex",
|
|
226
|
-
label:
|
|
229
|
+
label: `Agent config: codex (${codexTomlPath})`,
|
|
227
230
|
strategy: STRATEGY.MANUAL,
|
|
228
231
|
async detect() {
|
|
229
|
-
const home = os.homedir();
|
|
230
|
-
const codexTomlPath = path.join(home, ".codex", "config.toml");
|
|
231
232
|
try {
|
|
232
233
|
const raw = await fs.readFile(codexTomlPath, "utf8");
|
|
233
234
|
const duplicates = findDuplicateTomlKeys(raw);
|
|
@@ -236,7 +237,7 @@ function createCodexConfigCheck() {
|
|
|
236
237
|
ok: false,
|
|
237
238
|
severity: "warn",
|
|
238
239
|
detail: `Duplicate TOML keys: ${duplicates.join(", ")}`,
|
|
239
|
-
fix: `Remove duplicate entries in
|
|
240
|
+
fix: `Remove duplicate entries in ${codexTomlPath}: ${duplicates.join(", ")}`,
|
|
240
241
|
};
|
|
241
242
|
}
|
|
242
243
|
return { ok: true, severity: "info", detail: "Valid TOML (no duplicate keys)" };
|
|
@@ -248,7 +249,7 @@ function createCodexConfigCheck() {
|
|
|
248
249
|
ok: false,
|
|
249
250
|
severity: "warn",
|
|
250
251
|
detail: `Cannot read: ${err.message.split("\n")[0]}`,
|
|
251
|
-
fix:
|
|
252
|
+
fix: `Check file permissions on ${codexTomlPath}`,
|
|
252
253
|
};
|
|
253
254
|
}
|
|
254
255
|
},
|
package/src/checks/dir-setup.js
CHANGED
|
@@ -98,6 +98,39 @@ export function createLegacyKjHomeCheck() {
|
|
|
98
98
|
};
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
+
/**
|
|
102
|
+
* KJC-TSK-0662: the kj run pipeline kept its user stories in ~/.karajan/hu-stories/.
|
|
103
|
+
* 5.0 retired it and nothing reads that folder any more (MIGRATION-v5.md). Said, never
|
|
104
|
+
* touched: kj clean removes it when the user asks.
|
|
105
|
+
* @internal Exported for tests.
|
|
106
|
+
*/
|
|
107
|
+
export function createLegacyHuStoriesCheck() {
|
|
108
|
+
return {
|
|
109
|
+
name: "legacy-hu-stories",
|
|
110
|
+
label: "retired pipeline data (~/.karajan/hu-stories)",
|
|
111
|
+
strategy: STRATEGY.MANUAL,
|
|
112
|
+
describe: "Detect the user stories of the retired kj run pipeline",
|
|
113
|
+
async detect() {
|
|
114
|
+
const dir = path.join(getKarajanHome(), "hu-stories");
|
|
115
|
+
let entries;
|
|
116
|
+
try {
|
|
117
|
+
entries = await fs.readdir(dir);
|
|
118
|
+
} catch (err) {
|
|
119
|
+
if (err.code === "ENOENT") return { ok: true, severity: "info", detail: "No retired pipeline data" };
|
|
120
|
+
return { ok: false, severity: "warn", detail: `could not read ${dir}: ${err.message}` };
|
|
121
|
+
}
|
|
122
|
+
if (entries.length === 0) return { ok: true, severity: "info", detail: "No retired pipeline data" };
|
|
123
|
+
return {
|
|
124
|
+
ok: false,
|
|
125
|
+
severity: "warn",
|
|
126
|
+
detail: `${dir} still has ${entries.length} entries from the kj run pipeline, retired in 5.0: nothing reads them`,
|
|
127
|
+
// kj clean also applies its usual retention to plans and sessions: show first, then delete.
|
|
128
|
+
fix: "kj clean --hu-days 0 lists what would go (old plans and sessions too); add --yes to delete it",
|
|
129
|
+
};
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
101
134
|
export function getDirSetupChecks() {
|
|
102
|
-
return [createKarajanDirsCheck(), createLegacyKjHomeCheck()];
|
|
135
|
+
return [createKarajanDirsCheck(), createLegacyKjHomeCheck(), createLegacyHuStoriesCheck()];
|
|
103
136
|
}
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Native
|
|
2
|
+
* Native module check (KJC-BUG-0092, KJC-TSK-1353).
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* WARN in `kj doctor` with the exact remedy instead of a cryptic runtime crash.
|
|
4
|
+
* node-pty is kj's only native module since better-sqlite3 left (KJC-TSK-1353:
|
|
5
|
+
* every SQLite store runs on node:sqlite, built into Node). It is optional: it
|
|
6
|
+
* powers the HU Board's terminal. Where it needs its install script, pnpm
|
|
7
|
+
* (ERR_PNPM_IGNORED_BUILDS) and npm 12 (allowScripts) block it by default, so
|
|
8
|
+
* `kj doctor` warns with the exact remedy instead of a broken terminal.
|
|
10
9
|
*/
|
|
11
10
|
|
|
12
11
|
import { execFileSync } from "node:child_process";
|
|
@@ -32,19 +31,7 @@ function defaultNpmMajor() {
|
|
|
32
31
|
* allowScripts covers it; reinstalling blocks it again. Approve, then rebuild, in kj's dir.
|
|
33
32
|
*/
|
|
34
33
|
export const npmAllowScriptsRemedy = (pkgDir = OWN_PKG_DIR) =>
|
|
35
|
-
`cd "${pkgDir}" && npm install-scripts approve
|
|
36
|
-
|
|
37
|
-
// The addon is installed but its native build is missing (a missing package needs a reinstall, not this).
|
|
38
|
-
const UNBUILT_ADDON = /bindings file|better_sqlite3\.node/;
|
|
39
|
-
|
|
40
|
-
/** A missing better-sqlite3 addon becomes an error that says how to build it; any other error passes as it is. */
|
|
41
|
-
export function explainNativeLoadError(err, { npmMajor = defaultNpmMajor, pkgDir = OWN_PKG_DIR } = {}) {
|
|
42
|
-
if (!UNBUILT_ADDON.test(String(err?.message ?? err))) return err;
|
|
43
|
-
const remedy = (npmMajor() ?? 0) >= 12
|
|
44
|
-
? `npm 12 skipped its install script (allowScripts); build it with: ${npmAllowScriptsRemedy(pkgDir)}`
|
|
45
|
-
: "run kj doctor for the exact fix on this install";
|
|
46
|
-
return new Error(`better-sqlite3 native addon is not built, so the RAG cannot open its index — ${remedy}`, { cause: err });
|
|
47
|
-
}
|
|
34
|
+
`cd "${pkgDir}" && npm install-scripts approve node-pty && npm rebuild node-pty`;
|
|
48
35
|
|
|
49
36
|
/** pnpm lays packages out under a `.pnpm` virtual store and symlinks them in. */
|
|
50
37
|
function isPnpmInstall() {
|
|
@@ -54,50 +41,45 @@ function isPnpmInstall() {
|
|
|
54
41
|
);
|
|
55
42
|
}
|
|
56
43
|
|
|
57
|
-
/**
|
|
58
|
-
async function
|
|
59
|
-
|
|
60
|
-
new Database(":memory:").close();
|
|
44
|
+
/** Load node-pty's native binding. */
|
|
45
|
+
async function defaultLoadPty() {
|
|
46
|
+
await import("node-pty");
|
|
61
47
|
}
|
|
62
48
|
|
|
63
|
-
|
|
49
|
+
const NO_TERMINAL = "the HU Board terminal is unavailable (everything else works)";
|
|
50
|
+
|
|
51
|
+
export function createNativeBuildCheck({ loadPty = defaultLoadPty, isPnpm = isPnpmInstall, npmMajor = defaultNpmMajor, pkgDir = OWN_PKG_DIR } = {}) {
|
|
64
52
|
return {
|
|
65
53
|
name: "native-build",
|
|
66
|
-
label: "native modules (
|
|
54
|
+
label: "native modules (node-pty)",
|
|
67
55
|
strategy: STRATEGY.MANUAL,
|
|
68
56
|
async detect() {
|
|
69
57
|
try {
|
|
70
|
-
await
|
|
71
|
-
return {
|
|
72
|
-
ok: true,
|
|
73
|
-
severity: "info",
|
|
74
|
-
detail: "better-sqlite3 native addon loads — DB-backed commands available",
|
|
75
|
-
};
|
|
58
|
+
await loadPty();
|
|
59
|
+
return { ok: true, severity: "info", detail: "node-pty loads — the HU Board terminal is available" };
|
|
76
60
|
} catch (err) {
|
|
77
61
|
const firstLine = String(err?.message || err).split("\n")[0];
|
|
78
62
|
if (isPnpm()) {
|
|
79
63
|
return {
|
|
80
64
|
ok: false,
|
|
81
65
|
severity: "warn",
|
|
82
|
-
detail:
|
|
83
|
-
fix: "Approve the build then reinstall: `pnpm approve-builds
|
|
66
|
+
detail: `node-pty native build was skipped — pnpm blocks dependency build scripts by default; ${NO_TERMINAL}`,
|
|
67
|
+
fix: "Approve the build then reinstall: `pnpm approve-builds node-pty` — or install with npm: `npm i -g @karajan-family/code`",
|
|
84
68
|
};
|
|
85
69
|
}
|
|
86
70
|
if ((npmMajor() ?? 0) >= 12) {
|
|
87
71
|
return {
|
|
88
72
|
ok: false,
|
|
89
73
|
severity: "warn",
|
|
90
|
-
detail: `
|
|
74
|
+
detail: `node-pty failed to load: ${firstLine} — npm 12 skips dependency install scripts that allowScripts does not cover; ${NO_TERMINAL}`,
|
|
91
75
|
fix: npmAllowScriptsRemedy(pkgDir),
|
|
92
76
|
};
|
|
93
77
|
}
|
|
94
78
|
return {
|
|
95
79
|
ok: false,
|
|
96
80
|
severity: "warn",
|
|
97
|
-
// KJC-BUG-0118: the standalone (curl) binary ships without native
|
|
98
|
-
|
|
99
|
-
// npm install) instead of implying the install is broken.
|
|
100
|
-
detail: `better-sqlite3 failed to load: ${firstLine} — DB-backed features (RAG, board, MCP) unavailable; the standalone binary does not bundle native modules`,
|
|
81
|
+
// KJC-BUG-0118: the standalone (curl) binary ships without native modules by design.
|
|
82
|
+
detail: `node-pty failed to load: ${firstLine} — ${NO_TERMINAL}; the standalone binary does not bundle native modules`,
|
|
101
83
|
fix: "Reinstall to rebuild native modules: `npm i -g @karajan-family/code`",
|
|
102
84
|
};
|
|
103
85
|
}
|
package/src/checks/runner.js
CHANGED
|
@@ -51,162 +51,25 @@ export async function runChecks(checks, ctx, options = {}) {
|
|
|
51
51
|
|
|
52
52
|
const { config } = ctx;
|
|
53
53
|
const startTotal = Date.now();
|
|
54
|
-
const entries =
|
|
54
|
+
const entries = checks.map((check) => entryFor(check, config));
|
|
55
55
|
const overrides = {};
|
|
56
56
|
|
|
57
|
-
// Build applicable entries (skipped checks noted up front).
|
|
58
|
-
// A check.applies(config) may return:
|
|
59
|
-
// - true / false — boolean form (back-compat).
|
|
60
|
-
// - an object { applies: boolean, reason?: string } — when false, `reason`
|
|
61
|
-
// is shown verbatim so users see WHY (e.g. "sonarqube.enabled is false
|
|
62
|
-
// in kj.config.yml") instead of the opaque "Not applicable" message
|
|
63
|
-
// that confused users debugging their config.
|
|
64
|
-
for (const check of checks) {
|
|
65
|
-
if (typeof check.applies !== "function") {
|
|
66
|
-
entries.push({ check, status: null, detail: null, runMs: 0, detectResult: null, remediated: false });
|
|
67
|
-
continue;
|
|
68
|
-
}
|
|
69
|
-
const verdict = check.applies(config);
|
|
70
|
-
const isObj = verdict && typeof verdict === "object" && "applies" in verdict;
|
|
71
|
-
const applies = isObj ? Boolean(verdict.applies) : Boolean(verdict);
|
|
72
|
-
if (applies) {
|
|
73
|
-
entries.push({ check, status: null, detail: null, runMs: 0, detectResult: null, remediated: false });
|
|
74
|
-
continue;
|
|
75
|
-
}
|
|
76
|
-
const reason = (isObj && typeof verdict.reason === "string" && verdict.reason.trim())
|
|
77
|
-
? verdict.reason.trim()
|
|
78
|
-
: "Not applicable for current configuration";
|
|
79
|
-
entries.push({
|
|
80
|
-
check,
|
|
81
|
-
status: STATUS.SKIPPED,
|
|
82
|
-
detail: reason,
|
|
83
|
-
runMs: 0,
|
|
84
|
-
detectResult: null,
|
|
85
|
-
remediated: false,
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
|
|
89
57
|
// Phase 1: detect in parallel with timeout.
|
|
90
58
|
const detectBase = Date.now();
|
|
91
|
-
await Promise.all(
|
|
92
|
-
entries.map(async (entry) => {
|
|
93
|
-
if (entry.status === STATUS.SKIPPED) return;
|
|
94
|
-
const start = Date.now();
|
|
95
|
-
// Per-check override: checks that spawn slow tools (e.g. `npx <pkg>` cold
|
|
96
|
-
// start) declare detectTimeoutMs so the blanket pipeline timeout doesn't
|
|
97
|
-
// kill them. Falls back to the pipeline-wide timeoutMs.
|
|
98
|
-
const detectTimeoutMs = Number.isFinite(entry.check.detectTimeoutMs)
|
|
99
|
-
? entry.check.detectTimeoutMs
|
|
100
|
-
: timeoutMs;
|
|
101
|
-
try {
|
|
102
|
-
const result = await withTimeout(entry.check.detect({ config, signal }), detectTimeoutMs, entry.check.name);
|
|
103
|
-
entry.detectResult = result;
|
|
104
|
-
entry.runMs = Date.now() - start;
|
|
105
|
-
entry.status = resolveStatusFromDetect(entry.check, result);
|
|
106
|
-
entry.detail = result.detail;
|
|
107
|
-
// KJC-BUG-0049: si el check es degradable y falló (status FAIL/WARN tras
|
|
108
|
-
// resolveStatusFromDetect), aplicar disables al overrides y degradar a WARN.
|
|
109
|
-
// Así el preflight no aborta — la feature opcional se desactiva con aviso.
|
|
110
|
-
if (!result.ok && entry.check.degradable && (entry.status === STATUS.FAIL || entry.status === STATUS.WARN)) {
|
|
111
|
-
for (const dotPath of entry.check.degradable.disables || []) {
|
|
112
|
-
setDotPath(overrides, dotPath, false);
|
|
113
|
-
}
|
|
114
|
-
entry.status = STATUS.WARN;
|
|
115
|
-
entry.detail = `${result.detail} → ${entry.check.degradable.warn}`;
|
|
116
|
-
entry.degraded = true;
|
|
117
|
-
}
|
|
118
|
-
} catch (err) {
|
|
119
|
-
entry.runMs = Date.now() - start;
|
|
120
|
-
if (err instanceof TimeoutError) {
|
|
121
|
-
entry.detectResult = { ok: false, severity: "warn", detail: `Timeout after ${detectTimeoutMs}ms` };
|
|
122
|
-
// A timeout on a degradable (optional) check must not block the
|
|
123
|
-
// pipeline: degrade to WARN and disable its feature flags, same as
|
|
124
|
-
// a regular failure (KJC-BUG-0049 semantics).
|
|
125
|
-
if (entry.check.degradable) {
|
|
126
|
-
for (const dotPath of entry.check.degradable.disables || []) {
|
|
127
|
-
setDotPath(overrides, dotPath, false);
|
|
128
|
-
}
|
|
129
|
-
entry.status = STATUS.WARN;
|
|
130
|
-
entry.detail = `${entry.detectResult.detail} → ${entry.check.degradable.warn}`;
|
|
131
|
-
entry.degraded = true;
|
|
132
|
-
} else {
|
|
133
|
-
entry.status = STATUS.TIMEOUT;
|
|
134
|
-
entry.detail = entry.detectResult.detail;
|
|
135
|
-
}
|
|
136
|
-
} else {
|
|
137
|
-
entry.detectResult = { ok: false, severity: "fail", detail: `Detection error: ${err.message}` };
|
|
138
|
-
entry.status = STATUS.FAIL;
|
|
139
|
-
entry.detail = entry.detectResult.detail;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
})
|
|
143
|
-
);
|
|
59
|
+
await Promise.all(entries.map((entry) => detectEntry(entry, { config, signal, timeoutMs, overrides })));
|
|
144
60
|
logger.info?.(`Detect phase done in ${Date.now() - detectBase}ms`);
|
|
145
61
|
|
|
146
|
-
// Phase 2: remediate sequentially (only in "fix" mode, only failing checks).
|
|
147
62
|
if (mode !== "check-only") {
|
|
63
|
+
// Phase 2: remediate sequentially (only in "fix" mode, only failing checks).
|
|
148
64
|
for (const entry of entries) {
|
|
149
|
-
if (
|
|
150
|
-
const { check, detectResult } = entry;
|
|
151
|
-
if (check.strategy === STRATEGY.PROMPT && !yes) {
|
|
152
|
-
const approved = await onConfirm(check.describe || `Fix: ${check.name}`);
|
|
153
|
-
if (!approved) {
|
|
154
|
-
logger.info?.(`User declined remediation for ${check.name}`);
|
|
155
|
-
continue;
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
const start = Date.now();
|
|
159
|
-
try {
|
|
160
|
-
const rem = await withTimeout(
|
|
161
|
-
check.remediate({ config, extra: detectResult.extra, signal, logger }),
|
|
162
|
-
remediateTimeoutMs,
|
|
163
|
-
`${check.name}:remediate`
|
|
164
|
-
);
|
|
165
|
-
entry.remediated = rem.fixed === true;
|
|
166
|
-
entry.runMs += Date.now() - start;
|
|
167
|
-
if (rem.fixed) {
|
|
168
|
-
if (rem.changes) mergeOverrides(overrides, rem.changes);
|
|
169
|
-
entry.detail = rem.detail;
|
|
170
|
-
entry.status = STATUS.FIXED;
|
|
171
|
-
} else {
|
|
172
|
-
entry.detail = rem.detail || entry.detail;
|
|
173
|
-
entry.status = STATUS.FAIL;
|
|
174
|
-
}
|
|
175
|
-
} catch (err) {
|
|
176
|
-
entry.runMs += Date.now() - start;
|
|
177
|
-
const msg = err instanceof TimeoutError ? `Remediation timeout after ${remediateTimeoutMs}ms` : `Remediation error: ${err.message}`;
|
|
178
|
-
entry.detail = msg;
|
|
179
|
-
entry.status = STATUS.FAIL;
|
|
180
|
-
logger.warn?.(`Remediation failed for ${check.name}: ${msg}`);
|
|
181
|
-
}
|
|
65
|
+
if (shouldAttemptRemediation(entry)) await remediateEntry(entry, { config, signal, logger, yes, onConfirm, remediateTimeoutMs, overrides });
|
|
182
66
|
}
|
|
183
|
-
|
|
184
67
|
// Phase 3: re-verify fixed checks using the config merged with any
|
|
185
68
|
// runtime overrides applied by remediations. Without this merge, a check
|
|
186
69
|
// that rebinds to a new port (override) would re-verify against the old
|
|
187
70
|
// config and wrongly report failure.
|
|
188
71
|
const verifyConfig = mergeConfigAndOverrides(config, overrides);
|
|
189
|
-
await Promise.all(
|
|
190
|
-
entries.filter((e) => e.remediated).map(async (entry) => {
|
|
191
|
-
const start = Date.now();
|
|
192
|
-
try {
|
|
193
|
-
const result = await withTimeout(
|
|
194
|
-
entry.check.detect({ config: verifyConfig, signal }),
|
|
195
|
-
Number.isFinite(entry.check.detectTimeoutMs) ? entry.check.detectTimeoutMs : timeoutMs,
|
|
196
|
-
`${entry.check.name}:reverify`
|
|
197
|
-
);
|
|
198
|
-
entry.runMs += Date.now() - start;
|
|
199
|
-
if (!result.ok) {
|
|
200
|
-
entry.status = STATUS.FAIL;
|
|
201
|
-
entry.detail = `${entry.detail} (but re-verify failed: ${result.detail})`;
|
|
202
|
-
}
|
|
203
|
-
} catch (err) {
|
|
204
|
-
entry.runMs += Date.now() - start;
|
|
205
|
-
entry.status = STATUS.FAIL;
|
|
206
|
-
entry.detail = `${entry.detail} (re-verify error: ${err.message})`;
|
|
207
|
-
}
|
|
208
|
-
})
|
|
209
|
-
);
|
|
72
|
+
await Promise.all(entries.filter((e) => e.remediated).map((entry) => reverifyEntry(entry, { verifyConfig, signal, timeoutMs })));
|
|
210
73
|
}
|
|
211
74
|
|
|
212
75
|
// Flatten into reports.
|
|
@@ -234,6 +97,129 @@ export async function runChecks(checks, ctx, options = {}) {
|
|
|
234
97
|
};
|
|
235
98
|
}
|
|
236
99
|
|
|
100
|
+
// Build an applicable entry (skipped checks noted up front).
|
|
101
|
+
// A check.applies(config) may return:
|
|
102
|
+
// - true / false — boolean form (back-compat).
|
|
103
|
+
// - an object { applies: boolean, reason?: string } — when false, `reason`
|
|
104
|
+
// is shown verbatim so users see WHY (e.g. "sonarqube.enabled is false
|
|
105
|
+
// in kj.config.yml") instead of the opaque "Not applicable" message
|
|
106
|
+
// that confused users debugging their config.
|
|
107
|
+
function entryFor(check, config) {
|
|
108
|
+
const entry = { check, status: null, detail: null, runMs: 0, detectResult: null, remediated: false };
|
|
109
|
+
if (typeof check.applies !== "function") return entry;
|
|
110
|
+
const verdict = check.applies(config);
|
|
111
|
+
const isObj = verdict && typeof verdict === "object" && "applies" in verdict;
|
|
112
|
+
const applies = isObj ? Boolean(verdict.applies) : Boolean(verdict);
|
|
113
|
+
if (applies) return entry;
|
|
114
|
+
const reason = (isObj && typeof verdict.reason === "string" && verdict.reason.trim())
|
|
115
|
+
? verdict.reason.trim()
|
|
116
|
+
: "Not applicable for current configuration";
|
|
117
|
+
return { ...entry, status: STATUS.SKIPPED, detail: reason };
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Per-check override: checks that spawn slow tools (e.g. `npx <pkg>` cold
|
|
121
|
+
// start) declare detectTimeoutMs so the blanket pipeline timeout doesn't
|
|
122
|
+
// kill them. Falls back to the pipeline-wide timeoutMs.
|
|
123
|
+
const detectTimeoutOf = (check, timeoutMs) => (Number.isFinite(check.detectTimeoutMs) ? check.detectTimeoutMs : timeoutMs);
|
|
124
|
+
|
|
125
|
+
// KJC-BUG-0049: an optional (degradable) check that fails or times out does not
|
|
126
|
+
// block the pipeline: its feature flags are disabled and it degrades to WARN.
|
|
127
|
+
function degrade(entry, overrides, detail) {
|
|
128
|
+
for (const dotPath of entry.check.degradable.disables || []) {
|
|
129
|
+
setDotPath(overrides, dotPath, false);
|
|
130
|
+
}
|
|
131
|
+
entry.status = STATUS.WARN;
|
|
132
|
+
entry.detail = `${detail} → ${entry.check.degradable.warn}`;
|
|
133
|
+
entry.degraded = true;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
async function detectEntry(entry, { config, signal, timeoutMs, overrides }) {
|
|
137
|
+
if (entry.status === STATUS.SKIPPED) return;
|
|
138
|
+
const start = Date.now();
|
|
139
|
+
const detectTimeoutMs = detectTimeoutOf(entry.check, timeoutMs);
|
|
140
|
+
try {
|
|
141
|
+
const result = await withTimeout(entry.check.detect({ config, signal }), detectTimeoutMs, entry.check.name);
|
|
142
|
+
entry.detectResult = result;
|
|
143
|
+
entry.runMs = Date.now() - start;
|
|
144
|
+
entry.status = resolveStatusFromDetect(entry.check, result);
|
|
145
|
+
entry.detail = result.detail;
|
|
146
|
+
// Así el preflight no aborta — la feature opcional se desactiva con aviso.
|
|
147
|
+
if (!result.ok && entry.check.degradable && (entry.status === STATUS.FAIL || entry.status === STATUS.WARN)) {
|
|
148
|
+
degrade(entry, overrides, result.detail);
|
|
149
|
+
}
|
|
150
|
+
} catch (err) {
|
|
151
|
+
entry.runMs = Date.now() - start;
|
|
152
|
+
if (!(err instanceof TimeoutError)) {
|
|
153
|
+
entry.detectResult = { ok: false, severity: "fail", detail: `Detection error: ${err.message}` };
|
|
154
|
+
entry.status = STATUS.FAIL;
|
|
155
|
+
entry.detail = entry.detectResult.detail;
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
entry.detectResult = { ok: false, severity: "warn", detail: `Timeout after ${detectTimeoutMs}ms` };
|
|
159
|
+
if (entry.check.degradable) {
|
|
160
|
+
degrade(entry, overrides, entry.detectResult.detail);
|
|
161
|
+
} else {
|
|
162
|
+
entry.status = STATUS.TIMEOUT;
|
|
163
|
+
entry.detail = entry.detectResult.detail;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
async function remediateEntry(entry, { config, signal, logger, yes, onConfirm, remediateTimeoutMs, overrides }) {
|
|
169
|
+
const { check, detectResult } = entry;
|
|
170
|
+
if (check.strategy === STRATEGY.PROMPT && !yes) {
|
|
171
|
+
const approved = await onConfirm(check.describe || `Fix: ${check.name}`);
|
|
172
|
+
if (!approved) {
|
|
173
|
+
logger.info?.(`User declined remediation for ${check.name}`);
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
const start = Date.now();
|
|
178
|
+
try {
|
|
179
|
+
const rem = await withTimeout(
|
|
180
|
+
check.remediate({ config, extra: detectResult.extra, signal, logger }),
|
|
181
|
+
remediateTimeoutMs,
|
|
182
|
+
`${check.name}:remediate`
|
|
183
|
+
);
|
|
184
|
+
entry.remediated = rem.fixed === true;
|
|
185
|
+
entry.runMs += Date.now() - start;
|
|
186
|
+
if (rem.fixed) {
|
|
187
|
+
if (rem.changes) mergeOverrides(overrides, rem.changes);
|
|
188
|
+
entry.detail = rem.detail;
|
|
189
|
+
entry.status = STATUS.FIXED;
|
|
190
|
+
} else {
|
|
191
|
+
entry.detail = rem.detail || entry.detail;
|
|
192
|
+
entry.status = STATUS.FAIL;
|
|
193
|
+
}
|
|
194
|
+
} catch (err) {
|
|
195
|
+
entry.runMs += Date.now() - start;
|
|
196
|
+
const msg = err instanceof TimeoutError ? `Remediation timeout after ${remediateTimeoutMs}ms` : `Remediation error: ${err.message}`;
|
|
197
|
+
entry.detail = msg;
|
|
198
|
+
entry.status = STATUS.FAIL;
|
|
199
|
+
logger.warn?.(`Remediation failed for ${check.name}: ${msg}`);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
async function reverifyEntry(entry, { verifyConfig, signal, timeoutMs }) {
|
|
204
|
+
const start = Date.now();
|
|
205
|
+
try {
|
|
206
|
+
const result = await withTimeout(
|
|
207
|
+
entry.check.detect({ config: verifyConfig, signal }),
|
|
208
|
+
detectTimeoutOf(entry.check, timeoutMs),
|
|
209
|
+
`${entry.check.name}:reverify`
|
|
210
|
+
);
|
|
211
|
+
entry.runMs += Date.now() - start;
|
|
212
|
+
if (!result.ok) {
|
|
213
|
+
entry.status = STATUS.FAIL;
|
|
214
|
+
entry.detail = `${entry.detail} (but re-verify failed: ${result.detail})`;
|
|
215
|
+
}
|
|
216
|
+
} catch (err) {
|
|
217
|
+
entry.runMs += Date.now() - start;
|
|
218
|
+
entry.status = STATUS.FAIL;
|
|
219
|
+
entry.detail = `${entry.detail} (re-verify error: ${err.message})`;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
237
223
|
function shouldAttemptRemediation(entry) {
|
|
238
224
|
if (entry.status === STATUS.SKIPPED) return false;
|
|
239
225
|
if (entry.status === STATUS.OK) return false;
|
|
@@ -13,9 +13,9 @@ export const CORE_COMMANDS = [
|
|
|
13
13
|
// gets — it is the first command a new project ever runs.
|
|
14
14
|
"bootstrap",
|
|
15
15
|
"init",
|
|
16
|
-
"
|
|
16
|
+
"hu",
|
|
17
|
+
"review",
|
|
17
18
|
"plan",
|
|
18
|
-
"status",
|
|
19
19
|
"doctor",
|
|
20
20
|
"harden",
|
|
21
21
|
"config",
|
|
@@ -31,11 +31,11 @@ export const META_COMMANDS = ["advanced", "help"];
|
|
|
31
31
|
* so a newly-registered command can never silently vanish from `kj advanced`.
|
|
32
32
|
*/
|
|
33
33
|
export const ADVANCED_GROUPS = [
|
|
34
|
-
{ title: "
|
|
35
|
-
{ title: "Análisis
|
|
34
|
+
{ title: "Agentes y revisión", commands: ["code", "solomon", "agent", "scan", "tournament"] },
|
|
35
|
+
{ title: "Análisis previo", commands: ["discover", "spec", "onboard", "brief"] },
|
|
36
36
|
{ title: "Búsqueda / RAG", commands: ["rag", "qmd", "watch", "doc"] },
|
|
37
|
-
{ title: "Calidad / auditoría", commands: ["audit", "check", "mutate", "webperf", "sonar", "privacy", "release", "policy", "rules", "rulesync", "claims", "steward", "pr-size"] },
|
|
38
|
-
{ title: "Sesión / board", commands: ["
|
|
37
|
+
{ title: "Calidad / auditoría", commands: ["audit", "check", "mutate", "webperf", "sonar", "privacy", "release", "policy", "rules", "rulesync", "claims", "steward", "pr-size", "main-guard"] },
|
|
38
|
+
{ title: "Sesión / board", commands: ["report", "board", "adr", "worktree", "sentinel", "identity", "security", "handoff"] },
|
|
39
39
|
{ title: "Infra / setup", commands: ["install-tools", "ollama", "skills", "roles", "agents", "env"] },
|
|
40
40
|
{ title: "Mantenimiento", commands: ["clean", "sync", "telemetry", "report-issue"] },
|
|
41
41
|
];
|