hyperclaw 5.0.0 → 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.
Files changed (65) hide show
  1. package/README.md +204 -69
  2. package/dist/api-keys-guide-CGn5BSF7.js +149 -0
  3. package/dist/audit-BJohI_vC.js +441 -0
  4. package/dist/bounty-tools-CY_i91DU.js +211 -0
  5. package/dist/claw-tasks-Cyzdbhz_.js +80 -0
  6. package/dist/cost-tracker-Ca1UPZ33.js +103 -0
  7. package/dist/credentials-store-CA8UtK0T.js +77 -0
  8. package/dist/credentials-store-Cm7DH-kh.js +4 -0
  9. package/dist/cron-tasks-_pqQCmxc.js +82 -0
  10. package/dist/daemon-7ViroziB.js +5 -0
  11. package/dist/daemon-BfyKmZhr.js +318 -0
  12. package/dist/delivery-DVHmv1IR.js +4 -0
  13. package/dist/delivery-DpMX0Yyc.js +95 -0
  14. package/dist/destructive-gate-DZt71UZR.js +101 -0
  15. package/dist/engine-B0kLfRL0.js +256 -0
  16. package/dist/engine-BJUpRUOv.js +7 -0
  17. package/dist/env-resolve-17ekEU6p.js +10 -0
  18. package/dist/env-resolve-Z2XF6leB.js +115 -0
  19. package/dist/heartbeat-engine-Ut6pXBD6.js +83 -0
  20. package/dist/hub-9LaKnLjY.js +6 -0
  21. package/dist/hub-CfwUz9YW.js +515 -0
  22. package/dist/hyperclawbot-CBiDSKsa.js +505 -0
  23. package/dist/inference-0mlFQqIm.js +922 -0
  24. package/dist/inference-SzqFe_nk.js +6 -0
  25. package/dist/knowledge-graph-DE5lSF02.js +131 -0
  26. package/dist/loader-BkDi8MD9.js +400 -0
  27. package/dist/loader-DI2qDRPC.js +4 -0
  28. package/dist/logger-Cp8wC7F8.js +83 -0
  29. package/dist/manager-B2Gls5RG.js +218 -0
  30. package/dist/manager-CWNSML5D.js +117 -0
  31. package/dist/manager-SJe9gt-q.js +4 -0
  32. package/dist/mcp-loader-CvxRDtPC.js +94 -0
  33. package/dist/memory-auto-CpQHZlEJ.js +306 -0
  34. package/dist/memory-auto-Z6LCf-iK.js +5 -0
  35. package/dist/memory-integration-g2vxwgoE.js +91 -0
  36. package/dist/moltbook-Cl8cQfxJ.js +81 -0
  37. package/dist/nodes-registry-C9dCFwjh.js +52 -0
  38. package/dist/oauth-flow-CeaaGAz0.js +150 -0
  39. package/dist/oauth-provider-B4dzn56l.js +110 -0
  40. package/dist/observability-nZ3CBIxG.js +89 -0
  41. package/dist/onboard-BBBWcfhp.js +10 -0
  42. package/dist/onboard-Bw28IRQ3.js +4070 -0
  43. package/dist/orchestrator-BovkM63z.js +6 -0
  44. package/dist/orchestrator-DSbpkP1X.js +189 -0
  45. package/dist/osint-B4_m3VHQ.js +277 -0
  46. package/dist/pending-approval-BgNjjuI2.js +22 -0
  47. package/dist/run-main.js +82 -67
  48. package/dist/runner-CJFJUtPm.js +1271 -0
  49. package/dist/sdk/index.js +2 -2
  50. package/dist/sdk/index.mjs +2 -2
  51. package/dist/server-Brl_HQUB.js +1255 -0
  52. package/dist/server-DhfipkwN.js +4 -0
  53. package/dist/skill-runtime-BXWd-Ktf.js +102 -0
  54. package/dist/skill-runtime-jgklm02e.js +5 -0
  55. package/dist/src-Bhybpk1J.js +63 -0
  56. package/dist/src-DMJ4-uqk.js +458 -0
  57. package/dist/sub-agent-tools-DHY-4WWM.js +39 -0
  58. package/dist/tool-policy-DZvF8xlQ.js +189 -0
  59. package/dist/tts-elevenlabs-C06nUxMK.js +61 -0
  60. package/dist/update-check-w4XuxVl7.js +81 -0
  61. package/dist/vision-JOtOS1Br.js +121 -0
  62. package/dist/vision-tools-CB28ZCO_.js +5 -0
  63. package/dist/vision-tools-vPPwQ-0N.js +51 -0
  64. package/dist/voice-transcription-DBo5hXmu.js +138 -0
  65. package/package.json +1 -1
