feat(cli/sdk/mcp): add workspaces update for renaming#4189
feat(cli/sdk/mcp): add workspaces update for renaming#4189saddlepaddle merged 4 commits intomainfrom
Conversation
Expose workspace updates across all three client surfaces. The cloud
v2Workspace.update procedure already supports name/branch/hostId; only
name is wired through here since branch/host moves require host-side
git orchestration that isn't safe to drive from the cloud directly.
- CLI: superset workspaces update <id> --name "..."
- SDK: client.workspaces.update(id, { name })
- MCP-v2: workspaces_update tool
|
ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
✅ Files skipped from review due to trivial changes (1)
📝 WalkthroughWalkthroughThis PR adds a complete workspace update flow: SDK types and method, MCP tool and registration, CLI command, and documentation. ChangesWorkspace Update Across SDK, MCP, and CLI
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Greptile SummaryThis PR exposes an existing
Confidence Score: 4/5Safe to merge; the feature is additive and the cloud procedure already exists. The MCP tool and SDK type both permit a no-field call that fails at the server — worth tightening before the surface becomes widely used. The CLI correctly guards against an empty update; the MCP tool and SDK do not. Calling update(id, {}) or invoking workspaces_update with only an id silently reaches the server and returns an opaque BAD_REQUEST instead of a clear client-side message. The description in the MCP tool reinforces the misunderstanding by implying partial calls are always safe. packages/mcp-v2/src/tools/workspaces/update.ts and packages/sdk/src/resources/workspaces.ts need the no-field guard and type constraint respectively.
|
| Filename | Overview |
|---|---|
| packages/cli/src/commands/workspaces/update/command.ts | New CLI command for renaming a workspace — follows the existing create/delete pattern, with correct org-id guard and an explicit "No fields to update" check before hitting the cloud. |
| packages/sdk/src/resources/workspaces.ts | Adds update() method and WorkspaceUpdateParams/WorkspaceUpdateResult types. WorkspaceUpdateParams has only optional fields, so update(id, {}) type-checks but will fail at runtime with a server BAD_REQUEST. |
| packages/mcp-v2/src/tools/workspaces/update.ts | New MCP tool wrapping the cloud update procedure. No client-side guard against an empty-field call; the tool description implies a no-op is valid but the server returns BAD_REQUEST. |
| packages/mcp-v2/src/tools/register.ts | Imports and registers the new workspaces_update tool in the correct position between workspacesCreate and workspacesDelete. |
Sequence Diagram
sequenceDiagram
participant User
participant CLI/SDK/MCP
participant CloudAPI as Cloud API (v2Workspace.update)
Note over CLI/SDK/MCP: CLI path
User->>CLI/SDK/MCP: superset workspaces update id --name New
CLI/SDK/MCP->>CLI/SDK/MCP: "Guard: name === undefined, throws CLIError"
CLI/SDK/MCP->>CloudAPI: "v2Workspace.update.mutate({ id, name })"
CloudAPI-->>CLI/SDK/MCP: WorkspaceUpdateResult
CLI/SDK/MCP-->>User: Updated workspace id
Note over CLI/SDK/MCP: SDK path
User->>CLI/SDK/MCP: "client.workspaces.update(id, { name })"
CLI/SDK/MCP->>CloudAPI: mutation v2Workspace.update with id and name
CloudAPI-->>CLI/SDK/MCP: WorkspaceUpdateResult
CLI/SDK/MCP-->>User: WorkspaceUpdateResult
Note over CLI/SDK/MCP: MCP no name supplied no guard
User->>CLI/SDK/MCP: workspaces_update with id only
CLI/SDK/MCP->>CloudAPI: caller.v2Workspace.update with id only
CloudAPI-->>CLI/SDK/MCP: BAD_REQUEST no fields to update
Prompt To Fix All With AI
Fix the following 3 code review issues. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 3
packages/sdk/src/resources/workspaces.ts:201-204
Empty-object update compiles cleanly but fails at runtime. `WorkspaceUpdateParams` has only optional fields, so `client.workspaces.update(id, {})` passes the TypeScript compiler and then hits the cloud with nothing to change, returning a server-side BAD_REQUEST. A `RequireAtLeastOne` constraint makes the invalid call a compile-time error rather than a silent runtime failure.
```suggestion
/** Requires at least one field — an all-optional update is rejected by the server. */
export type WorkspaceUpdateParams = RequireAtLeastOne<{
/** New workspace name. */
name?: string;
}>;
/** Utility: at least one key of T must be present. */
type RequireAtLeastOne<T> = {
[K in keyof T]-?: Required<Pick<T, K>> & Partial<Omit<T, K>>;
}[keyof T];
```
### Issue 2 of 3
packages/mcp-v2/src/tools/workspaces/update.ts:9-10
The tool description says "omitted fields preserve their current value," which an LLM will reasonably interpret as meaning a call with only `id` is a safe no-op. In practice the server rejects it with BAD_REQUEST. The CLI guards against this client-side with an explicit "No fields to update" error; the MCP tool should do the same, or the description should make the constraint explicit.
```suggestion
description:
"Update fields on an existing workspace (cloud-index metadata). You must supply at least one optional field (e.g. name); passing only the id with no other fields is an error.",
```
### Issue 3 of 3
packages/mcp-v2/src/tools/workspaces/update.ts:15-18
No client-side guard against an all-optional payload. The CLI throws "No fields to update" before touching the network; without the same check here the MCP handler forwards `{ id }` to the server and returns an opaque cloud error instead of a clear message. Adding a pre-flight check mirrors the CLI's behaviour.
```suggestion
handler: async (input, ctx) => {
const { id, ...fields } = input;
if (Object.keys(fields).length === 0) {
throw new Error("No fields to update. Pass at least one field such as name.");
}
const caller = createMcpCaller(ctx);
return caller.v2Workspace.update(input);
},
```
Reviews (1): Last reviewed commit: "docs(skill): add workspaces update to su..." | Re-trigger Greptile
| export interface WorkspaceUpdateParams { | ||
| /** New workspace name. */ | ||
| name?: string; | ||
| } |
There was a problem hiding this comment.
Empty-object update compiles cleanly but fails at runtime.
WorkspaceUpdateParams has only optional fields, so client.workspaces.update(id, {}) passes the TypeScript compiler and then hits the cloud with nothing to change, returning a server-side BAD_REQUEST. A RequireAtLeastOne constraint makes the invalid call a compile-time error rather than a silent runtime failure.
| export interface WorkspaceUpdateParams { | |
| /** New workspace name. */ | |
| name?: string; | |
| } | |
| /** Requires at least one field — an all-optional update is rejected by the server. */ | |
| export type WorkspaceUpdateParams = RequireAtLeastOne<{ | |
| /** New workspace name. */ | |
| name?: string; | |
| }>; | |
| /** Utility: at least one key of T must be present. */ | |
| type RequireAtLeastOne<T> = { | |
| [K in keyof T]-?: Required<Pick<T, K>> & Partial<Omit<T, K>>; | |
| }[keyof T]; |
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/sdk/src/resources/workspaces.ts
Line: 201-204
Comment:
Empty-object update compiles cleanly but fails at runtime. `WorkspaceUpdateParams` has only optional fields, so `client.workspaces.update(id, {})` passes the TypeScript compiler and then hits the cloud with nothing to change, returning a server-side BAD_REQUEST. A `RequireAtLeastOne` constraint makes the invalid call a compile-time error rather than a silent runtime failure.
```suggestion
/** Requires at least one field — an all-optional update is rejected by the server. */
export type WorkspaceUpdateParams = RequireAtLeastOne<{
/** New workspace name. */
name?: string;
}>;
/** Utility: at least one key of T must be present. */
type RequireAtLeastOne<T> = {
[K in keyof T]-?: Required<Pick<T, K>> & Partial<Omit<T, K>>;
}[keyof T];
```
How can I resolve this? If you propose a fix, please make it concise.| description: | ||
| "Update fields on an existing workspace (cloud-index metadata). Only the fields you pass are changed; omitted fields preserve their current value.", |
There was a problem hiding this comment.
The tool description says "omitted fields preserve their current value," which an LLM will reasonably interpret as meaning a call with only
id is a safe no-op. In practice the server rejects it with BAD_REQUEST. The CLI guards against this client-side with an explicit "No fields to update" error; the MCP tool should do the same, or the description should make the constraint explicit.
| description: | |
| "Update fields on an existing workspace (cloud-index metadata). Only the fields you pass are changed; omitted fields preserve their current value.", | |
| description: | |
| "Update fields on an existing workspace (cloud-index metadata). You must supply at least one optional field (e.g. name); passing only the id with no other fields is an error.", |
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/mcp-v2/src/tools/workspaces/update.ts
Line: 9-10
Comment:
The tool description says "omitted fields preserve their current value," which an LLM will reasonably interpret as meaning a call with only `id` is a safe no-op. In practice the server rejects it with BAD_REQUEST. The CLI guards against this client-side with an explicit "No fields to update" error; the MCP tool should do the same, or the description should make the constraint explicit.
```suggestion
description:
"Update fields on an existing workspace (cloud-index metadata). You must supply at least one optional field (e.g. name); passing only the id with no other fields is an error.",
```
How can I resolve this? If you propose a fix, please make it concise.| handler: async (input, ctx) => { | ||
| const caller = createMcpCaller(ctx); | ||
| return caller.v2Workspace.update(input); | ||
| }, |
There was a problem hiding this comment.
No client-side guard against an all-optional payload. The CLI throws "No fields to update" before touching the network; without the same check here the MCP handler forwards
{ id } to the server and returns an opaque cloud error instead of a clear message. Adding a pre-flight check mirrors the CLI's behaviour.
| handler: async (input, ctx) => { | |
| const caller = createMcpCaller(ctx); | |
| return caller.v2Workspace.update(input); | |
| }, | |
| handler: async (input, ctx) => { | |
| const { id, ...fields } = input; | |
| if (Object.keys(fields).length === 0) { | |
| throw new Error("No fields to update. Pass at least one field such as name."); | |
| } | |
| const caller = createMcpCaller(ctx); | |
| return caller.v2Workspace.update(input); | |
| }, |
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/mcp-v2/src/tools/workspaces/update.ts
Line: 15-18
Comment:
No client-side guard against an all-optional payload. The CLI throws "No fields to update" before touching the network; without the same check here the MCP handler forwards `{ id }` to the server and returns an opaque cloud error instead of a clear message. Adding a pre-flight check mirrors the CLI's behaviour.
```suggestion
handler: async (input, ctx) => {
const { id, ...fields } = input;
if (Object.keys(fields).length === 0) {
throw new Error("No fields to update. Pass at least one field such as name.");
}
const caller = createMcpCaller(ctx);
return caller.v2Workspace.update(input);
},
```
How can I resolve this? If you propose a fix, please make it concise.
🧹 Preview Cleanup CompleteThe following preview resources have been cleaned up:
Thank you for your contribution! 🎉 |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/cli/src/commands/workspaces/update/command.ts`:
- Around line 17-24: The CLI currently only rejects undefined names but allows
empty or whitespace-only names to be sent to ctx.api.v2Workspace.update.mutate;
update the validation around options.name (the block that throws CLIError) to
trim the value and ensure it's non-empty (e.g., check that options.name?.trim()
is truthy) and throw the same CLIError with the "Pass --name <new-name>" hint
when invalid, before calling ctx.api.v2Workspace.update.mutate.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 4a802411-a2fd-4bc4-8095-3226429c067e
📒 Files selected for processing (5)
packages/cli/src/commands/workspaces/update/command.tspackages/mcp-v2/src/tools/register.tspackages/mcp-v2/src/tools/workspaces/update.tspackages/sdk/src/resources/workspaces.tsskills/superset/SKILL.md
| if (options.name === undefined) { | ||
| throw new CLIError("No fields to update", "Pass --name <new-name>"); | ||
| } | ||
|
|
||
| const updated = await ctx.api.v2Workspace.update.mutate({ | ||
| id, | ||
| name: options.name, | ||
| }); |
There was a problem hiding this comment.
Reject blank workspace names before calling the API.
Line 17 only checks undefined, so empty/whitespace values can still be sent at Line 23. Add a trimmed non-empty check for better CLI-side validation.
Proposed patch
- if (options.name === undefined) {
+ const name = options.name?.trim();
+ if (!name) {
throw new CLIError("No fields to update", "Pass --name <new-name>");
}
@@
const updated = await ctx.api.v2Workspace.update.mutate({
id,
- name: options.name,
+ name,
});📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (options.name === undefined) { | |
| throw new CLIError("No fields to update", "Pass --name <new-name>"); | |
| } | |
| const updated = await ctx.api.v2Workspace.update.mutate({ | |
| id, | |
| name: options.name, | |
| }); | |
| const name = options.name?.trim(); | |
| if (!name) { | |
| throw new CLIError("No fields to update", "Pass --name <new-name>"); | |
| } | |
| const updated = await ctx.api.v2Workspace.update.mutate({ | |
| id, | |
| name, | |
| }); |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/cli/src/commands/workspaces/update/command.ts` around lines 17 - 24,
The CLI currently only rejects undefined names but allows empty or
whitespace-only names to be sent to ctx.api.v2Workspace.update.mutate; update
the validation around options.name (the block that throws CLIError) to trim the
value and ensure it's non-empty (e.g., check that options.name?.trim() is
truthy) and throw the same CLIError with the "Pass --name <new-name>" hint when
invalid, before calling ctx.api.v2Workspace.update.mutate.
The CLI throws "No fields to update" client-side when --name is omitted.
The MCP tool was forwarding {id} to the server and surfacing an opaque
BAD_REQUEST. Mirror the CLI's behaviour with an explicit error and
sharpen the tool description so an LLM caller knows at-least-one-field
is required.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/mcp-v2/src/tools/workspaces/update.ts`:
- Line 19: Replace the CLI-specific wording in the validation error message that
currently mentions "--name" with MCP-neutral phrasing; locate the string "No
fields to update. Pass at least one field such as --name." in
packages/mcp-v2/src/tools/workspaces/update.ts and change it to something like
"No fields to update. Pass at least one updatable field such as name." (or "one
updatable field") so the message uses neutral field names rather than CLI flag
syntax.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: e5b35468-3266-4366-84dc-5c372e3cfdb1
📒 Files selected for processing (2)
packages/mcp-v2/src/tools/workspaces/update.tspackages/sdk/src/resources/workspaces.ts
| const { id: _id, ...fields } = input; | ||
| if (Object.keys(fields).length === 0) { | ||
| throw new Error( | ||
| "No fields to update. Pass at least one field such as --name.", |
There was a problem hiding this comment.
Use MCP-neutral validation text instead of CLI flag wording.
"--name" is CLI-specific and can confuse MCP users. Prefer "name" (or “one updatable field”) in this tool error.
Suggested tweak
- "No fields to update. Pass at least one field such as --name.",
+ "No fields to update. Pass at least one field such as name.",📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "No fields to update. Pass at least one field such as --name.", | |
| "No fields to update. Pass at least one field such as name.", |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/mcp-v2/src/tools/workspaces/update.ts` at line 19, Replace the
CLI-specific wording in the validation error message that currently mentions
"--name" with MCP-neutral phrasing; locate the string "No fields to update. Pass
at least one field such as --name." in
packages/mcp-v2/src/tools/workspaces/update.ts and change it to something like
"No fields to update. Pass at least one updatable field such as name." (or "one
updatable field") so the message uses neutral field names rather than CLI flag
syntax.
Description already states at-least-one-field; client-side guard adds boilerplate without saving a round-trip.
Changes since v0.2.11: - workspaces: add `superset workspaces update <id> --name "..."` for renaming. Branch/host moves stay desktop-only — they require host-side git orchestration that isn't safe to drive from the cloud directly. (#4189) - organization: new `superset organization members list` command (also exposed via SDK + mcp-v2). Read-only — add/remove keep their existing UI flows. (#4197) - tasks: new `superset tasks statuses list` command surfacing the organization's configured task statuses. (#4197) - host-service: paste a closed/merged PR URL or `#N` into the v2 new-workspace modal and the dropdown actually returns the PR instead of "No open pull requests found." Direct lookups now ignore the open-only state filter that bounds text-search results. (#4190) Push cli-v0.2.12 after this lands to fire the release pipeline.
Changes since alpha.8:
- workspaces.update accepts `{ name }` for renaming. Branch/host moves
stay desktop-only — they require host-side git orchestration that
isn't safe to drive from the cloud. (#4189)
- organization.members.list — read-only listing of org members.
add/remove deliberately not exposed; they have UI-side concerns
(invites, ownership transfer, audit) that aren't ready for a
programmatic API. (#4197)
- task.statuses.list — list configured task statuses for the org.
(#4197)
After merge: `cd packages/sdk && bun run build && cd dist && npm publish --access public`.
Summary
Expose
workspaces updateacross all three client surfaces so workspaces can be renamed without going through the desktop UI:superset workspaces update <id> --name "..."client.workspaces.update(id, { name })workspaces_updatetoolThe cloud
v2Workspace.updateprocedure already acceptsname,branch, andhostIdpatches. Onlynameis wired through here — branch and host moves require host-side git orchestration that isn't safe to drive directly from the cloud.The schema leaves room for additional fields when a clear use case shows up.
Why this PR
The CLI/SDK/MCP previously only had
create / list / deletefor workspaces — no way to rename one once it existed. The desktop app's host service has anaiRenameflow but no plain "set the name" entry point exposed externally.Test plan
superset workspaces update <id> --name "New name"updates the cloud row and the change appears insuperset workspaces listawait client.workspaces.update(id, { name: "..." })returns the updated rowworkspaces_updatefrom a connected MCP client and confirm the rename--namereturns "No fields to update" (CLI) / cloud-side BAD_REQUEST (SDK/MCP)Summary by cubic
Add workspace rename support across CLI, SDK, and MCP so you can rename a workspace without the desktop app. Routes through cloud
v2Workspace.update; onlynameis supported (branch/host moves are out of scope).superset workspaces update <id> --name "New name"; errors with "No fields to update" if--nameis missing.client.workspaces.update(id, { name })returns the updated workspace.workspaces_updatetool acceptsidand optionalname; validation is handled server-side.superset workspaces updateto the CLI reference.Written for commit d3f10b8. Summary will update on new commits.
Summary by CodeRabbit
New Features
Documentation