moonlait 0.2.1 → 0.3.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.
Files changed (3) hide show
  1. package/README.md +13 -0
  2. package/dist/cli.js +84 -65
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -46,6 +46,19 @@ moonlait service install
46
46
  `moonlait service status` says whether it is running, `moonlait service
47
47
  uninstall` removes it, and its log is `~/.moonlait/bridge.log`.
48
48
 
49
+ ### Two at once
50
+
51
+ A second bridge — a local Moonlait beside the real one — keeps its own
52
+ pairing and its own service, so neither displaces the other:
53
+
54
+ ```sh
55
+ moonlait pair <CODE> --server http://localhost:3100 --config ~/.moonlait/dev.json
56
+ moonlait service install --service dev --config ~/.moonlait/dev.json
57
+ ```
58
+
59
+ `--service dev` goes on `status` and `uninstall` too, and that bridge logs
60
+ to `~/.moonlait/bridge.dev.log`.
61
+
49
62
  To run it just for now instead, in a window you keep open:
50
63
 
51
64
  ```sh
package/dist/cli.js CHANGED
@@ -9549,22 +9549,22 @@ var error32 = () => {
9549
9549
  return `\uC798\uBABB\uB41C \uC635\uC158: ${joinValues(issue2.values, "\uB610\uB294 ")} \uC911 \uD558\uB098\uC5EC\uC57C \uD569\uB2C8\uB2E4`;
9550
9550
  case "too_big": {
9551
9551
  const adj = issue2.inclusive ? "\uC774\uD558" : "\uBBF8\uB9CC";
9552
- const suffix = adj === "\uBBF8\uB9CC" ? "\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4" : "\uC5EC\uC57C \uD569\uB2C8\uB2E4";
9552
+ const suffix2 = adj === "\uBBF8\uB9CC" ? "\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4" : "\uC5EC\uC57C \uD569\uB2C8\uB2E4";
9553
9553
  const sizing = getSizing(issue2.origin);
9554
9554
  const unit2 = sizing?.unit ?? "\uC694\uC18C";
9555
9555
  if (sizing)
9556
- return `${issue2.origin ?? "\uAC12"}\uC774 \uB108\uBB34 \uD07D\uB2C8\uB2E4: ${issue2.maximum.toString()}${unit2} ${adj}${suffix}`;
9557
- return `${issue2.origin ?? "\uAC12"}\uC774 \uB108\uBB34 \uD07D\uB2C8\uB2E4: ${issue2.maximum.toString()} ${adj}${suffix}`;
9556
+ return `${issue2.origin ?? "\uAC12"}\uC774 \uB108\uBB34 \uD07D\uB2C8\uB2E4: ${issue2.maximum.toString()}${unit2} ${adj}${suffix2}`;
9557
+ return `${issue2.origin ?? "\uAC12"}\uC774 \uB108\uBB34 \uD07D\uB2C8\uB2E4: ${issue2.maximum.toString()} ${adj}${suffix2}`;
9558
9558
  }
9559
9559
  case "too_small": {
9560
9560
  const adj = issue2.inclusive ? "\uC774\uC0C1" : "\uCD08\uACFC";
9561
- const suffix = adj === "\uC774\uC0C1" ? "\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4" : "\uC5EC\uC57C \uD569\uB2C8\uB2E4";
9561
+ const suffix2 = adj === "\uC774\uC0C1" ? "\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4" : "\uC5EC\uC57C \uD569\uB2C8\uB2E4";
9562
9562
  const sizing = getSizing(issue2.origin);
9563
9563
  const unit2 = sizing?.unit ?? "\uC694\uC18C";
9564
9564
  if (sizing) {
9565
- return `${issue2.origin ?? "\uAC12"}\uC774 \uB108\uBB34 \uC791\uC2B5\uB2C8\uB2E4: ${issue2.minimum.toString()}${unit2} ${adj}${suffix}`;
9565
+ return `${issue2.origin ?? "\uAC12"}\uC774 \uB108\uBB34 \uC791\uC2B5\uB2C8\uB2E4: ${issue2.minimum.toString()}${unit2} ${adj}${suffix2}`;
9566
9566
  }
9567
- return `${issue2.origin ?? "\uAC12"}\uC774 \uB108\uBB34 \uC791\uC2B5\uB2C8\uB2E4: ${issue2.minimum.toString()} ${adj}${suffix}`;
9567
+ return `${issue2.origin ?? "\uAC12"}\uC774 \uB108\uBB34 \uC791\uC2B5\uB2C8\uB2E4: ${issue2.minimum.toString()} ${adj}${suffix2}`;
9568
9568
  }
9569
9569
  case "invalid_format": {
9570
9570
  const _issue = issue2;
@@ -13472,9 +13472,9 @@ function codePointLengthVar(doc, ctx, accessor, inDoubt) {
13472
13472
  doc.write(`const ${v} = typeof ${accessor} === "string" && ${inDoubt} ? ${cpLen}(${accessor}) : ${accessor}.length;`);
13473
13473
  return v;
13474
13474
  }
13475
- function numericOperand(value, label) {
13475
+ function numericOperand(value, label2) {
13476
13476
  if (typeof value !== "number" || !Number.isFinite(value)) {
13477
- throw new ZodCompileUnsupportedError(`${label} bound of type ${typeof value}`);
13477
+ throw new ZodCompileUnsupportedError(`${label2} bound of type ${typeof value}`);
13478
13478
  }
13479
13479
  return `${value}`;
13480
13480
  }
@@ -13749,8 +13749,8 @@ function generateStringFormatCheck(doc, ctx, def, accessor, needsValue = true) {
13749
13749
  break;
13750
13750
  }
13751
13751
  case "ends_with": {
13752
- const suffix = def.suffix;
13753
- doc.write(`if (${accessor}.slice(-${suffix.length}) !== ${esc(suffix)}) return INVALID;`);
13752
+ const suffix2 = def.suffix;
13753
+ doc.write(`if (${accessor}.slice(-${suffix2.length}) !== ${esc(suffix2)}) return INVALID;`);
13754
13754
  break;
13755
13755
  }
13756
13756
  default: {
@@ -15439,12 +15439,12 @@ function _startsWith(prefix, params) {
15439
15439
  });
15440
15440
  }
15441
15441
  // @__NO_SIDE_EFFECTS__
15442
- function _endsWith(suffix, params) {
15442
+ function _endsWith(suffix2, params) {
15443
15443
  return new $ZodCheckEndsWith({
15444
15444
  check: "string_format",
15445
15445
  format: "ends_with",
15446
15446
  ...normalizeParams(params),
15447
- suffix
15447
+ suffix: suffix2
15448
15448
  });
15449
15449
  }
15450
15450
  // @__NO_SIDE_EFFECTS__
@@ -24242,28 +24242,32 @@ import { homedir as homedir2 } from "node:os";
24242
24242
  import path5 from "node:path";
24243
24243
  var LABEL = "com.moonlait.bridge";
24244
24244
  var TASK = "Moonlait bridge";
24245
- var logPath = () => path5.join(bridgeHome(), "bridge.log");
24246
- function plistPath() {
24247
- return path5.join(homedir2(), "Library", "LaunchAgents", `${LABEL}.plist`);
24248
- }
24249
- function unitPath() {
24250
- return path5.join(homedir2(), ".config", "systemd", "user", "moonlait.service");
24251
- }
24252
- var runnerPath = () => path5.join(bridgeHome(), "bridge-service.cmd");
24253
- var launcherPath = () => path5.join(bridgeHome(), "bridge-service.vbs");
24245
+ var suffix = (service) => service === void 0 ? "" : `.${service}`;
24246
+ var label = (service) => `${LABEL}${suffix(service)}`;
24247
+ var taskName = (service) => service === void 0 ? TASK : `${TASK} (${service})`;
24248
+ var unitName = (service) => service === void 0 ? "moonlait.service" : `moonlait-${service}.service`;
24249
+ var logPath = (service) => path5.join(bridgeHome(), `bridge${suffix(service)}.log`);
24250
+ function plistPath(service) {
24251
+ return path5.join(homedir2(), "Library", "LaunchAgents", `${label(service)}.plist`);
24252
+ }
24253
+ function unitPath(service) {
24254
+ return path5.join(homedir2(), ".config", "systemd", "user", unitName(service));
24255
+ }
24256
+ var runnerPath = (service) => path5.join(bridgeHome(), `bridge-service${suffix(service)}.cmd`);
24257
+ var launcherPath = (service) => path5.join(bridgeHome(), `bridge-service${suffix(service)}.vbs`);
24254
24258
  function runnerScript(paths) {
24255
24259
  const config2 = paths.config === void 0 ? "" : ` --config "${paths.config}"`;
24256
24260
  return [
24257
24261
  "@echo off",
24258
24262
  ":loop",
24259
- `"${paths.node}" "${paths.script}" start${config2} >> "${logPath()}" 2>&1`,
24263
+ `"${paths.node}" "${paths.script}" start${config2} >> "${logPath(paths.service)}" 2>&1`,
24260
24264
  "timeout /t 5 /nobreak > nul",
24261
24265
  "goto loop",
24262
24266
  ""
24263
24267
  ].join("\r\n");
24264
24268
  }
24265
- function launcherScript() {
24266
- return ['Set shell = CreateObject("WScript.Shell")', `shell.Run """${runnerPath()}""", 0, False`, ""].join("\r\n");
24269
+ function launcherScript(service) {
24270
+ return ['Set shell = CreateObject("WScript.Shell")', `shell.Run """${runnerPath(service)}""", 0, False`, ""].join("\r\n");
24267
24271
  }
24268
24272
  var escape = (value) => value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
24269
24273
  function plist(paths) {
@@ -24272,7 +24276,7 @@ function plist(paths) {
24272
24276
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
24273
24277
  <plist version="1.0">
24274
24278
  <dict>
24275
- <key>Label</key><string>${LABEL}</string>
24279
+ <key>Label</key><string>${label(paths.service)}</string>
24276
24280
  <key>ProgramArguments</key>
24277
24281
  <array>${args.map((arg) => `
