@questionbase/deskfree 0.4.5 → 0.4.7
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 +461 -140
- package/dist/bin.js.map +1 -1
- package/dist/cli/install.js +112 -12
- package/dist/cli/install.js.map +1 -1
- package/dist/cli/uninstall.js +43 -9
- package/dist/cli/uninstall.js.map +1 -1
- package/dist/index.js +187 -69
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
3
|
import { execSync, execFileSync, execFile } from 'child_process';
|
|
4
|
-
import { writeFileSync, chmodSync, existsSync, unlinkSync,
|
|
4
|
+
import { mkdirSync, writeFileSync, chmodSync, existsSync, unlinkSync, appendFileSync, readdirSync, readFileSync, statSync, createWriteStream } from 'fs';
|
|
5
|
+
import { homedir } from 'os';
|
|
6
|
+
import { dirname, join, extname } from 'path';
|
|
5
7
|
import { createRequire as createRequire$1 } from 'module';
|
|
6
|
-
import { join, dirname, extname } from 'path';
|
|
7
8
|
import { query, createSdkMcpServer, tool } from '@anthropic-ai/claude-agent-sdk';
|
|
8
9
|
import { z } from 'zod';
|
|
9
10
|
import { appendFile, readFile, mkdir, unlink } from 'fs/promises';
|
|
@@ -57,7 +58,90 @@ var install_exports = {};
|
|
|
57
58
|
__export(install_exports, {
|
|
58
59
|
install: () => install
|
|
59
60
|
});
|
|
60
|
-
function
|
|
61
|
+
function getMacPaths() {
|
|
62
|
+
const home = homedir();
|
|
63
|
+
const deskfreeDir = join(home, ".deskfree");
|
|
64
|
+
return {
|
|
65
|
+
deskfreeDir,
|
|
66
|
+
envFile: join(deskfreeDir, ".env"),
|
|
67
|
+
launcher: join(deskfreeDir, "launcher.sh"),
|
|
68
|
+
logDir: join(deskfreeDir, "logs"),
|
|
69
|
+
plist: join(home, "Library", "LaunchAgents", `${PLIST_LABEL}.plist`)
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function installMac(token) {
|
|
73
|
+
const paths = getMacPaths();
|
|
74
|
+
let nodeBinDir;
|
|
75
|
+
try {
|
|
76
|
+
const nodePath = execSync("which node", { encoding: "utf8" }).trim();
|
|
77
|
+
nodeBinDir = dirname(nodePath);
|
|
78
|
+
} catch {
|
|
79
|
+
console.error("Error: node not found in PATH");
|
|
80
|
+
process.exit(1);
|
|
81
|
+
}
|
|
82
|
+
mkdirSync(paths.deskfreeDir, { recursive: true });
|
|
83
|
+
mkdirSync(paths.logDir, { recursive: true });
|
|
84
|
+
mkdirSync(dirname(paths.plist), { recursive: true });
|
|
85
|
+
writeFileSync(paths.envFile, `DESKFREE_LAUNCH=${token}
|
|
86
|
+
`, { mode: 384 });
|
|
87
|
+
chmodSync(paths.envFile, 384);
|
|
88
|
+
console.log(`Wrote ${paths.envFile}`);
|
|
89
|
+
const launcher = `#!/bin/bash
|
|
90
|
+
set -euo pipefail
|
|
91
|
+
|
|
92
|
+
export PATH="${nodeBinDir}:$PATH"
|
|
93
|
+
|
|
94
|
+
# Update to latest version before starting
|
|
95
|
+
npm install -g ${PACKAGE} 2>/dev/null || true
|
|
96
|
+
|
|
97
|
+
# Source env
|
|
98
|
+
set -a
|
|
99
|
+
source "${paths.envFile}"
|
|
100
|
+
set +a
|
|
101
|
+
|
|
102
|
+
exec deskfree-agent start
|
|
103
|
+
`;
|
|
104
|
+
writeFileSync(paths.launcher, launcher, { mode: 493 });
|
|
105
|
+
chmodSync(paths.launcher, 493);
|
|
106
|
+
console.log(`Wrote ${paths.launcher}`);
|
|
107
|
+
const plist = `<?xml version="1.0" encoding="UTF-8"?>
|
|
108
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
109
|
+
<plist version="1.0">
|
|
110
|
+
<dict>
|
|
111
|
+
<key>Label</key>
|
|
112
|
+
<string>${PLIST_LABEL}</string>
|
|
113
|
+
<key>ProgramArguments</key>
|
|
114
|
+
<array>
|
|
115
|
+
<string>${paths.launcher}</string>
|
|
116
|
+
</array>
|
|
117
|
+
<key>KeepAlive</key>
|
|
118
|
+
<true/>
|
|
119
|
+
<key>RunAtLoad</key>
|
|
120
|
+
<true/>
|
|
121
|
+
<key>StandardOutPath</key>
|
|
122
|
+
<string>${join(paths.logDir, "stdout.log")}</string>
|
|
123
|
+
<key>StandardErrorPath</key>
|
|
124
|
+
<string>${join(paths.logDir, "stderr.log")}</string>
|
|
125
|
+
<key>ThrottleInterval</key>
|
|
126
|
+
<integer>10</integer>
|
|
127
|
+
</dict>
|
|
128
|
+
</plist>
|
|
129
|
+
`;
|
|
130
|
+
writeFileSync(paths.plist, plist);
|
|
131
|
+
console.log(`Wrote ${paths.plist}`);
|
|
132
|
+
try {
|
|
133
|
+
execSync(`launchctl bootout gui/$(id -u) ${paths.plist}`, {
|
|
134
|
+
stdio: "ignore"
|
|
135
|
+
});
|
|
136
|
+
} catch {
|
|
137
|
+
}
|
|
138
|
+
execSync(`launchctl bootstrap gui/$(id -u) ${paths.plist}`);
|
|
139
|
+
console.log(`
|
|
140
|
+
Service ${PLIST_LABEL} installed and started.`);
|
|
141
|
+
console.log(`Check status: launchctl print gui/$(id -u)/${PLIST_LABEL}`);
|
|
142
|
+
console.log(`Logs: tail -f ${join(paths.logDir, "stdout.log")}`);
|
|
143
|
+
}
|
|
144
|
+
function installLinux(token) {
|
|
61
145
|
if (process.getuid?.() !== 0) {
|
|
62
146
|
console.error("Error: install must be run as root (use sudo)");
|
|
63
147
|
process.exit(1);
|
|
@@ -69,10 +153,12 @@ function install(token) {
|
|
|
69
153
|
console.error("Error: npx not found in PATH");
|
|
70
154
|
process.exit(1);
|
|
71
155
|
}
|
|
72
|
-
writeFileSync(
|
|
73
|
-
`, {
|
|
74
|
-
|
|
75
|
-
|
|
156
|
+
writeFileSync(SYSTEMD_ENV_FILE, `DESKFREE_LAUNCH=${token}
|
|
157
|
+
`, {
|
|
158
|
+
mode: 384
|
|
159
|
+
});
|
|
160
|
+
chmodSync(SYSTEMD_ENV_FILE, 384);
|
|
161
|
+
console.log(`Wrote ${SYSTEMD_ENV_FILE}`);
|
|
76
162
|
const unit = `[Unit]
|
|
77
163
|
Description=DeskFree Agent
|
|
78
164
|
After=network-online.target
|
|
@@ -80,8 +166,9 @@ Wants=network-online.target
|
|
|
80
166
|
|
|
81
167
|
[Service]
|
|
82
168
|
Type=simple
|
|
169
|
+
ExecStartPre=${npxPath} ${PACKAGE} --version
|
|
83
170
|
ExecStart=${npxPath} ${PACKAGE} start
|
|
84
|
-
EnvironmentFile=${
|
|
171
|
+
EnvironmentFile=${SYSTEMD_ENV_FILE}
|
|
85
172
|
Environment=NODE_ENV=production
|
|
86
173
|
Restart=always
|
|
87
174
|
RestartSec=10
|
|
@@ -89,21 +176,33 @@ RestartSec=10
|
|
|
89
176
|
[Install]
|
|
90
177
|
WantedBy=multi-user.target
|
|
91
178
|
`;
|
|
92
|
-
writeFileSync(
|
|
93
|
-
console.log(`Wrote ${
|
|
179
|
+
writeFileSync(SYSTEMD_SERVICE_FILE, unit);
|
|
180
|
+
console.log(`Wrote ${SYSTEMD_SERVICE_FILE}`);
|
|
94
181
|
execSync("systemctl daemon-reload");
|
|
95
182
|
execSync(`systemctl enable ${SERVICE_NAME}`);
|
|
96
183
|
execSync(`systemctl start ${SERVICE_NAME}`);
|
|
97
|
-
console.log(`
|
|
184
|
+
console.log(`
|
|
185
|
+
Service ${SERVICE_NAME} installed and started.`);
|
|
98
186
|
console.log(`Check status: systemctl status ${SERVICE_NAME}`);
|
|
99
187
|
}
|
|
100
|
-
|
|
188
|
+
function install(token) {
|
|
189
|
+
if (process.platform === "darwin") {
|
|
190
|
+
installMac(token);
|
|
191
|
+
} else if (process.platform === "linux") {
|
|
192
|
+
installLinux(token);
|
|
193
|
+
} else {
|
|
194
|
+
console.error(`Unsupported platform: ${process.platform}`);
|
|
195
|
+
process.exit(1);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
var SERVICE_NAME, PACKAGE, PLIST_LABEL, SYSTEMD_SERVICE_FILE, SYSTEMD_ENV_FILE;
|
|
101
199
|
var init_install = __esm({
|
|
102
200
|
"src/cli/install.ts"() {
|
|
103
201
|
SERVICE_NAME = "deskfree-agent";
|
|
104
|
-
SERVICE_FILE = `/etc/systemd/system/${SERVICE_NAME}.service`;
|
|
105
|
-
ENV_FILE = `/etc/${SERVICE_NAME}.env`;
|
|
106
202
|
PACKAGE = "@questionbase/deskfree@latest";
|
|
203
|
+
PLIST_LABEL = "com.deskfree.agent";
|
|
204
|
+
SYSTEMD_SERVICE_FILE = `/etc/systemd/system/${SERVICE_NAME}.service`;
|
|
205
|
+
SYSTEMD_ENV_FILE = `/etc/${SERVICE_NAME}.env`;
|
|
107
206
|
}
|
|
108
207
|
});
|
|
109
208
|
|
|
@@ -112,7 +211,28 @@ var uninstall_exports = {};
|
|
|
112
211
|
__export(uninstall_exports, {
|
|
113
212
|
uninstall: () => uninstall
|
|
114
213
|
});
|
|
115
|
-
function
|
|
214
|
+
function uninstallMac() {
|
|
215
|
+
const home = homedir();
|
|
216
|
+
const plist = join(home, "Library", "LaunchAgents", `${PLIST_LABEL2}.plist`);
|
|
217
|
+
const deskfreeDir = join(home, ".deskfree");
|
|
218
|
+
const envFile = join(deskfreeDir, ".env");
|
|
219
|
+
const launcher = join(deskfreeDir, "launcher.sh");
|
|
220
|
+
try {
|
|
221
|
+
execSync(`launchctl bootout gui/$(id -u) ${plist}`, { stdio: "ignore" });
|
|
222
|
+
} catch {
|
|
223
|
+
}
|
|
224
|
+
for (const file of [plist, envFile, launcher]) {
|
|
225
|
+
if (existsSync(file)) {
|
|
226
|
+
unlinkSync(file);
|
|
227
|
+
console.log(`Removed ${file}`);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
console.log(`Service ${PLIST_LABEL2} uninstalled.`);
|
|
231
|
+
console.log(
|
|
232
|
+
`Note: logs and state in ${deskfreeDir} were preserved. Remove manually if desired.`
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
function uninstallLinux() {
|
|
116
236
|
if (process.getuid?.() !== 0) {
|
|
117
237
|
console.error("Error: uninstall must be run as root (use sudo)");
|
|
118
238
|
process.exit(1);
|
|
@@ -125,23 +245,104 @@ function uninstall() {
|
|
|
125
245
|
execSync(`systemctl disable ${SERVICE_NAME2}`, { stdio: "ignore" });
|
|
126
246
|
} catch {
|
|
127
247
|
}
|
|
128
|
-
if (existsSync(
|
|
129
|
-
unlinkSync(
|
|
130
|
-
console.log(`Removed ${
|
|
248
|
+
if (existsSync(SYSTEMD_SERVICE_FILE2)) {
|
|
249
|
+
unlinkSync(SYSTEMD_SERVICE_FILE2);
|
|
250
|
+
console.log(`Removed ${SYSTEMD_SERVICE_FILE2}`);
|
|
131
251
|
}
|
|
132
|
-
if (existsSync(
|
|
133
|
-
unlinkSync(
|
|
134
|
-
console.log(`Removed ${
|
|
252
|
+
if (existsSync(SYSTEMD_ENV_FILE2)) {
|
|
253
|
+
unlinkSync(SYSTEMD_ENV_FILE2);
|
|
254
|
+
console.log(`Removed ${SYSTEMD_ENV_FILE2}`);
|
|
135
255
|
}
|
|
136
256
|
execSync("systemctl daemon-reload");
|
|
137
257
|
console.log(`Service ${SERVICE_NAME2} uninstalled.`);
|
|
138
258
|
}
|
|
139
|
-
|
|
259
|
+
function uninstall() {
|
|
260
|
+
if (process.platform === "darwin") {
|
|
261
|
+
uninstallMac();
|
|
262
|
+
} else if (process.platform === "linux") {
|
|
263
|
+
uninstallLinux();
|
|
264
|
+
} else {
|
|
265
|
+
console.error(`Unsupported platform: ${process.platform}`);
|
|
266
|
+
process.exit(1);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
var SERVICE_NAME2, PLIST_LABEL2, SYSTEMD_SERVICE_FILE2, SYSTEMD_ENV_FILE2;
|
|
140
270
|
var init_uninstall = __esm({
|
|
141
271
|
"src/cli/uninstall.ts"() {
|
|
142
272
|
SERVICE_NAME2 = "deskfree-agent";
|
|
143
|
-
|
|
144
|
-
|
|
273
|
+
PLIST_LABEL2 = "com.deskfree.agent";
|
|
274
|
+
SYSTEMD_SERVICE_FILE2 = `/etc/systemd/system/${SERVICE_NAME2}.service`;
|
|
275
|
+
SYSTEMD_ENV_FILE2 = `/etc/${SERVICE_NAME2}.env`;
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
// src/cli/status.ts
|
|
280
|
+
var status_exports = {};
|
|
281
|
+
__export(status_exports, {
|
|
282
|
+
status: () => status
|
|
283
|
+
});
|
|
284
|
+
function statusMac() {
|
|
285
|
+
const home = homedir();
|
|
286
|
+
const plist = join(home, "Library", "LaunchAgents", `${PLIST_LABEL3}.plist`);
|
|
287
|
+
if (!existsSync(plist)) {
|
|
288
|
+
console.log("DeskFree Agent is not installed.");
|
|
289
|
+
console.log(`Run: npx @questionbase/deskfree@latest install <token>`);
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
console.log("DeskFree Agent (macOS LaunchAgent)\n");
|
|
293
|
+
try {
|
|
294
|
+
const output = execSync(
|
|
295
|
+
`launchctl print gui/$(id -u)/${PLIST_LABEL3} 2>&1`,
|
|
296
|
+
{ encoding: "utf8" }
|
|
297
|
+
);
|
|
298
|
+
const pidMatch = output.match(/pid\s*=\s*(\d+)/);
|
|
299
|
+
const stateMatch = output.match(/state\s*=\s*(\w+)/);
|
|
300
|
+
if (pidMatch) console.log(` PID: ${pidMatch[1]}`);
|
|
301
|
+
if (stateMatch) console.log(` State: ${stateMatch[1]}`);
|
|
302
|
+
const logDir = join(home, ".deskfree", "logs");
|
|
303
|
+
console.log(` Logs: ${logDir}/stdout.log`);
|
|
304
|
+
console.log(` Plist: ${plist}`);
|
|
305
|
+
} catch {
|
|
306
|
+
console.log(" Status: not running (service may be unloaded)");
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
function statusLinux() {
|
|
310
|
+
const serviceFile = `/etc/systemd/system/${SYSTEMD_SERVICE_NAME}.service`;
|
|
311
|
+
if (!existsSync(serviceFile)) {
|
|
312
|
+
console.log("DeskFree Agent is not installed.");
|
|
313
|
+
console.log(`Run: sudo npx @questionbase/deskfree@latest install <token>`);
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
console.log("DeskFree Agent (systemd service)\n");
|
|
317
|
+
try {
|
|
318
|
+
const output = execSync(
|
|
319
|
+
`systemctl status ${SYSTEMD_SERVICE_NAME} --no-pager 2>&1`,
|
|
320
|
+
{ encoding: "utf8" }
|
|
321
|
+
);
|
|
322
|
+
console.log(output);
|
|
323
|
+
} catch (err) {
|
|
324
|
+
if (err && typeof err === "object" && "stdout" in err) {
|
|
325
|
+
console.log(err.stdout);
|
|
326
|
+
} else {
|
|
327
|
+
console.log(" Status: unknown (could not query systemd)");
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
function status() {
|
|
332
|
+
if (process.platform === "darwin") {
|
|
333
|
+
statusMac();
|
|
334
|
+
} else if (process.platform === "linux") {
|
|
335
|
+
statusLinux();
|
|
336
|
+
} else {
|
|
337
|
+
console.error(`Unsupported platform: ${process.platform}`);
|
|
338
|
+
process.exit(1);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
var PLIST_LABEL3, SYSTEMD_SERVICE_NAME;
|
|
342
|
+
var init_status = __esm({
|
|
343
|
+
"src/cli/status.ts"() {
|
|
344
|
+
PLIST_LABEL3 = "com.deskfree.agent";
|
|
345
|
+
SYSTEMD_SERVICE_NAME = "deskfree-agent";
|
|
145
346
|
}
|
|
146
347
|
});
|
|
147
348
|
function toErrorMessage(error) {
|
|
@@ -2554,6 +2755,41 @@ function createWorkerTools(client, options) {
|
|
|
2554
2755
|
return errorResult(err);
|
|
2555
2756
|
}
|
|
2556
2757
|
}),
|
|
2758
|
+
createTool(WORKER_TOOLS.PROPOSE, async (params) => {
|
|
2759
|
+
try {
|
|
2760
|
+
const context = validateStringParam(params, "context", false);
|
|
2761
|
+
const taskId = validateStringParam(params, "taskId", false);
|
|
2762
|
+
const rawTasks = params.tasks;
|
|
2763
|
+
if (!Array.isArray(rawTasks) || rawTasks.length === 0) {
|
|
2764
|
+
throw new Error("tasks must be a non-empty array of task objects");
|
|
2765
|
+
}
|
|
2766
|
+
const tasks = rawTasks;
|
|
2767
|
+
for (let i = 0; i < tasks.length; i++) {
|
|
2768
|
+
const task = tasks[i];
|
|
2769
|
+
if (!task || typeof task !== "object") {
|
|
2770
|
+
throw new Error(`tasks[${i}] must be an object`);
|
|
2771
|
+
}
|
|
2772
|
+
if (!task.title || typeof task.title !== "string" || task.title.trim() === "") {
|
|
2773
|
+
throw new Error(`tasks[${i}].title must be a non-empty string`);
|
|
2774
|
+
}
|
|
2775
|
+
}
|
|
2776
|
+
await client.proposePlan({
|
|
2777
|
+
context,
|
|
2778
|
+
tasks,
|
|
2779
|
+
taskId
|
|
2780
|
+
});
|
|
2781
|
+
return {
|
|
2782
|
+
content: [
|
|
2783
|
+
{
|
|
2784
|
+
type: "text",
|
|
2785
|
+
text: `Proposal created with ${tasks.length} task(s)`
|
|
2786
|
+
}
|
|
2787
|
+
]
|
|
2788
|
+
};
|
|
2789
|
+
} catch (err) {
|
|
2790
|
+
return errorResult(err);
|
|
2791
|
+
}
|
|
2792
|
+
}),
|
|
2557
2793
|
createTool(WORKER_TOOLS.COMPLETE_TASK, async (params) => {
|
|
2558
2794
|
try {
|
|
2559
2795
|
const taskId = validateStringParam(params, "taskId", true);
|
|
@@ -6411,96 +6647,96 @@ var init_dist = __esm({
|
|
|
6411
6647
|
this.statusCode = statusCode;
|
|
6412
6648
|
}
|
|
6413
6649
|
static fromResponse(response, procedure, responseText) {
|
|
6414
|
-
const
|
|
6650
|
+
const status2 = response.status;
|
|
6415
6651
|
const statusText = response.statusText;
|
|
6416
|
-
if (
|
|
6652
|
+
if (status2 === 401) {
|
|
6417
6653
|
return new _DeskFreeError(
|
|
6418
6654
|
"auth",
|
|
6419
6655
|
procedure,
|
|
6420
|
-
`Authentication failed: ${
|
|
6656
|
+
`Authentication failed: ${status2} ${statusText} \u2014 ${responseText}`,
|
|
6421
6657
|
"Your bot token is invalid or has expired. Please check your authentication credentials.",
|
|
6422
|
-
|
|
6658
|
+
status2
|
|
6423
6659
|
);
|
|
6424
6660
|
}
|
|
6425
|
-
if (
|
|
6661
|
+
if (status2 === 403) {
|
|
6426
6662
|
return new _DeskFreeError(
|
|
6427
6663
|
"auth",
|
|
6428
6664
|
procedure,
|
|
6429
|
-
`Authorization failed: ${
|
|
6665
|
+
`Authorization failed: ${status2} ${statusText} \u2014 ${responseText}`,
|
|
6430
6666
|
"Your bot does not have permission to perform this action. Contact your administrator.",
|
|
6431
|
-
|
|
6667
|
+
status2
|
|
6432
6668
|
);
|
|
6433
6669
|
}
|
|
6434
|
-
if (
|
|
6670
|
+
if (status2 === 400) {
|
|
6435
6671
|
return new _DeskFreeError(
|
|
6436
6672
|
"client",
|
|
6437
6673
|
procedure,
|
|
6438
|
-
`Bad request: ${
|
|
6674
|
+
`Bad request: ${status2} ${statusText} \u2014 ${responseText}`,
|
|
6439
6675
|
"The request was invalid. Please check your input parameters and try again.",
|
|
6440
|
-
|
|
6676
|
+
status2
|
|
6441
6677
|
);
|
|
6442
6678
|
}
|
|
6443
|
-
if (
|
|
6679
|
+
if (status2 === 404) {
|
|
6444
6680
|
return new _DeskFreeError(
|
|
6445
6681
|
"client",
|
|
6446
6682
|
procedure,
|
|
6447
|
-
`Resource not found: ${
|
|
6683
|
+
`Resource not found: ${status2} ${statusText} \u2014 ${responseText}`,
|
|
6448
6684
|
procedure.includes("task") ? "The specified task was not found or is not available. Use deskfree_state to see available tasks." : "The requested resource was not found. Please check your input and try again.",
|
|
6449
|
-
|
|
6685
|
+
status2
|
|
6450
6686
|
);
|
|
6451
6687
|
}
|
|
6452
|
-
if (
|
|
6688
|
+
if (status2 === 409) {
|
|
6453
6689
|
return new _DeskFreeError(
|
|
6454
6690
|
"client",
|
|
6455
6691
|
procedure,
|
|
6456
|
-
`Conflict: ${
|
|
6692
|
+
`Conflict: ${status2} ${statusText} \u2014 ${responseText}`,
|
|
6457
6693
|
procedure.includes("start_task") || procedure.includes("claim") ? "The resource is already in use by another process. Use deskfree_state to see current status and try a different resource." : "The request conflicts with the current state of the resource. Please refresh and try again.",
|
|
6458
|
-
|
|
6694
|
+
status2
|
|
6459
6695
|
);
|
|
6460
6696
|
}
|
|
6461
|
-
if (
|
|
6697
|
+
if (status2 === 422) {
|
|
6462
6698
|
return new _DeskFreeError(
|
|
6463
6699
|
"client",
|
|
6464
6700
|
procedure,
|
|
6465
|
-
`Validation failed: ${
|
|
6701
|
+
`Validation failed: ${status2} ${statusText} \u2014 ${responseText}`,
|
|
6466
6702
|
"The request data failed validation. Please check all required fields and data formats.",
|
|
6467
|
-
|
|
6703
|
+
status2
|
|
6468
6704
|
);
|
|
6469
6705
|
}
|
|
6470
|
-
if (
|
|
6706
|
+
if (status2 === 429) {
|
|
6471
6707
|
return new _DeskFreeError(
|
|
6472
6708
|
"client",
|
|
6473
6709
|
procedure,
|
|
6474
|
-
`Rate limit exceeded: ${
|
|
6710
|
+
`Rate limit exceeded: ${status2} ${statusText} \u2014 ${responseText}`,
|
|
6475
6711
|
"Too many requests. Please wait a moment before trying again.",
|
|
6476
|
-
|
|
6712
|
+
status2
|
|
6477
6713
|
);
|
|
6478
6714
|
}
|
|
6479
|
-
if (
|
|
6480
|
-
const serverErrorMessage =
|
|
6715
|
+
if (status2 >= 500 && status2 < 600) {
|
|
6716
|
+
const serverErrorMessage = status2 === 502 || status2 === 503 ? "DeskFree service is temporarily unavailable due to maintenance or high load. Please try again in a few minutes." : status2 === 504 ? "The request timed out on the server. This may be due to high load. Please try again with a smaller request or wait a few minutes." : "DeskFree service encountered an internal error. Please try again in a few minutes.";
|
|
6481
6717
|
return new _DeskFreeError(
|
|
6482
6718
|
"server",
|
|
6483
6719
|
procedure,
|
|
6484
|
-
`Server error: ${
|
|
6720
|
+
`Server error: ${status2} ${statusText} \u2014 ${responseText}`,
|
|
6485
6721
|
serverErrorMessage,
|
|
6486
|
-
|
|
6722
|
+
status2
|
|
6487
6723
|
);
|
|
6488
6724
|
}
|
|
6489
|
-
if (
|
|
6725
|
+
if (status2 >= 400 && status2 < 500) {
|
|
6490
6726
|
return new _DeskFreeError(
|
|
6491
6727
|
"client",
|
|
6492
6728
|
procedure,
|
|
6493
|
-
`Client error: ${
|
|
6729
|
+
`Client error: ${status2} ${statusText} \u2014 ${responseText}`,
|
|
6494
6730
|
"The request was not accepted by the server. Please check your input and try again.",
|
|
6495
|
-
|
|
6731
|
+
status2
|
|
6496
6732
|
);
|
|
6497
6733
|
}
|
|
6498
6734
|
return new _DeskFreeError(
|
|
6499
6735
|
"client",
|
|
6500
6736
|
procedure,
|
|
6501
|
-
`HTTP error: ${
|
|
6502
|
-
`Request failed with error ${
|
|
6503
|
-
|
|
6737
|
+
`HTTP error: ${status2} ${statusText} \u2014 ${responseText}`,
|
|
6738
|
+
`Request failed with error ${status2}. Please try again or contact support if the problem persists.`,
|
|
6739
|
+
status2
|
|
6504
6740
|
);
|
|
6505
6741
|
}
|
|
6506
6742
|
static timeout(procedure, timeoutMs) {
|
|
@@ -7361,7 +7597,10 @@ You are the orchestrator. Your job: turn human intent into approved tasks, then
|
|
|
7361
7597
|
**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.
|
|
7362
7598
|
|
|
7363
7599
|
You do NOT claim tasks, complete tasks, or do work directly \u2014 you have no access to deskfree_start_task or deskfree_complete_task. Use \`deskfree_dispatch_worker\` to dispatch a worker for each approved task.
|
|
7364
|
-
- When a human writes in a task thread, decide:
|
|
7600
|
+
- When a human writes in a task thread, decide:
|
|
7601
|
+
- **Continuation of the same task?** \u2192 reopen and dispatch a worker.
|
|
7602
|
+
- **New/different work request?** \u2192 propose it as a new task (don't reopen the old one or do the work yourself).
|
|
7603
|
+
- **Just confirmation or deferred?** \u2192 leave it for now.
|
|
7365
7604
|
- Estimate token cost per task \u2014 consider files to read, reasoning, output.`;
|
|
7366
7605
|
DESKFREE_WORKER_DIRECTIVE = `## DeskFree Worker
|
|
7367
7606
|
You are a worker sub-agent. Your first message contains pre-loaded context \u2014 use it directly.
|
|
@@ -7814,18 +8053,7 @@ function runOrchestrator(opts) {
|
|
|
7814
8053
|
"deskfree-orchestrator": orchestratorServer
|
|
7815
8054
|
},
|
|
7816
8055
|
tools: [],
|
|
7817
|
-
allowedTools:
|
|
7818
|
-
"mcp__deskfree-orchestrator__*",
|
|
7819
|
-
"Read",
|
|
7820
|
-
"Write",
|
|
7821
|
-
"Edit",
|
|
7822
|
-
"Bash",
|
|
7823
|
-
"Glob",
|
|
7824
|
-
"Grep",
|
|
7825
|
-
"WebSearch",
|
|
7826
|
-
"WebFetch",
|
|
7827
|
-
"NotebookEdit"
|
|
7828
|
-
],
|
|
8056
|
+
allowedTools: ORCHESTRATOR_ALLOWED_TOOLS,
|
|
7829
8057
|
disallowedTools: DISALLOWED_BUILTIN_TOOLS
|
|
7830
8058
|
}
|
|
7831
8059
|
});
|
|
@@ -7846,18 +8074,7 @@ function runHeartbeat(opts) {
|
|
|
7846
8074
|
"deskfree-orchestrator": orchestratorServer
|
|
7847
8075
|
},
|
|
7848
8076
|
tools: [],
|
|
7849
|
-
allowedTools:
|
|
7850
|
-
"mcp__deskfree-orchestrator__*",
|
|
7851
|
-
"Read",
|
|
7852
|
-
"Write",
|
|
7853
|
-
"Edit",
|
|
7854
|
-
"Bash",
|
|
7855
|
-
"Glob",
|
|
7856
|
-
"Grep",
|
|
7857
|
-
"WebSearch",
|
|
7858
|
-
"WebFetch",
|
|
7859
|
-
"NotebookEdit"
|
|
7860
|
-
],
|
|
8077
|
+
allowedTools: ORCHESTRATOR_ALLOWED_TOOLS,
|
|
7861
8078
|
disallowedTools: DISALLOWED_BUILTIN_TOOLS
|
|
7862
8079
|
}
|
|
7863
8080
|
});
|
|
@@ -7880,11 +8097,19 @@ function runOneShotWorker(opts) {
|
|
|
7880
8097
|
}
|
|
7881
8098
|
});
|
|
7882
8099
|
}
|
|
7883
|
-
var MAX_ORCHESTRATOR_TURNS, DISALLOWED_BUILTIN_TOOLS;
|
|
8100
|
+
var MAX_ORCHESTRATOR_TURNS, ORCHESTRATOR_ALLOWED_TOOLS, DISALLOWED_BUILTIN_TOOLS;
|
|
7884
8101
|
var init_orchestrator = __esm({
|
|
7885
8102
|
"src/agents/orchestrator.ts"() {
|
|
7886
8103
|
init_dist();
|
|
7887
8104
|
MAX_ORCHESTRATOR_TURNS = 20;
|
|
8105
|
+
ORCHESTRATOR_ALLOWED_TOOLS = [
|
|
8106
|
+
"mcp__deskfree-orchestrator__*",
|
|
8107
|
+
"Read",
|
|
8108
|
+
"Glob",
|
|
8109
|
+
"Grep",
|
|
8110
|
+
"WebSearch",
|
|
8111
|
+
"WebFetch"
|
|
8112
|
+
];
|
|
7888
8113
|
DISALLOWED_BUILTIN_TOOLS = [
|
|
7889
8114
|
"TodoWrite",
|
|
7890
8115
|
"AskUserQuestion",
|
|
@@ -8049,6 +8274,86 @@ var init_health_state = __esm({
|
|
|
8049
8274
|
}
|
|
8050
8275
|
});
|
|
8051
8276
|
|
|
8277
|
+
// src/util/logger.ts
|
|
8278
|
+
var logger_exports = {};
|
|
8279
|
+
__export(logger_exports, {
|
|
8280
|
+
createLogger: () => createLogger,
|
|
8281
|
+
enableFileLogging: () => enableFileLogging,
|
|
8282
|
+
getLogFilePath: () => getLogFilePath,
|
|
8283
|
+
logger: () => logger
|
|
8284
|
+
});
|
|
8285
|
+
function enableFileLogging(filePath) {
|
|
8286
|
+
mkdirSync(dirname(filePath), { recursive: true });
|
|
8287
|
+
logFilePath = filePath;
|
|
8288
|
+
}
|
|
8289
|
+
function getLogFilePath() {
|
|
8290
|
+
return logFilePath;
|
|
8291
|
+
}
|
|
8292
|
+
function rotateIfNeeded() {
|
|
8293
|
+
if (!logFilePath) return;
|
|
8294
|
+
try {
|
|
8295
|
+
const stat = statSync(logFilePath);
|
|
8296
|
+
if (stat.size <= MAX_LOG_FILE_BYTES) return;
|
|
8297
|
+
const content = readFileSync(logFilePath, "utf8");
|
|
8298
|
+
const half = Math.floor(content.length / 2);
|
|
8299
|
+
const newlineIdx = content.indexOf("\n", half);
|
|
8300
|
+
const trimmed = newlineIdx >= 0 ? content.slice(newlineIdx + 1) : content.slice(half);
|
|
8301
|
+
writeFileSync(logFilePath, trimmed);
|
|
8302
|
+
} catch {
|
|
8303
|
+
}
|
|
8304
|
+
}
|
|
8305
|
+
function createLogger(component, minLevel = "info") {
|
|
8306
|
+
const minLevelNum = LEVELS[minLevel];
|
|
8307
|
+
function log(level, message, fields) {
|
|
8308
|
+
if (LEVELS[level] < minLevelNum) return;
|
|
8309
|
+
const entry = {
|
|
8310
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8311
|
+
level,
|
|
8312
|
+
component,
|
|
8313
|
+
msg: message,
|
|
8314
|
+
...fields
|
|
8315
|
+
};
|
|
8316
|
+
const line = JSON.stringify(entry);
|
|
8317
|
+
if (level === "error" || level === "warn") {
|
|
8318
|
+
process.stderr.write(line + "\n");
|
|
8319
|
+
} else {
|
|
8320
|
+
process.stdout.write(line + "\n");
|
|
8321
|
+
}
|
|
8322
|
+
if (logFilePath) {
|
|
8323
|
+
try {
|
|
8324
|
+
appendFileSync(logFilePath, line + "\n");
|
|
8325
|
+
if (++writesSinceCheck >= ROTATION_CHECK_INTERVAL) {
|
|
8326
|
+
writesSinceCheck = 0;
|
|
8327
|
+
rotateIfNeeded();
|
|
8328
|
+
}
|
|
8329
|
+
} catch {
|
|
8330
|
+
}
|
|
8331
|
+
}
|
|
8332
|
+
}
|
|
8333
|
+
return {
|
|
8334
|
+
debug: (msg, fields) => log("debug", msg, fields),
|
|
8335
|
+
info: (msg, fields) => log("info", msg, fields),
|
|
8336
|
+
warn: (msg, fields) => log("warn", msg, fields),
|
|
8337
|
+
error: (msg, fields) => log("error", msg, fields)
|
|
8338
|
+
};
|
|
8339
|
+
}
|
|
8340
|
+
var LEVELS, MAX_LOG_FILE_BYTES, ROTATION_CHECK_INTERVAL, logFilePath, writesSinceCheck, logger;
|
|
8341
|
+
var init_logger = __esm({
|
|
8342
|
+
"src/util/logger.ts"() {
|
|
8343
|
+
LEVELS = {
|
|
8344
|
+
debug: 0,
|
|
8345
|
+
info: 1,
|
|
8346
|
+
warn: 2,
|
|
8347
|
+
error: 3
|
|
8348
|
+
};
|
|
8349
|
+
MAX_LOG_FILE_BYTES = 5 * 1024 * 1024;
|
|
8350
|
+
ROTATION_CHECK_INTERVAL = 500;
|
|
8351
|
+
logFilePath = null;
|
|
8352
|
+
writesSinceCheck = 0;
|
|
8353
|
+
logger = createLogger("runtime");
|
|
8354
|
+
}
|
|
8355
|
+
});
|
|
8356
|
+
|
|
8052
8357
|
// src/gateway/polling.ts
|
|
8053
8358
|
async function pollAndDeliver(client, accountId, stateDir, cursor, onMessage, log) {
|
|
8054
8359
|
const ctx = { accountId };
|
|
@@ -11753,8 +12058,6 @@ var init_wrapper = __esm({
|
|
|
11753
12058
|
wrapper_default2 = import_websocket2.default;
|
|
11754
12059
|
}
|
|
11755
12060
|
});
|
|
11756
|
-
|
|
11757
|
-
// src/gateway/ws-gateway.ts
|
|
11758
12061
|
function nextBackoff(state2) {
|
|
11759
12062
|
const delay = Math.min(
|
|
11760
12063
|
BACKOFF_INITIAL_MS * Math.pow(BACKOFF_FACTOR, state2.attempt),
|
|
@@ -11934,11 +12237,11 @@ async function runWebSocketConnection(opts) {
|
|
|
11934
12237
|
}, PING_INTERVAL_MS);
|
|
11935
12238
|
if (opts.getWorkerStatus) {
|
|
11936
12239
|
try {
|
|
11937
|
-
const
|
|
12240
|
+
const status2 = opts.getWorkerStatus();
|
|
11938
12241
|
ws.send(
|
|
11939
12242
|
JSON.stringify({
|
|
11940
12243
|
action: "heartbeatResponse",
|
|
11941
|
-
...
|
|
12244
|
+
...status2
|
|
11942
12245
|
})
|
|
11943
12246
|
);
|
|
11944
12247
|
} catch (err) {
|
|
@@ -12008,11 +12311,11 @@ async function runWebSocketConnection(opts) {
|
|
|
12008
12311
|
} else if (msg.action === "heartbeatRequest") {
|
|
12009
12312
|
if (opts.getWorkerStatus && ws.readyState === wrapper_default2.OPEN) {
|
|
12010
12313
|
try {
|
|
12011
|
-
const
|
|
12314
|
+
const status2 = opts.getWorkerStatus();
|
|
12012
12315
|
ws.send(
|
|
12013
12316
|
JSON.stringify({
|
|
12014
12317
|
action: "heartbeatResponse",
|
|
12015
|
-
...
|
|
12318
|
+
...status2
|
|
12016
12319
|
})
|
|
12017
12320
|
);
|
|
12018
12321
|
} catch (err) {
|
|
@@ -12027,6 +12330,49 @@ async function runWebSocketConnection(opts) {
|
|
|
12027
12330
|
cleanup();
|
|
12028
12331
|
ws.close(1e3, "reload");
|
|
12029
12332
|
process.kill(process.pid, "SIGTERM");
|
|
12333
|
+
} else if (msg.action === "logs") {
|
|
12334
|
+
const MAX_RESPONSE_BYTES = 12e4;
|
|
12335
|
+
const lineCount = msg.lines ?? 200;
|
|
12336
|
+
try {
|
|
12337
|
+
const logFile = getLogFilePath();
|
|
12338
|
+
if (!logFile) {
|
|
12339
|
+
ws.send(
|
|
12340
|
+
JSON.stringify({
|
|
12341
|
+
action: "logsResponse",
|
|
12342
|
+
lines: [],
|
|
12343
|
+
error: "File logging not enabled"
|
|
12344
|
+
})
|
|
12345
|
+
);
|
|
12346
|
+
} else {
|
|
12347
|
+
const content = readFileSync(logFile, "utf8");
|
|
12348
|
+
const allLines = content.split("\n").filter(Boolean);
|
|
12349
|
+
let tail = allLines.slice(-lineCount);
|
|
12350
|
+
while (tail.length > 1) {
|
|
12351
|
+
const payload = JSON.stringify({
|
|
12352
|
+
action: "logsResponse",
|
|
12353
|
+
lines: tail
|
|
12354
|
+
});
|
|
12355
|
+
if (Buffer.byteLength(payload) <= MAX_RESPONSE_BYTES) break;
|
|
12356
|
+
tail = tail.slice(Math.ceil(tail.length * 0.25));
|
|
12357
|
+
}
|
|
12358
|
+
ws.send(
|
|
12359
|
+
JSON.stringify({
|
|
12360
|
+
action: "logsResponse",
|
|
12361
|
+
lines: tail
|
|
12362
|
+
})
|
|
12363
|
+
);
|
|
12364
|
+
}
|
|
12365
|
+
} catch (err) {
|
|
12366
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
12367
|
+
log.warn(`Failed to read logs: ${errMsg}`);
|
|
12368
|
+
ws.send(
|
|
12369
|
+
JSON.stringify({
|
|
12370
|
+
action: "logsResponse",
|
|
12371
|
+
lines: [],
|
|
12372
|
+
error: errMsg
|
|
12373
|
+
})
|
|
12374
|
+
);
|
|
12375
|
+
}
|
|
12030
12376
|
}
|
|
12031
12377
|
} catch (err) {
|
|
12032
12378
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -12145,6 +12491,7 @@ var PING_INTERVAL_MS, POLL_FALLBACK_INTERVAL_MS, WS_CONNECTION_TIMEOUT_MS, WS_PO
|
|
|
12145
12491
|
var init_ws_gateway = __esm({
|
|
12146
12492
|
"src/gateway/ws-gateway.ts"() {
|
|
12147
12493
|
init_health_state();
|
|
12494
|
+
init_logger();
|
|
12148
12495
|
init_polling();
|
|
12149
12496
|
init_dist();
|
|
12150
12497
|
init_wrapper();
|
|
@@ -12639,21 +12986,35 @@ function scheduleDailyCycle(label, run, hour, timezone, signal, log) {
|
|
|
12639
12986
|
}
|
|
12640
12987
|
function msUntilNextLocalHour(hour, timezone) {
|
|
12641
12988
|
const now = Date.now();
|
|
12642
|
-
const
|
|
12989
|
+
const hourFmt = new Intl.DateTimeFormat("en-US", {
|
|
12643
12990
|
timeZone: timezone,
|
|
12644
12991
|
hour: "numeric",
|
|
12645
12992
|
hour12: false
|
|
12646
12993
|
});
|
|
12994
|
+
const detailFmt = new Intl.DateTimeFormat("en-US", {
|
|
12995
|
+
timeZone: timezone,
|
|
12996
|
+
minute: "numeric",
|
|
12997
|
+
second: "numeric"
|
|
12998
|
+
});
|
|
12647
12999
|
for (let offsetMs = 6e4; offsetMs <= 25 * 36e5; offsetMs += 36e5) {
|
|
12648
13000
|
const candidateMs = now + offsetMs;
|
|
12649
|
-
const parts =
|
|
13001
|
+
const parts = hourFmt.formatToParts(new Date(candidateMs));
|
|
12650
13002
|
const hourPart = parts.find((p) => p.type === "hour");
|
|
12651
13003
|
const candidateHour = parseInt(hourPart?.value ?? "-1", 10);
|
|
12652
13004
|
if (candidateHour === hour) {
|
|
12653
|
-
const
|
|
12654
|
-
|
|
12655
|
-
|
|
12656
|
-
|
|
13005
|
+
const detailParts = detailFmt.formatToParts(new Date(candidateMs));
|
|
13006
|
+
const localMinute = parseInt(
|
|
13007
|
+
detailParts.find((p) => p.type === "minute")?.value ?? "0",
|
|
13008
|
+
10
|
|
13009
|
+
);
|
|
13010
|
+
const localSecond = parseInt(
|
|
13011
|
+
detailParts.find((p) => p.type === "second")?.value ?? "0",
|
|
13012
|
+
10
|
|
13013
|
+
);
|
|
13014
|
+
const snappedMs = candidateMs - localMinute * 6e4 - localSecond * 1e3;
|
|
13015
|
+
if (snappedMs > now + 6e4) {
|
|
13016
|
+
return snappedMs - now;
|
|
13017
|
+
}
|
|
12657
13018
|
}
|
|
12658
13019
|
}
|
|
12659
13020
|
return 24 * 36e5;
|
|
@@ -12749,50 +13110,6 @@ var init_registry = __esm({
|
|
|
12749
13110
|
"src/tools/registry.ts"() {
|
|
12750
13111
|
}
|
|
12751
13112
|
});
|
|
12752
|
-
|
|
12753
|
-
// src/util/logger.ts
|
|
12754
|
-
var logger_exports = {};
|
|
12755
|
-
__export(logger_exports, {
|
|
12756
|
-
createLogger: () => createLogger,
|
|
12757
|
-
logger: () => logger
|
|
12758
|
-
});
|
|
12759
|
-
function createLogger(component, minLevel = "info") {
|
|
12760
|
-
const minLevelNum = LEVELS[minLevel];
|
|
12761
|
-
function log(level, message, fields) {
|
|
12762
|
-
if (LEVELS[level] < minLevelNum) return;
|
|
12763
|
-
const entry = {
|
|
12764
|
-
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
12765
|
-
level,
|
|
12766
|
-
component,
|
|
12767
|
-
msg: message,
|
|
12768
|
-
...fields
|
|
12769
|
-
};
|
|
12770
|
-
const line = JSON.stringify(entry);
|
|
12771
|
-
if (level === "error" || level === "warn") {
|
|
12772
|
-
process.stderr.write(line + "\n");
|
|
12773
|
-
} else {
|
|
12774
|
-
process.stdout.write(line + "\n");
|
|
12775
|
-
}
|
|
12776
|
-
}
|
|
12777
|
-
return {
|
|
12778
|
-
debug: (msg, fields) => log("debug", msg, fields),
|
|
12779
|
-
info: (msg, fields) => log("info", msg, fields),
|
|
12780
|
-
warn: (msg, fields) => log("warn", msg, fields),
|
|
12781
|
-
error: (msg, fields) => log("error", msg, fields)
|
|
12782
|
-
};
|
|
12783
|
-
}
|
|
12784
|
-
var LEVELS, logger;
|
|
12785
|
-
var init_logger = __esm({
|
|
12786
|
-
"src/util/logger.ts"() {
|
|
12787
|
-
LEVELS = {
|
|
12788
|
-
debug: 0,
|
|
12789
|
-
info: 1,
|
|
12790
|
-
warn: 2,
|
|
12791
|
-
error: 3
|
|
12792
|
-
};
|
|
12793
|
-
logger = createLogger("runtime");
|
|
12794
|
-
}
|
|
12795
|
-
});
|
|
12796
13113
|
function checkRateLimit(userId) {
|
|
12797
13114
|
const now = Date.now();
|
|
12798
13115
|
const entry = rateLimitMap.get(userId);
|
|
@@ -13244,8 +13561,6 @@ function runWorker(opts) {
|
|
|
13244
13561
|
return query({
|
|
13245
13562
|
prompt,
|
|
13246
13563
|
options: {
|
|
13247
|
-
debug: true,
|
|
13248
|
-
debugFile: "/dev/stderr",
|
|
13249
13564
|
stderr: (data) => {
|
|
13250
13565
|
process.stderr.write(`[worker-sdk] ${data}
|
|
13251
13566
|
`);
|
|
@@ -13863,6 +14178,9 @@ async function startAgent(opts) {
|
|
|
13863
14178
|
}
|
|
13864
14179
|
mkdirSync(config.stateDir, { recursive: true });
|
|
13865
14180
|
mkdirSync(config.toolsDir, { recursive: true });
|
|
14181
|
+
const logFile = join(config.stateDir, "runtime.log");
|
|
14182
|
+
enableFileLogging(logFile);
|
|
14183
|
+
log.info(`File logging enabled: ${logFile}`);
|
|
13866
14184
|
if (config.tools.length > 0) {
|
|
13867
14185
|
log.info(`Installing ${config.tools.length} tool package(s)...`);
|
|
13868
14186
|
await installTools(config.tools, config.toolsDir, log);
|
|
@@ -14103,6 +14421,9 @@ if (command === "install") {
|
|
|
14103
14421
|
} else if (command === "uninstall") {
|
|
14104
14422
|
const { uninstall: uninstall2 } = await Promise.resolve().then(() => (init_uninstall(), uninstall_exports));
|
|
14105
14423
|
uninstall2();
|
|
14424
|
+
} else if (command === "status") {
|
|
14425
|
+
const { status: status2 } = await Promise.resolve().then(() => (init_status(), status_exports));
|
|
14426
|
+
status2();
|
|
14106
14427
|
} else {
|
|
14107
14428
|
let handleShutdown = function(signal) {
|
|
14108
14429
|
log.info(`Received ${signal} \u2014 shutting down...`);
|