prjct-cli 1.22.0 → 1.24.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 +230 -0
- package/bin/prjct +30 -13
- package/dist/bin/prjct-core.mjs +1748 -0
- package/dist/bin/prjct.mjs +17 -36672
- package/dist/cli/linear.mjs +14 -0
- package/dist/daemon/entry.mjs +1429 -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,175 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ContextEstimator - Pre-filter files before building context
|
|
3
|
-
*
|
|
4
|
-
* Estimates which files are needed based on task analysis
|
|
5
|
-
* BEFORE building full context - saves I/O
|
|
6
|
-
*
|
|
7
|
-
* @version 1.0.0
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import { glob } from 'glob'
|
|
11
|
-
import { getErrorMessage } from '../types/fs'
|
|
12
|
-
import log from '../utils/logger'
|
|
13
|
-
|
|
14
|
-
interface TaskAnalysis {
|
|
15
|
-
primaryDomain: string
|
|
16
|
-
projectTechnologies?: ProjectTech
|
|
17
|
-
semantic?: SemanticAnalysis
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
interface ProjectTech {
|
|
21
|
-
extensions?: Record<string, number>
|
|
22
|
-
directories?: string[]
|
|
23
|
-
[key: string]: unknown
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
interface SemanticAnalysis {
|
|
27
|
-
requiresMultipleAgents?: boolean
|
|
28
|
-
agents?: string[]
|
|
29
|
-
[key: string]: unknown
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
interface FilePatterns {
|
|
33
|
-
include: string[]
|
|
34
|
-
extensions: string[]
|
|
35
|
-
exclude: string[]
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
class ContextEstimator {
|
|
39
|
-
/**
|
|
40
|
-
* Estimate which files are needed for a task
|
|
41
|
-
*/
|
|
42
|
-
async estimateFiles(taskAnalysis: TaskAnalysis, projectPath: string): Promise<string[]> {
|
|
43
|
-
const domain = taskAnalysis.primaryDomain
|
|
44
|
-
const projectTech = taskAnalysis.projectTechnologies || {}
|
|
45
|
-
const semantic = taskAnalysis.semantic || {}
|
|
46
|
-
|
|
47
|
-
// Get patterns for this domain
|
|
48
|
-
const patterns = this.getPatternsForDomain(domain, projectTech)
|
|
49
|
-
|
|
50
|
-
// Expand with semantic understanding
|
|
51
|
-
if (semantic.requiresMultipleAgents && semantic.agents) {
|
|
52
|
-
// Multi-agent task - combine patterns
|
|
53
|
-
const allPatterns = semantic.agents.reduce(
|
|
54
|
-
(acc, agentDomain) => {
|
|
55
|
-
const agentPatterns = this.getPatternsForDomain(agentDomain, projectTech)
|
|
56
|
-
return {
|
|
57
|
-
include: [...acc.include, ...agentPatterns.include],
|
|
58
|
-
extensions: [...acc.extensions, ...agentPatterns.extensions],
|
|
59
|
-
}
|
|
60
|
-
},
|
|
61
|
-
{ include: [] as string[], extensions: [] as string[] }
|
|
62
|
-
)
|
|
63
|
-
|
|
64
|
-
patterns.include = [...new Set(allPatterns.include)]
|
|
65
|
-
patterns.extensions = [...new Set(allPatterns.extensions)]
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// Find files matching patterns
|
|
69
|
-
const files = await this.findMatchingFiles(projectPath, patterns)
|
|
70
|
-
|
|
71
|
-
// Limit to reasonable number
|
|
72
|
-
const maxFiles = 200
|
|
73
|
-
return files.slice(0, maxFiles)
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Get file patterns for a domain
|
|
78
|
-
*
|
|
79
|
-
* 100% AGENTIC: Uses REAL project data, not hardcoded patterns.
|
|
80
|
-
* No domain-specific assumptions or language→extension mapping.
|
|
81
|
-
*/
|
|
82
|
-
getPatternsForDomain(_domain: string, projectData: ProjectTech): FilePatterns {
|
|
83
|
-
const patterns: FilePatterns = {
|
|
84
|
-
include: [],
|
|
85
|
-
extensions: [],
|
|
86
|
-
exclude: ['node_modules', 'dist', 'build', '.git', '.next', 'target', 'vendor', 'coverage'],
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// Use REAL extensions from project (if provided in projectData)
|
|
90
|
-
if (projectData?.extensions) {
|
|
91
|
-
// projectData.extensions is {'.js': 45, '.ts': 23, ...}
|
|
92
|
-
patterns.extensions = Object.keys(projectData.extensions)
|
|
93
|
-
.filter((ext) => ext.startsWith('.'))
|
|
94
|
-
.slice(0, 15) // Top 15 extensions
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// Use REAL directories from project (if provided in projectData)
|
|
98
|
-
if (projectData?.directories) {
|
|
99
|
-
patterns.include = projectData.directories.filter((dir) => !patterns.exclude.includes(dir))
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// If no real data available, use minimal universal fallback
|
|
103
|
-
if (patterns.extensions.length === 0) {
|
|
104
|
-
patterns.extensions = ['*'] // All files
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
if (patterns.include.length === 0) {
|
|
108
|
-
patterns.include = ['.'] // Root directory
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// NO domain-specific hardcoding
|
|
112
|
-
// Claude decides what files matter based on actual analysis
|
|
113
|
-
|
|
114
|
-
return patterns
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Find files matching patterns
|
|
119
|
-
*/
|
|
120
|
-
async findMatchingFiles(projectPath: string, patterns: FilePatterns): Promise<string[]> {
|
|
121
|
-
const files: string[] = []
|
|
122
|
-
|
|
123
|
-
try {
|
|
124
|
-
// Build glob patterns
|
|
125
|
-
const globPatterns: string[] = []
|
|
126
|
-
|
|
127
|
-
// Add include patterns
|
|
128
|
-
for (const include of patterns.include) {
|
|
129
|
-
for (const ext of patterns.extensions) {
|
|
130
|
-
globPatterns.push(`${include}/**/*${ext}`)
|
|
131
|
-
globPatterns.push(`**/${include}/**/*${ext}`)
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// Also search root level
|
|
136
|
-
for (const ext of patterns.extensions) {
|
|
137
|
-
globPatterns.push(`*${ext}`)
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// Execute glob searches
|
|
141
|
-
for (const pattern of globPatterns) {
|
|
142
|
-
try {
|
|
143
|
-
const matches = await glob(pattern, {
|
|
144
|
-
cwd: projectPath,
|
|
145
|
-
ignore: patterns.exclude.map((ex) => `**/${ex}/**`),
|
|
146
|
-
nodir: true,
|
|
147
|
-
follow: false,
|
|
148
|
-
})
|
|
149
|
-
|
|
150
|
-
if (Array.isArray(matches)) {
|
|
151
|
-
files.push(...matches)
|
|
152
|
-
}
|
|
153
|
-
} catch (_error) {
|
|
154
|
-
// Skip invalid patterns
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// Remove duplicates and sort
|
|
159
|
-
return [...new Set(files)].sort()
|
|
160
|
-
} catch (error) {
|
|
161
|
-
log.error('Error finding files:', getErrorMessage(error))
|
|
162
|
-
return []
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Estimate context size (number of files)
|
|
168
|
-
*/
|
|
169
|
-
async estimateContextSize(taskAnalysis: TaskAnalysis, projectPath: string): Promise<number> {
|
|
170
|
-
const files = await this.estimateFiles(taskAnalysis, projectPath)
|
|
171
|
-
return files.length
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
export default ContextEstimator
|
package/core/domain/fibonacci.ts
DELETED
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Fibonacci Estimation Module
|
|
3
|
-
*
|
|
4
|
-
* Provides Fibonacci-based story point estimation with
|
|
5
|
-
* points-to-time conversion and historical suggestion.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import outcomeRecorder from '../outcomes/recorder'
|
|
9
|
-
|
|
10
|
-
// =============================================================================
|
|
11
|
-
// Constants
|
|
12
|
-
// =============================================================================
|
|
13
|
-
|
|
14
|
-
/** Valid Fibonacci story points */
|
|
15
|
-
export const FIBONACCI_POINTS = [1, 2, 3, 5, 8, 13, 21] as const
|
|
16
|
-
export type FibonacciPoint = (typeof FIBONACCI_POINTS)[number]
|
|
17
|
-
|
|
18
|
-
/** Default points-to-minutes mapping */
|
|
19
|
-
const DEFAULT_MINUTES_MAP: Record<FibonacciPoint, { min: number; max: number; typical: number }> = {
|
|
20
|
-
1: { min: 5, max: 15, typical: 10 },
|
|
21
|
-
2: { min: 15, max: 30, typical: 20 },
|
|
22
|
-
3: { min: 30, max: 60, typical: 45 },
|
|
23
|
-
5: { min: 60, max: 120, typical: 90 },
|
|
24
|
-
8: { min: 120, max: 240, typical: 180 },
|
|
25
|
-
13: { min: 240, max: 480, typical: 360 },
|
|
26
|
-
21: { min: 480, max: 960, typical: 720 },
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// =============================================================================
|
|
30
|
-
// Validation
|
|
31
|
-
// =============================================================================
|
|
32
|
-
|
|
33
|
-
/** Check if a number is a valid Fibonacci point */
|
|
34
|
-
export const isValidPoint = (n: number): n is FibonacciPoint =>
|
|
35
|
-
FIBONACCI_POINTS.includes(n as FibonacciPoint)
|
|
36
|
-
|
|
37
|
-
// =============================================================================
|
|
38
|
-
// Points-to-Time Conversion
|
|
39
|
-
// =============================================================================
|
|
40
|
-
|
|
41
|
-
/** Get the time range for a given point value */
|
|
42
|
-
export const pointsToMinutes = (
|
|
43
|
-
points: FibonacciPoint
|
|
44
|
-
): { min: number; max: number; typical: number } => {
|
|
45
|
-
return DEFAULT_MINUTES_MAP[points]
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/** Format a minute count as a human-readable duration */
|
|
49
|
-
export const formatMinutes = (minutes: number): string => {
|
|
50
|
-
if (minutes < 60) return `${minutes}m`
|
|
51
|
-
const hours = Math.floor(minutes / 60)
|
|
52
|
-
const mins = minutes % 60
|
|
53
|
-
return mins > 0 ? `${hours}h ${mins}m` : `${hours}h`
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/** Get a human-readable time range for a point value */
|
|
57
|
-
export const pointsToTimeRange = (points: FibonacciPoint): string => {
|
|
58
|
-
const range = pointsToMinutes(points)
|
|
59
|
-
return `${formatMinutes(range.min)}–${formatMinutes(range.max)}`
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// =============================================================================
|
|
63
|
-
// Historical Suggestion
|
|
64
|
-
// =============================================================================
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Suggest a point estimate based on historical outcomes for similar task types.
|
|
68
|
-
* Returns null if not enough data (< 3 outcomes).
|
|
69
|
-
*/
|
|
70
|
-
export const suggestFromHistory = async (
|
|
71
|
-
projectId: string,
|
|
72
|
-
taskType: string
|
|
73
|
-
): Promise<{ points: FibonacciPoint; basedOn: number } | null> => {
|
|
74
|
-
const outcomes = await outcomeRecorder.getAll(projectId)
|
|
75
|
-
|
|
76
|
-
// Filter by task type tag
|
|
77
|
-
const relevant = outcomes.filter((o) => o.tags?.includes(taskType))
|
|
78
|
-
|
|
79
|
-
if (relevant.length < 3) return null
|
|
80
|
-
|
|
81
|
-
// Calculate average actual duration in minutes
|
|
82
|
-
const totalMinutes = relevant.reduce((sum, o) => {
|
|
83
|
-
return sum + parseDuration(o.actualDuration)
|
|
84
|
-
}, 0)
|
|
85
|
-
const avgMinutes = totalMinutes / relevant.length
|
|
86
|
-
|
|
87
|
-
// Find closest Fibonacci point by typical time
|
|
88
|
-
const closest = findClosestPoint(avgMinutes)
|
|
89
|
-
|
|
90
|
-
return { points: closest, basedOn: relevant.length }
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// =============================================================================
|
|
94
|
-
// Helpers
|
|
95
|
-
// =============================================================================
|
|
96
|
-
|
|
97
|
-
/** Find the Fibonacci point whose typical time is closest to the given minutes */
|
|
98
|
-
export const findClosestPoint = (minutes: number): FibonacciPoint => {
|
|
99
|
-
let closest: FibonacciPoint = 1
|
|
100
|
-
let smallestDiff = Number.POSITIVE_INFINITY
|
|
101
|
-
|
|
102
|
-
for (const point of FIBONACCI_POINTS) {
|
|
103
|
-
const diff = Math.abs(DEFAULT_MINUTES_MAP[point].typical - minutes)
|
|
104
|
-
if (diff < smallestDiff) {
|
|
105
|
-
smallestDiff = diff
|
|
106
|
-
closest = point
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
return closest
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/** Parse a duration string like "2h 30m" to minutes */
|
|
114
|
-
const parseDuration = (duration: string): number => {
|
|
115
|
-
let minutes = 0
|
|
116
|
-
|
|
117
|
-
const hourMatch = duration.match(/(\d+)h/)
|
|
118
|
-
if (hourMatch) {
|
|
119
|
-
minutes += Number.parseInt(hourMatch[1], 10) * 60
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
const minMatch = duration.match(/(\d+)m/)
|
|
123
|
-
if (minMatch) {
|
|
124
|
-
minutes += Number.parseInt(minMatch[1], 10)
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
return minutes
|
|
128
|
-
}
|
|
@@ -1,296 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* File Hasher — Fast Content Hashing with SQLite Registry
|
|
3
|
-
*
|
|
4
|
-
* Computes content hashes for all project files and stores them in SQLite.
|
|
5
|
-
* On subsequent syncs, compares current hashes against stored hashes
|
|
6
|
-
* to identify added, modified, and deleted files.
|
|
7
|
-
*
|
|
8
|
-
* Uses Bun.hash (xxHash) for speed — <100ms for 500 files.
|
|
9
|
-
*
|
|
10
|
-
* @module domain/file-hasher
|
|
11
|
-
* @version 1.0.0
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
import fs from 'node:fs/promises'
|
|
15
|
-
import path from 'node:path'
|
|
16
|
-
import prjctDb from '../storage/database'
|
|
17
|
-
|
|
18
|
-
// =============================================================================
|
|
19
|
-
// Types
|
|
20
|
-
// =============================================================================
|
|
21
|
-
|
|
22
|
-
export interface FileHash {
|
|
23
|
-
path: string
|
|
24
|
-
hash: string
|
|
25
|
-
size: number
|
|
26
|
-
mtime: string
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export interface FileDiff {
|
|
30
|
-
added: string[]
|
|
31
|
-
modified: string[]
|
|
32
|
-
deleted: string[]
|
|
33
|
-
unchanged: string[]
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export interface HashRegistry {
|
|
37
|
-
files: Map<string, FileHash>
|
|
38
|
-
builtAt: string
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// =============================================================================
|
|
42
|
-
// Constants
|
|
43
|
-
// =============================================================================
|
|
44
|
-
|
|
45
|
-
const INDEXABLE_EXTENSIONS = new Set([
|
|
46
|
-
'.ts',
|
|
47
|
-
'.tsx',
|
|
48
|
-
'.js',
|
|
49
|
-
'.jsx',
|
|
50
|
-
'.mjs',
|
|
51
|
-
'.cjs',
|
|
52
|
-
'.json',
|
|
53
|
-
'.md',
|
|
54
|
-
'.css',
|
|
55
|
-
'.scss',
|
|
56
|
-
'.html',
|
|
57
|
-
'.vue',
|
|
58
|
-
'.svelte',
|
|
59
|
-
'.py',
|
|
60
|
-
'.go',
|
|
61
|
-
'.rs',
|
|
62
|
-
'.yaml',
|
|
63
|
-
'.yml',
|
|
64
|
-
'.toml',
|
|
65
|
-
])
|
|
66
|
-
|
|
67
|
-
const SKIP_DIRS = new Set([
|
|
68
|
-
'node_modules',
|
|
69
|
-
'.git',
|
|
70
|
-
'dist',
|
|
71
|
-
'build',
|
|
72
|
-
'out',
|
|
73
|
-
'.next',
|
|
74
|
-
'coverage',
|
|
75
|
-
'.cache',
|
|
76
|
-
'.turbo',
|
|
77
|
-
'.vercel',
|
|
78
|
-
'.prjct',
|
|
79
|
-
])
|
|
80
|
-
|
|
81
|
-
// =============================================================================
|
|
82
|
-
// File Discovery
|
|
83
|
-
// =============================================================================
|
|
84
|
-
|
|
85
|
-
async function listProjectFiles(dir: string, projectPath: string): Promise<string[]> {
|
|
86
|
-
const files: string[] = []
|
|
87
|
-
const entries = await fs.readdir(dir, { withFileTypes: true }).catch(() => [])
|
|
88
|
-
|
|
89
|
-
for (const entry of entries) {
|
|
90
|
-
const name = String(entry.name)
|
|
91
|
-
if (SKIP_DIRS.has(name)) continue
|
|
92
|
-
if (name.startsWith('.') && name !== '.env.example') continue
|
|
93
|
-
|
|
94
|
-
const fullPath = path.join(dir, name)
|
|
95
|
-
if (entry.isDirectory()) {
|
|
96
|
-
files.push(...(await listProjectFiles(fullPath, projectPath)))
|
|
97
|
-
} else if (entry.isFile()) {
|
|
98
|
-
const ext = path.extname(name).toLowerCase()
|
|
99
|
-
if (INDEXABLE_EXTENSIONS.has(ext)) {
|
|
100
|
-
files.push(path.relative(projectPath, fullPath))
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
return files
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// =============================================================================
|
|
108
|
-
// Hashing
|
|
109
|
-
// =============================================================================
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Compute a fast hash of file content using Bun.hash (xxHash64).
|
|
113
|
-
* Falls back to a simple checksum if Bun.hash is unavailable.
|
|
114
|
-
*/
|
|
115
|
-
function hashContent(content: string): string {
|
|
116
|
-
// Bun.hash returns a bigint (xxHash64) — extremely fast
|
|
117
|
-
if (typeof Bun !== 'undefined' && Bun.hash) {
|
|
118
|
-
return `xxh64:${Bun.hash(content).toString(36)}`
|
|
119
|
-
}
|
|
120
|
-
// Fallback: simple FNV-1a 32-bit hash (still fast, no crypto overhead)
|
|
121
|
-
let h = 0x811c9dc5
|
|
122
|
-
for (let i = 0; i < content.length; i++) {
|
|
123
|
-
h ^= content.charCodeAt(i)
|
|
124
|
-
h = Math.imul(h, 0x01000193)
|
|
125
|
-
}
|
|
126
|
-
return `fnv1a:${(h >>> 0).toString(36)}`
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* Compute hashes for all project files.
|
|
131
|
-
* Processes files in parallel batches for speed.
|
|
132
|
-
*
|
|
133
|
-
* Performance target: <100ms for 500 files.
|
|
134
|
-
*/
|
|
135
|
-
export async function computeHashes(projectPath: string): Promise<Map<string, FileHash>> {
|
|
136
|
-
const filePaths = await listProjectFiles(projectPath, projectPath)
|
|
137
|
-
const hashes = new Map<string, FileHash>()
|
|
138
|
-
|
|
139
|
-
const BATCH_SIZE = 100
|
|
140
|
-
for (let i = 0; i < filePaths.length; i += BATCH_SIZE) {
|
|
141
|
-
const batch = filePaths.slice(i, i + BATCH_SIZE)
|
|
142
|
-
const results = await Promise.all(
|
|
143
|
-
batch.map(async (filePath) => {
|
|
144
|
-
try {
|
|
145
|
-
const fullPath = path.join(projectPath, filePath)
|
|
146
|
-
const [content, stat] = await Promise.all([
|
|
147
|
-
fs.readFile(fullPath, 'utf-8'),
|
|
148
|
-
fs.stat(fullPath),
|
|
149
|
-
])
|
|
150
|
-
return {
|
|
151
|
-
path: filePath,
|
|
152
|
-
hash: hashContent(content),
|
|
153
|
-
size: stat.size,
|
|
154
|
-
mtime: stat.mtime.toISOString(),
|
|
155
|
-
} satisfies FileHash
|
|
156
|
-
} catch {
|
|
157
|
-
return null
|
|
158
|
-
}
|
|
159
|
-
})
|
|
160
|
-
)
|
|
161
|
-
|
|
162
|
-
for (const result of results) {
|
|
163
|
-
if (result) {
|
|
164
|
-
hashes.set(result.path, result)
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
return hashes
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
// =============================================================================
|
|
173
|
-
// Diff Detection
|
|
174
|
-
// =============================================================================
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* Compare current file hashes against stored registry.
|
|
178
|
-
* Returns lists of added, modified, deleted, and unchanged files.
|
|
179
|
-
*/
|
|
180
|
-
export function diffHashes(
|
|
181
|
-
current: Map<string, FileHash>,
|
|
182
|
-
stored: Map<string, FileHash>
|
|
183
|
-
): FileDiff {
|
|
184
|
-
const added: string[] = []
|
|
185
|
-
const modified: string[] = []
|
|
186
|
-
const unchanged: string[] = []
|
|
187
|
-
|
|
188
|
-
for (const [filePath, currentHash] of current) {
|
|
189
|
-
const storedHash = stored.get(filePath)
|
|
190
|
-
if (!storedHash) {
|
|
191
|
-
added.push(filePath)
|
|
192
|
-
} else if (storedHash.hash !== currentHash.hash) {
|
|
193
|
-
modified.push(filePath)
|
|
194
|
-
} else {
|
|
195
|
-
unchanged.push(filePath)
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
const deleted: string[] = []
|
|
200
|
-
for (const filePath of stored.keys()) {
|
|
201
|
-
if (!current.has(filePath)) {
|
|
202
|
-
deleted.push(filePath)
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
return { added, modified, deleted, unchanged }
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
// =============================================================================
|
|
210
|
-
// SQLite Persistence (uses index_checksums table)
|
|
211
|
-
// =============================================================================
|
|
212
|
-
|
|
213
|
-
/**
|
|
214
|
-
* Save file hashes to SQLite index_checksums table.
|
|
215
|
-
*/
|
|
216
|
-
export function saveHashes(projectId: string, hashes: Map<string, FileHash>): void {
|
|
217
|
-
const db = prjctDb.getDb(projectId)
|
|
218
|
-
|
|
219
|
-
db.transaction(() => {
|
|
220
|
-
// Clear existing checksums
|
|
221
|
-
db.prepare('DELETE FROM index_checksums').run()
|
|
222
|
-
|
|
223
|
-
// Insert all hashes
|
|
224
|
-
const insert = db.prepare(
|
|
225
|
-
'INSERT INTO index_checksums (path, checksum, size, mtime) VALUES (?, ?, ?, ?)'
|
|
226
|
-
)
|
|
227
|
-
|
|
228
|
-
for (const [, hash] of hashes) {
|
|
229
|
-
insert.run(hash.path, hash.hash, hash.size, hash.mtime)
|
|
230
|
-
}
|
|
231
|
-
})()
|
|
232
|
-
|
|
233
|
-
// Also store metadata about when hashes were computed
|
|
234
|
-
prjctDb.setDoc(projectId, 'file-hashes-meta', {
|
|
235
|
-
fileCount: hashes.size,
|
|
236
|
-
builtAt: new Date().toISOString(),
|
|
237
|
-
})
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
/**
|
|
241
|
-
* Load file hashes from SQLite index_checksums table.
|
|
242
|
-
*/
|
|
243
|
-
export function loadHashes(projectId: string): Map<string, FileHash> {
|
|
244
|
-
const hashes = new Map<string, FileHash>()
|
|
245
|
-
|
|
246
|
-
try {
|
|
247
|
-
const rows = prjctDb.query<{ path: string; checksum: string; size: number; mtime: string }>(
|
|
248
|
-
projectId,
|
|
249
|
-
'SELECT path, checksum, size, mtime FROM index_checksums'
|
|
250
|
-
)
|
|
251
|
-
|
|
252
|
-
for (const row of rows) {
|
|
253
|
-
hashes.set(row.path, {
|
|
254
|
-
path: row.path,
|
|
255
|
-
hash: row.checksum,
|
|
256
|
-
size: row.size || 0,
|
|
257
|
-
mtime: row.mtime || '',
|
|
258
|
-
})
|
|
259
|
-
}
|
|
260
|
-
} catch {
|
|
261
|
-
// Table might not exist yet or be empty
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
return hashes
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
// =============================================================================
|
|
268
|
-
// High-level API
|
|
269
|
-
// =============================================================================
|
|
270
|
-
|
|
271
|
-
/**
|
|
272
|
-
* Compute file hashes and diff against stored registry.
|
|
273
|
-
* Returns the diff and the current hashes (for saving after sync completes).
|
|
274
|
-
*
|
|
275
|
-
* If no stored hashes exist (first sync), all files are "added".
|
|
276
|
-
*/
|
|
277
|
-
export async function detectChanges(
|
|
278
|
-
projectPath: string,
|
|
279
|
-
projectId: string
|
|
280
|
-
): Promise<{ diff: FileDiff; currentHashes: Map<string, FileHash> }> {
|
|
281
|
-
const [currentHashes, storedHashes] = await Promise.all([
|
|
282
|
-
computeHashes(projectPath),
|
|
283
|
-
Promise.resolve(loadHashes(projectId)),
|
|
284
|
-
])
|
|
285
|
-
|
|
286
|
-
const diff = diffHashes(currentHashes, storedHashes)
|
|
287
|
-
|
|
288
|
-
return { diff, currentHashes }
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
/**
|
|
292
|
-
* Check if a hash registry exists for this project.
|
|
293
|
-
*/
|
|
294
|
-
export function hasHashRegistry(projectId: string): boolean {
|
|
295
|
-
return prjctDb.hasDoc(projectId, 'file-hashes-meta')
|
|
296
|
-
}
|