@sarkar-ai/deskmate 0.2.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,237 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.Executor = void 0;
37
+ const child_process_1 = require("child_process");
38
+ const util_1 = require("util");
39
+ const fs = __importStar(require("fs/promises"));
40
+ const path = __importStar(require("path"));
41
+ const os = __importStar(require("os"));
42
+ const logger_1 = require("./logger");
43
+ const approval_1 = require("./approval");
44
+ const platform_1 = require("./platform");
45
+ const log = (0, logger_1.createLogger)("Executor");
46
+ const execAsync = (0, util_1.promisify)(child_process_1.exec);
47
+ // Screenshot directory
48
+ const SCREENSHOT_DIR = path.join(os.tmpdir(), "deskmate-screenshots");
49
+ class Executor {
50
+ workingDir;
51
+ constructor(workingDir) {
52
+ this.workingDir = workingDir || process.env.WORKING_DIR || process.env.HOME || "/";
53
+ }
54
+ async executeCommand(command, cwd) {
55
+ const workingDir = cwd || this.workingDir;
56
+ log.info("Executing command", { command, workingDir });
57
+ log.debug("Command details", { shell: process.platform === "win32" ? "powershell.exe" : "/bin/zsh" });
58
+ try {
59
+ const startTime = Date.now();
60
+ const { stdout, stderr } = await execAsync(command, {
61
+ cwd: workingDir,
62
+ timeout: 120000, // 2 minute timeout
63
+ maxBuffer: 1024 * 1024 * 10, // 10MB buffer
64
+ shell: process.platform === "win32" ? "powershell.exe" : "/bin/zsh",
65
+ env: { ...process.env, PATH: process.env.PATH },
66
+ });
67
+ const duration = Date.now() - startTime;
68
+ const output = (stdout || stderr).trim();
69
+ log.info("Command completed successfully", { command, exitCode: 0, durationMs: duration });
70
+ log.debug("Command output", { output: output.slice(0, 500), outputLength: output.length });
71
+ return {
72
+ success: true,
73
+ output: output || "(command completed with no output)",
74
+ exitCode: 0,
75
+ };
76
+ }
77
+ catch (error) {
78
+ log.error("Command failed", {
79
+ command,
80
+ exitCode: error.code ?? 1,
81
+ error: error.message,
82
+ });
83
+ log.debug("Command error details", { stderr: error.stderr, stdout: error.stdout });
84
+ return {
85
+ success: false,
86
+ output: error.stderr || error.stdout || error.message,
87
+ exitCode: error.code ?? 1,
88
+ };
89
+ }
90
+ }
91
+ async readFile(filePath) {
92
+ const resolvedPath = path.isAbsolute(filePath)
93
+ ? filePath
94
+ : path.join(this.workingDir, filePath);
95
+ log.debug("Reading file", { filePath, resolvedPath });
96
+ // Check if folder access approval is needed
97
+ const approved = await approval_1.approvalManager.requestFolderAccess(resolvedPath);
98
+ if (!approved) {
99
+ throw new Error(`Access to ${resolvedPath} was not approved`);
100
+ }
101
+ const content = await fs.readFile(resolvedPath, "utf-8");
102
+ log.info("File read successfully", { filePath: resolvedPath, size: content.length });
103
+ return content;
104
+ }
105
+ async writeFile(filePath, content) {
106
+ const resolvedPath = path.isAbsolute(filePath)
107
+ ? filePath
108
+ : path.join(this.workingDir, filePath);
109
+ log.debug("Writing file", { filePath, resolvedPath, contentLength: content.length });
110
+ // Check if folder access approval is needed
111
+ const approved = await approval_1.approvalManager.requestFolderAccess(resolvedPath);
112
+ if (!approved) {
113
+ throw new Error(`Access to ${resolvedPath} was not approved`);
114
+ }
115
+ await fs.mkdir(path.dirname(resolvedPath), { recursive: true });
116
+ await fs.writeFile(resolvedPath, content, "utf-8");
117
+ log.info("File written successfully", { filePath: resolvedPath, size: content.length });
118
+ }
119
+ async listDirectory(dirPath) {
120
+ const resolvedPath = dirPath
121
+ ? path.isAbsolute(dirPath)
122
+ ? dirPath
123
+ : path.join(this.workingDir, dirPath)
124
+ : this.workingDir;
125
+ log.debug("Listing directory", { dirPath, resolvedPath });
126
+ // Check if folder access approval is needed
127
+ const approved = await approval_1.approvalManager.requestFolderAccess(resolvedPath);
128
+ if (!approved) {
129
+ throw new Error(`Access to ${resolvedPath} was not approved`);
130
+ }
131
+ const entries = await fs.readdir(resolvedPath, { withFileTypes: true });
132
+ const files = [];
133
+ for (const entry of entries) {
134
+ const fullPath = path.join(resolvedPath, entry.name);
135
+ try {
136
+ const stats = await fs.stat(fullPath);
137
+ files.push({
138
+ name: entry.name,
139
+ path: fullPath,
140
+ isDirectory: entry.isDirectory(),
141
+ size: stats.size,
142
+ modified: stats.mtime,
143
+ });
144
+ }
145
+ catch {
146
+ // Skip files we can't stat
147
+ }
148
+ }
149
+ log.info("Directory listed", { path: resolvedPath, itemCount: files.length });
150
+ return files;
151
+ }
152
+ async getSystemInfo() {
153
+ const info = {
154
+ platform: process.platform,
155
+ arch: process.arch,
156
+ nodeVersion: process.version,
157
+ workingDir: this.workingDir,
158
+ homeDir: process.env.HOME || "",
159
+ user: process.env.USER || "",
160
+ };
161
+ // Get additional system info
162
+ try {
163
+ const { stdout: hostname } = await execAsync("hostname");
164
+ info.hostname = hostname.trim();
165
+ }
166
+ catch { }
167
+ try {
168
+ const { stdout: uptime } = await execAsync("uptime");
169
+ info.uptime = uptime.trim();
170
+ }
171
+ catch { }
172
+ return info;
173
+ }
174
+ getWorkingDir() {
175
+ return this.workingDir;
176
+ }
177
+ setWorkingDir(dir) {
178
+ this.workingDir = dir;
179
+ }
180
+ async takeScreenshot() {
181
+ try {
182
+ // Ensure screenshot directory exists
183
+ await fs.mkdir(SCREENSHOT_DIR, { recursive: true });
184
+ const filename = `screenshot-${Date.now()}.png`;
185
+ const filepath = path.join(SCREENSHOT_DIR, filename);
186
+ log.info("Taking screenshot", { filepath });
187
+ await execAsync((0, platform_1.getScreenshotCommand)(filepath), {
188
+ timeout: 10000,
189
+ });
190
+ // Verify file was created
191
+ await fs.access(filepath);
192
+ log.info("Screenshot saved", { filepath });
193
+ return filepath;
194
+ }
195
+ catch (error) {
196
+ log.error("Screenshot failed", { error: error.message });
197
+ return null;
198
+ }
199
+ }
200
+ async getRecentScreenshots(since) {
201
+ try {
202
+ await fs.mkdir(SCREENSHOT_DIR, { recursive: true });
203
+ const files = await fs.readdir(SCREENSHOT_DIR);
204
+ const screenshots = [];
205
+ for (const file of files) {
206
+ if (!file.endsWith(".png"))
207
+ continue;
208
+ const filepath = path.join(SCREENSHOT_DIR, file);
209
+ const stats = await fs.stat(filepath);
210
+ if (stats.mtime >= since) {
211
+ screenshots.push(filepath);
212
+ }
213
+ }
214
+ return screenshots.sort();
215
+ }
216
+ catch {
217
+ return [];
218
+ }
219
+ }
220
+ async cleanupScreenshots() {
221
+ try {
222
+ const files = await fs.readdir(SCREENSHOT_DIR);
223
+ for (const file of files) {
224
+ if (file.endsWith(".png")) {
225
+ await fs.unlink(path.join(SCREENSHOT_DIR, file)).catch(() => { });
226
+ }
227
+ }
228
+ }
229
+ catch {
230
+ // Ignore cleanup errors
231
+ }
232
+ }
233
+ getScreenshotDir() {
234
+ return SCREENSHOT_DIR;
235
+ }
236
+ }
237
+ exports.Executor = Executor;
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createStderrLogger = exports.createLogger = exports.logger = void 0;
4
+ const LOG_LEVELS = {
5
+ debug: 0,
6
+ info: 1,
7
+ warn: 2,
8
+ error: 3,
9
+ silent: 4,
10
+ };
11
+ class Logger {
12
+ level;
13
+ context;
14
+ useStderr;
15
+ constructor(options) {
16
+ if (typeof options === "string") {
17
+ this.context = options;
18
+ this.useStderr = false;
19
+ }
20
+ else {
21
+ this.context = options?.context;
22
+ this.useStderr = options?.useStderr ?? false;
23
+ }
24
+ this.level = process.env.LOG_LEVEL?.toLowerCase() || "info";
25
+ }
26
+ shouldLog(level) {
27
+ return LOG_LEVELS[level] >= LOG_LEVELS[this.level];
28
+ }
29
+ formatMessage(level, message, data) {
30
+ const timestamp = new Date().toISOString();
31
+ const ctx = this.context ? `[${this.context}]` : "";
32
+ const dataStr = data ? ` ${JSON.stringify(data)}` : "";
33
+ return `${timestamp} ${level.toUpperCase().padEnd(5)} ${ctx} ${message}${dataStr}`;
34
+ }
35
+ output(method, message) {
36
+ if (this.useStderr) {
37
+ console.error(message);
38
+ }
39
+ else {
40
+ console[method](message);
41
+ }
42
+ }
43
+ debug(message, data) {
44
+ if (this.shouldLog("debug")) {
45
+ this.output("log", this.formatMessage("debug", message, data));
46
+ }
47
+ }
48
+ info(message, data) {
49
+ if (this.shouldLog("info")) {
50
+ this.output("log", this.formatMessage("info", message, data));
51
+ }
52
+ }
53
+ warn(message, data) {
54
+ if (this.shouldLog("warn")) {
55
+ this.output("warn", this.formatMessage("warn", message, data));
56
+ }
57
+ }
58
+ error(message, data) {
59
+ if (this.shouldLog("error")) {
60
+ this.output("error", this.formatMessage("error", message, data));
61
+ }
62
+ }
63
+ child(context) {
64
+ const childLogger = new Logger({
65
+ context: this.context ? `${this.context}:${context}` : context,
66
+ useStderr: this.useStderr,
67
+ });
68
+ childLogger.level = this.level;
69
+ return childLogger;
70
+ }
71
+ }
72
+ exports.logger = new Logger();
73
+ const createLogger = (context) => new Logger(context);
74
+ exports.createLogger = createLogger;
75
+ const createStderrLogger = (context) => new Logger({ context, useStderr: true });
76
+ exports.createStderrLogger = createStderrLogger;
@@ -0,0 +1,130 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.IS_WINDOWS = exports.IS_LINUX = exports.IS_MACOS = void 0;
37
+ exports.getScreenshotCommand = getScreenshotCommand;
38
+ exports.getProtectedFolderPatterns = getProtectedFolderPatterns;
39
+ exports.extractBaseFolder = extractBaseFolder;
40
+ exports.getScreenshotHint = getScreenshotHint;
41
+ const os = __importStar(require("os"));
42
+ const path = __importStar(require("path"));
43
+ exports.IS_MACOS = process.platform === "darwin";
44
+ exports.IS_LINUX = process.platform === "linux";
45
+ exports.IS_WINDOWS = process.platform === "win32";
46
+ /**
47
+ * Returns the platform-appropriate command to take a screenshot.
48
+ */
49
+ function getScreenshotCommand(filepath) {
50
+ if (exports.IS_MACOS)
51
+ return `screencapture -x "${filepath}"`;
52
+ if (exports.IS_LINUX)
53
+ return `import -window root "${filepath}"`;
54
+ if (exports.IS_WINDOWS)
55
+ return `powershell -c "Add-Type -AssemblyName System.Windows.Forms; [System.Windows.Forms.Screen]::PrimaryScreen | ForEach-Object { $bmp = New-Object System.Drawing.Bitmap($_.Bounds.Width, $_.Bounds.Height); $g = [System.Drawing.Graphics]::FromImage($bmp); $g.CopyFromScreen($_.Bounds.Location, [System.Drawing.Point]::Empty, $_.Bounds.Size); $bmp.Save('${filepath.replace(/'/g, "''")}') }"`;
56
+ return `echo "Screenshots not supported on ${process.platform}"`;
57
+ }
58
+ /**
59
+ * Returns regex patterns matching protected user folders for the current OS.
60
+ */
61
+ function getProtectedFolderPatterns() {
62
+ const home = os.homedir().replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
63
+ if (exports.IS_MACOS) {
64
+ return [
65
+ new RegExp(`^${home}/Desktop`),
66
+ new RegExp(`^${home}/Documents`),
67
+ new RegExp(`^${home}/Downloads`),
68
+ new RegExp(`^${home}/Pictures`),
69
+ new RegExp(`^${home}/Movies`),
70
+ new RegExp(`^${home}/Music`),
71
+ new RegExp(`^${home}/Library/Mobile Documents`),
72
+ ];
73
+ }
74
+ if (exports.IS_LINUX) {
75
+ return [
76
+ new RegExp(`^${home}/Desktop`),
77
+ new RegExp(`^${home}/Documents`),
78
+ new RegExp(`^${home}/Downloads`),
79
+ new RegExp(`^${home}/Pictures`),
80
+ new RegExp(`^${home}/Videos`),
81
+ new RegExp(`^${home}/Music`),
82
+ ];
83
+ }
84
+ // Windows
85
+ const winHome = home.replace(/\\/g, "[\\\\/]");
86
+ return [
87
+ new RegExp(`^${winHome}[\\\\/]Desktop`, "i"),
88
+ new RegExp(`^${winHome}[\\\\/]Documents`, "i"),
89
+ new RegExp(`^${winHome}[\\\\/]Downloads`, "i"),
90
+ new RegExp(`^${winHome}[\\\\/]Pictures`, "i"),
91
+ new RegExp(`^${winHome}[\\\\/]Videos`, "i"),
92
+ new RegExp(`^${winHome}[\\\\/]Music`, "i"),
93
+ ];
94
+ }
95
+ /**
96
+ * Extracts the base protected folder from a file path (e.g. /home/user/Desktop).
97
+ * Returns null if the path is not inside a protected folder.
98
+ */
99
+ function extractBaseFolder(filePath) {
100
+ const home = os.homedir();
101
+ const folders = exports.IS_MACOS
102
+ ? [
103
+ "Desktop",
104
+ "Documents",
105
+ "Downloads",
106
+ "Pictures",
107
+ "Movies",
108
+ "Music",
109
+ "Library/Mobile Documents",
110
+ ]
111
+ : ["Desktop", "Documents", "Downloads", "Pictures", "Videos", "Music"];
112
+ for (const folder of folders) {
113
+ const prefix = path.join(home, folder);
114
+ if (filePath.startsWith(prefix))
115
+ return prefix;
116
+ }
117
+ return null;
118
+ }
119
+ /**
120
+ * Returns a shell snippet for the system prompt that shows how to take a screenshot.
121
+ */
122
+ function getScreenshotHint(screenshotDir) {
123
+ if (exports.IS_MACOS) {
124
+ return `mkdir -p ${screenshotDir} && screencapture -x ${screenshotDir}/screenshot-$(date +%s).png && echo "Screenshot saved"`;
125
+ }
126
+ if (exports.IS_LINUX) {
127
+ return `mkdir -p ${screenshotDir} && import -window root ${screenshotDir}/screenshot-$(date +%s).png && echo "Screenshot saved"`;
128
+ }
129
+ return `echo "Use the /screenshot command instead"`;
130
+ }