@nitrostack/cli 1.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.
Files changed (100) hide show
  1. package/README.md +131 -0
  2. package/dist/commands/build.d.ts +6 -0
  3. package/dist/commands/build.d.ts.map +1 -0
  4. package/dist/commands/build.js +185 -0
  5. package/dist/commands/dev.d.ts +7 -0
  6. package/dist/commands/dev.d.ts.map +1 -0
  7. package/dist/commands/dev.js +365 -0
  8. package/dist/commands/generate-types.d.ts +8 -0
  9. package/dist/commands/generate-types.d.ts.map +1 -0
  10. package/dist/commands/generate-types.js +219 -0
  11. package/dist/commands/generate.d.ts +12 -0
  12. package/dist/commands/generate.d.ts.map +1 -0
  13. package/dist/commands/generate.js +375 -0
  14. package/dist/commands/init.d.ts +7 -0
  15. package/dist/commands/init.d.ts.map +1 -0
  16. package/dist/commands/init.js +324 -0
  17. package/dist/commands/install.d.ts +10 -0
  18. package/dist/commands/install.d.ts.map +1 -0
  19. package/dist/commands/install.js +80 -0
  20. package/dist/commands/start.d.ts +6 -0
  21. package/dist/commands/start.d.ts.map +1 -0
  22. package/dist/commands/start.js +70 -0
  23. package/dist/commands/upgrade.d.ts +10 -0
  24. package/dist/commands/upgrade.d.ts.map +1 -0
  25. package/dist/commands/upgrade.js +214 -0
  26. package/dist/index.d.ts +11 -0
  27. package/dist/index.d.ts.map +1 -0
  28. package/dist/index.js +94 -0
  29. package/dist/mcp-dev-wrapper.d.ts +15 -0
  30. package/dist/mcp-dev-wrapper.d.ts.map +1 -0
  31. package/dist/mcp-dev-wrapper.js +187 -0
  32. package/dist/ui/branding.d.ts +31 -0
  33. package/dist/ui/branding.d.ts.map +1 -0
  34. package/dist/ui/branding.js +136 -0
  35. package/package.json +69 -0
  36. package/templates/typescript-oauth/.env.example +27 -0
  37. package/templates/typescript-oauth/OAUTH_SETUP.md +592 -0
  38. package/templates/typescript-oauth/README.md +263 -0
  39. package/templates/typescript-oauth/package.json +29 -0
  40. package/templates/typescript-oauth/src/app.module.ts +92 -0
  41. package/templates/typescript-oauth/src/guards/oauth.guard.ts +126 -0
  42. package/templates/typescript-oauth/src/health/system.health.ts +55 -0
  43. package/templates/typescript-oauth/src/index.ts +63 -0
  44. package/templates/typescript-oauth/src/modules/flights/booking.tools.ts +323 -0
  45. package/templates/typescript-oauth/src/modules/flights/flights.module.ts +14 -0
  46. package/templates/typescript-oauth/src/modules/flights/flights.prompts.ts +228 -0
  47. package/templates/typescript-oauth/src/modules/flights/flights.resources.ts +215 -0
  48. package/templates/typescript-oauth/src/modules/flights/flights.tools.ts +457 -0
  49. package/templates/typescript-oauth/src/services/duffel.service.ts +285 -0
  50. package/templates/typescript-oauth/src/widgets/app/airport-search/page.tsx +270 -0
  51. package/templates/typescript-oauth/src/widgets/app/flight-details/page.tsx +261 -0
  52. package/templates/typescript-oauth/src/widgets/app/flight-search-results/page.tsx +378 -0
  53. package/templates/typescript-oauth/src/widgets/app/globals.css +167 -0
  54. package/templates/typescript-oauth/src/widgets/app/layout.tsx +18 -0
  55. package/templates/typescript-oauth/src/widgets/app/order-cancellation/page.tsx +207 -0
  56. package/templates/typescript-oauth/src/widgets/app/order-summary/page.tsx +245 -0
  57. package/templates/typescript-oauth/src/widgets/app/payment-confirmation/page.tsx +152 -0
  58. package/templates/typescript-oauth/src/widgets/app/seat-selection/page.tsx +486 -0
  59. package/templates/typescript-oauth/src/widgets/next-env.d.ts +5 -0
  60. package/templates/typescript-oauth/src/widgets/next.config.js +45 -0
  61. package/templates/typescript-oauth/src/widgets/package-lock.json +4493 -0
  62. package/templates/typescript-oauth/src/widgets/package.json +24 -0
  63. package/templates/typescript-oauth/src/widgets/tsconfig.json +28 -0
  64. package/templates/typescript-oauth/src/widgets/widget-manifest.json +395 -0
  65. package/templates/typescript-oauth/tsconfig.json +23 -0
  66. package/templates/typescript-pizzaz/README.md +252 -0
  67. package/templates/typescript-pizzaz/package.json +34 -0
  68. package/templates/typescript-pizzaz/src/app.module.ts +28 -0
  69. package/templates/typescript-pizzaz/src/index.ts +30 -0
  70. package/templates/typescript-pizzaz/src/modules/pizzaz/pizzaz.data.ts +106 -0
  71. package/templates/typescript-pizzaz/src/modules/pizzaz/pizzaz.module.ts +11 -0
  72. package/templates/typescript-pizzaz/src/modules/pizzaz/pizzaz.service.ts +60 -0
  73. package/templates/typescript-pizzaz/src/modules/pizzaz/pizzaz.tools.ts +197 -0
  74. package/templates/typescript-pizzaz/src/widgets/app/layout.tsx +18 -0
  75. package/templates/typescript-pizzaz/src/widgets/app/pizza-list/page.tsx +272 -0
  76. package/templates/typescript-pizzaz/src/widgets/app/pizza-map/page.tsx +216 -0
  77. package/templates/typescript-pizzaz/src/widgets/app/pizza-shop/page.tsx +374 -0
  78. package/templates/typescript-pizzaz/src/widgets/components/CompactShopCard.tsx +144 -0
  79. package/templates/typescript-pizzaz/src/widgets/components/PizzaCard.tsx +191 -0
  80. package/templates/typescript-pizzaz/src/widgets/next.config.js +45 -0
  81. package/templates/typescript-pizzaz/src/widgets/package.json +30 -0
  82. package/templates/typescript-pizzaz/src/widgets/tsconfig.json +28 -0
  83. package/templates/typescript-pizzaz/src/widgets/widget-manifest.json +253 -0
  84. package/templates/typescript-pizzaz/tsconfig.json +30 -0
  85. package/templates/typescript-starter/README.md +320 -0
  86. package/templates/typescript-starter/package.json +25 -0
  87. package/templates/typescript-starter/src/app.module.ts +34 -0
  88. package/templates/typescript-starter/src/health/system.health.ts +55 -0
  89. package/templates/typescript-starter/src/index.ts +29 -0
  90. package/templates/typescript-starter/src/modules/calculator/calculator.module.ts +12 -0
  91. package/templates/typescript-starter/src/modules/calculator/calculator.prompts.ts +73 -0
  92. package/templates/typescript-starter/src/modules/calculator/calculator.resources.ts +59 -0
  93. package/templates/typescript-starter/src/modules/calculator/calculator.tools.ts +166 -0
  94. package/templates/typescript-starter/src/widgets/app/calculator-result/page.tsx +180 -0
  95. package/templates/typescript-starter/src/widgets/app/layout.tsx +18 -0
  96. package/templates/typescript-starter/src/widgets/next.config.js +45 -0
  97. package/templates/typescript-starter/src/widgets/package.json +24 -0
  98. package/templates/typescript-starter/src/widgets/tsconfig.json +28 -0
  99. package/templates/typescript-starter/src/widgets/widget-manifest.json +48 -0
  100. package/templates/typescript-starter/tsconfig.json +23 -0
