@hyperdrive.bot/fleet-server 0.3.157 → 0.3.158
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/server/utils/git-command-cache.d.ts +67 -0
- package/dist/server/utils/git-command-cache.js +436 -0
- package/dist/server/utils/run-git-command.js +14 -4
- package/dist/server/utils/spawn-broker-child.mjs +156 -0
- package/dist/server/utils/spawn-broker.d.ts +120 -0
- package/dist/server/utils/spawn-broker.js +299 -0
- package/dist/server/utils/spawn.d.ts +21 -0
- package/dist/server/utils/spawn.js +144 -10
- package/dist/server/web-ui/_expo/static/js/web/{index-7ca8a9a256b79485a77556fab01588ca.js → index-461552a3716a48e99f87634c93c7b220.js} +4 -4
- package/dist/server/web-ui/_expo/static/js/web/index-461552a3716a48e99f87634c93c7b220.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/index-461552a3716a48e99f87634c93c7b220.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/{index-7ca8a9a256b79485a77556fab01588ca.js.map.br → index-461552a3716a48e99f87634c93c7b220.js.map.br} +0 -0
- package/dist/server/web-ui/_expo/static/js/web/{index-7ca8a9a256b79485a77556fab01588ca.js.map.gz → index-461552a3716a48e99f87634c93c7b220.js.map.gz} +0 -0
- package/dist/server/web-ui/index.html +1 -1
- package/dist/server/web-ui/index.html.br +0 -0
- package/dist/server/web-ui/index.html.gz +0 -0
- package/dist/src/utils/spawn-broker-child.mjs +156 -0
- package/dist/src/utils/spawn-broker.js +299 -0
- package/dist/src/utils/spawn.js +144 -10
- package/package.json +8 -8
- package/dist/server/web-ui/_expo/static/js/web/index-7ca8a9a256b79485a77556fab01588ca.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/index-7ca8a9a256b79485a77556fab01588ca.js.gz +0 -0
|
@@ -2,6 +2,7 @@ import { execFile, spawn } from "node:child_process";
|
|
|
2
2
|
import { extname } from "node:path";
|
|
3
3
|
import { promisify } from "node:util";
|
|
4
4
|
import { createExternalCommandProcessEnv } from "../server/paseo-env.js";
|
|
5
|
+
import { getSharedSpawnBroker, isSpawnBrokerEnabled, } from "./spawn-broker.js";
|
|
5
6
|
import { isWindowsCommandScript, quoteWindowsArgument, quoteWindowsCommand, } from "./windows-command.js";
|
|
6
7
|
const execFileAsync = promisify(execFile);
|
|
7
8
|
function hasPathSeparator(value) {
|
|
@@ -16,17 +17,21 @@ function shouldUseWindowsShell(command, requestedShell) {
|
|
|
16
17
|
}
|
|
17
18
|
return process.platform === "win32" && !hasPathSeparator(command) && !extname(command);
|
|
18
19
|
}
|
|
19
|
-
|
|
20
|
-
const { baseEnv, env, envOverlay
|
|
20
|
+
function resolveChildEnv(command, options) {
|
|
21
|
+
const { baseEnv, env, envOverlay } = options ?? {};
|
|
21
22
|
const resolvedBaseEnv = env ?? baseEnv ?? process.env;
|
|
23
|
+
return options?.envMode === "internal"
|
|
24
|
+
? { ...resolvedBaseEnv, ...envOverlay }
|
|
25
|
+
: createExternalCommandProcessEnv(command, resolvedBaseEnv, ...(envOverlay ? [envOverlay] : []));
|
|
26
|
+
}
|
|
27
|
+
export function spawnProcess(command, args, options) {
|
|
28
|
+
const { baseEnv: _baseEnv, env: _env, envOverlay: _envOverlay, ...spawnOptions } = options ?? {};
|
|
22
29
|
const isWindows = process.platform === "win32";
|
|
23
30
|
const shell = shouldUseWindowsShell(command, spawnOptions.shell);
|
|
24
31
|
const shouldQuoteForShell = isWindows && shell !== false;
|
|
25
32
|
const resolvedCommand = shouldQuoteForShell ? quoteWindowsCommand(command) : command;
|
|
26
33
|
const resolvedArgs = shouldQuoteForShell ? args.map(quoteWindowsArgument) : args;
|
|
27
|
-
const childEnv = options
|
|
28
|
-
? { ...resolvedBaseEnv, ...envOverlay }
|
|
29
|
-
: createExternalCommandProcessEnv(command, resolvedBaseEnv, ...(envOverlay ? [envOverlay] : []));
|
|
34
|
+
const childEnv = resolveChildEnv(command, options);
|
|
30
35
|
return spawn(resolvedCommand, resolvedArgs, {
|
|
31
36
|
...spawnOptions,
|
|
32
37
|
env: childEnv,
|
|
@@ -34,17 +39,53 @@ export function spawnProcess(command, args, options) {
|
|
|
34
39
|
windowsHide: true,
|
|
35
40
|
});
|
|
36
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Spawn a short-lived command whose stdin is ignored and whose stdout/stderr are
|
|
44
|
+
* piped. Runs through the spawn broker helper process when available (so the
|
|
45
|
+
* daemon does not fork its own large image), and falls back to spawnProcess.
|
|
46
|
+
* Use spawnProcess instead when you need stdin, detached, a pty or a real
|
|
47
|
+
* ChildProcess handle.
|
|
48
|
+
*/
|
|
49
|
+
export function spawnNonInteractive(command, args, options) {
|
|
50
|
+
const direct = () => spawnProcess(command, args, {
|
|
51
|
+
cwd: options?.cwd,
|
|
52
|
+
env: options?.env,
|
|
53
|
+
baseEnv: options?.baseEnv,
|
|
54
|
+
envOverlay: options?.envOverlay,
|
|
55
|
+
envMode: options?.envMode,
|
|
56
|
+
shell: options?.shell,
|
|
57
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
58
|
+
});
|
|
59
|
+
const shell = shouldUseWindowsShell(command, options?.shell);
|
|
60
|
+
if (!isSpawnBrokerEnabled() || shell !== false) {
|
|
61
|
+
return direct();
|
|
62
|
+
}
|
|
63
|
+
return getSharedSpawnBroker().spawn({
|
|
64
|
+
command,
|
|
65
|
+
args,
|
|
66
|
+
cwd: options?.cwd,
|
|
67
|
+
env: resolveChildEnv(command, options),
|
|
68
|
+
shell: false,
|
|
69
|
+
maxStdoutBytes: options?.maxStdoutBytes,
|
|
70
|
+
maxStderrBytes: options?.maxStderrBytes,
|
|
71
|
+
}, direct, { retryOnDirect: options?.retryOnDirect ?? false });
|
|
72
|
+
}
|
|
73
|
+
const DEFAULT_EXEC_MAX_BUFFER = 1024 * 1024;
|
|
37
74
|
export async function execCommand(command, args, options) {
|
|
38
|
-
const { baseEnv, env, envOverlay } = options ?? {};
|
|
39
|
-
const resolvedBaseEnv = env ?? baseEnv ?? process.env;
|
|
40
75
|
const isWindows = process.platform === "win32";
|
|
41
76
|
const shell = shouldUseWindowsShell(command, options?.shell);
|
|
42
77
|
const shouldQuoteForShell = isWindows && shell !== false;
|
|
78
|
+
if (!isSpawnBrokerEnabled() || shell !== false || shouldQuoteForShell) {
|
|
79
|
+
return execCommandDirect(command, args, options, shell);
|
|
80
|
+
}
|
|
81
|
+
return execCommandNonInteractive(command, args, options);
|
|
82
|
+
}
|
|
83
|
+
function execCommandDirect(command, args, options, shell) {
|
|
84
|
+
const isWindows = process.platform === "win32";
|
|
85
|
+
const shouldQuoteForShell = isWindows && shell !== false;
|
|
43
86
|
const resolvedCommand = shouldQuoteForShell ? quoteWindowsCommand(command) : command;
|
|
44
87
|
const resolvedArgs = shouldQuoteForShell ? args.map(quoteWindowsArgument) : args;
|
|
45
|
-
const childEnv = options
|
|
46
|
-
? { ...resolvedBaseEnv, ...envOverlay }
|
|
47
|
-
: createExternalCommandProcessEnv(command, resolvedBaseEnv, ...(envOverlay ? [envOverlay] : []));
|
|
88
|
+
const childEnv = resolveChildEnv(command, options);
|
|
48
89
|
return execFileAsync(resolvedCommand, resolvedArgs, {
|
|
49
90
|
cwd: options?.cwd,
|
|
50
91
|
env: childEnv,
|
|
@@ -56,6 +97,99 @@ export async function execCommand(command, args, options) {
|
|
|
56
97
|
windowsHide: true,
|
|
57
98
|
});
|
|
58
99
|
}
|
|
100
|
+
/**
|
|
101
|
+
* execFile semantics (timeout + killSignal, maxBuffer, "Command failed" errors
|
|
102
|
+
* carrying code/killed/signal/stdout/stderr) on top of spawnNonInteractive.
|
|
103
|
+
*/
|
|
104
|
+
function execCommandNonInteractive(command, args, options) {
|
|
105
|
+
const encoding = options?.encoding ?? "utf8";
|
|
106
|
+
const maxBuffer = options?.maxBuffer ?? DEFAULT_EXEC_MAX_BUFFER;
|
|
107
|
+
const killSignal = options?.killSignal ?? "SIGTERM";
|
|
108
|
+
const cmd = [command, ...args].join(" ");
|
|
109
|
+
return new Promise((resolve, reject) => {
|
|
110
|
+
const child = spawnNonInteractive(command, args, {
|
|
111
|
+
cwd: options?.cwd,
|
|
112
|
+
env: options?.env,
|
|
113
|
+
baseEnv: options?.baseEnv,
|
|
114
|
+
envOverlay: options?.envOverlay,
|
|
115
|
+
envMode: options?.envMode,
|
|
116
|
+
shell: false,
|
|
117
|
+
// One byte over the cap so the overflow is still detected here.
|
|
118
|
+
maxStdoutBytes: maxBuffer + 1,
|
|
119
|
+
maxStderrBytes: maxBuffer + 1,
|
|
120
|
+
});
|
|
121
|
+
const stdoutChunks = [];
|
|
122
|
+
const stderrChunks = [];
|
|
123
|
+
let stdoutLength = 0;
|
|
124
|
+
let stderrLength = 0;
|
|
125
|
+
let killed = false;
|
|
126
|
+
let settled = false;
|
|
127
|
+
let exError = null;
|
|
128
|
+
let timer;
|
|
129
|
+
const decode = (chunks) => Buffer.concat(chunks).toString(encoding);
|
|
130
|
+
const kill = () => {
|
|
131
|
+
killed = true;
|
|
132
|
+
try {
|
|
133
|
+
child.kill(killSignal);
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
exError = error;
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
const finish = (code, signal) => {
|
|
140
|
+
if (settled)
|
|
141
|
+
return;
|
|
142
|
+
settled = true;
|
|
143
|
+
if (timer)
|
|
144
|
+
clearTimeout(timer);
|
|
145
|
+
const stdout = decode(stdoutChunks);
|
|
146
|
+
const stderr = decode(stderrChunks);
|
|
147
|
+
if (!exError && code === 0 && signal === null) {
|
|
148
|
+
resolve({ stdout, stderr });
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
const error = exError ?? new Error(`Command failed: ${cmd}\n${stderr}`);
|
|
152
|
+
if (!exError) {
|
|
153
|
+
error.code = code !== null && code < 0 ? String(code) : code;
|
|
154
|
+
error.killed = killed;
|
|
155
|
+
error.signal = signal;
|
|
156
|
+
}
|
|
157
|
+
error.cmd = cmd;
|
|
158
|
+
error.stdout = stdout;
|
|
159
|
+
error.stderr = stderr;
|
|
160
|
+
reject(error);
|
|
161
|
+
};
|
|
162
|
+
const onData = (chunks, stream) => (chunk) => {
|
|
163
|
+
if (settled)
|
|
164
|
+
return;
|
|
165
|
+
const length = stream === "stdout" ? stdoutLength : stderrLength;
|
|
166
|
+
const room = maxBuffer - length;
|
|
167
|
+
if (chunk.length > room) {
|
|
168
|
+
chunks.push(chunk.subarray(0, Math.max(0, room)));
|
|
169
|
+
const error = new RangeError(`${stream} maxBuffer length exceeded`);
|
|
170
|
+
error.code = "ERR_CHILD_PROCESS_STDIO_MAXBUFFER";
|
|
171
|
+
exError = error;
|
|
172
|
+
kill();
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
chunks.push(chunk);
|
|
176
|
+
if (stream === "stdout")
|
|
177
|
+
stdoutLength += chunk.length;
|
|
178
|
+
else
|
|
179
|
+
stderrLength += chunk.length;
|
|
180
|
+
};
|
|
181
|
+
child.stdout?.on("data", onData(stdoutChunks, "stdout"));
|
|
182
|
+
child.stderr?.on("data", onData(stderrChunks, "stderr"));
|
|
183
|
+
child.on("error", (error) => {
|
|
184
|
+
exError = error;
|
|
185
|
+
finish(null, null);
|
|
186
|
+
});
|
|
187
|
+
child.on("close", (code, signal) => finish(code, signal));
|
|
188
|
+
if (options?.timeout && options.timeout > 0) {
|
|
189
|
+
timer = setTimeout(kill, options.timeout);
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
}
|
|
59
193
|
export function platformShell() {
|
|
60
194
|
if (process.platform === "win32") {
|
|
61
195
|
return { command: "cmd.exe", flag: ["/c"] };
|
|
@@ -849,7 +849,7 @@ __d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,"__esModule",{v
|
|
|
849
849
|
__d(function(g,r,i,a,m,e,d){"use strict";var t=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(e,"__esModule",{value:!0}),e.shouldAppendSitemap=u,e.shouldAppendNotFound=s,e.getRootStackRouteNames=function(){const t=[n.INTERNAL_SLOT_NAME];s()&&t.push(n.NOT_FOUND_ROUTE_NAME);u()&&t.push(n.SITEMAP_ROUTE_NAME);return t};const o=t(r(d[0])),n=r(d[1]);function u(){const t=o.default.expoConfig?.extra?.router;return!1!==t?.sitemap}function s(){const t=o.default.expoConfig?.extra?.router;return!1!==t?.notFound}},717,[718,721]);
|
|
850
850
|
__d(function(g,r,i,a,m,_e,d){"use strict";function e(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(_e,'__esModule',{value:!0}),Object.defineProperty(_e,"default",{enumerable:!0,get:function(){return N}}),Object.defineProperty(_e,"AppOwnership",{enumerable:!0,get:function(){return l.AppOwnership}}),Object.defineProperty(_e,"ExecutionEnvironment",{enumerable:!0,get:function(){return l.ExecutionEnvironment}}),Object.defineProperty(_e,"UserInterfaceIdiom",{enumerable:!0,get:function(){return l.UserInterfaceIdiom}});var n=e(r(d[0])),t=r(d[1]);r(d[2]);var u=e(r(d[3])),l=r(d[4]),o=e(r(d[5]));o.default||console.warn("No native ExponentConstants module found, are you sure the expo-constants's module is linked properly?");const s=(0,t.requireOptionalNativeModule)('ExpoUpdates');let f=null;if(s){let e;s.manifest?e=s.manifest:s.manifestString&&(e=JSON.parse(s.manifestString)),e&&Object.keys(e).length>0&&(f=e)}let c=null;if(u.default.EXDevLauncher){let e;u.default.EXDevLauncher.manifestString&&(e=JSON.parse(u.default.EXDevLauncher.manifestString)),e&&Object.keys(e).length>0&&(c=e)}let p=null;if(o.default&&o.default.manifest){const e=o.default.manifest;p='string'==typeof e?JSON.parse(e):e}let b=f??c??p;const E=o.default||{},{appOwnership:O}=E,x=(0,n.default)(E,["name","appOwnership"]),v=Object.assign({},x,{appOwnership:O??null});function _(e){return!h(e)}function h(e){return'metadata'in e}function S(e=!1){if(!b){const e=null===b?'null':'undefined';if(x.executionEnvironment,l.ExecutionEnvironment.Bare,x.executionEnvironment===l.ExecutionEnvironment.StoreClient||x.executionEnvironment===l.ExecutionEnvironment.Standalone)throw new t.CodedError('ERR_CONSTANTS_MANIFEST_UNAVAILABLE',`Constants.manifest is ${e}, must be an object.`)}return b}Object.defineProperties(v,{__unsafeNoWarnManifest:{get(){const e=S(!0);return e&&_(e)?e:null},enumerable:!1},__unsafeNoWarnManifest2:{get(){const e=S(!0);return e&&h(e)?e:null},enumerable:!1},manifest:{get(){const e=S();return e&&_(e)?e:null},enumerable:!0},manifest2:{get(){const e=S();return e&&h(e)?e:null},enumerable:!0},expoConfig:{get(){const e=S(!0);return e?s&&s.isEmbeddedLaunch?p:h(e)?e.extra?.expoClient??null:_(e)?e:null:null},enumerable:!0},expoGoConfig:{get(){const e=S(!0);return e?h(e)?e.extra?.expoGo??null:_(e)?e:null:null},enumerable:!0},easConfig:{get(){const e=S(!0);return e?h(e)?e.extra?.eas??null:_(e)?e:null:null},enumerable:!0},__rawManifest_TEST:{get:()=>b,set(e){b=e},enumerable:!1}});var N=v},718,[35,4,25,637,719,720]);
|
|
851
851
|
__d(function(g,r,i,a,m,e,d){"use strict";var t,n,o;Object.defineProperty(e,'__esModule',{value:!0}),Object.defineProperty(e,"AppOwnership",{enumerable:!0,get:function(){return t}}),Object.defineProperty(e,"ExecutionEnvironment",{enumerable:!0,get:function(){return n}}),Object.defineProperty(e,"UserInterfaceIdiom",{enumerable:!0,get:function(){return o}}),(function(t){t.Expo="expo"})(t||(t={})),(function(t){t.Bare="bare",t.Standalone="standalone",t.StoreClient="storeClient"})(n||(n={})),(function(t){t.Handset="handset",t.Tablet="tablet",t.Desktop="desktop",t.TV="tv",t.Unsupported="unsupported"})(o||(o={}))},719,[]);
|
|
852
|
-
__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),Object.defineProperty(e,"default",{enumerable:!0,get:function(){return s}});var t=r(d[0]);const n=(Date.now()+'-'+Math.floor(1e9*Math.random())).toString();function o(){if('undefined'!=typeof navigator&&'string'==typeof navigator.userAgent){const t=navigator.userAgent.toLowerCase();if(t.includes('edge'))return'Edge';if(t.includes('edg'))return'Chromium Edge';if(t.includes('opr')&&'opr'in window&&window.opr)return'Opera';if(t.includes('chrome')&&'chrome'in window&&window.chrome)return'Chrome';if(t.includes('trident'))return'IE';if(t.includes('firefox'))return'Firefox';if(t.includes('safari'))return'Safari'}}var s={get appOwnership(){return null},get executionEnvironment(){return t.ExecutionEnvironment.Bare},get sessionId(){return n},get isHeadless(){return'undefined'==typeof navigator||/\bHeadlessChrome\//.test(navigator.userAgent)},get expoVersion(){return this.manifest.sdkVersion||null},get linkingUri(){return'undefined'!=typeof location?location.origin:''},get expoRuntimeVersion(){return this.expoVersion},get deviceName(){return o()},get systemFonts(){return[]},get statusBarHeight(){return 0},get deviceYearClass(){return null},get manifest(){return"{\"name\":\"Paseo\",\"slug\":\"paseo-hyperdrive\",\"version\":\"0.3.
|
|
852
|
+
__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),Object.defineProperty(e,"default",{enumerable:!0,get:function(){return s}});var t=r(d[0]);const n=(Date.now()+'-'+Math.floor(1e9*Math.random())).toString();function o(){if('undefined'!=typeof navigator&&'string'==typeof navigator.userAgent){const t=navigator.userAgent.toLowerCase();if(t.includes('edge'))return'Edge';if(t.includes('edg'))return'Chromium Edge';if(t.includes('opr')&&'opr'in window&&window.opr)return'Opera';if(t.includes('chrome')&&'chrome'in window&&window.chrome)return'Chrome';if(t.includes('trident'))return'IE';if(t.includes('firefox'))return'Firefox';if(t.includes('safari'))return'Safari'}}var s={get appOwnership(){return null},get executionEnvironment(){return t.ExecutionEnvironment.Bare},get sessionId(){return n},get isHeadless(){return'undefined'==typeof navigator||/\bHeadlessChrome\//.test(navigator.userAgent)},get expoVersion(){return this.manifest.sdkVersion||null},get linkingUri(){return'undefined'!=typeof location?location.origin:''},get expoRuntimeVersion(){return this.expoVersion},get deviceName(){return o()},get systemFonts(){return[]},get statusBarHeight(){return 0},get deviceYearClass(){return null},get manifest(){return"{\"name\":\"Paseo\",\"slug\":\"paseo-hyperdrive\",\"version\":\"0.3.158\",\"orientation\":\"portrait\",\"icon\":\"./assets/images/icon.png\",\"scheme\":\"paseo\",\"userInterfaceStyle\":\"automatic\",\"newArchEnabled\":true,\"web\":{\"output\":\"single\",\"favicon\":\"./assets/images/favicon.png\",\"shortName\":\"Paseo\",\"orientation\":\"portrait\",\"name\":\"Paseo\"},\"autolinking\":{\"searchPaths\":[\"../../node_modules\",\"./node_modules\"]},\"experiments\":{\"typedRoutes\":true,\"reactCompiler\":true,\"autolinkingModuleResolution\":true},\"extra\":{\"router\":{},\"eas\":{\"build\":{\"experimental\":{\"ios\":{\"appExtensions\":[{\"bundleIdentifier\":\"bot.hyperdrive.paseo.AgentActivity\",\"targetName\":\"AgentActivity\"}]}}}}},\"sdkVersion\":\"54.0.0\",\"platforms\":[\"ios\",\"android\",\"web\"]}"},get manifest2(){return null},get experienceUrl(){return'undefined'!=typeof location?location.origin:''},get debugMode(){return!1},getWebViewUserAgentAsync:async()=>'undefined'!=typeof navigator?navigator.userAgent:null}},720,[719]);
|
|
853
853
|
__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.SITEMAP_ROUTE_NAME=e.NOT_FOUND_ROUTE_NAME=e.INTERNAL_SLOT_NAME=void 0,e.INTERNAL_SLOT_NAME='__root',e.NOT_FOUND_ROUTE_NAME='+not-found',e.SITEMAP_ROUTE_NAME='_sitemap'},721,[]);
|
|
854
854
|
__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.resolveHref=void 0,e.resolveHrefStringWithSegments=function(t,{segments:n=[],params:s={}}={},{relativeToDirectory:o}={}){if(t.startsWith('.')){let c=n?.map(t=>{if(!t.startsWith('['))return t;if(t.startsWith('[...')){t=t.slice(4,-1);const n=s[t];return Array.isArray(n)?n.join('/'):n?.split(',')?.join('/')??''}return t=t.slice(1,-1),s[t]}).filter(Boolean).join('/')??'/';o&&(c=`${c}/`);const f=new URL(t,`http://hostname/${c}`);t=`${f.pathname}${f.search}`}return t};function t(t,s){for(const[o,c=""]of Object.entries(s)){const f=`[${o}]`,l=`[...${o}]`;if(t.includes(f))t=t.replace(f,n(c));else{if(!t.includes(l))continue;t=t.replace(l,n(c))}delete s[o]}return{pathname:t,params:s}}function n(t){return Array.isArray(t)?t.map(t=>n(t)).join('/'):encodeURIComponent(t.toString())}function s(t){return Object.entries(t).filter(([,t])=>null!=t).map(([t,n])=>`${t}=${encodeURIComponent(n.toString())}`).join('&')}e.resolveHref=n=>{if('string'==typeof n)return(0,e.resolveHref)({pathname:n});const o=n.pathname??'';if(!n?.params)return o;const{pathname:c,params:f}=t(o,Object.assign({},n.params)),l=s(f);return c+(l?`?${l}`:'')}},722,[]);
|
|
855
855
|
__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.isRoutePreloadedInStack=function(t,o){if(!t||'stack'!==t.type)return!1;return t.preloadedRoutes.some(t=>t.key===o.key)}},723,[]);
|
|
@@ -15057,7 +15057,7 @@ __d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{v
|
|
|
15057
15057
|
__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),Object.defineProperty(e,"decodeOfferFragmentPayload",{enumerable:!0,get:function(){return n.decodeOfferFragmentPayload}}),Object.defineProperty(e,"buildDaemonWebSocketUrl",{enumerable:!0,get:function(){return t.buildDaemonWebSocketUrl}}),Object.defineProperty(e,"deriveLabelFromEndpoint",{enumerable:!0,get:function(){return t.deriveLabelFromEndpoint}}),Object.defineProperty(e,"extractHostPortFromWebSocketUrl",{enumerable:!0,get:function(){return t.extractHostPortFromWebSocketUrl}}),Object.defineProperty(e,"normalizeHostPort",{enumerable:!0,get:function(){return t.normalizeHostPort}}),Object.defineProperty(e,"parseConnectionUri",{enumerable:!0,get:function(){return t.parseConnectionUri}}),Object.defineProperty(e,"parseHostPort",{enumerable:!0,get:function(){return t.parseHostPort}}),Object.defineProperty(e,"serializeConnectionUri",{enumerable:!0,get:function(){return t.serializeConnectionUri}}),Object.defineProperty(e,"serializeConnectionUriForStorage",{enumerable:!0,get:function(){return t.serializeConnectionUriForStorage}}),Object.defineProperty(e,"shouldUseTlsForDefaultHostedRelay",{enumerable:!0,get:function(){return t.shouldUseTlsForDefaultHostedRelay}}),e.buildRelayWebSocketUrl=function(n){return(0,t.buildRelayWebSocketUrl)(Object.assign({},n,{role:"client"}))};var t=r(d[0]),n=r(d[1])},3412,[3392,3413]);
|
|
15058
15058
|
__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),Object.defineProperty(e,"ConnectionOfferV2Schema",{enumerable:!0,get:function(){return t}}),Object.defineProperty(e,"ConnectionOfferSchema",{enumerable:!0,get:function(){return o}}),e.decodeOfferFragmentPayload=l,e.parseConnectionOfferFromUrl=function(n){const t=f(n);if(!t)return null;const c=l(t);return o.parse(c)};var n=r(d[0]);const t=n.z.object({v:n.z.literal(2),serverId:n.z.string().min(1),daemonPublicKeyB64:n.z.string().min(1),relay:n.z.object({endpoint:n.z.string().min(1),useTls:n.z.boolean().optional()})}),o=t;function c(n){const t=n.replace(/-/g,"+").replace(/_/g,"/"),o=t.padEnd(t.length+(4-t.length%4)%4,"="),c=globalThis.atob(o),l=Uint8Array.from(c,n=>n.charCodeAt(0));return new TextDecoder("utf-8",{fatal:!0}).decode(l)}function l(n){const t=c(n);return JSON.parse(t)}const u="#offer=";function f(n){const t=n.trim();if(!t)return null;const o=t.indexOf(u);if(-1===o)return null;const c=t.slice(o+u.length).trim();return c.length>0?c:null}},3413,[3285]);
|
|
15059
15059
|
__d(function(g,r,i,a,m,_e,d){"use strict";function e(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(_e,'__esModule',{value:!0}),_e.resolveAppVersion=function(){const e=u(t.default?.version);if(e)return e;const o=u(n.default.expoConfig?.version);if(o)return o;const f=u(n.default.manifest?.version);if(f)return f;return null};var n=e(r(d[0])),t=e(r(d[1]));function u(e){if("string"!=typeof e)return null;const n=e.trim();return 0===n.length?null:n}},3414,[718,3415]);
|
|
15060
|
-
__d(function(e,t,r,a,o,i,n){o.exports={name:"@hyperdrive.bot/fleet-app",version:"0.3.
|
|
15060
|
+
__d(function(e,t,r,a,o,i,n){o.exports={name:"@hyperdrive.bot/fleet-app",version:"0.3.158",private:!0,main:"index.ts",scripts:{start:"npm run start:expo","start:expo":"cross-env APP_VARIANT=development expo start","reset-project":"node ./scripts/reset-project.js","build:terminal-webview":"node ./scripts/build-terminal-webview-html.mjs","eas-build-post-install":"npm --prefix ../.. run build:app-deps && npm run build:terminal-webview",android:"npm run android:development","android:development":"npm --prefix ../.. run build:client && cross-env APP_VARIANT=development expo prebuild --platform android --non-interactive && cross-env APP_VARIANT=development expo run:android --variant=debug","android:production":"npm --prefix ../.. run build:client && cross-env APP_VARIANT=production expo prebuild --platform android --non-interactive && cross-env APP_VARIANT=production expo run:android --variant=release","android:release":"npm run android:production","android:clear":"node -e \"require('node:fs').rmSync('android', { recursive: true, force: true })\"",ios:"npm --prefix ../.. run build:client && expo run:ios","ios:release":"npm --prefix ../.. run build:client && expo run:ios --configuration Release",web:"npm --prefix ../.. run build:client && concurrently --kill-others --names protocol,client,expo --prefix-colors yellow,blue,magenta \"npm --prefix ../.. run watch:protocol\" \"npm --prefix ../.. run watch:client\" \"npm run web:expo\"","web:expo":"expo start --web",lint:"expo lint",typecheck:"tsgo --noEmit",test:"vitest run","test:browser":"vitest run --project browser","test:e2e":"playwright test --project='Desktop Chrome'","test:e2e:reels":"cross-env NODE_ENV=development playwright test --config playwright.reels.config.ts","test:e2e:real":"cross-env E2E_FORK_PASEO_HOME_FROM=../../.dev/paseo-home playwright test --project=real-provider","test:e2e:ui":"playwright test --ui","test:coverage":"vitest run --project unit --coverage",build:"npm run build:web","build:web":"npm --prefix ../.. run build:app-deps && expo export --platform web --source-maps","profile:workspace-tabs":"node ./scripts/profile-workspace-tabs.mjs","deploy:web":"npm run build:web && wrangler pages deploy dist --project-name paseo-app --branch main"},dependencies:{"@bacons/apple-targets":"4.0.6","@datadog/browser-rum":"^6.23.0","@datadog/browser-rum-react":"^6.23.0","@datadog/mobile-react-native":"^2.7.0","@datadog/mobile-react-native-session-replay":"^2.14.8","@dnd-kit/core":"^6.3.1","@dnd-kit/sortable":"^10.0.0","@dnd-kit/utilities":"^3.2.2","@expo/image-utils":"0.8.8","@expo/plist":"0.4.9","@expo/prebuild-config":"54.0.8","@floating-ui/react-native":"^0.10.7","@gorhom/bottom-sheet":"^5.2.14","@gorhom/portal":"^1.0.14","@hyperdrive.bot/fleet-client":"*","@hyperdrive.bot/fleet-expo-two-way-audio":"*","@hyperdrive.bot/fleet-extension-sdk":"*","@hyperdrive.bot/fleet-highlight":"*","@react-native-async-storage/async-storage":"2.2.0","@react-native-masked-view/masked-view":"^0.3.2","@react-native/normalize-colors":"^0.81.5","@react-navigation/native":"^7.1.8","@sentry/electron":"^6.11.0","@sentry/react-native":"^6.20.0","@tanstack/react-query":"^5.90.11","@tanstack/react-virtual":"^3.13.21","@xterm/addon-clipboard":"^0.3.0-beta.213","@xterm/addon-fit":"^0.12.0-beta.213","@xterm/addon-image":"^0.10.0-beta.213","@xterm/addon-ligatures":"0.11.0-beta.213","@xterm/addon-search":"^0.17.0-beta.213","@xterm/addon-unicode11":"^0.10.0-beta.213","@xterm/addon-web-links":"^0.13.0-beta.213","@xterm/addon-webgl":"^0.20.0-beta.212","@xterm/xterm":"^6.1.0-beta.213",buffer:"^6.0.3",expo:"^54.0.18","expo-asset":"~12.0.12","expo-audio":"~1.0.13","expo-background-fetch":"~14.0.9","expo-build-properties":"^1.0.9","expo-camera":"~17.0.10","expo-clipboard":"~8.0.7","expo-constants":"~18.0.9","expo-crypto":"^15.0.8","expo-dev-client":"^6.0.15","expo-document-picker":"~14.0.8","expo-file-system":"~19.0.17","expo-haptics":"~15.0.7","expo-image":"~3.0.10","expo-image-manipulator":"~14.0.8","expo-image-picker":"^17.0.8","expo-keep-awake":"^15.0.7","expo-linking":"~8.0.8","expo-localization":"~17.0.9","expo-notifications":"^0.32.16","expo-router":"~6.0.13","expo-sharing":"^14.0.8","expo-speech":"~14.0.8","expo-speech-recognition":"^56.0.1","expo-splash-screen":"~31.0.10","expo-system-ui":"~6.0.7","expo-task-manager":"~14.0.9","expo-video":"~3.0.16","fast-deep-equal":"^3.1.3",htmlparser2:"^12.0.0",i18next:"^26.3.0","lucide-react-native":"^0.546.0","markdown-it":"^10.0.0","mnemonic-id":"^3.2.7","posthog-js":"^1.431.2","posthog-react-native":"^4.72.0",qrcode:"^1.5.4",react:"19.1.0","react-dom":"19.1.0","react-i18next":"^17.0.8","react-native":"0.81.5","react-native-draggable-flatlist":"^4.0.3","react-native-edge-to-edge":"^1.7.0","react-native-gesture-handler":"~2.28.0","react-native-keyboard-controller":"^1.21.7","react-native-markdown-display":"^7.0.2","react-native-nitro-modules":"0.35.5","react-native-reanimated":"~4.3.1","react-native-safe-area-context":"~5.6.0","react-native-screens":"~4.16.0","react-native-svg":"^15.14.0","react-native-uitextview":"^2.2.0","react-native-unistyles":"^3.2.4","react-native-web":"~0.21.0","react-native-webview":"^13.16.0","react-native-worklets":"~0.8.3","tiny-invariant":"^1.3.3","use-sync-external-store":"^1.6.0",zod:"^4.4.3",zustand:"^5.0.9"},devDependencies:{"@playwright/test":"^1.56.1","@testing-library/dom":"^10.4.1","@testing-library/react":"^16.3.2","@types/chai":"^5.2.2","@types/markdown-it":"^14.1.2","@types/qrcode":"^1.5.6","@types/react":"~19.2.0","@types/ws":"^8.18.1","@vitest/browser":"^4.1.7","@vitest/browser-playwright":"^4.1.7","@vitest/coverage-v8":"^4.1.7","@xterm/headless":"^6.1.0-beta.213",dotenv:"^17.2.3",eslint:"^9.25.0","eslint-config-expo":"~10.0.0",jsdom:"^20.0.3","material-icon-theme":"^5.32.0",playwright:"^1.56.1","serve-sim":"^0.1.40",typescript:"~5.9.2",vitest:"^4.1.6",wrangler:"^4.105.0",ws:"^8.20.0"}}},3415,[]);
|
|
15061
15061
|
__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.shouldUseDesktopDaemon=function(){return(0,n.isElectronRuntime)()},e.getDesktopDaemonStatus=async function(){return c(await(0,t.invokeDesktopCommand)("desktop_daemon_status"))},e.startDesktopDaemon=async function(){return c(await(0,t.invokeDesktopCommand)("start_desktop_daemon"))},e.stopDesktopDaemon=async function(n="manual_ipc"){return c(await(0,t.invokeDesktopCommand)("stop_desktop_daemon",{reason:n}))},e.restartDesktopDaemon=async function(){return c(await(0,t.invokeDesktopCommand)("restart_desktop_daemon"))},e.getDesktopDaemonLogs=async function(){return p(await(0,t.invokeDesktopCommand)("desktop_daemon_logs"))},e.getDesktopDaemonPairing=async function(){return k(await(0,t.invokeDesktopCommand)("desktop_daemon_pairing"))},e.getCliDaemonStatus=async function(){const n=await(0,t.invokeDesktopCommand)("cli_daemon_status");if("string"!=typeof n)throw new Error("Unexpected CLI daemon status response.");return n},e.listenToLocalTransportEvents=async function(t){const u=(0,n.getDesktopHost)()?.events?.on;if("function"!=typeof u)throw new Error("Desktop events API is unavailable.");const c=await u("local-daemon-transport-event",n=>{o(n)&&t({sessionId:s(n.sessionId)??"",kind:s(n.kind)??"error",text:s(n.text),binaryBase64:s(n.binaryBase64),code:l(n.code),reason:s(n.reason),error:s(n.error)})});return"function"==typeof c?c:()=>{}},e.openLocalTransportSession=async function(n){const o=await(0,t.invokeDesktopCommand)("open_local_daemon_transport",n);if("string"!=typeof o||0===o.trim().length)throw new Error("Unexpected local transport session response.");return o},e.sendLocalTransportMessage=async function(n){await(0,t.invokeDesktopCommand)("send_local_daemon_transport_message",Object.assign({sessionId:n.sessionId},n.text?{text:n.text}:{},n.binaryBase64?{binaryBase64:n.binaryBase64}:{}))},e.closeLocalTransportSession=async function(n){await(0,t.invokeDesktopCommand)("close_local_daemon_transport",{sessionId:n})},e.getCliInstallStatus=async function(){return f(await(0,t.invokeDesktopCommand)("get_cli_install_status"))},e.installCli=async function(){return f(await(0,t.invokeDesktopCommand)("install_cli"))},e.getSkillsStatus=async function(){return y(await(0,t.invokeDesktopCommand)("get_skills_status"))},e.installSkills=async function(){return y(await(0,t.invokeDesktopCommand)("install_skills"))},e.updateSkills=async function(){return y(await(0,t.invokeDesktopCommand)("update_skills"))},e.uninstallSkills=async function(){return y(await(0,t.invokeDesktopCommand)("uninstall_skills"))};var n=r(d[0]),t=r(d[1]);function o(n){return"object"==typeof n&&null!==n}function s(n){return"string"==typeof n&&n.trim().length>0?n:null}function l(n){return"number"==typeof n&&Number.isFinite(n)?n:null}function u(n){const t=s(n)?.toLowerCase();switch(t){case"starting":return"starting";case"running":return"running";case"errored":case"error":return"errored";default:return"stopped"}}function c(n){if(!o(n))throw new Error("Unexpected desktop daemon status response.");return{serverId:s(n.serverId)??"",status:u(n.status),listen:s(n.listen),hostname:s(n.hostname),pid:l(n.pid),home:s(n.home)??"",version:s(n.version),desktopManaged:!0===n.desktopManaged,error:s(n.error)}}function p(n){if(!o(n))throw new Error("Unexpected desktop daemon logs response.");return{logPath:s(n.logPath)??"",contents:"string"==typeof n.contents?n.contents:""}}function k(n){if(!o(n))throw new Error("Unexpected desktop daemon pairing response.");return{relayEnabled:!0===n.relayEnabled,url:s(n.url),qr:s(n.qr)}}function f(n){if(!o(n))throw new Error("Unexpected install status response.");return{installed:!0===n.installed}}function w(n){switch(n){case"not-installed":case"up-to-date":case"drift":return n;default:throw new Error(`Unexpected skills status state: ${String(n)}`)}}function _(n){if(!o(n))throw new Error("Unexpected skill op response.");const t=s(n.name);if(!t)throw new Error("Skill op missing name.");switch(n.kind){case"add":return{kind:"add",name:t};case"update":return{kind:"update",name:t};case"delete":return{kind:"delete",name:t};default:throw new Error(`Unexpected skill op kind: ${String(n.kind)}`)}}function y(n){if(!o(n))throw new Error("Unexpected skills status response.");const t=Array.isArray(n.ops)?n.ops.map(_):[];return{state:w(n.state),ops:t}}},3416,[3417,3419]);
|
|
15062
15062
|
__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.getDesktopHost=n,e.isElectronRuntime=o,e.isElectronRuntimeMac=function(){if(!o())return!1;if("undefined"==typeof navigator)return!1;const t=n()?.platform?.toLowerCase();if("darwin"===t||"mac"===t||"macos"===t)return!0;const u=navigator.userAgent;return u.includes("Mac OS")||u.includes("Macintosh")},r(d[0]);var t=r(d[1]);function n(){return(0,t.getElectronHost)()}function o(){return null!==n()}},3417,[25,3418]);
|
|
15063
15063
|
__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.getElectronHost=function(){if("undefined"==typeof window)return null;const t=window.paseoDesktop;if(!t||"object"!=typeof t)return null;return t}},3418,[]);
|
|
@@ -16708,5 +16708,5 @@ __d(function(g,r,_i,a,_m,_e,d){"use strict";var e,t=r(d[0]),n=this&&this.__creat
|
|
|
16708
16708
|
__r(694);
|
|
16709
16709
|
__r(341);
|
|
16710
16710
|
__r(0);
|
|
16711
|
-
//# sourceMappingURL=/_expo/static/js/web/index-
|
|
16712
|
-
//# debugId=
|
|
16711
|
+
//# sourceMappingURL=/_expo/static/js/web/index-461552a3716a48e99f87634c93c7b220.js.map
|
|
16712
|
+
//# debugId=761b09c0-f320-4cd2-a3d9-075d30b5fbb7
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -191,6 +191,6 @@
|
|
|
191
191
|
<body>
|
|
192
192
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
|
193
193
|
<div id="root"></div>
|
|
194
|
-
<script src="/_expo/static/js/web/index-
|
|
194
|
+
<script src="/_expo/static/js/web/index-461552a3716a48e99f87634c93c7b220.js" defer></script>
|
|
195
195
|
</body>
|
|
196
196
|
</html>
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
// Spawn broker helper process. The daemon forks this small Node process once and
|
|
2
|
+
// asks it to run non-interactive subprocesses (git, gh, which, ...) over IPC, so
|
|
3
|
+
// the daemon itself never forks its multi-GB image: on WSL2 every direct spawn()
|
|
4
|
+
// from the daemon blocked its event loop for about 100ms.
|
|
5
|
+
//
|
|
6
|
+
// Protocol (JSON over the IPC channel):
|
|
7
|
+
// parent -> child { type: "spawn", id, command, args, cwd, env, shell }
|
|
8
|
+
// { type: "kill", id, signal }
|
|
9
|
+
// child -> parent { type: "spawned", id, pid }
|
|
10
|
+
// { type: "data", id, fd: 1 | 2, data: base64 }
|
|
11
|
+
// { type: "error", id, error: { message, code, errno, syscall, path } }
|
|
12
|
+
// { type: "close", id, exitCode, signal }
|
|
13
|
+
//
|
|
14
|
+
// Timeouts, output caps and exit-code policy stay in the parent, which kills the
|
|
15
|
+
// child through the "kill" message exactly like it would kill a direct ChildProcess.
|
|
16
|
+
import { spawn } from "node:child_process";
|
|
17
|
+
|
|
18
|
+
const children = new Map();
|
|
19
|
+
|
|
20
|
+
function send(message) {
|
|
21
|
+
// Returns false when the channel is backed up (or gone; the disconnect handler
|
|
22
|
+
// cleans up in that case).
|
|
23
|
+
return sendRaw(message);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function serializeError(error) {
|
|
27
|
+
return {
|
|
28
|
+
message: error?.message ?? String(error),
|
|
29
|
+
code: error?.code,
|
|
30
|
+
errno: error?.errno,
|
|
31
|
+
syscall: error?.syscall,
|
|
32
|
+
path: error?.path,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const CHUNK_BYTES = 64 * 1024;
|
|
37
|
+
|
|
38
|
+
// Forward a stream in bounded chunks, stop forwarding once the caller's cap is
|
|
39
|
+
// reached (the caller decides whether to kill), and pause the source while the
|
|
40
|
+
// IPC channel is backed up so output never piles up in memory on either side.
|
|
41
|
+
function forward(stream, id, fd, maxBytes) {
|
|
42
|
+
const cap = Number.isFinite(maxBytes) && maxBytes >= 0 ? maxBytes : Infinity;
|
|
43
|
+
let forwarded = 0;
|
|
44
|
+
stream.on("data", (chunk) => {
|
|
45
|
+
if (forwarded >= cap) return;
|
|
46
|
+
const slice = chunk.length > cap - forwarded ? chunk.subarray(0, cap - forwarded) : chunk;
|
|
47
|
+
forwarded += slice.length;
|
|
48
|
+
for (let offset = 0; offset < slice.length; offset += CHUNK_BYTES) {
|
|
49
|
+
const part = slice.subarray(offset, offset + CHUNK_BYTES);
|
|
50
|
+
const ok = send({ type: "data", id, fd, data: part.toString("base64") });
|
|
51
|
+
if (!ok) {
|
|
52
|
+
stream.pause();
|
|
53
|
+
waitForDrain(() => stream.resume());
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const drainWaiters = [];
|
|
60
|
+
function waitForDrain(callback) {
|
|
61
|
+
drainWaiters.push(callback);
|
|
62
|
+
if (drainWaiters.length > 1) return;
|
|
63
|
+
// An empty message's send callback fires once everything queued before it
|
|
64
|
+
// has been written to the channel.
|
|
65
|
+
sendRaw({ type: "noop" }, () => {
|
|
66
|
+
const waiters = drainWaiters.splice(0);
|
|
67
|
+
for (const waiter of waiters) waiter();
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function sendRaw(message, callback) {
|
|
72
|
+
if (!process.connected) return false;
|
|
73
|
+
try {
|
|
74
|
+
return process.send(message, undefined, undefined, callback);
|
|
75
|
+
} catch {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function handleSpawn(message) {
|
|
81
|
+
const { id } = message;
|
|
82
|
+
let child;
|
|
83
|
+
try {
|
|
84
|
+
child = spawn(message.command, message.args, {
|
|
85
|
+
cwd: message.cwd,
|
|
86
|
+
env: message.env,
|
|
87
|
+
shell: message.shell ?? false,
|
|
88
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
89
|
+
windowsHide: true,
|
|
90
|
+
});
|
|
91
|
+
} catch (error) {
|
|
92
|
+
send({ type: "error", id, error: serializeError(error) });
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
children.set(id, child);
|
|
96
|
+
if (child.pid !== undefined) {
|
|
97
|
+
send({ type: "spawned", id, pid: child.pid });
|
|
98
|
+
}
|
|
99
|
+
forward(child.stdout, id, 1, message.maxStdoutBytes);
|
|
100
|
+
forward(child.stderr, id, 2, message.maxStderrBytes);
|
|
101
|
+
child.on("error", (error) => {
|
|
102
|
+
children.delete(id);
|
|
103
|
+
send({ type: "error", id, error: serializeError(error) });
|
|
104
|
+
});
|
|
105
|
+
child.on("close", (exitCode, signal) => {
|
|
106
|
+
children.delete(id);
|
|
107
|
+
send({ type: "close", id, exitCode, signal });
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function killAll() {
|
|
112
|
+
for (const child of children.values()) {
|
|
113
|
+
try {
|
|
114
|
+
child.kill("SIGKILL");
|
|
115
|
+
} catch {
|
|
116
|
+
// already gone
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
children.clear();
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
process.on("message", (message) => {
|
|
123
|
+
if (!message || typeof message !== "object") return;
|
|
124
|
+
if (message.type === "spawn") {
|
|
125
|
+
handleSpawn(message);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
if (message.type === "kill") {
|
|
129
|
+
const child = children.get(message.id);
|
|
130
|
+
if (child) {
|
|
131
|
+
try {
|
|
132
|
+
child.kill(message.signal ?? "SIGTERM");
|
|
133
|
+
} catch {
|
|
134
|
+
// already gone
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
if (message.type === "crash-for-test" && process.env.PASEO_SPAWN_BROKER_TEST_HOOKS === "1") {
|
|
140
|
+
process.exit(1);
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
// The daemon owns us: when its IPC channel closes (clean shutdown or crash) we take
|
|
145
|
+
// our children down and exit, so nothing is orphaned.
|
|
146
|
+
process.on("disconnect", () => {
|
|
147
|
+
killAll();
|
|
148
|
+
process.exit(0);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
for (const signal of ["SIGTERM", "SIGINT", "SIGHUP"]) {
|
|
152
|
+
process.on(signal, () => {
|
|
153
|
+
killAll();
|
|
154
|
+
process.exit(0);
|
|
155
|
+
});
|
|
156
|
+
}
|