Skip to content

feat(cli): show active workspace via workspace current and list marker#126

Merged
khaliqgant merged 1 commit intomainfrom
workspace-current
May 9, 2026
Merged

feat(cli): show active workspace via workspace current and list marker#126
khaliqgant merged 1 commit intomainfrom
workspace-current

Conversation

@khaliqgant
Copy link
Copy Markdown
Member

Summary

  • New relayfile workspace current subcommand: prints the workspace the CLI defaults to when no WORKSPACE arg is passed (the same resolveWorkspaceRecord("") precedence: env RELAYFILE_WORKSPACE → workspace id in the token → catalog default). --verbose reports the source.
  • relayfile workspace list now marks the active line with a leading * (git-branch style), pads inactive lines with two spaces, and suppresses the marker when no active workspace can be resolved.
  • relayfile workspace list --names-only restores the legacy bare-name output for scripts that parse the list.

Why

Today there's no first-class way to ask "which workspace is active?" — users have to cat ~/.relayfile/workspaces.json or run relayfile status (which actually contacts the server). And workspace list prints names with no indicator of which one any future command will use, so it's easy to lose track of which default you're working against.

Examples

$ relayfile workspace list
* alpha
  beta
  staging

$ relayfile workspace current
alpha

$ relayfile workspace current --verbose
alpha (id: ws_abc123, source: default)

$ RELAYFILE_WORKSPACE=beta relayfile workspace current --verbose
beta (id: ws_xyz789, source: env RELAYFILE_WORKSPACE)

$ relayfile workspace list --names-only
alpha
beta
staging

Test plan

  • go test ./cmd/relayfile-cli/ — full suite passes
  • TestWorkspaceCurrentPrintsActiveWorkspace — default-from-catalog path with and without --verbose
  • TestWorkspaceCurrentReportsEnvOverride — env beats catalog default and source string mentions RELAYFILE_WORKSPACE
  • TestWorkspaceCurrentErrorsWhenNoneActive — exits non-zero with a fix-it message instead of printing an empty line
  • TestWorkspaceListNamesOnlyRestoresBareOutput--names-only produces unmarked output
  • Updated 2 existing workspace list tests for the new marked default contract

🤖 Generated with Claude Code

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 9, 2026

Review Change Stack
No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f1e0395d-3b70-4c61-b6c2-2ecba23cc531

📥 Commits

Reviewing files that changed from the base of the PR and between 4d6a6f8 and 4652eea.

📒 Files selected for processing (5)
  • .trajectories/completed/2026-05/traj_h99ldnvo1d26.json
  • .trajectories/completed/2026-05/traj_h99ldnvo1d26.md
  • .trajectories/index.json
  • cmd/relayfile-cli/main.go
  • cmd/relayfile-cli/main_test.go
✅ Files skipped from review due to trivial changes (3)
  • .trajectories/completed/2026-05/traj_h99ldnvo1d26.json
  • .trajectories/index.json
  • .trajectories/completed/2026-05/traj_h99ldnvo1d26.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • cmd/relayfile-cli/main.go
  • cmd/relayfile-cli/main_test.go

📝 Walkthrough

Walkthrough

Adds relayfile workspace current to display the active workspace and enhances workspace list with a --names-only escape hatch and active-workspace * marking; both use a shared resolver that prefers env, then token claims, then local catalog default.

Changes

Workspace Current & List Enhancement

Layer / File(s) Summary
Trajectory Record
.trajectories/completed/2026-05/traj_h99ldnvo1d26.json, .trajectories/completed/2026-05/traj_h99ldnvo1d26.md, .trajectories/index.json
Documents the completed trajectory: new workspace current subcommand, active-workspace marker in list, --names-only escape hatch, and test updates.
CLI Help & Dispatcher
cmd/relayfile-cli/main.go
Help text and dispatcher updated to document and route workspace current [--verbose] and workspace list [--names-only]; missing-subcommand guidance updated.
Workspace List Output
cmd/relayfile-cli/main.go
runWorkspaceList adds --names-only, uses an emit helper, and marks the active workspace with * by default (legacy bare output when names-only).
Active Workspace Resolution
cmd/relayfile-cli/main.go
New activeWorkspaceName(token) helper resolves active workspace from RELAYFILE_WORKSPACE, token claims (workspace_id/wks), or local catalog default; returns empty when unresolved and a source descriptor.
Workspace Current Command
cmd/relayfile-cli/main.go
New runWorkspaceCurrent prints the resolved active workspace; errors when none active; --verbose shows id and resolution source.
Test Coverage
cmd/relayfile-cli/main_test.go
Updates two existing workspace list tests and adds tests for workspace current behaviors plus a --names-only regression test.

