From dfda6daeedb26928ea67a1064e4c8a88478adc2f Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Thu, 29 Jan 2026 10:41:19 +0700 Subject: [PATCH] refactor(cli): rename ps to ls and add top-level agent commands --- package-lock.json | 9 + packages/cli/docs/type-audit.md | 155 +++++++++ packages/cli/package.json | 5 +- packages/cli/src/cli.ts | 138 ++++++-- packages/cli/src/commands/agent/archive.ts | 140 ++++++++ packages/cli/src/commands/agent/attach.ts | 219 ++++++++++++ packages/cli/src/commands/agent/index.ts | 104 ++++-- packages/cli/src/commands/agent/inspect.ts | 44 +-- packages/cli/src/commands/agent/logs.ts | 215 +++++++----- .../cli/src/commands/agent/{ps.ts => ls.ts} | 89 +++-- packages/cli/src/commands/agent/mode.ts | 18 +- packages/cli/src/commands/agent/run.ts | 68 +++- packages/cli/src/commands/agent/send.ts | 76 ++++- packages/cli/src/commands/agent/stop.ts | 2 +- packages/cli/src/commands/agent/wait.ts | 198 +++++++++++ packages/cli/src/commands/daemon/index.ts | 8 +- packages/cli/src/commands/daemon/start.ts | 6 + packages/cli/src/commands/permit/allow.ts | 187 +++++++++++ packages/cli/src/commands/permit/deny.ts | 146 ++++++++ packages/cli/src/commands/permit/index.ts | 44 +++ packages/cli/src/commands/permit/ls.ts | 110 ++++++ packages/cli/src/commands/provider/index.ts | 35 ++ packages/cli/src/commands/provider/ls.ts | 70 ++++ packages/cli/src/commands/provider/models.ts | 69 ++++ packages/cli/src/commands/worktree/archive.ts | 129 +++++++ packages/cli/src/commands/worktree/index.ts | 29 ++ packages/cli/src/commands/worktree/ls.ts | 125 +++++++ ...4-agent-ps.test.ts => 04-agent-ls.test.ts} | 97 +++--- packages/cli/tests/05-agent-run.test.ts | 112 +++---- packages/cli/tests/06-agent-send.test.ts | 92 ++--- packages/cli/tests/07-agent-stop.test.ts | 88 ++--- packages/cli/tests/08-agent-logs.test.ts | 96 +++--- packages/cli/tests/09-agent-inspect.test.ts | 92 ++--- packages/cli/tests/11-agent-archive.test.ts | 122 +++++++ packages/cli/tests/11-agent-wait.test.ts | 185 ++++++++++ packages/cli/tests/12-permit-ls.test.ts | 107 ++++++ .../cli/tests/13-permit-allow-deny.test.ts | 175 ++++++++++ packages/cli/tests/14-worktree.test.ts | 169 ++++++++++ packages/cli/tests/15-provider.test.ts | 147 ++++++++ .../cli/tests/e2e/agent-lifecycle.test.ts | 246 ++++++++++++++ packages/cli/tests/e2e/agent-send.test.ts | 205 ++++++++++++ packages/cli/tests/e2e/permissions.test.ts | 285 ++++++++++++++++ packages/cli/tests/helpers/test-daemon.ts | 315 ++++++++++++++++++ packages/cli/tests/setup.ts | 4 +- .../server/src/client/daemon-client-v2.ts | 23 ++ packages/server/src/server/exports.ts | 17 + 46 files changed, 4473 insertions(+), 542 deletions(-) create mode 100644 packages/cli/docs/type-audit.md create mode 100644 packages/cli/src/commands/agent/archive.ts create mode 100644 packages/cli/src/commands/agent/attach.ts rename packages/cli/src/commands/agent/{ps.ts => ls.ts} (55%) create mode 100644 packages/cli/src/commands/agent/wait.ts create mode 100644 packages/cli/src/commands/permit/allow.ts create mode 100644 packages/cli/src/commands/permit/deny.ts create mode 100644 packages/cli/src/commands/permit/index.ts create mode 100644 packages/cli/src/commands/permit/ls.ts create mode 100644 packages/cli/src/commands/provider/index.ts create mode 100644 packages/cli/src/commands/provider/ls.ts create mode 100644 packages/cli/src/commands/provider/models.ts create mode 100644 packages/cli/src/commands/worktree/archive.ts create mode 100644 packages/cli/src/commands/worktree/index.ts create mode 100644 packages/cli/src/commands/worktree/ls.ts rename packages/cli/tests/{04-agent-ps.test.ts => 04-agent-ls.test.ts} (55%) create mode 100644 packages/cli/tests/11-agent-archive.test.ts create mode 100644 packages/cli/tests/11-agent-wait.test.ts create mode 100644 packages/cli/tests/12-permit-ls.test.ts create mode 100644 packages/cli/tests/13-permit-allow-deny.test.ts create mode 100644 packages/cli/tests/14-worktree.test.ts create mode 100644 packages/cli/tests/15-provider.test.ts create mode 100644 packages/cli/tests/e2e/agent-lifecycle.test.ts create mode 100644 packages/cli/tests/e2e/agent-send.test.ts create mode 100644 packages/cli/tests/e2e/permissions.test.ts create mode 100644 packages/cli/tests/helpers/test-daemon.ts diff --git a/package-lock.json b/package-lock.json index 4aae37e90..07e827756 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9276,6 +9276,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/mime-types": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRMsfuQbnRq1Ef+C+RKaENOxXX87Ygl38W1vDfPHRku02TgQr+Qd8iivLtAMcR0KF5/29xlnFihkTlbqFrGOVQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/minimist": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.5.tgz", @@ -26370,6 +26377,7 @@ "@paseo/server": "*", "chalk": "^5.3.0", "commander": "^12.0.0", + "mime-types": "^2.1.35", "ws": "^8.14.2", "yaml": "^2.8.2" }, @@ -26377,6 +26385,7 @@ "paseo": "bin/paseo" }, "devDependencies": { + "@types/mime-types": "^3.0.1", "@types/ws": "^8.5.8", "tsx": "^4.6.0", "typescript": "^5.2.2", diff --git a/packages/cli/docs/type-audit.md b/packages/cli/docs/type-audit.md new file mode 100644 index 000000000..62449e5a2 --- /dev/null +++ b/packages/cli/docs/type-audit.md @@ -0,0 +1,155 @@ +# CLI Type Audit (commands) + +## Scope +- Audited `packages/cli/src/commands/**` for inline type/interface definitions. +- Checked `@paseo/server` exports from `packages/server/src/server/exports.ts`. +- Note: `packages/server/src/index.ts` does **not** exist in this repo; the package export entrypoint is `./src/server/exports.ts` per `packages/server/package.json`. + +## Server Exports (current) +`packages/server/src/server/exports.ts` exports: +- `createPaseoDaemon`, `PaseoDaemon`, `PaseoDaemonConfig` +- `loadConfig`, `resolvePaseoHome` +- `createRootLogger`, `LogLevel`, `LogFormat` +- `loadPersistedConfig`, `PersistedConfig` +- `DaemonClientV2`, `DaemonClientV2Config`, `ConnectionState`, `DaemonEvent` + +No agent snapshot/timeline/permission/message types are exported. + +## Findings by File + +### `packages/cli/src/commands/agent/run.ts` +Inline types: +- `AgentSnapshot` (id/provider/cwd/createdAt/status/title) + +Recommended server type: +- `AgentSnapshotPayload` from `packages/server/src/shared/messages.ts` (daemon client returns this shape). **Not exported** from `@paseo/server` today. + +Notes: +- `AgentRunResult` is CLI output; no server type expected. + +--- + +### `packages/cli/src/commands/agent/ps.ts` +Inline types: +- `AgentSnapshot` (id/provider/cwd/createdAt/status/title/archivedAt?) + +Recommended server type: +- `AgentSnapshotPayload` (includes `archivedAt` and full snapshot fields). **Not exported**. + +Notes: +- `AgentListItem` is CLI output; no server type expected. + +--- + +### `packages/cli/src/commands/agent/send.ts` +Inline types: +- `AgentSnapshot` (id/provider/cwd/createdAt/status/title) + +Recommended server type: +- `AgentSnapshotPayload`. **Not exported**. + +Notes: +- `AgentSendResult` is CLI output; no server type expected. + +--- + +### `packages/cli/src/commands/agent/inspect.ts` +Inline types: +- `AgentSnapshotLike` (snapshot fields + `lastUsage`, `capabilities`, `availableModes`, `pendingPermissions`, `parentAgentId`) + +Recommended server types: +- `AgentSnapshotPayload` (overall snapshot shape). **Not exported**. +- `AgentUsage` for `lastUsage`. **Not exported** (in `packages/server/src/server/agent/agent-sdk-types.ts`). +- `AgentCapabilityFlags` for `capabilities`. **Not exported**. +- `AgentMode` for `availableModes`. **Not exported**. +- `AgentPermissionRequest` for `pendingPermissions`. **Not exported**. + +Notes: +- `pendingPermissions` uses `{ id, tool?: string }` but server type is `AgentPermissionRequest` with `{ name, kind, ... }`; current CLI projection is lossy and field names don’t match (`tool` vs `name`). +- `AgentInspect` and `InspectRow` are CLI output types. + +--- + +### `packages/cli/src/commands/agent/logs.ts` +Inline types: +- `AgentStreamSnapshotMessage` +- `AgentStreamMessage` +- Timeline item shape in `formatTimelineItem` and `extractTimelineFrom*` helpers (`{ type: string; ... }`) + +Recommended server types: +- `AgentStreamSnapshotMessage` from `packages/server/src/shared/messages.ts`. **Not exported**. +- `AgentStreamMessage` from `packages/server/src/shared/messages.ts`. **Not exported**. +- `AgentStreamEventPayload` from `packages/server/src/shared/messages.ts` (for `event` typing). **Not exported**. +- `AgentTimelineItem` from `packages/server/src/server/agent/agent-sdk-types.ts` (for timeline item shape). **Not exported**. + +Notes: +- These are WebSocket message types; they should come from shared message definitions to avoid drift. +- `LogEntry` is CLI output. + +--- + +### `packages/cli/src/commands/agent/mode.ts` +Inline types: +- `ModeListItem` (id/label/description) +- `SetModeResult` (agentId/mode) + +Recommended server type: +- `ModeListItem` duplicates the shape of `AgentMode` (id/label/description) from `packages/server/src/server/agent/agent-sdk-types.ts`. **Not exported**. + +Notes: +- `SetModeResult` is CLI output. + +--- + +### `packages/cli/src/commands/daemon/start.ts` +Inline types: +- `StartOptions` (CLI flags) + +Server type usage: +- CLI-only; no server type expected. + +--- + +### `packages/cli/src/commands/daemon/status.ts` +Inline types: +- `DaemonStatus` +- `StatusRow` + +Server type usage: +- CLI-only; no server type expected. + +--- + +### `packages/cli/src/commands/daemon/restart.ts` +Inline types: +- `RestartResult` + +Server type usage: +- CLI-only; no server type expected. + +--- + +### `packages/cli/src/commands/daemon/stop.ts` +Inline types: +- `StopResult` + +Server type usage: +- CLI-only; no server type expected. + +## Gaps in `@paseo/server` Exports (needed for CLI cleanup) +To replace inline types in CLI commands, `@paseo/server` would need to export (directly or re-export): +- From `packages/server/src/shared/messages.ts`: + - `AgentSnapshotPayload` + - `AgentStreamEventPayload` + - `AgentStreamMessage` + - `AgentStreamSnapshotMessage` + - (optionally) `AgentStateMessage`, `SessionStateMessage`, `SessionOutboundMessage` if CLI starts typing daemon event queues more strictly +- From `packages/server/src/server/agent/agent-sdk-types.ts`: + - `AgentMode` + - `AgentUsage` + - `AgentCapabilityFlags` + - `AgentPermissionRequest` + - `AgentTimelineItem` + +## Summary +Primary inline types that should become server imports are the agent snapshot/timeline/message/permission/mode shapes in `agent/*` commands. All are defined in server shared or agent SDK types today but are not exported through `@paseo/server`. diff --git a/packages/cli/package.json b/packages/cli/package.json index 93781915c..3d6a3cc55 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -8,16 +8,19 @@ }, "scripts": { "typecheck": "tsc --noEmit", - "test:e2e": "npx zx tests/run-all.ts" + "test:e2e": "npx zx tests/run-all.ts", + "test:e2e:lifecycle": "npx tsx tests/e2e/agent-lifecycle.test.ts" }, "dependencies": { "@paseo/server": "*", "chalk": "^5.3.0", "commander": "^12.0.0", + "mime-types": "^2.1.35", "ws": "^8.14.2", "yaml": "^2.8.2" }, "devDependencies": { + "@types/mime-types": "^3.0.1", "@types/ws": "^8.5.8", "tsx": "^4.6.0", "typescript": "^5.2.2", diff --git a/packages/cli/src/cli.ts b/packages/cli/src/cli.ts index 23b12c30d..7acd27c6a 100644 --- a/packages/cli/src/cli.ts +++ b/packages/cli/src/cli.ts @@ -1,9 +1,26 @@ import { Command } from 'commander' import { createAgentCommand } from './commands/agent/index.js' import { createDaemonCommand } from './commands/daemon/index.js' +import { createPermitCommand } from './commands/permit/index.js' +import { createProviderCommand } from './commands/provider/index.js' +import { createWorktreeCommand } from './commands/worktree/index.js' +import { runLsCommand } from './commands/agent/ls.js' +import { runRunCommand } from './commands/agent/run.js' +import { runLogsCommand } from './commands/agent/logs.js' +import { runStopCommand } from './commands/agent/stop.js' +import { runSendCommand } from './commands/agent/send.js' +import { runInspectCommand } from './commands/agent/inspect.js' +import { runWaitCommand } from './commands/agent/wait.js' +import { runAttachCommand } from './commands/agent/attach.js' +import { withOutput } from './output/index.js' const VERSION = '0.1.0' +// Helper function to collect multiple option values into an array +function collectMultiple(value: string, previous: string[]): string[] { + return previous.concat([value]) +} + export function createCli(): Command { const program = new Command() @@ -17,32 +34,115 @@ export function createCli(): Command { .option('--no-headers', 'omit table headers') .option('--no-color', 'disable colored output') - // Agent commands + // Primary agent commands (top-level) + program + .command('ls') + .description('List agents. By default shows running agents in current directory.') + .option('-a, --all', 'Include all statuses (not just running)') + .option('-g, --global', 'Show agents from all directories (not just current)') + .option('--json', 'Output in JSON format') + .option('--host ', 'Daemon host:port (default: localhost:6767)') + .action((options, command) => { + if (options.json) { + command.parent.opts().format = 'json' + } + return withOutput(runLsCommand)(options, command) + }) + + program + .command('run') + .description('Create and start an agent with a task') + .argument('', 'The task/prompt for the agent') + .option('-d, --detach', 'Run in background (detached)') + .option('--name ', 'Assign a name/title to the agent') + .option('--provider ', 'Agent provider: claude | codex | opencode', 'claude') + .option('--model ', 'Model to use (e.g., claude-sonnet-4-20250514, claude-3-5-haiku-20241022)') + .option('--mode ', 'Provider-specific mode (e.g., plan, default, bypass)') + .option('--worktree ', 'Create agent in a new git worktree') + .option('--base ', 'Base branch for worktree (default: current branch)') + .option('--image ', 'Attach image(s) to the initial prompt (can be used multiple times)', collectMultiple, []) + .option('--cwd ', 'Working directory (default: current)') + .option('--host ', 'Daemon host:port (default: localhost:6767)') + .action(withOutput(runRunCommand)) + + program + .command('attach') + .description("Attach to a running agent's output stream") + .argument('', 'Agent ID (or prefix)') + .option('--host ', 'Daemon host:port (default: localhost:6767)') + .action(runAttachCommand) + + program + .command('logs') + .description('View agent activity/timeline') + .argument('', 'Agent ID (or prefix)') + .option('-f, --follow', 'Follow log output (streaming)') + .option('--tail ', 'Show last n entries') + .option('--filter ', 'Filter by event type (tools, text, errors, permissions)') + .option('--since