tlc-claude-code 1.2.26 → 1.2.28

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 (177) hide show
  1. package/dashboard/dist/components/ActivityFeed.d.ts +17 -0
  2. package/dashboard/dist/components/ActivityFeed.js +42 -0
  3. package/dashboard/dist/components/ActivityFeed.test.d.ts +1 -0
  4. package/dashboard/dist/components/ActivityFeed.test.js +162 -0
  5. package/dashboard/dist/components/BranchSelector.d.ts +16 -0
  6. package/dashboard/dist/components/BranchSelector.js +49 -0
  7. package/dashboard/dist/components/BranchSelector.test.d.ts +1 -0
  8. package/dashboard/dist/components/BranchSelector.test.js +166 -0
  9. package/dashboard/dist/components/CommandPalette.d.ts +17 -0
  10. package/dashboard/dist/components/CommandPalette.js +118 -0
  11. package/dashboard/dist/components/CommandPalette.test.d.ts +1 -0
  12. package/dashboard/dist/components/CommandPalette.test.js +181 -0
  13. package/dashboard/dist/components/ConnectionStatus.d.ts +16 -0
  14. package/dashboard/dist/components/ConnectionStatus.js +27 -0
  15. package/dashboard/dist/components/ConnectionStatus.test.d.ts +1 -0
  16. package/dashboard/dist/components/ConnectionStatus.test.js +121 -0
  17. package/dashboard/dist/components/DeviceFrame.d.ts +19 -0
  18. package/dashboard/dist/components/DeviceFrame.js +52 -0
  19. package/dashboard/dist/components/DeviceFrame.test.d.ts +1 -0
  20. package/dashboard/dist/components/DeviceFrame.test.js +118 -0
  21. package/dashboard/dist/components/EnvironmentBadge.d.ts +11 -0
  22. package/dashboard/dist/components/EnvironmentBadge.js +16 -0
  23. package/dashboard/dist/components/EnvironmentBadge.test.d.ts +1 -0
  24. package/dashboard/dist/components/EnvironmentBadge.test.js +102 -0
  25. package/dashboard/dist/components/FocusIndicator.d.ts +19 -0
  26. package/dashboard/dist/components/FocusIndicator.js +47 -0
  27. package/dashboard/dist/components/FocusIndicator.test.d.ts +1 -0
  28. package/dashboard/dist/components/FocusIndicator.test.js +117 -0
  29. package/dashboard/dist/components/KeyboardHelp.d.ts +15 -0
  30. package/dashboard/dist/components/KeyboardHelp.js +61 -0
  31. package/dashboard/dist/components/KeyboardHelp.test.d.ts +1 -0
  32. package/dashboard/dist/components/KeyboardHelp.test.js +131 -0
  33. package/dashboard/dist/components/LogSearch.d.ts +13 -0
  34. package/dashboard/dist/components/LogSearch.js +43 -0
  35. package/dashboard/dist/components/LogSearch.test.d.ts +1 -0
  36. package/dashboard/dist/components/LogSearch.test.js +100 -0
  37. package/dashboard/dist/components/LogStream.d.ts +21 -0
  38. package/dashboard/dist/components/LogStream.js +123 -0
  39. package/dashboard/dist/components/LogStream.test.d.ts +1 -0
  40. package/dashboard/dist/components/LogStream.test.js +159 -0
  41. package/dashboard/dist/components/PlanView.d.ts +7 -0
  42. package/dashboard/dist/components/PlanView.js +74 -2
  43. package/dashboard/dist/components/PlanView.test.js +70 -1
  44. package/dashboard/dist/components/PreviewPanel.d.ts +18 -0
  45. package/dashboard/dist/components/PreviewPanel.js +73 -0
  46. package/dashboard/dist/components/PreviewPanel.test.d.ts +1 -0
  47. package/dashboard/dist/components/PreviewPanel.test.js +124 -0
  48. package/dashboard/dist/components/ProjectCard.d.ts +18 -0
  49. package/dashboard/dist/components/ProjectCard.js +19 -0
  50. package/dashboard/dist/components/ProjectCard.test.d.ts +1 -0
  51. package/dashboard/dist/components/ProjectCard.test.js +53 -0
  52. package/dashboard/dist/components/ProjectDetail.d.ts +44 -0
  53. package/dashboard/dist/components/ProjectDetail.js +65 -0
  54. package/dashboard/dist/components/ProjectDetail.test.d.ts +1 -0
  55. package/dashboard/dist/components/ProjectDetail.test.js +196 -0
  56. package/dashboard/dist/components/ProjectList.d.ts +11 -0
  57. package/dashboard/dist/components/ProjectList.js +62 -0
  58. package/dashboard/dist/components/ProjectList.test.d.ts +1 -0
  59. package/dashboard/dist/components/ProjectList.test.js +93 -0
  60. package/dashboard/dist/components/SettingsPanel.d.ts +32 -0
  61. package/dashboard/dist/components/SettingsPanel.js +154 -0
  62. package/dashboard/dist/components/SettingsPanel.test.d.ts +1 -0
  63. package/dashboard/dist/components/SettingsPanel.test.js +196 -0
  64. package/dashboard/dist/components/StatusBar.d.ts +16 -0
  65. package/dashboard/dist/components/StatusBar.js +47 -0
  66. package/dashboard/dist/components/StatusBar.test.d.ts +1 -0
  67. package/dashboard/dist/components/StatusBar.test.js +123 -0
  68. package/dashboard/dist/components/TaskBoard.d.ts +22 -0
  69. package/dashboard/dist/components/TaskBoard.js +102 -0
  70. package/dashboard/dist/components/TaskBoard.test.d.ts +1 -0
  71. package/dashboard/dist/components/TaskBoard.test.js +113 -0
  72. package/dashboard/dist/components/TaskCard.d.ts +17 -0
  73. package/dashboard/dist/components/TaskCard.js +29 -0
  74. package/dashboard/dist/components/TaskCard.test.d.ts +1 -0
  75. package/dashboard/dist/components/TaskCard.test.js +109 -0
  76. package/dashboard/dist/components/TaskDetail.d.ts +36 -0
  77. package/dashboard/dist/components/TaskDetail.js +41 -0
  78. package/dashboard/dist/components/TaskDetail.test.d.ts +1 -0
  79. package/dashboard/dist/components/TaskDetail.test.js +164 -0
  80. package/dashboard/dist/components/TaskFilter.d.ts +12 -0
  81. package/dashboard/dist/components/TaskFilter.js +138 -0
  82. package/dashboard/dist/components/TaskFilter.test.d.ts +1 -0
  83. package/dashboard/dist/components/TaskFilter.test.js +109 -0
  84. package/dashboard/dist/components/TeamPanel.d.ts +15 -0
  85. package/dashboard/dist/components/TeamPanel.js +24 -0
  86. package/dashboard/dist/components/TeamPanel.test.d.ts +1 -0
  87. package/dashboard/dist/components/TeamPanel.test.js +109 -0
  88. package/dashboard/dist/components/TeamPresence.d.ts +14 -0
  89. package/dashboard/dist/components/TeamPresence.js +31 -0
  90. package/dashboard/dist/components/TeamPresence.test.d.ts +1 -0
  91. package/dashboard/dist/components/TeamPresence.test.js +144 -0
  92. package/dashboard/dist/components/layout/Header.d.ts +9 -0
  93. package/dashboard/dist/components/layout/Header.js +11 -0
  94. package/dashboard/dist/components/layout/Header.test.d.ts +1 -0
  95. package/dashboard/dist/components/layout/Header.test.js +35 -0
  96. package/dashboard/dist/components/layout/Shell.d.ts +10 -0
  97. package/dashboard/dist/components/layout/Shell.js +5 -0
  98. package/dashboard/dist/components/layout/Shell.test.d.ts +1 -0
  99. package/dashboard/dist/components/layout/Shell.test.js +34 -0
  100. package/dashboard/dist/components/layout/Sidebar.d.ts +14 -0
  101. package/dashboard/dist/components/layout/Sidebar.js +8 -0
  102. package/dashboard/dist/components/layout/Sidebar.test.d.ts +1 -0
  103. package/dashboard/dist/components/layout/Sidebar.test.js +40 -0
  104. package/dashboard/dist/components/ui/Badge.d.ts +9 -0
  105. package/dashboard/dist/components/ui/Badge.js +13 -0
  106. package/dashboard/dist/components/ui/Badge.test.d.ts +1 -0
  107. package/dashboard/dist/components/ui/Badge.test.js +69 -0
  108. package/dashboard/dist/components/ui/Button.d.ts +12 -0
  109. package/dashboard/dist/components/ui/Button.js +14 -0
  110. package/dashboard/dist/components/ui/Button.test.d.ts +1 -0
  111. package/dashboard/dist/components/ui/Button.test.js +81 -0
  112. package/dashboard/dist/components/ui/Card.d.ts +21 -0
  113. package/dashboard/dist/components/ui/Card.js +20 -0
  114. package/dashboard/dist/components/ui/Card.test.d.ts +1 -0
  115. package/dashboard/dist/components/ui/Card.test.js +82 -0
  116. package/dashboard/dist/components/ui/Input.d.ts +13 -0
  117. package/dashboard/dist/components/ui/Input.js +8 -0
  118. package/dashboard/dist/components/ui/Input.test.d.ts +1 -0
  119. package/dashboard/dist/components/ui/Input.test.js +68 -0
  120. package/dashboard/dist/styles/tokens.d.ts +150 -0
  121. package/dashboard/dist/styles/tokens.js +184 -0
  122. package/dashboard/dist/styles/tokens.test.d.ts +1 -0
  123. package/dashboard/dist/styles/tokens.test.js +95 -0
  124. package/dashboard/dist/test/setup.d.ts +1 -0
  125. package/dashboard/dist/test/setup.js +1 -0
  126. package/dashboard/package.json +3 -0
  127. package/package.json +1 -1
  128. package/server/dashboard/index.html +157 -2
  129. package/server/index.js +38 -21
  130. package/server/lib/adapters/base-adapter.js +114 -0
  131. package/server/lib/adapters/base-adapter.test.js +90 -0
  132. package/server/lib/adapters/claude-adapter.js +141 -0
  133. package/server/lib/adapters/claude-adapter.test.js +180 -0
  134. package/server/lib/adapters/deepseek-adapter.js +153 -0
  135. package/server/lib/adapters/deepseek-adapter.test.js +193 -0
  136. package/server/lib/adapters/openai-adapter.js +190 -0
  137. package/server/lib/adapters/openai-adapter.test.js +231 -0
  138. package/server/lib/budget-tracker.js +169 -0
  139. package/server/lib/budget-tracker.test.js +165 -0
  140. package/server/lib/claude-injector.js +85 -0
  141. package/server/lib/claude-injector.test.js +161 -0
  142. package/server/lib/consensus-engine.js +135 -0
  143. package/server/lib/consensus-engine.test.js +152 -0
  144. package/server/lib/context-builder.js +112 -0
  145. package/server/lib/context-builder.test.js +120 -0
  146. package/server/lib/file-collector.js +322 -0
  147. package/server/lib/file-collector.test.js +307 -0
  148. package/server/lib/memory-classifier.js +175 -0
  149. package/server/lib/memory-classifier.test.js +169 -0
  150. package/server/lib/memory-committer.js +138 -0
  151. package/server/lib/memory-committer.test.js +136 -0
  152. package/server/lib/memory-hooks.js +127 -0
  153. package/server/lib/memory-hooks.test.js +136 -0
  154. package/server/lib/memory-init.js +104 -0
  155. package/server/lib/memory-init.test.js +119 -0
  156. package/server/lib/memory-observer.js +149 -0
  157. package/server/lib/memory-observer.test.js +158 -0
  158. package/server/lib/memory-reader.js +243 -0
  159. package/server/lib/memory-reader.test.js +216 -0
  160. package/server/lib/memory-storage.js +120 -0
  161. package/server/lib/memory-storage.test.js +136 -0
  162. package/server/lib/memory-writer.js +176 -0
  163. package/server/lib/memory-writer.test.js +231 -0
  164. package/server/lib/overdrive-command.js +30 -6
  165. package/server/lib/overdrive-command.test.js +8 -1
  166. package/server/lib/pattern-detector.js +216 -0
  167. package/server/lib/pattern-detector.test.js +241 -0
  168. package/server/lib/relevance-scorer.js +175 -0
  169. package/server/lib/relevance-scorer.test.js +107 -0
  170. package/server/lib/review-command.js +238 -0
  171. package/server/lib/review-command.test.js +245 -0
  172. package/server/lib/review-orchestrator.js +273 -0
  173. package/server/lib/review-orchestrator.test.js +300 -0
  174. package/server/lib/review-reporter.js +288 -0
  175. package/server/lib/review-reporter.test.js +240 -0
  176. package/server/lib/session-summary.js +90 -0
  177. package/server/lib/session-summary.test.js +156 -0
