hyperclaw 4.0.2 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. package/README.md +54 -3
  2. package/dist/a2ui-protocol-CfBI44-Q.js +75 -0
  3. package/dist/agents-routing-ChHiZp36.js +327 -0
  4. package/dist/agents-routing-ChqZ6l2S.js +4 -0
  5. package/dist/api-keys-guide-BCcOl0Q7.js +149 -0
  6. package/dist/audit-BaIiyWFu.js +441 -0
  7. package/dist/bounty-tools-DWudyZie.js +211 -0
  8. package/dist/browser-tools-BsTeGMnX.js +5 -0
  9. package/dist/browser-tools-D8_rLe2p.js +179 -0
  10. package/dist/claw-tasks-CgTsiNE8.js +80 -0
  11. package/dist/connector-5N0-X_xs.js +194 -0
  12. package/dist/connector-B3v0qcXg.js +425 -0
  13. package/dist/connector-B8R3iBY1.js +280 -0
  14. package/dist/connector-BAM-08NN.js +189 -0
  15. package/dist/connector-BC8FIVu4.js +181 -0
  16. package/dist/connector-BDmwwaVc.js +213 -0
  17. package/dist/connector-BGjbBy69.js +225 -0
  18. package/dist/connector-BO2SRzfG.js +218 -0
  19. package/dist/connector-BfXky0L3.js +167 -0
  20. package/dist/connector-BiiSJpx3.js +192 -0
  21. package/dist/connector-BnDmIhIu.js +85 -0
  22. package/dist/connector-C1HSoUyk.js +189 -0
  23. package/dist/connector-CKQHZOXg.js +568 -0
  24. package/dist/connector-CRl-iidy.js +239 -0
  25. package/dist/connector-Ci9glMD-.js +340 -0
  26. package/dist/connector-CjtZIEDj.js +181 -0
  27. package/dist/connector-Ck6JtOsX.js +531 -0
  28. package/dist/connector-D8Kelee0.js +286 -0
  29. package/dist/connector-DAnRJ0oP.js +162 -0
  30. package/dist/connector-DXTp5PE8.js +508 -0
  31. package/dist/connector-Dih6dUPP.js +173 -0
  32. package/dist/connector-DqTH_tPX.js +182 -0
  33. package/dist/connector-DrnEiiyP.js +419 -0
  34. package/dist/connector-DtR5GGTX.js +167 -0
  35. package/dist/connector-Tky_qS_K.js +350 -0
  36. package/dist/connector-ZSc3oTTy.js +305 -0
  37. package/dist/connector-sW5yhU1m.js +498 -0
  38. package/dist/connector-u3ICd3Ic.js +552 -0
  39. package/dist/cost-tracker-DD9wtWsr.js +103 -0
  40. package/dist/credentials-store-C6ir0Dae.js +4 -0
  41. package/dist/credentials-store-H13LqOwJ.js +77 -0
  42. package/dist/cron-tasks-Bli7Kzd2.js +82 -0
  43. package/dist/daemon-Bg4GtCmc.js +318 -0
  44. package/dist/daemon-DhmwY8k4.js +5 -0
  45. package/dist/delivery-BmIYy9VQ.js +4 -0
  46. package/dist/delivery-pWUPBp1F.js +95 -0
  47. package/dist/destructive-gate-D6vWOdEl.js +101 -0
  48. package/dist/developer-keys-CPWT7Q6S.js +8 -0
  49. package/dist/developer-keys-DrrcUqFa.js +127 -0
  50. package/dist/doctor-BvCe8BBk.js +230 -0
  51. package/dist/doctor-CxyPLYsJ.js +6 -0
  52. package/dist/engine-CEDSqXfw.js +256 -0
  53. package/dist/engine-Da4JMNpI.js +7 -0
  54. package/dist/env-resolve-CiXbWYwe.js +10 -0
  55. package/dist/env-resolve-CmGWhWXJ.js +115 -0
  56. package/dist/extraction-tools-HOZstZ0y.js +91 -0
  57. package/dist/extraction-tools-m4lmAv7l.js +5 -0
  58. package/dist/form_data-Cz040rio.js +8657 -0
  59. package/dist/gmail-watch-setup-Du7DVV7S.js +40 -0
  60. package/dist/health-B-asI__D.js +6 -0
  61. package/dist/health-Ds2YlpTB.js +152 -0
  62. package/dist/heartbeat-engine-BYT5ayQH.js +83 -0
  63. package/dist/hub-D0XwdjM-.js +515 -0
  64. package/dist/hub-LiD5Iztb.js +6 -0
  65. package/dist/hyperclawbot-zvczQgKx.js +505 -0
  66. package/dist/inference-BKVkBREb.js +6 -0
  67. package/dist/inference-DCXH4Q3x.js +922 -0
  68. package/dist/knowledge-graph-iBG76fvm.js +131 -0
  69. package/dist/loader-CC45xGpC.js +4 -0
  70. package/dist/loader-CnEdOyjT.js +400 -0
  71. package/dist/logger-ybOp7VOC.js +83 -0
  72. package/dist/manager-03ipO9R0.js +105 -0
  73. package/dist/manager-BpDfbDjg.js +117 -0
  74. package/dist/manager-Bxl0sqlh.js +4 -0
  75. package/dist/manager-CrVDn6eN.js +6 -0
  76. package/dist/manager-FCgF1plu.js +218 -0
  77. package/dist/manager-rgCsaWT1.js +40 -0
  78. package/dist/mcp-CfoSU4Uz.js +139 -0
  79. package/dist/mcp-loader-DkRBsLpk.js +94 -0
  80. package/dist/memory-BlHL7JCO.js +4 -0
  81. package/dist/memory-DsS_eFvJ.js +270 -0
  82. package/dist/memory-auto-BkvtSFUw.js +5 -0
  83. package/dist/memory-auto-Bnz_-1wP.js +306 -0
  84. package/dist/memory-integration-cSYkZyEo.js +91 -0
  85. package/dist/moltbook-BtLDZTfM.js +81 -0
  86. package/dist/node-Dw2Gi-cP.js +222 -0
  87. package/dist/nodes-registry-B8dmrlLv.js +52 -0
  88. package/dist/oauth-flow-DQPvMHRH.js +150 -0
  89. package/dist/oauth-provider-Uo4Nib_c.js +110 -0
  90. package/dist/observability-BV-Yx0V9.js +89 -0
  91. package/dist/onboard-0WoDxbv_.js +10 -0
  92. package/dist/onboard-BXNXCQp4.js +4070 -0
  93. package/dist/orchestrator-DmnEvMaL.js +189 -0
  94. package/dist/orchestrator-RI3bpqqc.js +6 -0
  95. package/dist/pairing-6iM27aD8.js +196 -0
  96. package/dist/pairing-dGoiGepK.js +4 -0
  97. package/dist/pc-access-CgCsYrpt.js +8 -0
  98. package/dist/pc-access-_iH2aorG.js +819 -0
  99. package/dist/pending-approval-CUXjysAo.js +22 -0
  100. package/dist/reminders-store-Drjed_-h.js +58 -0
  101. package/dist/renderer-BVQrd0_g.js +225 -0
  102. package/dist/rules-BE4GV6cV.js +103 -0
  103. package/dist/run-main.js +1607 -443
  104. package/dist/runner-DatMMYYE.js +1271 -0
  105. package/dist/sdk/index.js +2 -2
  106. package/dist/sdk/index.mjs +2 -2
  107. package/dist/security-BqNyT4ID.js +4 -0
  108. package/dist/security-tpgqPWWH.js +73 -0
  109. package/dist/server-D4wVHiX9.js +4 -0
  110. package/dist/server-Dh3JlBFB.js +1255 -0
  111. package/dist/session-store-BUiPz0Vv.js +5 -0
  112. package/dist/session-store-is4B6qmD.js +113 -0
  113. package/dist/sessions-tools-CbUTFe4i.js +5 -0
  114. package/dist/sessions-tools-CeqD7iil.js +95 -0
  115. package/dist/skill-loader-BaNLVmJy.js +7 -0
  116. package/dist/skill-loader-HgpF6Vqs.js +159 -0
  117. package/dist/skill-runtime-CJN24QPW.js +102 -0
  118. package/dist/skill-runtime-w1ig_lcw.js +5 -0
  119. package/dist/src-BxPHKO5x.js +63 -0
  120. package/dist/src-DIc-L2IG.js +20 -0
  121. package/dist/src-g_rNx5rh.js +458 -0
  122. package/dist/sub-agent-tools-CHQoHz9c.js +39 -0
  123. package/dist/theme-DcxwcUgZ.js +180 -0
  124. package/dist/theme-cx0fkgWC.js +8 -0
  125. package/dist/tool-policy-CNT-mF2Z.js +189 -0
  126. package/dist/tts-elevenlabs-BRosZv-f.js +61 -0
  127. package/dist/update-check-C2Dz85wJ.js +81 -0
  128. package/dist/vision-BMmiIKy7.js +121 -0
  129. package/dist/vision-tools-DVuYc17I.js +51 -0
  130. package/dist/vision-tools-U3YC4L-g.js +5 -0
  131. package/dist/voice-transcription-B555DbWR.js +138 -0
  132. package/dist/website-watch-tools-DFMrJU-R.js +139 -0
  133. package/dist/website-watch-tools-Du3W5sN7.js +5 -0
  134. package/package.json +1 -1
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- <p align="center">
1
+ <p align="center">
2
2
  <img src="assets/icon.png" width="120" alt="HyperClaw">
