@commandgarden/cli 0.2.0 → 1.0.1

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.
Files changed (2) hide show
  1. package/dist/main.js +148 -5
  2. package/package.json +1 -1
package/dist/main.js CHANGED
@@ -7,7 +7,7 @@ var __export = (target, all) => {
7
7
 
8
8
  // src/main.ts
9
9
  import { Command } from "commander";
10
- import { join as join2, dirname } from "path";
10
+ import { join as join3, dirname } from "path";
11
11
  import { homedir } from "os";
12
12
  import { fileURLToPath } from "url";
13
13
 
@@ -4870,13 +4870,136 @@ async function executeConfigSet(client, key, value) {
4870
4870
  }
4871
4871
  }
4872
4872
 
4873
+ // src/commands/gui-cmd.ts
4874
+ import { spawn as spawn2 } from "child_process";
4875
+ import { readFileSync as readFileSync5, writeFileSync as writeFileSync2, existsSync as existsSync3, unlinkSync as unlinkSync2, mkdirSync as mkdirSync2 } from "fs";
4876
+ import { join as join2 } from "path";
4877
+ import { exec } from "child_process";
4878
+ import { parse as parseYaml2 } from "yaml";
4879
+ function readAppPort(configPath) {
4880
+ try {
4881
+ if (existsSync3(configPath)) {
4882
+ const config2 = parseYaml2(readFileSync5(configPath, "utf-8"));
4883
+ const port = config2?.app?.port;
4884
+ if (typeof port === "number") return port;
4885
+ }
4886
+ } catch {
4887
+ }
4888
+ return 19826;
4889
+ }
4890
+ async function executeGuiStart(baseUrl, cgHome, appScript, opts) {
4891
+ const appPort = opts.configPath ? readAppPort(opts.configPath) : 19826;
4892
+ try {
4893
+ const resp = await fetch(`${baseUrl}/api/status`);
4894
+ if (!resp.ok) throw new Error();
4895
+ } catch {
4896
+ return "Daemon is not running. Start it with: cg daemon start (or use cg up)";
4897
+ }
4898
+ const pidPath = join2(cgHome, "app.pid");
4899
+ if (existsSync3(pidPath)) {
4900
+ const pid = parseInt(readFileSync5(pidPath, "utf-8").trim(), 10);
4901
+ try {
4902
+ process.kill(pid, 0);
4903
+ return "GUI is already running.";
4904
+ } catch {
4905
+ unlinkSync2(pidPath);
4906
+ }
4907
+ }
4908
+ mkdirSync2(cgHome, { recursive: true });
4909
+ if (opts.background) {
4910
+ const child2 = spawn2("node", [appScript], { detached: true, stdio: "ignore" });
4911
+ if (child2.pid) writeFileSync2(pidPath, String(child2.pid));
4912
+ child2.unref();
4913
+ if (!opts.noOpen) {
4914
+ const appUrl = `http://127.0.0.1:${appPort}`;
4915
+ for (let i = 0; i < 20; i++) {
4916
+ try {
4917
+ await fetch(appUrl);
4918
+ break;
4919
+ } catch {
4920
+ }
4921
+ await new Promise((r) => setTimeout(r, 250));
4922
+ }
4923
+ openBrowser(appUrl);
4924
+ }
4925
+ return `GUI started (PID: ${child2.pid ?? "unknown"}).`;
4926
+ }
4927
+ const child = spawn2("node", [appScript], { stdio: "inherit" });
4928
+ if (!opts.noOpen) {
4929
+ const appUrl = `http://127.0.0.1:${appPort}`;
4930
+ for (let i = 0; i < 20; i++) {
4931
+ try {
4932
+ await fetch(appUrl);
4933
+ break;
4934
+ } catch {
4935
+ }
4936
+ await new Promise((r) => setTimeout(r, 250));
4937
+ }
4938
+ openBrowser(appUrl);
4939
+ }
4940
+ await new Promise((resolve) => child.on("exit", () => resolve()));
4941
+ return "GUI stopped.";
4942
+ }
4943
+ function executeGuiStop(cgHome) {
4944
+ const pidPath = join2(cgHome, "app.pid");
4945
+ if (!existsSync3(pidPath)) return "GUI is not running (no PID file found).";
4946
+ const pid = parseInt(readFileSync5(pidPath, "utf-8").trim(), 10);
4947
+ try {
4948
+ process.kill(pid, "SIGTERM");
4949
+ unlinkSync2(pidPath);
4950
+ return `GUI stopped (PID: ${pid}).`;
4951
+ } catch {
4952
+ unlinkSync2(pidPath);
4953
+ return `GUI process ${pid} not found (stale PID file cleaned up).`;
4954
+ }
4955
+ }
4956
+ function executeGuiStatus(cgHome) {
4957
+ const pidPath = join2(cgHome, "app.pid");
4958
+ if (!existsSync3(pidPath)) return "GUI: not running (no PID file found).";
4959
+ const pid = parseInt(readFileSync5(pidPath, "utf-8").trim(), 10);
4960
+ try {
4961
+ process.kill(pid, 0);
4962
+ return `GUI: running (PID: ${pid}).`;
4963
+ } catch {
4964
+ return "GUI: not running (stale PID file).";
4965
+ }
4966
+ }
4967
+ function openBrowser(url) {
4968
+ const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
4969
+ exec(`${cmd} ${url}`);
4970
+ }
4971
+
4972
+ // src/commands/up-down.ts
4973
+ async function executeUp(baseUrl, cgHome, daemonScript, appScript, configPath) {
4974
+ const lines = [];
4975
+ lines.push(await executeDaemonStart(baseUrl, cgHome, daemonScript));
4976
+ for (let i = 0; i < 10; i++) {
4977
+ try {
4978
+ const resp = await fetch(`${baseUrl}/api/status`);
4979
+ if (resp.ok) break;
4980
+ } catch {
4981
+ }
4982
+ await new Promise((r) => setTimeout(r, 500));
4983
+ }
4984
+ lines.push(await executeGuiStart(baseUrl, cgHome, appScript, { background: true, configPath }));
4985
+ return lines.join("\n");
4986
+ }
4987
+ async function executeDown(cgHome) {
4988
+ const lines = [];
4989
+ lines.push(executeGuiStop(cgHome));
4990
+ lines.push(await executeDaemonStop(cgHome));
4991
+ lines.push("All services stopped.");
4992
+ return lines.join("\n");
4993
+ }
4994
+
4873
4995
  // src/main.ts
