@defai.digital/ax-cli 3.6.0 → 3.6.2

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 (101) hide show
  1. package/README.md +447 -102
  2. package/config-defaults/settings.yaml +24 -0
  3. package/dist/analyzers/code-smells/detectors/data-clumps-detector.js +7 -9
  4. package/dist/analyzers/code-smells/detectors/data-clumps-detector.js.map +1 -1
  5. package/dist/analyzers/code-smells/detectors/dead-code-detector.js +1 -1
  6. package/dist/analyzers/code-smells/detectors/dead-code-detector.js.map +1 -1
  7. package/dist/analyzers/code-smells/detectors/duplicate-code-detector.js +22 -10
  8. package/dist/analyzers/code-smells/detectors/duplicate-code-detector.js.map +1 -1
  9. package/dist/analyzers/code-smells/detectors/feature-envy-detector.js +1 -1
  10. package/dist/analyzers/code-smells/detectors/feature-envy-detector.js.map +1 -1
  11. package/dist/analyzers/code-smells/detectors/inappropriate-intimacy-detector.js +1 -1
  12. package/dist/analyzers/code-smells/detectors/inappropriate-intimacy-detector.js.map +1 -1
  13. package/dist/analyzers/code-smells/detectors/large-class-detector.js +4 -1
  14. package/dist/analyzers/code-smells/detectors/large-class-detector.js.map +1 -1
  15. package/dist/analyzers/code-smells/detectors/long-method-detector.js +4 -1
  16. package/dist/analyzers/code-smells/detectors/long-method-detector.js.map +1 -1
  17. package/dist/analyzers/code-smells/detectors/long-parameter-list-detector.js +4 -1
  18. package/dist/analyzers/code-smells/detectors/long-parameter-list-detector.js.map +1 -1
  19. package/dist/analyzers/code-smells/detectors/magic-numbers-detector.js +4 -5
  20. package/dist/analyzers/code-smells/detectors/magic-numbers-detector.js.map +1 -1
  21. package/dist/analyzers/code-smells/detectors/nested-conditionals-detector.js +4 -1
  22. package/dist/analyzers/code-smells/detectors/nested-conditionals-detector.js.map +1 -1
  23. package/dist/constants.d.ts +13 -0
  24. package/dist/constants.js +28 -0
  25. package/dist/constants.js.map +1 -1
  26. package/dist/schemas/settings-schemas.d.ts +40 -0
  27. package/dist/schemas/settings-schemas.js +32 -0
  28. package/dist/schemas/settings-schemas.js.map +1 -1
  29. package/dist/tools/web-search/index.d.ts +0 -2
  30. package/dist/tools/web-search/index.js +0 -2
  31. package/dist/tools/web-search/index.js.map +1 -1
  32. package/dist/tools/web-search/router.d.ts +0 -2
  33. package/dist/tools/web-search/router.js +2 -37
  34. package/dist/tools/web-search/router.js.map +1 -1
  35. package/dist/tools/web-search/web-search-tool.js +2 -12
  36. package/dist/tools/web-search/web-search-tool.js.map +1 -1
  37. package/dist/ui/components/chat-history.d.ts +2 -0
  38. package/dist/ui/components/chat-history.js +32 -81
  39. package/dist/ui/components/chat-history.js.map +1 -1
  40. package/dist/ui/components/chat-input.d.ts +4 -1
  41. package/dist/ui/components/chat-input.js +133 -52
  42. package/dist/ui/components/chat-input.js.map +1 -1
  43. package/dist/ui/components/chat-interface.js +4 -4
  44. package/dist/ui/components/chat-interface.js.map +1 -1
  45. package/dist/ui/components/keyboard-hints.js +2 -0
  46. package/dist/ui/components/keyboard-hints.js.map +1 -1
  47. package/dist/ui/components/status-bar.d.ts +2 -0
  48. package/dist/ui/components/status-bar.js +31 -17
  49. package/dist/ui/components/status-bar.js.map +1 -1
  50. package/dist/ui/components/tool-group-display.d.ts +15 -0
  51. package/dist/ui/components/tool-group-display.js +91 -0
  52. package/dist/ui/components/tool-group-display.js.map +1 -0
  53. package/dist/ui/components/welcome-panel.js +4 -0
  54. package/dist/ui/components/welcome-panel.js.map +1 -1
  55. package/dist/ui/hooks/use-enhanced-input.d.ts +4 -0
  56. package/dist/ui/hooks/use-enhanced-input.js +156 -9
  57. package/dist/ui/hooks/use-enhanced-input.js.map +1 -1
  58. package/dist/ui/hooks/use-input-handler.d.ts +4 -0
  59. package/dist/ui/hooks/use-input-handler.js +28 -10
  60. package/dist/ui/hooks/use-input-handler.js.map +1 -1
  61. package/dist/ui/utils/change-summarizer.d.ts +20 -0
  62. package/dist/ui/utils/change-summarizer.js +193 -0
  63. package/dist/ui/utils/change-summarizer.js.map +1 -0
  64. package/dist/ui/utils/tool-grouper.d.ts +62 -0
  65. package/dist/ui/utils/tool-grouper.js +224 -0
  66. package/dist/ui/utils/tool-grouper.js.map +1 -0
  67. package/dist/utils/audit-logger.d.ts +28 -70
  68. package/dist/utils/audit-logger.js +30 -135
  69. package/dist/utils/audit-logger.js.map +1 -1
  70. package/dist/utils/config-loader.d.ts +4 -0
  71. package/dist/utils/config-loader.js.map +1 -1
  72. package/dist/utils/paste-utils.d.ts +99 -0
  73. package/dist/utils/paste-utils.js +265 -0
  74. package/dist/utils/paste-utils.js.map +1 -0
  75. package/dist/utils/rate-limiter.d.ts +15 -1
  76. package/dist/utils/rate-limiter.js +15 -1
  77. package/dist/utils/rate-limiter.js.map +1 -1
  78. package/package.json +4 -8
  79. package/packages/schemas/package.json +1 -1
  80. package/.ax-cli/CUSTOM.md +0 -269
  81. package/.ax-cli/checkpoints/2025-11-20/checkpoint-2dd84869-e62d-46c8-9885-7e45f37f36e2.json +0 -69
  82. package/.ax-cli/checkpoints/2025-11-20/checkpoint-484dc350-353f-4808-9ed1-ebb3cefdab37.json +0 -24
  83. package/.ax-cli/checkpoints/2025-11-20/checkpoint-74a18b87-6172-4215-962b-44bb9f46a662.json +0 -69
  84. package/.ax-cli/checkpoints/2025-11-20/checkpoint-870a5fb9-6e82-4ff2-8ec8-af4c251cc514.json +0 -44
  85. package/.ax-cli/checkpoints/2025-11-20/checkpoint-93946601-0e83-456c-ba47-def9713124dd.json +0 -24
  86. package/.ax-cli/checkpoints/metadata.json +0 -62
  87. package/.ax-cli/index.json +0 -44
  88. package/.ax-cli/memory.json +0 -55
  89. package/.ax-cli/settings.json +0 -1
  90. package/dist/agent/chat-history-manager.d.ts +0 -56
  91. package/dist/agent/chat-history-manager.js +0 -150
  92. package/dist/agent/chat-history-manager.js.map +0 -1
  93. package/dist/agent/tool-manager.d.ts +0 -39
  94. package/dist/agent/tool-manager.js +0 -76
  95. package/dist/agent/tool-manager.js.map +0 -1
  96. package/dist/tools/web-search/engines/brave.d.ts +0 -16
  97. package/dist/tools/web-search/engines/brave.js +0 -99
  98. package/dist/tools/web-search/engines/brave.js.map +0 -1
  99. package/dist/tools/web-search/engines/tavily.d.ts +0 -17
  100. package/dist/tools/web-search/engines/tavily.js +0 -73
  101. package/dist/tools/web-search/engines/tavily.js.map +0 -1
