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,551 @@
1
+ import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest';
2
+
3
+ describe('compliance-command', () => {
4
+ let ComplianceCommand;
5
+ let parseArgs;
6
+ let complianceCommand;
7
+ let mockChecklist;
8
+ let mockReporter;
9
+ let mockEvidenceCollector;
10
+ let mockPolicyGenerator;
11
+
12
+ beforeEach(async () => {
13
+ // Reset modules to ensure clean state
14
+ vi.resetModules();
15
+
16
+ // Create mock checklist
17
+ mockChecklist = {
18
+ controls: [
19
+ {
20
+ id: 'CC1.1',
21
+ category: 'Security',
22
+ name: 'Control Environment',
23
+ description: 'The entity demonstrates commitment to integrity.',
24
+ status: 'implemented',
25
+ evidence: ['ev-001'],
26
+ gapSeverity: 'high',
27
+ estimatedEffort: '2 weeks',
28
+ },
29
+ {
30
+ id: 'CC6.1',
31
+ category: 'Security',
32
+ name: 'Access Control',
33
+ description: 'Logical access security software.',
34
+ status: 'not_implemented',
35
+ evidence: [],
36
+ gapSeverity: 'high',
37
+ estimatedEffort: '4 weeks',
38
+ },
39
+ {
40
+ id: 'CC6.2',
41
+ category: 'Security',
42
+ name: 'User Registration',
43
+ description: 'Register and authorize new users.',
44
+ status: 'partial',
45
+ evidence: ['ev-002'],
46
+ gapSeverity: 'high',
47
+ estimatedEffort: '2 weeks',
48
+ },
49
+ {
50
+ id: 'A1.1',
51
+ category: 'Availability',
52
+ name: 'Capacity Planning',
53
+ description: 'Maintain and monitor capacity requirements.',
54
+ status: 'not_implemented',
55
+ evidence: [],
56
+ gapSeverity: 'high',
57
+ estimatedEffort: '3 weeks',
58
+ },
59
+ {
60
+ id: 'C1.1',
61
+ category: 'Confidentiality',
62
+ name: 'Information Classification',
63
+ description: 'Identify and maintain classifications.',
64
+ status: 'implemented',
65
+ evidence: ['ev-003'],
66
+ gapSeverity: 'high',
67
+ estimatedEffort: '2 weeks',
68
+ },
69
+ ],
70
+ };
71
+
72
+ // Create mock reporter
73
+ mockReporter = {
74
+ generateReadinessReport: vi.fn().mockReturnValue({
75
+ title: 'SOC 2 Type II Readiness Report',
76
+ generatedAt: '2026-02-02T10:00:00.000Z',
77
+ period: { start: '2026-01-01', end: '2026-02-01' },
78
+ summary: {
79
+ overallScore: 85,
80
+ riskLevel: 'medium',
81
+ riskScore: 25,
82
+ totalControls: 5,
83
+ implemented: 2,
84
+ partial: 1,
85
+ gaps: 2,
86
+ },
87
+ categories: {
88
+ Security: { score: 50, implemented: 1, partial: 1, gaps: 1, total: 3 },
89
+ Availability: { score: 0, implemented: 0, partial: 0, gaps: 1, total: 1 },
90
+ Confidentiality: { score: 100, implemented: 1, partial: 0, gaps: 0, total: 1 },
91
+ },
92
+ findings: [],
93
+ recommendations: [],
94
+ }),
95
+ formatReportMarkdown: vi.fn().mockReturnValue('# SOC 2 Report\n\nContent here'),
96
+ formatReportHTML: vi.fn().mockReturnValue('<html><body>Report</body></html>'),
97
+ };
98
+
99
+ // Create mock evidence collector
100
+ mockEvidenceCollector = {
101
+ collectAll: vi.fn().mockResolvedValue({
102
+ items: [
103
+ { id: 'ev-001', type: 'policy', title: 'Access Control Policy' },
104
+ { id: 'ev-002', type: 'audit_log', title: 'User Access Logs' },
105
+ { id: 'ev-003', type: 'config', title: 'Security Config' },
106
+ ],
107
+ summary: {
108
+ totalItems: 3,
109
+ byType: { policy: 1, audit_log: 1, config: 1 },
110
+ },
111
+ }),
112
+ getAll: vi.fn().mockReturnValue([
113
+ { id: 'ev-001', type: 'policy', title: 'Access Control Policy' },
114
+ { id: 'ev-002', type: 'audit_log', title: 'User Access Logs' },
115
+ ]),
116
+ };
117
+
118
+ // Create mock policy generator
119
+ mockPolicyGenerator = {
120
+ generateAccessControlPolicy: vi.fn().mockReturnValue({
121
+ title: 'Access Control Policy',
122
+ sections: [{ heading: 'Purpose', content: 'Test content' }],
123
+ }),
124
+ generateDataProtectionPolicy: vi.fn().mockReturnValue({
125
+ title: 'Data Protection Policy',
126
+ sections: [{ heading: 'Purpose', content: 'Test content' }],
127
+ }),
128
+ generateIncidentResponsePolicy: vi.fn().mockReturnValue({
129
+ title: 'Incident Response Policy',
130
+ sections: [{ heading: 'Purpose', content: 'Test content' }],
131
+ }),
132
+ generateAuthPolicy: vi.fn().mockReturnValue({
133
+ title: 'Authentication Policy',
134
+ sections: [{ heading: 'Purpose', content: 'Test content' }],
135
+ }),
136
+ generateAcceptableUsePolicy: vi.fn().mockReturnValue({
137
+ title: 'Acceptable Use Policy',
138
+ sections: [{ heading: 'Purpose', content: 'Test content' }],
139
+ }),
140
+ };
141
+
142
+ // Mock the checklist module
143
+ vi.doMock('./compliance-checklist.js', () => ({
144
+ createComplianceChecklist: vi.fn().mockReturnValue(mockChecklist),
145
+ getSOC2Checklist: vi.fn().mockReturnValue(mockChecklist.controls),
146
+ getCompliancePercentage: vi.fn().mockReturnValue({
147
+ percentage: 50,
148
+ implemented: 2,
149
+ partial: 1,
150
+ notImplemented: 2,
151
+ notApplicable: 0,
152
+ total: 5,
153
+ byCategory: {
154
+ Security: { percentage: 50, implemented: 1, total: 3 },
155
+ Availability: { percentage: 0, implemented: 0, total: 1 },
156
+ Confidentiality: { percentage: 100, implemented: 1, total: 1 },
157
+ },
158
+ }),
159
+ getComplianceGaps: vi.fn().mockReturnValue([
160
+ {
161
+ id: 'CC6.1',
162
+ category: 'Security',
163
+ name: 'Access Control',
164
+ status: 'not_implemented',
165
+ gapSeverity: 'high',
166
+ estimatedEffort: '4 weeks',
167
+ },
168
+ {
169
+ id: 'CC6.2',
170
+ category: 'Security',
171
+ name: 'User Registration',
172
+ status: 'partial',
173
+ gapSeverity: 'high',
174
+ estimatedEffort: '2 weeks',
175
+ },
176
+ {
177
+ id: 'A1.1',
178
+ category: 'Availability',
179
+ name: 'Capacity Planning',
180
+ status: 'not_implemented',
181
+ gapSeverity: 'high',
182
+ estimatedEffort: '3 weeks',
183
+ },
184
+ ]),
185
+ getControlsByCategory: vi.fn().mockReturnValue({
186
+ Security: mockChecklist.controls.filter((c) => c.category === 'Security'),
187
+ Availability: mockChecklist.controls.filter((c) => c.category === 'Availability'),
188
+ Confidentiality: mockChecklist.controls.filter((c) => c.category === 'Confidentiality'),
189
+ }),
190
+ TSC_CATEGORIES: {
191
+ SECURITY: 'Security',
192
+ AVAILABILITY: 'Availability',
193
+ PROCESSING_INTEGRITY: 'Processing Integrity',
194
+ CONFIDENTIALITY: 'Confidentiality',
195
+ PRIVACY: 'Privacy',
196
+ },
197
+ }));
198
+
199
+ // Mock the reporter module
200
+ vi.doMock('./compliance-reporter.js', () => ({
201
+ createReporter: vi.fn().mockReturnValue(mockReporter),
202
+ generateReadinessReport: vi.fn().mockImplementation(() => mockReporter.generateReadinessReport()),
203
+ formatReportMarkdown: vi.fn().mockImplementation(() => mockReporter.formatReportMarkdown()),
204
+ formatReportHTML: vi.fn().mockImplementation(() => mockReporter.formatReportHTML()),
205
+ calculateCategoryScores: vi.fn().mockReturnValue({
206
+ Security: { score: 50, implemented: 1, partial: 1, gaps: 1, total: 3 },
207
+ Availability: { score: 0, implemented: 0, partial: 0, gaps: 1, total: 1 },
208
+ Confidentiality: { score: 100, implemented: 1, partial: 0, gaps: 0, total: 1 },
209
+ }),
210
+ }));
211
+
212
+ // Mock the evidence collector module
213
+ vi.doMock('./evidence-collector.js', () => ({
214
+ createEvidenceCollector: vi.fn().mockReturnValue(mockEvidenceCollector),
215
+ collectPolicyDocuments: vi.fn().mockResolvedValue({
216
+ type: 'policy',
217
+ content: { policies: [] },
218
+ }),
219
+ collectConfigSnapshot: vi.fn().mockResolvedValue({
220
+ type: 'config',
221
+ content: {},
222
+ }),
223
+ collectAuditLogs: vi.fn().mockResolvedValue({
224
+ type: 'audit_log',
225
+ content: { entries: [] },
226
+ }),
227
+ }));
228
+
229
+ // Mock the policy generator module
230
+ vi.doMock('./security-policy-generator.js', () => ({
231
+ generateAccessControlPolicy: mockPolicyGenerator.generateAccessControlPolicy,
232
+ generateDataProtectionPolicy: mockPolicyGenerator.generateDataProtectionPolicy,
233
+ generateIncidentResponsePolicy: mockPolicyGenerator.generateIncidentResponsePolicy,
234
+ generateAuthPolicy: mockPolicyGenerator.generateAuthPolicy,
235
+ generateAcceptableUsePolicy: mockPolicyGenerator.generateAcceptableUsePolicy,
236
+ exportAsMarkdown: vi.fn().mockReturnValue('# Policy\n\nContent'),
237
+ }));
238
+
239
+ // Import module after mocks are set up
240
+ const module = await import('./compliance-command.js');
241
+ ComplianceCommand = module.ComplianceCommand;
242
+ parseArgs = module.parseArgs;
243
+
244
+ // Create instance with mocks
245
+ complianceCommand = new ComplianceCommand({
246
+ checklist: mockChecklist,
247
+ reporter: mockReporter,
248
+ evidenceCollector: mockEvidenceCollector,
249
+ policyGenerator: mockPolicyGenerator,
250
+ });
251
+ });
252
+
253
+ afterEach(() => {
254
+ vi.resetAllMocks();
255
+ });
256
+
257
+ describe('parseArgs', () => {
258
+ it('parses empty args', () => {
259
+ const result = parseArgs([]);
260
+ expect(result).toEqual({
261
+ subcommand: null,
262
+ category: null,
263
+ format: 'text',
264
+ output: null,
265
+ unknownSubcommand: null,
266
+ });
267
+ });
268
+
269
+ it('parses status subcommand', () => {
270
+ const result = parseArgs(['status']);
271
+ expect(result.subcommand).toBe('status');
272
+ });
273
+
274
+ it('parses checklist subcommand', () => {
275
+ const result = parseArgs(['checklist']);
276
+ expect(result.subcommand).toBe('checklist');
277
+ });
278
+
279
+ it('parses evidence subcommand', () => {
280
+ const result = parseArgs(['evidence']);
281
+ expect(result.subcommand).toBe('evidence');
282
+ });
283
+
284
+ it('parses report subcommand', () => {
285
+ const result = parseArgs(['report']);
286
+ expect(result.subcommand).toBe('report');
287
+ });
288
+
289
+ it('parses policies subcommand', () => {
290
+ const result = parseArgs(['policies']);
291
+ expect(result.subcommand).toBe('policies');
292
+ });
293
+
294
+ it('parses gaps subcommand', () => {
295
+ const result = parseArgs(['gaps']);
296
+ expect(result.subcommand).toBe('gaps');
297
+ });
298
+
299
+ it('parses --category flag', () => {
300
+ const result = parseArgs(['checklist', '--category', 'Security']);
301
+ expect(result.category).toBe('Security');
302
+ });
303
+
304
+ it('parses --category= syntax', () => {
305
+ const result = parseArgs(['checklist', '--category=Availability']);
306
+ expect(result.category).toBe('Availability');
307
+ });
308
+
309
+ it('parses --format flag', () => {
310
+ const result = parseArgs(['report', '--format', 'markdown']);
311
+ expect(result.format).toBe('markdown');
312
+ });
313
+
314
+ it('parses --format= syntax', () => {
315
+ const result = parseArgs(['report', '--format=html']);
316
+ expect(result.format).toBe('html');
317
+ });
318
+
319
+ it('parses --output flag', () => {
320
+ const result = parseArgs(['report', '--output', '/path/to/report.md']);
321
+ expect(result.output).toBe('/path/to/report.md');
322
+ });
323
+
324
+ it('handles all subcommands', () => {
325
+ const subcommands = ['status', 'checklist', 'evidence', 'report', 'policies', 'gaps'];
326
+ for (const cmd of subcommands) {
327
+ const result = parseArgs([cmd]);
328
+ expect(result.subcommand).toBe(cmd);
329
+ }
330
+ });
331
+ });
332
+
333
+ describe('execute status', () => {
334
+ it('shows compliance percentage', async () => {
335
+ const result = await complianceCommand.execute(['status']);
336
+
337
+ expect(result.success).toBe(true);
338
+ expect(result.output).toContain('50%');
339
+ });
340
+
341
+ it('shows category breakdown', async () => {
342
+ const result = await complianceCommand.execute(['status']);
343
+
344
+ expect(result.success).toBe(true);
345
+ expect(result.output).toContain('Security');
346
+ expect(result.output).toContain('Availability');
347
+ expect(result.output).toContain('Confidentiality');
348
+ });
349
+
350
+ it('shows risk level', async () => {
351
+ const result = await complianceCommand.execute(['status']);
352
+
353
+ expect(result.success).toBe(true);
354
+ // Should contain some indicator of risk
355
+ expect(result.output.toLowerCase()).toMatch(/risk|gap/i);
356
+ });
357
+
358
+ it('shows gaps count', async () => {
359
+ const result = await complianceCommand.execute(['status']);
360
+
361
+ expect(result.success).toBe(true);
362
+ expect(result.output).toMatch(/\d+\s*(gap|control)/i);
363
+ });
364
+ });
365
+
366
+ describe('execute checklist', () => {
367
+ it('shows all controls', async () => {
368
+ const result = await complianceCommand.execute(['checklist']);
369
+
370
+ expect(result.success).toBe(true);
371
+ expect(result.output).toContain('CC1.1');
372
+ expect(result.output).toContain('CC6.1');
373
+ });
374
+
375
+ it('filters by category', async () => {
376
+ const result = await complianceCommand.execute(['checklist', '--category', 'Availability']);
377
+
378
+ expect(result.success).toBe(true);
379
+ expect(result.output).toContain('A1.1');
380
+ });
381
+
382
+ it('shows control status', async () => {
383
+ const result = await complianceCommand.execute(['checklist']);
384
+
385
+ expect(result.success).toBe(true);
386
+ // Should show status indicators
387
+ expect(result.output).toMatch(/implement|partial|not/i);
388
+ });
389
+ });
390
+
391
+ describe('execute evidence', () => {
392
+ it('collects all evidence', async () => {
393
+ const result = await complianceCommand.execute(['evidence']);
394
+
395
+ expect(result.success).toBe(true);
396
+ });
397
+
398
+ it('shows collection summary', async () => {
399
+ const result = await complianceCommand.execute(['evidence']);
400
+
401
+ expect(result.success).toBe(true);
402
+ expect(result.output).toMatch(/evidence|collected|item/i);
403
+ });
404
+
405
+ it('lists evidence items', async () => {
406
+ const result = await complianceCommand.execute(['evidence']);
407
+
408
+ expect(result.success).toBe(true);
409
+ // Should show evidence types or IDs
410
+ expect(result.output).toMatch(/policy|audit|config|ev-/i);
411
+ });
412
+ });
413
+
414
+ describe('execute report', () => {
415
+ it('generates full report', async () => {
416
+ const result = await complianceCommand.execute(['report']);
417
+
418
+ expect(result.success).toBe(true);
419
+ expect(result.output).toBeTruthy();
420
+ });
421
+
422
+ it('supports format flag for markdown', async () => {
423
+ const result = await complianceCommand.execute(['report', '--format', 'markdown']);
424
+
425
+ expect(result.success).toBe(true);
426
+ });
427
+
428
+ it('supports format flag for html', async () => {
429
+ const result = await complianceCommand.execute(['report', '--format', 'html']);
430
+
431
+ expect(result.success).toBe(true);
432
+ });
433
+
434
+ it('supports text format by default', async () => {
435
+ const result = await complianceCommand.execute(['report']);
436
+
437
+ expect(result.success).toBe(true);
438
+ });
439
+ });
440
+
441
+ describe('execute policies', () => {
442
+ it('generates all policies', async () => {
443
+ const result = await complianceCommand.execute(['policies']);
444
+
445
+ expect(result.success).toBe(true);
446
+ expect(result.output).toContain('Access Control');
447
+ });
448
+
449
+ it('lists available policy types', async () => {
450
+ const result = await complianceCommand.execute(['policies']);
451
+
452
+ expect(result.success).toBe(true);
453
+ // Should mention different policy types
454
+ expect(result.output).toMatch(/access|data|incident|auth|acceptable/i);
455
+ });
456
+ });
457
+
458
+ describe('execute gaps', () => {
459
+ it('shows unimplemented controls', async () => {
460
+ const result = await complianceCommand.execute(['gaps']);
461
+
462
+ expect(result.success).toBe(true);
463
+ expect(result.output).toContain('CC6.1');
464
+ });
465
+
466
+ it('shows partial controls', async () => {
467
+ const result = await complianceCommand.execute(['gaps']);
468
+
469
+ expect(result.success).toBe(true);
470
+ expect(result.output).toContain('CC6.2');
471
+ });
472
+
473
+ it('groups by priority', async () => {
474
+ const result = await complianceCommand.execute(['gaps']);
475
+
476
+ expect(result.success).toBe(true);
477
+ expect(result.output.toLowerCase()).toMatch(/high|priority/i);
478
+ });
479
+
480
+ it('shows gap severity', async () => {
481
+ const result = await complianceCommand.execute(['gaps']);
482
+
483
+ expect(result.success).toBe(true);
484
+ expect(result.output).toMatch(/not_implemented|partial|high/i);
485
+ });
486
+ });
487
+
488
+ describe('formatStatus', () => {
489
+ it('returns readable output', () => {
490
+ const status = {
491
+ percentage: 85,
492
+ implemented: 34,
493
+ partial: 4,
494
+ notImplemented: 2,
495
+ total: 40,
496
+ byCategory: {
497
+ Security: { percentage: 90, implemented: 20, total: 22 },
498
+ Availability: { percentage: 80, implemented: 3, total: 4 },
499
+ },
500
+ };
501
+
502
+ const output = complianceCommand.formatStatus(status);
503
+
504
+ expect(output).toContain('85%');
505
+ expect(output).toContain('Security');
506
+ expect(output).toContain('Availability');
507
+ });
508
+
509
+ it('includes progress bar', () => {
510
+ const status = {
511
+ percentage: 50,
512
+ implemented: 5,
513
+ partial: 0,
514
+ notImplemented: 5,
515
+ total: 10,
516
+ byCategory: {},
517
+ };
518
+
519
+ const output = complianceCommand.formatStatus(status);
520
+
521
+ // Should have some visual progress indicator
522
+ expect(output.length).toBeGreaterThan(0);
523
+ });
524
+ });
525
+
526
+ describe('error handling', () => {
527
+ it('handles unknown subcommand', async () => {
528
+ const result = await complianceCommand.execute(['unknown']);
529
+
530
+ expect(result.success).toBe(false);
531
+ expect(result.error).toContain('unknown');
532
+ });
533
+
534
+ it('handles missing subcommand gracefully', async () => {
535
+ const result = await complianceCommand.execute([]);
536
+
537
+ // Should either show help or status by default
538
+ expect(result.success).toBe(true);
539
+ });
540
+
541
+ it('handles errors gracefully', async () => {
542
+ // Override to throw an error
543
+ complianceCommand.handleStatus = vi.fn().mockRejectedValue(new Error('Test error'));
544
+
545
+ const result = await complianceCommand.execute(['status']);
546
+
547
+ expect(result.success).toBe(false);
548
+ expect(result.error).toContain('Test error');
549
+ });
550
+ });
551
+ });