prjct-cli 1.6.2 → 1.6.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 (66) hide show
  1. package/CHANGELOG.md +14 -2
  2. package/core/agentic/agent-router.ts +4 -4
  3. package/core/agentic/command-executor.ts +5 -4
  4. package/core/agentic/ground-truth.ts +2 -2
  5. package/core/agentic/orchestrator-executor.ts +2 -2
  6. package/core/agentic/prompt-builder.ts +4 -4
  7. package/core/ai-tools/generator.ts +2 -1
  8. package/core/cli/linear.ts +5 -3
  9. package/core/cli/start.ts +3 -2
  10. package/core/commands/analysis.ts +8 -7
  11. package/core/commands/analytics.ts +5 -4
  12. package/core/commands/cleanup.ts +7 -7
  13. package/core/commands/context.ts +3 -3
  14. package/core/commands/design.ts +3 -2
  15. package/core/commands/planning.ts +13 -12
  16. package/core/commands/registry.ts +2 -1
  17. package/core/commands/setup.ts +2 -1
  18. package/core/commands/shipping.ts +3 -3
  19. package/core/commands/snapshots.ts +11 -11
  20. package/core/commands/uninstall.ts +4 -3
  21. package/core/commands/workflow.ts +13 -12
  22. package/core/context-tools/index.ts +2 -1
  23. package/core/domain/agent-generator.ts +2 -1
  24. package/core/domain/context-estimator.ts +2 -1
  25. package/core/domain/task-stack.ts +3 -3
  26. package/core/index.ts +5 -4
  27. package/core/infrastructure/capability-installer.ts +2 -1
  28. package/core/infrastructure/command-installer.ts +9 -9
  29. package/core/infrastructure/editors-config.ts +6 -5
  30. package/core/infrastructure/setup.ts +14 -13
  31. package/core/infrastructure/update-checker.ts +2 -1
  32. package/core/integrations/issue-tracker/enricher.ts +2 -1
  33. package/core/integrations/issue-tracker/manager.ts +3 -2
  34. package/core/integrations/jira/client.ts +3 -2
  35. package/core/integrations/linear/client.ts +2 -1
  36. package/core/integrations/linear/sync.ts +3 -2
  37. package/core/plugin/builtin/webhook.ts +2 -1
  38. package/core/plugin/hooks.ts +4 -6
  39. package/core/plugin/loader.ts +2 -2
  40. package/core/plugin/registry.ts +3 -3
  41. package/core/server/routes.ts +4 -4
  42. package/core/services/hooks-service.ts +3 -2
  43. package/core/services/memory-service.ts +5 -5
  44. package/core/services/project-service.ts +3 -3
  45. package/core/services/skill-installer.ts +4 -3
  46. package/core/services/staleness-checker.ts +2 -1
  47. package/core/services/sync-service.ts +2 -2
  48. package/core/services/sync-verifier.ts +2 -2
  49. package/core/services/watch-service.ts +2 -1
  50. package/core/session/metrics.ts +3 -3
  51. package/core/session/session-log-manager.ts +2 -1
  52. package/core/session/task-session-manager.ts +2 -2
  53. package/core/types/fs.ts +25 -9
  54. package/core/types/index.ts +2 -0
  55. package/core/types/utils.ts +2 -0
  56. package/core/utils/keychain.ts +2 -1
  57. package/core/utils/project-credentials.ts +2 -1
  58. package/core/utils/session-helper.ts +2 -1
  59. package/core/utils/version.ts +2 -1
  60. package/core/workflow/workflow-preferences.ts +2 -1
  61. package/dist/bin/prjct.mjs +176 -135
  62. package/dist/core/infrastructure/command-installer.js +20 -10
  63. package/dist/core/infrastructure/editors-config.js +15 -5
  64. package/dist/core/infrastructure/setup.js +70 -27
  65. package/dist/core/utils/version.js +11 -1
  66. package/package.json +1 -1
@@ -14,6 +14,7 @@ import { linearService } from '../integrations/linear'
14
14
  import { generateUUID } from '../schemas'
