@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.
- package/.env.example +49 -0
- package/LICENSE +21 -0
- package/README.md +360 -0
- package/dist/cli/init.js +387 -0
- package/dist/cli.js +184 -0
- package/dist/clients/telegram.js +148 -0
- package/dist/core/agent/factory.js +67 -0
- package/dist/core/agent/index.js +32 -0
- package/dist/core/agent/providers/claude-code.js +158 -0
- package/dist/core/agent/types.js +9 -0
- package/dist/core/approval.js +192 -0
- package/dist/core/executor.js +237 -0
- package/dist/core/logger.js +76 -0
- package/dist/core/platform.js +130 -0
- package/dist/gateway/gateway.js +435 -0
- package/dist/gateway/index.js +9 -0
- package/dist/gateway/security.js +35 -0
- package/dist/gateway/session.js +195 -0
- package/dist/gateway/types.js +8 -0
- package/dist/index.js +130 -0
- package/dist/mcp/server.js +156 -0
- package/dist/telegram/bot.js +333 -0
- package/install.sh +817 -0
- package/package.json +73 -0
- package/uninstall.sh +121 -0
|
@@ -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
|
+
}
|