@infinitedusky/indusk-mcp 1.4.2 → 1.4.4

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.
@@ -267,6 +267,44 @@ export async function init(projectRoot, options = {}) {
267
267
  console.info(` ${ext.manifest.name}: ${result.slice(0, 100)}`);
268
268
  }
269
269
  }
270
+ // Print expected .mcp.json config for extensions with mcp_server
271
+ if (ext.manifest.mcp_server) {
272
+ const mcpJsonPath = join(projectRoot, ".mcp.json");
273
+ let hasMcpEntry = false;
274
+ if (existsSync(mcpJsonPath)) {
275
+ try {
276
+ const mcpConfig = JSON.parse(readFileSync(mcpJsonPath, "utf-8"));
277
+ hasMcpEntry = !!mcpConfig?.mcpServers?.[ext.manifest.name];
278
+ }
279
+ catch { }
280
+ }
281
+ if (!hasMcpEntry) {
282
+ const srv = ext.manifest.mcp_server;
283
+ const config = {};
284
+ if (srv.type)
285
+ config.type = srv.type;
286
+ if (srv.url)
287
+ config.url = srv.url;
288
+ if (srv.command)
289
+ config.command = srv.command;
290
+ if (srv.args)
291
+ config.args = srv.args;
292
+ if (srv.headers)
293
+ config.headers = srv.headers;
294
+ if (srv.env)
295
+ config.env = srv.env;
296
+ console.info(`\n ${ext.manifest.name}: add this to .mcp.json:\n`);
297
+ console.info(` "${ext.manifest.name}": ${JSON.stringify(config, null, " ")}\n`);
298
+ if (srv.setup_instructions) {
299
+ for (const instruction of srv.setup_instructions) {
300
+ console.info(` ${instruction}`);
301
+ }
302
+ }
303
+ }
304
+ else {
305
+ console.info(` ${ext.manifest.name}: .mcp.json entry exists`);
306
+ }
307
+ }
270
308
  }
271
309
  if (enabledExts.length === 0) {
272
310
  console.info(" no extensions enabled — run 'extensions enable' to add tool integrations");
@@ -1,8 +1,9 @@
1
1
  import { createHash } from "node:crypto";
2
- import { cpSync, existsSync, mkdirSync, readFileSync } from "node:fs";
2
+ import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync } from "node:fs";
3
3
  import { dirname, join } from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
5
  import { globSync } from "glob";
6
+ import { loadExtension } from "../../lib/extension-loader.js";
6
7
  const __dirname = dirname(fileURLToPath(import.meta.url));
7
8
  const packageRoot = join(__dirname, "../../..");
8
9
  function fileHash(path) {
@@ -137,4 +138,88 @@ export async function update(projectRoot) {
137
138
  else {
138
139
  console.info(" hooks not installed (run init to install)");
139
140
  }
141
+ // Sync enabled built-in extensions (manifests, skills, print mcp_server config)
142
+ console.info("\nChecking for extension updates...\n");
143
+ const builtinDir = join(packageRoot, "extensions");
144
+ const enabledDir = join(projectRoot, ".indusk/extensions");
145
+ let extUpdated = 0;
146
+ let extCurrent = 0;
147
+ if (existsSync(builtinDir) && existsSync(enabledDir)) {
148
+ const enabledFiles = readdirSync(enabledDir).filter((f) => f.endsWith(".json") && !f.startsWith("."));
149
+ for (const file of enabledFiles) {
150
+ const name = file.replace(".json", "");
151
+ const builtinManifest = join(builtinDir, name, "manifest.json");
152
+ const enabledManifest = join(enabledDir, file);
153
+ // Only sync built-in extensions (skip third-party)
154
+ if (!existsSync(builtinManifest))
155
+ continue;
156
+ const sourceH = fileHash(builtinManifest);
157
+ const targetH = fileHash(enabledManifest);
158
+ if (sourceH !== targetH) {
159
+ cpSync(builtinManifest, enabledManifest);
160
+ console.info(` updated: ${name} manifest`);
161
+ extUpdated++;
162
+ }
163
+ else {
164
+ console.info(` current: ${name}`);
165
+ extCurrent++;
166
+ }
167
+ // Sync extension skill
168
+ const builtinSkill = join(builtinDir, name, "skill.md");
169
+ const targetSkill = join(skillsTarget, name, "SKILL.md");
170
+ if (existsSync(builtinSkill) && existsSync(targetSkill)) {
171
+ const skillSourceH = fileHash(builtinSkill);
172
+ const skillTargetH = fileHash(targetSkill);
173
+ if (skillSourceH !== skillTargetH) {
174
+ cpSync(builtinSkill, targetSkill);
175
+ console.info(` updated: ${name} skill`);
176
+ }
177
+ }
178
+ else if (existsSync(builtinSkill) && !existsSync(targetSkill)) {
179
+ mkdirSync(join(skillsTarget, name), { recursive: true });
180
+ cpSync(builtinSkill, targetSkill);
181
+ console.info(` added: ${name} skill`);
182
+ }
183
+ // Print mcp_server config if extension has one
184
+ const manifest = loadExtension(enabledManifest);
185
+ if (manifest?.mcp_server) {
186
+ const mcpJsonPath = join(projectRoot, ".mcp.json");
187
+ let hasMcpEntry = false;
188
+ if (existsSync(mcpJsonPath)) {
189
+ try {
190
+ const mcpConfig = JSON.parse(readFileSync(mcpJsonPath, "utf-8"));
191
+ hasMcpEntry = !!mcpConfig?.mcpServers?.[name];
192
+ }
193
+ catch { }
194
+ }
195
+ if (!hasMcpEntry) {
196
+ const srv = manifest.mcp_server;
197
+ const config = {};
198
+ if (srv.type)
199
+ config.type = srv.type;
200
+ if (srv.url)
201
+ config.url = srv.url;
202
+ if (srv.command)
203
+ config.command = srv.command;
204
+ if (srv.args)
205
+ config.args = srv.args;
206
+ if (srv.headers)
207
+ config.headers = srv.headers;
208
+ if (srv.env)
209
+ config.env = srv.env;
210
+ console.info(`\n ${name}: add this to .mcp.json:\n`);
211
+ console.info(` "${name}": ${JSON.stringify(config, null, " ")}\n`);
212
+ if (srv.setup_instructions) {
213
+ for (const instruction of srv.setup_instructions) {
214
+ console.info(` ${instruction}`);
215
+ }
216
+ }
217
+ }
218
+ }
219
+ }
220
+ console.info(`\n${extUpdated} updated, ${extCurrent} current.`);
221
+ }
222
+ else {
223
+ console.info(" no extensions enabled");
224
+ }
140
225
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@infinitedusky/indusk-mcp",
3
- "version": "1.4.2",
3
+ "version": "1.4.4",
4
4
  "description": "InDusk development system — skills, MCP tools, and CLI for structured AI-assisted development",
5
5
  "type": "module",
6
6
  "files": [