@questionbase/deskfree 0.5.0 → 0.5.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.
- package/dist/bin.js +353 -293
- package/dist/bin.js.map +1 -1
- package/dist/cli/install.d.ts +1 -1
- package/dist/cli/install.js +75 -52
- package/dist/cli/install.js.map +1 -1
- package/dist/cli/uninstall.d.ts +1 -1
- package/dist/cli/uninstall.js +53 -28
- package/dist/cli/uninstall.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +65 -47
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import { spawn, execSync, execFileSync, execFile } from 'child_process';
|
|
4
|
-
import { mkdirSync, writeFileSync, chmodSync, existsSync, unlinkSync, appendFileSync, readdirSync, readFileSync, statSync, createWriteStream } from 'fs';
|
|
5
3
|
import { homedir } from 'os';
|
|
6
4
|
import { dirname, join, extname } from 'path';
|
|
5
|
+
import { spawn, execSync, execFileSync, execFile } from 'child_process';
|
|
6
|
+
import { mkdirSync, writeFileSync, chmodSync, existsSync, unlinkSync, appendFileSync, readdirSync, readFileSync, statSync, createWriteStream } from 'fs';
|
|
7
7
|
import { createRequire as createRequire$1 } from 'module';
|
|
8
8
|
import { query, createSdkMcpServer, tool } from '@anthropic-ai/claude-agent-sdk';
|
|
9
9
|
import { z } from 'zod';
|
|
@@ -33,8 +33,8 @@ var __commonJS = (cb, mod) => function __require3() {
|
|
|
33
33
|
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
34
34
|
};
|
|
35
35
|
var __export = (target, all) => {
|
|
36
|
-
for (var
|
|
37
|
-
__defProp(target,
|
|
36
|
+
for (var name2 in all)
|
|
37
|
+
__defProp(target, name2, { get: all[name2], enumerable: true });
|
|
38
38
|
};
|
|
39
39
|
var __copyProps = (to, from, except, desc) => {
|
|
40
40
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
@@ -52,25 +52,66 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
52
52
|
__defProp(target, "default", { value: mod, enumerable: true }) ,
|
|
53
53
|
mod
|
|
54
54
|
));
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
61
|
-
function getMacPaths() {
|
|
55
|
+
function getPlistLabel(name2) {
|
|
56
|
+
return `com.deskfree.agent.${name2}`;
|
|
57
|
+
}
|
|
58
|
+
function getServiceName(name2) {
|
|
59
|
+
return `deskfree-agent-${name2}`;
|
|
60
|
+
}
|
|
61
|
+
function getMacPaths(name2) {
|
|
62
62
|
const home = homedir();
|
|
63
|
-
const deskfreeDir = join(home, ".deskfree");
|
|
63
|
+
const deskfreeDir = join(home, ".deskfree", name2);
|
|
64
|
+
const plistLabel = getPlistLabel(name2);
|
|
64
65
|
return {
|
|
65
66
|
deskfreeDir,
|
|
66
67
|
envFile: join(deskfreeDir, ".env"),
|
|
67
68
|
launcher: join(deskfreeDir, "launcher.sh"),
|
|
68
69
|
logDir: join(deskfreeDir, "logs"),
|
|
69
|
-
plist: join(home, "Library", "LaunchAgents", `${
|
|
70
|
+
plist: join(home, "Library", "LaunchAgents", `${plistLabel}.plist`)
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
function getLinuxPaths(name2) {
|
|
74
|
+
const serviceName = getServiceName(name2);
|
|
75
|
+
return {
|
|
76
|
+
serviceName,
|
|
77
|
+
serviceFile: `/etc/systemd/system/${serviceName}.service`,
|
|
78
|
+
envFile: `/etc/${serviceName}.env`,
|
|
79
|
+
stateDir: `/var/lib/${serviceName}`,
|
|
80
|
+
logDir: `/var/log/${serviceName}`
|
|
70
81
|
};
|
|
71
82
|
}
|
|
72
|
-
function
|
|
73
|
-
const
|
|
83
|
+
function parseName(args) {
|
|
84
|
+
const idx = args.indexOf("--name");
|
|
85
|
+
if (idx === -1) return [DEFAULT_NAME, args];
|
|
86
|
+
const name2 = args[idx + 1];
|
|
87
|
+
if (!name2 || name2.startsWith("-")) {
|
|
88
|
+
console.error("Error: --name requires a value (e.g. --name kasper)");
|
|
89
|
+
process.exit(1);
|
|
90
|
+
}
|
|
91
|
+
if (!/^[a-z0-9-]+$/i.test(name2)) {
|
|
92
|
+
console.error(
|
|
93
|
+
"Error: --name must contain only letters, numbers, and hyphens"
|
|
94
|
+
);
|
|
95
|
+
process.exit(1);
|
|
96
|
+
}
|
|
97
|
+
const remaining = [...args.slice(0, idx), ...args.slice(idx + 2)];
|
|
98
|
+
return [name2, remaining];
|
|
99
|
+
}
|
|
100
|
+
var DEFAULT_NAME;
|
|
101
|
+
var init_paths = __esm({
|
|
102
|
+
"src/cli/paths.ts"() {
|
|
103
|
+
DEFAULT_NAME = "main";
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// src/cli/install.ts
|
|
108
|
+
var install_exports = {};
|
|
109
|
+
__export(install_exports, {
|
|
110
|
+
install: () => install
|
|
111
|
+
});
|
|
112
|
+
function installMac(token, name2) {
|
|
113
|
+
const paths = getMacPaths(name2);
|
|
114
|
+
const plistLabel = getPlistLabel(name2);
|
|
74
115
|
let nodeBinDir;
|
|
75
116
|
try {
|
|
76
117
|
const nodePath = execSync("which node", { encoding: "utf8" }).trim();
|
|
@@ -82,8 +123,13 @@ function installMac(token) {
|
|
|
82
123
|
mkdirSync(paths.deskfreeDir, { recursive: true });
|
|
83
124
|
mkdirSync(paths.logDir, { recursive: true });
|
|
84
125
|
mkdirSync(dirname(paths.plist), { recursive: true });
|
|
85
|
-
writeFileSync(
|
|
86
|
-
|
|
126
|
+
writeFileSync(
|
|
127
|
+
paths.envFile,
|
|
128
|
+
`DESKFREE_LAUNCH=${token}
|
|
129
|
+
DESKFREE_INSTANCE_NAME=${name2}
|
|
130
|
+
`,
|
|
131
|
+
{ mode: 384 }
|
|
132
|
+
);
|
|
87
133
|
chmodSync(paths.envFile, 384);
|
|
88
134
|
console.log(`Wrote ${paths.envFile}`);
|
|
89
135
|
const launcher = `#!/bin/bash
|
|
@@ -109,7 +155,7 @@ exec deskfree-agent start
|
|
|
109
155
|
<plist version="1.0">
|
|
110
156
|
<dict>
|
|
111
157
|
<key>Label</key>
|
|
112
|
-
<string>${
|
|
158
|
+
<string>${plistLabel}</string>
|
|
113
159
|
<key>ProgramArguments</key>
|
|
114
160
|
<array>
|
|
115
161
|
<string>${paths.launcher}</string>
|
|
@@ -137,15 +183,18 @@ exec deskfree-agent start
|
|
|
137
183
|
}
|
|
138
184
|
execSync(`launchctl bootstrap gui/$(id -u) ${paths.plist}`);
|
|
139
185
|
console.log(`
|
|
140
|
-
Service ${
|
|
141
|
-
console.log(`Check status: launchctl print gui/$(id -u)/${
|
|
186
|
+
Service ${plistLabel} installed and started.`);
|
|
187
|
+
console.log(`Check status: launchctl print gui/$(id -u)/${plistLabel}`);
|
|
142
188
|
console.log(`Logs: tail -f ${join(paths.logDir, "stdout.log")}`);
|
|
143
189
|
}
|
|
144
|
-
function installLinux(token) {
|
|
190
|
+
function installLinux(token, name2) {
|
|
145
191
|
if (process.getuid?.() !== 0) {
|
|
146
192
|
console.error("Error: install must be run as root (use sudo)");
|
|
147
193
|
process.exit(1);
|
|
148
194
|
}
|
|
195
|
+
const paths = getLinuxPaths(name2);
|
|
196
|
+
const serviceName = getServiceName(name2);
|
|
197
|
+
const systemUser = serviceName;
|
|
149
198
|
let npmPath;
|
|
150
199
|
let nodeBinDir;
|
|
151
200
|
try {
|
|
@@ -156,80 +205,78 @@ function installLinux(token) {
|
|
|
156
205
|
process.exit(1);
|
|
157
206
|
}
|
|
158
207
|
try {
|
|
159
|
-
execSync(
|
|
208
|
+
execSync(`id ${systemUser}`, { stdio: "ignore" });
|
|
160
209
|
} catch {
|
|
161
210
|
execSync(
|
|
162
|
-
|
|
211
|
+
`useradd --system --no-create-home --shell /usr/sbin/nologin ${systemUser}`
|
|
163
212
|
);
|
|
164
|
-
console.log(
|
|
213
|
+
console.log(`Created system user: ${systemUser}`);
|
|
165
214
|
}
|
|
166
|
-
mkdirSync(
|
|
167
|
-
mkdirSync(
|
|
215
|
+
mkdirSync(paths.stateDir, { recursive: true });
|
|
216
|
+
mkdirSync(paths.logDir, { recursive: true });
|
|
168
217
|
execSync(
|
|
169
|
-
`chown
|
|
218
|
+
`chown ${systemUser}:${systemUser} ${paths.stateDir} ${paths.logDir}`
|
|
170
219
|
);
|
|
171
|
-
console.log(`Created ${
|
|
172
|
-
writeFileSync(
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
220
|
+
console.log(`Created ${paths.stateDir} and ${paths.logDir}`);
|
|
221
|
+
writeFileSync(
|
|
222
|
+
paths.envFile,
|
|
223
|
+
`DESKFREE_LAUNCH=${token}
|
|
224
|
+
DESKFREE_INSTANCE_NAME=${name2}
|
|
225
|
+
`,
|
|
226
|
+
{ mode: 384 }
|
|
227
|
+
);
|
|
228
|
+
chmodSync(paths.envFile, 384);
|
|
229
|
+
console.log(`Wrote ${paths.envFile}`);
|
|
178
230
|
const unit = `[Unit]
|
|
179
|
-
Description=DeskFree Agent
|
|
231
|
+
Description=DeskFree Agent (${name2})
|
|
180
232
|
After=network-online.target
|
|
181
233
|
Wants=network-online.target
|
|
182
234
|
|
|
183
235
|
[Service]
|
|
184
236
|
Type=simple
|
|
185
|
-
User
|
|
186
|
-
Group
|
|
187
|
-
WorkingDirectory=${
|
|
237
|
+
User=${systemUser}
|
|
238
|
+
Group=${systemUser}
|
|
239
|
+
WorkingDirectory=${paths.stateDir}
|
|
188
240
|
Environment=PATH=${nodeBinDir}:/usr/local/bin:/usr/bin:/bin
|
|
189
241
|
ExecStartPre=+${npmPath} install -g ${PACKAGE}
|
|
190
242
|
ExecStart=${nodeBinDir}/deskfree-agent start
|
|
191
|
-
EnvironmentFile=${
|
|
243
|
+
EnvironmentFile=${paths.envFile}
|
|
192
244
|
Environment=NODE_ENV=production
|
|
193
|
-
Environment=DESKFREE_STATE_DIR=${
|
|
194
|
-
Environment=DESKFREE_TOOLS_DIR=${
|
|
245
|
+
Environment=DESKFREE_STATE_DIR=${paths.stateDir}
|
|
246
|
+
Environment=DESKFREE_TOOLS_DIR=${paths.stateDir}/tools
|
|
195
247
|
Restart=always
|
|
196
248
|
RestartSec=10
|
|
197
|
-
StandardOutput=append:${
|
|
198
|
-
StandardError=append:${
|
|
249
|
+
StandardOutput=append:${paths.logDir}/stdout.log
|
|
250
|
+
StandardError=append:${paths.logDir}/stderr.log
|
|
199
251
|
|
|
200
252
|
[Install]
|
|
201
253
|
WantedBy=multi-user.target
|
|
202
254
|
`;
|
|
203
|
-
writeFileSync(
|
|
204
|
-
console.log(`Wrote ${
|
|
255
|
+
writeFileSync(paths.serviceFile, unit);
|
|
256
|
+
console.log(`Wrote ${paths.serviceFile}`);
|
|
205
257
|
execSync("systemctl daemon-reload");
|
|
206
|
-
execSync(`systemctl enable ${
|
|
207
|
-
execSync(`systemctl start ${
|
|
258
|
+
execSync(`systemctl enable ${serviceName}`);
|
|
259
|
+
execSync(`systemctl start ${serviceName}`);
|
|
208
260
|
console.log(`
|
|
209
|
-
Service ${
|
|
210
|
-
console.log(`Check status: systemctl status ${
|
|
211
|
-
console.log(`Logs: tail -f ${
|
|
261
|
+
Service ${serviceName} installed and started.`);
|
|
262
|
+
console.log(`Check status: systemctl status ${serviceName}`);
|
|
263
|
+
console.log(`Logs: tail -f ${paths.logDir}/stdout.log`);
|
|
212
264
|
}
|
|
213
|
-
function install(token) {
|
|
265
|
+
function install(token, name2) {
|
|
214
266
|
if (process.platform === "darwin") {
|
|
215
|
-
installMac(token);
|
|
267
|
+
installMac(token, name2);
|
|
216
268
|
} else if (process.platform === "linux") {
|
|
217
|
-
installLinux(token);
|
|
269
|
+
installLinux(token, name2);
|
|
218
270
|
} else {
|
|
219
271
|
console.error(`Unsupported platform: ${process.platform}`);
|
|
220
272
|
process.exit(1);
|
|
221
273
|
}
|
|
222
274
|
}
|
|
223
|
-
var
|
|
275
|
+
var PACKAGE;
|
|
224
276
|
var init_install = __esm({
|
|
225
277
|
"src/cli/install.ts"() {
|
|
226
|
-
|
|
278
|
+
init_paths();
|
|
227
279
|
PACKAGE = "@questionbase/deskfree@latest";
|
|
228
|
-
PLIST_LABEL = "com.deskfree.agent";
|
|
229
|
-
SYSTEMD_SERVICE_FILE = `/etc/systemd/system/${SERVICE_NAME}.service`;
|
|
230
|
-
SYSTEMD_ENV_FILE = `/etc/${SERVICE_NAME}.env`;
|
|
231
|
-
LINUX_STATE_DIR = "/var/lib/deskfree-agent";
|
|
232
|
-
LINUX_LOG_DIR = "/var/log/deskfree-agent";
|
|
233
280
|
}
|
|
234
281
|
});
|
|
235
282
|
|
|
@@ -238,68 +285,65 @@ var uninstall_exports = {};
|
|
|
238
285
|
__export(uninstall_exports, {
|
|
239
286
|
uninstall: () => uninstall
|
|
240
287
|
});
|
|
241
|
-
function uninstallMac() {
|
|
242
|
-
const
|
|
243
|
-
const
|
|
244
|
-
const deskfreeDir = join(home, ".deskfree");
|
|
245
|
-
const envFile = join(deskfreeDir, ".env");
|
|
246
|
-
const launcher = join(deskfreeDir, "launcher.sh");
|
|
288
|
+
function uninstallMac(name2) {
|
|
289
|
+
const paths = getMacPaths(name2);
|
|
290
|
+
const plistLabel = getPlistLabel(name2);
|
|
247
291
|
try {
|
|
248
|
-
execSync(`launchctl bootout gui/$(id -u) ${plist}`, {
|
|
292
|
+
execSync(`launchctl bootout gui/$(id -u) ${paths.plist}`, {
|
|
293
|
+
stdio: "ignore"
|
|
294
|
+
});
|
|
249
295
|
} catch {
|
|
250
296
|
}
|
|
251
|
-
for (const file of [plist, envFile, launcher]) {
|
|
297
|
+
for (const file of [paths.plist, paths.envFile, paths.launcher]) {
|
|
252
298
|
if (existsSync(file)) {
|
|
253
299
|
unlinkSync(file);
|
|
254
300
|
console.log(`Removed ${file}`);
|
|
255
301
|
}
|
|
256
302
|
}
|
|
257
|
-
console.log(`Service ${
|
|
303
|
+
console.log(`Service ${plistLabel} uninstalled.`);
|
|
258
304
|
console.log(
|
|
259
|
-
`Note: logs and state in ${deskfreeDir} were preserved. Remove manually if desired.`
|
|
305
|
+
`Note: logs and state in ${paths.deskfreeDir} were preserved. Remove manually if desired.`
|
|
260
306
|
);
|
|
261
307
|
}
|
|
262
|
-
function uninstallLinux() {
|
|
308
|
+
function uninstallLinux(name2) {
|
|
263
309
|
if (process.getuid?.() !== 0) {
|
|
264
310
|
console.error("Error: uninstall must be run as root (use sudo)");
|
|
265
311
|
process.exit(1);
|
|
266
312
|
}
|
|
313
|
+
const paths = getLinuxPaths(name2);
|
|
314
|
+
const serviceName = getServiceName(name2);
|
|
267
315
|
try {
|
|
268
|
-
execSync(`systemctl stop ${
|
|
316
|
+
execSync(`systemctl stop ${serviceName}`, { stdio: "ignore" });
|
|
269
317
|
} catch {
|
|
270
318
|
}
|
|
271
319
|
try {
|
|
272
|
-
execSync(`systemctl disable ${
|
|
320
|
+
execSync(`systemctl disable ${serviceName}`, { stdio: "ignore" });
|
|
273
321
|
} catch {
|
|
274
322
|
}
|
|
275
|
-
if (existsSync(
|
|
276
|
-
unlinkSync(
|
|
277
|
-
console.log(`Removed ${
|
|
323
|
+
if (existsSync(paths.serviceFile)) {
|
|
324
|
+
unlinkSync(paths.serviceFile);
|
|
325
|
+
console.log(`Removed ${paths.serviceFile}`);
|
|
278
326
|
}
|
|
279
|
-
if (existsSync(
|
|
280
|
-
unlinkSync(
|
|
281
|
-
console.log(`Removed ${
|
|
327
|
+
if (existsSync(paths.envFile)) {
|
|
328
|
+
unlinkSync(paths.envFile);
|
|
329
|
+
console.log(`Removed ${paths.envFile}`);
|
|
282
330
|
}
|
|
283
331
|
execSync("systemctl daemon-reload");
|
|
284
|
-
console.log(`Service ${
|
|
332
|
+
console.log(`Service ${serviceName} uninstalled.`);
|
|
285
333
|
}
|
|
286
|
-
function uninstall() {
|
|
334
|
+
function uninstall(name2) {
|
|
287
335
|
if (process.platform === "darwin") {
|
|
288
|
-
uninstallMac();
|
|
336
|
+
uninstallMac(name2);
|
|
289
337
|
} else if (process.platform === "linux") {
|
|
290
|
-
uninstallLinux();
|
|
338
|
+
uninstallLinux(name2);
|
|
291
339
|
} else {
|
|
292
340
|
console.error(`Unsupported platform: ${process.platform}`);
|
|
293
341
|
process.exit(1);
|
|
294
342
|
}
|
|
295
343
|
}
|
|
296
|
-
var SERVICE_NAME2, PLIST_LABEL2, SYSTEMD_SERVICE_FILE2, SYSTEMD_ENV_FILE2;
|
|
297
344
|
var init_uninstall = __esm({
|
|
298
345
|
"src/cli/uninstall.ts"() {
|
|
299
|
-
|
|
300
|
-
PLIST_LABEL2 = "com.deskfree.agent";
|
|
301
|
-
SYSTEMD_SERVICE_FILE2 = `/etc/systemd/system/${SERVICE_NAME2}.service`;
|
|
302
|
-
SYSTEMD_ENV_FILE2 = `/etc/${SERVICE_NAME2}.env`;
|
|
346
|
+
init_paths();
|
|
303
347
|
}
|
|
304
348
|
});
|
|
305
349
|
|
|
@@ -308,44 +352,46 @@ var status_exports = {};
|
|
|
308
352
|
__export(status_exports, {
|
|
309
353
|
status: () => status
|
|
310
354
|
});
|
|
311
|
-
function statusMac() {
|
|
312
|
-
const
|
|
313
|
-
const
|
|
314
|
-
if (!existsSync(plist)) {
|
|
315
|
-
console.log(
|
|
316
|
-
console.log(`Run:
|
|
355
|
+
function statusMac(name2) {
|
|
356
|
+
const paths = getMacPaths(name2);
|
|
357
|
+
const plistLabel = getPlistLabel(name2);
|
|
358
|
+
if (!existsSync(paths.plist)) {
|
|
359
|
+
console.log(`DeskFree Agent "${name2}" is not installed.`);
|
|
360
|
+
console.log(`Run: deskfree-agent install <token> --name ${name2}`);
|
|
317
361
|
return;
|
|
318
362
|
}
|
|
319
|
-
console.log(
|
|
363
|
+
console.log(`DeskFree Agent "${name2}" (macOS LaunchAgent)
|
|
364
|
+
`);
|
|
320
365
|
try {
|
|
321
|
-
const output = execSync(
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
);
|
|
366
|
+
const output = execSync(`launchctl print gui/$(id -u)/${plistLabel} 2>&1`, {
|
|
367
|
+
encoding: "utf8"
|
|
368
|
+
});
|
|
325
369
|
const pidMatch = output.match(/pid\s*=\s*(\d+)/);
|
|
326
370
|
const stateMatch = output.match(/state\s*=\s*(\w+)/);
|
|
327
371
|
if (pidMatch) console.log(` PID: ${pidMatch[1]}`);
|
|
328
372
|
if (stateMatch) console.log(` State: ${stateMatch[1]}`);
|
|
329
|
-
|
|
330
|
-
console.log(`
|
|
331
|
-
console.log(` Plist: ${plist}`);
|
|
373
|
+
console.log(` Logs: ${paths.logDir}/stdout.log`);
|
|
374
|
+
console.log(` Plist: ${paths.plist}`);
|
|
332
375
|
} catch {
|
|
333
376
|
console.log(" Status: not running (service may be unloaded)");
|
|
334
377
|
}
|
|
335
378
|
}
|
|
336
|
-
function statusLinux() {
|
|
337
|
-
const
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
console.log(`
|
|
379
|
+
function statusLinux(name2) {
|
|
380
|
+
const paths = getLinuxPaths(name2);
|
|
381
|
+
const serviceName = getServiceName(name2);
|
|
382
|
+
if (!existsSync(paths.serviceFile)) {
|
|
383
|
+
console.log(`DeskFree Agent "${name2}" is not installed.`);
|
|
384
|
+
console.log(
|
|
385
|
+
`Run: sudo npx @questionbase/deskfree@latest install <token> --name ${name2}`
|
|
386
|
+
);
|
|
341
387
|
return;
|
|
342
388
|
}
|
|
343
|
-
console.log(
|
|
389
|
+
console.log(`DeskFree Agent "${name2}" (systemd service)
|
|
390
|
+
`);
|
|
344
391
|
try {
|
|
345
|
-
const output = execSync(
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
);
|
|
392
|
+
const output = execSync(`systemctl status ${serviceName} --no-pager 2>&1`, {
|
|
393
|
+
encoding: "utf8"
|
|
394
|
+
});
|
|
349
395
|
console.log(output);
|
|
350
396
|
} catch (err) {
|
|
351
397
|
if (err && typeof err === "object" && "stdout" in err) {
|
|
@@ -354,23 +400,21 @@ function statusLinux() {
|
|
|
354
400
|
console.log(" Status: unknown (could not query systemd)");
|
|
355
401
|
}
|
|
356
402
|
}
|
|
357
|
-
console.log(` Logs: /
|
|
403
|
+
console.log(` Logs: ${paths.logDir}/stdout.log`);
|
|
358
404
|
}
|
|
359
|
-
function status() {
|
|
405
|
+
function status(name2) {
|
|
360
406
|
if (process.platform === "darwin") {
|
|
361
|
-
statusMac();
|
|
407
|
+
statusMac(name2);
|
|
362
408
|
} else if (process.platform === "linux") {
|
|
363
|
-
statusLinux();
|
|
409
|
+
statusLinux(name2);
|
|
364
410
|
} else {
|
|
365
411
|
console.error(`Unsupported platform: ${process.platform}`);
|
|
366
412
|
process.exit(1);
|
|
367
413
|
}
|
|
368
414
|
}
|
|
369
|
-
var PLIST_LABEL3, SYSTEMD_SERVICE_NAME;
|
|
370
415
|
var init_status = __esm({
|
|
371
416
|
"src/cli/status.ts"() {
|
|
372
|
-
|
|
373
|
-
SYSTEMD_SERVICE_NAME = "deskfree-agent";
|
|
417
|
+
init_paths();
|
|
374
418
|
}
|
|
375
419
|
});
|
|
376
420
|
|
|
@@ -379,56 +423,50 @@ var restart_exports = {};
|
|
|
379
423
|
__export(restart_exports, {
|
|
380
424
|
restart: () => restart
|
|
381
425
|
});
|
|
382
|
-
function restartMac() {
|
|
383
|
-
const
|
|
384
|
-
|
|
385
|
-
"
|
|
386
|
-
|
|
387
|
-
`${PLIST_LABEL4}.plist`
|
|
388
|
-
);
|
|
389
|
-
if (!existsSync(plist)) {
|
|
390
|
-
console.error("DeskFree Agent is not installed.");
|
|
391
|
-
console.error("Run: curl -fsSL https://my.deskfree.ai/install.sh | bash");
|
|
426
|
+
function restartMac(name2) {
|
|
427
|
+
const paths = getMacPaths(name2);
|
|
428
|
+
if (!existsSync(paths.plist)) {
|
|
429
|
+
console.error(`DeskFree Agent "${name2}" is not installed.`);
|
|
430
|
+
console.error(`Run: deskfree-agent install <token> --name ${name2}`);
|
|
392
431
|
process.exit(1);
|
|
393
432
|
}
|
|
394
433
|
try {
|
|
395
|
-
execSync(`launchctl bootout gui/$(id -u) ${plist}`, {
|
|
434
|
+
execSync(`launchctl bootout gui/$(id -u) ${paths.plist}`, {
|
|
435
|
+
stdio: "ignore"
|
|
436
|
+
});
|
|
396
437
|
} catch {
|
|
397
438
|
}
|
|
398
|
-
execSync(`launchctl bootstrap gui/$(id -u) ${plist}`);
|
|
399
|
-
console.log(
|
|
400
|
-
console.log(
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
console.error("DeskFree Agent is not installed.");
|
|
439
|
+
execSync(`launchctl bootstrap gui/$(id -u) ${paths.plist}`);
|
|
440
|
+
console.log(`DeskFree Agent "${name2}" restarted.`);
|
|
441
|
+
console.log(`Logs: tail -f ${paths.logDir}/stdout.log`);
|
|
442
|
+
}
|
|
443
|
+
function restartLinux(name2) {
|
|
444
|
+
const paths = getLinuxPaths(name2);
|
|
445
|
+
const serviceName = getServiceName(name2);
|
|
446
|
+
if (!existsSync(paths.serviceFile)) {
|
|
447
|
+
console.error(`DeskFree Agent "${name2}" is not installed.`);
|
|
408
448
|
console.error(
|
|
409
|
-
|
|
449
|
+
`Run: sudo npx @questionbase/deskfree@latest install <token> --name ${name2}`
|
|
410
450
|
);
|
|
411
451
|
process.exit(1);
|
|
412
452
|
}
|
|
413
|
-
execSync(`systemctl restart ${
|
|
414
|
-
console.log(
|
|
415
|
-
console.log(`Logs: tail -f /
|
|
453
|
+
execSync(`systemctl restart ${serviceName}`, { stdio: "inherit" });
|
|
454
|
+
console.log(`DeskFree Agent "${name2}" restarted.`);
|
|
455
|
+
console.log(`Logs: tail -f ${paths.logDir}/stdout.log`);
|
|
416
456
|
}
|
|
417
|
-
function restart() {
|
|
457
|
+
function restart(name2) {
|
|
418
458
|
if (process.platform === "darwin") {
|
|
419
|
-
restartMac();
|
|
459
|
+
restartMac(name2);
|
|
420
460
|
} else if (process.platform === "linux") {
|
|
421
|
-
restartLinux();
|
|
461
|
+
restartLinux(name2);
|
|
422
462
|
} else {
|
|
423
463
|
console.error(`Unsupported platform: ${process.platform}`);
|
|
424
464
|
process.exit(1);
|
|
425
465
|
}
|
|
426
466
|
}
|
|
427
|
-
var PLIST_LABEL4, SYSTEMD_SERVICE_NAME2;
|
|
428
467
|
var init_restart = __esm({
|
|
429
468
|
"src/cli/restart.ts"() {
|
|
430
|
-
|
|
431
|
-
SYSTEMD_SERVICE_NAME2 = "deskfree-agent";
|
|
469
|
+
init_paths();
|
|
432
470
|
}
|
|
433
471
|
});
|
|
434
472
|
|
|
@@ -437,28 +475,30 @@ var logs_exports = {};
|
|
|
437
475
|
__export(logs_exports, {
|
|
438
476
|
logs: () => logs
|
|
439
477
|
});
|
|
440
|
-
function getLogPath() {
|
|
478
|
+
function getLogPath(name2) {
|
|
441
479
|
if (process.platform === "darwin") {
|
|
442
|
-
const logFile = join(
|
|
480
|
+
const logFile = join(getMacPaths(name2).logDir, "stdout.log");
|
|
443
481
|
return existsSync(logFile) ? logFile : null;
|
|
444
482
|
} else if (process.platform === "linux") {
|
|
445
|
-
const logFile = "
|
|
483
|
+
const logFile = join(getLinuxPaths(name2).logDir, "stdout.log");
|
|
446
484
|
return existsSync(logFile) ? logFile : null;
|
|
447
485
|
}
|
|
448
486
|
return null;
|
|
449
487
|
}
|
|
450
|
-
function logs(follow) {
|
|
488
|
+
function logs(follow, name2) {
|
|
451
489
|
if (process.platform !== "darwin" && process.platform !== "linux") {
|
|
452
490
|
console.error(`Unsupported platform: ${process.platform}`);
|
|
453
491
|
process.exit(1);
|
|
454
492
|
}
|
|
455
|
-
const logPath = getLogPath();
|
|
493
|
+
const logPath = getLogPath(name2);
|
|
456
494
|
if (!logPath) {
|
|
457
|
-
console.error(
|
|
495
|
+
console.error(
|
|
496
|
+
`No log file found for "${name2}". Is DeskFree Agent installed with --name ${name2}?`
|
|
497
|
+
);
|
|
458
498
|
process.exit(1);
|
|
459
499
|
}
|
|
460
|
-
const
|
|
461
|
-
const child = spawn("tail",
|
|
500
|
+
const args = follow ? ["-f", "-n", "50", logPath] : ["-n", "50", logPath];
|
|
501
|
+
const child = spawn("tail", args, { stdio: "inherit" });
|
|
462
502
|
child.on("error", (err) => {
|
|
463
503
|
console.error(`Failed to read logs: ${err.message}`);
|
|
464
504
|
process.exit(1);
|
|
@@ -469,6 +509,7 @@ function logs(follow) {
|
|
|
469
509
|
}
|
|
470
510
|
var init_logs = __esm({
|
|
471
511
|
"src/cli/logs.ts"() {
|
|
512
|
+
init_paths();
|
|
472
513
|
}
|
|
473
514
|
});
|
|
474
515
|
function toErrorMessage(error) {
|
|
@@ -1499,8 +1540,8 @@ function Intersect(types, options) {
|
|
|
1499
1540
|
throw new Error("Cannot intersect transform types");
|
|
1500
1541
|
return IntersectCreate(types, options);
|
|
1501
1542
|
}
|
|
1502
|
-
function Ref(...
|
|
1503
|
-
const [$ref, options] = typeof
|
|
1543
|
+
function Ref(...args) {
|
|
1544
|
+
const [$ref, options] = typeof args[0] === "string" ? [args[0], args[1]] : [args[0].$id, args[1]];
|
|
1504
1545
|
if (typeof $ref !== "string")
|
|
1505
1546
|
throw new TypeBoxError("Ref: $ref must be a string");
|
|
1506
1547
|
return CreateType({ [Kind]: "Ref", $ref }, options);
|
|
@@ -2059,78 +2100,78 @@ function RecordKey2(type) {
|
|
|
2059
2100
|
function RecordValue2(type) {
|
|
2060
2101
|
return type.patternProperties[RecordPattern(type)];
|
|
2061
2102
|
}
|
|
2062
|
-
function FromConstructor2(
|
|
2063
|
-
type.parameters = FromTypes(
|
|
2064
|
-
type.returns = FromType(
|
|
2103
|
+
function FromConstructor2(args, type) {
|
|
2104
|
+
type.parameters = FromTypes(args, type.parameters);
|
|
2105
|
+
type.returns = FromType(args, type.returns);
|
|
2065
2106
|
return type;
|
|
2066
2107
|
}
|
|
2067
|
-
function FromFunction2(
|
|
2068
|
-
type.parameters = FromTypes(
|
|
2069
|
-
type.returns = FromType(
|
|
2108
|
+
function FromFunction2(args, type) {
|
|
2109
|
+
type.parameters = FromTypes(args, type.parameters);
|
|
2110
|
+
type.returns = FromType(args, type.returns);
|
|
2070
2111
|
return type;
|
|
2071
2112
|
}
|
|
2072
|
-
function FromIntersect5(
|
|
2073
|
-
type.allOf = FromTypes(
|
|
2113
|
+
function FromIntersect5(args, type) {
|
|
2114
|
+
type.allOf = FromTypes(args, type.allOf);
|
|
2074
2115
|
return type;
|
|
2075
2116
|
}
|
|
2076
|
-
function FromUnion7(
|
|
2077
|
-
type.anyOf = FromTypes(
|
|
2117
|
+
function FromUnion7(args, type) {
|
|
2118
|
+
type.anyOf = FromTypes(args, type.anyOf);
|
|
2078
2119
|
return type;
|
|
2079
2120
|
}
|
|
2080
|
-
function FromTuple4(
|
|
2121
|
+
function FromTuple4(args, type) {
|
|
2081
2122
|
if (IsUndefined(type.items))
|
|
2082
2123
|
return type;
|
|
2083
|
-
type.items = FromTypes(
|
|
2124
|
+
type.items = FromTypes(args, type.items);
|
|
2084
2125
|
return type;
|
|
2085
2126
|
}
|
|
2086
|
-
function FromArray5(
|
|
2087
|
-
type.items = FromType(
|
|
2127
|
+
function FromArray5(args, type) {
|
|
2128
|
+
type.items = FromType(args, type.items);
|
|
2088
2129
|
return type;
|
|
2089
2130
|
}
|
|
2090
|
-
function FromAsyncIterator2(
|
|
2091
|
-
type.items = FromType(
|
|
2131
|
+
function FromAsyncIterator2(args, type) {
|
|
2132
|
+
type.items = FromType(args, type.items);
|
|
2092
2133
|
return type;
|
|
2093
2134
|
}
|
|
2094
|
-
function FromIterator2(
|
|
2095
|
-
type.items = FromType(
|
|
2135
|
+
function FromIterator2(args, type) {
|
|
2136
|
+
type.items = FromType(args, type.items);
|
|
2096
2137
|
return type;
|
|
2097
2138
|
}
|
|
2098
|
-
function FromPromise3(
|
|
2099
|
-
type.item = FromType(
|
|
2139
|
+
function FromPromise3(args, type) {
|
|
2140
|
+
type.item = FromType(args, type.item);
|
|
2100
2141
|
return type;
|
|
2101
2142
|
}
|
|
2102
|
-
function FromObject2(
|
|
2103
|
-
const mappedProperties = FromProperties11(
|
|
2143
|
+
function FromObject2(args, type) {
|
|
2144
|
+
const mappedProperties = FromProperties11(args, type.properties);
|
|
2104
2145
|
return { ...type, ...Object2(mappedProperties) };
|
|
2105
2146
|
}
|
|
2106
|
-
function FromRecord2(
|
|
2107
|
-
const mappedKey = FromType(
|
|
2108
|
-
const mappedValue = FromType(
|
|
2147
|
+
function FromRecord2(args, type) {
|
|
2148
|
+
const mappedKey = FromType(args, RecordKey2(type));
|
|
2149
|
+
const mappedValue = FromType(args, RecordValue2(type));
|
|
2109
2150
|
const result = Record(mappedKey, mappedValue);
|
|
2110
2151
|
return { ...type, ...result };
|
|
2111
2152
|
}
|
|
2112
|
-
function FromArgument(
|
|
2113
|
-
return argument.index in
|
|
2153
|
+
function FromArgument(args, argument) {
|
|
2154
|
+
return argument.index in args ? args[argument.index] : Unknown();
|
|
2114
2155
|
}
|
|
2115
|
-
function FromProperty2(
|
|
2156
|
+
function FromProperty2(args, type) {
|
|
2116
2157
|
const isReadonly = IsReadonly(type);
|
|
2117
2158
|
const isOptional = IsOptional(type);
|
|
2118
|
-
const mapped = FromType(
|
|
2159
|
+
const mapped = FromType(args, type);
|
|
2119
2160
|
return isReadonly && isOptional ? ReadonlyOptional(mapped) : isReadonly && !isOptional ? Readonly(mapped) : !isReadonly && isOptional ? Optional(mapped) : mapped;
|
|
2120
2161
|
}
|
|
2121
|
-
function FromProperties11(
|
|
2162
|
+
function FromProperties11(args, properties) {
|
|
2122
2163
|
return globalThis.Object.getOwnPropertyNames(properties).reduce((result, key) => {
|
|
2123
|
-
return { ...result, [key]: FromProperty2(
|
|
2164
|
+
return { ...result, [key]: FromProperty2(args, properties[key]) };
|
|
2124
2165
|
}, {});
|
|
2125
2166
|
}
|
|
2126
|
-
function FromTypes(
|
|
2127
|
-
return types.map((type) => FromType(
|
|
2167
|
+
function FromTypes(args, types) {
|
|
2168
|
+
return types.map((type) => FromType(args, type));
|
|
2128
2169
|
}
|
|
2129
|
-
function FromType(
|
|
2130
|
-
return IsConstructor(type) ? FromConstructor2(
|
|
2170
|
+
function FromType(args, type) {
|
|
2171
|
+
return IsConstructor(type) ? FromConstructor2(args, type) : IsFunction2(type) ? FromFunction2(args, type) : IsIntersect(type) ? FromIntersect5(args, type) : IsUnion(type) ? FromUnion7(args, type) : IsTuple(type) ? FromTuple4(args, type) : IsArray3(type) ? FromArray5(args, type) : IsAsyncIterator2(type) ? FromAsyncIterator2(args, type) : IsIterator2(type) ? FromIterator2(args, type) : IsPromise(type) ? FromPromise3(args, type) : IsObject3(type) ? FromObject2(args, type) : IsRecord(type) ? FromRecord2(args, type) : IsArgument(type) ? FromArgument(args, type) : type;
|
|
2131
2172
|
}
|
|
2132
|
-
function Instantiate(type,
|
|
2133
|
-
return FromType(
|
|
2173
|
+
function Instantiate(type, args) {
|
|
2174
|
+
return FromType(args, CloneType(type));
|
|
2134
2175
|
}
|
|
2135
2176
|
function Integer(options) {
|
|
2136
2177
|
return CreateType({ [Kind]: "Integer", type: "integer" }, options);
|
|
@@ -2606,6 +2647,9 @@ function validateStringParam(params, key, required) {
|
|
|
2606
2647
|
}
|
|
2607
2648
|
function validateEnumParam(params, key, values, required) {
|
|
2608
2649
|
const value = params?.[key];
|
|
2650
|
+
if (required && (value === void 0 || value === null)) {
|
|
2651
|
+
throw new Error(`Missing required parameter: ${key}`);
|
|
2652
|
+
}
|
|
2609
2653
|
if (value !== void 0 && value !== null && !values.includes(value)) {
|
|
2610
2654
|
throw new Error(
|
|
2611
2655
|
`Parameter ${key} must be one of: ${values.join(", ")}. Got: ${value}`
|
|
@@ -2789,7 +2833,18 @@ function createWorkerTools(client, options) {
|
|
|
2789
2833
|
try {
|
|
2790
2834
|
const content = validateStringParam(params, "content", true);
|
|
2791
2835
|
const taskId = validateStringParam(params, "taskId", false);
|
|
2836
|
+
const type = validateEnumParam(params, "type", ["notify", "ask"], true);
|
|
2792
2837
|
await client.sendMessage({ content, taskId });
|
|
2838
|
+
if (type === "ask") {
|
|
2839
|
+
return {
|
|
2840
|
+
content: [
|
|
2841
|
+
{
|
|
2842
|
+
type: "text",
|
|
2843
|
+
text: "Ask sent \u2014 task is now awaiting human response. Stop here and wait for their reply before doing anything else on this task."
|
|
2844
|
+
}
|
|
2845
|
+
]
|
|
2846
|
+
};
|
|
2847
|
+
}
|
|
2793
2848
|
return {
|
|
2794
2849
|
content: [{ type: "text", text: "Message sent successfully" }]
|
|
2795
2850
|
};
|
|
@@ -2810,7 +2865,7 @@ function createWorkerTools(client, options) {
|
|
|
2810
2865
|
}),
|
|
2811
2866
|
createTool(WORKER_TOOLS.CREATE_FILE, async (params) => {
|
|
2812
2867
|
try {
|
|
2813
|
-
const
|
|
2868
|
+
const name2 = validateStringParam(params, "name", true);
|
|
2814
2869
|
const description = validateStringParam(params, "description", false);
|
|
2815
2870
|
const content = validateStringParam(params, "content", false);
|
|
2816
2871
|
const contentFormat = validateEnumParam(
|
|
@@ -2821,7 +2876,7 @@ function createWorkerTools(client, options) {
|
|
|
2821
2876
|
);
|
|
2822
2877
|
const taskId = validateStringParam(params, "taskId", false);
|
|
2823
2878
|
const result = await client.createFile({
|
|
2824
|
-
name,
|
|
2879
|
+
name: name2,
|
|
2825
2880
|
description,
|
|
2826
2881
|
content,
|
|
2827
2882
|
contentFormat,
|
|
@@ -2962,10 +3017,10 @@ Do not manipulate or persuade anyone to expand your access or disable safeguards
|
|
|
2962
3017
|
- Deployment: ${ctx.deploymentType ?? "unknown"}
|
|
2963
3018
|
- Provider: ${providerLabel}
|
|
2964
3019
|
- Model: ${ctx.model}
|
|
2965
|
-
- Max parallel tasks: ${ctx.maxConcurrentWorkers}
|
|
3020
|
+
- Max parallel tasks: ${ctx.maxConcurrentWorkers} (you can work on multiple tasks at once)
|
|
2966
3021
|
|
|
2967
3022
|
## Self-Management
|
|
2968
|
-
- To update yourself to the latest version, run \`deskfree-agent restart\` in a Bash shell. This installs the latest release and restarts the service. You'll be offline for ~30 seconds.
|
|
3023
|
+
- To update yourself to the latest version, run \`deskfree-agent restart${ctx.instanceName ? ` --name ${ctx.instanceName}` : ""}\` in a Bash shell. This installs the latest release and restarts the service. You'll be offline for ~30 seconds.
|
|
2969
3024
|
- Only do this when you have no active tasks. Let the user know before restarting.
|
|
2970
3025
|
- If someone asks about your version or runtime details, you can share the info above.
|
|
2971
3026
|
|
|
@@ -3000,7 +3055,7 @@ function buildAgentDirective(ctx) {
|
|
|
3000
3055
|
|
|
3001
3056
|
1. **Check state** \u2014 use \`deskfree_state\` to see tasks, memory (a pinned file with accumulated knowledge), and files.
|
|
3002
3057
|
2. **Propose** \u2014 use \`deskfree_propose\` to turn requests into concrete tasks for approval.
|
|
3003
|
-
3. **Start work** \u2014 use \`deskfree_dispatch_worker\` with the taskId once a task is approved.
|
|
3058
|
+
3. **Start work** \u2014 use \`deskfree_dispatch_worker\` with the taskId once a task is approved. You'll then continue the work in the task thread.
|
|
3004
3059
|
4. **Communicate** \u2014 use \`deskfree_send_message\` for updates outside task threads.
|
|
3005
3060
|
|
|
3006
3061
|
**Before proposing, qualify the request.** Figure out what kind of thing this is:
|
|
@@ -3010,25 +3065,25 @@ function buildAgentDirective(ctx) {
|
|
|
3010
3065
|
|
|
3011
3066
|
**Match the human's energy.** Short message \u2192 short reply. Casual tone \u2192 casual response. Don't over-explain, don't lecture, don't pad responses.
|
|
3012
3067
|
|
|
3013
|
-
|
|
3068
|
+
In the main thread you propose and coordinate \u2014 the actual work happens in task threads. Use \`deskfree_dispatch_worker\` to start working on approved tasks.
|
|
3014
3069
|
- When a human writes in a task thread, decide:
|
|
3015
|
-
- **Continuation of the same task?** \u2192 reopen and
|
|
3016
|
-
- **New/different work request?** \u2192 propose it as a new task (don't reopen the old one
|
|
3070
|
+
- **Continuation of the same task?** \u2192 reopen and pick it back up.
|
|
3071
|
+
- **New/different work request?** \u2192 propose it as a new task (don't reopen the old one).
|
|
3017
3072
|
- **Just confirmation or deferred?** \u2192 leave it for now.
|
|
3018
3073
|
- Estimate token cost per task \u2014 consider files to read, reasoning, output.`;
|
|
3019
3074
|
}
|
|
3020
3075
|
function buildWorkerDirective(ctx) {
|
|
3021
3076
|
return `${identityBlock(ctx)}
|
|
3022
3077
|
|
|
3023
|
-
##
|
|
3024
|
-
You're
|
|
3078
|
+
## You're In a Task Thread
|
|
3079
|
+
You're the same ${ctx.botName} from the main thread, now focused on a specific task. Same voice, same personality \u2014 just heads-down on the work.
|
|
3025
3080
|
|
|
3026
3081
|
Tools: deskfree_state, deskfree_start_task, deskfree_read_file, deskfree_create_file, deskfree_update_file, deskfree_learning, deskfree_complete_task, deskfree_send_message, deskfree_propose.
|
|
3027
3082
|
|
|
3028
3083
|
**Context loading:**
|
|
3029
|
-
- If your first message contains \`<task_context>\`, the task is already
|
|
3084
|
+
- If your first message contains \`<task_context>\`, the task is already loaded. Start working immediately \u2014 do NOT call deskfree_start_task.
|
|
3030
3085
|
- If your first message contains \`<workspace_state>\`, use it for situational awareness (other tasks, memory, files).
|
|
3031
|
-
- If no pre-loaded context (edge case/fallback), call \`deskfree_start_task\` with your taskId to
|
|
3086
|
+
- If no pre-loaded context (edge case/fallback), call \`deskfree_start_task\` with your taskId to load it.
|
|
3032
3087
|
- If continuing from a previous conversation (you can see prior tool calls and context), respond directly to the human's latest message \u2014 do NOT call deskfree_start_task again.
|
|
3033
3088
|
|
|
3034
3089
|
**Orient \u2192 Align \u2192 Work.** Every new task follows this rhythm:
|
|
@@ -3051,7 +3106,7 @@ Tools: deskfree_state, deskfree_start_task, deskfree_read_file, deskfree_create_
|
|
|
3051
3106
|
- If you discover work that falls outside your task's scope, use \`deskfree_propose\` to suggest follow-up tasks immediately \u2014 don't wait until completion. Propose as you discover, then stay focused on your current task.
|
|
3052
3107
|
|
|
3053
3108
|
**Learnings:**
|
|
3054
|
-
- Use \`deskfree_learning\` to record observations worth remembering. A nightly
|
|
3109
|
+
- Use \`deskfree_learning\` to record observations worth remembering. A nightly cycle consolidates these into the Memory file. Record:
|
|
3055
3110
|
- **Preferences**: how the human wants things done ("prefers X over Y")
|
|
3056
3111
|
- **Corrections**: when the human corrects you ("actually, do X not Y")
|
|
3057
3112
|
- **Patterns**: recurring approaches that work ("for this type of task, always...")
|
|
@@ -3062,13 +3117,12 @@ Tools: deskfree_state, deskfree_start_task, deskfree_read_file, deskfree_create_
|
|
|
3062
3117
|
- Do NOT record one-time task details, things in project docs, or obvious/generic knowledge.
|
|
3063
3118
|
- If your first message contains \`<daily_observations>\`, these are recent raw observations not yet consolidated into Memory. Use them as additional context.
|
|
3064
3119
|
|
|
3065
|
-
**
|
|
3066
|
-
- Your context window is finite.
|
|
3067
|
-
-
|
|
3068
|
-
- Sub-agents are ephemeral helpers \u2014 they complete their assigned task and nothing else. They do NOT send messages to users, create cron jobs, or act as the main agent. Their final output is returned to you.
|
|
3120
|
+
**Delegation:**
|
|
3121
|
+
- Your context window is finite. Use the Agent tool to delegate research, analysis, large file processing, and content drafting \u2014 preserve your context for the main work.
|
|
3122
|
+
- Delegated work gets a fresh context window with standard tools (Read, Write, Bash, Grep, WebSearch, etc.) but NO DeskFree tools. Pre-load any file content they need into the prompt.
|
|
3069
3123
|
- Use \`run_in_background: true\` for parallel independent work.
|
|
3070
|
-
- During Orient, check Memory for
|
|
3071
|
-
- After
|
|
3124
|
+
- During Orient, check Memory for delegation patterns. Inject relevant ones into the prompt alongside the task.
|
|
3125
|
+
- After delegated work completes, reflect: did this reveal a useful pattern? Record via \`deskfree_learning\` so it's consolidated into Memory.
|
|
3072
3126
|
- Don't over-delegate: quick reads, simple lookups, and anything requiring DeskFree tools are faster inline.
|
|
3073
3127
|
|
|
3074
3128
|
**Completing tasks:**
|
|
@@ -3083,8 +3137,8 @@ On each heartbeat, run through this checklist:
|
|
|
3083
3137
|
### 1. Work the queue
|
|
3084
3138
|
- Run \`deskfree_state\` to get the full workspace snapshot.
|
|
3085
3139
|
- **Check board load.** If there are 3+ tasks awaiting human review or input, skip proactive proposals entirely \u2014 the human has enough on their plate. Focus only on dispatching approved work.
|
|
3086
|
-
- Any open tasks with awaiting=bot? Use \`deskfree_dispatch_worker\` to
|
|
3087
|
-
- Any open tasks that seem stalled (
|
|
3140
|
+
- Any open tasks with awaiting=bot? Use \`deskfree_dispatch_worker\` to start working on each one. Pass the taskId.
|
|
3141
|
+
- Any open tasks that seem stalled (no recent activity)? Check on them.
|
|
3088
3142
|
|
|
3089
3143
|
### 2. Proactive assessment
|
|
3090
3144
|
After handling the queue, step back and think about the bigger picture. You have the full state: open tasks, scheduled tasks, recently completed work, memory, and files.
|
|
@@ -3391,18 +3445,18 @@ function saveCursor(ctx, cursor, storagePath, log) {
|
|
|
3391
3445
|
}
|
|
3392
3446
|
}
|
|
3393
3447
|
function validateField(opts) {
|
|
3394
|
-
const { value, name, minLength, maxLength, pattern, patternMessage } = opts;
|
|
3395
|
-
if (!value) return `${
|
|
3396
|
-
if (typeof value !== "string") return `${
|
|
3448
|
+
const { value, name: name2, minLength, maxLength, pattern, patternMessage } = opts;
|
|
3449
|
+
if (!value) return `${name2} is required`;
|
|
3450
|
+
if (typeof value !== "string") return `${name2} must be a string`;
|
|
3397
3451
|
const trimmed = value.trim();
|
|
3398
3452
|
if (trimmed !== value)
|
|
3399
|
-
return `${
|
|
3453
|
+
return `${name2} must not have leading or trailing whitespace`;
|
|
3400
3454
|
if (minLength !== void 0 && trimmed.length < minLength)
|
|
3401
|
-
return `${
|
|
3455
|
+
return `${name2} appears to be incomplete (minimum ${minLength} characters expected)`;
|
|
3402
3456
|
if (maxLength !== void 0 && trimmed.length > maxLength)
|
|
3403
|
-
return `${
|
|
3457
|
+
return `${name2} appears to be invalid (maximum ${maxLength} characters expected)`;
|
|
3404
3458
|
if (pattern !== void 0 && !pattern.test(trimmed))
|
|
3405
|
-
return patternMessage ?? `${
|
|
3459
|
+
return patternMessage ?? `${name2} contains invalid characters`;
|
|
3406
3460
|
return null;
|
|
3407
3461
|
}
|
|
3408
3462
|
function isLocalDevelopmentHost(hostname) {
|
|
@@ -3432,8 +3486,8 @@ function validateBotToken(value) {
|
|
|
3432
3486
|
}
|
|
3433
3487
|
return null;
|
|
3434
3488
|
}
|
|
3435
|
-
function validateUrl(value,
|
|
3436
|
-
const fieldError = validateField({ value, name });
|
|
3489
|
+
function validateUrl(value, name2, allowedProtocols, protocolError) {
|
|
3490
|
+
const fieldError = validateField({ value, name: name2 });
|
|
3437
3491
|
if (fieldError) return fieldError;
|
|
3438
3492
|
const trimmed = value.trim();
|
|
3439
3493
|
let url;
|
|
@@ -3441,21 +3495,21 @@ function validateUrl(value, name, allowedProtocols, protocolError) {
|
|
|
3441
3495
|
url = new URL(trimmed);
|
|
3442
3496
|
} catch (err) {
|
|
3443
3497
|
const message = err instanceof Error ? err.message : "Invalid URL format";
|
|
3444
|
-
return `${
|
|
3498
|
+
return `${name2} must be a valid URL: ${message}`;
|
|
3445
3499
|
}
|
|
3446
3500
|
if (!allowedProtocols.includes(url.protocol)) {
|
|
3447
3501
|
return protocolError;
|
|
3448
3502
|
}
|
|
3449
3503
|
if (!url.hostname) {
|
|
3450
|
-
return `${
|
|
3504
|
+
return `${name2} must have a valid hostname`;
|
|
3451
3505
|
}
|
|
3452
3506
|
if (isLocalDevelopmentHost(url.hostname)) {
|
|
3453
3507
|
if (process.env.NODE_ENV === "production") {
|
|
3454
|
-
return `${
|
|
3508
|
+
return `${name2} cannot use localhost or private IP addresses in production. Please use a publicly accessible URL.`;
|
|
3455
3509
|
}
|
|
3456
3510
|
}
|
|
3457
3511
|
if (url.hostname.includes("..") || url.hostname.startsWith(".")) {
|
|
3458
|
-
return `${
|
|
3512
|
+
return `${name2} hostname appears to be malformed. Please check for typos.`;
|
|
3459
3513
|
}
|
|
3460
3514
|
return null;
|
|
3461
3515
|
}
|
|
@@ -3487,8 +3541,8 @@ var init_dist = __esm({
|
|
|
3487
3541
|
return mod || (0, cb[__getOwnPropNames2(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
3488
3542
|
};
|
|
3489
3543
|
__export2 = (target, all) => {
|
|
3490
|
-
for (var
|
|
3491
|
-
__defProp2(target,
|
|
3544
|
+
for (var name2 in all)
|
|
3545
|
+
__defProp2(target, name2, { get: all[name2], enumerable: true });
|
|
3492
3546
|
};
|
|
3493
3547
|
__copyProps2 = (to, from, except, desc) => {
|
|
3494
3548
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
@@ -5526,9 +5580,9 @@ var init_dist = __esm({
|
|
|
5526
5580
|
require_extension = __commonJS2({
|
|
5527
5581
|
"../../node_modules/ws/lib/extension.js"(exports$1, module) {
|
|
5528
5582
|
var { tokenChars } = require_validation();
|
|
5529
|
-
function push(dest,
|
|
5530
|
-
if (dest[
|
|
5531
|
-
else dest[
|
|
5583
|
+
function push(dest, name2, elem) {
|
|
5584
|
+
if (dest[name2] === void 0) dest[name2] = [elem];
|
|
5585
|
+
else dest[name2].push(elem);
|
|
5532
5586
|
}
|
|
5533
5587
|
function parse(header) {
|
|
5534
5588
|
const offers = /* @__PURE__ */ Object.create(null);
|
|
@@ -5554,12 +5608,12 @@ var init_dist = __esm({
|
|
|
5554
5608
|
throw new SyntaxError(`Unexpected character at index ${i}`);
|
|
5555
5609
|
}
|
|
5556
5610
|
if (end === -1) end = i;
|
|
5557
|
-
const
|
|
5611
|
+
const name2 = header.slice(start, end);
|
|
5558
5612
|
if (code === 44) {
|
|
5559
|
-
push(offers,
|
|
5613
|
+
push(offers, name2, params);
|
|
5560
5614
|
params = /* @__PURE__ */ Object.create(null);
|
|
5561
5615
|
} else {
|
|
5562
|
-
extensionName =
|
|
5616
|
+
extensionName = name2;
|
|
5563
5617
|
}
|
|
5564
5618
|
start = end = -1;
|
|
5565
5619
|
} else {
|
|
@@ -7269,13 +7323,13 @@ var init_dist = __esm({
|
|
|
7269
7323
|
* Validates that a string parameter is non-empty.
|
|
7270
7324
|
* Catches invalid inputs before they hit the network.
|
|
7271
7325
|
*/
|
|
7272
|
-
requireNonEmpty(value,
|
|
7326
|
+
requireNonEmpty(value, name2) {
|
|
7273
7327
|
if (!value || value.trim() === "") {
|
|
7274
7328
|
throw new DeskFreeError(
|
|
7275
7329
|
"client",
|
|
7276
|
-
|
|
7277
|
-
`${
|
|
7278
|
-
`Missing required parameter: ${
|
|
7330
|
+
name2,
|
|
7331
|
+
`${name2} is required and cannot be empty`,
|
|
7332
|
+
`Missing required parameter: ${name2}. Please provide a valid value.`
|
|
7279
7333
|
);
|
|
7280
7334
|
}
|
|
7281
7335
|
}
|
|
@@ -7971,7 +8025,7 @@ var init_dist = __esm({
|
|
|
7971
8025
|
WORKER_TOOLS = {
|
|
7972
8026
|
START_TASK: {
|
|
7973
8027
|
name: "deskfree_start_task",
|
|
7974
|
-
description: "
|
|
8028
|
+
description: "Load a task and start working on it. Returns full context (instructions, message history). Use deskfree_read_file to load any relevant files.",
|
|
7975
8029
|
parameters: Type.Object({
|
|
7976
8030
|
taskId: Type.String({ description: "Task UUID to claim" })
|
|
7977
8031
|
})
|
|
@@ -8028,8 +8082,8 @@ var init_dist = __esm({
|
|
|
8028
8082
|
PROPOSE: SHARED_TOOLS.PROPOSE
|
|
8029
8083
|
};
|
|
8030
8084
|
MAX_FULL_MESSAGES = 15;
|
|
8031
|
-
DESKFREE_AGENT_DIRECTIVE = `## DeskFree \u2014
|
|
8032
|
-
You
|
|
8085
|
+
DESKFREE_AGENT_DIRECTIVE = `## DeskFree \u2014 Main Thread
|
|
8086
|
+
You handle the main conversation thread. Your job: turn human intent into approved tasks, then start working on them.
|
|
8033
8087
|
|
|
8034
8088
|
**Main thread = short and snappy.** Keep responses to 1-3 sentences. Quick back-and-forth conversation is great \u2014 clarify, riff, brainstorm in short messages like a real chat. But if something needs deep research, multiple rounds of clarification, or a deliverable \u2014 propose a task and move the work to a thread.
|
|
8035
8089
|
|
|
@@ -8037,7 +8091,7 @@ You are the orchestrator. Your job: turn human intent into approved tasks, then
|
|
|
8037
8091
|
|
|
8038
8092
|
1. **Check state** \u2192 \`deskfree_state\` \u2014 see tasks, memory (a pinned file with accumulated knowledge), and files.
|
|
8039
8093
|
2. **Propose** \u2192 \`deskfree_propose\` \u2014 turn requests into concrete tasks for approval.
|
|
8040
|
-
3. **
|
|
8094
|
+
3. **Start work** \u2192 \`deskfree_dispatch_worker\` with the taskId. You'll then continue the work in the task thread.
|
|
8041
8095
|
4. **Communicate** \u2192 \`deskfree_send_message\` for updates outside task threads.
|
|
8042
8096
|
|
|
8043
8097
|
**Before proposing, qualify the request.** Figure out what kind of thing this is:
|
|
@@ -8047,20 +8101,21 @@ You are the orchestrator. Your job: turn human intent into approved tasks, then
|
|
|
8047
8101
|
|
|
8048
8102
|
**Match the human's energy.** Short message \u2192 short reply. Casual tone \u2192 casual response. Don't over-explain, don't lecture, don't pad responses.
|
|
8049
8103
|
|
|
8050
|
-
|
|
8104
|
+
In the main thread you propose and coordinate \u2014 the actual work happens in task threads. Use \`deskfree_dispatch_worker\` to start working on approved tasks.
|
|
8051
8105
|
- When a human writes in a task thread, decide:
|
|
8052
|
-
- **Continuation of the same task?** \u2192 reopen and
|
|
8053
|
-
- **New/different work request?** \u2192 propose it as a new task (don't reopen the old one
|
|
8106
|
+
- **Continuation of the same task?** \u2192 reopen and pick it back up.
|
|
8107
|
+
- **New/different work request?** \u2192 propose it as a new task (don't reopen the old one).
|
|
8054
8108
|
- **Just confirmation or deferred?** \u2192 leave it for now.
|
|
8055
8109
|
- Estimate token cost per task \u2014 consider files to read, reasoning, output.`;
|
|
8056
|
-
DESKFREE_WORKER_DIRECTIVE = `## DeskFree
|
|
8057
|
-
You
|
|
8110
|
+
DESKFREE_WORKER_DIRECTIVE = `## DeskFree \u2014 Task Thread
|
|
8111
|
+
You're in a task thread, focused on a specific piece of work. Same you as in the main thread \u2014 same voice, same personality.
|
|
8112
|
+
|
|
8058
8113
|
Tools: deskfree_state, deskfree_start_task, deskfree_read_file, deskfree_create_file, deskfree_update_file, deskfree_learning, deskfree_complete_task, deskfree_send_message, deskfree_propose.
|
|
8059
8114
|
|
|
8060
8115
|
**Context loading:**
|
|
8061
|
-
- If your first message contains \`<task_context>\`, the task is already
|
|
8116
|
+
- If your first message contains \`<task_context>\`, the task is already loaded. Start working immediately \u2014 do NOT call deskfree_start_task.
|
|
8062
8117
|
- If your first message contains \`<workspace_state>\`, use it for situational awareness (other tasks, memory, files).
|
|
8063
|
-
- If no pre-loaded context (edge case/fallback), call \`deskfree_start_task\` with your taskId to
|
|
8118
|
+
- If no pre-loaded context (edge case/fallback), call \`deskfree_start_task\` with your taskId to load it.
|
|
8064
8119
|
- If continuing from a previous conversation (you can see prior tool calls and context), respond directly to the human's latest message \u2014 do NOT call deskfree_start_task again.
|
|
8065
8120
|
|
|
8066
8121
|
**Orient \u2192 Align \u2192 Work.** Every new task follows this rhythm:
|
|
@@ -8083,7 +8138,7 @@ Tools: deskfree_state, deskfree_start_task, deskfree_read_file, deskfree_create_
|
|
|
8083
8138
|
- If you discover work that falls outside your task's scope, use \`deskfree_propose\` to suggest follow-up tasks immediately \u2014 don't wait until completion. Propose as you discover, then stay focused on your current task.
|
|
8084
8139
|
|
|
8085
8140
|
**Learnings:**
|
|
8086
|
-
- Use \`deskfree_learning\` to record observations worth remembering. A nightly
|
|
8141
|
+
- Use \`deskfree_learning\` to record observations worth remembering. A nightly cycle consolidates these into the Memory file. Record:
|
|
8087
8142
|
- **Preferences**: how the human wants things done ("prefers X over Y")
|
|
8088
8143
|
- **Corrections**: when the human corrects you ("actually, do X not Y")
|
|
8089
8144
|
- **Patterns**: recurring approaches that work ("for this type of task, always...")
|
|
@@ -8094,13 +8149,12 @@ Tools: deskfree_state, deskfree_start_task, deskfree_read_file, deskfree_create_
|
|
|
8094
8149
|
- Do NOT record one-time task details, things in project docs, or obvious/generic knowledge.
|
|
8095
8150
|
- If your first message contains \`<daily_observations>\`, these are recent raw observations not yet consolidated into Memory. Use them as additional context.
|
|
8096
8151
|
|
|
8097
|
-
**
|
|
8098
|
-
- Your context window is finite.
|
|
8099
|
-
-
|
|
8100
|
-
- Sub-agents are ephemeral helpers \u2014 they complete their assigned task and nothing else. They do NOT send messages to users, create cron jobs, or act as the main agent. Their final output is returned to you.
|
|
8152
|
+
**Delegation:**
|
|
8153
|
+
- Your context window is finite. Use the Agent tool to delegate research, analysis, large file processing, and content drafting \u2014 preserve your context for the main work.
|
|
8154
|
+
- Delegated work gets a fresh context window with standard tools (Read, Write, Bash, Grep, WebSearch, etc.) but NO DeskFree tools. Pre-load any file content they need into the prompt.
|
|
8101
8155
|
- Use \`run_in_background: true\` for parallel independent work.
|
|
8102
|
-
- During Orient, check Memory for
|
|
8103
|
-
- After
|
|
8156
|
+
- During Orient, check Memory for delegation patterns. Inject relevant ones into the prompt alongside the task.
|
|
8157
|
+
- After delegated work completes, reflect: did this reveal a useful pattern? Record via \`deskfree_learning\` so it's consolidated into Memory.
|
|
8104
8158
|
- Don't over-delegate: quick reads, simple lookups, and anything requiring DeskFree tools are faster inline.
|
|
8105
8159
|
|
|
8106
8160
|
**Completing tasks:**
|
|
@@ -8477,10 +8531,6 @@ function loadConfig() {
|
|
|
8477
8531
|
};
|
|
8478
8532
|
}
|
|
8479
8533
|
function mergeWithRemoteConfig(local, remote) {
|
|
8480
|
-
const stateDirOverridden = !!process.env["DESKFREE_STATE_DIR"];
|
|
8481
|
-
const toolsDirOverridden = !!process.env["DESKFREE_TOOLS_DIR"];
|
|
8482
|
-
const stateDir = stateDirOverridden ? local.stateDir : isDocker ? local.stateDir : join(homedir(), ".deskfree", remote.botId, "state");
|
|
8483
|
-
const toolsDir = toolsDirOverridden ? local.toolsDir : isDocker ? local.toolsDir : join(homedir(), ".deskfree", remote.botId, "tools");
|
|
8484
8534
|
let claudeCodePath;
|
|
8485
8535
|
if (remote.provider === "claude-code") {
|
|
8486
8536
|
try {
|
|
@@ -8495,8 +8545,6 @@ function mergeWithRemoteConfig(local, remote) {
|
|
|
8495
8545
|
}
|
|
8496
8546
|
return {
|
|
8497
8547
|
...local,
|
|
8498
|
-
stateDir,
|
|
8499
|
-
toolsDir,
|
|
8500
8548
|
claudeCodePath,
|
|
8501
8549
|
wsUrl: process.env["DESKFREE_WS_URL"] ?? remote.wsUrl,
|
|
8502
8550
|
model: process.env["DESKFREE_MODEL"] ?? remote.model,
|
|
@@ -8522,8 +8570,18 @@ var init_config = __esm({
|
|
|
8522
8570
|
init_dist();
|
|
8523
8571
|
isDocker = process.env["DOCKER"] === "1" || existsSync("/.dockerenv");
|
|
8524
8572
|
DEFAULTS = {
|
|
8525
|
-
stateDir: isDocker ? "/app/state" : join(
|
|
8526
|
-
|
|
8573
|
+
stateDir: isDocker ? "/app/state" : join(
|
|
8574
|
+
homedir(),
|
|
8575
|
+
".deskfree",
|
|
8576
|
+
process.env["DESKFREE_INSTANCE_NAME"] ?? "main",
|
|
8577
|
+
"state"
|
|
8578
|
+
),
|
|
8579
|
+
toolsDir: isDocker ? "/app/tools" : join(
|
|
8580
|
+
homedir(),
|
|
8581
|
+
".deskfree",
|
|
8582
|
+
process.env["DESKFREE_INSTANCE_NAME"] ?? "main",
|
|
8583
|
+
"tools"
|
|
8584
|
+
),
|
|
8527
8585
|
logLevel: "info",
|
|
8528
8586
|
healthPort: 3100
|
|
8529
8587
|
};
|
|
@@ -10775,9 +10833,9 @@ var require_event_target2 = __commonJS({
|
|
|
10775
10833
|
var require_extension2 = __commonJS({
|
|
10776
10834
|
"../../node_modules/ws/lib/extension.js"(exports$1, module) {
|
|
10777
10835
|
var { tokenChars } = require_validation2();
|
|
10778
|
-
function push(dest,
|
|
10779
|
-
if (dest[
|
|
10780
|
-
else dest[
|
|
10836
|
+
function push(dest, name2, elem) {
|
|
10837
|
+
if (dest[name2] === void 0) dest[name2] = [elem];
|
|
10838
|
+
else dest[name2].push(elem);
|
|
10781
10839
|
}
|
|
10782
10840
|
function parse(header) {
|
|
10783
10841
|
const offers = /* @__PURE__ */ Object.create(null);
|
|
@@ -10803,12 +10861,12 @@ var require_extension2 = __commonJS({
|
|
|
10803
10861
|
throw new SyntaxError(`Unexpected character at index ${i}`);
|
|
10804
10862
|
}
|
|
10805
10863
|
if (end === -1) end = i;
|
|
10806
|
-
const
|
|
10864
|
+
const name2 = header.slice(start, end);
|
|
10807
10865
|
if (code === 44) {
|
|
10808
|
-
push(offers,
|
|
10866
|
+
push(offers, name2, params);
|
|
10809
10867
|
params = /* @__PURE__ */ Object.create(null);
|
|
10810
10868
|
} else {
|
|
10811
|
-
extensionName =
|
|
10869
|
+
extensionName = name2;
|
|
10812
10870
|
}
|
|
10813
10871
|
start = end = -1;
|
|
10814
10872
|
} else {
|
|
@@ -12889,9 +12947,9 @@ function adaptTool(deskfreeTool) {
|
|
|
12889
12947
|
deskfreeTool.name,
|
|
12890
12948
|
deskfreeTool.description,
|
|
12891
12949
|
zodShape,
|
|
12892
|
-
async (
|
|
12950
|
+
async (args) => {
|
|
12893
12951
|
const result = await deskfreeTool.execute(
|
|
12894
|
-
|
|
12952
|
+
args
|
|
12895
12953
|
);
|
|
12896
12954
|
return {
|
|
12897
12955
|
content: result.content,
|
|
@@ -12922,7 +12980,7 @@ function createOrchestratorMcpServer(client, customTools = [], workerManager) {
|
|
|
12922
12980
|
function createDispatchWorkerTool(workerManager) {
|
|
12923
12981
|
return {
|
|
12924
12982
|
name: "deskfree_dispatch_worker",
|
|
12925
|
-
description: "
|
|
12983
|
+
description: "Start working on an approved task in its thread. You will pick up the task, load context, and handle follow-up messages there. Pass the taskId of the approved task.",
|
|
12926
12984
|
parameters: {
|
|
12927
12985
|
type: "object",
|
|
12928
12986
|
properties: {
|
|
@@ -12990,15 +13048,15 @@ function containsInjectionPattern(content) {
|
|
|
12990
13048
|
return INJECTION_PATTERNS.some((pattern) => pattern.test(content));
|
|
12991
13049
|
}
|
|
12992
13050
|
function withContentScan(execute, extractContent, scanner) {
|
|
12993
|
-
return async (
|
|
12994
|
-
const content = extractContent(
|
|
13051
|
+
return async (args) => {
|
|
13052
|
+
const content = extractContent(args);
|
|
12995
13053
|
if (content) {
|
|
12996
13054
|
const result = await scanner.scan(content);
|
|
12997
13055
|
if (!result.safe) {
|
|
12998
13056
|
return `Security check failed: ${result.reason ?? "content rejected"}. File not updated.`;
|
|
12999
13057
|
}
|
|
13000
13058
|
}
|
|
13001
|
-
return execute(
|
|
13059
|
+
return execute(args);
|
|
13002
13060
|
};
|
|
13003
13061
|
}
|
|
13004
13062
|
function validateDownloadUrl(url) {
|
|
@@ -13133,7 +13191,7 @@ function createWorkerMcpServer(client, customTools = [], contentScanner, dailyLo
|
|
|
13133
13191
|
if ((t.name === "deskfree_update_file" || t.name === "deskfree_create_file") && contentScanner) {
|
|
13134
13192
|
const wrappedExecute = withContentScan(
|
|
13135
13193
|
t.execute,
|
|
13136
|
-
(
|
|
13194
|
+
(args) => typeof args["content"] === "string" ? args["content"] : null,
|
|
13137
13195
|
contentScanner
|
|
13138
13196
|
);
|
|
13139
13197
|
return {
|
|
@@ -14485,8 +14543,9 @@ async function startAgent(opts) {
|
|
|
14485
14543
|
model: config.model,
|
|
14486
14544
|
platform: isDocker2 ? "Docker" : process.platform === "darwin" ? "macOS" : "Linux",
|
|
14487
14545
|
runtimeVersion,
|
|
14488
|
-
maxConcurrentWorkers: 5
|
|
14546
|
+
maxConcurrentWorkers: 5,
|
|
14489
14547
|
// updated after WorkerManager is created
|
|
14548
|
+
instanceName: process.env["DESKFREE_INSTANCE_NAME"] || void 0
|
|
14490
14549
|
};
|
|
14491
14550
|
mkdirSync(config.stateDir, { recursive: true });
|
|
14492
14551
|
mkdirSync(config.toolsDir, { recursive: true });
|
|
@@ -14724,10 +14783,11 @@ var init_entrypoint = __esm({
|
|
|
14724
14783
|
});
|
|
14725
14784
|
|
|
14726
14785
|
// src/bin.ts
|
|
14727
|
-
|
|
14728
|
-
var
|
|
14786
|
+
init_paths();
|
|
14787
|
+
var [name, cleanArgs] = parseName(process.argv.slice(2));
|
|
14788
|
+
var command = cleanArgs[0];
|
|
14729
14789
|
if (command === "install") {
|
|
14730
|
-
let token =
|
|
14790
|
+
let token = cleanArgs[1];
|
|
14731
14791
|
if (!token) {
|
|
14732
14792
|
const { createInterface } = await import('readline');
|
|
14733
14793
|
const rl = createInterface({
|
|
@@ -14749,20 +14809,20 @@ if (command === "install") {
|
|
|
14749
14809
|
}
|
|
14750
14810
|
}
|
|
14751
14811
|
const { install: install2 } = await Promise.resolve().then(() => (init_install(), install_exports));
|
|
14752
|
-
install2(token);
|
|
14812
|
+
install2(token, name);
|
|
14753
14813
|
} else if (command === "uninstall") {
|
|
14754
14814
|
const { uninstall: uninstall2 } = await Promise.resolve().then(() => (init_uninstall(), uninstall_exports));
|
|
14755
|
-
uninstall2();
|
|
14815
|
+
uninstall2(name);
|
|
14756
14816
|
} else if (command === "status") {
|
|
14757
14817
|
const { status: status2 } = await Promise.resolve().then(() => (init_status(), status_exports));
|
|
14758
|
-
status2();
|
|
14818
|
+
status2(name);
|
|
14759
14819
|
} else if (command === "restart") {
|
|
14760
14820
|
const { restart: restart2 } = await Promise.resolve().then(() => (init_restart(), restart_exports));
|
|
14761
|
-
restart2();
|
|
14821
|
+
restart2(name);
|
|
14762
14822
|
} else if (command === "logs") {
|
|
14763
|
-
const follow =
|
|
14823
|
+
const follow = cleanArgs.includes("-f") || cleanArgs.includes("--follow");
|
|
14764
14824
|
const { logs: logs2 } = await Promise.resolve().then(() => (init_logs(), logs_exports));
|
|
14765
|
-
logs2(follow);
|
|
14825
|
+
logs2(follow, name);
|
|
14766
14826
|
} else {
|
|
14767
14827
|
let handleShutdown = function(signal) {
|
|
14768
14828
|
log.info(`Received ${signal} \u2014 shutting down...`);
|
|
@@ -14777,7 +14837,7 @@ if (command === "install") {
|
|
|
14777
14837
|
};
|
|
14778
14838
|
let token;
|
|
14779
14839
|
if (command === "start") {
|
|
14780
|
-
token =
|
|
14840
|
+
token = cleanArgs[1];
|
|
14781
14841
|
} else if (command && !command.startsWith("-")) {
|
|
14782
14842
|
token = command;
|
|
14783
14843
|
}
|