hyperclaw 4.0.0 → 4.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +53 -18
- package/dist/a2ui-protocol-CT_jDEU9.js +75 -0
- package/dist/agents-routing-683Q2JGp.js +129 -0
- package/dist/agents-routing-BpZBswBH.js +4 -0
- package/dist/api-keys-guide-Bzig1R5W.js +149 -0
- package/dist/api-keys-guide-Dq5Obbp4.js +149 -0
- package/dist/audit-BYxPlnTQ.js +248 -0
- package/dist/bounty-tools-C6LyzxM-.js +211 -0
- package/dist/browser-tools-CQBSbIuO.js +5 -0
- package/dist/browser-tools-YQmwRLLM.js +179 -0
- package/dist/claw-tasks-BRLUvFRD.js +80 -0
- package/dist/connector-3HnyH8fn.js +167 -0
- package/dist/connector-6PMZo5Ky.js +189 -0
- package/dist/connector-B6eoF3DD.js +181 -0
- package/dist/connector-B9tLG8UZ.js +196 -0
- package/dist/connector-BOlqjXWP.js +182 -0
- package/dist/connector-BP8zsbP8.js +189 -0
- package/dist/connector-BPoSevxp.js +286 -0
- package/dist/connector-BRHj773i.js +163 -0
- package/dist/connector-BToxU-jV.js +267 -0
- package/dist/connector-BliDVsJQ.js +239 -0
- package/dist/connector-Bv6s9oP7.js +88 -0
- package/dist/connector-By5wWGTR.js +343 -0
- package/dist/connector-C1BaFFgN.js +213 -0
- package/dist/connector-CRRWY5Wv.js +167 -0
- package/dist/connector-CXPQVGyI.js +85 -0
- package/dist/connector-Cdk1CXKi.js +194 -0
- package/dist/connector-CwlgFgjx.js +181 -0
- package/dist/connector-DFchk6l7.js +178 -0
- package/dist/connector-DKw7tRAy.js +192 -0
- package/dist/connector-DRv1ahC_.js +343 -0
- package/dist/connector-DU63KW94.js +165 -0
- package/dist/connector-Dbvb1Cj9.js +280 -0
- package/dist/connector-DcZdQcgR.js +173 -0
- package/dist/connector-DxKL8VvZ.js +182 -0
- package/dist/connector-T_YdZtzv.js +162 -0
- package/dist/connector-i4gOS9xL.js +154 -0
- package/dist/connector-rHXE1ZD2.js +167 -0
- package/dist/connector-wdUXChwa.js +172 -0
- package/dist/cost-tracker-pVE15Yq4.js +103 -0
- package/dist/credentials-store-BvnMPJwi.js +4 -0
- package/dist/credentials-store-sb-TRLwR.js +77 -0
- package/dist/cron-tasks-BvDFNyiE.js +82 -0
- package/dist/delivery-B-SJqXLn.js +95 -0
- package/dist/delivery-D5Z98EVq.js +95 -0
- package/dist/delivery-DCOXhXEO.js +5 -0
- package/dist/delivery-VgFeuu2J.js +5 -0
- package/dist/destructive-gate-m-dWqUFg.js +101 -0
- package/dist/developer-keys-JaJK3T27.js +127 -0
- package/dist/developer-keys-kyqmtWK3.js +8 -0
- package/dist/doctor-3oi89QIc.js +175 -0
- package/dist/doctor-Cf1XSfp9.js +4 -0
- package/dist/engine-B4eMiTgl.js +7 -0
- package/dist/engine-B8M7dYul.js +7 -0
- package/dist/engine-BhT-1M9W.js +256 -0
- package/dist/engine-D49jnSd_.js +256 -0
- package/dist/env-resolve-DWOQ45jG.js +9 -0
- package/dist/env-resolve-szSWl0UF.js +94 -0
- package/dist/extraction-tools-D3qDFBJ1.js +91 -0
- package/dist/extraction-tools-DLr_AEwq.js +5 -0
- package/dist/form_data-B_hIUrxU.js +8657 -0
- package/dist/gmail-watch-setup-Czt8rXaX.js +40 -0
- package/dist/heartbeat-engine-CRqfPcFM.js +83 -0
- package/dist/hub-DTsqe5Bt.js +6 -0
- package/dist/hub-FrPTA33j.js +515 -0
- package/dist/hyperclawbot-D9KCtc4P.js +480 -0
- package/dist/hyperclawbot-DfMGowZC.js +480 -0
- package/dist/hyperclawbot-Dw27pJo4.js +480 -0
- package/dist/inference-CTWJeX9Q.js +922 -0
- package/dist/inference-ix607p7k.js +6 -0
- package/dist/knowledge-graph-DqA-Fztl.js +131 -0
- package/dist/loader-CISCqBto.js +400 -0
- package/dist/loader-CYMQ8VOS.js +4 -0
- package/dist/logger-8tEtAd3y.js +83 -0
- package/dist/manager-CPjeRe-6.js +4 -0
- package/dist/manager-Cwzj7w5R.js +105 -0
- package/dist/manager-DLmZI-9R.js +6 -0
- package/dist/manager-DSGhn5i3.js +117 -0
- package/dist/manager-DgyF52mg.js +218 -0
- package/dist/manager-Dm8nrMFx.js +40 -0
- package/dist/mcp-B_9Ber63.js +139 -0
- package/dist/mcp-loader-DSM5UiFG.js +94 -0
- package/dist/mcp-loader-j5ZLLw5O.js +94 -0
- package/dist/memory-BI1kPkAN.js +4 -0
- package/dist/memory-BVFGkxxK.js +270 -0
- package/dist/memory-auto-Bc7euou4.js +306 -0
- package/dist/memory-auto-DPfbkMVt.js +5 -0
- package/dist/memory-integration-DZExqWr4.js +91 -0
- package/dist/moltbook-B6ZeGN5_.js +81 -0
- package/dist/node-pwL6O_KX.js +222 -0
- package/dist/nodes-registry-CsPm_-CJ.js +52 -0
- package/dist/oauth-flow-CpWlgvNB.js +150 -0
- package/dist/oauth-provider-BZb6qOw5.js +110 -0
- package/dist/observability-B43YvNQV.js +89 -0
- package/dist/onboard-3q20ZyHj.js +9 -0
- package/dist/onboard-Bd_wsYdi.js +4086 -0
- package/dist/onboard-CAN7x3me.js +3026 -0
- package/dist/onboard-DnegOHMh.js +3026 -0
- package/dist/onboard-RYtDlYBw.js +9 -0
- package/dist/onboard-aTwlQs-4.js +9 -0
- package/dist/orchestrator-BSp2M5EU.js +189 -0
- package/dist/orchestrator-C7ko5tWa.js +6 -0
- package/dist/orchestrator-DfPkIx2Z.js +6 -0
- package/dist/orchestrator-NJQsmiBE.js +189 -0
- package/dist/pairing-DU0_J28n.js +87 -0
- package/dist/pairing-DWllbSbO.js +4 -0
- package/dist/pc-access-Ly-uA8mn.js +8 -0
- package/dist/pc-access-NxBvTrRj.js +819 -0
- package/dist/pending-approval-DIHvwwWS.js +22 -0
- package/dist/puppeteer-2o3QOwAy.js +2 -2
- package/dist/puppeteer-BYTMp3BI.js +2 -2
- package/dist/puppeteer-DQ45qwWk.js +2 -2
- package/dist/reminders-store-D79qdfN0.js +58 -0
- package/dist/renderer-pqlDRKbH.js +225 -0
- package/dist/rules-BooT_qFP.js +103 -0
- package/dist/run-main.js +366 -1109
- package/dist/runner-Bu--_RXw.js +810 -0
- package/dist/runner-D1rjuMTJ.js +810 -0
- package/dist/sdk/index.js +2 -2
- package/dist/sdk/index.mjs +2 -2
- package/dist/security-C-5URby1.js +73 -0
- package/dist/security-_xve79aq.js +4 -0
- package/dist/server-0kgyELx4.js +1047 -0
- package/dist/server-BIuTobTC.js +4 -0
- package/dist/server-BRlCEjyT.js +1047 -0
- package/dist/server-CCI1hv45.js +1047 -0
- package/dist/server-DU9POoWc.js +4 -0
- package/dist/server-RBqwE_GN.js +4 -0
- package/dist/session-store-CujxByI6.js +113 -0
- package/dist/session-store-qpJUg2M1.js +5 -0
- package/dist/sessions-tools-CB2qbwIk.js +5 -0
- package/dist/sessions-tools-DHMaTZIs.js +95 -0
- package/dist/skill-loader-BkceKkIg.js +7 -0
- package/dist/skill-loader-DhgIwK4J.js +159 -0
- package/dist/skill-runtime--LqxWrp5.js +102 -0
- package/dist/skill-runtime-C5l0Tgt-.js +5 -0
- package/dist/skill-runtime-DsXK_HYG.js +102 -0
- package/dist/skill-runtime-IVTiqrMR.js +5 -0
- package/dist/src-BEVLgaF1.js +63 -0
- package/dist/src-Bgu_OxTQ.js +458 -0
- package/dist/src-Bq-oKt7Z.js +458 -0
- package/dist/src-DWCUhnD4.js +20 -0
- package/dist/src-cfRTjFef.js +63 -0
- package/dist/sub-agent-tools-BD9DF8_g.js +39 -0
- package/dist/sub-agent-tools-V7b3T9_s.js +39 -0
- package/dist/tool-policy-DNvNRnve.js +189 -0
- package/dist/tts-elevenlabs-BUOGKL-k.js +61 -0
- package/dist/update-check-BD4qH7Am.js +81 -0
- package/dist/vision-DRq-f-Dj.js +121 -0
- package/dist/vision-tools-CFZEpQKm.js +5 -0
- package/dist/vision-tools-CQnBI9aa.js +51 -0
- package/dist/voice-transcription-CbQBToY0.js +138 -0
- package/dist/voice-transcription-CgWq54hn.js +138 -0
- package/dist/website-watch-tools-Bk_TnwuE.js +5 -0
- package/dist/website-watch-tools-DraMPxdl.js +139 -0
- package/package.json +1 -1
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
const require_chunk = require('./chunk-jS-bbMI5.js');
|
|
2
|
+
const chalk = require_chunk.__toESM(require("chalk"));
|
|
3
|
+
const inquirer = require_chunk.__toESM(require("inquirer"));
|
|
4
|
+
const ora = require_chunk.__toESM(require("ora"));
|
|
5
|
+
const fs_extra = require_chunk.__toESM(require("fs-extra"));
|
|
6
|
+
const path = require_chunk.__toESM(require("path"));
|
|
7
|
+
const os = require_chunk.__toESM(require("os"));
|
|
8
|
+
|
|
9
|
+
//#region src/commands/node.ts
|
|
10
|
+
const NODES_FILE = path.default.join(os.default.homedir(), ".hyperclaw", "nodes.json");
|
|
11
|
+
async function loadNodes() {
|
|
12
|
+
try {
|
|
13
|
+
return await fs_extra.default.readJson(NODES_FILE);
|
|
14
|
+
} catch {
|
|
15
|
+
return [];
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
async function saveNodes(nodes) {
|
|
19
|
+
await fs_extra.default.ensureDir(path.default.dirname(NODES_FILE));
|
|
20
|
+
await fs_extra.default.writeJson(NODES_FILE, nodes, { spaces: 2 });
|
|
21
|
+
}
|
|
22
|
+
const TYPE_EMOJI = {
|
|
23
|
+
local: "💻",
|
|
24
|
+
remote: "🖥️",
|
|
25
|
+
android: "📱",
|
|
26
|
+
raspberrypi: "🍓",
|
|
27
|
+
docker: "🐳",
|
|
28
|
+
vm: "☁️"
|
|
29
|
+
};
|
|
30
|
+
const STATUS_COLOR = {
|
|
31
|
+
online: chalk.default.green,
|
|
32
|
+
offline: chalk.default.red,
|
|
33
|
+
unknown: chalk.default.gray,
|
|
34
|
+
degraded: chalk.default.yellow
|
|
35
|
+
};
|
|
36
|
+
async function nodeList() {
|
|
37
|
+
const nodes = await loadNodes();
|
|
38
|
+
console.log(chalk.default.bold.cyan("\n 🖧 HYPERCLAW NODES\n"));
|
|
39
|
+
console.log(` ${chalk.default.green("●")} ${chalk.default.white("Local (this machine)".padEnd(22))} ${chalk.default.cyan("[local]")} ${chalk.default.green("online")}`);
|
|
40
|
+
console.log(` ${chalk.default.gray(`Node.js ${process.version} ${os.default.platform()} ${os.default.arch()} port 18789`)}`);
|
|
41
|
+
console.log();
|
|
42
|
+
if (nodes.length === 0) {
|
|
43
|
+
console.log(chalk.default.gray(" No additional nodes registered."));
|
|
44
|
+
console.log(chalk.default.gray(" Add a remote node: hyperclaw node add\n"));
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
for (const node of nodes) {
|
|
48
|
+
const dot = STATUS_COLOR[node.status]("●");
|
|
49
|
+
const emoji = TYPE_EMOJI[node.type];
|
|
50
|
+
const status = STATUS_COLOR[node.status](node.status);
|
|
51
|
+
console.log(` ${dot} ${chalk.default.white(node.name.padEnd(22))} ${chalk.default.cyan(`[${node.type}]`)} ${status}`);
|
|
52
|
+
if (node.host) console.log(` ${chalk.default.gray(`${node.host}:${node.port || 18789}`)}`);
|
|
53
|
+
if (node.androidDeviceId) console.log(` ${chalk.default.gray(`adb: ${node.androidDeviceId}`)}`);
|
|
54
|
+
if (node.capabilities.length > 0) console.log(` ${chalk.default.gray("caps:")} ${node.capabilities.join(", ")}`);
|
|
55
|
+
if (node.lastSeenAt) {
|
|
56
|
+
const ago = Math.round((Date.now() - new Date(node.lastSeenAt).getTime()) / 1e3 / 60);
|
|
57
|
+
console.log(` ${chalk.default.gray(`last seen: ${ago}m ago`)}`);
|
|
58
|
+
}
|
|
59
|
+
console.log();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
async function nodeAdd() {
|
|
63
|
+
console.log(chalk.default.bold.cyan("\n ➕ ADD NODE\n"));
|
|
64
|
+
const { type } = await inquirer.default.prompt([{
|
|
65
|
+
type: "list",
|
|
66
|
+
name: "type",
|
|
67
|
+
message: "Node type:",
|
|
68
|
+
choices: [
|
|
69
|
+
{
|
|
70
|
+
name: "🖥️ Remote server (SSH)",
|
|
71
|
+
value: "remote"
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
name: "📱 Android device (ADB)",
|
|
75
|
+
value: "android"
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
name: "🍓 Raspberry Pi",
|
|
79
|
+
value: "raspberrypi"
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
name: "🐳 Docker container",
|
|
83
|
+
value: "docker"
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
name: "☁️ VM / cloud instance",
|
|
87
|
+
value: "vm"
|
|
88
|
+
}
|
|
89
|
+
]
|
|
90
|
+
}]);
|
|
91
|
+
const { name } = await inquirer.default.prompt([{
|
|
92
|
+
type: "input",
|
|
93
|
+
name: "name",
|
|
94
|
+
message: "Node name:",
|
|
95
|
+
validate: (v) => !!v.trim() || "Required"
|
|
96
|
+
}]);
|
|
97
|
+
let extras = {};
|
|
98
|
+
if (type === "android") {
|
|
99
|
+
const { deviceId } = await inquirer.default.prompt([{
|
|
100
|
+
type: "input",
|
|
101
|
+
name: "deviceId",
|
|
102
|
+
message: "ADB device ID (run: adb devices):",
|
|
103
|
+
validate: (v) => !!v.trim() || "Required"
|
|
104
|
+
}]);
|
|
105
|
+
extras.androidDeviceId = deviceId;
|
|
106
|
+
extras.capabilities = ["channel:host", "always-on"];
|
|
107
|
+
} else {
|
|
108
|
+
const { host, port } = await inquirer.default.prompt([{
|
|
109
|
+
type: "input",
|
|
110
|
+
name: "host",
|
|
111
|
+
message: "Hostname or IP:",
|
|
112
|
+
validate: (v) => !!v.trim() || "Required"
|
|
113
|
+
}, {
|
|
114
|
+
type: "number",
|
|
115
|
+
name: "port",
|
|
116
|
+
message: "Gateway port:",
|
|
117
|
+
default: 18789
|
|
118
|
+
}]);
|
|
119
|
+
const { caps } = await inquirer.default.prompt([{
|
|
120
|
+
type: "checkbox",
|
|
121
|
+
name: "caps",
|
|
122
|
+
message: "Capabilities:",
|
|
123
|
+
choices: [
|
|
124
|
+
{
|
|
125
|
+
name: "Run agent inference",
|
|
126
|
+
value: "agent:run",
|
|
127
|
+
checked: true
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
name: "Host channel connections",
|
|
131
|
+
value: "channel:host"
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
name: "Execute code",
|
|
135
|
+
value: "code:execute"
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
name: "GPU acceleration",
|
|
139
|
+
value: "gpu"
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
name: "Always-on (24/7)",
|
|
143
|
+
value: "always-on"
|
|
144
|
+
}
|
|
145
|
+
]
|
|
146
|
+
}]);
|
|
147
|
+
extras = {
|
|
148
|
+
host,
|
|
149
|
+
port,
|
|
150
|
+
capabilities: caps
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
const node = {
|
|
154
|
+
id: name.toLowerCase().replace(/\s+/g, "-"),
|
|
155
|
+
name,
|
|
156
|
+
type,
|
|
157
|
+
status: "unknown",
|
|
158
|
+
addedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
159
|
+
capabilities: extras.capabilities || [],
|
|
160
|
+
...extras
|
|
161
|
+
};
|
|
162
|
+
const nodes = await loadNodes();
|
|
163
|
+
nodes.push(node);
|
|
164
|
+
await saveNodes(nodes);
|
|
165
|
+
console.log(chalk.default.green(`\n ✔ Node added: ${name}`));
|
|
166
|
+
console.log(chalk.default.gray(" Run: hyperclaw node probe to test the connection\n"));
|
|
167
|
+
}
|
|
168
|
+
async function nodeProbe(id) {
|
|
169
|
+
const nodes = await loadNodes();
|
|
170
|
+
const targets = id ? nodes.filter((n) => n.id === id) : nodes;
|
|
171
|
+
console.log(chalk.default.bold.cyan("\n 🔍 PROBING NODES\n"));
|
|
172
|
+
console.log(` ${chalk.default.cyan("○")} Local...`);
|
|
173
|
+
await new Promise((r) => setTimeout(r, 300));
|
|
174
|
+
console.log(` ${chalk.default.green("✔")} Local — online (${os.default.platform()} ${os.default.arch()})\n`);
|
|
175
|
+
for (const node of targets) {
|
|
176
|
+
const spinner = (0, ora.default)(` Probing ${node.name} (${node.host || node.androidDeviceId || node.type})...`).start();
|
|
177
|
+
await new Promise((r) => setTimeout(r, 1e3));
|
|
178
|
+
try {
|
|
179
|
+
if (node.host) {
|
|
180
|
+
const axios = (await import("axios")).default;
|
|
181
|
+
const res = await axios.get(`http://${node.host}:${node.port || 18789}/api/status`, { timeout: 3e3 });
|
|
182
|
+
node.status = "online";
|
|
183
|
+
node.version = res.data?.version;
|
|
184
|
+
node.lastSeenAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
185
|
+
spinner.succeed(`${node.name} — online${node.version ? ` (v${node.version})` : ""}`);
|
|
186
|
+
} else if (node.type === "android") {
|
|
187
|
+
const { exec } = await import("child_process");
|
|
188
|
+
const { promisify } = await import("util");
|
|
189
|
+
const execAsync = promisify(exec);
|
|
190
|
+
await execAsync(`adb -s ${node.androidDeviceId} shell echo ok`);
|
|
191
|
+
node.status = "online";
|
|
192
|
+
node.lastSeenAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
193
|
+
spinner.succeed(`${node.name} — online (ADB connected)`);
|
|
194
|
+
} else {
|
|
195
|
+
node.status = "unknown";
|
|
196
|
+
spinner.warn(`${node.name} — probe not supported for ${node.type}`);
|
|
197
|
+
}
|
|
198
|
+
} catch {
|
|
199
|
+
node.status = "offline";
|
|
200
|
+
spinner.fail(`${node.name} — offline / unreachable`);
|
|
201
|
+
}
|
|
202
|
+
console.log();
|
|
203
|
+
}
|
|
204
|
+
await saveNodes(nodes);
|
|
205
|
+
}
|
|
206
|
+
async function nodeRemove(id) {
|
|
207
|
+
const nodes = await loadNodes();
|
|
208
|
+
const idx = nodes.findIndex((n) => n.id === id);
|
|
209
|
+
if (idx === -1) {
|
|
210
|
+
console.log(chalk.default.red(`\n ✖ Node not found: ${id}\n`));
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
nodes.splice(idx, 1);
|
|
214
|
+
await saveNodes(nodes);
|
|
215
|
+
console.log(chalk.default.green(`\n ✔ Node removed: ${id}\n`));
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
//#endregion
|
|
219
|
+
exports.nodeAdd = nodeAdd;
|
|
220
|
+
exports.nodeList = nodeList;
|
|
221
|
+
exports.nodeProbe = nodeProbe;
|
|
222
|
+
exports.nodeRemove = nodeRemove;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
const require_chunk = require('./chunk-jS-bbMI5.js');
|
|
2
|
+
const events = require_chunk.__toESM(require("events"));
|
|
3
|
+
|
|
4
|
+
//#region src/services/nodes-registry.ts
|
|
5
|
+
var NodeRegistryImpl, NodeRegistry;
|
|
6
|
+
var init_nodes_registry = require_chunk.__esm({ "src/services/nodes-registry.ts"() {
|
|
7
|
+
NodeRegistryImpl = class extends events.EventEmitter {
|
|
8
|
+
nodes = /* @__PURE__ */ new Map();
|
|
9
|
+
pendingCommands = /* @__PURE__ */ new Map();
|
|
10
|
+
register(node) {
|
|
11
|
+
this.nodes.set(node.nodeId, node);
|
|
12
|
+
this.emit("node:registered", node);
|
|
13
|
+
}
|
|
14
|
+
unregister(nodeId) {
|
|
15
|
+
this.nodes.delete(nodeId);
|
|
16
|
+
this.emit("node:unregistered", nodeId);
|
|
17
|
+
}
|
|
18
|
+
getNodes() {
|
|
19
|
+
return Array.from(this.nodes.values());
|
|
20
|
+
}
|
|
21
|
+
getNode(nodeId) {
|
|
22
|
+
return this.nodes.get(nodeId);
|
|
23
|
+
}
|
|
24
|
+
/** Send a command to a node. Returns result or error. */
|
|
25
|
+
async sendCommand(nodeId, cmd) {
|
|
26
|
+
const node = this.nodes.get(nodeId);
|
|
27
|
+
if (!node) return {
|
|
28
|
+
ok: false,
|
|
29
|
+
error: `Node ${nodeId} not connected`
|
|
30
|
+
};
|
|
31
|
+
return node.send(cmd);
|
|
32
|
+
}
|
|
33
|
+
/** Handle response from a node (called when node replies to a command). */
|
|
34
|
+
handleCommandResponse(cmdId, result) {
|
|
35
|
+
const pending = this.pendingCommands.get(cmdId);
|
|
36
|
+
if (pending) {
|
|
37
|
+
clearTimeout(pending.timeout);
|
|
38
|
+
this.pendingCommands.delete(cmdId);
|
|
39
|
+
pending.resolve(result);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
updateLastSeen(nodeId) {
|
|
43
|
+
const node = this.nodes.get(nodeId);
|
|
44
|
+
if (node) node.lastSeenAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
NodeRegistry = new NodeRegistryImpl();
|
|
48
|
+
} });
|
|
49
|
+
|
|
50
|
+
//#endregion
|
|
51
|
+
init_nodes_registry();
|
|
52
|
+
exports.NodeRegistry = NodeRegistry;
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
const require_chunk = require('./chunk-jS-bbMI5.js');
|
|
2
|
+
const path = require_chunk.__toESM(require("path"));
|
|
3
|
+
const os = require_chunk.__toESM(require("os"));
|
|
4
|
+
const crypto = require_chunk.__toESM(require("crypto"));
|
|
5
|
+
const http = require_chunk.__toESM(require("http"));
|
|
6
|
+
|
|
7
|
+
//#region src/services/oauth-flow.ts
|
|
8
|
+
const HC_DIR = path.default.join(os.default.homedir(), ".hyperclaw");
|
|
9
|
+
const REDIRECT_PORT = 38789;
|
|
10
|
+
const REDIRECT_PATH = "/oauth/callback";
|
|
11
|
+
const PROVIDERS = {
|
|
12
|
+
google: {
|
|
13
|
+
authorize_url: "https://accounts.google.com/o/oauth2/v2/auth",
|
|
14
|
+
token_url: "https://oauth2.googleapis.com/token",
|
|
15
|
+
scopes: [
|
|
16
|
+
"openid",
|
|
17
|
+
"email",
|
|
18
|
+
"profile",
|
|
19
|
+
"https://www.googleapis.com/auth/aiplatform"
|
|
20
|
+
],
|
|
21
|
+
client_id: process.env.GOOGLE_OAUTH_CLIENT_ID || "",
|
|
22
|
+
client_secret: process.env.GOOGLE_OAUTH_CLIENT_SECRET
|
|
23
|
+
},
|
|
24
|
+
"google-gmail": {
|
|
25
|
+
authorize_url: "https://accounts.google.com/o/oauth2/v2/auth",
|
|
26
|
+
token_url: "https://oauth2.googleapis.com/token",
|
|
27
|
+
scopes: [
|
|
28
|
+
"openid",
|
|
29
|
+
"email",
|
|
30
|
+
"profile",
|
|
31
|
+
"https://www.googleapis.com/auth/gmail.modify",
|
|
32
|
+
"https://mail.google.com/"
|
|
33
|
+
],
|
|
34
|
+
client_id: process.env.GOOGLE_OAUTH_CLIENT_ID || "",
|
|
35
|
+
client_secret: process.env.GOOGLE_OAUTH_CLIENT_SECRET
|
|
36
|
+
},
|
|
37
|
+
microsoft: {
|
|
38
|
+
authorize_url: "https://login.microsoftonline.com/common/oauth2/v2.0/authorize",
|
|
39
|
+
token_url: "https://login.microsoftonline.com/common/oauth2/v2.0/token",
|
|
40
|
+
scopes: [
|
|
41
|
+
"openid",
|
|
42
|
+
"profile",
|
|
43
|
+
"offline_access",
|
|
44
|
+
"https://cognitiveservices.azure.com/.default"
|
|
45
|
+
],
|
|
46
|
+
client_id: process.env.AZURE_OAUTH_CLIENT_ID || process.env.MICROSOFT_OAUTH_CLIENT_ID || "",
|
|
47
|
+
client_secret: process.env.AZURE_OAUTH_CLIENT_SECRET || process.env.MICROSOFT_OAUTH_CLIENT_SECRET
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
async function runOAuthFlow(providerId, opts) {
|
|
51
|
+
const cfg = PROVIDERS[providerId];
|
|
52
|
+
if (!cfg) throw new Error(`OAuth provider "${providerId}" not configured. Supported: google, google-gmail (Gmail Pub/Sub), microsoft. Anthropic/OpenAI: use "hyperclaw auth add" (API keys) or "hyperclaw auth setup-token anthropic" for Claude Pro/Max.`);
|
|
53
|
+
const clientId = opts?.clientId || cfg.client_id || process.env.OAUTH_CLIENT_ID;
|
|
54
|
+
const clientSecret = opts?.clientSecret || cfg.client_secret || process.env.OAUTH_CLIENT_SECRET;
|
|
55
|
+
const scopes = opts?.scopes || cfg.scopes;
|
|
56
|
+
if (!clientId) {
|
|
57
|
+
const hint = providerId === "google" ? "Set GOOGLE_OAUTH_CLIENT_ID or OAUTH_CLIENT_ID. Create at: https://console.cloud.google.com/apis/credentials" : providerId === "microsoft" ? "Set AZURE_OAUTH_CLIENT_ID. Create at: https://portal.azure.com/#blade/Microsoft_AAD_RegisteredApps/ApplicationsListBlade" : "Set OAUTH_CLIENT_ID or pass --client-id";
|
|
58
|
+
throw new Error(`OAuth client_id required. ${hint}`);
|
|
59
|
+
}
|
|
60
|
+
const codeVerifier = crypto.default.randomBytes(32).toString("base64url");
|
|
61
|
+
const codeChallenge = crypto.default.createHash("sha256").update(codeVerifier).digest("base64url");
|
|
62
|
+
const authParams = new URLSearchParams({
|
|
63
|
+
client_id: clientId,
|
|
64
|
+
redirect_uri: `http://127.0.0.1:${REDIRECT_PORT}${REDIRECT_PATH}`,
|
|
65
|
+
response_type: "code",
|
|
66
|
+
scope: scopes.join(" "),
|
|
67
|
+
code_challenge: codeChallenge,
|
|
68
|
+
code_challenge_method: "S256",
|
|
69
|
+
access_type: "offline",
|
|
70
|
+
prompt: "consent"
|
|
71
|
+
});
|
|
72
|
+
const authUrl = `${cfg.authorize_url}?${authParams}`;
|
|
73
|
+
return new Promise((resolve, reject) => {
|
|
74
|
+
const server = http.default.createServer(async (req, res) => {
|
|
75
|
+
const url = new URL(req.url || "/", `http://127.0.0.1`);
|
|
76
|
+
if (url.pathname !== REDIRECT_PATH) {
|
|
77
|
+
res.writeHead(404);
|
|
78
|
+
res.end("Not found");
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const code = url.searchParams.get("code");
|
|
82
|
+
const error = url.searchParams.get("error");
|
|
83
|
+
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
84
|
+
if (error) {
|
|
85
|
+
res.writeHead(400);
|
|
86
|
+
res.end(`<h1>OAuth error</h1><p>${error}</p><p>You can close this tab.</p>`);
|
|
87
|
+
server.close();
|
|
88
|
+
reject(new Error(`OAuth error: ${error}`));
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if (!code) {
|
|
92
|
+
res.writeHead(400);
|
|
93
|
+
res.end("<h1>No code received</h1><p>You can close this tab.</p>");
|
|
94
|
+
server.close();
|
|
95
|
+
reject(new Error("No authorization code received"));
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const body = new URLSearchParams({
|
|
99
|
+
grant_type: "authorization_code",
|
|
100
|
+
code,
|
|
101
|
+
redirect_uri: `http://127.0.0.1:${REDIRECT_PORT}${REDIRECT_PATH}`,
|
|
102
|
+
code_verifier: codeVerifier
|
|
103
|
+
});
|
|
104
|
+
if (clientSecret) body.set("client_secret", clientSecret);
|
|
105
|
+
body.set("client_id", clientId);
|
|
106
|
+
try {
|
|
107
|
+
const tokenRes = await fetch(cfg.token_url, {
|
|
108
|
+
method: "POST",
|
|
109
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
110
|
+
body: body.toString()
|
|
111
|
+
});
|
|
112
|
+
const tokenData = await tokenRes.json();
|
|
113
|
+
if (tokenData.error) {
|
|
114
|
+
res.writeHead(400);
|
|
115
|
+
res.end(`<h1>Token error</h1><p>${tokenData.error}</p><p>You can close this tab.</p>`);
|
|
116
|
+
server.close();
|
|
117
|
+
reject(new Error(tokenData.error_description || tokenData.error));
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
res.writeHead(200);
|
|
121
|
+
res.end("<h1>Success!</h1><p>HyperClaw has received your tokens. You can close this tab and return to the terminal.</p>");
|
|
122
|
+
server.close();
|
|
123
|
+
resolve({
|
|
124
|
+
access_token: tokenData.access_token,
|
|
125
|
+
refresh_token: tokenData.refresh_token,
|
|
126
|
+
expires_in: tokenData.expires_in
|
|
127
|
+
});
|
|
128
|
+
} catch (e) {
|
|
129
|
+
res.writeHead(500);
|
|
130
|
+
res.end(`<h1>Error</h1><p>${e.message}</p><p>You can close this tab.</p>`);
|
|
131
|
+
server.close();
|
|
132
|
+
reject(e);
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
server.listen(REDIRECT_PORT, "127.0.0.1", () => {
|
|
136
|
+
try {
|
|
137
|
+
const { exec } = require("child_process");
|
|
138
|
+
const opener = process.platform === "win32" ? `start "" "${authUrl}"` : (process.platform === "darwin" ? "open" : "xdg-open") + ` "${authUrl}"`;
|
|
139
|
+
exec(opener);
|
|
140
|
+
} catch {}
|
|
141
|
+
});
|
|
142
|
+
server.on("error", (err) => {
|
|
143
|
+
server.close();
|
|
144
|
+
reject(err);
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
//#endregion
|
|
150
|
+
exports.runOAuthFlow = runOAuthFlow;
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
const require_chunk = require('./chunk-jS-bbMI5.js');
|
|
2
|
+
const fs_extra = require_chunk.__toESM(require("fs-extra"));
|
|
3
|
+
const path = require_chunk.__toESM(require("path"));
|
|
4
|
+
const os = require_chunk.__toESM(require("os"));
|
|
5
|
+
const https = require_chunk.__toESM(require("https"));
|
|
6
|
+
|
|
7
|
+
//#region src/services/oauth-provider.ts
|
|
8
|
+
function defaultTokenPath(providerId) {
|
|
9
|
+
return path.default.join(HC_DIR, `oauth-${providerId}.json`);
|
|
10
|
+
}
|
|
11
|
+
async function getProviderCredentialAsync(cfg) {
|
|
12
|
+
if (!cfg?.provider) return "";
|
|
13
|
+
const authType = cfg.provider.authType ?? "api_key";
|
|
14
|
+
if (authType === "api_key") {
|
|
15
|
+
const key = cfg.provider.apiKey;
|
|
16
|
+
if (key) return key;
|
|
17
|
+
const pid = cfg.provider.providerId || "openrouter";
|
|
18
|
+
switch (pid) {
|
|
19
|
+
case "openrouter": return process.env.OPENROUTER_API_KEY || "";
|
|
20
|
+
case "anthropic": return process.env.ANTHROPIC_API_KEY || "";
|
|
21
|
+
case "openai": return process.env.OPENAI_API_KEY || "";
|
|
22
|
+
case "xai": return process.env.XAI_API_KEY || "";
|
|
23
|
+
case "google": return process.env.GOOGLE_AI_API_KEY || "";
|
|
24
|
+
default: return process.env.OPENROUTER_API_KEY || process.env.ANTHROPIC_API_KEY || "";
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
const tokenPath = cfg.provider.oauthTokenPath || defaultTokenPath(cfg.provider.providerId || "default");
|
|
28
|
+
if (!await fs_extra.default.pathExists(tokenPath)) return "";
|
|
29
|
+
let data;
|
|
30
|
+
try {
|
|
31
|
+
data = await fs_extra.default.readJson(tokenPath);
|
|
32
|
+
} catch {
|
|
33
|
+
return "";
|
|
34
|
+
}
|
|
35
|
+
if (!data.access_token) return "";
|
|
36
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
37
|
+
const expiresAt = data.expires_at ?? 0;
|
|
38
|
+
if (expiresAt > 0 && now < expiresAt - 60) return data.access_token;
|
|
39
|
+
if (!data.refresh_token) return data.access_token;
|
|
40
|
+
const tokenUrl = data.token_url || DEFAULT_REFRESH_URLS[cfg.provider.providerId || ""] || "";
|
|
41
|
+
if (!tokenUrl) return data.access_token;
|
|
42
|
+
const refreshed = await refreshAccessToken({
|
|
43
|
+
token_url: tokenUrl,
|
|
44
|
+
refresh_token: data.refresh_token,
|
|
45
|
+
client_id: data.client_id || process.env.OAUTH_CLIENT_ID,
|
|
46
|
+
client_secret: data.client_secret || process.env.OAUTH_CLIENT_SECRET
|
|
47
|
+
});
|
|
48
|
+
if (refreshed.access_token) {
|
|
49
|
+
data.access_token = refreshed.access_token;
|
|
50
|
+
if (refreshed.expires_in) data.expires_at = now + refreshed.expires_in;
|
|
51
|
+
await fs_extra.default.writeJson(tokenPath, data, { spaces: 2 });
|
|
52
|
+
return data.access_token;
|
|
53
|
+
}
|
|
54
|
+
return data.access_token;
|
|
55
|
+
}
|
|
56
|
+
async function refreshAccessToken(opts) {
|
|
57
|
+
const body = new URLSearchParams({
|
|
58
|
+
grant_type: "refresh_token",
|
|
59
|
+
refresh_token: opts.refresh_token
|
|
60
|
+
});
|
|
61
|
+
if (opts.client_id) body.set("client_id", opts.client_id);
|
|
62
|
+
if (opts.client_secret) body.set("client_secret", opts.client_secret);
|
|
63
|
+
const u = new URL(opts.token_url);
|
|
64
|
+
return new Promise((resolve) => {
|
|
65
|
+
const req = https.default.request({
|
|
66
|
+
hostname: u.hostname,
|
|
67
|
+
port: 443,
|
|
68
|
+
path: u.pathname + u.search,
|
|
69
|
+
method: "POST",
|
|
70
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" }
|
|
71
|
+
}, (res) => {
|
|
72
|
+
let data = "";
|
|
73
|
+
res.on("data", (c) => data += c);
|
|
74
|
+
res.on("end", () => {
|
|
75
|
+
try {
|
|
76
|
+
const j = JSON.parse(data);
|
|
77
|
+
resolve({
|
|
78
|
+
access_token: j.access_token,
|
|
79
|
+
expires_in: j.expires_in
|
|
80
|
+
});
|
|
81
|
+
} catch {
|
|
82
|
+
resolve({});
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
req.on("error", () => resolve({}));
|
|
87
|
+
req.write(body.toString());
|
|
88
|
+
req.end();
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
/** Write token file (e.g. after OAuth callback or manual paste). */
|
|
92
|
+
async function writeOAuthToken(providerId, token, customPath) {
|
|
93
|
+
const p = customPath || defaultTokenPath(providerId);
|
|
94
|
+
await fs_extra.default.ensureDir(path.default.dirname(p));
|
|
95
|
+
await fs_extra.default.writeJson(p, token, { spaces: 2 });
|
|
96
|
+
}
|
|
97
|
+
var HC_DIR, DEFAULT_REFRESH_URLS;
|
|
98
|
+
var init_oauth_provider = require_chunk.__esm({ "src/services/oauth-provider.ts"() {
|
|
99
|
+
HC_DIR = path.default.join(os.default.homedir(), ".hyperclaw");
|
|
100
|
+
DEFAULT_REFRESH_URLS = {
|
|
101
|
+
google: "https://oauth2.googleapis.com/token",
|
|
102
|
+
openai: "https://api.openai.com/v1/auth/refresh",
|
|
103
|
+
anthropic: ""
|
|
104
|
+
};
|
|
105
|
+
} });
|
|
106
|
+
|
|
107
|
+
//#endregion
|
|
108
|
+
init_oauth_provider();
|
|
109
|
+
exports.getProviderCredentialAsync = getProviderCredentialAsync;
|
|
110
|
+
exports.writeOAuthToken = writeOAuthToken;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
const require_chunk = require('./chunk-jS-bbMI5.js');
|
|
2
|
+
|
|
3
|
+
//#region src/infra/observability.ts
|
|
4
|
+
/** Rough cost per 1M tokens (Claude Sonnet ballpark). */
|
|
5
|
+
const COST_PER_1M_INPUT = 3;
|
|
6
|
+
const COST_PER_1M_OUTPUT = 15;
|
|
7
|
+
function estimateCost(usage) {
|
|
8
|
+
if (!usage) return 0;
|
|
9
|
+
const inp = (usage.input || 0) + (usage.cacheRead || 0);
|
|
10
|
+
return inp / 1e6 * COST_PER_1M_INPUT + (usage.output || 0) / 1e6 * COST_PER_1M_OUTPUT;
|
|
11
|
+
}
|
|
12
|
+
function createRunTracer(sessionId, source) {
|
|
13
|
+
const startTime = (/* @__PURE__ */ new Date()).toISOString();
|
|
14
|
+
const toolCalls = [];
|
|
15
|
+
const pending = [];
|
|
16
|
+
const trace = {
|
|
17
|
+
sessionId,
|
|
18
|
+
source,
|
|
19
|
+
startTime,
|
|
20
|
+
toolCalls
|
|
21
|
+
};
|
|
22
|
+
return {
|
|
23
|
+
trace,
|
|
24
|
+
onToolCall(name, input) {
|
|
25
|
+
pending.push({
|
|
26
|
+
name,
|
|
27
|
+
input
|
|
28
|
+
});
|
|
29
|
+
},
|
|
30
|
+
onToolResult(name, result) {
|
|
31
|
+
const head = pending.shift();
|
|
32
|
+
toolCalls.push({
|
|
33
|
+
name: name || head?.name || "unknown",
|
|
34
|
+
input: head?.input ?? {},
|
|
35
|
+
result: result.slice(0, 500),
|
|
36
|
+
at: (/* @__PURE__ */ new Date()).toISOString()
|
|
37
|
+
});
|
|
38
|
+
},
|
|
39
|
+
onRunEnd(usage, error) {
|
|
40
|
+
trace.endTime = (/* @__PURE__ */ new Date()).toISOString();
|
|
41
|
+
trace.usage = usage;
|
|
42
|
+
trace.costUsd = estimateCost(usage);
|
|
43
|
+
trace.error = error;
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/** List trace files (for querying). */
|
|
48
|
+
async function listTraces(baseDir, limit = 50) {
|
|
49
|
+
try {
|
|
50
|
+
const fs = await import("fs-extra");
|
|
51
|
+
const path = await import("path");
|
|
52
|
+
const dir = path.join(baseDir, "traces");
|
|
53
|
+
if (!await fs.pathExists(dir)) return [];
|
|
54
|
+
const files = (await fs.readdir(dir)).filter((f) => f.endsWith(".json")).map((f) => path.join(dir, f));
|
|
55
|
+
const stats = await Promise.all(files.map(async (fp) => ({
|
|
56
|
+
fp,
|
|
57
|
+
mtime: (await fs.stat(fp)).mtime.getTime()
|
|
58
|
+
})));
|
|
59
|
+
stats.sort((a, b) => b.mtime - a.mtime);
|
|
60
|
+
const out = [];
|
|
61
|
+
for (const { fp } of stats.slice(0, limit)) try {
|
|
62
|
+
out.push(await fs.readJson(fp));
|
|
63
|
+
} catch {}
|
|
64
|
+
return out;
|
|
65
|
+
} catch {
|
|
66
|
+
return [];
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/** Write trace to file (e.g. ~/.hyperclaw/traces/). */
|
|
70
|
+
async function writeTraceToFile(baseDir, trace) {
|
|
71
|
+
try {
|
|
72
|
+
const fs = await import("fs-extra");
|
|
73
|
+
const path = await import("path");
|
|
74
|
+
const dir = path.join(baseDir, "traces");
|
|
75
|
+
await fs.ensureDir(dir);
|
|
76
|
+
const name = `run-${trace.startTime.replace(/[:.]/g, "-")}.json`;
|
|
77
|
+
const fp = path.join(dir, name);
|
|
78
|
+
await fs.writeJson(fp, trace, { spaces: 0 });
|
|
79
|
+
return fp;
|
|
80
|
+
} catch {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
//#endregion
|
|
86
|
+
exports.createRunTracer = createRunTracer;
|
|
87
|
+
exports.estimateCost = estimateCost;
|
|
88
|
+
exports.listTraces = listTraces;
|
|
89
|
+
exports.writeTraceToFile = writeTraceToFile;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
const require_chunk = require('./chunk-jS-bbMI5.js');
|
|
2
|
+
require('./paths-AIyBxIzm.js');
|
|
3
|
+
require('./paths-DPovhojT.js');
|
|
4
|
+
require('./env-resolve-BzDlV2CS.js');
|
|
5
|
+
const require_onboard = require('./onboard-DnegOHMh.js');
|
|
6
|
+
require('./server-CCI1hv45.js');
|
|
7
|
+
require('./theme-LUTKWUWd.js');
|
|
8
|
+
|
|
9
|
+
exports.HyperClawWizard = require_onboard.HyperClawWizard;
|