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
package/CHANGELOG.md CHANGED
@@ -1,11 +1,23 @@
1
1
  # Changelog
2
2
 
3
- ## [1.6.2] - 2026-02-06
3
+ ## [1.6.4] - 2026-02-07
4
4
 
5
5
  ### Bug Fixes
6
6
 
7
- - replace console.error with logger in routes.ts (PRJ-73) (#125)
7
+ - add type guards for error handling (PRJ-79) (#127)
8
+
9
+
10
+ ## [1.6.6] - 2026-02-07
11
+
12
+ ### Improvements
13
+
14
+ - **Type-safe error handling**: Added `getErrorMessage()` and `getErrorStack()` type guards to `core/types/fs.ts`. Replaced ~130 unsafe `(error as Error).message` casts across 59 files with safe `getErrorMessage(error)` calls. Fixed internal `as` casts in existing type guards (`isNotFoundError`, `isPermissionError`, etc.) to use `isNodeError()` guard instead. Zero remaining `(error as Error)` patterns in the codebase.
15
+
16
+ ## [1.6.5] - 2026-02-07
17
+
18
+ ### Bug Fixes
8
19
 
20
+ - **Replace console.error with logger in setup.ts**: 12 `console.error` warning calls replaced with `log.warn` for Gemini, Cursor, Windsurf, Antigravity, migration, status line, Context7, symlink, and gitignore warnings. User-facing chalk output preserved. Fatal direct-run error kept as `console.error`.
9
21
 
10
22
  ## [1.6.4] - 2026-02-06
11
23
 
@@ -16,7 +16,7 @@ import path from 'node:path'
16
16
  import configManager from '../infrastructure/config-manager'
17
17
  import pathManager from '../infrastructure/path-manager'
18
18
  import type { Agent, AssignmentContext } from '../types'
19
- import { isNotFoundError } from '../types/fs'
19
+ import { getErrorMessage, isNotFoundError } from '../types/fs'
20
20
 
21
21
  // Re-export types for convenience
22
22
  export type { Agent, AssignmentContext } from '../types'
@@ -61,7 +61,7 @@ class AgentRouter {
61
61
  } catch (error) {
62
62
  // Agents directory doesn't exist yet - expected for new projects
63
63
  if (!isNotFoundError(error)) {
64
- console.error(`Agent loading error: ${(error as Error).message}`)
64
+ console.error(`Agent loading error: ${getErrorMessage(error)}`)
65
65
  }
66
66
  return []
67
67
  }
@@ -88,7 +88,7 @@ class AgentRouter {
88
88
  } catch (error) {
89
89
  // Agent file doesn't exist - expected
90
90
  if (!isNotFoundError(error)) {
91
- console.error(`Agent load error: ${(error as Error).message}`)
91
+ console.error(`Agent load error: ${getErrorMessage(error)}`)
92
92
  }
93
93
  return null
94
94
  }
@@ -141,7 +141,7 @@ class AgentRouter {
141
141
  } catch (error) {
142
142
  // Non-critical - log unexpected errors but don't fail
143
143
  if (!isNotFoundError(error)) {
144
- console.error(`Agent usage log error: ${(error as Error).message}`)
144
+ console.error(`Agent usage log error: ${getErrorMessage(error)}`)
145
145
  }
146
146
  }
147
147
  }
@@ -17,6 +17,7 @@ import type {
17
17
  PromptContext,
18
18
  SimpleExecutionResult,
19
19
  } from '../types'
20
+ import { getErrorMessage } from '../types/fs'
20
21
  import { agentStream } from '../utils/agent-stream'
21
22
  import { fileExists } from '../utils/fs-helpers'
22
23
  import { printSubtaskProgress, type SubtaskDisplay } from '../utils/subtask-table'
@@ -204,7 +205,7 @@ export class CommandExecutor {
204
205
  }
205
206
  } catch (error) {
206
207
  // Orchestration failed - log warning but continue without it
207
- console.warn(`⚠️ Orchestrator warning: ${(error as Error).message}`)
208
+ console.warn(`⚠️ Orchestrator warning: ${getErrorMessage(error)}`)
208
209
  }
209
210
  }
210
211
 
