@bhooai/nexus-cli 0.1.5 → 2.0.1

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.
Files changed (112) hide show
  1. package/package.json +26 -27
  2. package/src/commands/add.ts +274 -0
  3. package/src/commands/build.ts +91 -0
  4. package/src/commands/db.ts +241 -0
  5. package/src/commands/dev.ts +149 -186
  6. package/src/commands/doctor.ts +102 -184
  7. package/src/commands/init.ts +204 -958
  8. package/src/commands/maintenance-commands.ts +40 -0
  9. package/src/commands/plugin.ts +233 -0
  10. package/src/commands/queue.ts +145 -0
  11. package/src/commands/test.ts +34 -0
  12. package/src/dispatcher.ts +98 -0
  13. package/src/generators.ts +102 -0
  14. package/src/index.ts +32 -90
  15. package/src/make/generators.ts +431 -0
  16. package/src/ports.ts +85 -0
  17. package/src/prompts.ts +68 -0
  18. package/src/templating/render.ts +109 -0
  19. package/src/util.ts +74 -112
  20. package/templates/base/Dockerfile.ejs +68 -0
  21. package/templates/base/README.md.ejs +62 -0
  22. package/templates/base/apps/admin/index.html.ejs +12 -0
  23. package/templates/base/apps/admin/nginx.conf.ejs +16 -0
  24. package/templates/base/apps/admin/package.json.ejs +15 -0
  25. package/templates/base/apps/admin/src/main.tsx.ejs +7 -0
  26. package/templates/base/apps/admin/vite.config.ts.ejs +22 -0
  27. package/templates/base/apps/ai-server/main.py.ejs +30 -0
  28. package/templates/base/apps/ai-server/requirements.txt +4 -0
  29. package/templates/base/apps/backend/src/main.ts +14 -0
  30. package/templates/base/apps/backend/src/routes/index.ts.ejs +11 -0
  31. package/templates/base/apps/frontend/index.html.ejs +12 -0
  32. package/templates/base/apps/frontend/nginx.conf.ejs +33 -0
  33. package/templates/base/apps/frontend/package.json.ejs +11 -0
  34. package/templates/base/apps/frontend/src/main.tsx.ejs +16 -0
  35. package/templates/base/apps/frontend/vite.config.ts.ejs +22 -0
  36. package/templates/base/docker-compose.yml.ejs +93 -0
  37. package/templates/base/dockerignore +21 -0
  38. package/templates/base/gitignore +43 -0
  39. package/templates/base/nexus.config.ts.ejs +97 -0
  40. package/templates/base/package.json.ejs +40 -0
  41. package/templates/{tsconfig.json → base/tsconfig.json} +2 -3
  42. package/tsconfig.json +5 -4
  43. package/PLAN.md +0 -141
  44. package/README.md +0 -34
  45. package/src/commands/cluster.ts +0 -133
  46. package/src/commands/node.ts +0 -106
  47. package/src/commands/pysetup.ts +0 -142
  48. package/src/commands/sync.ts +0 -116
  49. package/src/commands/uninstall.ts +0 -287
  50. package/src/config-sync.ts +0 -384
  51. package/src/dotenv.ts +0 -39
  52. package/src/supervisor.ts +0 -394
  53. package/src/wizard.ts +0 -149
  54. package/templates/Dockerfile +0 -60
  55. package/templates/README.md +0 -69
  56. package/templates/apps/admin/index.html +0 -12
  57. package/templates/apps/admin/package.json +0 -22
  58. package/templates/apps/admin/postcss.config.js +0 -3
  59. package/templates/apps/admin/src/main.tsx +0 -10
  60. package/templates/apps/admin/src/vite-env.d.ts +0 -18
  61. package/templates/apps/admin/tailwind.config.js +0 -9
  62. package/templates/apps/admin/tsconfig.json +0 -17
  63. package/templates/apps/admin/vite.config.ts +0 -64
  64. package/templates/apps/ai-server/main.py +0 -43
  65. package/templates/apps/ai-server/providers/__init__.py +0 -3
  66. package/templates/apps/ai-server/providers/base.py +0 -111
  67. package/templates/apps/ai-server/requirements.txt +0 -3
  68. package/templates/apps/ai-server/routers/__init__.py +0 -3
  69. package/templates/apps/ai-server/routers/chat.py +0 -47
  70. package/templates/apps/ai-server/routers/embeddings.py +0 -30
  71. package/templates/apps/ai-server/routers/lint.py +0 -167
  72. package/templates/apps/ai-server/routers/models.py +0 -23
  73. package/templates/apps/ai-server/routers/preflight.py +0 -169
  74. package/templates/apps/ai-server/settings.py +0 -48
  75. package/templates/apps/backend/package.json +0 -34
  76. package/templates/apps/backend/src/main.ts +0 -375
  77. package/templates/apps/backend/src/modules/admin/adminRoutes.ts +0 -732
  78. package/templates/apps/backend/src/modules/admin/clusterRoutes.ts +0 -391
  79. package/templates/apps/backend/src/modules/admin/databaseRoutes.ts +0 -161
  80. package/templates/apps/backend/src/modules/admin/lintProxy.ts +0 -89
  81. package/templates/apps/backend/src/modules/admin/preflightProxy.ts +0 -242
  82. package/templates/apps/backend/src/modules/admin/roleCatalog.ts +0 -78
  83. package/templates/apps/backend/src/modules/admin/schemaRoutes.ts +0 -449
  84. package/templates/apps/backend/src/modules/ai/aiProxy.ts +0 -265
  85. package/templates/apps/backend/src/modules/auth/authRoutes.ts +0 -220
  86. package/templates/apps/backend/src/modules/payments/paymentRoutes.ts +0 -100
  87. package/templates/apps/backend/src/modules/payments/paymentStore.ts +0 -172
  88. package/templates/apps/backend/src/modules/requests/requestLog.ts +0 -175
  89. package/templates/apps/backend/src/modules/users/userGraph.ts +0 -83
  90. package/templates/apps/backend/src/modules/users/userModel.ts +0 -88
  91. package/templates/apps/backend/src/plugins/CronScheduler.ts +0 -69
  92. package/templates/apps/backend/src/plugins/loadPlugins.ts +0 -107
  93. package/templates/apps/backend/tsconfig.json +0 -14
  94. package/templates/apps/frontend/index.html +0 -12
  95. package/templates/apps/frontend/package.json +0 -20
  96. package/templates/apps/frontend/postcss.config.js +0 -3
  97. package/templates/apps/frontend/src/index.css +0 -44
  98. package/templates/apps/frontend/src/main.tsx +0 -65
  99. package/templates/apps/frontend/tailwind.config.js +0 -9
  100. package/templates/apps/frontend/vite.config.ts +0 -72
  101. package/templates/bin/nexus.js +0 -35
  102. package/templates/bin/serve-all.mjs +0 -45
  103. package/templates/dockerignore +0 -15
  104. package/templates/gitignore +0 -12
  105. package/templates/nexus.config.ts +0 -69
  106. package/templates/package.json +0 -47
  107. package/tests/cli.test.ts +0 -52
  108. package/tests/config-sync.test.ts +0 -201
  109. package/tests/dotenv.test.ts +0 -51
  110. package/vitest.config.ts +0 -9
  111. package/vitest.config.ts.timestamp-1786095205351-444061f6ff5c58.mjs +0 -13
  112. /package/templates/{uploads → base/apps/backend/storage}/.gitkeep +0 -0
