@serjm/deepseek-code 0.3.1

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 (216) hide show
  1. package/CONTRIBUTING.md +73 -0
  2. package/README.md +194 -0
  3. package/README.ru.md +194 -0
  4. package/dist/api/index.d.ts +77 -0
  5. package/dist/api/index.d.ts.map +1 -0
  6. package/dist/api/index.js +263 -0
  7. package/dist/api/index.js.map +1 -0
  8. package/dist/cli/headless.d.ts +22 -0
  9. package/dist/cli/headless.d.ts.map +1 -0
  10. package/dist/cli/headless.js +122 -0
  11. package/dist/cli/headless.js.map +1 -0
  12. package/dist/cli/index.d.ts +3 -0
  13. package/dist/cli/index.d.ts.map +1 -0
  14. package/dist/cli/index.js +90 -0
  15. package/dist/cli/index.js.map +1 -0
  16. package/dist/cli/interactive.d.ts +18 -0
  17. package/dist/cli/interactive.d.ts.map +1 -0
  18. package/dist/cli/interactive.js +75 -0
  19. package/dist/cli/interactive.js.map +1 -0
  20. package/dist/commands/index.d.ts +30 -0
  21. package/dist/commands/index.d.ts.map +1 -0
  22. package/dist/commands/index.js +964 -0
  23. package/dist/commands/index.js.map +1 -0
  24. package/dist/config/defaults.d.ts +37 -0
  25. package/dist/config/defaults.d.ts.map +1 -0
  26. package/dist/config/defaults.js +39 -0
  27. package/dist/config/defaults.js.map +1 -0
  28. package/dist/config/loader.d.ts +4 -0
  29. package/dist/config/loader.d.ts.map +1 -0
  30. package/dist/config/loader.js +76 -0
  31. package/dist/config/loader.js.map +1 -0
  32. package/dist/core/agent-loop.d.ts +111 -0
  33. package/dist/core/agent-loop.d.ts.map +1 -0
  34. package/dist/core/agent-loop.js +485 -0
  35. package/dist/core/agent-loop.js.map +1 -0
  36. package/dist/core/checkpoint.d.ts +10 -0
  37. package/dist/core/checkpoint.d.ts.map +1 -0
  38. package/dist/core/checkpoint.js +83 -0
  39. package/dist/core/checkpoint.js.map +1 -0
  40. package/dist/core/extensions.d.ts +55 -0
  41. package/dist/core/extensions.d.ts.map +1 -0
  42. package/dist/core/extensions.js +113 -0
  43. package/dist/core/extensions.js.map +1 -0
  44. package/dist/core/git.d.ts +68 -0
  45. package/dist/core/git.d.ts.map +1 -0
  46. package/dist/core/git.js +148 -0
  47. package/dist/core/git.js.map +1 -0
  48. package/dist/core/hooks.d.ts +37 -0
  49. package/dist/core/hooks.d.ts.map +1 -0
  50. package/dist/core/hooks.js +77 -0
  51. package/dist/core/hooks.js.map +1 -0
  52. package/dist/core/i18n.d.ts +90 -0
  53. package/dist/core/i18n.d.ts.map +1 -0
  54. package/dist/core/i18n.js +253 -0
  55. package/dist/core/i18n.js.map +1 -0
  56. package/dist/core/lsp.d.ts +74 -0
  57. package/dist/core/lsp.d.ts.map +1 -0
  58. package/dist/core/lsp.js +239 -0
  59. package/dist/core/lsp.js.map +1 -0
  60. package/dist/core/mcp.d.ts +49 -0
  61. package/dist/core/mcp.d.ts.map +1 -0
  62. package/dist/core/mcp.js +195 -0
  63. package/dist/core/mcp.js.map +1 -0
  64. package/dist/core/memory.d.ts +38 -0
  65. package/dist/core/memory.d.ts.map +1 -0
  66. package/dist/core/memory.js +231 -0
  67. package/dist/core/memory.js.map +1 -0
  68. package/dist/core/metrics.d.ts +36 -0
  69. package/dist/core/metrics.d.ts.map +1 -0
  70. package/dist/core/metrics.js +111 -0
  71. package/dist/core/metrics.js.map +1 -0
  72. package/dist/core/review.d.ts +27 -0
  73. package/dist/core/review.d.ts.map +1 -0
  74. package/dist/core/review.js +201 -0
  75. package/dist/core/review.js.map +1 -0
  76. package/dist/core/sandbox.d.ts +52 -0
  77. package/dist/core/sandbox.d.ts.map +1 -0
  78. package/dist/core/sandbox.js +140 -0
  79. package/dist/core/sandbox.js.map +1 -0
  80. package/dist/core/scheduler.d.ts +56 -0
  81. package/dist/core/scheduler.d.ts.map +1 -0
  82. package/dist/core/scheduler.js +167 -0
  83. package/dist/core/scheduler.js.map +1 -0
  84. package/dist/core/session.d.ts +49 -0
  85. package/dist/core/session.d.ts.map +1 -0
  86. package/dist/core/session.js +127 -0
  87. package/dist/core/session.js.map +1 -0
  88. package/dist/core/skills.d.ts +36 -0
  89. package/dist/core/skills.d.ts.map +1 -0
  90. package/dist/core/skills.js +90 -0
  91. package/dist/core/skills.js.map +1 -0
  92. package/dist/core/subagent.d.ts +45 -0
  93. package/dist/core/subagent.d.ts.map +1 -0
  94. package/dist/core/subagent.js +130 -0
  95. package/dist/core/subagent.js.map +1 -0
  96. package/dist/core/themes.d.ts +35 -0
  97. package/dist/core/themes.d.ts.map +1 -0
  98. package/dist/core/themes.js +188 -0
  99. package/dist/core/themes.js.map +1 -0
  100. package/dist/tools/bash.d.ts +3 -0
  101. package/dist/tools/bash.d.ts.map +1 -0
  102. package/dist/tools/bash.js +92 -0
  103. package/dist/tools/bash.js.map +1 -0
  104. package/dist/tools/chrome-manager.d.ts +35 -0
  105. package/dist/tools/chrome-manager.d.ts.map +1 -0
  106. package/dist/tools/chrome-manager.js +163 -0
  107. package/dist/tools/chrome-manager.js.map +1 -0
  108. package/dist/tools/chrome.d.ts +78 -0
  109. package/dist/tools/chrome.d.ts.map +1 -0
  110. package/dist/tools/chrome.js +1058 -0
  111. package/dist/tools/chrome.js.map +1 -0
  112. package/dist/tools/edit.d.ts +3 -0
  113. package/dist/tools/edit.d.ts.map +1 -0
  114. package/dist/tools/edit.js +81 -0
  115. package/dist/tools/edit.js.map +1 -0
  116. package/dist/tools/glob.d.ts +3 -0
  117. package/dist/tools/glob.d.ts.map +1 -0
  118. package/dist/tools/glob.js +41 -0
  119. package/dist/tools/glob.js.map +1 -0
  120. package/dist/tools/grep.d.ts +3 -0
  121. package/dist/tools/grep.d.ts.map +1 -0
  122. package/dist/tools/grep.js +74 -0
  123. package/dist/tools/grep.js.map +1 -0
  124. package/dist/tools/path-safety.d.ts +3 -0
  125. package/dist/tools/path-safety.d.ts.map +1 -0
  126. package/dist/tools/path-safety.js +19 -0
  127. package/dist/tools/path-safety.js.map +1 -0
  128. package/dist/tools/read.d.ts +3 -0
  129. package/dist/tools/read.d.ts.map +1 -0
  130. package/dist/tools/read.js +58 -0
  131. package/dist/tools/read.js.map +1 -0
  132. package/dist/tools/registry.d.ts +4 -0
  133. package/dist/tools/registry.d.ts.map +1 -0
  134. package/dist/tools/registry.js +43 -0
  135. package/dist/tools/registry.js.map +1 -0
  136. package/dist/tools/types.d.ts +47 -0
  137. package/dist/tools/types.d.ts.map +1 -0
  138. package/dist/tools/types.js +90 -0
  139. package/dist/tools/types.js.map +1 -0
  140. package/dist/tools/write.d.ts +3 -0
  141. package/dist/tools/write.d.ts.map +1 -0
  142. package/dist/tools/write.js +51 -0
  143. package/dist/tools/write.js.map +1 -0
  144. package/dist/ui/activity-cards.d.ts +50 -0
  145. package/dist/ui/activity-cards.d.ts.map +1 -0
  146. package/dist/ui/activity-cards.js +185 -0
  147. package/dist/ui/activity-cards.js.map +1 -0
  148. package/dist/ui/app.d.ts +9 -0
  149. package/dist/ui/app.d.ts.map +1 -0
  150. package/dist/ui/app.js +852 -0
  151. package/dist/ui/app.js.map +1 -0
  152. package/dist/ui/chat-view.d.ts +10 -0
  153. package/dist/ui/chat-view.d.ts.map +1 -0
  154. package/dist/ui/chat-view.js +94 -0
  155. package/dist/ui/chat-view.js.map +1 -0
  156. package/dist/ui/error-boundary.d.ts +13 -0
  157. package/dist/ui/error-boundary.d.ts.map +1 -0
  158. package/dist/ui/error-boundary.js +16 -0
  159. package/dist/ui/error-boundary.js.map +1 -0
  160. package/dist/ui/fade-in.d.ts +8 -0
  161. package/dist/ui/fade-in.d.ts.map +1 -0
  162. package/dist/ui/fade-in.js +14 -0
  163. package/dist/ui/fade-in.js.map +1 -0
  164. package/dist/ui/input-bar.d.ts +16 -0
  165. package/dist/ui/input-bar.d.ts.map +1 -0
  166. package/dist/ui/input-bar.js +269 -0
  167. package/dist/ui/input-bar.js.map +1 -0
  168. package/dist/ui/markdown-view.d.ts +9 -0
  169. package/dist/ui/markdown-view.d.ts.map +1 -0
  170. package/dist/ui/markdown-view.js +240 -0
  171. package/dist/ui/markdown-view.js.map +1 -0
  172. package/dist/ui/matrix-rain.d.ts +2 -0
  173. package/dist/ui/matrix-rain.d.ts.map +1 -0
  174. package/dist/ui/matrix-rain.js +134 -0
  175. package/dist/ui/matrix-rain.js.map +1 -0
  176. package/dist/ui/reasoning-view.d.ts +12 -0
  177. package/dist/ui/reasoning-view.d.ts.map +1 -0
  178. package/dist/ui/reasoning-view.js +34 -0
  179. package/dist/ui/reasoning-view.js.map +1 -0
  180. package/dist/ui/results-panel.d.ts +11 -0
  181. package/dist/ui/results-panel.d.ts.map +1 -0
  182. package/dist/ui/results-panel.js +17 -0
  183. package/dist/ui/results-panel.js.map +1 -0
  184. package/dist/ui/setup-wizard.d.ts +30 -0
  185. package/dist/ui/setup-wizard.d.ts.map +1 -0
  186. package/dist/ui/setup-wizard.js +166 -0
  187. package/dist/ui/setup-wizard.js.map +1 -0
  188. package/dist/ui/status-bar.d.ts +14 -0
  189. package/dist/ui/status-bar.d.ts.map +1 -0
  190. package/dist/ui/status-bar.js +63 -0
  191. package/dist/ui/status-bar.js.map +1 -0
  192. package/dist/ui/tool-activity-card.d.ts +9 -0
  193. package/dist/ui/tool-activity-card.d.ts.map +1 -0
  194. package/dist/ui/tool-activity-card.js +172 -0
  195. package/dist/ui/tool-activity-card.js.map +1 -0
  196. package/dist/ui/tool-call-view.d.ts +9 -0
  197. package/dist/ui/tool-call-view.d.ts.map +1 -0
  198. package/dist/ui/tool-call-view.js +149 -0
  199. package/dist/ui/tool-call-view.js.map +1 -0
  200. package/dist/utils/clipboard.d.ts +6 -0
  201. package/dist/utils/clipboard.d.ts.map +1 -0
  202. package/dist/utils/clipboard.js +56 -0
  203. package/dist/utils/clipboard.js.map +1 -0
  204. package/dist/utils/ignore.d.ts +6 -0
  205. package/dist/utils/ignore.d.ts.map +1 -0
  206. package/dist/utils/ignore.js +40 -0
  207. package/dist/utils/ignore.js.map +1 -0
  208. package/dist/utils/logger.d.ts +4 -0
  209. package/dist/utils/logger.d.ts.map +1 -0
  210. package/dist/utils/logger.js +13 -0
  211. package/dist/utils/logger.js.map +1 -0
  212. package/dist/utils/string-width.d.ts +6 -0
  213. package/dist/utils/string-width.d.ts.map +1 -0
  214. package/dist/utils/string-width.js +37 -0
  215. package/dist/utils/string-width.js.map +1 -0
  216. package/package.json +68 -0
