prjct-cli 0.45.0 ā 0.45.3
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 +75 -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
|
@@ -3,25 +3,25 @@
|
|
|
3
3
|
* Write-Through Architecture: JSON ā MD ā Event
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import path from 'path'
|
|
7
|
-
|
|
8
|
-
import
|
|
6
|
+
import path from 'node:path'
|
|
7
|
+
import authorDetector from '../infrastructure/author-detector'
|
|
8
|
+
import commandInstaller from '../infrastructure/command-installer'
|
|
9
9
|
import { generateUUID } from '../schemas'
|
|
10
|
-
import type { Priority,
|
|
10
|
+
import type { Priority, TaskSection, TaskType } from '../schemas/state'
|
|
11
|
+
import { ideasStorage, queueStorage } from '../storage'
|
|
12
|
+
import type { CommandResult, ProjectContext } from '../types'
|
|
13
|
+
import { showNextSteps } from '../utils/next-steps'
|
|
14
|
+
import { OnboardingWizard } from '../wizard'
|
|
11
15
|
import {
|
|
12
|
-
PrjctCommandsBase,
|
|
13
|
-
contextBuilder,
|
|
14
|
-
toolRegistry,
|
|
15
|
-
pathManager,
|
|
16
16
|
configManager,
|
|
17
|
-
|
|
17
|
+
contextBuilder,
|
|
18
18
|
dateHelper,
|
|
19
|
-
|
|
19
|
+
fileHelper,
|
|
20
|
+
out,
|
|
21
|
+
PrjctCommandsBase,
|
|
22
|
+
pathManager,
|
|
23
|
+
toolRegistry,
|
|
20
24
|
} from './base'
|
|
21
|
-
import { queueStorage, ideasStorage } from '../storage'
|
|
22
|
-
import authorDetector from '../infrastructure/author-detector'
|
|
23
|
-
import commandInstaller from '../infrastructure/command-installer'
|
|
24
|
-
import { showNextSteps } from '../utils/next-steps'
|
|
25
25
|
|
|
26
26
|
// Lazy-loaded to avoid circular dependencies
|
|
27
27
|
let _analysisCommands: import('./analysis').AnalysisCommands | null = null
|
|
@@ -33,12 +33,32 @@ async function getAnalysisCommands(): Promise<import('./analysis').AnalysisComma
|
|
|
33
33
|
return _analysisCommands
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
export interface InitOptions {
|
|
37
|
+
yes?: boolean // Skip interactive wizard, use defaults
|
|
38
|
+
idea?: string | null // Initial idea for architect mode
|
|
39
|
+
}
|
|
40
|
+
|
|
36
41
|
export class PlanningCommands extends PrjctCommandsBase {
|
|
37
42
|
/**
|
|
38
|
-
* /p:init - Initialize prjct project
|
|
43
|
+
* /p:init - Initialize prjct project with interactive wizard
|
|
44
|
+
*
|
|
45
|
+
* @param options.yes - Skip wizard, use auto-detected values (for CI)
|
|
46
|
+
* @param options.idea - Initial idea for architect mode
|
|
47
|
+
* @param projectPath - Project directory path
|
|
39
48
|
*/
|
|
40
|
-
async init(
|
|
49
|
+
async init(
|
|
50
|
+
options: InitOptions | string | null = {},
|
|
51
|
+
projectPath: string = process.cwd()
|
|
52
|
+
): Promise<CommandResult> {
|
|
41
53
|
try {
|
|
54
|
+
// Handle legacy signature: init(idea, projectPath)
|
|
55
|
+
let opts: InitOptions = {}
|
|
56
|
+
if (typeof options === 'string' || options === null) {
|
|
57
|
+
opts = { idea: options }
|
|
58
|
+
} else {
|
|
59
|
+
opts = options
|
|
60
|
+
}
|
|
61
|
+
|
|
42
62
|
await this.initializeAgent()
|
|
43
63
|
|
|
44
64
|
const isConfigured = await configManager.isConfigured(projectPath)
|
|
@@ -48,6 +68,25 @@ export class PlanningCommands extends PrjctCommandsBase {
|
|
|
48
68
|
return { success: false, message: 'Already initialized' }
|
|
49
69
|
}
|
|
50
70
|
|
|
71
|
+
// Determine if we should run interactive wizard
|
|
72
|
+
const isTTY = process.stdout.isTTY && process.stdin.isTTY
|
|
73
|
+
const skipWizard = opts.yes || !isTTY || process.env.CI === 'true'
|
|
74
|
+
|
|
75
|
+
// Run wizard if interactive
|
|
76
|
+
let wizardResult = null
|
|
77
|
+
if (!skipWizard) {
|
|
78
|
+
const wizard = new OnboardingWizard(projectPath)
|
|
79
|
+
wizardResult = await wizard.run()
|
|
80
|
+
|
|
81
|
+
if (wizardResult.skipped) {
|
|
82
|
+
return { success: false, message: 'Setup cancelled' }
|
|
83
|
+
}
|
|
84
|
+
} else if (isTTY && opts.yes) {
|
|
85
|
+
// Non-interactive but show progress
|
|
86
|
+
const wizard = new OnboardingWizard(projectPath)
|
|
87
|
+
wizardResult = await wizard.runNonInteractive()
|
|
88
|
+
}
|
|
89
|
+
|
|
51
90
|
out.step(1, 4, 'Detecting author...')
|
|
52
91
|
|
|
53
92
|
const detectedAuthor = await authorDetector.detect()
|
|
@@ -55,7 +94,7 @@ export class PlanningCommands extends PrjctCommandsBase {
|
|
|
55
94
|
const author = {
|
|
56
95
|
name: detectedAuthor.name || undefined,
|
|
57
96
|
email: detectedAuthor.email || undefined,
|
|
58
|
-
github: detectedAuthor.github || undefined
|
|
97
|
+
github: detectedAuthor.github || undefined,
|
|
59
98
|
}
|
|
60
99
|
const config = await configManager.createConfig(projectPath, author)
|
|
61
100
|
const projectId = config.projectId
|
|
@@ -75,13 +114,32 @@ export class PlanningCommands extends PrjctCommandsBase {
|
|
|
75
114
|
'planning/roadmap.md': '# ROADMAP\n\n',
|
|
76
115
|
'planning/specs/.gitkeep': '# Specs directory - created by /p:spec\n',
|
|
77
116
|
'memory/context.jsonl': '',
|
|
78
|
-
'memory/patterns.json': JSON.stringify(
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
117
|
+
'memory/patterns.json': JSON.stringify(
|
|
118
|
+
{
|
|
119
|
+
version: 1,
|
|
120
|
+
decisions: {},
|
|
121
|
+
preferences: {},
|
|
122
|
+
workflows: {},
|
|
123
|
+
counters: {},
|
|
124
|
+
},
|
|
125
|
+
null,
|
|
126
|
+
2
|
|
127
|
+
),
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Save wizard preferences if available
|
|
131
|
+
if (wizardResult) {
|
|
132
|
+
baseFiles['config/wizard.json'] = JSON.stringify(
|
|
133
|
+
{
|
|
134
|
+
projectType: wizardResult.projectType,
|
|
135
|
+
agents: wizardResult.agents,
|
|
136
|
+
stack: wizardResult.stack,
|
|
137
|
+
preferences: wizardResult.preferences,
|
|
138
|
+
createdAt: new Date().toISOString(),
|
|
139
|
+
},
|
|
140
|
+
null,
|
|
141
|
+
2
|
|
142
|
+
)
|
|
85
143
|
}
|
|
86
144
|
|
|
87
145
|
for (const [filePath, content] of Object.entries(baseFiles)) {
|
|
@@ -98,16 +156,25 @@ export class PlanningCommands extends PrjctCommandsBase {
|
|
|
98
156
|
|
|
99
157
|
if (analysisResult.success) {
|
|
100
158
|
out.step(4, 4, 'Generating agents...')
|
|
101
|
-
|
|
159
|
+
|
|
160
|
+
// Pass wizard agent selection to sync if available
|
|
161
|
+
if (wizardResult?.agents) {
|
|
162
|
+
await analysis.sync(projectPath, { aiTools: wizardResult.agents })
|
|
163
|
+
} else {
|
|
164
|
+
await analysis.sync(projectPath)
|
|
165
|
+
}
|
|
166
|
+
|
|
102
167
|
out.done('initialized')
|
|
103
|
-
|
|
168
|
+
this._printNextSteps(wizardResult)
|
|
169
|
+
return { success: true, mode: 'existing', projectId, wizard: wizardResult }
|
|
104
170
|
}
|
|
105
171
|
}
|
|
106
172
|
|
|
173
|
+
const idea = opts.idea
|
|
107
174
|
if (isEmpty && !hasCode) {
|
|
108
175
|
if (!idea) {
|
|
109
176
|
out.done('blank project - provide idea for architect mode')
|
|
110
|
-
return { success: true, mode: 'blank_no_idea', projectId }
|
|
177
|
+
return { success: true, mode: 'blank_no_idea', projectId, wizard: wizardResult }
|
|
111
178
|
}
|
|
112
179
|
|
|
113
180
|
out.spin('architect mode...')
|
|
@@ -118,20 +185,60 @@ export class PlanningCommands extends PrjctCommandsBase {
|
|
|
118
185
|
await commandInstaller.installGlobalConfig()
|
|
119
186
|
|
|
120
187
|
out.done('architect mode ready')
|
|
121
|
-
return { success: true, mode: 'architect', projectId, idea }
|
|
188
|
+
return { success: true, mode: 'architect', projectId, idea, wizard: wizardResult }
|
|
122
189
|
}
|
|
123
190
|
|
|
124
191
|
await commandInstaller.installGlobalConfig()
|
|
125
192
|
|
|
126
193
|
out.done('initialized')
|
|
127
|
-
|
|
128
|
-
return { success: true, projectId }
|
|
194
|
+
this._printNextSteps(wizardResult)
|
|
195
|
+
return { success: true, projectId, wizard: wizardResult }
|
|
129
196
|
} catch (error) {
|
|
130
197
|
out.fail((error as Error).message)
|
|
131
198
|
return { success: false, error: (error as Error).message }
|
|
132
199
|
}
|
|
133
200
|
}
|
|
134
201
|
|
|
202
|
+
/**
|
|
203
|
+
* Print next steps after initialization
|
|
204
|
+
*/
|
|
205
|
+
private _printNextSteps(wizardResult: import('../wizard').WizardResult | null): void {
|
|
206
|
+
console.log('')
|
|
207
|
+
console.log(' Quick start:')
|
|
208
|
+
console.log(' prjct sync Update context after changes')
|
|
209
|
+
console.log(' prjct task Start working on a task')
|
|
210
|
+
console.log('')
|
|
211
|
+
|
|
212
|
+
if (wizardResult) {
|
|
213
|
+
const agentFiles = wizardResult.agents
|
|
214
|
+
.map((a) => {
|
|
215
|
+
switch (a) {
|
|
216
|
+
case 'claude':
|
|
217
|
+
return 'CLAUDE.md'
|
|
218
|
+
case 'cursor':
|
|
219
|
+
return '.cursorrules'
|
|
220
|
+
case 'windsurf':
|
|
221
|
+
return '.windsurfrules'
|
|
222
|
+
case 'copilot':
|
|
223
|
+
return '.github/copilot-instructions.md'
|
|
224
|
+
case 'gemini':
|
|
225
|
+
return 'GEMINI.md'
|
|
226
|
+
default:
|
|
227
|
+
return null
|
|
228
|
+
}
|
|
229
|
+
})
|
|
230
|
+
.filter(Boolean)
|
|
231
|
+
|
|
232
|
+
if (agentFiles.length > 0) {
|
|
233
|
+
console.log(` Generated: ${agentFiles.join(', ')}`)
|
|
234
|
+
console.log('')
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
console.log(' Docs: https://prjct.app/docs')
|
|
239
|
+
console.log('')
|
|
240
|
+
}
|
|
241
|
+
|
|
135
242
|
/**
|
|
136
243
|
* /p:feature - Add feature with value analysis, roadmap, and task breakdown
|
|
137
244
|
*/
|
|
@@ -153,7 +260,7 @@ export class PlanningCommands extends PrjctCommandsBase {
|
|
|
153
260
|
|
|
154
261
|
out.spin(`planning ${description}...`)
|
|
155
262
|
|
|
156
|
-
const context = await contextBuilder.build(projectPath, { description }) as ProjectContext
|
|
263
|
+
const context = (await contextBuilder.build(projectPath, { description })) as ProjectContext
|
|
157
264
|
const tasks = this._breakdownFeatureTasks(description)
|
|
158
265
|
const featureId = generateUUID()
|
|
159
266
|
|
|
@@ -165,21 +272,24 @@ export class PlanningCommands extends PrjctCommandsBase {
|
|
|
165
272
|
}
|
|
166
273
|
|
|
167
274
|
// Write-through: Add tasks (JSON ā MD ā Event)
|
|
168
|
-
await queueStorage.addTasks(
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
275
|
+
await queueStorage.addTasks(
|
|
276
|
+
projectId,
|
|
277
|
+
tasksWithAgents.map((t) => ({
|
|
278
|
+
description: t.task,
|
|
279
|
+
priority: 'medium' as Priority,
|
|
280
|
+
type: 'feature' as TaskType,
|
|
281
|
+
section: 'active' as TaskSection,
|
|
282
|
+
featureId,
|
|
283
|
+
originFeature: description,
|
|
284
|
+
agent: t.agent,
|
|
285
|
+
}))
|
|
286
|
+
)
|
|
177
287
|
|
|
178
288
|
await this.logToMemory(projectPath, 'feature_planned', {
|
|
179
289
|
feature: description,
|
|
180
290
|
featureId,
|
|
181
291
|
tasks: tasksWithAgents.length,
|
|
182
|
-
assignments: tasksWithAgents.map(t => ({ task: t.task, agent: t.agent })),
|
|
292
|
+
assignments: tasksWithAgents.map((t) => ({ task: t.task, agent: t.agent })),
|
|
183
293
|
timestamp: dateHelper.getTimestamp(),
|
|
184
294
|
})
|
|
185
295
|
|
|
@@ -187,7 +297,9 @@ export class PlanningCommands extends PrjctCommandsBase {
|
|
|
187
297
|
acc[t.agent] = (acc[t.agent] || 0) + 1
|
|
188
298
|
return acc
|
|
189
299
|
}, {})
|
|
190
|
-
const agentSummary = Object.entries(agentCounts)
|
|
300
|
+
const agentSummary = Object.entries(agentCounts)
|
|
301
|
+
.map(([a, c]) => `${a}:${c}`)
|
|
302
|
+
.join(' ')
|
|
191
303
|
|
|
192
304
|
out.done(`${tasks.length} tasks [${agentSummary}]`)
|
|
193
305
|
|
|
@@ -219,18 +331,22 @@ export class PlanningCommands extends PrjctCommandsBase {
|
|
|
219
331
|
|
|
220
332
|
out.spin('tracking bug...')
|
|
221
333
|
|
|
222
|
-
const context = await contextBuilder.build(projectPath, { description }) as ProjectContext
|
|
334
|
+
const context = (await contextBuilder.build(projectPath, { description })) as ProjectContext
|
|
223
335
|
const severity = this._detectBugSeverity(description)
|
|
224
336
|
|
|
225
|
-
const agentResult = await this._assignAgentForTask(
|
|
337
|
+
const agentResult = await this._assignAgentForTask(
|
|
338
|
+
`fix bug: ${description}`,
|
|
339
|
+
projectPath,
|
|
340
|
+
context
|
|
341
|
+
)
|
|
226
342
|
const agent = agentResult.agent?.name || 'generalist'
|
|
227
343
|
|
|
228
344
|
// Map severity to Priority type
|
|
229
345
|
const priorityMap: Record<string, Priority> = {
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
346
|
+
critical: 'critical',
|
|
347
|
+
high: 'high',
|
|
348
|
+
medium: 'medium',
|
|
349
|
+
low: 'low',
|
|
234
350
|
}
|
|
235
351
|
const priority = priorityMap[severity] || 'medium'
|
|
236
352
|
|
|
@@ -240,7 +356,7 @@ export class PlanningCommands extends PrjctCommandsBase {
|
|
|
240
356
|
priority,
|
|
241
357
|
type: 'bug' as TaskType,
|
|
242
358
|
section: 'active' as TaskSection,
|
|
243
|
-
agent
|
|
359
|
+
agent,
|
|
244
360
|
})
|
|
245
361
|
|
|
246
362
|
await this.logToMemory(projectPath, 'bug_reported', {
|
|
@@ -264,7 +380,10 @@ export class PlanningCommands extends PrjctCommandsBase {
|
|
|
264
380
|
/**
|
|
265
381
|
* /p:architect - Execute architect plan and generate code
|
|
266
382
|
*/
|
|
267
|
-
async architect(
|
|
383
|
+
async architect(
|
|
384
|
+
action: string = 'execute',
|
|
385
|
+
projectPath: string = process.cwd()
|
|
386
|
+
): Promise<CommandResult> {
|
|
268
387
|
if (action !== 'execute') {
|
|
269
388
|
return {
|
|
270
389
|
success: false,
|
|
@@ -319,7 +438,7 @@ export class PlanningCommands extends PrjctCommandsBase {
|
|
|
319
438
|
console.log(`\nš§ Stack:\n${stack}`)
|
|
320
439
|
console.log(`\nš Implementation Steps:\n${steps}`)
|
|
321
440
|
|
|
322
|
-
console.log(
|
|
441
|
+
console.log(`\n${'='.repeat(60)}`)
|
|
323
442
|
console.log('š¤ READY TO GENERATE CODE')
|
|
324
443
|
console.log('='.repeat(60))
|
|
325
444
|
|
|
@@ -372,7 +491,8 @@ export class PlanningCommands extends PrjctCommandsBase {
|
|
|
372
491
|
|
|
373
492
|
// Determine if simple or complex idea
|
|
374
493
|
const wordCount = description.split(/\s+/).length
|
|
375
|
-
const isComplex =
|
|
494
|
+
const isComplex =
|
|
495
|
+
wordCount > 20 || description.includes('with') || description.includes('that')
|
|
376
496
|
|
|
377
497
|
if (isComplex) {
|
|
378
498
|
// Complex idea ā Create architecture session
|
|
@@ -432,7 +552,10 @@ Generated: ${new Date().toLocaleString()}
|
|
|
432
552
|
/**
|
|
433
553
|
* /p:spec - Create detailed specifications for complex features
|
|
434
554
|
*/
|
|
435
|
-
async spec(
|
|
555
|
+
async spec(
|
|
556
|
+
featureName: string | null = null,
|
|
557
|
+
projectPath: string = process.cwd()
|
|
558
|
+
): Promise<CommandResult> {
|
|
436
559
|
try {
|
|
437
560
|
const initResult = await this.ensureProjectInit(projectPath)
|
|
438
561
|
if (!initResult.success) return initResult
|
|
@@ -451,9 +574,9 @@ Generated: ${new Date().toLocaleString()}
|
|
|
451
574
|
const specsPath = path.join(globalPath, 'planning', 'specs')
|
|
452
575
|
|
|
453
576
|
try {
|
|
454
|
-
const fs = await import('fs/promises')
|
|
577
|
+
const fs = await import('node:fs/promises')
|
|
455
578
|
const files = await fs.readdir(specsPath)
|
|
456
|
-
const specs = files.filter(f => f.endsWith('.md') && f !== '.gitkeep')
|
|
579
|
+
const specs = files.filter((f) => f.endsWith('.md') && f !== '.gitkeep')
|
|
457
580
|
|
|
458
581
|
if (specs.length === 0) {
|
|
459
582
|
out.warn('no specs yet')
|
|
@@ -467,7 +590,7 @@ Generated: ${new Date().toLocaleString()}
|
|
|
467
590
|
const name = s.replace('.md', '').replace(/-/g, ' ')
|
|
468
591
|
console.log(` ${i + 1}. ${name}`)
|
|
469
592
|
})
|
|
470
|
-
console.log('ā'.repeat(50)
|
|
593
|
+
console.log(`${'ā'.repeat(50)}\n`)
|
|
471
594
|
|
|
472
595
|
return { success: true, specs }
|
|
473
596
|
} catch (_error) {
|
|
@@ -8,16 +8,17 @@
|
|
|
8
8
|
* - Future migration to pure handler pattern
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import {
|
|
12
|
-
import { COMMANDS, CATEGORIES } from './command-data'
|
|
13
|
-
import { WorkflowCommands } from './workflow'
|
|
14
|
-
import { PlanningCommands } from './planning'
|
|
15
|
-
import { ShippingCommands } from './shipping'
|
|
11
|
+
import { AnalysisCommands } from './analysis'
|
|
16
12
|
import { AnalyticsCommands } from './analytics'
|
|
13
|
+
import { CATEGORIES, COMMANDS } from './command-data'
|
|
14
|
+
import { ContextCommands } from './context'
|
|
17
15
|
import { MaintenanceCommands } from './maintenance'
|
|
18
|
-
import {
|
|
16
|
+
import { PlanningCommands } from './planning'
|
|
17
|
+
import { commandRegistry } from './registry'
|
|
19
18
|
import { SetupCommands } from './setup'
|
|
20
|
-
import {
|
|
19
|
+
import { ShippingCommands } from './shipping'
|
|
20
|
+
import { UninstallCommands } from './uninstall'
|
|
21
|
+
import { WorkflowCommands } from './workflow'
|
|
21
22
|
|
|
22
23
|
// Singleton instances of command groups
|
|
23
24
|
const workflow = new WorkflowCommands()
|
|
@@ -28,6 +29,7 @@ const maintenance = new MaintenanceCommands()
|
|
|
28
29
|
const analysis = new AnalysisCommands()
|
|
29
30
|
const setup = new SetupCommands()
|
|
30
31
|
const context = new ContextCommands()
|
|
32
|
+
const uninstallCmd = new UninstallCommands()
|
|
31
33
|
|
|
32
34
|
/**
|
|
33
35
|
* Register categories
|
|
@@ -49,7 +51,7 @@ export function registerAllCommands(): void {
|
|
|
49
51
|
registerCategories()
|
|
50
52
|
|
|
51
53
|
// Helper to get metadata from COMMANDS
|
|
52
|
-
const getMeta = (name: string) => COMMANDS.find(c => c.name === name)
|
|
54
|
+
const getMeta = (name: string) => COMMANDS.find((c) => c.name === name)
|
|
53
55
|
|
|
54
56
|
// Workflow commands
|
|
55
57
|
commandRegistry.registerMethod('done', workflow, 'done', getMeta('done'))
|
|
@@ -86,6 +88,7 @@ export function registerAllCommands(): void {
|
|
|
86
88
|
// Setup commands
|
|
87
89
|
commandRegistry.registerMethod('start', setup, 'start', getMeta('start'))
|
|
88
90
|
commandRegistry.registerMethod('setup', setup, 'setup', getMeta('setup'))
|
|
91
|
+
commandRegistry.registerMethod('uninstall', uninstallCmd, 'uninstall', getMeta('uninstall'))
|
|
89
92
|
|
|
90
93
|
// Context command (for Claude templates)
|
|
91
94
|
commandRegistry.registerMethod('context', context, 'context', getMeta('context'))
|
|
@@ -103,5 +106,6 @@ export {
|
|
|
103
106
|
maintenance,
|
|
104
107
|
analysis,
|
|
105
108
|
setup,
|
|
106
|
-
context
|
|
109
|
+
context,
|
|
110
|
+
uninstallCmd,
|
|
107
111
|
}
|
|
@@ -5,30 +5,30 @@
|
|
|
5
5
|
* Each command is registered as a handler that receives context and returns a result.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import type { CommandResult } from '../types'
|
|
9
8
|
import configManager from '../infrastructure/config-manager'
|
|
10
9
|
import pathManager from '../infrastructure/path-manager'
|
|
10
|
+
import type { CommandResult } from '../types'
|
|
11
11
|
import { getTimestamp } from '../utils/date-helper'
|
|
12
12
|
|
|
13
13
|
// Re-export types for convenience
|
|
14
14
|
export type {
|
|
15
|
-
|
|
15
|
+
BlockingRules,
|
|
16
|
+
CategoryInfo,
|
|
16
17
|
CommandHandler,
|
|
18
|
+
CommandMeta,
|
|
19
|
+
CommandValidationResult as ValidationResult,
|
|
20
|
+
ExecutionContext,
|
|
17
21
|
HandlerFn,
|
|
18
22
|
RegistryCommandUsage as CommandUsage,
|
|
19
|
-
BlockingRules,
|
|
20
|
-
CommandMeta,
|
|
21
|
-
CategoryInfo,
|
|
22
23
|
RegistryStats,
|
|
23
|
-
CommandValidationResult as ValidationResult,
|
|
24
24
|
} from '../types'
|
|
25
25
|
|
|
26
26
|
import type {
|
|
27
|
-
|
|
27
|
+
CategoryInfo,
|
|
28
28
|
CommandHandler,
|
|
29
|
-
HandlerFn,
|
|
30
29
|
CommandMeta,
|
|
31
|
-
|
|
30
|
+
ExecutionContext,
|
|
31
|
+
HandlerFn,
|
|
32
32
|
RegistryStats,
|
|
33
33
|
} from '../types'
|
|
34
34
|
|
|
@@ -60,7 +60,11 @@ export class CommandRegistry {
|
|
|
60
60
|
/**
|
|
61
61
|
* Register a command handler function (function-based)
|
|
62
62
|
*/
|
|
63
|
-
registerFn<TParams>(
|
|
63
|
+
registerFn<TParams>(
|
|
64
|
+
name: string,
|
|
65
|
+
handler: HandlerFn<TParams>,
|
|
66
|
+
meta?: Partial<CommandMeta>
|
|
67
|
+
): void {
|
|
64
68
|
this.handlerFns.set(name, handler as HandlerFn<unknown>)
|
|
65
69
|
this.setMeta(name, meta)
|
|
66
70
|
}
|
|
@@ -134,10 +138,7 @@ export class CommandRegistry {
|
|
|
134
138
|
* Get list of registered commands
|
|
135
139
|
*/
|
|
136
140
|
list(): string[] {
|
|
137
|
-
return [
|
|
138
|
-
...this.handlers.keys(),
|
|
139
|
-
...this.handlerFns.keys(),
|
|
140
|
-
]
|
|
141
|
+
return [...this.handlers.keys(), ...this.handlerFns.keys()]
|
|
141
142
|
}
|
|
142
143
|
|
|
143
144
|
/**
|
package/core/commands/setup.ts
CHANGED
|
@@ -2,15 +2,15 @@
|
|
|
2
2
|
* Setup Commands: start, setup, installStatusLine, showAsciiArt
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import
|
|
6
|
-
import
|
|
5
|
+
import fs from 'node:fs'
|
|
6
|
+
import path from 'node:path'
|
|
7
7
|
import chalk from 'chalk'
|
|
8
8
|
|
|
9
9
|
import commandInstaller from '../infrastructure/command-installer'
|
|
10
10
|
import pathManager from '../infrastructure/path-manager'
|
|
11
11
|
import type { CommandResult, SetupOptions } from '../types'
|
|
12
|
-
import { PrjctCommandsBase } from './base'
|
|
13
12
|
import { VERSION } from '../utils/version'
|
|
13
|
+
import { PrjctCommandsBase } from './base'
|
|
14
14
|
|
|
15
15
|
export class SetupCommands extends PrjctCommandsBase {
|
|
16
16
|
/**
|
|
@@ -19,12 +19,13 @@ export class SetupCommands extends PrjctCommandsBase {
|
|
|
19
19
|
async start(): Promise<CommandResult> {
|
|
20
20
|
const aiProvider = require('../infrastructure/ai-provider')
|
|
21
21
|
const activeProvider = aiProvider.getActiveProvider()
|
|
22
|
-
|
|
22
|
+
|
|
23
23
|
console.log(`š Setting up prjct for ${activeProvider.displayName}...\n`)
|
|
24
24
|
|
|
25
25
|
const status = await commandInstaller.checkInstallation()
|
|
26
26
|
|
|
27
|
-
if (!status.claudeDetected) {
|
|
27
|
+
if (!status.claudeDetected) {
|
|
28
|
+
// Note: variable name is legacy, checks active provider
|
|
28
29
|
return {
|
|
29
30
|
success: false,
|
|
30
31
|
message:
|
|
@@ -43,11 +44,15 @@ export class SetupCommands extends PrjctCommandsBase {
|
|
|
43
44
|
}
|
|
44
45
|
}
|
|
45
46
|
|
|
46
|
-
console.log(
|
|
47
|
+
console.log(
|
|
48
|
+
`\nā
Installed ${result.installed?.length ?? 0} commands to:\n ${pathManager.getDisplayPath(result.path || '')}`
|
|
49
|
+
)
|
|
47
50
|
|
|
48
51
|
if ((result.errors?.length ?? 0) > 0) {
|
|
49
52
|
console.log(`\nā ļø ${result.errors?.length ?? 0} errors:`)
|
|
50
|
-
result.errors?.forEach((e: { file: string; error: string }) =>
|
|
53
|
+
result.errors?.forEach((e: { file: string; error: string }) =>
|
|
54
|
+
console.log(` - ${e.file}: ${e.error}`)
|
|
55
|
+
)
|
|
51
56
|
}
|
|
52
57
|
|
|
53
58
|
console.log('\nš Setup complete!')
|
|
@@ -87,12 +92,16 @@ export class SetupCommands extends PrjctCommandsBase {
|
|
|
87
92
|
|
|
88
93
|
if ((result.errors?.length ?? 0) > 0) {
|
|
89
94
|
console.log(`\nā ļø ${result.errors?.length ?? 0} errors:`)
|
|
90
|
-
result.errors?.forEach((e: { file: string; error: string }) =>
|
|
95
|
+
result.errors?.forEach((e: { file: string; error: string }) =>
|
|
96
|
+
console.log(` - ${e.file}: ${e.error}`)
|
|
97
|
+
)
|
|
91
98
|
}
|
|
92
99
|
|
|
93
100
|
console.log('\nš Installing global configuration...')
|
|
94
101
|
const configResult = await commandInstaller.installGlobalConfig()
|
|
95
|
-
const displayPath = configResult.path
|
|
102
|
+
const displayPath = configResult.path
|
|
103
|
+
? pathManager.getDisplayPath(configResult.path)
|
|
104
|
+
: 'global config'
|
|
96
105
|
|
|
97
106
|
if (configResult.success) {
|
|
98
107
|
if (configResult.action === 'created') {
|
|
@@ -108,7 +117,7 @@ export class SetupCommands extends PrjctCommandsBase {
|
|
|
108
117
|
|
|
109
118
|
const aiProvider = require('../infrastructure/ai-provider')
|
|
110
119
|
const activeProvider = aiProvider.getActiveProvider()
|
|
111
|
-
|
|
120
|
+
|
|
112
121
|
// Status line is currently Claude-only
|
|
113
122
|
if (activeProvider.name === 'claude') {
|
|
114
123
|
console.log('\nā” Installing status line...')
|
|
@@ -211,7 +220,7 @@ echo "ā” prjct"
|
|
|
211
220
|
|
|
212
221
|
settings.statusLine = {
|
|
213
222
|
type: 'command',
|
|
214
|
-
command: statusLinePath
|
|
223
|
+
command: statusLinePath,
|
|
215
224
|
}
|
|
216
225
|
|
|
217
226
|
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2))
|
|
@@ -235,7 +244,9 @@ echo "ā” prjct"
|
|
|
235
244
|
console.log(chalk.bold.cyan(' āāā āāā āāāāāāāāāāāāāāāāāāā āāā'))
|
|
236
245
|
console.log(chalk.bold.cyan(' āāā āāā āāā āāāāāā āāāāāāā āāā'))
|
|
237
246
|
console.log('')
|
|
238
|
-
console.log(
|
|
247
|
+
console.log(
|
|
248
|
+
` ${chalk.bold.cyan('prjct')}${chalk.magenta('/')}${chalk.green('cli')} ${chalk.dim.white(`v${VERSION} installed`)}`
|
|
249
|
+
)
|
|
239
250
|
console.log('')
|
|
240
251
|
console.log(` ${chalk.yellow('ā”')} Ship faster with zero friction`)
|
|
241
252
|
console.log(` ${chalk.green('š')} From idea to technical tasks in minutes`)
|
|
@@ -258,10 +269,11 @@ echo "ā” prjct"
|
|
|
258
269
|
console.log(chalk.dim('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā'))
|
|
259
270
|
console.log('')
|
|
260
271
|
console.log(` ${chalk.dim('Documentation:')} ${chalk.cyan('https://prjct.app')}`)
|
|
261
|
-
console.log(
|
|
272
|
+
console.log(
|
|
273
|
+
` ${chalk.dim('Report issues:')} ${chalk.cyan('https://github.com/jlopezlira/prjct-cli/issues')}`
|
|
274
|
+
)
|
|
262
275
|
console.log('')
|
|
263
276
|
console.log(chalk.bold.magenta('Happy shipping! š'))
|
|
264
277
|
console.log('')
|
|
265
278
|
}
|
|
266
|
-
|
|
267
279
|
}
|
|
@@ -3,22 +3,14 @@
|
|
|
3
3
|
* Write-Through Architecture: JSON ā MD ā Event
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import path from 'path'
|
|
7
|
-
|
|
8
|
-
import { isNotFoundError } from '../types/fs'
|
|
6
|
+
import path from 'node:path'
|
|
9
7
|
import memorySystem from '../agentic/memory-system'
|
|
8
|
+
import { shippedStorage, stateStorage } from '../storage'
|
|
10
9
|
import type { CommandResult } from '../types'
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
PrjctCommandsBase,
|
|
14
|
-
toolRegistry,
|
|
15
|
-
configManager,
|
|
16
|
-
fileHelper,
|
|
17
|
-
dateHelper,
|
|
18
|
-
out
|
|
19
|
-
} from './base'
|
|
20
|
-
import { stateStorage, shippedStorage } from '../storage'
|
|
10
|
+
import { isNotFoundError } from '../types/fs'
|
|
21
11
|
import { showNextSteps } from '../utils/next-steps'
|
|
12
|
+
import { detectProjectCommands } from '../utils/project-commands'
|
|
13
|
+
import { configManager, dateHelper, fileHelper, out, PrjctCommandsBase, toolRegistry } from './base'
|
|
22
14
|
|
|
23
15
|
export class ShippingCommands extends PrjctCommandsBase {
|
|
24
16
|
/**
|
|
@@ -93,7 +85,7 @@ export class ShippingCommands extends PrjctCommandsBase {
|
|
|
93
85
|
// Write-through: Record shipped feature (JSON ā MD ā Event)
|
|
94
86
|
await shippedStorage.addShipped(projectId, {
|
|
95
87
|
name: featureName,
|
|
96
|
-
version: newVersion
|
|
88
|
+
version: newVersion,
|
|
97
89
|
})
|
|
98
90
|
|
|
99
91
|
await this.logToMemory(projectPath, 'feature_shipped', {
|
|
@@ -112,7 +104,7 @@ export class ShippingCommands extends PrjctCommandsBase {
|
|
|
112
104
|
if (isQuickShip) {
|
|
113
105
|
await memorySystem.recordWorkflow(projectId, 'quick_ship', {
|
|
114
106
|
description: 'Ship without full checks',
|
|
115
|
-
feature_type: featureName.toLowerCase().includes('doc') ? 'docs' : 'other'
|
|
107
|
+
feature_type: featureName.toLowerCase().includes('doc') ? 'docs' : 'other',
|
|
116
108
|
})
|
|
117
109
|
}
|
|
118
110
|
|
|
@@ -213,7 +205,10 @@ export class ShippingCommands extends PrjctCommandsBase {
|
|
|
213
205
|
/**
|
|
214
206
|
* Create git commit for ship
|
|
215
207
|
*/
|
|
216
|
-
async _createShipCommit(
|
|
208
|
+
async _createShipCommit(
|
|
209
|
+
feature: string,
|
|
210
|
+
_projectPath: string
|
|
211
|
+
): Promise<{ success: boolean; message: string }> {
|
|
217
212
|
try {
|
|
218
213
|
await toolRegistry.get('Bash')!('git add .')
|
|
219
214
|
|