@@ -0,0 +1,224 @@
1
+ /**
2
+ * Tool Grouping Utilities
3
+ * Groups consecutive tool operations for cleaner UX in quiet mode
4
+ */
5
+ import { UI_CONFIG } from '../../constants.js';
6
+ /**
7
+ * Check if an entry is a ToolGroup
8
+ */
9
+ export function isToolGroup(entry) {
10
+ return 'operations' in entry && Array.isArray(entry.operations);
11
+ }
12
+ /**
13
+ * Extract file path from tool call arguments
14
+ */
15
+ function getResourceFromToolCall(entry) {
16
+ if (entry.type !== 'tool_call' && entry.type !== 'tool_result') {
17
+ return '';
18
+ }
19
+ const toolName = entry.toolCall?.function?.name;
20
+ if (!toolName)
21
+ return '';
22
+ try {
23
+ const argsStr = entry.toolCall?.function?.arguments;
24
+ if (!argsStr)
25
+ return '';
26
+ const args = JSON.parse(argsStr);
27
+ // File operations
28
+ if (toolName === 'view_file' || toolName === 'str_replace_editor' || toolName === 'create_file') {
29
+ return args.path || args.file_path || '';
30
+ }
31
+ // Search operations
32
+ if (toolName === 'search') {
33
+ return `search:${args.query || ''}`;
34
+ }
35
+ // Bash operations
36
+ if (toolName === 'bash') {
37
+ const cmd = args.command || '';
38
+ // Group by command type (git, npm, etc)
39
+ const cmdType = cmd.split(' ')[0];
40
+ return `bash:${cmdType}`;
41
+ }
42
+ // Todo operations
43
+ if (toolName === 'create_todo_list' || toolName === 'update_todo_list') {
44
+ return 'todo';
45
+ }
46
+ return '';
47
+ }
48
+ catch {
49
+ return '';
50
+ }
51
+ }
52
+ /**
53
+ * Determine group type based on tool name
54
+ */
55
+ function getGroupType(toolName) {
56
+ if (toolName === 'bash')
57
+ return 'bash';
58
+ if (toolName === 'search')
59
+ return 'search';
60
+ if (toolName === 'create_todo_list' || toolName === 'update_todo_list')
61
+ return 'todo';
62
+ if (toolName === 'view_file' || toolName === 'str_replace_editor' || toolName === 'create_file')
63
+ return 'file';
64
+ return 'mixed';
65
+ }
66
+ /**
67
+ * Check if two entries should be grouped together
68
+ */
69
+ function shouldGroup(current, previous, groupSize, maxGroupSize, timeWindow) {
70
+ // Don't group if we've hit the max size
71
+ if (groupSize >= maxGroupSize) {
72
+ return false;
73
+ }
74
+ // Only group tool operations
75
+ if ((current.type !== 'tool_call' && current.type !== 'tool_result') ||
76
+ (previous.type !== 'tool_call' && previous.type !== 'tool_result')) {
77
+ return false;
78
+ }
79
+ // Check time window
80
+ const timeDiff = current.timestamp.getTime() - previous.timestamp.getTime();
81
+ if (timeDiff > timeWindow) {
82
+ return false;
83
+ }
84
+ // Must operate on the same resource
85
+ const currentResource = getResourceFromToolCall(current);
86
+ const previousResource = getResourceFromToolCall(previous);
87
+ if (!currentResource || !previousResource) {
88
+ return false;
89
+ }
90
+ return currentResource === previousResource;
91
+ }
92
+ /**
93
+ * Group consecutive tool operations
94
+ *
95
+ * @param entries - Chat history entries
96
+ * @param options - Grouping configuration
97
+ * @returns Array of grouped or individual entries
98
+ */
99
+ export function groupConsecutiveTools(entries, options = {}) {
100
+ const { enabled = UI_CONFIG.GROUP_TOOL_CALLS, maxGroupSize = UI_CONFIG.MAX_GROUP_SIZE, timeWindow = UI_CONFIG.GROUP_TIME_WINDOW, } = options;
101
+ // If grouping disabled, return entries as-is
102
+ if (!enabled) {
103
+ return entries;
104
+ }
105
+ const result = [];
106
+ let currentGroup = null;
107
+ for (const entry of entries) {
108
+ // Non-tool entries always break the group
109
+ if (entry.type !== 'tool_call' && entry.type !== 'tool_result') {
110
+ if (currentGroup) {
111
+ result.push(currentGroup);
112
+ currentGroup = null;
113
+ }
114
+ result.push(entry);
115
+ continue;
116
+ }
117
+ const resource = getResourceFromToolCall(entry);
118
+ const toolName = entry.toolCall?.function?.name || 'unknown';
119
+ const groupType = getGroupType(toolName);
120
+ // Start new group or continue existing
121
+ if (!currentGroup) {
122
+ // Start new group
123
+ currentGroup = {
124
+ resource,
125
+ operations: [entry],
126
+ startTime: entry.timestamp instanceof Date ? entry.timestamp : new Date(entry.timestamp),
127
+ endTime: entry.timestamp instanceof Date ? entry.timestamp : new Date(entry.timestamp),
128
+ hasError: entry.toolResult ? !entry.toolResult.success : false,
129
+ groupType,
130
+ };
131
+ }
132
+ else if (shouldGroup(entry, currentGroup.operations[currentGroup.operations.length - 1], currentGroup.operations.length, maxGroupSize, timeWindow)) {
133
+ // Add to existing group
134
+ currentGroup.operations.push(entry);
135
+ currentGroup.endTime = entry.timestamp instanceof Date ? entry.timestamp : new Date(entry.timestamp);
136
+ if (entry.toolResult && !entry.toolResult.success) {
137
+ currentGroup.hasError = true;
138
+ }
139
+ }
140
+ else {
141
+ // Can't group, flush current and start new
142
+ result.push(currentGroup);
143
+ currentGroup = {
144
+ resource,
145
+ operations: [entry],
146
+ startTime: entry.timestamp instanceof Date ? entry.timestamp : new Date(entry.timestamp),
147
+ endTime: entry.timestamp instanceof Date ? entry.timestamp : new Date(entry.timestamp),
148
+ hasError: entry.toolResult ? !entry.toolResult.success : false,
149
+ groupType,
150
+ };
151
+ }
152
+ }
153
+ // Flush final group
154
+ if (currentGroup) {
155
+ result.push(currentGroup);
156
+ }
157
+ return result;
158
+ }
159
+ /**
160
+ * Get operation counts by type from a group
161
+ */
162
+ export function getOperationCounts(group) {
163
+ const counts = {
164
+ reads: 0,
165
+ updates: 0,
166
+ creates: 0,
167
+ searches: 0,
168
+ bash: 0,
169
+ todos: 0,
170
+ other: 0,
171
+ };
172
+ for (const op of group.operations) {
173
+ const toolName = op.toolCall?.function?.name;
174
+ if (!toolName)
175
+ continue;
176
+ switch (toolName) {
177
+ case 'view_file':
178
+ counts.reads++;
179
+ break;
180
+ case 'str_replace_editor':
181
+ counts.updates++;
182
+ break;
183
+ case 'create_file':
184
+ counts.creates++;
185
+ break;
186
+ case 'search':
187
+ counts.searches++;
188
+ break;
189
+ case 'bash':
190
+ counts.bash++;
191
+ break;
192
+ case 'create_todo_list':
193
+ case 'update_todo_list':
194
+ counts.todos++;
195
+ break;
196
+ default:
197
+ counts.other++;
198
+ }
199
+ }
200
+ return counts;
201
+ }
202
+ /**
203
+ * Get execution duration for a group in milliseconds
204
+ */
205
+ export function getGroupDuration(group) {
206
+ return group.endTime.getTime() - group.startTime.getTime();
207
+ }
208
+ /**
209
+ * Format duration in human-readable form
210
+ */
211
+ export function formatDuration(ms) {
212
+ if (ms < 1000) {
213
+ return `${ms}ms`;
214
+ }
215
+ else if (ms < 60000) {
216
+ return `${(ms / 1000).toFixed(1)}s`;
217
+ }
218
+ else {
219
+ const minutes = Math.floor(ms / 60000);
220
+ const seconds = Math.floor((ms % 60000) / 1000);
221
+ return `${minutes}m ${seconds}s`;
222
+ }
223
+ }
224
+ //# sourceMappingURL=tool-grouper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-grouper.js","sourceRoot":"","sources":["../../../src/ui/utils/tool-grouper.ts"],"names":[],"mappings":"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"}
@@ -1,12 +1,21 @@
1
1
  /**
2
- * Security Audit Logging System (REQ-SEC-008)
2
+ * Basic Audit Logger (Free Tier)
3
3
  *
4
- * Provides tamper-proof logging for security-critical events
5
- * Implements:
6
- * - Cryptographic log integrity verification
7
- * - Automatic log retention (90 days)
8
- * - SIEM-ready structured logging
9
- * - Critical event alerting
4
+ * Provides simple JSON logging for security events.
5
+ *
6
+ * Free Tier Features:
7
+ * Simple JSON logging to file
8
+ * 30-day retention (auto-cleanup)
9
+ * Basic event tracking
10
+ * ✅ Lightweight (no encryption, no hash chains)
11
+ *
12
+ * Enterprise features (requires @ax-cli/enterprise):
13
+ * - Compliance reports (SOC2, HIPAA, PCI-DSS)
14
+ * - Tamper-proof encrypted logs with hash chains
15
+ * - Real-time dashboards
16
+ * - Custom retention (1yr, 7yr, forever)
17
+ * - Incident response workflows
18
+ * - Anomaly detection
10
19
  *
11
20
  * Security: CVSS 6.1 (Medium Priority)
12
21
  */
