tlc-claude-code 1.2.29 → 1.4.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 (182) hide show
  1. package/dashboard/dist/components/AuditPane.d.ts +30 -0
  2. package/dashboard/dist/components/AuditPane.js +127 -0
  3. package/dashboard/dist/components/AuditPane.test.d.ts +1 -0
  4. package/dashboard/dist/components/AuditPane.test.js +339 -0
  5. package/dashboard/dist/components/CompliancePane.d.ts +39 -0
  6. package/dashboard/dist/components/CompliancePane.js +96 -0
  7. package/dashboard/dist/components/CompliancePane.test.d.ts +1 -0
  8. package/dashboard/dist/components/CompliancePane.test.js +183 -0
  9. package/dashboard/dist/components/SSOPane.d.ts +36 -0
  10. package/dashboard/dist/components/SSOPane.js +71 -0
  11. package/dashboard/dist/components/SSOPane.test.d.ts +1 -0
  12. package/dashboard/dist/components/SSOPane.test.js +155 -0
  13. package/dashboard/dist/components/UsagePane.d.ts +13 -0
  14. package/dashboard/dist/components/UsagePane.js +51 -0
  15. package/dashboard/dist/components/UsagePane.test.d.ts +1 -0
  16. package/dashboard/dist/components/UsagePane.test.js +142 -0
  17. package/dashboard/dist/components/WorkspaceDocsPane.d.ts +19 -0
  18. package/dashboard/dist/components/WorkspaceDocsPane.js +130 -0
  19. package/dashboard/dist/components/WorkspaceDocsPane.test.d.ts +1 -0
  20. package/dashboard/dist/components/WorkspaceDocsPane.test.js +242 -0
  21. package/dashboard/dist/components/WorkspacePane.d.ts +18 -0
  22. package/dashboard/dist/components/WorkspacePane.js +17 -0
  23. package/dashboard/dist/components/WorkspacePane.test.d.ts +1 -0
  24. package/dashboard/dist/components/WorkspacePane.test.js +84 -0
  25. package/dashboard/dist/components/ZeroRetentionPane.d.ts +44 -0
  26. package/dashboard/dist/components/ZeroRetentionPane.js +83 -0
  27. package/dashboard/dist/components/ZeroRetentionPane.test.d.ts +1 -0
  28. package/dashboard/dist/components/ZeroRetentionPane.test.js +160 -0
  29. package/package.json +1 -1
  30. package/server/lib/access-control-doc.js +541 -0
  31. package/server/lib/access-control-doc.test.js +672 -0
  32. package/server/lib/adr-generator.js +423 -0
  33. package/server/lib/adr-generator.test.js +586 -0
  34. package/server/lib/agent-progress-monitor.js +223 -0
  35. package/server/lib/agent-progress-monitor.test.js +202 -0
  36. package/server/lib/architecture-command.js +450 -0
  37. package/server/lib/architecture-command.test.js +754 -0
  38. package/server/lib/ast-analyzer.js +324 -0
  39. package/server/lib/ast-analyzer.test.js +437 -0
  40. package/server/lib/audit-attribution.js +191 -0
  41. package/server/lib/audit-attribution.test.js +359 -0
  42. package/server/lib/audit-classifier.js +202 -0
  43. package/server/lib/audit-classifier.test.js +209 -0
  44. package/server/lib/audit-command.js +275 -0
  45. package/server/lib/audit-command.test.js +325 -0
  46. package/server/lib/audit-exporter.js +380 -0
  47. package/server/lib/audit-exporter.test.js +464 -0
  48. package/server/lib/audit-logger.js +236 -0
  49. package/server/lib/audit-logger.test.js +364 -0
  50. package/server/lib/audit-query.js +257 -0
  51. package/server/lib/audit-query.test.js +352 -0
  52. package/server/lib/audit-storage.js +269 -0
  53. package/server/lib/audit-storage.test.js +272 -0
  54. package/server/lib/auth-system.test.js +4 -1
  55. package/server/lib/boundary-detector.js +427 -0
  56. package/server/lib/boundary-detector.test.js +320 -0
  57. package/server/lib/budget-alerts.js +138 -0
  58. package/server/lib/budget-alerts.test.js +235 -0
  59. package/server/lib/bulk-repo-init.js +342 -0
  60. package/server/lib/bulk-repo-init.test.js +388 -0
  61. package/server/lib/candidates-tracker.js +210 -0
  62. package/server/lib/candidates-tracker.test.js +300 -0
  63. package/server/lib/checkpoint-manager.js +251 -0
  64. package/server/lib/checkpoint-manager.test.js +474 -0
  65. package/server/lib/circular-detector.js +337 -0
  66. package/server/lib/circular-detector.test.js +353 -0
  67. package/server/lib/cohesion-analyzer.js +310 -0
  68. package/server/lib/cohesion-analyzer.test.js +447 -0
  69. package/server/lib/compliance-checklist.js +866 -0
  70. package/server/lib/compliance-checklist.test.js +476 -0
  71. package/server/lib/compliance-command.js +616 -0
  72. package/server/lib/compliance-command.test.js +551 -0
  73. package/server/lib/compliance-reporter.js +692 -0
  74. package/server/lib/compliance-reporter.test.js +707 -0
  75. package/server/lib/contract-testing.js +625 -0
  76. package/server/lib/contract-testing.test.js +342 -0
  77. package/server/lib/conversion-planner.js +469 -0
  78. package/server/lib/conversion-planner.test.js +361 -0
  79. package/server/lib/convert-command.js +351 -0
  80. package/server/lib/convert-command.test.js +608 -0
  81. package/server/lib/coupling-calculator.js +189 -0
  82. package/server/lib/coupling-calculator.test.js +509 -0
  83. package/server/lib/data-flow-doc.js +665 -0
  84. package/server/lib/data-flow-doc.test.js +659 -0
  85. package/server/lib/dependency-graph.js +367 -0
  86. package/server/lib/dependency-graph.test.js +516 -0
  87. package/server/lib/duplication-detector.js +349 -0
  88. package/server/lib/duplication-detector.test.js +401 -0
  89. package/server/lib/ephemeral-storage.js +249 -0
  90. package/server/lib/ephemeral-storage.test.js +254 -0
  91. package/server/lib/evidence-collector.js +627 -0
  92. package/server/lib/evidence-collector.test.js +901 -0
  93. package/server/lib/example-service.js +616 -0
  94. package/server/lib/example-service.test.js +397 -0
  95. package/server/lib/flow-diagram-generator.js +474 -0
  96. package/server/lib/flow-diagram-generator.test.js +446 -0
  97. package/server/lib/idp-manager.js +626 -0
  98. package/server/lib/idp-manager.test.js +587 -0
  99. package/server/lib/impact-scorer.js +184 -0
  100. package/server/lib/impact-scorer.test.js +211 -0
  101. package/server/lib/memory-exclusion.js +326 -0
  102. package/server/lib/memory-exclusion.test.js +241 -0
  103. package/server/lib/mermaid-generator.js +358 -0
  104. package/server/lib/mermaid-generator.test.js +301 -0
  105. package/server/lib/messaging-patterns.js +750 -0
  106. package/server/lib/messaging-patterns.test.js +213 -0
  107. package/server/lib/mfa-handler.js +452 -0
  108. package/server/lib/mfa-handler.test.js +490 -0
  109. package/server/lib/microservice-template.js +386 -0
  110. package/server/lib/microservice-template.test.js +325 -0
  111. package/server/lib/new-project-microservice.js +450 -0
  112. package/server/lib/new-project-microservice.test.js +600 -0
  113. package/server/lib/oauth-flow.js +375 -0
  114. package/server/lib/oauth-flow.test.js +487 -0
  115. package/server/lib/oauth-registry.js +190 -0
  116. package/server/lib/oauth-registry.test.js +306 -0
  117. package/server/lib/readme-generator.js +490 -0
  118. package/server/lib/readme-generator.test.js +493 -0
  119. package/server/lib/refactor-command.js +326 -0
  120. package/server/lib/refactor-command.test.js +528 -0
  121. package/server/lib/refactor-executor.js +254 -0
  122. package/server/lib/refactor-executor.test.js +305 -0
  123. package/server/lib/refactor-observer.js +292 -0
  124. package/server/lib/refactor-observer.test.js +422 -0
  125. package/server/lib/refactor-progress.js +193 -0
  126. package/server/lib/refactor-progress.test.js +251 -0
  127. package/server/lib/refactor-reporter.js +237 -0
  128. package/server/lib/refactor-reporter.test.js +247 -0
  129. package/server/lib/repo-dependency-tracker.js +261 -0
  130. package/server/lib/repo-dependency-tracker.test.js +350 -0
  131. package/server/lib/retention-policy.js +281 -0
  132. package/server/lib/retention-policy.test.js +486 -0
  133. package/server/lib/role-mapper.js +236 -0
  134. package/server/lib/role-mapper.test.js +395 -0
  135. package/server/lib/saml-provider.js +765 -0
  136. package/server/lib/saml-provider.test.js +643 -0
  137. package/server/lib/security-policy-generator.js +682 -0
  138. package/server/lib/security-policy-generator.test.js +544 -0
  139. package/server/lib/semantic-analyzer.js +198 -0
  140. package/server/lib/semantic-analyzer.test.js +474 -0
  141. package/server/lib/sensitive-detector.js +112 -0
  142. package/server/lib/sensitive-detector.test.js +209 -0
  143. package/server/lib/service-interaction-diagram.js +700 -0
  144. package/server/lib/service-interaction-diagram.test.js +638 -0
  145. package/server/lib/service-scaffold.js +486 -0
  146. package/server/lib/service-scaffold.test.js +373 -0
  147. package/server/lib/service-summary.js +553 -0
  148. package/server/lib/service-summary.test.js +619 -0
  149. package/server/lib/session-purge.js +460 -0
  150. package/server/lib/session-purge.test.js +312 -0
  151. package/server/lib/shared-kernel.js +578 -0
  152. package/server/lib/shared-kernel.test.js +255 -0
  153. package/server/lib/sso-command.js +544 -0
  154. package/server/lib/sso-command.test.js +552 -0
  155. package/server/lib/sso-session.js +492 -0
  156. package/server/lib/sso-session.test.js +670 -0
  157. package/server/lib/traefik-config.js +282 -0
  158. package/server/lib/traefik-config.test.js +312 -0
  159. package/server/lib/usage-command.js +218 -0
  160. package/server/lib/usage-command.test.js +391 -0
  161. package/server/lib/usage-formatter.js +192 -0
  162. package/server/lib/usage-formatter.test.js +267 -0
  163. package/server/lib/usage-history.js +122 -0
  164. package/server/lib/usage-history.test.js +206 -0
  165. package/server/lib/workspace-command.js +249 -0
  166. package/server/lib/workspace-command.test.js +264 -0
  167. package/server/lib/workspace-config.js +270 -0
  168. package/server/lib/workspace-config.test.js +312 -0
  169. package/server/lib/workspace-docs-command.js +547 -0
  170. package/server/lib/workspace-docs-command.test.js +692 -0
  171. package/server/lib/workspace-memory.js +451 -0
  172. package/server/lib/workspace-memory.test.js +403 -0
  173. package/server/lib/workspace-scanner.js +452 -0
  174. package/server/lib/workspace-scanner.test.js +677 -0
  175. package/server/lib/workspace-test-runner.js +315 -0
  176. package/server/lib/workspace-test-runner.test.js +294 -0
  177. package/server/lib/zero-retention-command.js +439 -0
  178. package/server/lib/zero-retention-command.test.js +448 -0
  179. package/server/lib/zero-retention.js +322 -0
  180. package/server/lib/zero-retention.test.js +258 -0
  181. package/server/package-lock.json +14 -0
  182. package/server/package.json +1 -0
