@nometria-ai/nom 0.1.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.
@@ -0,0 +1,854 @@
1
+ /**
2
+ * nom setup — Generate AI tool config files for every major IDE/agent.
3
+ *
4
+ * Creates:
5
+ * .cursor/rules/nometria.mdc — Cursor AI rules
6
+ * .clinerules — Cline / Roo Code
7
+ * .windsurfrules — Windsurf (Codeium)
8
+ * .github/copilot-instructions.md — GitHub Copilot
9
+ * .github/workflows/nometria-deploy.yml — Auto-deploy on push
10
+ * CLAUDE.md — Claude Code project instructions
11
+ * AGENTS.md — Universal agent deployment guide
12
+ * .claude/commands/deploy.md — Claude Code /deploy slash command
13
+ * .claude/commands/preview.md — Claude Code /preview slash command
14
+ * .claude/commands/status.md — Claude Code /status slash command
15
+ * .claude/commands/nometria-login.md — Claude Code /nometria-login slash command
16
+ * .continue/config.json — Continue.dev MCP config
17
+ */
18
+ import { mkdirSync, writeFileSync, existsSync, readFileSync } from 'node:fs';
19
+ import { join } from 'node:path';
20
+
21
+ export async function setup(flags) {
22
+ const dir = process.cwd();
23
+
24
+ // Read nometria.json if it exists
25
+ let config = { name: 'my-app', platform: 'aws', region: 'us-east-1' };
26
+ const configPath = join(dir, 'nometria.json');
27
+ if (existsSync(configPath)) {
28
+ try {
29
+ config = { ...config, ...JSON.parse(readFileSync(configPath, 'utf8')) };
30
+ } catch { /* use defaults */ }
31
+ }
32
+
33
+ const appName = config.name || 'my-app';
34
+ const platform = config.platform || 'aws';
35
+
36
+ console.log('\n Setting up AI tool integrations for Nometria\n');
37
+
38
+ const files = [];
39
+
40
+ // 1. Cursor rules
41
+ const cursorDir = join(dir, '.cursor', 'rules');
42
+ mkdirSync(cursorDir, { recursive: true });
43
+ writeFileSync(join(cursorDir, 'nometria.mdc'), cursorRules(appName, platform));
44
+ files.push('.cursor/rules/nometria.mdc');
45
+
46
+ // 2. Cline rules
47
+ writeFileSync(join(dir, '.clinerules'), clineRules(appName, platform));
48
+ files.push('.clinerules');
49
+
50
+ // 3. Windsurf rules
51
+ writeFileSync(join(dir, '.windsurfrules'), windsurfRules(appName, platform));
52
+ files.push('.windsurfrules');
53
+
54
+ // 4. GitHub Copilot instructions
55
+ const githubDir = join(dir, '.github');
56
+ mkdirSync(githubDir, { recursive: true });
57
+ writeFileSync(join(githubDir, 'copilot-instructions.md'), copilotInstructions(appName, platform));
58
+ files.push('.github/copilot-instructions.md');
59
+
60
+ // 5. GitHub Action for auto-deploy
61
+ const workflowDir = join(dir, '.github', 'workflows');
62
+ mkdirSync(workflowDir, { recursive: true });
63
+ writeFileSync(join(workflowDir, 'nometria-deploy.yml'), deployAction(appName));
64
+ files.push('.github/workflows/nometria-deploy.yml');
65
+
66
+ // 6. CLAUDE.md
67
+ writeFileSync(join(dir, 'CLAUDE.md'), claudeMd(appName, platform));
68
+ files.push('CLAUDE.md');
69
+
70
+ // 7. AGENTS.md — universal agent guide
71
+ writeFileSync(join(dir, 'AGENTS.md'), agentsMd(appName, platform));
72
+ files.push('AGENTS.md');
73
+
74
+ // 8. Claude Code slash commands
75
+ const claudeCommandsDir = join(dir, '.claude', 'commands');
76
+ mkdirSync(claudeCommandsDir, { recursive: true });
77
+ writeFileSync(join(claudeCommandsDir, 'deploy.md'), claudeCommandDeploy());
78
+ files.push('.claude/commands/deploy.md');
79
+ writeFileSync(join(claudeCommandsDir, 'preview.md'), claudeCommandPreview());
80
+ files.push('.claude/commands/preview.md');
81
+ writeFileSync(join(claudeCommandsDir, 'status.md'), claudeCommandStatus());
82
+ files.push('.claude/commands/status.md');
83
+ writeFileSync(join(claudeCommandsDir, 'nometria-login.md'), claudeCommandLogin());
84
+ files.push('.claude/commands/nometria-login.md');
85
+
86
+ // 9. Continue.dev config
87
+ const continueDir = join(dir, '.continue');
88
+ mkdirSync(continueDir, { recursive: true });
89
+ const continueConfigPath = join(continueDir, 'config.json');
90
+ writeContinueConfig(continueConfigPath);
91
+ files.push('.continue/config.json');
92
+
93
+ // Print results
94
+ for (const f of files) {
95
+ console.log(` ${f}`);
96
+ }
97
+
98
+ console.log(`
99
+ All AI tools now know how to deploy this project with Nometria.
100
+
101
+ Works with: Cursor, Claude Code, Cline, Windsurf, GitHub Copilot,
102
+ Continue.dev, Aider, and any MCP-compatible tool.
103
+
104
+ Claude Code users can now type:
105
+ /deploy Deploy to production
106
+ /preview Staging preview (free, 2hr)
107
+ /status Check deployment status
108
+ /nometria-login Set up authentication
109
+ `);
110
+ }
111
+
112
+ // ─── Templates ──────────────────────────────────────────────────────────────
113
+
114
+ function cursorRules(appName, platform) {
115
+ return `---
116
+ description: Nometria deployment rules for ${appName}
117
+ globs: ["**/*"]
118
+ alwaysApply: true
119
+ ---
120
+
121
+ # Nometria Deployment
122
+
123
+ This project deploys via **Nometria** (\`nom\` CLI). Configuration is in \`nometria.json\`.
124
+
125
+ ## Deployment Commands
126
+
127
+ | Command | Description |
128
+ |---------|-------------|
129
+ | \`nom deploy\` | Deploy to production (${platform}) |
130
+ | \`nom preview\` | Create staging preview (free, 2hr) |
131
+ | \`nom status\` | Check deployment status |
132
+ | \`nom logs -f\` | Stream live logs |
133
+ | \`nom github connect\` | Connect GitHub for auto-deploy |
134
+
135
+ ## Rules
136
+
137
+ 1. When the user asks to deploy, run \`nom deploy\` in the terminal
138
+ 2. When the user asks for a preview, run \`nom preview\`
139
+ 3. For deployment status, run \`nom status\`
140
+ 4. Environment variables are managed via \`nom env set KEY=VALUE\`
141
+ 5. Never call the Nometria Python API directly — use the \`nom\` CLI
142
+ 6. The deployment config is in \`nometria.json\` — do not modify it without asking
143
+ 7. If not authenticated, run \`nom login\` first (opens browser)
144
+
145
+ ## Quick Reference
146
+
147
+ - App: ${appName}
148
+ - Platform: ${platform}
149
+ - Config: \`nometria.json\`
150
+ - Docs: https://docs.nometria.com
151
+ `;
152
+ }
153
+
154
+ function clineRules(appName, platform) {
155
+ return `# Nometria Deployment Rules
156
+
157
+ This project (${appName}) deploys via Nometria.
158
+
159
+ ## How to Deploy
160
+
161
+ 1. Run \`nom deploy\` to deploy to production (${platform})
162
+ 2. Run \`nom preview\` for a staging preview (free, 2 hours)
163
+ 3. Run \`nom status\` to check deployment status
164
+ 4. Run \`nom logs -f\` to stream live logs
165
+
166
+ ## Important
167
+
168
+ - Configuration is in \`nometria.json\` — read it before making deployment decisions
169
+ - If not authenticated, run \`nom login\` (opens browser for sign-in)
170
+ - Environment variables: \`nom env set KEY=VALUE\` / \`nom env list\`
171
+ - Custom domains: \`nom domain add yourdomain.com\`
172
+ - Instance management: \`nom start\`, \`nom stop\`, \`nom upgrade 8gb\`
173
+ - GitHub auto-deploy: \`nom github connect\`
174
+ - Security scan: \`nom scan\`
175
+ - Never call backend APIs directly — always use the \`nom\` CLI
176
+ - The MCP server \`@nometria-ai/claude-code\` is also available for tool-based access
177
+ `;
178
+ }
179
+
180
+ function windsurfRules(appName, platform) {
181
+ return `# Nometria Deployment
182
+
183
+ This project (${appName}) deploys to ${platform} via Nometria.
184
+
185
+ ## Commands
186
+
187
+ Deploy: \`nom deploy\`
188
+ Preview: \`nom preview\` (free, 2hr expiry)
189
+ Status: \`nom status\`
190
+ Logs: \`nom logs -f\`
191
+ Login: \`nom login\` (opens browser)
192
+ GitHub: \`nom github connect\` (auto-deploy on push)
193
+ Env vars: \`nom env set KEY=VALUE\`
194
+ Scan: \`nom scan\`
195
+ Instance: \`nom start\` / \`nom stop\` / \`nom upgrade <size>\`
196
+ Domain: \`nom domain add yourdomain.com\`
197
+
198
+ ## Config
199
+
200
+ Deployment configuration is in \`nometria.json\`. Do not modify without asking the user.
201
+
202
+ ## Rules
203
+
204
+ - Always use the \`nom\` CLI for deployment operations
205
+ - Never call Nometria APIs directly
206
+ - If the user is not authenticated, run \`nom login\` first
207
+ - Check \`nom status\` before deploying to see current state
208
+ `;
209
+ }
210
+
211
+ function copilotInstructions(appName, platform) {
212
+ return `# Nometria Deployment
213
+
214
+ This project (**${appName}**) deploys to **${platform}** using Nometria.
215
+
216
+ ## Deployment
217
+
218
+ - Deploy: \`nom deploy\`
219
+ - Preview: \`nom preview\` (free staging URL, expires in 2 hours)
220
+ - Status: \`nom status\`
221
+ - Logs: \`nom logs -f\`
222
+
223
+ ## Setup
224
+
225
+ - Config: \`nometria.json\`
226
+ - Login: \`nom login\` (opens browser for authentication)
227
+ - GitHub auto-deploy: \`nom github connect\`
228
+
229
+ ## Management
230
+
231
+ - Environment variables: \`nom env set KEY=VALUE\` / \`nom env list\`
232
+ - Custom domain: \`nom domain add yourdomain.com\`
233
+ - Instance control: \`nom start\` / \`nom stop\` / \`nom upgrade 8gb\`
234
+ - Security scan: \`nom scan\`
235
+
236
+ ## Notes
237
+
238
+ - Always use the \`nom\` CLI — do not call Nometria APIs directly
239
+ - Read \`nometria.json\` for current deployment configuration
240
+ - Install: \`npm i -g @nometria-ai/nom\` or use \`npx @nometria-ai/nom\`
241
+ `;
242
+ }
243
+
244
+ function claudeMd(appName, platform) {
245
+ return `# ${appName}
246
+
247
+ This project deploys via **Nometria** to **${platform}**.
248
+
249
+ ## Deployment
250
+
251
+ \`\`\`bash
252
+ nom deploy # Deploy to production
253
+ nom preview # Staging preview (free, 2hr)
254
+ nom status # Check status
255
+ nom logs -f # Stream logs
256
+ \`\`\`
257
+
258
+ ## Config
259
+
260
+ Deployment configuration is in \`nometria.json\`. Read it before making deployment decisions.
261
+
262
+ ## Full CLI Reference
263
+
264
+ | Command | Description |
265
+ |---------|-------------|
266
+ | \`nom login\` | Sign in via browser |
267
+ | \`nom deploy\` | Deploy to production |
268
+ | \`nom preview\` | Staging preview |
269
+ | \`nom status\` | Deployment status |
270
+ | \`nom logs [-f]\` | View/stream logs |
271
+ | \`nom github connect\` | GitHub OAuth for auto-deploy |
272
+ | \`nom github push -m "msg"\` | Push to GitHub |
273
+ | \`nom start\` / \`nom stop\` | Instance control |
274
+ | \`nom upgrade <size>\` | Resize (2gb/4gb/8gb/16gb) |
275
+ | \`nom domain add <domain>\` | Custom domain |
276
+ | \`nom env set KEY=VALUE\` | Set env var |
277
+ | \`nom env list\` | List env vars |
278
+ | \`nom scan\` | AI security scan |
279
+ | \`nom setup\` | Regenerate AI tool configs |
280
+
281
+ ## MCP Server
282
+
283
+ For tool-based access: \`claude mcp add nometria -- npx @nometria-ai/claude-code\`
284
+
285
+ ## Rules
286
+
287
+ - Use the \`nom\` CLI for all deployment operations
288
+ - Never call backend APIs directly
289
+ - If unauthenticated, run \`nom login\` first
290
+ `;
291
+ }
292
+
293
+ function deployAction(appName) {
294
+ return `name: Deploy to Nometria
295
+
296
+ on:
297
+ push:
298
+ branches: [main]
299
+ workflow_dispatch:
300
+
301
+ jobs:
302
+ deploy:
303
+ runs-on: ubuntu-latest
304
+ steps:
305
+ - uses: actions/checkout@v4
306
+
307
+ - uses: actions/setup-node@v4
308
+ with:
309
+ node-version: '20'
310
+
311
+ - name: Install dependencies
312
+ run: npm ci
313
+
314
+ - name: Deploy
315
+ run: npx @nometria-ai/nom deploy --yes
316
+ env:
317
+ NOMETRIA_API_KEY: \${{ secrets.NOMETRIA_API_KEY }}
318
+ `;
319
+ }
320
+
321
+ // ─── Claude Code Slash Commands ─────────────────────────────────────────────
322
+
323
+ function claudeCommandDeploy() {
324
+ return `---
325
+ allowed-tools: Bash(curl:*), Bash(cat:*), Bash(sleep:*), Bash(echo:*), Bash(grep:*), Read, Write
326
+ description: Deploy your app to production via Nometria
327
+ argument-hint: Optional app name or migration ID
328
+ ---
329
+
330
+ # Deploy to Production
331
+
332
+ You are deploying the user's app to production via the Nometria platform. Execute this workflow precisely.
333
+
334
+ ## Step 1: Resolve API token
335
+
336
+ Find the Nometria API token. Check in this order:
337
+
338
+ \`\`\`bash
339
+ # 1. Environment variables (API key or JWT token)
340
+ echo "$NOMETRIA_API_KEY"
341
+ echo "$NOMETRIA_TOKEN"
342
+
343
+ # 2. .env file in current project
344
+ grep -s 'NOMETRIA_API_KEY\\|NOMETRIA_TOKEN' .env .env.local 2>/dev/null
345
+
346
+ # 3. Stored credentials from \\\`nom login\\\`
347
+ cat ~/.nometria/credentials.json 2>/dev/null
348
+
349
+ # 4. Home directory config (legacy)
350
+ cat ~/.nometria 2>/dev/null
351
+ \`\`\`
352
+
353
+ If no token is found, tell the user:
354
+
355
+ > No Nometria API token found. Run \\\`nom login\\\` or \\\`/nometria-login\\\` to authenticate.
356
+ > Get your API key at https://ownmy.app/settings/api-keys
357
+
358
+ **Stop here if no token.** Do not proceed without a valid token.
359
+
360
+ Store the token: \\\`TOKEN="<the token>"\\\`
361
+
362
+ ## Step 2: Identify the app
363
+
364
+ Check if there's a \\\`nometria.json\\\` in the workspace root:
365
+ \`\`\`bash
366
+ cat nometria.json 2>/dev/null
367
+ \`\`\`
368
+
369
+ If it exists, extract \\\`app_id\\\` and \\\`migration_id\\\` from it.
370
+
371
+ If not, or if the user specified an app name as \\\`$ARGUMENTS\\\`, list all migrations:
372
+
373
+ \`\`\`bash
374
+ curl -s -X POST https://app.ownmy.app/listUserMigrations \\
375
+ -H "Content-Type: application/json" \\
376
+ -H "Authorization: Bearer $TOKEN" \\
377
+ -d '{}'
378
+ \`\`\`
379
+
380
+ From the response, find the matching migration. If multiple apps exist and the user didn't specify which one, show a numbered list and ask them to pick.
381
+
382
+ Only proceed with migrations that have \\\`delivery_type: "hosting"\\\` and \\\`payment_status: "paid"\\\`.
383
+
384
+ Store: \\\`APP_ID="<app_id>"\\\` and \\\`MIGRATION_ID="<migration_id>"\\\`
385
+
386
+ ## Step 3: Check current deployment status
387
+
388
+ \`\`\`bash
389
+ curl -s -X POST https://app.ownmy.app/checkAwsStatus \\
390
+ -H "Content-Type: application/json" \\
391
+ -H "Authorization: Bearer $TOKEN" \\
392
+ -d "{\\"app_id\\": \\"$APP_ID\\"}"
393
+ \`\`\`
394
+
395
+ Parse the response to determine the instance state.
396
+
397
+ ## Step 4: Deploy or resync
398
+
399
+ **If instance is running** (\\\`data.instanceState === "running"\\\`):
400
+
401
+ Tell the user: "App is already running. Resyncing code to production..."
402
+
403
+ \`\`\`bash
404
+ curl -s -X POST https://app.ownmy.app/resyncHosting \\
405
+ -H "Content-Type: application/json" \\
406
+ -H "Authorization: Bearer $TOKEN" \\
407
+ -d "{\\"app_id\\": \\"$APP_ID\\"}"
408
+ \`\`\`
409
+
410
+ **If instance is stopped** (\\\`data.instanceState === "stopped"\\\`):
411
+
412
+ Tell the user: "Instance is stopped. Starting and resyncing..."
413
+
414
+ \`\`\`bash
415
+ curl -s -X POST https://app.ownmy.app/updateInstanceState \\
416
+ -H "Content-Type: application/json" \\
417
+ -H "Authorization: Bearer $TOKEN" \\
418
+ -d "{\\"app_id\\": \\"$APP_ID\\", \\"instance_state\\": \\"start\\"}"
419
+ \`\`\`
420
+
421
+ Then resync once it's running.
422
+
423
+ **If not deployed** (\\\`status === "not_deployed"\\\`):
424
+
425
+ Tell the user: "Deploying new production instance..."
426
+
427
+ \`\`\`bash
428
+ curl -s -X POST https://app.ownmy.app/deployToAws \\
429
+ -H "Content-Type: application/json" \\
430
+ -H "Authorization: Bearer $TOKEN" \\
431
+ -d "{\\"migration_id\\": \\"$MIGRATION_ID\\"}"
432
+ \`\`\`
433
+
434
+ ## Step 5: Poll for completion
435
+
436
+ Poll every 5 seconds until the deployment reaches a terminal state:
437
+
438
+ \`\`\`bash
439
+ curl -s -X POST https://app.ownmy.app/checkAwsStatus \\
440
+ -H "Content-Type: application/json" \\
441
+ -H "Authorization: Bearer $TOKEN" \\
442
+ -d "{\\"app_id\\": \\"$APP_ID\\"}"
443
+ \`\`\`
444
+
445
+ Terminal states:
446
+ - \\\`instanceState: "running"\\\` -> **Success**
447
+ - \\\`deploymentStatus: "failed"\\\` -> **Failure** (report \\\`errorMessage\\\`)
448
+ - \\\`instanceState: "terminated"\\\` -> **Failure**
449
+
450
+ Poll up to 60 times (5 minutes). Report progress every 3 polls.
451
+
452
+ ## Step 6: Report result
453
+
454
+ **On success**, display:
455
+
456
+ \`\`\`
457
+ Deployed successfully!
458
+
459
+ App: <app_name>
460
+ URL: <deployUrl or hosted_url>
461
+ IP: <ipAddress>
462
+ Type: <instanceType>
463
+ \`\`\`
464
+
465
+ **On failure**, display the error and suggest checking the Nometria dashboard.
466
+
467
+ ## Step 7: Save workspace config
468
+
469
+ If \\\`nometria.json\\\` doesn't exist, create it so future deploys are faster:
470
+
471
+ \`\`\`json
472
+ {
473
+ "app_id": "<APP_ID>",
474
+ "migration_id": "<MIGRATION_ID>",
475
+ "app_name": "<app_name>",
476
+ "api_url": "https://app.ownmy.app"
477
+ }
478
+ \`\`\`
479
+
480
+ Do all of the above. Execute every curl call and report results to the user.
481
+ `;
482
+ }
483
+
484
+ function claudeCommandPreview() {
485
+ return `---
486
+ allowed-tools: Bash(curl:*), Bash(cat:*), Bash(grep:*), Bash(echo:*), Read
487
+ description: Deploy a staging preview of your app via Nometria
488
+ argument-hint: Optional app name
489
+ ---
490
+
491
+ # Deploy Staging Preview
492
+
493
+ You are creating a temporary staging preview of the user's app. This is free and creates a short-lived URL.
494
+
495
+ ## Step 1: Resolve token
496
+
497
+ \`\`\`bash
498
+ TOKEN="\${NOMETRIA_API_KEY:-\${NOMETRIA_TOKEN:-$(grep -s 'NOMETRIA_API_KEY\\|NOMETRIA_TOKEN' .env .env.local 2>/dev/null | head -1 | cut -d= -f2- | tr -d ' "'"'"'')}}"
499
+ echo "Token found: $([ -n "$TOKEN" ] && echo 'yes' || echo 'no')"
500
+ \`\`\`
501
+
502
+ If no token: tell the user to run \\\`nom login\\\` or \\\`/nometria-login\\\` and stop.
503
+
504
+ ## Step 2: Identify the app
505
+
506
+ \`\`\`bash
507
+ # Try workspace config first
508
+ cat nometria.json 2>/dev/null
509
+ \`\`\`
510
+
511
+ If no \\\`nometria.json\\\`, list migrations:
512
+
513
+ \`\`\`bash
514
+ curl -s -X POST https://app.ownmy.app/listUserMigrations \\
515
+ -H "Content-Type: application/json" \\
516
+ -H "Authorization: Bearer $TOKEN" \\
517
+ -d '{}'
518
+ \`\`\`
519
+
520
+ Pick the correct migration. If \\\`$ARGUMENTS\\\` was provided, match by app name. Otherwise, if multiple exist, ask the user. Store \\\`MIGRATION_ID\\\`.
521
+
522
+ ## Step 3: Deploy preview
523
+
524
+ \`\`\`bash
525
+ curl -s -X POST https://app.ownmy.app/deployStagingPreview \\
526
+ -H "Content-Type: application/json" \\
527
+ -H "Authorization: Bearer $TOKEN" \\
528
+ -d "{\\"migration_id\\": \\"$MIGRATION_ID\\", \\"production\\": false}"
529
+ \`\`\`
530
+
531
+ ## Step 4: Report result
532
+
533
+ Parse the response. On success, display:
534
+
535
+ \`\`\`
536
+ Preview deployed!
537
+
538
+ URL: <preview_url>
539
+ Expires: ~2 hours
540
+
541
+ This is a temporary preview. Use /deploy for production.
542
+ \`\`\`
543
+
544
+ On failure, show the error message and suggest checking the dashboard.
545
+
546
+ Execute all curl commands and report the results.
547
+ `;
548
+ }
549
+
550
+ function claudeCommandStatus() {
551
+ return `---
552
+ allowed-tools: Bash(curl:*), Bash(cat:*), Bash(grep:*), Bash(echo:*), Read
553
+ description: Check deployment status of your Nometria apps
554
+ argument-hint: Optional app name to filter
555
+ ---
556
+
557
+ # Check Deployment Status
558
+
559
+ Show the user the current state of their Nometria deployments.
560
+
561
+ ## Step 1: Resolve token
562
+
563
+ \`\`\`bash
564
+ TOKEN="\${NOMETRIA_API_KEY:-\${NOMETRIA_TOKEN:-$(grep -s 'NOMETRIA_API_KEY\\|NOMETRIA_TOKEN' .env .env.local 2>/dev/null | head -1 | cut -d= -f2- | tr -d ' "'"'"'')}}"
565
+ \`\`\`
566
+
567
+ If no token: tell the user to run \\\`/nometria-login\\\` and stop.
568
+
569
+ ## Step 2: List all migrations
570
+
571
+ \`\`\`bash
572
+ curl -s -X POST https://app.ownmy.app/listUserMigrations \\
573
+ -H "Content-Type: application/json" \\
574
+ -H "Authorization: Bearer $TOKEN" \\
575
+ -d '{}'
576
+ \`\`\`
577
+
578
+ ## Step 3: Check AWS status for hosting apps
579
+
580
+ For each migration with \\\`delivery_type: "hosting"\\\`, check its status:
581
+
582
+ \`\`\`bash
583
+ curl -s -X POST https://app.ownmy.app/checkAwsStatus \\
584
+ -H "Content-Type: application/json" \\
585
+ -H "Authorization: Bearer $TOKEN" \\
586
+ -d "{\\"app_id\\": \\"<APP_ID>\\"}"
587
+ \`\`\`
588
+
589
+ ## Step 4: Display formatted table
590
+
591
+ Present results as a clear table showing App, Platform, Status, URL, and Instance.
592
+
593
+ Use these status indicators:
594
+ - running — app is live
595
+ - deploying / launching — deployment in progress
596
+ - stopped — instance exists but is off
597
+ - failed — deployment failed (show error if available)
598
+ - none — not deployed to hosting
599
+
600
+ If \\\`$ARGUMENTS\\\` was provided, filter the results to match that app name.
601
+
602
+ Also show totals: Total apps, Running, Stopped.
603
+
604
+ If there's a \\\`nometria.json\\\` in the workspace, highlight the linked app.
605
+
606
+ Execute all the curl calls and display the results.
607
+ `;
608
+ }
609
+
610
+ function claudeCommandLogin() {
611
+ return `---
612
+ allowed-tools: Bash(echo:*), Bash(cat:*), Bash(grep:*), Read, Write
613
+ description: Authenticate with the Nometria deployment platform
614
+ ---
615
+
616
+ # Nometria Login
617
+
618
+ Help the user set up their Nometria API token for deployments.
619
+
620
+ ## Step 1: Check existing token
621
+
622
+ \`\`\`bash
623
+ # Check environment (API key or JWT)
624
+ echo "API_KEY: $([ -n "$NOMETRIA_API_KEY" ] && echo 'set' || echo 'not set')"
625
+ echo "TOKEN: $([ -n "$NOMETRIA_TOKEN" ] && echo 'set' || echo 'not set')"
626
+
627
+ # Check .env
628
+ grep -s 'NOMETRIA_API_KEY\\|NOMETRIA_TOKEN' .env .env.local 2>/dev/null && echo "Found in .env" || echo ".env: not found"
629
+
630
+ # Check nom CLI credentials
631
+ cat ~/.nometria/credentials.json 2>/dev/null && echo "Found ~/.nometria/credentials.json" || echo "~/.nometria/credentials.json: not found"
632
+ \`\`\`
633
+
634
+ If a token already exists, tell the user they're already authenticated and show which source it was found in. Ask if they want to update it.
635
+
636
+ ## Step 2: Get the token
637
+
638
+ Tell the user:
639
+
640
+ > To get your Nometria API key:
641
+ >
642
+ > 1. Go to **https://ownmy.app/settings/api-keys**
643
+ > 2. Sign in to your account
644
+ > 3. Click **Generate New Key**
645
+ > 4. Copy the key and paste it here
646
+ >
647
+ > Your key is stored locally and never sent anywhere except the Nometria API.
648
+ > Alternatively, you can use \\\`nom login\\\` from the CLI.
649
+
650
+ Wait for the user to provide the token. They will paste it in the chat.
651
+
652
+ ## Step 3: Validate the token
653
+
654
+ Once the user provides a token, validate it:
655
+
656
+ \`\`\`bash
657
+ curl -s -X POST https://app.ownmy.app/listUserMigrations \\
658
+ -H "Content-Type: application/json" \\
659
+ -H "Authorization: Bearer <USER_TOKEN>" \\
660
+ -d '{}'
661
+ \`\`\`
662
+
663
+ If the response contains \\\`"success": true\\\`, the token is valid.
664
+
665
+ ## Step 4: Store the token
666
+
667
+ If the current directory has a \\\`.env\\\` file, append \\\`NOMETRIA_API_KEY=<key>\\\` to it.
668
+ If no \\\`.env\\\` exists, create \\\`.env\\\` with the key.
669
+ Warn the user if \\\`.env\\\` is not in \\\`.gitignore\\\`.
670
+
671
+ ## Step 5: Confirm
672
+
673
+ Tell the user they're authenticated and show available commands:
674
+ /deploy - Deploy to production
675
+ /preview - Deploy staging preview
676
+ /status - Check deployment status
677
+ nom deploy - Deploy from CLI
678
+ `;
679
+ }
680
+
681
+ // ─── AGENTS.md ──────────────────────────────────────────────────────────────
682
+
683
+ function agentsMd(appName, platform) {
684
+ return `# Nometria Agent Deployment Guide
685
+
686
+ > Deploy any app to any cloud from your IDE, CLI, or AI agent. Works with VS Code, Cursor, Claude Code, and any tool that can run \\\`curl\\\` or \\\`npx\\\`.
687
+
688
+ ## Quick Start — CLI (recommended)
689
+
690
+ \`\`\`bash
691
+ # Install and deploy in seconds
692
+ npx @nometria-ai/nom login
693
+ npx @nometria-ai/nom init
694
+ npx @nometria-ai/nom deploy
695
+ \`\`\`
696
+
697
+ ## Quick Start — curl (for AI agents)
698
+
699
+ \`\`\`bash
700
+ # 1. Set your token (API key or JWT)
701
+ export NOMETRIA_API_KEY="nometria_sk_..." # from https://ownmy.app/settings/api-keys
702
+
703
+ # 2. List your apps
704
+ curl -s -X POST https://app.ownmy.app/listUserMigrations \\
705
+ -H "Content-Type: application/json" \\
706
+ -H "Authorization: Bearer $NOMETRIA_API_KEY" -d '{}'
707
+
708
+ # 3. Deploy to production (resync if already running)
709
+ curl -s -X POST https://app.ownmy.app/resyncHosting \\
710
+ -H "Content-Type: application/json" \\
711
+ -H "Authorization: Bearer $NOMETRIA_API_KEY" \\
712
+ -d '{"app_id": "YOUR_APP_ID"}'
713
+ \`\`\`
714
+
715
+ ---
716
+
717
+ ## Developer Surfaces
718
+
719
+ | Surface | Install | Auth |
720
+ |---------|---------|------|
721
+ | **nom CLI** | \\\`npx @nometria-ai/nom\\\` | API key (\\\`NOMETRIA_API_KEY\\\`) |
722
+ | **VS Code/Cursor** | Extensions marketplace | OAuth login |
723
+ | **Claude Code** | \\\`/deploy\\\`, \\\`/preview\\\`, \\\`/status\\\` | API key or JWT |
724
+ | **Any AI agent** | curl | API key or JWT |
725
+
726
+ ---
727
+
728
+ ## Authentication
729
+
730
+ Every API call requires \\\`Authorization: Bearer <token>\\\` header. Both API keys (\\\`nometria_sk_...\\\`) and JWT tokens are accepted.
731
+
732
+ **Getting an API key:**
733
+ 1. Sign in at https://ownmy.app/settings/api-keys
734
+ 2. Go to Settings -> API Token
735
+ 3. Copy and store as \\\`NOMETRIA_API_KEY\\\` environment variable
736
+
737
+ **Base URL:** \\\`https://app.ownmy.app\\\`
738
+
739
+ All endpoints are \\\`POST\\\` with JSON body and \\\`Content-Type: application/json\\\`.
740
+
741
+ ---
742
+
743
+ ## API Reference
744
+
745
+ ### List Apps
746
+ \\\`POST /listUserMigrations\\\` — Returns all migrations with app_id, status, delivery_type, hosted_url
747
+
748
+ ### Check Status
749
+ \\\`POST /checkAwsStatus\\\` — Body: \\\`{"app_id": "..."}\\\` — Returns instanceState, deploymentStatus, ipAddress, deployUrl
750
+
751
+ ### Deploy New Instance
752
+ \\\`POST /deployToAws\\\` — Body: \\\`{"migration_id": "..."}\\\` — Creates new EC2 instance. Poll checkAwsStatus every 5s.
753
+
754
+ ### Resync Running App
755
+ \\\`POST /resyncHosting\\\` — Body: \\\`{"app_id": "..."}\\\` — Syncs latest code to running instance.
756
+
757
+ ### Staging Preview
758
+ \\\`POST /deployStagingPreview\\\` — Body: \\\`{"migration_id": "...", "production": false}\\\` — Free, 2hr preview.
759
+
760
+ ### Instance Control
761
+ \\\`POST /updateInstanceState\\\` — Body: \\\`{"app_id": "...", "instance_state": "start|stop|terminate"}\\\`
762
+
763
+ ### Upgrade Instance
764
+ \\\`POST /upgradeInstance\\\` — Body: \\\`{"app_id": "...", "instance_type": "2gb|4gb|8gb|16gb"}\\\`
765
+
766
+ ### Environment Variables
767
+ \\\`POST /setEnvVars\\\` — Body: \\\`{"app_id": "...", "env_vars": {"KEY": "value"}}\\\`
768
+
769
+ ### Custom Domain
770
+ \\\`POST /addCustomDomain\\\` — Body: \\\`{"app_id": "...", "custom_domain": "app.yourdomain.com"}\\\`
771
+
772
+ ### AI Security Scan
773
+ \\\`POST /runAiScan\\\` — Body: \\\`{"app_id": "...", "migration_id": "..."}\\\`
774
+
775
+ ---
776
+
777
+ ## Decision Logic for Agents
778
+
779
+ When the user says "deploy":
780
+
781
+ \\\`\\\`\\\`
782
+ Is there a nometria.json?
783
+ YES -> Use its app_id/migration_id
784
+ NO -> POST /listUserMigrations, pick the right one
785
+
786
+ POST /checkAwsStatus with app_id
787
+ instanceState === "running"?
788
+ YES -> POST /resyncHosting (fast code sync)
789
+ instanceState === "stopped"?
790
+ YES -> POST /updateInstanceState (start), then resyncHosting
791
+ status === "not_deployed"?
792
+ YES -> POST /deployToAws (new instance, takes 2-5 min)
793
+
794
+ Poll /checkAwsStatus every 5s until terminal state
795
+ Report URL to user
796
+ \\\`\\\`\\\`
797
+
798
+ ---
799
+
800
+ ## Configuration (\\\`nometria.json\\\`)
801
+
802
+ \\\`\\\`\\\`json
803
+ {
804
+ "name": "${appName}",
805
+ "framework": "vite",
806
+ "platform": "${platform}",
807
+ "region": "us-east-1",
808
+ "instanceType": "4gb",
809
+ "build": { "command": "npm run build", "output": "dist" }
810
+ }
811
+ \\\`\\\`\\\`
812
+
813
+ ---
814
+
815
+ ## IDE & CLI Integration
816
+
817
+ | Tool | Integration |
818
+ |------|-------------|
819
+ | **nom CLI** | \\\`npx @nometria-ai/nom deploy\\\` — deploy from terminal |
820
+ | **Claude Code** | Slash commands: \\\`/deploy\\\`, \\\`/preview\\\`, \\\`/status\\\`, \\\`/nometria-login\\\` |
821
+ | **Cursor** | Auto-rules in \\\`.cursor/rules/nometria.mdc\\\` |
822
+ | **VS Code / Cursor** | Extension: search "Nometria" in marketplace |
823
+ | **Any agent** | Read this file and use the curl commands above |
824
+ `;
825
+ }
826
+
827
+ function writeContinueConfig(configPath) {
828
+ let config = {};
829
+ if (existsSync(configPath)) {
830
+ try {
831
+ config = JSON.parse(readFileSync(configPath, 'utf8'));
832
+ } catch { /* start fresh */ }
833
+ }
834
+
835
+ // Add/update MCP server config
836
+ if (!config.experimental) config.experimental = {};
837
+ if (!config.experimental.modelContextProtocolServers) config.experimental.modelContextProtocolServers = [];
838
+
839
+ const servers = config.experimental.modelContextProtocolServers;
840
+ const existing = servers.findIndex(s => s.name === 'nometria');
841
+ const nometriaServer = {
842
+ name: 'nometria',
843
+ command: 'npx',
844
+ args: ['@nometria-ai/claude-code'],
845
+ };
846
+
847
+ if (existing >= 0) {
848
+ servers[existing] = nometriaServer;
849
+ } else {
850
+ servers.push(nometriaServer);
851
+ }
852
+
853
+ writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n');
854
+ }