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,306 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Skill Service
|
|
3
|
-
*
|
|
4
|
-
* Manages discoverable skills from SKILL.md files.
|
|
5
|
-
* Skills are reusable prompts/instructions with metadata.
|
|
6
|
-
*
|
|
7
|
-
* Skill sources (in priority order):
|
|
8
|
-
* 1. Project: .prjct/skills/*.md
|
|
9
|
-
* 2. Provider: ~/.claude/skills/* or ~/.gemini/skills/* (SKILL.md format)
|
|
10
|
-
* 3. Global: ~/.prjct-cli/skills/*.md
|
|
11
|
-
* 4. Built-in: templates/skills/*.md
|
|
12
|
-
*
|
|
13
|
-
* Note: Claude Code and Gemini CLI use identical SKILL.md format,
|
|
14
|
-
* so skills are compatible between both providers.
|
|
15
|
-
*
|
|
16
|
-
* @version 1.1.0
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
import fs from 'node:fs/promises'
|
|
20
|
-
import path from 'node:path'
|
|
21
|
-
import { glob } from 'glob'
|
|
22
|
-
|
|
23
|
-
import type { Skill, SkillMetadata, SkillSearchResult } from '../types'
|
|
24
|
-
import type { AIProviderName } from '../types/provider'
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Parse YAML-like frontmatter from markdown
|
|
28
|
-
*/
|
|
29
|
-
function parseFrontmatter(content: string): { metadata: Record<string, unknown>; body: string } {
|
|
30
|
-
const frontmatterRegex = /^---\s*\n([\s\S]*?)\n---\s*\n([\s\S]*)$/
|
|
31
|
-
const match = content.match(frontmatterRegex)
|
|
32
|
-
|
|
33
|
-
if (!match) {
|
|
34
|
-
return { metadata: {}, body: content }
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const [, frontmatter, body] = match
|
|
38
|
-
const metadata: Record<string, unknown> = {}
|
|
39
|
-
|
|
40
|
-
// Simple YAML parsing (key: value)
|
|
41
|
-
for (const line of frontmatter.split('\n')) {
|
|
42
|
-
const colonIndex = line.indexOf(':')
|
|
43
|
-
if (colonIndex > 0) {
|
|
44
|
-
const key = line.slice(0, colonIndex).trim()
|
|
45
|
-
let value: unknown = line.slice(colonIndex + 1).trim()
|
|
46
|
-
|
|
47
|
-
// Handle arrays [item1, item2]
|
|
48
|
-
if (typeof value === 'string' && value.startsWith('[') && value.endsWith(']')) {
|
|
49
|
-
value = value
|
|
50
|
-
.slice(1, -1)
|
|
51
|
-
.split(',')
|
|
52
|
-
.map((s) => s.trim().replace(/['"]/g, ''))
|
|
53
|
-
}
|
|
54
|
-
// Remove quotes
|
|
55
|
-
else if (typeof value === 'string' && (value.startsWith('"') || value.startsWith("'"))) {
|
|
56
|
-
value = value.slice(1, -1)
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
metadata[key] = value
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
return { metadata, body: body.trim() }
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Convert filename to skill ID
|
|
68
|
-
* For SKILL.md files, uses the parent directory name
|
|
69
|
-
*/
|
|
70
|
-
function fileToSkillId(filePath: string): string {
|
|
71
|
-
const basename = path.basename(filePath, '.md')
|
|
72
|
-
|
|
73
|
-
// For SKILL.md files (provider format), use parent directory name
|
|
74
|
-
if (basename.toUpperCase() === 'SKILL') {
|
|
75
|
-
const dirName = path.basename(path.dirname(filePath))
|
|
76
|
-
return dirName.toLowerCase().replace(/[^a-z0-9]+/g, '-')
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
return basename.toLowerCase().replace(/[^a-z0-9]+/g, '-')
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
class SkillService {
|
|
83
|
-
private skills: Map<string, Skill> = new Map()
|
|
84
|
-
private loaded = false
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Get all skill directories in order of priority
|
|
88
|
-
*/
|
|
89
|
-
private getSkillDirs(
|
|
90
|
-
projectPath?: string,
|
|
91
|
-
provider?: AIProviderName
|
|
92
|
-
): Array<{ dir: string; source: Skill['source'] }> {
|
|
93
|
-
const homeDir = process.env.HOME || process.env.USERPROFILE || '~'
|
|
94
|
-
const dirs: Array<{ dir: string; source: Skill['source'] }> = []
|
|
95
|
-
|
|
96
|
-
// Project skills (highest priority)
|
|
97
|
-
if (projectPath) {
|
|
98
|
-
dirs.push({ dir: path.join(projectPath, '.prjct', 'skills'), source: 'project' })
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// Provider skills (Claude or Gemini)
|
|
102
|
-
// Both use SKILL.md format, so skills are compatible
|
|
103
|
-
if (provider) {
|
|
104
|
-
const providerDir = provider === 'gemini' ? '.gemini' : '.claude'
|
|
105
|
-
dirs.push({ dir: path.join(homeDir, providerDir, 'skills'), source: 'global' })
|
|
106
|
-
} else {
|
|
107
|
-
// Check both providers if no specific one is set
|
|
108
|
-
dirs.push({ dir: path.join(homeDir, '.claude', 'skills'), source: 'global' })
|
|
109
|
-
dirs.push({ dir: path.join(homeDir, '.gemini', 'skills'), source: 'global' })
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// prjct global skills
|
|
113
|
-
dirs.push({ dir: path.join(homeDir, '.prjct-cli', 'skills'), source: 'global' })
|
|
114
|
-
|
|
115
|
-
// Built-in skills (lowest priority)
|
|
116
|
-
dirs.push({ dir: path.join(__dirname, '..', '..', 'templates', 'skills'), source: 'builtin' })
|
|
117
|
-
|
|
118
|
-
return dirs
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Load a single skill from file
|
|
123
|
-
*/
|
|
124
|
-
private async loadSkill(filePath: string, source: Skill['source']): Promise<Skill | null> {
|
|
125
|
-
try {
|
|
126
|
-
const content = await fs.readFile(filePath, 'utf-8')
|
|
127
|
-
const { metadata, body } = parseFrontmatter(content)
|
|
128
|
-
|
|
129
|
-
const id = fileToSkillId(filePath)
|
|
130
|
-
const name = (metadata.name as string) || id
|
|
131
|
-
|
|
132
|
-
// Extract _prjct source tracking metadata if present
|
|
133
|
-
const prjctMeta = metadata._prjct as Record<string, unknown> | undefined
|
|
134
|
-
|
|
135
|
-
return {
|
|
136
|
-
id,
|
|
137
|
-
name,
|
|
138
|
-
description: (metadata.description as string) || '',
|
|
139
|
-
content: body,
|
|
140
|
-
source,
|
|
141
|
-
filePath,
|
|
142
|
-
metadata: {
|
|
143
|
-
name,
|
|
144
|
-
description: metadata.description as string,
|
|
145
|
-
agent: metadata.agent as string,
|
|
146
|
-
tags: metadata.tags as string[],
|
|
147
|
-
version: metadata.version as string,
|
|
148
|
-
category: metadata.category as string,
|
|
149
|
-
author: metadata.author as string,
|
|
150
|
-
sourceUrl: prjctMeta?.sourceUrl as string,
|
|
151
|
-
sourceType: prjctMeta?.sourceType as SkillMetadata['sourceType'],
|
|
152
|
-
installedAt: prjctMeta?.installedAt as string,
|
|
153
|
-
sha: prjctMeta?.sha as string,
|
|
154
|
-
},
|
|
155
|
-
}
|
|
156
|
-
} catch (_error) {
|
|
157
|
-
// File read or parse error - expected for missing skills
|
|
158
|
-
return null
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/**
|
|
163
|
-
* Load all skills from all sources
|
|
164
|
-
*/
|
|
165
|
-
async loadSkills(projectPath?: string, provider?: AIProviderName): Promise<void> {
|
|
166
|
-
this.skills.clear()
|
|
167
|
-
const dirs = this.getSkillDirs(projectPath, provider)
|
|
168
|
-
|
|
169
|
-
for (const { dir, source } of dirs) {
|
|
170
|
-
try {
|
|
171
|
-
// Check both patterns in ALL skill directories:
|
|
172
|
-
// 1. Flat files: {dir}/{name}.md
|
|
173
|
-
// 2. Subdirectories: {dir}/{name}/SKILL.md (ecosystem standard)
|
|
174
|
-
const flatFiles = await glob('*.md', { cwd: dir, absolute: true })
|
|
175
|
-
const subdirFiles = await glob('*/SKILL.md', { cwd: dir, absolute: true })
|
|
176
|
-
|
|
177
|
-
// Load subdirectory skills first (ecosystem standard takes priority within same dir)
|
|
178
|
-
for (const file of subdirFiles) {
|
|
179
|
-
const skill = await this.loadSkill(file, source)
|
|
180
|
-
if (skill && !this.skills.has(skill.id)) {
|
|
181
|
-
this.skills.set(skill.id, skill)
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
// Then flat files (don't override subdirectory version)
|
|
186
|
-
for (const file of flatFiles) {
|
|
187
|
-
const skill = await this.loadSkill(file, source)
|
|
188
|
-
if (skill && !this.skills.has(skill.id)) {
|
|
189
|
-
this.skills.set(skill.id, skill)
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
} catch (_error) {
|
|
193
|
-
// Directory doesn't exist - expected for new installs
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
this.loaded = true
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
* Get all loaded skills
|
|
202
|
-
*/
|
|
203
|
-
async getAll(projectPath?: string): Promise<Skill[]> {
|
|
204
|
-
if (!this.loaded) {
|
|
205
|
-
await this.loadSkills(projectPath)
|
|
206
|
-
}
|
|
207
|
-
return Array.from(this.skills.values())
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
/**
|
|
211
|
-
* Get a skill by ID
|
|
212
|
-
*/
|
|
213
|
-
async get(id: string, projectPath?: string): Promise<Skill | null> {
|
|
214
|
-
if (!this.loaded) {
|
|
215
|
-
await this.loadSkills(projectPath)
|
|
216
|
-
}
|
|
217
|
-
return this.skills.get(id) || null
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
/**
|
|
221
|
-
* Search skills by query
|
|
222
|
-
*/
|
|
223
|
-
async search(query: string, projectPath?: string): Promise<SkillSearchResult[]> {
|
|
224
|
-
const skills = await this.getAll(projectPath)
|
|
225
|
-
const queryLower = query.toLowerCase()
|
|
226
|
-
|
|
227
|
-
const results: SkillSearchResult[] = []
|
|
228
|
-
|
|
229
|
-
for (const skill of skills) {
|
|
230
|
-
let relevance = 0
|
|
231
|
-
|
|
232
|
-
// Name match (highest weight)
|
|
233
|
-
if (skill.name.toLowerCase().includes(queryLower)) {
|
|
234
|
-
relevance += 10
|
|
235
|
-
}
|
|
236
|
-
if (skill.id.includes(queryLower)) {
|
|
237
|
-
relevance += 8
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
// Description match
|
|
241
|
-
if (skill.description.toLowerCase().includes(queryLower)) {
|
|
242
|
-
relevance += 5
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
// Tag match
|
|
246
|
-
if (skill.metadata.tags?.some((t) => t.toLowerCase().includes(queryLower))) {
|
|
247
|
-
relevance += 3
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
// Content match (lowest weight)
|
|
251
|
-
if (skill.content.toLowerCase().includes(queryLower)) {
|
|
252
|
-
relevance += 1
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
if (relevance > 0) {
|
|
256
|
-
results.push({ skill, relevance })
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
// Sort by relevance descending
|
|
261
|
-
return results.sort((a, b) => b.relevance - a.relevance)
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
/**
|
|
265
|
-
* List skills grouped by source
|
|
266
|
-
*/
|
|
267
|
-
async listBySource(projectPath?: string): Promise<Record<Skill['source'], Skill[]>> {
|
|
268
|
-
const skills = await this.getAll(projectPath)
|
|
269
|
-
|
|
270
|
-
const grouped: Record<Skill['source'], Skill[]> = {
|
|
271
|
-
project: [],
|
|
272
|
-
global: [],
|
|
273
|
-
builtin: [],
|
|
274
|
-
remote: [],
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
for (const skill of skills) {
|
|
278
|
-
grouped[skill.source].push(skill)
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
return grouped
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
/**
|
|
285
|
-
* Force reload skills
|
|
286
|
-
*/
|
|
287
|
-
async reload(projectPath?: string): Promise<void> {
|
|
288
|
-
this.loaded = false
|
|
289
|
-
await this.loadSkills(projectPath)
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
/**
|
|
293
|
-
* Get skill count
|
|
294
|
-
*/
|
|
295
|
-
async count(projectPath?: string): Promise<number> {
|
|
296
|
-
const skills = await this.getAll(projectPath)
|
|
297
|
-
return skills.length
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
// Singleton instance
|
|
302
|
-
const skillService = new SkillService()
|
|
303
|
-
export default skillService
|
|
304
|
-
|
|
305
|
-
// Export class for testing
|
|
306
|
-
export { SkillService }
|
|
@@ -1,229 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* StackDetector - Detects project technology stack
|
|
3
|
-
*
|
|
4
|
-
* Analyzes the project to detect:
|
|
5
|
-
* - Frontend frameworks (React, Vue, Svelte, Angular)
|
|
6
|
-
* - Backend frameworks (Express, Fastify, Hono, etc.)
|
|
7
|
-
* - Database usage (Prisma, Mongoose, etc.)
|
|
8
|
-
* - Docker configuration
|
|
9
|
-
* - Testing frameworks
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import fs from 'node:fs/promises'
|
|
13
|
-
import path from 'node:path'
|
|
14
|
-
import type { StackDetection, StackPackageJson } from '../types'
|
|
15
|
-
|
|
16
|
-
export type { StackDetection, StackPackageJson } from '../types'
|
|
17
|
-
|
|
18
|
-
// ============================================================================
|
|
19
|
-
// STACK DETECTOR
|
|
20
|
-
// ============================================================================
|
|
21
|
-
|
|
22
|
-
export class StackDetector {
|
|
23
|
-
private projectPath: string
|
|
24
|
-
|
|
25
|
-
constructor(projectPath: string) {
|
|
26
|
-
this.projectPath = projectPath
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Detect the full technology stack of the project
|
|
31
|
-
*/
|
|
32
|
-
async detect(): Promise<StackDetection> {
|
|
33
|
-
const stack: StackDetection = {
|
|
34
|
-
hasFrontend: false,
|
|
35
|
-
hasBackend: false,
|
|
36
|
-
hasDatabase: false,
|
|
37
|
-
hasDocker: false,
|
|
38
|
-
hasTesting: false,
|
|
39
|
-
frontendType: null,
|
|
40
|
-
frameworks: [],
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// Try to read package.json for JS/TS projects
|
|
44
|
-
const pkg = await this.readPackageJson()
|
|
45
|
-
|
|
46
|
-
if (pkg) {
|
|
47
|
-
const deps = { ...pkg.dependencies, ...pkg.devDependencies }
|
|
48
|
-
|
|
49
|
-
// Detect each category
|
|
50
|
-
this.detectFrontend(deps, stack)
|
|
51
|
-
this.detectBackend(deps, stack)
|
|
52
|
-
this.detectDatabase(deps, stack)
|
|
53
|
-
this.detectTesting(deps, pkg, stack)
|
|
54
|
-
this.collectFrameworks(deps, stack)
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Docker detection (file-based)
|
|
58
|
-
stack.hasDocker = await this.detectDocker()
|
|
59
|
-
|
|
60
|
-
return stack
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// ==========================================================================
|
|
64
|
-
// DETECTION METHODS
|
|
65
|
-
// ==========================================================================
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Detect frontend frameworks and type (web/mobile/both)
|
|
69
|
-
*/
|
|
70
|
-
private detectFrontend(deps: Record<string, string>, stack: StackDetection): void {
|
|
71
|
-
// Web frameworks
|
|
72
|
-
if (deps.react || deps.vue || deps.svelte || deps['@angular/core']) {
|
|
73
|
-
stack.hasFrontend = true
|
|
74
|
-
stack.frontendType = 'web'
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// Mobile frameworks
|
|
78
|
-
if (deps['react-native'] || deps.expo) {
|
|
79
|
-
stack.hasFrontend = true
|
|
80
|
-
stack.frontendType = stack.frontendType === 'web' ? 'both' : 'mobile'
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Detect backend frameworks
|
|
86
|
-
*/
|
|
87
|
-
private detectBackend(deps: Record<string, string>, stack: StackDetection): void {
|
|
88
|
-
const backendFrameworks = [
|
|
89
|
-
'express',
|
|
90
|
-
'fastify',
|
|
91
|
-
'hono',
|
|
92
|
-
'koa',
|
|
93
|
-
'@nestjs/core',
|
|
94
|
-
'nest',
|
|
95
|
-
'@hapi/hapi',
|
|
96
|
-
'restify',
|
|
97
|
-
'polka',
|
|
98
|
-
]
|
|
99
|
-
|
|
100
|
-
if (backendFrameworks.some((fw) => deps[fw])) {
|
|
101
|
-
stack.hasBackend = true
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Detect database/ORM usage
|
|
107
|
-
*/
|
|
108
|
-
private detectDatabase(deps: Record<string, string>, stack: StackDetection): void {
|
|
109
|
-
const databaseLibs = [
|
|
110
|
-
'prisma',
|
|
111
|
-
'@prisma/client',
|
|
112
|
-
'mongoose',
|
|
113
|
-
'pg',
|
|
114
|
-
'mysql2',
|
|
115
|
-
'sequelize',
|
|
116
|
-
'typeorm',
|
|
117
|
-
'drizzle-orm',
|
|
118
|
-
'knex',
|
|
119
|
-
'better-sqlite3',
|
|
120
|
-
'mongodb',
|
|
121
|
-
'redis',
|
|
122
|
-
'ioredis',
|
|
123
|
-
]
|
|
124
|
-
|
|
125
|
-
if (databaseLibs.some((lib) => deps[lib])) {
|
|
126
|
-
stack.hasDatabase = true
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* Detect testing frameworks
|
|
132
|
-
*/
|
|
133
|
-
private detectTesting(
|
|
134
|
-
deps: Record<string, string>,
|
|
135
|
-
pkg: StackPackageJson,
|
|
136
|
-
stack: StackDetection
|
|
137
|
-
): void {
|
|
138
|
-
const testingFrameworks = [
|
|
139
|
-
'jest',
|
|
140
|
-
'vitest',
|
|
141
|
-
'mocha',
|
|
142
|
-
'@testing-library/react',
|
|
143
|
-
'@testing-library/vue',
|
|
144
|
-
'cypress',
|
|
145
|
-
'playwright',
|
|
146
|
-
'@playwright/test',
|
|
147
|
-
'ava',
|
|
148
|
-
'tap',
|
|
149
|
-
'bun-types', // Bun's built-in test runner
|
|
150
|
-
]
|
|
151
|
-
|
|
152
|
-
if (testingFrameworks.some((fw) => deps[fw] || pkg.devDependencies?.[fw])) {
|
|
153
|
-
stack.hasTesting = true
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Detect Docker configuration
|
|
159
|
-
*/
|
|
160
|
-
private async detectDocker(): Promise<boolean> {
|
|
161
|
-
const dockerFiles = ['Dockerfile', 'docker-compose.yml', 'docker-compose.yaml', '.dockerignore']
|
|
162
|
-
|
|
163
|
-
for (const file of dockerFiles) {
|
|
164
|
-
if (await this.fileExists(file)) {
|
|
165
|
-
return true
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
return false
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Collect detected frameworks into the frameworks array
|
|
174
|
-
*/
|
|
175
|
-
private collectFrameworks(deps: Record<string, string>, stack: StackDetection): void {
|
|
176
|
-
// Frontend frameworks
|
|
177
|
-
if (deps.react) stack.frameworks.push('React')
|
|
178
|
-
if (deps.next) stack.frameworks.push('Next.js')
|
|
179
|
-
if (deps.vue) stack.frameworks.push('Vue')
|
|
180
|
-
if (deps.nuxt) stack.frameworks.push('Nuxt')
|
|
181
|
-
if (deps.svelte) stack.frameworks.push('Svelte')
|
|
182
|
-
if (deps['@angular/core']) stack.frameworks.push('Angular')
|
|
183
|
-
if (deps['react-native']) stack.frameworks.push('React Native')
|
|
184
|
-
if (deps.expo) stack.frameworks.push('Expo')
|
|
185
|
-
|
|
186
|
-
// Backend frameworks
|
|
187
|
-
if (deps.express) stack.frameworks.push('Express')
|
|
188
|
-
if (deps.fastify) stack.frameworks.push('Fastify')
|
|
189
|
-
if (deps.hono) stack.frameworks.push('Hono')
|
|
190
|
-
if (deps.koa) stack.frameworks.push('Koa')
|
|
191
|
-
if (deps['@nestjs/core'] || deps.nest) stack.frameworks.push('NestJS')
|
|
192
|
-
|
|
193
|
-
// Meta-frameworks
|
|
194
|
-
if (deps.astro) stack.frameworks.push('Astro')
|
|
195
|
-
if (deps.remix) stack.frameworks.push('Remix')
|
|
196
|
-
if (deps.gatsby) stack.frameworks.push('Gatsby')
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
// ==========================================================================
|
|
200
|
-
// HELPERS
|
|
201
|
-
// ==========================================================================
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* Read and parse package.json
|
|
205
|
-
*/
|
|
206
|
-
private async readPackageJson(): Promise<StackPackageJson | null> {
|
|
207
|
-
try {
|
|
208
|
-
const pkgPath = path.join(this.projectPath, 'package.json')
|
|
209
|
-
const content = await fs.readFile(pkgPath, 'utf-8')
|
|
210
|
-
return JSON.parse(content)
|
|
211
|
-
} catch {
|
|
212
|
-
return null
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
/**
|
|
217
|
-
* Check if a file exists in the project
|
|
218
|
-
*/
|
|
219
|
-
private async fileExists(filename: string): Promise<boolean> {
|
|
220
|
-
try {
|
|
221
|
-
await fs.access(path.join(this.projectPath, filename))
|
|
222
|
-
return true
|
|
223
|
-
} catch {
|
|
224
|
-
return false
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
export default StackDetector
|