@towles/tool 0.0.56 → 0.0.58

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@towles/tool",
3
- "version": "0.0.56",
3
+ "version": "0.0.58",
4
4
  "description": "CLI tool with auto-claude pipeline, developer tools, and journaling via markdown.",
5
5
  "keywords": [
6
6
  "auto-claude",
@@ -62,8 +62,20 @@ export default class Doctor extends BaseCommand {
62
62
  }
63
63
  }
64
64
 
65
+ // Claude plugin checks
66
+ this.log("");
67
+ const pluginChecks = await this.checkClaudePlugins();
68
+ for (const check of pluginChecks) {
69
+ const icon = check.ok ? pc.green("✓") : pc.red("✗");
70
+ const status = check.ok ? "installed" : "not installed";
71
+ this.log(`${icon} claude plugin ${check.name}: ${status}`);
72
+ if (!check.ok && check.installHint) {
73
+ this.log(` ${pc.dim(check.installHint)}`);
74
+ }
75
+ }
76
+
65
77
  // Summary
66
- const allOk = checks.every((c) => c.ok) && ghAuth.ok;
78
+ const allOk = checks.every((c) => c.ok) && ghAuth.ok && pluginChecks.every((c) => c.ok);
67
79
  this.log("");
68
80
  if (allOk) {
69
81
  this.log(pc.green("All checks passed!"));
@@ -101,4 +113,34 @@ export default class Doctor extends BaseCommand {
101
113
  return { ok: false };
102
114
  }
103
115
  }
116
+
117
+ private async checkClaudePlugins(): Promise<
118
+ { name: string; ok: boolean; installHint?: string }[]
119
+ > {
120
+ const requiredPlugins = [
121
+ {
122
+ id: "code-simplifier@claude-plugins-official",
123
+ name: "code-simplifier",
124
+ installCmd: "claude plugin install code-simplifier@claude-plugins-official --scope user",
125
+ },
126
+ ];
127
+
128
+ try {
129
+ const result = await x("claude", ["plugin", "list", "--json"]);
130
+ const plugins: { id: string }[] = JSON.parse(result.stdout);
131
+ const installedIds = new Set(plugins.map((p) => p.id));
132
+
133
+ return requiredPlugins.map((p) => ({
134
+ name: p.name,
135
+ ok: installedIds.has(p.id),
136
+ installHint: installedIds.has(p.id) ? undefined : `Run: ${p.installCmd}`,
137
+ }));
138
+ } catch {
139
+ return requiredPlugins.map((p) => ({
140
+ name: p.name,
141
+ ok: false,
142
+ installHint: `Run: ${p.installCmd}`,
143
+ }));
144
+ }
145
+ }
104
146
  }
@@ -96,35 +96,76 @@ export default class Install extends BaseCommand {
96
96
  this.showOtelInstructions();
97
97
  }
98
98
 
99
+ // Install Claude plugins
100
+ this.log(pc.bold("\n📦 Claude Plugins\n"));
101
+ await this.ensureClaudePlugins();
102
+
99
103
  this.log(pc.bold(pc.green("\n✅ Installation complete!\n")));
104
+ }
100
105
 
101
- // Offer to install plugins from marketplace
102
- this.log(pc.cyan("To install plugins from the Claude Code marketplace:"));
103
- this.log(
104
- pc.dim(" claude /plugins marketplace add https://github.com/ChrisTowles/towles-tool"),
105
- );
106
- this.log("");
106
+ private async ensureClaudePlugins(): Promise<void> {
107
+ const { x } = await import("tinyexec");
108
+
109
+ const requiredPlugins = [
110
+ {
111
+ id: "tt@towles-tool",
112
+ name: "tt-core",
113
+ marketplaceUrl: "https://github.com/ChrisTowles/towles-tool",
114
+ marketplace: "towles-tool",
115
+ },
116
+ {
117
+ id: "code-simplifier@claude-plugins-official",
118
+ name: "code-simplifier",
119
+ },
120
+ ];
121
+
122
+ // Get installed plugins
123
+ let installedIds = new Set<string>();
124
+ try {
125
+ const result = await x("claude", ["plugin", "list", "--json"]);
126
+ const plugins: { id: string }[] = JSON.parse(result.stdout);
127
+ installedIds = new Set(plugins.map((p) => p.id));
128
+ } catch {
129
+ this.log(pc.yellow("⚠ Could not list Claude plugins"));
130
+ }
107
131
 
108
- const answer = await consola.prompt("Install tt-core plugin from marketplace now?", {
109
- type: "confirm",
110
- initial: true,
111
- });
132
+ // Ensure marketplaces are added first
133
+ for (const plugin of requiredPlugins) {
134
+ if (plugin.marketplaceUrl && !installedIds.has(plugin.id)) {
135
+ try {
136
+ await x("claude", ["plugin", "marketplace", "add", plugin.marketplaceUrl]);
137
+ this.log(pc.dim(` Added marketplace: ${plugin.marketplace}`));
138
+ } catch {
139
+ // marketplace may already be added
140
+ }
141
+ }
142
+ }
112
143
 
113
- if (answer) {
114
- const { x } = await import("tinyexec");
115
- this.log("");
144
+ // Install missing plugins
145
+ for (const plugin of requiredPlugins) {
146
+ if (installedIds.has(plugin.id)) {
147
+ this.log(pc.dim(`✓ ${plugin.name} already installed`));
148
+ continue;
149
+ }
116
150
 
117
- const result = await x("claude", ["plugin", "install", "tt@towles-tool", "--scope", "user"]);
118
- if (result.stdout) this.log(result.stdout);
119
- if (result.stderr) this.log(pc.dim(result.stderr));
120
- if (result.exitCode === 0) {
121
- this.log(pc.green("✓ tt-core plugin installed"));
151
+ const answer = await consola.prompt(`Install ${plugin.name} plugin?`, {
152
+ type: "confirm",
153
+ initial: true,
154
+ });
155
+
156
+ if (answer) {
157
+ const result = await x("claude", ["plugin", "install", plugin.id, "--scope", "user"]);
158
+ if (result.exitCode === 0) {
159
+ this.log(pc.green(`✓ ${plugin.name} installed`));
160
+ } else {
161
+ if (result.stdout) this.log(result.stdout);
162
+ if (result.stderr) this.log(pc.dim(result.stderr));
163
+ this.log(pc.yellow(`⚠ ${plugin.name} install exited with code ${result.exitCode}`));
164
+ }
122
165
  } else {
123
- this.log(pc.yellow(`Command exited with code ${result.exitCode}`));
166
+ this.log(pc.dim(` Skipped ${plugin.name}`));
124
167
  }
125
168
  }
126
-
127
- this.log("");
128
169
  }
129
170
 
130
171
  private saveClaudeSettings(settings: ClaudeSettings): void {