harness-evolver 0.6.0 → 0.7.0
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 +59 -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,47 @@ 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
|
-
let settings = readJSON(settingsPath) || {};
|
|
111
|
-
if (!settings.enabledPlugins) settings.enabledPlugins = {};
|
|
112
|
-
settings.enabledPlugins["harness-evolver@local"] = true;
|
|
113
|
-
writeJSON(settingsPath, settings);
|
|
114
|
-
console.log(` ${GREEN}✓${RESET} Enabled in settings.json`);
|
|
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/
|
|
82
|
+
const skillsSource = path.join(PLUGIN_ROOT, "skills");
|
|
83
|
+
if (fs.existsSync(skillsSource)) {
|
|
84
|
+
for (const skill of fs.readdirSync(skillsSource, { withFileTypes: true })) {
|
|
85
|
+
if (skill.isDirectory()) {
|
|
86
|
+
copyDir(path.join(skillsSource, skill.name), path.join(commandsDir, skill.name));
|
|
87
|
+
console.log(` ${GREEN}✓${RESET} Installed command: harness-evolver:${skill.name}`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Agents → agents/
|
|
93
|
+
const agentsSource = path.join(PLUGIN_ROOT, "agents");
|
|
94
|
+
if (fs.existsSync(agentsSource)) {
|
|
95
|
+
fs.mkdirSync(agentsDir, { recursive: true });
|
|
96
|
+
for (const agent of fs.readdirSync(agentsSource)) {
|
|
97
|
+
copyFile(path.join(agentsSource, agent), path.join(agentsDir, agent));
|
|
98
|
+
console.log(` ${GREEN}✓${RESET} Installed agent: ${agent}`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
130
101
|
}
|
|
131
102
|
|
|
132
|
-
function
|
|
103
|
+
function installTools() {
|
|
133
104
|
const toolsDir = path.join(HOME, ".harness-evolver", "tools");
|
|
134
105
|
const toolsSource = path.join(PLUGIN_ROOT, "tools");
|
|
135
106
|
if (fs.existsSync(toolsSource)) {
|
|
136
107
|
fs.mkdirSync(toolsDir, { recursive: true });
|
|
137
108
|
for (const tool of fs.readdirSync(toolsSource)) {
|
|
138
109
|
if (tool.endsWith(".py")) {
|
|
139
|
-
|
|
110
|
+
copyFile(path.join(toolsSource, tool), path.join(toolsDir, tool));
|
|
140
111
|
}
|
|
141
112
|
}
|
|
142
|
-
console.log(` ${GREEN}✓${RESET}
|
|
113
|
+
console.log(` ${GREEN}✓${RESET} Installed tools to ~/.harness-evolver/tools/`);
|
|
143
114
|
}
|
|
144
115
|
}
|
|
145
116
|
|
|
@@ -148,10 +119,31 @@ function installExamples() {
|
|
|
148
119
|
const examplesSource = path.join(PLUGIN_ROOT, "examples");
|
|
149
120
|
if (fs.existsSync(examplesSource)) {
|
|
150
121
|
copyDir(examplesSource, examplesDir);
|
|
151
|
-
console.log(` ${GREEN}✓${RESET}
|
|
122
|
+
console.log(` ${GREEN}✓${RESET} Installed examples to ~/.harness-evolver/examples/`);
|
|
152
123
|
}
|
|
153
124
|
}
|
|
154
125
|
|
|
126
|
+
function cleanupBrokenPluginEntry(runtimeDir) {
|
|
127
|
+
// Remove the harness-evolver@local entry that doesn't work
|
|
128
|
+
const installedPath = path.join(HOME, runtimeDir, "plugins", "installed_plugins.json");
|
|
129
|
+
try {
|
|
130
|
+
const data = JSON.parse(fs.readFileSync(installedPath, "utf8"));
|
|
131
|
+
if (data.plugins && data.plugins["harness-evolver@local"]) {
|
|
132
|
+
delete data.plugins["harness-evolver@local"];
|
|
133
|
+
fs.writeFileSync(installedPath, JSON.stringify(data, null, 2) + "\n");
|
|
134
|
+
}
|
|
135
|
+
} catch {}
|
|
136
|
+
|
|
137
|
+
const settingsPath = path.join(HOME, runtimeDir, "settings.json");
|
|
138
|
+
try {
|
|
139
|
+
const data = JSON.parse(fs.readFileSync(settingsPath, "utf8"));
|
|
140
|
+
if (data.enabledPlugins && data.enabledPlugins["harness-evolver@local"] !== undefined) {
|
|
141
|
+
delete data.enabledPlugins["harness-evolver@local"];
|
|
142
|
+
fs.writeFileSync(settingsPath, JSON.stringify(data, null, 2) + "\n");
|
|
143
|
+
}
|
|
144
|
+
} catch {}
|
|
145
|
+
}
|
|
146
|
+
|
|
155
147
|
async function main() {
|
|
156
148
|
console.log(LOGO);
|
|
157
149
|
console.log(` ${DIM}Harness Evolver v${VERSION}${RESET}`);
|
|
@@ -164,7 +156,6 @@ async function main() {
|
|
|
164
156
|
}
|
|
165
157
|
console.log(` ${GREEN}✓${RESET} python3 found`);
|
|
166
158
|
|
|
167
|
-
// Detect runtimes
|
|
168
159
|
const RUNTIMES = [
|
|
169
160
|
{ name: "Claude Code", dir: ".claude" },
|
|
170
161
|
{ name: "Cursor", dir: ".cursor" },
|
|
@@ -180,7 +171,6 @@ async function main() {
|
|
|
180
171
|
|
|
181
172
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
182
173
|
|
|
183
|
-
// Runtime selection
|
|
184
174
|
console.log(`\n ${YELLOW}Which runtime(s) would you like to install for?${RESET}\n`);
|
|
185
175
|
RUNTIMES.forEach((r, i) => console.log(` ${i + 1}) ${r.name.padEnd(14)} (~/${r.dir})`));
|
|
186
176
|
if (RUNTIMES.length > 1) {
|
|
@@ -200,7 +190,6 @@ async function main() {
|
|
|
200
190
|
}
|
|
201
191
|
if (selected.length === 0) selected = [RUNTIMES[0]];
|
|
202
192
|
|
|
203
|
-
// Scope selection
|
|
204
193
|
console.log(`\n ${YELLOW}Where would you like to install?${RESET}\n`);
|
|
205
194
|
console.log(` 1) Global (~/${selected[0].dir}) - available in all projects`);
|
|
206
195
|
console.log(` 2) Local (./${selected[0].dir}) - this project only`);
|
|
@@ -210,23 +199,22 @@ async function main() {
|
|
|
210
199
|
|
|
211
200
|
console.log();
|
|
212
201
|
|
|
213
|
-
// Install
|
|
214
202
|
for (const runtime of selected) {
|
|
215
203
|
console.log(` Installing for ${BRIGHT_MAGENTA}${runtime.name}${RESET}\n`);
|
|
216
|
-
|
|
204
|
+
cleanupBrokenPluginEntry(runtime.dir);
|
|
205
|
+
installForRuntime(runtime.dir, scope);
|
|
217
206
|
console.log();
|
|
218
207
|
}
|
|
219
208
|
|
|
220
|
-
|
|
209
|
+
installTools();
|
|
221
210
|
installExamples();
|
|
222
211
|
|
|
223
|
-
// Version marker
|
|
224
212
|
const versionPath = path.join(HOME, ".harness-evolver", "VERSION");
|
|
225
213
|
fs.mkdirSync(path.dirname(versionPath), { recursive: true });
|
|
226
214
|
fs.writeFileSync(versionPath, VERSION);
|
|
227
215
|
console.log(` ${GREEN}✓${RESET} VERSION ${VERSION}`);
|
|
228
216
|
|
|
229
|
-
console.log(`\n ${GREEN}Done!${RESET}
|
|
217
|
+
console.log(`\n ${GREEN}Done!${RESET} Run ${BRIGHT_MAGENTA}/reload-plugins${RESET} in Claude Code, then ${BRIGHT_MAGENTA}/harness-evolver:init${RESET}`);
|
|
230
218
|
console.log(`\n ${DIM}Quick start with example:${RESET}`);
|
|
231
219
|
console.log(` cp -r ~/.harness-evolver/examples/classifier ./my-project`);
|
|
232
220
|
console.log(` cd my-project && claude`);
|