@hailer/mcp 0.2.3 → 0.2.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/.claude/agents/agent-marketplace-publisher.md +120 -0
- package/.claude/agents/agent-marketplace-reviewer.md +133 -0
- package/.claude/commands/help.md +28 -0
- package/.claude/commands/help:agents.md +71 -0
- package/.claude/commands/help:commands.md +39 -0
- package/.claude/commands/help:faq.md +69 -0
- package/.claude/commands/help:plugins.md +50 -0
- package/.claude/commands/help:tools.md +75 -0
- package/.claude/commands/install-plugin.md +261 -0
- package/.claude/commands/list-plugins.md +42 -0
- package/.claude/commands/marketplace-setup.md +33 -0
- package/.claude/commands/publish-plugin.md +55 -0
- package/.claude/commands/uninstall-plugin.md +87 -0
- package/.claude/hooks/interactive-mode.cjs +5 -3
- package/.claude/skills/marketplace-publishing.md +155 -0
- package/CHANGELOG.md +89 -0
- package/CLAUDE.md +83 -36
- package/dist/app.js +13 -1
- package/dist/config.d.ts +1 -0
- package/dist/config.js +3 -0
- package/dist/core.d.ts +3 -4
- package/dist/core.js +23 -65
- package/dist/mcp/tools/app-marketplace.js +10 -32
- package/dist/mcp/tools/bug-fixer-tools.d.ts +22 -0
- package/dist/mcp/tools/bug-fixer-tools.js +447 -31
- package/dist/mcp/tools/file.d.ts +5 -1
- package/dist/mcp/tools/file.js +122 -4
- package/dist/mcp/utils/hailer-api-client.d.ts +13 -0
- package/dist/mcp/utils/hailer-api-client.js +64 -0
- package/package.json +1 -1
- package/mcp-system-prompt.txt +0 -127
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Install a plugin from local marketplace clone to .claude/ folder
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Install Plugin from Local Marketplace
|
|
6
|
+
|
|
7
|
+
Copies plugin files from local marketplace repo to project's `.claude/` folder.
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
/install-plugin <plugin-name>
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Pre-flight Checks
|
|
16
|
+
|
|
17
|
+
### 1. Marketplace Path
|
|
18
|
+
```bash
|
|
19
|
+
PROJECT_ROOT="$(pwd)"
|
|
20
|
+
MARKETPLACE_PATH="$PROJECT_ROOT/hailer-marketplace"
|
|
21
|
+
if [ ! -d "$MARKETPLACE_PATH" ]; then
|
|
22
|
+
echo "ERROR: Marketplace not found at $MARKETPLACE_PATH"
|
|
23
|
+
echo "Clone it: git clone git@github.com:Bdolf/Hailer-Marketplace.git $MARKETPLACE_PATH"
|
|
24
|
+
exit 1
|
|
25
|
+
fi
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### 2. Plugin Exists
|
|
29
|
+
```bash
|
|
30
|
+
PLUGIN_NAME="$1"
|
|
31
|
+
if [ ! -d "$MARKETPLACE_PATH/$PLUGIN_NAME" ]; then
|
|
32
|
+
echo "ERROR: Plugin '$PLUGIN_NAME' not found in marketplace"
|
|
33
|
+
echo "Available plugins:"
|
|
34
|
+
ls -1 "$MARKETPLACE_PATH" | grep -v "^\." | grep -v "node_modules"
|
|
35
|
+
exit 1
|
|
36
|
+
fi
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Installation Steps
|
|
40
|
+
|
|
41
|
+
For each plugin, copy files to the correct locations:
|
|
42
|
+
|
|
43
|
+
| Source | Destination |
|
|
44
|
+
|--------|-------------|
|
|
45
|
+
| `{plugin}/agents/*.md` | `.claude/agents/` |
|
|
46
|
+
| `{plugin}/skills/*/` | `.claude/skills/` |
|
|
47
|
+
| `{plugin}/hooks/*.cjs` | `.claude/hooks/` |
|
|
48
|
+
| `{plugin}/hooks/hooks.json` | Merge into `.claude/settings.json` |
|
|
49
|
+
| `{plugin}/.lsp.json` | Install to `~/.claude/plugins/cache/` (LSP support) |
|
|
50
|
+
|
|
51
|
+
## Execution Script
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
#!/bin/bash
|
|
55
|
+
|
|
56
|
+
PROJECT_ROOT="$(pwd)"
|
|
57
|
+
MARKETPLACE_PATH="$PROJECT_ROOT/hailer-marketplace"
|
|
58
|
+
PLUGIN_NAME="$1"
|
|
59
|
+
PLUGIN_PATH="$MARKETPLACE_PATH/$PLUGIN_NAME"
|
|
60
|
+
TARGET_CLAUDE=".claude"
|
|
61
|
+
|
|
62
|
+
# Pre-flight
|
|
63
|
+
if [ ! -d "$PLUGIN_PATH" ]; then
|
|
64
|
+
echo "ERROR: Plugin '$PLUGIN_NAME' not found"
|
|
65
|
+
exit 1
|
|
66
|
+
fi
|
|
67
|
+
|
|
68
|
+
# Create target dirs if needed
|
|
69
|
+
mkdir -p "$TARGET_CLAUDE/agents" "$TARGET_CLAUDE/skills" "$TARGET_CLAUDE/hooks"
|
|
70
|
+
|
|
71
|
+
# Copy agents
|
|
72
|
+
if [ -d "$PLUGIN_PATH/agents" ]; then
|
|
73
|
+
cp -v "$PLUGIN_PATH/agents/"*.md "$TARGET_CLAUDE/agents/" 2>/dev/null
|
|
74
|
+
echo "Installed agents"
|
|
75
|
+
fi
|
|
76
|
+
|
|
77
|
+
# Copy skills (entire directories)
|
|
78
|
+
if [ -d "$PLUGIN_PATH/skills" ]; then
|
|
79
|
+
cp -rv "$PLUGIN_PATH/skills/"* "$TARGET_CLAUDE/skills/" 2>/dev/null || true
|
|
80
|
+
echo "Installed skills"
|
|
81
|
+
fi
|
|
82
|
+
|
|
83
|
+
# Copy hooks
|
|
84
|
+
if [ -d "$PLUGIN_PATH/hooks" ]; then
|
|
85
|
+
find "$PLUGIN_PATH/hooks" -name "*.cjs" -exec cp -v {} "$TARGET_CLAUDE/hooks/" \;
|
|
86
|
+
echo "Installed hooks"
|
|
87
|
+
fi
|
|
88
|
+
|
|
89
|
+
# Auto-install LSP if plugin has .lsp.json
|
|
90
|
+
if [ -f "$PLUGIN_PATH/.lsp.json" ]; then
|
|
91
|
+
echo "Plugin includes LSP support, installing..."
|
|
92
|
+
|
|
93
|
+
# Use typescript-lsp from marketplace as LSP source
|
|
94
|
+
LSP_SOURCE="$MARKETPLACE_PATH/typescript-lsp"
|
|
95
|
+
LSP_CACHE="$HOME/.claude/plugins/cache/hailer-mcp-marketplace/typescript-lsp/1.0.0"
|
|
96
|
+
LSP_INSTALLED="$HOME/.claude/plugins/installed_plugins.json"
|
|
97
|
+
|
|
98
|
+
# Create plugin cache directory
|
|
99
|
+
mkdir -p "$LSP_CACHE/.claude-plugin"
|
|
100
|
+
|
|
101
|
+
# Copy .lsp.json from the LSP plugin source (not the current plugin)
|
|
102
|
+
if [ -f "$LSP_SOURCE/.lsp.json" ]; then
|
|
103
|
+
cp "$LSP_SOURCE/.lsp.json" "$LSP_CACHE/.lsp.json"
|
|
104
|
+
else
|
|
105
|
+
cp "$PLUGIN_PATH/.lsp.json" "$LSP_CACHE/.lsp.json"
|
|
106
|
+
fi
|
|
107
|
+
|
|
108
|
+
# Copy the actual plugin.json from typescript-lsp plugin
|
|
109
|
+
if [ -f "$LSP_SOURCE/.claude-plugin/plugin.json" ]; then
|
|
110
|
+
cp "$LSP_SOURCE/.claude-plugin/plugin.json" "$LSP_CACHE/.claude-plugin/plugin.json"
|
|
111
|
+
else
|
|
112
|
+
# Fallback: create minimal plugin.json
|
|
113
|
+
cat > "$LSP_CACHE/.claude-plugin/plugin.json" << 'PLUGINJSON'
|
|
114
|
+
{
|
|
115
|
+
"name": "typescript-lsp",
|
|
116
|
+
"version": "1.0.0",
|
|
117
|
+
"description": "TypeScript/JavaScript LSP support"
|
|
118
|
+
}
|
|
119
|
+
PLUGINJSON
|
|
120
|
+
fi
|
|
121
|
+
|
|
122
|
+
# Register in installed_plugins.json
|
|
123
|
+
node -e "
|
|
124
|
+
const fs = require('fs');
|
|
125
|
+
const path = '$LSP_INSTALLED';
|
|
126
|
+
|
|
127
|
+
let data = { version: 2, plugins: {} };
|
|
128
|
+
if (fs.existsSync(path)) {
|
|
129
|
+
data = JSON.parse(fs.readFileSync(path, 'utf-8'));
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const key = 'typescript-lsp@hailer-mcp-marketplace';
|
|
133
|
+
if (!data.plugins[key]) {
|
|
134
|
+
data.plugins[key] = [{
|
|
135
|
+
scope: 'user',
|
|
136
|
+
installPath: '$LSP_CACHE',
|
|
137
|
+
version: '1.0.0',
|
|
138
|
+
installedAt: new Date().toISOString(),
|
|
139
|
+
lastUpdated: new Date().toISOString()
|
|
140
|
+
}];
|
|
141
|
+
fs.writeFileSync(path, JSON.stringify(data, null, 2));
|
|
142
|
+
console.log('LSP registered in installed_plugins.json');
|
|
143
|
+
} else {
|
|
144
|
+
console.log('LSP already registered');
|
|
145
|
+
}
|
|
146
|
+
"
|
|
147
|
+
|
|
148
|
+
# Enable LSP tool in settings.json and .env.local
|
|
149
|
+
node -e "
|
|
150
|
+
const fs = require('fs');
|
|
151
|
+
|
|
152
|
+
// 1. Update .claude/settings.json
|
|
153
|
+
const settingsPath = '.claude/settings.json';
|
|
154
|
+
let settings = {};
|
|
155
|
+
if (fs.existsSync(settingsPath)) {
|
|
156
|
+
settings = JSON.parse(fs.readFileSync(settingsPath, 'utf-8'));
|
|
157
|
+
}
|
|
158
|
+
if (!settings.env) settings.env = {};
|
|
159
|
+
if (settings.env.ENABLE_LSP_TOOL !== '1') {
|
|
160
|
+
settings.env.ENABLE_LSP_TOOL = '1';
|
|
161
|
+
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
|
|
162
|
+
console.log('ENABLE_LSP_TOOL set in .claude/settings.json');
|
|
163
|
+
} else {
|
|
164
|
+
console.log('ENABLE_LSP_TOOL already in settings.json');
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// 2. Update .env
|
|
168
|
+
const envPath = '.env';
|
|
169
|
+
let envContent = '';
|
|
170
|
+
if (fs.existsSync(envPath)) {
|
|
171
|
+
envContent = fs.readFileSync(envPath, 'utf-8');
|
|
172
|
+
}
|
|
173
|
+
if (!envContent.includes('ENABLE_LSP_TOOL=')) {
|
|
174
|
+
const line = (envContent && !envContent.endsWith('\n') ? '\n' : '') + 'ENABLE_LSP_TOOL=1\n';
|
|
175
|
+
fs.appendFileSync(envPath, line);
|
|
176
|
+
console.log('ENABLE_LSP_TOOL added to .env');
|
|
177
|
+
} else {
|
|
178
|
+
console.log('ENABLE_LSP_TOOL already in .env');
|
|
179
|
+
}
|
|
180
|
+
"
|
|
181
|
+
|
|
182
|
+
echo "LSP config installed"
|
|
183
|
+
fi
|
|
184
|
+
|
|
185
|
+
echo "Files copied. Updating CLAUDE.md..."
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Update CLAUDE.md (Node.js)
|
|
189
|
+
|
|
190
|
+
Run after file copy to add agent to the main `<agents>` table:
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
node << 'EOF'
|
|
194
|
+
const fs = require("fs");
|
|
195
|
+
const path = require("path");
|
|
196
|
+
|
|
197
|
+
const PLUGIN_NAME = process.env.PLUGIN_NAME;
|
|
198
|
+
const AGENTS_DIR = ".claude/agents";
|
|
199
|
+
const CLAUDE_MD = "CLAUDE.md";
|
|
200
|
+
|
|
201
|
+
// Find agent files for this plugin
|
|
202
|
+
const agentFiles = fs.readdirSync(AGENTS_DIR)
|
|
203
|
+
.filter(f => f.startsWith("agent-" + PLUGIN_NAME) || f.includes(PLUGIN_NAME))
|
|
204
|
+
.filter(f => f.endsWith(".md"));
|
|
205
|
+
|
|
206
|
+
if (agentFiles.length === 0) {
|
|
207
|
+
console.log("No agent files found for " + PLUGIN_NAME);
|
|
208
|
+
process.exit(0);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
let content = fs.readFileSync(CLAUDE_MD, "utf-8");
|
|
212
|
+
|
|
213
|
+
for (const agentFile of agentFiles) {
|
|
214
|
+
const agentPath = path.join(AGENTS_DIR, agentFile);
|
|
215
|
+
const agentContent = fs.readFileSync(agentPath, "utf-8");
|
|
216
|
+
const agentName = path.basename(agentFile, ".md");
|
|
217
|
+
|
|
218
|
+
// Parse frontmatter
|
|
219
|
+
const modelMatch = agentContent.match(/^model:\s*(\w+)/m);
|
|
220
|
+
const descMatch = agentContent.match(/^description:\s*(.{1,30})/m);
|
|
221
|
+
const model = modelMatch ? modelMatch[1] : "sonnet";
|
|
222
|
+
const desc = descMatch ? descMatch[1].trim() : PLUGIN_NAME;
|
|
223
|
+
|
|
224
|
+
// Check if already in agents table
|
|
225
|
+
if (content.includes("| `" + agentName + "`")) {
|
|
226
|
+
console.log(agentName + " already in <agents> table");
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Insert before </agents>
|
|
231
|
+
const newRow = "| " + desc + " | `" + agentName + "` | " + model + " |\n";
|
|
232
|
+
content = content.replace("</agents>", newRow + "</agents>");
|
|
233
|
+
console.log("Added " + agentName + " to <agents> table");
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
fs.writeFileSync(CLAUDE_MD, content);
|
|
237
|
+
console.log("CLAUDE.md updated");
|
|
238
|
+
EOF
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Note: Set `PLUGIN_NAME` env var before running.
|
|
242
|
+
|
|
243
|
+
## Full Command
|
|
244
|
+
|
|
245
|
+
Run both scripts in sequence:
|
|
246
|
+
```bash
|
|
247
|
+
# 1. Copy files (bash)
|
|
248
|
+
# 2. Update CLAUDE.md (node)
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
Then: `echo "Restart Claude Code to load: claude -c"`
|
|
252
|
+
|
|
253
|
+
## List Available Plugins
|
|
254
|
+
|
|
255
|
+
If no plugin name provided, list available:
|
|
256
|
+
```bash
|
|
257
|
+
PROJECT_ROOT="$(pwd)"
|
|
258
|
+
MARKETPLACE_PATH="$PROJECT_ROOT/hailer-marketplace"
|
|
259
|
+
echo "Available plugins in marketplace:"
|
|
260
|
+
jq -r '.plugins[] | " \(.name) v\(.version) - \(.description)"' "$MARKETPLACE_PATH/.claude-plugin/marketplace.json"
|
|
261
|
+
```
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: List available plugins from local marketplace
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# List Available Marketplace Plugins
|
|
6
|
+
|
|
7
|
+
Shows all plugins available in the local marketplace clone.
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
/list-plugins
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Execution
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
PROJECT_ROOT="$(pwd)"
|
|
19
|
+
MARKETPLACE_PATH="$PROJECT_ROOT/hailer-marketplace"
|
|
20
|
+
|
|
21
|
+
if [ ! -d "$MARKETPLACE_PATH/.git" ]; then
|
|
22
|
+
echo "Marketplace not found at $MARKETPLACE_PATH"
|
|
23
|
+
echo "Run /marketplace-setup first"
|
|
24
|
+
exit 1
|
|
25
|
+
fi
|
|
26
|
+
|
|
27
|
+
# Pull latest before listing
|
|
28
|
+
cd "$MARKETPLACE_PATH" && git pull origin main --quiet && cd - > /dev/null
|
|
29
|
+
echo "Pulled latest from marketplace"
|
|
30
|
+
echo ""
|
|
31
|
+
|
|
32
|
+
jq -r '.plugins[] | " \(.name)@\(.version) - \(.description)"' \
|
|
33
|
+
"$MARKETPLACE_PATH/.claude-plugin/marketplace.json"
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Output (ALWAYS SHOW TO USER)
|
|
37
|
+
|
|
38
|
+
After running the execution script, ALWAYS present the results to the user:
|
|
39
|
+
|
|
40
|
+
1. Show total count: "**X plugins available in marketplace**"
|
|
41
|
+
2. List each plugin with name, version, and description
|
|
42
|
+
3. Remind user they can install with `/install-plugin <name>`
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Clone or pull the Hailer marketplace repo
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Marketplace Setup
|
|
6
|
+
|
|
7
|
+
Clone if missing, pull if exists. Always uses project root directory.
|
|
8
|
+
|
|
9
|
+
## Execution
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
# Get project root (where CLAUDE.md is)
|
|
13
|
+
PROJECT_ROOT="$(pwd)"
|
|
14
|
+
|
|
15
|
+
# Marketplace path is always relative to project root
|
|
16
|
+
MARKETPLACE_PATH="$PROJECT_ROOT/hailer-marketplace"
|
|
17
|
+
|
|
18
|
+
echo "Project root: $PROJECT_ROOT"
|
|
19
|
+
echo "Marketplace path: $MARKETPLACE_PATH"
|
|
20
|
+
|
|
21
|
+
if [ -d "$MARKETPLACE_PATH/.git" ]; then
|
|
22
|
+
cd "$MARKETPLACE_PATH" && git pull origin main
|
|
23
|
+
echo "Pulled latest"
|
|
24
|
+
else
|
|
25
|
+
git clone git@github.com:Bdolf/Hailer-Marketplace.git "$MARKETPLACE_PATH"
|
|
26
|
+
echo "Cloned marketplace to $MARKETPLACE_PATH"
|
|
27
|
+
fi
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Important
|
|
31
|
+
|
|
32
|
+
The marketplace is always cloned to `./hailer-marketplace` in the project root.
|
|
33
|
+
Commands should use absolute paths when working with the marketplace.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Publish a plugin to the Hailer marketplace with pre-validation
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Publish Plugin to Marketplace
|
|
6
|
+
|
|
7
|
+
## Usage
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
/publish-plugin <name>
|
|
11
|
+
/publish-plugin <source-path>
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Execution
|
|
15
|
+
|
|
16
|
+
**Spawn the publisher agent** with the plugin info:
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
Task(
|
|
20
|
+
subagent_type="agent-marketplace-publisher",
|
|
21
|
+
prompt={
|
|
22
|
+
"task": "publish",
|
|
23
|
+
"plugin": {
|
|
24
|
+
"name": "<plugin-name>",
|
|
25
|
+
"type": "agent|skill|hook",
|
|
26
|
+
"source_path": "<path-to-source-file>",
|
|
27
|
+
"description": "<description>",
|
|
28
|
+
"author": "<author>"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
)
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Argument Handling
|
|
35
|
+
|
|
36
|
+
If argument is a **path** (contains `/` or `.md`):
|
|
37
|
+
- `source_path`: use argument directly
|
|
38
|
+
- `name`: extract from filename (e.g., `agent-my-agent.md` → `my-agent`)
|
|
39
|
+
- `type`: detect from path (`/agents/` → agent, `/skills/` → skill)
|
|
40
|
+
|
|
41
|
+
If argument is a **name**:
|
|
42
|
+
- Look for `.claude/agents/agent-{name}.md`
|
|
43
|
+
- Or ask user for source path
|
|
44
|
+
|
|
45
|
+
## Flow
|
|
46
|
+
|
|
47
|
+
1. Orchestrator spawns `agent-marketplace-publisher`
|
|
48
|
+
2. Publisher checks if plugin exists, suggests version
|
|
49
|
+
3. Publisher returns `needs_confirmation` with version suggestion
|
|
50
|
+
4. User confirms version
|
|
51
|
+
5. Publisher creates branch, commits, pushes
|
|
52
|
+
6. Publisher returns `trigger_review`
|
|
53
|
+
7. Orchestrator spawns `agent-marketplace-reviewer`
|
|
54
|
+
8. Reviewer validates and merges to main
|
|
55
|
+
9. Done - plugin published
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Uninstall a plugin from .claude/ folder
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Uninstall Plugin
|
|
6
|
+
|
|
7
|
+
Removes plugin files from project's `.claude/` folder and updates CLAUDE.md.
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
/uninstall-plugin <plugin-name>
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Execution Script
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
#!/bin/bash
|
|
19
|
+
|
|
20
|
+
PLUGIN_NAME="$1"
|
|
21
|
+
TARGET_CLAUDE=".claude"
|
|
22
|
+
|
|
23
|
+
if [ -z "$PLUGIN_NAME" ]; then
|
|
24
|
+
echo "Currently installed plugins:"
|
|
25
|
+
ls -1 "$TARGET_CLAUDE/agents/"agent-*.md 2>/dev/null | xargs -I{} basename {} .md | sed 's/^agent-//' | sort -u
|
|
26
|
+
exit 0
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
# Remove agents matching plugin name
|
|
30
|
+
REMOVED=0
|
|
31
|
+
for f in "$TARGET_CLAUDE/agents/agent-$PLUGIN_NAME"*.md; do
|
|
32
|
+
if [ -f "$f" ]; then
|
|
33
|
+
rm -v "$f"
|
|
34
|
+
REMOVED=$((REMOVED + 1))
|
|
35
|
+
fi
|
|
36
|
+
done
|
|
37
|
+
|
|
38
|
+
# Remove skills matching plugin name
|
|
39
|
+
if [ -d "$TARGET_CLAUDE/skills/$PLUGIN_NAME" ]; then
|
|
40
|
+
rm -rv "$TARGET_CLAUDE/skills/$PLUGIN_NAME"
|
|
41
|
+
REMOVED=$((REMOVED + 1))
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
# Remove hooks matching plugin name
|
|
45
|
+
find "$TARGET_CLAUDE/hooks" -name "${PLUGIN_NAME}*.cjs" -exec rm -v {} \; 2>/dev/null && REMOVED=$((REMOVED + 1))
|
|
46
|
+
|
|
47
|
+
if [ $REMOVED -eq 0 ]; then
|
|
48
|
+
echo "No files found for plugin '$PLUGIN_NAME'"
|
|
49
|
+
exit 1
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
echo "Files removed. Updating CLAUDE.md..."
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Update CLAUDE.md (Node.js)
|
|
56
|
+
|
|
57
|
+
Run after file removal to remove agent from the main `<agents>` table:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
node << EOF
|
|
61
|
+
const fs = require("fs");
|
|
62
|
+
|
|
63
|
+
const PLUGIN_NAME = "$PLUGIN_NAME";
|
|
64
|
+
const CLAUDE_MD = "CLAUDE.md";
|
|
65
|
+
|
|
66
|
+
let content = fs.readFileSync(CLAUDE_MD, "utf-8");
|
|
67
|
+
|
|
68
|
+
// Remove lines containing this agent from the <agents> table
|
|
69
|
+
// Match: | ... | \`agent-PLUGIN_NAME...\` | ... |
|
|
70
|
+
const pattern = new RegExp("^\\\\|.*\\\`agent-" + PLUGIN_NAME + "[^\\\`]*\\\`.*\\\\|$\\\\n?", "gm");
|
|
71
|
+
const newContent = content.replace(pattern, "");
|
|
72
|
+
|
|
73
|
+
if (newContent !== content) {
|
|
74
|
+
fs.writeFileSync(CLAUDE_MD, newContent);
|
|
75
|
+
console.log("Removed agent-" + PLUGIN_NAME + " from <agents> table");
|
|
76
|
+
} else {
|
|
77
|
+
console.log("agent-" + PLUGIN_NAME + " not found in <agents> table");
|
|
78
|
+
}
|
|
79
|
+
EOF
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Full Command
|
|
83
|
+
|
|
84
|
+
Run both scripts in sequence, then:
|
|
85
|
+
```
|
|
86
|
+
echo "Plugin uninstalled. Restart Claude Code: claude -c"
|
|
87
|
+
```
|
|
@@ -52,10 +52,11 @@ function processHook(data) {
|
|
|
52
52
|
process.exit(0);
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
const lowerPrompt = prompt.toLowerCase();
|
|
56
|
-
|
|
57
55
|
// Detect task types that benefit from questions
|
|
56
|
+
// Order matters - more specific patterns first
|
|
58
57
|
const taskPatterns = [
|
|
58
|
+
{ pattern: /publish.*market|market.*publish|update.*market|market.*update|market.*icon|market.*listing/i, type: 'marketplace-publish', questions: ['New listing or update existing? (need productId for update)', 'Metadata only or new version with code?', 'Do you have an icon? (must upload with isPublic: true)'], skill: 'marketplace-publishing' },
|
|
59
|
+
{ pattern: /publish|deploy|release|update.*app|app.*update|republish/i, type: 'app-publish', questions: ['Workspace only OR marketplace too?', 'Which app? (path or name)', 'Version bump needed?'], skill: 'publish-hailer-app' },
|
|
59
60
|
{ pattern: /build|create|make.*app/i, type: 'app', questions: ['What data to display?', 'What layout/components?', 'What user actions needed?'] },
|
|
60
61
|
{ pattern: /create|add.*insight|report/i, type: 'insight', questions: ['What metrics/aggregations?', 'Which workflows to query?', 'Any filters needed?'] },
|
|
61
62
|
{ pattern: /import|create.*activit|bulk/i, type: 'data', questions: ['Which workflow?', 'What field values?', 'How many records?'] },
|
|
@@ -66,6 +67,7 @@ function processHook(data) {
|
|
|
66
67
|
const matched = taskPatterns.find(p => p.pattern.test(prompt));
|
|
67
68
|
|
|
68
69
|
if (matched) {
|
|
70
|
+
const skillLine = matched.skill ? `\nLoad skill: ${matched.skill}` : '';
|
|
69
71
|
const output = `
|
|
70
72
|
<interactive-mode>
|
|
71
73
|
BEFORE STARTING: Consider asking clarifying questions.
|
|
@@ -75,7 +77,7 @@ Suggested questions to ask user:
|
|
|
75
77
|
${matched.questions.map(q => `- ${q}`).join('\n')}
|
|
76
78
|
|
|
77
79
|
Use AskUserQuestion tool if requirements are unclear.
|
|
78
|
-
Gather specifics before spawning agents or making changes
|
|
80
|
+
Gather specifics before spawning agents or making changes.${skillLine}
|
|
79
81
|
</interactive-mode>
|
|
80
82
|
`;
|
|
81
83
|
console.log(output);
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# Marketplace Publishing Skill
|
|
2
|
+
|
|
3
|
+
<when-to-use>
|
|
4
|
+
User wants to publish an app to marketplace, update marketplace listing, or change marketplace app icon/metadata.
|
|
5
|
+
</when-to-use>
|
|
6
|
+
|
|
7
|
+
<prerequisites>
|
|
8
|
+
- `productId` - Marketplace product ID (24-char hex)
|
|
9
|
+
- `appId` - The app being published (24-char hex)
|
|
10
|
+
- User must be Network Admin of the workspace
|
|
11
|
+
</prerequisites>
|
|
12
|
+
|
|
13
|
+
<option-a>
|
|
14
|
+
## Update Metadata Only (No Version Change)
|
|
15
|
+
|
|
16
|
+
For updating icon, name, description without publishing new code:
|
|
17
|
+
|
|
18
|
+
<step-1>
|
|
19
|
+
**Upload icon as PUBLIC file**
|
|
20
|
+
```javascript
|
|
21
|
+
upload_files({
|
|
22
|
+
files: [{ path: "/path/to/icon.png", isPublic: true }]
|
|
23
|
+
})
|
|
24
|
+
```
|
|
25
|
+
</step-1>
|
|
26
|
+
|
|
27
|
+
<critical>
|
|
28
|
+
`isPublic: true` is REQUIRED for marketplace icons to display!
|
|
29
|
+
</critical>
|
|
30
|
+
|
|
31
|
+
<step-2>
|
|
32
|
+
**Update product metadata**
|
|
33
|
+
```javascript
|
|
34
|
+
publish_app({
|
|
35
|
+
appId: "<appId>",
|
|
36
|
+
productId: "<productId>", // REQUIRED for update
|
|
37
|
+
title: "App Name",
|
|
38
|
+
description: "Description",
|
|
39
|
+
version: "1.0.0", // Current version (no bump needed)
|
|
40
|
+
versionDescription: "Release notes",
|
|
41
|
+
publisher: "Publisher Name",
|
|
42
|
+
iconFileId: "<public-file-id>"
|
|
43
|
+
})
|
|
44
|
+
```
|
|
45
|
+
</step-2>
|
|
46
|
+
</option-a>
|
|
47
|
+
|
|
48
|
+
<option-b>
|
|
49
|
+
## Publish New Version (Code Changes)
|
|
50
|
+
|
|
51
|
+
For publishing new app code with version bump:
|
|
52
|
+
|
|
53
|
+
<step-1>
|
|
54
|
+
**Upload icon as PUBLIC file (if changing)**
|
|
55
|
+
```javascript
|
|
56
|
+
upload_files({
|
|
57
|
+
files: [{ path: "/path/to/icon.png", isPublic: true }]
|
|
58
|
+
})
|
|
59
|
+
```
|
|
60
|
+
</step-1>
|
|
61
|
+
|
|
62
|
+
<step-2>
|
|
63
|
+
**Update manifest.json**
|
|
64
|
+
- Bump version (must be > current, e.g., "1.0.31" → "1.0.32")
|
|
65
|
+
- Update versionDescription
|
|
66
|
+
</step-2>
|
|
67
|
+
|
|
68
|
+
<step-3>
|
|
69
|
+
**Publish app bundle**
|
|
70
|
+
```javascript
|
|
71
|
+
publish_hailer_app({
|
|
72
|
+
projectDirectory: "/path/to/app",
|
|
73
|
+
publishToMarket: true
|
|
74
|
+
})
|
|
75
|
+
```
|
|
76
|
+
</step-3>
|
|
77
|
+
|
|
78
|
+
<step-4>
|
|
79
|
+
**Update product metadata**
|
|
80
|
+
```javascript
|
|
81
|
+
publish_app({
|
|
82
|
+
appId: "<appId>",
|
|
83
|
+
productId: "<productId>",
|
|
84
|
+
title: "App Name",
|
|
85
|
+
description: "Description",
|
|
86
|
+
version: "1.0.32",
|
|
87
|
+
versionDescription: "What's new",
|
|
88
|
+
publisher: "Publisher Name",
|
|
89
|
+
iconFileId: "<public-file-id>"
|
|
90
|
+
})
|
|
91
|
+
```
|
|
92
|
+
</step-4>
|
|
93
|
+
</option-b>
|
|
94
|
+
|
|
95
|
+
<option-c>
|
|
96
|
+
## First-Time Marketplace Listing
|
|
97
|
+
|
|
98
|
+
For apps not yet in marketplace:
|
|
99
|
+
|
|
100
|
+
<step-1>
|
|
101
|
+
**Upload icon as PUBLIC**
|
|
102
|
+
```javascript
|
|
103
|
+
upload_files({
|
|
104
|
+
files: [{ path: "/path/to/icon.png", isPublic: true }]
|
|
105
|
+
})
|
|
106
|
+
```
|
|
107
|
+
</step-1>
|
|
108
|
+
|
|
109
|
+
<step-2>
|
|
110
|
+
**Publish app with marketplace flag**
|
|
111
|
+
```javascript
|
|
112
|
+
publish_hailer_app({
|
|
113
|
+
projectDirectory: "/path/to/app",
|
|
114
|
+
publishToMarket: true
|
|
115
|
+
})
|
|
116
|
+
```
|
|
117
|
+
Returns a `targetId`.
|
|
118
|
+
</step-2>
|
|
119
|
+
|
|
120
|
+
<step-3>
|
|
121
|
+
**Create marketplace listing**
|
|
122
|
+
```javascript
|
|
123
|
+
publish_app({
|
|
124
|
+
appId: "<appId>",
|
|
125
|
+
versionId: "<targetId>", // From step 2
|
|
126
|
+
title: "App Name",
|
|
127
|
+
description: "Description",
|
|
128
|
+
version: "1.0.0",
|
|
129
|
+
versionDescription: "Initial release",
|
|
130
|
+
publisher: "Publisher Name",
|
|
131
|
+
iconFileId: "<public-file-id>"
|
|
132
|
+
})
|
|
133
|
+
```
|
|
134
|
+
</step-3>
|
|
135
|
+
|
|
136
|
+
<note>
|
|
137
|
+
Creating new listings requires admin permissions.
|
|
138
|
+
</note>
|
|
139
|
+
</option-c>
|
|
140
|
+
|
|
141
|
+
<common-errors>
|
|
142
|
+
| Error | Cause | Fix |
|
|
143
|
+
|-------|-------|-----|
|
|
144
|
+
| Icon shows placeholder | File not public | Re-upload with `isPublic: true` |
|
|
145
|
+
| "You have to be a network admin" | Missing permissions | Get admin access |
|
|
146
|
+
| "Version not greater than previous" | Version too low | Bump version higher |
|
|
147
|
+
| POST /app/publish fails | Needs file upload | Use `publish_hailer_app` for code changes |
|
|
148
|
+
</common-errors>
|
|
149
|
+
|
|
150
|
+
<api-reference>
|
|
151
|
+
- `v3.product.update` - Updates metadata (name, description, icon, images)
|
|
152
|
+
- `v3.product.create` - Creates new listing (admin only)
|
|
153
|
+
- `POST /app/publish` - Uploads app bundle (requires .tgz file)
|
|
154
|
+
- `v3.app.product.install` - Installs/updates in workspace
|
|
155
|
+
</api-reference>
|