palmier 0.7.7 → 0.7.9

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 (106) hide show
  1. package/README.md +1 -1
  2. package/dist/agents/agent.d.ts +3 -0
  3. package/dist/agents/agent.js +1 -1
  4. package/dist/agents/aider.d.ts +1 -0
  5. package/dist/agents/aider.js +1 -0
  6. package/dist/agents/claude.d.ts +1 -0
  7. package/dist/agents/claude.js +1 -0
  8. package/dist/agents/cline.d.ts +1 -0
  9. package/dist/agents/cline.js +1 -0
  10. package/dist/agents/codex.d.ts +1 -0
  11. package/dist/agents/codex.js +1 -0
  12. package/dist/agents/copilot.d.ts +1 -0
  13. package/dist/agents/copilot.js +1 -0
  14. package/dist/agents/cursor.d.ts +1 -0
  15. package/dist/agents/cursor.js +1 -0
  16. package/dist/agents/deepagents.d.ts +1 -0
  17. package/dist/agents/deepagents.js +1 -0
  18. package/dist/agents/droid.d.ts +1 -0
  19. package/dist/agents/droid.js +1 -0
  20. package/dist/agents/gemini.d.ts +1 -0
  21. package/dist/agents/gemini.js +1 -0
  22. package/dist/agents/goose.d.ts +1 -0
  23. package/dist/agents/goose.js +1 -0
  24. package/dist/agents/hermes.d.ts +1 -0
  25. package/dist/agents/hermes.js +1 -0
  26. package/dist/agents/kimi.d.ts +1 -0
  27. package/dist/agents/kimi.js +1 -0
  28. package/dist/agents/kiro.d.ts +1 -0
  29. package/dist/agents/kiro.js +1 -0
  30. package/dist/agents/openclaw.d.ts +1 -0
  31. package/dist/agents/openclaw.js +2 -2
  32. package/dist/agents/opencode.d.ts +1 -0
  33. package/dist/agents/opencode.js +1 -0
  34. package/dist/agents/qoder.d.ts +1 -0
  35. package/dist/agents/qoder.js +1 -0
  36. package/dist/agents/qwen.d.ts +1 -0
  37. package/dist/agents/qwen.js +1 -0
  38. package/dist/commands/pair.js +2 -2
  39. package/dist/mcp-tools.d.ts +2 -0
  40. package/dist/mcp-tools.js +20 -9
  41. package/dist/pending-requests.d.ts +30 -8
  42. package/dist/pending-requests.js +28 -15
  43. package/dist/platform/linux.js +11 -8
  44. package/dist/platform/windows.d.ts +5 -6
  45. package/dist/platform/windows.js +15 -12
  46. package/dist/pwa/assets/index-FP1Mipr6.js +120 -0
  47. package/dist/pwa/assets/index-bLTn8zBj.css +1 -0
  48. package/dist/pwa/assets/{web-CkWrlNwc.js → web-BpM3fNCn.js} +1 -1
  49. package/dist/pwa/assets/{web-lx34oBi7.js → web-CF-N8Di6.js} +1 -1
  50. package/dist/pwa/index.html +2 -2
  51. package/dist/pwa/service-worker.js +1 -1
  52. package/dist/rpc-handler.js +35 -24
  53. package/dist/task.js +1 -1
  54. package/dist/transports/http-transport.js +9 -8
  55. package/dist/types.d.ts +11 -6
  56. package/package.json +1 -1
  57. package/palmier-server/README.md +3 -3
  58. package/palmier-server/pwa/src/App.css +175 -28
  59. package/palmier-server/pwa/src/App.tsx +1 -0
  60. package/palmier-server/pwa/src/components/HostMenu.tsx +7 -2
  61. package/palmier-server/pwa/src/components/PullToRefreshIndicator.tsx +46 -0
  62. package/palmier-server/pwa/src/components/RunDetailView.tsx +58 -15
  63. package/palmier-server/pwa/src/components/SessionComposer.tsx +147 -0
  64. package/palmier-server/pwa/src/components/{RunsView.tsx → SessionsView.tsx} +79 -45
  65. package/palmier-server/pwa/src/components/TabBar.tsx +17 -10
  66. package/palmier-server/pwa/src/components/TaskCard.tsx +33 -35
  67. package/palmier-server/pwa/src/components/TaskForm.tsx +275 -349
  68. package/palmier-server/pwa/src/components/TasksView.tsx +172 -0
  69. package/palmier-server/pwa/src/constants.ts +1 -1
  70. package/palmier-server/pwa/src/contexts/HostStoreContext.tsx +16 -8
  71. package/palmier-server/pwa/src/draftGuard.ts +24 -0
  72. package/palmier-server/pwa/src/hooks/usePullToRefresh.ts +102 -0
  73. package/palmier-server/pwa/src/pages/Dashboard.tsx +343 -37
  74. package/palmier-server/pwa/src/types.ts +5 -14
  75. package/palmier-server/spec.md +39 -26
  76. package/src/agents/agent.ts +5 -1
  77. package/src/agents/aider.ts +1 -0
  78. package/src/agents/claude.ts +1 -0
  79. package/src/agents/cline.ts +1 -0
  80. package/src/agents/codex.ts +1 -0
  81. package/src/agents/copilot.ts +1 -0
  82. package/src/agents/cursor.ts +1 -0
  83. package/src/agents/deepagents.ts +1 -0
  84. package/src/agents/droid.ts +1 -0
  85. package/src/agents/gemini.ts +1 -0
  86. package/src/agents/goose.ts +1 -0
  87. package/src/agents/hermes.ts +1 -0
  88. package/src/agents/kimi.ts +1 -0
  89. package/src/agents/kiro.ts +1 -0
  90. package/src/agents/openclaw.ts +2 -2
  91. package/src/agents/opencode.ts +1 -0
  92. package/src/agents/qoder.ts +1 -0
  93. package/src/agents/qwen.ts +1 -0
  94. package/src/commands/pair.ts +2 -2
  95. package/src/mcp-tools.ts +22 -9
  96. package/src/pending-requests.ts +47 -15
  97. package/src/platform/linux.ts +10 -8
  98. package/src/platform/windows.ts +15 -12
  99. package/src/rpc-handler.ts +39 -26
  100. package/src/task.ts +1 -1
  101. package/src/transports/http-transport.ts +9 -8
  102. package/src/types.ts +10 -8
  103. package/test/pairing.test.ts +2 -2
  104. package/dist/pwa/assets/index-B-ByUHPS.css +0 -1
  105. package/dist/pwa/assets/index-Bt8Hhaw3.js +0 -118
  106. package/palmier-server/pwa/src/components/TaskListView.tsx +0 -431
