harness-evolver 0.6.0 → 0.7.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/bin/install.js +64 -71
- package/package.json +1 -1
package/bin/install.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
3
|
* Harness Evolver installer.
|
|
4
|
-
* Copies
|
|
4
|
+
* Copies skills/agents/tools directly to runtime directories (GSD pattern).
|
|
5
5
|
*
|
|
6
6
|
* Usage: npx harness-evolver@latest
|
|
7
7
|
*/
|
|
@@ -49,7 +49,6 @@ function copyDir(src, dest) {
|
|
|
49
49
|
const srcPath = path.join(src, entry.name);
|
|
50
50
|
const destPath = path.join(dest, entry.name);
|
|
51
51
|
if (entry.isDirectory()) {
|
|
52
|
-
if (entry.name === "node_modules" || entry.name === ".git" || entry.name === "__pycache__" || entry.name === "tests" || entry.name === "docs") continue;
|
|
53
52
|
copyDir(srcPath, destPath);
|
|
54
53
|
} else {
|
|
55
54
|
fs.copyFileSync(srcPath, destPath);
|
|
@@ -57,6 +56,11 @@ function copyDir(src, dest) {
|
|
|
57
56
|
}
|
|
58
57
|
}
|
|
59
58
|
|
|
59
|
+
function copyFile(src, dest) {
|
|
60
|
+
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
61
|
+
fs.copyFileSync(src, dest);
|
|
62
|
+
}
|
|
63
|
+
|
|
60
64
|
function checkPython() {
|
|
61
65
|
try {
|
|
62
66
|
execSync("python3 --version", { stdio: "pipe" });
|
|
@@ -66,80 +70,52 @@ function checkPython() {
|
|
|
66
70
|
}
|
|
67
71
|
}
|
|
68
72
|
|
|
69
|
-
function
|
|
70
|
-
try {
|
|
71
|
-
return JSON.parse(fs.readFileSync(filepath, "utf8"));
|
|
72
|
-
} catch {
|
|
73
|
-
return null;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
function writeJSON(filepath, data) {
|
|
78
|
-
fs.mkdirSync(path.dirname(filepath), { recursive: true });
|
|
79
|
-
fs.writeFileSync(filepath, JSON.stringify(data, null, 2) + "\n");
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
function installPlugin(runtimeDir, scope) {
|
|
73
|
+
function installForRuntime(runtimeDir, scope) {
|
|
83
74
|
const baseDir = scope === "local"
|
|
84
75
|
? path.join(process.cwd(), runtimeDir)
|
|
85
76
|
: path.join(HOME, runtimeDir);
|
|
86
77
|
|
|
87
|
-
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
// Count installed items
|
|
117
|
-
const skillCount = fs.existsSync(path.join(cacheDir, "skills"))
|
|
118
|
-
? fs.readdirSync(path.join(cacheDir, "skills")).filter(f =>
|
|
119
|
-
fs.statSync(path.join(cacheDir, "skills", f)).isDirectory()
|
|
120
|
-
).length
|
|
121
|
-
: 0;
|
|
122
|
-
const agentCount = fs.existsSync(path.join(cacheDir, "agents"))
|
|
123
|
-
? fs.readdirSync(path.join(cacheDir, "agents")).length
|
|
124
|
-
: 0;
|
|
125
|
-
const toolCount = fs.existsSync(path.join(cacheDir, "tools"))
|
|
126
|
-
? fs.readdirSync(path.join(cacheDir, "tools")).filter(f => f.endsWith(".py")).length
|
|
127
|
-
: 0;
|
|
128
|
-
|
|
129
|
-
console.log(` ${GREEN}✓${RESET} ${skillCount} skills, ${agentCount} agent, ${toolCount} tools`);
|
|
78
|
+
const commandsDir = path.join(baseDir, "commands", "harness-evolver");
|
|
79
|
+
const agentsDir = path.join(baseDir, "agents");
|
|
80
|
+
|
|
81
|
+
// Skills → commands/harness-evolver/ as flat .md files
|
|
82
|
+
// Claude Code expects commands/name.md, not commands/name/SKILL.md
|
|
83
|
+
const skillsSource = path.join(PLUGIN_ROOT, "skills");
|
|
84
|
+
if (fs.existsSync(skillsSource)) {
|
|
85
|
+
fs.mkdirSync(commandsDir, { recursive: true });
|
|
86
|
+
for (const skill of fs.readdirSync(skillsSource, { withFileTypes: true })) {
|
|
87
|
+
if (skill.isDirectory()) {
|
|
88
|
+
const skillMd = path.join(skillsSource, skill.name, "SKILL.md");
|
|
89
|
+
if (fs.existsSync(skillMd)) {
|
|
90
|
+
fs.copyFileSync(skillMd, path.join(commandsDir, skill.name + ".md"));
|
|
91
|
+
console.log(` ${GREEN}✓${RESET} Installed command: harness-evolver:${skill.name}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Agents → agents/
|
|
98
|
+
const agentsSource = path.join(PLUGIN_ROOT, "agents");
|
|
99
|
+
if (fs.existsSync(agentsSource)) {
|
|
100
|
+
fs.mkdirSync(agentsDir, { recursive: true });
|
|
101
|
+
for (const agent of fs.readdirSync(agentsSource)) {
|
|
102
|
+
copyFile(path.join(agentsSource, agent), path.join(agentsDir, agent));
|
|
103
|
+
console.log(` ${GREEN}✓${RESET} Installed agent: ${agent}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
130
106
|
}
|
|
131
107
|
|
|
132
|
-
function
|
|
108
|
+
function installTools() {
|
|
133
109
|
const toolsDir = path.join(HOME, ".harness-evolver", "tools");
|
|
134
110
|
const toolsSource = path.join(PLUGIN_ROOT, "tools");
|
|
135
111
|
if (fs.existsSync(toolsSource)) {
|
|
136
112
|
fs.mkdirSync(toolsDir, { recursive: true });
|
|
137
113
|
for (const tool of fs.readdirSync(toolsSource)) {
|
|
138
114
|
if (tool.endsWith(".py")) {
|
|
139
|
-
|
|
115
|
+
copyFile(path.join(toolsSource, tool), path.join(toolsDir, tool));
|
|
140
116
|
}
|
|
141
117
|
}
|
|
142
|
-
console.log(` ${GREEN}✓${RESET}
|
|
118
|
+
console.log(` ${GREEN}✓${RESET} Installed tools to ~/.harness-evolver/tools/`);
|
|
143
119
|
}
|
|
144
120
|
}
|
|
145
121
|
|
|
@@ -148,10 +124,31 @@ function installExamples() {
|
|
|
148
124
|
const examplesSource = path.join(PLUGIN_ROOT, "examples");
|
|
149
125
|
if (fs.existsSync(examplesSource)) {
|
|
150
126
|
copyDir(examplesSource, examplesDir);
|
|
151
|
-
console.log(` ${GREEN}✓${RESET}
|
|
127
|
+
console.log(` ${GREEN}✓${RESET} Installed examples to ~/.harness-evolver/examples/`);
|
|
152
128
|
}
|
|
153
129
|
}
|
|
154
130
|
|
|
131
|
+
function cleanupBrokenPluginEntry(runtimeDir) {
|
|
132
|
+
// Remove the harness-evolver@local entry that doesn't work
|
|
133
|
+
const installedPath = path.join(HOME, runtimeDir, "plugins", "installed_plugins.json");
|
|
134
|
+
try {
|
|
135
|
+
const data = JSON.parse(fs.readFileSync(installedPath, "utf8"));
|
|
136
|
+
if (data.plugins && data.plugins["harness-evolver@local"]) {
|
|
137
|
+
delete data.plugins["harness-evolver@local"];
|
|
138
|
+
fs.writeFileSync(installedPath, JSON.stringify(data, null, 2) + "\n");
|
|
139
|
+
}
|
|
140
|
+
} catch {}
|
|
141
|
+
|
|
142
|
+
const settingsPath = path.join(HOME, runtimeDir, "settings.json");
|
|
143
|
+
try {
|
|
144
|
+
const data = JSON.parse(fs.readFileSync(settingsPath, "utf8"));
|
|
145
|
+
if (data.enabledPlugins && data.enabledPlugins["harness-evolver@local"] !== undefined) {
|
|
146
|
+
delete data.enabledPlugins["harness-evolver@local"];
|
|
147
|
+
fs.writeFileSync(settingsPath, JSON.stringify(data, null, 2) + "\n");
|
|
148
|
+
}
|
|
149
|
+
} catch {}
|
|
150
|
+
}
|
|
151
|
+
|
|
155
152
|
async function main() {
|
|
156
153
|
console.log(LOGO);
|
|
157
154
|
console.log(` ${DIM}Harness Evolver v${VERSION}${RESET}`);
|
|
@@ -164,7 +161,6 @@ async function main() {
|
|
|
164
161
|
}
|
|
165
162
|
console.log(` ${GREEN}✓${RESET} python3 found`);
|
|
166
163
|
|
|
167
|
-
// Detect runtimes
|
|
168
164
|
const RUNTIMES = [
|
|
169
165
|
{ name: "Claude Code", dir: ".claude" },
|
|
170
166
|
{ name: "Cursor", dir: ".cursor" },
|
|
@@ -180,7 +176,6 @@ async function main() {
|
|
|
180
176
|
|
|
181
177
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
182
178
|
|
|
183
|
-
// Runtime selection
|
|
184
179
|
console.log(`\n ${YELLOW}Which runtime(s) would you like to install for?${RESET}\n`);
|
|
185
180
|
RUNTIMES.forEach((r, i) => console.log(` ${i + 1}) ${r.name.padEnd(14)} (~/${r.dir})`));
|
|
186
181
|
if (RUNTIMES.length > 1) {
|
|
@@ -200,7 +195,6 @@ async function main() {
|
|
|
200
195
|
}
|
|
201
196
|
if (selected.length === 0) selected = [RUNTIMES[0]];
|
|
202
197
|
|
|
203
|
-
// Scope selection
|
|
204
198
|
console.log(`\n ${YELLOW}Where would you like to install?${RESET}\n`);
|
|
205
199
|
console.log(` 1) Global (~/${selected[0].dir}) - available in all projects`);
|
|
206
200
|
console.log(` 2) Local (./${selected[0].dir}) - this project only`);
|
|
@@ -210,23 +204,22 @@ async function main() {
|
|
|
210
204
|
|
|
211
205
|
console.log();
|
|
212
206
|
|
|
213
|
-
// Install
|
|
214
207
|
for (const runtime of selected) {
|
|
215
208
|
console.log(` Installing for ${BRIGHT_MAGENTA}${runtime.name}${RESET}\n`);
|
|
216
|
-
|
|
209
|
+
cleanupBrokenPluginEntry(runtime.dir);
|
|
210
|
+
installForRuntime(runtime.dir, scope);
|
|
217
211
|
console.log();
|
|
218
212
|
}
|
|
219
213
|
|
|
220
|
-
|
|
214
|
+
installTools();
|
|
221
215
|
installExamples();
|
|
222
216
|
|
|
223
|
-
// Version marker
|
|
224
217
|
const versionPath = path.join(HOME, ".harness-evolver", "VERSION");
|
|
225
218
|
fs.mkdirSync(path.dirname(versionPath), { recursive: true });
|
|
226
219
|
fs.writeFileSync(versionPath, VERSION);
|
|
227
220
|
console.log(` ${GREEN}✓${RESET} VERSION ${VERSION}`);
|
|
228
221
|
|
|
229
|
-
console.log(`\n ${GREEN}Done!${RESET}
|
|
222
|
+
console.log(`\n ${GREEN}Done!${RESET} Run ${BRIGHT_MAGENTA}/reload-plugins${RESET} in Claude Code, then ${BRIGHT_MAGENTA}/harness-evolver:init${RESET}`);
|
|
230
223
|
console.log(`\n ${DIM}Quick start with example:${RESET}`);
|
|
231
224
|
console.log(` cp -r ~/.harness-evolver/examples/classifier ./my-project`);
|
|
232
225
|
console.log(` cd my-project && claude`);
|