15
15
  import { queueStorage, stateStorage } from '../storage'
16
16
  import type { CommandResult } from '../types'
17
+ import { getErrorMessage } from '../types/fs'
17
18
  import { showNextSteps, showStateInfo } from '../utils/next-steps'
18
19
  import { getLinearApiKey, getProjectCredentials } from '../utils/project-credentials'
19
20
  import {
@@ -145,8 +146,8 @@ export class WorkflowCommands extends PrjctCommandsBase {
145
146
  return { success: true, task: currentTask.description, currentTask }
146
147
  }
147
148
  } catch (error) {
148
- out.fail((error as Error).message)
149
- return { success: false, error: (error as Error).message }
149
+ out.fail(getErrorMessage(error))
150
+ return { success: false, error: getErrorMessage(error) }
150
151
  }
151
152
  }
152
153
 
@@ -231,8 +232,8 @@ export class WorkflowCommands extends PrjctCommandsBase {
231
232
 
232
233
  return { success: true, task, duration }
233
234
  } catch (error) {
234
- out.fail((error as Error).message)
235
- return { success: false, error: (error as Error).message }
235
+ out.fail(getErrorMessage(error))
236
+ return { success: false, error: getErrorMessage(error) }
236
237
  }
237
238
  }
238
239
 
@@ -263,8 +264,8 @@ export class WorkflowCommands extends PrjctCommandsBase {
263
264
 
264
265
  return { success: true, tasks, count: tasks.length }
265
266
  } catch (error) {
266
- out.fail((error as Error).message)
267
- return { success: false, error: (error as Error).message }
267
+ out.fail(getErrorMessage(error))
268
+ return { success: false, error: getErrorMessage(error) }
268
269
  }
269
270
  }
270
271
 
@@ -305,8 +306,8 @@ export class WorkflowCommands extends PrjctCommandsBase {
305
306
 
306
307
  return { success: true, task: currentTask.description, reason }
307
308
  } catch (error) {
308
- out.fail((error as Error).message)
309
- return { success: false, error: (error as Error).message }
309
+ out.fail(getErrorMessage(error))
310
+ return { success: false, error: getErrorMessage(error) }
310
311
  }
311
312
  }
312
313
 
@@ -353,8 +354,8 @@ export class WorkflowCommands extends PrjctCommandsBase {
353
354
 
354
355
  return { success: true, task: resumed.description }
355
356
  } catch (error) {
356
- out.fail((error as Error).message)
357
- return { success: false, error: (error as Error).message }
357
+ out.fail(getErrorMessage(error))
358
+ return { success: false, error: getErrorMessage(error) }
358
359
  }
359
360
  }
360
361
 
@@ -411,8 +412,8 @@ export class WorkflowCommands extends PrjctCommandsBase {
411
412
  },
412
413
  }
413
414
  } catch (error) {
414
- out.fail((error as Error).message)
415
- return { success: false, error: (error as Error).message }
415
+ out.fail(getErrorMessage(error))
416
+ return { success: false, error: getErrorMessage(error) }
416
417
  }
417
418
  }
418
419
  }
@@ -16,6 +16,7 @@
16
16
  */
17
17
 
18
18
  import { metricsStorage } from '../storage/metrics-storage'
19
+ import { getErrorMessage } from '../types/fs'
19
20
  import { getTimestamp } from '../utils/date-helper'
20
21
  import { findRelevantFiles } from './files-tool'
21
22
  import { analyzeImports } from './imports-tool'
@@ -115,7 +116,7 @@ export async function runContextTool(
115
116
  return {
116
117
  tool: 'error',
117
118
  result: {
118
- error: (error as Error).message,
119
+ error: getErrorMessage(error),
119
120
  code: 'EXECUTION_ERROR',
120
121
  },
121
122
  }
@@ -7,6 +7,7 @@
7
7
  import fs from 'node:fs/promises'
8
8
  import os from 'node:os'
9
9
  import path from 'node:path'
10
+ import { getErrorMessage } from '../types/fs'
10
11
  import log from '../utils/logger'
11
12
  import AgentLoader from './agent-loader'
12
13
 
@@ -140,7 +141,7 @@ ${config.contextFilter || 'Only relevant files'}
140
141
  }
