@camerontaylor/paseo-cli 0.8.0-fork.1 → 0.9.0-beta.2.fork.1

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 (125) hide show
  1. package/dist/cli.js +44 -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 +13 -13
  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 +12 -17
  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 +103 -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 +33 -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/runtime-toolchain.js +1 -1
  32. package/dist/commands/daemon/set-password.js +8 -7
  33. package/dist/commands/daemon/start.d.ts +17 -3
  34. package/dist/commands/daemon/start.js +47 -52
  35. package/dist/commands/daemon/status.d.ts +12 -20
  36. package/dist/commands/daemon/status.js +91 -342
  37. package/dist/commands/daemon/stop.d.ts +19 -14
  38. package/dist/commands/daemon/stop.js +53 -55
  39. package/dist/commands/heartbeat/index.js +3 -3
  40. package/dist/commands/hub/connect.d.ts +1 -0
  41. package/dist/commands/hub/connect.js +1 -1
  42. package/dist/commands/hub/daemon-client.d.ts +3 -2
  43. package/dist/commands/hub/daemon-client.js +3 -3
  44. package/dist/commands/hub/disconnect.d.ts +1 -0
  45. package/dist/commands/hub/disconnect.js +1 -1
  46. package/dist/commands/hub/index.js +2 -2
  47. package/dist/commands/hub/init.d.ts +3 -1
  48. package/dist/commands/hub/init.js +13 -12
  49. package/dist/commands/hub/login.d.ts +4 -4
  50. package/dist/commands/hub/login.js +1 -1
  51. package/dist/commands/hub/logout.d.ts +1 -0
  52. package/dist/commands/hub/logout.js +2 -2
  53. package/dist/commands/hub/permissions.d.ts +1 -0
  54. package/dist/commands/hub/permissions.js +2 -2
  55. package/dist/commands/onboard.d.ts +7 -2
  56. package/dist/commands/onboard.js +59 -210
  57. package/dist/commands/open.js +3 -1
  58. package/dist/commands/permit/allow.js +2 -15
  59. package/dist/commands/permit/deny.js +2 -15
  60. package/dist/commands/permit/ls.js +2 -15
  61. package/dist/commands/plugin/index.d.ts +6 -0
  62. package/dist/commands/plugin/index.js +62 -46
  63. package/dist/commands/plugin/scaffold.js +10 -0
  64. package/dist/commands/plugin/shared.d.ts +5 -3
  65. package/dist/commands/plugin/shared.js +13 -9
  66. package/dist/commands/plugin/update.d.ts +37 -0
  67. package/dist/commands/plugin/update.js +58 -0
  68. package/dist/commands/project/create.js +5 -3
  69. package/dist/commands/project/delete.js +4 -2
  70. package/dist/commands/project/ls.js +2 -2
  71. package/dist/commands/project/rename.js +4 -2
  72. package/dist/commands/provider/add.js +2 -2
  73. package/dist/commands/provider/diagnostic.js +1 -1
  74. package/dist/commands/provider/ls.js +2 -30
  75. package/dist/commands/provider/models.js +1 -1
  76. package/dist/commands/provider/rm.js +2 -2
  77. package/dist/commands/schedule/create.js +2 -2
  78. package/dist/commands/schedule/delete.js +1 -1
  79. package/dist/commands/schedule/inspect.js +1 -1
  80. package/dist/commands/schedule/logs.js +1 -1
  81. package/dist/commands/schedule/ls.js +1 -1
  82. package/dist/commands/schedule/pause.js +1 -1
  83. package/dist/commands/schedule/resume.js +1 -1
  84. package/dist/commands/schedule/run-once.js +1 -1
  85. package/dist/commands/schedule/shared.d.ts +3 -1
  86. package/dist/commands/schedule/shared.js +7 -5
  87. package/dist/commands/schedule/update.js +1 -1
  88. package/dist/commands/script/ls.js +1 -1
  89. package/dist/commands/script/shared.d.ts +2 -1
  90. package/dist/commands/script/shared.js +3 -3
  91. package/dist/commands/script/start.js +1 -1
  92. package/dist/commands/script/stop.js +1 -1
  93. package/dist/commands/terminal/capture.d.ts +1 -1
  94. package/dist/commands/terminal/capture.js +2 -3
  95. package/dist/commands/terminal/create.js +1 -1
  96. package/dist/commands/terminal/kill.js +1 -1
  97. package/dist/commands/terminal/ls.js +1 -1
  98. package/dist/commands/terminal/send-keys.d.ts +1 -1
  99. package/dist/commands/terminal/send-keys.js +2 -3
  100. package/dist/commands/terminal/shared.d.ts +2 -1
  101. package/dist/commands/terminal/shared.js +5 -3
  102. package/dist/commands/workspace/archive.d.ts +1 -0
  103. package/dist/commands/workspace/archive.js +4 -2
  104. package/dist/commands/workspace/create.js +4 -2
  105. package/dist/commands/workspace/ls.d.ts +1 -0
  106. package/dist/commands/workspace/ls.js +2 -2
  107. package/dist/commands/workspace/rename.d.ts +1 -0
  108. package/dist/commands/workspace/rename.js +4 -2
  109. package/dist/commands/workspace/setup.d.ts +1 -0
  110. package/dist/commands/workspace/setup.js +2 -2
  111. package/dist/commands/worktree/archive.js +4 -2
  112. package/dist/commands/worktree/create.js +2 -10
  113. package/dist/commands/worktree/ls.d.ts +0 -2
  114. package/dist/commands/worktree/ls.js +4 -30
  115. package/dist/output/with-output.d.ts +2 -0
  116. package/dist/run.js +11 -1
  117. package/dist/utils/client-id.d.ts +1 -1
  118. package/dist/utils/client-id.js +8 -14
  119. package/dist/utils/client.d.ts +16 -21
  120. package/dist/utils/client.js +57 -109
  121. package/dist/utils/command-options.d.ts +1 -0
  122. package/dist/utils/command-options.js +26 -2
  123. package/dist/utils/daemon-target.d.ts +13 -0
  124. package/dist/utils/daemon-target.js +51 -0
  125. package/package.json +8 -4
