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