@camerontaylor/paseo-cli 0.8.0-fork.1 → 0.8.0-fork.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.
Files changed (120) hide show
  1. package/dist/cli.js +25 -37
  2. package/dist/commands/agent/archive.js +2 -15
  3. package/dist/commands/agent/attach.d.ts +1 -0
  4. package/dist/commands/agent/attach.js +8 -12
  5. package/dist/commands/agent/delete.js +4 -15
  6. package/dist/commands/agent/detach.js +2 -13
  7. package/dist/commands/agent/import.js +2 -16
  8. package/dist/commands/agent/inspect.js +2 -15
  9. package/dist/commands/agent/logs.js +12 -12
  10. package/dist/commands/agent/ls.js +2 -23
  11. package/dist/commands/agent/mode.js +2 -2
  12. package/dist/commands/agent/open.js +2 -8
  13. package/dist/commands/agent/reload.js +2 -15
  14. package/dist/commands/agent/run.js +11 -16
  15. package/dist/commands/agent/send.js +6 -15
  16. package/dist/commands/agent/stop.js +2 -15
  17. package/dist/commands/agent/update.js +2 -15
  18. package/dist/commands/agent/wait.js +4 -15
  19. package/dist/commands/clone.js +2 -8
  20. package/dist/commands/daemon/config.d.ts +3 -0
  21. package/dist/commands/daemon/config.js +102 -0
  22. package/dist/commands/daemon/index.js +20 -52
  23. package/dist/commands/daemon/local-daemon.d.ts +10 -75
  24. package/dist/commands/daemon/local-daemon.js +61 -503
  25. package/dist/commands/daemon/pair.d.ts +3 -8
  26. package/dist/commands/daemon/pair.js +31 -61
  27. package/dist/commands/daemon/reload.d.ts +3 -1
  28. package/dist/commands/daemon/reload.js +10 -2
  29. package/dist/commands/daemon/restart.d.ts +19 -11
  30. package/dist/commands/daemon/restart.js +102 -88
  31. package/dist/commands/daemon/set-password.js +6 -7
  32. package/dist/commands/daemon/start.d.ts +17 -3
  33. package/dist/commands/daemon/start.js +47 -52
  34. package/dist/commands/daemon/status.d.ts +12 -20
  35. package/dist/commands/daemon/status.js +90 -342
  36. package/dist/commands/daemon/stop.d.ts +19 -14
  37. package/dist/commands/daemon/stop.js +53 -55
  38. package/dist/commands/heartbeat/index.js +3 -3
  39. package/dist/commands/hub/connect.d.ts +1 -0
  40. package/dist/commands/hub/connect.js +1 -1
  41. package/dist/commands/hub/daemon-client.d.ts +3 -2
  42. package/dist/commands/hub/daemon-client.js +3 -3
  43. package/dist/commands/hub/disconnect.d.ts +1 -0
  44. package/dist/commands/hub/disconnect.js +1 -1
  45. package/dist/commands/hub/index.js +2 -2
  46. package/dist/commands/hub/init.d.ts +3 -1
  47. package/dist/commands/hub/init.js +13 -12
  48. package/dist/commands/hub/login.d.ts +4 -4
  49. package/dist/commands/hub/login.js +1 -1
  50. package/dist/commands/hub/logout.d.ts +1 -0
  51. package/dist/commands/hub/logout.js +2 -2
  52. package/dist/commands/hub/permissions.d.ts +1 -0
  53. package/dist/commands/hub/permissions.js +2 -2
  54. package/dist/commands/onboard.d.ts +7 -2
  55. package/dist/commands/onboard.js +58 -210
  56. package/dist/commands/open.js +2 -0
  57. package/dist/commands/permit/allow.js +2 -15
  58. package/dist/commands/permit/deny.js +2 -15
  59. package/dist/commands/permit/ls.js +2 -15
  60. package/dist/commands/plugin/index.js +7 -7
  61. package/dist/commands/plugin/shared.d.ts +4 -3
  62. package/dist/commands/plugin/shared.js +8 -8
  63. package/dist/commands/project/create.js +5 -3
  64. package/dist/commands/project/delete.js +4 -2
  65. package/dist/commands/project/ls.js +2 -2
  66. package/dist/commands/project/rename.js +4 -2
  67. package/dist/commands/provider/add.js +2 -2
  68. package/dist/commands/provider/diagnostic.js +1 -1
  69. package/dist/commands/provider/ls.js +2 -30
  70. package/dist/commands/provider/models.js +1 -1
  71. package/dist/commands/provider/rm.js +2 -2
  72. package/dist/commands/schedule/create.js +2 -2
  73. package/dist/commands/schedule/delete.js +1 -1
  74. package/dist/commands/schedule/inspect.js +1 -1
  75. package/dist/commands/schedule/logs.js +1 -1
  76. package/dist/commands/schedule/ls.js +1 -1
  77. package/dist/commands/schedule/pause.js +1 -1
  78. package/dist/commands/schedule/resume.js +1 -1
  79. package/dist/commands/schedule/run-once.js +1 -1
  80. package/dist/commands/schedule/shared.d.ts +3 -1
  81. package/dist/commands/schedule/shared.js +7 -5
  82. package/dist/commands/schedule/update.js +1 -1
  83. package/dist/commands/script/ls.js +1 -1
  84. package/dist/commands/script/shared.d.ts +2 -1
  85. package/dist/commands/script/shared.js +3 -3
  86. package/dist/commands/script/start.js +1 -1
  87. package/dist/commands/script/stop.js +1 -1
  88. package/dist/commands/terminal/capture.d.ts +1 -1
  89. package/dist/commands/terminal/capture.js +2 -3
  90. package/dist/commands/terminal/create.js +1 -1
  91. package/dist/commands/terminal/kill.js +1 -1
  92. package/dist/commands/terminal/ls.js +1 -1
  93. package/dist/commands/terminal/send-keys.d.ts +1 -1
  94. package/dist/commands/terminal/send-keys.js +2 -3
  95. package/dist/commands/terminal/shared.d.ts +2 -1
  96. package/dist/commands/terminal/shared.js +5 -3
  97. package/dist/commands/workspace/archive.d.ts +1 -0
  98. package/dist/commands/workspace/archive.js +4 -2
  99. package/dist/commands/workspace/create.js +4 -2
  100. package/dist/commands/workspace/ls.d.ts +1 -0
  101. package/dist/commands/workspace/ls.js +2 -2
  102. package/dist/commands/workspace/rename.d.ts +1 -0
  103. package/dist/commands/workspace/rename.js +4 -2
  104. package/dist/commands/workspace/setup.d.ts +1 -0
  105. package/dist/commands/workspace/setup.js +2 -2
  106. package/dist/commands/worktree/archive.js +4 -2
  107. package/dist/commands/worktree/create.js +2 -10
  108. package/dist/commands/worktree/ls.d.ts +0 -2
  109. package/dist/commands/worktree/ls.js +4 -30
  110. package/dist/output/with-output.d.ts +2 -0
  111. package/dist/run.js +11 -1
  112. package/dist/utils/client-id.d.ts +1 -1
  113. package/dist/utils/client-id.js +8 -14
  114. package/dist/utils/client.d.ts +16 -21
  115. package/dist/utils/client.js +57 -109
  116. package/dist/utils/command-options.d.ts +1 -0
  117. package/dist/utils/command-options.js +24 -2
  118. package/dist/utils/daemon-target.d.ts +13 -0
  119. package/dist/utils/daemon-target.js +51 -0
  120. package/package.json +8 -4
