hyperclaw 4.0.2 → 5.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +246 -60
- 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/api-keys-guide-CGn5BSF7.js +149 -0
- package/dist/audit-BJohI_vC.js +441 -0
- package/dist/audit-BaIiyWFu.js +441 -0
- package/dist/bounty-tools-CY_i91DU.js +211 -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/claw-tasks-Cyzdbhz_.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-Ca1UPZ33.js +103 -0
- package/dist/cost-tracker-DD9wtWsr.js +103 -0
- package/dist/credentials-store-C6ir0Dae.js +4 -0
- package/dist/credentials-store-CA8UtK0T.js +77 -0
- package/dist/credentials-store-Cm7DH-kh.js +4 -0
- package/dist/credentials-store-H13LqOwJ.js +77 -0
- package/dist/cron-tasks-Bli7Kzd2.js +82 -0
- package/dist/cron-tasks-_pqQCmxc.js +82 -0
- package/dist/daemon-7ViroziB.js +5 -0
- package/dist/daemon-BfyKmZhr.js +318 -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-DVHmv1IR.js +4 -0
- package/dist/delivery-DpMX0Yyc.js +95 -0
- package/dist/delivery-pWUPBp1F.js +95 -0
- package/dist/destructive-gate-D6vWOdEl.js +101 -0
- package/dist/destructive-gate-DZt71UZR.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-B0kLfRL0.js +256 -0
- package/dist/engine-BJUpRUOv.js +7 -0
- package/dist/engine-CEDSqXfw.js +256 -0
- package/dist/engine-Da4JMNpI.js +7 -0
- package/dist/env-resolve-17ekEU6p.js +10 -0
- package/dist/env-resolve-CiXbWYwe.js +10 -0
- package/dist/env-resolve-CmGWhWXJ.js +115 -0
- package/dist/env-resolve-Z2XF6leB.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/heartbeat-engine-Ut6pXBD6.js +83 -0
- package/dist/hub-9LaKnLjY.js +6 -0
- package/dist/hub-CfwUz9YW.js +515 -0
- package/dist/hub-D0XwdjM-.js +515 -0
- package/dist/hub-LiD5Iztb.js +6 -0
- package/dist/hyperclawbot-CBiDSKsa.js +505 -0
- package/dist/hyperclawbot-zvczQgKx.js +505 -0
- package/dist/inference-0mlFQqIm.js +922 -0
- package/dist/inference-BKVkBREb.js +6 -0
- package/dist/inference-DCXH4Q3x.js +922 -0
- package/dist/inference-SzqFe_nk.js +6 -0
- package/dist/knowledge-graph-DE5lSF02.js +131 -0
- package/dist/knowledge-graph-iBG76fvm.js +131 -0
- package/dist/loader-BkDi8MD9.js +400 -0
- package/dist/loader-CC45xGpC.js +4 -0
- package/dist/loader-CnEdOyjT.js +400 -0
- package/dist/loader-DI2qDRPC.js +4 -0
- package/dist/logger-Cp8wC7F8.js +83 -0
- package/dist/logger-ybOp7VOC.js +83 -0
- package/dist/manager-03ipO9R0.js +105 -0
- package/dist/manager-B2Gls5RG.js +218 -0
- package/dist/manager-BpDfbDjg.js +117 -0
- package/dist/manager-Bxl0sqlh.js +4 -0
- package/dist/manager-CWNSML5D.js +117 -0
- package/dist/manager-CrVDn6eN.js +6 -0
- package/dist/manager-FCgF1plu.js +218 -0
- package/dist/manager-SJe9gt-q.js +4 -0
- package/dist/manager-rgCsaWT1.js +40 -0
- package/dist/mcp-CfoSU4Uz.js +139 -0
- package/dist/mcp-loader-CvxRDtPC.js +94 -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-auto-CpQHZlEJ.js +306 -0
- package/dist/memory-auto-Z6LCf-iK.js +5 -0
- package/dist/memory-integration-cSYkZyEo.js +91 -0
- package/dist/memory-integration-g2vxwgoE.js +91 -0
- package/dist/moltbook-BtLDZTfM.js +81 -0
- package/dist/moltbook-Cl8cQfxJ.js +81 -0
- package/dist/node-Dw2Gi-cP.js +222 -0
- package/dist/nodes-registry-B8dmrlLv.js +52 -0
- package/dist/nodes-registry-C9dCFwjh.js +52 -0
- package/dist/oauth-flow-CeaaGAz0.js +150 -0
- package/dist/oauth-flow-DQPvMHRH.js +150 -0
- package/dist/oauth-provider-B4dzn56l.js +110 -0
- package/dist/oauth-provider-Uo4Nib_c.js +110 -0
- package/dist/observability-BV-Yx0V9.js +89 -0
- package/dist/observability-nZ3CBIxG.js +89 -0
- package/dist/onboard-0WoDxbv_.js +10 -0
- package/dist/onboard-BBBWcfhp.js +10 -0
- package/dist/onboard-BXNXCQp4.js +4070 -0
- package/dist/onboard-Bw28IRQ3.js +4070 -0
- package/dist/orchestrator-BovkM63z.js +6 -0
- package/dist/orchestrator-DSbpkP1X.js +189 -0
- package/dist/orchestrator-DmnEvMaL.js +189 -0
- package/dist/orchestrator-RI3bpqqc.js +6 -0
- package/dist/osint-B4_m3VHQ.js +277 -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-BgNjjuI2.js +22 -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 +1639 -460
- package/dist/runner-CJFJUtPm.js +1271 -0
- 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-Brl_HQUB.js +1255 -0
- package/dist/server-D4wVHiX9.js +4 -0
- package/dist/server-Dh3JlBFB.js +1255 -0
- package/dist/server-DhfipkwN.js +4 -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-BXWd-Ktf.js +102 -0
- package/dist/skill-runtime-CJN24QPW.js +102 -0
- package/dist/skill-runtime-jgklm02e.js +5 -0
- package/dist/skill-runtime-w1ig_lcw.js +5 -0
- package/dist/src-Bhybpk1J.js +63 -0
- package/dist/src-BxPHKO5x.js +63 -0
- package/dist/src-DIc-L2IG.js +20 -0
- package/dist/src-DMJ4-uqk.js +458 -0
- package/dist/src-g_rNx5rh.js +458 -0
- package/dist/sub-agent-tools-CHQoHz9c.js +39 -0
- package/dist/sub-agent-tools-DHY-4WWM.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/tool-policy-DZvF8xlQ.js +189 -0
- package/dist/tts-elevenlabs-BRosZv-f.js +61 -0
- package/dist/tts-elevenlabs-C06nUxMK.js +61 -0
- package/dist/update-check-C2Dz85wJ.js +81 -0
- package/dist/update-check-w4XuxVl7.js +81 -0
- package/dist/vision-BMmiIKy7.js +121 -0
- package/dist/vision-JOtOS1Br.js +121 -0
- package/dist/vision-tools-CB28ZCO_.js +5 -0
- package/dist/vision-tools-DVuYc17I.js +51 -0
- package/dist/vision-tools-U3YC4L-g.js +5 -0
- package/dist/vision-tools-vPPwQ-0N.js +51 -0
- package/dist/voice-transcription-B555DbWR.js +138 -0
- package/dist/voice-transcription-DBo5hXmu.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-Z2XF6leB.js');
|
|
5
|
+
const require_onboard = require('./onboard-Bw28IRQ3.js');
|
|
6
|
+
require('./server-Brl_HQUB.js');
|
|
7
|
+
const require_daemon = require('./daemon-BfyKmZhr.js');
|
|
8
|
+
require('./theme-DcxwcUgZ.js');
|
|
9
|
+
const require_hub = require('./hub-CfwUz9YW.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-BkDi8MD9.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 {
|
|
@@ -33,7 +38,7 @@ var Dashboard = class {
|
|
|
33
38
|
console.clear();
|
|
34
39
|
await this.drawDashboard();
|
|
35
40
|
if (live) {
|
|
36
|
-
console.log(chalk.default.hex("#06b6d4")("
|
|
41
|
+
console.log(chalk.default.hex("#06b6d4")("?? LIVE MODE � Ctrl+C to exit\n"));
|
|
37
42
|
this.startLiveUpdates();
|
|
38
43
|
}
|
|
39
44
|
}
|
|
@@ -48,44 +53,44 @@ var Dashboard = class {
|
|
|
48
53
|
const model = cfg?.provider?.modelId || "openrouter/auto";
|
|
49
54
|
const channels = (cfg?.channels ?? cfg?.gateway?.enabledChannels ?? ["cli"]).join(", ");
|
|
50
55
|
const isRunning = await gm.isRunning(port);
|
|
51
|
-
const statusDot = isRunning ? chalk.default.hex("#06b6d4")("
|
|
56
|
+
const statusDot = isRunning ? chalk.default.hex("#06b6d4")("?") : chalk.default.gray("0");
|
|
52
57
|
const statusText = isRunning ? chalk.default.hex("#06b6d4")("ONLINE") : chalk.default.gray("OFFLINE");
|
|
53
58
|
const w = 72;
|
|
54
|
-
const line = "
|
|
59
|
+
const line = "=".repeat(w);
|
|
55
60
|
const c = chalk.default.hex("#06b6d4");
|
|
56
61
|
const row = (content) => {
|
|
57
62
|
const stripped = content.replace(/\x1b\[[0-9;]*m/g, "");
|
|
58
63
|
const pad = Math.max(0, w - stripped.length - 1);
|
|
59
|
-
return c(
|
|
64
|
+
return c(`� `) + content + " ".repeat(pad) + c(`�`);
|
|
60
65
|
};
|
|
61
|
-
console.log(c(
|
|
62
|
-
console.log(c(
|
|
63
|
-
console.log(c(
|
|
64
|
-
console.log(row(`${statusDot} Gateway ${statusText} ${chalk.default.gray("
|
|
65
|
-
console.log(row(`${c("
|
|
66
|
-
console.log(c(
|
|
66
|
+
console.log(c(`-${line}�`));
|
|
67
|
+
console.log(c(`�`) + chalk.default.bold.hex("#06b6d4")(`${"?? HYPERCLAW v5.0.1 � GATEWAY DASHBOARD".padStart(45).padEnd(w)}`) + c(`�`));
|
|
68
|
+
console.log(c(`�${line}�`));
|
|
69
|
+
console.log(row(`${statusDot} Gateway ${statusText} ${chalk.default.gray("�")} ws://localhost:${port} ${chalk.default.gray("�")} Agent: ${c(agent)}`));
|
|
70
|
+
console.log(row(`${c("?")} Model ${chalk.default.gray(model.slice(0, 30))} ${chalk.default.gray("�")} User: ${c(user)}`));
|
|
71
|
+
console.log(c(`�${"-".repeat(w)}�`));
|
|
67
72
|
console.log(row(chalk.default.bold("ACTIVE CHANNELS")));
|
|
68
73
|
const chList = (channels || "cli").split(", ");
|
|
69
74
|
for (let i = 0; i < chList.length; i += 3) {
|
|
70
|
-
const group = chList.slice(i, i + 3).map((ch) => ` ${c("
|
|
75
|
+
const group = chList.slice(i, i + 3).map((ch) => ` ${c("?")} ${ch.padEnd(12)}`).join("");
|
|
71
76
|
console.log(row(group));
|
|
72
77
|
}
|
|
73
|
-
console.log(c(
|
|
78
|
+
console.log(c(`�${"-".repeat(w)}�`));
|
|
74
79
|
console.log(row(chalk.default.bold("INSTALLED SKILLS")));
|
|
75
80
|
if (installed.length === 0) console.log(row(chalk.default.gray(" No skills installed. Run: hyperclaw hub")));
|
|
76
81
|
else for (let i = 0; i < installed.length; i += 3) {
|
|
77
|
-
const group = installed.slice(i, i + 3).map((s) => ` ${c("
|
|
82
|
+
const group = installed.slice(i, i + 3).map((s) => ` ${c("?")} ${s.name.slice(0, 14).padEnd(14)}`).join("");
|
|
78
83
|
console.log(row(group));
|
|
79
84
|
}
|
|
80
|
-
console.log(c(
|
|
85
|
+
console.log(c(`�${"-".repeat(w)}�`));
|
|
81
86
|
console.log(row(chalk.default.bold("RECENT ACTIVITY")));
|
|
82
87
|
const now = (/* @__PURE__ */ new Date()).toLocaleTimeString();
|
|
83
88
|
console.log(row(` [${now}] Gateway heartbeat: ${c("OK")}`));
|
|
84
|
-
console.log(row(` [${now}] AGENTS.md loaded
|
|
89
|
+
console.log(row(` [${now}] AGENTS.md loaded � rules active`));
|
|
85
90
|
console.log(row(` [${now}] Channels monitoring...`));
|
|
86
|
-
console.log(c(
|
|
87
|
-
console.log(row(chalk.default.gray("Commands: [d] ") + chalk.default.red("
|
|
88
|
-
console.log(c(
|
|
91
|
+
console.log(c(`�${"-".repeat(w)}�`));
|
|
92
|
+
console.log(row(chalk.default.gray("Commands: [d] ") + chalk.default.red("?? daemon") + chalk.default.gray(" [h] hub [g] gateway [m] memory [q] quit")));
|
|
93
|
+
console.log(c(`L${line}-\n`));
|
|
89
94
|
}
|
|
90
95
|
startLiveUpdates() {
|
|
91
96
|
let tick = 0;
|
|
@@ -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.1").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-DZvF8xlQ.js"));
|
|
2572
|
+
const { getBuiltinTools, getSessionsTools, getPCAccessTools, getBrowserTools, getExtractionTools, getWebsiteWatchTools, getVisionTools } = await Promise.resolve().then(() => require("./src-Bhybpk1J.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);
|
|
2670
|
+
process.exit(0);
|
|
2671
|
+
});
|
|
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);
|
|
1677
2674
|
process.exit(0);
|
|
1678
2675
|
});
|
|
1679
|
-
|
|
1680
|
-
|
|
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.1\")",
|
|
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,64 @@ 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-B2Gls5RG.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-B2Gls5RG.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-B2Gls5RG.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-B2Gls5RG.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-B2Gls5RG.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-Cm7DH-kh.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-BJohI_vC.js"));
|
|
3219
|
+
await runSecurityAudit({
|
|
3220
|
+
deep: opts.deep,
|
|
3221
|
+
fix: opts.fix,
|
|
3222
|
+
json: opts.json
|
|
3223
|
+
});
|
|
3224
|
+
process.exit(0);
|
|
3225
|
+
});
|
|
3226
|
+
program.command("osint").description("OSINT / Ethical Hacking mode — configure HyperClaw for security research").argument("[workflow]", "Workflow preset: recon | bugbounty | pentest | footprint | custom").option("--show", "Show current OSINT profile").option("--reset", "Clear OSINT profile and disable OSINT mode").action(async (workflow, opts) => {
|
|
3227
|
+
const { osintSetup, osintQuickStart } = await Promise.resolve().then(() => require("./osint-B4_m3VHQ.js"));
|
|
3228
|
+
if (opts.show || opts.reset) await osintSetup({
|
|
3229
|
+
show: opts.show,
|
|
3230
|
+
reset: opts.reset
|
|
3231
|
+
});
|
|
3232
|
+
else if (workflow === "setup" || workflow) await osintSetup({ mode: workflow });
|
|
3233
|
+
else await osintQuickStart();
|
|
3234
|
+
process.exit(0);
|
|
3235
|
+
});
|
|
3236
|
+
program.command("osint setup").description("Interactive OSINT session setup wizard").action(async () => {
|
|
3237
|
+
const { osintSetup } = await Promise.resolve().then(() => require("./osint-B4_m3VHQ.js"));
|
|
3238
|
+
await osintSetup({});
|
|
2076
3239
|
process.exit(0);
|
|
2077
3240
|
});
|
|
2078
3241
|
const agentRunCmd = program.command("agent").description("Run agent with thinking control");
|
|
2079
3242
|
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-
|
|
3243
|
+
const { runAgent } = await Promise.resolve().then(() => require("./src-Bhybpk1J.js"));
|
|
2081
3244
|
await runAgent({
|
|
2082
3245
|
message: opts.message,
|
|
2083
3246
|
thinking: opts.thinking,
|
|
@@ -2093,7 +3256,7 @@ agentRunCmd.requiredOption("-m, --message <text>", "Message to send to the agent
|
|
|
2093
3256
|
});
|
|
2094
3257
|
const threadsCmd = program.command("threads").description("ACP thread-bound agent sessions");
|
|
2095
3258
|
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-
|
|
3259
|
+
const { ACPThreadManager } = await Promise.resolve().then(() => require("./src-Bhybpk1J.js"));
|
|
2097
3260
|
const mgr = new ACPThreadManager();
|
|
2098
3261
|
const threads = await mgr.list({
|
|
2099
3262
|
channelId: opts.channel,
|
|
@@ -2103,33 +3266,33 @@ threadsCmd.command("list").description("List agent threads").option("--channel <
|
|
|
2103
3266
|
process.exit(0);
|
|
2104
3267
|
});
|
|
2105
3268
|
threadsCmd.command("terminate <id>").description("Terminate a thread").action(async (id) => {
|
|
2106
|
-
const { ACPThreadManager } = await Promise.resolve().then(() => require("./src-
|
|
3269
|
+
const { ACPThreadManager } = await Promise.resolve().then(() => require("./src-Bhybpk1J.js"));
|
|
2107
3270
|
await new ACPThreadManager().terminate(id);
|
|
2108
3271
|
console.log(require("chalk").green(`\n ✔ Thread terminated: ${id}\n`));
|
|
2109
3272
|
process.exit(0);
|
|
2110
3273
|
});
|
|
2111
3274
|
const canvasCmd = program.command("canvas").description("Live AI-driven UI canvas");
|
|
2112
3275
|
canvasCmd.command("show").description("Show current canvas components").action(async () => {
|
|
2113
|
-
const { CanvasRenderer } = await Promise.resolve().then(() => require("./renderer-
|
|
3276
|
+
const { CanvasRenderer } = await Promise.resolve().then(() => require("./renderer-BVQrd0_g.js"));
|
|
2114
3277
|
await new CanvasRenderer().show();
|
|
2115
3278
|
process.exit(0);
|
|
2116
3279
|
});
|
|
2117
3280
|
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-
|
|
3281
|
+
const { CanvasRenderer } = await Promise.resolve().then(() => require("./renderer-BVQrd0_g.js"));
|
|
2119
3282
|
await new CanvasRenderer().addComponent(type, title);
|
|
2120
3283
|
process.exit(0);
|
|
2121
3284
|
});
|
|
2122
3285
|
canvasCmd.command("clear").description("Clear all canvas components").action(async () => {
|
|
2123
|
-
const { CanvasRenderer } = await Promise.resolve().then(() => require("./renderer-
|
|
3286
|
+
const { CanvasRenderer } = await Promise.resolve().then(() => require("./renderer-BVQrd0_g.js"));
|
|
2124
3287
|
await new CanvasRenderer().clear();
|
|
2125
3288
|
process.exit(0);
|
|
2126
3289
|
});
|
|
2127
3290
|
canvasCmd.command("export").description("Export canvas as HTML file").action(async () => {
|
|
2128
|
-
const { CanvasRenderer } = await Promise.resolve().then(() => require("./renderer-
|
|
2129
|
-
const fs$
|
|
3291
|
+
const { CanvasRenderer } = await Promise.resolve().then(() => require("./renderer-BVQrd0_g.js"));
|
|
3292
|
+
const fs$7 = require("fs-extra");
|
|
2130
3293
|
const html = await new CanvasRenderer().exportHtml();
|
|
2131
3294
|
const outFile = require("path").join(require("os").homedir(), ".hyperclaw", "canvas", "export.html");
|
|
2132
|
-
await fs$
|
|
3295
|
+
await fs$7.writeFile(outFile, html);
|
|
2133
3296
|
console.log(require("chalk").green(`\n ✔ Canvas exported to ${outFile}\n`));
|
|
2134
3297
|
process.exit(0);
|
|
2135
3298
|
});
|
|
@@ -2146,167 +3309,167 @@ deliveryCmd.command("retry <id>").description("Retry a dead-lettered delivery it
|
|
|
2146
3309
|
});
|
|
2147
3310
|
const mcpCmd = program.command("mcp").description("MCP (Model Context Protocol) server management");
|
|
2148
3311
|
mcpCmd.command("list").action(async () => {
|
|
2149
|
-
const { mcpList } = await Promise.resolve().then(() => require("./mcp-
|
|
3312
|
+
const { mcpList } = await Promise.resolve().then(() => require("./mcp-CfoSU4Uz.js"));
|
|
2150
3313
|
await mcpList();
|
|
2151
3314
|
process.exit(0);
|
|
2152
3315
|
});
|
|
2153
3316
|
mcpCmd.command("add").action(async () => {
|
|
2154
|
-
const { mcpAdd } = await Promise.resolve().then(() => require("./mcp-
|
|
3317
|
+
const { mcpAdd } = await Promise.resolve().then(() => require("./mcp-CfoSU4Uz.js"));
|
|
2155
3318
|
await mcpAdd();
|
|
2156
3319
|
process.exit(0);
|
|
2157
3320
|
});
|
|
2158
3321
|
mcpCmd.command("remove <id>").action(async (id) => {
|
|
2159
|
-
const { mcpRemove } = await Promise.resolve().then(() => require("./mcp-
|
|
3322
|
+
const { mcpRemove } = await Promise.resolve().then(() => require("./mcp-CfoSU4Uz.js"));
|
|
2160
3323
|
await mcpRemove(id);
|
|
2161
3324
|
process.exit(0);
|
|
2162
3325
|
});
|
|
2163
3326
|
mcpCmd.command("probe [id]").action(async (id) => {
|
|
2164
|
-
const { mcpProbe } = await Promise.resolve().then(() => require("./mcp-
|
|
3327
|
+
const { mcpProbe } = await Promise.resolve().then(() => require("./mcp-CfoSU4Uz.js"));
|
|
2165
3328
|
await mcpProbe(id);
|
|
2166
3329
|
process.exit(0);
|
|
2167
3330
|
});
|
|
2168
3331
|
const nodeCmd = program.command("node").description("HyperClaw node management (local, remote, android)");
|
|
2169
3332
|
nodeCmd.command("list").action(async () => {
|
|
2170
|
-
const { nodeList } = await Promise.resolve().then(() => require("./node-
|
|
3333
|
+
const { nodeList } = await Promise.resolve().then(() => require("./node-Dw2Gi-cP.js"));
|
|
2171
3334
|
await nodeList();
|
|
2172
3335
|
process.exit(0);
|
|
2173
3336
|
});
|
|
2174
3337
|
nodeCmd.command("add").action(async () => {
|
|
2175
|
-
const { nodeAdd } = await Promise.resolve().then(() => require("./node-
|
|
3338
|
+
const { nodeAdd } = await Promise.resolve().then(() => require("./node-Dw2Gi-cP.js"));
|
|
2176
3339
|
await nodeAdd();
|
|
2177
3340
|
process.exit(0);
|
|
2178
3341
|
});
|
|
2179
3342
|
nodeCmd.command("probe [id]").action(async (id) => {
|
|
2180
|
-
const { nodeProbe } = await Promise.resolve().then(() => require("./node-
|
|
3343
|
+
const { nodeProbe } = await Promise.resolve().then(() => require("./node-Dw2Gi-cP.js"));
|
|
2181
3344
|
await nodeProbe(id);
|
|
2182
3345
|
process.exit(0);
|
|
2183
3346
|
});
|
|
2184
3347
|
nodeCmd.command("remove <id>").action(async (id) => {
|
|
2185
|
-
const { nodeRemove } = await Promise.resolve().then(() => require("./node-
|
|
3348
|
+
const { nodeRemove } = await Promise.resolve().then(() => require("./node-Dw2Gi-cP.js"));
|
|
2186
3349
|
await nodeRemove(id);
|
|
2187
3350
|
process.exit(0);
|
|
2188
3351
|
});
|
|
2189
3352
|
const arCmd = program.command("auto-reply").description("Auto-reply rule engine");
|
|
2190
3353
|
arCmd.command("list").action(async () => {
|
|
2191
|
-
const { AutoReplyEngine } = await Promise.resolve().then(() => require("./rules-
|
|
3354
|
+
const { AutoReplyEngine } = await Promise.resolve().then(() => require("./rules-BE4GV6cV.js"));
|
|
2192
3355
|
const e = new AutoReplyEngine();
|
|
2193
3356
|
await e.load();
|
|
2194
3357
|
e.showList();
|
|
2195
3358
|
process.exit(0);
|
|
2196
3359
|
});
|
|
2197
3360
|
arCmd.command("toggle <id>").action(async (id) => {
|
|
2198
|
-
const { AutoReplyEngine } = await Promise.resolve().then(() => require("./rules-
|
|
3361
|
+
const { AutoReplyEngine } = await Promise.resolve().then(() => require("./rules-BE4GV6cV.js"));
|
|
2199
3362
|
const e = new AutoReplyEngine();
|
|
2200
3363
|
await e.toggle(id);
|
|
2201
3364
|
process.exit(0);
|
|
2202
3365
|
});
|
|
2203
3366
|
arCmd.command("remove <id>").action(async (id) => {
|
|
2204
|
-
const { AutoReplyEngine } = await Promise.resolve().then(() => require("./rules-
|
|
3367
|
+
const { AutoReplyEngine } = await Promise.resolve().then(() => require("./rules-BE4GV6cV.js"));
|
|
2205
3368
|
const e = new AutoReplyEngine();
|
|
2206
3369
|
await e.remove(id);
|
|
2207
3370
|
process.exit(0);
|
|
2208
3371
|
});
|
|
2209
3372
|
const gmailCmd = program.command("gmail").description("Gmail Pub/Sub real-time notifications");
|
|
2210
3373
|
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$
|
|
3374
|
+
const chalk$11 = require("chalk");
|
|
2212
3375
|
try {
|
|
2213
|
-
const { setupGmailWatch } = await Promise.resolve().then(() => require("./gmail-watch-setup-
|
|
3376
|
+
const { setupGmailWatch } = await Promise.resolve().then(() => require("./gmail-watch-setup-Du7DVV7S.js"));
|
|
2214
3377
|
const labelIds = opts.labels.split(",").map((s) => s.trim()).filter(Boolean);
|
|
2215
3378
|
const result = await setupGmailWatch({
|
|
2216
3379
|
topicName: opts.topic,
|
|
2217
3380
|
labelIds
|
|
2218
3381
|
});
|
|
2219
|
-
console.log(chalk$
|
|
2220
|
-
console.log(chalk$
|
|
2221
|
-
console.log(chalk$
|
|
2222
|
-
console.log(chalk$
|
|
2223
|
-
console.log(chalk$
|
|
3382
|
+
console.log(chalk$11.hex("#06b6d4")("\n ✔ Gmail watch registered"));
|
|
3383
|
+
console.log(chalk$11.gray(` historyId: ${result.historyId}`));
|
|
3384
|
+
console.log(chalk$11.gray(` expiration: ${new Date(parseInt(result.expiration, 10)).toISOString()}`));
|
|
3385
|
+
console.log(chalk$11.gray("\n Push endpoint: https://<your-server>/webhook/gmail-pubsub"));
|
|
3386
|
+
console.log(chalk$11.gray(" Ensure email channel is enabled and gateway is publicly accessible.\n"));
|
|
2224
3387
|
} catch (e) {
|
|
2225
|
-
console.error(chalk$
|
|
3388
|
+
console.error(chalk$11.red("\n ✖ " + e.message + "\n"));
|
|
2226
3389
|
process.exit(1);
|
|
2227
3390
|
}
|
|
2228
3391
|
process.exit(0);
|
|
2229
3392
|
});
|
|
2230
3393
|
const cronCmd = program.command("cron").description("Scheduled tasks (cron → agent prompt)");
|
|
2231
3394
|
cronCmd.command("list").action(async () => {
|
|
2232
|
-
const chalk$
|
|
2233
|
-
const { loadCronTasks } = await Promise.resolve().then(() => require("./cron-tasks-
|
|
3395
|
+
const chalk$11 = require("chalk");
|
|
3396
|
+
const { loadCronTasks } = await Promise.resolve().then(() => require("./cron-tasks-_pqQCmxc.js"));
|
|
2234
3397
|
const tasks = await loadCronTasks();
|
|
2235
|
-
console.log(chalk$
|
|
3398
|
+
console.log(chalk$11.bold.cyan("\n ⏰ CRON TASKS\n"));
|
|
2236
3399
|
if (tasks.length === 0) {
|
|
2237
|
-
console.log(chalk$
|
|
3400
|
+
console.log(chalk$11.gray(" No tasks. Add: hyperclaw cron add \"0 9 * * 1-5\" \"Check calendar\"\n"));
|
|
2238
3401
|
process.exit(0);
|
|
2239
3402
|
return;
|
|
2240
3403
|
}
|
|
2241
3404
|
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$
|
|
3405
|
+
const dot = t.enabled ? chalk$11.green("●") : chalk$11.gray("○");
|
|
3406
|
+
console.log(` ${dot} ${chalk$11.white(t.name || t.id)}`);
|
|
3407
|
+
console.log(` ${chalk$11.gray("Schedule:")} ${t.schedule}`);
|
|
3408
|
+
console.log(` ${chalk$11.gray("Prompt:")} ${t.prompt.slice(0, 60)}${t.prompt.length > 60 ? "..." : ""}`);
|
|
3409
|
+
if (t.lastRunAt) console.log(` ${chalk$11.gray("Last run:")} ${t.lastRunAt}`);
|
|
2247
3410
|
console.log();
|
|
2248
3411
|
}
|
|
2249
3412
|
process.exit(0);
|
|
2250
3413
|
});
|
|
2251
3414
|
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-
|
|
3415
|
+
const chalk$11 = require("chalk");
|
|
3416
|
+
const { loadCronTasks, addCronTask, saveCronTasks } = await Promise.resolve().then(() => require("./cron-tasks-_pqQCmxc.js"));
|
|
2254
3417
|
await loadCronTasks();
|
|
2255
3418
|
addCronTask(schedule, prompt, opts.name);
|
|
2256
3419
|
await saveCronTasks();
|
|
2257
|
-
console.log(chalk$
|
|
2258
|
-
console.log(chalk$
|
|
3420
|
+
console.log(chalk$11.green(`\n ✔ Cron task added: ${schedule} → "${prompt.slice(0, 40)}..."\n`));
|
|
3421
|
+
console.log(chalk$11.gray(" Restart gateway to apply.\n"));
|
|
2259
3422
|
process.exit(0);
|
|
2260
3423
|
});
|
|
2261
3424
|
cronCmd.command("remove <id>").action(async (id) => {
|
|
2262
|
-
const chalk$
|
|
2263
|
-
const { loadCronTasks, removeCronTask, saveCronTasks } = await Promise.resolve().then(() => require("./cron-tasks-
|
|
3425
|
+
const chalk$11 = require("chalk");
|
|
3426
|
+
const { loadCronTasks, removeCronTask, saveCronTasks } = await Promise.resolve().then(() => require("./cron-tasks-_pqQCmxc.js"));
|
|
2264
3427
|
await loadCronTasks();
|
|
2265
3428
|
if (removeCronTask(id)) {
|
|
2266
3429
|
await saveCronTasks();
|
|
2267
|
-
console.log(chalk$
|
|
2268
|
-
} else console.log(chalk$
|
|
3430
|
+
console.log(chalk$11.green(`\n ✔ Task removed\n`));
|
|
3431
|
+
} else console.log(chalk$11.red(`\n ✖ Task not found: ${id}\n`));
|
|
2269
3432
|
process.exit(0);
|
|
2270
3433
|
});
|
|
2271
3434
|
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$
|
|
3435
|
+
const chalk$11 = require("chalk");
|
|
3436
|
+
const http$2 = await import("http");
|
|
3437
|
+
const fs$7 = await import("fs-extra");
|
|
3438
|
+
const path$7 = await import("path");
|
|
3439
|
+
const os$8 = await import("os");
|
|
2277
3440
|
let port = 18789;
|
|
2278
3441
|
try {
|
|
2279
|
-
const cfg = await fs$
|
|
3442
|
+
const cfg = await fs$7.readJson(path$7.join(os$8.homedir(), ".hyperclaw", "hyperclaw.json"));
|
|
2280
3443
|
port = cfg?.gateway?.port ?? 18789;
|
|
2281
3444
|
} catch {}
|
|
2282
3445
|
return new Promise((resolve, reject) => {
|
|
2283
|
-
const req = http.get(`http://127.0.0.1:${port}/api/nodes`, (res) => {
|
|
3446
|
+
const req = http$2.get(`http://127.0.0.1:${port}/api/nodes`, (res) => {
|
|
2284
3447
|
let data = "";
|
|
2285
3448
|
res.on("data", (c) => data += c);
|
|
2286
3449
|
res.on("end", () => {
|
|
2287
3450
|
try {
|
|
2288
3451
|
const j = JSON.parse(data);
|
|
2289
3452
|
const nodes = j.nodes || [];
|
|
2290
|
-
console.log(chalk$
|
|
3453
|
+
console.log(chalk$11.bold.cyan("\n 📱 CONNECTED NODES\n"));
|
|
2291
3454
|
if (nodes.length === 0) {
|
|
2292
|
-
console.log(chalk$
|
|
2293
|
-
console.log(chalk$
|
|
3455
|
+
console.log(chalk$11.gray(" No mobile nodes. Open iOS/Android app → Connect tab → pair with gateway."));
|
|
3456
|
+
console.log(chalk$11.gray(` Gateway: ws://localhost:${port}\n`));
|
|
2294
3457
|
} else {
|
|
2295
3458
|
for (const n of nodes) {
|
|
2296
|
-
console.log(` ${chalk$
|
|
2297
|
-
console.log(` ${chalk$
|
|
2298
|
-
console.log(` ${chalk$
|
|
3459
|
+
console.log(` ${chalk$11.green("●")} ${n.nodeId} ${chalk$11.gray(`(${n.platform || "?"})`)}`);
|
|
3460
|
+
console.log(` ${chalk$11.gray("Device:")} ${n.deviceName || "—"}`);
|
|
3461
|
+
console.log(` ${chalk$11.gray("Capabilities:")} ${Object.entries(n.capabilities || {}).filter(([, v]) => v).map(([k]) => k).join(", ") || "—"}`);
|
|
2299
3462
|
}
|
|
2300
3463
|
console.log();
|
|
2301
3464
|
}
|
|
2302
3465
|
} catch {
|
|
2303
|
-
console.log(chalk$
|
|
3466
|
+
console.log(chalk$11.red(" Could not reach gateway. Start with: hyperclaw daemon start\n"));
|
|
2304
3467
|
}
|
|
2305
3468
|
resolve();
|
|
2306
3469
|
});
|
|
2307
3470
|
});
|
|
2308
3471
|
req.on("error", () => {
|
|
2309
|
-
console.log(chalk$
|
|
3472
|
+
console.log(chalk$11.red(" Gateway offline. Start with: hyperclaw daemon start\n"));
|
|
2310
3473
|
resolve();
|
|
2311
3474
|
});
|
|
2312
3475
|
req.setTimeout(3e3, () => {
|
|
@@ -2317,20 +3480,20 @@ program.command("nodes").description("List connected mobile nodes (iOS/Android C
|
|
|
2317
3480
|
});
|
|
2318
3481
|
const whCmd = program.command("webhooks").description("Webhook endpoint management");
|
|
2319
3482
|
whCmd.command("list").action(async () => {
|
|
2320
|
-
const { WebhookManager } = await Promise.resolve().then(() => require("./manager-
|
|
3483
|
+
const { WebhookManager } = await Promise.resolve().then(() => require("./manager-CWNSML5D.js"));
|
|
2321
3484
|
const m = new WebhookManager();
|
|
2322
3485
|
await m.load();
|
|
2323
3486
|
m.showList();
|
|
2324
3487
|
process.exit(0);
|
|
2325
3488
|
});
|
|
2326
3489
|
whCmd.command("remove <id>").action(async (id) => {
|
|
2327
|
-
const { WebhookManager } = await Promise.resolve().then(() => require("./manager-
|
|
3490
|
+
const { WebhookManager } = await Promise.resolve().then(() => require("./manager-CWNSML5D.js"));
|
|
2328
3491
|
const m = new WebhookManager();
|
|
2329
3492
|
await m.remove(id);
|
|
2330
3493
|
process.exit(0);
|
|
2331
3494
|
});
|
|
2332
3495
|
whCmd.command("toggle <id>").action(async (id) => {
|
|
2333
|
-
const { WebhookManager } = await Promise.resolve().then(() => require("./manager-
|
|
3496
|
+
const { WebhookManager } = await Promise.resolve().then(() => require("./manager-CWNSML5D.js"));
|
|
2334
3497
|
const m = new WebhookManager();
|
|
2335
3498
|
await m.toggle(id);
|
|
2336
3499
|
process.exit(0);
|
|
@@ -2339,7 +3502,7 @@ const logsCmd = program.command("logs").description("View gateway logs");
|
|
|
2339
3502
|
logsCmd.option("-n, --lines <n>", "Number of lines to show", "50");
|
|
2340
3503
|
logsCmd.option("-f, --follow", "Stream logs in real time");
|
|
2341
3504
|
logsCmd.action(async (opts) => {
|
|
2342
|
-
const { tailLog, streamLog } = await Promise.resolve().then(() => require("./logger-
|
|
3505
|
+
const { tailLog, streamLog } = await Promise.resolve().then(() => require("./logger-Cp8wC7F8.js"));
|
|
2343
3506
|
if (opts.follow) await streamLog();
|
|
2344
3507
|
else {
|
|
2345
3508
|
await tailLog(parseInt(opts.lines));
|
|
@@ -2347,7 +3510,7 @@ logsCmd.action(async (opts) => {
|
|
|
2347
3510
|
}
|
|
2348
3511
|
});
|
|
2349
3512
|
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-
|
|
3513
|
+
const { startGateway } = await Promise.resolve().then(() => require("./server-DhfipkwN.js"));
|
|
2351
3514
|
await startGateway();
|
|
2352
3515
|
process.on("SIGINT", () => process.exit(0));
|
|
2353
3516
|
process.on("SIGTERM", () => process.exit(0));
|
|
@@ -2355,15 +3518,15 @@ program.command("gateway:serve").description("Start the gateway server in the fo
|
|
|
2355
3518
|
});
|
|
2356
3519
|
const gatewayCfgCmd = gatewayCmd.command("config").description("Configure gateway settings");
|
|
2357
3520
|
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$
|
|
3521
|
+
const chalk$11 = require("chalk");
|
|
3522
|
+
const fs$7 = require("fs-extra");
|
|
3523
|
+
const path$7 = require("path");
|
|
3524
|
+
const os$8 = require("os");
|
|
3525
|
+
const crypto$2 = require("crypto");
|
|
3526
|
+
const cfgFile = path$7.join(os$8.homedir(), ".hyperclaw", "hyperclaw.json");
|
|
2364
3527
|
let cfg = {};
|
|
2365
3528
|
try {
|
|
2366
|
-
cfg = await fs$
|
|
3529
|
+
cfg = await fs$7.readJson(cfgFile);
|
|
2367
3530
|
} catch {}
|
|
2368
3531
|
if (!cfg.gateway) cfg.gateway = {
|
|
2369
3532
|
port: 18789,
|
|
@@ -2374,48 +3537,48 @@ gatewayCfgCmd.option("--set-token <token>", "Set gateway auth token").option("--
|
|
|
2374
3537
|
hooks: true
|
|
2375
3538
|
};
|
|
2376
3539
|
if (opts.regenerateToken) {
|
|
2377
|
-
cfg.gateway.authToken = crypto.randomBytes(32).toString("hex");
|
|
2378
|
-
console.log(chalk$
|
|
2379
|
-
console.log(chalk$
|
|
3540
|
+
cfg.gateway.authToken = crypto$2.randomBytes(32).toString("hex");
|
|
3541
|
+
console.log(chalk$11.hex("#06b6d4")("\n ✔ New gateway token generated"));
|
|
3542
|
+
console.log(chalk$11.gray(` Token: ${cfg.gateway.authToken}`));
|
|
2380
3543
|
}
|
|
2381
3544
|
if (opts.setToken) {
|
|
2382
3545
|
cfg.gateway.authToken = opts.setToken;
|
|
2383
|
-
console.log(chalk$
|
|
3546
|
+
console.log(chalk$11.hex("#06b6d4")(`\n ✔ Gateway token set`));
|
|
2384
3547
|
}
|
|
2385
3548
|
if (opts.setPort) {
|
|
2386
3549
|
cfg.gateway.port = parseInt(opts.setPort);
|
|
2387
|
-
console.log(chalk$
|
|
3550
|
+
console.log(chalk$11.hex("#06b6d4")(`\n ✔ Port set to ${cfg.gateway.port}`));
|
|
2388
3551
|
}
|
|
2389
3552
|
if (opts.setBind) {
|
|
2390
3553
|
cfg.gateway.bind = opts.setBind;
|
|
2391
|
-
console.log(chalk$
|
|
3554
|
+
console.log(chalk$11.hex("#06b6d4")(`\n ✔ Bind set to ${cfg.gateway.bind}`));
|
|
2392
3555
|
}
|
|
2393
|
-
await fs$
|
|
2394
|
-
await fs$
|
|
2395
|
-
await fs$
|
|
2396
|
-
console.log(chalk$
|
|
3556
|
+
await fs$7.ensureDir(path$7.dirname(cfgFile));
|
|
3557
|
+
await fs$7.writeJson(cfgFile, cfg, { spaces: 2 });
|
|
3558
|
+
await fs$7.chmod(cfgFile, 384);
|
|
3559
|
+
console.log(chalk$11.gray(` Saved to ${cfgFile}\n`));
|
|
2397
3560
|
process.exit(0);
|
|
2398
3561
|
});
|
|
2399
3562
|
const authCmd = program.command("auth").description("OAuth and provider credentials");
|
|
2400
3563
|
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$
|
|
3564
|
+
const chalk$11 = require("chalk");
|
|
2402
3565
|
const inquirer$2 = require("inquirer");
|
|
2403
|
-
const { CredentialsStore } = await Promise.resolve().then(() => require("./credentials-store-
|
|
3566
|
+
const { CredentialsStore } = await Promise.resolve().then(() => require("./credentials-store-Cm7DH-kh.js"));
|
|
2404
3567
|
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$
|
|
3568
|
+
const { getApiKeyGuide, GENERIC_API_KEY_STEPS } = await Promise.resolve().then(() => require("./api-keys-guide-CGn5BSF7.js"));
|
|
3569
|
+
const fs$7 = await import("fs-extra");
|
|
3570
|
+
const path$7 = await import("path");
|
|
2408
3571
|
const guide = getApiKeyGuide(serviceId);
|
|
2409
3572
|
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$
|
|
3573
|
+
console.log(chalk$11.bold.hex("#06b6d4")(`\n 🔑 Add API key: ${guide?.name ?? serviceId}\n`));
|
|
3574
|
+
console.log(chalk$11.bold(" Steps:\n"));
|
|
3575
|
+
for (const step of steps) if (step.startsWith(" 🔗")) console.log(chalk$11.hex("#06b6d4")(step));
|
|
3576
|
+
else if (step.startsWith(" 💡")) console.log(chalk$11.gray(step));
|
|
3577
|
+
else console.log(chalk$11.gray(` ${step}`));
|
|
2415
3578
|
console.log();
|
|
2416
3579
|
const safeId = serviceId.replace(/[^a-zA-Z0-9_-]/g, "_").toLowerCase();
|
|
2417
3580
|
if (!safeId) {
|
|
2418
|
-
console.log(chalk$
|
|
3581
|
+
console.log(chalk$11.red("\n ✖ Invalid service ID\n"));
|
|
2419
3582
|
process.exit(1);
|
|
2420
3583
|
}
|
|
2421
3584
|
let apiKey = opts.key || process.env[`${safeId.toUpperCase().replace(/-/g, "_")}_API_KEY`];
|
|
@@ -2437,44 +3600,44 @@ authCmd.command("add <service_id>").description("Add API key for a service (any
|
|
|
2437
3600
|
});
|
|
2438
3601
|
const envVar = opts.envVar || `${safeId.toUpperCase().replace(/-/g, "_")}_API_KEY`;
|
|
2439
3602
|
const envPath = getEnvFilePath();
|
|
2440
|
-
await fs$
|
|
3603
|
+
await fs$7.ensureDir(path$7.dirname(envPath));
|
|
2441
3604
|
let envContent = "";
|
|
2442
|
-
if (await fs$
|
|
3605
|
+
if (await fs$7.pathExists(envPath)) envContent = await fs$7.readFile(envPath, "utf8");
|
|
2443
3606
|
const envLine = `${envVar}=${apiKey}`;
|
|
2444
3607
|
const re = new RegExp(`^${envVar}=.*$`, "m");
|
|
2445
3608
|
if (re.test(envContent)) envContent = envContent.replace(re, envLine);
|
|
2446
3609
|
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$
|
|
3610
|
+
await fs$7.writeFile(envPath, envContent, { mode: 384 });
|
|
3611
|
+
console.log(chalk$11.hex("#06b6d4")(`\n ✔ Added: ${safeId}`));
|
|
3612
|
+
console.log(chalk$11.gray(` Credentials: ~/.hyperclaw/credentials/${safeId}.json`));
|
|
3613
|
+
console.log(chalk$11.gray(` Env: ${envVar} (in .env — use in skills via process.env.${envVar.replace(/-/g, "_")})`));
|
|
3614
|
+
console.log(chalk$11.gray("\n Run: hyperclaw secrets apply to add to shell"));
|
|
3615
|
+
console.log(chalk$11.gray(" Run: hyperclaw secrets reload to inject into running gateway\n"));
|
|
2453
3616
|
process.exit(0);
|
|
2454
3617
|
});
|
|
2455
3618
|
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-
|
|
3619
|
+
const chalk$11 = require("chalk");
|
|
3620
|
+
const { CredentialsStore } = await Promise.resolve().then(() => require("./credentials-store-Cm7DH-kh.js"));
|
|
2458
3621
|
const { getHyperClawDir, getEnvFilePath } = await Promise.resolve().then(() => require("./paths-D-QecARF.js"));
|
|
2459
|
-
const fs$
|
|
3622
|
+
const fs$7 = await import("fs-extra");
|
|
2460
3623
|
const safeId = serviceId.replace(/[^a-zA-Z0-9_-]/g, "_").toLowerCase();
|
|
2461
3624
|
const creds = new CredentialsStore(getHyperClawDir());
|
|
2462
3625
|
await creds.remove(safeId);
|
|
2463
3626
|
const envVar = `${safeId.toUpperCase().replace(/-/g, "_")}_API_KEY`;
|
|
2464
3627
|
const envPath = getEnvFilePath();
|
|
2465
|
-
if (await fs$
|
|
2466
|
-
let c = await fs$
|
|
3628
|
+
if (await fs$7.pathExists(envPath)) {
|
|
3629
|
+
let c = await fs$7.readFile(envPath, "utf8");
|
|
2467
3630
|
c = c.replace(new RegExp(`^${envVar}=.*\n?`, "gm"), "");
|
|
2468
|
-
await fs$
|
|
3631
|
+
await fs$7.writeFile(envPath, c);
|
|
2469
3632
|
}
|
|
2470
|
-
console.log(chalk$
|
|
3633
|
+
console.log(chalk$11.hex("#06b6d4")(`\n ✔ Removed: ${safeId}\n`));
|
|
2471
3634
|
process.exit(0);
|
|
2472
3635
|
});
|
|
2473
3636
|
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$
|
|
3637
|
+
const chalk$11 = require("chalk");
|
|
2475
3638
|
const ora$4 = (await import("ora")).default;
|
|
2476
3639
|
try {
|
|
2477
|
-
const { runOAuthFlow } = await Promise.resolve().then(() => require("./oauth-flow-
|
|
3640
|
+
const { runOAuthFlow } = await Promise.resolve().then(() => require("./oauth-flow-CeaaGAz0.js"));
|
|
2478
3641
|
const spinner = ora$4("Starting OAuth flow...").start();
|
|
2479
3642
|
spinner.text = "Opening browser — complete the consent and return here.";
|
|
2480
3643
|
const tokens = await runOAuthFlow(provider, {
|
|
@@ -2482,7 +3645,7 @@ authCmd.command("oauth <provider>").description("Run full OAuth flow. Providers:
|
|
|
2482
3645
|
clientSecret: opts.clientSecret
|
|
2483
3646
|
});
|
|
2484
3647
|
spinner.stop();
|
|
2485
|
-
const { writeOAuthToken } = await Promise.resolve().then(() => require("./oauth-provider-
|
|
3648
|
+
const { writeOAuthToken } = await Promise.resolve().then(() => require("./oauth-provider-B4dzn56l.js"));
|
|
2486
3649
|
const now = Math.floor(Date.now() / 1e3);
|
|
2487
3650
|
const expires_at = tokens.expires_in ? now + tokens.expires_in : void 0;
|
|
2488
3651
|
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 +3655,19 @@ authCmd.command("oauth <provider>").description("Run full OAuth flow. Providers:
|
|
|
2492
3655
|
expires_at,
|
|
2493
3656
|
token_url: tokenUrl
|
|
2494
3657
|
});
|
|
2495
|
-
console.log(chalk$
|
|
2496
|
-
console.log(chalk$
|
|
3658
|
+
console.log(chalk$11.hex("#06b6d4")(`\n ✔ OAuth tokens saved for: ${provider}`));
|
|
3659
|
+
console.log(chalk$11.gray(" Set in hyperclaw.json: \"provider\": { \"authType\": \"oauth\", \"providerId\": \"" + provider + "\" }\n"));
|
|
2497
3660
|
} catch (e) {
|
|
2498
|
-
console.error(chalk$
|
|
3661
|
+
console.error(chalk$11.red("\n ✖ OAuth failed: " + e.message + "\n"));
|
|
2499
3662
|
process.exit(1);
|
|
2500
3663
|
}
|
|
2501
3664
|
process.exit(0);
|
|
2502
3665
|
});
|
|
2503
3666
|
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$
|
|
3667
|
+
const chalk$11 = require("chalk");
|
|
2505
3668
|
const inquirer$2 = await import("inquirer");
|
|
2506
3669
|
if (provider !== "anthropic") {
|
|
2507
|
-
console.log(chalk$
|
|
3670
|
+
console.log(chalk$11.yellow(`\n Provider "${provider}" may not support setup-token. Use "hyperclaw auth add" for API keys.\n`));
|
|
2508
3671
|
process.exit(1);
|
|
2509
3672
|
}
|
|
2510
3673
|
const { token } = await inquirer$2.default.prompt([{
|
|
@@ -2514,24 +3677,24 @@ authCmd.command("setup-token <provider>").description("Save setup token (Anthrop
|
|
|
2514
3677
|
mask: "●"
|
|
2515
3678
|
}]);
|
|
2516
3679
|
if (!token?.trim()) {
|
|
2517
|
-
console.log(chalk$
|
|
3680
|
+
console.log(chalk$11.red("\n ✖ No token provided.\n"));
|
|
2518
3681
|
process.exit(1);
|
|
2519
3682
|
}
|
|
2520
|
-
const { writeOAuthToken } = await Promise.resolve().then(() => require("./oauth-provider-
|
|
3683
|
+
const { writeOAuthToken } = await Promise.resolve().then(() => require("./oauth-provider-B4dzn56l.js"));
|
|
2521
3684
|
await writeOAuthToken("anthropic-setup", {
|
|
2522
3685
|
access_token: token.trim(),
|
|
2523
3686
|
token_url: "https://api.anthropic.com"
|
|
2524
3687
|
});
|
|
2525
|
-
console.log(chalk$
|
|
2526
|
-
console.log(chalk$
|
|
3688
|
+
console.log(chalk$11.hex("#06b6d4")("\n ✔ Anthropic setup token saved to ~/.hyperclaw/oauth-anthropic-setup.json"));
|
|
3689
|
+
console.log(chalk$11.gray(" Use providerId: anthropic with authType: oauth and oauthTokenPath for Claude Pro/Max.\n"));
|
|
2527
3690
|
process.exit(0);
|
|
2528
3691
|
});
|
|
2529
3692
|
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-
|
|
3693
|
+
const chalk$11 = require("chalk");
|
|
3694
|
+
const { writeOAuthToken } = await Promise.resolve().then(() => require("./oauth-provider-B4dzn56l.js"));
|
|
2532
3695
|
const access_token = opts.token || process.env.OAUTH_ACCESS_TOKEN;
|
|
2533
3696
|
if (!access_token) {
|
|
2534
|
-
console.log(chalk$
|
|
3697
|
+
console.log(chalk$11.red("\n ✖ Provide --token <access_token> or set OAUTH_ACCESS_TOKEN\n"));
|
|
2535
3698
|
process.exit(1);
|
|
2536
3699
|
}
|
|
2537
3700
|
const expires_at = opts.expiresIn ? Math.floor(Date.now() / 1e3) + parseInt(opts.expiresIn, 10) : void 0;
|
|
@@ -2541,22 +3704,22 @@ authCmd.command("oauth-set <provider>").description("Save OAuth tokens manually
|
|
|
2541
3704
|
expires_at,
|
|
2542
3705
|
token_url: opts.tokenUrl || void 0
|
|
2543
3706
|
});
|
|
2544
|
-
console.log(chalk$
|
|
2545
|
-
console.log(chalk$
|
|
3707
|
+
console.log(chalk$11.hex("#06b6d4")(`\n ✔ OAuth tokens saved for provider: ${provider}`));
|
|
3708
|
+
console.log(chalk$11.gray(" Set in hyperclaw.json: \"provider\": { \"authType\": \"oauth\", \"providerId\": \"" + provider + "\" }\n"));
|
|
2546
3709
|
process.exit(0);
|
|
2547
3710
|
});
|
|
2548
3711
|
const workspaceCmd = program.command("workspace").description("Manage agent workspace files");
|
|
2549
3712
|
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$
|
|
3713
|
+
const chalk$11 = require("chalk");
|
|
3714
|
+
const fs$7 = require("fs-extra");
|
|
3715
|
+
const path$7 = require("path");
|
|
3716
|
+
const os$8 = require("os");
|
|
3717
|
+
const targetDir = dir || path$7.join(os$8.homedir(), ".hyperclaw");
|
|
2555
3718
|
let cfg = {};
|
|
2556
3719
|
try {
|
|
2557
|
-
cfg = await fs$
|
|
3720
|
+
cfg = await fs$7.readJson(path$7.join(os$8.homedir(), ".hyperclaw", "hyperclaw.json"));
|
|
2558
3721
|
} catch {}
|
|
2559
|
-
const { initWorkspaceFiles } = await Promise.resolve().then(() => require("./memory-
|
|
3722
|
+
const { initWorkspaceFiles } = await Promise.resolve().then(() => require("./memory-BlHL7JCO.js"));
|
|
2560
3723
|
await initWorkspaceFiles({
|
|
2561
3724
|
agentName: cfg.identity?.agentName || "Hyper",
|
|
2562
3725
|
personality: cfg.identity?.personality || "helpful and concise",
|
|
@@ -2564,17 +3727,17 @@ workspaceCmd.command("init [dir]").description("Initialize workspace files (SOUL
|
|
|
2564
3727
|
userName: cfg.identity?.userName || "User",
|
|
2565
3728
|
rules: cfg.identity?.rules ?? []
|
|
2566
3729
|
}, targetDir);
|
|
2567
|
-
console.log(chalk$
|
|
2568
|
-
console.log(chalk$
|
|
3730
|
+
console.log(chalk$11.hex("#06b6d4")(`\n ✔ Workspace files initialized in ${targetDir}`));
|
|
3731
|
+
console.log(chalk$11.gray(" Files: SOUL.md USER.md TOOLS.md HEARTBEAT.md BOOTSTRAP.md\n"));
|
|
2569
3732
|
process.exit(0);
|
|
2570
3733
|
});
|
|
2571
3734
|
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$
|
|
3735
|
+
const chalk$11 = require("chalk");
|
|
3736
|
+
const fs$7 = require("fs-extra");
|
|
3737
|
+
const path$7 = require("path");
|
|
3738
|
+
const os$8 = require("os");
|
|
3739
|
+
const targetDir = dir || path$7.join(os$8.homedir(), ".hyperclaw");
|
|
3740
|
+
console.log(chalk$11.bold.hex("#06b6d4")("\n 📁 WORKSPACE\n"));
|
|
2578
3741
|
for (const fname of [
|
|
2579
3742
|
"SOUL.md",
|
|
2580
3743
|
"USER.md",
|
|
@@ -2584,27 +3747,27 @@ workspaceCmd.command("show [dir]").description("Show workspace files summary").a
|
|
|
2584
3747
|
"AGENTS.md",
|
|
2585
3748
|
"MEMORY.md"
|
|
2586
3749
|
]) {
|
|
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$
|
|
3750
|
+
const fpath = path$7.join(targetDir, fname);
|
|
3751
|
+
const exists = await fs$7.pathExists(fpath);
|
|
3752
|
+
const size = exists ? (await fs$7.stat(fpath)).size : 0;
|
|
3753
|
+
const dot = exists ? chalk$11.hex("#06b6d4")("✔") : chalk$11.gray("○");
|
|
3754
|
+
console.log(` ${dot} ${fname.padEnd(14)} ${exists ? chalk$11.gray(`${size} bytes`) : chalk$11.gray("(missing)")}`);
|
|
2592
3755
|
}
|
|
2593
3756
|
console.log();
|
|
2594
3757
|
process.exit(0);
|
|
2595
3758
|
});
|
|
2596
3759
|
const botCmd = program.command("bot").description("HyperClaw Bot — companion bot for remote gateway control");
|
|
2597
3760
|
botCmd.command("status").action(async () => {
|
|
2598
|
-
const { showBotStatus } = await Promise.resolve().then(() => require("./hyperclawbot-
|
|
3761
|
+
const { showBotStatus } = await Promise.resolve().then(() => require("./hyperclawbot-CBiDSKsa.js"));
|
|
2599
3762
|
await showBotStatus();
|
|
2600
3763
|
process.exit(0);
|
|
2601
3764
|
});
|
|
2602
3765
|
botCmd.command("setup").description("Configure HyperClaw Bot (Telegram token, allowed users)").action(async () => {
|
|
2603
3766
|
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$
|
|
3767
|
+
const { saveBotConfig } = await Promise.resolve().then(() => require("./hyperclawbot-CBiDSKsa.js"));
|
|
3768
|
+
const chalk$11 = require("chalk");
|
|
3769
|
+
console.log(chalk$11.bold.hex("#06b6d4")("\n 🦅 HYPERCLAW BOT SETUP\n"));
|
|
3770
|
+
console.log(chalk$11.gray(" Create a bot at t.me/BotFather, then paste the token below.\n"));
|
|
2608
3771
|
const { platform } = await inquirer$2.prompt([{
|
|
2609
3772
|
type: "list",
|
|
2610
3773
|
name: "platform",
|
|
@@ -2638,20 +3801,20 @@ botCmd.command("setup").description("Configure HyperClaw Bot (Telegram token, al
|
|
|
2638
3801
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2639
3802
|
};
|
|
2640
3803
|
await saveBotConfig(cfg);
|
|
2641
|
-
console.log(chalk$
|
|
3804
|
+
console.log(chalk$11.hex("#06b6d4")("\n ✔ HyperClaw Bot configured"));
|
|
2642
3805
|
if (platform === "discord") try {
|
|
2643
3806
|
require.resolve("discord.js");
|
|
2644
3807
|
} catch {
|
|
2645
|
-
console.log(chalk$
|
|
3808
|
+
console.log(chalk$11.yellow(" ⚠ For Discord: run: npm install discord.js"));
|
|
2646
3809
|
}
|
|
2647
|
-
console.log(chalk$
|
|
3810
|
+
console.log(chalk$11.gray(" Start with: hyperclaw bot start\n"));
|
|
2648
3811
|
process.exit(0);
|
|
2649
3812
|
});
|
|
2650
3813
|
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
3814
|
const { spawn } = await import("child_process");
|
|
2652
|
-
const path$
|
|
3815
|
+
const path$7 = await import("path");
|
|
2653
3816
|
if (opts?.background) {
|
|
2654
|
-
const entry = process.argv[1] || path$
|
|
3817
|
+
const entry = process.argv[1] || path$7.join(__dirname, "run-main.js");
|
|
2655
3818
|
const child = spawn(process.execPath, [
|
|
2656
3819
|
entry,
|
|
2657
3820
|
"bot",
|
|
@@ -2663,14 +3826,14 @@ botCmd.command("start").description("Start HyperClaw Bot (foreground or backgrou
|
|
|
2663
3826
|
cwd: process.cwd()
|
|
2664
3827
|
});
|
|
2665
3828
|
child.unref();
|
|
2666
|
-
const { writeBotPid } = await Promise.resolve().then(() => require("./hyperclawbot-
|
|
3829
|
+
const { writeBotPid } = await Promise.resolve().then(() => require("./hyperclawbot-CBiDSKsa.js"));
|
|
2667
3830
|
await writeBotPid(child.pid);
|
|
2668
3831
|
console.log(require("chalk").green(`\n ✔ HyperClaw Bot started in background (PID ${child.pid})`));
|
|
2669
3832
|
console.log(require("chalk").gray(" Stop with: hyperclaw bot stop\n"));
|
|
2670
3833
|
process.exit(0);
|
|
2671
3834
|
return;
|
|
2672
3835
|
}
|
|
2673
|
-
const { loadBotConfig, TelegramHyperClawBot, DiscordHyperClawBot } = await Promise.resolve().then(() => require("./hyperclawbot-
|
|
3836
|
+
const { loadBotConfig, TelegramHyperClawBot, DiscordHyperClawBot } = await Promise.resolve().then(() => require("./hyperclawbot-CBiDSKsa.js"));
|
|
2674
3837
|
const cfg = await loadBotConfig();
|
|
2675
3838
|
if (!cfg) {
|
|
2676
3839
|
console.log(require("chalk").red("\n ✖ HyperClaw Bot not configured. Run: hyperclaw bot setup\n"));
|
|
@@ -2696,42 +3859,42 @@ botCmd.command("start").description("Start HyperClaw Bot (foreground or backgrou
|
|
|
2696
3859
|
}
|
|
2697
3860
|
});
|
|
2698
3861
|
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-
|
|
3862
|
+
const chalk$11 = require("chalk");
|
|
3863
|
+
const { stopBotProcess } = await Promise.resolve().then(() => require("./hyperclawbot-CBiDSKsa.js"));
|
|
2701
3864
|
const stopped = await stopBotProcess();
|
|
2702
|
-
if (stopped) console.log(chalk$
|
|
2703
|
-
else console.log(chalk$
|
|
3865
|
+
if (stopped) console.log(chalk$11.green("\n ✔ HyperClaw Bot stopped\n"));
|
|
3866
|
+
else console.log(chalk$11.gray("\n Bot not running in background (no PID file). Use Ctrl+C to stop foreground bot.\n"));
|
|
2704
3867
|
process.exit(stopped ? 0 : 0);
|
|
2705
3868
|
});
|
|
2706
3869
|
memCmd.command("search <query>").description("Search MEMORY.md").action(async (query) => {
|
|
2707
|
-
const { searchMemory } = await Promise.resolve().then(() => require("./src-
|
|
3870
|
+
const { searchMemory } = await Promise.resolve().then(() => require("./src-Bhybpk1J.js"));
|
|
2708
3871
|
await searchMemory(query);
|
|
2709
3872
|
process.exit(0);
|
|
2710
3873
|
});
|
|
2711
3874
|
memCmd.command("auto-show").description("Show auto-extracted memories from MEMORY.md").action(async () => {
|
|
2712
|
-
const { showMemory } = await Promise.resolve().then(() => require("./src-
|
|
3875
|
+
const { showMemory } = await Promise.resolve().then(() => require("./src-Bhybpk1J.js"));
|
|
2713
3876
|
await showMemory();
|
|
2714
3877
|
process.exit(0);
|
|
2715
3878
|
});
|
|
2716
3879
|
memCmd.command("clear").description("Clear all auto-extracted memories").action(async () => {
|
|
2717
|
-
const { clearMemory } = await Promise.resolve().then(() => require("./src-
|
|
3880
|
+
const { clearMemory } = await Promise.resolve().then(() => require("./src-Bhybpk1J.js"));
|
|
2718
3881
|
await clearMemory();
|
|
2719
3882
|
process.exit(0);
|
|
2720
3883
|
});
|
|
2721
3884
|
memCmd.command("save <text>").description("Manually save a fact to MEMORY.md").action(async (text) => {
|
|
2722
|
-
const { saveMemoryDirect } = await Promise.resolve().then(() => require("./src-
|
|
3885
|
+
const { saveMemoryDirect } = await Promise.resolve().then(() => require("./src-Bhybpk1J.js"));
|
|
2723
3886
|
await saveMemoryDirect(text);
|
|
2724
3887
|
console.log(chalk.default.hex("#06b6d4")(` ✅ Saved: ${text}\n`));
|
|
2725
3888
|
process.exit(0);
|
|
2726
3889
|
});
|
|
2727
3890
|
const pcCmd = program.command("pc").description("PC access — give the AI access to your computer");
|
|
2728
3891
|
pcCmd.command("status").description("Show PC access status and config").action(async () => {
|
|
2729
|
-
const { showPCAccessStatus } = await Promise.resolve().then(() => require("./src-
|
|
3892
|
+
const { showPCAccessStatus } = await Promise.resolve().then(() => require("./src-Bhybpk1J.js"));
|
|
2730
3893
|
await showPCAccessStatus();
|
|
2731
3894
|
process.exit(0);
|
|
2732
3895
|
});
|
|
2733
3896
|
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-
|
|
3897
|
+
const { savePCAccessConfig } = await Promise.resolve().then(() => require("./src-Bhybpk1J.js"));
|
|
2735
3898
|
const level = opts.level;
|
|
2736
3899
|
const allowed = [
|
|
2737
3900
|
"read-only",
|
|
@@ -2758,7 +3921,7 @@ pcCmd.command("enable").description("Enable PC access for the AI").option("--lev
|
|
|
2758
3921
|
process.exit(0);
|
|
2759
3922
|
});
|
|
2760
3923
|
pcCmd.command("disable").description("Disable PC access").action(async () => {
|
|
2761
|
-
const { savePCAccessConfig } = await Promise.resolve().then(() => require("./src-
|
|
3924
|
+
const { savePCAccessConfig } = await Promise.resolve().then(() => require("./src-Bhybpk1J.js"));
|
|
2762
3925
|
await savePCAccessConfig({ enabled: false });
|
|
2763
3926
|
console.log(chalk.default.hex("#06b6d4")("\n ✅ PC access disabled\n"));
|
|
2764
3927
|
process.exit(0);
|
|
@@ -2782,7 +3945,7 @@ pcCmd.command("log").description("Show PC access audit log").option("-n, --lines
|
|
|
2782
3945
|
process.exit(0);
|
|
2783
3946
|
});
|
|
2784
3947
|
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-
|
|
3948
|
+
const { loadPCAccessConfig, getPCAccessTools } = await Promise.resolve().then(() => require("./src-Bhybpk1J.js"));
|
|
2786
3949
|
const cfg = await loadPCAccessConfig();
|
|
2787
3950
|
if (!cfg.enabled) {
|
|
2788
3951
|
console.log(chalk.default.red("\n ✖ PC access disabled. Run: hyperclaw pc enable\n"));
|
|
@@ -2798,9 +3961,9 @@ pcCmd.command("run <command>").description("Run a shell command via PC access (m
|
|
|
2798
3961
|
function checkForUpdate() {
|
|
2799
3962
|
const { execFile: execFile$1 } = require("child_process");
|
|
2800
3963
|
const { readFileSync } = require("fs");
|
|
2801
|
-
const path$
|
|
3964
|
+
const path$7 = require("path");
|
|
2802
3965
|
try {
|
|
2803
|
-
const pkgPath = path$
|
|
3966
|
+
const pkgPath = path$7.resolve(__dirname, "../../package.json");
|
|
2804
3967
|
const current = JSON.parse(readFileSync(pkgPath, "utf8")).version;
|
|
2805
3968
|
execFile$1("npm", [
|
|
2806
3969
|
"view",
|
|
@@ -2822,15 +3985,31 @@ function checkForUpdate() {
|
|
|
2822
3985
|
});
|
|
2823
3986
|
} catch {}
|
|
2824
3987
|
}
|
|
3988
|
+
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) => {
|
|
3989
|
+
await new require_onboard.Banner().showNeonBanner(false);
|
|
3990
|
+
const wizardOpts = {
|
|
3991
|
+
wizard: true,
|
|
3992
|
+
installDaemon: opts.installDaemon ?? false,
|
|
3993
|
+
reset: opts.reset ?? false,
|
|
3994
|
+
nonInteractive: opts.nonInteractive ?? false,
|
|
3995
|
+
jsonOutput: opts.json ?? false,
|
|
3996
|
+
gatewayPort: opts.gatewayPort ? parseInt(opts.gatewayPort) : void 0,
|
|
3997
|
+
gatewayBind: opts.gatewayBind ?? "loopback",
|
|
3998
|
+
anthropicApiKey: opts.anthropicApiKey,
|
|
3999
|
+
openaiApiKey: opts.openaiApiKey
|
|
4000
|
+
};
|
|
4001
|
+
await new require_onboard.HyperClawWizard().run(wizardOpts);
|
|
4002
|
+
process.exit(0);
|
|
4003
|
+
});
|
|
2825
4004
|
checkForUpdate();
|
|
2826
4005
|
if (process.argv.length === 2) (async () => {
|
|
2827
|
-
const { ConfigManager: ConfigManager$1 } = await Promise.resolve().then(() => require("./manager-
|
|
4006
|
+
const { ConfigManager: ConfigManager$1 } = await Promise.resolve().then(() => require("./manager-CrVDn6eN.js"));
|
|
2828
4007
|
const cfg = await new ConfigManager$1().load().catch(() => null);
|
|
2829
4008
|
if (cfg?.provider?.apiKey || cfg?.provider?.providerId) {
|
|
2830
4009
|
await new require_onboard.Banner().showNeonBanner(false);
|
|
2831
|
-
const { getTheme } = await Promise.resolve().then(() => require("./theme-
|
|
4010
|
+
const { getTheme } = await Promise.resolve().then(() => require("./theme-cx0fkgWC.js"));
|
|
2832
4011
|
const t = getTheme(false);
|
|
2833
|
-
const chalk$
|
|
4012
|
+
const chalk$11 = require("chalk");
|
|
2834
4013
|
console.log(t.bold(" Quick actions:\n"));
|
|
2835
4014
|
console.log(` ${t.c("hyperclaw onboard")} — re-run setup wizard`);
|
|
2836
4015
|
console.log(` ${t.c("hyperclaw onboard --install-daemon")} — wizard + daemon (full PC access)`);
|
|
@@ -2842,7 +4021,7 @@ if (process.argv.length === 2) (async () => {
|
|
|
2842
4021
|
console.log(` ${t.c("hyperclaw --help")} — all commands\n`);
|
|
2843
4022
|
} else {
|
|
2844
4023
|
await new require_onboard.Banner().showNeonBanner(false);
|
|
2845
|
-
const { HyperClawWizard: HyperClawWizard$1 } = await Promise.resolve().then(() => require("./onboard-
|
|
4024
|
+
const { HyperClawWizard: HyperClawWizard$1 } = await Promise.resolve().then(() => require("./onboard-BBBWcfhp.js"));
|
|
2846
4025
|
await new HyperClawWizard$1().run({ wizard: true });
|
|
2847
4026
|
}
|
|
2848
4027
|
process.exit(0);
|