claude-smart 0.1.15 → 0.1.16

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/README.md CHANGED
@@ -13,7 +13,7 @@
13
13
  <img src="https://img.shields.io/badge/License-Apache%202.0-blue.svg" alt="License">
14
14
  </a>
15
15
  <a href="plugin/pyproject.toml">
16
- <img src="https://img.shields.io/badge/version-0.1.15-green.svg" alt="Version">
16
+ <img src="https://img.shields.io/badge/version-0.1.16-green.svg" alt="Version">
17
17
  </a>
18
18
  <a href="plugin/pyproject.toml">
19
19
  <img src="https://img.shields.io/badge/python-%3E%3D3.12-brightgreen.svg" alt="Python">
@@ -9,7 +9,7 @@
9
9
  */
10
10
  "use strict";
11
11
 
12
- const { execFileSync, execSync } = require("child_process");
12
+ const { execFileSync, execSync, spawn } = require("child_process");
13
13
  const { appendFileSync, existsSync, mkdirSync, readFileSync } = require("fs");
14
14
  const { homedir } = require("os");
15
15
  const { dirname, join } = require("path");
@@ -18,6 +18,45 @@ const DEFAULT_MARKETPLACE_SOURCE = "ReflexioAI/claude-smart";
18
18
  const PLUGIN_SPEC = "claude-smart@reflexioai";
19
19
  const REFLEXIO_ENV_PATH = join(homedir(), ".reflexio", ".env");
20
20
 
