palmier 0.5.1 → 0.5.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 +9 -9
- package/dist/agents/agent-instructions.md +7 -11
- package/dist/agents/agent.d.ts +8 -3
- package/dist/agents/agent.js +7 -1
- package/dist/agents/claude.d.ts +2 -1
- package/dist/agents/claude.js +10 -5
- package/dist/agents/codex.d.ts +2 -1
- package/dist/agents/codex.js +10 -6
- package/dist/agents/copilot.d.ts +2 -1
- package/dist/agents/copilot.js +10 -3
- package/dist/agents/gemini.d.ts +2 -1
- package/dist/agents/gemini.js +11 -7
- package/dist/agents/kimi.d.ts +9 -0
- package/dist/agents/kimi.js +35 -0
- package/dist/agents/openclaw.d.ts +2 -1
- package/dist/agents/openclaw.js +3 -1
- package/dist/agents/qwen.d.ts +9 -0
- package/dist/agents/qwen.js +32 -0
- package/dist/agents/shared-prompt.d.ts +1 -1
- package/dist/agents/shared-prompt.js +7 -3
- package/dist/client-store.d.ts +12 -0
- package/dist/client-store.js +57 -0
- package/dist/commands/clients.d.ts +4 -0
- package/dist/commands/clients.js +27 -0
- package/dist/commands/info.js +5 -5
- package/dist/commands/init.js +1 -1
- package/dist/commands/pair.js +4 -4
- package/dist/commands/run.js +21 -8
- package/dist/commands/serve.js +1 -1
- package/dist/events.js +1 -1
- package/dist/index.js +13 -13
- package/dist/rpc-handler.js +13 -6
- package/dist/task.d.ts +13 -3
- package/dist/task.js +39 -7
- package/dist/transports/http-transport.js +30 -13
- package/dist/transports/nats-transport.js +4 -4
- package/dist/types.d.ts +3 -2
- package/package.json +1 -1
- package/src/agents/agent-instructions.md +7 -11
- package/src/agents/agent.ts +16 -4
- package/src/agents/claude.ts +11 -6
- package/src/agents/codex.ts +11 -7
- package/src/agents/copilot.ts +10 -4
- package/src/agents/gemini.ts +12 -8
- package/src/agents/kimi.ts +37 -0
- package/src/agents/openclaw.ts +4 -2
- package/src/agents/qwen.ts +34 -0
- package/src/agents/shared-prompt.ts +7 -3
- package/src/client-store.ts +68 -0
- package/src/commands/clients.ts +29 -0
- package/src/commands/info.ts +5 -5
- package/src/commands/init.ts +1 -1
- package/src/commands/pair.ts +4 -4
- package/src/commands/run.ts +22 -8
- package/src/commands/serve.ts +1 -1
- package/src/events.ts +1 -1
- package/src/index.ts +13 -13
- package/src/rpc-handler.ts +15 -6
- package/src/task.ts +43 -8
- package/src/transports/http-transport.ts +32 -13
- package/src/transports/nats-transport.ts +4 -4
- package/src/types.ts +4 -3
- package/test/agent-instructions.test.ts +48 -0
- package/test/agent-output-parsing.test.ts +12 -0
- package/dist/commands/sessions.d.ts +0 -4
- package/dist/commands/sessions.js +0 -27
- package/dist/session-store.d.ts +0 -12
- package/dist/session-store.js +0 -57
- package/src/commands/sessions.ts +0 -29
- package/src/session-store.ts +0 -68
package/README.md
CHANGED
|
@@ -46,9 +46,9 @@ All `palmier` commands should be run from a dedicated Palmier root directory (e.
|
|
|
46
46
|
|---|---|
|
|
47
47
|
| `palmier init` | Interactive setup wizard |
|
|
48
48
|
| `palmier pair` | Generate an OTP code to pair a new device |
|
|
49
|
-
| `palmier
|
|
50
|
-
| `palmier
|
|
51
|
-
| `palmier
|
|
49
|
+
| `palmier clients list` | List active client tokens |
|
|
50
|
+
| `palmier clients revoke <token>` | Revoke a specific client token |
|
|
51
|
+
| `palmier clients revoke-all` | Revoke all client tokens |
|
|
52
52
|
| `palmier info` | Show host connection info (address, mode) |
|
|
53
53
|
| `palmier serve` | Run the persistent RPC handler (default command) |
|
|
54
54
|
| `palmier restart` | Restart the palmier serve daemon |
|
|
@@ -70,17 +70,17 @@ Local access (`http://localhost:<port>`) works immediately — no pairing needed
|
|
|
70
70
|
|
|
71
71
|
For LAN or server mode, run `palmier pair` on the host to generate an OTP code. Enter it in the PWA — either at `http://<host-ip>:<port>` (LAN mode) or `https://app.palmier.me` (server mode).
|
|
72
72
|
|
|
73
|
-
### Managing
|
|
73
|
+
### Managing clients
|
|
74
74
|
|
|
75
75
|
```bash
|
|
76
76
|
# List all paired devices
|
|
77
|
-
palmier
|
|
77
|
+
palmier clients list
|
|
78
78
|
|
|
79
79
|
# Revoke a specific device's access
|
|
80
|
-
palmier
|
|
80
|
+
palmier clients revoke <token>
|
|
81
81
|
|
|
82
|
-
# Revoke all
|
|
83
|
-
palmier
|
|
82
|
+
# Revoke all clients (unpair all devices)
|
|
83
|
+
palmier clients revoke-all
|
|
84
84
|
```
|
|
85
85
|
|
|
86
86
|
The `init` command:
|
|
@@ -126,7 +126,7 @@ palmier restart
|
|
|
126
126
|
## How It Works
|
|
127
127
|
|
|
128
128
|
- The host runs as a **background daemon** (systemd user service on Linux, Registry Run key on Windows), staying alive via `palmier serve`.
|
|
129
|
-
- **Device access** — localhost is always trusted (no pairing needed). LAN and server mode devices communicate via direct HTTP or NATS respectively, and must pair via OTP to get a
|
|
129
|
+
- **Device access** — localhost is always trusted (no pairing needed). LAN and server mode devices communicate via direct HTTP or NATS respectively, and must pair via OTP to get a client token.
|
|
130
130
|
- **Tasks** are stored locally as Markdown files in a `tasks/` directory. Each task has a name, prompt, execution plan, and optional schedules (cron schedules or one-time dates).
|
|
131
131
|
- **Plan generation** is automatic — when you create or update a task, the host invokes your chosen agent CLI to generate an execution plan and name.
|
|
132
132
|
- **Schedules** are backed by systemd timers (Linux) or Task Scheduler (Windows). You can enable/disable them without deleting the task, and any task can still be run manually at any time.
|
|
@@ -2,23 +2,19 @@ You are an AI agent executing a task on behalf of the user via the Palmier platf
|
|
|
2
2
|
|
|
3
3
|
## Reporting Output
|
|
4
4
|
|
|
5
|
-
If you generate report or output files, print each file path on its own line
|
|
6
|
-
[PALMIER_REPORT]
|
|
7
|
-
[PALMIER_REPORT] summary.md
|
|
5
|
+
If you generate report or output files, print each file path on its own line using this exact format:
|
|
6
|
+
[PALMIER_REPORT] <filename>
|
|
8
7
|
|
|
9
8
|
## Completion
|
|
10
9
|
|
|
11
|
-
When you are done, output exactly one of these markers as the very last line:
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
Do not wrap them in code blocks or add text on the same line.
|
|
10
|
+
When you are done, output exactly one of these markers as the very last line (no other text on the same line):
|
|
11
|
+
[PALMIER_TASK_SUCCESS]
|
|
12
|
+
[PALMIER_TASK_FAILURE]
|
|
15
13
|
|
|
16
14
|
## Permissions
|
|
17
15
|
|
|
18
|
-
If the task fails because a tool was denied or you lack the required permissions, print each required permission on its own line
|
|
19
|
-
[PALMIER_PERMISSION]
|
|
20
|
-
[PALMIER_PERMISSION] Bash(npm test) | Run the test suite via npm
|
|
21
|
-
[PALMIER_PERMISSION] Write | Write generated output files
|
|
16
|
+
If the task fails because a tool was denied or you lack the required permissions, print each required permission on its own line using this exact format:
|
|
17
|
+
[PALMIER_PERMISSION] <tool_name> | <description>
|
|
22
18
|
|
|
23
19
|
## HTTP Endpoints
|
|
24
20
|
|
package/dist/agents/agent.d.ts
CHANGED
|
@@ -13,9 +13,13 @@ export interface AgentTool {
|
|
|
13
13
|
/** Return the command and args used to generate a plan from a prompt. */
|
|
14
14
|
getPlanGenerationCommandLine(prompt: string): CommandLine;
|
|
15
15
|
/** Return the command and args used to run a task. If followupPrompt is provided, use it instead of the task's prompt,
|
|
16
|
-
* and treat it as a continuation of the original run (reuse the same session, etc).
|
|
17
|
-
* permissions granted for this run only
|
|
18
|
-
|
|
16
|
+
* and treat it as a continuation of the original run (reuse the same session, etc).
|
|
17
|
+
* extraPermissions: pass an array of RequiredPermission for transient permissions granted for this run only,
|
|
18
|
+
* or pass `"yolo"` to enable yolo mode (auto-approve all tools, skip permission instructions). */
|
|
19
|
+
getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[] | "yolo"): CommandLine;
|
|
20
|
+
/** Whether this agent supports permission overrides (e.g. --allowedTools).
|
|
21
|
+
* If false, the permissions section is omitted from agent instructions. */
|
|
22
|
+
supportsPermissions: boolean;
|
|
19
23
|
/** Detect whether the agent CLI is available and perform any agent-specific
|
|
20
24
|
* initialization. Returns true if the agent was detected and initialized successfully. */
|
|
21
25
|
init(): Promise<boolean>;
|
|
@@ -23,6 +27,7 @@ export interface AgentTool {
|
|
|
23
27
|
export interface DetectedAgent {
|
|
24
28
|
key: string;
|
|
25
29
|
label: string;
|
|
30
|
+
supportsPermissions: boolean;
|
|
26
31
|
}
|
|
27
32
|
export declare function detectAgents(): Promise<DetectedAgent[]>;
|
|
28
33
|
export declare function getAgent(name: string): AgentTool;
|
package/dist/agents/agent.js
CHANGED
|
@@ -3,12 +3,16 @@ import { GeminiAgent } from "./gemini.js";
|
|
|
3
3
|
import { CodexAgent } from "./codex.js";
|
|
4
4
|
import { OpenClawAgent } from "./openclaw.js";
|
|
5
5
|
import { CopilotAgent } from "./copilot.js";
|
|
6
|
+
import { QwenAgent } from "./qwen.js";
|
|
7
|
+
import { KimiAgent } from "./kimi.js";
|
|
6
8
|
const agentRegistry = {
|
|
7
9
|
claude: new ClaudeAgent(),
|
|
8
10
|
gemini: new GeminiAgent(),
|
|
9
11
|
codex: new CodexAgent(),
|
|
10
12
|
openclaw: new OpenClawAgent(),
|
|
11
13
|
copilot: new CopilotAgent(),
|
|
14
|
+
qwen: new QwenAgent(),
|
|
15
|
+
kimi: new KimiAgent(),
|
|
12
16
|
};
|
|
13
17
|
const agentLabels = {
|
|
14
18
|
claude: "Claude Code",
|
|
@@ -16,6 +20,8 @@ const agentLabels = {
|
|
|
16
20
|
codex: "Codex CLI",
|
|
17
21
|
openclaw: "OpenClaw",
|
|
18
22
|
copilot: "Copilot CLI",
|
|
23
|
+
qwen: "Qwen Code",
|
|
24
|
+
kimi: "Kimi Code",
|
|
19
25
|
};
|
|
20
26
|
export async function detectAgents() {
|
|
21
27
|
const detected = [];
|
|
@@ -23,7 +29,7 @@ export async function detectAgents() {
|
|
|
23
29
|
const label = agentLabels[key] ?? key;
|
|
24
30
|
const ok = await agent.init();
|
|
25
31
|
if (ok)
|
|
26
|
-
detected.push({ key, label });
|
|
32
|
+
detected.push({ key, label, supportsPermissions: agent.supportsPermissions });
|
|
27
33
|
}
|
|
28
34
|
return detected;
|
|
29
35
|
}
|
package/dist/agents/claude.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { ParsedTask, RequiredPermission } from "../types.js";
|
|
2
2
|
import type { AgentTool, CommandLine } from "./agent.js";
|
|
3
3
|
export declare class ClaudeAgent implements AgentTool {
|
|
4
|
+
supportsPermissions: boolean;
|
|
4
5
|
getPlanGenerationCommandLine(prompt: string): CommandLine;
|
|
5
|
-
getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[]): CommandLine;
|
|
6
|
+
getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[] | "yolo"): CommandLine;
|
|
6
7
|
init(): Promise<boolean>;
|
|
7
8
|
}
|
|
8
9
|
//# sourceMappingURL=claude.d.ts.map
|
package/dist/agents/claude.js
CHANGED
|
@@ -2,6 +2,7 @@ import { execSync } from "child_process";
|
|
|
2
2
|
import { getAgentInstructions } from "./shared-prompt.js";
|
|
3
3
|
import { SHELL } from "../platform/index.js";
|
|
4
4
|
export class ClaudeAgent {
|
|
5
|
+
supportsPermissions = true;
|
|
5
6
|
getPlanGenerationCommandLine(prompt) {
|
|
6
7
|
return {
|
|
7
8
|
command: "claude",
|
|
@@ -9,11 +10,15 @@ export class ClaudeAgent {
|
|
|
9
10
|
};
|
|
10
11
|
}
|
|
11
12
|
getTaskRunCommandLine(task, followupPrompt, extraPermissions) {
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
args.push("--allowedTools",
|
|
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 = ["--permission-mode", yolo ? "bypassPermissions" : "acceptEdits", "-p"];
|
|
16
|
+
if (!yolo) {
|
|
17
|
+
args.push("--allowedTools", "WebFetch");
|
|
18
|
+
const allPerms = [...(task.frontmatter.permissions ?? []), ...(extraPermissions ?? [])];
|
|
19
|
+
for (const p of allPerms) {
|
|
20
|
+
args.push("--allowedTools", p.name);
|
|
21
|
+
}
|
|
17
22
|
}
|
|
18
23
|
if (followupPrompt) {
|
|
19
24
|
args.push("-c");
|
package/dist/agents/codex.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { ParsedTask, RequiredPermission } from "../types.js";
|
|
2
2
|
import type { AgentTool, CommandLine } from "./agent.js";
|
|
3
3
|
export declare class CodexAgent implements AgentTool {
|
|
4
|
+
supportsPermissions: boolean;
|
|
4
5
|
getPlanGenerationCommandLine(prompt: string): CommandLine;
|
|
5
|
-
getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[]): CommandLine;
|
|
6
|
+
getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[] | "yolo"): CommandLine;
|
|
6
7
|
init(): Promise<boolean>;
|
|
7
8
|
}
|
|
8
9
|
//# sourceMappingURL=codex.d.ts.map
|
package/dist/agents/codex.js
CHANGED
|
@@ -2,6 +2,7 @@ import { execSync } from "child_process";
|
|
|
2
2
|
import { getAgentInstructions } from "./shared-prompt.js";
|
|
3
3
|
import { SHELL } from "../platform/index.js";
|
|
4
4
|
export class CodexAgent {
|
|
5
|
+
supportsPermissions = true;
|
|
5
6
|
getPlanGenerationCommandLine(prompt) {
|
|
6
7
|
return {
|
|
7
8
|
command: "codex",
|
|
@@ -9,13 +10,16 @@ export class CodexAgent {
|
|
|
9
10
|
};
|
|
10
11
|
}
|
|
11
12
|
getTaskRunCommandLine(task, followupPrompt, extraPermissions) {
|
|
12
|
-
const
|
|
13
|
+
const yolo = extraPermissions === "yolo";
|
|
14
|
+
const prompt = followupPrompt ?? (getAgentInstructions(task.frontmatter.id, yolo || !this.supportsPermissions) + "\n\n" + (task.body || task.frontmatter.user_prompt));
|
|
13
15
|
// Using danger-full-access until workspace-write is fixed: https://github.com/openai/codex/issues/12572
|
|
14
|
-
const args = ["exec", "--
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
const args = ["exec", "--skip-git-repo-check", "--sandbox", "danger-full-access"];
|
|
17
|
+
if (!yolo) {
|
|
18
|
+
const allPerms = [...(task.frontmatter.permissions ?? []), ...(extraPermissions ?? [])];
|
|
19
|
+
for (const p of allPerms) {
|
|
20
|
+
args.push("--config");
|
|
21
|
+
args.push(`apps.${p.name}.default_tools_approval_mode="approve"`);
|
|
22
|
+
}
|
|
19
23
|
}
|
|
20
24
|
if (followupPrompt) {
|
|
21
25
|
args.push("resume", "--last");
|
package/dist/agents/copilot.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { ParsedTask, RequiredPermission } from "../types.js";
|
|
2
2
|
import type { AgentTool, CommandLine } from "./agent.js";
|
|
3
3
|
export declare class CopilotAgent implements AgentTool {
|
|
4
|
+
supportsPermissions: boolean;
|
|
4
5
|
getPlanGenerationCommandLine(prompt: string): CommandLine;
|
|
5
|
-
getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[]): CommandLine;
|
|
6
|
+
getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[] | "yolo"): CommandLine;
|
|
6
7
|
init(): Promise<boolean>;
|
|
7
8
|
}
|
|
8
9
|
//# sourceMappingURL=copilot.d.ts.map
|
package/dist/agents/copilot.js
CHANGED
|
@@ -2,6 +2,7 @@ import { execSync } from "child_process";
|
|
|
2
2
|
import { getAgentInstructions } from "./shared-prompt.js";
|
|
3
3
|
import { SHELL } from "../platform/index.js";
|
|
4
4
|
export class CopilotAgent {
|
|
5
|
+
supportsPermissions = false;
|
|
5
6
|
getPlanGenerationCommandLine(prompt) {
|
|
6
7
|
return {
|
|
7
8
|
command: "copilot",
|
|
@@ -9,10 +10,16 @@ export class CopilotAgent {
|
|
|
9
10
|
};
|
|
10
11
|
}
|
|
11
12
|
getTaskRunCommandLine(task, followupPrompt, extraPermissions) {
|
|
12
|
-
const
|
|
13
|
+
const yolo = extraPermissions === "yolo";
|
|
14
|
+
const prompt = followupPrompt ?? (getAgentInstructions(task.frontmatter.id, yolo || !this.supportsPermissions) + "\n\n" + (task.body || task.frontmatter.user_prompt));
|
|
13
15
|
const args = ["-p", prompt];
|
|
14
|
-
|
|
15
|
-
|
|
16
|
+
if (yolo) {
|
|
17
|
+
args.push("--yolo");
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
const allPerms = [...(task.frontmatter.permissions ?? []), ...(extraPermissions ?? [])];
|
|
21
|
+
args.push(`--allow-tool=${["web_fetch", ...allPerms.map((p) => p.name)].join(",")}`);
|
|
22
|
+
}
|
|
16
23
|
if (followupPrompt) {
|
|
17
24
|
args.push("--continue");
|
|
18
25
|
}
|
package/dist/agents/gemini.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { ParsedTask, RequiredPermission } from "../types.js";
|
|
2
2
|
import type { AgentTool, CommandLine } from "./agent.js";
|
|
3
3
|
export declare class GeminiAgent implements AgentTool {
|
|
4
|
+
supportsPermissions: boolean;
|
|
4
5
|
getPlanGenerationCommandLine(prompt: string): CommandLine;
|
|
5
|
-
getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[]): CommandLine;
|
|
6
|
+
getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[] | "yolo"): CommandLine;
|
|
6
7
|
init(): Promise<boolean>;
|
|
7
8
|
}
|
|
8
9
|
//# sourceMappingURL=gemini.d.ts.map
|
package/dist/agents/gemini.js
CHANGED
|
@@ -2,6 +2,7 @@ import { execSync } from "child_process";
|
|
|
2
2
|
import { getAgentInstructions } from "./shared-prompt.js";
|
|
3
3
|
import { SHELL } from "../platform/index.js";
|
|
4
4
|
export class GeminiAgent {
|
|
5
|
+
supportsPermissions = true;
|
|
5
6
|
getPlanGenerationCommandLine(prompt) {
|
|
6
7
|
return {
|
|
7
8
|
command: "gemini",
|
|
@@ -9,19 +10,22 @@ export class GeminiAgent {
|
|
|
9
10
|
};
|
|
10
11
|
}
|
|
11
12
|
getTaskRunCommandLine(task, followupPrompt, extraPermissions) {
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
if (
|
|
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 = ["--approval-mode", yolo ? "yolo" : "auto_edit"];
|
|
16
|
+
if (!yolo) {
|
|
17
|
+
const tools = ["run_shell_command", "web_fetch"];
|
|
18
|
+
const allPerms = [...(task.frontmatter.permissions ?? []), ...(extraPermissions ?? [])];
|
|
16
19
|
for (const p of allPerms) {
|
|
17
|
-
|
|
20
|
+
tools.push(p.name);
|
|
18
21
|
}
|
|
22
|
+
args.push("--allowed-tools", tools.join(","));
|
|
19
23
|
}
|
|
20
24
|
if (followupPrompt) {
|
|
21
25
|
args.push("--resume");
|
|
22
26
|
} // continue mode for followups
|
|
23
|
-
args.push("--prompt",
|
|
24
|
-
return { command: "gemini", args };
|
|
27
|
+
args.push("--prompt", "-"); // read prompt from stdin to avoid command line length limits
|
|
28
|
+
return { command: "gemini", args, stdin: prompt };
|
|
25
29
|
}
|
|
26
30
|
async init() {
|
|
27
31
|
try {
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ParsedTask, RequiredPermission } from "../types.js";
|
|
2
|
+
import type { AgentTool, CommandLine } from "./agent.js";
|
|
3
|
+
export declare class KimiAgent 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=kimi.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 KimiAgent {
|
|
5
|
+
supportsPermissions = false;
|
|
6
|
+
getPlanGenerationCommandLine(prompt) {
|
|
7
|
+
return {
|
|
8
|
+
command: "kimi",
|
|
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("--yolo");
|
|
18
|
+
}
|
|
19
|
+
if (followupPrompt) {
|
|
20
|
+
args.push("--continue");
|
|
21
|
+
}
|
|
22
|
+
args.push("-p", prompt);
|
|
23
|
+
return { command: "kimi", args };
|
|
24
|
+
}
|
|
25
|
+
async init() {
|
|
26
|
+
try {
|
|
27
|
+
execSync("kimi --version", { stdio: "ignore", shell: SHELL });
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=kimi.js.map
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { ParsedTask, RequiredPermission } from "../types.js";
|
|
2
2
|
import type { AgentTool, CommandLine } from "./agent.js";
|
|
3
3
|
export declare class OpenClawAgent implements AgentTool {
|
|
4
|
+
supportsPermissions: boolean;
|
|
4
5
|
getPlanGenerationCommandLine(prompt: string): CommandLine;
|
|
5
|
-
getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[]): CommandLine;
|
|
6
|
+
getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[] | "yolo"): CommandLine;
|
|
6
7
|
init(): Promise<boolean>;
|
|
7
8
|
}
|
|
8
9
|
//# sourceMappingURL=openclaw.d.ts.map
|
package/dist/agents/openclaw.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { execSync } from "child_process";
|
|
2
2
|
import { getAgentInstructions } from "./shared-prompt.js";
|
|
3
3
|
export class OpenClawAgent {
|
|
4
|
+
supportsPermissions = false;
|
|
4
5
|
getPlanGenerationCommandLine(prompt) {
|
|
5
6
|
return {
|
|
6
7
|
command: "openclaw",
|
|
@@ -8,7 +9,8 @@ export class OpenClawAgent {
|
|
|
8
9
|
};
|
|
9
10
|
}
|
|
10
11
|
getTaskRunCommandLine(task, followupPrompt, extraPermissions) {
|
|
11
|
-
const
|
|
12
|
+
const yolo = extraPermissions === "yolo";
|
|
13
|
+
const prompt = followupPrompt ?? (getAgentInstructions(task.frontmatter.id, yolo || !this.supportsPermissions) + "\n\n" + (task.body || task.frontmatter.user_prompt));
|
|
12
14
|
// OpenClaw does not support stdin as prompt.
|
|
13
15
|
const args = ["agent", "--local", "--session-id", task.frontmatter.id, "--message", prompt];
|
|
14
16
|
return { command: "openclaw", args };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ParsedTask, RequiredPermission } from "../types.js";
|
|
2
|
+
import type { AgentTool, CommandLine } from "./agent.js";
|
|
3
|
+
export declare class QwenAgent 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=qwen.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 QwenAgent {
|
|
5
|
+
supportsPermissions = false;
|
|
6
|
+
getPlanGenerationCommandLine(prompt) {
|
|
7
|
+
return {
|
|
8
|
+
command: "qwen",
|
|
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 = ["--approval-mode", yolo ? "yolo" : "auto-edit"];
|
|
16
|
+
if (followupPrompt) {
|
|
17
|
+
args.push("-c");
|
|
18
|
+
}
|
|
19
|
+
args.push("-p", prompt);
|
|
20
|
+
return { command: "qwen", args };
|
|
21
|
+
}
|
|
22
|
+
async init() {
|
|
23
|
+
try {
|
|
24
|
+
execSync("qwen --version", { stdio: "ignore", shell: SHELL });
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=qwen.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Agent instructions with the serve daemon's HTTP port and task ID baked in.
|
|
3
3
|
*/
|
|
4
|
-
export declare function getAgentInstructions(taskId: string): string;
|
|
4
|
+
export declare function getAgentInstructions(taskId: string, skipPermissions?: boolean): string;
|
|
5
5
|
export declare const TASK_SUCCESS_MARKER = "[PALMIER_TASK_SUCCESS]";
|
|
6
6
|
export declare const TASK_FAILURE_MARKER = "[PALMIER_TASK_FAILURE]";
|
|
7
7
|
export declare const TASK_REPORT_PREFIX = "[PALMIER_REPORT]";
|
|
@@ -7,11 +7,15 @@ const AGENT_INSTRUCTIONS_TEMPLATE = fs.readFileSync(path.join(__dirname, "agent-
|
|
|
7
7
|
/**
|
|
8
8
|
* Agent instructions with the serve daemon's HTTP port and task ID baked in.
|
|
9
9
|
*/
|
|
10
|
-
export function getAgentInstructions(taskId) {
|
|
11
|
-
const port = loadConfig().httpPort ??
|
|
12
|
-
|
|
10
|
+
export function getAgentInstructions(taskId, skipPermissions) {
|
|
11
|
+
const port = loadConfig().httpPort ?? 9966;
|
|
12
|
+
let instructions = AGENT_INSTRUCTIONS_TEMPLATE
|
|
13
13
|
.replace(/\{\{PORT\}\}/g, String(port))
|
|
14
14
|
.replace(/\{\{TASK_ID\}\}/g, taskId);
|
|
15
|
+
if (skipPermissions) {
|
|
16
|
+
instructions = instructions.replace(/## Permissions\r?\n[\s\S]*?(?=## |\r?\n---)/m, "");
|
|
17
|
+
}
|
|
18
|
+
return instructions;
|
|
15
19
|
}
|
|
16
20
|
export const TASK_SUCCESS_MARKER = "[PALMIER_TASK_SUCCESS]";
|
|
17
21
|
export const TASK_FAILURE_MARKER = "[PALMIER_TASK_FAILURE]";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface ClientEntry {
|
|
2
|
+
token: string;
|
|
3
|
+
createdAt: string;
|
|
4
|
+
label?: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function loadClients(): ClientEntry[];
|
|
7
|
+
export declare function addClient(label?: string): ClientEntry;
|
|
8
|
+
export declare function revokeClient(token: string): boolean;
|
|
9
|
+
export declare function revokeAllClients(): number;
|
|
10
|
+
export declare function validateClient(token: string): boolean;
|
|
11
|
+
export declare function hasClients(): boolean;
|
|
12
|
+
//# sourceMappingURL=client-store.d.ts.map
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
import * as path from "path";
|
|
3
|
+
import { randomBytes } from "crypto";
|
|
4
|
+
import { CONFIG_DIR } from "./config.js";
|
|
5
|
+
const CLIENTS_FILE = path.join(CONFIG_DIR, "clients.json");
|
|
6
|
+
function readFile() {
|
|
7
|
+
try {
|
|
8
|
+
if (!fs.existsSync(CLIENTS_FILE))
|
|
9
|
+
return [];
|
|
10
|
+
const raw = fs.readFileSync(CLIENTS_FILE, "utf-8");
|
|
11
|
+
return JSON.parse(raw);
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return [];
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
function writeFile(clients) {
|
|
18
|
+
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
19
|
+
fs.writeFileSync(CLIENTS_FILE, JSON.stringify(clients, null, 2), "utf-8");
|
|
20
|
+
}
|
|
21
|
+
export function loadClients() {
|
|
22
|
+
return readFile();
|
|
23
|
+
}
|
|
24
|
+
export function addClient(label) {
|
|
25
|
+
const clients = readFile();
|
|
26
|
+
const entry = {
|
|
27
|
+
token: randomBytes(32).toString("hex"),
|
|
28
|
+
createdAt: new Date().toISOString(),
|
|
29
|
+
...(label ? { label } : {}),
|
|
30
|
+
};
|
|
31
|
+
clients.push(entry);
|
|
32
|
+
writeFile(clients);
|
|
33
|
+
return entry;
|
|
34
|
+
}
|
|
35
|
+
export function revokeClient(token) {
|
|
36
|
+
const clients = readFile();
|
|
37
|
+
const idx = clients.findIndex((c) => c.token === token);
|
|
38
|
+
if (idx === -1)
|
|
39
|
+
return false;
|
|
40
|
+
clients.splice(idx, 1);
|
|
41
|
+
writeFile(clients);
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
export function revokeAllClients() {
|
|
45
|
+
const clients = readFile();
|
|
46
|
+
const count = clients.length;
|
|
47
|
+
writeFile([]);
|
|
48
|
+
return count;
|
|
49
|
+
}
|
|
50
|
+
export function validateClient(token) {
|
|
51
|
+
const clients = readFile();
|
|
52
|
+
return clients.some((c) => c.token === token);
|
|
53
|
+
}
|
|
54
|
+
export function hasClients() {
|
|
55
|
+
return readFile().length > 0;
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=client-store.js.map
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { loadClients, revokeClient, revokeAllClients } from "../client-store.js";
|
|
2
|
+
export async function clientsListCommand() {
|
|
3
|
+
const clients = loadClients();
|
|
4
|
+
if (clients.length === 0) {
|
|
5
|
+
console.log("No active clients.");
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
console.log(`${clients.length} active client(s):\n`);
|
|
9
|
+
for (const c of clients) {
|
|
10
|
+
const label = c.label ? ` (${c.label})` : "";
|
|
11
|
+
console.log(` ${c.token}${label} created ${c.createdAt}`);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export async function clientsRevokeCommand(token) {
|
|
15
|
+
if (revokeClient(token)) {
|
|
16
|
+
console.log("Client revoked.");
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
console.error("Client not found.");
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export async function clientsRevokeAllCommand() {
|
|
24
|
+
const count = revokeAllClients();
|
|
25
|
+
console.log(`Revoked ${count} client(s).`);
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=clients.js.map
|
package/dist/commands/info.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { loadConfig } from "../config.js";
|
|
2
|
-
import {
|
|
2
|
+
import { loadClients } from "../client-store.js";
|
|
3
3
|
/**
|
|
4
4
|
* Print host connection info for setting up clients.
|
|
5
5
|
*/
|
|
6
6
|
export async function infoCommand() {
|
|
7
7
|
const config = loadConfig();
|
|
8
|
-
const
|
|
8
|
+
const clients = loadClients();
|
|
9
9
|
console.log(`Host ID: ${config.hostId}`);
|
|
10
10
|
console.log(`Project root: ${config.projectRoot}`);
|
|
11
11
|
// Detected agents
|
|
@@ -15,9 +15,9 @@ export async function infoCommand() {
|
|
|
15
15
|
else {
|
|
16
16
|
console.log(`Agents: (none detected — run \`palmier agents\`)`);
|
|
17
17
|
}
|
|
18
|
-
//
|
|
19
|
-
console.log(`
|
|
20
|
-
if (
|
|
18
|
+
// Clients
|
|
19
|
+
console.log(`Clients: ${clients.length} active`);
|
|
20
|
+
if (clients.length === 0) {
|
|
21
21
|
console.log("");
|
|
22
22
|
console.log("No paired clients. Run `palmier pair` to connect a device.");
|
|
23
23
|
}
|
package/dist/commands/init.js
CHANGED
|
@@ -33,7 +33,7 @@ export async function initCommand() {
|
|
|
33
33
|
// LAN mode
|
|
34
34
|
const lanAnswer = await ask("Enable LAN access (direct HTTP from local network)? (y/N): ");
|
|
35
35
|
const lanEnabled = lanAnswer.trim().toLowerCase() === "y";
|
|
36
|
-
let httpPort =
|
|
36
|
+
let httpPort = 9966;
|
|
37
37
|
const portLabel = lanEnabled ? "HTTP port for local and LAN access" : "HTTP port for local access";
|
|
38
38
|
const portAnswer = await ask(`${portLabel} (default ${httpPort}): `);
|
|
39
39
|
const parsed = parseInt(portAnswer.trim(), 10);
|
package/dist/commands/pair.js
CHANGED
|
@@ -2,7 +2,7 @@ import * as http from "node:http";
|
|
|
2
2
|
import { StringCodec } from "nats";
|
|
3
3
|
import { loadConfig } from "../config.js";
|
|
4
4
|
import { connectNats } from "../nats-client.js";
|
|
5
|
-
import {
|
|
5
|
+
import { addClient } from "../client-store.js";
|
|
6
6
|
const CODE_CHARS = "ABCDEFGHJKMNPQRSTUVWXYZ23456789"; // no O/0/I/1/L
|
|
7
7
|
const CODE_LENGTH = 6;
|
|
8
8
|
export const PAIRING_EXPIRY_MS = 5 * 60 * 1000; // 5 minutes
|
|
@@ -12,10 +12,10 @@ export function generatePairingCode() {
|
|
|
12
12
|
return Array.from(bytes, (b) => CODE_CHARS[b % CODE_CHARS.length]).join("");
|
|
13
13
|
}
|
|
14
14
|
function buildPairResponse(config, label) {
|
|
15
|
-
const
|
|
15
|
+
const client = addClient(label);
|
|
16
16
|
return {
|
|
17
17
|
hostId: config.hostId,
|
|
18
|
-
|
|
18
|
+
clientToken: client.token,
|
|
19
19
|
};
|
|
20
20
|
}
|
|
21
21
|
/**
|
|
@@ -56,7 +56,7 @@ function httpPairRegister(port, code) {
|
|
|
56
56
|
export async function pairCommand() {
|
|
57
57
|
const config = loadConfig();
|
|
58
58
|
const code = generatePairingCode();
|
|
59
|
-
const httpPort = config.httpPort ??
|
|
59
|
+
const httpPort = config.httpPort ?? 9966;
|
|
60
60
|
let paired = false;
|
|
61
61
|
function onPaired() {
|
|
62
62
|
paired = true;
|