package/dist/cli.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { pairCommand } from "./commands/daemon/pair.js";
1
2
  import { Command, Option } from "commander";
2
3
  import { createAgentCommand } from "./commands/agent/index.js";
3
4
  import { createDaemonCommand } from "./commands/daemon/index.js";
@@ -15,9 +16,9 @@ import { createHeartbeatCommand } from "./commands/heartbeat/index.js";
15
16
  import { createHubCommand } from "./commands/hub/index.js";
16
17
  import { createHooksCommand } from "./commands/hooks.js";
17
18
  import { startCommand as daemonStartCommand } from "./commands/daemon/start.js";
18
- import { runStatusCommand as runDaemonStatusCommand } from "./commands/daemon/status.js";
19
- import { runRestartCommand as runDaemonRestartCommand } from "./commands/daemon/restart.js";
20
- import { runDaemonReloadCommand } from "./commands/daemon/reload.js";
19
+ import { daemonStatusCommand } from "./commands/daemon/status.js";
20
+ import { daemonRestartCommand } from "./commands/daemon/restart.js";
21
+ import { daemonReloadCommand } from "./commands/daemon/reload.js";
21
22
  import { addLsOptions, runLsCommand } from "./commands/agent/ls.js";
22
23
  import { addRunOptions, runRunCommand } from "./commands/agent/run.js";
23
24
  import { addLogsOptions, runLogsCommand } from "./commands/agent/logs.js";
@@ -32,16 +33,9 @@ import { addImportOptions, runImportCommand } from "./commands/agent/import.js";
32
33
  import { withOutput } from "./output/index.js";
33
34
  import { runCloneCommand } from "./commands/clone.js";
34
35
  import { onboardCommand } from "./commands/onboard.js";
35
- import { addDaemonHostOption, addJsonAndDaemonHostOptions, addJsonOption, withGlobalOptions, } from "./utils/command-options.js";
36
+ import { addDaemonHostOption, addJsonAndDaemonHostOptions, withGlobalOptions, } from "./utils/command-options.js";
36
37
  import { resolveCliVersion } from "./version.js";
37
38
  const VERSION = resolveCliVersion();
