prjct-cli 0.45.0 → 0.45.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (207) hide show
  1. package/CHANGELOG.md +82 -0
  2. package/bin/prjct.ts +117 -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 +58 -39
  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 +28 -4
  43. package/core/commands/commands.ts +57 -24
  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 +13 -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 +18 -19
  59. package/core/context-tools/imports-tool.ts +13 -33
  60. package/core/context-tools/index.ts +29 -54
  61. package/core/context-tools/recent-tool.ts +16 -22
  62. package/core/context-tools/signatures-tool.ts +17 -26
  63. package/core/context-tools/summary-tool.ts +20 -22
  64. package/core/context-tools/token-counter.ts +25 -20
  65. package/core/context-tools/types.ts +5 -5
  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 -16
  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 +25 -25
  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 +87 -345
  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 -17
  157. package/core/storage/metrics-storage.ts +39 -34
  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 -305
  170. package/core/types/integrations.ts +3 -3
  171. package/core/types/storage.ts +14 -14
  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 +18755 -15574
  194. package/dist/core/infrastructure/command-installer.js +86 -79
  195. package/dist/core/infrastructure/editors-config.js +6 -6
  196. package/dist/core/infrastructure/setup.js +246 -225
  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
@@ -10,26 +10,26 @@
10
10
 
11
11
  import { agentPerformanceTracker } from '../agents'
12
12
  import { outcomeAnalyzer } from '../outcomes'
13
- import type { TaskType } from '../types'
14
13
  import type {
15
14
  ContextDomain,
16
- SmartContextProjectState,
17
- FullContext,
15
+ DomainAnalysis,
18
16
  FilteredContext,
17
+ FullContext,
18
+ SmartContextProjectState,
19
19
  StackInfo,
20
- DomainAnalysis,
20
+ TaskType,
21
21
  } from '../types'
22
22
 
23
23
  // Re-export types for convenience
24
24
  export type {
25
- ContextDomain,
26
- FullContext,
27
- FilteredContext,
28
25
  AgentInfo,
26
+ ContextDomain,
29
27
  FeatureInfo,
28
+ FilteredContext,
29
+ FilterMetrics,
30
+ FullContext,
30
31
  PatternInfo,
31
32
  StackInfo,
32
- FilterMetrics,
33
33
  } from '../types'
34
34
 
35
35
  // Local type alias for backward compatibility
