@myop/cli 0.1.45 → 0.1.46

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.
@@ -0,0 +1,320 @@
1
+ ---
2
+ name: myop-angular-host
3
+ description: "Integrate Myop components into Angular applications using @myop/angular. This skill covers the MyopComponent standalone component, inputs, outputs, content projection, data binding, preloading, auto-generated packages, and local dev setup. Activate when the user is building an Angular app that hosts Myop components, or when you see @myop/angular in package.json."
4
+ ---
5
+
6
+ # Myop Angular Host Integration
7
+
8
+ Embed Myop components in Angular applications using `@myop/angular`.
9
+
10
+ ## When This Skill Activates
11
+
12
+ - `@myop/angular` is in `package.json` dependencies
13
+ - User asks to "add a Myop component to Angular", "integrate Myop in Angular"
14
+ - Files import from `@myop/angular`
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install @myop/angular @myop/sdk
20
+ ```
21
+
22
+ ## Quick Start
23
+
24
+ ### Option 1: Auto-Generated Package (Recommended)
25
+
26
+ ```bash
27
+ npm install https://cloud.myop.dev/npm/{componentId}/angular
28
+ ```
29
+
30
+ ```typescript
31
+ import { MyComponentComponent } from "@myop/my-component";
32
+
33
+ @Component({
34
+ selector: 'app-root',
35
+ standalone: true,
36
+ imports: [MyComponentComponent],
37
+ template: `
38
+ <my-component
39
+ [data]="{ title: 'Hello' }"
40
+ (cta)="onCta($event)"
41
+ />
42
+ `
43
+ })
44
+ export class AppComponent {
45
+ onCta(event: CtaEvent<MyComponentCtaPayloads>) {
46
+ console.log(event.action, event.payload);
47
+ }
48
+ }
49
+ ```
50
+
51
+ The auto-generated package bakes in the `componentId` and exports typed interfaces.
52
+
53
+ ### Option 2: MyopComponent Directly
54
+
55
+ ```typescript
56
+ import { MyopComponent } from "@myop/angular";
57
+
58
+ @Component({
59
+ selector: 'app-root',
60
+ standalone: true,
61
+ imports: [MyopComponent],
62
+ template: `
63
+ <myop-component
64
+ [componentId]="'your-component-id'"
65
+ [data]="data"
66
+ (cta)="onCta($event)"
67
+ />
68
+ `
69
+ })
70
+ export class AppComponent {
71
+ data = { title: 'Hello' };
72
+
73
+ onCta(event: CtaEvent) {
74
+ console.log(event.action, event.payload);
75
+ }
76
+ }
77
+ ```
78
+
79
+ ## Component API
80
+
81
+ **Selector:** `myop-component`
82
+
83
+ **Standalone:** Yes (`standalone: true`) — import directly, no NgModule needed.
84
+
85
+ ### Inputs
86
+
87
+ | Input | Type | Default | Description |
88
+ |-------|------|---------|-------------|
89
+ | `componentId` | `string` | — | Myop component ID (UUID) |
90
+ | `data` | `TData` | — | Data passed to `myop_init_interface`. Reactive via `ngOnChanges` |
91
+ | `fadeDuration` | `number` | `200` | Loader fade-out duration in ms |
92
+ | `autoSize` | `boolean` | `false` | Auto-size container to match iframe content |
93
+ | `environment` | `string` | — | Load from specific environment |
94
+ | `preview` | `boolean` | — | Load unpublished preview version |
95
+ | `on` | `(action, payload) => void` | — | Generic CTA callback |
96
+ | `loader` | `TemplateRef` | — | Custom loader template (input approach) |
97
+ | `fallback` | `TemplateRef` | — | Custom fallback template (input approach) |
98
+ | `componentConfig` | `IComponentInstanceConfig` | — | Direct config object (advanced) |
99
+
100
+ ### Outputs
101
+
102
+ | Output | Payload | Description |
103
+ |--------|---------|-------------|
104
+ | `(load)` | `ITypedMyopComponent<TData, TCtaPayloads>` | Component finished loading |
105
+ | `(error)` | `string` | Load failure message |
106
+ | `(sizeChange)` | `SizeInfo` | Auto-sized component changed dimensions |
107
+ | `(cta)` | `CtaEvent<TCtaPayloads>` | CTA event from component |
108
+
109
+ The `CtaEvent` type:
110
+ ```typescript
111
+ interface CtaEvent<TCtaPayloads> {
112
+ action: keyof TCtaPayloads | string;
113
+ payload: TCtaPayloads[keyof TCtaPayloads] | any;
114
+ }
115
+ ```
116
+
117
+ ## Content Projection (Loader & Fallback)
118
+
119
+ Two approaches — content projection or input binding:
120
+
121
+ ### Content Projection (ng-template)
122
+
123
+ ```html
124
+ <myop-component [componentId]="'...'">
125
+ <ng-template #loader>
126
+ <div class="spinner">Loading...</div>
127
+ </ng-template>
128
+ <ng-template #fallback>
129
+ <div class="error">Failed to load</div>
130
+ </ng-template>
131
+ </myop-component>
132
+ ```
133
+
134
+ ### Input Binding
135
+
136
+ ```typescript
137
+ @Component({
138
+ template: `
139
+ <myop-component [componentId]="'...'" [loader]="loaderTpl">
140
+ </myop-component>
141
+
142
+ <ng-template #loaderTpl>
143
+ <div class="spinner">Loading...</div>
144
+ </ng-template>
145
+ `
146
+ })
147
+ ```
148
+
149
+ Input binding takes precedence over content projection.
150
+
151
+ ## Data Binding
152
+
153
+ The `data` input is tracked via `ngOnChanges`. When the reference changes, `myop_init_interface(data)` is called:
154
+
155
+ ```typescript
156
+ @Component({
157
+ template: `
158
+ <button (click)="increment()">+1</button>
159
+ <myop-component [componentId]="'counter'" [data]="counterData" />
160
+ `
161
+ })
162
+ export class AppComponent {
163
+ count = 0;
164
+ counterData = { count: 0 };
165
+
166
+ increment() {
167
+ this.count++;
168
+ this.counterData = { count: this.count }; // New reference triggers update
169
+ }
170
+ }
171
+ ```
172
+
173
+ **Important:** You must create a new object reference for Angular change detection to trigger. Mutating the existing object won't work with `OnPush` change detection.
174
+
175
+ ## Preloading
176
+
177
+ ```typescript
178
+ import { preloadComponents, isPreloaded } from "@myop/angular";
179
+
180
+ // In app initializer or route guard
181
+ await preloadComponents(["component-id-1", "component-id-2"]);
182
+ await preloadComponents(["component-id-1"], "staging");
183
+
184
+ if (isPreloaded("component-id-1")) {
185
+ console.log("Will render instantly");
186
+ }
187
+ ```
188
+
189
+ ## Configuration Functions
190
+
191
+ ```typescript
192
+ import {
193
+ enableLocalDev,
194
+ setCloudRepositoryUrl,
195
+ setEnvironment,
196
+ } from "@myop/angular";
197
+
198
+ enableLocalDev(); // localhost:9292
199
+ setCloudRepositoryUrl("https://custom"); // Custom URL
200
+ setEnvironment("staging"); // Default environment
201
+ ```
202
+
203
+ ## CTA Event Handling
204
+
205
+ ```typescript
206
+ import { CtaEvent } from "@myop/angular";
207
+
208
+ // Define your component's CTA types
209
+ interface MyCtaPayloads {
210
+ 'task-toggled': { taskId: string; completed: boolean };
211
+ 'task-deleted': { taskId: string };
212
+ }
213
+
214
+ @Component({
215
+ template: `
216
+ <myop-component
217
+ [componentId]="'task-list'"
218
+ [data]="{ tasks }"
219
+ (cta)="onCta($event)"
220
+ />
221
+ `
222
+ })
223
+ export class TaskListHost {
224
+ tasks = [{ id: '1', title: 'Review PR', completed: false }];
225
+
226
+ onCta(event: CtaEvent<MyCtaPayloads>) {
227
+ switch (event.action) {
228
+ case 'task-toggled':
229
+ // event.payload typed as { taskId: string; completed: boolean }
230
+ break;
231
+ case 'task-deleted':
232
+ // event.payload typed as { taskId: string }
233
+ break;
234
+ }
235
+ }
236
+ }
237
+ ```
238
+
239
+ ## Auto-Generated Angular Package
240
+
241
+ ```bash
242
+ npm install https://cloud.myop.dev/npm/{componentId}/angular
243
+ ```
244
+
245
+ The generated package exports:
246
+ - `MyComponentComponent` — standalone Angular component with `componentId` baked in
247
+ - `MyComponentData` — typed data interface (from `MyopInitData`)
248
+ - `MyComponentCtaPayloads` — typed CTA payloads
249
+ - `MyComponentTypedComponent` — typed component instance interface
250
+ - `COMPONENT_ID` — the component ID constant
251
+
252
+ The generated component:
253
+ - Selector is auto-derived from name (e.g., `my-component`)
254
+ - `standalone: true`, imports `MyopComponent` from `@myop/angular`
255
+ - All inputs/outputs forwarded
256
+
257
+ ## Complete Example
258
+
259
+ ```typescript
260
+ import { Component } from '@angular/core';
261
+ import { MyopComponent, preloadComponents, type CtaEvent } from '@myop/angular';
262
+
263
+ preloadComponents(['sidebar-abc123']);
264
+
265
+ @Component({
266
+ selector: 'app-dashboard',
267
+ standalone: true,
268
+ imports: [MyopComponent],
269
+ template: `
270
+ <div style="display: flex; height: 100vh">
271
+ <myop-component
272
+ [componentId]="'sidebar-abc123'"
273
+ [data]="{ tasks: tasks }"
274
+ (cta)="handleCta($event)"
275
+ (load)="onLoaded($event)"
276
+ (error)="onError($event)"
277
+ style="width: 300px"
278
+ >
279
+ <ng-template #loader>
280
+ <div>Loading sidebar...</div>
281
+ </ng-template>
282
+ </myop-component>
283
+ </div>
284
+ `
285
+ })
286
+ export class DashboardComponent {
287
+ tasks = [
288
+ { id: '1', title: 'Review PR', completed: false },
289
+ { id: '2', title: 'Deploy', completed: true },
290
+ ];
291
+
292
+ handleCta(event: CtaEvent) {
293
+ if (event.action === 'task-toggled') {
294
+ const task = this.tasks.find(t => t.id === event.payload.taskId);
295
+ if (task) task.completed = event.payload.completed;
296
+ }
297
+ }
298
+
299
+ onLoaded(component: any) {
300
+ console.log('Component loaded:', component.id);
301
+ }
302
+
303
+ onError(error: string) {
304
+ console.error('Failed:', error);
305
+ }
306
+ }
307
+ ```
308
+
309
+ ## TypeScript Types
310
+
311
+ ```typescript
312
+ import type {
313
+ IPropTypes, // Full props type
314
+ ITypedMyopComponent, // Component instance with typed props
315
+ IMyopComponentProps, // myop_init_interface + myop_cta_handler
316
+ CtaEvent, // { action, payload } event type
317
+ SizeInfo, // { width, height, autoSizingWidth, autoSizingHeight }
318
+ IComponentInstanceConfig,
319
+ } from "@myop/angular";
320
+ ```
@@ -218,7 +218,9 @@ project/
218
218
  |---------|-------------|
219
219
  | `myop create` | Create a new component (scaffolds files + starts dev server) |
220
220
  | `myop dev` | Start development server with HMR on port 9292 |
221
- | `myop push` | Upload component to Myop platform |
221
+ | `myop push [componentId]` | Upload component to Myop platform (optional ID overrides config) |
222
+ | `myop pull [componentId]` | Download component HTML from Myop platform |
223
+ | `myop list [--org <orgId>]` | Browse, search, and batch pull/push remote components |
222
224
  | `myop sync` | Build and upload component to Myop platform |
223
225
  | `myop login` | Authenticate with Myop (opens browser) |
224
226
  | `myop logout` | Clear stored credentials |
@@ -231,24 +233,30 @@ project/
231
233
  ### What push does
232
234
 
233
235
  1. Reads `myop.config.json` to identify the component
234
- 2. Locates the HTML file (`index.html` for single-file mode, `dist/index.html` for multi-file)
235
- 3. Authenticates with Myop (prompts login if needed)
236
- 4. Uploads the HTML via a presigned URL
237
- 5. On first push: assigns a real `componentId` (UUID) and `organization` to `myop.config.json`
238
- 6. On subsequent pushes: adds a new version to the existing component
236
+ 2. If a `componentId` argument is passed, it overrides the one in config
237
+ 3. Locates the HTML file (`index.html` for single-file mode, `dist/index.html` for multi-file)
238
+ 4. Authenticates with Myop (prompts login if needed)
239
+ 5. Uploads the HTML via a presigned URL
240
+ 6. On first push: assigns a real `componentId` (UUID) and `organization` to `myop.config.json`
241
+ 7. On subsequent pushes: adds a new version to the existing component
239
242
 
240
243
  ### Running push
241
244
 
242
245
  From the component's project directory:
243
246
 
244
247
  ```bash
