@girardmedia/bootspring 2.0.52 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE CHANGED
@@ -1,16 +1,22 @@
1
- MIT License
1
+ Bootspring Proprietary License
2
2
 
3
- Copyright (c) 2026 Bootspring
3
+ Copyright (c) 2026 Bootspring (Girard Media LLC)
4
4
 
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
5
+ All rights reserved.
11
6
 
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
7
+ This software and associated documentation files (the "Software") are proprietary
8
+ and confidential. The Software is licensed, not sold.
9
+
10
+ PERMITTED USE:
11
+ - You may use the Software for your own development projects
12
+ - You may install and run the Software via npm for personal or commercial use
13
+ - You may use the outputs generated by the Software in your projects
14
+
15
+ RESTRICTIONS:
16
+ - You may NOT redistribute, sublicense, or resell the Software
17
+ - You may NOT modify, decompile, reverse engineer, or create derivative works
18
+ - You may NOT remove or alter any proprietary notices or labels
19
+ - You may NOT use the Software to create competing products or services
14
20
 
15
21
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
22
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
@@ -19,3 +25,5 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
25
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
26
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
27
  SOFTWARE.
28
+
29
+ For licensing inquiries: hello@bootspring.com
package/README.md CHANGED
@@ -4,7 +4,6 @@
4
4
 
