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
@@ -11,43 +11,42 @@
11
11
  * @version 3.3
12
12
  */
13
13
 
14
- import fs from 'fs/promises'
15
- import path from 'path'
14
+ import fs from 'node:fs/promises'
15
+ import path from 'node:path'
16
16
  import pathManager from '../infrastructure/path-manager'
17
- import { isNotFoundError } from '../types/fs'
18
17
  import { generateUUID } from '../schemas'
18
+ import { isNotFoundError } from '../types/fs'
19
19
  import { getTimestamp, getTodayKey } from '../utils/date-helper'
20
- import { appendJsonLine, getLastJsonLines } from '../utils/jsonl-helper'
21
20
  import { ensureDir } from '../utils/file-helper'
21
+ import { appendJsonLine, getLastJsonLines } from '../utils/jsonl-helper'
22
22
 
23
23
  // Re-export types from canonical location
24
24
  export type {
25
- Memory,
26
- MemoryTag,
27
- MemoryDatabase,
25
+ Decision,
28
26
  HistoryEntry,
29
27
  HistoryEventType,
30
- Decision,
31
- Workflow,
32
- Preference,
33
- Patterns,
28
+ Memory,
34
29
  MemoryContext,
35
30
  MemoryContextParams,
31
+ MemoryDatabase,
32
+ MemoryTag,
33
+ Patterns,
34
+ Preference,
35
+ Workflow,
36
36
  } from '../types/memory'
37
37
 
38
38
  export { MEMORY_TAGS } from '../types/memory'
39
39
 
40
40
  import type {
41
- Memory,
42
- MemoryTag,
43
- MemoryDatabase,
44
41
  HistoryEntry,
45
42
  HistoryEventType,
46
- Decision,
47
- Workflow,
48
- Preference,
49
- Patterns,
43
+ Memory,
50
44
  MemoryContext,
45
+ MemoryDatabase,
46
+ MemoryTag,
47
+ Patterns,
48
+ Preference,
49
+ Workflow,
51
50
  } from '../types/memory'
52
51
 
53
52
  import { MEMORY_TAGS } from '../types/memory'