248
+ # Push using componentId from myop.config.json
245
249
  myop push
250
+
251
+ # Push to a specific remote component (overrides config)
252
+ myop push <componentId>
246
253
  ```
247
254
 
248
255
  Or using npx (no global install needed):
249
256
 
250
257
  ```bash
251
258
  npx @myop/cli push
259
+ npx @myop/cli push <componentId>
252
260
  ```
253
261
 
254
262
  ### When the user asks to push
@@ -267,6 +275,65 @@ When the user says **"push to myop"**, **"deploy"**, **"upload"**, or **"run the
267
275
  - **What goes live** — The full HTML file is uploaded as-is. All CTA handlers, type definitions, styles, and preview scripts are included. The host application picks up changes automatically on next load (no host redeploy).
268
276
  - **Multi-file projects** — For projects with a build step, run `myop sync` instead (which runs `npm run build` first, then uploads `dist/index.html`).
269
277
 
278
+ ## Downloading with `myop pull`
279
+
280
+ `myop pull` downloads a component's latest HTML from the Myop platform into your local directory.
281
+
282
+ ### Running pull
283
+
284
+ ```bash
285
+ # Pull using componentId from myop.config.json
286
+ myop pull
287
+
288
+ # Pull a specific component by ID (works in empty directories)
289
+ myop pull <componentId>
290
+
291
+ # Pull to a custom output path
292
+ myop pull <componentId> -o ./components/sidebar/index.html
293
+ ```
294
+
295
+ ### When the user asks to pull
296
+
297
+ When the user says **"pull from myop"**, **"download component"**, or **"get the latest version"**, you should:
298
+
299
+ 1. `cd` into the component's project directory (or an empty directory for a new clone)
300
+ 2. Run `npx @myop/cli pull` (or `npx @myop/cli pull <componentId>` if pulling a specific component)
301
+ 3. Report the saved file path and size
302
+
303
+ ### Pull behavior
304
+
305
+ - **Existing directory** — overwrites `index.html` (or `dist/index.html` if it exists) with the latest remote version
306
+ - **Empty directory** — creates `index.html` + `myop.config.json` with component metadata
307
+ - **Custom output** — use `-o <path>` to write the HTML to a specific file; parent directories are created automatically
308
+
309
+ ## Browsing with `myop list`
310
+
311
+ `myop list` lets you browse all components in your organization, search and filter, select multiple, and batch pull or push them.
312
+
313
+ ### Running list
314
+
315
+ ```bash
316
+ # Interactive browse (prompts for org if multiple)
317
+ myop list
318
+
319
+ # Specify an organization
320
+ myop list --org <orgId>
321
+ ```
322
+
323
+ ### When the user asks to list or browse
324
+
325
+ When the user says **"show my components"**, **"list components"**, **"browse"**, or **"clone all components"**, you should:
326
+
327
+ 1. Run `npx @myop/cli list` via the terminal
328
+ 2. The interactive UI handles org selection, search, and batch operations
329
+
330
+ ### List behavior
331
+
332
+ - **Organization memory** — the selected org is saved to `~/.myop/preferences.json` and reused next time
333
+ - **Search** — type to filter components by name, select with enter, repeat across searches
334
+ - **Batch pull** — downloads all selected components in parallel, each into its own subdirectory with `index.html` + `myop.config.json`
335
+ - **Batch push** — scans local directories for matching `componentId`s and uploads them in parallel
336
+
270
337
  ## Workflow Summary
271
338
 
272
339
  1. `myop create` - Scaffold a new component
@@ -25,7 +25,9 @@ After installation, the `myop` command is available globally.
25
25
  |---------|-------------|
26
26
  | `myop create` | Create a new component (interactive, starts dev server after) |
27
27
  | `myop dev` | Start dev server with file watching and HMR |
28
- | `myop push` | Upload component to Myop platform |
28
+ | `myop push [componentId]` | Upload component to Myop platform |
29
+ | `myop pull [componentId]` | Download component HTML from Myop platform |
30
+ | `myop list [--org <orgId>]` | Browse, search, and batch pull/push remote components |
29
31
  | `myop sync` | Build and upload component to Myop platform |
30
32
  | `myop login` | Authenticate with Myop (opens browser for OAuth) |
31
33
  | `myop logout` | Clear stored credentials |
@@ -110,16 +112,21 @@ The dev server detects changes and triggers builds automatically:
110
112
  Uploads the component directly to the Myop platform (no build step).
111
113
 
112
114
  ```bash
