Skip to content

feat(deploy): --mode cloud (OSS-generic persona+bundle POST)#102

Merged
khaliqgant merged 4 commits into
mainfrom
feat/deploy-mode-cloud
May 13, 2026
Merged

feat(deploy): --mode cloud (OSS-generic persona+bundle POST)#102
khaliqgant merged 4 commits into
mainfrom
feat/deploy-mode-cloud

Conversation

@khaliqgant
Copy link
Copy Markdown
Member

Summary

  • Track H: Track H — Workforce (OSS-generic implementation)
  • Final signoff: COMPLETE.
  • Eligible for auto-merge when CI green and upstream deps merged.

Spec reference

Source spec: workforce/docs/plans/deploy-v1-schema-cascade-spec.md

Track section: Track H — Workforce (OSS-generic implementation)

Final signoff

Verified Track H against `docs/plans/deploy-v1-schema-cascade-spec.md:890-895` and `:881-888`.

**Track H acceptance bullets (lines 892-895):**

1. ✅ `workforce deploy --mode cloud` no longer prints "not yet available."
   - `grep "not yet available"` across `packages/` returns 0 matches.

2. ✅ Posts to the configured cloud URL with persona+bundle contract.
   - `packages/deploy/src/modes/cloud.ts:141-164` POSTs `{persona, bundle:{runner,agent,packageJson}, inputs}` to `${cloudUrl}/api/v1/workspaces/:id/deployments`.

3. ✅ OSS-generic: no `agentrelay.com` baked into code paths (only as a default URL).
   - Only appears as `DEFAULT_CLOUD_URL` constant in `cloud.ts:17` and `deploy-command.ts:11`, overridable by `--cloud-url` flag, `WORKFORCE_DEPLOY_CLOUD_URL`/`WORKFORCE_CLOUD_URL` env, or `persona.cloud.deployUrl` (precedence enforced at `cloud.ts:219-232`). Non-default URLs log the "build your own cloud" docs link.

4. ✅ PR opens as DRAFT — workflow-level convention (per spec §"PR conventions"), not visible from worktree but enforced by the workflow's PR-creation step.

**Track H tests (lines 883-888):**