@@ -37,7 +46,7 @@ export declare enum AuditCategory {
37
46
  SYSTEM_EVENT = "SYSTEM_EVENT"
38
47
  }
39
48
  /**
40
- * Audit event structure
49
+ * Audit event structure (basic version)
41
50
  */
42
51
  export interface AuditEvent {
43
52
  /**
@@ -84,17 +93,9 @@ export interface AuditEvent {
84
93
  * Source IP address (if applicable)
85
94
  */
86
95
  sourceIp?: string;
87
- /**
88
- * Previous log entry hash (for tamper detection)
89
- */
90
- previousHash?: string;
91
- /**
92
- * Current entry hash (SHA-256 of all fields)
93
- */
94
- hash?: string;
95
96
  }
96
97
  /**
97
- * Audit log configuration
98
+ * Audit log configuration (basic version)
98
99
  */
99
100
  export interface AuditLogConfig {
100
101
  /**
@@ -102,26 +103,18 @@ export interface AuditLogConfig {
102
103
  */
103
104
  logDirectory?: string;
104
105
  /**
105
- * Log retention period in days (default: 90)
106
+ * Log retention period in days (max 30 days in free tier)
106
107
  */
107
108
  retentionDays?: number;
108
- /**
109
- * Whether to emit critical event alerts
110
- */
111
- enableAlerts?: boolean;
112
- /**
113
- * Whether to enable tamper-proof chaining
114
- */
115
- enableChaining?: boolean;
116
109
  /**
117
110
  * Maximum log file size in bytes (default: 10MB)
118
111
  */
119
112
  maxFileSize?: number;
120
113
  }
