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,525 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Domain Classifier
|
|
3
|
-
*
|
|
4
|
-
* LLM-based task domain classification with caching and fallback chain.
|
|
5
|
-
* Replaces hardcoded keyword substring matching that caused false positives
|
|
6
|
-
* (e.g., "author" matching "auth" → backend).
|
|
7
|
-
*
|
|
8
|
-
* Fallback chain:
|
|
9
|
-
* 1. Cache lookup (file-based, 1hr TTL)
|
|
10
|
-
* 2. Confirmed patterns (from successful task completions)
|
|
11
|
-
* 3. LLM call (Claude haiku, ~200 tokens)
|
|
12
|
-
* 4. Improved heuristic (word-boundary matching, no substring traps)
|
|
13
|
-
*
|
|
14
|
-
* @see PRJ-299
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
import { createHash } from 'node:crypto'
|
|
18
|
-
import fs from 'node:fs/promises'
|
|
19
|
-
import path from 'node:path'
|
|
20
|
-
import {
|
|
21
|
-
type ClassificationCache,
|
|
22
|
-
type ClassificationDomain,
|
|
23
|
-
DEFAULT_CLASSIFICATION_CACHE,
|
|
24
|
-
GENERAL_CLASSIFICATION,
|
|
25
|
-
type TaskClassification,
|
|
26
|
-
TaskClassificationSchema,
|
|
27
|
-
} from '../schemas/classification'
|
|
28
|
-
import { renderSchemaForPrompt } from '../schemas/llm-output'
|
|
29
|
-
import { getErrorMessage, isNotFoundError } from '../types/fs'
|
|
30
|
-
|
|
31
|
-
const CACHE_TTL_MS = 60 * 60 * 1000 // 1 hour
|
|
32
|
-
|
|
33
|
-
// =============================================================================
|
|
34
|
-
// Project Context (passed to classifier)
|
|
35
|
-
// =============================================================================
|
|
36
|
-
|
|
37
|
-
export interface ProjectContext {
|
|
38
|
-
/** Domains detected during sync */
|
|
39
|
-
domains: {
|
|
40
|
-
hasFrontend: boolean
|
|
41
|
-
hasBackend: boolean
|
|
42
|
-
hasDatabase: boolean
|
|
43
|
-
hasTesting: boolean
|
|
44
|
-
hasDocker: boolean
|
|
45
|
-
}
|
|
46
|
-
/** Available agent names (without .md extension) */
|
|
47
|
-
agents: string[]
|
|
48
|
-
/** Project stack info */
|
|
49
|
-
stack?: { language?: string; framework?: string }
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// =============================================================================
|
|
53
|
-
// Hashing
|
|
54
|
-
// =============================================================================
|
|
55
|
-
|
|
56
|
-
function hashDescription(description: string): string {
|
|
57
|
-
return createHash('sha256').update(description.toLowerCase().trim()).digest('hex').slice(0, 16)
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// =============================================================================
|
|
61
|
-
// Cache Layer
|
|
62
|
-
// =============================================================================
|
|
63
|
-
|
|
64
|
-
async function loadCache(globalPath: string): Promise<ClassificationCache> {
|
|
65
|
-
try {
|
|
66
|
-
const cachePath = path.join(globalPath, 'storage', 'classification-cache.json')
|
|
67
|
-
const content = await fs.readFile(cachePath, 'utf-8')
|
|
68
|
-
return JSON.parse(content)
|
|
69
|
-
} catch (error) {
|
|
70
|
-
if (isNotFoundError(error)) return DEFAULT_CLASSIFICATION_CACHE
|
|
71
|
-
console.warn('[classifier] Failed to load cache:', getErrorMessage(error))
|
|
72
|
-
return DEFAULT_CLASSIFICATION_CACHE
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
async function saveCache(globalPath: string, cache: ClassificationCache): Promise<void> {
|
|
77
|
-
try {
|
|
78
|
-
const cachePath = path.join(globalPath, 'storage', 'classification-cache.json')
|
|
79
|
-
await fs.writeFile(cachePath, JSON.stringify(cache, null, 2))
|
|
80
|
-
} catch (error) {
|
|
81
|
-
console.warn('[classifier] Failed to save cache:', getErrorMessage(error))
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function lookupCache(
|
|
86
|
-
cache: ClassificationCache,
|
|
87
|
-
hash: string,
|
|
88
|
-
projectId: string
|
|
89
|
-
): TaskClassification | null {
|
|
90
|
-
const entry = cache.entries[hash]
|
|
91
|
-
if (!entry) return null
|
|
92
|
-
if (entry.projectId !== projectId) return null
|
|
93
|
-
|
|
94
|
-
// Check TTL
|
|
95
|
-
const age = Date.now() - new Date(entry.classifiedAt).getTime()
|
|
96
|
-
if (age > CACHE_TTL_MS) return null
|
|
97
|
-
|
|
98
|
-
return entry.classification
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// =============================================================================
|
|
102
|
-
// Confirmed Patterns (from successful task completions)
|
|
103
|
-
// =============================================================================
|
|
104
|
-
|
|
105
|
-
function lookupPatterns(cache: ClassificationCache, hash: string): TaskClassification | null {
|
|
106
|
-
const pattern = cache.confirmedPatterns.find((p) => p.descriptionHash === hash)
|
|
107
|
-
return pattern?.classification ?? null
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// =============================================================================
|
|
111
|
-
// LLM Classification (Claude Haiku via raw API)
|
|
112
|
-
// =============================================================================
|
|
113
|
-
|
|
114
|
-
async function classifyWithLLM(
|
|
115
|
-
description: string,
|
|
116
|
-
context: ProjectContext
|
|
117
|
-
): Promise<TaskClassification | null> {
|
|
118
|
-
const apiKey = process.env.ANTHROPIC_API_KEY
|
|
119
|
-
if (!apiKey) return null
|
|
120
|
-
|
|
121
|
-
const availableDomains = buildAvailableDomains(context)
|
|
122
|
-
const schemaBlock = renderSchemaForPrompt('classification') || ''
|
|
123
|
-
|
|
124
|
-
const prompt = `Classify this software engineering task into a domain.
|
|
125
|
-
|
|
126
|
-
Task: "${description}"
|
|
127
|
-
|
|
128
|
-
Available domains in this project: ${availableDomains.join(', ')}
|
|
129
|
-
Available agents: ${context.agents.join(', ') || 'none'}
|
|
130
|
-
Stack: ${context.stack?.language || 'unknown'} / ${context.stack?.framework || 'unknown'}
|
|
131
|
-
|
|
132
|
-
${schemaBlock}`
|
|
133
|
-
|
|
134
|
-
try {
|
|
135
|
-
const response = await fetch('https://api.anthropic.com/v1/messages', {
|
|
136
|
-
method: 'POST',
|
|
137
|
-
headers: {
|
|
138
|
-
'Content-Type': 'application/json',
|
|
139
|
-
'x-api-key': apiKey,
|
|
140
|
-
'anthropic-version': '2023-06-01',
|
|
141
|
-
},
|
|
142
|
-
body: JSON.stringify({
|
|
143
|
-
model: 'claude-haiku-4-5-20251001',
|
|
144
|
-
max_tokens: 200,
|
|
145
|
-
messages: [{ role: 'user', content: prompt }],
|
|
146
|
-
}),
|
|
147
|
-
})
|
|
148
|
-
|
|
149
|
-
if (!response.ok) return null
|
|
150
|
-
|
|
151
|
-
const data = (await response.json()) as {
|
|
152
|
-
content: Array<{ type: string; text?: string }>
|
|
153
|
-
}
|
|
154
|
-
const text = data.content?.[0]?.text
|
|
155
|
-
if (!text) return null
|
|
156
|
-
|
|
157
|
-
const parsed = JSON.parse(text)
|
|
158
|
-
|
|
159
|
-
// Validate with Zod schema (PRJ-264)
|
|
160
|
-
const result = TaskClassificationSchema.safeParse(parsed)
|
|
161
|
-
if (result.success) {
|
|
162
|
-
return result.data
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// Re-prompt: coerce what we can from partial response
|
|
166
|
-
return {
|
|
167
|
-
primaryDomain: availableDomains.includes(parsed.primaryDomain)
|
|
168
|
-
? parsed.primaryDomain
|
|
169
|
-
: 'general',
|
|
170
|
-
secondaryDomains: (parsed.secondaryDomains || []).filter((d: string) =>
|
|
171
|
-
availableDomains.includes(d as ClassificationDomain)
|
|
172
|
-
),
|
|
173
|
-
confidence: Math.min(1, Math.max(0, parsed.confidence || 0.5)),
|
|
174
|
-
filePatterns: Array.isArray(parsed.filePatterns) ? parsed.filePatterns : [],
|
|
175
|
-
relevantAgents: Array.isArray(parsed.relevantAgents) ? parsed.relevantAgents : [],
|
|
176
|
-
}
|
|
177
|
-
} catch {
|
|
178
|
-
return null
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
// =============================================================================
|
|
183
|
-
// Improved Heuristic (word-boundary matching, no substring traps)
|
|
184
|
-
// =============================================================================
|
|
185
|
-
|
|
186
|
-
/** Word-boundary keyword map — avoids substring false positives */
|
|
187
|
-
const DOMAIN_PATTERNS: Record<ClassificationDomain, RegExp[]> = {
|
|
188
|
-
frontend: [
|
|
189
|
-
/\bui\b/i,
|
|
190
|
-
/\bcomponents?\b/i,
|
|
191
|
-
/\breact\b/i,
|
|
192
|
-
/\bvue\b/i,
|
|
193
|
-
/\bangular\b/i,
|
|
194
|
-
/\bsvelte\b/i,
|
|
195
|
-
/\bnext\.?js\b/i,
|
|
196
|
-
/\bnuxt\b/i,
|
|
197
|
-
/\bcss\b/i,
|
|
198
|
-
/\bscss\b/i,
|
|
199
|
-
/\bstyles?\b/i,
|
|
200
|
-
/\bbuttons?\b/i,
|
|
201
|
-
/\bforms?\b/i,
|
|
202
|
-
/\bmodals?\b/i,
|
|
203
|
-
/\blayout\b/i,
|
|
204
|
-
/\bresponsive\b/i,
|
|
205
|
-
/\banimation\b/i,
|
|
206
|
-
/\bdom\b/i,
|
|
207
|
-
/\bhtml\b/i,
|
|
208
|
-
/\bfrontend\b/i,
|
|
209
|
-
/\bclient[- ]side\b/i,
|
|
210
|
-
/\bbrowser\b/i,
|
|
211
|
-
/\bjsx\b/i,
|
|
212
|
-
/\btsx\b/i,
|
|
213
|
-
/\bhooks?\b/i,
|
|
214
|
-
/\bredux\b/i,
|
|
215
|
-
/\bzustand\b/i,
|
|
216
|
-
/\btailwind\b/i,
|
|
217
|
-
/\bdashboard\b/i,
|
|
218
|
-
/\bpage\b/i,
|
|
219
|
-
/\bnavigation\b/i,
|
|
220
|
-
/\bsidebar\b/i,
|
|
221
|
-
/\bheader\b/i,
|
|
222
|
-
/\bfooter\b/i,
|
|
223
|
-
/\bwidget\b/i,
|
|
224
|
-
/\btooltip\b/i,
|
|
225
|
-
/\bdropdown\b/i,
|
|
226
|
-
/\bcarousel\b/i,
|
|
227
|
-
/\bprofile\s+page\b/i,
|
|
228
|
-
/\bdisplay\b/i,
|
|
229
|
-
],
|
|
230
|
-
backend: [
|
|
231
|
-
/\bapi\b/i,
|
|
232
|
-
/\bendpoints?\b/i,
|
|
233
|
-
/\bserver\b/i,
|
|
234
|
-
/\broutes?\b/i,
|
|
235
|
-
/\bhandlers?\b/i,
|
|
236
|
-
/\bcontrollers?\b/i,
|
|
237
|
-
/\bservices?\b/i,
|
|
238
|
-
/\bmiddleware\b/i,
|
|
239
|
-
/\bauth\b/i,
|
|
240
|
-
/\bauthentication\b/i,
|
|
241
|
-
/\bauthorization\b/i,
|
|
242
|
-
/\bjwt\b/i,
|
|
243
|
-
/\boauth\b/i,
|
|
244
|
-
/\brest\b/i,
|
|
245
|
-
/\bgraphql\b/i,
|
|
246
|
-
/\btrpc\b/i,
|
|
247
|
-
/\bexpress\b/i,
|
|
248
|
-
/\bfastify\b/i,
|
|
249
|
-
/\bhono\b/i,
|
|
250
|
-
/\bnest\.?js\b/i,
|
|
251
|
-
/\bvalidation\b/i,
|
|
252
|
-
/\bbusiness\s+logic\b/i,
|
|
253
|
-
/\bcron\b/i,
|
|
254
|
-
/\bwebhook\b/i,
|
|
255
|
-
/\bworker\b/i,
|
|
256
|
-
/\bqueue\b/i,
|
|
257
|
-
/\bcache\b/i,
|
|
258
|
-
],
|
|
259
|
-
database: [
|
|
260
|
-
/\bdatabase\b/i,
|
|
261
|
-
/\bdb\b/i,
|
|
262
|
-
/\bsql\b/i,
|
|
263
|
-
/\bquery\b/i,
|
|
264
|
-
/\btables?\b/i,
|
|
265
|
-
/\bschema\b/i,
|
|
266
|
-
/\bmigrations?\b/i,
|
|
267
|
-
/\bpostgres\b/i,
|
|
268
|
-
/\bmysql\b/i,
|
|
269
|
-
/\bsqlite\b/i,
|
|
270
|
-
/\bmongo\b/i,
|
|
271
|
-
/\bredis\b/i,
|
|
272
|
-
/\bprisma\b/i,
|
|
273
|
-
/\bdrizzle\b/i,
|
|
274
|
-
/\borm\b/i,
|
|
275
|
-
/\bentity\b/i,
|
|
276
|
-
/\brepository\b/i,
|
|
277
|
-
/\bdata\s+layer\b/i,
|
|
278
|
-
/\bpersist\b/i,
|
|
279
|
-
/\bindex(?:es|ing)?\b/i,
|
|
280
|
-
/\bconnection\s+pool\b/i,
|
|
281
|
-
],
|
|
282
|
-
devops: [
|
|
283
|
-
/\bdocker\b/i,
|
|
284
|
-
/\bkubernetes\b/i,
|
|
285
|
-
/\bk8s\b/i,
|
|
286
|
-
/\bci\b/i,
|
|
287
|
-
/\bcd\b/i,
|
|
288
|
-
/\bpipeline\b/i,
|
|
289
|
-
/\bdeploy\b/i,
|
|
290
|
-
/\bgithub\s+actions\b/i,
|
|
291
|
-
/\bvercel\b/i,
|
|
292
|
-
/\baws\b/i,
|
|
293
|
-
/\bgcp\b/i,
|
|
294
|
-
/\bazure\b/i,
|
|
295
|
-
/\bterraform\b/i,
|
|
296
|
-
/\bnginx\b/i,
|
|
297
|
-
/\bcaddy\b/i,
|
|
298
|
-
/\binfrastructure\b/i,
|
|
299
|
-
/\bmonitoring\b/i,
|
|
300
|
-
/\blogging\b/i,
|
|
301
|
-
/\bcontainer\b/i,
|
|
302
|
-
/\bhelm\b/i,
|
|
303
|
-
],
|
|
304
|
-
testing: [
|
|
305
|
-
/\btests?\b/i,
|
|
306
|
-
/\bspec\b/i,
|
|
307
|
-
/\bunit\s+tests?\b/i,
|
|
308
|
-
/\bintegration\s+tests?\b/i,
|
|
309
|
-
/\be2e\b/i,
|
|
310
|
-
/\bjest\b/i,
|
|
311
|
-
/\bvitest\b/i,
|
|
312
|
-
/\bplaywright\b/i,
|
|
313
|
-
/\bcypress\b/i,
|
|
314
|
-
/\bmocha\b/i,
|
|
315
|
-
/\bmocks?\b/i,
|
|
316
|
-
/\bstubs?\b/i,
|
|
317
|
-
/\bfixtures?\b/i,
|
|
318
|
-
/\bcoverage\b/i,
|
|
319
|
-
/\bassertions?\b/i,
|
|
320
|
-
],
|
|
321
|
-
docs: [
|
|
322
|
-
/\bdocument(?:ation)?\b/i,
|
|
323
|
-
/\bdocs\b/i,
|
|
324
|
-
/\breadme\b/i,
|
|
325
|
-
/\bchangelog\b/i,
|
|
326
|
-
/\bjsdoc\b/i,
|
|
327
|
-
/\btutorial\b/i,
|
|
328
|
-
/\bguide\b/i,
|
|
329
|
-
/\bmarkdown\b/i,
|
|
330
|
-
],
|
|
331
|
-
uxui: [
|
|
332
|
-
/\bdesign\b/i,
|
|
333
|
-
/\bux\b/i,
|
|
334
|
-
/\buser\s+experience\b/i,
|
|
335
|
-
/\baccessibility\b/i,
|
|
336
|
-
/\ba11y\b/i,
|
|
337
|
-
/\bwcag\b/i,
|
|
338
|
-
/\bfigma\b/i,
|
|
339
|
-
/\bprototype\b/i,
|
|
340
|
-
/\bwireframe\b/i,
|
|
341
|
-
/\busability\b/i,
|
|
342
|
-
],
|
|
343
|
-
general: [],
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
/**
|
|
347
|
-
* Improved heuristic classifier using word-boundary regex.
|
|
348
|
-
* Avoids substring traps like "author" matching "auth".
|
|
349
|
-
*/
|
|
350
|
-
function classifyWithHeuristic(description: string, context: ProjectContext): TaskClassification {
|
|
351
|
-
const availableDomains = buildAvailableDomains(context)
|
|
352
|
-
const scores = new Map<ClassificationDomain, number>()
|
|
353
|
-
|
|
354
|
-
for (const [domain, patterns] of Object.entries(DOMAIN_PATTERNS)) {
|
|
355
|
-
if (domain === 'general') continue
|
|
356
|
-
// Only score domains that exist in this project
|
|
357
|
-
if (!availableDomains.includes(domain as ClassificationDomain)) continue
|
|
358
|
-
|
|
359
|
-
let score = 0
|
|
360
|
-
for (const pattern of patterns) {
|
|
361
|
-
const matches = description.match(new RegExp(pattern, 'gi'))
|
|
362
|
-
if (matches) {
|
|
363
|
-
// Multi-word patterns score higher
|
|
364
|
-
score += pattern.source.includes('\\s') ? 3 : 1
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
if (score > 0) {
|
|
368
|
-
scores.set(domain as ClassificationDomain, score)
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
if (scores.size === 0) {
|
|
373
|
-
return GENERAL_CLASSIFICATION
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
const sorted = Array.from(scores.entries()).sort((a, b) => b[1] - a[1])
|
|
377
|
-
const primary = sorted[0][0]
|
|
378
|
-
const primaryScore = sorted[0][1]
|
|
379
|
-
const secondary = sorted.slice(1, 3).map(([d]) => d)
|
|
380
|
-
|
|
381
|
-
const totalScore = sorted.reduce((sum, [, s]) => sum + s, 0)
|
|
382
|
-
const confidence = Math.min(0.85, primaryScore / totalScore + 0.2)
|
|
383
|
-
|
|
384
|
-
// Map domain to file patterns
|
|
385
|
-
const filePatterns = getFilePatterns(primary)
|
|
386
|
-
|
|
387
|
-
// Map domain to agent names
|
|
388
|
-
const relevantAgents = context.agents.filter(
|
|
389
|
-
(a) => a === primary || a.includes(primary) || primary.includes(a.replace('.md', ''))
|
|
390
|
-
)
|
|
391
|
-
|
|
392
|
-
return {
|
|
393
|
-
primaryDomain: primary,
|
|
394
|
-
secondaryDomains: secondary,
|
|
395
|
-
confidence,
|
|
396
|
-
filePatterns,
|
|
397
|
-
relevantAgents,
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
// =============================================================================
|
|
402
|
-
// Helpers
|
|
403
|
-
// =============================================================================
|
|
404
|
-
|
|
405
|
-
function buildAvailableDomains(context: ProjectContext): ClassificationDomain[] {
|
|
406
|
-
const domains: ClassificationDomain[] = []
|
|
407
|
-
if (context.domains.hasFrontend) domains.push('frontend')
|
|
408
|
-
if (context.domains.hasBackend) domains.push('backend')
|
|
409
|
-
if (context.domains.hasDatabase) domains.push('database')
|
|
410
|
-
if (context.domains.hasTesting) domains.push('testing')
|
|
411
|
-
if (context.domains.hasDocker) domains.push('devops')
|
|
412
|
-
// Always include these as possibilities
|
|
413
|
-
domains.push('docs', 'uxui', 'general')
|
|
414
|
-
return domains
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
function getFilePatterns(domain: ClassificationDomain): string[] {
|
|
418
|
-
const patterns: Record<ClassificationDomain, string[]> = {
|
|
419
|
-
frontend: ['src/components/**', 'src/pages/**', 'src/hooks/**', '**/*.tsx', '**/*.jsx'],
|
|
420
|
-
backend: ['src/api/**', 'src/routes/**', 'src/services/**', 'src/handlers/**'],
|
|
421
|
-
database: ['src/models/**', 'src/schemas/**', '**/*.sql', 'prisma/**'],
|
|
422
|
-
devops: ['.github/**', 'docker/**', 'deploy/**', 'infra/**', '**/*.yml', '**/*.yaml'],
|
|
423
|
-
testing: ['**/*.test.*', '**/*.spec.*', 'tests/**', '__tests__/**', 'e2e/**'],
|
|
424
|
-
docs: ['docs/**', '**/*.md', '**/*.mdx'],
|
|
425
|
-
uxui: ['src/components/**', 'src/styles/**', '**/*.css'],
|
|
426
|
-
general: ['**/*.ts', '**/*.js'],
|
|
427
|
-
}
|
|
428
|
-
return patterns[domain] || patterns.general
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
// =============================================================================
|
|
432
|
-
// Main Classifier
|
|
433
|
-
// =============================================================================
|
|
434
|
-
|
|
435
|
-
export class DomainClassifier {
|
|
436
|
-
/**
|
|
437
|
-
* Classify a task description into a domain.
|
|
438
|
-
*
|
|
439
|
-
* Fallback chain:
|
|
440
|
-
* 1. Cache lookup (1hr TTL)
|
|
441
|
-
* 2. Confirmed patterns (from completed tasks)
|
|
442
|
-
* 3. LLM call (Claude haiku)
|
|
443
|
-
* 4. Improved heuristic (word-boundary matching)
|
|
444
|
-
*/
|
|
445
|
-
async classify(
|
|
446
|
-
description: string,
|
|
447
|
-
projectId: string,
|
|
448
|
-
globalPath: string,
|
|
449
|
-
context: ProjectContext
|
|
450
|
-
): Promise<{
|
|
451
|
-
classification: TaskClassification
|
|
452
|
-
source: 'cache' | 'history' | 'llm' | 'heuristic'
|
|
453
|
-
}> {
|
|
454
|
-
const hash = hashDescription(description)
|
|
455
|
-
const cache = await loadCache(globalPath)
|
|
456
|
-
|
|
457
|
-
// 1. Cache lookup
|
|
458
|
-
const cached = lookupCache(cache, hash, projectId)
|
|
459
|
-
if (cached) {
|
|
460
|
-
return { classification: cached, source: 'cache' }
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
// 2. Confirmed patterns
|
|
464
|
-
const pattern = lookupPatterns(cache, hash)
|
|
465
|
-
if (pattern) {
|
|
466
|
-
return { classification: pattern, source: 'history' }
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
// 3. LLM call
|
|
470
|
-
const llmResult = await classifyWithLLM(description, context)
|
|
471
|
-
if (llmResult) {
|
|
472
|
-
// Cache the LLM result
|
|
473
|
-
cache.entries[hash] = {
|
|
474
|
-
classification: llmResult,
|
|
475
|
-
classifiedAt: new Date().toISOString(),
|
|
476
|
-
source: 'llm',
|
|
477
|
-
descriptionHash: hash,
|
|
478
|
-
projectId,
|
|
479
|
-
}
|
|
480
|
-
await saveCache(globalPath, cache)
|
|
481
|
-
return { classification: llmResult, source: 'llm' }
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
// 4. Heuristic fallback
|
|
485
|
-
const heuristicResult = classifyWithHeuristic(description, context)
|
|
486
|
-
// Cache heuristic results too
|
|
487
|
-
cache.entries[hash] = {
|
|
488
|
-
classification: heuristicResult,
|
|
489
|
-
classifiedAt: new Date().toISOString(),
|
|
490
|
-
source: 'heuristic',
|
|
491
|
-
descriptionHash: hash,
|
|
492
|
-
projectId,
|
|
493
|
-
}
|
|
494
|
-
await saveCache(globalPath, cache)
|
|
495
|
-
return { classification: heuristicResult, source: 'heuristic' }
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
/**
|
|
499
|
-
* Persist a classification as a confirmed pattern after successful task completion.
|
|
500
|
-
*/
|
|
501
|
-
async confirmClassification(
|
|
502
|
-
description: string,
|
|
503
|
-
classification: TaskClassification,
|
|
504
|
-
globalPath: string
|
|
505
|
-
): Promise<void> {
|
|
506
|
-
const hash = hashDescription(description)
|
|
507
|
-
const cache = await loadCache(globalPath)
|
|
508
|
-
|
|
509
|
-
// Check if already confirmed
|
|
510
|
-
if (cache.confirmedPatterns.some((p) => p.descriptionHash === hash)) return
|
|
511
|
-
|
|
512
|
-
cache.confirmedPatterns.push({
|
|
513
|
-
descriptionHash: hash,
|
|
514
|
-
classification,
|
|
515
|
-
confirmedAt: new Date().toISOString(),
|
|
516
|
-
taskDescription: description,
|
|
517
|
-
})
|
|
518
|
-
await saveCache(globalPath, cache)
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
// Singleton
|
|
523
|
-
const domainClassifier = new DomainClassifier()
|
|
524
|
-
export default domainClassifier
|
|
525
|
-
export { hashDescription, classifyWithHeuristic, DOMAIN_PATTERNS }
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Environment Block Generator
|
|
3
|
-
*
|
|
4
|
-
* Generates a structured <env> block for prompt injection.
|
|
5
|
-
* Provides the LLM with structured environment context (project, git, platform,
|
|
6
|
-
* runtime, model) so it knows its operating environment before processing tasks.
|
|
7
|
-
*
|
|
8
|
-
* Research shows placing environment context early in prompts (position 2, after identity)
|
|
9
|
-
* significantly improves grounding and reduces hallucinations.
|
|
10
|
-
*
|
|
11
|
-
* @module agentic/environment-block
|
|
12
|
-
* @see PRJ-301
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
import os from 'node:os'
|
|
16
|
-
import { z } from 'zod'
|
|
17
|
-
|
|
18
|
-
// =============================================================================
|
|
19
|
-
// Schema
|
|
20
|
-
// =============================================================================
|
|
21
|
-
|
|
22
|
-
export const EnvironmentBlockInputSchema = z.object({
|
|
23
|
-
/** Project display name */
|
|
24
|
-
projectName: z.string(),
|
|
25
|
-
/** Absolute path to project root */
|
|
26
|
-
projectPath: z.string(),
|
|
27
|
-
/** Whether the project is a git repository */
|
|
28
|
-
isGitRepo: z.boolean().default(true),
|
|
29
|
-
/** Current git branch name */
|
|
30
|
-
gitBranch: z.string().optional(),
|
|
31
|
-
/** Operating system platform (auto-detected if not provided) */
|
|
32
|
-
platform: z.string().optional(),
|
|
33
|
-
/** JavaScript runtime (auto-detected if not provided) */
|
|
34
|
-
runtime: z.string().optional(),
|
|
35
|
-
/** Current date in ISO format (auto-generated if not provided) */
|
|
36
|
-
date: z.string().optional(),
|
|
37
|
-
/** AI model identifier (e.g., 'opus', 'sonnet', '2.5-pro') */
|
|
38
|
-
model: z.string().optional(),
|
|
39
|
-
/** AI provider name (e.g., 'claude', 'gemini', 'cursor') */
|
|
40
|
-
provider: z.string().optional(),
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
export type EnvironmentBlockInput = z.input<typeof EnvironmentBlockInputSchema>
|
|
44
|
-
|
|
45
|
-
// =============================================================================
|
|
46
|
-
// Runtime Detection
|
|
47
|
-
// =============================================================================
|
|
48
|
-
|
|
49
|
-
/** Detect the current JavaScript runtime */
|
|
50
|
-
function detectRuntime(): string {
|
|
51
|
-
if (typeof globalThis !== 'undefined' && 'Bun' in globalThis) {
|
|
52
|
-
return 'bun'
|
|
53
|
-
}
|
|
54
|
-
return 'node'
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/** Normalize platform name for readability */
|
|
58
|
-
function normalizePlatform(platform: string): string {
|
|
59
|
-
const platformMap: Record<string, string> = {
|
|
60
|
-
darwin: 'macOS',
|
|
61
|
-
linux: 'Linux',
|
|
62
|
-
win32: 'Windows',
|
|
63
|
-
freebsd: 'FreeBSD',
|
|
64
|
-
}
|
|
65
|
-
return platformMap[platform] ?? platform
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// =============================================================================
|
|
69
|
-
// Generator
|
|
70
|
-
// =============================================================================
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Build a structured environment block for prompt injection.
|
|
74
|
-
*
|
|
75
|
-
* Returns an XML-style `<env>` block containing project metadata,
|
|
76
|
-
* git state, platform info, and AI model/provider details.
|
|
77
|
-
*
|
|
78
|
-
* Fields with undefined/null values are omitted from output.
|
|
79
|
-
*/
|
|
80
|
-
export function buildEnvironmentBlock(input: EnvironmentBlockInput): string {
|
|
81
|
-
const platform = input.platform ?? os.platform()
|
|
82
|
-
const runtime = input.runtime ?? detectRuntime()
|
|
83
|
-
const date = input.date ?? new Date().toISOString().split('T')[0]
|
|
84
|
-
|
|
85
|
-
const fields: [string, string | undefined][] = [
|
|
86
|
-
['project', input.projectName],
|
|
87
|
-
['path', input.projectPath],
|
|
88
|
-
['git', input.isGitRepo ? 'true' : 'false'],
|
|
89
|
-
['branch', input.gitBranch],
|
|
90
|
-
['platform', normalizePlatform(platform)],
|
|
91
|
-
['runtime', runtime],
|
|
92
|
-
['date', date],
|
|
93
|
-
['model', input.model],
|
|
94
|
-
['provider', input.provider],
|
|
95
|
-
]
|
|
96
|
-
|
|
97
|
-
const lines = fields
|
|
98
|
-
.filter(([, value]) => value !== undefined)
|
|
99
|
-
.map(([key, value]) => `${key}: ${value}`)
|
|
100
|
-
|
|
101
|
-
return `<env>\n${lines.join('\n')}\n</env>`
|
|
102
|
-
}
|