unplugin-devpilot 0.0.2 → 0.0.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.
package/README.md ADDED
@@ -0,0 +1,105 @@
1
+ # unplugin-devpilot
2
+
3
+ [![npm version][npm-version-src]][npm-version-href]
4
+ [![npm downloads][npm-downloads-src]][npm-downloads-href]
5
+ [![Unit Test][unit-test-src]][unit-test-href]
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm i -D unplugin-devpilot
11
+ ```
12
+
13
+ <details>
14
+ <summary>Vite</summary><br>
15
+
16
+ ```ts
17
+ // vite.config.ts
18
+ import Devpilot from 'unplugin-devpilot/vite';
19
+
20
+ export default defineConfig({
21
+ plugins: [Devpilot()],
22
+ });
23
+ ```
24
+
25
+ <br></details>
26
+
27
+ <details>
28
+ <summary>Webpack</summary><br>
29
+
30
+ ```js
31
+ // webpack.config.js
32
+ import Devpilot from 'unplugin-devpilot/webpack';
33
+
34
+ export default {
35
+ /* ... */
36
+ plugins: [Devpilot()],
37
+ };
38
+ ```
39
+
40
+ <br></details>
41
+
42
+ <details>
43
+ <summary>Rspack</summary><br>
44
+
45
+ ```ts
46
+ // rspack.config.js
47
+ import Devpilot from 'unplugin-devpilot/rspack';
48
+
49
+ export default {
50
+ /* ... */
51
+ plugins: [Devpilot()],
52
+ };
53
+ ```
54
+
55
+ <br></details>
56
+
57
+ ## Client Import
58
+
59
+ Add this import to your project entry point to enable the devpilot client:
60
+
61
+ ```ts
62
+ // main.ts or main.js (entry point)
63
+ import 'virtual:devpilot-client';
64
+ ```
65
+
66
+ This import activates the WebSocket connection to the development server and initializes all registered plugins on the client side.
67
+
68
+ ## Configuration
69
+
70
+ You can customize the plugin behavior by passing options:
71
+
72
+ ```ts
73
+ // vite.config.ts
74
+ import Devpilot from 'unplugin-devpilot/vite';
75
+
76
+ export default defineConfig({
77
+ plugins: [
78
+ Devpilot({
79
+ wsPort: 3100, // Optional: Specify WebSocket port (will be randomly allocated if not specified)
80
+ mcpPort: 3101, // Optional: Specify MCP server port (will use random port if specified port is occupied)
81
+ plugins: [], // Optional: Array of DevpilotPlugin instances
82
+ }),
83
+ ],
84
+ });
85
+ ```
86
+
87
+ ### Port Allocation Strategy
88
+
89
+ - **wsPort**: When provided, the specified port is used if available; otherwise, a random available port is allocated. When not provided, a random available port is automatically allocated
90
+ - **mcpPort**: When not provided, defaults to 3101. If the port is already in use, an error will be thrown
91
+
92
+ This ensures your MCP server runs on a predictable port. If the default port is occupied, you'll need to specify a different port or free up the occupied port.
93
+
94
+ ## License
95
+
96
+ [MIT](./LICENSE) License © 2025-PRESENT [Huali](https://github.com/zcf0508)
97
+
98
+ <!-- Badges -->
99
+
100
+ [npm-version-src]: https://img.shields.io/npm/v/unplugin-devpilot.svg
101
+ [npm-version-href]: https://npmjs.com/package/unplugin-devpilot
102
+ [npm-downloads-src]: https://img.shields.io/npm/dm/unplugin-devpilot
103
+ [npm-downloads-href]: https://www.npmcharts.com/compare/unplugin-devpilot?interval=30
104
+ [unit-test-src]: https://github.com/zcf0508/unplugin-devpilot/actions/workflows/unit-test.yml/badge.svg
105
+ [unit-test-href]: https://github.com/zcf0508/unplugin-devpilot/actions/workflows/unit-test.yml
package/dist/farm.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { t as unpluginDevpilot } from "./index-CQudsm6j.mjs";
1
+ import { t as unpluginDevpilot } from "./index-WH3owjvn.mjs";
2
2
 
3
3
  //#region src/farm.d.ts
4
4
  /**
package/dist/farm.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { n as unpluginDevpilot } from "./src-D62s1VAN.mjs";
1
+ import { n as unpluginDevpilot } from "./src-AEXLBOF9.mjs";
2
2
 
3
3
  //#region src/farm.ts
4
4
  /**
@@ -1,3 +1,18 @@
1
+ //#region src/core/utils.d.ts
2
+ /**
3
+ * Resolve the module path relative to the plugin to an absolute path
4
+ * Handles cross-platform paths (Windows, macOS, Linux) and proper escaping for imports
5
+ * @param importMetaUrl - Pass in import.meta.url
6
+ * @param relativePath - Path relative to the plugin
7
+ * @example
8
+ * ```ts
9
+ * import { resolveModule } from 'unplugin-devpilot/core/utils'
10
+ *
11
+ * const skillPath = resolveModule(import.meta.url, './skill.md')
12
+ * ```
13
+ */
14
+ declare function resolveModule(importMetaUrl: string, relativePath: string): string;
15
+ //#endregion
1
16
  //#region ../../node_modules/.pnpm/zod@4.3.6/node_modules/zod/v3/helpers/typeAliases.d.cts
2
17
  type Primitive$2 = string | number | symbol | bigint | boolean | null | undefined;
3
18
  //#endregion
@@ -4128,4 +4143,4 @@ interface DevpilotPluginContext {
4128
4143
  */
4129
4144
  declare function resolveClientModule(importMetaUrl: string, relativePath: string): string;
4130
4145
  //#endregion
4131
- export { defineMcpToolRegister as i, resolveClientModule as n, McpToolRegister as r, DevpilotPluginContext as t };
4146
+ export { resolveModule as a, defineMcpToolRegister as i, resolveClientModule as n, McpToolRegister as r, DevpilotPluginContext as t };
@@ -1,4 +1,4 @@
1
- import { r as McpToolRegister, t as DevpilotPluginContext } from "./index-9V3dRAxA.mjs";
1
+ import { r as McpToolRegister, t as DevpilotPluginContext } from "./index-Csy16I0Z.mjs";
2
2
  import { UnpluginInstance } from "unplugin";
3
3
  import { WebSocket } from "ws";
4
4
 
@@ -25,11 +25,40 @@ interface DevpilotPlugin {
25
25
  */
26
26
  serverSetup?: (ctx: DevpilotPluginContext) => Record<string, (...args: any[]) => any>;
27
27
  mcpSetup?: (ctx: DevpilotPluginContext) => Array<McpToolRegister>;
28
+ /**
29
+ * The skill module path to be injected
30
+ * - npm package path: 'my-plugin/skill'
31
+ * - absolute path: '/path/to/skill.md'
32
+ *
33
+ * Note: relative paths need to be resolved to absolute paths first
34
+ * @example
35
+ * ```ts
36
+ * import { resolveSkillModule } from 'unplugin-devpilot'
37
+ *
38
+ * skillModule: resolveSkillModule(import.meta.url, './skill.md')
39
+ * ```
40
+ */
41
+ skillModule?: string | ((ctx: DevpilotPluginContext) => string);
28
42
  }
29
43
  interface Options {
30
44
  wsPort?: number;
31
45
  mcpPort?: number;
32
46
  plugins?: DevpilotPlugin[];
47
+ /**
48
+ * The path to generate the core skill file
49
+ * - directory path: './src/skills/devpilot' (will generate SKILL.md in this directory)
50
+ * - file path: './src/skills/devpilot/SKILL.md' (will generate the specified file)
51
+ *
52
+ * If not specified, no core skill file will be generated
53
+ * @example
54
+ * ```ts
55
+ * Devpilot({
56
+ * skillCorePath: './src/skills/devpilot',
57
+ * plugins: [],
58
+ * })
59
+ * ```
60
+ */
61
+ skillCorePath?: string;
33
62
  }
34
63
  //#endregion
35
64
  //#region ../../node_modules/.pnpm/birpc@4.0.0/node_modules/birpc/dist/index.d.mts
@@ -222,7 +251,27 @@ declare class ClientManager {
222
251
  }
223
252
  declare const clientManager: ClientManager;
224
253
  //#endregion
254
+ //#region src/core/skill-generator.d.ts
255
+ /**
256
+ * Resolve the skill module path relative to the plugin to an absolute path
257
+ * Handles cross-platform paths (Windows, macOS, Linux) and proper escaping for imports
258
+ * @param importMetaUrl - Pass in import.meta.url
259
+ * @param relativePath - Path relative to the plugin
260
+ * @example
261
+ * ```ts
262
+ * import { resolveSkillModule } from 'unplugin-devpilot'
263
+ *
264
+ * export function myPlugin(): DevpilotPlugin {
265
+ * return {
266
+ * namespace: 'my-plugin',
267
+ * skillModule: resolveSkillModule(import.meta.url, './skill.md'),
268
+ * }
269
+ * }
270
+ * ```
271
+ */
272
+ declare function resolveSkillModule(importMetaUrl: string, relativePath: string): string;
273
+ //#endregion
225
274
  //#region src/index.d.ts
226
275
  declare const unpluginDevpilot: UnpluginInstance<Options | undefined, false>;
227
276
  //#endregion
228
- export { ClientDiscoveryFilter as a, PendingTask as c, ServerFunctions as d, TaskHistory as f, BaseServerFunctions as i, PluginClientFunctions as l, Options as m, clientManager as n, ClientFunctions as o, DevpilotPlugin as p, BaseClientFunctions as r, ClientInfo as s, unpluginDevpilot as t, PluginServerFunctions as u };
277
+ export { BaseServerFunctions as a, ClientInfo as c, PluginServerFunctions as d, ServerFunctions as f, Options as h, BaseClientFunctions as i, PendingTask as l, DevpilotPlugin as m, resolveSkillModule as n, ClientDiscoveryFilter as o, TaskHistory as p, clientManager as r, ClientFunctions as s, unpluginDevpilot as t, PluginClientFunctions as u };
package/dist/index.d.mts CHANGED
@@ -1,3 +1,3 @@
1
- import { i as defineMcpToolRegister, n as resolveClientModule, t as DevpilotPluginContext } from "./index-9V3dRAxA.mjs";
2
- import { a as ClientDiscoveryFilter, c as PendingTask, d as ServerFunctions, f as TaskHistory, i as BaseServerFunctions, l as PluginClientFunctions, m as Options, n as clientManager, o as ClientFunctions, p as DevpilotPlugin, r as BaseClientFunctions, s as ClientInfo, t as unpluginDevpilot, u as PluginServerFunctions } from "./index-CQudsm6j.mjs";
3
- export { BaseClientFunctions, BaseServerFunctions, ClientDiscoveryFilter, ClientFunctions, ClientInfo, DevpilotPlugin, DevpilotPluginContext, Options, PendingTask, PluginClientFunctions, PluginServerFunctions, ServerFunctions, TaskHistory, clientManager, unpluginDevpilot as default, unpluginDevpilot, defineMcpToolRegister, resolveClientModule };
1
+ import { a as resolveModule, i as defineMcpToolRegister, n as resolveClientModule, t as DevpilotPluginContext } from "./index-Csy16I0Z.mjs";
2
+ import { a as BaseServerFunctions, c as ClientInfo, d as PluginServerFunctions, f as ServerFunctions, h as Options, i as BaseClientFunctions, l as PendingTask, m as DevpilotPlugin, n as resolveSkillModule, o as ClientDiscoveryFilter, p as TaskHistory, r as clientManager, s as ClientFunctions, t as unpluginDevpilot, u as PluginClientFunctions } from "./index-WH3owjvn.mjs";
3
+ export { BaseClientFunctions, BaseServerFunctions, ClientDiscoveryFilter, ClientFunctions, ClientInfo, DevpilotPlugin, DevpilotPluginContext, Options, PendingTask, PluginClientFunctions, PluginServerFunctions, ServerFunctions, TaskHistory, clientManager, unpluginDevpilot as default, unpluginDevpilot, defineMcpToolRegister, resolveClientModule, resolveModule, resolveSkillModule };
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { n as unpluginDevpilot, r as clientManager, t as src_default } from "./src-D62s1VAN.mjs";
2
- import { n as defineMcpToolRegister, t as resolveClientModule } from "./plugin-BPkoZQbf.mjs";
1
+ import { i as clientManager, n as unpluginDevpilot, r as resolveSkillModule, t as src_default } from "./src-AEXLBOF9.mjs";
2
+ import { n as defineMcpToolRegister, r as resolveModule, t as resolveClientModule } from "./plugin-B1Afr0m3.mjs";
3
3
 
4
- export { clientManager, src_default as default, defineMcpToolRegister, resolveClientModule, unpluginDevpilot };
4
+ export { clientManager, src_default as default, defineMcpToolRegister, resolveClientModule, resolveModule, resolveSkillModule, unpluginDevpilot };
@@ -1,6 +1,24 @@
1
1
  import { dirname, join } from "node:path";
2
2
  import { fileURLToPath, pathToFileURL } from "node:url";
3
3
 
4
+ //#region src/core/utils.ts
5
+ /**
6
+ * Resolve the module path relative to the plugin to an absolute path
7
+ * Handles cross-platform paths (Windows, macOS, Linux) and proper escaping for imports
8
+ * @param importMetaUrl - Pass in import.meta.url
9
+ * @param relativePath - Path relative to the plugin
10
+ * @example
11
+ * ```ts
12
+ * import { resolveModule } from 'unplugin-devpilot/core/utils'
13
+ *
14
+ * const skillPath = resolveModule(import.meta.url, './skill.md')
15
+ * ```
16
+ */
17
+ function resolveModule(importMetaUrl, relativePath) {
18
+ return pathToFileURL(join(dirname(fileURLToPath(importMetaUrl)), relativePath)).href;
19
+ }
20
+
21
+ //#endregion
4
22
  //#region src/core/plugin/mcp.ts
5
23
  function defineMcpToolRegister(name, config, cb) {
6
24
  return () => ({
@@ -30,8 +48,8 @@ function defineMcpToolRegister(name, config, cb) {
30
48
  * ```
