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.
- package/CHANGELOG.md +82 -0
- package/bin/prjct.ts +117 -10
- package/core/__tests__/agentic/memory-system.test.ts +39 -26
- package/core/__tests__/agentic/plan-mode.test.ts +64 -46
- package/core/__tests__/agentic/prompt-builder.test.ts +14 -14
- package/core/__tests__/services/project-index.test.ts +353 -0
- package/core/__tests__/types/fs.test.ts +3 -3
- package/core/__tests__/utils/date-helper.test.ts +10 -10
- package/core/__tests__/utils/output.test.ts +9 -6
- package/core/__tests__/utils/project-commands.test.ts +5 -6
- package/core/agentic/agent-router.ts +9 -10
- package/core/agentic/chain-of-thought.ts +16 -4
- package/core/agentic/command-executor.ts +66 -40
- package/core/agentic/context-builder.ts +8 -5
- package/core/agentic/ground-truth.ts +15 -9
- package/core/agentic/index.ts +145 -152
- package/core/agentic/loop-detector.ts +40 -11
- package/core/agentic/memory-system.ts +98 -35
- package/core/agentic/orchestrator-executor.ts +135 -71
- package/core/agentic/plan-mode.ts +46 -16
- package/core/agentic/prompt-builder.ts +108 -42
- package/core/agentic/services.ts +10 -9
- package/core/agentic/skill-loader.ts +9 -15
- package/core/agentic/smart-context.ts +129 -79
- package/core/agentic/template-executor.ts +13 -12
- package/core/agentic/template-loader.ts +7 -4
- package/core/agentic/tool-registry.ts +16 -13
- package/core/agents/index.ts +1 -1
- package/core/agents/performance.ts +10 -27
- package/core/ai-tools/formatters.ts +8 -6
- package/core/ai-tools/generator.ts +4 -4
- package/core/ai-tools/index.ts +1 -1
- package/core/ai-tools/registry.ts +21 -11
- package/core/bus/bus.ts +23 -16
- package/core/bus/index.ts +2 -2
- package/core/cli/linear.ts +3 -5
- package/core/cli/start.ts +28 -25
- package/core/commands/analysis.ts +58 -39
- package/core/commands/analytics.ts +52 -44
- package/core/commands/base.ts +15 -13
- package/core/commands/cleanup.ts +6 -13
- package/core/commands/command-data.ts +28 -4
- package/core/commands/commands.ts +57 -24
- package/core/commands/context.ts +4 -4
- package/core/commands/design.ts +3 -10
- package/core/commands/index.ts +5 -8
- package/core/commands/maintenance.ts +7 -4
- package/core/commands/planning.ts +179 -56
- package/core/commands/register.ts +13 -9
- package/core/commands/registry.ts +15 -14
- package/core/commands/setup.ts +26 -14
- package/core/commands/shipping.ts +11 -16
- package/core/commands/snapshots.ts +16 -32
- package/core/commands/uninstall.ts +541 -0
- package/core/commands/workflow.ts +24 -28
- package/core/constants/index.ts +10 -22
- package/core/context/generator.ts +82 -33
- package/core/context-tools/files-tool.ts +18 -19
- package/core/context-tools/imports-tool.ts +13 -33
- package/core/context-tools/index.ts +29 -54
- package/core/context-tools/recent-tool.ts +16 -22
- package/core/context-tools/signatures-tool.ts +17 -26
- package/core/context-tools/summary-tool.ts +20 -22
- package/core/context-tools/token-counter.ts +25 -20
- package/core/context-tools/types.ts +5 -5
- package/core/domain/agent-generator.ts +7 -5
- package/core/domain/agent-loader.ts +2 -2
- package/core/domain/analyzer.ts +19 -16
- package/core/domain/architecture-generator.ts +6 -3
- package/core/domain/context-estimator.ts +3 -4
- package/core/domain/snapshot-manager.ts +25 -22
- package/core/domain/task-stack.ts +24 -14
- package/core/errors.ts +1 -1
- package/core/events/events.ts +2 -4
- package/core/events/index.ts +1 -2
- package/core/index.ts +28 -16
- package/core/infrastructure/agent-detector.ts +3 -3
- package/core/infrastructure/ai-provider.ts +23 -20
- package/core/infrastructure/author-detector.ts +16 -10
- package/core/infrastructure/capability-installer.ts +2 -2
- package/core/infrastructure/claude-agent.ts +6 -6
- package/core/infrastructure/command-installer.ts +22 -17
- package/core/infrastructure/config-manager.ts +18 -14
- package/core/infrastructure/editors-config.ts +8 -4
- package/core/infrastructure/path-manager.ts +8 -6
- package/core/infrastructure/permission-manager.ts +20 -17
- package/core/infrastructure/setup.ts +42 -38
- package/core/infrastructure/update-checker.ts +5 -5
- package/core/integrations/issue-tracker/enricher.ts +8 -19
- package/core/integrations/issue-tracker/index.ts +2 -2
- package/core/integrations/issue-tracker/manager.ts +15 -15
- package/core/integrations/issue-tracker/types.ts +5 -22
- package/core/integrations/jira/client.ts +67 -59
- package/core/integrations/jira/index.ts +11 -14
- package/core/integrations/jira/mcp-adapter.ts +5 -10
- package/core/integrations/jira/service.ts +10 -10
- package/core/integrations/linear/client.ts +27 -18
- package/core/integrations/linear/index.ts +9 -12
- package/core/integrations/linear/service.ts +11 -11
- package/core/integrations/linear/sync.ts +8 -8
- package/core/outcomes/analyzer.ts +5 -18
- package/core/outcomes/index.ts +2 -2
- package/core/outcomes/recorder.ts +3 -3
- package/core/plugin/builtin/webhook.ts +19 -15
- package/core/plugin/hooks.ts +29 -21
- package/core/plugin/index.ts +7 -7
- package/core/plugin/loader.ts +19 -19
- package/core/plugin/registry.ts +12 -23
- package/core/schemas/agents.ts +1 -1
- package/core/schemas/analysis.ts +1 -1
- package/core/schemas/enriched-task.ts +62 -49
- package/core/schemas/ideas.ts +13 -13
- package/core/schemas/index.ts +17 -27
- package/core/schemas/issues.ts +40 -25
- package/core/schemas/metrics.ts +25 -25
- package/core/schemas/outcomes.ts +70 -62
- package/core/schemas/permissions.ts +15 -12
- package/core/schemas/prd.ts +27 -14
- package/core/schemas/project.ts +3 -3
- package/core/schemas/roadmap.ts +47 -34
- package/core/schemas/schemas.ts +3 -4
- package/core/schemas/shipped.ts +3 -3
- package/core/schemas/state.ts +43 -29
- package/core/server/index.ts +5 -6
- package/core/server/routes-extended.ts +68 -72
- package/core/server/routes.ts +3 -3
- package/core/server/server.ts +31 -26
- package/core/services/agent-generator.ts +237 -0
- package/core/services/agent-service.ts +2 -2
- package/core/services/breakdown-service.ts +2 -4
- package/core/services/context-generator.ts +299 -0
- package/core/services/context-selector.ts +420 -0
- package/core/services/doctor-service.ts +426 -0
- package/core/services/file-categorizer.ts +448 -0
- package/core/services/file-scorer.ts +270 -0
- package/core/services/git-analyzer.ts +267 -0
- package/core/services/index.ts +27 -10
- package/core/services/memory-service.ts +3 -4
- package/core/services/project-index.ts +911 -0
- package/core/services/project-service.ts +4 -4
- package/core/services/skill-installer.ts +14 -17
- package/core/services/skill-lock.ts +3 -3
- package/core/services/skill-service.ts +12 -6
- package/core/services/stack-detector.ts +245 -0
- package/core/services/sync-service.ts +87 -345
- package/core/services/watch-service.ts +294 -0
- package/core/session/compaction.ts +23 -31
- package/core/session/index.ts +11 -5
- package/core/session/log-migration.ts +3 -3
- package/core/session/metrics.ts +19 -14
- package/core/session/session-log-manager.ts +12 -17
- package/core/session/task-session-manager.ts +25 -25
- package/core/session/utils.ts +1 -1
- package/core/storage/ideas-storage.ts +41 -57
- package/core/storage/index-storage.ts +514 -0
- package/core/storage/index.ts +41 -17
- package/core/storage/metrics-storage.ts +39 -34
- package/core/storage/queue-storage.ts +35 -45
- package/core/storage/shipped-storage.ts +17 -20
- package/core/storage/state-storage.ts +50 -30
- package/core/storage/storage-manager.ts +6 -6
- package/core/storage/storage.ts +18 -15
- package/core/sync/auth-config.ts +3 -3
- package/core/sync/index.ts +13 -19
- package/core/sync/oauth-handler.ts +3 -3
- package/core/sync/sync-client.ts +4 -9
- package/core/sync/sync-manager.ts +12 -14
- package/core/types/commands.ts +42 -7
- package/core/types/index.ts +284 -305
- package/core/types/integrations.ts +3 -3
- package/core/types/storage.ts +14 -14
- package/core/types/utils.ts +3 -3
- package/core/utils/agent-stream.ts +3 -1
- package/core/utils/animations.ts +14 -11
- package/core/utils/branding.ts +7 -7
- package/core/utils/cache.ts +1 -3
- package/core/utils/collection-filters.ts +3 -15
- package/core/utils/date-helper.ts +2 -7
- package/core/utils/file-helper.ts +13 -8
- package/core/utils/jsonl-helper.ts +13 -10
- package/core/utils/keychain.ts +4 -8
- package/core/utils/logger.ts +1 -1
- package/core/utils/next-steps.ts +3 -3
- package/core/utils/output.ts +58 -11
- package/core/utils/project-commands.ts +6 -6
- package/core/utils/project-credentials.ts +5 -12
- package/core/utils/runtime.ts +2 -2
- package/core/utils/session-helper.ts +3 -4
- package/core/utils/version.ts +3 -3
- package/core/wizard/index.ts +13 -0
- package/core/wizard/onboarding.ts +633 -0
- package/core/workflow/state-machine.ts +7 -7
- package/dist/bin/prjct.mjs +18755 -15574
- package/dist/core/infrastructure/command-installer.js +86 -79
- package/dist/core/infrastructure/editors-config.js +6 -6
- package/dist/core/infrastructure/setup.js +246 -225
- package/dist/core/utils/version.js +9 -9
- package/package.json +11 -12
- package/scripts/build.js +3 -3
- package/scripts/postinstall.js +2 -2
- package/templates/mcp-config.json +6 -1
- package/templates/permissions/permissive.jsonc +1 -1
- package/templates/permissions/strict.jsonc +5 -9
- package/templates/global/docs/agents.md +0 -88
- package/templates/global/docs/architecture.md +0 -103
- package/templates/global/docs/commands.md +0 -96
- 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
|
|
15
|
-
import
|
|
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'
|
|
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
|
|
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'
|
|
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 (
|
|
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 {
|
|
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)
|
|
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>) =>
|
|
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>) =>
|
|
239
|
-
|
|
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>) =>
|
|
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>) =>
|
|
250
|
-
|
|
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>) =>
|
|
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>) =>
|
|
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 {
|
|
8
|
-
export {
|
|
7
|
+
export { type BusEventType, type EventCallback, type EventData, EventTypes } from '../types'
|
|
8
|
+
export { default, EventBus, emit, eventBus } from './bus'
|
package/core/cli/linear.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
|
13
|
-
import
|
|
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
|
|
26
|
-
const
|
|
25
|
+
const _BLUE = '\x1b[34m'
|
|
26
|
+
const _MAGENTA = '\x1b[35m'
|
|
27
27
|
const CYAN = '\x1b[36m'
|
|
28
28
|
const WHITE = '\x1b[37m'
|
|
29
|
-
const
|
|
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'
|
|
33
|
-
const G2 = '\x1b[38;2;80;180;255m'
|
|
34
|
-
const G3 = '\x1b[38;2;140;120;255m'
|
|
35
|
-
const G4 = '\x1b[38;2;200;80;220m'
|
|
36
|
-
const G5 = '\x1b[38;2;255;80;180m'
|
|
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
|
|
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 =
|
|
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(
|
|
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
|
|
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(
|
|
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 {
|
|
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(
|
|
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
|
|
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(
|
|
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 =
|
|
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(
|
|
295
|
-
|
|
296
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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
|
}
|