@@ -0,0 +1,12 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8"/>
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
6
+ <title><%= name %></title>
7
+ </head>
8
+ <body>
9
+ <div id="root"></div>
10
+ <script type="module" src="/src/main.tsx"></script>
11
+ </body>
12
+ </html>
@@ -0,0 +1,33 @@
1
+ server {
2
+ listen 80;
3
+ server_name _;
4
+ root /usr/share/nginx/html;
5
+ index index.html;
6
+
7
+ # SPA fallback: every non-file GET → index.html
8
+ location / {
9
+ try_files $uri $uri/ /index.html;
10
+ }
11
+
12
+ # API and WebSocket proxies — targets picked up from env at container boot
13
+ location /api/ {
14
+ proxy_pass http://backend:<%= backendPort %>/;
15
+ proxy_http_version 1.1;
16
+ proxy_set_header Host $host;
17
+ proxy_set_header X-Real-IP $remote_addr;
18
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
19
+ proxy_set_header X-Forwarded-Proto $scheme;
20
+ }
21
+ location /uploads/ {
22
+ proxy_pass http://backend:<%= backendPort %>/uploads/;
23
+ proxy_http_version 1.1;
24
+ proxy_set_header Host $host;
25
+ }
26
+ location /ws {
27
+ proxy_pass http://backend:<%= backendPort %>/ws;
28
+ proxy_http_version 1.1;
29
+ proxy_set_header Upgrade $http_upgrade;
30
+ proxy_set_header Connection "upgrade";
31
+ proxy_set_header Host $host;
32
+ }
33
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "name": "@<%= nameSlug %>/frontend",
3
+ "private": true,
4
+ "version": "0.1.0",
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite --port <%= frontendPort %>",
8
+ "build": "vite build",
9
+ "preview": "vite preview"
10
+ }
11
+ }
@@ -0,0 +1,16 @@
1
+ import React from 'react';
2
+ import { createRoot } from 'react-dom/client';
3
+
4
+ function App() {
5
+ return (
6
+ <main style={{ fontFamily: 'system-ui', padding: '2rem' }}>
7
+ <h1>Welcome to <%= name %></h1>
8
+ <p>Your Nexus app is up. Edit <code>apps/frontend/src/main.tsx</code> to get started.</p>
9
+ </main>
10
+ );
11
+ }
12
+
13
+ const rootEl = document.getElementById('root');
14
+ if (rootEl) {
15
+ createRoot(rootEl).render(<App />);
16
+ }
@@ -0,0 +1,22 @@
1
+ import { defineConfig } from 'vite';
2
+
3
+ export default defineConfig({
4
+ server: {
5
+ port: <%= frontendPort %>,
6
+ proxy: {
7
+ '/api': {
8
+ target: 'http://localhost:<%= backendPort %>',
9
+ changeOrigin: true,
10
+ rewrite: (p: string) => p.replace(/^\/api/, ''),
11
+ },
12
+ '/uploads': {
13
+ target: 'http://localhost:<%= backendPort %>',
14
+ changeOrigin: true,
15
+ },
16
+ '/ws': {
17
+ target: 'ws://localhost:<%= backendPort %>',
18
+ ws: true,
19
+ },
20
+ },
21
+ },
22
+ });
@@ -0,0 +1,93 @@
1
+ version: "3.9"
2
+
3
+ name: <%= nameSlug %>
4
+
5
+ services:
6
+ backend:
7
+ build:
8
+ context: .
9
+ dockerfile: Dockerfile
10
+ target: backend-base
11
+ ports:
12
+ - "<%= backendPort %>:<%= backendPort %>"
13
+ env_file: .env
14
+ environment:
15
+ NODE_ENV: production
16
+ NEXUS_DB_URI: ${NEXUS_DB_URI:-mongodb://mongo:27017/<%= nameSlug %>}
17
+ NEXUS_REDIS_URL: ${NEXUS_REDIS_URL:-redis://redis:6379}
18
+ volumes:
19
+ - ./apps/backend/storage:/app/apps/backend/storage
20
+ depends_on:
21
+ mongo:
22
+ condition: service_healthy
23
+ redis:
24
+ condition: service_started
25
+ restart: unless-stopped
26
+ healthcheck:
27
+ test: ["CMD", "wget", "-qO-", "http://localhost:<%= backendPort %>/health"]
28
+ interval: 30s
29
+ timeout: 5s
30
+ retries: 3
31
+
32
+ frontend:
33
+ build:
34
+ context: .
35
+ dockerfile: Dockerfile
36
+ target: frontend
37
+ ports:
38
+ - "<%= frontendPort %>:80"
39
+ depends_on:
40
+ - backend
41
+ restart: unless-stopped
42
+
43
+ admin:
44
+ build:
45
+ context: .
46
+ dockerfile: Dockerfile
47
+ target: admin
48
+ ports:
49
+ - "<%= adminPort %>:80"
50
+ depends_on:
51
+ - backend
52
+ restart: unless-stopped
53
+
54
+ ai-server:
55
+ build:
56
+ context: .
57
+ dockerfile: Dockerfile
58
+ target: ai-server
59
+ profiles: ["ai"]
60
+ ports:
61
+ - "<%= aiPort %>:<%= aiPort %>"
62
+ restart: unless-stopped
63
+
64
+ mongo:
65
+ image: mongo:7
66
+ restart: unless-stopped
67
+ volumes:
68
+ - mongo-data:/data/db
69
+ healthcheck:
70
+ test: ["CMD", "mongosh", "--quiet", "--eval", "db.runCommand('ping').ok"]
71
+ interval: 10s
72
+ timeout: 5s
73
+ retries: 5
74
+ ports:
75
+ - "27017:27017"
76
+
77
+ redis:
78
+ image: redis:7-alpine
79
+ restart: unless-stopped
80
+ command: redis-server --appendonly yes
81
+ volumes:
82
+ - redis-data:/data
83
+ healthcheck:
84
+ test: ["CMD", "redis-cli", "ping"]
85
+ interval: 10s
86
+ timeout: 3s
87
+ retries: 5
88
+ ports:
89
+ - "6379:6379"
90
+
91
+ volumes:
92
+ mongo-data:
93
+ redis-data:
@@ -0,0 +1,21 @@
1
+ node_modules
2
+ dist
3
+ build
4
+ .nexus-down
5
+ .nexus-ports.json
6
+ .env
7
+ .env.local
8
+ logs/
9
+ certs/
10
+ apps/*/storage/
11
+ .venv/
12
+ venv/
13
+ __pycache__/
14
+ *.pyc
15
+ .vscode/
16
+ .idea/
17
+ coverage/
18
+ .nyc_output/
19
+ playwright-report/
20
+ test-results/
21
+ .cache/
@@ -0,0 +1,43 @@
1
+ # Dependencies
2
+ node_modules/
3
+
4
+ # Build output
5
+ dist/
6
+ build/
7
+ *.tsbuildinfo
8
+
9
+ # Runtime
10
+ .env
11
+ .env.local
12
+ nexus.runtime.json
13
+
14
+ # Generated
15
+ logs/
16
+ certs/
17
+ !certs/.gitkeep
18
+
19
+ # Per-backend storage (apps/<backend>/storage/)
20
+ apps/*/storage/*
21
+ !apps/*/storage/.gitkeep
22
+
23
+ # Python
24
+ __pycache__/
25
+ *.py[cod]
26
+ .venv/
27
+ venv/
28
+ .pytest_cache/
29
+
30
+ # Editor / OS
31
+ .vscode/
32
+ .idea/
33
+ .DS_Store
34
+ Thumbs.db
35
+
36
+ # Test / coverage
37
+ coverage/
38
+ .nyc_output/
39
+ playwright-report/
40
+ test-results/
41
+
42
+ # Maintenance mode flag
43
+ .nexus-down
@@ -0,0 +1,97 @@
1
+ import type { NexusConfig } from '@bhooai/nexus-core';
2
+
3
+ /**
4
+ * Nexus config for <%= name %>.
5
+ *
6
+ * Precedence (low to high): code defaults < this file < nexus.runtime.json
7
+ * < NEXUS_* env vars < CLI flags.
8
+ *
9
+ * Secrets live in .env; do NOT commit them here.
10
+ */
11
+ const config: Partial<NexusConfig> = {
12
+ env: 'development',
13
+
14
+ server: {
15
+ port: <%= backendPort %>,
16
+ host: '127.0.0.1',
17
+ https: false,
18
+ trustProxy: false,
19
+ bodyLimit: 12 * 1024 * 1024,
20
+ },
21
+
22
+ uploads: {
23
+ dir: 'storage/uploads',
24
+ path: '/uploads',
25
+ maxFileSize: 10 * 1024 * 1024,
26
+ maxFiles: 20,
27
+ allowedTypes: [],
28
+ },
29
+
30
+ db: {
31
+ uri: process.env.NEXUS_DB_URI ?? '<%= mongoUri %>',
32
+ maxPoolSize: 10,
33
+ autoIndex: true,
34
+ },
35
+
36
+ redis: {
37
+ url: process.env.NEXUS_REDIS_URL ?? '<%= redisUrl %>',
38
+ keyPrefix: '<%= nameSlug %>:',
39
+ },
40
+
41
+ graphql: {
42
+ path: '/graphql',
43
+ federation: 'in-process',
44
+ subscriptions: true,
45
+ introspection: true,
46
+ },
47
+
48
+ ws: {
49
+ path: '/ws',
50
+ heartbeatMs: 30_000,
51
+ requireCsrf: true,
52
+ },
53
+
54
+ auth: {
55
+ jwt: {
56
+ accessTtl: 60 * 15,
57
+ refreshTtl: 60 * 60 * 24 * 30,
58
+ issuer: '<%= nameSlug %>',
59
+ audience: '<%= nameSlug %>-client',
60
+ },
61
+ cookieName: '<%= nameSlug %>_sid',
62
+ refreshCookieName: '<%= nameSlug %>_rid',
63
+ requireEmailVerification: false,
64
+ },
65
+
66
+ payments: {
67
+ webhookPath: '/payments/webhook/:provider',
68
+ currency: 'INR',
69
+ razorpay: { enabled: false, sandbox: true },
70
+ paypal: { enabled: false, sandbox: true },
71
+ },
72
+
73
+ email: { provider: 'log', from: 'no-reply@<%= nameSlug %>.local' },
74
+
75
+ certs: { dir: 'certs', keyType: 'rsa', rsaModulus: 2048, ecCurve: 'prime256v1', validityDays: 365 },
76
+
77
+ ads: { enabled: false, developerToken: '', clientId: '', clientSecret: '', refreshToken: '', customerId: '' },
78
+
79
+ webrtc: { rtcMinPort: 40000, rtcMaxPort: 40100, announceIp: '127.0.0.1' },
80
+
81
+ ai: {
82
+ serverUrl: `http://localhost:${process.env.AI_PORT ?? <%= aiPort %>}`,
83
+ timeoutMs: 60_000,
84
+ defaultProvider: 'auto',
85
+ schemaModel: 'llama3:latest',
86
+ },
87
+
88
+ logging: { level: 'info', format: 'pretty', console: true, dir: 'logs', maxFileSize: 10 * 1024 * 1024, maxFiles: 7 },
89
+
90
+ plugins: { dir: 'plugins', entries: [] },
91
+
92
+ frontend: { port: <%= frontendPort %>, host: 'localhost', enabled: true },
93
+
94
+ admin: { port: <%= adminPort %>, host: 'localhost', enabled: true },
95
+ };
96
+
97
+ export default config;
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "<%= nameSlug %>",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "workspaces": [
7
+ "apps/*"
8
+ ],
9
+ "scripts": {
10
+ "dev": "nexus dev",
11
+ "build": "nexus build",
12
+ "test": "nexus test",
13
+ "doctor": "nexus doctor",
14
+ "down": "nexus down",
15
+ "up": "nexus up"
16
+ },
17
+ "dependencies": {
18
+ "@bhooai/nexus-core": "^2.0.0",
19
+ "@bhooai/nexus-auth": "^2.0.0",
20
+ "@bhooai/nexus-data": "^2.0.0",
21
+ "@bhooai/nexus-cache": "^2.0.0",
22
+ "@bhooai/nexus-realtime": "^2.0.0",
23
+ "@bhooai/nexus-payments": "^2.0.0",
24
+ "@bhooai/nexus-email": "^2.0.0",
25
+ "@bhooai/nexus-ai-client": "^2.0.0",
26
+ "@bhooai/nexus-graphql": "^2.0.0",
27
+ "@bhooai/nexus-telemetry": "^2.0.0",
28
+ "tsx": "^4.19.0"
29
+ },
30
+ "devDependencies": {
31
+ "@types/node": "^22.5.0",
32
+ "typescript": "^5.6.2",
33
+ "react": "^18.3.1",
34
+ "react-dom": "^18.3.1",
35
+ "@types/react": "^18.3.12",
36
+ "@types/react-dom": "^18.3.1",
37
+ "vite": "^5.4.10",
38
+ "tailwindcss": "^3.4.14"
39
+ }
40
+ }
@@ -10,8 +10,7 @@
10
10
  "skipLibCheck": true,
11
11
  "resolveJsonModule": true,
12
12
  "allowImportingTsExtensions": true,
13
- "noEmit": true,
14
- "types": ["node"]
13
+ "noEmit": true
15
14
  },