31
49
  */
32
50
  function resolveClientModule(importMetaUrl, relativePath) {
33
- return pathToFileURL(join(dirname(fileURLToPath(importMetaUrl)), relativePath)).href;
51
+ return resolveModule(importMetaUrl, relativePath);
34
52
  }
35
53
 
36
54
  //#endregion
37
- export { defineMcpToolRegister as n, resolveClientModule as t };
55
+ export { defineMcpToolRegister as n, resolveModule as r, resolveClientModule as t };
package/dist/plugin.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { i as defineMcpToolRegister, n as resolveClientModule, r as McpToolRegister, t as DevpilotPluginContext } from "./index-9V3dRAxA.mjs";
2
- export { DevpilotPluginContext, McpToolRegister as McpServerRegister, defineMcpToolRegister, resolveClientModule };
1
+ import { a as resolveModule, i as defineMcpToolRegister, n as resolveClientModule, r as McpToolRegister, t as DevpilotPluginContext } from "./index-Csy16I0Z.mjs";
2
+ export { DevpilotPluginContext, McpToolRegister as McpServerRegister, defineMcpToolRegister, resolveClientModule, resolveModule };
package/dist/plugin.mjs CHANGED
@@ -1,3 +1,3 @@
1
- import { n as defineMcpToolRegister, t as resolveClientModule } from "./plugin-BPkoZQbf.mjs";
1
+ import { n as defineMcpToolRegister, r as resolveModule, t as resolveClientModule } from "./plugin-B1Afr0m3.mjs";
2
2
 
