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,720 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* JSON → SQLite Migration (PRJ-303)
|
|
3
|
-
*
|
|
4
|
-
* One-time migration: reads existing JSON/JSONL files and inserts into SQLite.
|
|
5
|
-
* Creates backup of original files before migration.
|
|
6
|
-
*
|
|
7
|
-
* Migration flow:
|
|
8
|
-
* 1. Check if prjct.db already exists → skip if so
|
|
9
|
-
* 2. Backup all JSON files to storage/backup/
|
|
10
|
-
* 3. Insert documents into kv_store (backward-compatible)
|
|
11
|
-
* 4. Populate normalized tables for indexed queries
|
|
12
|
-
* 5. Migrate events.jsonl → events table
|
|
13
|
-
* 6. Migrate index files → index tables
|
|
14
|
-
*
|
|
15
|
-
* Auto-runs on first StorageManager access when prjct.db doesn't exist.
|
|
16
|
-
*
|
|
17
|
-
* @version 1.0.0
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
import fs from 'node:fs/promises'
|
|
21
|
-
import path from 'node:path'
|
|
22
|
-
import pathManager from '../infrastructure/path-manager'
|
|
23
|
-
import { isNotFoundError } from '../types/fs'
|
|
24
|
-
import { prjctDb } from './database'
|
|
25
|
-
|
|
26
|
-
// =============================================================================
|
|
27
|
-
// Types
|
|
28
|
-
// =============================================================================
|
|
29
|
-
|
|
30
|
-
export interface MigrationResult {
|
|
31
|
-
success: boolean
|
|
32
|
-
migratedFiles: string[]
|
|
33
|
-
skippedFiles: string[]
|
|
34
|
-
errors: Array<{ file: string; error: string }>
|
|
35
|
-
backupDir: string | null
|
|
36
|
-
duration: number
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// =============================================================================
|
|
40
|
-
// File Definitions
|
|
41
|
-
// =============================================================================
|
|
42
|
-
|
|
43
|
-
/** Storage JSON files → kv_store keys */
|
|
44
|
-
const STORAGE_FILES: Array<{ filename: string; key: string }> = [
|
|
45
|
-
{ filename: 'state.json', key: 'state' },
|
|
46
|
-
{ filename: 'queue.json', key: 'queue' },
|
|
47
|
-
{ filename: 'ideas.json', key: 'ideas' },
|
|
48
|
-
{ filename: 'shipped.json', key: 'shipped' },
|
|
49
|
-
{ filename: 'metrics.json', key: 'metrics' },
|
|
50
|
-
{ filename: 'velocity.json', key: 'velocity' },
|
|
51
|
-
{ filename: 'analysis.json', key: 'analysis' },
|
|
52
|
-
{ filename: 'roadmap.json', key: 'roadmap' },
|
|
53
|
-
{ filename: 'session.json', key: 'session' },
|
|
54
|
-
{ filename: 'issues.json', key: 'issues' },
|
|
55
|
-
]
|
|
56
|
-
|
|
57
|
-
/** Index JSON files → index_meta keys */
|
|
58
|
-
const INDEX_FILES: Array<{ filename: string; key: string }> = [
|
|
59
|
-
{ filename: 'project-index.json', key: 'project-index' },
|
|
60
|
-
{ filename: 'domains.json', key: 'domains' },
|
|
61
|
-
{ filename: 'categories-cache.json', key: 'categories-cache' },
|
|
62
|
-
]
|
|
63
|
-
|
|
64
|
-
// =============================================================================
|
|
65
|
-
// Main Migration Function
|
|
66
|
-
// =============================================================================
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Migrate all JSON files to SQLite for a project.
|
|
70
|
-
* Safe to call multiple times — skips if DB already has data.
|
|
71
|
-
*/
|
|
72
|
-
export async function migrateJsonToSqlite(projectId: string): Promise<MigrationResult> {
|
|
73
|
-
const start = Date.now()
|
|
74
|
-
const result: MigrationResult = {
|
|
75
|
-
success: false,
|
|
76
|
-
migratedFiles: [],
|
|
77
|
-
skippedFiles: [],
|
|
78
|
-
errors: [],
|
|
79
|
-
backupDir: null,
|
|
80
|
-
duration: 0,
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
try {
|
|
84
|
-
// Check if already migrated (kv_store has data)
|
|
85
|
-
if (prjctDb.exists(projectId) && prjctDb.hasDoc(projectId, 'state')) {
|
|
86
|
-
result.success = true
|
|
87
|
-
result.duration = Date.now() - start
|
|
88
|
-
return result
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const globalPath = pathManager.getGlobalProjectPath(projectId)
|
|
92
|
-
const storagePath = path.join(globalPath, 'storage')
|
|
93
|
-
const indexPath = path.join(globalPath, 'index')
|
|
94
|
-
const memoryPath = path.join(globalPath, 'memory')
|
|
95
|
-
|
|
96
|
-
// Step 1: Create backup
|
|
97
|
-
result.backupDir = await createBackup(storagePath, indexPath, memoryPath)
|
|
98
|
-
|
|
99
|
-
// Step 2: Ensure DB is initialized (creates tables)
|
|
100
|
-
prjctDb.getDb(projectId)
|
|
101
|
-
|
|
102
|
-
// Step 3: Migrate storage JSON files → kv_store + normalized tables
|
|
103
|
-
for (const { filename, key } of STORAGE_FILES) {
|
|
104
|
-
const filePath = path.join(storagePath, filename)
|
|
105
|
-
const data = await readJsonSafe(filePath)
|
|
106
|
-
|
|
107
|
-
if (data === null) {
|
|
108
|
-
result.skippedFiles.push(filename)
|
|
109
|
-
continue
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
try {
|
|
113
|
-
// Write to kv_store (document storage)
|
|
114
|
-
prjctDb.setDoc(projectId, key, data)
|
|
115
|
-
|
|
116
|
-
// Populate normalized tables
|
|
117
|
-
populateNormalized(projectId, key, data)
|
|
118
|
-
|
|
119
|
-
result.migratedFiles.push(filename)
|
|
120
|
-
} catch (err) {
|
|
121
|
-
result.errors.push({ file: filename, error: String(err) })
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// Step 4: Migrate index files → index_meta + normalized index tables
|
|
126
|
-
for (const { filename, key } of INDEX_FILES) {
|
|
127
|
-
const filePath = path.join(indexPath, filename)
|
|
128
|
-
const data = await readJsonSafe(filePath)
|
|
129
|
-
|
|
130
|
-
if (data === null) {
|
|
131
|
-
result.skippedFiles.push(`index/${filename}`)
|
|
132
|
-
continue
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
try {
|
|
136
|
-
prjctDb.run(
|
|
137
|
-
projectId,
|
|
138
|
-
'INSERT OR REPLACE INTO index_meta (key, data, updated_at) VALUES (?, ?, ?)',
|
|
139
|
-
key,
|
|
140
|
-
JSON.stringify(data),
|
|
141
|
-
new Date().toISOString()
|
|
142
|
-
)
|
|
143
|
-
|
|
144
|
-
// Populate normalized index tables
|
|
145
|
-
populateIndexTables(projectId, key, data)
|
|
146
|
-
|
|
147
|
-
result.migratedFiles.push(`index/${filename}`)
|
|
148
|
-
} catch (err) {
|
|
149
|
-
result.errors.push({ file: `index/${filename}`, error: String(err) })
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// Step 5: Migrate checksums.json → index_checksums table
|
|
154
|
-
await migrateChecksums(projectId, indexPath, result)
|
|
155
|
-
|
|
156
|
-
// Step 6: Migrate file-scores.json → index_files table
|
|
157
|
-
await migrateFileScores(projectId, indexPath, result)
|
|
158
|
-
|
|
159
|
-
// Step 7: Migrate events.jsonl → events table
|
|
160
|
-
await migrateEventsJsonl(projectId, memoryPath, result)
|
|
161
|
-
|
|
162
|
-
// Step 8: Migrate learnings.jsonl → memory table
|
|
163
|
-
await migrateLearningsJsonl(projectId, memoryPath, result)
|
|
164
|
-
|
|
165
|
-
// Step 9: Clean up source JSON files (backup already exists)
|
|
166
|
-
if (result.errors.length === 0) {
|
|
167
|
-
await cleanupJsonFiles(storagePath, indexPath, memoryPath, result)
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
result.success = result.errors.length === 0
|
|
171
|
-
result.duration = Date.now() - start
|
|
172
|
-
return result
|
|
173
|
-
} catch (err) {
|
|
174
|
-
result.errors.push({ file: '<migration>', error: String(err) })
|
|
175
|
-
result.duration = Date.now() - start
|
|
176
|
-
return result
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
// =============================================================================
|
|
181
|
-
// Backup
|
|
182
|
-
// =============================================================================
|
|
183
|
-
|
|
184
|
-
async function createBackup(
|
|
185
|
-
storagePath: string,
|
|
186
|
-
indexPath: string,
|
|
187
|
-
memoryPath: string
|
|
188
|
-
): Promise<string> {
|
|
189
|
-
const backupDir = path.join(storagePath, 'backup')
|
|
190
|
-
await fs.mkdir(backupDir, { recursive: true })
|
|
191
|
-
await fs.mkdir(path.join(backupDir, 'index'), { recursive: true })
|
|
192
|
-
await fs.mkdir(path.join(backupDir, 'memory'), { recursive: true })
|
|
193
|
-
|
|
194
|
-
// Backup storage files
|
|
195
|
-
await copyFiles(
|
|
196
|
-
storagePath,
|
|
197
|
-
backupDir,
|
|
198
|
-
(name) => name.endsWith('.json') || name.endsWith('.jsonl')
|
|
199
|
-
)
|
|
200
|
-
|
|
201
|
-
// Backup index files
|
|
202
|
-
await copyFiles(indexPath, path.join(backupDir, 'index'))
|
|
203
|
-
|
|
204
|
-
// Backup memory files
|
|
205
|
-
await copyFiles(memoryPath, path.join(backupDir, 'memory'))
|
|
206
|
-
|
|
207
|
-
return backupDir
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
async function copyFiles(
|
|
211
|
-
srcDir: string,
|
|
212
|
-
destDir: string,
|
|
213
|
-
filter?: (name: string) => boolean
|
|
214
|
-
): Promise<void> {
|
|
215
|
-
try {
|
|
216
|
-
const entries = await fs.readdir(srcDir, { withFileTypes: true })
|
|
217
|
-
for (const entry of entries) {
|
|
218
|
-
if (!entry.isFile()) continue
|
|
219
|
-
if (filter && !filter(entry.name)) continue
|
|
220
|
-
const src = path.join(srcDir, entry.name)
|
|
221
|
-
const dest = path.join(destDir, entry.name)
|
|
222
|
-
await fs.copyFile(src, dest)
|
|
223
|
-
}
|
|
224
|
-
} catch (err) {
|
|
225
|
-
if (!isNotFoundError(err)) throw err
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
// =============================================================================
|
|
230
|
-
// Normalized Table Population
|
|
231
|
-
// =============================================================================
|
|
232
|
-
|
|
233
|
-
function populateNormalized(projectId: string, key: string, data: unknown): void {
|
|
234
|
-
switch (key) {
|
|
235
|
-
case 'state':
|
|
236
|
-
populateTasksFromState(projectId, data as Record<string, unknown>)
|
|
237
|
-
break
|
|
238
|
-
case 'queue':
|
|
239
|
-
populateQueueTasks(projectId, data as Record<string, unknown>)
|
|
240
|
-
break
|
|
241
|
-
case 'ideas':
|
|
242
|
-
populateIdeas(projectId, data as Record<string, unknown>)
|
|
243
|
-
break
|
|
244
|
-
case 'shipped':
|
|
245
|
-
populateShippedFeatures(projectId, data as Record<string, unknown>)
|
|
246
|
-
break
|
|
247
|
-
case 'metrics':
|
|
248
|
-
populateMetricsDaily(projectId, data as Record<string, unknown>)
|
|
249
|
-
break
|
|
250
|
-
case 'analysis':
|
|
251
|
-
populateAnalysis(projectId, data as Record<string, unknown>)
|
|
252
|
-
break
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
function populateTasksFromState(projectId: string, state: Record<string, unknown>): void {
|
|
257
|
-
const db = prjctDb.getDb(projectId)
|
|
258
|
-
|
|
259
|
-
const insertTask = db.prepare(`
|
|
260
|
-
INSERT OR REPLACE INTO tasks
|
|
261
|
-
(id, description, type, status, parent_description, branch, linear_id,
|
|
262
|
-
linear_uuid, session_id, feature_id, started_at, completed_at,
|
|
263
|
-
shipped_at, paused_at, pause_reason, pr_url, expected_value, data)
|
|
264
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
265
|
-
`)
|
|
266
|
-
|
|
267
|
-
const insertSubtask = db.prepare(`
|
|
268
|
-
INSERT OR REPLACE INTO subtasks
|
|
269
|
-
(id, task_id, description, status, domain, agent, sort_order,
|
|
270
|
-
depends_on, started_at, completed_at, output, summary)
|
|
271
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
272
|
-
`)
|
|
273
|
-
|
|
274
|
-
const migrateTask = (task: Record<string, unknown>, status?: string) => {
|
|
275
|
-
if (!task || !task.id) return
|
|
276
|
-
|
|
277
|
-
insertTask.run(
|
|
278
|
-
task.id as string,
|
|
279
|
-
(task.description ?? task.parentDescription ?? '') as string,
|
|
280
|
-
(task.type ?? null) as string | null,
|
|
281
|
-
(status ?? task.status ?? 'unknown') as string,
|
|
282
|
-
(task.parentDescription ?? null) as string | null,
|
|
283
|
-
(task.branch ?? null) as string | null,
|
|
284
|
-
(task.linearId ?? null) as string | null,
|
|
285
|
-
(task.linearUuid ?? null) as string | null,
|
|
286
|
-
(task.sessionId ?? null) as string | null,
|
|
287
|
-
(task.featureId ?? null) as string | null,
|
|
288
|
-
(task.startedAt ?? new Date().toISOString()) as string,
|
|
289
|
-
(task.completedAt ?? null) as string | null,
|
|
290
|
-
(task.shippedAt ?? null) as string | null,
|
|
291
|
-
(task.pausedAt ?? null) as string | null,
|
|
292
|
-
(task.pauseReason ?? null) as string | null,
|
|
293
|
-
(task.prUrl ?? null) as string | null,
|
|
294
|
-
task.expectedValue ? JSON.stringify(task.expectedValue) : null,
|
|
295
|
-
JSON.stringify(task)
|
|
296
|
-
)
|
|
297
|
-
|
|
298
|
-
// Migrate subtasks
|
|
299
|
-
const subtasks = task.subtasks as Array<Record<string, unknown>> | undefined
|
|
300
|
-
if (subtasks && Array.isArray(subtasks)) {
|
|
301
|
-
for (let i = 0; i < subtasks.length; i++) {
|
|
302
|
-
const st = subtasks[i]
|
|
303
|
-
insertSubtask.run(
|
|
304
|
-
(st.id ?? `subtask-${i}`) as string,
|
|
305
|
-
task.id as string,
|
|
306
|
-
(st.description ?? '') as string,
|
|
307
|
-
(st.status ?? 'pending') as string,
|
|
308
|
-
(st.domain ?? null) as string | null,
|
|
309
|
-
(st.agent ?? null) as string | null,
|
|
310
|
-
i,
|
|
311
|
-
st.dependsOn ? JSON.stringify(st.dependsOn) : null,
|
|
312
|
-
(st.startedAt ?? null) as string | null,
|
|
313
|
-
(st.completedAt ?? null) as string | null,
|
|
314
|
-
(st.output ?? null) as string | null,
|
|
315
|
-
st.summary ? JSON.stringify(st.summary) : null
|
|
316
|
-
)
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
if (state.currentTask) migrateTask(state.currentTask as Record<string, unknown>)
|
|
322
|
-
if (state.previousTask) migrateTask(state.previousTask as Record<string, unknown>)
|
|
323
|
-
|
|
324
|
-
const paused = state.pausedTasks as Array<Record<string, unknown>> | undefined
|
|
325
|
-
if (paused && Array.isArray(paused)) {
|
|
326
|
-
for (const task of paused) {
|
|
327
|
-
migrateTask(task, 'paused')
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
function populateQueueTasks(projectId: string, data: Record<string, unknown>): void {
|
|
333
|
-
const tasks = data.tasks as Array<Record<string, unknown>> | undefined
|
|
334
|
-
if (!tasks || !Array.isArray(tasks)) return
|
|
335
|
-
|
|
336
|
-
const db = prjctDb.getDb(projectId)
|
|
337
|
-
const stmt = db.prepare(`
|
|
338
|
-
INSERT OR REPLACE INTO queue_tasks
|
|
339
|
-
(id, description, type, priority, section, created_at, completed, completed_at,
|
|
340
|
-
feature_id, feature_name)
|
|
341
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
342
|
-
`)
|
|
343
|
-
|
|
344
|
-
for (const t of tasks) {
|
|
345
|
-
stmt.run(
|
|
346
|
-
t.id as string,
|
|
347
|
-
(t.description ?? '') as string,
|
|
348
|
-
(t.type ?? null) as string | null,
|
|
349
|
-
(t.priority ?? null) as string | null,
|
|
350
|
-
(t.section ?? null) as string | null,
|
|
351
|
-
(t.createdAt ?? new Date().toISOString()) as string,
|
|
352
|
-
t.completed ? 1 : 0,
|
|
353
|
-
(t.completedAt ?? null) as string | null,
|
|
354
|
-
(t.featureId ?? null) as string | null,
|
|
355
|
-
(t.featureName ?? null) as string | null
|
|
356
|
-
)
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
function populateIdeas(projectId: string, data: Record<string, unknown>): void {
|
|
361
|
-
const ideas = data.ideas as Array<Record<string, unknown>> | undefined
|
|
362
|
-
if (!ideas || !Array.isArray(ideas)) return
|
|
363
|
-
|
|
364
|
-
const db = prjctDb.getDb(projectId)
|
|
365
|
-
const stmt = db.prepare(`
|
|
366
|
-
INSERT OR REPLACE INTO ideas
|
|
367
|
-
(id, text, status, priority, tags, added_at, converted_to, details, data)
|
|
368
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
369
|
-
`)
|
|
370
|
-
|
|
371
|
-
for (const idea of ideas) {
|
|
372
|
-
stmt.run(
|
|
373
|
-
idea.id as string,
|
|
374
|
-
(idea.text ?? '') as string,
|
|
375
|
-
(idea.status ?? 'pending') as string,
|
|
376
|
-
(idea.priority ?? 'medium') as string,
|
|
377
|
-
idea.tags ? JSON.stringify(idea.tags) : null,
|
|
378
|
-
(idea.addedAt ?? new Date().toISOString()) as string,
|
|
379
|
-
(idea.convertedTo ?? null) as string | null,
|
|
380
|
-
(idea.details ?? null) as string | null,
|
|
381
|
-
JSON.stringify(idea)
|
|
382
|
-
)
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
function populateShippedFeatures(projectId: string, data: Record<string, unknown>): void {
|
|
387
|
-
const shipped = data.shipped as Array<Record<string, unknown>> | undefined
|
|
388
|
-
if (!shipped || !Array.isArray(shipped)) return
|
|
389
|
-
|
|
390
|
-
const db = prjctDb.getDb(projectId)
|
|
391
|
-
const stmt = db.prepare(`
|
|
392
|
-
INSERT OR REPLACE INTO shipped_features
|
|
393
|
-
(id, name, shipped_at, version, description, type, duration, data)
|
|
394
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
395
|
-
`)
|
|
396
|
-
|
|
397
|
-
for (const feature of shipped) {
|
|
398
|
-
stmt.run(
|
|
399
|
-
feature.id as string,
|
|
400
|
-
(feature.name ?? '') as string,
|
|
401
|
-
(feature.shippedAt ?? new Date().toISOString()) as string,
|
|
402
|
-
(feature.version ?? '0.0.0') as string,
|
|
403
|
-
(feature.description ?? null) as string | null,
|
|
404
|
-
(feature.type ?? null) as string | null,
|
|
405
|
-
(feature.duration ?? null) as string | null,
|
|
406
|
-
JSON.stringify(feature)
|
|
407
|
-
)
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
function populateMetricsDaily(projectId: string, data: Record<string, unknown>): void {
|
|
412
|
-
const dailyStats = data.dailyStats as Array<Record<string, unknown>> | undefined
|
|
413
|
-
if (!dailyStats || !Array.isArray(dailyStats)) return
|
|
414
|
-
|
|
415
|
-
const db = prjctDb.getDb(projectId)
|
|
416
|
-
const stmt = db.prepare(`
|
|
417
|
-
INSERT OR REPLACE INTO metrics_daily
|
|
418
|
-
(date, tokens_saved, syncs, avg_compression_rate, total_duration)
|
|
419
|
-
VALUES (?, ?, ?, ?, ?)
|
|
420
|
-
`)
|
|
421
|
-
|
|
422
|
-
for (const day of dailyStats) {
|
|
423
|
-
stmt.run(
|
|
424
|
-
day.date as string,
|
|
425
|
-
(day.tokensSaved ?? 0) as number,
|
|
426
|
-
(day.syncs ?? 0) as number,
|
|
427
|
-
(day.avgCompressionRate ?? 0) as number,
|
|
428
|
-
(day.totalDuration ?? 0) as number
|
|
429
|
-
)
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
function populateAnalysis(projectId: string, data: Record<string, unknown>): void {
|
|
434
|
-
const db = prjctDb.getDb(projectId)
|
|
435
|
-
const stmt = db.prepare(`
|
|
436
|
-
INSERT OR REPLACE INTO analysis
|
|
437
|
-
(id, status, commit_hash, signature, sealed_at, analyzed_at, data)
|
|
438
|
-
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
439
|
-
`)
|
|
440
|
-
|
|
441
|
-
const migrate = (analysis: Record<string, unknown>, id: string) => {
|
|
442
|
-
if (!analysis) return
|
|
443
|
-
stmt.run(
|
|
444
|
-
id,
|
|
445
|
-
(analysis.status ?? 'unknown') as string,
|
|
446
|
-
(analysis.commitHash ?? null) as string | null,
|
|
447
|
-
(analysis.signature ?? null) as string | null,
|
|
448
|
-
(analysis.sealedAt ?? null) as string | null,
|
|
449
|
-
(analysis.analyzedAt ?? null) as string | null,
|
|
450
|
-
JSON.stringify(analysis)
|
|
451
|
-
)
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
if (data.draft) migrate(data.draft as Record<string, unknown>, 'draft')
|
|
455
|
-
if (data.sealed) migrate(data.sealed as Record<string, unknown>, 'sealed')
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
// =============================================================================
|
|
459
|
-
// Index Table Population
|
|
460
|
-
// =============================================================================
|
|
461
|
-
|
|
462
|
-
function populateIndexTables(projectId: string, key: string, data: unknown): void {
|
|
463
|
-
if (key === 'categories-cache') {
|
|
464
|
-
populateCategoriesIndex(projectId, data as Record<string, unknown>)
|
|
465
|
-
}
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
function populateCategoriesIndex(projectId: string, cache: Record<string, unknown>): void {
|
|
469
|
-
const fileCategories = cache.fileCategories as Array<Record<string, unknown>> | undefined
|
|
470
|
-
if (!fileCategories || !Array.isArray(fileCategories)) return
|
|
471
|
-
|
|
472
|
-
const db = prjctDb.getDb(projectId)
|
|
473
|
-
const stmt = db.prepare(`
|
|
474
|
-
INSERT OR REPLACE INTO index_files
|
|
475
|
-
(path, categories, domain, score, size, mtime, language)
|
|
476
|
-
VALUES (?, ?, ?, COALESCE((SELECT score FROM index_files WHERE path = ?), 0), NULL, NULL, NULL)
|
|
477
|
-
`)
|
|
478
|
-
|
|
479
|
-
for (const fc of fileCategories) {
|
|
480
|
-
stmt.run(
|
|
481
|
-
fc.path as string,
|
|
482
|
-
fc.categories ? JSON.stringify(fc.categories) : null,
|
|
483
|
-
(fc.primaryDomain ?? null) as string | null,
|
|
484
|
-
fc.path as string
|
|
485
|
-
)
|
|
486
|
-
}
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
// =============================================================================
|
|
490
|
-
// Specialized File Migrations
|
|
491
|
-
// =============================================================================
|
|
492
|
-
|
|
493
|
-
async function migrateChecksums(
|
|
494
|
-
projectId: string,
|
|
495
|
-
indexPath: string,
|
|
496
|
-
result: MigrationResult
|
|
497
|
-
): Promise<void> {
|
|
498
|
-
const filePath = path.join(indexPath, 'checksums.json')
|
|
499
|
-
const data = await readJsonSafe(filePath)
|
|
500
|
-
if (data === null) {
|
|
501
|
-
result.skippedFiles.push('index/checksums.json')
|
|
502
|
-
return
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
try {
|
|
506
|
-
const checksums = (data as Record<string, unknown>).checksums as Record<string, string>
|
|
507
|
-
if (!checksums) return
|
|
508
|
-
|
|
509
|
-
const db = prjctDb.getDb(projectId)
|
|
510
|
-
const stmt = db.prepare('INSERT OR REPLACE INTO index_checksums (path, checksum) VALUES (?, ?)')
|
|
511
|
-
|
|
512
|
-
db.transaction(() => {
|
|
513
|
-
for (const [filePath, checksum] of Object.entries(checksums)) {
|
|
514
|
-
stmt.run(filePath, checksum)
|
|
515
|
-
}
|
|
516
|
-
})()
|
|
517
|
-
|
|
518
|
-
result.migratedFiles.push('index/checksums.json')
|
|
519
|
-
} catch (err) {
|
|
520
|
-
result.errors.push({ file: 'index/checksums.json', error: String(err) })
|
|
521
|
-
}
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
async function migrateFileScores(
|
|
525
|
-
projectId: string,
|
|
526
|
-
indexPath: string,
|
|
527
|
-
result: MigrationResult
|
|
528
|
-
): Promise<void> {
|
|
529
|
-
const filePath = path.join(indexPath, 'file-scores.json')
|
|
530
|
-
const data = await readJsonSafe(filePath)
|
|
531
|
-
if (data === null) {
|
|
532
|
-
result.skippedFiles.push('index/file-scores.json')
|
|
533
|
-
return
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
try {
|
|
537
|
-
const scores = (data as Record<string, unknown>).scores as Array<Record<string, unknown>>
|
|
538
|
-
if (!scores || !Array.isArray(scores)) return
|
|
539
|
-
|
|
540
|
-
const db = prjctDb.getDb(projectId)
|
|
541
|
-
const stmt = db.prepare(`
|
|
542
|
-
INSERT OR REPLACE INTO index_files
|
|
543
|
-
(path, score, size, mtime, language, categories, domain)
|
|
544
|
-
VALUES (?, ?, ?, ?, NULL,
|
|
545
|
-
COALESCE((SELECT categories FROM index_files WHERE path = ?), NULL),
|
|
546
|
-
COALESCE((SELECT domain FROM index_files WHERE path = ?), NULL))
|
|
547
|
-
`)
|
|
548
|
-
|
|
549
|
-
db.transaction(() => {
|
|
550
|
-
for (const file of scores) {
|
|
551
|
-
stmt.run(
|
|
552
|
-
file.path as string,
|
|
553
|
-
(file.score ?? 0) as number,
|
|
554
|
-
(file.size ?? null) as number | null,
|
|
555
|
-
(file.mtime ?? null) as string | null,
|
|
556
|
-
file.path as string,
|
|
557
|
-
file.path as string
|
|
558
|
-
)
|
|
559
|
-
}
|
|
560
|
-
})()
|
|
561
|
-
|
|
562
|
-
result.migratedFiles.push('index/file-scores.json')
|
|
563
|
-
} catch (err) {
|
|
564
|
-
result.errors.push({ file: 'index/file-scores.json', error: String(err) })
|
|
565
|
-
}
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
async function migrateEventsJsonl(
|
|
569
|
-
projectId: string,
|
|
570
|
-
memoryPath: string,
|
|
571
|
-
result: MigrationResult
|
|
572
|
-
): Promise<void> {
|
|
573
|
-
const filePath = path.join(memoryPath, 'events.jsonl')
|
|
574
|
-
|
|
575
|
-
try {
|
|
576
|
-
const content = await fs.readFile(filePath, 'utf-8')
|
|
577
|
-
const lines = content.split('\n').filter((line) => line.trim())
|
|
578
|
-
|
|
579
|
-
if (lines.length === 0) {
|
|
580
|
-
result.skippedFiles.push('memory/events.jsonl')
|
|
581
|
-
return
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
const db = prjctDb.getDb(projectId)
|
|
585
|
-
const stmt = db.prepare(
|
|
586
|
-
'INSERT INTO events (type, task_id, data, timestamp) VALUES (?, ?, ?, ?)'
|
|
587
|
-
)
|
|
588
|
-
|
|
589
|
-
db.transaction(() => {
|
|
590
|
-
for (const line of lines) {
|
|
591
|
-
try {
|
|
592
|
-
const event = JSON.parse(line) as Record<string, unknown>
|
|
593
|
-
const type = (event.type ?? event.action ?? 'unknown') as string
|
|
594
|
-
const taskId = (event.taskId ?? event.task_id ?? null) as string | null
|
|
595
|
-
const timestamp = (event.timestamp ?? event.ts ?? new Date().toISOString()) as string
|
|
596
|
-
stmt.run(type, taskId, line, timestamp)
|
|
597
|
-
} catch {
|
|
598
|
-
// Skip malformed lines
|
|
599
|
-
}
|
|
600
|
-
}
|
|
601
|
-
})()
|
|
602
|
-
|
|
603
|
-
result.migratedFiles.push('memory/events.jsonl')
|
|
604
|
-
} catch (err) {
|
|
605
|
-
if (isNotFoundError(err)) {
|
|
606
|
-
result.skippedFiles.push('memory/events.jsonl')
|
|
607
|
-
} else {
|
|
608
|
-
result.errors.push({ file: 'memory/events.jsonl', error: String(err) })
|
|
609
|
-
}
|
|
610
|
-
}
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
async function migrateLearningsJsonl(
|
|
614
|
-
projectId: string,
|
|
615
|
-
memoryPath: string,
|
|
616
|
-
result: MigrationResult
|
|
617
|
-
): Promise<void> {
|
|
618
|
-
const filePath = path.join(memoryPath, 'learnings.jsonl')
|
|
619
|
-
|
|
620
|
-
try {
|
|
621
|
-
const content = await fs.readFile(filePath, 'utf-8')
|
|
622
|
-
const lines = content.split('\n').filter((line) => line.trim())
|
|
623
|
-
|
|
624
|
-
if (lines.length === 0) {
|
|
625
|
-
result.skippedFiles.push('memory/learnings.jsonl')
|
|
626
|
-
return
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
const db = prjctDb.getDb(projectId)
|
|
630
|
-
const stmt = db.prepare(
|
|
631
|
-
'INSERT OR REPLACE INTO memory (key, domain, value, confidence, updated_at) VALUES (?, ?, ?, ?, ?)'
|
|
632
|
-
)
|
|
633
|
-
|
|
634
|
-
db.transaction(() => {
|
|
635
|
-
for (const line of lines) {
|
|
636
|
-
try {
|
|
637
|
-
const entry = JSON.parse(line) as Record<string, unknown>
|
|
638
|
-
const key = `learning:${entry.taskId ?? entry.timestamp ?? Date.now()}`
|
|
639
|
-
const tags = entry.tags as string[] | undefined
|
|
640
|
-
const domain = tags && tags.length > 0 ? tags[0] : null
|
|
641
|
-
stmt.run(key, domain, line, 1.0, (entry.timestamp ?? new Date().toISOString()) as string)
|
|
642
|
-
} catch {
|
|
643
|
-
// Skip malformed lines
|
|
644
|
-
}
|
|
645
|
-
}
|
|
646
|
-
})()
|
|
647
|
-
|
|
648
|
-
result.migratedFiles.push('memory/learnings.jsonl')
|
|
649
|
-
} catch (err) {
|
|
650
|
-
if (isNotFoundError(err)) {
|
|
651
|
-
result.skippedFiles.push('memory/learnings.jsonl')
|
|
652
|
-
} else {
|
|
653
|
-
result.errors.push({ file: 'memory/learnings.jsonl', error: String(err) })
|
|
654
|
-
}
|
|
655
|
-
}
|
|
656
|
-
}
|
|
657
|
-
|
|
658
|
-
// =============================================================================
|
|
659
|
-
// JSON Cleanup (post-migration)
|
|
660
|
-
// =============================================================================
|
|
661
|
-
|
|
662
|
-
/**
|
|
663
|
-
* Delete source JSON/JSONL files after successful migration.
|
|
664
|
-
* Keeps backup/ directory and context/*.md files intact.
|
|
665
|
-
*/
|
|
666
|
-
async function cleanupJsonFiles(
|
|
667
|
-
storagePath: string,
|
|
668
|
-
indexPath: string,
|
|
669
|
-
memoryPath: string,
|
|
670
|
-
result: MigrationResult
|
|
671
|
-
): Promise<void> {
|
|
672
|
-
const deleteFile = async (filePath: string, label: string) => {
|
|
673
|
-
try {
|
|
674
|
-
await fs.unlink(filePath)
|
|
675
|
-
} catch (err) {
|
|
676
|
-
if (!isNotFoundError(err)) {
|
|
677
|
-
result.errors.push({ file: label, error: `cleanup: ${String(err)}` })
|
|
678
|
-
}
|
|
679
|
-
}
|
|
680
|
-
}
|
|
681
|
-
|
|
682
|
-
// Delete storage JSON files (keep backup/ directory)
|
|
683
|
-
for (const { filename } of STORAGE_FILES) {
|
|
684
|
-
await deleteFile(path.join(storagePath, filename), `cleanup:${filename}`)
|
|
685
|
-
}
|
|
686
|
-
|
|
687
|
-
// Delete index JSON files
|
|
688
|
-
const indexFiles = [
|
|
689
|
-
'project-index.json',
|
|
690
|
-
'domains.json',
|
|
691
|
-
'categories-cache.json',
|
|
692
|
-
'checksums.json',
|
|
693
|
-
'file-scores.json',
|
|
694
|
-
]
|
|
695
|
-
for (const filename of indexFiles) {
|
|
696
|
-
await deleteFile(path.join(indexPath, filename), `cleanup:index/${filename}`)
|
|
697
|
-
}
|
|
698
|
-
|
|
699
|
-
// Delete memory JSONL files
|
|
700
|
-
await deleteFile(path.join(memoryPath, 'events.jsonl'), 'cleanup:memory/events.jsonl')
|
|
701
|
-
await deleteFile(path.join(memoryPath, 'learnings.jsonl'), 'cleanup:memory/learnings.jsonl')
|
|
702
|
-
}
|
|
703
|
-
|
|
704
|
-
// =============================================================================
|
|
705
|
-
// Helpers
|
|
706
|
-
// =============================================================================
|
|
707
|
-
|
|
708
|
-
async function readJsonSafe(filePath: string): Promise<unknown | null> {
|
|
709
|
-
try {
|
|
710
|
-
const content = await fs.readFile(filePath, 'utf-8')
|
|
711
|
-
return JSON.parse(content)
|
|
712
|
-
} catch (err) {
|
|
713
|
-
if (isNotFoundError(err) || err instanceof SyntaxError) {
|
|
714
|
-
return null
|
|
715
|
-
}
|
|
716
|
-
throw err
|
|
717
|
-
}
|
|
718
|
-
}
|
|
719
|
-
|
|
720
|
-
export default migrateJsonToSqlite
|