prjct-cli 0.15.1 → 0.18.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.
Files changed (72) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/bin/dev.js +0 -1
  3. package/bin/serve.js +19 -20
  4. package/core/__tests__/agentic/memory-system.test.ts +2 -1
  5. package/core/__tests__/agentic/plan-mode.test.ts +2 -1
  6. package/core/agentic/agent-router.ts +79 -14
  7. package/core/agentic/command-executor/command-executor.ts +2 -74
  8. package/core/agentic/services.ts +0 -48
  9. package/core/agentic/template-loader.ts +35 -1
  10. package/core/command-registry/setup-commands.ts +15 -0
  11. package/core/commands/base.ts +96 -77
  12. package/core/commands/planning.ts +13 -2
  13. package/core/commands/setup.ts +3 -85
  14. package/core/domain/agent-generator.ts +9 -17
  15. package/core/errors.ts +209 -0
  16. package/core/infrastructure/config-manager.ts +22 -5
  17. package/core/infrastructure/path-manager.ts +23 -1
  18. package/core/infrastructure/setup.ts +5 -50
  19. package/core/storage/ideas-storage.ts +4 -0
  20. package/core/storage/queue-storage.ts +4 -0
  21. package/core/storage/shipped-storage.ts +4 -0
  22. package/core/storage/state-storage.ts +4 -0
  23. package/core/storage/storage-manager.ts +52 -13
  24. package/core/sync/auth-config.ts +145 -0
  25. package/core/sync/index.ts +30 -0
  26. package/core/sync/oauth-handler.ts +148 -0
  27. package/core/sync/sync-client.ts +252 -0
  28. package/core/sync/sync-manager.ts +358 -0
  29. package/core/utils/logger.ts +19 -12
  30. package/package.json +2 -4
  31. package/templates/agentic/subagent-generation.md +109 -0
  32. package/templates/commands/auth.md +234 -0
  33. package/templates/commands/sync.md +129 -13
  34. package/templates/subagents/domain/backend.md +105 -0
  35. package/templates/subagents/domain/database.md +118 -0
  36. package/templates/subagents/domain/devops.md +148 -0
  37. package/templates/subagents/domain/frontend.md +99 -0
  38. package/templates/subagents/domain/testing.md +169 -0
  39. package/templates/subagents/workflow/prjct-planner.md +158 -0
  40. package/templates/subagents/workflow/prjct-shipper.md +179 -0
  41. package/templates/subagents/workflow/prjct-workflow.md +98 -0
  42. package/bin/generate-views.js +0 -209
  43. package/bin/migrate-to-json.js +0 -742
  44. package/core/agentic/context-filter.ts +0 -365
  45. package/core/agentic/parallel-tools.ts +0 -165
  46. package/core/agentic/response-templates.ts +0 -164
  47. package/core/agentic/semantic-compression.ts +0 -273
  48. package/core/agentic/think-blocks.ts +0 -202
  49. package/core/agentic/validation-rules.ts +0 -313
  50. package/core/domain/agent-matcher.ts +0 -130
  51. package/core/domain/agent-validator.ts +0 -250
  52. package/core/domain/architect-session.ts +0 -315
  53. package/core/domain/product-standards.ts +0 -106
  54. package/core/domain/smart-cache.ts +0 -167
  55. package/core/domain/task-analyzer.ts +0 -296
  56. package/core/infrastructure/legacy-installer-detector/cleanup.ts +0 -216
  57. package/core/infrastructure/legacy-installer-detector/detection.ts +0 -95
  58. package/core/infrastructure/legacy-installer-detector/index.ts +0 -171
  59. package/core/infrastructure/legacy-installer-detector/migration.ts +0 -87
  60. package/core/infrastructure/legacy-installer-detector/types.ts +0 -42
  61. package/core/infrastructure/legacy-installer-detector.ts +0 -7
  62. package/core/infrastructure/migrator/file-operations.ts +0 -125
  63. package/core/infrastructure/migrator/index.ts +0 -288
  64. package/core/infrastructure/migrator/project-scanner.ts +0 -90
  65. package/core/infrastructure/migrator/reports.ts +0 -117
  66. package/core/infrastructure/migrator/types.ts +0 -124
  67. package/core/infrastructure/migrator/validation.ts +0 -94
  68. package/core/infrastructure/migrator/version-migration.ts +0 -117
  69. package/core/infrastructure/migrator.ts +0 -10
  70. package/core/infrastructure/uuid-migration.ts +0 -750
  71. package/templates/commands/migrate-all.md +0 -96
  72. package/templates/commands/migrate.md +0 -140