3
- export { defineMcpToolRegister, resolveClientModule };
3
+ export { defineMcpToolRegister, resolveClientModule, resolveModule };
package/dist/rspack.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { t as unpluginDevpilot } from "./index-CQudsm6j.mjs";
1
+ import { t as unpluginDevpilot } from "./index-WH3owjvn.mjs";
2
2
 
3
3
  //#region src/rspack.d.ts
4
4
  /**
package/dist/rspack.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { n as unpluginDevpilot } from "./src-D62s1VAN.mjs";
1
+ import { n as unpluginDevpilot } from "./src-AEXLBOF9.mjs";
2
2
 
3
3
  //#region src/rspack.ts
4
4
  /**
@@ -1,3 +1,4 @@
1
+ import { r as resolveModule } from "./plugin-B1Afr0m3.mjs";
1
2
  import { createRequire } from "node:module";
2
3
  import process$1 from "node:process";
3
4
  import { createUnplugin } from "unplugin";
@@ -5,6 +6,11 @@ import { createServer } from "node:http";
5
6
  import { Http2ServerRequest } from "http2";
6
7
  import { Readable } from "stream";
7
8
  import crypto$1 from "crypto";
9
+ import { createServer as createServer$1 } from "node:net";
10
+ import { networkInterfaces } from "node:os";
11
+ import { dirname, extname, join } from "node:path";
12
+ import { promises } from "node:fs";
13
+ import { fileURLToPath } from "node:url";
8
14
 
9
15
  //#region rolldown:runtime
10
16
  var __create = Object.create;
@@ -19793,7 +19799,7 @@ var StreamableHTTPServerTransport = class {
19793
19799
 
19794
19800
  //#endregion
19795
19801
  //#region package.json
19796
- var version = "0.0.2";
19802
+ var version = "0.0.4";
19797
19803
 
19798
19804
  //#endregion
19799
19805
  //#region ../../node_modules/.pnpm/es-toolkit@1.44.0/node_modules/es-toolkit/dist/compat/util/uniqueId.mjs
@@ -20190,21 +20196,314 @@ async function startMcpServer(port) {
20190
20196
  });
20191
20197
  }
20192
20198
  function stopMcpServer() {
20193
- if (httpServer) {
20194
- httpServer.close();
20195
- httpServer = null;
20199
+ return new Promise((resolve) => {
20200
+ if (httpServer) {
20201
+ const server = httpServer;
20202
+ httpServer = null;
20203
+ server.close(() => resolve());
20204
+ } else resolve();
20205
+ });
20206
+ }
20207
+
20208
+ //#endregion
20209
+ //#region ../../node_modules/.pnpm/get-port-please@3.2.0/node_modules/get-port-please/dist/index.mjs
20210
+ const unsafePorts = /* @__PURE__ */ new Set([
20211
+ 1,
20212
+ 7,
20213
+ 9,
20214
+ 11,
20215
+ 13,
20216
+ 15,
20217
+ 17,
20218
+ 19,
20219
+ 20,
20220
+ 21,
20221
+ 22,
20222
+ 23,
20223
+ 25,
20224
+ 37,
20225
+ 42,
20226
+ 43,
20227
+ 53,
20228
+ 69,
20229
+ 77,
20230
+ 79,
20231
+ 87,
20232
+ 95,
20233
+ 101,
20234
+ 102,
20235
+ 103,
20236
+ 104,
20237
+ 109,
20238
+ 110,
20239
+ 111,
20240
+ 113,
20241
+ 115,
20242
+ 117,
20243
+ 119,
20244
+ 123,
20245
+ 135,
20246
+ 137,
20247
+ 139,
20248
+ 143,
20249
+ 161,
20250
+ 179,
20251
+ 389,
20252
+ 427,
20253
+ 465,
20254
+ 512,
20255
+ 513,
20256
+ 514,
20257
+ 515,
20258
+ 526,
20259
+ 530,
20260
+ 531,
20261
+ 532,
20262
+ 540,
20263
+ 548,
20264
+ 554,
20265
+ 556,
20266
+ 563,
20267
+ 587,
20268
+ 601,
20269
+ 636,
20270
+ 989,
20271
+ 990,
20272
+ 993,
20273
+ 995,
20274
+ 1719,
20275
+ 1720,
20276
+ 1723,
20277
+ 2049,
20278
+ 3659,
20279
+ 4045,
20280
+ 5060,
20281
+ 5061,
20282
+ 6e3,
20283
+ 6566,
20284
+ 6665,
20285
+ 6666,
20286
+ 6667,
20287
+ 6668,
20288
+ 6669,
20289
+ 6697,
20290
+ 10080
20291
+ ]);
20292
+ function isUnsafePort(port) {
20293
+ return unsafePorts.has(port);
20294
+ }
20295
+ function isSafePort(port) {
20296
+ return !isUnsafePort(port);
20297
+ }
20298
+ var GetPortError = class extends Error {
20299
+ constructor(message, opts) {
20300
+ super(message, opts);
20301
+ this.message = message;
20196
20302
  }
20303
+ name = "GetPortError";
20304
+ };
20305
+ function _log(verbose, message) {
20306
+ if (verbose) console.log(`[get-port] ${message}`);
20307
+ }
20308
+ function _tryPort(port, host) {
20309
+ return new Promise((resolve) => {
20310
+ const server = createServer$1();
20311
+ server.unref();
20312
+ server.on("error", () => {
20313
+ resolve(false);
20314
+ });
20315
+ server.listen({
20316
+ port,
20317
+ host
20318
+ }, () => {
20319
+ const { port: port2 } = server.address();
20320
+ server.close(() => {
20321
+ resolve(isSafePort(port2) && port2);
20322
+ });
20323
+ });
20324
+ });
20325
+ }
20326
+ function _getLocalHosts(additional) {
20327
+ const hosts = new Set(additional);
20328
+ for (const _interface of Object.values(networkInterfaces())) for (const config of _interface || []) if (config.address && !config.internal && !config.address.startsWith("fe80::") && !config.address.startsWith("169.254")) hosts.add(config.address);
20329
+ return [...hosts];
20330
+ }
20331
+ function _fmtOnHost(hostname) {
20332
+ return hostname ? `on host ${JSON.stringify(hostname)}` : "on any host";
20333
+ }
20334
+ async function getRandomPort(host) {
20335
+ const port = await checkPort(0, host);
20336
+ if (port === false) throw new GetPortError(`Unable to find a random port ${_fmtOnHost(host)}`);
20337
+ return port;
20338
+ }
20339
+ async function checkPort(port, host = process.env.HOST, verbose) {
20340
+ if (!host) host = _getLocalHosts([void 0, "0.0.0.0"]);
20341
+ if (!Array.isArray(host)) return _tryPort(port, host);
20342
+ for (const _host of host) {
20343
+ const _port = await _tryPort(port, _host);
20344
+ if (_port === false) {
20345
+ if (port < 1024 && verbose) _log(verbose, `Unable to listen to the privileged port ${port} ${_fmtOnHost(_host)}`);
20346
+ return false;
20347
+ }
20348
+ if (port === 0 && _port !== 0) port = _port;
20349
+ }
20350
+ return port;
20197
20351
  }