115
+ # Push using componentId from myop.config.json
113
116
  myop push
117
+
118
+ # Push to a specific remote component (overrides myop.config.json)
119
+ myop push <componentId>
114
120
  ```
115
121
 
116
122
  **What it does:**
117
123
  1. Reads `myop.config.json`
118
- 2. Finds the HTML file to upload (`index.html` in root for single-file mode, or `dist/index.html`)
119
- 3. Authenticates (prompts for login if needed)
120
- 4. Uploads HTML to Myop via presigned URL
121
- 5. Confirms upload
122
- 6. Updates `myop.config.json` with `componentId` (first push only)
124
+ 2. If a `componentId` argument is passed, it overrides the one in config
125
+ 3. Finds the HTML file to upload (`index.html` in root for single-file mode, or `dist/index.html`)
126
+ 4. Authenticates (prompts for login if needed)
127
+ 5. Uploads HTML to Myop via presigned URL
128
+ 6. Confirms upload
129
+ 7. Updates `myop.config.json` with `componentId` (first push only)
123
130
 
124
131
  **After first push:**
125
132
  - `myop.config.json` gets a real `componentId` (UUID)
@@ -131,6 +138,64 @@ myop push
131
138
  https://dashboard.myop.dev/dashboard/2.0/component/<componentId>
132
139
  ```
