@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.
Files changed (34) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +39 -96
  3. package/dist/commands/build.d.ts.map +1 -1
  4. package/dist/commands/build.js +4 -1
  5. package/dist/commands/dev.d.ts.map +1 -1
  6. package/dist/commands/dev.js +24 -52
  7. package/dist/commands/generate-types.d.ts +0 -1
  8. package/dist/commands/generate-types.d.ts.map +1 -1
  9. package/dist/commands/generate-types.js +18 -39
  10. package/dist/commands/generate.d.ts.map +1 -1
  11. package/dist/commands/generate.js +12 -4
  12. package/dist/commands/init.d.ts +3 -1
  13. package/dist/commands/init.d.ts.map +1 -1
  14. package/dist/commands/init.js +27 -15
  15. package/dist/commands/install.d.ts.map +1 -1
  16. package/dist/commands/install.js +3 -1
  17. package/dist/commands/start.d.ts.map +1 -1
  18. package/dist/commands/start.js +4 -4
  19. package/dist/commands/upgrade.d.ts.map +1 -1
  20. package/dist/commands/upgrade.js +92 -77
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +3 -1
  23. package/dist/ui/branding.d.ts +21 -4
  24. package/dist/ui/branding.d.ts.map +1 -1
  25. package/dist/ui/branding.js +121 -52
  26. package/package.json +5 -6
  27. package/templates/typescript-oauth/.env.example +27 -0
  28. package/templates/typescript-oauth/README.md +36 -231
  29. package/templates/typescript-pizzaz/.env.example +8 -0
  30. package/templates/typescript-pizzaz/README.md +42 -217
  31. package/templates/typescript-pizzaz/src/modules/pizzaz/pizzaz.module.ts +2 -1
  32. package/templates/typescript-pizzaz/src/modules/pizzaz/pizzaz.tasks.ts +294 -0
  33. package/templates/typescript-starter/.env.example +7 -0
  34. package/templates/typescript-starter/README.md +51 -284
