@getpaseo/cli 0.2.0-beta.1 → 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/cli.js +10 -2
- package/dist/commands/agent/detach.d.ts +9 -0
- package/dist/commands/agent/detach.js +38 -0
- package/dist/commands/agent/index.js +7 -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 +34 -0
- package/dist/commands/agent/run.js +133 -45
- package/dist/commands/heartbeat/index.d.ts +3 -0
- package/dist/commands/heartbeat/index.js +139 -0
- package/dist/commands/hub/index.d.ts +3 -0
- package/dist/commands/hub/index.js +65 -0
- package/dist/commands/open.d.ts +2 -0
- package/dist/commands/open.js +22 -17
- package/dist/commands/schedule/index.js +5 -6
- package/dist/commands/schedule/inspect.js +3 -0
- package/dist/commands/schedule/logs.js +2 -1
- package/dist/commands/schedule/ls.js +3 -1
- package/dist/commands/schedule/pause.js +2 -1
- package/dist/commands/schedule/resume.js +2 -1
- package/dist/commands/schedule/run-once.js +2 -1
- package/dist/commands/schedule/shared.d.ts +2 -0
- package/dist/commands/schedule/shared.js +25 -21
- package/dist/commands/schedule/update.js +2 -1
- package/dist/commands/workspace/archive.d.ts +12 -0
- package/dist/commands/workspace/archive.js +41 -0
- package/dist/commands/workspace/create.d.ts +49 -0
- package/dist/commands/workspace/create.js +114 -0
- package/dist/commands/workspace/index.d.ts +3 -0
- package/dist/commands/workspace/index.js +30 -0
- package/dist/commands/workspace/ls.d.ts +7 -0
- package/dist/commands/workspace/ls.js +28 -0
- package/dist/commands/workspace/shared.d.ts +12 -0
- package/dist/commands/workspace/shared.js +20 -0
- package/dist/utils/duration.d.ts +1 -1
- package/dist/utils/duration.js +8 -7
- package/package.json +4 -4
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { connectToDaemon, getDaemonHost } from "../../utils/client.js";
|
|
2
|
+
import { toWorkspaceRow, workspaceSchema } from "./shared.js";
|
|
3
|
+
function assertOptionsAbsent(values, message) {
|
|
4
|
+
if (values.some((value) => value !== undefined)) {
|
|
5
|
+
throw new Error(message);
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
function buildLocalWorkspaceSource(options, path) {
|
|
9
|
+
assertOptionsAbsent([
|
|
10
|
+
options.mode,
|
|
11
|
+
options.worktreeSlug,
|
|
12
|
+
options.newBranch,
|
|
13
|
+
options.base,
|
|
14
|
+
options.branch,
|
|
15
|
+
options.prNumber,
|
|
16
|
+
options.forge,
|
|
17
|
+
], "Worktree options require --isolation worktree");
|
|
18
|
+
return {
|
|
19
|
+
kind: "directory",
|
|
20
|
+
path,
|
|
21
|
+
...(options.project ? { projectId: options.project } : {}),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function buildBranchOffSource(options, source) {
|
|
25
|
+
assertOptionsAbsent([options.branch, options.prNumber, options.forge], "--branch, --pr-number, and --forge require a checkout mode");
|
|
26
|
+
return {
|
|
27
|
+
...source,
|
|
28
|
+
action: "branch-off",
|
|
29
|
+
...(options.newBranch ? { branchName: options.newBranch } : {}),
|
|
30
|
+
...(options.base ? { baseBranch: options.base } : {}),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function buildBranchCheckoutSource(options, source) {
|
|
34
|
+
if (!options.branch) {
|
|
35
|
+
throw new Error("--branch is required for --mode checkout-branch");
|
|
36
|
+
}
|
|
37
|
+
assertOptionsAbsent([options.newBranch, options.base, options.prNumber, options.forge], "--new-branch, --base, --pr-number, and --forge are not valid for --mode checkout-branch");
|
|
38
|
+
return { ...source, action: "checkout", refName: options.branch };
|
|
39
|
+
}
|
|
40
|
+
function buildPullRequestCheckoutSource(options, source) {
|
|
41
|
+
if (options.prNumber === undefined || options.prNumber === "") {
|
|
42
|
+
throw new Error("--pr-number is required for --mode checkout-pr");
|
|
43
|
+
}
|
|
44
|
+
const prNumber = Number(options.prNumber);
|
|
45
|
+
if (!Number.isInteger(prNumber) || prNumber <= 0) {
|
|
46
|
+
throw new Error("--pr-number must be a positive integer");
|
|
47
|
+
}
|
|
48
|
+
assertOptionsAbsent([options.newBranch, options.base, options.branch], "--new-branch, --base, and --branch are not valid for --mode checkout-pr");
|
|
49
|
+
return {
|
|
50
|
+
...source,
|
|
51
|
+
action: "checkout",
|
|
52
|
+
checkoutSource: {
|
|
53
|
+
kind: "change_request",
|
|
54
|
+
...(options.forge ? { forge: options.forge } : {}),
|
|
55
|
+
number: prNumber,
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
function buildWorktreeWorkspaceSource(options, path) {
|
|
60
|
+
const source = {
|
|
61
|
+
kind: "worktree",
|
|
62
|
+
...(path ? { cwd: path } : {}),
|
|
63
|
+
...(options.project ? { projectId: options.project } : {}),
|
|
64
|
+
...(options.worktreeSlug ? { worktreeSlug: options.worktreeSlug } : {}),
|
|
65
|
+
};
|
|
66
|
+
switch (options.mode ?? "branch-off") {
|
|
67
|
+
case "branch-off":
|
|
68
|
+
return buildBranchOffSource(options, source);
|
|
69
|
+
case "checkout-branch":
|
|
70
|
+
return buildBranchCheckoutSource(options, source);
|
|
71
|
+
case "checkout-pr":
|
|
72
|
+
return buildPullRequestCheckoutSource(options, source);
|
|
73
|
+
default:
|
|
74
|
+
throw new Error(`Unsupported worktree mode: ${String(options.mode)}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
export function buildWorkspaceSource(options) {
|
|
78
|
+
if (options.isolation === "local") {
|
|
79
|
+
return buildLocalWorkspaceSource(options, options.path ?? process.cwd());
|
|
80
|
+
}
|
|
81
|
+
if (options.isolation === "worktree") {
|
|
82
|
+
const sourcePath = options.path ?? (options.project ? undefined : process.cwd());
|
|
83
|
+
return buildWorktreeWorkspaceSource(options, sourcePath);
|
|
84
|
+
}
|
|
85
|
+
throw new Error(`Unsupported workspace isolation: ${String(options.isolation)}`);
|
|
86
|
+
}
|
|
87
|
+
export async function runCreateCommand(options, _command) {
|
|
88
|
+
const host = getDaemonHost({ host: options.host });
|
|
89
|
+
const client = await connectToDaemon({ host: options.host }).catch((error) => {
|
|
90
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
91
|
+
throw {
|
|
92
|
+
code: "DAEMON_NOT_RUNNING",
|
|
93
|
+
message: `Cannot connect to daemon at ${host}: ${message}`,
|
|
94
|
+
};
|
|
95
|
+
});
|
|
96
|
+
try {
|
|
97
|
+
const payload = await client.createWorkspace({
|
|
98
|
+
source: buildWorkspaceSource(options),
|
|
99
|
+
...(options.title ? { title: options.title } : {}),
|
|
100
|
+
});
|
|
101
|
+
if (!payload.workspace) {
|
|
102
|
+
throw new Error(payload.error ?? "Workspace creation failed");
|
|
103
|
+
}
|
|
104
|
+
return { type: "single", data: toWorkspaceRow(payload.workspace), schema: workspaceSchema };
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
108
|
+
throw { code: "WORKSPACE_CREATE_FAILED", message };
|
|
109
|
+
}
|
|
110
|
+
finally {
|
|
111
|
+
await client.close().catch(() => undefined);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=create.js.map
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { withOutput } from "../../output/index.js";
|
|
3
|
+
import { addJsonAndDaemonHostOptions } from "../../utils/command-options.js";
|
|
4
|
+
import { runArchiveCommand } from "./archive.js";
|
|
5
|
+
import { runCreateCommand } from "./create.js";
|
|
6
|
+
import { runLsCommand } from "./ls.js";
|
|
7
|
+
export function createWorkspaceCommand() {
|
|
8
|
+
const workspace = new Command("workspace").description("Manage workspaces");
|
|
9
|
+
addJsonAndDaemonHostOptions(workspace
|
|
10
|
+
.command("create")
|
|
11
|
+
.description("Create a workspace")
|
|
12
|
+
.requiredOption("--isolation <local|worktree>", "Workspace isolation")
|
|
13
|
+
.option("--path <path>", "Local directory or source checkout (default: current)")
|
|
14
|
+
.option("--project <id>", "Existing project id")
|
|
15
|
+
.option("--title <title>", "Workspace title")
|
|
16
|
+
.option("--mode <mode>", "Worktree mode: branch-off, checkout-branch, or checkout-pr (default: branch-off)")
|
|
17
|
+
.option("--worktree-slug <slug>", "Managed worktree path slug")
|
|
18
|
+
.option("--new-branch <name>", "New branch name (--mode branch-off)")
|
|
19
|
+
.option("--base <ref>", "Base ref (--mode branch-off)")
|
|
20
|
+
.option("--branch <name>", "Existing branch (--mode checkout-branch)")
|
|
21
|
+
.option("--pr-number <n>", "Pull request or change request number (--mode checkout-pr)")
|
|
22
|
+
.option("--forge <forge>", "Forge for --mode checkout-pr (default: source checkout)")).action(withOutput(runCreateCommand));
|
|
23
|
+
addJsonAndDaemonHostOptions(workspace.command("ls").description("List active workspaces")).action(withOutput(runLsCommand));
|
|
24
|
+
addJsonAndDaemonHostOptions(workspace
|
|
25
|
+
.command("archive")
|
|
26
|
+
.description("Archive a workspace and everything it owns")
|
|
27
|
+
.argument("<workspace-id>", "Workspace id")).action(withOutput(runArchiveCommand));
|
|
28
|
+
return workspace;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Command } from "commander";
|
|
2
|
+
import type { ListResult } from "../../output/index.js";
|
|
3
|
+
import { type WorkspaceRow } from "./shared.js";
|
|
4
|
+
export declare function runLsCommand(options: {
|
|
5
|
+
host?: string;
|
|
6
|
+
}, _command: Command): Promise<ListResult<WorkspaceRow>>;
|
|
7
|
+
//# sourceMappingURL=ls.d.ts.map
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { connectToDaemon, getDaemonHost } from "../../utils/client.js";
|
|
2
|
+
import { toWorkspaceRow, workspaceSchema } from "./shared.js";
|
|
3
|
+
export async function runLsCommand(options, _command) {
|
|
4
|
+
const host = getDaemonHost({ host: options.host });
|
|
5
|
+
const client = await connectToDaemon({ host: options.host }).catch((error) => {
|
|
6
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
7
|
+
throw {
|
|
8
|
+
code: "DAEMON_NOT_RUNNING",
|
|
9
|
+
message: `Cannot connect to daemon at ${host}: ${message}`,
|
|
10
|
+
};
|
|
11
|
+
});
|
|
12
|
+
try {
|
|
13
|
+
const workspaces = [];
|
|
14
|
+
let cursor;
|
|
15
|
+
do {
|
|
16
|
+
const payload = await client.fetchWorkspaces({
|
|
17
|
+
page: { limit: 200, ...(cursor ? { cursor } : {}) },
|
|
18
|
+
});
|
|
19
|
+
workspaces.push(...payload.entries.map(toWorkspaceRow));
|
|
20
|
+
cursor = payload.pageInfo.nextCursor ?? undefined;
|
|
21
|
+
} while (cursor);
|
|
22
|
+
return { type: "list", data: workspaces, schema: workspaceSchema };
|
|
23
|
+
}
|
|
24
|
+
finally {
|
|
25
|
+
await client.close().catch(() => undefined);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=ls.js.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { WorkspaceDescriptorPayload } from "@getpaseo/protocol/messages";
|
|
2
|
+
import type { OutputSchema } from "../../output/index.js";
|
|
3
|
+
export interface WorkspaceRow {
|
|
4
|
+
workspaceId: string;
|
|
5
|
+
project: string;
|
|
6
|
+
name: string;
|
|
7
|
+
isolation: "local" | "worktree";
|
|
8
|
+
cwd: string;
|
|
9
|
+
}
|
|
10
|
+
export declare const workspaceSchema: OutputSchema<WorkspaceRow>;
|
|
11
|
+
export declare function toWorkspaceRow(workspace: WorkspaceDescriptorPayload): WorkspaceRow;
|
|
12
|
+
//# sourceMappingURL=shared.d.ts.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export const workspaceSchema = {
|
|
2
|
+
idField: "workspaceId",
|
|
3
|
+
columns: [
|
|
4
|
+
{ header: "WORKSPACE ID", field: "workspaceId", width: 20 },
|
|
5
|
+
{ header: "PROJECT", field: "project", width: 20 },
|
|
6
|
+
{ header: "NAME", field: "name", width: 22 },
|
|
7
|
+
{ header: "ISOLATION", field: "isolation", width: 10 },
|
|
8
|
+
{ header: "CWD", field: "cwd", width: 42 },
|
|
9
|
+
],
|
|
10
|
+
};
|
|
11
|
+
export function toWorkspaceRow(workspace) {
|
|
12
|
+
return {
|
|
13
|
+
workspaceId: workspace.id,
|
|
14
|
+
project: workspace.projectDisplayName,
|
|
15
|
+
name: workspace.name,
|
|
16
|
+
isolation: workspace.workspaceKind === "worktree" ? "worktree" : "local",
|
|
17
|
+
cwd: workspace.workspaceDirectory,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=shared.js.map
|
package/dist/utils/duration.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Parse duration string to milliseconds.
|
|
3
|
-
* Supports formats like: 5m, 30s, 1h, 2h30m, 90, etc.
|
|
3
|
+
* Supports formats like: 5m, 30s, 1h, 2h30m, 1d, 90, etc.
|
|
4
4
|
* If no unit is specified, assumes seconds.
|
|
5
5
|
*/
|
|
6
6
|
export declare function parseDuration(input: string): number;
|
package/dist/utils/duration.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Parse duration string to milliseconds.
|
|
3
|
-
* Supports formats like: 5m, 30s, 1h, 2h30m, 90, etc.
|
|
3
|
+
* Supports formats like: 5m, 30s, 1h, 2h30m, 1d, 90, etc.
|
|
4
4
|
* If no unit is specified, assumes seconds.
|
|
5
5
|
*/
|
|
6
6
|
export function parseDuration(input) {
|
|
@@ -9,13 +9,14 @@ export function parseDuration(input) {
|
|
|
9
9
|
if (/^\d+$/.test(trimmed)) {
|
|
10
10
|
return parseInt(trimmed, 10) * 1000;
|
|
11
11
|
}
|
|
12
|
+
if (!/^(?:\d+[smhd])+$/.test(trimmed)) {
|
|
13
|
+
throw new Error(`Invalid duration format: ${input}. Use formats like: 5m, 30s, 1h, 2h30m, 1d`);
|
|
14
|
+
}
|
|
12
15
|
// Parse duration with units
|
|
13
16
|
let totalMs = 0;
|
|
14
|
-
const regex = /(\d+)([
|
|
17
|
+
const regex = /(\d+)([smhd])/g;
|
|
15
18
|
let match;
|
|
16
|
-
let hasMatch = false;
|
|
17
19
|
while ((match = regex.exec(trimmed)) !== null) {
|
|
18
|
-
hasMatch = true;
|
|
19
20
|
const value = parseInt(match[1], 10);
|
|
20
21
|
const unit = match[2];
|
|
21
22
|
switch (unit) {
|
|
@@ -28,11 +29,11 @@ export function parseDuration(input) {
|
|
|
28
29
|
case "h":
|
|
29
30
|
totalMs += value * 60 * 60 * 1000;
|
|
30
31
|
break;
|
|
32
|
+
case "d":
|
|
33
|
+
totalMs += value * 24 * 60 * 60 * 1000;
|
|
34
|
+
break;
|
|
31
35
|
}
|
|
32
36
|
}
|
|
33
|
-
if (!hasMatch) {
|
|
34
|
-
throw new Error(`Invalid duration format: ${input}. Use formats like: 5m, 30s, 1h, 2h30m`);
|
|
35
|
-
}
|
|
36
37
|
return totalMs;
|
|
37
38
|
}
|
|
38
39
|
//# sourceMappingURL=duration.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",
|