@hyperdrive.bot/paseo-cli 0.2.6

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 (212) hide show
  1. package/bin/paseo +3 -0
  2. package/dist/classify.d.ts +19 -0
  3. package/dist/classify.js +49 -0
  4. package/dist/cli.d.ts +3 -0
  5. package/dist/cli.js +119 -0
  6. package/dist/commands/agent/archive.d.ts +18 -0
  7. package/dist/commands/agent/archive.js +102 -0
  8. package/dist/commands/agent/attach.d.ts +11 -0
  9. package/dist/commands/agent/attach.js +159 -0
  10. package/dist/commands/agent/delete.d.ts +15 -0
  11. package/dist/commands/agent/delete.js +107 -0
  12. package/dist/commands/agent/import.d.ts +14 -0
  13. package/dist/commands/agent/import.js +122 -0
  14. package/dist/commands/agent/index.d.ts +3 -0
  15. package/dist/commands/agent/index.js +48 -0
  16. package/dist/commands/agent/inspect.d.ts +15 -0
  17. package/dist/commands/agent/inspect.js +209 -0
  18. package/dist/commands/agent/logs.d.ts +19 -0
  19. package/dist/commands/agent/logs.js +180 -0
  20. package/dist/commands/agent/ls.d.ts +44 -0
  21. package/dist/commands/agent/ls.js +204 -0
  22. package/dist/commands/agent/mode.d.ts +18 -0
  23. package/dist/commands/agent/mode.js +100 -0
  24. package/dist/commands/agent/reload.d.ts +15 -0
  25. package/dist/commands/agent/reload.js +75 -0
  26. package/dist/commands/agent/run.d.ts +44 -0
  27. package/dist/commands/agent/run.js +464 -0
  28. package/dist/commands/agent/send.d.ts +19 -0
  29. package/dist/commands/agent/send.js +187 -0
  30. package/dist/commands/agent/stop.d.ts +17 -0
  31. package/dist/commands/agent/stop.js +115 -0
  32. package/dist/commands/agent/update.d.ts +18 -0
  33. package/dist/commands/agent/update.js +139 -0
  34. package/dist/commands/agent/wait.d.ts +17 -0
  35. package/dist/commands/agent/wait.js +158 -0
  36. package/dist/commands/agent-hook.d.ts +7 -0
  37. package/dist/commands/agent-hook.js +67 -0
  38. package/dist/commands/chat/create.d.ts +9 -0
  39. package/dist/commands/chat/create.js +23 -0
  40. package/dist/commands/chat/delete.d.ts +6 -0
  41. package/dist/commands/chat/delete.js +20 -0
  42. package/dist/commands/chat/index.d.ts +3 -0
  43. package/dist/commands/chat/index.js +47 -0
  44. package/dist/commands/chat/inspect.d.ts +6 -0
  45. package/dist/commands/chat/inspect.js +20 -0
  46. package/dist/commands/chat/ls.d.ts +6 -0
  47. package/dist/commands/chat/ls.js +20 -0
  48. package/dist/commands/chat/post.d.ts +9 -0
  49. package/dist/commands/chat/post.js +28 -0
  50. package/dist/commands/chat/read.d.ts +11 -0
  51. package/dist/commands/chat/read.js +40 -0
  52. package/dist/commands/chat/schema.d.ts +36 -0
  53. package/dist/commands/chat/schema.js +81 -0
  54. package/dist/commands/chat/shared.d.ts +19 -0
  55. package/dist/commands/chat/shared.js +118 -0
  56. package/dist/commands/chat/wait.d.ts +9 -0
  57. package/dist/commands/chat/wait.js +45 -0
  58. package/dist/commands/daemon/index.d.ts +3 -0
  59. package/dist/commands/daemon/index.js +57 -0
  60. package/dist/commands/daemon/local-daemon.d.ts +78 -0
  61. package/dist/commands/daemon/local-daemon.js +544 -0
  62. package/dist/commands/daemon/pair.d.ts +9 -0
  63. package/dist/commands/daemon/pair.js +76 -0
  64. package/dist/commands/daemon/restart.d.ts +12 -0
  65. package/dist/commands/daemon/restart.js +99 -0
  66. package/dist/commands/daemon/runtime-toolchain.d.ts +6 -0
  67. package/dist/commands/daemon/runtime-toolchain.js +87 -0
  68. package/dist/commands/daemon/set-password.d.ts +17 -0
  69. package/dist/commands/daemon/set-password.js +82 -0
  70. package/dist/commands/daemon/start.d.ts +6 -0
  71. package/dist/commands/daemon/start.js +56 -0
  72. package/dist/commands/daemon/status.d.ts +10 -0
  73. package/dist/commands/daemon/status.js +338 -0
  74. package/dist/commands/daemon/stop.d.ts +15 -0
  75. package/dist/commands/daemon/stop.js +60 -0
  76. package/dist/commands/hooks.d.ts +19 -0
  77. package/dist/commands/hooks.js +89 -0
  78. package/dist/commands/loop/index.d.ts +3 -0
  79. package/dist/commands/loop/index.js +18 -0
  80. package/dist/commands/loop/inspect.d.ts +13 -0
  81. package/dist/commands/loop/inspect.js +100 -0
  82. package/dist/commands/loop/logs.d.ts +8 -0
  83. package/dist/commands/loop/logs.js +69 -0
  84. package/dist/commands/loop/ls.d.ts +18 -0
  85. package/dist/commands/loop/ls.js +62 -0
  86. package/dist/commands/loop/run.d.ts +30 -0
  87. package/dist/commands/loop/run.js +162 -0
  88. package/dist/commands/loop/stop.d.ts +15 -0
  89. package/dist/commands/loop/stop.js +56 -0
  90. package/dist/commands/loop/types.d.ts +138 -0
  91. package/dist/commands/loop/types.js +2 -0
  92. package/dist/commands/onboard.d.ts +10 -0
  93. package/dist/commands/onboard.js +416 -0
  94. package/dist/commands/open.d.ts +2 -0
  95. package/dist/commands/open.js +84 -0
  96. package/dist/commands/permit/allow.d.ts +20 -0
  97. package/dist/commands/permit/allow.js +133 -0
  98. package/dist/commands/permit/deny.d.ts +12 -0
  99. package/dist/commands/permit/deny.js +105 -0
  100. package/dist/commands/permit/index.d.ts +3 -0
  101. package/dist/commands/permit/index.js +27 -0
  102. package/dist/commands/permit/ls.d.ts +18 -0
  103. package/dist/commands/permit/ls.js +66 -0
  104. package/dist/commands/provider/index.d.ts +3 -0
  105. package/dist/commands/provider/index.js +16 -0
  106. package/dist/commands/provider/ls.d.ts +19 -0
  107. package/dist/commands/provider/ls.js +73 -0
  108. package/dist/commands/provider/models.d.ts +20 -0
  109. package/dist/commands/provider/models.js +53 -0
  110. package/dist/commands/schedule/create.d.ts +18 -0
  111. package/dist/commands/schedule/create.js +40 -0
  112. package/dist/commands/schedule/delete.d.ts +10 -0
  113. package/dist/commands/schedule/delete.js +32 -0
  114. package/dist/commands/schedule/index.d.ts +3 -0
  115. package/dist/commands/schedule/index.js +66 -0
  116. package/dist/commands/schedule/inspect.d.ts +6 -0
  117. package/dist/commands/schedule/inspect.js +24 -0
  118. package/dist/commands/schedule/logs.d.ts +6 -0
  119. package/dist/commands/schedule/logs.js +23 -0
  120. package/dist/commands/schedule/ls.d.ts +5 -0
  121. package/dist/commands/schedule/ls.js +23 -0
  122. package/dist/commands/schedule/pause.d.ts +5 -0
  123. package/dist/commands/schedule/pause.js +23 -0
  124. package/dist/commands/schedule/resume.d.ts +5 -0
  125. package/dist/commands/schedule/resume.js +23 -0
  126. package/dist/commands/schedule/run-once.d.ts +5 -0
  127. package/dist/commands/schedule/run-once.js +23 -0
  128. package/dist/commands/schedule/schema.d.ts +21 -0
  129. package/dist/commands/schedule/schema.js +67 -0
  130. package/dist/commands/schedule/shared.d.ts +56 -0
  131. package/dist/commands/schedule/shared.js +346 -0
  132. package/dist/commands/schedule/types.d.ts +168 -0
  133. package/dist/commands/schedule/types.js +2 -0
  134. package/dist/commands/schedule/update.d.ts +21 -0
  135. package/dist/commands/schedule/update.js +39 -0
  136. package/dist/commands/speech/index.d.ts +3 -0
  137. package/dist/commands/speech/index.js +5 -0
  138. package/dist/commands/terminal/capture.d.ts +10 -0
  139. package/dist/commands/terminal/capture.js +68 -0
  140. package/dist/commands/terminal/create.d.ts +10 -0
  141. package/dist/commands/terminal/create.js +38 -0
  142. package/dist/commands/terminal/index.d.ts +3 -0
  143. package/dist/commands/terminal/index.js +43 -0
  144. package/dist/commands/terminal/kill.d.ts +6 -0
  145. package/dist/commands/terminal/kill.js +36 -0
  146. package/dist/commands/terminal/ls.d.ts +10 -0
  147. package/dist/commands/terminal/ls.js +21 -0
  148. package/dist/commands/terminal/schema.d.ts +18 -0
  149. package/dist/commands/terminal/schema.js +23 -0
  150. package/dist/commands/terminal/send-keys.d.ts +7 -0
  151. package/dist/commands/terminal/send-keys.js +76 -0
  152. package/dist/commands/terminal/shared.d.ts +12 -0
  153. package/dist/commands/terminal/shared.js +61 -0
  154. package/dist/commands/workflow/get.d.ts +13 -0
  155. package/dist/commands/workflow/get.js +75 -0
  156. package/dist/commands/workflow/index.d.ts +10 -0
  157. package/dist/commands/workflow/index.js +21 -0
  158. package/dist/commands/workflow/start.d.ts +26 -0
  159. package/dist/commands/workflow/start.js +105 -0
  160. package/dist/commands/workflow/status.d.ts +17 -0
  161. package/dist/commands/workflow/status.js +57 -0
  162. package/dist/commands/worktree/archive.d.ts +20 -0
  163. package/dist/commands/worktree/archive.js +104 -0
  164. package/dist/commands/worktree/create-input.d.ts +15 -0
  165. package/dist/commands/worktree/create-input.js +56 -0
  166. package/dist/commands/worktree/create.d.ts +11 -0
  167. package/dist/commands/worktree/create.js +58 -0
  168. package/dist/commands/worktree/index.d.ts +3 -0
  169. package/dist/commands/worktree/index.js +25 -0
  170. package/dist/commands/worktree/ls.d.ts +19 -0
  171. package/dist/commands/worktree/ls.js +97 -0
  172. package/dist/index.d.ts +2 -0
  173. package/dist/index.js +6 -0
  174. package/dist/output/index.d.ts +45 -0
  175. package/dist/output/index.js +47 -0
  176. package/dist/output/json.d.ts +11 -0
  177. package/dist/output/json.js +37 -0
  178. package/dist/output/quiet.d.ts +9 -0
  179. package/dist/output/quiet.js +22 -0
  180. package/dist/output/render.d.ts +15 -0
  181. package/dist/output/render.js +83 -0
  182. package/dist/output/table.d.ts +13 -0
  183. package/dist/output/table.js +135 -0
  184. package/dist/output/types.d.ts +73 -0
  185. package/dist/output/types.js +8 -0
  186. package/dist/output/with-output.d.ts +41 -0
  187. package/dist/output/with-output.js +87 -0
  188. package/dist/output/yaml.d.ts +11 -0
  189. package/dist/output/yaml.js +38 -0
  190. package/dist/run.d.ts +14 -0
  191. package/dist/run.js +33 -0
  192. package/dist/utils/client-id.d.ts +2 -0
  193. package/dist/utils/client-id.js +37 -0
  194. package/dist/utils/client.d.ts +44 -0
  195. package/dist/utils/client.js +330 -0
  196. package/dist/utils/command-options.d.ts +6 -0
  197. package/dist/utils/command-options.js +17 -0
  198. package/dist/utils/duration.d.ts +7 -0
  199. package/dist/utils/duration.js +38 -0
  200. package/dist/utils/errors.d.ts +5 -0
  201. package/dist/utils/errors.js +10 -0
  202. package/dist/utils/hook-socket.d.ts +2 -0
  203. package/dist/utils/hook-socket.js +35 -0
  204. package/dist/utils/paths.d.ts +12 -0
  205. package/dist/utils/paths.js +22 -0
  206. package/dist/utils/provider-model.d.ts +11 -0
  207. package/dist/utils/provider-model.js +49 -0
  208. package/dist/utils/timeline.d.ts +11 -0
  209. package/dist/utils/timeline.js +11 -0
  210. package/dist/version.d.ts +2 -0
  211. package/dist/version.js +10 -0
  212. package/package.json +48 -0
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Command wrapper for automatic output rendering.
3
+ *
4
+ * Wraps command handlers to automatically render results and handle errors.
5
+ */
6
+ import type { Command } from "commander";
7
+ import type { AnyCommandResult, OutputOptions } from "./types.js";
8
+ /** Options that include output settings from global options */
9
+ export interface CommandOptions extends Partial<OutputOptions> {
10
+ /** Daemon host target from --host option */
11
+ host?: string;
12
+ /** JSON output flag from --json option */
13
+ json?: boolean;
14
+ [key: string]: unknown;
15
+ }
16
+ /**
17
+ * Wrap a command handler to automatically render output.
18
+ *
19
+ * The wrapped handler should return a CommandResult. The wrapper will:
20
+ * 1. Call the handler
21
+ * 2. Render the result using the appropriate format
22
+ * 3. Write to stdout
23
+ * 4. Handle errors by rendering to stderr and exiting with code 1
24
+ *
25
+ * @example
26
+ * ```typescript
27
+ * program
28
+ * .command('list')
29
+ * .action(withOutput(async (options) => {
30
+ * const data = await fetchData()
31
+ * return { type: 'list', data, schema }
32
+ * }))
33
+ * ```
34
+ */
35
+ export declare function withOutput<T, Args extends unknown[]>(handler: (...args: [...Args, CommandOptions, Command]) => Promise<AnyCommandResult<T>>): (...args: [...Args, CommandOptions, Command]) => Promise<void>;
36
+ /**
37
+ * Helper to create output options from partial input.
38
+ * Useful for testing or manual rendering.
39
+ */
40
+ export declare function createOutputOptions(partial?: Partial<OutputOptions>): OutputOptions;
41
+ //# sourceMappingURL=with-output.d.ts.map
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Command wrapper for automatic output rendering.
3
+ *
4
+ * Wraps command handlers to automatically render results and handle errors.
5
+ */
6
+ import { render, renderError, toCommandError, defaultOutputOptions } from "./render.js";
7
+ function normalizeFormat(raw) {
8
+ const value = typeof raw === "string" ? raw.trim().toLowerCase() : "";
9
+ // Common user expectation: "cli" means "table/human"
10
+ if (value === "cli")
11
+ return "table";
12
+ if (value === "table" || value === "json" || value === "yaml")
13
+ return value;
14
+ const error = {
15
+ code: "INVALID_FORMAT",
16
+ message: `Unsupported output format: ${String(raw)}`,
17
+ details: "Supported formats: table, json, yaml",
18
+ };
19
+ throw error;
20
+ }
21
+ /** Extract output options from command options */
22
+ function extractOutputOptions(options) {
23
+ const hasStructuredOutputSchema = typeof options.outputSchema === "string" && options.outputSchema.trim().length > 0;
24
+ if (hasStructuredOutputSchema) {
25
+ return {
26
+ format: "json",
27
+ quiet: false,
28
+ noHeaders: options.headers === false,
29
+ noColor: options.color === false,
30
+ };
31
+ }
32
+ return {
33
+ format: options.json ? "json" : normalizeFormat(options.format ?? defaultOutputOptions.format),
34
+ quiet: options.quiet ?? defaultOutputOptions.quiet,
35
+ noHeaders: options.headers === false, // Commander uses --no-headers -> headers: false
36
+ noColor: options.color === false, // Commander uses --no-color -> color: false
37
+ };
38
+ }
39
+ /**
40
+ * Wrap a command handler to automatically render output.
41
+ *
42
+ * The wrapped handler should return a CommandResult. The wrapper will:
43
+ * 1. Call the handler
44
+ * 2. Render the result using the appropriate format
45
+ * 3. Write to stdout
46
+ * 4. Handle errors by rendering to stderr and exiting with code 1
47
+ *
48
+ * @example
49
+ * ```typescript
50
+ * program
51
+ * .command('list')
52
+ * .action(withOutput(async (options) => {
53
+ * const data = await fetchData()
54
+ * return { type: 'list', data, schema }
55
+ * }))
56
+ * ```
57
+ */
58
+ export function withOutput(handler) {
59
+ return async (...args) => {
60
+ // Last two args are options and command
61
+ const command = args[args.length - 1];
62
+ // Use optsWithGlobals() to get both local and global options
63
+ const options = command.optsWithGlobals();
64
+ const outputOptions = extractOutputOptions(options);
65
+ try {
66
+ const result = await handler(...args);
67
+ const output = render(result, outputOptions);
68
+ if (output) {
69
+ process.stdout.write(output + "\n");
70
+ }
71
+ }
72
+ catch (error) {
73
+ const commandError = toCommandError(error);
74
+ const errorOutput = renderError(commandError, outputOptions);
75
+ process.stderr.write(errorOutput + "\n");
76
+ process.exit(1);
77
+ }
78
+ };
79
+ }
80
+ /**
81
+ * Helper to create output options from partial input.
82
+ * Useful for testing or manual rendering.
83
+ */
84
+ export function createOutputOptions(partial = {}) {
85
+ return { ...defaultOutputOptions, ...partial };
86
+ }
87
+ //# sourceMappingURL=with-output.js.map
@@ -0,0 +1,11 @@
1
+ /**
2
+ * YAML renderer for CLI output.
3
+ *
4
+ * Renders structured data as YAML for machine consumption and human readability.
5
+ */
6
+ import type { AnyCommandResult, OutputOptions } from "./types.js";
7
+ /** Render command result as YAML */
8
+ export declare function renderYaml<T>(result: AnyCommandResult<T>, _options: OutputOptions): string;
9
+ /** Render a single item as YAML document (for streaming) */
10
+ export declare function renderYamlDoc<T>(item: T, serialize?: (data: T) => unknown): string;
11
+ //# sourceMappingURL=yaml.d.ts.map
@@ -0,0 +1,38 @@
1
+ /**
2
+ * YAML renderer for CLI output.
3
+ *
4
+ * Renders structured data as YAML for machine consumption and human readability.
5
+ */
6
+ import YAML from "yaml";
7
+ /** Render command result as YAML */
8
+ export function renderYaml(result, _options) {
9
+ const { schema } = result;
10
+ // Apply custom serializer if provided
11
+ if (schema.serialize) {
12
+ if (result.type === "list") {
13
+ // If all items serialize to the same object, return just one
14
+ // This handles the case where a list of key-value rows should serialize
15
+ // to a single structured object
16
+ const serialized = result.data.map((item) => schema.serialize(item));
17
+ if (serialized.length > 0) {
18
+ const first = JSON.stringify(serialized[0]);
19
+ const allSame = serialized.every((s) => JSON.stringify(s) === first);
20
+ if (allSame) {
21
+ return YAML.stringify(serialized[0]);
22
+ }
23
+ }
24
+ return YAML.stringify(serialized);
25
+ }
26
+ else {
27
+ const serialized = schema.serialize(result.data);
28
+ return YAML.stringify(serialized);
29
+ }
30
+ }
31
+ return YAML.stringify(result.data);
32
+ }
33
+ /** Render a single item as YAML document (for streaming) */
34
+ export function renderYamlDoc(item, serialize) {
35
+ const output = serialize ? serialize(item) : item;
36
+ return YAML.stringify(output);
37
+ }
38
+ //# sourceMappingURL=yaml.js.map
package/dist/run.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ export interface RunCliOptions {
2
+ cwd?: string;
3
+ nodeArgv?: [string, string];
4
+ }
5
+ export declare function createCliParseArgv(input: {
6
+ argv: string[];
7
+ cwd: string;
8
+ nodeArgv?: [string, string];
9
+ }): string[] | {
10
+ kind: "open-project";
11
+ resolvedPath: string;
12
+ };
13
+ export declare function runCli(argv: string[], options?: RunCliOptions): Promise<number>;
14
+ //# sourceMappingURL=run.d.ts.map
package/dist/run.js ADDED
@@ -0,0 +1,33 @@
1
+ import { createCli } from "./cli.js";
2
+ import { classifyInvocation } from "./classify.js";
3
+ import { openDesktopWithProject } from "./commands/open.js";
4
+ export function createCliParseArgv(input) {
5
+ const program = createCli();
6
+ const knownCommands = new Set(program.commands.map((command) => command.name()));
7
+ const invocation = classifyInvocation({
8
+ argv: input.argv,
9
+ knownCommands,
10
+ cwd: input.cwd,
11
+ });
12
+ if (invocation.kind === "open-project") {
13
+ return invocation;
14
+ }
15
+ const nodeArgv = input.nodeArgv ?? ["paseo", "paseo"];
16
+ const cliArgv = invocation.argv.length === 0 ? ["onboard"] : invocation.argv;
17
+ return [...nodeArgv, ...cliArgv];
18
+ }
19
+ export async function runCli(argv, options = {}) {
20
+ const parseArgv = createCliParseArgv({
21
+ argv,
22
+ cwd: options.cwd ?? process.cwd(),
23
+ nodeArgv: options.nodeArgv,
24
+ });
25
+ if (!Array.isArray(parseArgv)) {
26
+ await openDesktopWithProject(parseArgv.resolvedPath);
27
+ return typeof process.exitCode === "number" ? process.exitCode : 0;
28
+ }
29
+ const program = createCli();
30
+ await program.parseAsync(parseArgv, { from: "node" });
31
+ return typeof process.exitCode === "number" ? process.exitCode : 0;
32
+ }
33
+ //# sourceMappingURL=run.js.map
@@ -0,0 +1,2 @@
1
+ export declare function getOrCreateCliClientId(): Promise<string>;
2
+ //# sourceMappingURL=client-id.d.ts.map
@@ -0,0 +1,37 @@
1
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
2
+ import { randomUUID } from "node:crypto";
3
+ import { dirname, join } from "node:path";
4
+ import { homedir } from "node:os";
5
+ const CLIENT_SESSION_KEY_FILE = join(process.env.PASEO_HOME ?? join(homedir(), ".paseo"), "cli-client-id");
6
+ let cachedClientId = null;
7
+ function normalizeClientId(value) {
8
+ const trimmed = value.trim();
9
+ return trimmed.length > 0 ? trimmed : null;
10
+ }
11
+ function generateClientId() {
12
+ return `cid_${randomUUID().replace(/-/g, "")}`;
13
+ }
14
+ export async function getOrCreateCliClientId() {
15
+ if (cachedClientId) {
16
+ return cachedClientId;
17
+ }
18
+ try {
19
+ const existing = normalizeClientId(await readFile(CLIENT_SESSION_KEY_FILE, "utf8"));
20
+ if (existing) {
21
+ cachedClientId = existing;
22
+ return existing;
23
+ }
24
+ }
25
+ catch (error) {
26
+ const code = error?.code;
27
+ if (code !== "ENOENT") {
28
+ throw error;
29
+ }
30
+ }
31
+ const nextValue = generateClientId();
32
+ await mkdir(dirname(CLIENT_SESSION_KEY_FILE), { recursive: true });
33
+ await writeFile(CLIENT_SESSION_KEY_FILE, nextValue, { mode: 0o600 });
34
+ cachedClientId = nextValue;
35
+ return nextValue;
36
+ }
37
+ //# sourceMappingURL=client-id.js.map
@@ -0,0 +1,44 @@
1
+ import { DaemonClient } from "@hyperdrive.bot/paseo-client/internal/daemon-client";
2
+ export interface ConnectOptions {
3
+ host?: string;
4
+ timeout?: number;
5
+ }
6
+ type DaemonTarget = {
7
+ type: "tcp";
8
+ url: string;
9
+ } | {
10
+ type: "ipc";
11
+ url: string;
12
+ socketPath: string;
13
+ };
14
+ /**
15
+ * Get the daemon host from environment or options
16
+ */
17
+ export declare function getDaemonHost(options?: ConnectOptions): string;
18
+ export declare function normalizeDaemonHost(raw: string): string | null;
19
+ export declare function resolveDefaultDaemonHost(env?: NodeJS.ProcessEnv): string;
20
+ export declare function resolveDefaultDaemonHosts(env?: NodeJS.ProcessEnv): string[];
21
+ export declare function resolveDaemonTarget(host: string): DaemonTarget;
22
+ export declare function resolveDaemonPassword(host: string): string | undefined;
23
+ export declare function connectToDaemon(options?: ConnectOptions): Promise<DaemonClient>;
24
+ /**
25
+ * Try to connect to the daemon, returns null if connection fails
26
+ */
27
+ export declare function tryConnectToDaemon(options?: ConnectOptions): Promise<DaemonClient | null>;
28
+ /** Minimal agent type for ID resolution */
29
+ interface AgentLike {
30
+ id: string;
31
+ title?: string | null;
32
+ }
33
+ /**
34
+ * Resolve an agent ID from a partial ID or name.
35
+ * Supports:
36
+ * - Full ID match
37
+ * - Prefix match (first N characters)
38
+ * - Title/name match (case-insensitive)
39
+ *
40
+ * Returns the full agent ID if found, null otherwise.
41
+ */
42
+ export declare function resolveAgentId(idOrName: string, agents: AgentLike[]): string | null;
43
+ export {};
44
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1,330 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { loadConfig, resolvePaseoHome } from "@hyperdrive.bot/paseo-server";
3
+ import { buildDaemonWebSocketUrl, buildRelayWebSocketUrl, normalizeHostPort, parseConnectionUri, shouldUseTlsForDefaultHostedRelay, } from "@hyperdrive.bot/paseo-protocol/daemon-endpoints";
4
+ import { parseConnectionOfferFromUrl, } from "@hyperdrive.bot/paseo-protocol/connection-offer";
5
+ import { DaemonClient, } from "@hyperdrive.bot/paseo-client/internal/daemon-client";
6
+ import path from "node:path";
7
+ import { WebSocket } from "ws";
8
+ import { getOrCreateCliClientId } from "./client-id.js";
9
+ import { resolveCliVersion } from "../version.js";
10
+ const DEFAULT_HOST = "localhost:6767";
11
+ const DEFAULT_TIMEOUT = 15000;
12
+ const PID_FILENAME = "paseo.pid";
13
+ /**
14
+ * Get the daemon host from environment or options
15
+ */
16
+ export function getDaemonHost(options) {
17
+ return resolveDaemonHostCandidates(options)[0] ?? DEFAULT_HOST;
18
+ }
19
+ export function normalizeDaemonHost(raw) {
20
+ const trimmed = raw.trim();
21
+ if (!trimmed) {
22
+ return null;
23
+ }
24
+ if (trimmed.startsWith("tcp://")) {
25
+ try {
26
+ const parsed = parseConnectionUri(trimmed);
27
+ const endpoint = normalizeHostPort(parsed.isIpv6 ? `[${parsed.host}]:${parsed.port}` : `${parsed.host}:${parsed.port}`);
28
+ const query = new URLSearchParams();
29
+ if (parsed.useTls) {
30
+ query.set("ssl", "true");
31
+ }
32
+ if (parsed.password) {
33
+ query.set("password", parsed.password);
34
+ }
35
+ const queryString = query.toString();
36
+ const suffix = queryString ? `?${queryString}` : "";
37
+ return `tcp://${endpoint}${suffix}`;
38
+ }
39
+ catch {
40
+ return null;
41
+ }
42
+ }
43
+ if (trimmed.startsWith("unix://") ||
44
+ trimmed.startsWith("pipe://") ||
45
+ trimmed.startsWith("\\\\.\\pipe\\")) {
46
+ return trimmed.startsWith("\\\\.\\pipe\\") ? `pipe://${trimmed}` : trimmed;
47
+ }
48
+ if (trimmed.startsWith("/") || trimmed.startsWith("~")) {
49
+ return `unix://${trimmed}`;
50
+ }
51
+ // Windows absolute paths (e.g. C:\Users\foo) are filesystem paths, not TCP or IPC targets.
52
+ if (/^[A-Za-z]:[/\\]/.test(trimmed)) {
53
+ return null;
54
+ }
55
+ if (/^\d+$/.test(trimmed)) {
56
+ return `127.0.0.1:${trimmed}`;
57
+ }
58
+ return trimmed.includes(":") ? trimmed : null;
59
+ }
60
+ export function resolveDefaultDaemonHost(env = process.env) {
61
+ return resolveDefaultDaemonHosts(env)[0] ?? DEFAULT_HOST;
62
+ }
63
+ function isIpcDaemonHost(host) {
64
+ return host !== null && (host.startsWith("unix://") || host.startsWith("pipe://"));
65
+ }
66
+ function isTcpDaemonHost(host) {
67
+ return host !== null && !isIpcDaemonHost(host);
68
+ }
69
+ function readPidSocketTarget(paseoHome) {
70
+ const pidPath = path.join(paseoHome, PID_FILENAME);
71
+ if (!existsSync(pidPath)) {
72
+ return null;
73
+ }
74
+ try {
75
+ const parsed = JSON.parse(readFileSync(pidPath, "utf-8"));
76
+ if (typeof parsed.listen === "string")
77
+ return parsed.listen;
78
+ if (typeof parsed.sockPath === "string")
79
+ return parsed.sockPath;
80
+ return null;
81
+ }
82
+ catch {
83
+ return null;
84
+ }
85
+ }
86
+ function resolveConfiguredIpcDaemonHost(env, paseoHome) {
87
+ const directEnvHost = normalizeDaemonHost(env.PASEO_LISTEN ?? "");
88
+ if (isIpcDaemonHost(directEnvHost)) {
89
+ return directEnvHost;
90
+ }
91
+ const pidHost = normalizeDaemonHost(readPidSocketTarget(paseoHome) ?? "");
92
+ if (isIpcDaemonHost(pidHost)) {
93
+ return pidHost;
94
+ }
95
+ const config = loadConfig(paseoHome, { env });
96
+ const configuredHost = normalizeDaemonHost(config.listen);
97
+ return isIpcDaemonHost(configuredHost) ? configuredHost : null;
98
+ }
99
+ function resolveConfiguredTcpDaemonHost(env, paseoHome) {
100
+ const configuredHost = normalizeDaemonHost(loadConfig(paseoHome, { env }).listen);
101
+ if (!isTcpDaemonHost(configuredHost)) {
102
+ return null;
103
+ }
104
+ return configuredHost === "127.0.0.1:6767" ? null : configuredHost;
105
+ }
106
+ export function resolveDefaultDaemonHosts(env = process.env) {
107
+ const paseoHome = resolvePaseoHome(env);
108
+ const candidates = [];
109
+ const configuredIpcHost = resolveConfiguredIpcDaemonHost(env, paseoHome);
110
+ if (configuredIpcHost) {
111
+ candidates.push(configuredIpcHost);
112
+ }
113
+ const configuredTcpHost = resolveConfiguredTcpDaemonHost(env, paseoHome);
114
+ if (configuredTcpHost) {
115
+ candidates.push(configuredTcpHost);
116
+ }
117
+ candidates.push(DEFAULT_HOST);
118
+ return Array.from(new Set(candidates));
119
+ }
120
+ function resolveDaemonHostCandidates(options) {
121
+ const explicitHost = options?.host ?? process.env.PASEO_HOST;
122
+ if (explicitHost) {
123
+ return [explicitHost];
124
+ }
125
+ return resolveDefaultDaemonHosts();
126
+ }
127
+ function stripIpcPrefix(trimmed) {
128
+ if (trimmed.startsWith("unix://"))
129
+ return trimmed.slice("unix://".length).trim();
130
+ if (trimmed.startsWith("pipe://"))
131
+ return trimmed.slice("pipe://".length).trim();
132
+ return trimmed;
133
+ }
134
+ export function resolveDaemonTarget(host) {
135
+ const trimmed = host.trim();
136
+ if (trimmed.startsWith("unix://") ||
137
+ trimmed.startsWith("pipe://") ||
138
+ trimmed.startsWith("\\\\.\\pipe\\")) {
139
+ const socketPath = stripIpcPrefix(trimmed);
140
+ if (!socketPath) {
141
+ throw new Error("Invalid IPC daemon target: missing socket path");
142
+ }
143
+ const isUnixSocket = trimmed.startsWith("unix://");
144
+ return {
145
+ type: "ipc",
146
+ url: isUnixSocket ? `ws+unix://${socketPath}:/ws` : "ws://localhost/ws",
147
+ socketPath,
148
+ };
149
+ }
150
+ if (trimmed.startsWith("tcp://")) {
151
+ const parsed = parseConnectionUri(trimmed);
152
+ const endpoint = normalizeHostPort(parsed.isIpv6 ? `[${parsed.host}]:${parsed.port}` : `${parsed.host}:${parsed.port}`);
153
+ return {
154
+ type: "tcp",
155
+ url: buildDaemonWebSocketUrl(endpoint, { useTls: parsed.useTls }),
156
+ };
157
+ }
158
+ return {
159
+ type: "tcp",
160
+ url: `ws://${trimmed}/ws`,
161
+ };
162
+ }
163
+ export function resolveDaemonPassword(host) {
164
+ const trimmed = host.trim();
165
+ if (trimmed.startsWith("tcp://")) {
166
+ const fromUri = parseConnectionUri(trimmed).password;
167
+ if (fromUri)
168
+ return fromUri;
169
+ }
170
+ const fromEnv = process.env.PASEO_PASSWORD;
171
+ return fromEnv && fromEnv.length > 0 ? fromEnv : undefined;
172
+ }
173
+ /**
174
+ * Create a WebSocket factory that works in Node.js
175
+ */
176
+ function createNodeWebSocketFactory() {
177
+ return (url, options) => {
178
+ return new WebSocket(url, options?.protocols, {
179
+ headers: options?.headers,
180
+ ...(options?.socketPath ? { socketPath: options.socketPath } : {}),
181
+ });
182
+ };
183
+ }
184
+ /**
185
+ * Create and connect a daemon client
186
+ * Returns the connected client or throws if connection fails
187
+ */
188
+ async function tryConnectHost(host, password, clientId, timeout, nodeWebSocketFactory) {
189
+ const target = resolveDaemonTarget(host);
190
+ const client = new DaemonClient({
191
+ url: target.url,
192
+ clientId,
193
+ clientType: "cli",
194
+ appVersion: resolveCliVersion(),
195
+ password,
196
+ connectTimeoutMs: timeout,
197
+ webSocketFactory: (url, config) => nodeWebSocketFactory(url, {
198
+ headers: config?.headers,
199
+ protocols: config?.protocols,
200
+ ...(target.type === "ipc" ? { socketPath: target.socketPath } : {}),
201
+ }),
202
+ reconnect: { enabled: false },
203
+ });
204
+ try {
205
+ await client.connect();
206
+ return { client };
207
+ }
208
+ catch (error) {
209
+ await client.close().catch(() => { });
210
+ return { error };
211
+ }
212
+ }
213
+ async function connectViaRelayOffer(offer, clientId, timeout, nodeWebSocketFactory) {
214
+ const url = buildRelayWebSocketUrl({
215
+ endpoint: offer.relay.endpoint,
216
+ serverId: offer.serverId,
217
+ role: "client",
218
+ useTls: offer.relay.useTls ?? shouldUseTlsForDefaultHostedRelay(offer.relay.endpoint),
219
+ });
220
+ const client = new DaemonClient({
221
+ url,
222
+ clientId,
223
+ clientType: "cli",
224
+ appVersion: resolveCliVersion(),
225
+ connectTimeoutMs: timeout,
226
+ webSocketFactory: (target, config) => nodeWebSocketFactory(target, { headers: config?.headers, protocols: config?.protocols }),
227
+ e2ee: { enabled: true, daemonPublicKeyB64: offer.daemonPublicKeyB64 },
228
+ reconnect: { enabled: false },
229
+ });
230
+ try {
231
+ await client.connect();
232
+ return client;
233
+ }
234
+ catch (error) {
235
+ await client.close().catch(() => { });
236
+ const message = error instanceof Error ? error.message : String(error);
237
+ const lastError = client.lastError ? ` (${client.lastError})` : "";
238
+ throw new Error(`Failed to connect via relay offer: ${message}${lastError}`, { cause: error });
239
+ }
240
+ }
241
+ function parseHostOfferOrNull(host) {
242
+ if (!host)
243
+ return null;
244
+ try {
245
+ return parseConnectionOfferFromUrl(host);
246
+ }
247
+ catch (error) {
248
+ const message = error instanceof Error ? error.message : String(error);
249
+ throw new Error(`Invalid pairing offer URL: ${message}`, { cause: error });
250
+ }
251
+ }
252
+ export async function connectToDaemon(options) {
253
+ const timeout = options?.timeout ?? DEFAULT_TIMEOUT;
254
+ const clientId = await getOrCreateCliClientId();
255
+ const nodeWebSocketFactory = createNodeWebSocketFactory();
256
+ const explicitHost = options?.host ?? process.env.PASEO_HOST;
257
+ const offer = parseHostOfferOrNull(explicitHost);
258
+ if (offer) {
259
+ return connectViaRelayOffer(offer, clientId, timeout, nodeWebSocketFactory);
260
+ }
261
+ const hosts = resolveDaemonHostCandidates(options);
262
+ async function tryNext(index, lastError) {
263
+ if (index >= hosts.length) {
264
+ if (lastError instanceof Error)
265
+ throw lastError;
266
+ throw new Error(`Unable to connect to Paseo daemon via ${hosts.join(", ")}`);
267
+ }
268
+ const host = hosts[index];
269
+ const password = resolveDaemonPassword(host);
270
+ const result = await tryConnectHost(host, password, clientId, timeout, nodeWebSocketFactory);
271
+ if ("client" in result) {
272
+ return result.client;
273
+ }
274
+ return tryNext(index + 1, result.error);
275
+ }
276
+ return tryNext(0, null);
277
+ }
278
+ /**
279
+ * Try to connect to the daemon, returns null if connection fails
280
+ */
281
+ export async function tryConnectToDaemon(options) {
282
+ try {
283
+ return await connectToDaemon(options);
284
+ }
285
+ catch {
286
+ return null;
287
+ }
288
+ }
289
+ /**
290
+ * Resolve an agent ID from a partial ID or name.
291
+ * Supports:
292
+ * - Full ID match
293
+ * - Prefix match (first N characters)
294
+ * - Title/name match (case-insensitive)
295
+ *
296
+ * Returns the full agent ID if found, null otherwise.
297
+ */
298
+ export function resolveAgentId(idOrName, agents) {
299
+ if (!idOrName || agents.length === 0) {
300
+ return null;
301
+ }
302
+ const query = idOrName.toLowerCase();
303
+ // Try exact ID match first
304
+ const exactMatch = agents.find((a) => a.id === idOrName);
305
+ if (exactMatch) {
306
+ return exactMatch.id;
307
+ }
308
+ // Try ID prefix match
309
+ const prefixMatches = agents.filter((a) => a.id.toLowerCase().startsWith(query));
310
+ if (prefixMatches.length === 1 && prefixMatches[0]) {
311
+ return prefixMatches[0].id;
312
+ }
313
+ // Try title/name match (case-insensitive)
314
+ const titleMatches = agents.filter((a) => a.title?.toLowerCase() === query);
315
+ if (titleMatches.length === 1 && titleMatches[0]) {
316
+ return titleMatches[0].id;
317
+ }
318
+ // Try partial title match
319
+ const partialTitleMatches = agents.filter((a) => a.title?.toLowerCase().includes(query));
320
+ if (partialTitleMatches.length === 1 && partialTitleMatches[0]) {
321
+ return partialTitleMatches[0].id;
322
+ }
323
+ // If we have multiple prefix matches and no unique title match, return first prefix match
324
+ const firstPrefixMatch = prefixMatches[0];
325
+ if (firstPrefixMatch) {
326
+ return firstPrefixMatch.id;
327
+ }
328
+ return null;
329
+ }
330
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1,6 @@
1
+ import type { Command } from "commander";
2
+ export declare function collectMultiple(value: string, previous: string[]): string[];
3
+ export declare function addJsonOption<T extends Command>(command: T): T;
4
+ export declare function addDaemonHostOption<T extends Command>(command: T): T;
5
+ export declare function addJsonAndDaemonHostOptions<T extends Command>(command: T): T;
6
+ //# sourceMappingURL=command-options.d.ts.map
@@ -0,0 +1,17 @@
1
+ const JSON_OPTION_DESCRIPTION = "Output in JSON format";
2
+ const DAEMON_HOST_OPTION_DESCRIPTION = "Daemon host target: host:port or tcp://host:port?ssl=true&password=secret (default: local socket/pipe, then localhost:6767)";
3
+ export function collectMultiple(value, previous) {
4
+ return previous.concat([value]);
5
+ }
6
+ export function addJsonOption(command) {
7
+ command.option("--json", JSON_OPTION_DESCRIPTION);
8
+ return command;
9
+ }
10
+ export function addDaemonHostOption(command) {
11
+ command.option("--host <host>", DAEMON_HOST_OPTION_DESCRIPTION);
12
+ return command;
13
+ }
14
+ export function addJsonAndDaemonHostOptions(command) {
15
+ return addDaemonHostOption(addJsonOption(command));
16
+ }
17
+ //# sourceMappingURL=command-options.js.map
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Parse duration string to milliseconds.
3
+ * Supports formats like: 5m, 30s, 1h, 2h30m, 90, etc.
4
+ * If no unit is specified, assumes seconds.
5
+ */
6
+ export declare function parseDuration(input: string): number;
7
+ //# sourceMappingURL=duration.d.ts.map