@feynmanzhang/open-party 0.1.2 → 0.1.3-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +349 -28
- package/dist/cli/index.js.map +1 -1
- package/dist/party-server.js +16 -1
- package/dist/party-server.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -201,7 +201,7 @@ function joinTailnet(authKey, timeout = 3e4) {
|
|
|
201
201
|
const binary = getTailscaleBinary();
|
|
202
202
|
try {
|
|
203
203
|
const output = execWithSudoFallback(
|
|
204
|
-
[binary, "up", "--authkey", authKey
|
|
204
|
+
[binary, "up", "--authkey", authKey],
|
|
205
205
|
timeout
|
|
206
206
|
);
|
|
207
207
|
return { success: true, output: output.trim() };
|
|
@@ -3171,7 +3171,7 @@ var init_dist2 = __esm({
|
|
|
3171
3171
|
});
|
|
3172
3172
|
if (!chunk) {
|
|
3173
3173
|
if (i === 1) {
|
|
3174
|
-
await new Promise((
|
|
3174
|
+
await new Promise((resolve3) => setTimeout(resolve3));
|
|
3175
3175
|
maxReadCount = 3;
|
|
3176
3176
|
continue;
|
|
3177
3177
|
}
|
|
@@ -3410,8 +3410,8 @@ function classifyFetchError(error) {
|
|
|
3410
3410
|
if (error instanceof DOMException && error.name === "AbortError") return null;
|
|
3411
3411
|
return null;
|
|
3412
3412
|
}
|
|
3413
|
-
function
|
|
3414
|
-
return new Promise((
|
|
3413
|
+
function sleep2(ms) {
|
|
3414
|
+
return new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
3415
3415
|
}
|
|
3416
3416
|
var UNKNOWN, PARTY_SERVER, DEGRADED, SUSPECT, DOWN, NOT_SERVER, MAYBE, MAYBE_MAX_RETRIES, BACKOFF_BASE, BACKOFF_CAP, FAILURE_SUSPECT, FAILURE_DOWN, PeerDiscovery;
|
|
3417
3417
|
var init_peer_discovery = __esm({
|
|
@@ -3487,7 +3487,7 @@ var init_peer_discovery = __esm({
|
|
|
3487
3487
|
} catch (e) {
|
|
3488
3488
|
console.error("[Discovery] Cycle failed:", e);
|
|
3489
3489
|
}
|
|
3490
|
-
await
|
|
3490
|
+
await sleep2(DISCOVERY_INTERVAL * 1e3);
|
|
3491
3491
|
}
|
|
3492
3492
|
}
|
|
3493
3493
|
async discoveryCycle() {
|
|
@@ -4940,9 +4940,20 @@ var init_dashboard = __esm({
|
|
|
4940
4940
|
|
|
4941
4941
|
// src/server/index.ts
|
|
4942
4942
|
var server_exports = {};
|
|
4943
|
+
import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync3, unlinkSync as unlinkSync2 } from "fs";
|
|
4944
|
+
import { join as join5, dirname as dirname3 } from "path";
|
|
4945
|
+
import { homedir as homedir4 } from "os";
|
|
4943
4946
|
async function periodicCleanup() {
|
|
4944
4947
|
}
|
|
4948
|
+
function pidFilePath2() {
|
|
4949
|
+
const pluginData = process.env.CLAUDE_PLUGIN_DATA || "";
|
|
4950
|
+
if (pluginData) return join5(pluginData, "server.pid");
|
|
4951
|
+
return join5(homedir4(), ".open-party", "server.pid");
|
|
4952
|
+
}
|
|
4945
4953
|
async function main() {
|
|
4954
|
+
const pidPath = pidFilePath2();
|
|
4955
|
+
mkdirSync3(dirname3(pidPath), { recursive: true });
|
|
4956
|
+
writeFileSync3(pidPath, String(process.pid));
|
|
4946
4957
|
console.log(`Starting Party Server on port ${PARTY_PORT} (Tailscale IP: ${getSelfIp()})`);
|
|
4947
4958
|
process.on("SIGHUP", () => {
|
|
4948
4959
|
});
|
|
@@ -4951,6 +4962,10 @@ async function main() {
|
|
|
4951
4962
|
const cleanupPromise = periodicCleanup();
|
|
4952
4963
|
const shutdown = () => {
|
|
4953
4964
|
console.log("\nShutting down Party Server...");
|
|
4965
|
+
try {
|
|
4966
|
+
unlinkSync2(pidPath);
|
|
4967
|
+
} catch {
|
|
4968
|
+
}
|
|
4954
4969
|
server.close();
|
|
4955
4970
|
process.exit(0);
|
|
4956
4971
|
};
|
|
@@ -5011,7 +5026,7 @@ async function installTailscale(platform) {
|
|
|
5011
5026
|
const args2 = entry.needsSudo ? [entry.cmd, ...entry.args] : entry.args;
|
|
5012
5027
|
console.log(`Running: ${cmd} ${args2.join(" ")}
|
|
5013
5028
|
`);
|
|
5014
|
-
return new Promise((
|
|
5029
|
+
return new Promise((resolve3) => {
|
|
5015
5030
|
const child = spawn(cmd, args2, {
|
|
5016
5031
|
stdio: "inherit",
|
|
5017
5032
|
windowsHide: true
|
|
@@ -5021,15 +5036,15 @@ async function installTailscale(platform) {
|
|
|
5021
5036
|
if (exited) return;
|
|
5022
5037
|
exited = true;
|
|
5023
5038
|
if (code === 0) {
|
|
5024
|
-
|
|
5039
|
+
resolve3({ success: true, output: "Installation completed." });
|
|
5025
5040
|
} else {
|
|
5026
|
-
|
|
5041
|
+
resolve3({ success: false, output: `Installation exited with code ${code}` });
|
|
5027
5042
|
}
|
|
5028
5043
|
});
|
|
5029
5044
|
child.on("error", (err) => {
|
|
5030
5045
|
if (exited) return;
|
|
5031
5046
|
exited = true;
|
|
5032
|
-
|
|
5047
|
+
resolve3({ success: false, output: err.message });
|
|
5033
5048
|
});
|
|
5034
5049
|
});
|
|
5035
5050
|
}
|
|
@@ -5320,7 +5335,7 @@ async function installPluginToAgent(agentType) {
|
|
|
5320
5335
|
// src/cli/setup.ts
|
|
5321
5336
|
var rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
5322
5337
|
function prompt(question) {
|
|
5323
|
-
return new Promise((
|
|
5338
|
+
return new Promise((resolve3) => rl.question(question, (answer) => resolve3(answer.trim())));
|
|
5324
5339
|
}
|
|
5325
5340
|
function cyan(text) {
|
|
5326
5341
|
return `\x1B[36m${text}\x1B[0m`;
|
|
@@ -5423,10 +5438,10 @@ async function handleInteractiveLogin(binary) {
|
|
|
5423
5438
|
console.log(`
|
|
5424
5439
|
${cyan("Running interactive login...")}`);
|
|
5425
5440
|
console.log("A browser window should open. Authenticate in the browser, then return here.\n");
|
|
5426
|
-
const { spawn:
|
|
5427
|
-
const child =
|
|
5428
|
-
const exitCode = await new Promise((
|
|
5429
|
-
child.on("close",
|
|
5441
|
+
const { spawn: spawn3 } = await import("child_process");
|
|
5442
|
+
const child = spawn3(binary, ["login"], { stdio: "inherit" });
|
|
5443
|
+
const exitCode = await new Promise((resolve3) => {
|
|
5444
|
+
child.on("close", resolve3);
|
|
5430
5445
|
});
|
|
5431
5446
|
resetTailscaleBinaryCache();
|
|
5432
5447
|
const status = getTailscaleInstallationStatus();
|
|
@@ -5442,7 +5457,7 @@ ${yellow("\u26A0\uFE0F Login may not have completed. Status: " + status.state)}
|
|
|
5442
5457
|
}
|
|
5443
5458
|
async function handleAuthKeyLogin(binary) {
|
|
5444
5459
|
console.log("");
|
|
5445
|
-
console.log("
|
|
5460
|
+
console.log("Ask the network creator to generate an Auth Key at:");
|
|
5446
5461
|
console.log(`${cyan(" https://login.tailscale.com/admin/settings/keys")}
|
|
5447
5462
|
`);
|
|
5448
5463
|
const authKey = await prompt("Enter Auth Key: ");
|
|
@@ -5532,12 +5547,12 @@ async function setupCommand() {
|
|
|
5532
5547
|
await stepAgentPlugin();
|
|
5533
5548
|
console.log(`
|
|
5534
5549
|
${bold(cyan("\u{1F680} Starting Party Server..."))}`);
|
|
5535
|
-
const { spawn:
|
|
5536
|
-
const { resolve:
|
|
5537
|
-
const { fileURLToPath } = await import("url");
|
|
5538
|
-
const
|
|
5539
|
-
const serverScript =
|
|
5540
|
-
const serverProc =
|
|
5550
|
+
const { spawn: spawn3 } = await import("child_process");
|
|
5551
|
+
const { resolve: resolve3, dirname: dirname4 } = await import("path");
|
|
5552
|
+
const { fileURLToPath: fileURLToPath2 } = await import("url");
|
|
5553
|
+
const __dirname2 = dirname4(fileURLToPath2(import.meta.url));
|
|
5554
|
+
const serverScript = resolve3(__dirname2, "..", "party-server.js");
|
|
5555
|
+
const serverProc = spawn3(process.execPath, [serverScript], {
|
|
5541
5556
|
detached: true,
|
|
5542
5557
|
stdio: "ignore",
|
|
5543
5558
|
windowsHide: true
|
|
@@ -5551,28 +5566,334 @@ ${bold(green("\u{1F389} Setup complete!"))}`);
|
|
|
5551
5566
|
rl.close();
|
|
5552
5567
|
}
|
|
5553
5568
|
|
|
5569
|
+
// src/cli/server-utils.ts
|
|
5570
|
+
import { spawn as spawn2, execSync as execSync3 } from "child_process";
|
|
5571
|
+
import { existsSync as existsSync4, readFileSync as readFileSync2, writeFileSync as writeFileSync2, unlinkSync, mkdirSync as mkdirSync2, openSync } from "fs";
|
|
5572
|
+
import { join as join4, dirname as dirname2, resolve as resolve2 } from "path";
|
|
5573
|
+
import { homedir as homedir3 } from "os";
|
|
5574
|
+
import { fileURLToPath } from "url";
|
|
5575
|
+
var __dirname = dirname2(fileURLToPath(import.meta.url));
|
|
5576
|
+
function pidFilePath() {
|
|
5577
|
+
const pluginData = process.env.CLAUDE_PLUGIN_DATA || "";
|
|
5578
|
+
if (pluginData) return join4(pluginData, "server.pid");
|
|
5579
|
+
return join4(homedir3(), ".open-party", "server.pid");
|
|
5580
|
+
}
|
|
5581
|
+
function logFilePath() {
|
|
5582
|
+
const pluginData = process.env.CLAUDE_PLUGIN_DATA || "";
|
|
5583
|
+
if (pluginData) return join4(pluginData, "server.log");
|
|
5584
|
+
return join4(homedir3(), ".open-party", "server.log");
|
|
5585
|
+
}
|
|
5586
|
+
function serverScriptPath() {
|
|
5587
|
+
return resolve2(__dirname, "..", "party-server.js");
|
|
5588
|
+
}
|
|
5589
|
+
function readPid() {
|
|
5590
|
+
const path = pidFilePath();
|
|
5591
|
+
if (!existsSync4(path)) return null;
|
|
5592
|
+
try {
|
|
5593
|
+
return parseInt(readFileSync2(path, "utf-8").trim(), 10);
|
|
5594
|
+
} catch {
|
|
5595
|
+
return null;
|
|
5596
|
+
}
|
|
5597
|
+
}
|
|
5598
|
+
function writePid(pid) {
|
|
5599
|
+
const path = pidFilePath();
|
|
5600
|
+
const dir = dirname2(path);
|
|
5601
|
+
if (!existsSync4(dir)) mkdirSync2(dir, { recursive: true });
|
|
5602
|
+
writeFileSync2(path, String(pid));
|
|
5603
|
+
}
|
|
5604
|
+
function removePidFile() {
|
|
5605
|
+
try {
|
|
5606
|
+
unlinkSync(pidFilePath());
|
|
5607
|
+
} catch {
|
|
5608
|
+
}
|
|
5609
|
+
}
|
|
5610
|
+
function isProcessRunning(pid) {
|
|
5611
|
+
if (process.platform === "win32") {
|
|
5612
|
+
try {
|
|
5613
|
+
const output = execSync3(`tasklist /FI "PID eq ${pid}" /NH`, {
|
|
5614
|
+
encoding: "utf-8",
|
|
5615
|
+
windowsHide: true,
|
|
5616
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
5617
|
+
});
|
|
5618
|
+
return output.includes(String(pid));
|
|
5619
|
+
} catch {
|
|
5620
|
+
return false;
|
|
5621
|
+
}
|
|
5622
|
+
}
|
|
5623
|
+
try {
|
|
5624
|
+
process.kill(pid, 0);
|
|
5625
|
+
return true;
|
|
5626
|
+
} catch {
|
|
5627
|
+
return false;
|
|
5628
|
+
}
|
|
5629
|
+
}
|
|
5630
|
+
function resolvePort() {
|
|
5631
|
+
return parseInt(process.env.PARTY_PORT || "8000", 10);
|
|
5632
|
+
}
|
|
5633
|
+
async function fetchJson(url, timeoutMs = 2e3) {
|
|
5634
|
+
try {
|
|
5635
|
+
const controller = new AbortController();
|
|
5636
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
5637
|
+
const resp = await fetch(url, { signal: controller.signal });
|
|
5638
|
+
clearTimeout(timer);
|
|
5639
|
+
if (!resp.ok) return null;
|
|
5640
|
+
return await resp.json();
|
|
5641
|
+
} catch {
|
|
5642
|
+
return null;
|
|
5643
|
+
}
|
|
5644
|
+
}
|
|
5645
|
+
async function isServerHealthy(port) {
|
|
5646
|
+
const p = port ?? resolvePort();
|
|
5647
|
+
const data = await fetchJson(`http://127.0.0.1:${p}/proxy/health`);
|
|
5648
|
+
return data !== null && data.status === "ok";
|
|
5649
|
+
}
|
|
5650
|
+
async function getServerHealth(port) {
|
|
5651
|
+
const p = port ?? resolvePort();
|
|
5652
|
+
return fetchJson(`http://127.0.0.1:${p}/proxy/health`);
|
|
5653
|
+
}
|
|
5654
|
+
async function getServerOverview(port) {
|
|
5655
|
+
const p = port ?? resolvePort();
|
|
5656
|
+
return fetchJson(`http://127.0.0.1:${p}/dashboard/api/overview`, 3e3);
|
|
5657
|
+
}
|
|
5658
|
+
async function spawnServerInBackground(port) {
|
|
5659
|
+
const script = serverScriptPath();
|
|
5660
|
+
if (!existsSync4(script)) {
|
|
5661
|
+
console.error(`Server script not found: ${script}`);
|
|
5662
|
+
return { pid: 0, ok: false };
|
|
5663
|
+
}
|
|
5664
|
+
const logPath = logFilePath();
|
|
5665
|
+
mkdirSync2(dirname2(logPath), { recursive: true });
|
|
5666
|
+
const logFd = openSync(logPath, "a");
|
|
5667
|
+
const env = { ...process.env, PARTY_PORT: String(port) };
|
|
5668
|
+
const proc = spawn2(process.execPath, [script], {
|
|
5669
|
+
stdio: ["ignore", logFd, logFd],
|
|
5670
|
+
detached: true,
|
|
5671
|
+
windowsHide: true,
|
|
5672
|
+
env
|
|
5673
|
+
});
|
|
5674
|
+
proc.unref();
|
|
5675
|
+
const pid = proc.pid;
|
|
5676
|
+
writePid(pid);
|
|
5677
|
+
proc.on("error", (err) => {
|
|
5678
|
+
console.error(`Failed to start server: ${err.message}`);
|
|
5679
|
+
});
|
|
5680
|
+
return { pid, ok: true };
|
|
5681
|
+
}
|
|
5682
|
+
async function waitForServerReady(port, timeoutMs = 1e4) {
|
|
5683
|
+
const deadline = Date.now() + timeoutMs;
|
|
5684
|
+
while (Date.now() < deadline) {
|
|
5685
|
+
if (await isServerHealthy(port)) return true;
|
|
5686
|
+
const pid = readPid();
|
|
5687
|
+
if (pid !== null && !isProcessRunning(pid)) {
|
|
5688
|
+
return false;
|
|
5689
|
+
}
|
|
5690
|
+
await sleep(500);
|
|
5691
|
+
}
|
|
5692
|
+
return false;
|
|
5693
|
+
}
|
|
5694
|
+
function killServer(pid) {
|
|
5695
|
+
try {
|
|
5696
|
+
if (process.platform === "win32") {
|
|
5697
|
+
execSync3(`taskkill /F /T /PID ${pid}`, { stdio: "ignore", windowsHide: true });
|
|
5698
|
+
} else {
|
|
5699
|
+
process.kill(pid, "SIGTERM");
|
|
5700
|
+
}
|
|
5701
|
+
} catch {
|
|
5702
|
+
}
|
|
5703
|
+
}
|
|
5704
|
+
function parseStartArgs(args2) {
|
|
5705
|
+
let daemon = false;
|
|
5706
|
+
let port = null;
|
|
5707
|
+
for (let i = 0; i < args2.length; i++) {
|
|
5708
|
+
if (args2[i] === "-d" || args2[i] === "--daemon") {
|
|
5709
|
+
daemon = true;
|
|
5710
|
+
} else if (args2[i] === "-p" || args2[i] === "--port") {
|
|
5711
|
+
const val = args2[++i];
|
|
5712
|
+
if (val) port = parseInt(val, 10);
|
|
5713
|
+
} else if (args2[i].startsWith("--port=")) {
|
|
5714
|
+
port = parseInt(args2[i].split("=")[1], 10);
|
|
5715
|
+
}
|
|
5716
|
+
}
|
|
5717
|
+
return { daemon, port };
|
|
5718
|
+
}
|
|
5719
|
+
function sleep(ms) {
|
|
5720
|
+
return new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
5721
|
+
}
|
|
5722
|
+
|
|
5554
5723
|
// src/cli/start-server.ts
|
|
5555
|
-
async function startServer() {
|
|
5724
|
+
async function startServer(args2 = []) {
|
|
5725
|
+
const opts = parseStartArgs(args2);
|
|
5726
|
+
const port = opts.port ?? resolvePort();
|
|
5727
|
+
if (opts.daemon) {
|
|
5728
|
+
await startDaemon(port);
|
|
5729
|
+
} else {
|
|
5730
|
+
await startForeground();
|
|
5731
|
+
}
|
|
5732
|
+
}
|
|
5733
|
+
async function startForeground() {
|
|
5734
|
+
writePid(process.pid);
|
|
5735
|
+
process.on("exit", () => {
|
|
5736
|
+
removePidFile();
|
|
5737
|
+
});
|
|
5556
5738
|
await Promise.resolve().then(() => (init_server(), server_exports));
|
|
5557
5739
|
}
|
|
5740
|
+
async function startDaemon(port) {
|
|
5741
|
+
if (await isServerHealthy(port)) {
|
|
5742
|
+
const pid2 = readPid();
|
|
5743
|
+
console.log(`Party Server is already running (PID ${pid2 ?? "unknown"}, port ${port}).`);
|
|
5744
|
+
process.exit(0);
|
|
5745
|
+
}
|
|
5746
|
+
const existingPid = readPid();
|
|
5747
|
+
if (existingPid !== null && !isProcessRunning(existingPid)) {
|
|
5748
|
+
removePidFile();
|
|
5749
|
+
}
|
|
5750
|
+
const { pid, ok } = await spawnServerInBackground(port);
|
|
5751
|
+
if (!ok) {
|
|
5752
|
+
process.exit(1);
|
|
5753
|
+
}
|
|
5754
|
+
console.log(`Starting Party Server in background (PID ${pid})...`);
|
|
5755
|
+
const ready = await waitForServerReady(port);
|
|
5756
|
+
if (ready) {
|
|
5757
|
+
console.log(`Party Server is running on port ${port}.`);
|
|
5758
|
+
console.log(` Dashboard: http://127.0.0.1:${port}/dashboard`);
|
|
5759
|
+
console.log(` Logs: ${logFilePath()}`);
|
|
5760
|
+
console.log(` Use 'open-party stop' to stop the server.`);
|
|
5761
|
+
} else {
|
|
5762
|
+
console.error("Party Server failed to start within timeout.");
|
|
5763
|
+
console.error(`Check logs: ${logFilePath()}`);
|
|
5764
|
+
process.exit(1);
|
|
5765
|
+
}
|
|
5766
|
+
}
|
|
5767
|
+
|
|
5768
|
+
// src/cli/stop-server.ts
|
|
5769
|
+
async function stopServer() {
|
|
5770
|
+
const pid = readPid();
|
|
5771
|
+
if (pid === null) {
|
|
5772
|
+
const port2 = resolvePort();
|
|
5773
|
+
const healthy = await isServerHealthy(port2);
|
|
5774
|
+
if (healthy) {
|
|
5775
|
+
console.log(`No PID file found, but a server is responding on port ${port2}.`);
|
|
5776
|
+
console.log("It may have been started manually. Kill it by port or process name.");
|
|
5777
|
+
} else {
|
|
5778
|
+
console.log("Party Server is not running (no PID file found).");
|
|
5779
|
+
}
|
|
5780
|
+
return;
|
|
5781
|
+
}
|
|
5782
|
+
if (!isProcessRunning(pid)) {
|
|
5783
|
+
console.log(`Stale PID file found (PID ${pid} is not running). Cleaning up.`);
|
|
5784
|
+
removePidFile();
|
|
5785
|
+
return;
|
|
5786
|
+
}
|
|
5787
|
+
console.log(`Stopping Party Server (PID ${pid})...`);
|
|
5788
|
+
killServer(pid);
|
|
5789
|
+
removePidFile();
|
|
5790
|
+
const port = resolvePort();
|
|
5791
|
+
const stillUp = await isServerHealthy(port);
|
|
5792
|
+
if (stillUp) {
|
|
5793
|
+
console.warn(`Process ${pid} was killed, but port ${port} is still responding.`);
|
|
5794
|
+
console.warn("Another process may be using this port.");
|
|
5795
|
+
} else {
|
|
5796
|
+
console.log("Party Server stopped.");
|
|
5797
|
+
}
|
|
5798
|
+
}
|
|
5799
|
+
|
|
5800
|
+
// src/cli/status.ts
|
|
5801
|
+
async function statusCommand() {
|
|
5802
|
+
const port = resolvePort();
|
|
5803
|
+
const pid = readPid();
|
|
5804
|
+
let processAlive = false;
|
|
5805
|
+
if (pid !== null) {
|
|
5806
|
+
processAlive = isProcessRunning(pid);
|
|
5807
|
+
}
|
|
5808
|
+
const healthy = await isServerHealthy(port);
|
|
5809
|
+
if (healthy) {
|
|
5810
|
+
const health = await getServerHealth(port);
|
|
5811
|
+
const overview = await getServerOverview(port);
|
|
5812
|
+
console.log("Party Server is running.");
|
|
5813
|
+
console.log(` PID: ${pid ?? "unknown (no PID file)"}`);
|
|
5814
|
+
console.log(` Port: ${port}`);
|
|
5815
|
+
console.log(` Tailscale IP: ${health?.tailscale_ip ?? "N/A"}`);
|
|
5816
|
+
console.log(` Hostname: ${health?.hostname ?? "N/A"}`);
|
|
5817
|
+
if (overview) {
|
|
5818
|
+
const server = overview.server;
|
|
5819
|
+
const agents = overview.agents;
|
|
5820
|
+
if (server?.uptime_seconds != null) {
|
|
5821
|
+
const uptime = server.uptime_seconds;
|
|
5822
|
+
const mins = Math.floor(uptime / 60);
|
|
5823
|
+
const secs = Math.floor(uptime % 60);
|
|
5824
|
+
console.log(` Uptime: ${mins}m ${secs}s`);
|
|
5825
|
+
}
|
|
5826
|
+
console.log(` Local agents: ${agents?.local_count ?? "N/A"}`);
|
|
5827
|
+
console.log(` Remote agents: ${agents?.remote_count ?? "N/A"}`);
|
|
5828
|
+
} else {
|
|
5829
|
+
console.log(` Local agents: ${health?.agent_count ?? "N/A"}`);
|
|
5830
|
+
}
|
|
5831
|
+
console.log(` Dashboard: http://127.0.0.1:${port}/dashboard`);
|
|
5832
|
+
} else if (processAlive && pid !== null) {
|
|
5833
|
+
console.log("Party Server process exists but is not responding on health endpoint.");
|
|
5834
|
+
console.log(` PID: ${pid}`);
|
|
5835
|
+
console.log(" The server may be starting up or has crashed.");
|
|
5836
|
+
console.log(` Logs: ~/.open-party/server.log`);
|
|
5837
|
+
} else if (pid !== null) {
|
|
5838
|
+
console.log("Party Server is NOT running (stale PID file).");
|
|
5839
|
+
console.log(` PID file references PID ${pid}, which is not a live process.`);
|
|
5840
|
+
console.log(" Use: open-party start to start the server.");
|
|
5841
|
+
} else {
|
|
5842
|
+
console.log("Party Server is NOT running.");
|
|
5843
|
+
console.log(" No PID file found.");
|
|
5844
|
+
console.log(" Use: open-party start to start the server.");
|
|
5845
|
+
}
|
|
5846
|
+
}
|
|
5558
5847
|
|
|
5559
5848
|
// src/cli/index.ts
|
|
5849
|
+
function showHelp() {
|
|
5850
|
+
console.log(`Usage: open-party <command> [options]
|
|
5851
|
+
|
|
5852
|
+
Commands:
|
|
5853
|
+
start Start the Party Server (default when no command given)
|
|
5854
|
+
stop Stop the Party Server
|
|
5855
|
+
status Show server status
|
|
5856
|
+
setup Interactive setup wizard (Tailscale + agent plugins)
|
|
5857
|
+
help Show this help message
|
|
5858
|
+
|
|
5859
|
+
Options for 'start':
|
|
5860
|
+
-d, --daemon Run in background (daemon mode)
|
|
5861
|
+
-p, --port <port> Override port (default: 8000, env: PARTY_PORT)
|
|
5862
|
+
|
|
5863
|
+
Examples:
|
|
5864
|
+
open-party Start server in foreground
|
|
5865
|
+
open-party start Start server in foreground
|
|
5866
|
+
open-party start -d Start server in background
|
|
5867
|
+
open-party start -d -p 9000 Start server in background on port 9000
|
|
5868
|
+
open-party stop Stop the server
|
|
5869
|
+
open-party status Check if the server is running`);
|
|
5870
|
+
}
|
|
5560
5871
|
var args = process.argv.slice(2);
|
|
5561
5872
|
var command = args[0] ?? "start";
|
|
5873
|
+
var commandArgs = args.slice(1);
|
|
5562
5874
|
async function main2() {
|
|
5563
5875
|
switch (command) {
|
|
5564
5876
|
case "setup":
|
|
5565
5877
|
await setupCommand();
|
|
5566
5878
|
break;
|
|
5567
5879
|
case "start":
|
|
5568
|
-
await startServer();
|
|
5880
|
+
await startServer(commandArgs);
|
|
5881
|
+
break;
|
|
5882
|
+
case "stop":
|
|
5883
|
+
await stopServer();
|
|
5884
|
+
break;
|
|
5885
|
+
case "status":
|
|
5886
|
+
await statusCommand();
|
|
5887
|
+
break;
|
|
5888
|
+
case "help":
|
|
5889
|
+
case "--help":
|
|
5890
|
+
case "-h":
|
|
5891
|
+
showHelp();
|
|
5569
5892
|
break;
|
|
5570
5893
|
default:
|
|
5571
|
-
console.log(`
|
|
5572
|
-
|
|
5573
|
-
|
|
5574
|
-
console.log(" setup Interactive setup wizard (Tailscale + agent plugins)");
|
|
5575
|
-
console.log(" start Start the Party Server (default)");
|
|
5894
|
+
console.log(`Unknown command: ${command}
|
|
5895
|
+
`);
|
|
5896
|
+
showHelp();
|
|
5576
5897
|
process.exit(1);
|
|
5577
5898
|
}
|
|
5578
5899
|
}
|