@jonathanleelx/meddle 0.2.2 → 0.3.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 CHANGED
@@ -5,8 +5,37 @@
5
5
 
6
6
  ## 使用
7
7
 
8
+ ### 方式一:npm 安装
9
+
8
10
  全局安装 `npm install @jonathanleelx/meddle -g`,会创建一个 `meddle` 命令。
9
11
 
12
+ ### 方式二:二进制安装(无需 Node.js)
13
+
14
+ **macOS / Linux:**
15
+
16
+ ```bash
17
+ curl -fsSL https://raw.githubusercontent.com/JonathanLee-LX/meddle/main/scripts/install-binary.sh | bash
18
+ ```
19
+
20
+ **Windows (PowerShell):**
21
+
22
+ ```powershell
23
+ irm https://raw.githubusercontent.com/JonathanLee-LX/meddle/main/scripts/install-binary.ps1 | iex
24
+ ```
25
+
26
+ **支持平台:**
27
+
28
+ | 平台 | 产物 |
29
+ |---|---|
30
+ | Linux x64 | `meddle-linux-x64` |
31
+ | Linux ARM64 | `meddle-linux-arm64` |
32
+ | macOS Intel | `meddle-darwin-x64` |
33
+ | macOS Apple Silicon | `meddle-darwin-arm64` |
34
+ | Windows x64 | `meddle-windows-x64.exe` |
35
+ | Windows ARM64 | `meddle-windows-arm64.exe` |
36
+
37
+ 二进制产物随 [GitHub Release](https://github.com/JonathanLee-LX/meddle/releases) 发布,也可手动下载。安装目录默认 `~/.meddle/bin`,可通过 `MEDDLE_BIN_DIR` 环境变量自定义。
38
+
10
39
  ### 命令
11
40
 
12
41
  ```bash
@@ -30,6 +30,7 @@ const {
30
30
  } = require('../../lib/sessions')
31
31
  const { resolveMeddleHome } = require('../../lib/meddle-home')
32
32
  const { GLOBAL_DEFAULT_PORT } = require('../../lib/session-args')
33
+ const { buildProxySpawn, getReentryArgv } = require('../../lib/spawn-proxy')
33
34
 
34
35
  function parseArgs(argv) {
35
36
  const args = argv.slice(4) // after 'meddle' 'session' 'create'
@@ -88,24 +89,26 @@ async function main() {
88
89
  // via its existing startup logic. We only ensure the root exists.
89
90
 
90
91
  // 3. spawn child
91
- const indexPath = path.join(__dirname, '..', '..', '..', 'index.js')
92
- const childEnv = {
93
- ...process.env,
94
- MEDDLE_HOME: meddleHome,
95
- PORT: String(port),
96
- MEDDLE_SESSION_ID: id,
97
- // Suppress the CA trust prompt — sessions reuse the shared CA
98
- // from ~/.meddle/ca which the user already trusted when setting up
99
- // the default session. Also avoid interactive prompts blocking
100
- // a non-interactive agent spawn.
101
- MEDDLE_HEADLESS: '1',
102
- // Disable MCP file discovery for non-default sessions; the MCP
103
- // proxy-url file is only meaningful for the default session.
104
- MEDDLE_MCP: '',
105
- }
106
- const child = spawn(process.execPath, [indexPath], {
92
+ const { args: spawnArgs, options: spawnOptions } = buildProxySpawn({
93
+ baseEnv: process.env,
94
+ reentryArgv: getReentryArgv(),
95
+ extraEnv: {
96
+ MEDDLE_HOME: meddleHome,
97
+ PORT: String(port),
98
+ MEDDLE_SESSION_ID: id,
99
+ // Suppress the CA trust prompt — sessions reuse the shared CA
100
+ // from ~/.meddle/ca which the user already trusted when setting up
101
+ // the default session. Also avoid interactive prompts blocking
102
+ // a non-interactive agent spawn.
103
+ MEDDLE_HEADLESS: '1',
104
+ // Disable MCP file discovery for non-default sessions; the MCP
105
+ // proxy-url file is only meaningful for the default session.
106
+ MEDDLE_MCP: '',
107
+ },
108
+ })
109
+ const child = spawn(process.execPath, spawnArgs, {
107
110
  cwd: process.cwd(),
108
- env: childEnv,
111
+ env: spawnOptions.env,
109
112
  stdio: 'inherit',
110
113
  detached: false,
111
114
  })
@@ -3,7 +3,7 @@
3
3
  */
4
4
 
5
5
  const { spawn } = require('child_process')
6
- const path = require('path')
6
+ const { buildProxySpawn, getReentryArgv } = require('../lib/spawn-proxy')
7
7
 
8
8
  // Parse arguments
9
9
  const args = process.argv.slice(3)
@@ -13,24 +13,27 @@ const interceptHttpsFlag = args.includes('--intercept-https')
13
13
  const noInterceptHttpsFlag = args.includes('--no-intercept-https')
14
14
 
15
15
  // Start proxy
16
- const indexPath = path.join(__dirname, '..', 'index.js')
17
- const spawnEnv = { ...process.env, DEBUG: process.env.DEBUG || '' }
18
- if (openFlag) spawnEnv.MEDDLE_OPEN = '1'
19
- if (remoteFlag) spawnEnv.MEDDLE_REMOTE = '1'
20
- if (interceptHttpsFlag) spawnEnv.MEDDLE_INTERCEPT_HTTPS = '1'
21
- if (noInterceptHttpsFlag) spawnEnv.MEDDLE_INTERCEPT_HTTPS = '0'
16
+ const extraEnv = { DEBUG: process.env.DEBUG || '' }
17
+ if (openFlag) extraEnv.MEDDLE_OPEN = '1'
18
+ if (remoteFlag) extraEnv.MEDDLE_REMOTE = '1'
19
+ if (interceptHttpsFlag) extraEnv.MEDDLE_INTERCEPT_HTTPS = '1'
20
+ if (noInterceptHttpsFlag) extraEnv.MEDDLE_INTERCEPT_HTTPS = '0'
22
21
 
23
22
  const remoteTokenIndex = args.indexOf('--remote-token')
24
23
  if (remoteTokenIndex >= 0 && args[remoteTokenIndex + 1]) {
25
- spawnEnv.MEDDLE_REMOTE_TOKEN = args[remoteTokenIndex + 1]
24
+ extraEnv.MEDDLE_REMOTE_TOKEN = args[remoteTokenIndex + 1]
26
25
  }
27
26
  const inlineRemoteToken = args.find(arg => arg.startsWith('--remote-token='))
28
- if (inlineRemoteToken) spawnEnv.MEDDLE_REMOTE_TOKEN = inlineRemoteToken.slice('--remote-token='.length)
27
+ if (inlineRemoteToken) extraEnv.MEDDLE_REMOTE_TOKEN = inlineRemoteToken.slice('--remote-token='.length)
29
28
 
30
- const child = spawn(process.execPath, [indexPath], {
31
- env: spawnEnv,
32
- stdio: 'inherit',
33
- cwd: process.cwd()
29
+ const { args: spawnArgs, options: spawnOptions } = buildProxySpawn({
30
+ baseEnv: process.env,
31
+ reentryArgv: getReentryArgv(),
32
+ extraEnv,
33
+ })
34
+ const child = spawn(process.execPath, spawnArgs, {
35
+ ...spawnOptions,
36
+ cwd: process.cwd(),
34
37
  })
35
38
 
36
39
  child.on('error', (err) => {
@@ -6,6 +6,7 @@ const fs = require('fs')
6
6
  const path = require('path')
7
7
  const { spawn } = require('child_process')
8
8
  const { resolveMeddleHome } = require('../lib/meddle-home')
9
+ const { buildProxySpawn, buildCliSpawn, getReentryArgv } = require('../lib/spawn-proxy')
9
10
 
10
11
  const rawArgs = process.argv.slice(3)
11
12
  const daemonFlag = rawArgs.includes('--daemon')
@@ -20,9 +21,13 @@ if (daemonFlag) {
20
21
  }
21
22
 
22
23
  function supervise() {
23
- const indexPath = path.join(__dirname, '..', '..', 'index.js')
24
24
  const proxyArgs = stripSupervisorArgs(rawArgs)
25
- const childEnv = { ...process.env, DEBUG: process.env.DEBUG || '', MEDDLE_SUPERVISED: '1' }
25
+ const { args: spawnArgs, options: spawnOptions } = buildProxySpawn({
26
+ baseEnv: process.env,
27
+ reentryArgv: getReentryArgv(),
28
+ extraArgv: proxyArgs,
29
+ extraEnv: { DEBUG: process.env.DEBUG || '', MEDDLE_SUPERVISED: '1' },
30
+ })
26
31
 
27
32
  let child = null
28
33
  let stopping = false
@@ -37,9 +42,9 @@ function supervise() {
37
42
  process.on('SIGTERM', () => stop('SIGTERM'))
38
43
 
39
44
  const start = () => {
40
- child = spawn(process.execPath, [indexPath, ...proxyArgs], {
45
+ child = spawn(process.execPath, spawnArgs, {
41
46
  cwd: process.cwd(),
42
- env: childEnv,
47
+ env: spawnOptions.env,
43
48
  stdio: 'inherit',
44
49
  })
45
50
 
@@ -71,12 +76,16 @@ function startDaemon() {
71
76
  const meddleDir = resolveMeddleHome()
72
77
  fs.mkdirSync(meddleDir, { recursive: true })
73
78
  const logFd = fs.openSync(path.join(meddleDir, 'supervisor.log'), 'a')
74
- const binPath = path.join(__dirname, '..', 'index')
75
- const child = spawn(process.execPath, [binPath, 'supervise', ...args], {
79
+ const { args: spawnArgs, options: spawnOptions } = buildCliSpawn({
80
+ baseEnv: process.env,
81
+ reentryArgv: getReentryArgv(),
82
+ extraArgv: ['supervise', ...args],
83
+ })
84
+ const child = spawn(process.execPath, spawnArgs, {
76
85
  cwd: process.cwd(),
77
86
  detached: true,
78
87
  stdio: ['ignore', logFd, logFd],
79
- env: process.env,
88
+ env: spawnOptions.env,
80
89
  })
81
90
  child.unref()
82
91
  console.log(`Supervisor started: pid=${child.pid}, log=${path.join(meddleDir, 'supervisor.log')}`)
@@ -0,0 +1,34 @@
1
+ 'use strict'
2
+
3
+ // Single-entry env dispatch for the meddle binary.
4
+ // Pure function: no process.env / process.argv reads, no side effects.
5
+ // The binary entrypoint (bin/main.js) calls this with explicit values and then
6
+ // requires the matching module. Self-spawn children set MEDDLE_ENTRY=proxy|mcp|cli
7
+ // instead of passing a script path, so a deno-compiled binary (which has no
8
+ // index.js / mcp-server.js / bin/index.js as files on disk) can still route.
9
+
10
+ /** @typedef {'proxy' | 'mcp' | 'cli'} Entry */
11
+
12
+ const ALLOWED = ['proxy', 'mcp', 'cli']
13
+
14
+ /**
15
+ * @param {{ env: Record<string, string | undefined>, argv: string[] }} input
16
+ * @returns {{ entry: Entry, argv: string[] }}
17
+ */
18
+ function dispatch({ env, argv }) {
19
+ const raw = env && typeof env.MEDDLE_ENTRY === 'string' ? env.MEDDLE_ENTRY : ''
20
+ const normalized = raw.trim().toLowerCase()
21
+ let entry
22
+ if (normalized === '') {
23
+ entry = 'cli'
24
+ } else if (ALLOWED.includes(normalized)) {
25
+ entry = normalized
26
+ } else {
27
+ throw new Error(
28
+ `Unknown MEDDLE_ENTRY "${raw}". Allowed values: ${ALLOWED.join(', ')} (case-insensitive). Omit to default to 'cli'.`
29
+ )
30
+ }
31
+ return { entry, argv: Array.isArray(argv) ? argv.slice() : [] }
32
+ }
33
+
34
+ module.exports = { dispatch, ALLOWED }
@@ -0,0 +1,51 @@
1
+ 'use strict'
2
+
3
+ const path = require('path')
4
+
5
+ // Pure constructor for the meddle self-spawn contract, parameterised by runtime
6
+ // context (binary vs node). All six prod self-spawn sites (mcp-server x2, supervise
7
+ // x2, session/create, start) build their { args, options } through this so the
8
+ // contract lives in ONE place.
9
+ //
10
+ // Reentry model:
11
+ // binary (deno compile): process.execPath IS meddle, reads MEDDLE_ENTRY, dispatches.
12
+ // -> reentryArgv = [] (no script path)
13
+ // npm/node: process.execPath is plain `node`, needs a script path to bin/main.js,
14
+ // which then dispatches via MEDDLE_ENTRY.
15
+ // -> reentryArgv = [absPathToBinMainJs]
16
+ // Callers pass reentryArgv explicitly via getReentryArgv() so buildProxySpawn stays
17
+ // pure (no process reads) and unit-testable with injected reentryArgv.
18
+
19
+ let reentryOverride = null // test hook; undefined = detect from process
20
+
21
+ function getReentryArgv() {
22
+ if (reentryOverride !== null) return reentryOverride.slice()
23
+ // The deno-compiled meddle binary's execPath does NOT look like node, and it
24
+ // dispatches via MEDDLE_ENTRY itself, so no script path is needed. Plain `node`
25
+ // needs bin/main.js to re-enter the dispatcher.
26
+ const exe = (process.execPath || '').toLowerCase()
27
+ const looksLikeNode = /(^|[\\\/])node(\.exe)?$/i.test(exe) || /[\\\/]node-[0-9]/i.test(exe)
28
+ if (!looksLikeNode) return [] // the meddle binary
29
+ // node: re-enter via bin/main.js (this file's neighbour).
30
+ return [path.join(__dirname, '..', 'main.js')]
31
+ }
32
+
33
+ function buildSpawn({ baseEnv, extraEnv, extraArgv, entry, reentryArgv } = {}) {
34
+ const env = Object.assign({}, baseEnv || {}, extraEnv || {}, { MEDDLE_ENTRY: entry })
35
+ const reentry = Array.isArray(reentryArgv) ? reentryArgv : [] // default = binary form
36
+ const args = reentry.concat(Array.isArray(extraArgv) ? extraArgv : [])
37
+ return { args, options: { env, stdio: 'inherit' } }
38
+ }
39
+
40
+ function buildProxySpawn(opts = {}) {
41
+ return buildSpawn({ ...(opts || {}), entry: 'proxy' })
42
+ }
43
+
44
+ function buildCliSpawn(opts = {}) {
45
+ return buildSpawn({ ...(opts || {}), entry: 'cli' })
46
+ }
47
+
48
+ // Test-only hook; do not call from prod code.
49
+ function __setReentryOverrideForTest(v) { reentryOverride = v === undefined ? null : v }
50
+
51
+ module.exports = { buildProxySpawn, buildCliSpawn, getReentryArgv, __setReentryOverrideForTest }
package/bin/main.js ADDED
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env node
2
+ 'use strict'
3
+
4
+ // Single injectable entrypoint for the meddle binary.
5
+ // - deno compile target: `deno compile bin/main.js` injects this; routing is via
6
+ // MEDDLE_ENTRY (proxy|mcp|cli) since the compiled binary has no index.js /
7
+ // mcp-server.js / bin/index.js as files on disk.
8
+ // - node/npm path: `meddle` still resolves to bin/index.js (see package.json "bin");
9
+ // this file is only required when MEDDLE_ENTRY is set (self-spawn children) or
10
+ // when invoked explicitly (e.g. `node bin/main.js`).
11
+ //
12
+ // Existing entry files (bin/index.js, index.js, mcp-server.js) are left runnable
13
+ // directly under node — npm path has zero regression.
14
+
15
+ const { dispatch } = require('./lib/dispatch')
16
+
17
+ const { entry, argv } = dispatch({ env: process.env, argv: process.argv.slice(2) })
18
+
19
+ if (entry === 'proxy') {
20
+ // Proxy server. process.argv must look like `node index.js [opts]` for index.js
21
+ // semantics (it reads process.argv via helpers like getFreePort etc.), so we
22
+ // splice argv into process.argv. index.js itself ignores argv for routing but
23
+ // MEDDLE_* env is the real config channel, so argv here is informational.
24
+ process.argv = [process.argv[0], 'index.js', ...argv]
25
+ require('../index.js')
26
+ } else if (entry === 'mcp') {
27
+ process.argv = [process.argv[0], 'mcp-server.js', ...argv]
28
+ require('../mcp-server.js')
29
+ } else {
30
+ // cli: bin/index.js expects argv = process.argv.slice(2) (the user command +
31
+ // flags), and strips --session itself. Forward verbatim.
32
+ process.argv = [process.argv[0], 'bin/index.js', ...argv]
33
+ require('./index.js')
34
+ }
package/mcp-server.js CHANGED
@@ -16,6 +16,7 @@ const {
16
16
  deleteSession, isPidAlive, allocatePort, generateId, sessionDir, readRegistry
17
17
  } = require('./bin/lib/sessions')
18
18
  const { GLOBAL_DEFAULT_PORT } = require('./bin/lib/session-args')
19
+ const { buildProxySpawn, getReentryArgv } = require('./bin/lib/spawn-proxy')
19
20
 
20
21
  const meddleDir = resolveMeddleHome()
21
22
  const mcpFile = path.join(meddleDir, 'mcp-proxy-url.json')
@@ -208,12 +209,15 @@ mcpServer.registerTool('start_proxy', {
208
209
  }
209
210
  proxyProcess = null
210
211
  cachedProxyUrl = null
211
- const indexPath = path.join(__dirname, 'index.js')
212
- const spawnEnv = { ...process.env, MEDDLE_MCP: '1', DEBUG: process.env.DEBUG || '' }
213
- const child = spawn(process.execPath, [indexPath], {
214
- env: spawnEnv,
212
+ const { args, options } = buildProxySpawn({
213
+ baseEnv: process.env,
214
+ reentryArgv: getReentryArgv(),
215
+ extraEnv: { MEDDLE_MCP: '1', DEBUG: process.env.DEBUG || '' },
216
+ })
217
+ const child = spawn(process.execPath, args, {
218
+ ...options,
215
219
  stdio: ['ignore', 'pipe', 'pipe'],
216
- cwd: process.cwd()
220
+ cwd: process.cwd(),
217
221
  })
218
222
  proxyProcess = child
219
223
  child.stdout?.on('data', (d) => process.stderr.write(d))
@@ -278,17 +282,19 @@ mcpServer.registerTool('create_session', {
278
282
  fs.mkdirSync(sDir, { recursive: true })
279
283
 
280
284
  // 3. spawn child
281
- const indexPath = path.join(__dirname, 'index.js')
282
- const childEnv = {
283
- ...process.env,
284
- MEDDLE_HOME: sDir,
285
- PORT: String(targetPort),
286
- MEDDLE_SESSION_ID: id,
287
- MEDDLE_HEADLESS: '1',
288
- MEDDLE_MCP: '1',
289
- }
290
- const child = spawn(process.execPath, [indexPath], {
291
- env: childEnv,
285
+ const { args, options } = buildProxySpawn({
286
+ baseEnv: process.env,
287
+ reentryArgv: getReentryArgv(),
288
+ extraEnv: {
289
+ MEDDLE_HOME: sDir,
290
+ PORT: String(targetPort),
291
+ MEDDLE_SESSION_ID: id,
292
+ MEDDLE_HEADLESS: '1',
293
+ MEDDLE_MCP: '1',
294
+ },
295
+ })
296
+ const child = spawn(process.execPath, args, {
297
+ ...options,
292
298
  stdio: ['ignore', 'ignore', 'ignore'],
293
299
  cwd: process.cwd(),
294
300
  detached: false,
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "@jonathanleelx/meddle",
3
- "version": "0.2.2",
3
+ "version": "0.3.0",
4
4
  "description": "A simple development proxy server with custom routing rules, mock responses, HTTPS interception, and a plugin system",
5
+ "type": "commonjs",
5
6
  "main": "index.js",
6
7
  "scripts": {
7
8
  "build": "tsc",
@@ -71,7 +72,6 @@
71
72
  "chalk": "^4.1.2",
72
73
  "chokidar": "^3.6.0",
73
74
  "debug": "^4.4.3",
74
- "esbuild": "^0.27.7",
75
75
  "express": "^5.2.1",
76
76
  "inquirer": "^8.2.7",
77
77
  "node-easy-cert": "^1.3.3",
@@ -1,37 +0,0 @@
1
- /**
2
- * 插件编译器
3
- * 将TypeScript插件代码编译为JavaScript
4
- */
5
- export interface CompileResult {
6
- success: boolean;
7
- jsCode?: string;
8
- error?: string;
9
- sourceMap?: string;
10
- }
11
- /**
12
- * 编译TypeScript插件代码为JavaScript
13
- */
14
- export declare function compilePluginCode(tsCode: string, _filename?: string): Promise<CompileResult>;
15
- /**
16
- * 编译插件文件
17
- * 读取.ts文件,编译并保存为.js文件
18
- */
19
- export declare function compilePluginFile(tsFilePath: string): Promise<CompileResult>;
20
- /**
21
- * 批量编译插件目录中的所有.ts文件
22
- */
23
- export declare function compilePluginsDirectory(pluginsDir: string): Promise<{
24
- total: number;
25
- success: number;
26
- failed: number;
27
- errors: string[];
28
- }>;
29
- /**
30
- * 验证编译后的JavaScript代码
31
- * 检查是否包含必需的plugin导出
32
- */
33
- export declare function validateCompiledPlugin(jsCode: string): {
34
- valid: boolean;
35
- error?: string;
36
- };
37
- //# sourceMappingURL=plugin-compiler.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"plugin-compiler.d.ts","sourceRoot":"","sources":["../../core/plugin-compiler.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,MAAM,WAAW,aAAa;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CACnC,MAAM,EAAE,MAAM,EACd,SAAS,GAAE,MAAoB,GAChC,OAAO,CAAC,aAAa,CAAC,CAuBxB;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CACnC,UAAU,EAAE,MAAM,GACnB,OAAO,CAAC,aAAa,CAAC,CAiCxB;AAED;;GAEG;AACH,wBAAsB,uBAAuB,CACzC,UAAU,EAAE,MAAM,GACnB,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAmC/E;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAyBzF"}
@@ -1,172 +0,0 @@
1
- "use strict";
2
- /**
3
- * 插件编译器
4
- * 将TypeScript插件代码编译为JavaScript
5
- */
6
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
- if (k2 === undefined) k2 = k;
8
- var desc = Object.getOwnPropertyDescriptor(m, k);
9
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
- desc = { enumerable: true, get: function() { return m[k]; } };
11
- }
12
- Object.defineProperty(o, k2, desc);
13
- }) : (function(o, m, k, k2) {
14
- if (k2 === undefined) k2 = k;
15
- o[k2] = m[k];
16
- }));
17
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
- Object.defineProperty(o, "default", { enumerable: true, value: v });
19
- }) : function(o, v) {
20
- o["default"] = v;
21
- });
22
- var __importStar = (this && this.__importStar) || (function () {
23
- var ownKeys = function(o) {
24
- ownKeys = Object.getOwnPropertyNames || function (o) {
25
- var ar = [];
26
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
27
- return ar;
28
- };
29
- return ownKeys(o);
30
- };
31
- return function (mod) {
32
- if (mod && mod.__esModule) return mod;
33
- var result = {};
34
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
35
- __setModuleDefault(result, mod);
36
- return result;
37
- };
38
- })();
39
- Object.defineProperty(exports, "__esModule", { value: true });
40
- exports.compilePluginCode = compilePluginCode;
41
- exports.compilePluginFile = compilePluginFile;
42
- exports.compilePluginsDirectory = compilePluginsDirectory;
43
- exports.validateCompiledPlugin = validateCompiledPlugin;
44
- const esbuild = __importStar(require("esbuild"));
45
- const fs = __importStar(require("fs"));
46
- const path = __importStar(require("path"));
47
- /**
48
- * 编译TypeScript插件代码为JavaScript
49
- */
50
- async function compilePluginCode(tsCode, _filename = 'plugin.ts') {
51
- try {
52
- const result = await esbuild.transform(tsCode, {
53
- loader: 'ts',
54
- target: 'node18',
55
- format: 'cjs',
56
- platform: 'node',
57
- sourcemap: 'inline',
58
- minify: false,
59
- keepNames: true,
60
- });
61
- return {
62
- success: true,
63
- jsCode: result.code,
64
- sourceMap: result.map,
65
- };
66
- }
67
- catch (error) {
68
- return {
69
- success: false,
70
- error: error.message || '编译失败',
71
- };
72
- }
73
- }
74
- /**
75
- * 编译插件文件
76
- * 读取.ts文件,编译并保存为.js文件
77
- */
78
- async function compilePluginFile(tsFilePath) {
79
- try {
80
- // 读取TypeScript文件
81
- if (!fs.existsSync(tsFilePath)) {
82
- return {
83
- success: false,
84
- error: '文件不存在: ' + tsFilePath,
85
- };
86
- }
87
- const tsCode = fs.readFileSync(tsFilePath, 'utf8');
88
- // 编译
89
- const compileResult = await compilePluginCode(tsCode, path.basename(tsFilePath));
90
- if (!compileResult.success) {
91
- return compileResult;
92
- }
93
- // 保存编译后的JavaScript文件
94
- const jsFilePath = tsFilePath.replace(/\.ts$/, '.js');
95
- fs.writeFileSync(jsFilePath, compileResult.jsCode, 'utf8');
96
- return {
97
- success: true,
98
- jsCode: compileResult.jsCode,
99
- };
100
- }
101
- catch (error) {
102
- return {
103
- success: false,
104
- error: error.message || '编译文件失败',
105
- };
106
- }
107
- }
108
- /**
109
- * 批量编译插件目录中的所有.ts文件
110
- */
111
- async function compilePluginsDirectory(pluginsDir) {
112
- const result = {
113
- total: 0,
114
- success: 0,
115
- failed: 0,
116
- errors: [],
117
- };
118
- try {
119
- if (!fs.existsSync(pluginsDir)) {
120
- return result;
121
- }
122
- const files = fs.readdirSync(pluginsDir);
123
- const tsFiles = files.filter(file => file.endsWith('.ts'));
124
- result.total = tsFiles.length;
125
- for (const file of tsFiles) {
126
- const filePath = path.join(pluginsDir, file);
127
- const compileResult = await compilePluginFile(filePath);
128
- if (compileResult.success) {
129
- result.success++;
130
- }
131
- else {
132
- result.failed++;
133
- result.errors.push(`${file}: ${compileResult.error}`);
134
- }
135
- }
136
- return result;
137
- }
138
- catch (error) {
139
- result.errors.push('目录编译失败: ' + error.message);
140
- return result;
141
- }
142
- }
143
- /**
144
- * 验证编译后的JavaScript代码
145
- * 检查是否包含必需的plugin导出
146
- */
147
- function validateCompiledPlugin(jsCode) {
148
- try {
149
- // 检查是否包含exports.plugin或module.exports.plugin
150
- if (!jsCode.includes('exports.plugin') && !jsCode.includes('module.exports')) {
151
- return {
152
- valid: false,
153
- error: '编译后的代码没有导出plugin对象',
154
- };
155
- }
156
- // 检查是否包含manifest
157
- if (!jsCode.includes('manifest')) {
158
- return {
159
- valid: false,
160
- error: '编译后的代码缺少manifest定义',
161
- };
162
- }
163
- return { valid: true };
164
- }
165
- catch (error) {
166
- return {
167
- valid: false,
168
- error: error.message,
169
- };
170
- }
171
- }
172
- //# sourceMappingURL=plugin-compiler.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"plugin-compiler.js","sourceRoot":"","sources":["../../core/plugin-compiler.ts"],"names":[],"mappings":"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"}