121
114
  /**
122
- * Audit Logger
115
+ * Basic Audit Logger (Free Tier)
123
116
  *
124
- * Provides tamper-proof audit logging with cryptographic verification
117
+ * Simple JSON logging for security events.
125
118
  *
126
119
  * @example
127
120
  * ```typescript
@@ -136,23 +129,13 @@ export interface AuditLogConfig {
136
129
  * outcome: 'failure',
137
130
  * details: { limit: 20, attempts: 25 },
138
131
  * });
139
- *
140
- * // Log critical event (triggers alert)
141
- * logger.logCritical({
142
- * category: AuditCategory.COMMAND_EXECUTION,
143
- * action: 'shell_injection_attempt',
144
- * outcome: 'failure',
145
- * details: { command: 'ls; rm -rf /' },
146
- * });
147
132
  * ```
148
133
  */
149
134
  export declare class AuditLogger {
150
135
  private static instance;
151
136
  private config;
152
137
  private currentLogFile;
153
- private lastHash;
154
138
  private eventCount;
155
- private alertCallbacks;
156
139
  private constructor();
157
140
  /**
158
141
  * Get singleton instance
@@ -163,38 +146,25 @@ export declare class AuditLogger {
163
146
  */
164
147
  static resetInstance(): void;
165
148
  /**
166
- * Register alert callback for critical events
167
- */
168
- onCriticalEvent(callback: (event: AuditEvent) => void): void;
169
- /**
170
- * Log an audit event
149
+ * Log an audit event (basic version - no hash chains)
171
150
  */
172
- log(event: Omit<AuditEvent, 'id' | 'timestamp' | 'hash' | 'previousHash'>): void;
151
+ log(event: Omit<AuditEvent, 'id' | 'timestamp'>): void;
173
152
  /**
174
153
  * Log critical security event (convenience method)
175
154
  */
176
- logCritical(event: Omit<AuditEvent, 'id' | 'timestamp' | 'severity' | 'hash' | 'previousHash'>): void;
155
+ logCritical(event: Omit<AuditEvent, 'id' | 'timestamp' | 'severity'>): void;
177
156
  /**
178
157
  * Log warning event (convenience method)
179
158
  */
180
- logWarning(event: Omit<AuditEvent, 'id' | 'timestamp' | 'severity' | 'hash' | 'previousHash'>): void;
159
+ logWarning(event: Omit<AuditEvent, 'id' | 'timestamp' | 'severity'>): void;
181
160
  /**
182
161
  * Log error event (convenience method)
183
162
  */
184
- logError(event: Omit<AuditEvent, 'id' | 'timestamp' | 'severity' | 'hash' | 'previousHash'>): void;
163
+ logError(event: Omit<AuditEvent, 'id' | 'timestamp' | 'severity'>): void;
185
164
  /**
186
165
  * Log info event (convenience method)
187
166
  */
188
- logInfo(event: Omit<AuditEvent, 'id' | 'timestamp' | 'severity' | 'hash' | 'previousHash'>): void;
189
- /**
190
- * Verify log integrity
191
- *
192
- * Checks the hash chain to detect tampering
193
- */
194
- verifyIntegrity(logFile?: string): {
195
- valid: boolean;
196
- errors: string[];
197
- };
167
+ logInfo(event: Omit<AuditEvent, 'id' | 'timestamp' | 'severity'>): void;
198
168
  /**
199
169
  * Get audit statistics
200
170
  */
@@ -208,10 +178,6 @@ export declare class AuditLogger {
208
178
  * Generate unique event ID
209
179
  */
210
180
  private generateEventId;
211
- /**
212
- * Calculate SHA-256 hash of event (excluding hash field itself)
213
- */
214
- private calculateHash;
215
181
  /**
216
182
  * Write event to log file
217
183
  */
@@ -220,10 +186,6 @@ export declare class AuditLogger {
220
186
  * Get current log file path
221
187
  */
222
188
  private getCurrentLogFile;
223
- /**
224
- * Load last hash from current log file
225
- */
226
- private loadLastHash;
227
189
  /**
228
190
  * Check if log file needs rotation
229
191
  */
@@ -233,13 +195,9 @@ export declare class AuditLogger {
233
195
  */
234
196
  private rotateLogFile;
235
197
  /**
236
- * Clean up old log files (retention policy)
198
+ * Clean up old log files (30-day retention in free tier)
237
199
  */
238
200
  private cleanupOldLogs;
239
- /**
240
- * Emit alert for critical events
241
- */
242
- private emitAlert;
243
201
  }
244
202
  /**
245
203
  * Get audit logger singleton
@@ -1,17 +1,25 @@
1
1
  /**
2
- * Security Audit Logging System (REQ-SEC-008)
2
+ * Basic Audit Logger (Free Tier)
3
3
  *
4
- * Provides tamper-proof logging for security-critical events
5
- * Implements:
6
- * - Cryptographic log integrity verification
7
- * - Automatic log retention (90 days)
8
- * - SIEM-ready structured logging
9
- * - Critical event alerting
4
+ * Provides simple JSON logging for security events.
5
+ *
6
+ * Free Tier Features:
7
+ * Simple JSON logging to file
8
+ * 30-day retention (auto-cleanup)
9
+ * Basic event tracking
10
+ * ✅ Lightweight (no encryption, no hash chains)
11
+ *
12
+ * Enterprise features (requires @ax-cli/enterprise):
13
+ * - Compliance reports (SOC2, HIPAA, PCI-DSS)
14
+ * - Tamper-proof encrypted logs with hash chains
15
+ * - Real-time dashboards
16
+ * - Custom retention (1yr, 7yr, forever)
17
+ * - Incident response workflows
18
+ * - Anomaly detection
10
19
  *
11
20
  * Security: CVSS 6.1 (Medium Priority)
12
21
  */
13
- import { createHash } from 'crypto';
14
- import { writeFileSync, readFileSync, existsSync, mkdirSync, readdirSync, unlinkSync, statSync } from 'fs';
22
+ import { writeFileSync, existsSync, mkdirSync, readdirSync, unlinkSync, statSync } from 'fs';
15
23
  import { join } from 'path';
16
24
  import { homedir } from 'os';
17
25
  /**
@@ -43,19 +51,17 @@ export var AuditCategory;
43
51
  AuditCategory["SYSTEM_EVENT"] = "SYSTEM_EVENT";
44
52
  })(AuditCategory || (AuditCategory = {}));
45
53
  /**
46
- * Default configuration
54
+ * Default configuration (free tier)
47
55
  */
48
56
  const DEFAULT_CONFIG = {
49
57
  logDirectory: join(homedir(), '.ax-cli', 'audit-logs'),
50
- retentionDays: 90,
51
- enableAlerts: true,
52
- enableChaining: true,
58
+ retentionDays: 30, // Free tier: max 30 days
53
59
  maxFileSize: 10 * 1024 * 1024, // 10MB
54
60
  };
55
61
  /**
56
- * Audit Logger
62
+ * Basic Audit Logger (Free Tier)
57
63
  *
58
- * Provides tamper-proof audit logging with cryptographic verification
64
+ * Simple JSON logging for security events.
59
65
  *
60
66
  * @example
61
67
  * ```typescript
@@ -70,35 +76,27 @@ const DEFAULT_CONFIG = {
70
76
  * outcome: 'failure',
71
77
  * details: { limit: 20, attempts: 25 },
72
78
  * });
73
- *
74
- * // Log critical event (triggers alert)
75
- * logger.logCritical({
76
- * category: AuditCategory.COMMAND_EXECUTION,
77
- * action: 'shell_injection_attempt',
78
- * outcome: 'failure',
79
- * details: { command: 'ls; rm -rf /' },
80
- * });
81
79
  * ```
82
80
  */
83
81
  export class AuditLogger {
84
82
  static instance = null;
85
83
  config;
86
84
  currentLogFile;
87
- lastHash = null;
88
85
  eventCount = 0;
89
- alertCallbacks = [];
90
86
  constructor(config = {}) {
91
- this.config = { ...DEFAULT_CONFIG, ...config };
87
+ // Enforce free tier limits
88
+ const retentionDays = Math.min(config.retentionDays || 30, 30);
89
+ this.config = {
90
+ ...DEFAULT_CONFIG,
91
+ ...config,
92
+ retentionDays
93
+ };
92
94
  // Ensure log directory exists
93
95
  if (!existsSync(this.config.logDirectory)) {
94
96
  mkdirSync(this.config.logDirectory, { recursive: true });
95
97
  }
96
98
  // Initialize log file
97
99
  this.currentLogFile = this.getCurrentLogFile();
98
- // Load last hash for chaining
99
- if (this.config.enableChaining) {
100
- this.lastHash = this.loadLastHash();
101
- }
102
100
  // Start retention cleanup (run once on init)
103
101
  this.cleanupOldLogs();
104
102
  }
@@ -118,13 +116,7 @@ export class AuditLogger {
118
116
  AuditLogger.instance = null;
119
117
  }
120
118
  /**
121
- * Register alert callback for critical events
122
- */
123
- onCriticalEvent(callback) {
124
- this.alertCallbacks.push(callback);
125
- }
126
- /**
127
- * Log an audit event
119
+ * Log an audit event (basic version - no hash chains)
128
120
  */
129
121
  log(event) {
130
122
  const fullEvent = {
@@ -132,18 +124,8 @@ export class AuditLogger {
132
124
  timestamp: new Date().toISOString(),
133
125
  ...event,
134
126
  };
135
- // Add hash chain for tamper detection
136
- if (this.config.enableChaining) {
137
- fullEvent.previousHash = this.lastHash || undefined;
138
- fullEvent.hash = this.calculateHash(fullEvent);
139
- this.lastHash = fullEvent.hash;
140
- }
141
127
  // Write to log file
142
128
  this.writeEvent(fullEvent);
143
- // Emit alert for critical events
144
- if (this.config.enableAlerts && fullEvent.severity === AuditSeverity.CRITICAL) {
145
- this.emitAlert(fullEvent);
146
- }
147
129
  // Check if we need to rotate log file
148
130
  this.checkLogRotation();
149
131
  this.eventCount++;
@@ -184,45 +166,6 @@ export class AuditLogger {
184
166
  severity: AuditSeverity.INFO,
185
167
  });
186
168
  }
187
- /**
188
- * Verify log integrity
189
- *
190
- * Checks the hash chain to detect tampering
191
- */
192
- verifyIntegrity(logFile) {
193
- const file = logFile || this.currentLogFile;
194
- if (!existsSync(file)) {
195
- return { valid: false, errors: ['Log file does not exist'] };
196
- }
197
- const errors = [];
198
- const lines = readFileSync(file, 'utf8').split('\n').filter(l => l.trim());
199
- let previousHash = null;
200
- for (let i = 0; i < lines.length; i++) {
201
- try {
202
- const event = JSON.parse(lines[i]);
203
- // Verify hash chain (normalize undefined to null for comparison)
204
- const eventPrevHash = event.previousHash || null;
205
- if (eventPrevHash !== previousHash) {
206
- errors.push(`Event ${event.id} (line ${i + 1}): Hash chain broken. ` +
207
- `Expected previous hash: ${previousHash}, got: ${eventPrevHash}`);
208
- }
209
- // Verify event hash
210
- const calculatedHash = this.calculateHash(event);
211
- if (event.hash !== calculatedHash) {
212
- errors.push(`Event ${event.id} (line ${i + 1}): Hash mismatch. ` +
213
- `Event may have been tampered with.`);
214
- }
215
- previousHash = event.hash || null;
216
- }
217
- catch (error) {
218
- errors.push(`Line ${i + 1}: Invalid JSON - ${error instanceof Error ? error.message : 'Unknown error'}`);
219
- }
220
- }
221
- return {
222
- valid: errors.length === 0,
223
- errors,
224
- };
225
- }
226
169
  /**
227
170
  * Get audit statistics
228
171
  */
@@ -242,22 +185,6 @@ export class AuditLogger {
242
185
  const random = Math.random().toString(36).substring(2, 11);
243
186
  return `evt_${timestamp}_${random}`;
244
187
  }
245
- /**
246
- * Calculate SHA-256 hash of event (excluding hash field itself)
247
- */
248
- calculateHash(event) {
249
- // Create copy without hash field
250
- const { hash, ...eventWithoutHash } = event;
251
- // Sort keys for consistent hashing, filter out undefined values
252
- const sortedKeys = Object.keys(eventWithoutHash)
253
- .filter(key => eventWithoutHash[key] !== undefined)
254
- .sort();
255
- const data = sortedKeys.map(key => {
256
- const value = eventWithoutHash[key];
257
- return `${key}:${JSON.stringify(value)}`;
258
- }).join('|');
259
- return createHash('sha256').update(data).digest('hex');
260
- }
261
188
  /**
262
189
  * Write event to log file
263
190
  */
@@ -280,24 +207,6 @@ export class AuditLogger {
280
207
  const date = new Date().toISOString().split('T')[0]; // YYYY-MM-DD
281
208
  return join(this.config.logDirectory, `audit-${date}.jsonl`);
282
209
  }
283
- /**
284
- * Load last hash from current log file
285
- */
286
- loadLastHash() {
287
- if (!existsSync(this.currentLogFile)) {
288
- return null;
289
- }
290
- try {
291
- const lines = readFileSync(this.currentLogFile, 'utf8').split('\n').filter(l => l.trim());
292
- if (lines.length === 0)
293
- return null;
294
- const lastEvent = JSON.parse(lines[lines.length - 1]);
295
- return lastEvent.hash || null;
296
- }
297
- catch {
298
- return null;
299
- }
300
- }
301
210
  /**
302
211
  * Check if log file needs rotation
303
212
  */
@@ -322,10 +231,9 @@ export class AuditLogger {
322
231
  */
323
232
  rotateLogFile() {
324
233
  this.currentLogFile = this.getCurrentLogFile();
325
- this.lastHash = this.loadLastHash();
326
234
  }
327
235
  /**
328
- * Clean up old log files (retention policy)
236
+ * Clean up old log files (30-day retention in free tier)
329
237
  */
330
238
  cleanupOldLogs() {
331
239
  try {
@@ -351,19 +259,6 @@ export class AuditLogger {
351
259
  console.error('Failed to clean up old audit logs:', error);
352
260
  }
353
261
  }
354
- /**
355
- * Emit alert for critical events
356
- */
357
- emitAlert(event) {
358
- for (const callback of this.alertCallbacks) {
359
- try {
360
- callback(event);
361
- }
362
- catch (error) {
363
- console.error('Alert callback failed:', error);
364
- }
365
- }
366
- }
367
262
  }
368
263
  /**
369
264
  * Get audit logger singleton