prjct-cli 1.22.0 → 1.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +147 -0
- package/bin/prjct +30 -13
- package/dist/bin/prjct.mjs +917 -35845
- package/dist/bin/prjct.mjs.map +7 -0
- package/dist/cli/linear.mjs +16 -0
- package/dist/cli/linear.mjs.map +7 -0
- package/dist/templates.json +1 -0
- package/package.json +4 -5
- package/bin/prjct.ts +0 -342
- package/core/__tests__/agentic/analysis-injection.test.ts +0 -377
- package/core/__tests__/agentic/cache-eviction.test.ts +0 -294
- package/core/__tests__/agentic/command-context.test.ts +0 -281
- package/core/__tests__/agentic/command-executor.test.ts +0 -659
- package/core/__tests__/agentic/domain-classifier.test.ts +0 -330
- package/core/__tests__/agentic/injection-validator.test.ts +0 -255
- package/core/__tests__/agentic/memory-system.test.ts +0 -281
- package/core/__tests__/agentic/plan-mode.test.ts +0 -386
- package/core/__tests__/agentic/prompt-assembly.test.ts +0 -298
- package/core/__tests__/agentic/prompt-builder.test.ts +0 -243
- package/core/__tests__/agentic/response-validator.test.ts +0 -263
- package/core/__tests__/agentic/semantic-matching.test.ts +0 -131
- package/core/__tests__/agentic/smart-context.test.ts +0 -372
- package/core/__tests__/agentic/tech-normalizer.test.ts +0 -136
- package/core/__tests__/agentic/token-budget.test.ts +0 -294
- package/core/__tests__/ai-tools/formatters.test.ts +0 -476
- package/core/__tests__/domain/bm25.test.ts +0 -225
- package/core/__tests__/domain/change-propagator.test.ts +0 -100
- package/core/__tests__/domain/fibonacci.test.ts +0 -113
- package/core/__tests__/domain/file-hasher.test.ts +0 -146
- package/core/__tests__/domain/file-ranker.test.ts +0 -169
- package/core/__tests__/domain/git-cochange.test.ts +0 -121
- package/core/__tests__/domain/import-graph.test.ts +0 -156
- package/core/__tests__/domain/velocity.test.ts +0 -623
- package/core/__tests__/infrastructure/performance-tracker.test.ts +0 -328
- package/core/__tests__/schemas/model.test.ts +0 -272
- package/core/__tests__/services/dependency-validator.test.ts +0 -175
- package/core/__tests__/services/hierarchical-agent-resolver.test.ts +0 -359
- package/core/__tests__/services/nested-context-resolver.test.ts +0 -443
- package/core/__tests__/services/project-index.test.ts +0 -355
- package/core/__tests__/services/staleness-checker.test.ts +0 -204
- package/core/__tests__/storage/analysis-storage.test.ts +0 -641
- package/core/__tests__/storage/archive-storage.test.ts +0 -455
- package/core/__tests__/storage/safe-reader.test.ts +0 -262
- package/core/__tests__/storage/sqlite-migration.test.ts +0 -1016
- package/core/__tests__/storage/state-storage-feedback.test.ts +0 -463
- package/core/__tests__/storage/state-storage-history.test.ts +0 -469
- package/core/__tests__/storage/storage-manager.test.ts +0 -383
- package/core/__tests__/storage/subtask-handoff.test.ts +0 -237
- package/core/__tests__/types/fs.test.ts +0 -125
- package/core/__tests__/utils/date-helper.test.ts +0 -449
- package/core/__tests__/utils/output.test.ts +0 -278
- package/core/__tests__/utils/preserve-sections.test.ts +0 -216
- package/core/__tests__/utils/project-commands.test.ts +0 -71
- package/core/__tests__/utils/retry.test.ts +0 -381
- package/core/__tests__/workflow/state-machine.test.ts +0 -216
- package/core/agentic/agent-router.ts +0 -150
- package/core/agentic/anti-hallucination.ts +0 -141
- package/core/agentic/chain-of-thought.ts +0 -234
- package/core/agentic/command-classifier.ts +0 -141
- package/core/agentic/command-context.ts +0 -168
- package/core/agentic/command-executor.ts +0 -471
- package/core/agentic/context-builder.ts +0 -285
- package/core/agentic/domain-classifier.ts +0 -525
- package/core/agentic/environment-block.ts +0 -102
- package/core/agentic/ground-truth.ts +0 -706
- package/core/agentic/index.ts +0 -193
- package/core/agentic/injection-validator.ts +0 -208
- package/core/agentic/loop-detector.ts +0 -451
- package/core/agentic/memory-system.ts +0 -1547
- package/core/agentic/orchestrator-executor.ts +0 -579
- package/core/agentic/plan-mode.ts +0 -525
- package/core/agentic/prompt-builder.ts +0 -1069
- package/core/agentic/response-validator.ts +0 -98
- package/core/agentic/services.ts +0 -167
- package/core/agentic/skill-loader.ts +0 -106
- package/core/agentic/smart-context.ts +0 -393
- package/core/agentic/tech-normalizer.ts +0 -167
- package/core/agentic/template-executor.ts +0 -272
- package/core/agentic/template-loader.ts +0 -109
- package/core/agentic/token-budget.ts +0 -226
- package/core/agentic/tool-registry.ts +0 -146
- package/core/agents/index.ts +0 -28
- package/core/agents/performance.ts +0 -429
- package/core/ai-tools/formatters.ts +0 -341
- package/core/ai-tools/generator.ts +0 -144
- package/core/ai-tools/index.ts +0 -15
- package/core/ai-tools/registry.ts +0 -201
- package/core/bus/bus.ts +0 -314
- package/core/bus/index.ts +0 -8
- package/core/cli/linear.ts +0 -500
- package/core/cli/lint-meta-commentary.ts +0 -177
- package/core/cli/start.ts +0 -386
- package/core/commands/analysis.ts +0 -1274
- package/core/commands/analytics.ts +0 -342
- package/core/commands/base.ts +0 -118
- package/core/commands/cleanup.ts +0 -157
- package/core/commands/command-data.ts +0 -463
- package/core/commands/commands.ts +0 -306
- package/core/commands/context.ts +0 -238
- package/core/commands/design.ts +0 -77
- package/core/commands/index.ts +0 -19
- package/core/commands/maintenance.ts +0 -77
- package/core/commands/performance.ts +0 -114
- package/core/commands/planning.ts +0 -662
- package/core/commands/register.ts +0 -127
- package/core/commands/registry.ts +0 -444
- package/core/commands/setup.ts +0 -280
- package/core/commands/shipping.ts +0 -267
- package/core/commands/snapshots.ts +0 -297
- package/core/commands/uninstall.ts +0 -542
- package/core/commands/velocity.ts +0 -149
- package/core/commands/workflow.ts +0 -505
- package/core/config/command-context.config.json +0 -66
- package/core/constants/index.ts +0 -379
- package/core/context/generator.ts +0 -368
- package/core/context-tools/files-tool.ts +0 -577
- package/core/context-tools/imports-tool.ts +0 -400
- package/core/context-tools/index.ts +0 -434
- package/core/context-tools/recent-tool.ts +0 -301
- package/core/context-tools/signatures-tool.ts +0 -495
- package/core/context-tools/summary-tool.ts +0 -301
- package/core/context-tools/token-counter.ts +0 -273
- package/core/context-tools/types.ts +0 -253
- package/core/domain/agent-generator.ts +0 -186
- package/core/domain/agent-loader.ts +0 -419
- package/core/domain/analyzer.ts +0 -387
- package/core/domain/architecture-generator.ts +0 -108
- package/core/domain/bm25.ts +0 -525
- package/core/domain/change-propagator.ts +0 -162
- package/core/domain/context-estimator.ts +0 -175
- package/core/domain/fibonacci.ts +0 -128
- package/core/domain/file-hasher.ts +0 -296
- package/core/domain/file-ranker.ts +0 -151
- package/core/domain/git-cochange.ts +0 -250
- package/core/domain/import-graph.ts +0 -315
- package/core/domain/snapshot-manager.ts +0 -415
- package/core/domain/task-stack.ts +0 -578
- package/core/domain/velocity.ts +0 -470
- package/core/errors.ts +0 -335
- package/core/events/events.ts +0 -85
- package/core/events/index.ts +0 -8
- package/core/index.ts +0 -481
- package/core/infrastructure/agent-detector.ts +0 -135
- package/core/infrastructure/ai-provider.ts +0 -578
- package/core/infrastructure/author-detector.ts +0 -133
- package/core/infrastructure/capability-installer.ts +0 -76
- package/core/infrastructure/claude-agent.ts +0 -297
- package/core/infrastructure/command-installer.ts +0 -752
- package/core/infrastructure/config-manager.ts +0 -364
- package/core/infrastructure/editors-config.ts +0 -172
- package/core/infrastructure/path-manager.ts +0 -571
- package/core/infrastructure/performance-tracker.ts +0 -326
- package/core/infrastructure/permission-manager.ts +0 -289
- package/core/infrastructure/setup.ts +0 -1061
- package/core/infrastructure/update-checker.ts +0 -246
- package/core/integrations/issue-tracker/enricher.ts +0 -271
- package/core/integrations/issue-tracker/index.ts +0 -8
- package/core/integrations/issue-tracker/manager.ts +0 -286
- package/core/integrations/issue-tracker/types.ts +0 -310
- package/core/integrations/jira/cache.ts +0 -57
- package/core/integrations/jira/client.ts +0 -688
- package/core/integrations/jira/index.ts +0 -23
- package/core/integrations/jira/service.ts +0 -244
- package/core/integrations/linear/cache.ts +0 -68
- package/core/integrations/linear/client.ts +0 -436
- package/core/integrations/linear/index.ts +0 -20
- package/core/integrations/linear/service.ts +0 -260
- package/core/integrations/linear/sync.ts +0 -314
- package/core/outcomes/analyzer.ts +0 -286
- package/core/outcomes/index.ts +0 -34
- package/core/outcomes/recorder.ts +0 -195
- package/core/plugin/builtin/webhook.ts +0 -148
- package/core/plugin/hooks.ts +0 -315
- package/core/plugin/index.ts +0 -50
- package/core/plugin/loader.ts +0 -354
- package/core/plugin/registry.ts +0 -326
- package/core/schemas/agents.ts +0 -27
- package/core/schemas/analysis.ts +0 -530
- package/core/schemas/classification.ts +0 -91
- package/core/schemas/command-context.ts +0 -29
- package/core/schemas/enriched-task.ts +0 -291
- package/core/schemas/ideas.ts +0 -114
- package/core/schemas/index.ts +0 -53
- package/core/schemas/issues.ts +0 -159
- package/core/schemas/llm-output.ts +0 -170
- package/core/schemas/metrics.ts +0 -143
- package/core/schemas/model.ts +0 -153
- package/core/schemas/outcomes.ts +0 -487
- package/core/schemas/performance.ts +0 -128
- package/core/schemas/permissions.ts +0 -180
- package/core/schemas/prd.ts +0 -450
- package/core/schemas/project.ts +0 -57
- package/core/schemas/roadmap.ts +0 -322
- package/core/schemas/schemas.ts +0 -38
- package/core/schemas/shipped.ts +0 -109
- package/core/schemas/state.ts +0 -284
- package/core/schemas/velocity.ts +0 -103
- package/core/server/index.ts +0 -21
- package/core/server/routes-extended.ts +0 -566
- package/core/server/routes.ts +0 -176
- package/core/server/server.ts +0 -149
- package/core/server/sse.ts +0 -192
- package/core/services/agent-generator.ts +0 -385
- package/core/services/agent-service.ts +0 -168
- package/core/services/breakdown-service.ts +0 -124
- package/core/services/context-generator.ts +0 -445
- package/core/services/context-selector.ts +0 -429
- package/core/services/dependency-validator.ts +0 -318
- package/core/services/diff-generator.ts +0 -313
- package/core/services/doctor-service.ts +0 -423
- package/core/services/file-categorizer.ts +0 -448
- package/core/services/file-scorer.ts +0 -270
- package/core/services/git-analyzer.ts +0 -293
- package/core/services/hierarchical-agent-resolver.ts +0 -236
- package/core/services/hooks-service.ts +0 -685
- package/core/services/index.ts +0 -46
- package/core/services/local-state-generator.ts +0 -158
- package/core/services/memory-service.ts +0 -181
- package/core/services/nested-context-resolver.ts +0 -842
- package/core/services/project-index.ts +0 -911
- package/core/services/project-service.ts +0 -155
- package/core/services/session-tracker.ts +0 -287
- package/core/services/skill-installer.ts +0 -447
- package/core/services/skill-lock.ts +0 -132
- package/core/services/skill-service.ts +0 -306
- package/core/services/stack-detector.ts +0 -229
- package/core/services/staleness-checker.ts +0 -327
- package/core/services/sync-service.ts +0 -1515
- package/core/services/sync-verifier.ts +0 -253
- package/core/services/watch-service.ts +0 -312
- package/core/session/compaction.ts +0 -248
- package/core/session/index.ts +0 -35
- package/core/session/log-migration.ts +0 -88
- package/core/session/metrics.ts +0 -323
- package/core/session/session-log-manager.ts +0 -307
- package/core/session/task-session-manager.ts +0 -404
- package/core/session/utils.ts +0 -51
- package/core/storage/analysis-storage.ts +0 -373
- package/core/storage/archive-storage.ts +0 -205
- package/core/storage/database.ts +0 -575
- package/core/storage/ideas-storage.ts +0 -298
- package/core/storage/index-storage.ts +0 -523
- package/core/storage/index.ts +0 -79
- package/core/storage/metrics-storage.ts +0 -321
- package/core/storage/migrate-json.ts +0 -720
- package/core/storage/queue-storage.ts +0 -336
- package/core/storage/safe-reader.ts +0 -105
- package/core/storage/shipped-storage.ts +0 -253
- package/core/storage/state-storage.ts +0 -1035
- package/core/storage/storage-manager.ts +0 -205
- package/core/storage/storage.ts +0 -177
- package/core/storage/velocity-storage.ts +0 -149
- package/core/sync/auth-config.ts +0 -138
- package/core/sync/index.ts +0 -31
- package/core/sync/oauth-handler.ts +0 -143
- package/core/sync/sync-client.ts +0 -251
- package/core/sync/sync-manager.ts +0 -327
- package/core/tsconfig.json +0 -22
- package/core/types/agentic.ts +0 -760
- package/core/types/agents.ts +0 -150
- package/core/types/bus.ts +0 -193
- package/core/types/citations.ts +0 -22
- package/core/types/commands.ts +0 -399
- package/core/types/config.ts +0 -92
- package/core/types/core.ts +0 -96
- package/core/types/diff.ts +0 -41
- package/core/types/domain.ts +0 -71
- package/core/types/errors.ts +0 -111
- package/core/types/events.ts +0 -42
- package/core/types/fs.ts +0 -72
- package/core/types/index.ts +0 -510
- package/core/types/infrastructure.ts +0 -210
- package/core/types/integrations.ts +0 -31
- package/core/types/jira.ts +0 -51
- package/core/types/logger.ts +0 -17
- package/core/types/memory.ts +0 -313
- package/core/types/outcomes.ts +0 -190
- package/core/types/output.ts +0 -47
- package/core/types/plugin.ts +0 -25
- package/core/types/project-sync.ts +0 -129
- package/core/types/provider.ts +0 -163
- package/core/types/server.ts +0 -71
- package/core/types/services.ts +0 -84
- package/core/types/session.ts +0 -135
- package/core/types/stack.ts +0 -19
- package/core/types/storage.ts +0 -318
- package/core/types/sync-verifier.ts +0 -33
- package/core/types/sync.ts +0 -121
- package/core/types/task.ts +0 -72
- package/core/types/template.ts +0 -24
- package/core/types/utils.ts +0 -92
- package/core/types/workflow.ts +0 -23
- package/core/utils/agent-stream.ts +0 -140
- package/core/utils/animations.ts +0 -251
- package/core/utils/branding.ts +0 -88
- package/core/utils/cache.ts +0 -187
- package/core/utils/citations.ts +0 -39
- package/core/utils/collection-filters.ts +0 -209
- package/core/utils/date-helper.ts +0 -176
- package/core/utils/error-messages.ts +0 -38
- package/core/utils/file-helper.ts +0 -277
- package/core/utils/fs-helpers.ts +0 -14
- package/core/utils/help.ts +0 -314
- package/core/utils/jsonl-helper.ts +0 -290
- package/core/utils/keychain.ts +0 -127
- package/core/utils/logger.ts +0 -77
- package/core/utils/markdown-builder.ts +0 -280
- package/core/utils/next-steps.ts +0 -95
- package/core/utils/output.ts +0 -403
- package/core/utils/preserve-sections.ts +0 -218
- package/core/utils/project-commands.ts +0 -126
- package/core/utils/project-credentials.ts +0 -143
- package/core/utils/provider-cache.ts +0 -49
- package/core/utils/retry.ts +0 -318
- package/core/utils/runtime.ts +0 -108
- package/core/utils/session-helper.ts +0 -278
- package/core/utils/subtask-table.ts +0 -227
- package/core/utils/version.ts +0 -128
- package/core/wizard/index.ts +0 -13
- package/core/wizard/onboarding.ts +0 -633
- package/core/workflow/index.ts +0 -7
- package/core/workflow/state-machine.ts +0 -198
- package/core/workflow/workflow-preferences.ts +0 -294
- package/dist/core/infrastructure/command-installer.js +0 -1141
- package/dist/core/infrastructure/editors-config.js +0 -177
- package/dist/core/infrastructure/setup.js +0 -2244
- package/dist/core/utils/version.js +0 -141
- package/templates/agentic/agent-routing.md +0 -45
- package/templates/agentic/agents/uxui.md +0 -63
- package/templates/agentic/checklist-routing.md +0 -98
- package/templates/agentic/orchestrator.md +0 -68
- package/templates/agentic/task-fragmentation.md +0 -89
- package/templates/agents/AGENTS.md +0 -68
- package/templates/analysis/analyze.md +0 -84
- package/templates/analysis/patterns.md +0 -60
- package/templates/antigravity/SKILL.md +0 -39
- package/templates/architect/discovery.md +0 -67
- package/templates/architect/phases.md +0 -59
- package/templates/checklists/architecture.md +0 -28
- package/templates/checklists/code-quality.md +0 -28
- package/templates/checklists/data.md +0 -33
- package/templates/checklists/documentation.md +0 -33
- package/templates/checklists/infrastructure.md +0 -33
- package/templates/checklists/performance.md +0 -33
- package/templates/checklists/security.md +0 -33
- package/templates/checklists/testing.md +0 -33
- package/templates/checklists/ux-ui.md +0 -37
- package/templates/commands/analyze.md +0 -56
- package/templates/commands/auth.md +0 -234
- package/templates/commands/bug.md +0 -163
- package/templates/commands/cleanup.md +0 -19
- package/templates/commands/dash.md +0 -99
- package/templates/commands/design.md +0 -15
- package/templates/commands/done.md +0 -291
- package/templates/commands/enrich.md +0 -174
- package/templates/commands/git.md +0 -295
- package/templates/commands/history.md +0 -389
- package/templates/commands/idea.md +0 -88
- package/templates/commands/impact.md +0 -864
- package/templates/commands/init.md +0 -54
- package/templates/commands/jira.md +0 -278
- package/templates/commands/linear.md +0 -288
- package/templates/commands/merge.md +0 -206
- package/templates/commands/next.md +0 -80
- package/templates/commands/p.md +0 -67
- package/templates/commands/p.toml +0 -37
- package/templates/commands/pause.md +0 -136
- package/templates/commands/plan.md +0 -696
- package/templates/commands/prd.md +0 -356
- package/templates/commands/resume.md +0 -171
- package/templates/commands/review.md +0 -276
- package/templates/commands/serve.md +0 -118
- package/templates/commands/setup.md +0 -91
- package/templates/commands/ship.md +0 -475
- package/templates/commands/skill.md +0 -259
- package/templates/commands/spec.md +0 -218
- package/templates/commands/status.md +0 -207
- package/templates/commands/sync.md +0 -104
- package/templates/commands/task.md +0 -312
- package/templates/commands/test.md +0 -93
- package/templates/commands/update.md +0 -63
- package/templates/commands/verify.md +0 -204
- package/templates/commands/workflow.md +0 -150
- package/templates/config/skill-mappings.json +0 -82
- package/templates/context/dashboard.md +0 -256
- package/templates/context/roadmap.md +0 -221
- package/templates/cursor/commands/bug.md +0 -8
- package/templates/cursor/commands/done.md +0 -4
- package/templates/cursor/commands/pause.md +0 -6
- package/templates/cursor/commands/resume.md +0 -4
- package/templates/cursor/commands/ship.md +0 -8
- package/templates/cursor/commands/sync.md +0 -4
- package/templates/cursor/commands/task.md +0 -8
- package/templates/cursor/p.md +0 -29
- package/templates/cursor/router.mdc +0 -28
- package/templates/design/api.md +0 -95
- package/templates/design/architecture.md +0 -77
- package/templates/design/component.md +0 -89
- package/templates/design/database.md +0 -78
- package/templates/design/flow.md +0 -94
- package/templates/global/ANTIGRAVITY.md +0 -254
- package/templates/global/CLAUDE.md +0 -497
- package/templates/global/CURSOR.mdc +0 -266
- package/templates/global/GEMINI.md +0 -293
- package/templates/global/STORAGE-SPEC.md +0 -391
- package/templates/global/WINDSURF.md +0 -266
- package/templates/global/modules/CLAUDE-commands.md +0 -70
- package/templates/global/modules/CLAUDE-core.md +0 -105
- package/templates/global/modules/CLAUDE-git.md +0 -50
- package/templates/global/modules/CLAUDE-intelligence.md +0 -92
- package/templates/global/modules/CLAUDE-storage.md +0 -50
- package/templates/global/modules/module-config.json +0 -36
- package/templates/mcp-config.json +0 -19
- package/templates/permissions/default.jsonc +0 -60
- package/templates/permissions/permissive.jsonc +0 -49
- package/templates/permissions/strict.jsonc +0 -58
- package/templates/planning-methodology.md +0 -195
- package/templates/skills/code-review.md +0 -47
- package/templates/skills/debug.md +0 -61
- package/templates/skills/refactor.md +0 -47
- package/templates/subagents/agent-base.md +0 -20
- package/templates/subagents/domain/backend.md +0 -109
- package/templates/subagents/domain/database.md +0 -121
- package/templates/subagents/domain/devops.md +0 -152
- package/templates/subagents/domain/frontend.md +0 -103
- package/templates/subagents/domain/testing.md +0 -169
- package/templates/subagents/pm-expert.md +0 -366
- package/templates/subagents/workflow/chief-architect.md +0 -657
- package/templates/subagents/workflow/prjct-planner.md +0 -159
- package/templates/subagents/workflow/prjct-shipper.md +0 -188
- package/templates/subagents/workflow/prjct-workflow.md +0 -98
- package/templates/tools/bash.txt +0 -22
- package/templates/tools/edit.txt +0 -18
- package/templates/tools/glob.txt +0 -19
- package/templates/tools/grep.txt +0 -21
- package/templates/tools/read.txt +0 -14
- package/templates/tools/task.txt +0 -20
- package/templates/tools/webfetch.txt +0 -16
- package/templates/tools/websearch.txt +0 -18
- package/templates/tools/write.txt +0 -17
- package/templates/windsurf/router.md +0 -28
- package/templates/windsurf/workflows/bug.md +0 -8
- package/templates/windsurf/workflows/done.md +0 -4
- package/templates/windsurf/workflows/pause.md +0 -4
- package/templates/windsurf/workflows/resume.md +0 -4
- package/templates/windsurf/workflows/ship.md +0 -8
- package/templates/windsurf/workflows/sync.md +0 -4
- package/templates/windsurf/workflows/task.md +0 -8
|
@@ -1,278 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Output Module Tests
|
|
3
|
-
* Minimal output system for prjct-cli
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { afterEach, beforeEach, describe, expect, it, spyOn } from 'bun:test'
|
|
7
|
-
import out, {
|
|
8
|
-
formatForHuman,
|
|
9
|
-
getOutputTier,
|
|
10
|
-
getTierConfig,
|
|
11
|
-
limitLines,
|
|
12
|
-
OUTPUT_TIERS,
|
|
13
|
-
setOutputTier,
|
|
14
|
-
} from '../../utils/output'
|
|
15
|
-
|
|
16
|
-
describe('Output Module', () => {
|
|
17
|
-
let consoleLogSpy: ReturnType<typeof spyOn>
|
|
18
|
-
let consoleErrorSpy: ReturnType<typeof spyOn>
|
|
19
|
-
let stdoutWriteSpy: ReturnType<typeof spyOn>
|
|
20
|
-
|
|
21
|
-
beforeEach(() => {
|
|
22
|
-
consoleLogSpy = spyOn(console, 'log').mockImplementation(() => {})
|
|
23
|
-
consoleErrorSpy = spyOn(console, 'error').mockImplementation(() => {})
|
|
24
|
-
stdoutWriteSpy = spyOn(process.stdout, 'write').mockImplementation(() => true)
|
|
25
|
-
out.stop()
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
afterEach(() => {
|
|
29
|
-
consoleLogSpy.mockRestore()
|
|
30
|
-
consoleErrorSpy.mockRestore()
|
|
31
|
-
stdoutWriteSpy.mockRestore()
|
|
32
|
-
out.stop()
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
describe('done()', () => {
|
|
36
|
-
it('should output success message with checkmark', () => {
|
|
37
|
-
out.done('task completed')
|
|
38
|
-
|
|
39
|
-
expect(consoleLogSpy).toHaveBeenCalledTimes(1)
|
|
40
|
-
const output = consoleLogSpy.mock.calls[0][0]
|
|
41
|
-
expect(output).toContain('✓')
|
|
42
|
-
expect(output).toContain('task completed')
|
|
43
|
-
})
|
|
44
|
-
|
|
45
|
-
it('should truncate long messages', () => {
|
|
46
|
-
const longMessage = 'a'.repeat(100)
|
|
47
|
-
out.done(longMessage)
|
|
48
|
-
|
|
49
|
-
const output = consoleLogSpy.mock.calls[0][0]
|
|
50
|
-
expect(output.length).toBeLessThan(80)
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
it('should return self for chaining', () => {
|
|
54
|
-
const result = out.done('test')
|
|
55
|
-
expect(result).toBe(out)
|
|
56
|
-
})
|
|
57
|
-
})
|
|
58
|
-
|
|
59
|
-
describe('fail()', () => {
|
|
60
|
-
it('should output error message with X mark', () => {
|
|
61
|
-
out.fail('something failed')
|
|
62
|
-
|
|
63
|
-
expect(consoleErrorSpy).toHaveBeenCalledTimes(1)
|
|
64
|
-
const output = consoleErrorSpy.mock.calls[0][0]
|
|
65
|
-
expect(output).toContain('✗')
|
|
66
|
-
expect(output).toContain('something failed')
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
it('should truncate long error messages', () => {
|
|
70
|
-
const longMessage = 'error '.repeat(50)
|
|
71
|
-
out.fail(longMessage)
|
|
72
|
-
|
|
73
|
-
const output = consoleErrorSpy.mock.calls[0][0]
|
|
74
|
-
expect(output.length).toBeLessThan(80)
|
|
75
|
-
})
|
|
76
|
-
|
|
77
|
-
it('should return self for chaining', () => {
|
|
78
|
-
const result = out.fail('test')
|
|
79
|
-
expect(result).toBe(out)
|
|
80
|
-
})
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
describe('warn()', () => {
|
|
84
|
-
it('should output warning message with warning symbol', () => {
|
|
85
|
-
out.warn('be careful')
|
|
86
|
-
|
|
87
|
-
expect(consoleLogSpy).toHaveBeenCalledTimes(1)
|
|
88
|
-
const output = consoleLogSpy.mock.calls[0][0]
|
|
89
|
-
expect(output).toContain('⚠')
|
|
90
|
-
expect(output).toContain('be careful')
|
|
91
|
-
})
|
|
92
|
-
|
|
93
|
-
it('should return self for chaining', () => {
|
|
94
|
-
const result = out.warn('test')
|
|
95
|
-
expect(result).toBe(out)
|
|
96
|
-
})
|
|
97
|
-
})
|
|
98
|
-
|
|
99
|
-
describe('spin()', () => {
|
|
100
|
-
it('should start spinner with message', async () => {
|
|
101
|
-
out.spin('loading')
|
|
102
|
-
|
|
103
|
-
await new Promise((resolve) => setTimeout(resolve, 150))
|
|
104
|
-
|
|
105
|
-
expect(stdoutWriteSpy).toHaveBeenCalled()
|
|
106
|
-
const output = stdoutWriteSpy.mock.calls[0][0]
|
|
107
|
-
expect(output).toContain('loading')
|
|
108
|
-
|
|
109
|
-
out.stop()
|
|
110
|
-
})
|
|
111
|
-
|
|
112
|
-
it('should return self for chaining', () => {
|
|
113
|
-
const result = out.spin('test')
|
|
114
|
-
out.stop()
|
|
115
|
-
expect(result).toBe(out)
|
|
116
|
-
})
|
|
117
|
-
})
|
|
118
|
-
|
|
119
|
-
describe('stop()', () => {
|
|
120
|
-
it('should stop spinner and clear line', async () => {
|
|
121
|
-
out.spin('loading')
|
|
122
|
-
await new Promise((resolve) => setTimeout(resolve, 150))
|
|
123
|
-
|
|
124
|
-
stdoutWriteSpy.mockClear()
|
|
125
|
-
out.stop()
|
|
126
|
-
|
|
127
|
-
// In TTY, stop() writes a clear sequence; in non-TTY, spinner doesn't
|
|
128
|
-
// use setInterval so stop() is a no-op (clear skips in non-TTY)
|
|
129
|
-
if (process.stdout.isTTY) {
|
|
130
|
-
expect(stdoutWriteSpy).toHaveBeenCalled()
|
|
131
|
-
} else {
|
|
132
|
-
expect(stdoutWriteSpy).not.toHaveBeenCalled()
|
|
133
|
-
}
|
|
134
|
-
})
|
|
135
|
-
|
|
136
|
-
it('should be safe to call multiple times', () => {
|
|
137
|
-
expect(() => {
|
|
138
|
-
out.stop()
|
|
139
|
-
out.stop()
|
|
140
|
-
out.stop()
|
|
141
|
-
}).not.toThrow()
|
|
142
|
-
})
|
|
143
|
-
|
|
144
|
-
it('should return self for chaining', () => {
|
|
145
|
-
const result = out.stop()
|
|
146
|
-
expect(result).toBe(out)
|
|
147
|
-
})
|
|
148
|
-
})
|
|
149
|
-
|
|
150
|
-
describe('edge cases', () => {
|
|
151
|
-
it('should handle empty messages', () => {
|
|
152
|
-
expect(() => out.done('')).not.toThrow()
|
|
153
|
-
expect(() => out.fail('')).not.toThrow()
|
|
154
|
-
expect(() => out.warn('')).not.toThrow()
|
|
155
|
-
})
|
|
156
|
-
|
|
157
|
-
it('should handle null/undefined messages', () => {
|
|
158
|
-
expect(() => out.done(null as unknown as string)).not.toThrow()
|
|
159
|
-
expect(() => out.done(undefined as unknown as string)).not.toThrow()
|
|
160
|
-
})
|
|
161
|
-
|
|
162
|
-
it('should handle messages with special characters', () => {
|
|
163
|
-
out.done('test with émojis 🎉 and spëcial çhars')
|
|
164
|
-
expect(consoleLogSpy).toHaveBeenCalled()
|
|
165
|
-
})
|
|
166
|
-
})
|
|
167
|
-
|
|
168
|
-
describe('Output Tiers', () => {
|
|
169
|
-
afterEach(() => {
|
|
170
|
-
setOutputTier('compact') // Reset to default
|
|
171
|
-
})
|
|
172
|
-
|
|
173
|
-
it('should have correct tier configs', () => {
|
|
174
|
-
expect(OUTPUT_TIERS.silent.maxLines).toBe(0)
|
|
175
|
-
expect(OUTPUT_TIERS.minimal.maxLines).toBe(1)
|
|
176
|
-
expect(OUTPUT_TIERS.compact.maxLines).toBe(4)
|
|
177
|
-
expect(OUTPUT_TIERS.verbose.maxLines).toBe(Infinity)
|
|
178
|
-
})
|
|
179
|
-
|
|
180
|
-
it('should get and set output tier', () => {
|
|
181
|
-
setOutputTier('verbose')
|
|
182
|
-
expect(getOutputTier()).toBe('verbose')
|
|
183
|
-
|
|
184
|
-
setOutputTier('minimal')
|
|
185
|
-
expect(getOutputTier()).toBe('minimal')
|
|
186
|
-
})
|
|
187
|
-
|
|
188
|
-
it('should return correct tier config', () => {
|
|
189
|
-
setOutputTier('compact')
|
|
190
|
-
const config = getTierConfig()
|
|
191
|
-
expect(config.maxLines).toBe(4)
|
|
192
|
-
expect(config.maxCharsPerLine).toBe(80)
|
|
193
|
-
expect(config.showMetrics).toBe(true)
|
|
194
|
-
})
|
|
195
|
-
})
|
|
196
|
-
|
|
197
|
-
describe('limitLines()', () => {
|
|
198
|
-
it('should limit content to maxLines', () => {
|
|
199
|
-
setOutputTier('compact') // maxLines = 4
|
|
200
|
-
const content = 'line1\nline2\nline3\nline4\nline5\nline6'
|
|
201
|
-
const result = limitLines(content)
|
|
202
|
-
|
|
203
|
-
expect(result.split('\n').length).toBe(5) // 4 lines + "...2 more lines"
|
|
204
|
-
expect(result).toContain('...2 more lines')
|
|
205
|
-
})
|
|
206
|
-
|
|
207
|
-
it('should not truncate if under limit', () => {
|
|
208
|
-
setOutputTier('compact')
|
|
209
|
-
const content = 'line1\nline2'
|
|
210
|
-
const result = limitLines(content)
|
|
211
|
-
|
|
212
|
-
expect(result).toBe(content)
|
|
213
|
-
})
|
|
214
|
-
|
|
215
|
-
it('should respect custom maxLines parameter', () => {
|
|
216
|
-
const content = 'line1\nline2\nline3\nline4'
|
|
217
|
-
const result = limitLines(content, 2)
|
|
218
|
-
|
|
219
|
-
expect(result.split('\n').length).toBe(3) // 2 lines + indicator
|
|
220
|
-
expect(result).toContain('...2 more lines')
|
|
221
|
-
})
|
|
222
|
-
|
|
223
|
-
it('should return content unchanged for verbose tier', () => {
|
|
224
|
-
setOutputTier('verbose')
|
|
225
|
-
const content = 'line1\nline2\nline3\nline4\nline5'
|
|
226
|
-
const result = limitLines(content)
|
|
227
|
-
|
|
228
|
-
expect(result).toBe(content)
|
|
229
|
-
})
|
|
230
|
-
})
|
|
231
|
-
|
|
232
|
-
describe('formatForHuman()', () => {
|
|
233
|
-
afterEach(() => {
|
|
234
|
-
setOutputTier('compact')
|
|
235
|
-
})
|
|
236
|
-
|
|
237
|
-
it('should format Linear issue object', () => {
|
|
238
|
-
const issue = {
|
|
239
|
-
identifier: 'PRJ-123',
|
|
240
|
-
title: 'Test issue title',
|
|
241
|
-
status: 'in_progress',
|
|
242
|
-
priority: 'high',
|
|
243
|
-
url: 'https://linear.app/test',
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
const result = formatForHuman(issue)
|
|
247
|
-
expect(result).toContain('PRJ-123')
|
|
248
|
-
expect(result).toContain('Test issue title')
|
|
249
|
-
expect(result).toContain('in_progress')
|
|
250
|
-
})
|
|
251
|
-
|
|
252
|
-
it('should format issue list', () => {
|
|
253
|
-
const list = {
|
|
254
|
-
issues: [
|
|
255
|
-
{ identifier: 'PRJ-1', title: 'First issue', priority: 'high' },
|
|
256
|
-
{ identifier: 'PRJ-2', title: 'Second issue', priority: 'none' },
|
|
257
|
-
],
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
const result = formatForHuman(list)
|
|
261
|
-
expect(result).toContain('PRJ-1')
|
|
262
|
-
expect(result).toContain('PRJ-2')
|
|
263
|
-
})
|
|
264
|
-
|
|
265
|
-
it('should return empty string for silent tier', () => {
|
|
266
|
-
setOutputTier('silent')
|
|
267
|
-
const result = formatForHuman({ test: 'data' })
|
|
268
|
-
expect(result).toBe('')
|
|
269
|
-
})
|
|
270
|
-
|
|
271
|
-
it('should return full JSON for verbose tier', () => {
|
|
272
|
-
setOutputTier('verbose')
|
|
273
|
-
const data = { test: 'data', nested: { key: 'value' } }
|
|
274
|
-
const result = formatForHuman(data)
|
|
275
|
-
expect(result).toBe(JSON.stringify(data, null, 2))
|
|
276
|
-
})
|
|
277
|
-
})
|
|
278
|
-
})
|
|
@@ -1,216 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'bun:test'
|
|
2
|
-
import {
|
|
3
|
-
extractPreservedContent,
|
|
4
|
-
extractPreservedSections,
|
|
5
|
-
hasPreservedSections,
|
|
6
|
-
mergePreservedSections,
|
|
7
|
-
stripPreservedSections,
|
|
8
|
-
validatePreserveBlocks,
|
|
9
|
-
wrapInPreserveMarkers,
|
|
10
|
-
} from '../../utils/preserve-sections'
|
|
11
|
-
|
|
12
|
-
describe('preserve-sections', () => {
|
|
13
|
-
describe('extractPreservedSections', () => {
|
|
14
|
-
it('should extract a single preserved section', () => {
|
|
15
|
-
const content = `# Header
|
|
16
|
-
|
|
17
|
-
<!-- prjct:preserve -->
|
|
18
|
-
My custom content
|
|
19
|
-
<!-- /prjct:preserve -->
|
|
20
|
-
|
|
21
|
-
# Footer`
|
|
22
|
-
|
|
23
|
-
const sections = extractPreservedSections(content)
|
|
24
|
-
expect(sections).toHaveLength(1)
|
|
25
|
-
expect(sections[0].content).toContain('My custom content')
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
it('should extract multiple preserved sections', () => {
|
|
29
|
-
const content = `# Header
|
|
30
|
-
|
|
31
|
-
<!-- prjct:preserve -->
|
|
32
|
-
First section
|
|
33
|
-
<!-- /prjct:preserve -->
|
|
34
|
-
|
|
35
|
-
Some content
|
|
36
|
-
|
|
37
|
-
<!-- prjct:preserve -->
|
|
38
|
-
Second section
|
|
39
|
-
<!-- /prjct:preserve -->`
|
|
40
|
-
|
|
41
|
-
const sections = extractPreservedSections(content)
|
|
42
|
-
expect(sections).toHaveLength(2)
|
|
43
|
-
expect(sections[0].content).toContain('First section')
|
|
44
|
-
expect(sections[1].content).toContain('Second section')
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
it('should handle named sections', () => {
|
|
48
|
-
const content = `<!-- prjct:preserve:custom-rules -->
|
|
49
|
-
My rules
|
|
50
|
-
<!-- /prjct:preserve -->`
|
|
51
|
-
|
|
52
|
-
const sections = extractPreservedSections(content)
|
|
53
|
-
expect(sections).toHaveLength(1)
|
|
54
|
-
expect(sections[0].id).toBe('custom-rules')
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
it('should return empty array when no preserved sections', () => {
|
|
58
|
-
const content = '# Just normal content'
|
|
59
|
-
const sections = extractPreservedSections(content)
|
|
60
|
-
expect(sections).toHaveLength(0)
|
|
61
|
-
})
|
|
62
|
-
|
|
63
|
-
it('should ignore unclosed preserve blocks', () => {
|
|
64
|
-
const content = `<!-- prjct:preserve -->
|
|
65
|
-
No closing tag here`
|
|
66
|
-
|
|
67
|
-
const sections = extractPreservedSections(content)
|
|
68
|
-
expect(sections).toHaveLength(0)
|
|
69
|
-
})
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
describe('extractPreservedContent', () => {
|
|
73
|
-
it('should extract inner content without markers', () => {
|
|
74
|
-
const content = `<!-- prjct:preserve -->
|
|
75
|
-
My content
|
|
76
|
-
<!-- /prjct:preserve -->`
|
|
77
|
-
|
|
78
|
-
const inner = extractPreservedContent(content)
|
|
79
|
-
expect(inner).toHaveLength(1)
|
|
80
|
-
expect(inner[0]).toBe('My content')
|
|
81
|
-
})
|
|
82
|
-
})
|
|
83
|
-
|
|
84
|
-
describe('hasPreservedSections', () => {
|
|
85
|
-
it('should return true when preserved sections exist', () => {
|
|
86
|
-
const content = '<!-- prjct:preserve -->content<!-- /prjct:preserve -->'
|
|
87
|
-
expect(hasPreservedSections(content)).toBe(true)
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
it('should return false when no preserved sections', () => {
|
|
91
|
-
const content = '# Normal markdown'
|
|
92
|
-
expect(hasPreservedSections(content)).toBe(false)
|
|
93
|
-
})
|
|
94
|
-
})
|
|
95
|
-
|
|
96
|
-
describe('mergePreservedSections', () => {
|
|
97
|
-
it('should append preserved sections to new content', () => {
|
|
98
|
-
const oldContent = `# Old Header
|
|
99
|
-
|
|
100
|
-
<!-- prjct:preserve -->
|
|
101
|
-
# My Rules
|
|
102
|
-
- Use tabs
|
|
103
|
-
<!-- /prjct:preserve -->`
|
|
104
|
-
|
|
105
|
-
const newContent = `# New Generated Content
|
|
106
|
-
|
|
107
|
-
This is fresh.`
|
|
108
|
-
|
|
109
|
-
const merged = mergePreservedSections(newContent, oldContent)
|
|
110
|
-
|
|
111
|
-
expect(merged).toContain('# New Generated Content')
|
|
112
|
-
expect(merged).toContain('My Rules')
|
|
113
|
-
expect(merged).toContain('Use tabs')
|
|
114
|
-
expect(merged).toContain('prjct:preserve')
|
|
115
|
-
})
|
|
116
|
-
|
|
117
|
-
it('should return new content unchanged when no preserved sections', () => {
|
|
118
|
-
const oldContent = '# Old content without preserve markers'
|
|
119
|
-
const newContent = '# New content'
|
|
120
|
-
|
|
121
|
-
const merged = mergePreservedSections(newContent, oldContent)
|
|
122
|
-
expect(merged).toBe(newContent)
|
|
123
|
-
})
|
|
124
|
-
|
|
125
|
-
it('should preserve multiple sections', () => {
|
|
126
|
-
const oldContent = `<!-- prjct:preserve -->
|
|
127
|
-
Section 1
|
|
128
|
-
<!-- /prjct:preserve -->
|
|
129
|
-
|
|
130
|
-
<!-- prjct:preserve -->
|
|
131
|
-
Section 2
|
|
132
|
-
<!-- /prjct:preserve -->`
|
|
133
|
-
|
|
134
|
-
const newContent = '# New'
|
|
135
|
-
|
|
136
|
-
const merged = mergePreservedSections(newContent, oldContent)
|
|
137
|
-
expect(merged).toContain('Section 1')
|
|
138
|
-
expect(merged).toContain('Section 2')
|
|
139
|
-
})
|
|
140
|
-
})
|
|
141
|
-
|
|
142
|
-
describe('wrapInPreserveMarkers', () => {
|
|
143
|
-
it('should wrap content with default markers', () => {
|
|
144
|
-
const content = 'My content'
|
|
145
|
-
const wrapped = wrapInPreserveMarkers(content)
|
|
146
|
-
|
|
147
|
-
expect(wrapped).toContain('<!-- prjct:preserve -->')
|
|
148
|
-
expect(wrapped).toContain('My content')
|
|
149
|
-
expect(wrapped).toContain('<!-- /prjct:preserve -->')
|
|
150
|
-
})
|
|
151
|
-
|
|
152
|
-
it('should wrap content with named markers', () => {
|
|
153
|
-
const content = 'My content'
|
|
154
|
-
const wrapped = wrapInPreserveMarkers(content, 'custom')
|
|
155
|
-
|
|
156
|
-
expect(wrapped).toContain('<!-- prjct:preserve:custom -->')
|
|
157
|
-
})
|
|
158
|
-
})
|
|
159
|
-
|
|
160
|
-
describe('stripPreservedSections', () => {
|
|
161
|
-
it('should remove preserved sections from content', () => {
|
|
162
|
-
const content = `# Header
|
|
163
|
-
|
|
164
|
-
<!-- prjct:preserve -->
|
|
165
|
-
Custom stuff
|
|
166
|
-
<!-- /prjct:preserve -->
|
|
167
|
-
|
|
168
|
-
# Footer`
|
|
169
|
-
|
|
170
|
-
const stripped = stripPreservedSections(content)
|
|
171
|
-
expect(stripped).toContain('# Header')
|
|
172
|
-
expect(stripped).toContain('# Footer')
|
|
173
|
-
expect(stripped).not.toContain('Custom stuff')
|
|
174
|
-
expect(stripped).not.toContain('prjct:preserve')
|
|
175
|
-
})
|
|
176
|
-
|
|
177
|
-
it('should return content unchanged when no preserved sections', () => {
|
|
178
|
-
const content = '# Normal content'
|
|
179
|
-
const stripped = stripPreservedSections(content)
|
|
180
|
-
expect(stripped).toBe(content)
|
|
181
|
-
})
|
|
182
|
-
})
|
|
183
|
-
|
|
184
|
-
describe('validatePreserveBlocks', () => {
|
|
185
|
-
it('should validate correct blocks', () => {
|
|
186
|
-
const content = `<!-- prjct:preserve -->
|
|
187
|
-
Content
|
|
188
|
-
<!-- /prjct:preserve -->`
|
|
189
|
-
|
|
190
|
-
const result = validatePreserveBlocks(content)
|
|
191
|
-
expect(result.valid).toBe(true)
|
|
192
|
-
expect(result.errors).toHaveLength(0)
|
|
193
|
-
})
|
|
194
|
-
|
|
195
|
-
it('should detect mismatched markers', () => {
|
|
196
|
-
const content = `<!-- prjct:preserve -->
|
|
197
|
-
Content without closing`
|
|
198
|
-
|
|
199
|
-
const result = validatePreserveBlocks(content)
|
|
200
|
-
expect(result.valid).toBe(false)
|
|
201
|
-
expect(result.errors.length).toBeGreaterThan(0)
|
|
202
|
-
})
|
|
203
|
-
|
|
204
|
-
it('should detect nested blocks', () => {
|
|
205
|
-
const content = `<!-- prjct:preserve -->
|
|
206
|
-
<!-- prjct:preserve -->
|
|
207
|
-
Nested
|
|
208
|
-
<!-- /prjct:preserve -->
|
|
209
|
-
<!-- /prjct:preserve -->`
|
|
210
|
-
|
|
211
|
-
const result = validatePreserveBlocks(content)
|
|
212
|
-
expect(result.valid).toBe(false)
|
|
213
|
-
expect(result.errors.some((e) => e.includes('Nested'))).toBe(true)
|
|
214
|
-
})
|
|
215
|
-
})
|
|
216
|
-
})
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Project command detection tests
|
|
3
|
-
* Ensures prjct-cli uses the repo's own test/lint tooling (not hardcoded).
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { afterEach, beforeEach, describe, expect, it } from 'bun:test'
|
|
7
|
-
import fs from 'node:fs/promises'
|
|
8
|
-
import os from 'node:os'
|
|
9
|
-
import path from 'node:path'
|
|
10
|
-
|
|
11
|
-
import { detectProjectCommands } from '../../utils/project-commands'
|
|
12
|
-
|
|
13
|
-
let tmpRoot: string | null = null
|
|
14
|
-
|
|
15
|
-
async function writeJson(filePath: string, data: unknown): Promise<void> {
|
|
16
|
-
await fs.mkdir(path.dirname(filePath), { recursive: true })
|
|
17
|
-
await fs.writeFile(filePath, JSON.stringify(data, null, 2), 'utf-8')
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
async function writeText(filePath: string, content: string): Promise<void> {
|
|
21
|
-
await fs.mkdir(path.dirname(filePath), { recursive: true })
|
|
22
|
-
await fs.writeFile(filePath, content, 'utf-8')
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
describe('detectProjectCommands', () => {
|
|
26
|
-
beforeEach(async () => {
|
|
27
|
-
tmpRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'prjct-detect-commands-'))
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
afterEach(async () => {
|
|
31
|
-
if (!tmpRoot) return
|
|
32
|
-
await fs.rm(tmpRoot, { recursive: true, force: true })
|
|
33
|
-
tmpRoot = null
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
it('detects JS project and respects declared pnpm packageManager', async () => {
|
|
37
|
-
await writeJson(path.join(tmpRoot!, 'package.json'), {
|
|
38
|
-
name: 'x',
|
|
39
|
-
packageManager: 'pnpm@9.0.0',
|
|
40
|
-
scripts: { test: 'vitest', lint: 'eslint .', typecheck: 'tsc -p tsconfig.json' },
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
const detected = await detectProjectCommands(tmpRoot!)
|
|
44
|
-
expect(detected.stack).toBe('js')
|
|
45
|
-
expect(detected.packageManager).toBe('pnpm')
|
|
46
|
-
expect(detected.test?.command).toBe('pnpm test')
|
|
47
|
-
expect(detected.lint?.command).toBe('pnpm run lint')
|
|
48
|
-
expect(detected.typecheck?.command).toBe('pnpm run typecheck')
|
|
49
|
-
})
|
|
50
|
-
|
|
51
|
-
it('detects Python pytest via pytest.ini', async () => {
|
|
52
|
-
await writeText(path.join(tmpRoot!, 'pytest.ini'), '[pytest]\n')
|
|
53
|
-
const detected = await detectProjectCommands(tmpRoot!)
|
|
54
|
-
expect(detected.stack).toBe('python')
|
|
55
|
-
expect(detected.test?.command).toBe('pytest')
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
it('detects Go via go.mod', async () => {
|
|
59
|
-
await writeText(path.join(tmpRoot!, 'go.mod'), 'module example.com/test\n')
|
|
60
|
-
const detected = await detectProjectCommands(tmpRoot!)
|
|
61
|
-
expect(detected.stack).toBe('go')
|
|
62
|
-
expect(detected.test?.command).toBe('go test ./...')
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
it('detects Rust via Cargo.toml', async () => {
|
|
66
|
-
await writeText(path.join(tmpRoot!, 'Cargo.toml'), '[package]\nname="x"\nversion="0.1.0"\n')
|
|
67
|
-
const detected = await detectProjectCommands(tmpRoot!)
|
|
68
|
-
expect(detected.stack).toBe('rust')
|
|
69
|
-
expect(detected.test?.command).toBe('cargo test')
|
|
70
|
-
})
|
|
71
|
-
})
|