@camerontaylor/paseo-cli 0.8.0-fork.1 → 0.8.0-fork.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +25 -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 +12 -12
- 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 +11 -16
- 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 +102 -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 +31 -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/set-password.js +6 -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 +90 -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 +58 -210
- package/dist/commands/open.js +2 -0
- 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.js +7 -7
- package/dist/commands/plugin/shared.d.ts +4 -3
- package/dist/commands/plugin/shared.js +8 -8
- 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 +24 -2
- package/dist/utils/daemon-target.d.ts +13 -0
- package/dist/utils/daemon-target.js +51 -0
- package/package.json +8 -4
|
@@ -3,5 +3,5 @@ import { type TerminalCommandOptions } from "./shared.js";
|
|
|
3
3
|
export interface TerminalSendKeysOptions extends TerminalCommandOptions {
|
|
4
4
|
literal?: boolean;
|
|
5
5
|
}
|
|
6
|
-
export declare function runSendKeysCommand(terminalId: string, keys: string[],
|
|
6
|
+
export declare function runSendKeysCommand(terminalId: string, keys: string[], options: TerminalSendKeysOptions, _command: Command): Promise<void>;
|
|
7
7
|
//# sourceMappingURL=send-keys.d.ts.map
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { renderError, toCommandError } from "../../output/render.js";
|
|
2
2
|
import { connectTerminalClient, resolveTerminalId, toTerminalCommandError, } from "./shared.js";
|
|
3
|
-
export async function runSendKeysCommand(terminalId, keys,
|
|
4
|
-
const options = command.optsWithGlobals();
|
|
3
|
+
export async function runSendKeysCommand(terminalId, keys, options, _command) {
|
|
5
4
|
try {
|
|
6
5
|
const payload = await executeSendKeysCommand(terminalId, keys, options);
|
|
7
6
|
if (options.json) {
|
|
@@ -18,7 +17,7 @@ export async function runSendKeysCommand(terminalId, keys, _options, command) {
|
|
|
18
17
|
}
|
|
19
18
|
}
|
|
20
19
|
async function executeSendKeysCommand(terminalId, keys, options) {
|
|
21
|
-
const { client, close } = await connectTerminalClient(options.
|
|
20
|
+
const { client, close } = await connectTerminalClient(options.daemonTarget);
|
|
22
21
|
try {
|
|
23
22
|
const resolvedId = await resolveTerminalId(client, terminalId);
|
|
24
23
|
if (!resolvedId) {
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import type { DaemonTarget } from "../../utils/daemon-target.js";
|
|
1
2
|
import type { CommandError, CommandOptions } from "../../output/index.js";
|
|
2
3
|
export interface TerminalCommandOptions extends CommandOptions {
|
|
3
4
|
host?: string;
|
|
4
5
|
}
|
|
5
|
-
export declare function connectTerminalClient(
|
|
6
|
+
export declare function connectTerminalClient(target: DaemonTarget): Promise<{
|
|
6
7
|
client: import("@camerontaylor/paseo-client").PaseoApi;
|
|
7
8
|
daemonHost: string;
|
|
8
9
|
close: () => Promise<void>;
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { createPaseoApi } from "@camerontaylor/paseo-client";
|
|
2
2
|
import { connectToDaemon, getDaemonHost } from "../../utils/client.js";
|
|
3
|
-
export async function connectTerminalClient(
|
|
4
|
-
const daemonHost = getDaemonHost({
|
|
3
|
+
export async function connectTerminalClient(target) {
|
|
4
|
+
const daemonHost = getDaemonHost({ target });
|
|
5
5
|
try {
|
|
6
|
-
const client = await connectToDaemon({
|
|
6
|
+
const client = await connectToDaemon({ target });
|
|
7
7
|
return { client: createPaseoApi(client), daemonHost, close: () => client.close() };
|
|
8
8
|
}
|
|
9
9
|
catch (err) {
|
|
10
|
+
if (err && typeof err === "object" && "code" in err)
|
|
11
|
+
throw err;
|
|
10
12
|
const message = err instanceof Error ? err.message : String(err);
|
|
11
13
|
const error = {
|
|
12
14
|
code: "DAEMON_NOT_RUNNING",
|
|
@@ -7,6 +7,7 @@ interface WorkspaceArchiveResult {
|
|
|
7
7
|
}
|
|
8
8
|
export declare function runArchiveCommand(workspaceId: string, options: {
|
|
9
9
|
host?: string;
|
|
10
|
+
daemonTarget: import("../../utils/daemon-target.js").DaemonTarget;
|
|
10
11
|
}, _command: Command): Promise<SingleResult<WorkspaceArchiveResult>>;
|
|
11
12
|
export {};
|
|
12
13
|
//# sourceMappingURL=archive.d.ts.map
|
|
@@ -8,8 +8,8 @@ const workspaceArchiveSchema = {
|
|
|
8
8
|
],
|
|
9
9
|
};
|
|
10
10
|
export async function runArchiveCommand(workspaceId, options, _command) {
|
|
11
|
-
const host = getDaemonHost({
|
|
12
|
-
const client = await connectToDaemon({
|
|
11
|
+
const host = getDaemonHost({ target: options.daemonTarget });
|
|
12
|
+
const client = await connectToDaemon({ target: options.daemonTarget }).catch((error) => {
|
|
13
13
|
const message = error instanceof Error ? error.message : String(error);
|
|
14
14
|
throw {
|
|
15
15
|
code: "DAEMON_NOT_RUNNING",
|
|
@@ -31,6 +31,8 @@ export async function runArchiveCommand(workspaceId, options, _command) {
|
|
|
31
31
|
};
|
|
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: "WORKSPACE_ARCHIVE_FAILED", message };
|
|
36
38
|
}
|
|
@@ -85,8 +85,8 @@ export function buildWorkspaceSource(options) {
|
|
|
85
85
|
throw new Error(`Unsupported workspace isolation: ${String(options.isolation)}`);
|
|
86
86
|
}
|
|
87
87
|
export async function runCreateCommand(options, _command) {
|
|
88
|
-
const host = getDaemonHost({
|
|
89
|
-
const client = await connectToDaemon({
|
|
88
|
+
const host = getDaemonHost({ target: options.daemonTarget });
|
|
89
|
+
const client = await connectToDaemon({ target: options.daemonTarget }).catch((error) => {
|
|
90
90
|
const message = error instanceof Error ? error.message : String(error);
|
|
91
91
|
throw {
|
|
92
92
|
code: "DAEMON_NOT_RUNNING",
|
|
@@ -104,6 +104,8 @@ export async function runCreateCommand(options, _command) {
|
|
|
104
104
|
return { type: "single", data: toWorkspaceRow(payload.workspace), schema: workspaceSchema };
|
|
105
105
|
}
|
|
106
106
|
catch (error) {
|
|
107
|
+
if (error && typeof error === "object" && "code" in error)
|
|
108
|
+
throw error;
|
|
107
109
|
const message = error instanceof Error ? error.message : String(error);
|
|
108
110
|
throw { code: "WORKSPACE_CREATE_FAILED", message };
|
|
109
111
|
}
|
|
@@ -3,5 +3,6 @@ import type { ListResult } from "../../output/index.js";
|
|
|
3
3
|
import { type WorkspaceRow } from "./shared.js";
|
|
4
4
|
export declare function runLsCommand(options: {
|
|
5
5
|
host?: string;
|
|
6
|
+
daemonTarget: import("../../utils/daemon-target.js").DaemonTarget;
|
|
6
7
|
}, _command: Command): Promise<ListResult<WorkspaceRow>>;
|
|
7
8
|
//# sourceMappingURL=ls.d.ts.map
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { connectToDaemon, getDaemonHost } from "../../utils/client.js";
|
|
2
2
|
import { toWorkspaceRow, workspaceSchema } from "./shared.js";
|
|
3
3
|
export async function runLsCommand(options, _command) {
|
|
4
|
-
const host = getDaemonHost({
|
|
5
|
-
const client = await connectToDaemon({
|
|
4
|
+
const host = getDaemonHost({ target: options.daemonTarget });
|
|
5
|
+
const client = await connectToDaemon({ target: options.daemonTarget }).catch((error) => {
|
|
6
6
|
const message = error instanceof Error ? error.message : String(error);
|
|
7
7
|
throw {
|
|
8
8
|
code: "DAEMON_NOT_RUNNING",
|
|
@@ -33,8 +33,8 @@ export function resolveWorkspaceTitle(input) {
|
|
|
33
33
|
}
|
|
34
34
|
export async function runRenameCommand(workspaceId, titleArg, options, _command) {
|
|
35
35
|
const title = resolveWorkspaceTitle({ title: titleArg, reset: options.reset });
|
|
36
|
-
const host = getDaemonHost({
|
|
37
|
-
const client = await connectToDaemon({
|
|
36
|
+
const host = getDaemonHost({ target: options.daemonTarget });
|
|
37
|
+
const client = await connectToDaemon({ target: options.daemonTarget }).catch((error) => {
|
|
38
38
|
const message = error instanceof Error ? error.message : String(error);
|
|
39
39
|
throw {
|
|
40
40
|
code: "DAEMON_NOT_RUNNING",
|
|
@@ -51,6 +51,8 @@ export async function runRenameCommand(workspaceId, titleArg, options, _command)
|
|
|
51
51
|
};
|
|
52
52
|
}
|
|
53
53
|
catch (error) {
|
|
54
|
+
if (error && typeof error === "object" && "code" in error)
|
|
55
|
+
throw error;
|
|
54
56
|
const message = error instanceof Error ? error.message : String(error);
|
|
55
57
|
throw { code: "WORKSPACE_RENAME_FAILED", message };
|
|
56
58
|
}
|
|
@@ -6,6 +6,7 @@ interface WorkspaceSetupResult {
|
|
|
6
6
|
}
|
|
7
7
|
export declare function runSetupCommand(workspaceId: string, options: {
|
|
8
8
|
host?: string;
|
|
9
|
+
daemonTarget: import("../../utils/daemon-target.js").DaemonTarget;
|
|
9
10
|
}, _command: Command): Promise<SingleResult<WorkspaceSetupResult>>;
|
|
10
11
|
export {};
|
|
11
12
|
//# sourceMappingURL=setup.d.ts.map
|
|
@@ -7,8 +7,8 @@ const workspaceSetupSchema = {
|
|
|
7
7
|
],
|
|
8
8
|
};
|
|
9
9
|
export async function runSetupCommand(workspaceId, options, _command) {
|
|
10
|
-
const host = getDaemonHost({
|
|
11
|
-
const client = await connectToDaemon({
|
|
10
|
+
const host = getDaemonHost({ target: options.daemonTarget });
|
|
11
|
+
const client = await connectToDaemon({ target: options.daemonTarget }).catch((error) => {
|
|
12
12
|
throw {
|
|
13
13
|
code: "DAEMON_NOT_RUNNING",
|
|
14
14
|
message: `Cannot connect to daemon at ${host}: ${error instanceof Error ? error.message : String(error)}`,
|
|
@@ -16,7 +16,7 @@ export async function runArchiveCommand(nameArg, options, _command) {
|
|
|
16
16
|
return runArchiveCommandWithDeps(nameArg, options, { connectToDaemon });
|
|
17
17
|
}
|
|
18
18
|
export async function runArchiveCommandWithDeps(nameArg, options, deps) {
|
|
19
|
-
const host = getDaemonHost({
|
|
19
|
+
const host = getDaemonHost({ target: options.daemonTarget });
|
|
20
20
|
// Validate arguments
|
|
21
21
|
if (!nameArg || nameArg.trim().length === 0) {
|
|
22
22
|
const error = {
|
|
@@ -28,9 +28,11 @@ export async function runArchiveCommandWithDeps(nameArg, options, deps) {
|
|
|
28
28
|
}
|
|
29
29
|
let client;
|
|
30
30
|
try {
|
|
31
|
-
client = await deps.connectToDaemon({
|
|
31
|
+
client = await deps.connectToDaemon({ target: options.daemonTarget });
|
|
32
32
|
}
|
|
33
33
|
catch (err) {
|
|
34
|
+
if (err && typeof err === "object" && "code" in err)
|
|
35
|
+
throw err;
|
|
34
36
|
const message = err instanceof Error ? err.message : String(err);
|
|
35
37
|
const error = {
|
|
36
38
|
code: "DAEMON_NOT_RUNNING",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import { connectToDaemon
|
|
2
|
+
import { connectToDaemon } from "../../utils/client.js";
|
|
3
3
|
import { buildCreateWorktreeRequest } from "./create-input.js";
|
|
4
4
|
export const createSchema = {
|
|
5
5
|
idField: "worktreePath",
|
|
@@ -15,15 +15,7 @@ function cmdError(code, message, details) {
|
|
|
15
15
|
export async function runCreateCommand(options, _command) {
|
|
16
16
|
const cwd = options.cwd ?? process.cwd();
|
|
17
17
|
const request = buildCreateWorktreeRequest(options, cwd);
|
|
18
|
-
const
|
|
19
|
-
let client;
|
|
20
|
-
try {
|
|
21
|
-
client = await connectToDaemon({ host: options.host });
|
|
22
|
-
}
|
|
23
|
-
catch (err) {
|
|
24
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
25
|
-
throw cmdError("DAEMON_NOT_RUNNING", `Cannot connect to daemon at ${host}: ${message}`, "Start the daemon with: paseo daemon start");
|
|
26
|
-
}
|
|
18
|
+
const client = await connectToDaemon({ target: options.daemonTarget });
|
|
27
19
|
try {
|
|
28
20
|
const response = await client.createPaseoWorktree(request);
|
|
29
21
|
const workspace = response.workspace;
|
|
@@ -7,8 +7,6 @@ export interface WorktreeListItem {
|
|
|
7
7
|
cwd: string;
|
|
8
8
|
agent: string;
|
|
9
9
|
}
|
|
10
|
-
export declare function resolvePaseoHomePath(): string;
|
|
11
|
-
export declare function resolvePaseoWorktreesDir(): string;
|
|
12
10
|
/** Schema for worktree ls output */
|
|
13
11
|
export declare const worktreeLsSchema: OutputSchema<WorktreeListItem>;
|
|
14
12
|
export type WorktreeLsResult = ListResult<WorktreeListItem>;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { connectToDaemon, getDaemonHost } from "../../utils/client.js";
|
|
1
|
+
import { basename } from "node:path";
|
|
2
|
+
import { connectToDaemon } from "../../utils/client.js";
|
|
4
3
|
/** Shorten home directory in path */
|
|
5
4
|
function shortenPath(path) {
|
|
6
5
|
const home = process.env.HOME;
|
|
@@ -13,16 +12,6 @@ function shortenPath(path) {
|
|
|
13
12
|
function extractWorktreeName(path) {
|
|
14
13
|
return basename(path);
|
|
15
14
|
}
|
|
16
|
-
export function resolvePaseoHomePath() {
|
|
17
|
-
return process.env.PASEO_HOME ?? join(homedir(), ".paseo");
|
|
18
|
-
}
|
|
19
|
-
export function resolvePaseoWorktreesDir() {
|
|
20
|
-
return join(resolvePaseoHomePath(), "worktrees");
|
|
21
|
-
}
|
|
22
|
-
function isAgentInManagedWorktree(agentCwd) {
|
|
23
|
-
const worktreesDir = resolvePaseoWorktreesDir();
|
|
24
|
-
return agentCwd === worktreesDir || agentCwd.startsWith(worktreesDir + sep);
|
|
25
|
-
}
|
|
26
15
|
/** Schema for worktree ls output */
|
|
27
16
|
export const worktreeLsSchema = {
|
|
28
17
|
idField: "name",
|
|
@@ -34,20 +23,7 @@ export const worktreeLsSchema = {
|
|
|
34
23
|
],
|
|
35
24
|
};
|
|
36
25
|
export async function runLsCommand(options, _command) {
|
|
37
|
-
const
|
|
38
|
-
let client;
|
|
39
|
-
try {
|
|
40
|
-
client = await connectToDaemon({ host: options.host });
|
|
41
|
-
}
|
|
42
|
-
catch (err) {
|
|
43
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
44
|
-
const error = {
|
|
45
|
-
code: "DAEMON_NOT_RUNNING",
|
|
46
|
-
message: `Cannot connect to daemon at ${host}: ${message}`,
|
|
47
|
-
details: "Start the daemon with: paseo daemon start",
|
|
48
|
-
};
|
|
49
|
-
throw error;
|
|
50
|
-
}
|
|
26
|
+
const client = await connectToDaemon({ target: options.daemonTarget });
|
|
51
27
|
try {
|
|
52
28
|
const agentsPayload = await client.fetchAgents({ filter: { includeArchived: true } });
|
|
53
29
|
const agents = agentsPayload.entries.map((entry) => entry.agent);
|
|
@@ -64,9 +40,7 @@ export async function runLsCommand(options, _command) {
|
|
|
64
40
|
// Build a map of worktree paths to agent IDs
|
|
65
41
|
const worktreeAgentMap = new Map();
|
|
66
42
|
for (const agent of agents) {
|
|
67
|
-
|
|
68
|
-
worktreeAgentMap.set(agent.cwd, agent.id.slice(0, 7));
|
|
69
|
-
}
|
|
43
|
+
worktreeAgentMap.set(agent.cwd, agent.id.slice(0, 7));
|
|
70
44
|
}
|
|
71
45
|
const items = response.worktrees.map((wt) => ({
|
|
72
46
|
name: extractWorktreeName(wt.worktreePath),
|
|
@@ -7,6 +7,8 @@ import type { Command } from "commander";
|
|
|
7
7
|
import type { AnyCommandResult, OutputOptions } from "./types.js";
|
|
8
8
|
/** Options that include output settings from global options */
|
|
9
9
|
export interface CommandOptions extends Partial<OutputOptions> {
|
|
10
|
+
daemonTarget: import("../utils/daemon-target.js").DaemonTarget;
|
|
11
|
+
home?: string;
|
|
10
12
|
/** Daemon host target from --host option */
|
|
11
13
|
host?: string;
|
|
12
14
|
/** JSON output flag from --json option */
|
package/dist/run.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { renderError, toCommandError, defaultOutputOptions } from "./output/render.js";
|
|
1
2
|
import { createCli } from "./cli.js";
|
|
2
3
|
import { classifyInvocation } from "./classify.js";
|
|
3
4
|
import { openDesktopWithProject } from "./commands/open.js";
|
|
@@ -34,7 +35,16 @@ export async function runCli(argv, options = {}) {
|
|
|
34
35
|
return typeof process.exitCode === "number" ? process.exitCode : 0;
|
|
35
36
|
}
|
|
36
37
|
const program = createCli();
|
|
37
|
-
|
|
38
|
+
try {
|
|
39
|
+
await program.parseAsync(parseArgv, { from: "node" });
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
process.stderr.write(renderError(toCommandError(error), {
|
|
43
|
+
...defaultOutputOptions,
|
|
44
|
+
format: argv.includes("--json") ? "json" : "table",
|
|
45
|
+
}) + "\n");
|
|
46
|
+
return 1;
|
|
47
|
+
}
|
|
38
48
|
return typeof process.exitCode === "number" ? process.exitCode : 0;
|
|
39
49
|
}
|
|
40
50
|
//# sourceMappingURL=run.js.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare function getOrCreateCliClientId(): Promise<string>;
|
|
1
|
+
export declare function getOrCreateCliClientId(home: string): Promise<string>;
|
|
2
2
|
//# sourceMappingURL=client-id.d.ts.map
|
package/dist/utils/client-id.js
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ensurePrivateDirectory } from "@camerontaylor/paseo-server";
|
|
2
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
2
3
|
import { randomUUID } from "node:crypto";
|
|
3
|
-
import {
|
|
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;
|
|
4
|
+
import { join } from "node:path";
|
|
7
5
|
function normalizeClientId(value) {
|
|
8
6
|
const trimmed = value.trim();
|
|
9
7
|
return trimmed.length > 0 ? trimmed : null;
|
|
@@ -11,14 +9,11 @@ function normalizeClientId(value) {
|
|
|
11
9
|
function generateClientId() {
|
|
12
10
|
return `cid_${randomUUID().replace(/-/g, "")}`;
|
|
13
11
|
}
|
|
14
|
-
export async function getOrCreateCliClientId() {
|
|
15
|
-
|
|
16
|
-
return cachedClientId;
|
|
17
|
-
}
|
|
12
|
+
export async function getOrCreateCliClientId(home) {
|
|
13
|
+
const clientSessionKeyFile = join(home, "cli-client-id");
|
|
18
14
|
try {
|
|
19
|
-
const existing = normalizeClientId(await readFile(
|
|
15
|
+
const existing = normalizeClientId(await readFile(clientSessionKeyFile, "utf8"));
|
|
20
16
|
if (existing) {
|
|
21
|
-
cachedClientId = existing;
|
|
22
17
|
return existing;
|
|
23
18
|
}
|
|
24
19
|
}
|
|
@@ -29,9 +24,8 @@ export async function getOrCreateCliClientId() {
|
|
|
29
24
|
}
|
|
30
25
|
}
|
|
31
26
|
const nextValue = generateClientId();
|
|
32
|
-
|
|
33
|
-
await writeFile(
|
|
34
|
-
cachedClientId = nextValue;
|
|
27
|
+
ensurePrivateDirectory(home);
|
|
28
|
+
await writeFile(clientSessionKeyFile, nextValue, { mode: 0o600 });
|
|
35
29
|
return nextValue;
|
|
36
30
|
}
|
|
37
31
|
//# sourceMappingURL=client-id.js.map
|
package/dist/utils/client.d.ts
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
|
+
import { type DaemonInstance } from "@camerontaylor/paseo-server";
|
|
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";
|
|
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
|