24278
24282
  <string>${escape(arg)}</string>`).join("")}
@@ -24285,8 +24289,8 @@ function plist(paths) {
24285
24289
  <key>PATH</key><string>${escape(process.env.PATH ?? "/usr/bin:/bin")}</string>
24286
24290
  <key>HOME</key><string>${escape(homedir2())}</string>
24287
24291
  </dict>
24288
- <key>StandardOutPath</key><string>${escape(logPath())}</string>
24289
- <key>StandardErrorPath</key><string>${escape(logPath())}</string>
24292
+ <key>StandardOutPath</key><string>${escape(logPath(paths.service))}</string>
24293
+ <key>StandardErrorPath</key><string>${escape(logPath(paths.service))}</string>
24290
24294
  </dict>
24291
24295
  </plist>
24292
24296
  `;
@@ -24322,62 +24326,64 @@ function waitUntilUnloaded(target, tries = 20) {
24322
24326
  }
24323
24327
  function install(paths) {
24324
24328
  if (process.platform === "darwin") {
24325
- const file2 = plistPath();
24329
+ const file2 = plistPath(paths.service);
24326
24330
  mkdirSync2(path5.dirname(file2), { recursive: true });
24327
24331
  mkdirSync2(bridgeHome(), { recursive: true });
24328
24332
  writeFileSync2(file2, plist(paths));
24329
24333
  const domain2 = `gui/${process.getuid?.() ?? 501}`;
24334
+ const name = label(paths.service);
24330
24335
  try {
24331
- run("launchctl", ["bootout", `${domain2}/${LABEL}`]);
24336
+ run("launchctl", ["bootout", `${domain2}/${name}`]);
24332
24337
  } catch {
24333
24338
  }
24334
- waitUntilUnloaded(`${domain2}/${LABEL}`);
24339
+ waitUntilUnloaded(`${domain2}/${name}`);
24335
24340
  try {
24336
24341
  run("launchctl", ["bootstrap", domain2, file2]);
24337
24342
  } catch {
24338
- waitUntilUnloaded(`${domain2}/${LABEL}`);
24343
+ waitUntilUnloaded(`${domain2}/${name}`);
24339
24344
  try {
24340
24345
  run("launchctl", ["bootstrap", domain2, file2]);
24341
24346
  } catch {
24342
- run("launchctl", ["kickstart", "-k", `${domain2}/${LABEL}`]);
24347
+ run("launchctl", ["kickstart", "-k", `${domain2}/${name}`]);
24343
24348
  }
24344
24349
  }
24345
24350
  return file2;
24346
24351
  }
24347
24352
  if (process.platform === "linux") {
24348
- const file2 = unitPath();
24353
+ const file2 = unitPath(paths.service);
24349
24354
  mkdirSync2(path5.dirname(file2), { recursive: true });
24350
24355
  writeFileSync2(file2, unit(paths));
24351
24356
  run("systemctl", ["--user", "daemon-reload"]);
24352
- run("systemctl", ["--user", "enable", "--now", "moonlait.service"]);
24357
+ run("systemctl", ["--user", "enable", "--now", unitName(paths.service)]);
24353
24358
  return file2;
24354
24359
  }
24355
24360
  if (process.platform === "win32") {
24356
24361
  mkdirSync2(bridgeHome(), { recursive: true });
24357
- writeFileSync2(runnerPath(), runnerScript(paths));
24358
- writeFileSync2(launcherPath(), launcherScript());
24359
- run("schtasks", ["/Create", "/TN", TASK, "/TR", `wscript.exe "${launcherPath()}"`, "/SC", "ONLOGON", "/F"]);
24360
- run("schtasks", ["/Run", "/TN", TASK]);
24361
- return launcherPath();
24362
+ writeFileSync2(runnerPath(paths.service), runnerScript(paths));
24363
+ writeFileSync2(launcherPath(paths.service), launcherScript(paths.service));
24364
+ const task = taskName(paths.service);
24365
+ run("schtasks", ["/Create", "/TN", task, "/TR", `wscript.exe "${launcherPath(paths.service)}"`, "/SC", "ONLOGON", "/F"]);
24366
+ run("schtasks", ["/Run", "/TN", task]);
24367
+ return launcherPath(paths.service);
24362
24368
  }
24363
24369
  throw new Error(`Installing as a service is not supported on ${process.platform}. Run \`moonlait start\` in a terminal instead.`);
24364
24370
  }