Sequence Diagram

sequenceDiagram
  participant User
  participant Dispatcher as CLI Dispatcher
  participant Current as workspace current
  participant List as workspace list
  participant Resolver as activeWorkspaceName
  participant Output
  User->>Dispatcher: workspace current [--verbose]
  Dispatcher->>Current: runWorkspaceCurrent()
  Current->>Resolver: activeWorkspaceName(token)
  Resolver->>Resolver: Check RELAYFILE_WORKSPACE
  Resolver->>Resolver: Check token workspace_id/wks
  Resolver->>Resolver: Check catalog default
  Resolver-->>Current: workspace name (and id/source)
  Current->>Output: Print name (+ id + source if verbose)
  User->>Dispatcher: workspace list [--names-only]
  Dispatcher->>List: runWorkspaceList()
  List->>Resolver: activeWorkspaceName(token)
  Resolver-->>List: active workspace (or empty)
  List->>Output: Print marked (default) or bare (names-only) list
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 I hopped through flags and helped them meet,

Current now speaks, the list wears a seat.
Env then token, catalog takes stage,
Names-only whispers, markers on the page.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main changes: adding a workspace current subcommand and marking the active workspace in the list output.
Description check ✅ Passed The description comprehensively explains the changes, motivation, examples, and test plan, all directly related to the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch workspace-current

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 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 `@cmd/relayfile-cli/main.go`:
- Around line 2308-2311: The current code swallows parse/config errors from
loadWorkspaceCatalog() causing activeWorkspaceName and runWorkspaceCurrent to
return empty values and emit “no active workspace”; change the control flow so
loadWorkspaceCatalog() errors are propagated and surfaced: update
activeWorkspaceName to return an error (e.g., (string, *Catalog, error) or
similar) instead of converting catalog errors into empty strings, and update
runWorkspaceCurrent to check and return/log that error (rather than treating
empty values as “no active workspace”); apply the same change to the other
occurrence around the loadWorkspaceCatalog call (the block referenced at lines
~2332-2335) so all catalog-parse/config errors are reported correctly.
- Around line 2246-2256: The active marker logic compares the listed entry
(variable name) only against activeWorkspaceName(tokenValue), but remote admin
lists emit workspace IDs so the marker can be missed when Name != ID; update the
code that sets marker inside the emit closure (and the similar block at
2269-2271) to also fetch and compare the active workspace ID (e.g., call an
activeWorkspaceID(tokenValue) helper or change activeWorkspaceName to return
both id and name) and mark the entry when name equals either the active name or
the active ID; ensure you retrieve the active ID once before using the emit
closure to avoid repeated calls.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 70eb5ba6-fdd1-4815-b2ae-1764f79f0d04

📥 Commits

Reviewing files that changed from the base of the PR and between 75f4347 and 4d6a6f8.

📒 Files selected for processing (5)
  • .trajectories/completed/2026-05/traj_h99ldnvo1d26.json
  • .trajectories/completed/2026-05/traj_h99ldnvo1d26.md
  • .trajectories/index.json
  • cmd/relayfile-cli/main.go
  • cmd/relayfile-cli/main_test.go