package/README.md CHANGED
@@ -8,7 +8,7 @@
8
8
 
9
9
  You have AI agents on your machine. But you have to sit at your desk to use them. Palmier lets you dispatch, schedule, and monitor them from any device, anywhere.
10
10
 
11
- It runs on your machine as a background daemon and connects to a mobile-friendly PWA, so you can create tasks, approve permissions, and check results without being at your computer.
11
+ It runs on your machine as a background daemon and connects to a mobile-friendly PWA, so you can start one-off sessions, schedule recurring tasks, approve permissions, and check results without being at your computer.
12
12
  > **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.
13
13
 
14
14
  ## Quick Start
@@ -22,6 +22,8 @@ export interface AgentTool {
22
22
  /** Whether this agent supports permission overrides (e.g. --allowedTools).
23
23
  * If false, the permissions section is omitted from agent instructions. */
24
24
  supportsPermissions: boolean;
25
+ /** Whether this agent supports yolo mode (auto-approve all tools). */
26
+ supportsYolo: boolean;
25
27
  /** Detect whether the agent CLI is available and perform any agent-specific
26
28
  * initialization. Returns true if the agent was detected and initialized successfully. */
27
29
  init(): Promise<boolean>;
@@ -30,6 +32,7 @@ export interface DetectedAgent {
30
32
  key: string;
31
33
  label: string;
32
34
  supportsPermissions: boolean;
35
+ supportsYolo: boolean;
33
36
  }
34
37
  export declare function detectAgents(): Promise<DetectedAgent[]>;
35
38
  export declare function getAgent(name: string): AgentTool;
@@ -59,7 +59,7 @@ export async function detectAgents() {
59
59
  const label = agentLabels[key] ?? key;
60
60
  const ok = await agent.init();
61
61
  if (ok)
62
- detected.push({ key, label, supportsPermissions: agent.supportsPermissions });
62
+ detected.push({ key, label, supportsPermissions: agent.supportsPermissions, supportsYolo: agent.supportsYolo });
63
63
  }
64
64
  return detected;
65
65
  }
@@ -2,6 +2,7 @@ import type { ParsedTask, RequiredPermission } from "../types.js";
2
2
  import type { AgentTool, CommandLine } from "./agent.js";