@@ -0,0 +1,209 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import {
3
+ classifyAction,
4
+ detectSensitive,
5
+ getSeverity,
6
+ } from './audit-classifier.js';
7
+
8
+ describe('audit-classifier', () => {
9
+ describe('classifyAction', () => {
10
+ it('returns "file:read" for Read tool', () => {
11
+ const action = { tool: 'Read', params: { file_path: '/src/index.js' } };
12
+ const result = classifyAction(action);
13
+ expect(result).toBe('file:read');
14
+ });
15
+
16
+ it('returns "file:write" for Write tool', () => {
17
+ const action = { tool: 'Write', params: { file_path: '/src/new.js', content: 'code' } };
18
+ const result = classifyAction(action);
19
+ expect(result).toBe('file:write');
20
+ });
21
+
22
+ it('returns "file:edit" for Edit tool', () => {
23
+ const action = { tool: 'Edit', params: { file_path: '/src/index.js', old_string: 'a', new_string: 'b' } };
24
+ const result = classifyAction(action);
25
+ expect(result).toBe('file:edit');
26
+ });
27
+
28
+ it('returns "shell:execute" for Bash tool', () => {
29
+ const action = { tool: 'Bash', params: { command: 'ls -la /src' } };
30
+ const result = classifyAction(action);
31
+ expect(result).toBe('shell:execute');
32
+ });
33
+
34
+ it('returns "shell:git" for git commands', () => {
35
+ const action = { tool: 'Bash', params: { command: 'git status' } };
36
+ const result = classifyAction(action);
37
+ expect(result).toBe('shell:git');
38
+ });
39
+
40
+ it('returns "shell:git" for git commands with flags', () => {
41
+ const action = { tool: 'Bash', params: { command: 'git commit -m "message"' } };
42
+ const result = classifyAction(action);
43
+ expect(result).toBe('shell:git');
44
+ });
45
+
46
+ it('returns "network:fetch" for WebFetch', () => {
47
+ const action = { tool: 'WebFetch', params: { url: 'https://example.com' } };
48
+ const result = classifyAction(action);
49
+ expect(result).toBe('network:fetch');
50
+ });
51
+
52
+ it('returns "network:search" for WebSearch', () => {
53
+ const action = { tool: 'WebSearch', params: { query: 'test query' } };
54
+ const result = classifyAction(action);
55
+ expect(result).toBe('network:search');
56
+ });
57
+
58
+ it('returns "file:glob" for Glob tool', () => {
59
+ const action = { tool: 'Glob', params: { pattern: '**/*.js' } };
60
+ const result = classifyAction(action);
61
+ expect(result).toBe('file:glob');
62
+ });
63
+
64
+ it('returns "file:grep" for Grep tool', () => {
65
+ const action = { tool: 'Grep', params: { pattern: 'function' } };
66
+ const result = classifyAction(action);
67
+ expect(result).toBe('file:grep');
68
+ });
69
+
70
+ it('returns "shell:npm" for npm commands', () => {
71
+ const action = { tool: 'Bash', params: { command: 'npm run test' } };
72
+ const result = classifyAction(action);
73
+ expect(result).toBe('shell:npm');
74
+ });
75
+
76
+ it('returns "unknown" for unrecognized tools', () => {
77
+ const action = { tool: 'CustomTool', params: {} };
78
+ const result = classifyAction(action);
79
+ expect(result).toBe('unknown');
80
+ });
81
+ });
82
+
83
+ describe('detectSensitive', () => {
84
+ it('flags .env file access', () => {
85
+ const action = { tool: 'Read', params: { file_path: '/project/.env' } };
86
+ const result = detectSensitive(action);
87
+ expect(result.isSensitive).toBe(true);
88
+ expect(result.reason).toContain('.env');
89
+ });
90
+
91
+ it('flags .env.local file access', () => {
92
+ const action = { tool: 'Write', params: { file_path: '/project/.env.local', content: 'SECRET=abc' } };
93
+ const result = detectSensitive(action);
94
+ expect(result.isSensitive).toBe(true);
95
+ });
96
+
97
+ it('flags credential patterns in file paths', () => {
98
+ const action = { tool: 'Read', params: { file_path: '/project/credentials.json' } };
99
+ const result = detectSensitive(action);
100
+ expect(result.isSensitive).toBe(true);
101
+ expect(result.reason).toContain('credential');
102
+ });
103
+
104
+ it('flags secrets directory access', () => {
105
+ const action = { tool: 'Read', params: { file_path: '/project/.secrets/api-key.txt' } };
106
+ const result = detectSensitive(action);
107
+ expect(result.isSensitive).toBe(true);
108
+ });
109
+
110
+ it('flags private key files', () => {
111
+ const action = { tool: 'Read', params: { file_path: '/home/user/.ssh/id_rsa' } };
112
+ const result = detectSensitive(action);
113
+ expect(result.isSensitive).toBe(true);
114
+ expect(result.reason).toContain('private key');
115
+ });
116
+
117
+ it('flags AWS credentials file', () => {
118
+ const action = { tool: 'Read', params: { file_path: '/home/user/.aws/credentials' } };
119
+ const result = detectSensitive(action);
120
+ expect(result.isSensitive).toBe(true);
121
+ });
122
+
123
+ it('does not flag regular source files', () => {
124
+ const action = { tool: 'Read', params: { file_path: '/project/src/index.js' } };
125
+ const result = detectSensitive(action);
126
+ expect(result.isSensitive).toBe(false);
127
+ });
128
+
129
+ it('flags password in command', () => {
130
+ const action = { tool: 'Bash', params: { command: 'echo "password=secret123"' } };
131
+ const result = detectSensitive(action);
132
+ expect(result.isSensitive).toBe(true);
133
+ });
134
+
135
+ it('flags API key in command', () => {
136
+ const action = { tool: 'Bash', params: { command: 'curl -H "Authorization: Bearer sk-abc123"' } };
137
+ const result = detectSensitive(action);
138
+ expect(result.isSensitive).toBe(true);
139
+ });
140
+
141
+ it('flags token patterns in write content', () => {
142
+ const action = { tool: 'Write', params: { file_path: '/config.js', content: 'const TOKEN = "ghp_abc123";' } };
143
+ const result = detectSensitive(action);
144
+ expect(result.isSensitive).toBe(true);
145
+ });
146
+ });
147
+
148
+ describe('getSeverity', () => {
149
+ it('returns "critical" for sensitive operations', () => {
150
+ const action = { tool: 'Read', params: { file_path: '/project/.env' } };
151
+ const result = getSeverity(action);
152
+ expect(result).toBe('critical');
153
+ });
154
+
155
+ it('returns "info" for read operations', () => {
156
+ const action = { tool: 'Read', params: { file_path: '/src/index.js' } };
157
+ const result = getSeverity(action);
158
+ expect(result).toBe('info');
159
+ });
160
+
161
+ it('returns "warning" for write operations', () => {
162
+ const action = { tool: 'Write', params: { file_path: '/src/new.js', content: 'code' } };
163
+ const result = getSeverity(action);
164
+ expect(result).toBe('warning');
165
+ });
166
+
167
+ it('returns "warning" for edit operations', () => {
168
+ const action = { tool: 'Edit', params: { file_path: '/src/index.js' } };
169
+ const result = getSeverity(action);
170
+ expect(result).toBe('warning');
171
+ });
172
+
173
+ it('returns "warning" for shell execution', () => {
174
+ const action = { tool: 'Bash', params: { command: 'npm install' } };
175
+ const result = getSeverity(action);
176
+ expect(result).toBe('warning');
177
+ });
178
+
179
+ it('returns "info" for git commands', () => {
180
+ const action = { tool: 'Bash', params: { command: 'git status' } };
181
+ const result = getSeverity(action);
182
+ expect(result).toBe('info');
183
+ });
184
+
185
+ it('returns "info" for glob/grep operations', () => {
186
+ const action = { tool: 'Glob', params: { pattern: '**/*.js' } };
187
+ const result = getSeverity(action);
188
+ expect(result).toBe('info');
189
+ });
190
+
191
+ it('returns "info" for network fetch', () => {
192
+ const action = { tool: 'WebFetch', params: { url: 'https://docs.example.com' } };
193
+ const result = getSeverity(action);
194
+ expect(result).toBe('info');
195
+ });
196
+
197
+ it('returns "critical" for destructive git commands', () => {
198
+ const action = { tool: 'Bash', params: { command: 'git push --force' } };
199
+ const result = getSeverity(action);
200
+ expect(result).toBe('critical');
201
+ });
202
+
203
+ it('returns "critical" for rm -rf commands', () => {
204
+ const action = { tool: 'Bash', params: { command: 'rm -rf /project/dist' } };
205
+ const result = getSeverity(action);
206
+ expect(result).toBe('critical');
207
+ });
208
+ });
209
+ });
@@ -0,0 +1,275 @@
1
+ /**
2
+ * Audit Command - CLI command to view and export audit logs
3
+ *
4
+ * Features:
5
+ * - View recent audit entries
6
+ * - Filter by user, action type, date
7
+ * - Export to JSON, CSV, Splunk, CEF formats
8
+ * - Verify log integrity (checksum validation)
9
+ */
10
+
11
+ import { AuditStorage } from './audit-storage.js';
12
+ import { AuditQuery } from './audit-query.js';
13
+ import { AuditExporter } from './audit-exporter.js';
14
+
15
+ const VALID_EXPORT_FORMATS = ['json', 'csv', 'splunk', 'cef'];
16
+
17
+ /**
18
+ * Parse command line arguments
19
+ * @param {string[]} args - Command line arguments
20
+ * @returns {Object} Parsed options
21
+ */
22
+ export function parseArgs(args) {
23
+ const result = {
24
+ user: null,
25
+ type: null,
26
+ since: null,
27
+ export: null,
28
+ verify: false,
29
+ limit: 20,
30
+ };
31
+
32
+ for (let i = 0; i < args.length; i++) {
33
+ const arg = args[i];
34
+
35
+ if (arg === '--verify') {
36
+ result.verify = true;
37
+ } else if (arg === '--user') {
38
+ result.user = args[i + 1];
39
+ i++;
40
+ } else if (arg.startsWith('--user=')) {
41
+ result.user = arg.split('=')[1];
42
+ } else if (arg === '--type') {
43
+ result.type = args[i + 1];
44
+ i++;
45
+ } else if (arg.startsWith('--type=')) {
46
+ result.type = arg.split('=')[1];
47
+ } else if (arg === '--since') {
48
+ result.since = args[i + 1];
49
+ i++;
50
+ } else if (arg.startsWith('--since=')) {
51
+ result.since = arg.split('=')[1];
52
+ } else if (arg === '--export') {
53
+ result.export = args[i + 1];
54
+ i++;
55
+ } else if (arg.startsWith('--export=')) {
56
+ result.export = arg.split('=')[1];
57
+ } else if (arg === '--limit') {
58
+ result.limit = parseInt(args[i + 1], 10);
59
+ i++;
60
+ } else if (arg.startsWith('--limit=')) {
61
+ result.limit = parseInt(arg.split('=')[1], 10);
62
+ }
63
+ }
64
+
65
+ return result;
66
+ }
67
+
68
+ /**
69
+ * AuditCommand class - handles tlc audit command
70
+ */
71
+ export class AuditCommand {
72
+ /**
73
+ * Create an AuditCommand instance
74
+ * @param {Object} options - Configuration options
75
+ * @param {AuditStorage} options.storage - AuditStorage instance
76
+ * @param {AuditQuery} options.query - AuditQuery instance
77
+ * @param {AuditExporter} options.exporter - AuditExporter instance
78
+ * @param {string} options.baseDir - Base directory for audit storage
79
+ */
80
+ constructor(options = {}) {
81
+ this.storage = options.storage || new AuditStorage(options.baseDir);
82
+ this.query = options.query || new AuditQuery(this.storage);
83
+ this.exporter = options.exporter || new AuditExporter(options.baseDir);
84
+ }
85
+
86
+ /**
87
+ * Execute the audit command
88
+ * @param {string[]} args - Command arguments
89
+ * @returns {Promise<Object>} Result { success, output, error? }
90
+ */
91
+ async execute(args) {
92
+ const options = parseArgs(args);
93
+
94
+ try {
95
+ // Handle --verify flag
96
+ if (options.verify) {
97
+ return await this.handleVerify();
98
+ }
99
+
100
+ // Handle --export flag
101
+ if (options.export) {
102
+ return await this.handleExport(options);
103
+ }
104
+
105
+ // Default: query and display entries
106
+ return await this.handleQuery(options);
107
+ } catch (error) {
108
+ return {
109
+ success: false,
110
+ output: '',
111
+ error: error.message,
112
+ };
113
+ }
114
+ }
115
+
116
+ /**
117
+ * Handle --verify flag
118
+ * @returns {Promise<Object>} Result
119
+ */
120
+ async handleVerify() {
121
+ const result = await this.storage.verifyIntegrity();
122
+ const output = this.formatVerifyResult(result);
123
+
124
+ return {
125
+ success: result.valid,
126
+ output,
127
+ };
128
+ }
129
+
130
+ /**
131
+ * Handle --export flag
132
+ * @param {Object} options - Parsed options
133
+ * @returns {Promise<Object>} Result
134
+ */
135
+ async handleExport(options) {
136
+ const format = options.export.toLowerCase();
137
+
138
+ if (!VALID_EXPORT_FORMATS.includes(format)) {
139
+ return {
140
+ success: false,
141
+ output: '',
142
+ error: `Invalid export format: ${options.export}. Valid formats: ${VALID_EXPORT_FORMATS.join(', ')}`,
143
+ };
144
+ }
145
+
146
+ // Build export options
147
+ const exportOptions = {};
148
+ if (options.since) {
149
+ exportOptions.from = new Date(options.since);
150
+ }
151
+
152
+ let content;
153
+ switch (format) {
154
+ case 'json':
155
+ content = await this.exporter.exportJSON(exportOptions);
156
+ break;
157
+ case 'csv':
158
+ content = await this.exporter.exportCSV(exportOptions);
159
+ break;
160
+ case 'splunk':
161
+ content = await this.exporter.exportSplunk(exportOptions);
162
+ break;
163
+ case 'cef':
164
+ content = await this.exporter.exportCEF(exportOptions);
165
+ break;
166
+ }
167
+
168
+ return {
169
+ success: true,
170
+ output: content,
171
+ };
172
+ }
173
+
174
+ /**
175
+ * Handle query (default behavior)
176
+ * @param {Object} options - Parsed options
177
+ * @returns {Promise<Object>} Result
178
+ */
179
+ async handleQuery(options) {
180
+ // Build query options
181
+ const queryOptions = {
182
+ limit: options.limit,
183
+ sort: 'desc',
184
+ };
185
+
186
+ if (options.user) {
187
+ queryOptions.user = options.user;
188
+ }
189
+
190
+ if (options.type) {
191
+ queryOptions.action = options.type;
192
+ }
193
+
194
+ if (options.since) {
195
+ queryOptions.from = new Date(options.since);
196
+ }
197
+
198
+ const result = await this.query.query(queryOptions);
199
+
200
+ if (result.entries.length === 0) {
201
+ return {
202
+ success: true,
203
+ output: 'No audit entries found.',
204
+ };
205
+ }
206
+
207
+ const output = this.formatQueryResult(result);
208
+
209
+ return {
210
+ success: true,
211
+ output,
212
+ };
213
+ }
214
+
215
+ /**
216
+ * Format query result for display
217
+ * @param {Object} result - Query result
218
+ * @returns {string} Formatted output
219
+ */
220
+ formatQueryResult(result) {
221
+ const lines = [];
222
+
223
+ lines.push(`Audit Log (${result.total} entries)`);
224
+ lines.push('='.repeat(60));
225
+ lines.push('');
226
+
227
+ for (const entry of result.entries) {
228
+ lines.push(this.formatEntry(entry));
229
+ }
230
+
231
+ if (result.hasMore) {
232
+ lines.push('');
233
+ lines.push(`... and more. Use --limit to see more entries.`);
234
+ }
235
+
236
+ return lines.join('\n');
237
+ }
238
+
239
+ /**
240
+ * Format a single entry for display
241
+ * @param {Object} entry - Audit entry
242
+ * @returns {string} Formatted entry
243
+ */
244
+ formatEntry(entry) {
245
+ const timestamp = entry.timestamp ? entry.timestamp.substring(0, 19).replace('T', ' ') : 'unknown';
246
+ const tool = entry.tool || 'unknown';
247
+ const user = entry.attribution?.user || entry.user || '-';
248
+ const classification = entry.classification || '-';
249
+ const severity = entry.severity || 'info';
250
+
251
+ return `[${timestamp}] ${severity.toUpperCase().padEnd(8)} ${tool.padEnd(12)} ${classification.padEnd(20)} ${user}`;
252
+ }
253
+
254
+ /**
255
+ * Format verify result for display
256
+ * @param {Object} result - Verification result
257
+ * @returns {string} Formatted output
258
+ */
259
+ formatVerifyResult(result) {
260
+ const lines = [];
261
+
262
+ if (result.valid) {
263
+ lines.push('Audit log integrity check: VALID');
264
+ lines.push(`Verified ${result.entryCount} entries`);
265
+ lines.push('All checksums and chain links are valid.');
266
+ } else {
267
+ lines.push('Audit log integrity check: INVALID');
268
+ lines.push(`Error at entry ${result.entryCount}: ${result.error}`);
269
+ lines.push('');
270
+ lines.push('WARNING: Possible tampering detected!');
271
+ }
272
+
273
+ return lines.join('\n');
274
+ }
275
+ }