tlc-claude-code 1.2.27 → 1.2.29

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 (179) hide show
  1. package/README.md +9 -4
  2. package/dashboard/dist/components/ActivityFeed.d.ts +17 -0
  3. package/dashboard/dist/components/ActivityFeed.js +42 -0
  4. package/dashboard/dist/components/ActivityFeed.test.d.ts +1 -0
  5. package/dashboard/dist/components/ActivityFeed.test.js +162 -0
  6. package/dashboard/dist/components/BranchSelector.d.ts +16 -0
  7. package/dashboard/dist/components/BranchSelector.js +49 -0
  8. package/dashboard/dist/components/BranchSelector.test.d.ts +1 -0
  9. package/dashboard/dist/components/BranchSelector.test.js +166 -0
  10. package/dashboard/dist/components/CommandPalette.d.ts +17 -0
  11. package/dashboard/dist/components/CommandPalette.js +118 -0
  12. package/dashboard/dist/components/CommandPalette.test.d.ts +1 -0
  13. package/dashboard/dist/components/CommandPalette.test.js +181 -0
  14. package/dashboard/dist/components/ConnectionStatus.d.ts +16 -0
  15. package/dashboard/dist/components/ConnectionStatus.js +27 -0
  16. package/dashboard/dist/components/ConnectionStatus.test.d.ts +1 -0
  17. package/dashboard/dist/components/ConnectionStatus.test.js +121 -0
  18. package/dashboard/dist/components/DeviceFrame.d.ts +19 -0
  19. package/dashboard/dist/components/DeviceFrame.js +52 -0
  20. package/dashboard/dist/components/DeviceFrame.test.d.ts +1 -0
  21. package/dashboard/dist/components/DeviceFrame.test.js +118 -0
  22. package/dashboard/dist/components/EnvironmentBadge.d.ts +11 -0
  23. package/dashboard/dist/components/EnvironmentBadge.js +16 -0
  24. package/dashboard/dist/components/EnvironmentBadge.test.d.ts +1 -0
  25. package/dashboard/dist/components/EnvironmentBadge.test.js +102 -0
  26. package/dashboard/dist/components/FocusIndicator.d.ts +19 -0
  27. package/dashboard/dist/components/FocusIndicator.js +47 -0
  28. package/dashboard/dist/components/FocusIndicator.test.d.ts +1 -0
  29. package/dashboard/dist/components/FocusIndicator.test.js +117 -0
  30. package/dashboard/dist/components/KeyboardHelp.d.ts +15 -0
  31. package/dashboard/dist/components/KeyboardHelp.js +61 -0
  32. package/dashboard/dist/components/KeyboardHelp.test.d.ts +1 -0
  33. package/dashboard/dist/components/KeyboardHelp.test.js +131 -0
  34. package/dashboard/dist/components/LogSearch.d.ts +13 -0
  35. package/dashboard/dist/components/LogSearch.js +43 -0
  36. package/dashboard/dist/components/LogSearch.test.d.ts +1 -0
  37. package/dashboard/dist/components/LogSearch.test.js +100 -0
  38. package/dashboard/dist/components/LogStream.d.ts +21 -0
  39. package/dashboard/dist/components/LogStream.js +123 -0
  40. package/dashboard/dist/components/LogStream.test.d.ts +1 -0
  41. package/dashboard/dist/components/LogStream.test.js +159 -0
  42. package/dashboard/dist/components/PreviewPanel.d.ts +18 -0
  43. package/dashboard/dist/components/PreviewPanel.js +73 -0
  44. package/dashboard/dist/components/PreviewPanel.test.d.ts +1 -0
  45. package/dashboard/dist/components/PreviewPanel.test.js +124 -0
  46. package/dashboard/dist/components/ProjectCard.d.ts +18 -0
  47. package/dashboard/dist/components/ProjectCard.js +19 -0
  48. package/dashboard/dist/components/ProjectCard.test.d.ts +1 -0
  49. package/dashboard/dist/components/ProjectCard.test.js +53 -0
  50. package/dashboard/dist/components/ProjectDetail.d.ts +44 -0
  51. package/dashboard/dist/components/ProjectDetail.js +65 -0
  52. package/dashboard/dist/components/ProjectDetail.test.d.ts +1 -0
  53. package/dashboard/dist/components/ProjectDetail.test.js +196 -0
  54. package/dashboard/dist/components/ProjectList.d.ts +11 -0
  55. package/dashboard/dist/components/ProjectList.js +62 -0
  56. package/dashboard/dist/components/ProjectList.test.d.ts +1 -0
  57. package/dashboard/dist/components/ProjectList.test.js +93 -0
  58. package/dashboard/dist/components/SettingsPanel.d.ts +32 -0
  59. package/dashboard/dist/components/SettingsPanel.js +154 -0
  60. package/dashboard/dist/components/SettingsPanel.test.d.ts +1 -0
  61. package/dashboard/dist/components/SettingsPanel.test.js +196 -0
  62. package/dashboard/dist/components/StatusBar.d.ts +16 -0
  63. package/dashboard/dist/components/StatusBar.js +47 -0
  64. package/dashboard/dist/components/StatusBar.test.d.ts +1 -0
  65. package/dashboard/dist/components/StatusBar.test.js +123 -0
  66. package/dashboard/dist/components/TaskBoard.d.ts +22 -0
  67. package/dashboard/dist/components/TaskBoard.js +102 -0
  68. package/dashboard/dist/components/TaskBoard.test.d.ts +1 -0
  69. package/dashboard/dist/components/TaskBoard.test.js +113 -0
  70. package/dashboard/dist/components/TaskCard.d.ts +17 -0
  71. package/dashboard/dist/components/TaskCard.js +29 -0
  72. package/dashboard/dist/components/TaskCard.test.d.ts +1 -0
  73. package/dashboard/dist/components/TaskCard.test.js +109 -0
  74. package/dashboard/dist/components/TaskDetail.d.ts +36 -0
  75. package/dashboard/dist/components/TaskDetail.js +41 -0
  76. package/dashboard/dist/components/TaskDetail.test.d.ts +1 -0
  77. package/dashboard/dist/components/TaskDetail.test.js +164 -0
  78. package/dashboard/dist/components/TaskFilter.d.ts +12 -0
  79. package/dashboard/dist/components/TaskFilter.js +138 -0
  80. package/dashboard/dist/components/TaskFilter.test.d.ts +1 -0
  81. package/dashboard/dist/components/TaskFilter.test.js +109 -0
  82. package/dashboard/dist/components/TeamPanel.d.ts +15 -0
  83. package/dashboard/dist/components/TeamPanel.js +24 -0
  84. package/dashboard/dist/components/TeamPanel.test.d.ts +1 -0
  85. package/dashboard/dist/components/TeamPanel.test.js +109 -0
  86. package/dashboard/dist/components/TeamPresence.d.ts +14 -0
  87. package/dashboard/dist/components/TeamPresence.js +31 -0
  88. package/dashboard/dist/components/TeamPresence.test.d.ts +1 -0
  89. package/dashboard/dist/components/TeamPresence.test.js +144 -0
  90. package/dashboard/dist/components/layout/Header.d.ts +9 -0
  91. package/dashboard/dist/components/layout/Header.js +11 -0
  92. package/dashboard/dist/components/layout/Header.test.d.ts +1 -0
  93. package/dashboard/dist/components/layout/Header.test.js +35 -0
  94. package/dashboard/dist/components/layout/Shell.d.ts +10 -0
  95. package/dashboard/dist/components/layout/Shell.js +5 -0
  96. package/dashboard/dist/components/layout/Shell.test.d.ts +1 -0
  97. package/dashboard/dist/components/layout/Shell.test.js +34 -0
  98. package/dashboard/dist/components/layout/Sidebar.d.ts +14 -0
  99. package/dashboard/dist/components/layout/Sidebar.js +8 -0
  100. package/dashboard/dist/components/layout/Sidebar.test.d.ts +1 -0
  101. package/dashboard/dist/components/layout/Sidebar.test.js +40 -0
  102. package/dashboard/dist/components/ui/Badge.d.ts +9 -0
  103. package/dashboard/dist/components/ui/Badge.js +13 -0
  104. package/dashboard/dist/components/ui/Badge.test.d.ts +1 -0
  105. package/dashboard/dist/components/ui/Badge.test.js +69 -0
  106. package/dashboard/dist/components/ui/Button.d.ts +12 -0
  107. package/dashboard/dist/components/ui/Button.js +14 -0
  108. package/dashboard/dist/components/ui/Button.test.d.ts +1 -0
  109. package/dashboard/dist/components/ui/Button.test.js +81 -0
  110. package/dashboard/dist/components/ui/Card.d.ts +21 -0
  111. package/dashboard/dist/components/ui/Card.js +20 -0
  112. package/dashboard/dist/components/ui/Card.test.d.ts +1 -0
  113. package/dashboard/dist/components/ui/Card.test.js +82 -0
  114. package/dashboard/dist/components/ui/Input.d.ts +13 -0
  115. package/dashboard/dist/components/ui/Input.js +8 -0
  116. package/dashboard/dist/components/ui/Input.test.d.ts +1 -0
  117. package/dashboard/dist/components/ui/Input.test.js +68 -0
  118. package/dashboard/dist/styles/tokens.d.ts +150 -0
  119. package/dashboard/dist/styles/tokens.js +184 -0
  120. package/dashboard/dist/styles/tokens.test.d.ts +1 -0
  121. package/dashboard/dist/styles/tokens.test.js +95 -0
  122. package/dashboard/dist/test/setup.d.ts +1 -0
  123. package/dashboard/dist/test/setup.js +1 -0
  124. package/dashboard/package.json +3 -0
  125. package/package.json +15 -4
  126. package/scripts/capture-screenshots.js +170 -0
  127. package/scripts/docs-update.js +253 -0
  128. package/scripts/generate-screenshots.js +321 -0
  129. package/scripts/project-docs.js +377 -0
  130. package/scripts/vps-setup.sh +477 -0
  131. package/server/lib/adapters/base-adapter.js +114 -0
  132. package/server/lib/adapters/base-adapter.test.js +90 -0
  133. package/server/lib/adapters/claude-adapter.js +141 -0
  134. package/server/lib/adapters/claude-adapter.test.js +180 -0
  135. package/server/lib/adapters/deepseek-adapter.js +153 -0
  136. package/server/lib/adapters/deepseek-adapter.test.js +193 -0
  137. package/server/lib/adapters/openai-adapter.js +190 -0
  138. package/server/lib/adapters/openai-adapter.test.js +231 -0
  139. package/server/lib/budget-tracker.js +169 -0
  140. package/server/lib/budget-tracker.test.js +165 -0
  141. package/server/lib/claude-injector.js +85 -0
  142. package/server/lib/claude-injector.test.js +161 -0
  143. package/server/lib/consensus-engine.js +135 -0
  144. package/server/lib/consensus-engine.test.js +152 -0
  145. package/server/lib/context-builder.js +112 -0
  146. package/server/lib/context-builder.test.js +120 -0
  147. package/server/lib/file-collector.js +322 -0
  148. package/server/lib/file-collector.test.js +307 -0
  149. package/server/lib/memory-classifier.js +175 -0
  150. package/server/lib/memory-classifier.test.js +169 -0
  151. package/server/lib/memory-committer.js +138 -0
  152. package/server/lib/memory-committer.test.js +136 -0
  153. package/server/lib/memory-hooks.js +127 -0
  154. package/server/lib/memory-hooks.test.js +136 -0
  155. package/server/lib/memory-init.js +104 -0
  156. package/server/lib/memory-init.test.js +119 -0
  157. package/server/lib/memory-observer.js +149 -0
  158. package/server/lib/memory-observer.test.js +158 -0
  159. package/server/lib/memory-reader.js +243 -0
  160. package/server/lib/memory-reader.test.js +216 -0
  161. package/server/lib/memory-storage.js +120 -0
  162. package/server/lib/memory-storage.test.js +136 -0
  163. package/server/lib/memory-writer.js +176 -0
  164. package/server/lib/memory-writer.test.js +231 -0
  165. package/server/lib/overdrive-command.js +30 -6
  166. package/server/lib/overdrive-command.test.js +8 -1
  167. package/server/lib/pattern-detector.js +216 -0
  168. package/server/lib/pattern-detector.test.js +241 -0
  169. package/server/lib/relevance-scorer.js +175 -0
  170. package/server/lib/relevance-scorer.test.js +107 -0
  171. package/server/lib/review-command.js +238 -0
  172. package/server/lib/review-command.test.js +245 -0
  173. package/server/lib/review-orchestrator.js +273 -0
  174. package/server/lib/review-orchestrator.test.js +300 -0
  175. package/server/lib/review-reporter.js +288 -0
  176. package/server/lib/review-reporter.test.js +240 -0
  177. package/server/lib/session-summary.js +90 -0
  178. package/server/lib/session-summary.test.js +156 -0
  179. package/templates/docs-sync.yml +91 -0
