prjct-cli 0.45.0 → 0.45.4

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.
Files changed (207) hide show
  1. package/CHANGELOG.md +82 -0
  2. package/bin/prjct.ts +117 -10
  3. package/core/__tests__/agentic/memory-system.test.ts +39 -26
  4. package/core/__tests__/agentic/plan-mode.test.ts +64 -46
  5. package/core/__tests__/agentic/prompt-builder.test.ts +14 -14
  6. package/core/__tests__/services/project-index.test.ts +353 -0
  7. package/core/__tests__/types/fs.test.ts +3 -3
  8. package/core/__tests__/utils/date-helper.test.ts +10 -10
  9. package/core/__tests__/utils/output.test.ts +9 -6
  10. package/core/__tests__/utils/project-commands.test.ts +5 -6
  11. package/core/agentic/agent-router.ts +9 -10
  12. package/core/agentic/chain-of-thought.ts +16 -4
  13. package/core/agentic/command-executor.ts +66 -40
  14. package/core/agentic/context-builder.ts +8 -5
  15. package/core/agentic/ground-truth.ts +15 -9
  16. package/core/agentic/index.ts +145 -152
  17. package/core/agentic/loop-detector.ts +40 -11
  18. package/core/agentic/memory-system.ts +98 -35
  19. package/core/agentic/orchestrator-executor.ts +135 -71
  20. package/core/agentic/plan-mode.ts +46 -16
  21. package/core/agentic/prompt-builder.ts +108 -42
  22. package/core/agentic/services.ts +10 -9
  23. package/core/agentic/skill-loader.ts +9 -15
  24. package/core/agentic/smart-context.ts +129 -79
  25. package/core/agentic/template-executor.ts +13 -12
  26. package/core/agentic/template-loader.ts +7 -4
  27. package/core/agentic/tool-registry.ts +16 -13
  28. package/core/agents/index.ts +1 -1
  29. package/core/agents/performance.ts +10 -27
  30. package/core/ai-tools/formatters.ts +8 -6
  31. package/core/ai-tools/generator.ts +4 -4
  32. package/core/ai-tools/index.ts +1 -1
  33. package/core/ai-tools/registry.ts +21 -11
  34. package/core/bus/bus.ts +23 -16
  35. package/core/bus/index.ts +2 -2
  36. package/core/cli/linear.ts +3 -5
  37. package/core/cli/start.ts +28 -25
  38. package/core/commands/analysis.ts +58 -39
  39. package/core/commands/analytics.ts +52 -44
  40. package/core/commands/base.ts +15 -13
  41. package/core/commands/cleanup.ts +6 -13
  42. package/core/commands/command-data.ts +28 -4
  43. package/core/commands/commands.ts +57 -24
  44. package/core/commands/context.ts +4 -4
  45. package/core/commands/design.ts +3 -10
  46. package/core/commands/index.ts +5 -8
  47. package/core/commands/maintenance.ts +7 -4
  48. package/core/commands/planning.ts +179 -56
  49. package/core/commands/register.ts +13 -9
  50. package/core/commands/registry.ts +15 -14
  51. package/core/commands/setup.ts +26 -14
  52. package/core/commands/shipping.ts +11 -16
  53. package/core/commands/snapshots.ts +16 -32
  54. package/core/commands/uninstall.ts +541 -0
  55. package/core/commands/workflow.ts +24 -28
  56. package/core/constants/index.ts +10 -22
  57. package/core/context/generator.ts +82 -33
  58. package/core/context-tools/files-tool.ts +18 -19
  59. package/core/context-tools/imports-tool.ts +13 -33
  60. package/core/context-tools/index.ts +29 -54
  61. package/core/context-tools/recent-tool.ts +16 -22
  62. package/core/context-tools/signatures-tool.ts +17 -26
  63. package/core/context-tools/summary-tool.ts +20 -22
  64. package/core/context-tools/token-counter.ts +25 -20
  65. package/core/context-tools/types.ts +5 -5
  66. package/core/domain/agent-generator.ts +7 -5
  67. package/core/domain/agent-loader.ts +2 -2
  68. package/core/domain/analyzer.ts +19 -16
  69. package/core/domain/architecture-generator.ts +6 -3
  70. package/core/domain/context-estimator.ts +3 -4
  71. package/core/domain/snapshot-manager.ts +25 -22
  72. package/core/domain/task-stack.ts +24 -14
  73. package/core/errors.ts +1 -1
  74. package/core/events/events.ts +2 -4
  75. package/core/events/index.ts +1 -2
  76. package/core/index.ts +28 -16
  77. package/core/infrastructure/agent-detector.ts +3 -3
  78. package/core/infrastructure/ai-provider.ts +23 -20
  79. package/core/infrastructure/author-detector.ts +16 -10
  80. package/core/infrastructure/capability-installer.ts +2 -2
  81. package/core/infrastructure/claude-agent.ts +6 -6
  82. package/core/infrastructure/command-installer.ts +22 -17
  83. package/core/infrastructure/config-manager.ts +18 -14
  84. package/core/infrastructure/editors-config.ts +8 -4
  85. package/core/infrastructure/path-manager.ts +8 -6
  86. package/core/infrastructure/permission-manager.ts +20 -17
  87. package/core/infrastructure/setup.ts +42 -38
  88. package/core/infrastructure/update-checker.ts +5 -5
  89. package/core/integrations/issue-tracker/enricher.ts +8 -19
  90. package/core/integrations/issue-tracker/index.ts +2 -2
  91. package/core/integrations/issue-tracker/manager.ts +15 -15
  92. package/core/integrations/issue-tracker/types.ts +5 -22
  93. package/core/integrations/jira/client.ts +67 -59
  94. package/core/integrations/jira/index.ts +11 -14
  95. package/core/integrations/jira/mcp-adapter.ts +5 -10
  96. package/core/integrations/jira/service.ts +10 -10
  97. package/core/integrations/linear/client.ts +27 -18
  98. package/core/integrations/linear/index.ts +9 -12
  99. package/core/integrations/linear/service.ts +11 -11
  100. package/core/integrations/linear/sync.ts +8 -8
  101. package/core/outcomes/analyzer.ts +5 -18
  102. package/core/outcomes/index.ts +2 -2
  103. package/core/outcomes/recorder.ts +3 -3
  104. package/core/plugin/builtin/webhook.ts +19 -15
  105. package/core/plugin/hooks.ts +29 -21
  106. package/core/plugin/index.ts +7 -7
  107. package/core/plugin/loader.ts +19 -19
  108. package/core/plugin/registry.ts +12 -23
  109. package/core/schemas/agents.ts +1 -1
  110. package/core/schemas/analysis.ts +1 -1
  111. package/core/schemas/enriched-task.ts +62 -49
  112. package/core/schemas/ideas.ts +13 -13
  113. package/core/schemas/index.ts +17 -27
  114. package/core/schemas/issues.ts +40 -25
  115. package/core/schemas/metrics.ts +25 -25
  116. package/core/schemas/outcomes.ts +70 -62
  117. package/core/schemas/permissions.ts +15 -12
  118. package/core/schemas/prd.ts +27 -14
  119. package/core/schemas/project.ts +3 -3
  120. package/core/schemas/roadmap.ts +47 -34
  121. package/core/schemas/schemas.ts +3 -4
  122. package/core/schemas/shipped.ts +3 -3
  123. package/core/schemas/state.ts +43 -29
  124. package/core/server/index.ts +5 -6
  125. package/core/server/routes-extended.ts +68 -72
  126. package/core/server/routes.ts +3 -3
  127. package/core/server/server.ts +31 -26
  128. package/core/services/agent-generator.ts +237 -0
  129. package/core/services/agent-service.ts +2 -2
  130. package/core/services/breakdown-service.ts +2 -4
  131. package/core/services/context-generator.ts +299 -0
  132. package/core/services/context-selector.ts +420 -0
  133. package/core/services/doctor-service.ts +426 -0
  134. package/core/services/file-categorizer.ts +448 -0
  135. package/core/services/file-scorer.ts +270 -0
  136. package/core/services/git-analyzer.ts +267 -0
  137. package/core/services/index.ts +27 -10
  138. package/core/services/memory-service.ts +3 -4
  139. package/core/services/project-index.ts +911 -0
  140. package/core/services/project-service.ts +4 -4
  141. package/core/services/skill-installer.ts +14 -17
  142. package/core/services/skill-lock.ts +3 -3
  143. package/core/services/skill-service.ts +12 -6
  144. package/core/services/stack-detector.ts +245 -0
  145. package/core/services/sync-service.ts +87 -345
  146. package/core/services/watch-service.ts +294 -0
  147. package/core/session/compaction.ts +23 -31
  148. package/core/session/index.ts +11 -5
  149. package/core/session/log-migration.ts +3 -3
  150. package/core/session/metrics.ts +19 -14
  151. package/core/session/session-log-manager.ts +12 -17
  152. package/core/session/task-session-manager.ts +25 -25
  153. package/core/session/utils.ts +1 -1
  154. package/core/storage/ideas-storage.ts +41 -57
  155. package/core/storage/index-storage.ts +514 -0
  156. package/core/storage/index.ts +41 -17
  157. package/core/storage/metrics-storage.ts +39 -34
  158. package/core/storage/queue-storage.ts +35 -45
  159. package/core/storage/shipped-storage.ts +17 -20
  160. package/core/storage/state-storage.ts +50 -30
  161. package/core/storage/storage-manager.ts +6 -6
  162. package/core/storage/storage.ts +18 -15
  163. package/core/sync/auth-config.ts +3 -3
  164. package/core/sync/index.ts +13 -19
  165. package/core/sync/oauth-handler.ts +3 -3
  166. package/core/sync/sync-client.ts +4 -9
  167. package/core/sync/sync-manager.ts +12 -14
  168. package/core/types/commands.ts +42 -7
  169. package/core/types/index.ts +284 -305
  170. package/core/types/integrations.ts +3 -3
  171. package/core/types/storage.ts +14 -14
  172. package/core/types/utils.ts +3 -3
  173. package/core/utils/agent-stream.ts +3 -1
  174. package/core/utils/animations.ts +14 -11
  175. package/core/utils/branding.ts +7 -7
  176. package/core/utils/cache.ts +1 -3
  177. package/core/utils/collection-filters.ts +3 -15
  178. package/core/utils/date-helper.ts +2 -7
  179. package/core/utils/file-helper.ts +13 -8
  180. package/core/utils/jsonl-helper.ts +13 -10
  181. package/core/utils/keychain.ts +4 -8
  182. package/core/utils/logger.ts +1 -1
  183. package/core/utils/next-steps.ts +3 -3
  184. package/core/utils/output.ts +58 -11
  185. package/core/utils/project-commands.ts +6 -6
  186. package/core/utils/project-credentials.ts +5 -12
  187. package/core/utils/runtime.ts +2 -2
  188. package/core/utils/session-helper.ts +3 -4
  189. package/core/utils/version.ts +3 -3
  190. package/core/wizard/index.ts +13 -0
  191. package/core/wizard/onboarding.ts +633 -0
  192. package/core/workflow/state-machine.ts +7 -7
  193. package/dist/bin/prjct.mjs +18755 -15574
  194. package/dist/core/infrastructure/command-installer.js +86 -79
  195. package/dist/core/infrastructure/editors-config.js +6 -6
  196. package/dist/core/infrastructure/setup.js +246 -225
  197. package/dist/core/utils/version.js +9 -9
  198. package/package.json +11 -12
  199. package/scripts/build.js +3 -3
  200. package/scripts/postinstall.js +2 -2
  201. package/templates/mcp-config.json +6 -1
  202. package/templates/permissions/permissive.jsonc +1 -1
  203. package/templates/permissions/strict.jsonc +5 -9
  204. package/templates/global/docs/agents.md +0 -88
  205. package/templates/global/docs/architecture.md +0 -103
  206. package/templates/global/docs/commands.md +0 -96
  207. package/templates/global/docs/validation.md +0 -95
