@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.
- package/dist/cli.js +44 -37
- package/dist/commands/agent/archive.js +2 -15
- package/dist/commands/agent/attach.d.ts +1 -0
- package/dist/commands/agent/attach.js +8 -12
- package/dist/commands/agent/delete.js +4 -15
- package/dist/commands/agent/detach.js +2 -13
- package/dist/commands/agent/import.js +2 -16
- package/dist/commands/agent/inspect.js +2 -15
- package/dist/commands/agent/logs.js +13 -13
- package/dist/commands/agent/ls.js +2 -23
- package/dist/commands/agent/mode.js +2 -2
- package/dist/commands/agent/open.js +2 -8
- package/dist/commands/agent/reload.js +2 -15
- package/dist/commands/agent/run.js +12 -17
- package/dist/commands/agent/send.js +6 -15
- package/dist/commands/agent/stop.js +2 -15
- package/dist/commands/agent/update.js +2 -15
- package/dist/commands/agent/wait.js +4 -15
- package/dist/commands/clone.js +2 -8
- package/dist/commands/daemon/config.d.ts +3 -0
- package/dist/commands/daemon/config.js +103 -0
- package/dist/commands/daemon/index.js +20 -52
- package/dist/commands/daemon/local-daemon.d.ts +10 -75
- package/dist/commands/daemon/local-daemon.js +61 -503
- package/dist/commands/daemon/pair.d.ts +3 -8
- package/dist/commands/daemon/pair.js +33 -61
- package/dist/commands/daemon/reload.d.ts +3 -1
- package/dist/commands/daemon/reload.js +10 -2
- package/dist/commands/daemon/restart.d.ts +19 -11
- package/dist/commands/daemon/restart.js +102 -88
- package/dist/commands/daemon/runtime-toolchain.js +1 -1
- package/dist/commands/daemon/set-password.js +8 -7
- package/dist/commands/daemon/start.d.ts +17 -3
- package/dist/commands/daemon/start.js +47 -52
- package/dist/commands/daemon/status.d.ts +12 -20
- package/dist/commands/daemon/status.js +91 -342
- package/dist/commands/daemon/stop.d.ts +19 -14
- package/dist/commands/daemon/stop.js +53 -55
- package/dist/commands/heartbeat/index.js +3 -3
- package/dist/commands/hub/connect.d.ts +1 -0
- package/dist/commands/hub/connect.js +1 -1
- package/dist/commands/hub/daemon-client.d.ts +3 -2
- package/dist/commands/hub/daemon-client.js +3 -3
- package/dist/commands/hub/disconnect.d.ts +1 -0
- package/dist/commands/hub/disconnect.js +1 -1
- package/dist/commands/hub/index.js +2 -2
- package/dist/commands/hub/init.d.ts +3 -1
- package/dist/commands/hub/init.js +13 -12
- package/dist/commands/hub/login.d.ts +4 -4
- package/dist/commands/hub/login.js +1 -1
- package/dist/commands/hub/logout.d.ts +1 -0
- package/dist/commands/hub/logout.js +2 -2
- package/dist/commands/hub/permissions.d.ts +1 -0
- package/dist/commands/hub/permissions.js +2 -2
- package/dist/commands/onboard.d.ts +7 -2
- package/dist/commands/onboard.js +59 -210
- package/dist/commands/open.js +3 -1
- package/dist/commands/permit/allow.js +2 -15
- package/dist/commands/permit/deny.js +2 -15
- package/dist/commands/permit/ls.js +2 -15
- package/dist/commands/plugin/index.d.ts +6 -0
- package/dist/commands/plugin/index.js +62 -46
- package/dist/commands/plugin/scaffold.js +10 -0
- package/dist/commands/plugin/shared.d.ts +5 -3
- package/dist/commands/plugin/shared.js +13 -9
- package/dist/commands/plugin/update.d.ts +37 -0
- package/dist/commands/plugin/update.js +58 -0
- package/dist/commands/project/create.js +5 -3
- package/dist/commands/project/delete.js +4 -2
- package/dist/commands/project/ls.js +2 -2
- package/dist/commands/project/rename.js +4 -2
- package/dist/commands/provider/add.js +2 -2
- package/dist/commands/provider/diagnostic.js +1 -1
- package/dist/commands/provider/ls.js +2 -30
- package/dist/commands/provider/models.js +1 -1
- package/dist/commands/provider/rm.js +2 -2
- package/dist/commands/schedule/create.js +2 -2
- package/dist/commands/schedule/delete.js +1 -1
- package/dist/commands/schedule/inspect.js +1 -1
- package/dist/commands/schedule/logs.js +1 -1
- package/dist/commands/schedule/ls.js +1 -1
- package/dist/commands/schedule/pause.js +1 -1
- package/dist/commands/schedule/resume.js +1 -1
- package/dist/commands/schedule/run-once.js +1 -1
- package/dist/commands/schedule/shared.d.ts +3 -1
- package/dist/commands/schedule/shared.js +7 -5
- package/dist/commands/schedule/update.js +1 -1
- package/dist/commands/script/ls.js +1 -1
- package/dist/commands/script/shared.d.ts +2 -1
- package/dist/commands/script/shared.js +3 -3
- package/dist/commands/script/start.js +1 -1
- package/dist/commands/script/stop.js +1 -1
- package/dist/commands/terminal/capture.d.ts +1 -1
- package/dist/commands/terminal/capture.js +2 -3
- package/dist/commands/terminal/create.js +1 -1
- package/dist/commands/terminal/kill.js +1 -1
- package/dist/commands/terminal/ls.js +1 -1
- package/dist/commands/terminal/send-keys.d.ts +1 -1
- package/dist/commands/terminal/send-keys.js +2 -3
- package/dist/commands/terminal/shared.d.ts +2 -1
- package/dist/commands/terminal/shared.js +5 -3
- package/dist/commands/workspace/archive.d.ts +1 -0
- package/dist/commands/workspace/archive.js +4 -2
- package/dist/commands/workspace/create.js +4 -2
- package/dist/commands/workspace/ls.d.ts +1 -0
- package/dist/commands/workspace/ls.js +2 -2
- package/dist/commands/workspace/rename.d.ts +1 -0
- package/dist/commands/workspace/rename.js +4 -2
- package/dist/commands/workspace/setup.d.ts +1 -0
- package/dist/commands/workspace/setup.js +2 -2
- package/dist/commands/worktree/archive.js +4 -2
- package/dist/commands/worktree/create.js +2 -10
- package/dist/commands/worktree/ls.d.ts +0 -2
- package/dist/commands/worktree/ls.js +4 -30
- package/dist/output/with-output.d.ts +2 -0
- package/dist/run.js +11 -1
- package/dist/utils/client-id.d.ts +1 -1
- package/dist/utils/client-id.js +8 -14
- package/dist/utils/client.d.ts +16 -21
- package/dist/utils/client.js +57 -109
- package/dist/utils/command-options.d.ts +1 -0
- package/dist/utils/command-options.js +26 -2
- package/dist/utils/daemon-target.d.ts +13 -0
- package/dist/utils/daemon-target.js +51 -0
- package/package.json +8 -4
package/dist/utils/client.d.ts
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
|
+
import { type DaemonInstance } from "@camerontaylor/paseo-server/daemon-control";
|
|
2
|
+
import { type DaemonTarget } from "./daemon-target.js";
|
|
3
|
+
export type { DaemonTarget } from "./daemon-target.js";
|
|
1
4
|
import { DaemonClient } from "@camerontaylor/paseo-client/internal/daemon-client";
|
|
2
5
|
export interface ConnectOptions {
|
|
3
|
-
|
|
6
|
+
target: DaemonTarget;
|
|
4
7
|
timeout?: number;
|
|
8
|
+
instance?: DaemonInstance;
|
|
5
9
|
}
|
|
6
|
-
|
|
7
|
-
code: "DAEMON_NOT_RUNNING";
|
|
8
|
-
message: string;
|
|
9
|
-
details: string;
|
|
10
|
-
}
|
|
11
|
-
type DaemonTarget = {
|
|
10
|
+
type TransportTarget = {
|
|
12
11
|
type: "tcp";
|
|
13
12
|
url: string;
|
|
14
13
|
} | {
|
|
@@ -16,25 +15,22 @@ type DaemonTarget = {
|
|
|
16
15
|
url: string;
|
|
17
16
|
socketPath: string;
|
|
18
17
|
};
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
*/
|
|
22
|
-
export declare function getDaemonHost(options?: ConnectOptions): string;
|
|
23
|
-
export declare function buildDaemonConnectionCommandError(options: {
|
|
24
|
-
host?: string;
|
|
18
|
+
export declare function getDaemonHost(options: ConnectOptions): string;
|
|
19
|
+
export declare function buildDaemonConnectionCommandError(options: ConnectOptions & {
|
|
25
20
|
error: unknown;
|
|
26
|
-
}):
|
|
21
|
+
}): {
|
|
22
|
+
code: string;
|
|
23
|
+
message: string;
|
|
24
|
+
details: string;
|
|
25
|
+
};
|
|
27
26
|
export declare function normalizeDaemonHost(raw: string): string | null;
|
|
28
|
-
export declare function
|
|
29
|
-
export declare function resolveDefaultDaemonHosts(env?: NodeJS.ProcessEnv): string[];
|
|
30
|
-
export declare function getExplicitDaemonHost(host: string | undefined, env?: NodeJS.ProcessEnv): string | undefined;
|
|
31
|
-
export declare function resolveDaemonTarget(host: string): DaemonTarget;
|
|
27
|
+
export declare function resolveDaemonTarget(host: string): TransportTarget;
|
|
32
28
|
export declare function resolveDaemonPassword(host: string): string | undefined;
|
|
33
|
-
export declare function connectToDaemon(options
|
|
29
|
+
export declare function connectToDaemon(options: ConnectOptions): Promise<DaemonClient>;
|
|
34
30
|
/**
|
|
35
31
|
* Try to connect to the daemon, returns null if connection fails
|
|
36
32
|
*/
|
|
37
|
-
export declare function tryConnectToDaemon(options
|
|
33
|
+
export declare function tryConnectToDaemon(options: ConnectOptions): Promise<DaemonClient | null>;
|
|
38
34
|
/** Minimal agent type for ID resolution */
|
|
39
35
|
interface AgentLike {
|
|
40
36
|
id: string;
|
|
@@ -50,5 +46,4 @@ interface AgentLike {
|
|
|
50
46
|
* Returns the full agent ID if found, null otherwise.
|
|
51
47
|
*/
|
|
52
48
|
export declare function resolveAgentId(idOrName: string, agents: AgentLike[]): string | null;
|
|
53
|
-
export {};
|
|
54
49
|
//# sourceMappingURL=client.d.ts.map
|
package/dist/utils/client.js
CHANGED
|
@@ -1,32 +1,39 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { waitForDaemonReady, resolvePaseoHome, } from "@camerontaylor/paseo-server/daemon-control";
|
|
2
|
+
import { describeDaemonTarget } from "./daemon-target.js";
|
|
3
3
|
import { buildDaemonWebSocketUrl, buildRelayWebSocketUrl, normalizeHostPort, parseConnectionUri, shouldUseTlsForDefaultHostedRelay, } from "@camerontaylor/paseo-protocol/daemon-endpoints";
|
|
4
4
|
import { parseConnectionOfferFromUrl, } from "@camerontaylor/paseo-protocol/connection-offer";
|
|
5
5
|
import { parseSshTransportUri } from "@camerontaylor/paseo-protocol/ssh-transport";
|
|
6
6
|
import { DaemonClient } from "@camerontaylor/paseo-client/internal/daemon-client";
|
|
7
|
-
import path from "node:path";
|
|
8
7
|
import { WebSocket } from "ws";
|
|
9
8
|
import { getOrCreateCliClientId } from "./client-id.js";
|
|
10
9
|
import { resolveCliVersion } from "../version.js";
|
|
11
10
|
import { createSshTunnel } from "../ssh/ssh-tunnel.js";
|
|
12
|
-
const DEFAULT_HOST = "localhost:6767";
|
|
13
11
|
const DEFAULT_TIMEOUT = 15000;
|
|
14
|
-
const PID_FILENAME = "paseo.pid";
|
|
15
|
-
/**
|
|
16
|
-
* Get the daemon host from environment or options
|
|
17
|
-
*/
|
|
18
12
|
export function getDaemonHost(options) {
|
|
19
|
-
return
|
|
13
|
+
return describeDaemonTarget(options.target);
|
|
20
14
|
}
|
|
21
15
|
export function buildDaemonConnectionCommandError(options) {
|
|
22
|
-
const
|
|
23
|
-
|
|
16
|
+
const error = options.error;
|
|
17
|
+
let message = error instanceof Error ? error.message : String(error);
|
|
18
|
+
if (error && typeof error === "object" && "message" in error)
|
|
19
|
+
message = String(error.message);
|
|
20
|
+
if (options.target.kind === "endpoint")
|
|
21
|
+
message = message.replaceAll(options.target.host, describeDaemonTarget(options.target));
|
|
22
|
+
if (message.startsWith("Cannot connect to daemon at "))
|
|
23
|
+
return error;
|
|
24
|
+
let code = "DAEMON_UNREACHABLE";
|
|
25
|
+
if (typeof error === "object" && error !== null && "code" in error)
|
|
26
|
+
code = String(error.code);
|
|
27
|
+
else if (message === "Password required")
|
|
28
|
+
code = "AUTH_REQUIRED";
|
|
29
|
+
else if (message === "Incorrect password")
|
|
30
|
+
code = "AUTH_FAILED";
|
|
24
31
|
return {
|
|
25
|
-
code
|
|
26
|
-
message: `Cannot connect to daemon at ${
|
|
27
|
-
details:
|
|
28
|
-
?
|
|
29
|
-
: "
|
|
32
|
+
code,
|
|
33
|
+
message: `Cannot connect to daemon at ${describeDaemonTarget(options.target)}: ${message}`,
|
|
34
|
+
details: options.target.kind === "instance"
|
|
35
|
+
? `Start with: paseo daemon start --home ${JSON.stringify(options.target.home)}`
|
|
36
|
+
: "Check the selected endpoint and credentials. SSH transport does not install or start the daemon.",
|
|
30
37
|
};
|
|
31
38
|
}
|
|
32
39
|
export function normalizeDaemonHost(raw) {
|
|
@@ -70,77 +77,6 @@ export function normalizeDaemonHost(raw) {
|
|
|
70
77
|
}
|
|
71
78
|
return trimmed.includes(":") ? trimmed : null;
|
|
72
79
|
}
|
|
73
|
-
export function resolveDefaultDaemonHost(env = process.env) {
|
|
74
|
-
return resolveDefaultDaemonHosts(env)[0] ?? DEFAULT_HOST;
|
|
75
|
-
}
|
|
76
|
-
function isIpcDaemonHost(host) {
|
|
77
|
-
return host !== null && (host.startsWith("unix://") || host.startsWith("pipe://"));
|
|
78
|
-
}
|
|
79
|
-
function isTcpDaemonHost(host) {
|
|
80
|
-
return host !== null && !isIpcDaemonHost(host);
|
|
81
|
-
}
|
|
82
|
-
function readPidSocketTarget(paseoHome) {
|
|
83
|
-
const pidPath = path.join(paseoHome, PID_FILENAME);
|
|
84
|
-
if (!existsSync(pidPath)) {
|
|
85
|
-
return null;
|
|
86
|
-
}
|
|
87
|
-
try {
|
|
88
|
-
const parsed = JSON.parse(readFileSync(pidPath, "utf-8"));
|
|
89
|
-
if (typeof parsed.listen === "string")
|
|
90
|
-
return parsed.listen;
|
|
91
|
-
if (typeof parsed.sockPath === "string")
|
|
92
|
-
return parsed.sockPath;
|
|
93
|
-
return null;
|
|
94
|
-
}
|
|
95
|
-
catch {
|
|
96
|
-
return null;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
function resolveConfiguredIpcDaemonHost(env, paseoHome) {
|
|
100
|
-
const directEnvHost = normalizeDaemonHost(env.PASEO_LISTEN ?? "");
|
|
101
|
-
if (isIpcDaemonHost(directEnvHost)) {
|
|
102
|
-
return directEnvHost;
|
|
103
|
-
}
|
|
104
|
-
const pidHost = normalizeDaemonHost(readPidSocketTarget(paseoHome) ?? "");
|
|
105
|
-
if (isIpcDaemonHost(pidHost)) {
|
|
106
|
-
return pidHost;
|
|
107
|
-
}
|
|
108
|
-
const config = loadConfig(paseoHome, { env });
|
|
109
|
-
const configuredHost = normalizeDaemonHost(config.listen);
|
|
110
|
-
return isIpcDaemonHost(configuredHost) ? configuredHost : null;
|
|
111
|
-
}
|
|
112
|
-
function resolveConfiguredTcpDaemonHost(env, paseoHome) {
|
|
113
|
-
const configuredHost = normalizeDaemonHost(loadConfig(paseoHome, { env }).listen);
|
|
114
|
-
if (!isTcpDaemonHost(configuredHost)) {
|
|
115
|
-
return null;
|
|
116
|
-
}
|
|
117
|
-
return configuredHost === "127.0.0.1:6767" ? null : configuredHost;
|
|
118
|
-
}
|
|
119
|
-
export function resolveDefaultDaemonHosts(env = process.env) {
|
|
120
|
-
const paseoHome = resolvePaseoHome(env);
|
|
121
|
-
const candidates = [];
|
|
122
|
-
const configuredIpcHost = resolveConfiguredIpcDaemonHost(env, paseoHome);
|
|
123
|
-
if (configuredIpcHost) {
|
|
124
|
-
candidates.push(configuredIpcHost);
|
|
125
|
-
}
|
|
126
|
-
const configuredTcpHost = resolveConfiguredTcpDaemonHost(env, paseoHome);
|
|
127
|
-
if (configuredTcpHost) {
|
|
128
|
-
candidates.push(configuredTcpHost);
|
|
129
|
-
}
|
|
130
|
-
candidates.push(DEFAULT_HOST);
|
|
131
|
-
return Array.from(new Set(candidates));
|
|
132
|
-
}
|
|
133
|
-
function resolveDaemonHostCandidates(options) {
|
|
134
|
-
const explicitHost = getExplicitDaemonHost(options?.host);
|
|
135
|
-
if (explicitHost) {
|
|
136
|
-
return [explicitHost];
|
|
137
|
-
}
|
|
138
|
-
return resolveDefaultDaemonHosts();
|
|
139
|
-
}
|
|
140
|
-
export function getExplicitDaemonHost(host, env = process.env) {
|
|
141
|
-
const explicitHost = host ?? env.PASEO_HOST;
|
|
142
|
-
return explicitHost?.trim() ? explicitHost : undefined;
|
|
143
|
-
}
|
|
144
80
|
function stripIpcPrefix(trimmed) {
|
|
145
81
|
if (trimmed.startsWith("unix://"))
|
|
146
82
|
return trimmed.slice("unix://".length).trim();
|
|
@@ -269,18 +205,34 @@ function parseHostOfferOrNull(host) {
|
|
|
269
205
|
throw new Error(`Invalid pairing offer URL: ${message}`, { cause: error });
|
|
270
206
|
}
|
|
271
207
|
}
|
|
272
|
-
|
|
273
|
-
const timeout = options
|
|
274
|
-
const
|
|
208
|
+
async function connectSelectedDaemon(options) {
|
|
209
|
+
const timeout = options.timeout ?? DEFAULT_TIMEOUT;
|
|
210
|
+
const deadline = Date.now() + timeout;
|
|
211
|
+
const explicitHost = options.target.kind === "endpoint"
|
|
212
|
+
? options.target.host
|
|
213
|
+
: (await waitForDaemonReady(options.target.home, {
|
|
214
|
+
timeoutMs: timeout,
|
|
215
|
+
instance: options.instance,
|
|
216
|
+
})).listen;
|
|
217
|
+
const clientId = await getOrCreateCliClientId(resolvePaseoHome({}));
|
|
275
218
|
const nodeWebSocketFactory = createNodeWebSocketFactory();
|
|
276
|
-
const explicitHost = getExplicitDaemonHost(options?.host);
|
|
277
219
|
if (explicitHost?.trim().startsWith("ssh://")) {
|
|
278
220
|
const target = parseSshTransportUri(explicitHost.trim());
|
|
279
221
|
const tunnel = await createSshTunnel(target);
|
|
280
222
|
const password = resolveDaemonPassword(explicitHost);
|
|
281
|
-
const result = await tryConnectHost(tunnel.endpoint, password, clientId,
|
|
282
|
-
if ("client" in result)
|
|
223
|
+
const result = await tryConnectHost(tunnel.endpoint, password, clientId, Math.max(1, deadline - Date.now()), nodeWebSocketFactory);
|
|
224
|
+
if ("client" in result) {
|
|
225
|
+
const close = result.client.close.bind(result.client);
|
|
226
|
+
result.client.close = async () => {
|
|
227
|
+
try {
|
|
228
|
+
await close();
|
|
229
|
+
}
|
|
230
|
+
finally {
|
|
231
|
+
tunnel.close();
|
|
232
|
+
}
|
|
233
|
+
};
|
|
283
234
|
return result.client;
|
|
235
|
+
}
|
|
284
236
|
const failure = tunnel.failureDetail();
|
|
285
237
|
tunnel.close();
|
|
286
238
|
if (failure)
|
|
@@ -289,24 +241,20 @@ export async function connectToDaemon(options) {
|
|
|
289
241
|
}
|
|
290
242
|
const offer = parseHostOfferOrNull(explicitHost);
|
|
291
243
|
if (offer) {
|
|
292
|
-
return connectViaRelayOffer(offer, clientId,
|
|
244
|
+
return connectViaRelayOffer(offer, clientId, Math.max(1, deadline - Date.now()), nodeWebSocketFactory);
|
|
293
245
|
}
|
|
294
|
-
const
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
return result.client;
|
|
306
|
-
}
|
|
307
|
-
return tryNext(index + 1, result.error);
|
|
246
|
+
const result = await tryConnectHost(explicitHost, resolveDaemonPassword(explicitHost), clientId, Math.max(1, deadline - Date.now()), nodeWebSocketFactory);
|
|
247
|
+
if ("client" in result)
|
|
248
|
+
return result.client;
|
|
249
|
+
throw result.error;
|
|
250
|
+
}
|
|
251
|
+
export async function connectToDaemon(options) {
|
|
252
|
+
try {
|
|
253
|
+
return await connectSelectedDaemon(options);
|
|
254
|
+
}
|
|
255
|
+
catch (error) {
|
|
256
|
+
throw buildDaemonConnectionCommandError({ ...options, error });
|
|
308
257
|
}
|
|
309
|
-
return tryNext(0, null);
|
|
310
258
|
}
|
|
311
259
|
/**
|
|
312
260
|
* Try to connect to the daemon, returns null if connection fails
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Command } from "commander";
|
|
2
|
+
export declare function addLocalDaemonOptions<T extends Command>(command: T): T;
|
|
2
3
|
export declare function collectMultiple(value: string, previous: string[]): string[];
|
|
3
4
|
export declare function addJsonOption<T extends Command>(command: T): T;
|
|
4
5
|
export declare function addDaemonHostOption<T extends Command>(command: T): T;
|
|
@@ -1,5 +1,12 @@
|
|
|
1
|
+
import { selectDaemonTarget } from "./daemon-target.js";
|
|
1
2
|
const JSON_OPTION_DESCRIPTION = "Output in JSON format";
|
|
2
|
-
const DAEMON_HOST_OPTION_DESCRIPTION = "
|
|
3
|
+
const DAEMON_HOST_OPTION_DESCRIPTION = "Explicit daemon endpoint: host:port, TCP, socket, SSH, or pairing URL (default: local home)";
|
|
4
|
+
const localCommands = new WeakSet();
|
|
5
|
+
export function addLocalDaemonOptions(command) {
|
|
6
|
+
localCommands.add(command);
|
|
7
|
+
command.option("--home <path>", "Local daemon home (default: ~/.paseo)");
|
|
8
|
+
return command;
|
|
9
|
+
}
|
|
3
10
|
export function collectMultiple(value, previous) {
|
|
4
11
|
return previous.concat([value]);
|
|
5
12
|
}
|
|
@@ -9,6 +16,8 @@ export function addJsonOption(command) {
|
|
|
9
16
|
}
|
|
10
17
|
export function addDaemonHostOption(command) {
|
|
11
18
|
command.option("--host <host>", DAEMON_HOST_OPTION_DESCRIPTION);
|
|
19
|
+
if (!command.options.some((option) => option.long === "--home"))
|
|
20
|
+
command.option("--home <path>", "Select a local daemon home (default: ~/.paseo)");
|
|
12
21
|
return command;
|
|
13
22
|
}
|
|
14
23
|
export function addJsonAndDaemonHostOptions(command) {
|
|
@@ -18,7 +27,22 @@ export function withGlobalOptions(handler) {
|
|
|
18
27
|
return (...args) => {
|
|
19
28
|
const command = args.at(-1);
|
|
20
29
|
const mergedArgs = [...args];
|
|
21
|
-
|
|
30
|
+
const options = command.optsWithGlobals();
|
|
31
|
+
const selectors = { home: new Set(), host: new Set() };
|
|
32
|
+
for (let current = command; current; current = current.parent) {
|
|
33
|
+
for (const key of ["home", "host"]) {
|
|
34
|
+
const value = current.opts()[key];
|
|
35
|
+
if (typeof value === "string")
|
|
36
|
+
selectors[key].add(value);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
for (const key of ["home", "host"]) {
|
|
40
|
+
if (selectors[key].size > 1)
|
|
41
|
+
throw { code: "TARGET_AMBIGUOUS", message: `Conflicting duplicate --${key} selectors.` };
|
|
42
|
+
}
|
|
43
|
+
const localOnly = localCommands.has(command);
|
|
44
|
+
options.daemonTarget = selectDaemonTarget(options, process.env, localOnly);
|
|
45
|
+
mergedArgs[mergedArgs.length - 2] = options;
|
|
22
46
|
return handler(...mergedArgs);
|
|
23
47
|
};
|
|
24
48
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type DaemonTarget = {
|
|
2
|
+
kind: "instance";
|
|
3
|
+
home: string;
|
|
4
|
+
} | {
|
|
5
|
+
kind: "endpoint";
|
|
6
|
+
host: string;
|
|
7
|
+
};
|
|
8
|
+
export declare function selectDaemonTarget(options: {
|
|
9
|
+
home?: string;
|
|
10
|
+
host?: string;
|
|
11
|
+
}, env?: NodeJS.ProcessEnv, localOnly?: boolean): DaemonTarget;
|
|
12
|
+
export declare function describeDaemonTarget(target: DaemonTarget): string;
|
|
13
|
+
//# sourceMappingURL=daemon-target.d.ts.map
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { resolvePaseoHome } from "@camerontaylor/paseo-server/daemon-control";
|
|
2
|
+
export function selectDaemonTarget(options, env = process.env, localOnly = false) {
|
|
3
|
+
for (const key of ["home", "host"]) {
|
|
4
|
+
if (options[key] !== undefined && !options[key].trim())
|
|
5
|
+
throw { code: "TARGET_INVALID", message: `--${key} requires a non-empty value.` };
|
|
6
|
+
}
|
|
7
|
+
if (options.home !== undefined && options.host !== undefined)
|
|
8
|
+
throw { code: "TARGET_AMBIGUOUS", message: "Choose either --home or --host, not both." };
|
|
9
|
+
if (localOnly) {
|
|
10
|
+
if (options.host !== undefined)
|
|
11
|
+
throw {
|
|
12
|
+
code: "LOCAL_OPERATION",
|
|
13
|
+
message: "This is a local operation; use --home. --host is not supported.",
|
|
14
|
+
};
|
|
15
|
+
return {
|
|
16
|
+
kind: "instance",
|
|
17
|
+
home: resolvePaseoHome({ PASEO_HOME: options.home ?? env.PASEO_HOME }),
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
if (options.home !== undefined)
|
|
21
|
+
return { kind: "instance", home: resolvePaseoHome({ PASEO_HOME: options.home }) };
|
|
22
|
+
if (options.host !== undefined)
|
|
23
|
+
return { kind: "endpoint", host: options.host };
|
|
24
|
+
if (env.PASEO_HOME && env.PASEO_HOST)
|
|
25
|
+
throw {
|
|
26
|
+
code: "TARGET_AMBIGUOUS",
|
|
27
|
+
message: "PASEO_HOME and PASEO_HOST are both set. Choose --home or --host explicitly.",
|
|
28
|
+
};
|
|
29
|
+
if (env.PASEO_HOST)
|
|
30
|
+
return { kind: "endpoint", host: env.PASEO_HOST };
|
|
31
|
+
return { kind: "instance", home: resolvePaseoHome({ PASEO_HOME: env.PASEO_HOME }) };
|
|
32
|
+
}
|
|
33
|
+
export function describeDaemonTarget(target) {
|
|
34
|
+
if (target.kind === "instance")
|
|
35
|
+
return `home ${target.home}`;
|
|
36
|
+
try {
|
|
37
|
+
const url = new URL(target.host);
|
|
38
|
+
if (url.password)
|
|
39
|
+
url.password = "REDACTED";
|
|
40
|
+
for (const key of url.searchParams.keys())
|
|
41
|
+
if (/password|token|secret/i.test(key))
|
|
42
|
+
url.searchParams.set(key, "REDACTED");
|
|
43
|
+
if (url.hash)
|
|
44
|
+
url.hash = "REDACTED";
|
|
45
|
+
return url.toString();
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return target.host.replace(/([?&](?:password|token|secret)=)[^&]*/gi, "$1REDACTED");
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=daemon-target.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camerontaylor/paseo-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0-beta.2.fork.1",
|
|
4
4
|
"description": "Paseo CLI - control your AI coding agents from the command line",
|
|
5
5
|
"bin": {
|
|
6
6
|
"paseo": "bin/paseo"
|
|
@@ -28,9 +28,9 @@
|
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@clack/prompts": "^1.0.0",
|
|
31
|
-
"@camerontaylor/paseo-client": "0.
|
|
32
|
-
"@camerontaylor/paseo-protocol": "0.
|
|
33
|
-
"@camerontaylor/paseo-server": "0.
|
|
31
|
+
"@camerontaylor/paseo-client": "0.9.0-beta.2.fork.1",
|
|
32
|
+
"@camerontaylor/paseo-protocol": "0.9.0-beta.2.fork.1",
|
|
33
|
+
"@camerontaylor/paseo-server": "0.9.0-beta.2.fork.1",
|
|
34
34
|
"chalk": "^5.3.0",
|
|
35
35
|
"commander": "^12.0.0",
|
|
36
36
|
"mime-types": "^2.1.35",
|
|
@@ -46,5 +46,9 @@
|
|
|
46
46
|
"typescript": "^5.2.2",
|
|
47
47
|
"vitest": "^4.1.6",
|
|
48
48
|
"zx": "^8.8.5"
|
|
49
|
+
},
|
|
50
|
+
"repository": {
|
|
51
|
+
"type": "git",
|
|
52
|
+
"url": "https://github.com/camerontaylor/paseo"
|
|
49
53
|
}
|
|
50
54
|
}
|