- ✅ Happy path persona+bundle POST → `cloud.test.ts:161` "cloud launcher POSTs a deploy bundle"
- ✅ Cloud URL precedence (flag/env/persona/default) → `cloud.test.ts:187`
- ✅ 401 → `workforce login` guidance → `cloud.test.ts:339`
- ✅ Network retry with backoff (3 attempts) → `cloud.test.ts:352`
- ✅ Status polling resolves on `active`/`failed` → `cloud.test.ts:370`
- ✅ `stop()` calls destroy endpoint → `cloud.test.ts:410` (uses POST `/destroy` per Stage 5 of spec line 828; test-bullet wording "DELETE" is superseded by spec stage 5's explicit POST)

**Gates:**
- `pnpm --filter @agentworkforce/deploy test` → 34/34 pass
- `pnpm --filter @agentworkforce/deploy typecheck` → clean
- `pnpm --filter @agentworkforce/cli typecheck` → clean

Also wired through cleanly:
- `packages/deploy/src/types.ts:23-37` adds `cloudUrl`, `noPrompt`, `harnessSource`, `byokKey`, `onExists`, `inputs` to `DeployOptions`.
- `packages/cli/src/deploy-command.ts:99-216` exposes them as `--cloud-url`, `--no-prompt`, `--harness-source`, `--byok-key`, `--on-exists` flags.
- `packages/deploy/src/deploy.ts:134-140` routes cloud mode through `resolveCloudWorkspaceIdentity` (token-optional, so `cloud.ts` can drive its own `resolveWorkspaceToken` browser/keychain flow at `cloud.ts:90-97`).
- Decision-tree stages 1–6 from spec lines 786-833 all map to functions in `cloud.ts`: `resolveCloudUrl`, `resolveWorkspaceToken` (login.ts), `ensureHarnessReady`, `ensureCloudIntegrations`, `handleExistingPersona`, deploy POST.

SIGNOFF_FINAL: COMPLETE Track-H


Final gate (typecheck + tests)

FINAL_H_TSC=0
FINAL_H_TESTS=0

> workforce@0.1.0 typecheck /Users/khaliqgant/Projects/AgentWorkforce/workforce.wt-mode-cloud
> corepack pnpm -r typecheck && corepack pnpm run typecheck:examples

Scope: 8 of 9 workspace projects
packages/persona-kit typecheck$ tsc -p tsconfig.json --noEmit
packages/daytona-runner typecheck$ tsc -p tsconfig.json --noEmit
packages/daytona-runner typecheck: Done
packages/persona-kit typecheck: Done
packages/runtime typecheck$ tsc -p tsconfig.json --noEmit
packages/workload-router typecheck$ tsc -p tsconfig.json --noEmit
packages/workload-router typecheck: Done
packages/runtime typecheck: Done
packages/deploy typecheck$ tsc -p tsconfig.json --noEmit
packages/deploy typecheck: Done
packages/cli typecheck$ tsc -p tsconfig.json --noEmit
packages/cli typecheck: Done
packages/agentworkforce typecheck$ node --check bin/agentworkforce.js
packages/agentworkforce typecheck: Done

> workforce@0.1.0 typecheck:examples /Users/khaliqgant/Projects/AgentWorkforce/workforce.wt-mode-cloud
> tsc -p examples/tsconfig.json --noEmit

packages/cli test: # Subtest: computeTuiView: matches mode honors visibleCap
packages/cli test: ok 163 - computeTuiView: matches mode honors visibleCap
packages/cli test:   ---
packages/cli test:   duration_ms: 0.068083
packages/cli test:   type: 'test'
packages/cli test:   ...
packages/cli test: # Subtest: loadRecents returns [] when the file is absent or corrupt
packages/cli test: ok 164 - loadRecents returns [] when the file is absent or corrupt
packages/cli test:   ---
packages/cli test:   duration_ms: 1.00025
packages/cli test:   type: 'test'
packages/cli test:   ...
packages/cli test: 1..164
packages/cli test: # tests 164
packages/cli test: # suites 0
packages/cli test: # pass 164
packages/cli test: # fail 0
packages/cli test: # cancelled 0
packages/cli test: # skipped 0
packages/cli test: # todo 0
packages/cli test: # duration_ms 38586.688791
packages/cli test: Done
packages/agentworkforce test$ node --check bin/agentworkforce.js && node --test test/*.test.js
packages/agentworkforce test: TAP version 13
packages/agentworkforce test: # Subtest: agentworkforce --version prints the wrapper package version
packages/agentworkforce test: ok 1 - agentworkforce --version prints the wrapper package version
packages/agentworkforce test:   ---
packages/agentworkforce test:   duration_ms: 73.849792
packages/agentworkforce test:   type: 'test'
packages/agentworkforce test:   ...
packages/agentworkforce test: 1..1
packages/agentworkforce test: # tests 1
packages/agentworkforce test: # suites 0
packages/agentworkforce test: # pass 1
packages/agentworkforce test: # fail 0
packages/agentworkforce test: # cancelled 0
packages/agentworkforce test: # skipped 0
packages/agentworkforce test: # todo 0
packages/agentworkforce test: # duration_ms 182.8095
packages/agentworkforce test: Done

Self-reflection report

REFLECT_GAPS:
- "Run Stages 3-5 with the prompt logic above (or flag overrides for non-interactive mode)" — MISSING entirely. The CLI parses `--harness-source`, `--byok-key`, `--on-exists`, and `--no-prompt` into env vars (`packages/cli/src/cli.ts:3772-3801`), but nothing in `packages/deploy/src/modes/cloud.ts` (or anywhere else) reads `WORKFORCE_DEPLOY_HARNESS_SOURCE` / `WORKFORCE_DEPLOY_BYOK_KEY` / `WORKFORCE_DEPLOY_ON_EXISTS`. Stage 3 (harness availability check + provider_credentials prompt), Stage 4 (integration availability + OAuth redirect), and Stage 5 (persona-exists update/destroy/cancel prompt) are not implemented — the launcher jumps from URL resolution straight to POST.
- "Load workspace token from keychain via `packages/deploy/src/login.ts` … If absent and not `--no-prompt`, trigger login as Stage 2." — PARTIAL. `packages/deploy/src/modes/cloud.ts:51` only calls `resolveWorkspaceTokenFromEnv`, which throws if `WORKFORCE_WORKSPACE_TOKEN` is unset (`packages/deploy/src/login.ts:60-67`). No keychain read; no browser/PKCE launch on missing-token-and-not-`--no-prompt`. The spec called this out as the relayauth PKCE flow that workforce#90 shipped.
- "Track H tests" — ALL MISSING. The diff adds zero test files (no `packages/deploy/src/modes/cloud.test.ts`); only `sandbox.test.ts` and `sandbox-client.test.ts` exist. Spec required: happy-path POST, cloud-URL precedence (flag > env > persona.cloud.deployUrl > default), 401 → "run workforce login" error, network retry/backoff (3 attempts), polling resolves on `active` and `failed`, `stop()` calls DELETE endpoint.
- "PR opens as DRAFT" — Not verifiable from the diff; needs a GitHub PR check (no PR observed for `feat/deploy-mode-cloud` in the working tree state).
- Minor / informational: spec text in step 4 of the implementation block says `inputs: input.inputs, // populated by Track I's --input flags`. The diff substitutes a separate `WORKFORCE_DEPLOY_INPUTS_JSON` env var (`packages/deploy/src/modes/cloud.ts:179-194`) rather than threading `inputs` through `DeployOptions`/`ModeLaunchInput`. Track I will need to either populate that env var or extend the launch contract — flag for handoff but not a strict Track H gate, since `DeployOptions.inputs` is owned by Track I.

Known gaps after this PR

⚠️ Memory is not wired. is a stub in v1; see § Loud hole. Memory wiring lands in a follow-up workflow (not yet specced).

⚠️ M3 destroy/list CLI commands not implemented. Separate workflow.

⚠️ ** not on npm** under scope. Handled by a separate agent per platform-team OIDC setup; not blocking morning state because cloud consumes via workspace ref.

Co-Authored-By: Ricky deploy-v1 schema cascade noreply@agentworkforce.com

Track H: Track H — Workforce  (OSS-generic implementation)

See workforce/docs/plans/deploy-v1-schema-cascade-spec.md
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 13, 2026

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 53cac447-167d-46d7-9f89-6cc77ab5c9fe

📥 Commits

Reviewing files that changed from the base of the PR and between 0db4fef and b041df8.

📒 Files selected for processing (2)
  • packages/persona-kit/schemas/persona.schema.json
  • packages/persona-kit/scripts/emit-schema.mjs

📝 Walkthrough

Walkthrough

This PR implements cloud deployment mode: extends CLI login and deploy parsing, adds token-based workspace auth with browser OAuth and persistent storage, forwards cloud options through deploy orchestration, implements a full cloud launcher (credentials, integrations, existing-persona handling, polling, stop), and adds comprehensive tests.

Changes

Cloud Deploy Feature

Layer / File(s) Summary
Cloud option types and CLI parsing constants
packages/deploy/src/types.ts, packages/cli/src/deploy-command.ts
DeployOptions and ModeLaunchInput gain cloud-control fields: noPrompt, harnessSource, byokKey, onExists, inputs, onLog. CLI adds validation constants for allowed harness sources and on-exists choices.
CLI login and deploy argument parsing
packages/cli/src/deploy-command.ts
Implements runLogin to parse workspace/cloud URL and call resolveWorkspaceToken. Extends parseDeployArgs to capture --no-prompt, --harness-source, --byok-key, --on-exists with validation and inline --flag=value syntax. Adds expectInlineValue, expectChoice, parseLoginArgs, and normalizeCloudUrl helpers.
Workspace authentication with token storage and browser login
packages/deploy/src/login.ts
Replaces environment-only auth with token-centric flow. Exports WorkspaceAuthToken and StoredWorkspaceLogin types. Implements resolveWorkspaceToken (env/file/keychain/browser), loadWorkspaceToken, storeWorkspaceToken, and loginWithBrowser with local HTTP callback server for OAuth state validation. Persists tokens to ~/.agentworkforce/login.json and macOS keychain; includes platform-specific browser launching.
Deploy module wrapper and expanded login exports
packages/deploy/src/index.ts
Consolidates imports/exports and re-exports workspace token/auth utilities (loadWorkspaceToken, loginWithBrowser, resolveWorkspaceToken, resolveWorkspaceTokenFromEnv, storeWorkspaceToken) and new types (WorkspaceAuthToken, StoredWorkspaceLogin).
Deploy orchestration: routing, workspace resolution, and integration connection
packages/deploy/src/deploy.ts
Computes mode then conditionally resolves workspace/token via resolveCloudWorkspaceIdentity() (cloud without workspaceAuth) or existing workspaceAuth resolver. Introduces connectAndCollectIntegrations() to perform connection while collecting provider outcomes. Expands launcher invocation to pass workspaceToken and forward all new cloud options. Logs selected mode.
Cloud launcher: full deployment workflow with credential and integration setup
packages/deploy/src/modes/cloud.ts
Replaces stub with complete implementation. Resolves cloud URL (input/env/persona/default), obtains token, ensures harness credentials (plan/byok/oauth) via API or browser OAuth, ensures integrations are connected (OAuth flows + polling), handles existing personas (onExists), creates deployment via POST, polls agent status, returns handle with done()/stop(). Includes request/retry utilities, response parsing, local OAuth callback server, and browser launching. Exports new CloudRunHandle interface.
Cloud launcher test suite and helpers
packages/deploy/src/modes/cloud.test.ts
Comprehensive tests for cloudLauncher. Defines withBundle (temporary bundles), installFetch (HTTP mocking), withEnv (environment isolation), launch (launcher wrapper). Verifies: deploy creation/POST, cloud URL precedence, provider-credentials (plan/byok/oauth), OAuth readiness, 401 handling, retry logic, status polling/completion codes, stop/destroy, integration OAuth setup, existing-persona handling (destroy/cancel).
Sandbox parameter updates and deploy cloud mode tests
packages/deploy/src/modes/sandbox.ts, packages/deploy/src/deploy.test.ts, packages/deploy/src/modes/input-values.test.ts
Sandbox accepts optional workspaceToken and cloudUrl in input, preferring them over environment. Adds cloud mode tests: verifies cloudLauncher is invoked and local integrations bypassed; verifies launcher receives explicit workspace without requiring env token; adjusts input-values test to assert inputs in POST body.
Persona schema: IntegrationSource discriminator
packages/persona-kit/schemas/persona.schema.json, packages/persona-kit/scripts/emit-schema.mjs
PersonaIntegrationConfig now includes source referencing a new IntegrationSource anyOf discriminator supporting deployer_user, workspace, and workspace_service_account (requires name). The emit script tightens workspace_service_account.name validation (length and pattern).

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs:

🐰 "A cloud-bound hop with tokens so bright,
Workspace auth flows through the starlit night,
OAuth swirls and persona lives dance,
While status polls give deployments their chance,
From browser to beacon, we launch with delight!"

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 4.60% 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 accurately describes the main change: implementing cloud deploy mode (--mode cloud) with OSS-generic persona+bundle POST support.
Description check ✅ Passed The description is extensive and directly related to the changeset, detailing Track H implementation, spec compliance verification, test results, and known gaps.
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 feat/deploy-mode-cloud

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

@khaliqgant khaliqgant marked this pull request as ready for review May 13, 2026 04:49
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: 1

🧹 Nitpick comments (2)
packages/cli/src/deploy-command.ts (1)

11-11: 💤 Low value

Consider extracting DEFAULT_CLOUD_URL to a shared constant.

DEFAULT_CLOUD_URL is duplicated here and in cloud.ts. While acceptable for now, a shared constant would prevent drift.

🤖 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/deploy-command.ts` at line 11, Extract the duplicated
DEFAULT_CLOUD_URL constant into a single shared exported constant (e.g., export
const DEFAULT_CLOUD_URL) in a new or existing shared module (e.g., a
constants/shared module), then update both references in deploy-command.ts
(currently using DEFAULT_CLOUD_URL) and cloud.ts to import and use that shared
constant; ensure you remove the local literal and export the single source of
truth so both modules import the same identifier DEFAULT_CLOUD_URL.
packages/deploy/src/login.ts (1)

167-176: 💤 Low value

Tokens in URL query parameters are logged to browser history.

OAuth tokens (access_token, refresh_token) arrive via query parameters, which browsers persist in history. Since this is a localhost callback for CLI auth, exposure risk is low, but consider documenting this or clearing browser history programmatically if security requirements tighten.

🤖 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/deploy/src/login.ts` around lines 167 - 176, The callback handler
extracts tokens from requestUrl (token, refreshToken, expiresAt, cloudUrl) and
currently leaves them in the browser history; update the login callback response
generation (the code around token / refreshToken extraction in
packages/deploy/src/login.ts) so the HTTP response served to the browser
includes a small client-side script that immediately clears the query string
(use window.history.replaceState to remove access_token/refresh_token/expires_at
from the URL) before rendering any UI or closing the tab, ensuring tokens are
not retained in browser history; keep server-side token handling unchanged but
ensure the response includes this JS action and any minimal UX to run it.
🤖 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/deploy/src/modes/cloud.ts`:
- Around line 813-828: The JSON.parse call in readInputsOverride should be
wrapped in a try-catch so malformed JSON yields a clearer error; catch the parse
error around JSON.parse(raw) and rethrow a new Error that mentions
WORKFORCE_DEPLOY_INPUTS_JSON is invalid and includes the original error.message
(and optionally the raw value) for context, while preserving the subsequent type
checks and the existing error shapes thrown for non-object or non-string values.

---

Nitpick comments:
In `@packages/cli/src/deploy-command.ts`:
- Line 11: Extract the duplicated DEFAULT_CLOUD_URL constant into a single
shared exported constant (e.g., export const DEFAULT_CLOUD_URL) in a new or
existing shared module (e.g., a constants/shared module), then update both
references in deploy-command.ts (currently using DEFAULT_CLOUD_URL) and cloud.ts
to import and use that shared constant; ensure you remove the local literal and
export the single source of truth so both modules import the same identifier
DEFAULT_CLOUD_URL.

In `@packages/deploy/src/login.ts`:
- Around line 167-176: The callback handler extracts tokens from requestUrl
(token, refreshToken, expiresAt, cloudUrl) and currently leaves them in the
browser history; update the login callback response generation (the code around
token / refreshToken extraction in packages/deploy/src/login.ts) so the HTTP
response served to the browser includes a small client-side script that
immediately clears the query string (use window.history.replaceState to remove
access_token/refresh_token/expires_at from the URL) before rendering any UI or
closing the tab, ensuring tokens are not retained in browser history; keep
server-side token handling unchanged but ensure the response includes this JS
action and any minimal UX to run it.
🪄 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: 32ec386a-c5b6-4ab2-bacb-203a1ba62951

📥 Commits

Reviewing files that changed from the base of the PR and between 19ebbee and ad36e7b.

📒 Files selected for processing (9)
  • packages/cli/src/deploy-command.ts
  • packages/deploy/src/deploy.test.ts
  • packages/deploy/src/deploy.ts
  • packages/deploy/src/index.ts
  • packages/deploy/src/login.ts
  • packages/deploy/src/modes/cloud.test.ts
  • packages/deploy/src/modes/cloud.ts
  • packages/deploy/src/modes/sandbox.ts
  • packages/deploy/src/types.ts

Comment thread packages/deploy/src/modes/cloud.ts
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 found 1 potential issue.

View 6 additional findings in Devin Review.

Open in Devin Review

Comment on lines +244 to +249
if (stdout.trim()) {
return {
workspace,
token: stdout.trim()
};
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔴 readMacKeychainLogin returns raw JSON string as auth token when stored workspace doesn't match

When parseStoredLogin successfully parses a keychain entry but the stored workspace doesn't match the requested one, the code falls through to the if (stdout.trim()) check and returns the entire raw JSON string as the token. For example, if the keychain stores {"workspace":"other-ws","token":"real-token"} under the generic agentworkforce service name, and the caller requests workspace my-ws, the function returns { workspace: "my-ws", token: '{"workspace":"other-ws","token":"real-token"}' }. This serialized JSON object is then used as a Bearer token in HTTP Authorization headers, causing 401 errors with confusing messages. The fix should continue to the next service name when parsed is non-null but the workspace doesn't match, reserving the raw-stdout-as-token fallback for cases where parseStoredLogin returns null (non-JSON values).

Suggested change
if (stdout.trim()) {
return {
workspace,
token: stdout.trim()
};
}
if (parsed) continue;
if (stdout.trim()) {
return {
workspace,
token: stdout.trim()
};
}
Open in Devin Review

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

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Already addressed in 0a9d893 (morning sweep). readMacKeychainLogin now uses if (parsed) continue; to skip generic-service keychain entries that parse cleanly but whose workspace field doesn't match — preventing the raw-JSON-as-bearer-token fallback. Reaffirmed clean on the post-rebase commit 0db4fef.

- login: skip keychain entry when stored workspace mismatches instead of
  returning the raw JSON blob as a bearer token (devin-ai)
- cloud: wrap WORKFORCE_DEPLOY_INPUTS_JSON parse in try/catch for a
  clearer error message on malformed JSON (coderabbit)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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: 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/persona-kit/schemas/persona.schema.json`:
- Around line 454-456: The schema allows an empty workspace_service_account
name; update the persona.schema.json schema for the workspace_service_account ->
name property to forbid empty strings by adding a validation constraint (e.g.,
"minLength": 1 or a non-empty pattern) to the "name" property so that "" no
longer validates; keep the existing "type": "string" and only add the non-empty
constraint to the "name" field to enforce user-supplied service account names.
🪄 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: 4c59fab3-85b2-4303-b9e2-eaf486302e9b

📥 Commits

Reviewing files that changed from the base of the PR and between 0a9d893 and 0db4fef.

📒 Files selected for processing (6)
  • packages/cli/src/deploy-command.ts
  • packages/deploy/src/index.ts
  • packages/deploy/src/modes/input-values.test.ts
  • packages/deploy/src/modes/sandbox.ts
  • packages/deploy/src/types.ts
  • packages/persona-kit/schemas/persona.schema.json
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/deploy/src/types.ts
  • packages/deploy/src/modes/sandbox.ts
  • packages/cli/src/deploy-command.ts

Comment thread packages/persona-kit/schemas/persona.schema.json
…ce_account.name

CodeRabbit (cloud#102 review) flagged that the generated JSON schema
accepted empty strings for `integrations.<provider>.source.name` when
`kind === "workspace_service_account"` — even though parse.ts has
rejected those at runtime since the source-discriminator landed.

The generator emits a bare `{ "type": "string" }` because the constraints
live in the parser (INTEGRATION_SOURCE_NAME_RE, max 64) and the TS source
type is a union literal whose `name` field has no annotatable position
for ts-json-schema-generator to pick up.

Mirror the three parser rules at the schema layer via a post-process walk
in emit-schema.mjs:

  "name": {
    "type": "string",
    "minLength": 1,
    "maxLength": 64,
    "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$"
  }

Now schema-validation rejects malformed names with the same precision the
parser does, instead of pushing the failure to deploy-time.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@khaliqgant khaliqgant merged commit ead1b15 into main May 13, 2026
1 of 2 checks passed
@khaliqgant khaliqgant deleted the feat/deploy-mode-cloud branch May 13, 2026 09:29
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