@defai.digital/ax-cli 3.5.4 → 3.6.0

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 (99) hide show
  1. package/.ax-cli/memory.json +8 -8
  2. package/README.md +7 -0
  3. package/config-defaults/messages.yaml +75 -0
  4. package/config-defaults/models.yaml +66 -0
  5. package/config-defaults/prompts.yaml +156 -0
  6. package/config-defaults/settings.yaml +86 -0
  7. package/dist/agent/chat-history-manager.d.ts +56 -0
  8. package/dist/agent/chat-history-manager.js +150 -0
  9. package/dist/agent/chat-history-manager.js.map +1 -0
  10. package/dist/agent/llm-agent.js +1 -1
  11. package/dist/agent/llm-agent.js.map +1 -1
  12. package/dist/agent/tool-manager.d.ts +39 -0
  13. package/dist/agent/tool-manager.js +76 -0
  14. package/dist/agent/tool-manager.js.map +1 -0
  15. package/dist/commands/memory.js +1 -1
  16. package/dist/commands/memory.js.map +1 -1
  17. package/dist/commands/setup.js +19 -6
  18. package/dist/commands/setup.js.map +1 -1
  19. package/dist/index.js +7 -0
  20. package/dist/index.js.map +1 -1
  21. package/dist/llm/client.d.ts +1 -0
  22. package/dist/llm/client.js +44 -0
  23. package/dist/llm/client.js.map +1 -1
  24. package/dist/mcp/health.js +4 -2
  25. package/dist/mcp/health.js.map +1 -1
  26. package/dist/mcp/ssrf-protection.d.ts +86 -0
  27. package/dist/mcp/ssrf-protection.js +313 -0
  28. package/dist/mcp/ssrf-protection.js.map +1 -0
  29. package/dist/mcp/validation.d.ts +4 -0
  30. package/dist/mcp/validation.js +122 -11
  31. package/dist/mcp/validation.js.map +1 -1
  32. package/dist/schemas/settings-schemas.d.ts +30 -0
  33. package/dist/schemas/settings-schemas.js +30 -0
  34. package/dist/schemas/settings-schemas.js.map +1 -1
  35. package/dist/tools/bash.d.ts +3 -2
  36. package/dist/tools/bash.js +31 -2
  37. package/dist/tools/bash.js.map +1 -1
  38. package/dist/tools/search.d.ts +1 -1
  39. package/dist/tools/search.js +121 -128
  40. package/dist/tools/search.js.map +1 -1
  41. package/dist/tools/text-editor.js +52 -15
  42. package/dist/tools/text-editor.js.map +1 -1
  43. package/dist/ui/components/chat-history.js +1 -1
  44. package/dist/ui/components/chat-history.js.map +1 -1
  45. package/dist/ui/components/chat-interface.js +3 -2
  46. package/dist/ui/components/chat-interface.js.map +1 -1
  47. package/dist/ui/components/confirmation-dialog.js +1 -1
  48. package/dist/ui/components/confirmation-dialog.js.map +1 -1
  49. package/dist/ui/components/status-bar.js +2 -2
  50. package/dist/ui/components/status-bar.js.map +1 -1
  51. package/dist/{hooks → ui/hooks}/use-chat-reducer.d.ts +1 -1
  52. package/dist/ui/hooks/use-chat-reducer.js.map +1 -0
  53. package/dist/{hooks → ui/hooks}/use-enhanced-input.js +8 -3
  54. package/dist/ui/hooks/use-enhanced-input.js.map +1 -0
  55. package/dist/{hooks → ui/hooks}/use-input-handler.d.ts +1 -1
  56. package/dist/{hooks → ui/hooks}/use-input-handler.js +28 -24
  57. package/dist/ui/hooks/use-input-handler.js.map +1 -0
  58. package/dist/utils/audit-logger.d.ts +247 -0
  59. package/dist/utils/audit-logger.js +374 -0
  60. package/dist/utils/audit-logger.js.map +1 -0
  61. package/dist/utils/command-security.d.ts +85 -0
  62. package/dist/utils/command-security.js +200 -0
  63. package/dist/utils/command-security.js.map +1 -0
  64. package/dist/utils/config-loader.js +3 -3
  65. package/dist/utils/config-loader.js.map +1 -1
  66. package/dist/utils/encryption.d.ts +78 -0
  67. package/dist/utils/encryption.js +216 -0
  68. package/dist/utils/encryption.js.map +1 -0
  69. package/dist/utils/error-sanitizer.d.ts +119 -0
  70. package/dist/utils/error-sanitizer.js +253 -0
  71. package/dist/utils/error-sanitizer.js.map +1 -0
  72. package/dist/utils/input-sanitizer.d.ts +210 -0
  73. package/dist/utils/input-sanitizer.js +362 -0
  74. package/dist/utils/input-sanitizer.js.map +1 -0
  75. package/dist/utils/json-utils.d.ts +13 -0
  76. package/dist/utils/json-utils.js +55 -1
  77. package/dist/utils/json-utils.js.map +1 -1
  78. package/dist/utils/path-security.d.ts +90 -0
  79. package/dist/utils/path-security.js +328 -0
  80. package/dist/utils/path-security.js.map +1 -0
  81. package/dist/utils/process-pool.d.ts +105 -0
  82. package/dist/utils/process-pool.js +326 -0
  83. package/dist/utils/process-pool.js.map +1 -0
  84. package/dist/utils/rate-limiter.d.ts +207 -0
  85. package/dist/utils/rate-limiter.js +303 -0
  86. package/dist/utils/rate-limiter.js.map +1 -0
  87. package/dist/utils/settings-manager.js +99 -6
  88. package/dist/utils/settings-manager.js.map +1 -1
  89. package/dist/utils/streaming-analyzer.js +9 -21
  90. package/dist/utils/streaming-analyzer.js.map +1 -1
  91. package/package.json +1 -1
  92. package/dist/hooks/use-chat-reducer.js.map +0 -1
  93. package/dist/hooks/use-enhanced-input.js.map +0 -1
  94. package/dist/hooks/use-input-handler.js.map +0 -1
  95. package/dist/hooks/use-input-history.d.ts +0 -9
  96. package/dist/hooks/use-input-history.js +0 -112
  97. package/dist/hooks/use-input-history.js.map +0 -1
  98. /package/dist/{hooks → ui/hooks}/use-chat-reducer.js +0 -0
  99. /package/dist/{hooks → ui/hooks}/use-enhanced-input.d.ts +0 -0