3
3
  <br>
4
4
  <h1 align="center">🦅 HyperClaw — Personal AI Assistant</h1>
@@ -6,7 +6,7 @@
6
6
 
7
7
  <p align="center">
8
8
  <img src="https://img.shields.io/badge/build-passing-brightgreen?style=flat-square" alt="build">
9
- <img src="https://img.shields.io/badge/release-v4.0.2-blue?style=flat-square" alt="release">
9
+ <img src="https://img.shields.io/badge/release-v5.0.0-blue?style=flat-square" alt="release">
10
10
  <img src="https://img.shields.io/badge/node-%E2%89%A522-green?style=flat-square" alt="node">
11
11
  <img src="https://img.shields.io/badge/license-MIT-gray?style=flat-square" alt="license">
12
12
  <img src="https://img.shields.io/badge/typescript-5.4-3178c6?style=flat-square&logo=typescript&logoColor=white" alt="typescript">
@@ -68,6 +68,19 @@ hyperclaw onboard
68
68
  hyperclaw onboard --install-daemon
69
69
  ```
70
70
 
71
+ ## Uninstall
72
+
73
+ ```bash
74
+ # Stop and remove daemon (if running)
75
+ hyperclaw daemon uninstall
76
+
77
+ # Remove the package
78
+ npm uninstall -g hyperclaw
79
+
80
+ # Remove config and data (optional)
81
+ rm -rf ~/.hyperclaw
82
+ ```
83
+
71
84
  > **Windows users**: HyperClaw runs natively via Node.js. No WSL2, no admin rights needed.
72
85
  > The daemon uses **Task Scheduler** and runs as your user account with full desktop access.
73
86
 
@@ -104,7 +117,7 @@ Upgrading? Run `hyperclaw doctor` to check and migrate.
104
117
 
105
118
  ## Channels
106
119
 
107
- HyperClaw connects to the channels you already use (27 channels):
120
+ HyperClaw connects to the channels you already use (28+ channels):
108
121
 
109
122
  | Channel | Status | Notes |
110
123
  |---------|--------|-------|
@@ -136,6 +149,8 @@ HyperClaw connects to the channels you already use (27 channels):
136
149
  | 🎙️ Voice Call | ✅ Available | Terminal voice session |
137
150
  | 🌐 Chrome Extension | ✅ Available | Browser sidebar |
138
151
 
152
+ Twitch is also available via IRC over WebSocket.
153
+
139
154
  Add a channel:
140
155
 
141
156
  ```bash