20198
20352
 
20199
20353
  //#endregion
20200
20354
  //#region src/core/options.ts
20201
- function resolveOptions(options) {
20355
+ let lastResolvedWsPort;
20356
+ let lastResolvedMcpPort;
20357
+ async function resolveOptions(options) {
20358
+ const wsPort = await resolveWsPort(options.wsPort);
20359
+ const mcpPort = await resolveMcpPort(options.mcpPort);
20360
+ lastResolvedWsPort = wsPort;
20361
+ lastResolvedMcpPort = mcpPort;
20202
20362
  return {
20203
- wsPort: options.wsPort || 3100,
20204
- mcpPort: options.mcpPort || 3101,
20205
- plugins: options.plugins || []
20363
+ wsPort,
20364
+ mcpPort,
20365
+ plugins: options.plugins || [],
20366
+ skillCorePath: options.skillCorePath
20206
20367
  };
20207
20368
  }
20369
+ async function resolveWsPort(preferred) {
20370
+ const candidate = preferred ?? lastResolvedWsPort;
20371
+ if (candidate !== void 0) {
20372
+ if (await checkPort(candidate) !== false) return candidate;
20373
+ if (candidate === lastResolvedWsPort) return candidate;
20374
+ }
20375
+ if (lastResolvedWsPort !== void 0) return lastResolvedWsPort;
20376
+ return getRandomPort();
20377
+ }
20378
+ async function resolveMcpPort(preferred) {
20379
+ const candidate = preferred || 3101;
20380
+ if (candidate === lastResolvedMcpPort) return candidate;
20381
+ if (await checkPort(candidate) === false) throw new Error(`MCP port ${candidate} is already in use. Please specify a different port or free up the port.`);
20382
+ return candidate;
20383
+ }
20384
+
20385
+ //#endregion
20386
+ //#region src/core/skill-generator.ts
20387
+ /**
20388
+ * Resolve the skill module path relative to the plugin to an absolute path
20389
+ * Handles cross-platform paths (Windows, macOS, Linux) and proper escaping for imports
20390
+ * @param importMetaUrl - Pass in import.meta.url
20391
+ * @param relativePath - Path relative to the plugin
20392
+ * @example
20393
+ * ```ts
20394
+ * import { resolveSkillModule } from 'unplugin-devpilot'
20395
+ *
20396
+ * export function myPlugin(): DevpilotPlugin {
20397
+ * return {
20398
+ * namespace: 'my-plugin',
20399
+ * skillModule: resolveSkillModule(import.meta.url, './skill.md'),
20400
+ * }
20401
+ * }
20402
+ * ```
20403
+ */
20404
+ function resolveSkillModule(importMetaUrl, relativePath) {
20405
+ return resolveModule(importMetaUrl, relativePath);
20406
+ }
20407
+ /**
20408
+ * Determine if a path is a directory (no file extension) or a file
20409
+ * @param path - The path to check
20410
+ * @returns true if the path is a directory, false if it's a file
20411
+ */
20412
+ function isDirectoryPath(path) {
20413
+ return extname(path) === "";
20414
+ }
20415
+ /**
20416
+ * Get the core skill file path, handling both directory and file paths
20417
+ * @param skillCorePath - The configured skill core path (directory or file)
20418
+ * @returns The actual file path to use for the core skill file
20419
+ */
20420
+ function getCoreSkillFilePath(skillCorePath) {
20421
+ if (isDirectoryPath(skillCorePath)) return join(skillCorePath, "SKILL.md");
20422
+ return skillCorePath;
20423
+ }
20424
+ /**
20425
+ * Get all plugin skill modules
20426
+ */
20427
+ function getPluginSkillModules(plugins, options) {
20428
+ const ctx = { wsPort: options.wsPort };
20429
+ return plugins.filter((p) => p.skillModule).map((p) => {
20430
+ const mod = typeof p.skillModule === "function" ? p.skillModule(ctx) : p.skillModule;
20431
+ let skillPath;
20432
+ if (mod.startsWith("file://")) skillPath = fileURLToPath(mod);
20433
+ else if (mod.startsWith("npm:") || !mod.startsWith(".") && !mod.startsWith("/") && (mod.includes("/") || mod.match(/^[@a-z0-9]\S+$/i))) skillPath = mod;
20434
+ else skillPath = mod;
20435
+ return {
20436
+ namespace: p.namespace,
20437
+ path: skillPath,
20438
+ originalSkillModule: mod
20439
+ };
20440
+ });
20441
+ }
20442
+ /**
20443
+ * Generate the core skill markdown content
20444
+ */
20445
+ function generateCoreSkillContent(options, isDev) {
20446
+ if (!isDev) return "";
20447
+ return `# Devpilot Core Skills
20448
+
20449
+ This is the core skill file that aggregates all plugin skills.
20450
+
20451
+ ## Available Skills
20452
+
20453
+ ${getPluginSkillModules(options.plugins, options).map((skill) => {
20454
+ if (skill.originalSkillModule.startsWith("file://")) {
20455
+ const linkPath = `./${skill.namespace}.md`;
20456
+ return `- [${skill.namespace}](${linkPath}) - ${skill.namespace} capabilities`;
20457
+ } else if (skill.originalSkillModule.startsWith("npm:") || !skill.originalSkillModule.startsWith(".") && !skill.originalSkillModule.startsWith("/") && (skill.originalSkillModule.includes("/") || skill.originalSkillModule.match(/^[@a-z0-9]\S+$/i))) return `- [${skill.namespace}](${skill.originalSkillModule}) - ${skill.namespace} capabilities`;
20458
+ else {
20459
+ const linkPath = `./${skill.namespace}.md`;
20460
+ return `- [${skill.namespace}](${linkPath}) - ${skill.namespace} capabilities`;
20461
+ }
20462
+ }).join("\n") || "No plugin skills configured"}
20463
+
20464
+ ## Usage
20465
+
20466
+ These skills can be used with Claude Agent to interact with web applications.
20467
+
20468
+ ## Configuration
20469
+
20470
+ - **Core Skill Path**: ${options.skillCorePath || "Not configured"}
20471
+ - **Plugins**: ${options.plugins.length}
20472
+ - **WebSocket Port**: ${options.wsPort}
20473
+ - **MCP Port**: ${options.mcpPort}
20474
+ `;
20475
+ }
20476
+ /**
20477
+ * Generate and write the core skill file
20478
+ */
20479
+ async function generateCoreSkill(options, isDev) {
20480
+ if (!options.skillCorePath) return;
20481
+ const skillFilePath = getCoreSkillFilePath(options.skillCorePath);
20482
+ const content = generateCoreSkillContent(options, isDev);
20483
+ if (!isDev || !content) {
20484
+ try {
20485
+ await promises.unlink(skillFilePath);
20486
+ } catch {}
20487
+ return;
20488
+ }
20489
+ let existingContent;
20490
+ try {
20491
+ existingContent = await promises.readFile(skillFilePath, "utf-8");
20492
+ } catch {}
20493
+ if (existingContent === content) return;
20494
+ const dir = dirname(skillFilePath);
20495
+ await promises.mkdir(dir, { recursive: true });
20496
+ const pluginSkills = getPluginSkillModules(options.plugins, options);
20497
+ for (const skill of pluginSkills) if (skill.originalSkillModule.startsWith("file://")) {
20498
+ const sourcePath = skill.path;
20499
+ const destPath = join(dir, `${skill.namespace}.md`);
20500
+ try {
20501
+ const skillContent = await promises.readFile(sourcePath, "utf-8");
20502
+ await promises.writeFile(destPath, skillContent, "utf-8");
20503
+ } catch {}
20504
+ }
20505
+ await promises.writeFile(skillFilePath, content, "utf-8");
20506
+ }
20208
20507
 
20209
20508
  //#endregion
20210
20509
  //#region ../../node_modules/.pnpm/birpc@4.0.0/node_modules/birpc/dist/index.mjs
@@ -23990,10 +24289,13 @@ function startWebSocketServer(port) {
23990
24289
  return wss;
23991
24290
  }
23992
24291
  function stopWebSocketServer() {
23993
- if (wss) {
23994
- wss.close();
23995
- wss = null;
23996
- }
24292
+ return new Promise((resolve) => {
24293
+ if (wss) {
24294
+ const server = wss;
24295
+ wss = null;
24296
+ server.close(() => resolve());
24297
+ } else resolve();
24298
+ });
23997
24299
  }
23998
24300
 
23999
24301
  //#endregion
@@ -24024,23 +24326,33 @@ ${handlerCollection}
24024
24326
  });
