@seastudio/sdk 3.0.1 → 3.0.3

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 (57) hide show
  1. package/bin/seastudio.js +0 -0
  2. package/dist/chunk-D7ONFXVY.js +98 -0
  3. package/dist/chunk-EIOFZMTC.cjs +109 -0
  4. package/dist/{chunk-AGBZJGTY.cjs → chunk-SUF5BPSK.cjs} +3 -1
  5. package/dist/{chunk-DDVRUPMZ.js → chunk-XU5GEWWL.js} +3 -1
  6. package/dist/develop-tool/cli/index.cjs +79 -7
  7. package/dist/develop-tool/cli/index.js +79 -7
  8. package/dist/index.cjs +42 -167
  9. package/dist/index.d.cts +2 -6
  10. package/dist/index.d.ts +2 -6
  11. package/dist/index.js +2 -7
  12. package/dist/mcp/core/index.d.cts +2 -2
  13. package/dist/mcp/core/index.d.ts +2 -2
  14. package/dist/mcp/index.cjs +27 -152
  15. package/dist/mcp/index.d.cts +12 -77
  16. package/dist/mcp/index.d.ts +12 -77
  17. package/dist/mcp/index.js +2 -7
  18. package/dist/mcp/seastudio/index.cjs +18 -18
  19. package/dist/mcp/seastudio/index.d.cts +34 -2
  20. package/dist/mcp/seastudio/index.d.ts +34 -2
  21. package/dist/mcp/seastudio/index.js +1 -1
  22. package/dist/{types-Clgf5gBf.d.cts → types-B32sUvc0.d.cts} +10 -2
  23. package/dist/{types-Clgf5gBf.d.ts → types-B32sUvc0.d.ts} +10 -2
  24. package/package.json +2 -22
  25. package/src/develop-tool/templates/plugin/frontend/package.json.tmpl +1 -1
  26. package/src/develop-tool/templates/plugin/frontend/src/main.tsx +3 -0
  27. package/src/develop-tool/templates/plugin/frontend/src/mcp-entry.ts.tmpl +12 -0
  28. package/dist/chunk-4ITOR5QE.js +0 -901
  29. package/dist/chunk-CSXDT47Y.cjs +0 -105
  30. package/dist/chunk-CVF4QHS6.cjs +0 -436
  31. package/dist/chunk-DSOSHJH2.js +0 -643
  32. package/dist/chunk-FLATZQA2.js +0 -174
  33. package/dist/chunk-HJJTBVKQ.cjs +0 -909
  34. package/dist/chunk-ISI2OLPI.cjs +0 -179
  35. package/dist/chunk-MYURVLGP.cjs +0 -165
  36. package/dist/chunk-QD4KISXM.js +0 -160
  37. package/dist/chunk-SNGU4SHO.cjs +0 -654
  38. package/dist/chunk-V7MNKGS7.js +0 -94
  39. package/dist/chunk-Z7LV7DCO.js +0 -429
  40. package/dist/mcp/plugin-editor/index.cjs +0 -47
  41. package/dist/mcp/plugin-editor/index.d.cts +0 -98
  42. package/dist/mcp/plugin-editor/index.d.ts +0 -98
  43. package/dist/mcp/plugin-editor/index.js +0 -2
  44. package/dist/mcp/plugin-excel/index.cjs +0 -31
  45. package/dist/mcp/plugin-excel/index.d.cts +0 -86
  46. package/dist/mcp/plugin-excel/index.d.ts +0 -86
  47. package/dist/mcp/plugin-excel/index.js +0 -2
  48. package/dist/mcp/plugin-preview/index.cjs +0 -23
  49. package/dist/mcp/plugin-preview/index.d.cts +0 -109
  50. package/dist/mcp/plugin-preview/index.d.ts +0 -109
  51. package/dist/mcp/plugin-preview/index.js +0 -2
  52. package/dist/mcp/plugin-seaflow/index.cjs +0 -35
  53. package/dist/mcp/plugin-seaflow/index.d.cts +0 -318
  54. package/dist/mcp/plugin-seaflow/index.d.ts +0 -318
  55. package/dist/mcp/plugin-seaflow/index.js +0 -2
  56. package/dist/tools-LMW67LIY.js +0 -2
  57. package/dist/tools-TU7PBMDO.cjs +0 -23
