mudra-skills 1.0.6 → 1.2.0
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 +46 -12
- package/bin/cli.js +178 -17
- package/package.json +6 -3
- package/.claude-plugin/plugin.json +0 -19
- package/CLAUDE.md +0 -35
- package/bin/install.js +0 -75
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# mudra-skills
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Skills for building [Mudra Band](https://wearabledevices.co.il) apps — works with Claude, Codex, and Antigravity. Generate 2D flat/screen apps, 3D/XR experiences, or let the router auto-classify your prompt.
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
@@ -8,27 +8,61 @@ Claude Code skills for building [Mudra Band](https://wearabledevices.co.il) apps
|
|
|
8
8
|
npx mudra-skills
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
You'll be prompted to choose your AI assistant:
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
```
|
|
14
|
+
Which AI assistant are you using?
|
|
15
|
+
(↑↓ to move, Enter to select)
|
|
14
16
|
|
|
15
|
-
|
|
17
|
+
❯ Claude
|
|
18
|
+
Codex
|
|
19
|
+
Antigravity
|
|
20
|
+
```
|
|
16
21
|
|
|
17
|
-
|
|
22
|
+
Or skip the prompt with the `--llm` flag:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npx mudra-skills --llm claude
|
|
26
|
+
npx mudra-skills --llm codex
|
|
27
|
+
npx mudra-skills --llm antigravity
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Where skills get installed
|
|
31
|
+
|
|
32
|
+
| AI | Install path | Invoke with |
|
|
18
33
|
|---|---|---|
|
|
19
|
-
| **
|
|
20
|
-
| **
|
|
21
|
-
| **
|
|
34
|
+
| **Claude** | `~/.claude/skills/` | `/mudra-master` |
|
|
35
|
+
| **Codex** | `~/.agents/skills/` | `$mudra-master` |
|
|
36
|
+
| **Antigravity** | `~/.gemini/antigravity/skills/` | `@mudra-master` |
|
|
37
|
+
|
|
38
|
+
## What You Get
|
|
39
|
+
|
|
40
|
+
Three skills, installed as folders:
|
|
41
|
+
|
|
42
|
+
| Skill | Description |
|
|
43
|
+
|---|---|
|
|
44
|
+
| **mudra-master** | Auto-router — classifies your prompt and hands off to 2D or 3D |
|
|
45
|
+
| **mudra-preview** | Generates single-file HTML 2D apps |
|
|
46
|
+
| **mudra-xr** | Generates single-file HTML 3D/XR apps using XR Blocks |
|
|
22
47
|
|
|
23
48
|
## Usage
|
|
24
49
|
|
|
25
|
-
|
|
50
|
+
### Claude
|
|
51
|
+
```
|
|
52
|
+
/mudra-master build a gesture-controlled music player
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Codex
|
|
56
|
+
```
|
|
57
|
+
$mudra-master build a gesture-controlled music player
|
|
58
|
+
```
|
|
26
59
|
|
|
60
|
+
### Antigravity
|
|
27
61
|
```
|
|
28
|
-
|
|
62
|
+
@mudra-master build a gesture-controlled music player
|
|
29
63
|
```
|
|
30
64
|
|
|
31
|
-
Or
|
|
65
|
+
Or just describe what you want — the router will classify it as 2D or 3D automatically.
|
|
32
66
|
|
|
33
67
|
## What Gets Generated
|
|
34
68
|
|
|
@@ -54,8 +88,8 @@ Every generated app includes:
|
|
|
54
88
|
|
|
55
89
|
## Requirements
|
|
56
90
|
|
|
57
|
-
- [Claude Code](https://claude.ai/code) CLI
|
|
58
91
|
- Node.js 18+
|
|
92
|
+
- One of: [Claude Code](https://claude.ai/code), [Codex CLI](https://github.com/openai/codex), or Antigravity
|
|
59
93
|
|
|
60
94
|
## License
|
|
61
95
|
|
package/bin/cli.js
CHANGED
|
@@ -7,12 +7,24 @@ import { execSync } from 'child_process';
|
|
|
7
7
|
|
|
8
8
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
9
9
|
const homeDir = process.env.HOME || process.env.USERPROFILE;
|
|
10
|
-
const
|
|
10
|
+
const CLAUDE_SKILLS_DIR = path.join(homeDir, '.claude', 'skills');
|
|
11
|
+
const CODEX_SKILLS_DIR = path.join(homeDir, '.agents', 'skills');
|
|
12
|
+
const ANTIGRAVITY_SKILLS_DIR = path.join(homeDir, '.gemini', 'antigravity', 'skills');
|
|
11
13
|
|
|
12
|
-
|
|
14
|
+
// Parse --llm flag before the command switch
|
|
15
|
+
let llmFlag = null;
|
|
16
|
+
const filteredArgv = [];
|
|
17
|
+
for (let i = 2; i < process.argv.length; i++) {
|
|
18
|
+
if (process.argv[i] === '--llm' && process.argv[i + 1]) {
|
|
19
|
+
llmFlag = process.argv[++i].toLowerCase();
|
|
20
|
+
} else {
|
|
21
|
+
filteredArgv.push(process.argv[i]);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
const [command, ...args] = filteredArgv;
|
|
13
25
|
|
|
14
26
|
switch (command ?? 'add') {
|
|
15
|
-
case 'add': await add(args[0]); break;
|
|
27
|
+
case 'add': await add(args[0], llmFlag); break;
|
|
16
28
|
case 'remove':
|
|
17
29
|
case 'rm': remove(args[0]); break;
|
|
18
30
|
case 'list':
|
|
@@ -20,7 +32,7 @@ switch (command ?? 'add') {
|
|
|
20
32
|
default: printHelp(); break;
|
|
21
33
|
}
|
|
22
34
|
|
|
23
|
-
async function add(source) {
|
|
35
|
+
async function add(source, llm) {
|
|
24
36
|
let skillsSource;
|
|
25
37
|
let tmpDir;
|
|
26
38
|
|
|
@@ -46,14 +58,80 @@ async function add(source) {
|
|
|
46
58
|
}
|
|
47
59
|
}
|
|
48
60
|
|
|
61
|
+
if (!llm) {
|
|
62
|
+
llm = await promptLLM();
|
|
63
|
+
}
|
|
64
|
+
|
|
49
65
|
try {
|
|
50
|
-
|
|
66
|
+
if (llm === 'claude') {
|
|
67
|
+
installClaude(skillsSource);
|
|
68
|
+
} else if (llm === 'codex') {
|
|
69
|
+
installCodex(skillsSource);
|
|
70
|
+
} else if (llm === 'antigravity') {
|
|
71
|
+
installAntigravity(skillsSource);
|
|
72
|
+
} else {
|
|
73
|
+
console.error(`Unknown LLM: "${llm}". Valid options: claude, codex, antigravity`);
|
|
74
|
+
process.exit(1);
|
|
75
|
+
}
|
|
51
76
|
} finally {
|
|
52
77
|
if (tmpDir) fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
53
78
|
}
|
|
54
79
|
}
|
|
55
80
|
|
|
56
|
-
function
|
|
81
|
+
function promptLLM() {
|
|
82
|
+
return new Promise((resolve) => {
|
|
83
|
+
const options = [
|
|
84
|
+
{ label: 'Claude', value: 'claude' },
|
|
85
|
+
{ label: 'Codex', value: 'codex' },
|
|
86
|
+
{ label: 'Antigravity', value: 'antigravity' },
|
|
87
|
+
];
|
|
88
|
+
let selected = 0;
|
|
89
|
+
let firstRender = true;
|
|
90
|
+
|
|
91
|
+
const render = () => {
|
|
92
|
+
if (!firstRender) {
|
|
93
|
+
process.stdout.write(`\x1B[${options.length}A`);
|
|
94
|
+
}
|
|
95
|
+
for (let i = 0; i < options.length; i++) {
|
|
96
|
+
const prefix = i === selected ? '❯ ' : ' ';
|
|
97
|
+
process.stdout.write(`\r\x1B[2K${prefix}${options[i].label}\n`);
|
|
98
|
+
}
|
|
99
|
+
firstRender = false;
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
process.stdout.write('\nWhich AI assistant are you using?\n');
|
|
103
|
+
process.stdout.write('(↑↓ to move, Enter to select)\n\n');
|
|
104
|
+
process.stdout.write('\x1B[?25l'); // hide cursor
|
|
105
|
+
|
|
106
|
+
process.stdin.setRawMode(true);
|
|
107
|
+
process.stdin.resume();
|
|
108
|
+
process.stdin.on('data', handler);
|
|
109
|
+
render();
|
|
110
|
+
|
|
111
|
+
function handler(key) {
|
|
112
|
+
if (key[0] === 0x1b && key[1] === 0x5b) {
|
|
113
|
+
if (key[2] === 0x41) { selected = (selected - 1 + options.length) % options.length; render(); }
|
|
114
|
+
else if (key[2] === 0x42) { selected = (selected + 1) % options.length; render(); }
|
|
115
|
+
} else if (key[0] === 0x0d || key[0] === 0x0a) {
|
|
116
|
+
process.stdin.removeListener('data', handler);
|
|
117
|
+
process.stdin.setRawMode(false);
|
|
118
|
+
process.stdin.pause();
|
|
119
|
+
process.stdout.write('\x1B[?25h'); // show cursor
|
|
120
|
+
process.stdout.write('\n');
|
|
121
|
+
resolve(options[selected].value);
|
|
122
|
+
} else if (key[0] === 0x03) { // Ctrl+C
|
|
123
|
+
process.stdin.removeListener('data', handler);
|
|
124
|
+
process.stdin.setRawMode(false);
|
|
125
|
+
process.stdin.pause();
|
|
126
|
+
process.stdout.write('\x1B[?25h');
|
|
127
|
+
process.stdout.write('\n');
|
|
128
|
+
process.exit(0);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function installClaude(skillsSource) {
|
|
57
135
|
if (!fs.existsSync(skillsSource)) {
|
|
58
136
|
console.error(`No skills directory found at: ${skillsSource}`);
|
|
59
137
|
process.exit(1);
|
|
@@ -67,7 +145,7 @@ function copySkills(skillsSource) {
|
|
|
67
145
|
process.exit(1);
|
|
68
146
|
}
|
|
69
147
|
|
|
70
|
-
fs.mkdirSync(
|
|
148
|
+
fs.mkdirSync(CLAUDE_SKILLS_DIR, { recursive: true });
|
|
71
149
|
|
|
72
150
|
const installed = [];
|
|
73
151
|
for (const entry of entries) {
|
|
@@ -75,7 +153,7 @@ function copySkills(skillsSource) {
|
|
|
75
153
|
const skillFile = path.join(src, 'SKILL.md');
|
|
76
154
|
if (!fs.existsSync(skillFile)) continue;
|
|
77
155
|
|
|
78
|
-
const dest = path.join(
|
|
156
|
+
const dest = path.join(CLAUDE_SKILLS_DIR, entry.name);
|
|
79
157
|
fs.mkdirSync(dest, { recursive: true });
|
|
80
158
|
execSync(`cp -r "${src}/." "${dest}"`);
|
|
81
159
|
installed.push(entry.name);
|
|
@@ -87,16 +165,98 @@ function copySkills(skillsSource) {
|
|
|
87
165
|
}
|
|
88
166
|
|
|
89
167
|
console.log('');
|
|
90
|
-
console.log(`Installed ${installed.length} skill(s) to ${
|
|
168
|
+
console.log(`Installed ${installed.length} skill(s) to ${CLAUDE_SKILLS_DIR}`);
|
|
91
169
|
for (const name of installed) console.log(` ✓ ${name}`);
|
|
92
170
|
console.log('');
|
|
93
171
|
console.log('Restart Claude Code (or run /reload-skills) to activate.');
|
|
94
172
|
console.log('');
|
|
95
173
|
}
|
|
96
174
|
|
|
175
|
+
function installCodex(skillsSource) {
|
|
176
|
+
if (!fs.existsSync(skillsSource)) {
|
|
177
|
+
console.error(`No skills directory found at: ${skillsSource}`);
|
|
178
|
+
process.exit(1);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const entries = fs.readdirSync(skillsSource, { withFileTypes: true })
|
|
182
|
+
.filter(e => e.isDirectory() && !e.name.startsWith('.'));
|
|
183
|
+
|
|
184
|
+
if (entries.length === 0) {
|
|
185
|
+
console.error('No skill folders found.');
|
|
186
|
+
process.exit(1);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
fs.mkdirSync(CODEX_SKILLS_DIR, { recursive: true });
|
|
190
|
+
|
|
191
|
+
const installed = [];
|
|
192
|
+
for (const entry of entries) {
|
|
193
|
+
const src = path.join(skillsSource, entry.name);
|
|
194
|
+
const skillFile = path.join(src, 'SKILL.md');
|
|
195
|
+
if (!fs.existsSync(skillFile)) continue;
|
|
196
|
+
|
|
197
|
+
const dest = path.join(CODEX_SKILLS_DIR, entry.name);
|
|
198
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
199
|
+
execSync(`cp -r "${src}/." "${dest}"`);
|
|
200
|
+
installed.push(entry.name);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (installed.length === 0) {
|
|
204
|
+
console.error('No valid skills found (each skill needs a SKILL.md).');
|
|
205
|
+
process.exit(1);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
console.log('');
|
|
209
|
+
console.log(`Installed ${installed.length} skill(s) to ${CODEX_SKILLS_DIR}`);
|
|
210
|
+
for (const name of installed) console.log(` ✓ ${name} → use $${name}`);
|
|
211
|
+
console.log('');
|
|
212
|
+
console.log('Codex picks up skills automatically. Invoke them with $skill-name.');
|
|
213
|
+
console.log('');
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function installAntigravity(skillsSource) {
|
|
217
|
+
if (!fs.existsSync(skillsSource)) {
|
|
218
|
+
console.error(`No skills directory found at: ${skillsSource}`);
|
|
219
|
+
process.exit(1);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const entries = fs.readdirSync(skillsSource, { withFileTypes: true })
|
|
223
|
+
.filter(e => e.isDirectory() && !e.name.startsWith('.'));
|
|
224
|
+
|
|
225
|
+
if (entries.length === 0) {
|
|
226
|
+
console.error('No skill folders found.');
|
|
227
|
+
process.exit(1);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
fs.mkdirSync(ANTIGRAVITY_SKILLS_DIR, { recursive: true });
|
|
231
|
+
|
|
232
|
+
const installed = [];
|
|
233
|
+
for (const entry of entries) {
|
|
234
|
+
const src = path.join(skillsSource, entry.name);
|
|
235
|
+
const skillFile = path.join(src, 'SKILL.md');
|
|
236
|
+
if (!fs.existsSync(skillFile)) continue;
|
|
237
|
+
|
|
238
|
+
const dest = path.join(ANTIGRAVITY_SKILLS_DIR, entry.name);
|
|
239
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
240
|
+
execSync(`cp -r "${src}/." "${dest}"`);
|
|
241
|
+
installed.push(entry.name);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (installed.length === 0) {
|
|
245
|
+
console.error('No valid skills found (each skill needs a SKILL.md).');
|
|
246
|
+
process.exit(1);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
console.log('');
|
|
250
|
+
console.log(`Installed ${installed.length} skill(s) to ${ANTIGRAVITY_SKILLS_DIR}`);
|
|
251
|
+
for (const name of installed) console.log(` ✓ ${name} → use @${name}`);
|
|
252
|
+
console.log('');
|
|
253
|
+
console.log('Antigravity picks up skills automatically. Invoke them with @skill-name or /skill-name.');
|
|
254
|
+
console.log('');
|
|
255
|
+
}
|
|
256
|
+
|
|
97
257
|
function remove(skillName) {
|
|
98
258
|
if (!skillName) { console.error('Usage: mudra-skills remove <skill-name>'); process.exit(1); }
|
|
99
|
-
const target = path.join(
|
|
259
|
+
const target = path.join(CLAUDE_SKILLS_DIR, skillName);
|
|
100
260
|
if (!fs.existsSync(target)) {
|
|
101
261
|
console.error(`Skill not found: ${skillName}`);
|
|
102
262
|
process.exit(1);
|
|
@@ -106,26 +266,27 @@ function remove(skillName) {
|
|
|
106
266
|
}
|
|
107
267
|
|
|
108
268
|
function list() {
|
|
109
|
-
if (!fs.existsSync(
|
|
269
|
+
if (!fs.existsSync(CLAUDE_SKILLS_DIR)) {
|
|
110
270
|
console.log('No skills installed yet.');
|
|
111
271
|
return;
|
|
112
272
|
}
|
|
113
|
-
const skills = fs.readdirSync(
|
|
114
|
-
.filter(e => e.isDirectory() && !e.name.startsWith('.') && fs.existsSync(path.join(
|
|
273
|
+
const skills = fs.readdirSync(CLAUDE_SKILLS_DIR, { withFileTypes: true })
|
|
274
|
+
.filter(e => e.isDirectory() && !e.name.startsWith('.') && fs.existsSync(path.join(CLAUDE_SKILLS_DIR, e.name, 'SKILL.md')));
|
|
115
275
|
|
|
116
276
|
if (skills.length === 0) {
|
|
117
277
|
console.log('No skills installed yet.');
|
|
118
278
|
return;
|
|
119
279
|
}
|
|
120
|
-
console.log(`Skills in ${
|
|
280
|
+
console.log(`Skills in ${CLAUDE_SKILLS_DIR}:`);
|
|
121
281
|
for (const s of skills) console.log(` ${s.name}`);
|
|
122
282
|
}
|
|
123
283
|
|
|
124
284
|
function printHelp() {
|
|
125
285
|
console.log(`
|
|
126
286
|
Usage:
|
|
127
|
-
npx mudra-skills
|
|
128
|
-
npx mudra-skills
|
|
129
|
-
npx mudra-skills
|
|
287
|
+
npx mudra-skills [--llm claude|codex|antigravity] Install skills (prompts if no --llm)
|
|
288
|
+
npx mudra-skills add [<github-url>] [--llm <name>] Install from URL
|
|
289
|
+
npx mudra-skills remove <name> Remove a Claude skill
|
|
290
|
+
npx mudra-skills list List installed Claude skills
|
|
130
291
|
`);
|
|
131
292
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mudra-skills",
|
|
3
|
-
"version": "1.0
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.2.0",
|
|
4
|
+
"description": "Mudra Band skills for Claude Code, Codex, and Antigravity — 2D, 3D/XR, or auto-classified",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"mudra-skills": "bin/cli.js"
|
|
@@ -24,5 +24,8 @@
|
|
|
24
24
|
"gestures",
|
|
25
25
|
"xr",
|
|
26
26
|
"webxr"
|
|
27
|
-
]
|
|
27
|
+
],
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"mudra-skills": "^1.1.0"
|
|
30
|
+
}
|
|
28
31
|
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "mudra",
|
|
3
|
-
"description": "Claude Code skills for building Mudra Band apps — generate 2D flat/screen apps, 3D/XR experiences, or let the router auto-classify and hand off.",
|
|
4
|
-
"version": "1.0.4",
|
|
5
|
-
"author": {
|
|
6
|
-
"name": "Wearable Devices",
|
|
7
|
-
"email": "jabbour.d@wearabledevices.co.il"
|
|
8
|
-
},
|
|
9
|
-
"homepage": "https://github.com/wearable-devices/mudra-skills",
|
|
10
|
-
"repository": "https://github.com/wearable-devices/mudra-skills",
|
|
11
|
-
"license": "MIT",
|
|
12
|
-
"keywords": [
|
|
13
|
-
"mudra",
|
|
14
|
-
"wearable",
|
|
15
|
-
"gestures",
|
|
16
|
-
"xr",
|
|
17
|
-
"webxr"
|
|
18
|
-
]
|
|
19
|
-
}
|
package/CLAUDE.md
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
# Mudra Plugin
|
|
2
|
-
|
|
3
|
-
This plugin provides skills for generating Mudra Band apps.
|
|
4
|
-
|
|
5
|
-
Use `/mudra-master` (or just describe an app idea) to build a 2D or 3D/XR app controlled by the Mudra Band wristband.
|
|
6
|
-
|
|
7
|
-
## Skills
|
|
8
|
-
|
|
9
|
-
- **mudra-master** — router: classifies prompt as 2D / 3D / ASK / DECLINE, then hands off
|
|
10
|
-
- **mudra-preview** — generates single-file HTML 2D apps
|
|
11
|
-
- **mudra-xr** — generates single-file HTML 3D/XR apps using XR Blocks
|
|
12
|
-
|
|
13
|
-
## Canonical Nine-Signal Table
|
|
14
|
-
|
|
15
|
-
| Signal | Type | Use for |
|
|
16
|
-
|---|---|---|
|
|
17
|
-
| `gesture` | discrete | finger pinches (index, middle, ring, little, thumb, grab) |
|
|
18
|
-
| `button` | discrete | hardware button press/release |
|
|
19
|
-
| `pressure` | analog | continuous squeeze force (0–1) |
|
|
20
|
-
| `navigation` | pointer | 2D cursor delta (x, y) — Pointer mode |
|
|
21
|
-
| `nav_direction` | discrete | swipe direction (up/down/left/right) — Direction mode |
|
|
22
|
-
| `imu_acc` | analog | accelerometer (x, y, z) — IMU mode |
|
|
23
|
-
| `imu_gyro` | analog | gyroscope (x, y, z) — IMU mode |
|
|
24
|
-
| `snc` | analog | 3-channel bio signal, batched arrays per channel |
|
|
25
|
-
| `battery` | discrete | battery level |
|
|
26
|
-
|
|
27
|
-
**Motion-mode exclusivity (non-negotiable):** each app uses exactly one of `navigation` XOR `nav_direction` XOR `imu_acc`+`imu_gyro`. The additive signals (`gesture`, `pressure`, `snc`, `battery`) combine freely with any mode.
|
|
28
|
-
|
|
29
|
-
## Protocol Rules
|
|
30
|
-
|
|
31
|
-
- WebSocket at `ws://127.0.0.1:8766`
|
|
32
|
-
- Subscribe one signal per command, key `signal` (singular): `{ "command": "subscribe", "signal": "<name>" }`
|
|
33
|
-
- Never use `signals` (plural) or batch subscribe
|
|
34
|
-
- Always wrap with `MudraWebSocket` class (includes mock fallback)
|
|
35
|
-
- Every app must include: mock fallback, always-visible simulator panel, keyboard shortcuts, connection-status indicator
|
package/bin/install.js
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import fs from 'fs';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
import { fileURLToPath } from 'url';
|
|
5
|
-
import { execSync } from 'child_process';
|
|
6
|
-
|
|
7
|
-
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
8
|
-
const pluginSrc = path.resolve(__dirname, '..');
|
|
9
|
-
const homeDir = process.env.HOME || process.env.USERPROFILE;
|
|
10
|
-
const pluginsDir = path.join(homeDir, '.claude', 'plugins');
|
|
11
|
-
|
|
12
|
-
const pkg = JSON.parse(fs.readFileSync(path.join(pluginSrc, 'package.json'), 'utf8'));
|
|
13
|
-
const version = pkg.version;
|
|
14
|
-
const MARKETPLACE = 'mudra-band';
|
|
15
|
-
const PLUGIN_NAME = 'mudra';
|
|
16
|
-
const PLUGIN_KEY = `${PLUGIN_NAME}@${MARKETPLACE}`;
|
|
17
|
-
|
|
18
|
-
// Install to top-level plugins directory (Claude Code scans here directly)
|
|
19
|
-
const target = path.join(pluginsDir, PLUGIN_NAME);
|
|
20
|
-
fs.mkdirSync(target, { recursive: true });
|
|
21
|
-
execSync(`cp -r "${pluginSrc}/." "${target}"`);
|
|
22
|
-
|
|
23
|
-
// Register the marketplace in known_marketplaces.json if not already there
|
|
24
|
-
const marketplacesFile = path.join(pluginsDir, 'known_marketplaces.json');
|
|
25
|
-
let marketplaces = {};
|
|
26
|
-
if (fs.existsSync(marketplacesFile)) {
|
|
27
|
-
marketplaces = JSON.parse(fs.readFileSync(marketplacesFile, 'utf8'));
|
|
28
|
-
}
|
|
29
|
-
if (!marketplaces[MARKETPLACE]) {
|
|
30
|
-
marketplaces[MARKETPLACE] = {
|
|
31
|
-
source: {
|
|
32
|
-
source: 'git',
|
|
33
|
-
url: 'https://github.com/jabbourWearable/mudra-skill.git',
|
|
34
|
-
},
|
|
35
|
-
installLocation: path.join(pluginsDir, 'marketplaces', MARKETPLACE),
|
|
36
|
-
lastUpdated: new Date().toISOString(),
|
|
37
|
-
};
|
|
38
|
-
fs.writeFileSync(marketplacesFile, JSON.stringify(marketplaces, null, 2));
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// Register the plugin in installed_plugins.json with the correct marketplace key
|
|
42
|
-
const installedFile = path.join(pluginsDir, 'installed_plugins.json');
|
|
43
|
-
let installed = { version: 2, plugins: {} };
|
|
44
|
-
if (fs.existsSync(installedFile)) {
|
|
45
|
-
installed = JSON.parse(fs.readFileSync(installedFile, 'utf8'));
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Remove stale npm entry from previous installs
|
|
49
|
-
delete installed.plugins['mudra@npm'];
|
|
50
|
-
|
|
51
|
-
const now = new Date().toISOString();
|
|
52
|
-
const previousInstall = installed.plugins[PLUGIN_KEY]?.[0];
|
|
53
|
-
installed.plugins[PLUGIN_KEY] = [
|
|
54
|
-
{
|
|
55
|
-
scope: 'user',
|
|
56
|
-
installPath: target,
|
|
57
|
-
version,
|
|
58
|
-
installedAt: previousInstall?.installedAt ?? now,
|
|
59
|
-
lastUpdated: now,
|
|
60
|
-
},
|
|
61
|
-
];
|
|
62
|
-
|
|
63
|
-
fs.writeFileSync(installedFile, JSON.stringify(installed, null, 2));
|
|
64
|
-
|
|
65
|
-
console.log('');
|
|
66
|
-
console.log('Mudra skills installed successfully!');
|
|
67
|
-
console.log('');
|
|
68
|
-
console.log('Next steps:');
|
|
69
|
-
console.log(' 1. Restart Claude Code, or run /reload-plugins');
|
|
70
|
-
console.log(' 2. Use the skills:');
|
|
71
|
-
console.log(' /mudra:mudra-master — auto-classify and route');
|
|
72
|
-
console.log(' /mudra:mudra-preview — generate 2D app');
|
|
73
|
-
console.log(' /mudra:mudra-xr — generate 3D/XR app');
|
|
74
|
-
console.log('');
|
|
75
|
-
console.log(`Plugin location: ${target}`);
|