@nitrostack/cli 1.0.13 → 1.0.15
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/assets/canonical.gitignore +57 -0
- package/dist/commands/init.d.ts +1 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +90 -16
- package/dist/commands/pack.d.ts +10 -0
- package/dist/commands/pack.d.ts.map +1 -0
- package/dist/commands/pack.js +82 -0
- package/dist/commands/upgrade.d.ts.map +1 -1
- package/dist/commands/upgrade.js +66 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -0
- package/dist/pack/canonical-gitignore.d.ts +14 -0
- package/dist/pack/canonical-gitignore.d.ts.map +1 -0
- package/dist/pack/canonical-gitignore.js +28 -0
- package/dist/pack/exclusions.d.ts +8 -0
- package/dist/pack/exclusions.d.ts.map +1 -0
- package/dist/pack/exclusions.js +84 -0
- package/dist/pack/gitignore.d.ts +21 -0
- package/dist/pack/gitignore.d.ts.map +1 -0
- package/dist/pack/gitignore.js +123 -0
- package/dist/pack/ignore-matcher.d.ts +19 -0
- package/dist/pack/ignore-matcher.d.ts.map +1 -0
- package/dist/pack/ignore-matcher.js +149 -0
- package/dist/pack/index.d.ts +11 -0
- package/dist/pack/index.d.ts.map +1 -0
- package/dist/pack/index.js +8 -0
- package/dist/pack/pack-project.d.ts +6 -0
- package/dist/pack/pack-project.d.ts.map +1 -0
- package/dist/pack/pack-project.js +59 -0
- package/dist/pack/standalone.d.ts +3 -0
- package/dist/pack/standalone.d.ts.map +1 -0
- package/dist/pack/standalone.js +95 -0
- package/dist/pack/tree.d.ts +5 -0
- package/dist/pack/tree.d.ts.map +1 -0
- package/dist/pack/tree.js +70 -0
- package/dist/pack/types.d.ts +35 -0
- package/dist/pack/types.d.ts.map +1 -0
- package/dist/pack/types.js +1 -0
- package/dist/pack/validate-project.d.ts +9 -0
- package/dist/pack/validate-project.d.ts.map +1 -0
- package/dist/pack/validate-project.js +44 -0
- package/dist/pack/zipper.d.ts +20 -0
- package/dist/pack/zipper.d.ts.map +1 -0
- package/dist/pack/zipper.js +121 -0
- package/dist/skills/clone.d.ts +28 -0
- package/dist/skills/clone.d.ts.map +1 -0
- package/dist/skills/clone.js +60 -0
- package/dist/skills/detect-agents.d.ts +8 -0
- package/dist/skills/detect-agents.d.ts.map +1 -0
- package/dist/skills/detect-agents.js +129 -0
- package/dist/skills/discover.d.ts +12 -0
- package/dist/skills/discover.d.ts.map +1 -0
- package/dist/skills/discover.js +45 -0
- package/dist/skills/index.d.ts +21 -0
- package/dist/skills/index.d.ts.map +1 -0
- package/dist/skills/index.js +97 -0
- package/dist/skills/installer.d.ts +21 -0
- package/dist/skills/installer.d.ts.map +1 -0
- package/dist/skills/installer.js +48 -0
- package/dist/skills/types.d.ts +39 -0
- package/dist/skills/types.d.ts.map +1 -0
- package/dist/skills/types.js +1 -0
- package/dist/skills/ui.d.ts +55 -0
- package/dist/skills/ui.d.ts.map +1 -0
- package/dist/skills/ui.js +102 -0
- package/package.json +6 -3
- package/templates/typescript-oauth/.env.example +1 -1
- package/templates/typescript-oauth/_gitignore +57 -0
- package/templates/typescript-pizzaz/.env.example +1 -1
- package/templates/typescript-pizzaz/_gitignore +57 -0
- package/templates/typescript-starter/.env.example +1 -1
- package/templates/typescript-starter/_gitignore +57 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Dependencies
|
|
2
|
+
node_modules/
|
|
3
|
+
src/widgets/node_modules/
|
|
4
|
+
|
|
5
|
+
# Build outputs
|
|
6
|
+
dist/
|
|
7
|
+
src/widgets/.next/
|
|
8
|
+
src/widgets/out/
|
|
9
|
+
|
|
10
|
+
# Environment files
|
|
11
|
+
.env
|
|
12
|
+
.env.local
|
|
13
|
+
.env.*.local
|
|
14
|
+
|
|
15
|
+
# IDE
|
|
16
|
+
.idea/
|
|
17
|
+
.vscode/
|
|
18
|
+
*.swp
|
|
19
|
+
*.swo
|
|
20
|
+
*~
|
|
21
|
+
|
|
22
|
+
# OS files
|
|
23
|
+
.DS_Store
|
|
24
|
+
Thumbs.db
|
|
25
|
+
|
|
26
|
+
# Logs
|
|
27
|
+
*.log
|
|
28
|
+
npm-debug.log*
|
|
29
|
+
yarn-debug.log*
|
|
30
|
+
yarn-error.log*
|
|
31
|
+
|
|
32
|
+
# Runtime data
|
|
33
|
+
pids/
|
|
34
|
+
*.pid
|
|
35
|
+
*.seed
|
|
36
|
+
*.pid.lock
|
|
37
|
+
|
|
38
|
+
# Coverage
|
|
39
|
+
coverage/
|
|
40
|
+
.nyc_output/
|
|
41
|
+
|
|
42
|
+
# Uploads
|
|
43
|
+
uploads/
|
|
44
|
+
|
|
45
|
+
# TypeScript cache
|
|
46
|
+
*.tsbuildinfo
|
|
47
|
+
|
|
48
|
+
# Optional npm cache
|
|
49
|
+
.npm/
|
|
50
|
+
|
|
51
|
+
# Optional eslint cache
|
|
52
|
+
.eslintcache
|
|
53
|
+
|
|
54
|
+
# OAuth tokens/secrets (never commit these!)
|
|
55
|
+
*.pem
|
|
56
|
+
*.key
|
|
57
|
+
tokens.json
|
package/dist/commands/init.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AA6IA,UAAU,WAAW;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,wBAAsB,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,WAAW,iBA2PtF"}
|
package/dist/commands/init.js
CHANGED
|
@@ -7,6 +7,81 @@ import inquirer from 'inquirer';
|
|
|
7
7
|
import { execSync } from 'child_process';
|
|
8
8
|
import { NITRO_BANNER_FULL, createSuccessBox, NitroSpinner, log, spacer, nextSteps, brand, showFooter } from '../ui/branding.js';
|
|
9
9
|
import { trackEvent, shutdownAnalytics } from '../analytics/posthog.js';
|
|
10
|
+
import { runSkillsFlow } from '../skills/index.js';
|
|
11
|
+
import { writeCanonicalGitignore } from '../pack/canonical-gitignore.js';
|
|
12
|
+
import readline from 'readline';
|
|
13
|
+
/**
|
|
14
|
+
* Prompts the user with a horizontal YES/NO choice using left/right arrow keys.
|
|
15
|
+
*/
|
|
16
|
+
async function promptYesNoHorizontal(message, defaultValue = false) {
|
|
17
|
+
return new Promise((resolve) => {
|
|
18
|
+
let value = defaultValue;
|
|
19
|
+
const stdin = process.stdin;
|
|
20
|
+
const stdout = process.stdout;
|
|
21
|
+
// Save TTY and raw mode state
|
|
22
|
+
const isRaw = stdin.isRaw;
|
|
23
|
+
if (stdin.isTTY) {
|
|
24
|
+
stdin.setRawMode(true);
|
|
25
|
+
}
|
|
26
|
+
readline.emitKeypressEvents(stdin);
|
|
27
|
+
stdin.resume();
|
|
28
|
+
// Hide cursor
|
|
29
|
+
stdout.write('\u001B[?25l');
|
|
30
|
+
const render = () => {
|
|
31
|
+
readline.clearLine(stdout, 0);
|
|
32
|
+
readline.cursorTo(stdout, 0);
|
|
33
|
+
const qMark = chalk.cyan('?');
|
|
34
|
+
const msg = chalk.bold(message);
|
|
35
|
+
const pointer = chalk.dim('›');
|
|
36
|
+
const separator = chalk.dim(' / ');
|
|
37
|
+
const noPart = !value
|
|
38
|
+
? chalk.cyan.underline('No')
|
|
39
|
+
: chalk.dim('No');
|
|
40
|
+
const yesPart = value
|
|
41
|
+
? chalk.cyan.underline('Yes')
|
|
42
|
+
: chalk.dim('Yes');
|
|
43
|
+
stdout.write(`${qMark} ${msg} ${pointer} ${noPart}${separator}${yesPart}`);
|
|
44
|
+
};
|
|
45
|
+
render();
|
|
46
|
+
const onKeypress = (str, key) => {
|
|
47
|
+
if (!key)
|
|
48
|
+
return;
|
|
49
|
+
if (key.name === 'left' || key.name === 'right') {
|
|
50
|
+
value = !value;
|
|
51
|
+
render();
|
|
52
|
+
}
|
|
53
|
+
else if (key.name === 'return' || key.name === 'enter') {
|
|
54
|
+
cleanup();
|
|
55
|
+
// Clear prompt line and print final answer
|
|
56
|
+
readline.clearLine(stdout, 0);
|
|
57
|
+
readline.cursorTo(stdout, 0);
|
|
58
|
+
const checkMark = chalk.green('✔');
|
|
59
|
+
const finalAns = value ? chalk.cyan('Yes') : chalk.cyan('No');
|
|
60
|
+
stdout.write(`${checkMark} ${chalk.white(message)} ${finalAns}\n`);
|
|
61
|
+
// Resolve after a small delay to prevent keypress bleeding into the next prompt
|
|
62
|
+
setTimeout(() => {
|
|
63
|
+
resolve(value);
|
|
64
|
+
}, 100);
|
|
65
|
+
}
|
|
66
|
+
else if (key.ctrl && key.name === 'c') {
|
|
67
|
+
cleanup();
|
|
68
|
+
process.exit(130); // SIGINT exit code
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
const cleanup = () => {
|
|
72
|
+
// Show cursor
|
|
73
|
+
stdout.write('\u001B[?25h');
|
|
74
|
+
stdin.removeListener('keypress', onKeypress);
|
|
75
|
+
// Consume any data currently sitting in the stream buffer
|
|
76
|
+
stdin.read();
|
|
77
|
+
if (stdin.isTTY) {
|
|
78
|
+
stdin.setRawMode(isRaw);
|
|
79
|
+
}
|
|
80
|
+
stdin.pause();
|
|
81
|
+
};
|
|
82
|
+
stdin.on('keypress', onKeypress);
|
|
83
|
+
});
|
|
84
|
+
}
|
|
10
85
|
// ES module equivalent of __dirname
|
|
11
86
|
const __filename = fileURLToPath(import.meta.url);
|
|
12
87
|
const __dirname = dirname(__filename);
|
|
@@ -69,14 +144,7 @@ export async function initCommand(projectName, options) {
|
|
|
69
144
|
const targetDir = path.join(process.cwd(), finalProjectName);
|
|
70
145
|
// Check if directory exists
|
|
71
146
|
if (fs.existsSync(targetDir)) {
|
|
72
|
-
const
|
|
73
|
-
{
|
|
74
|
-
type: 'confirm',
|
|
75
|
-
name: 'overwrite',
|
|
76
|
-
message: chalk.yellow(`Directory ${finalProjectName} already exists. Overwrite?`),
|
|
77
|
-
default: false,
|
|
78
|
-
},
|
|
79
|
-
]);
|
|
147
|
+
const overwrite = await promptYesNoHorizontal(chalk.yellow(`Directory ${finalProjectName} already exists. Overwrite?`), false);
|
|
80
148
|
if (!overwrite) {
|
|
81
149
|
log('Cancelled', 'warning');
|
|
82
150
|
process.exit(0);
|
|
@@ -99,7 +167,7 @@ export async function initCommand(projectName, options) {
|
|
|
99
167
|
value: 'typescript-pizzaz',
|
|
100
168
|
},
|
|
101
169
|
{
|
|
102
|
-
name: `${brand.signal('
|
|
170
|
+
name: `${brand.signal('Flight booking')} ${chalk.dim('Flight booking with OAuth 2.1 auth')}`,
|
|
103
171
|
value: 'typescript-oauth',
|
|
104
172
|
},
|
|
105
173
|
],
|
|
@@ -134,6 +202,11 @@ export async function initCommand(projectName, options) {
|
|
|
134
202
|
// Copy template files
|
|
135
203
|
if (fs.existsSync(templateDir)) {
|
|
136
204
|
fs.copySync(templateDir, targetDir);
|
|
205
|
+
// Template ships `_gitignore` (npm never packs files named `.gitignore`)
|
|
206
|
+
const placeholder = path.join(targetDir, '_gitignore');
|
|
207
|
+
if (fs.existsSync(placeholder)) {
|
|
208
|
+
fs.removeSync(placeholder);
|
|
209
|
+
}
|
|
137
210
|
}
|
|
138
211
|
else {
|
|
139
212
|
await createProjectFromScratch(targetDir, finalProjectName, {
|
|
@@ -142,6 +215,8 @@ export async function initCommand(projectName, options) {
|
|
|
142
215
|
author: finalAuthor,
|
|
143
216
|
});
|
|
144
217
|
}
|
|
218
|
+
// Always write canonical .gitignore — npm strips `.gitignore` from published templates
|
|
219
|
+
await writeCanonicalGitignore(targetDir);
|
|
145
220
|
// Update package.json
|
|
146
221
|
const packageJsonPath = path.join(targetDir, 'package.json');
|
|
147
222
|
if (fs.existsSync(packageJsonPath)) {
|
|
@@ -152,6 +227,12 @@ export async function initCommand(projectName, options) {
|
|
|
152
227
|
fs.writeJSONSync(packageJsonPath, packageJson, { spaces: 2 });
|
|
153
228
|
}
|
|
154
229
|
spinner.succeed('Project created');
|
|
230
|
+
// Agent skills prompt bypassed - installing project-level skills by default
|
|
231
|
+
// const addAgentSkills = await promptYesNoHorizontal('Add agent skills?', true);
|
|
232
|
+
// if (addAgentSkills) {
|
|
233
|
+
// await runSkillsFlow(options.force ?? false, targetDir);
|
|
234
|
+
// }
|
|
235
|
+
await runSkillsFlow(options.force ?? false, targetDir);
|
|
155
236
|
// Install dependencies
|
|
156
237
|
if (!options.skipInstall) {
|
|
157
238
|
spinner = new NitroSpinner('Installing dependencies...').start();
|
|
@@ -322,13 +403,6 @@ server.start().catch((error) => {
|
|
|
322
403
|
`;
|
|
323
404
|
fs.writeFileSync(path.join(targetDir, 'src', 'index.ts'), indexTs);
|
|
324
405
|
fs.writeFileSync(path.join(targetDir, '.env'), '# Environment variables\n');
|
|
325
|
-
const gitignore = `node_modules/
|
|
326
|
-
dist/
|
|
327
|
-
.env
|
|
328
|
-
.env.local
|
|
329
|
-
*.log
|
|
330
|
-
`;
|
|
331
|
-
fs.writeFileSync(path.join(targetDir, '.gitignore'), gitignore);
|
|
332
406
|
const readme = `# ${projectName}
|
|
333
407
|
|
|
334
408
|
${answers.description}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
interface PackCommandOptions {
|
|
2
|
+
output?: string;
|
|
3
|
+
dryRun?: boolean;
|
|
4
|
+
syncGitignore?: boolean;
|
|
5
|
+
includeEnv?: boolean;
|
|
6
|
+
cwd?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function packCommand(options: PackCommandOptions): Promise<void>;
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=pack.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pack.d.ts","sourceRoot":"","sources":["../../src/commands/pack.ts"],"names":[],"mappings":"AAiBA,UAAU,kBAAkB;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AA2CD,wBAAsB,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CA2D5E"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { createHeader, createSuccessBox, createErrorBox, NitroSpinner, spacer, brand, NITRO_BANNER_FULL, showFooter, } from '../ui/branding.js';
|
|
4
|
+
import { trackEvent, shutdownAnalytics } from '../analytics/posthog.js';
|
|
5
|
+
import { packProject } from '../pack/pack-project.js';
|
|
6
|
+
import { PackValidationError } from '../pack/validate-project.js';
|
|
7
|
+
function formatBytes(bytes) {
|
|
8
|
+
if (bytes < 1024)
|
|
9
|
+
return `${bytes} B`;
|
|
10
|
+
if (bytes < 1024 * 1024)
|
|
11
|
+
return `${(bytes / 1024).toFixed(1)} KB`;
|
|
12
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
13
|
+
}
|
|
14
|
+
function buildSummaryItems(result) {
|
|
15
|
+
const items = [
|
|
16
|
+
`${brand.skyBold(String(result.filesIncluded))} file(s) included`,
|
|
17
|
+
];
|
|
18
|
+
if (result.outputPath) {
|
|
19
|
+
items.push(`Output: ${brand.sky(result.outputPath)}`);
|
|
20
|
+
}
|
|
21
|
+
if (result.zipSizeBytes !== null) {
|
|
22
|
+
items.push(`Size: ${brand.skyBold(formatBytes(result.zipSizeBytes))}`);
|
|
23
|
+
}
|
|
24
|
+
if (result.gitignoreUpdated) {
|
|
25
|
+
items.push(`Added ${result.addedGitignoreRules.length} .gitignore rule(s)`);
|
|
26
|
+
}
|
|
27
|
+
return items;
|
|
28
|
+
}
|
|
29
|
+
function printExcludedCategories(result) {
|
|
30
|
+
console.log(chalk.bold('\nExcluded from zip:'));
|
|
31
|
+
for (const category of result.excludedCategories) {
|
|
32
|
+
console.log(` ${chalk.cyan(category.category)}: ${category.paths.join(', ')}`);
|
|
33
|
+
}
|
|
34
|
+
spacer();
|
|
35
|
+
}
|
|
36
|
+
function printDryRunTree(result) {
|
|
37
|
+
if (!result.dryRunTree)
|
|
38
|
+
return;
|
|
39
|
+
console.log(chalk.bold('File tree:'));
|
|
40
|
+
console.log(result.dryRunTree);
|
|
41
|
+
spacer();
|
|
42
|
+
}
|
|
43
|
+
export async function packCommand(options) {
|
|
44
|
+
console.log(NITRO_BANNER_FULL);
|
|
45
|
+
console.log(createHeader('Pack', 'Create optimized project archive'));
|
|
46
|
+
trackEvent('cli_command_invoked', {
|
|
47
|
+
command: 'pack',
|
|
48
|
+
options: Object.keys(options).filter((key) => options[key] !== undefined),
|
|
49
|
+
});
|
|
50
|
+
const packOptions = {
|
|
51
|
+
output: options.output,
|
|
52
|
+
dryRun: options.dryRun,
|
|
53
|
+
syncGitignore: options.syncGitignore ?? true,
|
|
54
|
+
includeEnv: options.includeEnv ?? false,
|
|
55
|
+
cwd: path.resolve(options.cwd ?? process.cwd()),
|
|
56
|
+
};
|
|
57
|
+
const spinner = new NitroSpinner(packOptions.dryRun ? 'Analyzing project files...' : 'Creating optimized zip...').start();
|
|
58
|
+
try {
|
|
59
|
+
const result = await packProject(packOptions);
|
|
60
|
+
spinner.succeed(packOptions.dryRun
|
|
61
|
+
? 'Dry run complete'
|
|
62
|
+
: `Created ${path.basename(result.outputPath ?? 'archive')}`);
|
|
63
|
+
printExcludedCategories(result);
|
|
64
|
+
if (packOptions.dryRun) {
|
|
65
|
+
printDryRunTree(result);
|
|
66
|
+
}
|
|
67
|
+
console.log(createSuccessBox(packOptions.dryRun ? 'Dry Run Complete' : 'Project Packed', buildSummaryItems(result)));
|
|
68
|
+
showFooter();
|
|
69
|
+
await shutdownAnalytics();
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
spinner.fail('Pack failed');
|
|
73
|
+
if (error instanceof PackValidationError) {
|
|
74
|
+
console.log(createErrorBox('Pack Failed', error.message));
|
|
75
|
+
await shutdownAnalytics();
|
|
76
|
+
process.exit(1);
|
|
77
|
+
}
|
|
78
|
+
console.log(createErrorBox('Pack Failed', error instanceof Error ? error.message : String(error)));
|
|
79
|
+
await shutdownAnalytics();
|
|
80
|
+
process.exit(1);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upgrade.d.ts","sourceRoot":"","sources":["../../src/commands/upgrade.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"upgrade.d.ts","sourceRoot":"","sources":["../../src/commands/upgrade.ts"],"names":[],"mappings":"AAmCA,UAAU,cAAc;IACtB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAUD;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAgD1E;AA2BD;;GAEG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAa9D;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAM1D;AAqED;;GAEG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAmM3E"}
|
package/dist/commands/upgrade.js
CHANGED
|
@@ -5,6 +5,10 @@ import fs from 'fs-extra';
|
|
|
5
5
|
import https from 'https';
|
|
6
6
|
import { createHeader, createBox, createSuccessBox, createErrorBox, NitroSpinner, log, spacer, nextSteps, NITRO_BANNER_FULL, showFooter } from '../ui/branding.js';
|
|
7
7
|
import { trackEvent, shutdownAnalytics } from '../analytics/posthog.js';
|
|
8
|
+
import { cloneSkillsRepo } from '../skills/clone.js';
|
|
9
|
+
import { discoverSkills } from '../skills/discover.js';
|
|
10
|
+
import { installSkills } from '../skills/installer.js';
|
|
11
|
+
import { AGENTS } from '../skills/detect-agents.js';
|
|
8
12
|
/**
|
|
9
13
|
* Fetch a package's latest published version from NPM using standard https module.
|
|
10
14
|
*/
|
|
@@ -236,6 +240,68 @@ export async function upgradeCommand(options) {
|
|
|
236
240
|
console.error(error);
|
|
237
241
|
}
|
|
238
242
|
}
|
|
243
|
+
// Upgrade skills
|
|
244
|
+
const rootPackageJson = fs.readJSONSync(rootPackageJsonPath);
|
|
245
|
+
const localSkillsVersion = rootPackageJson.nitrostack?.skillsVersion || '0.0.0';
|
|
246
|
+
let tempSkillsDir = null;
|
|
247
|
+
const skillsSpinner = new NitroSpinner('Checking agent skills...').start();
|
|
248
|
+
try {
|
|
249
|
+
tempSkillsDir = await cloneSkillsRepo();
|
|
250
|
+
const skillsPkgJsonPath = path.join(tempSkillsDir, 'package.json');
|
|
251
|
+
let remoteSkillsVersion = '1.0.0';
|
|
252
|
+
if (fs.existsSync(skillsPkgJsonPath)) {
|
|
253
|
+
const skillsPkgJson = fs.readJSONSync(skillsPkgJsonPath);
|
|
254
|
+
remoteSkillsVersion = skillsPkgJson.version || '1.0.0';
|
|
255
|
+
}
|
|
256
|
+
if (compareVersions(localSkillsVersion, remoteSkillsVersion) < 0) {
|
|
257
|
+
if (dryRun) {
|
|
258
|
+
allResults.push({
|
|
259
|
+
location: 'skills',
|
|
260
|
+
packageName: '@nitrostack/skills',
|
|
261
|
+
previousVersion: localSkillsVersion,
|
|
262
|
+
newVersion: remoteSkillsVersion,
|
|
263
|
+
upgraded: false,
|
|
264
|
+
});
|
|
265
|
+
skillsSpinner.info(`Skills: Updates available (${localSkillsVersion} → ${remoteSkillsVersion})`);
|
|
266
|
+
}
|
|
267
|
+
else {
|
|
268
|
+
const skills = await discoverSkills(tempSkillsDir);
|
|
269
|
+
await installSkills(AGENTS, skills, true, 'project', projectRoot);
|
|
270
|
+
// Write new version to package.json
|
|
271
|
+
const updatedPackageJson = fs.readJSONSync(rootPackageJsonPath);
|
|
272
|
+
if (!updatedPackageJson.nitrostack) {
|
|
273
|
+
updatedPackageJson.nitrostack = {};
|
|
274
|
+
}
|
|
275
|
+
updatedPackageJson.nitrostack.skillsVersion = remoteSkillsVersion;
|
|
276
|
+
fs.writeJSONSync(rootPackageJsonPath, updatedPackageJson, { spaces: 2 });
|
|
277
|
+
allResults.push({
|
|
278
|
+
location: 'skills',
|
|
279
|
+
packageName: '@nitrostack/skills',
|
|
280
|
+
previousVersion: localSkillsVersion,
|
|
281
|
+
newVersion: remoteSkillsVersion,
|
|
282
|
+
upgraded: true,
|
|
283
|
+
});
|
|
284
|
+
skillsSpinner.succeed(`Skills: Upgraded from ${localSkillsVersion} to ${remoteSkillsVersion}`);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
else {
|
|
288
|
+
skillsSpinner.info('Skills: All agent skills are up to date');
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
catch (error) {
|
|
292
|
+
skillsSpinner.fail('Failed to upgrade agent skills');
|
|
293
|
+
console.error(error);
|
|
294
|
+
}
|
|
295
|
+
finally {
|
|
296
|
+
if (tempSkillsDir) {
|
|
297
|
+
try {
|
|
298
|
+
fs.removeSync(tempSkillsDir);
|
|
299
|
+
}
|
|
300
|
+
catch {
|
|
301
|
+
// best effort
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
239
305
|
// Summary
|
|
240
306
|
spacer();
|
|
241
307
|
if (allResults.length === 0) {
|
package/dist/index.d.ts
CHANGED
|
@@ -9,4 +9,6 @@ export { generate } from './commands/generate.js';
|
|
|
9
9
|
export { upgradeCommand } from './commands/upgrade.js';
|
|
10
10
|
export { installCommand } from './commands/install.js';
|
|
11
11
|
export { cursorCommand } from './commands/cursor.js';
|
|
12
|
+
export { packCommand } from './commands/pack.js';
|
|
13
|
+
export { packProject } from './pack/pack-project.js';
|
|
12
14
|
//# sourceMappingURL=index.d.ts.map
|
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;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAepC,wBAAgB,aAAa,YAuF5B;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;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -9,6 +9,7 @@ import { generate } from './commands/generate.js';
|
|
|
9
9
|
import { upgradeCommand } from './commands/upgrade.js';
|
|
10
10
|
import { installCommand } from './commands/install.js';
|
|
11
11
|
import { cursorCommand } from './commands/cursor.js';
|
|
12
|
+
import { packCommand } from './commands/pack.js';
|
|
12
13
|
const require = createRequire(import.meta.url);
|
|
13
14
|
const packageJson = require('../package.json');
|
|
14
15
|
export function createProgram() {
|
|
@@ -25,6 +26,7 @@ export function createProgram() {
|
|
|
25
26
|
.option('--description <description>', 'Description of the project')
|
|
26
27
|
.option('--author <author>', 'Author of the project')
|
|
27
28
|
.option('--skip-install', 'Skip installing dependencies')
|
|
29
|
+
.option('--force', 'Overwrite existing skill files when adding agent skills')
|
|
28
30
|
.action(initCommand);
|
|
29
31
|
program
|
|
30
32
|
.command('dev')
|
|
@@ -76,6 +78,15 @@ export function createProgram() {
|
|
|
76
78
|
.option('-p, --port <port>', 'Port for default HTTP URL (for legacy-sse or streamable-http)')
|
|
77
79
|
.option('--force', 'Force overwrite of existing configuration')
|
|
78
80
|
.action(cursorCommand);
|
|
81
|
+
program
|
|
82
|
+
.command('pack')
|
|
83
|
+
.description('Create an optimized zip of the project (excludes build artifacts)')
|
|
84
|
+
.option('-o, --output <path>', 'Zip filename (always written to the project root)')
|
|
85
|
+
.option('--dry-run', 'Show excluded/included summary without creating zip')
|
|
86
|
+
.option('--include-env', 'Include .env files in the zip')
|
|
87
|
+
.option('--no-sync-gitignore', 'Skip merging canonical rules into local .gitignore')
|
|
88
|
+
.option('--cwd <dir>', 'Project directory', process.cwd())
|
|
89
|
+
.action(packCommand);
|
|
79
90
|
return program;
|
|
80
91
|
}
|
|
81
92
|
// Re-export commands for programmatic use
|
|
@@ -87,6 +98,8 @@ export { generate } from './commands/generate.js';
|
|
|
87
98
|
export { upgradeCommand } from './commands/upgrade.js';
|
|
88
99
|
export { installCommand } from './commands/install.js';
|
|
89
100
|
export { cursorCommand } from './commands/cursor.js';
|
|
101
|
+
export { packCommand } from './commands/pack.js';
|
|
102
|
+
export { packProject } from './pack/pack-project.js';
|
|
90
103
|
// Run the CLI when this module is the entry point
|
|
91
104
|
import { fileURLToPath } from 'url';
|
|
92
105
|
import { realpathSync } from 'fs';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve the bundled canonical .gitignore shipped with the CLI package.
|
|
3
|
+
*/
|
|
4
|
+
export declare function getCanonicalGitignorePath(): string;
|
|
5
|
+
/**
|
|
6
|
+
* Load canonical .gitignore rules from the bundled starter template copy.
|
|
7
|
+
*/
|
|
8
|
+
export declare function loadCanonicalGitignore(): Promise<string>;
|
|
9
|
+
/**
|
|
10
|
+
* Write the bundled canonical .gitignore into a project root as `.gitignore`.
|
|
11
|
+
* Used by init because npm never ships files named `.gitignore` in the package tarball.
|
|
12
|
+
*/
|
|
13
|
+
export declare function writeCanonicalGitignore(projectRoot: string): Promise<void>;
|
|
14
|
+
//# sourceMappingURL=canonical-gitignore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canonical-gitignore.d.ts","sourceRoot":"","sources":["../../src/pack/canonical-gitignore.ts"],"names":[],"mappings":"AAMA;;GAEG;AACH,wBAAgB,yBAAyB,IAAI,MAAM,CAElD;AAED;;GAEG;AACH,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,MAAM,CAAC,CAM9D;AAED;;;GAGG;AACH,wBAAsB,uBAAuB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAGhF"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { fileURLToPath } from 'url';
|
|
3
|
+
import fs from 'fs-extra';
|
|
4
|
+
const moduleDir = path.dirname(fileURLToPath(import.meta.url));
|
|
5
|
+
/**
|
|
6
|
+
* Resolve the bundled canonical .gitignore shipped with the CLI package.
|
|
7
|
+
*/
|
|
8
|
+
export function getCanonicalGitignorePath() {
|
|
9
|
+
return path.join(moduleDir, '../../assets/canonical.gitignore');
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Load canonical .gitignore rules from the bundled starter template copy.
|
|
13
|
+
*/
|
|
14
|
+
export async function loadCanonicalGitignore() {
|
|
15
|
+
const canonicalPath = getCanonicalGitignorePath();
|
|
16
|
+
if (!(await fs.pathExists(canonicalPath))) {
|
|
17
|
+
throw new Error(`Canonical .gitignore not found at ${canonicalPath}`);
|
|
18
|
+
}
|
|
19
|
+
return fs.readFile(canonicalPath, 'utf-8');
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Write the bundled canonical .gitignore into a project root as `.gitignore`.
|
|
23
|
+
* Used by init because npm never ships files named `.gitignore` in the package tarball.
|
|
24
|
+
*/
|
|
25
|
+
export async function writeCanonicalGitignore(projectRoot) {
|
|
26
|
+
const content = await loadCanonicalGitignore();
|
|
27
|
+
await fs.writeFile(path.join(projectRoot, '.gitignore'), content, 'utf-8');
|
|
28
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ExclusionCategory } from './types.js';
|
|
2
|
+
/** Env/secret patterns excluded by default; skipped when --include-env is set. */
|
|
3
|
+
export declare const ENV_EXCLUDED_PATTERNS: string[];
|
|
4
|
+
/** Hard-coded exclusions always applied in addition to merged .gitignore rules. */
|
|
5
|
+
export declare const HARD_EXCLUDED_PATTERNS: string[];
|
|
6
|
+
export declare const EXCLUSION_CATEGORIES: ExclusionCategory[];
|
|
7
|
+
export declare function getExclusionReport(includeEnv?: boolean): ExclusionCategory[];
|
|
8
|
+
//# sourceMappingURL=exclusions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exclusions.d.ts","sourceRoot":"","sources":["../../src/pack/exclusions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD,kFAAkF;AAClF,eAAO,MAAM,qBAAqB,EAAE,MAAM,EAIzC,CAAC;AAEF,mFAAmF;AACnF,eAAO,MAAM,sBAAsB,EAAE,MAAM,EA0B1C,CAAC;AAEF,eAAO,MAAM,oBAAoB,EAAE,iBAAiB,EAyCnD,CAAC;AAEF,wBAAgB,kBAAkB,CAAC,UAAU,GAAE,OAAe,GAAG,iBAAiB,EAAE,CAOnF"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/** Env/secret patterns excluded by default; skipped when --include-env is set. */
|
|
2
|
+
export const ENV_EXCLUDED_PATTERNS = [
|
|
3
|
+
'.env',
|
|
4
|
+
'.env.local',
|
|
5
|
+
'.env.*.local',
|
|
6
|
+
];
|
|
7
|
+
/** Hard-coded exclusions always applied in addition to merged .gitignore rules. */
|
|
8
|
+
export const HARD_EXCLUDED_PATTERNS = [
|
|
9
|
+
'.git/',
|
|
10
|
+
'**/node_modules/',
|
|
11
|
+
'**/dist/',
|
|
12
|
+
'**/build/',
|
|
13
|
+
'**/out/',
|
|
14
|
+
'**/.next/',
|
|
15
|
+
'*.tsbuildinfo',
|
|
16
|
+
'.npm/',
|
|
17
|
+
'.eslintcache',
|
|
18
|
+
'coverage/',
|
|
19
|
+
'.nyc_output/',
|
|
20
|
+
'tmp/',
|
|
21
|
+
'temp/',
|
|
22
|
+
'pids/',
|
|
23
|
+
'uploads/',
|
|
24
|
+
...ENV_EXCLUDED_PATTERNS,
|
|
25
|
+
'.idea/',
|
|
26
|
+
'.vscode/',
|
|
27
|
+
'.DS_Store',
|
|
28
|
+
'Thumbs.db',
|
|
29
|
+
'*.log',
|
|
30
|
+
'npm-debug.log*',
|
|
31
|
+
'yarn-debug.log*',
|
|
32
|
+
'yarn-error.log*',
|
|
33
|
+
'*.zip',
|
|
34
|
+
];
|
|
35
|
+
export const EXCLUSION_CATEGORIES = [
|
|
36
|
+
{
|
|
37
|
+
category: 'VCS',
|
|
38
|
+
paths: ['.git/'],
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
category: 'Dependencies',
|
|
42
|
+
paths: ['**/node_modules/'],
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
category: 'Build outputs',
|
|
46
|
+
paths: ['**/dist/', '**/build/', '**/out/', '**/.next/'],
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
category: 'Caches',
|
|
50
|
+
paths: ['*.tsbuildinfo', '.npm/', '.eslintcache'],
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
category: 'Test',
|
|
54
|
+
paths: ['coverage/', '.nyc_output/'],
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
category: 'Temp/runtime',
|
|
58
|
+
paths: ['tmp/', 'temp/', 'pids/', 'uploads/'],
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
category: 'Secrets',
|
|
62
|
+
paths: [...ENV_EXCLUDED_PATTERNS],
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
category: 'IDE/OS',
|
|
66
|
+
paths: ['.idea/', '.vscode/', '.DS_Store', 'Thumbs.db'],
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
category: 'Logs',
|
|
70
|
+
paths: ['*.log', 'npm-debug.log*', 'yarn-debug.log*', 'yarn-error.log*'],
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
category: 'Archives',
|
|
74
|
+
paths: ['*.zip'],
|
|
75
|
+
},
|
|
76
|
+
];
|
|
77
|
+
export function getExclusionReport(includeEnv = false) {
|
|
78
|
+
return EXCLUSION_CATEGORIES
|
|
79
|
+
.filter((entry) => !(includeEnv && entry.category === 'Secrets'))
|
|
80
|
+
.map((entry) => ({
|
|
81
|
+
category: entry.category,
|
|
82
|
+
paths: [...entry.paths],
|
|
83
|
+
}));
|
|
84
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type IgnoreMatcher } from './ignore-matcher.js';
|
|
2
|
+
import type { GitignoreMergeResult } from './types.js';
|
|
3
|
+
export interface BuildIgnoreMatcherOptions {
|
|
4
|
+
includeEnv?: boolean;
|
|
5
|
+
}
|
|
6
|
+
export type { IgnoreMatcher };
|
|
7
|
+
/**
|
|
8
|
+
* Non-destructively merge canonical rules into a local .gitignore.
|
|
9
|
+
* Existing local rules are preserved; only missing canonical rules are appended.
|
|
10
|
+
*/
|
|
11
|
+
export declare function mergeGitignoreRules(localContent: string, canonicalContent: string): GitignoreMergeResult;
|
|
12
|
+
/**
|
|
13
|
+
* Sync local .gitignore with canonical rules when enabled.
|
|
14
|
+
*/
|
|
15
|
+
export declare function syncProjectGitignore(projectRoot: string, syncGitignore: boolean): Promise<GitignoreMergeResult>;
|
|
16
|
+
/**
|
|
17
|
+
* Build a gitignore matcher from merged project rules and hard-coded exclusions.
|
|
18
|
+
*/
|
|
19
|
+
export declare function buildIgnoreMatcher(mergedGitignoreContent: string, options?: BuildIgnoreMatcherOptions): IgnoreMatcher;
|
|
20
|
+
export declare function isPathIgnored(matcher: IgnoreMatcher, projectRoot: string, absolutePath: string, isDirectory?: boolean): boolean;
|
|
21
|
+
//# sourceMappingURL=gitignore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gitignore.d.ts","sourceRoot":"","sources":["../../src/pack/gitignore.ts"],"names":[],"mappings":"AAIA,OAAO,EAAuB,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAC9E,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAIvD,MAAM,WAAW,yBAAyB;IACxC,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,YAAY,EAAE,aAAa,EAAE,CAAC;AA2B9B;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,YAAY,EAAE,MAAM,EACpB,gBAAgB,EAAE,MAAM,GACvB,oBAAoB,CAuCtB;AAQD;;GAEG;AACH,wBAAsB,oBAAoB,CACxC,WAAW,EAAE,MAAM,EACnB,aAAa,EAAE,OAAO,GACrB,OAAO,CAAC,oBAAoB,CAAC,CAoB/B;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,sBAAsB,EAAE,MAAM,EAC9B,OAAO,GAAE,yBAA8B,GACtC,aAAa,CAyBf;AAED,wBAAgB,aAAa,CAC3B,OAAO,EAAE,aAAa,EACtB,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,EACpB,WAAW,GAAE,OAAe,GAC3B,OAAO,CAMT"}
|