@vibetasks/cli 0.1.0 → 0.3.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.
@@ -0,0 +1,161 @@
1
+ // src/utils/daemon-config.ts
2
+ import fs from "fs/promises";
3
+ import path from "path";
4
+ import os from "os";
5
+ var DEFAULT_DAEMON_CONFIG = {
6
+ enabled: true,
7
+ keyboard_shortcut: "Ctrl+Alt+E",
8
+ auto_start: false,
9
+ notification_duration: 5e3,
10
+ auto_create_task: false,
11
+ capture_clipboard: true,
12
+ capture_screen: false,
13
+ // Screen capture requires additional setup
14
+ error_patterns: [
15
+ "Error:",
16
+ "Exception:",
17
+ "TypeError:",
18
+ "ReferenceError:",
19
+ "SyntaxError:",
20
+ "FATAL:",
21
+ "FAILED:",
22
+ "error\\[",
23
+ "panic:",
24
+ "Traceback",
25
+ "at Object\\.",
26
+ "at Module\\.",
27
+ "at async",
28
+ "npm ERR!",
29
+ "yarn error",
30
+ "pnpm ERR!"
31
+ ]
32
+ };
33
+ var DaemonConfigManager = class {
34
+ configDir;
35
+ configPath;
36
+ pidFilePath;
37
+ constructor() {
38
+ const configHome = process.env.XDG_CONFIG_HOME || (process.platform === "win32" ? process.env.APPDATA || path.join(os.homedir(), "AppData", "Roaming") : path.join(os.homedir(), ".config"));
39
+ this.configDir = path.join(configHome, "taskflow");
40
+ this.configPath = path.join(this.configDir, "daemon.json");
41
+ this.pidFilePath = path.join(this.configDir, "daemon.pid");
42
+ }
43
+ /**
44
+ * Ensure the config directory exists
45
+ */
46
+ async ensureConfigDir() {
47
+ try {
48
+ await fs.mkdir(this.configDir, { recursive: true });
49
+ } catch (error) {
50
+ if (error.code !== "EEXIST") {
51
+ throw new Error(`Failed to create config directory: ${error.message}`);
52
+ }
53
+ }
54
+ }
55
+ /**
56
+ * Get daemon configuration
57
+ */
58
+ async getConfig() {
59
+ try {
60
+ const data = await fs.readFile(this.configPath, "utf-8");
61
+ const config = JSON.parse(data);
62
+ return { ...DEFAULT_DAEMON_CONFIG, ...config };
63
+ } catch (error) {
64
+ if (error.code === "ENOENT") {
65
+ return { ...DEFAULT_DAEMON_CONFIG };
66
+ }
67
+ throw new Error(`Failed to read daemon config: ${error.message}`);
68
+ }
69
+ }
70
+ /**
71
+ * Save daemon configuration
72
+ */
73
+ async saveConfig(config) {
74
+ await this.ensureConfigDir();
75
+ const currentConfig = await this.getConfig();
76
+ const newConfig = { ...currentConfig, ...config };
77
+ try {
78
+ await fs.writeFile(this.configPath, JSON.stringify(newConfig, null, 2), "utf-8");
79
+ } catch (error) {
80
+ throw new Error(`Failed to write daemon config: ${error.message}`);
81
+ }
82
+ }
83
+ /**
84
+ * Get PID file path
85
+ */
86
+ getPidFilePath() {
87
+ return this.pidFilePath;
88
+ }
89
+ /**
90
+ * Get config directory path
91
+ */
92
+ getConfigDir() {
93
+ return this.configDir;
94
+ }
95
+ /**
96
+ * Save daemon PID
97
+ */
98
+ async savePid(pid) {
99
+ await this.ensureConfigDir();
100
+ await fs.writeFile(this.pidFilePath, pid.toString(), "utf-8");
101
+ }
102
+ /**
103
+ * Get daemon PID
104
+ */
105
+ async getPid() {
106
+ try {
107
+ const data = await fs.readFile(this.pidFilePath, "utf-8");
108
+ return parseInt(data.trim(), 10);
109
+ } catch (error) {
110
+ if (error.code === "ENOENT") {
111
+ return null;
112
+ }
113
+ throw error;
114
+ }
115
+ }
116
+ /**
117
+ * Remove PID file
118
+ */
119
+ async removePid() {
120
+ try {
121
+ await fs.unlink(this.pidFilePath);
122
+ } catch (error) {
123
+ if (error.code !== "ENOENT") {
124
+ throw error;
125
+ }
126
+ }
127
+ }
128
+ /**
129
+ * Check if daemon is running
130
+ */
131
+ async isDaemonRunning() {
132
+ const pid = await this.getPid();
133
+ if (!pid) return false;
134
+ try {
135
+ process.kill(pid, 0);
136
+ return true;
137
+ } catch (error) {
138
+ await this.removePid();
139
+ return false;
140
+ }
141
+ }
142
+ /**
143
+ * Parse keyboard shortcut string to key combination
144
+ */
145
+ parseShortcut(shortcut) {
146
+ const parts = shortcut.toLowerCase().split("+").map((p) => p.trim());
147
+ return {
148
+ ctrl: parts.includes("ctrl") || parts.includes("control"),
149
+ alt: parts.includes("alt"),
150
+ shift: parts.includes("shift"),
151
+ key: parts.find((p) => !["ctrl", "control", "alt", "shift"].includes(p)) || ""
152
+ };
153
+ }
154
+ };
155
+ var daemonConfigManager = new DaemonConfigManager();
156
+
157
+ export {
158
+ DEFAULT_DAEMON_CONFIG,
159
+ DaemonConfigManager,
160
+ daemonConfigManager
161
+ };
@@ -0,0 +1,430 @@
1
+ // src/utils/clipboard-monitor.ts
2
+ var clipboardy = null;
3
+ async function getClipboardy() {
4
+ if (!clipboardy) {
5
+ clipboardy = await import("clipboardy");
6
+ }
7
+ return clipboardy;
8
+ }
9
+ var nodeJsPatterns = {
10
+ name: "Node.js Errors",
11
+ category: "nodejs",
12
+ patterns: [
13
+ /^(Error|TypeError|ReferenceError|SyntaxError|RangeError|EvalError|URIError):\s*.+/m,
14
+ /^\s+at\s+.+\(.+:\d+:\d+\)/m,
15
+ /^Uncaught\s+(Error|TypeError|ReferenceError):/m,
16
+ /^UnhandledPromiseRejectionWarning:/m,
17
+ /^node:internal\//m
18
+ ],
19
+ extractInfo: (text) => {
20
+ const errorMatch = text.match(
21
+ /^(Error|TypeError|ReferenceError|SyntaxError|RangeError|EvalError|URIError):\s*(.+)/m
22
+ );
23
+ if (!errorMatch) return null;
24
+ const stackMatch = text.match(/at\s+(?:.+\s+)?\((.+):(\d+):(\d+)\)/);
25
+ const file = stackMatch?.[1];
26
+ const line = stackMatch ? parseInt(stackMatch[2], 10) : void 0;
27
+ const column = stackMatch ? parseInt(stackMatch[3], 10) : void 0;
28
+ const stackLines = text.split("\n").filter((l) => l.trim().startsWith("at "));
29
+ const stack = stackLines.length > 0 ? stackLines.join("\n") : void 0;
30
+ return {
31
+ type: errorMatch[1],
32
+ category: "nodejs",
33
+ message: errorMatch[2].trim(),
34
+ stack,
35
+ file,
36
+ line,
37
+ column,
38
+ rawText: text
39
+ };
40
+ }
41
+ };
42
+ var npmPatterns = {
43
+ name: "npm Errors",
44
+ category: "npm",
45
+ patterns: [
46
+ /npm ERR!/,
47
+ /npm WARN/,
48
+ /ERESOLVE/,
49
+ /E404/,
50
+ /ENOENT/,
51
+ /EPERM/,
52
+ /EACCES/,
53
+ /peer dep missing/i,
54
+ /Could not resolve dependency/
55
+ ],
56
+ extractInfo: (text) => {
57
+ const codeMatch = text.match(/npm ERR! code\s+(\w+)/);
58
+ const code = codeMatch?.[1];
59
+ const summaryMatch = text.match(/npm ERR!\s+(.+)/);
60
+ const message = summaryMatch?.[1] || "npm error detected";
61
+ if (text.includes("ERESOLVE")) {
62
+ const conflictMatch = text.match(/Conflicting peer dependency:\s*(.+)/);
63
+ return {
64
+ type: "ERESOLVE",
65
+ category: "npm",
66
+ message: conflictMatch?.[1] || "Dependency resolution conflict",
67
+ code: "ERESOLVE",
68
+ suggestion: "Try: npm install --legacy-peer-deps or npm install --force",
69
+ rawText: text
70
+ };
71
+ }
72
+ if (text.includes("E404") || text.includes("404 Not Found")) {
73
+ const packageMatch = text.match(/Not Found.*?:\s*(.+)/);
74
+ return {
75
+ type: "E404",
76
+ category: "npm",
77
+ message: `Package not found: ${packageMatch?.[1] || "unknown"}`,
78
+ code: "E404",
79
+ suggestion: "Check package name spelling or registry configuration",
80
+ rawText: text
81
+ };
82
+ }
83
+ return {
84
+ type: "npm error",
85
+ category: "npm",
86
+ message,
87
+ code,
88
+ rawText: text
89
+ };
90
+ }
91
+ };
92
+ var expoPatterns = {
93
+ name: "Expo/React Native Errors",
94
+ category: "expo",
95
+ patterns: [
96
+ /Error:\s*Unable to resolve module/,
97
+ /Metro Bundler/i,
98
+ /BUNDLE\s+.*failed/i,
99
+ /Red Box/i,
100
+ /Invariant Violation/,
101
+ /Native module.+cannot be null/,
102
+ /Cannot read property.+of undefined/,
103
+ /expo-.*error/i,
104
+ /RCTFatalException/,
105
+ /ExceptionsManager/
106
+ ],
107
+ extractInfo: (text) => {
108
+ const moduleMatch = text.match(/Unable to resolve module\s+['"]?([^'"]+)['"]?/);
109
+ if (moduleMatch) {
110
+ return {
111
+ type: "ModuleResolutionError",
112
+ category: "expo",
113
+ message: `Cannot find module: ${moduleMatch[1]}`,
114
+ suggestion: `Try: npx expo install ${moduleMatch[1]}`,
115
+ rawText: text
116
+ };
117
+ }
118
+ const invariantMatch = text.match(/Invariant Violation:\s*(.+)/);
119
+ if (invariantMatch) {
120
+ return {
121
+ type: "InvariantViolation",
122
+ category: "expo",
123
+ message: invariantMatch[1].trim(),
124
+ rawText: text
125
+ };
126
+ }
127
+ const nativeMatch = text.match(/Native module\s+['"]?([^'"]+)['"]?\s+cannot be null/);
128
+ if (nativeMatch) {
129
+ return {
130
+ type: "NativeModuleError",
131
+ category: "expo",
132
+ message: `Native module missing: ${nativeMatch[1]}`,
133
+ suggestion: "Try: npx expo prebuild --clean && npx expo run:ios/android",
134
+ rawText: text
135
+ };
136
+ }
137
+ if (text.includes("BUNDLE") && text.includes("failed")) {
138
+ return {
139
+ type: "BundleError",
140
+ category: "expo",
141
+ message: "Metro bundler failed to build",
142
+ suggestion: "Try: npx expo start -c (clear cache)",
143
+ rawText: text
144
+ };
145
+ }
146
+ return {
147
+ type: "ExpoError",
148
+ category: "expo",
149
+ message: "Expo/React Native error detected",
150
+ rawText: text
151
+ };
152
+ }
153
+ };
154
+ var webpackPatterns = {
155
+ name: "Webpack/Build Errors",
156
+ category: "webpack",
157
+ patterns: [
158
+ /Module not found:\s*Error/,
159
+ /ModuleNotFoundError/,
160
+ /ERROR in\s+/,
161
+ /webpack.*error/i,
162
+ /Failed to compile/i,
163
+ /Module build failed/,
164
+ /Syntax error in/i,
165
+ /Can't resolve/,
166
+ /You may need an appropriate loader/
167
+ ],
168
+ extractInfo: (text) => {
169
+ const moduleMatch = text.match(/Can't resolve\s+['"]?([^'"]+)['"]?/);
170
+ if (moduleMatch) {
171
+ return {
172
+ type: "ModuleNotFound",
173
+ category: "webpack",
174
+ message: `Cannot resolve: ${moduleMatch[1]}`,
175
+ suggestion: `Try: npm install ${moduleMatch[1]}`,
176
+ rawText: text
177
+ };
178
+ }
179
+ const fileMatch = text.match(/ERROR in\s+(.+):(\d+):(\d+)/);
180
+ if (fileMatch) {
181
+ return {
182
+ type: "WebpackError",
183
+ category: "webpack",
184
+ message: "Build error",
185
+ file: fileMatch[1],
186
+ line: parseInt(fileMatch[2], 10),
187
+ column: parseInt(fileMatch[3], 10),
188
+ rawText: text
189
+ };
190
+ }
191
+ if (text.includes("appropriate loader")) {
192
+ const extensionMatch = text.match(/\.(\w+)(?:\?|$)/);
193
+ return {
194
+ type: "LoaderError",
195
+ category: "webpack",
196
+ message: `Missing loader for .${extensionMatch?.[1] || "unknown"} files`,
197
+ suggestion: "Check webpack.config.js for missing loaders",
198
+ rawText: text
199
+ };
200
+ }
201
+ return {
202
+ type: "WebpackError",
203
+ category: "webpack",
204
+ message: "Webpack build error detected",
205
+ rawText: text
206
+ };
207
+ }
208
+ };
209
+ var typescriptPatterns = {
210
+ name: "TypeScript Errors",
211
+ category: "typescript",
212
+ patterns: [
213
+ /TS\d+:/,
214
+ /error TS\d+/,
215
+ /Type '.+' is not assignable to type/,
216
+ /Property '.+' does not exist on type/,
217
+ /Cannot find module '.+' or its corresponding type declarations/,
218
+ /Argument of type '.+' is not assignable/,
219
+ /Object is possibly 'undefined'/,
220
+ /Object is possibly 'null'/
221
+ ],
222
+ extractInfo: (text) => {
223
+ const codeMatch = text.match(/TS(\d+)/);
224
+ const code = codeMatch ? `TS${codeMatch[1]}` : void 0;
225
+ const fileMatch = text.match(/(.+\.tsx?)\((\d+),(\d+)\)/);
226
+ const file = fileMatch?.[1];
227
+ const line = fileMatch ? parseInt(fileMatch[2], 10) : void 0;
228
+ const column = fileMatch ? parseInt(fileMatch[3], 10) : void 0;
229
+ const messageMatch = text.match(/error TS\d+:\s*(.+)/);
230
+ const message = messageMatch?.[1] || "TypeScript error detected";
231
+ return {
232
+ type: "TypeScriptError",
233
+ category: "typescript",
234
+ message,
235
+ code,
236
+ file,
237
+ line,
238
+ column,
239
+ rawText: text
240
+ };
241
+ }
242
+ };
243
+ var pythonPatterns = {
244
+ name: "Python Errors",
245
+ category: "python",
246
+ patterns: [
247
+ /Traceback \(most recent call last\)/,
248
+ /^\s+File ".+", line \d+/m,
249
+ /^(NameError|TypeError|ValueError|KeyError|AttributeError|ImportError|ModuleNotFoundError|SyntaxError|IndentationError|IndexError|ZeroDivisionError|FileNotFoundError):/m,
250
+ /raise\s+\w+Error/
251
+ ],
252
+ extractInfo: (text) => {
253
+ if (!text.includes("Traceback")) {
254
+ const errorMatch2 = text.match(
255
+ /^(NameError|TypeError|ValueError|KeyError|AttributeError|ImportError|ModuleNotFoundError|SyntaxError|IndentationError|IndexError|ZeroDivisionError|FileNotFoundError):\s*(.+)/m
256
+ );
257
+ if (errorMatch2) {
258
+ return {
259
+ type: errorMatch2[1],
260
+ category: "python",
261
+ message: errorMatch2[2].trim(),
262
+ rawText: text
263
+ };
264
+ }
265
+ return null;
266
+ }
267
+ const lines = text.split("\n").filter((l) => l.trim());
268
+ const lastLine = lines[lines.length - 1];
269
+ const errorMatch = lastLine.match(/^(\w+Error):\s*(.+)/);
270
+ const fileMatch = text.match(/File "(.+)", line (\d+)/);
271
+ const file = fileMatch?.[1];
272
+ const line = fileMatch ? parseInt(fileMatch[2], 10) : void 0;
273
+ const stackLines = text.split("\n").filter((l) => l.trim().startsWith("File "));
274
+ const stack = stackLines.join("\n");
275
+ return {
276
+ type: errorMatch?.[1] || "PythonError",
277
+ category: "python",
278
+ message: errorMatch?.[2] || "Python error detected",
279
+ stack,
280
+ file,
281
+ line,
282
+ rawText: text
283
+ };
284
+ }
285
+ };
286
+ var ALL_PATTERNS = [
287
+ nodeJsPatterns,
288
+ npmPatterns,
289
+ expoPatterns,
290
+ webpackPatterns,
291
+ typescriptPatterns,
292
+ pythonPatterns
293
+ ];
294
+ function detectError(text) {
295
+ if (!text || text.length < 10) return null;
296
+ for (const pattern of ALL_PATTERNS) {
297
+ const hasMatch = pattern.patterns.some((p) => p.test(text));
298
+ if (hasMatch) {
299
+ const info = pattern.extractInfo(text);
300
+ if (info) return info;
301
+ }
302
+ }
303
+ return null;
304
+ }
305
+ function getErrorSummary(error) {
306
+ const parts = [];
307
+ parts.push(`[${error.category.toUpperCase()}]`);
308
+ parts.push(error.type);
309
+ if (error.message.length > 80) {
310
+ parts.push(error.message.substring(0, 77) + "...");
311
+ } else {
312
+ parts.push(error.message);
313
+ }
314
+ if (error.file) {
315
+ const shortFile = error.file.split(/[/\\]/).slice(-2).join("/");
316
+ parts.push(`@ ${shortFile}`);
317
+ if (error.line) {
318
+ parts[parts.length - 1] += `:${error.line}`;
319
+ }
320
+ }
321
+ return parts.join(" ");
322
+ }
323
+ function formatErrorForNotes(error) {
324
+ const lines = [];
325
+ lines.push(`## Error Details`);
326
+ lines.push("");
327
+ lines.push(`**Type:** ${error.type}`);
328
+ lines.push(`**Category:** ${error.category}`);
329
+ lines.push(`**Message:** ${error.message}`);
330
+ if (error.code) {
331
+ lines.push(`**Code:** ${error.code}`);
332
+ }
333
+ if (error.file) {
334
+ lines.push(`**File:** \`${error.file}\``);
335
+ if (error.line) {
336
+ lines.push(`**Line:** ${error.line}${error.column ? `:${error.column}` : ""}`);
337
+ }
338
+ }
339
+ if (error.suggestion) {
340
+ lines.push("");
341
+ lines.push(`### Suggestion`);
342
+ lines.push(error.suggestion);
343
+ }
344
+ if (error.stack) {
345
+ lines.push("");
346
+ lines.push(`### Stack Trace`);
347
+ lines.push("```");
348
+ lines.push(error.stack);
349
+ lines.push("```");
350
+ }
351
+ lines.push("");
352
+ lines.push(`### Raw Error`);
353
+ lines.push("```");
354
+ const rawLines = error.rawText.split("\n");
355
+ if (rawLines.length > 30) {
356
+ lines.push(rawLines.slice(0, 30).join("\n"));
357
+ lines.push(`... (${rawLines.length - 30} more lines)`);
358
+ } else {
359
+ lines.push(error.rawText);
360
+ }
361
+ lines.push("```");
362
+ return lines.join("\n");
363
+ }
364
+ function createClipboardMonitor(options) {
365
+ const interval = options.interval || 1e3;
366
+ const minLength = options.minLength || 20;
367
+ let running = false;
368
+ let lastClipboardContent = "";
369
+ let intervalId = null;
370
+ const checkClipboard = async () => {
371
+ try {
372
+ const clipboard = await getClipboardy();
373
+ const content = await clipboard.default.read();
374
+ if (content === lastClipboardContent || content.length < minLength) {
375
+ return;
376
+ }
377
+ lastClipboardContent = content;
378
+ const error = detectError(content);
379
+ if (error) {
380
+ options.onError(error);
381
+ }
382
+ } catch {
383
+ }
384
+ };
385
+ return {
386
+ start: async () => {
387
+ if (running) return;
388
+ await getClipboardy();
389
+ try {
390
+ const clipboard = await getClipboardy();
391
+ lastClipboardContent = await clipboard.default.read();
392
+ } catch {
393
+ lastClipboardContent = "";
394
+ }
395
+ running = true;
396
+ options.onStart?.();
397
+ intervalId = setInterval(checkClipboard, interval);
398
+ },
399
+ stop: () => {
400
+ if (!running) return;
401
+ running = false;
402
+ if (intervalId) {
403
+ clearInterval(intervalId);
404
+ intervalId = null;
405
+ }
406
+ options.onStop?.();
407
+ },
408
+ isRunning: () => running
409
+ };
410
+ }
411
+ async function readClipboard() {
412
+ const clipboard = await getClipboardy();
413
+ return clipboard.default.read();
414
+ }
415
+ async function checkClipboardForError() {
416
+ try {
417
+ const content = await readClipboard();
418
+ return detectError(content);
419
+ } catch {
420
+ return null;
421
+ }
422
+ }
423
+
424
+ export {
425
+ detectError,
426
+ getErrorSummary,
427
+ formatErrorForNotes,
428
+ createClipboardMonitor,
429
+ checkClipboardForError
430
+ };
@@ -0,0 +1,10 @@
1
+ import {
2
+ DEFAULT_DAEMON_CONFIG,
3
+ DaemonConfigManager,
4
+ daemonConfigManager
5
+ } from "./chunk-2KRLRG4G.js";
6
+ export {
7
+ DEFAULT_DAEMON_CONFIG,
8
+ DaemonConfigManager,
9
+ daemonConfigManager
10
+ };