package/bin/seastudio.js CHANGED
File without changes
@@ -0,0 +1,98 @@
1
+ import { allTools } from './chunk-XU5GEWWL.js';
2
+ import { normalizeMCPTool, normalizeMCPToolObjectSchema, getDefaultClient } from './chunk-ANWOL7SM.js';
3
+
4
+ // src/mcp/index.ts
5
+ async function loadPlugin(pluginName) {
6
+ if (pluginName === "seastudio") {
7
+ return import('./mcp/seastudio/index.js');
8
+ }
9
+ throw new Error(`Unknown plugin: ${pluginName}. \u63D2\u4EF6 MCP \u4E0D\u518D\u901A\u8FC7 SDK \u9759\u6001\u5BFC\u5165\u3002`);
10
+ }
11
+ var MCP_PACKAGES = [
12
+ { id: "seastudio", name: "SeaStudio", description: "\u6587\u4EF6/Shell/Git \u57FA\u7840\u80FD\u529B", tools: allTools }
13
+ ];
14
+ function mcpToolToOpenAI(tool) {
15
+ const normalizedTool = normalizeMCPTool(tool);
16
+ const outputSchema = normalizedTool.outputSchema ? normalizeMCPToolObjectSchema(normalizedTool.outputSchema) : void 0;
17
+ return {
18
+ type: "function",
19
+ ...normalizedTool.annotations ? { annotations: { ...normalizedTool.annotations } } : {},
20
+ ...outputSchema ? { outputSchema } : {},
21
+ function: {
22
+ name: normalizedTool.name,
23
+ description: normalizedTool.description,
24
+ parameters: normalizeMCPToolObjectSchema(normalizedTool.inputSchema),
25
+ ...outputSchema ? { outputSchema } : {}
26
+ }
27
+ };
28
+ }
29
+ function listAllTools() {
30
+ return [...allTools];
31
+ }
32
+ function toPackageName(source) {
33
+ if (source === "seastudio") {
34
+ return "SeaStudio";
35
+ }
36
+ return source;
37
+ }
38
+ function toPackageDescription(source) {
39
+ if (source === "seastudio") {
40
+ return "SeaStudio \u539F\u751F MCP \u80FD\u529B";
41
+ }
42
+ return `\u6765\u81EA\u63D2\u4EF6 ${source} \u7684 MCP \u80FD\u529B`;
43
+ }
44
+ function normalizeAvailableTool(raw) {
45
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
46
+ return null;
47
+ }
48
+ const tool = raw;
49
+ if (typeof tool.name !== "string" || typeof tool.description !== "string" || typeof tool.inputSchema !== "object") {
50
+ return null;
51
+ }
52
+ const normalized = normalizeMCPTool(tool);
53
+ const source = typeof tool.source === "string" && tool.source.trim() ? tool.source.trim() : "seastudio";
54
+ return {
55
+ ...normalized,
56
+ source
57
+ };
58
+ }
59
+ var MCP_TOOL_PACKAGE_INDEX = new Map(
60
+ allTools.map((tool) => [tool.name, "seastudio"])
61
+ );
62
+ function getMCPToolPackageIndex() {
63
+ return new Map(MCP_TOOL_PACKAGE_INDEX);
64
+ }
65
+ async function listAvailableTools() {
66
+ const result = await getDefaultClient().request("tools/list");
67
+ const rawTools = Array.isArray(result?.tools) ? result.tools : [];
68
+ return rawTools.map(normalizeAvailableTool).filter((tool) => Boolean(tool));
69
+ }
70
+ async function getMCPPackageIdForTool(toolName) {
71
+ const tool = (await listAvailableTools()).find((item) => item.name === toolName);
72
+ return tool?.source ?? null;
73
+ }
74
+ async function listAvailableToolsForLLM() {
75
+ return (await listAvailableTools()).map(mcpToolToOpenAI);
76
+ }
77
+ async function getMCPPackages() {
78
+ const grouped = /* @__PURE__ */ new Map();
79
+ for (const tool of await listAvailableTools()) {
80
+ const existing = grouped.get(tool.source);
81
+ if (existing) {
82
+ existing.toolCount += 1;
83
+ continue;
84
+ }
85
+ grouped.set(tool.source, {
86
+ id: tool.source,
87
+ name: toPackageName(tool.source),
88
+ description: toPackageDescription(tool.source),
89
+ toolCount: 1
90
+ });
91
+ }
92
+ return [...grouped.values()];
93
+ }
94
+ async function getToolsForLLM(disabledPackages) {
95
+ return (await listAvailableTools()).filter((tool) => !disabledPackages.has(tool.source)).map(mcpToolToOpenAI);
96
+ }
97
+
98
+ export { MCP_PACKAGES, getMCPPackageIdForTool, getMCPPackages, getMCPToolPackageIndex, getToolsForLLM, listAllTools, listAvailableTools, listAvailableToolsForLLM, loadPlugin, mcpToolToOpenAI };
@@ -0,0 +1,109 @@
1
+ 'use strict';
2
+
3
+ var chunkSUF5BPSK_cjs = require('./chunk-SUF5BPSK.cjs');
4
+ var chunkTFOJLA2F_cjs = require('./chunk-TFOJLA2F.cjs');
5
+
6
+ // src/mcp/index.ts
7
+ async function loadPlugin(pluginName) {
8
+ if (pluginName === "seastudio") {
9
+ return import('./mcp/seastudio/index.cjs');
10
+ }
11
+ throw new Error(`Unknown plugin: ${pluginName}. \u63D2\u4EF6 MCP \u4E0D\u518D\u901A\u8FC7 SDK \u9759\u6001\u5BFC\u5165\u3002`);
12
+ }
13
+ var MCP_PACKAGES = [
14
+ { id: "seastudio", name: "SeaStudio", description: "\u6587\u4EF6/Shell/Git \u57FA\u7840\u80FD\u529B", tools: chunkSUF5BPSK_cjs.allTools }
15
+ ];
16
+ function mcpToolToOpenAI(tool) {
17
+ const normalizedTool = chunkTFOJLA2F_cjs.normalizeMCPTool(tool);
18
+ const outputSchema = normalizedTool.outputSchema ? chunkTFOJLA2F_cjs.normalizeMCPToolObjectSchema(normalizedTool.outputSchema) : void 0;
19
+ return {
20
+ type: "function",
21
+ ...normalizedTool.annotations ? { annotations: { ...normalizedTool.annotations } } : {},
22
+ ...outputSchema ? { outputSchema } : {},
23
+ function: {
24
+ name: normalizedTool.name,
25
+ description: normalizedTool.description,
26
+ parameters: chunkTFOJLA2F_cjs.normalizeMCPToolObjectSchema(normalizedTool.inputSchema),
27
+ ...outputSchema ? { outputSchema } : {}
28
+ }
29
+ };
30
+ }
31
+ function listAllTools() {
32
+ return [...chunkSUF5BPSK_cjs.allTools];
33
+ }
34
+ function toPackageName(source) {
35
+ if (source === "seastudio") {
36
+ return "SeaStudio";
37
+ }
38
+ return source;
39
+ }
40
+ function toPackageDescription(source) {
41
+ if (source === "seastudio") {
42
+ return "SeaStudio \u539F\u751F MCP \u80FD\u529B";
43
+ }
44
+ return `\u6765\u81EA\u63D2\u4EF6 ${source} \u7684 MCP \u80FD\u529B`;
45
+ }
46
+ function normalizeAvailableTool(raw) {
47
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
48
+ return null;
49
+ }
50
+ const tool = raw;
51
+ if (typeof tool.name !== "string" || typeof tool.description !== "string" || typeof tool.inputSchema !== "object") {
52
+ return null;
53
+ }
54
+ const normalized = chunkTFOJLA2F_cjs.normalizeMCPTool(tool);
55
+ const source = typeof tool.source === "string" && tool.source.trim() ? tool.source.trim() : "seastudio";
56
+ return {
57
+ ...normalized,
58
+ source
59
+ };
60
+ }
61
+ var MCP_TOOL_PACKAGE_INDEX = new Map(
62
+ chunkSUF5BPSK_cjs.allTools.map((tool) => [tool.name, "seastudio"])
63
+ );
64
+ function getMCPToolPackageIndex() {
65
+ return new Map(MCP_TOOL_PACKAGE_INDEX);
66
+ }
67
+ async function listAvailableTools() {
68
+ const result = await chunkTFOJLA2F_cjs.getDefaultClient().request("tools/list");
69
+ const rawTools = Array.isArray(result?.tools) ? result.tools : [];
70
+ return rawTools.map(normalizeAvailableTool).filter((tool) => Boolean(tool));
71
+ }
72
+ async function getMCPPackageIdForTool(toolName) {
73
+ const tool = (await listAvailableTools()).find((item) => item.name === toolName);
74
+ return tool?.source ?? null;
75
+ }
76
+ async function listAvailableToolsForLLM() {
77
+ return (await listAvailableTools()).map(mcpToolToOpenAI);
78
+ }
79
+ async function getMCPPackages() {
80
+ const grouped = /* @__PURE__ */ new Map();
81
+ for (const tool of await listAvailableTools()) {
82
+ const existing = grouped.get(tool.source);
83
+ if (existing) {
84
+ existing.toolCount += 1;
85
+ continue;
86
+ }
87
+ grouped.set(tool.source, {
88
+ id: tool.source,
89
+ name: toPackageName(tool.source),
90
+ description: toPackageDescription(tool.source),
91
+ toolCount: 1
92
+ });
93
+ }
94
+ return [...grouped.values()];
95
+ }
96
+ async function getToolsForLLM(disabledPackages) {
97
+ return (await listAvailableTools()).filter((tool) => !disabledPackages.has(tool.source)).map(mcpToolToOpenAI);
98
+ }
99
+
100
+ exports.MCP_PACKAGES = MCP_PACKAGES;
101
+ exports.getMCPPackageIdForTool = getMCPPackageIdForTool;
102
+ exports.getMCPPackages = getMCPPackages;
103
+ exports.getMCPToolPackageIndex = getMCPToolPackageIndex;
104
+ exports.getToolsForLLM = getToolsForLLM;
105
+ exports.listAllTools = listAllTools;
106
+ exports.listAvailableTools = listAvailableTools;
107
+ exports.listAvailableToolsForLLM = listAvailableToolsForLLM;
108
+ exports.loadPlugin = loadPlugin;
109
+ exports.mcpToolToOpenAI = mcpToolToOpenAI;
@@ -1289,7 +1289,9 @@ var SeastudioNotifications = {
1289
1289
  /** 文件发送请求 */
1290
1290
  FILE_SEND_REQUESTED: "seastudio:file-send_requested",
1291
1291
  /** 文本发送请求 */
1292
- TEXT_SEND_REQUESTED: "seastudio:text-send_requested"
1292
+ TEXT_SEND_REQUESTED: "seastudio:text-send_requested",
1293
+ /** 代码提案审核反馈 */
1294
+ PROPOSAL_FEEDBACK: "seastudio:proposal-feedback"
1293
1295
  };
