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,448 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* FileCategorizer - LLM-based file categorization for Smart Context Selection
|
|
3
|
-
*
|
|
4
|
-
* Two-phase process:
|
|
5
|
-
* 1. DISCOVER DOMAINS: LLM analyzes project structure to identify functional domains
|
|
6
|
-
* 2. CATEGORIZE FILES: LLM assigns files to discovered domains
|
|
7
|
-
*
|
|
8
|
-
* Features:
|
|
9
|
-
* - Dynamic domain discovery (no hardcoded domains)
|
|
10
|
-
* - Batch processing (20 files per LLM call)
|
|
11
|
-
* - Heuristic fallback when LLM unavailable
|
|
12
|
-
* - Caching for efficiency
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
import path from 'node:path'
|
|
16
|
-
import {
|
|
17
|
-
type CategoriesCache,
|
|
18
|
-
type DiscoveredDomains,
|
|
19
|
-
type DomainDefinition,
|
|
20
|
-
type FileCategory,
|
|
21
|
-
INDEX_VERSION,
|
|
22
|
-
indexStorage,
|
|
23
|
-
type ScoredFile,
|
|
24
|
-
} from '../storage/index-storage'
|
|
25
|
-
import { getTimestamp } from '../utils/date-helper'
|
|
26
|
-
|
|
27
|
-
// ============================================================================
|
|
28
|
-
// TYPES
|
|
29
|
-
// ============================================================================
|
|
30
|
-
|
|
31
|
-
export interface CategorizationResult {
|
|
32
|
-
domains: DomainDefinition[]
|
|
33
|
-
categories: FileCategory[]
|
|
34
|
-
metrics: {
|
|
35
|
-
totalFiles: number
|
|
36
|
-
categorizedFiles: number
|
|
37
|
-
domainsDiscovered: number
|
|
38
|
-
llmCalls: number
|
|
39
|
-
usedHeuristics: boolean
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export interface CategorizationOptions {
|
|
44
|
-
batchSize?: number // Files per LLM call (default: 20)
|
|
45
|
-
maxDomains?: number // Max domains to discover (default: 15)
|
|
46
|
-
useLLM?: boolean // Use LLM or heuristics only (default: true)
|
|
47
|
-
projectId?: string // For caching
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// ============================================================================
|
|
51
|
-
// HEURISTIC PATTERNS
|
|
52
|
-
// ============================================================================
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Fallback heuristic patterns for when LLM is unavailable
|
|
56
|
-
* Maps directory/filename patterns to domain names
|
|
57
|
-
*/
|
|
58
|
-
const HEURISTIC_PATTERNS: { pattern: RegExp; domain: string }[] = [
|
|
59
|
-
// Payment-related
|
|
60
|
-
{ pattern: /\b(payment|stripe|billing|checkout|invoice)/i, domain: 'payments' },
|
|
61
|
-
|
|
62
|
-
// User/Auth
|
|
63
|
-
{ pattern: /\b(auth|login|signup|user|session|password|oauth)/i, domain: 'auth' },
|
|
64
|
-
|
|
65
|
-
// API
|
|
66
|
-
{ pattern: /\b(api|endpoint|route|controller)/i, domain: 'api' },
|
|
67
|
-
|
|
68
|
-
// Database
|
|
69
|
-
{ pattern: /\b(model|schema|migration|database|db|prisma|drizzle)/i, domain: 'database' },
|
|
70
|
-
|
|
71
|
-
// Frontend
|
|
72
|
-
{ pattern: /\b(component|page|view|layout|ui|button|form|modal)/i, domain: 'frontend' },
|
|
73
|
-
|
|
74
|
-
// Testing
|
|
75
|
-
{ pattern: /\b(test|spec|__tests__|e2e|cypress)/i, domain: 'testing' },
|
|
76
|
-
|
|
77
|
-
// Configuration
|
|
78
|
-
{ pattern: /\b(config|setting|env)/i, domain: 'config' },
|
|
79
|
-
|
|
80
|
-
// Utilities
|
|
81
|
-
{ pattern: /\b(util|helper|lib|common|shared)/i, domain: 'utilities' },
|
|
82
|
-
|
|
83
|
-
// Services/Business Logic
|
|
84
|
-
{ pattern: /\b(service|handler|processor|worker)/i, domain: 'services' },
|
|
85
|
-
|
|
86
|
-
// Types/Interfaces
|
|
87
|
-
{ pattern: /\b(type|interface|dto)/i, domain: 'types' },
|
|
88
|
-
]
|
|
89
|
-
|
|
90
|
-
// ============================================================================
|
|
91
|
-
// FILE CATEGORIZER CLASS
|
|
92
|
-
// ============================================================================
|
|
93
|
-
|
|
94
|
-
export class FileCategorizer {
|
|
95
|
-
private batchSize: number
|
|
96
|
-
private maxDomains: number
|
|
97
|
-
|
|
98
|
-
constructor(options: CategorizationOptions = {}) {
|
|
99
|
-
this.batchSize = options.batchSize || 20
|
|
100
|
-
this.maxDomains = options.maxDomains || 15
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// ==========================================================================
|
|
104
|
-
// MAIN METHODS
|
|
105
|
-
// ==========================================================================
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Full analysis: discover domains + categorize files
|
|
109
|
-
*/
|
|
110
|
-
async analyzeProject(
|
|
111
|
-
projectPath: string,
|
|
112
|
-
files: ScoredFile[],
|
|
113
|
-
options: CategorizationOptions = {}
|
|
114
|
-
): Promise<CategorizationResult> {
|
|
115
|
-
const useLLM = options.useLLM !== false
|
|
116
|
-
|
|
117
|
-
// Phase 1: Discover domains
|
|
118
|
-
const domains = useLLM
|
|
119
|
-
? await this.discoverDomainsWithLLM(projectPath, files)
|
|
120
|
-
: this.discoverDomainsHeuristic(files)
|
|
121
|
-
|
|
122
|
-
// Phase 2: Categorize files
|
|
123
|
-
const categories = useLLM
|
|
124
|
-
? await this.categorizeFilesWithLLM(files, domains)
|
|
125
|
-
: this.categorizeFilesHeuristic(files, domains)
|
|
126
|
-
|
|
127
|
-
// Update domain file counts
|
|
128
|
-
for (const domain of domains) {
|
|
129
|
-
domain.fileCount = categories.filter((c) => c.primaryDomain === domain.name).length
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// Save to cache if projectId provided
|
|
133
|
-
if (options.projectId) {
|
|
134
|
-
await this.saveToCache(options.projectId, domains, categories)
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
return {
|
|
138
|
-
domains,
|
|
139
|
-
categories,
|
|
140
|
-
metrics: {
|
|
141
|
-
totalFiles: files.length,
|
|
142
|
-
categorizedFiles: categories.length,
|
|
143
|
-
domainsDiscovered: domains.length,
|
|
144
|
-
llmCalls: useLLM ? Math.ceil(files.length / this.batchSize) + 1 : 0,
|
|
145
|
-
usedHeuristics: !useLLM,
|
|
146
|
-
},
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* Discover domains from project structure (LLM)
|
|
152
|
-
*/
|
|
153
|
-
async discoverDomainsWithLLM(
|
|
154
|
-
_projectPath: string,
|
|
155
|
-
files: ScoredFile[]
|
|
156
|
-
): Promise<DomainDefinition[]> {
|
|
157
|
-
// For now, fall back to heuristics
|
|
158
|
-
// TODO: Implement LLM call when LLM service is available
|
|
159
|
-
// The prompt would analyze directory structure and file names
|
|
160
|
-
// to identify functional domains unique to this project
|
|
161
|
-
return this.discoverDomainsHeuristic(files)
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* Categorize files using discovered domains (LLM)
|
|
166
|
-
*/
|
|
167
|
-
async categorizeFilesWithLLM(
|
|
168
|
-
files: ScoredFile[],
|
|
169
|
-
domains: DomainDefinition[]
|
|
170
|
-
): Promise<FileCategory[]> {
|
|
171
|
-
// For now, fall back to heuristics
|
|
172
|
-
// TODO: Implement LLM batch processing when LLM service is available
|
|
173
|
-
// The prompt would ask LLM to categorize batches of files using
|
|
174
|
-
// the discovered domain definitions
|
|
175
|
-
return this.categorizeFilesHeuristic(files, domains)
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
// ==========================================================================
|
|
179
|
-
// HEURISTIC METHODS (Fallback)
|
|
180
|
-
// ==========================================================================
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* Discover domains using heuristics (fallback)
|
|
184
|
-
*/
|
|
185
|
-
discoverDomainsHeuristic(files: ScoredFile[]): DomainDefinition[] {
|
|
186
|
-
const domainCounts = new Map<string, number>()
|
|
187
|
-
const domainPatterns = new Map<string, Set<string>>()
|
|
188
|
-
|
|
189
|
-
// Count files matching each heuristic pattern
|
|
190
|
-
for (const file of files) {
|
|
191
|
-
const filePath = file.path.toLowerCase()
|
|
192
|
-
for (const { pattern, domain } of HEURISTIC_PATTERNS) {
|
|
193
|
-
if (pattern.test(filePath)) {
|
|
194
|
-
domainCounts.set(domain, (domainCounts.get(domain) || 0) + 1)
|
|
195
|
-
if (!domainPatterns.has(domain)) {
|
|
196
|
-
domainPatterns.set(domain, new Set())
|
|
197
|
-
}
|
|
198
|
-
// Extract the matched directory as a pattern
|
|
199
|
-
const dir = path.dirname(file.path)
|
|
200
|
-
domainPatterns.get(domain)!.add(`**/${path.basename(dir)}/**`)
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
// Also detect domains from common directory names
|
|
206
|
-
const dirDomains = this.extractDirectoryDomains(files)
|
|
207
|
-
for (const [domain, count] of dirDomains) {
|
|
208
|
-
domainCounts.set(domain, (domainCounts.get(domain) || 0) + count)
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
// Build domain definitions for domains with at least 2 files
|
|
212
|
-
const domains: DomainDefinition[] = []
|
|
213
|
-
for (const [name, count] of domainCounts) {
|
|
214
|
-
if (count >= 2) {
|
|
215
|
-
const heuristic = HEURISTIC_PATTERNS.find((h) => h.domain === name)
|
|
216
|
-
domains.push({
|
|
217
|
-
name,
|
|
218
|
-
description: `Files related to ${name}`,
|
|
219
|
-
keywords: heuristic ? [name] : [name],
|
|
220
|
-
filePatterns: Array.from(domainPatterns.get(name) || []),
|
|
221
|
-
fileCount: count,
|
|
222
|
-
})
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
// Sort by file count (most files first) and limit
|
|
227
|
-
return domains.sort((a, b) => b.fileCount - a.fileCount).slice(0, this.maxDomains)
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
/**
|
|
231
|
-
* Extract domains from directory structure
|
|
232
|
-
*/
|
|
233
|
-
private extractDirectoryDomains(files: ScoredFile[]): Map<string, number> {
|
|
234
|
-
const dirCounts = new Map<string, number>()
|
|
235
|
-
|
|
236
|
-
for (const file of files) {
|
|
237
|
-
const parts = file.path.split('/')
|
|
238
|
-
// Look at immediate parent directories
|
|
239
|
-
for (const part of parts.slice(0, -1)) {
|
|
240
|
-
const normalizedDir = part.toLowerCase()
|
|
241
|
-
// Skip generic directories
|
|
242
|
-
if (['src', 'lib', 'app', 'core', 'dist', 'build'].includes(normalizedDir)) {
|
|
243
|
-
continue
|
|
244
|
-
}
|
|
245
|
-
// Count meaningful directory names
|
|
246
|
-
if (normalizedDir.length > 2 && !normalizedDir.startsWith('.')) {
|
|
247
|
-
dirCounts.set(normalizedDir, (dirCounts.get(normalizedDir) || 0) + 1)
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
return dirCounts
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
/**
|
|
256
|
-
* Categorize files using heuristics (fallback)
|
|
257
|
-
*/
|
|
258
|
-
categorizeFilesHeuristic(files: ScoredFile[], domains: DomainDefinition[]): FileCategory[] {
|
|
259
|
-
const categories: FileCategory[] = []
|
|
260
|
-
const now = getTimestamp()
|
|
261
|
-
|
|
262
|
-
for (const file of files) {
|
|
263
|
-
const matchedDomains: { domain: string; score: number }[] = []
|
|
264
|
-
const filePath = file.path.toLowerCase()
|
|
265
|
-
|
|
266
|
-
// Check against each domain's keywords and patterns
|
|
267
|
-
for (const domain of domains) {
|
|
268
|
-
let score = 0
|
|
269
|
-
|
|
270
|
-
// Check keywords
|
|
271
|
-
for (const keyword of domain.keywords) {
|
|
272
|
-
if (filePath.includes(keyword.toLowerCase())) {
|
|
273
|
-
score += 1
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
// Check heuristic patterns
|
|
278
|
-
for (const { pattern, domain: patternDomain } of HEURISTIC_PATTERNS) {
|
|
279
|
-
if (patternDomain === domain.name && pattern.test(filePath)) {
|
|
280
|
-
score += 2
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
// Check directory patterns
|
|
285
|
-
for (const pattern of domain.filePatterns) {
|
|
286
|
-
const patternBase = pattern.replace(/\*\*/g, '').replace(/\//g, '')
|
|
287
|
-
if (filePath.includes(patternBase.toLowerCase())) {
|
|
288
|
-
score += 1
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
if (score > 0) {
|
|
293
|
-
matchedDomains.push({ domain: domain.name, score })
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
// Sort by score and take top matches
|
|
298
|
-
matchedDomains.sort((a, b) => b.score - a.score)
|
|
299
|
-
|
|
300
|
-
const fileCategories =
|
|
301
|
-
matchedDomains.length > 0 ? matchedDomains.slice(0, 3).map((m) => m.domain) : ['general']
|
|
302
|
-
|
|
303
|
-
const primaryDomain = fileCategories[0]
|
|
304
|
-
const confidence = matchedDomains.length > 0 ? Math.min(1, matchedDomains[0].score / 5) : 0.1
|
|
305
|
-
|
|
306
|
-
categories.push({
|
|
307
|
-
path: file.path,
|
|
308
|
-
categories: fileCategories,
|
|
309
|
-
primaryDomain,
|
|
310
|
-
confidence,
|
|
311
|
-
categorizedAt: now,
|
|
312
|
-
method: 'heuristic',
|
|
313
|
-
})
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
return categories
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
// ==========================================================================
|
|
320
|
-
// CACHING
|
|
321
|
-
// ==========================================================================
|
|
322
|
-
|
|
323
|
-
/**
|
|
324
|
-
* Save domains and categories to cache
|
|
325
|
-
*/
|
|
326
|
-
async saveToCache(
|
|
327
|
-
projectId: string,
|
|
328
|
-
domains: DomainDefinition[],
|
|
329
|
-
categories: FileCategory[]
|
|
330
|
-
): Promise<void> {
|
|
331
|
-
const now = getTimestamp()
|
|
332
|
-
|
|
333
|
-
// Save domains
|
|
334
|
-
const domainsData: DiscoveredDomains = {
|
|
335
|
-
version: INDEX_VERSION,
|
|
336
|
-
projectId,
|
|
337
|
-
domains,
|
|
338
|
-
discoveredAt: now,
|
|
339
|
-
}
|
|
340
|
-
await indexStorage.writeDomains(projectId, domainsData)
|
|
341
|
-
|
|
342
|
-
// Build domain index (domain -> file paths)
|
|
343
|
-
const domainIndex: Record<string, string[]> = {}
|
|
344
|
-
for (const cat of categories) {
|
|
345
|
-
for (const domain of cat.categories) {
|
|
346
|
-
if (!domainIndex[domain]) {
|
|
347
|
-
domainIndex[domain] = []
|
|
348
|
-
}
|
|
349
|
-
domainIndex[domain].push(cat.path)
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
// Save categories
|
|
354
|
-
const cacheData: CategoriesCache = {
|
|
355
|
-
version: INDEX_VERSION,
|
|
356
|
-
lastUpdate: now,
|
|
357
|
-
fileCategories: categories,
|
|
358
|
-
domainIndex,
|
|
359
|
-
}
|
|
360
|
-
await indexStorage.writeCategories(projectId, cacheData)
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
/**
|
|
364
|
-
* Load cached categorization
|
|
365
|
-
*/
|
|
366
|
-
async loadFromCache(projectId: string): Promise<CategorizationResult | null> {
|
|
367
|
-
const [domainsData, cacheData] = await Promise.all([
|
|
368
|
-
indexStorage.readDomains(projectId),
|
|
369
|
-
indexStorage.readCategories(projectId),
|
|
370
|
-
])
|
|
371
|
-
|
|
372
|
-
if (!domainsData || !cacheData) {
|
|
373
|
-
return null
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
return {
|
|
377
|
-
domains: domainsData.domains,
|
|
378
|
-
categories: cacheData.fileCategories,
|
|
379
|
-
metrics: {
|
|
380
|
-
totalFiles: cacheData.fileCategories.length,
|
|
381
|
-
categorizedFiles: cacheData.fileCategories.length,
|
|
382
|
-
domainsDiscovered: domainsData.domains.length,
|
|
383
|
-
llmCalls: 0,
|
|
384
|
-
usedHeuristics: cacheData.fileCategories[0]?.method === 'heuristic',
|
|
385
|
-
},
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
/**
|
|
390
|
-
* Update categories for specific files (incremental)
|
|
391
|
-
*/
|
|
392
|
-
async updateFilesCategories(
|
|
393
|
-
projectId: string,
|
|
394
|
-
files: ScoredFile[],
|
|
395
|
-
options: CategorizationOptions = {}
|
|
396
|
-
): Promise<FileCategory[]> {
|
|
397
|
-
// Load existing domains
|
|
398
|
-
const domainsData = await indexStorage.readDomains(projectId)
|
|
399
|
-
if (!domainsData) {
|
|
400
|
-
// No domains yet, need full analysis
|
|
401
|
-
const result = await this.analyzeProject('', files, { ...options, projectId })
|
|
402
|
-
return result.categories
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
// Categorize just the new/changed files
|
|
406
|
-
const newCategories =
|
|
407
|
-
options.useLLM !== false
|
|
408
|
-
? await this.categorizeFilesWithLLM(files, domainsData.domains)
|
|
409
|
-
: this.categorizeFilesHeuristic(files, domainsData.domains)
|
|
410
|
-
|
|
411
|
-
// Load existing cache and merge
|
|
412
|
-
const existingCache = await indexStorage.readCategories(projectId)
|
|
413
|
-
if (existingCache) {
|
|
414
|
-
// Remove old entries for updated files
|
|
415
|
-
const updatedPaths = new Set(files.map((f) => f.path))
|
|
416
|
-
const existingCategories = existingCache.fileCategories.filter(
|
|
417
|
-
(c) => !updatedPaths.has(c.path)
|
|
418
|
-
)
|
|
419
|
-
|
|
420
|
-
// Merge and save
|
|
421
|
-
const allCategories = [...existingCategories, ...newCategories]
|
|
422
|
-
|
|
423
|
-
// Rebuild domain index
|
|
424
|
-
const domainIndex: Record<string, string[]> = {}
|
|
425
|
-
for (const cat of allCategories) {
|
|
426
|
-
for (const domain of cat.categories) {
|
|
427
|
-
if (!domainIndex[domain]) {
|
|
428
|
-
domainIndex[domain] = []
|
|
429
|
-
}
|
|
430
|
-
domainIndex[domain].push(cat.path)
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
const cacheData: CategoriesCache = {
|
|
435
|
-
version: INDEX_VERSION,
|
|
436
|
-
lastUpdate: getTimestamp(),
|
|
437
|
-
fileCategories: allCategories,
|
|
438
|
-
domainIndex,
|
|
439
|
-
}
|
|
440
|
-
await indexStorage.writeCategories(projectId, cacheData)
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
return newCategories
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
export const fileCategorizer = new FileCategorizer()
|
|
448
|
-
export default FileCategorizer
|
|
@@ -1,270 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* FileScorer - Calculates relevance scores for files
|
|
3
|
-
*
|
|
4
|
-
* Scoring factors:
|
|
5
|
-
* - recency: Modified recently? (0-20)
|
|
6
|
-
* - centrality: Imported by many files? (0-25)
|
|
7
|
-
* - configRelevance: Is config file? (0-20)
|
|
8
|
-
* - nameRelevance: Name indicates importance? (0-15)
|
|
9
|
-
* - sizeOptimal: Useful size (not too large)? (0-10)
|
|
10
|
-
* - gitActivity: Recent commits? (0-10)
|
|
11
|
-
*
|
|
12
|
-
* Total score: 0-100
|
|
13
|
-
* Files with score > 30 are considered relevant
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
import path from 'node:path'
|
|
17
|
-
|
|
18
|
-
// ============================================================================
|
|
19
|
-
// TYPES
|
|
20
|
-
// ============================================================================
|
|
21
|
-
|
|
22
|
-
export interface FileScore {
|
|
23
|
-
path: string
|
|
24
|
-
score: number
|
|
25
|
-
factors: {
|
|
26
|
-
recency: number // 0-20
|
|
27
|
-
centrality: number // 0-25
|
|
28
|
-
configRelevance: number // 0-20
|
|
29
|
-
nameRelevance: number // 0-15
|
|
30
|
-
sizeOptimal: number // 0-10
|
|
31
|
-
gitActivity: number // 0-10
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export interface FileStats {
|
|
36
|
-
path: string
|
|
37
|
-
size: number // bytes
|
|
38
|
-
mtime: Date // modification time
|
|
39
|
-
lines?: number // line count
|
|
40
|
-
imports?: string[] // files this imports
|
|
41
|
-
importedBy?: string[] // files that import this
|
|
42
|
-
recentCommits?: number // commits in last 30 days
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export interface ScoringContext {
|
|
46
|
-
allFiles: Map<string, FileStats>
|
|
47
|
-
configFiles: Set<string>
|
|
48
|
-
maxFileSize: number
|
|
49
|
-
maxRecentCommits: number
|
|
50
|
-
now: Date
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// ============================================================================
|
|
54
|
-
// CONSTANTS
|
|
55
|
-
// ============================================================================
|
|
56
|
-
|
|
57
|
-
export const RELEVANCE_THRESHOLD = 30
|
|
58
|
-
|
|
59
|
-
// Config file patterns (high importance)
|
|
60
|
-
const CONFIG_PATTERNS = [
|
|
61
|
-
/^package\.json$/,
|
|
62
|
-
/^tsconfig.*\.json$/,
|
|
63
|
-
/^\.env(\..*)?$/,
|
|
64
|
-
/^\.eslintrc.*$/,
|
|
65
|
-
/^\.prettierrc.*$/,
|
|
66
|
-
/^vite\.config\.\w+$/,
|
|
67
|
-
/^next\.config\.\w+$/,
|
|
68
|
-
/^webpack\.config\.\w+$/,
|
|
69
|
-
/^rollup\.config\.\w+$/,
|
|
70
|
-
/^jest\.config\.\w+$/,
|
|
71
|
-
/^vitest\.config\.\w+$/,
|
|
72
|
-
/^tailwind\.config\.\w+$/,
|
|
73
|
-
/^postcss\.config\.\w+$/,
|
|
74
|
-
/^Cargo\.toml$/,
|
|
75
|
-
/^go\.mod$/,
|
|
76
|
-
/^pyproject\.toml$/,
|
|
77
|
-
/^requirements\.txt$/,
|
|
78
|
-
/^Dockerfile$/,
|
|
79
|
-
/^docker-compose\.ya?ml$/,
|
|
80
|
-
/^\.github\/workflows\/.*\.ya?ml$/,
|
|
81
|
-
]
|
|
82
|
-
|
|
83
|
-
// Important filename patterns
|
|
84
|
-
const IMPORTANT_NAME_PATTERNS = [
|
|
85
|
-
/^index\.\w+$/, // Entry points
|
|
86
|
-
/^main\.\w+$/, // Main files
|
|
87
|
-
/^app\.\w+$/, // App files
|
|
88
|
-
/^server\.\w+$/, // Server files
|
|
89
|
-
/^router\.\w+$/, // Router files
|
|
90
|
-
/^routes\.\w+$/, // Routes
|
|
91
|
-
/^api\.\w+$/, // API files
|
|
92
|
-
/^schema\.\w+$/, // Schema files
|
|
93
|
-
/^types?\.\w+$/, // Type definitions
|
|
94
|
-
/^constants?\.\w+$/, // Constants
|
|
95
|
-
/^config\.\w+$/, // Config files
|
|
96
|
-
/^utils?\.\w+$/, // Utilities
|
|
97
|
-
/^helpers?\.\w+$/, // Helpers
|
|
98
|
-
/README\.md$/i, // Documentation
|
|
99
|
-
/CHANGELOG\.md$/i, // Changelog
|
|
100
|
-
]
|
|
101
|
-
|
|
102
|
-
// ============================================================================
|
|
103
|
-
// FILE SCORER
|
|
104
|
-
// ============================================================================
|
|
105
|
-
|
|
106
|
-
export class FileScorer {
|
|
107
|
-
/**
|
|
108
|
-
* Score a single file
|
|
109
|
-
*/
|
|
110
|
-
scoreFile(stats: FileStats, context: ScoringContext): FileScore {
|
|
111
|
-
const factors = {
|
|
112
|
-
recency: this.calculateRecency(stats, context),
|
|
113
|
-
centrality: this.calculateCentrality(stats, context),
|
|
114
|
-
configRelevance: this.calculateConfigRelevance(stats),
|
|
115
|
-
nameRelevance: this.calculateNameRelevance(stats),
|
|
116
|
-
sizeOptimal: this.calculateSizeOptimal(stats, context),
|
|
117
|
-
gitActivity: this.calculateGitActivity(stats, context),
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
const score = Object.values(factors).reduce((sum, v) => sum + v, 0)
|
|
121
|
-
|
|
122
|
-
return {
|
|
123
|
-
path: stats.path,
|
|
124
|
-
score: Math.min(100, Math.max(0, score)),
|
|
125
|
-
factors,
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* Score all files and return sorted by score
|
|
131
|
-
*/
|
|
132
|
-
scoreAll(context: ScoringContext): FileScore[] {
|
|
133
|
-
const scores: FileScore[] = []
|
|
134
|
-
|
|
135
|
-
for (const stats of context.allFiles.values()) {
|
|
136
|
-
scores.push(this.scoreFile(stats, context))
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
return scores.sort((a, b) => b.score - a.score)
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Get relevant files (score > threshold)
|
|
144
|
-
*/
|
|
145
|
-
getRelevantFiles(context: ScoringContext, threshold: number = RELEVANCE_THRESHOLD): FileScore[] {
|
|
146
|
-
return this.scoreAll(context).filter((f) => f.score >= threshold)
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
// ==========================================================================
|
|
150
|
-
// FACTOR CALCULATIONS
|
|
151
|
-
// ==========================================================================
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Recency factor (0-20)
|
|
155
|
-
* Files modified recently get higher scores
|
|
156
|
-
*/
|
|
157
|
-
private calculateRecency(stats: FileStats, context: ScoringContext): number {
|
|
158
|
-
const daysSinceModified =
|
|
159
|
-
(context.now.getTime() - stats.mtime.getTime()) / (1000 * 60 * 60 * 24)
|
|
160
|
-
|
|
161
|
-
if (daysSinceModified < 1) return 20 // Today
|
|
162
|
-
if (daysSinceModified < 7) return 15 // This week
|
|
163
|
-
if (daysSinceModified < 30) return 10 // This month
|
|
164
|
-
if (daysSinceModified < 90) return 5 // Last 3 months
|
|
165
|
-
return 0 // Older
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* Centrality factor (0-25)
|
|
170
|
-
* Files imported by many others are more important
|
|
171
|
-
*/
|
|
172
|
-
private calculateCentrality(stats: FileStats, context: ScoringContext): number {
|
|
173
|
-
const importedByCount = stats.importedBy?.length || 0
|
|
174
|
-
const totalFiles = context.allFiles.size
|
|
175
|
-
|
|
176
|
-
if (totalFiles === 0) return 0
|
|
177
|
-
|
|
178
|
-
// Normalize: files imported by 20%+ of codebase get max score
|
|
179
|
-
const ratio = importedByCount / totalFiles
|
|
180
|
-
if (ratio >= 0.2) return 25
|
|
181
|
-
if (ratio >= 0.1) return 20
|
|
182
|
-
if (ratio >= 0.05) return 15
|
|
183
|
-
if (importedByCount >= 5) return 10
|
|
184
|
-
if (importedByCount >= 2) return 5
|
|
185
|
-
return 0
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
/**
|
|
189
|
-
* Config relevance factor (0-20)
|
|
190
|
-
* Config files are always important
|
|
191
|
-
*/
|
|
192
|
-
private calculateConfigRelevance(stats: FileStats): number {
|
|
193
|
-
const filename = path.basename(stats.path)
|
|
194
|
-
|
|
195
|
-
for (const pattern of CONFIG_PATTERNS) {
|
|
196
|
-
if (pattern.test(filename) || pattern.test(stats.path)) {
|
|
197
|
-
return 20
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
return 0
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
/**
|
|
205
|
-
* Name relevance factor (0-15)
|
|
206
|
-
* Certain filenames indicate importance
|
|
207
|
-
*/
|
|
208
|
-
private calculateNameRelevance(stats: FileStats): number {
|
|
209
|
-
const filename = path.basename(stats.path)
|
|
210
|
-
|
|
211
|
-
for (const pattern of IMPORTANT_NAME_PATTERNS) {
|
|
212
|
-
if (pattern.test(filename)) {
|
|
213
|
-
return 15
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
// Directories that suggest importance
|
|
218
|
-
const dir = path.dirname(stats.path)
|
|
219
|
-
if (dir.includes('/api/') || dir.includes('/routes/')) return 10
|
|
220
|
-
if (dir.includes('/components/') && filename.startsWith('index')) return 10
|
|
221
|
-
if (dir.includes('/pages/') || dir.includes('/app/')) return 8
|
|
222
|
-
|
|
223
|
-
return 0
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
/**
|
|
227
|
-
* Size optimal factor (0-10)
|
|
228
|
-
* Files that are neither too small nor too large
|
|
229
|
-
*/
|
|
230
|
-
private calculateSizeOptimal(stats: FileStats, _context: ScoringContext): number {
|
|
231
|
-
const size = stats.size
|
|
232
|
-
|
|
233
|
-
// Too small (likely stub or barrel export)
|
|
234
|
-
if (size < 100) return 2
|
|
235
|
-
|
|
236
|
-
// Optimal range: 500 bytes to 50KB
|
|
237
|
-
if (size >= 500 && size <= 50_000) return 10
|
|
238
|
-
|
|
239
|
-
// Large but not huge (50KB - 200KB)
|
|
240
|
-
if (size > 50_000 && size <= 200_000) return 5
|
|
241
|
-
|
|
242
|
-
// Very large files are less useful as context
|
|
243
|
-
if (size > 200_000) return 0
|
|
244
|
-
|
|
245
|
-
// Small files (100-500 bytes)
|
|
246
|
-
return 5
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
/**
|
|
250
|
-
* Git activity factor (0-10)
|
|
251
|
-
* Files with recent commits are more actively developed
|
|
252
|
-
*/
|
|
253
|
-
private calculateGitActivity(stats: FileStats, context: ScoringContext): number {
|
|
254
|
-
const commits = stats.recentCommits || 0
|
|
255
|
-
|
|
256
|
-
if (context.maxRecentCommits === 0) return 0
|
|
257
|
-
|
|
258
|
-
// Normalize against max
|
|
259
|
-
const ratio = commits / context.maxRecentCommits
|
|
260
|
-
|
|
261
|
-
if (ratio >= 0.5) return 10 // Among most active
|
|
262
|
-
if (ratio >= 0.25) return 7
|
|
263
|
-
if (ratio >= 0.1) return 5
|
|
264
|
-
if (commits > 0) return 2
|
|
265
|
-
return 0
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
export const fileScorer = new FileScorer()
|
|
270
|
-
export default FileScorer
|