palmier 0.2.5 → 0.2.7

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 (78) hide show
  1. package/.github/workflows/ci.yml +16 -0
  2. package/LICENSE +190 -0
  3. package/README.md +286 -219
  4. package/dist/agents/agent.d.ts +6 -3
  5. package/dist/agents/agent.js +2 -0
  6. package/dist/agents/claude.d.ts +1 -1
  7. package/dist/agents/claude.js +12 -9
  8. package/dist/agents/codex.d.ts +1 -1
  9. package/dist/agents/codex.js +12 -10
  10. package/dist/agents/gemini.d.ts +1 -1
  11. package/dist/agents/gemini.js +13 -9
  12. package/dist/agents/openclaw.d.ts +2 -2
  13. package/dist/agents/openclaw.js +8 -7
  14. package/dist/agents/shared-prompt.d.ts +5 -4
  15. package/dist/agents/shared-prompt.js +10 -8
  16. package/dist/commands/agents.js +11 -0
  17. package/dist/commands/info.js +0 -22
  18. package/dist/commands/init.js +59 -95
  19. package/dist/commands/lan.d.ts +8 -0
  20. package/dist/commands/lan.js +51 -0
  21. package/dist/commands/mcpserver.js +12 -27
  22. package/dist/commands/pair.d.ts +1 -1
  23. package/dist/commands/pair.js +52 -56
  24. package/dist/commands/plan-generation.md +24 -32
  25. package/dist/commands/restart.d.ts +5 -0
  26. package/dist/commands/restart.js +9 -0
  27. package/dist/commands/run.js +311 -124
  28. package/dist/commands/serve.d.ts +1 -1
  29. package/dist/commands/serve.js +77 -17
  30. package/dist/commands/task-cleanup.d.ts +14 -0
  31. package/dist/commands/task-cleanup.js +84 -0
  32. package/dist/config.js +3 -17
  33. package/dist/events.d.ts +9 -0
  34. package/dist/events.js +46 -0
  35. package/dist/index.js +15 -0
  36. package/dist/platform/linux.d.ts +2 -0
  37. package/dist/platform/linux.js +22 -1
  38. package/dist/platform/platform.d.ts +4 -0
  39. package/dist/platform/windows.d.ts +3 -0
  40. package/dist/platform/windows.js +99 -82
  41. package/dist/rpc-handler.d.ts +2 -1
  42. package/dist/rpc-handler.js +43 -52
  43. package/dist/spawn-command.d.ts +29 -6
  44. package/dist/spawn-command.js +38 -15
  45. package/dist/transports/http-transport.d.ts +1 -1
  46. package/dist/transports/http-transport.js +103 -18
  47. package/dist/transports/nats-transport.d.ts +4 -2
  48. package/dist/transports/nats-transport.js +3 -4
  49. package/dist/types.d.ts +5 -5
  50. package/package.json +5 -3
  51. package/src/agents/agent.ts +8 -3
  52. package/src/agents/claude.ts +44 -43
  53. package/src/agents/codex.ts +11 -12
  54. package/src/agents/gemini.ts +12 -10
  55. package/src/agents/openclaw.ts +8 -7
  56. package/src/agents/shared-prompt.ts +10 -8
  57. package/src/commands/agents.ts +11 -0
  58. package/src/commands/info.ts +0 -24
  59. package/src/commands/init.ts +62 -119
  60. package/src/commands/lan.ts +58 -0
  61. package/src/commands/mcpserver.ts +12 -31
  62. package/src/commands/pair.ts +50 -63
  63. package/src/commands/plan-generation.md +24 -32
  64. package/src/commands/restart.ts +9 -0
  65. package/src/commands/run.ts +375 -143
  66. package/src/commands/serve.ts +96 -17
  67. package/src/config.ts +3 -18
  68. package/src/cross-spawn.d.ts +5 -0
  69. package/src/events.ts +51 -0
  70. package/src/index.ts +17 -0
  71. package/src/platform/linux.ts +25 -1
  72. package/src/platform/platform.ts +6 -0
  73. package/src/platform/windows.ts +100 -89
  74. package/src/rpc-handler.ts +46 -55
  75. package/src/spawn-command.ts +120 -83
  76. package/src/transports/http-transport.ts +123 -19
  77. package/src/transports/nats-transport.ts +4 -4
  78. package/src/types.ts +6 -8
@@ -1,12 +1,14 @@
1
+ import * as fs from "fs";
2
+ import * as path from "path";
1
3
  import * as http from "node:http";
2
4
  import { StringCodec } from "nats";
3
- import { loadConfig } from "../config.js";
5
+ import { loadConfig, CONFIG_DIR } from "../config.js";
4
6
  import { connectNats } from "../nats-client.js";
