@hopla/claude-setup 1.3.0 → 1.3.2
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/cli.js +80 -18
- package/package.json +1 -1
package/cli.js
CHANGED
|
@@ -140,6 +140,25 @@ const PLANNING_COMMANDS = [
|
|
|
140
140
|
"hopla-git-pr.md",
|
|
141
141
|
];
|
|
142
142
|
|
|
143
|
+
function removeExecutionCommands() {
|
|
144
|
+
const planningSet = new Set(PLANNING_COMMANDS);
|
|
145
|
+
const removed = [];
|
|
146
|
+
if (!fs.existsSync(COMMANDS_DIR)) return;
|
|
147
|
+
for (const file of fs.readdirSync(COMMANDS_DIR)) {
|
|
148
|
+
if (file.startsWith("hopla-") && !planningSet.has(file)) {
|
|
149
|
+
fs.rmSync(path.join(COMMANDS_DIR, file));
|
|
150
|
+
removed.push(file);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
if (removed.length > 0) {
|
|
154
|
+
log(`${CYAN}Removing execution commands (planning mode)...${RESET}`);
|
|
155
|
+
for (const file of removed) {
|
|
156
|
+
log(` ${RED}✕${RESET} Removed: ~/.claude/commands/${file}`);
|
|
157
|
+
}
|
|
158
|
+
log("");
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
143
162
|
async function install() {
|
|
144
163
|
const modeLabel = PLANNING ? "Planning Mode (Robert)" : "Full Install";
|
|
145
164
|
log(`\n${BOLD}@hopla/claude-setup${RESET} — Agentic Coding System ${CYAN}[${modeLabel}]${RESET}\n`);
|
|
@@ -151,6 +170,9 @@ async function install() {
|
|
|
151
170
|
// Remove old non-prefixed commands from previous versions
|
|
152
171
|
removeLegacyFiles();
|
|
153
172
|
|
|
173
|
+
// In planning mode, remove any execution commands left from a previous full install
|
|
174
|
+
if (PLANNING) removeExecutionCommands();
|
|
175
|
+
|
|
154
176
|
log(`${CYAN}Installing global rules...${RESET}`);
|
|
155
177
|
await installFile(
|
|
156
178
|
path.join(FILES_DIR, "CLAUDE.md"),
|
|
@@ -196,6 +218,14 @@ const HOPLA_PERMISSIONS = [
|
|
|
196
218
|
"Bash(echo *)",
|
|
197
219
|
];
|
|
198
220
|
|
|
221
|
+
const PLANNING_PERMISSIONS = [
|
|
222
|
+
"Bash(git branch*)",
|
|
223
|
+
"Bash(git log*)",
|
|
224
|
+
"Bash(git status*)",
|
|
225
|
+
];
|
|
226
|
+
|
|
227
|
+
const ALL_HOPLA_PERMISSIONS = new Set([...HOPLA_PERMISSIONS, ...PLANNING_PERMISSIONS]);
|
|
228
|
+
|
|
199
229
|
async function setupPermissions() {
|
|
200
230
|
const settingsPath = path.join(CLAUDE_DIR, "settings.json");
|
|
201
231
|
|
|
@@ -211,30 +241,62 @@ async function setupPermissions() {
|
|
|
211
241
|
if (!settings.permissions) settings.permissions = {};
|
|
212
242
|
if (!settings.permissions.allow) settings.permissions.allow = [];
|
|
213
243
|
|
|
214
|
-
|
|
215
|
-
const existing = new Set(settings.permissions.allow);
|
|
216
|
-
const toAdd = HOPLA_PERMISSIONS.filter((p) => !existing.has(p));
|
|
244
|
+
const targetPermissions = PLANNING ? PLANNING_PERMISSIONS : HOPLA_PERMISSIONS;
|
|
217
245
|
|
|
218
|
-
if (
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
246
|
+
if (PLANNING) {
|
|
247
|
+
// Replace: remove all hopla-owned permissions, then add planning-only ones
|
|
248
|
+
const cleaned = settings.permissions.allow.filter((p) => !ALL_HOPLA_PERMISSIONS.has(p));
|
|
249
|
+
const toAdd = targetPermissions.filter((p) => !cleaned.includes(p));
|
|
250
|
+
const toRemove = settings.permissions.allow.filter((p) => ALL_HOPLA_PERMISSIONS.has(p) && !targetPermissions.includes(p));
|
|
222
251
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
}
|
|
252
|
+
if (toAdd.length === 0 && toRemove.length === 0) {
|
|
253
|
+
log(`${GREEN}✓${RESET} Permissions already configured.\n`);
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
228
256
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
257
|
+
log(`${CYAN}Configuring permissions (planning mode)...${RESET}`);
|
|
258
|
+
log(` The following changes will be made to ~/.claude/settings.json:\n`);
|
|
259
|
+
for (const p of toRemove) {
|
|
260
|
+
log(` ${RED}-${RESET} ${p}`);
|
|
261
|
+
}
|
|
262
|
+
for (const p of toAdd) {
|
|
263
|
+
log(` ${CYAN}+${RESET} ${p}`);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const ok = await confirm(`\n Apply these permission changes? (y/N) `);
|
|
267
|
+
if (!ok) {
|
|
268
|
+
log(` ${YELLOW}↷${RESET} Skipped — you can edit ~/.claude/settings.json manually\n`);
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
settings.permissions.allow = [...cleaned, ...targetPermissions];
|
|
273
|
+
} else {
|
|
274
|
+
// Merge: add missing ones
|
|
275
|
+
const existing = new Set(settings.permissions.allow);
|
|
276
|
+
const toAdd = targetPermissions.filter((p) => !existing.has(p));
|
|
277
|
+
|
|
278
|
+
if (toAdd.length === 0) {
|
|
279
|
+
log(`${GREEN}✓${RESET} Permissions already configured.\n`);
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
log(`${CYAN}Configuring permissions...${RESET}`);
|
|
284
|
+
log(` The following will be added to ~/.claude/settings.json:\n`);
|
|
285
|
+
for (const p of toAdd) {
|
|
286
|
+
log(` ${CYAN}+${RESET} ${p}`);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const ok = await confirm(`\n Add these permissions? (y/N) `);
|
|
290
|
+
if (!ok) {
|
|
291
|
+
log(` ${YELLOW}↷${RESET} Skipped — you can add them manually to ~/.claude/settings.json\n`);
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
settings.permissions.allow = [...settings.permissions.allow, ...toAdd];
|
|
233
296
|
}
|
|
234
297
|
|
|
235
|
-
settings.permissions.allow = [...settings.permissions.allow, ...toAdd];
|
|
236
298
|
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
237
|
-
log(` ${GREEN}✓${RESET} Permissions
|
|
299
|
+
log(` ${GREEN}✓${RESET} Permissions configured.\n`);
|
|
238
300
|
}
|
|
239
301
|
|
|
240
302
|
const run = UNINSTALL ? uninstall : install;
|