@@ -0,0 +1,82 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { describe, it, expect } from 'vitest';
3
+ import { render } from 'ink-testing-library';
4
+ import { Card, CardHeader, CardBody, CardFooter } from './Card.js';
5
+ describe('Card', () => {
6
+ it('renders children', () => {
7
+ const { lastFrame } = render(_jsx(Card, { children: "Content" }));
8
+ expect(lastFrame()).toContain('Content');
9
+ });
10
+ it('renders with border by default', () => {
11
+ const { lastFrame } = render(_jsx(Card, { children: "Test" }));
12
+ const output = lastFrame() ?? '';
13
+ // Should contain box-drawing characters (various unicode box drawing)
14
+ expect(output).toContain('Test');
15
+ // Ink uses various box characters depending on style
16
+ expect(output.length).toBeGreaterThan('Test'.length);
17
+ });
18
+ describe('variants', () => {
19
+ it('renders default variant', () => {
20
+ const { lastFrame } = render(_jsx(Card, { variant: "default", children: "Default" }));
21
+ expect(lastFrame()).toContain('Default');
22
+ });
23
+ it('renders elevated variant with double border', () => {
24
+ const { lastFrame } = render(_jsx(Card, { variant: "elevated", children: "Elevated" }));
25
+ const output = lastFrame();
26
+ expect(output).toContain('Elevated');
27
+ });
28
+ it('renders outlined variant', () => {
29
+ const { lastFrame } = render(_jsx(Card, { variant: "outlined", children: "Outlined" }));
30
+ expect(lastFrame()).toContain('Outlined');
31
+ });
32
+ });
33
+ describe('title', () => {
34
+ it('renders title when provided', () => {
35
+ const { lastFrame } = render(_jsx(Card, { title: "My Card", children: "Body" }));
36
+ const output = lastFrame();
37
+ expect(output).toContain('My Card');
38
+ expect(output).toContain('Body');
39
+ });
40
+ });
41
+ describe('padding', () => {
42
+ it('respects padding prop', () => {
43
+ const { lastFrame } = render(_jsx(Card, { padding: 2, children: "Padded" }));
44
+ expect(lastFrame()).toContain('Padded');
45
+ });
46
+ });
47
+ });
48
+ describe('CardHeader', () => {
49
+ it('renders header content', () => {
50
+ const { lastFrame } = render(_jsx(CardHeader, { children: "Header" }));
51
+ expect(lastFrame()).toContain('Header');
52
+ });
53
+ it('renders with bold style', () => {
54
+ const { lastFrame } = render(_jsx(CardHeader, { children: "Title" }));
55
+ expect(lastFrame()).toContain('Title');
56
+ });
57
+ });
58
+ describe('CardBody', () => {
59
+ it('renders body content', () => {
60
+ const { lastFrame } = render(_jsx(CardBody, { children: "Body content" }));
61
+ expect(lastFrame()).toContain('Body content');
62
+ });
63
+ });
64
+ describe('CardFooter', () => {
65
+ it('renders footer content', () => {
66
+ const { lastFrame } = render(_jsx(CardFooter, { children: "Footer" }));
67
+ expect(lastFrame()).toContain('Footer');
68
+ });
69
+ it('renders with dimmed style', () => {
70
+ const { lastFrame } = render(_jsx(CardFooter, { children: "Actions" }));
71
+ expect(lastFrame()).toContain('Actions');
72
+ });
73
+ });
74
+ describe('Card composition', () => {
75
+ it('renders header, body, and footer together', () => {
76
+ const { lastFrame } = render(_jsxs(Card, { children: [_jsx(CardHeader, { children: "Title" }), _jsx(CardBody, { children: "Content here" }), _jsx(CardFooter, { children: "Actions" })] }));
77
+ const output = lastFrame();
78
+ expect(output).toContain('Title');
79
+ expect(output).toContain('Content here');
80
+ expect(output).toContain('Actions');
81
+ });
82
+ });
@@ -0,0 +1,13 @@
1
+ export interface InputProps {
2
+ value?: string;
3
+ placeholder?: string;
4
+ label?: string;
5
+ helperText?: string;
6
+ error?: string;
7
+ type?: 'text' | 'password';
8
+ focus?: boolean;
9
+ disabled?: boolean;
10
+ onChange?: (value: string) => void;
11
+ onSubmit?: (value: string) => void;
12
+ }
13
+ export declare function Input({ value, placeholder, label, helperText, error, type, focus, disabled, onChange, onSubmit, }: InputProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,8 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Text, Box } from 'ink';
3
+ import TextInput from 'ink-text-input';
4
+ export function Input({ value = '', placeholder = '', label, helperText, error, type = 'text', focus = false, disabled = false, onChange = () => { }, onSubmit, }) {
5
+ const displayValue = type === 'password' ? '*'.repeat(value.length) : value;
6
+ const borderColor = error ? 'red' : focus ? 'cyan' : 'gray';
7
+ return (_jsxs(Box, { flexDirection: "column", children: [label && (_jsx(Box, { marginBottom: 0, children: _jsx(Text, { color: "white", bold: true, children: label }) })), _jsxs(Box, { children: [_jsx(Text, { color: borderColor, children: "[" }), disabled ? (_jsx(Text, { dimColor: true, children: displayValue || placeholder })) : focus ? (_jsx(TextInput, { value: value, placeholder: placeholder, onChange: onChange, onSubmit: onSubmit, mask: type === 'password' ? '*' : undefined })) : (_jsx(Text, { color: value ? 'white' : 'gray', children: displayValue || placeholder })), _jsx(Text, { color: borderColor, children: "]" })] }), error && (_jsx(Box, { children: _jsxs(Text, { color: "red", children: ["\u2717 ", error] }) })), helperText && !error && (_jsx(Box, { children: _jsx(Text, { dimColor: true, children: helperText }) }))] }));
8
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,68 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { describe, it, expect } from 'vitest';
3
+ import { render } from 'ink-testing-library';
4
+ import { Input } from './Input.js';
5
+ describe('Input', () => {
6
+ it('renders with placeholder', () => {
7
+ const { lastFrame } = render(_jsx(Input, { placeholder: "Enter text..." }));
8
+ expect(lastFrame()).toContain('Enter text...');
9
+ });
10
+ it('renders with value', () => {
11
+ const { lastFrame } = render(_jsx(Input, { value: "Hello", onChange: () => { } }));
12
+ expect(lastFrame()).toContain('Hello');
13
+ });
14
+ describe('label', () => {
15
+ it('renders label when provided', () => {
16
+ const { lastFrame } = render(_jsx(Input, { label: "Username" }));
17
+ expect(lastFrame()).toContain('Username');
18
+ });
19
+ });
20
+ describe('helper text', () => {
21
+ it('renders helper text when provided', () => {
22
+ const { lastFrame } = render(_jsx(Input, { helperText: "Must be unique" }));
23
+ expect(lastFrame()).toContain('Must be unique');
24
+ });
25
+ });
26
+ describe('error state', () => {
27
+ it('shows error message when provided', () => {
28
+ const { lastFrame } = render(_jsx(Input, { error: "Invalid input" }));
29
+ expect(lastFrame()).toContain('Invalid input');
30
+ });
31
+ it('shows error indicator', () => {
32
+ const { lastFrame } = render(_jsx(Input, { error: "Error" }));
33
+ expect(lastFrame()).toContain('✗');
34
+ });
35
+ });
36
+ describe('focus', () => {
37
+ it('shows focus indicator when focused', () => {
38
+ const { lastFrame } = render(_jsx(Input, { focus: true, placeholder: "Focused" }));
39
+ const output = lastFrame();
40
+ expect(output).toContain('Focused');
41
+ });
42
+ it('shows different style when not focused', () => {
43
+ const { lastFrame: focused } = render(_jsx(Input, { focus: true, placeholder: "Test" }));
44
+ const { lastFrame: unfocused } = render(_jsx(Input, { focus: false, placeholder: "Test" }));
45
+ // Both should render
46
+ expect(focused()).toBeTruthy();
47
+ expect(unfocused()).toBeTruthy();
48
+ });
49
+ });
50
+ describe('disabled', () => {
51
+ it('shows disabled state', () => {
52
+ const { lastFrame } = render(_jsx(Input, { disabled: true, placeholder: "Disabled" }));
53
+ expect(lastFrame()).toContain('Disabled');
54
+ });
55
+ });
56
+ describe('types', () => {
57
+ it('renders text type by default', () => {
58
+ const { lastFrame } = render(_jsx(Input, { value: "visible", onChange: () => { } }));
59
+ expect(lastFrame()).toContain('visible');
60
+ });
61
+ it('masks password type', () => {
62
+ const { lastFrame } = render(_jsx(Input, { type: "password", value: "secret", onChange: () => { } }));
63
+ const output = lastFrame();
64
+ expect(output).not.toContain('secret');
65
+ expect(output).toContain('*');
66
+ });
67
+ });
68
+ });
@@ -0,0 +1,150 @@
1
+ /**
2
+ * Design Tokens - Colors, spacing, typography, and themes
3
+ */
4
+ export declare const colors: {
5
+ primary: {
6
+ 50: string;
7
+ 100: string;
8
+ 200: string;
9
+ 300: string;
10
+ 400: string;
11
+ 500: string;
12
+ 600: string;
13
+ 700: string;
14
+ 800: string;
15
+ 900: string;
16
+ };
17
+ gray: {
18
+ 50: string;
19
+ 100: string;
20
+ 200: string;
21
+ 300: string;
22
+ 400: string;
23
+ 500: string;
24
+ 600: string;
25
+ 700: string;
26
+ 800: string;
27
+ 900: string;
28
+ };
29
+ success: {
30
+ 50: string;
31
+ 100: string;
32
+ 500: string;
33
+ 600: string;
34
+ 700: string;
35
+ };
36
+ warning: {
37
+ 50: string;
38
+ 100: string;
39
+ 500: string;
40
+ 600: string;
41
+ 700: string;
42
+ };
43
+ error: {
44
+ 50: string;
45
+ 100: string;
46
+ 500: string;
47
+ 600: string;
48
+ 700: string;
49
+ };
50
+ info: {
51
+ 50: string;
52
+ 100: string;
53
+ 500: string;
54
+ 600: string;
55
+ 700: string;
56
+ };
57
+ white: string;
58
+ black: string;
59
+ };
60
+ export declare const spacing: {
61
+ 0: string;
62
+ 0.5: string;
63
+ 1: string;
64
+ 1.5: string;
65
+ 2: string;
66
+ 2.5: string;
67
+ 3: string;
68
+ 3.5: string;
69
+ 4: string;
70
+ 5: string;
71
+ 6: string;
72
+ 7: string;
73
+ 8: string;
74
+ 9: string;
75
+ 10: string;
76
+ 12: string;
77
+ 14: string;
78
+ 16: string;
79
+ };
80
+ export declare const typography: {
81
+ fontSize: {
82
+ xs: string;
83
+ sm: string;
84
+ base: string;
85
+ lg: string;
86
+ xl: string;
87
+ '2xl': string;
88
+ '3xl': string;
89
+ '4xl': string;
90
+ };
91
+ fontWeight: {
92
+ normal: number;
93
+ medium: number;
94
+ semibold: number;
95
+ bold: number;
96
+ };
97
+ lineHeight: {
98
+ none: number;
99
+ tight: number;
100
+ snug: number;
101
+ normal: number;
102
+ relaxed: number;
103
+ loose: number;
104
+ };
105
+ fontFamily: {
106
+ sans: string;
107
+ mono: string;
108
+ };
109
+ };
110
+ export declare const themes: {
111
+ light: {
112
+ background: string;
113
+ foreground: string;
114
+ muted: string;
115
+ mutedForeground: string;
116
+ border: string;
117
+ primary: string;
118
+ primaryForeground: string;
119
+ secondary: string;
120
+ secondaryForeground: string;
121
+ accent: string;
122
+ accentForeground: string;
123
+ success: string;
124
+ warning: string;
125
+ error: string;
126
+ info: string;
127
+ };
128
+ dark: {
129
+ background: string;
130
+ foreground: string;
131
+ muted: string;
132
+ mutedForeground: string;
133
+ border: string;
134
+ primary: string;
135
+ primaryForeground: string;
136
+ secondary: string;
137
+ secondaryForeground: string;
138
+ accent: string;
139
+ accentForeground: string;
140
+ success: string;
141
+ warning: string;
142
+ error: string;
143
+ info: string;
144
+ };
145
+ };
146
+ export type Theme = keyof typeof themes;
147
+ /**
148
+ * Generate CSS custom properties for a theme
149
+ */
150
+ export declare function generateCSSVariables(theme: Theme): string;
@@ -0,0 +1,184 @@
1
+ /**
2
+ * Design Tokens - Colors, spacing, typography, and themes
3
+ */
4
+ export const colors = {
5
+ // Primary palette
6
+ primary: {
7
+ 50: '#eff6ff',
8
+ 100: '#dbeafe',
9
+ 200: '#bfdbfe',
10
+ 300: '#93c5fd',
11
+ 400: '#60a5fa',
12
+ 500: '#3b82f6',
13
+ 600: '#2563eb',
14
+ 700: '#1d4ed8',
15
+ 800: '#1e40af',
16
+ 900: '#1e3a8a',
17
+ },
18
+ // Neutral grays
19
+ gray: {
20
+ 50: '#f9fafb',
21
+ 100: '#f3f4f6',
22
+ 200: '#e5e7eb',
23
+ 300: '#d1d5db',
24
+ 400: '#9ca3af',
25
+ 500: '#6b7280',
26
+ 600: '#4b5563',
27
+ 700: '#374151',
28
+ 800: '#1f2937',
29
+ 900: '#111827',
30
+ },
31
+ // Status colors
32
+ success: {
33
+ 50: '#f0fdf4',
34
+ 100: '#dcfce7',
35
+ 500: '#22c55e',
36
+ 600: '#16a34a',
37
+ 700: '#15803d',
38
+ },
39
+ warning: {
40
+ 50: '#fffbeb',
41
+ 100: '#fef3c7',
42
+ 500: '#f59e0b',
43
+ 600: '#d97706',
44
+ 700: '#b45309',
45
+ },
46
+ error: {
47
+ 50: '#fef2f2',
48
+ 100: '#fee2e2',
49
+ 500: '#ef4444',
50
+ 600: '#dc2626',
51
+ 700: '#b91c1c',
52
+ },
53
+ info: {
54
+ 50: '#eff6ff',
55
+ 100: '#dbeafe',
56
+ 500: '#3b82f6',
57
+ 600: '#2563eb',
58
+ 700: '#1d4ed8',
59
+ },
60
+ // Pure colors
61
+ white: '#ffffff',
62
+ black: '#000000',
63
+ };
64
+ export const spacing = {
65
+ 0: '0',
66
+ 0.5: '0.125rem',
67
+ 1: '0.25rem',
68
+ 1.5: '0.375rem',
69
+ 2: '0.5rem',
70
+ 2.5: '0.625rem',
71
+ 3: '0.75rem',
72
+ 3.5: '0.875rem',
73
+ 4: '1rem',
74
+ 5: '1.25rem',
75
+ 6: '1.5rem',
76
+ 7: '1.75rem',
77
+ 8: '2rem',
78
+ 9: '2.25rem',
79
+ 10: '2.5rem',
80
+ 12: '3rem',
81
+ 14: '3.5rem',
82
+ 16: '4rem',
83
+ };
84
+ export const typography = {
85
+ fontSize: {
86
+ xs: '0.75rem',
87
+ sm: '0.875rem',
88
+ base: '1rem',
89
+ lg: '1.125rem',
90
+ xl: '1.25rem',
91
+ '2xl': '1.5rem',
92
+ '3xl': '1.875rem',
93
+ '4xl': '2.25rem',
94
+ },
95
+ fontWeight: {
96
+ normal: 400,
97
+ medium: 500,
98
+ semibold: 600,
99
+ bold: 700,
100
+ },
101
+ lineHeight: {
102
+ none: 1,
103
+ tight: 1.25,
104
+ snug: 1.375,
105
+ normal: 1.5,
106
+ relaxed: 1.625,
107
+ loose: 2,
108
+ },
109
+ fontFamily: {
110
+ sans: 'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
111
+ mono: 'ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace',
112
+ },
113
+ };
114
+ export const themes = {
115
+ light: {
116
+ background: colors.white,
117
+ foreground: colors.gray[900],
118
+ muted: colors.gray[100],
119
+ mutedForeground: colors.gray[500],
120
+ border: colors.gray[200],
121
+ primary: colors.primary[600],
122
+ primaryForeground: colors.white,
123
+ secondary: colors.gray[100],
124
+ secondaryForeground: colors.gray[900],
125
+ accent: colors.primary[50],
126
+ accentForeground: colors.primary[700],
127
+ success: colors.success[600],
128
+ warning: colors.warning[600],
129
+ error: colors.error[600],
130
+ info: colors.info[600],
131
+ },
132
+ dark: {
133
+ background: colors.gray[900],
134
+ foreground: colors.gray[50],
135
+ muted: colors.gray[800],
136
+ mutedForeground: colors.gray[400],
137
+ border: colors.gray[700],
138
+ primary: colors.primary[500],
139
+ primaryForeground: colors.white,
140
+ secondary: colors.gray[800],
141
+ secondaryForeground: colors.gray[100],
142
+ accent: colors.gray[800],
143
+ accentForeground: colors.primary[400],
144
+ success: colors.success[500],
145
+ warning: colors.warning[500],
146
+ error: colors.error[500],
147
+ info: colors.info[500],
148
+ },
149
+ };
150
+ /**
151
+ * Generate CSS custom properties for a theme
152
+ */
153
+ export function generateCSSVariables(theme) {
154
+ const themeTokens = themes[theme];
155
+ const lines = [];
156
+ // Theme colors
157
+ for (const [key, value] of Object.entries(themeTokens)) {
158
+ lines.push(` --color-${key}: ${value};`);
159
+ }
160
+ // Primary palette
161
+ for (const [shade, value] of Object.entries(colors.primary)) {
162
+ lines.push(` --color-primary-${shade}: ${value};`);
163
+ }
164
+ // Gray palette
165
+ for (const [shade, value] of Object.entries(colors.gray)) {
166
+ lines.push(` --color-gray-${shade}: ${value};`);
167
+ }
168
+ // Spacing
169
+ for (const [key, value] of Object.entries(spacing)) {
170
+ const normalizedKey = String(key).replace('.', '_');
171
+ lines.push(` --spacing-${normalizedKey}: ${value};`);
172
+ }
173
+ // Typography
174
+ for (const [key, value] of Object.entries(typography.fontSize)) {
175
+ lines.push(` --font-size-${key}: ${value};`);
176
+ }
177
+ for (const [key, value] of Object.entries(typography.fontWeight)) {
178
+ lines.push(` --font-weight-${key}: ${value};`);
179
+ }
180
+ for (const [key, value] of Object.entries(typography.lineHeight)) {
181
+ lines.push(` --line-height-${key}: ${value};`);
182
+ }
183
+ return `:root {\n${lines.join('\n')}\n}`;
184
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,95 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { colors, spacing, typography, themes, generateCSSVariables, } from './tokens.js';
3
+ describe('tokens', () => {
4
+ describe('colors', () => {
5
+ it('has primary color palette', () => {
6
+ expect(colors.primary).toBeDefined();
7
+ expect(colors.primary[500]).toBeDefined();
8
+ });
9
+ it('has status colors', () => {
10
+ expect(colors.success).toBeDefined();
11
+ expect(colors.warning).toBeDefined();
12
+ expect(colors.error).toBeDefined();
13
+ expect(colors.info).toBeDefined();
14
+ });
15
+ it('has neutral grays', () => {
16
+ expect(colors.gray).toBeDefined();
17
+ expect(colors.gray[50]).toBeDefined();
18
+ expect(colors.gray[900]).toBeDefined();
19
+ });
20
+ });
21
+ describe('spacing', () => {
22
+ it('has spacing scale', () => {
23
+ expect(spacing[0]).toBe('0');
24
+ expect(spacing[1]).toBe('0.25rem');
25
+ expect(spacing[4]).toBe('1rem');
26
+ expect(spacing[8]).toBe('2rem');
27
+ });
28
+ it('has 16 steps', () => {
29
+ expect(Object.keys(spacing).length).toBeGreaterThanOrEqual(13);
30
+ });
31
+ });
32
+ describe('typography', () => {
33
+ it('has font sizes', () => {
34
+ expect(typography.fontSize.xs).toBeDefined();
35
+ expect(typography.fontSize.sm).toBeDefined();
36
+ expect(typography.fontSize.base).toBeDefined();
37
+ expect(typography.fontSize.lg).toBeDefined();
38
+ expect(typography.fontSize.xl).toBeDefined();
39
+ });
40
+ it('has font weights', () => {
41
+ expect(typography.fontWeight.normal).toBe(400);
42
+ expect(typography.fontWeight.medium).toBe(500);
43
+ expect(typography.fontWeight.semibold).toBe(600);
44
+ expect(typography.fontWeight.bold).toBe(700);
45
+ });
46
+ it('has line heights', () => {
47
+ expect(typography.lineHeight.tight).toBeDefined();
48
+ expect(typography.lineHeight.normal).toBeDefined();
49
+ expect(typography.lineHeight.relaxed).toBeDefined();
50
+ });
51
+ });
52
+ describe('themes', () => {
53
+ it('has light theme', () => {
54
+ expect(themes.light).toBeDefined();
55
+ expect(themes.light.background).toBeDefined();
56
+ expect(themes.light.foreground).toBeDefined();
57
+ expect(themes.light.primary).toBeDefined();
58
+ });
59
+ it('has dark theme', () => {
60
+ expect(themes.dark).toBeDefined();
61
+ expect(themes.dark.background).toBeDefined();
62
+ expect(themes.dark.foreground).toBeDefined();
63
+ expect(themes.dark.primary).toBeDefined();
64
+ });
65
+ it('has contrasting background/foreground', () => {
66
+ expect(themes.light.background).not.toBe(themes.light.foreground);
67
+ expect(themes.dark.background).not.toBe(themes.dark.foreground);
68
+ });
69
+ });
70
+ describe('generateCSSVariables', () => {
71
+ it('generates CSS custom properties', () => {
72
+ const css = generateCSSVariables('light');
73
+ expect(css).toContain('--color-primary');
74
+ expect(css).toContain('--color-background');
75
+ expect(css).toContain('--spacing-4');
76
+ });
77
+ it('generates different values for dark theme', () => {
78
+ const lightCSS = generateCSSVariables('light');
79
+ const darkCSS = generateCSSVariables('dark');
80
+ expect(lightCSS).not.toBe(darkCSS);
81
+ });
82
+ it('includes spacing variables', () => {
83
+ const css = generateCSSVariables('light');
84
+ expect(css).toContain('--spacing-0');
85
+ expect(css).toContain('--spacing-1');
86
+ expect(css).toContain('--spacing-8');
87
+ });
88
+ it('includes typography variables', () => {
89
+ const css = generateCSSVariables('light');
90
+ expect(css).toContain('--font-size-sm');
91
+ expect(css).toContain('--font-size-base');
92
+ expect(css).toContain('--font-weight-bold');
93
+ });
94
+ });
95
+ });
@@ -0,0 +1 @@
1
+ import '@testing-library/jest-dom';
@@ -0,0 +1 @@
1
+ import '@testing-library/jest-dom';
@@ -23,11 +23,14 @@
23
23
  "react": "^18.3.1"
24
24
  },
25
25
  "devDependencies": {
26
+ "@testing-library/jest-dom": "^6.9.1",
27
+ "@testing-library/react": "^14.3.1",
26
28
  "@types/dockerode": "^3.3.31",
27
29
  "@types/node": "^22.10.0",
28
30
  "@types/react": "^18.3.12",
29
31
  "@vitest/coverage-v8": "^4.0.18",
30
32
  "ink-testing-library": "^4.0.0",
33
+ "jsdom": "^27.4.0",
31
34
  "memfs": "^4.56.10",
32
35
  "tsx": "^4.19.2",
33
36
  "typescript": "^5.7.2",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tlc-claude-code",
3
- "version": "1.2.26",
3
+ "version": "1.2.28",
4
4
  "description": "TLC - Test Led Coding for Claude Code",
5
5
  "bin": {
6
6
  "tlc": "./bin/tlc.js",