@@ -1,365 +0,0 @@
1
- /**
2
- * Intelligent Context Filtering System
3
- *
4
- * Reduces context window usage by 70-90% by loading only
5
- * relevant files for each specialized agent
6
- *
7
- * @version 1.0.0
8
- */
9
-
10
- import fs from 'fs/promises'
11
- import path from 'path'
12
- import { glob } from 'glob'
13
- import log from '../utils/logger'
14
-
15
- interface Agent {
16
- name: string
17
- [key: string]: unknown
18
- }
19
-
20
- interface Task {
21
- [key: string]: unknown
22
- }
23
-
24
- interface FullContext {
25
- estimatedFiles?: string[]
26
- fileCount?: number
27
- [key: string]: unknown
28
- }
29
-
30
- interface Patterns {
31
- include: string[]
32
- exclude: string[]
33
- realExtensions?: Record<string, number>
34
- projectStructure?: string[]
35
- configFiles?: string[]
36
- detectedTech?: Record<string, unknown>
37
- }
38
-
39
- interface Metrics {
40
- originalFiles: number
41
- filteredFiles: number
42
- reductionPercent: number
43
- processingTime: number
44
- effectiveness: string
45
- }
46
-
47
- interface FilterResult {
48
- files: string[]
49
- patterns: {
50
- preEstimated?: boolean
51
- detectedTech?: Record<string, unknown>
52
- projectStructure?: string[]
53
- agentic?: boolean
54
- }
55
- metrics: Metrics
56
- agent: string
57
- filtered: boolean
58
- }
59
-
60
- class ContextFilter {
61
- fileCache: Map<string, unknown>
62
-
63
- constructor() {
64
- // Cache for file analysis
65
- this.fileCache = new Map()
66
- // NO HARDCODED PATTERNS - Everything is agentic
67
- // Claude decides what files are needed based on analysis
68
- }
69
-
70
- /**
71
- * Main entry point - filters context based on agent and task
72
- * IMPROVED: Supports pre-estimated files for lazy loading
73
- */
74
- async filterForAgent(
75
- agent: Agent,
76
- task: Task,
77
- projectPath: string,
78
- fullContext: FullContext = {}
79
- ): Promise<FilterResult> {
80
- const startTime = Date.now()
81
-
82
- // If files were pre-estimated (lazy loading), use them
83
- if (fullContext.estimatedFiles && fullContext.estimatedFiles.length > 0) {
84
- const filteredFiles = fullContext.estimatedFiles
85
-
86
- const metrics = this.calculateMetrics(fullContext.fileCount || filteredFiles.length, filteredFiles.length, startTime)
87
-
88
- return {
89
- files: filteredFiles,
90
- patterns: { preEstimated: true },
91
- metrics,
92
- agent: agent.name,
93
- filtered: true,
94
- }
95
- }
96
-
97
- // Fallback to traditional filtering if no pre-estimation
98
- // Determine what files this agent needs
99
- const relevantPatterns = await this.determineRelevantPatterns(agent, task, projectPath)
100
-
101
- // Load only relevant files
102
- const filteredFiles = await this.loadRelevantFiles(projectPath, relevantPatterns)
103
-
104
- // Calculate reduction metrics
105
- const metrics = this.calculateMetrics(
106
- fullContext.fileCount || 1000, // estimate if not provided
107
- filteredFiles.length,
108
- startTime
109
- )
110
-
111
- return {
112
- files: filteredFiles,
113
- patterns: {
114
- detectedTech: relevantPatterns.detectedTech,
115
- projectStructure: relevantPatterns.projectStructure,
116
- agentic: true, // Flag indicating this was agentic, not hardcoded
117
- },
118
- metrics,
119
- agent: agent.name,
120
- filtered: true,
121
- }
122
- }
123
-
124
- /**
125
- * Determine which patterns to use based on agent and task
126
- *
127
- * 100% AGENTIC: Uses analyzer for I/O, no hardcoded tech detection.
128
- * Claude decides what files matter based on actual project analysis.
129
- */
130
- async determineRelevantPatterns(_agent: Agent, _task: Task, projectPath: string): Promise<Patterns> {
131
- const { default: analyzer } = await import('../domain/analyzer')
132
- analyzer.init(projectPath)
133
-
134
- // Get REAL file extensions from project (not assumed)
135
- const realExtensions = await analyzer.getFileExtensions()
136
-
137
- // Get REAL directory structure (not assumed)
138
- const projectStructure = await analyzer.listDirectories()
139
-
140
- // Get config files that exist (not hardcoded list)
141
- const configFiles = await analyzer.listConfigFiles()
142
-
143
- // Build patterns from ACTUAL project data
144
- const patterns: Patterns = {
145
- include: [],
146
- exclude: ['node_modules', '.git', 'dist', 'build', 'coverage', '.next', '.nuxt', 'target', 'vendor'],
147
- realExtensions, // Actual extensions found in project
148
- projectStructure, // Actual directories
149
- configFiles, // Actual config files
150
- }
151
-
152
- return patterns
153
- }
154
-
155
- /**
156
- * Detect actual project structure (no assumptions)
157
- */
158
- async detectProjectStructure(projectPath: string): Promise<string[]> {
159
- try {
160
- const entries = await fs.readdir(projectPath, { withFileTypes: true })
161
- const directories = entries.filter((e) => e.isDirectory() && !e.name.startsWith('.')).map((e) => e.name)
162
- return directories
163
- } catch {
164
- return []
165
- }
166
- }
167
-
168
- /**
169
- * Detect technologies used in the project
170
- *
171
- * 100% AGENTIC: Uses analyzer for raw data.
172
- * No categorization - Claude decides what's relevant.
173
- */
174
- async detectProjectTechnologies(
175
- projectPath: string
176
- ): Promise<{ extensions: Record<string, number>; directories: string[]; configFiles: string[] }> {
177
- try {
178
- const { default: analyzer } = await import('../domain/analyzer')
179
- analyzer.init(projectPath)
180
-
181
- // Return raw data for Claude to analyze
182
- return {
183
- extensions: await analyzer.getFileExtensions(),
184
- directories: await analyzer.listDirectories(),
185
- configFiles: await analyzer.listConfigFiles(),
186
- }
187
- } catch (error) {
188
- log.error('Error detecting project data:', (error as Error).message)
189
- return { extensions: {}, directories: [], configFiles: [] }
190
- }
191
- }
192
-
193
- /**
194
- * Load only relevant files based on patterns
195
- */
196
- async loadRelevantFiles(projectPath: string, patterns: Patterns): Promise<string[]> {
197
- const files: string[] = []
198
-
199
- try {
200
- // Build glob patterns
201
- const globPatterns = this.buildGlobPatterns(patterns)
202
-
203
- // Execute glob searches
204
- for (const pattern of globPatterns) {
205
- const matches = await glob(pattern, {
206
- cwd: projectPath,
207
- ignore: patterns.exclude.map((ex) => `**/${ex}/**`),
208
- nodir: true,
209
- follow: false,
210
- })
211
-
212
- // Ensure matches is always an array (glob v10+ returns array, but be defensive)
213
- if (Array.isArray(matches)) {
214
- files.push(...matches)
215
- } else if (matches) {
216
- // Convert iterable to array if needed
217
- files.push(...Array.from(matches as Iterable<string>))
218
- }
219
- }
220
-
221
- // Remove duplicates and sort
222
- const uniqueFiles = [...new Set(files)].sort()
223
-
224
- // Limit to reasonable number
225
- const maxFiles = 300
226
- if (uniqueFiles.length > maxFiles) {
227
- log.debug(`Limiting context to ${maxFiles} files`)
228
- return uniqueFiles.slice(0, maxFiles)
229
- }
230
-
231
- // Expand context with related files
232
- const expandedFiles = await this.expandContext(uniqueFiles, projectPath)
233
-
234
- return expandedFiles.slice(0, maxFiles)
235
- } catch (error) {
236
- log.error('Error loading files:', (error as Error).message)
237
- return []
238
- }
239
- }
240
-
241
- /**
242
- * Build glob patterns from pattern configuration
243
- *
244
- * 100% AGENTIC: Uses REAL extensions from project, not hardcoded mapping.
245
- * No language→extension assumptions.
246
- */
247
- buildGlobPatterns(patterns: Patterns): string[] {
248
- const globs: string[] = []
249
-
250
- // Use REAL extensions found in project (no hardcoded mapping)
251
- if (patterns.realExtensions && Object.keys(patterns.realExtensions).length > 0) {
252
- // Get extensions that actually exist in this project
253
- const extensions = Object.keys(patterns.realExtensions)
254
- .filter((ext) => ext.startsWith('.')) // Only valid extensions
255
- .slice(0, 20) // Limit to top 20 most common
256
-
257
- if (extensions.length > 0) {
258
- globs.push(`**/*{${extensions.join(',')}}`)
259
- }
260
- }
261
-
262
- // Use REAL project structure (no assumptions)
263
- if (patterns.projectStructure && patterns.projectStructure.length > 0) {
264
- patterns.projectStructure.forEach((dir) => {
265
- // Exclude universal noise directories
266
- if (!patterns.exclude.includes(dir)) {
267
- globs.push(`${dir}/**/*`)
268
- }
269
- })
270
- }
271
-
272
- // Include REAL config files that exist (not hardcoded list)
273
- if (patterns.configFiles && patterns.configFiles.length > 0) {
274
- patterns.configFiles.forEach((file) => {
275
- globs.push(file)
276
- })
277
- }
278
-
279
- // Fallback: if no patterns detected, include all source-like files
280
- if (globs.length === 0) {
281
- globs.push('**/*')
282
- }
283
-
284
- return globs
285
- }
286
-
287
- /**
288
- * Calculate metrics for context reduction
289
- */
290
- calculateMetrics(originalCount: number, filteredCount: number, startTime: number): Metrics {
291
- const reduction = originalCount > 0 ? Math.round(((originalCount - filteredCount) / originalCount) * 100) : 0
292
-
293
- return {
294
- originalFiles: originalCount,
295
- filteredFiles: filteredCount,
296
- reductionPercent: reduction,
297
- processingTime: Date.now() - startTime,
298
- effectiveness: reduction > 70 ? 'high' : reduction > 40 ? 'medium' : 'low',
299
- }
300
- }
301
-
302
- /**
303
- * Check if file exists
304
- */
305
- async fileExists(filePath: string): Promise<boolean> {
306
- try {
307
- await fs.access(filePath)
308
- return true
309
- } catch {
310
- return false
311
- }
312
- }
313
-
314
- /**
315
- * Expand context with related files (tests, styles, etc.)
316
- */
317
- async expandContext(files: string[], _projectPath?: string): Promise<string[]> {
318
- const expanded = new Set(files)
319
-
320
- for (const file of files) {
321
- const ext = path.extname(file)
322
- const basename = path.basename(file, ext)
323
- const dirname = path.dirname(file)
324
-
325
- // 1. Look for test files
326
- const testPatterns = [
327
- path.join(dirname, `${basename}.test${ext}`),
328
- path.join(dirname, `${basename}.spec${ext}`),
329
- path.join(dirname, '__tests__', `${basename}.test${ext}`),
330
- path.join(dirname, 'tests', `${basename}.test${ext}`),
331
- ]
332
-
333
- // 2. Look for style files (for UI components)
334
- const stylePatterns = [
335
- path.join(dirname, `${basename}.css`),
336
- path.join(dirname, `${basename}.scss`),
337
- path.join(dirname, `${basename}.module.css`),
338
- path.join(dirname, `${basename}.module.scss`),
339
- ]
340
-
341
- // Check if these related files exist
342
- const potentialFiles = [...testPatterns, ...stylePatterns]
343
-
344
- for (const potential of potentialFiles) {
345
- if (!expanded.has(potential) && (await this.fileExists(potential))) {
346
- expanded.add(potential)
347
- }
348
- }
349
- }
350
-
351
- return Array.from(expanded).sort()
352
- }
353
-
354
- /**
355
- * Get filter statistics
356
- */
357
- getStatistics(): { cachedFiles: number; agentic: boolean } {
358
- return {
359
- cachedFiles: this.fileCache.size,
360
- agentic: true, // All filtering is now agentic, no hardcoded patterns
361
- }
362
- }
363
- }
364
-
365
- export default ContextFilter
@@ -1,165 +0,0 @@
1
- /**
2
- * Parallel Tools
3
- * Execute multiple tools in parallel for performance
4
- *
5
- * @module agentic/parallel-tools
6
- * @version 1.0.0
7
- */
8
-
9
- import fs from 'fs/promises'
10
-
11
- interface ToolCall {
12
- tool: string
13
- args: unknown[]
14
- }
15
-
16
- interface ToolResult {
17
- tool: string
18
- success: boolean
19
- result?: unknown
20
- error?: string
21
- duration: number
22
- }
23
-
24
- interface ParallelMetrics {
25
- totalCalls: number
26
- parallelCalls: number
27
- sequentialCalls: number
28
- averageDuration: number
29
- savedTime: number
30
- }
31
-
32
- class ParallelTools {
33
- private metrics: ParallelMetrics
34
-
35
- constructor() {
36
- this.metrics = {
37
- totalCalls: 0,
38
- parallelCalls: 0,
39
- sequentialCalls: 0,
40
- averageDuration: 0,
41
- savedTime: 0,
42
- }
43
- }
44
-
45
- /**
46
- * Execute multiple tool calls in parallel
47
- */
48
- async execute(toolCalls: ToolCall[]): Promise<ToolResult[]> {
49
- const startTime = Date.now()
50
-
51
- const promises = toolCalls.map(async (call) => {
52
- const callStart = Date.now()
53
- try {
54
- const result = await this.executeOne(call.tool, call.args)
55
- return {
56
- tool: call.tool,
57
- success: true,
58
- result,
59
- duration: Date.now() - callStart,
60
- }
61
- } catch (error) {
62
- return {
63
- tool: call.tool,
64
- success: false,
65
- error: (error as Error).message,
66
- duration: Date.now() - callStart,
67
- }
68
- }
69
- })
70
-
71
- const results = await Promise.all(promises)
72
-
73
- // Update metrics
74
- const totalDuration = Date.now() - startTime
75
- const sumIndividual = results.reduce((sum, r) => sum + r.duration, 0)
76
- this.metrics.totalCalls += toolCalls.length
77
- this.metrics.parallelCalls += toolCalls.length
78
- this.metrics.savedTime += sumIndividual - totalDuration
79
- this.metrics.averageDuration =
80
- (this.metrics.averageDuration * (this.metrics.totalCalls - toolCalls.length) + totalDuration) /
81
- this.metrics.totalCalls
82
-
83
- return results
84
- }
85
-
86
- /**
87
- * Execute a single tool
88
- */
89
- private async executeOne(tool: string, args: unknown[]): Promise<unknown> {
90
- switch (tool) {
91
- case 'Read':
92
- return await fs.readFile(args[0] as string, 'utf-8')
93
-
94
- case 'Write':
95
- await fs.writeFile(args[0] as string, args[1] as string, 'utf-8')
96
- return true
97
-
98
- case 'GetTimestamp':
99
- return new Date().toISOString()
100
-
101
- case 'GetDate':
102
- return new Date().toISOString().split('T')[0]
103
-
104
- default:
105
- throw new Error(`Unknown tool: ${tool}`)
106
- }
107
- }
108
-
109
- /**
110
- * Read multiple files in parallel
111
- */
112
- async readAll(paths: string[]): Promise<Map<string, string | null>> {
113
- const results = new Map<string, string | null>()
114
-
115
- const promises = paths.map(async (path) => {
116
- try {
117
- const content = await fs.readFile(path, 'utf-8')
118
- return { path, content }
119
- } catch {
120
- return { path, content: null }
121
- }
122
- })
123
-
124
- const readResults = await Promise.all(promises)
125
-
126
- readResults.forEach(({ path, content }) => {
127
- results.set(path, content)
128
- })
129
-
130
- return results
131
- }
132
-
133
- /**
134
- * Check if tools can be parallelized
135
- */
136
- canParallelize(tools: string[]): boolean {
137
- // Read operations can always be parallelized
138
- const readOnlyTools = ['Read', 'Glob', 'Grep', 'GetTimestamp', 'GetDate']
139
- return tools.every((tool) => readOnlyTools.includes(tool))
140
- }
141
-
142
- /**
143
- * Get parallelization metrics
144
- */
145
- getMetrics(): ParallelMetrics {
146
- return { ...this.metrics }
147
- }
148
-
149
- /**
150
- * Reset metrics
151
- */
152
- resetMetrics(): void {
153
- this.metrics = {
154
- totalCalls: 0,
155
- parallelCalls: 0,
156
- sequentialCalls: 0,
157
- averageDuration: 0,
158
- savedTime: 0,
159
- }
160
- }
161
- }
162
-
163
- const parallelTools = new ParallelTools()
164
- export default parallelTools
165
- export { ParallelTools }
@@ -1,164 +0,0 @@
1
- /**
2
- * Response Templates
3
- * Consistent response formatting for commands
4
- *
5
- * @module agentic/response-templates
6
- * @version 1.0.0
7
- */
8
-
9
- interface ResponseData {
10
- task?: string
11
- duration?: string
12
- feature?: string
13
- filesChanged?: number
14
- keyFile?: string
15
- nextAction?: string
16
- message?: string
17
- ideas?: number
18
- roadmapFeatures?: number
19
- pendingTasks?: number
20
- completedTasks?: number
21
- error?: string
22
- [key: string]: unknown
23
- }
24
-
25
- interface ResponseTemplate {
26
- success: (data: ResponseData) => string
27
- error: (data: ResponseData) => string
28
- }
29
-
30
- /**
31
- * Response templates by command
32
- */
33
- const templates: Record<string, ResponseTemplate> = {
34
- done: {
35
- success: (data) => `✅ ${data.task || 'Task'} (${data.duration || '?'})
36
-
37
- Files: ${data.filesChanged || 0} | Modified: ${data.keyFile || 'n/a'}
38
- Next: ${data.nextAction || '/p:next for queue'}`,
39
-
40
- error: (data) => `❌ Could not complete task
41
-
42
- ${data.error || 'Unknown error'}
43
- Try: /p:now to check current task`,
44
- },
45
-
46
- ship: {
47
- success: (data) => `🚀 ${data.feature || 'Feature'} shipped!
48
-
49
- ${data.message || 'Successfully deployed'}
50
- Next: ${data.nextAction || '/p:recap for progress'}`,
51
-
52
- error: (data) => `❌ Ship failed
53
-
54
- ${data.error || 'Unknown error'}
55
- Check git status and try again`,
56
- },
57
-
58
- now: {
59
- success: (data) => `🎯 Now working on: ${data.task || 'Task'}
60
-
61
- ${data.message || 'Focus set'}
62
- When done: /p:done`,
63
-
64
- error: (data) => `❌ Could not set task
65
-
66
- ${data.error || 'Unknown error'}
67
- Try: /p:init if project not initialized`,
68
- },
69
-
70
- feature: {
71
- success: (data) => `✨ Feature added: ${data.feature || 'New feature'}
72
-
73
- ${data.message || 'Added to roadmap'}
74
- Start: /p:now to begin first task`,
75
-
76
- error: (data) => `❌ Could not add feature
77
-
78
- ${data.error || 'Unknown error'}`,
79
- },
80
-
81
- idea: {
82
- success: (data) => `💡 Idea captured!
83
-
84
- ${data.message || 'Saved to ideas.md'}
85
- Total ideas: ${data.ideas || '?'}`,
86
-
87
- error: (data) => `❌ Could not save idea
88
-
89
- ${data.error || 'Unknown error'}`,
90
- },
91
-
92
- recap: {
93
- success: (data) => `📊 Project Recap
94
-
95
- Features: ${data.roadmapFeatures || 0}
96
- Pending: ${data.pendingTasks || 0}
97
- Completed: ${data.completedTasks || 0}
98
-
99
- ${data.message || ''}`,
100
-
101
- error: (data) => `❌ Could not generate recap
102
-
103
- ${data.error || 'Unknown error'}
104
- Try: /p:sync to refresh state`,
105
- },
106
-
107
- sync: {
108
- success: (data) => `🔄 Sync complete
109
-
110
- ${data.message || 'Project state updated'}
111
- Next: ${data.nextAction || '/p:recap for overview'}`,
112
-
113
- error: (data) => `❌ Sync failed
114
-
115
- ${data.error || 'Unknown error'}
116
- Try: /p:init to reinitialize`,
117
- },
118
-
119
- init: {
120
- success: (data) => `🎉 Project initialized!
121
-
122
- ${data.message || 'Ready to use prjct'}
123
- Next: /p:sync to analyze codebase`,
124
-
125
- error: (data) => `❌ Initialization failed
126
-
127
- ${data.error || 'Unknown error'}
128
- Check permissions and try again`,
129
- },
130
-
131
- default: {
132
- success: (data) => `✅ Done
133
-
134
- ${data.message || 'Operation completed'}`,
135
-
136
- error: (data) => `❌ Failed
137
-
138
- ${data.error || 'Unknown error'}`,
139
- },
140
- }
141
-
142
- /**
143
- * Format response for a command
144
- */
145
- function format(commandName: string, data: ResponseData): string {
146
- const template = templates[commandName] || templates.default
147
- const success = data.error ? false : true
148
-
149
- if (success) {
150
- return template.success(data)
151
- } else {
152
- return template.error(data)
153
- }
154
- }
155
-
156
- /**
157
- * Get template for command
158
- */
159
- function getTemplate(commandName: string): ResponseTemplate {
160
- return templates[commandName] || templates.default
161
- }
162
-
163
- export { format, getTemplate, templates }
164
- export default { format, getTemplate, templates }