@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/cli/install.d.ts
CHANGED
package/dist/cli/install.js
CHANGED
|
@@ -1,26 +1,42 @@
|
|
|
1
1
|
import { createRequire } from 'node:module';
|
|
2
|
-
import { execSync } from 'child_process';
|
|
3
|
-
import { mkdirSync, writeFileSync, chmodSync } from 'fs';
|
|
4
2
|
import { homedir } from 'os';
|
|
5
3
|
import { dirname, join } from 'path';
|
|
4
|
+
import { execSync } from 'child_process';
|
|
5
|
+
import { mkdirSync, writeFileSync, chmodSync } from 'fs';
|
|
6
6
|
|
|
7
7
|
createRequire(import.meta.url);
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
function
|
|
8
|
+
function getPlistLabel(name) {
|
|
9
|
+
return `com.deskfree.agent.${name}`;
|
|
10
|
+
}
|
|
11
|
+
function getServiceName(name) {
|
|
12
|
+
return `deskfree-agent-${name}`;
|
|
13
|
+
}
|
|
14
|
+
function getMacPaths(name) {
|
|
12
15
|
const home = homedir();
|
|
13
|
-
const deskfreeDir = join(home, ".deskfree");
|
|
16
|
+
const deskfreeDir = join(home, ".deskfree", name);
|
|
17
|
+
const plistLabel = getPlistLabel(name);
|
|
14
18
|
return {
|
|
15
19
|
deskfreeDir,
|
|
16
20
|
envFile: join(deskfreeDir, ".env"),
|
|
17
|
-
launcher: join(deskfreeDir, "
|
|
21
|
+
launcher: join(deskfreeDir, "deskfree.sh"),
|
|
18
22
|
logDir: join(deskfreeDir, "logs"),
|
|
19
|
-
plist: join(home, "Library", "LaunchAgents", `${
|
|
23
|
+
plist: join(home, "Library", "LaunchAgents", `${plistLabel}.plist`)
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
function getLinuxPaths(name) {
|
|
27
|
+
const serviceName = getServiceName(name);
|
|
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}`
|
|
20
34
|
};
|
|
21
35
|
}
|
|
22
|
-
|
|
23
|
-
|
|
36
|
+
var PACKAGE = "@questionbase/deskfree@latest";
|
|
37
|
+
function installMac(token, name) {
|
|
38
|
+
const paths = getMacPaths(name);
|
|
39
|
+
const plistLabel = getPlistLabel(name);
|
|
24
40
|
let nodeBinDir;
|
|
25
41
|
try {
|
|
26
42
|
const nodePath = execSync("which node", { encoding: "utf8" }).trim();
|
|
@@ -29,17 +45,24 @@ function installMac(token) {
|
|
|
29
45
|
console.error("Error: node not found in PATH");
|
|
30
46
|
process.exit(1);
|
|
31
47
|
}
|
|
48
|
+
const extraPathDirs = (process.env["PATH"] ?? "").split(":").filter((d) => d && d !== nodeBinDir);
|
|
49
|
+
const fullPath = [nodeBinDir, ...extraPathDirs].join(":");
|
|
32
50
|
mkdirSync(paths.deskfreeDir, { recursive: true });
|
|
33
51
|
mkdirSync(paths.logDir, { recursive: true });
|
|
34
52
|
mkdirSync(dirname(paths.plist), { recursive: true });
|
|
35
|
-
writeFileSync(
|
|
36
|
-
|
|
53
|
+
writeFileSync(
|
|
54
|
+
paths.envFile,
|
|
55
|
+
`DESKFREE_LAUNCH=${token}
|
|
56
|
+
DESKFREE_INSTANCE_NAME=${name}
|
|
57
|
+
`,
|
|
58
|
+
{ mode: 384 }
|
|
59
|
+
);
|
|
37
60
|
chmodSync(paths.envFile, 384);
|
|
38
61
|
console.log(`Wrote ${paths.envFile}`);
|
|
39
62
|
const launcher = `#!/bin/bash
|
|
40
63
|
set -euo pipefail
|
|
41
64
|
|
|
42
|
-
export PATH="${
|
|
65
|
+
export PATH="${fullPath}"
|
|
43
66
|
|
|
44
67
|
# Update to latest version before starting
|
|
45
68
|
npm install -g ${PACKAGE} 2>/dev/null || true
|
|
@@ -59,7 +82,7 @@ exec deskfree-agent start
|
|
|
59
82
|
<plist version="1.0">
|
|
60
83
|
<dict>
|
|
61
84
|
<key>Label</key>
|
|
62
|
-
<string>${
|
|
85
|
+
<string>${plistLabel}</string>
|
|
63
86
|
<key>ProgramArguments</key>
|
|
64
87
|
<array>
|
|
65
88
|
<string>${paths.launcher}</string>
|
|
@@ -87,19 +110,18 @@ exec deskfree-agent start
|
|
|
87
110
|
}
|
|
88
111
|
execSync(`launchctl bootstrap gui/$(id -u) ${paths.plist}`);
|
|
89
112
|
console.log(`
|
|
90
|
-
Service ${
|
|
91
|
-
console.log(`Check status: launchctl print gui/$(id -u)/${
|
|
113
|
+
Service ${plistLabel} installed and started.`);
|
|
114
|
+
console.log(`Check status: launchctl print gui/$(id -u)/${plistLabel}`);
|
|
92
115
|
console.log(`Logs: tail -f ${join(paths.logDir, "stdout.log")}`);
|
|
93
116
|
}
|
|
94
|
-
|
|
95
|
-
var SYSTEMD_ENV_FILE = `/etc/${SERVICE_NAME}.env`;
|
|
96
|
-
var LINUX_STATE_DIR = "/var/lib/deskfree-agent";
|
|
97
|
-
var LINUX_LOG_DIR = "/var/log/deskfree-agent";
|
|
98
|
-
function installLinux(token) {
|
|
117
|
+
function installLinux(token, name) {
|
|
99
118
|
if (process.getuid?.() !== 0) {
|
|
100
119
|
console.error("Error: install must be run as root (use sudo)");
|
|
101
120
|
process.exit(1);
|
|
102
121
|
}
|
|
122
|
+
const paths = getLinuxPaths(name);
|
|
123
|
+
const serviceName = getServiceName(name);
|
|
124
|
+
const systemUser = serviceName;
|
|
103
125
|
let npmPath;
|
|
104
126
|
let nodeBinDir;
|
|
105
127
|
try {
|
|
@@ -110,65 +132,68 @@ function installLinux(token) {
|
|
|
110
132
|
process.exit(1);
|
|
111
133
|
}
|
|
112
134
|
try {
|
|
113
|
-
execSync(
|
|
135
|
+
execSync(`id ${systemUser}`, { stdio: "ignore" });
|
|
114
136
|
} catch {
|
|
115
137
|
execSync(
|
|
116
|
-
|
|
138
|
+
`useradd --system --no-create-home --shell /usr/sbin/nologin ${systemUser}`
|
|
117
139
|
);
|
|
118
|
-
console.log(
|
|
140
|
+
console.log(`Created system user: ${systemUser}`);
|
|
119
141
|
}
|
|
120
|
-
mkdirSync(
|
|
121
|
-
mkdirSync(
|
|
142
|
+
mkdirSync(paths.stateDir, { recursive: true });
|
|
143
|
+
mkdirSync(paths.logDir, { recursive: true });
|
|
122
144
|
execSync(
|
|
123
|
-
`chown
|
|
145
|
+
`chown ${systemUser}:${systemUser} ${paths.stateDir} ${paths.logDir}`
|
|
146
|
+
);
|
|
147
|
+
console.log(`Created ${paths.stateDir} and ${paths.logDir}`);
|
|
148
|
+
writeFileSync(
|
|
149
|
+
paths.envFile,
|
|
150
|
+
`DESKFREE_LAUNCH=${token}
|
|
151
|
+
DESKFREE_INSTANCE_NAME=${name}
|
|
152
|
+
`,
|
|
153
|
+
{ mode: 384 }
|
|
124
154
|
);
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
`, {
|
|
128
|
-
mode: 384
|
|
129
|
-
});
|
|
130
|
-
chmodSync(SYSTEMD_ENV_FILE, 384);
|
|
131
|
-
console.log(`Wrote ${SYSTEMD_ENV_FILE}`);
|
|
155
|
+
chmodSync(paths.envFile, 384);
|
|
156
|
+
console.log(`Wrote ${paths.envFile}`);
|
|
132
157
|
const unit = `[Unit]
|
|
133
|
-
Description=DeskFree Agent
|
|
158
|
+
Description=DeskFree Agent (${name})
|
|
134
159
|
After=network-online.target
|
|
135
160
|
Wants=network-online.target
|
|
136
161
|
|
|
137
162
|
[Service]
|
|
138
163
|
Type=simple
|
|
139
|
-
User
|
|
140
|
-
Group
|
|
141
|
-
WorkingDirectory=${
|
|
164
|
+
User=${systemUser}
|
|
165
|
+
Group=${systemUser}
|
|
166
|
+
WorkingDirectory=${paths.stateDir}
|
|
142
167
|
Environment=PATH=${nodeBinDir}:/usr/local/bin:/usr/bin:/bin
|
|
143
168
|
ExecStartPre=+${npmPath} install -g ${PACKAGE}
|
|
144
169
|
ExecStart=${nodeBinDir}/deskfree-agent start
|
|
145
|
-
EnvironmentFile=${
|
|
170
|
+
EnvironmentFile=${paths.envFile}
|
|
146
171
|
Environment=NODE_ENV=production
|
|
147
|
-
Environment=DESKFREE_STATE_DIR=${
|
|
148
|
-
Environment=DESKFREE_TOOLS_DIR=${
|
|
172
|
+
Environment=DESKFREE_STATE_DIR=${paths.stateDir}
|
|
173
|
+
Environment=DESKFREE_TOOLS_DIR=${paths.stateDir}/tools
|
|
149
174
|
Restart=always
|
|
150
175
|
RestartSec=10
|
|
151
|
-
StandardOutput=append:${
|
|
152
|
-
StandardError=append:${
|
|
176
|
+
StandardOutput=append:${paths.logDir}/stdout.log
|
|
177
|
+
StandardError=append:${paths.logDir}/stderr.log
|
|
153
178
|
|
|
154
179
|
[Install]
|
|
155
180
|
WantedBy=multi-user.target
|
|
156
181
|
`;
|
|
157
|
-
writeFileSync(
|
|
158
|
-
console.log(`Wrote ${
|
|
182
|
+
writeFileSync(paths.serviceFile, unit);
|
|
183
|
+
console.log(`Wrote ${paths.serviceFile}`);
|
|
159
184
|
execSync("systemctl daemon-reload");
|
|
160
|
-
execSync(`systemctl enable ${
|
|
161
|
-
execSync(`systemctl start ${
|
|
185
|
+
execSync(`systemctl enable ${serviceName}`);
|
|
186
|
+
execSync(`systemctl start ${serviceName}`);
|
|
162
187
|
console.log(`
|
|
163
|
-
Service ${
|
|
164
|
-
console.log(`Check status: systemctl status ${
|
|
165
|
-
console.log(`Logs: tail -f ${
|
|
188
|
+
Service ${serviceName} installed and started.`);
|
|
189
|
+
console.log(`Check status: systemctl status ${serviceName}`);
|
|
190
|
+
console.log(`Logs: tail -f ${paths.logDir}/stdout.log`);
|
|
166
191
|
}
|
|
167
|
-
function install(token) {
|
|
192
|
+
function install(token, name) {
|
|
168
193
|
if (process.platform === "darwin") {
|
|
169
|
-
installMac(token);
|
|
194
|
+
installMac(token, name);
|
|
170
195
|
} else if (process.platform === "linux") {
|
|
171
|
-
installLinux(token);
|
|
196
|
+
installLinux(token, name);
|
|
172
197
|
} else {
|
|
173
198
|
console.error(`Unsupported platform: ${process.platform}`);
|
|
174
199
|
process.exit(1);
|
package/dist/cli/install.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/cli/install.ts"],"names":[],"mappings":"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","file":"install.js","sourcesContent":["import { execSync } from 'node:child_process';\nimport { chmodSync, mkdirSync, writeFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { dirname, join } from 'node:path';\n\nconst SERVICE_NAME = 'deskfree-agent';\nconst PACKAGE = '@questionbase/deskfree@latest';\n\n// ── macOS (launchd) ─────────────────────────────────────────────────────────\n\nconst PLIST_LABEL = 'com.deskfree.agent';\n\nfunction getMacPaths() {\n const home = homedir();\n const deskfreeDir = join(home, '.deskfree');\n return {\n deskfreeDir,\n envFile: join(deskfreeDir, '.env'),\n launcher: join(deskfreeDir, 'launcher.sh'),\n logDir: join(deskfreeDir, 'logs'),\n plist: join(home, 'Library', 'LaunchAgents', `${PLIST_LABEL}.plist`),\n };\n}\n\nfunction installMac(token: string): void {\n const paths = getMacPaths();\n\n // Resolve full path to node's bin directory (survives nvm/fnm across sessions)\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 // 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 writeFileSync(paths.envFile, `DESKFREE_LAUNCH=${token}\\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=\"${nodeBinDir}:$PATH\"\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-agent start\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>${PLIST_LABEL}</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 // 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 console.log(`\\nService ${PLIST_LABEL} installed and started.`);\n console.log(`Check status: launchctl print gui/$(id -u)/${PLIST_LABEL}`);\n console.log(`Logs: tail -f ${join(paths.logDir, 'stdout.log')}`);\n}\n\n// ── Linux (systemd) ─────────────────────────────────────────────────────────\n\nconst SYSTEMD_SERVICE_FILE = `/etc/systemd/system/${SERVICE_NAME}.service`;\nconst SYSTEMD_ENV_FILE = `/etc/${SERVICE_NAME}.env`;\n\nconst LINUX_STATE_DIR = '/var/lib/deskfree-agent';\nconst LINUX_LOG_DIR = '/var/log/deskfree-agent';\n\nfunction installLinux(token: string): void {\n if (process.getuid?.() !== 0) {\n console.error('Error: install must be run as root (use sudo)');\n process.exit(1);\n }\n\n // Resolve full npm/node bin dir so systemd doesn't depend on PATH\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 (no login shell, no home dir)\n try {\n execSync('id deskfree-agent', { stdio: 'ignore' });\n } catch {\n execSync(\n 'useradd --system --no-create-home --shell /usr/sbin/nologin deskfree-agent',\n );\n console.log('Created system user: deskfree-agent');\n }\n\n // Create state and log directories owned by the service user\n mkdirSync(LINUX_STATE_DIR, { recursive: true });\n mkdirSync(LINUX_LOG_DIR, { recursive: true });\n execSync(\n `chown deskfree-agent:deskfree-agent ${LINUX_STATE_DIR} ${LINUX_LOG_DIR}`,\n );\n console.log(`Created ${LINUX_STATE_DIR} and ${LINUX_LOG_DIR}`);\n\n // Write env file with token (chmod 600 — only root can read)\n writeFileSync(SYSTEMD_ENV_FILE, `DESKFREE_LAUNCH=${token}\\n`, {\n mode: 0o600,\n });\n chmodSync(SYSTEMD_ENV_FILE, 0o600);\n console.log(`Wrote ${SYSTEMD_ENV_FILE}`);\n\n // Write systemd unit file\n // ExecStartPre updates to latest version before each start (same as macOS launcher)\n const unit = `[Unit]\nDescription=DeskFree Agent\nAfter=network-online.target\nWants=network-online.target\n\n[Service]\nType=simple\nUser=deskfree-agent\nGroup=deskfree-agent\nWorkingDirectory=${LINUX_STATE_DIR}\nEnvironment=PATH=${nodeBinDir}:/usr/local/bin:/usr/bin:/bin\nExecStartPre=+${npmPath} install -g ${PACKAGE}\nExecStart=${nodeBinDir}/deskfree-agent start\nEnvironmentFile=${SYSTEMD_ENV_FILE}\nEnvironment=NODE_ENV=production\nEnvironment=DESKFREE_STATE_DIR=${LINUX_STATE_DIR}\nEnvironment=DESKFREE_TOOLS_DIR=${LINUX_STATE_DIR}/tools\nRestart=always\nRestartSec=10\nStandardOutput=append:${LINUX_LOG_DIR}/stdout.log\nStandardError=append:${LINUX_LOG_DIR}/stderr.log\n\n[Install]\nWantedBy=multi-user.target\n`;\n\n writeFileSync(SYSTEMD_SERVICE_FILE, unit);\n console.log(`Wrote ${SYSTEMD_SERVICE_FILE}`);\n\n // Enable and start\n execSync('systemctl daemon-reload');\n execSync(`systemctl enable ${SERVICE_NAME}`);\n execSync(`systemctl start ${SERVICE_NAME}`);\n\n console.log(`\\nService ${SERVICE_NAME} installed and started.`);\n console.log(`Check status: systemctl status ${SERVICE_NAME}`);\n console.log(`Logs: tail -f ${LINUX_LOG_DIR}/stdout.log`);\n}\n\n// ── Public API ──────────────────────────────────────────────────────────────\n\nexport function install(token: string): void {\n if (process.platform === 'darwin') {\n installMac(token);\n } else if (process.platform === 'linux') {\n installLinux(token);\n } else {\n console.error(`Unsupported platform: ${process.platform}`);\n process.exit(1);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/cli/paths.ts","../../src/cli/install.ts"],"names":["join"],"mappings":"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","file":"install.js","sourcesContent":["import { homedir } from 'node:os';\nimport { join } from 'node:path';\n\nconst DEFAULT_NAME = 'main';\n\nexport function resolveName(name?: string): string {\n return name ?? DEFAULT_NAME;\n}\n\nexport function getPlistLabel(name: string): string {\n return `com.deskfree.agent.${name}`;\n}\n\nexport function getServiceName(name: string): string {\n return `deskfree-agent-${name}`;\n}\n\nexport function getMacPaths(name: string) {\n const home = homedir();\n const deskfreeDir = join(home, '.deskfree', name);\n const plistLabel = getPlistLabel(name);\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(name: string) {\n const serviceName = getServiceName(name);\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/** Parse --name <value> from argv, returning [resolvedName, remainingArgs]. */\nexport function parseName(args: string[]): [string, string[]] {\n const idx = args.indexOf('--name');\n if (idx === -1) return [DEFAULT_NAME, args];\n const name = args[idx + 1];\n if (!name || name.startsWith('-')) {\n console.error('Error: --name requires a value (e.g. --name kasper)');\n process.exit(1);\n }\n if (!/^[a-z0-9-]+$/i.test(name)) {\n console.error(\n 'Error: --name must contain only letters, numbers, and hyphens',\n );\n process.exit(1);\n }\n const remaining = [...args.slice(0, idx), ...args.slice(idx + 2)];\n return [name, remaining];\n}\n","import {\n getLinuxPaths,\n getMacPaths,\n getPlistLabel,\n getServiceName,\n} from './paths.js';\nimport { execSync } from 'node:child_process';\nimport { chmodSync, mkdirSync, writeFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\n\nconst PACKAGE = '@questionbase/deskfree@latest';\n\n// ── macOS (launchd) ─────────────────────────────────────────────────────────\n\nfunction installMac(token: string, name: string): void {\n const paths = getMacPaths(name);\n const plistLabel = getPlistLabel(name);\n\n // Resolve full path to node's bin directory (survives nvm/fnm across sessions)\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 // Capture extra PATH dirs from the user's shell so the launcher can find\n // tools like `claude` that live outside the node bin directory.\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 writeFileSync(\n paths.envFile,\n `DESKFREE_LAUNCH=${token}\\nDESKFREE_INSTANCE_NAME=${name}\\n`,\n { mode: 0o600 },\n );\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-agent start\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 // 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 console.log(`\\nService ${plistLabel} installed and started.`);\n console.log(`Check status: launchctl print gui/$(id -u)/${plistLabel}`);\n console.log(`Logs: tail -f ${join(paths.logDir, 'stdout.log')}`);\n}\n\n// ── Linux (systemd) ─────────────────────────────────────────────────────────\n\nfunction installLinux(token: string, name: string): void {\n if (process.getuid?.() !== 0) {\n console.error('Error: install must be run as root (use sudo)');\n process.exit(1);\n }\n\n const paths = getLinuxPaths(name);\n const serviceName = getServiceName(name);\n const systemUser = serviceName;\n\n // Resolve full npm/node bin dir so systemd doesn't depend on PATH\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 (no login shell, no home dir)\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 owned by the service user\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 with token (chmod 600 — only root can read)\n writeFileSync(\n paths.envFile,\n `DESKFREE_LAUNCH=${token}\\nDESKFREE_INSTANCE_NAME=${name}\\n`,\n { mode: 0o600 },\n );\n chmodSync(paths.envFile, 0o600);\n console.log(`Wrote ${paths.envFile}`);\n\n // Write systemd unit file\n const unit = `[Unit]\nDescription=DeskFree Agent (${name})\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-agent start\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 // Enable and start\n execSync('systemctl daemon-reload');\n execSync(`systemctl enable ${serviceName}`);\n execSync(`systemctl start ${serviceName}`);\n\n console.log(`\\nService ${serviceName} installed and started.`);\n console.log(`Check status: systemctl status ${serviceName}`);\n console.log(`Logs: tail -f ${paths.logDir}/stdout.log`);\n}\n\n// ── Public API ──────────────────────────────────────────────────────────────\n\nexport function install(token: string, name: string): void {\n if (process.platform === 'darwin') {\n installMac(token, name);\n } else if (process.platform === 'linux') {\n installLinux(token, name);\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
|
@@ -1,64 +1,89 @@
|
|
|
1
1
|
import { createRequire } from 'node:module';
|
|
2
|
-
import { execSync } from 'child_process';
|
|
3
|
-
import { existsSync, unlinkSync } from 'fs';
|
|
4
2
|
import { homedir } from 'os';
|
|
5
3
|
import { join } from 'path';
|
|
4
|
+
import { execSync } from 'child_process';
|
|
5
|
+
import { existsSync, unlinkSync } from 'fs';
|
|
6
6
|
|
|
7
7
|
createRequire(import.meta.url);
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
function getPlistLabel(name) {
|
|
9
|
+
return `com.deskfree.agent.${name}`;
|
|
10
|
+
}
|
|
11
|
+
function getServiceName(name) {
|
|
12
|
+
return `deskfree-agent-${name}`;
|
|
13
|
+
}
|
|
14
|
+
function getMacPaths(name) {
|
|
11
15
|
const home = homedir();
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
+
const deskfreeDir = join(home, ".deskfree", name);
|
|
17
|
+
const plistLabel = getPlistLabel(name);
|
|
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(name) {
|
|
27
|
+
const serviceName = getServiceName(name);
|
|
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 uninstallMac(name) {
|
|
37
|
+
const paths = getMacPaths(name);
|
|
38
|
+
const plistLabel = getPlistLabel(name);
|
|
16
39
|
try {
|
|
17
|
-
execSync(`launchctl bootout gui/$(id -u) ${plist}`, {
|
|
40
|
+
execSync(`launchctl bootout gui/$(id -u) ${paths.plist}`, {
|
|
41
|
+
stdio: "ignore"
|
|
42
|
+
});
|
|
18
43
|
} catch {
|
|
19
44
|
}
|
|
20
|
-
for (const file of [plist, envFile, launcher]) {
|
|
45
|
+
for (const file of [paths.plist, paths.envFile, paths.launcher]) {
|
|
21
46
|
if (existsSync(file)) {
|
|
22
47
|
unlinkSync(file);
|
|
23
48
|
console.log(`Removed ${file}`);
|
|
24
49
|
}
|
|
25
50
|
}
|
|
26
|
-
console.log(`Service ${
|
|
51
|
+
console.log(`Service ${plistLabel} uninstalled.`);
|
|
27
52
|
console.log(
|
|
28
|
-
`Note: logs and state in ${deskfreeDir} were preserved. Remove manually if desired.`
|
|
53
|
+
`Note: logs and state in ${paths.deskfreeDir} were preserved. Remove manually if desired.`
|
|
29
54
|
);
|
|
30
55
|
}
|
|
31
|
-
|
|
32
|
-
var SYSTEMD_ENV_FILE = `/etc/${SERVICE_NAME}.env`;
|
|
33
|
-
function uninstallLinux() {
|
|
56
|
+
function uninstallLinux(name) {
|
|
34
57
|
if (process.getuid?.() !== 0) {
|
|
35
58
|
console.error("Error: uninstall must be run as root (use sudo)");
|
|
36
59
|
process.exit(1);
|
|
37
60
|
}
|
|
61
|
+
const paths = getLinuxPaths(name);
|
|
62
|
+
const serviceName = getServiceName(name);
|
|
38
63
|
try {
|
|
39
|
-
execSync(`systemctl stop ${
|
|
64
|
+
execSync(`systemctl stop ${serviceName}`, { stdio: "ignore" });
|
|
40
65
|
} catch {
|
|
41
66
|
}
|
|
42
67
|
try {
|
|
43
|
-
execSync(`systemctl disable ${
|
|
68
|
+
execSync(`systemctl disable ${serviceName}`, { stdio: "ignore" });
|
|
44
69
|
} catch {
|
|
45
70
|
}
|
|
46
|
-
if (existsSync(
|
|
47
|
-
unlinkSync(
|
|
48
|
-
console.log(`Removed ${
|
|
71
|
+
if (existsSync(paths.serviceFile)) {
|
|
72
|
+
unlinkSync(paths.serviceFile);
|
|
73
|
+
console.log(`Removed ${paths.serviceFile}`);
|
|
49
74
|
}
|
|
50
|
-
if (existsSync(
|
|
51
|
-
unlinkSync(
|
|
52
|
-
console.log(`Removed ${
|
|
75
|
+
if (existsSync(paths.envFile)) {
|
|
76
|
+
unlinkSync(paths.envFile);
|
|
77
|
+
console.log(`Removed ${paths.envFile}`);
|
|
53
78
|
}
|
|
54
79
|
execSync("systemctl daemon-reload");
|
|
55
|
-
console.log(`Service ${
|
|
80
|
+
console.log(`Service ${serviceName} uninstalled.`);
|
|
56
81
|
}
|
|
57
|
-
function uninstall() {
|
|
82
|
+
function uninstall(name) {
|
|
58
83
|
if (process.platform === "darwin") {
|
|
59
|
-
uninstallMac();
|
|
84
|
+
uninstallMac(name);
|
|
60
85
|
} else if (process.platform === "linux") {
|
|
61
|
-
uninstallLinux();
|
|
86
|
+
uninstallLinux(name);
|
|
62
87
|
} else {
|
|
63
88
|
console.error(`Unsupported platform: ${process.platform}`);
|
|
64
89
|
process.exit(1);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../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\nconst DEFAULT_NAME = 'main';\n\nexport function resolveName(name?: string): string {\n return name ?? DEFAULT_NAME;\n}\n\nexport function getPlistLabel(name: string): string {\n return `com.deskfree.agent.${name}`;\n}\n\nexport function getServiceName(name: string): string {\n return `deskfree-agent-${name}`;\n}\n\nexport function getMacPaths(name: string) {\n const home = homedir();\n const deskfreeDir = join(home, '.deskfree', name);\n const plistLabel = getPlistLabel(name);\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(name: string) {\n const serviceName = getServiceName(name);\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/** Parse --name <value> from argv, returning [resolvedName, remainingArgs]. */\nexport function parseName(args: string[]): [string, string[]] {\n const idx = args.indexOf('--name');\n if (idx === -1) return [DEFAULT_NAME, args];\n const name = args[idx + 1];\n if (!name || name.startsWith('-')) {\n console.error('Error: --name requires a value (e.g. --name kasper)');\n process.exit(1);\n }\n if (!/^[a-z0-9-]+$/i.test(name)) {\n console.error(\n 'Error: --name must contain only letters, numbers, and hyphens',\n );\n process.exit(1);\n }\n const remaining = [...args.slice(0, idx), ...args.slice(idx + 2)];\n return [name, remaining];\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(name: string): void {\n const paths = getMacPaths(name);\n const plistLabel = getPlistLabel(name);\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(`Service ${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(name: 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(name);\n const serviceName = getServiceName(name);\n\n // Stop and disable (ignore errors if not running/enabled)\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(`Service ${serviceName} uninstalled.`);\n}\n\n// ── Public API ──────────────────────────────────────────────────────────────\n\nexport function uninstall(name: string): void {\n if (process.platform === 'darwin') {\n uninstallMac(name);\n } else if (process.platform === 'linux') {\n uninstallLinux(name);\n } else {\n console.error(`Unsupported platform: ${process.platform}`);\n process.exit(1);\n }\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -421,8 +421,8 @@ declare function loadConfig(): LocalConfig;
|
|
|
421
421
|
* Env var overrides take precedence over API values for debugging/testing.
|
|
422
422
|
*
|
|
423
423
|
* When running multiple agents on the same machine, stateDir and toolsDir
|
|
424
|
-
* are
|
|
425
|
-
*
|
|
424
|
+
* are namespaced by instance name (DESKFREE_INSTANCE_NAME, default "main").
|
|
425
|
+
* The instance name is set during `deskfree-agent install --name <name>`.
|
|
426
426
|
*/
|
|
427
427
|
declare function mergeWithRemoteConfig(local: LocalConfig, remote: RuntimeBootstrapConfig): RuntimeConfig;
|
|
428
428
|
|