@nitrostack/cli 1.0.14 → 1.0.16

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 (52) hide show
  1. package/assets/canonical.gitignore +57 -0
  2. package/dist/commands/init.d.ts.map +1 -1
  3. package/dist/commands/init.js +8 -7
  4. package/dist/commands/pack.d.ts +10 -0
  5. package/dist/commands/pack.d.ts.map +1 -0
  6. package/dist/commands/pack.js +82 -0
  7. package/dist/index.d.ts +2 -0
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +12 -0
  10. package/dist/pack/canonical-gitignore.d.ts +14 -0
  11. package/dist/pack/canonical-gitignore.d.ts.map +1 -0
  12. package/dist/pack/canonical-gitignore.js +28 -0
  13. package/dist/pack/exclusions.d.ts +8 -0
  14. package/dist/pack/exclusions.d.ts.map +1 -0
  15. package/dist/pack/exclusions.js +84 -0
  16. package/dist/pack/gitignore.d.ts +21 -0
  17. package/dist/pack/gitignore.d.ts.map +1 -0
  18. package/dist/pack/gitignore.js +123 -0
  19. package/dist/pack/ignore-matcher.d.ts +19 -0
  20. package/dist/pack/ignore-matcher.d.ts.map +1 -0
  21. package/dist/pack/ignore-matcher.js +149 -0
  22. package/dist/pack/index.d.ts +11 -0
  23. package/dist/pack/index.d.ts.map +1 -0
  24. package/dist/pack/index.js +8 -0
  25. package/dist/pack/pack-project.d.ts +6 -0
  26. package/dist/pack/pack-project.d.ts.map +1 -0
  27. package/dist/pack/pack-project.js +59 -0
  28. package/dist/pack/standalone.d.ts +3 -0
  29. package/dist/pack/standalone.d.ts.map +1 -0
  30. package/dist/pack/standalone.js +95 -0
  31. package/dist/pack/tree.d.ts +5 -0
  32. package/dist/pack/tree.d.ts.map +1 -0
  33. package/dist/pack/tree.js +70 -0
  34. package/dist/pack/types.d.ts +35 -0
  35. package/dist/pack/types.d.ts.map +1 -0
  36. package/dist/pack/types.js +1 -0
  37. package/dist/pack/validate-project.d.ts +9 -0
  38. package/dist/pack/validate-project.d.ts.map +1 -0
  39. package/dist/pack/validate-project.js +44 -0
  40. package/dist/pack/zipper.d.ts +20 -0
  41. package/dist/pack/zipper.d.ts.map +1 -0
  42. package/dist/pack/zipper.js +121 -0
  43. package/package.json +6 -3
  44. package/templates/typescript-oauth/.env.example +14 -1
  45. package/templates/typescript-oauth/README.md +20 -0
  46. package/templates/typescript-oauth/_gitignore +57 -0
  47. package/templates/typescript-pizzaz/.env.example +13 -1
  48. package/templates/typescript-pizzaz/README.md +19 -0
  49. package/templates/typescript-pizzaz/_gitignore +57 -0
  50. package/templates/typescript-starter/.env.example +13 -1
  51. package/templates/typescript-starter/README.md +19 -0
  52. package/templates/typescript-starter/_gitignore +57 -0
