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,44 @@
1
+ export interface RetentionRule {
2
+ retention: string;
3
+ persist: boolean;
4
+ }
5
+ export interface RetentionPolicy {
6
+ retention?: string;
7
+ persist?: boolean;
8
+ sensitivityLevels?: Record<string, RetentionRule>;
9
+ dataTypes?: Record<string, RetentionRule>;
10
+ }
11
+ export interface PurgeEntry {
12
+ id: string;
13
+ timestamp: string;
14
+ itemCount: number;
15
+ dataTypes: string[];
16
+ }
17
+ export interface SensitiveDataInfo {
18
+ detected: boolean;
19
+ count: number;
20
+ types: string[];
21
+ }
22
+ export interface SubsystemStatus {
23
+ ephemeralStorage?: boolean;
24
+ sessionPurge?: boolean;
25
+ memoryExclusion?: boolean;
26
+ }
27
+ export interface ValidationResult {
28
+ valid: boolean;
29
+ conflicts: string[];
30
+ warnings: string[];
31
+ }
32
+ export interface ZeroRetentionPaneProps {
33
+ enabled?: boolean;
34
+ policy?: RetentionPolicy;
35
+ purgeHistory?: PurgeEntry[];
36
+ sensitiveDataDetected?: SensitiveDataInfo;
37
+ subsystems?: SubsystemStatus;
38
+ validation?: ValidationResult;
39
+ isActive?: boolean;
40
+ onToggle?: () => void;
41
+ onPurge?: () => void;
42
+ }
43
+ export declare function ZeroRetentionPane({ enabled, policy, purgeHistory, sensitiveDataDetected, subsystems, validation, isActive, onToggle, onPurge, }: ZeroRetentionPaneProps): import("react/jsx-runtime").JSX.Element;
44
+ export default ZeroRetentionPane;
@@ -0,0 +1,83 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, Text, useInput } from 'ink';
3
+ function formatTimestamp(ts) {
4
+ if (!ts)
5
+ return '';
6
+ try {
7
+ const date = new Date(ts);
8
+ if (isNaN(date.getTime()))
9
+ return '';
10
+ const hours = String(date.getUTCHours()).padStart(2, '0');
11
+ const minutes = String(date.getUTCMinutes()).padStart(2, '0');
12
+ const seconds = String(date.getUTCSeconds()).padStart(2, '0');
13
+ return `${hours}:${minutes}:${seconds}`;
14
+ }
15
+ catch {
16
+ return '';
17
+ }
18
+ }
19
+ function StatusIndicator({ enabled }) {
20
+ return (_jsxs(Box, { children: [_jsx(Text, { dimColor: true, children: "Status: " }), _jsx(Text, { color: enabled ? 'green' : 'gray', bold: true, children: enabled ? 'ENABLED' : 'DISABLED' })] }));
21
+ }
22
+ function SubsystemsList({ subsystems }) {
23
+ const items = [
24
+ { key: 'ephemeralStorage', label: 'Ephemeral Storage' },
25
+ { key: 'sessionPurge', label: 'Session Purge' },
26
+ { key: 'memoryExclusion', label: 'Memory Exclusion' },
27
+ ];
28
+ return (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { bold: true, dimColor: true, children: "Subsystems:" }), items.map((item) => {
29
+ const active = subsystems[item.key];
30
+ return (_jsx(Box, { children: _jsxs(Text, { color: active ? 'green' : 'gray', children: [active ? ' [x]' : ' [ ]', " ", item.label] }) }, item.key));
31
+ })] }));
32
+ }
33
+ function PolicySummary({ policy }) {
34
+ const rules = [];
35
+ if (policy.retention) {
36
+ rules.push({ label: 'Default', value: policy.retention });
37
+ }
38
+ if (policy.sensitivityLevels) {
39
+ Object.entries(policy.sensitivityLevels).forEach(([level, rule]) => {
40
+ rules.push({ label: level, value: rule.retention });
41
+ });
42
+ }
43
+ if (policy.dataTypes) {
44
+ Object.entries(policy.dataTypes).forEach(([type, rule]) => {
45
+ rules.push({ label: type, value: rule.retention });
46
+ });
47
+ }
48
+ return (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { bold: true, dimColor: true, children: "Policy:" }), rules.length === 0 ? (_jsx(Text, { color: "gray", children: " No policy rules configured" })) : (rules.slice(0, 5).map((rule, idx) => (_jsxs(Box, { children: [_jsxs(Text, { dimColor: true, children: [" ", rule.label, ": "] }), _jsx(Text, { color: rule.value === 'immediate' ? 'cyan' : 'white', children: rule.value })] }, idx)))), rules.length > 5 && (_jsxs(Text, { dimColor: true, children: [" ... and ", rules.length - 5, " more rules"] }))] }));
49
+ }
50
+ function PurgeHistory({ entries }) {
51
+ return (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { bold: true, dimColor: true, children: "Recent Purge Activity:" }), entries.length === 0 ? (_jsx(Text, { color: "gray", children: " No purge history - none yet" })) : (entries.slice(0, 5).map((entry) => {
52
+ const timestamp = formatTimestamp(entry.timestamp);
53
+ return (_jsxs(Box, { children: [timestamp && _jsxs(Text, { dimColor: true, children: [" [", timestamp, "] "] }), _jsxs(Text, { children: ["Purged ", entry.itemCount, " items "] }), _jsxs(Text, { dimColor: true, children: ["(", entry.dataTypes.join(', '), ")"] })] }, entry.id));
54
+ }))] }));
55
+ }
56
+ function SensitiveWarning({ info }) {
57
+ if (!info.detected || info.count === 0) {
58
+ return null;
59
+ }
60
+ return (_jsxs(Box, { flexDirection: "column", marginTop: 1, borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [_jsx(Box, { children: _jsx(Text, { color: "yellow", bold: true, children: "Warning: Sensitive Data Detected" }) }), _jsx(Box, { children: _jsxs(Text, { color: "yellow", children: ["Found ", info.count, " sensitive item(s): ", info.types.join(', ')] }) }), _jsx(Box, { children: _jsx(Text, { dimColor: true, children: "Enable zero-retention mode to protect this data" }) })] }));
61
+ }
62
+ function ValidationStatus({ validation }) {
63
+ if (validation.valid && validation.warnings.length === 0) {
64
+ return (_jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "green", children: "Configuration: Valid and OK" }) }));
65
+ }
66
+ return (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [validation.conflicts.length > 0 && (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "red", bold: true, children: "Conflicts:" }), validation.conflicts.map((conflict, idx) => (_jsxs(Text, { color: "red", children: [" - ", conflict] }, idx)))] })), validation.warnings.length > 0 && (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "yellow", bold: true, children: "Warnings:" }), validation.warnings.map((warning, idx) => (_jsxs(Text, { color: "yellow", children: [" - ", warning] }, idx)))] }))] }));
67
+ }
68
+ export function ZeroRetentionPane({ enabled = false, policy, purgeHistory = [], sensitiveDataDetected, subsystems, validation, isActive = false, onToggle, onPurge, }) {
69
+ useInput((input, _key) => {
70
+ if (!isActive)
71
+ return;
72
+ // Toggle with 't'
73
+ if (input === 't' && onToggle) {
74
+ onToggle();
75
+ }
76
+ // Force purge with 'p'
77
+ if (input === 'p' && onPurge) {
78
+ onPurge();
79
+ }
80
+ }, { isActive });
81
+ return (_jsxs(Box, { padding: 1, flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, children: "Zero-Retention Mode" }) }), _jsx(StatusIndicator, { enabled: enabled }), sensitiveDataDetected && (_jsx(SensitiveWarning, { info: sensitiveDataDetected })), validation && _jsx(ValidationStatus, { validation: validation }), subsystems && _jsx(SubsystemsList, { subsystems: subsystems }), policy && _jsx(PolicySummary, { policy: policy }), _jsx(PurgeHistory, { entries: purgeHistory }), isActive && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { dimColor: true, children: ["[t] Toggle ", enabled ? 'disable' : 'enable', enabled && ' [p] Force purge'] }) }))] }));
82
+ }
83
+ export default ZeroRetentionPane;
@@ -0,0 +1,160 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
3
+ import { render } from 'ink-testing-library';
4
+ import { ZeroRetentionPane } from './ZeroRetentionPane.js';
5
+ describe('ZeroRetentionPane', () => {
6
+ beforeEach(() => {
7
+ vi.useFakeTimers();
8
+ });
9
+ afterEach(() => {
10
+ vi.useRealTimers();
11
+ });
12
+ describe('enabled state', () => {
13
+ it('renders enabled state correctly', () => {
14
+ const { lastFrame } = render(_jsx(ZeroRetentionPane, { enabled: true }));
15
+ const output = lastFrame();
16
+ expect(output).toContain('Zero-Retention');
17
+ expect(output).toMatch(/enabled|active|on/i);
18
+ });
19
+ });
20
+ describe('disabled state', () => {
21
+ it('renders disabled state correctly', () => {
22
+ const { lastFrame } = render(_jsx(ZeroRetentionPane, { enabled: false }));
23
+ const output = lastFrame();
24
+ expect(output).toContain('Zero-Retention');
25
+ expect(output).toMatch(/disabled|inactive|off/i);
26
+ });
27
+ });
28
+ describe('toggle callback', () => {
29
+ it('toggle calls onToggle callback', () => {
30
+ const onToggle = vi.fn();
31
+ const { lastFrame } = render(_jsx(ZeroRetentionPane, { enabled: false, isActive: true, onToggle: onToggle }));
32
+ // Verify toggle control is shown when active and onToggle is provided
33
+ const output = lastFrame();
34
+ expect(output).toMatch(/\[t\]|toggle/i);
35
+ });
36
+ });
37
+ describe('retention policy summary', () => {
38
+ it('shows retention policy summary', () => {
39
+ const policy = {
40
+ retention: 'immediate',
41
+ persist: false,
42
+ sensitivityLevels: {
43
+ critical: { retention: 'immediate', persist: false },
44
+ high: { retention: 'immediate', persist: false },
45
+ medium: { retention: 'session', persist: false },
46
+ low: { retention: '24h', persist: true },
47
+ },
48
+ };
49
+ const { lastFrame } = render(_jsx(ZeroRetentionPane, { enabled: true, policy: policy }));
50
+ const output = lastFrame();
51
+ expect(output).toContain('Policy');
52
+ expect(output).toMatch(/immediate|session|purge/i);
53
+ });
54
+ });
55
+ describe('purge activity list', () => {
56
+ it('shows purge activity list', () => {
57
+ const purgeHistory = [
58
+ {
59
+ id: '1',
60
+ timestamp: '2024-01-15T10:30:00.000Z',
61
+ itemCount: 5,
62
+ dataTypes: ['secrets', 'pii'],
63
+ },
64
+ {
65
+ id: '2',
66
+ timestamp: '2024-01-15T10:35:00.000Z',
67
+ itemCount: 3,
68
+ dataTypes: ['general'],
69
+ },
70
+ ];
71
+ const { lastFrame } = render(_jsx(ZeroRetentionPane, { enabled: true, purgeHistory: purgeHistory }));
72
+ const output = lastFrame();
73
+ expect(output).toContain('Purge');
74
+ expect(output).toContain('5');
75
+ expect(output).toContain('3');
76
+ });
77
+ });
78
+ describe('sensitive data warning', () => {
79
+ it('shows warning for sensitive data', () => {
80
+ const sensitiveDataDetected = {
81
+ detected: true,
82
+ count: 3,
83
+ types: ['api_key', 'password', 'pii'],
84
+ };
85
+ const { lastFrame } = render(_jsx(ZeroRetentionPane, { enabled: true, sensitiveDataDetected: sensitiveDataDetected }));
86
+ const output = lastFrame();
87
+ expect(output).toMatch(/warning|sensitive|detected/i);
88
+ expect(output).toContain('3');
89
+ });
90
+ });
91
+ describe('empty purge history', () => {
92
+ it('handles empty purge history', () => {
93
+ const { lastFrame } = render(_jsx(ZeroRetentionPane, { enabled: true, purgeHistory: [] }));
94
+ const output = lastFrame();
95
+ expect(output).toContain('Zero-Retention');
96
+ expect(output).toMatch(/no.*purge|empty|none/i);
97
+ });
98
+ });
99
+ describe('policy formatting', () => {
100
+ it('formats policy for display', () => {
101
+ const policy = {
102
+ retention: 'immediate',
103
+ persist: false,
104
+ dataTypes: {
105
+ secrets: { retention: 'immediate', persist: false },
106
+ pii: { retention: 'session', persist: false },
107
+ general: { retention: '7d', persist: true },
108
+ },
109
+ };
110
+ const { lastFrame } = render(_jsx(ZeroRetentionPane, { enabled: true, policy: policy }));
111
+ const output = lastFrame();
112
+ // Should display policy rules in a readable format
113
+ expect(output).toContain('Policy');
114
+ expect(output).toBeDefined();
115
+ });
116
+ });
117
+ describe('subsystem status', () => {
118
+ it('shows subsystem status when provided', () => {
119
+ const subsystems = {
120
+ ephemeralStorage: true,
121
+ sessionPurge: true,
122
+ memoryExclusion: true,
123
+ };
124
+ const { lastFrame } = render(_jsx(ZeroRetentionPane, { enabled: true, subsystems: subsystems }));
125
+ const output = lastFrame();
126
+ expect(output).toMatch(/ephemeral|storage/i);
127
+ expect(output).toMatch(/session|purge/i);
128
+ });
129
+ });
130
+ describe('configuration validation', () => {
131
+ it('shows validation warnings when present', () => {
132
+ const validation = {
133
+ valid: false,
134
+ conflicts: ['Ephemeral storage has basePath set'],
135
+ warnings: ['Audit logging conflicts with zero-retention'],
136
+ };
137
+ const { lastFrame } = render(_jsx(ZeroRetentionPane, { enabled: true, validation: validation }));
138
+ const output = lastFrame();
139
+ expect(output).toMatch(/conflict|warning/i);
140
+ });
141
+ it('shows valid status when no conflicts', () => {
142
+ const validation = {
143
+ valid: true,
144
+ conflicts: [],
145
+ warnings: [],
146
+ };
147
+ const { lastFrame } = render(_jsx(ZeroRetentionPane, { enabled: true, validation: validation }));
148
+ const output = lastFrame();
149
+ expect(output).toMatch(/valid|ok|configured/i);
150
+ });
151
+ });
152
+ describe('keyboard controls', () => {
153
+ it('shows controls when active', () => {
154
+ const { lastFrame } = render(_jsx(ZeroRetentionPane, { enabled: false, isActive: true }));
155
+ const output = lastFrame();
156
+ // Should show control hints
157
+ expect(output).toMatch(/\[t\]|toggle|enable|disable/i);
158
+ });
159
+ });
160
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tlc-claude-code",
3
- "version": "1.2.29",
3
+ "version": "1.4.0",
4
4
  "description": "TLC - Test Led Coding for Claude Code",
5
5
  "bin": {
6
6
  "tlc": "./bin/tlc.js",