@esoteric-logic/praxis-harness 2.0.2 → 2.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/bin/praxis.js +94 -45
- package/package.json +1 -1
package/bin/praxis.js
CHANGED
|
@@ -37,7 +37,7 @@ async function install() {
|
|
|
37
37
|
header('Praxis Harness v' + VERSION);
|
|
38
38
|
|
|
39
39
|
// Ensure ~/.claude/ structure
|
|
40
|
-
for (const sub of ['rules', '
|
|
40
|
+
for (const sub of ['rules', 'skills', 'hooks']) {
|
|
41
41
|
fs.mkdirSync(path.join(CLAUDE_DIR, sub), { recursive: true });
|
|
42
42
|
}
|
|
43
43
|
|
|
@@ -59,17 +59,6 @@ async function install() {
|
|
|
59
59
|
ok(count + ' rules installed');
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
// Copy base/commands/* → ~/.claude/commands/
|
|
63
|
-
const cmdsDir = path.join(PKG_DIR, 'base', 'commands');
|
|
64
|
-
if (fs.existsSync(cmdsDir)) {
|
|
65
|
-
let count = 0;
|
|
66
|
-
for (const f of fs.readdirSync(cmdsDir)) {
|
|
67
|
-
copyFile(path.join(cmdsDir, f), path.join(CLAUDE_DIR, 'commands', f));
|
|
68
|
-
count++;
|
|
69
|
-
}
|
|
70
|
-
ok(count + ' commands installed');
|
|
71
|
-
}
|
|
72
|
-
|
|
73
62
|
// Copy base/skills/* → ~/.claude/skills/
|
|
74
63
|
const skillsDir = path.join(PKG_DIR, 'base', 'skills');
|
|
75
64
|
if (fs.existsSync(skillsDir)) {
|
|
@@ -87,6 +76,35 @@ async function install() {
|
|
|
87
76
|
ok(count + ' skills installed');
|
|
88
77
|
}
|
|
89
78
|
|
|
79
|
+
// Copy base/hooks/*.sh → ~/.claude/hooks/
|
|
80
|
+
const hooksDir = path.join(PKG_DIR, 'base', 'hooks');
|
|
81
|
+
if (fs.existsSync(hooksDir)) {
|
|
82
|
+
let count = 0;
|
|
83
|
+
for (const f of fs.readdirSync(hooksDir)) {
|
|
84
|
+
if (f.endsWith('.sh')) {
|
|
85
|
+
copyFile(path.join(hooksDir, f), path.join(CLAUDE_DIR, 'hooks', f));
|
|
86
|
+
// Make executable
|
|
87
|
+
fs.chmodSync(path.join(CLAUDE_DIR, 'hooks', f), 0o755);
|
|
88
|
+
count++;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
ok(count + ' hooks installed');
|
|
92
|
+
|
|
93
|
+
// Merge hooks configuration into settings.json
|
|
94
|
+
const hooksConfig = path.join(hooksDir, 'settings-hooks.json');
|
|
95
|
+
const settingsFile = path.join(CLAUDE_DIR, 'settings.json');
|
|
96
|
+
if (fs.existsSync(hooksConfig)) {
|
|
97
|
+
const hooksCfg = JSON.parse(fs.readFileSync(hooksConfig, 'utf8'));
|
|
98
|
+
let settings = {};
|
|
99
|
+
if (fs.existsSync(settingsFile)) {
|
|
100
|
+
try { settings = JSON.parse(fs.readFileSync(settingsFile, 'utf8')); } catch {}
|
|
101
|
+
}
|
|
102
|
+
Object.assign(settings, hooksCfg);
|
|
103
|
+
fs.writeFileSync(settingsFile, JSON.stringify(settings, null, 2) + '\n');
|
|
104
|
+
ok('hooks configuration merged into settings.json');
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
90
108
|
// Copy kits/ → ~/.claude/kits/
|
|
91
109
|
const kitsDir = path.join(PKG_DIR, 'kits');
|
|
92
110
|
if (fs.existsSync(kitsDir)) {
|
|
@@ -94,11 +112,29 @@ async function install() {
|
|
|
94
112
|
ok('kits installed');
|
|
95
113
|
}
|
|
96
114
|
|
|
97
|
-
// Orphan cleanup:
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
115
|
+
// Orphan cleanup: deleted rules and legacy files
|
|
116
|
+
const orphans = [
|
|
117
|
+
'obsidian.md', 'code-quality.md', 'security.md',
|
|
118
|
+
'communication.md', 'architecture.md'
|
|
119
|
+
];
|
|
120
|
+
for (const f of orphans) {
|
|
121
|
+
const target = path.join(CLAUDE_DIR, 'rules', f);
|
|
122
|
+
if (fs.existsSync(target)) {
|
|
123
|
+
fs.unlinkSync(target);
|
|
124
|
+
dim('removed legacy ' + f);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Orphan cleanup: old commands directory (v1.x)
|
|
129
|
+
const oldCmdsDir = path.join(CLAUDE_DIR, 'commands');
|
|
130
|
+
if (fs.existsSync(oldCmdsDir)) {
|
|
131
|
+
const files = fs.readdirSync(oldCmdsDir);
|
|
132
|
+
if (files.length > 0) {
|
|
133
|
+
for (const f of files) {
|
|
134
|
+
fs.unlinkSync(path.join(oldCmdsDir, f));
|
|
135
|
+
}
|
|
136
|
+
dim('cleaned up ' + files.length + ' legacy command files');
|
|
137
|
+
}
|
|
102
138
|
}
|
|
103
139
|
|
|
104
140
|
// Vault configuration
|
|
@@ -115,7 +151,7 @@ async function install() {
|
|
|
115
151
|
}
|
|
116
152
|
|
|
117
153
|
const config = {
|
|
118
|
-
version:
|
|
154
|
+
version: VERSION,
|
|
119
155
|
vault_path: vaultPath || '',
|
|
120
156
|
vault_backend: 'obsidian',
|
|
121
157
|
repo_path: PKG_DIR
|
|
@@ -140,7 +176,7 @@ async function install() {
|
|
|
140
176
|
// Summary
|
|
141
177
|
header('Install complete');
|
|
142
178
|
console.log(' Files copied to ' + CLAUDE_DIR);
|
|
143
|
-
console.log(' Run: npx praxis-harness health');
|
|
179
|
+
console.log(' Run: npx @esoteric-logic/praxis-harness health');
|
|
144
180
|
console.log('');
|
|
145
181
|
}
|
|
146
182
|
|
|
@@ -177,15 +213,6 @@ function health() {
|
|
|
177
213
|
}
|
|
178
214
|
}
|
|
179
215
|
|
|
180
|
-
// Commands
|
|
181
|
-
console.log('\nCommands:');
|
|
182
|
-
const cmdsDir = path.join(PKG_DIR, 'base', 'commands');
|
|
183
|
-
if (fs.existsSync(cmdsDir)) {
|
|
184
|
-
for (const f of fs.readdirSync(cmdsDir)) {
|
|
185
|
-
check(fs.existsSync(path.join(CLAUDE_DIR, 'commands', f)), 'commands/' + f + ' installed');
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
216
|
// Skills
|
|
190
217
|
console.log('\nSkills:');
|
|
191
218
|
const skillsDir = path.join(PKG_DIR, 'base', 'skills');
|
|
@@ -195,6 +222,18 @@ function health() {
|
|
|
195
222
|
}
|
|
196
223
|
}
|
|
197
224
|
|
|
225
|
+
// Hooks
|
|
226
|
+
console.log('\nHooks:');
|
|
227
|
+
const hooksDir = path.join(PKG_DIR, 'base', 'hooks');
|
|
228
|
+
if (fs.existsSync(hooksDir)) {
|
|
229
|
+
for (const f of fs.readdirSync(hooksDir)) {
|
|
230
|
+
if (f.endsWith('.sh')) {
|
|
231
|
+
check(fs.existsSync(path.join(CLAUDE_DIR, 'hooks', f)), 'hooks/' + f + ' installed');
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
check(fs.existsSync(path.join(CLAUDE_DIR, 'settings.json')), 'settings.json with hooks configured');
|
|
236
|
+
|
|
198
237
|
// Kits
|
|
199
238
|
console.log('\nKits:');
|
|
200
239
|
check(fs.existsSync(path.join(CLAUDE_DIR, 'kits')), 'kits directory installed');
|
|
@@ -236,34 +275,26 @@ function health() {
|
|
|
236
275
|
function uninstall() {
|
|
237
276
|
header('Uninstalling Praxis Harness');
|
|
238
277
|
|
|
239
|
-
// Remove
|
|
278
|
+
// Remove CLAUDE.md
|
|
240
279
|
const claudeMd = path.join(CLAUDE_DIR, 'CLAUDE.md');
|
|
241
280
|
if (fs.existsSync(claudeMd)) { fs.unlinkSync(claudeMd); ok('CLAUDE.md removed'); }
|
|
242
281
|
|
|
243
|
-
// Remove rules
|
|
282
|
+
// Remove rules
|
|
244
283
|
const rulesDir = path.join(PKG_DIR, 'base', 'rules');
|
|
245
284
|
if (fs.existsSync(rulesDir)) {
|
|
246
285
|
for (const f of fs.readdirSync(rulesDir)) {
|
|
247
286
|
const target = path.join(CLAUDE_DIR, 'rules', f);
|
|
248
287
|
if (fs.existsSync(target)) fs.unlinkSync(target);
|
|
249
288
|
}
|
|
250
|
-
// Also remove legacy
|
|
251
|
-
const
|
|
252
|
-
|
|
253
|
-
ok('rules removed');
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
// Remove commands from base/commands/
|
|
257
|
-
const cmdsDir = path.join(PKG_DIR, 'base', 'commands');
|
|
258
|
-
if (fs.existsSync(cmdsDir)) {
|
|
259
|
-
for (const f of fs.readdirSync(cmdsDir)) {
|
|
260
|
-
const target = path.join(CLAUDE_DIR, 'commands', f);
|
|
289
|
+
// Also remove legacy files
|
|
290
|
+
for (const f of ['obsidian.md', 'code-quality.md', 'security.md', 'communication.md', 'architecture.md']) {
|
|
291
|
+
const target = path.join(CLAUDE_DIR, 'rules', f);
|
|
261
292
|
if (fs.existsSync(target)) fs.unlinkSync(target);
|
|
262
293
|
}
|
|
263
|
-
ok('
|
|
294
|
+
ok('rules removed');
|
|
264
295
|
}
|
|
265
296
|
|
|
266
|
-
// Remove skills
|
|
297
|
+
// Remove skills
|
|
267
298
|
const skillsDir = path.join(PKG_DIR, 'base', 'skills');
|
|
268
299
|
if (fs.existsSync(skillsDir)) {
|
|
269
300
|
for (const entry of fs.readdirSync(skillsDir)) {
|
|
@@ -275,6 +306,17 @@ function uninstall() {
|
|
|
275
306
|
ok('skills removed');
|
|
276
307
|
}
|
|
277
308
|
|
|
309
|
+
// Remove hooks
|
|
310
|
+
const hooksDir = path.join(CLAUDE_DIR, 'hooks');
|
|
311
|
+
if (fs.existsSync(hooksDir)) {
|
|
312
|
+
for (const f of fs.readdirSync(hooksDir)) {
|
|
313
|
+
if (f.endsWith('.sh')) {
|
|
314
|
+
fs.unlinkSync(path.join(hooksDir, f));
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
ok('hooks removed');
|
|
318
|
+
}
|
|
319
|
+
|
|
278
320
|
// Remove kits
|
|
279
321
|
const kitsTarget = path.join(CLAUDE_DIR, 'kits');
|
|
280
322
|
if (fs.existsSync(kitsTarget)) {
|
|
@@ -282,6 +324,13 @@ function uninstall() {
|
|
|
282
324
|
ok('kits removed');
|
|
283
325
|
}
|
|
284
326
|
|
|
327
|
+
// Remove legacy commands directory
|
|
328
|
+
const oldCmdsDir = path.join(CLAUDE_DIR, 'commands');
|
|
329
|
+
if (fs.existsSync(oldCmdsDir)) {
|
|
330
|
+
fs.rmSync(oldCmdsDir, { recursive: true, force: true });
|
|
331
|
+
ok('legacy commands directory removed');
|
|
332
|
+
}
|
|
333
|
+
|
|
285
334
|
header('Uninstall complete');
|
|
286
335
|
dim('Config file preserved: ' + CONFIG_FILE);
|
|
287
336
|
dim('Run: rm ' + CONFIG_FILE + ' to remove config');
|
|
@@ -294,10 +343,10 @@ function printHelp() {
|
|
|
294
343
|
console.log(`
|
|
295
344
|
praxis-harness v${VERSION}
|
|
296
345
|
|
|
297
|
-
Usage: npx praxis-harness [command]
|
|
346
|
+
Usage: npx @esoteric-logic/praxis-harness [command]
|
|
298
347
|
|
|
299
348
|
Commands:
|
|
300
|
-
install Copy rules,
|
|
349
|
+
install Copy rules, skills, hooks, and kits to ~/.claude/ (default)
|
|
301
350
|
update Re-copy from latest npm package version
|
|
302
351
|
health Verify install integrity
|
|
303
352
|
uninstall Remove Praxis-owned files from ~/.claude/
|
package/package.json
CHANGED