141
142
  }
142
143
  } catch (error) {
143
- log.error('Agent cleanup failed:', (error as Error).message)
144
+ log.error('Agent cleanup failed:', getErrorMessage(error))
144
145
  }
145
146
 
146
147
  return removed
@@ -8,6 +8,7 @@
8
8
  */
9
9
 
10
10
  import { glob } from 'glob'
11
+ import { getErrorMessage } from '../types/fs'
11
12
  import log from '../utils/logger'
12
13
 
13
14
  interface TaskAnalysis {
@@ -157,7 +158,7 @@ class ContextEstimator {
157
158
  // Remove duplicates and sort
158
159
  return [...new Set(files)].sort()
159
160
  } catch (error) {
160
- log.error('Error finding files:', (error as Error).message)
161
+ log.error('Error finding files:', getErrorMessage(error))
161
162
  return []
162
163
  }
163
164
  }
@@ -14,7 +14,7 @@ import type {
14
14
  TaskStackSummary,
15
15
  TaskSwitchResult,
16
16
  } from '../types'
17
- import { isNotFoundError } from '../types/fs'
17
+ import { getErrorMessage, isNotFoundError } from '../types/fs'
18
18
  import log from '../utils/logger'
19
19
 
20
20
  const execAsync = promisify(exec)
@@ -150,7 +150,7 @@ export async function readStack(stackPath: string): Promise<TaskStackEntry[]> {
150
150
  try {
151
151
  entries.push(JSON.parse(line))
152
152
  } catch (error) {
153
- log.error('Error parsing stack line:', (error as Error).message)
153
+ log.error('Error parsing stack line:', getErrorMessage(error))
154
154
  }
155
155
  }
156
156
 
@@ -300,7 +300,7 @@ export class TaskStack {
300
300
  } catch (error) {
301
301
  // No now.md or error reading, just create empty stack
302
302
  await ensureStackFile(this.stackPath)
303
- return { migrated: true, hadTask: false, error: (error as Error).message }
303
+ return { migrated: true, hadTask: false, error: getErrorMessage(error) }
304
304
  }
305
305
  }
306
306
 
package/core/index.ts CHANGED
@@ -14,6 +14,7 @@ import type { CommandMeta } from './commands/registry'
14
14
  import { detectAllProviders, detectAntigravity } from './infrastructure/ai-provider'
15
15
  import configManager from './infrastructure/config-manager'
16
16
  import { sessionTracker } from './services/session-tracker'
17
+ import { getErrorMessage, getErrorStack } from './types/fs'
17
18
  import { getError } from './utils/error-messages'
18
19
  import { fileExists } from './utils/fs-helpers'
19
20
  import out from './utils/output'
@@ -199,9 +200,9 @@ async function main(): Promise<void> {
199
200
  out.end()
200
201
  process.exit(result?.success ? 0 : 1)
201
202
  } catch (error) {
202
- console.error('Error:', (error as Error).message)
203
+ console.error('Error:', getErrorMessage(error))
203
204
  if (process.env.DEBUG) {
204
- console.error((error as Error).stack)
205
+ console.error(getErrorStack(error))
205
206
  }
206
207
  // Show branding footer even on error
207
208
  out.end()
@@ -440,9 +441,9 @@ MORE INFO
440
441
 
441
442
  // Run CLI
442
443
  main().catch((error) => {
443
- console.error('Fatal error:', (error as Error).message)
444
+ console.error('Fatal error:', getErrorMessage(error))
444
445
  if (process.env.DEBUG) {
445
- console.error((error as Error).stack)
446
+ console.error(getErrorStack(error))
446
447
  }
447
448
  process.exit(1)
448
449
  })
@@ -10,6 +10,7 @@
10
10
 
11
11
  import { exec } from 'node:child_process'
12
12
  import { promisify } from 'node:util'
13
+ import { getErrorMessage } from '../types/fs'
13
14
 
14
15
  const execAsync = promisify(exec)
15
16
 
@@ -61,7 +62,7 @@ class CapabilityInstaller {
61
62
  success: false,
62
63
  capability,
63
64
  command,
64
- error: (error as Error).message,
65
+ error: getErrorMessage(error),
65
66
  }
66
67
  }