@@ -16,9 +16,9 @@ const configCache = new Map();
16
16
  * Get the config directory path
17
17
  */
18
18
  function getConfigDir() {
19
- // In development: src/utils -> ../../config
20
- // In production: dist/utils -> ../../config
21
- return join(__dirname, '../../config');
19
+ // In development: src/utils -> ../../config-defaults
20
+ // In production: dist/utils -> ../../config-defaults
21
+ return join(__dirname, '../../config-defaults');
22
22
  }
23
23
  /**
24
24
  * Load a YAML configuration file with optional schema validation
@@ -1 +1 @@
1
- {"version":3,"file":"config-loader.js","sourceRoot":"","sources":["../../src/utils/config-loader.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config-loader.js","sourceRoot":"","sources":["../../src/utils/config-loader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,78 @@
1
+ /**
2
+ * API Key Encryption Utilities
3
+ *
4
+ * Provides secure encryption/decryption for API keys stored in configuration
5
+ * files (REQ-SEC-003).
6
+ *
7
+ * Uses Node.js crypto module with:
8
+ * - AES-256-GCM for encryption (authenticated encryption)
9
+ * - PBKDF2 for key derivation from machine-specific identifier
10
+ * - Random IV for each encryption
11
+ * - Authentication tag verification
12
+ *
13
+ * @module encryption
14
+ */
15
+ /**
16
+ * Encrypted value format
17
+ */
18
+ export interface EncryptedValue {
19
+ encrypted: string;
20
+ iv: string;
21
+ tag: string;
22
+ version: number;
23
+ }
24
+ /**
25
+ * Encrypt a string value (typically an API key).
26
+ *
27
+ * @param plaintext - The value to encrypt
28
+ * @returns Encrypted value object with iv, tag, and encrypted data
29
+ */
30
+ export declare function encrypt(plaintext: string): EncryptedValue;
31
+ /**
32
+ * Decrypt an encrypted value.
33
+ *
34
+ * @param encryptedValue - The encrypted value object
35
+ * @returns Decrypted plaintext
36
+ * @throws Error if decryption fails (wrong machine, corrupted data, etc.)
37
+ */
38
+ export declare function decrypt(encryptedValue: EncryptedValue): string;
39
+ /**
40
+ * Check if a value is encrypted (has the expected structure).
41
+ *
42
+ * @param value - Value to check
43
+ * @returns True if value appears to be encrypted
44
+ */
45
+ export declare function isEncrypted(value: unknown): value is EncryptedValue;
46
+ /**
47
+ * Encrypt an object's sensitive fields.
48
+ *
49
+ * @param obj - Object containing sensitive fields
50
+ * @param fieldsToEncrypt - Array of field names to encrypt
51
+ * @returns New object with encrypted fields
52
+ */
53
+ export declare function encryptFields<T extends Record<string, any>>(obj: T, fieldsToEncrypt: string[]): T;
54
+ /**
55
+ * Decrypt an object's encrypted fields.
56
+ *
57
+ * @param obj - Object containing encrypted fields
58
+ * @param fieldsToDecrypt - Array of field names to decrypt
59
+ * @returns New object with decrypted fields
60
+ */
61
+ export declare function decryptFields<T extends Record<string, any>>(obj: T, fieldsToDecrypt: string[]): T;
62
+ /**
63
+ * Test if encryption is working (for diagnostics).
64
+ *
65
+ * @returns True if encryption/decryption round-trip works
66
+ */
67
+ export declare function testEncryption(): boolean;
68
+ /**
69
+ * Get encryption info for diagnostics.
70
+ */
71
+ export declare function getEncryptionInfo(): {
72
+ algorithm: string;
73
+ keyLength: number;
74
+ ivLength: number;
75
+ pbkdf2Iterations: number;
76
+ version: number;
77
+ machineId: string;
78
+ };
@@ -0,0 +1,216 @@
1
+ /**
2
+ * API Key Encryption Utilities
3
+ *
4
+ * Provides secure encryption/decryption for API keys stored in configuration
5
+ * files (REQ-SEC-003).
6
+ *
7
+ * Uses Node.js crypto module with:
8
+ * - AES-256-GCM for encryption (authenticated encryption)
9
+ * - PBKDF2 for key derivation from machine-specific identifier
10
+ * - Random IV for each encryption
11
+ * - Authentication tag verification
12
+ *
13
+ * @module encryption
14
+ */
15
+ import crypto from 'crypto';
16
+ import os from 'os';
17
+ /**
18
+ * Encryption configuration
19
+ */
20
+ const ENCRYPTION_CONFIG = {
21
+ algorithm: 'aes-256-gcm',
22
+ keyLength: 32, // 256 bits
23
+ ivLength: 16, // 128 bits
24
+ saltLength: 32, // 256 bits
25
+ tagLength: 16, // 128 bits
26
+ pbkdf2Iterations: 100000, // OWASP recommendation
27
+ version: 1,
28
+ };
29
+ /**
30
+ * Get a machine-specific identifier for key derivation.
31
+ * Uses hostname + platform + arch to create a unique-per-machine string.
32
+ *
33
+ * Note: This is not cryptographically strong protection (attacker with file
34
+ * access can derive the key), but it prevents casual browsing of config files
35
+ * and provides defense in depth.
36
+ */
37
+ function getMachineIdentifier() {
38
+ const hostname = os.hostname();
39
+ const platform = os.platform();
40
+ const arch = os.arch();
41
+ // Combine machine-specific data
42
+ return `${hostname}-${platform}-${arch}`;
43
+ }
44
+ /**
45
+ * Derive an encryption key from machine identifier and salt using PBKDF2.
46
+ *
47
+ * @param salt - Salt for key derivation
48
+ * @returns Derived encryption key
49
+ */
50
+ function deriveKey(salt) {
51
+ const machineId = getMachineIdentifier();
52
+ return crypto.pbkdf2Sync(machineId, salt, ENCRYPTION_CONFIG.pbkdf2Iterations, ENCRYPTION_CONFIG.keyLength, 'sha256');
53
+ }
54
+ /**
55
+ * Encrypt a string value (typically an API key).
56
+ *
57
+ * @param plaintext - The value to encrypt
58
+ * @returns Encrypted value object with iv, tag, and encrypted data
59
+ */
60
+ export function encrypt(plaintext) {
61
+ // Generate random salt and IV
62
+ const salt = crypto.randomBytes(ENCRYPTION_CONFIG.saltLength);
63
+ const iv = crypto.randomBytes(ENCRYPTION_CONFIG.ivLength);
64
+ // Derive key from machine identifier
65
+ const key = deriveKey(salt);
66
+ // Create cipher
67
+ const cipher = crypto.createCipheriv(ENCRYPTION_CONFIG.algorithm, key, iv);
68
+ // Encrypt the plaintext
69
+ let encrypted = cipher.update(plaintext, 'utf8', 'base64');
70
+ encrypted += cipher.final('base64');
71
+ // Get authentication tag
72
+ const tag = cipher.getAuthTag();
73
+ // Return encrypted value with metadata
74
+ // Store salt in the IV field for simplicity (both are public)
75
+ const saltAndIv = Buffer.concat([salt, iv]);
76
+ return {
77
+ encrypted,
78
+ iv: saltAndIv.toString('base64'),
79
+ tag: tag.toString('base64'),
80
+ version: ENCRYPTION_CONFIG.version,
81
+ };
82
+ }
83
+ /**
84
+ * Decrypt an encrypted value.
85
+ *
86
+ * @param encryptedValue - The encrypted value object
87
+ * @returns Decrypted plaintext
88
+ * @throws Error if decryption fails (wrong machine, corrupted data, etc.)
89
+ */
90
+ export function decrypt(encryptedValue) {
91
+ try {
92
+ // Check version
93
+ if (encryptedValue.version !== ENCRYPTION_CONFIG.version) {
94
+ throw new Error(`Unsupported encryption version: ${encryptedValue.version}`);
95
+ }
96
+ // Extract salt and IV
97
+ const saltAndIv = Buffer.from(encryptedValue.iv, 'base64');
98
+ if (saltAndIv.length !== ENCRYPTION_CONFIG.saltLength + ENCRYPTION_CONFIG.ivLength) {
99
+ throw new Error('Invalid encrypted data: incorrect salt/IV length');
100
+ }
101
+ const salt = saltAndIv.subarray(0, ENCRYPTION_CONFIG.saltLength);
102
+ const iv = saltAndIv.subarray(ENCRYPTION_CONFIG.saltLength);
103
+ // Derive key from machine identifier
104
+ const key = deriveKey(salt);
105
+ // Create decipher
106
+ const decipher = crypto.createDecipheriv(ENCRYPTION_CONFIG.algorithm, key, iv);
107
+ // Set authentication tag
108
+ const tag = Buffer.from(encryptedValue.tag, 'base64');
109
+ decipher.setAuthTag(tag);
110
+ // Decrypt
111
+ let decrypted = decipher.update(encryptedValue.encrypted, 'base64', 'utf8');
112
+ decrypted += decipher.final('utf8');
113
+ return decrypted;
114
+ }
115
+ catch (error) {
116
+ // Provide a user-friendly error message
117
+ if (error instanceof Error) {
118
+ if (error.message.includes('Unsupported state or unable to authenticate data')) {
119
+ throw new Error('Failed to decrypt API key. This may be due to: ' +
120
+ '(1) moving config to a different machine, ' +
121
+ '(2) corrupted config file, or ' +
122
+ '(3) config file was manually edited. ' +
123
+ 'Please re-enter your API key.');
124
+ }
125
+ throw new Error(`Decryption failed: ${error.message}`);
126
+ }
127
+ throw new Error('Decryption failed: Unknown error');
128
+ }
129
+ }
130
+ /**
131
+ * Check if a value is encrypted (has the expected structure).
132
+ *
133
+ * @param value - Value to check
134
+ * @returns True if value appears to be encrypted
135
+ */
136
+ export function isEncrypted(value) {
137
+ if (typeof value !== 'object' || value === null) {
138
+ return false;
139
+ }
140
+ const obj = value;
141
+ return (typeof obj.encrypted === 'string' &&
142
+ typeof obj.iv === 'string' &&
143
+ typeof obj.tag === 'string' &&
144
+ typeof obj.version === 'number');
145
+ }
146
+ /**
147
+ * Encrypt an object's sensitive fields.
148
+ *
149
+ * @param obj - Object containing sensitive fields
150
+ * @param fieldsToEncrypt - Array of field names to encrypt
151
+ * @returns New object with encrypted fields
152
+ */
153
+ export function encryptFields(obj, fieldsToEncrypt) {
154
+ const result = { ...obj };
155
+ for (const field of fieldsToEncrypt) {
156
+ if (field in result && typeof result[field] === 'string') {
157
+ // Don't re-encrypt already encrypted values
158
+ if (!isEncrypted(result[field])) {
159
+ result[field] = encrypt(result[field]);
160
+ }
161
+ }
162
+ }
163
+ return result;
164
+ }
165
+ /**
166
+ * Decrypt an object's encrypted fields.
167
+ *
168
+ * @param obj - Object containing encrypted fields
169
+ * @param fieldsToDecrypt - Array of field names to decrypt
170
+ * @returns New object with decrypted fields
171
+ */
172
+ export function decryptFields(obj, fieldsToDecrypt) {
173
+ const result = { ...obj };
174
+ for (const field of fieldsToDecrypt) {
175
+ if (field in result && isEncrypted(result[field])) {
176
+ try {
177
+ result[field] = decrypt(result[field]);
178
+ }
179
+ catch (error) {
180
+ // If decryption fails, leave the field as-is and let caller handle it
181
+ console.error(`Failed to decrypt field "${field}":`, error instanceof Error ? error.message : String(error));
182
+ }
183
+ }
184
+ }
185
+ return result;
186
+ }
187
+ /**
188
+ * Test if encryption is working (for diagnostics).
189
+ *
190
+ * @returns True if encryption/decryption round-trip works
191
+ */
192
+ export function testEncryption() {
193
+ try {
194
+ const testValue = 'test-api-key-12345';
195
+ const encrypted = encrypt(testValue);
196
+ const decrypted = decrypt(encrypted);
197
+ return decrypted === testValue;
198
+ }
199
+ catch {
200
+ return false;
201
+ }
202
+ }
203
+ /**
204
+ * Get encryption info for diagnostics.
205
+ */
206
+ export function getEncryptionInfo() {
207
+ return {
208
+ algorithm: ENCRYPTION_CONFIG.algorithm,
209
+ keyLength: ENCRYPTION_CONFIG.keyLength,
210
+ ivLength: ENCRYPTION_CONFIG.ivLength,
211
+ pbkdf2Iterations: ENCRYPTION_CONFIG.pbkdf2Iterations,
212
+ version: ENCRYPTION_CONFIG.version,
213
+ machineId: getMachineIdentifier(),
214
+ };
215
+ }
216
+ //# sourceMappingURL=encryption.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encryption.js","sourceRoot":"","sources":["../../src/utils/encryption.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Error Message Sanitization (REQ-SEC-010)
3
+ *
4
+ * Sanitizes error messages to prevent information disclosure
5
+ * Removes:
6
+ * - File system paths
7
+ * - API keys and secrets
8
+ * - Stack traces (for user-facing errors)
9
+ * - Internal implementation details
10
+ *
11
+ * Security: CVSS 6.5 (Medium Priority)
12
+ */
13
+ /**
14
+ * Sanitized error structure
15
+ */
16
+ export interface SanitizedError {
17
+ /**
18
+ * Sanitized error message (safe for user display)
19
+ */
20
+ message: string;
21
+ /**
22
+ * Error code (for documentation lookup)
23
+ */
24
+ code?: string;
25
+ /**
26
+ * Generic error category
27
+ */
28
+ category: string;
29
+ /**
30
+ * Suggested action for user
31
+ */
32
+ suggestion?: string;
33
+ /**
34
+ * Original error (for internal logging only)
35
+ */
36
+ originalError?: Error;
37
+ }
38
+ /**
39
+ * Error categories for user-friendly messages
40
+ */
41
+ export declare enum ErrorCategory {
42
+ NETWORK = "NETWORK",
43
+ FILE_SYSTEM = "FILE_SYSTEM",
44
+ VALIDATION = "VALIDATION",
45
+ AUTHENTICATION = "AUTHENTICATION",
46
+ RATE_LIMIT = "RATE_LIMIT",
47
+ API_ERROR = "API_ERROR",
48
+ INTERNAL = "INTERNAL",
49
+ USER_INPUT = "USER_INPUT"
50
+ }
51
+ /**
52
+ * Sanitize error message by removing sensitive information
53
+ *
54
+ * @param message - Raw error message
55
+ * @returns Sanitized message safe for user display
56
+ */
57
+ export declare function sanitizeErrorMessage(message: string): string;
58
+ /**
59
+ * Sanitize stack trace by removing sensitive paths
60
+ *
61
+ * @param stack - Raw stack trace
62
+ * @returns Sanitized stack trace
63
+ */
64
+ export declare function sanitizeStackTrace(stack: string): string;
65
+ /**
66
+ * Remove stack trace entirely (for user-facing errors)
67
+ *
68
+ * @param message - Error message with potential stack trace
69
+ * @returns Message without stack trace
70
+ */
71
+ export declare function removeStackTrace(message: string): string;
72
+ /**
73
+ * Categorize error and create user-friendly message
74
+ *
75
+ * @param error - Error object
76
+ * @returns Sanitized error with category and suggestion
77
+ */
78
+ export declare function sanitizeError(error: Error | unknown): SanitizedError;
79
+ /**
80
+ * Format sanitized error for user display
81
+ *
82
+ * @param sanitizedError - Sanitized error object
83
+ * @returns Formatted error message
84
+ */
85
+ export declare function formatUserError(sanitizedError: SanitizedError): string;
86
+ /**
87
+ * Create internal log message with full details (not sanitized)
88
+ *
89
+ * @param error - Original error
90
+ * @param context - Additional context
91
+ * @returns Detailed log message
92
+ */
93
+ export declare function createInternalLogMessage(error: Error | unknown, context?: Record<string, unknown>): string;
94
+ /**
95
+ * Safe error wrapper for user-facing operations
96
+ *
97
+ * @param operation - Async operation to execute
98
+ * @param errorHandler - Optional custom error handler
99
+ * @returns Result or sanitized error
100
+ *
101
+ * @example
102
+ * ```typescript
103
+ * const result = await safeExecute(
104
+ * () => riskyOperation(),
105
+ * (error) => console.error('Internal error:', error)
106
+ * );
107
+ *
108
+ * if (!result.success) {
109
+ * console.log(formatUserError(result.error));
110
+ * }
111
+ * ```
112
+ */
113
+ export declare function safeExecute<T>(operation: () => Promise<T>, errorHandler?: (error: Error, sanitized: SanitizedError) => void): Promise<{
114
+ success: true;
115
+ data: T;
116
+ } | {
117
+ success: false;
118
+ error: SanitizedError;
119
+ }>;