5
- import { detectLanIp } from "../transports/http-transport.js";
6
7
  import { addSession } from "../session-store.js";
7
8
  const CODE_CHARS = "ABCDEFGHJKMNPQRSTUVWXYZ23456789"; // no O/0/I/1/L
8
9
  const CODE_LENGTH = 6;
9
10
  const EXPIRY_MS = 5 * 60 * 1000; // 5 minutes
11
+ const LAN_LOCKFILE = path.join(CONFIG_DIR, "lan.json");
10
12
  function generateCode() {
11
13
  const bytes = new Uint8Array(CODE_LENGTH);
12
14
  crypto.getRandomValues(bytes);
@@ -14,15 +16,13 @@ function generateCode() {
14
16
  }
15
17
  function buildPairResponse(config, label) {
16
18
  const session = addSession(label);
17
- const response = {
19
+ return {
18
20
  hostId: config.hostId,
19
21
  sessionToken: session.token,
20
22
  };
21
- return response;
22
23
  }
23
24
  /**
24
- * POST to the running serve process and long-poll until paired or expired.
25
- * Returns true if paired, false if expired/failed.
25
+ * POST to the running LAN server and long-poll until paired or expired.
26
26
  */
27
27
  function lanPairRegister(port, code) {
28
28
  const body = JSON.stringify({ code, expiryMs: EXPIRY_MS });
@@ -33,7 +33,7 @@ function lanPairRegister(port, code) {
33
33
  path: "/internal/pair-register",
34
34
  method: "POST",
35
35
  headers: { "Content-Type": "application/json" },
36
- timeout: EXPIRY_MS + 5000, // slightly longer than expiry
36
+ timeout: EXPIRY_MS + 5000,
37
37
  }, (res) => {
38
38
  const chunks = [];
39
39
  res.on("data", (chunk) => chunks.push(chunk));
@@ -47,26 +47,30 @@ function lanPairRegister(port, code) {
47
47
  }
48
48
  });
49
49
  });
50
- req.on("error", (err) => {
51
- console.error(`Failed to reach palmier serve on port ${port}: ${err.message}`);
52
- console.error("Make sure `palmier serve` is running first.");
53
- resolve(false);
54
- });
55
- req.on("timeout", () => {
56
- req.destroy();
57
- resolve(false);
58
- });
50
+ req.on("error", () => resolve(false));
51
+ req.on("timeout", () => { req.destroy(); resolve(false); });
59
52
  req.end(body);
60
53
  });
61
54
  }
55
+ /**
56
+ * Read the LAN lockfile to check if `palmier lan` is running.
57
+ */
58
+ function getLanPort() {
59
+ try {
60
+ const raw = fs.readFileSync(LAN_LOCKFILE, "utf-8");
61
+ return JSON.parse(raw).port;
62
+ }
63
+ catch {
64
+ return null;
65
+ }
66
+ }
62
67
  /**
63
68
  * Generate an OTP code and wait for a PWA client to pair.
64
- * Listens on NATS (nats/auto modes) and/or HTTP (lan/auto modes).
69
+ * Listens on NATS always, and also on the LAN server if `palmier lan` is running.
65
70
  */