67
68
  }
@@ -22,7 +22,7 @@ import type {
22
22
  SyncResult,
23
23
  UninstallResult,
24
24
  } from '../types'
25
- import { isNotFoundError } from '../types/fs'
25
+ import { getErrorMessage, isNotFoundError } from '../types/fs'
26
26
  import { getPackageRoot } from '../utils/version'
27
27
 
28
28
  // =============================================================================
@@ -150,7 +150,7 @@ export async function installDocs(): Promise<{ success: boolean; error?: string
150
150
 
151
151
  return { success: true }
152
152
  } catch (error) {
153
- return { success: false, error: (error as Error).message }
153
+ return { success: false, error: getErrorMessage(error) }
154
154
  }
155
155
  }
156
156
 
@@ -277,7 +277,7 @@ export async function installGlobalConfig(): Promise<GlobalConfigResult> {
277
277
  } catch (error) {
278
278
  return {
279
279
  success: false,
280
- error: (error as Error).message,
280
+ error: getErrorMessage(error),
281
281
  action: 'failed',
282
282
  }
283
283
  }
@@ -409,7 +409,7 @@ export class CommandInstaller {
409
409
 
410
410
  installed.push(file.replace('.md', ''))
411
411
  } catch (error) {
412
- errors.push({ file, error: (error as Error).message })
412
+ errors.push({ file, error: getErrorMessage(error) })
413
413
  }
414
414
  }
415
415
 
@@ -422,7 +422,7 @@ export class CommandInstaller {
422
422
  } catch (error) {
423
423
  return {
424
424
  success: false,
425
- error: (error as Error).message,
425
+ error: getErrorMessage(error),
426
426
  }
427
427
  }
428
428
  }
@@ -443,7 +443,7 @@ export class CommandInstaller {
443
443
  uninstalled.push(file.replace('.md', ''))
444
444
  } catch (error) {
445
445
  if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {
446
- errors.push({ file, error: (error as Error).message })
446
+ errors.push({ file, error: getErrorMessage(error) })
447
447
  }
448
448
  }
449
449
  }
@@ -463,7 +463,7 @@ export class CommandInstaller {
463
463
  } catch (error) {
464
464
  return {
465
465
  success: false,
466
- error: (error as Error).message,
466
+ error: getErrorMessage(error),
467
467
  }
468
468
  }
469
469
  }
@@ -673,7 +673,7 @@ export class CommandInstaller {
673
673
  results.updated++
674
674
  }
675
675
  } catch (error) {
676
- results.errors!.push({ file, error: (error as Error).message })
676
+ results.errors!.push({ file, error: getErrorMessage(error) })
677
677
  }
678
678
  }
679
679
 
@@ -685,7 +685,7 @@ export class CommandInstaller {
685
685
  } catch (error) {
686
686
  return {
687
687
  success: false,
688
- error: (error as Error).message,
688
+ error: getErrorMessage(error),
689
689
  added: 0,
690
690
  updated: 0,
691
691
  removed: 0,
@@ -12,6 +12,7 @@
12
12
  import fs from 'node:fs/promises'
13
13
  import os from 'node:os'
14
14
  import path from 'node:path'
15
+ import { getErrorMessage } from '../types/fs'
15
16
  import type { AIProviderName } from '../types/provider'
16
17
 
17
18
  interface EditorConfig {
@@ -42,7 +43,7 @@ class EditorsConfig {
42
43
  try {
43
44
  await fs.mkdir(this.configDir, { recursive: true })
44
45
  } catch (error) {
45
- console.error('[editors-config] Error creating config directory:', (error as Error).message)
46
+ console.error('[editors-config] Error creating config directory:', getErrorMessage(error))
46
47
  }
47
48
  }
48
49
 
@@ -57,7 +58,7 @@ class EditorsConfig {
57
58
  if ((error as NodeJS.ErrnoException).code === 'ENOENT') {
58
59
  return null
59
60
  }
60
- console.error('[editors-config] Error loading config:', (error as Error).message)
61
+ console.error('[editors-config] Error loading config:', getErrorMessage(error))
61
62
  return null
62
63
  }
63
64
  }
@@ -85,7 +86,7 @@ class EditorsConfig {
85
86
 
86
87
  return true
87
88
  } catch (error) {
88
- console.error('[editors-config] Error saving config:', (error as Error).message)
89
+ console.error('[editors-config] Error saving config:', getErrorMessage(error))
89
90
  return false
90
91
  }
91
92
  }
@@ -132,7 +133,7 @@ class EditorsConfig {
132
133
 
133
134
  return true
134
135
  } catch (error) {
135
- console.error('[editors-config] Error updating version:', (error as Error).message)
136
+ console.error('[editors-config] Error updating version:', getErrorMessage(error))
136
137
  return false
137
138
  }
138
139
  }