24365
- function uninstall() {
24371
+ function uninstall(service) {
24366
24372
  if (process.platform === "darwin") {
24367
- const file2 = plistPath();
24373
+ const file2 = plistPath(service);
24368
24374
  if (!existsSync4(file2)) return null;
24369
24375
  try {
24370
- run("launchctl", ["bootout", `gui/${process.getuid?.() ?? 501}/${LABEL}`]);
24376
+ run("launchctl", ["bootout", `gui/${process.getuid?.() ?? 501}/${label(service)}`]);
24371
24377
  } catch {
24372
24378
  }
24373
24379
  rmSync(file2);
24374
24380
  return file2;
24375
24381
  }
24376
24382
  if (process.platform === "linux") {
24377
- const file2 = unitPath();
24383
+ const file2 = unitPath(service);
24378
24384
  if (!existsSync4(file2)) return null;
24379
24385
  try {
24380
- run("systemctl", ["--user", "disable", "--now", "moonlait.service"]);
24386
+ run("systemctl", ["--user", "disable", "--now", unitName(service)]);
24381
24387
  } catch {
24382
24388
  }
24383
24389
  rmSync(file2);
@@ -24385,24 +24391,24 @@ function uninstall() {
24385
24391
  return file2;
24386
24392
  }
24387
24393
  if (process.platform === "win32") {
24388
- if (!existsSync4(launcherPath())) return null;
24394
+ if (!existsSync4(launcherPath(service))) return null;
24389
24395
  try {
24390
- run("schtasks", ["/End", "/TN", TASK]);
24391
- run("schtasks", ["/Delete", "/TN", TASK, "/F"]);
24396
+ run("schtasks", ["/End", "/TN", taskName(service)]);
24397
+ run("schtasks", ["/Delete", "/TN", taskName(service), "/F"]);
24392
24398
  } catch {
24393
24399
  }
24394
- rmSync(launcherPath());
24395
- rmSync(runnerPath(), { force: true });
24396
- return launcherPath();
24400
+ rmSync(launcherPath(service));
24401
+ rmSync(runnerPath(service), { force: true });
24402
+ return launcherPath(service);
24397
24403
  }
24398
24404
  throw new Error(`Nothing to remove: the service is not installed on ${process.platform}.`);
24399
24405
  }
24400
- function status() {
24406
+ function status(service) {
24401
24407
  if (process.platform === "darwin") {
24402
- const file2 = plistPath();
24408
+ const file2 = plistPath(service);
24403
24409
  let running = false;
24404
24410
  try {
24405
- execFileSync2("launchctl", ["print", `gui/${process.getuid?.() ?? 501}/${LABEL}`], { stdio: "ignore" });
24411
+ execFileSync2("launchctl", ["print", `gui/${process.getuid?.() ?? 501}/${label(service)}`], { stdio: "ignore" });
24406
24412
  running = true;
24407
24413
  } catch {
24408
24414
  running = false;
@@ -24410,10 +24416,10 @@ function status() {
24410
24416
  return { installed: existsSync4(file2), running, file: file2 };
24411
24417
  }
24412
24418
  if (process.platform === "linux") {
24413
- const file2 = unitPath();
24419
+ const file2 = unitPath(service);
24414
24420
  let running = false;
24415
24421
  try {
24416
- execFileSync2("systemctl", ["--user", "is-active", "--quiet", "moonlait.service"], { stdio: "ignore" });
24422
+ execFileSync2("systemctl", ["--user", "is-active", "--quiet", unitName(service)], { stdio: "ignore" });
24417
24423
  running = true;
24418
24424
  } catch {
24419
24425
  running = false;
@@ -24421,10 +24427,10 @@ function status() {
24421
24427
  return { installed: existsSync4(file2), running, file: file2 };
24422
24428
  }
24423
24429
  if (process.platform === "win32") {
24424
- const file2 = launcherPath();
24430
+ const file2 = launcherPath(service);
24425
24431
  let running = false;
24426
24432
  try {
24427
- const output2 = execFileSync2("schtasks", ["/Query", "/TN", TASK, "/FO", "LIST"], { encoding: "utf8" });
24433
+ const output2 = execFileSync2("schtasks", ["/Query", "/TN", taskName(service), "/FO", "LIST"], { encoding: "utf8" });
24428
24434
  running = /\bRunning\b/i.test(output2);
24429
24435
  } catch {
24430
24436
  return { installed: false, running: false, file: file2 };
@@ -24536,21 +24542,25 @@ async function main() {
24536
24542
  }
24537
24543
  if (command === "service") {
24538
24544
  const action = argument ?? "status";
24545
+ const service = option("service");
24546
+ if (service !== void 0 && !/^[a-z0-9-]{1,20}$/.test(service)) {
24547
+ throw new Error("A service name is lowercase letters, numbers and dashes, e.g. --service dev");
24548
+ }
24539
24549
  if (action === "status") {
24540
- const state = status();
24550
+ const state = status(service);
24541
24551
  console.log(
24542
24552
  !state.installed ? `Not installed. Keep the bridge running with: ${RUN} service install` : state.running ? `Installed and running (${state.file}).
24543
- Log: ${logPath()}` : `Installed but not running (${state.file}).
24544
- Log: ${logPath()}`
24553
+ Log: ${logPath(service)}` : `Installed but not running (${state.file}).
24554
+ Log: ${logPath(service)}`
24545
24555
  );
24546
24556
  return;
24547
24557
  }
24548
24558
  if (action === "uninstall") {
24549
- const file3 = uninstall();
24559
+ const file3 = uninstall(service);
24550
24560
  console.log(file3 === null ? "The service was not installed." : `Removed ${file3}. The bridge stops at the next login, or now.`);
24551
24561
  return;
24552
24562
  }
24553
- if (action !== "install") throw new Error(`Usage: ${RUN} service [install|uninstall|status]`);
24563
+ if (action !== "install") throw new Error(`Usage: ${RUN} service [install|uninstall|status] [--service <name>] [--config <file>]`);
24554
24564
  if (import.meta.filename.endsWith(".ts")) {
24555
24565
  throw new Error("Install the published package first: npm install -g moonlait, then `moonlait service install`.");
24556
24566
  }
@@ -24558,14 +24568,23 @@ Log: ${logPath()}`
24558
24568
  throw new Error("This copy lives in npx's cache, which npm can clear.\nInstall it for good first: npm install -g moonlait, then `moonlait service install`.");
24559
24569
  }
24560
24570
  if (loadConfig(file2) === null) throw new Error(`Not paired yet. Run: ${RUN} pair <CODE> --server <url>`);
24571
+ if (service !== void 0 && option("config") === void 0) {
24572
+ throw new Error(
24573
+ `--service ${service} needs its own pairing, or it would be a second copy of the main bridge.
24574
+ ${RUN} pair <CODE> --server <url> --config ~/.moonlait/${service}.json
24575
+ ${RUN} service install --service ${service} --config ~/.moonlait/${service}.json`
24576
+ );
24577
+ }
24561
24578
  const installed2 = install({
24562
24579
  node: process.execPath,
24563
24580
  script: import.meta.filename,
24564
- ...option("config") !== void 0 ? { config: path6.resolve(option("config")) } : {}
24581
+ ...option("config") !== void 0 ? { config: path6.resolve(option("config")) } : {},
24582
+ ...service !== void 0 ? { service } : {}
24565
24583
  });
24584
+ const named = service === void 0 ? "" : ` --service ${service}`;
24566
24585
  console.log(`The bridge now runs in the background and starts at login (${installed2}).`);
24567
- console.log(`Log: ${logPath()}`);
24568
- console.log(`Stop it with: ${RUN} service uninstall`);
24586
+ console.log(`Log: ${logPath(service)}`);
24587
+ console.log(`Stop it with: ${RUN} service uninstall${named}`);
24569
24588
  return;
24570
24589
  }
24571
24590
  console.log(`Usage: ${RUN} pair <CODE> --server <url> | folders [add|remove <folder>\u2026] | start | service [install|uninstall|status] | agents`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "moonlait",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "Message the coding agents on your computer — Claude Code, Codex and Antigravity — from Moonlait on your phone.",
5
5
  "license": "MIT",
6
6
  "author": "Jorge Bermudez Roldan",