@hopla/claude-setup 1.4.3 → 1.4.5

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 CHANGED
@@ -72,17 +72,38 @@ function removeFile(dest, label) {
72
72
  async function uninstall() {
73
73
  log(`\n${BOLD}@hopla/claude-setup${RESET} — Uninstall\n`);
74
74
 
75
- const commandFiles = fs.readdirSync(path.join(FILES_DIR, "commands"));
76
- const filesToRemove = [
77
- { dest: path.join(CLAUDE_DIR, "CLAUDE.md"), label: "~/.claude/CLAUDE.md" },
78
- ...commandFiles.map((file) => ({
75
+ const srcEntries = fs.readdirSync(path.join(FILES_DIR, "commands"));
76
+ const srcFiles = srcEntries.filter((f) =>
77
+ fs.statSync(path.join(FILES_DIR, "commands", f)).isFile()
78
+ );
79
+ const srcDirs = srcEntries.filter((f) =>
80
+ fs.statSync(path.join(FILES_DIR, "commands", f)).isDirectory()
81
+ );
82
+
83
+ const itemsToRemove = [
84
+ { dest: path.join(CLAUDE_DIR, "CLAUDE.md"), label: "~/.claude/CLAUDE.md", isDir: false },
85
+ ...srcFiles.map((file) => ({
79
86
  dest: path.join(COMMANDS_DIR, file),
80
87
  label: `~/.claude/commands/${file}`,
88
+ isDir: false,
89
+ })),
90
+ ...srcDirs.map((dir) => ({
91
+ dest: path.join(COMMANDS_DIR, dir),
92
+ label: `~/.claude/commands/${dir}/`,
93
+ isDir: true,
81
94
  })),
82
95
  ];
83
96
 
84
- log(`The following files will be removed:`);
85
- for (const { label } of filesToRemove) {
97
+ // Also remove skills and hooks installed by hopla
98
+ if (fs.existsSync(SKILLS_DIR)) {
99
+ itemsToRemove.push({ dest: SKILLS_DIR, label: "~/.claude/skills/", isDir: true });
100
+ }
101
+ if (fs.existsSync(HOOKS_DIR)) {
102
+ itemsToRemove.push({ dest: HOOKS_DIR, label: "~/.claude/hooks/", isDir: true });
103
+ }
104
+
105
+ log(`The following will be removed:`);
106
+ for (const { label } of itemsToRemove) {
86
107
  log(` ${RED}✕${RESET} ${label}`);
87
108
  }
88
109
 
@@ -93,40 +114,34 @@ async function uninstall() {
93
114
  }
94
115
 
95
116
  log("");
96
- for (const { dest, label } of filesToRemove) {
97
- removeFile(dest, label);
117
+ for (const { dest, label, isDir } of itemsToRemove) {
118
+ if (fs.existsSync(dest)) {
119
+ fs.rmSync(dest, { recursive: isDir });
120
+ log(` ${RED}✕${RESET} Removed: ${label}`);
121
+ } else {
122
+ log(` ${YELLOW}↷${RESET} Not found: ${label}`);
123
+ }
98
124
  }
99
125
 
100
126
  log(`\n${GREEN}${BOLD}Done!${RESET} Files removed.\n`);
101
127
  }
102
128
 
103
- const LEGACY_FILES = [
104
- "code-review-fix.md",
105
- "code-review.md",
106
- "commit.md",
107
- "create-prd.md",
108
- "execute.md",
109
- "execution-report.md",
110
- "plan-feature.md",
111
- "prime.md",
112
- "system-review.md",
113
- "hopla-lang.md",
114
- "hopla-commit.md",
115
- ];
116
-
117
- function removeLegacyFiles() {
129
+ function removeStaleCommands(currentCommandFiles) {
130
+ if (!fs.existsSync(COMMANDS_DIR)) return;
131
+ const currentSet = new Set(currentCommandFiles);
118
132
  const removed = [];
119
- for (const file of LEGACY_FILES) {
120
- const dest = path.join(COMMANDS_DIR, file);
121
- if (fs.existsSync(dest)) {
122
- fs.rmSync(dest);
133
+ for (const file of fs.readdirSync(COMMANDS_DIR)) {
134
+ const filePath = path.join(COMMANDS_DIR, file);
135
+ if (!fs.statSync(filePath).isFile()) continue;
136
+ if (file.startsWith("hopla-") && !currentSet.has(file)) {
137
+ fs.rmSync(filePath);
123
138
  removed.push(file);
124
139
  }
125
140
  }
126
141
  if (removed.length > 0) {
127
- log(`${CYAN}Cleaning up legacy commands...${RESET}`);
142
+ log(`${CYAN}Removing stale commands from previous versions...${RESET}`);
128
143
  for (const file of removed) {
129
- log(` ${YELLOW}↷${RESET} Removed legacy: ~/.claude/commands/${file}`);
144
+ log(` ${YELLOW}↷${RESET} Removed: ~/.claude/commands/${file}`);
130
145
  }
131
146
  log("");
132
147
  }
@@ -142,25 +157,6 @@ const PLANNING_COMMANDS = [
142
157
  "hopla-git-pr.md",
143
158
  ];
144
159
 
145
- function removeExecutionCommands() {
146
- const planningSet = new Set(PLANNING_COMMANDS);
147
- const removed = [];
148
- if (!fs.existsSync(COMMANDS_DIR)) return;
149
- for (const file of fs.readdirSync(COMMANDS_DIR)) {
150
- if (file.startsWith("hopla-") && !planningSet.has(file)) {
151
- fs.rmSync(path.join(COMMANDS_DIR, file));
152
- removed.push(file);
153
- }
154
- }
155
- if (removed.length > 0) {
156
- log(`${CYAN}Removing execution commands (planning mode)...${RESET}`);
157
- for (const file of removed) {
158
- log(` ${RED}✕${RESET} Removed: ~/.claude/commands/${file}`);
159
- }
160
- log("");
161
- }
162
- }
163
-
164
160
  async function install() {
165
161
  const modeLabel = PLANNING ? "Planning Mode (Robert)" : "Full Install";
166
162
  log(`\n${BOLD}@hopla/claude-setup${RESET} — Agentic Coding System ${CYAN}[${modeLabel}]${RESET}\n`);
@@ -169,20 +165,7 @@ async function install() {
169
165
  fs.mkdirSync(CLAUDE_DIR, { recursive: true });
170
166
  fs.mkdirSync(COMMANDS_DIR, { recursive: true });
171
167
 
172
- // Remove old non-prefixed commands from previous versions
173
- removeLegacyFiles();
174
-
175
- // In planning mode, remove any execution commands left from a previous full install
176
- if (PLANNING) removeExecutionCommands();
177
-
178
- log(`${CYAN}Installing global rules...${RESET}`);
179
- await installFile(
180
- path.join(FILES_DIR, "CLAUDE.md"),
181
- path.join(CLAUDE_DIR, "CLAUDE.md"),
182
- "~/.claude/CLAUDE.md"
183
- );
184
-
185
- log(`\n${CYAN}Installing commands...${RESET}`);
168
+ // Determine which command files will be installed
186
169
  const allCommandEntries = fs.readdirSync(path.join(FILES_DIR, "commands"));
187
170
  const allCommandFiles = allCommandEntries.filter((f) => {
188
171
  const stat = fs.statSync(path.join(FILES_DIR, "commands", f));
@@ -195,6 +178,18 @@ async function install() {
195
178
  const commandFiles = PLANNING
196
179
  ? allCommandFiles.filter((f) => PLANNING_COMMANDS.includes(f))
197
180
  : allCommandFiles;
181
+
182
+ // Remove stale hopla-* commands not in the current version
183
+ removeStaleCommands(commandFiles);
184
+
185
+ log(`${CYAN}Installing global rules...${RESET}`);
186
+ await installFile(
187
+ path.join(FILES_DIR, "CLAUDE.md"),
188
+ path.join(CLAUDE_DIR, "CLAUDE.md"),
189
+ "~/.claude/CLAUDE.md"
190
+ );
191
+
192
+ log(`\n${CYAN}Installing commands...${RESET}`);
198
193
  for (const file of commandFiles.sort()) {
199
194
  await installFile(
200
195
  path.join(FILES_DIR, "commands", file),
@@ -53,6 +53,6 @@ Pending plans:
53
53
  - add-user-authentication.md ← ready to execute with /hopla-execute
54
54
  ```
55
55
 
56
- End with a sentence like: "Listo para continuar — ¿por dónde empezamos?" or "All caught up — what are we working on today?" depending on the language the user writes in.
56
+ End with a sentence like: "All caught up — what are we working on today?" (adapt to the user's language).
57
57
 
58
58
  Do NOT use headers in the prose summary. Write it as natural, friendly prose, then the pending plans list if applicable.
@@ -41,9 +41,8 @@ Do NOT reproduce the full plan. Instead, present a structured summary in the use
41
41
 
42
42
  ## Step 3: Ask for Approval
43
43
 
44
- After the summary, ask:
45
- > "¿Todo claro? Puedes aprobar para ejecutar, pedir cambios, o hacer preguntas sobre alguna tarea."
46
- > (or in English if the conversation is in English)
44
+ After the summary, ask (in the user's language):
45
+ > "All clear? You can approve to execute, request changes, or ask questions about any task."
47
46
 
48
47
  **Review loop:**
49
48
  - If the user has questions → answer them based on the plan content
@@ -10,6 +10,22 @@ Perform a meta-level analysis of how well the implementation followed the plan.
10
10
  - **$1** — Path to the structured plan file
11
11
  - **$2** — Path to the execution report file
12
12
 
13
+ ## Step 0: Check for Existing Review
14
+
15
+ Before doing anything else, check if a system review already exists for this plan:
16
+
17
+ ```bash
18
+ ls .agents/system-reviews/
19
+ ```
20
+
21
+ Look for a file that matches the feature name derived from **$1** (the plan filename). If a matching review exists:
22
+ - Skip Steps 1–6
23
+ - Go directly to **Step 7** to archive the plan
24
+
25
+ If no matching review exists, continue with Step 1.
26
+
27
+ ---
28
+
13
29
  ## Step 1: Load All Context
14
30
 
15
31
  Read these four artifacts in order:
@@ -137,3 +153,15 @@ After the analysis, use this to prioritize actions:
137
153
  | Same manual step done 3+ times | Create a new command |
138
154
  | Plan was ambiguous in the same spot twice | Update plan-feature command |
139
155
  | First time seeing this issue | Note it, don't over-engineer yet |
156
+
157
+ ## Step 7: Archive the Plan
158
+
159
+ Move the completed plan to the archive folder:
160
+
161
+ ```bash
162
+ mkdir -p .agents/plans/done
163
+ mv "$1" .agents/plans/done/
164
+ ```
165
+
166
+ Then notify the user:
167
+ > "✅ System review saved to `.agents/system-reviews/[feature]-review.md`. Plan archived to `.agents/plans/done/[plan-name].md` — the active plans folder is now clean."
@@ -41,9 +41,7 @@ async function main() {
41
41
  }
42
42
 
43
43
  if (lines.length > 0) {
44
- const context = lines.join("\n\n");
45
- const output = `Display the following session context to the user as your first message, formatted as a clear summary:\n\n${context}`;
46
- process.stdout.write(output);
44
+ process.stdout.write(lines.join("\n\n"));
47
45
  }
48
46
 
49
47
  process.exit(0);
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: hopla-code-review
3
- description: Performs a technical code review on recently changed files. Use when the user says "review the code", "revisar el código", "code review", "analiza los cambios", "check my code", "revisa mi código", "look for issues", or asks for feedback on their implementation.
3
+ description: Performs a technical code review on recently changed files. Use when the user says "review the code", "code review", "check my code", "look for issues", or asks for feedback on their implementation.
4
4
  ---
5
5
 
6
6
  Perform a technical code review focused on finding real bugs and issues.
@@ -7,13 +7,13 @@ Detect the user's intent and execute the appropriate git workflow.
7
7
 
8
8
  ## Intent Detection
9
9
 
10
- **If the user wants to commit** (keywords: "commit", "comitea", "guarda los cambios", "save changes", "crear commit", "hacer commit"):
10
+ **If the user wants to commit** (keywords: "commit", "save changes", "create commit"):
11
11
  - Read and follow the instructions in `commit.md` (located in the same directory as this skill)
12
12
 
13
- **If the user wants to create a PR or push** (keywords: "PR", "pull request", "crea un PR", "abre un PR", "push", "merge request"):
13
+ **If the user wants to create a PR or push** (keywords: "PR", "pull request", "push", "merge request"):
14
14
  - Read and follow the instructions in `pr.md` (located in the same directory as this skill)
15
15
 
16
- **If unclear**, ask the user one short question: "¿Commit o Pull Request?" / "Commit or Pull Request?"
16
+ **If unclear**, ask the user one short question: "Commit or Pull Request?"
17
17
 
18
18
  ## File References
19
19
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: hopla-prime
3
- description: Orients Claude in a project at the start of a session. Use when the user says "orient yourself", "get oriented", "prime yourself", "ponte al día", "qué es este proyecto", "what is this project", "load context", or asks Claude to familiarize itself with the codebase before starting work.
3
+ description: Orients Claude in a project at the start of a session. Use when the user says "orient yourself", "get oriented", "prime yourself", "what is this project", "load context", or asks Claude to familiarize itself with the codebase before starting work.
4
4
  ---
5
5
 
6
6
  Get oriented in this project before doing any work.
@@ -54,6 +54,6 @@ Pending plans:
54
54
  - add-user-authentication.md ← ready to execute with /hopla-execute
55
55
  ```
56
56
 
57
- End with a sentence like: "Listo para continuar — ¿por dónde empezamos?" or "All caught up — what are we working on today?" depending on the language the user writes in.
57
+ End with a sentence like: "All caught up — what are we working on today?" (adapt to the user's language).
58
58
 
59
59
  Do NOT use headers in the prose summary. Write it as natural, friendly prose, then the pending plans list if applicable.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hopla/claude-setup",
3
- "version": "1.4.3",
3
+ "version": "1.4.5",
4
4
  "description": "Hopla team agentic coding system for Claude Code",
5
5
  "type": "module",
6
6
  "bin": {