palmier 0.3.2 → 0.3.3
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 +11 -15
- package/dist/commands/lan.js +1 -1
- package/dist/commands/pair.d.ts +2 -0
- package/dist/commands/pair.js +8 -1
- package/dist/platform/windows.js +3 -2
- package/dist/update-checker.d.ts +2 -0
- package/dist/update-checker.js +7 -2
- package/package.json +1 -1
- package/src/commands/lan.ts +1 -1
- package/src/commands/pair.ts +11 -1
- package/src/platform/windows.ts +3 -2
- package/src/update-checker.ts +7 -2
- package/dist/pairing.d.ts +0 -3
- package/dist/pairing.js +0 -9
- package/src/pairing.ts +0 -10
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
**Website:** [palmier.me](https://www.palmier.me) | **App:** [app.palmier.me](https://app.palmier.me)
|
|
8
8
|
|
|
9
|
-
A Node.js CLI that runs on your machine as a persistent daemon. It
|
|
9
|
+
A Node.js CLI that runs on your machine as a persistent daemon. It lets you create, schedule, and run AI agent tasks from your phone or browser, communicating via a cloud relay (NATS) and/or direct HTTP.
|
|
10
10
|
|
|
11
11
|
> **Important:** By using Palmier, you agree to the [Terms of Service](https://www.palmier.me/terms) and [Privacy Policy](https://www.palmier.me/privacy). See the [Disclaimer](#disclaimer) section below.
|
|
12
12
|
|
|
@@ -16,10 +16,10 @@ The host supports two independent connection modes, enabled during `palmier init
|
|
|
16
16
|
|
|
17
17
|
| Mode | Transport | PWA URL | Features |
|
|
18
18
|
|------|-----------|---------|----------|
|
|
19
|
-
| **Server** |
|
|
19
|
+
| **Server** | Cloud relay (NATS) | `https://app.palmier.me` | Push notifications, remote access |
|
|
20
20
|
| **LAN** | HTTP (direct, on-demand) | `http://<host-ip>:7400` | Low-latency, no external server needed |
|
|
21
21
|
|
|
22
|
-
**Server mode** relays communication through the Palmier server via NATS. All features including push notifications are available. The PWA is served over HTTPS.
|
|
22
|
+
**Server mode** relays communication through the Palmier cloud server (via [NATS](https://nats.io), a lightweight messaging system). All features including push notifications are available. The PWA is served over HTTPS.
|
|
23
23
|
|
|
24
24
|
**LAN mode** is started on-demand via `palmier lan`. It runs a local HTTP server that reverse-proxies PWA assets from `app.palmier.me` and serves API endpoints locally. The browser accesses everything at `http://<host-ip>:<port>` (same-origin). Push notifications are not available in LAN mode.
|
|
25
25
|
|
|
@@ -35,6 +35,8 @@ The host supports two independent connection modes, enabled during `palmier init
|
|
|
35
35
|
npm install -g palmier
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
+
All `palmier` commands should be run from a dedicated Palmier root directory (e.g., `~/palmier`). This is where tasks, configuration, and execution data are stored.
|
|
39
|
+
|
|
38
40
|
## CLI Commands
|
|
39
41
|
|
|
40
42
|
| Command | Description |
|
|
@@ -57,7 +59,7 @@ npm install -g palmier
|
|
|
57
59
|
### Quick Start
|
|
58
60
|
|
|
59
61
|
1. Install the host: `npm install -g palmier`
|
|
60
|
-
2. Run `palmier init` in your
|
|
62
|
+
2. Run `palmier init` in your Palmier root directory (e.g., `~/palmier`).
|
|
61
63
|
3. The wizard detects installed agents, registers with the Palmier server, installs a background daemon, and generates a pairing code.
|
|
62
64
|
4. Enter the pairing code in the Palmier PWA to connect your device.
|
|
63
65
|
|
|
@@ -153,7 +155,6 @@ src/
|
|
|
153
155
|
spawn-command.ts # Shared helper for spawning CLI tools
|
|
154
156
|
task.ts # Task file management
|
|
155
157
|
types.ts # Shared type definitions
|
|
156
|
-
pairing.ts # OTP code generation and expiry constant
|
|
157
158
|
lan-lock.ts # LAN lockfile path and port reader
|
|
158
159
|
events.ts # Event broadcasting (NATS pub/sub or HTTP SSE)
|
|
159
160
|
agents/
|
|
@@ -210,11 +211,11 @@ Requires a provisioned host (`palmier init`) with server mode enabled.
|
|
|
210
211
|
|---|---|---|
|
|
211
212
|
| `send-push-notification` | `title`, `body` (required) | Send a push notification to all paired devices |
|
|
212
213
|
|
|
213
|
-
##
|
|
214
|
+
## Uninstalling
|
|
214
215
|
|
|
215
|
-
To fully remove
|
|
216
|
+
To fully remove Palmier from a machine:
|
|
216
217
|
|
|
217
|
-
1. **Unpair
|
|
218
|
+
1. **Unpair your device** in the PWA (via the host menu).
|
|
218
219
|
|
|
219
220
|
2. **Stop and remove the daemon:**
|
|
220
221
|
|
|
@@ -248,16 +249,11 @@ To fully remove a host from a machine:
|
|
|
248
249
|
schtasks /delete /tn "PalmierTask-*" /f 2>$null
|
|
249
250
|
```
|
|
250
251
|
|
|
251
|
-
4. **Remove
|
|
252
|
+
4. **Remove configuration and task data:**
|
|
252
253
|
|
|
253
254
|
```bash
|
|
254
255
|
rm -rf ~/.config/palmier
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
5. **Remove the tasks directory** from your project root:
|
|
258
|
-
|
|
259
|
-
```bash
|
|
260
|
-
rm -rf tasks/
|
|
256
|
+
rm -rf tasks/ # from your Palmier root directory
|
|
261
257
|
```
|
|
262
258
|
|
|
263
259
|
## Disclaimer
|
package/dist/commands/lan.js
CHANGED
|
@@ -2,7 +2,7 @@ import * as fs from "fs";
|
|
|
2
2
|
import { loadConfig, CONFIG_DIR } from "../config.js";
|
|
3
3
|
import { createRpcHandler } from "../rpc-handler.js";
|
|
4
4
|
import { startHttpTransport, detectLanIp } from "../transports/http-transport.js";
|
|
5
|
-
import { generatePairingCode } from "
|
|
5
|
+
import { generatePairingCode } from "./pair.js";
|
|
6
6
|
import { LAN_LOCKFILE } from "../lan-lock.js";
|
|
7
7
|
const bold = (s) => `\x1b[1m${s}\x1b[0m`;
|
|
8
8
|
const cyan = (s) => `\x1b[36m${s}\x1b[0m`;
|
package/dist/commands/pair.d.ts
CHANGED
package/dist/commands/pair.js
CHANGED
|
@@ -3,8 +3,15 @@ import { StringCodec } from "nats";
|
|
|
3
3
|
import { loadConfig } from "../config.js";
|
|
4
4
|
import { connectNats } from "../nats-client.js";
|
|
5
5
|
import { addSession } from "../session-store.js";
|
|
6
|
-
import { generatePairingCode, PAIRING_EXPIRY_MS } from "../pairing.js";
|
|
7
6
|
import { getLanPort } from "../lan-lock.js";
|
|
7
|
+
const CODE_CHARS = "ABCDEFGHJKMNPQRSTUVWXYZ23456789"; // no O/0/I/1/L
|
|
8
|
+
const CODE_LENGTH = 6;
|
|
9
|
+
export const PAIRING_EXPIRY_MS = 5 * 60 * 1000; // 5 minutes
|
|
10
|
+
export function generatePairingCode() {
|
|
11
|
+
const bytes = new Uint8Array(CODE_LENGTH);
|
|
12
|
+
crypto.getRandomValues(bytes);
|
|
13
|
+
return Array.from(bytes, (b) => CODE_CHARS[b % CODE_CHARS.length]).join("");
|
|
14
|
+
}
|
|
8
15
|
function buildPairResponse(config, label) {
|
|
9
16
|
const session = addSession(label);
|
|
10
17
|
return {
|
package/dist/platform/windows.js
CHANGED
|
@@ -63,8 +63,9 @@ function schtasksTaskName(taskId) {
|
|
|
63
63
|
export class WindowsPlatform {
|
|
64
64
|
installDaemon(config) {
|
|
65
65
|
const script = process.argv[1] || "palmier";
|
|
66
|
-
// Write a VBS launcher that starts the daemon with no visible console window
|
|
67
|
-
|
|
66
|
+
// Write a VBS launcher that starts the daemon with no visible console window.
|
|
67
|
+
// VBS doesn't use backslash escaping — only quotes need doubling ("").
|
|
68
|
+
const vbs = `CreateObject("WScript.Shell").Run """${process.execPath}"" ""${script}"" serve", 0, False`;
|
|
68
69
|
fs.writeFileSync(DAEMON_VBS_FILE, vbs, "utf-8");
|
|
69
70
|
const regValue = `"${process.env.SYSTEMROOT || "C:\\Windows"}\\System32\\wscript.exe" "${DAEMON_VBS_FILE}"`;
|
|
70
71
|
try {
|
package/dist/update-checker.d.ts
CHANGED
package/dist/update-checker.js
CHANGED
|
@@ -4,8 +4,11 @@ import { fileURLToPath } from "url";
|
|
|
4
4
|
import { spawnCommand } from "./spawn-command.js";
|
|
5
5
|
import { getPlatform } from "./platform/index.js";
|
|
6
6
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
7
|
-
const
|
|
8
|
-
|
|
7
|
+
const packageRoot = path.join(__dirname, "..");
|
|
8
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(packageRoot, "package.json"), "utf-8"));
|
|
9
|
+
/** True when running from a source checkout (has .git) rather than a global npm install. */
|
|
10
|
+
export const isDevBuild = fs.existsSync(path.join(packageRoot, ".git"));
|
|
11
|
+
export const currentVersion = isDevBuild ? `${pkg.version}-dev` : pkg.version;
|
|
9
12
|
let latestVersion = null;
|
|
10
13
|
let lastCheckTime = 0;
|
|
11
14
|
const CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;
|
|
@@ -13,6 +16,8 @@ const CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;
|
|
|
13
16
|
* Check the npm registry for the latest version of palmier.
|
|
14
17
|
*/
|
|
15
18
|
export async function checkForUpdate() {
|
|
19
|
+
if (isDevBuild)
|
|
20
|
+
return;
|
|
16
21
|
const now = Date.now();
|
|
17
22
|
if (now - lastCheckTime < CHECK_INTERVAL_MS)
|
|
18
23
|
return;
|
package/package.json
CHANGED
package/src/commands/lan.ts
CHANGED
|
@@ -2,7 +2,7 @@ import * as fs from "fs";
|
|
|
2
2
|
import { loadConfig, CONFIG_DIR } from "../config.js";
|
|
3
3
|
import { createRpcHandler } from "../rpc-handler.js";
|
|
4
4
|
import { startHttpTransport, detectLanIp } from "../transports/http-transport.js";
|
|
5
|
-
import { generatePairingCode } from "
|
|
5
|
+
import { generatePairingCode } from "./pair.js";
|
|
6
6
|
import { LAN_LOCKFILE } from "../lan-lock.js";
|
|
7
7
|
|
|
8
8
|
const bold = (s: string) => `\x1b[1m${s}\x1b[0m`;
|
package/src/commands/pair.ts
CHANGED
|
@@ -3,10 +3,20 @@ import { StringCodec } from "nats";
|
|
|
3
3
|
import { loadConfig } from "../config.js";
|
|
4
4
|
import { connectNats } from "../nats-client.js";
|
|
5
5
|
import { addSession } from "../session-store.js";
|
|
6
|
-
import { generatePairingCode, PAIRING_EXPIRY_MS } from "../pairing.js";
|
|
7
6
|
import { getLanPort } from "../lan-lock.js";
|
|
8
7
|
import type { HostConfig } from "../types.js";
|
|
9
8
|
|
|
9
|
+
const CODE_CHARS = "ABCDEFGHJKMNPQRSTUVWXYZ23456789"; // no O/0/I/1/L
|
|
10
|
+
const CODE_LENGTH = 6;
|
|
11
|
+
|
|
12
|
+
export const PAIRING_EXPIRY_MS = 5 * 60 * 1000; // 5 minutes
|
|
13
|
+
|
|
14
|
+
export function generatePairingCode(): string {
|
|
15
|
+
const bytes = new Uint8Array(CODE_LENGTH);
|
|
16
|
+
crypto.getRandomValues(bytes);
|
|
17
|
+
return Array.from(bytes, (b) => CODE_CHARS[b % CODE_CHARS.length]).join("");
|
|
18
|
+
}
|
|
19
|
+
|
|
10
20
|
function buildPairResponse(config: HostConfig, label?: string) {
|
|
11
21
|
const session = addSession(label);
|
|
12
22
|
return {
|
package/src/platform/windows.ts
CHANGED
|
@@ -78,8 +78,9 @@ export class WindowsPlatform implements PlatformService {
|
|
|
78
78
|
installDaemon(config: HostConfig): void {
|
|
79
79
|
const script = process.argv[1] || "palmier";
|
|
80
80
|
|
|
81
|
-
// Write a VBS launcher that starts the daemon with no visible console window
|
|
82
|
-
|
|
81
|
+
// Write a VBS launcher that starts the daemon with no visible console window.
|
|
82
|
+
// VBS doesn't use backslash escaping — only quotes need doubling ("").
|
|
83
|
+
const vbs = `CreateObject("WScript.Shell").Run """${process.execPath}"" ""${script}"" serve", 0, False`;
|
|
83
84
|
fs.writeFileSync(DAEMON_VBS_FILE, vbs, "utf-8");
|
|
84
85
|
|
|
85
86
|
const regValue = `"${process.env.SYSTEMROOT || "C:\\Windows"}\\System32\\wscript.exe" "${DAEMON_VBS_FILE}"`;
|
package/src/update-checker.ts
CHANGED
|
@@ -5,8 +5,12 @@ import { spawnCommand } from "./spawn-command.js";
|
|
|
5
5
|
import { getPlatform } from "./platform/index.js";
|
|
6
6
|
|
|
7
7
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
8
|
-
const
|
|
9
|
-
|
|
8
|
+
const packageRoot = path.join(__dirname, "..");
|
|
9
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(packageRoot, "package.json"), "utf-8")) as { version: string };
|
|
10
|
+
|
|
11
|
+
/** True when running from a source checkout (has .git) rather than a global npm install. */
|
|
12
|
+
export const isDevBuild = fs.existsSync(path.join(packageRoot, ".git"));
|
|
13
|
+
export const currentVersion = isDevBuild ? `${pkg.version}-dev` : pkg.version;
|
|
10
14
|
|
|
11
15
|
let latestVersion: string | null = null;
|
|
12
16
|
let lastCheckTime = 0;
|
|
@@ -16,6 +20,7 @@ const CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;
|
|
|
16
20
|
* Check the npm registry for the latest version of palmier.
|
|
17
21
|
*/
|
|
18
22
|
export async function checkForUpdate(): Promise<void> {
|
|
23
|
+
if (isDevBuild) return;
|
|
19
24
|
const now = Date.now();
|
|
20
25
|
if (now - lastCheckTime < CHECK_INTERVAL_MS) return;
|
|
21
26
|
lastCheckTime = now;
|
package/dist/pairing.d.ts
DELETED
package/dist/pairing.js
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
const CODE_CHARS = "ABCDEFGHJKMNPQRSTUVWXYZ23456789"; // no O/0/I/1/L
|
|
2
|
-
const CODE_LENGTH = 6;
|
|
3
|
-
export const PAIRING_EXPIRY_MS = 5 * 60 * 1000; // 5 minutes
|
|
4
|
-
export function generatePairingCode() {
|
|
5
|
-
const bytes = new Uint8Array(CODE_LENGTH);
|
|
6
|
-
crypto.getRandomValues(bytes);
|
|
7
|
-
return Array.from(bytes, (b) => CODE_CHARS[b % CODE_CHARS.length]).join("");
|
|
8
|
-
}
|
|
9
|
-
//# sourceMappingURL=pairing.js.map
|
package/src/pairing.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
const CODE_CHARS = "ABCDEFGHJKMNPQRSTUVWXYZ23456789"; // no O/0/I/1/L
|
|
2
|
-
const CODE_LENGTH = 6;
|
|
3
|
-
|
|
4
|
-
export const PAIRING_EXPIRY_MS = 5 * 60 * 1000; // 5 minutes
|
|
5
|
-
|
|
6
|
-
export function generatePairingCode(): string {
|
|
7
|
-
const bytes = new Uint8Array(CODE_LENGTH);
|
|
8
|
-
crypto.getRandomValues(bytes);
|
|
9
|
-
return Array.from(bytes, (b) => CODE_CHARS[b % CODE_CHARS.length]).join("");
|
|
10
|
-
}
|