@@ -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, brand } from '../ui/branding.js';
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 nitrostack from npm registry
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('npm view nitrostack version', {
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('Failed to fetch latest version from npm');
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 getCurrentVersion(packageJsonPath) {
24
+ function getCoreVersion(packageJsonPath) {
25
25
  if (!fs.existsSync(packageJsonPath)) {
26
26
  return null;
27
27
  }
28
28
  const packageJson = fs.readJSONSync(packageJsonPath);
29
- const version = packageJson.dependencies?.nitrostack ||
30
- packageJson.devDependencies?.nitrostack;
31
- return version || null;
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 version in package.json
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 false;
60
+ return [];
61
61
  }
62
62
  const packageJson = fs.readJSONSync(packageJsonPath);
63
- let updated = false;
64
- if (packageJson.dependencies?.nitrostack) {
65
- packageJson.dependencies.nitrostack = `^${newVersion}`;
66
- updated = true;
67
- }
68
- if (packageJson.devDependencies?.nitrostack) {
69
- packageJson.devDependencies.nitrostack = `^${newVersion}`;
70
- updated = true;
71
- }
72
- if (updated && !dryRun) {
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 updated;
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(createHeader('Upgrade', 'Update nitrostack to the latest version'));
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 rootCurrentVersion = getCurrentVersion(rootPackageJsonPath);
101
- if (!rootCurrentVersion) {
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 rootParsedVersion = parseVersion(rootCurrentVersion);
118
- if (compareVersions(rootParsedVersion, latestVersion) >= 0) {
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: ${rootParsedVersion}`,
137
+ `Current version: ${currentParsedVersion}`,
122
138
  `Latest version: ${latestVersion}`,
123
139
  ]));
124
140
  return;
125
141
  }
126
- const results = [];
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 rootUpdated = updatePackageJson(rootPackageJsonPath, latestVersion, dryRun);
139
- if (rootUpdated) {
140
- results.push({
141
- location: 'root',
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: No changes needed');
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
- process.exit(1);
170
+ console.error(error);
160
171
  }
161
172
  // Upgrade widgets if they exist
162
173
  if (fs.existsSync(widgetsPackageJsonPath)) {
163
- const widgetsCurrentVersion = getCurrentVersion(widgetsPackageJsonPath);
164
- if (widgetsCurrentVersion) {
165
- const widgetsSpinner = new NitroSpinner('Updating widgets package.json...').start();
166
- try {
167
- const widgetsUpdated = updatePackageJson(widgetsPackageJsonPath, latestVersion, dryRun);
168
- if (widgetsUpdated) {
169
- results.push({
170
- location: 'src/widgets',
171
- previousVersion: widgetsCurrentVersion,
172
- newVersion: `^${latestVersion}`,
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
- catch (error) {
187
- widgetsSpinner.fail('Failed to upgrade widgets');
186
+ else {
187
+ widgetsSpinner.info('Widgets: All @nitrostack packages are up to date');
188
188
  }
189
189
  }
190
- }
191
- else {
192
- log('No widgets directory found', 'dim');
190
+ catch (error) {
191
+ widgetsSpinner.fail('Failed to upgrade widgets');
192
+ }
193
193
  }
194
194
  // Summary
195
195
  spacer();
196
- if (results.length === 0) {
196
+ if (allResults.length === 0) {
197
197
  log('No packages were upgraded', 'warning');
198
198
  }
199
199
  else {
200
- const summaryItems = results.map(r => `${r.location}: ${parseVersion(r.previousVersion)} → ${parseVersion(r.newVersion)}`);
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
- console.log(brand.accentBold('\n Dry run complete - no changes made\n'));
203
- log('Run without --dry-run to apply upgrade', 'dim');
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', summaryItems));
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
- 'Test your application',
210
- 'Check the changelog for breaking changes',
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
  }
@@ -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,YA8D5B;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"}
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-auth)', '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
@@ -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
- accent: import("chalk").ChalkInstance;
3
- accentBold: import("chalk").ChalkInstance;
4
- accentLight: import("chalk").ChalkInstance;
5
- accentLighter: import("chalk").ChalkInstance;
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":"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"}
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"}
@@ -1,59 +1,112 @@
1
1
  import chalk from 'chalk';
2
2
  import ora from 'ora';
3
3
  // ═══════════════════════════════════════════════════════════════════════════
4
- // NITROSTACK CLI BRANDING
4
+ // OFFICIAL MCP BRANDING (Wekan Enterprise Solutions)
5
5
  // ═══════════════════════════════════════════════════════════════════════════
6
- const ACCENT = '#FF6B35';
7
- const ACCENT_LIGHT = '#FF8C42';
8
- const ACCENT_LIGHTER = '#FFA94D';
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
- accent: chalk.hex(ACCENT),
11
- accentBold: chalk.hex(ACCENT).bold,
12
- accentLight: chalk.hex(ACCENT_LIGHT),
13
- accentLighter: chalk.hex(ACCENT_LIGHTER),
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.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('╚══════════════════════════════════════════════════════════════════╝')}
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 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
- `;
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: 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 },
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('┌──────────────────────────────────────────────────────────────────┐\n');
47
- for (const line of lines) {
48
- const paddedLine = line.padEnd(64);
49
- output += border('│') + ' ' + paddedLine + ' ' + border('│') + '\n';
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
- chalk.green.bold(`✓ ${title}`),
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
- chalk.red.bold(`✗ ${title}`),
118
+ brand.error.bold(`✗ ${title}`),
66
119
  '',
67
- chalk.white(message.substring(0, 60)),
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))} ${chalk.cyan(value)}`);
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: 'yellow',
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 ? chalk.green('✓ ') + chalk.dim(text) : undefined);
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 ? chalk.red('✗ ') + chalk.dim(text) : undefined);
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 ? chalk.blue('ℹ ') + chalk.dim(text) : undefined);
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 ? chalk.yellow('⚠ ') + chalk.dim(text) : undefined);
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: chalk.green('✓'),
117
- error: chalk.red('✗'),
118
- info: chalk.blue('ℹ'),
119
- warning: chalk.yellow('⚠'),
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}.`) + ' ' + chalk.cyan(step));
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.6",
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": "Abhishek Pandit <abhishekpanditofficial@gmail.com>",
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/abhishekpanditofficial/nitrostack.git",
62
+ "url": "https://github.com/nitrocloudofficial/nitrostack.git",
63
63
  "directory": "typescript/packages/cli"
64
64
  },
65
65
  "bugs": {
66
- "url": "https://github.com/abhishekpanditofficial/nitrostack/issues"
66
+ "url": "https://github.com/nitrocloudofficial/nitrostack/issues"
67
67
  },
68
68
  "homepage": "https://nitrostack.ai"
69
- }
70
-
69
+ }