Skip to content

feat(relay-workspace): RelayWorkspaceManager scaffolding for Spec 05#11

Merged
khaliqgant merged 2 commits into
mainfrom
ricky/wave-pear-cloud-agents/05-integrations-connect
May 21, 2026
Merged

feat(relay-workspace): RelayWorkspaceManager scaffolding for Spec 05#11
khaliqgant merged 2 commits into
mainfrom
ricky/wave-pear-cloud-agents/05-integrations-connect

Conversation

@khaliqgant

Copy link
Copy Markdown
Member

WIP scaffolding for Spec 05's account-wide RelayWorkspaceManager — the single account-level relayfile workspace pear uses for the mount + integrations connect. Replaces the random per-project crypto.randomUUID() relayWorkspaceId in store.ts. Builds on #7 (shared scaffold).

Files in this PR:

  • src/main/relay-workspace.ts: provisions/joins the account workspace via RelayfileSetup, caches the WorkspaceHandle.
  • src/main/relay-workspace.types.ts: persisted shape.
  • src/main/relay-workspace.test.ts: smoke test.

Remaining work (full Spec 05): rewire integrations connect to handle.requestJson against connect-session / integrations/{provider}/status / integrations/{provider} (bypassing the whitelist-gated connectIntegration), replace project.relayWorkspaceId usages with RelayWorkspaceManager.getWorkspaceId(), add per-project visibility section. See slim spec specs/05-integrations-connect.md from #5.

🤖 Generated with Claude Code

@coderabbitai

coderabbitai Bot commented May 21, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@khaliqgant has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 13 minutes and 12 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Free

Run ID: 1e61860f-4691-4134-b0c1-2705aa674a82

📥 Commits

Reviewing files that changed from the base of the PR and between d66ef8b and c59ce49.

📒 Files selected for processing (3)
  • src/main/relay-workspace.test.ts
  • src/main/relay-workspace.ts
  • src/main/relay-workspace.types.ts

Note

🎁 Summarized by CodeRabbit Free

Your organization is on the Free plan. CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please upgrade your subscription to CodeRabbit Pro by visiting https://app.coderabbit.ai/login.

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

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Devin Review found 1 potential issue.

View 4 additional findings in Devin Review.

Open in Devin Review

Comment on lines +110 to +127
pendingHandle = this.bootstrap(auth)
.then((result) => {
if (!this.isCurrentBootstrap(pendingHandle, authContext, generation)) {
return this.getCurrentOrNextHandle()
}

if (result.persist) writePersistedWorkspace(result.persist)
this.handle = result.handle
this.handleAuth = authContext
return result.handle
})
.finally(() => {
if (this.pendingHandle === pendingHandle && this.bootstrapGeneration === generation) {
this.pendingHandle = null
this.pendingAuth = null
}
})
return pendingHandle

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔴 Stale bootstrap rejection propagates error to caller instead of redirecting to current handle

In createGuardedBootstrap, the stale-bootstrap redirect logic (getCurrentOrNextHandle) only exists in the .then() callback at src/main/relay-workspace.ts:112-113. If this.bootstrap(auth) rejects (e.g. network error, server error from joinWorkspace/createWorkspace), the .then() is skipped entirely and the rejection propagates directly to the original caller. There is no .catch() handler to detect that the bootstrap is stale and redirect the caller to the current/next handle.

Scenario: (1) Call A starts bootstrap for auth A. (2) Auth changes; call B triggers reset() and starts bootstrap for auth B. (3) Bootstrap B succeeds — valid handle is available. (4) Bootstrap A rejects (network error). The caller of firstHandle receives the network error from bootstrap A, even though a valid handle B exists. The tests only cover the success-then-redirect case, not the error-then-redirect case.

Suggested change
pendingHandle = this.bootstrap(auth)
.then((result) => {
if (!this.isCurrentBootstrap(pendingHandle, authContext, generation)) {
return this.getCurrentOrNextHandle()
}
if (result.persist) writePersistedWorkspace(result.persist)
this.handle = result.handle
this.handleAuth = authContext
return result.handle
})
.finally(() => {
if (this.pendingHandle === pendingHandle && this.bootstrapGeneration === generation) {
this.pendingHandle = null
this.pendingAuth = null
}
})
return pendingHandle
pendingHandle = this.bootstrap(auth)
.then((result) => {
if (!this.isCurrentBootstrap(pendingHandle, authContext, generation)) {
return this.getCurrentOrNextHandle()
}
if (result.persist) writePersistedWorkspace(result.persist)
this.handle = result.handle
this.handleAuth = authContext
return result.handle
})
.catch((err) => {
if (!this.isCurrentBootstrap(pendingHandle, authContext, generation)) {
return this.getCurrentOrNextHandle()
}
throw err
})
.finally(() => {
if (this.pendingHandle === pendingHandle && this.bootstrapGeneration === generation) {
this.pendingHandle = null
this.pendingAuth = null
}
})
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@khaliqgant khaliqgant changed the base branch from wave/pear-shared-scaffold to main May 21, 2026 14:08
khaliqgant and others added 2 commits May 21, 2026 16:09
WIP scaffolding for Spec 05's account-wide RelayWorkspaceManager — the single
account-level relayfile workspace pear uses for the relayfile mount + integrations
connect. Replaces the random per-project crypto.randomUUID() relayWorkspaceId in
store.ts.

- src/main/relay-workspace.ts: provisions/joins the account workspace via
  RelayfileSetup, caches the WorkspaceHandle.
- src/main/relay-workspace.types.ts: persisted shape.
- src/main/relay-workspace.test.ts: unit smoke.

Remaining work (full Spec 05 implementation): wire the integrations connect
flow to use handle.requestJson against connect-session / integrations/{provider}/status /
integrations/{provider} (bypassing the SDK's whitelist-gated connectIntegration),
replace project.relayWorkspaceId usages with RelayWorkspaceManager.getWorkspaceId(),
add the per-project visibility section. See specs/05-integrations-connect.md.

Builds on shared scaffolding (#7).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…handle

createGuardedBootstrap only handled the success path of a superseded
bootstrap (redirecting to getCurrentOrNextHandle inside .then). When a stale
bootstrap rejected — e.g. a network blip on joinWorkspace after auth changed
and a newer bootstrap already succeeded — the error propagated to the
original caller even though a valid handle existed. Add a .catch that
applies the same redirect logic before the .finally cleanup.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@khaliqgant khaliqgant force-pushed the ricky/wave-pear-cloud-agents/05-integrations-connect branch from 23369c4 to c59ce49 Compare May 21, 2026 14:09
@khaliqgant khaliqgant merged commit 832254a into main May 21, 2026
1 check passed
miyaontherelay added a commit that referenced this pull request Jun 8, 2026
Fix #11: WebGL doesn't repaint while the host is display:none. When the
visible effect runs after a hidden→visible transition, call the new
runtime.refreshOnShow() so the canvas redraws.

Fix #10: the runtime captures opts.getInputSrtt once at first acquire.
Rebind on each effect run via setInputSrttGetter so a remount with a
fresh inputSrttRef can't leave the predictor reading a stale ref.

Fix #14 (detach guard) was implemented inside the runtime in the prior
commit by tracking lastMountedContainer — no use-terminal change
needed.
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