├── .editorconfig ├── .gitattributes ├── .gitignore ├── .vscode ├── extensions.json └── settings.json ├── .yarn └── sdks │ ├── integrations.yml │ └── typescript │ ├── bin │ ├── tsc │ └── tsserver │ ├── lib │ ├── tsc.js │ ├── tsserver.js │ ├── tsserverlibrary.js │ └── typescript.js │ └── package.json ├── .yarnrc.yml ├── README.md ├── bundle.ts ├── dist ├── bundle.js └── nodeEntry.cjs ├── package.json ├── scripts └── python-script.py ├── src ├── impl │ └── runPythonScript.ts ├── index.ts ├── nodeEntry.ts └── nodes │ └── RunPythonScriptNode.ts ├── tsconfig.json └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | 7 | [*.{js,json,yml}] 8 | charset = utf-8 9 | indent_style = space 10 | indent_size = 2 11 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | /.yarn/** linguist-vendored 2 | /.yarn/releases/* binary 3 | /.yarn/plugins/**/* binary 4 | /.pnp.* binary linguist-generated 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .yarn/* 2 | !.yarn/patches 3 | !.yarn/plugins 4 | !.yarn/releases 5 | !.yarn/sdks 6 | !.yarn/versions 7 | 8 | # Swap the comments on the following lines if you don't wish to use zero-installs 9 | # Documentation here: https://yarnpkg.com/features/zero-installs 10 | # !.yarn/cache 11 | .pnp.* 12 | node_modules 13 | 14 | # src/**/*.js 15 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "arcanis.vscode-zipfs" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "search.exclude": { 3 | "**/.yarn": true, 4 | "**/.pnp.*": true 5 | }, 6 | "files.exclude": { 7 | "**/.git": true, 8 | "**/.svn": true, 9 | "**/.hg": true, 10 | "**/CVS": true, 11 | "**/.DS_Store": true, 12 | "**/Thumbs.db": true 13 | }, 14 | "typescript.tsdk": ".yarn/sdks/typescript/lib", 15 | "typescript.enablePromptUseWorkspaceTsdk": true, 16 | "[python]": { 17 | "editor.defaultFormatter": "ms-python.black-formatter" 18 | }, 19 | "python.formatting.provider": "none" 20 | } 21 | -------------------------------------------------------------------------------- /.yarn/sdks/integrations.yml: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by @yarnpkg/sdks. 2 | # Manual changes might be lost! 3 | 4 | integrations: 5 | - vscode 6 | -------------------------------------------------------------------------------- /.yarn/sdks/typescript/bin/tsc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const {existsSync} = require(`fs`); 4 | const {createRequire} = require(`module`); 5 | const {resolve} = require(`path`); 6 | 7 | const relPnpApiPath = "../../../../.pnp.cjs"; 8 | 9 | const absPnpApiPath = resolve(__dirname, relPnpApiPath); 10 | const absRequire = createRequire(absPnpApiPath); 11 | 12 | if (existsSync(absPnpApiPath)) { 13 | if (!process.versions.pnp) { 14 | // Setup the environment to be able to require typescript/bin/tsc 15 | require(absPnpApiPath).setup(); 16 | } 17 | } 18 | 19 | // Defer to the real typescript/bin/tsc your application uses 20 | module.exports = absRequire(`typescript/bin/tsc`); 21 | -------------------------------------------------------------------------------- /.yarn/sdks/typescript/bin/tsserver: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const {existsSync} = require(`fs`); 4 | const {createRequire} = require(`module`); 5 | const {resolve} = require(`path`); 6 | 7 | const relPnpApiPath = "../../../../.pnp.cjs"; 8 | 9 | const absPnpApiPath = resolve(__dirname, relPnpApiPath); 10 | const absRequire = createRequire(absPnpApiPath); 11 | 12 | if (existsSync(absPnpApiPath)) { 13 | if (!process.versions.pnp) { 14 | // Setup the environment to be able to require typescript/bin/tsserver 15 | require(absPnpApiPath).setup(); 16 | } 17 | } 18 | 19 | // Defer to the real typescript/bin/tsserver your application uses 20 | module.exports = absRequire(`typescript/bin/tsserver`); 21 | -------------------------------------------------------------------------------- /.yarn/sdks/typescript/lib/tsc.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const {existsSync} = require(`fs`); 4 | const {createRequire} = require(`module`); 5 | const {resolve} = require(`path`); 6 | 7 | const relPnpApiPath = "../../../../.pnp.cjs"; 8 | 9 | const absPnpApiPath = resolve(__dirname, relPnpApiPath); 10 | const absRequire = createRequire(absPnpApiPath); 11 | 12 | if (existsSync(absPnpApiPath)) { 13 | if (!process.versions.pnp) { 14 | // Setup the environment to be able to require typescript/lib/tsc.js 15 | require(absPnpApiPath).setup(); 16 | } 17 | } 18 | 19 | // Defer to the real typescript/lib/tsc.js your application uses 20 | module.exports = absRequire(`typescript/lib/tsc.js`); 21 | -------------------------------------------------------------------------------- /.yarn/sdks/typescript/lib/tsserver.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const {existsSync} = require(`fs`); 4 | const {createRequire} = require(`module`); 5 | const {resolve} = require(`path`); 6 | 7 | const relPnpApiPath = "../../../../.pnp.cjs"; 8 | 9 | const absPnpApiPath = resolve(__dirname, relPnpApiPath); 10 | const absRequire = createRequire(absPnpApiPath); 11 | 12 | const moduleWrapper = tsserver => { 13 | if (!process.versions.pnp) { 14 | return tsserver; 15 | } 16 | 17 | const {isAbsolute} = require(`path`); 18 | const pnpApi = require(`pnpapi`); 19 | 20 | const isVirtual = str => str.match(/\/(\$\$virtual|__virtual__)\//); 21 | const isPortal = str => str.startsWith("portal:/"); 22 | const normalize = str => str.replace(/\\/g, `/`).replace(/^\/?/, `/`); 23 | 24 | const dependencyTreeRoots = new Set(pnpApi.getDependencyTreeRoots().map(locator => { 25 | return `${locator.name}@${locator.reference}`; 26 | })); 27 | 28 | // VSCode sends the zip paths to TS using the "zip://" prefix, that TS 29 | // doesn't understand. This layer makes sure to remove the protocol 30 | // before forwarding it to TS, and to add it back on all returned paths. 31 | 32 | function toEditorPath(str) { 33 | // We add the `zip:` prefix to both `.zip/` paths and virtual paths 34 | if (isAbsolute(str) && !str.match(/^\^?(zip:|\/zip\/)/) && (str.match(/\.zip\//) || isVirtual(str))) { 35 | // We also take the opportunity to turn virtual paths into physical ones; 36 | // this makes it much easier to work with workspaces that list peer 37 | // dependencies, since otherwise Ctrl+Click would bring us to the virtual 38 | // file instances instead of the real ones. 39 | // 40 | // We only do this to modules owned by the the dependency tree roots. 41 | // This avoids breaking the resolution when jumping inside a vendor 42 | // with peer dep (otherwise jumping into react-dom would show resolution 43 | // errors on react). 44 | // 45 | const resolved = isVirtual(str) ? pnpApi.resolveVirtual(str) : str; 46 | if (resolved) { 47 | const locator = pnpApi.findPackageLocator(resolved); 48 | if (locator && (dependencyTreeRoots.has(`${locator.name}@${locator.reference}`) || isPortal(locator.reference))) { 49 | str = resolved; 50 | } 51 | } 52 | 53 | str = normalize(str); 54 | 55 | if (str.match(/\.zip\//)) { 56 | switch (hostInfo) { 57 | // Absolute VSCode `Uri.fsPath`s need to start with a slash. 58 | // VSCode only adds it automatically for supported schemes, 59 | // so we have to do it manually for the `zip` scheme. 60 | // The path needs to start with a caret otherwise VSCode doesn't handle the protocol 61 | // 62 | // Ref: https://github.com/microsoft/vscode/issues/105014#issuecomment-686760910 63 | // 64 | // 2021-10-08: VSCode changed the format in 1.61. 65 | // Before | ^zip:/c:/foo/bar.zip/package.json 66 | // After | ^/zip//c:/foo/bar.zip/package.json 67 | // 68 | // 2022-04-06: VSCode changed the format in 1.66. 69 | // Before | ^/zip//c:/foo/bar.zip/package.json 70 | // After | ^/zip/c:/foo/bar.zip/package.json 71 | // 72 | // 2022-05-06: VSCode changed the format in 1.68 73 | // Before | ^/zip/c:/foo/bar.zip/package.json 74 | // After | ^/zip//c:/foo/bar.zip/package.json 75 | // 76 | case `vscode <1.61`: { 77 | str = `^zip:${str}`; 78 | } break; 79 | 80 | case `vscode <1.66`: { 81 | str = `^/zip/${str}`; 82 | } break; 83 | 84 | case `vscode <1.68`: { 85 | str = `^/zip${str}`; 86 | } break; 87 | 88 | case `vscode`: { 89 | str = `^/zip/${str}`; 90 | } break; 91 | 92 | // To make "go to definition" work, 93 | // We have to resolve the actual file system path from virtual path 94 | // and convert scheme to supported by [vim-rzip](https://github.com/lbrayner/vim-rzip) 95 | case `coc-nvim`: { 96 | str = normalize(resolved).replace(/\.zip\//, `.zip::`); 97 | str = resolve(`zipfile:${str}`); 98 | } break; 99 | 100 | // Support neovim native LSP and [typescript-language-server](https://github.com/theia-ide/typescript-language-server) 101 | // We have to resolve the actual file system path from virtual path, 102 | // everything else is up to neovim 103 | case `neovim`: { 104 | str = normalize(resolved).replace(/\.zip\//, `.zip::`); 105 | str = `zipfile://${str}`; 106 | } break; 107 | 108 | default: { 109 | str = `zip:${str}`; 110 | } break; 111 | } 112 | } else { 113 | str = str.replace(/^\/?/, process.platform === `win32` ? `` : `/`); 114 | } 115 | } 116 | 117 | return str; 118 | } 119 | 120 | function fromEditorPath(str) { 121 | switch (hostInfo) { 122 | case `coc-nvim`: { 123 | str = str.replace(/\.zip::/, `.zip/`); 124 | // The path for coc-nvim is in format of //zipfile://.yarn/... 125 | // So in order to convert it back, we use .* to match all the thing 126 | // before `zipfile:` 127 | return process.platform === `win32` 128 | ? str.replace(/^.*zipfile:\//, ``) 129 | : str.replace(/^.*zipfile:/, ``); 130 | } break; 131 | 132 | case `neovim`: { 133 | str = str.replace(/\.zip::/, `.zip/`); 134 | // The path for neovim is in format of zipfile:////.yarn/... 135 | return str.replace(/^zipfile:\/\//, ``); 136 | } break; 137 | 138 | case `vscode`: 139 | default: { 140 | return str.replace(/^\^?(zip:|\/zip(\/ts-nul-authority)?)\/+/, process.platform === `win32` ? `` : `/`) 141 | } break; 142 | } 143 | } 144 | 145 | // Force enable 'allowLocalPluginLoads' 146 | // TypeScript tries to resolve plugins using a path relative to itself 147 | // which doesn't work when using the global cache 148 | // https://github.com/microsoft/TypeScript/blob/1b57a0395e0bff191581c9606aab92832001de62/src/server/project.ts#L2238 149 | // VSCode doesn't want to enable 'allowLocalPluginLoads' due to security concerns but 150 | // TypeScript already does local loads and if this code is running the user trusts the workspace 151 | // https://github.com/microsoft/vscode/issues/45856 152 | const ConfiguredProject = tsserver.server.ConfiguredProject; 153 | const {enablePluginsWithOptions: originalEnablePluginsWithOptions} = ConfiguredProject.prototype; 154 | ConfiguredProject.prototype.enablePluginsWithOptions = function() { 155 | this.projectService.allowLocalPluginLoads = true; 156 | return originalEnablePluginsWithOptions.apply(this, arguments); 157 | }; 158 | 159 | // And here is the point where we hijack the VSCode <-> TS communications 160 | // by adding ourselves in the middle. We locate everything that looks 161 | // like an absolute path of ours and normalize it. 162 | 163 | const Session = tsserver.server.Session; 164 | const {onMessage: originalOnMessage, send: originalSend} = Session.prototype; 165 | let hostInfo = `unknown`; 166 | 167 | Object.assign(Session.prototype, { 168 | onMessage(/** @type {string | object} */ message) { 169 | const isStringMessage = typeof message === 'string'; 170 | const parsedMessage = isStringMessage ? JSON.parse(message) : message; 171 | 172 | if ( 173 | parsedMessage != null && 174 | typeof parsedMessage === `object` && 175 | parsedMessage.arguments && 176 | typeof parsedMessage.arguments.hostInfo === `string` 177 | ) { 178 | hostInfo = parsedMessage.arguments.hostInfo; 179 | if (hostInfo === `vscode` && process.env.VSCODE_IPC_HOOK) { 180 | const [, major, minor] = (process.env.VSCODE_IPC_HOOK.match( 181 | // The RegExp from https://semver.org/ but without the caret at the start 182 | /(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/ 183 | ) ?? []).map(Number) 184 | 185 | if (major === 1) { 186 | if (minor < 61) { 187 | hostInfo += ` <1.61`; 188 | } else if (minor < 66) { 189 | hostInfo += ` <1.66`; 190 | } else if (minor < 68) { 191 | hostInfo += ` <1.68`; 192 | } 193 | } 194 | } 195 | } 196 | 197 | const processedMessageJSON = JSON.stringify(parsedMessage, (key, value) => { 198 | return typeof value === 'string' ? fromEditorPath(value) : value; 199 | }); 200 | 201 | return originalOnMessage.call( 202 | this, 203 | isStringMessage ? processedMessageJSON : JSON.parse(processedMessageJSON) 204 | ); 205 | }, 206 | 207 | send(/** @type {any} */ msg) { 208 | return originalSend.call(this, JSON.parse(JSON.stringify(msg, (key, value) => { 209 | return typeof value === `string` ? toEditorPath(value) : value; 210 | }))); 211 | } 212 | }); 213 | 214 | return tsserver; 215 | }; 216 | 217 | if (existsSync(absPnpApiPath)) { 218 | if (!process.versions.pnp) { 219 | // Setup the environment to be able to require typescript/lib/tsserver.js 220 | require(absPnpApiPath).setup(); 221 | } 222 | } 223 | 224 | // Defer to the real typescript/lib/tsserver.js your application uses 225 | module.exports = moduleWrapper(absRequire(`typescript/lib/tsserver.js`)); 226 | -------------------------------------------------------------------------------- /.yarn/sdks/typescript/lib/tsserverlibrary.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const {existsSync} = require(`fs`); 4 | const {createRequire} = require(`module`); 5 | const {resolve} = require(`path`); 6 | 7 | const relPnpApiPath = "../../../../.pnp.cjs"; 8 | 9 | const absPnpApiPath = resolve(__dirname, relPnpApiPath); 10 | const absRequire = createRequire(absPnpApiPath); 11 | 12 | const moduleWrapper = tsserver => { 13 | if (!process.versions.pnp) { 14 | return tsserver; 15 | } 16 | 17 | const {isAbsolute} = require(`path`); 18 | const pnpApi = require(`pnpapi`); 19 | 20 | const isVirtual = str => str.match(/\/(\$\$virtual|__virtual__)\//); 21 | const isPortal = str => str.startsWith("portal:/"); 22 | const normalize = str => str.replace(/\\/g, `/`).replace(/^\/?/, `/`); 23 | 24 | const dependencyTreeRoots = new Set(pnpApi.getDependencyTreeRoots().map(locator => { 25 | return `${locator.name}@${locator.reference}`; 26 | })); 27 | 28 | // VSCode sends the zip paths to TS using the "zip://" prefix, that TS 29 | // doesn't understand. This layer makes sure to remove the protocol 30 | // before forwarding it to TS, and to add it back on all returned paths. 31 | 32 | function toEditorPath(str) { 33 | // We add the `zip:` prefix to both `.zip/` paths and virtual paths 34 | if (isAbsolute(str) && !str.match(/^\^?(zip:|\/zip\/)/) && (str.match(/\.zip\//) || isVirtual(str))) { 35 | // We also take the opportunity to turn virtual paths into physical ones; 36 | // this makes it much easier to work with workspaces that list peer 37 | // dependencies, since otherwise Ctrl+Click would bring us to the virtual 38 | // file instances instead of the real ones. 39 | // 40 | // We only do this to modules owned by the the dependency tree roots. 41 | // This avoids breaking the resolution when jumping inside a vendor 42 | // with peer dep (otherwise jumping into react-dom would show resolution 43 | // errors on react). 44 | // 45 | const resolved = isVirtual(str) ? pnpApi.resolveVirtual(str) : str; 46 | if (resolved) { 47 | const locator = pnpApi.findPackageLocator(resolved); 48 | if (locator && (dependencyTreeRoots.has(`${locator.name}@${locator.reference}`) || isPortal(locator.reference))) { 49 | str = resolved; 50 | } 51 | } 52 | 53 | str = normalize(str); 54 | 55 | if (str.match(/\.zip\//)) { 56 | switch (hostInfo) { 57 | // Absolute VSCode `Uri.fsPath`s need to start with a slash. 58 | // VSCode only adds it automatically for supported schemes, 59 | // so we have to do it manually for the `zip` scheme. 60 | // The path needs to start with a caret otherwise VSCode doesn't handle the protocol 61 | // 62 | // Ref: https://github.com/microsoft/vscode/issues/105014#issuecomment-686760910 63 | // 64 | // 2021-10-08: VSCode changed the format in 1.61. 65 | // Before | ^zip:/c:/foo/bar.zip/package.json 66 | // After | ^/zip//c:/foo/bar.zip/package.json 67 | // 68 | // 2022-04-06: VSCode changed the format in 1.66. 69 | // Before | ^/zip//c:/foo/bar.zip/package.json 70 | // After | ^/zip/c:/foo/bar.zip/package.json 71 | // 72 | // 2022-05-06: VSCode changed the format in 1.68 73 | // Before | ^/zip/c:/foo/bar.zip/package.json 74 | // After | ^/zip//c:/foo/bar.zip/package.json 75 | // 76 | case `vscode <1.61`: { 77 | str = `^zip:${str}`; 78 | } break; 79 | 80 | case `vscode <1.66`: { 81 | str = `^/zip/${str}`; 82 | } break; 83 | 84 | case `vscode <1.68`: { 85 | str = `^/zip${str}`; 86 | } break; 87 | 88 | case `vscode`: { 89 | str = `^/zip/${str}`; 90 | } break; 91 | 92 | // To make "go to definition" work, 93 | // We have to resolve the actual file system path from virtual path 94 | // and convert scheme to supported by [vim-rzip](https://github.com/lbrayner/vim-rzip) 95 | case `coc-nvim`: { 96 | str = normalize(resolved).replace(/\.zip\//, `.zip::`); 97 | str = resolve(`zipfile:${str}`); 98 | } break; 99 | 100 | // Support neovim native LSP and [typescript-language-server](https://github.com/theia-ide/typescript-language-server) 101 | // We have to resolve the actual file system path from virtual path, 102 | // everything else is up to neovim 103 | case `neovim`: { 104 | str = normalize(resolved).replace(/\.zip\//, `.zip::`); 105 | str = `zipfile://${str}`; 106 | } break; 107 | 108 | default: { 109 | str = `zip:${str}`; 110 | } break; 111 | } 112 | } else { 113 | str = str.replace(/^\/?/, process.platform === `win32` ? `` : `/`); 114 | } 115 | } 116 | 117 | return str; 118 | } 119 | 120 | function fromEditorPath(str) { 121 | switch (hostInfo) { 122 | case `coc-nvim`: { 123 | str = str.replace(/\.zip::/, `.zip/`); 124 | // The path for coc-nvim is in format of //zipfile://.yarn/... 125 | // So in order to convert it back, we use .* to match all the thing 126 | // before `zipfile:` 127 | return process.platform === `win32` 128 | ? str.replace(/^.*zipfile:\//, ``) 129 | : str.replace(/^.*zipfile:/, ``); 130 | } break; 131 | 132 | case `neovim`: { 133 | str = str.replace(/\.zip::/, `.zip/`); 134 | // The path for neovim is in format of zipfile:////.yarn/... 135 | return str.replace(/^zipfile:\/\//, ``); 136 | } break; 137 | 138 | case `vscode`: 139 | default: { 140 | return str.replace(/^\^?(zip:|\/zip(\/ts-nul-authority)?)\/+/, process.platform === `win32` ? `` : `/`) 141 | } break; 142 | } 143 | } 144 | 145 | // Force enable 'allowLocalPluginLoads' 146 | // TypeScript tries to resolve plugins using a path relative to itself 147 | // which doesn't work when using the global cache 148 | // https://github.com/microsoft/TypeScript/blob/1b57a0395e0bff191581c9606aab92832001de62/src/server/project.ts#L2238 149 | // VSCode doesn't want to enable 'allowLocalPluginLoads' due to security concerns but 150 | // TypeScript already does local loads and if this code is running the user trusts the workspace 151 | // https://github.com/microsoft/vscode/issues/45856 152 | const ConfiguredProject = tsserver.server.ConfiguredProject; 153 | const {enablePluginsWithOptions: originalEnablePluginsWithOptions} = ConfiguredProject.prototype; 154 | ConfiguredProject.prototype.enablePluginsWithOptions = function() { 155 | this.projectService.allowLocalPluginLoads = true; 156 | return originalEnablePluginsWithOptions.apply(this, arguments); 157 | }; 158 | 159 | // And here is the point where we hijack the VSCode <-> TS communications 160 | // by adding ourselves in the middle. We locate everything that looks 161 | // like an absolute path of ours and normalize it. 162 | 163 | const Session = tsserver.server.Session; 164 | const {onMessage: originalOnMessage, send: originalSend} = Session.prototype; 165 | let hostInfo = `unknown`; 166 | 167 | Object.assign(Session.prototype, { 168 | onMessage(/** @type {string | object} */ message) { 169 | const isStringMessage = typeof message === 'string'; 170 | const parsedMessage = isStringMessage ? JSON.parse(message) : message; 171 | 172 | if ( 173 | parsedMessage != null && 174 | typeof parsedMessage === `object` && 175 | parsedMessage.arguments && 176 | typeof parsedMessage.arguments.hostInfo === `string` 177 | ) { 178 | hostInfo = parsedMessage.arguments.hostInfo; 179 | if (hostInfo === `vscode` && process.env.VSCODE_IPC_HOOK) { 180 | const [, major, minor] = (process.env.VSCODE_IPC_HOOK.match( 181 | // The RegExp from https://semver.org/ but without the caret at the start 182 | /(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/ 183 | ) ?? []).map(Number) 184 | 185 | if (major === 1) { 186 | if (minor < 61) { 187 | hostInfo += ` <1.61`; 188 | } else if (minor < 66) { 189 | hostInfo += ` <1.66`; 190 | } else if (minor < 68) { 191 | hostInfo += ` <1.68`; 192 | } 193 | } 194 | } 195 | } 196 | 197 | const processedMessageJSON = JSON.stringify(parsedMessage, (key, value) => { 198 | return typeof value === 'string' ? fromEditorPath(value) : value; 199 | }); 200 | 201 | return originalOnMessage.call( 202 | this, 203 | isStringMessage ? processedMessageJSON : JSON.parse(processedMessageJSON) 204 | ); 205 | }, 206 | 207 | send(/** @type {any} */ msg) { 208 | return originalSend.call(this, JSON.parse(JSON.stringify(msg, (key, value) => { 209 | return typeof value === `string` ? toEditorPath(value) : value; 210 | }))); 211 | } 212 | }); 213 | 214 | return tsserver; 215 | }; 216 | 217 | if (existsSync(absPnpApiPath)) { 218 | if (!process.versions.pnp) { 219 | // Setup the environment to be able to require typescript/lib/tsserverlibrary.js 220 | require(absPnpApiPath).setup(); 221 | } 222 | } 223 | 224 | // Defer to the real typescript/lib/tsserverlibrary.js your application uses 225 | module.exports = moduleWrapper(absRequire(`typescript/lib/tsserverlibrary.js`)); 226 | -------------------------------------------------------------------------------- /.yarn/sdks/typescript/lib/typescript.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const {existsSync} = require(`fs`); 4 | const {createRequire} = require(`module`); 5 | const {resolve} = require(`path`); 6 | 7 | const relPnpApiPath = "../../../../.pnp.cjs"; 8 | 9 | const absPnpApiPath = resolve(__dirname, relPnpApiPath); 10 | const absRequire = createRequire(absPnpApiPath); 11 | 12 | if (existsSync(absPnpApiPath)) { 13 | if (!process.versions.pnp) { 14 | // Setup the environment to be able to require typescript/lib/typescript.js 15 | require(absPnpApiPath).setup(); 16 | } 17 | } 18 | 19 | // Defer to the real typescript/lib/typescript.js your application uses 20 | module.exports = absRequire(`typescript/lib/typescript.js`); 21 | -------------------------------------------------------------------------------- /.yarn/sdks/typescript/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "typescript", 3 | "version": "5.2.2-sdk", 4 | "main": "./lib/typescript.js", 5 | "type": "commonjs" 6 | } 7 | -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | nodeLinker: node-modules 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

