palmier 1.0.3 → 1.0.4

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 CHANGED
@@ -179,6 +179,7 @@ palmier passwords clear
179
179
  The wizard:
180
180
  - Detects installed agent CLIs and caches the result; agents previously installed by Palmier have their installed version re-probed so the recorded version stays in sync with manual upgrades
181
181
  - Offers to install missing supported agents from npm (one at a time, arrow-key menu). After each install the agent's version is stamped (becoming "Palmier-managed"), the wizard kicks off authentication, and waits for you to press Enter before offering the next install. On re-init, the agents list is saved after every install so an interrupted wizard is resumable.
182
+ - Offers to install the **Playwright CLI** for browser automation (see [Browser Automation](#browser-automation)). Skipped on re-init if it's already managed.
182
183
  - Asks for the HTTP port
183
184
  - Detects the default network interface (used for auto-LAN)
184
185
  - Shows a summary (including any existing scheduled tasks to recover) and asks for confirmation
@@ -200,10 +201,17 @@ Agents installed by the user outside the wizard (e.g., `npm install -g <pkg>` di
200
201
 
201
202
  Run `palmier agents` to manage agent CLIs after setup: it lists installed agents and offers an interactive picker to install or uninstall one. `palmier init` only prompts for an agent install when none are detected; once any agent is installed, init just lists them and continues with host registration.
202
203
 
204
+ ### Browser Automation
205
+
206
+ Some capabilities (like the [saved-password autofill](#saved-passwords)) drive a real browser through the [`playwright-cli`](https://www.npmjs.com/package/@playwright/cli) skill. `palmier init` offers to install and manage the Playwright CLI (`@playwright/cli`) for this. When you opt in, Palmier manages it **just like an agent CLI** — the version is stamped, re-probed live on each daemon start, and the PWA shows a "Browser Automation Update Available" dialog (same flow as agents) when a newer version is published. Its version is shown in the app's host drawer. The browser binaries Playwright needs are downloaded lazily on first use, not during init.
207
+
208
+ Unlike agents, the Playwright CLI has **no explicit uninstall** — it's not offered in any uninstall picker. It is removed only by a full `palmier uninstall`.
209
+
203
210
  ### Updates
204
211
 
205
212
  - **Palmier itself** — when a newer version of `palmier` is published to npm, the PWA shows a dismissible "Update Available" dialog. Clicking "Update Now" runs `npm update -g palmier` on the host and restarts the daemon. Clicking "Dismiss" suppresses the dialog for that exact version (per host, per device); a future release re-arms it.
206
213
  - **Palmier-managed agents** — same flow per agent: when npm publishes a newer version, the PWA shows an "Agent Update Available" dialog. Clicking "Update Now" runs `npm update -g <pkg>` on the host (no daemon restart needed). Dismissals are per host, per agent, per version.
214
+ - **Managed Playwright CLI** — same flow: a "Browser Automation Update Available" dialog runs `npm update -g @playwright/cli`. Dismissals are per host, per version.
207
215
 
208
216
  ### Re-detecting the LAN Network
209
217
 
@@ -226,7 +234,7 @@ The default network interface is detected once during `palmier init` and saved t
226
234
  | `palmier serve` | Run the persistent RPC handler (default command) |
227
235
  | `palmier restart` | Restart the palmier serve daemon |
228
236
  | `palmier run <task-id>` | Execute a specific task |
229
- | `palmier uninstall` | Stop daemon, remove all scheduled tasks, and uninstall Palmier-managed agent CLIs |
237
+ | `palmier uninstall` | Stop daemon, remove all scheduled tasks, and uninstall Palmier-managed agent CLIs and the managed Playwright CLI |
230
238
 
231
239
  ## Uninstalling
232
240
 
@@ -234,7 +242,7 @@ To fully remove Palmier from a machine:
234
242
 
235
243
  1. **Unpair your device** in the PWA (via the host menu).
236
244
 
237
- 2. **Stop the daemon, remove all scheduled tasks, and uninstall Palmier-managed agent CLIs:**
245
+ 2. **Stop the daemon, remove all scheduled tasks, and uninstall Palmier-managed agent CLIs and the managed Playwright CLI:**
238
246
 
239
247
  ```bash
240
248
  palmier uninstall
@@ -16,6 +16,7 @@ import { kiroAgent } from "./kiro.js";
16
16
  import { clineAgent } from "./cline.js";
17
17
  import { qoderAgent } from "./qoder.js";
18
18
  import { hermesAgent } from "./hermes.js";
19
+ import { grokAgent } from "./grok.js";
19
20
  export function getPromptCommandLine(agent, prompt) {
20
21
  return { args: [...agent.promptArgs, prompt] };
21
22
  }
@@ -70,6 +71,7 @@ const agentRegistry = {
70
71
  cline: clineAgent,
71
72
  qoder: qoderAgent,
72
73
  hermes: hermesAgent,
74
+ grok: grokAgent,
73
75
  };
74
76
  const TIER_ONE_ORDER = ["claude", "codex", "copilot"];
75
77
  export function listInstallableAgents() {
@@ -14,7 +14,7 @@ export const claudeAgent = {
14
14
  const prompt = followupPrompt ?? getAgentInstructions(task);
15
15
  const args = ["--permission-mode", yolo ? "bypassPermissions" : "acceptEdits", "-p"];
16
16
  if (!yolo) {
17
- args.push("--allowedTools", "Bash(curl)", "WebFetch");
17
+ args.push("--allowedTools", "WebFetch", "Skill(playwright-cli)", "Bash(curl)", "Bash(wget)", "Bash(playwright)", "Bash(playwright-cli)");
18
18
  const allPerms = [...(task.frontmatter.permissions ?? []), ...(extraPermissions ?? [])];
19
19
  for (const p of allPerms) {
20
20
  args.push(p.name);
@@ -0,0 +1,2 @@
1
+ import type { AgentTool } from "./agent.js";
2
+ export declare const grokAgent: AgentTool;
@@ -0,0 +1,21 @@
1
+ import { getAgentInstructions } from "./shared-prompt.js";
2
+ export const grokAgent = {
3
+ label: "Grok Build",
4
+ command: "grok",
5
+ promptArgs: ["-p"],
6
+ probeArg: "--version",
7
+ supportsYolo: true,
8
+ getTaskRunCommandLine(task, followupPrompt, extraPermissions) {
9
+ const yolo = extraPermissions === "yolo";
10
+ const prompt = followupPrompt ?? getAgentInstructions(task);
11
+ const args = [];
12
+ if (yolo) {
13
+ args.push("--always-approve");
14
+ }
15
+ if (followupPrompt) {
16
+ args.push("-c");
17
+ }
18
+ args.push("-p", prompt);
19
+ return { args };
20
+ },
21
+ };
@@ -25,4 +25,10 @@ export declare function pickAndUninstallAgent(current: DetectedAgent[]): Promise
25
25
  * Shared between the `palmier agents` interactive picker and the bulk
26
26
  * managed-agent removal in `palmier uninstall`. */
27
27
  export declare function uninstallAgent(agent: DetectedAgent): boolean;
28
+ /** `npm install -g <pkg>`. Shared by the agent installer and the Playwright CLI
29
+ * tool manager. Logs progress and a permissions hint on failure. */
30
+ export declare function npmInstallGlobal(npmPackage: string): boolean;
28
31
  export declare function uninstallManagedAgents(agents: DetectedAgent[]): void;
32
+ /** `npm uninstall -g <pkg>`. Shared by the agent uninstaller and the Playwright
33
+ * CLI tool manager (the latter only via `palmier uninstall`, never a picker). */
34
+ export declare function npmUninstallGlobal(npmPackage: string): boolean;
@@ -105,16 +105,18 @@ export async function pickAndUninstallAgent(current) {
105
105
  export function uninstallAgent(agent) {
106
106
  if (!agent.npmPackage)
107
107
  return false;
108
- if (!uninstallAgentPackage(agent.npmPackage)) {
108
+ if (!npmUninstallGlobal(agent.npmPackage)) {
109
109
  console.log(red(` Skipped ${agent.label}; uninstall it manually with npm uninstall -g ${agent.npmPackage}.`));
110
110
  return false;
111
111
  }
112
112
  console.log(green(` ${agent.label} uninstalled.`));
113
113
  return true;
114
114
  }
115
- function installAgentPackage(agent) {
116
- console.log(`\nInstalling ${cyan(agent.npmPackage)}...\n`);
117
- const cmd = `npm install -g ${agent.npmPackage}`;
115
+ /** `npm install -g <pkg>`. Shared by the agent installer and the Playwright CLI
116
+ * tool manager. Logs progress and a permissions hint on failure. */
117
+ export function npmInstallGlobal(npmPackage) {
118
+ console.log(`\nInstalling ${cyan(npmPackage)}...\n`);
119
+ const cmd = `npm install -g ${npmPackage}`;
118
120
  const result = spawnSync(cmd, { shell: true, stdio: "inherit" });
119
121
  if (result.error) {
120
122
  console.log(`\n${red(`Failed to run npm: ${result.error.message}`)}`);
@@ -134,6 +136,9 @@ function installAgentPackage(agent) {
134
136
  }
135
137
  return true;
136
138
  }
139
+ function installAgentPackage(agent) {
140
+ return npmInstallGlobal(agent.npmPackage);
141
+ }
137
142
  export function uninstallManagedAgents(agents) {
138
143
  const managed = agents.filter((a) => a.version && a.npmPackage);
139
144
  if (managed.length === 0) {
@@ -156,7 +161,9 @@ export function uninstallManagedAgents(agents) {
156
161
  console.log(`\n${yellow(`Uninstalled ${succeeded} of ${managed.length} agent CLIs (${failed} skipped).`)}`);
157
162
  }
158
163
  }
159
- function uninstallAgentPackage(npmPackage) {
164
+ /** `npm uninstall -g <pkg>`. Shared by the agent uninstaller and the Playwright
165
+ * CLI tool manager (the latter only via `palmier uninstall`, never a picker). */
166
+ export function npmUninstallGlobal(npmPackage) {
160
167
  console.log(`\nUninstalling ${cyan(npmPackage)}...\n`);
161
168
  const cmd = `npm uninstall -g ${npmPackage}`;
162
169
  const result = spawnSync(cmd, { shell: true, stdio: "inherit" });
@@ -5,6 +5,7 @@ import { homedir } from "os";
5
5
  import { loadConfig, saveConfig } from "../config.js";
6
6
  import { detectAgents } from "../agents/agent.js";
7
7
  import { colors, pickAndInstallAgent, printInstalledAgents } from "../agents/wizard.js";
8
+ import { installPlaywrightCli, getPlaywrightCliVersion, PLAYWRIGHT_CLI_LABEL } from "../playwright-cli.js";
8
9
  import { getPlatform } from "../platform/index.js";
9
10
  import { pairCommand } from "./pair.js";
10
11
  import { detectDefaultInterface, getInterfaceIpv4 } from "../network.js";
@@ -47,6 +48,22 @@ export async function initCommand() {
47
48
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
48
49
  const ask = (q) => new Promise((resolve) => rl.question(q, resolve));
49
50
  try {
51
+ // Browser automation is optional. Palmier manages the Playwright CLI like an
52
+ // agent CLI (install, version-stamp, update) once the user opts in; an
53
+ // already-managed install is re-probed rather than re-prompted.
54
+ let playwrightCliVersion = previousConfig?.playwrightCliVersion;
55
+ if (playwrightCliVersion) {
56
+ playwrightCliVersion = getPlaywrightCliVersion() ?? playwrightCliVersion;
57
+ }
58
+ else {
59
+ const answer = (await ask(`\nInstall ${PLAYWRIGHT_CLI_LABEL} for browser automation? Lets agents control a browser — e.g. autofill saved passwords. (Y/n): `)).trim().toLowerCase();
60
+ if (answer !== "n" && answer !== "no") {
61
+ if (installPlaywrightCli()) {
62
+ playwrightCliVersion = getPlaywrightCliVersion() ?? undefined;
63
+ console.log(green(` ${PLAYWRIGHT_CLI_LABEL} installed.`));
64
+ }
65
+ }
66
+ }
50
67
  let httpPort = 7256;
51
68
  const portAnswer = await ask(`HTTP port (default ${httpPort}): `);
52
69
  const parsed = parseInt(portAnswer.trim(), 10);
@@ -72,6 +89,9 @@ export async function initCommand() {
72
89
  console.log(` ${dim("Remote (web):")} ${cyan("https://app.palmier.me")}`);
73
90
  console.log(` Pair a browser on any device. Traffic always goes through the relay.\n`);
74
91
  console.log(` ${dim("Agents:")} ${agents.map((a) => a.version ? `${a.label} v${a.version}` : a.label).join(", ")}\n`);
92
+ if (playwrightCliVersion) {
93
+ console.log(` ${dim("Browser:")} ${PLAYWRIGHT_CLI_LABEL} v${playwrightCliVersion}\n`);
94
+ }
75
95
  const existingTasks = listTasks(projectRoot);
76
96
  if (existingTasks.length > 0) {
77
97
  console.log(` ${dim("Recover tasks:")} ${existingTasks.length} existing task(s) found:`);
@@ -114,6 +134,7 @@ export async function initCommand() {
114
134
  natsJwt: registerResponse.natsJwt,
115
135
  natsNkeySeed: registerResponse.natsNkeySeed,
116
136
  agents,
137
+ ...(playwrightCliVersion ? { playwrightCliVersion } : {}),
117
138
  httpPort,
118
139
  defaultInterface,
119
140
  };
@@ -9,6 +9,7 @@ import { getTaskDir, readTaskStatus, writeTaskStatus, parseTaskFile, appendRunMe
9
9
  import { publishHostEvent } from "../events.js";
10
10
  import { getPlatform } from "../platform/index.js";
11
11
  import { detectAgents } from "../agents/agent.js";
12
+ import { getPlaywrightCliVersion } from "../playwright-cli.js";
12
13
  import { saveConfig } from "../config.js";
13
14
  import { CONFIG_DIR } from "../config.js";
14
15
  import { StringCodec } from "nats";
@@ -102,6 +103,11 @@ export async function serveCommand() {
102
103
  console.log(`Starting Palmier daemon v${currentVersion}...`);
103
104
  const agents = await detectAgents(config.agents);
104
105
  config.agents = agents;
106
+ // Keep the managed Playwright CLI version in sync with manual upgrades, same
107
+ // as agents. Only touched when Palmier already manages it.
108
+ if (config.playwrightCliVersion) {
109
+ config.playwrightCliVersion = getPlaywrightCliVersion() ?? config.playwrightCliVersion;
110
+ }
105
111
  saveConfig(config);
106
112
  console.log(`Detected agents: ${agents.map((a) => a.key).join(", ") || "none"}`);
107
113
  let nc;
@@ -1,6 +1,7 @@
1
1
  import { getPlatform } from "../platform/index.js";
2
2
  import { loadConfig } from "../config.js";
3
3
  import { uninstallManagedAgents } from "../agents/wizard.js";
4
+ import { uninstallPlaywrightCli, PLAYWRIGHT_CLI_LABEL } from "../playwright-cli.js";
4
5
  export async function uninstallCommand() {
5
6
  console.log("Stopping daemon and removing scheduled tasks...");
6
7
  const platform = getPlatform();
@@ -14,6 +15,10 @@ export async function uninstallCommand() {
14
15
  if (config?.agents) {
15
16
  uninstallManagedAgents(config.agents);
16
17
  }
18
+ if (config?.playwrightCliVersion) {
19
+ console.log(`\nUninstalling ${PLAYWRIGHT_CLI_LABEL}...`);
20
+ uninstallPlaywrightCli();
21
+ }
17
22
  console.log("\nUninstall finished.");
18
23
  console.log("To remove the palmier package itself: npm uninstall -g palmier");
19
24
  console.log("To also remove configuration and task data, see https://github.com/caihongxu/palmier#uninstalling");
@@ -0,0 +1,10 @@
1
+ /** Palmier-managed browser-automation tool. Managed like an agent CLI (install,
2
+ * version-stamp, re-probe, PWA update prompt) but never offered for explicit
3
+ * uninstall — it's only removed by `palmier uninstall`. */
4
+ export declare const PLAYWRIGHT_CLI_PACKAGE = "@playwright/cli";
5
+ export declare const PLAYWRIGHT_CLI_LABEL = "Playwright CLI";
6
+ /** Installed global version, or null when not installed. Doubles as the
7
+ * "is it installed" check (mirrors how agents resolve their version). */
8
+ export declare function getPlaywrightCliVersion(): string | null;
9
+ export declare function installPlaywrightCli(): boolean;
10
+ export declare function uninstallPlaywrightCli(): boolean;
@@ -0,0 +1,18 @@
1
+ import { getNpmInstalledVersion } from "./agents/agent.js";
2
+ import { npmInstallGlobal, npmUninstallGlobal } from "./agents/wizard.js";
3
+ /** Palmier-managed browser-automation tool. Managed like an agent CLI (install,
4
+ * version-stamp, re-probe, PWA update prompt) but never offered for explicit
5
+ * uninstall — it's only removed by `palmier uninstall`. */
6
+ export const PLAYWRIGHT_CLI_PACKAGE = "@playwright/cli";
7
+ export const PLAYWRIGHT_CLI_LABEL = "Playwright CLI";
8
+ /** Installed global version, or null when not installed. Doubles as the
9
+ * "is it installed" check (mirrors how agents resolve their version). */
10
+ export function getPlaywrightCliVersion() {
11
+ return getNpmInstalledVersion(PLAYWRIGHT_CLI_PACKAGE);
12
+ }
13
+ export function installPlaywrightCli() {
14
+ return npmInstallGlobal(PLAYWRIGHT_CLI_PACKAGE);
15
+ }
16
+ export function uninstallPlaywrightCli() {
17
+ return npmUninstallGlobal(PLAYWRIGHT_CLI_PACKAGE);
18
+ }
@@ -11,6 +11,7 @@ import { validateClient, revokeClient } from "./client-store.js";
11
11
  import { publishHostEvent } from "./events.js";
12
12
  import { getLinkedDevice, setLinkedDevice, clearLinkedDevice, clearLinkedDeviceIfMatches } from "./linked-device.js";
13
13
  import { currentVersion, performUpdate, performAgentUpdate } from "./update-checker.js";
14
+ import { PLAYWRIGHT_CLI_PACKAGE, PLAYWRIGHT_CLI_LABEL } from "./playwright-cli.js";
14
15
  import { saveConfig } from "./config.js";
15
16
  import { parseReportFiles, parseTaskOutcome, stripPalmierMarkers } from "./commands/run.js";
16
17
  import { clearTaskQueue } from "./event-queues.js";
@@ -185,6 +186,9 @@ export function createRpcHandler(config, nc) {
185
186
  linked_client_token: getLinkedDevice()?.clientToken ?? null,
186
187
  pending_prompts: listPending(),
187
188
  lan_url: buildLanUrl(config.httpPort ?? 7256, config.defaultInterface),
189
+ playwright_cli: config.playwrightCliVersion
190
+ ? { label: PLAYWRIGHT_CLI_LABEL, npmPackage: PLAYWRIGHT_CLI_PACKAGE, version: config.playwrightCliVersion }
191
+ : null,
188
192
  };
189
193
  }
190
194
  case "task.list": {
@@ -663,6 +667,18 @@ export function createRpcHandler(config, nc) {
663
667
  saveConfig(config);
664
668
  return { ok: true, version: newVersion ?? entry.version };
665
669
  }
670
+ case "host.updatePlaywrightCli": {
671
+ if (!config.playwrightCliVersion)
672
+ return { error: "Playwright CLI is not managed by Palmier" };
673
+ const error = await performAgentUpdate(PLAYWRIGHT_CLI_PACKAGE);
674
+ if (error)
675
+ return { error };
676
+ const newVersion = getNpmInstalledVersion(PLAYWRIGHT_CLI_PACKAGE);
677
+ if (newVersion)
678
+ config.playwrightCliVersion = newVersion;
679
+ saveConfig(config);
680
+ return { ok: true, version: newVersion ?? config.playwrightCliVersion };
681
+ }
666
682
  case "device.link": {
667
683
  const params = request.params;
668
684
  if (!params.fcmToken)
package/dist/types.d.ts CHANGED
@@ -14,6 +14,9 @@ export interface HostConfig {
14
14
  /** Runtime marker for "managed by Palmier" — present iff Palmier installed/manages this agent. */
15
15
  version?: string;
16
16
  }>;
17
+ /** Installed version of the Palmier-managed Playwright CLI (`@playwright/cli`).
18
+ * Present iff Palmier manages it; mirrors the agents' `version` marker. */
19
+ playwrightCliVersion?: string;
17
20
  httpPort?: number;
18
21
  /** OS network interface name of the IPv4 default route, captured on the
19
22
  * most recent `palmier pair`. Used to resolve the host's LAN URL live for
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "palmier",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "Palmier host CLI - provisions, executes tasks, and serves NATS RPC",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Hongxu Cai",