Comment thread cmd/relayfile-cli/main.go
Comment on lines +2246 to +2256
activeName, _ := activeWorkspaceName(tokenValue)
emit := func(name string) {
if *namesOnly || activeName == "" {
fmt.Fprintln(stdout, name)
return
}
marker := " "
if name == activeName {
marker = "* "
}
fmt.Fprintln(stdout, marker+name)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Active marker can be wrong when remote list entries are IDs.

activeWorkspaceName prefers catalog names, but remote admin listing emits workspace IDs. If Name != ID, the active workspace won’t get the * marker.

💡 Proposed fix
  activeName, _ := activeWorkspaceName(tokenValue)
+ activeID := ""
+ if record, ok := workspaceRecordByName(activeName); ok {
+ 	activeID = strings.TrimSpace(record.ID)
+ }

  emit := func(name string) {
  	if *namesOnly || activeName == "" {
  		fmt.Fprintln(stdout, name)
  		return
  	}
  	marker := "  "
- 	if name == activeName {
+ 	if name == activeName || (activeID != "" && name == activeID) {
  		marker = "* "
  	}
  	fmt.Fprintln(stdout, marker+name)
  }

Also applies to: 2269-2271

🤖 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 `@cmd/relayfile-cli/main.go` around lines 2246 - 2256, The active marker logic
compares the listed entry (variable name) only against
activeWorkspaceName(tokenValue), but remote admin lists emit workspace IDs so
the marker can be missed when Name != ID; update the code that sets marker
inside the emit closure (and the similar block at 2269-2271) to also fetch and
compare the active workspace ID (e.g., call an activeWorkspaceID(tokenValue)
helper or change activeWorkspaceName to return both id and name) and mark the
entry when name equals either the active name or the active ID; ensure you
retrieve the active ID once before using the emit closure to avoid repeated
calls.

Comment thread cmd/relayfile-cli/main.go
Comment on lines +2308 to +2311
catalog, err := loadWorkspaceCatalog()
if err != nil {
return "", ""
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

workspace current hides catalog parse errors as “no active workspace.”

When loadWorkspaceCatalog() fails, activeWorkspaceName returns empty values, and runWorkspaceCurrent emits a misleading “no active workspace” error instead of the real parse/config error.

💡 Proposed fix
-func activeWorkspaceName(token string) (string, string) {
+func activeWorkspaceName(token string) (string, string, error) {
 	...
 	catalog, err := loadWorkspaceCatalog()
 	if err != nil {
-		return "", ""
+		return "", "", err
 	}
 	if name := strings.TrimSpace(catalog.Default); name != "" {
-		return name, "default"
+		return name, "default", nil
 	}
-	return "", ""
+	return "", "", nil
 }

- name, source := activeWorkspaceName(tokenValue)
+ name, source, err := activeWorkspaceName(tokenValue)
+ if err != nil {
+ 	return err
+ }

Also applies to: 2332-2335

🤖 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 `@cmd/relayfile-cli/main.go` around lines 2308 - 2311, The current code
swallows parse/config errors from loadWorkspaceCatalog() causing
activeWorkspaceName and runWorkspaceCurrent to return empty values and emit “no
active workspace”; change the control flow so loadWorkspaceCatalog() errors are
propagated and surfaced: update activeWorkspaceName to return an error (e.g.,
(string, *Catalog, error) or similar) instead of converting catalog errors into
empty strings, and update runWorkspaceCurrent to check and return/log that error
(rather than treating empty values as “no active workspace”); apply the same
change to the other occurrence around the loadWorkspaceCatalog call (the block
referenced at lines ~2332-2335) so all catalog-parse/config errors are reported
correctly.

Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 2 additional findings.

Open in Devin Review

Adds `relayfile workspace current` to print the workspace that
`resolveWorkspaceRecord("")` would pick — the same precedence used by
every CLI command that defaults to "the active workspace" (env
`RELAYFILE_WORKSPACE` > workspace id embedded in the token >
catalog `default`). `--verbose` reports the resolution source.

Also marks the active line in `relayfile workspace list` with a leading
`* `, padding inactive lines with two spaces (git-branch convention).
The marker is suppressed when no active workspace can be resolved, and
`--names-only` restores the legacy bare-name output for scripts that
parse the list.

Adds 4 new tests; updates 2 existing list tests for the marker contract.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@khaliqgant khaliqgant force-pushed the workspace-current branch from 4d6a6f8 to 4652eea Compare May 9, 2026 18:53
@khaliqgant khaliqgant merged commit d8f0433 into main May 9, 2026
7 checks passed
@khaliqgant khaliqgant deleted the workspace-current branch May 9, 2026 18:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant