prjct-cli 0.19.0 → 0.20.1

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 (230) hide show
  1. package/CHANGELOG.md +66 -6
  2. package/CLAUDE.md +56 -15
  3. package/README.md +5 -6
  4. package/bin/prjct +59 -42
  5. package/bin/prjct.ts +60 -0
  6. package/core/__tests__/agentic/memory-system.test.ts +18 -3
  7. package/core/__tests__/agentic/plan-mode.test.ts +55 -26
  8. package/core/__tests__/agentic/prompt-builder.test.ts +6 -6
  9. package/core/__tests__/utils/project-commands.test.ts +72 -0
  10. package/core/agentic/agent-router.ts +3 -12
  11. package/core/agentic/command-executor.ts +372 -3
  12. package/core/agentic/context-builder.ts +7 -27
  13. package/core/agentic/ground-truth.ts +604 -5
  14. package/core/agentic/index.ts +180 -0
  15. package/core/agentic/loop-detector.ts +418 -4
  16. package/core/agentic/memory-system.ts +857 -3
  17. package/core/agentic/plan-mode.ts +491 -4
  18. package/core/agentic/prompt-builder.ts +44 -65
  19. package/core/agentic/services.ts +13 -5
  20. package/core/agentic/skill-loader.ts +112 -0
  21. package/core/agentic/smart-context.ts +37 -122
  22. package/core/agentic/template-loader.ts +79 -122
  23. package/core/agentic/tool-registry.ts +5 -11
  24. package/core/agents/index.ts +1 -1
  25. package/core/agents/performance.ts +4 -2
  26. package/core/bus/bus.ts +262 -0
  27. package/core/bus/index.ts +3 -313
  28. package/core/commands/analysis.ts +5 -5
  29. package/core/commands/analytics.ts +11 -11
  30. package/core/commands/base.ts +33 -209
  31. package/core/commands/cleanup.ts +148 -0
  32. package/core/commands/command-data.ts +346 -0
  33. package/core/commands/commands.ts +216 -0
  34. package/core/commands/design.ts +83 -0
  35. package/core/commands/index.ts +13 -207
  36. package/core/commands/maintenance.ts +52 -473
  37. package/core/commands/planning.ts +3 -3
  38. package/core/commands/register.ts +104 -0
  39. package/core/commands/registry.ts +441 -0
  40. package/core/commands/setup.ts +25 -9
  41. package/core/commands/shipping.ts +48 -11
  42. package/core/commands/snapshots.ts +299 -0
  43. package/core/commands/workflow.ts +2 -2
  44. package/core/constants/index.ts +254 -4
  45. package/core/domain/agent-loader.ts +5 -6
  46. package/core/domain/task-stack.ts +555 -4
  47. package/core/errors.ts +127 -1
  48. package/core/events/events.ts +87 -0
  49. package/core/events/index.ts +4 -138
  50. package/core/index.ts +15 -23
  51. package/core/infrastructure/agent-detector.ts +126 -201
  52. package/core/infrastructure/author-detector.ts +99 -171
  53. package/core/infrastructure/command-installer.ts +476 -4
  54. package/core/infrastructure/config-manager.ts +41 -37
  55. package/core/infrastructure/path-manager.ts +59 -9
  56. package/core/infrastructure/permission-manager.ts +286 -0
  57. package/core/outcomes/analyzer.ts +7 -41
  58. package/core/outcomes/index.ts +1 -1
  59. package/core/outcomes/recorder.ts +1 -1
  60. package/core/{plugins → plugin/builtin}/webhook.ts +6 -22
  61. package/core/plugin/loader.ts +5 -5
  62. package/core/plugin/registry.ts +2 -2
  63. package/core/schemas/ideas.ts +85 -54
  64. package/core/schemas/index.ts +14 -33
  65. package/core/schemas/permissions.ts +177 -0
  66. package/core/schemas/project.ts +39 -12
  67. package/core/schemas/roadmap.ts +94 -59
  68. package/core/schemas/schemas.ts +39 -0
  69. package/core/schemas/shipped.ts +87 -60
  70. package/core/schemas/state.ts +110 -70
  71. package/core/server/index.ts +21 -0
  72. package/core/server/routes.ts +165 -0
  73. package/core/server/server.ts +136 -0
  74. package/core/server/sse.ts +135 -0
  75. package/core/services/agent-service.ts +170 -0
  76. package/core/services/breakdown-service.ts +126 -0
  77. package/core/services/index.ts +21 -0
  78. package/core/services/memory-service.ts +108 -0
  79. package/core/services/project-service.ts +146 -0
  80. package/core/services/skill-service.ts +253 -0
  81. package/core/session/compaction.ts +257 -0
  82. package/core/session/index.ts +20 -8
  83. package/core/{infrastructure/session-manager/migration.ts → session/log-migration.ts} +9 -9
  84. package/core/{infrastructure/session-manager/session-manager.ts → session/session-log-manager.ts} +27 -26
  85. package/core/session/{session-manager.ts → task-session-manager.ts} +7 -4
  86. package/core/session/utils.ts +1 -1
  87. package/core/storage/ideas-storage.ts +10 -26
  88. package/core/storage/index.ts +14 -162
  89. package/core/storage/queue-storage.ts +13 -11
  90. package/core/storage/shipped-storage.ts +4 -17
  91. package/core/storage/state-storage.ts +35 -43
  92. package/core/storage/storage-manager.ts +42 -52
  93. package/core/storage/storage.ts +160 -0
  94. package/core/sync/auth-config.ts +1 -8
  95. package/core/sync/index.ts +17 -10
  96. package/core/sync/oauth-handler.ts +1 -6
  97. package/core/sync/sync-client.ts +6 -34
  98. package/core/sync/sync-manager.ts +11 -40
  99. package/core/types/agentic.ts +577 -0
  100. package/core/types/agents.ts +145 -0
  101. package/core/types/bus.ts +82 -0
  102. package/core/types/commands.ts +366 -0
  103. package/core/types/config.ts +66 -0
  104. package/core/types/core.ts +96 -0
  105. package/core/types/domain.ts +71 -0
  106. package/core/types/events.ts +42 -0
  107. package/core/types/fs.ts +56 -0
  108. package/core/types/index.ts +387 -500
  109. package/core/types/infrastructure.ts +196 -0
  110. package/core/{agentic/memory-system/types.ts → types/memory.ts} +33 -8
  111. package/core/{outcomes/types.ts → types/outcomes.ts} +53 -8
  112. package/core/types/plugin.ts +25 -0
  113. package/core/types/server.ts +54 -0
  114. package/core/types/services.ts +65 -0
  115. package/core/types/session.ts +135 -0
  116. package/core/types/storage.ts +148 -0
  117. package/core/types/sync.ts +121 -0
  118. package/core/types/task.ts +72 -0
  119. package/core/types/template.ts +24 -0
  120. package/core/types/utils.ts +90 -0
  121. package/core/utils/cache.ts +195 -0
  122. package/core/utils/collection-filters.ts +245 -0
  123. package/core/utils/date-helper.ts +1 -5
  124. package/core/utils/file-helper.ts +20 -10
  125. package/core/utils/jsonl-helper.ts +5 -8
  126. package/core/utils/markdown-builder.ts +277 -0
  127. package/core/utils/project-commands.ts +132 -0
  128. package/core/utils/runtime.ts +119 -0
  129. package/dist/bin/prjct.mjs +12568 -0
  130. package/package.json +13 -8
  131. package/scripts/build.js +106 -0
  132. package/scripts/postinstall.js +50 -8
  133. package/templates/agentic/agents/uxui.md +210 -0
  134. package/templates/agentic/subagent-generation.md +1 -1
  135. package/templates/commands/bug.md +219 -41
  136. package/templates/commands/feature.md +368 -80
  137. package/templates/commands/serve.md +118 -0
  138. package/templates/commands/ship.md +152 -14
  139. package/templates/commands/skill.md +110 -0
  140. package/templates/commands/sync.md +63 -4
  141. package/templates/commands/test.md +40 -188
  142. package/templates/mcp-config.json +0 -36
  143. package/templates/permissions/default.jsonc +60 -0
  144. package/templates/permissions/permissive.jsonc +49 -0
  145. package/templates/permissions/strict.jsonc +62 -0
  146. package/templates/skills/code-review.md +47 -0
  147. package/templates/skills/debug.md +61 -0
  148. package/templates/skills/refactor.md +47 -0
  149. package/templates/subagents/domain/devops.md +1 -1
  150. package/templates/subagents/domain/testing.md +6 -10
  151. package/templates/subagents/workflow/prjct-shipper.md +16 -7
  152. package/templates/tools/bash.txt +22 -0
  153. package/templates/tools/edit.txt +18 -0
  154. package/templates/tools/glob.txt +19 -0
  155. package/templates/tools/grep.txt +21 -0
  156. package/templates/tools/read.txt +14 -0
  157. package/templates/tools/task.txt +20 -0
  158. package/templates/tools/webfetch.txt +16 -0
  159. package/templates/tools/websearch.txt +18 -0
  160. package/templates/tools/write.txt +17 -0
  161. package/core/agentic/command-executor/command-executor.ts +0 -312
  162. package/core/agentic/command-executor/index.ts +0 -16
  163. package/core/agentic/command-executor/status-signal.ts +0 -38
  164. package/core/agentic/command-executor/types.ts +0 -79
  165. package/core/agentic/ground-truth/index.ts +0 -76
  166. package/core/agentic/ground-truth/types.ts +0 -33
  167. package/core/agentic/ground-truth/utils.ts +0 -48
  168. package/core/agentic/ground-truth/verifiers/analyze.ts +0 -54
  169. package/core/agentic/ground-truth/verifiers/done.ts +0 -75
  170. package/core/agentic/ground-truth/verifiers/feature.ts +0 -70
  171. package/core/agentic/ground-truth/verifiers/index.ts +0 -37
  172. package/core/agentic/ground-truth/verifiers/init.ts +0 -52
  173. package/core/agentic/ground-truth/verifiers/now.ts +0 -57
  174. package/core/agentic/ground-truth/verifiers/ship.ts +0 -85
  175. package/core/agentic/ground-truth/verifiers/spec.ts +0 -45
  176. package/core/agentic/ground-truth/verifiers/sync.ts +0 -47
  177. package/core/agentic/ground-truth/verifiers.ts +0 -6
  178. package/core/agentic/loop-detector/error-analysis.ts +0 -97
  179. package/core/agentic/loop-detector/hallucination.ts +0 -71
  180. package/core/agentic/loop-detector/index.ts +0 -41
  181. package/core/agentic/loop-detector/loop-detector.ts +0 -222
  182. package/core/agentic/loop-detector/types.ts +0 -66
  183. package/core/agentic/memory-system/history.ts +0 -53
  184. package/core/agentic/memory-system/index.ts +0 -192
  185. package/core/agentic/memory-system/patterns.ts +0 -156
  186. package/core/agentic/memory-system/semantic-memories.ts +0 -278
  187. package/core/agentic/memory-system/session.ts +0 -21
  188. package/core/agentic/plan-mode/approval.ts +0 -57
  189. package/core/agentic/plan-mode/constants.ts +0 -44
  190. package/core/agentic/plan-mode/index.ts +0 -28
  191. package/core/agentic/plan-mode/plan-mode.ts +0 -407
  192. package/core/agentic/plan-mode/types.ts +0 -193
  193. package/core/agents/types.ts +0 -126
  194. package/core/command-registry/categories.ts +0 -23
  195. package/core/command-registry/commands.ts +0 -15
  196. package/core/command-registry/core-commands.ts +0 -344
  197. package/core/command-registry/index.ts +0 -158
  198. package/core/command-registry/optional-commands.ts +0 -163
  199. package/core/command-registry/setup-commands.ts +0 -83
  200. package/core/command-registry/types.ts +0 -59
  201. package/core/command-registry.ts +0 -9
  202. package/core/commands/types.ts +0 -185
  203. package/core/commands.ts +0 -11
  204. package/core/constants/formats.ts +0 -187
  205. package/core/context-sync.ts +0 -18
  206. package/core/data/index.ts +0 -27
  207. package/core/data/md-base-manager.ts +0 -203
  208. package/core/data/md-ideas-manager.ts +0 -155
  209. package/core/data/md-queue-manager.ts +0 -180
  210. package/core/data/md-shipped-manager.ts +0 -90
  211. package/core/data/md-state-manager.ts +0 -137
  212. package/core/domain/task-stack/index.ts +0 -19
  213. package/core/domain/task-stack/parser.ts +0 -86
  214. package/core/domain/task-stack/storage.ts +0 -123
  215. package/core/domain/task-stack/task-stack.ts +0 -340
  216. package/core/domain/task-stack/types.ts +0 -51
  217. package/core/infrastructure/command-installer/command-installer.ts +0 -327
  218. package/core/infrastructure/command-installer/global-config.ts +0 -136
  219. package/core/infrastructure/command-installer/index.ts +0 -25
  220. package/core/infrastructure/command-installer/types.ts +0 -41
  221. package/core/infrastructure/session-manager/index.ts +0 -23
  222. package/core/infrastructure/session-manager/types.ts +0 -45
  223. package/core/infrastructure/session-manager.ts +0 -8
  224. package/core/serializers/ideas-serializer.ts +0 -187
  225. package/core/serializers/index.ts +0 -36
  226. package/core/serializers/queue-serializer.ts +0 -210
  227. package/core/serializers/shipped-serializer.ts +0 -108
  228. package/core/serializers/state-serializer.ts +0 -136
  229. package/core/session/types.ts +0 -29
  230. /package/core/infrastructure/{agents/claude-agent.ts → claude-agent.ts} +0 -0