@@ -379,7 +380,7 @@ export class CommandExecutor {
379
380
  // Record failed attempt for loop detection
380
381
  const attemptInfo = loopDetector.recordAttempt(commandName, loopContext, {
381
382
  success: false,
382
- error: (error as Error).message,
383
+ error: getErrorMessage(error),
383
384
  })
384
385
 
385
386
  // Check if we should escalate after this failure
@@ -396,7 +397,7 @@ export class CommandExecutor {
396
397
 
397
398
  return {
398
399
  success: false,
399
- error: (error as Error).message,
400
+ error: getErrorMessage(error),
400
401
  attemptNumber: attemptInfo.attemptNumber,
401
402
  isLooping: attemptInfo.isLooping,
402
403
  }
@@ -456,7 +457,7 @@ export class CommandExecutor {
456
457
  } catch (error) {
457
458
  return {
458
459
  success: false,
459
- error: (error as Error).message,
460
+ error: getErrorMessage(error),
460
461
  }
461
462
  }
462
463
  }
@@ -18,7 +18,7 @@ import path from 'node:path'
18
18
  import { promisify } from 'node:util'
19
19
 
20
20
  import type { GroundTruthContext, VerificationResult, Verifier } from '../types'
21
- import { isNotFoundError } from '../types/fs'
21
+ import { getErrorMessage, isNotFoundError } from '../types/fs'
22
22
 
23
23
  const execAsync = promisify(exec)
24
24
 
@@ -651,7 +651,7 @@ export async function verify(
651
651
  return {
652
652
  verified: false,
653
653
  actual: {},
654
- warnings: [`Verification error: ${(error as Error).message}`],
654
+ warnings: [`Verification error: ${getErrorMessage(error)}`],
655
655
  recommendations: ['Check file permissions and project configuration'],
656
656
  }
657
657
  }
@@ -31,7 +31,7 @@ import type {
31
31
  OrchestratorSubtask,
32
32
  RealCodebaseContext,
33
33
  } from '../types'
34
- import { isNotFoundError } from '../types/fs'
34
+ import { getErrorMessage, isNotFoundError } from '../types/fs'
35
35
  import { parseFrontmatter } from './template-loader'
36
36
 
37
37
  const execAsync = promisify(execCallback)
@@ -347,7 +347,7 @@ export class OrchestratorExecutor {
347
347
  return JSON.parse(content)
348
348
  } catch (error) {
349
349
  if (isNotFoundError(error)) return null
350
- console.warn('Failed to load repo-analysis.json:', (error as Error).message)
350
+ console.warn('Failed to load repo-analysis.json:', getErrorMessage(error))
351
351
  return null
352
352
  }
353
353
  }
@@ -25,7 +25,7 @@ import type {
25
25
  Template,
26
26
  ThinkBlock,
27
27
  } from '../types'
28
- import { isNotFoundError } from '../types/fs'
28
+ import { getErrorMessage, isNotFoundError } from '../types/fs'
29
29
  import { fileExists } from '../utils/fs-helpers'
30
30
  import { getPackageRoot } from '../utils/version'
31
31
 
@@ -94,7 +94,7 @@ class PromptBuilder {
94
94
  }
95
95
  } catch (error) {
96
96
  if (!isNotFoundError(error)) {
97
- console.error(`Template loading warning: ${(error as Error).message}`)
97
+ console.error(`Template loading warning: ${getErrorMessage(error)}`)
98
98
  }
99
99
  }
100
100
 
@@ -184,7 +184,7 @@ class PromptBuilder {
184
184
  } catch (error) {
185
185
  // Silent fail - checklists are optional enhancement
186
186
  if (!isNotFoundError(error)) {
187
- console.error(`Checklist loading warning: ${(error as Error).message}`)
187
+ console.error(`Checklist loading warning: ${getErrorMessage(error)}`)
188
188
  }
189
189
  }
190
190
 
@@ -281,7 +281,7 @@ class PromptBuilder {
281
281
  } catch (error) {
282
282
  // Outcomes not available yet - expected for new projects
283
283
  if (!isNotFoundError(error) && !(error instanceof SyntaxError)) {
284
- console.error(`Outcome detection warning: ${(error as Error).message}`)
284
+ console.error(`Outcome detection warning: ${getErrorMessage(error)}`)
285
285
  }
286
286
  }
287
287
 
@@ -7,6 +7,7 @@
7
7
 
8
8
  import fs from 'node:fs/promises'
9
9
  import path from 'node:path'
10
+ import { getErrorMessage } from '../types/fs'
10
11
  import { mergePreservedSections, validatePreserveBlocks } from '../utils/preserve-sections'