1294
1296
 
1295
1297
  exports.SeastudioNotifications = SeastudioNotifications;
@@ -1287,7 +1287,9 @@ var SeastudioNotifications = {
1287
1287
  /** 文件发送请求 */
1288
1288
  FILE_SEND_REQUESTED: "seastudio:file-send_requested",
1289
1289
  /** 文本发送请求 */
1290
- TEXT_SEND_REQUESTED: "seastudio:text-send_requested"
1290
+ TEXT_SEND_REQUESTED: "seastudio:text-send_requested",
1291
+ /** 代码提案审核反馈 */
1292
+ PROPOSAL_FEEDBACK: "seastudio:proposal-feedback"
1291
1293
  };
1292
1294
 
1293
1295
  export { SeastudioNotifications, SeastudioRequests, agentManagementTools, agentTabTools, allTools, annotateTool, batchFileTools, clipboardTools, codeQualityTools, fileTools, gitTools, pluginManagementTools, pluginTabTools, seaCloudTools, seastudio, shellTools, tools };
@@ -9,8 +9,8 @@ var fs = require('fs');
9
9
  var url = require('url');
10
10
  var chalk = require('chalk');
11
11
  var ora2 = require('ora');
12
- var os = require('os');
13
12
  var child_process = require('child_process');
13
+ var os = require('os');
14
14
  var https = require('https');