24025
24327
  `;
24026
24328
  }
24027
- const unpluginDevpilot = createUnplugin((rawOptions = {}) => {
24028
- const options = resolveOptions(rawOptions);
24029
- let serversStarted = false;
24030
- const name = "unplugin-devpilot";
24031
- async function startServers() {
24032
- if (serversStarted) return;
24329
+ let serversStarted = false;
24330
+ let lastOptions = null;
24331
+ async function startServers(rawOptions) {
24332
+ const options = await resolveOptions(rawOptions);
24333
+ lastOptions = options;
24334
+ registerPluginServerMethods(options.plugins);
24335
+ registerPluginMcpRegisterMethods(options.plugins);
24336
+ if (!serversStarted) {
24033
24337
  serversStarted = true;
24034
- registerPluginServerMethods(options.plugins);
24035
- registerPluginMcpRegisterMethods(options.plugins);
24036
24338
  startWebSocketServer(options.wsPort);
24037
24339
  await startMcpServer(options.mcpPort);
24038
24340
  }
24039
- function stopServers() {
24040
- if (!serversStarted) return;
24041
- serversStarted = false;
24042
- stopWebSocketServer();
24043
- stopMcpServer();
24341
+ await generateCoreSkill(options, process$1.env.NODE_ENV !== "production");
24342
+ return options;
24343
+ }
24344
+ async function stopServers() {
24345
+ if (!serversStarted) return;
24346
+ serversStarted = false;
24347
+ await Promise.all([stopWebSocketServer(), stopMcpServer()]);
24348
+ if (lastOptions) await generateCoreSkill(lastOptions, false);
24349
+ }
24350
+ const unpluginDevpilot = createUnplugin((rawOptions = {}) => {
24351
+ let options = null;
24352
+ let isDevServer = false;
24353
+ const name = "unplugin-devpilot";
24354
+ async function ensureServersStarted() {
24355
+ options = await startServers(rawOptions);
24044
24356
  }
24045
24357
  return {
24046
24358
  name,
@@ -24051,38 +24363,53 @@ const unpluginDevpilot = createUnplugin((rawOptions = {}) => {
24051
24363
  loadInclude(id) {
24052
24364
  return id === RESOLVED_VIRTUAL_MODULE_ID;
24053
24365
  },
24054
- load(id) {
24055
- if (id === RESOLVED_VIRTUAL_MODULE_ID) return generateVirtualClientModule(options, process$1.env.NODE_ENV !== "production");
24366
+ async load(id) {
24367
+ if (id === RESOLVED_VIRTUAL_MODULE_ID) {
24368
+ if (!options) options = await resolveOptions(rawOptions);
24369
+ return generateVirtualClientModule(options, process$1.env.NODE_ENV !== "production");
24370
+ }
24056
24371
  },
24057
24372
  buildStart() {
24058
24373
  if (process$1.env.NODE_ENV === "production") return;
24059
- startServers();
24374
+ if (isDevServer) return;
24375
+ return ensureServersStarted();
24060
24376
  },
24061
24377
  buildEnd() {
24062
- stopServers();
24378
+ if (isDevServer) return;
24379
+ return stopServers();
24063
24380
  },
24064
24381
  vite: { configureServer() {
24065
- startServers();
24382
+ isDevServer = true;
24383
+ ensureServersStarted();
24066
24384
  } },
24067
24385
  webpack(compiler) {
24068
24386
  compiler.hooks.watchRun.tapPromise(name, async () => {
24069
- await startServers();
24387
+ isDevServer = true;
24388
+ await ensureServersStarted();
24070
24389
  });
24071
- compiler.hooks.done.tap(name, () => {
24072
- if (!compiler.options.watch) stopServers();
24390
+ compiler.hooks.shutdown?.tap(name, () => {
24391
+ stopServers();
24073
24392
  });
24074
24393
  },
24075
24394
  rspack(compiler) {
24076
24395
  compiler.hooks.watchRun.tapPromise(name, async () => {
24077
- await startServers();
24396
+ isDevServer = true;
24397
+ await ensureServersStarted();
24078
24398
  });
24079
- compiler.hooks.done.tap(name, () => {
24080
- if (!compiler.options.watch) stopServers();
24399
+ compiler.hooks.shutdown?.tap(name, () => {
24400
+ stopServers();
24081
24401
  });
24082
- }
24402
+ },
24403
+ farm: { configureDevServer() {
24404
+ isDevServer = true;
24405
+ ensureServersStarted();
24406
+ } }
24083
24407
  };
24084
24408
  });
24409
+ process$1.on("beforeExit", () => {
24410
+ stopServers();
24411
+ });
24085
24412
  var src_default = unpluginDevpilot;
24086
24413
 
24087
24414
  //#endregion
24088
- export { unpluginDevpilot as n, clientManager as r, src_default as t };
24415
+ export { clientManager as i, unpluginDevpilot as n, resolveSkillModule as r, src_default as t };
package/dist/vite.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { t as unpluginDevpilot } from "./index-CQudsm6j.mjs";
1
+ import { t as unpluginDevpilot } from "./index-WH3owjvn.mjs";
2
2
 
3
3
  //#region src/vite.d.ts
4
4
  /**
package/dist/vite.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { n as unpluginDevpilot } from "./src-D62s1VAN.mjs";
1
+ import { n as unpluginDevpilot } from "./src-AEXLBOF9.mjs";
2
2
 
3
3
  //#region src/vite.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { t as unpluginDevpilot } from "./index-CQudsm6j.mjs";
1
+ import { t as unpluginDevpilot } from "./index-WH3owjvn.mjs";
2
2
 
3
3
  //#region src/webpack.d.ts
4
4
  /**
package/dist/webpack.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { n as unpluginDevpilot } from "./src-D62s1VAN.mjs";
1
+ import { n as unpluginDevpilot } from "./src-AEXLBOF9.mjs";
2
2
 
3
3
  //#region src/webpack.ts
4
4
  /**
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "unplugin-devpilot",
3
3
  "type": "module",
4
- "version": "0.0.2",
4
+ "version": "0.0.4",
5
5
  "description": "Description.",
6
6
  "author": "zcf0508 <zcf0508@live.com>",
7
7
  "license": "MIT",
@@ -52,6 +52,30 @@
52
52
  "engines": {
53
53
  "node": ">=20.19.0"
54
54
  },
55
+ "peerDependencies": {
56
+ "@farmfe/core": ">=1",
57
+ "@nuxt/kit": "^3",
58
+ "@nuxt/schema": "^3",
59
+ "vite": ">=3",
60
+ "webpack": "^4 || ^5"
61
+ },
62
+ "peerDependenciesMeta": {
63
+ "@farmfe/core": {
64
+ "optional": true
65
+ },
66
+ "@nuxt/kit": {
67
+ "optional": true
68
+ },
69
+ "@nuxt/schema": {
70
+ "optional": true
71
+ },
72
+ "vite": {
73
+ "optional": true
74
+ },
75
+ "webpack": {
76
+ "optional": true
77
+ }
78
+ },
55
79
  "dependencies": {
56
80
  "unplugin": "^3.0.0"
57
81
  },
@@ -60,6 +84,7 @@
60
84
  "@types/ws": "^8.18.1",
61
85
  "birpc": "^4.0.0",
62
86
  "es-toolkit": "^1.44.0",
87
+ "get-port-please": "^3.2.0",
63
88
  "hookable": "^6.0.1",
64
89
  "mitt": "^3.0.1",
65
90
  "ws": "^8.19.0",
@@ -69,8 +94,8 @@
69
94
  "build": "tsdown",
70
95
  "dev": "tsdown --watch",
71
96
  "test": "vitest --run",
72
- "typecheck:client": "tsc --project tsconfig.client.json --noEmit",
73
- "typecheck:node": "tsc --noEmit",
97
+ "typecheck:client": "tsgo --project tsconfig.client.json --noEmit",
98
+ "typecheck:node": "tsgo --noEmit",
74
99
  "typecheck": "pnpm run typecheck:client && pnpm run typecheck:node"
75
100
  }
76
101
  }