@@ -290,6 +305,42 @@ Send these in any connected channel (Telegram, Discord, Slack, etc.):
290
305
  | `/verbose on\|off` | Verbose mode |
291
306
  | `/usage off\|tokens\|full` | Per-response usage footer |
292
307
 
308
+ ## HyperClaw Bot commands
309
+
310
+ Control the gateway remotely via your Telegram or Discord bot (`hyperclaw bot start`):
311
+
312
+ | Command | Description |
313
+ |---------|-------------|
314
+ | `/status` | Gateway + daemon status |
315
+ | `/restart` | Restart the gateway |
316
+ | `/logs [n]` | Last N log lines (default 20) |
317
+ | `/channels` | List configured channels |
318
+ | `/approve <ch> <code>` | Approve a DM pairing code |
319
+ | `/hook list` | List all hooks |
320
+ | `/hook on <id>` | Enable a hook |
321
+ | `/hook off <id>` | Disable a hook |
322
+ | `/agent <msg>` | Send a message to the AI agent |
323
+ | `/activation` | Show current group activation mode |
324
+ | `/activation mention` | Bot responds only to @mentions and replies _(default)_ |
325
+ | `/activation always` | Bot responds to all messages in a group |
326
+ | `/security` | Security audit summary |
327
+ | `/help` | List all commands |
328
+
329
+ ## Agent-to-Agent (session tools)
330
+
331
+ When the gateway is running, the agent has access to session tools for agent-to-agent communication:
332
+
333
+ | Tool | Description |
334
+ |------|-------------|
335
+ | `sessions_list` | List all active WebSocket sessions connected to the gateway |
336
+ | `sessions_send` | Send a message to another session (by session ID) |
337
+ | `sessions_history` | Get the chat transcript of a session (`"self"` for current) |
338
+
339
+ Example — ask the agent to ping another session:
340
+ ```
341
+ "List all connected sessions and send a hello to the first one"
342
+ ```
343
+
293
344
  ---
294
345
 
295
346
  ## From source