15
15
  var promises$1 = require('stream/promises');
16
16
  var archiver = require('archiver');
@@ -438,6 +438,73 @@ app.listen(port, '127.0.0.1', () => {
438
438
  process.exit(1);
439
439
  }
440
440
  });
441
+ function normalizeTools(tools) {
442
+ return tools.map((tool) => JSON.parse(JSON.stringify({
443
+ name: tool.name,
444
+ description: tool.description,
445
+ inputSchema: tool.inputSchema,
446
+ ...tool.outputSchema ? { outputSchema: tool.outputSchema } : {},
447
+ ...tool.annotations ? { annotations: tool.annotations } : {}
448
+ })));
449
+ }
450
+ function loadManifestFromEntry(entryPath) {
451
+ const readerScript = `
452
+ import { pathToFileURL } from 'node:url';
453
+ const entryPath = process.argv[1];
454
+ const mod = await import(pathToFileURL(entryPath).href);
455
+ const manifest = mod.pluginMcpManifest ?? (Array.isArray(mod.mcpTools)
456
+ ? { schemaVersion: 1, tools: mod.mcpTools }
457
+ : null);
458
+ if (!manifest) {
459
+ throw new Error('frontend/src/mcp-entry.ts \u5FC5\u987B\u5BFC\u51FA pluginMcpManifest \u6216 mcpTools');
460
+ }
461
+ process.stdout.write(JSON.stringify(manifest));
462
+ `;
463
+ const result = child_process.spawnSync(process.execPath, [
464
+ "--experimental-strip-types",
465
+ "--experimental-specifier-resolution=node",
466
+ "--input-type=module",
467
+ "-e",
468
+ readerScript,
469
+ entryPath
470
+ ], {
471
+ encoding: "utf-8"
472
+ });
473
+ if (result.status !== 0) {
474
+ throw new Error((result.stderr || result.stdout || "\u8BFB\u53D6 frontend/src/mcp-entry.ts \u5931\u8D25").trim());
475
+ }
476
+ const parsed = JSON.parse(result.stdout || "{}");
477
+ return {
478
+ schemaVersion: 1,
479
+ tools: normalizeTools(parsed.tools ?? [])
480
+ };
481
+ }
482
+ async function generatePluginMcpManifest(projectDir) {
483
+ const frontendDir = fs.existsSync(path.join(projectDir, "src")) ? projectDir : path.join(projectDir, "frontend");
484
+ const entryPath = path.join(frontendDir, "src", "mcp-entry.ts");
485
+ const outputPath = path.join(frontendDir, "dist", "mcp-manifest.json");
486
+ if (!fs.existsSync(entryPath)) {
487
+ throw new Error(`\u672A\u627E\u5230\u6807\u51C6 MCP \u5165\u53E3\u6587\u4EF6: ${entryPath}`);
488
+ }
489
+ const manifest = loadManifestFromEntry(entryPath);
490
+ await promises.mkdir(path.dirname(outputPath), { recursive: true });
491
+ await promises.writeFile(outputPath, `${JSON.stringify(manifest, null, 2)}
492
+ `, "utf-8");
493
+ return {
494
+ outputPath,
495
+ toolCount: manifest.tools.length
496
+ };
497
+ }
498
+ var generateMcpManifestCommand = new commander.Command("generate-mcp-manifest").description("\u4ECE frontend/src/mcp-entry.ts \u751F\u6210 dist/mcp-manifest.json").option("-d, --dir <directory>", "\u63D2\u4EF6\u9879\u76EE\u76EE\u5F55", ".").action(async (options) => {
499
+ try {
500
+ const projectDir = path.resolve(process.cwd(), options.dir || ".");
501
+ const result = await generatePluginMcpManifest(projectDir);
502
+ console.log(`Generated ${result.outputPath} (${result.toolCount} tools)`);
503
+ } catch (error) {
504
+ console.error(error instanceof Error ? error.message : String(error));
505
+ process.exit(1);
506
+ }
507
+ });
441
508
  var PYTHON_STANDALONE_RELEASE_API = "https://api.github.com/repos/astral-sh/python-build-standalone/releases/latest";
