* feat(cli): add workspace rename command `paseo workspace rename <workspace-id> <title>` sets a workspace's user-visible title through the existing workspace.title.set RPC, and `--reset` clears the override so the name reverts to the branch or directory. The command reads the descriptor back so the output shows what a reset reverted to. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(cli): harden workspace rename against read-back and arg failures Review findings on the rename command: - A failed workspace list sweep after a successful title change reported the whole command as failed. The read-back is display-only, so it now runs outside the mutation's error path and degrades to a null name. - Only --reset needs the descriptor read back; a set title is already the resolved display name, so the common path no longer pages the list. - Dropped the `"code" in error` rethrow. Nothing in that block throws a CommandError, but DaemonRpcError always carries a `code` property even when it is undefined, so the guard let those through to render as UNKNOWN_ERROR with a stack instead of WORKSPACE_RENAME_FAILED. - Commander 12 allows excess positionals, so an unquoted multi-word title renamed to its first word and dropped the rest. The command now rejects excess arguments. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * refactor(cli): report the rename RPC response instead of reading back Reading the descriptor back to show what --reset reverted to was the only reason rename needed a paged workspace sweep, and that sweep dragged in everything around it: a failure path that could report an applied rename as failed, a nullable name, and a bespoke warning sink to tell the two null cases apart. Sibling commands don't do this. `workspace archive`, `agent mode`, and `schedule update` all report what the RPC returned and stop; the one command that reads back is `agent update`, which has the same "applied but reported as failed" bug. So rename now mirrors `workspace archive`. `--reset` reports `title: null` rather than naming what it reverted to; `paseo workspace ls` shows the resolved name. This also reverts the `collectWorkspaces` extraction, whose only second caller was rename. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
59 lines
1.8 KiB
TypeScript
59 lines
1.8 KiB
TypeScript
#!/usr/bin/env npx tsx
|
|
|
|
import assert from "node:assert";
|
|
import { basename } from "node:path";
|
|
import { createE2ETestContext } from "./helpers/test-daemon.ts";
|
|
|
|
console.log("=== Workspace Rename Command ===\n");
|
|
|
|
const ctx = await createE2ETestContext({ timeout: 30000 });
|
|
|
|
try {
|
|
const created = await ctx.paseo([
|
|
"workspace",
|
|
"create",
|
|
"--isolation",
|
|
"local",
|
|
"--path",
|
|
ctx.workDir,
|
|
"--title",
|
|
"Original title",
|
|
"--json",
|
|
]);
|
|
assert.strictEqual(created.exitCode, 0, created.stderr);
|
|
const workspaceId = JSON.parse(created.stdout).workspaceId as string;
|
|
|
|
const renamed = await ctx.paseo(["workspace", "rename", workspaceId, "Auth rework", "--json"]);
|
|
assert.strictEqual(renamed.exitCode, 0, renamed.stderr);
|
|
assert.deepStrictEqual(JSON.parse(renamed.stdout), {
|
|
workspaceId,
|
|
title: "Auth rework",
|
|
});
|
|
|
|
const renamedList = await ctx.paseo(["workspace", "ls", "--json"]);
|
|
assert.strictEqual(renamedList.exitCode, 0, renamedList.stderr);
|
|
assert.strictEqual(
|
|
JSON.parse(renamedList.stdout).find(
|
|
(workspace: { workspaceId: string }) => workspace.workspaceId === workspaceId,
|
|
)?.name,
|
|
"Auth rework",
|
|
);
|
|
|
|
const reset = await ctx.paseo(["workspace", "rename", workspaceId, "--reset", "--json"]);
|
|
assert.strictEqual(reset.exitCode, 0, reset.stderr);
|
|
assert.deepStrictEqual(JSON.parse(reset.stdout), { workspaceId, title: null });
|
|
|
|
const resetList = await ctx.paseo(["workspace", "ls", "--json"]);
|
|
assert.strictEqual(resetList.exitCode, 0, resetList.stderr);
|
|
assert.strictEqual(
|
|
JSON.parse(resetList.stdout).find(
|
|
(workspace: { workspaceId: string }) => workspace.workspaceId === workspaceId,
|
|
)?.name,
|
|
basename(ctx.workDir),
|
|
);
|
|
} finally {
|
|
await ctx.stop();
|
|
}
|
|
|
|
console.log("=== Workspace Rename Command Tests Passed ===");
|