21
+ function runClaude(args, { spinnerLabel } = {}) {
22
+ const useSpinner = Boolean(spinnerLabel) && process.stdout.isTTY && !process.env.CI;
23
+ return new Promise((resolve) => {
24
+ const child = spawn("claude", args, {
25
+ stdio: useSpinner ? ["inherit", "pipe", "pipe"] : "inherit",
26
+ });
27
+
28
+ let spinnerActive = false;
29
+ let timer = null;
30
+ if (useSpinner) {
31
+ const frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
32
+ let i = 0;
33
+ spinnerActive = true;
34
+ const render = () => {
35
+ process.stdout.write(`\r${frames[i = (i + 1) % frames.length]} ${spinnerLabel}`);
36
+ };
37
+ render();
38
+ timer = setInterval(render, 80);
39
+
40
+ const clear = () => {
41
+ if (!spinnerActive) return;
42
+ spinnerActive = false;
43
+ clearInterval(timer);
44
+ process.stdout.write("\r\x1b[2K");
45
+ };
46
+ const passthrough = (stream) => (chunk) => {
47
+ clear();
48
+ stream.write(chunk);
49
+ };
50
+ child.stdout.on("data", passthrough(process.stdout));
51
+ child.stderr.on("data", passthrough(process.stderr));
52
+ child.on("exit", clear);
53
+ }
54
+
55
+ child.on("exit", (code) => resolve(typeof code === "number" ? code : 1));
56
+ child.on("error", () => resolve(1));
57
+ });
58
+ }
59
+
21
60
  function hasClaudeCli() {
22
61
  const probe = process.platform === "win32" ? "where claude" : "command -v claude";
23
62
  try {
@@ -79,7 +118,7 @@ function parseSource(args) {
79
118
  return value;
80
119
  }
81
120
 
82
- function runUpdate() {
121
+ async function runUpdate() {
83
122
  if (!hasClaudeCli()) {
84
123
  process.stderr.write(
85
124
  "error: 'claude' CLI not found on PATH. " +
@@ -88,10 +127,10 @@ function runUpdate() {
88
127
  process.exit(1);
89
128
  }
90
129
 
91
- try {
92
- execFileSync("claude", ["plugin", "update", PLUGIN_SPEC], { stdio: "inherit" });
93
- } catch (err) {
94
- const code = typeof err.status === "number" ? err.status : 1;
130
+ const code = await runClaude(["plugin", "update", PLUGIN_SPEC], {
131
+ spinnerLabel: "Checking for claude-smart updates…",
132
+ });
133
+ if (code !== 0) {
95
134
  process.stderr.write(`error: \`claude plugin update ${PLUGIN_SPEC}\` failed (exit ${code})\n`);
96
135
  process.exit(code);
97
136
  }
@@ -99,7 +138,7 @@ function runUpdate() {
99
138
  process.stdout.write("\nclaude-smart updated. Restart Claude Code to apply.\n");
100
139
  }
101
140
 
102
- function runUninstall() {
141
+ async function runUninstall() {
103
142
  if (!hasClaudeCli()) {
104
143
  process.stderr.write(
105
144
  "error: 'claude' CLI not found on PATH. " +
@@ -108,10 +147,10 @@ function runUninstall() {
108
147
  process.exit(1);
109
148
  }
110
149
 
111
- try {
112
- execFileSync("claude", ["plugin", "uninstall", PLUGIN_SPEC], { stdio: "inherit" });
113
- } catch (err) {
114
- const code = typeof err.status === "number" ? err.status : 1;
150
+ const code = await runClaude(["plugin", "uninstall", PLUGIN_SPEC], {
151
+ spinnerLabel: "Uninstalling claude-smart…",
152
+ });
153
+ if (code !== 0) {
115
154
  process.stderr.write(
116
155
  `error: \`claude plugin uninstall ${PLUGIN_SPEC}\` failed (exit ${code})\n`,
117
156
  );
@@ -128,7 +167,7 @@ function runUninstall() {
128
167
  );
129
168
  }
130
169
 
131
- function runInstall(args) {
170
+ async function runInstall(args) {
132
171
  if (!hasClaudeCli()) {
133
172
  process.stderr.write(
134
173
  "error: 'claude' CLI not found on PATH. " +
@@ -139,17 +178,15 @@ function runInstall(args) {
139
178
 
140
179
  const source = parseSource(args);
141
180
  const steps = [
142
- ["plugin", "marketplace", "add", source],
143
- ["plugin", "install", PLUGIN_SPEC],
181
+ { args: ["plugin", "marketplace", "add", source], label: "Adding marketplace…" },
182
+ { args: ["plugin", "install", PLUGIN_SPEC], label: "Installing claude-smart…" },
144
183
  ];
145
184
 
146
- for (const stepArgs of steps) {
147
- try {
148
- execFileSync("claude", stepArgs, { stdio: "inherit" });
149
- } catch (err) {
150
- const code = typeof err.status === "number" ? err.status : 1;
185
+ for (const step of steps) {
186
+ const code = await runClaude(step.args, { spinnerLabel: step.label });
187
+ if (code !== 0) {
151
188
  process.stderr.write(
152
- `error: \`claude ${stepArgs.join(" ")}\` failed (exit ${code})\n`,
189
+ `error: \`claude ${step.args.join(" ")}\` failed (exit ${code})\n`,
153
190
  );
154
191
  process.exit(code);
155
192
  }
@@ -173,7 +210,7 @@ function runInstall(args) {
173
210
  );
174
211
  }
175
212
 
176
- function main() {
213
+ async function main() {
177
214
  const args = process.argv.slice(2);
178
215
  const cmd = args[0] || "install";
179
216
 
@@ -183,17 +220,17 @@ function main() {
183
220
  }
184
221
 
185
222
  if (cmd === "install") {
186
- runInstall(args.slice(1));
223
+ await runInstall(args.slice(1));
187
224
  return;
188
225
  }
189
226
 
190
227
  if (cmd === "update") {
191
- runUpdate();
228
+ await runUpdate();
192
229
  return;
193
230
  }
194
231
 
195
232
  if (cmd === "uninstall") {
196
- runUninstall();
233
+ await runUninstall();
197
234
  return;
198
235
  }
199
236
 
@@ -203,4 +240,7 @@ function main() {
203
240
  process.exit(1);
204
241
  }
205
242
 
206
- main();
243
+ main().catch((err) => {
244
+ process.stderr.write(`claude-smart: ${err && err.message ? err.message : err}\n`);
245
+ process.exit(1);
246
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-smart",
3
- "version": "0.1.15",
3
+ "version": "0.1.16",
4
4
  "description": "Self-improving Claude Code plugin — learns from corrections via reflexio",
5
5
  "keywords": [
6
6
  "claude",