@questionbase/deskfree 0.6.9 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin.js +522 -385
- package/dist/bin.js.map +1 -1
- package/dist/cli/start.d.ts +3 -0
- package/dist/cli/start.js +209 -0
- package/dist/cli/start.js.map +1 -0
- package/dist/cli/stop.d.ts +3 -0
- package/dist/cli/stop.js +80 -0
- package/dist/cli/stop.js.map +1 -0
- package/dist/cli/uninstall.d.ts +1 -1
- package/dist/cli/uninstall.js +20 -20
- package/dist/cli/uninstall.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +15 -15
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/cli/install.d.ts +0 -3
- package/dist/cli/install.js +0 -197
- package/dist/cli/install.js.map +0 -1
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
import { homedir } from 'os';
|
|
3
|
+
import { dirname, join } from 'path';
|
|
4
|
+
import { execSync } from 'child_process';
|
|
5
|
+
import { existsSync, mkdirSync, writeFileSync, chmodSync } from 'fs';
|
|
6
|
+
|
|
7
|
+
createRequire(import.meta.url);
|
|
8
|
+
function getPlistLabel(botId) {
|
|
9
|
+
return `com.deskfree.agent.${botId}`;
|
|
10
|
+
}
|
|
11
|
+
function getServiceName(botId) {
|
|
12
|
+
return `deskfree-${botId}`;
|
|
13
|
+
}
|
|
14
|
+
function getMacPaths(botId) {
|
|
15
|
+
const home = homedir();
|
|
16
|
+
const deskfreeDir = join(home, ".deskfree", botId);
|
|
17
|
+
const plistLabel = getPlistLabel(botId);
|
|
18
|
+
return {
|
|
19
|
+
deskfreeDir,
|
|
20
|
+
envFile: join(deskfreeDir, ".env"),
|
|
21
|
+
launcher: join(deskfreeDir, "deskfree.sh"),
|
|
22
|
+
logDir: join(deskfreeDir, "logs"),
|
|
23
|
+
plist: join(home, "Library", "LaunchAgents", `${plistLabel}.plist`)
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
function getLinuxPaths(botId) {
|
|
27
|
+
const serviceName = getServiceName(botId);
|
|
28
|
+
return {
|
|
29
|
+
serviceName,
|
|
30
|
+
serviceFile: `/etc/systemd/system/${serviceName}.service`,
|
|
31
|
+
envFile: `/etc/${serviceName}.env`,
|
|
32
|
+
stateDir: `/var/lib/${serviceName}`,
|
|
33
|
+
logDir: `/var/log/${serviceName}`
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
var PACKAGE = "@questionbase/deskfree@latest";
|
|
37
|
+
function startMac(botId, stage) {
|
|
38
|
+
const paths = getMacPaths(botId);
|
|
39
|
+
const plistLabel = getPlistLabel(botId);
|
|
40
|
+
const isInstalled = existsSync(paths.plist);
|
|
41
|
+
if (!isInstalled) {
|
|
42
|
+
let nodeBinDir;
|
|
43
|
+
try {
|
|
44
|
+
const nodePath = execSync("which node", { encoding: "utf8" }).trim();
|
|
45
|
+
nodeBinDir = dirname(nodePath);
|
|
46
|
+
} catch {
|
|
47
|
+
console.error("Error: node not found in PATH");
|
|
48
|
+
process.exit(1);
|
|
49
|
+
}
|
|
50
|
+
const extraPathDirs = (process.env["PATH"] ?? "").split(":").filter((d) => d && d !== nodeBinDir);
|
|
51
|
+
const fullPath = [nodeBinDir, ...extraPathDirs].join(":");
|
|
52
|
+
mkdirSync(paths.deskfreeDir, { recursive: true });
|
|
53
|
+
mkdirSync(paths.logDir, { recursive: true });
|
|
54
|
+
mkdirSync(dirname(paths.plist), { recursive: true });
|
|
55
|
+
const envLines = [`BOT=${botId}`];
|
|
56
|
+
if (stage) envLines.push(`STAGE=${stage}`);
|
|
57
|
+
writeFileSync(paths.envFile, envLines.join("\n") + "\n", { mode: 384 });
|
|
58
|
+
chmodSync(paths.envFile, 384);
|
|
59
|
+
console.log(`Wrote ${paths.envFile}`);
|
|
60
|
+
const launcher = `#!/bin/bash
|
|
61
|
+
set -euo pipefail
|
|
62
|
+
|
|
63
|
+
export PATH="${fullPath}"
|
|
64
|
+
|
|
65
|
+
# Update to latest version before starting
|
|
66
|
+
npm install -g ${PACKAGE} 2>/dev/null || true
|
|
67
|
+
|
|
68
|
+
# Source env
|
|
69
|
+
set -a
|
|
70
|
+
source "${paths.envFile}"
|
|
71
|
+
set +a
|
|
72
|
+
|
|
73
|
+
exec deskfree run "$BOT"
|
|
74
|
+
`;
|
|
75
|
+
writeFileSync(paths.launcher, launcher, { mode: 493 });
|
|
76
|
+
chmodSync(paths.launcher, 493);
|
|
77
|
+
console.log(`Wrote ${paths.launcher}`);
|
|
78
|
+
const plist = `<?xml version="1.0" encoding="UTF-8"?>
|
|
79
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
80
|
+
<plist version="1.0">
|
|
81
|
+
<dict>
|
|
82
|
+
<key>Label</key>
|
|
83
|
+
<string>${plistLabel}</string>
|
|
84
|
+
<key>ProgramArguments</key>
|
|
85
|
+
<array>
|
|
86
|
+
<string>${paths.launcher}</string>
|
|
87
|
+
</array>
|
|
88
|
+
<key>KeepAlive</key>
|
|
89
|
+
<true/>
|
|
90
|
+
<key>RunAtLoad</key>
|
|
91
|
+
<true/>
|
|
92
|
+
<key>StandardOutPath</key>
|
|
93
|
+
<string>${join(paths.logDir, "stdout.log")}</string>
|
|
94
|
+
<key>StandardErrorPath</key>
|
|
95
|
+
<string>${join(paths.logDir, "stderr.log")}</string>
|
|
96
|
+
<key>ThrottleInterval</key>
|
|
97
|
+
<integer>10</integer>
|
|
98
|
+
</dict>
|
|
99
|
+
</plist>
|
|
100
|
+
`;
|
|
101
|
+
writeFileSync(paths.plist, plist);
|
|
102
|
+
console.log(`Wrote ${paths.plist}`);
|
|
103
|
+
}
|
|
104
|
+
try {
|
|
105
|
+
execSync(`launchctl bootout gui/$(id -u) ${paths.plist}`, {
|
|
106
|
+
stdio: "ignore"
|
|
107
|
+
});
|
|
108
|
+
} catch {
|
|
109
|
+
}
|
|
110
|
+
execSync(`launchctl bootstrap gui/$(id -u) ${paths.plist}`);
|
|
111
|
+
if (isInstalled) {
|
|
112
|
+
console.log(`Bot ${botId} started.`);
|
|
113
|
+
} else {
|
|
114
|
+
console.log(`
|
|
115
|
+
Bot ${botId} installed and started.`);
|
|
116
|
+
}
|
|
117
|
+
console.log(`Logs: tail -f ${join(paths.logDir, "stdout.log")}`);
|
|
118
|
+
}
|
|
119
|
+
function startLinux(botId, stage) {
|
|
120
|
+
const paths = getLinuxPaths(botId);
|
|
121
|
+
const serviceName = getServiceName(botId);
|
|
122
|
+
const isInstalled = existsSync(paths.serviceFile);
|
|
123
|
+
if (!isInstalled) {
|
|
124
|
+
if (process.getuid?.() !== 0) {
|
|
125
|
+
console.error("Error: first-time setup must be run as root (use sudo)");
|
|
126
|
+
process.exit(1);
|
|
127
|
+
}
|
|
128
|
+
const systemUser = serviceName;
|
|
129
|
+
let npmPath;
|
|
130
|
+
let nodeBinDir;
|
|
131
|
+
try {
|
|
132
|
+
npmPath = execSync("which npm", { encoding: "utf8" }).trim();
|
|
133
|
+
nodeBinDir = dirname(npmPath);
|
|
134
|
+
} catch {
|
|
135
|
+
console.error("Error: npm not found in PATH");
|
|
136
|
+
process.exit(1);
|
|
137
|
+
}
|
|
138
|
+
try {
|
|
139
|
+
execSync(`id ${systemUser}`, { stdio: "ignore" });
|
|
140
|
+
} catch {
|
|
141
|
+
execSync(
|
|
142
|
+
`useradd --system --no-create-home --shell /usr/sbin/nologin ${systemUser}`
|
|
143
|
+
);
|
|
144
|
+
console.log(`Created system user: ${systemUser}`);
|
|
145
|
+
}
|
|
146
|
+
mkdirSync(paths.stateDir, { recursive: true });
|
|
147
|
+
mkdirSync(paths.logDir, { recursive: true });
|
|
148
|
+
execSync(
|
|
149
|
+
`chown ${systemUser}:${systemUser} ${paths.stateDir} ${paths.logDir}`
|
|
150
|
+
);
|
|
151
|
+
console.log(`Created ${paths.stateDir} and ${paths.logDir}`);
|
|
152
|
+
const envLines = [`BOT=${botId}`];
|
|
153
|
+
if (stage) envLines.push(`STAGE=${stage}`);
|
|
154
|
+
writeFileSync(paths.envFile, envLines.join("\n") + "\n", { mode: 384 });
|
|
155
|
+
chmodSync(paths.envFile, 384);
|
|
156
|
+
console.log(`Wrote ${paths.envFile}`);
|
|
157
|
+
const unit = `[Unit]
|
|
158
|
+
Description=DeskFree Agent (${botId})
|
|
159
|
+
After=network-online.target
|
|
160
|
+
Wants=network-online.target
|
|
161
|
+
|
|
162
|
+
[Service]
|
|
163
|
+
Type=simple
|
|
164
|
+
User=${systemUser}
|
|
165
|
+
Group=${systemUser}
|
|
166
|
+
WorkingDirectory=${paths.stateDir}
|
|
167
|
+
Environment=PATH=${nodeBinDir}:/usr/local/bin:/usr/bin:/bin
|
|
168
|
+
ExecStartPre=+${npmPath} install -g ${PACKAGE}
|
|
169
|
+
ExecStart=${nodeBinDir}/deskfree run ${botId}
|
|
170
|
+
EnvironmentFile=${paths.envFile}
|
|
171
|
+
Environment=NODE_ENV=production
|
|
172
|
+
Environment=DESKFREE_STATE_DIR=${paths.stateDir}
|
|
173
|
+
Environment=DESKFREE_TOOLS_DIR=${paths.stateDir}/tools
|
|
174
|
+
Restart=always
|
|
175
|
+
RestartSec=10
|
|
176
|
+
StandardOutput=append:${paths.logDir}/stdout.log
|
|
177
|
+
StandardError=append:${paths.logDir}/stderr.log
|
|
178
|
+
|
|
179
|
+
[Install]
|
|
180
|
+
WantedBy=multi-user.target
|
|
181
|
+
`;
|
|
182
|
+
writeFileSync(paths.serviceFile, unit);
|
|
183
|
+
console.log(`Wrote ${paths.serviceFile}`);
|
|
184
|
+
execSync("systemctl daemon-reload");
|
|
185
|
+
execSync(`systemctl enable ${serviceName}`);
|
|
186
|
+
}
|
|
187
|
+
execSync(`systemctl start ${serviceName}`);
|
|
188
|
+
if (isInstalled) {
|
|
189
|
+
console.log(`Bot ${botId} started.`);
|
|
190
|
+
} else {
|
|
191
|
+
console.log(`
|
|
192
|
+
Bot ${botId} installed and started.`);
|
|
193
|
+
}
|
|
194
|
+
console.log(`Logs: tail -f ${paths.logDir}/stdout.log`);
|
|
195
|
+
}
|
|
196
|
+
function start(botId, stage) {
|
|
197
|
+
if (process.platform === "darwin") {
|
|
198
|
+
startMac(botId, stage);
|
|
199
|
+
} else if (process.platform === "linux") {
|
|
200
|
+
startLinux(botId, stage);
|
|
201
|
+
} else {
|
|
202
|
+
console.error(`Unsupported platform: ${process.platform}`);
|
|
203
|
+
process.exit(1);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
export { start };
|
|
208
|
+
//# sourceMappingURL=start.js.map
|
|
209
|
+
//# sourceMappingURL=start.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/cli/paths.ts","../../src/cli/start.ts"],"names":["join"],"mappings":"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","file":"start.js","sourcesContent":["import { homedir } from 'node:os';\nimport { join } from 'node:path';\n\nexport function getPlistLabel(botId: string): string {\n return `com.deskfree.agent.${botId}`;\n}\n\nexport function getServiceName(botId: string): string {\n return `deskfree-${botId}`;\n}\n\nexport function getMacPaths(botId: string) {\n const home = homedir();\n const deskfreeDir = join(home, '.deskfree', botId);\n const plistLabel = getPlistLabel(botId);\n return {\n deskfreeDir,\n envFile: join(deskfreeDir, '.env'),\n launcher: join(deskfreeDir, 'deskfree.sh'),\n logDir: join(deskfreeDir, 'logs'),\n plist: join(home, 'Library', 'LaunchAgents', `${plistLabel}.plist`),\n };\n}\n\nexport function getLinuxPaths(botId: string) {\n const serviceName = getServiceName(botId);\n return {\n serviceName,\n serviceFile: `/etc/systemd/system/${serviceName}.service`,\n envFile: `/etc/${serviceName}.env`,\n stateDir: `/var/lib/${serviceName}`,\n logDir: `/var/log/${serviceName}`,\n };\n}\n\n/**\n * Parse a bot ID from argv.\n * Returns [botId | null, commandArgs].\n * Bot ID is the first positional arg that looks like a bot ID (starts with 'B').\n */\nexport function parseBotId(args: string[]): [string | null, string[]] {\n // Look for --stage and skip its value\n const result: string[] = [];\n let botId: string | null = null;\n let i = 0;\n while (i < args.length) {\n if (args[i] === '--stage') {\n result.push(args[i]!, args[i + 1] ?? '');\n i += 2;\n continue;\n }\n // First positional arg that starts with B is the bot ID\n if (\n !botId &&\n args[i] &&\n !args[i]!.startsWith('-') &&\n /^B[A-Z0-9]+$/i.test(args[i]!)\n ) {\n botId = args[i]!;\n } else {\n result.push(args[i]!);\n }\n i++;\n }\n return [botId, result];\n}\n","import {\n getLinuxPaths,\n getMacPaths,\n getPlistLabel,\n getServiceName,\n} from './paths.js';\nimport { execSync } from 'node:child_process';\nimport { chmodSync, existsSync, mkdirSync, writeFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\n\nconst PACKAGE = '@questionbase/deskfree@latest';\n\n// ── macOS (launchd) ─────────────────────────────────────────────────────────\n\nfunction startMac(botId: string, stage?: string): void {\n const paths = getMacPaths(botId);\n const plistLabel = getPlistLabel(botId);\n const isInstalled = existsSync(paths.plist);\n\n if (!isInstalled) {\n // First-time setup\n let nodeBinDir: string;\n try {\n const nodePath = execSync('which node', { encoding: 'utf8' }).trim();\n nodeBinDir = dirname(nodePath);\n } catch {\n console.error('Error: node not found in PATH');\n process.exit(1);\n }\n\n const extraPathDirs = (process.env['PATH'] ?? '')\n .split(':')\n .filter((d) => d && d !== nodeBinDir);\n const fullPath = [nodeBinDir, ...extraPathDirs].join(':');\n\n // Create directories\n mkdirSync(paths.deskfreeDir, { recursive: true });\n mkdirSync(paths.logDir, { recursive: true });\n mkdirSync(dirname(paths.plist), { recursive: true });\n\n // Write env file (chmod 600)\n const envLines = [`BOT=${botId}`];\n if (stage) envLines.push(`STAGE=${stage}`);\n writeFileSync(paths.envFile, envLines.join('\\n') + '\\n', { mode: 0o600 });\n chmodSync(paths.envFile, 0o600);\n console.log(`Wrote ${paths.envFile}`);\n\n // Write launcher script\n const launcher = `#!/bin/bash\nset -euo pipefail\n\nexport PATH=\"${fullPath}\"\n\n# Update to latest version before starting\nnpm install -g ${PACKAGE} 2>/dev/null || true\n\n# Source env\nset -a\nsource \"${paths.envFile}\"\nset +a\n\nexec deskfree run \"$BOT\"\n`;\n\n writeFileSync(paths.launcher, launcher, { mode: 0o755 });\n chmodSync(paths.launcher, 0o755);\n console.log(`Wrote ${paths.launcher}`);\n\n // Write LaunchAgent plist\n const plist = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n <key>Label</key>\n <string>${plistLabel}</string>\n <key>ProgramArguments</key>\n <array>\n <string>${paths.launcher}</string>\n </array>\n <key>KeepAlive</key>\n <true/>\n <key>RunAtLoad</key>\n <true/>\n <key>StandardOutPath</key>\n <string>${join(paths.logDir, 'stdout.log')}</string>\n <key>StandardErrorPath</key>\n <string>${join(paths.logDir, 'stderr.log')}</string>\n <key>ThrottleInterval</key>\n <integer>10</integer>\n</dict>\n</plist>\n`;\n\n writeFileSync(paths.plist, plist);\n console.log(`Wrote ${paths.plist}`);\n }\n\n // Unload if already loaded (ignore errors)\n try {\n execSync(`launchctl bootout gui/$(id -u) ${paths.plist}`, {\n stdio: 'ignore',\n });\n } catch {\n // not loaded — fine\n }\n\n // Load the service\n execSync(`launchctl bootstrap gui/$(id -u) ${paths.plist}`);\n\n if (isInstalled) {\n console.log(`Bot ${botId} started.`);\n } else {\n console.log(`\\nBot ${botId} installed and started.`);\n }\n console.log(`Logs: tail -f ${join(paths.logDir, 'stdout.log')}`);\n}\n\n// ── Linux (systemd) ─────────────────────────────────────────────────────────\n\nfunction startLinux(botId: string, stage?: string): void {\n const paths = getLinuxPaths(botId);\n const serviceName = getServiceName(botId);\n const isInstalled = existsSync(paths.serviceFile);\n\n if (!isInstalled) {\n if (process.getuid?.() !== 0) {\n console.error('Error: first-time setup must be run as root (use sudo)');\n process.exit(1);\n }\n\n const systemUser = serviceName;\n\n let npmPath: string;\n let nodeBinDir: string;\n try {\n npmPath = execSync('which npm', { encoding: 'utf8' }).trim();\n nodeBinDir = dirname(npmPath);\n } catch {\n console.error('Error: npm not found in PATH');\n process.exit(1);\n }\n\n // Create dedicated system user\n try {\n execSync(`id ${systemUser}`, { stdio: 'ignore' });\n } catch {\n execSync(\n `useradd --system --no-create-home --shell /usr/sbin/nologin ${systemUser}`,\n );\n console.log(`Created system user: ${systemUser}`);\n }\n\n // Create state and log directories\n mkdirSync(paths.stateDir, { recursive: true });\n mkdirSync(paths.logDir, { recursive: true });\n execSync(\n `chown ${systemUser}:${systemUser} ${paths.stateDir} ${paths.logDir}`,\n );\n console.log(`Created ${paths.stateDir} and ${paths.logDir}`);\n\n // Write env file\n const envLines = [`BOT=${botId}`];\n if (stage) envLines.push(`STAGE=${stage}`);\n writeFileSync(paths.envFile, envLines.join('\\n') + '\\n', { mode: 0o600 });\n chmodSync(paths.envFile, 0o600);\n console.log(`Wrote ${paths.envFile}`);\n\n // Write systemd unit file\n const unit = `[Unit]\nDescription=DeskFree Agent (${botId})\nAfter=network-online.target\nWants=network-online.target\n\n[Service]\nType=simple\nUser=${systemUser}\nGroup=${systemUser}\nWorkingDirectory=${paths.stateDir}\nEnvironment=PATH=${nodeBinDir}:/usr/local/bin:/usr/bin:/bin\nExecStartPre=+${npmPath} install -g ${PACKAGE}\nExecStart=${nodeBinDir}/deskfree run ${botId}\nEnvironmentFile=${paths.envFile}\nEnvironment=NODE_ENV=production\nEnvironment=DESKFREE_STATE_DIR=${paths.stateDir}\nEnvironment=DESKFREE_TOOLS_DIR=${paths.stateDir}/tools\nRestart=always\nRestartSec=10\nStandardOutput=append:${paths.logDir}/stdout.log\nStandardError=append:${paths.logDir}/stderr.log\n\n[Install]\nWantedBy=multi-user.target\n`;\n\n writeFileSync(paths.serviceFile, unit);\n console.log(`Wrote ${paths.serviceFile}`);\n\n execSync('systemctl daemon-reload');\n execSync(`systemctl enable ${serviceName}`);\n }\n\n execSync(`systemctl start ${serviceName}`);\n\n if (isInstalled) {\n console.log(`Bot ${botId} started.`);\n } else {\n console.log(`\\nBot ${botId} installed and started.`);\n }\n console.log(`Logs: tail -f ${paths.logDir}/stdout.log`);\n}\n\n// ── Public API ──────────────────────────────────────────────────────────────\n\nexport function start(botId: string, stage?: string): void {\n if (process.platform === 'darwin') {\n startMac(botId, stage);\n } else if (process.platform === 'linux') {\n startLinux(botId, stage);\n } else {\n console.error(`Unsupported platform: ${process.platform}`);\n process.exit(1);\n }\n}\n"]}
|
package/dist/cli/stop.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
import { homedir } from 'os';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
import { execSync } from 'child_process';
|
|
5
|
+
import { existsSync } from 'fs';
|
|
6
|
+
|
|
7
|
+
createRequire(import.meta.url);
|
|
8
|
+
function getPlistLabel(botId) {
|
|
9
|
+
return `com.deskfree.agent.${botId}`;
|
|
10
|
+
}
|
|
11
|
+
function getServiceName(botId) {
|
|
12
|
+
return `deskfree-${botId}`;
|
|
13
|
+
}
|
|
14
|
+
function getMacPaths(botId) {
|
|
15
|
+
const home = homedir();
|
|
16
|
+
const deskfreeDir = join(home, ".deskfree", botId);
|
|
17
|
+
const plistLabel = getPlistLabel(botId);
|
|
18
|
+
return {
|
|
19
|
+
deskfreeDir,
|
|
20
|
+
envFile: join(deskfreeDir, ".env"),
|
|
21
|
+
launcher: join(deskfreeDir, "deskfree.sh"),
|
|
22
|
+
logDir: join(deskfreeDir, "logs"),
|
|
23
|
+
plist: join(home, "Library", "LaunchAgents", `${plistLabel}.plist`)
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
function getLinuxPaths(botId) {
|
|
27
|
+
const serviceName = getServiceName(botId);
|
|
28
|
+
return {
|
|
29
|
+
serviceName,
|
|
30
|
+
serviceFile: `/etc/systemd/system/${serviceName}.service`,
|
|
31
|
+
envFile: `/etc/${serviceName}.env`,
|
|
32
|
+
stateDir: `/var/lib/${serviceName}`,
|
|
33
|
+
logDir: `/var/log/${serviceName}`
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
function stopMac(botId) {
|
|
37
|
+
const paths = getMacPaths(botId);
|
|
38
|
+
if (!existsSync(paths.plist)) {
|
|
39
|
+
console.error(`Bot ${botId} is not installed.`);
|
|
40
|
+
console.error(`Run: deskfree start ${botId}`);
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
execSync(`launchctl bootout gui/$(id -u) ${paths.plist}`, {
|
|
45
|
+
stdio: "ignore"
|
|
46
|
+
});
|
|
47
|
+
console.log(`Bot ${botId} stopped.`);
|
|
48
|
+
} catch {
|
|
49
|
+
console.log(`Bot ${botId} is not running.`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function stopLinux(botId) {
|
|
53
|
+
const paths = getLinuxPaths(botId);
|
|
54
|
+
const serviceName = getServiceName(botId);
|
|
55
|
+
if (!existsSync(paths.serviceFile)) {
|
|
56
|
+
console.error(`Bot ${botId} is not installed.`);
|
|
57
|
+
console.error(`Run: deskfree start ${botId}`);
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
try {
|
|
61
|
+
execSync(`systemctl stop ${serviceName}`, { stdio: "inherit" });
|
|
62
|
+
console.log(`Bot ${botId} stopped.`);
|
|
63
|
+
} catch {
|
|
64
|
+
console.log(`Bot ${botId} is not running.`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function stop(botId) {
|
|
68
|
+
if (process.platform === "darwin") {
|
|
69
|
+
stopMac(botId);
|
|
70
|
+
} else if (process.platform === "linux") {
|
|
71
|
+
stopLinux(botId);
|
|
72
|
+
} else {
|
|
73
|
+
console.error(`Unsupported platform: ${process.platform}`);
|
|
74
|
+
process.exit(1);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export { stop };
|
|
79
|
+
//# sourceMappingURL=stop.js.map
|
|
80
|
+
//# sourceMappingURL=stop.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/cli/paths.ts","../../src/cli/stop.ts"],"names":[],"mappings":"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","file":"stop.js","sourcesContent":["import { homedir } from 'node:os';\nimport { join } from 'node:path';\n\nexport function getPlistLabel(botId: string): string {\n return `com.deskfree.agent.${botId}`;\n}\n\nexport function getServiceName(botId: string): string {\n return `deskfree-${botId}`;\n}\n\nexport function getMacPaths(botId: string) {\n const home = homedir();\n const deskfreeDir = join(home, '.deskfree', botId);\n const plistLabel = getPlistLabel(botId);\n return {\n deskfreeDir,\n envFile: join(deskfreeDir, '.env'),\n launcher: join(deskfreeDir, 'deskfree.sh'),\n logDir: join(deskfreeDir, 'logs'),\n plist: join(home, 'Library', 'LaunchAgents', `${plistLabel}.plist`),\n };\n}\n\nexport function getLinuxPaths(botId: string) {\n const serviceName = getServiceName(botId);\n return {\n serviceName,\n serviceFile: `/etc/systemd/system/${serviceName}.service`,\n envFile: `/etc/${serviceName}.env`,\n stateDir: `/var/lib/${serviceName}`,\n logDir: `/var/log/${serviceName}`,\n };\n}\n\n/**\n * Parse a bot ID from argv.\n * Returns [botId | null, commandArgs].\n * Bot ID is the first positional arg that looks like a bot ID (starts with 'B').\n */\nexport function parseBotId(args: string[]): [string | null, string[]] {\n // Look for --stage and skip its value\n const result: string[] = [];\n let botId: string | null = null;\n let i = 0;\n while (i < args.length) {\n if (args[i] === '--stage') {\n result.push(args[i]!, args[i + 1] ?? '');\n i += 2;\n continue;\n }\n // First positional arg that starts with B is the bot ID\n if (\n !botId &&\n args[i] &&\n !args[i]!.startsWith('-') &&\n /^B[A-Z0-9]+$/i.test(args[i]!)\n ) {\n botId = args[i]!;\n } else {\n result.push(args[i]!);\n }\n i++;\n }\n return [botId, result];\n}\n","import { getLinuxPaths, getMacPaths, getServiceName } from './paths.js';\nimport { execSync } from 'node:child_process';\nimport { existsSync } from 'node:fs';\n\nfunction stopMac(botId: string): void {\n const paths = getMacPaths(botId);\n\n if (!existsSync(paths.plist)) {\n console.error(`Bot ${botId} is not installed.`);\n console.error(`Run: deskfree start ${botId}`);\n process.exit(1);\n }\n\n try {\n execSync(`launchctl bootout gui/$(id -u) ${paths.plist}`, {\n stdio: 'ignore',\n });\n console.log(`Bot ${botId} stopped.`);\n } catch {\n console.log(`Bot ${botId} is not running.`);\n }\n}\n\nfunction stopLinux(botId: string): void {\n const paths = getLinuxPaths(botId);\n const serviceName = getServiceName(botId);\n\n if (!existsSync(paths.serviceFile)) {\n console.error(`Bot ${botId} is not installed.`);\n console.error(`Run: deskfree start ${botId}`);\n process.exit(1);\n }\n\n try {\n execSync(`systemctl stop ${serviceName}`, { stdio: 'inherit' });\n console.log(`Bot ${botId} stopped.`);\n } catch {\n console.log(`Bot ${botId} is not running.`);\n }\n}\n\nexport function stop(botId: string): void {\n if (process.platform === 'darwin') {\n stopMac(botId);\n } else if (process.platform === 'linux') {\n stopLinux(botId);\n } else {\n console.error(`Unsupported platform: ${process.platform}`);\n process.exit(1);\n }\n}\n"]}
|
package/dist/cli/uninstall.d.ts
CHANGED
package/dist/cli/uninstall.js
CHANGED
|
@@ -5,16 +5,16 @@ import { execSync } from 'child_process';
|
|
|
5
5
|
import { existsSync, unlinkSync } from 'fs';
|
|
6
6
|
|
|
7
7
|
createRequire(import.meta.url);
|
|
8
|
-
function getPlistLabel(
|
|
9
|
-
return `com.deskfree.agent.${
|
|
8
|
+
function getPlistLabel(botId) {
|
|
9
|
+
return `com.deskfree.agent.${botId}`;
|
|
10
10
|
}
|
|
11
|
-
function getServiceName(
|
|
12
|
-
return `deskfree-${
|
|
11
|
+
function getServiceName(botId) {
|
|
12
|
+
return `deskfree-${botId}`;
|
|
13
13
|
}
|
|
14
|
-
function getMacPaths(
|
|
14
|
+
function getMacPaths(botId) {
|
|
15
15
|
const home = homedir();
|
|
16
|
-
const deskfreeDir = join(home, ".deskfree",
|
|
17
|
-
const plistLabel = getPlistLabel(
|
|
16
|
+
const deskfreeDir = join(home, ".deskfree", botId);
|
|
17
|
+
const plistLabel = getPlistLabel(botId);
|
|
18
18
|
return {
|
|
19
19
|
deskfreeDir,
|
|
20
20
|
envFile: join(deskfreeDir, ".env"),
|
|
@@ -23,8 +23,8 @@ function getMacPaths(name) {
|
|
|
23
23
|
plist: join(home, "Library", "LaunchAgents", `${plistLabel}.plist`)
|
|
24
24
|
};
|
|
25
25
|
}
|
|
26
|
-
function getLinuxPaths(
|
|
27
|
-
const serviceName = getServiceName(
|
|
26
|
+
function getLinuxPaths(botId) {
|
|
27
|
+
const serviceName = getServiceName(botId);
|
|
28
28
|
return {
|
|
29
29
|
serviceName,
|
|
30
30
|
serviceFile: `/etc/systemd/system/${serviceName}.service`,
|
|
@@ -33,9 +33,9 @@ function getLinuxPaths(name) {
|
|
|
33
33
|
logDir: `/var/log/${serviceName}`
|
|
34
34
|
};
|
|
35
35
|
}
|
|
36
|
-
function uninstallMac(
|
|
37
|
-
const paths = getMacPaths(
|
|
38
|
-
const plistLabel = getPlistLabel(
|
|
36
|
+
function uninstallMac(botId) {
|
|
37
|
+
const paths = getMacPaths(botId);
|
|
38
|
+
const plistLabel = getPlistLabel(botId);
|
|
39
39
|
try {
|
|
40
40
|
execSync(`launchctl bootout gui/$(id -u) ${paths.plist}`, {
|
|
41
41
|
stdio: "ignore"
|
|
@@ -48,18 +48,18 @@ function uninstallMac(name) {
|
|
|
48
48
|
console.log(`Removed ${file}`);
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
|
-
console.log(`
|
|
51
|
+
console.log(`Bot ${botId} (${plistLabel}) uninstalled.`);
|
|
52
52
|
console.log(
|
|
53
53
|
`Note: logs and state in ${paths.deskfreeDir} were preserved. Remove manually if desired.`
|
|
54
54
|
);
|
|
55
55
|
}
|
|
56
|
-
function uninstallLinux(
|
|
56
|
+
function uninstallLinux(botId) {
|
|
57
57
|
if (process.getuid?.() !== 0) {
|
|
58
58
|
console.error("Error: uninstall must be run as root (use sudo)");
|
|
59
59
|
process.exit(1);
|
|
60
60
|
}
|
|
61
|
-
const paths = getLinuxPaths(
|
|
62
|
-
const serviceName = getServiceName(
|
|
61
|
+
const paths = getLinuxPaths(botId);
|
|
62
|
+
const serviceName = getServiceName(botId);
|
|
63
63
|
try {
|
|
64
64
|
execSync(`systemctl stop ${serviceName}`, { stdio: "ignore" });
|
|
65
65
|
} catch {
|
|
@@ -77,13 +77,13 @@ function uninstallLinux(name) {
|
|
|
77
77
|
console.log(`Removed ${paths.envFile}`);
|
|
78
78
|
}
|
|
79
79
|
execSync("systemctl daemon-reload");
|
|
80
|
-
console.log(`
|
|
80
|
+
console.log(`Bot ${botId} (${serviceName}) uninstalled.`);
|
|
81
81
|
}
|
|
82
|
-
function uninstall(
|
|
82
|
+
function uninstall(botId) {
|
|
83
83
|
if (process.platform === "darwin") {
|
|
84
|
-
uninstallMac(
|
|
84
|
+
uninstallMac(botId);
|
|
85
85
|
} else if (process.platform === "linux") {
|
|
86
|
-
uninstallLinux(
|
|
86
|
+
uninstallLinux(botId);
|
|
87
87
|
} else {
|
|
88
88
|
console.error(`Unsupported platform: ${process.platform}`);
|
|
89
89
|
process.exit(1);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/cli/paths.ts","../../src/cli/uninstall.ts"],"names":[],"mappings":";;;;;;;
|
|
1
|
+
{"version":3,"sources":["../../src/cli/paths.ts","../../src/cli/uninstall.ts"],"names":[],"mappings":"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","file":"uninstall.js","sourcesContent":["import { homedir } from 'node:os';\nimport { join } from 'node:path';\n\nexport function getPlistLabel(botId: string): string {\n return `com.deskfree.agent.${botId}`;\n}\n\nexport function getServiceName(botId: string): string {\n return `deskfree-${botId}`;\n}\n\nexport function getMacPaths(botId: string) {\n const home = homedir();\n const deskfreeDir = join(home, '.deskfree', botId);\n const plistLabel = getPlistLabel(botId);\n return {\n deskfreeDir,\n envFile: join(deskfreeDir, '.env'),\n launcher: join(deskfreeDir, 'deskfree.sh'),\n logDir: join(deskfreeDir, 'logs'),\n plist: join(home, 'Library', 'LaunchAgents', `${plistLabel}.plist`),\n };\n}\n\nexport function getLinuxPaths(botId: string) {\n const serviceName = getServiceName(botId);\n return {\n serviceName,\n serviceFile: `/etc/systemd/system/${serviceName}.service`,\n envFile: `/etc/${serviceName}.env`,\n stateDir: `/var/lib/${serviceName}`,\n logDir: `/var/log/${serviceName}`,\n };\n}\n\n/**\n * Parse a bot ID from argv.\n * Returns [botId | null, commandArgs].\n * Bot ID is the first positional arg that looks like a bot ID (starts with 'B').\n */\nexport function parseBotId(args: string[]): [string | null, string[]] {\n // Look for --stage and skip its value\n const result: string[] = [];\n let botId: string | null = null;\n let i = 0;\n while (i < args.length) {\n if (args[i] === '--stage') {\n result.push(args[i]!, args[i + 1] ?? '');\n i += 2;\n continue;\n }\n // First positional arg that starts with B is the bot ID\n if (\n !botId &&\n args[i] &&\n !args[i]!.startsWith('-') &&\n /^B[A-Z0-9]+$/i.test(args[i]!)\n ) {\n botId = args[i]!;\n } else {\n result.push(args[i]!);\n }\n i++;\n }\n return [botId, result];\n}\n","import {\n getLinuxPaths,\n getMacPaths,\n getPlistLabel,\n getServiceName,\n} from './paths.js';\nimport { execSync } from 'node:child_process';\nimport { existsSync, unlinkSync } from 'node:fs';\n\n// ── macOS (launchd) ─────────────────────────────────────────────────────────\n\nfunction uninstallMac(botId: string): void {\n const paths = getMacPaths(botId);\n const plistLabel = getPlistLabel(botId);\n\n // Unload (ignore errors if not loaded)\n try {\n execSync(`launchctl bootout gui/$(id -u) ${paths.plist}`, {\n stdio: 'ignore',\n });\n } catch {\n // not loaded — fine\n }\n\n // Remove files\n for (const file of [paths.plist, paths.envFile, paths.launcher]) {\n if (existsSync(file)) {\n unlinkSync(file);\n console.log(`Removed ${file}`);\n }\n }\n\n console.log(`Bot ${botId} (${plistLabel}) uninstalled.`);\n console.log(\n `Note: logs and state in ${paths.deskfreeDir} were preserved. Remove manually if desired.`,\n );\n}\n\n// ── Linux (systemd) ─────────────────────────────────────────────────────────\n\nfunction uninstallLinux(botId: string): void {\n if (process.getuid?.() !== 0) {\n console.error('Error: uninstall must be run as root (use sudo)');\n process.exit(1);\n }\n\n const paths = getLinuxPaths(botId);\n const serviceName = getServiceName(botId);\n\n // Stop and disable\n try {\n execSync(`systemctl stop ${serviceName}`, { stdio: 'ignore' });\n } catch {\n // not running — fine\n }\n try {\n execSync(`systemctl disable ${serviceName}`, { stdio: 'ignore' });\n } catch {\n // not enabled — fine\n }\n\n // Remove files\n if (existsSync(paths.serviceFile)) {\n unlinkSync(paths.serviceFile);\n console.log(`Removed ${paths.serviceFile}`);\n }\n if (existsSync(paths.envFile)) {\n unlinkSync(paths.envFile);\n console.log(`Removed ${paths.envFile}`);\n }\n\n execSync('systemctl daemon-reload');\n console.log(`Bot ${botId} (${serviceName}) uninstalled.`);\n}\n\n// ── Public API ──────────────────────────────────────────────────────────────\n\nexport function uninstall(botId: string): void {\n if (process.platform === 'darwin') {\n uninstallMac(botId);\n } else if (process.platform === 'linux') {\n uninstallLinux(botId);\n } else {\n console.error(`Unsupported platform: ${process.platform}`);\n process.exit(1);\n }\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -398,8 +398,8 @@ declare function loadConfig(): LocalConfig;
|
|
|
398
398
|
* Env var overrides take precedence over API values for debugging/testing.
|
|
399
399
|
*
|
|
400
400
|
* When running multiple agents on the same machine, stateDir and toolsDir
|
|
401
|
-
* are namespaced by
|
|
402
|
-
*
|
|
401
|
+
* are namespaced by bot ID (BOT env var).
|
|
402
|
+
* Each bot gets its own directory under ~/.deskfree/<botId>/.
|
|
403
403
|
*/
|
|
404
404
|
declare function mergeWithRemoteConfig(local: LocalConfig, remote: RuntimeBootstrapConfig): RuntimeConfig;
|
|
405
405
|
|
package/dist/index.js
CHANGED
|
@@ -12642,18 +12642,8 @@ function runOneShotWorker(opts) {
|
|
|
12642
12642
|
init_dist();
|
|
12643
12643
|
var isDocker = process.env["DOCKER"] === "1" || existsSync("/.dockerenv");
|
|
12644
12644
|
var DEFAULTS = {
|
|
12645
|
-
stateDir: isDocker ? "/app/state" : join(
|
|
12646
|
-
|
|
12647
|
-
".deskfree",
|
|
12648
|
-
process.env["DESKFREE_INSTANCE_NAME"] ?? "main",
|
|
12649
|
-
"state"
|
|
12650
|
-
),
|
|
12651
|
-
toolsDir: isDocker ? "/app/tools" : join(
|
|
12652
|
-
homedir(),
|
|
12653
|
-
".deskfree",
|
|
12654
|
-
process.env["DESKFREE_INSTANCE_NAME"] ?? "main",
|
|
12655
|
-
"tools"
|
|
12656
|
-
),
|
|
12645
|
+
stateDir: isDocker ? "/app/state" : join(homedir(), ".deskfree", process.env["BOT"] ?? "default", "state"),
|
|
12646
|
+
toolsDir: isDocker ? "/app/tools" : join(homedir(), ".deskfree", process.env["BOT"] ?? "default", "tools"),
|
|
12657
12647
|
logLevel: "info",
|
|
12658
12648
|
healthPort: 3100
|
|
12659
12649
|
};
|
|
@@ -14185,6 +14175,13 @@ ${userMessage}
|
|
|
14185
14175
|
const delta = extractTextDelta2(message);
|
|
14186
14176
|
if (delta) {
|
|
14187
14177
|
fullText += delta;
|
|
14178
|
+
if (!fullText.trim()) {
|
|
14179
|
+
log.warn(`Skipping whitespace-only delta`, {
|
|
14180
|
+
delta: JSON.stringify(delta),
|
|
14181
|
+
fullText: JSON.stringify(fullText)
|
|
14182
|
+
});
|
|
14183
|
+
continue;
|
|
14184
|
+
}
|
|
14188
14185
|
if (!streamStarted) {
|
|
14189
14186
|
setInboundThreadId(taskId);
|
|
14190
14187
|
await streamingSession.start(fullText, taskId);
|
|
@@ -14253,7 +14250,10 @@ ${userMessage}
|
|
|
14253
14250
|
}
|
|
14254
14251
|
}
|
|
14255
14252
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
14256
|
-
|
|
14253
|
+
const errStack = err instanceof Error ? err.stack : void 0;
|
|
14254
|
+
log.warn(`Worker drain loop error for task ${taskId}: ${errMsg}`, {
|
|
14255
|
+
stack: errStack
|
|
14256
|
+
});
|
|
14257
14257
|
try {
|
|
14258
14258
|
await client.sendMessage({
|
|
14259
14259
|
content: "Sorry, I encountered an error while working on this task. Please try again.",
|
|
@@ -14484,7 +14484,7 @@ async function startAgent(opts) {
|
|
|
14484
14484
|
log.info("DeskFree Agent Runtime starting...");
|
|
14485
14485
|
const { getRotationToken: getRotationToken2, setInitialRotationToken: setInitialRotationToken2 } = await Promise.resolve().then(() => (init_ws_gateway(), ws_gateway_exports));
|
|
14486
14486
|
const { collectFingerprint: collectFingerprint2 } = await Promise.resolve().then(() => (init_fingerprint(), fingerprint_exports));
|
|
14487
|
-
const runtimeVersion = "0.
|
|
14487
|
+
const runtimeVersion = "0.7.1";
|
|
14488
14488
|
const fingerprint = collectFingerprint2(localConfig.stateDir, runtimeVersion);
|
|
14489
14489
|
log.info("Connecting to DeskFree...", { wsUrl: localConfig.wsUrl });
|
|
14490
14490
|
const connectResult = await initialConnect({
|
|
@@ -14529,7 +14529,7 @@ async function startAgent(opts) {
|
|
|
14529
14529
|
runtimeVersion,
|
|
14530
14530
|
maxConcurrentWorkers: 5,
|
|
14531
14531
|
// updated after WorkerManager is created
|
|
14532
|
-
instanceName: process.env["
|
|
14532
|
+
instanceName: process.env["BOT"] || void 0
|
|
14533
14533
|
};
|
|
14534
14534
|
mkdirSync(config.stateDir, { recursive: true });
|
|
14535
14535
|
mkdirSync(config.toolsDir, { recursive: true });
|