5
5
  [![npm version](https://badge.fury.io/js/@girardmedia%2Fbootspring.svg)](https://www.npmjs.com/package/@girardmedia/bootspring)
6
6
  [![CI](https://github.com/bootspring/bootspring/actions/workflows/ci.yml/badge.svg)](https://github.com/bootspring/bootspring/actions/workflows/ci.yml)
7
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8
7
 
9
8
  Bootspring is an AI-powered development platform that provides intelligent context, specialized agents, and workflow automation for any MCP-compatible AI assistant.
10
9
 
package/bin/bootspring.js CHANGED
@@ -7,6 +7,7 @@
7
7
 
8
8
  const path = require('path');
9
9
  const selfUpdate = require('../core/self-update');
10
+ const { ensureProjectMcpConfig } = require('../core/mcp-config');
10
11
 
11
12
  const VERSION = require('../package.json').version;
12
13
 
@@ -111,6 +112,11 @@ async function main() {
111
112
  return;
112
113
  }
113
114
 
115
+ const mcpConfigResult = ensureProjectMcpConfig(process.cwd(), { createIfMissing: false });
116
+ if (mcpConfigResult.status === 'updated') {
117
+ console.error('[bootspring] Updated .mcp.json to use the managed latest-package launcher.');
118
+ }
119
+
114
120
  try {
115
121
  await runCommand(command, args.slice(1));
116
122
  } catch (error) {
package/cli/init.js CHANGED
@@ -15,7 +15,7 @@ const { execSync } = require('child_process');
15
15
  const config = require('../core/config');
16
16
  const utils = require('../core/utils');
17
17
  const contextLoader = require('../core/context-loader');
18
- const { getManagedMcpServerConfig } = require('../core/mcp-config');
18
+ const { getManagedMcpServerConfig, ensureProjectMcpConfig } = require('../core/mcp-config');
19
19
  const { runQuestionnaire } = require('../generators/questionnaire');
20
20
  const claudeTemplate = require('../generators/templates/claude.template');
21
21
  const seedTemplate = require('../generators/templates/seed.template');
@@ -543,7 +543,6 @@ ${utils.COLORS.dim}Development scaffolding with intelligence${utils.COLORS.reset
543
543
  }
544
544
 
545
545
  // 4. MCP configuration (local or global)
546
- const mcpPath = path.join(projectRoot, '.mcp.json');
547
546
  const globalMcpPath = getGlobalMcpPath();
548
547
  const isGlobal = isGloballyInstalled();
549
548
  const hasGlobalMcp = isGlobalMcpConfigured();
@@ -592,18 +591,17 @@ ${utils.COLORS.dim}Development scaffolding with intelligence${utils.COLORS.reset
592
591
  } catch (error) {
593
592
  globalSpinner.fail(`Global MCP config failed: ${error.message}`);
594
593
  }
595
- } else if (!utils.fileExists(mcpPath)) {
596
- // Local .mcp.json
594
+ } else {
597
595
  const mcpSpinner = utils.createSpinner('Creating .mcp.json').start();
598
- const mcpConfig = {
599
- mcpServers: {
600
- bootspring: getManagedMcpServerConfig()
601
- }
602
- };
603
- if (utils.writeFile(mcpPath, JSON.stringify(mcpConfig, null, 2))) {
596
+ const result = ensureProjectMcpConfig(projectRoot, { createIfMissing: true });
597
+ if (result.status === 'created') {
604
598
  mcpSpinner.succeed('Created .mcp.json (MCP server config)');
599
+ } else if (result.status === 'updated' || result.status === 'added') {
600
+ mcpSpinner.succeed('Updated .mcp.json (MCP server config)');
601
+ } else if (result.status === 'unchanged') {
602
+ mcpSpinner.succeed('Verified .mcp.json (MCP server config)');
605
603
  } else {
606
- mcpSpinner.fail('Failed to create .mcp.json');
604
+ mcpSpinner.fail(`Failed to configure .mcp.json${result.error ? `: ${result.error.message}` : ''}`);
607
605
  }
608
606
  }
609
607
 
package/cli/mcp.js CHANGED
@@ -3,12 +3,11 @@
3
3
  * Manage the hosted MCP proxy configuration.
4
4
  */
5
5
 
6
- const path = require('path');
7
6
  const config = require('../core/config');
8
7
  const utils = require('../core/utils');
9
8
  const api = require('../core/api-client');
10
9
  const auth = require('../core/auth');
11
- const { getManagedMcpServerConfig } = require('../core/mcp-config');
10
+ const { ensureProjectMcpConfig } = require('../core/mcp-config');
12
11
  const { redactErrorMessage } = require('../core/redaction');
13
12
 
14
13
  const C = utils.COLORS;
@@ -20,18 +19,17 @@ async function startServer() {
20
19
 
21
20
  function generateConfig() {
22
21
  const cfg = config.load();
23
- const mcpPath = path.join(cfg._projectRoot, '.mcp.json');
24
- const mcpConfig = {
25
- mcpServers: {
26
- bootspring: getManagedMcpServerConfig()
27
- }
28
- };
29
-
30
22
  const spinner = utils.createSpinner('Generating .mcp.json').start();
31
- if (utils.writeFile(mcpPath, JSON.stringify(mcpConfig, null, 2))) {
32
- spinner.succeed(`Created ${mcpPath}`);
23
+ const result = ensureProjectMcpConfig(cfg._projectRoot, { createIfMissing: true });
24
+
25
+ if (result.status === 'created') {
26
+ spinner.succeed(`Created ${result.path}`);
27
+ } else if (result.status === 'updated' || result.status === 'added') {
28
+ spinner.succeed(`Updated ${result.path}`);
29
+ } else if (result.status === 'unchanged') {
30
+ spinner.succeed(`Already configured ${result.path}`);
33
31
  } else {
34
- spinner.fail('Failed to create .mcp.json');
32
+ spinner.fail(`Failed to configure .mcp.json${result.error ? `: ${result.error.message}` : ''}`);
35
33
  }
36
34
  }
37
35
 
@@ -1,4 +1,8 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
1
4
  const PACKAGE_NAME = require('../package.json').name || '@girardmedia/bootspring';
5
+ const PROJECT_MCP_FILENAME = '.mcp.json';
2
6
 
3
7
  function getManagedMcpServerConfig() {
4
8
  return {
@@ -8,7 +12,104 @@ function getManagedMcpServerConfig() {
8
12
  };
9
13
  }
10
14
 
15
+ function isManagedMcpServerConfig(serverConfig) {
16
+ const expected = getManagedMcpServerConfig();
17
+ return (
18
+ serverConfig?.command === expected.command &&
19
+ Array.isArray(serverConfig?.args) &&
20
+ serverConfig.args.join('\u0000') === expected.args.join('\u0000')
21
+ );
22
+ }
23
+
24
+ function normalizeManagedMcpServerConfig(existingServerConfig) {
25
+ const managedConfig = getManagedMcpServerConfig();
26
+ const env = existingServerConfig?.env && typeof existingServerConfig.env === 'object' && !Array.isArray(existingServerConfig.env)
27
+ ? existingServerConfig.env
28
+ : {};
29
+
30
+ return {
31
+ ...managedConfig,
32
+ env
33
+ };
34
+ }
35
+
36
+ function ensureProjectMcpConfig(projectRoot = process.cwd(), options = {}) {
37
+ const createIfMissing = options.createIfMissing === true;
38
+ const mcpPath = path.join(projectRoot, PROJECT_MCP_FILENAME);
39
+
40
+ if (!fs.existsSync(mcpPath)) {
41
+ if (!createIfMissing) {
42
+ return { status: 'missing', changed: false, path: mcpPath };
43
+ }
44
+
45
+ const nextConfig = {
46
+ mcpServers: {
47
+ bootspring: getManagedMcpServerConfig()
48
+ }
49
+ };
50
+
51
+ try {
52
+ fs.writeFileSync(mcpPath, JSON.stringify(nextConfig, null, 2));
53
+ return { status: 'created', changed: true, path: mcpPath, config: nextConfig };
54
+ } catch (error) {
55
+ return { status: 'error', changed: false, path: mcpPath, error };
56
+ }
57
+ }
58
+
59
+ let currentConfig;
60
+ try {
61
+ currentConfig = JSON.parse(fs.readFileSync(mcpPath, 'utf8'));
62
+ } catch (error) {
63
+ return { status: 'invalid', changed: false, path: mcpPath, error };
64
+ }
65
+
66
+ if (!currentConfig || typeof currentConfig !== 'object' || Array.isArray(currentConfig)) {
67
+ return {
68
+ status: 'invalid',
69
+ changed: false,
70
+ path: mcpPath,
71
+ error: new Error('Project MCP config must be a JSON object')
72
+ };
73
+ }
74
+
75
+ const currentServers = currentConfig.mcpServers && typeof currentConfig.mcpServers === 'object' && !Array.isArray(currentConfig.mcpServers)
76
+ ? currentConfig.mcpServers
77
+ : {};
78
+ const currentBootspring = currentServers.bootspring;
79
+
80
+ if (currentBootspring && isManagedMcpServerConfig(currentBootspring)) {
81
+ return { status: 'unchanged', changed: false, path: mcpPath, config: currentConfig };
82
+ }
83
+
84
+ if (!currentBootspring && !createIfMissing) {
85
+ return { status: 'absent', changed: false, path: mcpPath, config: currentConfig };
86
+ }
87
+
88
+ const nextConfig = {
89
+ ...currentConfig,
90
+ mcpServers: {
91
+ ...currentServers,
92
+ bootspring: normalizeManagedMcpServerConfig(currentBootspring)
93
+ }
94
+ };
95
+
96
+ try {
97
+ fs.writeFileSync(mcpPath, JSON.stringify(nextConfig, null, 2));
98
+ return {
99
+ status: currentBootspring ? 'updated' : 'added',
100
+ changed: true,
101
+ path: mcpPath,
102
+ config: nextConfig
103
+ };
104
+ } catch (error) {
105
+ return { status: 'error', changed: false, path: mcpPath, error };
106
+ }
107
+ }
108
+
11
109
  module.exports = {
12
110
  PACKAGE_NAME,
13
- getManagedMcpServerConfig
111
+ PROJECT_MCP_FILENAME,
112
+ getManagedMcpServerConfig,
113
+ isManagedMcpServerConfig,
114
+ ensureProjectMcpConfig
14
115
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@girardmedia/bootspring",
3
- "version": "2.0.52",
3
+ "version": "2.1.0",
4
4
  "description": "Thin client for Bootspring cloud MCP, hosted agents, and paywalled workflow intelligence",
5
5
  "keywords": [
6
6
  "ai",
@@ -14,7 +14,7 @@
14
14
  "devtools"
15
15
  ],
16
16
  "author": "Bootspring",
17
- "license": "MIT",
17
+ "license": "SEE LICENSE IN LICENSE",
18
18
  "repository": {
19
19
  "type": "git",
20
20
  "url": "https://github.com/bootspring/bootspring.git"