Rivet Logo

2 | 3 | # Rivet Example Plugin - Python Execution 4 | 5 | This project is an example of a [Rivet](https://github.com/Ironclad/rivet) plugin that allows you to execute Python code in a Rivet node. 6 | 7 | - [Using the plugin](#using-the-plugin) 8 | - [In Rivet](#in-rivet) 9 | - [In Code](#in-code) 10 | - [Making your own plugin](#making-your-own-plugin) 11 | - [⚠️ Important Notes ⚠️](#️-important-notes-️) 12 | - [1. Plugin Definition](#1-plugin-definition) 13 | - [2. Node Definitions](#2-node-definitions) 14 | - [3. Bundling](#3-bundling) 15 | - [5. Serving your plugin](#5-serving-your-plugin) 16 | - [Local Development](#local-development) 17 | 18 | ## Using the plugin 19 | 20 | ### In Rivet 21 | 22 | To use this plugin in Rivet: 23 | 24 | 1. Navigate to the Project tab in the left sidebar. You will see a + button next to `Plugins`, 25 | click it to open the Add Plugin modal. 26 | 2. In Add NPM Plugin, enter `rivet-plugin-example-python-exec` and click `Add NPM Plugin`. 27 | 3. The example plugin is now installed in your project. You can add the Run Python Script using the Add Node menu, in the "Example" group.. 28 | 29 | ### In Code 30 | 31 | Load your plugin and Rivet into your application: 32 | 33 | ```ts 34 | import * as Rivet from "@ironclad/rivet-core"; 35 | import examplePlugin from "rivet-plugin-example-python-exec"; 36 | ``` 37 | 38 | Register your plugin with Rivet be using the `globalRivetNodeRegistry` or creating a new `NodeRegistration` and registering with that: 39 | 40 | ```ts 41 | Rivet.globalRivetNodeRegistry.registerPlugin(examplePlugin(Rivet)); 42 | ``` 43 | 44 | ## Making your own plugin 45 | 46 | ### ⚠️ Important Notes ⚠️ 47 | 48 | - You must bundle your plugins, or include all code for your plugin in the ESM files. Plugins are loaded using `import(pluginUrl)` so must follow all rules for ESM modules. This means that you cannot use `require` or `module.exports` in your plugin code. If you need to use external libraries, you must bundle them. 49 | 50 | - You also cannot import nor bundle `@ironclad/rivet-core` in your plugin. The rivet core library is passed into your default export function as an argument. Be careful to only use `import type` statements for the core library, otherwise your plugin will not bundle successfully. 51 | 52 | - This repo is also an example of a Node.js-only plugin. It is important that Node-only plugins are separated into two separate bundles - an isomorphic bundle that defines the plugin and all of the nodes, and a Node-only bundle that contains the node-only implementations. The isomorphic bundle is allowed to _dynamically_ import the node bundle, but cannot statically import it (except for types, of course). 53 | 54 | - **Currently, all node.js dependencies must be bundled into the node entry point, as node_modules is not installed for Rivet.** 55 | 56 | This repository has examples for both dual-bundling with [ESBuild](https://esbuild.github.io/), only importing types from `@ironclad/rivet-core`, and using `import()` to dynamically import the node bundle from the isomorphic bundle. 57 | 58 | ### 1. Plugin Definition 59 | 60 | Follow the example in [src/index.ts](src/index.ts) to define your plugin. Your plugin must default-export a function that takes in the Rivet Core library as its only argument, and returns a valid `RivetPlugin` object. 61 | 62 | ### 2. Node Definitions 63 | 64 | Follow the example in [src/nodes/ExamplePluginNode.ts](src/nodes/ExamplePluginNode.ts) to define your plugin's nodes. You should follow a simlar syntax of exporting functions that take in the Rivet Core library. 65 | 66 | - Nodes must implement `PluginNodeDefinition` by calling `pluginNodeDefinition(yourPluginImpl, "Node Name")`. 67 | - Node implementations must implement `PluginNodeImpl`. 68 | - `T` should be your plugin's type definition. 69 | 70 | ### 3. Bundling 71 | 72 | See [bundle.ts](bundle.ts) for an example of how to bundle your plugin. You can use any bundler you like, but you must bundle into two final files - an isomorphic bundle, and a node.js only bundle. You can use the [ESBuild](https://esbuild.github.io/) bundler to bundle your plugin into a single file. 73 | 74 | It is important that all external libraries are bundled in the _isomorphic bundle_, because browsers cannot load bare imports. However, you are allowed to 75 | import any external libraries in the _node bundle_. Note that as of now, dependencies of a bundle are not loaded. This means that node_modules dependencies must be bundled into the final bundle. 76 | 77 | ### 5. Serving your plugin 78 | 79 | You should then publish your plugin to NPM. The bundled files should be included, and the `"main"` field in your `package.json` should point to the isomorphic bundle. 80 | 81 | ## Local Development 82 | 83 | 1. Run `yarn dev` to start the compiler and bundler in watch mode. This will automatically recombine and rebundle your changes into the `dist` folder. This will also copy the bundled files into the plugin install directory. 84 | 2. After each change, you must restart Rivet to see the changes. 85 | -------------------------------------------------------------------------------- /bundle.ts: -------------------------------------------------------------------------------- 1 | import * as esbuild from "esbuild"; 2 | import { match } from "ts-pattern"; 3 | import { join, dirname } from "node:path"; 4 | import copy from "recursive-copy"; 5 | import { platform, homedir } from "node:os"; 6 | import { readFile, rm, mkdir, copyFile } from "node:fs/promises"; 7 | import { fileURLToPath } from "node:url"; 8 | 9 | const __dirname = dirname(fileURLToPath(import.meta.url)); 10 | 11 | // Roughly https://github.com/demurgos/appdata-path/blob/master/lib/index.js but appdata local and .local/share, try to match `dirs` from rust 12 | function getAppDataLocalPath() { 13 | const identifier = "com.ironcladapp.rivet"; 14 | return match(platform()) 15 | .with("win32", () => join(homedir(), "AppData", "Local", identifier)) 16 | .with("darwin", () => 17 | join(homedir(), "Library", "Application Support", identifier) 18 | ) 19 | .with("linux", () => join(homedir(), ".local", "share", identifier)) 20 | .otherwise(() => { 21 | if (platform().startsWith("win")) { 22 | return join(homedir(), "AppData", "Local", identifier); 23 | } else { 24 | return join(homedir(), ".local", "share", identifier); 25 | } 26 | }); 27 | } 28 | 29 | const syncPlugin: esbuild.Plugin = { 30 | name: "onBuild", 31 | setup(build) { 32 | build.onEnd(async () => { 33 | const packageJson = JSON.parse( 34 | await readFile(join(__dirname, "package.json"), "utf-8") 35 | ); 36 | const pluginName = packageJson.name; 37 | 38 | const rivetPluginsDirectory = join(getAppDataLocalPath(), "plugins"); 39 | const thisPluginDirectory = join( 40 | rivetPluginsDirectory, 41 | `${pluginName}-latest` 42 | ); 43 | 44 | await rm(join(thisPluginDirectory, "package"), { 45 | recursive: true, 46 | force: true, 47 | }); 48 | await mkdir(join(thisPluginDirectory, "package"), { recursive: true }); 49 | 50 | await copy( 51 | join(__dirname, "dist"), 52 | join(thisPluginDirectory, "package", "dist") 53 | ); 54 | await copyFile( 55 | join(__dirname, "package.json"), 56 | join(thisPluginDirectory, "package", "package.json") 57 | ); 58 | 59 | // Copy .git to mark as locally installed plugin 60 | await copy( 61 | join(__dirname, ".git"), 62 | join(thisPluginDirectory, "package", ".git") 63 | ); 64 | 65 | console.log( 66 | `Synced ${pluginName} to Rivet at ${thisPluginDirectory}. Refresh or restart Rivet to see changes.` 67 | ); 68 | }); 69 | }, 70 | }; 71 | 72 | // The isomorphic dynamically imports the node entry point, so we need to rewrite the import to point to the 73 | // bundled node entry point instead of the original place it was. 74 | const rewriteNodeEntryPlugin: esbuild.Plugin = { 75 | name: "rewrite-node-entry", 76 | setup(build) { 77 | build.onResolve({ filter: /\/nodeEntry$/ }, (args) => { 78 | return { 79 | external: true, 80 | path: "../dist/nodeEntry.cjs", 81 | }; 82 | }); 83 | }, 84 | }; 85 | 86 | const isomorphicBundleOptions: esbuild.BuildOptions = { 87 | entryPoints: ["src/index.ts"], 88 | bundle: true, 89 | platform: "neutral", 90 | target: "es2020", 91 | outfile: "dist/bundle.js", 92 | format: "esm", 93 | external: ["./src/nodeEntry"], 94 | plugins: [rewriteNodeEntryPlugin], 95 | }; 96 | 97 | const nodeBundleOptions = { 98 | entryPoints: ["src/nodeEntry.ts"], 99 | bundle: true, 100 | platform: "node", 101 | target: "es2020", 102 | outfile: "dist/nodeEntry.cjs", 103 | format: "cjs", 104 | plugins: [] as esbuild.Plugin[], 105 | } satisfies esbuild.BuildOptions; 106 | 107 | // TODO will node bundle always run after isomorphic bundle, or is there a race condition? 108 | if (process.argv.includes("--sync")) { 109 | nodeBundleOptions.plugins.push(syncPlugin); 110 | } 111 | 112 | if (process.argv.includes("--watch")) { 113 | const isoContext = await esbuild.context(isomorphicBundleOptions); 114 | await isoContext.watch(); 115 | 116 | const nodeContext = await esbuild.context(nodeBundleOptions); 117 | await nodeContext.watch(); 118 | 119 | console.log("Watching for changes..."); 120 | } else { 121 | await esbuild.build(isomorphicBundleOptions); 122 | await esbuild.build(nodeBundleOptions); 123 | } 124 | -------------------------------------------------------------------------------- /dist/bundle.js: -------------------------------------------------------------------------------- 1 | // src/nodes/RunPythonScriptNode.ts 2 | function RunPythonScriptNode_default(rivet) { 3 | const nodeImpl = { 4 | // This should create a new instance of your node type from scratch. 5 | create() { 6 | const node = { 7 | // Use rivet.newId to generate new IDs for your nodes. 8 | id: rivet.newId(), 9 | // This is the default data that your node will store 10 | data: { 11 | scriptPath: "", 12 | arguments: "" 13 | }, 14 | // This is the default title of your node. 15 | title: "Run Python Script", 16 | // This must match the type of your node. 17 | type: "runPythonScript", 18 | // X and Y should be set to 0. Width should be set to a reasonable number so there is no overflow. 19 | visualData: { 20 | x: 0, 21 | y: 0, 22 | width: 200 23 | } 24 | }; 25 | return node; 26 | }, 27 | // This function should return all input ports for your node, given its data, connections, all other nodes, and the project. The 28 | // connection, nodes, and project are for advanced use-cases and can usually be ignored. 29 | getInputDefinitions(data, _connections, _nodes, _project) { 30 | const inputs = []; 31 | if (data.useScriptPathInput) { 32 | inputs.push({ 33 | id: "scriptPath", 34 | dataType: "string", 35 | title: "Script Path" 36 | }); 37 | } 38 | if (data.useArgumentsInput) { 39 | inputs.push({ 40 | id: "arguments", 41 | dataType: "string[]", 42 | title: "Arguments" 43 | }); 44 | } 45 | return inputs; 46 | }, 47 | // This function should return all output ports for your node, given its data, connections, all other nodes, and the project. The 48 | // connection, nodes, and project are for advanced use-cases and can usually be ignored. 49 | getOutputDefinitions(_data, _connections, _nodes, _project) { 50 | return [ 51 | { 52 | id: "output", 53 | dataType: "string", 54 | title: "Output" 55 | } 56 | ]; 57 | }, 58 | // This returns UI information for your node, such as how it appears in the context menu. 59 | getUIData() { 60 | return { 61 | contextMenuTitle: "Run Python Script", 62 | group: "Example", 63 | infoBoxBody: "This is an example of running a python script using a rivet node.", 64 | infoBoxTitle: "Run Python Script Node" 65 | }; 66 | }, 67 | // This function defines all editors that appear when you edit your node. 68 | getEditors(_data) { 69 | return [ 70 | { 71 | type: "string", 72 | dataKey: "scriptPath", 73 | useInputToggleDataKey: "useScriptPathInput", 74 | label: "Script Path" 75 | }, 76 | { 77 | type: "string", 78 | dataKey: "arguments", 79 | useInputToggleDataKey: "useArgumentsInput", 80 | label: "Arguments" 81 | } 82 | ]; 83 | }, 84 | // This function returns the body of the node when it is rendered on the graph. You should show 85 | // what the current data of the node is in some way that is useful at a glance. 86 | getBody(data) { 87 | return rivet.dedent` 88 | ${data.scriptPath} ${data.arguments} 89 | `; 90 | }, 91 | // This is the main processing function for your node. It can do whatever you like, but it must return 92 | // a valid Outputs object, which is a map of port IDs to DataValue objects. The return value of this function 93 | // must also correspond to the output definitions you defined in the getOutputDefinitions function. 94 | async process(data, inputData, context) { 95 | if (context.executor !== "nodejs") { 96 | throw new Error("This node can only be run using a nodejs executor."); 97 | } 98 | const scriptPath = rivet.getInputOrData( 99 | data, 100 | inputData, 101 | "scriptPath", 102 | "string" 103 | ); 104 | let args; 105 | function splitArgs(args2) { 106 | const matcher = /(?:[^\s"]+|"[^"]*")+/g; 107 | return args2.match(matcher) || []; 108 | } 109 | const inputArguments = inputData["arguments"]; 110 | if (data.useArgumentsInput && inputArguments) { 111 | if (rivet.isArrayDataType(inputArguments.type)) { 112 | args = rivet.coerceType(inputArguments, "string[]"); 113 | } else { 114 | const stringArgs = rivet.coerceType(inputArguments, "string"); 115 | args = splitArgs(stringArgs); 116 | } 117 | } else { 118 | args = splitArgs(data.arguments); 119 | } 120 | const { runPythonScript } = await import("../dist/nodeEntry.cjs"); 121 | const output = await runPythonScript(scriptPath, args); 122 | return { 123 | ["output"]: { 124 | type: "string", 125 | value: output 126 | } 127 | }; 128 | } 129 | }; 130 | const nodeDefinition = rivet.pluginNodeDefinition( 131 | nodeImpl, 132 | "Run Python Script" 133 | ); 134 | return nodeDefinition; 135 | } 136 | 137 | // src/index.ts 138 | var initializer = (rivet) => { 139 | const node = RunPythonScriptNode_default(rivet); 140 | const plugin = { 141 | // The ID of your plugin should be unique across all plugins. 142 | id: "rivet-plugin-example-python-exec", 143 | // The name of the plugin is what is displayed in the Rivet UI. 144 | name: "Rivet Plugin Example - Python Exec", 145 | // Define all configuration settings in the configSpec object. 146 | configSpec: {}, 147 | // Define any additional context menu groups your plugin adds here. 148 | contextMenuGroups: [ 149 | { 150 | id: "example", 151 | label: "Example" 152 | } 153 | ], 154 | // Register any additional nodes your plugin adds here. This is passed a `register` 155 | // function, which you can use to register your nodes. 156 | register: (register) => { 157 | register(node); 158 | } 159 | }; 160 | return plugin; 161 | }; 162 | var src_default = initializer; 163 | export { 164 | src_default as default 165 | }; 166 | -------------------------------------------------------------------------------- /dist/nodeEntry.cjs: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __create = Object.create; 3 | var __defProp = Object.defineProperty; 4 | var __getOwnPropDesc = Object.getOwnPropertyDescriptor; 5 | var __getOwnPropNames = Object.getOwnPropertyNames; 6 | var __getProtoOf = Object.getPrototypeOf; 7 | var __hasOwnProp = Object.prototype.hasOwnProperty; 8 | var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; 9 | var __commonJS = (cb, mod) => function __require() { 10 | return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; 11 | }; 12 | var __export = (target, all) => { 13 | for (var name in all) 14 | __defProp(target, name, { get: all[name], enumerable: true }); 15 | }; 16 | var __copyProps = (to, from, except, desc) => { 17 | if (from && typeof from === "object" || typeof from === "function") { 18 | for (let key of __getOwnPropNames(from)) 19 | if (!__hasOwnProp.call(to, key) && key !== except) 20 | __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); 21 | } 22 | return to; 23 | }; 24 | var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( 25 | // If the importer is in node compatibility mode or this is not an ESM 26 | // file that has been converted to a CommonJS file using a Babel- 27 | // compatible transform (i.e. "__esModule" has not been set), then set 28 | // "default" to the CommonJS "module.exports" for node compatibility. 29 | isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, 30 | mod 31 | )); 32 | var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); 33 | var __publicField = (obj, key, value) => { 34 | __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); 35 | return value; 36 | }; 37 | var __accessCheck = (obj, member, msg) => { 38 | if (!member.has(obj)) 39 | throw TypeError("Cannot " + msg); 40 | }; 41 | var __privateGet = (obj, member, getter) => { 42 | __accessCheck(obj, member, "read from private field"); 43 | return getter ? getter.call(obj) : member.get(obj); 44 | }; 45 | var __privateAdd = (obj, member, value) => { 46 | if (member.has(obj)) 47 | throw TypeError("Cannot add the same private member more than once"); 48 | member instanceof WeakSet ? member.add(obj) : member.set(obj, value); 49 | }; 50 | var __privateSet = (obj, member, value, setter) => { 51 | __accessCheck(obj, member, "write to private field"); 52 | setter ? setter.call(obj, value) : member.set(obj, value); 53 | return value; 54 | }; 55 | var __privateMethod = (obj, member, method) => { 56 | __accessCheck(obj, member, "access private method"); 57 | return method; 58 | }; 59 | 60 | // node_modules/isexe/windows.js 61 | var require_windows = __commonJS({ 62 | "node_modules/isexe/windows.js"(exports, module2) { 63 | module2.exports = isexe; 64 | isexe.sync = sync; 65 | var fs = require("fs"); 66 | function checkPathExt(path3, options) { 67 | var pathext = options.pathExt !== void 0 ? options.pathExt : process.env.PATHEXT; 68 | if (!pathext) { 69 | return true; 70 | } 71 | pathext = pathext.split(";"); 72 | if (pathext.indexOf("") !== -1) { 73 | return true; 74 | } 75 | for (var i = 0; i < pathext.length; i++) { 76 | var p = pathext[i].toLowerCase(); 77 | if (p && path3.substr(-p.length).toLowerCase() === p) { 78 | return true; 79 | } 80 | } 81 | return false; 82 | } 83 | function checkStat(stat, path3, options) { 84 | if (!stat.isSymbolicLink() && !stat.isFile()) { 85 | return false; 86 | } 87 | return checkPathExt(path3, options); 88 | } 89 | function isexe(path3, options, cb) { 90 | fs.stat(path3, function(er, stat) { 91 | cb(er, er ? false : checkStat(stat, path3, options)); 92 | }); 93 | } 94 | function sync(path3, options) { 95 | return checkStat(fs.statSync(path3), path3, options); 96 | } 97 | } 98 | }); 99 | 100 | // node_modules/isexe/mode.js 101 | var require_mode = __commonJS({ 102 | "node_modules/isexe/mode.js"(exports, module2) { 103 | module2.exports = isexe; 104 | isexe.sync = sync; 105 | var fs = require("fs"); 106 | function isexe(path3, options, cb) { 107 | fs.stat(path3, function(er, stat) { 108 | cb(er, er ? false : checkStat(stat, options)); 109 | }); 110 | } 111 | function sync(path3, options) { 112 | return checkStat(fs.statSync(path3), options); 113 | } 114 | function checkStat(stat, options) { 115 | return stat.isFile() && checkMode(stat, options); 116 | } 117 | function checkMode(stat, options) { 118 | var mod = stat.mode; 119 | var uid = stat.uid; 120 | var gid = stat.gid; 121 | var myUid = options.uid !== void 0 ? options.uid : process.getuid && process.getuid(); 122 | var myGid = options.gid !== void 0 ? options.gid : process.getgid && process.getgid(); 123 | var u = parseInt("100", 8); 124 | var g = parseInt("010", 8); 125 | var o = parseInt("001", 8); 126 | var ug = u | g; 127 | var ret = mod & o || mod & g && gid === myGid || mod & u && uid === myUid || mod & ug && myUid === 0; 128 | return ret; 129 | } 130 | } 131 | }); 132 | 133 | // node_modules/isexe/index.js 134 | var require_isexe = __commonJS({ 135 | "node_modules/isexe/index.js"(exports, module2) { 136 | var fs = require("fs"); 137 | var core; 138 | if (process.platform === "win32" || global.TESTING_WINDOWS) { 139 | core = require_windows(); 140 | } else { 141 | core = require_mode(); 142 | } 143 | module2.exports = isexe; 144 | isexe.sync = sync; 145 | function isexe(path3, options, cb) { 146 | if (typeof options === "function") { 147 | cb = options; 148 | options = {}; 149 | } 150 | if (!cb) { 151 | if (typeof Promise !== "function") { 152 | throw new TypeError("callback not provided"); 153 | } 154 | return new Promise(function(resolve, reject) { 155 | isexe(path3, options || {}, function(er, is) { 156 | if (er) { 157 | reject(er); 158 | } else { 159 | resolve(is); 160 | } 161 | }); 162 | }); 163 | } 164 | core(path3, options || {}, function(er, is) { 165 | if (er) { 166 | if (er.code === "EACCES" || options && options.ignoreErrors) { 167 | er = null; 168 | is = false; 169 | } 170 | } 171 | cb(er, is); 172 | }); 173 | } 174 | function sync(path3, options) { 175 | try { 176 | return core.sync(path3, options || {}); 177 | } catch (er) { 178 | if (options && options.ignoreErrors || er.code === "EACCES") { 179 | return false; 180 | } else { 181 | throw er; 182 | } 183 | } 184 | } 185 | } 186 | }); 187 | 188 | // node_modules/which/which.js 189 | var require_which = __commonJS({ 190 | "node_modules/which/which.js"(exports, module2) { 191 | var isWindows = process.platform === "win32" || process.env.OSTYPE === "cygwin" || process.env.OSTYPE === "msys"; 192 | var path3 = require("path"); 193 | var COLON = isWindows ? ";" : ":"; 194 | var isexe = require_isexe(); 195 | var getNotFoundError = (cmd) => Object.assign(new Error(`not found: ${cmd}`), { code: "ENOENT" }); 196 | var getPathInfo = (cmd, opt) => { 197 | const colon = opt.colon || COLON; 198 | const pathEnv = cmd.match(/\//) || isWindows && cmd.match(/\\/) ? [""] : [ 199 | // windows always checks the cwd first 200 | ...isWindows ? [process.cwd()] : [], 201 | ...(opt.path || process.env.PATH || /* istanbul ignore next: very unusual */ 202 | "").split(colon) 203 | ]; 204 | const pathExtExe = isWindows ? opt.pathExt || process.env.PATHEXT || ".EXE;.CMD;.BAT;.COM" : ""; 205 | const pathExt = isWindows ? pathExtExe.split(colon) : [""]; 206 | if (isWindows) { 207 | if (cmd.indexOf(".") !== -1 && pathExt[0] !== "") 208 | pathExt.unshift(""); 209 | } 210 | return { 211 | pathEnv, 212 | pathExt, 213 | pathExtExe 214 | }; 215 | }; 216 | var which = (cmd, opt, cb) => { 217 | if (typeof opt === "function") { 218 | cb = opt; 219 | opt = {}; 220 | } 221 | if (!opt) 222 | opt = {}; 223 | const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt); 224 | const found = []; 225 | const step = (i) => new Promise((resolve, reject) => { 226 | if (i === pathEnv.length) 227 | return opt.all && found.length ? resolve(found) : reject(getNotFoundError(cmd)); 228 | const ppRaw = pathEnv[i]; 229 | const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw; 230 | const pCmd = path3.join(pathPart, cmd); 231 | const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd; 232 | resolve(subStep(p, i, 0)); 233 | }); 234 | const subStep = (p, i, ii) => new Promise((resolve, reject) => { 235 | if (ii === pathExt.length) 236 | return resolve(step(i + 1)); 237 | const ext = pathExt[ii]; 238 | isexe(p + ext, { pathExt: pathExtExe }, (er, is) => { 239 | if (!er && is) { 240 | if (opt.all) 241 | found.push(p + ext); 242 | else 243 | return resolve(p + ext); 244 | } 245 | return resolve(subStep(p, i, ii + 1)); 246 | }); 247 | }); 248 | return cb ? step(0).then((res) => cb(null, res), cb) : step(0); 249 | }; 250 | var whichSync = (cmd, opt) => { 251 | opt = opt || {}; 252 | const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt); 253 | const found = []; 254 | for (let i = 0; i < pathEnv.length; i++) { 255 | const ppRaw = pathEnv[i]; 256 | const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw; 257 | const pCmd = path3.join(pathPart, cmd); 258 | const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd; 259 | for (let j = 0; j < pathExt.length; j++) { 260 | const cur = p + pathExt[j]; 261 | try { 262 | const is = isexe.sync(cur, { pathExt: pathExtExe }); 263 | if (is) { 264 | if (opt.all) 265 | found.push(cur); 266 | else 267 | return cur; 268 | } 269 | } catch (ex) { 270 | } 271 | } 272 | } 273 | if (opt.all && found.length) 274 | return found; 275 | if (opt.nothrow) 276 | return null; 277 | throw getNotFoundError(cmd); 278 | }; 279 | module2.exports = which; 280 | which.sync = whichSync; 281 | } 282 | }); 283 | 284 | // node_modules/path-key/index.js 285 | var require_path_key = __commonJS({ 286 | "node_modules/path-key/index.js"(exports, module2) { 287 | "use strict"; 288 | var pathKey2 = (options = {}) => { 289 | const environment = options.env || process.env; 290 | const platform = options.platform || process.platform; 291 | if (platform !== "win32") { 292 | return "PATH"; 293 | } 294 | return Object.keys(environment).reverse().find((key) => key.toUpperCase() === "PATH") || "Path"; 295 | }; 296 | module2.exports = pathKey2; 297 | module2.exports.default = pathKey2; 298 | } 299 | }); 300 | 301 | // node_modules/cross-spawn/lib/util/resolveCommand.js 302 | var require_resolveCommand = __commonJS({ 303 | "node_modules/cross-spawn/lib/util/resolveCommand.js"(exports, module2) { 304 | "use strict"; 305 | var path3 = require("path"); 306 | var which = require_which(); 307 | var getPathKey = require_path_key(); 308 | function resolveCommandAttempt(parsed, withoutPathExt) { 309 | const env = parsed.options.env || process.env; 310 | const cwd = process.cwd(); 311 | const hasCustomCwd = parsed.options.cwd != null; 312 | const shouldSwitchCwd = hasCustomCwd && process.chdir !== void 0 && !process.chdir.disabled; 313 | if (shouldSwitchCwd) { 314 | try { 315 | process.chdir(parsed.options.cwd); 316 | } catch (err) { 317 | } 318 | } 319 | let resolved; 320 | try { 321 | resolved = which.sync(parsed.command, { 322 | path: env[getPathKey({ env })], 323 | pathExt: withoutPathExt ? path3.delimiter : void 0 324 | }); 325 | } catch (e) { 326 | } finally { 327 | if (shouldSwitchCwd) { 328 | process.chdir(cwd); 329 | } 330 | } 331 | if (resolved) { 332 | resolved = path3.resolve(hasCustomCwd ? parsed.options.cwd : "", resolved); 333 | } 334 | return resolved; 335 | } 336 | function resolveCommand(parsed) { 337 | return resolveCommandAttempt(parsed) || resolveCommandAttempt(parsed, true); 338 | } 339 | module2.exports = resolveCommand; 340 | } 341 | }); 342 | 343 | // node_modules/cross-spawn/lib/util/escape.js 344 | var require_escape = __commonJS({ 345 | "node_modules/cross-spawn/lib/util/escape.js"(exports, module2) { 346 | "use strict"; 347 | var metaCharsRegExp = /([()\][%!^"`<>&|;, *?])/g; 348 | function escapeCommand(arg) { 349 | arg = arg.replace(metaCharsRegExp, "^$1"); 350 | return arg; 351 | } 352 | function escapeArgument(arg, doubleEscapeMetaChars) { 353 | arg = `${arg}`; 354 | arg = arg.replace(/(\\*)"/g, '$1$1\\"'); 355 | arg = arg.replace(/(\\*)$/, "$1$1"); 356 | arg = `"${arg}"`; 357 | arg = arg.replace(metaCharsRegExp, "^$1"); 358 | if (doubleEscapeMetaChars) { 359 | arg = arg.replace(metaCharsRegExp, "^$1"); 360 | } 361 | return arg; 362 | } 363 | module2.exports.command = escapeCommand; 364 | module2.exports.argument = escapeArgument; 365 | } 366 | }); 367 | 368 | // node_modules/shebang-regex/index.js 369 | var require_shebang_regex = __commonJS({ 370 | "node_modules/shebang-regex/index.js"(exports, module2) { 371 | "use strict"; 372 | module2.exports = /^#!(.*)/; 373 | } 374 | }); 375 | 376 | // node_modules/shebang-command/index.js 377 | var require_shebang_command = __commonJS({ 378 | "node_modules/shebang-command/index.js"(exports, module2) { 379 | "use strict"; 380 | var shebangRegex = require_shebang_regex(); 381 | module2.exports = (string = "") => { 382 | const match = string.match(shebangRegex); 383 | if (!match) { 384 | return null; 385 | } 386 | const [path3, argument] = match[0].replace(/#! ?/, "").split(" "); 387 | const binary = path3.split("/").pop(); 388 | if (binary === "env") { 389 | return argument; 390 | } 391 | return argument ? `${binary} ${argument}` : binary; 392 | }; 393 | } 394 | }); 395 | 396 | // node_modules/cross-spawn/lib/util/readShebang.js 397 | var require_readShebang = __commonJS({ 398 | "node_modules/cross-spawn/lib/util/readShebang.js"(exports, module2) { 399 | "use strict"; 400 | var fs = require("fs"); 401 | var shebangCommand = require_shebang_command(); 402 | function readShebang(command) { 403 | const size = 150; 404 | const buffer = Buffer.alloc(size); 405 | let fd; 406 | try { 407 | fd = fs.openSync(command, "r"); 408 | fs.readSync(fd, buffer, 0, size, 0); 409 | fs.closeSync(fd); 410 | } catch (e) { 411 | } 412 | return shebangCommand(buffer.toString()); 413 | } 414 | module2.exports = readShebang; 415 | } 416 | }); 417 | 418 | // node_modules/cross-spawn/lib/parse.js 419 | var require_parse = __commonJS({ 420 | "node_modules/cross-spawn/lib/parse.js"(exports, module2) { 421 | "use strict"; 422 | var path3 = require("path"); 423 | var resolveCommand = require_resolveCommand(); 424 | var escape = require_escape(); 425 | var readShebang = require_readShebang(); 426 | var isWin = process.platform === "win32"; 427 | var isExecutableRegExp = /\.(?:com|exe)$/i; 428 | var isCmdShimRegExp = /node_modules[\\/].bin[\\/][^\\/]+\.cmd$/i; 429 | function detectShebang(parsed) { 430 | parsed.file = resolveCommand(parsed); 431 | const shebang = parsed.file && readShebang(parsed.file); 432 | if (shebang) { 433 | parsed.args.unshift(parsed.file); 434 | parsed.command = shebang; 435 | return resolveCommand(parsed); 436 | } 437 | return parsed.file; 438 | } 439 | function parseNonShell(parsed) { 440 | if (!isWin) { 441 | return parsed; 442 | } 443 | const commandFile = detectShebang(parsed); 444 | const needsShell = !isExecutableRegExp.test(commandFile); 445 | if (parsed.options.forceShell || needsShell) { 446 | const needsDoubleEscapeMetaChars = isCmdShimRegExp.test(commandFile); 447 | parsed.command = path3.normalize(parsed.command); 448 | parsed.command = escape.command(parsed.command); 449 | parsed.args = parsed.args.map((arg) => escape.argument(arg, needsDoubleEscapeMetaChars)); 450 | const shellCommand = [parsed.command].concat(parsed.args).join(" "); 451 | parsed.args = ["/d", "/s", "/c", `"${shellCommand}"`]; 452 | parsed.command = process.env.comspec || "cmd.exe"; 453 | parsed.options.windowsVerbatimArguments = true; 454 | } 455 | return parsed; 456 | } 457 | function parse(command, args, options) { 458 | if (args && !Array.isArray(args)) { 459 | options = args; 460 | args = null; 461 | } 462 | args = args ? args.slice(0) : []; 463 | options = Object.assign({}, options); 464 | const parsed = { 465 | command, 466 | args, 467 | options, 468 | file: void 0, 469 | original: { 470 | command, 471 | args 472 | } 473 | }; 474 | return options.shell ? parsed : parseNonShell(parsed); 475 | } 476 | module2.exports = parse; 477 | } 478 | }); 479 | 480 | // node_modules/cross-spawn/lib/enoent.js 481 | var require_enoent = __commonJS({ 482 | "node_modules/cross-spawn/lib/enoent.js"(exports, module2) { 483 | "use strict"; 484 | var isWin = process.platform === "win32"; 485 | function notFoundError(original, syscall) { 486 | return Object.assign(new Error(`${syscall} ${original.command} ENOENT`), { 487 | code: "ENOENT", 488 | errno: "ENOENT", 489 | syscall: `${syscall} ${original.command}`, 490 | path: original.command, 491 | spawnargs: original.args 492 | }); 493 | } 494 | function hookChildProcess(cp, parsed) { 495 | if (!isWin) { 496 | return; 497 | } 498 | const originalEmit = cp.emit; 499 | cp.emit = function(name, arg1) { 500 | if (name === "exit") { 501 | const err = verifyENOENT(arg1, parsed, "spawn"); 502 | if (err) { 503 | return originalEmit.call(cp, "error", err); 504 | } 505 | } 506 | return originalEmit.apply(cp, arguments); 507 | }; 508 | } 509 | function verifyENOENT(status, parsed) { 510 | if (isWin && status === 1 && !parsed.file) { 511 | return notFoundError(parsed.original, "spawn"); 512 | } 513 | return null; 514 | } 515 | function verifyENOENTSync(status, parsed) { 516 | if (isWin && status === 1 && !parsed.file) { 517 | return notFoundError(parsed.original, "spawnSync"); 518 | } 519 | return null; 520 | } 521 | module2.exports = { 522 | hookChildProcess, 523 | verifyENOENT, 524 | verifyENOENTSync, 525 | notFoundError 526 | }; 527 | } 528 | }); 529 | 530 | // node_modules/cross-spawn/index.js 531 | var require_cross_spawn = __commonJS({ 532 | "node_modules/cross-spawn/index.js"(exports, module2) { 533 | "use strict"; 534 | var cp = require("child_process"); 535 | var parse = require_parse(); 536 | var enoent = require_enoent(); 537 | function spawn(command, args, options) { 538 | const parsed = parse(command, args, options); 539 | const spawned = cp.spawn(parsed.command, parsed.args, parsed.options); 540 | enoent.hookChildProcess(spawned, parsed); 541 | return spawned; 542 | } 543 | function spawnSync(command, args, options) { 544 | const parsed = parse(command, args, options); 545 | const result = cp.spawnSync(parsed.command, parsed.args, parsed.options); 546 | result.error = result.error || enoent.verifyENOENTSync(result.status, parsed); 547 | return result; 548 | } 549 | module2.exports = spawn; 550 | module2.exports.spawn = spawn; 551 | module2.exports.sync = spawnSync; 552 | module2.exports._parse = parse; 553 | module2.exports._enoent = enoent; 554 | } 555 | }); 556 | 557 | // node_modules/merge-stream/index.js 558 | var require_merge_stream = __commonJS({ 559 | "node_modules/merge-stream/index.js"(exports, module2) { 560 | "use strict"; 561 | var { PassThrough } = require("stream"); 562 | module2.exports = function() { 563 | var sources = []; 564 | var output = new PassThrough({ objectMode: true }); 565 | output.setMaxListeners(0); 566 | output.add = add; 567 | output.isEmpty = isEmpty; 568 | output.on("unpipe", remove); 569 | Array.prototype.slice.call(arguments).forEach(add); 570 | return output; 571 | function add(source) { 572 | if (Array.isArray(source)) { 573 | source.forEach(add); 574 | return this; 575 | } 576 | sources.push(source); 577 | source.once("end", remove.bind(null, source)); 578 | source.once("error", output.emit.bind(output, "error")); 579 | source.pipe(output, { end: false }); 580 | return this; 581 | } 582 | function isEmpty() { 583 | return sources.length == 0; 584 | } 585 | function remove(source) { 586 | sources = sources.filter(function(it) { 587 | return it !== source; 588 | }); 589 | if (!sources.length && output.readable) { 590 | output.end(); 591 | } 592 | } 593 | }; 594 | } 595 | }); 596 | 597 | // src/nodeEntry.ts 598 | var nodeEntry_exports = {}; 599 | __export(nodeEntry_exports, { 600 | runPythonScript: () => runPythonScript 601 | }); 602 | module.exports = __toCommonJS(nodeEntry_exports); 603 | 604 | // node_modules/execa/index.js 605 | var import_node_buffer2 = require("buffer"); 606 | var import_node_path2 = __toESM(require("path"), 1); 607 | var import_node_child_process3 = __toESM(require("child_process"), 1); 608 | var import_node_process4 = __toESM(require("process"), 1); 609 | var import_cross_spawn = __toESM(require_cross_spawn(), 1); 610 | 611 | // node_modules/strip-final-newline/index.js 612 | function stripFinalNewline(input) { 613 | const LF = typeof input === "string" ? "\n" : "\n".charCodeAt(); 614 | const CR = typeof input === "string" ? "\r" : "\r".charCodeAt(); 615 | if (input[input.length - 1] === LF) { 616 | input = input.slice(0, -1); 617 | } 618 | if (input[input.length - 1] === CR) { 619 | input = input.slice(0, -1); 620 | } 621 | return input; 622 | } 623 | 624 | // node_modules/npm-run-path/index.js 625 | var import_node_process = __toESM(require("process"), 1); 626 | var import_node_path = __toESM(require("path"), 1); 627 | var import_node_url = __toESM(require("url"), 1); 628 | 629 | // node_modules/npm-run-path/node_modules/path-key/index.js 630 | function pathKey(options = {}) { 631 | const { 632 | env = process.env, 633 | platform = process.platform 634 | } = options; 635 | if (platform !== "win32") { 636 | return "PATH"; 637 | } 638 | return Object.keys(env).reverse().find((key) => key.toUpperCase() === "PATH") || "Path"; 639 | } 640 | 641 | // node_modules/npm-run-path/index.js 642 | function npmRunPath(options = {}) { 643 | const { 644 | cwd = import_node_process.default.cwd(), 645 | path: path_ = import_node_process.default.env[pathKey()], 646 | execPath = import_node_process.default.execPath 647 | } = options; 648 | let previous; 649 | const cwdString = cwd instanceof URL ? import_node_url.default.fileURLToPath(cwd) : cwd; 650 | let cwdPath = import_node_path.default.resolve(cwdString); 651 | const result = []; 652 | while (previous !== cwdPath) { 653 | result.push(import_node_path.default.join(cwdPath, "node_modules/.bin")); 654 | previous = cwdPath; 655 | cwdPath = import_node_path.default.resolve(cwdPath, ".."); 656 | } 657 | result.push(import_node_path.default.resolve(cwdString, execPath, "..")); 658 | return [...result, path_].join(import_node_path.default.delimiter); 659 | } 660 | function npmRunPathEnv({ env = import_node_process.default.env, ...options } = {}) { 661 | env = { ...env }; 662 | const path3 = pathKey({ env }); 663 | options.path = env[path3]; 664 | env[path3] = npmRunPath(options); 665 | return env; 666 | } 667 | 668 | // node_modules/mimic-fn/index.js 669 | var copyProperty = (to, from, property, ignoreNonConfigurable) => { 670 | if (property === "length" || property === "prototype") { 671 | return; 672 | } 673 | if (property === "arguments" || property === "caller") { 674 | return; 675 | } 676 | const toDescriptor = Object.getOwnPropertyDescriptor(to, property); 677 | const fromDescriptor = Object.getOwnPropertyDescriptor(from, property); 678 | if (!canCopyProperty(toDescriptor, fromDescriptor) && ignoreNonConfigurable) { 679 | return; 680 | } 681 | Object.defineProperty(to, property, fromDescriptor); 682 | }; 683 | var canCopyProperty = function(toDescriptor, fromDescriptor) { 684 | return toDescriptor === void 0 || toDescriptor.configurable || toDescriptor.writable === fromDescriptor.writable && toDescriptor.enumerable === fromDescriptor.enumerable && toDescriptor.configurable === fromDescriptor.configurable && (toDescriptor.writable || toDescriptor.value === fromDescriptor.value); 685 | }; 686 | var changePrototype = (to, from) => { 687 | const fromPrototype = Object.getPrototypeOf(from); 688 | if (fromPrototype === Object.getPrototypeOf(to)) { 689 | return; 690 | } 691 | Object.setPrototypeOf(to, fromPrototype); 692 | }; 693 | var wrappedToString = (withName, fromBody) => `/* Wrapped ${withName}*/ 694 | ${fromBody}`; 695 | var toStringDescriptor = Object.getOwnPropertyDescriptor(Function.prototype, "toString"); 696 | var toStringName = Object.getOwnPropertyDescriptor(Function.prototype.toString, "name"); 697 | var changeToString = (to, from, name) => { 698 | const withName = name === "" ? "" : `with ${name.trim()}() `; 699 | const newToString = wrappedToString.bind(null, withName, from.toString()); 700 | Object.defineProperty(newToString, "name", toStringName); 701 | Object.defineProperty(to, "toString", { ...toStringDescriptor, value: newToString }); 702 | }; 703 | function mimicFunction(to, from, { ignoreNonConfigurable = false } = {}) { 704 | const { name } = to; 705 | for (const property of Reflect.ownKeys(from)) { 706 | copyProperty(to, from, property, ignoreNonConfigurable); 707 | } 708 | changePrototype(to, from); 709 | changeToString(to, from, name); 710 | return to; 711 | } 712 | 713 | // node_modules/onetime/index.js 714 | var calledFunctions = /* @__PURE__ */ new WeakMap(); 715 | var onetime = (function_, options = {}) => { 716 | if (typeof function_ !== "function") { 717 | throw new TypeError("Expected a function"); 718 | } 719 | let returnValue; 720 | let callCount = 0; 721 | const functionName = function_.displayName || function_.name || ""; 722 | const onetime2 = function(...arguments_) { 723 | calledFunctions.set(onetime2, ++callCount); 724 | if (callCount === 1) { 725 | returnValue = function_.apply(this, arguments_); 726 | function_ = null; 727 | } else if (options.throw === true) { 728 | throw new Error(`Function \`${functionName}\` can only be called once`); 729 | } 730 | return returnValue; 731 | }; 732 | mimicFunction(onetime2, function_); 733 | calledFunctions.set(onetime2, callCount); 734 | return onetime2; 735 | }; 736 | onetime.callCount = (function_) => { 737 | if (!calledFunctions.has(function_)) { 738 | throw new Error(`The given function \`${function_.name}\` is not wrapped by the \`onetime\` package`); 739 | } 740 | return calledFunctions.get(function_); 741 | }; 742 | var onetime_default = onetime; 743 | 744 | // node_modules/execa/lib/error.js 745 | var import_node_process2 = __toESM(require("process"), 1); 746 | 747 | // node_modules/human-signals/build/src/main.js 748 | var import_node_os2 = require("os"); 749 | 750 | // node_modules/human-signals/build/src/realtime.js 751 | var getRealtimeSignals = () => { 752 | const length = SIGRTMAX - SIGRTMIN + 1; 753 | return Array.from({ length }, getRealtimeSignal); 754 | }; 755 | var getRealtimeSignal = (value, index) => ({ 756 | name: `SIGRT${index + 1}`, 757 | number: SIGRTMIN + index, 758 | action: "terminate", 759 | description: "Application-specific signal (realtime)", 760 | standard: "posix" 761 | }); 762 | var SIGRTMIN = 34; 763 | var SIGRTMAX = 64; 764 | 765 | // node_modules/human-signals/build/src/signals.js 766 | var import_node_os = require("os"); 767 | 768 | // node_modules/human-signals/build/src/core.js 769 | var SIGNALS = [ 770 | { 771 | name: "SIGHUP", 772 | number: 1, 773 | action: "terminate", 774 | description: "Terminal closed", 775 | standard: "posix" 776 | }, 777 | { 778 | name: "SIGINT", 779 | number: 2, 780 | action: "terminate", 781 | description: "User interruption with CTRL-C", 782 | standard: "ansi" 783 | }, 784 | { 785 | name: "SIGQUIT", 786 | number: 3, 787 | action: "core", 788 | description: "User interruption with CTRL-\\", 789 | standard: "posix" 790 | }, 791 | { 792 | name: "SIGILL", 793 | number: 4, 794 | action: "core", 795 | description: "Invalid machine instruction", 796 | standard: "ansi" 797 | }, 798 | { 799 | name: "SIGTRAP", 800 | number: 5, 801 | action: "core", 802 | description: "Debugger breakpoint", 803 | standard: "posix" 804 | }, 805 | { 806 | name: "SIGABRT", 807 | number: 6, 808 | action: "core", 809 | description: "Aborted", 810 | standard: "ansi" 811 | }, 812 | { 813 | name: "SIGIOT", 814 | number: 6, 815 | action: "core", 816 | description: "Aborted", 817 | standard: "bsd" 818 | }, 819 | { 820 | name: "SIGBUS", 821 | number: 7, 822 | action: "core", 823 | description: "Bus error due to misaligned, non-existing address or paging error", 824 | standard: "bsd" 825 | }, 826 | { 827 | name: "SIGEMT", 828 | number: 7, 829 | action: "terminate", 830 | description: "Command should be emulated but is not implemented", 831 | standard: "other" 832 | }, 833 | { 834 | name: "SIGFPE", 835 | number: 8, 836 | action: "core", 837 | description: "Floating point arithmetic error", 838 | standard: "ansi" 839 | }, 840 | { 841 | name: "SIGKILL", 842 | number: 9, 843 | action: "terminate", 844 | description: "Forced termination", 845 | standard: "posix", 846 | forced: true 847 | }, 848 | { 849 | name: "SIGUSR1", 850 | number: 10, 851 | action: "terminate", 852 | description: "Application-specific signal", 853 | standard: "posix" 854 | }, 855 | { 856 | name: "SIGSEGV", 857 | number: 11, 858 | action: "core", 859 | description: "Segmentation fault", 860 | standard: "ansi" 861 | }, 862 | { 863 | name: "SIGUSR2", 864 | number: 12, 865 | action: "terminate", 866 | description: "Application-specific signal", 867 | standard: "posix" 868 | }, 869 | { 870 | name: "SIGPIPE", 871 | number: 13, 872 | action: "terminate", 873 | description: "Broken pipe or socket", 874 | standard: "posix" 875 | }, 876 | { 877 | name: "SIGALRM", 878 | number: 14, 879 | action: "terminate", 880 | description: "Timeout or timer", 881 | standard: "posix" 882 | }, 883 | { 884 | name: "SIGTERM", 885 | number: 15, 886 | action: "terminate", 887 | description: "Termination", 888 | standard: "ansi" 889 | }, 890 | { 891 | name: "SIGSTKFLT", 892 | number: 16, 893 | action: "terminate", 894 | description: "Stack is empty or overflowed", 895 | standard: "other" 896 | }, 897 | { 898 | name: "SIGCHLD", 899 | number: 17, 900 | action: "ignore", 901 | description: "Child process terminated, paused or unpaused", 902 | standard: "posix" 903 | }, 904 | { 905 | name: "SIGCLD", 906 | number: 17, 907 | action: "ignore", 908 | description: "Child process terminated, paused or unpaused", 909 | standard: "other" 910 | }, 911 | { 912 | name: "SIGCONT", 913 | number: 18, 914 | action: "unpause", 915 | description: "Unpaused", 916 | standard: "posix", 917 | forced: true 918 | }, 919 | { 920 | name: "SIGSTOP", 921 | number: 19, 922 | action: "pause", 923 | description: "Paused", 924 | standard: "posix", 925 | forced: true 926 | }, 927 | { 928 | name: "SIGTSTP", 929 | number: 20, 930 | action: "pause", 931 | description: 'Paused using CTRL-Z or "suspend"', 932 | standard: "posix" 933 | }, 934 | { 935 | name: "SIGTTIN", 936 | number: 21, 937 | action: "pause", 938 | description: "Background process cannot read terminal input", 939 | standard: "posix" 940 | }, 941 | { 942 | name: "SIGBREAK", 943 | number: 21, 944 | action: "terminate", 945 | description: "User interruption with CTRL-BREAK", 946 | standard: "other" 947 | }, 948 | { 949 | name: "SIGTTOU", 950 | number: 22, 951 | action: "pause", 952 | description: "Background process cannot write to terminal output", 953 | standard: "posix" 954 | }, 955 | { 956 | name: "SIGURG", 957 | number: 23, 958 | action: "ignore", 959 | description: "Socket received out-of-band data", 960 | standard: "bsd" 961 | }, 962 | { 963 | name: "SIGXCPU", 964 | number: 24, 965 | action: "core", 966 | description: "Process timed out", 967 | standard: "bsd" 968 | }, 969 | { 970 | name: "SIGXFSZ", 971 | number: 25, 972 | action: "core", 973 | description: "File too big", 974 | standard: "bsd" 975 | }, 976 | { 977 | name: "SIGVTALRM", 978 | number: 26, 979 | action: "terminate", 980 | description: "Timeout or timer", 981 | standard: "bsd" 982 | }, 983 | { 984 | name: "SIGPROF", 985 | number: 27, 986 | action: "terminate", 987 | description: "Timeout or timer", 988 | standard: "bsd" 989 | }, 990 | { 991 | name: "SIGWINCH", 992 | number: 28, 993 | action: "ignore", 994 | description: "Terminal window size changed", 995 | standard: "bsd" 996 | }, 997 | { 998 | name: "SIGIO", 999 | number: 29, 1000 | action: "terminate", 1001 | description: "I/O is available", 1002 | standard: "other" 1003 | }, 1004 | { 1005 | name: "SIGPOLL", 1006 | number: 29, 1007 | action: "terminate", 1008 | description: "Watched event", 1009 | standard: "other" 1010 | }, 1011 | { 1012 | name: "SIGINFO", 1013 | number: 29, 1014 | action: "ignore", 1015 | description: "Request for process information", 1016 | standard: "other" 1017 | }, 1018 | { 1019 | name: "SIGPWR", 1020 | number: 30, 1021 | action: "terminate", 1022 | description: "Device running out of power", 1023 | standard: "systemv" 1024 | }, 1025 | { 1026 | name: "SIGSYS", 1027 | number: 31, 1028 | action: "core", 1029 | description: "Invalid system call", 1030 | standard: "other" 1031 | }, 1032 | { 1033 | name: "SIGUNUSED", 1034 | number: 31, 1035 | action: "terminate", 1036 | description: "Invalid system call", 1037 | standard: "other" 1038 | } 1039 | ]; 1040 | 1041 | // node_modules/human-signals/build/src/signals.js 1042 | var getSignals = () => { 1043 | const realtimeSignals = getRealtimeSignals(); 1044 | const signals2 = [...SIGNALS, ...realtimeSignals].map(normalizeSignal); 1045 | return signals2; 1046 | }; 1047 | var normalizeSignal = ({ 1048 | name, 1049 | number: defaultNumber, 1050 | description, 1051 | action, 1052 | forced = false, 1053 | standard 1054 | }) => { 1055 | const { 1056 | signals: { [name]: constantSignal } 1057 | } = import_node_os.constants; 1058 | const supported = constantSignal !== void 0; 1059 | const number = supported ? constantSignal : defaultNumber; 1060 | return { name, number, description, supported, action, forced, standard }; 1061 | }; 1062 | 1063 | // node_modules/human-signals/build/src/main.js 1064 | var getSignalsByName = () => { 1065 | const signals2 = getSignals(); 1066 | return Object.fromEntries(signals2.map(getSignalByName)); 1067 | }; 1068 | var getSignalByName = ({ 1069 | name, 1070 | number, 1071 | description, 1072 | supported, 1073 | action, 1074 | forced, 1075 | standard 1076 | }) => [name, { name, number, description, supported, action, forced, standard }]; 1077 | var signalsByName = getSignalsByName(); 1078 | var getSignalsByNumber = () => { 1079 | const signals2 = getSignals(); 1080 | const length = SIGRTMAX + 1; 1081 | const signalsA = Array.from( 1082 | { length }, 1083 | (value, number) => getSignalByNumber(number, signals2) 1084 | ); 1085 | return Object.assign({}, ...signalsA); 1086 | }; 1087 | var getSignalByNumber = (number, signals2) => { 1088 | const signal = findSignalByNumber(number, signals2); 1089 | if (signal === void 0) { 1090 | return {}; 1091 | } 1092 | const { name, description, supported, action, forced, standard } = signal; 1093 | return { 1094 | [number]: { 1095 | name, 1096 | number, 1097 | description, 1098 | supported, 1099 | action, 1100 | forced, 1101 | standard 1102 | } 1103 | }; 1104 | }; 1105 | var findSignalByNumber = (number, signals2) => { 1106 | const signal = signals2.find(({ name }) => import_node_os2.constants.signals[name] === number); 1107 | if (signal !== void 0) { 1108 | return signal; 1109 | } 1110 | return signals2.find((signalA) => signalA.number === number); 1111 | }; 1112 | var signalsByNumber = getSignalsByNumber(); 1113 | 1114 | // node_modules/execa/lib/error.js 1115 | var getErrorPrefix = ({ timedOut, timeout, errorCode, signal, signalDescription, exitCode, isCanceled }) => { 1116 | if (timedOut) { 1117 | return `timed out after ${timeout} milliseconds`; 1118 | } 1119 | if (isCanceled) { 1120 | return "was canceled"; 1121 | } 1122 | if (errorCode !== void 0) { 1123 | return `failed with ${errorCode}`; 1124 | } 1125 | if (signal !== void 0) { 1126 | return `was killed with ${signal} (${signalDescription})`; 1127 | } 1128 | if (exitCode !== void 0) { 1129 | return `failed with exit code ${exitCode}`; 1130 | } 1131 | return "failed"; 1132 | }; 1133 | var makeError = ({ 1134 | stdout, 1135 | stderr, 1136 | all, 1137 | error, 1138 | signal, 1139 | exitCode, 1140 | command, 1141 | escapedCommand, 1142 | timedOut, 1143 | isCanceled, 1144 | killed, 1145 | parsed: { options: { timeout, cwd = import_node_process2.default.cwd() } } 1146 | }) => { 1147 | exitCode = exitCode === null ? void 0 : exitCode; 1148 | signal = signal === null ? void 0 : signal; 1149 | const signalDescription = signal === void 0 ? void 0 : signalsByName[signal].description; 1150 | const errorCode = error && error.code; 1151 | const prefix = getErrorPrefix({ timedOut, timeout, errorCode, signal, signalDescription, exitCode, isCanceled }); 1152 | const execaMessage = `Command ${prefix}: ${command}`; 1153 | const isError = Object.prototype.toString.call(error) === "[object Error]"; 1154 | const shortMessage = isError ? `${execaMessage} 1155 | ${error.message}` : execaMessage; 1156 | const message = [shortMessage, stderr, stdout].filter(Boolean).join("\n"); 1157 | if (isError) { 1158 | error.originalMessage = error.message; 1159 | error.message = message; 1160 | } else { 1161 | error = new Error(message); 1162 | } 1163 | error.shortMessage = shortMessage; 1164 | error.command = command; 1165 | error.escapedCommand = escapedCommand; 1166 | error.exitCode = exitCode; 1167 | error.signal = signal; 1168 | error.signalDescription = signalDescription; 1169 | error.stdout = stdout; 1170 | error.stderr = stderr; 1171 | error.cwd = cwd; 1172 | if (all !== void 0) { 1173 | error.all = all; 1174 | } 1175 | if ("bufferedData" in error) { 1176 | delete error.bufferedData; 1177 | } 1178 | error.failed = true; 1179 | error.timedOut = Boolean(timedOut); 1180 | error.isCanceled = isCanceled; 1181 | error.killed = killed && !timedOut; 1182 | return error; 1183 | }; 1184 | 1185 | // node_modules/execa/lib/stdio.js 1186 | var aliases = ["stdin", "stdout", "stderr"]; 1187 | var hasAlias = (options) => aliases.some((alias) => options[alias] !== void 0); 1188 | var normalizeStdio = (options) => { 1189 | if (!options) { 1190 | return; 1191 | } 1192 | const { stdio } = options; 1193 | if (stdio === void 0) { 1194 | return aliases.map((alias) => options[alias]); 1195 | } 1196 | if (hasAlias(options)) { 1197 | throw new Error(`It's not possible to provide \`stdio\` in combination with one of ${aliases.map((alias) => `\`${alias}\``).join(", ")}`); 1198 | } 1199 | if (typeof stdio === "string") { 1200 | return stdio; 1201 | } 1202 | if (!Array.isArray(stdio)) { 1203 | throw new TypeError(`Expected \`stdio\` to be of type \`string\` or \`Array\`, got \`${typeof stdio}\``); 1204 | } 1205 | const length = Math.max(stdio.length, aliases.length); 1206 | return Array.from({ length }, (value, index) => stdio[index]); 1207 | }; 1208 | 1209 | // node_modules/execa/lib/kill.js 1210 | var import_node_os3 = __toESM(require("os"), 1); 1211 | 1212 | // node_modules/signal-exit/dist/mjs/signals.js 1213 | var signals = []; 1214 | signals.push("SIGHUP", "SIGINT", "SIGTERM"); 1215 | if (process.platform !== "win32") { 1216 | signals.push( 1217 | "SIGALRM", 1218 | "SIGABRT", 1219 | "SIGVTALRM", 1220 | "SIGXCPU", 1221 | "SIGXFSZ", 1222 | "SIGUSR2", 1223 | "SIGTRAP", 1224 | "SIGSYS", 1225 | "SIGQUIT", 1226 | "SIGIOT" 1227 | // should detect profiler and enable/disable accordingly. 1228 | // see #21 1229 | // 'SIGPROF' 1230 | ); 1231 | } 1232 | if (process.platform === "linux") { 1233 | signals.push("SIGIO", "SIGPOLL", "SIGPWR", "SIGSTKFLT"); 1234 | } 1235 | 1236 | // node_modules/signal-exit/dist/mjs/index.js 1237 | var processOk = (process7) => !!process7 && typeof process7 === "object" && typeof process7.removeListener === "function" && typeof process7.emit === "function" && typeof process7.reallyExit === "function" && typeof process7.listeners === "function" && typeof process7.kill === "function" && typeof process7.pid === "number" && typeof process7.on === "function"; 1238 | var kExitEmitter = Symbol.for("signal-exit emitter"); 1239 | var global2 = globalThis; 1240 | var ObjectDefineProperty = Object.defineProperty.bind(Object); 1241 | var Emitter = class { 1242 | constructor() { 1243 | __publicField(this, "emitted", { 1244 | afterExit: false, 1245 | exit: false 1246 | }); 1247 | __publicField(this, "listeners", { 1248 | afterExit: [], 1249 | exit: [] 1250 | }); 1251 | __publicField(this, "count", 0); 1252 | __publicField(this, "id", Math.random()); 1253 | if (global2[kExitEmitter]) { 1254 | return global2[kExitEmitter]; 1255 | } 1256 | ObjectDefineProperty(global2, kExitEmitter, { 1257 | value: this, 1258 | writable: false, 1259 | enumerable: false, 1260 | configurable: false 1261 | }); 1262 | } 1263 | on(ev, fn) { 1264 | this.listeners[ev].push(fn); 1265 | } 1266 | removeListener(ev, fn) { 1267 | const list = this.listeners[ev]; 1268 | const i = list.indexOf(fn); 1269 | if (i === -1) { 1270 | return; 1271 | } 1272 | if (i === 0 && list.length === 1) { 1273 | list.length = 0; 1274 | } else { 1275 | list.splice(i, 1); 1276 | } 1277 | } 1278 | emit(ev, code, signal) { 1279 | if (this.emitted[ev]) { 1280 | return false; 1281 | } 1282 | this.emitted[ev] = true; 1283 | let ret = false; 1284 | for (const fn of this.listeners[ev]) { 1285 | ret = fn(code, signal) === true || ret; 1286 | } 1287 | if (ev === "exit") { 1288 | ret = this.emit("afterExit", code, signal) || ret; 1289 | } 1290 | return ret; 1291 | } 1292 | }; 1293 | var SignalExitBase = class { 1294 | }; 1295 | var signalExitWrap = (handler) => { 1296 | return { 1297 | onExit(cb, opts) { 1298 | return handler.onExit(cb, opts); 1299 | }, 1300 | load() { 1301 | return handler.load(); 1302 | }, 1303 | unload() { 1304 | return handler.unload(); 1305 | } 1306 | }; 1307 | }; 1308 | var SignalExitFallback = class extends SignalExitBase { 1309 | onExit() { 1310 | return () => { 1311 | }; 1312 | } 1313 | load() { 1314 | } 1315 | unload() { 1316 | } 1317 | }; 1318 | var _hupSig, _emitter, _process, _originalProcessEmit, _originalProcessReallyExit, _sigListeners, _loaded, _processReallyExit, processReallyExit_fn, _processEmit, processEmit_fn; 1319 | var SignalExit = class extends SignalExitBase { 1320 | constructor(process7) { 1321 | super(); 1322 | __privateAdd(this, _processReallyExit); 1323 | __privateAdd(this, _processEmit); 1324 | // "SIGHUP" throws an `ENOSYS` error on Windows, 1325 | // so use a supported signal instead 1326 | /* c8 ignore start */ 1327 | __privateAdd(this, _hupSig, process4.platform === "win32" ? "SIGINT" : "SIGHUP"); 1328 | /* c8 ignore stop */ 1329 | __privateAdd(this, _emitter, new Emitter()); 1330 | __privateAdd(this, _process, void 0); 1331 | __privateAdd(this, _originalProcessEmit, void 0); 1332 | __privateAdd(this, _originalProcessReallyExit, void 0); 1333 | __privateAdd(this, _sigListeners, {}); 1334 | __privateAdd(this, _loaded, false); 1335 | __privateSet(this, _process, process7); 1336 | __privateSet(this, _sigListeners, {}); 1337 | for (const sig of signals) { 1338 | __privateGet(this, _sigListeners)[sig] = () => { 1339 | const listeners = __privateGet(this, _process).listeners(sig); 1340 | let { count } = __privateGet(this, _emitter); 1341 | const p = process7; 1342 | if (typeof p.__signal_exit_emitter__ === "object" && typeof p.__signal_exit_emitter__.count === "number") { 1343 | count += p.__signal_exit_emitter__.count; 1344 | } 1345 | if (listeners.length === count) { 1346 | this.unload(); 1347 | const ret = __privateGet(this, _emitter).emit("exit", null, sig); 1348 | const s = sig === "SIGHUP" ? __privateGet(this, _hupSig) : sig; 1349 | if (!ret) 1350 | process7.kill(process7.pid, s); 1351 | } 1352 | }; 1353 | } 1354 | __privateSet(this, _originalProcessReallyExit, process7.reallyExit); 1355 | __privateSet(this, _originalProcessEmit, process7.emit); 1356 | } 1357 | onExit(cb, opts) { 1358 | if (!processOk(__privateGet(this, _process))) { 1359 | return () => { 1360 | }; 1361 | } 1362 | if (__privateGet(this, _loaded) === false) { 1363 | this.load(); 1364 | } 1365 | const ev = opts?.alwaysLast ? "afterExit" : "exit"; 1366 | __privateGet(this, _emitter).on(ev, cb); 1367 | return () => { 1368 | __privateGet(this, _emitter).removeListener(ev, cb); 1369 | if (__privateGet(this, _emitter).listeners["exit"].length === 0 && __privateGet(this, _emitter).listeners["afterExit"].length === 0) { 1370 | this.unload(); 1371 | } 1372 | }; 1373 | } 1374 | load() { 1375 | if (__privateGet(this, _loaded)) { 1376 | return; 1377 | } 1378 | __privateSet(this, _loaded, true); 1379 | __privateGet(this, _emitter).count += 1; 1380 | for (const sig of signals) { 1381 | try { 1382 | const fn = __privateGet(this, _sigListeners)[sig]; 1383 | if (fn) 1384 | __privateGet(this, _process).on(sig, fn); 1385 | } catch (_) { 1386 | } 1387 | } 1388 | __privateGet(this, _process).emit = (ev, ...a) => { 1389 | return __privateMethod(this, _processEmit, processEmit_fn).call(this, ev, ...a); 1390 | }; 1391 | __privateGet(this, _process).reallyExit = (code) => { 1392 | return __privateMethod(this, _processReallyExit, processReallyExit_fn).call(this, code); 1393 | }; 1394 | } 1395 | unload() { 1396 | if (!__privateGet(this, _loaded)) { 1397 | return; 1398 | } 1399 | __privateSet(this, _loaded, false); 1400 | signals.forEach((sig) => { 1401 | const listener = __privateGet(this, _sigListeners)[sig]; 1402 | if (!listener) { 1403 | throw new Error("Listener not defined for signal: " + sig); 1404 | } 1405 | try { 1406 | __privateGet(this, _process).removeListener(sig, listener); 1407 | } catch (_) { 1408 | } 1409 | }); 1410 | __privateGet(this, _process).emit = __privateGet(this, _originalProcessEmit); 1411 | __privateGet(this, _process).reallyExit = __privateGet(this, _originalProcessReallyExit); 1412 | __privateGet(this, _emitter).count -= 1; 1413 | } 1414 | }; 1415 | _hupSig = new WeakMap(); 1416 | _emitter = new WeakMap(); 1417 | _process = new WeakMap(); 1418 | _originalProcessEmit = new WeakMap(); 1419 | _originalProcessReallyExit = new WeakMap(); 1420 | _sigListeners = new WeakMap(); 1421 | _loaded = new WeakMap(); 1422 | _processReallyExit = new WeakSet(); 1423 | processReallyExit_fn = function(code) { 1424 | if (!processOk(__privateGet(this, _process))) { 1425 | return 0; 1426 | } 1427 | __privateGet(this, _process).exitCode = code || 0; 1428 | __privateGet(this, _emitter).emit("exit", __privateGet(this, _process).exitCode, null); 1429 | return __privateGet(this, _originalProcessReallyExit).call(__privateGet(this, _process), __privateGet(this, _process).exitCode); 1430 | }; 1431 | _processEmit = new WeakSet(); 1432 | processEmit_fn = function(ev, ...args) { 1433 | const og = __privateGet(this, _originalProcessEmit); 1434 | if (ev === "exit" && processOk(__privateGet(this, _process))) { 1435 | if (typeof args[0] === "number") { 1436 | __privateGet(this, _process).exitCode = args[0]; 1437 | } 1438 | const ret = og.call(__privateGet(this, _process), ev, ...args); 1439 | __privateGet(this, _emitter).emit("exit", __privateGet(this, _process).exitCode, null); 1440 | return ret; 1441 | } else { 1442 | return og.call(__privateGet(this, _process), ev, ...args); 1443 | } 1444 | }; 1445 | var process4 = globalThis.process; 1446 | var { 1447 | /** 1448 | * Called when the process is exiting, whether via signal, explicit 1449 | * exit, or running out of stuff to do. 1450 | * 1451 | * If the global process object is not suitable for instrumentation, 1452 | * then this will be a no-op. 1453 | * 1454 | * Returns a function that may be used to unload signal-exit. 1455 | */ 1456 | onExit, 1457 | /** 1458 | * Load the listeners. Likely you never need to call this, unless 1459 | * doing a rather deep integration with signal-exit functionality. 1460 | * Mostly exposed for the benefit of testing. 1461 | * 1462 | * @internal 1463 | */ 1464 | load, 1465 | /** 1466 | * Unload the listeners. Likely you never need to call this, unless 1467 | * doing a rather deep integration with signal-exit functionality. 1468 | * Mostly exposed for the benefit of testing. 1469 | * 1470 | * @internal 1471 | */ 1472 | unload 1473 | } = signalExitWrap(processOk(process4) ? new SignalExit(process4) : new SignalExitFallback()); 1474 | 1475 | // node_modules/execa/lib/kill.js 1476 | var DEFAULT_FORCE_KILL_TIMEOUT = 1e3 * 5; 1477 | var spawnedKill = (kill, signal = "SIGTERM", options = {}) => { 1478 | const killResult = kill(signal); 1479 | setKillTimeout(kill, signal, options, killResult); 1480 | return killResult; 1481 | }; 1482 | var setKillTimeout = (kill, signal, options, killResult) => { 1483 | if (!shouldForceKill(signal, options, killResult)) { 1484 | return; 1485 | } 1486 | const timeout = getForceKillAfterTimeout(options); 1487 | const t = setTimeout(() => { 1488 | kill("SIGKILL"); 1489 | }, timeout); 1490 | if (t.unref) { 1491 | t.unref(); 1492 | } 1493 | }; 1494 | var shouldForceKill = (signal, { forceKillAfterTimeout }, killResult) => isSigterm(signal) && forceKillAfterTimeout !== false && killResult; 1495 | var isSigterm = (signal) => signal === import_node_os3.default.constants.signals.SIGTERM || typeof signal === "string" && signal.toUpperCase() === "SIGTERM"; 1496 | var getForceKillAfterTimeout = ({ forceKillAfterTimeout = true }) => { 1497 | if (forceKillAfterTimeout === true) { 1498 | return DEFAULT_FORCE_KILL_TIMEOUT; 1499 | } 1500 | if (!Number.isFinite(forceKillAfterTimeout) || forceKillAfterTimeout < 0) { 1501 | throw new TypeError(`Expected the \`forceKillAfterTimeout\` option to be a non-negative integer, got \`${forceKillAfterTimeout}\` (${typeof forceKillAfterTimeout})`); 1502 | } 1503 | return forceKillAfterTimeout; 1504 | }; 1505 | var spawnedCancel = (spawned, context) => { 1506 | const killResult = spawned.kill(); 1507 | if (killResult) { 1508 | context.isCanceled = true; 1509 | } 1510 | }; 1511 | var timeoutKill = (spawned, signal, reject) => { 1512 | spawned.kill(signal); 1513 | reject(Object.assign(new Error("Timed out"), { timedOut: true, signal })); 1514 | }; 1515 | var setupTimeout = (spawned, { timeout, killSignal = "SIGTERM" }, spawnedPromise) => { 1516 | if (timeout === 0 || timeout === void 0) { 1517 | return spawnedPromise; 1518 | } 1519 | let timeoutId; 1520 | const timeoutPromise = new Promise((resolve, reject) => { 1521 | timeoutId = setTimeout(() => { 1522 | timeoutKill(spawned, killSignal, reject); 1523 | }, timeout); 1524 | }); 1525 | const safeSpawnedPromise = spawnedPromise.finally(() => { 1526 | clearTimeout(timeoutId); 1527 | }); 1528 | return Promise.race([timeoutPromise, safeSpawnedPromise]); 1529 | }; 1530 | var validateTimeout = ({ timeout }) => { 1531 | if (timeout !== void 0 && (!Number.isFinite(timeout) || timeout < 0)) { 1532 | throw new TypeError(`Expected the \`timeout\` option to be a non-negative integer, got \`${timeout}\` (${typeof timeout})`); 1533 | } 1534 | }; 1535 | var setExitHandler = async (spawned, { cleanup, detached }, timedPromise) => { 1536 | if (!cleanup || detached) { 1537 | return timedPromise; 1538 | } 1539 | const removeExitHandler = onExit(() => { 1540 | spawned.kill(); 1541 | }); 1542 | return timedPromise.finally(() => { 1543 | removeExitHandler(); 1544 | }); 1545 | }; 1546 | 1547 | // node_modules/execa/lib/pipe.js 1548 | var import_node_fs = require("fs"); 1549 | var import_node_child_process = require("child_process"); 1550 | 1551 | // node_modules/is-stream/index.js 1552 | function isStream(stream) { 1553 | return stream !== null && typeof stream === "object" && typeof stream.pipe === "function"; 1554 | } 1555 | function isWritableStream(stream) { 1556 | return isStream(stream) && stream.writable !== false && typeof stream._write === "function" && typeof stream._writableState === "object"; 1557 | } 1558 | 1559 | // node_modules/execa/lib/pipe.js 1560 | var isExecaChildProcess = (target) => target instanceof import_node_child_process.ChildProcess && typeof target.then === "function"; 1561 | var pipeToTarget = (spawned, streamName, target) => { 1562 | if (typeof target === "string") { 1563 | spawned[streamName].pipe((0, import_node_fs.createWriteStream)(target)); 1564 | return spawned; 1565 | } 1566 | if (isWritableStream(target)) { 1567 | spawned[streamName].pipe(target); 1568 | return spawned; 1569 | } 1570 | if (!isExecaChildProcess(target)) { 1571 | throw new TypeError("The second argument must be a string, a stream or an Execa child process."); 1572 | } 1573 | if (!isWritableStream(target.stdin)) { 1574 | throw new TypeError("The target child process's stdin must be available."); 1575 | } 1576 | spawned[streamName].pipe(target.stdin); 1577 | return target; 1578 | }; 1579 | var addPipeMethods = (spawned) => { 1580 | if (spawned.stdout !== null) { 1581 | spawned.pipeStdout = pipeToTarget.bind(void 0, spawned, "stdout"); 1582 | } 1583 | if (spawned.stderr !== null) { 1584 | spawned.pipeStderr = pipeToTarget.bind(void 0, spawned, "stderr"); 1585 | } 1586 | if (spawned.all !== void 0) { 1587 | spawned.pipeAll = pipeToTarget.bind(void 0, spawned, "all"); 1588 | } 1589 | }; 1590 | 1591 | // node_modules/execa/lib/stream.js 1592 | var import_node_fs2 = require("fs"); 1593 | var import_promises = require("timers/promises"); 1594 | 1595 | // node_modules/get-stream/source/contents.js 1596 | var getStreamContents = async (stream, { init, convertChunk, getSize, truncateChunk, addChunk, getFinalChunk, finalize }, { maxBuffer = Number.POSITIVE_INFINITY } = {}) => { 1597 | if (!isAsyncIterable(stream)) { 1598 | throw new Error("The first argument must be a Readable, a ReadableStream, or an async iterable."); 1599 | } 1600 | const state = init(); 1601 | state.length = 0; 1602 | try { 1603 | for await (const chunk of stream) { 1604 | const chunkType = getChunkType(chunk); 1605 | const convertedChunk = convertChunk[chunkType](chunk, state); 1606 | appendChunk({ convertedChunk, state, getSize, truncateChunk, addChunk, maxBuffer }); 1607 | } 1608 | appendFinalChunk({ state, convertChunk, getSize, truncateChunk, addChunk, getFinalChunk, maxBuffer }); 1609 | return finalize(state); 1610 | } catch (error) { 1611 | error.bufferedData = finalize(state); 1612 | throw error; 1613 | } 1614 | }; 1615 | var appendFinalChunk = ({ state, getSize, truncateChunk, addChunk, getFinalChunk, maxBuffer }) => { 1616 | const convertedChunk = getFinalChunk(state); 1617 | if (convertedChunk !== void 0) { 1618 | appendChunk({ convertedChunk, state, getSize, truncateChunk, addChunk, maxBuffer }); 1619 | } 1620 | }; 1621 | var appendChunk = ({ convertedChunk, state, getSize, truncateChunk, addChunk, maxBuffer }) => { 1622 | const chunkSize = getSize(convertedChunk); 1623 | const newLength = state.length + chunkSize; 1624 | if (newLength <= maxBuffer) { 1625 | addNewChunk(convertedChunk, state, addChunk, newLength); 1626 | return; 1627 | } 1628 | const truncatedChunk = truncateChunk(convertedChunk, maxBuffer - state.length); 1629 | if (truncatedChunk !== void 0) { 1630 | addNewChunk(truncatedChunk, state, addChunk, maxBuffer); 1631 | } 1632 | throw new MaxBufferError(); 1633 | }; 1634 | var addNewChunk = (convertedChunk, state, addChunk, newLength) => { 1635 | state.contents = addChunk(convertedChunk, state, newLength); 1636 | state.length = newLength; 1637 | }; 1638 | var isAsyncIterable = (stream) => typeof stream === "object" && stream !== null && typeof stream[Symbol.asyncIterator] === "function"; 1639 | var getChunkType = (chunk) => { 1640 | const typeOfChunk = typeof chunk; 1641 | if (typeOfChunk === "string") { 1642 | return "string"; 1643 | } 1644 | if (typeOfChunk !== "object" || chunk === null) { 1645 | return "others"; 1646 | } 1647 | if (globalThis.Buffer?.isBuffer(chunk)) { 1648 | return "buffer"; 1649 | } 1650 | const prototypeName = objectToString.call(chunk); 1651 | if (prototypeName === "[object ArrayBuffer]") { 1652 | return "arrayBuffer"; 1653 | } 1654 | if (prototypeName === "[object DataView]") { 1655 | return "dataView"; 1656 | } 1657 | if (Number.isInteger(chunk.byteLength) && Number.isInteger(chunk.byteOffset) && objectToString.call(chunk.buffer) === "[object ArrayBuffer]") { 1658 | return "typedArray"; 1659 | } 1660 | return "others"; 1661 | }; 1662 | var { toString: objectToString } = Object.prototype; 1663 | var MaxBufferError = class extends Error { 1664 | constructor() { 1665 | super("maxBuffer exceeded"); 1666 | __publicField(this, "name", "MaxBufferError"); 1667 | } 1668 | }; 1669 | 1670 | // node_modules/get-stream/source/utils.js 1671 | var identity = (value) => value; 1672 | var noop = () => void 0; 1673 | var getContentsProp = ({ contents }) => contents; 1674 | var throwObjectStream = (chunk) => { 1675 | throw new Error(`Streams in object mode are not supported: ${String(chunk)}`); 1676 | }; 1677 | var getLengthProp = (convertedChunk) => convertedChunk.length; 1678 | 1679 | // node_modules/get-stream/source/array-buffer.js 1680 | async function getStreamAsArrayBuffer(stream, options) { 1681 | return getStreamContents(stream, arrayBufferMethods, options); 1682 | } 1683 | var initArrayBuffer = () => ({ contents: new ArrayBuffer(0) }); 1684 | var useTextEncoder = (chunk) => textEncoder.encode(chunk); 1685 | var textEncoder = new TextEncoder(); 1686 | var useUint8Array = (chunk) => new Uint8Array(chunk); 1687 | var useUint8ArrayWithOffset = (chunk) => new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength); 1688 | var truncateArrayBufferChunk = (convertedChunk, chunkSize) => convertedChunk.slice(0, chunkSize); 1689 | var addArrayBufferChunk = (convertedChunk, { contents, length: previousLength }, length) => { 1690 | const newContents = hasArrayBufferResize() ? resizeArrayBuffer(contents, length) : resizeArrayBufferSlow(contents, length); 1691 | new Uint8Array(newContents).set(convertedChunk, previousLength); 1692 | return newContents; 1693 | }; 1694 | var resizeArrayBufferSlow = (contents, length) => { 1695 | if (length <= contents.byteLength) { 1696 | return contents; 1697 | } 1698 | const arrayBuffer = new ArrayBuffer(getNewContentsLength(length)); 1699 | new Uint8Array(arrayBuffer).set(new Uint8Array(contents), 0); 1700 | return arrayBuffer; 1701 | }; 1702 | var resizeArrayBuffer = (contents, length) => { 1703 | if (length <= contents.maxByteLength) { 1704 | contents.resize(length); 1705 | return contents; 1706 | } 1707 | const arrayBuffer = new ArrayBuffer(length, { maxByteLength: getNewContentsLength(length) }); 1708 | new Uint8Array(arrayBuffer).set(new Uint8Array(contents), 0); 1709 | return arrayBuffer; 1710 | }; 1711 | var getNewContentsLength = (length) => SCALE_FACTOR ** Math.ceil(Math.log(length) / Math.log(SCALE_FACTOR)); 1712 | var SCALE_FACTOR = 2; 1713 | var finalizeArrayBuffer = ({ contents, length }) => hasArrayBufferResize() ? contents : contents.slice(0, length); 1714 | var hasArrayBufferResize = () => "resize" in ArrayBuffer.prototype; 1715 | var arrayBufferMethods = { 1716 | init: initArrayBuffer, 1717 | convertChunk: { 1718 | string: useTextEncoder, 1719 | buffer: useUint8Array, 1720 | arrayBuffer: useUint8Array, 1721 | dataView: useUint8ArrayWithOffset, 1722 | typedArray: useUint8ArrayWithOffset, 1723 | others: throwObjectStream 1724 | }, 1725 | getSize: getLengthProp, 1726 | truncateChunk: truncateArrayBufferChunk, 1727 | addChunk: addArrayBufferChunk, 1728 | getFinalChunk: noop, 1729 | finalize: finalizeArrayBuffer 1730 | }; 1731 | 1732 | // node_modules/get-stream/source/buffer.js 1733 | async function getStreamAsBuffer(stream, options) { 1734 | if (!("Buffer" in globalThis)) { 1735 | throw new Error("getStreamAsBuffer() is only supported in Node.js"); 1736 | } 1737 | try { 1738 | return arrayBufferToNodeBuffer(await getStreamAsArrayBuffer(stream, options)); 1739 | } catch (error) { 1740 | if (error.bufferedData !== void 0) { 1741 | error.bufferedData = arrayBufferToNodeBuffer(error.bufferedData); 1742 | } 1743 | throw error; 1744 | } 1745 | } 1746 | var arrayBufferToNodeBuffer = (arrayBuffer) => globalThis.Buffer.from(arrayBuffer); 1747 | 1748 | // node_modules/get-stream/source/string.js 1749 | async function getStreamAsString(stream, options) { 1750 | return getStreamContents(stream, stringMethods, options); 1751 | } 1752 | var initString = () => ({ contents: "", textDecoder: new TextDecoder() }); 1753 | var useTextDecoder = (chunk, { textDecoder }) => textDecoder.decode(chunk, { stream: true }); 1754 | var addStringChunk = (convertedChunk, { contents }) => contents + convertedChunk; 1755 | var truncateStringChunk = (convertedChunk, chunkSize) => convertedChunk.slice(0, chunkSize); 1756 | var getFinalStringChunk = ({ textDecoder }) => { 1757 | const finalChunk = textDecoder.decode(); 1758 | return finalChunk === "" ? void 0 : finalChunk; 1759 | }; 1760 | var stringMethods = { 1761 | init: initString, 1762 | convertChunk: { 1763 | string: identity, 1764 | buffer: useTextDecoder, 1765 | arrayBuffer: useTextDecoder, 1766 | dataView: useTextDecoder, 1767 | typedArray: useTextDecoder, 1768 | others: throwObjectStream 1769 | }, 1770 | getSize: getLengthProp, 1771 | truncateChunk: truncateStringChunk, 1772 | addChunk: addStringChunk, 1773 | getFinalChunk: getFinalStringChunk, 1774 | finalize: getContentsProp 1775 | }; 1776 | 1777 | // node_modules/execa/lib/stream.js 1778 | var import_merge_stream = __toESM(require_merge_stream(), 1); 1779 | var validateInputOptions = (input) => { 1780 | if (input !== void 0) { 1781 | throw new TypeError("The `input` and `inputFile` options cannot be both set."); 1782 | } 1783 | }; 1784 | var getInputSync = ({ input, inputFile }) => { 1785 | if (typeof inputFile !== "string") { 1786 | return input; 1787 | } 1788 | validateInputOptions(input); 1789 | return (0, import_node_fs2.readFileSync)(inputFile); 1790 | }; 1791 | var handleInputSync = (options) => { 1792 | const input = getInputSync(options); 1793 | if (isStream(input)) { 1794 | throw new TypeError("The `input` option cannot be a stream in sync mode"); 1795 | } 1796 | return input; 1797 | }; 1798 | var getInput = ({ input, inputFile }) => { 1799 | if (typeof inputFile !== "string") { 1800 | return input; 1801 | } 1802 | validateInputOptions(input); 1803 | return (0, import_node_fs2.createReadStream)(inputFile); 1804 | }; 1805 | var handleInput = (spawned, options) => { 1806 | const input = getInput(options); 1807 | if (input === void 0) { 1808 | return; 1809 | } 1810 | if (isStream(input)) { 1811 | input.pipe(spawned.stdin); 1812 | } else { 1813 | spawned.stdin.end(input); 1814 | } 1815 | }; 1816 | var makeAllStream = (spawned, { all }) => { 1817 | if (!all || !spawned.stdout && !spawned.stderr) { 1818 | return; 1819 | } 1820 | const mixed = (0, import_merge_stream.default)(); 1821 | if (spawned.stdout) { 1822 | mixed.add(spawned.stdout); 1823 | } 1824 | if (spawned.stderr) { 1825 | mixed.add(spawned.stderr); 1826 | } 1827 | return mixed; 1828 | }; 1829 | var getBufferedData = async (stream, streamPromise) => { 1830 | if (!stream || streamPromise === void 0) { 1831 | return; 1832 | } 1833 | await (0, import_promises.setTimeout)(0); 1834 | stream.destroy(); 1835 | try { 1836 | return await streamPromise; 1837 | } catch (error) { 1838 | return error.bufferedData; 1839 | } 1840 | }; 1841 | var getStreamPromise = (stream, { encoding, buffer, maxBuffer }) => { 1842 | if (!stream || !buffer) { 1843 | return; 1844 | } 1845 | if (encoding === "utf8" || encoding === "utf-8") { 1846 | return getStreamAsString(stream, { maxBuffer }); 1847 | } 1848 | if (encoding === null || encoding === "buffer") { 1849 | return getStreamAsBuffer(stream, { maxBuffer }); 1850 | } 1851 | return applyEncoding(stream, maxBuffer, encoding); 1852 | }; 1853 | var applyEncoding = async (stream, maxBuffer, encoding) => { 1854 | const buffer = await getStreamAsBuffer(stream, { maxBuffer }); 1855 | return buffer.toString(encoding); 1856 | }; 1857 | var getSpawnedResult = async ({ stdout, stderr, all }, { encoding, buffer, maxBuffer }, processDone) => { 1858 | const stdoutPromise = getStreamPromise(stdout, { encoding, buffer, maxBuffer }); 1859 | const stderrPromise = getStreamPromise(stderr, { encoding, buffer, maxBuffer }); 1860 | const allPromise = getStreamPromise(all, { encoding, buffer, maxBuffer: maxBuffer * 2 }); 1861 | try { 1862 | return await Promise.all([processDone, stdoutPromise, stderrPromise, allPromise]); 1863 | } catch (error) { 1864 | return Promise.all([ 1865 | { error, signal: error.signal, timedOut: error.timedOut }, 1866 | getBufferedData(stdout, stdoutPromise), 1867 | getBufferedData(stderr, stderrPromise), 1868 | getBufferedData(all, allPromise) 1869 | ]); 1870 | } 1871 | }; 1872 | 1873 | // node_modules/execa/lib/promise.js 1874 | var nativePromisePrototype = (/* @__PURE__ */ (async () => { 1875 | })()).constructor.prototype; 1876 | var descriptors = ["then", "catch", "finally"].map((property) => [ 1877 | property, 1878 | Reflect.getOwnPropertyDescriptor(nativePromisePrototype, property) 1879 | ]); 1880 | var mergePromise = (spawned, promise) => { 1881 | for (const [property, descriptor] of descriptors) { 1882 | const value = typeof promise === "function" ? (...args) => Reflect.apply(descriptor.value, promise(), args) : descriptor.value.bind(promise); 1883 | Reflect.defineProperty(spawned, property, { ...descriptor, value }); 1884 | } 1885 | }; 1886 | var getSpawnedPromise = (spawned) => new Promise((resolve, reject) => { 1887 | spawned.on("exit", (exitCode, signal) => { 1888 | resolve({ exitCode, signal }); 1889 | }); 1890 | spawned.on("error", (error) => { 1891 | reject(error); 1892 | }); 1893 | if (spawned.stdin) { 1894 | spawned.stdin.on("error", (error) => { 1895 | reject(error); 1896 | }); 1897 | } 1898 | }); 1899 | 1900 | // node_modules/execa/lib/command.js 1901 | var import_node_buffer = require("buffer"); 1902 | var import_node_child_process2 = require("child_process"); 1903 | var normalizeArgs = (file, args = []) => { 1904 | if (!Array.isArray(args)) { 1905 | return [file]; 1906 | } 1907 | return [file, ...args]; 1908 | }; 1909 | var NO_ESCAPE_REGEXP = /^[\w.-]+$/; 1910 | var escapeArg = (arg) => { 1911 | if (typeof arg !== "string" || NO_ESCAPE_REGEXP.test(arg)) { 1912 | return arg; 1913 | } 1914 | return `"${arg.replaceAll('"', '\\"')}"`; 1915 | }; 1916 | var joinCommand = (file, args) => normalizeArgs(file, args).join(" "); 1917 | var getEscapedCommand = (file, args) => normalizeArgs(file, args).map((arg) => escapeArg(arg)).join(" "); 1918 | var SPACES_REGEXP = / +/g; 1919 | var parseExpression = (expression) => { 1920 | const typeOfExpression = typeof expression; 1921 | if (typeOfExpression === "string") { 1922 | return expression; 1923 | } 1924 | if (typeOfExpression === "number") { 1925 | return String(expression); 1926 | } 1927 | if (typeOfExpression === "object" && expression !== null && !(expression instanceof import_node_child_process2.ChildProcess) && "stdout" in expression) { 1928 | const typeOfStdout = typeof expression.stdout; 1929 | if (typeOfStdout === "string") { 1930 | return expression.stdout; 1931 | } 1932 | if (import_node_buffer.Buffer.isBuffer(expression.stdout)) { 1933 | return expression.stdout.toString(); 1934 | } 1935 | throw new TypeError(`Unexpected "${typeOfStdout}" stdout in template expression`); 1936 | } 1937 | throw new TypeError(`Unexpected "${typeOfExpression}" in template expression`); 1938 | }; 1939 | var concatTokens = (tokens, nextTokens, isNew) => isNew || tokens.length === 0 || nextTokens.length === 0 ? [...tokens, ...nextTokens] : [ 1940 | ...tokens.slice(0, -1), 1941 | `${tokens.at(-1)}${nextTokens[0]}`, 1942 | ...nextTokens.slice(1) 1943 | ]; 1944 | var parseTemplate = ({ templates, expressions, tokens, index, template }) => { 1945 | const templateString = template ?? templates.raw[index]; 1946 | const templateTokens = templateString.split(SPACES_REGEXP).filter(Boolean); 1947 | const newTokens = concatTokens( 1948 | tokens, 1949 | templateTokens, 1950 | templateString.startsWith(" ") 1951 | ); 1952 | if (index === expressions.length) { 1953 | return newTokens; 1954 | } 1955 | const expression = expressions[index]; 1956 | const expressionTokens = Array.isArray(expression) ? expression.map((expression2) => parseExpression(expression2)) : [parseExpression(expression)]; 1957 | return concatTokens( 1958 | newTokens, 1959 | expressionTokens, 1960 | templateString.endsWith(" ") 1961 | ); 1962 | }; 1963 | var parseTemplates = (templates, expressions) => { 1964 | let tokens = []; 1965 | for (const [index, template] of templates.entries()) { 1966 | tokens = parseTemplate({ templates, expressions, tokens, index, template }); 1967 | } 1968 | return tokens; 1969 | }; 1970 | 1971 | // node_modules/execa/lib/verbose.js 1972 | var import_node_util = require("util"); 1973 | var import_node_process3 = __toESM(require("process"), 1); 1974 | var verboseDefault = (0, import_node_util.debuglog)("execa").enabled; 1975 | var padField = (field, padding) => String(field).padStart(padding, "0"); 1976 | var getTimestamp = () => { 1977 | const date = /* @__PURE__ */ new Date(); 1978 | return `${padField(date.getHours(), 2)}:${padField(date.getMinutes(), 2)}:${padField(date.getSeconds(), 2)}.${padField(date.getMilliseconds(), 3)}`; 1979 | }; 1980 | var logCommand = (escapedCommand, { verbose }) => { 1981 | if (!verbose) { 1982 | return; 1983 | } 1984 | import_node_process3.default.stderr.write(`[${getTimestamp()}] ${escapedCommand} 1985 | `); 1986 | }; 1987 | 1988 | // node_modules/execa/index.js 1989 | var DEFAULT_MAX_BUFFER = 1e3 * 1e3 * 100; 1990 | var getEnv = ({ env: envOption, extendEnv, preferLocal, localDir, execPath }) => { 1991 | const env = extendEnv ? { ...import_node_process4.default.env, ...envOption } : envOption; 1992 | if (preferLocal) { 1993 | return npmRunPathEnv({ env, cwd: localDir, execPath }); 1994 | } 1995 | return env; 1996 | }; 1997 | var handleArguments = (file, args, options = {}) => { 1998 | const parsed = import_cross_spawn.default._parse(file, args, options); 1999 | file = parsed.command; 2000 | args = parsed.args; 2001 | options = parsed.options; 2002 | options = { 2003 | maxBuffer: DEFAULT_MAX_BUFFER, 2004 | buffer: true, 2005 | stripFinalNewline: true, 2006 | extendEnv: true, 2007 | preferLocal: false, 2008 | localDir: options.cwd || import_node_process4.default.cwd(), 2009 | execPath: import_node_process4.default.execPath, 2010 | encoding: "utf8", 2011 | reject: true, 2012 | cleanup: true, 2013 | all: false, 2014 | windowsHide: true, 2015 | verbose: verboseDefault, 2016 | ...options 2017 | }; 2018 | options.env = getEnv(options); 2019 | options.stdio = normalizeStdio(options); 2020 | if (import_node_process4.default.platform === "win32" && import_node_path2.default.basename(file, ".exe") === "cmd") { 2021 | args.unshift("/q"); 2022 | } 2023 | return { file, args, options, parsed }; 2024 | }; 2025 | var handleOutput = (options, value, error) => { 2026 | if (typeof value !== "string" && !import_node_buffer2.Buffer.isBuffer(value)) { 2027 | return error === void 0 ? void 0 : ""; 2028 | } 2029 | if (options.stripFinalNewline) { 2030 | return stripFinalNewline(value); 2031 | } 2032 | return value; 2033 | }; 2034 | function execa(file, args, options) { 2035 | const parsed = handleArguments(file, args, options); 2036 | const command = joinCommand(file, args); 2037 | const escapedCommand = getEscapedCommand(file, args); 2038 | logCommand(escapedCommand, parsed.options); 2039 | validateTimeout(parsed.options); 2040 | let spawned; 2041 | try { 2042 | spawned = import_node_child_process3.default.spawn(parsed.file, parsed.args, parsed.options); 2043 | } catch (error) { 2044 | const dummySpawned = new import_node_child_process3.default.ChildProcess(); 2045 | const errorPromise = Promise.reject(makeError({ 2046 | error, 2047 | stdout: "", 2048 | stderr: "", 2049 | all: "", 2050 | command, 2051 | escapedCommand, 2052 | parsed, 2053 | timedOut: false, 2054 | isCanceled: false, 2055 | killed: false 2056 | })); 2057 | mergePromise(dummySpawned, errorPromise); 2058 | return dummySpawned; 2059 | } 2060 | const spawnedPromise = getSpawnedPromise(spawned); 2061 | const timedPromise = setupTimeout(spawned, parsed.options, spawnedPromise); 2062 | const processDone = setExitHandler(spawned, parsed.options, timedPromise); 2063 | const context = { isCanceled: false }; 2064 | spawned.kill = spawnedKill.bind(null, spawned.kill.bind(spawned)); 2065 | spawned.cancel = spawnedCancel.bind(null, spawned, context); 2066 | const handlePromise = async () => { 2067 | const [{ error, exitCode, signal, timedOut }, stdoutResult, stderrResult, allResult] = await getSpawnedResult(spawned, parsed.options, processDone); 2068 | const stdout = handleOutput(parsed.options, stdoutResult); 2069 | const stderr = handleOutput(parsed.options, stderrResult); 2070 | const all = handleOutput(parsed.options, allResult); 2071 | if (error || exitCode !== 0 || signal !== null) { 2072 | const returnedError = makeError({ 2073 | error, 2074 | exitCode, 2075 | signal, 2076 | stdout, 2077 | stderr, 2078 | all, 2079 | command, 2080 | escapedCommand, 2081 | parsed, 2082 | timedOut, 2083 | isCanceled: context.isCanceled || (parsed.options.signal ? parsed.options.signal.aborted : false), 2084 | killed: spawned.killed 2085 | }); 2086 | if (!parsed.options.reject) { 2087 | return returnedError; 2088 | } 2089 | throw returnedError; 2090 | } 2091 | return { 2092 | command, 2093 | escapedCommand, 2094 | exitCode: 0, 2095 | stdout, 2096 | stderr, 2097 | all, 2098 | failed: false, 2099 | timedOut: false, 2100 | isCanceled: false, 2101 | killed: false 2102 | }; 2103 | }; 2104 | const handlePromiseOnce = onetime_default(handlePromise); 2105 | handleInput(spawned, parsed.options); 2106 | spawned.all = makeAllStream(spawned, parsed.options); 2107 | addPipeMethods(spawned); 2108 | mergePromise(spawned, handlePromiseOnce); 2109 | return spawned; 2110 | } 2111 | function execaSync(file, args, options) { 2112 | const parsed = handleArguments(file, args, options); 2113 | const command = joinCommand(file, args); 2114 | const escapedCommand = getEscapedCommand(file, args); 2115 | logCommand(escapedCommand, parsed.options); 2116 | const input = handleInputSync(parsed.options); 2117 | let result; 2118 | try { 2119 | result = import_node_child_process3.default.spawnSync(parsed.file, parsed.args, { ...parsed.options, input }); 2120 | } catch (error) { 2121 | throw makeError({ 2122 | error, 2123 | stdout: "", 2124 | stderr: "", 2125 | all: "", 2126 | command, 2127 | escapedCommand, 2128 | parsed, 2129 | timedOut: false, 2130 | isCanceled: false, 2131 | killed: false 2132 | }); 2133 | } 2134 | const stdout = handleOutput(parsed.options, result.stdout, result.error); 2135 | const stderr = handleOutput(parsed.options, result.stderr, result.error); 2136 | if (result.error || result.status !== 0 || result.signal !== null) { 2137 | const error = makeError({ 2138 | stdout, 2139 | stderr, 2140 | error: result.error, 2141 | signal: result.signal, 2142 | exitCode: result.status, 2143 | command, 2144 | escapedCommand, 2145 | parsed, 2146 | timedOut: result.error && result.error.code === "ETIMEDOUT", 2147 | isCanceled: false, 2148 | killed: result.signal !== null 2149 | }); 2150 | if (!parsed.options.reject) { 2151 | return error; 2152 | } 2153 | throw error; 2154 | } 2155 | return { 2156 | command, 2157 | escapedCommand, 2158 | exitCode: 0, 2159 | stdout, 2160 | stderr, 2161 | failed: false, 2162 | timedOut: false, 2163 | isCanceled: false, 2164 | killed: false 2165 | }; 2166 | } 2167 | var normalizeScriptStdin = ({ input, inputFile, stdio }) => input === void 0 && inputFile === void 0 && stdio === void 0 ? { stdin: "inherit" } : {}; 2168 | var normalizeScriptOptions = (options = {}) => ({ 2169 | preferLocal: true, 2170 | ...normalizeScriptStdin(options), 2171 | ...options 2172 | }); 2173 | function create$(options) { 2174 | function $2(templatesOrOptions, ...expressions) { 2175 | if (!Array.isArray(templatesOrOptions)) { 2176 | return create$({ ...options, ...templatesOrOptions }); 2177 | } 2178 | const [file, ...args] = parseTemplates(templatesOrOptions, expressions); 2179 | return execa(file, args, normalizeScriptOptions(options)); 2180 | } 2181 | $2.sync = (templates, ...expressions) => { 2182 | if (!Array.isArray(templates)) { 2183 | throw new TypeError("Please use $(options).sync`command` instead of $.sync(options)`command`."); 2184 | } 2185 | const [file, ...args] = parseTemplates(templates, expressions); 2186 | return execaSync(file, args, normalizeScriptOptions(options)); 2187 | }; 2188 | return $2; 2189 | } 2190 | var $ = create$(); 2191 | 2192 | // src/impl/runPythonScript.ts 2193 | var import_node_path3 = require("path"); 2194 | async function runPythonScript(path3, args) { 2195 | if (path3 === "") { 2196 | path3 = (0, import_node_path3.join)(__dirname, "..", "scripts", "python-script.py"); 2197 | } 2198 | const { stdout } = await execa("python3", [path3, ...args]); 2199 | return stdout; 2200 | } 2201 | // Annotate the CommonJS export names for ESM import in node: 2202 | 0 && (module.exports = { 2203 | runPythonScript 2204 | }); 2205 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rivet-plugin-example-python-exec", 3 | "packageManager": "yarn@3.5.0", 4 | "version": "0.0.8", 5 | "type": "module", 6 | "main": "dist/bundle.js", 7 | "files": [ 8 | "dist" 9 | ], 10 | "scripts": { 11 | "build": "tsc -b && tsx bundle.ts", 12 | "dev": "run-p watch:tsc watch:esbuild:sync", 13 | "watch:tsc": "tsc -b -w --preserveWatchOutput", 14 | "watch:esbuild": "tsx bundle.ts --watch", 15 | "watch:esbuild:sync": "tsx bundle.ts --watch --sync" 16 | }, 17 | "dependencies": { 18 | "@ironclad/rivet-core": "^1.5.0", 19 | "execa": "^8.0.1" 20 | }, 21 | "devDependencies": { 22 | "esbuild": "^0.19.2", 23 | "npm-run-all": "^4.1.5", 24 | "recursive-copy": "^2.0.14", 25 | "tsx": "^3.12.10", 26 | "typescript": "^5.2.2" 27 | }, 28 | "volta": { 29 | "node": "20.6.1" 30 | }, 31 | "rivet": { 32 | "skipInstall": true 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /scripts/python-script.py: -------------------------------------------------------------------------------- 1 | print('Hello world from python!'); 2 | -------------------------------------------------------------------------------- /src/impl/runPythonScript.ts: -------------------------------------------------------------------------------- 1 | import { execa } from "execa"; 2 | import { join } from "node:path"; 3 | 4 | export async function runPythonScript( 5 | path: string, 6 | args: string[] 7 | ): Promise { 8 | if (path === "") { 9 | path = join(__dirname, "..", "scripts", "python-script.py"); 10 | } 11 | 12 | const { stdout } = await execa("python3", [path, ...args]); 13 | 14 | return stdout; 15 | } 16 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | // It is important that you only import types from @ironclad/rivet-core, and not 2 | // any of the actual Rivet code. Rivet is passed into the initializer function as 3 | // a parameter, and you can use it to access any Rivet functionality you need. 4 | import type { RivetPlugin, RivetPluginInitializer } from "@ironclad/rivet-core"; 5 | 6 | import runPythonScriptNode from "./nodes/RunPythonScriptNode"; 7 | 8 | // A Rivet plugin must default export a plugin initializer function. This takes in the Rivet library as its 9 | // only parameter. This function must return a valid RivetPlugin object. 10 | const initializer: RivetPluginInitializer = (rivet) => { 11 | // Initialize any nodes in here in the same way, by passing them the Rivet library. 12 | const node = runPythonScriptNode(rivet); 13 | 14 | // The plugin object is the definition for your plugin. 15 | const plugin: RivetPlugin = { 16 | // The ID of your plugin should be unique across all plugins. 17 | id: "rivet-plugin-example-python-exec", 18 | 19 | // The name of the plugin is what is displayed in the Rivet UI. 20 | name: "Rivet Plugin Example - Python Exec", 21 | 22 | // Define all configuration settings in the configSpec object. 23 | configSpec: {}, 24 | 25 | // Define any additional context menu groups your plugin adds here. 26 | contextMenuGroups: [ 27 | { 28 | id: "example", 29 | label: "Example", 30 | }, 31 | ], 32 | 33 | // Register any additional nodes your plugin adds here. This is passed a `register` 34 | // function, which you can use to register your nodes. 35 | register: (register) => { 36 | register(node); 37 | }, 38 | }; 39 | 40 | // Make sure to return your plugin definition. 41 | return plugin; 42 | }; 43 | 44 | // Make sure to default export your plugin. 45 | export default initializer; 46 | -------------------------------------------------------------------------------- /src/nodeEntry.ts: -------------------------------------------------------------------------------- 1 | // This file is the node.js entry point, which is dynamically imported by the process() method of nodes. 2 | // Anything in here can use node.js imports and APIs. 3 | export * from "./impl/runPythonScript"; 4 | -------------------------------------------------------------------------------- /src/nodes/RunPythonScriptNode.ts: -------------------------------------------------------------------------------- 1 | // **** IMPORTANT **** 2 | // Make sure you do `import type` and do not pull in the entire Rivet core library here. 3 | // Export a function that takes in a Rivet object, and you can access rivet library functionality 4 | // from there. 5 | import type { 6 | ChartNode, 7 | EditorDefinition, 8 | Inputs, 9 | InternalProcessContext, 10 | NodeBodySpec, 11 | NodeConnection, 12 | NodeId, 13 | NodeInputDefinition, 14 | NodeOutputDefinition, 15 | NodeUIData, 16 | Outputs, 17 | PluginNodeImpl, 18 | PortId, 19 | Project, 20 | Rivet, 21 | } from "@ironclad/rivet-core"; 22 | 23 | // This defines your new type of node. 24 | export type RunPythonScriptNode = ChartNode< 25 | "runPythonScript", 26 | RunPythonScriptNodeData 27 | >; 28 | 29 | // This defines the data that your new node will store. 30 | export type RunPythonScriptNodeData = { 31 | /** The path to the python script to run. If unset, runs scripts/python-script.py */ 32 | scriptPath: string; 33 | 34 | /** Takes in the script path using an input if true/. */ 35 | useScriptPathInput?: boolean; 36 | 37 | /** Arguments to pass to the python script. */ 38 | arguments: string; 39 | 40 | /** Take in the arguments to the script using an input if true. */ 41 | useArgumentsInput?: boolean; 42 | }; 43 | 44 | // Make sure you export functions that take in the Rivet library, so that you do not 45 | // import the entire Rivet core library in your plugin. 46 | export default function (rivet: typeof Rivet) { 47 | // This is your main node implementation. It is an object that implements the PluginNodeImpl interface. 48 | const nodeImpl: PluginNodeImpl = { 49 | // This should create a new instance of your node type from scratch. 50 | create(): RunPythonScriptNode { 51 | const node: RunPythonScriptNode = { 52 | // Use rivet.newId to generate new IDs for your nodes. 53 | id: rivet.newId(), 54 | 55 | // This is the default data that your node will store 56 | data: { 57 | scriptPath: "", 58 | arguments: "", 59 | }, 60 | 61 | // This is the default title of your node. 62 | title: "Run Python Script", 63 | 64 | // This must match the type of your node. 65 | type: "runPythonScript", 66 | 67 | // X and Y should be set to 0. Width should be set to a reasonable number so there is no overflow. 68 | visualData: { 69 | x: 0, 70 | y: 0, 71 | width: 200, 72 | }, 73 | }; 74 | return node; 75 | }, 76 | 77 | // This function should return all input ports for your node, given its data, connections, all other nodes, and the project. The 78 | // connection, nodes, and project are for advanced use-cases and can usually be ignored. 79 | getInputDefinitions( 80 | data: RunPythonScriptNodeData, 81 | _connections: NodeConnection[], 82 | _nodes: Record, 83 | _project: Project 84 | ): NodeInputDefinition[] { 85 | const inputs: NodeInputDefinition[] = []; 86 | 87 | if (data.useScriptPathInput) { 88 | inputs.push({ 89 | id: "scriptPath" as PortId, 90 | dataType: "string", 91 | title: "Script Path", 92 | }); 93 | } 94 | 95 | if (data.useArgumentsInput) { 96 | inputs.push({ 97 | id: "arguments" as PortId, 98 | dataType: "string[]", 99 | title: "Arguments", 100 | }); 101 | } 102 | 103 | return inputs; 104 | }, 105 | 106 | // This function should return all output ports for your node, given its data, connections, all other nodes, and the project. The 107 | // connection, nodes, and project are for advanced use-cases and can usually be ignored. 108 | getOutputDefinitions( 109 | _data: RunPythonScriptNodeData, 110 | _connections: NodeConnection[], 111 | _nodes: Record, 112 | _project: Project 113 | ): NodeOutputDefinition[] { 114 | return [ 115 | { 116 | id: "output" as PortId, 117 | dataType: "string", 118 | title: "Output", 119 | }, 120 | ]; 121 | }, 122 | 123 | // This returns UI information for your node, such as how it appears in the context menu. 124 | getUIData(): NodeUIData { 125 | return { 126 | contextMenuTitle: "Run Python Script", 127 | group: "Example", 128 | infoBoxBody: 129 | "This is an example of running a python script using a rivet node.", 130 | infoBoxTitle: "Run Python Script Node", 131 | }; 132 | }, 133 | 134 | // This function defines all editors that appear when you edit your node. 135 | getEditors( 136 | _data: RunPythonScriptNodeData 137 | ): EditorDefinition[] { 138 | return [ 139 | { 140 | type: "string", 141 | dataKey: "scriptPath", 142 | useInputToggleDataKey: "useScriptPathInput", 143 | label: "Script Path", 144 | }, 145 | { 146 | type: "string", 147 | dataKey: "arguments", 148 | useInputToggleDataKey: "useArgumentsInput", 149 | label: "Arguments", 150 | }, 151 | ]; 152 | }, 153 | 154 | // This function returns the body of the node when it is rendered on the graph. You should show 155 | // what the current data of the node is in some way that is useful at a glance. 156 | getBody( 157 | data: RunPythonScriptNodeData 158 | ): string | NodeBodySpec | NodeBodySpec[] | undefined { 159 | return rivet.dedent` 160 | ${data.scriptPath} ${data.arguments} 161 | `; 162 | }, 163 | 164 | // This is the main processing function for your node. It can do whatever you like, but it must return 165 | // a valid Outputs object, which is a map of port IDs to DataValue objects. The return value of this function 166 | // must also correspond to the output definitions you defined in the getOutputDefinitions function. 167 | async process( 168 | data: RunPythonScriptNodeData, 169 | inputData: Inputs, 170 | context: InternalProcessContext 171 | ): Promise { 172 | if (context.executor !== "nodejs") { 173 | throw new Error("This node can only be run using a nodejs executor."); 174 | } 175 | 176 | const scriptPath = rivet.getInputOrData( 177 | data, 178 | inputData, 179 | "scriptPath", 180 | "string" 181 | ); 182 | 183 | let args: string[]; 184 | 185 | function splitArgs(args: string): string[] { 186 | const matcher = /(?:[^\s"]+|"[^"]*")+/g; 187 | return args.match(matcher) || []; 188 | } 189 | 190 | const inputArguments = inputData["arguments" as PortId]; 191 | if (data.useArgumentsInput && inputArguments) { 192 | if (rivet.isArrayDataType(inputArguments.type)) { 193 | args = rivet.coerceType(inputArguments, "string[]"); 194 | } else { 195 | const stringArgs = rivet.coerceType(inputArguments, "string"); 196 | args = splitArgs(stringArgs); 197 | } 198 | } else { 199 | args = splitArgs(data.arguments); 200 | } 201 | 202 | // IMPORTANT 203 | // It is important that you separate node-only plugins into two separately bundled parts: 204 | // 1. The isomorphic bundle, which contains the node definition and all the code here 205 | // 2. The node bundle, which contains the node entry point and any node-only code 206 | // You are allowed to dynamically import the node entry point from the isomorphic bundle (in the process function) 207 | const { runPythonScript } = await import("../nodeEntry"); 208 | 209 | const output = await runPythonScript(scriptPath, args); 210 | 211 | return { 212 | ["output" as PortId]: { 213 | type: "string", 214 | value: output, 215 | }, 216 | }; 217 | }, 218 | }; 219 | 220 | // Once a node is defined, you must pass it to rivet.pluginNodeDefinition, which will return a valid 221 | // PluginNodeDefinition object. 222 | const nodeDefinition = rivet.pluginNodeDefinition( 223 | nodeImpl, 224 | "Run Python Script" 225 | ); 226 | 227 | // This definition should then be used in the `register` function of your plugin definition. 228 | return nodeDefinition; 229 | } 230 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "module": "ESNext", 5 | "moduleResolution": "bundler", 6 | "esModuleInterop": true, 7 | "forceConsistentCasingInFileNames": true, 8 | "strict": true, 9 | "skipLibCheck": true, 10 | "noEmit": true 11 | } 12 | } 13 | --------------------------------------------------------------------------------