@@ -0,0 +1,306 @@
1
+ const require_chunk = require('./chunk-jS-bbMI5.js');
2
+ const chalk = require_chunk.__toESM(require("chalk"));
3
+ const fs_extra = require_chunk.__toESM(require("fs-extra"));
4
+ const path = require_chunk.__toESM(require("path"));
5
+ const os = require_chunk.__toESM(require("os"));
6
+
7
+ //#region packages/core/src/agent/memory-auto.ts
8
+ function isSensitive(text) {
9
+ return SENSITIVE_PATTERNS.some((p) => p.test(text));
10
+ }
11
+ function extractFactsLocally(turns) {
12
+ const facts = [];
13
+ const userMessages = turns.filter((t) => t.role === "user").map((t) => t.content);
14
+ for (const msg of userMessages) {
15
+ if (isSensitive(msg)) continue;
16
+ for (const pattern of PREFERENCE_PATTERNS) {
17
+ const m = msg.match(pattern);
18
+ if (m?.[1] && m[1].length > 4) facts.push({
19
+ fact: `User preference: ${m[1].trim()}`,
20
+ category: "preference",
21
+ confidence: "high"
22
+ });
23
+ }
24
+ for (const pattern of IDENTITY_PATTERNS) {
25
+ const m = msg.match(pattern);
26
+ if (m?.[1] && m[1].length > 2) facts.push({
27
+ fact: `About user: ${m[1].trim()}`,
28
+ category: "identity",
29
+ confidence: "high"
30
+ });
31
+ }
32
+ for (const pattern of GOAL_PATTERNS) {
33
+ const m = msg.match(pattern);
34
+ if (m?.[1] && m[1].length > 8) facts.push({
35
+ fact: `User goal: ${m[1].trim()}`,
36
+ category: "goal",
37
+ confidence: "medium"
38
+ });
39
+ }
40
+ }
41
+ const seen = /* @__PURE__ */ new Set();
42
+ return facts.filter((f) => {
43
+ const key = f.fact.toLowerCase().slice(0, 40);
44
+ if (seen.has(key)) return false;
45
+ seen.add(key);
46
+ return true;
47
+ });
48
+ }
49
+ async function readMemory() {
50
+ try {
51
+ return await fs_extra.default.readFile(MEMORY_FILE, "utf8");
52
+ } catch {
53
+ return "";
54
+ }
55
+ }
56
+ async function appendMemory(facts) {
57
+ if (facts.length === 0) return 0;
58
+ const existing = await readMemory();
59
+ const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
60
+ let added = 0;
61
+ const newLines = [];
62
+ const addedFacts = [];
63
+ for (const f of facts) {
64
+ if (existing.toLowerCase().includes(f.fact.toLowerCase().slice(0, 30))) continue;
65
+ newLines.push(`- ${today} [${f.category}] ${f.fact}`);
66
+ addedFacts.push(f);
67
+ added++;
68
+ }
69
+ if (newLines.length === 0) return 0;
70
+ await fs_extra.default.ensureDir(HC_DIR);
71
+ if (!await fs_extra.default.pathExists(MEMORY_FILE)) await fs_extra.default.writeFile(MEMORY_FILE, "# HyperClaw Memory\n\n");
72
+ await fs_extra.default.appendFile(MEMORY_FILE, "\n" + newLines.join("\n") + "\n");
73
+ try {
74
+ const { onMemoryAppended } = await Promise.resolve().then(() => require("./memory-integration-g2vxwgoE.js"));
75
+ await onMemoryAppended(addedFacts.map((f) => ({ fact: f.fact })));
76
+ } catch {}
77
+ return added;
78
+ }
79
+ async function saveMemoryDirect(text) {
80
+ await fs_extra.default.ensureDir(HC_DIR);
81
+ if (!await fs_extra.default.pathExists(MEMORY_FILE)) await fs_extra.default.writeFile(MEMORY_FILE, "# HyperClaw Memory\n\n");
82
+ const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
83
+ await fs_extra.default.appendFile(MEMORY_FILE, `\n- ${today} ${text}\n`);
84
+ try {
85
+ const { onMemoryAppended } = await Promise.resolve().then(() => require("./memory-integration-g2vxwgoE.js"));
86
+ await onMemoryAppended([{ fact: text }]);
87
+ } catch {}
88
+ }
89
+ async function extractFactsWithAI(turns, inferenceOpts) {
90
+ const totalText = turns.map((t) => t.content).join(" ");
91
+ if (totalText.length < 100) return [];
92
+ const localFacts = extractFactsLocally(turns);
93
+ const hasPersonalContext = /\b(I|my|me|mine|myself)\b/i.test(totalText);
94
+ if (!hasPersonalContext) return localFacts;
95
+ try {
96
+ const { InferenceEngine } = await Promise.resolve().then(() => require("./inference-SzqFe_nk.js"));
97
+ const engine = new InferenceEngine({
98
+ model: inferenceOpts.model,
99
+ apiKey: inferenceOpts.apiKey,
100
+ provider: inferenceOpts.provider,
101
+ maxTokens: 512,
102
+ tools: []
103
+ });
104
+ const conversationSummary = turns.slice(-6).map((t) => `${t.role === "user" ? "User" : "AI"}: ${t.content.slice(0, 300)}`).join("\n");
105
+ const result = await engine.run([{
106
+ role: "user",
107
+ content: `Extract ONLY concrete, reusable facts about the USER from this conversation.
108
+ Skip: passwords, API keys, one-off questions, assistant responses.
109
+ Include: name, job, preferences, ongoing projects, locations, recurring tasks.
110
+
111
+ Conversation:
112
+ ${conversationSummary}
113
+
114
+ Respond with a JSON array of strings, each a short fact starting with "User".
115
+ If nothing worth saving, respond: []
116
+ Example: ["User's name is Alex", "User prefers TypeScript over JavaScript", "User is building a SaaS app"]`
117
+ }]);
118
+ const clean = result.text.replace(/```json|```/g, "").trim();
119
+ const aiFactStrings = JSON.parse(clean);
120
+ const allFacts = [...localFacts];
121
+ const existingFactText = localFacts.map((f) => f.fact.toLowerCase());
122
+ for (const factStr of aiFactStrings) {
123
+ if (!factStr || factStr.length < 5) continue;
124
+ if (isSensitive(factStr)) continue;
125
+ if (existingFactText.some((e) => e.includes(factStr.toLowerCase().slice(0, 20)))) continue;
126
+ const cat = /prefer|like|hate|always|never|don't/i.test(factStr) ? "preference" : /goal|want|trying|working on|building/i.test(factStr) ? "goal" : /name|job|work|role|from|based/i.test(factStr) ? "identity" : "context";
127
+ allFacts.push({
128
+ fact: factStr,
129
+ category: cat,
130
+ confidence: "medium"
131
+ });
132
+ }
133
+ return allFacts;
134
+ } catch {
135
+ return localFacts;
136
+ }
137
+ }
138
+ async function showMemory() {
139
+ const content = await readMemory();
140
+ if (!content.trim()) {
141
+ console.log(chalk.default.gray("\n 🧠 MEMORY.md is empty\n"));
142
+ return;
143
+ }
144
+ console.log(chalk.default.bold.cyan("\n 🧠 MEMORY\n"));
145
+ const lines = content.split("\n").filter((l) => l.trim());
146
+ for (const line of lines) if (line.startsWith("#")) console.log(chalk.default.bold.white(line));
147
+ else if (line.startsWith("-")) {
148
+ const parts = line.match(/^-\s+(\S+)\s+\[(\w+)\]\s+(.+)$/);
149
+ if (parts) {
150
+ const [, date, cat, fact] = parts;
151
+ const catColor = cat === "preference" ? chalk.default.cyan : cat === "identity" ? chalk.default.yellow : cat === "goal" ? chalk.default.green : chalk.default.gray;
152
+ console.log(` ${chalk.default.gray(date)} ${catColor(`[${cat}]`)} ${fact}`);
153
+ } else console.log(` ${line}`);
154
+ }
155
+ console.log();
156
+ }
157
+ async function clearMemory() {
158
+ await fs_extra.default.writeFile(MEMORY_FILE, "# HyperClaw Memory\n\n");
159
+ console.log(chalk.default.green(" ✅ Memory cleared\n"));
160
+ }
161
+ async function searchMemory(query) {
162
+ const content = await readMemory();
163
+ const lines = content.split("\n").filter((l) => l.toLowerCase().includes(query.toLowerCase()));
164
+ if (lines.length === 0) {
165
+ console.log(chalk.default.gray(` No memories found for: "${query}"\n`));
166
+ return;
167
+ }
168
+ console.log(chalk.default.bold.cyan(`\n 🔍 Memory search: "${query}"\n`));
169
+ for (const line of lines) console.log(` ${line}`);
170
+ console.log();
171
+ }
172
+ var HC_DIR, MEMORY_FILE, SOUL_FILE, PREFERENCE_PATTERNS, IDENTITY_PATTERNS, GOAL_PATTERNS, SENSITIVE_PATTERNS, AutoMemory;
173
+ var init_memory_auto = require_chunk.__esm({ "packages/core/src/agent/memory-auto.ts"() {
174
+ HC_DIR = path.default.join(os.default.homedir(), ".hyperclaw");
175
+ MEMORY_FILE = path.default.join(HC_DIR, "MEMORY.md");
176
+ SOUL_FILE = path.default.join(HC_DIR, "SOUL.md");
177
+ PREFERENCE_PATTERNS = [
178
+ /i (?:prefer|like|love|hate|dislike|always|never)\s+(.{5,80})/i,
179
+ /(?:my favorite|my preferred)\s+(.{5,80})/i,
180
+ /(?:please )?always\s+((?:use|do|write|respond|answer|format|reply)\s+.{5,60})/i,
181
+ /don'?t (?:ever )?(.{5,60})/i,
182
+ /(?:i want you to always)\s+(.{5,80})/i
183
+ ];
184
+ IDENTITY_PATTERNS = [
185
+ /(?:my name is|i'?m called|call me)\s+([A-ZΑ-Ωa-zα-ω][a-zα-ω]{1,30})/i,
186
+ /i(?:'m| am) (?:a |an )?([A-Za-zΑ-Ωα-ω][\w\s]{3,40}?)(?:\.|,|$)/i,
187
+ /i work (?:at|for|as)\s+(.{5,60})/i,
188
+ /i(?:'m| am) (?:from|in|based in)\s+(.{3,40})/i,
189
+ /my (?:job|role|position|title) is\s+(.{5,60})/i
190
+ ];
191
+ GOAL_PATTERNS = [
192
+ /i(?:'m| am) (?:working on|building|creating|developing)\s+(.{10,100})/i,
193
+ /i want to\s+(.{10,100})/i,
194
+ /my goal is (?:to\s+)?(.{10,100})/i,
195
+ /i'?m trying to\s+(.{10,100})/i
196
+ ];
197
+ SENSITIVE_PATTERNS = [
198
+ /password/i,
199
+ /passwd/i,
200
+ /secret key/i,
201
+ /api.?key/i,
202
+ /credit.?card/i,
203
+ /\b\d{4}[\s-]\d{4}[\s-]\d{4}[\s-]\d{4}\b/,
204
+ /ssn|social security/i,
205
+ /\b\d{3}-\d{2}-\d{4}\b/
206
+ ];
207
+ AutoMemory = class {
208
+ turns = [];
209
+ turnsSinceLastExtract = 0;
210
+ extractEveryNTurns;
211
+ useAI;
212
+ aiOpts;
213
+ constructor(opts = {}) {
214
+ this.extractEveryNTurns = opts.extractEveryNTurns ?? 4;
215
+ this.useAI = opts.useAI ?? false;
216
+ this.aiOpts = opts.aiOpts;
217
+ }
218
+ addTurn(role, content) {
219
+ this.turns.push({
220
+ role,
221
+ content,
222
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
223
+ });
224
+ this.turnsSinceLastExtract++;
225
+ }
226
+ async maybeExtract() {
227
+ if (this.turnsSinceLastExtract < this.extractEveryNTurns) return 0;
228
+ this.turnsSinceLastExtract = 0;
229
+ return this.extract();
230
+ }
231
+ async extract() {
232
+ const facts = this.useAI && this.aiOpts ? await extractFactsWithAI(this.turns, this.aiOpts) : extractFactsLocally(this.turns);
233
+ const saved = await appendMemory(facts);
234
+ if (saved > 0) console.log(chalk.default.gray(` 🧠 Auto-saved ${saved} fact${saved === 1 ? "" : "s"} to MEMORY.md`));
235
+ return saved;
236
+ }
237
+ clearTurns() {
238
+ this.turns = [];
239
+ }
240
+ getTurns() {
241
+ return [...this.turns];
242
+ }
243
+ };
244
+ } });
245
+
246
+ //#endregion
247
+ Object.defineProperty(exports, 'AutoMemory', {
248
+ enumerable: true,
249
+ get: function () {
250
+ return AutoMemory;
251
+ }
252
+ });
253
+ Object.defineProperty(exports, 'appendMemory', {
254
+ enumerable: true,
255
+ get: function () {
256
+ return appendMemory;
257
+ }
258
+ });
259
+ Object.defineProperty(exports, 'clearMemory', {
260
+ enumerable: true,
261
+ get: function () {
262
+ return clearMemory;
263
+ }
264
+ });
265
+ Object.defineProperty(exports, 'extractFactsLocally', {
266
+ enumerable: true,
267
+ get: function () {
268
+ return extractFactsLocally;
269
+ }
270
+ });
271
+ Object.defineProperty(exports, 'extractFactsWithAI', {
272
+ enumerable: true,
273
+ get: function () {
274
+ return extractFactsWithAI;
275
+ }
276
+ });
277
+ Object.defineProperty(exports, 'init_memory_auto', {
278
+ enumerable: true,
279
+ get: function () {
280
+ return init_memory_auto;
281
+ }
282
+ });
283
+ Object.defineProperty(exports, 'readMemory', {
284
+ enumerable: true,
285
+ get: function () {
286
+ return readMemory;
287
+ }
288
+ });
289
+ Object.defineProperty(exports, 'saveMemoryDirect', {
290
+ enumerable: true,
291
+ get: function () {
292
+ return saveMemoryDirect;
293
+ }
294
+ });
295
+ Object.defineProperty(exports, 'searchMemory', {
296
+ enumerable: true,
297
+ get: function () {
298
+ return searchMemory;
299
+ }
300
+ });
301
+ Object.defineProperty(exports, 'showMemory', {
302
+ enumerable: true,
303
+ get: function () {
304
+ return showMemory;
305
+ }
306
+ });
@@ -0,0 +1,5 @@
1
+ const require_chunk = require('./chunk-jS-bbMI5.js');
2
+ const require_memory_auto = require('./memory-auto-CpQHZlEJ.js');
3
+
4
+ require_memory_auto.init_memory_auto();
5
+ exports.AutoMemory = require_memory_auto.AutoMemory;
@@ -0,0 +1,91 @@
1
+ const require_chunk = require('./chunk-jS-bbMI5.js');
2
+ const require_paths = require('./paths-AIyBxIzm.js');
3
+ const require_paths$1 = require('./paths-DPovhojT.js');
4
+ const fs_extra = require_chunk.__toESM(require("fs-extra"));
5
+ const path = require_chunk.__toESM(require("path"));
6
+
7
+ //#region src/services/memory-integration.ts
8
+ async function getConfig() {
9
+ try {
10
+ const cfg = await fs_extra.default.readJson(require_paths.getConfigPath());
11
+ return cfg.memoryIntegration ?? {};
12
+ } catch {
13
+ return {};
14
+ }
15
+ }
16
+ /** Sync MEMORY.md to vault (Obsidian / Raycast / Hazel). */
17
+ async function syncMemoryToVault(vaultDir) {
18
+ const target = path.default.join(vaultDir, "HyperClaw-MEMORY.md");
19
+ if (await fs_extra.default.pathExists(MEMORY_FILE)) {
20
+ await fs_extra.default.ensureDir(vaultDir);
21
+ await fs_extra.default.copy(MEMORY_FILE, target, { overwrite: true });
22
+ }
23
+ }
24
+ /** Write daily note with session summary and new facts. */
25
+ async function writeDailyNote(vaultDir, date, content) {
26
+ const filename = `${date}.md`;
27
+ const target = path.default.join(vaultDir, "HyperClaw", filename);
28
+ await fs_extra.default.ensureDir(path.default.dirname(target));
29
+ const lines = [
30
+ `# HyperClaw — ${date}`,
31
+ "",
32
+ `> Auto-generated daily note from HyperClaw interactions.`,
33
+ ""
34
+ ];
35
+ if (content.sessionId && (content.turnCount ?? 0) > 0) {
36
+ lines.push(`## Session ${content.sessionId}`);
37
+ lines.push(`- Turns: ${content.turnCount}`);
38
+ lines.push("");
39
+ }
40
+ if (content.newFacts?.length) {
41
+ lines.push("## New memories");
42
+ for (const f of content.newFacts) lines.push(`- ${f}`);
43
+ lines.push("");
44
+ }
45
+ const body = lines.join("\n");
46
+ if (await fs_extra.default.pathExists(target)) await fs_extra.default.appendFile(target, "\n---\n" + body);
47
+ else await fs_extra.default.writeFile(target, body);
48
+ }
49
+ /** Append new fact to daily note (for incremental updates). */
50
+ async function appendToDailyNote(vaultDir, date, fact) {
51
+ const filename = `${date}.md`;
52
+ const target = path.default.join(vaultDir, "HyperClaw", filename);
53
+ await fs_extra.default.ensureDir(path.default.dirname(target));
54
+ const line = `- ${(/* @__PURE__ */ new Date()).toISOString().slice(11, 19)} ${fact}\n`;
55
+ if (!await fs_extra.default.pathExists(target)) await fs_extra.default.writeFile(target, `# HyperClaw — ${date}\n\n`);
56
+ await fs_extra.default.appendFile(target, line);
57
+ }
58
+ /** Called after MEMORY.md append — sync to vault + optionally add to daily note. */
59
+ async function onMemoryAppended(facts) {
60
+ const cfg = await getConfig();
61
+ const vaultDir = cfg.vaultDir;
62
+ if (!vaultDir) return;
63
+ if (cfg.syncOnAppend !== false) await syncMemoryToVault(vaultDir);
64
+ if (cfg.dailyNotes && facts.length > 0) {
65
+ const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
66
+ for (const f of facts) await appendToDailyNote(vaultDir, today, f.fact);
67
+ }
68
+ }
69
+ /** Called on session end — sync + write session summary to daily note. */
70
+ async function onSessionEnd(payload) {
71
+ const cfg = await getConfig();
72
+ const vaultDir = cfg.vaultDir;
73
+ if (!vaultDir || !cfg.dailyNotes) return;
74
+ await syncMemoryToVault(vaultDir);
75
+ const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
76
+ await writeDailyNote(vaultDir, today, {
77
+ sessionId: payload.sessionId,
78
+ turnCount: payload.turnCount,
79
+ newFacts: payload.newFacts
80
+ });
81
+ }
82
+ var MEMORY_FILE;
83
+ var init_memory_integration = require_chunk.__esm({ "src/services/memory-integration.ts"() {
84
+ require_paths$1.init_paths();
85
+ MEMORY_FILE = path.default.join(require_paths.getHyperClawDir(), "MEMORY.md");
86
+ } });
87
+
88
+ //#endregion
89
+ init_memory_integration();
90
+ exports.onMemoryAppended = onMemoryAppended;
91
+ exports.onSessionEnd = onSessionEnd;
@@ -0,0 +1,81 @@
1
+ const require_chunk = require('./chunk-jS-bbMI5.js');
2
+ const https = require_chunk.__toESM(require("https"));
3
+
4
+ //#region src/services/moltbook.ts
5
+ /** List feed (public or for connected agents). */
6
+ async function getFeed(limit = 20) {
7
+ if (!MOLTBOOK_API) return [];
8
+ try {
9
+ const body = await fetchJson(`${MOLTBOOK_API}/api/feed?limit=${limit}`);
10
+ return Array.isArray(body.posts) ? body.posts : [];
11
+ } catch {
12
+ return [];
13
+ }
14
+ }
15
+ /** Publish a post as the configured agent. */
16
+ async function publishPost(content, opts) {
17
+ if (!MOLTBOOK_API) return null;
18
+ try {
19
+ const body = await postJson(`${MOLTBOOK_API}/api/posts`, { content }, opts?.agentToken);
20
+ return body.post || null;
21
+ } catch {
22
+ return null;
23
+ }
24
+ }
25
+ function fetchJson(url) {
26
+ return new Promise((resolve, reject) => {
27
+ const u = new URL(url);
28
+ const req = https.default.get(url, (res) => {
29
+ let data = "";
30
+ res.on("data", (c) => data += c);
31
+ res.on("end", () => {
32
+ try {
33
+ resolve(JSON.parse(data));
34
+ } catch {
35
+ reject(new Error("Invalid JSON"));
36
+ }
37
+ });
38
+ });
39
+ req.on("error", reject);
40
+ });
41
+ }
42
+ function postJson(url, payload, token) {
43
+ return new Promise((resolve, reject) => {
44
+ const u = new URL(url);
45
+ const body = JSON.stringify(payload);
46
+ const opts = {
47
+ hostname: u.hostname,
48
+ port: 443,
49
+ path: u.pathname,
50
+ method: "POST",
51
+ headers: {
52
+ "Content-Type": "application/json",
53
+ "Content-Length": Buffer.byteLength(body),
54
+ ...token ? { Authorization: `Bearer ${token}` } : {}
55
+ }
56
+ };
57
+ const req = https.default.request(opts, (res) => {
58
+ let data = "";
59
+ res.on("data", (c) => data += c);
60
+ res.on("end", () => {
61
+ try {
62
+ resolve(JSON.parse(data || "{}"));
63
+ } catch {
64
+ resolve({});
65
+ }
66
+ });
67
+ });
68
+ req.on("error", reject);
69
+ req.write(body);
70
+ req.end();
71
+ });
72
+ }
73
+ var MOLTBOOK_API;
74
+ var init_moltbook = require_chunk.__esm({ "src/services/moltbook.ts"() {
75
+ MOLTBOOK_API = process.env.MOLTBOOK_API_URL || "";
76
+ } });
77
+
78
+ //#endregion
79
+ init_moltbook();
80
+ exports.getFeed = getFeed;
81
+ exports.publishPost = publishPost;
@@ -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;