4874
4996
  var __filename = fileURLToPath(import.meta.url);
4875
4997
  var __dirname = dirname(__filename);
4876
- var DAEMON_SCRIPT = join2(__dirname, "..", "..", "daemon", "dist", "main.js");
4877
- var CG_HOME = join2(homedir(), ".commandgarden");
4878
- var TOKEN_PATH = join2(CG_HOME, "session-token");
4879
- var CONFIG_PATH = join2(CG_HOME, "config.yaml");
4998
+ var DAEMON_SCRIPT = join3(__dirname, "..", "..", "daemon", "dist", "main.js");
4999
+ var APP_SCRIPT = join3(__dirname, "..", "..", "app", "dist", "server", "main.js");
5000
+ var CG_HOME = join3(homedir(), ".commandgarden");
5001
+ var TOKEN_PATH = join3(CG_HOME, "session-token");
5002
+ var CONFIG_PATH = join3(CG_HOME, "config.yaml");
4880
5003
  var BASE_URL = `http://127.0.0.1:19825`;
4881
5004
  function createClient() {
4882
5005
  const token = readToken(TOKEN_PATH);
@@ -4945,4 +5068,24 @@ config.command("set <key> <value>").description("Set a configuration value (e.g.
4945
5068
  const client = createClient();
4946
5069
  console.log(await executeConfigSet(client, key, value));
4947
5070
  });
5071
+ var gui = program.command("gui").description("Manage the GUI app server");
5072
+ gui.command("start", { isDefault: true }).description("Start the GUI (foreground by default)").option("-b, --background", "Run in background").option("--no-open", "Do not open browser").action(async (opts) => {
5073
+ console.log(await executeGuiStart(BASE_URL, CG_HOME, APP_SCRIPT, {
5074
+ background: opts.background,
5075
+ noOpen: opts.open === false,
5076
+ configPath: CONFIG_PATH
5077
+ }));
5078
+ });
5079
+ gui.command("stop").description("Stop the GUI").action(() => {
5080
+ console.log(executeGuiStop(CG_HOME));
5081
+ });
5082
+ gui.command("status").description("Check GUI status").action(() => {
5083
+ console.log(executeGuiStatus(CG_HOME));
5084
+ });
5085
+ program.command("up").description("Start daemon + GUI, open browser").action(async () => {
5086
+ console.log(await executeUp(BASE_URL, CG_HOME, DAEMON_SCRIPT, APP_SCRIPT, CONFIG_PATH));
5087
+ });
5088
+ program.command("down").description("Stop GUI + daemon").action(async () => {
5089
+ console.log(await executeDown(CG_HOME));
5090
+ });
4948
5091
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@commandgarden/cli",
3
- "version": "0.2.0",
3
+ "version": "1.0.1",
4
4
  "description": "Enterprise browser automation CLI",
5
5
  "type": "module",
6
6
  "license": "MIT",