palmier 1.0.6 → 1.0.8
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 +3 -3
- package/dist/mcp-tools.js +2 -1
- package/dist/playwright-fill.d.ts +4 -2
- package/dist/playwright-fill.js +5 -2
- package/dist/rpc-handler.js +10 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -57,7 +57,7 @@ Palmier exposes an [MCP](https://modelcontextprotocol.io) server at `http://loca
|
|
|
57
57
|
| `notify` | Send a push notification to the user's device |
|
|
58
58
|
| `request-input` | Request input from the user (blocks until response) |
|
|
59
59
|
| `request-confirmation` | Request confirmation from the user (blocks until response) |
|
|
60
|
-
| `fill-password` | Fill a saved password or PIN into the active browser session, prompting the user if unknown (the secret is never revealed to the agent) |
|
|
60
|
+
| `fill-password` | Fill a saved password or PIN into the active browser session and submit the form, prompting the user if unknown (the secret is never revealed to the agent) |
|
|
61
61
|
| `device-geolocation` | Get GPS location of the user's mobile device |
|
|
62
62
|
| `read-contacts` | Read the contact list from the user's device |
|
|
63
63
|
| `create-contact` | Create a new contact on the user's device |
|
|
@@ -156,9 +156,9 @@ Revoking the linked device also clears the host's linked-device record; device c
|
|
|
156
156
|
|
|
157
157
|
### Saved Passwords
|
|
158
158
|
|
|
159
|
-
Palmier can store website passwords and PINs like a browser's password manager so agents can sign in to sites without ever seeing the credentials. When an agent driving a browser (via the `playwright-cli` skill) reaches a login or PIN field, it calls the `fill-password` tool with the page URL, the username, and the field's element ref. Palmier matches the saved secret by **origin
|
|
159
|
+
Palmier can store website passwords and PINs like a browser's password manager so agents can sign in to sites without ever seeing the credentials. When an agent driving a browser (via the `playwright-cli` skill) reaches a login or PIN field, it calls the `fill-password` tool with the page URL, the username, and the field's element ref. Palmier matches the saved secret by **origin**, fills it directly into the live browser session, and presses Enter to submit the form in the same step — so the plaintext secret sits on the page for as little time as possible and never enters the agent's context. If nothing is saved for that `(origin, username)`, Palmier prompts you in the app with a masked dialog. The dialog has a "Save for next time" checkbox (on by default): leave it checked to store the secret for reuse, or uncheck it to fill it just this once without saving. Either way it is filled into the page. The plaintext secret is never returned to the agent and is never written to task history.
|
|
160
160
|
|
|
161
|
-
Saved passwords and PINs are encrypted at rest with AES-256-GCM under a host-local key, both stored in `~/.config/palmier/` (`passwords.enc` and `password-key`). Manage them from the host:
|
|
161
|
+
Saved passwords and PINs are encrypted at rest with AES-256-GCM under a host-local key, both stored in `~/.config/palmier/` (`passwords.enc` and `password-key`). Manage them from the app via **Manage saved passwords** in the side panel (lists origin and username only, with per-entry delete), or from the host CLI:
|
|
162
162
|
|
|
163
163
|
```bash
|
|
164
164
|
# List saved passwords (origin and username only — never the password)
|
package/dist/mcp-tools.js
CHANGED
|
@@ -182,8 +182,9 @@ const requestConfirmationTool = {
|
|
|
182
182
|
const fillPasswordTool = {
|
|
183
183
|
name: "fill-password",
|
|
184
184
|
description: [
|
|
185
|
-
"Fill the user's saved password or PIN into a credential field in the active playwright-cli browser session.",
|
|
185
|
+
"Fill the user's saved password or PIN into a credential field and submit the form, in the active playwright-cli browser session.",
|
|
186
186
|
"Use this instead of typing a password or PIN yourself — the secret is never revealed to you.",
|
|
187
|
+
"After filling, it immediately presses Enter to submit, so the secret stays on the page for as little time as possible. Call this only once the field is the last thing left to fill before submitting.",
|
|
187
188
|
"Provide the page URL, the username/login identifier, and the playwright-cli ref of the field (and the session name if you opened a named session).",
|
|
188
189
|
"If a secret for this (site, username) is already saved it is filled directly; otherwise the user is prompted to enter it, it is saved, then filled.",
|
|
189
190
|
'Response: `{"ok": true}` on success, or `{"aborted": true}` if the user declines to provide it.',
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Fill `password` into the `ref` element of the agent's live playwright-cli
|
|
3
|
-
* browser session
|
|
4
|
-
* by session name, so this lands
|
|
3
|
+
* browser session and submit (Enter) in the same invocation. playwright-cli
|
|
4
|
+
* keeps a persistent server-side browser keyed by session name, so this lands
|
|
5
|
+
* on the same page the agent is driving. Filling and submitting in one call
|
|
6
|
+
* keeps the plaintext secret on the page for as short a window as possible.
|
|
5
7
|
*
|
|
6
8
|
* The password is passed as an argv element (no shell, so no history/injection),
|
|
7
9
|
* which leaves it briefly visible to other processes of the same user;
|
package/dist/playwright-fill.js
CHANGED
|
@@ -18,8 +18,10 @@ async function resolvePlaywrightCli() {
|
|
|
18
18
|
}
|
|
19
19
|
/**
|
|
20
20
|
* Fill `password` into the `ref` element of the agent's live playwright-cli
|
|
21
|
-
* browser session
|
|
22
|
-
* by session name, so this lands
|
|
21
|
+
* browser session and submit (Enter) in the same invocation. playwright-cli
|
|
22
|
+
* keeps a persistent server-side browser keyed by session name, so this lands
|
|
23
|
+
* on the same page the agent is driving. Filling and submitting in one call
|
|
24
|
+
* keeps the plaintext secret on the page for as short a window as possible.
|
|
23
25
|
*
|
|
24
26
|
* The password is passed as an argv element (no shell, so no history/injection),
|
|
25
27
|
* which leaves it briefly visible to other processes of the same user;
|
|
@@ -33,6 +35,7 @@ export async function fillPasswordInBrowser(ref, password, session) {
|
|
|
33
35
|
"fill",
|
|
34
36
|
ref,
|
|
35
37
|
password,
|
|
38
|
+
"--submit",
|
|
36
39
|
];
|
|
37
40
|
const { exitCode, output } = await spawnCommand(command, args, { cwd: process.cwd(), resolveOnFailure: true });
|
|
38
41
|
if (exitCode !== 0) {
|
package/dist/rpc-handler.js
CHANGED
|
@@ -10,6 +10,7 @@ import { getAgent, getPromptCommandLine, getNpmInstalledVersion } from "./agents
|
|
|
10
10
|
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
|
+
import { listPasswords, deletePassword } from "./password-store.js";
|
|
13
14
|
import { currentVersion, performUpdate, performAgentUpdate } from "./update-checker.js";
|
|
14
15
|
import { PLAYWRIGHT_CLI_PACKAGE, PLAYWRIGHT_CLI_LABEL } from "./playwright-cli.js";
|
|
15
16
|
import { saveConfig } from "./config.js";
|
|
@@ -696,6 +697,15 @@ export function createRpcHandler(config, nc) {
|
|
|
696
697
|
clearLinkedDevice();
|
|
697
698
|
return { ok: true };
|
|
698
699
|
}
|
|
700
|
+
case "passwords.list": {
|
|
701
|
+
return { passwords: listPasswords() };
|
|
702
|
+
}
|
|
703
|
+
case "passwords.delete": {
|
|
704
|
+
const params = request.params;
|
|
705
|
+
if (!params?.origin || !params?.username)
|
|
706
|
+
return { error: "origin and username are required" };
|
|
707
|
+
return { ok: deletePassword(params.origin, params.username) };
|
|
708
|
+
}
|
|
699
709
|
case "clients.revoke_self": {
|
|
700
710
|
const clientToken = request.clientToken ?? "";
|
|
701
711
|
if (!clientToken)
|