mycohive-claw 4.0.1 → 4.0.3
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/package.json +2 -2
- package/scripts/postinstall.cjs +192 -0
- package/scripts/postinstall.js +0 -235
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mycohive-claw",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.3",
|
|
4
4
|
"description": "OpenClaw Plugin for Multi-Agent Orchestration with LLM Intent Routing",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"build": "tsc",
|
|
30
30
|
"dev": "tsc --watch",
|
|
31
31
|
"typecheck": "tsc --noEmit",
|
|
32
|
-
"postinstall": "node scripts/postinstall.
|
|
32
|
+
"postinstall": "node scripts/postinstall.cjs"
|
|
33
33
|
},
|
|
34
34
|
"openclaw": {
|
|
35
35
|
"extensions": [
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* postinstall.cjs
|
|
3
|
+
* Version: 4.0.0
|
|
4
|
+
*
|
|
5
|
+
* Auto-register plugin after npm install.
|
|
6
|
+
* No manual configuration needed.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const fs = require("fs");
|
|
10
|
+
const path = require("path");
|
|
11
|
+
const { execSync } = require("child_process");
|
|
12
|
+
|
|
13
|
+
// Find OpenClaw config path
|
|
14
|
+
function findOpenClawConfig() {
|
|
15
|
+
const candidates = [
|
|
16
|
+
// Linux/macOS
|
|
17
|
+
path.join(process.env.HOME || "", ".openclaw", "config.yml"),
|
|
18
|
+
path.join(process.env.HOME || "", ".openclaw", "config.yaml"),
|
|
19
|
+
path.join(process.env.HOME || "", ".config", "openclaw", "config.yml"),
|
|
20
|
+
path.join(process.env.HOME || "", ".config", "openclaw", "config.yaml"),
|
|
21
|
+
// Windows
|
|
22
|
+
path.join(process.env.APPDATA || "", "openclaw", "config.yml"),
|
|
23
|
+
path.join(process.env.APPDATA || "", "openclaw", "config.yaml"),
|
|
24
|
+
path.join(process.env.USERPROFILE || "", ".openclaw", "config.yml"),
|
|
25
|
+
path.join(process.env.USERPROFILE || "", ".openclaw", "config.yaml"),
|
|
26
|
+
// Server/container
|
|
27
|
+
"/etc/openclaw/config.yml",
|
|
28
|
+
"/etc/openclaw/config.yaml",
|
|
29
|
+
// Local project
|
|
30
|
+
".openclaw.yml",
|
|
31
|
+
".openclaw.yaml",
|
|
32
|
+
"openclaw.config.yml",
|
|
33
|
+
"openclaw.config.yaml",
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
for (const p of candidates) {
|
|
37
|
+
if (fs.existsSync(p)) return p;
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Try CLI to get config path
|
|
43
|
+
function findViaCLI() {
|
|
44
|
+
try {
|
|
45
|
+
const out = execSync(
|
|
46
|
+
"openclaw config 2>/dev/null || openclaw info 2>/dev/null || echo NOT_FOUND",
|
|
47
|
+
{ encoding: "utf-8", timeout: 5000 }
|
|
48
|
+
);
|
|
49
|
+
const lines = out.split("\n");
|
|
50
|
+
for (const line of lines) {
|
|
51
|
+
const match = line.match(/[\/\\]?[\w\-\\/.]+\.ya?ml/);
|
|
52
|
+
if (match && fs.existsSync(match[0])) return match[0];
|
|
53
|
+
}
|
|
54
|
+
} catch { /* ignore */ }
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Minimal YAML parser (no external deps)
|
|
59
|
+
function parseYaml(content) {
|
|
60
|
+
const result = {};
|
|
61
|
+
const lines = content.split("\n");
|
|
62
|
+
let currentSection = null;
|
|
63
|
+
let sectionIndent = 0;
|
|
64
|
+
|
|
65
|
+
for (let rawLine of lines) {
|
|
66
|
+
const line = rawLine.replace(/#[^\n]*$/, "").trimEnd();
|
|
67
|
+
if (!line) continue;
|
|
68
|
+
|
|
69
|
+
const indent = line.search(/\S/);
|
|
70
|
+
const isArrayItem = line.trimStart().startsWith("- ");
|
|
71
|
+
|
|
72
|
+
if (indent === 0) {
|
|
73
|
+
const colonIdx = line.indexOf(":");
|
|
74
|
+
if (colonIdx <= 0) continue;
|
|
75
|
+
const key = line.slice(0, colonIdx).trim();
|
|
76
|
+
const val = line.slice(colonIdx + 1).trim();
|
|
77
|
+
if (val === "" || val === "|" || val === ">") {
|
|
78
|
+
currentSection = key;
|
|
79
|
+
sectionIndent = 0;
|
|
80
|
+
result[key] = {};
|
|
81
|
+
} else {
|
|
82
|
+
result[key] = val.replace(/^["']|["']$/g, "");
|
|
83
|
+
currentSection = null;
|
|
84
|
+
}
|
|
85
|
+
} else if (indent > sectionIndent && currentSection && typeof result[currentSection] === "object") {
|
|
86
|
+
const colonIdx = line.indexOf(":");
|
|
87
|
+
if (colonIdx <= 0) continue;
|
|
88
|
+
const key = line.trimStart().slice(0, colonIdx - indent).trim();
|
|
89
|
+
const val = line.slice(colonIdx + 1).trim();
|
|
90
|
+
if (isArrayItem) {
|
|
91
|
+
if (!Array.isArray(result[currentSection][key])) {
|
|
92
|
+
result[currentSection][key] = [];
|
|
93
|
+
}
|
|
94
|
+
if (val) result[currentSection][key].push(val.replace(/^["']|["']$/g, ""));
|
|
95
|
+
} else if (val === "" || val === "|" || val === ">") {
|
|
96
|
+
result[currentSection][key] = {};
|
|
97
|
+
} else {
|
|
98
|
+
result[currentSection][key] = val.replace(/^["']|["']$/g, "");
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return result;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Serialize to YAML
|
|
106
|
+
function toYaml(obj, indent = 0) {
|
|
107
|
+
const sp = " ".repeat(indent);
|
|
108
|
+
let out = "";
|
|
109
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
110
|
+
if (v === null || v === undefined) continue;
|
|
111
|
+
if (typeof v === "object" && !Array.isArray(v)) {
|
|
112
|
+
out += `${sp}${k}:\n${toYaml(v, indent + 1)}`;
|
|
113
|
+
} else if (Array.isArray(v)) {
|
|
114
|
+
out += `${sp}${k}:\n`;
|
|
115
|
+
for (const item of v) {
|
|
116
|
+
if (typeof item === "object") {
|
|
117
|
+
const inner = toYaml(item, indent + 2);
|
|
118
|
+
out += `${sp} -\n${inner}`;
|
|
119
|
+
} else {
|
|
120
|
+
out += `${sp} - ${item}\n`;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
} else {
|
|
124
|
+
out += `${sp}${k}: ${v}\n`;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return out;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function main() {
|
|
131
|
+
console.log("[MycoHive-Claw] postinstall running...");
|
|
132
|
+
|
|
133
|
+
const packageDir = path.resolve(__dirname, "..");
|
|
134
|
+
const distIndex = path.join(packageDir, "dist", "index.js");
|
|
135
|
+
|
|
136
|
+
if (!fs.existsSync(distIndex)) {
|
|
137
|
+
console.warn("[MycoHive-Claw] dist/index.js not found, skipping");
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Find config
|
|
142
|
+
let configPath = findViaCLI() || findOpenClawConfig();
|
|
143
|
+
|
|
144
|
+
if (!configPath) {
|
|
145
|
+
// Create default config
|
|
146
|
+
console.log("[MycoHive-Claw] Creating default config...");
|
|
147
|
+
const openclawDir = path.join(process.env.HOME || ".", ".openclaw");
|
|
148
|
+
configPath = path.join(openclawDir, "config.yml");
|
|
149
|
+
try {
|
|
150
|
+
fs.mkdirSync(openclawDir, { recursive: true });
|
|
151
|
+
const defaultConfig = {
|
|
152
|
+
plugins: {
|
|
153
|
+
entries: {},
|
|
154
|
+
allow: ["restart"],
|
|
155
|
+
},
|
|
156
|
+
};
|
|
157
|
+
defaultConfig.plugins.entries.mycohive = { path: packageDir, enabled: true };
|
|
158
|
+
fs.writeFileSync(configPath, toYaml(defaultConfig), "utf-8");
|
|
159
|
+
console.log(`[MycoHive-Claw] Created: ${configPath}`);
|
|
160
|
+
} catch (err) {
|
|
161
|
+
console.error(`[MycoHive-Claw] Create failed: ${err.message}`);
|
|
162
|
+
}
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Read and update existing config
|
|
167
|
+
try {
|
|
168
|
+
const raw = fs.readFileSync(configPath, "utf-8");
|
|
169
|
+
const config = parseYaml(raw);
|
|
170
|
+
|
|
171
|
+
// Init plugins section
|
|
172
|
+
if (!config.plugins) config.plugins = {};
|
|
173
|
+
if (!config.plugins.entries) config.plugins.entries = {};
|
|
174
|
+
if (!config.plugins.allow) config.plugins.allow = [];
|
|
175
|
+
|
|
176
|
+
// Register plugin
|
|
177
|
+
config.plugins.entries.mycohive = { path: packageDir, enabled: true };
|
|
178
|
+
|
|
179
|
+
// Add "restart" to allow list so openclaw restart works
|
|
180
|
+
if (!config.plugins.allow.includes("restart")) {
|
|
181
|
+
config.plugins.allow.push("restart");
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
fs.writeFileSync(configPath, toYaml(config), "utf-8");
|
|
185
|
+
console.log(`[MycoHive-Claw] Registered in: ${configPath}`);
|
|
186
|
+
console.log("[MycoHive-Claw] Run 'openclaw restart' to load the plugin");
|
|
187
|
+
} catch (err) {
|
|
188
|
+
console.error(`[MycoHive-Claw] Update failed: ${err.message}`);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
main();
|
package/scripts/postinstall.js
DELETED
|
@@ -1,235 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* postinstall.js
|
|
3
|
-
* 版本: v4.0.0
|
|
4
|
-
*
|
|
5
|
-
* npm install 后自动执行:检测 OpenClaw 配置并注册插件。
|
|
6
|
-
* 目标:实现安装后即用,无需手动配置。
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
const fs = require("fs");
|
|
10
|
-
const path = require("path");
|
|
11
|
-
|
|
12
|
-
// 尝试找到 OpenClaw 配置目录
|
|
13
|
-
function findOpenClawConfig() {
|
|
14
|
-
const possiblePaths = [
|
|
15
|
-
// Linux/macOS 全局
|
|
16
|
-
path.join(process.env.HOME || "", ".openclaw", "config.yml"),
|
|
17
|
-
path.join(process.env.HOME || "", ".openclaw", "config.yaml"),
|
|
18
|
-
path.join(process.env.HOME || "", ".config", "openclaw", "config.yml"),
|
|
19
|
-
path.join(process.env.HOME || "", ".config", "openclaw", "config.yaml"),
|
|
20
|
-
// Windows
|
|
21
|
-
path.join(process.env.APPDATA || "", "openclaw", "config.yml"),
|
|
22
|
-
path.join(process.env.APPDATA || "", "openclaw", "config.yaml"),
|
|
23
|
-
path.join(process.env.USERPROFILE || "", ".openclaw", "config.yml"),
|
|
24
|
-
path.join(process.env.USERPROFILE || "", ".openclaw", "config.yaml"),
|
|
25
|
-
// 容器/服务端
|
|
26
|
-
"/etc/openclaw/config.yml",
|
|
27
|
-
"/etc/openclaw/config.yaml",
|
|
28
|
-
// 本地项目
|
|
29
|
-
".openclaw.yml",
|
|
30
|
-
".openclaw.yaml",
|
|
31
|
-
"openclaw.config.yml",
|
|
32
|
-
"openclaw.config.yaml",
|
|
33
|
-
];
|
|
34
|
-
|
|
35
|
-
for (const p of possiblePaths) {
|
|
36
|
-
if (fs.existsSync(p)) {
|
|
37
|
-
return p;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
return null;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// 尝试通过 openclaw CLI 查找配置路径
|
|
44
|
-
function findOpenClawConfigViaCLI() {
|
|
45
|
-
try {
|
|
46
|
-
const { execSync } = require("child_process");
|
|
47
|
-
// 尝试获取 openclaw 配置路径
|
|
48
|
-
const out = execSync("openclaw config 2>/dev/null || openclaw info 2>/dev/null || echo NOT_FOUND", {
|
|
49
|
-
encoding: "utf-8",
|
|
50
|
-
timeout: 5000,
|
|
51
|
-
});
|
|
52
|
-
const lines = out.split("\n");
|
|
53
|
-
for (const line of lines) {
|
|
54
|
-
if (line.includes("config") || line.includes("Config") || line.includes(".yml") || line.includes(".yaml")) {
|
|
55
|
-
const match = line.match(/[\/\\]?[\w\-\\/.]+\.ya?ml/);
|
|
56
|
-
if (match && fs.existsSync(match[0])) {
|
|
57
|
-
return match[0];
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
} catch {
|
|
62
|
-
// CLI 不可用或超时,忽略
|
|
63
|
-
}
|
|
64
|
-
return null;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// 解析 YAML(简化版,不依赖外部库)
|
|
68
|
-
function parseYaml(content) {
|
|
69
|
-
const result = {};
|
|
70
|
-
const lines = content.split("\n");
|
|
71
|
-
let currentKey = null;
|
|
72
|
-
let indent = 0;
|
|
73
|
-
|
|
74
|
-
for (let line of lines) {
|
|
75
|
-
// 移除行尾注释
|
|
76
|
-
line = line.replace(/\s*#.*$/, "").trimRight();
|
|
77
|
-
if (!line || line.startsWith("#")) continue;
|
|
78
|
-
|
|
79
|
-
const lineIndent = line.search(/\S/);
|
|
80
|
-
const isArrayItem = line.trimStart().startsWith("- ");
|
|
81
|
-
|
|
82
|
-
if (lineIndent === 0) {
|
|
83
|
-
const colonIdx = line.indexOf(":");
|
|
84
|
-
if (colonIdx > 0) {
|
|
85
|
-
const key = line.slice(0, colonIdx).trim();
|
|
86
|
-
const value = line.slice(colonIdx + 1).trim();
|
|
87
|
-
if (value === "" || value === "|" || value === ">") {
|
|
88
|
-
currentKey = key;
|
|
89
|
-
indent = lineIndent;
|
|
90
|
-
if (!result[key]) result[key] = {};
|
|
91
|
-
} else {
|
|
92
|
-
result[key] = value.replace(/^["']|["']$/g, "");
|
|
93
|
-
currentKey = null;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
} else if (lineIndent > indent && currentKey && typeof result[currentKey] === "object") {
|
|
97
|
-
const colonIdx = line.indexOf(":");
|
|
98
|
-
if (colonIdx > 0) {
|
|
99
|
-
const key = line.slice(lineIndent).slice(0, colonIdx - lineIndent).trim();
|
|
100
|
-
const value = line.slice(colonIdx + 1).trim();
|
|
101
|
-
if (value === "" || value === "|" || value === ">") {
|
|
102
|
-
result[currentKey][key] = {};
|
|
103
|
-
} else {
|
|
104
|
-
result[currentKey][key] = value.replace(/^["']|["']$/g, "");
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
return result;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// 序列化回 YAML
|
|
113
|
-
function toYaml(obj, indent = 0) {
|
|
114
|
-
const spaces = " ".repeat(indent);
|
|
115
|
-
let out = "";
|
|
116
|
-
|
|
117
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
118
|
-
if (value === null || value === undefined) continue;
|
|
119
|
-
|
|
120
|
-
if (typeof value === "object" && !Array.isArray(value)) {
|
|
121
|
-
out += `${spaces}${key}:\n${toYaml(value, indent + 1)}`;
|
|
122
|
-
} else if (Array.isArray(value)) {
|
|
123
|
-
out += `${spaces}${key}:\n`;
|
|
124
|
-
for (const item of value) {
|
|
125
|
-
if (typeof item === "object") {
|
|
126
|
-
out += `${spaces} -\n${toYaml(item, indent + 2)}`;
|
|
127
|
-
} else {
|
|
128
|
-
out += `${spaces} - ${item}\n`;
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
} else {
|
|
132
|
-
out += `${spaces}${key}: ${value}\n`;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
return out;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// 在配置对象中插入插件配置
|
|
139
|
-
function injectPluginConfig(config, pluginPath) {
|
|
140
|
-
const pluginName = "mycohive";
|
|
141
|
-
|
|
142
|
-
// 确保 plugins 存在
|
|
143
|
-
if (!config.plugins) config.plugins = {};
|
|
144
|
-
if (!config.plugins.entries) config.plugins.entries = {};
|
|
145
|
-
|
|
146
|
-
// 注入插件配置
|
|
147
|
-
config.plugins.entries[pluginName] = {
|
|
148
|
-
path: pluginPath,
|
|
149
|
-
enabled: true,
|
|
150
|
-
};
|
|
151
|
-
|
|
152
|
-
// 确保 plugins.allow 包含必要权限
|
|
153
|
-
if (!config.plugins.allow) {
|
|
154
|
-
config.plugins.allow = [];
|
|
155
|
-
}
|
|
156
|
-
const requiredAllows = ["restart"];
|
|
157
|
-
for (const perm of requiredAllows) {
|
|
158
|
-
if (!config.plugins.allow.includes(perm)) {
|
|
159
|
-
config.plugins.allow.push(perm);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
return config;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
// 写入配置文件
|
|
167
|
-
function writeConfig(configPath, config) {
|
|
168
|
-
const yaml = toYaml(config);
|
|
169
|
-
fs.writeFileSync(configPath, yaml, "utf-8");
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
async function main() {
|
|
173
|
-
console.log("[MycoHive-Claw] Running postinstall...");
|
|
174
|
-
|
|
175
|
-
// 找到当前包的位置
|
|
176
|
-
const packageDir = path.resolve(__dirname, "..");
|
|
177
|
-
const distIndex = path.join(packageDir, "dist", "index.js");
|
|
178
|
-
|
|
179
|
-
if (!fs.existsSync(distIndex)) {
|
|
180
|
-
console.warn("[MycoHive-Claw] dist/index.js not found, skipping auto-config (run npm build first)");
|
|
181
|
-
return;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// 1. 查找 OpenClaw 配置
|
|
185
|
-
let configPath = findOpenClawConfigViaCLI() || findOpenClawConfig();
|
|
186
|
-
|
|
187
|
-
if (!configPath) {
|
|
188
|
-
console.log("[MycoHive-Claw] OpenClaw config not found, creating default config...");
|
|
189
|
-
|
|
190
|
-
// 创建默认配置目录和文件
|
|
191
|
-
const openclawDir = path.join(process.env.HOME || process.env.USERPROFILE || ".", ".openclaw");
|
|
192
|
-
configPath = path.join(openclawDir, "config.yml");
|
|
193
|
-
|
|
194
|
-
try {
|
|
195
|
-
if (!fs.existsSync(openclawDir)) {
|
|
196
|
-
fs.mkdirSync(openclawDir, { recursive: true });
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
const defaultConfig = {
|
|
200
|
-
plugins: {
|
|
201
|
-
entries: {},
|
|
202
|
-
allow: ["restart"],
|
|
203
|
-
},
|
|
204
|
-
};
|
|
205
|
-
injectPluginConfig(defaultConfig, packageDir);
|
|
206
|
-
writeConfig(configPath, defaultConfig);
|
|
207
|
-
console.log(`[MycoHive-Claw] Created default config at: ${configPath}`);
|
|
208
|
-
console.log("[MycoHive-Claw] Run 'openclaw restart' to load the plugin");
|
|
209
|
-
} catch (err) {
|
|
210
|
-
console.error("[MycoHive-Claw] Failed to create config:", err.message);
|
|
211
|
-
}
|
|
212
|
-
return;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
// 2. 读取现有配置
|
|
216
|
-
try {
|
|
217
|
-
const content = fs.readFileSync(configPath, "utf-8");
|
|
218
|
-
let config = parseYaml(content);
|
|
219
|
-
|
|
220
|
-
if (Object.keys(config).length === 0) {
|
|
221
|
-
// 解析失败,使用空配置
|
|
222
|
-
config = { plugins: { entries: {}, allow: [] } };
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
injectPluginConfig(config, packageDir);
|
|
226
|
-
writeConfig(configPath, config);
|
|
227
|
-
|
|
228
|
-
console.log(`[MycoHive-Claw] Plugin registered in: ${configPath}`);
|
|
229
|
-
console.log("[MycoHive-Claw] Run 'openclaw restart' to load the plugin, or it will auto-load on next start");
|
|
230
|
-
} catch (err) {
|
|
231
|
-
console.error("[MycoHive-Claw] Failed to update config:", err.message);
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
main().catch(console.error);
|