@getpaseo/cli 0.2.0-beta.1 → 0.2.0-beta.2
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 +5 -0
- package/dist/commands/agent/run.d.ts +28 -0
- package/dist/commands/agent/run.js +73 -31
- 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/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
package/dist/cli.js
CHANGED
|
@@ -9,6 +9,9 @@ import { createScheduleCommand } from "./commands/schedule/index.js";
|
|
|
9
9
|
import { createSpeechCommand } from "./commands/speech/index.js";
|
|
10
10
|
import { createTerminalCommand } from "./commands/terminal/index.js";
|
|
11
11
|
import { createWorktreeCommand } from "./commands/worktree/index.js";
|
|
12
|
+
import { createWorkspaceCommand } from "./commands/workspace/index.js";
|
|
13
|
+
import { createHeartbeatCommand } from "./commands/heartbeat/index.js";
|
|
14
|
+
import { createHubCommand } from "./commands/hub/index.js";
|
|
12
15
|
import { createHooksCommand } from "./commands/hooks.js";
|
|
13
16
|
import { startCommand as daemonStartCommand } from "./commands/daemon/start.js";
|
|
14
17
|
import { runStatusCommand as runDaemonStatusCommand } from "./commands/daemon/status.js";
|
|
@@ -100,6 +103,7 @@ export function createCli() {
|
|
|
100
103
|
program.addCommand(createAgentCommand());
|
|
101
104
|
// Daemon commands
|
|
102
105
|
program.addCommand(createDaemonCommand());
|
|
106
|
+
program.addCommand(createHubCommand());
|
|
103
107
|
// Chat commands
|
|
104
108
|
program.addCommand(createChatCommand());
|
|
105
109
|
// Terminal commands
|
|
@@ -108,14 +112,18 @@ export function createCli() {
|
|
|
108
112
|
program.addCommand(createLoopCommand());
|
|
109
113
|
// Schedule commands
|
|
110
114
|
program.addCommand(createScheduleCommand());
|
|
115
|
+
program.addCommand(createHeartbeatCommand());
|
|
111
116
|
// Permission commands
|
|
112
117
|
program.addCommand(createPermitCommand());
|
|
113
118
|
// Provider commands
|
|
114
119
|
program.addCommand(createProviderCommand());
|
|
115
120
|
// Speech model commands
|
|
116
121
|
program.addCommand(createSpeechCommand());
|
|
117
|
-
//
|
|
118
|
-
program.addCommand(
|
|
122
|
+
// Workspace commands
|
|
123
|
+
program.addCommand(createWorkspaceCommand());
|
|
124
|
+
// COMPAT(worktreeCli): legacy command alias added before workspace was the product unit.
|
|
125
|
+
// Added in v0.2.0; remove after 2027-01-17.
|
|
126
|
+
program.addCommand(createWorktreeCommand(), { hidden: true });
|
|
119
127
|
return program;
|
|
120
128
|
}
|
|
121
129
|
//# sourceMappingURL=cli.js.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Command } from "commander";
|
|
2
|
+
import type { CommandOptions, SingleResult } from "../../output/index.js";
|
|
3
|
+
interface AgentDetachResult {
|
|
4
|
+
agentId: string;
|
|
5
|
+
status: "detached";
|
|
6
|
+
}
|
|
7
|
+
export declare function runDetachCommand(agentIdArg: string, options: CommandOptions, _command: Command): Promise<SingleResult<AgentDetachResult>>;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=detach.d.ts.map
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { connectToDaemon, getDaemonHost, resolveAgentId } from "../../utils/client.js";
|
|
2
|
+
const detachSchema = {
|
|
3
|
+
idField: "agentId",
|
|
4
|
+
columns: [
|
|
5
|
+
{ header: "AGENT ID", field: "agentId" },
|
|
6
|
+
{ header: "STATUS", field: "status" },
|
|
7
|
+
],
|
|
8
|
+
};
|
|
9
|
+
export async function runDetachCommand(agentIdArg, options, _command) {
|
|
10
|
+
const host = getDaemonHost({ host: options.host });
|
|
11
|
+
let client;
|
|
12
|
+
try {
|
|
13
|
+
client = await connectToDaemon({ host: options.host });
|
|
14
|
+
}
|
|
15
|
+
catch (error) {
|
|
16
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
17
|
+
throw {
|
|
18
|
+
code: "DAEMON_NOT_RUNNING",
|
|
19
|
+
message: `Cannot connect to daemon at ${host}: ${message}`,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
const payload = await client.fetchAgents({ filter: { includeArchived: true } });
|
|
24
|
+
const agentId = resolveAgentId(agentIdArg, payload.entries.map((entry) => entry.agent));
|
|
25
|
+
if (!agentId) {
|
|
26
|
+
throw {
|
|
27
|
+
code: "AGENT_NOT_FOUND",
|
|
28
|
+
message: `Agent not found: ${agentIdArg}`,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
await client.detachAgent(agentId);
|
|
32
|
+
return { type: "single", data: { agentId, status: "detached" }, schema: detachSchema };
|
|
33
|
+
}
|
|
34
|
+
finally {
|
|
35
|
+
await client.close().catch(() => undefined);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=detach.js.map
|
|
@@ -13,6 +13,7 @@ import { addAttachOptions, runAttachCommand } from "./attach.js";
|
|
|
13
13
|
import { addReloadOptions, runReloadCommand } from "./reload.js";
|
|
14
14
|
import { addImportOptions, runImportCommand } from "./import.js";
|
|
15
15
|
import { runUpdateCommand } from "./update.js";
|
|
16
|
+
import { runDetachCommand } from "./detach.js";
|
|
16
17
|
import { withOutput } from "../../output/index.js";
|
|
17
18
|
import { addDaemonHostOption, addJsonAndDaemonHostOptions, collectMultiple, } from "../../utils/command-options.js";
|
|
18
19
|
export function createAgentCommand() {
|
|
@@ -37,6 +38,10 @@ export function createAgentCommand() {
|
|
|
37
38
|
.option("--list", "List available modes for this agent")).action(withOutput(runModeCommand));
|
|
38
39
|
addJsonAndDaemonHostOptions(addArchiveOptions(agent.command("archive"))).action(withOutput(runArchiveCommand));
|
|
39
40
|
addJsonAndDaemonHostOptions(addReloadOptions(agent.command("reload"))).action(withOutput(runReloadCommand));
|
|
41
|
+
addJsonAndDaemonHostOptions(agent
|
|
42
|
+
.command("detach")
|
|
43
|
+
.description("Make a subagent independent without stopping or moving it")
|
|
44
|
+
.argument("<id>", "Agent ID, prefix, or name")).action(withOutput(runDetachCommand));
|
|
40
45
|
addJsonAndDaemonHostOptions(agent
|
|
41
46
|
.command("update")
|
|
42
47
|
.description("Update an agent's metadata")
|
|
@@ -14,6 +14,7 @@ export interface AgentRunResult {
|
|
|
14
14
|
/** Schema for agent run output */
|
|
15
15
|
export declare const agentRunSchema: OutputSchema<AgentRunResult>;
|
|
16
16
|
export interface AgentRunOptions extends CommandOptions {
|
|
17
|
+
background?: boolean;
|
|
17
18
|
detach?: boolean;
|
|
18
19
|
title?: string;
|
|
19
20
|
name?: string;
|
|
@@ -21,6 +22,7 @@ export interface AgentRunOptions extends CommandOptions {
|
|
|
21
22
|
model?: string;
|
|
22
23
|
thinking?: string;
|
|
23
24
|
mode?: string;
|
|
25
|
+
isolation?: string;
|
|
24
26
|
worktree?: string;
|
|
25
27
|
base?: string;
|
|
26
28
|
workspace?: string;
|
|
@@ -40,5 +42,31 @@ export declare function resolveStructuredResponseMessage(options: {
|
|
|
40
42
|
agentId: string;
|
|
41
43
|
lastMessage: string | null;
|
|
42
44
|
}): Promise<string | null>;
|
|
45
|
+
interface RunWorkspace {
|
|
46
|
+
id?: string;
|
|
47
|
+
cwd: string;
|
|
48
|
+
}
|
|
49
|
+
export interface RunWorkspaceLookupClient {
|
|
50
|
+
fetchWorkspaces(options: {
|
|
51
|
+
filter: {
|
|
52
|
+
query: string;
|
|
53
|
+
};
|
|
54
|
+
page: {
|
|
55
|
+
limit: number;
|
|
56
|
+
};
|
|
57
|
+
}): Promise<{
|
|
58
|
+
entries: Array<{
|
|
59
|
+
id: string;
|
|
60
|
+
workspaceDirectory: string;
|
|
61
|
+
}>;
|
|
62
|
+
pageInfo: {
|
|
63
|
+
nextCursor: string | null;
|
|
64
|
+
};
|
|
65
|
+
}>;
|
|
66
|
+
}
|
|
67
|
+
export declare function resolveExistingRunWorkspace(client: RunWorkspaceLookupClient, workspaceId: string): Promise<RunWorkspace>;
|
|
43
68
|
export declare function runRunCommand(prompt: string, options: AgentRunOptions, _command: Command): Promise<SingleResult<AgentRunResult>>;
|
|
69
|
+
export declare function resolveRunCallerAgentId(env?: {
|
|
70
|
+
PASEO_AGENT_ID?: string;
|
|
71
|
+
}): string | undefined;
|
|
44
72
|
//# sourceMappingURL=run.d.ts.map
|
|
@@ -9,25 +9,29 @@ import { collectMultiple } from "../../utils/command-options.js";
|
|
|
9
9
|
import { resolveProviderAndModel } from "../../utils/provider-model.js";
|
|
10
10
|
export { resolveProviderAndModel } from "../../utils/provider-model.js";
|
|
11
11
|
export function addRunOptions(cmd) {
|
|
12
|
-
return cmd
|
|
12
|
+
return (cmd
|
|
13
13
|
.description("Create and start an agent with a task")
|
|
14
14
|
.argument("<prompt>", "The task/prompt for the agent")
|
|
15
|
-
.option("-d, --
|
|
15
|
+
.option("-d, --background", "Run in background")
|
|
16
|
+
// COMPAT(detachRunFlag): --detach used to mean background execution, not
|
|
17
|
+
// ownership transfer. Added in v0.2.0; remove after 2027-01-17.
|
|
18
|
+
.addOption(new Option("--detach", "Legacy alias for --background").hideHelp())
|
|
16
19
|
.option("--title <title>", "Assign a title to the agent")
|
|
17
20
|
.addOption(new Option("--name <name>", "Hidden alias for --title").hideHelp())
|
|
18
21
|
.option("--provider <provider>", "Agent provider, or provider/model (e.g. codex or codex/gpt-5.4)")
|
|
19
22
|
.option("--model <model>", "Model to use (e.g., claude-sonnet-4-20250514, claude-3-5-haiku-20241022)")
|
|
20
23
|
.option("--thinking <id>", "Thinking option ID to use for this run")
|
|
21
24
|
.option("--mode <mode>", "Provider-specific mode (e.g., plan, default, bypass)")
|
|
22
|
-
.option("--
|
|
23
|
-
.
|
|
25
|
+
.option("--isolation <local|worktree>", "Create a new workspace with this isolation")
|
|
26
|
+
.addOption(new Option("--worktree <name>", "Legacy workspace isolation alias").hideHelp())
|
|
27
|
+
.option("--base <branch>", "Base branch for an isolated workspace")
|
|
24
28
|
.option("--workspace <id>", "Run in an existing workspace (default: a new workspace is created per run; falls back to $PASEO_WORKSPACE_ID)")
|
|
25
29
|
.option("--image <path>", "Attach image(s) to the initial prompt (can be used multiple times)", collectMultiple, [])
|
|
26
30
|
.option("--cwd <path>", "Working directory (default: current)")
|
|
27
31
|
.option("--env <key=value>", "Set environment variable(s) for the agent process (can be used multiple times)", collectMultiple, [])
|
|
28
32
|
.option("--label <key=value>", "Add label(s) to the agent (can be used multiple times)", collectMultiple, [])
|
|
29
33
|
.option("--wait-timeout <duration>", "Maximum time to wait for agent to finish (e.g., 30s, 5m, 1h). Default: no limit")
|
|
30
|
-
.option("--output-schema <schema>", "Output JSON matching the provided schema file path or inline JSON schema");
|
|
34
|
+
.option("--output-schema <schema>", "Output JSON matching the provided schema file path or inline JSON schema"));
|
|
31
35
|
}
|
|
32
36
|
/** Schema for agent run output */
|
|
33
37
|
export const agentRunSchema = {
|
|
@@ -172,35 +176,48 @@ function validateRunOptions(prompt, options, outputSchema) {
|
|
|
172
176
|
details: "Usage: paseo agent run [options] <prompt>",
|
|
173
177
|
};
|
|
174
178
|
}
|
|
175
|
-
|
|
179
|
+
const createsIsolatedWorkspace = options.isolation === "worktree" || Boolean(options.worktree);
|
|
180
|
+
if (options.isolation && options.isolation !== "local" && options.isolation !== "worktree") {
|
|
176
181
|
throw {
|
|
177
182
|
code: "INVALID_OPTIONS",
|
|
178
|
-
message:
|
|
179
|
-
details: "
|
|
183
|
+
message: `Unsupported workspace isolation: ${options.isolation}`,
|
|
184
|
+
details: "Use --isolation local or --isolation worktree",
|
|
180
185
|
};
|
|
181
186
|
}
|
|
182
|
-
if (options.
|
|
187
|
+
if (options.base && !createsIsolatedWorkspace) {
|
|
183
188
|
throw {
|
|
184
189
|
code: "INVALID_OPTIONS",
|
|
185
|
-
message: "--
|
|
186
|
-
details: "
|
|
190
|
+
message: "--base can only be used with --isolation worktree",
|
|
191
|
+
details: "Usage: paseo agent run --isolation worktree --base <branch> <prompt>",
|
|
187
192
|
};
|
|
188
193
|
}
|
|
189
|
-
if (options.
|
|
194
|
+
if (options.isolation && options.workspace) {
|
|
190
195
|
throw {
|
|
191
196
|
code: "INVALID_OPTIONS",
|
|
192
|
-
message: "--
|
|
193
|
-
details: "
|
|
197
|
+
message: "--isolation and --workspace cannot be combined",
|
|
198
|
+
details: "Select an existing workspace or create a new one with an isolation choice",
|
|
194
199
|
};
|
|
195
200
|
}
|
|
196
|
-
|
|
201
|
+
// COMPAT(worktreeRunFlag): --worktree implies a new worktree-isolated workspace.
|
|
202
|
+
// Added in v0.2.0; remove after 2027-01-17.
|
|
203
|
+
if (options.worktree && options.workspace) {
|
|
197
204
|
throw {
|
|
198
205
|
code: "INVALID_OPTIONS",
|
|
199
|
-
message: "--
|
|
206
|
+
message: "--worktree and --workspace cannot be combined",
|
|
207
|
+
details: "Use --isolation worktree instead of the legacy --worktree flag",
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
if (outputSchema && runsInBackground(options)) {
|
|
211
|
+
throw {
|
|
212
|
+
code: "INVALID_OPTIONS",
|
|
213
|
+
message: "--output-schema cannot be used with --background",
|
|
200
214
|
details: "Structured output requires waiting for the agent to finish",
|
|
201
215
|
};
|
|
202
216
|
}
|
|
203
217
|
}
|
|
218
|
+
function runsInBackground(options) {
|
|
219
|
+
return Boolean(options.background || options.detach);
|
|
220
|
+
}
|
|
204
221
|
function parseWaitTimeoutOption(waitTimeout) {
|
|
205
222
|
if (!waitTimeout)
|
|
206
223
|
return 0;
|
|
@@ -289,27 +306,46 @@ async function connectToDaemonOrThrow(hostOption, host) {
|
|
|
289
306
|
};
|
|
290
307
|
}
|
|
291
308
|
}
|
|
309
|
+
export async function resolveExistingRunWorkspace(client, workspaceId) {
|
|
310
|
+
const result = await client.fetchWorkspaces({
|
|
311
|
+
filter: { query: workspaceId },
|
|
312
|
+
page: { limit: 200 },
|
|
313
|
+
});
|
|
314
|
+
const workspace = result.entries.find((entry) => entry.id === workspaceId);
|
|
315
|
+
if (workspace) {
|
|
316
|
+
return { id: workspace.id, cwd: workspace.workspaceDirectory };
|
|
317
|
+
}
|
|
318
|
+
throw {
|
|
319
|
+
code: "WORKSPACE_NOT_FOUND",
|
|
320
|
+
message: `Workspace not found: ${workspaceId}`,
|
|
321
|
+
};
|
|
322
|
+
}
|
|
292
323
|
// Workspace policy for `paseo run`. Precedence:
|
|
293
324
|
// 1. --workspace <id> -> run in that existing workspace
|
|
294
|
-
// 2. $
|
|
295
|
-
// 3.
|
|
296
|
-
// 4.
|
|
297
|
-
//
|
|
298
|
-
// $PASEO_WORKSPACE_ID (validateRunOptions), so worktree resolution here never
|
|
299
|
-
// races an existing-workspace selection.
|
|
325
|
+
// 2. $PASEO_AGENT_ID -> daemon resolves the caller's workspace
|
|
326
|
+
// 3. $PASEO_WORKSPACE_ID -> exported by workspace terminals
|
|
327
|
+
// 4. --isolation <kind> -> mint a new workspace with explicit isolation
|
|
328
|
+
// 5. bare run -> mint a new local-backed workspace for cwd
|
|
300
329
|
async function resolveRunWorkspace(client, options, cwd) {
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
const explicit = options.worktree
|
|
304
|
-
? undefined
|
|
305
|
-
: options.workspace?.trim() || process.env.PASEO_WORKSPACE_ID?.trim();
|
|
330
|
+
const requestedIsolation = options.isolation ?? (options.worktree ? "worktree" : undefined);
|
|
331
|
+
const explicit = requestedIsolation ? undefined : options.workspace?.trim();
|
|
306
332
|
if (explicit) {
|
|
307
333
|
console.error(`Using workspace ${explicit}`);
|
|
308
|
-
return
|
|
334
|
+
return resolveExistingRunWorkspace(client, explicit);
|
|
335
|
+
}
|
|
336
|
+
if (!requestedIsolation && resolveRunCallerAgentId()) {
|
|
337
|
+
return { cwd };
|
|
338
|
+
}
|
|
339
|
+
const ambientWorkspaceId = requestedIsolation
|
|
340
|
+
? undefined
|
|
341
|
+
: process.env.PASEO_WORKSPACE_ID?.trim();
|
|
342
|
+
if (ambientWorkspaceId) {
|
|
343
|
+
console.error(`Using workspace ${ambientWorkspaceId}`);
|
|
344
|
+
return resolveExistingRunWorkspace(client, ambientWorkspaceId);
|
|
309
345
|
}
|
|
310
346
|
// TODO: thread the run `prompt` as firstAgentContext so workspace-level
|
|
311
347
|
// title/branch generation picks up the task description (U8/U6 deferred).
|
|
312
|
-
const result =
|
|
348
|
+
const result = requestedIsolation === "worktree"
|
|
313
349
|
? await client.createWorkspace({
|
|
314
350
|
source: {
|
|
315
351
|
kind: "worktree",
|
|
@@ -357,6 +393,7 @@ export async function runRunCommand(prompt, options, _command) {
|
|
|
357
393
|
const requestEnv = Object.keys(env).length > 0 ? env : undefined;
|
|
358
394
|
const workspace = await resolveRunWorkspace(client, options, cwd);
|
|
359
395
|
const workspaceId = workspace.id;
|
|
396
|
+
const callerAgentId = resolveRunCallerAgentId();
|
|
360
397
|
const runCwd = workspace.cwd;
|
|
361
398
|
if (outputSchema) {
|
|
362
399
|
let structuredAgent = null;
|
|
@@ -366,6 +403,7 @@ export async function runRunCommand(prompt, options, _command) {
|
|
|
366
403
|
provider: resolvedProviderModel.provider,
|
|
367
404
|
cwd: runCwd,
|
|
368
405
|
workspaceId,
|
|
406
|
+
callerAgentId,
|
|
369
407
|
title: resolvedTitle,
|
|
370
408
|
modeId: options.mode,
|
|
371
409
|
model: resolvedProviderModel.model,
|
|
@@ -420,6 +458,7 @@ export async function runRunCommand(prompt, options, _command) {
|
|
|
420
458
|
provider: resolvedProviderModel.provider,
|
|
421
459
|
cwd: runCwd,
|
|
422
460
|
workspaceId,
|
|
461
|
+
callerAgentId,
|
|
423
462
|
title: resolvedTitle,
|
|
424
463
|
modeId: options.mode,
|
|
425
464
|
model: resolvedProviderModel.model,
|
|
@@ -429,8 +468,8 @@ export async function runRunCommand(prompt, options, _command) {
|
|
|
429
468
|
env: requestEnv,
|
|
430
469
|
labels: Object.keys(labels).length > 0 ? labels : undefined,
|
|
431
470
|
});
|
|
432
|
-
// Default run behavior is foreground: wait for completion unless
|
|
433
|
-
if (!options
|
|
471
|
+
// Default run behavior is foreground: wait for completion unless background execution is set.
|
|
472
|
+
if (!runsInBackground(options)) {
|
|
434
473
|
const state = await client.waitForFinish(agent.id, waitTimeoutMs);
|
|
435
474
|
await client.close();
|
|
436
475
|
const finalAgent = state.final ?? agent;
|
|
@@ -461,4 +500,7 @@ export async function runRunCommand(prompt, options, _command) {
|
|
|
461
500
|
throw error;
|
|
462
501
|
}
|
|
463
502
|
}
|
|
503
|
+
export function resolveRunCallerAgentId(env = process.env) {
|
|
504
|
+
return env.PASEO_AGENT_ID?.trim() || undefined;
|
|
505
|
+
}
|
|
464
506
|
//# sourceMappingURL=run.js.map
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { withOutput } from "../../output/index.js";
|
|
3
|
+
import { addJsonAndDaemonHostOptions } from "../../utils/command-options.js";
|
|
4
|
+
import { parseDuration } from "../../utils/duration.js";
|
|
5
|
+
import { connectScheduleClient, toScheduleCommandError, toScheduleRow, } from "../schedule/shared.js";
|
|
6
|
+
import { scheduleSchema } from "../schedule/schema.js";
|
|
7
|
+
const heartbeatDeleteSchema = {
|
|
8
|
+
idField: "id",
|
|
9
|
+
columns: [
|
|
10
|
+
{ header: "ID", field: "id" },
|
|
11
|
+
{ header: "STATUS", field: "status" },
|
|
12
|
+
],
|
|
13
|
+
};
|
|
14
|
+
function requireCallerAgentId() {
|
|
15
|
+
const agentId = process.env.PASEO_AGENT_ID?.trim();
|
|
16
|
+
if (!agentId) {
|
|
17
|
+
throw new Error("Heartbeat commands must run inside a Paseo agent");
|
|
18
|
+
}
|
|
19
|
+
return agentId;
|
|
20
|
+
}
|
|
21
|
+
async function requireOwnedHeartbeat(client, id, agentId) {
|
|
22
|
+
const payload = await client.scheduleInspect({ id });
|
|
23
|
+
if (payload.error || !payload.schedule) {
|
|
24
|
+
throw new Error(payload.error ?? `Heartbeat not found: ${id}`);
|
|
25
|
+
}
|
|
26
|
+
if (payload.schedule.target.type !== "agent" || payload.schedule.target.agentId !== agentId) {
|
|
27
|
+
throw new Error(`Heartbeat ${id} does not belong to agent ${agentId}`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
async function runCreateHeartbeat(prompt, options, _command) {
|
|
31
|
+
const agentId = requireCallerAgentId();
|
|
32
|
+
const cron = options.cron?.trim();
|
|
33
|
+
if (!cron) {
|
|
34
|
+
throw new Error("--cron is required");
|
|
35
|
+
}
|
|
36
|
+
const { client } = await connectScheduleClient(options.host);
|
|
37
|
+
try {
|
|
38
|
+
const maxRuns = options.maxRuns ? Number.parseInt(options.maxRuns, 10) : undefined;
|
|
39
|
+
if (maxRuns !== undefined && (!Number.isSafeInteger(maxRuns) || maxRuns <= 0)) {
|
|
40
|
+
throw new Error("--max-runs must be a positive integer");
|
|
41
|
+
}
|
|
42
|
+
const payload = await client.scheduleCreate({
|
|
43
|
+
prompt: prompt.trim(),
|
|
44
|
+
cadence: {
|
|
45
|
+
type: "cron",
|
|
46
|
+
expression: cron,
|
|
47
|
+
...(options.timezone?.trim() ? { timezone: options.timezone.trim() } : {}),
|
|
48
|
+
},
|
|
49
|
+
target: { type: "agent", agentId },
|
|
50
|
+
...(options.name?.trim() ? { name: options.name.trim() } : {}),
|
|
51
|
+
...(maxRuns ? { maxRuns } : {}),
|
|
52
|
+
...(options.expiresIn
|
|
53
|
+
? { expiresAt: new Date(Date.now() + parseDuration(options.expiresIn)).toISOString() }
|
|
54
|
+
: {}),
|
|
55
|
+
});
|
|
56
|
+
if (payload.error || !payload.schedule) {
|
|
57
|
+
throw new Error(payload.error ?? "Heartbeat creation failed");
|
|
58
|
+
}
|
|
59
|
+
return { type: "single", data: toScheduleRow(payload.schedule), schema: scheduleSchema };
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
throw toScheduleCommandError("HEARTBEAT_CREATE_FAILED", "create heartbeat", error);
|
|
63
|
+
}
|
|
64
|
+
finally {
|
|
65
|
+
await client.close().catch(() => undefined);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
async function runUpdateHeartbeat(id, options, _command) {
|
|
69
|
+
const agentId = requireCallerAgentId();
|
|
70
|
+
const cron = options.cron?.trim();
|
|
71
|
+
if (!cron) {
|
|
72
|
+
throw new Error("--cron is required");
|
|
73
|
+
}
|
|
74
|
+
const { client } = await connectScheduleClient(options.host);
|
|
75
|
+
try {
|
|
76
|
+
await requireOwnedHeartbeat(client, id, agentId);
|
|
77
|
+
const payload = await client.scheduleUpdate({
|
|
78
|
+
id,
|
|
79
|
+
cadence: {
|
|
80
|
+
type: "cron",
|
|
81
|
+
expression: cron,
|
|
82
|
+
...(options.timezone?.trim() ? { timezone: options.timezone.trim() } : {}),
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
if (payload.error || !payload.schedule) {
|
|
86
|
+
throw new Error(payload.error ?? `Heartbeat update failed: ${id}`);
|
|
87
|
+
}
|
|
88
|
+
return { type: "single", data: toScheduleRow(payload.schedule), schema: scheduleSchema };
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
throw toScheduleCommandError("HEARTBEAT_UPDATE_FAILED", "update heartbeat", error);
|
|
92
|
+
}
|
|
93
|
+
finally {
|
|
94
|
+
await client.close().catch(() => undefined);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
async function runDeleteHeartbeat(id, options, _command) {
|
|
98
|
+
const agentId = requireCallerAgentId();
|
|
99
|
+
const { client } = await connectScheduleClient(options.host);
|
|
100
|
+
try {
|
|
101
|
+
await requireOwnedHeartbeat(client, id, agentId);
|
|
102
|
+
const payload = await client.scheduleDelete({ id });
|
|
103
|
+
if (payload.error) {
|
|
104
|
+
throw new Error(payload.error);
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
type: "single",
|
|
108
|
+
data: { id: payload.scheduleId, status: "deleted" },
|
|
109
|
+
schema: heartbeatDeleteSchema,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
throw toScheduleCommandError("HEARTBEAT_DELETE_FAILED", "delete heartbeat", error);
|
|
114
|
+
}
|
|
115
|
+
finally {
|
|
116
|
+
await client.close().catch(() => undefined);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
export function createHeartbeatCommand() {
|
|
120
|
+
const heartbeat = new Command("heartbeat").description("Manage this agent's heartbeats");
|
|
121
|
+
addJsonAndDaemonHostOptions(heartbeat
|
|
122
|
+
.command("create")
|
|
123
|
+
.description("Create a recurring prompt for this agent")
|
|
124
|
+
.argument("<prompt>", "Prompt to send")
|
|
125
|
+
.requiredOption("--cron <expr>", "Five-field cron cadence")
|
|
126
|
+
.option("--timezone <iana>", "IANA time zone")
|
|
127
|
+
.option("--name <name>", "Heartbeat name")
|
|
128
|
+
.option("--max-runs <n>", "Maximum number of runs")
|
|
129
|
+
.option("--expires-in <duration>", "Time to live")).action(withOutput(runCreateHeartbeat));
|
|
130
|
+
addJsonAndDaemonHostOptions(heartbeat
|
|
131
|
+
.command("update")
|
|
132
|
+
.description("Change a heartbeat cron cadence")
|
|
133
|
+
.argument("<id>", "Heartbeat ID")
|
|
134
|
+
.requiredOption("--cron <expr>", "Five-field cron cadence")
|
|
135
|
+
.option("--timezone <iana>", "IANA time zone")).action(withOutput(runUpdateHeartbeat));
|
|
136
|
+
addJsonAndDaemonHostOptions(heartbeat.command("delete").description("Delete a heartbeat").argument("<id>", "Heartbeat ID")).action(withOutput(runDeleteHeartbeat));
|
|
137
|
+
return heartbeat;
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { withOutput } from "../../output/index.js";
|
|
3
|
+
import { addJsonAndDaemonHostOptions } from "../../utils/command-options.js";
|
|
4
|
+
import { connectToDaemon } from "../../utils/client.js";
|
|
5
|
+
const schema = {
|
|
6
|
+
idField: "state",
|
|
7
|
+
columns: [
|
|
8
|
+
{ header: "STATE", field: "state" },
|
|
9
|
+
{ header: "HUB", field: "hub" },
|
|
10
|
+
{ header: "DAEMON", field: "daemonId" },
|
|
11
|
+
{ header: "SCOPES", field: "scopes" },
|
|
12
|
+
{ header: "CONNECTED", field: "connectedAt" },
|
|
13
|
+
{ header: "ERROR", field: "error" },
|
|
14
|
+
{ header: "WARNING", field: "warning" },
|
|
15
|
+
],
|
|
16
|
+
};
|
|
17
|
+
function result(status, warning) {
|
|
18
|
+
return {
|
|
19
|
+
type: "list",
|
|
20
|
+
data: [
|
|
21
|
+
{
|
|
22
|
+
state: status.state,
|
|
23
|
+
daemonId: status.daemonId,
|
|
24
|
+
hub: status.hubOrigin,
|
|
25
|
+
scopes: status.scopes.join(", "),
|
|
26
|
+
connectedAt: status.connectedAt,
|
|
27
|
+
error: status.lastError,
|
|
28
|
+
warning,
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
schema,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
async function withClient(host, action) {
|
|
35
|
+
const client = await connectToDaemon({ host });
|
|
36
|
+
try {
|
|
37
|
+
return await action(client);
|
|
38
|
+
}
|
|
39
|
+
finally {
|
|
40
|
+
await client.close().catch(() => undefined);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
export function createHubCommand() {
|
|
44
|
+
const hub = new Command("hub").description("Manage this daemon's Paseo Hub relationship");
|
|
45
|
+
addJsonAndDaemonHostOptions(hub.command("connect").argument("<url>").requiredOption("--token <token>")).action(withOutput(async (...args) => {
|
|
46
|
+
const url = args[0];
|
|
47
|
+
const options = args.at(-2);
|
|
48
|
+
return withClient(options.host, async (client) => result((await client.connectHub(url, options.token)).status));
|
|
49
|
+
}));
|
|
50
|
+
addJsonAndDaemonHostOptions(hub.command("status")).action(withOutput(async (...args) => {
|
|
51
|
+
const options = args.at(-2);
|
|
52
|
+
return withClient(options.host, async (client) => result((await client.getHubStatus()).status));
|
|
53
|
+
}));
|
|
54
|
+
addJsonAndDaemonHostOptions(hub
|
|
55
|
+
.command("disconnect")
|
|
56
|
+
.option("--force", "Remove local authority even if the Hub is offline")).action(withOutput(async (...args) => {
|
|
57
|
+
const options = args.at(-2);
|
|
58
|
+
return withClient(options.host, async (client) => {
|
|
59
|
+
const response = await client.disconnectHub(options.force ?? false);
|
|
60
|
+
return result(response.status, response.warning);
|
|
61
|
+
});
|
|
62
|
+
}));
|
|
63
|
+
return hub;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Command } from "commander";
|
|
1
|
+
import { Command, Option } from "commander";
|
|
2
2
|
import { withOutput } from "../../output/index.js";
|
|
3
3
|
import { addJsonAndDaemonHostOptions } from "../../utils/command-options.js";
|
|
4
4
|
import { runCreateCommand } from "./create.js";
|
|
@@ -16,16 +16,15 @@ export function createScheduleCommand() {
|
|
|
16
16
|
.command("create")
|
|
17
17
|
.description("Create a schedule")
|
|
18
18
|
.argument("<prompt>", "Prompt to run on the schedule")
|
|
19
|
-
.option("--every <duration>", "
|
|
19
|
+
.option("--every <duration>", "Cron-compatible cadence preset (for example: 5m, 1h)")
|
|
20
20
|
.option("--cron <expr>", "Cron cadence expression")
|
|
21
21
|
.option("--timezone <iana>", "IANA time zone for cron cadence (default: UTC)")
|
|
22
22
|
.option("--name <name>", "Optional schedule name")
|
|
23
|
-
.
|
|
23
|
+
.addOption(new Option("--target <target>", "Legacy schedule target").hideHelp())
|
|
24
24
|
.option("--provider <provider>", "Agent provider, or provider/model (e.g. codex or codex/gpt-5.4)")
|
|
25
25
|
.option("--mode <mode>", "Provider-specific mode (e.g. claude bypassPermissions, opencode build)")
|
|
26
26
|
.option("--cwd <path>", "Working directory (default: current; required with --host)")
|
|
27
|
-
.option("--run-now", "Fire one immediate run on creation
|
|
28
|
-
.option("--no-run-now", "Wait the full interval before the first run (only with --every)")
|
|
27
|
+
.option("--run-now", "Fire one immediate run on creation")
|
|
29
28
|
.option("--max-runs <n>", "Maximum number of runs")
|
|
30
29
|
.option("--expires-in <duration>", "Time to live for the schedule")).action(withOutput(runCreateCommand));
|
|
31
30
|
addJsonAndDaemonHostOptions(schedule.command("ls").description("List schedules")).action(withOutput(runLsCommand));
|
|
@@ -48,7 +47,7 @@ export function createScheduleCommand() {
|
|
|
48
47
|
.command("update")
|
|
49
48
|
.description("Update an existing schedule in place")
|
|
50
49
|
.argument("<id>", "Schedule ID")
|
|
51
|
-
.option("--every <duration>", "
|
|
50
|
+
.option("--every <duration>", "Cron-compatible cadence preset (for example: 5m, 1h)")
|
|
52
51
|
.option("--cron <expr>", "Switch to cron cadence expression")
|
|
53
52
|
.option("--timezone <iana>", "IANA time zone for cron cadence (requires --cron)")
|
|
54
53
|
.option("--name <name>", "Rename the schedule (empty string clears the name)")
|
|
@@ -7,6 +7,9 @@ export async function runInspectCommand(id, options, _command) {
|
|
|
7
7
|
if (payload.error || !payload.schedule) {
|
|
8
8
|
throw new Error(payload.error ?? `Schedule not found: ${id}`);
|
|
9
9
|
}
|
|
10
|
+
if (payload.schedule.target.type !== "new-agent") {
|
|
11
|
+
throw new Error(`Schedule not found: ${id}`);
|
|
12
|
+
}
|
|
10
13
|
const rows = createScheduleInspectRows(payload.schedule);
|
|
11
14
|
return {
|
|
12
15
|
type: "list",
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { scheduleLogSchema, toScheduleLogRow } from "./schema.js";
|
|
2
|
-
import { connectScheduleClient, toScheduleCommandError, } from "./shared.js";
|
|
2
|
+
import { connectScheduleClient, requireNewAgentSchedule, toScheduleCommandError, } from "./shared.js";
|
|
3
3
|
export async function runLogsCommand(id, options, _command) {
|
|
4
4
|
const { client } = await connectScheduleClient(options.host);
|
|
5
5
|
try {
|
|
6
|
+
await requireNewAgentSchedule(client, id);
|
|
6
7
|
const payload = await client.scheduleLogs({ id });
|
|
7
8
|
if (payload.error) {
|
|
8
9
|
throw new Error(payload.error);
|
|
@@ -9,7 +9,9 @@ export async function runLsCommand(options, _command) {
|
|
|
9
9
|
}
|
|
10
10
|
return {
|
|
11
11
|
type: "list",
|
|
12
|
-
data: payload.schedules
|
|
12
|
+
data: payload.schedules
|
|
13
|
+
.filter((schedule) => schedule.target.type === "new-agent")
|
|
14
|
+
.map(toScheduleRow),
|
|
13
15
|
schema: scheduleSchema,
|
|
14
16
|
};
|
|
15
17
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { scheduleSchema } from "./schema.js";
|
|
2
|
-
import { connectScheduleClient, toScheduleCommandError, toScheduleRow, } from "./shared.js";
|
|
2
|
+
import { connectScheduleClient, requireNewAgentSchedule, toScheduleCommandError, toScheduleRow, } from "./shared.js";
|
|
3
3
|
export async function runPauseCommand(id, options, _command) {
|
|
4
4
|
const { client } = await connectScheduleClient(options.host);
|
|
5
5
|
try {
|
|
6
|
+
await requireNewAgentSchedule(client, id);
|
|
6
7
|
const payload = await client.schedulePause({ id });
|
|
7
8
|
if (payload.error || !payload.schedule) {
|
|
8
9
|
throw new Error(payload.error ?? `Failed to pause schedule: ${id}`);
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { scheduleSchema } from "./schema.js";
|
|
2
|
-
import { connectScheduleClient, toScheduleCommandError, toScheduleRow, } from "./shared.js";
|
|
2
|
+
import { connectScheduleClient, requireNewAgentSchedule, toScheduleCommandError, toScheduleRow, } from "./shared.js";
|
|
3
3
|
export async function runResumeCommand(id, options, _command) {
|
|
4
4
|
const { client } = await connectScheduleClient(options.host);
|
|
5
5
|
try {
|
|
6
|
+
await requireNewAgentSchedule(client, id);
|
|
6
7
|
const payload = await client.scheduleResume({ id });
|
|
7
8
|
if (payload.error || !payload.schedule) {
|
|
8
9
|
throw new Error(payload.error ?? `Failed to resume schedule: ${id}`);
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { scheduleSchema } from "./schema.js";
|
|
2
|
-
import { connectScheduleClient, toScheduleCommandError, toScheduleRow, } from "./shared.js";
|
|
2
|
+
import { connectScheduleClient, requireNewAgentSchedule, toScheduleCommandError, toScheduleRow, } from "./shared.js";
|
|
3
3
|
export async function runRunOnceCommand(id, options, _command) {
|
|
4
4
|
const { client } = await connectScheduleClient(options.host);
|
|
5
5
|
try {
|
|
6
|
+
await requireNewAgentSchedule(client, id);
|
|
6
7
|
const payload = await client.scheduleRunOnce({ id });
|
|
7
8
|
if (payload.error || !payload.schedule) {
|
|
8
9
|
throw new Error(payload.error ?? `Failed to run schedule once: ${id}`);
|
|
@@ -8,6 +8,7 @@ export declare function connectScheduleClient(host: string | undefined): Promise
|
|
|
8
8
|
host: string;
|
|
9
9
|
}>;
|
|
10
10
|
export declare function toScheduleCommandError(code: string, action: string, error: unknown): CommandError;
|
|
11
|
+
export declare function requireNewAgentSchedule(client: ScheduleDaemonClient, id: string): Promise<void>;
|
|
11
12
|
export declare function formatCadence(cadence: ScheduleCadence): string;
|
|
12
13
|
export declare function formatTarget(target: ScheduleTarget | ScheduleListItem["target"]): string;
|
|
13
14
|
export declare function formatDurationMs(durationMs: number): string;
|
|
@@ -43,6 +44,7 @@ export interface ScheduleUpdateOptionsInput {
|
|
|
43
44
|
clearExpires?: boolean;
|
|
44
45
|
}
|
|
45
46
|
export declare function parseScheduleUpdateInput(options: ScheduleUpdateOptionsInput): UpdateScheduleInput;
|
|
47
|
+
export declare function compileEveryPresetToCron(value: string): string;
|
|
46
48
|
export interface ScheduleRow {
|
|
47
49
|
id: string;
|
|
48
50
|
name: string | null;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { connectToDaemon, getDaemonHost } from "../../utils/client.js";
|
|
2
2
|
import { parseDuration } from "../../utils/duration.js";
|
|
3
3
|
import { resolveProviderAndModel } from "../../utils/provider-model.js";
|
|
4
|
+
import { everyMsToFiveFieldCron } from "@getpaseo/protocol/schedule/cadence";
|
|
4
5
|
export async function connectScheduleClient(host) {
|
|
5
6
|
const resolvedHost = getDaemonHost({ host });
|
|
6
7
|
try {
|
|
@@ -28,6 +29,12 @@ export function toScheduleCommandError(code, action, error) {
|
|
|
28
29
|
message: `Failed to ${action}: ${message}`,
|
|
29
30
|
};
|
|
30
31
|
}
|
|
32
|
+
export async function requireNewAgentSchedule(client, id) {
|
|
33
|
+
const payload = await client.scheduleInspect({ id });
|
|
34
|
+
if (payload.error || !payload.schedule || payload.schedule.target.type !== "new-agent") {
|
|
35
|
+
throw new Error(payload.error ?? `Schedule not found: ${id}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
31
38
|
export function formatCadence(cadence) {
|
|
32
39
|
if (cadence.type === "cron") {
|
|
33
40
|
const timezoneSuffix = cadence.timezone ? ` (${cadence.timezone})` : "";
|
|
@@ -66,11 +73,7 @@ export function formatDurationMs(durationMs) {
|
|
|
66
73
|
}
|
|
67
74
|
function resolveScheduleTarget(args) {
|
|
68
75
|
const { targetValue, hasExplicitNewAgentOption, createNewAgentTarget } = args;
|
|
69
|
-
const currentAgentId = process.env.PASEO_AGENT_ID?.trim();
|
|
70
76
|
if (!targetValue) {
|
|
71
|
-
if (currentAgentId && !hasExplicitNewAgentOption) {
|
|
72
|
-
return { type: "self", agentId: currentAgentId };
|
|
73
|
-
}
|
|
74
77
|
return createNewAgentTarget();
|
|
75
78
|
}
|
|
76
79
|
if (targetValue === "new-agent") {
|
|
@@ -84,6 +87,9 @@ function resolveScheduleTarget(args) {
|
|
|
84
87
|
};
|
|
85
88
|
}
|
|
86
89
|
if (targetValue === "self") {
|
|
90
|
+
// COMPAT(scheduleSelfTarget): heartbeat creation moved to `paseo heartbeat create`.
|
|
91
|
+
// Added in v0.2.0; remove after 2027-01-17.
|
|
92
|
+
const currentAgentId = process.env.PASEO_AGENT_ID?.trim();
|
|
87
93
|
if (!currentAgentId) {
|
|
88
94
|
throw {
|
|
89
95
|
code: "INVALID_TARGET",
|
|
@@ -153,22 +159,8 @@ export function parseScheduleCreateInput(options) {
|
|
|
153
159
|
...(expiresAt ? { expiresAt } : {}),
|
|
154
160
|
};
|
|
155
161
|
}
|
|
156
|
-
function resolveRunOnCreate(runNow,
|
|
157
|
-
|
|
158
|
-
throw {
|
|
159
|
-
code: "REDUNDANT_RUN_NOW",
|
|
160
|
-
message: "--run-now is redundant with --every (interval schedules already fire on creation)",
|
|
161
|
-
details: "Drop --run-now, or use --no-run-now to wait the full interval before the first run",
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
|
-
if (runNow === false && cadenceType === "cron") {
|
|
165
|
-
throw {
|
|
166
|
-
code: "REDUNDANT_NO_RUN_NOW",
|
|
167
|
-
message: "--no-run-now is redundant with --cron (cron schedules never fire on creation)",
|
|
168
|
-
details: "Drop --no-run-now, or use --run-now to fire one immediate run on creation",
|
|
169
|
-
};
|
|
170
|
-
}
|
|
171
|
-
return runNow ?? cadenceType === "every";
|
|
162
|
+
function resolveRunOnCreate(runNow, _cadenceType) {
|
|
163
|
+
return runNow ?? false;
|
|
172
164
|
}
|
|
173
165
|
export function parseScheduleUpdateInput(options) {
|
|
174
166
|
const id = options.id.trim();
|
|
@@ -220,7 +212,7 @@ function parseCadenceFromFlags(every, cron, timezone) {
|
|
|
220
212
|
};
|
|
221
213
|
}
|
|
222
214
|
if (every !== undefined) {
|
|
223
|
-
return { type: "
|
|
215
|
+
return { type: "cron", expression: compileEveryPresetToCron(every) };
|
|
224
216
|
}
|
|
225
217
|
if (cron !== undefined) {
|
|
226
218
|
return {
|
|
@@ -231,6 +223,18 @@ function parseCadenceFromFlags(every, cron, timezone) {
|
|
|
231
223
|
}
|
|
232
224
|
return undefined;
|
|
233
225
|
}
|
|
226
|
+
export function compileEveryPresetToCron(value) {
|
|
227
|
+
const durationMs = parseDuration(value);
|
|
228
|
+
const cron = everyMsToFiveFieldCron(durationMs);
|
|
229
|
+
if (cron) {
|
|
230
|
+
return cron;
|
|
231
|
+
}
|
|
232
|
+
throw {
|
|
233
|
+
code: "UNREPRESENTABLE_CADENCE",
|
|
234
|
+
message: `${value} cannot be represented faithfully by five-field cron`,
|
|
235
|
+
details: "Use --cron for calendar schedules",
|
|
236
|
+
};
|
|
237
|
+
}
|
|
234
238
|
function parseTimeZoneFlag(timeZone) {
|
|
235
239
|
if (timeZone === undefined) {
|
|
236
240
|
return undefined;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createScheduleInspectRows, createScheduleInspectSchema, } from "./schema.js";
|
|
2
|
-
import { connectScheduleClient, parseScheduleUpdateInput, toScheduleCommandError, } from "./shared.js";
|
|
2
|
+
import { connectScheduleClient, parseScheduleUpdateInput, requireNewAgentSchedule, toScheduleCommandError, } from "./shared.js";
|
|
3
3
|
export async function runUpdateCommand(id, options, _command) {
|
|
4
4
|
const input = parseScheduleUpdateInput({
|
|
5
5
|
id,
|
|
@@ -19,6 +19,7 @@ export async function runUpdateCommand(id, options, _command) {
|
|
|
19
19
|
});
|
|
20
20
|
const { client } = await connectScheduleClient(options.host);
|
|
21
21
|
try {
|
|
22
|
+
await requireNewAgentSchedule(client, id);
|
|
22
23
|
const payload = await client.scheduleUpdate(input);
|
|
23
24
|
if (payload.error || !payload.schedule) {
|
|
24
25
|
throw new Error(payload.error ?? `Failed to update schedule: ${id}`);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Command } from "commander";
|
|
2
|
+
import type { SingleResult } from "../../output/index.js";
|
|
3
|
+
interface WorkspaceArchiveResult {
|
|
4
|
+
workspaceId: string;
|
|
5
|
+
status: "archived";
|
|
6
|
+
archivedAt: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function runArchiveCommand(workspaceId: string, options: {
|
|
9
|
+
host?: string;
|
|
10
|
+
}, _command: Command): Promise<SingleResult<WorkspaceArchiveResult>>;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=archive.d.ts.map
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { connectToDaemon, getDaemonHost } from "../../utils/client.js";
|
|
2
|
+
const workspaceArchiveSchema = {
|
|
3
|
+
idField: "workspaceId",
|
|
4
|
+
columns: [
|
|
5
|
+
{ header: "WORKSPACE ID", field: "workspaceId", width: 20 },
|
|
6
|
+
{ header: "STATUS", field: "status", width: 10 },
|
|
7
|
+
{ header: "ARCHIVED AT", field: "archivedAt", width: 26 },
|
|
8
|
+
],
|
|
9
|
+
};
|
|
10
|
+
export async function runArchiveCommand(workspaceId, options, _command) {
|
|
11
|
+
const host = getDaemonHost({ host: options.host });
|
|
12
|
+
const client = await connectToDaemon({ host: options.host }).catch((error) => {
|
|
13
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
14
|
+
throw {
|
|
15
|
+
code: "DAEMON_NOT_RUNNING",
|
|
16
|
+
message: `Cannot connect to daemon at ${host}: ${message}`,
|
|
17
|
+
};
|
|
18
|
+
});
|
|
19
|
+
try {
|
|
20
|
+
const payload = await client.archiveWorkspace(workspaceId);
|
|
21
|
+
if (payload.error) {
|
|
22
|
+
throw new Error(payload.error);
|
|
23
|
+
}
|
|
24
|
+
if (!payload.archivedAt) {
|
|
25
|
+
throw new Error("Workspace archive did not return an archive timestamp");
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
type: "single",
|
|
29
|
+
data: { workspaceId, status: "archived", archivedAt: payload.archivedAt },
|
|
30
|
+
schema: workspaceArchiveSchema,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
35
|
+
throw { code: "WORKSPACE_ARCHIVE_FAILED", message };
|
|
36
|
+
}
|
|
37
|
+
finally {
|
|
38
|
+
await client.close().catch(() => undefined);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=archive.js.map
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { Command } from "commander";
|
|
2
|
+
import type { CommandOptions, SingleResult } from "../../output/index.js";
|
|
3
|
+
import { type WorkspaceRow } from "./shared.js";
|
|
4
|
+
export interface WorkspaceCreateOptions extends CommandOptions {
|
|
5
|
+
isolation?: string;
|
|
6
|
+
path?: string;
|
|
7
|
+
project?: string;
|
|
8
|
+
title?: string;
|
|
9
|
+
mode?: string;
|
|
10
|
+
worktreeSlug?: string;
|
|
11
|
+
newBranch?: string;
|
|
12
|
+
base?: string;
|
|
13
|
+
branch?: string;
|
|
14
|
+
prNumber?: string;
|
|
15
|
+
forge?: string;
|
|
16
|
+
}
|
|
17
|
+
export declare function buildWorkspaceSource(options: WorkspaceCreateOptions): {
|
|
18
|
+
projectId?: string | undefined;
|
|
19
|
+
kind: "directory";
|
|
20
|
+
path: string;
|
|
21
|
+
} | {
|
|
22
|
+
baseBranch?: string | undefined;
|
|
23
|
+
branchName?: string | undefined;
|
|
24
|
+
action: "branch-off";
|
|
25
|
+
kind: "worktree";
|
|
26
|
+
cwd?: string;
|
|
27
|
+
projectId?: string;
|
|
28
|
+
worktreeSlug?: string;
|
|
29
|
+
} | {
|
|
30
|
+
action: "checkout";
|
|
31
|
+
refName: string;
|
|
32
|
+
kind: "worktree";
|
|
33
|
+
cwd?: string;
|
|
34
|
+
projectId?: string;
|
|
35
|
+
worktreeSlug?: string;
|
|
36
|
+
} | {
|
|
37
|
+
action: "checkout";
|
|
38
|
+
checkoutSource: {
|
|
39
|
+
number: number;
|
|
40
|
+
forge?: string | undefined;
|
|
41
|
+
kind: "change_request";
|
|
42
|
+
};
|
|
43
|
+
kind: "worktree";
|
|
44
|
+
cwd?: string;
|
|
45
|
+
projectId?: string;
|
|
46
|
+
worktreeSlug?: string;
|
|
47
|
+
};
|
|
48
|
+
export declare function runCreateCommand(options: WorkspaceCreateOptions, _command: Command): Promise<SingleResult<WorkspaceRow>>;
|
|
49
|
+
//# sourceMappingURL=create.d.ts.map
|
|
@@ -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.2",
|
|
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.2",
|
|
31
|
+
"@getpaseo/protocol": "0.2.0-beta.2",
|
|
32
|
+
"@getpaseo/server": "0.2.0-beta.2",
|
|
33
33
|
"chalk": "^5.3.0",
|
|
34
34
|
"commander": "^12.0.0",
|
|
35
35
|
"mime-types": "^2.1.35",
|