clawdbot 2026.1.4-1 → 2026.1.5-1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +32 -6
- package/README.md +26 -1
- package/dist/agents/pi-embedded-runner.js +2 -0
- package/dist/agents/pi-embedded-subscribe.js +18 -3
- package/dist/agents/pi-tools.js +45 -6
- package/dist/agents/tools/browser-tool.js +38 -89
- package/dist/agents/tools/cron-tool.js +8 -8
- package/dist/agents/workspace.js +8 -1
- package/dist/auto-reply/command-detection.js +26 -0
- package/dist/auto-reply/reply/agent-runner.js +15 -8
- package/dist/auto-reply/reply/commands.js +36 -25
- package/dist/auto-reply/reply/directive-handling.js +4 -2
- package/dist/auto-reply/reply/directives.js +12 -0
- package/dist/auto-reply/reply/session-updates.js +2 -4
- package/dist/auto-reply/reply.js +26 -4
- package/dist/browser/config.js +22 -4
- package/dist/browser/profiles-service.js +3 -1
- package/dist/browser/profiles.js +14 -3
- package/dist/canvas-host/a2ui/.bundle.hash +2 -0
- package/dist/cli/gateway-cli.js +2 -2
- package/dist/cli/profile.js +81 -0
- package/dist/cli/program.js +10 -1
- package/dist/cli/run-main.js +33 -0
- package/dist/commands/configure.js +5 -0
- package/dist/commands/onboard-providers.js +1 -1
- package/dist/commands/setup.js +4 -1
- package/dist/config/defaults.js +56 -0
- package/dist/config/io.js +47 -6
- package/dist/config/paths.js +2 -2
- package/dist/config/port-defaults.js +32 -0
- package/dist/config/sessions.js +3 -2
- package/dist/config/validation.js +2 -2
- package/dist/config/zod-schema.js +16 -0
- package/dist/discord/monitor.js +75 -266
- package/dist/entry.js +16 -0
- package/dist/gateway/call.js +8 -1
- package/dist/gateway/server-methods/chat.js +1 -1
- package/dist/gateway/server.js +14 -3
- package/dist/index.js +2 -2
- package/dist/infra/control-ui-assets.js +118 -0
- package/dist/infra/dotenv.js +15 -0
- package/dist/infra/shell-env.js +79 -0
- package/dist/infra/system-events.js +50 -23
- package/dist/macos/relay.js +8 -2
- package/dist/telegram/bot.js +24 -1
- package/dist/utils.js +8 -2
- package/dist/web/auto-reply.js +18 -21
- package/dist/web/inbound.js +5 -1
- package/dist/web/qr-image.js +4 -4
- package/dist/web/session.js +2 -3
- package/docs/agent.md +0 -2
- package/docs/assets/markdown.css +4 -1
- package/docs/audio.md +0 -2
- package/docs/clawd.md +0 -2
- package/docs/configuration.md +62 -3
- package/docs/docs.json +9 -1
- package/docs/faq.md +32 -7
- package/docs/gateway.md +28 -0
- package/docs/images.md +0 -2
- package/docs/index.md +2 -4
- package/docs/mac/icon.md +1 -1
- package/docs/nix.md +57 -11
- package/docs/onboarding.md +0 -2
- package/docs/refactor/webagent-session.md +0 -2
- package/docs/research/memory.md +1 -1
- package/docs/skills.md +0 -2
- package/docs/templates/AGENTS.md +2 -2
- package/docs/tools.md +15 -0
- package/docs/whatsapp.md +2 -0
- package/package.json +9 -16
- package/dist/control-ui/assets/index-BFID3yAA.css +0 -1
- package/dist/control-ui/assets/index-CE_axlTS.js +0 -2235
- package/dist/control-ui/assets/index-CE_axlTS.js.map +0 -1
- package/dist/control-ui/index.html +0 -15
- package/dist/daemon/constants.js +0 -10
- package/dist/daemon/launchd.js +0 -276
- package/dist/daemon/legacy.js +0 -63
- package/dist/daemon/program-args.js +0 -76
- package/dist/daemon/schtasks.js +0 -257
- package/dist/daemon/service.js +0 -60
- package/dist/daemon/systemd.js +0 -266
- package/dist/imessage/client.js +0 -165
- package/dist/imessage/index.js +0 -3
- package/dist/imessage/monitor.js +0 -272
- package/dist/imessage/probe.js +0 -26
- package/dist/imessage/send.js +0 -83
- package/dist/imessage/targets.js +0 -176
- package/dist/signal/client.js +0 -134
- package/dist/signal/daemon.js +0 -69
- package/dist/signal/index.js +0 -3
- package/dist/signal/monitor.js +0 -336
- package/dist/signal/probe.js +0 -46
- package/dist/signal/send.js +0 -91
- package/dist/slack/actions.js +0 -97
- package/dist/slack/index.js +0 -5
- package/dist/slack/monitor.js +0 -1029
- package/dist/slack/probe.js +0 -47
- package/dist/slack/send.js +0 -131
- package/dist/slack/token.js +0 -10
- package/dist/tui/commands.js +0 -74
- package/dist/tui/components/assistant-message.js +0 -16
- package/dist/tui/components/chat-log.js +0 -92
- package/dist/tui/components/custom-editor.js +0 -53
- package/dist/tui/components/selectors.js +0 -8
- package/dist/tui/components/tool-execution.js +0 -111
- package/dist/tui/components/user-message.js +0 -17
- package/dist/tui/gateway-chat.js +0 -140
- package/dist/tui/layout.js +0 -41
- package/dist/tui/message-list.js +0 -57
- package/dist/tui/theme/theme.js +0 -80
- package/dist/tui/theme.js +0 -25
- package/dist/tui/tui.js +0 -708
- package/dist/wizard/clack-prompter.js +0 -56
- package/dist/wizard/onboarding.js +0 -452
- package/dist/wizard/prompts.js +0 -6
- package/dist/wizard/session.js +0 -203
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8" />
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
-
<title>Clawdbot Control</title>
|
|
7
|
-
<meta name="color-scheme" content="dark light" />
|
|
8
|
-
<script type="module" crossorigin src="/assets/index-CE_axlTS.js"></script>
|
|
9
|
-
<link rel="stylesheet" crossorigin href="/assets/index-BFID3yAA.css">
|
|
10
|
-
</head>
|
|
11
|
-
<body>
|
|
12
|
-
<clawdbot-app></clawdbot-app>
|
|
13
|
-
</body>
|
|
14
|
-
</html>
|
|
15
|
-
|
package/dist/daemon/constants.js
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
export const GATEWAY_LAUNCH_AGENT_LABEL = "com.clawdbot.gateway";
|
|
2
|
-
export const GATEWAY_SYSTEMD_SERVICE_NAME = "clawdbot-gateway";
|
|
3
|
-
export const GATEWAY_WINDOWS_TASK_NAME = "Clawdbot Gateway";
|
|
4
|
-
export const LEGACY_GATEWAY_LAUNCH_AGENT_LABELS = [
|
|
5
|
-
"com.steipete.clawdbot.gateway",
|
|
6
|
-
"com.steipete.clawdis.gateway",
|
|
7
|
-
"com.clawdis.gateway",
|
|
8
|
-
];
|
|
9
|
-
export const LEGACY_GATEWAY_SYSTEMD_SERVICE_NAMES = ["clawdis-gateway"];
|
|
10
|
-
export const LEGACY_GATEWAY_WINDOWS_TASK_NAMES = ["Clawdis Gateway"];
|
package/dist/daemon/launchd.js
DELETED
|
@@ -1,276 +0,0 @@
|
|
|
1
|
-
import { execFile } from "node:child_process";
|
|
2
|
-
import fs from "node:fs/promises";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
import { promisify } from "node:util";
|
|
5
|
-
import { GATEWAY_LAUNCH_AGENT_LABEL, LEGACY_GATEWAY_LAUNCH_AGENT_LABELS, } from "./constants.js";
|
|
6
|
-
const execFileAsync = promisify(execFile);
|
|
7
|
-
function resolveHomeDir(env) {
|
|
8
|
-
const home = env.HOME?.trim() || env.USERPROFILE?.trim();
|
|
9
|
-
if (!home)
|
|
10
|
-
throw new Error("Missing HOME");
|
|
11
|
-
return home;
|
|
12
|
-
}
|
|
13
|
-
function resolveLaunchAgentPlistPathForLabel(env, label) {
|
|
14
|
-
const home = resolveHomeDir(env);
|
|
15
|
-
return path.join(home, "Library", "LaunchAgents", `${label}.plist`);
|
|
16
|
-
}
|
|
17
|
-
export function resolveLaunchAgentPlistPath(env) {
|
|
18
|
-
return resolveLaunchAgentPlistPathForLabel(env, GATEWAY_LAUNCH_AGENT_LABEL);
|
|
19
|
-
}
|
|
20
|
-
export function resolveGatewayLogPaths(env) {
|
|
21
|
-
const home = resolveHomeDir(env);
|
|
22
|
-
const logDir = path.join(home, ".clawdbot", "logs");
|
|
23
|
-
return {
|
|
24
|
-
logDir,
|
|
25
|
-
stdoutPath: path.join(logDir, "gateway.log"),
|
|
26
|
-
stderrPath: path.join(logDir, "gateway.err.log"),
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
function plistEscape(value) {
|
|
30
|
-
return value
|
|
31
|
-
.replaceAll("&", "&")
|
|
32
|
-
.replaceAll("<", "<")
|
|
33
|
-
.replaceAll(">", ">")
|
|
34
|
-
.replaceAll('"', """)
|
|
35
|
-
.replaceAll("'", "'");
|
|
36
|
-
}
|
|
37
|
-
function plistUnescape(value) {
|
|
38
|
-
return value
|
|
39
|
-
.replaceAll("'", "'")
|
|
40
|
-
.replaceAll(""", '"')
|
|
41
|
-
.replaceAll(">", ">")
|
|
42
|
-
.replaceAll("<", "<")
|
|
43
|
-
.replaceAll("&", "&");
|
|
44
|
-
}
|
|
45
|
-
function renderEnvDict(env) {
|
|
46
|
-
if (!env)
|
|
47
|
-
return "";
|
|
48
|
-
const entries = Object.entries(env).filter(([, value]) => typeof value === "string" && value.trim());
|
|
49
|
-
if (entries.length === 0)
|
|
50
|
-
return "";
|
|
51
|
-
const items = entries
|
|
52
|
-
.map(([key, value]) => `
|
|
53
|
-
<key>${plistEscape(key)}</key>
|
|
54
|
-
<string>${plistEscape(value?.trim() ?? "")}</string>`)
|
|
55
|
-
.join("");
|
|
56
|
-
return `
|
|
57
|
-
<key>EnvironmentVariables</key>
|
|
58
|
-
<dict>${items}
|
|
59
|
-
</dict>`;
|
|
60
|
-
}
|
|
61
|
-
export async function readLaunchAgentProgramArguments(env) {
|
|
62
|
-
const plistPath = resolveLaunchAgentPlistPath(env);
|
|
63
|
-
try {
|
|
64
|
-
const plist = await fs.readFile(plistPath, "utf8");
|
|
65
|
-
const programMatch = plist.match(/<key>ProgramArguments<\/key>\s*<array>([\s\S]*?)<\/array>/i);
|
|
66
|
-
if (!programMatch)
|
|
67
|
-
return null;
|
|
68
|
-
const args = Array.from(programMatch[1].matchAll(/<string>([\s\S]*?)<\/string>/gi)).map((match) => plistUnescape(match[1] ?? "").trim());
|
|
69
|
-
const workingDirMatch = plist.match(/<key>WorkingDirectory<\/key>\s*<string>([\s\S]*?)<\/string>/i);
|
|
70
|
-
const workingDirectory = workingDirMatch
|
|
71
|
-
? plistUnescape(workingDirMatch[1] ?? "").trim()
|
|
72
|
-
: "";
|
|
73
|
-
return {
|
|
74
|
-
programArguments: args.filter(Boolean),
|
|
75
|
-
...(workingDirectory ? { workingDirectory } : {}),
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
catch {
|
|
79
|
-
return null;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
export function buildLaunchAgentPlist({ label = GATEWAY_LAUNCH_AGENT_LABEL, programArguments, workingDirectory, stdoutPath, stderrPath, environment, }) {
|
|
83
|
-
const argsXml = programArguments
|
|
84
|
-
.map((arg) => `\n <string>${plistEscape(arg)}</string>`)
|
|
85
|
-
.join("");
|
|
86
|
-
const workingDirXml = workingDirectory
|
|
87
|
-
? `
|
|
88
|
-
<key>WorkingDirectory</key>
|
|
89
|
-
<string>${plistEscape(workingDirectory)}</string>`
|
|
90
|
-
: "";
|
|
91
|
-
const envXml = renderEnvDict(environment);
|
|
92
|
-
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
93
|
-
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
94
|
-
<plist version="1.0">
|
|
95
|
-
<dict>
|
|
96
|
-
<key>Label</key>
|
|
97
|
-
<string>${plistEscape(label)}</string>
|
|
98
|
-
<key>RunAtLoad</key>
|
|
99
|
-
<true/>
|
|
100
|
-
<key>KeepAlive</key>
|
|
101
|
-
<true/>
|
|
102
|
-
<key>ProgramArguments</key>
|
|
103
|
-
<array>${argsXml}
|
|
104
|
-
</array>
|
|
105
|
-
${workingDirXml}
|
|
106
|
-
<key>StandardOutPath</key>
|
|
107
|
-
<string>${plistEscape(stdoutPath)}</string>
|
|
108
|
-
<key>StandardErrorPath</key>
|
|
109
|
-
<string>${plistEscape(stderrPath)}</string>${envXml}
|
|
110
|
-
</dict>
|
|
111
|
-
</plist>
|
|
112
|
-
`;
|
|
113
|
-
}
|
|
114
|
-
async function execLaunchctl(args) {
|
|
115
|
-
try {
|
|
116
|
-
const { stdout, stderr } = await execFileAsync("launchctl", args, {
|
|
117
|
-
encoding: "utf8",
|
|
118
|
-
});
|
|
119
|
-
return {
|
|
120
|
-
stdout: String(stdout ?? ""),
|
|
121
|
-
stderr: String(stderr ?? ""),
|
|
122
|
-
code: 0,
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
catch (error) {
|
|
126
|
-
const e = error;
|
|
127
|
-
return {
|
|
128
|
-
stdout: typeof e.stdout === "string" ? e.stdout : "",
|
|
129
|
-
stderr: typeof e.stderr === "string"
|
|
130
|
-
? e.stderr
|
|
131
|
-
: typeof e.message === "string"
|
|
132
|
-
? e.message
|
|
133
|
-
: "",
|
|
134
|
-
code: typeof e.code === "number" ? e.code : 1,
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
function resolveGuiDomain() {
|
|
139
|
-
if (typeof process.getuid !== "function")
|
|
140
|
-
return "gui/501";
|
|
141
|
-
return `gui/${process.getuid()}`;
|
|
142
|
-
}
|
|
143
|
-
export async function isLaunchAgentLoaded() {
|
|
144
|
-
const domain = resolveGuiDomain();
|
|
145
|
-
const label = GATEWAY_LAUNCH_AGENT_LABEL;
|
|
146
|
-
const res = await execLaunchctl(["print", `${domain}/${label}`]);
|
|
147
|
-
return res.code === 0;
|
|
148
|
-
}
|
|
149
|
-
export async function findLegacyLaunchAgents(env) {
|
|
150
|
-
const domain = resolveGuiDomain();
|
|
151
|
-
const results = [];
|
|
152
|
-
for (const label of LEGACY_GATEWAY_LAUNCH_AGENT_LABELS) {
|
|
153
|
-
const plistPath = resolveLaunchAgentPlistPathForLabel(env, label);
|
|
154
|
-
const res = await execLaunchctl(["print", `${domain}/${label}`]);
|
|
155
|
-
const loaded = res.code === 0;
|
|
156
|
-
let exists = false;
|
|
157
|
-
try {
|
|
158
|
-
await fs.access(plistPath);
|
|
159
|
-
exists = true;
|
|
160
|
-
}
|
|
161
|
-
catch {
|
|
162
|
-
// ignore
|
|
163
|
-
}
|
|
164
|
-
if (loaded || exists) {
|
|
165
|
-
results.push({ label, plistPath, loaded, exists });
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
return results;
|
|
169
|
-
}
|
|
170
|
-
export async function uninstallLegacyLaunchAgents({ env, stdout, }) {
|
|
171
|
-
const domain = resolveGuiDomain();
|
|
172
|
-
const agents = await findLegacyLaunchAgents(env);
|
|
173
|
-
if (agents.length === 0)
|
|
174
|
-
return agents;
|
|
175
|
-
const home = resolveHomeDir(env);
|
|
176
|
-
const trashDir = path.join(home, ".Trash");
|
|
177
|
-
try {
|
|
178
|
-
await fs.mkdir(trashDir, { recursive: true });
|
|
179
|
-
}
|
|
180
|
-
catch {
|
|
181
|
-
// ignore
|
|
182
|
-
}
|
|
183
|
-
for (const agent of agents) {
|
|
184
|
-
await execLaunchctl(["bootout", domain, agent.plistPath]);
|
|
185
|
-
await execLaunchctl(["unload", agent.plistPath]);
|
|
186
|
-
try {
|
|
187
|
-
await fs.access(agent.plistPath);
|
|
188
|
-
}
|
|
189
|
-
catch {
|
|
190
|
-
continue;
|
|
191
|
-
}
|
|
192
|
-
const dest = path.join(trashDir, `${agent.label}.plist`);
|
|
193
|
-
try {
|
|
194
|
-
await fs.rename(agent.plistPath, dest);
|
|
195
|
-
stdout.write(`Moved legacy LaunchAgent to Trash: ${dest}\n`);
|
|
196
|
-
}
|
|
197
|
-
catch {
|
|
198
|
-
stdout.write(`Legacy LaunchAgent remains at ${agent.plistPath} (could not move)\n`);
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
return agents;
|
|
202
|
-
}
|
|
203
|
-
export async function uninstallLaunchAgent({ env, stdout, }) {
|
|
204
|
-
const domain = resolveGuiDomain();
|
|
205
|
-
const plistPath = resolveLaunchAgentPlistPath(env);
|
|
206
|
-
await execLaunchctl(["bootout", domain, plistPath]);
|
|
207
|
-
await execLaunchctl(["unload", plistPath]);
|
|
208
|
-
try {
|
|
209
|
-
await fs.access(plistPath);
|
|
210
|
-
}
|
|
211
|
-
catch {
|
|
212
|
-
stdout.write(`LaunchAgent not found at ${plistPath}\n`);
|
|
213
|
-
return;
|
|
214
|
-
}
|
|
215
|
-
const home = resolveHomeDir(env);
|
|
216
|
-
const trashDir = path.join(home, ".Trash");
|
|
217
|
-
const dest = path.join(trashDir, `${GATEWAY_LAUNCH_AGENT_LABEL}.plist`);
|
|
218
|
-
try {
|
|
219
|
-
await fs.mkdir(trashDir, { recursive: true });
|
|
220
|
-
await fs.rename(plistPath, dest);
|
|
221
|
-
stdout.write(`Moved LaunchAgent to Trash: ${dest}\n`);
|
|
222
|
-
}
|
|
223
|
-
catch {
|
|
224
|
-
stdout.write(`LaunchAgent remains at ${plistPath} (could not move)\n`);
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
export async function installLaunchAgent({ env, stdout, programArguments, workingDirectory, environment, }) {
|
|
228
|
-
const { logDir, stdoutPath, stderrPath } = resolveGatewayLogPaths(env);
|
|
229
|
-
await fs.mkdir(logDir, { recursive: true });
|
|
230
|
-
const domain = resolveGuiDomain();
|
|
231
|
-
for (const legacyLabel of LEGACY_GATEWAY_LAUNCH_AGENT_LABELS) {
|
|
232
|
-
const legacyPlistPath = resolveLaunchAgentPlistPathForLabel(env, legacyLabel);
|
|
233
|
-
await execLaunchctl(["bootout", domain, legacyPlistPath]);
|
|
234
|
-
await execLaunchctl(["unload", legacyPlistPath]);
|
|
235
|
-
try {
|
|
236
|
-
await fs.unlink(legacyPlistPath);
|
|
237
|
-
}
|
|
238
|
-
catch {
|
|
239
|
-
// ignore
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
const plistPath = resolveLaunchAgentPlistPath(env);
|
|
243
|
-
await fs.mkdir(path.dirname(plistPath), { recursive: true });
|
|
244
|
-
const plist = buildLaunchAgentPlist({
|
|
245
|
-
programArguments,
|
|
246
|
-
workingDirectory,
|
|
247
|
-
stdoutPath,
|
|
248
|
-
stderrPath,
|
|
249
|
-
environment,
|
|
250
|
-
});
|
|
251
|
-
await fs.writeFile(plistPath, plist, "utf8");
|
|
252
|
-
await execLaunchctl(["bootout", domain, plistPath]);
|
|
253
|
-
await execLaunchctl(["unload", plistPath]);
|
|
254
|
-
const boot = await execLaunchctl(["bootstrap", domain, plistPath]);
|
|
255
|
-
if (boot.code !== 0) {
|
|
256
|
-
throw new Error(`launchctl bootstrap failed: ${boot.stderr || boot.stdout}`.trim());
|
|
257
|
-
}
|
|
258
|
-
await execLaunchctl(["enable", `${domain}/${GATEWAY_LAUNCH_AGENT_LABEL}`]);
|
|
259
|
-
await execLaunchctl([
|
|
260
|
-
"kickstart",
|
|
261
|
-
"-k",
|
|
262
|
-
`${domain}/${GATEWAY_LAUNCH_AGENT_LABEL}`,
|
|
263
|
-
]);
|
|
264
|
-
stdout.write(`Installed LaunchAgent: ${plistPath}\n`);
|
|
265
|
-
stdout.write(`Logs: ${stdoutPath}\n`);
|
|
266
|
-
return { plistPath };
|
|
267
|
-
}
|
|
268
|
-
export async function restartLaunchAgent({ stdout, }) {
|
|
269
|
-
const domain = resolveGuiDomain();
|
|
270
|
-
const label = GATEWAY_LAUNCH_AGENT_LABEL;
|
|
271
|
-
const res = await execLaunchctl(["kickstart", "-k", `${domain}/${label}`]);
|
|
272
|
-
if (res.code !== 0) {
|
|
273
|
-
throw new Error(`launchctl kickstart failed: ${res.stderr || res.stdout}`.trim());
|
|
274
|
-
}
|
|
275
|
-
stdout.write(`Restarted LaunchAgent: ${domain}/${label}\n`);
|
|
276
|
-
}
|
package/dist/daemon/legacy.js
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { findLegacyLaunchAgents, uninstallLegacyLaunchAgents, } from "./launchd.js";
|
|
2
|
-
import { findLegacyScheduledTasks, uninstallLegacyScheduledTasks, } from "./schtasks.js";
|
|
3
|
-
import { findLegacySystemdUnits, uninstallLegacySystemdUnits, } from "./systemd.js";
|
|
4
|
-
function formatLegacyLaunchAgents(agents) {
|
|
5
|
-
return agents.map((agent) => ({
|
|
6
|
-
platform: "darwin",
|
|
7
|
-
label: agent.label,
|
|
8
|
-
detail: [
|
|
9
|
-
agent.loaded ? "loaded" : "not loaded",
|
|
10
|
-
agent.exists ? `plist: ${agent.plistPath}` : "plist missing",
|
|
11
|
-
].join(", "),
|
|
12
|
-
}));
|
|
13
|
-
}
|
|
14
|
-
function formatLegacySystemdUnits(units) {
|
|
15
|
-
return units.map((unit) => ({
|
|
16
|
-
platform: "linux",
|
|
17
|
-
label: `${unit.name}.service`,
|
|
18
|
-
detail: [
|
|
19
|
-
unit.enabled ? "enabled" : "disabled",
|
|
20
|
-
unit.exists ? `unit: ${unit.unitPath}` : "unit missing",
|
|
21
|
-
].join(", "),
|
|
22
|
-
}));
|
|
23
|
-
}
|
|
24
|
-
function formatLegacyScheduledTasks(tasks) {
|
|
25
|
-
return tasks.map((task) => ({
|
|
26
|
-
platform: "win32",
|
|
27
|
-
label: task.name,
|
|
28
|
-
detail: [
|
|
29
|
-
task.installed ? "installed" : "not installed",
|
|
30
|
-
task.scriptExists ? `script: ${task.scriptPath}` : "script missing",
|
|
31
|
-
].join(", "),
|
|
32
|
-
}));
|
|
33
|
-
}
|
|
34
|
-
export async function findLegacyGatewayServices(env) {
|
|
35
|
-
if (process.platform === "darwin") {
|
|
36
|
-
const agents = await findLegacyLaunchAgents(env);
|
|
37
|
-
return formatLegacyLaunchAgents(agents);
|
|
38
|
-
}
|
|
39
|
-
if (process.platform === "linux") {
|
|
40
|
-
const units = await findLegacySystemdUnits(env);
|
|
41
|
-
return formatLegacySystemdUnits(units);
|
|
42
|
-
}
|
|
43
|
-
if (process.platform === "win32") {
|
|
44
|
-
const tasks = await findLegacyScheduledTasks(env);
|
|
45
|
-
return formatLegacyScheduledTasks(tasks);
|
|
46
|
-
}
|
|
47
|
-
return [];
|
|
48
|
-
}
|
|
49
|
-
export async function uninstallLegacyGatewayServices({ env, stdout, }) {
|
|
50
|
-
if (process.platform === "darwin") {
|
|
51
|
-
const agents = await uninstallLegacyLaunchAgents({ env, stdout });
|
|
52
|
-
return formatLegacyLaunchAgents(agents);
|
|
53
|
-
}
|
|
54
|
-
if (process.platform === "linux") {
|
|
55
|
-
const units = await uninstallLegacySystemdUnits({ env, stdout });
|
|
56
|
-
return formatLegacySystemdUnits(units);
|
|
57
|
-
}
|
|
58
|
-
if (process.platform === "win32") {
|
|
59
|
-
const tasks = await uninstallLegacyScheduledTasks({ env, stdout });
|
|
60
|
-
return formatLegacyScheduledTasks(tasks);
|
|
61
|
-
}
|
|
62
|
-
return [];
|
|
63
|
-
}
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs/promises";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
function isNodeRuntime(execPath) {
|
|
4
|
-
const base = path.basename(execPath).toLowerCase();
|
|
5
|
-
return base === "node" || base === "node.exe";
|
|
6
|
-
}
|
|
7
|
-
async function resolveCliEntrypointPathForService() {
|
|
8
|
-
const argv1 = process.argv[1];
|
|
9
|
-
if (!argv1)
|
|
10
|
-
throw new Error("Unable to resolve CLI entrypoint path");
|
|
11
|
-
const normalized = path.resolve(argv1);
|
|
12
|
-
const looksLikeDist = /[/\\]dist[/\\].+\.(cjs|js|mjs)$/.test(normalized);
|
|
13
|
-
if (looksLikeDist) {
|
|
14
|
-
await fs.access(normalized);
|
|
15
|
-
return normalized;
|
|
16
|
-
}
|
|
17
|
-
const distCandidates = [
|
|
18
|
-
path.resolve(path.dirname(normalized), "..", "dist", "index.js"),
|
|
19
|
-
path.resolve(path.dirname(normalized), "..", "dist", "index.mjs"),
|
|
20
|
-
path.resolve(path.dirname(normalized), "dist", "index.js"),
|
|
21
|
-
path.resolve(path.dirname(normalized), "dist", "index.mjs"),
|
|
22
|
-
];
|
|
23
|
-
for (const candidate of distCandidates) {
|
|
24
|
-
try {
|
|
25
|
-
await fs.access(candidate);
|
|
26
|
-
return candidate;
|
|
27
|
-
}
|
|
28
|
-
catch {
|
|
29
|
-
// keep going
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
throw new Error(`Cannot find built CLI at ${distCandidates.join(" or ")}. Run "pnpm build" first, or use dev mode.`);
|
|
33
|
-
}
|
|
34
|
-
function resolveRepoRootForDev() {
|
|
35
|
-
const argv1 = process.argv[1];
|
|
36
|
-
if (!argv1)
|
|
37
|
-
throw new Error("Unable to resolve repo root");
|
|
38
|
-
const normalized = path.resolve(argv1);
|
|
39
|
-
const parts = normalized.split(path.sep);
|
|
40
|
-
const srcIndex = parts.lastIndexOf("src");
|
|
41
|
-
if (srcIndex === -1) {
|
|
42
|
-
throw new Error("Dev mode requires running from repo (src/index.ts)");
|
|
43
|
-
}
|
|
44
|
-
return parts.slice(0, srcIndex).join(path.sep);
|
|
45
|
-
}
|
|
46
|
-
async function resolveTsxCliPath(repoRoot) {
|
|
47
|
-
const candidate = path.join(repoRoot, "node_modules", "tsx", "dist", "cli.mjs");
|
|
48
|
-
await fs.access(candidate);
|
|
49
|
-
return candidate;
|
|
50
|
-
}
|
|
51
|
-
export async function resolveGatewayProgramArguments(params) {
|
|
52
|
-
const gatewayArgs = ["gateway-daemon", "--port", String(params.port)];
|
|
53
|
-
const nodePath = process.execPath;
|
|
54
|
-
if (!params.dev) {
|
|
55
|
-
try {
|
|
56
|
-
const cliEntrypointPath = await resolveCliEntrypointPathForService();
|
|
57
|
-
return {
|
|
58
|
-
programArguments: [nodePath, cliEntrypointPath, ...gatewayArgs],
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
catch (error) {
|
|
62
|
-
if (!isNodeRuntime(nodePath)) {
|
|
63
|
-
return { programArguments: [nodePath, ...gatewayArgs] };
|
|
64
|
-
}
|
|
65
|
-
throw error;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
const repoRoot = resolveRepoRootForDev();
|
|
69
|
-
const tsxCliPath = await resolveTsxCliPath(repoRoot);
|
|
70
|
-
const devCliPath = path.join(repoRoot, "src", "index.ts");
|
|
71
|
-
await fs.access(devCliPath);
|
|
72
|
-
return {
|
|
73
|
-
programArguments: [nodePath, tsxCliPath, devCliPath, ...gatewayArgs],
|
|
74
|
-
workingDirectory: repoRoot,
|
|
75
|
-
};
|
|
76
|
-
}
|
package/dist/daemon/schtasks.js
DELETED
|
@@ -1,257 +0,0 @@
|
|
|
1
|
-
import { execFile } from "node:child_process";
|
|
2
|
-
import fs from "node:fs/promises";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
import { promisify } from "node:util";
|
|
5
|
-
import { GATEWAY_WINDOWS_TASK_NAME, LEGACY_GATEWAY_WINDOWS_TASK_NAMES, } from "./constants.js";
|
|
6
|
-
const execFileAsync = promisify(execFile);
|
|
7
|
-
function resolveHomeDir(env) {
|
|
8
|
-
const home = env.USERPROFILE?.trim() || env.HOME?.trim();
|
|
9
|
-
if (!home)
|
|
10
|
-
throw new Error("Missing HOME");
|
|
11
|
-
return home;
|
|
12
|
-
}
|
|
13
|
-
function resolveTaskScriptPath(env) {
|
|
14
|
-
const home = resolveHomeDir(env);
|
|
15
|
-
return path.join(home, ".clawdbot", "gateway.cmd");
|
|
16
|
-
}
|
|
17
|
-
function resolveLegacyTaskScriptPath(env) {
|
|
18
|
-
const home = resolveHomeDir(env);
|
|
19
|
-
return path.join(home, ".clawdis", "gateway.cmd");
|
|
20
|
-
}
|
|
21
|
-
function quoteCmdArg(value) {
|
|
22
|
-
if (!/[ \t"]/g.test(value))
|
|
23
|
-
return value;
|
|
24
|
-
return `"${value.replace(/"/g, '\\"')}"`;
|
|
25
|
-
}
|
|
26
|
-
function parseCommandLine(value) {
|
|
27
|
-
const args = [];
|
|
28
|
-
let current = "";
|
|
29
|
-
let inQuotes = false;
|
|
30
|
-
let escapeNext = false;
|
|
31
|
-
for (const char of value) {
|
|
32
|
-
if (escapeNext) {
|
|
33
|
-
current += char;
|
|
34
|
-
escapeNext = false;
|
|
35
|
-
continue;
|
|
36
|
-
}
|
|
37
|
-
if (char === "\\") {
|
|
38
|
-
escapeNext = true;
|
|
39
|
-
continue;
|
|
40
|
-
}
|
|
41
|
-
if (char === '"') {
|
|
42
|
-
inQuotes = !inQuotes;
|
|
43
|
-
continue;
|
|
44
|
-
}
|
|
45
|
-
if (!inQuotes && /\s/.test(char)) {
|
|
46
|
-
if (current) {
|
|
47
|
-
args.push(current);
|
|
48
|
-
current = "";
|
|
49
|
-
}
|
|
50
|
-
continue;
|
|
51
|
-
}
|
|
52
|
-
current += char;
|
|
53
|
-
}
|
|
54
|
-
if (current)
|
|
55
|
-
args.push(current);
|
|
56
|
-
return args;
|
|
57
|
-
}
|
|
58
|
-
export async function readScheduledTaskCommand(env) {
|
|
59
|
-
const scriptPath = resolveTaskScriptPath(env);
|
|
60
|
-
try {
|
|
61
|
-
const content = await fs.readFile(scriptPath, "utf8");
|
|
62
|
-
let workingDirectory = "";
|
|
63
|
-
let commandLine = "";
|
|
64
|
-
for (const rawLine of content.split(/\r?\n/)) {
|
|
65
|
-
const line = rawLine.trim();
|
|
66
|
-
if (!line)
|
|
67
|
-
continue;
|
|
68
|
-
if (line.startsWith("@echo"))
|
|
69
|
-
continue;
|
|
70
|
-
if (line.toLowerCase().startsWith("rem "))
|
|
71
|
-
continue;
|
|
72
|
-
if (line.toLowerCase().startsWith("set "))
|
|
73
|
-
continue;
|
|
74
|
-
if (line.toLowerCase().startsWith("cd /d ")) {
|
|
75
|
-
workingDirectory = line
|
|
76
|
-
.slice("cd /d ".length)
|
|
77
|
-
.trim()
|
|
78
|
-
.replace(/^"|"$/g, "");
|
|
79
|
-
continue;
|
|
80
|
-
}
|
|
81
|
-
commandLine = line;
|
|
82
|
-
break;
|
|
83
|
-
}
|
|
84
|
-
if (!commandLine)
|
|
85
|
-
return null;
|
|
86
|
-
return {
|
|
87
|
-
programArguments: parseCommandLine(commandLine),
|
|
88
|
-
...(workingDirectory ? { workingDirectory } : {}),
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
catch {
|
|
92
|
-
return null;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
function buildTaskScript({ programArguments, workingDirectory, environment, }) {
|
|
96
|
-
const lines = ["@echo off"];
|
|
97
|
-
if (workingDirectory) {
|
|
98
|
-
lines.push(`cd /d ${quoteCmdArg(workingDirectory)}`);
|
|
99
|
-
}
|
|
100
|
-
if (environment) {
|
|
101
|
-
for (const [key, value] of Object.entries(environment)) {
|
|
102
|
-
if (!value)
|
|
103
|
-
continue;
|
|
104
|
-
lines.push(`set ${key}=${value}`);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
const command = programArguments.map(quoteCmdArg).join(" ");
|
|
108
|
-
lines.push(command);
|
|
109
|
-
return `${lines.join("\r\n")}\r\n`;
|
|
110
|
-
}
|
|
111
|
-
async function execSchtasks(args) {
|
|
112
|
-
try {
|
|
113
|
-
const { stdout, stderr } = await execFileAsync("schtasks", args, {
|
|
114
|
-
encoding: "utf8",
|
|
115
|
-
windowsHide: true,
|
|
116
|
-
});
|
|
117
|
-
return {
|
|
118
|
-
stdout: String(stdout ?? ""),
|
|
119
|
-
stderr: String(stderr ?? ""),
|
|
120
|
-
code: 0,
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
catch (error) {
|
|
124
|
-
const e = error;
|
|
125
|
-
return {
|
|
126
|
-
stdout: typeof e.stdout === "string" ? e.stdout : "",
|
|
127
|
-
stderr: typeof e.stderr === "string"
|
|
128
|
-
? e.stderr
|
|
129
|
-
: typeof e.message === "string"
|
|
130
|
-
? e.message
|
|
131
|
-
: "",
|
|
132
|
-
code: typeof e.code === "number" ? e.code : 1,
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
async function assertSchtasksAvailable() {
|
|
137
|
-
const res = await execSchtasks(["/Query"]);
|
|
138
|
-
if (res.code === 0)
|
|
139
|
-
return;
|
|
140
|
-
const detail = res.stderr || res.stdout;
|
|
141
|
-
throw new Error(`schtasks unavailable: ${detail || "unknown error"}`.trim());
|
|
142
|
-
}
|
|
143
|
-
export async function installScheduledTask({ env, stdout, programArguments, workingDirectory, environment, }) {
|
|
144
|
-
await assertSchtasksAvailable();
|
|
145
|
-
const scriptPath = resolveTaskScriptPath(env);
|
|
146
|
-
await fs.mkdir(path.dirname(scriptPath), { recursive: true });
|
|
147
|
-
const script = buildTaskScript({
|
|
148
|
-
programArguments,
|
|
149
|
-
workingDirectory,
|
|
150
|
-
environment,
|
|
151
|
-
});
|
|
152
|
-
await fs.writeFile(scriptPath, script, "utf8");
|
|
153
|
-
const quotedScript = quoteCmdArg(scriptPath);
|
|
154
|
-
const create = await execSchtasks([
|
|
155
|
-
"/Create",
|
|
156
|
-
"/F",
|
|
157
|
-
"/SC",
|
|
158
|
-
"ONLOGON",
|
|
159
|
-
"/RL",
|
|
160
|
-
"LIMITED",
|
|
161
|
-
"/TN",
|
|
162
|
-
GATEWAY_WINDOWS_TASK_NAME,
|
|
163
|
-
"/TR",
|
|
164
|
-
quotedScript,
|
|
165
|
-
]);
|
|
166
|
-
if (create.code !== 0) {
|
|
167
|
-
throw new Error(`schtasks create failed: ${create.stderr || create.stdout}`.trim());
|
|
168
|
-
}
|
|
169
|
-
await execSchtasks(["/Run", "/TN", GATEWAY_WINDOWS_TASK_NAME]);
|
|
170
|
-
stdout.write(`Installed Scheduled Task: ${GATEWAY_WINDOWS_TASK_NAME}\n`);
|
|
171
|
-
stdout.write(`Task script: ${scriptPath}\n`);
|
|
172
|
-
return { scriptPath };
|
|
173
|
-
}
|
|
174
|
-
export async function uninstallScheduledTask({ env, stdout, }) {
|
|
175
|
-
await assertSchtasksAvailable();
|
|
176
|
-
await execSchtasks(["/Delete", "/F", "/TN", GATEWAY_WINDOWS_TASK_NAME]);
|
|
177
|
-
const scriptPath = resolveTaskScriptPath(env);
|
|
178
|
-
try {
|
|
179
|
-
await fs.unlink(scriptPath);
|
|
180
|
-
stdout.write(`Removed task script: ${scriptPath}\n`);
|
|
181
|
-
}
|
|
182
|
-
catch {
|
|
183
|
-
stdout.write(`Task script not found at ${scriptPath}\n`);
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
export async function restartScheduledTask({ stdout, }) {
|
|
187
|
-
await assertSchtasksAvailable();
|
|
188
|
-
await execSchtasks(["/End", "/TN", GATEWAY_WINDOWS_TASK_NAME]);
|
|
189
|
-
const res = await execSchtasks(["/Run", "/TN", GATEWAY_WINDOWS_TASK_NAME]);
|
|
190
|
-
if (res.code !== 0) {
|
|
191
|
-
throw new Error(`schtasks run failed: ${res.stderr || res.stdout}`.trim());
|
|
192
|
-
}
|
|
193
|
-
stdout.write(`Restarted Scheduled Task: ${GATEWAY_WINDOWS_TASK_NAME}\n`);
|
|
194
|
-
}
|
|
195
|
-
export async function isScheduledTaskInstalled() {
|
|
196
|
-
await assertSchtasksAvailable();
|
|
197
|
-
const res = await execSchtasks(["/Query", "/TN", GATEWAY_WINDOWS_TASK_NAME]);
|
|
198
|
-
return res.code === 0;
|
|
199
|
-
}
|
|
200
|
-
export async function findLegacyScheduledTasks(env) {
|
|
201
|
-
const results = [];
|
|
202
|
-
let schtasksAvailable = true;
|
|
203
|
-
try {
|
|
204
|
-
await assertSchtasksAvailable();
|
|
205
|
-
}
|
|
206
|
-
catch {
|
|
207
|
-
schtasksAvailable = false;
|
|
208
|
-
}
|
|
209
|
-
for (const name of LEGACY_GATEWAY_WINDOWS_TASK_NAMES) {
|
|
210
|
-
const scriptPath = resolveLegacyTaskScriptPath(env);
|
|
211
|
-
let installed = false;
|
|
212
|
-
if (schtasksAvailable) {
|
|
213
|
-
const res = await execSchtasks(["/Query", "/TN", name]);
|
|
214
|
-
installed = res.code === 0;
|
|
215
|
-
}
|
|
216
|
-
let scriptExists = false;
|
|
217
|
-
try {
|
|
218
|
-
await fs.access(scriptPath);
|
|
219
|
-
scriptExists = true;
|
|
220
|
-
}
|
|
221
|
-
catch {
|
|
222
|
-
// ignore
|
|
223
|
-
}
|
|
224
|
-
if (installed || scriptExists) {
|
|
225
|
-
results.push({ name, scriptPath, installed, scriptExists });
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
return results;
|
|
229
|
-
}
|
|
230
|
-
export async function uninstallLegacyScheduledTasks({ env, stdout, }) {
|
|
231
|
-
const tasks = await findLegacyScheduledTasks(env);
|
|
232
|
-
if (tasks.length === 0)
|
|
233
|
-
return tasks;
|
|
234
|
-
let schtasksAvailable = true;
|
|
235
|
-
try {
|
|
236
|
-
await assertSchtasksAvailable();
|
|
237
|
-
}
|
|
238
|
-
catch {
|
|
239
|
-
schtasksAvailable = false;
|
|
240
|
-
}
|
|
241
|
-
for (const task of tasks) {
|
|
242
|
-
if (schtasksAvailable && task.installed) {
|
|
243
|
-
await execSchtasks(["/Delete", "/F", "/TN", task.name]);
|
|
244
|
-
}
|
|
245
|
-
else if (!schtasksAvailable && task.installed) {
|
|
246
|
-
stdout.write(`schtasks unavailable; unable to remove legacy task: ${task.name}\n`);
|
|
247
|
-
}
|
|
248
|
-
try {
|
|
249
|
-
await fs.unlink(task.scriptPath);
|
|
250
|
-
stdout.write(`Removed legacy task script: ${task.scriptPath}\n`);
|
|
251
|
-
}
|
|
252
|
-
catch {
|
|
253
|
-
stdout.write(`Legacy task script not found at ${task.scriptPath}\n`);
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
return tasks;
|
|
257
|
-
}
|