@@ -0,0 +1,187 @@
1
+ #!/usr/bin/env node
2
+ import { spawn } from 'child_process';
3
+ import chokidar from 'chokidar';
4
+ import path from 'path';
5
+ import { fileURLToPath } from 'url';
6
+ import http from 'http';
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = path.dirname(__filename);
9
+ /**
10
+ * MCP Server Hot Reload Wrapper
11
+ *
12
+ * This wrapper:
13
+ * 1. Starts the MCP server as a child process
14
+ * 2. Watches for changes in the dist/ directory
15
+ * 3. Restarts the server when changes are detected
16
+ * 4. Maintains stdio connection for Studio
17
+ * 5. Captures stderr from the MCP server and streams it over an SSE endpoint
18
+ *
19
+ * IMPORTANT: All logs go to stderr to avoid corrupting MCP JSON-RPC on stdout
20
+ */
21
+ export async function run() {
22
+ const distPath = process.argv[2];
23
+ if (!distPath) {
24
+ console.error('Usage: mcp-dev-wrapper <path-to-dist/index.js>');
25
+ process.exit(1);
26
+ return;
27
+ }
28
+ const projectRoot = path.resolve(distPath, '../..');
29
+ const watchPath = path.join(projectRoot, 'dist');
30
+ let mcpProcess = null;
31
+ let isRestarting = false;
32
+ let consecutiveFailures = 0;
33
+ const maxConsecutiveFailures = 3;
34
+ let restartTimeout = null;
35
+ let sseClient = null;
36
+ const logCache = [];
37
+ // Create an HTTP server for SSE log streaming
38
+ const logServer = http.createServer((req, res) => {
39
+ if (req.url === '/mcp-logs') {
40
+ res.writeHead(200, {
41
+ 'Content-Type': 'text/event-stream',
42
+ 'Cache-Control': 'no-cache',
43
+ 'Connection': 'keep-alive',
44
+ 'Access-Control-Allow-Origin': '*', // Allow all origins
45
+ });
46
+ sseClient = res;
47
+ // Send cached logs
48
+ logCache.forEach(log => {
49
+ sseClient?.write(`data: ${log}\n\n`);
50
+ });
51
+ req.on('close', () => {
52
+ sseClient = null;
53
+ });
54
+ }
55
+ else {
56
+ res.writeHead(404);
57
+ res.end();
58
+ }
59
+ });
60
+ const logServerPort = parseInt(process.env.MCP_LOG_PORT || '3004');
61
+ logServer.listen(logServerPort, () => {
62
+ console.error(`[NitroStack Hot Reload] Log streaming server running at http://localhost:${logServerPort}/mcp-logs`);
63
+ });
64
+ function startMCPServer() {
65
+ if (isRestarting)
66
+ return;
67
+ console.error(`[DEBUG] mcp-dev-wrapper.ts: MCP_SERVER_PORT is ${process.env.MCP_SERVER_PORT}`);
68
+ const mcpEnv = {
69
+ ...process.env,
70
+ NODE_ENV: 'development',
71
+ PORT: process.env.MCP_SERVER_PORT,
72
+ };
73
+ mcpProcess = spawn('node', [distPath], {
74
+ stdio: ['inherit', 'inherit', 'pipe'], // Pipe stderr to capture logs
75
+ env: mcpEnv,
76
+ });
77
+ if (!mcpProcess)
78
+ return;
79
+ let buffer = '';
80
+ if (mcpProcess.stderr) {
81
+ mcpProcess.stderr.on('data', (data) => {
82
+ buffer += data.toString();
83
+ let boundary = buffer.indexOf('\n');
84
+ while (boundary !== -1) {
85
+ const line = buffer.substring(0, boundary);
86
+ buffer = buffer.substring(boundary + 1);
87
+ // Forward to the console for local debugging
88
+ process.stderr.write(line + '\n');
89
+ if (line.startsWith('NITRO_LOG::')) {
90
+ const logJson = line.substring('NITRO_LOG::'.length);
91
+ logCache.push(logJson);
92
+ if (sseClient) {
93
+ sseClient.write(`data: ${logJson}\n\n`);
94
+ }
95
+ }
96
+ boundary = buffer.indexOf('\n');
97
+ }
98
+ });
99
+ }
100
+ mcpProcess.on('exit', (code) => {
101
+ if (!isRestarting) {
102
+ if (code !== 0) {
103
+ consecutiveFailures++;
104
+ if (consecutiveFailures >= maxConsecutiveFailures) {
105
+ console.error(`[NitroStack Hot Reload] Server failed ${maxConsecutiveFailures} times in a row. Giving up.`);
106
+ console.error('[NitroStack Hot Reload] Check your configuration and try again.');
107
+ process.exit(1);
108
+ }
109
+ console.error(`[NitroStack Hot Reload] Server exited with code ${code} (attempt ${consecutiveFailures}/${maxConsecutiveFailures}), restarting...`);
110
+ }
111
+ else {
112
+ consecutiveFailures = 0;
113
+ console.error(`[NitroStack Hot Reload] Server exited with code ${code}, restarting...`);
114
+ }
115
+ mcpProcess = null;
116
+ setTimeout(startMCPServer, 1000);
117
+ }
118
+ });
119
+ mcpProcess.on('error', (err) => {
120
+ console.error('[NitroStack Hot Reload] Server error:', err);
121
+ });
122
+ }
123
+ function restartMCPServer() {
124
+ if (restartTimeout) {
125
+ clearTimeout(restartTimeout);
126
+ }
127
+ restartTimeout = setTimeout(() => {
128
+ if (isRestarting)
129
+ return;
130
+ isRestarting = true;
131
+ if (mcpProcess) {
132
+ console.error('[NitroStack Hot Reload] Changes detected, restarting server...');
133
+ mcpProcess.kill('SIGTERM');
134
+ setTimeout(() => {
135
+ mcpProcess = null;
136
+ isRestarting = false;
137
+ startMCPServer();
138
+ console.error('[NitroStack Hot Reload] Server restarted successfully');
139
+ }, 1500);
140
+ }
141
+ else {
142
+ isRestarting = false;
143
+ startMCPServer();
144
+ }
145
+ }, 1000);
146
+ }
147
+ // Start the server initially
148
+ startMCPServer();
149
+ const watcher = chokidar.watch(watchPath, {
150
+ ignoreInitial: true,
151
+ persistent: true,
152
+ awaitWriteFinish: {
153
+ stabilityThreshold: 100,
154
+ pollInterval: 50,
155
+ },
156
+ });
157
+ watcher.on('change', (filepath) => {
158
+ console.error(`[NitroStack Hot Reload] File changed: ${path.relative(projectRoot, filepath)}`);
159
+ restartMCPServer();
160
+ });
161
+ watcher.on('add', (filepath) => {
162
+ console.error(`[NitroStack Hot Reload] File added: ${path.relative(projectRoot, filepath)}`);
163
+ restartMCPServer();
164
+ });
165
+ const shutdown = () => {
166
+ console.error('[NitroStack Hot Reload] Shutting down...');
167
+ watcher.close();
168
+ if (mcpProcess) {
169
+ mcpProcess.kill('SIGTERM');
170
+ }
171
+ logServer.close();
172
+ process.exit(0);
173
+ };
174
+ process.on('SIGINT', shutdown);
175
+ process.on('SIGTERM', shutdown);
176
+ }
177
+ // Run if main
178
+ const currentFilePath = fileURLToPath(import.meta.url);
179
+ if (process.argv[1] && (process.argv[1] === currentFilePath ||
180
+ process.argv[1].endsWith('mcp-dev-wrapper.js') ||
181
+ process.argv[1].endsWith('mcp-dev-wrapper.ts') ||
182
+ process.argv[1].endsWith('mcp-dev-wrapper'))) {
183
+ run().catch(err => {
184
+ console.error(err);
185
+ process.exit(1);
186
+ });
187
+ }
@@ -0,0 +1,31 @@
1
+ export declare const brand: {
2
+ accent: import("chalk").ChalkInstance;
3
+ accentBold: import("chalk").ChalkInstance;
4
+ accentLight: import("chalk").ChalkInstance;
5
+ accentLighter: import("chalk").ChalkInstance;
6
+ };
7
+ export declare const NITRO_BANNER_FULL: string;
8
+ export declare function createHeader(title: string, subtitle?: string): string;
9
+ export declare function createBox(lines: string[], type?: 'success' | 'error' | 'info' | 'warning'): string;
10
+ export declare function createSuccessBox(title: string, items: string[]): string;
11
+ export declare function createErrorBox(title: string, message: string): string;
12
+ export declare function createInfoBox(items: {
13
+ label: string;
14
+ value: string;
15
+ }[]): string;
16
+ export declare class NitroSpinner {
17
+ private spinner;
18
+ constructor(text: string);
19
+ start(): this;
20
+ update(text: string): this;
21
+ succeed(text?: string): this;
22
+ fail(text?: string): this;
23
+ info(text?: string): this;
24
+ warn(text?: string): this;
25
+ stop(): this;
26
+ }
27
+ export declare function log(message: string, type?: 'success' | 'error' | 'info' | 'warning' | 'dim'): void;
28
+ export declare function divider(): void;
29
+ export declare function spacer(): void;
30
+ export declare function nextSteps(steps: string[]): void;
31
+ //# sourceMappingURL=branding.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"branding.d.ts","sourceRoot":"","sources":["../../src/ui/branding.ts"],"names":[],"mappings":"AAWA,eAAO,MAAM,KAAK;;;;;CAKjB,CAAC;AAEF,eAAO,MAAM,iBAAiB,QAa7B,CAAC;AAEF,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CASrE;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,IAAI,GAAE,SAAS,GAAG,OAAO,GAAG,MAAM,GAAG,SAAkB,GAAG,MAAM,CAoB1G;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,CAQvE;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAQrE;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAAE,GAAG,MAAM,CAK/E;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,OAAO,CAAM;gBAET,IAAI,EAAE,MAAM;IAQxB,KAAK,IAAI,IAAI;IAKb,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAK1B,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI;IAK5B,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI;IAKzB,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI;IAKzB,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI;IAKzB,IAAI,IAAI,IAAI;CAIb;AAED,wBAAgB,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,GAAE,SAAS,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,GAAG,KAAc,GAAG,IAAI,CAU1G;AAED,wBAAgB,OAAO,IAAI,IAAI,CAE9B;AAED,wBAAgB,MAAM,IAAI,IAAI,CAE7B;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAM/C"}
@@ -0,0 +1,136 @@
1
+ import chalk from 'chalk';
2
+ import ora from 'ora';
3
+ // ═══════════════════════════════════════════════════════════════════════════
4
+ // NITROSTACK CLI BRANDING
5
+ // ═══════════════════════════════════════════════════════════════════════════
6
+ const ACCENT = '#FF6B35';
7
+ const ACCENT_LIGHT = '#FF8C42';
8
+ const ACCENT_LIGHTER = '#FFA94D';
9
+ export const brand = {
10
+ accent: chalk.hex(ACCENT),
11
+ accentBold: chalk.hex(ACCENT).bold,
12
+ accentLight: chalk.hex(ACCENT_LIGHT),
13
+ accentLighter: chalk.hex(ACCENT_LIGHTER),
14
+ };
15
+ export const NITRO_BANNER_FULL = `
16
+ ${brand.accentBold('╔══════════════════════════════════════════════════════════════════╗')}
17
+ ${brand.accentBold('║')} ${brand.accentBold('║')}
18
+ ${brand.accentBold('║')} ${brand.accentBold('███╗ ██╗██╗████████╗██████╗ ██████╗ ')} ${brand.accentBold('║')}
19
+ ${brand.accentBold('║')} ${brand.accentLight('████╗ ██║██║╚══██╔══╝██╔══██╗██╔═══██╗')} ${brand.accentBold('║')}
20
+ ${brand.accentBold('║')} ${brand.accentLighter('██╔██╗ ██║██║ ██║ ██████╔╝██║ ██║')} ${brand.accentBold('║')}
21
+ ${brand.accentBold('║')} ${chalk.hex('#FFCC80')('██║╚██╗██║██║ ██║ ██╔══██╗██║ ██║')} ${brand.accentBold('║')}
22
+ ${brand.accentBold('║')} ${chalk.hex('#FFE0B2')('██║ ╚████║██║ ██║ ██║ ██║╚██████╔╝')} ${brand.accentBold('║')}
23
+ ${brand.accentBold('║')} ${chalk.dim('╚═╝ ╚═══╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ')} ${brand.accentBold('║')}
24
+ ${brand.accentBold('║')} ${brand.accentBold('║')}
25
+ ${brand.accentBold('║')} ${chalk.white.bold('S T A C K')} ${chalk.dim('─────────────────────────────────────────')} ${brand.accentBold('║')}
26
+ ${brand.accentBold('║')} ${brand.accentBold('║')}
27
+ ${brand.accentBold('╚══════════════════════════════════════════════════════════════════╝')}
28
+ `;
29
+ export function createHeader(title, subtitle) {
30
+ const paddedTitle = title.padEnd(40);
31
+ const paddedSubtitle = (subtitle || '').padEnd(40);
32
+ return `
33
+ ${brand.accentBold('┌──────────────────────────────────────────────────────────────────┐')}
34
+ ${brand.accentBold('│')} ${brand.accentBold('NITRO')}${chalk.white.bold('STACK')} ${chalk.dim('━━')} ${chalk.white.bold(paddedTitle)} ${brand.accentBold('│')}
35
+ ${subtitle ? brand.accentBold('│') + ' ' + chalk.dim(paddedSubtitle) + ' ' + brand.accentBold('│') + '\n' : ''}${brand.accentBold('└──────────────────────────────────────────────────────────────────┘')}
36
+ `;
37
+ }
38
+ export function createBox(lines, type = 'info') {
39
+ const colors = {
40
+ success: { border: chalk.green, title: chalk.green.bold },
41
+ error: { border: chalk.red, title: chalk.red.bold },
42
+ info: { border: brand.accent, title: brand.accentBold },
43
+ warning: { border: chalk.yellow, title: chalk.yellow.bold },
44
+ };
45
+ const { border } = colors[type];
46
+ let output = border('┌──────────────────────────────────────────────────────────────────┐\n');
47
+ for (const line of lines) {
48
+ const paddedLine = line.padEnd(64);
49
+ output += border('│') + ' ' + paddedLine + ' ' + border('│') + '\n';
50
+ }
51
+ output += border('└──────────────────────────────────────────────────────────────────┘');
52
+ return output;
53
+ }
54
+ export function createSuccessBox(title, items) {
55
+ const lines = [
56
+ chalk.green.bold(`✓ ${title}`),
57
+ '',
58
+ ...items.map(item => chalk.dim(` ${item}`)),
59
+ '',
60
+ ];
61
+ return createBox(lines, 'success');
62
+ }
63
+ export function createErrorBox(title, message) {
64
+ const lines = [
65
+ chalk.red.bold(`✗ ${title}`),
66
+ '',
67
+ chalk.white(message.substring(0, 60)),
68
+ '',
69
+ ];
70
+ return createBox(lines, 'error');
71
+ }
72
+ export function createInfoBox(items) {
73
+ const lines = items.map(({ label, value }) => `${chalk.white.bold(label.padEnd(14))} ${chalk.cyan(value)}`);
74
+ return createBox(['', ...lines, ''], 'info');
75
+ }
76
+ export class NitroSpinner {
77
+ spinner;
78
+ constructor(text) {
79
+ this.spinner = ora({
80
+ text: chalk.dim(text),
81
+ color: 'yellow',
82
+ spinner: 'dots12',
83
+ });
84
+ }
85
+ start() {
86
+ this.spinner.start();
87
+ return this;
88
+ }
89
+ update(text) {
90
+ this.spinner.text = chalk.dim(text);
91
+ return this;
92
+ }
93
+ succeed(text) {
94
+ this.spinner.succeed(text ? chalk.green('✓ ') + chalk.dim(text) : undefined);
95
+ return this;
96
+ }
97
+ fail(text) {
98
+ this.spinner.fail(text ? chalk.red('✗ ') + chalk.dim(text) : undefined);
99
+ return this;
100
+ }
101
+ info(text) {
102
+ this.spinner.info(text ? chalk.blue('ℹ ') + chalk.dim(text) : undefined);
103
+ return this;
104
+ }
105
+ warn(text) {
106
+ this.spinner.warn(text ? chalk.yellow('⚠ ') + chalk.dim(text) : undefined);
107
+ return this;
108
+ }
109
+ stop() {
110
+ this.spinner.stop();
111
+ return this;
112
+ }
113
+ }
114
+ export function log(message, type = 'info') {
115
+ const icons = {
116
+ success: chalk.green('✓'),
117
+ error: chalk.red('✗'),
118
+ info: chalk.blue('ℹ'),
119
+ warning: chalk.yellow('⚠'),
120
+ dim: chalk.dim('·'),
121
+ };
122
+ console.log(` ${icons[type]} ${type === 'dim' ? chalk.dim(message) : message}`);
123
+ }
124
+ export function divider() {
125
+ console.log(chalk.dim(' ─────────────────────────────────────────────────────────────'));
126
+ }
127
+ export function spacer() {
128
+ console.log('');
129
+ }
130
+ export function nextSteps(steps) {
131
+ console.log(chalk.white.bold('\n Next steps:\n'));
132
+ steps.forEach((step, i) => {
133
+ console.log(chalk.dim(` ${i + 1}.`) + ' ' + chalk.cyan(step));
134
+ });
135
+ console.log('');
136
+ }
package/package.json ADDED
@@ -0,0 +1,69 @@
1
+ {
2
+ "name": "@nitrostack/cli",
3
+ "version": "1.0.0",
4
+ "description": "CLI for NitroStack - Create and manage MCP server projects",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "bin": {
9
+ "nitrostack-cli": "dist/index.js",
10
+ "@nitrostack/cli": "dist/index.js"
11
+ },
12
+ "exports": {
13
+ ".": {
14
+ "import": "./dist/index.js",
15
+ "require": "./dist/index.js",
16
+ "types": "./dist/index.d.ts"
17
+ }
18
+ },
19
+ "files": [
20
+ "dist/",
21
+ "templates/",
22
+ "README.md"
23
+ ],
24
+ "scripts": {
25
+ "build": "tsc && chmod +x dist/index.js",
26
+ "dev": "tsc --watch",
27
+ "test": "NODE_OPTIONS=--experimental-vm-modules jest",
28
+ "test:coverage": "NODE_OPTIONS=--experimental-vm-modules jest --coverage",
29
+ "prepublishOnly": "npm run build"
30
+ },
31
+ "keywords": [
32
+ "nitrostack",
33
+ "cli",
34
+ "mcp",
35
+ "create",
36
+ "scaffold",
37
+ "generator"
38
+ ],
39
+ "author": "Abhishek Pandit <abhishekpanditofficial@gmail.com>",
40
+ "license": "Apache-2.0",
41
+ "dependencies": {
42
+ "chalk": "^5.3.0",
43
+ "chokidar": "^3.6.0",
44
+ "commander": "^12.1.0",
45
+ "fs-extra": "^11.3.2",
46
+ "inquirer": "^9.3.7",
47
+ "open": "^10.1.0",
48
+ "ora": "^8.1.1"
49
+ },
50
+ "devDependencies": {
51
+ "@types/fs-extra": "^11.0.4",
52
+ "@types/inquirer": "^9.0.9",
53
+ "@types/jest": "^29.5.14",
54
+ "@types/node": "^22.10.5",
55
+ "jest": "^29.7.0",
56
+ "ts-jest": "^29.2.5",
57
+ "typescript": "^5.7.2"
58
+ },
59
+ "repository": {
60
+ "type": "git",
61
+ "url": "https://github.com/abhishekpanditofficial/nitrostack.git",
62
+ "directory": "typescript/packages/cli"
63
+ },
64
+ "bugs": {
65
+ "url": "https://github.com/abhishekpanditofficial/nitrostack/issues"
66
+ },
67
+ "homepage": "https://nitrostack.vercel.app"
68
+ }
69
+
@@ -0,0 +1,27 @@
1
+
2
+ # OAuth 2.1 MCP Server Configuration
3
+ # =============================================================================
4
+ # TRANSPORT MODE (AUTO-CONFIGURED)
5
+ # =============================================================================
6
+ # When OAuth is configured, the server automatically runs in DUAL mode:
7
+ # - STDIO: For MCP protocol communication with Studio/Claude
8
+ # - HTTP: For OAuth metadata endpoints (/.well-known/oauth-protected-resource)
9
+ # Both transports run simultaneously on different channels.
10
+ # =============================================================================
11
+ # REQUIRED: Server Configuration
12
+ # =============================================================================
13
+ # =============================================================================
14
+ # Auth0 Configuration
15
+ # =============================================================================
16
+ # After creating your API and Application in Auth0, fill in these values:
17
+ # Your Auth0 API Identifier (from APIs → MCP Server → Identifier)
18
+ # This MUST match exactly what you set when creating the API
19
+ RESOURCE_URI=https://mcplocal
20
+ # Your Auth0 tenant domain (authorization server)
21
+ AUTH_SERVER_URL=https://dev-5dt0utuk31h13tjm.us.auth0.com
22
+ # Expected token audience (should match RESOURCE_URI)
23
+ TOKEN_AUDIENCE=https://mcplocal
24
+ # Expected token issuer (your Auth0 tenant domain with trailing slash)
25
+ TOKEN_ISSUER=https://dev-5dt0utuk31h13tjm.us.auth0.com/
26
+
27
+ DUFFEL_API_KEY=duffel_test_-w0wGDHB0M3DU9k-sBeUbxLqwcibUQqfEbjWDTKNnlf