@@ -161,7 +162,7 @@ class EditorsConfig {
161
162
  }
162
163
  return true
163
164
  } catch (error) {
164
- console.error('[editors-config] Error deleting config:', (error as Error).message)
165
+ console.error('[editors-config] Error deleting config:', getErrorMessage(error))
165
166
  return false
166
167
  }
167
168
  }
@@ -24,9 +24,10 @@ import path from 'node:path'
24
24
  import chalk from 'chalk'
25
25
  import { getTimeout } from '../constants'
26
26
  import { dependencyValidator } from '../services/dependency-validator'
27
- import { isNotFoundError } from '../types/fs'
27
+ import { getErrorMessage, isNotFoundError } from '../types/fs'
28
28
  import type { AIProviderConfig, AIProviderName } from '../types/provider'
29
29
  import { fileExists } from '../utils/fs-helpers'
30
+ import log from '../utils/logger'
30
31
  import { getPackageRoot, VERSION } from '../utils/version'
31
32
  import {
32
33
  detectAllProviders,
@@ -270,7 +271,7 @@ async function installGeminiRouter(): Promise<boolean> {
270
271
  }
271
272
  return false
272
273
  } catch (error) {
273
- console.error(`Gemini router warning: ${(error as Error).message}`)
274
+ log.warn(`Gemini router warning: ${getErrorMessage(error)}`)
274
275
  return false
275
276
  }
276
277
  }
@@ -340,7 +341,7 @@ async function installGeminiGlobalConfig(): Promise<{ success: boolean; action:
340
341
  await fs.writeFile(globalConfigPath, updatedContent, 'utf-8')
341
342
  return { success: true, action: 'updated' }
342
343
  } catch (error) {
343
- console.error(`Gemini config warning: ${(error as Error).message}`)
344
+ log.warn(`Gemini config warning: ${getErrorMessage(error)}`)
344
345
  return { success: false, action: null }
345
346
  }
346
347
  }
@@ -373,7 +374,7 @@ export async function installAntigravitySkill(): Promise<{
373
374
 
374
375
  // Read template content
375
376
  if (!(await fileExists(templatePath))) {
376
- console.error('Antigravity SKILL.md template not found')
377
+ log.warn('Antigravity SKILL.md template not found')
377
378
  return { success: false, action: null }
378
379
  }
379
380
 
@@ -384,7 +385,7 @@ export async function installAntigravitySkill(): Promise<{
384
385
 
385
386
  return { success: true, action: skillExists ? 'updated' : 'created' }
386
387
  } catch (error) {
387
- console.error(`Antigravity skill warning: ${(error as Error).message}`)
388
+ log.warn(`Antigravity skill warning: ${getErrorMessage(error)}`)
388
389
  return { success: false, action: null }
389
390
  }
390
391
  }
@@ -465,7 +466,7 @@ export async function installCursorProject(projectRoot: string): Promise<{
465
466
  result.success = result.rulesCreated || result.commandsCreated
466
467
  return result
467
468
  } catch (error) {
468
- console.error(`Cursor installation warning: ${(error as Error).message}`)
469
+ log.warn(`Cursor installation warning: ${getErrorMessage(error)}`)
469
470
  return result
470
471
  }
