@nitrostack/cli 1.0.6 → 1.0.8
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/LICENSE +201 -0
- package/README.md +39 -96
- package/dist/commands/build.d.ts.map +1 -1
- package/dist/commands/build.js +4 -1
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/dev.js +24 -52
- package/dist/commands/generate-types.d.ts +0 -1
- package/dist/commands/generate-types.d.ts.map +1 -1
- package/dist/commands/generate-types.js +18 -39
- package/dist/commands/generate.d.ts.map +1 -1
- package/dist/commands/generate.js +12 -4
- package/dist/commands/init.d.ts +3 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +27 -15
- package/dist/commands/install.d.ts.map +1 -1
- package/dist/commands/install.js +3 -1
- package/dist/commands/start.d.ts.map +1 -1
- package/dist/commands/start.js +4 -4
- package/dist/commands/upgrade.d.ts.map +1 -1
- package/dist/commands/upgrade.js +92 -77
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/ui/branding.d.ts +21 -4
- package/dist/ui/branding.d.ts.map +1 -1
- package/dist/ui/branding.js +121 -52
- package/package.json +5 -6
- package/templates/typescript-oauth/.env.example +27 -0
- package/templates/typescript-oauth/README.md +36 -231
- package/templates/typescript-pizzaz/.env.example +8 -0
- package/templates/typescript-pizzaz/README.md +42 -217
- package/templates/typescript-pizzaz/src/modules/pizzaz/pizzaz.module.ts +2 -1
- package/templates/typescript-pizzaz/src/modules/pizzaz/pizzaz.tasks.ts +294 -0
- package/templates/typescript-starter/.env.example +7 -0
- package/templates/typescript-starter/README.md +51 -284
package/dist/commands/upgrade.js
CHANGED
|
@@ -2,33 +2,33 @@ import chalk from 'chalk';
|
|
|
2
2
|
import { execSync } from 'child_process';
|
|
3
3
|
import path from 'path';
|
|
4
4
|
import fs from 'fs-extra';
|
|
5
|
-
import { createHeader, createSuccessBox, createErrorBox, NitroSpinner, log, spacer, nextSteps,
|
|
5
|
+
import { createHeader, createBox, createSuccessBox, createErrorBox, NitroSpinner, log, spacer, nextSteps, NITRO_BANNER_FULL, showFooter } from '../ui/branding.js';
|
|
6
6
|
/**
|
|
7
|
-
* Get the latest version of
|
|
7
|
+
* Get the latest version of a package from npm registry
|
|
8
8
|
*/
|
|
9
|
-
function getLatestVersion() {
|
|
9
|
+
function getLatestVersion(packageName = '@nitrostack/core') {
|
|
10
10
|
try {
|
|
11
|
-
const result = execSync(
|
|
11
|
+
const result = execSync(`npm view ${packageName} version`, {
|
|
12
12
|
encoding: 'utf-8',
|
|
13
13
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
14
14
|
}).trim();
|
|
15
15
|
return result;
|
|
16
16
|
}
|
|
17
17
|
catch {
|
|
18
|
-
throw new Error(
|
|
18
|
+
throw new Error(`Failed to fetch latest version for ${packageName} from npm`);
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
/**
|
|
22
|
-
* Get the current installed version of nitrostack from package.json
|
|
22
|
+
* Get the current installed version of @nitrostack/core from package.json
|
|
23
23
|
*/
|
|
24
|
-
function
|
|
24
|
+
function getCoreVersion(packageJsonPath) {
|
|
25
25
|
if (!fs.existsSync(packageJsonPath)) {
|
|
26
26
|
return null;
|
|
27
27
|
}
|
|
28
28
|
const packageJson = fs.readJSONSync(packageJsonPath);
|
|
29
|
-
|
|
30
|
-
packageJson.devDependencies?.nitrostack
|
|
31
|
-
|
|
29
|
+
return packageJson.dependencies?.['@nitrostack/core'] ||
|
|
30
|
+
packageJson.devDependencies?.['@nitrostack/core'] ||
|
|
31
|
+
null;
|
|
32
32
|
}
|
|
33
33
|
/**
|
|
34
34
|
* Parse version string to extract the actual version number
|
|
@@ -53,26 +53,41 @@ function compareVersions(v1, v2) {
|
|
|
53
53
|
return 0;
|
|
54
54
|
}
|
|
55
55
|
/**
|
|
56
|
-
* Update nitrostack
|
|
56
|
+
* Update all @nitrostack/* versions in package.json
|
|
57
57
|
*/
|
|
58
58
|
function updatePackageJson(packageJsonPath, newVersion, dryRun) {
|
|
59
59
|
if (!fs.existsSync(packageJsonPath)) {
|
|
60
|
-
return
|
|
60
|
+
return [];
|
|
61
61
|
}
|
|
62
62
|
const packageJson = fs.readJSONSync(packageJsonPath);
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
63
|
+
const results = [];
|
|
64
|
+
let hasChanges = false;
|
|
65
|
+
const updateDeps = (deps) => {
|
|
66
|
+
if (!deps)
|
|
67
|
+
return;
|
|
68
|
+
for (const pkg of Object.keys(deps)) {
|
|
69
|
+
if (pkg.startsWith('@nitrostack/')) {
|
|
70
|
+
const currentVersion = deps[pkg];
|
|
71
|
+
if (compareVersions(currentVersion, newVersion) < 0) {
|
|
72
|
+
results.push({
|
|
73
|
+
location: path.basename(path.dirname(packageJsonPath)),
|
|
74
|
+
packageName: pkg,
|
|
75
|
+
previousVersion: currentVersion,
|
|
76
|
+
newVersion: `^${newVersion}`,
|
|
77
|
+
upgraded: true,
|
|
78
|
+
});
|
|
79
|
+
deps[pkg] = `^${newVersion}`;
|
|
80
|
+
hasChanges = true;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
updateDeps(packageJson.dependencies);
|
|
86
|
+
updateDeps(packageJson.devDependencies);
|
|
87
|
+
if (hasChanges && !dryRun) {
|
|
73
88
|
fs.writeJSONSync(packageJsonPath, packageJson, { spaces: 2 });
|
|
74
89
|
}
|
|
75
|
-
return
|
|
90
|
+
return results;
|
|
76
91
|
}
|
|
77
92
|
/**
|
|
78
93
|
* Run npm install silently
|
|
@@ -87,7 +102,8 @@ function runNpmInstall(directory) {
|
|
|
87
102
|
* Main upgrade command handler
|
|
88
103
|
*/
|
|
89
104
|
export async function upgradeCommand(options) {
|
|
90
|
-
console.log(
|
|
105
|
+
console.log(NITRO_BANNER_FULL);
|
|
106
|
+
console.log(createHeader('Upgrade', 'Update @nitrostack packages to latest'));
|
|
91
107
|
const projectRoot = process.cwd();
|
|
92
108
|
const rootPackageJsonPath = path.join(projectRoot, 'package.json');
|
|
93
109
|
const widgetsPath = path.join(projectRoot, 'src', 'widgets');
|
|
@@ -97,16 +113,16 @@ export async function upgradeCommand(options) {
|
|
|
97
113
|
console.log(createErrorBox('Not a NitroStack Project', 'package.json not found'));
|
|
98
114
|
process.exit(1);
|
|
99
115
|
}
|
|
100
|
-
const
|
|
101
|
-
if (!
|
|
102
|
-
console.log(createErrorBox('Not a NitroStack Project', 'nitrostack is not a dependency'));
|
|
116
|
+
const coreVersion = getCoreVersion(rootPackageJsonPath);
|
|
117
|
+
if (!coreVersion) {
|
|
118
|
+
console.log(createErrorBox('Not a NitroStack Project', '@nitrostack/core is not a dependency'));
|
|
103
119
|
process.exit(1);
|
|
104
120
|
}
|
|
105
121
|
// Fetch latest version
|
|
106
122
|
const spinner = new NitroSpinner('Checking for updates...').start();
|
|
107
123
|
let latestVersion;
|
|
108
124
|
try {
|
|
109
|
-
latestVersion = getLatestVersion();
|
|
125
|
+
latestVersion = getLatestVersion('@nitrostack/core');
|
|
110
126
|
spinner.succeed(`Latest version: ${chalk.cyan(latestVersion)}`);
|
|
111
127
|
}
|
|
112
128
|
catch (error) {
|
|
@@ -114,16 +130,16 @@ export async function upgradeCommand(options) {
|
|
|
114
130
|
process.exit(1);
|
|
115
131
|
}
|
|
116
132
|
// Check if already on latest
|
|
117
|
-
const
|
|
118
|
-
if (compareVersions(
|
|
133
|
+
const currentParsedVersion = parseVersion(coreVersion);
|
|
134
|
+
if (compareVersions(currentParsedVersion, latestVersion) >= 0) {
|
|
119
135
|
spacer();
|
|
120
136
|
console.log(createSuccessBox('Already Up to Date', [
|
|
121
|
-
`Current version: ${
|
|
137
|
+
`Current version: ${currentParsedVersion}`,
|
|
122
138
|
`Latest version: ${latestVersion}`,
|
|
123
139
|
]));
|
|
124
140
|
return;
|
|
125
141
|
}
|
|
126
|
-
const
|
|
142
|
+
const allResults = [];
|
|
127
143
|
const dryRun = options.dryRun ?? false;
|
|
128
144
|
if (dryRun) {
|
|
129
145
|
spacer();
|
|
@@ -135,15 +151,10 @@ export async function upgradeCommand(options) {
|
|
|
135
151
|
// Upgrade root
|
|
136
152
|
const rootSpinner = new NitroSpinner('Updating root package.json...').start();
|
|
137
153
|
try {
|
|
138
|
-
const
|
|
139
|
-
if (
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
previousVersion: rootCurrentVersion,
|
|
143
|
-
newVersion: `^${latestVersion}`,
|
|
144
|
-
upgraded: true,
|
|
145
|
-
});
|
|
146
|
-
rootSpinner.succeed(`Root: ${chalk.dim(rootCurrentVersion)} → ${chalk.cyan(`^${latestVersion}`)}`);
|
|
154
|
+
const results = updatePackageJson(rootPackageJsonPath, latestVersion, dryRun);
|
|
155
|
+
if (results.length > 0) {
|
|
156
|
+
allResults.push(...results);
|
|
157
|
+
rootSpinner.succeed(`Root: Updated ${results.length} @nitrostack packages`);
|
|
147
158
|
if (!dryRun) {
|
|
148
159
|
const installSpinner = new NitroSpinner('Installing dependencies...').start();
|
|
149
160
|
runNpmInstall(projectRoot);
|
|
@@ -151,64 +162,68 @@ export async function upgradeCommand(options) {
|
|
|
151
162
|
}
|
|
152
163
|
}
|
|
153
164
|
else {
|
|
154
|
-
rootSpinner.info('Root:
|
|
165
|
+
rootSpinner.info('Root: All @nitrostack packages are up to date');
|
|
155
166
|
}
|
|
156
167
|
}
|
|
157
168
|
catch (error) {
|
|
158
169
|
rootSpinner.fail('Failed to upgrade root');
|
|
159
|
-
|
|
170
|
+
console.error(error);
|
|
160
171
|
}
|
|
161
172
|
// Upgrade widgets if they exist
|
|
162
173
|
if (fs.existsSync(widgetsPackageJsonPath)) {
|
|
163
|
-
const
|
|
164
|
-
|
|
165
|
-
const
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
upgraded: true,
|
|
174
|
-
});
|
|
175
|
-
widgetsSpinner.succeed(`Widgets: ${chalk.dim(widgetsCurrentVersion)} → ${chalk.cyan(`^${latestVersion}`)}`);
|
|
176
|
-
if (!dryRun) {
|
|
177
|
-
const installSpinner = new NitroSpinner('Installing widget dependencies...').start();
|
|
178
|
-
runNpmInstall(widgetsPath);
|
|
179
|
-
installSpinner.succeed('Widget dependencies installed');
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
else {
|
|
183
|
-
widgetsSpinner.info('Widgets: No changes needed');
|
|
174
|
+
const widgetsSpinner = new NitroSpinner('Updating widgets package.json...').start();
|
|
175
|
+
try {
|
|
176
|
+
const results = updatePackageJson(widgetsPackageJsonPath, latestVersion, dryRun);
|
|
177
|
+
if (results.length > 0) {
|
|
178
|
+
allResults.push(...results);
|
|
179
|
+
widgetsSpinner.succeed(`Widgets: Updated ${results.length} @nitrostack packages`);
|
|
180
|
+
if (!dryRun) {
|
|
181
|
+
const installSpinner = new NitroSpinner('Installing widget dependencies...').start();
|
|
182
|
+
runNpmInstall(widgetsPath);
|
|
183
|
+
installSpinner.succeed('Widget dependencies installed');
|
|
184
184
|
}
|
|
185
185
|
}
|
|
186
|
-
|
|
187
|
-
widgetsSpinner.
|
|
186
|
+
else {
|
|
187
|
+
widgetsSpinner.info('Widgets: All @nitrostack packages are up to date');
|
|
188
188
|
}
|
|
189
189
|
}
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
190
|
+
catch (error) {
|
|
191
|
+
widgetsSpinner.fail('Failed to upgrade widgets');
|
|
192
|
+
}
|
|
193
193
|
}
|
|
194
194
|
// Summary
|
|
195
195
|
spacer();
|
|
196
|
-
if (
|
|
196
|
+
if (allResults.length === 0) {
|
|
197
197
|
log('No packages were upgraded', 'warning');
|
|
198
198
|
}
|
|
199
199
|
else {
|
|
200
|
-
|
|
200
|
+
// Unique packages upgraded
|
|
201
|
+
const uniquePackages = Array.from(new Set(allResults.map(r => r.packageName)));
|
|
202
|
+
const summaryItems = uniquePackages.map(pkg => {
|
|
203
|
+
const result = allResults.find(r => r.packageName === pkg);
|
|
204
|
+
return `${pkg}: ${parseVersion(result.previousVersion)} → ${parseVersion(result.newVersion)}`;
|
|
205
|
+
});
|
|
201
206
|
if (dryRun) {
|
|
202
|
-
|
|
203
|
-
log(
|
|
207
|
+
spacer();
|
|
208
|
+
console.log(createBox([
|
|
209
|
+
chalk.yellow.bold('Dry run complete'),
|
|
210
|
+
'',
|
|
211
|
+
chalk.dim('No changes were made to your project.'),
|
|
212
|
+
chalk.dim('Run without --dry-run to apply the upgrade.'),
|
|
213
|
+
], 'warning'));
|
|
204
214
|
}
|
|
205
215
|
else {
|
|
206
|
-
console.log(createSuccessBox('Upgrade Complete',
|
|
216
|
+
console.log(createSuccessBox('Upgrade Complete', [
|
|
217
|
+
...summaryItems,
|
|
218
|
+
'',
|
|
219
|
+
chalk.dim(`Total updates across all packages: ${allResults.length}`)
|
|
220
|
+
]));
|
|
207
221
|
nextSteps([
|
|
208
|
-
'Review the changes',
|
|
209
|
-
'
|
|
210
|
-
'Check
|
|
222
|
+
'Review the changes in package.json',
|
|
223
|
+
'Restart your development server',
|
|
224
|
+
'Check docs.nitrostack.ai for migration guides',
|
|
211
225
|
]);
|
|
212
226
|
}
|
|
227
|
+
showFooter();
|
|
213
228
|
}
|
|
214
229
|
}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAapC,wBAAgB,aAAa,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAapC,wBAAgB,aAAa,YAgE5B;AAGD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -20,7 +20,9 @@ export function createProgram() {
|
|
|
20
20
|
.command('init')
|
|
21
21
|
.description('Initialize a new NitroStack project')
|
|
22
22
|
.argument('[project-name]', 'Name of the project')
|
|
23
|
-
.option('--template <template>', 'Template to use (typescript, typescript-
|
|
23
|
+
.option('--template <template>', 'Template to use (typescript-starter, typescript-pizzaz, typescript-oauth)', 'typescript-starter')
|
|
24
|
+
.option('--description <description>', 'Description of the project')
|
|
25
|
+
.option('--author <author>', 'Author of the project')
|
|
24
26
|
.option('--skip-install', 'Skip installing dependencies')
|
|
25
27
|
.action(initCommand);
|
|
26
28
|
program
|
package/dist/ui/branding.d.ts
CHANGED
|
@@ -1,9 +1,25 @@
|
|
|
1
|
+
export declare const LINKS: {
|
|
2
|
+
website: string;
|
|
3
|
+
docs: string;
|
|
4
|
+
studio: string;
|
|
5
|
+
};
|
|
1
6
|
export declare const brand: {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
7
|
+
signal: import("chalk").ChalkInstance;
|
|
8
|
+
signalBold: import("chalk").ChalkInstance;
|
|
9
|
+
sky: import("chalk").ChalkInstance;
|
|
10
|
+
skyBold: import("chalk").ChalkInstance;
|
|
11
|
+
mint: import("chalk").ChalkInstance;
|
|
12
|
+
mintBold: import("chalk").ChalkInstance;
|
|
13
|
+
error: import("chalk").ChalkInstance;
|
|
14
|
+
warning: import("chalk").ChalkInstance;
|
|
6
15
|
};
|
|
16
|
+
/**
|
|
17
|
+
* Creates a clickable terminal link using OSC 8 escape sequence
|
|
18
|
+
*/
|
|
19
|
+
export declare function terminalLink(text: string, url: string): string;
|
|
20
|
+
/**
|
|
21
|
+
* Redesigned Banner with Restored ASCII NITRO
|
|
22
|
+
*/
|
|
7
23
|
export declare const NITRO_BANNER_FULL: string;
|
|
8
24
|
export declare function createHeader(title: string, subtitle?: string): string;
|
|
9
25
|
export declare function createBox(lines: string[], type?: 'success' | 'error' | 'info' | 'warning'): string;
|
|
@@ -28,4 +44,5 @@ export declare function log(message: string, type?: 'success' | 'error' | 'info'
|
|
|
28
44
|
export declare function divider(): void;
|
|
29
45
|
export declare function spacer(): void;
|
|
30
46
|
export declare function nextSteps(steps: string[]): void;
|
|
47
|
+
export declare function showFooter(): void;
|
|
31
48
|
//# sourceMappingURL=branding.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"branding.d.ts","sourceRoot":"","sources":["../../src/ui/branding.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"branding.d.ts","sourceRoot":"","sources":["../../src/ui/branding.ts"],"names":[],"mappings":"AAgBA,eAAO,MAAM,KAAK;;;;CAIjB,CAAC;AAEF,eAAO,MAAM,KAAK;;;;;;;;;CASjB,CAAC;AASF;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAG9D;AAaD;;GAEG;AACH,eAAO,MAAM,iBAAiB,QAa7B,CAAC;AAEF,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAqBrE;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,IAAI,GAAE,SAAS,GAAG,OAAO,GAAG,MAAM,GAAG,SAAkB,GAAG,MAAM,CA4B1G;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,CAc/C;AAED,wBAAgB,UAAU,IAAI,IAAI,CAYjC"}
|
package/dist/ui/branding.js
CHANGED
|
@@ -1,59 +1,112 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import ora from 'ora';
|
|
3
3
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
4
|
-
//
|
|
4
|
+
// OFFICIAL MCP BRANDING (Wekan Enterprise Solutions)
|
|
5
5
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
const
|
|
6
|
+
// Core Colors
|
|
7
|
+
const SIGNAL_BLUE = '#187CF4'; // Primary
|
|
8
|
+
const SKY_BLUE = '#05A3FD'; // Secondary
|
|
9
|
+
const SUCCESS_MINT = '#2AB5A5'; // Success
|
|
10
|
+
const ERROR_FLAME = '#EF4444'; // Error
|
|
11
|
+
const WARNING_AMBER = '#F59E0B'; // Warning
|
|
12
|
+
const SLATE_INK = '#121217'; // Text Primary (Light Mode Context)
|
|
13
|
+
// Official Links
|
|
14
|
+
export const LINKS = {
|
|
15
|
+
website: 'https://nitrostack.ai',
|
|
16
|
+
docs: 'https://docs.nitrostack.ai',
|
|
17
|
+
studio: 'https://nitrostack.ai/studio',
|
|
18
|
+
};
|
|
9
19
|
export const brand = {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
20
|
+
signal: chalk.hex(SIGNAL_BLUE),
|
|
21
|
+
signalBold: chalk.hex(SIGNAL_BLUE).bold,
|
|
22
|
+
sky: chalk.hex(SKY_BLUE),
|
|
23
|
+
skyBold: chalk.hex(SKY_BLUE).bold,
|
|
24
|
+
mint: chalk.hex(SUCCESS_MINT),
|
|
25
|
+
mintBold: chalk.hex(SUCCESS_MINT).bold,
|
|
26
|
+
error: chalk.hex(ERROR_FLAME),
|
|
27
|
+
warning: chalk.hex(WARNING_AMBER),
|
|
14
28
|
};
|
|
29
|
+
const TOTAL_WIDTH = 68;
|
|
30
|
+
/**
|
|
31
|
+
* Strips ANSI codes for visual length calculation
|
|
32
|
+
*/
|
|
33
|
+
const stripAnsi = (str) => str.replace(/\u001b\[[0-9;]*m/g, '');
|
|
34
|
+
/**
|
|
35
|
+
* Creates a clickable terminal link using OSC 8 escape sequence
|
|
36
|
+
*/
|
|
37
|
+
export function terminalLink(text, url) {
|
|
38
|
+
// OSC 8 escape sequence: \x1b]8;;url\x1b\\text\x1b]8;;\x1b\\
|
|
39
|
+
return `\u001b]8;;${url}\u001b\\${text}\u001b]8;;\u001b\\`;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Creates a line for a box with consistent width and borders
|
|
43
|
+
*/
|
|
44
|
+
function boxLine(content, borderColor = brand.signalBold) {
|
|
45
|
+
const visualLength = stripAnsi(content).length;
|
|
46
|
+
const paddingSize = Math.max(0, TOTAL_WIDTH - visualLength - 2);
|
|
47
|
+
const padding = ' '.repeat(paddingSize);
|
|
48
|
+
return borderColor('║') + content + padding + borderColor('║');
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Redesigned Banner with Restored ASCII NITRO
|
|
52
|
+
*/
|
|
15
53
|
export const NITRO_BANNER_FULL = `
|
|
16
|
-
${brand.
|
|
17
|
-
${
|
|
18
|
-
${
|
|
19
|
-
${
|
|
20
|
-
${
|
|
21
|
-
${
|
|
22
|
-
${
|
|
23
|
-
${
|
|
24
|
-
${
|
|
25
|
-
${brand.
|
|
26
|
-
${
|
|
27
|
-
${brand.
|
|
54
|
+
${brand.signalBold('╔' + '═'.repeat(TOTAL_WIDTH - 2) + '╗')}
|
|
55
|
+
${boxLine('')}
|
|
56
|
+
${boxLine(' ' + brand.signalBold('███╗ ██╗██╗████████╗██████╗ ██████╗ '))}
|
|
57
|
+
${boxLine(' ' + brand.signalBold('████╗ ██║██║╚══██╔══╝██╔══██╗██╔═══██╗'))}
|
|
58
|
+
${boxLine(' ' + brand.signalBold('██╔██╗ ██║██║ ██║ ██████╔╝██║ ██║'))}
|
|
59
|
+
${boxLine(' ' + brand.skyBold('██║╚██╗██║██║ ██║ ██╔══██╗██║ ██║'))}
|
|
60
|
+
${boxLine(' ' + brand.skyBold('██║ ╚████║██║ ██║ ██║ ██║╚██████╔╝'))}
|
|
61
|
+
${boxLine(' ' + chalk.dim('╚═╝ ╚═══╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ '))}
|
|
62
|
+
${boxLine('')}
|
|
63
|
+
${boxLine(' ' + brand.signalBold('NITROSTACK') + ' ' + chalk.dim('─ Official MCP Framework'))}
|
|
64
|
+
${boxLine('')}
|
|
65
|
+
${brand.signalBold('╚' + '═'.repeat(TOTAL_WIDTH - 2) + '╝')}
|
|
28
66
|
`;
|
|
29
67
|
export function createHeader(title, subtitle) {
|
|
30
|
-
const
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
68
|
+
const content = ' ' + brand.signalBold('NITROSTACK') + ' ' + chalk.dim('─') + ' ' + chalk.white.bold(title);
|
|
69
|
+
const subContent = subtitle ? ' ' + chalk.dim(subtitle) : '';
|
|
70
|
+
const borderTop = brand.signalBold('┌' + '─'.repeat(TOTAL_WIDTH - 2) + '┐');
|
|
71
|
+
const borderBottom = brand.signalBold('└' + '─'.repeat(TOTAL_WIDTH - 2) + '┘');
|
|
72
|
+
const line = (c) => {
|
|
73
|
+
const visualLength = stripAnsi(c).length;
|
|
74
|
+
const paddingSize = Math.max(0, TOTAL_WIDTH - visualLength - 2);
|
|
75
|
+
const padding = ' '.repeat(paddingSize);
|
|
76
|
+
return brand.signalBold('│') + c + padding + brand.signalBold('│');
|
|
77
|
+
};
|
|
78
|
+
let header = `\n${borderTop}\n${line(content)}\n`;
|
|
79
|
+
if (subtitle) {
|
|
80
|
+
header += `${line(subContent)}\n`;
|
|
81
|
+
}
|
|
82
|
+
header += `${borderBottom}\n`;
|
|
83
|
+
return header;
|
|
37
84
|
}
|
|
38
85
|
export function createBox(lines, type = 'info') {
|
|
39
86
|
const colors = {
|
|
40
|
-
success: { border:
|
|
41
|
-
error: { border:
|
|
42
|
-
info: { border: brand.
|
|
43
|
-
warning: { border:
|
|
87
|
+
success: { border: brand.mint, bTop: '┌', bSide: '│', bBot: '└' },
|
|
88
|
+
error: { border: brand.error, bTop: '┌', bSide: '│', bBot: '└' },
|
|
89
|
+
info: { border: brand.signal, bTop: '┌', bSide: '│', bBot: '└' },
|
|
90
|
+
warning: { border: brand.warning, bTop: '┌', bSide: '│', bBot: '└' },
|
|
44
91
|
};
|
|
45
|
-
const { border } = colors[type];
|
|
46
|
-
let output = border('
|
|
47
|
-
for (
|
|
48
|
-
const
|
|
49
|
-
|
|
92
|
+
const { border, bTop, bSide, bBot } = colors[type];
|
|
93
|
+
let output = border(bTop + '─'.repeat(TOTAL_WIDTH - 2) + '┐\n');
|
|
94
|
+
for (let line of lines) {
|
|
95
|
+
const maxInnerWidth = TOTAL_WIDTH - 6;
|
|
96
|
+
const visualLength = stripAnsi(line).length;
|
|
97
|
+
if (visualLength > maxInnerWidth) {
|
|
98
|
+
line = line.substring(0, maxInnerWidth - 3) + '...';
|
|
99
|
+
}
|
|
100
|
+
const finalVisualLength = stripAnsi(line).length;
|
|
101
|
+
const padding = ' '.repeat(Math.max(0, TOTAL_WIDTH - finalVisualLength - 6));
|
|
102
|
+
output += border(bSide) + ' ' + line + padding + ' ' + border(bSide) + '\n';
|
|
50
103
|
}
|
|
51
|
-
output += border('
|
|
104
|
+
output += border(bBot + '─'.repeat(TOTAL_WIDTH - 2) + '┘');
|
|
52
105
|
return output;
|
|
53
106
|
}
|
|
54
107
|
export function createSuccessBox(title, items) {
|
|
55
108
|
const lines = [
|
|
56
|
-
|
|
109
|
+
brand.mintBold(`✓ ${title}`),
|
|
57
110
|
'',
|
|
58
111
|
...items.map(item => chalk.dim(` ${item}`)),
|
|
59
112
|
'',
|
|
@@ -62,15 +115,15 @@ export function createSuccessBox(title, items) {
|
|
|
62
115
|
}
|
|
63
116
|
export function createErrorBox(title, message) {
|
|
64
117
|
const lines = [
|
|
65
|
-
|
|
118
|
+
brand.error.bold(`✗ ${title}`),
|
|
66
119
|
'',
|
|
67
|
-
chalk.white(message.substring(0,
|
|
120
|
+
chalk.white(message.substring(0, TOTAL_WIDTH - 10)),
|
|
68
121
|
'',
|
|
69
122
|
];
|
|
70
123
|
return createBox(lines, 'error');
|
|
71
124
|
}
|
|
72
125
|
export function createInfoBox(items) {
|
|
73
|
-
const lines = items.map(({ label, value }) => `${chalk.white.bold(label.padEnd(14))} ${
|
|
126
|
+
const lines = items.map(({ label, value }) => `${chalk.white.bold(label.padEnd(14))} ${brand.sky(value)}`);
|
|
74
127
|
return createBox(['', ...lines, ''], 'info');
|
|
75
128
|
}
|
|
76
129
|
export class NitroSpinner {
|
|
@@ -78,7 +131,7 @@ export class NitroSpinner {
|
|
|
78
131
|
constructor(text) {
|
|
79
132
|
this.spinner = ora({
|
|
80
133
|
text: chalk.dim(text),
|
|
81
|
-
color: '
|
|
134
|
+
color: 'blue',
|
|
82
135
|
spinner: 'dots12',
|
|
83
136
|
});
|
|
84
137
|
}
|
|
@@ -91,19 +144,19 @@ export class NitroSpinner {
|
|
|
91
144
|
return this;
|
|
92
145
|
}
|
|
93
146
|
succeed(text) {
|
|
94
|
-
this.spinner.succeed(text ?
|
|
147
|
+
this.spinner.succeed(text ? brand.mint('✓ ') + chalk.dim(text) : undefined);
|
|
95
148
|
return this;
|
|
96
149
|
}
|
|
97
150
|
fail(text) {
|
|
98
|
-
this.spinner.fail(text ?
|
|
151
|
+
this.spinner.fail(text ? brand.error('✗ ') + chalk.dim(text) : undefined);
|
|
99
152
|
return this;
|
|
100
153
|
}
|
|
101
154
|
info(text) {
|
|
102
|
-
this.spinner.info(text ?
|
|
155
|
+
this.spinner.info(text ? brand.signal('ℹ ') + chalk.dim(text) : undefined);
|
|
103
156
|
return this;
|
|
104
157
|
}
|
|
105
158
|
warn(text) {
|
|
106
|
-
this.spinner.warn(text ?
|
|
159
|
+
this.spinner.warn(text ? brand.warning('⚠ ') + chalk.dim(text) : undefined);
|
|
107
160
|
return this;
|
|
108
161
|
}
|
|
109
162
|
stop() {
|
|
@@ -113,16 +166,16 @@ export class NitroSpinner {
|
|
|
113
166
|
}
|
|
114
167
|
export function log(message, type = 'info') {
|
|
115
168
|
const icons = {
|
|
116
|
-
success:
|
|
117
|
-
error:
|
|
118
|
-
info:
|
|
119
|
-
warning:
|
|
169
|
+
success: brand.mint('✓'),
|
|
170
|
+
error: brand.error('✗'),
|
|
171
|
+
info: brand.signal('ℹ'),
|
|
172
|
+
warning: brand.warning('⚠'),
|
|
120
173
|
dim: chalk.dim('·'),
|
|
121
174
|
};
|
|
122
175
|
console.log(` ${icons[type]} ${type === 'dim' ? chalk.dim(message) : message}`);
|
|
123
176
|
}
|
|
124
177
|
export function divider() {
|
|
125
|
-
console.log(chalk.dim('
|
|
178
|
+
console.log(chalk.dim(' ' + '─'.repeat(TOTAL_WIDTH - 4)));
|
|
126
179
|
}
|
|
127
180
|
export function spacer() {
|
|
128
181
|
console.log('');
|
|
@@ -130,7 +183,23 @@ export function spacer() {
|
|
|
130
183
|
export function nextSteps(steps) {
|
|
131
184
|
console.log(chalk.white.bold('\n Next steps:\n'));
|
|
132
185
|
steps.forEach((step, i) => {
|
|
133
|
-
console.log(chalk.dim(` ${i + 1}.`) + ' ' +
|
|
186
|
+
console.log(chalk.dim(` ${i + 1}.`) + ' ' + brand.sky(step));
|
|
134
187
|
});
|
|
188
|
+
// Always promote NitroStudio
|
|
189
|
+
const studioStep = steps.length + 1;
|
|
190
|
+
const studioText = brand.signalBold('Download NitroStudio');
|
|
191
|
+
const urlText = brand.sky(LINKS.studio);
|
|
192
|
+
const clickableUrl = terminalLink(urlText, LINKS.studio);
|
|
193
|
+
console.log(chalk.dim(` ${studioStep}.`) + ' ' + studioText + ' ' + chalk.dim('(') + clickableUrl + chalk.dim(')') + ' ' + chalk.dim('to run your MCP project with a visual client'));
|
|
135
194
|
console.log('');
|
|
136
195
|
}
|
|
196
|
+
export function showFooter() {
|
|
197
|
+
const website = terminalLink(brand.signal(LINKS.website), LINKS.website);
|
|
198
|
+
const docs = terminalLink(brand.signal(LINKS.docs), LINKS.docs);
|
|
199
|
+
const studio = terminalLink(brand.signal(LINKS.studio), LINKS.studio);
|
|
200
|
+
const content = `${chalk.dim('Website:')} ${website} ${chalk.dim('Docs:')} ${docs} ${chalk.dim('Studio:')} ${studio}`;
|
|
201
|
+
// Center the footer content
|
|
202
|
+
const visualLength = stripAnsi(content).length;
|
|
203
|
+
const padding = ' '.repeat(Math.max(0, Math.floor((TOTAL_WIDTH - visualLength) / 2)));
|
|
204
|
+
console.log('\n' + padding + content + '\n');
|
|
205
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nitrostack/cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.8",
|
|
4
4
|
"description": "CLI for NitroStack - Create and manage MCP server projects",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"scaffold",
|
|
37
37
|
"generator"
|
|
38
38
|
],
|
|
39
|
-
"author": "
|
|
39
|
+
"author": "Nitrostack Inc <hello@nitrostack.ai>",
|
|
40
40
|
"license": "Apache-2.0",
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"chalk": "^5.3.0",
|
|
@@ -59,12 +59,11 @@
|
|
|
59
59
|
},
|
|
60
60
|
"repository": {
|
|
61
61
|
"type": "git",
|
|
62
|
-
"url": "https://github.com/
|
|
62
|
+
"url": "https://github.com/nitrocloudofficial/nitrostack.git",
|
|
63
63
|
"directory": "typescript/packages/cli"
|
|
64
64
|
},
|
|
65
65
|
"bugs": {
|
|
66
|
-
"url": "https://github.com/
|
|
66
|
+
"url": "https://github.com/nitrocloudofficial/nitrostack/issues"
|
|
67
67
|
},
|
|
68
68
|
"homepage": "https://nitrostack.ai"
|
|
69
|
-
}
|
|
70
|
-
|
|
69
|
+
}
|