133
140
 
141
+ ## Pull Command
142
+
143
+ Downloads a component's HTML from the Myop platform.
144
+
145
+ ```bash
146
+ # Pull using componentId from myop.config.json
147
+ myop pull
148
+
149
+ # Pull a specific component by ID
150
+ myop pull <componentId>
151
+
152
+ # Pull to a specific output path
153
+ myop pull <componentId> -o ./my-component/index.html
154
+ ```
155
+
156
+ **What it does:**
157
+ 1. Determines `componentId` from the argument or `myop.config.json`
158
+ 2. Authenticates (prompts for login if needed)
159
+ 3. Fetches the component HTML from Myop
160
+ 4. Writes the HTML to `index.html` (or `dist/index.html` if it exists, or `-o` path)
161
+ 5. Creates or updates `myop.config.json` with the component metadata
162
+
163
+ **Use cases:**
164
+ - **Clone a remote component locally** — `myop pull <componentId>` in an empty directory creates `index.html` + `myop.config.json`
165
+ - **Sync latest version** — run `myop pull` in an existing component directory to get the latest remote version
166
+ - **Download to custom path** — use `-o` flag to specify where the HTML file should be saved
167
+
168
+ ## List Command
169
+
170
+ Browse all components in your organization, search and filter, select multiple, then batch pull or push.
171
+
172
+ ```bash
173
+ # Interactive browse (prompts for org if needed)
174
+ myop list
175
+
176
+ # Use a specific organization
177
+ myop list --org <orgId>
178
+ ```
179
+
180
+ **What it does:**
181
+ 1. Authenticates and loads your organizations
182
+ 2. Resolves which org to use (saved default, `--org` flag, or prompts)
183
+ 3. Fetches all components in the organization
184
+ 4. Shows a searchable list — type to filter, enter to select, repeat
185
+ 5. When done selecting, choose Pull or Push
186
+ 6. **Pull** — downloads all selected components in parallel, each into its own subdirectory with `index.html` + `myop.config.json`
187
+ 7. **Push** — scans local directories for matching `componentId`s and uploads them in parallel
188
+
189
+ **Batch pull example** (great for cloning an environment):
190
+ ```bash
191
+ mkdir my-components && cd my-components
192
+ myop list
193
+ # Select components, choose Pull
194
+ # Each component gets its own subdirectory
195
+ ```
196
+
197
+ **Organization memory** — the selected org is saved to `~/.myop/preferences.json` so you don't have to pick it every time.
198
+
134
199
  ## Sync Command
135
200
 
136
201
  Builds and uploads the component to the Myop platform (for multi-file projects with a build step).