@@ -1,44 +0,0 @@
1
- /**
2
- * Plan Mode Constants
3
- */
4
-
5
- /**
6
- * Commands that require planning mode
7
- */
8
- export const PLAN_REQUIRED_COMMANDS = [
9
- 'feature', // New features need planning
10
- 'spec', // Specs are planning by definition
11
- 'design', // Architecture needs planning
12
- 'refactor', // Refactoring needs impact analysis
13
- 'migrate', // Migrations are high-risk
14
- ]
15
-
16
- /**
17
- * Commands that are destructive and need approval
18
- */
19
- export const DESTRUCTIVE_COMMANDS = [
20
- 'ship', // Commits and pushes
21
- 'cleanup', // Deletes files/code
22
- 'git', // Git operations
23
- 'migrate', // Database/schema changes
24
- ]
25
-
26
- /**
27
- * Read-only tools allowed in planning mode
28
- */
29
- export const PLANNING_TOOLS = ['Read', 'Glob', 'Grep', 'GetTimestamp', 'GetDate', 'GetDateTime']
30
-
31
- /**
32
- * Plan status enum
33
- */
34
- export const PLAN_STATUS = {
35
- GATHERING: 'gathering', // Collecting information
36
- ANALYZING: 'analyzing', // Understanding context
37
- PROPOSING: 'proposing', // Generating plan
38
- PENDING_APPROVAL: 'pending', // Waiting for user
39
- APPROVED: 'approved', // User approved
40
- REJECTED: 'rejected', // User rejected
41
- EXECUTING: 'executing', // Running the plan
42
- COMPLETED: 'completed', // Done
43
- ABORTED: 'aborted', // User stopped mid-execution
44
- }
@@ -1,28 +0,0 @@
1
- /**
2
- * Plan Mode System
3
- *
4
- * P3.4: Plan Mode + Approval Flow
5
- * Separates planning from execution for better user confidence.
6
- *
7
- * Pattern from: Devin AI, Windsurf, Kiro
8
- */
9
-
10
- export type {
11
- PlanParams,
12
- GatheredInfo,
13
- ProposedPlan,
14
- PlanStep,
15
- Plan,
16
- ApprovalPrompt,
17
- ApprovalContext,
18
- } from './types'
19
-
20
- export { PLAN_STATUS, PLAN_REQUIRED_COMMANDS, DESTRUCTIVE_COMMANDS, PLANNING_TOOLS } from './constants'
21
- export { generateApprovalPrompt } from './approval'
22
- export { PlanMode } from './plan-mode'
23
-
24
- import { PlanMode } from './plan-mode'
25
-
26
- // Export singleton
27
- const planMode = new PlanMode()
28
- export default planMode
@@ -1,407 +0,0 @@
1
- /**
2
- * Plan Mode Class
3
- * Core plan management functionality
4
- */
5
-
6
- import type { Plan, PlanParams, GatheredInfo, ProposedPlan, PlanStep, ApprovalContext, ApprovalPrompt } from './types'
7
- import { PLAN_STATUS, PLAN_REQUIRED_COMMANDS, DESTRUCTIVE_COMMANDS, PLANNING_TOOLS } from './constants'
8
- import { generateApprovalPrompt } from './approval'
9
- import { generateUUID } from '../../schemas'
10
-
11
- export class PlanMode {
12
- activePlans: Map<string, Plan>
13
-
14
- constructor() {
15
- this.activePlans = new Map() // projectId -> plan state
16
- }
17
-
18
- /**
19
- * Check if command requires planning mode
20
- */
21
- requiresPlanning(commandName: string): boolean {
22
- return PLAN_REQUIRED_COMMANDS.includes(commandName)
23
- }
24
-
25
- /**
26
- * Check if command is destructive and needs approval
27
- */
28
- isDestructive(commandName: string): boolean {
29
- return DESTRUCTIVE_COMMANDS.includes(commandName)
30
- }
31
-
32
- /**
33
- * Check if tool is allowed in planning mode
34
- */
35
- isToolAllowedInPlanning(toolName: string): boolean {
36
- return PLANNING_TOOLS.includes(toolName)
37
- }
38
-
39
- /**
40
- * Get allowed tools for current mode
41
- */
42
- getAllowedTools(inPlanningMode: boolean, templateTools: string[]): string[] {
43
- if (!inPlanningMode) {
44
- return templateTools
45
- }
46
- // In planning mode, only allow read-only tools
47
- return templateTools.filter((tool) => PLANNING_TOOLS.includes(tool))
48
- }
49
-
50
- /**
51
- * Start planning mode for a command
52
- */
53
- startPlanning(projectId: string, commandName: string, params: PlanParams): Plan {
54
- const plan: Plan = {
55
- id: generateUUID(),
56
- projectId,
57
- command: commandName,
58
- params,
59
- status: PLAN_STATUS.GATHERING,
60
- startedAt: new Date().toISOString(),
61
- gatheredInfo: [],
62
- analysis: null,
63
- proposedPlan: null,
64
- userFeedback: null,
65
- approvedAt: null,
66
- executionStartedAt: null,
67
- completedAt: null,
68
- steps: [],
69
- currentStep: 0,
70
- }
71
-
72
- this.activePlans.set(projectId, plan)
73
- return plan
74
- }
75
-
76
- /**
77
- * Get active plan for project
78
- */
79
- getActivePlan(projectId: string): Plan | null {
80
- return this.activePlans.get(projectId) || null
81
- }
82
-
83
- /**
84
- * Check if project is in planning mode
85
- */
86
- isInPlanningMode(projectId: string): boolean {
87
- const plan = this.getActivePlan(projectId)
88
- if (!plan) return false
89
- return [PLAN_STATUS.GATHERING, PLAN_STATUS.ANALYZING, PLAN_STATUS.PROPOSING, PLAN_STATUS.PENDING_APPROVAL].includes(
90
- plan.status
91
- )
92
- }
93
-
94
- /**
95
- * Record gathered information
96
- */
97
- recordGatheredInfo(projectId: string, info: GatheredInfo): void {
98
- const plan = this.getActivePlan(projectId)
99
- if (!plan) return
100
-
101
- plan.gatheredInfo.push({
102
- ...info,
103
- gatheredAt: new Date().toISOString(),
104
- })
105
- }
106
-
107
- /**
108
- * Update plan status
109
- */
110
- updateStatus(projectId: string, status: string): void {
111
- const plan = this.getActivePlan(projectId)
112
- if (!plan) return
113
-
114
- plan.status = status
115
-
116
- // Track timestamps for key transitions
117
- if (status === PLAN_STATUS.APPROVED) {
118
- plan.approvedAt = new Date().toISOString()
119
- } else if (status === PLAN_STATUS.EXECUTING) {
120
- plan.executionStartedAt = new Date().toISOString()
121
- } else if (status === PLAN_STATUS.COMPLETED || status === PLAN_STATUS.ABORTED) {
122
- plan.completedAt = new Date().toISOString()
123
- }
124
- }
125
-
126
- /**
127
- * Set analysis results
128
- */
129
- setAnalysis(projectId: string, analysis: unknown): void {
130
- const plan = this.getActivePlan(projectId)
131
- if (!plan) return
132
-
133
- plan.analysis = analysis
134
- plan.status = PLAN_STATUS.ANALYZING
135
- }
136
-
137
- /**
138
- * Propose a plan for user approval
139
- */
140
- proposePlan(projectId: string, proposedPlan: ProposedPlan): ReturnType<typeof this.formatPlanForApproval> | null {
141
- const plan = this.getActivePlan(projectId)
142
- if (!plan) return null
143
-
144
- plan.proposedPlan = proposedPlan
145
- plan.status = PLAN_STATUS.PENDING_APPROVAL
146
-
147
- return this.formatPlanForApproval(plan)
148
- }
149
-
150
- /**
151
- * Format plan for user approval display
152
- */
153
- formatPlanForApproval(plan: Plan) {
154
- const proposed = plan.proposedPlan
155
-
156
- return {
157
- summary: proposed?.summary || `Plan for: ${plan.command}`,
158
- approach: proposed?.approach,
159
- steps: proposed?.steps || [],
160
- risks: proposed?.risks || [],
161
- alternatives: proposed?.alternatives || [],
162
- estimatedTime: proposed?.estimatedTime,
163
- affectedFiles: proposed?.affectedFiles || [],
164
- requiresConfirmation: true,
165
- planId: plan.id,
166
- }
167
- }
168
-
169
- /**
170
- * User approves the plan
171
- */
172
- approvePlan(
173
- projectId: string,
174
- feedback: string | null = null
175
- ): { approved: boolean; planId: string; steps: PlanStep[]; message: string } | null {
176
- const plan = this.getActivePlan(projectId)
177
- if (!plan || plan.status !== PLAN_STATUS.PENDING_APPROVAL) {
178
- return null
179
- }
180
-
181
- plan.userFeedback = feedback
182
- plan.status = PLAN_STATUS.APPROVED
183
- plan.approvedAt = new Date().toISOString()
184
-
185
- // Convert proposed plan to executable steps
186
- plan.steps = (plan.proposedPlan?.steps || []).map((step, index) => ({
187
- index,
188
- description: typeof step === 'string' ? step : step.description || '',
189
- status: 'pending' as const,
190
- tool: typeof step === 'string' ? undefined : step.tool,
191
- args: typeof step === 'string' ? undefined : step.args,
192
- }))
193
-
194
- return {
195
- approved: true,
196
- planId: plan.id,
197
- steps: plan.steps,
198
- message: `Plan approved. ${plan.steps.length} steps to execute.`,
199
- }
200
- }
201
-
202
- /**
203
- * User rejects the plan
204
- */
205
- rejectPlan(
206
- projectId: string,
207
- reason: string | null = null
208
- ): { rejected: boolean; planId: string; reason: string | null; message: string } | null {
209
- const plan = this.getActivePlan(projectId)
210
- if (!plan) return null
211
-
212
- plan.status = PLAN_STATUS.REJECTED
213
- plan.userFeedback = reason
214
- plan.completedAt = new Date().toISOString()
215
-
216
- // Clear active plan
217
- this.activePlans.delete(projectId)
218
-
219
- return {
220
- rejected: true,
221
- planId: plan.id,
222
- reason,
223
- message: 'Plan rejected. No changes made.',
224
- }
225
- }
226
-
227
- /**
228
- * Start executing approved plan
229
- */
230
- startExecution(projectId: string): ReturnType<typeof this.getNextStep> {
231
- const plan = this.getActivePlan(projectId)
232
- if (!plan || plan.status !== PLAN_STATUS.APPROVED) {
233
- return null
234
- }
235
-
236
- plan.status = PLAN_STATUS.EXECUTING
237
- plan.executionStartedAt = new Date().toISOString()
238
- plan.currentStep = 0
239
-
240
- return this.getNextStep(projectId)
241
- }
242
-
243
- /**
244
- * Get next step to execute
245
- */
246
- getNextStep(
247
- projectId: string
248
- ): { stepNumber: number; totalSteps: number; step: PlanStep; progress: number } | null {
249
- const plan = this.getActivePlan(projectId)
250
- if (!plan || plan.status !== PLAN_STATUS.EXECUTING) {
251
- return null
252
- }
253
-
254
- const step = plan.steps[plan.currentStep]
255
- if (!step) {
256
- // All steps complete
257
- this.completePlan(projectId)
258
- return null
259
- }
260
-
261
- return {
262
- stepNumber: plan.currentStep + 1,
263
- totalSteps: plan.steps.length,
264
- step,
265
- progress: Math.round((plan.currentStep / plan.steps.length) * 100),
266
- }
267
- }
268
-
269
- /**
270
- * Mark current step as complete
271
- */
272
- completeStep(projectId: string, result: unknown = {}): ReturnType<typeof this.getNextStep> {
273
- const plan = this.getActivePlan(projectId)
274
- if (!plan || plan.status !== PLAN_STATUS.EXECUTING) {
275
- return null
276
- }
277
-
278
- // Update current step
279
- plan.steps[plan.currentStep].status = 'completed'
280
- plan.steps[plan.currentStep].result = result
281
- plan.steps[plan.currentStep].completedAt = new Date().toISOString()
282
-
283
- // Move to next step
284
- plan.currentStep++
285
-
286
- return this.getNextStep(projectId)
287
- }
288
-
289
- /**
290
- * Mark step as failed
291
- */
292
- failStep(projectId: string, error: string): { failed: boolean; step: number; error: string; options: string[] } | null {
293
- const plan = this.getActivePlan(projectId)
294
- if (!plan) return null
295
-
296
- plan.steps[plan.currentStep].status = 'failed'
297
- plan.steps[plan.currentStep].error = error
298
-
299
- return {
300
- failed: true,
301
- step: plan.currentStep + 1,
302
- error,
303
- options: ['retry', 'skip', 'abort'],
304
- }
305
- }
306
-
307
- /**
308
- * Complete the plan
309
- */
310
- completePlan(projectId: string) {
311
- const plan = this.getActivePlan(projectId)
312
- if (!plan) return null
313
-
314
- plan.status = PLAN_STATUS.COMPLETED
315
- plan.completedAt = new Date().toISOString()
316
-
317
- const summary = {
318
- planId: plan.id,
319
- command: plan.command,
320
- totalSteps: plan.steps.length,
321
- completedSteps: plan.steps.filter((s) => s.status === 'completed').length,
322
- failedSteps: plan.steps.filter((s) => s.status === 'failed').length,
323
- duration: this._calculateDuration(plan.executionStartedAt, plan.completedAt),
324
- }
325
-
326
- // Clear active plan
327
- this.activePlans.delete(projectId)
328
-
329
- return summary
330
- }
331
-
332
- /**
333
- * Abort plan execution
334
- */
335
- abortPlan(projectId: string, reason: string = 'User requested') {
336
- const plan = this.getActivePlan(projectId)
337
- if (!plan) return null
338
-
339
- plan.status = PLAN_STATUS.ABORTED
340
- plan.completedAt = new Date().toISOString()
341
- plan.abortReason = reason
342
-
343
- const summary = {
344
- aborted: true,
345
- planId: plan.id,
346
- reason,
347
- completedSteps: plan.steps.filter((s) => s.status === 'completed').length,
348
- totalSteps: plan.steps.length,
349
- }
350
-
351
- // Clear active plan
352
- this.activePlans.delete(projectId)
353
-
354
- return summary
355
- }
356
-
357
- /**
358
- * Generate approval prompt for destructive commands
359
- */
360
- generateApprovalPrompt(commandName: string, context: ApprovalContext): ApprovalPrompt {
361
- return generateApprovalPrompt(commandName, context)
362
- }
363
-
364
- /**
365
- * Format plan status for display
366
- */
367
- formatStatus(projectId: string): string {
368
- const plan = this.getActivePlan(projectId)
369
- if (!plan) return 'No active plan'
370
-
371
- const statusEmoji: Record<string, string> = {
372
- [PLAN_STATUS.GATHERING]: '🔍',
373
- [PLAN_STATUS.ANALYZING]: '🧠',
374
- [PLAN_STATUS.PROPOSING]: '📝',
375
- [PLAN_STATUS.PENDING_APPROVAL]: '⏳',
376
- [PLAN_STATUS.APPROVED]: '✅',
377
- [PLAN_STATUS.EXECUTING]: '⚡',
378
- [PLAN_STATUS.COMPLETED]: '🎉',
379
- [PLAN_STATUS.REJECTED]: '❌',
380
- [PLAN_STATUS.ABORTED]: '🛑',
381
- }
382
-
383
- const lines = [`${statusEmoji[plan.status] || '📋'} Plan: ${plan.command}`, `Status: ${plan.status}`]
384
-
385
- if (plan.status === PLAN_STATUS.EXECUTING) {
386
- const progress = Math.round((plan.currentStep / plan.steps.length) * 100)
387
- lines.push(`Progress: ${plan.currentStep}/${plan.steps.length} (${progress}%)`)
388
- }
389
-
390
- return lines.join('\n')
391
- }
392
-
393
- /**
394
- * Calculate duration between two timestamps
395
- */
396
- private _calculateDuration(start: string | null, end: string | null): string | null {
397
- if (!start || !end) return null
398
- const ms = new Date(end).getTime() - new Date(start).getTime()
399
- const seconds = Math.floor(ms / 1000)
400
- const minutes = Math.floor(seconds / 60)
401
- const hours = Math.floor(minutes / 60)
402
-
403
- if (hours > 0) return `${hours}h ${minutes % 60}m`
404
- if (minutes > 0) return `${minutes}m ${seconds % 60}s`
405
- return `${seconds}s`
406
- }
407
- }
@@ -1,193 +0,0 @@
1
- /**
2
- * Plan Mode Types
3
- *
4
- * Types for the planning system that gathers context,
5
- * proposes plans, and executes approved changes.
6
- */
7
-
8
- import type { CommandParams } from '../../types'
9
-
10
- /**
11
- * Parameters passed to planning mode.
12
- * Extends standard CommandParams with planning-specific options.
13
- */
14
- export interface PlanParams extends CommandParams {
15
- /** Skip approval prompt */
16
- autoApprove?: boolean
17
- /** Verbose output during planning */
18
- verbose?: boolean
19
- }
20
-
21
- /**
22
- * Information gathered during the planning phase.
23
- */
24
- export interface GatheredInfo {
25
- /** Type of information (e.g., 'file_content', 'git_status', 'analysis') */
26
- type: GatheredInfoType
27
- /** Source of the information (e.g., file path, command) */
28
- source: string
29
- /** The gathered data */
30
- data: string | GatheredFileData | GatheredAnalysisData
31
- /** When this info was gathered */
32
- gatheredAt: string
33
- }
34
-
35
- export type GatheredInfoType =
36
- | 'file_content'
37
- | 'git_status'
38
- | 'git_diff'
39
- | 'analysis'
40
- | 'dependencies'
41
- | 'structure'
42
-
43
- export interface GatheredFileData {
44
- path: string
45
- content: string
46
- lines: number
47
- }
48
-
49
- export interface GatheredAnalysisData {
50
- summary: string
51
- findings: string[]
52
- }
53
-
54
- /**
55
- * A proposed plan for executing changes.
56
- */
57
- export interface ProposedPlan {
58
- /** Brief summary of what will be done */
59
- summary: string
60
- /** Detailed approach explanation */
61
- approach: string
62
- /** Steps to execute */
63
- steps: PlanStepDefinition[]
64
- /** Potential risks */
65
- risks?: string[]
66
- /** Alternative approaches considered */
67
- alternatives?: string[]
68
- /** Estimated time to complete */
69
- estimatedTime?: string
70
- /** Files that will be modified */
71
- affectedFiles: string[]
72
- }
73
-
74
- export interface PlanStepDefinition {
75
- /** Step description */
76
- description: string
77
- /** Tool to use (if any) */
78
- tool?: string
79
- /** Arguments for the tool */
80
- args?: string[]
81
- }
82
-
83
- /**
84
- * A step in the plan with execution status.
85
- */
86
- export interface PlanStep {
87
- index: number
88
- description: string
89
- status: 'pending' | 'completed' | 'failed'
90
- tool?: string
91
- args?: string[]
92
- result?: PlanStepResult
93
- completedAt?: string
94
- error?: string
95
- }
96
-
97
- export interface PlanStepResult {
98
- success: boolean
99
- output?: string
100
- filesModified?: string[]
101
- }
102
-
103
- /**
104
- * Plan status values.
105
- */
106
- export type PlanStatus =
107
- | 'gathering'
108
- | 'analyzing'
109
- | 'proposing'
110
- | 'awaiting_approval'
111
- | 'executing'
112
- | 'completed'
113
- | 'aborted'
114
-
115
- /**
116
- * A complete plan instance.
117
- */
118
- export interface Plan {
119
- id: string
120
- projectId: string
121
- command: string
122
- params: PlanParams
123
- status: PlanStatus
124
- startedAt: string
125
- gatheredInfo: GatheredInfo[]
126
- analysis: PlanAnalysis | null
127
- proposedPlan: ProposedPlan | null
128
- userFeedback: string | null
129
- approvedAt: string | null
130
- executionStartedAt: string | null
131
- completedAt: string | null
132
- steps: PlanStep[]
133
- currentStep: number
134
- abortReason?: string
135
- }
136
-
137
- export interface PlanAnalysis {
138
- complexity: 'low' | 'medium' | 'high'
139
- riskLevel: 'low' | 'medium' | 'high'
140
- estimatedDuration: string
141
- dependencies: string[]
142
- }
143
-
144
- /**
145
- * Prompt shown to user for approval.
146
- */
147
- export interface ApprovalPrompt {
148
- title: string
149
- message: string
150
- details?: string[]
151
- options: ApprovalOption[]
152
- }
153
-
154
- export interface ApprovalOption {
155
- key: string
156
- label: string
157
- action: 'approve' | 'reject' | 'modify' | 'abort'
158
- }
159
-
160
- /**
161
- * Context for approval decisions.
162
- */
163
- export interface ApprovalContext {
164
- /** Current git branch */
165
- branch?: string
166
- /** Files that will be changed */
167
- changedFiles: ChangedFile[]
168
- /** Proposed commit message */
169
- commitMessage?: string
170
- /** Files that will be deleted */
171
- filesToDelete: string[]
172
- /** Total lines of code affected */
173
- linesOfCode?: number
174
- /** Type of operation */
175
- operation: ApprovalOperation
176
- /** Warnings to show user */
177
- warnings: string[]
178
- }
179
-
180
- export interface ChangedFile {
181
- path: string
182
- action: 'create' | 'modify' | 'delete'
183
- linesAdded?: number
184
- linesRemoved?: number
185
- }
186
-
187
- export type ApprovalOperation =
188
- | 'create_files'
189
- | 'modify_files'
190
- | 'delete_files'
191
- | 'git_commit'
192
- | 'git_push'
193
- | 'run_command'