fix(cli): list all non-archived agents by default and drop ls --ui
This commit is contained in:
@@ -42,11 +42,10 @@ export function createCli(): Command {
|
||||
// Primary agent commands (top-level)
|
||||
program
|
||||
.command('ls')
|
||||
.description('List agents. By default shows background agents (without ui=true) in current directory.')
|
||||
.option('-a, --all', 'Include all statuses (not just running)')
|
||||
.option('-g, --global', 'Show agents from all directories (not just current)')
|
||||
.description('List agents. By default excludes archived agents.')
|
||||
.option('-a, --all', 'Include archived agents')
|
||||
.option('-g, --global', 'Legacy no-op (kept for compatibility)')
|
||||
.option('--label <key=value>', 'Filter by label (can be used multiple times)', collectMultiple, [])
|
||||
.option('--ui', 'Show only UI agents (equivalent to --label ui=true)')
|
||||
.option('--json', 'Output in JSON format')
|
||||
.option('--host <host>', 'Daemon host:port (default: localhost:6767)')
|
||||
.action(withOutput(runLsCommand))
|
||||
|
||||
@@ -22,11 +22,10 @@ export function createAgentCommand(): Command {
|
||||
// Primary agent commands (same as top-level)
|
||||
agent
|
||||
.command('ls')
|
||||
.description('List agents. By default shows background agents (without ui=true) in current directory.')
|
||||
.option('-a, --all', 'Include all statuses (not just running)')
|
||||
.option('-g, --global', 'Show agents from all directories (not just current)')
|
||||
.description('List agents. By default excludes archived agents.')
|
||||
.option('-a, --all', 'Include archived agents')
|
||||
.option('-g, --global', 'Legacy no-op (kept for compatibility)')
|
||||
.option('--label <key=value>', 'Filter by label (can be used multiple times)', collectMultiple, [])
|
||||
.option('--ui', 'Show only UI agents (equivalent to --label ui=true)')
|
||||
.option('--json', 'Output in JSON format')
|
||||
.option('--host <host>', 'Daemon host:port (default: localhost:6767)')
|
||||
.action(withOutput(runLsCommand))
|
||||
|
||||
@@ -74,26 +74,22 @@ function toListItem(agent: AgentSnapshotPayload): AgentListItem {
|
||||
export type AgentLsResult = ListResult<AgentListItem>
|
||||
|
||||
export interface AgentLsOptions extends CommandOptions {
|
||||
/** -a: Include all statuses (not just running/idle) */
|
||||
/** -a: Include archived agents */
|
||||
all?: boolean
|
||||
/** -g: Show agents globally (not just current directory) */
|
||||
/** Legacy flag retained for CLI compatibility */
|
||||
global?: boolean
|
||||
/** Filter by specific status */
|
||||
status?: string
|
||||
/** Filter by specific cwd (overrides default cwd filtering) */
|
||||
/** Filter by specific cwd */
|
||||
cwd?: string
|
||||
/** Filter by labels (key=value format) */
|
||||
label?: string[]
|
||||
/** Filter to UI agents only (equivalent to --label ui=true) */
|
||||
ui?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Agent ls command with correct semantics from design doc:
|
||||
* - `paseo agent ls` → running/idle agents in current directory
|
||||
* - `paseo agent ls -a` → all statuses in current directory
|
||||
* - `paseo agent ls -g` → running/idle agents globally
|
||||
* - `paseo agent ls -ag` → everything everywhere
|
||||
* Agent ls command semantics:
|
||||
* - `paseo agent ls` → all non-archived agents
|
||||
* - `paseo agent ls -a` → include archived agents
|
||||
*/
|
||||
export async function runLsCommand(
|
||||
options: AgentLsOptions,
|
||||
@@ -117,39 +113,26 @@ export async function runLsCommand(
|
||||
try {
|
||||
let agents = await client.fetchAgents()
|
||||
|
||||
// Status filtering:
|
||||
// By default, only show running/idle agents (not error, archived, etc.)
|
||||
// With -a flag, show all statuses
|
||||
// By default, exclude archived agents. `-a` includes them.
|
||||
if (!options.all) {
|
||||
agents = agents.filter((a) => {
|
||||
// Show running and idle agents, exclude archived
|
||||
return (a.status === 'running' || a.status === 'idle') && !a.archivedAt
|
||||
})
|
||||
agents = agents.filter((a) => !a.archivedAt)
|
||||
}
|
||||
|
||||
// If explicit status filter is provided, use it
|
||||
// If explicit status filter is provided, apply it.
|
||||
if (options.status) {
|
||||
agents = agents.filter((a) => a.status === options.status)
|
||||
}
|
||||
|
||||
// Directory filtering:
|
||||
// By default, only show agents in current working directory
|
||||
// With -g flag, show agents globally (all directories)
|
||||
if (!options.global) {
|
||||
const currentCwd = options.cwd ?? process.cwd()
|
||||
// Optional cwd filter.
|
||||
if (options.cwd) {
|
||||
const targetCwd = options.cwd.replace(/\/$/, '')
|
||||
agents = agents.filter((a) => {
|
||||
// Normalize paths for comparison
|
||||
const agentCwd = a.cwd.replace(/\/$/, '')
|
||||
const targetCwd = currentCwd.replace(/\/$/, '')
|
||||
// Match exact cwd or subdirectories
|
||||
return agentCwd === targetCwd || agentCwd.startsWith(targetCwd + '/')
|
||||
})
|
||||
}
|
||||
|
||||
// Label filtering:
|
||||
// Parse --label flags and --ui flag
|
||||
// --ui is equivalent to --label ui=true
|
||||
// By default (no --ui flag), show background agents (those WITHOUT ui=true)
|
||||
// Parse --label filters (key=value).
|
||||
const labelFilters: Record<string, string> = {}
|
||||
if (options.label) {
|
||||
for (const labelStr of options.label) {
|
||||
@@ -161,14 +144,9 @@ export async function runLsCommand(
|
||||
}
|
||||
}
|
||||
}
|
||||
// Add ui=true filter if --ui flag is set
|
||||
if (options.ui) {
|
||||
labelFilters['ui'] = 'true'
|
||||
}
|
||||
|
||||
// Apply label filtering
|
||||
// Apply label filtering only when explicitly requested.
|
||||
if (Object.keys(labelFilters).length > 0) {
|
||||
// Filter to agents that have ALL specified labels (AND semantics)
|
||||
agents = agents.filter((a) => {
|
||||
const agentLabels = a.labels
|
||||
for (const [key, value] of Object.entries(labelFilters)) {
|
||||
@@ -178,11 +156,6 @@ export async function runLsCommand(
|
||||
}
|
||||
return true
|
||||
})
|
||||
} else {
|
||||
// Default: show background agents only (those without ui=true)
|
||||
agents = agents.filter((a) => {
|
||||
return a.labels['ui'] !== 'true'
|
||||
})
|
||||
}
|
||||
|
||||
await client.close()
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
* - paseo ls --json returns valid JSON (or error)
|
||||
* - paseo ls -a flag is accepted
|
||||
* - paseo ls -g flag is accepted
|
||||
* - paseo ls does not support --ui
|
||||
*/
|
||||
|
||||
import assert from 'node:assert'
|
||||
@@ -52,6 +53,7 @@ try {
|
||||
assert(result.stdout.includes('-g'), 'help should mention -g flag')
|
||||
assert(result.stdout.includes('--global'), 'help should mention --global flag')
|
||||
assert(result.stdout.includes('--host'), 'help should mention --host option')
|
||||
assert(!result.stdout.includes('--ui'), 'help should not mention --ui')
|
||||
console.log('✓ paseo ls --help shows options\n')
|
||||
}
|
||||
|
||||
@@ -138,6 +140,17 @@ try {
|
||||
assert(!output.includes('error: option'), 'should not have option parsing error')
|
||||
console.log('✓ -q (quiet) flag is accepted\n')
|
||||
}
|
||||
|
||||
// Test 9: paseo ls --ui is rejected (flag removed)
|
||||
{
|
||||
console.log('Test 9: paseo ls --ui is rejected')
|
||||
const result =
|
||||
await $`PASEO_HOST=localhost:${port} PASEO_HOME=${paseoHome} npx paseo ls --ui`.nothrow()
|
||||
assert.notStrictEqual(result.exitCode, 0, 'should fail for removed --ui flag')
|
||||
const output = result.stdout + result.stderr
|
||||
assert(output.includes('unknown option'), 'should report unknown option for --ui')
|
||||
console.log('✓ paseo ls --ui is rejected\n')
|
||||
}
|
||||
} finally {
|
||||
// Clean up temp directory
|
||||
await rm(paseoHome, { recursive: true, force: true })
|
||||
|
||||
Reference in New Issue
Block a user