@@ -47,38 +47,105 @@ class SmartContext {
47
47
 
48
48
  // Frontend indicators
49
49
  const frontendKeywords = [
50
- 'ui', 'component', 'react', 'vue', 'angular', 'css', 'style',
51
- 'button', 'form', 'modal', 'layout', 'responsive', 'animation',
52
- 'dom', 'html', 'frontend', 'fe', 'client', 'browser', 'jsx', 'tsx'
50
+ 'ui',
51
+ 'component',
52
+ 'react',
53
+ 'vue',
54
+ 'angular',
55
+ 'css',
56
+ 'style',
57
+ 'button',
58
+ 'form',
59
+ 'modal',
60
+ 'layout',
61
+ 'responsive',
62
+ 'animation',
63
+ 'dom',
64
+ 'html',
65
+ 'frontend',
66
+ 'fe',
67
+ 'client',
68
+ 'browser',
69
+ 'jsx',
70
+ 'tsx',
53
71
  ]
54
72
 
55
73
  // Backend indicators
56
74
  const backendKeywords = [
57
- 'api', 'server', 'database', 'db', 'endpoint', 'route', 'handler',
58
- 'controller', 'service', 'repository', 'model', 'query', 'backend',
59
- 'be', 'rest', 'graphql', 'prisma', 'sql', 'redis', 'auth'
75
+ 'api',
76
+ 'server',
77
+ 'database',
78
+ 'db',
79
+ 'endpoint',
80
+ 'route',
81
+ 'handler',
82
+ 'controller',
83
+ 'service',
84
+ 'repository',
85
+ 'model',
86
+ 'query',
87
+ 'backend',
88
+ 'be',
89
+ 'rest',
90
+ 'graphql',
91
+ 'prisma',
92
+ 'sql',
93
+ 'redis',
94
+ 'auth',
60
95
  ]
61
96
 
62
97
  // DevOps indicators
63
98
  const devopsKeywords = [
64
- 'deploy', 'docker', 'kubernetes', 'k8s', 'ci', 'cd', 'pipeline',
65
- 'terraform', 'ansible', 'aws', 'gcp', 'azure', 'config', 'nginx',
66
- 'devops', 'infrastructure', 'monitoring', 'logging', 'build'
99
+ 'deploy',
100
+ 'docker',
101
+ 'kubernetes',
102
+ 'k8s',
103
+ 'ci',
104
+ 'cd',
105
+ 'pipeline',
106
+ 'terraform',
107
+ 'ansible',
108
+ 'aws',
109
+ 'gcp',
110
+ 'azure',
111
+ 'config',
112
+ 'nginx',
113
+ 'devops',
114
+ 'infrastructure',
115
+ 'monitoring',
116
+ 'logging',
117
+ 'build',
67
118
  ]
68
119
 
69
120
  // Docs indicators
70
121
  const docsKeywords = [
71
- 'document', 'docs', 'readme', 'changelog', 'comment', 'jsdoc',
72
- 'tutorial', 'guide', 'explain', 'describe', 'markdown'
122
+ 'document',
123
+ 'docs',
124
+ 'readme',
125
+ 'changelog',
126
+ 'comment',
127
+ 'jsdoc',
128
+ 'tutorial',
129
+ 'guide',
130
+ 'explain',
131
+ 'describe',
132
+ 'markdown',
73
133
  ]
74
134
 
75
135
  // Testing indicators
76
136
  const testingKeywords = [
77
- 'test', 'spec',
137
+ 'test',
138
+ 'spec',
78
139
  // JS/TS
79
- 'bun', 'bun test', 'jest', 'mocha', 'cypress', 'playwright',
140
+ 'bun',
141
+ 'bun test',
142
+ 'jest',
143
+ 'mocha',
144
+ 'cypress',
145
+ 'playwright',
80
146
  // Python
81
- 'pytest', 'unittest',
147
+ 'pytest',
148
+ 'unittest',
82
149
  // Go
83
150
  'go test',
84
151
  // Rust
@@ -86,17 +153,24 @@ class SmartContext {
86
153
  // .NET
87
154
  'dotnet test',
88
155
  // Java
89
- 'mvn test', 'gradle test', 'gradlew test',
90
- 'e2e', 'unit', 'integration', 'coverage', 'mock', 'fixture'
156
+ 'mvn test',
157
+ 'gradle test',
158
+ 'gradlew test',
159
+ 'e2e',
160
+ 'unit',
161
+ 'integration',
162
+ 'coverage',
163
+ 'mock',
164
+ 'fixture',
91
165
  ]
92
166
 
93
167
  // Count matches
94
168
  const scores: Record<ContextDomain, number> = {
95
- frontend: frontendKeywords.filter(k => lower.includes(k)).length,
96
- backend: backendKeywords.filter(k => lower.includes(k)).length,
97
- devops: devopsKeywords.filter(k => lower.includes(k)).length,
98
- docs: docsKeywords.filter(k => lower.includes(k)).length,
99
- testing: testingKeywords.filter(k => lower.includes(k)).length,
169
+ frontend: frontendKeywords.filter((k) => lower.includes(k)).length,
170
+ backend: backendKeywords.filter((k) => lower.includes(k)).length,
171
+ devops: devopsKeywords.filter((k) => lower.includes(k)).length,
172
+ docs: docsKeywords.filter((k) => lower.includes(k)).length,
173
+ testing: testingKeywords.filter((k) => lower.includes(k)).length,
100
174
  general: 0,
101
175
  }
102
176
 
@@ -135,29 +209,26 @@ class SmartContext {
135
209
  const relevantDomains = [taskDomain, ...secondary, 'general']
136
210
 
137
211
  // Filter agents
138
- const filteredAgents = fullContext.agents.filter(
139
- agent => relevantDomains.includes(agent.domain)
212
+ const filteredAgents = fullContext.agents.filter((agent) =>
213
+ relevantDomains.includes(agent.domain)
140
214
  )
141
215
 
142
216
  // Enrich with performance data
143
217
  for (const agent of filteredAgents) {
144
- const perf = await agentPerformanceTracker.getAgentPerformance(
145
- projectId,
146
- agent.name
147
- )
218
+ const perf = await agentPerformanceTracker.getAgentPerformance(projectId, agent.name)
148
219
  if (perf) {
149
220
  agent.successRate = perf.successRate
150
221
  }
151
222
  }
152
223
 
153
224
  // Filter roadmap
154
- const filteredRoadmap = fullContext.roadmap.filter(
155
- feature => feature.relatedTo.some(domain => relevantDomains.includes(domain))
225
+ const filteredRoadmap = fullContext.roadmap.filter((feature) =>
226
+ feature.relatedTo.some((domain) => relevantDomains.includes(domain))
156
227
  )
157
228
 
158
229
  // Filter patterns
159
- const filteredPatterns = fullContext.patterns.filter(
160
- pattern => relevantDomains.includes(pattern.domain)
230
+ const filteredPatterns = fullContext.patterns.filter((pattern) =>
231
+ relevantDomains.includes(pattern.domain)
161
232
  )
162
233
 
163
234
  // Get relevant patterns from outcomes
@@ -248,19 +319,8 @@ class SmartContext {
248
319
  /infra/i,
249
320
  /k8s/i,
250
321
  ],
251
- docs: [
252
- /\.(md|mdx|rst|txt)$/i,
253
- /docs?\//i,
254
- /readme/i,
255
- /changelog/i,
256
- ],
257
- testing: [
258
- /\.(test|spec)\./i,
259
- /tests?\//i,
260
- /__tests__\//i,
261
- /e2e\//i,
262
- /fixtures?\//i,
263
- ],
322
+ docs: [/\.(md|mdx|rst|txt)$/i, /docs?\//i, /readme/i, /changelog/i],
323
+ testing: [/\.(test|spec)\./i, /tests?\//i, /__tests__\//i, /e2e\//i, /fixtures?\//i],
264
324
  general: [],
265
325
  }
266
326
 
@@ -270,19 +330,15 @@ class SmartContext {
270
330
  }
271
331
 
272
332
  // Always include config files
273
- const configPatterns = [
274
- /package\.json$/,
275
- /tsconfig\.json$/,
276
- /\.config\.(ts|js)$/,
277
- ]
333
+ const configPatterns = [/package\.json$/, /tsconfig\.json$/, /\.config\.(ts|js)$/]
278
334
 
279
- return files.filter(file => {
335
+ return files.filter((file) => {
280
336
  // Include if matches domain patterns
281
- if (domainPatterns.some(p => p.test(file))) {
337
+ if (domainPatterns.some((p) => p.test(file))) {
282
338
  return true
283
339
  }
284
340
  // Include config files
285
- if (configPatterns.some(p => p.test(file))) {
341
+ if (configPatterns.some((p) => p.test(file))) {
286
342
  return true
287
343
  }
288
344
  return false
@@ -292,14 +348,16 @@ class SmartContext {
292
348
  /**
293
349
  * Estimate context size in approximate tokens.
294
350
  */
295
- private estimateSize(context: Partial<{
296
- agents: unknown[]
297
- roadmap: unknown[]
298
- patterns: unknown[]
299
- stack: unknown
300
- files: string[]
301
- state: unknown
302
- }>): number {
351
+ private estimateSize(
352
+ context: Partial<{
353
+ agents: unknown[]
354
+ roadmap: unknown[]
355
+ patterns: unknown[]
356
+ stack: unknown
357
+ files: string[]
358
+ state: unknown
359
+ }>
360
+ ): number {
303
361
  let size = 0
304
362
 
305
363
  // Rough estimates: each item ~50 tokens, files ~10 tokens each
@@ -349,22 +407,14 @@ class SmartContext {
349
407
  const taskType = this.contextDomainToTaskType(domainAnalysis.primary)
350
408
 
351
409
  // Get agent suggestion
352
- const agentSuggestion = await agentPerformanceTracker.suggestAgent(
353
- projectId,
354
- taskType
355
- )
410
+ const agentSuggestion = await agentPerformanceTracker.suggestAgent(projectId, taskType)
356
411
 
357
412
  // Get duration estimate
358
- const durationEstimate = await outcomeAnalyzer.suggestEstimate(
359
- projectId,
360
- taskType
361
- )
413
+ const durationEstimate = await outcomeAnalyzer.suggestEstimate(projectId, taskType)
362
414
 
363
415
  // Get relevant patterns
364
416
  const patterns = await outcomeAnalyzer.detectPatterns(projectId)
365
- const relevantPatterns = patterns
366
- .slice(0, 3)
367
- .map(p => p.description)
417
+ const relevantPatterns = patterns.slice(0, 3).map((p) => p.description)
368
418
 
369
419
  return {
370
420
  domain: domainAnalysis.primary,
@@ -9,9 +9,8 @@
9
9
  * @version 1.0.0
10
10
  */
11
11
 
12
- import fs from 'fs/promises'
13
- import path from 'path'
14
- import os from 'os'
12
+ import fs from 'node:fs/promises'
13
+ import path from 'node:path'
15
14
  import configManager from '../infrastructure/config-manager'
16
15
  import pathManager from '../infrastructure/path-manager'
17
16
  import { isNotFoundError } from '../types/fs'
@@ -119,7 +118,7 @@ export class TemplateExecutor {
119
118
  agentsDir: path.join(globalPath, 'agents'),
120
119
  skillsDir: activeProvider.skillsDir,
121
120
  stateJson: path.join(globalPath, 'storage', 'state.json'),
122
- }
121
+ },
123
122
  }
124
123
  }
125
124
 
@@ -141,7 +140,7 @@ export class TemplateExecutor {
141
140
  const projectId = await this.getProjectId(projectPath)
142
141
  const agentsDir = path.join(pathManager.getGlobalProjectPath(projectId), 'agents')
143
142
  const files = await fs.readdir(agentsDir)
144
- return files.some(f => f.endsWith('.md'))
143
+ return files.some((f) => f.endsWith('.md'))
145
144
  } catch (error) {
146
145
  if (isNotFoundError(error)) return false
147
146
  return false
@@ -156,9 +155,7 @@ export class TemplateExecutor {
156
155
  const projectId = await this.getProjectId(projectPath)
157
156
  const agentsDir = path.join(pathManager.getGlobalProjectPath(projectId), 'agents')
158
157
  const files = await fs.readdir(agentsDir)
159
- return files
160
- .filter(f => f.endsWith('.md'))
161
- .map(f => f.replace('.md', ''))
158
+ return files.filter((f) => f.endsWith('.md')).map((f) => f.replace('.md', ''))
162
159
  } catch {
163
160
  return []
164
161
  }
@@ -199,7 +196,9 @@ You are executing a prjct command as ${context.agentName}. Follow the template-f
199
196
 
200
197
  2. **Check if orchestration is needed**
201
198
  - This command ${requiresOrchestration ? 'REQUIRES' : 'does NOT require'} orchestration
202
- ${requiresOrchestration ? `
199
+ ${
200
+ requiresOrchestration
201
+ ? `
203
202
  3. **Orchestration steps:**
204
203
  - Read: ${context.paths.orchestrator}
205
204
  - Read: ${context.paths.repoAnalysis} to understand project technologies
@@ -217,11 +216,13 @@ You are executing a prjct command as ${context.agentName}. Follow the template-f
217
216
 
218
217
  - Check if task should be fragmented (read: ${context.paths.taskFragmentation})
219
218
  - If agents loaded, check their skills and load from ${context.paths.skillsDir}
220
- ` : `
219
+ `
220
+ : `
221
221
  3. **Simple execution:**
222
222
  - Execute the command template directly
223
223
  - No agent routing needed
224
- `}
224
+ `
225
+ }
225
226
 
226
227
  4. **Execute the command template** with full context
227
228
 
@@ -258,7 +259,7 @@ When fragmenting tasks:
258
259
  return {
259
260
  prompt,
260
261
  context,
261
- requiresOrchestration
262
+ requiresOrchestration,
262
263
  }
263
264
  }
264
265
  }
@@ -5,8 +5,8 @@
5
5
  * @module agentic/template-loader
6
6
  */
7
7
 
8
- import fs from 'fs/promises'
9
- import path from 'path'
8
+ import fs from 'node:fs/promises'
9
+ import path from 'node:path'
10
10
  import { TemplateError } from '../errors'
11
11
  import type { Frontmatter, ParsedTemplate } from '../types'
12
12
 
@@ -53,7 +53,10 @@ export function parseFrontmatter(content: string): ParsedTemplate {
53
53
 
54
54
  // Parse arrays
55
55
  if (value.startsWith('[') && value.endsWith(']')) {
56
- frontmatter[key.trim()] = value.slice(1, -1).split(',').map((v) => v.trim())
56
+ frontmatter[key.trim()] = value
57
+ .slice(1, -1)
58
+ .split(',')
59
+ .map((v) => v.trim())
57
60
  } else {
58
61
  // Remove quotes if present
59
62
  frontmatter[key.trim()] = value.replace(/^["']|["']$/g, '')
@@ -108,5 +111,5 @@ export default {
108
111
  load,
109
112
  parseFrontmatter,
110
113
  getAllowedTools,
111
- clearCache
114
+ clearCache,
112
115
  }
@@ -6,9 +6,9 @@
6
6
  * @version 1.0.0
7
7
  */
8
8
 
9
- import fs from 'fs/promises'
10
- import { exec } from 'child_process'
11
- import { promisify } from 'util'
9
+ import { exec } from 'node:child_process'
10
+ import fs from 'node:fs/promises'
11
+ import { promisify } from 'node:util'
12
12
  import type { ToolFunction, ToolRegistryInterface } from '../types'
13
13
 
14
14
  // Re-export types for convenience
@@ -83,18 +83,21 @@ toolRegistry.register('Write', async (filePath: unknown, content: unknown): Prom
83
83
  })
84
84
 
85
85
  // Execute bash command
86
- toolRegistry.register('Bash', async (command: unknown): Promise<{ stdout: string; stderr: string }> => {
87
- try {
88
- const { stdout, stderr } = await execAsync(command as string)
89
- return { stdout, stderr }
90
- } catch (error) {
91
- const err = error as { stdout?: string; stderr?: string; message?: string }
92
- return {
93
- stdout: err.stdout || '',
94
- stderr: err.stderr || err.message || 'Command failed',
86
+ toolRegistry.register(
87
+ 'Bash',
88
+ async (command: unknown): Promise<{ stdout: string; stderr: string }> => {
89
+ try {
90
+ const { stdout, stderr } = await execAsync(command as string)
91
+ return { stdout, stderr }
92
+ } catch (error) {
93
+ const err = error as { stdout?: string; stderr?: string; message?: string }
94
+ return {
95
+ stdout: err.stdout || '',
96
+ stderr: err.stderr || err.message || 'Command failed',
97
+ }
95
98
  }
96
99
  }
97
- })
100
+ )
98
101
 
99
102
  // Get current timestamp
100
103
  toolRegistry.register('GetTimestamp', async (): Promise<string> => {
@@ -24,5 +24,5 @@
24
24
  * ```
25
25
  */
26
26
 
27
- export { AgentPerformanceTracker, default as agentPerformanceTracker } from './performance'
28
27
  export * from '../types'
28
+ export { AgentPerformanceTracker, default as agentPerformanceTracker } from './performance'
@@ -5,16 +5,16 @@
5
5
  * Enables learning which agent works best for which task type.
6
6
  */
7
7
 
8
- import path from 'path'
9
- import * as fileHelper from '../utils/file-helper'
8
+ import path from 'node:path'
10
9
  import pathManager from '../infrastructure/path-manager'
11
10
  import type {
12
11
  AgentPerformance,
13
- AgentTaskRecord,
14
- AgentSuggestion,
15
12
  AgentPerformanceSummary,
13
+ AgentSuggestion,
14
+ AgentTaskRecord,
16
15
  TaskType,
17
16
  } from '../types'
17
+ import * as fileHelper from '../utils/file-helper'
18
18
 
19
19
  const PERFORMANCE_DIR = 'analysis'
20
20
  const PERFORMANCE_FILE = 'agent-performance.json'
@@ -94,10 +94,7 @@ export class AgentPerformanceTracker {
94
94
  return []
95
95
  }
96
96
 
97
- const data = await fileHelper.readJson<{ agents: AgentPerformance[] }>(
98
- perfPath,
99
- { agents: [] }
100
- )
97
+ const data = await fileHelper.readJson<{ agents: AgentPerformance[] }>(perfPath, { agents: [] })
101
98
  return data?.agents ?? []
102
99
  }
103
100
 
@@ -115,17 +112,11 @@ export class AgentPerformanceTracker {
115
112
  /**
116
113
  * Update performance summary after a task completion.
117
114
  */
118
- private async updatePerformance(
119
- projectId: string,
120
- record: AgentTaskRecord
121
- ): Promise<void> {
115
+ private async updatePerformance(projectId: string, record: AgentTaskRecord): Promise<void> {
122
116
  const perfPath = this.getPerformancePath(projectId)
123
117
  await fileHelper.ensureDir(path.dirname(perfPath))
124
118
 
125
- const data = await fileHelper.readJson<{ agents: AgentPerformance[] }>(
126
- perfPath,
127
- { agents: [] }
128
- )
119
+ const data = await fileHelper.readJson<{ agents: AgentPerformance[] }>(perfPath, { agents: [] })
129
120
 
130
121
  if (!data) return
131
122
 
@@ -279,10 +270,7 @@ export class AgentPerformanceTracker {
279
270
  /**
280
271
  * Suggest the best agent for a task type.
281
272
  */
282
- async suggestAgent(
283
- projectId: string,
284
- taskType: TaskType
285
- ): Promise<AgentSuggestion | null> {
273
+ async suggestAgent(projectId: string, taskType: TaskType): Promise<AgentSuggestion | null> {
286
274
  const allPerf = await this.getAllPerformance(projectId)
287
275
 
288
276
  if (allPerf.length === 0) {
@@ -308,9 +296,7 @@ export class AgentPerformanceTracker {
308
296
  }
309
297
 
310
298
  // Fallback to most experienced agent
311
- const byExperience = [...allPerf].sort(
312
- (a, b) => b.tasksCompleted - a.tasksCompleted
313
- )
299
+ const byExperience = [...allPerf].sort((a, b) => b.tasksCompleted - a.tasksCompleted)
314
300
  const fallback = byExperience[0]
315
301
 
316
302
  return {
@@ -364,10 +350,7 @@ export class AgentPerformanceTracker {
364
350
  'design',
365
351
  'other',
366
352
  ]
367
- const byTaskType: Record<TaskType, string | null> = {} as Record<
368
- TaskType,
369
- string | null
370
- >
353
+ const byTaskType: Record<TaskType, string | null> = {} as Record<TaskType, string | null>
371
354
 
372
355
  for (const taskType of taskTypes) {
373
356
  const best = allPerf.find((a) => a.bestFor.includes(taskType))
@@ -41,7 +41,7 @@ export interface ProjectContext {
41
41
  * Format context for Claude Code (CLAUDE.md)
42
42
  * Detailed markdown with full context
43
43
  */
44
- export function formatForClaude(ctx: ProjectContext, config: AIToolConfig): string {
44
+ export function formatForClaude(ctx: ProjectContext, _config: AIToolConfig): string {
45
45
  return `# ${ctx.name} - Project Rules
46
46
  <!-- projectId: ${ctx.projectId} -->
47
47
  <!-- Generated: ${new Date().toISOString()} -->
@@ -117,7 +117,7 @@ Load from \`~/.prjct-cli/projects/${ctx.projectId}/agents/\`:
117
117
  * Format context for Cursor (.cursorrules)
118
118
  * Concise rules format, optimized for inline suggestions
119
119
  */
120
- export function formatForCursor(ctx: ProjectContext, config: AIToolConfig): string {
120
+ export function formatForCursor(ctx: ProjectContext, _config: AIToolConfig): string {
121
121
  const rules: string[] = []
122
122
 
123
123
  // Project identity
@@ -164,7 +164,7 @@ export function formatForCursor(ctx: ProjectContext, config: AIToolConfig): stri
164
164
  * Format context for GitHub Copilot (.github/copilot-instructions.md)
165
165
  * Minimal bullet points
166
166
  */
167
- export function formatForCopilot(ctx: ProjectContext, config: AIToolConfig): string {
167
+ export function formatForCopilot(ctx: ProjectContext, _config: AIToolConfig): string {
168
168
  const lines: string[] = []
169
169
 
170
170
  lines.push('# Copilot Instructions')
@@ -197,7 +197,7 @@ export function formatForCopilot(ctx: ProjectContext, config: AIToolConfig): str
197
197
  * Format context for Windsurf (.windsurfrules)
198
198
  * Optimized for Cascade AI with flow-based suggestions
199
199
  */
200
- export function formatForWindsurf(ctx: ProjectContext, config: AIToolConfig): string {
200
+ export function formatForWindsurf(ctx: ProjectContext, _config: AIToolConfig): string {
201
201
  const rules: string[] = []
202
202
 
203
203
  // Project identity
@@ -242,7 +242,7 @@ export function formatForWindsurf(ctx: ProjectContext, config: AIToolConfig): st
242
242
  * Format context for Continue.dev (.continue/config.json)
243
243
  * JSON config with system message and context providers
244
244
  */
245
- export function formatForContinue(ctx: ProjectContext, config: AIToolConfig): string {
245
+ export function formatForContinue(ctx: ProjectContext, _config: AIToolConfig): string {
246
246
  const systemMessage = [
247
247
  `You are working on ${ctx.name}, a ${ctx.projectType} ${ctx.ecosystem} project.`,
248
248
  '',
@@ -289,7 +289,9 @@ export function formatForContinue(ctx: ProjectContext, config: AIToolConfig): st
289
289
  /**
290
290
  * Get formatter function for a tool
291
291
  */
292
- export function getFormatter(toolId: string): ((ctx: ProjectContext, config: AIToolConfig) => string) | null {
292
+ export function getFormatter(
293
+ toolId: string
294
+ ): ((ctx: ProjectContext, config: AIToolConfig) => string) | null {
293
295
  const formatters: Record<string, (ctx: ProjectContext, config: AIToolConfig) => string> = {
294
296
  claude: formatForClaude,
295
297
  cursor: formatForCursor,
@@ -5,10 +5,10 @@
5
5
  * Each tool gets context in its preferred format.
6
6
  */
7
7
 
8
- import fs from 'fs/promises'
9
- import path from 'path'
10
- import { AI_TOOLS, DEFAULT_AI_TOOLS, getAIToolConfig, type AIToolConfig } from './registry'
8
+ import fs from 'node:fs/promises'
9
+ import path from 'node:path'
11
10
  import { getFormatter, type ProjectContext } from './formatters'
11
+ import { AI_TOOLS, type AIToolConfig, DEFAULT_AI_TOOLS, getAIToolConfig } from './registry'
12
12
 
13
13
  export interface GenerateResult {
14
14
  toolId: string
@@ -111,7 +111,7 @@ export function getOutputFiles(
111
111
  toolIds: string[] = DEFAULT_AI_TOOLS
112
112
  ): { toolId: string; file: string; location: 'repo' | 'global' }[] {
113
113
  return toolIds
114
- .map(id => {
114
+ .map((id) => {
115
115
  const config = AI_TOOLS[id]
116
116
  if (!config) return null
117
117
  return {
@@ -10,6 +10,6 @@
10
10
  * - Tool-specific output formats
11
11
  */
12
12
 
13
- export * from './registry'
14
13
  export * from './formatters'
15
14
  export * from './generator'
15
+ export * from './registry'