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,578 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* AI Provider - Multi-agent support for prjct-cli
|
|
3
|
-
*
|
|
4
|
-
* Supports multiple AI coding agents with a unified abstraction layer:
|
|
5
|
-
* - Claude Code (CLI): ~/.claude/, CLAUDE.md, .md commands
|
|
6
|
-
* - Gemini CLI (CLI): ~/.gemini/, GEMINI.md, .toml commands
|
|
7
|
-
* - Cursor IDE (GUI): .cursor/ (project-level), .mdc rules
|
|
8
|
-
* - Windsurf IDE (GUI): .windsurf/ (project-level), .md rules with YAML frontmatter
|
|
9
|
-
*
|
|
10
|
-
* Key differences:
|
|
11
|
-
* - CLI providers (Claude/Gemini) have global config directories
|
|
12
|
-
* - Cursor/Windsurf have project-level config only (no ~/.cursor/ or ~/.windsurf/)
|
|
13
|
-
*
|
|
14
|
-
* @see https://geminicli.com/docs/cli/gemini-md/
|
|
15
|
-
* @see https://geminicli.com/docs/cli/skills/
|
|
16
|
-
* @see https://cursor.com/docs/context/rules
|
|
17
|
-
* @see https://docs.windsurf.com/windsurf/cascade/memories
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
import { exec } from 'node:child_process'
|
|
21
|
-
import os from 'node:os'
|
|
22
|
-
import path from 'node:path'
|
|
23
|
-
import { promisify } from 'node:util'
|
|
24
|
-
import { compareSemver } from '../schemas/model'
|
|
25
|
-
import { fileExists } from '../utils/fs-helpers'
|
|
26
|
-
import { readProviderCache, writeProviderCache } from '../utils/provider-cache'
|
|
27
|
-
|
|
28
|
-
const execAsync = promisify(exec)
|
|
29
|
-
const SPAWN_TIMEOUT_MS = 2000
|
|
30
|
-
|
|
31
|
-
import type {
|
|
32
|
-
AIProviderConfig,
|
|
33
|
-
AIProviderName,
|
|
34
|
-
CursorProjectDetection,
|
|
35
|
-
ProviderBranding,
|
|
36
|
-
ProviderDetectionResult,
|
|
37
|
-
ProviderSelectionResult,
|
|
38
|
-
WindsurfProjectDetection,
|
|
39
|
-
} from '../types/provider'
|
|
40
|
-
|
|
41
|
-
// =============================================================================
|
|
42
|
-
// Provider Configurations
|
|
43
|
-
// =============================================================================
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Claude Code provider configuration
|
|
47
|
-
*/
|
|
48
|
-
export const ClaudeProvider: AIProviderConfig = {
|
|
49
|
-
name: 'claude',
|
|
50
|
-
displayName: 'Claude Code',
|
|
51
|
-
cliCommand: 'claude',
|
|
52
|
-
configDir: path.join(os.homedir(), '.claude'),
|
|
53
|
-
contextFile: 'CLAUDE.md',
|
|
54
|
-
skillsDir: path.join(os.homedir(), '.claude', 'skills'),
|
|
55
|
-
commandsDir: '.claude/commands',
|
|
56
|
-
commandFormat: 'md',
|
|
57
|
-
settingsFile: 'settings.json',
|
|
58
|
-
projectSettingsFile: 'settings.local.json',
|
|
59
|
-
ignoreFile: '.claudeignore',
|
|
60
|
-
websiteUrl: 'https://www.anthropic.com/claude',
|
|
61
|
-
docsUrl: 'https://docs.anthropic.com/claude-code',
|
|
62
|
-
defaultModel: 'sonnet',
|
|
63
|
-
supportedModels: ['opus', 'sonnet', 'haiku'],
|
|
64
|
-
minCliVersion: '1.0.0',
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Gemini CLI provider configuration
|
|
69
|
-
*/
|
|
70
|
-
export const GeminiProvider: AIProviderConfig = {
|
|
71
|
-
name: 'gemini',
|
|
72
|
-
displayName: 'Gemini CLI',
|
|
73
|
-
cliCommand: 'gemini',
|
|
74
|
-
configDir: path.join(os.homedir(), '.gemini'),
|
|
75
|
-
contextFile: 'GEMINI.md',
|
|
76
|
-
skillsDir: path.join(os.homedir(), '.gemini', 'skills'),
|
|
77
|
-
commandsDir: '.gemini/commands',
|
|
78
|
-
commandFormat: 'toml',
|
|
79
|
-
settingsFile: 'settings.json',
|
|
80
|
-
projectSettingsFile: 'settings.json',
|
|
81
|
-
ignoreFile: '.geminiignore',
|
|
82
|
-
websiteUrl: 'https://geminicli.com',
|
|
83
|
-
docsUrl: 'https://geminicli.com/docs',
|
|
84
|
-
defaultModel: '2.5-flash',
|
|
85
|
-
supportedModels: ['2.5-pro', '2.5-flash', '2.0-flash'],
|
|
86
|
-
minCliVersion: '1.0.0',
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Google Antigravity provider configuration
|
|
91
|
-
*
|
|
92
|
-
* An "agent-first" platform that manages multiple agents.
|
|
93
|
-
* Config is located in ~/.gemini/antigravity/
|
|
94
|
-
* Uses SKILL.md for skills and mcp_config.json for tools.
|
|
95
|
-
*/
|
|
96
|
-
export const AntigravityProvider: AIProviderConfig = {
|
|
97
|
-
name: 'antigravity',
|
|
98
|
-
displayName: 'Google Antigravity',
|
|
99
|
-
cliCommand: null, // Not a CLI command, but a platform/app
|
|
100
|
-
configDir: path.join(os.homedir(), '.gemini', 'antigravity'),
|
|
101
|
-
contextFile: 'ANTIGRAVITY.md',
|
|
102
|
-
skillsDir: path.join(os.homedir(), '.gemini', 'antigravity', 'global_skills'),
|
|
103
|
-
commandsDir: '.agent/skills', // Antigravity uses .agent/skills in projects
|
|
104
|
-
commandFormat: 'md', // Uses SKILL.md
|
|
105
|
-
settingsFile: 'mcp_config.json', // Uses MCP config
|
|
106
|
-
projectSettingsFile: null,
|
|
107
|
-
ignoreFile: '.agentignore', // Assumed
|
|
108
|
-
websiteUrl: 'https://gemini.google.com/app/antigravity',
|
|
109
|
-
docsUrl: 'https://gemini.google.com/app/antigravity',
|
|
110
|
-
defaultModel: null, // Platform-managed
|
|
111
|
-
supportedModels: [],
|
|
112
|
-
minCliVersion: null,
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Cursor IDE provider configuration
|
|
117
|
-
*
|
|
118
|
-
* Key differences from Claude/Gemini:
|
|
119
|
-
* - NOT a CLI (GUI app, VS Code fork)
|
|
120
|
-
* - No global config directory (~/.cursor/ doesn't exist)
|
|
121
|
-
* - Project-level config only (.cursor/rules/, .cursor/commands/)
|
|
122
|
-
* - User can select any model (GPT, Claude, Gemini, DeepSeek, etc.)
|
|
123
|
-
*
|
|
124
|
-
* @see https://cursor.com/docs/context/rules
|
|
125
|
-
*/
|
|
126
|
-
export const CursorProvider: AIProviderConfig = {
|
|
127
|
-
name: 'cursor',
|
|
128
|
-
displayName: 'Cursor IDE',
|
|
129
|
-
cliCommand: null, // Not a CLI - GUI app
|
|
130
|
-
configDir: null, // No global config directory
|
|
131
|
-
contextFile: 'prjct.mdc', // Uses .mdc format with frontmatter
|
|
132
|
-
skillsDir: null, // No skills directory
|
|
133
|
-
commandsDir: '.cursor/commands',
|
|
134
|
-
rulesDir: '.cursor/rules', // Cursor-specific: rules directory
|
|
135
|
-
commandFormat: 'md',
|
|
136
|
-
settingsFile: null,
|
|
137
|
-
projectSettingsFile: null,
|
|
138
|
-
ignoreFile: '.cursorignore',
|
|
139
|
-
isProjectLevel: true, // Config is project-level only
|
|
140
|
-
websiteUrl: 'https://cursor.com',
|
|
141
|
-
docsUrl: 'https://cursor.com/docs',
|
|
142
|
-
defaultModel: null, // Multi-model IDE, user selects
|
|
143
|
-
supportedModels: [],
|
|
144
|
-
minCliVersion: null,
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* Windsurf IDE provider configuration
|
|
149
|
-
*
|
|
150
|
-
* Key differences from Cursor:
|
|
151
|
-
* - Uses .md files (not .mdc) with YAML frontmatter
|
|
152
|
-
* - Uses "workflows" instead of "commands"
|
|
153
|
-
* - Frontmatter uses `trigger: always_on` instead of `alwaysApply: true`
|
|
154
|
-
* - Character limits: 6000 per file, 12000 total
|
|
155
|
-
*
|
|
156
|
-
* @see https://docs.windsurf.com/windsurf/cascade/memories
|
|
157
|
-
* @see https://docs.windsurf.com/windsurf/cascade/workflows
|
|
158
|
-
*/
|
|
159
|
-
export const WindsurfProvider: AIProviderConfig = {
|
|
160
|
-
name: 'windsurf',
|
|
161
|
-
displayName: 'Windsurf IDE',
|
|
162
|
-
cliCommand: null, // Not a CLI - GUI app
|
|
163
|
-
configDir: null, // No global config directory
|
|
164
|
-
contextFile: 'prjct.md', // Uses .md format (not .mdc)
|
|
165
|
-
skillsDir: null, // No skills directory
|
|
166
|
-
commandsDir: '.windsurf/workflows', // Windsurf uses "workflows" not "commands"
|
|
167
|
-
rulesDir: '.windsurf/rules',
|
|
168
|
-
commandFormat: 'md',
|
|
169
|
-
settingsFile: null,
|
|
170
|
-
projectSettingsFile: null,
|
|
171
|
-
ignoreFile: '.windsurfignore',
|
|
172
|
-
isProjectLevel: true, // Config is project-level only
|
|
173
|
-
websiteUrl: 'https://windsurf.com',
|
|
174
|
-
docsUrl: 'https://docs.windsurf.com',
|
|
175
|
-
defaultModel: null, // Multi-model IDE, user selects
|
|
176
|
-
supportedModels: [],
|
|
177
|
-
minCliVersion: null,
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
/**
|
|
181
|
-
* All available providers
|
|
182
|
-
*/
|
|
183
|
-
export const Providers: Record<AIProviderName, AIProviderConfig> = {
|
|
184
|
-
claude: ClaudeProvider,
|
|
185
|
-
gemini: GeminiProvider,
|
|
186
|
-
cursor: CursorProvider,
|
|
187
|
-
antigravity: AntigravityProvider,
|
|
188
|
-
windsurf: WindsurfProvider,
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
// =============================================================================
|
|
192
|
-
// Provider Detection
|
|
193
|
-
// =============================================================================
|
|
194
|
-
|
|
195
|
-
/**
|
|
196
|
-
* Check if a CLI command is available
|
|
197
|
-
*/
|
|
198
|
-
async function whichCommand(command: string): Promise<string | null> {
|
|
199
|
-
try {
|
|
200
|
-
const { stdout } = await execAsync(`which ${command}`, { timeout: SPAWN_TIMEOUT_MS })
|
|
201
|
-
return stdout.trim()
|
|
202
|
-
} catch {
|
|
203
|
-
return null
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
* Get CLI version
|
|
209
|
-
*/
|
|
210
|
-
async function getCliVersion(command: string): Promise<string | null> {
|
|
211
|
-
try {
|
|
212
|
-
const { stdout } = await execAsync(`${command} --version`, { timeout: SPAWN_TIMEOUT_MS })
|
|
213
|
-
// Extract version number from output (e.g., "claude 1.0.0" -> "1.0.0")
|
|
214
|
-
const match = stdout.match(/\d+\.\d+\.\d+/)
|
|
215
|
-
return match ? match[0] : stdout.trim()
|
|
216
|
-
} catch {
|
|
217
|
-
return null
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
/**
|
|
222
|
-
* Detect if a specific CLI-based provider is installed
|
|
223
|
-
* Note: Cursor is NOT a CLI, use detectCursorProject() instead
|
|
224
|
-
*/
|
|
225
|
-
export async function detectProvider(provider: AIProviderName): Promise<ProviderDetectionResult> {
|
|
226
|
-
const config = Providers[provider]
|
|
227
|
-
|
|
228
|
-
// Cursor is not a CLI - return not installed for CLI detection
|
|
229
|
-
if (!config.cliCommand) {
|
|
230
|
-
return { installed: false }
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
const cliPath = await whichCommand(config.cliCommand)
|
|
234
|
-
|
|
235
|
-
if (!cliPath) {
|
|
236
|
-
return { installed: false }
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
const version = await getCliVersion(config.cliCommand)
|
|
240
|
-
const versionWarning = validateCliVersion(provider, version || undefined)
|
|
241
|
-
|
|
242
|
-
return {
|
|
243
|
-
installed: true,
|
|
244
|
-
version: version || undefined,
|
|
245
|
-
path: cliPath,
|
|
246
|
-
versionWarning: versionWarning || undefined,
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
/**
|
|
251
|
-
* Validate that a detected CLI version meets the provider's minimum requirement.
|
|
252
|
-
* Returns a warning message if the version is below minimum, or null if OK.
|
|
253
|
-
*/
|
|
254
|
-
export function validateCliVersion(
|
|
255
|
-
provider: AIProviderName,
|
|
256
|
-
version: string | undefined
|
|
257
|
-
): string | null {
|
|
258
|
-
const config = Providers[provider]
|
|
259
|
-
if (!config.minCliVersion || !version) return null
|
|
260
|
-
|
|
261
|
-
if (compareSemver(version, config.minCliVersion) < 0) {
|
|
262
|
-
return `⚠️ ${config.displayName} v${version} is below minimum v${config.minCliVersion}. Some features may not work correctly.`
|
|
263
|
-
}
|
|
264
|
-
return null
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
/**
|
|
268
|
-
* Detect all available CLI-based providers
|
|
269
|
-
* Results are cached to disk with a 10-minute TTL to avoid redundant shell spawns.
|
|
270
|
-
* Pass refresh=true to force re-detection.
|
|
271
|
-
*/
|
|
272
|
-
export async function detectAllProviders(refresh = false): Promise<{
|
|
273
|
-
claude: ProviderDetectionResult
|
|
274
|
-
gemini: ProviderDetectionResult
|
|
275
|
-
}> {
|
|
276
|
-
if (!refresh) {
|
|
277
|
-
const cached = await readProviderCache()
|
|
278
|
-
if (cached) return cached
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
const [claude, gemini] = await Promise.all([detectProvider('claude'), detectProvider('gemini')])
|
|
282
|
-
const detection = { claude, gemini }
|
|
283
|
-
|
|
284
|
-
await writeProviderCache(detection).catch(() => {})
|
|
285
|
-
|
|
286
|
-
return detection
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
/**
|
|
290
|
-
* Get the active provider based on detection or configuration
|
|
291
|
-
*
|
|
292
|
-
* Priority:
|
|
293
|
-
* 1. Check project config for saved provider preference
|
|
294
|
-
* 2. Auto-detect single installed provider
|
|
295
|
-
* 3. Default to Claude if both installed (backward compatibility)
|
|
296
|
-
*/
|
|
297
|
-
export async function getActiveProvider(
|
|
298
|
-
projectProvider?: AIProviderName
|
|
299
|
-
): Promise<AIProviderConfig> {
|
|
300
|
-
// If project has a saved preference, use it
|
|
301
|
-
if (projectProvider && Providers[projectProvider]) {
|
|
302
|
-
return Providers[projectProvider]
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
// Auto-detect
|
|
306
|
-
const detection = await detectAllProviders()
|
|
307
|
-
|
|
308
|
-
// If only one is installed, use it
|
|
309
|
-
if (detection.claude.installed && !detection.gemini.installed) {
|
|
310
|
-
return ClaudeProvider
|
|
311
|
-
}
|
|
312
|
-
if (detection.gemini.installed && !detection.claude.installed) {
|
|
313
|
-
return GeminiProvider
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
// Default to Claude for backward compatibility
|
|
317
|
-
return ClaudeProvider
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
/**
|
|
321
|
-
* Check if config directory exists for a provider
|
|
322
|
-
* Returns false for project-level providers (Cursor)
|
|
323
|
-
*/
|
|
324
|
-
export async function hasProviderConfig(provider: AIProviderName): Promise<boolean> {
|
|
325
|
-
const config = Providers[provider]
|
|
326
|
-
if (!config.configDir) {
|
|
327
|
-
return false // Cursor has no global config directory
|
|
328
|
-
}
|
|
329
|
-
return fileExists(config.configDir)
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
// =============================================================================
|
|
333
|
-
// Provider Branding
|
|
334
|
-
// =============================================================================
|
|
335
|
-
|
|
336
|
-
/**
|
|
337
|
-
* Get provider-specific branding
|
|
338
|
-
*/
|
|
339
|
-
export function getProviderBranding(provider: AIProviderName): ProviderBranding {
|
|
340
|
-
// Generic commit footer for all providers
|
|
341
|
-
const commitFooter = `Generated with [p/](https://www.prjct.app/)`
|
|
342
|
-
|
|
343
|
-
const signatures: Record<AIProviderName, string> = {
|
|
344
|
-
claude: '⚡ prjct + Claude',
|
|
345
|
-
gemini: '⚡ prjct + Gemini',
|
|
346
|
-
cursor: '⚡ prjct + Cursor',
|
|
347
|
-
antigravity: '⚡ prjct + Antigravity',
|
|
348
|
-
windsurf: '⚡ prjct + Windsurf',
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
return {
|
|
352
|
-
commitFooter,
|
|
353
|
-
signature: signatures[provider] || '⚡ prjct',
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
// =============================================================================
|
|
358
|
-
// Cursor Project Detection
|
|
359
|
-
// =============================================================================
|
|
360
|
-
|
|
361
|
-
/**
|
|
362
|
-
* Detect if a project is configured for Cursor IDE
|
|
363
|
-
*
|
|
364
|
-
* Cursor has NO global config (~/.cursor/ doesn't exist).
|
|
365
|
-
* Detection is based on project-level .cursor/ directory.
|
|
366
|
-
*/
|
|
367
|
-
export async function detectCursorProject(projectRoot: string): Promise<CursorProjectDetection> {
|
|
368
|
-
const cursorDir = path.join(projectRoot, '.cursor')
|
|
369
|
-
const rulesDir = path.join(cursorDir, 'rules')
|
|
370
|
-
const routerPath = path.join(rulesDir, 'prjct.mdc')
|
|
371
|
-
|
|
372
|
-
const [detected, routerInstalled] = await Promise.all([
|
|
373
|
-
fileExists(cursorDir),
|
|
374
|
-
fileExists(routerPath),
|
|
375
|
-
])
|
|
376
|
-
|
|
377
|
-
return {
|
|
378
|
-
detected,
|
|
379
|
-
routerInstalled,
|
|
380
|
-
projectRoot: detected ? projectRoot : undefined,
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
/**
|
|
385
|
-
* Check if Cursor routers need to be regenerated
|
|
386
|
-
*/
|
|
387
|
-
export async function needsCursorRouterRegeneration(projectRoot: string): Promise<boolean> {
|
|
388
|
-
const detection = await detectCursorProject(projectRoot)
|
|
389
|
-
|
|
390
|
-
// Only check if .cursor/ exists (project uses Cursor)
|
|
391
|
-
// and prjct router is missing
|
|
392
|
-
return detection.detected && !detection.routerInstalled
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
// =============================================================================
|
|
396
|
-
// Windsurf Project Detection
|
|
397
|
-
// =============================================================================
|
|
398
|
-
|
|
399
|
-
/**
|
|
400
|
-
* Detect if a project is configured for Windsurf IDE
|
|
401
|
-
*
|
|
402
|
-
* Windsurf has NO global config (~/.windsurf/ doesn't exist).
|
|
403
|
-
* Detection is based on project-level .windsurf/ directory.
|
|
404
|
-
*/
|
|
405
|
-
export async function detectWindsurfProject(
|
|
406
|
-
projectRoot: string
|
|
407
|
-
): Promise<WindsurfProjectDetection> {
|
|
408
|
-
const windsurfDir = path.join(projectRoot, '.windsurf')
|
|
409
|
-
const rulesDir = path.join(windsurfDir, 'rules')
|
|
410
|
-
const routerPath = path.join(rulesDir, 'prjct.md')
|
|
411
|
-
|
|
412
|
-
const [detected, routerInstalled] = await Promise.all([
|
|
413
|
-
fileExists(windsurfDir),
|
|
414
|
-
fileExists(routerPath),
|
|
415
|
-
])
|
|
416
|
-
|
|
417
|
-
return {
|
|
418
|
-
detected,
|
|
419
|
-
routerInstalled,
|
|
420
|
-
projectRoot: detected ? projectRoot : undefined,
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
/**
|
|
425
|
-
* Check if Windsurf routers need to be regenerated
|
|
426
|
-
*/
|
|
427
|
-
export async function needsWindsurfRouterRegeneration(projectRoot: string): Promise<boolean> {
|
|
428
|
-
const detection = await detectWindsurfProject(projectRoot)
|
|
429
|
-
|
|
430
|
-
// Only check if .windsurf/ exists (project uses Windsurf)
|
|
431
|
-
// and prjct router is missing
|
|
432
|
-
return detection.detected && !detection.routerInstalled
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
// =============================================================================
|
|
436
|
-
// Antigravity Detection
|
|
437
|
-
// =============================================================================
|
|
438
|
-
|
|
439
|
-
/**
|
|
440
|
-
* Result of Antigravity detection
|
|
441
|
-
*/
|
|
442
|
-
export interface AntigravityDetection {
|
|
443
|
-
/** Whether ~/.gemini/antigravity/ exists */
|
|
444
|
-
installed: boolean
|
|
445
|
-
|
|
446
|
-
/** Whether prjct skill is installed */
|
|
447
|
-
skillInstalled: boolean
|
|
448
|
-
|
|
449
|
-
/** Path to config directory */
|
|
450
|
-
configPath?: string
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
/**
|
|
454
|
-
* Detect if Google Antigravity is installed
|
|
455
|
-
*
|
|
456
|
-
* Antigravity is NOT a CLI command - it's a GUI platform.
|
|
457
|
-
* Detection is based on ~/.gemini/antigravity/ directory.
|
|
458
|
-
*/
|
|
459
|
-
export async function detectAntigravity(): Promise<AntigravityDetection> {
|
|
460
|
-
const configPath = AntigravityProvider.configDir
|
|
461
|
-
if (!configPath) {
|
|
462
|
-
return { installed: false, skillInstalled: false }
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
const skillPath = path.join(configPath, 'skills', 'prjct', 'SKILL.md')
|
|
466
|
-
const [installed, skillInstalled] = await Promise.all([
|
|
467
|
-
fileExists(configPath),
|
|
468
|
-
fileExists(skillPath),
|
|
469
|
-
])
|
|
470
|
-
|
|
471
|
-
return {
|
|
472
|
-
installed,
|
|
473
|
-
skillInstalled,
|
|
474
|
-
configPath: installed ? configPath : undefined,
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
// =============================================================================
|
|
479
|
-
// Provider Paths
|
|
480
|
-
// =============================================================================
|
|
481
|
-
|
|
482
|
-
/**
|
|
483
|
-
* Get full path to global context file
|
|
484
|
-
* Returns null for project-level providers (Cursor)
|
|
485
|
-
*/
|
|
486
|
-
export function getGlobalContextPath(provider: AIProviderName): string | null {
|
|
487
|
-
const config = Providers[provider]
|
|
488
|
-
if (!config.configDir) {
|
|
489
|
-
return null // Cursor has no global config
|
|
490
|
-
}
|
|
491
|
-
return path.join(config.configDir, config.contextFile)
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
/**
|
|
495
|
-
* Get full path to global settings file
|
|
496
|
-
* Returns null for project-level providers (Cursor)
|
|
497
|
-
*/
|
|
498
|
-
export function getGlobalSettingsPath(provider: AIProviderName): string | null {
|
|
499
|
-
const config = Providers[provider]
|
|
500
|
-
if (!config.configDir || !config.settingsFile) {
|
|
501
|
-
return null // Cursor has no global settings
|
|
502
|
-
}
|
|
503
|
-
return path.join(config.configDir, config.settingsFile)
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
/**
|
|
507
|
-
* Get full path to skills directory
|
|
508
|
-
* Returns null for providers without skill support (Cursor)
|
|
509
|
-
*/
|
|
510
|
-
export function getSkillsPath(provider: AIProviderName): string | null {
|
|
511
|
-
return Providers[provider].skillsDir
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
/**
|
|
515
|
-
* Get commands directory relative to project root
|
|
516
|
-
*/
|
|
517
|
-
export function getCommandsDir(provider: AIProviderName): string {
|
|
518
|
-
return Providers[provider].commandsDir
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
/**
|
|
522
|
-
* Get full path to commands directory in a project
|
|
523
|
-
*/
|
|
524
|
-
export function getProjectCommandsPath(provider: AIProviderName, projectRoot: string): string {
|
|
525
|
-
const config = Providers[provider]
|
|
526
|
-
return path.join(projectRoot, config.commandsDir)
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
// =============================================================================
|
|
530
|
-
// Provider Selection (for setup)
|
|
531
|
-
// =============================================================================
|
|
532
|
-
|
|
533
|
-
/**
|
|
534
|
-
* Determine which provider to use during setup
|
|
535
|
-
* Returns selection result with detection details
|
|
536
|
-
*/
|
|
537
|
-
export async function selectProvider(): Promise<ProviderSelectionResult> {
|
|
538
|
-
const detection = await detectAllProviders()
|
|
539
|
-
|
|
540
|
-
const claudeInstalled = detection.claude.installed
|
|
541
|
-
const geminiInstalled = detection.gemini.installed
|
|
542
|
-
|
|
543
|
-
// Neither installed
|
|
544
|
-
if (!claudeInstalled && !geminiInstalled) {
|
|
545
|
-
// Default to Claude, setup will prompt to install
|
|
546
|
-
return {
|
|
547
|
-
provider: 'claude',
|
|
548
|
-
userSelected: false,
|
|
549
|
-
detection,
|
|
550
|
-
}
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
// Only Claude installed
|
|
554
|
-
if (claudeInstalled && !geminiInstalled) {
|
|
555
|
-
return {
|
|
556
|
-
provider: 'claude',
|
|
557
|
-
userSelected: false,
|
|
558
|
-
detection,
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
// Only Gemini installed
|
|
563
|
-
if (geminiInstalled && !claudeInstalled) {
|
|
564
|
-
return {
|
|
565
|
-
provider: 'gemini',
|
|
566
|
-
userSelected: false,
|
|
567
|
-
detection,
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
// Both installed - will need user selection
|
|
572
|
-
// For now, default to Claude (caller should prompt user)
|
|
573
|
-
return {
|
|
574
|
-
provider: 'claude',
|
|
575
|
-
userSelected: true, // Indicates user should be prompted
|
|
576
|
-
detection,
|
|
577
|
-
}
|
|
578
|
-
}
|
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Author Detector - Detects author information from multiple sources
|
|
3
|
-
*
|
|
4
|
-
* Detection priority:
|
|
5
|
-
* 1. GitHub CLI (gh api user) - Most reliable for GitHub username
|
|
6
|
-
* 2. Git config (user.name and user.email)
|
|
7
|
-
* 3. Fallback to 'Unknown'
|
|
8
|
-
*
|
|
9
|
-
* @module infrastructure/author-detector
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import { exec as execCallback } from 'node:child_process'
|
|
13
|
-
import { promisify } from 'node:util'
|
|
14
|
-
import type { AuthorConfigStatus, DetectedAuthorInfo } from '../types'
|
|
15
|
-
|
|
16
|
-
const exec = promisify(execCallback)
|
|
17
|
-
|
|
18
|
-
// ============ Internal Helpers ============
|
|
19
|
-
|
|
20
|
-
async function execCommand(command: string): Promise<{ success: boolean; output: string }> {
|
|
21
|
-
try {
|
|
22
|
-
const { stdout } = await exec(command, { timeout: 5000 })
|
|
23
|
-
return { success: true, output: stdout.trim() }
|
|
24
|
-
} catch (_error) {
|
|
25
|
-
return { success: false, output: '' }
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// ============ Detection Functions ============
|
|
30
|
-
|
|
31
|
-
export async function detectGitHubUsername(): Promise<string | null> {
|
|
32
|
-
let result = await execCommand('gh api user --jq .login')
|
|
33
|
-
if (result.success && result.output) return result.output
|
|
34
|
-
|
|
35
|
-
result = await execCommand('git config --global github.user')
|
|
36
|
-
if (result.success && result.output) return result.output
|
|
37
|
-
|
|
38
|
-
return null
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export async function detectGitName(): Promise<string | null> {
|
|
42
|
-
const result = await execCommand('git config user.name')
|
|
43
|
-
return result.success && result.output ? result.output : null
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export async function detectGitEmail(): Promise<string | null> {
|
|
47
|
-
const result = await execCommand('git config user.email')
|
|
48
|
-
return result.success && result.output ? result.output : null
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export async function detect(): Promise<DetectedAuthorInfo> {
|
|
52
|
-
const [github, name, email] = await Promise.all([
|
|
53
|
-
detectGitHubUsername(),
|
|
54
|
-
detectGitName(),
|
|
55
|
-
detectGitEmail(),
|
|
56
|
-
])
|
|
57
|
-
|
|
58
|
-
return {
|
|
59
|
-
github,
|
|
60
|
-
email,
|
|
61
|
-
name: name || github || 'Unknown',
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export async function detectAuthorForLogs(): Promise<string> {
|
|
66
|
-
const author = await detect()
|
|
67
|
-
return author.github || (author.name !== 'Unknown' ? author.name! : 'unknown')
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// ============ Status Functions ============
|
|
71
|
-
|
|
72
|
-
export async function isGitHubCLIAvailable(): Promise<boolean> {
|
|
73
|
-
const result = await execCommand('gh --version')
|
|
74
|
-
return result.success
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
export async function isGitConfigured(): Promise<boolean> {
|
|
78
|
-
const [name, email] = await Promise.all([detectGitName(), detectGitEmail()])
|
|
79
|
-
return !!(name && email)
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
export async function getConfigStatus(): Promise<AuthorConfigStatus> {
|
|
83
|
-
const [hasGitHub, hasGit, author] = await Promise.all([
|
|
84
|
-
isGitHubCLIAvailable(),
|
|
85
|
-
isGitConfigured(),
|
|
86
|
-
detect(),
|
|
87
|
-
])
|
|
88
|
-
|
|
89
|
-
return {
|
|
90
|
-
hasGitHub,
|
|
91
|
-
hasGit,
|
|
92
|
-
author,
|
|
93
|
-
isComplete: !!(author.github || (author.name !== 'Unknown' && author.email)),
|
|
94
|
-
recommendations: getRecommendations(hasGitHub, hasGit, author),
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
function getRecommendations(
|
|
99
|
-
hasGitHub: boolean,
|
|
100
|
-
hasGit: boolean,
|
|
101
|
-
author: DetectedAuthorInfo
|
|
102
|
-
): string[] {
|
|
103
|
-
const recommendations: string[] = []
|
|
104
|
-
|
|
105
|
-
if (!hasGitHub && !author.github) {
|
|
106
|
-
recommendations.push(
|
|
107
|
-
'Install GitHub CLI (gh) for better collaboration support: https://cli.github.com/'
|
|
108
|
-
)
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
if (!hasGit) {
|
|
112
|
-
recommendations.push('Configure git user: git config --global user.name "Your Name"')
|
|
113
|
-
recommendations.push('Configure git email: git config --global user.email "your@email.com"')
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
if (author.github && !author.email) {
|
|
117
|
-
recommendations.push('Consider setting your git email for better tracking')
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
return recommendations
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// ============ Formatting ============
|
|
124
|
-
|
|
125
|
-
export function formatAuthor(author: DetectedAuthorInfo): string {
|
|
126
|
-
const parts: string[] = []
|
|
127
|
-
|
|
128
|
-
if (author.name && author.name !== 'Unknown') parts.push(author.name)
|
|
129
|
-
if (author.github) parts.push(`@${author.github}`)
|
|
130
|
-
if (author.email) parts.push(`<${author.email}>`)
|
|
131
|
-
|
|
132
|
-
return parts.join(' ') || 'Unknown'
|
|
133
|
-
}
|