@@ -9,16 +9,16 @@
9
9
  * Phase 3: + Continue.dev + Auto-detection
10
10
  */
11
11
 
12
- import { execSync } from 'child_process'
13
- import fs from 'fs'
14
- import path from 'path'
15
- import os from 'os'
12
+ import { execSync } from 'node:child_process'
13
+ import fs from 'node:fs'
14
+ import os from 'node:os'
15
+ import path from 'node:path'
16
16
 
17
17
  export interface AIToolConfig {
18
18
  id: string
19
19
  name: string
20
20
  outputFile: string
21
- outputPath: 'repo' | 'global' // 'repo' = project root, 'global' = ~/.prjct-cli/projects/{id}/context/
21
+ outputPath: 'repo' | 'global' // 'repo' = project root, 'global' = ~/.prjct-cli/projects/{id}/context/
22
22
  maxTokens: number
23
23
  format: 'detailed' | 'concise' | 'minimal' | 'json'
24
24
  description: string
@@ -76,9 +76,16 @@ export const AI_TOOLS: Record<string, AIToolConfig> = {
76
76
  }
77
77
 
78
78
  /**
79
- * Default tools to generate (Phase 2: all major tools)
79
+ * Default tools to generate
80
+ * CLI tools only - IDE tools (cursor, windsurf, copilot) are OPT-IN
81
+ * Use --editors flag or "all" to include IDE tools
80
82
  */
81
- export const DEFAULT_AI_TOOLS = ['claude', 'cursor', 'copilot', 'windsurf']
83
+ export const DEFAULT_AI_TOOLS = ['claude']
84
+
85
+ /**
86
+ * IDE tools - require explicit opt-in (--editors flag)
87
+ */
88
+ export const IDE_AI_TOOLS = ['cursor', 'windsurf', 'copilot', 'continue']
82
89
 
83
90
  /**
84
91
  * All supported tool IDs
@@ -101,8 +108,8 @@ export function parseAgentsFlag(value: string): string[] {
101
108
  return SUPPORTED_AI_TOOLS
102
109
  }
103
110
 
104
- const requested = value.split(',').map(s => s.trim().toLowerCase())
105
- return requested.filter(id => AI_TOOLS[id])
111
+ const requested = value.split(',').map((s) => s.trim().toLowerCase())
112
+ return requested.filter((id) => AI_TOOLS[id])
106
113
  }
107
114
 
108
115
  /**
@@ -163,7 +170,10 @@ export function detectInstalledTools(repoPath: string = process.cwd()): string[]
163
170
  }
164
171
 
165
172
  // Continue.dev: check for .continue/ directory
166
- if (fs.existsSync(path.join(repoPath, '.continue')) || fs.existsSync(path.join(os.homedir(), '.continue'))) {
173
+ if (
174
+ fs.existsSync(path.join(repoPath, '.continue')) ||
175
+ fs.existsSync(path.join(os.homedir(), '.continue'))
176
+ ) {
167
177
  detected.push('continue')
168
178
  }
169
179
 
@@ -191,5 +201,5 @@ export function resolveToolIds(
191
201
  }
192
202
 
193
203
  // Specific list provided
194
- return mode.filter(id => AI_TOOLS[id])
204
+ return mode.filter((id) => AI_TOOLS[id])
195
205
  }
package/core/bus/bus.ts CHANGED
@@ -7,10 +7,10 @@
7
7
  * @version 1.0.0
8
8
  */
9
9
 
10
- import fs from 'fs/promises'
11
- import path from 'path'
10
+ import fs from 'node:fs/promises'
11
+ import path from 'node:path'
12
12
  import pathManager from '../infrastructure/path-manager'
13
- import { EventTypes, type EventData, type EventCallback } from '../types'
13
+ import { type EventCallback, type EventData, EventTypes } from '../types'
14
14
 
15
15
  class EventBus {
16
16
  private listeners: Map<string, Set<EventCallback>>
@@ -83,7 +83,7 @@ class EventBus {
83
83
  type: event,
84
84
  timestamp,
85
85
  projectId: this.projectId,
86
- ...data
86
+ ...data,
87
87
  }
88
88
 
89
89
  // Store in history
@@ -102,7 +102,7 @@ class EventBus {
102
102
 
103
103
  // Execute all callbacks
104
104
  const results = await Promise.allSettled(
105
- callbacks.map(cb => this.executeCallback(cb, eventData))
105
+ callbacks.map((cb) => this.executeCallback(cb, eventData))
106
106
  )
107
107
 
108
108
  // Log any errors
@@ -186,7 +186,7 @@ class EventBus {
186
186
  await fs.mkdir(path.dirname(eventsPath), { recursive: true })
187
187
 
188
188
  // Append event
189
- const line = JSON.stringify(eventData) + '\n'
189
+ const line = `${JSON.stringify(eventData)}\n`
190
190
  await fs.appendFile(eventsPath, line)
191
191
  } catch (_error) {
192
192
  // Silently fail - logging should not break functionality
@@ -199,7 +199,7 @@ class EventBus {
199
199
  getHistory(limit: number = 10, type: string | null = null): EventData[] {
200
200
  let events = this.history
201
201
  if (type) {
202
- events = events.filter(e => e.type === type || e.type.startsWith(type))
202
+ events = events.filter((e) => e.type === type || e.type.startsWith(type))
203
203
  }
204
204
  return events.slice(-limit)
205
205
  }
@@ -233,30 +233,37 @@ const eventBus = new EventBus()
233
233
 
234
234
  // Convenience methods for common events
235
235
  const emit = {
236
- sessionStarted: (data: Record<string, unknown>) => eventBus.emit(EventTypes.SESSION_STARTED, data),
236
+ sessionStarted: (data: Record<string, unknown>) =>
237
+ eventBus.emit(EventTypes.SESSION_STARTED, data),
237
238
  sessionPaused: (data: Record<string, unknown>) => eventBus.emit(EventTypes.SESSION_PAUSED, data),
238
- sessionResumed: (data: Record<string, unknown>) => eventBus.emit(EventTypes.SESSION_RESUMED, data),
239
- sessionCompleted: (data: Record<string, unknown>) => eventBus.emit(EventTypes.SESSION_COMPLETED, data),
239
+ sessionResumed: (data: Record<string, unknown>) =>
240
+ eventBus.emit(EventTypes.SESSION_RESUMED, data),
241
+ sessionCompleted: (data: Record<string, unknown>) =>
242
+ eventBus.emit(EventTypes.SESSION_COMPLETED, data),
240
243
 
241
244
  taskCreated: (data: Record<string, unknown>) => eventBus.emit(EventTypes.TASK_CREATED, data),
242
245
  taskCompleted: (data: Record<string, unknown>) => eventBus.emit(EventTypes.TASK_COMPLETED, data),
243
246
 
244
247
  featureAdded: (data: Record<string, unknown>) => eventBus.emit(EventTypes.FEATURE_ADDED, data),
245
- featureShipped: (data: Record<string, unknown>) => eventBus.emit(EventTypes.FEATURE_SHIPPED, data),
248
+ featureShipped: (data: Record<string, unknown>) =>
249
+ eventBus.emit(EventTypes.FEATURE_SHIPPED, data),
246
250
 
247
251
  ideaCaptured: (data: Record<string, unknown>) => eventBus.emit(EventTypes.IDEA_CAPTURED, data),
248
252
 
249
- snapshotCreated: (data: Record<string, unknown>) => eventBus.emit(EventTypes.SNAPSHOT_CREATED, data),
250
- snapshotRestored: (data: Record<string, unknown>) => eventBus.emit(EventTypes.SNAPSHOT_RESTORED, data),
253
+ snapshotCreated: (data: Record<string, unknown>) =>
254
+ eventBus.emit(EventTypes.SNAPSHOT_CREATED, data),
255
+ snapshotRestored: (data: Record<string, unknown>) =>
256
+ eventBus.emit(EventTypes.SNAPSHOT_RESTORED, data),
251
257
 
252
258
  commitCreated: (data: Record<string, unknown>) => eventBus.emit(EventTypes.COMMIT_CREATED, data),
253
259
  pushCompleted: (data: Record<string, unknown>) => eventBus.emit(EventTypes.PUSH_COMPLETED, data),
254
260
 
255
- projectInitialized: (data: Record<string, unknown>) => eventBus.emit(EventTypes.PROJECT_INITIALIZED, data),
261
+ projectInitialized: (data: Record<string, unknown>) =>
262
+ eventBus.emit(EventTypes.PROJECT_INITIALIZED, data),
256
263
  projectSynced: (data: Record<string, unknown>) => eventBus.emit(EventTypes.PROJECT_SYNCED, data),
257
- analysisCompleted: (data: Record<string, unknown>) => eventBus.emit(EventTypes.ANALYSIS_COMPLETED, data)
264
+ analysisCompleted: (data: Record<string, unknown>) =>
265
+ eventBus.emit(EventTypes.ANALYSIS_COMPLETED, data),
258
266
  }
259
267
 
260
268
  export { EventBus, eventBus, emit }
261
269
  export default { EventBus, EventTypes, eventBus, emit }
262
-
package/core/bus/index.ts CHANGED
@@ -4,5 +4,5 @@
4
4
  * Barrel export for bus module
5
5
  */
6
6
 
7
- export { EventBus, eventBus, emit, default } from './bus'
8
- export { EventTypes, type EventData, type EventCallback, type BusEventType } from '../types'
7
+ export { type BusEventType, type EventCallback, type EventData, EventTypes } from '../types'
8
+ export { default, EventBus, emit, eventBus } from './bus'
@@ -26,10 +26,10 @@
26
26
 
27
27
  import { linearService, linearSync } from '../integrations/linear'
28
28
  import {
29
+ getCredentialSource,
29
30
  getLinearApiKey,
30
- setLinearCredentials,
31
31
  getProjectCredentials,
32
- getCredentialSource,
32
+ setLinearCredentials,
33
33
  } from '../utils/project-credentials'
34
34
 
35
35
  // Parse arguments
@@ -129,9 +129,7 @@ async function main(): Promise<void> {
129
129
  output({
130
130
  success: true,
131
131
  teams,
132
- defaultTeam: selectedTeamId
133
- ? { id: selectedTeamId, key: selectedTeamKey }
134
- : null,
132
+ defaultTeam: selectedTeamId ? { id: selectedTeamId, key: selectedTeamKey } : null,
135
133
  })
136
134
  break
137
135
  }
package/core/cli/start.ts CHANGED
@@ -8,13 +8,13 @@
8
8
  * 4. Installs routers and global config
9
9
  */
10
10
 
11
- import fs from 'fs'
12
- import path from 'path'
13
- import os from 'os'
14
- import readline from 'readline'
15
- import { VERSION } from '../utils/version'
11
+ import fs from 'node:fs'
12
+ import os from 'node:os'
13
+ import path from 'node:path'
14
+ import readline from 'node:readline'
16
15
  import { detectAllProviders, Providers } from '../infrastructure/ai-provider'
17
16
  import type { AIProviderName } from '../types/provider'
17
+ import { VERSION } from '../utils/version'
18
18
 
19
19
  // Colors
20
20
  const RESET = '\x1b[0m'
@@ -22,18 +22,18 @@ const BOLD = '\x1b[1m'
22
22
  const DIM = '\x1b[2m'
23
23
  const GREEN = '\x1b[32m'
24
24
  const YELLOW = '\x1b[33m'
25
- const BLUE = '\x1b[34m'
26
- const MAGENTA = '\x1b[35m'
25
+ const _BLUE = '\x1b[34m'
26
+ const _MAGENTA = '\x1b[35m'
27
27
  const CYAN = '\x1b[36m'
28
28
  const WHITE = '\x1b[37m'
29
- const BG_BLUE = '\x1b[44m'
29
+ const _BG_BLUE = '\x1b[44m'
30
30
 
31
31
  // True color gradient (cyan -> blue -> purple -> pink)
32
- const G1 = '\x1b[38;2;0;255;255m' // Cyan
33
- const G2 = '\x1b[38;2;80;180;255m' // Sky blue
34
- const G3 = '\x1b[38;2;140;120;255m' // Blue-purple
35
- const G4 = '\x1b[38;2;200;80;220m' // Purple
36
- const G5 = '\x1b[38;2;255;80;180m' // Pink
32
+ const G1 = '\x1b[38;2;0;255;255m' // Cyan
33
+ const G2 = '\x1b[38;2;80;180;255m' // Sky blue
34
+ const G3 = '\x1b[38;2;140;120;255m' // Blue-purple
35
+ const G4 = '\x1b[38;2;200;80;220m' // Purple
36
+ const G5 = '\x1b[38;2;255;80;180m' // Pink
37
37
 
38
38
  // Large block letters - PRJCT (7 lines tall)
39
39
  const BANNER = `
@@ -64,7 +64,7 @@ interface ProviderOption {
64
64
  /**
65
65
  * Create readline interface for user input
66
66
  */
67
- function createReadline(): readline.Interface {
67
+ function _createReadline(): readline.Interface {
68
68
  return readline.createInterface({
69
69
  input: process.stdin,
70
70
  output: process.stdout,
@@ -94,9 +94,8 @@ function showProviderSelection(options: ProviderOption[], currentIndex: number):
94
94
  const status = option.installed
95
95
  ? `${GREEN}(installed)${RESET}`
96
96
  : `${YELLOW}(will install)${RESET}`
97
- const name = index === currentIndex
98
- ? `${BOLD}${option.displayName}${RESET}`
99
- : option.displayName
97
+ const name =
98
+ index === currentIndex ? `${BOLD}${option.displayName}${RESET}` : option.displayName
100
99
 
101
100
  console.log(` ${cursor} ${checkbox} ${name} ${status}`)
102
101
  })
@@ -126,20 +125,20 @@ async function selectProviders(): Promise<AIProviderName[]> {
126
125
  ]
127
126
 
128
127
  // If neither installed, select Claude by default
129
- if (!options.some(o => o.selected)) {
128
+ if (!options.some((o) => o.selected)) {
130
129
  options[0].selected = true
131
130
  }
132
131
 
133
132
  // Non-interactive mode: auto-select detected providers
134
133
  if (!process.stdin.isTTY) {
135
134
  console.log(`\n${BOLD} Detected providers:${RESET}\n`)
136
- options.forEach(option => {
135
+ options.forEach((option) => {
137
136
  if (option.installed) {
138
137
  console.log(` ${GREEN}✓${RESET} ${option.displayName}`)
139
138
  }
140
139
  })
141
140
  console.log('')
142
- return options.filter(o => o.selected).map(o => o.name)
141
+ return options.filter((o) => o.selected).map((o) => o.name)
143
142
  }
144
143
 
145
144
  return new Promise((resolve) => {
@@ -172,7 +171,7 @@ async function selectProviders(): Promise<AIProviderName[]> {
172
171
 
173
172
  if (key === '\r' || key === '\n') {
174
173
  cleanup()
175
- const selected = options.filter(o => o.selected).map(o => o.name)
174
+ const selected = options.filter((o) => o.selected).map((o) => o.name)
176
175
  resolve(selected.length > 0 ? selected : ['claude'])
177
176
  return
178
177
  }
@@ -230,7 +229,9 @@ async function installRouter(provider: AIProviderName): Promise<boolean> {
230
229
 
231
230
  return false
232
231
  } catch (error) {
233
- console.error(` ${YELLOW}⚠${RESET} Failed to install ${provider} router: ${(error as Error).message}`)
232
+ console.error(
233
+ ` ${YELLOW}⚠${RESET} Failed to install ${provider} router: ${(error as Error).message}`
234
+ )
234
235
  return false
235
236
  }
236
237
  }
@@ -280,7 +281,7 @@ async function installGlobalConfig(provider: AIProviderName): Promise<boolean> {
280
281
  fs.writeFileSync(dest, before + prjctSection + after)
281
282
  } else {
282
283
  // Append
283
- fs.writeFileSync(dest, existing + '\n\n' + content)
284
+ fs.writeFileSync(dest, `${existing}\n\n${content}`)
284
285
  }
285
286
  } else {
286
287
  // Create new
@@ -292,7 +293,9 @@ async function installGlobalConfig(provider: AIProviderName): Promise<boolean> {
292
293
 
293
294
  return false
294
295
  } catch (error) {
295
- console.error(` ${YELLOW}⚠${RESET} Failed to install ${provider} config: ${(error as Error).message}`)
296
+ console.error(
297
+ ` ${YELLOW}⚠${RESET} Failed to install ${provider} config: ${(error as Error).message}`
298
+ )
296
299
  return false
297
300
  }
298
301
  }
@@ -324,7 +327,7 @@ function showCompletion(providers: AIProviderName[]): void {
324
327
  console.log(`\n${GREEN}${BOLD} ✓ Setup complete!${RESET}\n`)
325
328
 
326
329
  console.log(` ${DIM}Configured providers:${RESET}`)
327
- providers.forEach(p => {
330
+ providers.forEach((p) => {
328
331
  const config = Providers[p]
329
332
  console.log(` ${GREEN}✓${RESET} ${config.displayName}`)
330
333
  })
@@ -2,30 +2,32 @@
2
2
  * Analysis Commands: analyze, sync, and related helpers
3
3
  */
4
4
 
5
- import path from 'path'
6
-
7
- import type { CommandResult, AnalyzeOptions, ProjectContext } from '../types'
8
- import {
9
- PrjctCommandsBase,
10
- contextBuilder,
11
- toolRegistry,
12
- pathManager,
13
- configManager,
14
- dateHelper
15
- } from './base'
16
- import analyzer from '../domain/analyzer'
5
+ import path from 'node:path'
17
6
  import { generateContext } from '../context/generator'
7
+ import analyzer from '../domain/analyzer'
18
8
  import commandInstaller from '../infrastructure/command-installer'
9
+ import { formatCost } from '../schemas/metrics'
19
10
  import { syncService } from '../services'
20
- import { showNextSteps } from '../utils/next-steps'
21
11
  import { metricsStorage } from '../storage/metrics-storage'
22
- import { formatCost } from '../schemas/metrics'
12
+ import type { AnalyzeOptions, CommandResult, ProjectContext } from '../types'
13
+ import { showNextSteps } from '../utils/next-steps'
14
+ import {
15
+ configManager,
16
+ contextBuilder,
17
+ dateHelper,
18
+ PrjctCommandsBase,
19
+ pathManager,
20
+ toolRegistry,
21
+ } from './base'
23
22
 
24
23
  export class AnalysisCommands extends PrjctCommandsBase {
25
24
  /**
26
25
  * /p:analyze - Analyze repository and generate summary
27
26
  */
28
- async analyze(options: AnalyzeOptions = {}, projectPath: string = process.cwd()): Promise<CommandResult> {
27
+ async analyze(
28
+ options: AnalyzeOptions = {},
29
+ projectPath: string = process.cwd()
30
+ ): Promise<CommandResult> {
29
31
  try {
30
32
  await this.initializeAgent()
31
33
 
@@ -33,7 +35,7 @@ export class AnalysisCommands extends PrjctCommandsBase {
33
35
 
34
36
  analyzer.init(projectPath)
35
37
 
36
- const context = await contextBuilder.build(projectPath, options) as ProjectContext
38
+ const context = (await contextBuilder.build(projectPath, options)) as ProjectContext
37
39
 
38
40
  const analysisData = {
39
41
  packageJson: await analyzer.readPackageJson(),
@@ -60,12 +62,7 @@ export class AnalysisCommands extends PrjctCommandsBase {
60
62
 
61
63
  const projectId = await configManager.getProjectId(projectPath)
62
64
  const summaryPath =
63
- context.paths.analysis ||
64
- pathManager.getFilePath(
65
- projectId!,
66
- 'analysis',
67
- 'repo-summary.md'
68
- )
65
+ context.paths.analysis || pathManager.getFilePath(projectId!, 'analysis', 'repo-summary.md')
69
66
 
70
67
  await toolRegistry.get('Write')!(summaryPath, summary)
71
68
 
@@ -165,7 +162,9 @@ export class AnalysisCommands extends PrjctCommandsBase {
165
162
  if (data.hasReadme) lines.push('- **Documentation**: README.md found')
166
163
  lines.push('')
167
164
 
168
- const gitStats = data.gitStats as { totalCommits?: number; contributors?: number; age?: string } | undefined
165
+ const gitStats = data.gitStats as
166
+ | { totalCommits?: number; contributors?: number; age?: string }
167
+ | undefined
169
168
  lines.push('## Git Statistics\n')
170
169
  lines.push(`- **Total Commits**: ${gitStats?.totalCommits || 0}`)
171
170
  lines.push(`- **Contributors**: ${gitStats?.contributors || 0}`)
@@ -208,7 +207,10 @@ export class AnalysisCommands extends PrjctCommandsBase {
208
207
  *
209
208
  * This eliminates the need for Claude to make 50+ individual tool calls.
210
209
  */
211
- async sync(projectPath: string = process.cwd(), options: { aiTools?: string[] } = {}): Promise<CommandResult> {
210
+ async sync(
211
+ projectPath: string = process.cwd(),
212
+ options: { aiTools?: string[] } = {}
213
+ ): Promise<CommandResult> {
212
214
  try {
213
215
  const initResult = await this.ensureProjectInit(projectPath)
214
216
  if (!initResult.success) return initResult
@@ -252,7 +254,7 @@ export class AnalysisCommands extends PrjctCommandsBase {
252
254
 
253
255
  // Show AI Tools generated (multi-agent output)
254
256
  if (result.aiTools && result.aiTools.length > 0) {
255
- const successTools = result.aiTools.filter(t => t.success)
257
+ const successTools = result.aiTools.filter((t) => t.success)
256
258
  console.log(`🤖 AI Tools Context (${successTools.length})`)
257
259
  for (const tool of result.aiTools) {
258
260
  const status = tool.success ? '✓' : '✗'
@@ -261,8 +263,8 @@ export class AnalysisCommands extends PrjctCommandsBase {
261
263
  console.log('')
262
264
  }
263
265
 
264
- const workflowAgents = result.agents.filter(a => a.type === 'workflow').map(a => a.name)
265
- const domainAgents = result.agents.filter(a => a.type === 'domain').map(a => a.name)
266
+ const workflowAgents = result.agents.filter((a) => a.type === 'workflow').map((a) => a.name)
267
+ const domainAgents = result.agents.filter((a) => a.type === 'domain').map((a) => a.name)
266
268
 
267
269
  console.log(`🤖 Agents Regenerated (${result.agents.length})`)
268
270
  console.log(`├── Workflow: ${workflowAgents.join(', ')}`)
@@ -286,14 +288,21 @@ export class AnalysisCommands extends PrjctCommandsBase {
286
288
 
287
289
  // Summary metrics
288
290
  const elapsed = Date.now() - startTime
289
- const contextFilesCount = result.contextFiles.length + (result.aiTools?.filter(t => t.success).length || 0)
291
+ const contextFilesCount =
292
+ result.contextFiles.length + (result.aiTools?.filter((t) => t.success).length || 0)
290
293
  const agentCount = result.agents.length
291
294
 
292
295
  console.log('─'.repeat(45))
293
296
  console.log(`📊 Sync Summary`)
294
- console.log(` Stack: ${result.stats.ecosystem} (${result.stats.frameworks.join(', ') || 'no frameworks'})`)
295
- console.log(` Files: ${result.stats.fileCount} analyzed → ${contextFilesCount} context files`)
296
- console.log(` Agents: ${agentCount} (${result.agents.filter(a => a.type === 'domain').length} domain)`)
297
+ console.log(
298
+ ` Stack: ${result.stats.ecosystem} (${result.stats.frameworks.join(', ') || 'no frameworks'})`
299
+ )
300
+ console.log(
301
+ ` Files: ${result.stats.fileCount} analyzed → ${contextFilesCount} context files`
302
+ )
303
+ console.log(
304
+ ` Agents: ${agentCount} (${result.agents.filter((a) => a.type === 'domain').length} domain)`
305
+ )
297
306
  console.log(` Time: ${(elapsed / 1000).toFixed(1)}s`)
298
307
  console.log('')
299
308
 
@@ -360,8 +369,8 @@ export class AnalysisCommands extends PrjctCommandsBase {
360
369
  const globalPath = pathManager.getGlobalProjectPath(projectId)
361
370
  let projectName = 'Unknown'
362
371
  try {
363
- const fs = require('fs/promises')
364
- const path = require('path')
372
+ const fs = require('node:fs/promises')
373
+ const path = require('node:path')
365
374
  const projectJson = JSON.parse(
366
375
  await fs.readFile(path.join(globalPath, 'project.json'), 'utf-8')
367
376
  )
@@ -384,14 +393,18 @@ export class AnalysisCommands extends PrjctCommandsBase {
384
393
  console.log('')
385
394
  console.log('╭─────────────────────────────────────────────────╮')
386
395
  console.log('│ 📊 prjct-cli Value Dashboard │')
387
- console.log(`│ Project: ${projectName.padEnd(20).slice(0, 20)} | Since: ${firstSyncDate.padEnd(12).slice(0, 12)} │`)
396
+ console.log(
397
+ `│ Project: ${projectName.padEnd(20).slice(0, 20)} | Since: ${firstSyncDate.padEnd(12).slice(0, 12)} │`
398
+ )
388
399
  console.log('╰─────────────────────────────────────────────────╯')
389
400
  console.log('')
390
401
 
391
402
  // Token Savings Section
392
403
  console.log('💰 TOKEN SAVINGS')
393
404
  console.log(` Total saved: ${this._formatTokens(summary.totalTokensSaved)} tokens`)
394
- console.log(` Compression: ${(summary.compressionRate * 100).toFixed(0)}% average reduction`)
405
+ console.log(
406
+ ` Compression: ${(summary.compressionRate * 100).toFixed(0)}% average reduction`
407
+ )
395
408
  console.log(` Estimated cost: ${formatCost(summary.estimatedCostSaved)} saved`)
396
409
  console.log('')
397
410
 
@@ -421,7 +434,9 @@ export class AnalysisCommands extends PrjctCommandsBase {
421
434
  if (summary.trend !== 0) {
422
435
  const trendIcon = summary.trend > 0 ? '↑' : '↓'
423
436
  const trendSign = summary.trend > 0 ? '+' : ''
424
- console.log(` ${trendIcon} ${trendSign}${summary.trend.toFixed(0)}% vs previous 30 days`)
437
+ console.log(
438
+ ` ${trendIcon} ${trendSign}${summary.trend.toFixed(0)}% vs previous 30 days`
439
+ )
425
440
  }
426
441
  console.log('')
427
442
  }
@@ -433,7 +448,12 @@ export class AnalysisCommands extends PrjctCommandsBase {
433
448
 
434
449
  // Export mode - return markdown
435
450
  if (options.export) {
436
- const markdown = this._generateStatsMarkdown(summary, dailyStats, projectName, firstSyncDate)
451
+ const markdown = this._generateStatsMarkdown(
452
+ summary,
453
+ dailyStats,
454
+ projectName,
455
+ firstSyncDate
456
+ )
437
457
  console.log(markdown)
438
458
  return { success: true, data: { markdown } }
439
459
  }
@@ -493,7 +513,7 @@ export class AnalysisCommands extends PrjctCommandsBase {
493
513
  last30DaysTokens: number
494
514
  trend: number
495
515
  },
496
- dailyStats: { date: string; tokensSaved: number; syncs: number }[],
516
+ _dailyStats: { date: string; tokensSaved: number; syncs: number }[],
497
517
  projectName: string,
498
518
  firstSyncDate: string
499
519
  ): string {
@@ -549,5 +569,4 @@ export class AnalysisCommands extends PrjctCommandsBase {
549
569
 
550
570
  return lines.join('\n')
551
571
  }
552
-
553
572
  }