16
15
  "include": ["apps/**/*", "nexus.config.ts"]
17
- }
16
+ }
package/tsconfig.json CHANGED
@@ -1,9 +1,10 @@
1
1
  {
2
2
  "extends": "../../tsconfig.base.json",
3
3
  "compilerOptions": {
4
- "rootDir": "./src",
5
- "outDir": "./dist"
4
+ "outDir": "dist",
5
+ "rootDir": "src",
6
+ "composite": false
6
7
  },
7
8
  "include": ["src/**/*"],
8
- "references": [{ "path": "../nexus-core" }]
9
- }
9
+ "exclude": ["dist/**", "node_modules/**"]
10
+ }
package/PLAN.md DELETED
@@ -1,141 +0,0 @@
1
- # Plan: `nexus init` — all-in-one setup wizard
2
-
3
- ## Goal
4
- Turn `nexus init` into a single interactive command that, when it finishes, leaves a
5
- fully bootable stack: Node backend, frontend, admin, Python AI server, Mongo + Redis
6
- wired, JWT secret, AI provider keys, and the cluster token. After running it once,
7
- `npm run dev` starts everything.
8
-
9
- ## Current state (source of truth)
10
-
11
- `nexus init` (`packages/nexus-cli/src/commands/init.ts`) today:
12
- 1. Scaffolds templates (`listFiles(TEMPLATES)` -> write each)
13
- 2. `wireFrameworkDependency()` — workspace paths + `file:` dep + Vite/Tailwind patching
14
- 3. `allocateProjectPorts()` — auto-pick free ports for server/frontend/admin/ai/lb/agent
15
- 4. `ensureJwtSecret()` — generate `NEXUS_AUTH_JWT_SECRET`, add empty AI/payment env keys
16
- 5. `chooseKind()` — interactive root/node prompt (the only wizard step today)
17
- 6. `applyClusterConfig()` — write cluster section into `nexus.config.ts`
18
- 7. `installDependencies()` — `npm install`
19
- 8. `printSetup()` — onboarding text
20
-
21
- Gaps that prevent "everything at once":
22
- - Python deps never installed (separate `nexus pysetup` command, forgotten by users)
23
- - No Mongo/Redis reachability check before scaffolding -> silent failures at `npm run dev`
24
- - No way to customize DB URI / Redis URL / AI provider keys during init (empty placeholders only)
25
- - No final verification that the scaffolded project actually loads
26
- - `.env` doesn't get `MONGODB_URI`/`REDIS_URL` (Python AI server can't connect)
27
-
28
- `pysetup.ts` is non-interactive (one-shot pip install). `doctor.ts` has reusable check
29
- logic (`tcpReachable`, `versionOf`, `parseHostPort`) but it's a monolithic `doctor()`
30
- function, not exported helpers.
31
-
32
- ## Wizard flow (interactive when stdin is a TTY; flag-driven otherwise)
33
-
34
- ```
35
- nexus init [target] [--as=root|node] [--no-interactive] [--no-venv] [--no-install] [--skip-mongo-check]
36
- ```
37
-
38
- | # | Step | Interactive prompt | Non-interactive fallback |
39
- |---|------|--------------------|--------------------------|
40
- | 0 | Banner — "BhooAI Nexus — project setup wizard" + what it'll do | shown | shown |
41
- | 1 | Prerequisite scan — detect node, npm, python, git, Mongo TCP, Redis TCP. Blocks on missing node/python (critical); warns on missing Mongo/Redis (asks to continue) | shown, "Continue anyway?" if Mongo/Redis down | `--skip-mongo-check` skips; missing node/python -> exit 1 |
42
- | 2 | Project name -> `package.json` name + Mongo db name | prompt, default = dir basename | `--name <x>` or dir basename |
43
- | 3 | Server kind root/node (existing `chooseKind`) | prompt | `--as=root\|node` |
44
- | 4 | Cluster role + port (if node) | prompt role, default `backend` | `--role` `--port` |
45
- | 5 | Ports — auto-allocate (existing) OR custom | "Auto-allocate free ports? Y/n" | auto (existing) |
46
- | 6 | Mongo URI — confirm or edit, DB name from step 2 | prompt, default `mongodb://localhost:27017/<name>` | `--mongo-uri` |
47
- | 7 | Redis URL — confirm or edit | prompt, default `redis://localhost:6379` | `--redis-url` |
48
- | 8 | AI providers — multi-select (openai/ollama/anthropic/google/groq/...), then enter API key for each selected (written to `.env`). Ollama/lmstudio need no key. | multi-select + per-key prompt | `--ai-providers openai,ollama` (keys via env or `--ai-key <id>=<val>`) |
49
- | 9 | Python venv — "Create a virtualenv for the AI server? Y/n" | prompt | `--no-venv` skips; `--venv` forces |
50
- | 10 | Review summary — table of all chosen values; "Proceed? Y/n" | shown | proceeds |
51
- | 11 | Scaffold templates (existing) | — | — |
52
- | 12 | Wire framework (existing) | — | — |
53
- | 13 | Allocate ports (existing) | — | — |
54
- | 14 | Write config — patch `nexus.config.ts` with chosen Mongo URI / Redis URL / AI serverUrl + `applyClusterConfig` (existing) | — | — |
55
- | 15 | Generate `.env` — JWT secret (existing) + `MONGODB_URI` + `REDIS_URL` + AI provider keys from step 8 + cluster token + payment placeholders (existing) | — | — |
56
- | 16 | npm install (existing) | — | — |
57
- | 17 | Python setup — invoke `pysetup(['--venv'\|--no-venv])` -> creates `apps/ai-server/.venv` + `pip install -r requirements.txt` | — | — |
58
- | 18 | Verify — run an in-process mini-doctor on the new project: load `nexus.config.ts`, TCP-check Mongo/Redis, check backend/frontend/admin/ai ports free, sign+verify a JWT. Print pass/fail table. | — | — |
59
- | 19 | Next steps — print URLs (backend `:port/health`, frontend, admin, ai `127.0.0.1:port`), pairing token, and `npm run dev` | shown | shown |
60
-
61
- ## Files to change (8)
62
-
63
- ### Framework — CLI
64
-
65
- 1. **`packages/nexus-cli/src/wizard.ts`** (NEW) — shared wizard primitives used by `init`
66
- and `pysetup`:
67
- - `isInteractive()` — `process.stdin.isTTY && !process.env.CI`
68
- - `prompt(q, default?)`, `confirm(q, default?)`, `select(q, options)`, `multiSelect(q, options)`
69
- - `banner(title, lines)`, `summaryTable(rows)`, `statusIcon(ok)`
70
- - Built on `node:readline/promises` (already used by `chooseKind`)
71
- - No new deps
72
-
73
- 2. **`packages/nexus-cli/src/commands/init.ts`** (rewrite) — orchestrate the 20-step flow
74
- above. Keep existing helpers (`wireFrameworkDependency`, `allocateProjectPorts`,
75
- `ensureJwtSecret`, `applyClusterConfig`, `installDependencies`, `printSetup`); insert
76
- prerequisite scan, prompts (steps 2/6/7/8/9), review, pysetup call, verify. Extract
77
- `ensureJwtSecret`'s env-key writing into a reusable `writeEnv(target, entries)` so the
78
- new `.env` step is one call. Add flags: `--name`, `--mongo-uri`, `--redis-url`,
79
- `--ai-providers`, `--ai-key`, `--venv`/`--no-venv`, `--no-interactive`,
80
- `--skip-mongo-check`.
81
-
82
- 3. **`packages/nexus-cli/src/commands/pysetup.ts`** (extend) — accept an `--interactive`
83
- flag that, when set and TTY, prompts for venv y/n + python path before installing.
84
- Expose `pysetup(args)` so `init` can call it programmatically (already exported). No
85
- behavior change for direct `nexus pysetup` invocation unless `--interactive` passed.
86
-
87
- 4. **`packages/nexus-cli/src/commands/doctor.ts`** (refactor) — extract the reusable
88
- prerequisite scan into exported helpers in `util.ts` so `init` step 1 reuses them:
89
- `scanRuntimes()` (node/npm/python/git versions), `scanServices(cfg)` (Mongo/Redis/AI
90
- TCP + port-free checks). `doctor()` becomes a thin renderer over these. No output change.
91
-
92
- 5. **`packages/nexus-cli/src/util.ts`** — add `scanRuntimes()`, `scanServices(cfg)`,
93
- `tcpReachable` (exists), `versionOf` (exists). Move the runtime + service check logic
94
- out of `doctor.ts` so both `doctor` and `init` share one implementation.
95
-
96
- 6. **`packages/nexus-cli/src/index.ts`** — update `init` help line to list new flags; no
97
- dispatch change (init already wired at `index.ts:20`).
98
-
99
- ### Framework — templates
100
-
101
- 7. **`packages/nexus-cli/templates/package.json`** — add `"pysetup": "nexus pysetup"`
102
- script so users can re-run it easily. (Optional; the wizard runs it automatically.)
103
-
104
- 8. **`packages/nexus-cli/templates/nexus.config.ts`** — no structural change, but the
105
- wizard patches it at step 14 with the chosen Mongo URI / Redis URL / AI serverUrl.
106
- (Patch logic lives in `init.ts`, not the template.)
107
-
108
- ## Security / correctness invariants
109
-
110
- - **Python AI server binds `127.0.0.1`** — wizard writes `AI_HOST=127.0.0.1` into `.env`
111
- and the template `settings.py` reads it (pairs with the `/py-server` plan; if that plan
112
- hasn't run yet, the wizard still sets the env so a future `settings.py` picks it up).
113
- - **`.env` is the single secrets sink** — JWT secret, Mongo URI, Redis URL, AI keys,
114
- cluster token all land there. `nexus.config.ts` stays clean (no secrets), matching the
115
- existing precedence comment.
116
- - **No external exposure of Python** — only Node binds `0.0.0.0`; AI server stays
117
- loopback. Wizard's verify step asserts `ai.serverUrl` host is `127.0.0.1` or `localhost`.
118
- - **Idempotent** — re-running `nexus init .` in an existing project updates config +
119
- `.env` without clobbering secrets (existing `ensureJwtSecret` pattern preserved).
120
-
121
- ## Verification (after execution)
122
-
123
- 1. `nexus init test-app` (interactive) -> walk through prompts -> all 20 steps complete.
124
- 2. `cd test-app && npm run doctor` -> all green.
125
- 3. `cd test-app && npm run dev` -> backend, frontend, admin, AI server all start;
126
- `http://localhost:<port>/health` returns ok.
127
- 4. `nexus init test-app --no-interactive --name ci-app --mongo-uri mongodb://localhost:27017/ci-app --ai-providers ollama --venv`
128
- -> fully non-interactive, exit 0.
129
- 5. Re-run `nexus init .` inside `test-app` -> secrets preserved, config updated.
130
- 6. Existing `cli.test.ts` (`run('init', [dir, '--skip-install'])`) still exits 0 and
131
- scaffolds the four-terminal tree (non-interactive mode, no pysetup).
132
-
133
- ## Decisions (confirmed)
134
-
135
- - Wizard interactivity auto-detected via TTY + `!CI`; `--no-interactive` forces flags-only.
136
- - Mongo/Redis down at init -> warn + "Continue anyway?" (default yes). Hard requirement
137
- only for node/python.
138
- - AI provider keys typed inline during the wizard (hidden echo). Left blank = fill later.
139
- - Python venv default **yes** (deps don't pollute global site-packages).
140
- - `--skip-install` skips BOTH npm install and pysetup (so tests/CI don't hang on pip).
141
- - Plan saved here at `packages/nexus-cli/PLAN.md` (matches repo `PLAN.md` convention).
package/README.md DELETED
@@ -1,34 +0,0 @@
1
- # @bhooai/nexus-cli
2
-
3
- The `nexus` CLI: `init`, `dev`, `doctor`, and a multi-process supervisor.
4
-
5
- ## Commands
6
-
7
- | command | what it does |
8
- | --- | --- |
9
- | `init [target] [--force]` | scaffold a new Nexus project from `templates/` |
10
- | `dev [--only a,b]` | start backend + frontend + AI + admin under the supervisor |
11
- | `doctor` | verify node/python versions and mongo/redis reachability (advisory) |
12
- | `build` / `test` / `plugin` / `add` | reserved/forwarded to the workspace tools |
13
-
14
- ## Templates
15
-
16
- `templates/` holds the real project files copied by `init` — a runnable backend
17
- (boots `NexusServer` with the security stack + `/health`, `/csrf-token`, `/echo`),
18
- a React+Vite frontend, a Python FastAPI AI server, an admin shell, and the CLI
19
- `bin/nexus.js` shim. `init` is idempotent (skips existing files unless `--force`).
20
-
21
- ## Supervisor
22
-
23
- `Supervisor` owns the four child processes, streams prefixed logs, handles
24
- graceful Ctrl-C, and exposes a localhost HTTP control API (start/stop/restart/
25
- status/logs-tail) that the admin app consumes — decoupling admin from
26
- OS-specific process management.
27
-
28
- ## Usage
29
-
30
- ```bash
31
- node bin/nexus.js init ./my-app
32
- node bin/nexus.js doctor
33
- node bin/nexus.js dev
34
- ```