palmier 1.1.22 → 1.1.24

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 (45) hide show
  1. package/DISCLAIMER.md +4 -2
  2. package/README.md +2 -19
  3. package/dist/agents/agent-instructions.md +0 -5
  4. package/dist/agents/agent.d.ts +3 -12
  5. package/dist/agents/agent.js +0 -2
  6. package/dist/agents/aider.js +2 -7
  7. package/dist/agents/claude.js +2 -12
  8. package/dist/agents/cline.js +2 -7
  9. package/dist/agents/codex.js +2 -4
  10. package/dist/agents/copilot.js +2 -10
  11. package/dist/agents/cursor.js +2 -7
  12. package/dist/agents/deepagents.js +2 -7
  13. package/dist/agents/droid.js +2 -7
  14. package/dist/agents/goose.js +2 -4
  15. package/dist/agents/grok.js +2 -7
  16. package/dist/agents/hermes.js +2 -7
  17. package/dist/agents/kimi.js +2 -6
  18. package/dist/agents/kiro.js +2 -7
  19. package/dist/agents/openclaw.js +1 -1
  20. package/dist/agents/opencode.js +2 -7
  21. package/dist/agents/qoder.js +2 -7
  22. package/dist/agents/qwen.js +2 -4
  23. package/dist/agents/shared-prompt.d.ts +0 -1
  24. package/dist/agents/shared-prompt.js +1 -8
  25. package/dist/agents/wizard.js +0 -2
  26. package/dist/commands/run.d.ts +1 -2
  27. package/dist/commands/run.js +97 -180
  28. package/dist/index.js +0 -22
  29. package/dist/password-store.d.ts +1 -3
  30. package/dist/password-store.js +1 -7
  31. package/dist/pending-requests.d.ts +3 -5
  32. package/dist/pwa/assets/index-CXiDfnsf.js +117 -0
  33. package/dist/pwa/assets/index-DWgTuvMe.css +1 -0
  34. package/dist/pwa/assets/{web-DQDmufih.js → web-BIh8c8oo.js} +1 -1
  35. package/dist/pwa/assets/{web-ew6AFUex.js → web-DTphq1C9.js} +1 -1
  36. package/dist/pwa/assets/{web-Dp5Zj6HJ.js → web-durUDXGk.js} +1 -1
  37. package/dist/pwa/index.html +2 -2
  38. package/dist/rpc-handler.js +1 -11
  39. package/dist/transports/http-transport.js +0 -37
  40. package/dist/types.d.ts +2 -10
  41. package/package.json +1 -1
  42. package/dist/commands/passwords.d.ts +0 -3
  43. package/dist/commands/passwords.js +0 -25
  44. package/dist/pwa/assets/index-ByB7B0d2.css +0 -1
  45. package/dist/pwa/assets/index-rqAuAC0q.js +0 -121
@@ -2,157 +2,116 @@ import * as fs from "fs";
2
2
  import * as path from "path";
3
3
  import { spawnCommand } from "../spawn-command.js";
4
4
  import { loadConfig } from "../config.js";
5
- import { parseTaskFile, taskDisplayName, getTaskDir, writeTaskFile, writeTaskStatus, readTaskStatus, appendHistory, createRunDir, claimPendingRun, appendRunMessage, getRunDir, beginStreamingMessage, formatAgentModelComment } from "../task.js";
5
+ import { parseTaskFile, taskDisplayName, getTaskDir, writeTaskStatus, readTaskStatus, appendHistory, createRunDir, claimPendingRun, appendRunMessage, getRunDir, beginStreamingMessage, formatAgentModelComment } from "../task.js";
6
6
  import { getAgent } from "../agents/agent.js";
7
7
  import { getPlatform } from "../platform/index.js";
8
- import { TASK_SUCCESS_MARKER, TASK_FAILURE_MARKER, TASK_PERMISSION_PREFIX, AGENT_MODEL_PREFIX } from "../agents/shared-prompt.js";
8
+ import { TASK_SUCCESS_MARKER, TASK_FAILURE_MARKER, AGENT_MODEL_PREFIX } from "../agents/shared-prompt.js";
9
9
  import { extractFileLinks, resolveTaskFile } from "../task-files.js";
