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,209 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Collection Filter Utilities
|
|
3
|
-
*
|
|
4
|
-
* Reusable filtering and sorting functions for storage collections.
|
|
5
|
-
* Eliminates duplicated filter logic across storage classes.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import type { Priority, TaskSection } from '../schemas/state'
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Priority order mapping for sorting (highest priority first)
|
|
12
|
-
*/
|
|
13
|
-
export const PRIORITY_ORDER: Record<Priority, number> = {
|
|
14
|
-
critical: 0,
|
|
15
|
-
high: 1,
|
|
16
|
-
medium: 2,
|
|
17
|
-
low: 3,
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Section order mapping for sorting
|
|
22
|
-
*/
|
|
23
|
-
export const SECTION_ORDER: Record<TaskSection, number> = {
|
|
24
|
-
active: 0,
|
|
25
|
-
previously_active: 1,
|
|
26
|
-
backlog: 2,
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Filter items by a specific field value
|
|
31
|
-
*/
|
|
32
|
-
export function filterByField<T, K extends keyof T>(items: T[], field: K, value: T[K]): T[] {
|
|
33
|
-
return items.filter((item) => item[field] === value)
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Filter items by multiple field values (OR logic)
|
|
38
|
-
*/
|
|
39
|
-
export function filterByFieldIn<T, K extends keyof T>(items: T[], field: K, values: T[K][]): T[] {
|
|
40
|
-
return items.filter((item) => values.includes(item[field]))
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Filter items excluding a specific field value
|
|
45
|
-
*/
|
|
46
|
-
export function filterByFieldNot<T, K extends keyof T>(items: T[], field: K, value: T[K]): T[] {
|
|
47
|
-
return items.filter((item) => item[field] !== value)
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Combined filter: field equals value AND another field is falsy
|
|
52
|
-
* Useful for filtering active items that aren't completed
|
|
53
|
-
*/
|
|
54
|
-
export function filterActiveByField<T, K extends keyof T>(
|
|
55
|
-
items: T[],
|
|
56
|
-
field: K,
|
|
57
|
-
value: T[K],
|
|
58
|
-
activeField: keyof T
|
|
59
|
-
): T[] {
|
|
60
|
-
return items.filter((item) => item[field] === value && !item[activeField])
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Filter items where a field is truthy
|
|
65
|
-
*/
|
|
66
|
-
export function filterByTruthy<T, K extends keyof T>(items: T[], field: K): T[] {
|
|
67
|
-
return items.filter((item) => Boolean(item[field]))
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Filter items where a field is falsy
|
|
72
|
-
*/
|
|
73
|
-
export function filterByFalsy<T, K extends keyof T>(items: T[], field: K): T[] {
|
|
74
|
-
return items.filter((item) => !item[field])
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Sort items by priority (highest first)
|
|
79
|
-
*/
|
|
80
|
-
export function sortByPriority<T extends { priority: Priority }>(items: T[]): T[] {
|
|
81
|
-
return [...items].sort((a, b) => PRIORITY_ORDER[a.priority] - PRIORITY_ORDER[b.priority])
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Sort items by section, then priority
|
|
86
|
-
*/
|
|
87
|
-
export function sortBySectionAndPriority<T extends { section: TaskSection; priority: Priority }>(
|
|
88
|
-
items: T[]
|
|
89
|
-
): T[] {
|
|
90
|
-
return [...items].sort((a, b) => {
|
|
91
|
-
const sectionDiff = SECTION_ORDER[a.section] - SECTION_ORDER[b.section]
|
|
92
|
-
if (sectionDiff !== 0) return sectionDiff
|
|
93
|
-
return PRIORITY_ORDER[a.priority] - PRIORITY_ORDER[b.priority]
|
|
94
|
-
})
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Sort items by date field
|
|
99
|
-
*/
|
|
100
|
-
export function sortByDate<T>(
|
|
101
|
-
items: T[],
|
|
102
|
-
dateField: keyof T,
|
|
103
|
-
direction: 'asc' | 'desc' = 'desc'
|
|
104
|
-
): T[] {
|
|
105
|
-
return [...items].sort((a, b) => {
|
|
106
|
-
const dateA = new Date(a[dateField] as string).getTime()
|
|
107
|
-
const dateB = new Date(b[dateField] as string).getTime()
|
|
108
|
-
return direction === 'desc' ? dateB - dateA : dateA - dateB
|
|
109
|
-
})
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Filter items by date range
|
|
114
|
-
*/
|
|
115
|
-
export function filterByDateRange<T>(
|
|
116
|
-
items: T[],
|
|
117
|
-
dateField: keyof T,
|
|
118
|
-
startDate: Date,
|
|
119
|
-
endDate: Date
|
|
120
|
-
): T[] {
|
|
121
|
-
return items.filter((item) => {
|
|
122
|
-
const date = new Date(item[dateField] as string)
|
|
123
|
-
return date >= startDate && date <= endDate
|
|
124
|
-
})
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Filter items from the last N days
|
|
129
|
-
*/
|
|
130
|
-
export function filterByLastDays<T>(items: T[], dateField: keyof T, days: number): T[] {
|
|
131
|
-
const startDate = new Date()
|
|
132
|
-
startDate.setDate(startDate.getDate() - days)
|
|
133
|
-
return filterByDateRange(items, dateField, startDate, new Date())
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* Group items by a field value
|
|
138
|
-
*/
|
|
139
|
-
export function groupByField<T, K extends keyof T>(items: T[], field: K): Map<T[K], T[]> {
|
|
140
|
-
const groups = new Map<T[K], T[]>()
|
|
141
|
-
|
|
142
|
-
for (const item of items) {
|
|
143
|
-
const key = item[field]
|
|
144
|
-
if (!groups.has(key)) {
|
|
145
|
-
groups.set(key, [])
|
|
146
|
-
}
|
|
147
|
-
groups.get(key)!.push(item)
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
return groups
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Count items by field value
|
|
155
|
-
*/
|
|
156
|
-
export function countByField<T, K extends keyof T>(items: T[], field: K): Map<T[K], number> {
|
|
157
|
-
const counts = new Map<T[K], number>()
|
|
158
|
-
|
|
159
|
-
for (const item of items) {
|
|
160
|
-
const key = item[field]
|
|
161
|
-
counts.set(key, (counts.get(key) || 0) + 1)
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
return counts
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
/**
|
|
168
|
-
* Get the first N items
|
|
169
|
-
*/
|
|
170
|
-
export function take<T>(items: T[], count: number): T[] {
|
|
171
|
-
return items.slice(0, count)
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
* Get the last N items
|
|
176
|
-
*/
|
|
177
|
-
export function takeLast<T>(items: T[], count: number): T[] {
|
|
178
|
-
return items.slice(-count)
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* Find item by field value
|
|
183
|
-
*/
|
|
184
|
-
export function findByField<T, K extends keyof T>(
|
|
185
|
-
items: T[],
|
|
186
|
-
field: K,
|
|
187
|
-
value: T[K]
|
|
188
|
-
): T | undefined {
|
|
189
|
-
return items.find((item) => item[field] === value)
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
/**
|
|
193
|
-
* Check if any item matches field value
|
|
194
|
-
*/
|
|
195
|
-
export function anyByField<T, K extends keyof T>(items: T[], field: K, value: T[K]): boolean {
|
|
196
|
-
return items.some((item) => item[field] === value)
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* Remove duplicates by field
|
|
201
|
-
*/
|
|
202
|
-
export function uniqueByField<T, K extends keyof T>(items: T[], field: K): T[] {
|
|
203
|
-
const seen = new Set<T[K]>()
|
|
204
|
-
return items.filter((item) => {
|
|
205
|
-
if (seen.has(item[field])) return false
|
|
206
|
-
seen.add(item[field])
|
|
207
|
-
return true
|
|
208
|
-
})
|
|
209
|
-
}
|
|
@@ -1,176 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Date Helper - Centralized date operations and formatting
|
|
3
|
-
*
|
|
4
|
-
* Eliminates duplicated date logic across:
|
|
5
|
-
* - session-manager.ts (_getDateKey, _getTodayKey)
|
|
6
|
-
* - path-manager.ts (getSessionPath date formatting)
|
|
7
|
-
* - commands.ts (38+ inline date operations)
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import { formatDistanceToNowStrict } from 'date-fns'
|
|
11
|
-
import type { DateComponents } from '../types'
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Format a date to YYYY-MM-DD format
|
|
15
|
-
*/
|
|
16
|
-
export function formatDate(date: Date): string {
|
|
17
|
-
const year = date.getFullYear()
|
|
18
|
-
const month = (date.getMonth() + 1).toString().padStart(2, '0')
|
|
19
|
-
const day = date.getDate().toString().padStart(2, '0')
|
|
20
|
-
return `${year}-${month}-${day}`
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Format a date to YYYY-MM format
|
|
25
|
-
*/
|
|
26
|
-
export function formatMonth(date: Date): string {
|
|
27
|
-
const year = date.getFullYear()
|
|
28
|
-
const month = (date.getMonth() + 1).toString().padStart(2, '0')
|
|
29
|
-
return `${year}-${month}`
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Get date key for today (YYYY-MM-DD)
|
|
34
|
-
*/
|
|
35
|
-
export function getTodayKey(): string {
|
|
36
|
-
return formatDate(new Date())
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Get date key for any date (YYYY-MM-DD)
|
|
41
|
-
* Alias for formatDate for consistency with session-manager
|
|
42
|
-
*/
|
|
43
|
-
export function getDateKey(date: Date): string {
|
|
44
|
-
return formatDate(date)
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Get year, month, day components from a date
|
|
49
|
-
* Useful for path construction
|
|
50
|
-
*/
|
|
51
|
-
export function getYearMonthDay(date: Date): DateComponents {
|
|
52
|
-
return {
|
|
53
|
-
year: date.getFullYear().toString(),
|
|
54
|
-
month: (date.getMonth() + 1).toString().padStart(2, '0'),
|
|
55
|
-
day: date.getDate().toString().padStart(2, '0'),
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Parse a date string to Date object
|
|
61
|
-
* Supports: YYYY-MM-DD, YYYY-MM, ISO strings
|
|
62
|
-
*/
|
|
63
|
-
export function parseDate(dateString: string): Date {
|
|
64
|
-
return new Date(dateString)
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Get current timestamp in ISO format
|
|
69
|
-
*/
|
|
70
|
-
export function getTimestamp(): string {
|
|
71
|
-
return new Date().toISOString()
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Get date N days ago from today
|
|
76
|
-
*/
|
|
77
|
-
export function getDaysAgo(days: number): Date {
|
|
78
|
-
const date = new Date()
|
|
79
|
-
date.setDate(date.getDate() - days)
|
|
80
|
-
return date
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Get date N days from today
|
|
85
|
-
*/
|
|
86
|
-
export function getDaysFromNow(days: number): Date {
|
|
87
|
-
const date = new Date()
|
|
88
|
-
date.setDate(date.getDate() + days)
|
|
89
|
-
return date
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Get date range between two dates
|
|
94
|
-
*/
|
|
95
|
-
export function getDateRange(fromDate: Date, toDate: Date): Date[] {
|
|
96
|
-
const dates: Date[] = []
|
|
97
|
-
let current = new Date(fromDate)
|
|
98
|
-
|
|
99
|
-
while (current <= toDate) {
|
|
100
|
-
dates.push(new Date(current))
|
|
101
|
-
current = new Date(current.getFullYear(), current.getMonth(), current.getDate() + 1)
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
return dates
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Check if a date is today
|
|
109
|
-
*/
|
|
110
|
-
export function isToday(date: Date): boolean {
|
|
111
|
-
return formatDate(date) === getTodayKey()
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Check if a date is within the last N days
|
|
116
|
-
*/
|
|
117
|
-
export function isWithinLastDays(date: Date, days: number): boolean {
|
|
118
|
-
const threshold = getDaysAgo(days)
|
|
119
|
-
return date >= threshold
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* Format duration in human-readable format
|
|
124
|
-
*/
|
|
125
|
-
export function formatDuration(milliseconds: number): string {
|
|
126
|
-
const seconds = Math.floor(milliseconds / 1000)
|
|
127
|
-
const minutes = Math.floor(seconds / 60)
|
|
128
|
-
const hours = Math.floor(minutes / 60)
|
|
129
|
-
const days = Math.floor(hours / 24)
|
|
130
|
-
|
|
131
|
-
if (days > 0) {
|
|
132
|
-
return `${days}d ${hours % 24}h`
|
|
133
|
-
}
|
|
134
|
-
if (hours > 0) {
|
|
135
|
-
return `${hours}h ${minutes % 60}m`
|
|
136
|
-
}
|
|
137
|
-
if (minutes > 0) {
|
|
138
|
-
return `${minutes}m`
|
|
139
|
-
}
|
|
140
|
-
return `${seconds}s`
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* Calculate duration between two dates
|
|
145
|
-
*/
|
|
146
|
-
export function calculateDuration(startDate: Date, endDate: Date = new Date()): string {
|
|
147
|
-
const milliseconds = endDate.getTime() - startDate.getTime()
|
|
148
|
-
return formatDuration(milliseconds)
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* Get start of day (00:00:00.000)
|
|
153
|
-
*/
|
|
154
|
-
export function getStartOfDay(date: Date): Date {
|
|
155
|
-
const result = new Date(date)
|
|
156
|
-
result.setHours(0, 0, 0, 0)
|
|
157
|
-
return result
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* Get end of day (23:59:59.999)
|
|
162
|
-
*/
|
|
163
|
-
export function getEndOfDay(date: Date): Date {
|
|
164
|
-
const result = new Date(date)
|
|
165
|
-
result.setHours(23, 59, 59, 999)
|
|
166
|
-
return result
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Convert a date/timestamp to a relative string (e.g. "5 minutes ago").
|
|
171
|
-
* Uses date-fns formatDistanceToNowStrict for accurate, token-friendly output.
|
|
172
|
-
*/
|
|
173
|
-
export function toRelative(date: string | Date): string {
|
|
174
|
-
const d = typeof date === 'string' ? new Date(date) : date
|
|
175
|
-
return formatDistanceToNowStrict(d, { addSuffix: true })
|
|
176
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Error Messages Catalog
|
|
3
|
-
*
|
|
4
|
-
* Centralized error messages with context and recovery hints.
|
|
5
|
-
* Types and catalog live in core/types/errors.ts.
|
|
6
|
-
*
|
|
7
|
-
* @see PRJ-131
|
|
8
|
-
* @module utils/error-messages
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import type { ErrorCode, ErrorWithHint } from '../types/errors'
|
|
12
|
-
import { ERRORS } from '../types/errors'
|
|
13
|
-
|
|
14
|
-
export type { ErrorCode, ErrorWithHint } from '../types/errors'
|
|
15
|
-
export { ERRORS } from '../types/errors'
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Get error with optional overrides
|
|
19
|
-
*/
|
|
20
|
-
export function getError(code: ErrorCode, overrides?: Partial<ErrorWithHint>): ErrorWithHint {
|
|
21
|
-
const base = ERRORS[code]
|
|
22
|
-
return { ...base, ...overrides }
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Create a custom error with hint
|
|
27
|
-
*/
|
|
28
|
-
export function createError(
|
|
29
|
-
message: string,
|
|
30
|
-
hint?: string,
|
|
31
|
-
options?: { file?: string; docs?: string }
|
|
32
|
-
): ErrorWithHint {
|
|
33
|
-
return {
|
|
34
|
-
message,
|
|
35
|
-
hint,
|
|
36
|
-
...options,
|
|
37
|
-
}
|
|
38
|
-
}
|
|
@@ -1,277 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs/promises'
|
|
2
|
-
import path from 'node:path'
|
|
3
|
-
import { safeRead, type ValidationSchema } from '../storage/safe-reader'
|
|
4
|
-
import { isNotFoundError } from '../types/fs'
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* File Helper - Centralized file operations with error handling
|
|
8
|
-
*
|
|
9
|
-
* Eliminates duplicated fs operations across:
|
|
10
|
-
* - 101 fs.readFile/writeFile calls in 18 files
|
|
11
|
-
* - Consistent error handling
|
|
12
|
-
* - JSON read/write patterns
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
interface ListFilesOptions {
|
|
16
|
-
filesOnly?: boolean
|
|
17
|
-
dirsOnly?: boolean
|
|
18
|
-
extension?: string
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Read JSON file and parse.
|
|
23
|
-
* When a Zod schema is provided, validates the data and creates a .backup on corruption.
|
|
24
|
-
*/
|
|
25
|
-
export async function readJson<T = unknown>(
|
|
26
|
-
filePath: string,
|
|
27
|
-
defaultValue: T | null = null,
|
|
28
|
-
schema?: ValidationSchema
|
|
29
|
-
): Promise<T | null> {
|
|
30
|
-
if (schema) {
|
|
31
|
-
const data = await safeRead<T>(filePath, schema)
|
|
32
|
-
return data ?? defaultValue
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
try {
|
|
36
|
-
const content = await fs.readFile(filePath, 'utf-8')
|
|
37
|
-
return JSON.parse(content) as T
|
|
38
|
-
} catch (error) {
|
|
39
|
-
if (isNotFoundError(error)) {
|
|
40
|
-
return defaultValue
|
|
41
|
-
}
|
|
42
|
-
throw error
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Write object to JSON file (pretty-printed)
|
|
48
|
-
*/
|
|
49
|
-
export async function writeJson(filePath: string, data: unknown, indent = 2): Promise<void> {
|
|
50
|
-
const content = JSON.stringify(data, null, indent)
|
|
51
|
-
await fs.writeFile(filePath, content, 'utf-8')
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Read text file
|
|
56
|
-
*/
|
|
57
|
-
export async function readFile(filePath: string, defaultValue = ''): Promise<string> {
|
|
58
|
-
try {
|
|
59
|
-
return await fs.readFile(filePath, 'utf-8')
|
|
60
|
-
} catch (error) {
|
|
61
|
-
if (isNotFoundError(error)) {
|
|
62
|
-
return defaultValue
|
|
63
|
-
}
|
|
64
|
-
throw error
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Write text file
|
|
70
|
-
*/
|
|
71
|
-
export async function writeFile(filePath: string, content: string): Promise<void> {
|
|
72
|
-
const dir = path.dirname(filePath)
|
|
73
|
-
await fs.mkdir(dir, { recursive: true })
|
|
74
|
-
await fs.writeFile(filePath, content, 'utf-8')
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Atomic write - writes to temp file then renames (prevents partial writes)
|
|
79
|
-
*/
|
|
80
|
-
export async function atomicWrite(filePath: string, content: string): Promise<void> {
|
|
81
|
-
const dir = path.dirname(filePath)
|
|
82
|
-
await fs.mkdir(dir, { recursive: true })
|
|
83
|
-
const tempPath = `${filePath}.${Date.now()}.tmp`
|
|
84
|
-
await fs.writeFile(tempPath, content, 'utf-8')
|
|
85
|
-
await fs.rename(tempPath, filePath)
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Append to text file
|
|
90
|
-
*/
|
|
91
|
-
export async function appendToFile(filePath: string, content: string): Promise<void> {
|
|
92
|
-
await fs.appendFile(filePath, content, 'utf-8')
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Append a single line to file (with newline and directory creation)
|
|
97
|
-
*/
|
|
98
|
-
export async function appendLine(filePath: string, line: string): Promise<void> {
|
|
99
|
-
const dir = path.dirname(filePath)
|
|
100
|
-
await fs.mkdir(dir, { recursive: true })
|
|
101
|
-
await fs.appendFile(filePath, `${line}\n`, 'utf-8')
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Prepend to text file (adds content at beginning)
|
|
106
|
-
*/
|
|
107
|
-
export async function prependToFile(filePath: string, content: string): Promise<void> {
|
|
108
|
-
try {
|
|
109
|
-
const existing = await fs.readFile(filePath, 'utf-8')
|
|
110
|
-
await fs.writeFile(filePath, content + existing, 'utf-8')
|
|
111
|
-
} catch (error) {
|
|
112
|
-
if (isNotFoundError(error)) {
|
|
113
|
-
await fs.writeFile(filePath, content, 'utf-8')
|
|
114
|
-
} else {
|
|
115
|
-
throw error
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Check if file exists
|
|
122
|
-
*/
|
|
123
|
-
export async function fileExists(filePath: string): Promise<boolean> {
|
|
124
|
-
try {
|
|
125
|
-
await fs.access(filePath)
|
|
126
|
-
return true
|
|
127
|
-
} catch (error) {
|
|
128
|
-
if (isNotFoundError(error)) {
|
|
129
|
-
return false
|
|
130
|
-
}
|
|
131
|
-
throw error
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* Check if directory exists
|
|
137
|
-
*/
|
|
138
|
-
export async function dirExists(dirPath: string): Promise<boolean> {
|
|
139
|
-
try {
|
|
140
|
-
const stats = await fs.stat(dirPath)
|
|
141
|
-
return stats.isDirectory()
|
|
142
|
-
} catch (error) {
|
|
143
|
-
if (isNotFoundError(error)) {
|
|
144
|
-
return false
|
|
145
|
-
}
|
|
146
|
-
throw error
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* Ensure directory exists (create if not)
|
|
152
|
-
*/
|
|
153
|
-
export async function ensureDir(dirPath: string): Promise<void> {
|
|
154
|
-
await fs.mkdir(dirPath, { recursive: true })
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Delete file if it exists
|
|
159
|
-
*/
|
|
160
|
-
export async function deleteFile(filePath: string): Promise<boolean> {
|
|
161
|
-
try {
|
|
162
|
-
await fs.unlink(filePath)
|
|
163
|
-
return true
|
|
164
|
-
} catch (error) {
|
|
165
|
-
if (isNotFoundError(error)) {
|
|
166
|
-
return false // File didn't exist
|
|
167
|
-
}
|
|
168
|
-
throw error
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Delete directory and all contents
|
|
174
|
-
*/
|
|
175
|
-
export async function deleteDir(dirPath: string): Promise<boolean> {
|
|
176
|
-
try {
|
|
177
|
-
await fs.rm(dirPath, { recursive: true, force: true })
|
|
178
|
-
return true
|
|
179
|
-
} catch (error) {
|
|
180
|
-
if (isNotFoundError(error)) {
|
|
181
|
-
return false
|
|
182
|
-
}
|
|
183
|
-
throw error
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
/**
|
|
188
|
-
* List files in directory
|
|
189
|
-
*/
|
|
190
|
-
export async function listFiles(
|
|
191
|
-
dirPath: string,
|
|
192
|
-
options: ListFilesOptions = {}
|
|
193
|
-
): Promise<string[]> {
|
|
194
|
-
try {
|
|
195
|
-
const entries = await fs.readdir(dirPath, { withFileTypes: true })
|
|
196
|
-
let files = entries
|
|
197
|
-
|
|
198
|
-
if (options.filesOnly) {
|
|
199
|
-
files = files.filter((entry) => entry.isFile())
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
if (options.dirsOnly) {
|
|
203
|
-
files = files.filter((entry) => entry.isDirectory())
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
if (options.extension) {
|
|
207
|
-
files = files.filter((entry) => entry.name.endsWith(options.extension!))
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
return files.map((entry) => entry.name)
|
|
211
|
-
} catch (error) {
|
|
212
|
-
if (isNotFoundError(error)) {
|
|
213
|
-
return []
|
|
214
|
-
}
|
|
215
|
-
throw error
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
/**
|
|
220
|
-
* Get file size in bytes
|
|
221
|
-
*/
|
|
222
|
-
export async function getFileSize(filePath: string): Promise<number> {
|
|
223
|
-
const stats = await fs.stat(filePath)
|
|
224
|
-
return stats.size
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
/**
|
|
228
|
-
* Get file modification time
|
|
229
|
-
*/
|
|
230
|
-
export async function getFileModifiedTime(filePath: string): Promise<Date> {
|
|
231
|
-
const stats = await fs.stat(filePath)
|
|
232
|
-
return stats.mtime
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
/**
|
|
236
|
-
* Copy file
|
|
237
|
-
*/
|
|
238
|
-
export async function copyFile(sourcePath: string, destPath: string): Promise<void> {
|
|
239
|
-
await fs.copyFile(sourcePath, destPath)
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
/**
|
|
243
|
-
* Move/rename file
|
|
244
|
-
*/
|
|
245
|
-
export async function moveFile(oldPath: string, newPath: string): Promise<void> {
|
|
246
|
-
await fs.rename(oldPath, newPath)
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
/**
|
|
250
|
-
* Read file and split into lines
|
|
251
|
-
*/
|
|
252
|
-
export async function readLines(filePath: string): Promise<string[]> {
|
|
253
|
-
const content = await readFile(filePath, '')
|
|
254
|
-
return content.split('\n')
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
/**
|
|
258
|
-
* Write lines to file
|
|
259
|
-
*/
|
|
260
|
-
export async function writeLines(filePath: string, lines: string[]): Promise<void> {
|
|
261
|
-
const content = lines.join('\n')
|
|
262
|
-
await writeFile(filePath, content)
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
/**
|
|
266
|
-
* Get file extension
|
|
267
|
-
*/
|
|
268
|
-
export function getFileExtension(filePath: string): string {
|
|
269
|
-
return path.extname(filePath)
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
/**
|
|
273
|
-
* Get filename without extension
|
|
274
|
-
*/
|
|
275
|
-
export function getFileNameWithoutExtension(filePath: string): string {
|
|
276
|
-
return path.basename(filePath, path.extname(filePath))
|
|
277
|
-
}
|
package/core/utils/fs-helpers.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs/promises'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Async check if a file/directory exists
|
|
5
|
-
* Replacement for fs.existsSync
|
|
6
|
-
*/
|
|
7
|
-
export async function fileExists(filePath: string): Promise<boolean> {
|
|
8
|
-
try {
|
|
9
|
-
await fs.access(filePath)
|
|
10
|
-
return true
|
|
11
|
-
} catch {
|
|
12
|
-
return false
|
|
13
|
-
}
|
|
14
|
-
}
|