palmier 0.6.1 → 0.6.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.
Files changed (44) hide show
  1. package/DISCLAIMER.md +2 -2
  2. package/dist/agents/agent-instructions.md +1 -1
  3. package/dist/agents/agent.d.ts +2 -0
  4. package/dist/agents/agent.js +21 -0
  5. package/dist/agents/aider.d.ts +9 -0
  6. package/dist/agents/aider.js +32 -0
  7. package/dist/agents/cursor.d.ts +9 -0
  8. package/dist/agents/cursor.js +35 -0
  9. package/dist/agents/deepagents.d.ts +9 -0
  10. package/dist/agents/deepagents.js +35 -0
  11. package/dist/agents/droid.d.ts +9 -0
  12. package/dist/agents/droid.js +32 -0
  13. package/dist/agents/goose.d.ts +9 -0
  14. package/dist/agents/goose.js +32 -0
  15. package/dist/agents/opencode.d.ts +9 -0
  16. package/dist/agents/opencode.js +35 -0
  17. package/dist/agents/openhands.d.ts +9 -0
  18. package/dist/agents/openhands.js +35 -0
  19. package/dist/commands/run.js +2 -2
  20. package/dist/pwa/assets/{index-C7Ib48wG.js → index-ByhOhTz1.js} +1 -1
  21. package/dist/pwa/index.html +2 -2
  22. package/dist/pwa/manifest.webmanifest +1 -1
  23. package/dist/pwa/service-worker.js +1 -1
  24. package/dist/rpc-handler.js +4 -3
  25. package/dist/transports/http-transport.js +3 -1
  26. package/package.json +1 -1
  27. package/palmier-server/pwa/index.html +1 -1
  28. package/palmier-server/pwa/src/constants.ts +1 -1
  29. package/palmier-server/pwa/src/service-worker.ts +3 -3
  30. package/palmier-server/pwa/vite.config.ts +1 -1
  31. package/palmier-server/server/src/index.ts +2 -0
  32. package/palmier-server/spec.md +1 -1
  33. package/src/agents/agent-instructions.md +1 -1
  34. package/src/agents/agent.ts +23 -0
  35. package/src/agents/aider.ts +37 -0
  36. package/src/agents/cursor.ts +38 -0
  37. package/src/agents/deepagents.ts +38 -0
  38. package/src/agents/droid.ts +37 -0
  39. package/src/agents/goose.ts +35 -0
  40. package/src/agents/opencode.ts +38 -0
  41. package/src/agents/openhands.ts +38 -0
  42. package/src/commands/run.ts +2 -2
  43. package/src/rpc-handler.ts +4 -3
  44. package/src/transports/http-transport.ts +3 -2
package/DISCLAIMER.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  ## AI Agent Execution
6
6
 
7
- Palmier spawns third-party AI agent CLIs (such as Claude Code, Gemini CLI, and Codex CLI) that can:
7
+ Palmier spawns third-party AI agent CLIs (such as Claude Code, Gemini CLI, Codex CLI, GitHub Copilot, and others) that can:
8
8
 
9
9
  - **Read, create, modify, and delete files** on your machine
10
10
  - **Execute arbitrary shell commands** with your user permissions
@@ -23,7 +23,7 @@ Tasks can be configured to run on schedules (cron) or in response to events with
23
23
 
24
24
  ## Third-Party Services
25
25
 
26
- Task prompts and execution data may be transmitted to third-party AI service providers (Anthropic, Google, OpenAI, etc.) according to their respective terms and privacy policies. Palmier does not control how these services process your data.
26
+ Task prompts and execution data may be transmitted to third-party AI service providers (Anthropic, Google, OpenAI, etc.) according to their respective terms and privacy policies. Palmier does not install and has no control over how these services process your data.
27
27
 
