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
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
import { VALID_TASK_TYPES } from "./policy-resolver.js";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Built-in intent patterns for deterministic pre-triage classification.
|
|
5
|
-
* Each pattern maps keywords/regex to a taskType + complexity level.
|
|
6
|
-
* Evaluated top-down; first match with confidence >= threshold wins.
|
|
7
|
-
*/
|
|
8
|
-
const INTENT_PATTERNS = [
|
|
9
|
-
// No-code tasks (data analysis, document generation, SQL queries, CSV transforms)
|
|
10
|
-
// Placed before audit so specific multi-word patterns win over single-word "analizar"/"analyze"
|
|
11
|
-
{
|
|
12
|
-
id: "no-code",
|
|
13
|
-
keywords: [
|
|
14
|
-
"generate report", "create document", "analyze data", "transform csv",
|
|
15
|
-
"sql query", "sql queries", "generate queries", "data analysis", "process data",
|
|
16
|
-
"export to", "import from", "convert data", "parse file",
|
|
17
|
-
"generar informe", "crear documento", "analizar datos", "transformar csv",
|
|
18
|
-
"consulta sql", "generar consultas", "analisis de datos", "procesar datos",
|
|
19
|
-
"exportar a", "importar de", "convertir datos", "parsear fichero",
|
|
20
|
-
],
|
|
21
|
-
taskType: "no-code",
|
|
22
|
-
level: "simple",
|
|
23
|
-
confidence: 0.9,
|
|
24
|
-
message: "No-code task detected — TDD and SonarQube disabled, coder generates non-code output",
|
|
25
|
-
},
|
|
26
|
-
// Audit / analysis tasks (no code changes, read-only analysis)
|
|
27
|
-
{
|
|
28
|
-
id: "audit",
|
|
29
|
-
keywords: ["audit", "review", "analyze", "check", "verify", "inspect", "scan", "auditar", "revisar", "analizar", "comprobar", "verificar", "inspeccionar"],
|
|
30
|
-
taskType: "audit",
|
|
31
|
-
level: "simple",
|
|
32
|
-
confidence: 0.9,
|
|
33
|
-
message: "Audit/analysis task detected — skipping coder and reviewer",
|
|
34
|
-
},
|
|
35
|
-
// Documentation-only tasks
|
|
36
|
-
{
|
|
37
|
-
id: "doc-readme",
|
|
38
|
-
keywords: ["readme", "docs", "documentation", "jsdoc", "typedoc", "changelog"],
|
|
39
|
-
taskType: "doc",
|
|
40
|
-
level: "trivial",
|
|
41
|
-
confidence: 0.95,
|
|
42
|
-
message: "Documentation-only task detected",
|
|
43
|
-
},
|
|
44
|
-
// Test-only tasks
|
|
45
|
-
{
|
|
46
|
-
id: "add-tests",
|
|
47
|
-
keywords: ["add test", "write test", "missing test", "test coverage", "add spec", "write spec", "unit test", "integration test"],
|
|
48
|
-
taskType: "add-tests",
|
|
49
|
-
level: "simple",
|
|
50
|
-
confidence: 0.9,
|
|
51
|
-
message: "Test-addition task detected",
|
|
52
|
-
},
|
|
53
|
-
// Refactoring tasks
|
|
54
|
-
{
|
|
55
|
-
id: "refactor",
|
|
56
|
-
keywords: ["refactor", "rename", "extract method", "extract function", "clean up", "cleanup", "reorganize", "restructure", "simplify"],
|
|
57
|
-
taskType: "refactor",
|
|
58
|
-
level: "simple",
|
|
59
|
-
confidence: 0.85,
|
|
60
|
-
message: "Refactoring task detected",
|
|
61
|
-
},
|
|
62
|
-
// Infrastructure / DevOps tasks
|
|
63
|
-
{
|
|
64
|
-
id: "infra-devops",
|
|
65
|
-
keywords: ["ci/cd", "pipeline", "dockerfile", "docker-compose", "kubernetes", "k8s", "terraform", "deploy", "nginx", "github actions", "gitlab ci"],
|
|
66
|
-
taskType: "infra",
|
|
67
|
-
level: "simple",
|
|
68
|
-
confidence: 0.85,
|
|
69
|
-
message: "Infrastructure/DevOps task detected",
|
|
70
|
-
},
|
|
71
|
-
// Trivial fixes (typos, comments, formatting)
|
|
72
|
-
{
|
|
73
|
-
id: "trivial-fix",
|
|
74
|
-
keywords: ["typo", "fix typo", "spelling", "comment", "fix comment", "formatting", "lint", "fix lint", "whitespace"],
|
|
75
|
-
taskType: "sw",
|
|
76
|
-
level: "trivial",
|
|
77
|
-
confidence: 0.9,
|
|
78
|
-
message: "Trivial fix detected",
|
|
79
|
-
},
|
|
80
|
-
// Frontend / UI tasks (sets hasFrontend flag for impeccable role activation)
|
|
81
|
-
{
|
|
82
|
-
id: "frontend-ui",
|
|
83
|
-
keywords: ["html", "css", "ui", "landing", "component", "responsive", "accessibility", "a11y", "frontend", "design", "layout", "styling", "dark mode", "animation"],
|
|
84
|
-
taskType: "sw",
|
|
85
|
-
level: "simple",
|
|
86
|
-
confidence: 0.8,
|
|
87
|
-
message: "Frontend/UI task detected",
|
|
88
|
-
hasFrontend: true,
|
|
89
|
-
},
|
|
90
|
-
];
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Compile custom intent patterns from config.guards.intent.patterns
|
|
94
|
-
* Custom patterns are evaluated BEFORE built-in ones.
|
|
95
|
-
*/
|
|
96
|
-
export function compileIntentPatterns(configGuards) {
|
|
97
|
-
const custom = Array.isArray(configGuards?.intent?.patterns)
|
|
98
|
-
? configGuards.intent.patterns.map(p => ({
|
|
99
|
-
id: p.id || "custom-intent",
|
|
100
|
-
keywords: Array.isArray(p.keywords) ? p.keywords : [],
|
|
101
|
-
taskType: VALID_TASK_TYPES.has(p.taskType) ? p.taskType : "sw",
|
|
102
|
-
level: p.level || "simple",
|
|
103
|
-
confidence: typeof p.confidence === "number" ? p.confidence : 0.85,
|
|
104
|
-
message: p.message || "Custom intent pattern matched",
|
|
105
|
-
}))
|
|
106
|
-
: [];
|
|
107
|
-
|
|
108
|
-
return [...custom, ...INTENT_PATTERNS];
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Check if a task description matches any of the keywords.
|
|
113
|
-
* Returns true if at least one keyword (case-insensitive substring) appears in the task.
|
|
114
|
-
*/
|
|
115
|
-
function matchesKeywords(task, keywords) {
|
|
116
|
-
const lower = task.toLowerCase();
|
|
117
|
-
for (const kw of keywords) {
|
|
118
|
-
if (lower.includes(kw.toLowerCase())) {
|
|
119
|
-
return true;
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
return false;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Classify a task description using deterministic keyword patterns.
|
|
127
|
-
*
|
|
128
|
-
* Returns:
|
|
129
|
-
* { classified: true, taskType, level, confidence, patternId, message }
|
|
130
|
-
* or { classified: false } if no pattern matches above threshold
|
|
131
|
-
*/
|
|
132
|
-
export function classifyIntent(task, config = {}) {
|
|
133
|
-
if (!task || typeof task !== "string") {
|
|
134
|
-
return { classified: false };
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
const configGuards = config?.guards || {};
|
|
138
|
-
const threshold = configGuards?.intent?.confidence_threshold ?? 0.85;
|
|
139
|
-
const patterns = compileIntentPatterns(configGuards);
|
|
140
|
-
|
|
141
|
-
for (const pattern of patterns) {
|
|
142
|
-
if (!matchesKeywords(task, pattern.keywords)) continue;
|
|
143
|
-
|
|
144
|
-
if (pattern.confidence >= threshold) {
|
|
145
|
-
const result = {
|
|
146
|
-
classified: true,
|
|
147
|
-
taskType: pattern.taskType,
|
|
148
|
-
level: pattern.level,
|
|
149
|
-
confidence: pattern.confidence,
|
|
150
|
-
patternId: pattern.id,
|
|
151
|
-
message: pattern.message,
|
|
152
|
-
};
|
|
153
|
-
if (pattern.hasFrontend) result.hasFrontend = true;
|
|
154
|
-
return result;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
return { classified: false };
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
export { INTENT_PATTERNS };
|
package/src/guards/perf-guard.js
DELETED
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
const FRONTEND_EXTENSIONS = new Set([".html", ".htm", ".css", ".jsx", ".tsx", ".astro", ".vue", ".svelte"]);
|
|
2
|
-
|
|
3
|
-
// Built-in perf anti-patterns (applied to added lines in frontend files)
|
|
4
|
-
const PERF_PATTERNS = [
|
|
5
|
-
{ id: "img-no-dimensions", pattern: /<img\b(?![^>]*\bwidth\b)(?![^>]*\bheight\b)[^>]*>/i, severity: "warning", message: "Image without width/height attributes (causes CLS)" },
|
|
6
|
-
{ id: "img-no-lazy", pattern: /<img\b(?![^>]*\bloading\s*=)(?![^>]*\bfetchpriority\s*=)[^>]*>/i, severity: "info", message: "Image without loading=\"lazy\" or fetchpriority (consider lazy loading)" },
|
|
7
|
-
{ id: "script-no-defer", pattern: /<script\b(?![^>]*\b(?:defer|async)\b)(?![^>]*type\s*=\s*["']module["'])[^>]*src\s*=/i, severity: "warning", message: "External script without defer/async (render-blocking)" },
|
|
8
|
-
{ id: "font-no-display", pattern: /@font-face\s*\{(?![^}]*font-display)/i, severity: "warning", message: "@font-face without font-display (causes FOIT)" },
|
|
9
|
-
{ id: "css-import", pattern: /@import\s+(?:url\()?["'](?!.*\.module\.)/i, severity: "info", message: "CSS @import (causes sequential loading, prefer <link>)" },
|
|
10
|
-
{ id: "inline-style-large", pattern: /style\s*=\s*["'][^"']{200,}["']/i, severity: "warning", message: "Large inline style (>200 chars, consider external CSS)" },
|
|
11
|
-
{ id: "document-write", pattern: /document\.write\s*\(/, severity: "warning", message: "document.write() blocks parsing and degrades performance" },
|
|
12
|
-
];
|
|
13
|
-
|
|
14
|
-
// Patterns for package.json changes (heavy dependencies added)
|
|
15
|
-
const HEAVY_DEPS = [
|
|
16
|
-
{ id: "heavy-moment", pattern: /"moment"/, severity: "info", message: "moment.js added (consider dayjs or date-fns for smaller bundle)" },
|
|
17
|
-
{ id: "heavy-lodash", pattern: /"lodash"(?!\/)/, severity: "info", message: "Full lodash added (consider lodash-es or individual imports)" },
|
|
18
|
-
{ id: "heavy-jquery", pattern: /"jquery"/, severity: "info", message: "jQuery added (consider native DOM APIs)" },
|
|
19
|
-
];
|
|
20
|
-
|
|
21
|
-
function getExtension(filePath) {
|
|
22
|
-
if (!filePath) return "";
|
|
23
|
-
const dot = filePath.lastIndexOf(".");
|
|
24
|
-
return dot >= 0 ? filePath.slice(dot).toLowerCase() : "";
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Check if any modified file in the diff is a frontend file
|
|
29
|
-
*/
|
|
30
|
-
export function hasFrontendFiles(diff) {
|
|
31
|
-
if (!diff) return false;
|
|
32
|
-
for (const line of diff.split("\n")) {
|
|
33
|
-
if (line.startsWith("+++ b/")) {
|
|
34
|
-
const ext = getExtension(line.slice(6));
|
|
35
|
-
if (FRONTEND_EXTENSIONS.has(ext)) return true;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
return false;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Extract added lines grouped by file from a unified diff
|
|
43
|
-
*/
|
|
44
|
-
function extractAddedLinesByFile(diff) {
|
|
45
|
-
const results = [];
|
|
46
|
-
let currentFile = null;
|
|
47
|
-
let lineNum = 0;
|
|
48
|
-
|
|
49
|
-
for (const line of diff.split("\n")) {
|
|
50
|
-
if (line.startsWith("+++ b/")) {
|
|
51
|
-
currentFile = line.slice(6);
|
|
52
|
-
continue;
|
|
53
|
-
}
|
|
54
|
-
if (line.startsWith("@@ ")) {
|
|
55
|
-
const match = /@@ -\d+(?:,\d+)? \+(\d+)/.exec(line);
|
|
56
|
-
lineNum = match ? Number.parseInt(match[1], 10) - 1 : 0;
|
|
57
|
-
continue;
|
|
58
|
-
}
|
|
59
|
-
if (line.startsWith("+") && !line.startsWith("+++")) {
|
|
60
|
-
lineNum += 1;
|
|
61
|
-
results.push({ file: currentFile, line: lineNum, content: line.slice(1) });
|
|
62
|
-
} else if (!line.startsWith("-")) {
|
|
63
|
-
lineNum += 1;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
return results;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Scan diff for frontend performance anti-patterns.
|
|
71
|
-
* Returns { pass: boolean, violations: [...], skipped: boolean }
|
|
72
|
-
*/
|
|
73
|
-
export function scanPerfDiff(diff, config = {}) {
|
|
74
|
-
if (!diff || typeof diff !== "string") {
|
|
75
|
-
return { pass: true, violations: [], skipped: true };
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
if (!hasFrontendFiles(diff)) {
|
|
79
|
-
return { pass: true, violations: [], skipped: true };
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const customPatterns = Array.isArray(config?.guards?.perf?.patterns)
|
|
83
|
-
? config.guards.perf.patterns.map(p => ({
|
|
84
|
-
id: p.id || "custom-perf",
|
|
85
|
-
pattern: typeof p.pattern === "string" ? new RegExp(p.pattern, p.flags || "i") : p.pattern,
|
|
86
|
-
severity: p.severity || "warning",
|
|
87
|
-
message: p.message || "Custom perf pattern matched",
|
|
88
|
-
}))
|
|
89
|
-
: [];
|
|
90
|
-
|
|
91
|
-
const allPatterns = [...PERF_PATTERNS, ...customPatterns];
|
|
92
|
-
const addedLines = extractAddedLinesByFile(diff);
|
|
93
|
-
const violations = [];
|
|
94
|
-
|
|
95
|
-
for (const { file, line, content } of addedLines) {
|
|
96
|
-
const ext = getExtension(file);
|
|
97
|
-
const isFrontend = FRONTEND_EXTENSIONS.has(ext);
|
|
98
|
-
const isPackageJson = file?.endsWith("package.json");
|
|
99
|
-
|
|
100
|
-
if (isFrontend) {
|
|
101
|
-
for (const { id, pattern, severity, message } of allPatterns) {
|
|
102
|
-
if (pattern.test(content)) {
|
|
103
|
-
violations.push({ id, severity, file, line, message, matchedContent: content.trim().slice(0, 200) });
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
if (isPackageJson) {
|
|
109
|
-
for (const { id, pattern, severity, message } of HEAVY_DEPS) {
|
|
110
|
-
if (pattern.test(content)) {
|
|
111
|
-
violations.push({ id, severity, file, line, message, matchedContent: content.trim().slice(0, 200) });
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// perf-guard is advisory by default — only blocks on critical (none built-in are critical)
|
|
118
|
-
const blockOnWarning = Boolean(config?.guards?.perf?.block_on_warning);
|
|
119
|
-
const hasCritical = violations.some(v => v.severity === "critical");
|
|
120
|
-
const hasWarning = violations.some(v => v.severity === "warning");
|
|
121
|
-
const pass = !hasCritical && !(blockOnWarning && hasWarning);
|
|
122
|
-
|
|
123
|
-
return { pass, violations, skipped: false };
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
export { PERF_PATTERNS, HEAVY_DEPS, FRONTEND_EXTENSIONS };
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Policy guard for kj_resume answers.
|
|
3
|
-
*
|
|
4
|
-
* Detects host-AI attempts to bypass pipeline policies (skip TDD, ignore
|
|
5
|
-
* reviewer, disable security, etc.) and rejects them with context-aware
|
|
6
|
-
* suggestions for valid alternatives.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
const BYPASS_PATTERNS = [
|
|
10
|
-
{ regex: /\b(?:skip|omit|drop)\s+(?:the\s+)?(?:tests?|tdd|testing)\b/i, policy: "tdd" },
|
|
11
|
-
{ regex: /\bdisable\s+(?:the\s+)?(?:tests?|tdd|testing)\b/i, policy: "tdd" },
|
|
12
|
-
{ regex: /\b(?:don'?t|do\s+not|no\s+need\s+(?:for|to))\s+(?:run\s+)?tests?\b/i, policy: "tdd" },
|
|
13
|
-
{ regex: /\bcontinue\s+without\s+test/i, policy: "tdd" },
|
|
14
|
-
{ regex: /\bswitch\s+(?:to\s+)?(?:standard\s+)?methodology/i, policy: "tdd" },
|
|
15
|
-
{ regex: /\bswitch\s+methodology/i, policy: "tdd" },
|
|
16
|
-
{ regex: /\b(?:skip|ignore|bypass|disable)\s+(?:the\s+)?(?:review(?:er)?|code\s+review)\b/i, policy: "reviewer" },
|
|
17
|
-
{ regex: /\b(?:approve|pass)\s+without\s+review/i, policy: "reviewer" },
|
|
18
|
-
{ regex: /\bmark\s+as\s+approved\b/i, policy: "reviewer" },
|
|
19
|
-
{ regex: /\bjust\s+ship\s+it/i, policy: "reviewer" },
|
|
20
|
-
{ regex: /\bignore\s+(?:the\s+)?(?:review(?:er)?\s+)?feedback\b/i, policy: "reviewer" },
|
|
21
|
-
{ regex: /\b(?:skip|ignore|bypass|disable)\s+(?:the\s+)?(?:sonar|sonarqube|quality\s+gate)/i, policy: "sonar" },
|
|
22
|
-
{ regex: /\bignore\s+sonar\s+issues?\b/i, policy: "sonar" },
|
|
23
|
-
{ regex: /\b(?:skip|ignore|bypass|disable)\s+(?:the\s+)?security(?:\s+checks?)?\b/i, policy: "security" },
|
|
24
|
-
];
|
|
25
|
-
|
|
26
|
-
const SUGGESTIONS_BY_POLICY = {
|
|
27
|
-
tdd: [
|
|
28
|
-
"Provide specific guidance for the coder on how to fix the failing tests",
|
|
29
|
-
"Describe the expected behavior so the coder can write correct tests",
|
|
30
|
-
"Suggest a different approach to implement the feature that is easier to test",
|
|
31
|
-
],
|
|
32
|
-
reviewer: [
|
|
33
|
-
"Provide technical guidance to address the reviewer's feedback",
|
|
34
|
-
"Explain why the current approach is correct if you disagree with the review",
|
|
35
|
-
"Suggest alternative implementations that satisfy the reviewer's concerns",
|
|
36
|
-
],
|
|
37
|
-
sonar: [
|
|
38
|
-
"Provide guidance on how to resolve the SonarQube issues",
|
|
39
|
-
"Explain the code changes needed to satisfy quality gate requirements",
|
|
40
|
-
],
|
|
41
|
-
security: [
|
|
42
|
-
"Provide guidance on how to fix the security issues found",
|
|
43
|
-
"Explain the secure alternative for the flagged pattern",
|
|
44
|
-
],
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
const CONTEXT_SUGGESTIONS = {
|
|
48
|
-
reviewer_fail_fast: [
|
|
49
|
-
"Provide specific technical guidance for the coder to address the reviewer's feedback",
|
|
50
|
-
"Suggest a different approach that resolves the reviewer's concerns",
|
|
51
|
-
],
|
|
52
|
-
max_iterations: [
|
|
53
|
-
"Provide focused guidance to help the coder converge on a solution",
|
|
54
|
-
"Narrow the scope: specify exactly which file/function to change and how",
|
|
55
|
-
"Continue with additional iterations by choosing option 1 or 2",
|
|
56
|
-
],
|
|
57
|
-
standby_exhausted: [
|
|
58
|
-
"Wait and retry — the provider may be temporarily overloaded",
|
|
59
|
-
"Continue to resume from where the pipeline left off",
|
|
60
|
-
],
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Validate a resume answer against pipeline policies.
|
|
65
|
-
*
|
|
66
|
-
* @param {string|null} answer - The resume answer from the host
|
|
67
|
-
* @param {string} [pauseContext] - The context of the pause (e.g. "reviewer_fail_fast")
|
|
68
|
-
* @returns {{ valid: boolean, reason?: string, suggestions?: string[] }}
|
|
69
|
-
*/
|
|
70
|
-
export function validatePolicyCompliance(answer, pauseContext) {
|
|
71
|
-
if (answer == null || answer === "") return { valid: true };
|
|
72
|
-
if (typeof answer !== "string") return { valid: true };
|
|
73
|
-
|
|
74
|
-
const text = answer.trim();
|
|
75
|
-
for (const { regex, policy } of BYPASS_PATTERNS) {
|
|
76
|
-
if (regex.test(text)) {
|
|
77
|
-
const suggestions = [
|
|
78
|
-
...(CONTEXT_SUGGESTIONS[pauseContext] || []),
|
|
79
|
-
...(SUGGESTIONS_BY_POLICY[policy] || []),
|
|
80
|
-
];
|
|
81
|
-
return {
|
|
82
|
-
valid: false,
|
|
83
|
-
reason: `Pipeline policy "${policy}" cannot be bypassed. Provide technical guidance instead.`,
|
|
84
|
-
suggestions: [...new Set(suggestions)],
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
return { valid: true };
|
|
90
|
-
}
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Policy resolution: map task type + config toggles to concrete pipeline
|
|
3
|
-
* flags (TDD, Sonar, reviewer retries, tests required, coder required, ...).
|
|
4
|
-
*
|
|
5
|
-
* @typedef {import("../types/policy.js").ResolvedPolicies} ResolvedPolicies
|
|
6
|
-
* @typedef {import("../types/config.js").KarajanConfig} KarajanConfig
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
// KJC-TSK-0400: spike y research añadidos como tipos no-code. Comparten
|
|
10
|
-
// las defaults restrictivas (tdd/sonar/testsRequired off) porque NO
|
|
11
|
-
// producen código que medir: un SPIKE es un .md de decisión, un research
|
|
12
|
-
// es una nota de investigación. Forzar Sonar les hace fallar siempre.
|
|
13
|
-
export const VALID_TASK_TYPES = new Set([
|
|
14
|
-
"sw", "infra", "doc", "add-tests", "refactor",
|
|
15
|
-
"audit", "analysis", "no-code", "spike", "research",
|
|
16
|
-
]);
|
|
17
|
-
|
|
18
|
-
export const DEFAULT_POLICIES = {
|
|
19
|
-
sw: { tdd: true, sonar: true, reviewer: true, testsRequired: true },
|
|
20
|
-
infra: { tdd: false, sonar: false, reviewer: false, testsRequired: false },
|
|
21
|
-
doc: { tdd: false, sonar: false, reviewer: true, testsRequired: false },
|
|
22
|
-
"add-tests": { tdd: false, sonar: true, reviewer: true, testsRequired: true },
|
|
23
|
-
refactor: { tdd: true, sonar: true, reviewer: true, testsRequired: false },
|
|
24
|
-
audit: { tdd: false, sonar: false, reviewer: false, testsRequired: false, coderRequired: false },
|
|
25
|
-
analysis: { tdd: false, sonar: false, reviewer: false, testsRequired: false, coderRequired: false },
|
|
26
|
-
"no-code": { tdd: false, sonar: false, reviewer: true, testsRequired: false, coderRequired: true },
|
|
27
|
-
spike: { tdd: false, sonar: false, reviewer: true, testsRequired: false, coderRequired: true },
|
|
28
|
-
research: { tdd: false, sonar: false, reviewer: true, testsRequired: false, coderRequired: true },
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
// KJC-TSK-0400: si el title arranca con [SPIKE] / [DOC] / [RESEARCH] /
|
|
32
|
-
// [NOCODE], inferimos el task_type del prefijo. Pensado para casos donde
|
|
33
|
-
// el planner emite task_type='sw' por defecto pero el title declara
|
|
34
|
-
// claramente que la HU no produce código. Devuelve null si no hay match.
|
|
35
|
-
const TITLE_PREFIX_TO_TYPE = {
|
|
36
|
-
SPIKE: "spike",
|
|
37
|
-
RESEARCH: "research",
|
|
38
|
-
DOC: "doc",
|
|
39
|
-
NOCODE: "no-code",
|
|
40
|
-
"NO-CODE": "no-code",
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
export function inferTaskTypeFromTitle(title) {
|
|
44
|
-
if (typeof title !== "string") return null;
|
|
45
|
-
const m = title.match(/^\s*\[([A-Z][A-Z-]+)\]/);
|
|
46
|
-
if (!m) return null;
|
|
47
|
-
return TITLE_PREFIX_TO_TYPE[m[1].toUpperCase()] || null;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// KJC-TSK-0400: dado un HU del plan, devuelve el task_type efectivo:
|
|
51
|
-
// explícito en story.task_type si es válido, si no inferido del title.
|
|
52
|
-
// Fallback 'sw' (conservador, mantiene gates activos cuando hay duda).
|
|
53
|
-
export function effectiveTaskType(story) {
|
|
54
|
-
if (!story || typeof story !== "object") return "sw";
|
|
55
|
-
if (VALID_TASK_TYPES.has(story.task_type)) return story.task_type;
|
|
56
|
-
return inferTaskTypeFromTitle(story.title) || "sw";
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const FALLBACK_TYPE = "sw";
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Resolve pipeline policies for a given taskType.
|
|
63
|
-
* Unknown / null / undefined taskType falls back to "sw" (conservative).
|
|
64
|
-
* configOverrides optionally merges over defaults per taskType.
|
|
65
|
-
*/
|
|
66
|
-
export function resolvePolicies(taskType, configOverrides) {
|
|
67
|
-
const resolvedType = VALID_TASK_TYPES.has(taskType) ? taskType : FALLBACK_TYPE;
|
|
68
|
-
const base = { ...DEFAULT_POLICIES[resolvedType] };
|
|
69
|
-
const overrides = configOverrides?.[resolvedType];
|
|
70
|
-
if (overrides && typeof overrides === "object") {
|
|
71
|
-
Object.assign(base, overrides);
|
|
72
|
-
}
|
|
73
|
-
return base;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Resolve policies for a taskType and return a flat object with the resolved
|
|
78
|
-
* taskType plus all policy flags. This is the main entry point for the
|
|
79
|
-
* orchestrator to determine which pipeline stages to enable/disable.
|
|
80
|
-
*/
|
|
81
|
-
export function applyPolicies({ taskType, policies } = {}) {
|
|
82
|
-
const resolvedType = VALID_TASK_TYPES.has(taskType) ? taskType : FALLBACK_TYPE;
|
|
83
|
-
const resolved = resolvePolicies(taskType, policies);
|
|
84
|
-
return { taskType: resolvedType, ...resolved };
|
|
85
|
-
}
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
// KJC-TSK-0583 — Inbound secret redaction for the review boundary.
|
|
2
|
-
//
|
|
3
|
-
// The outbound boundary (output-guard.js) already blocks committing secrets.
|
|
4
|
-
// This closes the *inbound* gap: a hardcoded credential in the working tree
|
|
5
|
-
// would otherwise reach the (possibly cloud) reviewer model verbatim inside the
|
|
6
|
-
// diff. `redactSecrets` masks each credential before the model sees it, reusing
|
|
7
|
-
// the SAME catalog as output-guard — no new patterns, no AI cost, deterministic.
|
|
8
|
-
import { CREDENTIAL_PATTERNS } from "./output-guard.js";
|
|
9
|
-
|
|
10
|
-
// Families whose match begins with a fixed, identifiable literal prefix. The
|
|
11
|
-
// placeholder keeps that prefix so the reviewer can still tell WHAT kind of
|
|
12
|
-
// secret was redacted (and say "move it to .env") without seeing the value.
|
|
13
|
-
const STABLE_PREFIX_BY_ID = {
|
|
14
|
-
"aws-key": "AKIA",
|
|
15
|
-
"npm-token": "npm_",
|
|
16
|
-
"openai-key": "sk-",
|
|
17
|
-
"anthropic-key": "sk-ant-",
|
|
18
|
-
"stripe-key": "sk_live_",
|
|
19
|
-
"stripe-test": "sk_test_",
|
|
20
|
-
"google-api-key": "AIza",
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
// Families with a dynamic prefix: keep the real match up to and including the
|
|
24
|
-
// first separator (ghp_/gho_/…, xoxb-/xoxp-/…), then mask the rest.
|
|
25
|
-
const DYNAMIC_SEPARATOR_BY_ID = {
|
|
26
|
-
"github-token": "_",
|
|
27
|
-
"slack-token": "-",
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
const GENERIC = "***REDACTED-SECRET***";
|
|
31
|
-
const SUFFIX = "***REDACTED***";
|
|
32
|
-
|
|
33
|
-
function placeholderFor(id, match) {
|
|
34
|
-
const stable = STABLE_PREFIX_BY_ID[id];
|
|
35
|
-
if (stable) return `${stable}${SUFFIX}`;
|
|
36
|
-
const sep = DYNAMIC_SEPARATOR_BY_ID[id];
|
|
37
|
-
if (sep) {
|
|
38
|
-
const idx = match.indexOf(sep);
|
|
39
|
-
return idx >= 0 ? `${match.slice(0, idx + 1)}${SUFFIX}` : GENERIC;
|
|
40
|
-
}
|
|
41
|
-
return GENERIC;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// Apply the most specific prefixes first so `sk-ant-` wins over `sk-`; families
|
|
45
|
-
// without a stable prefix keep their catalog order (stable sort) and run last.
|
|
46
|
-
function orderedPatterns() {
|
|
47
|
-
return [...CREDENTIAL_PATTERNS].sort(
|
|
48
|
-
(a, b) => (STABLE_PREFIX_BY_ID[b.id]?.length ?? 0) - (STABLE_PREFIX_BY_ID[a.id]?.length ?? 0)
|
|
49
|
-
);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Mask every credential in `text`, preserving line structure. Pure and
|
|
54
|
-
* deterministic: clean text is returned untouched (no-op, no cost).
|
|
55
|
-
* @param {string} text
|
|
56
|
-
* @returns {string}
|
|
57
|
-
*/
|
|
58
|
-
export function redactSecrets(text) {
|
|
59
|
-
if (typeof text !== "string" || text.length === 0) return text;
|
|
60
|
-
let out = text;
|
|
61
|
-
for (const { id, pattern } of orderedPatterns()) {
|
|
62
|
-
const flags = pattern.flags.includes("g") ? pattern.flags : `${pattern.flags}g`;
|
|
63
|
-
out = out.replace(new RegExp(pattern.source, flags), (match) =>
|
|
64
|
-
// Idempotent: a broad pattern (generic-secret, hardcoded-key-assignment)
|
|
65
|
-
// can span an already-masked value; leave the more specific placeholder
|
|
66
|
-
// in place instead of clobbering it with the generic one.
|
|
67
|
-
match.includes("REDACTED") ? match : placeholderFor(id, match)
|
|
68
|
-
);
|
|
69
|
-
}
|
|
70
|
-
return out;
|
|
71
|
-
}
|
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* HU Acceptance Test Runner.
|
|
3
|
-
* Executes acceptance_tests commands for an HU and returns structured results.
|
|
4
|
-
* Brain uses this to determine if an HU is done (all pass) or needs fixing (with diagnostics).
|
|
5
|
-
*/
|
|
6
|
-
import { runCommand } from "../utils/process.js";
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Run a single acceptance test command.
|
|
10
|
-
* @param {string} cmd - Shell command to execute
|
|
11
|
-
* @param {string} cwd - Working directory
|
|
12
|
-
* @param {number} [timeoutMs=30000] - Timeout per test
|
|
13
|
-
* @returns {Promise<{cmd: string, passed: boolean, output: string, exitCode: number}>}
|
|
14
|
-
*/
|
|
15
|
-
async function runSingleTest(cmd, cwd, timeoutMs = 30000, env = null) {
|
|
16
|
-
try {
|
|
17
|
-
const result = await runCommand("bash", ["-c", cmd], {
|
|
18
|
-
timeout: timeoutMs,
|
|
19
|
-
cwd,
|
|
20
|
-
// PAR-H (KJC-TSK-0631): lane env (KJ_LANE_SLOT / KJ_PORT_OFFSET) so
|
|
21
|
-
// tests that start services can offset their ports. execa merges
|
|
22
|
-
// this on top of process.env.
|
|
23
|
-
...(env ? { env } : {})
|
|
24
|
-
});
|
|
25
|
-
const output = (result.stdout || "") + (result.stderr || "");
|
|
26
|
-
return {
|
|
27
|
-
cmd,
|
|
28
|
-
passed: result.exitCode === 0,
|
|
29
|
-
output: output.slice(-500), // last 500 chars for diagnostics
|
|
30
|
-
exitCode: result.exitCode
|
|
31
|
-
};
|
|
32
|
-
} catch (err) {
|
|
33
|
-
return {
|
|
34
|
-
cmd,
|
|
35
|
-
passed: false,
|
|
36
|
-
output: err.message?.slice(-500) || "Command timed out or crashed",
|
|
37
|
-
exitCode: -1
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Run all acceptance tests for an HU.
|
|
44
|
-
*
|
|
45
|
-
* Accepts two shapes:
|
|
46
|
-
* - Legacy: plain string shell command.
|
|
47
|
-
* - v2.7.5: { type: "shell" | "gherkin", content, file? }
|
|
48
|
-
*
|
|
49
|
-
* Shell entries execute immediately (exit code 0 = pass). Gherkin entries
|
|
50
|
-
* cannot be executed directly — that's Phase 3 of tests-first where the
|
|
51
|
-
* tester role translates them into real code tests. Until then, we report
|
|
52
|
-
* them as "pending" and skip rather than failing the whole gate.
|
|
53
|
-
*
|
|
54
|
-
* @param {Array<string|object>} tests - Array of shell commands OR structured entries
|
|
55
|
-
* @param {string} cwd - Working directory
|
|
56
|
-
* @returns {Promise<{allPassed: boolean, results: object[], summary: string, diagnostics: string|null, pending: number}>}
|
|
57
|
-
*/
|
|
58
|
-
export async function runAcceptanceTests(tests, cwd, { env = null } = {}) {
|
|
59
|
-
if (!tests || tests.length === 0) {
|
|
60
|
-
return { allPassed: false, results: [], summary: "No acceptance tests defined", diagnostics: null, pending: 0 };
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const results = [];
|
|
64
|
-
let pending = 0;
|
|
65
|
-
for (const entry of tests) {
|
|
66
|
-
let type = "shell";
|
|
67
|
-
let cmd;
|
|
68
|
-
if (typeof entry === "string") {
|
|
69
|
-
cmd = entry;
|
|
70
|
-
} else if (entry && typeof entry === "object" && typeof entry.content === "string") {
|
|
71
|
-
type = entry.type === "gherkin" ? "gherkin" : "shell";
|
|
72
|
-
cmd = entry.content;
|
|
73
|
-
} else {
|
|
74
|
-
results.push({ cmd: JSON.stringify(entry), passed: false, output: "Malformed acceptance_test entry", exitCode: -2, type: "invalid" });
|
|
75
|
-
continue;
|
|
76
|
-
}
|
|
77
|
-
if (type === "gherkin") {
|
|
78
|
-
// Gherkin entries need a translator (Phase 3). Mark them pending
|
|
79
|
-
// so the coder/tester sees they haven't been validated yet —
|
|
80
|
-
// better than silently passing (would lie) or hard-failing
|
|
81
|
-
// (would block the whole pipeline).
|
|
82
|
-
pending += 1;
|
|
83
|
-
results.push({
|
|
84
|
-
cmd,
|
|
85
|
-
passed: false,
|
|
86
|
-
output: "Gherkin test not yet executable (awaits tester translation — Phase 3)",
|
|
87
|
-
exitCode: 0,
|
|
88
|
-
type: "gherkin",
|
|
89
|
-
pending: true,
|
|
90
|
-
});
|
|
91
|
-
continue;
|
|
92
|
-
}
|
|
93
|
-
const result = await runSingleTest(cmd, cwd, 30000, env);
|
|
94
|
-
results.push({ ...result, type: "shell" });
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
const executedResults = results.filter((r) => !r.pending);
|
|
98
|
-
const passed = executedResults.filter((r) => r.passed);
|
|
99
|
-
const failed = executedResults.filter((r) => !r.passed);
|
|
100
|
-
const allPassed = failed.length === 0;
|
|
101
|
-
|
|
102
|
-
const shellSummary = `${passed.length}/${executedResults.length} shell tests passed`;
|
|
103
|
-
const summary = pending > 0
|
|
104
|
-
? `${shellSummary}, ${pending} gherkin test(s) pending translation`
|
|
105
|
-
: shellSummary;
|
|
106
|
-
|
|
107
|
-
let diagnostics = null;
|
|
108
|
-
if (!allPassed) {
|
|
109
|
-
diagnostics = failed.map((f) =>
|
|
110
|
-
`FAIL: ${f.cmd}\n exit=${f.exitCode}\n output: ${f.output.trim().split("\n").slice(-5).join("\n ")}`
|
|
111
|
-
).join("\n\n");
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
return { allPassed, results, summary, diagnostics, pending };
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Build a concrete diagnostic prompt for Brain to send to the coder.
|
|
119
|
-
* Reads the failed test outputs and produces actionable instructions.
|
|
120
|
-
* @param {object[]} failedResults - Array of failed test results
|
|
121
|
-
* @returns {string} Prompt for the coder with concrete fix instructions
|
|
122
|
-
*/
|
|
123
|
-
export function buildDiagnosticPrompt(failedResults) {
|
|
124
|
-
if (!failedResults || failedResults.length === 0) return "";
|
|
125
|
-
const lines = ["The following acceptance tests FAILED. Fix each one:", ""];
|
|
126
|
-
for (const f of failedResults) {
|
|
127
|
-
lines.push(`❌ Command: ${f.cmd}`);
|
|
128
|
-
lines.push(` Exit code: ${f.exitCode}`);
|
|
129
|
-
const lastLines = f.output.trim().split("\n").slice(-8);
|
|
130
|
-
lines.push(` Last output:`);
|
|
131
|
-
for (const l of lastLines) {
|
|
132
|
-
lines.push(` ${l}`);
|
|
133
|
-
}
|
|
134
|
-
lines.push("");
|
|
135
|
-
}
|
|
136
|
-
lines.push("Fix ALL failing tests. Run each command yourself to verify before finishing.");
|
|
137
|
-
return lines.join("\n");
|
|
138
|
-
}
|