@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.
Files changed (2) hide show
  1. package/cli.js +80 -18
  2. 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
- // Find permissions not yet added
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 (toAdd.length === 0) {
219
- log(`${GREEN}✓${RESET} Permissions already configured.\n`);
220
- return;
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
- log(`${CYAN}Configuring permissions...${RESET}`);
224
- log(` The following will be added to ~/.claude/settings.json:\n`);
225
- for (const p of toAdd) {
226
- log(` ${CYAN}+${RESET} ${p}`);
227
- }
252
+ if (toAdd.length === 0 && toRemove.length === 0) {
253
+ log(`${GREEN}✓${RESET} Permissions already configured.\n`);
254
+ return;
255
+ }
228
256
 
229
- const ok = await confirm(`\n Add these permissions? (y/N) `);
230
- if (!ok) {
231
- log(` ${YELLOW}↷${RESET} Skipped you can add them manually to ~/.claude/settings.json\n`);
232
- return;
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 added.\n`);
299
+ log(` ${GREEN}✓${RESET} Permissions configured.\n`);
238
300
  }
239
301
 
240
302
  const run = UNINSTALL ? uninstall : install;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hopla/claude-setup",
3
- "version": "1.3.0",
3
+ "version": "1.3.2",
4
4
  "description": "Hopla team agentic coding system for Claude Code",
5
5
  "type": "module",
6
6
  "bin": {