471
472
  }
@@ -515,7 +516,7 @@ async function addCursorToGitignore(projectRoot: string): Promise<boolean> {
515
516
  await fs.writeFile(gitignorePath, newContent, 'utf-8')
516
517
  return true
517
518
  } catch (error) {
518
- console.error(`Gitignore update warning: ${(error as Error).message}`)
519
+ log.warn(`Gitignore update warning: ${getErrorMessage(error)}`)
519
520
  return false
520
521
  }
521
522
  }
@@ -615,7 +616,7 @@ export async function installWindsurfProject(projectRoot: string): Promise<{
615
616
  result.success = result.rulesCreated || result.workflowsCreated
616
617
  return result
617
618
  } catch (error) {
618
- console.error(`Windsurf installation warning: ${(error as Error).message}`)
619
+ log.warn(`Windsurf installation warning: ${getErrorMessage(error)}`)
619
620
  return result
620
621
  }
621
622
  }
@@ -665,7 +666,7 @@ async function addWindsurfToGitignore(projectRoot: string): Promise<boolean> {
665
666
  await fs.writeFile(gitignorePath, newContent, 'utf-8')
666
667
  return true
667
668
  } catch (error) {
668
- console.error(`Gitignore update warning: ${(error as Error).message}`)
669
+ log.warn(`Gitignore update warning: ${getErrorMessage(error)}`)
669
670
  return false
670
671
  }
671
672
  }
@@ -738,7 +739,7 @@ async function migrateProjectsCliVersion(): Promise<void> {
738
739
  // Silently fail if projects directory doesn't exist
739
740
  if (!isNotFoundError(error)) {
740
741
  // Log unexpected errors but don't crash - migration is optional
741
- console.error(`Migration warning: ${(error as Error).message}`)
742
+ log.warn(`Migration warning: ${getErrorMessage(error)}`)
742
743
  }
743
744
  }
744
745
  }
@@ -912,7 +913,7 @@ echo "prjct"
912
913
  // Silently fail if directories don't exist
913
914
  if (!isNotFoundError(error)) {
914
915
  // Log unexpected errors but don't crash - status line is optional
915
- console.error(`Status line warning: ${(error as Error).message}`)
916
+ log.warn(`Status line warning: ${getErrorMessage(error)}`)
916
917
  }
917
918
  }
918
919
  }
@@ -965,7 +966,7 @@ async function installContext7MCP(): Promise<void> {
965
966
  }
966
967
  } catch (error) {
967
968
  // Non-fatal error, just log
968
- console.error(`Context7 MCP setup warning: ${(error as Error).message}`)
969
+ log.warn(`Context7 MCP setup warning: ${getErrorMessage(error)}`)
969
970
  }
970
971
  }
971
972
 
@@ -1018,7 +1019,7 @@ async function ensureStatusLineSymlink(linkPath: string, targetPath: string): Pr
1018
1019
  } catch (copyError) {
1019
1020
  // Both symlink and copy failed - log if unexpected error
1020
1021
  if (!isNotFoundError(copyError)) {
1021
- console.error(`Symlink fallback warning: ${(copyError as Error).message}`)
1022
+ log.warn(`Symlink fallback warning: ${(copyError as Error).message}`)
1022
1023
  }
1023
1024
  }
1024
1025
  }
@@ -9,6 +9,7 @@ import https from 'node:https'
9
9
  import os from 'node:os'
10
10
  import path from 'node:path'
11
11
  import chalk from 'chalk'
12
+ import { getErrorMessage } from '../types/fs'
12
13
  import { fileExists } from '../utils/fs-helpers'
13
14
 
14
15
  interface UpdateCache {
@@ -44,7 +45,7 @@ class UpdateChecker {
44
45
  const packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf8'))
45
46
  return packageJson.version
46
47
  } catch (error) {
47
- console.error('Error reading package version:', (error as Error).message)
48
+ console.error('Error reading package version:', getErrorMessage(error))
48
49
  return null
49
50
  }
50
51
  }
