prjct-cli 0.44.1 → 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.
Files changed (207) hide show
  1. package/CHANGELOG.md +114 -0
  2. package/bin/prjct.ts +131 -10
  3. package/core/__tests__/agentic/memory-system.test.ts +39 -26
  4. package/core/__tests__/agentic/plan-mode.test.ts +64 -46
  5. package/core/__tests__/agentic/prompt-builder.test.ts +14 -14
  6. package/core/__tests__/services/project-index.test.ts +353 -0
  7. package/core/__tests__/types/fs.test.ts +3 -3
  8. package/core/__tests__/utils/date-helper.test.ts +10 -10
  9. package/core/__tests__/utils/output.test.ts +9 -6
  10. package/core/__tests__/utils/project-commands.test.ts +5 -6
  11. package/core/agentic/agent-router.ts +9 -10
  12. package/core/agentic/chain-of-thought.ts +16 -4
  13. package/core/agentic/command-executor.ts +66 -40
  14. package/core/agentic/context-builder.ts +8 -5
  15. package/core/agentic/ground-truth.ts +15 -9
  16. package/core/agentic/index.ts +145 -152
  17. package/core/agentic/loop-detector.ts +40 -11
  18. package/core/agentic/memory-system.ts +98 -35
  19. package/core/agentic/orchestrator-executor.ts +135 -71
  20. package/core/agentic/plan-mode.ts +46 -16
  21. package/core/agentic/prompt-builder.ts +108 -42
  22. package/core/agentic/services.ts +10 -9
  23. package/core/agentic/skill-loader.ts +9 -15
  24. package/core/agentic/smart-context.ts +129 -79
  25. package/core/agentic/template-executor.ts +13 -12
  26. package/core/agentic/template-loader.ts +7 -4
  27. package/core/agentic/tool-registry.ts +16 -13
  28. package/core/agents/index.ts +1 -1
  29. package/core/agents/performance.ts +10 -27
  30. package/core/ai-tools/formatters.ts +8 -6
  31. package/core/ai-tools/generator.ts +4 -4
  32. package/core/ai-tools/index.ts +1 -1
  33. package/core/ai-tools/registry.ts +21 -11
  34. package/core/bus/bus.ts +23 -16
  35. package/core/bus/index.ts +2 -2
  36. package/core/cli/linear.ts +3 -5
  37. package/core/cli/start.ts +28 -25
  38. package/core/commands/analysis.ts +287 -29
  39. package/core/commands/analytics.ts +52 -44
  40. package/core/commands/base.ts +15 -13
  41. package/core/commands/cleanup.ts +6 -13
  42. package/core/commands/command-data.ts +49 -8
  43. package/core/commands/commands.ts +60 -23
  44. package/core/commands/context.ts +4 -4
  45. package/core/commands/design.ts +3 -10
  46. package/core/commands/index.ts +5 -8
  47. package/core/commands/maintenance.ts +7 -4
  48. package/core/commands/planning.ts +179 -56
  49. package/core/commands/register.ts +14 -9
  50. package/core/commands/registry.ts +15 -14
  51. package/core/commands/setup.ts +26 -14
  52. package/core/commands/shipping.ts +11 -16
  53. package/core/commands/snapshots.ts +16 -32
  54. package/core/commands/uninstall.ts +541 -0
  55. package/core/commands/workflow.ts +24 -28
  56. package/core/constants/index.ts +10 -22
  57. package/core/context/generator.ts +82 -33
  58. package/core/context-tools/files-tool.ts +583 -0
  59. package/core/context-tools/imports-tool.ts +403 -0
  60. package/core/context-tools/index.ts +433 -0
  61. package/core/context-tools/recent-tool.ts +307 -0
  62. package/core/context-tools/signatures-tool.ts +501 -0
  63. package/core/context-tools/summary-tool.ts +307 -0
  64. package/core/context-tools/token-counter.ts +284 -0
  65. package/core/context-tools/types.ts +253 -0
  66. package/core/domain/agent-generator.ts +7 -5
  67. package/core/domain/agent-loader.ts +2 -2
  68. package/core/domain/analyzer.ts +19 -16
  69. package/core/domain/architecture-generator.ts +6 -3
  70. package/core/domain/context-estimator.ts +3 -4
  71. package/core/domain/snapshot-manager.ts +25 -22
  72. package/core/domain/task-stack.ts +24 -14
  73. package/core/errors.ts +1 -1
  74. package/core/events/events.ts +2 -4
  75. package/core/events/index.ts +1 -2
  76. package/core/index.ts +28 -12
  77. package/core/infrastructure/agent-detector.ts +3 -3
  78. package/core/infrastructure/ai-provider.ts +23 -20
  79. package/core/infrastructure/author-detector.ts +16 -10
  80. package/core/infrastructure/capability-installer.ts +2 -2
  81. package/core/infrastructure/claude-agent.ts +6 -6
  82. package/core/infrastructure/command-installer.ts +22 -17
  83. package/core/infrastructure/config-manager.ts +18 -14
  84. package/core/infrastructure/editors-config.ts +8 -4
  85. package/core/infrastructure/path-manager.ts +8 -6
  86. package/core/infrastructure/permission-manager.ts +20 -17
  87. package/core/infrastructure/setup.ts +42 -38
  88. package/core/infrastructure/update-checker.ts +5 -5
  89. package/core/integrations/issue-tracker/enricher.ts +8 -19
  90. package/core/integrations/issue-tracker/index.ts +2 -2
  91. package/core/integrations/issue-tracker/manager.ts +15 -15
  92. package/core/integrations/issue-tracker/types.ts +5 -22
  93. package/core/integrations/jira/client.ts +67 -59
  94. package/core/integrations/jira/index.ts +11 -14
  95. package/core/integrations/jira/mcp-adapter.ts +5 -10
  96. package/core/integrations/jira/service.ts +10 -10
  97. package/core/integrations/linear/client.ts +27 -18
  98. package/core/integrations/linear/index.ts +9 -12
  99. package/core/integrations/linear/service.ts +11 -11
  100. package/core/integrations/linear/sync.ts +8 -8
  101. package/core/outcomes/analyzer.ts +5 -18
  102. package/core/outcomes/index.ts +2 -2
  103. package/core/outcomes/recorder.ts +3 -3
  104. package/core/plugin/builtin/webhook.ts +19 -15
  105. package/core/plugin/hooks.ts +29 -21
  106. package/core/plugin/index.ts +7 -7
  107. package/core/plugin/loader.ts +19 -19
  108. package/core/plugin/registry.ts +12 -23
  109. package/core/schemas/agents.ts +1 -1
  110. package/core/schemas/analysis.ts +1 -1
  111. package/core/schemas/enriched-task.ts +62 -49
  112. package/core/schemas/ideas.ts +13 -13
  113. package/core/schemas/index.ts +17 -27
  114. package/core/schemas/issues.ts +40 -25
  115. package/core/schemas/metrics.ts +143 -0
  116. package/core/schemas/outcomes.ts +70 -62
  117. package/core/schemas/permissions.ts +15 -12
  118. package/core/schemas/prd.ts +27 -14
  119. package/core/schemas/project.ts +3 -3
  120. package/core/schemas/roadmap.ts +47 -34
  121. package/core/schemas/schemas.ts +3 -4
  122. package/core/schemas/shipped.ts +3 -3
  123. package/core/schemas/state.ts +43 -29
  124. package/core/server/index.ts +5 -6
  125. package/core/server/routes-extended.ts +68 -72
  126. package/core/server/routes.ts +3 -3
  127. package/core/server/server.ts +31 -26
  128. package/core/services/agent-generator.ts +237 -0
  129. package/core/services/agent-service.ts +2 -2
  130. package/core/services/breakdown-service.ts +2 -4
  131. package/core/services/context-generator.ts +299 -0
  132. package/core/services/context-selector.ts +420 -0
  133. package/core/services/doctor-service.ts +426 -0
  134. package/core/services/file-categorizer.ts +448 -0
  135. package/core/services/file-scorer.ts +270 -0
  136. package/core/services/git-analyzer.ts +267 -0
  137. package/core/services/index.ts +27 -10
  138. package/core/services/memory-service.ts +3 -4
  139. package/core/services/project-index.ts +911 -0
  140. package/core/services/project-service.ts +4 -4
  141. package/core/services/skill-installer.ts +14 -17
  142. package/core/services/skill-lock.ts +3 -3
  143. package/core/services/skill-service.ts +12 -6
  144. package/core/services/stack-detector.ts +245 -0
  145. package/core/services/sync-service.ts +170 -329
  146. package/core/services/watch-service.ts +294 -0
  147. package/core/session/compaction.ts +23 -31
  148. package/core/session/index.ts +11 -5
  149. package/core/session/log-migration.ts +3 -3
  150. package/core/session/metrics.ts +19 -14
  151. package/core/session/session-log-manager.ts +12 -17
  152. package/core/session/task-session-manager.ts +25 -25
  153. package/core/session/utils.ts +1 -1
  154. package/core/storage/ideas-storage.ts +41 -57
  155. package/core/storage/index-storage.ts +514 -0
  156. package/core/storage/index.ts +41 -13
  157. package/core/storage/metrics-storage.ts +320 -0
  158. package/core/storage/queue-storage.ts +35 -45
  159. package/core/storage/shipped-storage.ts +17 -20
  160. package/core/storage/state-storage.ts +50 -30
  161. package/core/storage/storage-manager.ts +6 -6
  162. package/core/storage/storage.ts +18 -15
  163. package/core/sync/auth-config.ts +3 -3
  164. package/core/sync/index.ts +13 -19
  165. package/core/sync/oauth-handler.ts +3 -3
  166. package/core/sync/sync-client.ts +4 -9
  167. package/core/sync/sync-manager.ts +12 -14
  168. package/core/types/commands.ts +42 -7
  169. package/core/types/index.ts +284 -302
  170. package/core/types/integrations.ts +3 -3
  171. package/core/types/storage.ts +49 -0
  172. package/core/types/utils.ts +3 -3
  173. package/core/utils/agent-stream.ts +3 -1
  174. package/core/utils/animations.ts +14 -11
  175. package/core/utils/branding.ts +7 -7
  176. package/core/utils/cache.ts +1 -3
  177. package/core/utils/collection-filters.ts +3 -15
  178. package/core/utils/date-helper.ts +2 -7
  179. package/core/utils/file-helper.ts +13 -8
  180. package/core/utils/jsonl-helper.ts +13 -10
  181. package/core/utils/keychain.ts +4 -8
  182. package/core/utils/logger.ts +1 -1
  183. package/core/utils/next-steps.ts +3 -3
  184. package/core/utils/output.ts +58 -11
  185. package/core/utils/project-commands.ts +6 -6
  186. package/core/utils/project-credentials.ts +5 -12
  187. package/core/utils/runtime.ts +2 -2
  188. package/core/utils/session-helper.ts +3 -4
  189. package/core/utils/version.ts +3 -3
  190. package/core/wizard/index.ts +13 -0
  191. package/core/wizard/onboarding.ts +633 -0
  192. package/core/workflow/state-machine.ts +7 -7
  193. package/dist/bin/prjct.mjs +18907 -13189
  194. package/dist/core/infrastructure/command-installer.js +96 -111
  195. package/dist/core/infrastructure/editors-config.js +6 -6
  196. package/dist/core/infrastructure/setup.js +256 -257
  197. package/dist/core/utils/version.js +9 -9
  198. package/package.json +11 -12
  199. package/scripts/build.js +3 -3
  200. package/scripts/postinstall.js +2 -2
  201. package/templates/mcp-config.json +6 -1
  202. package/templates/permissions/permissive.jsonc +1 -1
  203. package/templates/permissions/strict.jsonc +5 -9
  204. package/templates/global/docs/agents.md +0 -88
  205. package/templates/global/docs/architecture.md +0 -103
  206. package/templates/global/docs/commands.md +0 -96
  207. package/templates/global/docs/validation.md +0 -95
