prjct-cli 1.22.0 → 1.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +147 -0
- package/bin/prjct +30 -13
- package/dist/bin/prjct.mjs +917 -35845
- package/dist/bin/prjct.mjs.map +7 -0
- package/dist/cli/linear.mjs +16 -0
- package/dist/cli/linear.mjs.map +7 -0
- package/dist/templates.json +1 -0
- package/package.json +4 -5
- package/bin/prjct.ts +0 -342
- package/core/__tests__/agentic/analysis-injection.test.ts +0 -377
- package/core/__tests__/agentic/cache-eviction.test.ts +0 -294
- package/core/__tests__/agentic/command-context.test.ts +0 -281
- package/core/__tests__/agentic/command-executor.test.ts +0 -659
- package/core/__tests__/agentic/domain-classifier.test.ts +0 -330
- package/core/__tests__/agentic/injection-validator.test.ts +0 -255
- package/core/__tests__/agentic/memory-system.test.ts +0 -281
- package/core/__tests__/agentic/plan-mode.test.ts +0 -386
- package/core/__tests__/agentic/prompt-assembly.test.ts +0 -298
- package/core/__tests__/agentic/prompt-builder.test.ts +0 -243
- package/core/__tests__/agentic/response-validator.test.ts +0 -263
- package/core/__tests__/agentic/semantic-matching.test.ts +0 -131
- package/core/__tests__/agentic/smart-context.test.ts +0 -372
- package/core/__tests__/agentic/tech-normalizer.test.ts +0 -136
- package/core/__tests__/agentic/token-budget.test.ts +0 -294
- package/core/__tests__/ai-tools/formatters.test.ts +0 -476
- package/core/__tests__/domain/bm25.test.ts +0 -225
- package/core/__tests__/domain/change-propagator.test.ts +0 -100
- package/core/__tests__/domain/fibonacci.test.ts +0 -113
- package/core/__tests__/domain/file-hasher.test.ts +0 -146
- package/core/__tests__/domain/file-ranker.test.ts +0 -169
- package/core/__tests__/domain/git-cochange.test.ts +0 -121
- package/core/__tests__/domain/import-graph.test.ts +0 -156
- package/core/__tests__/domain/velocity.test.ts +0 -623
- package/core/__tests__/infrastructure/performance-tracker.test.ts +0 -328
- package/core/__tests__/schemas/model.test.ts +0 -272
- package/core/__tests__/services/dependency-validator.test.ts +0 -175
- package/core/__tests__/services/hierarchical-agent-resolver.test.ts +0 -359
- package/core/__tests__/services/nested-context-resolver.test.ts +0 -443
- package/core/__tests__/services/project-index.test.ts +0 -355
- package/core/__tests__/services/staleness-checker.test.ts +0 -204
- package/core/__tests__/storage/analysis-storage.test.ts +0 -641
- package/core/__tests__/storage/archive-storage.test.ts +0 -455
- package/core/__tests__/storage/safe-reader.test.ts +0 -262
- package/core/__tests__/storage/sqlite-migration.test.ts +0 -1016
- package/core/__tests__/storage/state-storage-feedback.test.ts +0 -463
- package/core/__tests__/storage/state-storage-history.test.ts +0 -469
- package/core/__tests__/storage/storage-manager.test.ts +0 -383
- package/core/__tests__/storage/subtask-handoff.test.ts +0 -237
- package/core/__tests__/types/fs.test.ts +0 -125
- package/core/__tests__/utils/date-helper.test.ts +0 -449
- package/core/__tests__/utils/output.test.ts +0 -278
- package/core/__tests__/utils/preserve-sections.test.ts +0 -216
- package/core/__tests__/utils/project-commands.test.ts +0 -71
- package/core/__tests__/utils/retry.test.ts +0 -381
- package/core/__tests__/workflow/state-machine.test.ts +0 -216
- package/core/agentic/agent-router.ts +0 -150
- package/core/agentic/anti-hallucination.ts +0 -141
- package/core/agentic/chain-of-thought.ts +0 -234
- package/core/agentic/command-classifier.ts +0 -141
- package/core/agentic/command-context.ts +0 -168
- package/core/agentic/command-executor.ts +0 -471
- package/core/agentic/context-builder.ts +0 -285
- package/core/agentic/domain-classifier.ts +0 -525
- package/core/agentic/environment-block.ts +0 -102
- package/core/agentic/ground-truth.ts +0 -706
- package/core/agentic/index.ts +0 -193
- package/core/agentic/injection-validator.ts +0 -208
- package/core/agentic/loop-detector.ts +0 -451
- package/core/agentic/memory-system.ts +0 -1547
- package/core/agentic/orchestrator-executor.ts +0 -579
- package/core/agentic/plan-mode.ts +0 -525
- package/core/agentic/prompt-builder.ts +0 -1069
- package/core/agentic/response-validator.ts +0 -98
- package/core/agentic/services.ts +0 -167
- package/core/agentic/skill-loader.ts +0 -106
- package/core/agentic/smart-context.ts +0 -393
- package/core/agentic/tech-normalizer.ts +0 -167
- package/core/agentic/template-executor.ts +0 -272
- package/core/agentic/template-loader.ts +0 -109
- package/core/agentic/token-budget.ts +0 -226
- package/core/agentic/tool-registry.ts +0 -146
- package/core/agents/index.ts +0 -28
- package/core/agents/performance.ts +0 -429
- package/core/ai-tools/formatters.ts +0 -341
- package/core/ai-tools/generator.ts +0 -144
- package/core/ai-tools/index.ts +0 -15
- package/core/ai-tools/registry.ts +0 -201
- package/core/bus/bus.ts +0 -314
- package/core/bus/index.ts +0 -8
- package/core/cli/linear.ts +0 -500
- package/core/cli/lint-meta-commentary.ts +0 -177
- package/core/cli/start.ts +0 -386
- package/core/commands/analysis.ts +0 -1274
- package/core/commands/analytics.ts +0 -342
- package/core/commands/base.ts +0 -118
- package/core/commands/cleanup.ts +0 -157
- package/core/commands/command-data.ts +0 -463
- package/core/commands/commands.ts +0 -306
- package/core/commands/context.ts +0 -238
- package/core/commands/design.ts +0 -77
- package/core/commands/index.ts +0 -19
- package/core/commands/maintenance.ts +0 -77
- package/core/commands/performance.ts +0 -114
- package/core/commands/planning.ts +0 -662
- package/core/commands/register.ts +0 -127
- package/core/commands/registry.ts +0 -444
- package/core/commands/setup.ts +0 -280
- package/core/commands/shipping.ts +0 -267
- package/core/commands/snapshots.ts +0 -297
- package/core/commands/uninstall.ts +0 -542
- package/core/commands/velocity.ts +0 -149
- package/core/commands/workflow.ts +0 -505
- package/core/config/command-context.config.json +0 -66
- package/core/constants/index.ts +0 -379
- package/core/context/generator.ts +0 -368
- package/core/context-tools/files-tool.ts +0 -577
- package/core/context-tools/imports-tool.ts +0 -400
- package/core/context-tools/index.ts +0 -434
- package/core/context-tools/recent-tool.ts +0 -301
- package/core/context-tools/signatures-tool.ts +0 -495
- package/core/context-tools/summary-tool.ts +0 -301
- package/core/context-tools/token-counter.ts +0 -273
- package/core/context-tools/types.ts +0 -253
- package/core/domain/agent-generator.ts +0 -186
- package/core/domain/agent-loader.ts +0 -419
- package/core/domain/analyzer.ts +0 -387
- package/core/domain/architecture-generator.ts +0 -108
- package/core/domain/bm25.ts +0 -525
- package/core/domain/change-propagator.ts +0 -162
- package/core/domain/context-estimator.ts +0 -175
- package/core/domain/fibonacci.ts +0 -128
- package/core/domain/file-hasher.ts +0 -296
- package/core/domain/file-ranker.ts +0 -151
- package/core/domain/git-cochange.ts +0 -250
- package/core/domain/import-graph.ts +0 -315
- package/core/domain/snapshot-manager.ts +0 -415
- package/core/domain/task-stack.ts +0 -578
- package/core/domain/velocity.ts +0 -470
- package/core/errors.ts +0 -335
- package/core/events/events.ts +0 -85
- package/core/events/index.ts +0 -8
- package/core/index.ts +0 -481
- package/core/infrastructure/agent-detector.ts +0 -135
- package/core/infrastructure/ai-provider.ts +0 -578
- package/core/infrastructure/author-detector.ts +0 -133
- package/core/infrastructure/capability-installer.ts +0 -76
- package/core/infrastructure/claude-agent.ts +0 -297
- package/core/infrastructure/command-installer.ts +0 -752
- package/core/infrastructure/config-manager.ts +0 -364
- package/core/infrastructure/editors-config.ts +0 -172
- package/core/infrastructure/path-manager.ts +0 -571
- package/core/infrastructure/performance-tracker.ts +0 -326
- package/core/infrastructure/permission-manager.ts +0 -289
- package/core/infrastructure/setup.ts +0 -1061
- package/core/infrastructure/update-checker.ts +0 -246
- package/core/integrations/issue-tracker/enricher.ts +0 -271
- package/core/integrations/issue-tracker/index.ts +0 -8
- package/core/integrations/issue-tracker/manager.ts +0 -286
- package/core/integrations/issue-tracker/types.ts +0 -310
- package/core/integrations/jira/cache.ts +0 -57
- package/core/integrations/jira/client.ts +0 -688
- package/core/integrations/jira/index.ts +0 -23
- package/core/integrations/jira/service.ts +0 -244
- package/core/integrations/linear/cache.ts +0 -68
- package/core/integrations/linear/client.ts +0 -436
- package/core/integrations/linear/index.ts +0 -20
- package/core/integrations/linear/service.ts +0 -260
- package/core/integrations/linear/sync.ts +0 -314
- package/core/outcomes/analyzer.ts +0 -286
- package/core/outcomes/index.ts +0 -34
- package/core/outcomes/recorder.ts +0 -195
- package/core/plugin/builtin/webhook.ts +0 -148
- package/core/plugin/hooks.ts +0 -315
- package/core/plugin/index.ts +0 -50
- package/core/plugin/loader.ts +0 -354
- package/core/plugin/registry.ts +0 -326
- package/core/schemas/agents.ts +0 -27
- package/core/schemas/analysis.ts +0 -530
- package/core/schemas/classification.ts +0 -91
- package/core/schemas/command-context.ts +0 -29
- package/core/schemas/enriched-task.ts +0 -291
- package/core/schemas/ideas.ts +0 -114
- package/core/schemas/index.ts +0 -53
- package/core/schemas/issues.ts +0 -159
- package/core/schemas/llm-output.ts +0 -170
- package/core/schemas/metrics.ts +0 -143
- package/core/schemas/model.ts +0 -153
- package/core/schemas/outcomes.ts +0 -487
- package/core/schemas/performance.ts +0 -128
- package/core/schemas/permissions.ts +0 -180
- package/core/schemas/prd.ts +0 -450
- package/core/schemas/project.ts +0 -57
- package/core/schemas/roadmap.ts +0 -322
- package/core/schemas/schemas.ts +0 -38
- package/core/schemas/shipped.ts +0 -109
- package/core/schemas/state.ts +0 -284
- package/core/schemas/velocity.ts +0 -103
- package/core/server/index.ts +0 -21
- package/core/server/routes-extended.ts +0 -566
- package/core/server/routes.ts +0 -176
- package/core/server/server.ts +0 -149
- package/core/server/sse.ts +0 -192
- package/core/services/agent-generator.ts +0 -385
- package/core/services/agent-service.ts +0 -168
- package/core/services/breakdown-service.ts +0 -124
- package/core/services/context-generator.ts +0 -445
- package/core/services/context-selector.ts +0 -429
- package/core/services/dependency-validator.ts +0 -318
- package/core/services/diff-generator.ts +0 -313
- package/core/services/doctor-service.ts +0 -423
- package/core/services/file-categorizer.ts +0 -448
- package/core/services/file-scorer.ts +0 -270
- package/core/services/git-analyzer.ts +0 -293
- package/core/services/hierarchical-agent-resolver.ts +0 -236
- package/core/services/hooks-service.ts +0 -685
- package/core/services/index.ts +0 -46
- package/core/services/local-state-generator.ts +0 -158
- package/core/services/memory-service.ts +0 -181
- package/core/services/nested-context-resolver.ts +0 -842
- package/core/services/project-index.ts +0 -911
- package/core/services/project-service.ts +0 -155
- package/core/services/session-tracker.ts +0 -287
- package/core/services/skill-installer.ts +0 -447
- package/core/services/skill-lock.ts +0 -132
- package/core/services/skill-service.ts +0 -306
- package/core/services/stack-detector.ts +0 -229
- package/core/services/staleness-checker.ts +0 -327
- package/core/services/sync-service.ts +0 -1515
- package/core/services/sync-verifier.ts +0 -253
- package/core/services/watch-service.ts +0 -312
- package/core/session/compaction.ts +0 -248
- package/core/session/index.ts +0 -35
- package/core/session/log-migration.ts +0 -88
- package/core/session/metrics.ts +0 -323
- package/core/session/session-log-manager.ts +0 -307
- package/core/session/task-session-manager.ts +0 -404
- package/core/session/utils.ts +0 -51
- package/core/storage/analysis-storage.ts +0 -373
- package/core/storage/archive-storage.ts +0 -205
- package/core/storage/database.ts +0 -575
- package/core/storage/ideas-storage.ts +0 -298
- package/core/storage/index-storage.ts +0 -523
- package/core/storage/index.ts +0 -79
- package/core/storage/metrics-storage.ts +0 -321
- package/core/storage/migrate-json.ts +0 -720
- package/core/storage/queue-storage.ts +0 -336
- package/core/storage/safe-reader.ts +0 -105
- package/core/storage/shipped-storage.ts +0 -253
- package/core/storage/state-storage.ts +0 -1035
- package/core/storage/storage-manager.ts +0 -205
- package/core/storage/storage.ts +0 -177
- package/core/storage/velocity-storage.ts +0 -149
- package/core/sync/auth-config.ts +0 -138
- package/core/sync/index.ts +0 -31
- package/core/sync/oauth-handler.ts +0 -143
- package/core/sync/sync-client.ts +0 -251
- package/core/sync/sync-manager.ts +0 -327
- package/core/tsconfig.json +0 -22
- package/core/types/agentic.ts +0 -760
- package/core/types/agents.ts +0 -150
- package/core/types/bus.ts +0 -193
- package/core/types/citations.ts +0 -22
- package/core/types/commands.ts +0 -399
- package/core/types/config.ts +0 -92
- package/core/types/core.ts +0 -96
- package/core/types/diff.ts +0 -41
- package/core/types/domain.ts +0 -71
- package/core/types/errors.ts +0 -111
- package/core/types/events.ts +0 -42
- package/core/types/fs.ts +0 -72
- package/core/types/index.ts +0 -510
- package/core/types/infrastructure.ts +0 -210
- package/core/types/integrations.ts +0 -31
- package/core/types/jira.ts +0 -51
- package/core/types/logger.ts +0 -17
- package/core/types/memory.ts +0 -313
- package/core/types/outcomes.ts +0 -190
- package/core/types/output.ts +0 -47
- package/core/types/plugin.ts +0 -25
- package/core/types/project-sync.ts +0 -129
- package/core/types/provider.ts +0 -163
- package/core/types/server.ts +0 -71
- package/core/types/services.ts +0 -84
- package/core/types/session.ts +0 -135
- package/core/types/stack.ts +0 -19
- package/core/types/storage.ts +0 -318
- package/core/types/sync-verifier.ts +0 -33
- package/core/types/sync.ts +0 -121
- package/core/types/task.ts +0 -72
- package/core/types/template.ts +0 -24
- package/core/types/utils.ts +0 -92
- package/core/types/workflow.ts +0 -23
- package/core/utils/agent-stream.ts +0 -140
- package/core/utils/animations.ts +0 -251
- package/core/utils/branding.ts +0 -88
- package/core/utils/cache.ts +0 -187
- package/core/utils/citations.ts +0 -39
- package/core/utils/collection-filters.ts +0 -209
- package/core/utils/date-helper.ts +0 -176
- package/core/utils/error-messages.ts +0 -38
- package/core/utils/file-helper.ts +0 -277
- package/core/utils/fs-helpers.ts +0 -14
- package/core/utils/help.ts +0 -314
- package/core/utils/jsonl-helper.ts +0 -290
- package/core/utils/keychain.ts +0 -127
- package/core/utils/logger.ts +0 -77
- package/core/utils/markdown-builder.ts +0 -280
- package/core/utils/next-steps.ts +0 -95
- package/core/utils/output.ts +0 -403
- package/core/utils/preserve-sections.ts +0 -218
- package/core/utils/project-commands.ts +0 -126
- package/core/utils/project-credentials.ts +0 -143
- package/core/utils/provider-cache.ts +0 -49
- package/core/utils/retry.ts +0 -318
- package/core/utils/runtime.ts +0 -108
- package/core/utils/session-helper.ts +0 -278
- package/core/utils/subtask-table.ts +0 -227
- package/core/utils/version.ts +0 -128
- package/core/wizard/index.ts +0 -13
- package/core/wizard/onboarding.ts +0 -633
- package/core/workflow/index.ts +0 -7
- package/core/workflow/state-machine.ts +0 -198
- package/core/workflow/workflow-preferences.ts +0 -294
- package/dist/core/infrastructure/command-installer.js +0 -1141
- package/dist/core/infrastructure/editors-config.js +0 -177
- package/dist/core/infrastructure/setup.js +0 -2244
- package/dist/core/utils/version.js +0 -141
- package/templates/agentic/agent-routing.md +0 -45
- package/templates/agentic/agents/uxui.md +0 -63
- package/templates/agentic/checklist-routing.md +0 -98
- package/templates/agentic/orchestrator.md +0 -68
- package/templates/agentic/task-fragmentation.md +0 -89
- package/templates/agents/AGENTS.md +0 -68
- package/templates/analysis/analyze.md +0 -84
- package/templates/analysis/patterns.md +0 -60
- package/templates/antigravity/SKILL.md +0 -39
- package/templates/architect/discovery.md +0 -67
- package/templates/architect/phases.md +0 -59
- package/templates/checklists/architecture.md +0 -28
- package/templates/checklists/code-quality.md +0 -28
- package/templates/checklists/data.md +0 -33
- package/templates/checklists/documentation.md +0 -33
- package/templates/checklists/infrastructure.md +0 -33
- package/templates/checklists/performance.md +0 -33
- package/templates/checklists/security.md +0 -33
- package/templates/checklists/testing.md +0 -33
- package/templates/checklists/ux-ui.md +0 -37
- package/templates/commands/analyze.md +0 -56
- package/templates/commands/auth.md +0 -234
- package/templates/commands/bug.md +0 -163
- package/templates/commands/cleanup.md +0 -19
- package/templates/commands/dash.md +0 -99
- package/templates/commands/design.md +0 -15
- package/templates/commands/done.md +0 -291
- package/templates/commands/enrich.md +0 -174
- package/templates/commands/git.md +0 -295
- package/templates/commands/history.md +0 -389
- package/templates/commands/idea.md +0 -88
- package/templates/commands/impact.md +0 -864
- package/templates/commands/init.md +0 -54
- package/templates/commands/jira.md +0 -278
- package/templates/commands/linear.md +0 -288
- package/templates/commands/merge.md +0 -206
- package/templates/commands/next.md +0 -80
- package/templates/commands/p.md +0 -67
- package/templates/commands/p.toml +0 -37
- package/templates/commands/pause.md +0 -136
- package/templates/commands/plan.md +0 -696
- package/templates/commands/prd.md +0 -356
- package/templates/commands/resume.md +0 -171
- package/templates/commands/review.md +0 -276
- package/templates/commands/serve.md +0 -118
- package/templates/commands/setup.md +0 -91
- package/templates/commands/ship.md +0 -475
- package/templates/commands/skill.md +0 -259
- package/templates/commands/spec.md +0 -218
- package/templates/commands/status.md +0 -207
- package/templates/commands/sync.md +0 -104
- package/templates/commands/task.md +0 -312
- package/templates/commands/test.md +0 -93
- package/templates/commands/update.md +0 -63
- package/templates/commands/verify.md +0 -204
- package/templates/commands/workflow.md +0 -150
- package/templates/config/skill-mappings.json +0 -82
- package/templates/context/dashboard.md +0 -256
- package/templates/context/roadmap.md +0 -221
- package/templates/cursor/commands/bug.md +0 -8
- package/templates/cursor/commands/done.md +0 -4
- package/templates/cursor/commands/pause.md +0 -6
- package/templates/cursor/commands/resume.md +0 -4
- package/templates/cursor/commands/ship.md +0 -8
- package/templates/cursor/commands/sync.md +0 -4
- package/templates/cursor/commands/task.md +0 -8
- package/templates/cursor/p.md +0 -29
- package/templates/cursor/router.mdc +0 -28
- package/templates/design/api.md +0 -95
- package/templates/design/architecture.md +0 -77
- package/templates/design/component.md +0 -89
- package/templates/design/database.md +0 -78
- package/templates/design/flow.md +0 -94
- package/templates/global/ANTIGRAVITY.md +0 -254
- package/templates/global/CLAUDE.md +0 -497
- package/templates/global/CURSOR.mdc +0 -266
- package/templates/global/GEMINI.md +0 -293
- package/templates/global/STORAGE-SPEC.md +0 -391
- package/templates/global/WINDSURF.md +0 -266
- package/templates/global/modules/CLAUDE-commands.md +0 -70
- package/templates/global/modules/CLAUDE-core.md +0 -105
- package/templates/global/modules/CLAUDE-git.md +0 -50
- package/templates/global/modules/CLAUDE-intelligence.md +0 -92
- package/templates/global/modules/CLAUDE-storage.md +0 -50
- package/templates/global/modules/module-config.json +0 -36
- package/templates/mcp-config.json +0 -19
- package/templates/permissions/default.jsonc +0 -60
- package/templates/permissions/permissive.jsonc +0 -49
- package/templates/permissions/strict.jsonc +0 -58
- package/templates/planning-methodology.md +0 -195
- package/templates/skills/code-review.md +0 -47
- package/templates/skills/debug.md +0 -61
- package/templates/skills/refactor.md +0 -47
- package/templates/subagents/agent-base.md +0 -20
- package/templates/subagents/domain/backend.md +0 -109
- package/templates/subagents/domain/database.md +0 -121
- package/templates/subagents/domain/devops.md +0 -152
- package/templates/subagents/domain/frontend.md +0 -103
- package/templates/subagents/domain/testing.md +0 -169
- package/templates/subagents/pm-expert.md +0 -366
- package/templates/subagents/workflow/chief-architect.md +0 -657
- package/templates/subagents/workflow/prjct-planner.md +0 -159
- package/templates/subagents/workflow/prjct-shipper.md +0 -188
- package/templates/subagents/workflow/prjct-workflow.md +0 -98
- package/templates/tools/bash.txt +0 -22
- package/templates/tools/edit.txt +0 -18
- package/templates/tools/glob.txt +0 -19
- package/templates/tools/grep.txt +0 -21
- package/templates/tools/read.txt +0 -14
- package/templates/tools/task.txt +0 -20
- package/templates/tools/webfetch.txt +0 -16
- package/templates/tools/websearch.txt +0 -18
- package/templates/tools/write.txt +0 -17
- package/templates/windsurf/router.md +0 -28
- package/templates/windsurf/workflows/bug.md +0 -8
- package/templates/windsurf/workflows/done.md +0 -4
- package/templates/windsurf/workflows/pause.md +0 -4
- package/templates/windsurf/workflows/resume.md +0 -4
- package/templates/windsurf/workflows/ship.md +0 -8
- package/templates/windsurf/workflows/sync.md +0 -4
- package/templates/windsurf/workflows/task.md +0 -8
package/core/utils/runtime.ts
DELETED
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Runtime Detection Utility
|
|
3
|
-
*
|
|
4
|
-
* Detects available JavaScript runtimes and provides utilities
|
|
5
|
-
* for runtime-agnostic code execution.
|
|
6
|
-
*
|
|
7
|
-
* @version 1.0.0
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import type { Runtime } from '../types'
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Detect the current JavaScript runtime
|
|
14
|
-
*/
|
|
15
|
-
export function detectRuntime(): Runtime {
|
|
16
|
-
// Check for Bun-specific global
|
|
17
|
-
if (typeof globalThis !== 'undefined' && 'Bun' in globalThis) {
|
|
18
|
-
return 'bun'
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
return 'node'
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Check if Bun is available on the system
|
|
26
|
-
*/
|
|
27
|
-
export function isBunAvailable(): boolean {
|
|
28
|
-
// If we're already running in Bun, it's available
|
|
29
|
-
if (detectRuntime() === 'bun') {
|
|
30
|
-
return true
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// Check if bun command exists in PATH
|
|
34
|
-
try {
|
|
35
|
-
const { execSync } = require('node:child_process')
|
|
36
|
-
execSync('bun --version', { stdio: 'ignore' })
|
|
37
|
-
return true
|
|
38
|
-
} catch (_error) {
|
|
39
|
-
return false
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Check if Node is available on the system
|
|
45
|
-
*/
|
|
46
|
-
export function isNodeAvailable(): boolean {
|
|
47
|
-
// If we're running, Node is available (either native or via Bun's node compat)
|
|
48
|
-
return true
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Get runtime version
|
|
53
|
-
*/
|
|
54
|
-
export function getRuntimeVersion(): string {
|
|
55
|
-
const runtime = detectRuntime()
|
|
56
|
-
|
|
57
|
-
if (runtime === 'bun') {
|
|
58
|
-
return `bun ${Bun.version || 'unknown'}`
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
return `node ${process.version}`
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Check if we're running in a Bun environment
|
|
66
|
-
*/
|
|
67
|
-
export function isBun(): boolean {
|
|
68
|
-
return detectRuntime() === 'bun'
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Check if we're running in a Node environment
|
|
73
|
-
*/
|
|
74
|
-
export function isNode(): boolean {
|
|
75
|
-
return detectRuntime() === 'node'
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Get the preferred runtime for execution
|
|
80
|
-
* Returns 'bun' if available, otherwise 'node'
|
|
81
|
-
*/
|
|
82
|
-
export function getPreferredRuntime(): Runtime {
|
|
83
|
-
if (isBunAvailable()) {
|
|
84
|
-
return 'bun'
|
|
85
|
-
}
|
|
86
|
-
return 'node'
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Get command to run a script with the appropriate runtime
|
|
91
|
-
*/
|
|
92
|
-
export function getRunCommand(scriptPath: string, args: string[] = []): string {
|
|
93
|
-
const runtime = getPreferredRuntime()
|
|
94
|
-
const argsStr = args.length > 0 ? ` ${args.join(' ')}` : ''
|
|
95
|
-
|
|
96
|
-
if (runtime === 'bun') {
|
|
97
|
-
return `bun ${scriptPath}${argsStr}`
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// For Node, check if it's a .ts file
|
|
101
|
-
if (scriptPath.endsWith('.ts')) {
|
|
102
|
-
// Use compiled version
|
|
103
|
-
const jsPath = scriptPath.replace(/\.ts$/, '.js').replace('/bin/', '/dist/bin/')
|
|
104
|
-
return `node ${jsPath}${argsStr}`
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
return `node ${scriptPath}${argsStr}`
|
|
108
|
-
}
|
|
@@ -1,278 +0,0 @@
|
|
|
1
|
-
import path from 'node:path'
|
|
2
|
-
import { getErrorMessage } from '../types/fs'
|
|
3
|
-
import * as dateHelper from './date-helper'
|
|
4
|
-
import * as fileHelper from './file-helper'
|
|
5
|
-
import * as jsonlHelper from './jsonl-helper'
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Session Helper - High-level session operations
|
|
9
|
-
*
|
|
10
|
-
* Simplifies common session workflows by combining:
|
|
11
|
-
* - date-helper (date formatting)
|
|
12
|
-
* - jsonl-helper (JSONL parsing)
|
|
13
|
-
* - file-helper (file operations)
|
|
14
|
-
* - path-manager (path construction)
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
interface SessionEntry {
|
|
18
|
-
ts?: string
|
|
19
|
-
timestamp?: string
|
|
20
|
-
type?: string
|
|
21
|
-
[key: string]: unknown
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
interface SessionStats {
|
|
25
|
-
totalEntries: number
|
|
26
|
-
byType: Record<string, number>
|
|
27
|
-
byDate: Record<string, number>
|
|
28
|
-
activeDays: number
|
|
29
|
-
averagePerDay: number
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
interface ArchiveResult {
|
|
33
|
-
archived: number
|
|
34
|
-
files: string[]
|
|
35
|
-
errors: Array<{ filename: string; error: string }>
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Build session file path for today
|
|
40
|
-
*/
|
|
41
|
-
export function getTodaySessionFilePath(
|
|
42
|
-
projectGlobalPath: string,
|
|
43
|
-
layer: string,
|
|
44
|
-
filename: string | null = null
|
|
45
|
-
): string {
|
|
46
|
-
const today = dateHelper.getTodayKey()
|
|
47
|
-
const yearMonth = dateHelper.formatMonth(new Date())
|
|
48
|
-
const [year, month] = yearMonth.split('-')
|
|
49
|
-
|
|
50
|
-
const sessionDir = path.join(projectGlobalPath, layer, 'sessions', year, month)
|
|
51
|
-
|
|
52
|
-
if (filename) {
|
|
53
|
-
return path.join(sessionDir, filename)
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
return path.join(sessionDir, `${today}.jsonl`)
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Ensure today's session directory exists
|
|
61
|
-
*/
|
|
62
|
-
export async function ensureTodaySessionDir(
|
|
63
|
-
projectGlobalPath: string,
|
|
64
|
-
layer: string
|
|
65
|
-
): Promise<string> {
|
|
66
|
-
const yearMonth = dateHelper.formatMonth(new Date())
|
|
67
|
-
const [year, month] = yearMonth.split('-')
|
|
68
|
-
|
|
69
|
-
const sessionDir = path.join(projectGlobalPath, layer, 'sessions', year, month)
|
|
70
|
-
await fileHelper.ensureDir(sessionDir)
|
|
71
|
-
|
|
72
|
-
return sessionDir
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Write log entry to today's session
|
|
77
|
-
*/
|
|
78
|
-
export async function writeToSession(
|
|
79
|
-
projectGlobalPath: string,
|
|
80
|
-
layer: string,
|
|
81
|
-
entry: SessionEntry,
|
|
82
|
-
filename: string | null = null
|
|
83
|
-
): Promise<void> {
|
|
84
|
-
await ensureTodaySessionDir(projectGlobalPath, layer)
|
|
85
|
-
|
|
86
|
-
const filePath = getTodaySessionFilePath(projectGlobalPath, layer, filename)
|
|
87
|
-
|
|
88
|
-
// Add timestamp if not present
|
|
89
|
-
if (!entry.ts && !entry.timestamp) {
|
|
90
|
-
entry.ts = dateHelper.getTimestamp()
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
await jsonlHelper.appendJsonLine(filePath, entry)
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Read today's session logs
|
|
98
|
-
*/
|
|
99
|
-
export async function readTodaySession<T = SessionEntry>(
|
|
100
|
-
projectGlobalPath: string,
|
|
101
|
-
layer: string,
|
|
102
|
-
filename: string | null = null
|
|
103
|
-
): Promise<T[]> {
|
|
104
|
-
const filePath = getTodaySessionFilePath(projectGlobalPath, layer, filename)
|
|
105
|
-
return await jsonlHelper.readJsonLines<T>(filePath)
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Read session logs for a date range
|
|
110
|
-
*/
|
|
111
|
-
export async function readRecentSessions<T = SessionEntry>(
|
|
112
|
-
projectGlobalPath: string,
|
|
113
|
-
layer: string,
|
|
114
|
-
daysBack = 7
|
|
115
|
-
): Promise<T[]> {
|
|
116
|
-
const fromDate = dateHelper.getDaysAgo(daysBack)
|
|
117
|
-
const toDate = new Date()
|
|
118
|
-
|
|
119
|
-
const dates = dateHelper.getDateRange(fromDate, toDate)
|
|
120
|
-
const allEntries: T[] = []
|
|
121
|
-
|
|
122
|
-
for (const date of dates) {
|
|
123
|
-
const yearMonth = dateHelper.formatMonth(date)
|
|
124
|
-
const dateKey = dateHelper.getDateKey(date)
|
|
125
|
-
const [year, month] = yearMonth.split('-')
|
|
126
|
-
|
|
127
|
-
const filePath = path.join(
|
|
128
|
-
projectGlobalPath,
|
|
129
|
-
layer,
|
|
130
|
-
'sessions',
|
|
131
|
-
year,
|
|
132
|
-
month,
|
|
133
|
-
`${dateKey}.jsonl`
|
|
134
|
-
)
|
|
135
|
-
|
|
136
|
-
const entries = await jsonlHelper.readJsonLines<T>(filePath)
|
|
137
|
-
allEntries.push(...entries)
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
return allEntries
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* Get session statistics for a layer
|
|
145
|
-
*/
|
|
146
|
-
export async function getSessionStats(
|
|
147
|
-
projectGlobalPath: string,
|
|
148
|
-
layer: string,
|
|
149
|
-
daysBack = 30
|
|
150
|
-
): Promise<SessionStats> {
|
|
151
|
-
const entries = await readRecentSessions<SessionEntry>(projectGlobalPath, layer, daysBack)
|
|
152
|
-
|
|
153
|
-
// Group by type
|
|
154
|
-
const byType: Record<string, number> = {}
|
|
155
|
-
for (const entry of entries) {
|
|
156
|
-
const type = entry.type || 'unknown'
|
|
157
|
-
byType[type] = (byType[type] || 0) + 1
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// Group by date
|
|
161
|
-
const byDate: Record<string, number> = {}
|
|
162
|
-
for (const entry of entries) {
|
|
163
|
-
const timestamp = entry.ts || entry.timestamp
|
|
164
|
-
if (timestamp) {
|
|
165
|
-
const date = dateHelper.getDateKey(new Date(timestamp))
|
|
166
|
-
byDate[date] = (byDate[date] || 0) + 1
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
return {
|
|
171
|
-
totalEntries: entries.length,
|
|
172
|
-
byType,
|
|
173
|
-
byDate,
|
|
174
|
-
activeDays: Object.keys(byDate).length,
|
|
175
|
-
averagePerDay: entries.length / Math.max(daysBack, 1),
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* Archive old session data (move sessions older than N days)
|
|
181
|
-
*/
|
|
182
|
-
export async function archiveOldSessions(
|
|
183
|
-
projectGlobalPath: string,
|
|
184
|
-
layer: string,
|
|
185
|
-
daysToKeep = 30
|
|
186
|
-
): Promise<ArchiveResult> {
|
|
187
|
-
const cutoffDate = dateHelper.getDaysAgo(daysToKeep)
|
|
188
|
-
const archiveDir = path.join(projectGlobalPath, layer, 'archive')
|
|
189
|
-
await fileHelper.ensureDir(archiveDir)
|
|
190
|
-
|
|
191
|
-
const sessionsDir = path.join(projectGlobalPath, layer, 'sessions')
|
|
192
|
-
|
|
193
|
-
// Find all session files older than cutoff
|
|
194
|
-
const archived: string[] = []
|
|
195
|
-
const errors: Array<{ filename: string; error: string }> = []
|
|
196
|
-
|
|
197
|
-
try {
|
|
198
|
-
const years = await fileHelper.listFiles(sessionsDir, { dirsOnly: true })
|
|
199
|
-
|
|
200
|
-
for (const year of years) {
|
|
201
|
-
const yearPath = path.join(sessionsDir, year)
|
|
202
|
-
const months = await fileHelper.listFiles(yearPath, { dirsOnly: true })
|
|
203
|
-
|
|
204
|
-
for (const month of months) {
|
|
205
|
-
const monthPath = path.join(yearPath, month)
|
|
206
|
-
const sessionFiles = await fileHelper.listFiles(monthPath, { filesOnly: true })
|
|
207
|
-
|
|
208
|
-
for (const filename of sessionFiles) {
|
|
209
|
-
// Parse date from filename (YYYY-MM-DD.jsonl)
|
|
210
|
-
const dateMatch = filename.match(/(\d{4}-\d{2}-\d{2})/)
|
|
211
|
-
if (!dateMatch) continue
|
|
212
|
-
|
|
213
|
-
const sessionDate = new Date(dateMatch[1])
|
|
214
|
-
if (sessionDate < cutoffDate) {
|
|
215
|
-
const sourcePath = path.join(monthPath, filename)
|
|
216
|
-
const destPath = path.join(archiveDir, filename)
|
|
217
|
-
|
|
218
|
-
try {
|
|
219
|
-
await fileHelper.moveFile(sourcePath, destPath)
|
|
220
|
-
archived.push(filename)
|
|
221
|
-
} catch (error) {
|
|
222
|
-
errors.push({ filename, error: getErrorMessage(error) })
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
} catch (_error) {
|
|
229
|
-
// Sessions directory might not exist yet - expected
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
return {
|
|
233
|
-
archived: archived.length,
|
|
234
|
-
files: archived,
|
|
235
|
-
errors,
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
/**
|
|
240
|
-
* Clean empty session directories
|
|
241
|
-
*/
|
|
242
|
-
export async function cleanEmptySessionDirs(
|
|
243
|
-
projectGlobalPath: string,
|
|
244
|
-
layer: string
|
|
245
|
-
): Promise<number> {
|
|
246
|
-
const sessionsDir = path.join(projectGlobalPath, layer, 'sessions')
|
|
247
|
-
let cleaned = 0
|
|
248
|
-
|
|
249
|
-
try {
|
|
250
|
-
const years = await fileHelper.listFiles(sessionsDir, { dirsOnly: true })
|
|
251
|
-
|
|
252
|
-
for (const year of years) {
|
|
253
|
-
const yearPath = path.join(sessionsDir, year)
|
|
254
|
-
const months = await fileHelper.listFiles(yearPath, { dirsOnly: true })
|
|
255
|
-
|
|
256
|
-
for (const month of months) {
|
|
257
|
-
const monthPath = path.join(yearPath, month)
|
|
258
|
-
const files = await fileHelper.listFiles(monthPath)
|
|
259
|
-
|
|
260
|
-
if (files.length === 0) {
|
|
261
|
-
await fileHelper.deleteDir(monthPath)
|
|
262
|
-
cleaned++
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
// Check if year directory is now empty
|
|
267
|
-
const remainingMonths = await fileHelper.listFiles(yearPath, { dirsOnly: true })
|
|
268
|
-
if (remainingMonths.length === 0) {
|
|
269
|
-
await fileHelper.deleteDir(yearPath)
|
|
270
|
-
cleaned++
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
} catch (_error) {
|
|
274
|
-
// Sessions directory might not exist - expected
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
return cleaned
|
|
278
|
-
}
|
|
@@ -1,227 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Subtask Progress Display
|
|
3
|
-
*
|
|
4
|
-
* Clean, minimal visual display of subtask progress.
|
|
5
|
-
* No tables - just a clean list with animated status.
|
|
6
|
-
*
|
|
7
|
-
* @see PRJ-138
|
|
8
|
-
* @module utils/subtask-table
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import chalk from 'chalk'
|
|
12
|
-
|
|
13
|
-
// Color palette for domains (cycle through these)
|
|
14
|
-
const DOMAIN_COLOR_PALETTE = [
|
|
15
|
-
chalk.cyan,
|
|
16
|
-
chalk.magenta,
|
|
17
|
-
chalk.yellow,
|
|
18
|
-
chalk.blue,
|
|
19
|
-
chalk.green,
|
|
20
|
-
chalk.redBright,
|
|
21
|
-
chalk.magentaBright,
|
|
22
|
-
chalk.cyanBright,
|
|
23
|
-
]
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Get consistent color for a domain name using hash
|
|
27
|
-
* Same domain name always returns same color
|
|
28
|
-
*/
|
|
29
|
-
function getDomainColor(domain: string): (text: string) => string {
|
|
30
|
-
let hash = 0
|
|
31
|
-
for (const char of domain) {
|
|
32
|
-
hash = (hash << 5) - hash + char.charCodeAt(0)
|
|
33
|
-
hash = hash & hash
|
|
34
|
-
}
|
|
35
|
-
const index = Math.abs(hash) % DOMAIN_COLOR_PALETTE.length
|
|
36
|
-
return DOMAIN_COLOR_PALETTE[index]
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// Terminal control sequences (not colors - chalk doesn't handle these)
|
|
40
|
-
const HIDE_CURSOR = '\x1b[?25l'
|
|
41
|
-
const SHOW_CURSOR = '\x1b[?25h'
|
|
42
|
-
|
|
43
|
-
// Spinner frames (dots animation)
|
|
44
|
-
const SPINNER_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']
|
|
45
|
-
|
|
46
|
-
export type SubtaskStatus = 'pending' | 'in_progress' | 'completed' | 'failed' | 'blocked'
|
|
47
|
-
|
|
48
|
-
export interface SubtaskDisplay {
|
|
49
|
-
id: string
|
|
50
|
-
domain: string
|
|
51
|
-
description: string
|
|
52
|
-
status: SubtaskStatus
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Format a single subtask line
|
|
57
|
-
*/
|
|
58
|
-
function formatSubtaskLine(
|
|
59
|
-
index: number,
|
|
60
|
-
subtask: SubtaskDisplay,
|
|
61
|
-
spinnerFrame: string = '▶'
|
|
62
|
-
): string {
|
|
63
|
-
const num = chalk.dim(String(index + 1).padStart(2))
|
|
64
|
-
const domainColorFn = getDomainColor(subtask.domain)
|
|
65
|
-
const domain = domainColorFn(subtask.domain.padEnd(10))
|
|
66
|
-
const desc =
|
|
67
|
-
subtask.description.length > 32
|
|
68
|
-
? `${subtask.description.slice(0, 29)}...`
|
|
69
|
-
: subtask.description.padEnd(32)
|
|
70
|
-
|
|
71
|
-
let status: string
|
|
72
|
-
switch (subtask.status) {
|
|
73
|
-
case 'completed':
|
|
74
|
-
status = chalk.green('✓ Complete')
|
|
75
|
-
break
|
|
76
|
-
case 'in_progress':
|
|
77
|
-
status = chalk.yellow(`${spinnerFrame} Working...`)
|
|
78
|
-
break
|
|
79
|
-
case 'pending':
|
|
80
|
-
status = chalk.gray('○ Pending')
|
|
81
|
-
break
|
|
82
|
-
case 'failed':
|
|
83
|
-
status = chalk.red('✗ Failed')
|
|
84
|
-
break
|
|
85
|
-
case 'blocked':
|
|
86
|
-
status = chalk.gray('⊘ Blocked')
|
|
87
|
-
break
|
|
88
|
-
default:
|
|
89
|
-
status = chalk.gray(`○ ${subtask.status}`)
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
return ` ${num} ${domain} ${desc} ${status}`
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Render static subtask progress (no animation)
|
|
97
|
-
*/
|
|
98
|
-
export function renderSubtaskProgress(subtasks: SubtaskDisplay[]): string {
|
|
99
|
-
if (subtasks.length === 0) return ''
|
|
100
|
-
|
|
101
|
-
const lines: string[] = []
|
|
102
|
-
|
|
103
|
-
lines.push('')
|
|
104
|
-
lines.push(` ${chalk.bold.white('SUBTASK PROGRESS')}`)
|
|
105
|
-
lines.push(` ${chalk.dim('─'.repeat(58))}`)
|
|
106
|
-
|
|
107
|
-
for (let i = 0; i < subtasks.length; i++) {
|
|
108
|
-
lines.push(formatSubtaskLine(i, subtasks[i]))
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
lines.push('')
|
|
112
|
-
|
|
113
|
-
return lines.join('\n')
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Print static subtask progress
|
|
118
|
-
*/
|
|
119
|
-
export function printSubtaskProgress(subtasks: SubtaskDisplay[]): void {
|
|
120
|
-
console.log(renderSubtaskProgress(subtasks))
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Animated subtask progress with spinner
|
|
125
|
-
* Returns a controller to update/stop the animation
|
|
126
|
-
*/
|
|
127
|
-
export function createSubtaskAnimation(subtasks: SubtaskDisplay[]) {
|
|
128
|
-
let frameIndex = 0
|
|
129
|
-
let intervalId: ReturnType<typeof setInterval> | null = null
|
|
130
|
-
let lastOutput = ''
|
|
131
|
-
|
|
132
|
-
const render = () => {
|
|
133
|
-
const spinnerFrame = SPINNER_FRAMES[frameIndex % SPINNER_FRAMES.length]
|
|
134
|
-
const lines: string[] = []
|
|
135
|
-
|
|
136
|
-
lines.push('')
|
|
137
|
-
lines.push(` ${chalk.bold.white('SUBTASK PROGRESS')}`)
|
|
138
|
-
lines.push(` ${chalk.dim('─'.repeat(58))}`)
|
|
139
|
-
|
|
140
|
-
for (let i = 0; i < subtasks.length; i++) {
|
|
141
|
-
lines.push(formatSubtaskLine(i, subtasks[i], spinnerFrame))
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
lines.push('')
|
|
145
|
-
|
|
146
|
-
return lines.join('\n')
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
const clear = () => {
|
|
150
|
-
if (lastOutput) {
|
|
151
|
-
const lineCount = lastOutput.split('\n').length
|
|
152
|
-
// Move up and clear each line
|
|
153
|
-
process.stdout.write(`\x1b[${lineCount}A`)
|
|
154
|
-
for (let i = 0; i < lineCount; i++) {
|
|
155
|
-
process.stdout.write('\x1b[2K\n')
|
|
156
|
-
}
|
|
157
|
-
process.stdout.write(`\x1b[${lineCount}A`)
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
const draw = () => {
|
|
162
|
-
clear()
|
|
163
|
-
lastOutput = render()
|
|
164
|
-
process.stdout.write(lastOutput)
|
|
165
|
-
frameIndex++
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
return {
|
|
169
|
-
/**
|
|
170
|
-
* Start the animation
|
|
171
|
-
*/
|
|
172
|
-
start: () => {
|
|
173
|
-
process.stdout.write(HIDE_CURSOR)
|
|
174
|
-
lastOutput = render()
|
|
175
|
-
process.stdout.write(lastOutput)
|
|
176
|
-
intervalId = setInterval(draw, 80)
|
|
177
|
-
},
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* Update subtask status
|
|
181
|
-
*/
|
|
182
|
-
update: (index: number, status: SubtaskStatus) => {
|
|
183
|
-
if (index >= 0 && index < subtasks.length) {
|
|
184
|
-
subtasks[index].status = status
|
|
185
|
-
}
|
|
186
|
-
},
|
|
187
|
-
|
|
188
|
-
/**
|
|
189
|
-
* Stop animation and show final state
|
|
190
|
-
*/
|
|
191
|
-
stop: () => {
|
|
192
|
-
if (intervalId) {
|
|
193
|
-
clearInterval(intervalId)
|
|
194
|
-
intervalId = null
|
|
195
|
-
}
|
|
196
|
-
clear()
|
|
197
|
-
// Print final state with static icons
|
|
198
|
-
const finalLines: string[] = []
|
|
199
|
-
finalLines.push('')
|
|
200
|
-
finalLines.push(` ${chalk.bold.white('SUBTASK PROGRESS')}`)
|
|
201
|
-
finalLines.push(` ${chalk.dim('─'.repeat(58))}`)
|
|
202
|
-
for (let i = 0; i < subtasks.length; i++) {
|
|
203
|
-
finalLines.push(formatSubtaskLine(i, subtasks[i], '▶'))
|
|
204
|
-
}
|
|
205
|
-
finalLines.push('')
|
|
206
|
-
process.stdout.write(finalLines.join('\n'))
|
|
207
|
-
process.stdout.write(SHOW_CURSOR)
|
|
208
|
-
},
|
|
209
|
-
|
|
210
|
-
/**
|
|
211
|
-
* Get current subtasks state
|
|
212
|
-
*/
|
|
213
|
-
getSubtasks: () => [...subtasks],
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
/**
|
|
218
|
-
* Simple progress line
|
|
219
|
-
* Output: "Progress: 2/4 subtasks complete"
|
|
220
|
-
*/
|
|
221
|
-
export function renderProgressLine(completed: number, total: number): string {
|
|
222
|
-
return ` ${chalk.dim('Progress:')} ${completed}/${total} subtasks complete`
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
// Legacy exports for backwards compatibility
|
|
226
|
-
export const renderSubtaskTable = renderSubtaskProgress
|
|
227
|
-
export const printSubtaskTable = printSubtaskProgress
|