10
10
  import { publishHostEvent } from "../events.js";
11
11
  /**
12
- * Invoke the agent CLI in a continuation loop to handle permission requests.
13
12
  * `invokeTask` is the ParsedTask whose prompt is passed to the agent (for
14
13
  * triggered tasks this is the per-trigger augmented task).
15
14
  */
16
- async function invokeAgentWithRetries(ctx, invokeTask) {
17
- // eslint-disable-next-line no-constant-condition
18
- while (true) {
19
- let writer;
20
- let activeStream;
21
- const lineBufs = { stdout: "", stderr: "" };
22
- let suppressedStderr = "";
23
- let notifyPending = false;
24
- let notifyTimer;
25
- let agentModel;
26
- let agentModelWritten = false;
27
- const captureCliModel = createCliModelCapture(ctx.agent);
28
- function throttledNotify() {
29
- if (notifyPending)
30
- return;
31
- notifyPending = true;
32
- notifyTimer = setTimeout(() => {
33
- notifyPending = false;
34
- publishHostEvent(ctx.taskId, { event_type: "result-updated", run_id: ctx.runId });
35
- }, 500);
36
- }
37
- function ensureWriter(stream) {
38
- if (writer && activeStream === stream)
39
- return writer;
40
- if (writer)
41
- writer.end();
42
- writer = beginStreamingMessage(ctx.taskDir, ctx.runId, Date.now(), stream);
43
- activeStream = stream;
15
+ async function invokeAgent(ctx, invokeTask) {
16
+ let writer;
17
+ let activeStream;
18
+ const lineBufs = { stdout: "", stderr: "" };
19
+ let suppressedStderr = "";
20
+ let notifyPending = false;
21
+ let notifyTimer;
22
+ let agentModel;
23
+ let agentModelWritten = false;
24
+ const captureCliModel = createCliModelCapture(ctx.agent);
25
+ function throttledNotify() {
26
+ if (notifyPending)
27
+ return;
28
+ notifyPending = true;
29
+ notifyTimer = setTimeout(() => {
30
+ notifyPending = false;
31
+ publishHostEvent(ctx.taskId, { event_type: "result-updated", run_id: ctx.runId });
32
+ }, 500);
33
+ }
34
+ function ensureWriter(stream) {
35
+ if (writer && activeStream === stream)
44
36
  return writer;
37
+ if (writer)
38
+ writer.end();
39
+ writer = beginStreamingMessage(ctx.taskDir, ctx.runId, Date.now(), stream);
40
+ activeStream = stream;
41
+ return writer;
42
+ }
43
+ function flushAgentModel() {
44
+ if (!agentModel || agentModelWritten || !writer)
45
+ return;
46
+ writer.write(formatAgentModelComment(agentModel));
47
+ agentModelWritten = true;
48
+ throttledNotify();
49
+ }
50
+ function onStderr(chunk) {
51
+ if (ctx.agent.suppressStdErr)
52
+ suppressedStderr += chunk;
53
+ else
54
+ emit("stderr", chunk);
55
+ const cliModel = captureCliModel(chunk);
56
+ if (cliModel && !agentModelWritten)
57
+ agentModel = cliModel;
58
+ flushAgentModel();
59
+ }
60
+ function emit(stream, chunk) {
61
+ lineBufs[stream] += chunk;
62
+ const lines = lineBufs[stream].split("\n");
63
+ lineBufs[stream] = lines.pop() ?? "";
64
+ if (stream === "stdout" && !agentModel) {
65
+ agentModel = parseAgentModel(lines.join("\n"));
45
66
  }
46
- function flushAgentModel() {
47
- if (!agentModel || agentModelWritten || !writer)
48
- return;
49
- writer.write(formatAgentModelComment(agentModel));
50
- agentModelWritten = true;
67
+ const filtered = lines.filter((l) => !l.startsWith("[PALMIER"));
68
+ if (filtered.length > 0) {
69
+ ensureWriter(stream).write(filtered.join("\n") + "\n");
51
70
  throttledNotify();
52
71
  }
53
- function onStderr(chunk) {
54
- if (ctx.agent.suppressStdErr)
55
- suppressedStderr += chunk;
56
- else
57
- emit("stderr", chunk);
58
- const cliModel = captureCliModel(chunk);
59
- if (cliModel && !agentModelWritten)
60
- agentModel = cliModel;
61
- flushAgentModel();
62
- }
63
- function emit(stream, chunk) {
64
- lineBufs[stream] += chunk;
65
- const lines = lineBufs[stream].split("\n");
66
- lineBufs[stream] = lines.pop() ?? "";
67
- if (stream === "stdout" && !agentModel) {
68
- agentModel = parseAgentModel(lines.join("\n"));
69
- }
70
- const filtered = lines.filter((l) => !l.startsWith("[PALMIER"));
71
- if (filtered.length > 0) {
72
- ensureWriter(stream).write(filtered.join("\n") + "\n");
73
- throttledNotify();
74
- }
75
- flushAgentModel();
76
- }
77
- function flushTrailingLine(stream) {
78
- const trailing = lineBufs[stream];
79
- if (trailing && !trailing.startsWith("[PALMIER")) {
80
- ensureWriter(stream).write(trailing);
81
- }
82
- }
83
- const { args, stdin, env: agentEnv, files } = ctx.agent.getTaskRunCommandLine(invokeTask, undefined, ctx.task.frontmatter.yolo_mode ? "yolo" : ctx.transientPermissions);
84
- const command = ctx.agent.command;
85
- const runDir = getRunDir(ctx.taskDir, ctx.runId);
86
- if (files) {
87
- for (const f of files)
88
- fs.writeFileSync(path.join(runDir, f.path), f.content, "utf-8");
72
+ flushAgentModel();
73
+ }
74
+ function flushTrailingLine(stream) {
75
+ const trailing = lineBufs[stream];
76
+ if (trailing && !trailing.startsWith("[PALMIER")) {
77
+ ensureWriter(stream).write(trailing);
89
78
  }
90
- const result = await spawnCommand(command, args, {
91
- cwd: runDir,
92
- env: { ...ctx.guiEnv, ...agentEnv, PALMIER_RUN_DIR: runDir, PALMIER_HTTP_PORT: String(ctx.config.httpPort ?? 7256) },
93
- echoStdout: true,
94
- resolveOnFailure: true,
95
- stdin,
96
- onStdout: (chunk) => emit("stdout", chunk),
97
- onStderr,
79
+ }
80
+ const { args, stdin, env: agentEnv, files } = ctx.agent.getTaskRunCommandLine(invokeTask);
81
+ const command = ctx.agent.command;
82
+ const runDir = getRunDir(ctx.taskDir, ctx.runId);
83
+ if (files) {
84
+ for (const f of files)
85
+ fs.writeFileSync(path.join(runDir, f.path), f.content, "utf-8");
86
+ }
87
+ const result = await spawnCommand(command, args, {
88
+ cwd: runDir,
89
+ env: { ...ctx.guiEnv, ...agentEnv, PALMIER_RUN_DIR: runDir, PALMIER_HTTP_PORT: String(ctx.config.httpPort ?? 7256) },
90
+ echoStdout: true,
91
+ resolveOnFailure: true,
92
+ stdin,
93
+ onStdout: (chunk) => emit("stdout", chunk),
94
+ onStderr,
95
+ });
96
+ const outcome = result.exitCode !== 0 ? "failed" : parseTaskOutcome(result.output);
97
+ const linkedFiles = listLinkedTaskFiles(ctx.taskDir, ctx.runId, result.output);
98
+ flushTrailingLine("stdout");
99
+ if (outcome === "failed")
100
+ emit("stderr", suppressedStderr);
101
+ flushTrailingLine("stderr");
102
+ if (notifyTimer)
103
+ clearTimeout(notifyTimer);
104
+ writer?.end();
105
+ await publishHostEvent(ctx.taskId, { event_type: "result-updated", run_id: ctx.runId });
106
+ if (linkedFiles.length > 0) {
107
+ await publishHostEvent(ctx.taskId, {
108
+ event_type: "report-generated",
109
+ run_id: ctx.runId,
110
+ name: taskDisplayName(ctx.task.frontmatter),
111
+ report_files: linkedFiles,
98
112
  });
99
- const outcome = result.exitCode !== 0 ? "failed" : parseTaskOutcome(result.output);
100
- const linkedFiles = listLinkedTaskFiles(ctx.taskDir, ctx.runId, result.output);
101
- const requiredPermissions = parsePermissions(result.output);
102
- flushTrailingLine("stdout");
103
- if (outcome === "failed")
104
- emit("stderr", suppressedStderr);
105
- flushTrailingLine("stderr");
106
- if (requiredPermissions.length > 0) {
107
- const permLines = requiredPermissions.map((p) => `- **${p.name}** ${p.description}`).join("\n");
108
- ensureWriter("stdout").write(`\n\n**Permissions requested:**\n${permLines}\n`);
109
- }
110
- if (notifyTimer)
111
- clearTimeout(notifyTimer);
112
- writer?.end();
113
- await publishHostEvent(ctx.taskId, { event_type: "result-updated", run_id: ctx.runId });
114
- if (linkedFiles.length > 0) {
115
- await publishHostEvent(ctx.taskId, {
116
- event_type: "report-generated",
117
- run_id: ctx.runId,
118
- name: taskDisplayName(ctx.task.frontmatter),
119
- report_files: linkedFiles,
120
- });
121
- }
122
- if (requiredPermissions.length > 0) {
123
- const response = await requestPermission(ctx.config, ctx.task, ctx.taskDir, requiredPermissions);
124
- if (response === "aborted") {
125
- await appendAndNotify(ctx, {
126
- role: "user",
127
- time: Date.now(),
128
- content: "Deny & Abort Task",
129
- type: "permission",
130
- });
131
- return { outcome: "failed" };
132
- }
133
- const newPerms = requiredPermissions.filter((rp) => !ctx.task.frontmatter.permissions?.some((ep) => ep.name === rp.name)
134
- && !ctx.transientPermissions.some((ep) => ep.name === rp.name));
135
- await appendAndNotify(ctx, {
136
- role: "user",
137
- time: Date.now(),
138
- content: response === "granted_all" ? "Allow Always" : "Allow Once",
139
- type: "permission",
140
- });
141
- if (response === "granted_all") {
142
- ctx.task.frontmatter.permissions = [...(ctx.task.frontmatter.permissions ?? []), ...newPerms];
143
- invokeTask.frontmatter.permissions = ctx.task.frontmatter.permissions;
144
- writeTaskFile(ctx.taskDir, ctx.task);
145
- }
146
- else {
147
- ctx.transientPermissions = [...ctx.transientPermissions, ...newPerms];
148
- }
149
- // Retry with the new permissions if the agent failed.
150
- if (outcome === "failed") {
151
- continue;
152
- }
153
- }
154
- return { outcome };
155
113
  }
114
+ return { outcome };
156
115
  }
157
116
  export function stripPalmierMarkers(output) {
158
117
  return output.split("\n").filter((l) => !l.startsWith("[PALMIER")).join("\n").trim();
@@ -217,7 +176,6 @@ export async function runCommand(taskId) {
217
176
  const agent = getAgent(task.frontmatter.agent);
218
177
  const ctx = {
219
178
  agent, task, taskDir, runId, guiEnv, config, taskId,
220
- transientPermissions: [],
221
179
  };
222
180
  // Command-output and on_new_* tasks share the same trigger machinery: the
223
181
  // daemon owns the trigger source (the shell command's stdout / a NATS
@@ -238,7 +196,7 @@ export async function runCommand(taskId) {
238
196
  time: Date.now(),
239
197
  content: task.frontmatter.user_prompt,
240
198
  });
241
- const result = await invokeAgentWithRetries(ctx, task);
199
+ const result = await invokeAgent(ctx, task);
242
200
  const outcome = resolveOutcome(taskDir, result.outcome);
243
201
  appendRunMessage(taskDir, runId, { role: "status", time: Date.now(), content: "", type: outcome });
244
202
  await publishTaskEvent(taskDir, taskId, outcome, taskName, runId);
@@ -299,7 +257,7 @@ async function runEventTriggeredMode(ctx) {
299
257
  const perEventTask = {
300
258
  frontmatter: { ...ctx.task.frontmatter, user_prompt: perEventPrompt },
301
259
  };
302
- const result = await invokeAgentWithRetries(ctx, perEventTask);
260
+ const result = await invokeAgent(ctx, perEventTask);
303
261
  lastOutcome = result.outcome;
304
262
  }
305
263
  }
@@ -324,28 +282,6 @@ async function publishTaskEvent(taskDir, taskId, eventType, taskName, runId) {
324
282
  payload.run_id = runId;
325
283
  await publishHostEvent(taskId, payload);
326
284
  }
327
- async function requestPermission(config, task, taskDir, requiredPermissions) {
328
- const port = config.httpPort ?? 7256;
329
- const res = await fetch(`http://localhost:${port}/request-permission`, {
330
- method: "POST",
331
- headers: { "Content-Type": "application/json" },
332
- body: JSON.stringify({
333
- taskId: task.frontmatter.id,
334
- taskName: taskDisplayName(task.frontmatter),
335
- permissions: requiredPermissions,
336
- }),
337
- });
338
- const body = await res.json();
339
- const response = body.response;
340
- if (!response || !["granted", "granted_all", "aborted"].includes(response)) {
341
- throw new Error(`Permission request failed: ${body.error ?? `unexpected response: ${JSON.stringify(body)}`}`);
342
- }
343
- writeTaskStatus(taskDir, {
344
- running_state: response === "aborted" ? "aborted" : "started",
345
- time_stamp: Date.now(),
346
- });
347
- return response;
348
- }
349
285
  async function requestConfirmation(config, task, taskDir) {
350
286
  const port = config.httpPort ?? 7256;
351
287
  const res = await fetch(`http://localhost:${port}/request-confirmation?taskId=${encodeURIComponent(task.frontmatter.id)}`, {
@@ -376,25 +312,6 @@ export function listLinkedTaskFiles(taskDir, runId, output) {
376
312
  }
377
313
  });
378
314
  }
379
- export function parsePermissions(output) {
380
- const regex = new RegExp(`^\\${TASK_PERMISSION_PREFIX}\\s+(.+)$`, "gm");
381
- const perms = [];
382
- let match;
383
- while ((match = regex.exec(output)) !== null) {
384
- const raw = match[1].trim();
385
- // Skip placeholder examples echoed from the prompt (e.g. "<tool_name> | <description>").
386
- if (raw.startsWith("<"))
387
- continue;
388
- const sep = raw.indexOf("|");
389
- if (sep !== -1) {
390
- perms.push({ name: raw.slice(0, sep).trim(), description: raw.slice(sep + 1).trim() });
391
- }
392
- else {
393
- perms.push({ name: raw, description: "" });
394
- }
395
- }
396
- return perms;
397
- }
398
315
  export function parseAgentModel(output) {
399
316
  const regex = new RegExp(`^\\${AGENT_MODEL_PREFIX}[ \\t]+(.+)$`, "gm");
400
317
  let match;
package/dist/index.js CHANGED
@@ -11,7 +11,6 @@ import { serveCommand } from "./commands/serve.js";
11
11
  import { pairCommand } from "./commands/pair.js";
12
12
  import { restartCommand } from "./commands/restart.js";
13
13
  import { clientsListCommand, clientsRevokeCommand, clientsRevokeAllCommand } from "./commands/clients.js";
14
- import { passwordsListCommand, passwordsDeleteCommand, passwordsClearCommand } from "./commands/passwords.js";
15
14
  import { agentsCommand } from "./commands/agents.js";
16
15
  import { uninstallCommand } from "./commands/uninstall.js";
17
16
  const __dirname = dirname(fileURLToPath(import.meta.url));
@@ -78,27 +77,6 @@ clientsCmd
78
77
  .action(async () => {
79
78
  await clientsRevokeAllCommand();
80
79
  });
81
- const passwordsCmd = program
82
- .command("passwords")
83
- .description("Manage saved passwords");
84
- passwordsCmd
85
- .command("list")
86
- .description("List saved passwords (origin and username only)")
87
- .action(async () => {
88
- await passwordsListCommand();
89
- });
90
- passwordsCmd
91
- .command("delete <origin> [username]")
92
- .description("Delete a saved password (omit username to delete all for the origin)")
93
- .action(async (origin, username) => {
94
- await passwordsDeleteCommand(origin, username);
95
- });
96
- passwordsCmd
97
- .command("clear")
98
- .description("Delete all saved passwords")
99
- .action(async () => {
100
- await passwordsClearCommand();
101
- });
102
80
  program
103
81
  .command("agents")
104
82
  .description("List, install, and uninstall agent CLIs")
@@ -8,6 +8,4 @@ export declare function normalizeOrigin(url: string): string;
8
8
  export declare function lookupPassword(origin: string, username: string): string | undefined;
9
9
  export declare function savePassword(origin: string, username: string, password: string): void;
10
10
  export declare function listPasswords(): PasswordIdentity[];
11
- /** Delete one (origin, username) entry, or every entry for an origin when username is omitted. */
12
- export declare function deletePassword(origin: string, username?: string): boolean;
13
- export declare function clearPasswords(): number;
11
+ export declare function deletePassword(origin: string, username: string): boolean;
@@ -80,17 +80,11 @@ export function savePassword(origin, username, password) {
80
80
  export function listPasswords() {
81
81
  return readFile().map(({ origin, username }) => ({ origin, username }));
82
82
  }
83
- /** Delete one (origin, username) entry, or every entry for an origin when username is omitted. */
84
83
  export function deletePassword(origin, username) {
85
84
  const entries = readFile();
86
- const remaining = entries.filter((e) => username === undefined ? e.origin !== origin : !(e.origin === origin && e.username === username));
85
+ const remaining = entries.filter((e) => !(e.origin === origin && e.username === username));
87
86
  if (remaining.length === entries.length)
88
87
  return false;
89
88
  writeFile(remaining);
90
89
  return true;
91
90
  }
92
- export function clearPasswords() {
93
- const entries = readFile();
94
- writeFile([]);
95
- return entries.length;
96
- }
@@ -1,8 +1,6 @@
1
- import type { RequiredPermission } from "./types.js";
2
1
  export interface PendingRequestMeta {
3
2
  /** The task the request belongs to. */
4
3
  session_id?: string;
5
- /** Task name, set for permission requests. */
6
4
  session_name?: string;
7
5
  description?: string;
8
6
  input_questions?: string[];
@@ -10,10 +8,10 @@ export interface PendingRequestMeta {
10
8
  secret?: boolean;
11
9
  }
12
10
  export interface PendingRequest {
13
- type: "confirmation" | "permission" | "input" | "choice";
11
+ type: "confirmation" | "input" | "choice";
14
12
  resolve: (value: string[]) => void;
15
- /** Permission list (for 'permission'), input descriptions (for 'input'), or option labels (for 'choice'). */
16
- params?: RequiredPermission[] | string[];
13
+ /** Input descriptions (for 'input') or option labels (for 'choice'). */
14
+ params?: string[];
17
15
  /** Display context for PWAs that connect while this request is already open. */
18
16
  meta?: PendingRequestMeta;
19
17
  }