@@ -0,0 +1,35 @@
1
+ import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { describe, it, expect } from 'vitest';
3
+ import { render } from 'ink-testing-library';
4
+ import { Header } from './Header.js';
5
+ describe('Header', () => {
6
+ it('renders title', () => {
7
+ const { lastFrame } = render(_jsx(Header, { title: "TLC Dashboard" }));
8
+ expect(lastFrame()).toContain('TLC Dashboard');
9
+ });
10
+ it('renders subtitle', () => {
11
+ const { lastFrame } = render(_jsx(Header, { title: "TLC", subtitle: "v1.0.0" }));
12
+ const output = lastFrame();
13
+ expect(output).toContain('TLC');
14
+ expect(output).toContain('v1.0.0');
15
+ });
16
+ it('renders breadcrumbs', () => {
17
+ const { lastFrame } = render(_jsx(Header, { title: "TLC", breadcrumbs: ['Home', 'Projects', 'MyApp'] }));
18
+ const output = lastFrame();
19
+ expect(output).toContain('Home');
20
+ expect(output).toContain('Projects');
21
+ expect(output).toContain('MyApp');
22
+ });
23
+ it('renders actions', () => {
24
+ const { lastFrame } = render(_jsx(Header, { title: "TLC", actions: _jsx(_Fragment, { children: "[q]Quit" }) }));
25
+ expect(lastFrame()).toContain('Quit');
26
+ });
27
+ it('renders status indicator', () => {
28
+ const { lastFrame } = render(_jsx(Header, { title: "TLC", status: "online" }));
29
+ expect(lastFrame()).toContain('●');
30
+ });
31
+ it('renders separator between breadcrumbs', () => {
32
+ const { lastFrame } = render(_jsx(Header, { title: "TLC", breadcrumbs: ['A', 'B'] }));
33
+ expect(lastFrame()).toContain('›');
34
+ });
35
+ });
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ export interface ShellProps {
3
+ header?: React.ReactNode;
4
+ footer?: React.ReactNode;
5
+ sidebar?: React.ReactNode;
6
+ sidebarWidth?: number;
7
+ showSidebar?: boolean;
8
+ children: React.ReactNode;
9
+ }
10
+ export declare function Shell({ header, footer, sidebar, sidebarWidth, showSidebar, children, }: ShellProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,5 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, Text } from 'ink';
3
+ export function Shell({ header, footer, sidebar, sidebarWidth = 30, showSidebar = true, children, }) {
4
+ return (_jsxs(Box, { flexDirection: "column", flexGrow: 1, children: [header && (_jsx(Box, { borderStyle: "single", borderColor: "gray", paddingX: 1, children: typeof header === 'string' ? (_jsx(Text, { bold: true, color: "cyan", children: header })) : (header) })), _jsxs(Box, { flexGrow: 1, flexDirection: "row", children: [sidebar && showSidebar && (_jsx(Box, { width: sidebarWidth, borderStyle: "single", borderColor: "gray", flexDirection: "column", paddingX: 1, children: typeof sidebar === 'string' ? _jsx(Text, { children: sidebar }) : sidebar })), _jsx(Box, { flexGrow: 1, flexDirection: "column", paddingX: 1, children: typeof children === 'string' ? _jsx(Text, { children: children }) : children })] }), footer && (_jsx(Box, { borderStyle: "single", borderColor: "gray", paddingX: 1, children: typeof footer === 'string' ? (_jsx(Text, { dimColor: true, children: footer })) : (footer) }))] }));
5
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,34 @@
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 { Text } from 'ink';
5
+ import { Shell } from './Shell.js';
6
+ describe('Shell', () => {
7
+ it('renders children', () => {
8
+ const { lastFrame } = render(_jsx(Shell, { children: _jsx(Text, { children: "Content here" }) }));
9
+ expect(lastFrame()).toContain('Content here');
10
+ });
11
+ it('renders header', () => {
12
+ const { lastFrame } = render(_jsx(Shell, { header: "TLC Dashboard", children: _jsx(Text, { children: "Content" }) }));
13
+ expect(lastFrame()).toContain('TLC Dashboard');
14
+ });
15
+ it('renders footer', () => {
16
+ const { lastFrame } = render(_jsx(Shell, { footer: "Press q to quit", children: _jsx(Text, { children: "Content" }) }));
17
+ expect(lastFrame()).toContain('Press q to quit');
18
+ });
19
+ it('renders sidebar when provided', () => {
20
+ const { lastFrame } = render(_jsx(Shell, { sidebar: _jsx(Text, { children: "Sidebar" }), children: _jsx(Text, { children: "Main content" }) }));
21
+ const output = lastFrame();
22
+ expect(output).toContain('Sidebar');
23
+ expect(output).toContain('Main content');
24
+ });
25
+ it('respects sidebarWidth', () => {
26
+ const { lastFrame } = render(_jsx(Shell, { sidebar: _jsx(Text, { children: "Nav" }), sidebarWidth: 20, children: _jsx(Text, { children: "Main" }) }));
27
+ expect(lastFrame()).toContain('Nav');
28
+ expect(lastFrame()).toContain('Main');
29
+ });
30
+ it('can hide sidebar', () => {
31
+ const { lastFrame } = render(_jsx(Shell, { sidebar: _jsx(Text, { children: "Hidden" }), showSidebar: false, children: _jsx(Text, { children: "Only main" }) }));
32
+ expect(lastFrame()).toContain('Only main');
33
+ });
34
+ });
@@ -0,0 +1,14 @@
1
+ import React from 'react';
2
+ export interface SidebarProps {
3
+ title?: string;
4
+ children: React.ReactNode;
5
+ }
6
+ export declare function Sidebar({ title, children }: SidebarProps): import("react/jsx-runtime").JSX.Element;
7
+ export interface SidebarItemProps {
8
+ label: string;
9
+ icon?: string;
10
+ active?: boolean;
11
+ badge?: string;
12
+ shortcut?: string;
13
+ }
14
+ export declare function SidebarItem({ label, icon, active, badge, shortcut, }: SidebarItemProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,8 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, Text } from 'ink';
3
+ export function Sidebar({ title, children }) {
4
+ return (_jsxs(Box, { flexDirection: "column", paddingY: 1, children: [title && (_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, color: "cyan", children: title }) })), children] }));
5
+ }
6
+ export function SidebarItem({ label, icon, active = false, badge, shortcut, }) {
7
+ return (_jsxs(Box, { children: [shortcut && (_jsxs(Text, { color: "gray", children: ["[", shortcut, "] "] })), icon && _jsxs(Text, { children: [icon, " "] }), _jsx(Text, { bold: active, color: active ? 'cyan' : 'white', inverse: active, children: label }), badge && (_jsxs(Text, { color: "yellow", children: [" (", badge, ")"] }))] }));
8
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,40 @@
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 { Sidebar, SidebarItem } from './Sidebar.js';
5
+ describe('Sidebar', () => {
6
+ it('renders children', () => {
7
+ const { lastFrame } = render(_jsx(Sidebar, { children: _jsx(SidebarItem, { label: "Home" }) }));
8
+ expect(lastFrame()).toContain('Home');
9
+ });
10
+ it('renders title when provided', () => {
11
+ const { lastFrame } = render(_jsx(Sidebar, { title: "Navigation", children: _jsx(SidebarItem, { label: "Home" }) }));
12
+ expect(lastFrame()).toContain('Navigation');
13
+ });
14
+ });
15
+ describe('SidebarItem', () => {
16
+ it('renders label', () => {
17
+ const { lastFrame } = render(_jsx(SidebarItem, { label: "Dashboard" }));
18
+ expect(lastFrame()).toContain('Dashboard');
19
+ });
20
+ it('renders with icon', () => {
21
+ const { lastFrame } = render(_jsx(SidebarItem, { label: "Home", icon: "\uD83C\uDFE0" }));
22
+ const output = lastFrame();
23
+ expect(output).toContain('🏠');
24
+ expect(output).toContain('Home');
25
+ });
26
+ it('shows active state', () => {
27
+ const { lastFrame } = render(_jsx(SidebarItem, { label: "Active", active: true }));
28
+ expect(lastFrame()).toContain('Active');
29
+ });
30
+ it('shows badge when provided', () => {
31
+ const { lastFrame } = render(_jsx(SidebarItem, { label: "Issues", badge: "5" }));
32
+ const output = lastFrame();
33
+ expect(output).toContain('Issues');
34
+ expect(output).toContain('5');
35
+ });
36
+ it('shows keyboard shortcut', () => {
37
+ const { lastFrame } = render(_jsx(SidebarItem, { label: "Chat", shortcut: "1" }));
38
+ expect(lastFrame()).toContain('1');
39
+ });
40
+ });
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ export interface BadgeProps {
3
+ variant?: 'success' | 'warning' | 'error' | 'info' | 'neutral';
4
+ size?: 'sm' | 'md';
5
+ showDot?: boolean;
6
+ showBrackets?: boolean;
7
+ children: React.ReactNode;
8
+ }
9
+ export declare function Badge({ variant, size, showDot, showBrackets, children, }: BadgeProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,13 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Text, Box } from 'ink';
3
+ const variantColors = {
4
+ success: 'green',
5
+ warning: 'yellow',
6
+ error: 'red',
7
+ info: 'blue',
8
+ neutral: 'gray',
9
+ };
10
+ export function Badge({ variant = 'neutral', size = 'md', showDot = false, showBrackets = true, children, }) {
11
+ const color = variantColors[variant];
12
+ return (_jsxs(Box, { children: [showBrackets && _jsx(Text, { color: color, children: "[" }), showDot && _jsx(Text, { color: color, children: "\u25CF " }), _jsx(Text, { color: color, bold: size === 'md', children: children }), showBrackets && _jsx(Text, { color: color, children: "]" })] }));
13
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,69 @@
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 { Badge } from './Badge.js';
5
+ describe('Badge', () => {
6
+ it('renders badge text', () => {
7
+ const { lastFrame } = render(_jsx(Badge, { children: "Active" }));
8
+ expect(lastFrame()).toContain('Active');
9
+ });
10
+ describe('variants', () => {
11
+ it('renders success variant', () => {
12
+ const { lastFrame } = render(_jsx(Badge, { variant: "success", children: "Passed" }));
13
+ expect(lastFrame()).toContain('Passed');
14
+ });
15
+ it('renders warning variant', () => {
16
+ const { lastFrame } = render(_jsx(Badge, { variant: "warning", children: "Pending" }));
17
+ expect(lastFrame()).toContain('Pending');
18
+ });
19
+ it('renders error variant', () => {
20
+ const { lastFrame } = render(_jsx(Badge, { variant: "error", children: "Failed" }));
21
+ expect(lastFrame()).toContain('Failed');
22
+ });
23
+ it('renders info variant', () => {
24
+ const { lastFrame } = render(_jsx(Badge, { variant: "info", children: "Note" }));
25
+ expect(lastFrame()).toContain('Note');
26
+ });
27
+ it('renders neutral variant', () => {
28
+ const { lastFrame } = render(_jsx(Badge, { variant: "neutral", children: "Draft" }));
29
+ expect(lastFrame()).toContain('Draft');
30
+ });
31
+ });
32
+ describe('sizes', () => {
33
+ it('renders small size', () => {
34
+ const { lastFrame } = render(_jsx(Badge, { size: "sm", children: "Small" }));
35
+ expect(lastFrame()).toContain('Small');
36
+ });
37
+ it('renders medium size (default)', () => {
38
+ const { lastFrame } = render(_jsx(Badge, { children: "Medium" }));
39
+ expect(lastFrame()).toContain('Medium');
40
+ });
41
+ });
42
+ describe('dot indicator', () => {
43
+ it('shows dot when enabled', () => {
44
+ const { lastFrame } = render(_jsx(Badge, { showDot: true, children: "Active" }));
45
+ const output = lastFrame();
46
+ expect(output).toContain('Active');
47
+ expect(output).toContain('●');
48
+ });
49
+ it('hides dot by default', () => {
50
+ const { lastFrame } = render(_jsx(Badge, { children: "Status" }));
51
+ const output = lastFrame();
52
+ expect(output).toContain('Status');
53
+ expect(output).not.toContain('●');
54
+ });
55
+ });
56
+ describe('brackets', () => {
57
+ it('shows brackets by default', () => {
58
+ const { lastFrame } = render(_jsx(Badge, { children: "Test" }));
59
+ const output = lastFrame();
60
+ expect(output).toContain('[');
61
+ expect(output).toContain(']');
62
+ });
63
+ it('can hide brackets', () => {
64
+ const { lastFrame } = render(_jsx(Badge, { showBrackets: false, children: "Test" }));
65
+ const output = lastFrame();
66
+ expect(output).toContain('Test');
67
+ });
68
+ });
69
+ });
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ export interface ButtonProps {
3
+ variant?: 'primary' | 'secondary' | 'ghost' | 'danger';
4
+ loading?: boolean;
5
+ disabled?: boolean;
6
+ leftIcon?: string;
7
+ rightIcon?: string;
8
+ showBrackets?: boolean;
9
+ isFocused?: boolean;
10
+ children: React.ReactNode;
11
+ }
12
+ export declare function Button({ variant, loading, disabled, leftIcon, rightIcon, showBrackets, isFocused, children, }: ButtonProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,14 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Text, Box } from 'ink';
3
+ import Spinner from 'ink-spinner';
4
+ const variantColors = {
5
+ primary: 'blue',
6
+ secondary: 'white',
7
+ ghost: 'gray',
8
+ danger: 'red',
9
+ };
10
+ export function Button({ variant = 'primary', loading = false, disabled = false, leftIcon, rightIcon, showBrackets = true, isFocused = false, children, }) {
11
+ const color = variantColors[variant];
12
+ const dimmed = disabled || loading;
13
+ return (_jsxs(Box, { children: [showBrackets && (_jsx(Text, { color: isFocused ? 'cyan' : 'gray', dimColor: dimmed, children: "[" })), loading && (_jsxs(Text, { color: color, children: [_jsx(Spinner, { type: "dots" }), ' '] })), leftIcon && !loading && (_jsxs(Text, { color: color, dimColor: dimmed, children: [leftIcon, ' '] })), _jsx(Text, { color: color, bold: variant === 'primary' || isFocused, dimColor: dimmed, children: children }), rightIcon && !loading && (_jsxs(Text, { color: color, dimColor: dimmed, children: [' ', rightIcon] })), showBrackets && (_jsx(Text, { color: isFocused ? 'cyan' : 'gray', dimColor: dimmed, children: "]" }))] }));
14
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,81 @@
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 { Button } from './Button.js';
5
+ describe('Button', () => {
6
+ it('renders button text', () => {
7
+ const { lastFrame } = render(_jsx(Button, { children: "Click me" }));
8
+ expect(lastFrame()).toContain('Click me');
9
+ });
10
+ describe('variants', () => {
11
+ it('renders primary variant with highlight', () => {
12
+ const { lastFrame } = render(_jsx(Button, { variant: "primary", children: "Primary" }));
13
+ expect(lastFrame()).toContain('Primary');
14
+ });
15
+ it('renders secondary variant', () => {
16
+ const { lastFrame } = render(_jsx(Button, { variant: "secondary", children: "Secondary" }));
17
+ expect(lastFrame()).toContain('Secondary');
18
+ });
19
+ it('renders ghost variant', () => {
20
+ const { lastFrame } = render(_jsx(Button, { variant: "ghost", children: "Ghost" }));
21
+ expect(lastFrame()).toContain('Ghost');
22
+ });
23
+ it('renders danger variant', () => {
24
+ const { lastFrame } = render(_jsx(Button, { variant: "danger", children: "Danger" }));
25
+ expect(lastFrame()).toContain('Danger');
26
+ });
27
+ });
28
+ describe('states', () => {
29
+ it('shows disabled state with dimmed text', () => {
30
+ const { lastFrame } = render(_jsx(Button, { disabled: true, children: "Disabled" }));
31
+ expect(lastFrame()).toContain('Disabled');
32
+ });
33
+ it('shows loading state with spinner', () => {
34
+ const { lastFrame } = render(_jsx(Button, { loading: true, children: "Loading" }));
35
+ const output = lastFrame();
36
+ expect(output).toContain('Loading');
37
+ // Should show spinner character
38
+ expect(output).toMatch(/[⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏◐◓◑◒]/);
39
+ });
40
+ });
41
+ describe('icons', () => {
42
+ it('renders with left icon', () => {
43
+ const { lastFrame } = render(_jsx(Button, { leftIcon: "+", children: "Add" }));
44
+ const output = lastFrame();
45
+ expect(output).toContain('+');
46
+ expect(output).toContain('Add');
47
+ });
48
+ it('renders with right icon', () => {
49
+ const { lastFrame } = render(_jsx(Button, { rightIcon: "\u2192", children: "Next" }));
50
+ const output = lastFrame();
51
+ expect(output).toContain('Next');
52
+ expect(output).toContain('→');
53
+ });
54
+ });
55
+ describe('brackets', () => {
56
+ it('renders with brackets by default', () => {
57
+ const { lastFrame } = render(_jsx(Button, { children: "OK" }));
58
+ const output = lastFrame();
59
+ expect(output).toContain('[');
60
+ expect(output).toContain(']');
61
+ });
62
+ it('can hide brackets', () => {
63
+ const { lastFrame } = render(_jsx(Button, { showBrackets: false, children: "OK" }));
64
+ const output = lastFrame();
65
+ expect(output).toContain('OK');
66
+ });
67
+ });
68
+ describe('focus', () => {
69
+ it('shows focus indicator when focused', () => {
70
+ const { lastFrame } = render(_jsx(Button, { isFocused: true, children: "Focused" }));
71
+ expect(lastFrame()).toContain('Focused');
72
+ });
73
+ it('shows different style when not focused', () => {
74
+ const { lastFrame: focused } = render(_jsx(Button, { isFocused: true, children: "Test" }));
75
+ const { lastFrame: unfocused } = render(_jsx(Button, { isFocused: false, children: "Test" }));
76
+ // Both should render the text
77
+ expect(focused()).toContain('Test');
78
+ expect(unfocused()).toContain('Test');
79
+ });
80
+ });
81
+ });
@@ -0,0 +1,21 @@
1
+ import React from 'react';
2
+ export interface CardProps {
3
+ variant?: 'default' | 'elevated' | 'outlined';
4
+ title?: string;
5
+ padding?: number;
6
+ width?: number | string;
7
+ children: React.ReactNode;
8
+ }
9
+ export declare function Card({ variant, title, padding, width, children, }: CardProps): import("react/jsx-runtime").JSX.Element;
10
+ export interface CardHeaderProps {
11
+ children: React.ReactNode;
12
+ }
13
+ export declare function CardHeader({ children }: CardHeaderProps): import("react/jsx-runtime").JSX.Element;
14
+ export interface CardBodyProps {
15
+ children: React.ReactNode;
16
+ }
17
+ export declare function CardBody({ children }: CardBodyProps): import("react/jsx-runtime").JSX.Element;
18
+ export interface CardFooterProps {
19
+ children: React.ReactNode;
20
+ }
21
+ export declare function CardFooter({ children }: CardFooterProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,20 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, Text } from 'ink';
3
+ const borderStyles = {
4
+ default: 'single',
5
+ elevated: 'double',
6
+ outlined: 'round',
7
+ };
8
+ export function Card({ variant = 'default', title, padding = 1, width, children, }) {
9
+ const content = typeof children === 'string' ? _jsx(Text, { children: children }) : children;
10
+ return (_jsxs(Box, { flexDirection: "column", borderStyle: borderStyles[variant], borderColor: "gray", paddingX: padding, paddingY: padding > 0 ? 0 : 0, width: width, children: [title && (_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, color: "white", children: title }) })), content] }));
11
+ }
12
+ export function CardHeader({ children }) {
13
+ return (_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, color: "white", children: children }) }));
14
+ }
15
+ export function CardBody({ children }) {
16
+ return (_jsx(Box, { flexDirection: "column", children: typeof children === 'string' ? _jsx(Text, { children: children }) : children }));
17
+ }
18
+ export function CardFooter({ children }) {
19
+ return (_jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: children }) }));
20
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -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
+ });