442
509
  var TARGET_PYTHON_MINOR = Number(process.env.SEASTUDIO_AGENT_PYTHON_MINOR) || 12;
443
510
  var MAX_PYTHON_MINOR = 13;
@@ -605,11 +672,11 @@ function pickPythonRuntimeAsset(assets, target) {
605
672
  return matches[0];
606
673
  }
607
674
  async function fetchText(url, headers) {
608
- return new Promise((resolve3, reject) => {
675
+ return new Promise((resolve4, reject) => {
609
676
  https__default.default.get(url, { headers }, (res) => {
610
677
  if (res.statusCode && res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
611
678
  res.resume();
612
- fetchText(res.headers.location, headers).then(resolve3).catch(reject);
679
+ fetchText(res.headers.location, headers).then(resolve4).catch(reject);
613
680
  return;
614
681
  }
615
682
  if (res.statusCode && res.statusCode >= 400) {
@@ -619,13 +686,13 @@ async function fetchText(url, headers) {
619
686
  }
620
687
  const chunks = [];
621
688
  res.on("data", (chunk) => chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)));
622
- res.on("end", () => resolve3(Buffer.concat(chunks).toString("utf8")));
689
+ res.on("end", () => resolve4(Buffer.concat(chunks).toString("utf8")));
623
690
  res.on("error", reject);
624
691
  }).on("error", reject);
625
692
  });
626
693
  }
627
694
  async function sleep(ms) {
628
- await new Promise((resolve3) => setTimeout(resolve3, ms));
695
+ await new Promise((resolve4) => setTimeout(resolve4, ms));
629
696
  }
630
697
  async function withRetries(label, task) {
631
698
  let lastError;
@@ -960,6 +1027,10 @@ var packCommand = new commander.Command("pack").description("\u6253\u5305\u63D2\
960
1027
  `);
961
1028
  process.exit(1);
962
1029
  }
1030
+ if (config.type === "plugin") {
1031
+ const generated = await generatePluginMcpManifest(projectDir);
1032
+ logPackStep(`\u751F\u6210 MCP manifest\uFF1A${generated.outputPath} (${generated.toolCount} tools)`);
1033
+ }
963
1034
  spinnerDist.succeed("frontend/dist/index.html \u5DF2\u627E\u5230");
964
1035
  } else {
965
1036
  const spinnerDist = ora2__default.default("\u8FDC\u7A0B\u63D2\u4EF6\uFF0C\u8DF3\u8FC7 frontend build \u68C0\u67E5").start();
@@ -1093,8 +1164,8 @@ var installCommand = new commander.Command("install").description("\u5B89\u88C5
1093
1164
  const tempDir = path.join(targetRoot, ".temp-install-" + Date.now());
1094
1165
  fs.mkdirSync(tempDir, { recursive: true });
1095
1166
  console.log(`\u{1F4E6} \u89E3\u538B\u5B89\u88C5\u5305: ${path.basename(archivePath)}`);
1096
- await new Promise((resolve3, reject) => {
1097
- fs.createReadStream(archivePath).pipe(unzipper.Extract({ path: tempDir })).on("close", resolve3).on("error", reject);
1167
+ await new Promise((resolve4, reject) => {
1168
+ fs.createReadStream(archivePath).pipe(unzipper.Extract({ path: tempDir })).on("close", resolve4).on("error", reject);
1098
1169
  });
1099
1170
  const configPath = path.join(tempDir, "seastudio.config.json");
1100
1171
  if (!fs.existsSync(configPath)) {
@@ -1133,6 +1204,7 @@ var installCommand = new commander.Command("install").description("\u5B89\u88C5
1133
1204
  var program = new commander.Command();
1134
1205
  program.name("seastudio").description("SeaStudio Plugin Development CLI").version("1.0.0");
1135
1206
  program.addCommand(createCommand);
1207
+ program.addCommand(generateMcpManifestCommand);
1136
1208
  program.addCommand(packCommand);
1137
1209
  program.addCommand(installCommand);
1138
1210
  program.parse();
@@ -7,8 +7,8 @@ import { existsSync, createWriteStream, mkdirSync, createReadStream } from 'fs';
7
7
  import { fileURLToPath } from 'url';
8
8
  import chalk from 'chalk';
9
9
  import ora2 from 'ora';
10
- import { tmpdir } from 'os';
11
10
  import { spawnSync, spawn } from 'child_process';
11
+ import { tmpdir } from 'os';
12
12
  import https from 'https';
13
13
  import { pipeline } from 'stream/promises';
14
14
  import archiver from 'archiver';
@@ -427,6 +427,73 @@ app.listen(port, '127.0.0.1', () => {
427
427
  process.exit(1);
428
428
  }
429
429
  });
430
+ function normalizeTools(tools) {
431
+ return tools.map((tool) => JSON.parse(JSON.stringify({
432
+ name: tool.name,
433
+ description: tool.description,
434
+ inputSchema: tool.inputSchema,
435
+ ...tool.outputSchema ? { outputSchema: tool.outputSchema } : {},
436
+ ...tool.annotations ? { annotations: tool.annotations } : {}
437
+ })));
438
+ }
439
+ function loadManifestFromEntry(entryPath) {
440
+ const readerScript = `
441
+ import { pathToFileURL } from 'node:url';
442
+ const entryPath = process.argv[1];
443
+ const mod = await import(pathToFileURL(entryPath).href);
444
+ const manifest = mod.pluginMcpManifest ?? (Array.isArray(mod.mcpTools)
445
+ ? { schemaVersion: 1, tools: mod.mcpTools }
446
+ : null);
447
+ if (!manifest) {
448
+ throw new Error('frontend/src/mcp-entry.ts \u5FC5\u987B\u5BFC\u51FA pluginMcpManifest \u6216 mcpTools');
449
+ }
450
+ process.stdout.write(JSON.stringify(manifest));
451
+ `;
452
+ const result = spawnSync(process.execPath, [
453
+ "--experimental-strip-types",
454
+ "--experimental-specifier-resolution=node",
455
+ "--input-type=module",
456
+ "-e",
457
+ readerScript,
458
+ entryPath
459
+ ], {
460
+ encoding: "utf-8"
461
+ });
462
+ if (result.status !== 0) {
463
+ throw new Error((result.stderr || result.stdout || "\u8BFB\u53D6 frontend/src/mcp-entry.ts \u5931\u8D25").trim());
464
+ }
465
+ const parsed = JSON.parse(result.stdout || "{}");
466
+ return {
467
+ schemaVersion: 1,
468
+ tools: normalizeTools(parsed.tools ?? [])
469
+ };
470
+ }
471
+ async function generatePluginMcpManifest(projectDir) {
472
+ const frontendDir = existsSync(join(projectDir, "src")) ? projectDir : join(projectDir, "frontend");
473
+ const entryPath = join(frontendDir, "src", "mcp-entry.ts");
474
+ const outputPath = join(frontendDir, "dist", "mcp-manifest.json");
475
+ if (!existsSync(entryPath)) {
476
+ throw new Error(`\u672A\u627E\u5230\u6807\u51C6 MCP \u5165\u53E3\u6587\u4EF6: ${entryPath}`);
477
+ }
478
+ const manifest = loadManifestFromEntry(entryPath);
479
+ await mkdir(dirname(outputPath), { recursive: true });
480
+ await writeFile(outputPath, `${JSON.stringify(manifest, null, 2)}
481
+ `, "utf-8");
482
+ return {
483
+ outputPath,
484
+ toolCount: manifest.tools.length
485
+ };
486
+ }
487
+ var generateMcpManifestCommand = new Command("generate-mcp-manifest").description("\u4ECE frontend/src/mcp-entry.ts \u751F\u6210 dist/mcp-manifest.json").option("-d, --dir <directory>", "\u63D2\u4EF6\u9879\u76EE\u76EE\u5F55", ".").action(async (options) => {
488
+ try {
489
+ const projectDir = resolve(process.cwd(), options.dir || ".");
490
+ const result = await generatePluginMcpManifest(projectDir);
491
+ console.log(`Generated ${result.outputPath} (${result.toolCount} tools)`);
492
+ } catch (error) {
493
+ console.error(error instanceof Error ? error.message : String(error));
494
+ process.exit(1);
495
+ }
496
+ });
430
497
  var PYTHON_STANDALONE_RELEASE_API = "https://api.github.com/repos/astral-sh/python-build-standalone/releases/latest";
431
498
  var TARGET_PYTHON_MINOR = Number(process.env.SEASTUDIO_AGENT_PYTHON_MINOR) || 12;
432
499
  var MAX_PYTHON_MINOR = 13;
@@ -594,11 +661,11 @@ function pickPythonRuntimeAsset(assets, target) {
594
661
  return matches[0];
595
662
  }
596
663
  async function fetchText(url, headers) {
597
- return new Promise((resolve3, reject) => {
664
+ return new Promise((resolve4, reject) => {
598
665
  https.get(url, { headers }, (res) => {
599
666
  if (res.statusCode && res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
600
667
  res.resume();
601
- fetchText(res.headers.location, headers).then(resolve3).catch(reject);
668
+ fetchText(res.headers.location, headers).then(resolve4).catch(reject);
602
669
  return;
603
670
  }
604
671
  if (res.statusCode && res.statusCode >= 400) {
@@ -608,13 +675,13 @@ async function fetchText(url, headers) {
608
675
  }
609
676
  const chunks = [];
610
677
  res.on("data", (chunk) => chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)));
611
- res.on("end", () => resolve3(Buffer.concat(chunks).toString("utf8")));
678
+ res.on("end", () => resolve4(Buffer.concat(chunks).toString("utf8")));
612
679
  res.on("error", reject);
613
680
  }).on("error", reject);
614
681
  });
615
682
  }
616
683
  async function sleep(ms) {
617
- await new Promise((resolve3) => setTimeout(resolve3, ms));
684
+ await new Promise((resolve4) => setTimeout(resolve4, ms));
618
685
  }
619
686
  async function withRetries(label, task) {
620
687
  let lastError;
@@ -949,6 +1016,10 @@ var packCommand = new Command("pack").description("\u6253\u5305\u63D2\u4EF6\u621
949
1016
  `);
950
1017
  process.exit(1);
951
1018
  }
1019
+ if (config.type === "plugin") {
1020
+ const generated = await generatePluginMcpManifest(projectDir);
1021
+ logPackStep(`\u751F\u6210 MCP manifest\uFF1A${generated.outputPath} (${generated.toolCount} tools)`);
1022
+ }
952
1023
  spinnerDist.succeed("frontend/dist/index.html \u5DF2\u627E\u5230");
953
1024
  } else {
954
1025
  const spinnerDist = ora2("\u8FDC\u7A0B\u63D2\u4EF6\uFF0C\u8DF3\u8FC7 frontend build \u68C0\u67E5").start();
@@ -1082,8 +1153,8 @@ var installCommand = new Command("install").description("\u5B89\u88C5 .seaplugin
1082
1153
  const tempDir = join(targetRoot, ".temp-install-" + Date.now());
1083
1154
  mkdirSync(tempDir, { recursive: true });
1084
1155
  console.log(`\u{1F4E6} \u89E3\u538B\u5B89\u88C5\u5305: ${basename(archivePath)}`);
1085
- await new Promise((resolve3, reject) => {
1086
- createReadStream(archivePath).pipe(Extract({ path: tempDir })).on("close", resolve3).on("error", reject);
1156
+ await new Promise((resolve4, reject) => {
1157
+ createReadStream(archivePath).pipe(Extract({ path: tempDir })).on("close", resolve4).on("error", reject);
1087
1158
  });
1088
1159
  const configPath = join(tempDir, "seastudio.config.json");
1089
1160
  if (!existsSync(configPath)) {
@@ -1122,6 +1193,7 @@ var installCommand = new Command("install").description("\u5B89\u88C5 .seaplugin
1122
1193
  var program = new Command();
1123
1194
  program.name("seastudio").description("SeaStudio Plugin Development CLI").version("1.0.0");
1124
1195
  program.addCommand(createCommand);
1196
+ program.addCommand(generateMcpManifestCommand);
1125
1197
  program.addCommand(packCommand);
1126
1198
  program.addCommand(installCommand);
1127
1199
  program.parse();