hyperclaw 4.0.1 → 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 +7 -4
- 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-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 +2 -2
- 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-D5Z98EVq.js +95 -0
- package/dist/delivery-DCOXhXEO.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-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-Bd_wsYdi.js +4086 -0
- package/dist/onboard-CAN7x3me.js +3026 -0
- package/dist/onboard-DnegOHMh.js +4 -4
- 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 +289 -1031
- 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 +2 -2
- package/dist/server-DU9POoWc.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-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,6 @@
|
|
|
1
|
+
const require_chunk = require('./chunk-jS-bbMI5.js');
|
|
2
|
+
const require_inference = require('./inference-CTWJeX9Q.js');
|
|
3
|
+
|
|
4
|
+
require_inference.init_inference();
|
|
5
|
+
exports.InferenceEngine = require_inference.InferenceEngine;
|
|
6
|
+
exports.getBuiltinTools = require_inference.getBuiltinTools;
|
|
@@ -0,0 +1,131 @@
|
|
|
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
|
+
|
|
6
|
+
//#region src/services/knowledge-graph.ts
|
|
7
|
+
async function load() {
|
|
8
|
+
try {
|
|
9
|
+
const data = await fs_extra.default.readJson(KG_FILE);
|
|
10
|
+
return {
|
|
11
|
+
...DEFAULT_GRAPH,
|
|
12
|
+
...data
|
|
13
|
+
};
|
|
14
|
+
} catch {
|
|
15
|
+
return { ...DEFAULT_GRAPH };
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
async function save(graph) {
|
|
19
|
+
await fs_extra.default.ensureDir(path.default.dirname(KG_FILE));
|
|
20
|
+
await fs_extra.default.writeJson(KG_FILE, graph, { spaces: 2 });
|
|
21
|
+
}
|
|
22
|
+
function slug(label, type) {
|
|
23
|
+
const base = label.toLowerCase().replace(/[^a-z0-9]+/g, "-").slice(0, 40);
|
|
24
|
+
return `${type}_${base}_${Date.now().toString(36)}`;
|
|
25
|
+
}
|
|
26
|
+
/** Add entity. */
|
|
27
|
+
async function addEntity(type, label, props = {}) {
|
|
28
|
+
const graph = await load();
|
|
29
|
+
const id = slug(label, type);
|
|
30
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
31
|
+
const entity = {
|
|
32
|
+
id,
|
|
33
|
+
type,
|
|
34
|
+
label,
|
|
35
|
+
props,
|
|
36
|
+
createdAt: now,
|
|
37
|
+
updatedAt: now
|
|
38
|
+
};
|
|
39
|
+
const idx = graph.entities.findIndex((e) => e.id === id);
|
|
40
|
+
if (idx >= 0) graph.entities[idx] = {
|
|
41
|
+
...entity,
|
|
42
|
+
createdAt: graph.entities[idx].createdAt
|
|
43
|
+
};
|
|
44
|
+
else graph.entities.push(entity);
|
|
45
|
+
await save(graph);
|
|
46
|
+
return id;
|
|
47
|
+
}
|
|
48
|
+
/** Add relation. */
|
|
49
|
+
async function addRelation(fromId, toId, type, props) {
|
|
50
|
+
const graph = await load();
|
|
51
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
52
|
+
const rel = {
|
|
53
|
+
from: fromId,
|
|
54
|
+
to: toId,
|
|
55
|
+
type,
|
|
56
|
+
props,
|
|
57
|
+
createdAt: now
|
|
58
|
+
};
|
|
59
|
+
const exists = graph.relations.some((r) => r.from === fromId && r.to === toId && r.type === type);
|
|
60
|
+
if (!exists) graph.relations.push(rel);
|
|
61
|
+
await save(graph);
|
|
62
|
+
}
|
|
63
|
+
/** Add fact (convenience). */
|
|
64
|
+
async function addFact(fact, tags) {
|
|
65
|
+
return addEntity("fact", fact.slice(0, 200), {
|
|
66
|
+
fullText: fact,
|
|
67
|
+
tags: tags?.join(",") ?? ""
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
/** Add preference. */
|
|
71
|
+
async function addPreference(topic, value) {
|
|
72
|
+
const topicId = await addEntity("topic", topic);
|
|
73
|
+
const prefId = await addEntity("preference", `${topic}: ${value}`, {
|
|
74
|
+
topic,
|
|
75
|
+
value
|
|
76
|
+
});
|
|
77
|
+
await addRelation(prefId, topicId, "belongs_to");
|
|
78
|
+
return prefId;
|
|
79
|
+
}
|
|
80
|
+
/** Add project. */
|
|
81
|
+
async function addProject(name, description) {
|
|
82
|
+
return addEntity("project", name, { description: description ?? "" });
|
|
83
|
+
}
|
|
84
|
+
/** Query memory for context (semantic-ish: type + label/props match). */
|
|
85
|
+
async function queryMemory(query) {
|
|
86
|
+
const graph = await load();
|
|
87
|
+
const { types = [], tags = [], limit = 20 } = query;
|
|
88
|
+
let entities = graph.entities;
|
|
89
|
+
if (types.length > 0) entities = entities.filter((e) => types.includes(e.type));
|
|
90
|
+
if (tags.length > 0) entities = entities.filter((e) => {
|
|
91
|
+
const t = String(e.props.tags || "").split(",");
|
|
92
|
+
return tags.some((tag) => t.some((x) => x.toLowerCase().includes(tag.toLowerCase())));
|
|
93
|
+
});
|
|
94
|
+
entities = entities.sort((a, b) => new Date(b.updatedAt || b.createdAt).getTime() - new Date(a.updatedAt || a.createdAt).getTime()).slice(0, limit);
|
|
95
|
+
if (entities.length === 0) return "";
|
|
96
|
+
const lines = entities.map((e) => {
|
|
97
|
+
const d = e.updatedAt || e.createdAt;
|
|
98
|
+
return `- [${e.type}] ${e.label} (${d.slice(0, 10)})`;
|
|
99
|
+
});
|
|
100
|
+
return lines.join("\n");
|
|
101
|
+
}
|
|
102
|
+
/** Get full context string for injection into prompts. */
|
|
103
|
+
async function getContextSummary(limit = 30) {
|
|
104
|
+
const facts = await queryMemory({
|
|
105
|
+
types: [
|
|
106
|
+
"fact",
|
|
107
|
+
"preference",
|
|
108
|
+
"project"
|
|
109
|
+
],
|
|
110
|
+
limit
|
|
111
|
+
});
|
|
112
|
+
if (!facts) return "";
|
|
113
|
+
return `## Knowledge Graph Context\n${facts}`;
|
|
114
|
+
}
|
|
115
|
+
var KG_FILE, DEFAULT_GRAPH;
|
|
116
|
+
var init_knowledge_graph = require_chunk.__esm({ "src/services/knowledge-graph.ts"() {
|
|
117
|
+
KG_FILE = path.default.join(os.default.homedir(), ".hyperclaw", "knowledge-graph.json");
|
|
118
|
+
DEFAULT_GRAPH = {
|
|
119
|
+
entities: [],
|
|
120
|
+
relations: [],
|
|
121
|
+
version: 1
|
|
122
|
+
};
|
|
123
|
+
} });
|
|
124
|
+
|
|
125
|
+
//#endregion
|
|
126
|
+
init_knowledge_graph();
|
|
127
|
+
exports.addFact = addFact;
|
|
128
|
+
exports.addPreference = addPreference;
|
|
129
|
+
exports.addProject = addProject;
|
|
130
|
+
exports.getContextSummary = getContextSummary;
|
|
131
|
+
exports.queryMemory = queryMemory;
|
|
@@ -0,0 +1,400 @@
|
|
|
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 src/hooks/loader.ts
|
|
8
|
+
const BUILTIN_HOOKS = [
|
|
9
|
+
{
|
|
10
|
+
id: "session-memory",
|
|
11
|
+
name: "Session Memory",
|
|
12
|
+
description: "Writes a summary of each session to MEMORY.md on close.",
|
|
13
|
+
trigger: "session:end",
|
|
14
|
+
eligible: true,
|
|
15
|
+
enabled: true,
|
|
16
|
+
builtin: true,
|
|
17
|
+
tags: ["memory", "sessions"],
|
|
18
|
+
version: "1.0.0"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
id: "command-logger",
|
|
22
|
+
name: "Command Logger",
|
|
23
|
+
description: "Logs every AI command execution to the daily log file.",
|
|
24
|
+
trigger: "message:sent",
|
|
25
|
+
eligible: true,
|
|
26
|
+
enabled: false,
|
|
27
|
+
builtin: true,
|
|
28
|
+
tags: ["logging", "debug"],
|
|
29
|
+
version: "1.0.0"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
id: "gateway-health",
|
|
33
|
+
name: "Gateway Health Monitor",
|
|
34
|
+
description: "Pings the gateway every 5 minutes and logs latency.",
|
|
35
|
+
trigger: "cron",
|
|
36
|
+
eligible: true,
|
|
37
|
+
enabled: true,
|
|
38
|
+
builtin: true,
|
|
39
|
+
tags: ["health", "monitoring"],
|
|
40
|
+
version: "1.1.0"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
id: "auto-backup",
|
|
44
|
+
name: "Auto Backup",
|
|
45
|
+
description: "Backs up AGENTS.md and config to ~/.hyperclaw/backups/ daily.",
|
|
46
|
+
trigger: "cron",
|
|
47
|
+
eligible: true,
|
|
48
|
+
enabled: false,
|
|
49
|
+
builtin: true,
|
|
50
|
+
tags: ["backup", "config"],
|
|
51
|
+
version: "1.0.0"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
id: "dm-guard",
|
|
55
|
+
name: "DM Guard",
|
|
56
|
+
description: "Enforces DM policy and logs policy violations.",
|
|
57
|
+
trigger: "message:received",
|
|
58
|
+
eligible: true,
|
|
59
|
+
enabled: true,
|
|
60
|
+
builtin: true,
|
|
61
|
+
tags: ["security", "dm-policy"],
|
|
62
|
+
version: "2.0.0"
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
id: "voice-wake",
|
|
66
|
+
name: "Voice Wake Detector",
|
|
67
|
+
description: "Listens for wake word and starts voice session (macOS/iOS only).",
|
|
68
|
+
trigger: "gateway:start",
|
|
69
|
+
eligible: process.platform === "darwin",
|
|
70
|
+
enabled: false,
|
|
71
|
+
builtin: true,
|
|
72
|
+
tags: ["voice", "macos"],
|
|
73
|
+
version: "1.0.0"
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
id: "morning-briefing",
|
|
77
|
+
name: "Morning Briefing (Heartbeat)",
|
|
78
|
+
description: "Proactive daily briefing: agent generates summary from MEMORY, reminders, knowledge graph. Writes to HEARTBEAT.md.",
|
|
79
|
+
trigger: "cron",
|
|
80
|
+
eligible: true,
|
|
81
|
+
enabled: false,
|
|
82
|
+
builtin: true,
|
|
83
|
+
tags: [
|
|
84
|
+
"heartbeat",
|
|
85
|
+
"briefing",
|
|
86
|
+
"automation"
|
|
87
|
+
],
|
|
88
|
+
version: "1.0.0"
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
id: "website-watch",
|
|
92
|
+
name: "Website Change Monitor",
|
|
93
|
+
description: "Every 15 min, checks watched URLs for changes. Use watch_website_add tool to add URLs.",
|
|
94
|
+
trigger: "cron",
|
|
95
|
+
eligible: true,
|
|
96
|
+
enabled: true,
|
|
97
|
+
builtin: true,
|
|
98
|
+
tags: ["automation", "monitoring"],
|
|
99
|
+
version: "1.0.0"
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
id: "voice-note-transcription",
|
|
103
|
+
name: "Voice Note Transcription",
|
|
104
|
+
description: "Transcribes incoming voice messages via Whisper (OPENAI_API_KEY). Used by channels when audioPath is set.",
|
|
105
|
+
trigger: "message:received",
|
|
106
|
+
eligible: true,
|
|
107
|
+
enabled: true,
|
|
108
|
+
builtin: true,
|
|
109
|
+
tags: [
|
|
110
|
+
"voice",
|
|
111
|
+
"transcription",
|
|
112
|
+
"messaging"
|
|
113
|
+
],
|
|
114
|
+
version: "1.0.0"
|
|
115
|
+
}
|
|
116
|
+
];
|
|
117
|
+
var HookLoader = class {
|
|
118
|
+
stateFile;
|
|
119
|
+
state = {};
|
|
120
|
+
constructor() {
|
|
121
|
+
this.stateFile = path.default.join(os.default.homedir(), ".hyperclaw", "hooks-state.json");
|
|
122
|
+
this.loadState();
|
|
123
|
+
}
|
|
124
|
+
loadState() {
|
|
125
|
+
try {
|
|
126
|
+
this.state = fs_extra.default.readJsonSync(this.stateFile);
|
|
127
|
+
} catch {
|
|
128
|
+
this.state = {};
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
saveState() {
|
|
132
|
+
fs_extra.default.ensureDirSync(path.default.dirname(this.stateFile));
|
|
133
|
+
fs_extra.default.writeJsonSync(this.stateFile, this.state, { spaces: 2 });
|
|
134
|
+
}
|
|
135
|
+
isEnabled(hook) {
|
|
136
|
+
if (this.state[hook.id] !== void 0) return this.state[hook.id].enabled;
|
|
137
|
+
return hook.enabled;
|
|
138
|
+
}
|
|
139
|
+
getHooks(eligibleOnly = false) {
|
|
140
|
+
const hooks = eligibleOnly ? BUILTIN_HOOKS.filter((h) => h.eligible) : BUILTIN_HOOKS;
|
|
141
|
+
return hooks.map((h) => ({
|
|
142
|
+
...h,
|
|
143
|
+
enabled: this.isEnabled(h),
|
|
144
|
+
eligible: h.eligible
|
|
145
|
+
}));
|
|
146
|
+
}
|
|
147
|
+
list(eligibleOnly = false) {
|
|
148
|
+
const hooks = this.getHooks(eligibleOnly);
|
|
149
|
+
console.log(chalk.default.bold.cyan("\n ⚡ HYPERCLAW HOOKS\n"));
|
|
150
|
+
for (const hook of hooks) {
|
|
151
|
+
const dot = hook.enabled ? chalk.default.green("●") : chalk.default.gray("○");
|
|
152
|
+
const eligBadge = hook.eligible ? "" : chalk.default.red(" [ineligible]");
|
|
153
|
+
const builtinBadge = hook.builtin ? chalk.default.gray(" [builtin]") : "";
|
|
154
|
+
console.log(` ${dot} ${chalk.default.white(hook.id)}${eligBadge}${builtinBadge}`);
|
|
155
|
+
console.log(` ${chalk.default.gray(hook.description)}`);
|
|
156
|
+
console.log(` ${chalk.default.gray(`trigger: ${hook.trigger} v${hook.version} tags: ${hook.tags.join(", ")}`)}`);
|
|
157
|
+
console.log();
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
info(id) {
|
|
161
|
+
const hook = BUILTIN_HOOKS.find((h) => h.id === id);
|
|
162
|
+
if (!hook) {
|
|
163
|
+
console.log(chalk.default.red(` ✖ Hook not found: ${id}`));
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
const enabled = this.isEnabled(hook);
|
|
167
|
+
console.log(chalk.default.bold.cyan(`\n Hook: ${hook.name}\n`));
|
|
168
|
+
console.log(` ID: ${hook.id}`);
|
|
169
|
+
console.log(` Status: ${enabled ? chalk.default.green("enabled") : chalk.default.gray("disabled")}`);
|
|
170
|
+
console.log(` Eligible: ${hook.eligible ? chalk.default.green("yes") : chalk.default.red("no — OS not supported")}`);
|
|
171
|
+
console.log(` Trigger: ${hook.trigger}`);
|
|
172
|
+
console.log(` Description: ${hook.description}`);
|
|
173
|
+
console.log(` Tags: ${hook.tags.join(", ")}`);
|
|
174
|
+
console.log(` Version: ${hook.version}`);
|
|
175
|
+
console.log();
|
|
176
|
+
}
|
|
177
|
+
enable(id) {
|
|
178
|
+
const hook = BUILTIN_HOOKS.find((h) => h.id === id);
|
|
179
|
+
if (!hook) {
|
|
180
|
+
console.log(chalk.default.red(` ✖ Hook not found: ${id}`));
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
if (!hook.eligible) {
|
|
184
|
+
console.log(chalk.default.red(` ✖ Hook not eligible on this OS: ${id}`));
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
this.state[id] = { enabled: true };
|
|
188
|
+
this.saveState();
|
|
189
|
+
console.log(chalk.default.green(` ✔ Hook enabled: ${id}`));
|
|
190
|
+
}
|
|
191
|
+
disable(id) {
|
|
192
|
+
const hook = BUILTIN_HOOKS.find((h) => h.id === id);
|
|
193
|
+
if (!hook) {
|
|
194
|
+
console.log(chalk.default.red(` ✖ Hook not found: ${id}`));
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
this.state[id] = { enabled: false };
|
|
198
|
+
this.saveState();
|
|
199
|
+
console.log(chalk.default.green(` ✔ Hook disabled: ${id}`));
|
|
200
|
+
}
|
|
201
|
+
async install(pack) {
|
|
202
|
+
const s = require("ora")(`Installing hook pack: ${pack}...`).start();
|
|
203
|
+
await new Promise((r) => setTimeout(r, 1500));
|
|
204
|
+
s.succeed(`Hook pack installed: ${pack}`);
|
|
205
|
+
console.log(chalk.default.gray(` Run: hyperclaw hooks list to see new hooks`));
|
|
206
|
+
}
|
|
207
|
+
/** Execute enabled hooks for a trigger. Fire-and-forget. */
|
|
208
|
+
async execute(trigger, payload) {
|
|
209
|
+
const toRun = BUILTIN_HOOKS.filter((h) => h.trigger === trigger && h.eligible && this.isEnabled(h));
|
|
210
|
+
for (const hook of toRun) this.runHandler(hook, payload).catch((err) => console.error(`[hooks] ${hook.id} error:`, err?.message || err));
|
|
211
|
+
}
|
|
212
|
+
/** Execute a single cron hook by ID. Used by CronRunner. */
|
|
213
|
+
async executeCronHook(hookId) {
|
|
214
|
+
const hook = BUILTIN_HOOKS.find((h) => h.id === hookId && h.trigger === "cron" && h.eligible && this.isEnabled(h));
|
|
215
|
+
if (hook) await this.runHandler(hook, {}).catch((err) => console.error(`[hooks] ${hook.id} error:`, err?.message || err));
|
|
216
|
+
}
|
|
217
|
+
/** Start cron schedules: gateway-health (5 min), auto-backup (3am), website-watch (15 min), morning-briefing (8am), + user cron-tasks. */
|
|
218
|
+
startCronScheduler() {
|
|
219
|
+
const cron = require("node-cron");
|
|
220
|
+
const stops = [];
|
|
221
|
+
const t1 = cron.schedule("*/5 * * * *", () => {
|
|
222
|
+
this.executeCronHook("gateway-health").catch(() => {});
|
|
223
|
+
});
|
|
224
|
+
const t2 = cron.schedule("0 3 * * *", () => {
|
|
225
|
+
this.executeCronHook("auto-backup").catch(() => {});
|
|
226
|
+
});
|
|
227
|
+
const t3 = cron.schedule("*/15 * * * *", () => {
|
|
228
|
+
this.executeCronHook("website-watch").catch(() => {});
|
|
229
|
+
});
|
|
230
|
+
const t4 = cron.schedule("0 8 * * *", () => {
|
|
231
|
+
this.executeCronHook("morning-briefing").catch(() => {});
|
|
232
|
+
});
|
|
233
|
+
stops.push(() => {
|
|
234
|
+
t1.stop();
|
|
235
|
+
t2.stop();
|
|
236
|
+
t3.stop();
|
|
237
|
+
t4.stop();
|
|
238
|
+
});
|
|
239
|
+
(async () => {
|
|
240
|
+
try {
|
|
241
|
+
const { loadCronTasks, runCronTask } = await Promise.resolve().then(() => require("./cron-tasks-BvDFNyiE.js"));
|
|
242
|
+
const tasks = await loadCronTasks();
|
|
243
|
+
let port = 18789;
|
|
244
|
+
try {
|
|
245
|
+
const cfg = await fs_extra.default.readJson(path.default.join(os.default.homedir(), ".hyperclaw", "hyperclaw.json"));
|
|
246
|
+
port = cfg?.gateway?.port ?? 18789;
|
|
247
|
+
} catch {}
|
|
248
|
+
for (const task of tasks) {
|
|
249
|
+
if (!task.enabled) continue;
|
|
250
|
+
try {
|
|
251
|
+
const t = cron.schedule(task.schedule, () => runCronTask(task, port).catch(() => {}));
|
|
252
|
+
stops.push(() => t.stop());
|
|
253
|
+
} catch {}
|
|
254
|
+
}
|
|
255
|
+
} catch {}
|
|
256
|
+
})();
|
|
257
|
+
return () => {
|
|
258
|
+
stops.forEach((s) => s());
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
async runHandler(hook, payload) {
|
|
262
|
+
const handlers = {
|
|
263
|
+
"session-memory": async () => {
|
|
264
|
+
const sessionId = payload?.sessionId;
|
|
265
|
+
const turnCount = payload?.turnCount ?? 0;
|
|
266
|
+
const newFacts = payload?.newFacts;
|
|
267
|
+
if (turnCount > 0 && sessionId) {
|
|
268
|
+
const entry = `\n- ${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}: Session ${sessionId} closed after ${turnCount} turns\n`;
|
|
269
|
+
await fs_extra.default.appendFile(path.default.join(os.default.homedir(), ".hyperclaw", "MEMORY.md"), entry);
|
|
270
|
+
}
|
|
271
|
+
try {
|
|
272
|
+
const { onSessionEnd } = await Promise.resolve().then(() => require("./memory-integration-DZExqWr4.js"));
|
|
273
|
+
await onSessionEnd({
|
|
274
|
+
sessionId,
|
|
275
|
+
turnCount,
|
|
276
|
+
newFacts
|
|
277
|
+
});
|
|
278
|
+
} catch {}
|
|
279
|
+
},
|
|
280
|
+
"command-logger": async () => {
|
|
281
|
+
const logDir = path.default.join(os.default.homedir(), ".hyperclaw", "logs");
|
|
282
|
+
const logFile = path.default.join(logDir, `commands-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}.log`);
|
|
283
|
+
await fs_extra.default.ensureDir(logDir);
|
|
284
|
+
const msg = String(payload?.message ?? "").slice(0, 100);
|
|
285
|
+
const resp = String(payload?.response ?? "").slice(0, 200);
|
|
286
|
+
const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] msg=${msg} | resp=${resp}\n`;
|
|
287
|
+
await fs_extra.default.appendFile(logFile, line);
|
|
288
|
+
},
|
|
289
|
+
"dm-guard": async () => {
|
|
290
|
+
if (payload?.channel) {
|
|
291
|
+
const auditDir = path.default.join(os.default.homedir(), ".hyperclaw", "logs");
|
|
292
|
+
await fs_extra.default.ensureDir(auditDir);
|
|
293
|
+
const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] message:received channel=${payload.channel}\n`;
|
|
294
|
+
await fs_extra.default.appendFile(path.default.join(auditDir, "dm-guard.log"), line);
|
|
295
|
+
}
|
|
296
|
+
},
|
|
297
|
+
"gateway-health": async () => {
|
|
298
|
+
const hcDir = path.default.join(os.default.homedir(), ".hyperclaw");
|
|
299
|
+
let port = 18789;
|
|
300
|
+
try {
|
|
301
|
+
const cfg = await fs_extra.default.readJson(path.default.join(hcDir, "hyperclaw.json"));
|
|
302
|
+
if (cfg?.gateway?.port) port = cfg.gateway.port;
|
|
303
|
+
} catch {}
|
|
304
|
+
const logDir = path.default.join(hcDir, "logs");
|
|
305
|
+
const logFile = path.default.join(logDir, "gateway-health.log");
|
|
306
|
+
const start = Date.now();
|
|
307
|
+
try {
|
|
308
|
+
const http = await import("http");
|
|
309
|
+
await new Promise((resolve, reject) => {
|
|
310
|
+
const req = http.get(`http://127.0.0.1:${port}/api/status`, (res) => {
|
|
311
|
+
let data = "";
|
|
312
|
+
res.on("data", (c) => data += c);
|
|
313
|
+
res.on("end", () => {
|
|
314
|
+
resolve();
|
|
315
|
+
});
|
|
316
|
+
});
|
|
317
|
+
req.on("error", reject);
|
|
318
|
+
req.setTimeout(5e3, () => {
|
|
319
|
+
req.destroy();
|
|
320
|
+
reject(new Error("Timeout"));
|
|
321
|
+
});
|
|
322
|
+
});
|
|
323
|
+
const latency = Date.now() - start;
|
|
324
|
+
await fs_extra.default.ensureDir(logDir);
|
|
325
|
+
await fs_extra.default.appendFile(logFile, `[${(/* @__PURE__ */ new Date()).toISOString()}] OK latency=${latency}ms\n`);
|
|
326
|
+
} catch (e) {
|
|
327
|
+
await fs_extra.default.ensureDir(logDir);
|
|
328
|
+
await fs_extra.default.appendFile(logFile, `[${(/* @__PURE__ */ new Date()).toISOString()}] FAIL ${e.message}\n`);
|
|
329
|
+
}
|
|
330
|
+
},
|
|
331
|
+
"auto-backup": async () => {
|
|
332
|
+
const hcDir = path.default.join(os.default.homedir(), ".hyperclaw");
|
|
333
|
+
const backupDir = path.default.join(hcDir, "backups");
|
|
334
|
+
await fs_extra.default.ensureDir(backupDir);
|
|
335
|
+
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
336
|
+
for (const f of [
|
|
337
|
+
"hyperclaw.json",
|
|
338
|
+
"AGENTS.md",
|
|
339
|
+
"MEMORY.md",
|
|
340
|
+
"SOUL.md"
|
|
341
|
+
]) {
|
|
342
|
+
const src = path.default.join(hcDir, f);
|
|
343
|
+
if (await fs_extra.default.pathExists(src)) await fs_extra.default.copy(src, path.default.join(backupDir, `${f}.${ts}.bak`));
|
|
344
|
+
}
|
|
345
|
+
},
|
|
346
|
+
"voice-wake": async () => {},
|
|
347
|
+
"morning-briefing": async () => {
|
|
348
|
+
try {
|
|
349
|
+
const { runMorningBriefing, persistBriefing } = await Promise.resolve().then(() => require("./heartbeat-engine-CRqfPcFM.js"));
|
|
350
|
+
const text = await runMorningBriefing();
|
|
351
|
+
await persistBriefing(text);
|
|
352
|
+
} catch (e) {
|
|
353
|
+
const logDir = path.default.join(os.default.homedir(), ".hyperclaw", "logs");
|
|
354
|
+
await fs_extra.default.ensureDir(logDir);
|
|
355
|
+
await fs_extra.default.appendFile(path.default.join(logDir, "heartbeat-errors.log"), `[${(/* @__PURE__ */ new Date()).toISOString()}] ${e.message}\n`);
|
|
356
|
+
}
|
|
357
|
+
},
|
|
358
|
+
"website-watch": async () => {
|
|
359
|
+
const path$2 = await import("path");
|
|
360
|
+
const os$2 = await import("os");
|
|
361
|
+
const fs$1 = await import("fs-extra");
|
|
362
|
+
const watchFile = path$2.join(os$2.homedir(), ".hyperclaw", "website-watches.json");
|
|
363
|
+
if (!await fs$1.pathExists(watchFile)) return;
|
|
364
|
+
const watches = await fs$1.readJson(watchFile).catch(() => ({}));
|
|
365
|
+
const crypto = await import("crypto");
|
|
366
|
+
const https = await import("https");
|
|
367
|
+
const http = await import("http");
|
|
368
|
+
const fetch = (u) => new Promise((res, rej) => {
|
|
369
|
+
const c = u.startsWith("https") ? https : http;
|
|
370
|
+
const req = c.get(u, { timeout: 1e4 }, (r) => {
|
|
371
|
+
let d = "";
|
|
372
|
+
r.on("data", (x) => d += x);
|
|
373
|
+
r.on("end", () => res(d));
|
|
374
|
+
});
|
|
375
|
+
req.on("error", rej);
|
|
376
|
+
});
|
|
377
|
+
const hash = (s) => crypto.createHash("sha256").update(s.replace(/\s+/g, " ").slice(0, 5e4)).digest("hex").slice(0, 16);
|
|
378
|
+
for (const url of Object.keys(watches)) try {
|
|
379
|
+
const content = await fetch(url);
|
|
380
|
+
const h = hash(content);
|
|
381
|
+
if (h !== watches[url].lastHash) {
|
|
382
|
+
watches[url].lastHash = h;
|
|
383
|
+
watches[url].lastCheck = (/* @__PURE__ */ new Date()).toISOString();
|
|
384
|
+
}
|
|
385
|
+
} catch {}
|
|
386
|
+
await fs$1.writeJson(watchFile, watches, { spaces: 2 });
|
|
387
|
+
}
|
|
388
|
+
};
|
|
389
|
+
const fn = handlers[hook.id];
|
|
390
|
+
if (fn) await fn();
|
|
391
|
+
}
|
|
392
|
+
};
|
|
393
|
+
|
|
394
|
+
//#endregion
|
|
395
|
+
Object.defineProperty(exports, 'HookLoader', {
|
|
396
|
+
enumerable: true,
|
|
397
|
+
get: function () {
|
|
398
|
+
return HookLoader;
|
|
399
|
+
}
|
|
400
|
+
});
|
|
@@ -0,0 +1,83 @@
|
|
|
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 src/logging/logger.ts
|
|
8
|
+
const LEVEL_COLOR = {
|
|
9
|
+
debug: chalk.default.gray,
|
|
10
|
+
info: chalk.default.cyan,
|
|
11
|
+
warn: chalk.default.yellow,
|
|
12
|
+
error: chalk.default.red,
|
|
13
|
+
silent: chalk.default.gray
|
|
14
|
+
};
|
|
15
|
+
const LOG_DIR = path.default.join(os.default.homedir(), ".hyperclaw", "logs");
|
|
16
|
+
const LOG_FILE = path.default.join(LOG_DIR, "hyperclaw.log");
|
|
17
|
+
const MAX_LOG_BYTES = 5 * 1024 * 1024;
|
|
18
|
+
function formatConsole(entry) {
|
|
19
|
+
const ts = chalk.default.gray(entry.ts.slice(11, 23));
|
|
20
|
+
const level = LEVEL_COLOR[entry.level](entry.level.toUpperCase().padEnd(5));
|
|
21
|
+
const mod = chalk.default.blue(`[${entry.module}]`);
|
|
22
|
+
const data = entry.data ? chalk.default.gray(" " + JSON.stringify(entry.data)) : "";
|
|
23
|
+
return ` ${ts} ${level} ${mod} ${entry.message}${data}`;
|
|
24
|
+
}
|
|
25
|
+
async function tailLog(lines = 50) {
|
|
26
|
+
if (!await fs_extra.default.pathExists(LOG_FILE)) {
|
|
27
|
+
console.log(chalk.default.gray("\n No log file yet. Start the daemon first.\n"));
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const content = await fs_extra.default.readFile(LOG_FILE, "utf8");
|
|
31
|
+
const all = content.trim().split("\n").filter(Boolean);
|
|
32
|
+
const tail = all.slice(-lines);
|
|
33
|
+
console.log(chalk.default.bold.cyan(`\n 📋 LAST ${tail.length} LOG ENTRIES\n`));
|
|
34
|
+
for (const line of tail) try {
|
|
35
|
+
const entry = JSON.parse(line);
|
|
36
|
+
console.log(formatConsole(entry));
|
|
37
|
+
} catch {
|
|
38
|
+
console.log(chalk.default.gray(" " + line));
|
|
39
|
+
}
|
|
40
|
+
console.log();
|
|
41
|
+
}
|
|
42
|
+
async function streamLog() {
|
|
43
|
+
console.log(chalk.default.bold.cyan("\n 📡 STREAMING LOGS (Ctrl+C to stop)\n"));
|
|
44
|
+
await fs_extra.default.ensureDir(LOG_DIR);
|
|
45
|
+
await fs_extra.default.ensureFile(LOG_FILE);
|
|
46
|
+
const { createReadStream } = await import("fs");
|
|
47
|
+
const { Tail } = await import("tail").catch(() => ({ Tail: null }));
|
|
48
|
+
if (Tail) {
|
|
49
|
+
const tail = new Tail(LOG_FILE);
|
|
50
|
+
tail.on("line", (line) => {
|
|
51
|
+
try {
|
|
52
|
+
const entry = JSON.parse(line);
|
|
53
|
+
console.log(formatConsole(entry));
|
|
54
|
+
} catch {
|
|
55
|
+
console.log(chalk.default.gray(" " + line));
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
} else {
|
|
59
|
+
const { spawn } = await import("child_process");
|
|
60
|
+
const proc = spawn("tail", ["-f", LOG_FILE], { stdio: [
|
|
61
|
+
"ignore",
|
|
62
|
+
"pipe",
|
|
63
|
+
"ignore"
|
|
64
|
+
] });
|
|
65
|
+
proc.stdout?.on("data", (chunk) => {
|
|
66
|
+
const lines = chunk.toString().split("\n");
|
|
67
|
+
for (const line of lines) {
|
|
68
|
+
if (!line.trim()) continue;
|
|
69
|
+
try {
|
|
70
|
+
const entry = JSON.parse(line);
|
|
71
|
+
console.log(formatConsole(entry));
|
|
72
|
+
} catch {
|
|
73
|
+
console.log(chalk.default.gray(" " + line));
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
await new Promise(() => {});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
//#endregion
|
|
82
|
+
exports.streamLog = streamLog;
|
|
83
|
+
exports.tailLog = tailLog;
|