@@ -6,6 +6,7 @@
6
6
  * The actual AI call happens through Claude Code's execution context.
7
7
  */
8
8
 
9
+ import { getErrorMessage } from '../../types/fs'
9
10
  import type { EnrichedIssue, Issue } from './types'
10
11
 
11
12
  // =============================================================================
@@ -233,7 +234,7 @@ export function parseEnrichmentResponse(response: string): EnrichmentResult | nu
233
234
  relatedCode: parsed.relatedCode,
234
235
  }
235
236
  } catch (error) {
236
- console.error('[enricher] Failed to parse enrichment:', (error as Error).message)
237
+ console.error('[enricher] Failed to parse enrichment:', getErrorMessage(error))
237
238
  return null
238
239
  }
239
240
  }
@@ -3,6 +3,7 @@
3
3
  * Orchestrates multiple issue tracker providers and enrichment.
4
4
  */
5
5
 
6
+ import { getErrorMessage } from '../../types/fs'
6
7
  import { jiraProvider } from '../jira/client'
7
8
  import { linearProvider } from '../linear/client'
8
9
  import {
@@ -241,7 +242,7 @@ export class IssueTrackerManager {
241
242
  } catch (error) {
242
243
  result.errors.push({
243
244
  issueId: issue.externalId,
244
- error: (error as Error).message,
245
+ error: getErrorMessage(error),
245
246
  })
246
247
  }
247
248
  }
@@ -251,7 +252,7 @@ export class IssueTrackerManager {
251
252
  } catch (error) {
252
253
  result.errors.push({
253
254
  issueId: 'sync',
254
- error: (error as Error).message,
255
+ error: getErrorMessage(error),
255
256
  })
256
257
  return result
257
258
  }
@@ -14,6 +14,7 @@
14
14
  * - Requires MCP server configured in ~/.claude/mcp.json
15
15
  */
16
16
 
