@1tool/js-boost 1.1.0 → 1.2.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/README.md +18 -9
- package/package.json +1 -1
- package/src/cli.js +2 -2
- package/src/configure/mcp.js +25 -27
- package/src/index.js +2 -2
- package/src/init.js +8 -3
- package/src/utils/mcp.js +3 -3
- package/src/utils/reader.js +25 -0
package/README.md
CHANGED
|
@@ -13,9 +13,11 @@ Instead of manually maintaining separate instruction files for each AI agent, yo
|
|
|
13
13
|
├── guidelines/
|
|
14
14
|
│ ├── general.md ← coding conventions
|
|
15
15
|
│ └── testing.md ← testing standards
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
├── skills/
|
|
17
|
+
│ └── my-skill/
|
|
18
|
+
│ └── SKILL.md ← on-demand skill (loaded when relevant)
|
|
19
|
+
└── mcp/
|
|
20
|
+
└── mcp.json ← MCP server definitions
|
|
19
21
|
```
|
|
20
22
|
|
|
21
23
|
Run `npx @1tool/js-boost generate` and get the right file for each configured agent:
|
|
@@ -141,14 +143,11 @@ During `init` (and `agents`), installed agents are pre-selected automatically ba
|
|
|
141
143
|
|
|
142
144
|
## Configuration
|
|
143
145
|
|
|
144
|
-
|
|
146
|
+
MCP server definitions live in `.ai/mcp/mcp.json` (managed by `js-boost mcp`):
|
|
145
147
|
|
|
146
148
|
```json
|
|
147
149
|
{
|
|
148
|
-
"
|
|
149
|
-
"projectDescription": "",
|
|
150
|
-
"agents": ["claude_code", "cursor", "codex"],
|
|
151
|
-
"mcpServers": {
|
|
150
|
+
"servers": {
|
|
152
151
|
"my-api": {
|
|
153
152
|
"type": "remote",
|
|
154
153
|
"url": "https://my-mcp.com/mcp",
|
|
@@ -161,7 +160,17 @@ During `init` (and `agents`), installed agents are pre-selected automatically ba
|
|
|
161
160
|
"env": { "API_KEY": "secret" }
|
|
162
161
|
}
|
|
163
162
|
},
|
|
164
|
-
"
|
|
163
|
+
"disabled": []
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Agent selection and project metadata live in `js-boost.config.json` (managed by `init` / `agents`):
|
|
168
|
+
|
|
169
|
+
```json
|
|
170
|
+
{
|
|
171
|
+
"projectName": "my-app",
|
|
172
|
+
"projectDescription": "",
|
|
173
|
+
"agents": ["claude_code", "cursor", "codex"]
|
|
165
174
|
}
|
|
166
175
|
```
|
|
167
176
|
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -88,7 +88,7 @@ program
|
|
|
88
88
|
.option('--dir <path>', 'Project directory', process.cwd())
|
|
89
89
|
.action(async (options) => {
|
|
90
90
|
const projectDir = path.resolve(options.dir);
|
|
91
|
-
const { readGuidelines, readSkills, readConfig } = await import('./utils/reader.js');
|
|
91
|
+
const { readGuidelines, readSkills, readConfig, readMcpConfig } = await import('./utils/reader.js');
|
|
92
92
|
const { buildMcpServers } = await import('./utils/mcp.js');
|
|
93
93
|
const { AGENTS, AGENTS_MD_CONSUMERS, MCP_JSON_CONSUMERS } = await import('./agents.js');
|
|
94
94
|
const aiDir = path.join(projectDir, '.ai');
|
|
@@ -96,7 +96,7 @@ program
|
|
|
96
96
|
|
|
97
97
|
const guidelines = await readGuidelines(aiDir);
|
|
98
98
|
const skills = await readSkills(aiDir);
|
|
99
|
-
const mcpServers = buildMcpServers(
|
|
99
|
+
const mcpServers = buildMcpServers(readMcpConfig(aiDir));
|
|
100
100
|
|
|
101
101
|
const allAgentKeys = Object.keys(AGENTS);
|
|
102
102
|
const activeAgents = new Set(config.agents ?? allAgentKeys);
|
package/src/configure/mcp.js
CHANGED
|
@@ -2,11 +2,11 @@ import path from 'path';
|
|
|
2
2
|
import chalk from 'chalk';
|
|
3
3
|
import { text, select, multiselect, isCancel } from '@clack/prompts';
|
|
4
4
|
import { DEFAULT_MCP_SERVERS } from '../utils/mcp.js';
|
|
5
|
-
import {
|
|
5
|
+
import { readMcpConfig, writeMcpConfig } from '../utils/reader.js';
|
|
6
6
|
|
|
7
|
-
function displayServers(
|
|
8
|
-
const userServers =
|
|
9
|
-
const disabled = new Set(
|
|
7
|
+
function displayServers(mcpConfig) {
|
|
8
|
+
const userServers = mcpConfig.servers || {};
|
|
9
|
+
const disabled = new Set(mcpConfig.disabled || []);
|
|
10
10
|
const builtinKeys = Object.keys(DEFAULT_MCP_SERVERS);
|
|
11
11
|
|
|
12
12
|
if (builtinKeys.length > 0) {
|
|
@@ -34,13 +34,13 @@ function displayServers(config) {
|
|
|
34
34
|
console.log('');
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
async function addServer(
|
|
37
|
+
async function addServer(mcpConfig) {
|
|
38
38
|
const name = await text({
|
|
39
39
|
message: 'Server key',
|
|
40
40
|
placeholder: 'my-api',
|
|
41
41
|
validate: (v) => {
|
|
42
42
|
if (!v.trim()) return 'Key is required';
|
|
43
|
-
if ((
|
|
43
|
+
if ((mcpConfig.servers || {})[v.trim()]) return `"${v.trim()}" already exists`;
|
|
44
44
|
if (DEFAULT_MCP_SERVERS[v.trim()]) return `"${v.trim()}" is a built-in — use "Toggle built-ins" to enable/disable it`;
|
|
45
45
|
if (!/^[a-z0-9_-]+$/.test(v.trim())) return 'Use only lowercase letters, numbers, hyphens, underscores';
|
|
46
46
|
},
|
|
@@ -72,7 +72,7 @@ async function addServer(config) {
|
|
|
72
72
|
});
|
|
73
73
|
if (isCancel(description)) return;
|
|
74
74
|
|
|
75
|
-
|
|
75
|
+
mcpConfig.servers[key] = {
|
|
76
76
|
type: 'remote',
|
|
77
77
|
url: url.trim(),
|
|
78
78
|
...(description.trim() ? { description: description.trim() } : {}),
|
|
@@ -111,7 +111,7 @@ async function addServer(config) {
|
|
|
111
111
|
}
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
-
|
|
114
|
+
mcpConfig.servers[key] = {
|
|
115
115
|
type: 'stdio',
|
|
116
116
|
command: command.trim(),
|
|
117
117
|
...(args.length ? { args } : {}),
|
|
@@ -122,8 +122,8 @@ async function addServer(config) {
|
|
|
122
122
|
console.log(` ${chalk.green('✓')} Added ${chalk.cyan(key)}`);
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
-
async function removeServer(
|
|
126
|
-
const keys = Object.keys(
|
|
125
|
+
async function removeServer(mcpConfig) {
|
|
126
|
+
const keys = Object.keys(mcpConfig.servers);
|
|
127
127
|
if (keys.length === 0) {
|
|
128
128
|
console.log(chalk.dim(' No custom servers to remove.'));
|
|
129
129
|
return;
|
|
@@ -132,7 +132,7 @@ async function removeServer(config) {
|
|
|
132
132
|
const toRemove = await multiselect({
|
|
133
133
|
message: 'Select servers to remove',
|
|
134
134
|
options: keys.map((k) => {
|
|
135
|
-
const srv =
|
|
135
|
+
const srv = mcpConfig.servers[k];
|
|
136
136
|
const addr = srv.type === 'remote'
|
|
137
137
|
? srv.url
|
|
138
138
|
: `${srv.command}${srv.args?.length ? ' ' + srv.args.join(' ') : ''}`;
|
|
@@ -143,7 +143,7 @@ async function removeServer(config) {
|
|
|
143
143
|
if (isCancel(toRemove)) return;
|
|
144
144
|
|
|
145
145
|
for (const k of toRemove) {
|
|
146
|
-
delete
|
|
146
|
+
delete mcpConfig.servers[k];
|
|
147
147
|
}
|
|
148
148
|
|
|
149
149
|
if (toRemove.length) {
|
|
@@ -151,14 +151,14 @@ async function removeServer(config) {
|
|
|
151
151
|
}
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
-
async function toggleDefaults(
|
|
154
|
+
async function toggleDefaults(mcpConfig) {
|
|
155
155
|
const keys = Object.keys(DEFAULT_MCP_SERVERS);
|
|
156
156
|
if (keys.length === 0) {
|
|
157
157
|
console.log(chalk.dim(' No built-in servers configured.'));
|
|
158
158
|
return;
|
|
159
159
|
}
|
|
160
160
|
|
|
161
|
-
const disabled = new Set(
|
|
161
|
+
const disabled = new Set(mcpConfig.disabled || []);
|
|
162
162
|
|
|
163
163
|
const enabled = await multiselect({
|
|
164
164
|
message: 'Which built-in servers should be enabled?',
|
|
@@ -173,14 +173,12 @@ async function toggleDefaults(config) {
|
|
|
173
173
|
if (isCancel(enabled)) return;
|
|
174
174
|
|
|
175
175
|
const enabledSet = new Set(enabled);
|
|
176
|
-
|
|
176
|
+
mcpConfig.disabled = keys.filter((k) => !enabledSet.has(k));
|
|
177
177
|
}
|
|
178
178
|
|
|
179
179
|
export async function configureMcp(projectDir) {
|
|
180
|
-
const
|
|
181
|
-
const
|
|
182
|
-
config.mcpServers = config.mcpServers || {};
|
|
183
|
-
config.disableMcpServers = config.disableMcpServers || [];
|
|
180
|
+
const aiDir = path.join(projectDir, '.ai');
|
|
181
|
+
const mcpConfig = readMcpConfig(aiDir);
|
|
184
182
|
|
|
185
183
|
console.log('');
|
|
186
184
|
console.log(chalk.bold.blue('⚡ js-boost') + chalk.dim(' — MCP server configuration'));
|
|
@@ -189,9 +187,9 @@ export async function configureMcp(projectDir) {
|
|
|
189
187
|
let running = true;
|
|
190
188
|
|
|
191
189
|
while (running) {
|
|
192
|
-
displayServers(
|
|
190
|
+
displayServers(mcpConfig);
|
|
193
191
|
|
|
194
|
-
const hasCustom = Object.keys(
|
|
192
|
+
const hasCustom = Object.keys(mcpConfig.servers).length > 0;
|
|
195
193
|
const hasBuiltins = Object.keys(DEFAULT_MCP_SERVERS).length > 0;
|
|
196
194
|
|
|
197
195
|
const options = [
|
|
@@ -209,15 +207,15 @@ export async function configureMcp(projectDir) {
|
|
|
209
207
|
}
|
|
210
208
|
|
|
211
209
|
console.log('');
|
|
212
|
-
if (action === 'add') await addServer(
|
|
213
|
-
if (action === 'remove') await removeServer(
|
|
214
|
-
if (action === 'toggle') await toggleDefaults(
|
|
210
|
+
if (action === 'add') await addServer(mcpConfig);
|
|
211
|
+
if (action === 'remove') await removeServer(mcpConfig);
|
|
212
|
+
if (action === 'toggle') await toggleDefaults(mcpConfig);
|
|
215
213
|
console.log('');
|
|
216
214
|
}
|
|
217
215
|
|
|
218
|
-
|
|
216
|
+
writeMcpConfig(aiDir, mcpConfig);
|
|
219
217
|
console.log('');
|
|
220
|
-
console.log(chalk.green(' ✓ Saved to
|
|
221
|
-
console.log(chalk.dim(' Run
|
|
218
|
+
console.log(chalk.green(' ✓ Saved to .ai/mcp/mcp.json'));
|
|
219
|
+
console.log(chalk.dim(' Run `@1tool/js-boost generate` to apply changes to agent files.'));
|
|
222
220
|
console.log('');
|
|
223
221
|
}
|
package/src/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
2
|
import chalk from 'chalk';
|
|
3
|
-
import { readGuidelines, readSkills, readConfig, writeFile } from './utils/reader.js';
|
|
3
|
+
import { readGuidelines, readSkills, readConfig, readMcpConfig, writeFile } from './utils/reader.js';
|
|
4
4
|
import { buildMcpServers, generateMcpJson, generateJunieMcpJson } from './utils/mcp.js';
|
|
5
5
|
import { AGENTS_MD_CONSUMERS, MCP_JSON_CONSUMERS } from './agents.js';
|
|
6
6
|
import { generateAgentsMd } from './generators/agents.js';
|
|
@@ -33,7 +33,7 @@ export async function generate(projectDir, options = {}) {
|
|
|
33
33
|
// 1. Read source files
|
|
34
34
|
const guidelines = await readGuidelines(aiDir);
|
|
35
35
|
const skills = await readSkills(aiDir);
|
|
36
|
-
const mcpServers = buildMcpServers(
|
|
36
|
+
const mcpServers = buildMcpServers(readMcpConfig(aiDir));
|
|
37
37
|
|
|
38
38
|
if (guidelines.length === 0 && skills.length === 0) {
|
|
39
39
|
log(chalk.yellow(' ⚠ No guidelines or skills found in .ai/'));
|
package/src/init.js
CHANGED
|
@@ -2,7 +2,7 @@ import path from 'path';
|
|
|
2
2
|
import fs from 'fs';
|
|
3
3
|
import chalk from 'chalk';
|
|
4
4
|
import { multiselect, isCancel, cancel } from '@clack/prompts';
|
|
5
|
-
import { writeFile } from './utils/reader.js';
|
|
5
|
+
import { writeFile, writeMcpConfig } from './utils/reader.js';
|
|
6
6
|
import { AGENTS } from './agents.js';
|
|
7
7
|
import { detectInstalledAgents } from './utils/detect.js';
|
|
8
8
|
|
|
@@ -102,6 +102,13 @@ export async function init(projectDir, options = {}) {
|
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
+
// Create .ai/mcp/mcp.json if it doesn't exist yet
|
|
106
|
+
const mcpJsonPath = path.join(aiDir, 'mcp', 'mcp.json');
|
|
107
|
+
if (!fs.existsSync(mcpJsonPath) || force) {
|
|
108
|
+
writeMcpConfig(aiDir, { servers: {}, disabled: [] });
|
|
109
|
+
console.log(` ${chalk.green('✓')} ${chalk.cyan('.ai/mcp/mcp.json')}`);
|
|
110
|
+
}
|
|
111
|
+
|
|
105
112
|
// Create js-boost.config.json with defaults (or read existing)
|
|
106
113
|
const configPath = path.join(projectDir, 'js-boost.config.json');
|
|
107
114
|
let existingConfig = {};
|
|
@@ -116,8 +123,6 @@ export async function init(projectDir, options = {}) {
|
|
|
116
123
|
projectName: existingConfig.projectName || path.basename(projectDir),
|
|
117
124
|
projectDescription: existingConfig.projectDescription || '',
|
|
118
125
|
agents: selectedAgents,
|
|
119
|
-
mcpServers: existingConfig.mcpServers || {},
|
|
120
|
-
disableMcpServers: existingConfig.disableMcpServers || [],
|
|
121
126
|
};
|
|
122
127
|
|
|
123
128
|
writeFile(configPath, JSON.stringify(config, null, 2));
|
package/src/utils/mcp.js
CHANGED
|
@@ -8,9 +8,9 @@ export const DEFAULT_MCP_SERVERS = {
|
|
|
8
8
|
* Build the MCP servers object, merging defaults with user-defined servers
|
|
9
9
|
* from js-boost.config.json
|
|
10
10
|
*/
|
|
11
|
-
export function buildMcpServers(
|
|
12
|
-
const userServers =
|
|
13
|
-
const disabledDefaults =
|
|
11
|
+
export function buildMcpServers(mcpConfig = {}) {
|
|
12
|
+
const userServers = mcpConfig.servers || {};
|
|
13
|
+
const disabledDefaults = mcpConfig.disabled || [];
|
|
14
14
|
|
|
15
15
|
const servers = {};
|
|
16
16
|
|
package/src/utils/reader.js
CHANGED
|
@@ -74,6 +74,31 @@ export function readConfig(projectDir) {
|
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
+
/**
|
|
78
|
+
* Read .ai/mcp/mcp.json — MCP server definitions
|
|
79
|
+
* Returns { servers: {}, disabled: [] }
|
|
80
|
+
*/
|
|
81
|
+
export function readMcpConfig(aiDir) {
|
|
82
|
+
const mcpPath = path.join(aiDir, 'mcp', 'mcp.json');
|
|
83
|
+
if (!fs.existsSync(mcpPath)) return { servers: {}, disabled: [] };
|
|
84
|
+
try {
|
|
85
|
+
const parsed = JSON.parse(fs.readFileSync(mcpPath, 'utf8'));
|
|
86
|
+
return {
|
|
87
|
+
servers: parsed.servers || {},
|
|
88
|
+
disabled: parsed.disabled || [],
|
|
89
|
+
};
|
|
90
|
+
} catch {
|
|
91
|
+
return { servers: {}, disabled: [] };
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Write .ai/mcp/mcp.json
|
|
97
|
+
*/
|
|
98
|
+
export function writeMcpConfig(aiDir, mcpConfig) {
|
|
99
|
+
writeFile(path.join(aiDir, 'mcp', 'mcp.json'), JSON.stringify(mcpConfig, null, 2));
|
|
100
|
+
}
|
|
101
|
+
|
|
77
102
|
/**
|
|
78
103
|
* Ensure a directory exists
|
|
79
104
|
*/
|