@@ -0,0 +1,75 @@
1
+ const require_chunk = require('./chunk-jS-bbMI5.js');
2
+
3
+ //#region src/canvas/a2ui-protocol.ts
4
+ /** Map HyperClaw component type to A2UI-compatible type. */
5
+ function toA2UIType(t) {
6
+ const map = {
7
+ chart: "chart",
8
+ table: "table",
9
+ form: "form",
10
+ markdown: "markdown",
11
+ image: "image",
12
+ custom: "custom",
13
+ script: "script"
14
+ };
15
+ return map[t] || "custom";
16
+ }
17
+ /** Convert a CanvasComponent to A2UI surface. */
18
+ function componentToSurface(c) {
19
+ return {
20
+ id: c.id,
21
+ type: toA2UIType(c.type),
22
+ props: {
23
+ title: c.title,
24
+ width: c.width || "half"
25
+ },
26
+ data: c.data
27
+ };
28
+ }
29
+ /** Generate beginRendering from canvas state (full sync). */
30
+ function toBeginRendering(canvas) {
31
+ const surfaces = canvas.components.map(componentToSurface);
32
+ const dataModel = {};
33
+ for (const c of canvas.components) if (c.data != null) dataModel[c.id] = c.data;
34
+ return {
35
+ type: "beginRendering",
36
+ surfaceId: canvas.id,
37
+ surfaces,
38
+ dataModel: Object.keys(dataModel).length ? dataModel : void 0
39
+ };
40
+ }
41
+ /** Generate surfaceUpdate for newly added component. */
42
+ function toSurfaceUpdate(canvasId, component) {
43
+ return {
44
+ type: "surfaceUpdate",
45
+ surfaceId: canvasId,
46
+ surfaces: [componentToSurface(component)]
47
+ };
48
+ }
49
+ /** Generate dataModelUpdate when component data changes. */
50
+ function toDataModelUpdate(canvasId, componentId, data) {
51
+ return {
52
+ type: "dataModelUpdate",
53
+ surfaceId: canvasId,
54
+ updates: { [componentId]: data }
55
+ };
56
+ }
57
+ /** Generate deleteSurface for removed components. */
58
+ function toDeleteSurface(canvasId, componentIds) {
59
+ return {
60
+ type: "deleteSurface",
61
+ surfaceId: canvasId,
62
+ surfaceIds: componentIds
63
+ };
64
+ }
65
+ /** Serialize A2UI messages to JSONL (one message per line). */
66
+ function toJSONL(messages) {
67
+ return messages.map((m) => JSON.stringify(m)).join("\n");
68
+ }
69
+
70
+ //#endregion
71
+ exports.toBeginRendering = toBeginRendering;
72
+ exports.toDataModelUpdate = toDataModelUpdate;
73
+ exports.toDeleteSurface = toDeleteSurface;
74
+ exports.toJSONL = toJSONL;
75
+ exports.toSurfaceUpdate = toSurfaceUpdate;
@@ -0,0 +1,327 @@
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 fs_extra = require_chunk.__toESM(require("fs-extra"));
5
+ const path = require_chunk.__toESM(require("path"));
6
+ const os = require_chunk.__toESM(require("os"));
7
+
8
+ //#region src/routing/session-key.ts
9
+ /**
10
+
11
+ * Compute the canonical session key for an inbound message context.
12
+
13
+ */
14
+ function computeSessionKey(ctx) {
15
+ const { agentId, channel, peerKind, peerId, threadId, topicId, dmScope } = ctx;
16
+ if (peerKind === "dm") {
17
+ if (dmScope === "main" || dmScope === void 0) return `agent:${agentId}:main`;
18
+ return `agent:${agentId}:${channel}:dm:${peerId}`;
19
+ }
20
+ if (peerKind === "group") {
21
+ let key$1 = `agent:${agentId}:${channel}:group:${peerId}`;
22
+ if (topicId) key$1 += `:topic:${topicId}`;
23
+ if (threadId) key$1 += `:thread:${threadId}`;
24
+ return key$1;
25
+ }
26
+ let key = `agent:${agentId}:${channel}:channel:${peerId}`;
27
+ if (threadId) key += `:thread:${threadId}`;
28
+ return key;
29
+ }
30
+
31
+ //#endregion
32
+ //#region src/routing/agents-routing.ts
33
+ const STATE_FILE = path.default.join(os.default.homedir(), ".hyperclaw", "routing.json");
34
+ const DEFAULT_AGENT = {
35
+ id: "main",
36
+ name: "main",
37
+ workspace: path.default.join(os.default.homedir(), ".hyperclaw", "workspace"),
38
+ default: true
39
+ };
40
+ var AgentRouter = class {
41
+ config;
42
+ constructor(config) {
43
+ this.config = config ?? this._loadConfig();
44
+ }
45
+ _loadConfig() {
46
+ try {
47
+ return fs_extra.default.readJsonSync(STATE_FILE);
48
+ } catch {
49
+ return {
50
+ agents: { list: [DEFAULT_AGENT] },
51
+ bindings: [],
52
+ session: { dmScope: "main" }
53
+ };
54
+ }
55
+ }
56
+ _saveConfig() {
57
+ fs_extra.default.ensureDirSync(path.default.dirname(STATE_FILE));
58
+ fs_extra.default.writeJsonSync(STATE_FILE, this.config, { spaces: 2 });
59
+ }
60
+ route(msg) {
61
+ const agents = this.config.agents?.list ?? [DEFAULT_AGENT];
62
+ const bindings = this.config.bindings ?? [];
63
+ const broadcastAgents = this._resolveBroadcast(msg);
64
+ const matched = this._matchBinding(msg, bindings, agents);
65
+ const agentDef = matched.agentDef;
66
+ const sessionKey = this._computeKey(msg, agentDef.id);
67
+ const skipLastRoute = msg.isDM ? this._shouldSkipLastRoute(msg) : false;
68
+ return {
69
+ agentId: agentDef.id,
70
+ agentDef,
71
+ sessionKey,
72
+ matchedBy: matched.matchedBy,
73
+ ...broadcastAgents.length > 1 ? { broadcast: broadcastAgents } : {},
74
+ ...skipLastRoute ? { skipLastRoute: true } : {}
75
+ };
76
+ }
77
+ _matchBinding(msg, bindings, agents) {
78
+ const find = (id) => agents.find((a) => a.id === id) ?? DEFAULT_AGENT;
79
+ for (const b of bindings) {
80
+ if (!this._matchesFilter(msg, b.match)) continue;
81
+ return {
82
+ agentDef: find(b.agentId),
83
+ matchedBy: this._describeMatch(b.match)
84
+ };
85
+ }
86
+ const defaultAgent = agents.find((a) => a.default) ?? agents[0] ?? DEFAULT_AGENT;
87
+ return {
88
+ agentDef: defaultAgent,
89
+ matchedBy: "default"
90
+ };
91
+ }
92
+ _matchesFilter(msg, match) {
93
+ if (match.channel && match.channel !== msg.channel) return false;
94
+ if (match.accountId && match.accountId !== "*" && match.accountId !== msg.accountId) return false;
95
+ if (match.peer) {
96
+ if (match.peer.kind !== msg.peer.kind) return false;
97
+ if (match.peer.id !== msg.peer.id) return false;
98
+ }
99
+ if (match.guildId && match.guildId !== msg.guildId) return false;
100
+ if (match.roles?.length) {
101
+ const senderRoles = msg.roles ?? [];
102
+ if (!match.roles.every((r) => senderRoles.includes(r))) return false;
103
+ }
104
+ if (match.teamId && match.teamId !== msg.teamId) return false;
105
+ return true;
106
+ }
107
+ _describeMatch(m) {
108
+ const parts = [];
109
+ if (m.channel) parts.push(`channel=${m.channel}`);
110
+ if (m.peer) parts.push(`peer=${m.peer.kind}:${m.peer.id}`);
111
+ if (m.guildId) parts.push(`guild=${m.guildId}`);
112
+ if (m.teamId) parts.push(`team=${m.teamId}`);
113
+ if (m.accountId) parts.push(`account=${m.accountId}`);
114
+ return parts.join(" ") || "channel-match";
115
+ }
116
+ _computeKey(msg, agentId) {
117
+ const dmScope = this.config.session?.dmScope ?? "main";
118
+ const ctx = {
119
+ agentId,
120
+ channel: msg.channel,
121
+ peerKind: msg.isDM ? "dm" : msg.peer.kind,
122
+ peerId: msg.peer.id,
123
+ threadId: msg.threadId,
124
+ topicId: msg.topicId,
125
+ dmScope: msg.isDM ? dmScope : void 0
126
+ };
127
+ return computeSessionKey(ctx);
128
+ }
129
+ _resolveBroadcast(msg) {
130
+ const bc = this.config.broadcast;
131
+ if (!bc) return [];
132
+ const agentIds = bc[msg.peer.id] ?? bc[msg.senderId];
133
+ if (Array.isArray(agentIds)) return agentIds;
134
+ return [];
135
+ }
136
+ /**
137
+ * Returns true when the inbound DM sender is not the pinned owner.
138
+ * Pinned owner = the single non-wildcard allowFrom entry for this channel.
139
+ */
140
+ _shouldSkipLastRoute(msg) {
141
+ const chanCfg = this.config.channels?.[msg.channel];
142
+ if (!chanCfg?.allowFrom) return false;
143
+ const nonWild = chanCfg.allowFrom.filter((id) => id !== "*" && id !== "**");
144
+ if (nonWild.length !== 1) return false;
145
+ const pinnedOwner = nonWild[0];
146
+ return msg.senderId !== pinnedOwner;
147
+ }
148
+ resolveDefaultAccount(channelId) {
149
+ return this.config.channels?.[channelId]?.defaultAccount;
150
+ }
151
+ listBindings() {
152
+ const agents = this.config.agents?.list ?? [];
153
+ const bindings = this.config.bindings ?? [];
154
+ console.log(chalk.default.bold.cyan("\n 🦅 AGENT BINDINGS\n"));
155
+ if (agents.length === 0) {
156
+ console.log(chalk.default.gray(" No agents configured.\n"));
157
+ return;
158
+ }
159
+ for (const a of agents) {
160
+ const def = a.default ? chalk.default.green(" [default]") : "";
161
+ const model = a.model ? chalk.default.gray(` model:${a.model}`) : "";
162
+ console.log(` ${chalk.default.bold(a.id)}${def} ${chalk.default.gray(a.workspace)}${model}`);
163
+ }
164
+ console.log();
165
+ if (bindings.length === 0) {
166
+ console.log(chalk.default.gray(" No explicit bindings — all traffic → default agent.\n"));
167
+ return;
168
+ }
169
+ console.log(chalk.default.bold(" Bindings:\n"));
170
+ for (const b of bindings) {
171
+ const m = b.match;
172
+ const parts = [];
173
+ if (m.channel) parts.push(chalk.default.cyan(m.channel));
174
+ if (m.peer) parts.push(`peer:${m.peer.kind}/${chalk.default.white(m.peer.id)}`);
175
+ if (m.guildId) parts.push(`guild:${chalk.default.white(m.guildId)}`);
176
+ if (m.teamId) parts.push(`team:${chalk.default.white(m.teamId)}`);
177
+ if (m.roles?.length) parts.push(`roles:[${m.roles.join(",")}]`);
178
+ if (m.accountId) parts.push(`account:${m.accountId}`);
179
+ console.log(` ${parts.join(" ")} ${chalk.default.gray("→")} ${chalk.default.bold(b.agentId)}`);
180
+ }
181
+ const bc = this.config.broadcast;
182
+ if (bc) {
183
+ console.log(chalk.default.bold("\n Broadcast groups:\n"));
184
+ const strat = bc.strategy ?? "parallel";
185
+ for (const [peerId, agents$1] of Object.entries(bc)) {
186
+ if (peerId === "strategy") continue;
187
+ if (Array.isArray(agents$1)) console.log(` ${chalk.default.white(peerId)} ${chalk.default.gray(`→ [${agents$1.join(", ")}]`)} ${chalk.default.gray(`(${strat})`)}`);
188
+ }
189
+ }
190
+ console.log();
191
+ }
192
+ async bind() {
193
+ console.log(chalk.default.cyan("\n Bind a channel/peer to an agent\n"));
194
+ const { channel, matchType } = await inquirer.default.prompt([{
195
+ type: "input",
196
+ name: "channel",
197
+ message: "Channel ID (e.g. telegram, discord, slack, whatsapp):",
198
+ validate: (v) => v.trim().length > 0 || "Required"
199
+ }, {
200
+ type: "list",
201
+ name: "matchType",
202
+ message: "Match by:",
203
+ choices: [
204
+ {
205
+ name: "Any message on this channel",
206
+ value: "channel"
207
+ },
208
+ {
209
+ name: "Specific peer (group ID, user ID, channel ID)",
210
+ value: "peer"
211
+ },
212
+ {
213
+ name: "Discord guild",
214
+ value: "guild"
215
+ },
216
+ {
217
+ name: "Slack team",
218
+ value: "team"
219
+ },
220
+ {
221
+ name: "Account ID",
222
+ value: "account"
223
+ }
224
+ ]
225
+ }]);
226
+ const match = { channel };
227
+ if (matchType === "peer") {
228
+ const { kind, peerId } = await inquirer.default.prompt([{
229
+ type: "list",
230
+ name: "kind",
231
+ message: "Peer type:",
232
+ choices: [
233
+ "group",
234
+ "channel",
235
+ "dm",
236
+ "room"
237
+ ]
238
+ }, {
239
+ type: "input",
240
+ name: "peerId",
241
+ message: "Peer ID:",
242
+ validate: (v) => v.trim().length > 0 || "Required"
243
+ }]);
244
+ match.peer = {
245
+ kind,
246
+ id: peerId
247
+ };
248
+ } else if (matchType === "guild") {
249
+ const { guildId } = await inquirer.default.prompt([{
250
+ type: "input",
251
+ name: "guildId",
252
+ message: "Discord guild ID:",
253
+ validate: (v) => v.trim().length > 0 || "Required"
254
+ }]);
255
+ match.guildId = guildId;
256
+ } else if (matchType === "team") {
257
+ const { teamId } = await inquirer.default.prompt([{
258
+ type: "input",
259
+ name: "teamId",
260
+ message: "Slack team ID:",
261
+ validate: (v) => v.trim().length > 0 || "Required"
262
+ }]);
263
+ match.teamId = teamId;
264
+ } else if (matchType === "account") {
265
+ const { accountId } = await inquirer.default.prompt([{
266
+ type: "input",
267
+ name: "accountId",
268
+ message: "Account ID:",
269
+ validate: (v) => v.trim().length > 0 || "Required"
270
+ }]);
271
+ match.accountId = accountId;
272
+ }
273
+ const agentIds = (this.config.agents?.list ?? []).map((a) => a.id);
274
+ const { agentId } = await inquirer.default.prompt([{
275
+ type: agentIds.length > 1 ? "list" : "input",
276
+ name: "agentId",
277
+ message: "Route to agent ID:",
278
+ choices: agentIds.length > 1 ? agentIds : void 0,
279
+ default: agentIds[0] ?? "main"
280
+ }]);
281
+ if (!this.config.bindings) this.config.bindings = [];
282
+ this.config.bindings.unshift({
283
+ match,
284
+ agentId,
285
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
286
+ });
287
+ this._saveConfig();
288
+ console.log(chalk.default.green(`\n ✔ Binding added: ${channel}/${matchType} → ${agentId}\n`));
289
+ }
290
+ async unbind() {
291
+ const bindings = this.config.bindings ?? [];
292
+ if (bindings.length === 0) {
293
+ console.log(chalk.default.gray("\n No bindings to remove.\n"));
294
+ return;
295
+ }
296
+ const { toRemove } = await inquirer.default.prompt([{
297
+ type: "checkbox",
298
+ name: "toRemove",
299
+ message: "Select bindings to remove:",
300
+ choices: bindings.map((b, i) => ({
301
+ name: `${this._describeMatch(b.match)} → ${b.agentId}`,
302
+ value: i
303
+ }))
304
+ }]);
305
+ for (const idx of toRemove.sort((a, b) => b - a)) bindings.splice(idx, 1);
306
+ this.config.bindings = bindings;
307
+ this._saveConfig();
308
+ console.log(chalk.default.green(`\n ✔ Removed ${toRemove.length} binding(s)\n`));
309
+ }
310
+ getConfig() {
311
+ return this.config;
312
+ }
313
+ getAgents() {
314
+ return this.config.agents?.list ?? [DEFAULT_AGENT];
315
+ }
316
+ getBindings() {
317
+ return this.config.bindings ?? [];
318
+ }
319
+ };
320
+
321
+ //#endregion
322
+ Object.defineProperty(exports, 'AgentRouter', {
323
+ enumerable: true,
324
+ get: function () {
325
+ return AgentRouter;
326
+ }
327
+ });
@@ -0,0 +1,4 @@
1
+ const require_chunk = require('./chunk-jS-bbMI5.js');
2
+ const require_agents_routing = require('./agents-routing-ChHiZp36.js');
3
+
4
+ exports.AgentRouter = require_agents_routing.AgentRouter;
@@ -0,0 +1,149 @@
1
+ const require_chunk = require('./chunk-jS-bbMI5.js');
2
+
3
+ //#region src/infra/api-keys-guide.ts
4
+ const API_KEYS_GUIDE = [
5
+ {
6
+ serviceId: "anthropic",
7
+ name: "Anthropic (Claude)",
8
+ envVar: "ANTHROPIC_API_KEY",
9
+ url: "platform.anthropic.com",
10
+ setupSteps: [
11
+ "1. Go to platform.anthropic.com → API Keys.",
12
+ "2. Sign up / sign in with an Anthropic account.",
13
+ "3. Create Key — copy it (starts with sk-ant-). Not shown again!",
14
+ "",
15
+ " 🔗 platform.anthropic.com/settings/keys"
16
+ ]
17
+ },
18
+ {
19
+ serviceId: "openai",
20
+ name: "OpenAI (GPT)",
21
+ envVar: "OPENAI_API_KEY",
22
+ url: "platform.openai.com",
23
+ setupSteps: [
24
+ "1. Go to platform.openai.com → API keys.",
25
+ "2. Create new secret key — copy it (starts with sk-). Not shown again!",
26
+ "3. You need billing enabled for production use.",
27
+ "",
28
+ " 🔗 platform.openai.com/api-keys"
29
+ ]
30
+ },
31
+ {
32
+ serviceId: "openrouter",
33
+ name: "OpenRouter",
34
+ envVar: "OPENROUTER_API_KEY",
35
+ url: "openrouter.ai",
36
+ setupSteps: [
37
+ "1. Go to openrouter.ai → Keys.",
38
+ "2. Sign in (Google/GitHub).",
39
+ "3. Create Key — copy it. OpenRouter provides access to many models (Claude, GPT etc.).",
40
+ "",
41
+ " 🔗 openrouter.ai/keys"
42
+ ]
43
+ },
44
+ {
45
+ serviceId: "tavily",
46
+ name: "Tavily (Web Search)",
47
+ envVar: "TAVILY_API_KEY",
48
+ url: "tavily.com",
49
+ setupSteps: [
50
+ "1. Go to tavily.com → Sign up.",
51
+ "2. Dashboard → API Keys → Create API Key.",
52
+ "3. Copy the key. Used for the web-search skill.",
53
+ "",
54
+ " 🔗 app.tavily.com"
55
+ ]
56
+ },
57
+ {
58
+ serviceId: "elevenlabs",
59
+ name: "ElevenLabs (TTS)",
60
+ envVar: "ELEVENLABS_API_KEY",
61
+ url: "elevenlabs.io",
62
+ setupSteps: [
63
+ "1. Go to elevenlabs.io → Profile → API Key.",
64
+ "2. Copy the API key (or create a new one).",
65
+ "3. Used for talk mode (voice responses).",
66
+ "",
67
+ " 🔗 elevenlabs.io/app/settings/api-keys"
68
+ ]
69
+ },
70
+ {
71
+ serviceId: "deepl",
72
+ name: "DeepL (Translation)",
73
+ envVar: "DEEPL_API_KEY",
74
+ url: "deepl.com",
75
+ setupSteps: [
76
+ "1. Go to deepl.com/pro-api → Get API key.",
77
+ "2. Sign up (free tier available).",
78
+ "3. Account → API keys — copy the Authentication Key.",
79
+ "",
80
+ " 🔗 deepl.com/pro-api"
81
+ ]
82
+ },
83
+ {
84
+ serviceId: "github",
85
+ name: "GitHub (PAT)",
86
+ envVar: "GITHUB_TOKEN",
87
+ url: "github.com",
88
+ setupSteps: [
89
+ "1. GitHub → Settings → Developer settings → Personal access tokens.",
90
+ "2. Generate new token (classic or fine-grained).",
91
+ "3. Select scopes: repo, read:user etc. depending on use case.",
92
+ "",
93
+ " 🔗 github.com/settings/tokens"
94
+ ]
95
+ },
96
+ {
97
+ serviceId: "xai",
98
+ name: "xAI (Grok)",
99
+ envVar: "XAI_API_KEY",
100
+ url: "x.ai",
101
+ setupSteps: [
102
+ "1. Go to console.x.ai → API keys.",
103
+ "2. Sign in and create a new key.",
104
+ "3. Copy the key.",
105
+ "",
106
+ " 🔗 console.x.ai"
107
+ ]
108
+ },
109
+ {
110
+ serviceId: "google",
111
+ name: "Google AI (Gemini)",
112
+ envVar: "GOOGLE_AI_API_KEY",
113
+ url: "ai.google.dev",
114
+ setupSteps: [
115
+ "1. Go to aistudio.google.com/apikey.",
116
+ "2. Get API key or Create API key.",
117
+ "3. Copy the key.",
118
+ "",
119
+ " 🔗 aistudio.google.com/apikey"
120
+ ]
121
+ }
122
+ ];
123
+ const SERVICE_ID_MAP = new Map(API_KEYS_GUIDE.map((g) => [g.serviceId.toLowerCase(), g]));
124
+ /** Known name aliases (e.g. anthropic, claude -> anthropic) */
125
+ const ALIASES = {
126
+ claude: "anthropic",
127
+ gpt: "openai",
128
+ xai: "xai",
129
+ google: "google"
130
+ };
131
+ function getApiKeyGuide(serviceId) {
132
+ const id = serviceId.toLowerCase().replace(/[^a-z0-9-]/g, "");
133
+ return SERVICE_ID_MAP.get(id) ?? SERVICE_ID_MAP.get(ALIASES[id] ?? "") ?? null;
134
+ }
135
+ /** For unknown services — generic API key instructions */
136
+ const GENERIC_API_KEY_STEPS = [
137
+ "For an unknown service:",
138
+ "1. Go to the official service website (e.g. developers.xxx.com).",
139
+ "2. Sign up / sign in. An account is usually required.",
140
+ "3. Look for \"API Keys\", \"Credentials\", \"Developer\" or \"Integrations\" section.",
141
+ "4. Create a new API key or token. Copy it immediately — many services do not show it again.",
142
+ "5. Keep it secret — do not share it or commit it to a repo.",
143
+ "",
144
+ " 💡 Known services: anthropic, openai, openrouter, tavily, elevenlabs, deepl, github, xai, google"
145
+ ];
146
+
147
+ //#endregion
148
+ exports.GENERIC_API_KEY_STEPS = GENERIC_API_KEY_STEPS;
149
+ exports.getApiKeyGuide = getApiKeyGuide;