38
- function resolveHostnamesOption(hostnames, allowedHosts) {
39
- if (typeof hostnames === "string")
40
- return hostnames;
41
- if (typeof allowedHosts === "string")
42
- return allowedHosts;
43
- return undefined;
44
- }
45
39
  export function createCli() {
46
40
  const program = new Command();
47
41
  program
@@ -78,32 +72,10 @@ export function createCli() {
78
72
  program.addCommand(onboardCommand());
79
73
  program.addCommand(daemonStartCommand());
80
74
  program.addCommand(createHooksCommand());
81
- addJsonOption(program
82
- .command("status")
83
- .description('Show local daemon status (alias for "paseo daemon status")'))
84
- .option("--home <path>", "Paseo home directory (default: ~/.paseo)")
85
- .action(withOutput(runDaemonStatusCommand));
86
- addJsonAndDaemonHostOptions(program.command("reload").description('Reload daemon config (alias for "paseo daemon reload")')).action(withOutput(runDaemonReloadCommand));
87
- addJsonOption(program
88
- .command("restart")
89
- .description('Restart local daemon (alias for "paseo daemon restart")'))
90
- .option("--home <path>", "Paseo home directory (default: ~/.paseo)")
91
- .option("--timeout <seconds>", "Wait timeout before force step (default: 15)")
92
- .option("--force", "Send SIGKILL if graceful stop times out")
93
- .option("--listen <listen>", "Listen target for restarted daemon (host:port, port, or unix socket)")
94
- .option("--port <port>", "Port for restarted daemon listen target")
95
- .option("--relay", "Enable relay on restarted daemon")
96
- .option("--no-relay", "Disable relay on restarted daemon")
97
- .option("--no-mcp", "Disable Agent MCP on restarted daemon")
98
- .option("--hostnames <hosts>", 'Daemon hostnames (comma-separated, e.g. "myhost,.example.com" or "true" for any)')
99
- .addOption(new Option("--allowed-hosts <hosts>").hideHelp())
100
- .action(withOutput((...args) => {
101
- const [options, command] = args.slice(-2);
102
- return runDaemonRestartCommand({
103
- ...options,
104
- hostnames: resolveHostnamesOption(options.hostnames, options.allowedHosts),
105
- }, command);
106
- }));
75
+ program.addCommand(daemonStatusCommand());
76
+ program.addCommand(daemonRestartCommand());
77
+ program.addCommand(daemonReloadCommand());
78
+ program.addCommand(pairCommand());
107
79
  // Advanced agent commands (less common operations)
108
80
  program.addCommand(createAgentCommand());
109
81
  // Daemon commands
@@ -130,6 +102,22 @@ export function createCli() {
130
102
  // COMPAT(worktreeCli): legacy command alias added before workspace was the product unit.
131
103
  // Added in v0.2.0; remove after 2027-01-17.
132
104
  program.addCommand(createWorktreeCommand(), { hidden: true });
105
+ const enforceSelectorDuplicates = (command) => {
106
+ for (const option of command.options) {
107
+ if (option.long !== "--home" && option.long !== "--host")
108
+ continue;
109
+ option.argParser((value, previous) => {
110
+ if (previous !== undefined && previous !== value)
111
+ throw {
112
+ code: "TARGET_AMBIGUOUS",
113
+ message: `Conflicting duplicate ${option.long} selectors.`,
114
+ };
115
+ return value;
116
+ });
117
+ }
118
+ command.commands.forEach(enforceSelectorDuplicates);
119
+ };
120
+ enforceSelectorDuplicates(program);
133
121
  return program;
134
122
  }
135
123
  //# sourceMappingURL=cli.js.map
@@ -1,4 +1,4 @@
1
- import { connectToDaemon, getDaemonHost, resolveAgentId } from "../../utils/client.js";
1
+ import { connectToDaemon, resolveAgentId } from "../../utils/client.js";
2
2
  /** Schema for archive command output */
3
3
  export const archiveSchema = {
4
4
  idField: "agentId",
@@ -15,7 +15,6 @@ export function addArchiveOptions(cmd) {
15
15
  .option("--force", "Force archive running agent (interrupts active run first)");
16
16
  }
17
17
  export async function runArchiveCommand(agentIdArg, options, _command) {
18
- const host = getDaemonHost({ host: options.host });
19
18
  // Validate arguments
20
19
  if (!agentIdArg || agentIdArg.trim().length === 0) {
21
20
  const error = {
@@ -25,19 +24,7 @@ export async function runArchiveCommand(agentIdArg, options, _command) {
25
24
  };
26
25
  throw error;
27
26
  }
28
- let client;
29
- try {
30
- client = await connectToDaemon({ host: options.host });
31
- }
32
- catch (err) {
33
- const message = err instanceof Error ? err.message : String(err);
34
- const error = {
35
- code: "DAEMON_NOT_RUNNING",
36
- message: `Cannot connect to daemon at ${host}: ${message}`,
37
- details: "Start the daemon with: paseo daemon start",
38
- };
39
- throw error;
40
- }
27
+ const client = await connectToDaemon({ target: options.daemonTarget });
41
28
  try {
42
29
  const agentsPayload = await client.fetchAgents({ filter: { includeArchived: true } });
43
30
  const agents = agentsPayload.entries.map((entry) => entry.agent);
@@ -2,6 +2,7 @@ import type { Command } from "commander";
2
2
  export declare function addAttachOptions(cmd: Command): Command;
3
3
  export interface AgentAttachOptions {
4
4
  host?: string;
5
+ daemonTarget: import("../../utils/daemon-target.js").DaemonTarget;
5
6
  [key: string]: unknown;
6
7
  }
7
8
  /**
@@ -3,7 +3,7 @@ export function addAttachOptions(cmd) {
3
3
  .description("Attach to a running agent's output stream")
4
4
  .argument("<id>", "Agent ID (or prefix)");
5
5
  }
6
- import { connectToDaemon, getDaemonHost } from "../../utils/client.js";
6
+ import { connectToDaemon } from "../../utils/client.js";
7
7
  import { fetchProjectedTimelineItems, LIVE_HISTORY_FETCH_TIMEOUT_MS, } from "../../utils/timeline.js";
8
8
  /**
9
9
  * Format and print a timeline item to the terminal
@@ -74,22 +74,12 @@ function printStreamEvent(event) {
74
74
  * Attach to a running agent's output stream
75
75
  */
76
76
  export async function runAttachCommand(id, options, _command) {
77
- const host = getDaemonHost({ host: options.host });
78
77
  if (!id) {
79
78
  console.error("Error: Agent ID required");
80
79
  console.error("Usage: paseo attach <id>");
81
80
  process.exit(1);
82
81
  }
83
- let client;
84
- try {
85
- client = await connectToDaemon({ host: options.host });
86
- }
87
- catch (err) {
88
- const message = err instanceof Error ? err.message : String(err);
89
- console.error(`Error: Cannot connect to daemon at ${host}: ${message}`);
90
- console.error("Start the daemon with: paseo daemon start");
91
- process.exit(1);
92
- }
82
+ const client = await connectToDaemon({ target: options.daemonTarget });
93
83
  try {
94
84
  const fetchResult = await client.fetchAgent({ agentId: id });
95
85
  if (!fetchResult) {
@@ -121,6 +111,12 @@ export async function runAttachCommand(id, options, _command) {
121
111
  if (message.type === "agent.timeline.replacement") {
122
112
  console.log("\n[Timeline replaced; earlier output is no longer current]");
123
113
  }
114
+ else if (message.type === "agent.timeline.subscription_restored") {
115
+ console.log("\n[Reconnected; live output resumed. Events may have been missed.]");
116
+ }
117
+ else if (message.type === "agent.timeline.error") {
118
+ console.error(`Timeline observation stopped: ${message.payload.error}`);
119
+ }
124
120
  else {
125
121
  printStreamEvent(message.payload.event);
126
122
  }
@@ -1,4 +1,4 @@
1
- import { connectToDaemon, getDaemonHost } from "../../utils/client.js";
1
+ import { connectToDaemon } from "../../utils/client.js";
2
2
  import { isSameOrDescendantPath } from "../../utils/paths.js";
3
3
  export function addDeleteOptions(cmd) {
4
4
  return cmd
@@ -12,7 +12,6 @@ export const deleteSchema = {
12
12
  columns: [{ header: "DELETED", field: "deletedCount" }],
13
13
  };
14
14
  export async function runDeleteCommand(id, options, _command) {
15
- const host = getDaemonHost({ host: options.host });
16
15
  if (!id && !options.all && !options.cwd) {
17
16
  const error = {
18
17
  code: "MISSING_ARGUMENT",
@@ -21,19 +20,7 @@ export async function runDeleteCommand(id, options, _command) {
21
20
  };
22
21
  throw error;
23
22
  }
24
- let client;
25
- try {
26
- client = await connectToDaemon({ host: options.host });
27
- }
28
- catch (err) {
29
- const message = err instanceof Error ? err.message : String(err);
30
- const error = {
31
- code: "DAEMON_NOT_RUNNING",
32
- message: `Cannot connect to daemon at ${host}: ${message}`,
33
- details: "Start the daemon with: paseo daemon start",
34
- };
35
- throw error;
36
- }
23
+ const client = await connectToDaemon({ target: options.daemonTarget });
37
24
  try {
38
25
  const fetchPayload = await client.fetchAgents({ filter: { includeArchived: true } });
39
26
  let agents = fetchPayload.entries.map((entry) => entry.agent);
@@ -69,6 +56,8 @@ export async function runDeleteCommand(id, options, _command) {
69
56
  return { ok: true, id: agent.id };
70
57
  }
71
58
  catch (err) {
59
+ if (err && typeof err === "object" && "code" in err)
60
+ throw err;
72
61
  const message = err instanceof Error ? err.message : String(err);
73
62
  return { ok: false, id: agent.id, message };
74
63
  }
@@ -1,4 +1,4 @@
1
- import { connectToDaemon, getDaemonHost, resolveAgentId } from "../../utils/client.js";
1
+ import { connectToDaemon, resolveAgentId } from "../../utils/client.js";
2
2
  const detachSchema = {
3
3
  idField: "agentId",
4
4
  columns: [
@@ -7,18 +7,7 @@ const detachSchema = {
7
7
  ],
8
8
  };
9
9
  export async function runDetachCommand(agentIdArg, options, _command) {
10
- const host = getDaemonHost({ host: options.host });
11
- let client;
12
- try {
13
- client = await connectToDaemon({ host: options.host });
14
- }
15
- catch (error) {
16
- const message = error instanceof Error ? error.message : String(error);
17
- throw {
18
- code: "DAEMON_NOT_RUNNING",
19
- message: `Cannot connect to daemon at ${host}: ${message}`,
20
- };
21
- }
10
+ const client = await connectToDaemon({ target: options.daemonTarget });
22
11
  try {
23
12
  const payload = await client.fetchAgents({ filter: { includeArchived: true } });
24
13
  const agentId = resolveAgentId(agentIdArg, payload.entries.map((entry) => entry.agent));
@@ -1,4 +1,4 @@
1
- import { connectToDaemon, getDaemonHost } from "../../utils/client.js";
1
+ import { connectToDaemon } from "../../utils/client.js";
2
2
  import { collectMultiple } from "../../utils/command-options.js";
3
3
  import { agentRunSchema } from "./run.js";
4
4
  export function addImportOptions(cmd) {
@@ -66,21 +66,7 @@ export function resolveImportCwd(explicitCwd, defaultCwd) {
66
66
  }
67
67
  return cwd;
68
68
  }
69
- async function connectToDaemonOrThrow(hostOption, host) {
70
- try {
71
- return await connectToDaemon({ host: hostOption });
72
- }
73
- catch (err) {
74
- const message = err instanceof Error ? err.message : String(err);
75
- throw {
76
- code: "DAEMON_NOT_RUNNING",
77
- message: `Cannot connect to daemon at ${host}: ${message}`,
78
- details: "Start the daemon with: paseo daemon start",
79
- };
80
- }
81
- }
82
69
  export async function runImportCommand(sessionIdArg, options, _command) {
83
- const host = getDaemonHost({ host: options.host });
84
70
  const sessionId = sessionIdArg.trim();
85
71
  if (!sessionId) {
86
72
  throw {
@@ -92,7 +78,7 @@ export async function runImportCommand(sessionIdArg, options, _command) {
92
78
  const provider = parseImportProvider(options.provider);
93
79
  const cwd = resolveImportCwd(options.cwd, process.cwd());
94
80
  const labels = parseImportLabels(options.label);
95
- const client = await connectToDaemonOrThrow(options.host, host);
81
+ const client = await connectToDaemon({ target: options.daemonTarget });
96
82
  try {
97
83
  const agent = await client.importAgent({
98
84
  provider,
@@ -1,5 +1,5 @@
1
1
  import { PARENT_AGENT_ID_LABEL } from "@camerontaylor/paseo-protocol/agent-labels";
2
- import { connectToDaemon, getDaemonHost } from "../../utils/client.js";
2
+ import { connectToDaemon } from "../../utils/client.js";
3
3
  export function addInspectOptions(cmd) {
4
4
  return cmd
5
5
  .description("Show detailed information about an agent")
@@ -151,7 +151,6 @@ function toInspectRows(agent) {
151
151
  return rows;
152
152
  }
153
153
  export async function runInspectCommand(agentIdArg, options, _command) {
154
- const host = getDaemonHost({ host: options.host });
155
154
  // Validate arguments
156
155
  if (!agentIdArg || agentIdArg.trim().length === 0) {
157
156
  const error = {
@@ -161,19 +160,7 @@ export async function runInspectCommand(agentIdArg, options, _command) {
161
160
  };
162
161
  throw error;
163
162
  }
164
- let client;
165
- try {
166
- client = await connectToDaemon({ host: options.host });
167
- }
168
- catch (err) {
169
- const message = err instanceof Error ? err.message : String(err);
170
- const error = {
171
- code: "DAEMON_NOT_RUNNING",
172
- message: `Cannot connect to daemon at ${host}: ${message}`,
173
- details: "Start the daemon with: paseo daemon start",
174
- };
175
- throw error;
176
- }
163
+ const client = await connectToDaemon({ target: options.daemonTarget });
177
164
  try {
178
165
  const fetchResult = await client.fetchAgent({ agentId: agentIdArg });
179
166
  if (!fetchResult) {
@@ -1,4 +1,4 @@
1
- import { connectToDaemon, getDaemonHost } from "../../utils/client.js";
1
+ import { connectToDaemon } from "../../utils/client.js";
2
2
  import { fetchProjectedTimelineItems, LIVE_HISTORY_FETCH_TIMEOUT_MS, } from "../../utils/timeline.js";
3
3
  import { curateAgentActivity } from "@camerontaylor/paseo-server";
4
4
  export function addLogsOptions(cmd) {
@@ -53,22 +53,12 @@ function matchesFilter(item, filter) {
53
53
  }
54
54
  }
55
55
  export async function runLogsCommand(id, options, _command) {
56
- const host = getDaemonHost({ host: options.host });
57
56
  if (!id) {
58
57
  console.error("Error: Agent ID required");
59
58
  console.error("Usage: paseo agent logs <id>");
60
59
  process.exit(1);
61
60
  }
62
- let client;
63
- try {
64
- client = await connectToDaemon({ host: options.host });
65
- }
66
- catch (err) {
67
- const message = err instanceof Error ? err.message : String(err);
68
- console.error(`Error: Cannot connect to daemon at ${host}: ${message}`);
69
- console.error("Start the daemon with: paseo daemon start");
70
- process.exit(1);
71
- }
61
+ const client = await connectToDaemon({ target: options.daemonTarget });
72
62
  try {
73
63
  const fetchResult = await client.fetchAgent({ agentId: id });
74
64
  if (!fetchResult) {
@@ -111,6 +101,8 @@ export async function runLogsCommand(id, options, _command) {
111
101
  console.log(transcript);
112
102
  }
113
103
  catch (err) {
104
+ if (err && typeof err === "object" && "code" in err)
105
+ throw err;
114
106
  const message = err instanceof Error ? err.message : String(err);
115
107
  console.error(`Error: Failed to get logs: ${message}`);
116
108
  await client.close().catch(() => { });
@@ -151,6 +143,14 @@ async function runFollowMode(client, agentId, options) {
151
143
  console.log("\n[Timeline replaced; earlier output is no longer current]");
152
144
  return;
153
145
  }
146
+ if (message.type === "agent.timeline.error") {
147
+ console.error(`Timeline observation stopped: ${message.payload.error}`);
148
+ return;
149
+ }
150
+ if (message.type === "agent.timeline.subscription_restored") {
151
+ console.log("\n[Reconnected; live output resumed. Events may have been missed.]");
152
+ return;
153
+ }
154
154
  if (message.payload.event.type === "timeline") {
155
155
  const item = message.payload.event.item;
156
156
  // Apply filter
@@ -1,4 +1,4 @@
1
- import { connectToDaemon, getDaemonHost } from "../../utils/client.js";
1
+ import { connectToDaemon } from "../../utils/client.js";
2
2
  import { collectMultiple } from "../../utils/command-options.js";
3
3
  import { isSameOrDescendantPath } from "../../utils/paths.js";
4
4
  export function addLsOptions(cmd) {
@@ -78,20 +78,6 @@ function toListItem(agent) {
78
78
  created: relativeTime(agent.createdAt),
79
79
  };
80
80
  }
81
- function daemonConnectionFailure(host, cause) {
82
- const reason = cause instanceof Error ? cause.message : String(cause);
83
- const isSsh = host.trim().startsWith("ssh://");
84
- return {
85
- code: "DAEMON_NOT_RUNNING",
86
- message: `Cannot reach the daemon at ${host}: ${reason}`,
87
- details: isSsh
88
- ? "Start the Paseo daemon on the SSH host; SSH transport does not install or start it."
89
- : [
90
- "Start a local daemon with: paseo daemon start",
91
- "To use another daemon, pass --host <host:port> or set PASEO_HOST.",
92
- ].join("\n"),
93
- };
94
- }
95
81
  function parseLabelFilters(labels) {
96
82
  const labelFilters = {};
97
83
  for (const labelStr of labels ?? []) {
@@ -134,14 +120,7 @@ export function buildAgentLsFetchOptions(options) {
134
120
  * - `paseo agent ls -ag` → global agents, including archived
135
121
  */
136
122
  export async function runLsCommand(options, _command) {
137
- const host = getDaemonHost({ host: options.host });
138
- let client;
139
- try {
140
- client = await connectToDaemon({ host: options.host });
141
- }
142
- catch (err) {
143
- throw daemonConnectionFailure(host, err);
144
- }
123
+ const client = await connectToDaemon({ target: options.daemonTarget });
145
124
  try {
146
125
  const normalizedThinkingOptionId = options.thinking?.trim();
147
126
  if (options.thinking !== undefined && !normalizedThinkingOptionId) {
@@ -23,14 +23,14 @@ const missingModeError = () => ({
23
23
  });
24
24
  export async function runModeCommand(id, mode, options, _command) {
25
25
  const normalizedMode = mode?.trim();
26
- const host = getDaemonHost({ host: options.host });
26
+ const host = getDaemonHost({ target: options.daemonTarget });
27
27
  // Validate arguments
28
28
  if (!options.list && !normalizedMode) {
29
29
  throw missingModeError();
30
30
  }
31
31
  let client;
32
32
  try {
33
- client = await connectToDaemon({ host: options.host });
33
+ client = await connectToDaemon({ target: options.daemonTarget });
34
34
  const fetchResult = await client.fetchAgent({ agentId: id });
35
35
  if (!fetchResult) {
36
36
  const error = {
@@ -1,4 +1,4 @@
1
- import { buildDaemonConnectionCommandError, connectToDaemon } from "../../utils/client.js";
1
+ import { connectToDaemon } from "../../utils/client.js";
2
2
  import { openDesktopWithAgent } from "../open.js";
3
3
  const openAgentSchema = {
4
4
  idField: "agentId",
@@ -19,13 +19,7 @@ async function resolveServerId(options) {
19
19
  if (explicitServerId) {
20
20
  return explicitServerId;
21
21
  }
22
- let client;
23
- try {
24
- client = await connectToDaemon({ host: options.host });
25
- }
26
- catch (error) {
27
- throw buildDaemonConnectionCommandError({ host: options.host, error });
28
- }
22
+ const client = await connectToDaemon({ target: options.daemonTarget });
29
23
  try {
30
24
  const serverId = client.getLastServerInfoMessage()?.serverId.trim();
31
25
  if (!serverId) {
@@ -1,4 +1,4 @@
1
- import { connectToDaemon, getDaemonHost, resolveAgentId } from "../../utils/client.js";
1
+ import { connectToDaemon, resolveAgentId } from "../../utils/client.js";
2
2
  export const reloadSchema = {
3
3
  idField: "agentId",
4
4
  columns: [
@@ -13,7 +13,6 @@ export function addReloadOptions(cmd) {
13
13
  .argument("<id>", "Agent ID, prefix, or name");
14
14
  }
15
15
  export async function runReloadCommand(agentIdArg, options, _command) {
16
- const host = getDaemonHost({ host: options.host });
17
16
  if (!agentIdArg || agentIdArg.trim().length === 0) {
18
17
  const error = {
19
18
  code: "MISSING_AGENT_ID",
@@ -22,19 +21,7 @@ export async function runReloadCommand(agentIdArg, options, _command) {
22
21
  };
23
22
  throw error;
24
23
  }
25
- let client;
26
- try {
27
- client = await connectToDaemon({ host: options.host });
28
- }
29
- catch (err) {
30
- const message = err instanceof Error ? err.message : String(err);
31
- const error = {
32
- code: "DAEMON_NOT_RUNNING",
33
- message: `Cannot connect to daemon at ${host}: ${message}`,
34
- details: "Start the daemon with: paseo daemon start",
35
- };
36
- throw error;
37
- }
24
+ const client = await connectToDaemon({ target: options.daemonTarget });
38
25
  try {
39
26
  const agentsPayload = await client.fetchAgents({ filter: { includeArchived: true } });
40
27
  const agents = agentsPayload.entries.map((entry) => entry.agent);
@@ -1,6 +1,6 @@
1
1
  import { Option } from "commander";
2
2
  import { getStructuredAgentResponse, StructuredAgentResponseError } from "@camerontaylor/paseo-server";
3
- import { connectToDaemon, getDaemonHost } from "../../utils/client.js";
3
+ import { connectToDaemon } from "../../utils/client.js";
4
4
  import { readFileSync } from "node:fs";
5
5
  import { resolve } from "node:path";
6
6
  import { lookup } from "mime-types";
@@ -57,6 +57,7 @@ function resolveNewWorkspaceKind(options) {
57
57
  function buildRunWorkspaceSource(options, cwd) {
58
58
  const newWorkspace = resolveNewWorkspaceKind(options) ?? "local";
59
59
  return buildWorkspaceSource({
60
+ daemonTarget: options.daemonTarget,
60
61
  isolation: newWorkspace,
61
62
  path: cwd,
62
63
  mode: options.worktreeMode,
@@ -93,6 +94,8 @@ function loadOutputSchema(value) {
93
94
  source = readFileSync(resolve(trimmed), "utf8");
94
95
  }
95
96
  catch (err) {
97
+ if (err && typeof err === "object" && "code" in err)
98
+ throw err;
96
99
  const message = err instanceof Error ? err.message : String(err);
97
100
  const error = {
98
101
  code: "INVALID_OUTPUT_SCHEMA",
@@ -107,6 +110,8 @@ function loadOutputSchema(value) {
107
110
  parsed = JSON.parse(source);
108
111
  }
109
112
  catch (err) {
113
+ if (err && typeof err === "object" && "code" in err)
114
+ throw err;
110
115
  const message = err instanceof Error ? err.message : String(err);
111
116
  const error = {
112
117
  code: "INVALID_OUTPUT_SCHEMA",
@@ -285,6 +290,8 @@ function parseWaitTimeoutOption(waitTimeout) {
285
290
  return ms;
286
291
  }
287
292
  catch (err) {
293
+ if (err && typeof err === "object" && "code" in err)
294
+ throw err;
288
295
  const message = err instanceof Error ? err.message : String(err);
289
296
  throw {
290
297
  code: "INVALID_TIMEOUT",
@@ -310,6 +317,8 @@ function loadRunImages(imagePaths) {
310
317
  };
311
318
  }
312
319
  catch (err) {
320
+ if (err && typeof err === "object" && "code" in err)
321
+ throw err;
313
322
  const message = err instanceof Error ? err.message : String(err);
314
323
  throw new Error(`Failed to read image ${imagePath}: ${message}`, { cause: err });
315
324
  }
@@ -349,19 +358,6 @@ function parseKeyValueFlags(flags, options) {
349
358
  }
350
359
  return labels;
351
360
  }
352
- async function connectToDaemonOrThrow(hostOption, host) {
353
- try {
354
- return await connectToDaemon({ host: hostOption });
355
- }
356
- catch (err) {
357
- const message = err instanceof Error ? err.message : String(err);
358
- throw {
359
- code: "DAEMON_NOT_RUNNING",
360
- message: `Cannot connect to daemon at ${host}: ${message}`,
361
- details: "Start the daemon with: paseo daemon start",
362
- };
363
- }
364
- }
365
361
  export async function resolveExistingRunWorkspace(client, workspaceId) {
366
362
  const result = await client.fetchWorkspaces({
367
363
  filter: { query: workspaceId },
@@ -416,13 +412,12 @@ async function resolveRunWorkspace(client, options, cwd) {
416
412
  return { id: result.workspace.id, cwd: result.workspace.workspaceDirectory ?? cwd };
417
413
  }
418
414
  export async function runRunCommand(prompt, options, _command) {
419
- const host = getDaemonHost({ host: options.host });
420
415
  const outputSchema = options.outputSchema ? loadOutputSchema(options.outputSchema) : undefined;
421
416
  validateRunOptions(prompt, options, outputSchema);
422
417
  const waitTimeoutMs = parseWaitTimeoutOption(options.waitTimeout);
423
418
  const resolvedProviderModel = resolveProviderAndModel(options);
424
419
  const resolvedTitle = options.title ?? options.name;
425
- const client = await connectToDaemonOrThrow(options.host, host);
420
+ const client = await connectToDaemon({ target: options.daemonTarget });
426
421
  try {
427
422
  // Resolve working directory
428
423
  const cwd = options.cwd ?? process.cwd();
@@ -1,5 +1,5 @@
1
1
  import { collectMultiple } from "../../utils/command-options.js";
2
- import { connectToDaemon, getDaemonHost } from "../../utils/client.js";
2
+ import { connectToDaemon } from "../../utils/client.js";
3
3
  import { readFile } from "node:fs/promises";
4
4
  import { extname, resolve } from "node:path";
5
5
  /** Schema for agent send output */
@@ -50,6 +50,8 @@ async function readImageFiles(imagePaths) {
50
50
  return { data: buffer.toString("base64"), mimeType };
51
51
  }
52
52
  catch (err) {
53
+ if (err && typeof err === "object" && "code" in err)
54
+ throw err;
53
55
  const message = err instanceof Error ? err.message : String(err);
54
56
  throw {
55
57
  code: "IMAGE_READ_ERROR",
@@ -89,6 +91,8 @@ async function resolvePromptInput(options) {
89
91
  return await readFile(resolve(promptFilePath), "utf8");
90
92
  }
91
93
  catch (err) {
94
+ if (err && typeof err === "object" && "code" in err)
95
+ throw err;
92
96
  const message = err instanceof Error ? err.message : String(err);
93
97
  const error = {
94
98
  code: "PROMPT_FILE_READ_ERROR",
@@ -116,7 +120,6 @@ function buildSendResult(agentIdArg, state) {
116
120
  return { agentId, status: "completed", message: "Agent completed processing the message" };
117
121
  }
118
122
  export async function runSendCommand(agentIdArg, prompt, options, _command) {
119
- const host = getDaemonHost({ host: options.host });
120
123
  // Validate arguments
121
124
  if (!agentIdArg || agentIdArg.trim().length === 0) {
122
125
  const error = {
@@ -131,19 +134,7 @@ export async function runSendCommand(agentIdArg, prompt, options, _command) {
131
134
  promptOption: options.prompt,
132
135
  promptFile: options.promptFile,
133
136
  });
134
- let client;
135
- try {
136
- client = await connectToDaemon({ host: options.host });
137
- }
138
- catch (err) {
139
- const message = err instanceof Error ? err.message : String(err);
140
- const error = {
141
- code: "DAEMON_NOT_RUNNING",
142
- message: `Cannot connect to daemon at ${host}: ${message}`,
143
- details: "Start the daemon with: paseo daemon start",
144
- };
145
- throw error;
146
- }
137
+ const client = await connectToDaemon({ target: options.daemonTarget });
147
138
  try {
148
139
  // Read image files if provided
149
140
  const images = options.image && options.image.length > 0 ? await readImageFiles(options.image) : undefined;