deeper-cli 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (188) hide show
  1. package/README.md +254 -0
  2. package/dist/cli/index.d.ts +1 -0
  3. package/dist/cli/index.js +12067 -0
  4. package/dist/cli/index.js.map +1 -0
  5. package/dist/index.d.ts +415 -0
  6. package/dist/index.js +1599 -0
  7. package/dist/index.js.map +1 -0
  8. package/docs/superpowers/plans/2026-05-14-deepercode-implementation.md +24 -0
  9. package/docs/superpowers/plans/2026-05-14-deepercode-plan.md +1248 -0
  10. package/docs/superpowers/specs/2026-05-14-deepercode-design.md +560 -0
  11. package/package.json +60 -0
  12. package/src/cli/bootstrap.ts +69 -0
  13. package/src/cli/chat-repl.ts +932 -0
  14. package/src/cli/commands/chat.ts +39 -0
  15. package/src/cli/commands/chat.tsx +39 -0
  16. package/src/cli/commands/config.ts +133 -0
  17. package/src/cli/commands/mcp.ts +172 -0
  18. package/src/cli/commands/run.ts +147 -0
  19. package/src/cli/commands/skill.ts +152 -0
  20. package/src/cli/index.ts +184 -0
  21. package/src/core/bugscan.ts +145 -0
  22. package/src/core/config.ts +285 -0
  23. package/src/core/constants.ts +49 -0
  24. package/src/core/eventbus.ts +202 -0
  25. package/src/core/logger.ts +109 -0
  26. package/src/core/storage.ts +96 -0
  27. package/src/index.ts +26 -0
  28. package/src/mcp/ConfigLoader.ts +74 -0
  29. package/src/mcp/MCPClient.ts +326 -0
  30. package/src/mcp/ResourceAdapter.ts +58 -0
  31. package/src/mcp/SSETransport.ts +133 -0
  32. package/src/mcp/StdioTransport.ts +116 -0
  33. package/src/mcp/ToolAdapter.ts +71 -0
  34. package/src/mcp/types.ts +58 -0
  35. package/src/memory/xmemory.ts +275 -0
  36. package/src/model/DeepSeekClient.ts +292 -0
  37. package/src/model/MessageBuilder.ts +155 -0
  38. package/src/model/RetryManager.ts +82 -0
  39. package/src/model/StreamHandler.ts +158 -0
  40. package/src/model/types.ts +86 -0
  41. package/src/skills/SkillCreator.ts +153 -0
  42. package/src/skills/SkillEngine.ts +158 -0
  43. package/src/skills/SkillExecutor.ts +107 -0
  44. package/src/skills/SkillLoader.ts +182 -0
  45. package/src/skills/SkillRegistry.ts +73 -0
  46. package/src/skills/SkillTrigger.ts +82 -0
  47. package/src/skills/types.ts +28 -0
  48. package/src/tools/ToolExecutor.ts +103 -0
  49. package/src/tools/ToolRegistry.ts +71 -0
  50. package/src/tools/ToolValidator.ts +103 -0
  51. package/src/tools/builtin/ai/context_summarize.ts +76 -0
  52. package/src/tools/builtin/ai/memory_store.ts +86 -0
  53. package/src/tools/builtin/ai/prompt_template.ts +71 -0
  54. package/src/tools/builtin/ai/skill_create.ts +53 -0
  55. package/src/tools/builtin/ai/subagent.ts +39 -0
  56. package/src/tools/builtin/ai/todo_manager.ts +157 -0
  57. package/src/tools/builtin/ai/token_count.ts +196 -0
  58. package/src/tools/builtin/ai/tool_create.ts +52 -0
  59. package/src/tools/builtin/code/analyze_deps.ts +72 -0
  60. package/src/tools/builtin/code/bug_scan.ts +80 -0
  61. package/src/tools/builtin/code/code_metrics.ts +111 -0
  62. package/src/tools/builtin/code/extract_function.ts +86 -0
  63. package/src/tools/builtin/code/format_code.ts +57 -0
  64. package/src/tools/builtin/code/generate_code.ts +75 -0
  65. package/src/tools/builtin/code/import_organizer.ts +82 -0
  66. package/src/tools/builtin/code/lint_code.ts +48 -0
  67. package/src/tools/builtin/code/parse_ast.ts +86 -0
  68. package/src/tools/builtin/code/refactor_code.ts +63 -0
  69. package/src/tools/builtin/code/type_check.ts +48 -0
  70. package/src/tools/builtin/data/chart_generate.ts +62 -0
  71. package/src/tools/builtin/data/csv_parse.ts +56 -0
  72. package/src/tools/builtin/data/data_diff.ts +79 -0
  73. package/src/tools/builtin/data/data_transform.ts +74 -0
  74. package/src/tools/builtin/data/data_validate.ts +75 -0
  75. package/src/tools/builtin/data/json_parse.ts +71 -0
  76. package/src/tools/builtin/data/template_render.ts +58 -0
  77. package/src/tools/builtin/data/toml_parse.ts +42 -0
  78. package/src/tools/builtin/data/xml_parse.ts +79 -0
  79. package/src/tools/builtin/data/yaml_parse.ts +42 -0
  80. package/src/tools/builtin/database/db_backup.ts +53 -0
  81. package/src/tools/builtin/database/db_restore.ts +51 -0
  82. package/src/tools/builtin/database/db_schema.ts +66 -0
  83. package/src/tools/builtin/database/nosql_query.ts +50 -0
  84. package/src/tools/builtin/database/orm_generate.ts +66 -0
  85. package/src/tools/builtin/database/redis_command.ts +46 -0
  86. package/src/tools/builtin/database/sql_migrate.ts +55 -0
  87. package/src/tools/builtin/database/sql_query.ts +60 -0
  88. package/src/tools/builtin/filesystem/batch_read.ts +56 -0
  89. package/src/tools/builtin/filesystem/batch_write.ts +67 -0
  90. package/src/tools/builtin/filesystem/copy_file.ts +36 -0
  91. package/src/tools/builtin/filesystem/create_dir.ts +30 -0
  92. package/src/tools/builtin/filesystem/delete_file.ts +30 -0
  93. package/src/tools/builtin/filesystem/diff_files.ts +47 -0
  94. package/src/tools/builtin/filesystem/edit_file.ts +47 -0
  95. package/src/tools/builtin/filesystem/file_info.ts +52 -0
  96. package/src/tools/builtin/filesystem/glob_find.ts +44 -0
  97. package/src/tools/builtin/filesystem/list_dir.ts +51 -0
  98. package/src/tools/builtin/filesystem/merge_files.ts +44 -0
  99. package/src/tools/builtin/filesystem/move_file.ts +37 -0
  100. package/src/tools/builtin/filesystem/read_file.ts +55 -0
  101. package/src/tools/builtin/filesystem/watch_file.ts +33 -0
  102. package/src/tools/builtin/filesystem/write_file.ts +45 -0
  103. package/src/tools/builtin/index.ts +244 -0
  104. package/src/tools/builtin/network/api_call.ts +79 -0
  105. package/src/tools/builtin/network/browser_action.ts +54 -0
  106. package/src/tools/builtin/network/check_url.ts +59 -0
  107. package/src/tools/builtin/network/download_file.ts +64 -0
  108. package/src/tools/builtin/network/graphql_query.ts +46 -0
  109. package/src/tools/builtin/network/http_request.ts +61 -0
  110. package/src/tools/builtin/network/parse_html.ts +101 -0
  111. package/src/tools/builtin/network/proxy_request.ts +53 -0
  112. package/src/tools/builtin/network/screenshot_page.ts +58 -0
  113. package/src/tools/builtin/network/web_fetch.ts +70 -0
  114. package/src/tools/builtin/network/web_search.ts +128 -0
  115. package/src/tools/builtin/network/websocket_connect.ts +70 -0
  116. package/src/tools/builtin/project/build_project.ts +68 -0
  117. package/src/tools/builtin/project/config_manage.ts +99 -0
  118. package/src/tools/builtin/project/coverage_report.ts +59 -0
  119. package/src/tools/builtin/project/docker_manage.ts +90 -0
  120. package/src/tools/builtin/project/env_manage.ts +88 -0
  121. package/src/tools/builtin/project/npm_manage.ts +71 -0
  122. package/src/tools/builtin/project/project_init.ts +59 -0
  123. package/src/tools/builtin/project/run_test.ts +74 -0
  124. package/src/tools/builtin/search/codebase_search.ts +76 -0
  125. package/src/tools/builtin/search/find_definition.ts +84 -0
  126. package/src/tools/builtin/search/find_references.ts +75 -0
  127. package/src/tools/builtin/search/fuzzy_find.ts +75 -0
  128. package/src/tools/builtin/search/grep_search.ts +90 -0
  129. package/src/tools/builtin/search/regex_find.ts +91 -0
  130. package/src/tools/builtin/search/search_docs.ts +51 -0
  131. package/src/tools/builtin/search/search_package.ts +50 -0
  132. package/src/tools/builtin/search/symbol_search.ts +82 -0
  133. package/src/tools/builtin/search/text_search.ts +63 -0
  134. package/src/tools/builtin/security/decrypt_file.ts +54 -0
  135. package/src/tools/builtin/security/encrypt_file.ts +52 -0
  136. package/src/tools/builtin/security/hash_generate.ts +48 -0
  137. package/src/tools/builtin/security/jwt_decode.ts +53 -0
  138. package/src/tools/builtin/security/secret_scan.ts +82 -0
  139. package/src/tools/builtin/security/vulnerability_check.ts +71 -0
  140. package/src/tools/builtin/shell/background_terminal.ts +38 -0
  141. package/src/tools/builtin/shell/check_status.ts +48 -0
  142. package/src/tools/builtin/shell/interactive_terminal.ts +31 -0
  143. package/src/tools/builtin/shell/kill_terminal.ts +29 -0
  144. package/src/tools/builtin/shell/list_terminals.ts +61 -0
  145. package/src/tools/builtin/shell/pipe_commands.ts +55 -0
  146. package/src/tools/builtin/shell/process-pool.ts +150 -0
  147. package/src/tools/builtin/shell/run_async.ts +73 -0
  148. package/src/tools/builtin/shell/run_command.ts +60 -0
  149. package/src/tools/builtin/shell/send_ctrl_keys.ts +43 -0
  150. package/src/tools/builtin/shell/send_keys.ts +36 -0
  151. package/src/tools/builtin/shell/send_text.ts +35 -0
  152. package/src/tools/builtin/shell/shell_script.ts +65 -0
  153. package/src/tools/builtin/shell/stop_command.ts +40 -0
  154. package/src/tools/builtin/shell/terminal_resize.ts +31 -0
  155. package/src/tools/builtin/shell/terminal_screenshot.ts +28 -0
  156. package/src/tools/builtin/system/log_viewer.ts +89 -0
  157. package/src/tools/builtin/system/notify_user.ts +55 -0
  158. package/src/tools/builtin/system/process_list.ts +66 -0
  159. package/src/tools/builtin/system/resource_monitor.ts +66 -0
  160. package/src/tools/builtin/system/system_info.ts +41 -0
  161. package/src/tools/tool-types.ts +97 -0
  162. package/src/ui/AgentTree.tsx +98 -0
  163. package/src/ui/App.tsx +46 -0
  164. package/src/ui/ChatView.tsx +278 -0
  165. package/src/ui/ConfirmDialog.tsx +68 -0
  166. package/src/ui/DiffView.tsx +64 -0
  167. package/src/ui/FilePreview.tsx +59 -0
  168. package/src/ui/InputBox.tsx +267 -0
  169. package/src/ui/MessageBubble.tsx +30 -0
  170. package/src/ui/Spinner.tsx +35 -0
  171. package/src/ui/StatusBar.tsx +41 -0
  172. package/src/ui/ToolCallCard.tsx +73 -0
  173. package/src/ui/ansi.ts +50 -0
  174. package/src/ui/markdown.ts +238 -0
  175. package/src/ui/themes/dark.ts +4 -0
  176. package/src/ui/themes/default.ts +25 -0
  177. package/src/ui/themes/light.ts +14 -0
  178. package/tests/unit/BuiltinTools.test.ts +129 -0
  179. package/tests/unit/BuiltinToolsIntegration.test.ts +111 -0
  180. package/tests/unit/FilesystemTools.test.ts +211 -0
  181. package/tests/unit/SkillLoader.test.ts +141 -0
  182. package/tests/unit/SkillRegistry.test.ts +113 -0
  183. package/tests/unit/ToolExecutor.test.ts +160 -0
  184. package/tests/unit/ToolRegistry.test.ts +103 -0
  185. package/tests/unit/ToolValidator.test.ts +137 -0
  186. package/tsconfig.json +28 -0
  187. package/tsup.config.ts +17 -0
  188. package/vitest.config.ts +20 -0
