@bhooai/nexus-cli 0.1.5 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +8 -12
- package/src/commands/add.ts +274 -0
- package/src/commands/build.ts +91 -0
- package/src/commands/db.ts +241 -0
- package/src/commands/dev.ts +149 -186
- package/src/commands/doctor.ts +102 -184
- package/src/commands/init.ts +204 -958
- package/src/commands/maintenance-commands.ts +40 -0
- package/src/commands/plugin.ts +233 -0
- package/src/commands/queue.ts +145 -0
- package/src/commands/test.ts +34 -0
- package/src/dispatcher.ts +98 -0
- package/src/generators.ts +102 -0
- package/src/index.ts +32 -90
- package/src/make/generators.ts +431 -0
- package/src/ports.ts +85 -0
- package/src/prompts.ts +68 -0
- package/src/templating/render.ts +109 -0
- package/src/util.ts +74 -112
- package/templates/base/Dockerfile.ejs +68 -0
- package/templates/base/README.md.ejs +62 -0
- package/templates/base/apps/admin/index.html.ejs +12 -0
- package/templates/base/apps/admin/nginx.conf.ejs +16 -0
- package/templates/base/apps/admin/package.json.ejs +15 -0
- package/templates/base/apps/admin/src/main.tsx.ejs +7 -0
- package/templates/base/apps/admin/vite.config.ts.ejs +22 -0
- package/templates/base/apps/ai-server/main.py.ejs +30 -0
- package/templates/base/apps/ai-server/requirements.txt +4 -0
- package/templates/base/apps/backend/src/main.ts +14 -0
- package/templates/base/apps/backend/src/routes/index.ts.ejs +11 -0
- package/templates/base/apps/frontend/index.html.ejs +12 -0
- package/templates/base/apps/frontend/nginx.conf.ejs +33 -0
- package/templates/base/apps/frontend/package.json.ejs +11 -0
- package/templates/base/apps/frontend/src/main.tsx.ejs +16 -0
- package/templates/base/apps/frontend/vite.config.ts.ejs +22 -0
- package/templates/base/docker-compose.yml.ejs +93 -0
- package/templates/base/dockerignore +21 -0
- package/templates/base/gitignore +43 -0
- package/templates/base/nexus.config.ts.ejs +97 -0
- package/templates/base/package.json.ejs +40 -0
- package/templates/{tsconfig.json → base/tsconfig.json} +2 -3
- package/tsconfig.json +5 -4
- package/PLAN.md +0 -141
- package/README.md +0 -34
- package/src/commands/cluster.ts +0 -133
- package/src/commands/node.ts +0 -106
- package/src/commands/pysetup.ts +0 -142
- package/src/commands/sync.ts +0 -116
- package/src/commands/uninstall.ts +0 -287
- package/src/config-sync.ts +0 -384
- package/src/dotenv.ts +0 -39
- package/src/supervisor.ts +0 -394
- package/src/wizard.ts +0 -149
- package/templates/Dockerfile +0 -60
- package/templates/README.md +0 -69
- package/templates/apps/admin/index.html +0 -12
- package/templates/apps/admin/package.json +0 -22
- package/templates/apps/admin/postcss.config.js +0 -3
- package/templates/apps/admin/src/main.tsx +0 -10
- package/templates/apps/admin/src/vite-env.d.ts +0 -18
- package/templates/apps/admin/tailwind.config.js +0 -9
- package/templates/apps/admin/tsconfig.json +0 -17
- package/templates/apps/admin/vite.config.ts +0 -64
- package/templates/apps/ai-server/main.py +0 -43
- package/templates/apps/ai-server/providers/__init__.py +0 -3
- package/templates/apps/ai-server/providers/base.py +0 -111
- package/templates/apps/ai-server/requirements.txt +0 -3
- package/templates/apps/ai-server/routers/__init__.py +0 -3
- package/templates/apps/ai-server/routers/chat.py +0 -47
- package/templates/apps/ai-server/routers/embeddings.py +0 -30
- package/templates/apps/ai-server/routers/lint.py +0 -167
- package/templates/apps/ai-server/routers/models.py +0 -23
- package/templates/apps/ai-server/routers/preflight.py +0 -169
- package/templates/apps/ai-server/settings.py +0 -48
- package/templates/apps/backend/package.json +0 -34
- package/templates/apps/backend/src/main.ts +0 -375
- package/templates/apps/backend/src/modules/admin/adminRoutes.ts +0 -732
- package/templates/apps/backend/src/modules/admin/clusterRoutes.ts +0 -391
- package/templates/apps/backend/src/modules/admin/databaseRoutes.ts +0 -161
- package/templates/apps/backend/src/modules/admin/lintProxy.ts +0 -89
- package/templates/apps/backend/src/modules/admin/preflightProxy.ts +0 -242
- package/templates/apps/backend/src/modules/admin/roleCatalog.ts +0 -78
- package/templates/apps/backend/src/modules/admin/schemaRoutes.ts +0 -449
- package/templates/apps/backend/src/modules/ai/aiProxy.ts +0 -265
- package/templates/apps/backend/src/modules/auth/authRoutes.ts +0 -220
- package/templates/apps/backend/src/modules/payments/paymentRoutes.ts +0 -100
- package/templates/apps/backend/src/modules/payments/paymentStore.ts +0 -172
- package/templates/apps/backend/src/modules/requests/requestLog.ts +0 -175
- package/templates/apps/backend/src/modules/users/userGraph.ts +0 -83
- package/templates/apps/backend/src/modules/users/userModel.ts +0 -88
- package/templates/apps/backend/src/plugins/CronScheduler.ts +0 -69
- package/templates/apps/backend/src/plugins/loadPlugins.ts +0 -107
- package/templates/apps/backend/tsconfig.json +0 -14
- package/templates/apps/frontend/index.html +0 -12
- package/templates/apps/frontend/package.json +0 -20
- package/templates/apps/frontend/postcss.config.js +0 -3
- package/templates/apps/frontend/src/index.css +0 -44
- package/templates/apps/frontend/src/main.tsx +0 -65
- package/templates/apps/frontend/tailwind.config.js +0 -9
- package/templates/apps/frontend/vite.config.ts +0 -72
- package/templates/bin/nexus.js +0 -35
- package/templates/bin/serve-all.mjs +0 -45
- package/templates/dockerignore +0 -15
- package/templates/gitignore +0 -12
- package/templates/nexus.config.ts +0 -69
- package/templates/package.json +0 -47
- package/tests/cli.test.ts +0 -52
- package/tests/config-sync.test.ts +0 -201
- package/tests/dotenv.test.ts +0 -51
- package/vitest.config.ts +0 -9
- package/vitest.config.ts.timestamp-1786095205351-444061f6ff5c58.mjs +0 -13
- /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,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
|
+
}
|
package/tsconfig.json
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"extends": "../../tsconfig.base.json",
|
|
3
3
|
"compilerOptions": {
|
|
4
|
-
"
|
|
5
|
-
"
|
|
4
|
+
"outDir": "dist",
|
|
5
|
+
"rootDir": "src",
|
|
6
|
+
"composite": false
|
|
6
7
|
},
|
|
7
8
|
"include": ["src/**/*"],
|
|
8
|
-
"
|
|
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
|
-
```
|