@getpaseo/cli 0.2.0-beta.2 → 0.2.0-beta.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/commands/agent/index.js +2 -0
- package/dist/commands/agent/open.d.ts +11 -0
- package/dist/commands/agent/open.js +61 -0
- package/dist/commands/agent/run.d.ts +7 -1
- package/dist/commands/agent/run.js +82 -36
- package/dist/commands/open.d.ts +2 -0
- package/dist/commands/open.js +22 -17
- package/package.json +4 -4
|
@@ -14,6 +14,7 @@ import { addReloadOptions, runReloadCommand } from "./reload.js";
|
|
|
14
14
|
import { addImportOptions, runImportCommand } from "./import.js";
|
|
15
15
|
import { runUpdateCommand } from "./update.js";
|
|
16
16
|
import { runDetachCommand } from "./detach.js";
|
|
17
|
+
import { addOpenOptions, runOpenCommand } from "./open.js";
|
|
17
18
|
import { withOutput } from "../../output/index.js";
|
|
18
19
|
import { addDaemonHostOption, addJsonAndDaemonHostOptions, collectMultiple, } from "../../utils/command-options.js";
|
|
19
20
|
export function createAgentCommand() {
|
|
@@ -24,6 +25,7 @@ export function createAgentCommand() {
|
|
|
24
25
|
addJsonAndDaemonHostOptions(addImportOptions(agent.command("import"))).action(withOutput(runImportCommand));
|
|
25
26
|
addDaemonHostOption(addAttachOptions(agent.command("attach"))).action(runAttachCommand);
|
|
26
27
|
addDaemonHostOption(addLogsOptions(agent.command("logs"))).action(runLogsCommand);
|
|
28
|
+
addJsonAndDaemonHostOptions(addOpenOptions(agent.command("open"))).action(withOutput(runOpenCommand));
|
|
27
29
|
addJsonAndDaemonHostOptions(addStopOptions(agent.command("stop"))).action(withOutput(runStopCommand));
|
|
28
30
|
addJsonAndDaemonHostOptions(addDeleteOptions(agent.command("delete"))).action(withOutput(runDeleteCommand));
|
|
29
31
|
addJsonAndDaemonHostOptions(addSendOptions(agent.command("send"))).action(withOutput(runSendCommand));
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Command } from "commander";
|
|
2
|
+
import type { CommandOptions, SingleResult } from "../../output/index.js";
|
|
3
|
+
interface OpenAgentResult {
|
|
4
|
+
agentId: string;
|
|
5
|
+
serverId: string;
|
|
6
|
+
status: "opened";
|
|
7
|
+
}
|
|
8
|
+
export declare function addOpenOptions(command: Command): Command;
|
|
9
|
+
export declare function runOpenCommand(agentIdArg: string, options: CommandOptions, _command: Command): Promise<SingleResult<OpenAgentResult>>;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=open.d.ts.map
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { buildDaemonConnectionCommandError, connectToDaemon } from "../../utils/client.js";
|
|
2
|
+
import { openDesktopWithAgent } from "../open.js";
|
|
3
|
+
const openAgentSchema = {
|
|
4
|
+
idField: "agentId",
|
|
5
|
+
columns: [
|
|
6
|
+
{ header: "AGENT ID", field: "agentId" },
|
|
7
|
+
{ header: "SERVER ID", field: "serverId" },
|
|
8
|
+
{ header: "STATUS", field: "status" },
|
|
9
|
+
],
|
|
10
|
+
};
|
|
11
|
+
export function addOpenOptions(command) {
|
|
12
|
+
return command
|
|
13
|
+
.description("Open an existing agent in Paseo Desktop")
|
|
14
|
+
.argument("<agent-id>", "Existing agent ID")
|
|
15
|
+
.option("--server <server-id>", "Server ID (defaults to the local daemon)");
|
|
16
|
+
}
|
|
17
|
+
async function resolveServerId(options) {
|
|
18
|
+
const explicitServerId = typeof options.server === "string" ? options.server.trim() : "";
|
|
19
|
+
if (explicitServerId) {
|
|
20
|
+
return explicitServerId;
|
|
21
|
+
}
|
|
22
|
+
let client;
|
|
23
|
+
try {
|
|
24
|
+
client = await connectToDaemon({ host: options.host });
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
throw buildDaemonConnectionCommandError({ host: options.host, error });
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
const serverId = client.getLastServerInfoMessage()?.serverId.trim();
|
|
31
|
+
if (!serverId) {
|
|
32
|
+
const error = {
|
|
33
|
+
code: "SERVER_ID_UNAVAILABLE",
|
|
34
|
+
message: "The daemon did not report a server ID.",
|
|
35
|
+
};
|
|
36
|
+
throw error;
|
|
37
|
+
}
|
|
38
|
+
return serverId;
|
|
39
|
+
}
|
|
40
|
+
finally {
|
|
41
|
+
await client.close().catch(() => { });
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
export async function runOpenCommand(agentIdArg, options, _command) {
|
|
45
|
+
const agentId = agentIdArg.trim();
|
|
46
|
+
if (!agentId) {
|
|
47
|
+
const error = {
|
|
48
|
+
code: "MISSING_AGENT_ID",
|
|
49
|
+
message: "Agent ID is required.",
|
|
50
|
+
};
|
|
51
|
+
throw error;
|
|
52
|
+
}
|
|
53
|
+
const serverId = await resolveServerId(options);
|
|
54
|
+
await openDesktopWithAgent({ serverId, agentId });
|
|
55
|
+
return {
|
|
56
|
+
type: "single",
|
|
57
|
+
data: { agentId, serverId, status: "opened" },
|
|
58
|
+
schema: openAgentSchema,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=open.js.map
|
|
@@ -22,9 +22,15 @@ export interface AgentRunOptions extends CommandOptions {
|
|
|
22
22
|
model?: string;
|
|
23
23
|
thinking?: string;
|
|
24
24
|
mode?: string;
|
|
25
|
-
|
|
25
|
+
newWorkspace?: string;
|
|
26
26
|
worktree?: string;
|
|
27
|
+
worktreeMode?: string;
|
|
28
|
+
worktreeSlug?: string;
|
|
29
|
+
newBranch?: string;
|
|
27
30
|
base?: string;
|
|
31
|
+
branch?: string;
|
|
32
|
+
prNumber?: string;
|
|
33
|
+
forge?: string;
|
|
28
34
|
workspace?: string;
|
|
29
35
|
image?: string[];
|
|
30
36
|
cwd?: string;
|
|
@@ -7,6 +7,7 @@ import { lookup } from "mime-types";
|
|
|
7
7
|
import { parseDuration } from "../../utils/duration.js";
|
|
8
8
|
import { collectMultiple } from "../../utils/command-options.js";
|
|
9
9
|
import { resolveProviderAndModel } from "../../utils/provider-model.js";
|
|
10
|
+
import { buildWorkspaceSource } from "../workspace/create.js";
|
|
10
11
|
export { resolveProviderAndModel } from "../../utils/provider-model.js";
|
|
11
12
|
export function addRunOptions(cmd) {
|
|
12
13
|
return (cmd
|
|
@@ -22,10 +23,16 @@ export function addRunOptions(cmd) {
|
|
|
22
23
|
.option("--model <model>", "Model to use (e.g., claude-sonnet-4-20250514, claude-3-5-haiku-20241022)")
|
|
23
24
|
.option("--thinking <id>", "Thinking option ID to use for this run")
|
|
24
25
|
.option("--mode <mode>", "Provider-specific mode (e.g., plan, default, bypass)")
|
|
25
|
-
.option("--
|
|
26
|
+
.option("--new-workspace <local|worktree>", "Create a separate local or worktree workspace")
|
|
26
27
|
.addOption(new Option("--worktree <name>", "Legacy workspace isolation alias").hideHelp())
|
|
27
|
-
.option("--
|
|
28
|
-
.option("--
|
|
28
|
+
.option("--worktree-mode <mode>", "Worktree mode: branch-off, checkout-branch, or checkout-pr")
|
|
29
|
+
.option("--worktree-slug <slug>", "Managed worktree path slug")
|
|
30
|
+
.option("--new-branch <name>", "New branch name for branch-off mode")
|
|
31
|
+
.option("--base <ref>", "Base ref for branch-off mode")
|
|
32
|
+
.option("--branch <name>", "Existing branch for checkout-branch mode")
|
|
33
|
+
.option("--pr-number <n>", "Pull request or change request number for checkout-pr mode")
|
|
34
|
+
.option("--forge <forge>", "Forge for checkout-pr mode")
|
|
35
|
+
.option("--workspace <id>", "Run in an existing workspace (defaults to the caller workspace when agent-scoped)")
|
|
29
36
|
.option("--image <path>", "Attach image(s) to the initial prompt (can be used multiple times)", collectMultiple, [])
|
|
30
37
|
.option("--cwd <path>", "Working directory (default: current)")
|
|
31
38
|
.option("--env <key=value>", "Set environment variable(s) for the agent process (can be used multiple times)", collectMultiple, [])
|
|
@@ -44,6 +51,23 @@ export const agentRunSchema = {
|
|
|
44
51
|
{ header: "TITLE", field: "title", width: 20 },
|
|
45
52
|
],
|
|
46
53
|
};
|
|
54
|
+
function resolveNewWorkspaceKind(options) {
|
|
55
|
+
return options.newWorkspace ?? (options.worktree ? "worktree" : undefined);
|
|
56
|
+
}
|
|
57
|
+
function buildRunWorkspaceSource(options, cwd) {
|
|
58
|
+
const newWorkspace = resolveNewWorkspaceKind(options) ?? "local";
|
|
59
|
+
return buildWorkspaceSource({
|
|
60
|
+
isolation: newWorkspace,
|
|
61
|
+
path: cwd,
|
|
62
|
+
mode: options.worktreeMode,
|
|
63
|
+
worktreeSlug: options.worktreeSlug ?? options.worktree,
|
|
64
|
+
newBranch: options.newBranch,
|
|
65
|
+
base: options.base,
|
|
66
|
+
branch: options.branch,
|
|
67
|
+
prNumber: options.prNumber,
|
|
68
|
+
forge: options.forge,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
47
71
|
function toRunResult(agent, statusOverride) {
|
|
48
72
|
return {
|
|
49
73
|
agentId: agent.id,
|
|
@@ -168,34 +192,56 @@ function structuredRunSchema(output) {
|
|
|
168
192
|
serialize: () => output,
|
|
169
193
|
};
|
|
170
194
|
}
|
|
171
|
-
function
|
|
172
|
-
|
|
195
|
+
function validateRunWorkspaceOptions(options) {
|
|
196
|
+
const newWorkspace = resolveNewWorkspaceKind(options);
|
|
197
|
+
if (options.newWorkspace &&
|
|
198
|
+
options.newWorkspace !== "local" &&
|
|
199
|
+
options.newWorkspace !== "worktree") {
|
|
173
200
|
throw {
|
|
174
|
-
code: "
|
|
175
|
-
message:
|
|
176
|
-
details: "
|
|
201
|
+
code: "INVALID_OPTIONS",
|
|
202
|
+
message: `Unsupported new workspace kind: ${options.newWorkspace}`,
|
|
203
|
+
details: "Use --new-workspace local or --new-workspace worktree",
|
|
177
204
|
};
|
|
178
205
|
}
|
|
179
|
-
|
|
180
|
-
if (options.isolation && options.isolation !== "local" && options.isolation !== "worktree") {
|
|
206
|
+
if (options.newWorkspace && options.worktree) {
|
|
181
207
|
throw {
|
|
182
208
|
code: "INVALID_OPTIONS",
|
|
183
|
-
message:
|
|
184
|
-
details: "Use --
|
|
209
|
+
message: "--new-workspace and --worktree cannot be combined",
|
|
210
|
+
details: "Use --new-workspace worktree and the supported worktree options",
|
|
185
211
|
};
|
|
186
212
|
}
|
|
187
|
-
|
|
213
|
+
const hasWorktreeCreationOptions = [
|
|
214
|
+
options.worktreeMode,
|
|
215
|
+
options.worktreeSlug,
|
|
216
|
+
options.newBranch,
|
|
217
|
+
options.base,
|
|
218
|
+
options.branch,
|
|
219
|
+
options.prNumber,
|
|
220
|
+
options.forge,
|
|
221
|
+
].some((value) => value !== undefined);
|
|
222
|
+
if (hasWorktreeCreationOptions && newWorkspace !== "worktree") {
|
|
188
223
|
throw {
|
|
189
224
|
code: "INVALID_OPTIONS",
|
|
190
|
-
message: "
|
|
191
|
-
details: "Usage: paseo
|
|
225
|
+
message: "Worktree options require --new-workspace worktree",
|
|
226
|
+
details: "Usage: paseo run --new-workspace worktree [worktree options] <prompt>",
|
|
192
227
|
};
|
|
193
228
|
}
|
|
194
|
-
if (
|
|
229
|
+
if (newWorkspace === "worktree") {
|
|
230
|
+
try {
|
|
231
|
+
buildRunWorkspaceSource(options, options.cwd ?? process.cwd());
|
|
232
|
+
}
|
|
233
|
+
catch (error) {
|
|
234
|
+
throw {
|
|
235
|
+
code: "INVALID_OPTIONS",
|
|
236
|
+
message: error instanceof Error ? error.message : String(error),
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
if (options.newWorkspace && options.workspace) {
|
|
195
241
|
throw {
|
|
196
242
|
code: "INVALID_OPTIONS",
|
|
197
|
-
message: "--
|
|
198
|
-
details: "Select an existing workspace or create a new one
|
|
243
|
+
message: "--new-workspace and --workspace cannot be combined",
|
|
244
|
+
details: "Select an existing workspace or explicitly create a new one",
|
|
199
245
|
};
|
|
200
246
|
}
|
|
201
247
|
// COMPAT(worktreeRunFlag): --worktree implies a new worktree-isolated workspace.
|
|
@@ -204,9 +250,19 @@ function validateRunOptions(prompt, options, outputSchema) {
|
|
|
204
250
|
throw {
|
|
205
251
|
code: "INVALID_OPTIONS",
|
|
206
252
|
message: "--worktree and --workspace cannot be combined",
|
|
207
|
-
details: "Use --
|
|
253
|
+
details: "Use --new-workspace worktree instead of the legacy --worktree flag",
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
function validateRunOptions(prompt, options, outputSchema) {
|
|
258
|
+
if (!prompt || prompt.trim().length === 0) {
|
|
259
|
+
throw {
|
|
260
|
+
code: "MISSING_PROMPT",
|
|
261
|
+
message: "A prompt is required",
|
|
262
|
+
details: "Usage: paseo agent run [options] <prompt>",
|
|
208
263
|
};
|
|
209
264
|
}
|
|
265
|
+
validateRunWorkspaceOptions(options);
|
|
210
266
|
if (outputSchema && runsInBackground(options)) {
|
|
211
267
|
throw {
|
|
212
268
|
code: "INVALID_OPTIONS",
|
|
@@ -324,37 +380,27 @@ export async function resolveExistingRunWorkspace(client, workspaceId) {
|
|
|
324
380
|
// 1. --workspace <id> -> run in that existing workspace
|
|
325
381
|
// 2. $PASEO_AGENT_ID -> daemon resolves the caller's workspace
|
|
326
382
|
// 3. $PASEO_WORKSPACE_ID -> exported by workspace terminals
|
|
327
|
-
// 4. --
|
|
383
|
+
// 4. --new-workspace <kind> -> mint a new workspace explicitly
|
|
328
384
|
// 5. bare run -> mint a new local-backed workspace for cwd
|
|
329
385
|
async function resolveRunWorkspace(client, options, cwd) {
|
|
330
|
-
const
|
|
331
|
-
const explicit =
|
|
386
|
+
const newWorkspace = resolveNewWorkspaceKind(options);
|
|
387
|
+
const explicit = newWorkspace ? undefined : options.workspace?.trim();
|
|
332
388
|
if (explicit) {
|
|
333
389
|
console.error(`Using workspace ${explicit}`);
|
|
334
390
|
return resolveExistingRunWorkspace(client, explicit);
|
|
335
391
|
}
|
|
336
|
-
if (!
|
|
392
|
+
if (!newWorkspace && resolveRunCallerAgentId()) {
|
|
337
393
|
return { cwd };
|
|
338
394
|
}
|
|
339
|
-
const ambientWorkspaceId =
|
|
340
|
-
? undefined
|
|
341
|
-
: process.env.PASEO_WORKSPACE_ID?.trim();
|
|
395
|
+
const ambientWorkspaceId = newWorkspace ? undefined : process.env.PASEO_WORKSPACE_ID?.trim();
|
|
342
396
|
if (ambientWorkspaceId) {
|
|
343
397
|
console.error(`Using workspace ${ambientWorkspaceId}`);
|
|
344
398
|
return resolveExistingRunWorkspace(client, ambientWorkspaceId);
|
|
345
399
|
}
|
|
346
400
|
// TODO: thread the run `prompt` as firstAgentContext so workspace-level
|
|
347
401
|
// title/branch generation picks up the task description (U8/U6 deferred).
|
|
348
|
-
const
|
|
349
|
-
|
|
350
|
-
source: {
|
|
351
|
-
kind: "worktree",
|
|
352
|
-
cwd,
|
|
353
|
-
worktreeSlug: options.worktree,
|
|
354
|
-
baseBranch: options.base,
|
|
355
|
-
},
|
|
356
|
-
})
|
|
357
|
-
: await client.createWorkspace({ source: { kind: "directory", path: cwd } });
|
|
402
|
+
const source = buildRunWorkspaceSource(options, cwd);
|
|
403
|
+
const result = await client.createWorkspace({ source });
|
|
358
404
|
if (!result.workspace) {
|
|
359
405
|
throw {
|
|
360
406
|
code: "WORKSPACE_CREATE_FAILED",
|
package/dist/commands/open.d.ts
CHANGED
|
@@ -1,2 +1,4 @@
|
|
|
1
|
+
import { type AgentDeepLinkTarget } from "@getpaseo/protocol/agent-deep-link";
|
|
1
2
|
export declare function openDesktopWithProject(projectPath: string): Promise<void>;
|
|
3
|
+
export declare function openDesktopWithAgent(target: AgentDeepLinkTarget): Promise<void>;
|
|
2
4
|
//# sourceMappingURL=open.d.ts.map
|
package/dist/commands/open.js
CHANGED
|
@@ -2,6 +2,7 @@ import { existsSync } from "node:fs";
|
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { spawnProcess } from "@getpaseo/server";
|
|
5
|
+
import { buildAgentDeepLink } from "@getpaseo/protocol/agent-deep-link";
|
|
5
6
|
function findDesktopApp() {
|
|
6
7
|
if (process.platform === "darwin") {
|
|
7
8
|
const candidates = [
|
|
@@ -55,25 +56,26 @@ function spawnDetached(command, args) {
|
|
|
55
56
|
env: cleanEnvForDesktopLaunch(),
|
|
56
57
|
}).unref();
|
|
57
58
|
}
|
|
59
|
+
function launchDesktop(args) {
|
|
60
|
+
if (process.env.PASEO_DESKTOP_CLI === "1") {
|
|
61
|
+
throw new Error("Cannot open Paseo Desktop while running in desktop CLI passthrough mode.");
|
|
62
|
+
}
|
|
63
|
+
const desktopApp = findDesktopApp();
|
|
64
|
+
if (!desktopApp) {
|
|
65
|
+
throw new Error("Paseo desktop app not found. Install it from https://github.com/getpaseo/paseo/releases");
|
|
66
|
+
}
|
|
67
|
+
if (process.platform === "darwin") {
|
|
68
|
+
// -n forces a new instance even if the app is already running. The new
|
|
69
|
+
// instance relays its argv to the existing one through Electron's
|
|
70
|
+
// single-instance lock. -g keeps the terminal in the foreground.
|
|
71
|
+
spawnDetached("open", ["-n", "-g", "-a", desktopApp, "--args", ...args]);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
spawnDetached(desktopApp, args);
|
|
75
|
+
}
|
|
58
76
|
export async function openDesktopWithProject(projectPath) {
|
|
59
77
|
try {
|
|
60
|
-
|
|
61
|
-
throw new Error("Cannot open a desktop project while running in desktop CLI passthrough mode.");
|
|
62
|
-
}
|
|
63
|
-
const desktopApp = findDesktopApp();
|
|
64
|
-
if (!desktopApp) {
|
|
65
|
-
throw new Error("Paseo desktop app not found. Install it from https://github.com/getpaseo/paseo/releases");
|
|
66
|
-
}
|
|
67
|
-
if (process.platform === "darwin") {
|
|
68
|
-
// -n forces a new instance even if the app is already running.
|
|
69
|
-
// The new instance hits requestSingleInstanceLock(), fails, and relays
|
|
70
|
-
// the argv to the first instance via the second-instance event.
|
|
71
|
-
// -g keeps the terminal in the foreground (better CLI UX).
|
|
72
|
-
// Without -n, macOS just activates the existing window and drops --args.
|
|
73
|
-
spawnDetached("open", ["-n", "-g", "-a", desktopApp, "--args", projectPath]);
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
spawnDetached(desktopApp, [projectPath]);
|
|
78
|
+
launchDesktop([projectPath]);
|
|
77
79
|
}
|
|
78
80
|
catch (error) {
|
|
79
81
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -81,4 +83,7 @@ export async function openDesktopWithProject(projectPath) {
|
|
|
81
83
|
process.exitCode = 1;
|
|
82
84
|
}
|
|
83
85
|
}
|
|
86
|
+
export async function openDesktopWithAgent(target) {
|
|
87
|
+
launchDesktop([buildAgentDeepLink(target)]);
|
|
88
|
+
}
|
|
84
89
|
//# sourceMappingURL=open.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@getpaseo/cli",
|
|
3
|
-
"version": "0.2.0-beta.
|
|
3
|
+
"version": "0.2.0-beta.3",
|
|
4
4
|
"description": "Paseo CLI - control your AI coding agents from the command line",
|
|
5
5
|
"bin": {
|
|
6
6
|
"paseo": "bin/paseo"
|
|
@@ -27,9 +27,9 @@
|
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@clack/prompts": "^1.0.0",
|
|
30
|
-
"@getpaseo/client": "0.2.0-beta.
|
|
31
|
-
"@getpaseo/protocol": "0.2.0-beta.
|
|
32
|
-
"@getpaseo/server": "0.2.0-beta.
|
|
30
|
+
"@getpaseo/client": "0.2.0-beta.3",
|
|
31
|
+
"@getpaseo/protocol": "0.2.0-beta.3",
|
|
32
|
+
"@getpaseo/server": "0.2.0-beta.3",
|
|
33
33
|
"chalk": "^5.3.0",
|
|
34
34
|
"commander": "^12.0.0",
|
|
35
35
|
"mime-types": "^2.1.35",
|