hyperclaw 4.0.2 → 5.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +246 -60
- package/dist/a2ui-protocol-CfBI44-Q.js +75 -0
- package/dist/agents-routing-ChHiZp36.js +327 -0
- package/dist/agents-routing-ChqZ6l2S.js +4 -0
- package/dist/api-keys-guide-BCcOl0Q7.js +149 -0
- package/dist/api-keys-guide-CGn5BSF7.js +149 -0
- package/dist/audit-BJohI_vC.js +441 -0
- package/dist/audit-BaIiyWFu.js +441 -0
- package/dist/bounty-tools-CY_i91DU.js +211 -0
- package/dist/bounty-tools-DWudyZie.js +211 -0
- package/dist/browser-tools-BsTeGMnX.js +5 -0
- package/dist/browser-tools-D8_rLe2p.js +179 -0
- package/dist/claw-tasks-CgTsiNE8.js +80 -0
- package/dist/claw-tasks-Cyzdbhz_.js +80 -0
- package/dist/connector-5N0-X_xs.js +194 -0
- package/dist/connector-B3v0qcXg.js +425 -0
- package/dist/connector-B8R3iBY1.js +280 -0
- package/dist/connector-BAM-08NN.js +189 -0
- package/dist/connector-BC8FIVu4.js +181 -0
- package/dist/connector-BDmwwaVc.js +213 -0
- package/dist/connector-BGjbBy69.js +225 -0
- package/dist/connector-BO2SRzfG.js +218 -0
- package/dist/connector-BfXky0L3.js +167 -0
- package/dist/connector-BiiSJpx3.js +192 -0
- package/dist/connector-BnDmIhIu.js +85 -0
- package/dist/connector-C1HSoUyk.js +189 -0
- package/dist/connector-CKQHZOXg.js +568 -0
- package/dist/connector-CRl-iidy.js +239 -0
- package/dist/connector-Ci9glMD-.js +340 -0
- package/dist/connector-CjtZIEDj.js +181 -0
- package/dist/connector-Ck6JtOsX.js +531 -0
- package/dist/connector-D8Kelee0.js +286 -0
- package/dist/connector-DAnRJ0oP.js +162 -0
- package/dist/connector-DXTp5PE8.js +508 -0
- package/dist/connector-Dih6dUPP.js +173 -0
- package/dist/connector-DqTH_tPX.js +182 -0
- package/dist/connector-DrnEiiyP.js +419 -0
- package/dist/connector-DtR5GGTX.js +167 -0
- package/dist/connector-Tky_qS_K.js +350 -0
- package/dist/connector-ZSc3oTTy.js +305 -0
- package/dist/connector-sW5yhU1m.js +498 -0
- package/dist/connector-u3ICd3Ic.js +552 -0
- package/dist/cost-tracker-Ca1UPZ33.js +103 -0
- package/dist/cost-tracker-DD9wtWsr.js +103 -0
- package/dist/credentials-store-C6ir0Dae.js +4 -0
- package/dist/credentials-store-CA8UtK0T.js +77 -0
- package/dist/credentials-store-Cm7DH-kh.js +4 -0
- package/dist/credentials-store-H13LqOwJ.js +77 -0
- package/dist/cron-tasks-Bli7Kzd2.js +82 -0
- package/dist/cron-tasks-_pqQCmxc.js +82 -0
- package/dist/daemon-7ViroziB.js +5 -0
- package/dist/daemon-BfyKmZhr.js +318 -0
- package/dist/daemon-Bg4GtCmc.js +318 -0
- package/dist/daemon-DhmwY8k4.js +5 -0
- package/dist/delivery-BmIYy9VQ.js +4 -0
- package/dist/delivery-DVHmv1IR.js +4 -0
- package/dist/delivery-DpMX0Yyc.js +95 -0
- package/dist/delivery-pWUPBp1F.js +95 -0
- package/dist/destructive-gate-D6vWOdEl.js +101 -0
- package/dist/destructive-gate-DZt71UZR.js +101 -0
- package/dist/developer-keys-CPWT7Q6S.js +8 -0
- package/dist/developer-keys-DrrcUqFa.js +127 -0
- package/dist/doctor-BvCe8BBk.js +230 -0
- package/dist/doctor-CxyPLYsJ.js +6 -0
- package/dist/engine-B0kLfRL0.js +256 -0
- package/dist/engine-BJUpRUOv.js +7 -0
- package/dist/engine-CEDSqXfw.js +256 -0
- package/dist/engine-Da4JMNpI.js +7 -0
- package/dist/env-resolve-17ekEU6p.js +10 -0
- package/dist/env-resolve-CiXbWYwe.js +10 -0
- package/dist/env-resolve-CmGWhWXJ.js +115 -0
- package/dist/env-resolve-Z2XF6leB.js +115 -0
- package/dist/extraction-tools-HOZstZ0y.js +91 -0
- package/dist/extraction-tools-m4lmAv7l.js +5 -0
- package/dist/form_data-Cz040rio.js +8657 -0
- package/dist/gmail-watch-setup-Du7DVV7S.js +40 -0
- package/dist/health-B-asI__D.js +6 -0
- package/dist/health-Ds2YlpTB.js +152 -0
- package/dist/heartbeat-engine-BYT5ayQH.js +83 -0
- package/dist/heartbeat-engine-Ut6pXBD6.js +83 -0
- package/dist/hub-9LaKnLjY.js +6 -0
- package/dist/hub-CfwUz9YW.js +515 -0
- package/dist/hub-D0XwdjM-.js +515 -0
- package/dist/hub-LiD5Iztb.js +6 -0
- package/dist/hyperclawbot-CBiDSKsa.js +505 -0
- package/dist/hyperclawbot-zvczQgKx.js +505 -0
- package/dist/inference-0mlFQqIm.js +922 -0
- package/dist/inference-BKVkBREb.js +6 -0
- package/dist/inference-DCXH4Q3x.js +922 -0
- package/dist/inference-SzqFe_nk.js +6 -0
- package/dist/knowledge-graph-DE5lSF02.js +131 -0
- package/dist/knowledge-graph-iBG76fvm.js +131 -0
- package/dist/loader-BkDi8MD9.js +400 -0
- package/dist/loader-CC45xGpC.js +4 -0
- package/dist/loader-CnEdOyjT.js +400 -0
- package/dist/loader-DI2qDRPC.js +4 -0
- package/dist/logger-Cp8wC7F8.js +83 -0
- package/dist/logger-ybOp7VOC.js +83 -0
- package/dist/manager-03ipO9R0.js +105 -0
- package/dist/manager-B2Gls5RG.js +218 -0
- package/dist/manager-BpDfbDjg.js +117 -0
- package/dist/manager-Bxl0sqlh.js +4 -0
- package/dist/manager-CWNSML5D.js +117 -0
- package/dist/manager-CrVDn6eN.js +6 -0
- package/dist/manager-FCgF1plu.js +218 -0
- package/dist/manager-SJe9gt-q.js +4 -0
- package/dist/manager-rgCsaWT1.js +40 -0
- package/dist/mcp-CfoSU4Uz.js +139 -0
- package/dist/mcp-loader-CvxRDtPC.js +94 -0
- package/dist/mcp-loader-DkRBsLpk.js +94 -0
- package/dist/memory-BlHL7JCO.js +4 -0
- package/dist/memory-DsS_eFvJ.js +270 -0
- package/dist/memory-auto-BkvtSFUw.js +5 -0
- package/dist/memory-auto-Bnz_-1wP.js +306 -0
- package/dist/memory-auto-CpQHZlEJ.js +306 -0
- package/dist/memory-auto-Z6LCf-iK.js +5 -0
- package/dist/memory-integration-cSYkZyEo.js +91 -0
- package/dist/memory-integration-g2vxwgoE.js +91 -0
- package/dist/moltbook-BtLDZTfM.js +81 -0
- package/dist/moltbook-Cl8cQfxJ.js +81 -0
- package/dist/node-Dw2Gi-cP.js +222 -0
- package/dist/nodes-registry-B8dmrlLv.js +52 -0
- package/dist/nodes-registry-C9dCFwjh.js +52 -0
- package/dist/oauth-flow-CeaaGAz0.js +150 -0
- package/dist/oauth-flow-DQPvMHRH.js +150 -0
- package/dist/oauth-provider-B4dzn56l.js +110 -0
- package/dist/oauth-provider-Uo4Nib_c.js +110 -0
- package/dist/observability-BV-Yx0V9.js +89 -0
- package/dist/observability-nZ3CBIxG.js +89 -0
- package/dist/onboard-0WoDxbv_.js +10 -0
- package/dist/onboard-BBBWcfhp.js +10 -0
- package/dist/onboard-BXNXCQp4.js +4070 -0
- package/dist/onboard-Bw28IRQ3.js +4070 -0
- package/dist/orchestrator-BovkM63z.js +6 -0
- package/dist/orchestrator-DSbpkP1X.js +189 -0
- package/dist/orchestrator-DmnEvMaL.js +189 -0
- package/dist/orchestrator-RI3bpqqc.js +6 -0
- package/dist/osint-B4_m3VHQ.js +277 -0
- package/dist/pairing-6iM27aD8.js +196 -0
- package/dist/pairing-dGoiGepK.js +4 -0
- package/dist/pc-access-CgCsYrpt.js +8 -0
- package/dist/pc-access-_iH2aorG.js +819 -0
- package/dist/pending-approval-BgNjjuI2.js +22 -0
- package/dist/pending-approval-CUXjysAo.js +22 -0
- package/dist/reminders-store-Drjed_-h.js +58 -0
- package/dist/renderer-BVQrd0_g.js +225 -0
- package/dist/rules-BE4GV6cV.js +103 -0
- package/dist/run-main.js +1639 -460
- package/dist/runner-CJFJUtPm.js +1271 -0
- package/dist/runner-DatMMYYE.js +1271 -0
- package/dist/sdk/index.js +2 -2
- package/dist/sdk/index.mjs +2 -2
- package/dist/security-BqNyT4ID.js +4 -0
- package/dist/security-tpgqPWWH.js +73 -0
- package/dist/server-Brl_HQUB.js +1255 -0
- package/dist/server-D4wVHiX9.js +4 -0
- package/dist/server-Dh3JlBFB.js +1255 -0
- package/dist/server-DhfipkwN.js +4 -0
- package/dist/session-store-BUiPz0Vv.js +5 -0
- package/dist/session-store-is4B6qmD.js +113 -0
- package/dist/sessions-tools-CbUTFe4i.js +5 -0
- package/dist/sessions-tools-CeqD7iil.js +95 -0
- package/dist/skill-loader-BaNLVmJy.js +7 -0
- package/dist/skill-loader-HgpF6Vqs.js +159 -0
- package/dist/skill-runtime-BXWd-Ktf.js +102 -0
- package/dist/skill-runtime-CJN24QPW.js +102 -0
- package/dist/skill-runtime-jgklm02e.js +5 -0
- package/dist/skill-runtime-w1ig_lcw.js +5 -0
- package/dist/src-Bhybpk1J.js +63 -0
- package/dist/src-BxPHKO5x.js +63 -0
- package/dist/src-DIc-L2IG.js +20 -0
- package/dist/src-DMJ4-uqk.js +458 -0
- package/dist/src-g_rNx5rh.js +458 -0
- package/dist/sub-agent-tools-CHQoHz9c.js +39 -0
- package/dist/sub-agent-tools-DHY-4WWM.js +39 -0
- package/dist/theme-DcxwcUgZ.js +180 -0
- package/dist/theme-cx0fkgWC.js +8 -0
- package/dist/tool-policy-CNT-mF2Z.js +189 -0
- package/dist/tool-policy-DZvF8xlQ.js +189 -0
- package/dist/tts-elevenlabs-BRosZv-f.js +61 -0
- package/dist/tts-elevenlabs-C06nUxMK.js +61 -0
- package/dist/update-check-C2Dz85wJ.js +81 -0
- package/dist/update-check-w4XuxVl7.js +81 -0
- package/dist/vision-BMmiIKy7.js +121 -0
- package/dist/vision-JOtOS1Br.js +121 -0
- package/dist/vision-tools-CB28ZCO_.js +5 -0
- package/dist/vision-tools-DVuYc17I.js +51 -0
- package/dist/vision-tools-U3YC4L-g.js +5 -0
- package/dist/vision-tools-vPPwQ-0N.js +51 -0
- package/dist/voice-transcription-B555DbWR.js +138 -0
- package/dist/voice-transcription-DBo5hXmu.js +138 -0
- package/dist/website-watch-tools-DFMrJU-R.js +139 -0
- package/dist/website-watch-tools-Du3W5sN7.js +5 -0
- package/package.json +1 -1
|
@@ -0,0 +1,40 @@
|
|
|
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 chalk = require_chunk.__toESM(require("chalk"));
|
|
5
|
+
const ora = require_chunk.__toESM(require("ora"));
|
|
6
|
+
const fs_extra = require_chunk.__toESM(require("fs-extra"));
|
|
7
|
+
|
|
8
|
+
//#region src/config/manager.ts
|
|
9
|
+
require_paths$1.init_paths();
|
|
10
|
+
var ConfigManager = class {
|
|
11
|
+
async save(config) {
|
|
12
|
+
await fs_extra.default.ensureDir(require_paths.getHyperClawDir());
|
|
13
|
+
await fs_extra.default.writeJson(require_paths.getConfigPath(), config, { spaces: 2 });
|
|
14
|
+
}
|
|
15
|
+
async load() {
|
|
16
|
+
if (await fs_extra.default.pathExists(require_paths.getConfigPath())) return fs_extra.default.readJson(require_paths.getConfigPath());
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
async sync(options) {
|
|
20
|
+
const spinner = (0, ora.default)(`Syncing to ${options.to}...`).start();
|
|
21
|
+
await new Promise((resolve) => setTimeout(resolve, 2e3));
|
|
22
|
+
if (options.encrypt) {
|
|
23
|
+
spinner.text = "Encrypting configuration...";
|
|
24
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
25
|
+
}
|
|
26
|
+
spinner.succeed(`Synced to ${options.to} ${options.encrypt ? "(encrypted)" : ""}`);
|
|
27
|
+
console.log(chalk.default.gray(`Backup location: ${options.to}://hyperclaw-config-${Date.now()}`));
|
|
28
|
+
}
|
|
29
|
+
getConfigPath() {
|
|
30
|
+
return require_paths.getHyperClawDir();
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
//#endregion
|
|
35
|
+
Object.defineProperty(exports, 'ConfigManager', {
|
|
36
|
+
enumerable: true,
|
|
37
|
+
get: function () {
|
|
38
|
+
return ConfigManager;
|
|
39
|
+
}
|
|
40
|
+
});
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
const require_chunk = require('./chunk-jS-bbMI5.js');
|
|
2
|
+
const chalk = require_chunk.__toESM(require("chalk"));
|
|
3
|
+
const inquirer = require_chunk.__toESM(require("inquirer"));
|
|
4
|
+
const ora = require_chunk.__toESM(require("ora"));
|
|
5
|
+
const fs_extra = require_chunk.__toESM(require("fs-extra"));
|
|
6
|
+
const path = require_chunk.__toESM(require("path"));
|
|
7
|
+
const os = require_chunk.__toESM(require("os"));
|
|
8
|
+
|
|
9
|
+
//#region src/commands/mcp.ts
|
|
10
|
+
const MCP_FILE = path.default.join(os.default.homedir(), ".hyperclaw", "mcp-servers.json");
|
|
11
|
+
async function loadServers() {
|
|
12
|
+
try {
|
|
13
|
+
return await fs_extra.default.readJson(MCP_FILE);
|
|
14
|
+
} catch {
|
|
15
|
+
return [];
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
async function saveServers(servers) {
|
|
19
|
+
await fs_extra.default.ensureDir(path.default.dirname(MCP_FILE));
|
|
20
|
+
await fs_extra.default.writeJson(MCP_FILE, servers, { spaces: 2 });
|
|
21
|
+
}
|
|
22
|
+
async function mcpList() {
|
|
23
|
+
const servers = await loadServers();
|
|
24
|
+
console.log(chalk.default.bold.cyan("\n 🔌 MCP SERVERS\n"));
|
|
25
|
+
if (servers.length === 0) {
|
|
26
|
+
console.log(chalk.default.gray(" No MCP servers registered.\n"));
|
|
27
|
+
console.log(chalk.default.gray(" Add one: hyperclaw mcp add\n"));
|
|
28
|
+
console.log(chalk.default.gray(" Or install via skill hub: hyperclaw hub --install mcp-filesystem\n"));
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
for (const s of servers) {
|
|
32
|
+
const dot = s.enabled ? chalk.default.green("●") : chalk.default.gray("○");
|
|
33
|
+
console.log(` ${dot} ${chalk.default.white(s.name)} ${chalk.default.gray(`[${s.transport}]`)}`);
|
|
34
|
+
if (s.command) console.log(` ${chalk.default.gray("cmd:")} ${s.command}`);
|
|
35
|
+
if (s.url) console.log(` ${chalk.default.gray("url:")} ${chalk.default.cyan(s.url)}`);
|
|
36
|
+
if (s.tools?.length) console.log(` ${chalk.default.gray("tools:")} ${s.tools.slice(0, 5).join(", ")}${s.tools.length > 5 ? ` +${s.tools.length - 5} more` : ""}`);
|
|
37
|
+
if (s.lastProbeAt) console.log(` ${chalk.default.gray(`last probe: ${new Date(s.lastProbeAt).toLocaleString()}`)}`);
|
|
38
|
+
console.log();
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
async function mcpAdd() {
|
|
42
|
+
console.log(chalk.default.bold.cyan("\n ➕ ADD MCP SERVER\n"));
|
|
43
|
+
const { name } = await inquirer.default.prompt([{
|
|
44
|
+
type: "input",
|
|
45
|
+
name: "name",
|
|
46
|
+
message: "Server name:",
|
|
47
|
+
validate: (v) => !!v.trim() || "Required"
|
|
48
|
+
}]);
|
|
49
|
+
const { transport } = await inquirer.default.prompt([{
|
|
50
|
+
type: "list",
|
|
51
|
+
name: "transport",
|
|
52
|
+
message: "Transport:",
|
|
53
|
+
choices: [
|
|
54
|
+
"stdio",
|
|
55
|
+
"sse",
|
|
56
|
+
"http"
|
|
57
|
+
]
|
|
58
|
+
}]);
|
|
59
|
+
let command;
|
|
60
|
+
let url;
|
|
61
|
+
if (transport === "stdio") {
|
|
62
|
+
const res = await inquirer.default.prompt([{
|
|
63
|
+
type: "input",
|
|
64
|
+
name: "command",
|
|
65
|
+
message: "Start command (e.g. node /path/to/server.js):",
|
|
66
|
+
validate: (v) => !!v.trim() || "Required"
|
|
67
|
+
}]);
|
|
68
|
+
command = res.command;
|
|
69
|
+
} else {
|
|
70
|
+
const res = await inquirer.default.prompt([{
|
|
71
|
+
type: "input",
|
|
72
|
+
name: "url",
|
|
73
|
+
message: `URL (e.g. http://localhost:3001):`,
|
|
74
|
+
validate: (v) => v.startsWith("http") || "Must start with http"
|
|
75
|
+
}]);
|
|
76
|
+
url = res.url;
|
|
77
|
+
}
|
|
78
|
+
const server = {
|
|
79
|
+
id: name.toLowerCase().replace(/\s+/g, "-"),
|
|
80
|
+
name,
|
|
81
|
+
transport,
|
|
82
|
+
command,
|
|
83
|
+
url,
|
|
84
|
+
enabled: true,
|
|
85
|
+
addedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
86
|
+
};
|
|
87
|
+
const servers = await loadServers();
|
|
88
|
+
servers.push(server);
|
|
89
|
+
await saveServers(servers);
|
|
90
|
+
console.log(chalk.default.green(`\n ✔ MCP server added: ${name}`));
|
|
91
|
+
console.log(chalk.default.gray(" Run: hyperclaw mcp probe to test the connection\n"));
|
|
92
|
+
}
|
|
93
|
+
async function mcpRemove(id) {
|
|
94
|
+
const servers = await loadServers();
|
|
95
|
+
const idx = servers.findIndex((s) => s.id === id);
|
|
96
|
+
if (idx === -1) {
|
|
97
|
+
console.log(chalk.default.red(`\n ✖ Server not found: ${id}\n`));
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
servers.splice(idx, 1);
|
|
101
|
+
await saveServers(servers);
|
|
102
|
+
console.log(chalk.default.green(`\n ✔ MCP server removed: ${id}\n`));
|
|
103
|
+
}
|
|
104
|
+
async function mcpProbe(id) {
|
|
105
|
+
const servers = await loadServers();
|
|
106
|
+
const targets = id ? servers.filter((s) => s.id === id) : servers;
|
|
107
|
+
if (targets.length === 0) {
|
|
108
|
+
console.log(chalk.default.gray("\n No servers to probe. Add one: hyperclaw mcp add\n"));
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
console.log(chalk.default.bold.cyan("\n 🔍 PROBING MCP SERVERS\n"));
|
|
112
|
+
for (const server of targets) {
|
|
113
|
+
const spinner = (0, ora.default)(` Probing ${server.name}...`).start();
|
|
114
|
+
await new Promise((r) => setTimeout(r, 800));
|
|
115
|
+
if (server.transport === "http" || server.transport === "sse") try {
|
|
116
|
+
const axios = (await import("axios")).default;
|
|
117
|
+
const res = await axios.get(`${server.url}/tools`, { timeout: 3e3 });
|
|
118
|
+
server.tools = res.data?.tools?.map((t) => t.name) || [];
|
|
119
|
+
server.lastProbeAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
120
|
+
await saveServers(servers);
|
|
121
|
+
spinner.succeed(`${server.name} — ${server.tools?.length ?? 0} tools`);
|
|
122
|
+
if ((server.tools?.length ?? 0) > 0) console.log(chalk.default.gray(` ${server.tools?.join(", ") ?? ""}`));
|
|
123
|
+
} catch {
|
|
124
|
+
spinner.warn(`${server.name} — unreachable (${server.url})`);
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
server.lastProbeAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
128
|
+
await saveServers(servers);
|
|
129
|
+
spinner.succeed(`${server.name} — stdio (probe requires running server)`);
|
|
130
|
+
}
|
|
131
|
+
console.log();
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
//#endregion
|
|
136
|
+
exports.mcpAdd = mcpAdd;
|
|
137
|
+
exports.mcpList = mcpList;
|
|
138
|
+
exports.mcpProbe = mcpProbe;
|
|
139
|
+
exports.mcpRemove = mcpRemove;
|
|
@@ -0,0 +1,94 @@
|
|
|
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/mcp-loader.ts
|
|
7
|
+
async function getMCPConfig() {
|
|
8
|
+
try {
|
|
9
|
+
const cfg = await fs_extra.default.readJson(path.default.join(HC_DIR, "hyperclaw.json"));
|
|
10
|
+
const servers = cfg.mcp?.servers ?? [];
|
|
11
|
+
return Array.isArray(servers) ? servers : [];
|
|
12
|
+
} catch {
|
|
13
|
+
return [];
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
/** Load tools from all configured MCP servers. */
|
|
17
|
+
async function loadMCPTools() {
|
|
18
|
+
const servers = await getMCPConfig();
|
|
19
|
+
if (servers.length === 0) return [];
|
|
20
|
+
let Client;
|
|
21
|
+
let StdioClientTransport;
|
|
22
|
+
let StreamableHTTPClientTransport;
|
|
23
|
+
try {
|
|
24
|
+
const sdk = await import("@modelcontextprotocol/sdk");
|
|
25
|
+
Client = sdk.Client;
|
|
26
|
+
StdioClientTransport = sdk.StdioClientTransport;
|
|
27
|
+
StreamableHTTPClientTransport = sdk.StreamableHTTPClientTransport;
|
|
28
|
+
} catch {
|
|
29
|
+
return [];
|
|
30
|
+
}
|
|
31
|
+
const tools = [];
|
|
32
|
+
for (const srv of servers) try {
|
|
33
|
+
const client = new Client({
|
|
34
|
+
name: "hyperclaw",
|
|
35
|
+
version: "5.0.1"
|
|
36
|
+
});
|
|
37
|
+
if (srv.url) {
|
|
38
|
+
const transport = new StreamableHTTPClientTransport(new URL(srv.url));
|
|
39
|
+
await client.connect(transport);
|
|
40
|
+
} else if (srv.command) {
|
|
41
|
+
const transport = new StdioClientTransport({
|
|
42
|
+
command: srv.command,
|
|
43
|
+
args: srv.args ?? []
|
|
44
|
+
});
|
|
45
|
+
await client.connect(transport);
|
|
46
|
+
} else continue;
|
|
47
|
+
const allTools = [];
|
|
48
|
+
let cursor;
|
|
49
|
+
do {
|
|
50
|
+
const res = await client.listTools?.({ cursor }) ?? {
|
|
51
|
+
tools: [],
|
|
52
|
+
nextCursor: void 0
|
|
53
|
+
};
|
|
54
|
+
allTools.push(...res.tools ?? []);
|
|
55
|
+
cursor = res.nextCursor;
|
|
56
|
+
} while (cursor);
|
|
57
|
+
for (const t of allTools) {
|
|
58
|
+
const toolName = t.name;
|
|
59
|
+
const mcpClient = client;
|
|
60
|
+
tools.push({
|
|
61
|
+
name: `mcp_${srv.name}_${toolName}`.replace(/[^a-z0-9_]/gi, "_"),
|
|
62
|
+
description: (t.description ?? toolName).slice(0, 500),
|
|
63
|
+
input_schema: t.inputSchema && typeof t.inputSchema === "object" && "type" in t.inputSchema && "properties" in t.inputSchema ? t.inputSchema : {
|
|
64
|
+
type: "object",
|
|
65
|
+
properties: {}
|
|
66
|
+
},
|
|
67
|
+
handler: async (input) => {
|
|
68
|
+
try {
|
|
69
|
+
const result = await mcpClient.callTool?.({
|
|
70
|
+
name: toolName,
|
|
71
|
+
arguments: input
|
|
72
|
+
});
|
|
73
|
+
const content = result?.content;
|
|
74
|
+
if (Array.isArray(content)) return content.map((c) => c?.text ?? JSON.stringify(c)).join("\n");
|
|
75
|
+
return typeof content === "string" ? content : JSON.stringify(result ?? {});
|
|
76
|
+
} catch (e) {
|
|
77
|
+
return `MCP error: ${e.message}`;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
} catch (e) {
|
|
83
|
+
console.error(`[mcp] Failed to load ${srv.name}:`, e.message);
|
|
84
|
+
}
|
|
85
|
+
return tools;
|
|
86
|
+
}
|
|
87
|
+
var HC_DIR;
|
|
88
|
+
var init_mcp_loader = require_chunk.__esm({ "src/services/mcp-loader.ts"() {
|
|
89
|
+
HC_DIR = path.default.join(os.default.homedir(), ".hyperclaw");
|
|
90
|
+
} });
|
|
91
|
+
|
|
92
|
+
//#endregion
|
|
93
|
+
init_mcp_loader();
|
|
94
|
+
exports.loadMCPTools = loadMCPTools;
|
|
@@ -0,0 +1,94 @@
|
|
|
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/mcp-loader.ts
|
|
7
|
+
async function getMCPConfig() {
|
|
8
|
+
try {
|
|
9
|
+
const cfg = await fs_extra.default.readJson(path.default.join(HC_DIR, "hyperclaw.json"));
|
|
10
|
+
const servers = cfg.mcp?.servers ?? [];
|
|
11
|
+
return Array.isArray(servers) ? servers : [];
|
|
12
|
+
} catch {
|
|
13
|
+
return [];
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
/** Load tools from all configured MCP servers. */
|
|
17
|
+
async function loadMCPTools() {
|
|
18
|
+
const servers = await getMCPConfig();
|
|
19
|
+
if (servers.length === 0) return [];
|
|
20
|
+
let Client;
|
|
21
|
+
let StdioClientTransport;
|
|
22
|
+
let StreamableHTTPClientTransport;
|
|
23
|
+
try {
|
|
24
|
+
const sdk = await import("@modelcontextprotocol/sdk");
|
|
25
|
+
Client = sdk.Client;
|
|
26
|
+
StdioClientTransport = sdk.StdioClientTransport;
|
|
27
|
+
StreamableHTTPClientTransport = sdk.StreamableHTTPClientTransport;
|
|
28
|
+
} catch {
|
|
29
|
+
return [];
|
|
30
|
+
}
|
|
31
|
+
const tools = [];
|
|
32
|
+
for (const srv of servers) try {
|
|
33
|
+
const client = new Client({
|
|
34
|
+
name: "hyperclaw",
|
|
35
|
+
version: "5.0.0"
|
|
36
|
+
});
|
|
37
|
+
if (srv.url) {
|
|
38
|
+
const transport = new StreamableHTTPClientTransport(new URL(srv.url));
|
|
39
|
+
await client.connect(transport);
|
|
40
|
+
} else if (srv.command) {
|
|
41
|
+
const transport = new StdioClientTransport({
|
|
42
|
+
command: srv.command,
|
|
43
|
+
args: srv.args ?? []
|
|
44
|
+
});
|
|
45
|
+
await client.connect(transport);
|
|
46
|
+
} else continue;
|
|
47
|
+
const allTools = [];
|
|
48
|
+
let cursor;
|
|
49
|
+
do {
|
|
50
|
+
const res = await client.listTools?.({ cursor }) ?? {
|
|
51
|
+
tools: [],
|
|
52
|
+
nextCursor: void 0
|
|
53
|
+
};
|
|
54
|
+
allTools.push(...res.tools ?? []);
|
|
55
|
+
cursor = res.nextCursor;
|
|
56
|
+
} while (cursor);
|
|
57
|
+
for (const t of allTools) {
|
|
58
|
+
const toolName = t.name;
|
|
59
|
+
const mcpClient = client;
|
|
60
|
+
tools.push({
|
|
61
|
+
name: `mcp_${srv.name}_${toolName}`.replace(/[^a-z0-9_]/gi, "_"),
|
|
62
|
+
description: (t.description ?? toolName).slice(0, 500),
|
|
63
|
+
input_schema: t.inputSchema && typeof t.inputSchema === "object" && "type" in t.inputSchema && "properties" in t.inputSchema ? t.inputSchema : {
|
|
64
|
+
type: "object",
|
|
65
|
+
properties: {}
|
|
66
|
+
},
|
|
67
|
+
handler: async (input) => {
|
|
68
|
+
try {
|
|
69
|
+
const result = await mcpClient.callTool?.({
|
|
70
|
+
name: toolName,
|
|
71
|
+
arguments: input
|
|
72
|
+
});
|
|
73
|
+
const content = result?.content;
|
|
74
|
+
if (Array.isArray(content)) return content.map((c) => c?.text ?? JSON.stringify(c)).join("\n");
|
|
75
|
+
return typeof content === "string" ? content : JSON.stringify(result ?? {});
|
|
76
|
+
} catch (e) {
|
|
77
|
+
return `MCP error: ${e.message}`;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
} catch (e) {
|
|
83
|
+
console.error(`[mcp] Failed to load ${srv.name}:`, e.message);
|
|
84
|
+
}
|
|
85
|
+
return tools;
|
|
86
|
+
}
|
|
87
|
+
var HC_DIR;
|
|
88
|
+
var init_mcp_loader = require_chunk.__esm({ "src/services/mcp-loader.ts"() {
|
|
89
|
+
HC_DIR = path.default.join(os.default.homedir(), ".hyperclaw");
|
|
90
|
+
} });
|
|
91
|
+
|
|
92
|
+
//#endregion
|
|
93
|
+
init_mcp_loader();
|
|
94
|
+
exports.loadMCPTools = loadMCPTools;
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
const require_chunk = require('./chunk-jS-bbMI5.js');
|
|
2
|
+
const chalk = require_chunk.__toESM(require("chalk"));
|
|
3
|
+
const ora = require_chunk.__toESM(require("ora"));
|
|
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/agents/memory.ts
|
|
9
|
+
var MemoryManager = class {
|
|
10
|
+
baseDir;
|
|
11
|
+
agentsFile;
|
|
12
|
+
memoryFile;
|
|
13
|
+
logFile;
|
|
14
|
+
constructor(workspaceDir) {
|
|
15
|
+
this.baseDir = workspaceDir || path.default.join(os.default.homedir(), ".hyperclaw");
|
|
16
|
+
this.agentsFile = path.default.join(this.baseDir, "AGENTS.md");
|
|
17
|
+
this.memoryFile = path.default.join(this.baseDir, "MEMORY.md");
|
|
18
|
+
this.logFile = path.default.join(this.baseDir, "logs", `${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}.md`);
|
|
19
|
+
}
|
|
20
|
+
async init(identity) {
|
|
21
|
+
await fs_extra.default.ensureDir(this.baseDir);
|
|
22
|
+
await fs_extra.default.ensureDir(path.default.join(this.baseDir, "logs"));
|
|
23
|
+
const spinner = (0, ora.default)("Initializing memory and agent identity...").start();
|
|
24
|
+
await this.writeAgentsMd(identity);
|
|
25
|
+
await this.writeMemoryMd(identity);
|
|
26
|
+
await this.initDailyLog();
|
|
27
|
+
spinner.succeed("AGENTS.md, MEMORY.md and daily log created");
|
|
28
|
+
console.log(chalk.default.gray(` 📁 Workspace: ${this.baseDir}`));
|
|
29
|
+
console.log(chalk.default.gray(` 📄 AGENTS.md: ${this.agentsFile}`));
|
|
30
|
+
console.log(chalk.default.gray(` 🧠 MEMORY.md: ${this.memoryFile}`));
|
|
31
|
+
console.log();
|
|
32
|
+
}
|
|
33
|
+
async writeAgentsMd(id) {
|
|
34
|
+
const content = `# AGENTS.md — HyperClaw Global Agent Rules
|
|
35
|
+
> Generated: ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
36
|
+
> This file is read by ALL sessions and subagents.
|
|
37
|
+
|
|
38
|
+
## Identity
|
|
39
|
+
- **Agent Name:** ${id.agentName}
|
|
40
|
+
- **User Name:** ${id.userName}
|
|
41
|
+
- **Personality:** ${id.personality}
|
|
42
|
+
- **Language:** ${id.language}
|
|
43
|
+
|
|
44
|
+
## Global Rules
|
|
45
|
+
${id.rules.map((r, i) => `${i + 1}. ${r}`).join("\n")}
|
|
46
|
+
|
|
47
|
+
## Subagent Hierarchy
|
|
48
|
+
- Parent: HyperClaw Core
|
|
49
|
+
- Children: Channel Agents (Telegram, Discord, etc.)
|
|
50
|
+
- All subagents MUST inherit these rules
|
|
51
|
+
- No subagent may override global safety rules
|
|
52
|
+
|
|
53
|
+
## Memory Protocol
|
|
54
|
+
- Write significant events to MEMORY.md
|
|
55
|
+
- Log daily interactions to logs/YYYY-MM-DD.md
|
|
56
|
+
- Always read AGENTS.md at session start
|
|
57
|
+
|
|
58
|
+
## Safety Boundaries
|
|
59
|
+
- Never reveal the auth token
|
|
60
|
+
- Never execute code outside the sandbox skill
|
|
61
|
+
- Always ask for confirmation before irreversible actions
|
|
62
|
+
- Refuse requests that violate user privacy
|
|
63
|
+
|
|
64
|
+
## Cross-Session Persistence
|
|
65
|
+
- Session state is stored in ~/.hyperclaw/sessions/
|
|
66
|
+
- Use memory tools to recall past interactions
|
|
67
|
+
`;
|
|
68
|
+
await fs_extra.default.writeFile(this.agentsFile, content, "utf8");
|
|
69
|
+
}
|
|
70
|
+
async writeMemoryMd(id) {
|
|
71
|
+
const content = `# MEMORY.md — HyperClaw Persistent Memory
|
|
72
|
+
> Initialized: ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
73
|
+
|
|
74
|
+
## User Profile
|
|
75
|
+
- Name: ${id.userName}
|
|
76
|
+
- Preferred language: ${id.language}
|
|
77
|
+
- Agent alias: ${id.agentName}
|
|
78
|
+
|
|
79
|
+
## Session History
|
|
80
|
+
*(Populated automatically during sessions)*
|
|
81
|
+
|
|
82
|
+
## Key Facts
|
|
83
|
+
*(Write important information here for future sessions)*
|
|
84
|
+
|
|
85
|
+
## Reminders
|
|
86
|
+
*(Active reminders are listed here)*
|
|
87
|
+
`;
|
|
88
|
+
await fs_extra.default.writeFile(this.memoryFile, content, "utf8");
|
|
89
|
+
}
|
|
90
|
+
async initDailyLog() {
|
|
91
|
+
const today = (/* @__PURE__ */ new Date()).toLocaleDateString("en-US", {
|
|
92
|
+
weekday: "long",
|
|
93
|
+
year: "numeric",
|
|
94
|
+
month: "long",
|
|
95
|
+
day: "numeric"
|
|
96
|
+
});
|
|
97
|
+
const content = `# Daily Log — ${today}
|
|
98
|
+
|
|
99
|
+
## Sessions
|
|
100
|
+
- ${(/* @__PURE__ */ new Date()).toLocaleTimeString()} — Session initialized
|
|
101
|
+
|
|
102
|
+
## Notes
|
|
103
|
+
`;
|
|
104
|
+
await fs_extra.default.ensureDir(path.default.dirname(this.logFile));
|
|
105
|
+
await fs_extra.default.writeFile(this.logFile, content, "utf8");
|
|
106
|
+
}
|
|
107
|
+
async appendRule(rule) {
|
|
108
|
+
const spinner = (0, ora.default)("Writing rule to AGENTS.md...").start();
|
|
109
|
+
const content = await fs_extra.default.readFile(this.agentsFile, "utf8");
|
|
110
|
+
const updated = content.replace("*(Populated automatically during sessions)*", `*(Populated automatically during sessions)*\n\n### Added Rule\n- ${rule}`);
|
|
111
|
+
await fs_extra.default.writeFile(this.agentsFile, updated, "utf8");
|
|
112
|
+
spinner.succeed(`Rule added to AGENTS.md`);
|
|
113
|
+
}
|
|
114
|
+
async addMemory(fact) {
|
|
115
|
+
const spinner = (0, ora.default)("Writing to MEMORY.md...").start();
|
|
116
|
+
const content = await fs_extra.default.readFile(this.memoryFile, "utf8");
|
|
117
|
+
const entry = `\n- [${(/* @__PURE__ */ new Date()).toISOString()}] ${fact}`;
|
|
118
|
+
const updated = content.replace("*(Write important information here for future sessions)*", `*(Write important information here for future sessions)*${entry}`);
|
|
119
|
+
await fs_extra.default.writeFile(this.memoryFile, updated, "utf8");
|
|
120
|
+
spinner.succeed(`Memory updated`);
|
|
121
|
+
}
|
|
122
|
+
async load() {
|
|
123
|
+
try {
|
|
124
|
+
const agents = await fs_extra.default.readFile(this.agentsFile, "utf8");
|
|
125
|
+
const memory = await fs_extra.default.readFile(this.memoryFile, "utf8");
|
|
126
|
+
return {
|
|
127
|
+
agents,
|
|
128
|
+
memory
|
|
129
|
+
};
|
|
130
|
+
} catch {
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
getBaseDir() {
|
|
135
|
+
return this.baseDir;
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
async function initWorkspaceFiles(identity, workspaceDir) {
|
|
139
|
+
const files = {
|
|
140
|
+
"SOUL.md": generateSoul(identity),
|
|
141
|
+
"USER.md": generateUser(identity),
|
|
142
|
+
"TOOLS.md": generateTools(),
|
|
143
|
+
"HEARTBEAT.md": generateHeartbeat(),
|
|
144
|
+
"BOOTSTRAP.md": generateBootstrap(identity)
|
|
145
|
+
};
|
|
146
|
+
await fs_extra.default.ensureDir(workspaceDir);
|
|
147
|
+
for (const [fname, content] of Object.entries(files)) {
|
|
148
|
+
const fpath = path.default.join(workspaceDir, fname);
|
|
149
|
+
if (!await fs_extra.default.pathExists(fpath)) await fs_extra.default.writeFile(fpath, content, "utf8");
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
function generateSoul(id) {
|
|
153
|
+
return `# SOUL.md — Agent Personality & Values
|
|
154
|
+
> Generated: ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
155
|
+
|
|
156
|
+
## Core Identity
|
|
157
|
+
- **Name:** ${id.agentName}
|
|
158
|
+
- **Personality:** ${id.personality}
|
|
159
|
+
- **Primary language:** ${id.language}
|
|
160
|
+
|
|
161
|
+
## Values
|
|
162
|
+
- Honesty over flattery
|
|
163
|
+
- Brevity — get to the point
|
|
164
|
+
- Respect autonomy — suggest, never demand
|
|
165
|
+
- Always confirm before irreversible actions
|
|
166
|
+
|
|
167
|
+
## Boundaries
|
|
168
|
+
- Never reveal gateway tokens or API keys
|
|
169
|
+
- Always ask confirmation before destructive actions
|
|
170
|
+
- Never claim to be human when sincerely asked
|
|
171
|
+
`;
|
|
172
|
+
}
|
|
173
|
+
function generateUser(id) {
|
|
174
|
+
return `# USER.md — About the Person I Work For
|
|
175
|
+
> Generated: ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
176
|
+
|
|
177
|
+
## Identity
|
|
178
|
+
- **Name:** ${id.userName}
|
|
179
|
+
- **Preferred language:** ${id.language}
|
|
180
|
+
|
|
181
|
+
## Communication Preferences
|
|
182
|
+
- Tone: casual
|
|
183
|
+
- Response length: auto
|
|
184
|
+
|
|
185
|
+
## What I'm Working On
|
|
186
|
+
*(Update this regularly — agent uses it for context)*
|
|
187
|
+
|
|
188
|
+
## My Stack
|
|
189
|
+
*(Add your tools here)*
|
|
190
|
+
|
|
191
|
+
## Do NOT do these things
|
|
192
|
+
- Pad responses with unnecessary filler
|
|
193
|
+
|
|
194
|
+
## Always do these things
|
|
195
|
+
- Respond in ${id.language} unless I write in another language
|
|
196
|
+
`;
|
|
197
|
+
}
|
|
198
|
+
function generateTools() {
|
|
199
|
+
return `# TOOLS.md — Available Skills & Tools
|
|
200
|
+
> Generated: ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
201
|
+
|
|
202
|
+
## Active Skills
|
|
203
|
+
| ID | Name | Status |
|
|
204
|
+
|----|------|--------|
|
|
205
|
+
| reminders | Smart Reminders | ✅ enabled |
|
|
206
|
+
| translator | Real-time Translator | ✅ enabled |
|
|
207
|
+
|
|
208
|
+
## Add More Skills
|
|
209
|
+
\`\`\`
|
|
210
|
+
hyperclaw hub # Browse available skills
|
|
211
|
+
hyperclaw hub --install web-search
|
|
212
|
+
\`\`\`
|
|
213
|
+
|
|
214
|
+
## MCP Servers
|
|
215
|
+
No MCP servers configured. Add with: \`hyperclaw mcp add\`
|
|
216
|
+
`;
|
|
217
|
+
}
|
|
218
|
+
function generateHeartbeat() {
|
|
219
|
+
return `# HEARTBEAT.md — System Health Log
|
|
220
|
+
> Initialized: ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
221
|
+
|
|
222
|
+
Auto-written by the gateway-health hook every 5 minutes.
|
|
223
|
+
Enable with: \`hyperclaw hooks enable gateway-health\`
|
|
224
|
+
|
|
225
|
+
## Last Status
|
|
226
|
+
Pending first heartbeat...
|
|
227
|
+
`;
|
|
228
|
+
}
|
|
229
|
+
function generateBootstrap(id) {
|
|
230
|
+
return `# BOOTSTRAP.md β€” Fast Start Context
|
|
231
|
+
> Generated: ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
232
|
+
|
|
233
|
+
## Mission
|
|
234
|
+
Help ${id.userName} move the current task forward with minimal setup friction.
|
|
235
|
+
|
|
236
|
+
## First Tasks
|
|
237
|
+
1. Read AGENTS.md, USER.md, TOOLS.md, and MEMORY.md if present.
|
|
238
|
+
2. Confirm the current repo / project shape before editing anything.
|
|
239
|
+
3. Prefer the smallest change that unblocks progress.
|
|
240
|
+
|
|
241
|
+
## Environment
|
|
242
|
+
- Agent: ${id.agentName}
|
|
243
|
+
- User: ${id.userName}
|
|
244
|
+
- Language: ${id.language}
|
|
245
|
+
|
|
246
|
+
## Current Constraints
|
|
247
|
+
- Ask before irreversible actions.
|
|
248
|
+
- Keep secrets out of workspace markdown files.
|
|
249
|
+
- Update docs when behavior changes.
|
|
250
|
+
|
|
251
|
+
## Definition Of Done
|
|
252
|
+
- Requested change is implemented.
|
|
253
|
+
- Relevant checks or verifications are run when available.
|
|
254
|
+
- Important follow-up risks are documented briefly.
|
|
255
|
+
`;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
//#endregion
|
|
259
|
+
Object.defineProperty(exports, 'MemoryManager', {
|
|
260
|
+
enumerable: true,
|
|
261
|
+
get: function () {
|
|
262
|
+
return MemoryManager;
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
Object.defineProperty(exports, 'initWorkspaceFiles', {
|
|
266
|
+
enumerable: true,
|
|
267
|
+
get: function () {
|
|
268
|
+
return initWorkspaceFiles;
|
|
269
|
+
}
|
|
270
|
+
});
|