@@ -0,0 +1,121 @@
1
+ import path from 'path';
2
+ import fs from 'fs';
3
+ import { createWriteStream } from 'fs';
4
+ import archiver from 'archiver';
5
+ import { isPathIgnored } from './gitignore.js';
6
+ /** True when realPath is the root or a descendant of rootReal. */
7
+ function isInsideRoot(realPath, rootReal) {
8
+ const relative = path.relative(rootReal, realPath);
9
+ return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative));
10
+ }
11
+ /**
12
+ * Collect relative file paths that should be included, and pruned excluded roots.
13
+ * Excluded directories are recorded once and not descended into.
14
+ * Symlinks are resolved via stat/realpath so:
15
+ * - symlink-to-directory is walked (not archived as a file)
16
+ * - cycles and targets outside the project root are skipped
17
+ */
18
+ export async function collectFilesToPack(projectRoot, matcher) {
19
+ const includedPaths = [];
20
+ const excludedPaths = [];
21
+ const visitedDirs = new Set();
22
+ let projectRootReal;
23
+ try {
24
+ projectRootReal = await fs.promises.realpath(projectRoot);
25
+ }
26
+ catch {
27
+ projectRootReal = path.resolve(projectRoot);
28
+ }
29
+ async function walk(currentDir) {
30
+ let currentReal;
31
+ try {
32
+ currentReal = await fs.promises.realpath(currentDir);
33
+ }
34
+ catch {
35
+ return;
36
+ }
37
+ if (visitedDirs.has(currentReal)) {
38
+ return;
39
+ }
40
+ if (!isInsideRoot(currentReal, projectRootReal)) {
41
+ return;
42
+ }
43
+ visitedDirs.add(currentReal);
44
+ let entries;
45
+ try {
46
+ entries = await fs.promises.readdir(currentDir, { withFileTypes: true });
47
+ }
48
+ catch {
49
+ return;
50
+ }
51
+ entries.sort((a, b) => a.name.localeCompare(b.name));
52
+ for (const entry of entries) {
53
+ const absolutePath = path.join(currentDir, entry.name);
54
+ const relativePath = path.relative(projectRoot, absolutePath).split(path.sep).join('/');
55
+ let isDirectory = entry.isDirectory();
56
+ let isFile = entry.isFile();
57
+ if (entry.isSymbolicLink()) {
58
+ try {
59
+ const realTarget = await fs.promises.realpath(absolutePath);
60
+ if (!isInsideRoot(realTarget, projectRootReal)) {
61
+ // Symlink escapes the project — skip
62
+ continue;
63
+ }
64
+ const stats = await fs.promises.stat(absolutePath);
65
+ isDirectory = stats.isDirectory();
66
+ isFile = stats.isFile();
67
+ }
68
+ catch {
69
+ // Broken symlink — skip
70
+ continue;
71
+ }
72
+ }
73
+ if (isPathIgnored(matcher, projectRoot, absolutePath, isDirectory)) {
74
+ const displayPath = isDirectory ? `${relativePath}/` : relativePath;
75
+ excludedPaths.push(displayPath);
76
+ continue;
77
+ }
78
+ if (isDirectory) {
79
+ await walk(absolutePath);
80
+ continue;
81
+ }
82
+ if (isFile) {
83
+ includedPaths.push(relativePath);
84
+ }
85
+ }
86
+ }
87
+ await walk(projectRoot);
88
+ includedPaths.sort();
89
+ excludedPaths.sort();
90
+ return {
91
+ filesIncluded: includedPaths.length,
92
+ includedPaths,
93
+ excludedPaths,
94
+ };
95
+ }
96
+ /**
97
+ * Create an optimized zip archive from the project directory.
98
+ */
99
+ export async function createOptimizedZip(projectRoot, outputPath, matcher) {
100
+ const collection = await collectFilesToPack(projectRoot, matcher);
101
+ const outputDir = path.dirname(outputPath);
102
+ await fs.promises.mkdir(outputDir, { recursive: true });
103
+ await new Promise((resolve, reject) => {
104
+ const output = createWriteStream(outputPath);
105
+ const archive = archiver('zip', { zlib: { level: 9 } });
106
+ output.on('close', () => resolve());
107
+ output.on('error', reject);
108
+ archive.on('error', reject);
109
+ archive.pipe(output);
110
+ for (const relativePath of collection.includedPaths) {
111
+ const absolutePath = path.join(projectRoot, relativePath);
112
+ archive.file(absolutePath, { name: relativePath });
113
+ }
114
+ void archive.finalize();
115
+ });
116
+ return collection;
117
+ }
118
+ export async function getZipSizeBytes(outputPath) {
119
+ const stats = await fs.promises.stat(outputPath);
120
+ return stats.size;
121
+ }
package/package.json CHANGED
@@ -1,13 +1,14 @@
1
1
  {
2
2
  "name": "@nitrostack/cli",
3
- "version": "1.0.14",
3
+ "version": "1.0.16",
4
4
  "description": "CLI for NitroStack - Create and manage MCP server projects",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
8
8
  "bin": {
9
9
  "nitrostack-cli": "dist/index.js",
10
- "@nitrostack/cli": "dist/index.js"
10
+ "@nitrostack/cli": "dist/index.js",
11
+ "nitrostack-pack": "dist/pack/standalone.js"
11
12
  },
12
13
  "exports": {
13
14
  ".": {
@@ -23,7 +24,7 @@
23
24
  "assets"
24
25
  ],
25
26
  "scripts": {
26
- "build": "tsc && chmod +x dist/index.js",
27
+ "build": "tsc && chmod +x dist/index.js dist/pack/standalone.js",
27
28
  "dev": "tsc --watch",
28
29
  "test": "NODE_OPTIONS=--experimental-vm-modules jest",
29
30
  "test:coverage": "NODE_OPTIONS=--experimental-vm-modules jest --coverage",
@@ -40,6 +41,7 @@
40
41
  "author": "Nitrostack Inc <hello@nitrostack.ai>",
41
42
  "license": "Apache-2.0",
42
43
  "dependencies": {
44
+ "archiver": "^7.0.1",
43
45
  "chalk": "^5.3.0",
44
46
  "chokidar": "^3.6.0",
45
47
  "commander": "^12.1.0",
@@ -51,6 +53,7 @@
51
53
  "posthog-node": "^5.21.2"
52
54
  },
53
55
  "devDependencies": {
56
+ "@types/archiver": "^6.0.3",
54
57
  "@types/fs-extra": "^11.0.4",
55
58
  "@types/inquirer": "^9.0.9",
56
59
  "@types/jest": "^29.5.14",
@@ -1,6 +1,6 @@
1
1
  # NitroStack Configuration
2
2
  NITRO_LOG_LEVEL=info
3
- NITROSTACK_APP_MODE=openai
3
+ NITROSTACK_APP_MODE=universal
4
4
 
5
5
  # Server Transport Configuration (Optional)
6
6
  # =============================================================================
@@ -12,6 +12,19 @@ NITROSTACK_APP_MODE=openai
12
12
  # HOST=localhost
13
13
  # ENABLE_CORS=true
14
14
 
15
+ # MCP Protocol Version (Optional)
16
+ # =============================================================================
17
+ # NITRO_MCP_PROTOCOL_VERSION selects which MCP wire revision NitroStack speaks.
18
+ # Unset (default) defaults to 'auto' (serves 2026-07-28 stateless with legacy fallback).
19
+ # - auto : serve both eras from one process (default).
20
+ # - 2026-07-28 : the new stateless spec (server/discover, per-request _meta,
21
+ # Mcp-Method/Mcp-Name headers, cache hints, MRTR, extensions).
22
+ # - 2025-06-18 : the legacy 2025 sessionful spec.
23
+ # On 2026, Dynamic Client Registration (below) is deprecated in favor of CIMD.
24
+ # Your @Tool/@Resource/@Prompt/@Widget code is identical either way.
25
+ # =============================================================================
26
+ # NITRO_MCP_PROTOCOL_VERSION=auto
27
+
15
28
  # Streamable HTTP Session Limits (Optional)
16
29
  # =============================================================================
17
30
  # Bounds memory against unauthenticated initialize floods. Defaults: 1000 sessions,
@@ -41,6 +41,26 @@ Use NitroStudio to test auth flows, inspect tool requests, and validate behavior
41
41
  - Download: <https://nitrostack.ai/studio>
42
42
  - Studio: <https://nitrostack.ai/studio>
43
43
 
44
+ ## MCP protocol version (optional)
45
+
46
+ This server runs in **`auto` mode by default**, dynamically serving both the new
47
+ **2026-07-28** stateless spec and legacy 2025 JSON-RPC clients from a single endpoint.
48
+ You can customize the wire revision via environment variable — no code changes are needed:
49
+
50
+ ```bash
51
+ # default (when unset): serve both modern and legacy statelessly
52
+ NITRO_MCP_PROTOCOL_VERSION=auto
53
+
54
+ # new stateless spec only (strict mode)
55
+ NITRO_MCP_PROTOCOL_VERSION=2026-07-28
56
+
57
+ # legacy 2025 sessionful wire
58
+ NITRO_MCP_PROTOCOL_VERSION=2025-06-18
59
+ ```
60
+
61
+ On 2026, Dynamic Client Registration is deprecated in favor of Client ID Metadata
62
+ Documents (CIMD). See `.env.example` for details.
63
+
44
64
  ## Links
45
65
 
46
66
  - Docs: <https://docs.nitrostack.ai>
@@ -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
@@ -1,6 +1,6 @@
1
1
  # NitroStack Configuration
2
2
  NITRO_LOG_LEVEL=info
3
- NITROSTACK_APP_MODE=openai
3
+ NITROSTACK_APP_MODE=universal
4
4
 
5
5
  # Server Transport Configuration (Optional)
6
6
  # =============================================================================
@@ -12,6 +12,18 @@ NITROSTACK_APP_MODE=openai
12
12
  # HOST=localhost
13
13
  # ENABLE_CORS=true
14
14
 
15
+ # MCP Protocol Version (Optional)
16
+ # =============================================================================
17
+ # NITRO_MCP_PROTOCOL_VERSION selects which MCP wire revision NitroStack speaks.
18
+ # Unset (default) defaults to 'auto' (serves 2026-07-28 stateless with legacy fallback).
19
+ # - auto : serve both eras from one process (default).
20
+ # - 2026-07-28 : the new stateless spec (server/discover, per-request _meta,
21
+ # Mcp-Method/Mcp-Name headers, cache hints, MRTR, extensions).
22
+ # - 2025-06-18 : the legacy 2025 sessionful spec.
23
+ # Your @Tool/@Resource/@Prompt/@Widget code is identical either way.
24
+ # =============================================================================
25
+ # NITRO_MCP_PROTOCOL_VERSION=auto
26
+
15
27
  # Mapbox Configuration (Optional)
16
28
  # =============================================================================
17
29
  # The map widget uses Mapbox GL for interactive maps.
@@ -39,6 +39,25 @@ NitroStudio is the fastest way to test and debug interactive widget output.
39
39
  - Download: <https://nitrostack.ai/studio>
40
40
  - Studio: <https://nitrostack.ai/studio>
41
41
 
42
+ ## MCP protocol version (optional)
43
+
44
+ This server runs in **`auto` mode by default**, dynamically serving both the new
45
+ **2026-07-28** stateless spec and legacy 2025 JSON-RPC clients from a single endpoint.
46
+ You can customize the wire revision via environment variable — no code changes are needed:
47
+
48
+ ```bash
49
+ # default (when unset): serve both modern and legacy statelessly
50
+ NITRO_MCP_PROTOCOL_VERSION=auto
51
+
52
+ # new stateless spec only (strict mode)
53
+ NITRO_MCP_PROTOCOL_VERSION=2026-07-28
54
+
55
+ # legacy 2025 sessionful wire
56
+ NITRO_MCP_PROTOCOL_VERSION=2025-06-18
57
+ ```
58
+
59
+ See `.env.example` for details.
60
+
42
61
  ## Links
43
62
 
44
63
  - Docs: <https://docs.nitrostack.ai>
@@ -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
@@ -1,6 +1,6 @@
1
1
  # NitroStack Configuration
2
2
  NITRO_LOG_LEVEL=info
3
- NITROSTACK_APP_MODE=openai
3
+ NITROSTACK_APP_MODE=universal
4
4
 
5
5
  # Server Transport Configuration (Optional)
6
6
  # =============================================================================
@@ -11,3 +11,15 @@ NITROSTACK_APP_MODE=openai
11
11
  # PORT=3000
12
12
  # HOST=localhost
13
13
  # ENABLE_CORS=true
14
+
15
+ # MCP Protocol Version (Optional)
16
+ # =============================================================================
17
+ # NITRO_MCP_PROTOCOL_VERSION selects which MCP wire revision NitroStack speaks.
18
+ # Unset (default) defaults to 'auto' (serves 2026-07-28 stateless with legacy fallback).
19
+ # - auto : serve both eras from one process (default).
20
+ # - 2026-07-28 : the new stateless spec (server/discover, per-request _meta,
21
+ # Mcp-Method/Mcp-Name headers, cache hints, MRTR, extensions).
22
+ # - 2025-06-18 : the legacy 2025 sessionful spec.
23
+ # Your @Tool/@Resource/@Prompt/@Widget code is identical either way.
24
+ # =============================================================================
25
+ # NITRO_MCP_PROTOCOL_VERSION=auto
@@ -34,6 +34,25 @@ development.
34
34
  - Download: <https://nitrostack.ai/studio>
35
35
  - Studio: <https://nitrostack.ai/studio>
36
36
 
37
+ ## MCP protocol version (optional)
38
+
39
+ This server runs in **`auto` mode by default**, dynamically serving both the new
40
+ **2026-07-28** stateless spec and legacy 2025 JSON-RPC clients from a single endpoint.
41
+ You can customize the wire revision via environment variable — no code changes are needed:
42
+
43
+ ```bash
44
+ # default (when unset): serve both modern and legacy statelessly
45
+ NITRO_MCP_PROTOCOL_VERSION=auto
46
+
47
+ # new stateless spec only (strict mode)
48
+ NITRO_MCP_PROTOCOL_VERSION=2026-07-28
49
+
50
+ # legacy 2025 sessionful wire
51
+ NITRO_MCP_PROTOCOL_VERSION=2025-06-18
52
+ ```
53
+
54
+ See `.env.example` for details.
55
+
37
56
  ## Links
38
57
 
39
58
  - Docs: <https://docs.nitrostack.ai>
@@ -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