@pixelbyte-software/pixcode 1.41.3 → 1.41.5
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/assets/{index-Bq2twGSW.js → index-BmK4VcVP.js} +52 -52
- package/dist/assets/index-CHa1760s.css +32 -0
- package/dist/index.html +2 -2
- package/dist-server/server/routes/live-view.js +44 -8
- package/dist-server/server/routes/live-view.js.map +1 -1
- package/dist-server/server/services/live-view.js +105 -100
- package/dist-server/server/services/live-view.js.map +1 -1
- package/dist-server/server/services/runtime-manager.js +312 -0
- package/dist-server/server/services/runtime-manager.js.map +1 -0
- package/package.json +2 -1
- package/scripts/smoke/live-view-diagnostics.mjs +2 -2
- package/scripts/smoke/live-view-environment.mjs +92 -0
- package/scripts/smoke/live-view-integration.mjs +58 -46
- package/scripts/smoke/runtime-manager.mjs +99 -0
- package/server/routes/live-view.js +45 -8
- package/server/services/live-view.js +110 -107
- package/server/services/runtime-manager.js +323 -0
- package/dist/assets/index-BC8CXTJj.css +0 -32
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import assert from 'node:assert/strict';
|
|
4
|
+
import fs from 'node:fs';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
|
|
7
|
+
const root = process.cwd();
|
|
8
|
+
|
|
9
|
+
function read(relativePath) {
|
|
10
|
+
return fs.readFileSync(path.join(root, relativePath), 'utf8');
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const managerSource = read('server/services/runtime-manager.js');
|
|
14
|
+
assert.match(managerSource, /RUNTIME_DEFINITIONS/, 'Runtime manager should define a central runtime registry.');
|
|
15
|
+
assert.match(managerSource, /node/, 'Runtime manager should include Node.js.');
|
|
16
|
+
assert.match(managerSource, /php/, 'Runtime manager should include PHP.');
|
|
17
|
+
assert.match(managerSource, /python/, 'Runtime manager should include Python.');
|
|
18
|
+
assert.match(managerSource, /go/, 'Runtime manager should include Go.');
|
|
19
|
+
assert.match(managerSource, /java/, 'Runtime manager should include Java.');
|
|
20
|
+
assert.match(managerSource, /rust/, 'Runtime manager should include Rust.');
|
|
21
|
+
assert.match(managerSource, /discoverRuntime/, 'Runtime manager should expose runtime discovery.');
|
|
22
|
+
assert.match(managerSource, /resolveLiveViewRuntime/, 'Runtime manager should expose Live View runtime resolution.');
|
|
23
|
+
|
|
24
|
+
const liveViewSource = read('server/services/live-view.js');
|
|
25
|
+
assert.match(liveViewSource, /resolveLiveViewRuntime/, 'Live View should route runtime checks through the runtime manager.');
|
|
26
|
+
assert.match(liveViewSource, /runtime:\s*session\.runtime/, 'Live View public session payload should expose runtime diagnostics.');
|
|
27
|
+
assert.ok(
|
|
28
|
+
liveViewSource.includes('target.runtime'),
|
|
29
|
+
'Live View start should keep the runtime manager result on the session.',
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
const {
|
|
33
|
+
discoverRuntime,
|
|
34
|
+
resolveLiveViewRuntime,
|
|
35
|
+
runtimeManager,
|
|
36
|
+
} = await import('../../server/services/runtime-manager.js');
|
|
37
|
+
|
|
38
|
+
assert.equal(typeof runtimeManager.discover, 'function', 'Runtime manager should expose a discover method.');
|
|
39
|
+
|
|
40
|
+
const nodeRuntime = await discoverRuntime('node');
|
|
41
|
+
assert.equal(nodeRuntime.id, 'node');
|
|
42
|
+
assert.equal(nodeRuntime.status, 'available', 'The current Node runtime should be detected as available.');
|
|
43
|
+
assert.ok(nodeRuntime.path, 'Node runtime should include an executable path.');
|
|
44
|
+
assert.match(nodeRuntime.version || '', /\d+\.\d+\.\d+/, 'Node runtime should include a version.');
|
|
45
|
+
|
|
46
|
+
const missingPython = await discoverRuntime('python', {
|
|
47
|
+
strictPath: true,
|
|
48
|
+
env: {
|
|
49
|
+
...process.env,
|
|
50
|
+
PATH: '',
|
|
51
|
+
Path: '',
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
assert.equal(missingPython.status, 'missing', 'Missing Python should produce a missing runtime status.');
|
|
55
|
+
assert.match(missingPython.diagnostic.message, /Python/i, 'Missing Python diagnostics should name the runtime.');
|
|
56
|
+
assert.match(missingPython.diagnostic.action, /python/i, 'Missing Python diagnostics should include an actionable install command.');
|
|
57
|
+
|
|
58
|
+
const nodeLiveRuntime = await resolveLiveViewRuntime({
|
|
59
|
+
id: 'npm-dev-vite',
|
|
60
|
+
label: 'Vite dev server',
|
|
61
|
+
framework: 'Vite',
|
|
62
|
+
command: 'npm',
|
|
63
|
+
args: ['run', 'dev'],
|
|
64
|
+
displayCommand: 'npm run dev',
|
|
65
|
+
packageManager: 'npm',
|
|
66
|
+
}, {
|
|
67
|
+
env: {
|
|
68
|
+
...process.env,
|
|
69
|
+
PATH: '',
|
|
70
|
+
Path: '',
|
|
71
|
+
},
|
|
72
|
+
preferManaged: true,
|
|
73
|
+
});
|
|
74
|
+
assert.equal(nodeLiveRuntime.runtime.id, 'node', 'JavaScript Live View commands should resolve to the Node runtime.');
|
|
75
|
+
assert.equal(nodeLiveRuntime.managedRuntime?.id, 'npm', 'JavaScript Live View commands should keep the managed npm hook.');
|
|
76
|
+
assert.equal(nodeLiveRuntime.available, true, 'Managed npm should keep JavaScript projects runnable when npm is missing.');
|
|
77
|
+
assert.match(nodeLiveRuntime.reason, /Node package runner/i, 'Managed npm diagnostics should explain the package runner.');
|
|
78
|
+
|
|
79
|
+
const phpLiveRuntime = await resolveLiveViewRuntime({
|
|
80
|
+
id: 'php-built-in',
|
|
81
|
+
label: 'PHP built-in server',
|
|
82
|
+
framework: 'PHP',
|
|
83
|
+
command: 'php',
|
|
84
|
+
args: ['-S', '127.0.0.1:$PORT', '-t', '.'],
|
|
85
|
+
displayCommand: 'php -S 127.0.0.1:$PORT -t .',
|
|
86
|
+
}, {
|
|
87
|
+
env: {
|
|
88
|
+
...process.env,
|
|
89
|
+
PATH: '',
|
|
90
|
+
Path: '',
|
|
91
|
+
},
|
|
92
|
+
preferManaged: true,
|
|
93
|
+
});
|
|
94
|
+
assert.equal(phpLiveRuntime.runtime.id, 'php', 'PHP Live View commands should resolve to the PHP runtime.');
|
|
95
|
+
assert.equal(phpLiveRuntime.managedRuntime?.id, 'frankenphp', 'PHP Live View commands should keep the managed FrankenPHP hook.');
|
|
96
|
+
assert.equal(phpLiveRuntime.available, true, 'Managed PHP should keep PHP projects runnable when php is missing.');
|
|
97
|
+
assert.match(phpLiveRuntime.reason, /PHP runtime/i, 'Managed PHP diagnostics should explain the Pixcode runtime.');
|
|
98
|
+
|
|
99
|
+
console.log('runtime manager smoke passed');
|
|
@@ -31,6 +31,29 @@ function buildUrls(req, session) {
|
|
|
31
31
|
};
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
function buildEnvironmentTunnel(tunnel, urls) {
|
|
35
|
+
const active = Boolean(tunnel?.running && urls?.external);
|
|
36
|
+
return {
|
|
37
|
+
status: active ? 'active' : 'local-only',
|
|
38
|
+
url: active ? urls.external : null,
|
|
39
|
+
localUrl: urls?.local || null,
|
|
40
|
+
preferredUrl: urls?.preferred || urls?.local || null,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function attachEnvironmentRuntimeState(environment, urls, tunnel) {
|
|
45
|
+
if (!environment) return environment;
|
|
46
|
+
return {
|
|
47
|
+
...environment,
|
|
48
|
+
urls,
|
|
49
|
+
tunnel: buildEnvironmentTunnel(tunnel, urls),
|
|
50
|
+
diagnostics: {
|
|
51
|
+
...environment.diagnostics,
|
|
52
|
+
publicTunnelReady: Boolean(tunnel?.running && urls?.external),
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
34
57
|
function escapeHtml(value) {
|
|
35
58
|
return String(value ?? '')
|
|
36
59
|
.replaceAll('&', '&')
|
|
@@ -202,10 +225,13 @@ router.get('/:projectName/status', async (req, res) => {
|
|
|
202
225
|
const { projectName } = req.params;
|
|
203
226
|
const projectPath = await resolveProjectPath(projectName);
|
|
204
227
|
const state = await getLiveViewState(projectName, projectPath);
|
|
228
|
+
const urls = buildUrls(req, state.session);
|
|
229
|
+
const tunnel = getTunnelState();
|
|
205
230
|
res.json({
|
|
206
231
|
...state,
|
|
207
|
-
urls
|
|
208
|
-
tunnel
|
|
232
|
+
urls,
|
|
233
|
+
tunnel,
|
|
234
|
+
environment: attachEnvironmentRuntimeState(state.environment, urls, tunnel),
|
|
209
235
|
});
|
|
210
236
|
} catch (error) {
|
|
211
237
|
res.status(error.statusCode || 500).json({ error: error.message || 'Failed to read Live View state' });
|
|
@@ -217,11 +243,15 @@ router.post('/:projectName/start', async (req, res) => {
|
|
|
217
243
|
const { projectName } = req.params;
|
|
218
244
|
const projectPath = await resolveProjectPath(projectName);
|
|
219
245
|
const session = await startLiveView(projectName, projectPath, req.body || {});
|
|
246
|
+
const state = await getLiveViewState(projectName, projectPath);
|
|
247
|
+
const urls = buildUrls(req, session);
|
|
248
|
+
const tunnel = getTunnelState();
|
|
220
249
|
res.json({
|
|
221
250
|
success: true,
|
|
222
251
|
session,
|
|
223
|
-
urls
|
|
224
|
-
tunnel
|
|
252
|
+
urls,
|
|
253
|
+
tunnel,
|
|
254
|
+
environment: attachEnvironmentRuntimeState(state.environment, urls, tunnel),
|
|
225
255
|
});
|
|
226
256
|
} catch (error) {
|
|
227
257
|
const status = error.code === 'LIVE_VIEW_NOT_AVAILABLE' ? 422 : 500;
|
|
@@ -234,11 +264,15 @@ router.post('/:projectName/restart', async (req, res) => {
|
|
|
234
264
|
const { projectName } = req.params;
|
|
235
265
|
const projectPath = await resolveProjectPath(projectName);
|
|
236
266
|
const session = await restartLiveView(projectName, projectPath, req.body || {});
|
|
267
|
+
const state = await getLiveViewState(projectName, projectPath);
|
|
268
|
+
const urls = buildUrls(req, session);
|
|
269
|
+
const tunnel = getTunnelState();
|
|
237
270
|
res.json({
|
|
238
271
|
success: true,
|
|
239
272
|
session,
|
|
240
|
-
urls
|
|
241
|
-
tunnel
|
|
273
|
+
urls,
|
|
274
|
+
tunnel,
|
|
275
|
+
environment: attachEnvironmentRuntimeState(state.environment, urls, tunnel),
|
|
242
276
|
});
|
|
243
277
|
} catch (error) {
|
|
244
278
|
res.status(500).json({ error: error.message || 'Failed to restart Live View' });
|
|
@@ -248,11 +282,14 @@ router.post('/:projectName/restart', async (req, res) => {
|
|
|
248
282
|
router.post('/:projectName/stop', async (req, res) => {
|
|
249
283
|
try {
|
|
250
284
|
const session = await stopLiveView(req.params.projectName);
|
|
285
|
+
const urls = buildUrls(req, session);
|
|
286
|
+
const tunnel = getTunnelState();
|
|
251
287
|
res.json({
|
|
252
288
|
success: true,
|
|
253
289
|
session,
|
|
254
|
-
urls
|
|
255
|
-
tunnel
|
|
290
|
+
urls,
|
|
291
|
+
tunnel,
|
|
292
|
+
environment: attachEnvironmentRuntimeState(null, urls, tunnel),
|
|
256
293
|
});
|
|
257
294
|
} catch (error) {
|
|
258
295
|
res.status(500).json({ error: error.message || 'Failed to stop Live View' });
|
|
@@ -5,13 +5,13 @@ import net from 'node:net';
|
|
|
5
5
|
import path from 'node:path';
|
|
6
6
|
|
|
7
7
|
import { buildCliSpawnEnv } from './install-jobs.js';
|
|
8
|
-
import { ensureManagedRuntime
|
|
8
|
+
import { ensureManagedRuntime } from './managed-runtimes.js';
|
|
9
|
+
import { resolveLiveViewRuntime } from './runtime-manager.js';
|
|
9
10
|
|
|
10
11
|
const sessionsByProject = new Map();
|
|
11
12
|
const sessionsByShareId = new Map();
|
|
12
13
|
const READY_TIMEOUT_MS = 12000;
|
|
13
14
|
const LOG_LIMIT = 200;
|
|
14
|
-
const RUNTIME_CHECK_TIMEOUT_MS = 1800;
|
|
15
15
|
|
|
16
16
|
const localUrlRegex = /https?:\/\/(?:localhost|127\.0\.0\.1|0\.0\.0\.0|\[[^\]]+\])(?::(\d+))?[^\s"'<>]*/i;
|
|
17
17
|
|
|
@@ -82,88 +82,6 @@ function buildDisplayCommand(command, args) {
|
|
|
82
82
|
return [command, ...args].join(' ');
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
function quoteForPosixShell(value) {
|
|
86
|
-
return `'${String(value).replaceAll("'", "'\\''")}'`;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
function quoteForWindowsShell(value) {
|
|
90
|
-
return `"${String(value).replaceAll('"', '""')}"`;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function isPathLikeCommand(command) {
|
|
94
|
-
return path.isAbsolute(command) || command.includes('/') || command.includes('\\');
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
function runtimeMissingReason(command, framework) {
|
|
98
|
-
const base = `${command} is not available on this machine.`;
|
|
99
|
-
if (framework === 'PHP' || command === 'php') {
|
|
100
|
-
return 'Pixcode can prepare a local PHP runtime automatically before starting this project.';
|
|
101
|
-
}
|
|
102
|
-
if (command === 'npm' || command === 'pnpm' || command === 'yarn' || command === 'bun') {
|
|
103
|
-
return `${base} Pixcode can prepare a local Node package runner automatically before starting this project.`;
|
|
104
|
-
}
|
|
105
|
-
if (command === 'python' || command === 'python3') {
|
|
106
|
-
return `${base} Pixcode does not have a managed Python runtime for this stack yet.`;
|
|
107
|
-
}
|
|
108
|
-
return `${base} Pixcode does not have a managed ${framework || command} runtime for this stack yet.`;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
async function checkCommandAvailability(command, env = process.env) {
|
|
112
|
-
if (!command || command.includes('\n') || command.includes('\r')) return true;
|
|
113
|
-
|
|
114
|
-
if (isPathLikeCommand(command)) {
|
|
115
|
-
try {
|
|
116
|
-
await fs.access(command);
|
|
117
|
-
return true;
|
|
118
|
-
} catch {
|
|
119
|
-
return false;
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
const checker = process.platform === 'win32'
|
|
124
|
-
? {
|
|
125
|
-
command: process.env.ComSpec || 'cmd.exe',
|
|
126
|
-
args: ['/d', '/s', '/c', `where ${quoteForWindowsShell(command)}`],
|
|
127
|
-
}
|
|
128
|
-
: {
|
|
129
|
-
command: '/bin/sh',
|
|
130
|
-
args: ['-lc', `command -v ${quoteForPosixShell(command)}`],
|
|
131
|
-
};
|
|
132
|
-
|
|
133
|
-
return new Promise((resolve) => {
|
|
134
|
-
let settled = false;
|
|
135
|
-
let child = null;
|
|
136
|
-
const finish = (available) => {
|
|
137
|
-
if (settled) return;
|
|
138
|
-
settled = true;
|
|
139
|
-
clearTimeout(timer);
|
|
140
|
-
resolve(available);
|
|
141
|
-
};
|
|
142
|
-
|
|
143
|
-
const timer = setTimeout(() => {
|
|
144
|
-
try {
|
|
145
|
-
child?.kill();
|
|
146
|
-
} catch {
|
|
147
|
-
// Ignore a raced process exit.
|
|
148
|
-
}
|
|
149
|
-
finish(true);
|
|
150
|
-
}, RUNTIME_CHECK_TIMEOUT_MS);
|
|
151
|
-
|
|
152
|
-
child = spawn(checker.command, checker.args, {
|
|
153
|
-
env,
|
|
154
|
-
stdio: 'ignore',
|
|
155
|
-
windowsHide: true,
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
child.on('error', (error) => {
|
|
159
|
-
finish(error?.code === 'ENOENT' ? false : true);
|
|
160
|
-
});
|
|
161
|
-
child.on('exit', (code) => {
|
|
162
|
-
finish(code === 0);
|
|
163
|
-
});
|
|
164
|
-
});
|
|
165
|
-
}
|
|
166
|
-
|
|
167
85
|
function buildPackageCommand(packageManager, scriptName, id, label, framework, extraArgs = []) {
|
|
168
86
|
const args = packageRunArgs(packageManager, scriptName, extraArgs);
|
|
169
87
|
return {
|
|
@@ -376,6 +294,91 @@ function buildManagedPhpCommand(runtimeStatus) {
|
|
|
376
294
|
};
|
|
377
295
|
}
|
|
378
296
|
|
|
297
|
+
function publicCommand(command) {
|
|
298
|
+
if (!command) return null;
|
|
299
|
+
return {
|
|
300
|
+
id: command.id,
|
|
301
|
+
label: command.label,
|
|
302
|
+
displayCommand: command.displayCommand,
|
|
303
|
+
custom: command.custom === true || command.id === 'custom',
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
function liveViewEnvironmentMode(target, session) {
|
|
308
|
+
const kind = session?.kind || target?.kind || 'none';
|
|
309
|
+
if (kind === 'static') return 'static';
|
|
310
|
+
if (kind === 'process') return 'local-process';
|
|
311
|
+
return 'unavailable';
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
function liveViewEnvironmentStatus(target, session) {
|
|
315
|
+
if (session?.status) return session.status;
|
|
316
|
+
if (target?.available) return 'ready';
|
|
317
|
+
return 'unavailable';
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
function liveViewEnvironmentCommand(target, session) {
|
|
321
|
+
return publicCommand(session?.command) || publicCommand(target?.command);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
function liveViewEnvironmentLogs(session) {
|
|
325
|
+
return Array.isArray(session?.log) ? session.log.slice(-40) : [];
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
function liveViewEnvironmentRuntime(target, session) {
|
|
329
|
+
return session?.runtime || target?.runtime || null;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
function liveViewEnvironmentManagedRuntime(target, session) {
|
|
333
|
+
return session?.managedRuntime || target?.managedRuntime || target?.command?.managedRuntime || null;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
export function buildLiveViewEnvironment({ target = null, session = null } = {}) {
|
|
337
|
+
const mode = liveViewEnvironmentMode(target, session);
|
|
338
|
+
const status = liveViewEnvironmentStatus(target, session);
|
|
339
|
+
const command = liveViewEnvironmentCommand(target, session);
|
|
340
|
+
const framework = session?.framework || target?.framework || null;
|
|
341
|
+
const label = session?.label || target?.label || framework || 'Live View';
|
|
342
|
+
const runtime = liveViewEnvironmentRuntime(target, session);
|
|
343
|
+
const managedRuntime = liveViewEnvironmentManagedRuntime(target, session);
|
|
344
|
+
const logs = liveViewEnvironmentLogs(session);
|
|
345
|
+
const reason = session?.error || target?.reason || null;
|
|
346
|
+
|
|
347
|
+
return {
|
|
348
|
+
id: mode === 'unavailable' ? 'live-view-unavailable' : `live-view-${mode}`,
|
|
349
|
+
mode,
|
|
350
|
+
status,
|
|
351
|
+
framework,
|
|
352
|
+
label,
|
|
353
|
+
command,
|
|
354
|
+
runtime,
|
|
355
|
+
managedRuntime,
|
|
356
|
+
port: session?.port ?? null,
|
|
357
|
+
upstreamUrl: session?.upstreamUrl ?? null,
|
|
358
|
+
sharePath: session?.sharePath ?? null,
|
|
359
|
+
logs,
|
|
360
|
+
diagnostics: {
|
|
361
|
+
runnerKind: session?.kind || target?.kind || 'none',
|
|
362
|
+
targetAvailable: Boolean(target?.available || session),
|
|
363
|
+
reason,
|
|
364
|
+
error: session?.error || null,
|
|
365
|
+
exitCode: session?.exitCode ?? null,
|
|
366
|
+
exitSignal: session?.exitSignal ?? null,
|
|
367
|
+
spawnErrorCode: session?.spawnErrorCode ?? null,
|
|
368
|
+
startedAt: session?.startedAt || null,
|
|
369
|
+
stoppedAt: session?.stoppedAt || null,
|
|
370
|
+
readyTimeoutMs: READY_TIMEOUT_MS,
|
|
371
|
+
staticServing: mode === 'static',
|
|
372
|
+
customCommand: command?.custom === true,
|
|
373
|
+
publicTunnelReady: false,
|
|
374
|
+
},
|
|
375
|
+
tunnel: {
|
|
376
|
+
status: 'local-only',
|
|
377
|
+
url: null,
|
|
378
|
+
},
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
|
|
379
382
|
function detectPackageCommand(packageJson, packageManager) {
|
|
380
383
|
const scripts = packageJson.scripts || {};
|
|
381
384
|
const devScript = String(scripts.dev || '');
|
|
@@ -596,11 +599,13 @@ export async function detectLiveViewTarget(projectPath, options = {}) {
|
|
|
596
599
|
|
|
597
600
|
const processCommand = await detectProcessCommand(projectPath);
|
|
598
601
|
if (processCommand) {
|
|
602
|
+
const runtimeResolution = await resolveLiveViewRuntime(processCommand, {
|
|
603
|
+
env: options.env || process.env,
|
|
604
|
+
preferManaged: true,
|
|
605
|
+
});
|
|
606
|
+
|
|
599
607
|
if (isPackageManagerCommand(processCommand.command)) {
|
|
600
|
-
const managedRuntime =
|
|
601
|
-
env: options.env || process.env,
|
|
602
|
-
preferManaged: true,
|
|
603
|
-
});
|
|
608
|
+
const managedRuntime = runtimeResolution.managedRuntime;
|
|
604
609
|
const command = buildManagedPackageCommand(processCommand, managedRuntime);
|
|
605
610
|
return {
|
|
606
611
|
available: true,
|
|
@@ -609,17 +614,13 @@ export async function detectLiveViewTarget(projectPath, options = {}) {
|
|
|
609
614
|
framework: processCommand.framework,
|
|
610
615
|
command,
|
|
611
616
|
managedRuntime,
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
: 'Pixcode will run this project with its managed Node package runner.',
|
|
617
|
+
runtime: runtimeResolution.runtime,
|
|
618
|
+
reason: runtimeResolution.reason,
|
|
615
619
|
};
|
|
616
620
|
}
|
|
617
621
|
|
|
618
622
|
if (processCommand.framework === 'PHP' || processCommand.command === 'php') {
|
|
619
|
-
const managedRuntime =
|
|
620
|
-
env: options.env || process.env,
|
|
621
|
-
preferManaged: true,
|
|
622
|
-
});
|
|
623
|
+
const managedRuntime = runtimeResolution.managedRuntime;
|
|
623
624
|
const command = buildManagedPhpCommand(managedRuntime);
|
|
624
625
|
return {
|
|
625
626
|
available: true,
|
|
@@ -628,14 +629,12 @@ export async function detectLiveViewTarget(projectPath, options = {}) {
|
|
|
628
629
|
framework: command.framework,
|
|
629
630
|
command,
|
|
630
631
|
managedRuntime,
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
: 'Pixcode will run this project with its managed PHP runtime.',
|
|
632
|
+
runtime: runtimeResolution.runtime,
|
|
633
|
+
reason: runtimeResolution.reason,
|
|
634
634
|
};
|
|
635
635
|
}
|
|
636
636
|
|
|
637
|
-
|
|
638
|
-
if (!runtimeAvailable) {
|
|
637
|
+
if (!runtimeResolution.available) {
|
|
639
638
|
return {
|
|
640
639
|
available: false,
|
|
641
640
|
kind: 'process',
|
|
@@ -643,7 +642,8 @@ export async function detectLiveViewTarget(projectPath, options = {}) {
|
|
|
643
642
|
framework: processCommand.framework,
|
|
644
643
|
command: processCommand,
|
|
645
644
|
missingRuntime: processCommand.command,
|
|
646
|
-
|
|
645
|
+
runtime: runtimeResolution.runtime,
|
|
646
|
+
reason: runtimeResolution.reason,
|
|
647
647
|
};
|
|
648
648
|
}
|
|
649
649
|
|
|
@@ -653,6 +653,7 @@ export async function detectLiveViewTarget(projectPath, options = {}) {
|
|
|
653
653
|
label: processCommand.label,
|
|
654
654
|
framework: processCommand.framework,
|
|
655
655
|
command: processCommand,
|
|
656
|
+
runtime: runtimeResolution.runtime,
|
|
656
657
|
};
|
|
657
658
|
}
|
|
658
659
|
|
|
@@ -732,11 +733,8 @@ function publicSession(session) {
|
|
|
732
733
|
kind: session.kind,
|
|
733
734
|
framework: session.framework,
|
|
734
735
|
label: session.label,
|
|
735
|
-
command: session.command
|
|
736
|
-
|
|
737
|
-
label: session.command.label,
|
|
738
|
-
displayCommand: session.command.displayCommand,
|
|
739
|
-
} : null,
|
|
736
|
+
command: publicCommand(session.command),
|
|
737
|
+
runtime: session.runtime || null,
|
|
740
738
|
managedRuntime: session.managedRuntime || null,
|
|
741
739
|
port: session.port,
|
|
742
740
|
upstreamUrl: session.upstreamUrl,
|
|
@@ -753,9 +751,11 @@ function publicSession(session) {
|
|
|
753
751
|
export async function getLiveViewState(projectName, projectPath) {
|
|
754
752
|
const target = await detectLiveViewTarget(projectPath);
|
|
755
753
|
const session = sessionsByProject.get(projectName) ?? null;
|
|
754
|
+
const publicLiveViewSession = publicSession(session);
|
|
756
755
|
return {
|
|
757
756
|
target,
|
|
758
|
-
session:
|
|
757
|
+
session: publicLiveViewSession,
|
|
758
|
+
environment: buildLiveViewEnvironment({ target, session: publicLiveViewSession }),
|
|
759
759
|
};
|
|
760
760
|
}
|
|
761
761
|
|
|
@@ -780,6 +780,7 @@ export async function startLiveView(projectName, projectPath, options = {}) {
|
|
|
780
780
|
command: customCommand,
|
|
781
781
|
args: [],
|
|
782
782
|
displayCommand: customCommand,
|
|
783
|
+
custom: true,
|
|
783
784
|
shell: true,
|
|
784
785
|
},
|
|
785
786
|
}
|
|
@@ -803,6 +804,7 @@ export async function startLiveView(projectName, projectPath, options = {}) {
|
|
|
803
804
|
label: target.label,
|
|
804
805
|
staticRoot: target.staticRoot,
|
|
805
806
|
command: null,
|
|
807
|
+
runtime: null,
|
|
806
808
|
port: null,
|
|
807
809
|
upstreamUrl: null,
|
|
808
810
|
startedAt: new Date().toISOString(),
|
|
@@ -842,6 +844,7 @@ export async function startLiveView(projectName, projectPath, options = {}) {
|
|
|
842
844
|
framework: target.framework,
|
|
843
845
|
label: target.label,
|
|
844
846
|
command,
|
|
847
|
+
runtime: target.runtime || null,
|
|
845
848
|
managedRuntime: runtimeStatus,
|
|
846
849
|
port,
|
|
847
850
|
host: '127.0.0.1',
|