prjct-cli 1.22.0 → 1.23.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/CHANGELOG.md +147 -0
- package/bin/prjct +30 -13
- package/dist/bin/prjct.mjs +917 -35845
- package/dist/bin/prjct.mjs.map +7 -0
- package/dist/cli/linear.mjs +16 -0
- package/dist/cli/linear.mjs.map +7 -0
- package/dist/templates.json +1 -0
- package/package.json +4 -5
- package/bin/prjct.ts +0 -342
- package/core/__tests__/agentic/analysis-injection.test.ts +0 -377
- package/core/__tests__/agentic/cache-eviction.test.ts +0 -294
- package/core/__tests__/agentic/command-context.test.ts +0 -281
- package/core/__tests__/agentic/command-executor.test.ts +0 -659
- package/core/__tests__/agentic/domain-classifier.test.ts +0 -330
- package/core/__tests__/agentic/injection-validator.test.ts +0 -255
- package/core/__tests__/agentic/memory-system.test.ts +0 -281
- package/core/__tests__/agentic/plan-mode.test.ts +0 -386
- package/core/__tests__/agentic/prompt-assembly.test.ts +0 -298
- package/core/__tests__/agentic/prompt-builder.test.ts +0 -243
- package/core/__tests__/agentic/response-validator.test.ts +0 -263
- package/core/__tests__/agentic/semantic-matching.test.ts +0 -131
- package/core/__tests__/agentic/smart-context.test.ts +0 -372
- package/core/__tests__/agentic/tech-normalizer.test.ts +0 -136
- package/core/__tests__/agentic/token-budget.test.ts +0 -294
- package/core/__tests__/ai-tools/formatters.test.ts +0 -476
- package/core/__tests__/domain/bm25.test.ts +0 -225
- package/core/__tests__/domain/change-propagator.test.ts +0 -100
- package/core/__tests__/domain/fibonacci.test.ts +0 -113
- package/core/__tests__/domain/file-hasher.test.ts +0 -146
- package/core/__tests__/domain/file-ranker.test.ts +0 -169
- package/core/__tests__/domain/git-cochange.test.ts +0 -121
- package/core/__tests__/domain/import-graph.test.ts +0 -156
- package/core/__tests__/domain/velocity.test.ts +0 -623
- package/core/__tests__/infrastructure/performance-tracker.test.ts +0 -328
- package/core/__tests__/schemas/model.test.ts +0 -272
- package/core/__tests__/services/dependency-validator.test.ts +0 -175
- package/core/__tests__/services/hierarchical-agent-resolver.test.ts +0 -359
- package/core/__tests__/services/nested-context-resolver.test.ts +0 -443
- package/core/__tests__/services/project-index.test.ts +0 -355
- package/core/__tests__/services/staleness-checker.test.ts +0 -204
- package/core/__tests__/storage/analysis-storage.test.ts +0 -641
- package/core/__tests__/storage/archive-storage.test.ts +0 -455
- package/core/__tests__/storage/safe-reader.test.ts +0 -262
- package/core/__tests__/storage/sqlite-migration.test.ts +0 -1016
- package/core/__tests__/storage/state-storage-feedback.test.ts +0 -463
- package/core/__tests__/storage/state-storage-history.test.ts +0 -469
- package/core/__tests__/storage/storage-manager.test.ts +0 -383
- package/core/__tests__/storage/subtask-handoff.test.ts +0 -237
- package/core/__tests__/types/fs.test.ts +0 -125
- package/core/__tests__/utils/date-helper.test.ts +0 -449
- package/core/__tests__/utils/output.test.ts +0 -278
- package/core/__tests__/utils/preserve-sections.test.ts +0 -216
- package/core/__tests__/utils/project-commands.test.ts +0 -71
- package/core/__tests__/utils/retry.test.ts +0 -381
- package/core/__tests__/workflow/state-machine.test.ts +0 -216
- package/core/agentic/agent-router.ts +0 -150
- package/core/agentic/anti-hallucination.ts +0 -141
- package/core/agentic/chain-of-thought.ts +0 -234
- package/core/agentic/command-classifier.ts +0 -141
- package/core/agentic/command-context.ts +0 -168
- package/core/agentic/command-executor.ts +0 -471
- package/core/agentic/context-builder.ts +0 -285
- package/core/agentic/domain-classifier.ts +0 -525
- package/core/agentic/environment-block.ts +0 -102
- package/core/agentic/ground-truth.ts +0 -706
- package/core/agentic/index.ts +0 -193
- package/core/agentic/injection-validator.ts +0 -208
- package/core/agentic/loop-detector.ts +0 -451
- package/core/agentic/memory-system.ts +0 -1547
- package/core/agentic/orchestrator-executor.ts +0 -579
- package/core/agentic/plan-mode.ts +0 -525
- package/core/agentic/prompt-builder.ts +0 -1069
- package/core/agentic/response-validator.ts +0 -98
- package/core/agentic/services.ts +0 -167
- package/core/agentic/skill-loader.ts +0 -106
- package/core/agentic/smart-context.ts +0 -393
- package/core/agentic/tech-normalizer.ts +0 -167
- package/core/agentic/template-executor.ts +0 -272
- package/core/agentic/template-loader.ts +0 -109
- package/core/agentic/token-budget.ts +0 -226
- package/core/agentic/tool-registry.ts +0 -146
- package/core/agents/index.ts +0 -28
- package/core/agents/performance.ts +0 -429
- package/core/ai-tools/formatters.ts +0 -341
- package/core/ai-tools/generator.ts +0 -144
- package/core/ai-tools/index.ts +0 -15
- package/core/ai-tools/registry.ts +0 -201
- package/core/bus/bus.ts +0 -314
- package/core/bus/index.ts +0 -8
- package/core/cli/linear.ts +0 -500
- package/core/cli/lint-meta-commentary.ts +0 -177
- package/core/cli/start.ts +0 -386
- package/core/commands/analysis.ts +0 -1274
- package/core/commands/analytics.ts +0 -342
- package/core/commands/base.ts +0 -118
- package/core/commands/cleanup.ts +0 -157
- package/core/commands/command-data.ts +0 -463
- package/core/commands/commands.ts +0 -306
- package/core/commands/context.ts +0 -238
- package/core/commands/design.ts +0 -77
- package/core/commands/index.ts +0 -19
- package/core/commands/maintenance.ts +0 -77
- package/core/commands/performance.ts +0 -114
- package/core/commands/planning.ts +0 -662
- package/core/commands/register.ts +0 -127
- package/core/commands/registry.ts +0 -444
- package/core/commands/setup.ts +0 -280
- package/core/commands/shipping.ts +0 -267
- package/core/commands/snapshots.ts +0 -297
- package/core/commands/uninstall.ts +0 -542
- package/core/commands/velocity.ts +0 -149
- package/core/commands/workflow.ts +0 -505
- package/core/config/command-context.config.json +0 -66
- package/core/constants/index.ts +0 -379
- package/core/context/generator.ts +0 -368
- package/core/context-tools/files-tool.ts +0 -577
- package/core/context-tools/imports-tool.ts +0 -400
- package/core/context-tools/index.ts +0 -434
- package/core/context-tools/recent-tool.ts +0 -301
- package/core/context-tools/signatures-tool.ts +0 -495
- package/core/context-tools/summary-tool.ts +0 -301
- package/core/context-tools/token-counter.ts +0 -273
- package/core/context-tools/types.ts +0 -253
- package/core/domain/agent-generator.ts +0 -186
- package/core/domain/agent-loader.ts +0 -419
- package/core/domain/analyzer.ts +0 -387
- package/core/domain/architecture-generator.ts +0 -108
- package/core/domain/bm25.ts +0 -525
- package/core/domain/change-propagator.ts +0 -162
- package/core/domain/context-estimator.ts +0 -175
- package/core/domain/fibonacci.ts +0 -128
- package/core/domain/file-hasher.ts +0 -296
- package/core/domain/file-ranker.ts +0 -151
- package/core/domain/git-cochange.ts +0 -250
- package/core/domain/import-graph.ts +0 -315
- package/core/domain/snapshot-manager.ts +0 -415
- package/core/domain/task-stack.ts +0 -578
- package/core/domain/velocity.ts +0 -470
- package/core/errors.ts +0 -335
- package/core/events/events.ts +0 -85
- package/core/events/index.ts +0 -8
- package/core/index.ts +0 -481
- package/core/infrastructure/agent-detector.ts +0 -135
- package/core/infrastructure/ai-provider.ts +0 -578
- package/core/infrastructure/author-detector.ts +0 -133
- package/core/infrastructure/capability-installer.ts +0 -76
- package/core/infrastructure/claude-agent.ts +0 -297
- package/core/infrastructure/command-installer.ts +0 -752
- package/core/infrastructure/config-manager.ts +0 -364
- package/core/infrastructure/editors-config.ts +0 -172
- package/core/infrastructure/path-manager.ts +0 -571
- package/core/infrastructure/performance-tracker.ts +0 -326
- package/core/infrastructure/permission-manager.ts +0 -289
- package/core/infrastructure/setup.ts +0 -1061
- package/core/infrastructure/update-checker.ts +0 -246
- package/core/integrations/issue-tracker/enricher.ts +0 -271
- package/core/integrations/issue-tracker/index.ts +0 -8
- package/core/integrations/issue-tracker/manager.ts +0 -286
- package/core/integrations/issue-tracker/types.ts +0 -310
- package/core/integrations/jira/cache.ts +0 -57
- package/core/integrations/jira/client.ts +0 -688
- package/core/integrations/jira/index.ts +0 -23
- package/core/integrations/jira/service.ts +0 -244
- package/core/integrations/linear/cache.ts +0 -68
- package/core/integrations/linear/client.ts +0 -436
- package/core/integrations/linear/index.ts +0 -20
- package/core/integrations/linear/service.ts +0 -260
- package/core/integrations/linear/sync.ts +0 -314
- package/core/outcomes/analyzer.ts +0 -286
- package/core/outcomes/index.ts +0 -34
- package/core/outcomes/recorder.ts +0 -195
- package/core/plugin/builtin/webhook.ts +0 -148
- package/core/plugin/hooks.ts +0 -315
- package/core/plugin/index.ts +0 -50
- package/core/plugin/loader.ts +0 -354
- package/core/plugin/registry.ts +0 -326
- package/core/schemas/agents.ts +0 -27
- package/core/schemas/analysis.ts +0 -530
- package/core/schemas/classification.ts +0 -91
- package/core/schemas/command-context.ts +0 -29
- package/core/schemas/enriched-task.ts +0 -291
- package/core/schemas/ideas.ts +0 -114
- package/core/schemas/index.ts +0 -53
- package/core/schemas/issues.ts +0 -159
- package/core/schemas/llm-output.ts +0 -170
- package/core/schemas/metrics.ts +0 -143
- package/core/schemas/model.ts +0 -153
- package/core/schemas/outcomes.ts +0 -487
- package/core/schemas/performance.ts +0 -128
- package/core/schemas/permissions.ts +0 -180
- package/core/schemas/prd.ts +0 -450
- package/core/schemas/project.ts +0 -57
- package/core/schemas/roadmap.ts +0 -322
- package/core/schemas/schemas.ts +0 -38
- package/core/schemas/shipped.ts +0 -109
- package/core/schemas/state.ts +0 -284
- package/core/schemas/velocity.ts +0 -103
- package/core/server/index.ts +0 -21
- package/core/server/routes-extended.ts +0 -566
- package/core/server/routes.ts +0 -176
- package/core/server/server.ts +0 -149
- package/core/server/sse.ts +0 -192
- package/core/services/agent-generator.ts +0 -385
- package/core/services/agent-service.ts +0 -168
- package/core/services/breakdown-service.ts +0 -124
- package/core/services/context-generator.ts +0 -445
- package/core/services/context-selector.ts +0 -429
- package/core/services/dependency-validator.ts +0 -318
- package/core/services/diff-generator.ts +0 -313
- package/core/services/doctor-service.ts +0 -423
- package/core/services/file-categorizer.ts +0 -448
- package/core/services/file-scorer.ts +0 -270
- package/core/services/git-analyzer.ts +0 -293
- package/core/services/hierarchical-agent-resolver.ts +0 -236
- package/core/services/hooks-service.ts +0 -685
- package/core/services/index.ts +0 -46
- package/core/services/local-state-generator.ts +0 -158
- package/core/services/memory-service.ts +0 -181
- package/core/services/nested-context-resolver.ts +0 -842
- package/core/services/project-index.ts +0 -911
- package/core/services/project-service.ts +0 -155
- package/core/services/session-tracker.ts +0 -287
- package/core/services/skill-installer.ts +0 -447
- package/core/services/skill-lock.ts +0 -132
- package/core/services/skill-service.ts +0 -306
- package/core/services/stack-detector.ts +0 -229
- package/core/services/staleness-checker.ts +0 -327
- package/core/services/sync-service.ts +0 -1515
- package/core/services/sync-verifier.ts +0 -253
- package/core/services/watch-service.ts +0 -312
- package/core/session/compaction.ts +0 -248
- package/core/session/index.ts +0 -35
- package/core/session/log-migration.ts +0 -88
- package/core/session/metrics.ts +0 -323
- package/core/session/session-log-manager.ts +0 -307
- package/core/session/task-session-manager.ts +0 -404
- package/core/session/utils.ts +0 -51
- package/core/storage/analysis-storage.ts +0 -373
- package/core/storage/archive-storage.ts +0 -205
- package/core/storage/database.ts +0 -575
- package/core/storage/ideas-storage.ts +0 -298
- package/core/storage/index-storage.ts +0 -523
- package/core/storage/index.ts +0 -79
- package/core/storage/metrics-storage.ts +0 -321
- package/core/storage/migrate-json.ts +0 -720
- package/core/storage/queue-storage.ts +0 -336
- package/core/storage/safe-reader.ts +0 -105
- package/core/storage/shipped-storage.ts +0 -253
- package/core/storage/state-storage.ts +0 -1035
- package/core/storage/storage-manager.ts +0 -205
- package/core/storage/storage.ts +0 -177
- package/core/storage/velocity-storage.ts +0 -149
- package/core/sync/auth-config.ts +0 -138
- package/core/sync/index.ts +0 -31
- package/core/sync/oauth-handler.ts +0 -143
- package/core/sync/sync-client.ts +0 -251
- package/core/sync/sync-manager.ts +0 -327
- package/core/tsconfig.json +0 -22
- package/core/types/agentic.ts +0 -760
- package/core/types/agents.ts +0 -150
- package/core/types/bus.ts +0 -193
- package/core/types/citations.ts +0 -22
- package/core/types/commands.ts +0 -399
- package/core/types/config.ts +0 -92
- package/core/types/core.ts +0 -96
- package/core/types/diff.ts +0 -41
- package/core/types/domain.ts +0 -71
- package/core/types/errors.ts +0 -111
- package/core/types/events.ts +0 -42
- package/core/types/fs.ts +0 -72
- package/core/types/index.ts +0 -510
- package/core/types/infrastructure.ts +0 -210
- package/core/types/integrations.ts +0 -31
- package/core/types/jira.ts +0 -51
- package/core/types/logger.ts +0 -17
- package/core/types/memory.ts +0 -313
- package/core/types/outcomes.ts +0 -190
- package/core/types/output.ts +0 -47
- package/core/types/plugin.ts +0 -25
- package/core/types/project-sync.ts +0 -129
- package/core/types/provider.ts +0 -163
- package/core/types/server.ts +0 -71
- package/core/types/services.ts +0 -84
- package/core/types/session.ts +0 -135
- package/core/types/stack.ts +0 -19
- package/core/types/storage.ts +0 -318
- package/core/types/sync-verifier.ts +0 -33
- package/core/types/sync.ts +0 -121
- package/core/types/task.ts +0 -72
- package/core/types/template.ts +0 -24
- package/core/types/utils.ts +0 -92
- package/core/types/workflow.ts +0 -23
- package/core/utils/agent-stream.ts +0 -140
- package/core/utils/animations.ts +0 -251
- package/core/utils/branding.ts +0 -88
- package/core/utils/cache.ts +0 -187
- package/core/utils/citations.ts +0 -39
- package/core/utils/collection-filters.ts +0 -209
- package/core/utils/date-helper.ts +0 -176
- package/core/utils/error-messages.ts +0 -38
- package/core/utils/file-helper.ts +0 -277
- package/core/utils/fs-helpers.ts +0 -14
- package/core/utils/help.ts +0 -314
- package/core/utils/jsonl-helper.ts +0 -290
- package/core/utils/keychain.ts +0 -127
- package/core/utils/logger.ts +0 -77
- package/core/utils/markdown-builder.ts +0 -280
- package/core/utils/next-steps.ts +0 -95
- package/core/utils/output.ts +0 -403
- package/core/utils/preserve-sections.ts +0 -218
- package/core/utils/project-commands.ts +0 -126
- package/core/utils/project-credentials.ts +0 -143
- package/core/utils/provider-cache.ts +0 -49
- package/core/utils/retry.ts +0 -318
- package/core/utils/runtime.ts +0 -108
- package/core/utils/session-helper.ts +0 -278
- package/core/utils/subtask-table.ts +0 -227
- package/core/utils/version.ts +0 -128
- package/core/wizard/index.ts +0 -13
- package/core/wizard/onboarding.ts +0 -633
- package/core/workflow/index.ts +0 -7
- package/core/workflow/state-machine.ts +0 -198
- package/core/workflow/workflow-preferences.ts +0 -294
- package/dist/core/infrastructure/command-installer.js +0 -1141
- package/dist/core/infrastructure/editors-config.js +0 -177
- package/dist/core/infrastructure/setup.js +0 -2244
- package/dist/core/utils/version.js +0 -141
- package/templates/agentic/agent-routing.md +0 -45
- package/templates/agentic/agents/uxui.md +0 -63
- package/templates/agentic/checklist-routing.md +0 -98
- package/templates/agentic/orchestrator.md +0 -68
- package/templates/agentic/task-fragmentation.md +0 -89
- package/templates/agents/AGENTS.md +0 -68
- package/templates/analysis/analyze.md +0 -84
- package/templates/analysis/patterns.md +0 -60
- package/templates/antigravity/SKILL.md +0 -39
- package/templates/architect/discovery.md +0 -67
- package/templates/architect/phases.md +0 -59
- package/templates/checklists/architecture.md +0 -28
- package/templates/checklists/code-quality.md +0 -28
- package/templates/checklists/data.md +0 -33
- package/templates/checklists/documentation.md +0 -33
- package/templates/checklists/infrastructure.md +0 -33
- package/templates/checklists/performance.md +0 -33
- package/templates/checklists/security.md +0 -33
- package/templates/checklists/testing.md +0 -33
- package/templates/checklists/ux-ui.md +0 -37
- package/templates/commands/analyze.md +0 -56
- package/templates/commands/auth.md +0 -234
- package/templates/commands/bug.md +0 -163
- package/templates/commands/cleanup.md +0 -19
- package/templates/commands/dash.md +0 -99
- package/templates/commands/design.md +0 -15
- package/templates/commands/done.md +0 -291
- package/templates/commands/enrich.md +0 -174
- package/templates/commands/git.md +0 -295
- package/templates/commands/history.md +0 -389
- package/templates/commands/idea.md +0 -88
- package/templates/commands/impact.md +0 -864
- package/templates/commands/init.md +0 -54
- package/templates/commands/jira.md +0 -278
- package/templates/commands/linear.md +0 -288
- package/templates/commands/merge.md +0 -206
- package/templates/commands/next.md +0 -80
- package/templates/commands/p.md +0 -67
- package/templates/commands/p.toml +0 -37
- package/templates/commands/pause.md +0 -136
- package/templates/commands/plan.md +0 -696
- package/templates/commands/prd.md +0 -356
- package/templates/commands/resume.md +0 -171
- package/templates/commands/review.md +0 -276
- package/templates/commands/serve.md +0 -118
- package/templates/commands/setup.md +0 -91
- package/templates/commands/ship.md +0 -475
- package/templates/commands/skill.md +0 -259
- package/templates/commands/spec.md +0 -218
- package/templates/commands/status.md +0 -207
- package/templates/commands/sync.md +0 -104
- package/templates/commands/task.md +0 -312
- package/templates/commands/test.md +0 -93
- package/templates/commands/update.md +0 -63
- package/templates/commands/verify.md +0 -204
- package/templates/commands/workflow.md +0 -150
- package/templates/config/skill-mappings.json +0 -82
- package/templates/context/dashboard.md +0 -256
- package/templates/context/roadmap.md +0 -221
- package/templates/cursor/commands/bug.md +0 -8
- package/templates/cursor/commands/done.md +0 -4
- package/templates/cursor/commands/pause.md +0 -6
- package/templates/cursor/commands/resume.md +0 -4
- package/templates/cursor/commands/ship.md +0 -8
- package/templates/cursor/commands/sync.md +0 -4
- package/templates/cursor/commands/task.md +0 -8
- package/templates/cursor/p.md +0 -29
- package/templates/cursor/router.mdc +0 -28
- package/templates/design/api.md +0 -95
- package/templates/design/architecture.md +0 -77
- package/templates/design/component.md +0 -89
- package/templates/design/database.md +0 -78
- package/templates/design/flow.md +0 -94
- package/templates/global/ANTIGRAVITY.md +0 -254
- package/templates/global/CLAUDE.md +0 -497
- package/templates/global/CURSOR.mdc +0 -266
- package/templates/global/GEMINI.md +0 -293
- package/templates/global/STORAGE-SPEC.md +0 -391
- package/templates/global/WINDSURF.md +0 -266
- package/templates/global/modules/CLAUDE-commands.md +0 -70
- package/templates/global/modules/CLAUDE-core.md +0 -105
- package/templates/global/modules/CLAUDE-git.md +0 -50
- package/templates/global/modules/CLAUDE-intelligence.md +0 -92
- package/templates/global/modules/CLAUDE-storage.md +0 -50
- package/templates/global/modules/module-config.json +0 -36
- package/templates/mcp-config.json +0 -19
- package/templates/permissions/default.jsonc +0 -60
- package/templates/permissions/permissive.jsonc +0 -49
- package/templates/permissions/strict.jsonc +0 -58
- package/templates/planning-methodology.md +0 -195
- package/templates/skills/code-review.md +0 -47
- package/templates/skills/debug.md +0 -61
- package/templates/skills/refactor.md +0 -47
- package/templates/subagents/agent-base.md +0 -20
- package/templates/subagents/domain/backend.md +0 -109
- package/templates/subagents/domain/database.md +0 -121
- package/templates/subagents/domain/devops.md +0 -152
- package/templates/subagents/domain/frontend.md +0 -103
- package/templates/subagents/domain/testing.md +0 -169
- package/templates/subagents/pm-expert.md +0 -366
- package/templates/subagents/workflow/chief-architect.md +0 -657
- package/templates/subagents/workflow/prjct-planner.md +0 -159
- package/templates/subagents/workflow/prjct-shipper.md +0 -188
- package/templates/subagents/workflow/prjct-workflow.md +0 -98
- package/templates/tools/bash.txt +0 -22
- package/templates/tools/edit.txt +0 -18
- package/templates/tools/glob.txt +0 -19
- package/templates/tools/grep.txt +0 -21
- package/templates/tools/read.txt +0 -14
- package/templates/tools/task.txt +0 -20
- package/templates/tools/webfetch.txt +0 -16
- package/templates/tools/websearch.txt +0 -18
- package/templates/tools/write.txt +0 -17
- package/templates/windsurf/router.md +0 -28
- package/templates/windsurf/workflows/bug.md +0 -8
- package/templates/windsurf/workflows/done.md +0 -4
- package/templates/windsurf/workflows/pause.md +0 -4
- package/templates/windsurf/workflows/resume.md +0 -4
- package/templates/windsurf/workflows/ship.md +0 -8
- package/templates/windsurf/workflows/sync.md +0 -4
- package/templates/windsurf/workflows/task.md +0 -8
|
@@ -1,330 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Domain Classifier Tests
|
|
3
|
-
* PRJ-299: LLM-based domain classification with fallback chain
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { describe, expect, it } from 'bun:test'
|
|
7
|
-
import {
|
|
8
|
-
classifyWithHeuristic,
|
|
9
|
-
hashDescription,
|
|
10
|
-
type ProjectContext,
|
|
11
|
-
} from '../../agentic/domain-classifier'
|
|
12
|
-
|
|
13
|
-
// Default project context for testing (all domains available)
|
|
14
|
-
const fullContext: ProjectContext = {
|
|
15
|
-
domains: {
|
|
16
|
-
hasFrontend: true,
|
|
17
|
-
hasBackend: true,
|
|
18
|
-
hasDatabase: true,
|
|
19
|
-
hasTesting: true,
|
|
20
|
-
hasDocker: true,
|
|
21
|
-
},
|
|
22
|
-
agents: ['frontend', 'backend', 'database', 'testing', 'devops'],
|
|
23
|
-
stack: { language: 'TypeScript', framework: 'Hono' },
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// Backend-only project context
|
|
27
|
-
const backendOnlyContext: ProjectContext = {
|
|
28
|
-
domains: {
|
|
29
|
-
hasFrontend: false,
|
|
30
|
-
hasBackend: true,
|
|
31
|
-
hasDatabase: false,
|
|
32
|
-
hasTesting: false,
|
|
33
|
-
hasDocker: false,
|
|
34
|
-
},
|
|
35
|
-
agents: ['backend'],
|
|
36
|
-
stack: { language: 'TypeScript', framework: 'Hono' },
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
describe('DomainClassifier PRJ-299', () => {
|
|
40
|
-
describe('classifyWithHeuristic', () => {
|
|
41
|
-
// =================================================================
|
|
42
|
-
// Substring Trap Tests (the whole reason for PRJ-299)
|
|
43
|
-
// =================================================================
|
|
44
|
-
describe('substring traps (critical fixes)', () => {
|
|
45
|
-
it('should NOT match "author" to "auth" domain', () => {
|
|
46
|
-
const result = classifyWithHeuristic('Fix the author display on profile page', fullContext)
|
|
47
|
-
// "author" should NOT trigger backend (auth)
|
|
48
|
-
// "profile page" and "display" should trigger frontend
|
|
49
|
-
expect(result.primaryDomain).not.toBe('backend')
|
|
50
|
-
expect(result.primaryDomain).toBe('frontend')
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
it('should match standalone "auth" to backend', () => {
|
|
54
|
-
const result = classifyWithHeuristic(
|
|
55
|
-
'Fix the auth middleware for JWT validation',
|
|
56
|
-
fullContext
|
|
57
|
-
)
|
|
58
|
-
expect(result.primaryDomain).toBe('backend')
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
it('should NOT match "testament" to "test" domain', () => {
|
|
62
|
-
const result = classifyWithHeuristic(
|
|
63
|
-
'Update the testament of the old testament module',
|
|
64
|
-
fullContext
|
|
65
|
-
)
|
|
66
|
-
expect(result.primaryDomain).not.toBe('testing')
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
it('should NOT match "button" to "but" in other domains', () => {
|
|
70
|
-
const result = classifyWithHeuristic('Add a button component', fullContext)
|
|
71
|
-
expect(result.primaryDomain).toBe('frontend')
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
it('should NOT match "configure" to "config" in devops', () => {
|
|
75
|
-
// "configure" without a devops context word should not go to devops
|
|
76
|
-
const result = classifyWithHeuristic('Configure the React component props', fullContext)
|
|
77
|
-
expect(result.primaryDomain).toBe('frontend')
|
|
78
|
-
})
|
|
79
|
-
})
|
|
80
|
-
|
|
81
|
-
// =================================================================
|
|
82
|
-
// Correct Classification Tests
|
|
83
|
-
// =================================================================
|
|
84
|
-
describe('frontend detection', () => {
|
|
85
|
-
it('should detect "Build responsive dashboard" as frontend', () => {
|
|
86
|
-
const result = classifyWithHeuristic('Build responsive dashboard', fullContext)
|
|
87
|
-
expect(result.primaryDomain).toBe('frontend')
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
it('should detect React component tasks', () => {
|
|
91
|
-
const result = classifyWithHeuristic('Create a modal dialog for user settings', fullContext)
|
|
92
|
-
expect(result.primaryDomain).toBe('frontend')
|
|
93
|
-
})
|
|
94
|
-
|
|
95
|
-
it('should detect CSS/styling tasks', () => {
|
|
96
|
-
const result = classifyWithHeuristic(
|
|
97
|
-
'Fix the layout for mobile responsive view',
|
|
98
|
-
fullContext
|
|
99
|
-
)
|
|
100
|
-
expect(result.primaryDomain).toBe('frontend')
|
|
101
|
-
})
|
|
102
|
-
|
|
103
|
-
it('should detect page/navigation tasks', () => {
|
|
104
|
-
const result = classifyWithHeuristic(
|
|
105
|
-
'Add sidebar navigation with dropdown menus',
|
|
106
|
-
fullContext
|
|
107
|
-
)
|
|
108
|
-
expect(result.primaryDomain).toBe('frontend')
|
|
109
|
-
})
|
|
110
|
-
})
|
|
111
|
-
|
|
112
|
-
describe('backend detection', () => {
|
|
113
|
-
it('should detect API endpoint tasks', () => {
|
|
114
|
-
const result = classifyWithHeuristic(
|
|
115
|
-
'Create REST API endpoint for user management',
|
|
116
|
-
fullContext
|
|
117
|
-
)
|
|
118
|
-
expect(result.primaryDomain).toBe('backend')
|
|
119
|
-
})
|
|
120
|
-
|
|
121
|
-
it('should detect middleware tasks', () => {
|
|
122
|
-
const result = classifyWithHeuristic('Add rate limiting middleware', fullContext)
|
|
123
|
-
expect(result.primaryDomain).toBe('backend')
|
|
124
|
-
})
|
|
125
|
-
|
|
126
|
-
it('should detect authentication tasks', () => {
|
|
127
|
-
const result = classifyWithHeuristic('Implement JWT authentication flow', fullContext)
|
|
128
|
-
expect(result.primaryDomain).toBe('backend')
|
|
129
|
-
})
|
|
130
|
-
})
|
|
131
|
-
|
|
132
|
-
describe('database detection', () => {
|
|
133
|
-
it('should detect schema/migration tasks', () => {
|
|
134
|
-
const result = classifyWithHeuristic(
|
|
135
|
-
'Create database migration for users table',
|
|
136
|
-
fullContext
|
|
137
|
-
)
|
|
138
|
-
expect(result.primaryDomain).toBe('database')
|
|
139
|
-
})
|
|
140
|
-
|
|
141
|
-
it('should detect connection pooling as database (not schema)', () => {
|
|
142
|
-
const result = classifyWithHeuristic('Optimize database connection pooling', fullContext)
|
|
143
|
-
expect(result.primaryDomain).toBe('database')
|
|
144
|
-
})
|
|
145
|
-
|
|
146
|
-
it('should detect ORM/Prisma tasks', () => {
|
|
147
|
-
const result = classifyWithHeuristic('Update Prisma schema with new entity', fullContext)
|
|
148
|
-
expect(result.primaryDomain).toBe('database')
|
|
149
|
-
})
|
|
150
|
-
})
|
|
151
|
-
|
|
152
|
-
describe('devops detection', () => {
|
|
153
|
-
it('should detect Docker tasks', () => {
|
|
154
|
-
const result = classifyWithHeuristic(
|
|
155
|
-
'Create Docker container for production deployment',
|
|
156
|
-
fullContext
|
|
157
|
-
)
|
|
158
|
-
expect(result.primaryDomain).toBe('devops')
|
|
159
|
-
})
|
|
160
|
-
|
|
161
|
-
it('should detect CI/CD tasks', () => {
|
|
162
|
-
const result = classifyWithHeuristic(
|
|
163
|
-
'Fix the CI pipeline for automated deployment',
|
|
164
|
-
fullContext
|
|
165
|
-
)
|
|
166
|
-
expect(result.primaryDomain).toBe('devops')
|
|
167
|
-
})
|
|
168
|
-
})
|
|
169
|
-
|
|
170
|
-
describe('testing detection', () => {
|
|
171
|
-
it('should detect test writing tasks', () => {
|
|
172
|
-
const result = classifyWithHeuristic('Add unit tests for the payment service', fullContext)
|
|
173
|
-
expect(result.primaryDomain).toBe('testing')
|
|
174
|
-
})
|
|
175
|
-
|
|
176
|
-
it('should detect coverage improvement tasks', () => {
|
|
177
|
-
const result = classifyWithHeuristic('Improve test coverage for auth module', fullContext)
|
|
178
|
-
expect(result.primaryDomain).toBe('testing')
|
|
179
|
-
})
|
|
180
|
-
})
|
|
181
|
-
|
|
182
|
-
// =================================================================
|
|
183
|
-
// Multi-domain Tasks
|
|
184
|
-
// =================================================================
|
|
185
|
-
describe('multi-domain tasks', () => {
|
|
186
|
-
it('should detect secondary domains', () => {
|
|
187
|
-
const result = classifyWithHeuristic(
|
|
188
|
-
'Add API endpoint with React frontend component',
|
|
189
|
-
fullContext
|
|
190
|
-
)
|
|
191
|
-
expect(result.secondaryDomains.length).toBeGreaterThan(0)
|
|
192
|
-
})
|
|
193
|
-
|
|
194
|
-
it('should limit secondary domains to 2', () => {
|
|
195
|
-
const result = classifyWithHeuristic(
|
|
196
|
-
'Add API endpoint with React component and Docker deploy with test coverage and database migration',
|
|
197
|
-
fullContext
|
|
198
|
-
)
|
|
199
|
-
expect(result.secondaryDomains.length).toBeLessThanOrEqual(2)
|
|
200
|
-
})
|
|
201
|
-
})
|
|
202
|
-
|
|
203
|
-
// =================================================================
|
|
204
|
-
// Project Context Filtering
|
|
205
|
-
// =================================================================
|
|
206
|
-
describe('project context filtering', () => {
|
|
207
|
-
it('should not classify as frontend when project has no frontend', () => {
|
|
208
|
-
const result = classifyWithHeuristic(
|
|
209
|
-
'Add a button component with responsive layout',
|
|
210
|
-
backendOnlyContext
|
|
211
|
-
)
|
|
212
|
-
// Can't be frontend since project doesn't have it
|
|
213
|
-
// Falls through to general or docs (always available)
|
|
214
|
-
expect(result.primaryDomain).not.toBe('frontend')
|
|
215
|
-
})
|
|
216
|
-
|
|
217
|
-
it('should respect available agents', () => {
|
|
218
|
-
const result = classifyWithHeuristic('Create REST API endpoint', backendOnlyContext)
|
|
219
|
-
expect(result.primaryDomain).toBe('backend')
|
|
220
|
-
})
|
|
221
|
-
})
|
|
222
|
-
|
|
223
|
-
// =================================================================
|
|
224
|
-
// Confidence Scoring
|
|
225
|
-
// =================================================================
|
|
226
|
-
describe('confidence scoring', () => {
|
|
227
|
-
it('should have higher confidence for strong signals than multi-domain', () => {
|
|
228
|
-
// Single-domain (strong frontend signal) vs multi-domain (split between frontend and backend)
|
|
229
|
-
const strong = classifyWithHeuristic(
|
|
230
|
-
'Create React component with jsx tsx ui button form modal',
|
|
231
|
-
fullContext
|
|
232
|
-
)
|
|
233
|
-
const split = classifyWithHeuristic(
|
|
234
|
-
'Add API endpoint with React component and database query',
|
|
235
|
-
fullContext
|
|
236
|
-
)
|
|
237
|
-
expect(strong.confidence).toBeGreaterThanOrEqual(split.confidence)
|
|
238
|
-
})
|
|
239
|
-
|
|
240
|
-
it('should cap confidence at 0.85 for heuristic', () => {
|
|
241
|
-
const result = classifyWithHeuristic(
|
|
242
|
-
'ui component react vue angular css style button form modal layout responsive animation',
|
|
243
|
-
fullContext
|
|
244
|
-
)
|
|
245
|
-
expect(result.confidence).toBeLessThanOrEqual(0.85)
|
|
246
|
-
})
|
|
247
|
-
|
|
248
|
-
it('should return 0.3 confidence for unknown domains', () => {
|
|
249
|
-
const result = classifyWithHeuristic(
|
|
250
|
-
'Do something completely unrelated to any domain',
|
|
251
|
-
fullContext
|
|
252
|
-
)
|
|
253
|
-
expect(result.confidence).toBe(0.3)
|
|
254
|
-
expect(result.primaryDomain).toBe('general')
|
|
255
|
-
})
|
|
256
|
-
})
|
|
257
|
-
|
|
258
|
-
// =================================================================
|
|
259
|
-
// Edge Cases
|
|
260
|
-
// =================================================================
|
|
261
|
-
describe('edge cases', () => {
|
|
262
|
-
it('should handle empty description', () => {
|
|
263
|
-
const result = classifyWithHeuristic('', fullContext)
|
|
264
|
-
expect(result.primaryDomain).toBe('general')
|
|
265
|
-
expect(result.confidence).toBe(0.3)
|
|
266
|
-
})
|
|
267
|
-
|
|
268
|
-
it('should handle very long descriptions', () => {
|
|
269
|
-
const longDesc = 'Fix the bug in the component '.repeat(100)
|
|
270
|
-
const result = classifyWithHeuristic(longDesc, fullContext)
|
|
271
|
-
expect(result.primaryDomain).toBeDefined()
|
|
272
|
-
})
|
|
273
|
-
|
|
274
|
-
it('should be case-insensitive', () => {
|
|
275
|
-
const lower = classifyWithHeuristic('add react component', fullContext)
|
|
276
|
-
const upper = classifyWithHeuristic('ADD REACT COMPONENT', fullContext)
|
|
277
|
-
expect(lower.primaryDomain).toBe(upper.primaryDomain)
|
|
278
|
-
})
|
|
279
|
-
})
|
|
280
|
-
})
|
|
281
|
-
|
|
282
|
-
// =================================================================
|
|
283
|
-
// Hash Function
|
|
284
|
-
// =================================================================
|
|
285
|
-
describe('hashDescription', () => {
|
|
286
|
-
it('should produce consistent hashes', () => {
|
|
287
|
-
const hash1 = hashDescription('Fix the auth middleware')
|
|
288
|
-
const hash2 = hashDescription('Fix the auth middleware')
|
|
289
|
-
expect(hash1).toBe(hash2)
|
|
290
|
-
})
|
|
291
|
-
|
|
292
|
-
it('should be case-insensitive', () => {
|
|
293
|
-
const hash1 = hashDescription('Fix the Auth Middleware')
|
|
294
|
-
const hash2 = hashDescription('fix the auth middleware')
|
|
295
|
-
expect(hash1).toBe(hash2)
|
|
296
|
-
})
|
|
297
|
-
|
|
298
|
-
it('should trim whitespace', () => {
|
|
299
|
-
const hash1 = hashDescription(' Fix the auth middleware ')
|
|
300
|
-
const hash2 = hashDescription('Fix the auth middleware')
|
|
301
|
-
expect(hash1).toBe(hash2)
|
|
302
|
-
})
|
|
303
|
-
|
|
304
|
-
it('should produce different hashes for different descriptions', () => {
|
|
305
|
-
const hash1 = hashDescription('Fix frontend component')
|
|
306
|
-
const hash2 = hashDescription('Fix backend service')
|
|
307
|
-
expect(hash1).not.toBe(hash2)
|
|
308
|
-
})
|
|
309
|
-
|
|
310
|
-
it('should return a 16-character hex string', () => {
|
|
311
|
-
const hash = hashDescription('Test description')
|
|
312
|
-
expect(hash).toMatch(/^[a-f0-9]{16}$/)
|
|
313
|
-
})
|
|
314
|
-
})
|
|
315
|
-
|
|
316
|
-
// =================================================================
|
|
317
|
-
// File Patterns
|
|
318
|
-
// =================================================================
|
|
319
|
-
describe('file patterns', () => {
|
|
320
|
-
it('should return frontend file patterns for frontend domain', () => {
|
|
321
|
-
const result = classifyWithHeuristic('Add React component', fullContext)
|
|
322
|
-
expect(result.filePatterns.length).toBeGreaterThan(0)
|
|
323
|
-
})
|
|
324
|
-
|
|
325
|
-
it('should return relevant agents', () => {
|
|
326
|
-
const result = classifyWithHeuristic('Create REST API endpoint', fullContext)
|
|
327
|
-
expect(result.relevantAgents).toContain('backend')
|
|
328
|
-
})
|
|
329
|
-
})
|
|
330
|
-
})
|
|
@@ -1,255 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Injection Validator Tests
|
|
3
|
-
* Tests for safeInject, truncation, skill filtering, and budget tracking.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { describe, expect, it } from 'bun:test'
|
|
7
|
-
import { z } from 'zod'
|
|
8
|
-
import {
|
|
9
|
-
DEFAULT_BUDGETS,
|
|
10
|
-
estimateTokens,
|
|
11
|
-
filterSkillsByDomains,
|
|
12
|
-
InjectionBudgetTracker,
|
|
13
|
-
safeInject,
|
|
14
|
-
safeInjectString,
|
|
15
|
-
truncateToTokenBudget,
|
|
16
|
-
} from '../../agentic/injection-validator'
|
|
17
|
-
|
|
18
|
-
// =============================================================================
|
|
19
|
-
// safeInject
|
|
20
|
-
// =============================================================================
|
|
21
|
-
|
|
22
|
-
describe('safeInject', () => {
|
|
23
|
-
const schema = z.object({ name: z.string(), value: z.number() })
|
|
24
|
-
const fallback = { name: 'unknown', value: 0 }
|
|
25
|
-
|
|
26
|
-
it('returns validated data on valid input', () => {
|
|
27
|
-
const data = { name: 'test', value: 42 }
|
|
28
|
-
expect(safeInject(data, schema, fallback)).toEqual(data)
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
it('returns fallback on invalid input', () => {
|
|
32
|
-
const data = { name: 123, value: 'bad' }
|
|
33
|
-
expect(safeInject(data, schema, fallback)).toEqual(fallback)
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
it('returns fallback on null input', () => {
|
|
37
|
-
expect(safeInject(null, schema, fallback)).toEqual(fallback)
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
it('returns fallback on undefined input', () => {
|
|
41
|
-
expect(safeInject(undefined, schema, fallback)).toEqual(fallback)
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
it('strips extra fields via Zod', () => {
|
|
45
|
-
const data = { name: 'test', value: 42, extra: 'ignored' }
|
|
46
|
-
const result = safeInject(data, schema, fallback)
|
|
47
|
-
expect(result.name).toBe('test')
|
|
48
|
-
expect(result.value).toBe(42)
|
|
49
|
-
})
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
// =============================================================================
|
|
53
|
-
// safeInjectString
|
|
54
|
-
// =============================================================================
|
|
55
|
-
|
|
56
|
-
describe('safeInjectString', () => {
|
|
57
|
-
const schema = z.object({ count: z.number() })
|
|
58
|
-
const formatter = (d: { count: number }) => `Items: ${d.count}`
|
|
59
|
-
|
|
60
|
-
it('returns formatted string on valid input', () => {
|
|
61
|
-
expect(safeInjectString({ count: 5 }, schema, formatter, 'N/A')).toBe('Items: 5')
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
it('returns fallback string on invalid input', () => {
|
|
65
|
-
expect(safeInjectString({ count: 'bad' }, schema, formatter, 'N/A')).toBe('N/A')
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
it('returns fallback string on null', () => {
|
|
69
|
-
expect(safeInjectString(null, schema, formatter, 'no data')).toBe('no data')
|
|
70
|
-
})
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
// =============================================================================
|
|
74
|
-
// truncateToTokenBudget
|
|
75
|
-
// =============================================================================
|
|
76
|
-
|
|
77
|
-
describe('truncateToTokenBudget', () => {
|
|
78
|
-
it('returns text unchanged if within budget', () => {
|
|
79
|
-
const text = 'short text'
|
|
80
|
-
expect(truncateToTokenBudget(text, 100)).toBe(text)
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
it('truncates text that exceeds budget', () => {
|
|
84
|
-
const text = 'a'.repeat(500) // 500 chars = ~125 tokens
|
|
85
|
-
const result = truncateToTokenBudget(text, 50) // 50 tokens = 200 chars
|
|
86
|
-
expect(result.length).toBeLessThan(500)
|
|
87
|
-
expect(result).toContain('truncated')
|
|
88
|
-
expect(result).toContain('~50 tokens')
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
it('truncates to exact char limit', () => {
|
|
92
|
-
const text = 'a'.repeat(100)
|
|
93
|
-
const result = truncateToTokenBudget(text, 10) // 10 tokens = 40 chars
|
|
94
|
-
expect(result.startsWith('a'.repeat(40))).toBe(true)
|
|
95
|
-
})
|
|
96
|
-
|
|
97
|
-
it('handles empty string', () => {
|
|
98
|
-
expect(truncateToTokenBudget('', 100)).toBe('')
|
|
99
|
-
})
|
|
100
|
-
|
|
101
|
-
it('handles zero budget', () => {
|
|
102
|
-
const result = truncateToTokenBudget('some text', 0)
|
|
103
|
-
expect(result).toContain('truncated')
|
|
104
|
-
})
|
|
105
|
-
})
|
|
106
|
-
|
|
107
|
-
// =============================================================================
|
|
108
|
-
// estimateTokens
|
|
109
|
-
// =============================================================================
|
|
110
|
-
|
|
111
|
-
describe('estimateTokens', () => {
|
|
112
|
-
it('estimates tokens at ~4 chars per token', () => {
|
|
113
|
-
expect(estimateTokens('a'.repeat(100))).toBe(25)
|
|
114
|
-
})
|
|
115
|
-
|
|
116
|
-
it('rounds up partial tokens', () => {
|
|
117
|
-
expect(estimateTokens('abc')).toBe(1) // 3/4 = 0.75, ceil = 1
|
|
118
|
-
})
|
|
119
|
-
|
|
120
|
-
it('handles empty string', () => {
|
|
121
|
-
expect(estimateTokens('')).toBe(0)
|
|
122
|
-
})
|
|
123
|
-
})
|
|
124
|
-
|
|
125
|
-
// =============================================================================
|
|
126
|
-
// filterSkillsByDomains
|
|
127
|
-
// =============================================================================
|
|
128
|
-
|
|
129
|
-
describe('filterSkillsByDomains', () => {
|
|
130
|
-
const skills = [
|
|
131
|
-
{ name: 'react-patterns', content: 'React component patterns and hooks' },
|
|
132
|
-
{ name: 'api-design', content: 'RESTful API design and endpoint patterns' },
|
|
133
|
-
{ name: 'jest-testing', content: 'Jest test patterns and assertions' },
|
|
134
|
-
{ name: 'docker-deploy', content: 'Docker and Kubernetes deployment' },
|
|
135
|
-
{ name: 'general-coding', content: 'General coding best practices' },
|
|
136
|
-
]
|
|
137
|
-
|
|
138
|
-
it('returns all skills when no domains detected', () => {
|
|
139
|
-
expect(filterSkillsByDomains(skills, [])).toEqual(skills)
|
|
140
|
-
})
|
|
141
|
-
|
|
142
|
-
it('returns all skills when skills array is empty', () => {
|
|
143
|
-
expect(filterSkillsByDomains([], ['frontend'])).toEqual([])
|
|
144
|
-
})
|
|
145
|
-
|
|
146
|
-
it('filters to frontend-relevant skills', () => {
|
|
147
|
-
const result = filterSkillsByDomains(skills, ['frontend'])
|
|
148
|
-
expect(result.some((s) => s.name === 'react-patterns')).toBe(true)
|
|
149
|
-
expect(result.some((s) => s.name === 'docker-deploy')).toBe(false)
|
|
150
|
-
})
|
|
151
|
-
|
|
152
|
-
it('filters to backend-relevant skills', () => {
|
|
153
|
-
const result = filterSkillsByDomains(skills, ['backend'])
|
|
154
|
-
expect(result.some((s) => s.name === 'api-design')).toBe(true)
|
|
155
|
-
expect(result.some((s) => s.name === 'react-patterns')).toBe(false)
|
|
156
|
-
})
|
|
157
|
-
|
|
158
|
-
it('filters to testing-relevant skills', () => {
|
|
159
|
-
const result = filterSkillsByDomains(skills, ['testing'])
|
|
160
|
-
expect(result.some((s) => s.name === 'jest-testing')).toBe(true)
|
|
161
|
-
})
|
|
162
|
-
|
|
163
|
-
it('supports multiple domains', () => {
|
|
164
|
-
const result = filterSkillsByDomains(skills, ['frontend', 'testing'])
|
|
165
|
-
expect(result.some((s) => s.name === 'react-patterns')).toBe(true)
|
|
166
|
-
expect(result.some((s) => s.name === 'jest-testing')).toBe(true)
|
|
167
|
-
expect(result.some((s) => s.name === 'docker-deploy')).toBe(false)
|
|
168
|
-
})
|
|
169
|
-
|
|
170
|
-
it('matches domain name itself as keyword', () => {
|
|
171
|
-
const customSkills = [{ name: 'devops-helper', content: 'general devops tools' }]
|
|
172
|
-
const result = filterSkillsByDomains(customSkills, ['devops'])
|
|
173
|
-
expect(result).toHaveLength(1)
|
|
174
|
-
})
|
|
175
|
-
|
|
176
|
-
it('is case insensitive', () => {
|
|
177
|
-
const result = filterSkillsByDomains(skills, ['Frontend'])
|
|
178
|
-
expect(result.some((s) => s.name === 'react-patterns')).toBe(true)
|
|
179
|
-
})
|
|
180
|
-
})
|
|
181
|
-
|
|
182
|
-
// =============================================================================
|
|
183
|
-
// InjectionBudgetTracker
|
|
184
|
-
// =============================================================================
|
|
185
|
-
|
|
186
|
-
describe('InjectionBudgetTracker', () => {
|
|
187
|
-
it('tracks cumulative token usage', () => {
|
|
188
|
-
const tracker = new InjectionBudgetTracker({ totalPrompt: 100 })
|
|
189
|
-
tracker.addSection('a'.repeat(200), 100) // 200 chars = 50 tokens
|
|
190
|
-
expect(tracker.totalUsed).toBe(50)
|
|
191
|
-
expect(tracker.remaining).toBe(50)
|
|
192
|
-
})
|
|
193
|
-
|
|
194
|
-
it('truncates sections to per-section budget', () => {
|
|
195
|
-
const tracker = new InjectionBudgetTracker({ totalPrompt: 1000 })
|
|
196
|
-
const result = tracker.addSection('a'.repeat(500), 50) // budget: 50 tokens = 200 chars
|
|
197
|
-
expect(result.length).toBeLessThan(500)
|
|
198
|
-
})
|
|
199
|
-
|
|
200
|
-
it('returns empty string when total budget exhausted', () => {
|
|
201
|
-
const tracker = new InjectionBudgetTracker({ totalPrompt: 10 })
|
|
202
|
-
tracker.addSection('a'.repeat(100), 50) // uses all 10 tokens of total budget
|
|
203
|
-
const result = tracker.addSection('more content', 50)
|
|
204
|
-
expect(result).toBe('')
|
|
205
|
-
})
|
|
206
|
-
|
|
207
|
-
it('fits content to remaining total budget', () => {
|
|
208
|
-
const tracker = new InjectionBudgetTracker({ totalPrompt: 30 })
|
|
209
|
-
tracker.addSection('a'.repeat(80), 30) // 80 chars = 20 tokens
|
|
210
|
-
// Remaining: 10 tokens
|
|
211
|
-
const result = tracker.addSection('b'.repeat(200), 100) // wants 100 tokens, only 10 left
|
|
212
|
-
expect(result.length).toBeLessThan(200)
|
|
213
|
-
expect(tracker.remaining).toBe(0)
|
|
214
|
-
})
|
|
215
|
-
|
|
216
|
-
it('uses default budgets when none provided', () => {
|
|
217
|
-
const tracker = new InjectionBudgetTracker()
|
|
218
|
-
expect(tracker.config.totalPrompt).toBe(DEFAULT_BUDGETS.totalPrompt)
|
|
219
|
-
expect(tracker.config.autoContext).toBe(DEFAULT_BUDGETS.autoContext)
|
|
220
|
-
})
|
|
221
|
-
|
|
222
|
-
it('allows partial budget overrides', () => {
|
|
223
|
-
const tracker = new InjectionBudgetTracker({ totalPrompt: 5000 })
|
|
224
|
-
expect(tracker.config.totalPrompt).toBe(5000)
|
|
225
|
-
expect(tracker.config.autoContext).toBe(DEFAULT_BUDGETS.autoContext) // unchanged
|
|
226
|
-
})
|
|
227
|
-
|
|
228
|
-
it('remaining never goes negative', () => {
|
|
229
|
-
const tracker = new InjectionBudgetTracker({ totalPrompt: 5 })
|
|
230
|
-
tracker.addSection('a'.repeat(1000), 500)
|
|
231
|
-
expect(tracker.remaining).toBe(0)
|
|
232
|
-
})
|
|
233
|
-
})
|
|
234
|
-
|
|
235
|
-
// =============================================================================
|
|
236
|
-
// DEFAULT_BUDGETS
|
|
237
|
-
// =============================================================================
|
|
238
|
-
|
|
239
|
-
describe('DEFAULT_BUDGETS', () => {
|
|
240
|
-
it('has all required fields', () => {
|
|
241
|
-
expect(DEFAULT_BUDGETS.autoContext).toBeGreaterThan(0)
|
|
242
|
-
expect(DEFAULT_BUDGETS.agentContent).toBeGreaterThan(0)
|
|
243
|
-
expect(DEFAULT_BUDGETS.skillContent).toBeGreaterThan(0)
|
|
244
|
-
expect(DEFAULT_BUDGETS.stateData).toBeGreaterThan(0)
|
|
245
|
-
expect(DEFAULT_BUDGETS.memories).toBeGreaterThan(0)
|
|
246
|
-
expect(DEFAULT_BUDGETS.totalPrompt).toBeGreaterThan(0)
|
|
247
|
-
})
|
|
248
|
-
|
|
249
|
-
it('totalPrompt is larger than individual budgets', () => {
|
|
250
|
-
expect(DEFAULT_BUDGETS.totalPrompt).toBeGreaterThan(DEFAULT_BUDGETS.autoContext)
|
|
251
|
-
expect(DEFAULT_BUDGETS.totalPrompt).toBeGreaterThan(DEFAULT_BUDGETS.agentContent)
|
|
252
|
-
expect(DEFAULT_BUDGETS.totalPrompt).toBeGreaterThan(DEFAULT_BUDGETS.skillContent)
|
|
253
|
-
expect(DEFAULT_BUDGETS.totalPrompt).toBeGreaterThan(DEFAULT_BUDGETS.stateData)
|
|
254
|
-
})
|
|
255
|
-
})
|