@@ -240,10 +239,19 @@ export class HistoryStore {
240
239
  const yearMonth = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}`
241
240
  const day = getTodayKey()
242
241
 
243
- return path.join(pathManager.getGlobalProjectPath(projectId), 'memory', 'sessions', yearMonth, `${day}.jsonl`)
242
+ return path.join(
243
+ pathManager.getGlobalProjectPath(projectId),
244
+ 'memory',
245
+ 'sessions',
246
+ yearMonth,
247
+ `${day}.jsonl`
248
+ )
244
249
  }
245
250
 
246
- async appendHistory(projectId: string, entry: Record<string, unknown> & { type: HistoryEventType }): Promise<void> {
251
+ async appendHistory(
252
+ projectId: string,
253
+ entry: Record<string, unknown> & { type: HistoryEventType }
254
+ ): Promise<void> {
247
255
  const sessionPath = this._getSessionPath(projectId)
248
256
  await ensureDir(path.dirname(sessionPath))
249
257
 
@@ -294,7 +302,12 @@ export class PatternStore extends CachedStore<Patterns> {
294
302
  return this.save(projectId)
295
303
  }
296
304
 
297
- async recordDecision(projectId: string, key: string, value: string, context: string = ''): Promise<void> {
305
+ async recordDecision(
306
+ projectId: string,
307
+ key: string,
308
+ value: string,
309
+ context: string = ''
310
+ ): Promise<void> {
298
311
  const patterns = await this.load(projectId)
299
312
  const now = getTimestamp()
300
313
 
@@ -333,7 +346,10 @@ export class PatternStore extends CachedStore<Patterns> {
333
346
  await this.save(projectId)
334
347
  }
335
348
 
336
- async getDecision(projectId: string, key: string): Promise<{ value: string; confidence: string } | null> {
349
+ async getDecision(
350
+ projectId: string,
351
+ key: string
352
+ ): Promise<{ value: string; confidence: string } | null> {
337
353
  const patterns = await this.load(projectId)
338
354
  const decision = patterns.decisions[key]
339
355
 
@@ -348,7 +364,11 @@ export class PatternStore extends CachedStore<Patterns> {
348
364
  return decision !== null
349
365
  }
350
366
 
351
- async recordWorkflow(projectId: string, workflowName: string, pattern: Record<string, unknown>): Promise<void> {
367
+ async recordWorkflow(
368
+ projectId: string,
369
+ workflowName: string,
370
+ pattern: Record<string, unknown>
371
+ ): Promise<void> {
352
372
  const patterns = await this.load(projectId)
353
373
  const now = getTimestamp()
354
374
 
@@ -381,7 +401,11 @@ export class PatternStore extends CachedStore<Patterns> {
381
401
  await this.save(projectId)
382
402
  }
383
403
 
384
- async getPreference(projectId: string, key: string, defaultValue: unknown = null): Promise<unknown> {
404
+ async getPreference(
405
+ projectId: string,
406
+ key: string,
407
+ defaultValue: unknown = null
408
+ ): Promise<unknown> {
385
409
  const patterns = await this.load(projectId)
386
410
  return patterns.preferences[key]?.value ?? defaultValue
387
411
  }
@@ -391,7 +415,8 @@ export class PatternStore extends CachedStore<Patterns> {
391
415
 
392
416
  return {
393
417
  decisions: Object.keys(patterns.decisions).length,
394
- learnedDecisions: Object.values(patterns.decisions).filter((d) => d.confidence !== 'low').length,
418
+ learnedDecisions: Object.values(patterns.decisions).filter((d) => d.confidence !== 'low')
419
+ .length,
395
420
  workflows: Object.keys(patterns.workflows).length,
396
421
  preferences: Object.keys(patterns.preferences).length,
397
422
  }
@@ -535,7 +560,11 @@ export class SemanticMemories extends CachedStore<MemoryDatabase> {
535
560
  return true
536
561
  }
537
562
 
538
- async findByTags(projectId: string, tags: string[], matchAll: boolean = false): Promise<Memory[]> {
563
+ async findByTags(
564
+ projectId: string,
565
+ tags: string[],
566
+ matchAll: boolean = false
567
+ ): Promise<Memory[]> {
539
568
  const db = await this.load(projectId)
540
569
  const parsedTags = this._coerceTags(tags)
541
570
 
@@ -556,11 +585,16 @@ export class SemanticMemories extends CachedStore<MemoryDatabase> {
556
585
  const queryLower = query.toLowerCase()
557
586
 
558
587
  return db.memories.filter(
559
- (m) => m.title.toLowerCase().includes(queryLower) || m.content.toLowerCase().includes(queryLower)
588
+ (m) =>
589
+ m.title.toLowerCase().includes(queryLower) || m.content.toLowerCase().includes(queryLower)
560
590
  )
561
591
  }
562
592
 
563
- async getRelevantMemories(projectId: string, context: MemoryContext, limit: number = 5): Promise<Memory[]> {
593
+ async getRelevantMemories(
594
+ projectId: string,
595
+ context: MemoryContext,
596
+ limit: number = 5
597
+ ): Promise<Memory[]> {
564
598
  const db = await this.load(projectId)
565
599
 
566
600
  const scored = db.memories.map((memory) => {
@@ -625,7 +659,12 @@ export class SemanticMemories extends CachedStore<MemoryDatabase> {
625
659
  return keywords.filter((k) => k.length > 2 && !stopWords.includes(k))
626
660
  }
627
661
 
628
- async autoRemember(projectId: string, decisionType: string, value: string, context: string = ''): Promise<void> {
662
+ async autoRemember(
663
+ projectId: string,
664
+ decisionType: string,
665
+ value: string,
666
+ context: string = ''
667
+ ): Promise<void> {
629
668
  const tagMap: Record<string, string[]> = {
630
669
  commit_footer: [MEMORY_TAGS.COMMIT_STYLE],
631
670
  branch_naming: [MEMORY_TAGS.BRANCH_NAMING],
@@ -736,11 +775,20 @@ export class MemorySystem {
736
775
  return this._semanticMemories.searchMemories(projectId, query)
737
776
  }
738
777
 
739
- getRelevantMemories(projectId: string, context: MemoryContext, limit?: number): Promise<Memory[]> {
778
+ getRelevantMemories(
779
+ projectId: string,
780
+ context: MemoryContext,
781
+ limit?: number
782
+ ): Promise<Memory[]> {
740
783
  return this._semanticMemories.getRelevantMemories(projectId, context, limit)
741
784
  }
742
785
 
743
- autoRemember(projectId: string, decisionType: string, value: string, context?: string): Promise<void> {
786
+ autoRemember(
787
+ projectId: string,
788
+ decisionType: string,
789
+ value: string,
790
+ context?: string
791
+ ): Promise<void> {
744
792
  return this._semanticMemories.autoRemember(projectId, decisionType, value, context)
745
793
  }
746
794
 
@@ -784,7 +832,10 @@ export class MemorySystem {
784
832
  return this._patternStore.recordDecision(projectId, key, value, context)
785
833
  }
786
834
 
787
- getDecision(projectId: string, key: string): Promise<{ value: string; confidence: string } | null> {
835
+ getDecision(
836
+ projectId: string,
837
+ key: string
838
+ ): Promise<{ value: string; confidence: string } | null> {
788
839
  return this._patternStore.getDecision(projectId, key)
789
840
  }
790
841
 
@@ -792,7 +843,11 @@ export class MemorySystem {
792
843
  return this._patternStore.hasPattern(projectId, key)
793
844
  }
794
845
 
795
- recordWorkflow(projectId: string, workflowName: string, pattern: Record<string, unknown>): Promise<void> {
846
+ recordWorkflow(
847
+ projectId: string,
848
+ workflowName: string,
849
+ pattern: Record<string, unknown>
850
+ ): Promise<void> {
796
851
  return this._patternStore.recordWorkflow(projectId, workflowName, pattern)
797
852
  }
798
853
 
@@ -816,7 +871,10 @@ export class MemorySystem {
816
871
  // TIER 3: History
817
872
  // ===========================================================================
818
873
 
819
- appendHistory(projectId: string, entry: Record<string, unknown> & { type: HistoryEventType }): Promise<void> {
874
+ appendHistory(
875
+ projectId: string,
876
+ entry: Record<string, unknown> & { type: HistoryEventType }
877
+ ): Promise<void> {
820
878
  return this._historyStore.appendHistory(projectId, entry)
821
879
  }
822
880
 
@@ -838,7 +896,12 @@ export class MemorySystem {
838
896
  return null
839
897
  }
840
898
 
841
- async learnDecision(projectId: string, key: string, value: string, context: string = ''): Promise<void> {
899
+ async learnDecision(
900
+ projectId: string,
901
+ key: string,
902
+ value: string,
903
+ context: string = ''
904
+ ): Promise<void> {
842
905
  this.setSession(`decision:${key}`, value)
843
906
  await this.recordDecision(projectId, key, value, context)
844
907
  await this.appendHistory(projectId, { type: 'decision', key, value, context })
@@ -13,20 +13,15 @@
13
13
  * @version 1.0.0
14
14
  */
15
15
 
16
- import fs from 'fs/promises'
17
- import path from 'path'
18
- import os from 'os'
19
- import pathManager from '../infrastructure/path-manager'
16
+ import fs from 'node:fs/promises'
17
+ import os from 'node:os'
18
+ import path from 'node:path'
20
19
  import configManager from '../infrastructure/config-manager'
20
+ import pathManager from '../infrastructure/path-manager'
21
21
  import { stateStorage } from '../storage'
22
+ import type { LoadedAgent, LoadedSkill, OrchestratorContext, OrchestratorSubtask } from '../types'
22
23
  import { isNotFoundError } from '../types/fs'
23
24
  import { parseFrontmatter } from './template-loader'
24
- import type {
25
- OrchestratorContext,
26
- LoadedAgent,
27
- LoadedSkill,
28
- OrchestratorSubtask,
29
- } from '../types'
30
25
 
31
26
  // =============================================================================
32
27
  // Domain Detection Keywords
@@ -38,49 +33,139 @@ import type {
38
33
  */
39
34
  const DOMAIN_KEYWORDS: Record<string, string[]> = {
40
35
  database: [
41
- 'database', 'db', 'sql', 'query', 'table', 'schema', 'migration',
42
- 'postgres', 'mysql', 'sqlite', 'mongo', 'redis', 'prisma', 'drizzle',
43
- 'orm', 'model', 'entity', 'repository', 'data layer', 'persist',
36
+ 'database',
37
+ 'db',
38
+ 'sql',
39
+ 'query',
40
+ 'table',
41
+ 'schema',
42
+ 'migration',
43
+ 'postgres',
44
+ 'mysql',
45
+ 'sqlite',
46
+ 'mongo',
47
+ 'redis',
48
+ 'prisma',
49
+ 'drizzle',
50
+ 'orm',
51
+ 'model',
52
+ 'entity',
53
+ 'repository',
54
+ 'data layer',
55
+ 'persist',
44
56
  ],
45
57
  backend: [
46
- 'api', 'endpoint', 'route', 'server', 'controller', 'service',
47
- 'middleware', 'auth', 'authentication', 'authorization', 'jwt', 'oauth',
48
- 'rest', 'graphql', 'trpc', 'express', 'fastify', 'hono', 'nest',
49
- 'validation', 'business logic',
58
+ 'api',
59
+ 'endpoint',
60
+ 'route',
61
+ 'server',
62
+ 'controller',
63
+ 'service',
64
+ 'middleware',
65
+ 'auth',
66
+ 'authentication',
67
+ 'authorization',
68
+ 'jwt',
69
+ 'oauth',
70
+ 'rest',
71
+ 'graphql',
72
+ 'trpc',
73
+ 'express',
74
+ 'fastify',
75
+ 'hono',
76
+ 'nest',
77
+ 'validation',
78
+ 'business logic',
50
79
  ],
51
80
  frontend: [
52
- 'ui', 'component', 'page', 'form', 'button', 'input', 'modal', 'dialog',
53
- 'react', 'vue', 'svelte', 'angular', 'next', 'nuxt', 'solid',
54
- 'css', 'style', 'tailwind', 'layout', 'responsive', 'animation',
55
- 'hook', 'state', 'context', 'redux', 'zustand', 'jotai',
81
+ 'ui',
82
+ 'component',
83
+ 'page',
84
+ 'form',
85
+ 'button',
86
+ 'input',
87
+ 'modal',
88
+ 'dialog',
89
+ 'react',
90
+ 'vue',
91
+ 'svelte',
92
+ 'angular',
93
+ 'next',
94
+ 'nuxt',
95
+ 'solid',
96
+ 'css',
97
+ 'style',
98
+ 'tailwind',
99
+ 'layout',
100
+ 'responsive',
101
+ 'animation',
102
+ 'hook',
103
+ 'state',
104
+ 'context',
105
+ 'redux',
106
+ 'zustand',
107
+ 'jotai',
56
108
  ],
57
109
  testing: [
58
- 'test', 'spec', 'unit', 'integration', 'e2e', 'jest', 'vitest',
59
- 'playwright', 'cypress', 'mocha', 'chai', 'mock', 'stub', 'fixture',
60
- 'coverage', 'assertion',
110
+ 'test',
111
+ 'spec',
112
+ 'unit',
113
+ 'integration',
114
+ 'e2e',
115
+ 'jest',
116
+ 'vitest',
117
+ 'playwright',
118
+ 'cypress',
119
+ 'mocha',
120
+ 'chai',
121
+ 'mock',
122
+ 'stub',
123
+ 'fixture',
124
+ 'coverage',
125
+ 'assertion',
61
126
  ],
62
127
  devops: [
63
- 'docker', 'kubernetes', 'k8s', 'ci', 'cd', 'pipeline', 'deploy',
64
- 'github actions', 'vercel', 'aws', 'gcp', 'azure', 'terraform',
65
- 'nginx', 'caddy', 'env', 'environment', 'config', 'secret',
128
+ 'docker',
129
+ 'kubernetes',
130
+ 'k8s',
131
+ 'ci',
132
+ 'cd',
133
+ 'pipeline',
134
+ 'deploy',
135
+ 'github actions',
136
+ 'vercel',
137
+ 'aws',
138
+ 'gcp',
139
+ 'azure',
140
+ 'terraform',
141
+ 'nginx',
142
+ 'caddy',
143
+ 'env',
144
+ 'environment',
145
+ 'config',
146
+ 'secret',
66
147
  ],
67
148
  uxui: [
68
- 'design', 'ux', 'user experience', 'accessibility', 'a11y',
69
- 'color', 'typography', 'spacing', 'prototype', 'wireframe',
70
- 'figma', 'user flow', 'interaction',
149
+ 'design',
150
+ 'ux',
151
+ 'user experience',
152
+ 'accessibility',
153
+ 'a11y',
154
+ 'color',
155
+ 'typography',
156
+ 'spacing',
157
+ 'prototype',
158
+ 'wireframe',
159
+ 'figma',
160
+ 'user flow',
161
+ 'interaction',
71
162
  ],
72
163
  }
73
164
 
74
165
  /**
75
166
  * Domain dependency order - earlier domains should complete first
76
167
  */
77
- const DOMAIN_DEPENDENCY_ORDER = [
78
- 'database',
79
- 'backend',
80
- 'frontend',
81
- 'testing',
82
- 'devops',
83
- ]
168
+ const DOMAIN_DEPENDENCY_ORDER = ['database', 'backend', 'frontend', 'testing', 'devops']
84
169
 
85
170
  // =============================================================================
86
171
  // Orchestrator Executor Class
@@ -108,11 +193,7 @@ export class OrchestratorExecutor {
108
193
  const repoAnalysis = await this.loadRepoAnalysis(globalPath)
109
194
 
110
195
  // Step 3: Detect domains from task + project context
111
- const { domains, primary } = await this.detectDomains(
112
- taskDescription,
113
- projectId,
114
- repoAnalysis
115
- )
196
+ const { domains, primary } = await this.detectDomains(taskDescription, projectId, repoAnalysis)
116
197
 
117
198
  // Step 4: Load agents for detected domains
118
199
  const agents = await this.loadAgents(domains, projectId)
@@ -126,12 +207,7 @@ export class OrchestratorExecutor {
126
207
  // Step 7: Create subtasks if fragmentation is required
127
208
  let subtasks: OrchestratorSubtask[] | null = null
128
209
  if (requiresFragmentation && command === 'task') {
129
- subtasks = await this.createSubtasks(
130
- taskDescription,
131
- domains,
132
- agents,
133
- projectId
134
- )
210
+ subtasks = await this.createSubtasks(taskDescription, domains, agents, projectId)
135
211
  }
136
212
 
137
213
  return {
@@ -229,10 +305,8 @@ export class OrchestratorExecutor {
229
305
  .filter(([domain]) => {
230
306
  // Check if agent exists for this domain
231
307
  return availableAgents.some(
232
- agent =>
233
- agent === domain ||
234
- agent.includes(domain) ||
235
- domain.includes(agent.replace('.md', ''))
308
+ (agent) =>
309
+ agent === domain || agent.includes(domain) || domain.includes(agent.replace('.md', ''))
236
310
  )
237
311
  })
238
312
  .sort((a, b) => b[1] - a[1]) // Sort by score descending
@@ -256,7 +330,7 @@ export class OrchestratorExecutor {
256
330
  try {
257
331
  const agentsDir = path.join(globalPath, 'agents')
258
332
  const files = await fs.readdir(agentsDir)
259
- return files.filter(f => f.endsWith('.md')).map(f => f.replace('.md', ''))
333
+ return files.filter((f) => f.endsWith('.md')).map((f) => f.replace('.md', ''))
260
334
  } catch {
261
335
  return []
262
336
  }
@@ -275,11 +349,7 @@ export class OrchestratorExecutor {
275
349
 
276
350
  for (const domain of domains) {
277
351
  // Try exact match first, then variations
278
- const possibleNames = [
279
- `${domain}.md`,
280
- `${domain}-agent.md`,
281
- `prjct-${domain}.md`,
282
- ]
352
+ const possibleNames = [`${domain}.md`, `${domain}-agent.md`, `prjct-${domain}.md`]
283
353
 
284
354
  for (const fileName of possibleNames) {
285
355
  const filePath = path.join(agentsDir, fileName)
@@ -297,10 +367,7 @@ export class OrchestratorExecutor {
297
367
 
298
368
  // Found one, no need to try other variations
299
369
  break
300
- } catch {
301
- // Try next variation
302
- continue
303
- }
370
+ } catch {}
304
371
  }
305
372
  }
306
373
 
@@ -320,12 +387,12 @@ export class OrchestratorExecutor {
320
387
  const frontmatter = { ...parsed.frontmatter }
321
388
  if (typeof frontmatter.skills === 'string') {
322
389
  // Handle comma-separated string
323
- frontmatter.skills = (frontmatter.skills as string).split(',').map(s => s.trim())
390
+ frontmatter.skills = (frontmatter.skills as string).split(',').map((s) => s.trim())
324
391
  }
325
392
 
326
393
  return {
327
394
  frontmatter: frontmatter as { skills?: string[]; [key: string]: unknown },
328
- body: parsed.content
395
+ body: parsed.content,
329
396
  }
330
397
  }
331
398
 
@@ -438,11 +505,11 @@ export class OrchestratorExecutor {
438
505
  // Create subtask for each domain
439
506
  const subtasks: OrchestratorSubtask[] = sortedDomains.map((domain, index) => {
440
507
  // Find the agent for this domain
441
- const agent = agents.find(a => a.domain === domain)
508
+ const agent = agents.find((a) => a.domain === domain)
442
509
  const agentFile = agent ? `${agent.name}.md` : `${domain}.md`
443
510
 
444
511
  // Determine dependencies - each subtask depends on previous ones
445
- const dependsOn = sortedDomains.slice(0, index).map((d, i) => `subtask-${i + 1}`)
512
+ const dependsOn = sortedDomains.slice(0, index).map((_d, i) => `subtask-${i + 1}`)
446
513
 
447
514
  return {
448
515
  id: `subtask-${index + 1}`,
@@ -458,7 +525,7 @@ export class OrchestratorExecutor {
458
525
  // Store subtasks in state.json via state storage
459
526
  await stateStorage.createSubtasks(
460
527
  projectId,
461
- subtasks.map(st => ({
528
+ subtasks.map((st) => ({
462
529
  id: st.id,
463
530
  description: st.description,
464
531
  domain: st.domain,
@@ -473,10 +540,7 @@ export class OrchestratorExecutor {
473
540
  /**
474
541
  * Generate a domain-specific subtask description
475
542
  */
476
- private generateSubtaskDescription(
477
- fullTask: string,
478
- domain: string
479
- ): string {
543
+ private generateSubtaskDescription(fullTask: string, domain: string): string {
480
544
  const domainDescriptions: Record<string, string> = {
481
545
  database: 'Set up data layer: schema, models, migrations',
482
546
  backend: 'Implement API: routes, controllers, services, validation',
@@ -8,22 +8,34 @@
8
8
  * Pattern from: Devin AI, Windsurf, Kiro
9
9
  */
10
10
 
11
+ import { generateUUID } from '../schemas'
11
12
  import type {
12
- PlanParams,
13
+ ApprovalContext,
14
+ ApprovalPrompt,
13
15
  GatheredInfo,
14
- ProposedPlan,
15
- PlanStep,
16
- PlanStepResult,
17
- PlanStatus,
18
16
  Plan,
19
17
  PlanAnalysis,
20
- ApprovalPrompt,
21
- ApprovalContext,
18
+ PlanParams,
19
+ PlanStatus,
20
+ PlanStep,
21
+ PlanStepResult,
22
+ ProposedPlan,
22
23
  } from '../types'
23
- import { generateUUID } from '../schemas'
24
24
  import { getTimestamp } from '../utils/date-helper'
25
- export { PLAN_STATUS, PLAN_REQUIRED_COMMANDS, DESTRUCTIVE_COMMANDS, PLANNING_TOOLS } from '../constants'
26
- import { PLAN_STATUS, PLAN_REQUIRED_COMMANDS, DESTRUCTIVE_COMMANDS, PLANNING_TOOLS } from '../constants'
25
+
26
+ export {
27
+ DESTRUCTIVE_COMMANDS,
28
+ PLAN_REQUIRED_COMMANDS,
29
+ PLAN_STATUS,
30
+ PLANNING_TOOLS,
31
+ } from '../constants'
32
+
33
+ import {
34
+ DESTRUCTIVE_COMMANDS,
35
+ PLAN_REQUIRED_COMMANDS,
36
+ PLAN_STATUS,
37
+ PLANNING_TOOLS,
38
+ } from '../constants'
27
39
 
28
40
  // =============================================================================
29
41
  // Approval
@@ -32,7 +44,10 @@ import { PLAN_STATUS, PLAN_REQUIRED_COMMANDS, DESTRUCTIVE_COMMANDS, PLANNING_TOO
32
44
  /**
33
45
  * Generate approval prompt for destructive commands
34
46
  */
35
- export function generateApprovalPrompt(commandName: string, context: ApprovalContext): ApprovalPrompt {
47
+ export function generateApprovalPrompt(
48
+ commandName: string,
49
+ context: ApprovalContext
50
+ ): ApprovalPrompt {
36
51
  const prompts: Record<string, ApprovalPrompt> = {
37
52
  ship: {
38
53
  title: 'Ship Confirmation',
@@ -51,7 +66,10 @@ export function generateApprovalPrompt(commandName: string, context: ApprovalCon
51
66
  cleanup: {
52
67
  title: 'Cleanup Confirmation',
53
68
  message: 'This will delete files/code. Continue?',
54
- details: [`Files to delete: ${context.filesToDelete?.length || 0}`, `Code to remove: ${context.linesOfCode || 0} lines`],
69
+ details: [
70
+ `Files to delete: ${context.filesToDelete?.length || 0}`,
71
+ `Code to remove: ${context.linesOfCode || 0} lines`,
72
+ ],
55
73
  options: [
56
74
  { key: 'y', label: 'Yes, cleanup', action: 'approve' },
57
75
  { key: 'n', label: 'No, cancel', action: 'reject' },
@@ -218,7 +236,10 @@ export class PlanMode {
218
236
  /**
219
237
  * Propose a plan for user approval
220
238
  */
221
- proposePlan(projectId: string, proposedPlan: ProposedPlan): ReturnType<typeof this.formatPlanForApproval> | null {
239
+ proposePlan(
240
+ projectId: string,
241
+ proposedPlan: ProposedPlan
242
+ ): ReturnType<typeof this.formatPlanForApproval> | null {
222
243
  const plan = this.getActivePlan(projectId)
223
244
  if (!plan) return null
224
245
 
@@ -350,7 +371,10 @@ export class PlanMode {
350
371
  /**
351
372
  * Mark current step as complete
352
373
  */
353
- completeStep(projectId: string, result: PlanStepResult = { success: true }): ReturnType<typeof this.getNextStep> {
374
+ completeStep(
375
+ projectId: string,
376
+ result: PlanStepResult = { success: true }
377
+ ): ReturnType<typeof this.getNextStep> {
354
378
  const plan = this.getActivePlan(projectId)
355
379
  if (!plan || plan.status !== PLAN_STATUS.EXECUTING) {
356
380
  return null
@@ -370,7 +394,10 @@ export class PlanMode {
370
394
  /**
371
395
  * Mark step as failed
372
396
  */
373
- failStep(projectId: string, error: string): { failed: boolean; step: number; error: string; options: string[] } | null {
397
+ failStep(
398
+ projectId: string,
399
+ error: string
400
+ ): { failed: boolean; step: number; error: string; options: string[] } | null {
374
401
  const plan = this.getActivePlan(projectId)
375
402
  if (!plan) return null
376
403
 
@@ -461,7 +488,10 @@ export class PlanMode {
461
488
  [PLAN_STATUS.ABORTED]: '🛑',
462
489
  }
463
490
 
464
- const lines = [`${statusEmoji[plan.status] || '📋'} Plan: ${plan.command}`, `Status: ${plan.status}`]
491
+ const lines = [
492
+ `${statusEmoji[plan.status] || '📋'} Plan: ${plan.command}`,
493
+ `Status: ${plan.status}`,
494
+ ]
465
495
 
466
496
  if (plan.status === PLAN_STATUS.EXECUTING) {
467
497
  const progress = Math.round((plan.currentStep / plan.steps.length) * 100)