66
71
  export async function pairCommand() {
67
72
  const config = loadConfig();
68
73
  const code = generateCode();
69
- const mode = config.mode ?? "nats";
70
74
  let paired = false;
71
75
  function onPaired() {
72
76
  paired = true;
@@ -79,48 +83,40 @@ export async function pairCommand() {
79
83
  console.log("");
80
84
  console.log(` ${code}`);
81
85
  console.log("");
82
- if (mode === "lan" || mode === "auto") {
83
- const ip = detectLanIp();
84
- const port = config.directPort ?? 7400;
85
- console.log(` LAN Address: ${ip}:${port}`);
86
- console.log("");
87
- }
88
86
  console.log("Code expires in 5 minutes.");
89
- // NATS pairing (nats or auto mode)
90
- if (mode === "nats" || mode === "auto") {
91
- const nc = await connectNats(config);
92
- const sc = StringCodec();
93
- const subject = `pair.${code}`;
94
- const sub = nc.subscribe(subject, { max: 1 });
95
- cleanups.push(() => {
96
- sub.unsubscribe();
97
- nc.close();
98
- });
99
- (async () => {
100
- for await (const msg of sub) {
101
- if (paired)
102
- break;
103
- let label;
104
- try {
105
- if (msg.data && msg.data.length > 0) {
106
- const body = JSON.parse(sc.decode(msg.data));
107
- label = body.label;
108
- }
109
- }
110
- catch { /* empty body is fine */ }
111
- const response = buildPairResponse(config, label);
112
- if (msg.reply) {
113
- msg.respond(sc.encode(JSON.stringify(response)));
87
+ // NATS pairing (always active)
88
+ const nc = await connectNats(config);
89
+ const sc = StringCodec();
90
+ const subject = `pair.${code}`;
91
+ const sub = nc.subscribe(subject, { max: 1 });
92
+ cleanups.push(() => {
93
+ sub.unsubscribe();
94
+ nc.close();
95
+ });
96
+ (async () => {
97
+ for await (const msg of sub) {
98
+ if (paired)
99
+ break;
100
+ let label;
101
+ try {
102
+ if (msg.data && msg.data.length > 0) {
103
+ const body = JSON.parse(sc.decode(msg.data));
104
+ label = body.label;
114
105
  }
115
- onPaired();
116
106
  }
117
- })();
118
- }
119
- // LAN pairing — long-poll the running serve process
120
- if (mode === "lan" || mode === "auto") {
121
- const port = config.directPort ?? 7400;
107
+ catch { /* empty body is fine */ }
108
+ const response = buildPairResponse(config, label);
109
+ if (msg.reply) {
110
+ msg.respond(sc.encode(JSON.stringify(response)));
111
+ }
112
+ onPaired();
113
+ }
114
+ })();
115
+ // LAN pairing — if `palmier lan` is running, also register with it
116
+ const lanPort = getLanPort();
117
+ if (lanPort) {
122
118
  (async () => {
123
- const result = await lanPairRegister(port, code);
119
+ const result = await lanPairRegister(lanPort, code);
124
120
  if (result)
125
121
  onPaired();
126
122
  })();
@@ -1,32 +1,24 @@
1
- You are a task planning assistant. Given a task description, produce a detailed Markdown execution plan that an agent can follow step by step. **Do not execute any part of the plan yourself.**
2
-
3
- Your output must begin with a raw YAML frontmatter block (delimited by `---`), followed by the plan body in Markdown. Do NOT wrap the frontmatter in code fences. The very first line of your output must be `---`.
4
-
5
- **Output format:**
6
-
7
- ---
8
- task_name: <short descriptive name, 3-6 words>
9
- ---
10
-
11
- <plan body in Markdown>
12
-
13
- **Frontmatter fields:**
14
-
15
- - `task_name`: A concise label for the task (e.g., "Clean up temp files", "Update system packages", "Backup database daily").
16
-
17
- **Plan body sections:**
18
-
19
- ### 1. Goal
20
- State what the task accomplishes and the expected end state.
21
-
22
- ### 2. Plan
23
- A numbered sequence of concrete, actionable steps. Use sub-steps for complex actions and include conditional branches where behavior may vary (e.g., "If file exists, do A; otherwise, do B"). Each step should be specific enough for the agent to execute without ambiguity.
24
-
25
- ### 3. Output Format (if applicable)
26
- If the task produces a report, email, or other formatted output, specify the exact structure, sections, tone, and any templates the agent should follow.
27
-
28
- Use Markdown formatting throughout — headings, code blocks, and tables where appropriate.
29
-
30
- **Important:** Any relative times or dates in the task description (e.g., "yesterday", "last week") are relative to when the task is executed, not when this plan is generated. The agent must resolve them at execution time.
31
-
32
- **Task description:**
1
+ You are a task planning assistant. Given a task description, produce a Markdown execution plan for an agent. **Do not execute any part of the plan yourself.**
2
+
3
+ Output a raw YAML frontmatter block (delimited by `---`) followed by the plan body. Do NOT wrap frontmatter in code fences. The first line of output must be `---`.
4
+
5
+ ---
6
+ task_name: <short name, 3-6 words>
7
+ ---
8
+
9
+ **Frontmatter:** `task_name` — concise label (e.g., "Clean up temp files", "Backup database daily").
10
+
11
+ **Plan body:**
12
+
13
+ ### 1. Goal
14
+ What the task accomplishes and the expected end state.
15
+
16
+ ### 2. Plan
17
+ Numbered sequence of concrete, actionable steps. Include conditional branches where behavior may vary. Each step must be unambiguous.
18
+
19
+ ### 3. Output Format (if applicable)
20
+ If the task produces formatted output (report, email, etc.), specify structure, sections, tone, and templates.
21
+
22
+ Relative times in the task description (e.g., "yesterday") are relative to execution time, not plan generation time.
23
+
24
+ **Task description:**
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Restart the palmier serve daemon.
3
+ */
4
+ export declare function restartCommand(): Promise<void>;
5
+ //# sourceMappingURL=restart.d.ts.map
@@ -0,0 +1,9 @@
1
+ import { getPlatform } from "../platform/index.js";
2
+ /**
3
+ * Restart the palmier serve daemon.
4
+ */
5
+ export async function restartCommand() {
6
+ const platform = getPlatform();
7
+ await platform.restartDaemon();
8
+ }
9
+ //# sourceMappingURL=restart.js.map