28
28
  When using server mode, communication between your device and the host is relayed through the Palmier server. See the [Privacy Policy](https://www.palmier.me/privacy) for details on what data is collected.
29
29
 
@@ -28,7 +28,7 @@ The request blocks until the user responds. Response: `{"values":["answer1","ans
28
28
 
29
29
  **Sending push notifications** — To notify the user, POST to `/notify` with:
30
30
  ```json
31
- {"title":"...","body":"..."}
31
+ {"taskId":"{{TASK_ID}}","title":"...","body":"..."}
32
32
  ```
33
33
 
34
34
  ---
@@ -4,6 +4,8 @@ export interface CommandLine {
4
4
  args: string[];
5
5
  /** If provided, the string is written to the process's stdin and then the pipe is closed. */
6
6
  stdin?: string;
7
+ /** Additional environment variables to set for the spawned process. */
8
+ env?: Record<string, string>;
7
9
  }
8
10
  /**
9
11
  * Interface that each agent tool must implement.
@@ -1,10 +1,17 @@
1
1
  import { ClaudeAgent } from "./claude.js";
2
2
  import { GeminiAgent } from "./gemini.js";
3
3
  import { CodexAgent } from "./codex.js";
4
+ import { DroidAgent } from "./droid.js";
4
5
  import { OpenClawAgent } from "./openclaw.js";
5
6
  import { CopilotAgent } from "./copilot.js";
6
7
  import { QwenAgent } from "./qwen.js";
7
8
  import { KimiAgent } from "./kimi.js";
9
+ import { GooseAgent } from "./goose.js";
10
+ import { OpenCodeAgent } from "./opencode.js";
11
+ import { DeepAgents } from "./deepagents.js";
12
+ import { Aider } from "./aider.js";
13
+ import { OpenHands } from "./openhands.js";
14
+ import { Cursor } from "./cursor.js";
8
15
  const agentRegistry = {
9
16
  claude: new ClaudeAgent(),
10
17
  gemini: new GeminiAgent(),
@@ -13,15 +20,29 @@ const agentRegistry = {
13
20
  copilot: new CopilotAgent(),
14
21
  qwen: new QwenAgent(),
15
22
  kimi: new KimiAgent(),
23
+ droid: new DroidAgent(),
24
+ goose: new GooseAgent(),
25
+ opencode: new OpenCodeAgent(),
26
+ deepagents: new DeepAgents(),
27
+ aider: new Aider(),
28
+ openhands: new OpenHands(),
29
+ cursor: new Cursor(),
16
30
  };
17
31
  const agentLabels = {
18
32
  claude: "Claude Code",
19
33
  gemini: "Gemini CLI",
20
34
  codex: "Codex CLI",
35
+ droid: "Droid CLI",
21
36
  openclaw: "OpenClaw",
22
37
  copilot: "Copilot CLI",
23
38
  qwen: "Qwen Code",
24
39
  kimi: "Kimi Code",
40
+ goose: "Goose CLI",
41
+ opencode: "OpenCode",
42
+ deepagents: "Deep Agents CLI",
43
+ aider: "Aider",
44
+ openhands: "OpenHands",
45
+ cursor: "Cursor CLI",
25
46
  };
26
47
  export async function detectAgents() {
27
48
  const detected = [];
@@ -0,0 +1,9 @@
1
+ import type { ParsedTask, RequiredPermission } from "../types.js";
2
+ import type { AgentTool, CommandLine } from "./agent.js";
3
+ export declare class Aider implements AgentTool {
4
+ supportsPermissions: boolean;
5
+ getPlanGenerationCommandLine(prompt: string): CommandLine;
6
+ getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[] | "yolo"): CommandLine;
7
+ init(): Promise<boolean>;
8
+ }
9
+ //# sourceMappingURL=aider.d.ts.map
@@ -0,0 +1,32 @@
1
+ import { execSync } from "child_process";
2
+ import { getAgentInstructions } from "./shared-prompt.js";
3
+ import { SHELL } from "../platform/index.js";
4
+ export class Aider {
5
+ supportsPermissions = false;
6
+ getPlanGenerationCommandLine(prompt) {
7
+ return {
8
+ command: "aider",
9
+ args: ["--message", prompt],
10
+ };
11
+ }
12
+ getTaskRunCommandLine(task, followupPrompt, extraPermissions) {
13
+ const yolo = extraPermissions === "yolo";
14
+ const prompt = followupPrompt ?? (getAgentInstructions(task.frontmatter.id, yolo || !this.supportsPermissions) + "\n\n" + (task.body || task.frontmatter.user_prompt));
15
+ const args = [];
16
+ if (yolo) {
17
+ args.push("--yes-always");
18
+ }
19
+ args.push("--message", prompt);
20
+ return { command: "aider", args };
21
+ }
22
+ async init() {
23
+ try {
24
+ execSync("aider --version", { stdio: "ignore", shell: SHELL });
25
+ }
26
+ catch {
27
+ return false;
28
+ }
29
+ return true;
30
+ }
31
+ }
32
+ //# sourceMappingURL=aider.js.map
@@ -0,0 +1,9 @@
1
+ import type { ParsedTask, RequiredPermission } from "../types.js";
2
+ import type { AgentTool, CommandLine } from "./agent.js";
3
+ export declare class Cursor implements AgentTool {
4
+ supportsPermissions: boolean;
5
+ getPlanGenerationCommandLine(prompt: string): CommandLine;
6
+ getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[] | "yolo"): CommandLine;
7
+ init(): Promise<boolean>;
8
+ }
9
+ //# sourceMappingURL=cursor.d.ts.map
@@ -0,0 +1,35 @@
1
+ import { execSync } from "child_process";
2
+ import { getAgentInstructions } from "./shared-prompt.js";
3
+ import { SHELL } from "../platform/index.js";
4
+ export class Cursor {
5
+ supportsPermissions = false;
6
+ getPlanGenerationCommandLine(prompt) {
7
+ return {
8
+ command: "cursor",
9
+ args: ["-p", prompt],
10
+ };
11
+ }
12
+ getTaskRunCommandLine(task, followupPrompt, extraPermissions) {
13
+ const yolo = extraPermissions === "yolo";
14
+ const prompt = followupPrompt ?? (getAgentInstructions(task.frontmatter.id, yolo || !this.supportsPermissions) + "\n\n" + (task.body || task.frontmatter.user_prompt));
15
+ const args = [];
16
+ if (yolo) {
17
+ args.push("--force");
18
+ }
19
+ if (followupPrompt) {
20
+ args.push("--continue");
21
+ } // continue mode for followups
22
+ args.push("-p", prompt);
23
+ return { command: "cursor", args };
24
+ }
25
+ async init() {
26
+ try {
27
+ execSync("cursor --version", { stdio: "ignore", shell: SHELL });
28
+ }
29
+ catch {
30
+ return false;
31
+ }
32
+ return true;
33
+ }
34
+ }
35
+ //# sourceMappingURL=cursor.js.map
@@ -0,0 +1,9 @@
1
+ import type { ParsedTask, RequiredPermission } from "../types.js";
2
+ import type { AgentTool, CommandLine } from "./agent.js";
3
+ export declare class DeepAgents implements AgentTool {
4
+ supportsPermissions: boolean;
5
+ getPlanGenerationCommandLine(prompt: string): CommandLine;
6
+ getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[] | "yolo"): CommandLine;
7
+ init(): Promise<boolean>;
8
+ }
9
+ //# sourceMappingURL=deepagents.d.ts.map
@@ -0,0 +1,35 @@
1
+ import { execSync } from "child_process";
2
+ import { getAgentInstructions } from "./shared-prompt.js";
3
+ import { SHELL } from "../platform/index.js";
4
+ export class DeepAgents {
5
+ supportsPermissions = false;
6
+ getPlanGenerationCommandLine(prompt) {
7
+ return {
8
+ command: "deepagents",
9
+ args: ["--non-interactive", prompt],
10
+ };
11
+ }
12
+ getTaskRunCommandLine(task, followupPrompt, extraPermissions) {
13
+ const yolo = extraPermissions === "yolo";
14
+ const prompt = followupPrompt ?? (getAgentInstructions(task.frontmatter.id, yolo || !this.supportsPermissions) + "\n\n" + (task.body || task.frontmatter.user_prompt));
15
+ const args = [];
16
+ if (yolo) {
17
+ args.push("--auto-approve");
18
+ }
19
+ if (followupPrompt) {
20
+ args.push("--resume");
21
+ } // continue mode for followups
22
+ args.push("--non-interactive", prompt);
23
+ return { command: "deepagents", args };
24
+ }
25
+ async init() {
26
+ try {
27
+ execSync("deepagents --version", { stdio: "ignore", shell: SHELL });
28
+ }
29
+ catch {
30
+ return false;
31
+ }
32
+ return true;
33
+ }
34
+ }
35
+ //# sourceMappingURL=deepagents.js.map
@@ -0,0 +1,9 @@
1
+ import type { ParsedTask, RequiredPermission } from "../types.js";
2
+ import type { AgentTool, CommandLine } from "./agent.js";
3
+ export declare class DroidAgent implements AgentTool {
4
+ supportsPermissions: boolean;
5
+ getPlanGenerationCommandLine(prompt: string): CommandLine;
6
+ getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[] | "yolo"): CommandLine;
7
+ init(): Promise<boolean>;
8
+ }
9
+ //# sourceMappingURL=droid.d.ts.map
@@ -0,0 +1,32 @@
1
+ import { execSync } from "child_process";
2
+ import { getAgentInstructions } from "./shared-prompt.js";
3
+ import { SHELL } from "../platform/index.js";
4
+ export class DroidAgent {
5
+ supportsPermissions = false;
6
+ getPlanGenerationCommandLine(prompt) {
7
+ return {
8
+ command: "droid",
9
+ args: ["exec", prompt],
10
+ };
11
+ }
12
+ getTaskRunCommandLine(task, followupPrompt, extraPermissions) {
13
+ const yolo = extraPermissions === "yolo";
14
+ const prompt = followupPrompt ?? (getAgentInstructions(task.frontmatter.id, yolo || !this.supportsPermissions) + "\n\n" + (task.body || task.frontmatter.user_prompt));
15
+ const args = ["exec", "--session-id", task.frontmatter.id];
16
+ if (yolo) {
17
+ args.push("--skip-permissions-unsafe");
18
+ }
19
+ args.push(prompt);
20
+ return { command: "droid", args };
21
+ }
22
+ async init() {
23
+ try {
24
+ execSync("droid --version", { stdio: "ignore", shell: SHELL });
25
+ }
26
+ catch {
27
+ return false;
28
+ }
29
+ return true;
30
+ }
31
+ }
32
+ //# sourceMappingURL=droid.js.map
@@ -0,0 +1,9 @@
1
+ import type { ParsedTask, RequiredPermission } from "../types.js";
2
+ import type { AgentTool, CommandLine } from "./agent.js";
3
+ export declare class GooseAgent implements AgentTool {
4
+ supportsPermissions: boolean;
5
+ getPlanGenerationCommandLine(prompt: string): CommandLine;
6
+ getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[] | "yolo"): CommandLine;
7
+ init(): Promise<boolean>;
8
+ }
9
+ //# sourceMappingURL=goose.d.ts.map
@@ -0,0 +1,32 @@
1
+ import { execSync } from "child_process";
2
+ import { getAgentInstructions } from "./shared-prompt.js";
3
+ import { SHELL } from "../platform/index.js";
4
+ export class GooseAgent {
5
+ supportsPermissions = false;
6
+ getPlanGenerationCommandLine(prompt) {
7
+ return {
8
+ command: "goose",
9
+ args: ["run", "--text", prompt],
10
+ };
11
+ }
12
+ getTaskRunCommandLine(task, followupPrompt, extraPermissions) {
13
+ const yolo = extraPermissions === "yolo";
14
+ const prompt = followupPrompt ?? (getAgentInstructions(task.frontmatter.id, yolo || !this.supportsPermissions) + "\n\n" + (task.body || task.frontmatter.user_prompt));
15
+ const args = ["run"];
16
+ if (followupPrompt) {
17
+ args.push("--resume");
18
+ } // continue mode for followups
19
+ args.push("--text", prompt);
20
+ return { command: "goose", args, ...(yolo ? { env: { GOOSE_MODE: "auto" } } : {}) };
21
+ }
22
+ async init() {
23
+ try {
24
+ execSync("goose --version", { stdio: "ignore", shell: SHELL });
25
+ }
26
+ catch {
27
+ return false;
28
+ }
29
+ return true;
30
+ }
31
+ }
32
+ //# sourceMappingURL=goose.js.map
@@ -0,0 +1,9 @@
1
+ import type { ParsedTask, RequiredPermission } from "../types.js";
2
+ import type { AgentTool, CommandLine } from "./agent.js";
3
+ export declare class OpenCodeAgent implements AgentTool {
4
+ supportsPermissions: boolean;
5
+ getPlanGenerationCommandLine(prompt: string): CommandLine;
6
+ getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[] | "yolo"): CommandLine;
7
+ init(): Promise<boolean>;
8
+ }
9
+ //# sourceMappingURL=opencode.d.ts.map
@@ -0,0 +1,35 @@
1
+ import { execSync } from "child_process";
2
+ import { getAgentInstructions } from "./shared-prompt.js";
3
+ import { SHELL } from "../platform/index.js";
4
+ export class OpenCodeAgent {
5
+ supportsPermissions = false;
6
+ getPlanGenerationCommandLine(prompt) {
7
+ return {
8
+ command: "opencode",
9
+ args: ["run", prompt],
10
+ };
11
+ }
12
+ getTaskRunCommandLine(task, followupPrompt, extraPermissions) {
13
+ const yolo = extraPermissions === "yolo";
14
+ const prompt = followupPrompt ?? (getAgentInstructions(task.frontmatter.id, yolo || !this.supportsPermissions) + "\n\n" + (task.body || task.frontmatter.user_prompt));
15
+ const args = ["run"];
16
+ if (yolo) {
17
+ args.push("--dangerously-skip-permissions");
18
+ }
19
+ if (followupPrompt) {
20
+ args.push("--continue");
21
+ } // continue mode for followups
22
+ args.push(prompt);
23
+ return { command: "opencode", args };
24
+ }
25
+ async init() {
26
+ try {
27
+ execSync("opencode --version", { stdio: "ignore", shell: SHELL });
28
+ }
29
+ catch {
30
+ return false;
31
+ }
32
+ return true;
33
+ }
34
+ }
35
+ //# sourceMappingURL=opencode.js.map
@@ -0,0 +1,9 @@
1
+ import type { ParsedTask, RequiredPermission } from "../types.js";
2
+ import type { AgentTool, CommandLine } from "./agent.js";
3
+ export declare class OpenHands implements AgentTool {
4
+ supportsPermissions: boolean;
5
+ getPlanGenerationCommandLine(prompt: string): CommandLine;
6
+ getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[] | "yolo"): CommandLine;
7
+ init(): Promise<boolean>;
8
+ }
9
+ //# sourceMappingURL=openhands.d.ts.map
@@ -0,0 +1,35 @@
1
+ import { execSync } from "child_process";
2
+ import { getAgentInstructions } from "./shared-prompt.js";
3
+ import { SHELL } from "../platform/index.js";
4
+ export class OpenHands {
5
+ supportsPermissions = false;
6
+ getPlanGenerationCommandLine(prompt) {
7
+ return {
8
+ command: "openhands",
9
+ args: ["--headless", "-t", prompt],
10
+ };
11
+ }
12
+ getTaskRunCommandLine(task, followupPrompt, extraPermissions) {
13
+ const yolo = extraPermissions === "yolo";
14
+ const prompt = followupPrompt ?? (getAgentInstructions(task.frontmatter.id, yolo || !this.supportsPermissions) + "\n\n" + (task.body || task.frontmatter.user_prompt));
15
+ const args = ["--headless"];
16
+ if (yolo) {
17
+ args.push("--always-approve");
18
+ }
19
+ if (followupPrompt) {
20
+ args.push("--resume", "--last");
21
+ } // continue mode for followups
22
+ args.push("-t", prompt);
23
+ return { command: "openhands", args };
24
+ }
25
+ async init() {
26
+ try {
27
+ execSync("openhands --version", { stdio: "ignore", shell: SHELL });
28
+ }
29
+ catch {
30
+ return false;
31
+ }
32
+ return true;
33
+ }
34
+ }
35
+ //# sourceMappingURL=openhands.js.map
@@ -33,13 +33,13 @@ async function invokeAgentWithRetries(ctx, invokeTask) {
33
33
  publishHostEvent(ctx.nc, ctx.config.hostId, ctx.taskId, { event_type: "result-updated", run_id: ctx.runId });
34
34
  }, 500);
35
35
  }
36
- const { command, args, stdin } = ctx.agent.getTaskRunCommandLine(invokeTask, undefined, ctx.task.frontmatter.yolo_mode ? "yolo" : ctx.transientPermissions);
36
+ const { command, args, stdin, env: agentEnv } = ctx.agent.getTaskRunCommandLine(invokeTask, undefined, ctx.task.frontmatter.yolo_mode ? "yolo" : ctx.transientPermissions);
37
37
  const truncate = (s, max = 100) => s.length > max ? s.slice(0, max) + "…" : s;
38
38
  const displayArgs = args.map((a) => truncate(a));
39
39
  console.log(`[invoke] ${command} ${displayArgs.join(" ")}${stdin ? ` (stdin: ${truncate(stdin, 100)})` : ""}`);
40
40
  const result = await spawnCommand(command, args, {
41
41
  cwd: getRunDir(ctx.taskDir, ctx.runId),
42
- env: { ...ctx.guiEnv, PALMIER_TASK_ID: ctx.task.frontmatter.id, PALMIER_RUN_DIR: getRunDir(ctx.taskDir, ctx.runId), PALMIER_HTTP_PORT: String(ctx.config.httpPort ?? 9966) },
42
+ env: { ...ctx.guiEnv, ...agentEnv, PALMIER_TASK_ID: ctx.task.frontmatter.id, PALMIER_RUN_DIR: getRunDir(ctx.taskDir, ctx.runId), PALMIER_HTTP_PORT: String(ctx.config.httpPort ?? 9966) },
43
43
  echoStdout: true,
44
44
  resolveOnFailure: true,
45
45
  stdin,