@@ -0,0 +1,202 @@
1
+ import { EventEmitter } from 'node:events';
2
+
3
+ export interface ContextUpdatedPayload {
4
+ modelName: string;
5
+ tokenCount: number;
6
+ memoryUsage: number;
7
+ uptime: number;
8
+ }
9
+
10
+ export interface MessagePayload {
11
+ id: string;
12
+ role: 'user' | 'assistant' | 'system';
13
+ content: string;
14
+ thinking?: string;
15
+ timestamp: number;
16
+ }
17
+
18
+ export interface ToolCallPayload {
19
+ id: string;
20
+ toolName: string;
21
+ args: Record<string, unknown>;
22
+ status: 'pending' | 'running' | 'completed' | 'failed';
23
+ result?: string;
24
+ }
25
+
26
+ export interface DiffPayload {
27
+ filePath: string;
28
+ oldContent: string;
29
+ newContent: string;
30
+ }
31
+
32
+ export interface AgentPayload {
33
+ id: string;
34
+ name: string;
35
+ status: 'idle' | 'running' | 'completed' | 'failed';
36
+ parentId?: string;
37
+ task: string;
38
+ children?: AgentPayload[];
39
+ }
40
+
41
+ export const Events = {
42
+ CONTEXT_UPDATED: 'context:updated',
43
+ MESSAGE_SEND: 'message:send',
44
+ MESSAGE_RECEIVED: 'message:received',
45
+ MESSAGE_STREAMING: 'message:streaming',
46
+ TOOL_CALL_START: 'tool:call:start',
47
+ TOOL_CALL_END: 'tool:call:end',
48
+ FILE_DIFF: 'file:diff',
49
+ AGENT_TREE_UPDATED: 'agent:tree:updated',
50
+ APP_QUIT: 'app:quit',
51
+ APP_CLEAR: 'app:clear',
52
+ STATUS_UPDATE: 'status:update',
53
+ CONFIG_CHANGED: 'config:changed',
54
+ AGENT_STATUS_CHANGE: 'agent:status:change',
55
+ AGENT_CREATED: 'agent:created',
56
+ AGENT_THINKING: 'agent:thinking',
57
+ AGENT_EXECUTING: 'agent:executing',
58
+ AGENT_WAITING: 'agent:waiting',
59
+ AGENT_COMPLETED: 'agent:completed',
60
+ AGENT_FAILED: 'agent:failed',
61
+ AGENT_CANCELLED: 'agent:cancelled',
62
+ AGENT_LOOP_ITERATION: 'agent:loop:iteration',
63
+ AGENT_LOOP_DETECTED: 'agent:loop:detected',
64
+ AGENT_LOOP_LIMIT: 'agent:loop:limit',
65
+ TOOL_CALL_ERROR: 'tool:call:error',
66
+ ORCHESTRATOR_DECOMPOSE: 'orchestrator:decompose',
67
+ ORCHESTRATOR_DISPATCH: 'orchestrator:dispatch',
68
+ ORCHESTRATOR_AGGREGATE: 'orchestrator:aggregate',
69
+ SUBAGENT_START: 'subagent:start',
70
+ SUBAGENT_TIMEOUT: 'subagent:timeout',
71
+ SUBAGENT_COMPLETE: 'subagent:complete',
72
+ SUBAGENT_ERROR: 'subagent:error',
73
+ POOL_ACQUIRE: 'pool:acquire',
74
+ POOL_RELEASE: 'pool:release',
75
+ POOL_QUEUE: 'pool:queue',
76
+ CONTEXT_SUMMARIZED: 'context:summarized',
77
+ CONTEXT_TOKEN_WARNING: 'context:token:warning',
78
+ MCP_CONNECTED: 'mcp:connected',
79
+ MCP_ERROR: 'mcp:error',
80
+ MCP_DISCONNECTED: 'mcp:disconnected',
81
+ MCP_TOOLS_DISCOVERED: 'mcp:tools:discovered',
82
+ SKILL_LOADED: 'skill:loaded',
83
+ SKILL_EXECUTED: 'skill:executed',
84
+ SKILL_CREATED: 'skill:created',
85
+ SKILL_TRIGGERED: 'skill:triggered',
86
+ } as const;
87
+
88
+ export const EventBusEvents = Events;
89
+
90
+ export class EventBus extends EventEmitter {
91
+ private static instance: EventBus;
92
+
93
+ static getInstance(): EventBus {
94
+ if (!EventBus.instance) {
95
+ EventBus.instance = new EventBus();
96
+ }
97
+ return EventBus.instance;
98
+ }
99
+
100
+ onContextUpdated(handler: (payload: ContextUpdatedPayload) => void): void {
101
+ this.on(EventBusEvents.CONTEXT_UPDATED, handler);
102
+ }
103
+
104
+ emitContextUpdated(payload: ContextUpdatedPayload): void {
105
+ this.emit(EventBusEvents.CONTEXT_UPDATED, payload);
106
+ }
107
+
108
+ onMessageSend(handler: (payload: { content: string }) => void): void {
109
+ this.on(EventBusEvents.MESSAGE_SEND, handler);
110
+ }
111
+
112
+ emitMessageSend(payload: { content: string }): void {
113
+ this.emit(EventBusEvents.MESSAGE_SEND, payload);
114
+ }
115
+
116
+ onMessageReceived(handler: (payload: MessagePayload) => void): void {
117
+ this.on(EventBusEvents.MESSAGE_RECEIVED, handler);
118
+ }
119
+
120
+ emitMessageReceived(payload: MessagePayload): void {
121
+ this.emit(EventBusEvents.MESSAGE_RECEIVED, payload);
122
+ }
123
+
124
+ onMessageStreaming(handler: (payload: { id: string; content: string; thinking?: string }) => void): void {
125
+ this.on(EventBusEvents.MESSAGE_STREAMING, handler);
126
+ }
127
+
128
+ emitMessageStreaming(payload: { id: string; content: string; thinking?: string }): void {
129
+ this.emit(EventBusEvents.MESSAGE_STREAMING, payload);
130
+ }
131
+
132
+ onToolCallStart(handler: (payload: ToolCallPayload) => void): void {
133
+ this.on(EventBusEvents.TOOL_CALL_START, handler);
134
+ }
135
+
136
+ emitToolCallStart(payload: ToolCallPayload): void {
137
+ this.emit(EventBusEvents.TOOL_CALL_START, payload);
138
+ }
139
+
140
+ onToolCallEnd(handler: (payload: ToolCallPayload) => void): void {
141
+ this.on(EventBusEvents.TOOL_CALL_END, handler);
142
+ }
143
+
144
+ emitToolCallEnd(payload: ToolCallPayload): void {
145
+ this.emit(EventBusEvents.TOOL_CALL_END, payload);
146
+ }
147
+
148
+ onFileDiff(handler: (payload: DiffPayload) => void): void {
149
+ this.on(EventBusEvents.FILE_DIFF, handler);
150
+ }
151
+
152
+ emitFileDiff(payload: DiffPayload): void {
153
+ this.emit(EventBusEvents.FILE_DIFF, payload);
154
+ }
155
+
156
+ onAgentTreeUpdated(handler: (payload: { agents: AgentPayload[] }) => void): void {
157
+ this.on(EventBusEvents.AGENT_TREE_UPDATED, handler);
158
+ }
159
+
160
+ emitAgentTreeUpdated(payload: { agents: AgentPayload[] }): void {
161
+ this.emit(EventBusEvents.AGENT_TREE_UPDATED, payload);
162
+ }
163
+
164
+ onAppQuit(handler: () => void): void {
165
+ this.on(EventBusEvents.APP_QUIT, handler);
166
+ }
167
+
168
+ emitAppQuit(): void {
169
+ this.emit(EventBusEvents.APP_QUIT);
170
+ }
171
+
172
+ onAppClear(handler: () => void): void {
173
+ this.on(EventBusEvents.APP_CLEAR, handler);
174
+ }
175
+
176
+ emitAppClear(): void {
177
+ this.emit(EventBusEvents.APP_CLEAR);
178
+ }
179
+
180
+ onStatusUpdate(handler: (payload: Partial<ContextUpdatedPayload>) => void): void {
181
+ this.on(EventBusEvents.STATUS_UPDATE, handler);
182
+ }
183
+
184
+ emitStatusUpdate(payload: Partial<ContextUpdatedPayload>): void {
185
+ this.emit(EventBusEvents.STATUS_UPDATE, payload);
186
+ }
187
+
188
+ onConfigChanged(handler: (payload: Record<string, unknown>) => void): void {
189
+ this.on(EventBusEvents.CONFIG_CHANGED, handler);
190
+ }
191
+
192
+ emitConfigChanged(payload: Record<string, unknown>): void {
193
+ this.emit(EventBusEvents.CONFIG_CHANGED, payload);
194
+ }
195
+
196
+ reset(): void {
197
+ this.removeAllListeners();
198
+ }
199
+ }
200
+
201
+ export const eventbus = EventBus.getInstance();
202
+ export const globalEventBus = eventbus;
@@ -0,0 +1,109 @@
1
+ import { appendFileSync, existsSync, mkdirSync } from 'node:fs';
2
+ import { join, dirname } from 'node:path';
3
+ import { DEEPER_LOGS_DIR } from './constants.js';
4
+
5
+ export type LogLevel = 'debug' | 'info' | 'warn' | 'error';
6
+
7
+ const LOG_LEVEL_RANK: Record<LogLevel, number> = {
8
+ debug: 0,
9
+ info: 1,
10
+ warn: 2,
11
+ error: 3,
12
+ };
13
+
14
+ export class Logger {
15
+ private level: LogLevel;
16
+ private logDir: string;
17
+ private currentLogFile: string;
18
+
19
+ constructor(level: LogLevel = 'info', logDir?: string) {
20
+ this.level = level;
21
+ this.logDir = logDir ?? DEEPER_LOGS_DIR;
22
+ this.currentLogFile = this.generateLogFileName();
23
+ this.ensureLogDir();
24
+ }
25
+
26
+ setLevel(level: LogLevel): void {
27
+ this.level = level;
28
+ }
29
+
30
+ debug(message: string, data?: unknown): void {
31
+ this.log('debug', message, data);
32
+ }
33
+
34
+ info(message: string, data?: unknown): void {
35
+ this.log('info', message, data);
36
+ }
37
+
38
+ warn(message: string, data?: unknown): void {
39
+ this.log('warn', message, data);
40
+ }
41
+
42
+ error(message: string, data?: unknown): void {
43
+ this.log('error', message, data);
44
+ }
45
+
46
+ private log(level: LogLevel, message: string, data?: unknown): void {
47
+ if (LOG_LEVEL_RANK[level] < LOG_LEVEL_RANK[this.level]) {
48
+ return;
49
+ }
50
+
51
+ const timestamp = new Date().toISOString();
52
+ const formatted = this.formatMessage(level, timestamp, message, data);
53
+
54
+ switch (level) {
55
+ case 'error':
56
+ console.error(formatted);
57
+ break;
58
+ case 'warn':
59
+ console.warn(formatted);
60
+ break;
61
+ default:
62
+ console.log(formatted);
63
+ break;
64
+ }
65
+
66
+ try {
67
+ appendFileSync(this.currentLogFile, this.stripAnsi(formatted) + '\n', 'utf-8');
68
+ } catch {
69
+ }
70
+ }
71
+
72
+ private formatMessage(level: LogLevel, timestamp: string, message: string, data?: unknown): string {
73
+ const levelUpper = level.toUpperCase();
74
+ const base = `[${timestamp}] [${levelUpper}] ${message}`;
75
+ if (data !== undefined) {
76
+ if (typeof data === 'string') {
77
+ return `${base} ${data}`;
78
+ }
79
+ if (data instanceof Error) {
80
+ return `${base} ${data.message}\n${data.stack ?? ''}`;
81
+ }
82
+ try {
83
+ return `${base} ${JSON.stringify(data)}`;
84
+ } catch {
85
+ return `${base} [Unserializable data]`;
86
+ }
87
+ }
88
+ return base;
89
+ }
90
+
91
+ private stripAnsi(text: string): string {
92
+ return text.replace(/\x1b\[[0-9;]*m/g, '');
93
+ }
94
+
95
+ private generateLogFileName(): string {
96
+ const now = new Date();
97
+ const dateStr = now.toISOString().slice(0, 10).replace(/-/g, '');
98
+ return join(this.logDir, `deeper-${dateStr}.log`);
99
+ }
100
+
101
+ private ensureLogDir(): void {
102
+ const dir = dirname(this.currentLogFile);
103
+ if (!existsSync(dir)) {
104
+ mkdirSync(dir, { recursive: true });
105
+ }
106
+ }
107
+ }
108
+
109
+ export const logger = new Logger();
@@ -0,0 +1,96 @@
1
+ import { existsSync, readFileSync, writeFileSync, mkdirSync, unlinkSync, readdirSync } from 'node:fs';
2
+ import { join, dirname } from 'node:path';
3
+ import { DEEPER_HOME } from './constants.js';
4
+
5
+ export class Storage {
6
+ private baseDir: string;
7
+
8
+ constructor(baseDir?: string) {
9
+ this.baseDir = baseDir ?? join(DEEPER_HOME, 'storage');
10
+ this.ensureDir(this.baseDir);
11
+ }
12
+
13
+ get<T = unknown>(key: string): T | null {
14
+ const filePath = this.getFilePath(key);
15
+ try {
16
+ if (!existsSync(filePath)) {
17
+ return null;
18
+ }
19
+ const content = readFileSync(filePath, 'utf-8');
20
+ return JSON.parse(content) as T;
21
+ } catch {
22
+ return null;
23
+ }
24
+ }
25
+
26
+ set<T = unknown>(key: string, value: T): void {
27
+ const filePath = this.getFilePath(key);
28
+ this.ensureDir(dirname(filePath));
29
+ writeFileSync(filePath, JSON.stringify(value, null, 2), 'utf-8');
30
+ }
31
+
32
+ delete(key: string): boolean {
33
+ const filePath = this.getFilePath(key);
34
+ try {
35
+ if (existsSync(filePath)) {
36
+ unlinkSync(filePath);
37
+ return true;
38
+ }
39
+ } catch {
40
+ }
41
+ return false;
42
+ }
43
+
44
+ has(key: string): boolean {
45
+ return existsSync(this.getFilePath(key));
46
+ }
47
+
48
+ keys(): string[] {
49
+ const result: string[] = [];
50
+ try {
51
+ if (existsSync(this.baseDir)) {
52
+ const files = readdirSync(this.baseDir, { recursive: true });
53
+ for (const file of files) {
54
+ const fileName = typeof file === 'string' ? file : file.toString('utf-8');
55
+ if (fileName.endsWith('.json')) {
56
+ result.push(fileName.replace(/\.json$/, '').replace(/\\/g, '/'));
57
+ }
58
+ }
59
+ }
60
+ } catch {
61
+ }
62
+ return result;
63
+ }
64
+
65
+ clear(): void {
66
+ try {
67
+ const files = readdirSync(this.baseDir, { recursive: true });
68
+ for (const file of files) {
69
+ const fullPath = join(this.baseDir, typeof file === 'string' ? file : file.toString('utf-8'));
70
+ try {
71
+ unlinkSync(fullPath);
72
+ } catch {
73
+ }
74
+ }
75
+ } catch {
76
+ }
77
+ }
78
+
79
+ setBaseDir(dir: string): void {
80
+ this.baseDir = dir;
81
+ this.ensureDir(dir);
82
+ }
83
+
84
+ private getFilePath(key: string): string {
85
+ const safeKey = key.replace(/[<>:"/\\|?*]/g, '_');
86
+ return join(this.baseDir, `${safeKey}.json`);
87
+ }
88
+
89
+ private ensureDir(dir: string): void {
90
+ if (!existsSync(dir)) {
91
+ mkdirSync(dir, { recursive: true });
92
+ }
93
+ }
94
+ }
95
+
96
+ export const storage = new Storage();
package/src/index.ts ADDED
@@ -0,0 +1,26 @@
1
+ export { defaultTheme, type Theme } from './ui/themes/default.ts';
2
+ export { darkTheme } from './ui/themes/dark.ts';
3
+ export { lightTheme } from './ui/themes/light.ts';
4
+
5
+ export { Spinner } from './ui/Spinner.tsx';
6
+ export { MessageBubble } from './ui/MessageBubble.tsx';
7
+ export { ToolCallCard } from './ui/ToolCallCard.tsx';
8
+ export { DiffView } from './ui/DiffView.tsx';
9
+ export { FilePreview } from './ui/FilePreview.tsx';
10
+ export { AgentTree } from './ui/AgentTree.tsx';
11
+ export { ConfirmDialog } from './ui/ConfirmDialog.tsx';
12
+ export { StatusBar } from './ui/StatusBar.tsx';
13
+ export { InputBox } from './ui/InputBox.tsx';
14
+ export { ChatView } from './ui/ChatView.tsx';
15
+ export { App } from './ui/App.tsx';
16
+
17
+ export { eventbus, EventBusEvents, type ContextUpdatedPayload, type MessagePayload, type ToolCallPayload, type DiffPayload, type AgentPayload } from './core/eventbus.ts';
18
+ export { loadConfig, saveConfig, getConfig, updateConfig, resetConfig, getConfigValue, setConfigValue, getApiKey, getModel, getBaseUrl, type DeeperConfig, type MCPConfigEntry, type SkillConfigEntry } from './core/config.ts';
19
+ export { DEEPER_VERSION, DEEPER_NAME, DEEPER_HOME, DEEPER_CONFIG_FILE, DEEPSEEK_DEFAULT_MODEL, DEEPSEEK_BASE_URL, TOOL_CATEGORIES, AGENT_MAX_SUB_AGENTS, CONTEXT_MAX_TOKENS, MCP_CONNECTION_TIMEOUT_MS } from './core/constants.ts';
20
+ export type { ToolCategory } from './core/constants.ts';
21
+ export { type JSONSchema, type ToolParameter, type ToolDefinition, type ToolResult, type ToolExecutor, type Tool, type ToolCall, type ToolCallResult, type ToolSafetyLevel, TOOL_SAFETY_MAP } from './tools/tool-types.ts';
22
+ export { type DeepSeekMessage, type DeepSeekToolCall, type DeepSeekToolDefinition, type DeepSeekRequest, type DeepSeekResponse, type DeepSeekStreamChunk, type ChatMessage, type ToolCallRecord, type AgentInfo, type SlashCommand, SLASH_COMMANDS } from './model/types.ts';
23
+
24
+ export { bootstrap, checkNodeVersion, getVersionInfo, type BootstrapResult } from './cli/bootstrap.ts';
25
+ export { chat } from './cli/commands/chat.tsx';
26
+ export { run } from './cli/commands/run.ts';
@@ -0,0 +1,74 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { existsSync } from 'node:fs';
3
+ import { DEEPER_MCP_FILE } from '../core/constants.js';
4
+ import type { MCPServerConfig } from './types.js';
5
+
6
+ export class ConfigLoader {
7
+ private configPath: string;
8
+
9
+ constructor(configPath?: string) {
10
+ this.configPath = configPath || DEEPER_MCP_FILE;
11
+ }
12
+
13
+ async load(): Promise<MCPServerConfig[]> {
14
+ if (!existsSync(this.configPath)) {
15
+ return [];
16
+ }
17
+
18
+ try {
19
+ const content = await readFile(this.configPath, 'utf-8');
20
+ const parsed = JSON.parse(content);
21
+
22
+ if (Array.isArray(parsed)) {
23
+ return this.validateConfigs(parsed);
24
+ }
25
+
26
+ if (parsed && parsed.mcpServers) {
27
+ return this.validateConfigs(parsed.mcpServers);
28
+ }
29
+
30
+ return [];
31
+ } catch {
32
+ return [];
33
+ }
34
+ }
35
+
36
+ async loadSingle(name: string): Promise<MCPServerConfig | null> {
37
+ const configs = await this.load();
38
+ return configs.find((c) => c.name === name) || null;
39
+ }
40
+
41
+ private validateConfigs(raw: unknown[]): MCPServerConfig[] {
42
+ const valid: MCPServerConfig[] = [];
43
+
44
+ for (const item of raw) {
45
+ if (!item || typeof item !== 'object') continue;
46
+
47
+ const obj = item as Record<string, unknown>;
48
+
49
+ if (!obj.name || typeof obj.name !== 'string') continue;
50
+ if (!obj.type || (obj.type !== 'stdio' && obj.type !== 'sse')) continue;
51
+
52
+ const config: MCPServerConfig = {
53
+ name: obj.name,
54
+ type: obj.type as 'stdio' | 'sse',
55
+ command: typeof obj.command === 'string' ? obj.command : undefined,
56
+ args: Array.isArray(obj.args) ? obj.args.map(String) : undefined,
57
+ url: typeof obj.url === 'string' ? obj.url : undefined,
58
+ headers: typeof obj.headers === 'object' && obj.headers
59
+ ? obj.headers as Record<string, string>
60
+ : undefined,
61
+ env: typeof obj.env === 'object' && obj.env
62
+ ? obj.env as Record<string, string>
63
+ : undefined,
64
+ };
65
+
66
+ if (config.type === 'stdio' && !config.command) continue;
67
+ if (config.type === 'sse' && !config.url) continue;
68
+
69
+ valid.push(config);
70
+ }
71
+
72
+ return valid;
73
+ }
74
+ }