@@ -9,12 +9,12 @@
9
9
  * @version 1.0.0
10
10
  */
11
11
 
12
- import fs from 'fs/promises'
13
- import path from 'path'
14
- import { hookSystem } from './hooks'
15
- import { eventBus, type EventCallback } from '../bus'
12
+ import fs from 'node:fs/promises'
13
+ import path from 'node:path'
14
+ import { type EventCallback, eventBus } from '../bus'
16
15
  import pathManager from '../infrastructure/path-manager'
17
16
  import { isNotFoundError } from '../types/fs'
17
+ import { hookSystem } from './hooks'
18
18
 
19
19
  type PluginSource = 'builtin' | 'global' | 'project'
20
20
  type HookHandler = (data: unknown) => unknown | Promise<unknown>
@@ -118,9 +118,10 @@ class PluginLoader {
118
118
  for (const file of files) {
119
119
  const filePath = path.join(globalPath, file)
120
120
  if (file.endsWith('.js') || file.endsWith('.ts') || (await this.isDirectory(filePath))) {
121
- const pluginPath = (file.endsWith('.js') || file.endsWith('.ts'))
122
- ? filePath
123
- : path.join(filePath, 'index.js')
121
+ const pluginPath =
122
+ file.endsWith('.js') || file.endsWith('.ts')
123
+ ? filePath
124
+ : path.join(filePath, 'index.js')
124
125
  await this.loadPlugin(pluginPath, 'global')
125
126
  }
126
127
  }
@@ -169,7 +170,11 @@ class PluginLoader {
169
170
  /**
170
171
  * Load a single plugin
171
172
  */
172
- async loadPlugin(pluginPath: string, source: PluginSource, config: Record<string, unknown> = {}): Promise<void> {
173
+ async loadPlugin(
174
+ pluginPath: string,
175
+ source: PluginSource,
176
+ config: Record<string, unknown> = {}
177
+ ): Promise<void> {
173
178
  try {
174
179
  // Check if file exists
175
180
  await fs.access(pluginPath)
@@ -192,7 +197,7 @@ class PluginLoader {
192
197
  this.plugins.set(plugin.name, {
193
198
  ...plugin,
194
199
  source,
195
- config: { ...config, ...(this.config[plugin.name] as Record<string, unknown> || {}) }
200
+ config: { ...config, ...((this.config[plugin.name] as Record<string, unknown>) || {}) },
196
201
  })
197
202
  this.pluginPaths.set(plugin.name, pluginPath)
198
203
 
@@ -212,10 +217,9 @@ class PluginLoader {
212
217
  config: this.plugins.get(plugin.name)!.config!,
213
218
  eventBus,
214
219
  hookSystem,
215
- projectPath: this.projectPath
220
+ projectPath: this.projectPath,
216
221
  })
217
222
  }
218
-
219
223
  } catch (error) {
220
224
  const err = error as NodeJS.ErrnoException
221
225
  if (err.code === 'ENOENT') {
@@ -235,7 +239,7 @@ class PluginLoader {
235
239
  for (const [hookPoint, handler] of Object.entries(plugin.hooks || {})) {
236
240
  hookSystem.register(hookPoint, handler, {
237
241
  pluginName: plugin.name,
238
- priority: plugin.priority || 10
242
+ priority: plugin.priority || 10,
239
243
  })
240
244
  }
241
245
  }
@@ -304,7 +308,7 @@ class PluginLoader {
304
308
  * Get plugins by source
305
309
  */
306
310
  getPluginsBySource(source: PluginSource): Plugin[] {
307
- return this.getAllPlugins().filter(p => p.source === source)
311
+ return this.getAllPlugins().filter((p) => p.source === source)
308
312
  }
309
313
 
310
314
  /**
@@ -319,7 +323,7 @@ class PluginLoader {
319
323
  commands[name] = {
320
324
  handler: handler.handler,
321
325
  plugin: plugin.name,
322
- description: handler.description || `Command from ${plugin.name}`
326
+ description: handler.description || `Command from ${plugin.name}`,
323
327
  }
324
328
  }
325
329
  }
@@ -347,10 +351,6 @@ class PluginLoader {
347
351
  // Singleton instance
348
352
  const pluginLoader = new PluginLoader()
349
353
 
350
- export {
351
- PluginLoader,
352
- pluginLoader,
353
- Plugin
354
- }
354
+ export { PluginLoader, pluginLoader, type Plugin }
355
355
 
356
356
  export default { PluginLoader, pluginLoader }
@@ -6,11 +6,11 @@
6
6
  * @version 1.0.0
7
7
  */
8
8
 
9
- import fs from 'fs/promises'
10
- import path from 'path'
9
+ import fs from 'node:fs/promises'
10
+ import path from 'node:path'
11
11
  import pathManager from '../infrastructure/path-manager'
12
- import { pluginLoader } from './loader'
13
12
  import { isNotFoundError } from '../types/fs'
13
+ import { pluginLoader } from './loader'
14
14
 
15
15
  type PluginSource = 'builtin' | 'global' | 'project'
16
16
 
@@ -51,16 +51,10 @@ class PluginRegistry {
51
51
  */
52
52
  async discoverPlugins(): Promise<void> {
53
53
  // Built-in plugins
54
- await this.discoverFromPath(
55
- path.join(__dirname, '..', 'plugins'),
56
- 'builtin'
57
- )
54
+ await this.discoverFromPath(path.join(__dirname, '..', 'plugins'), 'builtin')
58
55
 
59
56
  // Global plugins
60
- await this.discoverFromPath(
61
- path.join(pathManager.getGlobalBasePath(), 'plugins'),
62
- 'global'
63
- )
57
+ await this.discoverFromPath(path.join(pathManager.getGlobalBasePath(), 'plugins'), 'global')
64
58
  }
65
59
 
66
60
  /**
@@ -91,7 +85,7 @@ class PluginRegistry {
91
85
  this.availablePlugins.set(metadata.name, {
92
86
  ...metadata,
93
87
  path: pluginPath,
94
- source
88
+ source,
95
89
  })
96
90
  }
97
91
  } catch (error) {
@@ -125,7 +119,7 @@ class PluginRegistry {
125
119
  return {
126
120
  name: nameMatch[1],
127
121
  version: versionMatch ? versionMatch[1] : '1.0.0',
128
- description: descMatch ? descMatch[1] : ''
122
+ description: descMatch ? descMatch[1] : '',
129
123
  }
130
124
  }
131
125
 
@@ -137,7 +131,7 @@ class PluginRegistry {
137
131
  return {
138
132
  name: plugin.name,
139
133
  version: plugin.version || '1.0.0',
140
- description: plugin.description || ''
134
+ description: plugin.description || '',
141
135
  }
142
136
  }
143
137
  } catch (error) {
@@ -161,7 +155,7 @@ class PluginRegistry {
161
155
  * Get available plugins by source
162
156
  */
163
157
  getAvailableBySource(source: PluginSource): PluginMetadata[] {
164
- return this.getAvailable().filter(p => p.source === source)
158
+ return this.getAvailable().filter((p) => p.source === source)
165
159
  }
166
160
 
167
161
  /**
@@ -190,7 +184,7 @@ class PluginRegistry {
190
184
  return {
191
185
  ...(available || { name, version: '1.0.0', description: '' }),
192
186
  loaded: !!loaded,
193
- active: loaded ? true : false
187
+ active: !!loaded,
194
188
  }
195
189
  }
196
190
 
@@ -287,7 +281,7 @@ class PluginRegistry {
287
281
  const bySource: Record<PluginSource, PluginMetadata[]> = {
288
282
  builtin: [],
289
283
  global: [],
290
- project: []
284
+ project: [],
291
285
  }
292
286
 
293
287
  for (const plugin of available) {
@@ -329,11 +323,6 @@ class PluginRegistry {
329
323
  // Singleton instance
330
324
  const pluginRegistry = new PluginRegistry()
331
325
 
332
- export {
333
- PluginRegistry,
334
- pluginRegistry,
335
- PluginMetadata,
336
- PluginInfo
337
- }
326
+ export { PluginRegistry, pluginRegistry, type PluginMetadata, type PluginInfo }
338
327
 
339
328
  export default { PluginRegistry, pluginRegistry }
@@ -23,5 +23,5 @@ export const DEFAULT_AGENT: Omit<AgentSchema, 'name' | 'description'> = {
23
23
  patterns: [],
24
24
  filesOwned: [],
25
25
  bestFor: [],
26
- avoidFor: []
26
+ avoidFor: [],
27
27
  }
@@ -37,5 +37,5 @@ export const DEFAULT_ANALYSIS: Omit<AnalysisSchema, 'projectId'> = {
37
37
  fileCount: 0,
38
38
  patterns: [],
39
39
  antiPatterns: [],
40
- analyzedAt: new Date().toISOString()
40
+ analyzedAt: new Date().toISOString(),
41
41
  }
@@ -19,20 +19,14 @@ export const TaskTypeSchema = z.enum([
19
19
  'epic',
20
20
  ])
21
21
 
22
- export const PrioritySchema = z.enum([
23
- 'critical',
24
- 'high',
25
- 'medium',
26
- 'low',
27
- 'none',
28
- ])
22
+ export const PrioritySchema = z.enum(['critical', 'high', 'medium', 'low', 'none'])
29
23
 
30
24
  export const ComplexitySchema = z.enum([
31
- 'trivial', // < 1 hour
32
- 'small', // 1-4 hours
33
- 'medium', // 1-2 days
34
- 'large', // 3-5 days
35
- 'epic', // > 1 week
25
+ 'trivial', // < 1 hour
26
+ 'small', // 1-4 hours
27
+ 'medium', // 1-2 days
28
+ 'large', // 3-5 days
29
+ 'epic', // > 1 week
36
30
  ])
37
31
 
38
32
  export const RiskLevelSchema = z.enum(['none', 'low', 'medium', 'high', 'critical'])
@@ -45,7 +39,9 @@ export const UserStorySchema = z.object({
45
39
  role: z.string().describe('The user role (e.g., "mobile user")'),
46
40
  action: z.string().describe('What the user wants to do'),
47
41
  benefit: z.string().describe('The benefit they get'),
48
- formatted: z.string().describe('Formatted user story: "As a [role], I want [action] so that [benefit]"'),
42
+ formatted: z
43
+ .string()
44
+ .describe('Formatted user story: "As a [role], I want [action] so that [benefit]"'),
49
45
  })
50
46
 
51
47
  // =============================================================================
@@ -91,11 +87,15 @@ export const DependenciesSchema = z.object({
91
87
  code: z.array(CodeDependencySchema).default([]),
92
88
  api: z.array(ApiDependencySchema).default([]),
93
89
  tasks: z.array(TaskDependencySchema).default([]),
94
- infrastructure: z.array(z.object({
95
- service: z.string(),
96
- purpose: z.string(),
97
- risk: RiskLevelSchema,
98
- })).default([]),
90
+ infrastructure: z
91
+ .array(
92
+ z.object({
93
+ service: z.string(),
94
+ purpose: z.string(),
95
+ risk: RiskLevelSchema,
96
+ })
97
+ )
98
+ .default([]),
99
99
  })
100
100
 
101
101
  // =============================================================================
@@ -103,31 +103,45 @@ export const DependenciesSchema = z.object({
103
103
  // =============================================================================
104
104
 
105
105
  export const TechnicalAnalysisSchema = z.object({
106
- affectedFiles: z.array(z.object({
107
- path: z.string(),
108
- changes: z.string().describe('Expected changes'),
109
- complexity: ComplexitySchema,
110
- })).default([]),
111
-
112
- existingPatterns: z.array(z.object({
113
- pattern: z.string().describe('Pattern name'),
114
- file: z.string().describe('Reference file'),
115
- relevance: z.string().describe('Why it is relevant'),
116
- })).default([]),
106
+ affectedFiles: z
107
+ .array(
108
+ z.object({
109
+ path: z.string(),
110
+ changes: z.string().describe('Expected changes'),
111
+ complexity: ComplexitySchema,
112
+ })
113
+ )
114
+ .default([]),
115
+
116
+ existingPatterns: z
117
+ .array(
118
+ z.object({
119
+ pattern: z.string().describe('Pattern name'),
120
+ file: z.string().describe('Reference file'),
121
+ relevance: z.string().describe('Why it is relevant'),
122
+ })
123
+ )
124
+ .default([]),
117
125
 
118
126
  suggestedApproach: z.string().optional().describe('Recommended approach'),
119
127
 
120
- potentialRisks: z.array(z.object({
121
- risk: z.string(),
122
- mitigation: z.string(),
123
- severity: RiskLevelSchema,
124
- })).default([]),
125
-
126
- testingStrategy: z.object({
127
- unit: z.array(z.string()).default([]),
128
- integration: z.array(z.string()).default([]),
129
- e2e: z.array(z.string()).default([]),
130
- }).optional(),
128
+ potentialRisks: z
129
+ .array(
130
+ z.object({
131
+ risk: z.string(),
132
+ mitigation: z.string(),
133
+ severity: RiskLevelSchema,
134
+ })
135
+ )
136
+ .default([]),
137
+
138
+ testingStrategy: z
139
+ .object({
140
+ unit: z.array(z.string()).default([]),
141
+ integration: z.array(z.string()).default([]),
142
+ e2e: z.array(z.string()).default([]),
143
+ })
144
+ .optional(),
131
145
  })
132
146
 
133
147
  // =============================================================================
@@ -174,12 +188,9 @@ export const EnrichedTaskSchema = z.object({
174
188
  // Enrichment
175
189
  userStory: UserStorySchema,
176
190
  acceptanceCriteria: z.array(AcceptanceCriterionSchema).min(1),
177
- definitionOfDone: z.array(z.string()).default([
178
- 'Code reviewed',
179
- 'Tests pass',
180
- 'Documentation updated',
181
- 'Deployed to staging',
182
- ]),
191
+ definitionOfDone: z
192
+ .array(z.string())
193
+ .default(['Code reviewed', 'Tests pass', 'Documentation updated', 'Deployed to staging']),
183
194
 
184
195
  // Technical analysis
185
196
  technicalAnalysis: TechnicalAnalysisSchema,
@@ -241,13 +252,15 @@ export function isReadyForDev(task: EnrichedTask): { ready: boolean; reasons: st
241
252
  }
242
253
 
243
254
  // Check blockers
244
- const blockingDeps = task.dependencies.tasks.filter(t => t.blocking)
255
+ const blockingDeps = task.dependencies.tasks.filter((t) => t.blocking)
245
256
  if (blockingDeps.length > 0) {
246
- reasons.push(`Blocked by: ${blockingDeps.map(t => t.id).join(', ')}`)
257
+ reasons.push(`Blocked by: ${blockingDeps.map((t) => t.id).join(', ')}`)
247
258
  }
248
259
 
249
260
  // Check critical risks
250
- const criticalRisks = task.technicalAnalysis.potentialRisks.filter(r => r.severity === 'critical')
261
+ const criticalRisks = task.technicalAnalysis.potentialRisks.filter(
262
+ (r) => r.severity === 'critical'
263
+ )
251
264
  if (criticalRisks.length > 0) {
252
265
  reasons.push('Has unmitigated critical risks')
253
266
  }
@@ -23,32 +23,32 @@ export const ImpactEffortSchema = z.object({
23
23
  })
24
24
 
25
25
  export const TechStackSchema = z.object({
26
- frontend: z.string().optional(), // "Next.js 14, HeroUI"
27
- backend: z.string().optional(), // "Supabase (Auth, DB, RLS, Realtime)"
28
- payments: z.string().optional(), // "Stripe Billing"
29
- ai: z.string().optional(), // "Vercel AI SDK"
30
- deploy: z.string().optional(), // "Vercel"
26
+ frontend: z.string().optional(), // "Next.js 14, HeroUI"
27
+ backend: z.string().optional(), // "Supabase (Auth, DB, RLS, Realtime)"
28
+ payments: z.string().optional(), // "Stripe Billing"
29
+ ai: z.string().optional(), // "Vercel AI SDK"
30
+ deploy: z.string().optional(), // "Vercel"
31
31
  other: z.array(z.string()).optional(),
32
32
  })
33
33
 
34
34
  export const IdeaModuleSchema = z.object({
35
- name: z.string(), // "Multi-tenant"
36
- description: z.string(), // "Empresas con RLS estricto"
35
+ name: z.string(), // "Multi-tenant"
36
+ description: z.string(), // "Empresas con RLS estricto"
37
37
  })
38
38
 
39
39
  export const IdeaRoleSchema = z.object({
40
- name: z.string(), // "SUPER_ADMIN"
40
+ name: z.string(), // "SUPER_ADMIN"
41
41
  description: z.string().optional(),
42
42
  })
43
43
 
44
44
  export const IdeaItemSchema = z.object({
45
- id: z.string(), // idea_xxxxxxxx
46
- text: z.string(), // Title/summary
45
+ id: z.string(), // idea_xxxxxxxx
46
+ text: z.string(), // Title/summary
47
47
  details: z.string().optional(),
48
48
  priority: IdeaPrioritySchema,
49
49
  status: IdeaStatusSchema,
50
50
  tags: z.array(z.string()),
51
- addedAt: z.string(), // ISO8601
51
+ addedAt: z.string(), // ISO8601
52
52
  completedAt: z.string().optional(),
53
53
  convertedTo: z.string().optional(),
54
54
  // Source documentation
@@ -105,10 +105,10 @@ export const DEFAULT_IDEA: Omit<IdeaSchema, 'id' | 'text'> = {
105
105
  priority: 'medium',
106
106
  status: 'pending',
107
107
  tags: [],
108
- addedAt: new Date().toISOString()
108
+ addedAt: new Date().toISOString(),
109
109
  }
110
110
 
111
111
  export const DEFAULT_IDEAS: IdeasJson = {
112
112
  ideas: [],
113
- lastUpdated: ''
113
+ lastUpdated: '',
114
114
  }
@@ -12,44 +12,34 @@
12
12
  * - memory/ (context.jsonl, patterns.json)
13
13
  */
14
14
 
15
- // State (current task + queue)
16
- export * from './state'
17
-
18
- // Issues (local cache of issue tracker issues)
19
- export * from './issues'
20
-
21
- // Project metadata
22
- export * from './project'
23
-
24
15
  // Agents
25
16
  export * from './agents'
26
-
27
- // Ideas
28
- export * from './ideas'
29
-
30
- // Roadmap (features)
31
- export * from './roadmap'
32
-
33
- // Shipped items
34
- export * from './shipped'
35
-
36
17
  // Analysis
37
18
  export * from './analysis'
38
-
19
+ // Ideas
20
+ export * from './ideas'
21
+ // Issues (local cache of issue tracker issues)
22
+ export * from './issues'
39
23
  // Outcomes
40
24
  export * from './outcomes'
41
-
42
25
  // Permissions
43
26
  export * from './permissions'
44
-
27
+ // Project metadata
28
+ export * from './project'
29
+ // Roadmap (features)
30
+ export * from './roadmap'
45
31
  // Utilities (ID generators and path helpers)
46
32
  export {
47
- generateUUID,
48
- generateTaskId,
33
+ GLOBAL_STORAGE,
49
34
  generateFeatureId,
50
35
  generateIdeaId,
51
- generateShipId,
52
36
  generateSessionId,
53
- GLOBAL_STORAGE,
54
- getProjectPath
37
+ generateShipId,
38
+ generateTaskId,
39
+ generateUUID,
40
+ getProjectPath,
55
41
  } from './schemas'
42
+ // Shipped items
43
+ export * from './shipped'
44
+ // State (current task + queue)
45
+ export * from './state'
@@ -14,7 +14,14 @@ import { z } from 'zod'
14
14
  // =============================================================================
15
15
 
16
16
  export const IssueProviderSchema = z.enum(['linear', 'jira', 'github', 'monday', 'asana', 'none'])
17
- export const IssueStatusSchema = z.enum(['backlog', 'todo', 'in_progress', 'in_review', 'done', 'cancelled'])
17
+ export const IssueStatusSchema = z.enum([
18
+ 'backlog',
19
+ 'todo',
20
+ 'in_progress',
21
+ 'in_review',
22
+ 'done',
23
+ 'cancelled',
24
+ ])
18
25
  export const IssuePrioritySchema = z.enum(['none', 'urgent', 'high', 'medium', 'low'])
19
26
  export const IssueTypeSchema = z.enum(['feature', 'bug', 'improvement', 'task', 'chore', 'epic'])
20
27
 
@@ -27,8 +34,8 @@ export const IssueTypeSchema = z.enum(['feature', 'bug', 'improvement', 'task',
27
34
  */
28
35
  export const CachedIssueSchema = z.object({
29
36
  // Core identifiers
30
- id: z.string(), // Provider UUID
31
- identifier: z.string(), // Human-readable ID (e.g., "PRJ-123")
37
+ id: z.string(), // Provider UUID
38
+ identifier: z.string(), // Human-readable ID (e.g., "PRJ-123")
32
39
 
33
40
  // Issue content
34
41
  title: z.string(),
@@ -40,27 +47,33 @@ export const CachedIssueSchema = z.object({
40
47
  type: IssueTypeSchema.optional(),
41
48
 
42
49
  // Metadata
43
- assignee: z.object({
44
- id: z.string(),
45
- name: z.string(),
46
- email: z.string().optional(),
47
- }).optional(),
50
+ assignee: z
51
+ .object({
52
+ id: z.string(),
53
+ name: z.string(),
54
+ email: z.string().optional(),
55
+ })
56
+ .optional(),
48
57
  labels: z.array(z.string()).default([]),
49
- team: z.object({
50
- id: z.string(),
51
- name: z.string(),
52
- key: z.string().optional(),
53
- }).optional(),
54
- project: z.object({
55
- id: z.string(),
56
- name: z.string(),
57
- }).optional(),
58
+ team: z
59
+ .object({
60
+ id: z.string(),
61
+ name: z.string(),
62
+ key: z.string().optional(),
63
+ })
64
+ .optional(),
65
+ project: z
66
+ .object({
67
+ id: z.string(),
68
+ name: z.string(),
69
+ })
70
+ .optional(),
58
71
 
59
72
  // URLs and timestamps
60
73
  url: z.string(),
61
- createdAt: z.string(), // ISO8601 from provider
62
- updatedAt: z.string(), // ISO8601 from provider
63
- fetchedAt: z.string(), // ISO8601 when we cached it
74
+ createdAt: z.string(), // ISO8601 from provider
75
+ updatedAt: z.string(), // ISO8601 from provider
76
+ fetchedAt: z.string(), // ISO8601 when we cached it
64
77
  })
65
78
 
66
79
  // =============================================================================
@@ -76,7 +89,7 @@ export const IssuesJsonSchema = z.object({
76
89
  provider: IssueProviderSchema,
77
90
 
78
91
  // Sync metadata
79
- lastSync: z.string(), // ISO8601 of last full sync
92
+ lastSync: z.string(), // ISO8601 of last full sync
80
93
  staleAfter: z.number().default(1800000), // 30 minutes in ms
81
94
 
82
95
  // Issues map: identifier -> issue
@@ -91,10 +104,12 @@ export const SyncResultSchema = z.object({
91
104
  provider: IssueProviderSchema,
92
105
  fetched: z.number(),
93
106
  updated: z.number(),
94
- errors: z.array(z.object({
95
- issueId: z.string(),
96
- error: z.string(),
97
- })),
107
+ errors: z.array(
108
+ z.object({
109
+ issueId: z.string(),
110
+ error: z.string(),
111
+ })
112
+ ),
98
113
  timestamp: z.string(),
99
114
  })
100
115