@join-pantheon/cli 0.26.1 → 0.26.2

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/doctor.js CHANGED
@@ -16,8 +16,8 @@ import { workerProc, menubarProc, notifierProc } from "./machine.js";
16
16
  import { chooseAgent, describeChoice } from "./agents.js";
17
17
  import { onPathNamed } from "./which.js";
18
18
  import { VERSION } from "./version.js";
19
- import { serviceInstalled } from "./service.js";
20
- import { hostEnv } from "./host-env.js";
19
+ import { serviceInstalled, servicesUnavailable } from "./service.js";
20
+ import { hostEnv, platformName } from "./host-env.js";
21
21
  const HOSTED_RELAY = "relay.joinpantheon.network";
22
22
  const sh = (cmd, cwd) => {
23
23
  try {
@@ -56,7 +56,7 @@ export async function doctor(projectDir) {
56
56
  : add("fail", "node", `v${process.versions.node} is too old`, "pantheon needs Node 22 or newer (the relay uses node:sqlite) — install it and re-run", `v${process.versions.node}, too old`);
57
57
  const host = hostEnv();
58
58
  if (host.ephemeral) {
59
- add("warn", "machine", `${host.platform} in ${host.kind === "container" ? "a container" : "a cloud workspace"} — ${host.evidence.join("; ")}`, `this is not the computer you work on, which is why it reports ${host.platform} to someone who may be sitting at a Mac. The team and your account are fine here, but the menu bar, desktop alerts and the worker belong on your own machine — run the setup from a terminal there.`, `${host.platform} in ${host.kind === "container" ? "a container" : "a cloud workspace"}`);
59
+ add("warn", "machine", `${host.platform} in ${host.kind === "container" ? "a container" : "a cloud workspace"} — ${host.evidence.join("; ")}`, `this is not the computer you work on, which is why it reports ${platformName(host.platform)} to someone who may be sitting at a Mac. The team and your account are fine here, but the menu bar, desktop alerts and the worker belong on your own machine — run the setup from a terminal there.`, `${host.platform} in ${host.kind === "container" ? "a container" : "a cloud workspace"}`);
60
60
  }
61
61
  else {
62
62
  add("pass", "machine", `${host.platform}${host.desktop ? " — menu bar and desktop alerts can run here" : " — no menu bar or desktop alerts (macOS only); use phone or chat delivery"}`, undefined, `${host.platform}${host.desktop ? ", desktop" : ""}`);
@@ -255,7 +255,10 @@ export async function doctor(projectDir) {
255
255
  add("pass", "wake rights", `${who} — worker is running`, undefined, `${wakers.length} may wake; worker running`);
256
256
  }
257
257
  else {
258
- add("warn", "wake rights", `${who}, but no worker is running here, so nothing can be woken`, "start one with `pantheon service install worker --project <a git repo>`; until then a peer's act waits for you to type", `${wakers.length} may wake; worker not running`);
258
+ const noSvc = servicesUnavailable(host.platform);
259
+ add("warn", "wake rights", `${who}, but no worker is running here, so nothing can be woken`, noSvc
260
+ ? "Pantheon does not run in the background on Windows yet, so a peer's act waits until your agent is open"
261
+ : "start one with `pantheon service install worker --project <a git repo>`; until then a peer's act waits for you to type", `${wakers.length} may wake; worker not running`);
259
262
  }
260
263
  }
261
264
  if (host.desktop) {
package/dist/host-env.js CHANGED
@@ -40,9 +40,10 @@ export function hostEnv(env = process.env, plat = process.platform, exists = exi
40
40
  desktop: false,
41
41
  };
42
42
  }
43
+ export const platformName = (p) => p === "win32" ? "Windows" : p === "darwin" ? "macOS" : p === "linux" ? "Linux" : p;
43
44
  export function ephemeralWarning(host) {
44
45
  return `this looks like ${host.kind === "container" ? "a container" : "a cloud workspace"}, not the computer you work on `
45
- + `(${host.evidence.join("; ")}). That is why this machine reports ${host.platform}: your editor's agent is running `
46
+ + `(${host.evidence.join("; ")}). That is why this machine reports ${platformName(host.platform)}: your editor's agent is running `
46
47
  + `somewhere else, so the menu bar and desktop alerts cannot be installed, and anything installed here disappears with `
47
48
  + `the session. Your account and team are fine — run the same setup from a terminal on your own computer to finish it.`;
48
49
  }
@@ -50,8 +51,8 @@ export function desktopUnavailable(host, what) {
50
51
  if (host.desktop)
51
52
  return null;
52
53
  if (host.ephemeral) {
53
- return `not available — ${what} ${what === "desktop alerts" ? "need" : "needs"} your own computer, and this is ${host.kind === "container" ? "a container" : "a cloud workspace"} reporting ${host.platform}`;
54
+ return `not available — ${what} ${what === "desktop alerts" ? "need" : "needs"} your own computer, and this is ${host.kind === "container" ? "a container" : "a cloud workspace"} reporting ${platformName(host.platform)}`;
54
55
  }
55
- return `not available — ${what} ${host.platform === "darwin" ? "could not be built here" : `${what === "desktop alerts" ? "are" : "is"} macOS-only, and this machine is ${host.platform}`}`;
56
+ return `not available — ${what} ${host.platform === "darwin" ? "could not be built here" : `${what === "desktop alerts" ? "are" : "is"} macOS-only, and this machine is ${platformName(host.platform)}`}`;
56
57
  }
57
58
  //# sourceMappingURL=host-env.js.map
@@ -9,7 +9,7 @@ import { newKeypair } from "./identity.js";
9
9
  import { installForUser } from "./install.js";
10
10
  import { writeIntent, installHooks } from "./notify.js";
11
11
  import { detectAvailable, agentById } from "./agents.js";
12
- import { installService } from "./service.js";
12
+ import { installService, servicesUnavailable } from "./service.js";
13
13
  import { ensureNativeNotifier } from "./notifier.js";
14
14
  import { ensureTrayBinary, writeTrayCommands } from "./tray.js";
15
15
  import { desktopUnavailable, ephemeralWarning, hostEnv } from "./host-env.js";
@@ -30,6 +30,7 @@ export function wireUp(opts, deps = {}) {
30
30
  const ensureNotifier = deps.ensureNotifier ?? ensureNativeNotifier;
31
31
  const ensureTray = deps.ensureTray ?? ensureTrayBinary;
32
32
  const host = deps.host ?? hostEnv();
33
+ const noServices = servicesUnavailable(host.platform);
33
34
  const tools = installForUser().map((t) => ({ tool: t.tool, status: t.status }));
34
35
  const granted = [];
35
36
  const warnings = [];
@@ -92,6 +93,9 @@ export function wireUp(opts, deps = {}) {
92
93
  if (how === "off") {
93
94
  tools.push({ tool: "worker", status: "off (--no-worker) — this machine cannot answer the team while you are away" });
94
95
  }
96
+ else if (opts.unattended && noServices) {
97
+ tools.push({ tool: "worker", status: noServices });
98
+ }
95
99
  else if (opts.unattended) {
96
100
  const project = opts.unattended;
97
101
  const isRepo = sh(`git -C ${JSON.stringify(project)} rev-parse --is-inside-work-tree 2>/dev/null`) === "true";
package/dist/service.js CHANGED
@@ -13,6 +13,12 @@ const SERVICE_BASE_PATH = [
13
13
  export function servicePath(envPath = process.env.PATH ?? "") {
14
14
  return [...new Set([...envPath.split(":"), ...SERVICE_BASE_PATH].filter(Boolean))].join(":");
15
15
  }
16
+ export function servicesUnavailable(plat = platform()) {
17
+ if (plat !== "win32")
18
+ return null;
19
+ return "not available — Pantheon does not run in the background on Windows yet. "
20
+ + "Your agent still answers peers whenever it is open; nothing runs here while you are away.";
21
+ }
16
22
  export function plistPath(kind = "worker") {
17
23
  return join(homedir(), "Library", "LaunchAgents", `${LABEL(kind)}.plist`);
18
24
  }
@@ -87,6 +93,9 @@ WantedBy=default.target
87
93
  `;
88
94
  }
89
95
  export function installService(kind, cwd, args) {
96
+ const noServices = servicesUnavailable();
97
+ if (noServices)
98
+ throw new Error(noServices.replace(/^not available — /, ""));
90
99
  const out = [];
91
100
  const abs = resolve(cwd);
92
101
  const logDir = join(abs, ".pantheon");
@@ -134,6 +143,14 @@ export function installService(kind, cwd, args) {
134
143
  }
135
144
  export function uninstallService(kind) {
136
145
  const out = [];
146
+ if (platform() === "win32") {
147
+ const stray = unitPath(kind);
148
+ if (existsSync(stray)) {
149
+ unlinkSync(stray);
150
+ return [` removed ${stray}`];
151
+ }
152
+ return [` no ${kind} service installed`];
153
+ }
137
154
  if (platform() === "darwin") {
138
155
  const p = plistPath(kind);
139
156
  if (!existsSync(p))
@@ -188,6 +205,8 @@ export function restartService(kind, exec = (c, a) => execFileSync(c, a, { stdio
188
205
  }
189
206
  export function serviceInstalled(kind) {
190
207
  try {
208
+ if (platform() === "win32")
209
+ return false;
191
210
  return existsSync(platform() === "darwin" ? plistPath(kind) : unitPath(kind));
192
211
  }
193
212
  catch {
package/dist/which.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { execFileSync } from "node:child_process";
2
2
  import { accessSync, constants, existsSync, statSync } from "node:fs";
3
- import { win32 } from "node:path";
3
+ import { posix, win32 } from "node:path";
4
4
  import { platform } from "node:os";
5
5
  export const DEFAULT_PATHEXT = ".COM;.EXE;.BAT;.CMD;.VBS;.JS;.PS1";
6
6
  const isWindows = (os = platform()) => os === "win32";
@@ -43,6 +43,23 @@ export function whichWindows(name, env = process.env, exists = runnable) {
43
43
  export function which(name, os = platform(), env = process.env) {
44
44
  if (isWindows(os))
45
45
  return whichWindows(name, env);
46
+ return loginShellWhich(name) ?? posixOnPath(name, env);
47
+ }
48
+ function posixOnPath(name, env) {
49
+ if (!name)
50
+ return null;
51
+ if (name.includes("/"))
52
+ return runnable(name) ? name : null;
53
+ for (const dir of (env.PATH ?? "").split(":")) {
54
+ if (!dir)
55
+ continue;
56
+ const full = posix.join(dir, name);
57
+ if (runnable(full))
58
+ return full;
59
+ }
60
+ return null;
61
+ }
62
+ function loginShellWhich(name) {
46
63
  try {
47
64
  const out = execFileSync("sh", ["-lc", `command -v ${name}`], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
48
65
  if (!out)
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@join-pantheon/cli",
3
- "version": "0.26.1",
4
- "description": "Let your coding agent collaborate directly with your teammates' agents \u2014 ask, agree an interface, and deliver, without a human relaying messages.",
3
+ "version": "0.26.2",
4
+ "description": "Let your coding agent collaborate directly with your teammates' agents — ask, agree an interface, and deliver, without a human relaying messages.",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "pantheon": "bin/pantheon.js"