3
3
  export declare class Aider implements AgentTool {
4
4
  supportsPermissions: boolean;
5
+ supportsYolo: boolean;
5
6
  getPromptCommandLine(prompt: string): CommandLine;
6
7
  getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[] | "yolo"): CommandLine;
7
8
  init(): Promise<boolean>;
@@ -3,6 +3,7 @@ import { getAgentInstructions } from "./shared-prompt.js";
3
3
  import { SHELL } from "../platform/index.js";
4
4
  export class Aider {
5
5
  supportsPermissions = false;
6
+ supportsYolo = true;
6
7
  getPromptCommandLine(prompt) {
7
8
  return { command: "aider", args: ["--message", prompt] };
8
9
  }
@@ -2,6 +2,7 @@ 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
4
  supportsPermissions: boolean;
5
+ supportsYolo: boolean;
5
6
  getPromptCommandLine(prompt: string): CommandLine;
6
7
  getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[] | "yolo"): CommandLine;
7
8
  init(): Promise<boolean>;
@@ -3,6 +3,7 @@ import { getAgentInstructions } from "./shared-prompt.js";
3
3
  import { SHELL } from "../platform/index.js";
4
4
  export class ClaudeAgent {
5
5
  supportsPermissions = true;
6
+ supportsYolo = true;
6
7
  getPromptCommandLine(prompt) {
7
8
  return { command: "claude", args: ["-p", prompt] };
8
9
  }
@@ -2,6 +2,7 @@ import type { ParsedTask, RequiredPermission } from "../types.js";
2
2
  import type { AgentTool, CommandLine } from "./agent.js";
3
3
  export declare class Cline implements AgentTool {
4
4
  supportsPermissions: boolean;
5
+ supportsYolo: boolean;
5
6
  getPromptCommandLine(prompt: string): CommandLine;
6
7
  getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[] | "yolo"): CommandLine;
7
8
  init(): Promise<boolean>;
@@ -3,6 +3,7 @@ import { getAgentInstructions } from "./shared-prompt.js";
3
3
  import { SHELL } from "../platform/index.js";
4
4
  export class Cline {
5
5
  supportsPermissions = false;
6
+ supportsYolo = true;
6
7
  getPromptCommandLine(prompt) {
7
8
  return { command: "cline ", args: ["--yolo", "-p", prompt] };
8
9
  }
@@ -2,6 +2,7 @@ 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
4
  supportsPermissions: boolean;
5
+ supportsYolo: boolean;
5
6
  getPromptCommandLine(prompt: string): CommandLine;
6
7
  getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[] | "yolo"): CommandLine;
7
8
  init(): Promise<boolean>;
@@ -3,6 +3,7 @@ import { getAgentInstructions } from "./shared-prompt.js";
3
3
  import { SHELL } from "../platform/index.js";
4
4
  export class CodexAgent {
5
5
  supportsPermissions = true;
6
+ supportsYolo = true;
6
7
  getPromptCommandLine(prompt) {
7
8
  return { command: "codex", args: ["exec", "--skip-git-repo-check", prompt] };
8
9
  }
@@ -2,6 +2,7 @@ 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
4
  supportsPermissions: boolean;
5
+ supportsYolo: boolean;
5
6
  getPromptCommandLine(prompt: string): CommandLine;
6
7
  getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[] | "yolo"): CommandLine;
7
8
  init(): Promise<boolean>;
@@ -3,6 +3,7 @@ import { getAgentInstructions } from "./shared-prompt.js";
3
3
  import { SHELL } from "../platform/index.js";
4
4
  export class CopilotAgent {
5
5
  supportsPermissions = false;
6
+ supportsYolo = true;
6
7
  getPromptCommandLine(prompt) {
7
8
  return { command: "copilot", args: ["-p", prompt] };
8
9
  }
@@ -2,6 +2,7 @@ import type { ParsedTask, RequiredPermission } from "../types.js";
2
2
  import type { AgentTool, CommandLine } from "./agent.js";
3
3
  export declare class Cursor implements AgentTool {
4
4
  supportsPermissions: boolean;
5
+ supportsYolo: boolean;
5
6
  getPromptCommandLine(prompt: string): CommandLine;
6
7
  getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[] | "yolo"): CommandLine;
7
8
  init(): Promise<boolean>;
@@ -3,6 +3,7 @@ import { getAgentInstructions } from "./shared-prompt.js";
3
3
  import { SHELL } from "../platform/index.js";
4
4
  export class Cursor {
5
5
  supportsPermissions = false;
6
+ supportsYolo = true;
6
7
  getPromptCommandLine(prompt) {
7
8
  return { command: "cursor", args: ["-p", prompt] };
8
9
  }
@@ -2,6 +2,7 @@ import type { ParsedTask, RequiredPermission } from "../types.js";
2
2
  import type { AgentTool, CommandLine } from "./agent.js";
3
3
  export declare class DeepAgents implements AgentTool {
4
4
  supportsPermissions: boolean;
5
+ supportsYolo: boolean;
5
6
  getPromptCommandLine(prompt: string): CommandLine;
6
7
  getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[] | "yolo"): CommandLine;
7
8
  init(): Promise<boolean>;
@@ -3,6 +3,7 @@ import { getAgentInstructions } from "./shared-prompt.js";
3
3
  import { SHELL } from "../platform/index.js";
4
4
  export class DeepAgents {
5
5
  supportsPermissions = false;
6
+ supportsYolo = true;
6
7
  getPromptCommandLine(prompt) {
7
8
  return { command: "deepagents", args: ["--non-interactive", prompt] };
8
9
  }
@@ -2,6 +2,7 @@ import type { ParsedTask, RequiredPermission } from "../types.js";
2
2
  import type { AgentTool, CommandLine } from "./agent.js";
3
3
  export declare class DroidAgent implements AgentTool {
4
4
  supportsPermissions: boolean;
5
+ supportsYolo: boolean;
5
6
  getPromptCommandLine(prompt: string): CommandLine;
6
7
  getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[] | "yolo"): CommandLine;
7
8
  init(): Promise<boolean>;
@@ -3,6 +3,7 @@ import { getAgentInstructions } from "./shared-prompt.js";
3
3
  import { SHELL } from "../platform/index.js";
4
4
  export class DroidAgent {
5
5
  supportsPermissions = false;
6
+ supportsYolo = true;
6
7
  getPromptCommandLine(prompt) {
7
8
  return { command: "droid", args: ["exec", prompt] };
8
9
  }
@@ -2,6 +2,7 @@ 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
4
  supportsPermissions: boolean;
5
+ supportsYolo: boolean;
5
6
  getPromptCommandLine(prompt: string): CommandLine;
6
7
  getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[] | "yolo"): CommandLine;
7
8
  init(): Promise<boolean>;
@@ -3,6 +3,7 @@ import { getAgentInstructions } from "./shared-prompt.js";
3
3
  import { SHELL } from "../platform/index.js";
4
4
  export class GeminiAgent {
5
5
  supportsPermissions = true;
6
+ supportsYolo = true;
6
7
  getPromptCommandLine(prompt) {
7
8
  return { command: "gemini", args: ["--prompt", prompt] };
8
9
  }
@@ -2,6 +2,7 @@ import type { ParsedTask, RequiredPermission } from "../types.js";
2
2
  import type { AgentTool, CommandLine } from "./agent.js";
3
3
  export declare class GooseAgent implements AgentTool {
4
4
  supportsPermissions: boolean;
5
+ supportsYolo: boolean;
5
6
  getPromptCommandLine(prompt: string): CommandLine;
6
7
  getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[] | "yolo"): CommandLine;
7
8
  init(): Promise<boolean>;
@@ -3,6 +3,7 @@ import { getAgentInstructions } from "./shared-prompt.js";
3
3
  import { SHELL } from "../platform/index.js";
4
4
  export class GooseAgent {
5
5
  supportsPermissions = false;
6
+ supportsYolo = true;
6
7
  getPromptCommandLine(prompt) {
7
8
  return { command: "goose", args: ["run", "--text", prompt] };
8
9
  }
@@ -2,6 +2,7 @@ import type { ParsedTask, RequiredPermission } from "../types.js";
2
2
  import type { AgentTool, CommandLine } from "./agent.js";
3
3
  export declare class Hermes implements AgentTool {
4
4
  supportsPermissions: boolean;
5
+ supportsYolo: boolean;
5
6
  getPromptCommandLine(prompt: string): CommandLine;
6
7
  getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[] | "yolo"): CommandLine;
7
8
  init(): Promise<boolean>;
@@ -3,6 +3,7 @@ import { getAgentInstructions } from "./shared-prompt.js";
3
3
  import { SHELL } from "../platform/index.js";
4
4
  export class Hermes {
5
5
  supportsPermissions = false;
6
+ supportsYolo = true;
6
7
  getPromptCommandLine(prompt) {
7
8
  return { command: "hermes", args: ["chat", "-q", prompt] };
8
9
  }
@@ -2,6 +2,7 @@ import type { ParsedTask, RequiredPermission } from "../types.js";
2
2
  import type { AgentTool, CommandLine } from "./agent.js";
3
3
  export declare class KimiAgent implements AgentTool {
4
4
  supportsPermissions: boolean;
5
+ supportsYolo: boolean;
5
6
  getPromptCommandLine(prompt: string): CommandLine;
6
7
  getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[] | "yolo"): CommandLine;
7
8
  init(): Promise<boolean>;
@@ -3,6 +3,7 @@ import { getAgentInstructions } from "./shared-prompt.js";
3
3
  import { SHELL } from "../platform/index.js";
4
4
  export class KimiAgent {
5
5
  supportsPermissions = false;
6
+ supportsYolo = true;
6
7
  getPromptCommandLine(prompt) {
7
8
  return { command: "kimi", args: ["-p", prompt] };
8
9
  }
@@ -2,6 +2,7 @@ import type { ParsedTask, RequiredPermission } from "../types.js";
2
2
  import type { AgentTool, CommandLine } from "./agent.js";
3
3
  export declare class Kiro implements AgentTool {
4
4
  supportsPermissions: boolean;
5
+ supportsYolo: boolean;
5
6
  getPromptCommandLine(prompt: string): CommandLine;
6
7
  getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[] | "yolo"): CommandLine;
7
8
  init(): Promise<boolean>;
@@ -3,6 +3,7 @@ import { getAgentInstructions } from "./shared-prompt.js";
3
3
  import { SHELL } from "../platform/index.js";
4
4
  export class Kiro {
5
5
  supportsPermissions = false;
6
+ supportsYolo = true;
6
7
  getPromptCommandLine(prompt) {
7
8
  return { command: "kiro-cli", args: ["--no-interactive", prompt] };
8
9
  }
@@ -2,6 +2,7 @@ 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
4
  supportsPermissions: boolean;
5
+ supportsYolo: boolean;
5
6
  getPromptCommandLine(prompt: string): CommandLine;
6
7
  getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[] | "yolo"): CommandLine;
7
8
  init(): Promise<boolean>;
@@ -2,12 +2,12 @@ import { execSync } from "child_process";
2
2
  import { getAgentInstructions } from "./shared-prompt.js";
3
3
  export class OpenClawAgent {
4
4
  supportsPermissions = false;
5
+ supportsYolo = false;
5
6
  getPromptCommandLine(prompt) {
6
7
  return { command: "openclaw", args: ["agent", "--local", "--agent", "main", "--message", prompt] };
7
8
  }
8
9
  getTaskRunCommandLine(task, followupPrompt, extraPermissions) {
9
- const yolo = extraPermissions === "yolo";
10
- const prompt = followupPrompt ?? getAgentInstructions(task, yolo || !this.supportsPermissions);
10
+ const prompt = followupPrompt ?? getAgentInstructions(task, true);
11
11
  // OpenClaw does not support stdin as prompt.
12
12
  const args = ["agent", "--local", "--session-id", task.frontmatter.id, "--message", prompt];
13
13
  return { command: "openclaw", args };
@@ -2,6 +2,7 @@ import type { ParsedTask, RequiredPermission } from "../types.js";
2
2
  import type { AgentTool, CommandLine } from "./agent.js";
3
3
  export declare class OpenCodeAgent implements AgentTool {
4
4
  supportsPermissions: boolean;
5
+ supportsYolo: boolean;
5
6
  getPromptCommandLine(prompt: string): CommandLine;
6
7
  getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[] | "yolo"): CommandLine;
7
8
  init(): Promise<boolean>;
@@ -3,6 +3,7 @@ import { getAgentInstructions } from "./shared-prompt.js";
3
3
  import { SHELL } from "../platform/index.js";
4
4
  export class OpenCodeAgent {
5
5
  supportsPermissions = false;
6
+ supportsYolo = true;
6
7
  getPromptCommandLine(prompt) {
7
8
  return { command: "opencode", args: ["run", prompt] };
8
9
  }
@@ -2,6 +2,7 @@ import type { ParsedTask, RequiredPermission } from "../types.js";
2
2
  import type { AgentTool, CommandLine } from "./agent.js";
3
3
  export declare class Qoder implements AgentTool {
4
4
  supportsPermissions: boolean;
5
+ supportsYolo: boolean;
5
6
  getPromptCommandLine(prompt: string): CommandLine;
6
7
  getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[] | "yolo"): CommandLine;
7
8
  init(): Promise<boolean>;
@@ -3,6 +3,7 @@ import { getAgentInstructions } from "./shared-prompt.js";
3
3
  import { SHELL } from "../platform/index.js";
4
4
  export class Qoder {
5
5
  supportsPermissions = false;
6
+ supportsYolo = true;
6
7
  getPromptCommandLine(prompt) {
7
8
  return { command: "qodercli", args: ["-p", prompt] };
8
9
  }
@@ -2,6 +2,7 @@ import type { ParsedTask, RequiredPermission } from "../types.js";
2
2
  import type { AgentTool, CommandLine } from "./agent.js";
3
3
  export declare class QwenAgent implements AgentTool {
4
4
  supportsPermissions: boolean;
5
+ supportsYolo: boolean;
5
6
  getPromptCommandLine(prompt: string): CommandLine;
6
7
  getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[] | "yolo"): CommandLine;
7
8
  init(): Promise<boolean>;
@@ -3,6 +3,7 @@ import { getAgentInstructions } from "./shared-prompt.js";
3
3
  import { SHELL } from "../platform/index.js";
4
4
  export class QwenAgent {
5
5
  supportsPermissions = false;
6
+ supportsYolo = true;
6
7
  getPromptCommandLine(prompt) {
7
8
  return { command: "qwen", args: ["-p", prompt] };
8
9
  }
@@ -5,7 +5,7 @@ import { connectNats } from "../nats-client.js";
5
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
- export const PAIRING_EXPIRY_MS = 5 * 60 * 1000; // 5 minutes
8
+ export const PAIRING_EXPIRY_MS = 60 * 1000; // 1 minute
9
9
  export function generatePairingCode() {
10
10
  const bytes = new Uint8Array(CODE_LENGTH);
11
11
  crypto.getRandomValues(bytes);
@@ -69,7 +69,7 @@ export async function pairCommand() {
69
69
  console.log("");
70
70
  console.log(` ${code}`);
71
71
  console.log("");
72
- console.log("Code expires in 5 minutes.");
72
+ console.log("Code expires in 1 minute.");
73
73
  // NATS pairing (server mode)
74
74
  const nc = await connectNats(config);
75
75
  const sc = StringCodec();
@@ -32,6 +32,8 @@ export interface ResourceDefinition {
32
32
  restPath: string;
33
33
  /** Return the current resource content. */
34
34
  read: () => unknown;
35
+ /** Register a listener for content changes. Returns an unsubscribe function. */
36
+ subscribe: (listener: () => void) => () => void;
35
37
  }
36
38
  export declare const agentResources: ResourceDefinition[];
37
39
  export declare const agentResourceMap: Map<string, ResourceDefinition>;
package/dist/mcp-tools.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import { StringCodec } from "nats";
2
2
  import { registerPending } from "./pending-requests.js";
3
3
  import { getCapabilityDevice } from "./device-capabilities.js";
4
- import { getNotifications } from "./notification-store.js";
5
- import { getSmsMessages } from "./sms-store.js";
4
+ import { getNotifications, onNotificationsChanged } from "./notification-store.js";
5
+ import { getSmsMessages, onSmsChanged } from "./sms-store.js";
6
6
  export class ToolError extends Error {
7
7
  statusCode;
8
8
  constructor(message, statusCode = 500) {
@@ -50,7 +50,7 @@ const requestInputTool = {
50
50
  "Request input from the user.",
51
51
  "The request blocks until the user responds.",
52
52
  'Response: `{"values": ["answer1", "answer2"]}` on success, or `{"aborted": true}` if the user declines.',
53
- "When you need information from the user (credentials, answers to questions, preferences, clarifications, etc.), do not guess, fail, or prompt via stdout, even in a non-interactive environment — use this endpoint instead.",
53
+ "When you need information from the user (credentials, answers to questions, preferences, clarifications, etc.), do not guess, fail, or prompt via stdout, even in a non-interactive environment — use this instead.",
54
54
  ],
55
55
  inputSchema: {
56
56
  type: "object",
@@ -69,12 +69,17 @@ const requestInputTool = {
69
69
  const { description, questions } = args;
70
70
  if (!questions?.length)
71
71
  throw new ToolError("questions is required", 400);
72
- const pendingPromise = registerPending(ctx.sessionId, "input", questions);
72
+ const pendingPromise = registerPending(ctx.sessionId, "input", questions, {
73
+ session_id: ctx.sessionId,
74
+ session_name: ctx.agentName,
75
+ description,
76
+ input_questions: questions,
77
+ });
73
78
  await ctx.publishEvent("_input", {
74
79
  event_type: "input-request",
75
80
  host_id: ctx.config.hostId,
76
81
  session_id: ctx.sessionId,
77
- agent_name: ctx.agentName,
82
+ session_name: ctx.agentName,
78
83
  description,
79
84
  input_questions: questions,
80
85
  });
@@ -111,12 +116,16 @@ const requestConfirmationTool = {
111
116
  const { description } = args;
112
117
  if (!description)
113
118
  throw new ToolError("description is required", 400);
114
- const pendingPromise = registerPending(ctx.sessionId, "confirmation");
119
+ const pendingPromise = registerPending(ctx.sessionId, "confirmation", undefined, {
120
+ session_id: ctx.sessionId,
121
+ session_name: ctx.agentName,
122
+ description,
123
+ });
115
124
  await ctx.publishEvent("_confirm", {
116
125
  event_type: "confirm-request",
117
126
  host_id: ctx.config.hostId,
118
127
  session_id: ctx.sessionId,
119
- agent_name: ctx.agentName,
128
+ session_name: ctx.agentName,
120
129
  description,
121
130
  });
122
131
  const response = await pendingPromise;
@@ -134,7 +143,7 @@ const deviceGeolocationTool = {
134
143
  name: "device-geolocation",
135
144
  description: [
136
145
  "Get the GPS location of the user's mobile device.",
137
- "When you need the user's real-time location, use this endpoint.",
146
+ "When you need the user's real-time location, use this.",
138
147
  "Blocks until the device responds (up to 30 seconds).",
139
148
  'Response: `{"latitude": ..., "longitude": ..., "accuracy": ..., "timestamp": ...}` on success, or `{"error": "..."}` on failure.',
140
149
  ],
@@ -571,7 +580,7 @@ const sendEmailTool = {
571
580
  name: "send-email",
572
581
  description: [
573
582
  "Send an email from the user's mobile device.",
574
- "When you need to send an email, use this tool. The email app opens on the device with the draft pre-filled for the user to review and send.",
583
+ "When you need to send an email, use this. The email app opens on the device with the draft pre-filled for the user to review and send.",
575
584
  'Response: `{"ok": true}` on success, or `{"error": "..."}` on failure.',
576
585
  ],
577
586
  inputSchema: {
@@ -642,6 +651,7 @@ const deviceNotificationsResource = {
642
651
  mimeType: "application/json",
643
652
  restPath: "/notifications",
644
653
  read: getNotifications,
654
+ subscribe: onNotificationsChanged,
645
655
  };
646
656
  const deviceSmsResource = {
647
657
  uri: "sms-messages://device",
@@ -653,6 +663,7 @@ const deviceSmsResource = {
653
663
  mimeType: "application/json",
654
664
  restPath: "/sms-messages",
655
665
  read: getSmsMessages,
666
+ subscribe: onSmsChanged,
656
667
  };
657
668
  export const agentResources = [deviceNotificationsResource, deviceSmsResource];
658
669
  export const agentResourceMap = new Map(agentResources.map((r) => [r.uri, r]));
@@ -1,27 +1,49 @@
1
1
  import type { RequiredPermission } from "./types.js";
2
+ export interface PendingRequestMeta {
3
+ /** Doubles as task_id for permission-type entries (the key the task uses). */
4
+ session_id?: string;
5
+ /** Human-readable label for whoever opened the prompt — agent name for
6
+ * confirm/input, task name for permission. */
7
+ session_name?: string;
8
+ description?: string;
9
+ input_questions?: string[];
10
+ }
2
11
  export interface PendingRequest {
3
12
  type: "confirmation" | "permission" | "input";
4
13
  resolve: (value: string[]) => void;
5
14
  /** Permission list (for 'permission') or input descriptions (for 'input'). */
6
15
  params?: RequiredPermission[] | string[];
16
+ /** Display context for PWAs that connect while this request is already open. */
17
+ meta?: PendingRequestMeta;
7
18
  }
8
19
  /**
9
- * Register a pending request for a task. Returns a Promise that resolves
10
- * when `resolvePending` is called with the user's response.
11
- * Only one pending request per task at a time.
20
+ * Register a pending request keyed by either a sessionId (confirmation / input)
21
+ * or a taskId (permission). The `meta` is surfaced to PWAs that connect after
22
+ * the request was opened, so their modals can render without replaying events.
23
+ * Only one pending request per key at a time.
12
24
  */
13
- export declare function registerPending(taskId: string, type: PendingRequest["type"], params?: PendingRequest["params"]): Promise<string[]>;
25
+ export declare function registerPending(key: string, type: PendingRequest["type"], params?: PendingRequest["params"], meta?: PendingRequestMeta): Promise<string[]>;
14
26
  /**
15
27
  * Resolve a pending request with the user's response.
16
28
  * Returns true if a pending request was found and resolved.
17
29
  */
18
- export declare function resolvePending(taskId: string, value: string[]): boolean;
30
+ export declare function resolvePending(key: string, value: string[]): boolean;
19
31
  /**
20
- * Get the current pending request for a task (if any).
32
+ * Get the current pending request for a key (if any).
21
33
  */
22
- export declare function getPending(taskId: string): PendingRequest | undefined;
34
+ export declare function getPending(key: string): PendingRequest | undefined;
23
35
  /**
24
36
  * Remove a pending request without resolving it.
25
37
  */
26
- export declare function removePending(taskId: string): void;
38
+ export declare function removePending(key: string): void;
39
+ /**
40
+ * List all currently-pending requests, stripped of the unserializable `resolve`
41
+ * callback. Used by `host.info` so the PWA can seed its modal state on connect.
42
+ */
43
+ export declare function listPending(): Array<{
44
+ key: string;
45
+ type: PendingRequest["type"];
46
+ params?: PendingRequest["params"];
47
+ meta?: PendingRequestMeta;
48
+ }>;
27
49
  //# sourceMappingURL=pending-requests.d.ts.map
@@ -1,39 +1,52 @@
1
1
  const pending = new Map();
2
2
  /**
3
- * Register a pending request for a task. Returns a Promise that resolves
4
- * when `resolvePending` is called with the user's response.
5
- * Only one pending request per task at a time.
3
+ * Register a pending request keyed by either a sessionId (confirmation / input)
4
+ * or a taskId (permission). The `meta` is surfaced to PWAs that connect after
5
+ * the request was opened, so their modals can render without replaying events.
6
+ * Only one pending request per key at a time.
6
7
  */
7
- export function registerPending(taskId, type, params) {
8
- if (pending.has(taskId)) {
9
- return Promise.reject(new Error(`Task ${taskId} already has a pending request`));
8
+ export function registerPending(key, type, params, meta) {
9
+ if (pending.has(key)) {
10
+ return Promise.reject(new Error(`Key ${key} already has a pending request`));
10
11
  }
11
12
  return new Promise((resolve) => {
12
- pending.set(taskId, { type, resolve, params });
13
+ pending.set(key, { type, resolve, params, meta });
13
14
  });
14
15
  }
15
16
  /**
16
17
  * Resolve a pending request with the user's response.
17
18
  * Returns true if a pending request was found and resolved.
18
19
  */
19
- export function resolvePending(taskId, value) {
20
- const entry = pending.get(taskId);
20
+ export function resolvePending(key, value) {
21
+ const entry = pending.get(key);
21
22
  if (!entry)
22
23
  return false;
23
- pending.delete(taskId);
24
+ pending.delete(key);
24
25
  entry.resolve(value);
25
26
  return true;
26
27
  }
27
28
  /**
28
- * Get the current pending request for a task (if any).
29
+ * Get the current pending request for a key (if any).
29
30
  */
30
- export function getPending(taskId) {
31
- return pending.get(taskId);
31
+ export function getPending(key) {
32
+ return pending.get(key);
32
33
  }
33
34
  /**
34
35
  * Remove a pending request without resolving it.
35
36
  */
36
- export function removePending(taskId) {
37
- pending.delete(taskId);
37
+ export function removePending(key) {
38
+ pending.delete(key);
39
+ }
40
+ /**
41
+ * List all currently-pending requests, stripped of the unserializable `resolve`
42
+ * callback. Used by `host.info` so the PWA can seed its modal state on connect.
43
+ */
44
+ export function listPending() {
45
+ return [...pending.entries()].map(([key, entry]) => ({
46
+ key,
47
+ type: entry.type,
48
+ params: entry.params,
49
+ meta: entry.meta,
50
+ }));
38
51
  }
39
52
  //# sourceMappingURL=pending-requests.js.map