karajan-code 4.70.4 → 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/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 -143
- 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 -150
- package/src/commands/go.js +71 -53
- package/src/commands/harden.js +90 -81
- 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 +421 -341
- 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/secrets.js +36 -0
- package/src/config.js +1 -0
- package/src/environment/adr.js +16 -2
- package/src/git/karajan-label.js +20 -8
- package/src/guards/main-guard.js +54 -0
- package/src/harden/hook-templates.js +16 -1
- package/src/harden/sentinel/posttooluse.mjs +18 -6
- package/src/harden/sentinel/pretooluse-sentinel.mjs +64 -36
- package/src/harden/sentinel/sentinel-lib.mjs +129 -26
- package/src/harden/sentinel/sentinel-shell.mjs +5 -16
- package/src/harden/sentinel/sessionstart.mjs +3 -2
- package/src/harden/sentinel/stop.mjs +5 -4
- 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 +1 -35
- package/src/mcp/handlers/management-handlers.js +2 -42
- package/src/mcp/server-handlers.js +16 -22
- package/src/mcp/tools.js +1 -196
- 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/gate-gitignore.js +23 -4
- package/src/review/gate-hook.js +12 -4
- package/src/review/one-shot-review.js +45 -35
- package/src/review/publish-pr.js +14 -2
- package/src/review/repo-docs.js +73 -0
- package/src/review/repo-stack.js +59 -0
- package/src/review/reviewer-fallback.js +19 -4
- 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 +1 -24
- 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/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
package/src/commands/audit.js
CHANGED
|
@@ -289,141 +289,144 @@ export async function auditCommand({ task, config, logger, dimensions, json, age
|
|
|
289
289
|
const deterministicCtx = await role.collectDeterministic(roleInput);
|
|
290
290
|
const deterministicMd = formatDeterministicSummary(deterministicCtx);
|
|
291
291
|
|
|
292
|
-
|
|
293
|
-
// Runs after the deterministic phase, before the LLM. Auto-skipped on
|
|
294
|
-
// --no-harness or if `runHarnessSection` surfaces an error (graceful
|
|
295
|
-
// degradation: a missing Docker daemon must not break `kj audit`).
|
|
296
|
-
let harnessSummary = null;
|
|
297
|
-
if (!noHarness) {
|
|
298
|
-
try {
|
|
299
|
-
harnessSummary = await runHarnessSection({
|
|
300
|
-
projectDir: config?.projectDir || process.cwd(),
|
|
301
|
-
harnessConfig: config?.audit?.harness || null,
|
|
302
|
-
});
|
|
303
|
-
if (harnessSummary?.ok && !harnessSummary.skipped) {
|
|
304
|
-
runLog.logText(`[audit] harness score=${harnessSummary.score}/100 grade=${harnessSummary.grade}`);
|
|
305
|
-
}
|
|
306
|
-
} catch (e) {
|
|
307
|
-
harnessSummary = { ok: false, error: e?.message || String(e) };
|
|
308
|
-
runLog.logText(`[audit] harness skipped: ${harnessSummary.error}`);
|
|
309
|
-
}
|
|
310
|
-
}
|
|
292
|
+
const harnessSummary = noHarness ? null : await runHarness({ config, runLog });
|
|
311
293
|
const harnessMd = formatHarnessSection(harnessSummary);
|
|
312
294
|
|
|
313
295
|
// --json suppresses the interactive flow regardless: it would mangle
|
|
314
296
|
// a script's stdout. JSON consumers always get the full audit unless
|
|
315
297
|
// they explicitly pass deterministicOnly.
|
|
316
298
|
const reportPath = await resolveReportFilePath(reportFile, json);
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
}
|
|
299
|
+
const runLlm = await chooseLlm({ deterministicOnly, json, yes, deterministicMd, promptFn, logger });
|
|
300
|
+
const invocation = { task, dimensions, noSonar, noOsv, noSemgrep, noHarness, noAiSlop, json, deterministicOnly, yes };
|
|
301
|
+
const ctx = { config, logger, runLog, json, trend, invocation, deterministicCtx, deterministicMd, harnessSummary, harnessMd, reportPath };
|
|
302
|
+
if (!runLlm) return deterministicOnlyAudit(ctx);
|
|
303
|
+
return llmAudit({ ...ctx, roleInput, available, fallbackCandidates });
|
|
304
|
+
});
|
|
305
|
+
}
|
|
325
306
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
await fs.writeFile(reportPath, payload, "utf8");
|
|
347
|
-
runLog.logText(`[audit] report written (deterministic-only) → ${reportPath}`);
|
|
348
|
-
logger.info(`Audit report written: ${reportPath}`);
|
|
349
|
-
}
|
|
350
|
-
persistAuditRun(config?.projectDir || process.cwd(), { runId: new Date().toISOString(), timestamp: new Date().toISOString(), gitSha: null, harness: harnessSummary?.ok && !harnessSummary.skipped ? harnessSummary : null, rawReportPath: reportPath });
|
|
351
|
-
logger.info("Audit completed (deterministic-only).");
|
|
352
|
-
return { ok: true, mode: "deterministic-only", reportPath: reportPath || undefined };
|
|
353
|
-
}
|
|
307
|
+
/**
|
|
308
|
+
* KJC-TSK-0471 — Harness Scorecard (Docker one-shot, golden metric).
|
|
309
|
+
* Runs after the deterministic phase, before the LLM. Skipped on
|
|
310
|
+
* --no-harness; an error from `runHarnessSection` degrades gracefully
|
|
311
|
+
* (a missing Docker daemon must not break `kj audit`).
|
|
312
|
+
*/
|
|
313
|
+
async function runHarness({ config, runLog }) {
|
|
314
|
+
try {
|
|
315
|
+
const summary = await runHarnessSection({
|
|
316
|
+
projectDir: config?.projectDir || process.cwd(),
|
|
317
|
+
harnessConfig: config?.audit?.harness || null,
|
|
318
|
+
});
|
|
319
|
+
if (summary?.ok && !summary.skipped) runLog.logText(`[audit] harness score=${summary.score}/100 grade=${summary.grade}`);
|
|
320
|
+
return summary;
|
|
321
|
+
} catch (e) {
|
|
322
|
+
const summary = { ok: false, error: e?.message || String(e) };
|
|
323
|
+
runLog.logText(`[audit] harness skipped: ${summary.error}`);
|
|
324
|
+
return summary;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
354
327
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
roleInput: { ...roleInput, onOutput: progress.onOutput },
|
|
366
|
-
deterministicCtx,
|
|
367
|
-
available,
|
|
368
|
-
candidates: fallbackCandidates,
|
|
369
|
-
onFallback: (cand) => logger.warn(`Audit provider fallback → ${cand.provider}${cand.model ? ` (${cand.model})` : " (default model)"}`),
|
|
370
|
-
});
|
|
371
|
-
progress.finish(roleResult.ok ? "done" : "failed");
|
|
372
|
-
} catch (err) { progress.finish("failed"); throw err; }
|
|
373
|
-
|
|
374
|
-
if (!roleResult.ok) {
|
|
375
|
-
const err = roleResult.result?.error || "Audit failed";
|
|
376
|
-
throw new Error(err);
|
|
377
|
-
}
|
|
328
|
+
/** Two-phase audit (KJC-TSK-0364): asks before spending tokens, unless --json, --yes or --deterministic-only. */
|
|
329
|
+
async function chooseLlm({ deterministicOnly, json, yes, deterministicMd, promptFn, logger }) {
|
|
330
|
+
if (deterministicOnly) return false;
|
|
331
|
+
if (json || yes) return true;
|
|
332
|
+
console.log(deterministicMd);
|
|
333
|
+
console.log("");
|
|
334
|
+
const ok = await promptContinueWithLlm({ promptFn });
|
|
335
|
+
if (!ok) logger.info("LLM analysis skipped (deterministic-only mode).");
|
|
336
|
+
return ok;
|
|
337
|
+
}
|
|
378
338
|
|
|
379
|
-
|
|
380
|
-
const usage = roleResult.usage;
|
|
381
|
-
if (parsed?.summary?.overallHealth) {
|
|
382
|
-
runLog.logText(`[audit] findings=${parsed.summary.totalFindings} (critical=${parsed.summary.critical}, high=${parsed.summary.high})`);
|
|
383
|
-
}
|
|
384
|
-
if (usage?.available) {
|
|
385
|
-
runLog.logText(`[audit] usage tokens=${usage.total_tokens} cost=$${(usage.cost_usd ?? 0).toFixed(4)} duration=${(usage.durationMs / 1000).toFixed(1)}s`);
|
|
386
|
-
}
|
|
339
|
+
const scoredHarness = (summary) => (summary?.ok && !summary.skipped ? summary : null);
|
|
387
340
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
if (json) {
|
|
394
|
-
const jsonPayload = parsed
|
|
395
|
-
? { ...parsed, harnessScore: harnessJson, harnessScoreDiff: history.diff, usage: usage || undefined }
|
|
396
|
-
: { ...roleResult, harnessScore: harnessJson, harnessScoreDiff: history.diff, usage: usage || undefined };
|
|
397
|
-
stdoutContent = JSON.stringify(jsonPayload, null, 2);
|
|
398
|
-
} else if (parsed?.summary?.overallHealth) {
|
|
399
|
-
stdoutContent = `${formatAudit(parsed, usage)}\n${harnessMd}${historyMd}`;
|
|
400
|
-
} else if (parsed?.raw) {
|
|
401
|
-
stdoutContent = parsed.raw + (usage ? `\n\n${formatUsageSummary(usage) || ""}` : "") + `\n${harnessMd}${historyMd}`;
|
|
402
|
-
} else {
|
|
403
|
-
stdoutContent = `${roleResult.summary || "Audit complete."}\n${harnessMd}${historyMd}`;
|
|
404
|
-
}
|
|
405
|
-
console.log(stdoutContent);
|
|
406
|
-
|
|
407
|
-
if (reportPath) {
|
|
408
|
-
let payload;
|
|
409
|
-
if (reportPath.endsWith(".json")) {
|
|
410
|
-
const jsonPayload = parsed
|
|
411
|
-
? { ...parsed, harnessScore: harnessJson, harnessScoreDiff: history.diff, usage: usage || undefined }
|
|
412
|
-
: { ...roleResult, harnessScore: harnessJson, harnessScoreDiff: history.diff, usage: usage || undefined };
|
|
413
|
-
payload = JSON.stringify(jsonPayload, null, 2);
|
|
414
|
-
} else {
|
|
415
|
-
const header = await buildReportHeader(config?.projectDir, describeInvocation({ task, dimensions, noSonar, noOsv, noSemgrep, noHarness, noAiSlop, json, deterministicOnly, yes }));
|
|
416
|
-
payload = header + stdoutContent + "\n";
|
|
417
|
-
}
|
|
418
|
-
await fs.writeFile(reportPath, payload, "utf8");
|
|
419
|
-
runLog.logText(`[audit] report written → ${reportPath}`);
|
|
420
|
-
logger.info(`Audit report written: ${reportPath}`);
|
|
421
|
-
}
|
|
341
|
+
/** The harness score as JSON and the history block, shared by both paths. */
|
|
342
|
+
function harnessReport({ config, harnessSummary, trend }) {
|
|
343
|
+
const history = loadAuditHistoryContext(config?.projectDir || process.cwd(), scoredHarness(harnessSummary), { showTrend: trend });
|
|
344
|
+
return { harnessJson: harnessSummaryForJson(harnessSummary), history, historyMd: composeHistoryBlock(history) };
|
|
345
|
+
}
|
|
422
346
|
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
347
|
+
async function writeReport({ ctx, payloadJson, markdownBody, note }) {
|
|
348
|
+
const { config, runLog, logger, reportPath, invocation } = ctx;
|
|
349
|
+
if (!reportPath) return;
|
|
350
|
+
const payload = reportPath.endsWith(".json")
|
|
351
|
+
? payloadJson
|
|
352
|
+
: `${await buildReportHeader(config?.projectDir, describeInvocation(invocation))}${markdownBody}`;
|
|
353
|
+
await fs.writeFile(reportPath, payload, "utf8");
|
|
354
|
+
runLog.logText(`[audit] report written${note} → ${reportPath}`);
|
|
355
|
+
logger.info(`Audit report written: ${reportPath}`);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
function persistRun(ctx) {
|
|
359
|
+
const now = new Date().toISOString();
|
|
360
|
+
persistAuditRun(ctx.config?.projectDir || process.cwd(), { runId: now, timestamp: now, gitSha: null, harness: scoredHarness(ctx.harnessSummary), rawReportPath: ctx.reportPath });
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/** Deterministic-only path: the report from what was already collected, persisted, zero tokens spent. */
|
|
364
|
+
async function deterministicOnlyAudit(ctx) {
|
|
365
|
+
const { json, invocation, deterministicCtx, deterministicMd, harnessMd, reportPath, logger } = ctx;
|
|
366
|
+
const { harnessJson, history, historyMd } = harnessReport(ctx);
|
|
367
|
+
const payloadJson = JSON.stringify({ deterministic: deterministicCtx, harnessScore: harnessJson, harnessScoreDiff: history.diff, mode: "deterministic-only" }, null, 2);
|
|
368
|
+
let stdoutContent = `${harnessMd}${historyMd}`;
|
|
369
|
+
if (json) stdoutContent = payloadJson;
|
|
370
|
+
else if (invocation.deterministicOnly) stdoutContent = `${deterministicMd}\n${harnessMd}${historyMd}`;
|
|
371
|
+
if (json || invocation.deterministicOnly || harnessMd) console.log(stdoutContent);
|
|
372
|
+
await writeReport({ ctx, payloadJson, markdownBody: `${deterministicMd}\n${harnessMd}${historyMd}`, note: " (deterministic-only)" });
|
|
373
|
+
persistRun(ctx);
|
|
374
|
+
logger.info("Audit completed (deterministic-only).");
|
|
375
|
+
return { ok: true, mode: "deterministic-only", reportPath: reportPath || undefined };
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* KJC-BUG-0094: resilient fallback — if the configured provider/model
|
|
380
|
+
* is down (e.g. an inherited model like "claude-fable-5" is offline),
|
|
381
|
+
* degrade to the provider default, then to the next installed provider,
|
|
382
|
+
* reusing the deterministic context so no static analysis is re-run.
|
|
383
|
+
*/
|
|
384
|
+
async function runLlmPhase({ config, logger, roleInput, deterministicCtx, available, fallbackCandidates }) {
|
|
385
|
+
const progress = createCliProgressReporter({ role: "auditor" });
|
|
386
|
+
try {
|
|
387
|
+
const roleResult = await runAuditWithFallback({
|
|
388
|
+
config, logger,
|
|
389
|
+
roleInput: { ...roleInput, onOutput: progress.onOutput },
|
|
390
|
+
deterministicCtx,
|
|
391
|
+
available,
|
|
392
|
+
candidates: fallbackCandidates,
|
|
393
|
+
onFallback: (cand) => logger.warn(`Audit provider fallback → ${cand.provider}${cand.model ? ` (${cand.model})` : " (default model)"}`),
|
|
394
|
+
});
|
|
395
|
+
progress.finish(roleResult.ok ? "done" : "failed");
|
|
396
|
+
return roleResult;
|
|
397
|
+
} catch (err) {
|
|
398
|
+
progress.finish("failed");
|
|
399
|
+
throw err;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
function llmStdout({ parsed, usage, roleResult, harnessMd, historyMd }) {
|
|
404
|
+
if (parsed?.summary?.overallHealth) return `${formatAudit(parsed, usage)}\n${harnessMd}${historyMd}`;
|
|
405
|
+
if (parsed?.raw) return parsed.raw + (usage ? `\n\n${formatUsageSummary(usage) || ""}` : "") + `\n${harnessMd}${historyMd}`;
|
|
406
|
+
return `${roleResult.summary || "Audit complete."}\n${harnessMd}${historyMd}`;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/** The LLM phase, over the deterministic context already collected. */
|
|
410
|
+
async function llmAudit(ctx) {
|
|
411
|
+
const { json, runLog, logger, harnessMd, reportPath } = ctx;
|
|
412
|
+
const roleResult = await runLlmPhase(ctx);
|
|
413
|
+
if (!roleResult.ok) throw new Error(roleResult.result?.error || "Audit failed");
|
|
414
|
+
const parsed = roleResult.result;
|
|
415
|
+
const usage = roleResult.usage;
|
|
416
|
+
if (parsed?.summary?.overallHealth) {
|
|
417
|
+
runLog.logText(`[audit] findings=${parsed.summary.totalFindings} (critical=${parsed.summary.critical}, high=${parsed.summary.high})`);
|
|
418
|
+
}
|
|
419
|
+
if (usage?.available) {
|
|
420
|
+
runLog.logText(`[audit] usage tokens=${usage.total_tokens} cost=$${(usage.cost_usd ?? 0).toFixed(4)} duration=${(usage.durationMs / 1000).toFixed(1)}s`);
|
|
421
|
+
}
|
|
422
|
+
const { harnessJson, history, historyMd } = harnessReport(ctx);
|
|
423
|
+
const payloadJson = JSON.stringify({ ...(parsed || roleResult), harnessScore: harnessJson, harnessScoreDiff: history.diff, usage: usage || undefined }, null, 2);
|
|
424
|
+
const stdoutContent = json ? payloadJson : llmStdout({ parsed, usage, roleResult, harnessMd, historyMd });
|
|
425
|
+
console.log(stdoutContent);
|
|
426
|
+
await writeReport({ ctx, payloadJson, markdownBody: `${stdoutContent}\n`, note: "" });
|
|
427
|
+
persistRun(ctx);
|
|
428
|
+
logger.info("Audit completed.");
|
|
429
|
+
return { ok: true, reportPath: reportPath || undefined };
|
|
427
430
|
}
|
|
428
431
|
|
|
429
432
|
// Exposed for tests — kept module-private otherwise.
|
package/src/commands/board.js
CHANGED
|
@@ -2,9 +2,10 @@ import fs from "node:fs";
|
|
|
2
2
|
import http from "node:http";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import net from "node:net";
|
|
5
|
-
import {
|
|
5
|
+
import { spawn } from "node:child_process";
|
|
6
6
|
import { getKarajanHome } from "../utils/paths.js";
|
|
7
7
|
import { projectSlug as slugOfDir } from "../plan/plan-store.js";
|
|
8
|
+
import { mainCheckout } from "../utils/main-checkout.js";
|
|
8
9
|
import { getPortOccupant } from "../utils/port-occupant.js";
|
|
9
10
|
|
|
10
11
|
const BOARD_DIR = path.resolve(import.meta.dirname, "../../packages/hu-board");
|
|
@@ -90,16 +91,11 @@ export function buildBoardUrl(port, projectSlug) {
|
|
|
90
91
|
}
|
|
91
92
|
|
|
92
93
|
/**
|
|
93
|
-
* KJC-TSK-0884: the board slug of a project is its
|
|
94
|
-
*
|
|
94
|
+
* KJC-TSK-0884: the board slug of a project is its main checkout's (#2566), even from a
|
|
95
|
+
* lane or a subfolder, or the lane opens an empty view. A git failure throws, never falls back.
|
|
95
96
|
*/
|
|
96
97
|
export function boardSlug(projectDir) {
|
|
97
|
-
|
|
98
|
-
try {
|
|
99
|
-
const common = execFileSync("git", ["-C", projectDir, "rev-parse", "--path-format=absolute", "--git-common-dir"], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
|
|
100
|
-
if (path.basename(common) === ".git") dir = path.dirname(common);
|
|
101
|
-
} catch { /* not a git repo: the dir is the project */ }
|
|
102
|
-
return slugOfDir(dir);
|
|
98
|
+
return slugOfDir(mainCheckout(projectDir));
|
|
103
99
|
}
|
|
104
100
|
|
|
105
101
|
/**
|
package/src/commands/check.js
CHANGED
|
@@ -25,16 +25,7 @@ export async function checkCommand({ projectDir = process.cwd(), profile = "stan
|
|
|
25
25
|
// An evaluation error (corrupt store, git failure) is a failing check, never
|
|
26
26
|
// a silent pass: the only tolerated non-red state is the explicit "no index".
|
|
27
27
|
const ragCoverage = await createRagCoverageCheck().detect({ config, projectDir }).catch((err) => ({ ok: false, severity: "fail", detail: `rag coverage could not be evaluated: ${err.message}` }));
|
|
28
|
-
|
|
29
|
-
// KJC-TSK-0728: observed agent CLIs ride the same snapshot as "(cli)"
|
|
30
|
-
// entries, so a newly-appeared agent binary trips the same drift question.
|
|
31
|
-
let aiSurface = null;
|
|
32
|
-
try {
|
|
33
|
-
const clis = (await detectObservedAgents().catch(() => []))
|
|
34
|
-
.filter((a) => a.available)
|
|
35
|
-
.map((a) => `${a.name} (cli)`);
|
|
36
|
-
aiSurface = checkAiSurface({ projectDir, extraSurface: clis });
|
|
37
|
-
} catch { /* inventory is best-effort */ }
|
|
28
|
+
const aiSurface = await observedAiSurface(projectDir);
|
|
38
29
|
|
|
39
30
|
// KJC-TSK-1059: young dependencies the branch brings in, a warning outside the review.
|
|
40
31
|
const depCooldown = await branchCooldownLines({ projectDir, base: config?.base_branch ?? "main", thresholdHours: config?.supply_chain?.cooldown_hours })
|
|
@@ -48,10 +39,35 @@ export async function checkCommand({ projectDir = process.cwd(), profile = "stan
|
|
|
48
39
|
return ok ? 0 : 1;
|
|
49
40
|
}
|
|
50
41
|
|
|
42
|
+
printReport({ profile, result, method, ragCoverage, aiSurface, depCooldown, audit, config, ok, logger });
|
|
43
|
+
return ok ? 0 : 1;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// KJC-TSK-0694: same deal for the MCP inventory — a nudge, never a gate.
|
|
47
|
+
// KJC-TSK-0728: observed agent CLIs ride the same snapshot as "(cli)"
|
|
48
|
+
// entries, so a newly-appeared agent binary trips the same drift question.
|
|
49
|
+
async function observedAiSurface(projectDir) {
|
|
50
|
+
try {
|
|
51
|
+
const clis = (await detectObservedAgents().catch(() => []))
|
|
52
|
+
.filter((a) => a.available)
|
|
53
|
+
.map((a) => `${a.name} (cli)`);
|
|
54
|
+
return checkAiSurface({ projectDir, extraSurface: clis });
|
|
55
|
+
} catch { return null; /* inventory is best-effort */ }
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const mark = (ok) => (ok ? "✓" : "✗");
|
|
59
|
+
|
|
60
|
+
function verdictLine(ok, harnessOk) {
|
|
61
|
+
if (ok) return "Harness OK.";
|
|
62
|
+
if (harnessOk) return "RAG index drift detected — a gate cannot protect what it cannot see.";
|
|
63
|
+
return "Harness drift detected — run `kj harden` to repair.";
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function printReport({ profile, result, method, ragCoverage, aiSurface, depCooldown, audit, config, ok, logger }) {
|
|
51
67
|
logger.info?.(`kj check (${profile})`);
|
|
52
|
-
for (const c of result.checks) logger.info?.(` ${c.ok
|
|
68
|
+
for (const c of result.checks) logger.info?.(` ${mark(c.ok)} ${c.id}: ${c.detail}`);
|
|
53
69
|
if (method) logger.info?.(` method: ${formatMethodStats(method)}`);
|
|
54
|
-
logger.info?.(` ${ragCoverage.ok
|
|
70
|
+
logger.info?.(` ${mark(ragCoverage.ok)} rag-coverage: ${ragCoverage.detail}`);
|
|
55
71
|
if (aiSurface) logger.info?.(` ${formatAiSurface(aiSurface)}`);
|
|
56
72
|
for (const line of depCooldown) logger.info?.(` ${line}`);
|
|
57
73
|
logger.info?.(` ${audit.line}`);
|
|
@@ -59,8 +75,5 @@ export async function checkCommand({ projectDir = process.cwd(), profile = "stan
|
|
|
59
75
|
// said out loud next to everything else that describes the project. Never
|
|
60
76
|
// a check: it has no ok/fail, it informs.
|
|
61
77
|
logger.info?.(` ${panelSummary(config)}`);
|
|
62
|
-
|
|
63
|
-
else if (result.ok) logger.info?.("RAG index drift detected — a gate cannot protect what it cannot see.");
|
|
64
|
-
else logger.info?.("Harness drift detected — run `kj harden` to repair.");
|
|
65
|
-
return ok ? 0 : 1;
|
|
78
|
+
logger.info?.(verdictLine(ok, result.ok));
|
|
66
79
|
}
|
package/src/commands/doctor.js
CHANGED
|
@@ -33,6 +33,7 @@ import { getNodeChecks } from "../checks/node.js";
|
|
|
33
33
|
import { getNativeBuildChecks } from "../checks/native-build.js";
|
|
34
34
|
import { getPortChecks } from "../checks/ports.js";
|
|
35
35
|
import { getTokenChecks } from "../checks/tokens.js";
|
|
36
|
+
import { getAgentTokenChecks } from "../checks/agent-token.js";
|
|
36
37
|
import { getMcpHealthChecks } from "../checks/mcp-health.js";
|
|
37
38
|
import { getSkillsChecks } from "../checks/skills.js";
|
|
38
39
|
import { getDirSetupChecks } from "../checks/dir-setup.js";
|
|
@@ -72,6 +73,7 @@ function buildChecks(config, { projectOnly = false } = {}) {
|
|
|
72
73
|
...getPhoneChecks(),
|
|
73
74
|
...getPortChecks(),
|
|
74
75
|
...getTokenChecks(config),
|
|
76
|
+
...getAgentTokenChecks({ projectDir }),
|
|
75
77
|
...getMcpHealthChecks(),
|
|
76
78
|
...getSkillsChecks(),
|
|
77
79
|
...getCiChecks(),
|