hyperclaw 4.0.2 → 5.0.0
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/README.md +54 -3
- package/dist/a2ui-protocol-CfBI44-Q.js +75 -0
- package/dist/agents-routing-ChHiZp36.js +327 -0
- package/dist/agents-routing-ChqZ6l2S.js +4 -0
- package/dist/api-keys-guide-BCcOl0Q7.js +149 -0
- package/dist/audit-BaIiyWFu.js +441 -0
- package/dist/bounty-tools-DWudyZie.js +211 -0
- package/dist/browser-tools-BsTeGMnX.js +5 -0
- package/dist/browser-tools-D8_rLe2p.js +179 -0
- package/dist/claw-tasks-CgTsiNE8.js +80 -0
- package/dist/connector-5N0-X_xs.js +194 -0
- package/dist/connector-B3v0qcXg.js +425 -0
- package/dist/connector-B8R3iBY1.js +280 -0
- package/dist/connector-BAM-08NN.js +189 -0
- package/dist/connector-BC8FIVu4.js +181 -0
- package/dist/connector-BDmwwaVc.js +213 -0
- package/dist/connector-BGjbBy69.js +225 -0
- package/dist/connector-BO2SRzfG.js +218 -0
- package/dist/connector-BfXky0L3.js +167 -0
- package/dist/connector-BiiSJpx3.js +192 -0
- package/dist/connector-BnDmIhIu.js +85 -0
- package/dist/connector-C1HSoUyk.js +189 -0
- package/dist/connector-CKQHZOXg.js +568 -0
- package/dist/connector-CRl-iidy.js +239 -0
- package/dist/connector-Ci9glMD-.js +340 -0
- package/dist/connector-CjtZIEDj.js +181 -0
- package/dist/connector-Ck6JtOsX.js +531 -0
- package/dist/connector-D8Kelee0.js +286 -0
- package/dist/connector-DAnRJ0oP.js +162 -0
- package/dist/connector-DXTp5PE8.js +508 -0
- package/dist/connector-Dih6dUPP.js +173 -0
- package/dist/connector-DqTH_tPX.js +182 -0
- package/dist/connector-DrnEiiyP.js +419 -0
- package/dist/connector-DtR5GGTX.js +167 -0
- package/dist/connector-Tky_qS_K.js +350 -0
- package/dist/connector-ZSc3oTTy.js +305 -0
- package/dist/connector-sW5yhU1m.js +498 -0
- package/dist/connector-u3ICd3Ic.js +552 -0
- package/dist/cost-tracker-DD9wtWsr.js +103 -0
- package/dist/credentials-store-C6ir0Dae.js +4 -0
- package/dist/credentials-store-H13LqOwJ.js +77 -0
- package/dist/cron-tasks-Bli7Kzd2.js +82 -0
- package/dist/daemon-Bg4GtCmc.js +318 -0
- package/dist/daemon-DhmwY8k4.js +5 -0
- package/dist/delivery-BmIYy9VQ.js +4 -0
- package/dist/delivery-pWUPBp1F.js +95 -0
- package/dist/destructive-gate-D6vWOdEl.js +101 -0
- package/dist/developer-keys-CPWT7Q6S.js +8 -0
- package/dist/developer-keys-DrrcUqFa.js +127 -0
- package/dist/doctor-BvCe8BBk.js +230 -0
- package/dist/doctor-CxyPLYsJ.js +6 -0
- package/dist/engine-CEDSqXfw.js +256 -0
- package/dist/engine-Da4JMNpI.js +7 -0
- package/dist/env-resolve-CiXbWYwe.js +10 -0
- package/dist/env-resolve-CmGWhWXJ.js +115 -0
- package/dist/extraction-tools-HOZstZ0y.js +91 -0
- package/dist/extraction-tools-m4lmAv7l.js +5 -0
- package/dist/form_data-Cz040rio.js +8657 -0
- package/dist/gmail-watch-setup-Du7DVV7S.js +40 -0
- package/dist/health-B-asI__D.js +6 -0
- package/dist/health-Ds2YlpTB.js +152 -0
- package/dist/heartbeat-engine-BYT5ayQH.js +83 -0
- package/dist/hub-D0XwdjM-.js +515 -0
- package/dist/hub-LiD5Iztb.js +6 -0
- package/dist/hyperclawbot-zvczQgKx.js +505 -0
- package/dist/inference-BKVkBREb.js +6 -0
- package/dist/inference-DCXH4Q3x.js +922 -0
- package/dist/knowledge-graph-iBG76fvm.js +131 -0
- package/dist/loader-CC45xGpC.js +4 -0
- package/dist/loader-CnEdOyjT.js +400 -0
- package/dist/logger-ybOp7VOC.js +83 -0
- package/dist/manager-03ipO9R0.js +105 -0
- package/dist/manager-BpDfbDjg.js +117 -0
- package/dist/manager-Bxl0sqlh.js +4 -0
- package/dist/manager-CrVDn6eN.js +6 -0
- package/dist/manager-FCgF1plu.js +218 -0
- package/dist/manager-rgCsaWT1.js +40 -0
- package/dist/mcp-CfoSU4Uz.js +139 -0
- package/dist/mcp-loader-DkRBsLpk.js +94 -0
- package/dist/memory-BlHL7JCO.js +4 -0
- package/dist/memory-DsS_eFvJ.js +270 -0
- package/dist/memory-auto-BkvtSFUw.js +5 -0
- package/dist/memory-auto-Bnz_-1wP.js +306 -0
- package/dist/memory-integration-cSYkZyEo.js +91 -0
- package/dist/moltbook-BtLDZTfM.js +81 -0
- package/dist/node-Dw2Gi-cP.js +222 -0
- package/dist/nodes-registry-B8dmrlLv.js +52 -0
- package/dist/oauth-flow-DQPvMHRH.js +150 -0
- package/dist/oauth-provider-Uo4Nib_c.js +110 -0
- package/dist/observability-BV-Yx0V9.js +89 -0
- package/dist/onboard-0WoDxbv_.js +10 -0
- package/dist/onboard-BXNXCQp4.js +4070 -0
- package/dist/orchestrator-DmnEvMaL.js +189 -0
- package/dist/orchestrator-RI3bpqqc.js +6 -0
- package/dist/pairing-6iM27aD8.js +196 -0
- package/dist/pairing-dGoiGepK.js +4 -0
- package/dist/pc-access-CgCsYrpt.js +8 -0
- package/dist/pc-access-_iH2aorG.js +819 -0
- package/dist/pending-approval-CUXjysAo.js +22 -0
- package/dist/reminders-store-Drjed_-h.js +58 -0
- package/dist/renderer-BVQrd0_g.js +225 -0
- package/dist/rules-BE4GV6cV.js +103 -0
- package/dist/run-main.js +1607 -443
- package/dist/runner-DatMMYYE.js +1271 -0
- package/dist/sdk/index.js +2 -2
- package/dist/sdk/index.mjs +2 -2
- package/dist/security-BqNyT4ID.js +4 -0
- package/dist/security-tpgqPWWH.js +73 -0
- package/dist/server-D4wVHiX9.js +4 -0
- package/dist/server-Dh3JlBFB.js +1255 -0
- package/dist/session-store-BUiPz0Vv.js +5 -0
- package/dist/session-store-is4B6qmD.js +113 -0
- package/dist/sessions-tools-CbUTFe4i.js +5 -0
- package/dist/sessions-tools-CeqD7iil.js +95 -0
- package/dist/skill-loader-BaNLVmJy.js +7 -0
- package/dist/skill-loader-HgpF6Vqs.js +159 -0
- package/dist/skill-runtime-CJN24QPW.js +102 -0
- package/dist/skill-runtime-w1ig_lcw.js +5 -0
- package/dist/src-BxPHKO5x.js +63 -0
- package/dist/src-DIc-L2IG.js +20 -0
- package/dist/src-g_rNx5rh.js +458 -0
- package/dist/sub-agent-tools-CHQoHz9c.js +39 -0
- package/dist/theme-DcxwcUgZ.js +180 -0
- package/dist/theme-cx0fkgWC.js +8 -0
- package/dist/tool-policy-CNT-mF2Z.js +189 -0
- package/dist/tts-elevenlabs-BRosZv-f.js +61 -0
- package/dist/update-check-C2Dz85wJ.js +81 -0
- package/dist/vision-BMmiIKy7.js +121 -0
- package/dist/vision-tools-DVuYc17I.js +51 -0
- package/dist/vision-tools-U3YC4L-g.js +5 -0
- package/dist/voice-transcription-B555DbWR.js +138 -0
- package/dist/website-watch-tools-DFMrJU-R.js +139 -0
- package/dist/website-watch-tools-Du3W5sN7.js +5 -0
- package/package.json +1 -1
package/dist/run-main.js
CHANGED
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
const require_chunk = require('./chunk-jS-bbMI5.js');
|
|
2
2
|
require('./paths-AIyBxIzm.js');
|
|
3
3
|
require('./paths-DPovhojT.js');
|
|
4
|
-
require('./env-resolve-
|
|
5
|
-
const require_onboard = require('./onboard-
|
|
6
|
-
require('./server-
|
|
7
|
-
require('./
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
const require_manager
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
const
|
|
4
|
+
require('./env-resolve-CmGWhWXJ.js');
|
|
5
|
+
const require_onboard = require('./onboard-BXNXCQp4.js');
|
|
6
|
+
require('./server-Dh3JlBFB.js');
|
|
7
|
+
const require_daemon = require('./daemon-Bg4GtCmc.js');
|
|
8
|
+
require('./theme-DcxwcUgZ.js');
|
|
9
|
+
const require_hub = require('./hub-D0XwdjM-.js');
|
|
10
|
+
const require_manager = require('./manager-rgCsaWT1.js');
|
|
11
|
+
const require_manager$1 = require('./manager-03ipO9R0.js');
|
|
12
|
+
const require_memory = require('./memory-DsS_eFvJ.js');
|
|
13
|
+
const require_loader = require('./loader-CnEdOyjT.js');
|
|
14
|
+
const require_agents_routing = require('./agents-routing-ChHiZp36.js');
|
|
15
|
+
const require_pairing = require('./pairing-6iM27aD8.js');
|
|
16
|
+
const require_doctor = require('./doctor-BvCe8BBk.js');
|
|
17
|
+
const require_health = require('./health-Ds2YlpTB.js');
|
|
18
|
+
const require_security = require('./security-tpgqPWWH.js');
|
|
19
|
+
const require_developer_keys = require('./developer-keys-DrrcUqFa.js');
|
|
18
20
|
const commander = require_chunk.__toESM(require("commander"));
|
|
19
21
|
const chalk = require_chunk.__toESM(require("chalk"));
|
|
20
22
|
const inquirer = require_chunk.__toESM(require("inquirer"));
|
|
@@ -22,10 +24,13 @@ const ora = require_chunk.__toESM(require("ora"));
|
|
|
22
24
|
const fs_extra = require_chunk.__toESM(require("fs-extra"));
|
|
23
25
|
const path = require_chunk.__toESM(require("path"));
|
|
24
26
|
const os = require_chunk.__toESM(require("os"));
|
|
27
|
+
const crypto = require_chunk.__toESM(require("crypto"));
|
|
25
28
|
const child_process = require_chunk.__toESM(require("child_process"));
|
|
26
29
|
const util = require_chunk.__toESM(require("util"));
|
|
30
|
+
const http = require_chunk.__toESM(require("http"));
|
|
27
31
|
const fs = require_chunk.__toESM(require("fs"));
|
|
28
32
|
const readline = require_chunk.__toESM(require("readline"));
|
|
33
|
+
const net = require_chunk.__toESM(require("net"));
|
|
29
34
|
|
|
30
35
|
//#region src/cli/dashboard.ts
|
|
31
36
|
var Dashboard = class {
|
|
@@ -59,7 +64,7 @@ var Dashboard = class {
|
|
|
59
64
|
return c(`║ `) + content + " ".repeat(pad) + c(`║`);
|
|
60
65
|
};
|
|
61
66
|
console.log(c(`╔${line}╗`));
|
|
62
|
-
console.log(c(`║`) + chalk.default.bold.hex("#06b6d4")(`${"🦅 HYPERCLAW
|
|
67
|
+
console.log(c(`║`) + chalk.default.bold.hex("#06b6d4")(`${"🦅 HYPERCLAW v5.0.0 — GATEWAY DASHBOARD".padStart(45).padEnd(w)}`) + c(`║`));
|
|
63
68
|
console.log(c(`╠${line}╣`));
|
|
64
69
|
console.log(row(`${statusDot} Gateway ${statusText} ${chalk.default.gray("│")} ws://localhost:${port} ${chalk.default.gray("│")} Agent: ${c(agent)}`));
|
|
65
70
|
console.log(row(`${c("◆")} Model ${chalk.default.gray(model.slice(0, 30))} ${chalk.default.gray("│")} User: ${c(user)}`));
|
|
@@ -140,7 +145,7 @@ async function recordAudio(outFile, seconds) {
|
|
|
140
145
|
async function transcribeWhisper(filePath, lang) {
|
|
141
146
|
const apiKey = process.env.OPENAI_API_KEY || process.env.ANTHROPIC_API_KEY;
|
|
142
147
|
if (!apiKey) throw new Error("No OPENAI_API_KEY set");
|
|
143
|
-
const FormData = (await Promise.resolve().then(() => require_chunk.__toDynamicImportESM()(require("./form_data-
|
|
148
|
+
const FormData = (await Promise.resolve().then(() => require_chunk.__toDynamicImportESM()(require("./form_data-Cz040rio.js"))).catch(() => null))?.default;
|
|
144
149
|
if (!FormData) throw new Error("form-data not installed");
|
|
145
150
|
const form = new FormData();
|
|
146
151
|
form.append("file", fs.createReadStream(filePath), {
|
|
@@ -284,6 +289,185 @@ var VoiceEngine = class {
|
|
|
284
289
|
}
|
|
285
290
|
};
|
|
286
291
|
|
|
292
|
+
//#endregion
|
|
293
|
+
//#region src/infra/device-pairing.ts
|
|
294
|
+
const DEVICES_DIR = path.default.join(os.default.homedir(), ".hyperclaw", "devices");
|
|
295
|
+
const PENDING_FILE = path.default.join(DEVICES_DIR, "pending.json");
|
|
296
|
+
const PAIRED_FILE = path.default.join(DEVICES_DIR, "paired.json");
|
|
297
|
+
const PENDING_EXPIRY_MS = 10 * 60 * 1e3;
|
|
298
|
+
const TOKEN_BYTES = 16;
|
|
299
|
+
async function readPending() {
|
|
300
|
+
try {
|
|
301
|
+
const data = await fs_extra.default.readJson(PENDING_FILE);
|
|
302
|
+
return Array.isArray(data) ? data : [];
|
|
303
|
+
} catch {
|
|
304
|
+
return [];
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
async function writePending(entries) {
|
|
308
|
+
await fs_extra.default.ensureDir(DEVICES_DIR);
|
|
309
|
+
await fs_extra.default.writeJson(PENDING_FILE, entries, {
|
|
310
|
+
spaces: 2,
|
|
311
|
+
mode: 384
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
async function readPaired() {
|
|
315
|
+
try {
|
|
316
|
+
const data = await fs_extra.default.readJson(PAIRED_FILE);
|
|
317
|
+
return Array.isArray(data) ? data : [];
|
|
318
|
+
} catch {
|
|
319
|
+
return [];
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
async function writePaired(devices) {
|
|
323
|
+
await fs_extra.default.ensureDir(DEVICES_DIR);
|
|
324
|
+
await fs_extra.default.writeJson(PAIRED_FILE, devices, {
|
|
325
|
+
spaces: 2,
|
|
326
|
+
mode: 384
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
var DevicePairingStore = class {
|
|
330
|
+
/**
|
|
331
|
+
|
|
332
|
+
* Creates a pending pairing request and returns:
|
|
333
|
+
|
|
334
|
+
* - requestId: show to user for approve/reject
|
|
335
|
+
|
|
336
|
+
* - setupCode: base64-encoded JSON {url, token} — send to device
|
|
337
|
+
|
|
338
|
+
*/
|
|
339
|
+
async createRequest(gatewayUrl, opts) {
|
|
340
|
+
const now = Date.now();
|
|
341
|
+
const all = (await readPending()).filter((e) => new Date(e.expiresAt).getTime() > now);
|
|
342
|
+
const requestId = crypto.default.randomBytes(6).toString("hex");
|
|
343
|
+
const token = crypto.default.randomBytes(TOKEN_BYTES).toString("hex");
|
|
344
|
+
const expiresAt = new Date(now + PENDING_EXPIRY_MS).toISOString();
|
|
345
|
+
const entry = {
|
|
346
|
+
requestId,
|
|
347
|
+
token,
|
|
348
|
+
expiresAt,
|
|
349
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
350
|
+
...opts?.deviceName ? { deviceName: opts.deviceName } : {},
|
|
351
|
+
...opts?.platform ? { platform: opts.platform } : {}
|
|
352
|
+
};
|
|
353
|
+
all.push(entry);
|
|
354
|
+
await writePending(all);
|
|
355
|
+
const payload = {
|
|
356
|
+
url: gatewayUrl,
|
|
357
|
+
token
|
|
358
|
+
};
|
|
359
|
+
const setupCode = Buffer.from(JSON.stringify(payload)).toString("base64");
|
|
360
|
+
return {
|
|
361
|
+
requestId,
|
|
362
|
+
setupCode,
|
|
363
|
+
expiresAt
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
async listPending() {
|
|
367
|
+
const now = Date.now();
|
|
368
|
+
const all = await readPending();
|
|
369
|
+
return all.filter((e) => new Date(e.expiresAt).getTime() > now);
|
|
370
|
+
}
|
|
371
|
+
async listPaired() {
|
|
372
|
+
return readPaired();
|
|
373
|
+
}
|
|
374
|
+
async approve(requestId) {
|
|
375
|
+
const now = Date.now();
|
|
376
|
+
const pending = await readPending();
|
|
377
|
+
const idx = pending.findIndex((e) => e.requestId === requestId && new Date(e.expiresAt).getTime() > now);
|
|
378
|
+
if (idx === -1) return null;
|
|
379
|
+
const entry = pending[idx];
|
|
380
|
+
pending.splice(idx, 1);
|
|
381
|
+
await writePending(pending);
|
|
382
|
+
const deviceId = `device-${crypto.default.randomBytes(4).toString("hex")}`;
|
|
383
|
+
const longToken = crypto.default.randomBytes(32).toString("hex");
|
|
384
|
+
const device = {
|
|
385
|
+
deviceId,
|
|
386
|
+
requestId: entry.requestId,
|
|
387
|
+
token: longToken,
|
|
388
|
+
pairedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
389
|
+
...entry.deviceName ? { deviceName: entry.deviceName } : {},
|
|
390
|
+
...entry.platform ? { platform: entry.platform } : {}
|
|
391
|
+
};
|
|
392
|
+
const paired = await readPaired();
|
|
393
|
+
paired.push(device);
|
|
394
|
+
await writePaired(paired);
|
|
395
|
+
return device;
|
|
396
|
+
}
|
|
397
|
+
async reject(requestId) {
|
|
398
|
+
const pending = await readPending();
|
|
399
|
+
const idx = pending.findIndex((e) => e.requestId === requestId);
|
|
400
|
+
if (idx === -1) return false;
|
|
401
|
+
pending.splice(idx, 1);
|
|
402
|
+
await writePending(pending);
|
|
403
|
+
return true;
|
|
404
|
+
}
|
|
405
|
+
async unpair(deviceId) {
|
|
406
|
+
const paired = await readPaired();
|
|
407
|
+
const idx = paired.findIndex((d) => d.deviceId === deviceId);
|
|
408
|
+
if (idx === -1) return false;
|
|
409
|
+
paired.splice(idx, 1);
|
|
410
|
+
await writePaired(paired);
|
|
411
|
+
return true;
|
|
412
|
+
}
|
|
413
|
+
async verifyToken(token) {
|
|
414
|
+
const now = Date.now();
|
|
415
|
+
const pending = await readPending();
|
|
416
|
+
const pendingMatch = pending.find((e) => e.token === token && new Date(e.expiresAt).getTime() > now);
|
|
417
|
+
if (pendingMatch) return this.approve(pendingMatch.requestId);
|
|
418
|
+
const paired = await readPaired();
|
|
419
|
+
return paired.find((d) => d.token === token) ?? null;
|
|
420
|
+
}
|
|
421
|
+
async touchDevice(deviceId) {
|
|
422
|
+
const paired = await readPaired();
|
|
423
|
+
const device = paired.find((d) => d.deviceId === deviceId);
|
|
424
|
+
if (device) {
|
|
425
|
+
device.lastSeenAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
426
|
+
await writePaired(paired);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
static parseSetupCode(setupCode) {
|
|
430
|
+
try {
|
|
431
|
+
const json = Buffer.from(setupCode, "base64").toString("utf8");
|
|
432
|
+
const parsed = JSON.parse(json);
|
|
433
|
+
if (typeof parsed.url === "string" && typeof parsed.token === "string") return parsed;
|
|
434
|
+
return null;
|
|
435
|
+
} catch {
|
|
436
|
+
return null;
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
async showCLI() {
|
|
440
|
+
const now = Date.now();
|
|
441
|
+
const pending = (await readPending()).filter((e) => new Date(e.expiresAt).getTime() > now);
|
|
442
|
+
const paired = await readPaired();
|
|
443
|
+
console.log(chalk.default.bold.cyan("\n 📱 DEVICE PAIRING\n"));
|
|
444
|
+
if (pending.length > 0) {
|
|
445
|
+
console.log(chalk.default.yellow(" Pending requests:\n"));
|
|
446
|
+
for (const e of pending) {
|
|
447
|
+
const expiresIn = Math.round((new Date(e.expiresAt).getTime() - now) / 6e4);
|
|
448
|
+
const name = e.deviceName ? chalk.default.white(` "${e.deviceName}"`) : "";
|
|
449
|
+
const plat = e.platform ? chalk.default.gray(` (${e.platform})`) : "";
|
|
450
|
+
console.log(` ${chalk.default.yellow("○")} ${chalk.default.bold(e.requestId)}${name}${plat} ${chalk.default.gray(`expires in ${expiresIn}m`)}`);
|
|
451
|
+
}
|
|
452
|
+
console.log();
|
|
453
|
+
}
|
|
454
|
+
if (paired.length > 0) {
|
|
455
|
+
console.log(chalk.default.green(" Paired devices:\n"));
|
|
456
|
+
for (const d of paired) {
|
|
457
|
+
const name = d.deviceName ? chalk.default.white(` "${d.deviceName}"`) : "";
|
|
458
|
+
const plat = d.platform ? chalk.default.gray(` (${d.platform})`) : "";
|
|
459
|
+
const seen = d.lastSeenAt ? chalk.default.gray(` last seen: ${new Date(d.lastSeenAt).toLocaleDateString()}`) : "";
|
|
460
|
+
console.log(` ${chalk.default.green("●")} ${chalk.default.bold(d.deviceId)}${name}${plat} ${chalk.default.gray(`paired: ${new Date(d.pairedAt).toLocaleDateString()}`)}${seen}`);
|
|
461
|
+
}
|
|
462
|
+
console.log();
|
|
463
|
+
}
|
|
464
|
+
if (pending.length === 0 && paired.length === 0) {
|
|
465
|
+
console.log(chalk.default.gray(" No pending or paired devices."));
|
|
466
|
+
console.log(chalk.default.gray(" In Telegram, message your bot: /pair\n"));
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
};
|
|
470
|
+
|
|
287
471
|
//#endregion
|
|
288
472
|
//#region src/commands/message-send.ts
|
|
289
473
|
async function sendMessage(opts) {
|
|
@@ -345,17 +529,28 @@ const CHANNELS = [
|
|
|
345
529
|
platforms: ["all"],
|
|
346
530
|
tokenLabel: "Telegram Bot Token",
|
|
347
531
|
tokenHint: "Get from @BotFather → /newbot",
|
|
532
|
+
extraFields: [{
|
|
533
|
+
name: "dmPolicy",
|
|
534
|
+
label: "DM policy",
|
|
535
|
+
hint: "pairing (default) | allowlist | open | disabled",
|
|
536
|
+
required: false
|
|
537
|
+
}, {
|
|
538
|
+
name: "groupActivation",
|
|
539
|
+
label: "Group activation",
|
|
540
|
+
hint: "mention (default) | always",
|
|
541
|
+
required: false
|
|
542
|
+
}],
|
|
348
543
|
setupSteps: [
|
|
349
|
-
"1. Open Telegram
|
|
350
|
-
"2.
|
|
351
|
-
"3.
|
|
352
|
-
"4.
|
|
353
|
-
"5. Copy the token and paste it below.",
|
|
544
|
+
"1. Open Telegram → @BotFather → /newbot. Save the token.",
|
|
545
|
+
"2. Config: channels.telegram.botToken, dmPolicy (default: pairing), groups.",
|
|
546
|
+
"3. Start gateway, approve first DM: hyperclaw pairing approve telegram <CODE>",
|
|
547
|
+
"4. Add bot to groups; set groups[\"*\"].requireMention for mention gating.",
|
|
354
548
|
"",
|
|
355
|
-
" 🔗
|
|
549
|
+
" 🔗 docs/telegram.md — full setup"
|
|
356
550
|
],
|
|
357
551
|
status: "recommended",
|
|
358
|
-
npmPackage: "node-telegram-bot-api"
|
|
552
|
+
npmPackage: "node-telegram-bot-api",
|
|
553
|
+
notes: "DMs + groups. Pairing, allowlist, voice notes. Long polling default."
|
|
359
554
|
},
|
|
360
555
|
{
|
|
361
556
|
id: "discord",
|
|
@@ -367,23 +562,37 @@ const CHANNELS = [
|
|
|
367
562
|
tokenLabel: "Discord Bot Token",
|
|
368
563
|
tokenHint: "discord.com/developers/applications",
|
|
369
564
|
setupSteps: [
|
|
370
|
-
"1.
|
|
371
|
-
"2.
|
|
372
|
-
"3.
|
|
373
|
-
"4.
|
|
374
|
-
"5.
|
|
375
|
-
"6.
|
|
565
|
+
"1. Discord Developer Portal → New Application → Bot → Reset Token.",
|
|
566
|
+
"2. Enable Message Content Intent (and Server Members if needed).",
|
|
567
|
+
"3. OAuth2 URL Generator: scope bot + applications.commands, permissions: View Channels, Send Messages, Read Message History.",
|
|
568
|
+
"4. Add bot to server, enable Developer Mode, copy Server ID and User ID.",
|
|
569
|
+
"5. Enable DMs from server members (right‑click server → Privacy Settings).",
|
|
570
|
+
"6. hyperclaw gateway → DM the bot → hyperclaw pairing approve discord <CODE>",
|
|
376
571
|
"",
|
|
377
|
-
" 🔗 discord.
|
|
572
|
+
" 🔗 docs/discord-setup.md — full setup guide"
|
|
573
|
+
],
|
|
574
|
+
extraFields: [
|
|
575
|
+
{
|
|
576
|
+
name: "listenGuildIds",
|
|
577
|
+
label: "Guild IDs to listen in",
|
|
578
|
+
hint: "[] = all. Add Server IDs to restrict.",
|
|
579
|
+
required: false
|
|
580
|
+
},
|
|
581
|
+
{
|
|
582
|
+
name: "requireMentionInGuild",
|
|
583
|
+
label: "Require @mention in guild",
|
|
584
|
+
hint: "true (default) | false",
|
|
585
|
+
required: false
|
|
586
|
+
},
|
|
587
|
+
{
|
|
588
|
+
name: "dmPolicy",
|
|
589
|
+
label: "DM policy",
|
|
590
|
+
hint: "\"pairing\" (default) | \"allowlist\" | \"open\" | \"none\"",
|
|
591
|
+
required: false
|
|
592
|
+
}
|
|
378
593
|
],
|
|
379
|
-
extraFields: [{
|
|
380
|
-
name: "clientId",
|
|
381
|
-
label: "Client ID (Application ID)",
|
|
382
|
-
hint: "From OAuth2 → General",
|
|
383
|
-
required: true
|
|
384
|
-
}],
|
|
385
594
|
status: "recommended",
|
|
386
|
-
npmPackage: "
|
|
595
|
+
npmPackage: "ws"
|
|
387
596
|
},
|
|
388
597
|
{
|
|
389
598
|
id: "whatsapp",
|
|
@@ -392,18 +601,38 @@ const CHANNELS = [
|
|
|
392
601
|
requiresGateway: true,
|
|
393
602
|
supportsDM: true,
|
|
394
603
|
platforms: ["all"],
|
|
395
|
-
tokenLabel: "
|
|
604
|
+
tokenLabel: "Access Token",
|
|
396
605
|
tokenHint: "business.whatsapp.com",
|
|
606
|
+
extraFields: [
|
|
607
|
+
{
|
|
608
|
+
name: "phoneNumberId",
|
|
609
|
+
label: "Phone Number ID",
|
|
610
|
+
hint: "From Meta API Setup",
|
|
611
|
+
required: true
|
|
612
|
+
},
|
|
613
|
+
{
|
|
614
|
+
name: "verifyToken",
|
|
615
|
+
label: "Webhook verify token",
|
|
616
|
+
hint: "Any string for webhook verification",
|
|
617
|
+
required: false
|
|
618
|
+
},
|
|
619
|
+
{
|
|
620
|
+
name: "dmPolicy",
|
|
621
|
+
label: "DM policy",
|
|
622
|
+
hint: "pairing (default) | allowlist | open | disabled",
|
|
623
|
+
required: false
|
|
624
|
+
}
|
|
625
|
+
],
|
|
397
626
|
setupSteps: [
|
|
398
|
-
"1.
|
|
399
|
-
"2.
|
|
400
|
-
"3.
|
|
401
|
-
"4.
|
|
402
|
-
"5. You also need a Phone Number ID and WhatsApp Business Account ID.",
|
|
627
|
+
"1. Meta for Developers → Create App → Business → Add WhatsApp.",
|
|
628
|
+
"2. API Setup: copy Phone Number ID and Access Token.",
|
|
629
|
+
"3. Webhook: https://<host>/webhook/whatsapp, subscribe to messages.",
|
|
630
|
+
"4. Start gateway. Approve DMs: hyperclaw pairing approve whatsapp <CODE>",
|
|
403
631
|
"",
|
|
404
|
-
" 🔗
|
|
632
|
+
" 🔗 docs/whatsapp.md — full setup"
|
|
405
633
|
],
|
|
406
634
|
status: "available",
|
|
635
|
+
notes: "Meta Business API. Webhook required.",
|
|
407
636
|
npmPackage: void 0
|
|
408
637
|
},
|
|
409
638
|
{
|
|
@@ -413,42 +642,87 @@ const CHANNELS = [
|
|
|
413
642
|
requiresGateway: true,
|
|
414
643
|
supportsDM: true,
|
|
415
644
|
platforms: ["all"],
|
|
645
|
+
extraFields: [{
|
|
646
|
+
name: "dmPolicy",
|
|
647
|
+
label: "DM policy",
|
|
648
|
+
hint: "pairing (default) | allowlist | open | disabled",
|
|
649
|
+
required: false
|
|
650
|
+
}],
|
|
416
651
|
setupSteps: [
|
|
417
|
-
"1. No Meta
|
|
418
|
-
"2.
|
|
419
|
-
"3.
|
|
420
|
-
"4.
|
|
421
|
-
"5. After connecting, the session is saved — no QR needed again.",
|
|
652
|
+
"1. No Meta API — uses WhatsApp Web. Install: npm install @whiskeysockets/baileys",
|
|
653
|
+
"2. hyperclaw channels add whatsapp-baileys, then hyperclaw gateway",
|
|
654
|
+
"3. Scan QR (WhatsApp → Linked Devices → Link a device)",
|
|
655
|
+
"4. Approve first DM: hyperclaw pairing approve whatsapp-baileys <CODE>",
|
|
422
656
|
"",
|
|
423
|
-
"
|
|
657
|
+
" 🔗 docs/whatsapp.md — full setup"
|
|
424
658
|
],
|
|
425
659
|
status: "available",
|
|
426
|
-
notes: "WhatsApp Web via Baileys
|
|
660
|
+
notes: "WhatsApp Web via Baileys. No Meta Business. Pairing, voice notes.",
|
|
427
661
|
npmPackage: "@whiskeysockets/baileys"
|
|
428
662
|
},
|
|
429
663
|
{
|
|
430
664
|
id: "slack",
|
|
431
665
|
name: "Slack",
|
|
432
666
|
emoji: "💼",
|
|
433
|
-
requiresGateway:
|
|
667
|
+
requiresGateway: true,
|
|
434
668
|
supportsDM: true,
|
|
435
669
|
platforms: ["all"],
|
|
436
670
|
tokenLabel: "Slack Bot Token (xoxb-...)",
|
|
437
|
-
extraFields: [
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
671
|
+
extraFields: [
|
|
672
|
+
{
|
|
673
|
+
name: "appToken",
|
|
674
|
+
label: "App Token (xapp-...)",
|
|
675
|
+
hint: "Required for Socket Mode (default) — connections:write scope",
|
|
676
|
+
required: false
|
|
677
|
+
},
|
|
678
|
+
{
|
|
679
|
+
name: "signingSecret",
|
|
680
|
+
label: "Signing Secret",
|
|
681
|
+
hint: "Required for HTTP Events API mode only",
|
|
682
|
+
required: false
|
|
683
|
+
},
|
|
684
|
+
{
|
|
685
|
+
name: "mode",
|
|
686
|
+
label: "Connection mode",
|
|
687
|
+
hint: "socket (default) | http",
|
|
688
|
+
required: false
|
|
689
|
+
},
|
|
690
|
+
{
|
|
691
|
+
name: "userToken",
|
|
692
|
+
label: "User Token (xoxp-...)",
|
|
693
|
+
hint: "Optional — for read operations",
|
|
694
|
+
required: false
|
|
695
|
+
},
|
|
696
|
+
{
|
|
697
|
+
name: "ackReaction",
|
|
698
|
+
label: "Ack reaction emoji",
|
|
699
|
+
hint: "Shortcode without colons, e.g. eyes",
|
|
700
|
+
required: false
|
|
701
|
+
},
|
|
702
|
+
{
|
|
703
|
+
name: "typingReaction",
|
|
704
|
+
label: "Typing reaction emoji",
|
|
705
|
+
hint: "Shortcode, e.g. hourglass_flowing_sand",
|
|
706
|
+
required: false
|
|
707
|
+
}
|
|
708
|
+
],
|
|
442
709
|
setupSteps: [
|
|
443
710
|
"1. Go to api.slack.com/apps → Create New App → From scratch.",
|
|
444
|
-
"2.
|
|
445
|
-
"
|
|
446
|
-
"
|
|
447
|
-
"
|
|
711
|
+
"2. Socket Mode (default — no public URL needed):",
|
|
712
|
+
" a. Settings → Socket Mode → Enable Socket Mode.",
|
|
713
|
+
" b. Settings → Basic Information → App-Level Tokens → Generate Token (connections:write) → copy xapp-...",
|
|
714
|
+
" c. OAuth & Permissions: add bot scopes (chat:write, im:read, im:history, channels:history, etc.).",
|
|
715
|
+
" d. Install App → copy Bot Token (xoxb-...).",
|
|
716
|
+
"3. HTTP mode (alternative):",
|
|
717
|
+
" a. Event Subscriptions → Request URL: https://<host>/webhook/slack.",
|
|
718
|
+
" b. Basic Information → Signing Secret — copy it.",
|
|
719
|
+
"4. Subscribe to bot events: app_mention, message.im, message.channels, message.groups, message.mpim, reaction_added.",
|
|
720
|
+
"5. App Home → Messages Tab → Enable.",
|
|
448
721
|
"",
|
|
449
722
|
" 🔗 api.slack.com/apps"
|
|
450
723
|
],
|
|
451
|
-
status: "
|
|
724
|
+
status: "recommended",
|
|
725
|
+
notes: "Socket Mode (default) requires appToken. HTTP mode requires signingSecret. Supports DMs, channels, threads, reactions, streaming.",
|
|
452
726
|
npmPackage: "@slack/bolt"
|
|
453
727
|
},
|
|
454
728
|
{
|
|
@@ -458,38 +732,160 @@ const CHANNELS = [
|
|
|
458
732
|
requiresGateway: true,
|
|
459
733
|
supportsDM: true,
|
|
460
734
|
platforms: ["linux", "darwin"],
|
|
461
|
-
tokenLabel: "
|
|
462
|
-
tokenHint: "
|
|
735
|
+
tokenLabel: "Bot phone number (E.164)",
|
|
736
|
+
tokenHint: "e.g. +15551234567 — use a dedicated bot number",
|
|
463
737
|
setupSteps: [
|
|
464
738
|
"1. Install signal-cli: https://github.com/AsamK/signal-cli",
|
|
465
|
-
"2. Register number: signal-cli -a +1XXXXXXXXX register",
|
|
466
|
-
"3. Verify electronically (if available) or via SMS code.",
|
|
467
|
-
"4. Enter your phone number here (e.g. +1XXXXXXXXX).",
|
|
468
739
|
"",
|
|
469
|
-
"
|
|
740
|
+
" Path A — Link existing Signal account (QR):",
|
|
741
|
+
" signal-cli link -n \"HyperClaw\" then scan in Signal.",
|
|
742
|
+
"",
|
|
743
|
+
" Path B — Register dedicated bot number (SMS):",
|
|
744
|
+
" signal-cli -a +<BOT_NUMBER> register",
|
|
745
|
+
" signal-cli -a +<BOT_NUMBER> register --captcha '<URL>' (if captcha required)",
|
|
746
|
+
" signal-cli -a +<BOT_NUMBER> verify <CODE>",
|
|
747
|
+
"",
|
|
748
|
+
"2. Set account: \"+<BOT_NUMBER>\" in config.",
|
|
749
|
+
"3. autoStart=true (default) spawns daemon automatically.",
|
|
750
|
+
" Or run daemon yourself and set httpUrl: \"http://127.0.0.1:8080\".",
|
|
751
|
+
"",
|
|
752
|
+
" Access control:",
|
|
753
|
+
" dmPolicy=pairing (default) — senders get pairing code (expires 1h)",
|
|
754
|
+
" groupPolicy=allowlist (default) — only groupAllowFrom senders trigger bot",
|
|
755
|
+
"",
|
|
756
|
+
" Chunking: textChunkLimit=4000, chunkMode=length|newline",
|
|
757
|
+
" Reactions: actions.reactions=true, reactionLevel=off|ack|minimal|extensive",
|
|
758
|
+
"",
|
|
759
|
+
" 🔗 github.com/AsamK/signal-cli",
|
|
760
|
+
" 🔗 github.com/AsamK/signal-cli/wiki/Registration-with-captcha"
|
|
761
|
+
],
|
|
762
|
+
extraFields: [
|
|
763
|
+
{
|
|
764
|
+
name: "account",
|
|
765
|
+
label: "Bot number (E.164)",
|
|
766
|
+
hint: "+15551234567",
|
|
767
|
+
required: true
|
|
768
|
+
},
|
|
769
|
+
{
|
|
770
|
+
name: "cliPath",
|
|
771
|
+
label: "signal-cli path",
|
|
772
|
+
hint: "signal-cli (if on PATH)",
|
|
773
|
+
required: false
|
|
774
|
+
},
|
|
775
|
+
{
|
|
776
|
+
name: "httpUrl",
|
|
777
|
+
label: "Daemon URL (external)",
|
|
778
|
+
hint: "http://127.0.0.1:8080 — skips autoStart",
|
|
779
|
+
required: false
|
|
780
|
+
},
|
|
781
|
+
{
|
|
782
|
+
name: "httpPort",
|
|
783
|
+
label: "Daemon port",
|
|
784
|
+
hint: "8080 (default)",
|
|
785
|
+
required: false
|
|
786
|
+
},
|
|
787
|
+
{
|
|
788
|
+
name: "autoStart",
|
|
789
|
+
label: "Auto-spawn daemon",
|
|
790
|
+
hint: "true (default) / false",
|
|
791
|
+
required: false
|
|
792
|
+
},
|
|
793
|
+
{
|
|
794
|
+
name: "startupTimeoutMs",
|
|
795
|
+
label: "Startup timeout (ms)",
|
|
796
|
+
hint: "15000 default, max 120000",
|
|
797
|
+
required: false
|
|
798
|
+
},
|
|
799
|
+
{
|
|
800
|
+
name: "dmPolicy",
|
|
801
|
+
label: "DM policy",
|
|
802
|
+
hint: "\"pairing\" (default) | \"allowlist\" | \"open\" | \"disabled\"",
|
|
803
|
+
required: false
|
|
804
|
+
},
|
|
805
|
+
{
|
|
806
|
+
name: "groupPolicy",
|
|
807
|
+
label: "Group policy",
|
|
808
|
+
hint: "\"allowlist\" (default) | \"open\" | \"disabled\"",
|
|
809
|
+
required: false
|
|
810
|
+
},
|
|
811
|
+
{
|
|
812
|
+
name: "textChunkLimit",
|
|
813
|
+
label: "Text chunk limit (chars)",
|
|
814
|
+
hint: "4000 default",
|
|
815
|
+
required: false
|
|
816
|
+
},
|
|
817
|
+
{
|
|
818
|
+
name: "chunkMode",
|
|
819
|
+
label: "Chunk mode",
|
|
820
|
+
hint: "\"length\" (default) | \"newline\"",
|
|
821
|
+
required: false
|
|
822
|
+
}
|
|
470
823
|
],
|
|
471
824
|
status: "available",
|
|
472
|
-
notes: "
|
|
825
|
+
notes: "signal-cli HTTP daemon + SSE events. DMs, groups, typing, reactions, chunking, multi-account."
|
|
473
826
|
},
|
|
474
827
|
{
|
|
475
828
|
id: "imessage",
|
|
476
|
-
name: "iMessage",
|
|
829
|
+
name: "iMessage (BlueBubbles)",
|
|
477
830
|
emoji: "💬",
|
|
478
831
|
requiresGateway: true,
|
|
479
832
|
supportsDM: true,
|
|
480
833
|
platforms: ["darwin"],
|
|
834
|
+
tokenLabel: "BlueBubbles server URL",
|
|
835
|
+
extraFields: [{
|
|
836
|
+
name: "password",
|
|
837
|
+
label: "BlueBubbles password",
|
|
838
|
+
hint: "Set in BlueBubbles server settings",
|
|
839
|
+
required: true
|
|
840
|
+
}, {
|
|
841
|
+
name: "dmPolicy",
|
|
842
|
+
label: "DM policy",
|
|
843
|
+
hint: "pairing (default) | allowlist | open | disabled",
|
|
844
|
+
required: false
|
|
845
|
+
}],
|
|
481
846
|
setupSteps: [
|
|
482
|
-
"1. macOS only.
|
|
483
|
-
"2. BlueBubbles:
|
|
484
|
-
"3.
|
|
485
|
-
"4.
|
|
847
|
+
"1. macOS only. Install BlueBubbles server: bluebubbles.app",
|
|
848
|
+
"2. BlueBubbles → Settings: enable web API, set password, note Server URL.",
|
|
849
|
+
"3. Add channel (imessage or bluebubbles), enter serverUrl + password.",
|
|
850
|
+
"4. hyperclaw gateway → hyperclaw pairing approve bluebubbles <CODE>",
|
|
486
851
|
"",
|
|
487
|
-
" 🔗 bluebubbles.
|
|
852
|
+
" 🔗 docs/bluebubbles.md — bluebubbles.app"
|
|
488
853
|
],
|
|
489
|
-
status: os.default.platform() === "darwin" ? "
|
|
490
|
-
notes: "
|
|
854
|
+
status: os.default.platform() === "darwin" ? "recommended" : "unavailable",
|
|
855
|
+
notes: "BlueBubbles server on Mac. DMs, pairing. Groups planned.",
|
|
491
856
|
npmPackage: "bluebubbles-api"
|
|
492
857
|
},
|
|
858
|
+
{
|
|
859
|
+
id: "imessage-native",
|
|
860
|
+
name: "iMessage (imsg CLI — legacy)",
|
|
861
|
+
emoji: "💬",
|
|
862
|
+
requiresGateway: true,
|
|
863
|
+
supportsDM: true,
|
|
864
|
+
platforms: ["darwin"],
|
|
865
|
+
extraFields: [{
|
|
866
|
+
name: "cliPath",
|
|
867
|
+
label: "imsg binary path",
|
|
868
|
+
hint: "Default: imsg (must be in PATH)",
|
|
869
|
+
required: false
|
|
870
|
+
}, {
|
|
871
|
+
name: "dbPath",
|
|
872
|
+
label: "Messages DB path",
|
|
873
|
+
hint: "Default: ~/Library/Messages/chat.db",
|
|
874
|
+
required: false
|
|
875
|
+
}],
|
|
876
|
+
setupSteps: [
|
|
877
|
+
"1. macOS only. Install imsg: brew install steipete/tap/imsg",
|
|
878
|
+
"2. Verify: imsg rpc --help",
|
|
879
|
+
"3. Grant Full Disk Access + Automation to Terminal/Node (one-time: imsg chats --limit 1).",
|
|
880
|
+
"4. No token needed — imsg runs locally via JSON-RPC on stdio.",
|
|
881
|
+
"5. (Optional) Set cliPath if imsg is not in PATH.",
|
|
882
|
+
"",
|
|
883
|
+
" ⚠️ Legacy integration — for new setups use iMessage (BlueBubbles)",
|
|
884
|
+
" 🔗 github.com/steipete/imsg"
|
|
885
|
+
],
|
|
886
|
+
status: os.default.platform() === "darwin" ? "available" : "unavailable",
|
|
887
|
+
notes: "Legacy — gateway spawns imsg rpc over JSON-RPC stdio. For new setups prefer BlueBubbles."
|
|
888
|
+
},
|
|
493
889
|
{
|
|
494
890
|
id: "matrix",
|
|
495
891
|
name: "Matrix",
|
|
@@ -497,26 +893,84 @@ const CHANNELS = [
|
|
|
497
893
|
requiresGateway: true,
|
|
498
894
|
supportsDM: true,
|
|
499
895
|
platforms: ["all"],
|
|
500
|
-
tokenLabel:
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
896
|
+
tokenLabel: "Access Token (syt_...)",
|
|
897
|
+
tokenHint: "Or set userId + password instead",
|
|
898
|
+
extraFields: [
|
|
899
|
+
{
|
|
900
|
+
name: "homeserver",
|
|
901
|
+
label: "Homeserver URL",
|
|
902
|
+
hint: "e.g. https://matrix.example.org",
|
|
903
|
+
required: true
|
|
904
|
+
},
|
|
905
|
+
{
|
|
906
|
+
name: "accessToken",
|
|
907
|
+
label: "Access Token (syt_...)",
|
|
908
|
+
hint: "Preferred; userId auto-fetched via /whoami",
|
|
909
|
+
required: false
|
|
910
|
+
},
|
|
911
|
+
{
|
|
912
|
+
name: "userId",
|
|
913
|
+
label: "Matrix User ID",
|
|
914
|
+
hint: "@bot:example.org — required only for password login",
|
|
915
|
+
required: false
|
|
916
|
+
},
|
|
917
|
+
{
|
|
918
|
+
name: "password",
|
|
919
|
+
label: "Password (alternative to token)",
|
|
920
|
+
hint: "Token cached to credentials file on first login",
|
|
921
|
+
required: false
|
|
922
|
+
},
|
|
923
|
+
{
|
|
924
|
+
name: "deviceName",
|
|
925
|
+
label: "Device display name",
|
|
926
|
+
hint: "Shown in Matrix clients",
|
|
927
|
+
required: false
|
|
928
|
+
},
|
|
929
|
+
{
|
|
930
|
+
name: "encryption",
|
|
931
|
+
label: "Enable E2EE",
|
|
932
|
+
hint: "true | false — requires crypto native module",
|
|
933
|
+
required: false
|
|
934
|
+
},
|
|
935
|
+
{
|
|
936
|
+
name: "threadReplies",
|
|
937
|
+
label: "Thread replies",
|
|
938
|
+
hint: "off | inbound (default) | always",
|
|
939
|
+
required: false
|
|
940
|
+
},
|
|
941
|
+
{
|
|
942
|
+
name: "textChunkLimit",
|
|
943
|
+
label: "Text chunk limit (chars)",
|
|
944
|
+
hint: "Default: 16000",
|
|
945
|
+
required: false
|
|
946
|
+
},
|
|
947
|
+
{
|
|
948
|
+
name: "mediaMaxMb",
|
|
949
|
+
label: "Media size limit (MB)",
|
|
950
|
+
hint: "Default: 10",
|
|
951
|
+
required: false
|
|
952
|
+
},
|
|
953
|
+
{
|
|
954
|
+
name: "autoJoin",
|
|
955
|
+
label: "Auto-join invites",
|
|
956
|
+
hint: "always (default) | allowlist | off",
|
|
957
|
+
required: false
|
|
958
|
+
}
|
|
959
|
+
],
|
|
511
960
|
setupSteps: [
|
|
512
|
-
"1. Create a bot account on matrix.org
|
|
513
|
-
"2.
|
|
514
|
-
"
|
|
515
|
-
"
|
|
961
|
+
"1. Create a Matrix bot account on any homeserver (matrix.org has free accounts).",
|
|
962
|
+
"2. Get an access token via the login API:",
|
|
963
|
+
" curl -X POST https://<homeserver>/_matrix/client/v3/login \\",
|
|
964
|
+
" -H \"Content-Type: application/json\" \\",
|
|
965
|
+
" -d '{\"type\":\"m.login.password\",\"identifier\":{\"type\":\"m.id.user\",\"user\":\"<username>\"},\"password\":\"<password>\"}'",
|
|
966
|
+
" Or set userId + password — HyperClaw will call the login API and cache the token.",
|
|
967
|
+
"3. Invite the bot account to a room or DM it from any Matrix client (Element, Beeper, etc.).",
|
|
968
|
+
"4. For Beeper, enable E2EE: set encryption: true and verify the device in Element.",
|
|
516
969
|
"",
|
|
517
|
-
" 🔗 matrix.org — element.io"
|
|
970
|
+
" 🔗 matrix.org/ecosystem/hosting/ — element.io"
|
|
518
971
|
],
|
|
519
972
|
status: "available",
|
|
973
|
+
notes: "Supports DMs, rooms, threads, media, reactions, polls, location, E2EE, multi-account.",
|
|
520
974
|
npmPackage: "matrix-js-sdk"
|
|
521
975
|
},
|
|
522
976
|
{
|
|
@@ -530,25 +984,81 @@ const CHANNELS = [
|
|
|
530
984
|
extraFields: [
|
|
531
985
|
{
|
|
532
986
|
name: "server",
|
|
533
|
-
label: "Server",
|
|
987
|
+
label: "Server (IRC_HOST)",
|
|
534
988
|
hint: "e.g. irc.libera.chat",
|
|
535
989
|
required: true
|
|
536
990
|
},
|
|
991
|
+
{
|
|
992
|
+
name: "port",
|
|
993
|
+
label: "Port (IRC_PORT)",
|
|
994
|
+
hint: "Default: 6697 (TLS) or 6667",
|
|
995
|
+
required: false
|
|
996
|
+
},
|
|
997
|
+
{
|
|
998
|
+
name: "tls",
|
|
999
|
+
label: "TLS (IRC_TLS)",
|
|
1000
|
+
hint: "true / false — default: false",
|
|
1001
|
+
required: false
|
|
1002
|
+
},
|
|
537
1003
|
{
|
|
538
1004
|
name: "nick",
|
|
539
|
-
label: "Nickname",
|
|
1005
|
+
label: "Nickname (IRC_NICK)",
|
|
540
1006
|
required: true
|
|
541
1007
|
},
|
|
1008
|
+
{
|
|
1009
|
+
name: "username",
|
|
1010
|
+
label: "Username / ident (IRC_USERNAME)",
|
|
1011
|
+
required: false
|
|
1012
|
+
},
|
|
1013
|
+
{
|
|
1014
|
+
name: "realname",
|
|
1015
|
+
label: "Real name (IRC_REALNAME)",
|
|
1016
|
+
required: false
|
|
1017
|
+
},
|
|
1018
|
+
{
|
|
1019
|
+
name: "password",
|
|
1020
|
+
label: "Server password (IRC_PASSWORD)",
|
|
1021
|
+
hint: "Not NickServ — leave blank if none",
|
|
1022
|
+
required: false
|
|
1023
|
+
},
|
|
542
1024
|
{
|
|
543
1025
|
name: "channels",
|
|
544
|
-
label: "
|
|
1026
|
+
label: "Channels to join (IRC_CHANNELS)",
|
|
1027
|
+
hint: "#room1,#room2",
|
|
1028
|
+
required: false
|
|
1029
|
+
},
|
|
1030
|
+
{
|
|
1031
|
+
name: "nickservPassword",
|
|
1032
|
+
label: "NickServ password (IRC_NICKSERV_PASSWORD)",
|
|
1033
|
+
hint: "Identify after connect",
|
|
1034
|
+
required: false
|
|
1035
|
+
},
|
|
1036
|
+
{
|
|
1037
|
+
name: "groupPolicy",
|
|
1038
|
+
label: "Group policy",
|
|
1039
|
+
hint: "\"allowlist\" (default) or \"open\"",
|
|
1040
|
+
required: false
|
|
1041
|
+
},
|
|
1042
|
+
{
|
|
1043
|
+
name: "dmPolicy",
|
|
1044
|
+
label: "DM policy",
|
|
1045
|
+
hint: "\"pairing\" (default) | \"allowlist\" | \"open\"",
|
|
545
1046
|
required: false
|
|
546
1047
|
}
|
|
547
1048
|
],
|
|
548
1049
|
setupSteps: [
|
|
549
1050
|
"1. Choose an IRC server (e.g. irc.libera.chat, irc.oftc.net).",
|
|
550
|
-
"2.
|
|
551
|
-
"3.
|
|
1051
|
+
"2. Set a nickname for the bot and the channels it should join.",
|
|
1052
|
+
"3. Enable TLS (recommended): set port 6697 and tls: true.",
|
|
1053
|
+
"4. If your nick is registered, set nickservPassword to auto-identify.",
|
|
1054
|
+
"5. Access control defaults: groupPolicy=allowlist (bot only replies in",
|
|
1055
|
+
" configured groups), dmPolicy=pairing (new DMs need pairing approval).",
|
|
1056
|
+
"6. To allow everyone in a channel without mention, set per-channel:",
|
|
1057
|
+
" groups[\"#mychan\"].requireMention = false, allowFrom = [\"*\"].",
|
|
1058
|
+
"",
|
|
1059
|
+
" Env vars: IRC_HOST IRC_PORT IRC_TLS IRC_NICK IRC_USERNAME",
|
|
1060
|
+
" IRC_REALNAME IRC_PASSWORD IRC_CHANNELS",
|
|
1061
|
+
" IRC_NICKSERV_PASSWORD IRC_NICKSERV_REGISTER_EMAIL",
|
|
552
1062
|
"",
|
|
553
1063
|
" 🔗 libera.chat — oftc.net"
|
|
554
1064
|
],
|
|
@@ -562,31 +1072,71 @@ const CHANNELS = [
|
|
|
562
1072
|
requiresGateway: true,
|
|
563
1073
|
supportsDM: true,
|
|
564
1074
|
platforms: ["all"],
|
|
565
|
-
tokenLabel: "
|
|
566
|
-
tokenHint: "
|
|
1075
|
+
tokenLabel: "Bot Token (MATTERMOST_BOT_TOKEN)",
|
|
1076
|
+
tokenHint: "System Console → Integrations → Bot Accounts → Add Bot Account",
|
|
567
1077
|
setupSteps: [
|
|
568
|
-
"1.
|
|
569
|
-
"2.
|
|
570
|
-
"3.
|
|
571
|
-
"4.
|
|
572
|
-
"5.
|
|
1078
|
+
"1. Create a Bot Account: System Console → Integrations → Bot Accounts → Add Bot Account.",
|
|
1079
|
+
"2. Copy the bot token shown after creation (not shown again).",
|
|
1080
|
+
"3. Note your Mattermost base URL (e.g. https://chat.example.com).",
|
|
1081
|
+
"4. The connector uses WebSocket events — no outgoing webhook needed.",
|
|
1082
|
+
"5. For slash commands: set commands.native=true and expose callbackUrl.",
|
|
1083
|
+
"6. For buttons: add capabilities: [\"inlineButtons\"] and set interactions.callbackBaseUrl.",
|
|
1084
|
+
"",
|
|
1085
|
+
" Env vars: MATTERMOST_BOT_TOKEN MATTERMOST_URL",
|
|
573
1086
|
"",
|
|
574
|
-
"
|
|
1087
|
+
" Chat modes:",
|
|
1088
|
+
" oncall (default) — reply only when @mentioned",
|
|
1089
|
+
" onmessage — reply to every channel message",
|
|
1090
|
+
" onchar — reply when message starts with a prefix (e.g. \">\", \"!\")",
|
|
1091
|
+
"",
|
|
1092
|
+
" Access control:",
|
|
1093
|
+
" dmPolicy=pairing (default) | allowlist | open | none",
|
|
1094
|
+
" groupPolicy=allowlist (default) | open",
|
|
1095
|
+
" groupAllowFrom=[userId1, ...] — sender gate for channels",
|
|
1096
|
+
"",
|
|
1097
|
+
" 🔗 docs.mattermost.com — mattermost.com"
|
|
1098
|
+
],
|
|
1099
|
+
extraFields: [
|
|
1100
|
+
{
|
|
1101
|
+
name: "baseUrl",
|
|
1102
|
+
label: "Base URL (MATTERMOST_URL)",
|
|
1103
|
+
hint: "https://chat.example.com",
|
|
1104
|
+
required: true
|
|
1105
|
+
},
|
|
1106
|
+
{
|
|
1107
|
+
name: "chatmode",
|
|
1108
|
+
label: "Chat mode",
|
|
1109
|
+
hint: "\"oncall\" (default) | \"onmessage\" | \"onchar\"",
|
|
1110
|
+
required: false
|
|
1111
|
+
},
|
|
1112
|
+
{
|
|
1113
|
+
name: "oncharPrefixes",
|
|
1114
|
+
label: "onchar prefixes",
|
|
1115
|
+
hint: ">, ! (comma-separated, for chatmode=onchar)",
|
|
1116
|
+
required: false
|
|
1117
|
+
},
|
|
1118
|
+
{
|
|
1119
|
+
name: "dmPolicy",
|
|
1120
|
+
label: "DM policy",
|
|
1121
|
+
hint: "\"pairing\" (default) | \"open\" | \"allowlist\" | \"none\"",
|
|
1122
|
+
required: false
|
|
1123
|
+
},
|
|
1124
|
+
{
|
|
1125
|
+
name: "groupPolicy",
|
|
1126
|
+
label: "Group policy",
|
|
1127
|
+
hint: "\"allowlist\" (default) | \"open\"",
|
|
1128
|
+
required: false
|
|
1129
|
+
},
|
|
1130
|
+
{
|
|
1131
|
+
name: "capabilities",
|
|
1132
|
+
label: "Capabilities",
|
|
1133
|
+
hint: "\"inlineButtons\" — comma-separated",
|
|
1134
|
+
required: false
|
|
1135
|
+
}
|
|
575
1136
|
],
|
|
576
|
-
extraFields: [{
|
|
577
|
-
name: "serverUrl",
|
|
578
|
-
label: "Server URL",
|
|
579
|
-
hint: "https://mattermost.example.com",
|
|
580
|
-
required: true
|
|
581
|
-
}, {
|
|
582
|
-
name: "webhookToken",
|
|
583
|
-
label: "Outgoing Webhook Token",
|
|
584
|
-
hint: "From Integrations > Outgoing Webhook",
|
|
585
|
-
required: true
|
|
586
|
-
}],
|
|
587
1137
|
status: "available",
|
|
588
|
-
notes: "
|
|
589
|
-
npmPackage: "
|
|
1138
|
+
notes: "WebSocket + REST. Supports DMs, channels, buttons, reactions, slash commands, multi-account.",
|
|
1139
|
+
npmPackage: "ws"
|
|
590
1140
|
},
|
|
591
1141
|
{
|
|
592
1142
|
id: "googlechat",
|
|
@@ -609,18 +1159,27 @@ const CHANNELS = [
|
|
|
609
1159
|
id: "msteams",
|
|
610
1160
|
name: "Microsoft Teams",
|
|
611
1161
|
emoji: "🟣",
|
|
612
|
-
requiresGateway:
|
|
613
|
-
supportsDM:
|
|
1162
|
+
requiresGateway: true,
|
|
1163
|
+
supportsDM: true,
|
|
614
1164
|
platforms: ["all"],
|
|
615
|
-
tokenLabel: "
|
|
1165
|
+
tokenLabel: "App ID (Azure Bot)",
|
|
1166
|
+
extraFields: [{
|
|
1167
|
+
name: "appPassword",
|
|
1168
|
+
label: "App Password (client secret)",
|
|
1169
|
+
hint: "From Azure Bot → Manage → Certificates & secrets",
|
|
1170
|
+
required: true
|
|
1171
|
+
}],
|
|
616
1172
|
setupSteps: [
|
|
617
|
-
"1.
|
|
618
|
-
"2.
|
|
619
|
-
"3.
|
|
1173
|
+
"1. Create an Azure Bot: portal.azure.com → Create a resource → Azure Bot",
|
|
1174
|
+
"2. Type of App: Single Tenant. Create new Microsoft App ID.",
|
|
1175
|
+
"3. Configuration → copy App ID. Manage → Certificates & secrets → New client secret → copy Value (appPassword).",
|
|
1176
|
+
"4. Channels → Microsoft Teams → Configure. Set Messaging endpoint: https://<your-host>/webhook/msteams",
|
|
1177
|
+
"5. Build a Teams app manifest with botId = App ID. Upload to Teams.",
|
|
620
1178
|
"",
|
|
621
|
-
" 🔗 docs.
|
|
1179
|
+
" 🔗 docs/msteams.md — full setup guide"
|
|
622
1180
|
],
|
|
623
|
-
status: "available"
|
|
1181
|
+
status: "available",
|
|
1182
|
+
notes: "Bot Framework. Text + DM. Channel/group files require Graph + SharePoint."
|
|
624
1183
|
},
|
|
625
1184
|
{
|
|
626
1185
|
id: "nostr",
|
|
@@ -650,24 +1209,61 @@ const CHANNELS = [
|
|
|
650
1209
|
id: "line",
|
|
651
1210
|
name: "LINE",
|
|
652
1211
|
emoji: "🟩",
|
|
653
|
-
requiresGateway:
|
|
1212
|
+
requiresGateway: true,
|
|
654
1213
|
supportsDM: true,
|
|
655
1214
|
platforms: ["all"],
|
|
656
1215
|
tokenLabel: "LINE Channel access token",
|
|
657
|
-
extraFields: [
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
1216
|
+
extraFields: [
|
|
1217
|
+
{
|
|
1218
|
+
name: "channelSecret",
|
|
1219
|
+
label: "Channel Secret",
|
|
1220
|
+
hint: "From LINE Developers Console → Basic settings",
|
|
1221
|
+
required: true
|
|
1222
|
+
},
|
|
1223
|
+
{
|
|
1224
|
+
name: "tokenFile",
|
|
1225
|
+
label: "Token file path (optional)",
|
|
1226
|
+
hint: "Alternative to pasting token directly",
|
|
1227
|
+
required: false
|
|
1228
|
+
},
|
|
1229
|
+
{
|
|
1230
|
+
name: "secretFile",
|
|
1231
|
+
label: "Secret file path (optional)",
|
|
1232
|
+
hint: "Alternative to pasting secret directly",
|
|
1233
|
+
required: false
|
|
1234
|
+
},
|
|
1235
|
+
{
|
|
1236
|
+
name: "webhookPath",
|
|
1237
|
+
label: "Webhook path",
|
|
1238
|
+
hint: "Default: /line/webhook",
|
|
1239
|
+
required: false
|
|
1240
|
+
},
|
|
1241
|
+
{
|
|
1242
|
+
name: "mediaMaxMb",
|
|
1243
|
+
label: "Media download limit (MB)",
|
|
1244
|
+
hint: "Default: 10",
|
|
1245
|
+
required: false
|
|
1246
|
+
},
|
|
1247
|
+
{
|
|
1248
|
+
name: "groupPolicy",
|
|
1249
|
+
label: "Group policy",
|
|
1250
|
+
hint: "open | allowlist | disabled (default: allowlist)",
|
|
1251
|
+
required: false
|
|
1252
|
+
}
|
|
1253
|
+
],
|
|
662
1254
|
setupSteps: [
|
|
663
|
-
"1. Go to developers.line.biz → Console → Create provider & channel.",
|
|
664
|
-
"2.
|
|
665
|
-
"3. Channel
|
|
666
|
-
"4.
|
|
1255
|
+
"1. Go to developers.line.biz → Console → Create provider & Messaging API channel.",
|
|
1256
|
+
"2. Channel access token: Issue or Regenerate — copy it.",
|
|
1257
|
+
"3. Channel secret: from Basic settings — copy it.",
|
|
1258
|
+
"4. Enable \"Use webhook\" in Messaging API settings.",
|
|
1259
|
+
"5. Set webhook URL (HTTPS required):",
|
|
1260
|
+
" https://<gateway-host>/line/webhook",
|
|
1261
|
+
"6. Paste token + secret below.",
|
|
667
1262
|
"",
|
|
668
1263
|
" 🔗 developers.line.biz"
|
|
669
1264
|
],
|
|
670
1265
|
status: "available",
|
|
1266
|
+
notes: "Webhook receiver. Supports DMs, groups, media, Flex messages, quick replies, locations.",
|
|
671
1267
|
npmPackage: "@line/bot-sdk"
|
|
672
1268
|
},
|
|
673
1269
|
{
|
|
@@ -695,27 +1291,68 @@ const CHANNELS = [
|
|
|
695
1291
|
{
|
|
696
1292
|
id: "synology-chat",
|
|
697
1293
|
name: "Synology Chat",
|
|
698
|
-
emoji: "
|
|
1294
|
+
emoji: "💬",
|
|
699
1295
|
requiresGateway: true,
|
|
700
1296
|
supportsDM: true,
|
|
701
1297
|
platforms: ["all"],
|
|
702
|
-
tokenLabel: "
|
|
703
|
-
tokenHint: "Synology Chat
|
|
704
|
-
extraFields: [
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
1298
|
+
tokenLabel: "Outgoing Webhook Token (SYNOLOGY_CHAT_TOKEN)",
|
|
1299
|
+
tokenHint: "From Synology Chat Integrations Outgoing Webhook",
|
|
1300
|
+
extraFields: [
|
|
1301
|
+
{
|
|
1302
|
+
name: "incomingUrl",
|
|
1303
|
+
label: "Incoming Webhook URL (SYNOLOGY_CHAT_INCOMING_URL)",
|
|
1304
|
+
hint: "From Synology Chat Integrations Incoming Webhook",
|
|
1305
|
+
required: true
|
|
1306
|
+
},
|
|
1307
|
+
{
|
|
1308
|
+
name: "webhookPath",
|
|
1309
|
+
label: "Gateway inbound path",
|
|
1310
|
+
hint: "/webhook/synology (default)",
|
|
1311
|
+
required: false
|
|
1312
|
+
},
|
|
1313
|
+
{
|
|
1314
|
+
name: "dmPolicy",
|
|
1315
|
+
label: "DM policy",
|
|
1316
|
+
hint: "\"allowlist\" (default) | \"open\" | \"pairing\" | \"disabled\"",
|
|
1317
|
+
required: false
|
|
1318
|
+
},
|
|
1319
|
+
{
|
|
1320
|
+
name: "allowedUserIds",
|
|
1321
|
+
label: "Allowed user IDs (SYNOLOGY_ALLOWED_USER_IDS)",
|
|
1322
|
+
hint: "Numeric Synology Chat user IDs, comma-separated",
|
|
1323
|
+
required: false
|
|
1324
|
+
},
|
|
1325
|
+
{
|
|
1326
|
+
name: "rateLimitPerMinute",
|
|
1327
|
+
label: "Rate limit per sender/min (SYNOLOGY_RATE_LIMIT)",
|
|
1328
|
+
hint: "30 (default)",
|
|
1329
|
+
required: false
|
|
1330
|
+
},
|
|
1331
|
+
{
|
|
1332
|
+
name: "allowInsecureSsl",
|
|
1333
|
+
label: "Allow insecure SSL",
|
|
1334
|
+
hint: "false (default) — true only for self-signed NAS certs",
|
|
1335
|
+
required: false
|
|
1336
|
+
}
|
|
1337
|
+
],
|
|
710
1338
|
setupSteps: [
|
|
711
|
-
"1. Synology Chat
|
|
712
|
-
"2.
|
|
713
|
-
"
|
|
1339
|
+
"1. Synology Chat Integrations Incoming Webhook Create copy URL.",
|
|
1340
|
+
"2. Synology Chat Integrations Outgoing Webhook Create:",
|
|
1341
|
+
" Outgoing URL: https://<gateway>/webhook/synology",
|
|
1342
|
+
" Copy the generated token.",
|
|
1343
|
+
"3. Set token + incomingUrl in config (or env vars).",
|
|
1344
|
+
"4. dmPolicy=allowlist requires at least one allowedUserId.",
|
|
1345
|
+
"",
|
|
1346
|
+
" Env vars: SYNOLOGY_CHAT_TOKEN SYNOLOGY_CHAT_INCOMING_URL",
|
|
1347
|
+
" SYNOLOGY_ALLOWED_USER_IDS SYNOLOGY_RATE_LIMIT OPENCLAW_BOT_NAME",
|
|
1348
|
+
"",
|
|
1349
|
+
" Multi-account: channels.synology-chat.accounts.{ default, alerts }",
|
|
1350
|
+
" Targets: <numericId>, synology-chat:<id>, user:<id>",
|
|
714
1351
|
"",
|
|
715
1352
|
" 🔗 kb.synology.com"
|
|
716
1353
|
],
|
|
717
1354
|
status: "available",
|
|
718
|
-
notes: "
|
|
1355
|
+
notes: "Gateway webhooks. Token verify, rate limiting, multi-account, allowInsecureSsl."
|
|
719
1356
|
},
|
|
720
1357
|
{
|
|
721
1358
|
id: "twitch",
|
|
@@ -726,61 +1363,84 @@ const CHANNELS = [
|
|
|
726
1363
|
platforms: ["all"],
|
|
727
1364
|
tokenLabel: "OAuth Token (oauth:...)",
|
|
728
1365
|
tokenHint: "Generate a Twitch chat token for your bot account",
|
|
729
|
-
extraFields: [
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
1366
|
+
extraFields: [
|
|
1367
|
+
{
|
|
1368
|
+
name: "username",
|
|
1369
|
+
label: "Bot username",
|
|
1370
|
+
required: true
|
|
1371
|
+
},
|
|
1372
|
+
{
|
|
1373
|
+
name: "channels",
|
|
1374
|
+
label: "Channels (comma-separated)",
|
|
1375
|
+
hint: "vevisk,secondchannel",
|
|
1376
|
+
required: true
|
|
1377
|
+
},
|
|
1378
|
+
{
|
|
1379
|
+
name: "commandPrefix",
|
|
1380
|
+
label: "Command prefix",
|
|
1381
|
+
hint: "! (default)",
|
|
1382
|
+
required: false
|
|
1383
|
+
}
|
|
1384
|
+
],
|
|
738
1385
|
setupSteps: [
|
|
739
|
-
"1. Create
|
|
740
|
-
"2.
|
|
741
|
-
"3. Add
|
|
1386
|
+
"1. Create Twitch bot account. Generate OAuth: twitchapps.com/tmi",
|
|
1387
|
+
"2. Config: username, oauthToken, channels (required).",
|
|
1388
|
+
"3. Add allowFrom (recommended) to restrict who can trigger.",
|
|
1389
|
+
"4. Public chat: prefix required (default !). Whispers: no prefix.",
|
|
742
1390
|
"",
|
|
743
|
-
" 🔗 dev.twitch.tv"
|
|
1391
|
+
" 🔗 docs/twitch.md — dev.twitch.tv"
|
|
744
1392
|
],
|
|
745
1393
|
status: "available",
|
|
746
|
-
notes: "
|
|
1394
|
+
notes: "IRC over WebSocket. Channel chat + whispers. Pairing, allowlist, modsBypass."
|
|
747
1395
|
},
|
|
748
1396
|
{
|
|
749
1397
|
id: "tlon",
|
|
750
|
-
name: "Tlon",
|
|
751
|
-
emoji: "
|
|
1398
|
+
name: "Tlon (Urbit Groups)",
|
|
1399
|
+
emoji: "🌊",
|
|
752
1400
|
requiresGateway: true,
|
|
753
1401
|
supportsDM: true,
|
|
754
1402
|
platforms: ["all"],
|
|
755
|
-
tokenLabel: "
|
|
756
|
-
tokenHint: "
|
|
1403
|
+
tokenLabel: "Login Code",
|
|
1404
|
+
tokenHint: "Ship login code from Landscape → Settings → Access key (e.g. lidlut-tabwed-pillex-ridrup)",
|
|
757
1405
|
extraFields: [
|
|
758
1406
|
{
|
|
759
|
-
name: "
|
|
760
|
-
label: "
|
|
761
|
-
hint: "e.g.
|
|
1407
|
+
name: "ship",
|
|
1408
|
+
label: "Ship Name",
|
|
1409
|
+
hint: "e.g. ~sampel-palnet",
|
|
762
1410
|
required: true
|
|
763
1411
|
},
|
|
764
1412
|
{
|
|
765
|
-
name: "
|
|
766
|
-
label: "
|
|
1413
|
+
name: "url",
|
|
1414
|
+
label: "Ship URL",
|
|
1415
|
+
hint: "e.g. https://sampel-palnet.tlon.network or http://localhost:8080",
|
|
1416
|
+
required: true
|
|
1417
|
+
},
|
|
1418
|
+
{
|
|
1419
|
+
name: "ownerShip",
|
|
1420
|
+
label: "Owner Ship",
|
|
1421
|
+
hint: "Your personal ship — always authorized, receives approval notifications",
|
|
767
1422
|
required: false
|
|
768
1423
|
},
|
|
769
1424
|
{
|
|
770
|
-
name: "
|
|
771
|
-
label: "
|
|
1425
|
+
name: "allowPrivateNetwork",
|
|
1426
|
+
label: "Allow Private Network",
|
|
1427
|
+
hint: "Enable for localhost/LAN ships (SSRF opt-in)",
|
|
772
1428
|
required: false
|
|
773
1429
|
}
|
|
774
1430
|
],
|
|
775
1431
|
setupSteps: [
|
|
776
|
-
"1.
|
|
777
|
-
"2.
|
|
778
|
-
"3.
|
|
1432
|
+
"1. Install plugin: hyperclaw plugins install @hyperclaw/extension-tlon",
|
|
1433
|
+
"2. Get your ship login code from Landscape (Settings → System → Access key).",
|
|
1434
|
+
"3. Configure channels.tlon with ship name, URL, and login code.",
|
|
1435
|
+
"4. Optionally set ownerShip to receive approval notifications.",
|
|
1436
|
+
"5. Restart gateway: hyperclaw gateway restart",
|
|
1437
|
+
"6. DM the bot ship in Tlon or mention it in a group channel.",
|
|
779
1438
|
"",
|
|
780
|
-
"
|
|
1439
|
+
" Plugin required — connects via Urbit Eyre HTTP API + SSE stream.",
|
|
1440
|
+
" See: docs/tlon.md"
|
|
781
1441
|
],
|
|
782
1442
|
status: "available",
|
|
783
|
-
notes: "
|
|
1443
|
+
notes: "Urbit Eyre HTTP API + SSE. DMs, groups, reactions, owner approval, auto-discovery. Plugin: @hyperclaw/extension-tlon"
|
|
784
1444
|
},
|
|
785
1445
|
{
|
|
786
1446
|
id: "instagram",
|
|
@@ -914,46 +1574,136 @@ const CHANNELS = [
|
|
|
914
1574
|
status: "available"
|
|
915
1575
|
},
|
|
916
1576
|
{
|
|
917
|
-
id: "nextcloud",
|
|
1577
|
+
id: "nextcloud-talk",
|
|
918
1578
|
name: "Nextcloud Talk",
|
|
919
1579
|
emoji: "☁️",
|
|
920
1580
|
requiresGateway: true,
|
|
921
1581
|
supportsDM: true,
|
|
922
1582
|
platforms: ["all"],
|
|
923
|
-
tokenLabel: "Nextcloud URL",
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
1583
|
+
tokenLabel: "Nextcloud instance URL",
|
|
1584
|
+
tokenHint: "e.g. https://cloud.example.com",
|
|
1585
|
+
extraFields: [
|
|
1586
|
+
{
|
|
1587
|
+
name: "botSecret",
|
|
1588
|
+
label: "Bot shared secret",
|
|
1589
|
+
hint: "From: occ talk:bot:install",
|
|
1590
|
+
required: true
|
|
1591
|
+
},
|
|
1592
|
+
{
|
|
1593
|
+
name: "botSecretFile",
|
|
1594
|
+
label: "Bot secret file path (optional)",
|
|
1595
|
+
hint: "Alternative to inline secret",
|
|
1596
|
+
required: false
|
|
1597
|
+
},
|
|
1598
|
+
{
|
|
1599
|
+
name: "apiUser",
|
|
1600
|
+
label: "API username (optional)",
|
|
1601
|
+
hint: "For DM detection + fallback send via OCS API",
|
|
1602
|
+
required: false
|
|
1603
|
+
},
|
|
1604
|
+
{
|
|
1605
|
+
name: "apiPassword",
|
|
1606
|
+
label: "API/app password (optional)",
|
|
1607
|
+
hint: "Nextcloud app password for apiUser",
|
|
1608
|
+
required: false
|
|
1609
|
+
},
|
|
1610
|
+
{
|
|
1611
|
+
name: "webhookPort",
|
|
1612
|
+
label: "Webhook listener port",
|
|
1613
|
+
hint: "Default: 8788",
|
|
1614
|
+
required: false
|
|
1615
|
+
},
|
|
1616
|
+
{
|
|
1617
|
+
name: "webhookPath",
|
|
1618
|
+
label: "Webhook path",
|
|
1619
|
+
hint: "Default: /nextcloud-talk-webhook",
|
|
1620
|
+
required: false
|
|
1621
|
+
},
|
|
1622
|
+
{
|
|
1623
|
+
name: "webhookPublicUrl",
|
|
1624
|
+
label: "Webhook public URL",
|
|
1625
|
+
hint: "If behind a proxy — set this in occ talk:bot:install",
|
|
1626
|
+
required: false
|
|
1627
|
+
},
|
|
1628
|
+
{
|
|
1629
|
+
name: "groupPolicy",
|
|
1630
|
+
label: "Room policy",
|
|
1631
|
+
hint: "allowlist (default) | open | disabled",
|
|
1632
|
+
required: false
|
|
1633
|
+
},
|
|
1634
|
+
{
|
|
1635
|
+
name: "textChunkLimit",
|
|
1636
|
+
label: "Text chunk limit (chars)",
|
|
1637
|
+
hint: "Default: 32000",
|
|
1638
|
+
required: false
|
|
1639
|
+
}
|
|
1640
|
+
],
|
|
933
1641
|
setupSteps: [
|
|
934
|
-
"1.
|
|
935
|
-
"
|
|
1642
|
+
"1. On your Nextcloud server, create the bot:",
|
|
1643
|
+
" ./occ talk:bot:install \"HyperClaw\" \"<shared-secret>\" \"<webhook-url>\" --feature reaction",
|
|
1644
|
+
" Replace <webhook-url> with your gateway URL, e.g. https://yourhost/nextcloud-talk-webhook",
|
|
1645
|
+
"2. Enable the bot in the target room settings (room → ⋯ → Bots).",
|
|
1646
|
+
"3. Enter the Nextcloud URL (token field) and the shared secret below.",
|
|
1647
|
+
"4. (Optional) Add apiUser + app password to enable DM detection via OCS API.",
|
|
936
1648
|
"",
|
|
937
|
-
" 🔗 nextcloud.com"
|
|
1649
|
+
" 🔗 nextcloud.com — docs.nextcloud.com/server/latest/admin_manual/talk_bots.html"
|
|
938
1650
|
],
|
|
939
|
-
status: "available"
|
|
1651
|
+
status: "available",
|
|
1652
|
+
notes: "Webhook bot. Supports DMs (with apiUser), rooms, reactions. No media uploads."
|
|
940
1653
|
},
|
|
941
1654
|
{
|
|
942
1655
|
id: "zalo",
|
|
943
1656
|
name: "Zalo",
|
|
944
1657
|
emoji: "🔵",
|
|
945
|
-
requiresGateway:
|
|
1658
|
+
requiresGateway: true,
|
|
946
1659
|
supportsDM: true,
|
|
947
1660
|
platforms: ["all"],
|
|
948
|
-
tokenLabel: "Zalo
|
|
1661
|
+
tokenLabel: "Zalo Bot Token (12345689:abc-xyz)",
|
|
1662
|
+
tokenHint: "From bot.zaloplatforms.com",
|
|
1663
|
+
extraFields: [
|
|
1664
|
+
{
|
|
1665
|
+
name: "tokenFile",
|
|
1666
|
+
label: "Token file path (optional)",
|
|
1667
|
+
hint: "Alternative to inline token",
|
|
1668
|
+
required: false
|
|
1669
|
+
},
|
|
1670
|
+
{
|
|
1671
|
+
name: "groupPolicy",
|
|
1672
|
+
label: "Group policy",
|
|
1673
|
+
hint: "allowlist (default) | open | disabled",
|
|
1674
|
+
required: false
|
|
1675
|
+
},
|
|
1676
|
+
{
|
|
1677
|
+
name: "webhookUrl",
|
|
1678
|
+
label: "Webhook URL (optional)",
|
|
1679
|
+
hint: "HTTPS required — leave blank for long-polling",
|
|
1680
|
+
required: false
|
|
1681
|
+
},
|
|
1682
|
+
{
|
|
1683
|
+
name: "webhookSecret",
|
|
1684
|
+
label: "Webhook secret (optional)",
|
|
1685
|
+
hint: "8-256 chars — required if webhookUrl is set",
|
|
1686
|
+
required: false
|
|
1687
|
+
},
|
|
1688
|
+
{
|
|
1689
|
+
name: "mediaMaxMb",
|
|
1690
|
+
label: "Media size limit (MB)",
|
|
1691
|
+
hint: "Default: 5",
|
|
1692
|
+
required: false
|
|
1693
|
+
}
|
|
1694
|
+
],
|
|
949
1695
|
setupSteps: [
|
|
950
|
-
"1.
|
|
951
|
-
"2. Create
|
|
952
|
-
"3.
|
|
1696
|
+
"1. Go to https://bot.zaloplatforms.com and sign in.",
|
|
1697
|
+
"2. Create a new bot and configure its settings.",
|
|
1698
|
+
"3. Copy the bot token (format: 12345689:abc-xyz).",
|
|
1699
|
+
"4. Paste the token below.",
|
|
1700
|
+
"5. (Optional) Set webhookUrl for webhook mode (HTTPS required).",
|
|
1701
|
+
" Leave blank to use long-polling (no public URL needed).",
|
|
953
1702
|
"",
|
|
954
|
-
" 🔗
|
|
1703
|
+
" 🔗 bot.zaloplatforms.com"
|
|
955
1704
|
],
|
|
956
|
-
status: "available"
|
|
1705
|
+
status: "available",
|
|
1706
|
+
notes: "Experimental. DMs supported; groups with allowlist policy. Long-polling by default."
|
|
957
1707
|
},
|
|
958
1708
|
{
|
|
959
1709
|
id: "web",
|
|
@@ -1042,18 +1792,24 @@ const ZALO_PERSONAL = {
|
|
|
1042
1792
|
requiresGateway: true,
|
|
1043
1793
|
supportsDM: true,
|
|
1044
1794
|
platforms: ["all"],
|
|
1045
|
-
tokenLabel: "
|
|
1046
|
-
tokenHint: "
|
|
1795
|
+
tokenLabel: "Cookie (from chat.zalo.me)",
|
|
1796
|
+
tokenHint: "DevTools → Application → Cookies",
|
|
1797
|
+
extraFields: [{
|
|
1798
|
+
name: "dmPolicy",
|
|
1799
|
+
label: "DM policy",
|
|
1800
|
+
hint: "pairing (default) | allowlist | open | disabled",
|
|
1801
|
+
required: false
|
|
1802
|
+
}],
|
|
1047
1803
|
setupSteps: [
|
|
1048
|
-
"1.
|
|
1049
|
-
"2. Open
|
|
1050
|
-
"3.
|
|
1051
|
-
"4.
|
|
1804
|
+
"1. ⚠️ Experimental — unofficial. Account ban risk. Use at your own risk.",
|
|
1805
|
+
"2. Open chat.zalo.me, log in. DevTools → Application → Cookies → copy.",
|
|
1806
|
+
"3. Add channel, set cookie (or ZALO_PERSONAL_COOKIE env).",
|
|
1807
|
+
"4. hyperclaw gateway → hyperclaw pairing approve zalo-personal <CODE>",
|
|
1052
1808
|
"",
|
|
1053
|
-
"
|
|
1809
|
+
" 🔗 docs/zalo-personal.md — full setup"
|
|
1054
1810
|
],
|
|
1055
1811
|
status: "available",
|
|
1056
|
-
notes: "
|
|
1812
|
+
notes: "Zalo Web cookie auth. DMs only. No groups. Text chunked ~2000 chars."
|
|
1057
1813
|
};
|
|
1058
1814
|
CHANNELS.push(ZALO_PERSONAL);
|
|
1059
1815
|
|
|
@@ -1185,6 +1941,180 @@ async function getConfiguredChannels() {
|
|
|
1185
1941
|
return [];
|
|
1186
1942
|
}
|
|
1187
1943
|
}
|
|
1944
|
+
/**
|
|
1945
|
+
* hyperclaw channels login [channel]
|
|
1946
|
+
* Shortcut for first-time login flows (QR pairing, bot tokens, OAuth).
|
|
1947
|
+
* Delegates to channelsAdd with a login-oriented preamble.
|
|
1948
|
+
*/
|
|
1949
|
+
async function channelsLogin(channelId) {
|
|
1950
|
+
console.log(chalk.default.bold.cyan("\n 🔑 Channel Login\n"));
|
|
1951
|
+
console.log(chalk.default.gray(" This wizard will guide you through first-time login for a channel.\n"));
|
|
1952
|
+
console.log(chalk.default.gray(" WhatsApp → QR code scan"));
|
|
1953
|
+
console.log(chalk.default.gray(" Telegram → bot token (from @BotFather)"));
|
|
1954
|
+
console.log(chalk.default.gray(" Discord → bot token (from Discord Developer Portal)"));
|
|
1955
|
+
console.log(chalk.default.gray(" Slack → bot + app tokens"));
|
|
1956
|
+
console.log(chalk.default.gray(" Signal → phone number + signal-cli daemon\n"));
|
|
1957
|
+
await channelsAdd(channelId);
|
|
1958
|
+
}
|
|
1959
|
+
function httpProbe(url, ms = 1200) {
|
|
1960
|
+
return new Promise((resolve) => {
|
|
1961
|
+
const req = http.default.get(url, { timeout: ms }, (res) => {
|
|
1962
|
+
res.resume();
|
|
1963
|
+
resolve((res.statusCode ?? 0) < 500);
|
|
1964
|
+
});
|
|
1965
|
+
req.on("error", () => resolve(false));
|
|
1966
|
+
req.on("timeout", () => {
|
|
1967
|
+
req.destroy();
|
|
1968
|
+
resolve(false);
|
|
1969
|
+
});
|
|
1970
|
+
});
|
|
1971
|
+
}
|
|
1972
|
+
/** Attempt a lightweight connectivity probe for a channel. */
|
|
1973
|
+
async function probeChannel(channelId, channelCfg) {
|
|
1974
|
+
switch (channelId) {
|
|
1975
|
+
case "telegram": {
|
|
1976
|
+
const token = channelCfg?.token || process.env.TELEGRAM_BOT_TOKEN;
|
|
1977
|
+
if (!token) return {
|
|
1978
|
+
status: "skipped",
|
|
1979
|
+
detail: "no token"
|
|
1980
|
+
};
|
|
1981
|
+
const ok = await httpProbe(`https://api.telegram.org/bot${token}/getMe`);
|
|
1982
|
+
return ok ? {
|
|
1983
|
+
status: "connected",
|
|
1984
|
+
detail: "api.telegram.org ok"
|
|
1985
|
+
} : {
|
|
1986
|
+
status: "unreachable",
|
|
1987
|
+
detail: "api.telegram.org unreachable"
|
|
1988
|
+
};
|
|
1989
|
+
}
|
|
1990
|
+
case "discord": {
|
|
1991
|
+
const ok = await httpProbe("https://discord.com/api/v10/gateway");
|
|
1992
|
+
return ok ? {
|
|
1993
|
+
status: "connected",
|
|
1994
|
+
detail: "discord.com/api ok"
|
|
1995
|
+
} : {
|
|
1996
|
+
status: "unreachable",
|
|
1997
|
+
detail: "discord.com unreachable"
|
|
1998
|
+
};
|
|
1999
|
+
}
|
|
2000
|
+
case "signal": {
|
|
2001
|
+
const daemonUrl = channelCfg?.daemonUrl || "http://127.0.0.1:8080";
|
|
2002
|
+
const ok = await httpProbe(`${daemonUrl}/v1/about`);
|
|
2003
|
+
return ok ? {
|
|
2004
|
+
status: "connected",
|
|
2005
|
+
detail: `signal-cli at ${daemonUrl}`
|
|
2006
|
+
} : {
|
|
2007
|
+
status: "unreachable",
|
|
2008
|
+
detail: `signal-cli not reachable at ${daemonUrl}`
|
|
2009
|
+
};
|
|
2010
|
+
}
|
|
2011
|
+
case "mattermost": {
|
|
2012
|
+
const baseUrl = channelCfg?.baseUrl;
|
|
2013
|
+
if (!baseUrl) return {
|
|
2014
|
+
status: "skipped",
|
|
2015
|
+
detail: "no baseUrl"
|
|
2016
|
+
};
|
|
2017
|
+
const ok = await httpProbe(`${baseUrl}/api/v4/system/ping`);
|
|
2018
|
+
return ok ? {
|
|
2019
|
+
status: "connected",
|
|
2020
|
+
detail: "system/ping ok"
|
|
2021
|
+
} : {
|
|
2022
|
+
status: "unreachable",
|
|
2023
|
+
detail: "server unreachable"
|
|
2024
|
+
};
|
|
2025
|
+
}
|
|
2026
|
+
case "matrix": {
|
|
2027
|
+
const homeserver = channelCfg?.homeserver;
|
|
2028
|
+
if (!homeserver) return {
|
|
2029
|
+
status: "skipped",
|
|
2030
|
+
detail: "no homeserver"
|
|
2031
|
+
};
|
|
2032
|
+
const ok = await httpProbe(`${homeserver}/_matrix/client/versions`);
|
|
2033
|
+
return ok ? {
|
|
2034
|
+
status: "connected",
|
|
2035
|
+
detail: "matrix client ok"
|
|
2036
|
+
} : {
|
|
2037
|
+
status: "unreachable",
|
|
2038
|
+
detail: "homeserver unreachable"
|
|
2039
|
+
};
|
|
2040
|
+
}
|
|
2041
|
+
case "slack": {
|
|
2042
|
+
const ok = await httpProbe("https://slack.com/api/api.test");
|
|
2043
|
+
return ok ? {
|
|
2044
|
+
status: "connected",
|
|
2045
|
+
detail: "slack.com/api ok"
|
|
2046
|
+
} : {
|
|
2047
|
+
status: "unreachable",
|
|
2048
|
+
detail: "slack.com unreachable"
|
|
2049
|
+
};
|
|
2050
|
+
}
|
|
2051
|
+
default: return {
|
|
2052
|
+
status: "skipped",
|
|
2053
|
+
detail: "probe not implemented"
|
|
2054
|
+
};
|
|
2055
|
+
}
|
|
2056
|
+
}
|
|
2057
|
+
/**
|
|
2058
|
+
* hyperclaw channels status [--probe]
|
|
2059
|
+
* Show all configured channels with their status.
|
|
2060
|
+
* --probe attempts a real connectivity check for each.
|
|
2061
|
+
*/
|
|
2062
|
+
async function channelsStatus(opts = {}) {
|
|
2063
|
+
const configFile = path.default.join(os.default.homedir(), ".hyperclaw", "config.json");
|
|
2064
|
+
let cfg = {};
|
|
2065
|
+
try {
|
|
2066
|
+
cfg = fs_extra.default.readJsonSync(configFile);
|
|
2067
|
+
} catch {}
|
|
2068
|
+
const configured = cfg.channels || [];
|
|
2069
|
+
console.log(chalk.default.bold.cyan("\n 📡 CHANNEL STATUS\n"));
|
|
2070
|
+
if (configured.length === 0) {
|
|
2071
|
+
console.log(chalk.default.gray(" No channels configured.\n"));
|
|
2072
|
+
console.log(chalk.default.gray(" Add a channel: hyperclaw channels add\n"));
|
|
2073
|
+
return;
|
|
2074
|
+
}
|
|
2075
|
+
const spinner = opts.probe ? (0, ora.default)("Probing channels...").start() : null;
|
|
2076
|
+
const results = [];
|
|
2077
|
+
for (const id of configured) {
|
|
2078
|
+
const ch = getChannel(id);
|
|
2079
|
+
if (!ch) continue;
|
|
2080
|
+
const channelCfg = cfg.channelConfigs?.[id];
|
|
2081
|
+
const dmPolicy = channelCfg?.dmPolicy?.policy ?? channelCfg?.dmPolicy;
|
|
2082
|
+
const r = {
|
|
2083
|
+
id,
|
|
2084
|
+
name: ch.name,
|
|
2085
|
+
emoji: ch.emoji,
|
|
2086
|
+
configured: true,
|
|
2087
|
+
dmPolicy
|
|
2088
|
+
};
|
|
2089
|
+
if (opts.probe) {
|
|
2090
|
+
const { status, detail } = await probeChannel(id, channelCfg);
|
|
2091
|
+
r.probe = status;
|
|
2092
|
+
r.probeDetail = detail;
|
|
2093
|
+
}
|
|
2094
|
+
results.push(r);
|
|
2095
|
+
}
|
|
2096
|
+
if (spinner) spinner.stop();
|
|
2097
|
+
const allIds = CHANNELS.map((c) => c.id);
|
|
2098
|
+
const unconfigured = allIds.filter((id) => !configured.includes(id));
|
|
2099
|
+
for (const r of results) {
|
|
2100
|
+
const probeStr = opts.probe ? r.probe === "connected" ? chalk.default.green(" ✔ connected") : r.probe === "unreachable" ? chalk.default.red(" ✖ unreachable") : chalk.default.gray(" — skipped") : "";
|
|
2101
|
+
const dm = r.dmPolicy ? chalk.default.gray(` dm:${r.dmPolicy}`) : "";
|
|
2102
|
+
console.log(` ${chalk.default.green("●")} ${r.emoji} ${r.name.padEnd(18)}${dm}${probeStr}`);
|
|
2103
|
+
if (opts.probe && r.probeDetail) console.log(` ${chalk.default.gray(r.probeDetail)}`);
|
|
2104
|
+
}
|
|
2105
|
+
if (unconfigured.length > 0) console.log(chalk.default.gray(`\n ○ ${unconfigured.length} unconfigured channel(s) — add with: hyperclaw channels add`));
|
|
2106
|
+
console.log();
|
|
2107
|
+
if (opts.probe) {
|
|
2108
|
+
const unreachable = results.filter((r) => r.probe === "unreachable");
|
|
2109
|
+
if (unreachable.length > 0) {
|
|
2110
|
+
console.log(chalk.default.yellow(` ⚠ ${unreachable.length} channel(s) unreachable:`));
|
|
2111
|
+
for (const r of unreachable) console.log(chalk.default.gray(` ${r.id}: ${r.probeDetail}`));
|
|
2112
|
+
console.log();
|
|
2113
|
+
console.log(chalk.default.gray(" Troubleshoot: hyperclaw doctor"));
|
|
2114
|
+
console.log(chalk.default.gray(" Logs: hyperclaw logs --follow\n"));
|
|
2115
|
+
} else console.log(chalk.default.green(" ✔ All probed channels reachable\n"));
|
|
2116
|
+
}
|
|
2117
|
+
}
|
|
1188
2118
|
|
|
1189
2119
|
//#endregion
|
|
1190
2120
|
//#region src/infra/update-channels.ts
|
|
@@ -1496,22 +2426,68 @@ var init_queue = require_chunk.__esm({ "src/delivery/queue.ts"() {
|
|
|
1496
2426
|
//#endregion
|
|
1497
2427
|
//#region src/cli/run-main.ts
|
|
1498
2428
|
const program = new commander.Command();
|
|
1499
|
-
program.name("hyperclaw").description("⚡ HyperClaw — AI Gateway Platform. The Lobster Evolution 🦅").version("
|
|
2429
|
+
program.name("hyperclaw").description("⚡ HyperClaw — AI Gateway Platform. The Lobster Evolution 🦅").version("5.0.0").option("--profile <name>", "Use an isolated gateway profile. Auto-scopes HYPERCLAW_STATE_DIR and HYPERCLAW_CONFIG_PATH. Required for multi-gateway setups (rescue bot, staging, etc.). Example: hyperclaw --profile rescue gateway --port 19001").hook("preAction", (thisCommand) => {
|
|
2430
|
+
const profile = thisCommand.opts().profile;
|
|
2431
|
+
if (profile) {
|
|
2432
|
+
const os$8 = require("os");
|
|
2433
|
+
const path$7 = require("path");
|
|
2434
|
+
const home = os$8.homedir();
|
|
2435
|
+
if (!process.env.HYPERCLAW_STATE_DIR) process.env.HYPERCLAW_STATE_DIR = path$7.join(home, `.hyperclaw-${profile}`);
|
|
2436
|
+
if (!process.env.HYPERCLAW_CONFIG_PATH) process.env.HYPERCLAW_CONFIG_PATH = path$7.join(process.env.HYPERCLAW_STATE_DIR, "hyperclaw.json");
|
|
2437
|
+
}
|
|
2438
|
+
});
|
|
1500
2439
|
program.command("init").description("Initialize HyperClaw with interactive wizard").option("-a, --auto-config", "Auto-configure with defaults").option("-d, --daemon", "Install as system daemon").option("-s, --start-now", "Start gateway after setup").action(async (opts) => {
|
|
1501
2440
|
await new require_onboard.Banner().showNeonBanner(false);
|
|
1502
2441
|
await new require_onboard.HyperClawWizard().run(opts);
|
|
1503
2442
|
process.exit(0);
|
|
1504
2443
|
});
|
|
1505
|
-
program.command("onboard").description("Full onboarding wizard — preferred setup path").option("--install-daemon", "Auto-install system daemon (starts on boot, grants full PC access)").option("--quick", "Use QuickStart mode (skip advanced options)").action(async (opts) => {
|
|
2444
|
+
program.command("onboard").description("Full onboarding wizard — preferred setup path").option("--install-daemon", "Auto-install system daemon (starts on boot, grants full PC access)").option("--quick", "Use QuickStart mode (skip advanced options)").option("--reset", "Reset config before running wizard (sends to trash, not deleted)").option("--reset-scope <scope>", "What to reset: config | config+creds | full", "config").option("--non-interactive", "Run in non-interactive mode (use flags for all options)").option("--json", "Output result as JSON (use with --non-interactive)").option("--anthropic-api-key <key>", "Anthropic API key (non-interactive)").option("--openai-api-key <key>", "OpenAI API key (non-interactive)").option("--gateway-port <port>", "Gateway port (non-interactive)", "18789").option("--gateway-bind <bind>", "Gateway bind: loopback | all (non-interactive)", "loopback").option("--daemon-runtime <runtime>", "Daemon runtime: node | bun (non-interactive)", "node").option("--skip-skills", "Skip skills setup (non-interactive)").option("--skip-search", "Skip web search setup (non-interactive)").action(async (opts) => {
|
|
1506
2445
|
await new require_onboard.Banner().showNeonBanner(false);
|
|
2446
|
+
if (opts.reset) {
|
|
2447
|
+
const fs$7 = require("fs-extra");
|
|
2448
|
+
const path$7 = require("path");
|
|
2449
|
+
const os$8 = require("os");
|
|
2450
|
+
const hcDir = path$7.join(os$8.homedir(), ".hyperclaw");
|
|
2451
|
+
const scope = opts.resetScope ?? "config";
|
|
2452
|
+
const filesToRemove = [path$7.join(hcDir, "hyperclaw.json")];
|
|
2453
|
+
if (scope === "config+creds" || scope === "full") {
|
|
2454
|
+
filesToRemove.push(path$7.join(hcDir, "credentials"));
|
|
2455
|
+
filesToRemove.push(path$7.join(hcDir, "sessions"));
|
|
2456
|
+
}
|
|
2457
|
+
if (scope === "full") filesToRemove.push(path$7.join(hcDir, "workspace"));
|
|
2458
|
+
const chalk$11 = require("chalk");
|
|
2459
|
+
console.log(chalk$11.yellow(`\n ⚠ Reset scope: ${chalk$11.bold(scope)}\n`));
|
|
2460
|
+
console.log(chalk$11.gray(" Files to remove:"));
|
|
2461
|
+
filesToRemove.forEach((f) => console.log(chalk$11.gray(` • ${f}`)));
|
|
2462
|
+
const inquirer$2 = require("inquirer");
|
|
2463
|
+
const { confirmReset } = await inquirer$2.prompt([{
|
|
2464
|
+
type: "confirm",
|
|
2465
|
+
name: "confirmReset",
|
|
2466
|
+
message: "Confirm reset? (files will be moved to trash/backup, not permanently deleted)",
|
|
2467
|
+
default: false
|
|
2468
|
+
}]);
|
|
2469
|
+
if (confirmReset) {
|
|
2470
|
+
const backupDir = path$7.join(hcDir, `backup-${Date.now()}`);
|
|
2471
|
+
await fs$7.ensureDir(backupDir);
|
|
2472
|
+
for (const f of filesToRemove) if (await fs$7.pathExists(f)) {
|
|
2473
|
+
const dest = path$7.join(backupDir, path$7.basename(f));
|
|
2474
|
+
await fs$7.move(f, dest);
|
|
2475
|
+
console.log(chalk$11.gray(` ✓ Moved ${path$7.basename(f)} → backup/`));
|
|
2476
|
+
}
|
|
2477
|
+
console.log(chalk$11.green("\n ✔ Reset complete. Starting fresh...\n"));
|
|
2478
|
+
} else {
|
|
2479
|
+
console.log(chalk$11.gray("\n Reset cancelled.\n"));
|
|
2480
|
+
process.exit(0);
|
|
2481
|
+
}
|
|
2482
|
+
}
|
|
1507
2483
|
if (opts.installDaemon) {
|
|
1508
|
-
const chalk$
|
|
1509
|
-
console.log(chalk$
|
|
1510
|
-
console.log(chalk$
|
|
1511
|
-
console.log(chalk$
|
|
1512
|
-
console.log(chalk$
|
|
1513
|
-
console.log(chalk$
|
|
1514
|
-
console.log(chalk$
|
|
2484
|
+
const chalk$11 = require("chalk");
|
|
2485
|
+
console.log(chalk$11.yellow("\n ⚠ --install-daemon mode\n"));
|
|
2486
|
+
console.log(chalk$11.gray(" The daemon will run as a background system service and will have:\n"));
|
|
2487
|
+
console.log(chalk$11.white(" • Full shell / command execution on this machine"));
|
|
2488
|
+
console.log(chalk$11.white(" • File system read & write access"));
|
|
2489
|
+
console.log(chalk$11.white(" • Network access (gateway WebSocket)"));
|
|
2490
|
+
console.log(chalk$11.white(" • Auto-start on every system boot\n"));
|
|
1515
2491
|
const inquirer$2 = require("inquirer");
|
|
1516
2492
|
const { confirmed } = await inquirer$2.prompt([{
|
|
1517
2493
|
type: "confirm",
|
|
@@ -1520,14 +2496,23 @@ program.command("onboard").description("Full onboarding wizard — preferred set
|
|
|
1520
2496
|
default: false
|
|
1521
2497
|
}]);
|
|
1522
2498
|
if (!confirmed) {
|
|
1523
|
-
console.log(chalk$
|
|
2499
|
+
console.log(chalk$11.gray("\n Cancelled. Run without --install-daemon to choose during setup.\n"));
|
|
1524
2500
|
process.exit(0);
|
|
1525
2501
|
}
|
|
1526
2502
|
}
|
|
1527
2503
|
await new require_onboard.HyperClawWizard().run({
|
|
1528
2504
|
...opts,
|
|
1529
2505
|
wizard: true,
|
|
1530
|
-
installDaemon: opts.installDaemon ?? false
|
|
2506
|
+
installDaemon: opts.installDaemon ?? false,
|
|
2507
|
+
nonInteractive: opts.nonInteractive ?? false,
|
|
2508
|
+
jsonOutput: opts.json ?? false,
|
|
2509
|
+
skipSkills: opts.skipSkills ?? false,
|
|
2510
|
+
skipSearch: opts.skipSearch ?? false,
|
|
2511
|
+
daemonRuntime: opts.daemonRuntime ?? "node",
|
|
2512
|
+
gatewayPort: opts.gatewayPort ? parseInt(opts.gatewayPort) : void 0,
|
|
2513
|
+
gatewayBind: opts.gatewayBind ?? "loopback",
|
|
2514
|
+
anthropicApiKey: opts.anthropicApiKey,
|
|
2515
|
+
openaiApiKey: opts.openaiApiKey
|
|
1531
2516
|
});
|
|
1532
2517
|
process.exit(0);
|
|
1533
2518
|
});
|
|
@@ -1552,18 +2537,18 @@ gatewayCmd.command("status").description("Show gateway status").action(async ()
|
|
|
1552
2537
|
process.exit(0);
|
|
1553
2538
|
});
|
|
1554
2539
|
gatewayCmd.command("start").description("Start the gateway service").option("-p, --port <port>", "Override port").action(async (opts) => {
|
|
1555
|
-
await new
|
|
2540
|
+
await new require_daemon.DaemonManager().start();
|
|
1556
2541
|
});
|
|
1557
2542
|
gatewayCmd.command("stop").description("Stop the gateway service").action(async () => {
|
|
1558
|
-
await new
|
|
2543
|
+
await new require_daemon.DaemonManager().stop();
|
|
1559
2544
|
process.exit(0);
|
|
1560
2545
|
});
|
|
1561
2546
|
gatewayCmd.command("restart").description("Restart the gateway service").action(async () => {
|
|
1562
|
-
const dm = new
|
|
2547
|
+
const dm = new require_daemon.DaemonManager();
|
|
1563
2548
|
await dm.restart();
|
|
1564
2549
|
});
|
|
1565
2550
|
program.command("daemon").description("Manage HyperClaw system service (alias: gateway)").argument("<action>", "start|stop|restart|status|logs|install|uninstall").action(async (action) => {
|
|
1566
|
-
const dm = new
|
|
2551
|
+
const dm = new require_daemon.DaemonManager();
|
|
1567
2552
|
if (action === "start") await new require_onboard.Banner().showNeonBanner(true);
|
|
1568
2553
|
await dm.handle(action);
|
|
1569
2554
|
if (action === "start" || action === "restart") return;
|
|
@@ -1571,20 +2556,20 @@ program.command("daemon").description("Manage HyperClaw system service (alias: g
|
|
|
1571
2556
|
});
|
|
1572
2557
|
const sandboxCmd = program.command("sandbox").description("Debug sandbox and tool policy");
|
|
1573
2558
|
sandboxCmd.command("explain").description("Show effective sandbox mode, tool policy, and allowed tools").option("--json", "Output as JSON").action(async (opts) => {
|
|
1574
|
-
const chalk$
|
|
1575
|
-
const fs$
|
|
1576
|
-
const path$
|
|
1577
|
-
const os$
|
|
2559
|
+
const chalk$11 = require("chalk");
|
|
2560
|
+
const fs$7 = require("fs-extra");
|
|
2561
|
+
const path$7 = require("path");
|
|
2562
|
+
const os$8 = require("os");
|
|
1578
2563
|
const { getConfigPath } = await Promise.resolve().then(() => require("./paths-D-QecARF.js"));
|
|
1579
2564
|
const cfgPath = getConfigPath();
|
|
1580
2565
|
let cfg = {};
|
|
1581
2566
|
try {
|
|
1582
|
-
cfg = await fs$
|
|
2567
|
+
cfg = await fs$7.readJson(cfgPath);
|
|
1583
2568
|
} catch {}
|
|
1584
2569
|
const sandboxMode = cfg?.agents?.defaults?.sandbox?.mode ?? "non-main";
|
|
1585
2570
|
const toolsCfg = cfg?.tools ?? {};
|
|
1586
|
-
const { describeToolPolicy, applyToolPolicy } = await Promise.resolve().then(() => require("./tool-policy-
|
|
1587
|
-
const { getBuiltinTools, getSessionsTools, getPCAccessTools, getBrowserTools, getExtractionTools, getWebsiteWatchTools, getVisionTools } = await Promise.resolve().then(() => require("./src-
|
|
2571
|
+
const { describeToolPolicy, applyToolPolicy } = await Promise.resolve().then(() => require("./tool-policy-CNT-mF2Z.js"));
|
|
2572
|
+
const { getBuiltinTools, getSessionsTools, getPCAccessTools, getBrowserTools, getExtractionTools, getWebsiteWatchTools, getVisionTools } = await Promise.resolve().then(() => require("./src-BxPHKO5x.js"));
|
|
1588
2573
|
const allTools = [
|
|
1589
2574
|
...getBuiltinTools(),
|
|
1590
2575
|
...getSessionsTools(() => null),
|
|
@@ -1612,15 +2597,15 @@ sandboxCmd.command("explain").description("Show effective sandbox mode, tool pol
|
|
|
1612
2597
|
}, null, 2));
|
|
1613
2598
|
process.exit(0);
|
|
1614
2599
|
}
|
|
1615
|
-
console.log(chalk$
|
|
2600
|
+
console.log(chalk$11.bold.hex("#06b6d4")("\n 🔒 SANDBOX EXPLAIN\n"));
|
|
1616
2601
|
console.log(` Sandbox mode: ${sandboxMode} (non-main sessions get restricted pcTools)`);
|
|
1617
2602
|
console.log(` Tool profile: ${policy.profile}`);
|
|
1618
2603
|
console.log(` Policy source: ${policy.source}`);
|
|
1619
2604
|
if (policy.allow?.length) console.log(` Allow: ${policy.allow.join(", ")}`);
|
|
1620
2605
|
if (policy.deny?.length) console.log(` Deny: ${policy.deny.join(", ")}`);
|
|
1621
2606
|
console.log(` Tools: ${filtered.length} / ${allTools.length} allowed`);
|
|
1622
|
-
console.log(chalk$
|
|
1623
|
-
console.log(chalk$
|
|
2607
|
+
console.log(chalk$11.gray("\n Allowed: " + filtered.map((t) => t.name).join(", ")));
|
|
2608
|
+
console.log(chalk$11.gray("\n Elevated: " + ((cfg?.tools?.elevated)?.enabled ? "enabled" : "disabled")));
|
|
1624
2609
|
console.log();
|
|
1625
2610
|
process.exit(0);
|
|
1626
2611
|
});
|
|
@@ -1637,6 +2622,14 @@ channelsCmd.command("remove <channel>").description("Remove a channel").action(a
|
|
|
1637
2622
|
await channelsRemove(channel);
|
|
1638
2623
|
process.exit(0);
|
|
1639
2624
|
});
|
|
2625
|
+
channelsCmd.command("login [channel]").description("First-time login / QR pairing for a channel").action(async (channel) => {
|
|
2626
|
+
await channelsLogin(channel);
|
|
2627
|
+
process.exit(0);
|
|
2628
|
+
});
|
|
2629
|
+
channelsCmd.command("status").description("Show channel status (use --probe to test connectivity)").option("--probe", "Probe each channel for real connectivity").action(async (opts) => {
|
|
2630
|
+
await channelsStatus({ probe: !!opts.probe });
|
|
2631
|
+
process.exit(0);
|
|
2632
|
+
});
|
|
1640
2633
|
const hooksCmd = program.command("hooks").description("Hook management");
|
|
1641
2634
|
hooksCmd.command("list").description("List all hooks").option("--eligible", "Show only eligible hooks").action((opts) => {
|
|
1642
2635
|
new require_loader.HookLoader().list(opts.eligible);
|
|
@@ -1672,12 +2665,67 @@ agentsCmd.command("unbind").description("Remove channel ↔ agent bindings").act
|
|
|
1672
2665
|
process.exit(0);
|
|
1673
2666
|
});
|
|
1674
2667
|
const pairingCmd = program.command("pairing").description("DM pairing codes");
|
|
1675
|
-
pairingCmd.command("list").description("List pending
|
|
1676
|
-
new require_pairing.
|
|
2668
|
+
pairingCmd.command("list [channel]").description("List pending DM pairing requests (optionally filter by channel)").action(async (channel) => {
|
|
2669
|
+
await new require_pairing.GlobalPairingManager().showList(channel);
|
|
1677
2670
|
process.exit(0);
|
|
1678
2671
|
});
|
|
1679
|
-
pairingCmd.command("approve <channel> <code>").description("Approve a pairing code and add
|
|
1680
|
-
new require_pairing.
|
|
2672
|
+
pairingCmd.command("approve <channel> <code>").description("Approve a pairing code and add sender to channel allowlist").option("--account <id>", "Account ID for multi-account channels", "default").action(async (channel, code, opts) => {
|
|
2673
|
+
await new require_pairing.GlobalPairingManager().cliApprove(channel, code, opts.account);
|
|
2674
|
+
process.exit(0);
|
|
2675
|
+
});
|
|
2676
|
+
const devicesCmd = program.command("devices").description("Node/device pairing (iOS, Android, macOS, headless)");
|
|
2677
|
+
devicesCmd.command("list").description("List pending and paired devices").action(async () => {
|
|
2678
|
+
await new DevicePairingStore().showCLI();
|
|
2679
|
+
process.exit(0);
|
|
2680
|
+
});
|
|
2681
|
+
devicesCmd.command("pair").description("Create a new device pairing request and print setup code").option("-u, --gateway-url <url>", "Gateway WebSocket URL", "ws://localhost:18789").option("-n, --name <name>", "Device name (optional)").option("-p, --platform <platform>", "Platform hint: ios|android|macos|headless (optional)").action(async (opts) => {
|
|
2682
|
+
const store = new DevicePairingStore();
|
|
2683
|
+
const result = await store.createRequest(opts.gatewayUrl, {
|
|
2684
|
+
deviceName: opts.name,
|
|
2685
|
+
platform: opts.platform
|
|
2686
|
+
});
|
|
2687
|
+
console.log(chalk.default.bold.cyan("\n 📱 DEVICE PAIR REQUEST\n"));
|
|
2688
|
+
console.log(` Request ID: ${chalk.default.bold(result.requestId)}`);
|
|
2689
|
+
console.log(` Expires: ${chalk.default.gray(new Date(result.expiresAt).toLocaleTimeString())}`);
|
|
2690
|
+
console.log();
|
|
2691
|
+
console.log(chalk.default.yellow(" Setup code (send to device or paste in app):"));
|
|
2692
|
+
console.log(chalk.default.bold(`\n ${result.setupCode}\n`));
|
|
2693
|
+
console.log(chalk.default.gray(" Approve: hyperclaw devices approve " + result.requestId));
|
|
2694
|
+
console.log(chalk.default.gray(" Reject: hyperclaw devices reject " + result.requestId));
|
|
2695
|
+
console.log(chalk.default.gray("\n Telegram: message your bot with /pair for guided flow.\n"));
|
|
2696
|
+
process.exit(0);
|
|
2697
|
+
});
|
|
2698
|
+
devicesCmd.command("approve <requestId>").description("Approve a pending device pairing request").action(async (requestId) => {
|
|
2699
|
+
const store = new DevicePairingStore();
|
|
2700
|
+
const device = await store.approve(requestId);
|
|
2701
|
+
if (device) {
|
|
2702
|
+
console.log(chalk.default.green(`\n ✔ Device approved: ${chalk.default.bold(device.deviceId)}`));
|
|
2703
|
+
if (device.deviceName) console.log(chalk.default.gray(` Name: ${device.deviceName}`));
|
|
2704
|
+
console.log(chalk.default.gray(` Paired at: ${device.pairedAt}\n`));
|
|
2705
|
+
} else {
|
|
2706
|
+
console.log(chalk.default.red(`\n ✖ Request not found or expired: ${requestId}\n`));
|
|
2707
|
+
process.exit(1);
|
|
2708
|
+
}
|
|
2709
|
+
process.exit(0);
|
|
2710
|
+
});
|
|
2711
|
+
devicesCmd.command("reject <requestId>").description("Reject a pending device pairing request").action(async (requestId) => {
|
|
2712
|
+
const store = new DevicePairingStore();
|
|
2713
|
+
const ok = await store.reject(requestId);
|
|
2714
|
+
if (ok) console.log(chalk.default.green(`\n ✔ Request rejected: ${requestId}\n`));
|
|
2715
|
+
else {
|
|
2716
|
+
console.log(chalk.default.red(`\n ✖ Request not found: ${requestId}\n`));
|
|
2717
|
+
process.exit(1);
|
|
2718
|
+
}
|
|
2719
|
+
process.exit(0);
|
|
2720
|
+
});
|
|
2721
|
+
devicesCmd.command("unpair <deviceId>").description("Remove a paired device").action(async (deviceId) => {
|
|
2722
|
+
const store = new DevicePairingStore();
|
|
2723
|
+
const ok = await store.unpair(deviceId);
|
|
2724
|
+
if (ok) console.log(chalk.default.green(`\n ✔ Device unpaired: ${deviceId}\n`));
|
|
2725
|
+
else {
|
|
2726
|
+
console.log(chalk.default.red(`\n ✖ Device not found: ${deviceId}\n`));
|
|
2727
|
+
process.exit(1);
|
|
2728
|
+
}
|
|
1681
2729
|
process.exit(0);
|
|
1682
2730
|
});
|
|
1683
2731
|
const msgCmd = program.command("message").description("Send messages");
|
|
@@ -1741,13 +2789,13 @@ skillCmd.command("install <id>").description("Install skill from ClawHub (or bun
|
|
|
1741
2789
|
process.exit(0);
|
|
1742
2790
|
});
|
|
1743
2791
|
program.command("menu-bar").description("Launch macOS menu bar companion (Electron tray app)").action(async () => {
|
|
1744
|
-
const path$
|
|
2792
|
+
const path$7 = await import("path");
|
|
1745
2793
|
const { spawn } = await import("child_process");
|
|
1746
|
-
const fs$
|
|
1747
|
-
const root = path$
|
|
1748
|
-
const altRoot = path$
|
|
1749
|
-
const macosDir = await fs$
|
|
1750
|
-
if (!macosDir || !await fs$
|
|
2794
|
+
const fs$7 = await import("fs-extra");
|
|
2795
|
+
const root = path$7.join(process.cwd(), "apps", "macos");
|
|
2796
|
+
const altRoot = path$7.join(__dirname, "..", "..", "apps", "macos");
|
|
2797
|
+
const macosDir = await fs$7.pathExists(root) ? root : await fs$7.pathExists(altRoot) ? altRoot : null;
|
|
2798
|
+
if (!macosDir || !await fs$7.pathExists(path$7.join(macosDir, "package.json"))) {
|
|
1751
2799
|
console.log(chalk.default.gray("\n macOS menu bar app not found."));
|
|
1752
2800
|
console.log(chalk.default.gray(" Run from HyperClaw repo root, or: cd apps/macos && npm start\n"));
|
|
1753
2801
|
process.exit(1);
|
|
@@ -1774,8 +2822,15 @@ program.command("update").description("Update HyperClaw").option("-c, --channel
|
|
|
1774
2822
|
await performUpdate(effective.channel, installKind);
|
|
1775
2823
|
process.exit(0);
|
|
1776
2824
|
});
|
|
1777
|
-
program.command("doctor").description("Health check — surfaces misconfigs
|
|
1778
|
-
await require_doctor.runDoctor(opts.fix
|
|
2825
|
+
program.command("doctor").description("Health check — surfaces misconfigs, risky DM policies, and repairs").option("--fix", "Auto-repair fixable issues").option("--repair", "Apply recommended repairs (same as --fix)").option("--force", "Apply aggressive repairs (use with --repair)").option("-y, --yes", "Accept defaults without prompting").option("--non-interactive", "Skip prompts; only run safe migrations").option("--deep", "Scan system services for extra gateway installs").action(async (opts) => {
|
|
2826
|
+
await require_doctor.runDoctor(opts.fix || opts.repair, {
|
|
2827
|
+
fix: opts.fix,
|
|
2828
|
+
repair: opts.repair,
|
|
2829
|
+
force: opts.force,
|
|
2830
|
+
yes: opts.yes,
|
|
2831
|
+
nonInteractive: opts.nonInteractive,
|
|
2832
|
+
deep: opts.deep
|
|
2833
|
+
});
|
|
1779
2834
|
process.exit(0);
|
|
1780
2835
|
});
|
|
1781
2836
|
const memCmd = program.command("memory").description("Agent memory management");
|
|
@@ -1857,7 +2912,7 @@ cfgCmd.command("set-service-key <serviceId> [apiKey]").description("Set API key
|
|
|
1857
2912
|
cfgCmd.command("schema").description("Show configuration schema").action(() => {
|
|
1858
2913
|
console.log(chalk.default.bold.hex("#06b6d4")("\n Config schema: ~/.hyperclaw/config.json\n"));
|
|
1859
2914
|
const schema = {
|
|
1860
|
-
version: "string (e.g. \"
|
|
2915
|
+
version: "string (e.g. \"5.0.0\")",
|
|
1861
2916
|
workspaceName: "string",
|
|
1862
2917
|
provider: {
|
|
1863
2918
|
providerId: "string",
|
|
@@ -1950,17 +3005,17 @@ program.command("deploy").description("Deploy gateway to cloud (Fly.io or Render
|
|
|
1950
3005
|
program.command("voice-call").description("Start voice call session — terminal mode, talks to gateway").option("-u, --gateway-url <url>", "Gateway URL", "http://localhost:18789").action(async (opts) => {
|
|
1951
3006
|
const axios = (await import("axios")).default;
|
|
1952
3007
|
const readline$2 = await import("readline");
|
|
1953
|
-
const chalk$
|
|
3008
|
+
const chalk$11 = require("chalk");
|
|
1954
3009
|
const url = opts.gatewayUrl || "http://localhost:18789";
|
|
1955
|
-
console.log(chalk$
|
|
1956
|
-
console.log(chalk$
|
|
1957
|
-
console.log(chalk$
|
|
3010
|
+
console.log(chalk$11.bold.cyan("\n 🎙️ HYPERCLAW VOICE CALL\n"));
|
|
3011
|
+
console.log(chalk$11.gray(` Gateway: ${url}`));
|
|
3012
|
+
console.log(chalk$11.gray(" Type a message and press Enter. Ctrl+C to exit.\n"));
|
|
1958
3013
|
const rl = readline$2.createInterface({
|
|
1959
3014
|
input: process.stdin,
|
|
1960
3015
|
output: process.stdout
|
|
1961
3016
|
});
|
|
1962
3017
|
const ask = () => {
|
|
1963
|
-
rl.question(chalk$
|
|
3018
|
+
rl.question(chalk$11.cyan(" You: "), async (input) => {
|
|
1964
3019
|
if (!input?.trim()) {
|
|
1965
3020
|
ask();
|
|
1966
3021
|
return;
|
|
@@ -1970,9 +3025,9 @@ program.command("voice-call").description("Start voice call session — terminal
|
|
|
1970
3025
|
message: input.trim(),
|
|
1971
3026
|
thinking: "none"
|
|
1972
3027
|
}, { timeout: 6e4 });
|
|
1973
|
-
console.log(chalk$
|
|
3028
|
+
console.log(chalk$11.green(` 🦅 Agent: ${(res.data?.response || "").slice(0, 500)}\n`));
|
|
1974
3029
|
} catch (e) {
|
|
1975
|
-
console.log(chalk$
|
|
3030
|
+
console.log(chalk$11.red(` Error: ${e.response?.data?.error || e.message}\n`));
|
|
1976
3031
|
}
|
|
1977
3032
|
ask();
|
|
1978
3033
|
});
|
|
@@ -1992,13 +3047,102 @@ program.command("dashboard").description("Launch live terminal dashboard").optio
|
|
|
1992
3047
|
await new Dashboard().launch(opts.live);
|
|
1993
3048
|
if (!opts.live) process.exit(0);
|
|
1994
3049
|
});
|
|
1995
|
-
program.command("status").description("System overview").action(async () => {
|
|
3050
|
+
program.command("status").description("System overview").option("--all", "Full local diagnosis (read-only)").option("--deep", "Also probe the running gateway").action(async (opts) => {
|
|
1996
3051
|
await new require_onboard.Banner().showStatus();
|
|
3052
|
+
if (opts.all || opts.deep) {
|
|
3053
|
+
const fs$7 = await import("fs-extra");
|
|
3054
|
+
const { getConfigPath } = await Promise.resolve().then(() => require("./paths-D-QecARF.js"));
|
|
3055
|
+
const t = (await Promise.resolve().then(() => require("./theme-cx0fkgWC.js"))).getTheme(false);
|
|
3056
|
+
const configPath = getConfigPath();
|
|
3057
|
+
console.log(t.bold("\n ─── Deep status ───\n"));
|
|
3058
|
+
try {
|
|
3059
|
+
const cfg = await fs$7.readJson(configPath);
|
|
3060
|
+
console.log(t.muted(" Config: ") + (cfg ? t.success("loaded") : t.error("missing")));
|
|
3061
|
+
console.log(t.muted(" Channels: ") + JSON.stringify(cfg?.gateway?.enabledChannels || cfg?.channels || []));
|
|
3062
|
+
} catch {
|
|
3063
|
+
console.log(t.muted(" Config: ") + t.error("unreadable"));
|
|
3064
|
+
}
|
|
3065
|
+
if (opts.deep) {
|
|
3066
|
+
const http$2 = await import("http");
|
|
3067
|
+
const { resolveGatewayUrl } = await Promise.resolve().then(() => require("./health-B-asI__D.js"));
|
|
3068
|
+
const cfg = await new require_manager.ConfigManager().load();
|
|
3069
|
+
const { gatewayUrl } = resolveGatewayUrl(cfg);
|
|
3070
|
+
const u = new URL(gatewayUrl);
|
|
3071
|
+
const optsReq = {
|
|
3072
|
+
hostname: u.hostname,
|
|
3073
|
+
port: u.port || (u.protocol === "https:" ? 443 : 80),
|
|
3074
|
+
path: "/api/status",
|
|
3075
|
+
method: "GET",
|
|
3076
|
+
timeout: 3e3
|
|
3077
|
+
};
|
|
3078
|
+
if (u.protocol === "https:") {
|
|
3079
|
+
const https = await import("https");
|
|
3080
|
+
await new Promise((resolve) => {
|
|
3081
|
+
const req = https.request(`${gatewayUrl}/api/status`, { timeout: 3e3 }, (res) => {
|
|
3082
|
+
let d = "";
|
|
3083
|
+
res.on("data", (c) => d += c);
|
|
3084
|
+
res.on("end", () => {
|
|
3085
|
+
try {
|
|
3086
|
+
const j = JSON.parse(d);
|
|
3087
|
+
console.log(t.muted(" Gateway: ") + t.success("reachable") + ` (sessions: ${j.sessions ?? "-"}, uptime: ${j.uptime ?? "-"})`);
|
|
3088
|
+
} catch {
|
|
3089
|
+
console.log(t.muted(" Gateway: ") + t.error("unreachable or invalid response"));
|
|
3090
|
+
}
|
|
3091
|
+
resolve();
|
|
3092
|
+
});
|
|
3093
|
+
});
|
|
3094
|
+
req.on("error", () => {
|
|
3095
|
+
console.log(t.muted(" Gateway: ") + t.error("unreachable"));
|
|
3096
|
+
resolve();
|
|
3097
|
+
});
|
|
3098
|
+
req.on("timeout", () => {
|
|
3099
|
+
req.destroy();
|
|
3100
|
+
console.log(t.muted(" Gateway: ") + t.error("timeout"));
|
|
3101
|
+
resolve();
|
|
3102
|
+
});
|
|
3103
|
+
req.end();
|
|
3104
|
+
});
|
|
3105
|
+
} else await new Promise((resolve) => {
|
|
3106
|
+
const req = http$2.request(optsReq, (res) => {
|
|
3107
|
+
let d = "";
|
|
3108
|
+
res.on("data", (c) => d += c);
|
|
3109
|
+
res.on("end", () => {
|
|
3110
|
+
try {
|
|
3111
|
+
const j = JSON.parse(d);
|
|
3112
|
+
console.log(t.muted(" Gateway: ") + t.success("reachable") + ` (sessions: ${j.sessions ?? "-"}, uptime: ${j.uptime ?? "-"})`);
|
|
3113
|
+
} catch {
|
|
3114
|
+
console.log(t.muted(" Gateway: ") + t.error("unreachable or invalid response"));
|
|
3115
|
+
}
|
|
3116
|
+
resolve();
|
|
3117
|
+
});
|
|
3118
|
+
});
|
|
3119
|
+
req.on("error", () => {
|
|
3120
|
+
console.log(t.muted(" Gateway: ") + t.error("unreachable"));
|
|
3121
|
+
resolve();
|
|
3122
|
+
});
|
|
3123
|
+
req.on("timeout", () => {
|
|
3124
|
+
req.destroy();
|
|
3125
|
+
console.log(t.muted(" Gateway: ") + t.error("timeout"));
|
|
3126
|
+
resolve();
|
|
3127
|
+
});
|
|
3128
|
+
req.end();
|
|
3129
|
+
});
|
|
3130
|
+
}
|
|
3131
|
+
console.log();
|
|
3132
|
+
}
|
|
1997
3133
|
process.exit(0);
|
|
1998
3134
|
});
|
|
3135
|
+
program.command("health").description("Quick gateway health probe (Runtime, RPC probe, channel count)").option("--json", "Output raw JSON").option("-v, --verbose", "Show state dir, config path, and env overrides").action(async (opts) => {
|
|
3136
|
+
const result = await require_health.runHealth({
|
|
3137
|
+
json: opts.json,
|
|
3138
|
+
verbose: opts.verbose
|
|
3139
|
+
});
|
|
3140
|
+
if (!result.allOk) process.exitCode = 1;
|
|
3141
|
+
process.exit(process.exitCode ?? 0);
|
|
3142
|
+
});
|
|
1999
3143
|
const themeCmd = program.command("theme").description("Switch CLI color theme");
|
|
2000
3144
|
themeCmd.command("list").description("List available themes").action(async () => {
|
|
2001
|
-
const { allThemes, getThemeName } = await Promise.resolve().then(() => require("./theme-
|
|
3145
|
+
const { allThemes, getThemeName } = await Promise.resolve().then(() => require("./theme-cx0fkgWC.js"));
|
|
2002
3146
|
const current = getThemeName();
|
|
2003
3147
|
console.log(chalk.default.bold.hex("#06b6d4")("\n 🎨 AVAILABLE THEMES\n"));
|
|
2004
3148
|
for (const { name, label } of allThemes()) {
|
|
@@ -2010,7 +3154,7 @@ themeCmd.command("list").description("List available themes").action(async () =>
|
|
|
2010
3154
|
process.exit(0);
|
|
2011
3155
|
});
|
|
2012
3156
|
themeCmd.command("set <theme>").description("Set theme: dark | grey | white").action(async (name) => {
|
|
2013
|
-
const { setThemeName, allThemes } = await Promise.resolve().then(() => require("./theme-
|
|
3157
|
+
const { setThemeName, allThemes } = await Promise.resolve().then(() => require("./theme-cx0fkgWC.js"));
|
|
2014
3158
|
const valid = allThemes().map((t) => t.name);
|
|
2015
3159
|
if (!valid.includes(name)) {
|
|
2016
3160
|
console.log(chalk.default.red(`\n ✖ Unknown theme: "${name}". Use: ${valid.join(" | ")}\n`));
|
|
@@ -2022,7 +3166,7 @@ themeCmd.command("set <theme>").description("Set theme: dark | grey | white").ac
|
|
|
2022
3166
|
process.exit(0);
|
|
2023
3167
|
});
|
|
2024
3168
|
themeCmd.command("preview").description("Preview all themes side-by-side").action(async () => {
|
|
2025
|
-
const { allThemes, getTheme, setThemeName, getThemeName } = await Promise.resolve().then(() => require("./theme-
|
|
3169
|
+
const { allThemes, getTheme, setThemeName, getThemeName } = await Promise.resolve().then(() => require("./theme-cx0fkgWC.js"));
|
|
2026
3170
|
const current = getThemeName();
|
|
2027
3171
|
console.log(chalk.default.bold("\n 🎨 THEME PREVIEW\n"));
|
|
2028
3172
|
for (const { name, label } of allThemes()) {
|
|
@@ -2039,45 +3183,49 @@ themeCmd.command("preview").description("Preview all themes side-by-side").actio
|
|
|
2039
3183
|
});
|
|
2040
3184
|
const secretsCmd = program.command("secrets").description("External secrets management");
|
|
2041
3185
|
secretsCmd.command("audit").description("Audit all required secrets").option("--required-by <ids>", "Filter by skill/provider IDs (comma-separated)").action(async (opts) => {
|
|
2042
|
-
const { SecretsManager } = await Promise.resolve().then(() => require("./manager-
|
|
3186
|
+
const { SecretsManager } = await Promise.resolve().then(() => require("./manager-FCgF1plu.js"));
|
|
2043
3187
|
const filter = opts.requiredBy?.split(",");
|
|
2044
3188
|
await new SecretsManager().audit(filter);
|
|
2045
3189
|
process.exit(0);
|
|
2046
3190
|
});
|
|
2047
3191
|
secretsCmd.command("set <KEY=value>").description("Set a secret in .env file").action(async (kv) => {
|
|
2048
|
-
const { SecretsManager } = await Promise.resolve().then(() => require("./manager-
|
|
3192
|
+
const { SecretsManager } = await Promise.resolve().then(() => require("./manager-FCgF1plu.js"));
|
|
2049
3193
|
await new SecretsManager().set(kv);
|
|
2050
3194
|
process.exit(0);
|
|
2051
3195
|
});
|
|
2052
3196
|
secretsCmd.command("apply").description("Write secrets from .env to shell config (~/.bashrc, ~/.zshrc)").action(async () => {
|
|
2053
|
-
const { SecretsManager } = await Promise.resolve().then(() => require("./manager-
|
|
3197
|
+
const { SecretsManager } = await Promise.resolve().then(() => require("./manager-FCgF1plu.js"));
|
|
2054
3198
|
await new SecretsManager().apply();
|
|
2055
3199
|
process.exit(0);
|
|
2056
3200
|
});
|
|
2057
3201
|
secretsCmd.command("reload").description("Reload secrets into running gateway").action(async () => {
|
|
2058
|
-
const { SecretsManager } = await Promise.resolve().then(() => require("./manager-
|
|
3202
|
+
const { SecretsManager } = await Promise.resolve().then(() => require("./manager-FCgF1plu.js"));
|
|
2059
3203
|
await new SecretsManager().reload();
|
|
2060
3204
|
process.exit(0);
|
|
2061
3205
|
});
|
|
2062
3206
|
secretsCmd.command("remove <key>").description("Remove a secret from .env").action(async (key) => {
|
|
2063
|
-
const { SecretsManager } = await Promise.resolve().then(() => require("./manager-
|
|
3207
|
+
const { SecretsManager } = await Promise.resolve().then(() => require("./manager-FCgF1plu.js"));
|
|
2064
3208
|
await new SecretsManager().remove(key);
|
|
2065
3209
|
process.exit(0);
|
|
2066
3210
|
});
|
|
2067
3211
|
secretsCmd.command("credentials").description("List provider credential files (credentials/*.json)").action(async () => {
|
|
2068
|
-
const { CredentialsStore } = await Promise.resolve().then(() => require("./credentials-store-
|
|
3212
|
+
const { CredentialsStore } = await Promise.resolve().then(() => require("./credentials-store-C6ir0Dae.js"));
|
|
2069
3213
|
await new CredentialsStore().showList();
|
|
2070
3214
|
process.exit(0);
|
|
2071
3215
|
});
|
|
2072
3216
|
const securityCmd = program.command("security").description("Security tools");
|
|
2073
|
-
securityCmd.command("audit").description("Security audit — file permissions, DM policies, embedded secrets").option("--deep", "Full deep scan including token entropy and installed skill risks").action(async (opts) => {
|
|
2074
|
-
const { runSecurityAudit } = await Promise.resolve().then(() => require("./audit-
|
|
2075
|
-
await runSecurityAudit(
|
|
3217
|
+
securityCmd.command("audit").description("Security audit — file permissions, DM policies, embedded secrets").option("--deep", "Full deep scan including token entropy and installed skill risks").option("--fix", "Auto-fix safe findings (file permissions etc.)").option("--json", "Machine-readable JSON output").action(async (opts) => {
|
|
3218
|
+
const { runSecurityAudit } = await Promise.resolve().then(() => require("./audit-BaIiyWFu.js"));
|
|
3219
|
+
await runSecurityAudit({
|
|
3220
|
+
deep: opts.deep,
|
|
3221
|
+
fix: opts.fix,
|
|
3222
|
+
json: opts.json
|
|
3223
|
+
});
|
|
2076
3224
|
process.exit(0);
|
|
2077
3225
|
});
|
|
2078
3226
|
const agentRunCmd = program.command("agent").description("Run agent with thinking control");
|
|
2079
3227
|
agentRunCmd.requiredOption("-m, --message <text>", "Message to send to the agent").option("--thinking <level>", "Thinking level: high|medium|low|none", "none").option("--model <model>", "Override model").option("--session <id>", "Session/thread ID").option("--multi-step", "Decompose into steps and run each (sequential)").option("--parallel", "Run sub-agents in parallel for independent subtasks").option("--verbose", "Show thinking blocks and request details").option("--workspace <dir>", "Override workspace directory").action(async (opts) => {
|
|
2080
|
-
const { runAgent } = await Promise.resolve().then(() => require("./src-
|
|
3228
|
+
const { runAgent } = await Promise.resolve().then(() => require("./src-BxPHKO5x.js"));
|
|
2081
3229
|
await runAgent({
|
|
2082
3230
|
message: opts.message,
|
|
2083
3231
|
thinking: opts.thinking,
|
|
@@ -2093,7 +3241,7 @@ agentRunCmd.requiredOption("-m, --message <text>", "Message to send to the agent
|
|
|
2093
3241
|
});
|
|
2094
3242
|
const threadsCmd = program.command("threads").description("ACP thread-bound agent sessions");
|
|
2095
3243
|
threadsCmd.command("list").description("List agent threads").option("--channel <id>", "Filter by channel").option("--active", "Show only active threads").action(async (opts) => {
|
|
2096
|
-
const { ACPThreadManager } = await Promise.resolve().then(() => require("./src-
|
|
3244
|
+
const { ACPThreadManager } = await Promise.resolve().then(() => require("./src-BxPHKO5x.js"));
|
|
2097
3245
|
const mgr = new ACPThreadManager();
|
|
2098
3246
|
const threads = await mgr.list({
|
|
2099
3247
|
channelId: opts.channel,
|
|
@@ -2103,33 +3251,33 @@ threadsCmd.command("list").description("List agent threads").option("--channel <
|
|
|
2103
3251
|
process.exit(0);
|
|
2104
3252
|
});
|
|
2105
3253
|
threadsCmd.command("terminate <id>").description("Terminate a thread").action(async (id) => {
|
|
2106
|
-
const { ACPThreadManager } = await Promise.resolve().then(() => require("./src-
|
|
3254
|
+
const { ACPThreadManager } = await Promise.resolve().then(() => require("./src-BxPHKO5x.js"));
|
|
2107
3255
|
await new ACPThreadManager().terminate(id);
|
|
2108
3256
|
console.log(require("chalk").green(`\n ✔ Thread terminated: ${id}\n`));
|
|
2109
3257
|
process.exit(0);
|
|
2110
3258
|
});
|
|
2111
3259
|
const canvasCmd = program.command("canvas").description("Live AI-driven UI canvas");
|
|
2112
3260
|
canvasCmd.command("show").description("Show current canvas components").action(async () => {
|
|
2113
|
-
const { CanvasRenderer } = await Promise.resolve().then(() => require("./renderer-
|
|
3261
|
+
const { CanvasRenderer } = await Promise.resolve().then(() => require("./renderer-BVQrd0_g.js"));
|
|
2114
3262
|
await new CanvasRenderer().show();
|
|
2115
3263
|
process.exit(0);
|
|
2116
3264
|
});
|
|
2117
3265
|
canvasCmd.command("add <type> <title>").description("Add a canvas component (type: chart|table|form|markdown|image|custom)").action(async (type, title) => {
|
|
2118
|
-
const { CanvasRenderer } = await Promise.resolve().then(() => require("./renderer-
|
|
3266
|
+
const { CanvasRenderer } = await Promise.resolve().then(() => require("./renderer-BVQrd0_g.js"));
|
|
2119
3267
|
await new CanvasRenderer().addComponent(type, title);
|
|
2120
3268
|
process.exit(0);
|
|
2121
3269
|
});
|
|
2122
3270
|
canvasCmd.command("clear").description("Clear all canvas components").action(async () => {
|
|
2123
|
-
const { CanvasRenderer } = await Promise.resolve().then(() => require("./renderer-
|
|
3271
|
+
const { CanvasRenderer } = await Promise.resolve().then(() => require("./renderer-BVQrd0_g.js"));
|
|
2124
3272
|
await new CanvasRenderer().clear();
|
|
2125
3273
|
process.exit(0);
|
|
2126
3274
|
});
|
|
2127
3275
|
canvasCmd.command("export").description("Export canvas as HTML file").action(async () => {
|
|
2128
|
-
const { CanvasRenderer } = await Promise.resolve().then(() => require("./renderer-
|
|
2129
|
-
const fs$
|
|
3276
|
+
const { CanvasRenderer } = await Promise.resolve().then(() => require("./renderer-BVQrd0_g.js"));
|
|
3277
|
+
const fs$7 = require("fs-extra");
|
|
2130
3278
|
const html = await new CanvasRenderer().exportHtml();
|
|
2131
3279
|
const outFile = require("path").join(require("os").homedir(), ".hyperclaw", "canvas", "export.html");
|
|
2132
|
-
await fs$
|
|
3280
|
+
await fs$7.writeFile(outFile, html);
|
|
2133
3281
|
console.log(require("chalk").green(`\n ✔ Canvas exported to ${outFile}\n`));
|
|
2134
3282
|
process.exit(0);
|
|
2135
3283
|
});
|
|
@@ -2146,167 +3294,167 @@ deliveryCmd.command("retry <id>").description("Retry a dead-lettered delivery it
|
|
|
2146
3294
|
});
|
|
2147
3295
|
const mcpCmd = program.command("mcp").description("MCP (Model Context Protocol) server management");
|
|
2148
3296
|
mcpCmd.command("list").action(async () => {
|
|
2149
|
-
const { mcpList } = await Promise.resolve().then(() => require("./mcp-
|
|
3297
|
+
const { mcpList } = await Promise.resolve().then(() => require("./mcp-CfoSU4Uz.js"));
|
|
2150
3298
|
await mcpList();
|
|
2151
3299
|
process.exit(0);
|
|
2152
3300
|
});
|
|
2153
3301
|
mcpCmd.command("add").action(async () => {
|
|
2154
|
-
const { mcpAdd } = await Promise.resolve().then(() => require("./mcp-
|
|
3302
|
+
const { mcpAdd } = await Promise.resolve().then(() => require("./mcp-CfoSU4Uz.js"));
|
|
2155
3303
|
await mcpAdd();
|
|
2156
3304
|
process.exit(0);
|
|
2157
3305
|
});
|
|
2158
3306
|
mcpCmd.command("remove <id>").action(async (id) => {
|
|
2159
|
-
const { mcpRemove } = await Promise.resolve().then(() => require("./mcp-
|
|
3307
|
+
const { mcpRemove } = await Promise.resolve().then(() => require("./mcp-CfoSU4Uz.js"));
|
|
2160
3308
|
await mcpRemove(id);
|
|
2161
3309
|
process.exit(0);
|
|
2162
3310
|
});
|
|
2163
3311
|
mcpCmd.command("probe [id]").action(async (id) => {
|
|
2164
|
-
const { mcpProbe } = await Promise.resolve().then(() => require("./mcp-
|
|
3312
|
+
const { mcpProbe } = await Promise.resolve().then(() => require("./mcp-CfoSU4Uz.js"));
|
|
2165
3313
|
await mcpProbe(id);
|
|
2166
3314
|
process.exit(0);
|
|
2167
3315
|
});
|
|
2168
3316
|
const nodeCmd = program.command("node").description("HyperClaw node management (local, remote, android)");
|
|
2169
3317
|
nodeCmd.command("list").action(async () => {
|
|
2170
|
-
const { nodeList } = await Promise.resolve().then(() => require("./node-
|
|
3318
|
+
const { nodeList } = await Promise.resolve().then(() => require("./node-Dw2Gi-cP.js"));
|
|
2171
3319
|
await nodeList();
|
|
2172
3320
|
process.exit(0);
|
|
2173
3321
|
});
|
|
2174
3322
|
nodeCmd.command("add").action(async () => {
|
|
2175
|
-
const { nodeAdd } = await Promise.resolve().then(() => require("./node-
|
|
3323
|
+
const { nodeAdd } = await Promise.resolve().then(() => require("./node-Dw2Gi-cP.js"));
|
|
2176
3324
|
await nodeAdd();
|
|
2177
3325
|
process.exit(0);
|
|
2178
3326
|
});
|
|
2179
3327
|
nodeCmd.command("probe [id]").action(async (id) => {
|
|
2180
|
-
const { nodeProbe } = await Promise.resolve().then(() => require("./node-
|
|
3328
|
+
const { nodeProbe } = await Promise.resolve().then(() => require("./node-Dw2Gi-cP.js"));
|
|
2181
3329
|
await nodeProbe(id);
|
|
2182
3330
|
process.exit(0);
|
|
2183
3331
|
});
|
|
2184
3332
|
nodeCmd.command("remove <id>").action(async (id) => {
|
|
2185
|
-
const { nodeRemove } = await Promise.resolve().then(() => require("./node-
|
|
3333
|
+
const { nodeRemove } = await Promise.resolve().then(() => require("./node-Dw2Gi-cP.js"));
|
|
2186
3334
|
await nodeRemove(id);
|
|
2187
3335
|
process.exit(0);
|
|
2188
3336
|
});
|
|
2189
3337
|
const arCmd = program.command("auto-reply").description("Auto-reply rule engine");
|
|
2190
3338
|
arCmd.command("list").action(async () => {
|
|
2191
|
-
const { AutoReplyEngine } = await Promise.resolve().then(() => require("./rules-
|
|
3339
|
+
const { AutoReplyEngine } = await Promise.resolve().then(() => require("./rules-BE4GV6cV.js"));
|
|
2192
3340
|
const e = new AutoReplyEngine();
|
|
2193
3341
|
await e.load();
|
|
2194
3342
|
e.showList();
|
|
2195
3343
|
process.exit(0);
|
|
2196
3344
|
});
|
|
2197
3345
|
arCmd.command("toggle <id>").action(async (id) => {
|
|
2198
|
-
const { AutoReplyEngine } = await Promise.resolve().then(() => require("./rules-
|
|
3346
|
+
const { AutoReplyEngine } = await Promise.resolve().then(() => require("./rules-BE4GV6cV.js"));
|
|
2199
3347
|
const e = new AutoReplyEngine();
|
|
2200
3348
|
await e.toggle(id);
|
|
2201
3349
|
process.exit(0);
|
|
2202
3350
|
});
|
|
2203
3351
|
arCmd.command("remove <id>").action(async (id) => {
|
|
2204
|
-
const { AutoReplyEngine } = await Promise.resolve().then(() => require("./rules-
|
|
3352
|
+
const { AutoReplyEngine } = await Promise.resolve().then(() => require("./rules-BE4GV6cV.js"));
|
|
2205
3353
|
const e = new AutoReplyEngine();
|
|
2206
3354
|
await e.remove(id);
|
|
2207
3355
|
process.exit(0);
|
|
2208
3356
|
});
|
|
2209
3357
|
const gmailCmd = program.command("gmail").description("Gmail Pub/Sub real-time notifications");
|
|
2210
3358
|
gmailCmd.command("watch-setup").description("Register Gmail watch for push notifications. Requires: hyperclaw auth oauth google-gmail").requiredOption("-t, --topic <name>", "Pub/Sub topic (e.g. projects/myproject/topics/gmail-push)").option("-l, --labels <ids>", "Label IDs to watch (comma-separated)", "INBOX").action(async (opts) => {
|
|
2211
|
-
const chalk$
|
|
3359
|
+
const chalk$11 = require("chalk");
|
|
2212
3360
|
try {
|
|
2213
|
-
const { setupGmailWatch } = await Promise.resolve().then(() => require("./gmail-watch-setup-
|
|
3361
|
+
const { setupGmailWatch } = await Promise.resolve().then(() => require("./gmail-watch-setup-Du7DVV7S.js"));
|
|
2214
3362
|
const labelIds = opts.labels.split(",").map((s) => s.trim()).filter(Boolean);
|
|
2215
3363
|
const result = await setupGmailWatch({
|
|
2216
3364
|
topicName: opts.topic,
|
|
2217
3365
|
labelIds
|
|
2218
3366
|
});
|
|
2219
|
-
console.log(chalk$
|
|
2220
|
-
console.log(chalk$
|
|
2221
|
-
console.log(chalk$
|
|
2222
|
-
console.log(chalk$
|
|
2223
|
-
console.log(chalk$
|
|
3367
|
+
console.log(chalk$11.hex("#06b6d4")("\n ✔ Gmail watch registered"));
|
|
3368
|
+
console.log(chalk$11.gray(` historyId: ${result.historyId}`));
|
|
3369
|
+
console.log(chalk$11.gray(` expiration: ${new Date(parseInt(result.expiration, 10)).toISOString()}`));
|
|
3370
|
+
console.log(chalk$11.gray("\n Push endpoint: https://<your-server>/webhook/gmail-pubsub"));
|
|
3371
|
+
console.log(chalk$11.gray(" Ensure email channel is enabled and gateway is publicly accessible.\n"));
|
|
2224
3372
|
} catch (e) {
|
|
2225
|
-
console.error(chalk$
|
|
3373
|
+
console.error(chalk$11.red("\n ✖ " + e.message + "\n"));
|
|
2226
3374
|
process.exit(1);
|
|
2227
3375
|
}
|
|
2228
3376
|
process.exit(0);
|
|
2229
3377
|
});
|
|
2230
3378
|
const cronCmd = program.command("cron").description("Scheduled tasks (cron → agent prompt)");
|
|
2231
3379
|
cronCmd.command("list").action(async () => {
|
|
2232
|
-
const chalk$
|
|
2233
|
-
const { loadCronTasks } = await Promise.resolve().then(() => require("./cron-tasks-
|
|
3380
|
+
const chalk$11 = require("chalk");
|
|
3381
|
+
const { loadCronTasks } = await Promise.resolve().then(() => require("./cron-tasks-Bli7Kzd2.js"));
|
|
2234
3382
|
const tasks = await loadCronTasks();
|
|
2235
|
-
console.log(chalk$
|
|
3383
|
+
console.log(chalk$11.bold.cyan("\n ⏰ CRON TASKS\n"));
|
|
2236
3384
|
if (tasks.length === 0) {
|
|
2237
|
-
console.log(chalk$
|
|
3385
|
+
console.log(chalk$11.gray(" No tasks. Add: hyperclaw cron add \"0 9 * * 1-5\" \"Check calendar\"\n"));
|
|
2238
3386
|
process.exit(0);
|
|
2239
3387
|
return;
|
|
2240
3388
|
}
|
|
2241
3389
|
for (const t of tasks) {
|
|
2242
|
-
const dot = t.enabled ? chalk$
|
|
2243
|
-
console.log(` ${dot} ${chalk$
|
|
2244
|
-
console.log(` ${chalk$
|
|
2245
|
-
console.log(` ${chalk$
|
|
2246
|
-
if (t.lastRunAt) console.log(` ${chalk$
|
|
3390
|
+
const dot = t.enabled ? chalk$11.green("●") : chalk$11.gray("○");
|
|
3391
|
+
console.log(` ${dot} ${chalk$11.white(t.name || t.id)}`);
|
|
3392
|
+
console.log(` ${chalk$11.gray("Schedule:")} ${t.schedule}`);
|
|
3393
|
+
console.log(` ${chalk$11.gray("Prompt:")} ${t.prompt.slice(0, 60)}${t.prompt.length > 60 ? "..." : ""}`);
|
|
3394
|
+
if (t.lastRunAt) console.log(` ${chalk$11.gray("Last run:")} ${t.lastRunAt}`);
|
|
2247
3395
|
console.log();
|
|
2248
3396
|
}
|
|
2249
3397
|
process.exit(0);
|
|
2250
3398
|
});
|
|
2251
3399
|
cronCmd.command("add").arguments("<schedule> <prompt>").option("-n, --name <name>", "Task name").action(async (schedule, prompt, opts) => {
|
|
2252
|
-
const chalk$
|
|
2253
|
-
const { loadCronTasks, addCronTask, saveCronTasks } = await Promise.resolve().then(() => require("./cron-tasks-
|
|
3400
|
+
const chalk$11 = require("chalk");
|
|
3401
|
+
const { loadCronTasks, addCronTask, saveCronTasks } = await Promise.resolve().then(() => require("./cron-tasks-Bli7Kzd2.js"));
|
|
2254
3402
|
await loadCronTasks();
|
|
2255
3403
|
addCronTask(schedule, prompt, opts.name);
|
|
2256
3404
|
await saveCronTasks();
|
|
2257
|
-
console.log(chalk$
|
|
2258
|
-
console.log(chalk$
|
|
3405
|
+
console.log(chalk$11.green(`\n ✔ Cron task added: ${schedule} → "${prompt.slice(0, 40)}..."\n`));
|
|
3406
|
+
console.log(chalk$11.gray(" Restart gateway to apply.\n"));
|
|
2259
3407
|
process.exit(0);
|
|
2260
3408
|
});
|
|
2261
3409
|
cronCmd.command("remove <id>").action(async (id) => {
|
|
2262
|
-
const chalk$
|
|
2263
|
-
const { loadCronTasks, removeCronTask, saveCronTasks } = await Promise.resolve().then(() => require("./cron-tasks-
|
|
3410
|
+
const chalk$11 = require("chalk");
|
|
3411
|
+
const { loadCronTasks, removeCronTask, saveCronTasks } = await Promise.resolve().then(() => require("./cron-tasks-Bli7Kzd2.js"));
|
|
2264
3412
|
await loadCronTasks();
|
|
2265
3413
|
if (removeCronTask(id)) {
|
|
2266
3414
|
await saveCronTasks();
|
|
2267
|
-
console.log(chalk$
|
|
2268
|
-
} else console.log(chalk$
|
|
3415
|
+
console.log(chalk$11.green(`\n ✔ Task removed\n`));
|
|
3416
|
+
} else console.log(chalk$11.red(`\n ✖ Task not found: ${id}\n`));
|
|
2269
3417
|
process.exit(0);
|
|
2270
3418
|
});
|
|
2271
3419
|
program.command("nodes").description("List connected mobile nodes (iOS/Android Connect tab)").action(async () => {
|
|
2272
|
-
const chalk$
|
|
2273
|
-
const http = await import("http");
|
|
2274
|
-
const fs$
|
|
2275
|
-
const path$
|
|
2276
|
-
const os$
|
|
3420
|
+
const chalk$11 = require("chalk");
|
|
3421
|
+
const http$2 = await import("http");
|
|
3422
|
+
const fs$7 = await import("fs-extra");
|
|
3423
|
+
const path$7 = await import("path");
|
|
3424
|
+
const os$8 = await import("os");
|
|
2277
3425
|
let port = 18789;
|
|
2278
3426
|
try {
|
|
2279
|
-
const cfg = await fs$
|
|
3427
|
+
const cfg = await fs$7.readJson(path$7.join(os$8.homedir(), ".hyperclaw", "hyperclaw.json"));
|
|
2280
3428
|
port = cfg?.gateway?.port ?? 18789;
|
|
2281
3429
|
} catch {}
|
|
2282
3430
|
return new Promise((resolve, reject) => {
|
|
2283
|
-
const req = http.get(`http://127.0.0.1:${port}/api/nodes`, (res) => {
|
|
3431
|
+
const req = http$2.get(`http://127.0.0.1:${port}/api/nodes`, (res) => {
|
|
2284
3432
|
let data = "";
|
|
2285
3433
|
res.on("data", (c) => data += c);
|
|
2286
3434
|
res.on("end", () => {
|
|
2287
3435
|
try {
|
|
2288
3436
|
const j = JSON.parse(data);
|
|
2289
3437
|
const nodes = j.nodes || [];
|
|
2290
|
-
console.log(chalk$
|
|
3438
|
+
console.log(chalk$11.bold.cyan("\n 📱 CONNECTED NODES\n"));
|
|
2291
3439
|
if (nodes.length === 0) {
|
|
2292
|
-
console.log(chalk$
|
|
2293
|
-
console.log(chalk$
|
|
3440
|
+
console.log(chalk$11.gray(" No mobile nodes. Open iOS/Android app → Connect tab → pair with gateway."));
|
|
3441
|
+
console.log(chalk$11.gray(` Gateway: ws://localhost:${port}\n`));
|
|
2294
3442
|
} else {
|
|
2295
3443
|
for (const n of nodes) {
|
|
2296
|
-
console.log(` ${chalk$
|
|
2297
|
-
console.log(` ${chalk$
|
|
2298
|
-
console.log(` ${chalk$
|
|
3444
|
+
console.log(` ${chalk$11.green("●")} ${n.nodeId} ${chalk$11.gray(`(${n.platform || "?"})`)}`);
|
|
3445
|
+
console.log(` ${chalk$11.gray("Device:")} ${n.deviceName || "—"}`);
|
|
3446
|
+
console.log(` ${chalk$11.gray("Capabilities:")} ${Object.entries(n.capabilities || {}).filter(([, v]) => v).map(([k]) => k).join(", ") || "—"}`);
|
|
2299
3447
|
}
|
|
2300
3448
|
console.log();
|
|
2301
3449
|
}
|
|
2302
3450
|
} catch {
|
|
2303
|
-
console.log(chalk$
|
|
3451
|
+
console.log(chalk$11.red(" Could not reach gateway. Start with: hyperclaw daemon start\n"));
|
|
2304
3452
|
}
|
|
2305
3453
|
resolve();
|
|
2306
3454
|
});
|
|
2307
3455
|
});
|
|
2308
3456
|
req.on("error", () => {
|
|
2309
|
-
console.log(chalk$
|
|
3457
|
+
console.log(chalk$11.red(" Gateway offline. Start with: hyperclaw daemon start\n"));
|
|
2310
3458
|
resolve();
|
|
2311
3459
|
});
|
|
2312
3460
|
req.setTimeout(3e3, () => {
|
|
@@ -2317,20 +3465,20 @@ program.command("nodes").description("List connected mobile nodes (iOS/Android C
|
|
|
2317
3465
|
});
|
|
2318
3466
|
const whCmd = program.command("webhooks").description("Webhook endpoint management");
|
|
2319
3467
|
whCmd.command("list").action(async () => {
|
|
2320
|
-
const { WebhookManager } = await Promise.resolve().then(() => require("./manager-
|
|
3468
|
+
const { WebhookManager } = await Promise.resolve().then(() => require("./manager-BpDfbDjg.js"));
|
|
2321
3469
|
const m = new WebhookManager();
|
|
2322
3470
|
await m.load();
|
|
2323
3471
|
m.showList();
|
|
2324
3472
|
process.exit(0);
|
|
2325
3473
|
});
|
|
2326
3474
|
whCmd.command("remove <id>").action(async (id) => {
|
|
2327
|
-
const { WebhookManager } = await Promise.resolve().then(() => require("./manager-
|
|
3475
|
+
const { WebhookManager } = await Promise.resolve().then(() => require("./manager-BpDfbDjg.js"));
|
|
2328
3476
|
const m = new WebhookManager();
|
|
2329
3477
|
await m.remove(id);
|
|
2330
3478
|
process.exit(0);
|
|
2331
3479
|
});
|
|
2332
3480
|
whCmd.command("toggle <id>").action(async (id) => {
|
|
2333
|
-
const { WebhookManager } = await Promise.resolve().then(() => require("./manager-
|
|
3481
|
+
const { WebhookManager } = await Promise.resolve().then(() => require("./manager-BpDfbDjg.js"));
|
|
2334
3482
|
const m = new WebhookManager();
|
|
2335
3483
|
await m.toggle(id);
|
|
2336
3484
|
process.exit(0);
|
|
@@ -2339,7 +3487,7 @@ const logsCmd = program.command("logs").description("View gateway logs");
|
|
|
2339
3487
|
logsCmd.option("-n, --lines <n>", "Number of lines to show", "50");
|
|
2340
3488
|
logsCmd.option("-f, --follow", "Stream logs in real time");
|
|
2341
3489
|
logsCmd.action(async (opts) => {
|
|
2342
|
-
const { tailLog, streamLog } = await Promise.resolve().then(() => require("./logger-
|
|
3490
|
+
const { tailLog, streamLog } = await Promise.resolve().then(() => require("./logger-ybOp7VOC.js"));
|
|
2343
3491
|
if (opts.follow) await streamLog();
|
|
2344
3492
|
else {
|
|
2345
3493
|
await tailLog(parseInt(opts.lines));
|
|
@@ -2347,7 +3495,7 @@ logsCmd.action(async (opts) => {
|
|
|
2347
3495
|
}
|
|
2348
3496
|
});
|
|
2349
3497
|
program.command("gateway:serve").description("Start the gateway server in the foreground (used by daemon)").action(async () => {
|
|
2350
|
-
const { startGateway } = await Promise.resolve().then(() => require("./server-
|
|
3498
|
+
const { startGateway } = await Promise.resolve().then(() => require("./server-D4wVHiX9.js"));
|
|
2351
3499
|
await startGateway();
|
|
2352
3500
|
process.on("SIGINT", () => process.exit(0));
|
|
2353
3501
|
process.on("SIGTERM", () => process.exit(0));
|
|
@@ -2355,15 +3503,15 @@ program.command("gateway:serve").description("Start the gateway server in the fo
|
|
|
2355
3503
|
});
|
|
2356
3504
|
const gatewayCfgCmd = gatewayCmd.command("config").description("Configure gateway settings");
|
|
2357
3505
|
gatewayCfgCmd.option("--set-token <token>", "Set gateway auth token").option("--regenerate-token", "Generate a new random token").option("--set-port <port>", "Set gateway port").option("--set-bind <addr>", "Set gateway bind address").action(async (opts) => {
|
|
2358
|
-
const chalk$
|
|
2359
|
-
const fs$
|
|
2360
|
-
const path$
|
|
2361
|
-
const os$
|
|
2362
|
-
const crypto = require("crypto");
|
|
2363
|
-
const cfgFile = path$
|
|
3506
|
+
const chalk$11 = require("chalk");
|
|
3507
|
+
const fs$7 = require("fs-extra");
|
|
3508
|
+
const path$7 = require("path");
|
|
3509
|
+
const os$8 = require("os");
|
|
3510
|
+
const crypto$2 = require("crypto");
|
|
3511
|
+
const cfgFile = path$7.join(os$8.homedir(), ".hyperclaw", "hyperclaw.json");
|
|
2364
3512
|
let cfg = {};
|
|
2365
3513
|
try {
|
|
2366
|
-
cfg = await fs$
|
|
3514
|
+
cfg = await fs$7.readJson(cfgFile);
|
|
2367
3515
|
} catch {}
|
|
2368
3516
|
if (!cfg.gateway) cfg.gateway = {
|
|
2369
3517
|
port: 18789,
|
|
@@ -2374,48 +3522,48 @@ gatewayCfgCmd.option("--set-token <token>", "Set gateway auth token").option("--
|
|
|
2374
3522
|
hooks: true
|
|
2375
3523
|
};
|
|
2376
3524
|
if (opts.regenerateToken) {
|
|
2377
|
-
cfg.gateway.authToken = crypto.randomBytes(32).toString("hex");
|
|
2378
|
-
console.log(chalk$
|
|
2379
|
-
console.log(chalk$
|
|
3525
|
+
cfg.gateway.authToken = crypto$2.randomBytes(32).toString("hex");
|
|
3526
|
+
console.log(chalk$11.hex("#06b6d4")("\n ✔ New gateway token generated"));
|
|
3527
|
+
console.log(chalk$11.gray(` Token: ${cfg.gateway.authToken}`));
|
|
2380
3528
|
}
|
|
2381
3529
|
if (opts.setToken) {
|
|
2382
3530
|
cfg.gateway.authToken = opts.setToken;
|
|
2383
|
-
console.log(chalk$
|
|
3531
|
+
console.log(chalk$11.hex("#06b6d4")(`\n ✔ Gateway token set`));
|
|
2384
3532
|
}
|
|
2385
3533
|
if (opts.setPort) {
|
|
2386
3534
|
cfg.gateway.port = parseInt(opts.setPort);
|
|
2387
|
-
console.log(chalk$
|
|
3535
|
+
console.log(chalk$11.hex("#06b6d4")(`\n ✔ Port set to ${cfg.gateway.port}`));
|
|
2388
3536
|
}
|
|
2389
3537
|
if (opts.setBind) {
|
|
2390
3538
|
cfg.gateway.bind = opts.setBind;
|
|
2391
|
-
console.log(chalk$
|
|
3539
|
+
console.log(chalk$11.hex("#06b6d4")(`\n ✔ Bind set to ${cfg.gateway.bind}`));
|
|
2392
3540
|
}
|
|
2393
|
-
await fs$
|
|
2394
|
-
await fs$
|
|
2395
|
-
await fs$
|
|
2396
|
-
console.log(chalk$
|
|
3541
|
+
await fs$7.ensureDir(path$7.dirname(cfgFile));
|
|
3542
|
+
await fs$7.writeJson(cfgFile, cfg, { spaces: 2 });
|
|
3543
|
+
await fs$7.chmod(cfgFile, 384);
|
|
3544
|
+
console.log(chalk$11.gray(` Saved to ${cfgFile}\n`));
|
|
2397
3545
|
process.exit(0);
|
|
2398
3546
|
});
|
|
2399
3547
|
const authCmd = program.command("auth").description("OAuth and provider credentials");
|
|
2400
3548
|
authCmd.command("add <service_id>").description("Add API key for a service (any provider we do not ship). Stored in credentials/ and .env.").option("--key <api_key>", "API key (prompts if omitted)").option("--base-url <url>", "Base URL (optional, e.g. https://api.example.com)").option("--env-var <name>", "Env var name (default: <SERVICE_ID>_API_KEY)").action(async (serviceId, opts) => {
|
|
2401
|
-
const chalk$
|
|
3549
|
+
const chalk$11 = require("chalk");
|
|
2402
3550
|
const inquirer$2 = require("inquirer");
|
|
2403
|
-
const { CredentialsStore } = await Promise.resolve().then(() => require("./credentials-store-
|
|
3551
|
+
const { CredentialsStore } = await Promise.resolve().then(() => require("./credentials-store-C6ir0Dae.js"));
|
|
2404
3552
|
const { getHyperClawDir, getEnvFilePath } = await Promise.resolve().then(() => require("./paths-D-QecARF.js"));
|
|
2405
|
-
const { getApiKeyGuide, GENERIC_API_KEY_STEPS } = await Promise.resolve().then(() => require("./api-keys-guide-
|
|
2406
|
-
const fs$
|
|
2407
|
-
const path$
|
|
3553
|
+
const { getApiKeyGuide, GENERIC_API_KEY_STEPS } = await Promise.resolve().then(() => require("./api-keys-guide-BCcOl0Q7.js"));
|
|
3554
|
+
const fs$7 = await import("fs-extra");
|
|
3555
|
+
const path$7 = await import("path");
|
|
2408
3556
|
const guide = getApiKeyGuide(serviceId);
|
|
2409
3557
|
const steps = guide?.setupSteps ?? GENERIC_API_KEY_STEPS;
|
|
2410
|
-
console.log(chalk$
|
|
2411
|
-
console.log(chalk$
|
|
2412
|
-
for (const step of steps) if (step.startsWith(" 🔗")) console.log(chalk$
|
|
2413
|
-
else if (step.startsWith(" 💡")) console.log(chalk$
|
|
2414
|
-
else console.log(chalk$
|
|
3558
|
+
console.log(chalk$11.bold.hex("#06b6d4")(`\n 🔑 Add API key: ${guide?.name ?? serviceId}\n`));
|
|
3559
|
+
console.log(chalk$11.bold(" Steps:\n"));
|
|
3560
|
+
for (const step of steps) if (step.startsWith(" 🔗")) console.log(chalk$11.hex("#06b6d4")(step));
|
|
3561
|
+
else if (step.startsWith(" 💡")) console.log(chalk$11.gray(step));
|
|
3562
|
+
else console.log(chalk$11.gray(` ${step}`));
|
|
2415
3563
|
console.log();
|
|
2416
3564
|
const safeId = serviceId.replace(/[^a-zA-Z0-9_-]/g, "_").toLowerCase();
|
|
2417
3565
|
if (!safeId) {
|
|
2418
|
-
console.log(chalk$
|
|
3566
|
+
console.log(chalk$11.red("\n ✖ Invalid service ID\n"));
|
|
2419
3567
|
process.exit(1);
|
|
2420
3568
|
}
|
|
2421
3569
|
let apiKey = opts.key || process.env[`${safeId.toUpperCase().replace(/-/g, "_")}_API_KEY`];
|
|
@@ -2437,44 +3585,44 @@ authCmd.command("add <service_id>").description("Add API key for a service (any
|
|
|
2437
3585
|
});
|
|
2438
3586
|
const envVar = opts.envVar || `${safeId.toUpperCase().replace(/-/g, "_")}_API_KEY`;
|
|
2439
3587
|
const envPath = getEnvFilePath();
|
|
2440
|
-
await fs$
|
|
3588
|
+
await fs$7.ensureDir(path$7.dirname(envPath));
|
|
2441
3589
|
let envContent = "";
|
|
2442
|
-
if (await fs$
|
|
3590
|
+
if (await fs$7.pathExists(envPath)) envContent = await fs$7.readFile(envPath, "utf8");
|
|
2443
3591
|
const envLine = `${envVar}=${apiKey}`;
|
|
2444
3592
|
const re = new RegExp(`^${envVar}=.*$`, "m");
|
|
2445
3593
|
if (re.test(envContent)) envContent = envContent.replace(re, envLine);
|
|
2446
3594
|
else envContent = envContent.trimEnd() + (envContent ? "\n" : "") + envLine + "\n";
|
|
2447
|
-
await fs$
|
|
2448
|
-
console.log(chalk$
|
|
2449
|
-
console.log(chalk$
|
|
2450
|
-
console.log(chalk$
|
|
2451
|
-
console.log(chalk$
|
|
2452
|
-
console.log(chalk$
|
|
3595
|
+
await fs$7.writeFile(envPath, envContent, { mode: 384 });
|
|
3596
|
+
console.log(chalk$11.hex("#06b6d4")(`\n ✔ Added: ${safeId}`));
|
|
3597
|
+
console.log(chalk$11.gray(` Credentials: ~/.hyperclaw/credentials/${safeId}.json`));
|
|
3598
|
+
console.log(chalk$11.gray(` Env: ${envVar} (in .env — use in skills via process.env.${envVar.replace(/-/g, "_")})`));
|
|
3599
|
+
console.log(chalk$11.gray("\n Run: hyperclaw secrets apply to add to shell"));
|
|
3600
|
+
console.log(chalk$11.gray(" Run: hyperclaw secrets reload to inject into running gateway\n"));
|
|
2453
3601
|
process.exit(0);
|
|
2454
3602
|
});
|
|
2455
3603
|
authCmd.command("remove <service_id>").description("Remove API key for a service from credentials and .env").action(async (serviceId) => {
|
|
2456
|
-
const chalk$
|
|
2457
|
-
const { CredentialsStore } = await Promise.resolve().then(() => require("./credentials-store-
|
|
3604
|
+
const chalk$11 = require("chalk");
|
|
3605
|
+
const { CredentialsStore } = await Promise.resolve().then(() => require("./credentials-store-C6ir0Dae.js"));
|
|
2458
3606
|
const { getHyperClawDir, getEnvFilePath } = await Promise.resolve().then(() => require("./paths-D-QecARF.js"));
|
|
2459
|
-
const fs$
|
|
3607
|
+
const fs$7 = await import("fs-extra");
|
|
2460
3608
|
const safeId = serviceId.replace(/[^a-zA-Z0-9_-]/g, "_").toLowerCase();
|
|
2461
3609
|
const creds = new CredentialsStore(getHyperClawDir());
|
|
2462
3610
|
await creds.remove(safeId);
|
|
2463
3611
|
const envVar = `${safeId.toUpperCase().replace(/-/g, "_")}_API_KEY`;
|
|
2464
3612
|
const envPath = getEnvFilePath();
|
|
2465
|
-
if (await fs$
|
|
2466
|
-
let c = await fs$
|
|
3613
|
+
if (await fs$7.pathExists(envPath)) {
|
|
3614
|
+
let c = await fs$7.readFile(envPath, "utf8");
|
|
2467
3615
|
c = c.replace(new RegExp(`^${envVar}=.*\n?`, "gm"), "");
|
|
2468
|
-
await fs$
|
|
3616
|
+
await fs$7.writeFile(envPath, c);
|
|
2469
3617
|
}
|
|
2470
|
-
console.log(chalk$
|
|
3618
|
+
console.log(chalk$11.hex("#06b6d4")(`\n ✔ Removed: ${safeId}\n`));
|
|
2471
3619
|
process.exit(0);
|
|
2472
3620
|
});
|
|
2473
3621
|
authCmd.command("oauth <provider>").description("Run full OAuth flow. Providers: google, google-gmail (Gmail Pub/Sub), microsoft").option("--client-id <id>", "OAuth client ID (or GOOGLE_OAUTH_CLIENT_ID)").option("--client-secret <secret>", "OAuth client secret (optional for PKCE)").action(async (provider, opts) => {
|
|
2474
|
-
const chalk$
|
|
3622
|
+
const chalk$11 = require("chalk");
|
|
2475
3623
|
const ora$4 = (await import("ora")).default;
|
|
2476
3624
|
try {
|
|
2477
|
-
const { runOAuthFlow } = await Promise.resolve().then(() => require("./oauth-flow-
|
|
3625
|
+
const { runOAuthFlow } = await Promise.resolve().then(() => require("./oauth-flow-DQPvMHRH.js"));
|
|
2478
3626
|
const spinner = ora$4("Starting OAuth flow...").start();
|
|
2479
3627
|
spinner.text = "Opening browser — complete the consent and return here.";
|
|
2480
3628
|
const tokens = await runOAuthFlow(provider, {
|
|
@@ -2482,7 +3630,7 @@ authCmd.command("oauth <provider>").description("Run full OAuth flow. Providers:
|
|
|
2482
3630
|
clientSecret: opts.clientSecret
|
|
2483
3631
|
});
|
|
2484
3632
|
spinner.stop();
|
|
2485
|
-
const { writeOAuthToken } = await Promise.resolve().then(() => require("./oauth-provider-
|
|
3633
|
+
const { writeOAuthToken } = await Promise.resolve().then(() => require("./oauth-provider-Uo4Nib_c.js"));
|
|
2486
3634
|
const now = Math.floor(Date.now() / 1e3);
|
|
2487
3635
|
const expires_at = tokens.expires_in ? now + tokens.expires_in : void 0;
|
|
2488
3636
|
const tokenUrl = provider === "google" || provider === "google-gmail" ? "https://oauth2.googleapis.com/token" : provider === "microsoft" ? "https://login.microsoftonline.com/common/oauth2/v2.0/token" : void 0;
|
|
@@ -2492,19 +3640,19 @@ authCmd.command("oauth <provider>").description("Run full OAuth flow. Providers:
|
|
|
2492
3640
|
expires_at,
|
|
2493
3641
|
token_url: tokenUrl
|
|
2494
3642
|
});
|
|
2495
|
-
console.log(chalk$
|
|
2496
|
-
console.log(chalk$
|
|
3643
|
+
console.log(chalk$11.hex("#06b6d4")(`\n ✔ OAuth tokens saved for: ${provider}`));
|
|
3644
|
+
console.log(chalk$11.gray(" Set in hyperclaw.json: \"provider\": { \"authType\": \"oauth\", \"providerId\": \"" + provider + "\" }\n"));
|
|
2497
3645
|
} catch (e) {
|
|
2498
|
-
console.error(chalk$
|
|
3646
|
+
console.error(chalk$11.red("\n ✖ OAuth failed: " + e.message + "\n"));
|
|
2499
3647
|
process.exit(1);
|
|
2500
3648
|
}
|
|
2501
3649
|
process.exit(0);
|
|
2502
3650
|
});
|
|
2503
3651
|
authCmd.command("setup-token <provider>").description("Save setup token (Anthropic Claude Pro/Max). Run: claude setup-token, paste result here.").action(async (provider) => {
|
|
2504
|
-
const chalk$
|
|
3652
|
+
const chalk$11 = require("chalk");
|
|
2505
3653
|
const inquirer$2 = await import("inquirer");
|
|
2506
3654
|
if (provider !== "anthropic") {
|
|
2507
|
-
console.log(chalk$
|
|
3655
|
+
console.log(chalk$11.yellow(`\n Provider "${provider}" may not support setup-token. Use "hyperclaw auth add" for API keys.\n`));
|
|
2508
3656
|
process.exit(1);
|
|
2509
3657
|
}
|
|
2510
3658
|
const { token } = await inquirer$2.default.prompt([{
|
|
@@ -2514,24 +3662,24 @@ authCmd.command("setup-token <provider>").description("Save setup token (Anthrop
|
|
|
2514
3662
|
mask: "●"
|
|
2515
3663
|
}]);
|
|
2516
3664
|
if (!token?.trim()) {
|
|
2517
|
-
console.log(chalk$
|
|
3665
|
+
console.log(chalk$11.red("\n ✖ No token provided.\n"));
|
|
2518
3666
|
process.exit(1);
|
|
2519
3667
|
}
|
|
2520
|
-
const { writeOAuthToken } = await Promise.resolve().then(() => require("./oauth-provider-
|
|
3668
|
+
const { writeOAuthToken } = await Promise.resolve().then(() => require("./oauth-provider-Uo4Nib_c.js"));
|
|
2521
3669
|
await writeOAuthToken("anthropic-setup", {
|
|
2522
3670
|
access_token: token.trim(),
|
|
2523
3671
|
token_url: "https://api.anthropic.com"
|
|
2524
3672
|
});
|
|
2525
|
-
console.log(chalk$
|
|
2526
|
-
console.log(chalk$
|
|
3673
|
+
console.log(chalk$11.hex("#06b6d4")("\n ✔ Anthropic setup token saved to ~/.hyperclaw/oauth-anthropic-setup.json"));
|
|
3674
|
+
console.log(chalk$11.gray(" Use providerId: anthropic with authType: oauth and oauthTokenPath for Claude Pro/Max.\n"));
|
|
2527
3675
|
process.exit(0);
|
|
2528
3676
|
});
|
|
2529
3677
|
authCmd.command("oauth-set <provider>").description("Save OAuth tokens manually (access_token, refresh_token, etc.) to ~/.hyperclaw/oauth-<provider>.json").option("--token <access_token>", "Access token").option("--refresh <refresh_token>", "Refresh token (optional)").option("--expires-in <seconds>", "Token lifetime in seconds (optional)").option("--token-url <url>", "Refresh endpoint URL (optional)").action(async (provider, opts) => {
|
|
2530
|
-
const chalk$
|
|
2531
|
-
const { writeOAuthToken } = await Promise.resolve().then(() => require("./oauth-provider-
|
|
3678
|
+
const chalk$11 = require("chalk");
|
|
3679
|
+
const { writeOAuthToken } = await Promise.resolve().then(() => require("./oauth-provider-Uo4Nib_c.js"));
|
|
2532
3680
|
const access_token = opts.token || process.env.OAUTH_ACCESS_TOKEN;
|
|
2533
3681
|
if (!access_token) {
|
|
2534
|
-
console.log(chalk$
|
|
3682
|
+
console.log(chalk$11.red("\n ✖ Provide --token <access_token> or set OAUTH_ACCESS_TOKEN\n"));
|
|
2535
3683
|
process.exit(1);
|
|
2536
3684
|
}
|
|
2537
3685
|
const expires_at = opts.expiresIn ? Math.floor(Date.now() / 1e3) + parseInt(opts.expiresIn, 10) : void 0;
|
|
@@ -2541,22 +3689,22 @@ authCmd.command("oauth-set <provider>").description("Save OAuth tokens manually
|
|
|
2541
3689
|
expires_at,
|
|
2542
3690
|
token_url: opts.tokenUrl || void 0
|
|
2543
3691
|
});
|
|
2544
|
-
console.log(chalk$
|
|
2545
|
-
console.log(chalk$
|
|
3692
|
+
console.log(chalk$11.hex("#06b6d4")(`\n ✔ OAuth tokens saved for provider: ${provider}`));
|
|
3693
|
+
console.log(chalk$11.gray(" Set in hyperclaw.json: \"provider\": { \"authType\": \"oauth\", \"providerId\": \"" + provider + "\" }\n"));
|
|
2546
3694
|
process.exit(0);
|
|
2547
3695
|
});
|
|
2548
3696
|
const workspaceCmd = program.command("workspace").description("Manage agent workspace files");
|
|
2549
3697
|
workspaceCmd.command("init [dir]").description("Initialize workspace files (SOUL.md, USER.md, TOOLS.md, HEARTBEAT.md, BOOTSTRAP.md) in a directory").action(async (dir) => {
|
|
2550
|
-
const chalk$
|
|
2551
|
-
const fs$
|
|
2552
|
-
const path$
|
|
2553
|
-
const os$
|
|
2554
|
-
const targetDir = dir || path$
|
|
3698
|
+
const chalk$11 = require("chalk");
|
|
3699
|
+
const fs$7 = require("fs-extra");
|
|
3700
|
+
const path$7 = require("path");
|
|
3701
|
+
const os$8 = require("os");
|
|
3702
|
+
const targetDir = dir || path$7.join(os$8.homedir(), ".hyperclaw");
|
|
2555
3703
|
let cfg = {};
|
|
2556
3704
|
try {
|
|
2557
|
-
cfg = await fs$
|
|
3705
|
+
cfg = await fs$7.readJson(path$7.join(os$8.homedir(), ".hyperclaw", "hyperclaw.json"));
|
|
2558
3706
|
} catch {}
|
|
2559
|
-
const { initWorkspaceFiles } = await Promise.resolve().then(() => require("./memory-
|
|
3707
|
+
const { initWorkspaceFiles } = await Promise.resolve().then(() => require("./memory-BlHL7JCO.js"));
|
|
2560
3708
|
await initWorkspaceFiles({
|
|
2561
3709
|
agentName: cfg.identity?.agentName || "Hyper",
|
|
2562
3710
|
personality: cfg.identity?.personality || "helpful and concise",
|
|
@@ -2564,17 +3712,17 @@ workspaceCmd.command("init [dir]").description("Initialize workspace files (SOUL
|
|
|
2564
3712
|
userName: cfg.identity?.userName || "User",
|
|
2565
3713
|
rules: cfg.identity?.rules ?? []
|
|
2566
3714
|
}, targetDir);
|
|
2567
|
-
console.log(chalk$
|
|
2568
|
-
console.log(chalk$
|
|
3715
|
+
console.log(chalk$11.hex("#06b6d4")(`\n ✔ Workspace files initialized in ${targetDir}`));
|
|
3716
|
+
console.log(chalk$11.gray(" Files: SOUL.md USER.md TOOLS.md HEARTBEAT.md BOOTSTRAP.md\n"));
|
|
2569
3717
|
process.exit(0);
|
|
2570
3718
|
});
|
|
2571
3719
|
workspaceCmd.command("show [dir]").description("Show workspace files summary").action(async (dir) => {
|
|
2572
|
-
const chalk$
|
|
2573
|
-
const fs$
|
|
2574
|
-
const path$
|
|
2575
|
-
const os$
|
|
2576
|
-
const targetDir = dir || path$
|
|
2577
|
-
console.log(chalk$
|
|
3720
|
+
const chalk$11 = require("chalk");
|
|
3721
|
+
const fs$7 = require("fs-extra");
|
|
3722
|
+
const path$7 = require("path");
|
|
3723
|
+
const os$8 = require("os");
|
|
3724
|
+
const targetDir = dir || path$7.join(os$8.homedir(), ".hyperclaw");
|
|
3725
|
+
console.log(chalk$11.bold.hex("#06b6d4")("\n 📁 WORKSPACE\n"));
|
|
2578
3726
|
for (const fname of [
|
|
2579
3727
|
"SOUL.md",
|
|
2580
3728
|
"USER.md",
|
|
@@ -2584,27 +3732,27 @@ workspaceCmd.command("show [dir]").description("Show workspace files summary").a
|
|
|
2584
3732
|
"AGENTS.md",
|
|
2585
3733
|
"MEMORY.md"
|
|
2586
3734
|
]) {
|
|
2587
|
-
const fpath = path$
|
|
2588
|
-
const exists = await fs$
|
|
2589
|
-
const size = exists ? (await fs$
|
|
2590
|
-
const dot = exists ? chalk$
|
|
2591
|
-
console.log(` ${dot} ${fname.padEnd(14)} ${exists ? chalk$
|
|
3735
|
+
const fpath = path$7.join(targetDir, fname);
|
|
3736
|
+
const exists = await fs$7.pathExists(fpath);
|
|
3737
|
+
const size = exists ? (await fs$7.stat(fpath)).size : 0;
|
|
3738
|
+
const dot = exists ? chalk$11.hex("#06b6d4")("✔") : chalk$11.gray("○");
|
|
3739
|
+
console.log(` ${dot} ${fname.padEnd(14)} ${exists ? chalk$11.gray(`${size} bytes`) : chalk$11.gray("(missing)")}`);
|
|
2592
3740
|
}
|
|
2593
3741
|
console.log();
|
|
2594
3742
|
process.exit(0);
|
|
2595
3743
|
});
|
|
2596
3744
|
const botCmd = program.command("bot").description("HyperClaw Bot — companion bot for remote gateway control");
|
|
2597
3745
|
botCmd.command("status").action(async () => {
|
|
2598
|
-
const { showBotStatus } = await Promise.resolve().then(() => require("./hyperclawbot-
|
|
3746
|
+
const { showBotStatus } = await Promise.resolve().then(() => require("./hyperclawbot-zvczQgKx.js"));
|
|
2599
3747
|
await showBotStatus();
|
|
2600
3748
|
process.exit(0);
|
|
2601
3749
|
});
|
|
2602
3750
|
botCmd.command("setup").description("Configure HyperClaw Bot (Telegram token, allowed users)").action(async () => {
|
|
2603
3751
|
const inquirer$2 = require("inquirer");
|
|
2604
|
-
const { saveBotConfig } = await Promise.resolve().then(() => require("./hyperclawbot-
|
|
2605
|
-
const chalk$
|
|
2606
|
-
console.log(chalk$
|
|
2607
|
-
console.log(chalk$
|
|
3752
|
+
const { saveBotConfig } = await Promise.resolve().then(() => require("./hyperclawbot-zvczQgKx.js"));
|
|
3753
|
+
const chalk$11 = require("chalk");
|
|
3754
|
+
console.log(chalk$11.bold.hex("#06b6d4")("\n 🦅 HYPERCLAW BOT SETUP\n"));
|
|
3755
|
+
console.log(chalk$11.gray(" Create a bot at t.me/BotFather, then paste the token below.\n"));
|
|
2608
3756
|
const { platform } = await inquirer$2.prompt([{
|
|
2609
3757
|
type: "list",
|
|
2610
3758
|
name: "platform",
|
|
@@ -2638,20 +3786,20 @@ botCmd.command("setup").description("Configure HyperClaw Bot (Telegram token, al
|
|
|
2638
3786
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2639
3787
|
};
|
|
2640
3788
|
await saveBotConfig(cfg);
|
|
2641
|
-
console.log(chalk$
|
|
3789
|
+
console.log(chalk$11.hex("#06b6d4")("\n ✔ HyperClaw Bot configured"));
|
|
2642
3790
|
if (platform === "discord") try {
|
|
2643
3791
|
require.resolve("discord.js");
|
|
2644
3792
|
} catch {
|
|
2645
|
-
console.log(chalk$
|
|
3793
|
+
console.log(chalk$11.yellow(" ⚠ For Discord: run: npm install discord.js"));
|
|
2646
3794
|
}
|
|
2647
|
-
console.log(chalk$
|
|
3795
|
+
console.log(chalk$11.gray(" Start with: hyperclaw bot start\n"));
|
|
2648
3796
|
process.exit(0);
|
|
2649
3797
|
});
|
|
2650
3798
|
botCmd.command("start").description("Start HyperClaw Bot (foreground or background)").option("--background", "Run bot in background (use hyperclaw bot stop to stop)").action(async (opts) => {
|
|
2651
3799
|
const { spawn } = await import("child_process");
|
|
2652
|
-
const path$
|
|
3800
|
+
const path$7 = await import("path");
|
|
2653
3801
|
if (opts?.background) {
|
|
2654
|
-
const entry = process.argv[1] || path$
|
|
3802
|
+
const entry = process.argv[1] || path$7.join(__dirname, "run-main.js");
|
|
2655
3803
|
const child = spawn(process.execPath, [
|
|
2656
3804
|
entry,
|
|
2657
3805
|
"bot",
|
|
@@ -2663,14 +3811,14 @@ botCmd.command("start").description("Start HyperClaw Bot (foreground or backgrou
|
|
|
2663
3811
|
cwd: process.cwd()
|
|
2664
3812
|
});
|
|
2665
3813
|
child.unref();
|
|
2666
|
-
const { writeBotPid } = await Promise.resolve().then(() => require("./hyperclawbot-
|
|
3814
|
+
const { writeBotPid } = await Promise.resolve().then(() => require("./hyperclawbot-zvczQgKx.js"));
|
|
2667
3815
|
await writeBotPid(child.pid);
|
|
2668
3816
|
console.log(require("chalk").green(`\n ✔ HyperClaw Bot started in background (PID ${child.pid})`));
|
|
2669
3817
|
console.log(require("chalk").gray(" Stop with: hyperclaw bot stop\n"));
|
|
2670
3818
|
process.exit(0);
|
|
2671
3819
|
return;
|
|
2672
3820
|
}
|
|
2673
|
-
const { loadBotConfig, TelegramHyperClawBot, DiscordHyperClawBot } = await Promise.resolve().then(() => require("./hyperclawbot-
|
|
3821
|
+
const { loadBotConfig, TelegramHyperClawBot, DiscordHyperClawBot } = await Promise.resolve().then(() => require("./hyperclawbot-zvczQgKx.js"));
|
|
2674
3822
|
const cfg = await loadBotConfig();
|
|
2675
3823
|
if (!cfg) {
|
|
2676
3824
|
console.log(require("chalk").red("\n ✖ HyperClaw Bot not configured. Run: hyperclaw bot setup\n"));
|
|
@@ -2696,42 +3844,42 @@ botCmd.command("start").description("Start HyperClaw Bot (foreground or backgrou
|
|
|
2696
3844
|
}
|
|
2697
3845
|
});
|
|
2698
3846
|
botCmd.command("stop").description("Stop HyperClaw Bot (when running in background)").action(async () => {
|
|
2699
|
-
const chalk$
|
|
2700
|
-
const { stopBotProcess } = await Promise.resolve().then(() => require("./hyperclawbot-
|
|
3847
|
+
const chalk$11 = require("chalk");
|
|
3848
|
+
const { stopBotProcess } = await Promise.resolve().then(() => require("./hyperclawbot-zvczQgKx.js"));
|
|
2701
3849
|
const stopped = await stopBotProcess();
|
|
2702
|
-
if (stopped) console.log(chalk$
|
|
2703
|
-
else console.log(chalk$
|
|
3850
|
+
if (stopped) console.log(chalk$11.green("\n ✔ HyperClaw Bot stopped\n"));
|
|
3851
|
+
else console.log(chalk$11.gray("\n Bot not running in background (no PID file). Use Ctrl+C to stop foreground bot.\n"));
|
|
2704
3852
|
process.exit(stopped ? 0 : 0);
|
|
2705
3853
|
});
|
|
2706
3854
|
memCmd.command("search <query>").description("Search MEMORY.md").action(async (query) => {
|
|
2707
|
-
const { searchMemory } = await Promise.resolve().then(() => require("./src-
|
|
3855
|
+
const { searchMemory } = await Promise.resolve().then(() => require("./src-BxPHKO5x.js"));
|
|
2708
3856
|
await searchMemory(query);
|
|
2709
3857
|
process.exit(0);
|
|
2710
3858
|
});
|
|
2711
3859
|
memCmd.command("auto-show").description("Show auto-extracted memories from MEMORY.md").action(async () => {
|
|
2712
|
-
const { showMemory } = await Promise.resolve().then(() => require("./src-
|
|
3860
|
+
const { showMemory } = await Promise.resolve().then(() => require("./src-BxPHKO5x.js"));
|
|
2713
3861
|
await showMemory();
|
|
2714
3862
|
process.exit(0);
|
|
2715
3863
|
});
|
|
2716
3864
|
memCmd.command("clear").description("Clear all auto-extracted memories").action(async () => {
|
|
2717
|
-
const { clearMemory } = await Promise.resolve().then(() => require("./src-
|
|
3865
|
+
const { clearMemory } = await Promise.resolve().then(() => require("./src-BxPHKO5x.js"));
|
|
2718
3866
|
await clearMemory();
|
|
2719
3867
|
process.exit(0);
|
|
2720
3868
|
});
|
|
2721
3869
|
memCmd.command("save <text>").description("Manually save a fact to MEMORY.md").action(async (text) => {
|
|
2722
|
-
const { saveMemoryDirect } = await Promise.resolve().then(() => require("./src-
|
|
3870
|
+
const { saveMemoryDirect } = await Promise.resolve().then(() => require("./src-BxPHKO5x.js"));
|
|
2723
3871
|
await saveMemoryDirect(text);
|
|
2724
3872
|
console.log(chalk.default.hex("#06b6d4")(` ✅ Saved: ${text}\n`));
|
|
2725
3873
|
process.exit(0);
|
|
2726
3874
|
});
|
|
2727
3875
|
const pcCmd = program.command("pc").description("PC access — give the AI access to your computer");
|
|
2728
3876
|
pcCmd.command("status").description("Show PC access status and config").action(async () => {
|
|
2729
|
-
const { showPCAccessStatus } = await Promise.resolve().then(() => require("./src-
|
|
3877
|
+
const { showPCAccessStatus } = await Promise.resolve().then(() => require("./src-BxPHKO5x.js"));
|
|
2730
3878
|
await showPCAccessStatus();
|
|
2731
3879
|
process.exit(0);
|
|
2732
3880
|
});
|
|
2733
3881
|
pcCmd.command("enable").description("Enable PC access for the AI").option("--level <level>", "Access level: read-only | sandboxed | full", "full").option("--paths <paths>", "Comma-separated allowed paths (sandboxed mode)").action(async (opts) => {
|
|
2734
|
-
const { savePCAccessConfig } = await Promise.resolve().then(() => require("./src-
|
|
3882
|
+
const { savePCAccessConfig } = await Promise.resolve().then(() => require("./src-BxPHKO5x.js"));
|
|
2735
3883
|
const level = opts.level;
|
|
2736
3884
|
const allowed = [
|
|
2737
3885
|
"read-only",
|
|
@@ -2758,7 +3906,7 @@ pcCmd.command("enable").description("Enable PC access for the AI").option("--lev
|
|
|
2758
3906
|
process.exit(0);
|
|
2759
3907
|
});
|
|
2760
3908
|
pcCmd.command("disable").description("Disable PC access").action(async () => {
|
|
2761
|
-
const { savePCAccessConfig } = await Promise.resolve().then(() => require("./src-
|
|
3909
|
+
const { savePCAccessConfig } = await Promise.resolve().then(() => require("./src-BxPHKO5x.js"));
|
|
2762
3910
|
await savePCAccessConfig({ enabled: false });
|
|
2763
3911
|
console.log(chalk.default.hex("#06b6d4")("\n ✅ PC access disabled\n"));
|
|
2764
3912
|
process.exit(0);
|
|
@@ -2782,7 +3930,7 @@ pcCmd.command("log").description("Show PC access audit log").option("-n, --lines
|
|
|
2782
3930
|
process.exit(0);
|
|
2783
3931
|
});
|
|
2784
3932
|
pcCmd.command("run <command>").description("Run a shell command via PC access (must be enabled)").action(async (command) => {
|
|
2785
|
-
const { loadPCAccessConfig, getPCAccessTools } = await Promise.resolve().then(() => require("./src-
|
|
3933
|
+
const { loadPCAccessConfig, getPCAccessTools } = await Promise.resolve().then(() => require("./src-BxPHKO5x.js"));
|
|
2786
3934
|
const cfg = await loadPCAccessConfig();
|
|
2787
3935
|
if (!cfg.enabled) {
|
|
2788
3936
|
console.log(chalk.default.red("\n ✖ PC access disabled. Run: hyperclaw pc enable\n"));
|
|
@@ -2798,9 +3946,9 @@ pcCmd.command("run <command>").description("Run a shell command via PC access (m
|
|
|
2798
3946
|
function checkForUpdate() {
|
|
2799
3947
|
const { execFile: execFile$1 } = require("child_process");
|
|
2800
3948
|
const { readFileSync } = require("fs");
|
|
2801
|
-
const path$
|
|
3949
|
+
const path$7 = require("path");
|
|
2802
3950
|
try {
|
|
2803
|
-
const pkgPath = path$
|
|
3951
|
+
const pkgPath = path$7.resolve(__dirname, "../../package.json");
|
|
2804
3952
|
const current = JSON.parse(readFileSync(pkgPath, "utf8")).version;
|
|
2805
3953
|
execFile$1("npm", [
|
|
2806
3954
|
"view",
|
|
@@ -2822,15 +3970,31 @@ function checkForUpdate() {
|
|
|
2822
3970
|
});
|
|
2823
3971
|
} catch {}
|
|
2824
3972
|
}
|
|
3973
|
+
program.command("setup").description("Setup wizard — alias for `hyperclaw onboard`").option("--install-daemon", "Auto-install system daemon").option("--reset", "Reset config before running wizard").option("--non-interactive", "Non-interactive mode").option("--json", "Output result as JSON (use with --non-interactive)").option("--anthropic-api-key <key>", "Anthropic API key (non-interactive)").option("--openai-api-key <key>", "OpenAI API key (non-interactive)").option("--gateway-port <port>", "Gateway port (non-interactive)", "18789").option("--gateway-bind <bind>", "Gateway bind: loopback | all", "loopback").action(async (opts) => {
|
|
3974
|
+
await new require_onboard.Banner().showNeonBanner(false);
|
|
3975
|
+
const wizardOpts = {
|
|
3976
|
+
wizard: true,
|
|
3977
|
+
installDaemon: opts.installDaemon ?? false,
|
|
3978
|
+
reset: opts.reset ?? false,
|
|
3979
|
+
nonInteractive: opts.nonInteractive ?? false,
|
|
3980
|
+
jsonOutput: opts.json ?? false,
|
|
3981
|
+
gatewayPort: opts.gatewayPort ? parseInt(opts.gatewayPort) : void 0,
|
|
3982
|
+
gatewayBind: opts.gatewayBind ?? "loopback",
|
|
3983
|
+
anthropicApiKey: opts.anthropicApiKey,
|
|
3984
|
+
openaiApiKey: opts.openaiApiKey
|
|
3985
|
+
};
|
|
3986
|
+
await new require_onboard.HyperClawWizard().run(wizardOpts);
|
|
3987
|
+
process.exit(0);
|
|
3988
|
+
});
|
|
2825
3989
|
checkForUpdate();
|
|
2826
3990
|
if (process.argv.length === 2) (async () => {
|
|
2827
|
-
const { ConfigManager: ConfigManager$1 } = await Promise.resolve().then(() => require("./manager-
|
|
3991
|
+
const { ConfigManager: ConfigManager$1 } = await Promise.resolve().then(() => require("./manager-CrVDn6eN.js"));
|
|
2828
3992
|
const cfg = await new ConfigManager$1().load().catch(() => null);
|
|
2829
3993
|
if (cfg?.provider?.apiKey || cfg?.provider?.providerId) {
|
|
2830
3994
|
await new require_onboard.Banner().showNeonBanner(false);
|
|
2831
|
-
const { getTheme } = await Promise.resolve().then(() => require("./theme-
|
|
3995
|
+
const { getTheme } = await Promise.resolve().then(() => require("./theme-cx0fkgWC.js"));
|
|
2832
3996
|
const t = getTheme(false);
|
|
2833
|
-
const chalk$
|
|
3997
|
+
const chalk$11 = require("chalk");
|
|
2834
3998
|
console.log(t.bold(" Quick actions:\n"));
|
|
2835
3999
|
console.log(` ${t.c("hyperclaw onboard")} — re-run setup wizard`);
|
|
2836
4000
|
console.log(` ${t.c("hyperclaw onboard --install-daemon")} — wizard + daemon (full PC access)`);
|
|
@@ -2842,7 +4006,7 @@ if (process.argv.length === 2) (async () => {
|
|
|
2842
4006
|
console.log(` ${t.c("hyperclaw --help")} — all commands\n`);
|
|
2843
4007
|
} else {
|
|
2844
4008
|
await new require_onboard.Banner().showNeonBanner(false);
|
|
2845
|
-
const { HyperClawWizard: HyperClawWizard$1 } = await Promise.resolve().then(() => require("./onboard-
|
|
4009
|
+
const { HyperClawWizard: HyperClawWizard$1 } = await Promise.resolve().then(() => require("./onboard-0WoDxbv_.js"));
|
|
2846
4010
|
await new HyperClawWizard$1().run({ wizard: true });
|
|
2847
4011
|
}
|
|
2848
4012
|
process.exit(0);
|