gencode-ai 0.1.1 → 0.1.2
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.
- package/.gencode/settings.local.json +7 -0
- package/README.md +11 -11
- package/dist/agent/agent.d.ts +42 -1
- package/dist/agent/agent.d.ts.map +1 -1
- package/dist/agent/agent.js +82 -15
- package/dist/agent/agent.js.map +1 -1
- package/dist/cli/components/App.d.ts +8 -1
- package/dist/cli/components/App.d.ts.map +1 -1
- package/dist/cli/components/App.js +231 -29
- package/dist/cli/components/App.js.map +1 -1
- package/dist/cli/components/CommandSuggestions.d.ts.map +1 -1
- package/dist/cli/components/CommandSuggestions.js +2 -0
- package/dist/cli/components/CommandSuggestions.js.map +1 -1
- package/dist/cli/components/Header.d.ts +1 -1
- package/dist/cli/components/Header.d.ts.map +1 -1
- package/dist/cli/components/Header.js +4 -6
- package/dist/cli/components/Header.js.map +1 -1
- package/dist/cli/components/Logo.d.ts +1 -0
- package/dist/cli/components/Logo.d.ts.map +1 -1
- package/dist/cli/components/Logo.js +16 -3
- package/dist/cli/components/Logo.js.map +1 -1
- package/dist/cli/components/Messages.d.ts +4 -4
- package/dist/cli/components/Messages.d.ts.map +1 -1
- package/dist/cli/components/Messages.js +51 -25
- package/dist/cli/components/Messages.js.map +1 -1
- package/dist/cli/components/PermissionPrompt.d.ts +60 -0
- package/dist/cli/components/PermissionPrompt.d.ts.map +1 -0
- package/dist/cli/components/PermissionPrompt.js +192 -0
- package/dist/cli/components/PermissionPrompt.js.map +1 -0
- package/dist/cli/components/ProviderManager.js +3 -3
- package/dist/cli/components/ProviderManager.js.map +1 -1
- package/dist/cli/components/Spinner.d.ts +7 -2
- package/dist/cli/components/Spinner.d.ts.map +1 -1
- package/dist/cli/components/Spinner.js +116 -25
- package/dist/cli/components/Spinner.js.map +1 -1
- package/dist/cli/components/TodoList.d.ts +7 -0
- package/dist/cli/components/TodoList.d.ts.map +1 -0
- package/dist/cli/components/TodoList.js +34 -0
- package/dist/cli/components/TodoList.js.map +1 -0
- package/dist/cli/components/index.d.ts +1 -0
- package/dist/cli/components/index.d.ts.map +1 -1
- package/dist/cli/components/index.js +1 -0
- package/dist/cli/components/index.js.map +1 -1
- package/dist/cli/index.js +47 -7
- package/dist/cli/index.js.map +1 -1
- package/dist/config/index.d.ts +13 -4
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +18 -3
- package/dist/config/index.js.map +1 -1
- package/dist/config/levels.d.ts +49 -0
- package/dist/config/levels.d.ts.map +1 -0
- package/dist/config/levels.js +222 -0
- package/dist/config/levels.js.map +1 -0
- package/dist/config/loader.d.ts +46 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +153 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/manager.d.ts +115 -15
- package/dist/config/manager.d.ts.map +1 -1
- package/dist/config/manager.js +260 -34
- package/dist/config/manager.js.map +1 -1
- package/dist/config/manager.test.d.ts +5 -0
- package/dist/config/manager.test.d.ts.map +1 -0
- package/dist/config/manager.test.js +192 -0
- package/dist/config/manager.test.js.map +1 -0
- package/dist/config/merger.d.ts +56 -0
- package/dist/config/merger.d.ts.map +1 -0
- package/dist/config/merger.js +177 -0
- package/dist/config/merger.js.map +1 -0
- package/dist/config/test-utils.d.ts +24 -0
- package/dist/config/test-utils.d.ts.map +1 -0
- package/dist/config/test-utils.js +55 -0
- package/dist/config/test-utils.js.map +1 -0
- package/dist/config/types.d.ts +78 -9
- package/dist/config/types.d.ts.map +1 -1
- package/dist/config/types.js +52 -2
- package/dist/config/types.js.map +1 -1
- package/dist/memory/import-resolver.d.ts +46 -0
- package/dist/memory/import-resolver.d.ts.map +1 -0
- package/dist/memory/import-resolver.js +117 -0
- package/dist/memory/import-resolver.js.map +1 -0
- package/dist/memory/index.d.ts +7 -6
- package/dist/memory/index.d.ts.map +1 -1
- package/dist/memory/index.js +7 -5
- package/dist/memory/index.js.map +1 -1
- package/dist/memory/init-prompt.d.ts +22 -0
- package/dist/memory/init-prompt.d.ts.map +1 -0
- package/dist/memory/init-prompt.js +103 -0
- package/dist/memory/init-prompt.js.map +1 -0
- package/dist/memory/memory-manager.d.ts +119 -0
- package/dist/memory/memory-manager.d.ts.map +1 -0
- package/dist/memory/memory-manager.js +587 -0
- package/dist/memory/memory-manager.js.map +1 -0
- package/dist/memory/rules-parser.d.ts +38 -0
- package/dist/memory/rules-parser.d.ts.map +1 -0
- package/dist/memory/rules-parser.js +69 -0
- package/dist/memory/rules-parser.js.map +1 -0
- package/dist/memory/test-utils.d.ts +20 -0
- package/dist/memory/test-utils.d.ts.map +1 -0
- package/dist/memory/test-utils.js +44 -0
- package/dist/memory/test-utils.js.map +1 -0
- package/dist/memory/types.d.ts +70 -63
- package/dist/memory/types.d.ts.map +1 -1
- package/dist/memory/types.js +42 -2
- package/dist/memory/types.js.map +1 -1
- package/dist/permissions/audit.d.ts +82 -0
- package/dist/permissions/audit.d.ts.map +1 -0
- package/dist/permissions/audit.js +229 -0
- package/dist/permissions/audit.js.map +1 -0
- package/dist/permissions/index.d.ts +11 -1
- package/dist/permissions/index.d.ts.map +1 -1
- package/dist/permissions/index.js +15 -0
- package/dist/permissions/index.js.map +1 -1
- package/dist/permissions/manager.d.ts +149 -13
- package/dist/permissions/manager.d.ts.map +1 -1
- package/dist/permissions/manager.js +480 -35
- package/dist/permissions/manager.js.map +1 -1
- package/dist/permissions/manager.test.d.ts +5 -0
- package/dist/permissions/manager.test.d.ts.map +1 -0
- package/dist/permissions/manager.test.js +213 -0
- package/dist/permissions/manager.test.js.map +1 -0
- package/dist/permissions/persistence.d.ts +74 -0
- package/dist/permissions/persistence.d.ts.map +1 -0
- package/dist/permissions/persistence.js +248 -0
- package/dist/permissions/persistence.js.map +1 -0
- package/dist/permissions/persistence.test.d.ts +5 -0
- package/dist/permissions/persistence.test.d.ts.map +1 -0
- package/dist/permissions/persistence.test.js +171 -0
- package/dist/permissions/persistence.test.js.map +1 -0
- package/dist/permissions/prompt-matcher.d.ts +64 -0
- package/dist/permissions/prompt-matcher.d.ts.map +1 -0
- package/dist/permissions/prompt-matcher.js +415 -0
- package/dist/permissions/prompt-matcher.js.map +1 -0
- package/dist/permissions/prompt-matcher.test.d.ts +5 -0
- package/dist/permissions/prompt-matcher.test.d.ts.map +1 -0
- package/dist/permissions/prompt-matcher.test.js +107 -0
- package/dist/permissions/prompt-matcher.test.js.map +1 -0
- package/dist/permissions/types.d.ts +157 -0
- package/dist/permissions/types.d.ts.map +1 -1
- package/dist/permissions/types.js +43 -8
- package/dist/permissions/types.js.map +1 -1
- package/dist/prompts/index.d.ts +92 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +241 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/tools/builtin/bash.d.ts.map +1 -1
- package/dist/tools/builtin/bash.js +2 -1
- package/dist/tools/builtin/bash.js.map +1 -1
- package/dist/tools/builtin/edit.d.ts.map +1 -1
- package/dist/tools/builtin/edit.js +2 -1
- package/dist/tools/builtin/edit.js.map +1 -1
- package/dist/tools/builtin/glob.d.ts.map +1 -1
- package/dist/tools/builtin/glob.js +2 -1
- package/dist/tools/builtin/glob.js.map +1 -1
- package/dist/tools/builtin/grep.d.ts.map +1 -1
- package/dist/tools/builtin/grep.js +2 -1
- package/dist/tools/builtin/grep.js.map +1 -1
- package/dist/tools/builtin/read.d.ts.map +1 -1
- package/dist/tools/builtin/read.js +2 -1
- package/dist/tools/builtin/read.js.map +1 -1
- package/dist/tools/builtin/todowrite.d.ts +15 -0
- package/dist/tools/builtin/todowrite.d.ts.map +1 -0
- package/dist/tools/builtin/todowrite.js +88 -0
- package/dist/tools/builtin/todowrite.js.map +1 -0
- package/dist/tools/builtin/webfetch.d.ts.map +1 -1
- package/dist/tools/builtin/webfetch.js +2 -5
- package/dist/tools/builtin/webfetch.js.map +1 -1
- package/dist/tools/builtin/websearch.d.ts.map +1 -1
- package/dist/tools/builtin/websearch.js +2 -16
- package/dist/tools/builtin/websearch.js.map +1 -1
- package/dist/tools/builtin/write.d.ts.map +1 -1
- package/dist/tools/builtin/write.js +2 -1
- package/dist/tools/builtin/write.js.map +1 -1
- package/dist/tools/index.d.ts +7 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +4 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/types.d.ts +22 -0
- package/dist/tools/types.d.ts.map +1 -1
- package/dist/tools/types.js +8 -0
- package/dist/tools/types.js.map +1 -1
- package/docs/config-system-comparison.md +707 -0
- package/docs/memory-system.md +238 -0
- package/docs/permissions.md +368 -0
- package/docs/proposals/0005-todo-system.md +350 -85
- package/docs/proposals/0006-memory-system.md +11 -10
- package/docs/proposals/0012-ask-user-question.md +941 -206
- package/docs/proposals/0023-permission-enhancements.md +61 -2
- package/docs/proposals/0041-configuration-system.md +33 -2
- package/docs/proposals/0042-prompt-optimization.md +866 -0
- package/docs/proposals/README.md +6 -5
- package/jest.config.js +26 -0
- package/package.json +8 -2
- package/src/agent/agent.ts +111 -16
- package/src/cli/components/App.tsx +309 -36
- package/src/cli/components/CommandSuggestions.tsx +2 -0
- package/src/cli/components/Header.tsx +11 -17
- package/src/cli/components/Logo.tsx +76 -9
- package/src/cli/components/Messages.tsx +73 -53
- package/src/cli/components/PermissionPrompt.tsx +388 -0
- package/src/cli/components/ProviderManager.tsx +5 -5
- package/src/cli/components/Spinner.tsx +138 -25
- package/src/cli/components/TodoList.tsx +54 -0
- package/src/cli/components/index.ts +6 -0
- package/src/cli/index.tsx +54 -6
- package/src/config/index.ts +78 -4
- package/src/config/levels.test.ts +163 -0
- package/src/config/levels.ts +285 -0
- package/src/config/loader.test.ts +120 -0
- package/src/config/loader.ts +178 -0
- package/src/config/manager.test.ts +215 -0
- package/src/config/manager.ts +328 -40
- package/src/config/merger.test.ts +360 -0
- package/src/config/merger.ts +221 -0
- package/src/config/test-utils.ts +79 -0
- package/src/config/types.ts +152 -9
- package/src/memory/import-resolver.test.ts +117 -0
- package/src/memory/import-resolver.ts +149 -0
- package/src/memory/index.ts +11 -0
- package/src/memory/init-prompt.ts +113 -0
- package/src/memory/memory-manager.test.ts +198 -0
- package/src/memory/memory-manager.ts +716 -0
- package/src/memory/rules-parser.test.ts +182 -0
- package/src/memory/rules-parser.ts +82 -0
- package/src/memory/test-utils.ts +60 -0
- package/src/memory/types.ts +119 -0
- package/src/permissions/audit.ts +284 -0
- package/src/permissions/index.ts +20 -1
- package/src/permissions/manager.test.ts +260 -0
- package/src/permissions/manager.ts +592 -40
- package/src/permissions/persistence.test.ts +220 -0
- package/src/permissions/persistence.ts +301 -0
- package/src/permissions/prompt-matcher.test.ts +213 -0
- package/src/permissions/prompt-matcher.ts +472 -0
- package/src/permissions/types.ts +236 -8
- package/src/prompts/index.test.ts +279 -0
- package/src/prompts/index.ts +306 -0
- package/src/prompts/system/anthropic.txt +29 -0
- package/src/prompts/system/base.txt +124 -0
- package/src/prompts/system/gemini.txt +35 -0
- package/src/prompts/system/generic.txt +128 -0
- package/src/prompts/system/openai.txt +29 -0
- package/src/prompts/tools/bash.txt +60 -0
- package/src/prompts/tools/edit.txt +29 -0
- package/src/prompts/tools/glob.txt +35 -0
- package/src/prompts/tools/grep.txt +43 -0
- package/src/prompts/tools/read.txt +22 -0
- package/src/prompts/tools/todowrite.txt +71 -0
- package/src/prompts/tools/webfetch.txt +34 -0
- package/src/prompts/tools/websearch.txt +41 -0
- package/src/prompts/tools/write.txt +23 -0
- package/src/tools/builtin/bash.ts +2 -1
- package/src/tools/builtin/edit.ts +2 -1
- package/src/tools/builtin/glob.ts +2 -1
- package/src/tools/builtin/grep.ts +2 -1
- package/src/tools/builtin/read.ts +2 -1
- package/src/tools/builtin/todowrite.ts +102 -0
- package/src/tools/builtin/webfetch.ts +2 -5
- package/src/tools/builtin/websearch.ts +2 -16
- package/src/tools/builtin/write.ts +2 -1
- package/src/tools/index.ts +4 -0
- package/src/tools/types.ts +12 -0
- package/tsconfig.json +1 -1
|
@@ -22,13 +22,22 @@ import { PromptInput, ConfirmPrompt } from './Input.js';
|
|
|
22
22
|
import { ModelSelector } from './ModelSelector.js';
|
|
23
23
|
import { ProviderManager } from './ProviderManager.js';
|
|
24
24
|
import { CommandSuggestions, getFilteredCommands } from './CommandSuggestions.js';
|
|
25
|
+
import {
|
|
26
|
+
PermissionPrompt,
|
|
27
|
+
PermissionRulesDisplay,
|
|
28
|
+
PermissionAuditDisplay,
|
|
29
|
+
} from './PermissionPrompt.js';
|
|
30
|
+
import { TodoList } from './TodoList.js';
|
|
25
31
|
import { colors, icons } from './theme.js';
|
|
32
|
+
import { getTodos } from '../../tools/index.js';
|
|
26
33
|
import type { ProviderName } from '../../providers/index.js';
|
|
34
|
+
import type { ApprovalAction, ApprovalSuggestion } from '../../permissions/types.js';
|
|
35
|
+
import { gatherContextFiles, buildInitPrompt, getContextSummary } from '../../memory/index.js';
|
|
27
36
|
|
|
28
37
|
// Types
|
|
29
38
|
interface HistoryItem {
|
|
30
39
|
id: string;
|
|
31
|
-
type: 'header' | 'welcome' | 'user' | 'assistant' | 'tool_call' | 'tool_result' | 'info' | 'completion';
|
|
40
|
+
type: 'header' | 'welcome' | 'user' | 'assistant' | 'tool_call' | 'tool_result' | 'info' | 'completion' | 'todos';
|
|
32
41
|
content: string;
|
|
33
42
|
meta?: Record<string, unknown>;
|
|
34
43
|
}
|
|
@@ -36,11 +45,14 @@ interface HistoryItem {
|
|
|
36
45
|
interface ConfirmState {
|
|
37
46
|
tool: string;
|
|
38
47
|
input: Record<string, unknown>;
|
|
39
|
-
|
|
48
|
+
suggestions: ApprovalSuggestion[];
|
|
49
|
+
resolve: (action: ApprovalAction) => void;
|
|
40
50
|
}
|
|
41
51
|
|
|
42
52
|
interface SettingsManager {
|
|
43
53
|
save: (settings: { model?: string }) => Promise<void>;
|
|
54
|
+
getCwd?: () => string;
|
|
55
|
+
addPermissionRule?: (pattern: string, type: 'allow' | 'deny', level?: 'global' | 'project' | 'local') => Promise<void>;
|
|
44
56
|
}
|
|
45
57
|
|
|
46
58
|
interface Session {
|
|
@@ -49,10 +61,16 @@ interface Session {
|
|
|
49
61
|
updatedAt: string;
|
|
50
62
|
}
|
|
51
63
|
|
|
64
|
+
interface PermissionSettings {
|
|
65
|
+
allow?: string[];
|
|
66
|
+
deny?: string[];
|
|
67
|
+
}
|
|
68
|
+
|
|
52
69
|
interface AppProps {
|
|
53
70
|
config: AgentConfig;
|
|
54
71
|
settingsManager?: SettingsManager;
|
|
55
72
|
resumeLatest?: boolean;
|
|
73
|
+
permissionSettings?: PermissionSettings;
|
|
56
74
|
}
|
|
57
75
|
|
|
58
76
|
// ============================================================================
|
|
@@ -125,10 +143,64 @@ function SessionsTable({ sessions }: SessionsTableProps) {
|
|
|
125
143
|
);
|
|
126
144
|
}
|
|
127
145
|
|
|
146
|
+
// ============================================================================
|
|
147
|
+
// Memory Files Display Component
|
|
148
|
+
// ============================================================================
|
|
149
|
+
interface MemoryFileInfo {
|
|
150
|
+
path: string;
|
|
151
|
+
level: string;
|
|
152
|
+
size: number;
|
|
153
|
+
type: 'file' | 'rule';
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function MemoryFilesDisplay({ files }: { files: MemoryFileInfo[] }) {
|
|
157
|
+
const formatSize = (bytes: number): string => {
|
|
158
|
+
if (bytes < 1024) return `${bytes}B`;
|
|
159
|
+
return `${(bytes / 1024).toFixed(1)}KB`;
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
const memoryFiles = files.filter((f) => f.type === 'file');
|
|
163
|
+
const ruleFiles = files.filter((f) => f.type === 'rule');
|
|
164
|
+
|
|
165
|
+
return (
|
|
166
|
+
<Box flexDirection="column">
|
|
167
|
+
{memoryFiles.length > 0 && (
|
|
168
|
+
<>
|
|
169
|
+
<Text color={colors.info}>Loaded Memory Files:</Text>
|
|
170
|
+
{memoryFiles.map((f, i) => (
|
|
171
|
+
<Text key={f.path}>
|
|
172
|
+
<Text color={colors.textMuted}> [{i + 1}] </Text>
|
|
173
|
+
<Text color={colors.primary}>{f.path} </Text>
|
|
174
|
+
<Text color={colors.textMuted}>({f.level}, {formatSize(f.size)})</Text>
|
|
175
|
+
</Text>
|
|
176
|
+
))}
|
|
177
|
+
</>
|
|
178
|
+
)}
|
|
179
|
+
{ruleFiles.length > 0 && (
|
|
180
|
+
<Box flexDirection="column" marginTop={memoryFiles.length > 0 ? 1 : 0}>
|
|
181
|
+
<Text color={colors.info}>
|
|
182
|
+
Loaded Rules:
|
|
183
|
+
</Text>
|
|
184
|
+
{ruleFiles.map((f, i) => (
|
|
185
|
+
<Text key={f.path}>
|
|
186
|
+
<Text color={colors.textMuted}> [{i + 1}] </Text>
|
|
187
|
+
<Text color={colors.warning}>{f.path} </Text>
|
|
188
|
+
<Text color={colors.textMuted}>({f.level}, {formatSize(f.size)})</Text>
|
|
189
|
+
</Text>
|
|
190
|
+
))}
|
|
191
|
+
</Box>
|
|
192
|
+
)}
|
|
193
|
+
{files.length === 0 && (
|
|
194
|
+
<Text color={colors.textMuted}>No memory files loaded</Text>
|
|
195
|
+
)}
|
|
196
|
+
</Box>
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
|
|
128
200
|
// ============================================================================
|
|
129
201
|
// Main App
|
|
130
202
|
// ============================================================================
|
|
131
|
-
export function App({ config, settingsManager, resumeLatest }: AppProps) {
|
|
203
|
+
export function App({ config, settingsManager, resumeLatest, permissionSettings }: AppProps) {
|
|
132
204
|
const { exit } = useApp();
|
|
133
205
|
const agent = useAgent(config);
|
|
134
206
|
|
|
@@ -160,6 +232,8 @@ export function App({ config, settingsManager, resumeLatest }: AppProps) {
|
|
|
160
232
|
const [isThinking, setIsThinking] = useState(false);
|
|
161
233
|
const [streamingText, setStreamingText] = useState('');
|
|
162
234
|
const streamingTextRef = useRef(''); // Track current streaming text for closure
|
|
235
|
+
const [processingStartTime, setProcessingStartTime] = useState<number | undefined>(undefined);
|
|
236
|
+
const [tokenCount, setTokenCount] = useState(0);
|
|
163
237
|
const [confirmState, setConfirmState] = useState<ConfirmState | null>(null);
|
|
164
238
|
const [showModelSelector, setShowModelSelector] = useState(false);
|
|
165
239
|
const [showProviderManager, setShowProviderManager] = useState(false);
|
|
@@ -168,6 +242,7 @@ export function App({ config, settingsManager, resumeLatest }: AppProps) {
|
|
|
168
242
|
const [inputKey, setInputKey] = useState(0); // Force cursor to end after autocomplete
|
|
169
243
|
const [pendingTool, setPendingTool] = useState<{ name: string; input: Record<string, unknown> } | null>(null);
|
|
170
244
|
const pendingToolRef = useRef<{ name: string; input: Record<string, unknown> } | null>(null);
|
|
245
|
+
const [todos, setTodos] = useState<ReturnType<typeof getTodos>>([]);
|
|
171
246
|
|
|
172
247
|
// Check if showing command suggestions
|
|
173
248
|
const showCmdSuggestions = input.startsWith('/') && !isProcessing;
|
|
@@ -186,12 +261,30 @@ export function App({ config, settingsManager, resumeLatest }: AppProps) {
|
|
|
186
261
|
// Initialize
|
|
187
262
|
useEffect(() => {
|
|
188
263
|
const init = async () => {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
264
|
+
// Initialize permission system with settings
|
|
265
|
+
await agent.initializePermissions(permissionSettings);
|
|
266
|
+
|
|
267
|
+
// Set enhanced confirm callback with approval options
|
|
268
|
+
agent.setEnhancedConfirmCallback(async (tool, toolInput, suggestions) => {
|
|
269
|
+
return new Promise<ApprovalAction>((resolve) => {
|
|
270
|
+
setConfirmState({
|
|
271
|
+
tool,
|
|
272
|
+
input: toolInput as Record<string, unknown>,
|
|
273
|
+
suggestions,
|
|
274
|
+
resolve,
|
|
275
|
+
});
|
|
192
276
|
});
|
|
193
277
|
});
|
|
194
278
|
|
|
279
|
+
// Set callback to save permission rules to settings.local.json
|
|
280
|
+
if (settingsManager?.addPermissionRule) {
|
|
281
|
+
agent.setSaveRuleCallback(async (tool, pattern) => {
|
|
282
|
+
// Format as Claude Code style pattern: Tool(pattern) or just Tool
|
|
283
|
+
const rulePattern = pattern ? `${tool}(${pattern})` : tool;
|
|
284
|
+
await settingsManager.addPermissionRule!(rulePattern, 'allow', 'local');
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
|
|
195
288
|
if (resumeLatest) {
|
|
196
289
|
const resumed = await agent.resumeLatest();
|
|
197
290
|
if (resumed) {
|
|
@@ -200,12 +293,12 @@ export function App({ config, settingsManager, resumeLatest }: AppProps) {
|
|
|
200
293
|
}
|
|
201
294
|
};
|
|
202
295
|
init();
|
|
203
|
-
}, [agent, resumeLatest, addHistory]);
|
|
296
|
+
}, [agent, resumeLatest, addHistory, permissionSettings, settingsManager]);
|
|
204
297
|
|
|
205
|
-
// Handle
|
|
206
|
-
const
|
|
298
|
+
// Handle permission decision
|
|
299
|
+
const handlePermissionDecision = (action: ApprovalAction) => {
|
|
207
300
|
if (confirmState) {
|
|
208
|
-
confirmState.resolve(
|
|
301
|
+
confirmState.resolve(action);
|
|
209
302
|
setConfirmState(null);
|
|
210
303
|
}
|
|
211
304
|
};
|
|
@@ -321,13 +414,113 @@ export function App({ config, settingsManager, resumeLatest }: AppProps) {
|
|
|
321
414
|
return true;
|
|
322
415
|
}
|
|
323
416
|
|
|
417
|
+
case 'permissions': {
|
|
418
|
+
const permManager = agent.getPermissionManager();
|
|
419
|
+
|
|
420
|
+
if (arg === 'audit') {
|
|
421
|
+
// Show audit log
|
|
422
|
+
const auditLog = permManager.getAuditLog(20);
|
|
423
|
+
if (auditLog.length === 0) {
|
|
424
|
+
addHistory({ type: 'info', content: 'No permission decisions recorded yet' });
|
|
425
|
+
} else {
|
|
426
|
+
const entries = auditLog.map((e) => ({
|
|
427
|
+
time: e.timestamp.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit' }),
|
|
428
|
+
tool: e.tool,
|
|
429
|
+
input: e.inputSummary,
|
|
430
|
+
decision: e.decision,
|
|
431
|
+
rule: e.matchedRule,
|
|
432
|
+
}));
|
|
433
|
+
addHistory({
|
|
434
|
+
type: 'info',
|
|
435
|
+
content: '__PERMISSION_AUDIT__',
|
|
436
|
+
meta: { entries },
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
} else if (arg === 'stats') {
|
|
440
|
+
// Show statistics
|
|
441
|
+
const stats = permManager.getAuditStats();
|
|
442
|
+
addHistory({
|
|
443
|
+
type: 'info',
|
|
444
|
+
content: `Permissions: ${stats.allowed + stats.confirmed} allowed, ${stats.denied + stats.rejected} denied`,
|
|
445
|
+
});
|
|
446
|
+
} else {
|
|
447
|
+
// Show rules
|
|
448
|
+
const rules = permManager.getRules();
|
|
449
|
+
const prompts = permManager.getAllowedPrompts();
|
|
450
|
+
const displayRules = rules.map((r) => ({
|
|
451
|
+
type: r.scope === 'session' ? 'Session' : r.description?.startsWith('Settings') ? 'Settings' : 'Built-in',
|
|
452
|
+
tool: typeof r.tool === 'string' ? r.tool : r.tool.toString(),
|
|
453
|
+
pattern: typeof r.pattern === 'string' ? r.pattern : r.pattern?.toString(),
|
|
454
|
+
scope: r.scope ?? 'session',
|
|
455
|
+
mode: r.mode,
|
|
456
|
+
}));
|
|
457
|
+
addHistory({
|
|
458
|
+
type: 'info',
|
|
459
|
+
content: '__PERMISSIONS__',
|
|
460
|
+
meta: { rules: displayRules, prompts },
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
return true;
|
|
464
|
+
}
|
|
465
|
+
|
|
324
466
|
case 'init': {
|
|
325
|
-
|
|
467
|
+
// Gather context files and generate AGENT.md
|
|
468
|
+
addHistory({ type: 'info', content: 'Analyzing codebase...' });
|
|
469
|
+
|
|
470
|
+
const contextFiles = await gatherContextFiles(cwd);
|
|
471
|
+
addHistory({ type: 'info', content: getContextSummary(contextFiles) });
|
|
472
|
+
|
|
473
|
+
// Check if AGENT.md already exists
|
|
474
|
+
const memoryManager = agent.getMemoryManager();
|
|
475
|
+
const existingPath = await memoryManager.getExistingProjectMemoryPath(cwd);
|
|
476
|
+
let existingContent: string | undefined;
|
|
477
|
+
|
|
478
|
+
if (existingPath) {
|
|
479
|
+
try {
|
|
480
|
+
const fs = await import('fs/promises');
|
|
481
|
+
existingContent = await fs.readFile(existingPath, 'utf-8');
|
|
482
|
+
addHistory({
|
|
483
|
+
type: 'info',
|
|
484
|
+
content: `Found existing: ${existingPath.replace(cwd, '.')}`,
|
|
485
|
+
});
|
|
486
|
+
} catch {
|
|
487
|
+
// File doesn't exist or can't be read
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// Build init prompt and run through agent
|
|
492
|
+
const initPrompt = buildInitPrompt(contextFiles, existingContent);
|
|
493
|
+
addHistory({ type: 'info', content: 'Generating AGENT.md...' });
|
|
494
|
+
addHistory({ type: 'user', content: '/init' });
|
|
495
|
+
await runAgent(initPrompt);
|
|
326
496
|
return true;
|
|
327
497
|
}
|
|
328
498
|
|
|
329
499
|
case 'memory': {
|
|
330
|
-
|
|
500
|
+
// Show loaded memory files
|
|
501
|
+
const memoryManager = agent.getMemoryManager();
|
|
502
|
+
const loadedFiles = memoryManager.getLoadedFileList();
|
|
503
|
+
|
|
504
|
+
if (loadedFiles.length === 0) {
|
|
505
|
+
// Try to load memory first
|
|
506
|
+
await agent.loadMemory();
|
|
507
|
+
const filesAfterLoad = memoryManager.getLoadedFileList();
|
|
508
|
+
if (filesAfterLoad.length === 0) {
|
|
509
|
+
addHistory({ type: 'info', content: 'No memory files found' });
|
|
510
|
+
} else {
|
|
511
|
+
addHistory({
|
|
512
|
+
type: 'info',
|
|
513
|
+
content: '__MEMORY__',
|
|
514
|
+
meta: { files: filesAfterLoad },
|
|
515
|
+
});
|
|
516
|
+
}
|
|
517
|
+
} else {
|
|
518
|
+
addHistory({
|
|
519
|
+
type: 'info',
|
|
520
|
+
content: '__MEMORY__',
|
|
521
|
+
meta: { files: loadedFiles },
|
|
522
|
+
});
|
|
523
|
+
}
|
|
331
524
|
return true;
|
|
332
525
|
}
|
|
333
526
|
|
|
@@ -347,6 +540,8 @@ export function App({ config, settingsManager, resumeLatest }: AppProps) {
|
|
|
347
540
|
streamingTextRef.current = '';
|
|
348
541
|
interruptFlagRef.current = false;
|
|
349
542
|
const startTime = Date.now();
|
|
543
|
+
setProcessingStartTime(startTime);
|
|
544
|
+
setTokenCount(0);
|
|
350
545
|
|
|
351
546
|
try {
|
|
352
547
|
for await (const event of agent.run(prompt)) {
|
|
@@ -360,6 +555,8 @@ export function App({ config, settingsManager, resumeLatest }: AppProps) {
|
|
|
360
555
|
setIsThinking(false);
|
|
361
556
|
streamingTextRef.current += event.text;
|
|
362
557
|
setStreamingText(streamingTextRef.current);
|
|
558
|
+
// Estimate token count (roughly 4 chars per token)
|
|
559
|
+
setTokenCount((prev) => prev + Math.max(1, Math.ceil(event.text.length / 4)));
|
|
363
560
|
break;
|
|
364
561
|
|
|
365
562
|
case 'tool_start':
|
|
@@ -376,24 +573,37 @@ export function App({ config, settingsManager, resumeLatest }: AppProps) {
|
|
|
376
573
|
break;
|
|
377
574
|
|
|
378
575
|
case 'tool_result':
|
|
379
|
-
//
|
|
380
|
-
if (
|
|
576
|
+
// For TodoWrite: add todos first, then hide tool_call/tool_result
|
|
577
|
+
if (event.name === 'TodoWrite') {
|
|
578
|
+
const currentTodos = getTodos();
|
|
579
|
+
setTodos(currentTodos);
|
|
580
|
+
if (currentTodos.length > 0) {
|
|
581
|
+
addHistory({
|
|
582
|
+
type: 'todos',
|
|
583
|
+
content: '',
|
|
584
|
+
meta: { todos: currentTodos },
|
|
585
|
+
});
|
|
586
|
+
}
|
|
587
|
+
} else {
|
|
588
|
+
// Add tool_call to history (now completed) - use ref for correct value
|
|
589
|
+
if (pendingToolRef.current) {
|
|
590
|
+
addHistory({
|
|
591
|
+
type: 'tool_call',
|
|
592
|
+
content: pendingToolRef.current.name,
|
|
593
|
+
meta: { toolName: pendingToolRef.current.name, input: pendingToolRef.current.input },
|
|
594
|
+
});
|
|
595
|
+
}
|
|
596
|
+
// Add tool_result to history
|
|
381
597
|
addHistory({
|
|
382
|
-
type: '
|
|
383
|
-
content:
|
|
384
|
-
meta: {
|
|
598
|
+
type: 'tool_result',
|
|
599
|
+
content: event.result.output,
|
|
600
|
+
meta: {
|
|
601
|
+
toolName: event.name,
|
|
602
|
+
success: event.result.success,
|
|
603
|
+
metadata: event.result.metadata,
|
|
604
|
+
},
|
|
385
605
|
});
|
|
386
606
|
}
|
|
387
|
-
// Add tool_result to history
|
|
388
|
-
addHistory({
|
|
389
|
-
type: 'tool_result',
|
|
390
|
-
content: event.result.output,
|
|
391
|
-
meta: {
|
|
392
|
-
toolName: event.name,
|
|
393
|
-
success: event.result.success,
|
|
394
|
-
metadata: event.result.metadata,
|
|
395
|
-
},
|
|
396
|
-
});
|
|
397
607
|
pendingToolRef.current = null;
|
|
398
608
|
setPendingTool(null);
|
|
399
609
|
setIsThinking(true);
|
|
@@ -413,6 +623,7 @@ export function App({ config, settingsManager, resumeLatest }: AppProps) {
|
|
|
413
623
|
// Add completion message with duration
|
|
414
624
|
const durationMs = Date.now() - startTime;
|
|
415
625
|
addHistory({ type: 'completion', content: '', meta: { durationMs } });
|
|
626
|
+
setProcessingStartTime(undefined);
|
|
416
627
|
break;
|
|
417
628
|
}
|
|
418
629
|
}
|
|
@@ -454,6 +665,47 @@ export function App({ config, settingsManager, resumeLatest }: AppProps) {
|
|
|
454
665
|
return;
|
|
455
666
|
}
|
|
456
667
|
|
|
668
|
+
// Handle # prefix for quick memory adds
|
|
669
|
+
// ## note -> user memory (~/.gencode/AGENT.md)
|
|
670
|
+
// # note -> project memory (./AGENT.md)
|
|
671
|
+
if (trimmed.startsWith('#') && !trimmed.startsWith('#!/')) {
|
|
672
|
+
const memoryManager = agent.getMemoryManager();
|
|
673
|
+
let level: 'user' | 'project';
|
|
674
|
+
let content: string;
|
|
675
|
+
|
|
676
|
+
if (trimmed.startsWith('## ')) {
|
|
677
|
+
level = 'user';
|
|
678
|
+
content = trimmed.slice(3).trim();
|
|
679
|
+
} else if (trimmed.startsWith('# ')) {
|
|
680
|
+
level = 'project';
|
|
681
|
+
content = trimmed.slice(2).trim();
|
|
682
|
+
} else {
|
|
683
|
+
// Just # with no space, treat as project
|
|
684
|
+
level = 'project';
|
|
685
|
+
content = trimmed.slice(1).trim();
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
if (!content) {
|
|
689
|
+
addHistory({ type: 'info', content: 'Empty memory entry ignored' });
|
|
690
|
+
return;
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
try {
|
|
694
|
+
const savedPath = await memoryManager.quickAdd(content, level, cwd);
|
|
695
|
+
const displayPath = savedPath.replace(process.env.HOME || '', '~');
|
|
696
|
+
addHistory({
|
|
697
|
+
type: 'info',
|
|
698
|
+
content: `Added to ${level} memory: ${displayPath}`,
|
|
699
|
+
});
|
|
700
|
+
} catch (error) {
|
|
701
|
+
addHistory({
|
|
702
|
+
type: 'info',
|
|
703
|
+
content: `Failed to add to memory: ${error instanceof Error ? error.message : String(error)}`,
|
|
704
|
+
});
|
|
705
|
+
}
|
|
706
|
+
return;
|
|
707
|
+
}
|
|
708
|
+
|
|
457
709
|
if (trimmed.startsWith('/')) {
|
|
458
710
|
const handled = await handleCommand(trimmed);
|
|
459
711
|
if (!handled) {
|
|
@@ -537,9 +789,29 @@ export function App({ config, settingsManager, resumeLatest }: AppProps) {
|
|
|
537
789
|
if (item.content === '__SESSIONS__' && item.meta?.input) {
|
|
538
790
|
return <SessionsTable sessions={item.meta.input as Session[]} />;
|
|
539
791
|
}
|
|
792
|
+
if (item.content === '__PERMISSIONS__' && item.meta?.rules) {
|
|
793
|
+
return (
|
|
794
|
+
<PermissionRulesDisplay
|
|
795
|
+
rules={item.meta.rules as { type: string; tool: string; pattern?: string; scope: string; mode: string }[]}
|
|
796
|
+
allowedPrompts={item.meta.prompts as { tool: string; prompt: string }[] | undefined}
|
|
797
|
+
/>
|
|
798
|
+
);
|
|
799
|
+
}
|
|
800
|
+
if (item.content === '__PERMISSION_AUDIT__' && item.meta?.entries) {
|
|
801
|
+
return (
|
|
802
|
+
<PermissionAuditDisplay
|
|
803
|
+
entries={item.meta.entries as { time: string; tool: string; input: string; decision: string; rule?: string }[]}
|
|
804
|
+
/>
|
|
805
|
+
);
|
|
806
|
+
}
|
|
807
|
+
if (item.content === '__MEMORY__' && item.meta?.files) {
|
|
808
|
+
return <MemoryFilesDisplay files={item.meta.files as MemoryFileInfo[]} />;
|
|
809
|
+
}
|
|
540
810
|
return <InfoMessage text={item.content} />;
|
|
541
811
|
case 'completion':
|
|
542
812
|
return <CompletionMessage durationMs={(item.meta?.durationMs as number) || 0} />;
|
|
813
|
+
case 'todos':
|
|
814
|
+
return <TodoList todos={item.meta?.todos as ReturnType<typeof getTodos>} />;
|
|
543
815
|
default:
|
|
544
816
|
return null;
|
|
545
817
|
}
|
|
@@ -551,17 +823,18 @@ export function App({ config, settingsManager, resumeLatest }: AppProps) {
|
|
|
551
823
|
{(item) => <Box key={item.id}>{renderHistoryItem(item)}</Box>}
|
|
552
824
|
</Static>
|
|
553
825
|
|
|
554
|
-
{pendingTool && <PendingToolCall name={pendingTool.name} input={pendingTool.input} />}
|
|
826
|
+
{pendingTool && !confirmState && <PendingToolCall name={pendingTool.name} input={pendingTool.input} />}
|
|
555
827
|
|
|
556
828
|
{streamingText && <AssistantMessage text={streamingText} streaming />}
|
|
557
829
|
|
|
558
830
|
{confirmState && (
|
|
559
|
-
<
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
831
|
+
<PermissionPrompt
|
|
832
|
+
tool={confirmState.tool}
|
|
833
|
+
input={confirmState.input}
|
|
834
|
+
suggestions={confirmState.suggestions}
|
|
835
|
+
onDecision={handlePermissionDecision}
|
|
836
|
+
projectPath={settingsManager?.getCwd?.() ?? process.cwd()}
|
|
837
|
+
/>
|
|
565
838
|
)}
|
|
566
839
|
|
|
567
840
|
{showModelSelector && (
|
|
@@ -602,8 +875,8 @@ export function App({ config, settingsManager, resumeLatest }: AppProps) {
|
|
|
602
875
|
</Box>
|
|
603
876
|
)}
|
|
604
877
|
|
|
605
|
-
{isProcessing ? (
|
|
606
|
-
<ProgressBar />
|
|
878
|
+
{isProcessing && !confirmState ? (
|
|
879
|
+
<ProgressBar startTime={processingStartTime} tokenCount={tokenCount} isThinking={isThinking} />
|
|
607
880
|
) : showCmdSuggestions && cmdSuggestions.length > 0 ? (
|
|
608
881
|
<Box marginTop={1}>
|
|
609
882
|
<Text color={colors.textMuted}> Tab to complete · ↑↓ navigate</Text>
|
|
@@ -9,6 +9,8 @@ interface Command {
|
|
|
9
9
|
export const COMMANDS: Command[] = [
|
|
10
10
|
{ name: '/model', description: 'Switch model' },
|
|
11
11
|
{ name: '/provider', description: 'Manage providers' },
|
|
12
|
+
{ name: '/permissions', description: 'View permission rules' },
|
|
13
|
+
{ name: '/permissions audit', description: 'View permission audit log' },
|
|
12
14
|
{ name: '/sessions', description: 'List sessions' },
|
|
13
15
|
{ name: '/resume', description: 'Resume session' },
|
|
14
16
|
{ name: '/new', description: 'New session' },
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Box, Text } from 'ink';
|
|
2
2
|
import { colors } from './theme.js';
|
|
3
|
-
import {
|
|
3
|
+
import { BigLogo } from './Logo.js';
|
|
4
4
|
|
|
5
5
|
interface HeaderProps {
|
|
6
6
|
provider: string;
|
|
@@ -8,20 +8,14 @@ interface HeaderProps {
|
|
|
8
8
|
cwd: string;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
export function Header({
|
|
12
|
-
const home = process.env.HOME || '';
|
|
13
|
-
const cwdDisplay = cwd.startsWith(home) ? '~' + cwd.slice(home.length) : cwd;
|
|
14
|
-
|
|
11
|
+
export function Header({ model, cwd }: HeaderProps) {
|
|
15
12
|
return (
|
|
16
|
-
<Box flexDirection="
|
|
17
|
-
<
|
|
18
|
-
<Box
|
|
19
|
-
<
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
</Box>
|
|
23
|
-
<Text color={colors.textMuted}>{model} · API Usage Billing</Text>
|
|
24
|
-
<Text color={colors.textMuted}>{cwdDisplay}</Text>
|
|
13
|
+
<Box flexDirection="column" marginTop={1}>
|
|
14
|
+
<BigLogo />
|
|
15
|
+
<Box marginTop={1}>
|
|
16
|
+
<Text color={colors.textSecondary}>{model}</Text>
|
|
17
|
+
<Text color={colors.textMuted}> · </Text>
|
|
18
|
+
<Text color={colors.textMuted}>{cwd}</Text>
|
|
25
19
|
</Box>
|
|
26
20
|
</Box>
|
|
27
21
|
);
|
|
@@ -29,8 +23,8 @@ export function Header({ provider, model, cwd }: HeaderProps) {
|
|
|
29
23
|
|
|
30
24
|
export function Welcome() {
|
|
31
25
|
return (
|
|
32
|
-
<
|
|
33
|
-
|
|
34
|
-
</
|
|
26
|
+
<Box marginTop={1}>
|
|
27
|
+
<Text color={colors.textMuted}>? for help · Ctrl+C to exit</Text>
|
|
28
|
+
</Box>
|
|
35
29
|
);
|
|
36
30
|
}
|
|
@@ -1,16 +1,83 @@
|
|
|
1
1
|
import { Box, Text } from 'ink';
|
|
2
|
+
import { colors } from './theme.js';
|
|
2
3
|
|
|
4
|
+
// Small G logo for inline use
|
|
3
5
|
export function Logo() {
|
|
4
|
-
// Full G with 3D shadow - subdued slate color
|
|
5
|
-
const slateColor = "#64748B"; // Slate 500 - stable, professional
|
|
6
6
|
return (
|
|
7
|
-
<Box
|
|
8
|
-
<Text color={
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
<Box marginRight={1}>
|
|
8
|
+
<Text bold color={colors.brand}>◆</Text>
|
|
9
|
+
</Box>
|
|
10
|
+
);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Large ASCII art logo with elegant gradient
|
|
14
|
+
export function BigLogo() {
|
|
15
|
+
// Indigo gradient - brand colors
|
|
16
|
+
const c1 = '#818CF8'; // Indigo 400
|
|
17
|
+
const c2 = '#818CF8'; // Indigo 400
|
|
18
|
+
const c3 = '#A5B4FC'; // Indigo 300
|
|
19
|
+
const c4 = '#A5B4FC'; // Indigo 300
|
|
20
|
+
const c5 = '#C7D2FE'; // Indigo 200
|
|
21
|
+
const c6 = '#C7D2FE'; // Indigo 200
|
|
22
|
+
const c7 = '#C7D2FE'; // Indigo 200
|
|
23
|
+
|
|
24
|
+
// G E N C O D E
|
|
25
|
+
return (
|
|
26
|
+
<Box flexDirection="column">
|
|
27
|
+
<Text>
|
|
28
|
+
<Text color={c1}> ██████╗ </Text>
|
|
29
|
+
<Text color={c2}>███████╗</Text>
|
|
30
|
+
<Text color={c3}>███╗ ██╗</Text>
|
|
31
|
+
<Text color={c4}> ██████╗</Text>
|
|
32
|
+
<Text color={c5}> ██████╗ </Text>
|
|
33
|
+
<Text color={c6}>██████╗ </Text>
|
|
34
|
+
<Text color={c7}>███████╗</Text>
|
|
35
|
+
</Text>
|
|
36
|
+
<Text>
|
|
37
|
+
<Text color={c1}>██╔════╝ </Text>
|
|
38
|
+
<Text color={c2}>██╔════╝</Text>
|
|
39
|
+
<Text color={c3}>████╗ ██║</Text>
|
|
40
|
+
<Text color={c4}>██╔════╝</Text>
|
|
41
|
+
<Text color={c5}>██╔═══██╗</Text>
|
|
42
|
+
<Text color={c6}>██╔══██╗</Text>
|
|
43
|
+
<Text color={c7}>██╔════╝</Text>
|
|
44
|
+
</Text>
|
|
45
|
+
<Text>
|
|
46
|
+
<Text color={c1}>██║ ███╗</Text>
|
|
47
|
+
<Text color={c2}>█████╗ </Text>
|
|
48
|
+
<Text color={c3}>██╔██╗ ██║</Text>
|
|
49
|
+
<Text color={c4}>██║ </Text>
|
|
50
|
+
<Text color={c5}>██║ ██║</Text>
|
|
51
|
+
<Text color={c6}>██║ ██║</Text>
|
|
52
|
+
<Text color={c7}>█████╗ </Text>
|
|
53
|
+
</Text>
|
|
54
|
+
<Text>
|
|
55
|
+
<Text color={c1}>██║ ██║</Text>
|
|
56
|
+
<Text color={c2}>██╔══╝ </Text>
|
|
57
|
+
<Text color={c3}>██║╚██╗██║</Text>
|
|
58
|
+
<Text color={c4}>██║ </Text>
|
|
59
|
+
<Text color={c5}>██║ ██║</Text>
|
|
60
|
+
<Text color={c6}>██║ ██║</Text>
|
|
61
|
+
<Text color={c7}>██╔══╝ </Text>
|
|
62
|
+
</Text>
|
|
63
|
+
<Text>
|
|
64
|
+
<Text color={c1}>╚██████╔╝</Text>
|
|
65
|
+
<Text color={c2}>███████╗</Text>
|
|
66
|
+
<Text color={c3}>██║ ╚████║</Text>
|
|
67
|
+
<Text color={c4}>╚██████╗</Text>
|
|
68
|
+
<Text color={c5}>╚██████╔╝</Text>
|
|
69
|
+
<Text color={c6}>██████╔╝</Text>
|
|
70
|
+
<Text color={c7}>███████╗</Text>
|
|
71
|
+
</Text>
|
|
72
|
+
<Text>
|
|
73
|
+
<Text color={c1}> ╚═════╝ </Text>
|
|
74
|
+
<Text color={c2}>╚══════╝</Text>
|
|
75
|
+
<Text color={c3}>╚═╝ ╚═══╝</Text>
|
|
76
|
+
<Text color={c4}> ╚═════╝</Text>
|
|
77
|
+
<Text color={c5}> ╚═════╝ </Text>
|
|
78
|
+
<Text color={c6}>╚═════╝ </Text>
|
|
79
|
+
<Text color={c7}>╚══════╝</Text>
|
|
80
|
+
</Text>
|
|
14
81
|
</Box>
|
|
15
82
|
);
|
|
16
83
|
}
|