@jamiexiongr/panda-hub 0.1.19 → 0.1.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -13
- package/dist/{chunk-N5CXOFMD.mjs → chunk-SPTBBMUL.mjs} +350 -27
- package/dist/chunk-YKNCRHVV.mjs +489 -0
- package/dist/cli.mjs +17 -8
- package/dist/index.mjs +4 -2
- package/dist/{src-EGC2EU26.mjs → src-M7W7LPHG.mjs} +1 -1
- package/dist/web/assets/{diagnostics-page-CNt0HQLr.js → diagnostics-page-BKp7IiZk.js} +1 -1
- package/dist/web/assets/index-DhjIbKkn.js +142 -0
- package/dist/web/assets/index-QBVYFqgo.css +1 -0
- package/dist/web/assets/{session-diff-preview-Dy910n6F.js → session-diff-preview-BU4XO0fT.js} +1 -1
- package/dist/web/assets/{web-C7Ef9J6I.js → web-BqX5x67V.js} +1 -1
- package/dist/web/assets/{web-BFlqriRI.js → web-C3EZUi0V.js} +1 -1
- package/dist/web/assets/{web-P7eDOfOq.js → web-CIHpZyzh.js} +1 -1
- package/dist/web/assets/{web-BGzSBKmu.js → web-Ck4th-0Z.js} +1 -1
- package/dist/web/assets/{web-DCi2I8TJ.js → web-HzS7kaoe.js} +1 -1
- package/dist/web/index.html +2 -2
- package/dist/web/sw.js +1 -1
- package/package.json +2 -1
- package/dist/chunk-SKHIQ4LT.mjs +0 -109
- package/dist/web/assets/index-5NBpaOlM.js +0 -142
- package/dist/web/assets/index-CtgLzUhf.css +0 -1
package/README.md
CHANGED
|
@@ -2,19 +2,30 @@
|
|
|
2
2
|
|
|
3
3
|
Published hub runtime for Panda, including the built web UI.
|
|
4
4
|
|
|
5
|
-
## Usage
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
panda-hub
|
|
9
|
-
panda-hub tailscareserv
|
|
10
|
-
```
|
|
11
|
-
|
|
12
|
-
`tailscareserv` and `--tailscale-serve` both enable automatic `tailscale serve` publishing.
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
-
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
panda-hub
|
|
9
|
+
panda-hub tailscareserv
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
`tailscareserv` and `--tailscale-serve` both enable automatic `tailscale serve` publishing.
|
|
13
|
+
|
|
14
|
+
Windows service management:
|
|
15
|
+
|
|
16
|
+
```powershell
|
|
17
|
+
panda-hub service install --name=PandaHub tailscareserv
|
|
18
|
+
panda-hub service status
|
|
19
|
+
panda-hub service restart
|
|
20
|
+
panda-hub service uninstall
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
`service install` stores the startup args and current `PANDA_*` environment values in the Windows service definition. If you change them later, run `service install` again to update the service.
|
|
24
|
+
|
|
25
|
+
When enabled, hub startup will:
|
|
26
|
+
|
|
27
|
+
- detect whether `tailscale` is available and online
|
|
28
|
+
- run `tailscale serve --bg`
|
|
18
29
|
- print the generated Tailscale HTTPS URL in the startup log
|
|
19
30
|
|
|
20
31
|
## Environment
|
|
@@ -2468,12 +2468,24 @@ var devManagerServiceStatusSchema = external_exports.enum([
|
|
|
2468
2468
|
"stopped",
|
|
2469
2469
|
"degraded"
|
|
2470
2470
|
]);
|
|
2471
|
+
var devManagerServiceManagerSchema = external_exports.enum([
|
|
2472
|
+
"process",
|
|
2473
|
+
"windows-service"
|
|
2474
|
+
]);
|
|
2475
|
+
var devManagerServiceControllerStatusSchema = external_exports.enum([
|
|
2476
|
+
"missing",
|
|
2477
|
+
"running",
|
|
2478
|
+
"stopped",
|
|
2479
|
+
"unknown"
|
|
2480
|
+
]);
|
|
2471
2481
|
var devManagerJobKindSchema = external_exports.enum([
|
|
2472
2482
|
"dev-start",
|
|
2473
2483
|
"dev-restart",
|
|
2474
2484
|
"dev-stop",
|
|
2475
2485
|
"dev-probe",
|
|
2476
2486
|
"npm-publish",
|
|
2487
|
+
"release-service-install",
|
|
2488
|
+
"release-service-uninstall",
|
|
2477
2489
|
"release-install-run",
|
|
2478
2490
|
"apk-build"
|
|
2479
2491
|
]);
|
|
@@ -2503,8 +2515,10 @@ var devManagerConfigSchema = external_exports.object({
|
|
|
2503
2515
|
dev_web_hub_url: external_exports.string().default(""),
|
|
2504
2516
|
dev_web_args: external_exports.string().default(""),
|
|
2505
2517
|
release_hub_port: external_exports.number().int().positive().nullable().default(null),
|
|
2518
|
+
release_hub_service_name: external_exports.string().default("PandaHub"),
|
|
2506
2519
|
release_hub_args: external_exports.string().default(""),
|
|
2507
2520
|
release_agent_port: external_exports.number().int().positive().nullable().default(null),
|
|
2521
|
+
release_agent_service_name: external_exports.string().default("PandaAgent"),
|
|
2508
2522
|
release_agent_hub_url: external_exports.string().default(""),
|
|
2509
2523
|
release_agent_direct_base_url: external_exports.string().default(""),
|
|
2510
2524
|
release_agent_ws_base_url: external_exports.string().default(""),
|
|
@@ -2532,6 +2546,10 @@ var devManagerServiceStateSchema = external_exports.object({
|
|
|
2532
2546
|
key: devManagerServiceKeySchema,
|
|
2533
2547
|
label: external_exports.string(),
|
|
2534
2548
|
status: devManagerServiceStatusSchema,
|
|
2549
|
+
manager: devManagerServiceManagerSchema.default("process"),
|
|
2550
|
+
service_name: external_exports.string().nullable().default(null),
|
|
2551
|
+
service_registered: external_exports.boolean().default(false),
|
|
2552
|
+
service_status: devManagerServiceControllerStatusSchema.nullable().default(null),
|
|
2535
2553
|
configured_port: external_exports.number().int().positive().nullable().default(null),
|
|
2536
2554
|
detected_pids: external_exports.array(external_exports.number().int().positive()).default([]),
|
|
2537
2555
|
probe: devManagerServiceProbeSchema.nullable().default(null)
|
|
@@ -2582,6 +2600,8 @@ var devManagerActionRequestSchema = external_exports.object({
|
|
|
2582
2600
|
"stop-development",
|
|
2583
2601
|
"probe-development",
|
|
2584
2602
|
"publish-npm",
|
|
2603
|
+
"install-release-services",
|
|
2604
|
+
"uninstall-release-services",
|
|
2585
2605
|
"install-latest-release",
|
|
2586
2606
|
"build-apk"
|
|
2587
2607
|
])
|
|
@@ -8260,8 +8280,10 @@ var defaultConfig = () => ({
|
|
|
8260
8280
|
dev_web_hub_url: `http://${LOCALHOST}:4344`,
|
|
8261
8281
|
dev_web_args: "",
|
|
8262
8282
|
release_hub_port: 4343,
|
|
8283
|
+
release_hub_service_name: "PandaHub",
|
|
8263
8284
|
release_hub_args: "",
|
|
8264
8285
|
release_agent_port: 4242,
|
|
8286
|
+
release_agent_service_name: "PandaAgent",
|
|
8265
8287
|
release_agent_hub_url: `http://${LOCALHOST}:4343`,
|
|
8266
8288
|
release_agent_direct_base_url: `http://${LOCALHOST}:4242`,
|
|
8267
8289
|
release_agent_ws_base_url: `ws://${LOCALHOST}:4242/ws`,
|
|
@@ -8312,8 +8334,10 @@ var normalizeConfig = (input) => {
|
|
|
8312
8334
|
dev_web_hub_url: normalizeText(input?.dev_web_hub_url) || buildHttpBaseUrl(devHubPort, defaults.dev_web_hub_url),
|
|
8313
8335
|
dev_web_args: normalizeText(input?.dev_web_args),
|
|
8314
8336
|
release_hub_port: releaseHubPort,
|
|
8337
|
+
release_hub_service_name: normalizeText(input?.release_hub_service_name) || defaults.release_hub_service_name,
|
|
8315
8338
|
release_hub_args: normalizeText(input?.release_hub_args),
|
|
8316
8339
|
release_agent_port: releaseAgentPort,
|
|
8340
|
+
release_agent_service_name: normalizeText(input?.release_agent_service_name) || defaults.release_agent_service_name,
|
|
8317
8341
|
release_agent_hub_url: normalizeText(input?.release_agent_hub_url) || buildHttpBaseUrl(releaseHubPort, defaults.release_agent_hub_url),
|
|
8318
8342
|
release_agent_direct_base_url: normalizeText(input?.release_agent_direct_base_url) || buildHttpBaseUrl(releaseAgentPort, defaults.release_agent_direct_base_url),
|
|
8319
8343
|
release_agent_ws_base_url: normalizeText(input?.release_agent_ws_base_url) || buildWsBaseUrl(releaseAgentPort, defaults.release_agent_ws_base_url),
|
|
@@ -8493,6 +8517,60 @@ var killByPort = async (port) => {
|
|
|
8493
8517
|
}
|
|
8494
8518
|
return pids;
|
|
8495
8519
|
};
|
|
8520
|
+
var resolveWindowsServiceControllerName = (serviceName) => {
|
|
8521
|
+
const normalizedName = normalizeNullableText(serviceName);
|
|
8522
|
+
if (!normalizedName) {
|
|
8523
|
+
return null;
|
|
8524
|
+
}
|
|
8525
|
+
return `${normalizedName.replace(/[^\w]/g, "").toLowerCase()}.exe`;
|
|
8526
|
+
};
|
|
8527
|
+
var queryWindowsServiceStatus = (serviceName) => {
|
|
8528
|
+
const normalizedName = normalizeNullableText(serviceName);
|
|
8529
|
+
if (process.platform !== "win32" || !normalizedName) {
|
|
8530
|
+
return null;
|
|
8531
|
+
}
|
|
8532
|
+
const controllerName = resolveWindowsServiceControllerName(normalizedName);
|
|
8533
|
+
const escapedName = normalizedName.replace(/'/g, "''");
|
|
8534
|
+
const escapedControllerName = (controllerName ?? normalizedName).replace(/'/g, "''");
|
|
8535
|
+
const result = spawnSync2(
|
|
8536
|
+
"powershell.exe",
|
|
8537
|
+
[
|
|
8538
|
+
"-NoProfile",
|
|
8539
|
+
"-Command",
|
|
8540
|
+
[
|
|
8541
|
+
`$service = Get-Service -Name '${escapedControllerName}' -ErrorAction SilentlyContinue`,
|
|
8542
|
+
`if ($null -eq $service) { $service = Get-Service -DisplayName '${escapedName}' -ErrorAction SilentlyContinue }`,
|
|
8543
|
+
`if ($null -eq $service) { '__MISSING__' } else { @{ Name = $service.Name; DisplayName = $service.DisplayName; Status = $service.Status.ToString() } | ConvertTo-Json -Compress }`
|
|
8544
|
+
].join("; ")
|
|
8545
|
+
],
|
|
8546
|
+
{
|
|
8547
|
+
encoding: "utf8",
|
|
8548
|
+
timeout: GLOBAL_COMMAND_TIMEOUT_MS,
|
|
8549
|
+
windowsHide: true
|
|
8550
|
+
}
|
|
8551
|
+
);
|
|
8552
|
+
const rawOutput = `${result.stdout ?? ""}
|
|
8553
|
+
${result.stderr ?? ""}`.trim();
|
|
8554
|
+
let resolvedDisplayName = normalizedName;
|
|
8555
|
+
let resolvedControllerName = controllerName ?? normalizedName;
|
|
8556
|
+
let normalizedOutput = rawOutput.trim().toLowerCase();
|
|
8557
|
+
try {
|
|
8558
|
+
const parsed = JSON.parse(rawOutput);
|
|
8559
|
+
resolvedDisplayName = normalizeNullableText(parsed.DisplayName) ?? resolvedDisplayName;
|
|
8560
|
+
resolvedControllerName = normalizeNullableText(parsed.Name) ?? resolvedControllerName;
|
|
8561
|
+
normalizedOutput = (normalizeNullableText(parsed.Status) ?? rawOutput).trim().toLowerCase();
|
|
8562
|
+
} catch {
|
|
8563
|
+
}
|
|
8564
|
+
const status = normalizedOutput === "__missing__" ? "missing" : normalizedOutput === "running" ? "running" : normalizedOutput === "stopped" ? "stopped" : "unknown";
|
|
8565
|
+
return {
|
|
8566
|
+
name: normalizedName,
|
|
8567
|
+
displayName: resolvedDisplayName,
|
|
8568
|
+
controllerName: resolvedControllerName,
|
|
8569
|
+
installed: status !== "missing",
|
|
8570
|
+
status,
|
|
8571
|
+
rawOutput
|
|
8572
|
+
};
|
|
8573
|
+
};
|
|
8496
8574
|
var probeUrl = async (url, options) => {
|
|
8497
8575
|
const resolvedUrl = withProbePath(url, options?.probePath ?? "/health");
|
|
8498
8576
|
if (!resolvedUrl) {
|
|
@@ -8845,6 +8923,109 @@ const killByPort = async (port) => {
|
|
|
8845
8923
|
return pids
|
|
8846
8924
|
}
|
|
8847
8925
|
|
|
8926
|
+
const resolveWindowsServiceControllerName = (serviceName) => {
|
|
8927
|
+
const normalizedName = String(serviceName || '').trim()
|
|
8928
|
+
if (!normalizedName) {
|
|
8929
|
+
return null
|
|
8930
|
+
}
|
|
8931
|
+
return normalizedName.replace(/[^\w]/g, '').toLowerCase() + '.exe'
|
|
8932
|
+
}
|
|
8933
|
+
|
|
8934
|
+
const queryWindowsServiceStatus = (serviceName) => {
|
|
8935
|
+
if (process.platform !== 'win32' || !serviceName) {
|
|
8936
|
+
return null
|
|
8937
|
+
}
|
|
8938
|
+
const normalizedName = String(serviceName).trim()
|
|
8939
|
+
const controllerName = resolveWindowsServiceControllerName(normalizedName) || normalizedName
|
|
8940
|
+
const escapedName = normalizedName.replace(/'/g, "''")
|
|
8941
|
+
const escapedControllerName = controllerName.replace(/'/g, "''")
|
|
8942
|
+
const result = spawnSync('powershell.exe', ['-NoProfile', '-Command', [
|
|
8943
|
+
"$service = Get-Service -Name '" + escapedControllerName + "' -ErrorAction SilentlyContinue",
|
|
8944
|
+
"if ($null -eq $service) { $service = Get-Service -DisplayName '" + escapedName + "' -ErrorAction SilentlyContinue }",
|
|
8945
|
+
"if ($null -eq $service) { '__MISSING__' } else { @{ Name = $service.Name; DisplayName = $service.DisplayName; Status = $service.Status.ToString() } | ConvertTo-Json -Compress }",
|
|
8946
|
+
].join('; ')], {
|
|
8947
|
+
encoding: 'utf8',
|
|
8948
|
+
timeout: 5000,
|
|
8949
|
+
windowsHide: true,
|
|
8950
|
+
})
|
|
8951
|
+
const rawOutput = (String(result.stdout || '') + '\n' + String(result.stderr || '')).trim()
|
|
8952
|
+
let resolvedDisplayName = normalizedName
|
|
8953
|
+
let resolvedControllerName = controllerName
|
|
8954
|
+
let normalizedOutput = rawOutput.trim().toLowerCase()
|
|
8955
|
+
try {
|
|
8956
|
+
const parsed = JSON.parse(rawOutput)
|
|
8957
|
+
resolvedDisplayName = String(parsed.DisplayName || '').trim() || resolvedDisplayName
|
|
8958
|
+
resolvedControllerName = String(parsed.Name || '').trim() || resolvedControllerName
|
|
8959
|
+
normalizedOutput = (String(parsed.Status || '').trim() || rawOutput).trim().toLowerCase()
|
|
8960
|
+
} catch {}
|
|
8961
|
+
const status =
|
|
8962
|
+
normalizedOutput === '__missing__'
|
|
8963
|
+
? 'missing'
|
|
8964
|
+
: normalizedOutput === 'running'
|
|
8965
|
+
? 'running'
|
|
8966
|
+
: normalizedOutput === 'stopped'
|
|
8967
|
+
? 'stopped'
|
|
8968
|
+
: 'unknown'
|
|
8969
|
+
return {
|
|
8970
|
+
displayName: resolvedDisplayName,
|
|
8971
|
+
controllerName: resolvedControllerName,
|
|
8972
|
+
installed: status !== 'missing',
|
|
8973
|
+
status,
|
|
8974
|
+
rawOutput,
|
|
8975
|
+
}
|
|
8976
|
+
}
|
|
8977
|
+
|
|
8978
|
+
const waitForWindowsServiceStatus = async (serviceName, desiredStatus, timeoutMs) => {
|
|
8979
|
+
const startedAt = Date.now()
|
|
8980
|
+
let latest = queryWindowsServiceStatus(serviceName)
|
|
8981
|
+
while (latest && latest.status !== desiredStatus && Date.now() - startedAt < timeoutMs) {
|
|
8982
|
+
await wait(750)
|
|
8983
|
+
latest = queryWindowsServiceStatus(serviceName)
|
|
8984
|
+
}
|
|
8985
|
+
return latest
|
|
8986
|
+
}
|
|
8987
|
+
|
|
8988
|
+
const stopWindowsService = async (serviceName) => {
|
|
8989
|
+
const current = queryWindowsServiceStatus(serviceName)
|
|
8990
|
+
if (!current || !current.installed || current.status === 'stopped') {
|
|
8991
|
+
return current
|
|
8992
|
+
}
|
|
8993
|
+
const escapedName = String(current.controllerName || serviceName).replace(/'/g, "''")
|
|
8994
|
+
const result = spawnSync('powershell.exe', ['-NoProfile', '-Command', "Stop-Service -Name '" + escapedName + "' -Force -ErrorAction Stop"], {
|
|
8995
|
+
encoding: 'utf8',
|
|
8996
|
+
timeout: 5000,
|
|
8997
|
+
windowsHide: true,
|
|
8998
|
+
})
|
|
8999
|
+
const output = (String(result.stdout || '') + '\n' + String(result.stderr || '')).trim()
|
|
9000
|
+
const latest = await waitForWindowsServiceStatus(serviceName, 'stopped', 20000)
|
|
9001
|
+
if (!latest || latest.status !== 'stopped') {
|
|
9002
|
+
throw new Error(output || '停止 Windows 服务失败。')
|
|
9003
|
+
}
|
|
9004
|
+
return latest
|
|
9005
|
+
}
|
|
9006
|
+
|
|
9007
|
+
const startWindowsService = async (serviceName) => {
|
|
9008
|
+
const current = queryWindowsServiceStatus(serviceName)
|
|
9009
|
+
if (!current || !current.installed) {
|
|
9010
|
+
throw new Error('Windows 服务不存在。')
|
|
9011
|
+
}
|
|
9012
|
+
if (current.status === 'running') {
|
|
9013
|
+
return current
|
|
9014
|
+
}
|
|
9015
|
+
const escapedName = String(current.controllerName || serviceName).replace(/'/g, "''")
|
|
9016
|
+
const result = spawnSync('powershell.exe', ['-NoProfile', '-Command', "Start-Service -Name '" + escapedName + "' -ErrorAction Stop"], {
|
|
9017
|
+
encoding: 'utf8',
|
|
9018
|
+
timeout: 5000,
|
|
9019
|
+
windowsHide: true,
|
|
9020
|
+
})
|
|
9021
|
+
const output = (String(result.stdout || '') + '\n' + String(result.stderr || '')).trim()
|
|
9022
|
+
const latest = await waitForWindowsServiceStatus(serviceName, 'running', 20000)
|
|
9023
|
+
if (!latest || latest.status !== 'running') {
|
|
9024
|
+
throw new Error(output || '启动 Windows 服务失败。')
|
|
9025
|
+
}
|
|
9026
|
+
return latest
|
|
9027
|
+
}
|
|
9028
|
+
|
|
8848
9029
|
const probe = async (url, probePath) => {
|
|
8849
9030
|
if (!url) {
|
|
8850
9031
|
return { ok: false, message: '未配置地址。' }
|
|
@@ -8957,11 +9138,30 @@ const main = async () => {
|
|
|
8957
9138
|
await wait(payload.stopDelayMs || 1500)
|
|
8958
9139
|
|
|
8959
9140
|
for (const service of payload.stopServices) {
|
|
8960
|
-
|
|
8961
|
-
|
|
8962
|
-
await appendLog(
|
|
9141
|
+
if (service.serviceName) {
|
|
9142
|
+
const status = await stopWindowsService(service.serviceName)
|
|
9143
|
+
await appendLog(
|
|
9144
|
+
jobPath,
|
|
9145
|
+
'info',
|
|
9146
|
+
status && status.installed
|
|
9147
|
+
? '已停止 Windows 服务 ' + service.label + '(' + service.serviceName + ')。'
|
|
9148
|
+
: service.label + ' 对应的 Windows 服务未安装,回退到端口停止。',
|
|
9149
|
+
)
|
|
9150
|
+
if (!status || !status.installed) {
|
|
9151
|
+
const pids = await killByPort(service.port)
|
|
9152
|
+
if (pids.length > 0) {
|
|
9153
|
+
await appendLog(jobPath, 'info', '已停止 ' + service.label + ',PID: ' + pids.join(', '))
|
|
9154
|
+
} else {
|
|
9155
|
+
await appendLog(jobPath, 'info', service.label + ' 当前没有监听中的端口进程。')
|
|
9156
|
+
}
|
|
9157
|
+
}
|
|
8963
9158
|
} else {
|
|
8964
|
-
await
|
|
9159
|
+
const pids = await killByPort(service.port)
|
|
9160
|
+
if (pids.length > 0) {
|
|
9161
|
+
await appendLog(jobPath, 'info', '已停止 ' + service.label + ',PID: ' + pids.join(', '))
|
|
9162
|
+
} else {
|
|
9163
|
+
await appendLog(jobPath, 'info', service.label + ' 当前没有监听中的端口进程。')
|
|
9164
|
+
}
|
|
8965
9165
|
}
|
|
8966
9166
|
}
|
|
8967
9167
|
|
|
@@ -8976,13 +9176,29 @@ const main = async () => {
|
|
|
8976
9176
|
|
|
8977
9177
|
const probeResults = []
|
|
8978
9178
|
for (const service of payload.startServices) {
|
|
8979
|
-
|
|
8980
|
-
|
|
8981
|
-
|
|
8982
|
-
|
|
8983
|
-
|
|
8984
|
-
|
|
8985
|
-
|
|
9179
|
+
if (service.serviceName) {
|
|
9180
|
+
try {
|
|
9181
|
+
await startWindowsService(service.serviceName)
|
|
9182
|
+
await appendLog(
|
|
9183
|
+
jobPath,
|
|
9184
|
+
'info',
|
|
9185
|
+
'已启动 Windows 服务 ' + service.label + '(' + service.serviceName + ')。',
|
|
9186
|
+
)
|
|
9187
|
+
} catch (error) {
|
|
9188
|
+
const message = error instanceof Error ? error.message : String(error)
|
|
9189
|
+
await appendLog(jobPath, 'error', '启动 ' + service.label + ' 失败:' + message)
|
|
9190
|
+
probeResults.push({ label: service.label, ok: false, message })
|
|
9191
|
+
continue
|
|
9192
|
+
}
|
|
9193
|
+
} else {
|
|
9194
|
+
try {
|
|
9195
|
+
await startDetached(jobPath, service.command, service.label)
|
|
9196
|
+
} catch (error) {
|
|
9197
|
+
const message = error instanceof Error ? error.message : String(error)
|
|
9198
|
+
await appendLog(jobPath, 'error', '启动 ' + service.label + ' 失败:' + message)
|
|
9199
|
+
probeResults.push({ label: service.label, ok: false, message })
|
|
9200
|
+
continue
|
|
9201
|
+
}
|
|
8986
9202
|
}
|
|
8987
9203
|
|
|
8988
9204
|
const probeResult = await waitForProbe(service.probeUrl, service.probePath, service.timeoutMs)
|
|
@@ -9125,6 +9341,50 @@ var createDevManager = ({
|
|
|
9125
9341
|
);
|
|
9126
9342
|
const buildReleaseHubCommand = (config) => buildShellCommand("panda hub", config.release_hub_args);
|
|
9127
9343
|
const buildReleaseAgentCommand = (config) => buildShellCommand("panda agent", config.release_agent_args);
|
|
9344
|
+
const buildReleaseHubEnvOverrides = (config) => ({
|
|
9345
|
+
PANDA_HUB_PORT: config.release_hub_port ? String(config.release_hub_port) : null
|
|
9346
|
+
});
|
|
9347
|
+
const buildReleaseAgentEnvOverrides = (config) => ({
|
|
9348
|
+
PANDA_AGENT_PORT: config.release_agent_port ? String(config.release_agent_port) : null,
|
|
9349
|
+
PANDA_HUB_URL: config.release_agent_hub_url,
|
|
9350
|
+
PANDA_AGENT_DIRECT_BASE_URL: config.release_agent_direct_base_url,
|
|
9351
|
+
PANDA_AGENT_WS_BASE_URL: config.release_agent_ws_base_url,
|
|
9352
|
+
PANDA_AGENT_NAME: normalizeNullableText(config.release_agent_name)
|
|
9353
|
+
});
|
|
9354
|
+
const validateWindowsServiceName = (value, label) => {
|
|
9355
|
+
if (!/^[A-Za-z0-9._() \-]+$/.test(value)) {
|
|
9356
|
+
throw new Error(`${label} \u53EA\u80FD\u5305\u542B\u5B57\u6BCD\u3001\u6570\u5B57\u3001\u7A7A\u683C\u3001\u70B9\u3001\u4E0B\u5212\u7EBF\u3001\u5706\u62EC\u53F7\u548C\u8FDE\u5B57\u7B26\u3002`);
|
|
9357
|
+
}
|
|
9358
|
+
};
|
|
9359
|
+
const quoteCommandArg = (value) => {
|
|
9360
|
+
const normalized = value.trim();
|
|
9361
|
+
if (!normalized) {
|
|
9362
|
+
return '""';
|
|
9363
|
+
}
|
|
9364
|
+
return `"${normalized.replace(/"/g, '\\"')}"`;
|
|
9365
|
+
};
|
|
9366
|
+
const buildReleaseHubServiceInstallCommand = (config) => {
|
|
9367
|
+
validateWindowsServiceName(config.release_hub_service_name, "\u6B63\u5F0F\u7248 Hub \u670D\u52A1\u540D");
|
|
9368
|
+
const command = `panda hub service install --name=${quoteCommandArg(
|
|
9369
|
+
config.release_hub_service_name
|
|
9370
|
+
)}`;
|
|
9371
|
+
return buildShellCommand(command, config.release_hub_args);
|
|
9372
|
+
};
|
|
9373
|
+
const buildReleaseAgentServiceInstallCommand = (config) => {
|
|
9374
|
+
validateWindowsServiceName(config.release_agent_service_name, "\u6B63\u5F0F\u7248 Agent \u670D\u52A1\u540D");
|
|
9375
|
+
const command = `panda agent service install --name=${quoteCommandArg(
|
|
9376
|
+
config.release_agent_service_name
|
|
9377
|
+
)}`;
|
|
9378
|
+
return buildShellCommand(command, config.release_agent_args);
|
|
9379
|
+
};
|
|
9380
|
+
const buildReleaseHubServiceUninstallCommand = (config) => {
|
|
9381
|
+
validateWindowsServiceName(config.release_hub_service_name, "\u6B63\u5F0F\u7248 Hub \u670D\u52A1\u540D");
|
|
9382
|
+
return `panda hub service uninstall --name=${quoteCommandArg(config.release_hub_service_name)}`;
|
|
9383
|
+
};
|
|
9384
|
+
const buildReleaseAgentServiceUninstallCommand = (config) => {
|
|
9385
|
+
validateWindowsServiceName(config.release_agent_service_name, "\u6B63\u5F0F\u7248 Agent \u670D\u52A1\u540D");
|
|
9386
|
+
return `panda agent service uninstall --name=${quoteCommandArg(config.release_agent_service_name)}`;
|
|
9387
|
+
};
|
|
9128
9388
|
const resolveServiceCommand = async (config, key) => {
|
|
9129
9389
|
const projectPath = getExecutionRoot(config);
|
|
9130
9390
|
if (key.startsWith("dev-")) {
|
|
@@ -9171,22 +9431,14 @@ var createDevManager = ({
|
|
|
9171
9431
|
projectPath,
|
|
9172
9432
|
command: buildReleaseHubCommand(config),
|
|
9173
9433
|
nodeVersion: config.nvm_version,
|
|
9174
|
-
env:
|
|
9175
|
-
PANDA_HUB_PORT: config.release_hub_port ? String(config.release_hub_port) : null
|
|
9176
|
-
}
|
|
9434
|
+
env: buildReleaseHubEnvOverrides(config)
|
|
9177
9435
|
});
|
|
9178
9436
|
}
|
|
9179
9437
|
return resolveManagedCommand({
|
|
9180
9438
|
projectPath,
|
|
9181
9439
|
command: buildReleaseAgentCommand(config),
|
|
9182
9440
|
nodeVersion: config.nvm_version,
|
|
9183
|
-
env:
|
|
9184
|
-
PANDA_AGENT_PORT: config.release_agent_port ? String(config.release_agent_port) : null,
|
|
9185
|
-
PANDA_HUB_URL: config.release_agent_hub_url,
|
|
9186
|
-
PANDA_AGENT_DIRECT_BASE_URL: config.release_agent_direct_base_url,
|
|
9187
|
-
PANDA_AGENT_WS_BASE_URL: config.release_agent_ws_base_url,
|
|
9188
|
-
PANDA_AGENT_NAME: normalizeNullableText(config.release_agent_name)
|
|
9189
|
-
}
|
|
9441
|
+
env: buildReleaseAgentEnvOverrides(config)
|
|
9190
9442
|
});
|
|
9191
9443
|
};
|
|
9192
9444
|
const getServiceSpecs = (config) => [
|
|
@@ -9220,6 +9472,7 @@ var createDevManager = ({
|
|
|
9220
9472
|
port: config.release_hub_port,
|
|
9221
9473
|
probeUrl: buildHttpBaseUrl(config.release_hub_port, ""),
|
|
9222
9474
|
probePath: "/health",
|
|
9475
|
+
serviceName: config.release_hub_service_name,
|
|
9223
9476
|
start: () => resolveServiceCommand(config, "release-hub")
|
|
9224
9477
|
},
|
|
9225
9478
|
{
|
|
@@ -9228,18 +9481,28 @@ var createDevManager = ({
|
|
|
9228
9481
|
port: config.release_agent_port,
|
|
9229
9482
|
probeUrl: config.release_agent_direct_base_url,
|
|
9230
9483
|
probePath: "/health",
|
|
9484
|
+
serviceName: config.release_agent_service_name,
|
|
9231
9485
|
start: () => resolveServiceCommand(config, "release-agent")
|
|
9232
9486
|
}
|
|
9233
9487
|
];
|
|
9234
9488
|
const buildServiceSnapshots = async (config, options) => await Promise.all(
|
|
9235
9489
|
getServiceSpecs(config).map(async (service) => {
|
|
9236
9490
|
const quickProbe = await probeLocalPort(service.port);
|
|
9237
|
-
const
|
|
9491
|
+
const controllerStatus = queryWindowsServiceStatus(service.serviceName);
|
|
9492
|
+
const usesWindowsService = Boolean(
|
|
9493
|
+
service.key.startsWith("release-") && controllerStatus?.installed
|
|
9494
|
+
);
|
|
9495
|
+
const manager = usesWindowsService ? "windows-service" : "process";
|
|
9496
|
+
const status = usesWindowsService ? controllerStatus?.status === "running" ? quickProbe.ok ? "running" : "degraded" : controllerStatus?.status === "stopped" ? quickProbe.ok ? "degraded" : "stopped" : controllerStatus?.status === "missing" ? quickProbe.ok ? "running" : service.port || service.probeUrl ? "stopped" : "unknown" : quickProbe.ok ? "running" : "unknown" : quickProbe.ok ? "running" : service.port || service.probeUrl ? "stopped" : "unknown";
|
|
9238
9497
|
if (options?.includeProbe !== true) {
|
|
9239
9498
|
return {
|
|
9240
9499
|
key: service.key,
|
|
9241
9500
|
label: service.label,
|
|
9242
9501
|
status,
|
|
9502
|
+
manager,
|
|
9503
|
+
service_name: service.serviceName ?? null,
|
|
9504
|
+
service_registered: controllerStatus?.installed ?? false,
|
|
9505
|
+
service_status: controllerStatus?.status ?? null,
|
|
9243
9506
|
configured_port: service.port,
|
|
9244
9507
|
detected_pids: [],
|
|
9245
9508
|
probe: null
|
|
@@ -9249,6 +9512,10 @@ var createDevManager = ({
|
|
|
9249
9512
|
key: service.key,
|
|
9250
9513
|
label: service.label,
|
|
9251
9514
|
status,
|
|
9515
|
+
manager,
|
|
9516
|
+
service_name: service.serviceName ?? null,
|
|
9517
|
+
service_registered: controllerStatus?.installed ?? false,
|
|
9518
|
+
service_status: controllerStatus?.status ?? null,
|
|
9252
9519
|
configured_port: service.port,
|
|
9253
9520
|
detected_pids: [],
|
|
9254
9521
|
probe: quickProbe
|
|
@@ -9590,9 +9857,61 @@ var createDevManager = ({
|
|
|
9590
9857
|
await job.succeed("APK \u7F16\u8BD1\u5B8C\u6210\u3002");
|
|
9591
9858
|
});
|
|
9592
9859
|
};
|
|
9860
|
+
const installReleaseServices = async () => {
|
|
9861
|
+
const { config } = await readStoredConfig(codexHome);
|
|
9862
|
+
const executionRoot = getExecutionRoot(config);
|
|
9863
|
+
return runManagedJob("release-service-install", "\u6CE8\u518C\u6216\u66F4\u65B0\u6B63\u5F0F\u7248\u670D\u52A1", async (job) => {
|
|
9864
|
+
if (process.platform !== "win32") {
|
|
9865
|
+
throw new Error("\u6B63\u5F0F\u7248\u670D\u52A1\u6CE8\u518C\u5F53\u524D\u53EA\u652F\u6301 Windows\u3002");
|
|
9866
|
+
}
|
|
9867
|
+
await job.append("info", "\u51C6\u5907\u6CE8\u518C\u6216\u66F4\u65B0\u6B63\u5F0F\u7248 Hub Windows \u670D\u52A1\u3002");
|
|
9868
|
+
const hubCommand = await resolveManagedCommand({
|
|
9869
|
+
projectPath: executionRoot,
|
|
9870
|
+
command: buildReleaseHubServiceInstallCommand(config),
|
|
9871
|
+
nodeVersion: config.nvm_version,
|
|
9872
|
+
env: buildReleaseHubEnvOverrides(config)
|
|
9873
|
+
});
|
|
9874
|
+
await runCommandWithLogs(hubCommand, job, "\u6CE8\u518C\u6B63\u5F0F\u7248 Hub \u670D\u52A1");
|
|
9875
|
+
await job.append("info", "\u51C6\u5907\u6CE8\u518C\u6216\u66F4\u65B0\u6B63\u5F0F\u7248 Agent Windows \u670D\u52A1\u3002");
|
|
9876
|
+
const agentCommand = await resolveManagedCommand({
|
|
9877
|
+
projectPath: executionRoot,
|
|
9878
|
+
command: buildReleaseAgentServiceInstallCommand(config),
|
|
9879
|
+
nodeVersion: config.nvm_version,
|
|
9880
|
+
env: buildReleaseAgentEnvOverrides(config)
|
|
9881
|
+
});
|
|
9882
|
+
await runCommandWithLogs(agentCommand, job, "\u6CE8\u518C\u6B63\u5F0F\u7248 Agent \u670D\u52A1");
|
|
9883
|
+
await job.succeed("\u6B63\u5F0F\u7248 Hub \u4E0E Agent \u670D\u52A1\u5DF2\u6CE8\u518C\u6216\u66F4\u65B0\u3002");
|
|
9884
|
+
});
|
|
9885
|
+
};
|
|
9886
|
+
const uninstallReleaseServices = async () => {
|
|
9887
|
+
const { config } = await readStoredConfig(codexHome);
|
|
9888
|
+
const executionRoot = getExecutionRoot(config);
|
|
9889
|
+
return runManagedJob("release-service-uninstall", "\u79FB\u9664\u6B63\u5F0F\u7248\u670D\u52A1", async (job) => {
|
|
9890
|
+
if (process.platform !== "win32") {
|
|
9891
|
+
throw new Error("\u6B63\u5F0F\u7248\u670D\u52A1\u79FB\u9664\u5F53\u524D\u53EA\u652F\u6301 Windows\u3002");
|
|
9892
|
+
}
|
|
9893
|
+
await job.append("info", "\u51C6\u5907\u79FB\u9664\u6B63\u5F0F\u7248 Agent Windows \u670D\u52A1\u3002");
|
|
9894
|
+
const agentCommand = await resolveManagedCommand({
|
|
9895
|
+
projectPath: executionRoot,
|
|
9896
|
+
command: buildReleaseAgentServiceUninstallCommand(config),
|
|
9897
|
+
nodeVersion: config.nvm_version
|
|
9898
|
+
});
|
|
9899
|
+
await runCommandWithLogs(agentCommand, job, "\u79FB\u9664\u6B63\u5F0F\u7248 Agent \u670D\u52A1");
|
|
9900
|
+
await job.append("info", "\u51C6\u5907\u79FB\u9664\u6B63\u5F0F\u7248 Hub Windows \u670D\u52A1\u3002");
|
|
9901
|
+
const hubCommand = await resolveManagedCommand({
|
|
9902
|
+
projectPath: executionRoot,
|
|
9903
|
+
command: buildReleaseHubServiceUninstallCommand(config),
|
|
9904
|
+
nodeVersion: config.nvm_version
|
|
9905
|
+
});
|
|
9906
|
+
await runCommandWithLogs(hubCommand, job, "\u79FB\u9664\u6B63\u5F0F\u7248 Hub \u670D\u52A1");
|
|
9907
|
+
await job.succeed("\u6B63\u5F0F\u7248 Hub \u4E0E Agent \u670D\u52A1\u5DF2\u79FB\u9664\u3002");
|
|
9908
|
+
});
|
|
9909
|
+
};
|
|
9593
9910
|
const installLatestRelease = async () => {
|
|
9594
9911
|
const { config } = await readStoredConfig(codexHome);
|
|
9595
9912
|
const executionRoot = getExecutionRoot(config);
|
|
9913
|
+
const releaseHubServiceStatus = queryWindowsServiceStatus(config.release_hub_service_name);
|
|
9914
|
+
const releaseAgentServiceStatus = queryWindowsServiceStatus(config.release_agent_service_name);
|
|
9596
9915
|
const installCommand = await resolveManagedCommand({
|
|
9597
9916
|
projectPath: executionRoot,
|
|
9598
9917
|
command: `npm install -g ${RELEASE_PACKAGE_NAME}@latest --registry=${NPM_REGISTRY_URL}`,
|
|
@@ -9624,17 +9943,20 @@ var createDevManager = ({
|
|
|
9624
9943
|
stopServices: [
|
|
9625
9944
|
{
|
|
9626
9945
|
label: "\u6B63\u5F0F\u7248 Agent",
|
|
9627
|
-
port: config.release_agent_port
|
|
9946
|
+
port: config.release_agent_port,
|
|
9947
|
+
serviceName: releaseAgentServiceStatus?.installed ? config.release_agent_service_name : null
|
|
9628
9948
|
},
|
|
9629
9949
|
{
|
|
9630
9950
|
label: "\u6B63\u5F0F\u7248 Hub",
|
|
9631
|
-
port: config.release_hub_port
|
|
9951
|
+
port: config.release_hub_port,
|
|
9952
|
+
serviceName: releaseHubServiceStatus?.installed ? config.release_hub_service_name : null
|
|
9632
9953
|
}
|
|
9633
9954
|
],
|
|
9634
9955
|
installCommand,
|
|
9635
9956
|
startServices: [
|
|
9636
9957
|
{
|
|
9637
9958
|
label: "\u6B63\u5F0F\u7248 Hub",
|
|
9959
|
+
serviceName: releaseHubServiceStatus?.installed ? config.release_hub_service_name : null,
|
|
9638
9960
|
command: releaseHubCommand,
|
|
9639
9961
|
probeUrl: buildHttpBaseUrl(config.release_hub_port, ""),
|
|
9640
9962
|
probePath: "/health",
|
|
@@ -9642,6 +9964,7 @@ var createDevManager = ({
|
|
|
9642
9964
|
},
|
|
9643
9965
|
{
|
|
9644
9966
|
label: "\u6B63\u5F0F\u7248 Agent",
|
|
9967
|
+
serviceName: releaseAgentServiceStatus?.installed ? config.release_agent_service_name : null,
|
|
9645
9968
|
command: releaseAgentCommand,
|
|
9646
9969
|
probeUrl: config.release_agent_direct_base_url,
|
|
9647
9970
|
probePath: "/health",
|
|
@@ -9681,7 +10004,7 @@ var createDevManager = ({
|
|
|
9681
10004
|
};
|
|
9682
10005
|
};
|
|
9683
10006
|
const executeAction = async (action) => {
|
|
9684
|
-
const job = action === "start-development" ? await runDevelopmentLifecycle("start") : action === "restart-development" ? await runDevelopmentLifecycle("restart") : action === "stop-development" ? await runDevelopmentLifecycle("stop") : action === "probe-development" ? await runDevelopmentLifecycle("probe") : action === "publish-npm" ? await runNpmPublish() : action === "build-apk" ? await runApkBuild() : await installLatestRelease();
|
|
10007
|
+
const job = action === "start-development" ? await runDevelopmentLifecycle("start") : action === "restart-development" ? await runDevelopmentLifecycle("restart") : action === "stop-development" ? await runDevelopmentLifecycle("stop") : action === "probe-development" ? await runDevelopmentLifecycle("probe") : action === "publish-npm" ? await runNpmPublish() : action === "install-release-services" ? await installReleaseServices() : action === "uninstall-release-services" ? await uninstallReleaseServices() : action === "build-apk" ? await runApkBuild() : await installLatestRelease();
|
|
9685
10008
|
return {
|
|
9686
10009
|
ok: true,
|
|
9687
10010
|
job,
|
|
@@ -11241,7 +11564,7 @@ var startPandaSessionService = async ({
|
|
|
11241
11564
|
return nextOverlayEntries;
|
|
11242
11565
|
};
|
|
11243
11566
|
const readTimelineFromRollout = async (sessionId) => {
|
|
11244
|
-
const { readCodexTimeline } = await import("./src-
|
|
11567
|
+
const { readCodexTimeline } = await import("./src-M7W7LPHG.mjs");
|
|
11245
11568
|
return readCodexTimeline(sessionId, {
|
|
11246
11569
|
codexHome,
|
|
11247
11570
|
sessionFiles: discoveredSessionFiles
|
|
@@ -12709,7 +13032,7 @@ var startPandaSessionService = async ({
|
|
|
12709
13032
|
lastSnapshotRefreshAt = Date.now();
|
|
12710
13033
|
return snapshot;
|
|
12711
13034
|
}
|
|
12712
|
-
const { discoverLocalCodexData } = await import("./src-
|
|
13035
|
+
const { discoverLocalCodexData } = await import("./src-M7W7LPHG.mjs");
|
|
12713
13036
|
const discovery = await discoverLocalCodexData({
|
|
12714
13037
|
agentId: localAgentId,
|
|
12715
13038
|
agentName: localAgentName,
|