17
+ import { getErrorMessage } from '../../types/fs'
17
18
  import type {
18
19
  CreateIssueInput,
19
20
  FetchOptions,
@@ -261,7 +262,7 @@ export class JiraProvider implements IssueTrackerProvider {
261
262
  this.baseUrl = ''
262
263
  this.auth = ''
263
264
  this._authMode = 'none'
264
- throw new Error(`JIRA connection failed: ${(error as Error).message}`)
265
+ throw new Error(`JIRA connection failed: ${getErrorMessage(error)}`)
265
266
  }
266
267
  } else {
267
268
  // MCP mode - no direct API access, Claude uses MCP tools
@@ -340,7 +341,7 @@ export class JiraProvider implements IssueTrackerProvider {
340
341
  return this.mapIssue(issue)
341
342
  } catch (error) {
342
343
  // Issue not found
343
- if ((error as Error).message.includes('404')) {
344
+ if (getErrorMessage(error).includes('404')) {
344
345
  return null
345
346
  }
346
347
  throw error
@@ -4,6 +4,7 @@
4
4
  */
5
5
 
6
6
  import { LinearClient as LinearSDK } from '@linear/sdk'
7
+ import { getErrorMessage } from '../../types/fs'
7
8
  import { getCredential } from '../../utils/keychain'
8
9
  import type {
9
10
  CreateIssueInput,
@@ -84,7 +85,7 @@ export class LinearProvider implements IssueTrackerProvider {
84
85
  await this.sdk.viewer
85
86
  } catch (error) {
86
87
  this.sdk = null
87
- throw new Error(`Linear connection failed: ${(error as Error).message}`)
88
+ throw new Error(`Linear connection failed: ${getErrorMessage(error)}`)
88
89
  }
89
90
  }
90
91
 
@@ -24,6 +24,7 @@ import {
24
24
  type SyncResult,
25
25
  } from '../../schemas/issues'
26
26
  import { getProjectPath } from '../../schemas/schemas'
27
+ import { getErrorMessage } from '../../types/fs'
27
28
  import { fileExists } from '../../utils/fs-helpers'
28
29
  import type { Issue } from '../issue-tracker/types'
29
30
  import { linearService } from './service'
@@ -60,7 +61,7 @@ export class LinearSync {
60
61
  } catch (err) {
61
62
  errors.push({
62
63
  issueId: issue.externalId || issue.id,
63
- error: (err as Error).message,
64
+ error: getErrorMessage(err),
64
65
  })
65
66
  }
66
67
  }
@@ -85,7 +86,7 @@ export class LinearSync {
85
86
  } catch (err) {
86
87
  errors.push({
87
88
  issueId: 'all',
88
- error: (err as Error).message,
89
+ error: getErrorMessage(err),
89
90
  })
90
91
  return {
91
92
  provider: 'linear',
@@ -20,6 +20,7 @@
20
20
  import crypto from 'node:crypto'
21
21
  import { EventTypes } from '../../bus'
22
22
  import type { WebhookConfig, WebhookPayload, WebhookPluginContext } from '../../types'
23
+ import { getErrorMessage } from '../../types/fs'
23
24
  import { HookPoints } from '../hooks'
24
25
 
25
26
  const plugin = {
@@ -139,7 +140,7 @@ const plugin = {
139
140
  console.error(`[webhook] Request failed: ${response.status}`)
140
141
  }
141
142
  } catch (error) {
142
- console.error(`[webhook] Error sending webhook:`, (error as Error).message)
143
+ console.error(`[webhook] Error sending webhook:`, getErrorMessage(error))
143
144
  }
144
145
  },
145
146
  }
@@ -8,6 +8,7 @@
8
8
  */
9
9
 
10
10
  import { EventTypes, eventBus } from '../bus'
11
+ import { getErrorMessage } from '../types/fs'
11
12
 
12
13
  /**
13
14
  * Hook Points - Where plugins can intercept
@@ -144,7 +145,7 @@ class HookSystem {
144
145
  result = { ...result, ...(modified as Record<string, unknown>) }
145
146
  }
146
147
  } catch (error) {
147
- console.error(`Hook error [${hook.pluginName}] at ${hookPoint}:`, (error as Error).message)
148
+ console.error(`Hook error [${hook.pluginName}] at ${hookPoint}:`, getErrorMessage(error))
148
149
  // Continue with other hooks
149
150
  }
150
151
  }
@@ -164,10 +165,7 @@ class HookSystem {
164
165
  try {
165
166
  await hook.handler(data)
166
167
  } catch (error) {
167
- console.error(
168
- `Hook error [${hook.pluginName}] at ${hookPoint}:`,
169
- (error as Error).message
170
- )
168
+ console.error(`Hook error [${hook.pluginName}] at ${hookPoint}:`, getErrorMessage(error))
171
169
  }
172
170
  })
173
171
  )
@@ -199,7 +197,7 @@ class HookSystem {
199
197
  } catch (error) {
200
198
  console.error(
201
199
  `Transform hook error [${hook.pluginName}] at ${hookPoint}:`,
202
- (error as Error).message
200
+ getErrorMessage(error)
203
201
  )
204
202
  // Keep previous value on error
205
203
  }
@@ -13,7 +13,7 @@ import fs from 'node:fs/promises'
13
13
  import path from 'node:path'
14
14
  import { type EventCallback, eventBus } from '../bus'
15
15
  import pathManager from '../infrastructure/path-manager'
16
- import { isNotFoundError } from '../types/fs'
16
+ import { getErrorMessage, isNotFoundError } from '../types/fs'
17
17
  import { hookSystem } from './hooks'
18
18
 
19
19
  type PluginSource = 'builtin' | 'global' | 'project'
@@ -162,7 +162,7 @@ class PluginLoader {
162
162
  await this.loadPlugin(fullPath, 'project', spec.config)
163
163
  }
164
164
  } catch (error) {
165
- console.error(`Failed to load plugin: ${spec}`, (error as Error).message)
165
+ console.error(`Failed to load plugin: ${spec}`, getErrorMessage(error))
166
166
  }
167
167
  }
168
168
  }