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
|
@@ -17,39 +17,19 @@
|
|
|
17
17
|
// ---- Command launcher modal ----
|
|
18
18
|
//
|
|
19
19
|
// Opens a small form inside the existing <dialog> singleton with a
|
|
20
|
-
// command picker (
|
|
20
|
+
// command picker (today: clean) and the appropriate
|
|
21
21
|
// fields per command. Submit POSTs to /api/commands/:command, the
|
|
22
22
|
// server spawns a detached `kj` child, and we open the existing log
|
|
23
|
-
// viewer (
|
|
24
|
-
//
|
|
23
|
+
// viewer (openGenericLogPanel's tail loop, pointed at the
|
|
24
|
+
// generic /api/runs/:commandId/log endpoint).
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
async function showCommandLauncher() {
|
|
28
28
|
const dlg = ensureDialog();
|
|
29
29
|
// Per-command field schemas — kept in the client because each
|
|
30
30
|
// command has different inputs and the modal renders accordingly.
|
|
31
|
+
// KJC-TSK-1323: kj plan (generate) and kj architect left with 5.0, which retired them.
|
|
31
32
|
const SCHEMAS = {
|
|
32
|
-
plan: {
|
|
33
|
-
label: '📋 kj plan',
|
|
34
|
-
help: 'Generate an implementation plan with HUs. Paste the task text OR a file path.',
|
|
35
|
-
fields: [
|
|
36
|
-
{ name: 'taskFile', label: 'SPEC file path (absolute)', type: 'text', placeholder: '/home/me/project/SPEC.md' },
|
|
37
|
-
{ name: 'task', label: 'OR paste task text directly', type: 'textarea', rows: 6 },
|
|
38
|
-
{ name: 'context', label: 'Extra context (optional)', type: 'text' },
|
|
39
|
-
{ name: 'projectDir', label: 'Project directory (optional, defaults to board\'s cwd)', type: 'text' },
|
|
40
|
-
{ name: 'quick', label: '--quick (skip synth + reviewer)', type: 'checkbox' },
|
|
41
|
-
],
|
|
42
|
-
},
|
|
43
|
-
architect: {
|
|
44
|
-
label: '🏛 kj architect',
|
|
45
|
-
help: 'Design an architecture and persist ADRs. Same input as kj plan.',
|
|
46
|
-
fields: [
|
|
47
|
-
{ name: 'taskFile', label: 'SPEC file path (absolute)', type: 'text', placeholder: '/home/me/project/SPEC.md' },
|
|
48
|
-
{ name: 'task', label: 'OR paste task text directly', type: 'textarea', rows: 6 },
|
|
49
|
-
{ name: 'context', label: 'Extra context (optional)', type: 'text' },
|
|
50
|
-
{ name: 'projectDir', label: 'Project directory (optional)', type: 'text' },
|
|
51
|
-
],
|
|
52
|
-
},
|
|
53
33
|
clean: {
|
|
54
34
|
label: '🧹 kj clean',
|
|
55
35
|
help: 'Garbage-collect plans / sessions / batches. --nuke wipes everything including the board DB.',
|
|
@@ -60,25 +40,10 @@ async function showCommandLauncher() {
|
|
|
60
40
|
},
|
|
61
41
|
};
|
|
62
42
|
|
|
63
|
-
|
|
64
|
-
// language — one textarea, clear promise of what will happen. The full
|
|
65
|
-
// technical launcher (file paths, architect, clean) stays one click
|
|
66
|
-
// away behind "Más opciones…".
|
|
67
|
-
const maggle = isMaggleMode();
|
|
68
|
-
let advancedVisible = !maggle;
|
|
69
|
-
if (maggle) {
|
|
70
|
-
SCHEMAS.plan.label = maggleText('launcher.planLabel', SCHEMAS.plan.label);
|
|
71
|
-
SCHEMAS.plan.help = maggleText('launcher.planHelp', SCHEMAS.plan.help);
|
|
72
|
-
SCHEMAS.plan.simpleFields = [
|
|
73
|
-
{ name: 'task', label: maggleText('launcher.taskLabel', 'Task'), type: 'textarea', rows: 6 },
|
|
74
|
-
];
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
let active = 'plan';
|
|
43
|
+
let active = 'clean';
|
|
78
44
|
const renderForm = () => {
|
|
79
45
|
const s = SCHEMAS[active];
|
|
80
|
-
const
|
|
81
|
-
const fields = visibleFields.map((f) => {
|
|
46
|
+
const fields = s.fields.map((f) => {
|
|
82
47
|
const id = `cmd-field-${f.name}`;
|
|
83
48
|
if (f.type === 'textarea') {
|
|
84
49
|
return `
|
|
@@ -112,7 +77,7 @@ async function showCommandLauncher() {
|
|
|
112
77
|
</button>
|
|
113
78
|
</div>
|
|
114
79
|
<div style="padding:12px 18px;display:flex;gap:8px;border-bottom:1px solid var(--border)">
|
|
115
|
-
${Object.entries(SCHEMAS).
|
|
80
|
+
${Object.entries(SCHEMAS).map(([key, s]) => `
|
|
116
81
|
<button type="button" data-cmd="${key}"
|
|
117
82
|
style="padding:6px 12px;border:1px solid var(--border);
|
|
118
83
|
background:${key === active ? 'var(--color-green)' : 'var(--bg-primary)'};
|
|
@@ -121,13 +86,6 @@ async function showCommandLauncher() {
|
|
|
121
86
|
${esc(s.label)}
|
|
122
87
|
</button>
|
|
123
88
|
`).join('')}
|
|
124
|
-
${maggle && !advancedVisible ? `
|
|
125
|
-
<button type="button" id="cmd-more"
|
|
126
|
-
style="margin-left:auto;padding:6px 12px;border:1px solid var(--border);background:var(--bg-primary);color:var(--text-muted);border-radius:var(--radius-sm);cursor:pointer;font-size:0.85rem"
|
|
127
|
-
title="Comandos técnicos: kj plan con ficheros, kj architect, kj clean">
|
|
128
|
-
${esc(maggleText('launcher.more', 'More…'))}
|
|
129
|
-
</button>
|
|
130
|
-
` : ''}
|
|
131
89
|
</div>
|
|
132
90
|
<form id="cmd-form" onsubmit="return false"
|
|
133
91
|
style="padding:14px 18px;display:flex;flex-direction:column;gap:12px;width:min(640px, 88vw);box-sizing:border-box">
|
|
@@ -149,8 +107,6 @@ async function showCommandLauncher() {
|
|
|
149
107
|
dlg.querySelectorAll('[data-cmd]').forEach((btn) => {
|
|
150
108
|
btn.addEventListener('click', () => { active = btn.dataset.cmd; renderForm(); });
|
|
151
109
|
});
|
|
152
|
-
const moreBtn = dlg.querySelector('#cmd-more');
|
|
153
|
-
if (moreBtn) moreBtn.addEventListener('click', () => { advancedVisible = true; renderForm(); });
|
|
154
110
|
dlg.querySelector('#cmd-close').addEventListener('click', () => dlg.close());
|
|
155
111
|
dlg.querySelector('#cmd-cancel').addEventListener('click', () => dlg.close());
|
|
156
112
|
dlg.querySelector('#cmd-submit').addEventListener('click', () => submitCommand(active));
|
|
@@ -168,23 +124,6 @@ async function showCommandLauncher() {
|
|
|
168
124
|
if (v) body[f.name] = v;
|
|
169
125
|
}
|
|
170
126
|
}
|
|
171
|
-
// plan / architect: at least one of taskFile or task is required.
|
|
172
|
-
if ((command === 'plan' || command === 'architect') && !body.taskFile && !body.task) {
|
|
173
|
-
await showError(
|
|
174
|
-
maggle ? 'Escribe primero qué quieres pedir — con tus palabras vale.' : 'Provide either a SPEC file path or paste the task text.',
|
|
175
|
-
{ title: 'Missing input' }
|
|
176
|
-
);
|
|
177
|
-
return;
|
|
178
|
-
}
|
|
179
|
-
// AC2: before launching, the maggle confirms knowing exactly what
|
|
180
|
-
// will happen — in their language, never a command name alone.
|
|
181
|
-
if (maggle && command === 'plan') {
|
|
182
|
-
const ok = await showConfirm(maggleText('launcher.confirm', ''), {
|
|
183
|
-
title: SCHEMAS.plan.label,
|
|
184
|
-
okLabel: maggleText('launcher.submit', 'Run'),
|
|
185
|
-
});
|
|
186
|
-
if (!ok) return;
|
|
187
|
-
}
|
|
188
127
|
if (command === 'clean' && body.nuke) {
|
|
189
128
|
const ok = await showConfirm(
|
|
190
129
|
'`kj clean --nuke` will delete EVERY plan / session / batch + wipe the HU Board DB. Cannot be undone.',
|
|
@@ -220,8 +159,7 @@ async function showCommandLauncher() {
|
|
|
220
159
|
|
|
221
160
|
/**
|
|
222
161
|
* Open the run-log panel pointed at a /api/runs/<commandId>/log
|
|
223
|
-
* tail
|
|
224
|
-
* just swaps the URL it polls.
|
|
162
|
+
* tail, with the generic panel UI (openGenericLogPanel).
|
|
225
163
|
*/
|
|
226
164
|
function openCommandLogViewer(commandLabel, commandId) {
|
|
227
165
|
const args = {
|
|
@@ -161,6 +161,16 @@ function formatDuration(ms) {
|
|
|
161
161
|
return `${min}m ${sec.toString().padStart(2, '0')}s`;
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
+
// KJC-TSK-0403 + KJC-BUG-0405: the three kanban lanes, one place for every view. A failed
|
|
165
|
+
// HU goes back to Pending with its badge; `running` is what kj hu move and the shared-board
|
|
166
|
+
// mirror write, next to the pipeline's coding/reviewing.
|
|
167
|
+
const KANBAN_RUNNING = new Set(['coding', 'reviewing', 'running']);
|
|
168
|
+
function kanbanColumnOf(status) {
|
|
169
|
+
if (KANBAN_RUNNING.has(status)) return 'running';
|
|
170
|
+
if (status === 'done') return 'done';
|
|
171
|
+
return 'pending';
|
|
172
|
+
}
|
|
173
|
+
|
|
164
174
|
function scoreClass(score, max = 60) {
|
|
165
175
|
if (score === null || score === undefined) return '';
|
|
166
176
|
const pct = score / max;
|
|
@@ -23,7 +23,7 @@ async function renderGovernance() {
|
|
|
23
23
|
return;
|
|
24
24
|
}
|
|
25
25
|
localStorage.setItem(GOV_DIR_KEY, data.dir);
|
|
26
|
-
app.innerHTML = govDirForm(data.dir) + govIdentity(data.identity) + govChain(data.report, data.anchor) + govRules(data.policy, data.report) + govGrants(data.report.grants, data.policy) + govSignals(data.report.signals);
|
|
26
|
+
app.innerHTML = govDirForm(data.dir) + govIdentity(data.identity) + govChain(data.report, data.anchor) + govRules(data.policy, data.report) + govGrants(data.report.grants, data.policy) + govSignals(data.report.signals) + govLanes(data.lanes);
|
|
27
27
|
} catch (err) {
|
|
28
28
|
app.innerHTML = govDirForm(dir) + `<div class="empty-state"><div class="empty-state__title">Governance unavailable</div><div class="empty-state__text">${esc(err.message)}</div></div>`;
|
|
29
29
|
}
|
|
@@ -146,4 +146,16 @@ function govGrants(g, policy) {
|
|
|
146
146
|
return `<div class="section-header"><span class="section-header__title">Standing exceptions</span><span class="section-header__count">${(g.alive || []).length} alive · ${(g.soon || []).length} expiring · ${(g.expired || []).length} expired · ${g.point || 0} one-off</span></div>${alive}${renewals ? `<ul class="gov-list">${renewals}</ul>` : ''}${form}<p id="gov-msg" class="gov-note"></p>`;
|
|
147
147
|
}
|
|
148
148
|
|
|
149
|
+
// KJC-TSK-1314: worktree lanes outside the method, each with what to do about it.
|
|
150
|
+
function govLanes(lanes) {
|
|
151
|
+
if (!lanes) return '';
|
|
152
|
+
const head = '<div class="section-header"><span class="section-header__title">Lanes</span></div>';
|
|
153
|
+
if (lanes.error) return `${head}<p class="gov-note">⚠ ${esc(lanes.error)}</p>`;
|
|
154
|
+
const items = [
|
|
155
|
+
...lanes.noCard.map((l) => `<li>⚠ ${esc(l.slug)} (${esc(l.branch)}): its branch names no card. Work starts from a card.</li>`),
|
|
156
|
+
...lanes.merged.map((l) => `<li>⚠ ${esc(l.slug)}: PR #${esc(String(l.pr))} is merged and the lane is still there: <code>${esc(l.done)}</code></li>`),
|
|
157
|
+
];
|
|
158
|
+
return head + (items.length ? `<ul class="gov-list">${items.join('')}</ul>` : '<p class="gov-note">Every lane works a card and none is left over.</p>');
|
|
159
|
+
}
|
|
160
|
+
|
|
149
161
|
const govSignals = (signals) => `<div class="section-header"><span class="section-header__title">Signals</span></div>${(signals || []).length ? `<ul class="gov-list">${signals.map((s) => `<li>⚠ ${esc(s)}</li>`).join('')}</ul>` : '<p class="gov-note">None.</p>'}`;
|
|
@@ -14,58 +14,6 @@
|
|
|
14
14
|
// - lastOpenedLog (mutable in app.js — assignment crosses scripts
|
|
15
15
|
// transparently because both share the same realm)
|
|
16
16
|
|
|
17
|
-
/**
|
|
18
|
-
* PR4: launch a single HU from the per-card ▶ button. Confirms with
|
|
19
|
-
* the user (so an accidental click doesn't kick a run) and POSTs to
|
|
20
|
-
* the new /api/hus/:huId/run endpoint, which resolves the planId
|
|
21
|
-
* server-side from the SQLite row.
|
|
22
|
-
*
|
|
23
|
-
* Exposed on `window` because the inline onclick on the card calls it.
|
|
24
|
-
*/
|
|
25
|
-
window.runSingleHuFromCard = async function runSingleHuFromCard(huId, title) {
|
|
26
|
-
const friendlyTitle = (title || huId).replace(/'/g, "'");
|
|
27
|
-
const ok = await showConfirm(
|
|
28
|
-
`¿Lanzar solo esta HU?\n\n${friendlyTitle}\n\nKarajan ejecutará únicamente esta HU; las demás del plan no se tocarán.`,
|
|
29
|
-
{ title: 'Lanzar HU individual', okLabel: 'Lanzar', cancelLabel: 'Cancelar' }
|
|
30
|
-
);
|
|
31
|
-
if (!ok) return;
|
|
32
|
-
try {
|
|
33
|
-
const res = await fetch(`/api/hus/${encodeURIComponent(huId)}/run`, {
|
|
34
|
-
method: 'POST',
|
|
35
|
-
headers: { 'Content-Type': 'application/json' },
|
|
36
|
-
body: JSON.stringify({}),
|
|
37
|
-
});
|
|
38
|
-
if (!res.ok) {
|
|
39
|
-
const msg = (await res.json().catch(() => ({}))).error || `HTTP ${res.status}`;
|
|
40
|
-
await showError(msg, { title: 'No se pudo lanzar la HU' });
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
const body = await res.json();
|
|
44
|
-
// Surface the log path so the user can tail it from the View log button
|
|
45
|
-
// AND auto-open the viewer so the click produces visible feedback. Without
|
|
46
|
-
// the open, the user clicks Lanzar, sees nothing change, and concludes the
|
|
47
|
-
// run never started — the run IS started, the log IS being written, the
|
|
48
|
-
// UI just wasn't showing it.
|
|
49
|
-
//
|
|
50
|
-
// The tail URL must be derived from body.logPath, not constructed from
|
|
51
|
-
// huId. When `kj run --plan ... --hu <id>` is launched, runPlan writes to
|
|
52
|
-
// <runsDir>/<planId>--hu-<localHuId>.log
|
|
53
|
-
// — not <runsDir>/hu-<huId>.log. The previous code guessed the wrong
|
|
54
|
-
// filename and the viewer would have hit a non-existent file even if
|
|
55
|
-
// it had been opened.
|
|
56
|
-
if (body.logPath) {
|
|
57
|
-
const logBasename = body.logPath.split('/').pop().replace(/\.log$/, '');
|
|
58
|
-
const tailUrl = (offset) => `/api/runs/${encodeURIComponent(logBasename)}/log?offset=${offset || 0}`;
|
|
59
|
-
lastOpenedLog = { id: `hu-${huId}`, label: `HU ${huId}`, tailUrl };
|
|
60
|
-
openGenericLogPanel({ id: logBasename, label: `HU ${huId}`, tailUrl });
|
|
61
|
-
}
|
|
62
|
-
await fetch('/api/sync', { method: 'POST' }).catch(() => {});
|
|
63
|
-
await renderBoard();
|
|
64
|
-
} catch (err) {
|
|
65
|
-
await showError(err.message || String(err), { title: 'Fallo al lanzar la HU' });
|
|
66
|
-
}
|
|
67
|
-
};
|
|
68
|
-
|
|
69
17
|
/**
|
|
70
18
|
* KJC-TSK-0394 step 2: devolver una HU al estado `pending` desde
|
|
71
19
|
* cualquier estado no-terminal (coding/reviewing/blocked zombi) o
|
|
@@ -174,27 +122,28 @@ window.saveHuAssignee = async function saveHuAssignee(storyId) {
|
|
|
174
122
|
}
|
|
175
123
|
};
|
|
176
124
|
|
|
177
|
-
// KJC-TSK-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
125
|
+
// KJC-TSK-1324: the ▶ of a card. Board story ids are `<project>::<hu id>` (sync.js).
|
|
126
|
+
window.startCardLane = async function startCardLane(storyId, event) {
|
|
127
|
+
event?.stopPropagation();
|
|
128
|
+
const [project, huId] = String(storyId).split('::');
|
|
129
|
+
if (!project || !huId) return showError(`Not a board card: ${storyId}`, { title: 'Cannot start the card' });
|
|
181
130
|
const ok = await showConfirm(
|
|
182
|
-
|
|
183
|
-
{ title: '
|
|
131
|
+
`Start ${huId}?\n\nkj opens its lane, moves the card to running and your panel's coder writes it there. Reviewing and committing stay with you.`,
|
|
132
|
+
{ title: 'Start card', okLabel: 'Start' }
|
|
184
133
|
);
|
|
185
134
|
if (!ok) return;
|
|
186
135
|
try {
|
|
187
|
-
const res = await fetch(`/api/
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
136
|
+
const res = await fetch(`/api/hu/${encodeURIComponent(huId)}/start`, {
|
|
137
|
+
method: 'POST',
|
|
138
|
+
headers: { 'Content-Type': 'application/json' },
|
|
139
|
+
body: JSON.stringify({ project }),
|
|
140
|
+
});
|
|
141
|
+
const payload = await res.json().catch(() => ({}));
|
|
142
|
+
if (res.status === 409) return showError(`${huId} already has a lane. Open it with:\n\ncd ${payload.lane}`, { title: 'Card already started' });
|
|
143
|
+
if (!res.ok) return showError(payload.error || `HTTP ${res.status}`, { title: 'Could not start the card' });
|
|
144
|
+
openCommandLogViewer(`hu start ${huId}`, payload.commandId);
|
|
196
145
|
} catch (err) {
|
|
197
|
-
await showError(err.message || String(err), { title: '
|
|
146
|
+
await showError(err.message || String(err), { title: 'Could not start the card' });
|
|
198
147
|
}
|
|
199
148
|
};
|
|
200
149
|
|
|
@@ -15,8 +15,7 @@
|
|
|
15
15
|
// - showStoryDetail() (utils/story-detail-view.js)
|
|
16
16
|
// - showSessionDetail() (utils/sessions-view.js)
|
|
17
17
|
// - selectProject() (app.js)
|
|
18
|
-
// - triggerSync()
|
|
19
|
-
// startStandbyPolling() (utils/api.js)
|
|
18
|
+
// - triggerSync() (utils/api.js)
|
|
20
19
|
// - subscribeToServerEvents(),
|
|
21
20
|
// smartRefresh() (utils/server-push.js)
|
|
22
21
|
// - selectedProject, currentView,
|
|
@@ -45,7 +44,7 @@ document.getElementById('sync-btn').addEventListener('click', async () => {
|
|
|
45
44
|
});
|
|
46
45
|
|
|
47
46
|
// Commands button — opens the launcher modal so the user can run
|
|
48
|
-
// `kj
|
|
47
|
+
// `kj clean` (and more later) without
|
|
49
48
|
// dropping to a terminal. Output streams to the existing log panel.
|
|
50
49
|
document.getElementById('commands-btn').addEventListener('click', () => {
|
|
51
50
|
showCommandLauncher();
|
|
@@ -145,13 +144,13 @@ window.showSessionDetail = showSessionDetail;
|
|
|
145
144
|
window.closeModal = closeModal;
|
|
146
145
|
window.selectProject = selectProject;
|
|
147
146
|
|
|
148
|
-
// KJC-TSK-0414 PR4: arranca el polling del banner de standby al cargar la página.
|
|
149
|
-
startStandbyPolling();
|
|
150
|
-
|
|
151
147
|
// Initial load — sync disk data first so new batches are visible
|
|
152
|
-
triggerSync().then(() => {
|
|
153
|
-
handleRoute();
|
|
148
|
+
triggerSync().then(async () => {
|
|
149
|
+
const shown = handleRoute();
|
|
154
150
|
subscribeToServerEvents();
|
|
151
|
+
// KJC-TSK-1198: the guided tour, by itself on the first visit only, once the view is drawn.
|
|
152
|
+
await shown;
|
|
153
|
+
maybeStartFirstTour();
|
|
155
154
|
});
|
|
156
155
|
|
|
157
156
|
// Auto-refresh every 60 seconds as a SAFETY NET only — the board is
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// KJC-TSK-0501 step 7/8 — Floating run-log panel + window controls.
|
|
2
2
|
//
|
|
3
3
|
// Classic script (no exports). Loaded by index.html before app.js so
|
|
4
|
-
// the function declarations hoist and
|
|
5
|
-
//
|
|
4
|
+
// the function declarations hoist and the other scripts call
|
|
5
|
+
// openGenericLogPanel() directly.
|
|
6
6
|
// `logPollTimer` and `logViewerState` are top-level `let` bindings in
|
|
7
7
|
// this classic script — same realm as app.js, so the cross-script
|
|
8
8
|
// references keep working unchanged.
|
|
@@ -19,23 +19,10 @@
|
|
|
19
19
|
let logPollTimer = null;
|
|
20
20
|
let logViewerState = { planId: null, panel: null, offset: 0, isMax: false, isMin: false };
|
|
21
21
|
|
|
22
|
-
/**
|
|
23
|
-
* Open (or refocus) the run-log panel for the given plan. Thin shim
|
|
24
|
-
* over `openGenericLogPanel` — the original entry point used for
|
|
25
|
-
* `kj run --plan` runs that the Run-plan button kicks off.
|
|
26
|
-
*/
|
|
27
|
-
function openLogViewer(planId) {
|
|
28
|
-
return openGenericLogPanel({
|
|
29
|
-
id: planId,
|
|
30
|
-
label: 'Run log',
|
|
31
|
-
tailUrl: (offset) => `/api/plans/${encodeURIComponent(planId)}/log?offset=${offset}`,
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
|
|
35
22
|
/**
|
|
36
23
|
* Generic floating log panel anchored bottom-right. Used by:
|
|
37
|
-
* - openLogViewer(planId) → /api/plans/:planId/log
|
|
38
24
|
* - openCommandLogViewer(cmd, id) → /api/runs/:commandId/log
|
|
25
|
+
* (KJC-TSK-1351: the per-plan kj run log viewer went with kj run)
|
|
39
26
|
*
|
|
40
27
|
* The only thing that changes between callers is the tail URL +
|
|
41
28
|
* the label; the window controls (min/max/close), polling, and ANSI
|
|
@@ -18,12 +18,7 @@ const MAGGLE_LABELS = {
|
|
|
18
18
|
'board.title': 'Tu trabajo',
|
|
19
19
|
'board.stories': 'tareas',
|
|
20
20
|
'board.story': 'tarea',
|
|
21
|
-
'board.run': '▶ Continuar con lo pendiente',
|
|
22
|
-
'board.runTitle': 'Karajan seguirá con las tareas que faltan, una a una. Podrás ver la actividad aquí.',
|
|
23
|
-
'board.stop': '⏹ Parar',
|
|
24
|
-
'board.stopTitle': 'Detiene el trabajo en marcha. Lo ya terminado se conserva.',
|
|
25
21
|
'board.viewLog': '📜 Ver actividad',
|
|
26
|
-
'board.running': 'en marcha',
|
|
27
22
|
'board.ragPlaceholder': '🔍 Pregunta lo que quieras sobre este proyecto…',
|
|
28
23
|
'header.subtitle': 'tu tablero de trabajo',
|
|
29
24
|
'nav.board': 'Tablero',
|
|
@@ -31,14 +26,9 @@ const MAGGLE_LABELS = {
|
|
|
31
26
|
'nav.more': 'Más',
|
|
32
27
|
'picker.hint': 'Elige un proyecto para ver su tablero. Para cambiar de proyecto, vuelve a «Proyectos».',
|
|
33
28
|
'picker.project': 'proyecto',
|
|
34
|
-
'launcher.title': '
|
|
35
|
-
'launcher.
|
|
36
|
-
'launcher.planHelp': 'Cuéntale a Karajan qué quieres construir o cambiar, con tus palabras. Lo convertirá en tareas que verás en el tablero — todavía no toca tu código.',
|
|
37
|
-
'launcher.taskLabel': 'Qué quieres pedir',
|
|
38
|
-
'launcher.submit': 'Pedir',
|
|
29
|
+
'launcher.title': '⚡ Mantenimiento de Karajan',
|
|
30
|
+
'launcher.submit': 'Ejecutar',
|
|
39
31
|
'launcher.cancel': 'Cancelar',
|
|
40
|
-
'launcher.more': 'Más opciones…',
|
|
41
|
-
'launcher.confirm': 'Voy a convertir tu petición en tareas del tablero. Tardará unos minutos y podrás seguir la actividad en esta ventana. ¿Sigo?',
|
|
42
32
|
'conversation.title': 'Habla con tu agente',
|
|
43
33
|
'conversation.hide': 'Ocultar — la conversación sigue viva',
|
|
44
34
|
'conversation.end': 'Terminar la sesión del agente',
|
|
@@ -143,6 +143,11 @@ function showHelp() {
|
|
|
143
143
|
Tip: hover any tab in the header for ~1 second to see a one-line summary.
|
|
144
144
|
</div>
|
|
145
145
|
<div style="padding:12px 18px;border-top:1px solid var(--border);text-align:right">
|
|
146
|
+
<button id="app-dialog-tour" class="control-btn"
|
|
147
|
+
style="padding:6px 16px;border:none;background:var(--color-blue,#3b82f6);color:#fff;
|
|
148
|
+
border-radius:var(--radius-sm);cursor:pointer;margin-right:8px">
|
|
149
|
+
▶ Start the guided tour
|
|
150
|
+
</button>
|
|
146
151
|
<button id="app-dialog-close" class="control-btn"
|
|
147
152
|
style="padding:6px 16px;border:1px solid var(--border);
|
|
148
153
|
background:var(--bg-primary);color:var(--text);
|
|
@@ -157,6 +162,8 @@ function showHelp() {
|
|
|
157
162
|
};
|
|
158
163
|
dlg.addEventListener('close', done, { once: true });
|
|
159
164
|
dlg.querySelector('#app-dialog-close').addEventListener('click', done, { once: true });
|
|
165
|
+
// KJC-TSK-1198: the tour highlights the page, so the modal closes first.
|
|
166
|
+
dlg.querySelector('#app-dialog-tour').addEventListener('click', () => { done(); startBoardTour(); }, { once: true });
|
|
160
167
|
dlg.showModal();
|
|
161
168
|
});
|
|
162
169
|
}
|
|
@@ -52,7 +52,7 @@ async function renderProjectPicker() {
|
|
|
52
52
|
const c = { pending: 0, running: 0, done: 0, failed: 0 };
|
|
53
53
|
for (const s of stories) {
|
|
54
54
|
if (['pending', 'certified', 'needs_context', 'blocked'].includes(s.status)) c.pending += 1;
|
|
55
|
-
else if (
|
|
55
|
+
else if (kanbanColumnOf(s.status) === 'running') c.running += 1;
|
|
56
56
|
else if (s.status === 'done') c.done += 1;
|
|
57
57
|
else if (s.status === 'failed') c.failed += 1;
|
|
58
58
|
}
|
|
@@ -164,20 +164,11 @@ async function patchBoardIncremental() {
|
|
|
164
164
|
stories = await api(`/api/projects/${encodeURIComponent(selectedProject)}/stories`);
|
|
165
165
|
} catch { return false; }
|
|
166
166
|
|
|
167
|
-
//
|
|
168
|
-
// renderBoard's `columns` object — change there, change here).
|
|
169
|
-
const statusToColumn = (status) => {
|
|
170
|
-
if (['pending', 'certified', 'needs_context', 'blocked'].includes(status)) return 'pending';
|
|
171
|
-
if (['coding', 'reviewing'].includes(status)) return 'running';
|
|
172
|
-
if (status === 'done') return 'done';
|
|
173
|
-
if (status === 'failed') return 'failed';
|
|
174
|
-
return 'pending'; // safe default
|
|
175
|
-
};
|
|
176
|
-
|
|
167
|
+
// KJC-BUG-0405: the same lanes renderBoard uses (formatters.js::kanbanColumnOf).
|
|
177
168
|
const seen = new Set();
|
|
178
169
|
for (const story of stories) {
|
|
179
170
|
seen.add(story.id);
|
|
180
|
-
const targetCol = columns[
|
|
171
|
+
const targetCol = columns[kanbanColumnOf(story.status)];
|
|
181
172
|
if (!targetCol) continue;
|
|
182
173
|
const existing = kanban.querySelector(`.story-card[data-story-id="${cssEscape(story.id)}"]`);
|
|
183
174
|
if (!existing) {
|
|
@@ -232,21 +223,11 @@ async function patchBoardIncremental() {
|
|
|
232
223
|
setTimeout(() => node.remove(), 160);
|
|
233
224
|
}
|
|
234
225
|
}
|
|
235
|
-
// Recount each column
|
|
226
|
+
// Recount each column (the Running column's count is the "how many in progress").
|
|
236
227
|
for (const [cls, col] of Object.entries(columns)) {
|
|
237
228
|
const counter = col.querySelector('[data-column-count]');
|
|
238
229
|
if (counter) counter.textContent = String(col.querySelectorAll('.story-card').length);
|
|
239
230
|
col.style.opacity = col.querySelectorAll('.story-card').length === 0 ? '0.55' : '1';
|
|
240
231
|
}
|
|
241
|
-
const runningCount = columns.running.querySelectorAll('.story-card').length;
|
|
242
|
-
const runningBadge = document.querySelector('.section-header__badge');
|
|
243
|
-
if (runningBadge) {
|
|
244
|
-
if (runningCount > 0) {
|
|
245
|
-
runningBadge.textContent = `⚙ ${runningCount} running…`;
|
|
246
|
-
runningBadge.style.display = '';
|
|
247
|
-
} else {
|
|
248
|
-
runningBadge.style.display = 'none';
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
232
|
return true;
|
|
252
233
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// KJC-TSK-1197 — notice shown above the kanban when the project's board mirrors the
|
|
2
|
+
// shared board (GitHub Issues, ADR 0025): what it is, how it changes, where it lives.
|
|
3
|
+
//
|
|
4
|
+
// Classic script (no exports), loaded before app.js like plan-rollup-view.js.
|
|
5
|
+
// Globals consumed: esc() (app.js).
|
|
6
|
+
|
|
7
|
+
// owner/name as GitHub allows them: nothing that could leave the href.
|
|
8
|
+
const SHARED_BOARD_REPO = /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/;
|
|
9
|
+
|
|
10
|
+
/** The notice for the first plan that mirrors the shared board, or '' when there is none. */
|
|
11
|
+
function sharedBoardNoticeHtml(plans) {
|
|
12
|
+
const mirror = (plans || []).find((p) => p.readonly === 'github');
|
|
13
|
+
if (!mirror) return '';
|
|
14
|
+
const link = SHARED_BOARD_REPO.test(mirror.repo || '')
|
|
15
|
+
? ` <a href="https://github.com/${mirror.repo}/issues?q=${encodeURIComponent('label:kj:hu')}" target="_blank" rel="noopener" style="color:var(--color-blue,#3b82f6);">Open its issues on GitHub (${esc(mirror.repo)})</a>`
|
|
16
|
+
: '';
|
|
17
|
+
return `
|
|
18
|
+
<div role="note" style="margin:8px 0;padding:10px 14px;background:var(--bg-primary);border:1px solid var(--border);border-left:4px solid var(--color-blue,#3b82f6);border-radius:var(--radius-sm);font-size:0.85rem;">
|
|
19
|
+
<strong>This is the team's shared board.</strong>
|
|
20
|
+
Its stories live as GitHub Issues and the whole team sees the same ones, so it is read-only here:
|
|
21
|
+
change a story with <code>kj hu move</code> from a terminal.${link}
|
|
22
|
+
</div>
|
|
23
|
+
`;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Fills the notice slot for a project. No-op when the slot is not mounted. */
|
|
27
|
+
async function renderSharedBoardNotice(projectId) {
|
|
28
|
+
const slot = document.getElementById('shared-board-notice');
|
|
29
|
+
if (!slot) return;
|
|
30
|
+
const r = await fetch(`/api/projects/${encodeURIComponent(projectId)}/plans-outcome`);
|
|
31
|
+
if (!r.ok) throw new Error(`plans-outcome answered ${r.status}`);
|
|
32
|
+
slot.innerHTML = sharedBoardNoticeHtml((await r.json()).plans);
|
|
33
|
+
}
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
// - projectIsSharedCache (mutable, app.js)
|
|
13
13
|
// - renderStoryEditForm() (app.js)
|
|
14
14
|
// - closeModal(), changeHuStatusFromModal(), resetHuToPending(),
|
|
15
|
-
//
|
|
15
|
+
// saveHuModels(), saveHuAssignee() — bound on
|
|
16
16
|
// window from app.js so the inline handlers in this template
|
|
17
17
|
// keep working unchanged.
|
|
18
18
|
|
|
@@ -104,20 +104,6 @@ async function showStoryDetail(storyId) {
|
|
|
104
104
|
↺ Reset
|
|
105
105
|
</button>
|
|
106
106
|
` : ''}
|
|
107
|
-
${(() => {
|
|
108
|
-
// KJC-TSK-0408: Undo solo si la HU tiene snapshot_sha en outcome.
|
|
109
|
-
let parsedOutcome = null;
|
|
110
|
-
try { parsedOutcome = typeof story.outcome === 'string' ? JSON.parse(story.outcome) : story.outcome; } catch { /* */ }
|
|
111
|
-
const canUndo = parsedOutcome?.snapshot_sha && !parsedOutcome?.reverted;
|
|
112
|
-
return canUndo ? `
|
|
113
|
-
<button id="undo-hu-btn" class="control-btn"
|
|
114
|
-
style="padding:6px 12px;border:1px solid var(--color-red,#ef4444);background:var(--bg-primary);color:var(--color-red,#ef4444);border-radius:var(--radius-sm);cursor:pointer;font-size:0.85rem"
|
|
115
|
-
title="Deshacer cambios de esta HU: restaura los ficheros al snapshot pre-run y marca pending"
|
|
116
|
-
onclick="undoHuChanges('${esc(story.id)}')">
|
|
117
|
-
⏪ Undo
|
|
118
|
-
</button>
|
|
119
|
-
` : '';
|
|
120
|
-
})()}
|
|
121
107
|
<button class="modal__close" onclick="closeModal()">×</button>
|
|
122
108
|
</div>
|
|
123
109
|
</div>
|
|
@@ -254,10 +240,10 @@ async function showStoryDetail(storyId) {
|
|
|
254
240
|
<div class="modal__section" style="border:1px solid var(--color-yellow,#eab308);background:rgba(234,179,8,0.08);padding:10px 12px;border-radius:var(--radius-sm)">
|
|
255
241
|
<div class="modal__section-title" style="color:var(--color-yellow,#eab308)">⚠ Missing test contract</div>
|
|
256
242
|
<div style="font-size:0.85rem;line-height:1.5;margin-top:4px">
|
|
257
|
-
This HU has no
|
|
258
|
-
|
|
259
|
-
add
|
|
260
|
-
or a <code>gherkin</code> Given/When/Then spec.
|
|
243
|
+
This HU has no acceptance tests declared. The method writes the failing
|
|
244
|
+
test first, so declare at least one: ✎ Edit above, or
|
|
245
|
+
<code>kj hu add --tests</code>. A test is a <code>shell</code> command that
|
|
246
|
+
exits 0 on pass, or a <code>gherkin</code> Given/When/Then spec.
|
|
261
247
|
</div>
|
|
262
248
|
</div>
|
|
263
249
|
` : `
|
|
@@ -91,7 +91,6 @@ export function cleanupZombies(opts = {}) {
|
|
|
91
91
|
const storyIds = db.prepare('SELECT id FROM stories WHERE project_id = ?').all(proj.id).map((r) => r.id);
|
|
92
92
|
const sessionIds = db.prepare('SELECT id FROM sessions WHERE project_id = ?').all(proj.id).map((r) => r.id);
|
|
93
93
|
const fsPaths = [
|
|
94
|
-
...storyIds.map((sid) => path.join(getKjHome(), 'hu-stories', sid)),
|
|
95
94
|
...sessionIds.map((sid) => path.join(getKjHome(), 'sessions', sid)),
|
|
96
95
|
...plansRoots().map((root) => path.join(root, proj.id)),
|
|
97
96
|
];
|