magicpath-ai 1.3.0-beta.1 → 1.3.0-beta.11
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 +164 -53
- package/dist/cli.js +28 -1
- package/dist/cli.js.map +1 -1
- package/dist/commands/add.d.ts +49 -0
- package/dist/commands/add.js +140 -27
- package/dist/commands/add.js.map +1 -1
- package/dist/commands/auth.d.ts +2 -2
- package/dist/commands/auth.js +139 -38
- package/dist/commands/auth.js.map +1 -1
- package/dist/commands/clone.js +112 -86
- package/dist/commands/clone.js.map +1 -1
- package/dist/commands/info.d.ts +2 -0
- package/dist/commands/info.js +124 -0
- package/dist/commands/info.js.map +1 -0
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.js +113 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/integrate.js +108 -175
- package/dist/commands/integrate.js.map +1 -1
- package/dist/commands/list.d.ts +2 -0
- package/dist/commands/list.js +216 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/retheme.d.ts +2 -0
- package/dist/commands/retheme.js +327 -0
- package/dist/commands/retheme.js.map +1 -0
- package/dist/commands/schema.d.ts +2 -0
- package/dist/commands/schema.js +249 -0
- package/dist/commands/schema.js.map +1 -0
- package/dist/commands/search.d.ts +2 -0
- package/dist/commands/search.js +124 -0
- package/dist/commands/search.js.map +1 -0
- package/dist/commands/view.d.ts +2 -0
- package/dist/commands/view.js +27 -0
- package/dist/commands/view.js.map +1 -0
- package/dist/commands/whoami.d.ts +2 -0
- package/dist/commands/whoami.js +74 -0
- package/dist/commands/whoami.js.map +1 -0
- package/dist/util/api.d.ts +4 -0
- package/dist/util/api.js +12 -0
- package/dist/util/api.js.map +1 -1
- package/dist/util/auth.js +5 -0
- package/dist/util/auth.js.map +1 -1
- package/dist/util/component.d.ts +8 -8
- package/dist/util/component.js +8 -2
- package/dist/util/component.js.map +1 -1
- package/dist/util/diff.d.ts +4 -0
- package/dist/util/diff.js +11 -3
- package/dist/util/diff.js.map +1 -1
- package/dist/util/error.d.ts +7 -1
- package/dist/util/error.js +5 -1
- package/dist/util/error.js.map +1 -1
- package/dist/util/integrate.d.ts +13 -2
- package/dist/util/integrate.js +111 -9
- package/dist/util/integrate.js.map +1 -1
- package/dist/util/output.d.ts +15 -0
- package/dist/util/output.js +36 -0
- package/dist/util/output.js.map +1 -0
- package/package.json +3 -2
- package/skills/cli-reference.md +146 -0
- package/skills/guide.md +66 -0
package/README.md
CHANGED
|
@@ -1,96 +1,207 @@
|
|
|
1
1
|
# MagicPath CLI
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A component platform for AI agents. Search, add, and integrate UI components from MagicPath directly into your projects — works with Claude Code, Cursor, and GitHub Copilot.
|
|
4
4
|
|
|
5
5
|
## Quick Start
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
|
|
8
|
+
npm install -g magicpath-ai@beta
|
|
9
|
+
magicpath-ai login
|
|
10
|
+
magicpath-ai init # run in your project directory
|
|
9
11
|
```
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
After `init`, Claude Code, Cursor, and GitHub Copilot automatically pick up MagicPath skills — just mention MagicPath in conversation and your agent knows what to do.
|
|
12
14
|
|
|
13
|
-
|
|
15
|
+
## Commands
|
|
14
16
|
|
|
15
|
-
|
|
17
|
+
### Auth
|
|
18
|
+
|
|
19
|
+
#### `login`
|
|
20
|
+
|
|
21
|
+
Log in to your MagicPath account. Opens your browser for one-click authentication.
|
|
16
22
|
|
|
17
23
|
```bash
|
|
18
|
-
|
|
24
|
+
magicpath-ai login
|
|
25
|
+
magicpath-ai login --code <code> # headless fallback
|
|
19
26
|
```
|
|
20
27
|
|
|
21
|
-
|
|
28
|
+
#### `logout`
|
|
22
29
|
|
|
23
30
|
```bash
|
|
24
|
-
|
|
25
|
-
magicpath-ai clone -k <access-key>
|
|
31
|
+
magicpath-ai logout
|
|
26
32
|
```
|
|
27
33
|
|
|
28
|
-
|
|
34
|
+
#### `whoami`
|
|
35
|
+
|
|
36
|
+
Show the currently authenticated user.
|
|
29
37
|
|
|
30
38
|
```bash
|
|
31
|
-
|
|
32
|
-
npx magicpath-ai clone -k <access-key>
|
|
39
|
+
magicpath-ai whoami
|
|
33
40
|
```
|
|
34
41
|
|
|
35
|
-
|
|
42
|
+
### Discovery
|
|
36
43
|
|
|
37
|
-
|
|
44
|
+
#### `search`
|
|
38
45
|
|
|
39
|
-
|
|
46
|
+
Search component names across all your projects.
|
|
40
47
|
|
|
41
48
|
```bash
|
|
42
|
-
|
|
49
|
+
magicpath-ai search "button"
|
|
50
|
+
magicpath-ai search "nav" --limit 5
|
|
43
51
|
```
|
|
44
52
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
53
|
+
| Option | Description |
|
|
54
|
+
|--------|-------------|
|
|
55
|
+
| `--limit <n>` | Max results (default: 20) |
|
|
56
|
+
|
|
57
|
+
#### `list-projects`
|
|
58
|
+
|
|
59
|
+
List all projects for the current user.
|
|
48
60
|
|
|
49
|
-
**Example:**
|
|
50
61
|
```bash
|
|
51
|
-
|
|
62
|
+
magicpath-ai list-projects
|
|
63
|
+
magicpath-ai list-projects --limit 10 --offset 0
|
|
52
64
|
```
|
|
53
65
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
4. <� Your project is ready to go!
|
|
66
|
+
| Option | Description |
|
|
67
|
+
|--------|-------------|
|
|
68
|
+
| `--limit <n>` | Max results |
|
|
69
|
+
| `--offset <n>` | Skip first N results (default: 0) |
|
|
59
70
|
|
|
60
|
-
|
|
71
|
+
#### `list-components`
|
|
61
72
|
|
|
62
|
-
|
|
63
|
-
- All project files and assets
|
|
64
|
-
- Configuration files
|
|
65
|
-
- Dependencies and setup instructions
|
|
66
|
-
- Ready-to-run codebase
|
|
73
|
+
List components in a project. Supports cursor-based pagination.
|
|
67
74
|
|
|
68
|
-
|
|
75
|
+
```bash
|
|
76
|
+
magicpath-ai list-components <projectId>
|
|
77
|
+
magicpath-ai list-components <projectId> --limit 20
|
|
78
|
+
magicpath-ai list-components <projectId> --after <lastId>
|
|
79
|
+
```
|
|
69
80
|
|
|
70
|
-
|
|
71
|
-
|
|
81
|
+
| Option | Description |
|
|
82
|
+
|--------|-------------|
|
|
83
|
+
| `--limit <n>` | Max results per page (default: 100) |
|
|
84
|
+
| `--after <id>` | Fetch components after this ID |
|
|
85
|
+
| `--sort-by <field>` | Sort by `name` or `createdAt` (default: name) |
|
|
86
|
+
| `--order <dir>` | Sort direction: `asc` or `desc` (default: asc) |
|
|
87
|
+
|
|
88
|
+
#### `view`
|
|
89
|
+
|
|
90
|
+
Open a component preview in the browser.
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
magicpath-ai view <generatedName>
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Components
|
|
97
|
+
|
|
98
|
+
#### `add`
|
|
99
|
+
|
|
100
|
+
Add a MagicPath component to your project. Fetches the component files, writes them to your project, and installs any required dependencies.
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
magicpath-ai add <generatedName>
|
|
104
|
+
magicpath-ai add wispy-river-5234 --path src/components/ui
|
|
105
|
+
magicpath-ai add wispy-river-5234 --inspect # view source without installing
|
|
106
|
+
magicpath-ai add wispy-river-5234 --dry-run # preview file list only
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
| Option | Description |
|
|
110
|
+
|--------|-------------|
|
|
111
|
+
| `-p, --path <path>` | Custom component path (default: `src/components/magicpath`) |
|
|
112
|
+
| `--inspect` | Show full source code without installing |
|
|
113
|
+
| `--dry-run` | Preview file list without writing |
|
|
114
|
+
| `-y, --yes` | Skip confirmation prompts |
|
|
115
|
+
| `--overwrite` | Overwrite existing files |
|
|
116
|
+
| `-d, --debug` | Enable debug logging |
|
|
117
|
+
|
|
118
|
+
#### `integrate`
|
|
119
|
+
|
|
120
|
+
Integrate a MagicPath component into your project using AI. Offers two modes: integrate into a specific file, or retheme your entire project to match the component.
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
magicpath-ai integrate <generatedName>
|
|
124
|
+
magicpath-ai integrate wispy-river-5234 --target src/app/page.tsx
|
|
125
|
+
magicpath-ai integrate wispy-river-5234 --dry-run
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
| Option | Description |
|
|
129
|
+
|--------|-------------|
|
|
130
|
+
| `-t, --target <file>` | Target file to integrate into (skips interactive prompt) |
|
|
131
|
+
| `--no-review` | Apply changes without review |
|
|
132
|
+
| `--dry-run` | Show what would happen without writing |
|
|
133
|
+
| `-d, --debug` | Enable debug logging |
|
|
134
|
+
|
|
135
|
+
### AI Agent Setup
|
|
72
136
|
|
|
73
|
-
|
|
137
|
+
#### `init`
|
|
74
138
|
|
|
75
|
-
|
|
76
|
-
2. **Secure Download**: The CLI securely downloads your project from MagicPath servers
|
|
77
|
-
3. **Local Setup**: Projects are extracted and set up in your chosen directory
|
|
78
|
-
4. **Ready to Code**: Start editing, remixing, and building immediately
|
|
139
|
+
Set up MagicPath skills for AI agents. Creates rule/skill files for Claude Code, Cursor, and GitHub Copilot in your project.
|
|
79
140
|
|
|
80
|
-
|
|
141
|
+
```bash
|
|
142
|
+
magicpath-ai init
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
#### `info`
|
|
146
|
+
|
|
147
|
+
Show project and auth context. Useful for agent context injection.
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
magicpath-ai info
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
#### `schema`
|
|
154
|
+
|
|
155
|
+
Show JSON Schema for a command's input/output.
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
magicpath-ai schema add
|
|
159
|
+
magicpath-ai schema --all
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
#### `clone`
|
|
163
|
+
|
|
164
|
+
Download and unpack a full MagicPath project using a one-time access key.
|
|
81
165
|
|
|
82
|
-
|
|
83
|
-
-
|
|
84
|
-
|
|
166
|
+
```bash
|
|
167
|
+
magicpath-ai clone -k <accessKey>
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
| Option | Description |
|
|
171
|
+
|--------|-------------|
|
|
172
|
+
| `-k, --key <accessKey>` | Access key (required) |
|
|
173
|
+
| `-i, --ide <ide>` | Open in IDE (cursor, antigravity, vscode, webstorm) |
|
|
174
|
+
| `--dir <directory>` | Target directory (non-interactive) |
|
|
175
|
+
| `--name <projectName>` | Project name (non-interactive) |
|
|
176
|
+
|
|
177
|
+
## Global Options
|
|
178
|
+
|
|
179
|
+
| Option | Description |
|
|
180
|
+
|--------|-------------|
|
|
181
|
+
| `-o json` | Structured JSON output (also skips interactive prompts) |
|
|
182
|
+
|
|
183
|
+
The `-d, --debug` flag is available on `add`, `clone`, and `integrate` for verbose logging.
|
|
184
|
+
|
|
185
|
+
## Environment Variables
|
|
85
186
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
- Use `--debug` flag for detailed error information
|
|
187
|
+
| Variable | Description |
|
|
188
|
+
|----------|-------------|
|
|
189
|
+
| `MAGICPATH_TOKEN` | Auth token (bypasses login flow) |
|
|
90
190
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
-
|
|
191
|
+
## AI Agent Integration
|
|
192
|
+
|
|
193
|
+
Running `magicpath-ai init` in your project creates skill files that teach AI agents how to use MagicPath:
|
|
194
|
+
|
|
195
|
+
- **Claude Code** — `.claude/skills/magicpath/SKILL.md`
|
|
196
|
+
- **Cursor** — `.cursor/rules/magicpath.mdc`
|
|
197
|
+
- **GitHub Copilot** — `.github/instructions/magicpath.instructions.md`
|
|
198
|
+
|
|
199
|
+
Once set up, agents automatically know how to search for components, add them to your project, and integrate them into specific files.
|
|
200
|
+
|
|
201
|
+
## Requirements
|
|
202
|
+
|
|
203
|
+
- Node.js >= 16.0.0
|
|
204
|
+
- npm or yarn
|
|
94
205
|
|
|
95
206
|
## Support
|
|
96
207
|
|
|
@@ -100,8 +211,8 @@ When you clone a MagicPath project, you'll get a complete local copy with:
|
|
|
100
211
|
|
|
101
212
|
## License
|
|
102
213
|
|
|
103
|
-
MIT
|
|
214
|
+
MIT - Jack Beoris
|
|
104
215
|
|
|
105
216
|
---
|
|
106
217
|
|
|
107
|
-
Made with
|
|
218
|
+
Made with love by the MagicPath team
|
package/dist/cli.js
CHANGED
|
@@ -1,13 +1,40 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { program } from 'commander';
|
|
3
|
+
import { setJsonMode } from './util/output.js';
|
|
3
4
|
import { registerCloneCommand } from './commands/clone.js';
|
|
4
5
|
import { registerAddCommand } from './commands/add.js';
|
|
5
6
|
import { registerIntegrateCommand } from './commands/integrate.js';
|
|
7
|
+
// import { registerRethemeCommand } from './commands/retheme.js';
|
|
6
8
|
import { registerAuthCommands } from './commands/auth.js';
|
|
7
|
-
|
|
9
|
+
import { registerWhoamiCommand } from './commands/whoami.js';
|
|
10
|
+
import { registerListCommands } from './commands/list.js';
|
|
11
|
+
import { registerSchemaCommand } from './commands/schema.js';
|
|
12
|
+
import { registerInitCommand } from './commands/init.js';
|
|
13
|
+
import { registerViewCommand } from './commands/view.js';
|
|
14
|
+
import { registerInfoCommand } from './commands/info.js';
|
|
15
|
+
import { registerSearchCommand } from './commands/search.js';
|
|
16
|
+
program
|
|
17
|
+
.name('magicpath')
|
|
18
|
+
.description('CLI for MagicPath AI')
|
|
19
|
+
.version('1.3.0')
|
|
20
|
+
.option('-o, --output <format>', 'Output format: json')
|
|
21
|
+
.hook('preAction', (thisCommand) => {
|
|
22
|
+
const opts = thisCommand.optsWithGlobals();
|
|
23
|
+
if (opts.output === 'json') {
|
|
24
|
+
setJsonMode(true);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
8
27
|
registerCloneCommand(program);
|
|
9
28
|
registerAddCommand(program);
|
|
10
29
|
registerIntegrateCommand(program);
|
|
30
|
+
// registerRethemeCommand(program);
|
|
11
31
|
registerAuthCommands(program);
|
|
32
|
+
registerWhoamiCommand(program);
|
|
33
|
+
registerListCommands(program);
|
|
34
|
+
registerSchemaCommand(program);
|
|
35
|
+
registerInitCommand(program);
|
|
36
|
+
registerViewCommand(program);
|
|
37
|
+
registerInfoCommand(program);
|
|
38
|
+
registerSearchCommand(program);
|
|
12
39
|
program.parse();
|
|
13
40
|
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AACnE,kEAAkE;AAClE,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAE7D,OAAO;KACJ,IAAI,CAAC,WAAW,CAAC;KACjB,WAAW,CAAC,sBAAsB,CAAC;KACnC,OAAO,CAAC,OAAO,CAAC;KAChB,MAAM,CAAC,uBAAuB,EAAE,qBAAqB,CAAC;KACtD,IAAI,CAAC,WAAW,EAAE,CAAC,WAAW,EAAE,EAAE;IACjC,MAAM,IAAI,GAAG,WAAW,CAAC,eAAe,EAAE,CAAC;IAC3C,IAAI,IAAI,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;QAC3B,WAAW,CAAC,IAAI,CAAC,CAAC;IACpB,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,oBAAoB,CAAC,OAAO,CAAC,CAAC;AAC9B,kBAAkB,CAAC,OAAO,CAAC,CAAC;AAC5B,wBAAwB,CAAC,OAAO,CAAC,CAAC;AAClC,mCAAmC;AACnC,oBAAoB,CAAC,OAAO,CAAC,CAAC;AAC9B,qBAAqB,CAAC,OAAO,CAAC,CAAC;AAC/B,oBAAoB,CAAC,OAAO,CAAC,CAAC;AAC9B,qBAAqB,CAAC,OAAO,CAAC,CAAC;AAC/B,mBAAmB,CAAC,OAAO,CAAC,CAAC;AAC7B,mBAAmB,CAAC,OAAO,CAAC,CAAC;AAC7B,mBAAmB,CAAC,OAAO,CAAC,CAAC;AAC7B,qBAAqB,CAAC,OAAO,CAAC,CAAC;AAE/B,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
package/dist/commands/add.d.ts
CHANGED
|
@@ -1,2 +1,51 @@
|
|
|
1
1
|
import type { Command } from 'commander';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
export declare const addOptionsSchema: z.ZodObject<{
|
|
4
|
+
yes: z.ZodDefault<z.ZodBoolean>;
|
|
5
|
+
overwrite: z.ZodDefault<z.ZodBoolean>;
|
|
6
|
+
path: z.ZodOptional<z.ZodString>;
|
|
7
|
+
debug: z.ZodDefault<z.ZodBoolean>;
|
|
8
|
+
dryRun: z.ZodDefault<z.ZodBoolean>;
|
|
9
|
+
inspect: z.ZodDefault<z.ZodBoolean>;
|
|
10
|
+
}, "strip", z.ZodTypeAny, {
|
|
11
|
+
debug: boolean;
|
|
12
|
+
yes: boolean;
|
|
13
|
+
overwrite: boolean;
|
|
14
|
+
dryRun: boolean;
|
|
15
|
+
inspect: boolean;
|
|
16
|
+
path?: string | undefined;
|
|
17
|
+
}, {
|
|
18
|
+
debug?: boolean | undefined;
|
|
19
|
+
path?: string | undefined;
|
|
20
|
+
yes?: boolean | undefined;
|
|
21
|
+
overwrite?: boolean | undefined;
|
|
22
|
+
dryRun?: boolean | undefined;
|
|
23
|
+
inspect?: boolean | undefined;
|
|
24
|
+
}>;
|
|
25
|
+
export type AddOptions = z.infer<typeof addOptionsSchema>;
|
|
26
|
+
export declare const addOutputSchema: z.ZodObject<{
|
|
27
|
+
component: z.ZodString;
|
|
28
|
+
generatedName: z.ZodString;
|
|
29
|
+
filesWritten: z.ZodArray<z.ZodString, "many">;
|
|
30
|
+
dependenciesInstalled: z.ZodArray<z.ZodString, "many">;
|
|
31
|
+
importStatement: z.ZodOptional<z.ZodString>;
|
|
32
|
+
usage: z.ZodOptional<z.ZodString>;
|
|
33
|
+
dryRun: z.ZodBoolean;
|
|
34
|
+
}, "strip", z.ZodTypeAny, {
|
|
35
|
+
generatedName: string;
|
|
36
|
+
component: string;
|
|
37
|
+
dryRun: boolean;
|
|
38
|
+
filesWritten: string[];
|
|
39
|
+
dependenciesInstalled: string[];
|
|
40
|
+
importStatement?: string | undefined;
|
|
41
|
+
usage?: string | undefined;
|
|
42
|
+
}, {
|
|
43
|
+
generatedName: string;
|
|
44
|
+
component: string;
|
|
45
|
+
dryRun: boolean;
|
|
46
|
+
filesWritten: string[];
|
|
47
|
+
dependenciesInstalled: string[];
|
|
48
|
+
importStatement?: string | undefined;
|
|
49
|
+
usage?: string | undefined;
|
|
50
|
+
}>;
|
|
2
51
|
export declare function registerAddCommand(program: Command): void;
|
package/dist/commands/add.js
CHANGED
|
@@ -6,14 +6,26 @@ import { enableDebugLogger, logger } from '../util/logger.js';
|
|
|
6
6
|
import { MagicPathError } from '../util/error.js';
|
|
7
7
|
import { AuthRequiredError } from '../util/authError.js';
|
|
8
8
|
import { brandSpinner } from '../util/ui.js';
|
|
9
|
+
import { isJsonMode, jsonResult, jsonError } from '../util/output.js';
|
|
9
10
|
import { fetchComponent, checkExistingFiles, writeComponentFiles, checkUtilsExists, writeUtilsFile, resolveComponentsPath, resolveUtilsPath, sanitizeComponentFolderName, extractComponentExports, generateImportStatement, generateUsageExample, writeUsageFile, DEFAULT_COMPONENTS_PATH, } from '../util/component.js';
|
|
10
11
|
import { installPackages } from '../util/dependencies.js';
|
|
11
12
|
import { runLoginFlow } from './auth.js';
|
|
12
|
-
const addOptionsSchema = z.object({
|
|
13
|
+
export const addOptionsSchema = z.object({
|
|
13
14
|
yes: z.boolean().default(false),
|
|
14
15
|
overwrite: z.boolean().default(false),
|
|
15
16
|
path: z.string().optional(),
|
|
16
17
|
debug: z.boolean().default(false),
|
|
18
|
+
dryRun: z.boolean().default(false),
|
|
19
|
+
inspect: z.boolean().default(false),
|
|
20
|
+
});
|
|
21
|
+
export const addOutputSchema = z.object({
|
|
22
|
+
component: z.string(),
|
|
23
|
+
generatedName: z.string(),
|
|
24
|
+
filesWritten: z.array(z.string()),
|
|
25
|
+
dependenciesInstalled: z.array(z.string()),
|
|
26
|
+
importStatement: z.string().optional(),
|
|
27
|
+
usage: z.string().optional(),
|
|
28
|
+
dryRun: z.boolean(),
|
|
17
29
|
});
|
|
18
30
|
export function registerAddCommand(program) {
|
|
19
31
|
program
|
|
@@ -21,9 +33,11 @@ export function registerAddCommand(program) {
|
|
|
21
33
|
.description('Add a MagicPath component to your project')
|
|
22
34
|
.argument('<generatedName>', 'The generated name of the component (e.g., wispy-river-5234)')
|
|
23
35
|
.option('-y, --yes', 'Skip confirmation prompts', false)
|
|
24
|
-
.option('
|
|
36
|
+
.option('--overwrite', 'Overwrite existing files', false)
|
|
25
37
|
.option('-p, --path <path>', `Custom path for components (default: ${DEFAULT_COMPONENTS_PATH})`)
|
|
26
38
|
.option('-d, --debug', 'Enable debug logging', false)
|
|
39
|
+
.option('--dry-run', 'Show what would happen without writing files', false)
|
|
40
|
+
.option('--inspect', 'Show component source code without installing (implies --dry-run)', false)
|
|
27
41
|
.action(async (generatedName, options) => {
|
|
28
42
|
try {
|
|
29
43
|
let addOptions;
|
|
@@ -35,23 +49,43 @@ export function registerAddCommand(program) {
|
|
|
35
49
|
}
|
|
36
50
|
if (addOptions.debug)
|
|
37
51
|
enableDebugLogger();
|
|
52
|
+
// --inspect implies --dry-run and --yes (no prompts, no writing)
|
|
53
|
+
if (addOptions.inspect) {
|
|
54
|
+
addOptions.dryRun = true;
|
|
55
|
+
addOptions.yes = true;
|
|
56
|
+
}
|
|
57
|
+
// In JSON mode, imply --yes (skip prompts)
|
|
58
|
+
const json = isJsonMode();
|
|
59
|
+
if (json)
|
|
60
|
+
addOptions.yes = true;
|
|
38
61
|
logger.debug({ generatedName, options: addOptions });
|
|
39
62
|
const cwd = process.cwd();
|
|
40
63
|
// Check if we're in a valid project directory
|
|
41
64
|
const packageJsonPath = path.join(cwd, 'package.json');
|
|
42
65
|
if (!fs.existsSync(packageJsonPath)) {
|
|
43
|
-
throw new MagicPathError('No package.json found. Please run this command from the root of your project.'
|
|
66
|
+
throw new MagicPathError('No package.json found. Please run this command from the root of your React project.', {
|
|
67
|
+
code: 'MISSING_PACKAGE_JSON',
|
|
68
|
+
suggestion: 'Run this command from the root of your project where package.json is located.',
|
|
69
|
+
});
|
|
44
70
|
}
|
|
45
71
|
// Step 1: Fetch component from registry
|
|
46
|
-
const fetchSpinner =
|
|
72
|
+
const fetchSpinner = json
|
|
73
|
+
? null
|
|
74
|
+
: brandSpinner(`Fetching component "${generatedName}"...`).start();
|
|
47
75
|
let componentData;
|
|
48
76
|
try {
|
|
49
77
|
componentData = await fetchComponent(generatedName);
|
|
50
|
-
fetchSpinner
|
|
78
|
+
fetchSpinner?.succeed(`Found component: ${componentData.name}`);
|
|
51
79
|
}
|
|
52
80
|
catch (err) {
|
|
53
81
|
if (err instanceof AuthRequiredError) {
|
|
54
|
-
fetchSpinner
|
|
82
|
+
fetchSpinner?.fail('Not logged in');
|
|
83
|
+
if (json) {
|
|
84
|
+
throw new MagicPathError('Not authenticated. Set MAGICPATH_TOKEN or run `magicpath-ai login`.', {
|
|
85
|
+
code: 'NOT_AUTHENTICATED',
|
|
86
|
+
suggestion: 'Run `magicpath-ai login` or set the MAGICPATH_TOKEN environment variable.',
|
|
87
|
+
});
|
|
88
|
+
}
|
|
55
89
|
const { shouldLogin } = await prompts({
|
|
56
90
|
type: 'confirm',
|
|
57
91
|
name: 'shouldLogin',
|
|
@@ -82,7 +116,7 @@ export function registerAddCommand(program) {
|
|
|
82
116
|
}
|
|
83
117
|
}
|
|
84
118
|
else {
|
|
85
|
-
fetchSpinner
|
|
119
|
+
fetchSpinner?.fail('Failed to fetch component');
|
|
86
120
|
if (err instanceof MagicPathError) {
|
|
87
121
|
throw err;
|
|
88
122
|
}
|
|
@@ -103,8 +137,10 @@ export function registerAddCommand(program) {
|
|
|
103
137
|
// Step 2: Check for existing files
|
|
104
138
|
const existingFiles = checkExistingFiles(componentData.files, componentsPath);
|
|
105
139
|
if (existingFiles.length > 0 && !addOptions.overwrite) {
|
|
106
|
-
|
|
107
|
-
|
|
140
|
+
if (!json) {
|
|
141
|
+
console.log('\nThe following files already exist:');
|
|
142
|
+
existingFiles.forEach((file) => console.log(` - ${file}`));
|
|
143
|
+
}
|
|
108
144
|
if (!addOptions.yes) {
|
|
109
145
|
const { shouldOverwrite } = await prompts({
|
|
110
146
|
type: 'confirm',
|
|
@@ -118,6 +154,12 @@ export function registerAddCommand(program) {
|
|
|
118
154
|
}
|
|
119
155
|
}
|
|
120
156
|
else {
|
|
157
|
+
if (json) {
|
|
158
|
+
throw new MagicPathError(`Files already exist: ${existingFiles.join(', ')}. Use --overwrite to replace.`, {
|
|
159
|
+
code: 'FILES_EXIST',
|
|
160
|
+
suggestion: 'Pass `--overwrite` to replace existing files.',
|
|
161
|
+
});
|
|
162
|
+
}
|
|
121
163
|
console.log('Use --overwrite to replace existing files.');
|
|
122
164
|
return;
|
|
123
165
|
}
|
|
@@ -139,35 +181,100 @@ export function registerAddCommand(program) {
|
|
|
139
181
|
return;
|
|
140
182
|
}
|
|
141
183
|
}
|
|
184
|
+
// Build result data for JSON output
|
|
185
|
+
const filesWritten = componentData.files.map((f) => path.relative(cwd, path.join(componentsPath, f.path)));
|
|
186
|
+
// Extract import info
|
|
187
|
+
const mainFile = componentData.files[0];
|
|
188
|
+
let importStatement;
|
|
189
|
+
let usageStr;
|
|
190
|
+
if (mainFile) {
|
|
191
|
+
const fileName = mainFile.name.replace(/\.tsx?$/, '');
|
|
192
|
+
const importPath = addOptions.path
|
|
193
|
+
? `@/${addOptions.path}/${componentFolderName}/${fileName}`
|
|
194
|
+
: `@/components/magicpath/${componentFolderName}/${fileName}`;
|
|
195
|
+
const exportInfo = extractComponentExports(mainFile.content);
|
|
196
|
+
if (exportInfo) {
|
|
197
|
+
importStatement = generateImportStatement(exportInfo, importPath);
|
|
198
|
+
usageStr = generateUsageExample(exportInfo);
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
importStatement = `import { ${fileName} } from '${importPath}';`;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
// Dry run: return what would happen without writing
|
|
205
|
+
if (addOptions.dryRun) {
|
|
206
|
+
const fileContents = addOptions.inspect || json
|
|
207
|
+
? componentData.files.map((f) => ({
|
|
208
|
+
path: f.path,
|
|
209
|
+
name: f.name,
|
|
210
|
+
content: f.content,
|
|
211
|
+
}))
|
|
212
|
+
: undefined;
|
|
213
|
+
if (json) {
|
|
214
|
+
jsonResult({
|
|
215
|
+
component: componentData.name,
|
|
216
|
+
generatedName: componentData.generatedName,
|
|
217
|
+
filesWritten,
|
|
218
|
+
files: fileContents,
|
|
219
|
+
dependenciesInstalled: componentData.dependencies,
|
|
220
|
+
importStatement,
|
|
221
|
+
usage: usageStr,
|
|
222
|
+
dryRun: true,
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
console.log('\n[Dry run] Would install:');
|
|
226
|
+
console.log(` Component: ${componentData.name}`);
|
|
227
|
+
console.log(` Files: ${filesWritten.join(', ')}`);
|
|
228
|
+
console.log(` Dependencies: ${componentData.dependencies.join(', ') || 'none'}`);
|
|
229
|
+
if (importStatement)
|
|
230
|
+
console.log(` Import: ${importStatement}`);
|
|
231
|
+
// --inspect: show file contents
|
|
232
|
+
if (addOptions.inspect) {
|
|
233
|
+
for (const f of componentData.files) {
|
|
234
|
+
console.log(`\n${'─'.repeat(60)}`);
|
|
235
|
+
console.log(` ${f.path}`);
|
|
236
|
+
console.log(`${'─'.repeat(60)}`);
|
|
237
|
+
console.log(f.content);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
142
242
|
// Step 4: Write component files
|
|
143
|
-
const writeSpinner =
|
|
243
|
+
const writeSpinner = json
|
|
244
|
+
? null
|
|
245
|
+
: brandSpinner('Writing component files...').start();
|
|
144
246
|
try {
|
|
145
247
|
writeComponentFiles(componentData.files, componentsPath, true);
|
|
146
|
-
writeSpinner
|
|
248
|
+
writeSpinner?.succeed(`Wrote ${componentData.files.length} file(s) to ${path.relative(cwd, componentsPath) || '.'}`);
|
|
147
249
|
}
|
|
148
250
|
catch (err) {
|
|
149
|
-
writeSpinner
|
|
251
|
+
writeSpinner?.fail('Failed to write component files');
|
|
150
252
|
throw new MagicPathError('Failed to write component files. Please check permissions and try again.');
|
|
151
253
|
}
|
|
152
254
|
// Step 5: Install utils if needed
|
|
153
255
|
const utilsExists = checkUtilsExists(utilsPath);
|
|
154
256
|
if (!utilsExists && componentData.utils.content) {
|
|
155
|
-
const utilsSpinner =
|
|
257
|
+
const utilsSpinner = json
|
|
258
|
+
? null
|
|
259
|
+
: brandSpinner('Installing utilities...').start();
|
|
156
260
|
try {
|
|
157
261
|
writeUtilsFile(componentData.utils.content, utilsPath);
|
|
158
|
-
utilsSpinner
|
|
262
|
+
utilsSpinner?.succeed(`Wrote utils.ts to ${path.relative(cwd, utilsPath) || '.'}`);
|
|
159
263
|
}
|
|
160
264
|
catch (err) {
|
|
161
|
-
utilsSpinner
|
|
265
|
+
utilsSpinner?.fail('Failed to write utils file');
|
|
162
266
|
logger.debug({ err });
|
|
163
|
-
|
|
164
|
-
|
|
267
|
+
if (!json) {
|
|
268
|
+
console.log(' Warning: Could not write utils.ts. You may need to create it manually.');
|
|
269
|
+
}
|
|
165
270
|
}
|
|
166
271
|
}
|
|
167
272
|
// Step 6: Install dependencies
|
|
273
|
+
const installedDeps = [];
|
|
168
274
|
if (componentData.dependencies.length > 0) {
|
|
169
275
|
try {
|
|
170
276
|
const { installed, skipped } = installPackages(componentData.dependencies, cwd);
|
|
277
|
+
installedDeps.push(...installed);
|
|
171
278
|
if (skipped.length > 0) {
|
|
172
279
|
logger.debug({
|
|
173
280
|
message: 'Skipped already installed packages',
|
|
@@ -177,39 +284,44 @@ export function registerAddCommand(program) {
|
|
|
177
284
|
}
|
|
178
285
|
catch (err) {
|
|
179
286
|
if (err instanceof MagicPathError) {
|
|
180
|
-
|
|
181
|
-
|
|
287
|
+
if (!json)
|
|
288
|
+
console.log(`\n⚠️ ${err.message}`);
|
|
182
289
|
}
|
|
183
290
|
}
|
|
184
291
|
}
|
|
292
|
+
// JSON output
|
|
293
|
+
if (json) {
|
|
294
|
+
jsonResult({
|
|
295
|
+
component: componentData.name,
|
|
296
|
+
generatedName: componentData.generatedName,
|
|
297
|
+
filesWritten,
|
|
298
|
+
dependenciesInstalled: installedDeps,
|
|
299
|
+
importStatement,
|
|
300
|
+
usage: usageStr,
|
|
301
|
+
dryRun: false,
|
|
302
|
+
});
|
|
303
|
+
}
|
|
185
304
|
// Step 7: Show success message and write usage file
|
|
186
305
|
console.log(`\n✅ Successfully added "${componentData.name}" to your project!`);
|
|
187
306
|
console.log(`\nUsage:`);
|
|
188
|
-
// Show import and usage example
|
|
189
|
-
const mainFile = componentData.files[0];
|
|
190
307
|
if (mainFile) {
|
|
191
308
|
const fileName = mainFile.name.replace(/\.tsx?$/, '');
|
|
192
309
|
const importPath = addOptions.path
|
|
193
310
|
? `@/${addOptions.path}/${componentFolderName}/${fileName}`
|
|
194
311
|
: `@/components/magicpath/${componentFolderName}/${fileName}`;
|
|
195
|
-
// Try to extract actual export info from the component source
|
|
196
312
|
const exportInfo = extractComponentExports(mainFile.content);
|
|
197
313
|
if (exportInfo) {
|
|
198
|
-
// Show accurate import statement based on actual exports
|
|
199
314
|
console.log(` ${generateImportStatement(exportInfo, importPath)}`);
|
|
200
315
|
console.log('');
|
|
201
316
|
console.log(` ${generateUsageExample(exportInfo)}`);
|
|
202
|
-
// Show required props hint if there are any
|
|
203
317
|
if (exportInfo.requiredProps.length > 0) {
|
|
204
318
|
console.log('');
|
|
205
319
|
console.log(` Required props: ${exportInfo.requiredProps.join(', ')}`);
|
|
206
320
|
}
|
|
207
321
|
}
|
|
208
322
|
else {
|
|
209
|
-
// Fallback to simple named export assumption
|
|
210
323
|
console.log(` import { ${fileName} } from '${importPath}';`);
|
|
211
324
|
}
|
|
212
|
-
// Write usage.md file to the component folder
|
|
213
325
|
try {
|
|
214
326
|
writeUsageFile(componentsPath, {
|
|
215
327
|
componentName: componentData.name,
|
|
@@ -221,11 +333,12 @@ export function registerAddCommand(program) {
|
|
|
221
333
|
}
|
|
222
334
|
catch (err) {
|
|
223
335
|
logger.debug({ err });
|
|
224
|
-
// Non-fatal - just skip writing the usage file
|
|
225
336
|
}
|
|
226
337
|
}
|
|
227
338
|
}
|
|
228
339
|
catch (err) {
|
|
340
|
+
if (isJsonMode())
|
|
341
|
+
jsonError(err);
|
|
229
342
|
if (err instanceof MagicPathError) {
|
|
230
343
|
console.error(`\n${err.message}`);
|
|
231
344
|
process.exit(1);
|