@@ -0,0 +1,27 @@
1
+ import type { DeepSeekConfig } from '../config/defaults.js';
2
+ export interface ReviewOptions {
3
+ files?: string[];
4
+ gitRef?: string;
5
+ runLinters?: boolean;
6
+ autoFix?: boolean;
7
+ prNumber?: number;
8
+ prUrl?: string;
9
+ }
10
+ export interface ReviewIssue {
11
+ file: string;
12
+ line: number;
13
+ severity: 'critical' | 'major' | 'minor' | 'info';
14
+ category: 'correctness' | 'security' | 'quality' | 'performance';
15
+ message: string;
16
+ suggestion?: string;
17
+ }
18
+ export interface ReviewResult {
19
+ issues: ReviewIssue[];
20
+ summary: string;
21
+ score: number;
22
+ linterOutput?: string;
23
+ durationMs: number;
24
+ }
25
+ export declare function reviewCode(config: DeepSeekConfig, options: ReviewOptions): Promise<ReviewResult>;
26
+ export declare function formatReviewReport(result: ReviewResult): string;
27
+ //# sourceMappingURL=review.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review.d.ts","sourceRoot":"","sources":["../../src/core/review.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAE3D,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,UAAU,GAAG,OAAO,GAAG,OAAO,GAAG,MAAM,CAAC;IAClD,QAAQ,EAAE,aAAa,GAAG,UAAU,GAAG,SAAS,GAAG,aAAa,CAAC;IACjE,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;CACpB;AAcD,wBAAsB,UAAU,CAC9B,MAAM,EAAE,cAAc,EACtB,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,YAAY,CAAC,CA2FvB;AAED,wBAAgB,kBAAkB,CAAE,MAAM,EAAE,YAAY,GAAG,MAAM,CAWhE"}
@@ -0,0 +1,201 @@
1
+ import { execSync } from 'node:child_process';
2
+ import { readFile } from 'node:fs/promises';
3
+ import { join } from 'node:path';
4
+ import { DeepSeekAPI } from '../api/index.js';
5
+ const LINTER_COMMANDS = {
6
+ ts: 'npx tsc --noEmit 2>&1 || true',
7
+ eslint: 'npx eslint . --format compact 2>&1 || true',
8
+ };
9
+ const severityWeight = {
10
+ critical: 0,
11
+ major: 1,
12
+ minor: 2,
13
+ info: 3,
14
+ };
15
+ export async function reviewCode(config, options) {
16
+ const startTime = Date.now();
17
+ const api = new DeepSeekAPI(config);
18
+ let linterOutput = '';
19
+ const filesToReview = await determineScope(options);
20
+ if (filesToReview.length === 0) {
21
+ return {
22
+ issues: [],
23
+ summary: 'No files to review.',
24
+ score: 100,
25
+ durationMs: Date.now() - startTime,
26
+ };
27
+ }
28
+ if (options.runLinters !== false) {
29
+ linterOutput = await runLinters(filesToReview);
30
+ }
31
+ const fileContents = [];
32
+ for (const file of filesToReview.slice(0, 10)) {
33
+ try {
34
+ const content = await readFile(file, 'utf-8');
35
+ fileContents.push(`=== ${file} ===\n${content.slice(0, 5000)}`);
36
+ }
37
+ catch {
38
+ // Skip unreadable files.
39
+ }
40
+ }
41
+ const reviewPrompt = `Review the following code for issues. Focus on:
42
+ 1. Correctness
43
+ 2. Security
44
+ 3. Quality
45
+ 4. Performance
46
+
47
+ Return strict JSON only:
48
+ {
49
+ "issues": [
50
+ {
51
+ "file": "path",
52
+ "line": 1,
53
+ "severity": "critical|major|minor|info",
54
+ "category": "correctness|security|quality|performance",
55
+ "message": "short finding",
56
+ "suggestion": "optional fix"
57
+ }
58
+ ],
59
+ "summary": "overall assessment",
60
+ "score": 0
61
+ }
62
+
63
+ Files:
64
+ ${fileContents.join('\n\n')}
65
+
66
+ ${linterOutput ? `\nLinter output:\n${linterOutput}` : ''}`;
67
+ let issues = [];
68
+ let summary = `Reviewed ${filesToReview.length} file(s).`;
69
+ let score = 100;
70
+ try {
71
+ const response = await api.chat([
72
+ { role: 'system', content: 'You are a code review expert. Return strict JSON only.' },
73
+ { role: 'user', content: reviewPrompt },
74
+ ]);
75
+ const parsed = parseReviewResponse(response.content);
76
+ if (parsed) {
77
+ issues = normalizeIssues(parsed.issues ?? []);
78
+ summary = parsed.summary ?? summary;
79
+ if (typeof parsed.score === 'number') {
80
+ score = clampScore(parsed.score);
81
+ }
82
+ }
83
+ }
84
+ catch {
85
+ // Keep deterministic fallback summary below.
86
+ }
87
+ if (issues.length === 0) {
88
+ score = Math.max(score, linterOutput.trim() ? 90 : 100);
89
+ }
90
+ else if (score === 100) {
91
+ score = Math.max(0, 100 - issues.length * 5);
92
+ }
93
+ return {
94
+ issues,
95
+ summary,
96
+ score,
97
+ linterOutput,
98
+ durationMs: Date.now() - startTime,
99
+ };
100
+ }
101
+ export function formatReviewReport(result) {
102
+ if (result.issues.length === 0) {
103
+ return `**Findings**\n\nNo issues found.\n\n**Summary**\n\nScore: **${result.score}/100**\nDuration: ${(result.durationMs / 1000).toFixed(1)}s\n\n${result.summary}`;
104
+ }
105
+ const findings = result.issues.slice(0, 20).map(issue => {
106
+ const suggestion = issue.suggestion ? `\n Suggestion: ${issue.suggestion}` : '';
107
+ return `- [${issue.severity.toUpperCase()}] ${issue.file}:${issue.line} (${issue.category}) — ${issue.message}${suggestion}`;
108
+ }).join('\n');
109
+ return `**Findings**\n\n${findings}\n\n**Summary**\n\nScore: **${result.score}/100**\nIssues: ${result.issues.length}\nDuration: ${(result.durationMs / 1000).toFixed(1)}s\n\n${result.summary}`;
110
+ }
111
+ async function determineScope(options) {
112
+ if (options.files && options.files.length > 0) {
113
+ return options.files.map(file => file.startsWith(process.cwd()) ? file : join(process.cwd(), file));
114
+ }
115
+ if (options.prUrl) {
116
+ return [];
117
+ }
118
+ try {
119
+ const ref = options.gitRef ?? 'HEAD';
120
+ const output = execSync(`git diff --name-only ${ref}`, {
121
+ encoding: 'utf-8',
122
+ windowsHide: true,
123
+ });
124
+ return output.split('\n').filter(Boolean).map(file => join(process.cwd(), file));
125
+ }
126
+ catch {
127
+ return [];
128
+ }
129
+ }
130
+ async function runLinters(files) {
131
+ const output = [];
132
+ const hasTsFiles = files.some(file => file.endsWith('.ts') || file.endsWith('.tsx'));
133
+ if (hasTsFiles) {
134
+ try {
135
+ const result = execSync(LINTER_COMMANDS.ts, {
136
+ encoding: 'utf-8',
137
+ timeout: 60000,
138
+ windowsHide: true,
139
+ });
140
+ if (result.trim())
141
+ output.push(`[tsc]\n${result}`);
142
+ }
143
+ catch {
144
+ // Ignore linter process failures, capture only output.
145
+ }
146
+ try {
147
+ const result = execSync(LINTER_COMMANDS.eslint, {
148
+ encoding: 'utf-8',
149
+ timeout: 60000,
150
+ windowsHide: true,
151
+ });
152
+ if (result.trim())
153
+ output.push(`[eslint]\n${result}`);
154
+ }
155
+ catch {
156
+ // Ignore linter process failures, capture only output.
157
+ }
158
+ }
159
+ return output.join('\n\n');
160
+ }
161
+ function parseReviewResponse(content) {
162
+ const fencedMatch = content.match(/```json\n([\s\S]*?)\n```/);
163
+ const raw = fencedMatch?.[1] ?? content.trim();
164
+ try {
165
+ return JSON.parse(raw);
166
+ }
167
+ catch {
168
+ return null;
169
+ }
170
+ }
171
+ function normalizeIssues(issues) {
172
+ const normalized = [];
173
+ for (const issue of issues) {
174
+ if (!issue || typeof issue !== 'object')
175
+ continue;
176
+ const candidate = issue;
177
+ if (!candidate.file || !candidate.message)
178
+ continue;
179
+ normalized.push({
180
+ file: candidate.file,
181
+ line: typeof candidate.line === 'number' ? candidate.line : 1,
182
+ severity: isSeverity(candidate.severity) ? candidate.severity : 'minor',
183
+ category: isCategory(candidate.category) ? candidate.category : 'quality',
184
+ message: candidate.message,
185
+ suggestion: candidate.suggestion,
186
+ });
187
+ }
188
+ return normalized.sort((a, b) => severityWeight[a.severity] - severityWeight[b.severity] ||
189
+ a.file.localeCompare(b.file) ||
190
+ a.line - b.line);
191
+ }
192
+ function isSeverity(value) {
193
+ return value === 'critical' || value === 'major' || value === 'minor' || value === 'info';
194
+ }
195
+ function isCategory(value) {
196
+ return value === 'correctness' || value === 'security' || value === 'quality' || value === 'performance';
197
+ }
198
+ function clampScore(score) {
199
+ return Math.max(0, Math.min(100, Math.round(score)));
200
+ }
201
+ //# sourceMappingURL=review.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review.js","sourceRoot":"","sources":["../../src/core/review.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ export interface SandboxOptions {
2
+ /** Docker image to use */
3
+ image?: string;
4
+ /** Timeout in ms */
5
+ timeout?: number;
6
+ /** Network access: none, isolated, full */
7
+ network?: 'none' | 'isolated' | 'full';
8
+ /** Mount current project directory */
9
+ mountProject?: boolean;
10
+ /** Additional directories to mount */
11
+ mounts?: Array<{
12
+ host: string;
13
+ container: string;
14
+ }>;
15
+ /** Environment variables */
16
+ env?: Record<string, string>;
17
+ }
18
+ export interface SandboxResult {
19
+ stdout: string;
20
+ stderr: string;
21
+ exitCode: number;
22
+ durationMs: number;
23
+ }
24
+ /**
25
+ * Sandbox for isolated command execution using Docker.
26
+ * Falls back to direct execution if Docker is not available.
27
+ */
28
+ export declare class Sandbox {
29
+ private dockerAvailable;
30
+ /**
31
+ * Check if sandbox is supported on the current platform.
32
+ * On Windows, sandbox requires Docker/WSL which may not be available.
33
+ */
34
+ isSupported(): boolean;
35
+ /**
36
+ * Check if Docker-based sandbox (with isolation) is available.
37
+ */
38
+ isDockerAvailable(): Promise<boolean>;
39
+ /**
40
+ * Get a human-readable reason why sandbox might be limited on this platform.
41
+ */
42
+ getCapabilityInfo(): {
43
+ supported: boolean;
44
+ reason?: string;
45
+ action?: string;
46
+ };
47
+ execute(command: string, options?: SandboxOptions): Promise<SandboxResult>;
48
+ private executeInDocker;
49
+ private executeDirect;
50
+ }
51
+ export declare const sandbox: Sandbox;
52
+ //# sourceMappingURL=sandbox.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sandbox.d.ts","sourceRoot":"","sources":["../../src/core/sandbox.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,cAAc;IAC7B,0BAA0B;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oBAAoB;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,2CAA2C;IAC3C,OAAO,CAAC,EAAE,MAAM,GAAG,UAAU,GAAG,MAAM,CAAC;IACvC,sCAAsC;IACtC,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,sCAAsC;IACtC,MAAM,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACpD,4BAA4B;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAID;;;GAGG;AACH,qBAAa,OAAO;IAClB,OAAO,CAAC,eAAe,CAAuB;IAE9C;;;OAGG;IACH,WAAW,IAAK,OAAO;IAMvB;;OAEG;IACG,iBAAiB,IAAK,OAAO,CAAC,OAAO,CAAC;IAa5C;;OAEG;IACH,iBAAiB,IAAK;QAAE,SAAS,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE;IAYxE,OAAO,CAAE,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,aAAa,CAAC;YAWvE,eAAe;YAwDf,aAAa;CA2B5B;AAGD,eAAO,MAAM,OAAO,SAAgB,CAAA"}
@@ -0,0 +1,140 @@
1
+ import { execSync } from 'node:child_process';
2
+ import { randomUUID } from 'node:crypto';
3
+ import { sep } from 'node:path';
4
+ import { platform } from 'node:os';
5
+ /** Convert Windows backslash paths to forward-slash paths for Docker mount syntax */
6
+ function toDockerPath(p) {
7
+ return p.split(sep).join('/');
8
+ }
9
+ const DEFAULT_IMAGE = 'node:20-alpine';
10
+ /**
11
+ * Sandbox for isolated command execution using Docker.
12
+ * Falls back to direct execution if Docker is not available.
13
+ */
14
+ export class Sandbox {
15
+ dockerAvailable = null;
16
+ /**
17
+ * Check if sandbox is supported on the current platform.
18
+ * On Windows, sandbox requires Docker/WSL which may not be available.
19
+ */
20
+ isSupported() {
21
+ // Direct execution fallback works on all platforms,
22
+ // but Docker-based isolation is only meaningful with Docker/WSL.
23
+ return true; // direct execution always works
24
+ }
25
+ /**
26
+ * Check if Docker-based sandbox (with isolation) is available.
27
+ */
28
+ async isDockerAvailable() {
29
+ if (this.dockerAvailable !== null)
30
+ return this.dockerAvailable;
31
+ try {
32
+ execSync('docker --version', { encoding: 'utf-8', stdio: 'pipe', windowsHide: true });
33
+ this.dockerAvailable = true;
34
+ }
35
+ catch {
36
+ this.dockerAvailable = false;
37
+ }
38
+ return this.dockerAvailable;
39
+ }
40
+ /**
41
+ * Get a human-readable reason why sandbox might be limited on this platform.
42
+ */
43
+ getCapabilityInfo() {
44
+ const os = platform();
45
+ if (os === 'win32') {
46
+ return {
47
+ supported: false,
48
+ reason: 'current sandbox implementation requires Docker/WSL/Linux runtime',
49
+ action: 'use WSL/Podman or disable sandbox command',
50
+ };
51
+ }
52
+ return { supported: true };
53
+ }
54
+ async execute(command, options = {}) {
55
+ const startTime = Date.now();
56
+ if (await this.isDockerAvailable()) {
57
+ return this.executeInDocker(command, options, startTime);
58
+ }
59
+ // Fallback: direct execution
60
+ return this.executeDirect(command, options, startTime);
61
+ }
62
+ async executeInDocker(command, options, startTime) {
63
+ const containerName = `dsc-sandbox-${randomUUID().slice(0, 8)}`;
64
+ const image = options.image ?? DEFAULT_IMAGE;
65
+ const timeout = options.timeout ?? 120000;
66
+ const dockerArgs = [
67
+ 'run',
68
+ '--rm',
69
+ '--name', containerName,
70
+ '--network', options.network === 'full' ? 'bridge' : 'none',
71
+ '-w', '/workspace',
72
+ ];
73
+ if (options.mountProject !== false) {
74
+ dockerArgs.push('-v', `${toDockerPath(process.cwd())}:/workspace`);
75
+ }
76
+ if (options.mounts) {
77
+ for (const m of options.mounts) {
78
+ dockerArgs.push('-v', `${toDockerPath(m.host)}:${m.container}`);
79
+ }
80
+ }
81
+ if (options.env) {
82
+ for (const [key, value] of Object.entries(options.env)) {
83
+ dockerArgs.push('-e', `${key}=${value}`);
84
+ }
85
+ }
86
+ dockerArgs.push(image, 'sh', '-c', command);
87
+ try {
88
+ const output = execSync(dockerArgs.join(' '), {
89
+ encoding: 'utf-8',
90
+ timeout,
91
+ windowsHide: true,
92
+ stdio: 'pipe',
93
+ });
94
+ return {
95
+ stdout: output,
96
+ stderr: '',
97
+ exitCode: 0,
98
+ durationMs: Date.now() - startTime,
99
+ };
100
+ }
101
+ catch (err) {
102
+ const error = err;
103
+ return {
104
+ stdout: error.stdout ?? '',
105
+ stderr: error.stderr ?? error.message,
106
+ exitCode: error.status ?? 1,
107
+ durationMs: Date.now() - startTime,
108
+ };
109
+ }
110
+ }
111
+ async executeDirect(command, options, startTime) {
112
+ const timeout = options.timeout ?? 120000;
113
+ try {
114
+ const output = execSync(command, {
115
+ encoding: 'utf-8',
116
+ timeout,
117
+ windowsHide: true,
118
+ maxBuffer: 10 * 1024 * 1024,
119
+ });
120
+ return {
121
+ stdout: output,
122
+ stderr: '',
123
+ exitCode: 0,
124
+ durationMs: Date.now() - startTime,
125
+ };
126
+ }
127
+ catch (err) {
128
+ const error = err;
129
+ return {
130
+ stdout: error.stdout ?? '',
131
+ stderr: error.stderr ?? error.message,
132
+ exitCode: error.status ?? 1,
133
+ durationMs: Date.now() - startTime,
134
+ };
135
+ }
136
+ }
137
+ }
138
+ // Singleton
139
+ export const sandbox = new Sandbox();
140
+ //# sourceMappingURL=sandbox.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sandbox.js","sourceRoot":"","sources":["../../src/core/sandbox.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ import { EventEmitter } from 'node:events';
2
+ export interface ScheduledTask {
3
+ id: string;
4
+ prompt: string;
5
+ interval: number;
6
+ lastRun: number;
7
+ nextRun: number;
8
+ runCount: number;
9
+ maxRuns?: number;
10
+ createdAt: number;
11
+ }
12
+ export type TaskCallback = (prompt: string) => Promise<void>;
13
+ /**
14
+ * Simple in-memory scheduler for recurring tasks (/loop command).
15
+ * Tasks run within the CLI session and are lost on exit.
16
+ */
17
+ export declare class Scheduler extends EventEmitter {
18
+ private tasks;
19
+ private timers;
20
+ private callback;
21
+ setCallback(cb: TaskCallback): void;
22
+ /**
23
+ * Add a recurring task
24
+ */
25
+ addTask(prompt: string, intervalMs: number, maxRuns?: number): ScheduledTask;
26
+ /**
27
+ * Parse interval string (e.g., "5m", "1h", "30s") to milliseconds
28
+ */
29
+ static parseInterval(str: string): number;
30
+ /**
31
+ * Remove a task
32
+ */
33
+ removeTask(id: string): boolean;
34
+ /**
35
+ * List all active tasks
36
+ */
37
+ listTasks(): ScheduledTask[];
38
+ /**
39
+ * Clear all tasks
40
+ */
41
+ clearAll(): void;
42
+ /**
43
+ * Get task count
44
+ */
45
+ get count(): number;
46
+ /**
47
+ * Save tasks to disk for persistence across restarts.
48
+ */
49
+ save(): Promise<void>;
50
+ /**
51
+ * Load tasks from disk and re-activate them.
52
+ */
53
+ load(callback?: TaskCallback): Promise<void>;
54
+ }
55
+ export declare const scheduler: Scheduler;
56
+ //# sourceMappingURL=scheduler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scheduler.d.ts","sourceRoot":"","sources":["../../src/core/scheduler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAM1C,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,YAAY,GAAG,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;AAM5D;;;GAGG;AACH,qBAAa,SAAU,SAAQ,YAAY;IACzC,OAAO,CAAC,KAAK,CAAwC;IACrD,OAAO,CAAC,MAAM,CAAyD;IACvE,OAAO,CAAC,QAAQ,CAA4B;IAE5C,WAAW,CAAE,EAAE,EAAE,YAAY,GAAG,IAAI;IAIpC;;OAEG;IACH,OAAO,CAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,aAAa;IA8C7E;;OAEG;IACH,MAAM,CAAC,aAAa,CAAE,GAAG,EAAE,MAAM,GAAG,MAAM;IAgB1C;;OAEG;IACH,UAAU,CAAE,EAAE,EAAE,MAAM,GAAG,OAAO;IAWhC;;OAEG;IACH,SAAS,IAAK,aAAa,EAAE;IAK7B;;OAEG;IACH,QAAQ,IAAK,IAAI;IASjB;;OAEG;IACH,IAAI,KAAK,IAAK,MAAM,CAEnB;IAED;;OAEG;IACG,IAAI,IAAK,OAAO,CAAC,IAAI,CAAC;IAY5B;;OAEG;IACG,IAAI,CAAE,QAAQ,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;CAiCpD;AAGD,eAAO,MAAM,SAAS,WAAkB,CAAA"}
@@ -0,0 +1,167 @@
1
+ import { EventEmitter } from 'node:events';
2
+ import { readFile, writeFile, mkdir } from 'node:fs/promises';
3
+ import { existsSync } from 'node:fs';
4
+ import { homedir } from 'node:os';
5
+ import { join } from 'node:path';
6
+ function getSchedulerFile() {
7
+ return join(homedir(), '.deepseek-code', 'scheduler-tasks.json');
8
+ }
9
+ /**
10
+ * Simple in-memory scheduler for recurring tasks (/loop command).
11
+ * Tasks run within the CLI session and are lost on exit.
12
+ */
13
+ export class Scheduler extends EventEmitter {
14
+ tasks = new Map();
15
+ timers = new Map();
16
+ callback = null;
17
+ setCallback(cb) {
18
+ this.callback = cb;
19
+ }
20
+ /**
21
+ * Add a recurring task
22
+ */
23
+ addTask(prompt, intervalMs, maxRuns) {
24
+ const id = `task_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
25
+ const now = Date.now();
26
+ const task = {
27
+ id,
28
+ prompt,
29
+ interval: intervalMs,
30
+ lastRun: 0,
31
+ nextRun: now + intervalMs,
32
+ runCount: 0,
33
+ maxRuns,
34
+ createdAt: now,
35
+ };
36
+ this.tasks.set(id, task);
37
+ const timer = setInterval(async () => {
38
+ const current = this.tasks.get(id);
39
+ if (!current) {
40
+ clearInterval(timer);
41
+ return;
42
+ }
43
+ // Check max runs
44
+ if (current.maxRuns && current.runCount >= current.maxRuns) {
45
+ this.removeTask(id);
46
+ return;
47
+ }
48
+ current.lastRun = Date.now();
49
+ current.nextRun = current.lastRun + current.interval;
50
+ current.runCount++;
51
+ this.emit('taskRun', current);
52
+ if (this.callback) {
53
+ await this.callback(current.prompt);
54
+ }
55
+ }, intervalMs);
56
+ this.timers.set(id, timer);
57
+ return task;
58
+ }
59
+ /**
60
+ * Parse interval string (e.g., "5m", "1h", "30s") to milliseconds
61
+ */
62
+ static parseInterval(str) {
63
+ const match = str.match(/^(\d+)\s*(s|m|h|min)?$/);
64
+ if (!match)
65
+ return 10 * 60 * 1000; // default 10m
66
+ const value = parseInt(match[1], 10);
67
+ const unit = match[2] ?? 'm';
68
+ switch (unit) {
69
+ case 's': return value * 1000;
70
+ case 'm':
71
+ case 'min': return value * 60 * 1000;
72
+ case 'h': return value * 3600 * 1000;
73
+ default: return value * 60 * 1000;
74
+ }
75
+ }
76
+ /**
77
+ * Remove a task
78
+ */
79
+ removeTask(id) {
80
+ const timer = this.timers.get(id);
81
+ if (timer) {
82
+ clearInterval(timer);
83
+ this.timers.delete(id);
84
+ }
85
+ const removed = this.tasks.delete(id);
86
+ if (removed)
87
+ this.save().catch(() => { });
88
+ return removed;
89
+ }
90
+ /**
91
+ * List all active tasks
92
+ */
93
+ listTasks() {
94
+ return Array.from(this.tasks.values())
95
+ .sort((a, b) => a.nextRun - b.nextRun);
96
+ }
97
+ /**
98
+ * Clear all tasks
99
+ */
100
+ clearAll() {
101
+ for (const [id, timer] of this.timers) {
102
+ clearInterval(timer);
103
+ this.timers.delete(id);
104
+ }
105
+ this.tasks.clear();
106
+ this.save().catch(() => { });
107
+ }
108
+ /**
109
+ * Get task count
110
+ */
111
+ get count() {
112
+ return this.tasks.size;
113
+ }
114
+ /**
115
+ * Save tasks to disk for persistence across restarts.
116
+ */
117
+ async save() {
118
+ const dir = join(homedir(), '.deepseek-code');
119
+ if (!existsSync(dir)) {
120
+ await mkdir(dir, { recursive: true });
121
+ }
122
+ const tasks = Array.from(this.tasks.values()).map(t => ({
123
+ ...t,
124
+ // Don't save timer references
125
+ }));
126
+ await writeFile(getSchedulerFile(), JSON.stringify(tasks, null, 2), 'utf-8');
127
+ }
128
+ /**
129
+ * Load tasks from disk and re-activate them.
130
+ */
131
+ async load(callback) {
132
+ if (callback)
133
+ this.setCallback(callback);
134
+ const schedulerFile = getSchedulerFile();
135
+ if (!existsSync(schedulerFile))
136
+ return;
137
+ try {
138
+ const content = await readFile(schedulerFile, 'utf-8');
139
+ const tasks = JSON.parse(content);
140
+ for (const task of tasks) {
141
+ // Re-activate tasks that haven't expired
142
+ if (task.maxRuns && task.runCount >= task.maxRuns)
143
+ continue;
144
+ // Calculate remaining interval
145
+ const now = Date.now();
146
+ const elapsed = now - task.lastRun;
147
+ const remaining = Math.max(0, task.interval - elapsed);
148
+ if (remaining > 0) {
149
+ // Re-schedule with remaining time
150
+ setTimeout(() => {
151
+ this.addTask(task.prompt, task.interval, task.maxRuns);
152
+ }, remaining);
153
+ }
154
+ else {
155
+ // Already past due, schedule immediately
156
+ this.addTask(task.prompt, task.interval, task.maxRuns);
157
+ }
158
+ }
159
+ }
160
+ catch {
161
+ // Ignore load errors
162
+ }
163
+ }
164
+ }
165
+ // Singleton
166
+ export const scheduler = new Scheduler();
167
+ //# sourceMappingURL=scheduler.js.map