@@ -1,4 +1,4 @@
1
- import { connectToDaemon, getDaemonHost } from "../../utils/client.js";
1
+ import { connectToDaemon } from "../../utils/client.js";
2
2
  /** Schema for permit allow/deny output */
3
3
  export const permitResponseSchema = {
4
4
  idField: "requestId",
@@ -21,7 +21,6 @@ export const permitResponseSchema = {
21
21
  ],
22
22
  };
23
23
  export async function runAllowCommand(agentIdOrPrefix, reqId, options, _command) {
24
- const host = getDaemonHost({ host: options.host });
25
24
  // No validation needed - if no reqId provided, allow all by default
26
25
  // Parse input JSON if provided
27
26
  let updatedInput;
@@ -38,19 +37,7 @@ export async function runAllowCommand(agentIdOrPrefix, reqId, options, _command)
38
37
  throw error;
39
38
  }
40
39
  }
41
- let client;
42
- try {
43
- client = await connectToDaemon({ host: options.host });
44
- }
45
- catch (err) {
46
- const message = err instanceof Error ? err.message : String(err);
47
- const error = {
48
- code: "DAEMON_NOT_RUNNING",
49
- message: `Cannot connect to daemon at ${host}: ${message}`,
50
- details: "Start the daemon with: paseo daemon start",
51
- };
52
- throw error;
53
- }
40
+ const client = await connectToDaemon({ target: options.daemonTarget });
54
41
  try {
55
42
  const fetchResult = await client.fetchAgent({ agentId: agentIdOrPrefix });
56
43
  if (!fetchResult) {
@@ -1,7 +1,6 @@
1
- import { connectToDaemon, getDaemonHost } from "../../utils/client.js";
1
+ import { connectToDaemon } from "../../utils/client.js";
2
2
  import { permitResponseSchema } from "./allow.js";
3
3
  export async function runDenyCommand(agentIdOrPrefix, reqId, options, _command) {
4
- const host = getDaemonHost({ host: options.host });
5
4
  // Validate arguments
6
5
  if (!options.all && !reqId) {
7
6
  const error = {
@@ -11,19 +10,7 @@ export async function runDenyCommand(agentIdOrPrefix, reqId, options, _command)
11
10
  };
12
11
  throw error;
13
12
  }
14
- let client;
15
- try {
16
- client = await connectToDaemon({ host: options.host });
17
- }
18
- catch (err) {
19
- const message = err instanceof Error ? err.message : String(err);
20
- const error = {
21
- code: "DAEMON_NOT_RUNNING",
22
- message: `Cannot connect to daemon at ${host}: ${message}`,
23
- details: "Start the daemon with: paseo daemon start",
24
- };
25
- throw error;
26
- }
13
+ const client = await connectToDaemon({ target: options.daemonTarget });
27
14
  try {
28
15
  const fetchResult = await client.fetchAgent({ agentId: agentIdOrPrefix });
29
16
  if (!fetchResult) {
@@ -1,4 +1,4 @@
1
- import { connectToDaemon, getDaemonHost } from "../../utils/client.js";
1
+ import { connectToDaemon } from "../../utils/client.js";
2
2
  /** Schema for permit ls output */
3
3
  export const permitLsSchema = {
4
4
  idField: "id",
@@ -20,20 +20,7 @@ function toListItem(agent, permission) {
20
20
  };
21
21
  }
22
22
  export async function runLsCommand(options, _command) {
23
- const host = getDaemonHost({ host: options.host });
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 agentsPayload = await client.fetchAgents({ filter: { includeArchived: true } });
39
26
  const agents = agentsPayload.entries.map((entry) => entry.agent);
@@ -1,3 +1,4 @@
1
+ import { type UpdateOutcome } from "./update.js";
1
2
  import { Command } from "commander";
2
3
  import type { PluginListItem, PluginLogEntry } from "@camerontaylor/paseo-protocol/messages";
3
4
  import type { CommandOptions, ListResult, SingleResult } from "../../output/index.js";
@@ -8,10 +9,15 @@ interface PluginOptions extends CommandOptions {
8
9
  ref?: string;
9
10
  path?: string;
10
11
  all?: boolean;
12
+ version?: string;
13
+ check?: boolean;
14
+ yes?: boolean;
11
15
  }
12
16
  export declare function runPluginInitCommand(directory: string, options: PluginOptions, _command: Command): Promise<SingleResult<PluginScaffold>>;
13
17
  export declare function runPluginListCommand(pluginId: string | undefined, options: PluginOptions, _command: Command): Promise<ListResult<PluginListItem>>;
14
18
  export declare function runPluginLogsCommand(pluginId: string, options: PluginOptions, _command: Command): Promise<ListResult<PluginLogEntry>>;
19
+ export declare function runPluginInstallCommand(source: string, options: PluginOptions, _command: Command): Promise<SingleResult<PluginListItem>>;
20
+ export declare function runPluginUpdateCommand(pluginId: string | undefined, options: PluginOptions, _command: Command): Promise<ListResult<UpdateOutcome>>;
15
21
  export declare function createPluginCommand(): Command;
16
22
  export {};
17
23
  //# sourceMappingURL=index.d.ts.map
@@ -1,19 +1,27 @@
1
+ import { createInterface } from "node:readline/promises";
2
+ import { reviewPluginUpdates } from "./update.js";
1
3
  import { Command } from "commander";
2
- import path from "node:path";
3
- import { formatPluginSourceReference, parsePluginSourceReference, } from "@camerontaylor/paseo-protocol/plugin-source-reference";
4
+ import { formatPluginSourceReference, formatPluginIdentity, } from "@camerontaylor/paseo-protocol/plugin-source-reference";
4
5
  import { withOutput } from "../../output/index.js";
5
6
  import { addJsonAndDaemonHostOptions, addJsonOption } from "../../utils/command-options.js";
6
7
  import { scaffoldPluginDirectory } from "./scaffold.js";
7
- import { withPluginLogsClient, withPluginManagementClient, withPluginSourceClient, } from "./shared.js";
8
+ import { withPluginLogsClient, withPluginUpdateClient, withPluginManagementClient, withPluginSourceClient, } from "./shared.js";
8
9
  const pluginSchema = {
9
10
  idField: "id",
10
11
  columns: [
11
12
  { header: "PLUGIN", field: "id", width: 20 },
12
13
  { header: "STATUS", field: "status", width: 10 },
13
14
  { header: "ENABLED", field: (plugin) => (plugin.enabled ? "yes" : "no"), width: 8 },
14
- { header: "SOURCE", field: (plugin) => plugin.source ?? "directory", width: 10 },
15
- { header: "COMMIT", field: (plugin) => shortCommit(plugin.commit), width: 14 },
16
- { header: "REF", field: (plugin) => plugin.ref ?? "-", width: 24 },
15
+ {
16
+ header: "SOURCE",
17
+ field: (plugin) => plugin.installation ? formatPluginIdentity(plugin.installation.identity) : "-",
18
+ width: 40,
19
+ },
20
+ {
21
+ header: "REVISION",
22
+ field: (plugin) => plugin.installation?.currentRevision ?? "-",
23
+ width: 16,
24
+ },
17
25
  { header: "DIRECTORY", field: "path", width: 40 },
18
26
  { header: "ERROR", field: (plugin) => plugin.error ?? "", width: 40 },
19
27
  ],
@@ -33,17 +41,16 @@ const pluginLogsSchema = {
33
41
  { header: "MESSAGE", field: "message", width: 80 },
34
42
  ],
35
43
  };
36
- function shortCommit(commit) {
37
- return commit?.slice(0, 12) ?? "-";
38
- }
39
44
  const pluginUpdateSchema = {
40
45
  idField: "id",
41
46
  columns: [
42
- { header: "PLUGIN", field: "id", width: 20 },
43
- { header: "PREVIOUS", field: (plugin) => shortCommit(plugin.previousCommit), width: 14 },
44
- { header: "CURRENT", field: (plugin) => shortCommit(plugin.currentCommit), width: 14 },
45
- { header: "COMMITS", field: (plugin) => String(plugin.commits), width: 8 },
46
- { header: "UPDATED", field: (plugin) => (plugin.updated ? "yes" : "no"), width: 8 },
47
+ { header: "PLUGIN", field: "id", width: 24 },
48
+ { header: "RESULT", field: "outcome", width: 18 },
49
+ {
50
+ header: "DETAIL",
51
+ field: (item) => item.error ?? item.warning ?? item.plugin?.installation?.currentRevision ?? "",
52
+ width: 50,
53
+ },
47
54
  ],
48
55
  };
49
56
  export async function runPluginInitCommand(directory, options, _command) {
@@ -54,50 +61,55 @@ export async function runPluginInitCommand(directory, options, _command) {
54
61
  };
55
62
  }
56
63
  export async function runPluginListCommand(pluginId, options, _command) {
57
- const plugins = await withPluginManagementClient(options.host, (client) => client.listPlugins());
64
+ const plugins = await withPluginManagementClient(options.daemonTarget, (client) => client.listPlugins());
58
65
  const data = pluginId ? plugins.filter((plugin) => plugin.id === pluginId) : plugins;
59
66
  if (pluginId && data.length === 0)
60
67
  throw new Error(`Plugin is not configured: ${pluginId}`);
61
68
  return { type: "list", data, schema: pluginSchema };
62
69
  }
63
70
  export async function runPluginLogsCommand(pluginId, options, _command) {
64
- const data = await withPluginLogsClient(options.host, (client) => client.getPluginLogs(pluginId));
71
+ const data = await withPluginLogsClient(options.daemonTarget, (client) => client.getPluginLogs(pluginId));
65
72
  return { type: "list", data, schema: pluginLogsSchema };
66
73
  }
67
- async function install(source, options, _command) {
68
- process.stderr.write("Trusting plugin code: server code and Git build commands run unsandboxed on the daemon host; client code runs inside Paseo. Dependencies and future updates are part of the codebase you trust.\n");
69
- const isExplicitPath = path.isAbsolute(source) ||
70
- source === "." ||
71
- source === ".." ||
72
- source.startsWith("./") ||
73
- source.startsWith("../") ||
74
- source.startsWith(".\\") ||
75
- source.startsWith("..\\");
76
- const hasPluginPathSuffix = parsePluginSourceReference(source).pluginPath !== undefined;
77
- const canUseLegacyDirectoryInstall = isExplicitPath && !hasPluginPathSuffix && !options.ref && !options.path;
74
+ export async function runPluginInstallCommand(source, options, _command) {
75
+ process.stderr.write("Trusting plugin code: server code and preparation commands run unsandboxed on the daemon host; client code runs inside Paseo. Dependencies and future updates are part of the codebase you trust.\n");
78
76
  const sourceReference = formatPluginSourceReference(source, options.path);
79
- const data = canUseLegacyDirectoryInstall
80
- ? await withPluginManagementClient(options.host, (client) => client.installDirectoryPlugin(source, options.id))
81
- : await withPluginSourceClient(options.host, (client) => client.installPluginSource({
82
- source: sourceReference,
83
- ...(options.id ? { id: options.id } : {}),
84
- ...(options.ref ? { ref: options.ref } : {}),
85
- }));
77
+ const data = await withPluginSourceClient(options.daemonTarget, (client) => client.installPluginSource({
78
+ source: sourceReference,
79
+ ...(options.id ? { id: options.id } : {}),
80
+ ...(options.ref ? { ref: options.ref } : {}),
81
+ }));
86
82
  return { type: "single", data, schema: pluginSchema };
87
83
  }
88
- async function update(pluginId, options, _command) {
89
- if ((pluginId === undefined) === (options.all !== true)) {
90
- throw new Error("Choose one plugin ID or pass --all");
91
- }
92
- const data = await withPluginSourceClient(options.host, (client) => client.updatePluginSources(pluginId));
84
+ export async function runPluginUpdateCommand(pluginId, options, _command) {
85
+ const data = await withPluginUpdateClient(options.daemonTarget, (client) => reviewPluginUpdates(client, { ...options, pluginId }, {
86
+ interactive: process.stdin.isTTY === true,
87
+ structured: options.json === true ||
88
+ ["json", "yaml"].includes(options.format?.trim().toLowerCase() ?? ""),
89
+ write: (text) => process.stderr.write(text),
90
+ confirm: async (message) => {
91
+ const prompt = createInterface({ input: process.stdin, output: process.stderr });
92
+ try {
93
+ return /^(y|yes)$/i.test((await prompt.question(message)).trim());
94
+ }
95
+ catch {
96
+ return false;
97
+ }
98
+ finally {
99
+ prompt.close();
100
+ }
101
+ },
102
+ }));
103
+ if (data.some((item) => item.outcome === "error"))
104
+ process.exitCode = 1;
93
105
  return { type: "list", data, schema: pluginUpdateSchema };
94
106
  }
95
107
  async function act(action, pluginId, options) {
96
- const data = await withPluginManagementClient(options.host, (client) => client[`${action}Plugin`](pluginId));
108
+ const data = await withPluginManagementClient(options.daemonTarget, (client) => client[`${action}Plugin`](pluginId));
97
109
  return { type: "single", data, schema: pluginSchema };
98
110
  }
99
111
  async function remove(pluginId, options, _command) {
100
- const data = await withPluginManagementClient(options.host, async (client) => {
112
+ const data = await withPluginManagementClient(options.daemonTarget, async (client) => {
101
113
  const current = (await client.listPlugins()).find((plugin) => plugin.id === pluginId);
102
114
  if (!current)
103
115
  throw new Error(`Plugin is not configured: ${pluginId}`);
@@ -119,16 +131,20 @@ export function createPluginCommand() {
119
131
  addJsonAndDaemonHostOptions(plugin
120
132
  .command("install")
121
133
  .alias("add")
122
- .description("Trust and install a plugin from a directory or Git repository")
123
- .argument("<source>", "Host directory, Git source, or Git source:plugin/path")
134
+ .description("Trust and install a plugin from a directory, Git repository, or npm package")
135
+ .argument("<source>", "Host directory, Git or npm source, optionally followed by :plugin/path")
124
136
  .option("--id <id>", "Runtime plugin ID (defaults to paseo-plugin.json id)")
125
137
  .option("--ref <ref>", "Git branch, tag, or commit")
126
- .option("--path <path>", "Legacy form of the :plugin/path source suffix")).action(withOutput(install));
138
+ .option("--path <path>", "Legacy form of the :plugin/path source suffix")).action(withOutput(runPluginInstallCommand));
127
139
  addJsonAndDaemonHostOptions(plugin
128
140
  .command("update")
129
- .description("Fetch and install Git-managed plugin updates")
141
+ .description("Review and update installed plugins")
130
142
  .argument("[id]")
131
- .option("--all", "Update every Git-managed plugin")).action(withOutput(update));
143
+ .option("--all", "Review all configured plugins")
144
+ .option("--check", "Show available updates without installing")
145
+ .option("--yes", "Apply displayed updates without asking")
146
+ .option("--ref <ref>", "Apply a Git branch, tag, or commit without asking")
147
+ .option("--version <version>", "Apply an npm version, tag, or range without asking")).action(withOutput(runPluginUpdateCommand));
132
148
  for (const action of ["reload", "enable", "disable"]) {
133
149
  addJsonAndDaemonHostOptions(plugin.command(action).description(`${action} a plugin`).argument("<id>")).action(withOutput((id, options, _command) => act(action, id, options)));
134
150
  }
@@ -130,6 +130,16 @@ export async function scaffoldPluginDirectory(targetDirectory, requestedId) {
130
130
  name: id,
131
131
  private: true,
132
132
  version: "0.0.0",
133
+ files: [
134
+ "paseo-plugin.json",
135
+ "index.client.ts",
136
+ "index.client.tsx",
137
+ "index.server.ts",
138
+ "index.server.tsx",
139
+ "client/",
140
+ "server/",
141
+ "shared/",
142
+ ],
133
143
  scripts: { typecheck: "tsc --noEmit" },
134
144
  devDependencies: {
135
145
  "@camerontaylor/paseo-plugin": version,
@@ -1,5 +1,7 @@
1
+ import type { DaemonTarget } from "../../utils/daemon-target.js";
1
2
  import type { DaemonClient } from "@camerontaylor/paseo-client/internal/daemon-client";
2
- export declare function withPluginManagementClient<T>(host: string | undefined, run: (client: DaemonClient) => Promise<T>): Promise<T>;
3
- export declare function withPluginLogsClient<T>(host: string | undefined, run: (client: DaemonClient) => Promise<T>): Promise<T>;
4
- export declare function withPluginSourceClient<T>(host: string | undefined, run: (client: DaemonClient) => Promise<T>): Promise<T>;
3
+ export declare function withPluginManagementClient<T>(target: DaemonTarget, run: (client: DaemonClient) => Promise<T>): Promise<T>;
4
+ export declare function withPluginLogsClient<T>(target: DaemonTarget, run: (client: DaemonClient) => Promise<T>): Promise<T>;
5
+ export declare function withPluginSourceClient<T>(target: DaemonTarget, run: (client: DaemonClient) => Promise<T>): Promise<T>;
6
+ export declare function withPluginUpdateClient<T>(target: DaemonTarget, run: (client: DaemonClient) => Promise<T>): Promise<T>;
5
7
  //# sourceMappingURL=shared.d.ts.map
@@ -1,6 +1,6 @@
1
1
  import { connectToDaemon } from "../../utils/client.js";
2
- async function withPluginClient(host, feature, updateMessage, run) {
3
- const client = await connectToDaemon({ host });
2
+ async function withPluginClient(target, feature, updateMessage, run) {
3
+ const client = await connectToDaemon({ target });
4
4
  if (client.getLastServerInfoMessage()?.features?.[feature] !== true) {
5
5
  await client.close().catch(() => undefined);
6
6
  throw {
@@ -15,16 +15,20 @@ async function withPluginClient(host, feature, updateMessage, run) {
15
15
  await client.close().catch(() => undefined);
16
16
  }
17
17
  }
18
- export async function withPluginManagementClient(host, run) {
18
+ export async function withPluginManagementClient(target, run) {
19
19
  // COMPAT(pluginManagement): added in v0.3.1, remove gate after 2027-08-14.
20
- return withPluginClient(host, "pluginManagement", "Update the host to use plugin management.", run);
20
+ return withPluginClient(target, "pluginManagement", "Update the host to use plugin management.", run);
21
21
  }
22
- export async function withPluginLogsClient(host, run) {
22
+ export async function withPluginLogsClient(target, run) {
23
23
  // COMPAT(pluginLogs): added in v0.4.0, remove gate after 2027-08-16.
24
- return withPluginClient(host, "pluginLogs", "Update the host to view plugin logs.", run);
24
+ return withPluginClient(target, "pluginLogs", "Update the host to view plugin logs.", run);
25
25
  }
26
- export async function withPluginSourceClient(host, run) {
27
- // COMPAT(pluginGitManagement): added in v0.7.0, remove gate after 2027-08-26.
28
- return withPluginClient(host, "pluginGitManagement", "Update the host to install and update Git plugins.", run);
26
+ export async function withPluginSourceClient(target, run) {
27
+ // COMPAT(pluginSourceInstallation): added in v0.8.0; remove gate after 2027-03-16 once daemon floor supports source identifiers.
28
+ return withPluginClient(target, "pluginSourceInstallation", "Update the host to install plugin sources.", run);
29
+ }
30
+ export async function withPluginUpdateClient(target, run) {
31
+ // COMPAT(pluginSourceUpdates): added in v0.8.0; remove after 2027-03-16 once daemon floor supports reviewed updates.
32
+ return withPluginClient(target, "pluginSourceUpdates", "Update the host to review plugin updates.", run);
29
33
  }
30
34
  //# sourceMappingURL=shared.js.map
@@ -0,0 +1,37 @@
1
+ import type { PluginUpdatePreview, PluginUpdateResult, PluginUpdateSelection, PluginUpdateProposal } from "@camerontaylor/paseo-protocol/messages";
2
+ interface UpdateClient {
3
+ previewPluginUpdates(input: {
4
+ pluginId?: string;
5
+ target?: PluginUpdateSelection;
6
+ }): Promise<PluginUpdatePreview[]>;
7
+ applyPluginUpdates(proposals: PluginUpdateProposal[]): Promise<PluginUpdateResult[]>;
8
+ }
9
+ export interface UpdateOptions {
10
+ pluginId?: string;
11
+ all?: boolean;
12
+ ref?: string;
13
+ version?: string;
14
+ check?: boolean;
15
+ yes?: boolean;
16
+ }
17
+ export interface UpdateInteraction {
18
+ interactive: boolean;
19
+ structured: boolean;
20
+ write(text: string): void;
21
+ confirm(message: string): Promise<boolean>;
22
+ }
23
+ export interface UpdateOutcome {
24
+ id: string;
25
+ outcome: PluginUpdatePreview["outcome"] | PluginUpdateResult["outcome"] | "declined";
26
+ current?: PluginUpdatePreview["current"];
27
+ target?: PluginUpdatePreview["target"];
28
+ links?: string[];
29
+ proposal?: PluginUpdateProposal;
30
+ plugin?: PluginUpdateResult["plugin"];
31
+ error?: string;
32
+ warning?: string;
33
+ }
34
+ export declare function reviewPluginUpdates(client: UpdateClient, options: UpdateOptions, interaction: UpdateInteraction): Promise<UpdateOutcome[]>;
35
+ export declare function formatUpdatePreview(items: PluginUpdatePreview[]): string;
36
+ export {};
37
+ //# sourceMappingURL=update.d.ts.map
@@ -0,0 +1,58 @@
1
+ export async function reviewPluginUpdates(client, options, interaction) {
2
+ if ((options.pluginId === undefined) === (options.all !== true))
3
+ throw new Error("Choose one plugin ID or pass --all");
4
+ if (options.ref && options.version)
5
+ throw new Error("Choose --ref or --version, not both");
6
+ let target;
7
+ if (options.ref)
8
+ target = { kind: "git", ref: options.ref };
9
+ if (options.version)
10
+ target = { kind: "npm", version: options.version };
11
+ if (target && options.all)
12
+ throw new Error("An explicit target requires one plugin ID, without --all");
13
+ const preview = await client.previewPluginUpdates({ pluginId: options.pluginId, target });
14
+ if (!interaction.structured)
15
+ interaction.write(formatUpdatePreview(preview));
16
+ if (options.check)
17
+ return preview;
18
+ const proposals = preview.flatMap((item) => (item.proposal ? [item.proposal] : []));
19
+ if (!proposals.length)
20
+ return preview;
21
+ if (!options.yes && !target) {
22
+ if (interaction.structured || !interaction.interactive)
23
+ throw new Error("Confirmation required; rerun with --yes.");
24
+ if (!(await interaction.confirm(options.all ? "Update these plugins? [y/N] " : `Update ${options.pluginId}? [y/N] `))) {
25
+ return preview.map((item) => (item.proposal ? { id: item.id, outcome: "declined" } : item));
26
+ }
27
+ }
28
+ const applied = new Map((await client.applyPluginUpdates(proposals)).map((item) => [item.id, item]));
29
+ return preview.map((item) => applied.get(item.id) ?? item);
30
+ }
31
+ export function formatUpdatePreview(items) {
32
+ return items
33
+ .map((item) => {
34
+ const current = item.current?.currentRevision ?? "unknown";
35
+ const target = item.target?.kind === "git" ? item.target.commit : item.target?.version;
36
+ let text;
37
+ switch (item.outcome) {
38
+ case "update":
39
+ text = `${current} → ${target}`;
40
+ break;
41
+ case "current":
42
+ text = `up to date (${current})`;
43
+ break;
44
+ case "installed-newer":
45
+ text = `installed ${current} is newer than latest ${target}; keeping installed version`;
46
+ break;
47
+ case "local":
48
+ text = "local directory; use Reload after editing";
49
+ break;
50
+ case "error":
51
+ text = item.error ?? "Check failed";
52
+ break;
53
+ }
54
+ return `${item.id}: ${text}\n${item.links.map((link) => `Review: ${link}\n`).join("")}`;
55
+ })
56
+ .join("\n");
57
+ }
58
+ //# sourceMappingURL=update.js.map
@@ -18,10 +18,10 @@ export async function runCreateCommand(pathArg, options, _command) {
18
18
  const projectPath = resolveProjectPath({
19
19
  pathArg,
20
20
  cwd: process.cwd(),
21
- daemonTarget: options.host ?? process.env.PASEO_HOST,
21
+ daemonTarget: options.daemonTarget.kind === "endpoint" ? options.daemonTarget.host : undefined,
22
22
  });
23
- const client = await connectToDaemon({ host: options.host }).catch((error) => {
24
- throw buildDaemonConnectionCommandError({ host: options.host, error });
23
+ const client = await connectToDaemon({ target: options.daemonTarget }).catch((error) => {
24
+ throw buildDaemonConnectionCommandError({ target: options.daemonTarget, error });
25
25
  });
26
26
  try {
27
27
  const payload = await client.addProject(projectPath);
@@ -31,6 +31,8 @@ export async function runCreateCommand(pathArg, options, _command) {
31
31
  return { type: "single", data: toProjectRow(payload.project), schema: projectSchema };
32
32
  }
33
33
  catch (error) {
34
+ if (error && typeof error === "object" && "code" in error)
35
+ throw error;
34
36
  const message = error instanceof Error ? error.message : String(error);
35
37
  throw { code: "PROJECT_CREATE_FAILED", message };
36
38
  }
@@ -11,8 +11,8 @@ const projectDeleteSchema = {
11
11
  ],
12
12
  };
13
13
  export async function runDeleteCommand(projectId, options, _command) {
14
- const client = await connectToDaemon({ host: options.host }).catch((error) => {
15
- throw buildDaemonConnectionCommandError({ host: options.host, error });
14
+ const client = await connectToDaemon({ target: options.daemonTarget }).catch((error) => {
15
+ throw buildDaemonConnectionCommandError({ target: options.daemonTarget, error });
16
16
  });
17
17
  try {
18
18
  const result = await client.removeProject(projectId);
@@ -23,6 +23,8 @@ export async function runDeleteCommand(projectId, options, _command) {
23
23
  };
24
24
  }
25
25
  catch (error) {
26
+ if (error && typeof error === "object" && "code" in error)
27
+ throw error;
26
28
  const message = error instanceof Error ? error.message : String(error);
27
29
  throw { code: "PROJECT_DELETE_FAILED", message };
28
30
  }
@@ -1,8 +1,8 @@
1
1
  import { buildDaemonConnectionCommandError, connectToDaemon } from "../../utils/client.js";
2
2
  import { projectSchema, toProjectRow } from "./shared.js";
3
3
  export async function runLsCommand(options, _command) {
4
- const client = await connectToDaemon({ host: options.host }).catch((error) => {
5
- throw buildDaemonConnectionCommandError({ host: options.host, error });
4
+ const client = await connectToDaemon({ target: options.daemonTarget }).catch((error) => {
5
+ throw buildDaemonConnectionCommandError({ target: options.daemonTarget, error });
6
6
  });
7
7
  try {
8
8
  const payload = await client.listProjects();
@@ -28,8 +28,8 @@ export function resolveProjectName(input) {
28
28
  }
29
29
  export async function runRenameCommand(projectId, nameArg, options, _command) {
30
30
  const name = resolveProjectName({ name: nameArg, reset: options.reset });
31
- const client = await connectToDaemon({ host: options.host }).catch((error) => {
32
- throw buildDaemonConnectionCommandError({ host: options.host, error });
31
+ const client = await connectToDaemon({ target: options.daemonTarget }).catch((error) => {
32
+ throw buildDaemonConnectionCommandError({ target: options.daemonTarget, error });
33
33
  });
34
34
  try {
35
35
  const applied = await client.renameProject(projectId, name);
@@ -40,6 +40,8 @@ export async function runRenameCommand(projectId, nameArg, options, _command) {
40
40
  };
41
41
  }
42
42
  catch (error) {
43
+ if (error && typeof error === "object" && "code" in error)
44
+ throw error;
43
45
  const message = error instanceof Error ? error.message : String(error);
44
46
  throw { code: "PROJECT_RENAME_FAILED", message };
45
47
  }
@@ -96,8 +96,8 @@ export async function runAddCommand(id, options, _command) {
96
96
  message: error instanceof Error ? error.message : String(error),
97
97
  };
98
98
  }
99
- const host = getDaemonHost({ host: options.host });
100
- const client = await connectToDaemon({ host: options.host }).catch((error) => {
99
+ const host = getDaemonHost({ target: options.daemonTarget });
100
+ const client = await connectToDaemon({ target: options.daemonTarget }).catch((error) => {
101
101
  const message = error instanceof Error ? error.message : String(error);
102
102
  throw {
103
103
  code: "DAEMON_NOT_RUNNING",
@@ -12,7 +12,7 @@ export const providerDiagnosticSchema = {
12
12
  },
13
13
  };
14
14
  export async function runDiagnosticCommand(provider, options, _command) {
15
- const client = await connectToDaemon({ host: options.host });
15
+ const client = await connectToDaemon({ target: options.daemonTarget });
16
16
  try {
17
17
  const result = await client.getProviderDiagnostic(provider.trim().toLowerCase());
18
18
  return {
@@ -1,18 +1,4 @@
1
- import { AGENT_PROVIDER_DEFINITIONS } from "@camerontaylor/paseo-protocol/provider-manifest";
2
- import { tryConnectToDaemon } from "../../utils/client.js";
3
- /** Derive provider list from the manifest — single source of truth */
4
- const PROVIDERS = AGENT_PROVIDER_DEFINITIONS.map((def) => ({
5
- provider: def.id,
6
- label: def.label,
7
- source: "builtin",
8
- status: "available",
9
- enabled: def.enabledByDefault === false ? "Disabled" : "Enabled",
10
- defaultMode: def.defaultModeId ?? "-",
11
- modes: def.modes.length > 0 ? def.modes.map((m) => m.label).join(", ") : "-",
12
- }));
13
- function getStaticProviders() {
14
- return PROVIDERS;
15
- }
1
+ import { connectToDaemon } from "../../utils/client.js";
16
2
  /** Schema for provider ls output */
17
3
  export const providerLsSchema = {
18
4
  idField: "provider",
@@ -38,14 +24,7 @@ export const providerLsSchema = {
38
24
  ],
39
25
  };
40
26
  export async function runLsCommand(options, _command) {
41
- const client = await tryConnectToDaemon({ host: options.host });
42
- if (!client) {
43
- return {
44
- type: "list",
45
- data: getStaticProviders(),
46
- schema: providerLsSchema,
47
- };
48
- }
27
+ const client = await connectToDaemon({ target: options.daemonTarget });
49
28
  try {
50
29
  const snapshot = await client.getProvidersSnapshot();
51
30
  return {
@@ -62,13 +41,6 @@ export async function runLsCommand(options, _command) {
62
41
  schema: providerLsSchema,
63
42
  };
64
43
  }
65
- catch {
66
- return {
67
- type: "list",
68
- data: getStaticProviders(),
69
- schema: providerLsSchema,
70
- };
71
- }
72
44
  finally {
73
45
  await client.close().catch(() => { });
74
46
  }
@@ -23,7 +23,7 @@ const providerModelsWithThinkingSchema = {
23
23
  };
24
24
  export async function runModelsCommand(provider, options, _command) {
25
25
  const normalizedProvider = provider.toLowerCase();
26
- const client = await connectToDaemon({ host: options.host });
26
+ const client = await connectToDaemon({ target: options.daemonTarget });
27
27
  try {
28
28
  const result = await client.listProviderModels(normalizedProvider);
29
29
  if (result.error) {
@@ -14,8 +14,8 @@ export async function runRmCommand(id, options, _command) {
14
14
  message: `"${id}" is a built-in provider and cannot be removed.`,
15
15
  };
16
16
  }
17
- const host = getDaemonHost({ host: options.host });
18
- const client = await connectToDaemon({ host: options.host }).catch((error) => {
17
+ const host = getDaemonHost({ target: options.daemonTarget });
18
+ const client = await connectToDaemon({ target: options.daemonTarget }).catch((error) => {
19
19
  const message = error instanceof Error ? error.message : String(error);
20
20
  throw {
21
21
  code: "DAEMON_NOT_RUNNING",
@@ -14,12 +14,12 @@ export async function runCreateCommand(prompt, options, command) {
14
14
  mode: options.mode,
15
15
  thinking: options.thinking,
16
16
  cwd: options.cwd,
17
- host: options.host,
17
+ daemonTarget: options.daemonTarget,
18
18
  maxRuns: options.maxRuns,
19
19
  expiresIn: options.expiresIn,
20
20
  runNow,
21
21
  });
22
- const { client } = await connectScheduleClient(options.host);
22
+ const { client } = await connectScheduleClient(options.daemonTarget);
23
23
  try {
24
24
  const payload = await client.scheduleCreate(input);
25
25
  if (payload.error || !payload.schedule) {