11
12
  import { getFormatter, type ProjectContext } from './formatters'
12
13
  import { AI_TOOLS, type AIToolConfig, DEFAULT_AI_TOOLS, getAIToolConfig } from './registry'
@@ -118,7 +119,7 @@ async function generateForTool(
118
119
  outputFile: config.outputFile,
119
120
  outputPath: '',
120
121
  success: false,
121
- error: (error as Error).message,
122
+ error: getErrorMessage(error),
122
123
  }
123
124
  }
124
125
  }
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env bun
2
+
2
3
  /**
3
4
  * Linear CLI - Bridge between templates and SDK
4
5
  *
@@ -31,6 +32,7 @@
31
32
 
32
33
  import type { CreateIssueInput, Issue } from '../integrations/issue-tracker/types'
33
34
  import { linearService, linearSync } from '../integrations/linear'
35
+ import { getErrorMessage } from '../types/fs'
34
36
  import { formatForHuman, setOutputTier } from '../utils/output'
35
37
  import {
36
38
  getCredentialSource,
@@ -451,10 +453,10 @@ async function main(): Promise<void> {
451
453
  }
452
454
  } catch (err) {
453
455
  if (jsonMode) {
454
- output({ configured: true, source, connectionError: (err as Error).message })
456
+ output({ configured: true, source, connectionError: getErrorMessage(err) })
455
457
  } else {
456
458
  console.log(`Linear: Connection error`)
457
- console.log(`Error: ${(err as Error).message}`)
459
+ console.log(`Error: ${getErrorMessage(err)}`)
458
460
  }
459
461
  }
460
462
  break
@@ -491,7 +493,7 @@ async function main(): Promise<void> {
491
493
  error(`Unknown command: ${command}. Use --help to see available commands.`)
492
494
  }
493
495
  } catch (err) {
494
- error((err as Error).message)
496
+ error(getErrorMessage(err))
495
497
  }
496
498
  }
497
499
 
package/core/cli/start.ts CHANGED
@@ -14,6 +14,7 @@ import path from 'node:path'
14
14
  import readline from 'node:readline'
15
15
  import chalk from 'chalk'
16
16
  import { detectAllProviders, Providers } from '../infrastructure/ai-provider'
17
+ import { getErrorMessage } from '../types/fs'
17
18
  import type { AIProviderName } from '../types/provider'
18
19
  import { fileExists } from '../utils/fs-helpers'
19
20
  import { VERSION } from '../utils/version'
@@ -217,7 +218,7 @@ async function installRouter(provider: AIProviderName): Promise<boolean> {
217
218
  return false
218
219
  } catch (error) {
219
220
  console.error(
220
- ` ${chalk.yellow('⚠')} Failed to install ${provider} router: ${(error as Error).message}`
221
+ ` ${chalk.yellow('⚠')} Failed to install ${provider} router: ${getErrorMessage(error)}`
221
222
  )
222
223
  return false
223
224
  }
@@ -281,7 +282,7 @@ async function installGlobalConfig(provider: AIProviderName): Promise<boolean> {
281
282
  return false
282
283
  } catch (error) {
283
284
  console.error(
284
- ` ${chalk.yellow('⚠')} Failed to install ${provider} config: ${(error as Error).message}`
285
+ ` ${chalk.yellow('⚠')} Failed to install ${provider} config: ${getErrorMessage(error)}`
285
286
  )
286
287
  return false
287
288
  }
@@ -14,6 +14,7 @@ import { createStalenessChecker, memoryService, syncService } from '../services'
14
14
  import { formatDiffPreview, formatFullDiff, generateSyncDiff } from '../services/diff-generator'
15
15
  import { metricsStorage } from '../storage/metrics-storage'
16
16
  import type { AnalyzeOptions, CommandResult, ProjectContext } from '../types'
17
+ import { getErrorMessage } from '../types/fs'
17
18
  import { showNextSteps } from '../utils/next-steps'
18
19
  import out from '../utils/output'
19
20
  import {
@@ -100,8 +101,8 @@ export class AnalysisCommands extends PrjctCommandsBase {
100
101
  data: analysisData,
101
102
  }
102
103
  } catch (error) {
103
- console.error('❌ Error:', (error as Error).message)
104
- return { success: false, error: (error as Error).message }
104
+ console.error('❌ Error:', getErrorMessage(error))
105
+ return { success: false, error: getErrorMessage(error) }
105
106
  }
106
107
  }
107
108
 
@@ -461,8 +462,8 @@ export class AnalysisCommands extends PrjctCommandsBase {
461
462
  out.stop()
462
463
  return this.showSyncResult(result, startTime)
463
464
  } catch (error) {
464
- out.fail((error as Error).message)
465
- return { success: false, error: (error as Error).message }
465
+ out.fail(getErrorMessage(error))
466
+ return { success: false, error: getErrorMessage(error) }
466
467
  }
467
468
  }
468
469
 
@@ -766,8 +767,8 @@ export class AnalysisCommands extends PrjctCommandsBase {
766
767
  data: { ...summary, session: sessionActivity, patterns: patternsSummary },
767
768
  }
768
769
  } catch (error) {
769
- console.error('❌ Error:', (error as Error).message)
770
- return { success: false, error: (error as Error).message }
770
+ console.error('❌ Error:', getErrorMessage(error))
771
+ return { success: false, error: getErrorMessage(error) }
771
772
  }
772
773
  }
773
774
 
@@ -825,7 +826,7 @@ export class AnalysisCommands extends PrjctCommandsBase {
825
826
 
826
827
  return { success: true, data: { ...status, session: sessionInfo } }
827
828
  } catch (error) {
828
- const errMsg = (error as Error).message
829
+ const errMsg = getErrorMessage(error)
829
830
  if (options.json) {
830
831
  console.log(JSON.stringify({ success: false, error: errMsg }))
831
832
  } else {
@@ -7,6 +7,7 @@ import path from 'node:path'
7
7
  import { createStalenessChecker } from '../services'
8
8
  import { ideasStorage, queueStorage, shippedStorage, stateStorage } from '../storage'
9
9
  import type { CommandResult, ProjectContext } from '../types'
10
+ import { getErrorMessage } from '../types/fs'
10
11
  import {
11
12
  configManager,
12
13
  contextBuilder,
@@ -204,8 +205,8 @@ export class AnalyticsCommands extends PrjctCommandsBase {
204
205
  },
205
206
  }
206
207
  } catch (error) {
207
- out.fail((error as Error).message)
208
- return { success: false, error: (error as Error).message }
208
+ out.fail(getErrorMessage(error))
209
+ return { success: false, error: getErrorMessage(error) }
209
210
  }
210
211
  }
211
212
 
@@ -307,8 +308,8 @@ export class AnalyticsCommands extends PrjctCommandsBase {
307
308
  console.log(' Use /p:help to see all commands\n')
308
309
  return { success: false, error: `Unknown topic: ${topic}` }
309
310
  } catch (error) {
310
- out.fail((error as Error).message)
311
- return { success: false, error: (error as Error).message }
311
+ out.fail(getErrorMessage(error))
312
+ return { success: false, error: getErrorMessage(error) }
312
313
  }
313
314
  }
314
315
 
@@ -8,7 +8,7 @@ import path from 'node:path'
8
8
  import { memoryService } from '../services'
9
9
  import { ideasStorage, queueStorage } from '../storage'
10
10
  import type { CleanupOptions, CommandResult } from '../types'
11
- import { isNotFoundError } from '../types/fs'
11
+ import { getErrorMessage, isNotFoundError } from '../types/fs'
12
12
  import { configManager, dateHelper, jsonlHelper, out, pathManager } from './base'
13
13
 
14
14
  /**
@@ -41,7 +41,7 @@ export async function cleanupMemory(projectPath: string): Promise<{
41
41
  } catch (error) {
42
42
  // Skip file if not found, otherwise log unexpected errors
43
43
  if (!isNotFoundError(error)) {
44
- console.error(`Cleanup warning for ${filePath}: ${(error as Error).message}`)
44
+ console.error(`Cleanup warning for ${filePath}: ${getErrorMessage(error)}`)
45
45
  }
46
46
  }
47
47
  }
@@ -101,7 +101,7 @@ export async function cleanup(
101
101
  if (isNotFoundError(error)) {
102
102
  cleaned.push('Memory: No file found')
103
103
  } else {
104
- cleaned.push(`Memory: Error - ${(error as Error).message}`)
104
+ cleaned.push(`Memory: Error - ${getErrorMessage(error)}`)
105
105
  }
106
106
  }
107
107
 
@@ -117,7 +117,7 @@ export async function cleanup(
117
117
  if (isNotFoundError(error)) {
118
118
  cleaned.push('Ideas: No file found')
119
119
  } else {
120
- cleaned.push(`Ideas: Error - ${(error as Error).message}`)
120
+ cleaned.push(`Ideas: Error - ${getErrorMessage(error)}`)
121
121
  }
122
122
  }
123
123
 
@@ -137,7 +137,7 @@ export async function cleanup(
137
137
  if (isNotFoundError(error)) {
138
138
  cleaned.push('Queue: No file found')
139
139
  } else {
140
- cleaned.push(`Queue: Error - ${(error as Error).message}`)
140
+ cleaned.push(`Queue: Error - ${getErrorMessage(error)}`)
141
141
  }
142
142
  }
143
143
 
@@ -151,7 +151,7 @@ export async function cleanup(
151
151
  out.done(`${cleaned.length} items cleaned`)
152
152
  return { success: true, cleaned }
153
153
  } catch (error) {
154
- out.fail((error as Error).message)
155
- return { success: false, error: (error as Error).message }
154
+ out.fail(getErrorMessage(error))
155
+ return { success: false, error: getErrorMessage(error) }
156
156
  }
157
157
  }
@@ -22,7 +22,7 @@ import configManager from '../infrastructure/config-manager'
22
22
  import pathManager from '../infrastructure/path-manager'
23
23
  import { stateStorage } from '../storage'
24
24
  import type { CommandResult } from '../types'
25
- import { isNotFoundError } from '../types/fs'
25
+ import { getErrorMessage, isNotFoundError } from '../types/fs'
26
26
 
27
27
  // =============================================================================
28
28
  // Types
@@ -149,7 +149,7 @@ export class ContextCommands {
149
149
  )
150
150
  } catch (error) {
151
151
  // Orchestration failed - continue without it
152
- console.error(`Warning: Orchestrator failed: ${(error as Error).message}`)
152
+ console.error(`Warning: Orchestrator failed: ${getErrorMessage(error)}`)
153
153
  }
154
154
  }
155
155
 
@@ -198,7 +198,7 @@ export class ContextCommands {
198
198
  } catch (error) {
199
199
  return {
200
200
  success: false,
201
- message: `Context error: ${(error as Error).message}`,
201
+ message: `Context error: ${getErrorMessage(error)}`,
202
202
  }
203
203
  }
204
204
  }
@@ -7,6 +7,7 @@
7
7
  import path from 'node:path'
8
8
  import { memoryService } from '../services'
9
9
  import type { CommandResult, DesignOptions } from '../types'
10
+ import { getErrorMessage } from '../types/fs'
10
11
  import { configManager, dateHelper, fileHelper, out, pathManager } from './base'
11
12
 
12
13
  /**
@@ -70,7 +71,7 @@ export async function design(
70
71
  out.done(`${designType} design created`)
71
72
  return { success: true, designPath: designFilePath, type: designType, target: designTarget }
72
73
  } catch (error) {
73
- out.fail((error as Error).message)
74
- return { success: false, error: (error as Error).message }
74
+ out.fail(getErrorMessage(error))
75
+ return { success: false, error: getErrorMessage(error) }
75
76
  }
76
77
  }
@@ -10,6 +10,7 @@ import { generateUUID } from '../schemas'
10
10
  import type { Priority, TaskSection, TaskType } from '../schemas/state'
11
11
  import { ideasStorage, queueStorage } from '../storage'
12
12
  import type { CommandResult, ProjectContext } from '../types'
13
+ import { getErrorMessage } from '../types/fs'
13
14
  import { showNextSteps } from '../utils/next-steps'
14
15
  import { OnboardingWizard } from '../wizard'
15
16
  import {
@@ -194,8 +195,8 @@ export class PlanningCommands extends PrjctCommandsBase {
194
195
  this._printNextSteps(wizardResult)
195
196
  return { success: true, projectId, wizard: wizardResult }
196
197
  } catch (error) {
197
- out.fail((error as Error).message)
198
- return { success: false, error: (error as Error).message }
198
+ out.fail(getErrorMessage(error))
199
+ return { success: false, error: getErrorMessage(error) }
199
200
  }
200
201
  }
201
202
 
@@ -306,8 +307,8 @@ export class PlanningCommands extends PrjctCommandsBase {
306
307
 
307
308
  return { success: true, feature: description, featureId, tasks: tasksWithAgents }
308
309
  } catch (error) {
309
- out.fail((error as Error).message)
310
- return { success: false, error: (error as Error).message }
310
+ out.fail(getErrorMessage(error))
311
+ return { success: false, error: getErrorMessage(error) }
311
312
  }
312
313
  }
313
314
 
@@ -373,8 +374,8 @@ export class PlanningCommands extends PrjctCommandsBase {
373
374
 
374
375
  return { success: true, bug: description, severity, agent }
375
376
  } catch (error) {
376
- out.fail((error as Error).message)
377
- return { success: false, error: (error as Error).message }
377
+ out.fail(getErrorMessage(error))
378
+ return { success: false, error: getErrorMessage(error) }
378
379
  }
379
380
  }
380
381
 
@@ -466,8 +467,8 @@ export class PlanningCommands extends PrjctCommandsBase {
466
467
  idea,
467
468
  }
468
469
  } catch (error) {
469
- console.error('❌ Error:', (error as Error).message)
470
- return { success: false, error: (error as Error).message }
470
+ console.error('❌ Error:', getErrorMessage(error))
471
+ return { success: false, error: getErrorMessage(error) }
471
472
  }
472
473
  }
473
474
 
@@ -545,8 +546,8 @@ Generated: ${new Date().toLocaleString()}
545
546
  return { success: true, mode: 'capture', idea: description }
546
547
  }
547
548
  } catch (error) {
548
- out.fail((error as Error).message)
549
- return { success: false, error: (error as Error).message }
549
+ out.fail(getErrorMessage(error))
550
+ return { success: false, error: getErrorMessage(error) }
550
551
  }
551
552
  }
552
553
 
@@ -656,8 +657,8 @@ Status: Draft
656
657
 
657
658
  return { success: true, feature: featureName, specPath: specFile }
658
659
  } catch (error) {
659
- out.fail((error as Error).message)
660
- return { success: false, error: (error as Error).message }
660
+ out.fail(getErrorMessage(error))
661
+ return { success: false, error: getErrorMessage(error) }
661
662
  }
662
663
  }
663
664
  }
@@ -8,6 +8,7 @@
8
8
  import configManager from '../infrastructure/config-manager'
9
9
  import pathManager from '../infrastructure/path-manager'
10
10
  import type { CommandResult } from '../types'
11
+ import { getErrorMessage } from '../types/fs'
11
12
  import { getTimestamp } from '../utils/date-helper'
12
13
 
13
14
  // Re-export types for convenience
@@ -367,7 +368,7 @@ export class CommandRegistry {
367
368
  } catch (error) {
368
369
  return {
369
370
  success: false,
370
- error: (error as Error).message,
371
+ error: getErrorMessage(error),
371
372
  }
372
373
  }
373
374
  }
@@ -8,6 +8,7 @@ import chalk from 'chalk'
8
8
  import commandInstaller from '../infrastructure/command-installer'
9
9
  import pathManager from '../infrastructure/path-manager'
10
10
  import type { CommandResult, SetupOptions } from '../types'
11
+ import { getErrorMessage } from '../types/fs'
11
12
  import { fileExists } from '../utils/fs-helpers'
12
13
  import { VERSION } from '../utils/version'
13
14
  import { PrjctCommandsBase } from './base'
@@ -227,7 +228,7 @@ echo "⚡ prjct"
227
228
 
228
229
  return { success: true }
229
230
  } catch (error) {
230
- return { success: false, error: (error as Error).message }
231
+ return { success: false, error: getErrorMessage(error) }
231
232
  }
232
233
  }
233
234
 
@@ -7,7 +7,7 @@ import path from 'node:path'
7
7
  import memorySystem from '../agentic/memory-system'
8
8
  import { shippedStorage, stateStorage } from '../storage'
9
9
  import type { CommandResult } from '../types'
10
- import { isNotFoundError } from '../types/fs'
10
+ import { getErrorMessage, isNotFoundError } from '../types/fs'
11
11
  import { showNextSteps } from '../utils/next-steps'
12
12
  import { detectProjectCommands } from '../utils/project-commands'
13
13
  import { runWorkflowHooks } from '../workflow/workflow-preferences'
@@ -136,8 +136,8 @@ export class ShippingCommands extends PrjctCommandsBase {
136
136
 
137
137
  return { success: true, feature: featureName, version: newVersion }
138
138
  } catch (error) {
139
- out.fail((error as Error).message)
140
- return { success: false, error: (error as Error).message }
139
+ out.fail(getErrorMessage(error))
140
+ return { success: false, error: getErrorMessage(error) }
141
141
  }
142
142
  }
143
143
 
@@ -7,7 +7,7 @@
7
7
  import path from 'node:path'
8
8
  import { memoryService } from '../services'
9
9
  import type { CommandResult } from '../types'
10
- import { isNotFoundError } from '../types/fs'
10
+ import { getErrorMessage, isNotFoundError } from '../types/fs'
11
11
  import { configManager, dateHelper, fileHelper, out, pathManager } from './base'
12
12
 
13
13
  interface SnapshotHistory {
@@ -71,8 +71,8 @@ export async function recover(projectPath: string = process.cwd()): Promise<Comm
71
71
 
72
72
  return { success: true, session: sessionData }
73
73
  } catch (error) {
74
- out.fail((error as Error).message)
75
- return { success: false, error: (error as Error).message }
74
+ out.fail(getErrorMessage(error))
75
+ return { success: false, error: getErrorMessage(error) }
76
76
  }
77
77
  }
78
78
 
@@ -148,11 +148,11 @@ export async function undo(projectPath: string = process.cwd()): Promise<Command
148
148
  return { success: true, snapshotId: stashMessage }
149
149
  } catch (gitError) {
150
150
  out.failWithHint('GIT_OPERATION_FAILED')
151
- return { success: false, error: (gitError as Error).message }
151
+ return { success: false, error: getErrorMessage(gitError) }
152
152
  }
153
153
  } catch (error) {
154
- out.fail((error as Error).message)
155
- return { success: false, error: (error as Error).message }
154
+ out.fail(getErrorMessage(error))
155
+ return { success: false, error: getErrorMessage(error) }
156
156
  }
157
157
  }
158
158
 
@@ -232,11 +232,11 @@ export async function redo(projectPath: string = process.cwd()): Promise<Command
232
232
  return { success: true }
233
233
  } catch (gitError) {
234
234
  out.failWithHint('GIT_OPERATION_FAILED')
235
- return { success: false, error: (gitError as Error).message }
235
+ return { success: false, error: getErrorMessage(gitError) }
236
236
  }
237
237
  } catch (error) {
238
- out.fail((error as Error).message)
239
- return { success: false, error: (error as Error).message }
238
+ out.fail(getErrorMessage(error))
239
+ return { success: false, error: getErrorMessage(error) }
240
240
  }
241
241
  }
242
242
 
@@ -291,7 +291,7 @@ export async function history(projectPath: string = process.cwd()): Promise<Comm
291
291
 
292
292
  return { success: true, snapshots: snapshotHistory.snapshots, current: snapshotHistory.current }
293
293
  } catch (error) {
294
- out.fail((error as Error).message)
295
- return { success: false, error: (error as Error).message }
294
+ out.fail(getErrorMessage(error))
295
+ return { success: false, error: getErrorMessage(error) }
296
296
  }
297
297
  }
@@ -16,6 +16,7 @@ import chalk from 'chalk'
16
16
  import { getProviderPaths } from '../infrastructure/command-installer'
17
17
  import pathManager from '../infrastructure/path-manager'
18
18
  import type { CommandResult, UninstallOptions } from '../types'
19
+ import { getErrorMessage } from '../types/fs'
19
20
  import { fileExists } from '../utils/fs-helpers'
20
21
  import { PrjctCommandsBase } from './base'
21
22
 
@@ -347,7 +348,7 @@ async function performUninstall(
347
348
  deleted.push(item.path)
348
349
  }
349
350
  } catch (error) {
350
- errors.push(`${item.path}: ${(error as Error).message}`)
351
+ errors.push(`${item.path}: ${getErrorMessage(error)}`)
351
352
  }
352
353
  }
353
354
 
@@ -360,7 +361,7 @@ async function performUninstall(
360
361
  }
361
362
  deleted.push('Homebrew: prjct-cli')
362
363
  } catch (error) {
363
- errors.push(`Homebrew: ${(error as Error).message}`)
364
+ errors.push(`Homebrew: ${getErrorMessage(error)}`)
364
365
  }
365
366
  }
366
367
 
@@ -371,7 +372,7 @@ async function performUninstall(
371
372
  }
372
373
  deleted.push('npm: prjct-cli')
373
374
  } catch (error) {
374
- errors.push(`npm: ${(error as Error).message}`)
375
+ errors.push(`npm: ${getErrorMessage(error)}`)
375
376
  }
376
377
  }
377
378
  }