prjct-cli 0.45.0 → 0.45.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (207) hide show
  1. package/CHANGELOG.md +75 -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
@@ -3,7 +3,7 @@
3
3
  * Implements prjct commands for Claude Code environment
4
4
  */
5
5
 
6
- import fs from 'fs/promises'
6
+ import fs from 'node:fs/promises'
7
7
  import { isNotFoundError } from '../types/fs'
8
8
 
9
9
  declare const global: typeof globalThis & {
@@ -71,7 +71,7 @@ class ClaudeAgent {
71
71
  */
72
72
  async readFile(filePath: string): Promise<string> {
73
73
  try {
74
- if (global.mcp && global.mcp.filesystem) {
74
+ if (global.mcp?.filesystem) {
75
75
  return await global.mcp.filesystem.read(filePath)
76
76
  }
77
77
  } catch (_error) {
@@ -86,7 +86,7 @@ class ClaudeAgent {
86
86
  */
87
87
  async writeFile(filePath: string, content: string): Promise<void> {
88
88
  try {
89
- if (global.mcp && global.mcp.filesystem) {
89
+ if (global.mcp?.filesystem) {
90
90
  return await global.mcp.filesystem.write(filePath, content)
91
91
  }
92
92
  } catch (_error) {
@@ -101,7 +101,7 @@ class ClaudeAgent {
101
101
  */
102
102
  async listDirectory(dirPath: string): Promise<string[]> {
103
103
  try {
104
- if (global.mcp && global.mcp.filesystem) {
104
+ if (global.mcp?.filesystem) {
105
105
  return await global.mcp.filesystem.list(dirPath)
106
106
  }
107
107
  } catch (_error) {
@@ -148,7 +148,7 @@ class ClaudeAgent {
148
148
  return '📋 No tasks queued'
149
149
  }
150
150
 
151
- return '📋 Queue:\n' + tasks.map((t, i) => `${i + 1}. ${t}`).join('\n')
151
+ return `📋 Queue:\n${tasks.map((t, i) => `${i + 1}. ${t}`).join('\n')}`
152
152
  }
153
153
 
154
154
  /**
@@ -161,7 +161,7 @@ class ClaudeAgent {
161
161
  🚀 Shipped: ${data.shippedCount}
162
162
  📝 Queue: ${data.queuedCount}
163
163
  💡 Ideas: ${data.ideasCount}
164
- ${data.recentActivity ? '\n' + data.recentActivity : ''}`
164
+ ${data.recentActivity ? `\n${data.recentActivity}` : ''}`
165
165
  }
166
166
 
167
167
  /**
@@ -12,18 +12,18 @@
12
12
  * @version 0.6.0 - Multi-provider support
13
13
  */
14
14
 
15
- import fs from 'fs/promises'
16
- import path from 'path'
17
- import os from 'os'
18
- import { getPackageRoot } from '../utils/version'
19
- import { isNotFoundError } from '../types/fs'
15
+ import fs from 'node:fs/promises'
16
+ import os from 'node:os'
17
+ import path from 'node:path'
20
18
  import type {
21
- InstallResult,
22
- UninstallResult,
23
19
  CheckResult,
24
- SyncResult,
25
20
  GlobalConfigResult,
21
+ InstallResult,
22
+ SyncResult,
23
+ UninstallResult,
26
24
  } from '../types'
25
+ import { isNotFoundError } from '../types/fs'
26
+ import { getPackageRoot } from '../utils/version'
27
27
 
28
28
  // =============================================================================
29
29
  // Global Config
@@ -82,13 +82,18 @@ export async function installGlobalConfig(): Promise<GlobalConfigResult> {
82
82
  await fs.mkdir(activeProvider.configDir, { recursive: true })
83
83
 
84
84
  const globalConfigPath = path.join(activeProvider.configDir, activeProvider.contextFile)
85
- const templatePath = path.join(getPackageRoot(), 'templates', 'global', activeProvider.contextFile)
85
+ const templatePath = path.join(
86
+ getPackageRoot(),
87
+ 'templates',
88
+ 'global',
89
+ activeProvider.contextFile
90
+ )
86
91
 
87
92
  // Read template content
88
93
  let templateContent = ''
89
94
  try {
90
95
  templateContent = await fs.readFile(templatePath, 'utf-8')
91
- } catch (error) {
96
+ } catch (_error) {
92
97
  // Fallback if provider-specific template not found
93
98
  const fallbackTemplatePath = path.join(getPackageRoot(), 'templates/global/CLAUDE.md')
94
99
  templateContent = await fs.readFile(fallbackTemplatePath, 'utf-8')
@@ -133,7 +138,7 @@ export async function installGlobalConfig(): Promise<GlobalConfigResult> {
133
138
 
134
139
  if (!hasMarkers) {
135
140
  // No markers - append prjct section at the end
136
- const updatedContent = existingContent + '\n\n' + templateContent
141
+ const updatedContent = `${existingContent}\n\n${templateContent}`
137
142
  await fs.writeFile(globalConfigPath, updatedContent, 'utf-8')
138
143
  return {
139
144
  success: true,
@@ -183,10 +188,10 @@ export class CommandInstaller {
183
188
 
184
189
  constructor() {
185
190
  this.homeDir = os.homedir()
186
-
191
+
187
192
  const aiProvider = require('./ai-provider')
188
193
  const activeProvider = aiProvider.getActiveProvider()
189
-
194
+
190
195
  // Command paths are provider-specific
191
196
  if (activeProvider.name === 'gemini') {
192
197
  this.claudeCommandsPath = path.join(activeProvider.configDir, 'commands')
@@ -194,7 +199,7 @@ export class CommandInstaller {
194
199
  // Claude: Commands are in p/ subdirectory to avoid cluttering commands/
195
200
  this.claudeCommandsPath = path.join(activeProvider.configDir, 'commands', 'p')
196
201
  }
197
-
202
+
198
203
  this.claudeConfigPath = activeProvider.configDir
199
204
  this.templatesDir = path.join(getPackageRoot(), 'templates', 'commands')
200
205
  }
@@ -228,7 +233,7 @@ export class CommandInstaller {
228
233
  try {
229
234
  const files = await fs.readdir(this.templatesDir)
230
235
  return files.filter((f) => f.endsWith('.md'))
231
- } catch (error) {
236
+ } catch (_error) {
232
237
  // Fallback to core commands if template directory not accessible (ENOENT or other)
233
238
  return [
234
239
  'init.md',
@@ -332,7 +337,7 @@ export class CommandInstaller {
332
337
  // Try to remove the /p directory if empty
333
338
  try {
334
339
  await fs.rmdir(this.claudeCommandsPath)
335
- } catch (error) {
340
+ } catch (_error) {
336
341
  // Directory not empty or doesn't exist - that's fine (ENOTEMPTY or ENOENT)
337
342
  }
338
343
 
@@ -438,7 +443,7 @@ export class CommandInstaller {
438
443
  const aiProvider = require('./ai-provider')
439
444
  const activeProvider = aiProvider.getActiveProvider()
440
445
  const routerFile = activeProvider.name === 'gemini' ? 'p.toml' : 'p.md'
441
-
446
+
442
447
  try {
443
448
  const routerSource = path.join(this.templatesDir, routerFile)
444
449
  const routerDest = path.join(activeProvider.configDir, 'commands', routerFile)
@@ -10,19 +10,19 @@
10
10
  * @version 0.3.0
11
11
  */
12
12
 
13
- import fs from 'fs/promises'
14
- import path from 'path'
13
+ import fs from 'node:fs/promises'
14
+ import path from 'node:path'
15
15
  import * as jsonc from 'jsonc-parser'
16
- import pathManager from './path-manager'
17
- import authorDetector from './author-detector'
18
- import { VERSION } from '../utils/version'
19
- import { getTimestamp } from '../utils/date-helper'
20
16
  import { getErrorMessage } from '../errors'
17
+ import type { Author, GlobalConfig, LocalConfig } from '../types'
21
18
  import { isNotFoundError } from '../types/fs'
22
- import type { Author, LocalConfig, GlobalConfig } from '../types'
19
+ import { getTimestamp } from '../utils/date-helper'
20
+ import { VERSION } from '../utils/version'
21
+ import authorDetector from './author-detector'
22
+ import pathManager from './path-manager'
23
23
 
24
24
  // Re-export types for convenience
25
- export type { Author, LocalConfig, GlobalConfig } from '../types'
25
+ export type { Author, GlobalConfig, LocalConfig } from '../types'
26
26
 
27
27
  /**
28
28
  * Parse JSON or JSONC content safely
@@ -36,7 +36,9 @@ function parseJsonc<T>(content: string): T {
36
36
  })
37
37
  if (errors.length > 0) {
38
38
  const firstError = errors[0]
39
- throw new SyntaxError(`JSON parse error at offset ${firstError.offset}: ${jsonc.printParseErrorCode(firstError.error)}`)
39
+ throw new SyntaxError(
40
+ `JSON parse error at offset ${firstError.offset}: ${jsonc.printParseErrorCode(firstError.error)}`
41
+ )
40
42
  }
41
43
  return result
42
44
  }
@@ -72,7 +74,7 @@ class ConfigManager {
72
74
  await fs.mkdir(configDir, { recursive: true })
73
75
 
74
76
  const content = JSON.stringify(config, null, 2)
75
- await fs.writeFile(configPath, content + '\n', 'utf-8')
77
+ await fs.writeFile(configPath, `${content}\n`, 'utf-8')
76
78
  }
77
79
 
78
80
  /**
@@ -91,7 +93,9 @@ class ConfigManager {
91
93
  return null
92
94
  }
93
95
  // Log other errors for debugging
94
- console.warn(`Warning: Could not read global config for ${projectId}: ${getErrorMessage(error)}`)
96
+ console.warn(
97
+ `Warning: Could not read global config for ${projectId}: ${getErrorMessage(error)}`
98
+ )
95
99
  return null
96
100
  }
97
101
  }
@@ -106,7 +110,7 @@ class ConfigManager {
106
110
  await fs.mkdir(configDir, { recursive: true })
107
111
 
108
112
  const content = JSON.stringify(config, null, 2)
109
- await fs.writeFile(configPath, content + '\n', 'utf-8')
113
+ await fs.writeFile(configPath, `${content}\n`, 'utf-8')
110
114
  }
111
115
 
112
116
  /**
@@ -231,7 +235,7 @@ class ConfigManager {
231
235
  */
232
236
  async getProjectId(projectPath: string): Promise<string> {
233
237
  const config = await this.readConfig(projectPath)
234
- if (config && config.projectId) {
238
+ if (config?.projectId) {
235
239
  return config.projectId
236
240
  }
237
241
  return pathManager.generateProjectId(projectPath)
@@ -300,7 +304,7 @@ class ConfigManager {
300
304
  await this.addAuthor(projectId, {
301
305
  name: author.name ?? undefined,
302
306
  email: author.email ?? undefined,
303
- github: author.github ?? undefined
307
+ github: author.github ?? undefined,
304
308
  })
305
309
 
306
310
  return author.github || author.name || 'Unknown'
@@ -9,9 +9,9 @@
9
9
  * @version 0.6.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 os from 'node:os'
14
+ import path from 'node:path'
15
15
  import type { AIProviderName } from '../types/provider'
16
16
 
17
17
  interface EditorConfig {
@@ -65,7 +65,11 @@ class EditorsConfig {
65
65
  /**
66
66
  * Save installation configuration
67
67
  */
68
- async saveConfig(version: string, installPath: string, provider: AIProviderName = 'claude'): Promise<boolean> {
68
+ async saveConfig(
69
+ version: string,
70
+ installPath: string,
71
+ provider: AIProviderName = 'claude'
72
+ ): Promise<boolean> {
69
73
  try {
70
74
  await this.ensureConfigDir()
71
75
 
@@ -9,13 +9,13 @@
9
9
  * @version 0.2.1
10
10
  */
11
11
 
12
- import fs from 'fs/promises'
13
- import path from 'path'
14
- import crypto from 'crypto'
15
- import os from 'os'
12
+ import crypto from 'node:crypto'
13
+ import fs from 'node:fs/promises'
14
+ import os from 'node:os'
15
+ import path from 'node:path'
16
+ import type { SessionInfo } from '../types'
16
17
  import * as dateHelper from '../utils/date-helper'
17
18
  import * as fileHelper from '../utils/file-helper'
18
- import type { SessionInfo } from '../types'
19
19
 
20
20
  class PathManager {
21
21
  globalBaseDir: string
@@ -24,7 +24,9 @@ class PathManager {
24
24
 
25
25
  constructor() {
26
26
  const envOverride = process.env.PRJCT_CLI_HOME?.trim()
27
- this.globalBaseDir = envOverride ? path.resolve(envOverride) : path.join(os.homedir(), '.prjct-cli')
27
+ this.globalBaseDir = envOverride
28
+ ? path.resolve(envOverride)
29
+ : path.join(os.homedir(), '.prjct-cli')
28
30
  this.globalProjectsDir = path.join(this.globalBaseDir, 'projects')
29
31
  this.globalConfigDir = path.join(this.globalBaseDir, 'config')
30
32
  }
@@ -9,9 +9,9 @@
9
9
  */
10
10
 
11
11
  import {
12
- type PermissionsConfig,
13
- type PermissionLevel,
14
12
  buildDefaultPermissions,
13
+ type PermissionLevel,
14
+ type PermissionsConfig,
15
15
  } from '../schemas/permissions'
16
16
  import type { PermissionCheckResult } from '../types'
17
17
 
@@ -114,11 +114,12 @@ class PermissionManager {
114
114
  allowed: match.level === 'allow',
115
115
  level: match.level,
116
116
  matchedPattern: match.pattern,
117
- reason: match.level === 'deny'
118
- ? `Command denied by pattern: ${match.pattern}`
119
- : match.level === 'ask'
120
- ? `Command requires approval: ${match.pattern}`
121
- : undefined,
117
+ reason:
118
+ match.level === 'deny'
119
+ ? `Command denied by pattern: ${match.pattern}`
120
+ : match.level === 'ask'
121
+ ? `Command requires approval: ${match.pattern}`
122
+ : undefined,
122
123
  }
123
124
  }
124
125
 
@@ -145,11 +146,12 @@ class PermissionManager {
145
146
  allowed: match.level === 'allow',
146
147
  level: match.level,
147
148
  matchedPattern: match.pattern,
148
- reason: match.level === 'deny'
149
- ? `File operation denied: ${operation} on ${match.pattern}`
150
- : match.level === 'ask'
151
- ? `File operation requires approval: ${operation}`
152
- : undefined,
149
+ reason:
150
+ match.level === 'deny'
151
+ ? `File operation denied: ${operation} on ${match.pattern}`
152
+ : match.level === 'ask'
153
+ ? `File operation requires approval: ${operation}`
154
+ : undefined,
153
155
  }
154
156
  }
155
157
 
@@ -239,11 +241,12 @@ class PermissionManager {
239
241
  return {
240
242
  allowed: level === 'allow',
241
243
  level,
242
- reason: level === 'deny'
243
- ? 'External directory access denied'
244
- : level === 'ask'
245
- ? 'External directory access requires approval'
246
- : undefined,
244
+ reason:
245
+ level === 'deny'
246
+ ? 'External directory access denied'
247
+ : level === 'ask'
248
+ ? 'External directory access requires approval'
249
+ : undefined,
247
250
  }
248
251
  }
249
252
 
@@ -17,23 +17,22 @@
17
17
  * - scripts/postinstall.js (if npm scripts are enabled)
18
18
  */
19
19
 
20
- import { execSync } from 'child_process'
21
- import fs from 'fs'
22
- import path from 'path'
23
- import os from 'os'
24
- import installer from './command-installer'
25
- import editorsConfig from './editors-config'
26
- import { VERSION, getPackageRoot } from '../utils/version'
20
+ import { execSync } from 'node:child_process'
21
+ import fs from 'node:fs'
22
+ import os from 'node:os'
23
+ import path from 'node:path'
27
24
  import { isNotFoundError } from '../types/fs'
25
+ import type { AIProviderConfig, AIProviderName } from '../types/provider'
26
+ import { getPackageRoot, VERSION } from '../utils/version'
28
27
  import {
29
- selectProvider,
30
- detectProvider,
31
28
  detectAllProviders,
32
29
  detectAntigravity,
30
+ detectProvider,
33
31
  Providers,
34
- AntigravityProvider,
32
+ selectProvider,
35
33
  } from './ai-provider'
36
- import type { AIProviderName, AIProviderConfig } from '../types/provider'
34
+ import installer from './command-installer'
35
+ import editorsConfig from './editors-config'
37
36
 
38
37
  // Colors
39
38
  const GREEN = '\x1b[32m'
@@ -50,8 +49,8 @@ interface ProviderSetupResult {
50
49
  }
51
50
 
52
51
  interface SetupResults {
53
- provider: AIProviderName // Primary provider (for backward compat)
54
- providers: ProviderSetupResult[] // All installed providers
52
+ provider: AIProviderName // Primary provider (for backward compat)
53
+ providers: ProviderSetupResult[] // All installed providers
55
54
  cliInstalled: boolean
56
55
  commandsAdded: number
57
56
  commandsUpdated: number
@@ -61,7 +60,7 @@ interface SetupResults {
61
60
  /**
62
61
  * Check if an AI CLI is installed
63
62
  */
64
- async function hasAICLI(provider: AIProviderConfig): Promise<boolean> {
63
+ async function _hasAICLI(provider: AIProviderConfig): Promise<boolean> {
65
64
  const detection = detectProvider(provider.name)
66
65
  return detection.installed
67
66
  }
@@ -70,9 +69,8 @@ async function hasAICLI(provider: AIProviderConfig): Promise<boolean> {
70
69
  * Install AI CLI for the specified provider
71
70
  */
72
71
  async function installAICLI(provider: AIProviderConfig): Promise<boolean> {
73
- const packageName = provider.name === 'claude'
74
- ? '@anthropic-ai/claude-code'
75
- : '@google/gemini-cli'
72
+ const packageName =
73
+ provider.name === 'claude' ? '@anthropic-ai/claude-code' : '@google/gemini-cli'
76
74
 
77
75
  try {
78
76
  console.log(`${YELLOW}📦 ${provider.displayName} not found. Installing...${NC}`)
@@ -83,7 +81,9 @@ async function installAICLI(provider: AIProviderConfig): Promise<boolean> {
83
81
  console.log('')
84
82
  return true
85
83
  } catch (error) {
86
- console.log(`${YELLOW}⚠️ Failed to install ${provider.displayName}: ${(error as Error).message}${NC}`)
84
+ console.log(
85
+ `${YELLOW}⚠️ Failed to install ${provider.displayName}: ${(error as Error).message}${NC}`
86
+ )
87
87
  console.log(`${DIM}Please install manually: npm install -g ${packageName}${NC}`)
88
88
  console.log('')
89
89
  return false
@@ -97,7 +97,7 @@ export async function run(): Promise<SetupResults> {
97
97
  // Step 0: Detect all available providers
98
98
  const detection = detectAllProviders()
99
99
  const selection = selectProvider()
100
- const primaryProvider = Providers[selection.provider]
100
+ const _primaryProvider = Providers[selection.provider]
101
101
 
102
102
  const results: SetupResults = {
103
103
  provider: selection.provider,
@@ -281,7 +281,7 @@ async function installGeminiGlobalConfig(): Promise<{ success: boolean; action:
281
281
 
282
282
  if (!hasMarkers) {
283
283
  // No markers - append prjct section at the end
284
- const updatedContent = existingContent + '\n\n' + templateContent
284
+ const updatedContent = `${existingContent}\n\n${templateContent}`
285
285
  fs.writeFileSync(globalConfigPath, updatedContent, 'utf-8')
286
286
  return { success: true, action: 'appended' }
287
287
  }
@@ -317,7 +317,10 @@ async function installGeminiGlobalConfig(): Promise<{ success: boolean; action:
317
317
  * Antigravity uses SKILL.md files in ~/.gemini/antigravity/skills/
318
318
  * This is the recommended integration method (not MCP).
319
319
  */
320
- export async function installAntigravitySkill(): Promise<{ success: boolean; action: string | null }> {
320
+ export async function installAntigravitySkill(): Promise<{
321
+ success: boolean
322
+ action: string | null
323
+ }> {
321
324
  try {
322
325
  const antigravitySkillsDir = path.join(os.homedir(), '.gemini', 'antigravity', 'skills')
323
326
  const prjctSkillDir = path.join(antigravitySkillsDir, 'prjct')
@@ -408,8 +411,7 @@ export async function installCursorProject(projectRoot: string): Promise<{
408
411
  // Copy individual command files → .cursor/commands/
409
412
  // This enables /sync, /task, /done, /ship, etc. syntax in Cursor
410
413
  if (fs.existsSync(cursorCommandsSource)) {
411
- const commandFiles = fs.readdirSync(cursorCommandsSource)
412
- .filter(f => f.endsWith('.md'))
414
+ const commandFiles = fs.readdirSync(cursorCommandsSource).filter((f) => f.endsWith('.md'))
413
415
 
414
416
  for (const file of commandFiles) {
415
417
  const src = path.join(cursorCommandsSource, file)
@@ -469,8 +471,8 @@ async function addCursorToGitignore(projectRoot: string): Promise<boolean> {
469
471
 
470
472
  // Append to .gitignore
471
473
  const newContent = fileExists
472
- ? content.trimEnd() + '\n\n' + entriesToAdd.join('\n') + '\n'
473
- : entriesToAdd.join('\n') + '\n'
474
+ ? `${content.trimEnd()}\n\n${entriesToAdd.join('\n')}\n`
475
+ : `${entriesToAdd.join('\n')}\n`
474
476
 
475
477
  fs.writeFileSync(gitignorePath, newContent, 'utf-8')
476
478
  return true
@@ -537,7 +539,12 @@ export async function installWindsurfProject(projectRoot: string): Promise<{
537
539
  const routerDest = path.join(rulesDir, 'prjct.md')
538
540
 
539
541
  const routerSource = path.join(getPackageRoot(), 'templates', 'windsurf', 'router.md')
540
- const windsurfWorkflowsSource = path.join(getPackageRoot(), 'templates', 'windsurf', 'workflows')
542
+ const windsurfWorkflowsSource = path.join(
543
+ getPackageRoot(),
544
+ 'templates',
545
+ 'windsurf',
546
+ 'workflows'
547
+ )
541
548
 
542
549
  // Ensure directories exist
543
550
  fs.mkdirSync(rulesDir, { recursive: true })
@@ -552,8 +559,7 @@ export async function installWindsurfProject(projectRoot: string): Promise<{
552
559
  // Copy individual workflow files → .windsurf/workflows/
553
560
  // This enables /sync, /task, /done, /ship, etc. syntax in Windsurf
554
561
  if (fs.existsSync(windsurfWorkflowsSource)) {
555
- const workflowFiles = fs.readdirSync(windsurfWorkflowsSource)
556
- .filter(f => f.endsWith('.md'))
562
+ const workflowFiles = fs.readdirSync(windsurfWorkflowsSource).filter((f) => f.endsWith('.md'))
557
563
 
558
564
  for (const file of workflowFiles) {
559
565
  const src = path.join(windsurfWorkflowsSource, file)
@@ -613,8 +619,8 @@ async function addWindsurfToGitignore(projectRoot: string): Promise<boolean> {
613
619
 
614
620
  // Append to .gitignore
615
621
  const newContent = fileExists
616
- ? content.trimEnd() + '\n\n' + entriesToAdd.join('\n') + '\n'
617
- : entriesToAdd.join('\n') + '\n'
622
+ ? `${content.trimEnd()}\n\n${entriesToAdd.join('\n')}\n`
623
+ : `${entriesToAdd.join('\n')}\n`
618
624
 
619
625
  fs.writeFileSync(gitignorePath, newContent, 'utf-8')
620
626
  return true
@@ -654,9 +660,10 @@ async function migrateProjectsCliVersion(): Promise<void> {
654
660
  return
655
661
  }
656
662
 
657
- const projectDirs = fs.readdirSync(projectsDir, { withFileTypes: true })
658
- .filter(dirent => dirent.isDirectory())
659
- .map(dirent => dirent.name)
663
+ const projectDirs = fs
664
+ .readdirSync(projectsDir, { withFileTypes: true })
665
+ .filter((dirent) => dirent.isDirectory())
666
+ .map((dirent) => dirent.name)
660
667
 
661
668
  let migrated = 0
662
669
 
@@ -795,10 +802,7 @@ async function installStatusLine(): Promise<void> {
795
802
  if (fs.existsSync(sourceScript)) {
796
803
  // Copy script and update version
797
804
  let scriptContent = fs.readFileSync(sourceScript, 'utf8')
798
- scriptContent = scriptContent.replace(
799
- /CLI_VERSION="[^"]*"/,
800
- `CLI_VERSION="${VERSION}"`
801
- )
805
+ scriptContent = scriptContent.replace(/CLI_VERSION="[^"]*"/, `CLI_VERSION="${VERSION}"`)
802
806
  fs.writeFileSync(prjctStatusLinePath, scriptContent, { mode: 0o755 })
803
807
 
804
808
  // Copy lib/ modules
@@ -910,7 +914,7 @@ function ensureStatusLineSymlink(linkPath: string, targetPath: string): void {
910
914
  }
911
915
  // Create symlink
912
916
  fs.symlinkSync(targetPath, linkPath)
913
- } catch (error) {
917
+ } catch (_error) {
914
918
  // If symlink fails (e.g., Windows, permission issues), try copy instead
915
919
  try {
916
920
  if (fs.existsSync(targetPath)) {
@@ -4,10 +4,10 @@
4
4
  * @version 0.5.0
5
5
  */
6
6
 
7
- import https from 'https'
8
- import fs from 'fs'
9
- import path from 'path'
10
- import os from 'os'
7
+ import fs from 'node:fs'
8
+ import https from 'node:https'
9
+ import os from 'node:os'
10
+ import path from 'node:path'
11
11
  import chalk from 'chalk'
12
12
 
13
13
  interface UpdateCache {
@@ -162,7 +162,7 @@ class UpdateChecker {
162
162
  const cache = this.readCache()
163
163
  const now = Date.now()
164
164
 
165
- if (cache && cache.lastCheck && now - cache.lastCheck < this.checkInterval) {
165
+ if (cache?.lastCheck && now - cache.lastCheck < this.checkInterval) {
166
166
  // Cache is still valid
167
167
  if (cache.latestVersion && this.compareVersions(cache.latestVersion, currentVersion) > 0) {
168
168
  return {
@@ -6,7 +6,7 @@
6
6
  * The actual AI call happens through Claude Code's execution context.
7
7
  */
8
8
 
9
- import type { Issue, EnrichedIssue } from './types'
9
+ import type { EnrichedIssue, Issue } from './types'
10
10
 
11
11
  // =============================================================================
12
12
  // Enrichment Templates
@@ -81,13 +81,9 @@ export function generateLLMPrompt(
81
81
  projectContext: ProjectContext,
82
82
  enrichment: EnrichmentResult
83
83
  ): string {
84
- const filesList = enrichment.affectedFiles
85
- .map(f => `- ${f}`)
86
- .join('\n')
84
+ const filesList = enrichment.affectedFiles.map((f) => `- ${f}`).join('\n')
87
85
 
88
- const acList = enrichment.acceptanceCriteria
89
- .map(ac => `- [ ] ${ac}`)
90
- .join('\n')
86
+ const acList = enrichment.acceptanceCriteria.map((ac) => `- [ ] ${ac}`).join('\n')
91
87
 
92
88
  return `## Task: ${issue.title}
93
89
 
@@ -150,10 +146,7 @@ export interface EnrichmentResult {
150
146
  /**
151
147
  * Build enriched issue from result
152
148
  */
153
- export function buildEnrichedIssue(
154
- issue: Issue,
155
- enrichment: EnrichmentResult
156
- ): EnrichedIssue {
149
+ export function buildEnrichedIssue(issue: Issue, enrichment: EnrichmentResult): EnrichedIssue {
157
150
  return {
158
151
  ...issue,
159
152
  enrichment: {
@@ -213,8 +206,8 @@ export function formatEnrichmentAsMarkdown(enrichment: EnrichmentResult): string
213
206
  export function parseEnrichmentResponse(response: string): EnrichmentResult | null {
214
207
  try {
215
208
  // Extract JSON from response (may be wrapped in markdown code block)
216
- const jsonMatch = response.match(/```(?:json)?\s*([\s\S]*?)```/) ||
217
- response.match(/\{[\s\S]*\}/)
209
+ const jsonMatch =
210
+ response.match(/```(?:json)?\s*([\s\S]*?)```/) || response.match(/\{[\s\S]*\}/)
218
211
 
219
212
  if (!jsonMatch) {
220
213
  console.error('[enricher] No JSON found in response')
@@ -232,12 +225,8 @@ export function parseEnrichmentResponse(response: string): EnrichmentResult | nu
232
225
 
233
226
  return {
234
227
  description: parsed.description,
235
- acceptanceCriteria: Array.isArray(parsed.acceptanceCriteria)
236
- ? parsed.acceptanceCriteria
237
- : [],
238
- affectedFiles: Array.isArray(parsed.affectedFiles)
239
- ? parsed.affectedFiles
240
- : [],
228
+ acceptanceCriteria: Array.isArray(parsed.acceptanceCriteria) ? parsed.acceptanceCriteria : [],
229
+ affectedFiles: Array.isArray(parsed.affectedFiles) ? parsed.affectedFiles : [],
241
230
  technicalNotes: parsed.technicalNotes || '',
242
231
  estimatedComplexity: parsed.estimatedComplexity,
243
232
  suggestedApproach: parsed.suggestedApproach,
@@ -3,6 +3,6 @@
3
3
  * Unified interface for Linear, Jira, Monday, and other issue trackers.
4
4
  */
5
5
 
6
- export * from './types'
7
6
  export * from './enricher'
8
- export { issueTrackerManager, IssueTrackerManager } from './manager'
7
+ export { IssueTrackerManager, issueTrackerManager } from './manager'
8
+ export * from './types'