diff --git a/CHANGELOG.md b/CHANGELOG.md index 97a3568..b3017c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## 3.3.0 + +- Surface each development session's authenticated `browserPreviewUrl` for + owner/builder review before deployment, while retaining the raw + `previewUrl` for bounded CLI and agent inspection. +- Direct humans to the persistent **Development preview — Not live** shell and + its Full size, Tablet, Mobile, and Reload controls instead of the raw + capability origin that can return `AUTH_REQUIRED` in a normal browser. + ## 3.2.0 - Validate manifest-declared Postgres-backed queues, their bounded retry and diff --git a/README.md b/README.md index b8cc5ca..12b3956 100644 --- a/README.md +++ b/README.md @@ -12,12 +12,12 @@ offline source bundle, but cannot connect to or deploy through OpenCloud. ## Install a pinned release -OpenCloud application skills pin an exact CLI release. To install `v3.2.0` in +OpenCloud application skills pin an exact CLI release. To install `v3.3.0` in an isolated task directory: ```bash -OPENCLOUD_CLI_VERSION="v3.2.0" -OPENCLOUD_CLI_PACKAGE="opencloud-cli-3.2.0.tgz" +OPENCLOUD_CLI_VERSION="v3.3.0" +OPENCLOUD_CLI_PACKAGE="opencloud-cli-3.3.0.tgz" OPENCLOUD_CLI_DIR="$(mktemp -d)" curl -fsSLo "$OPENCLOUD_CLI_DIR/$OPENCLOUD_CLI_PACKAGE" \ @@ -180,6 +180,14 @@ Use the stable capability preview and isolated migration-replayed database befor "$OPENCLOUD_CLI" app dev evidence . ``` +`app dev start` returns `session.browserPreviewUrl`, and `app dev status` +returns the same owner/builder review link as top-level `browserPreviewUrl`. +Give that URL to a human reviewer: it opens the isolated revision in a +persistent **Development preview — Not live** shell with Full size, Tablet, +Mobile, and Reload controls. Keep the raw `previewUrl` for CLI and agent +inspection; opening it directly in a normal browser may return +`AUTH_REQUIRED`. + Development data is isolated from production and uses dummy records. Auth, Files, Functions, and background jobs are available; Realtime and cron are not. Manifest- generated secrets receive isolated synthetic development values, while owner- diff --git a/package-lock.json b/package-lock.json index c14a611..5a89a99 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@opencloud/cli", - "version": "3.2.0", + "version": "3.3.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@opencloud/cli", - "version": "3.2.0", + "version": "3.3.0", "dependencies": { "@napi-rs/keyring": "1.3.0" }, diff --git a/package.json b/package.json index 3e87d6a..ca12fa3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@opencloud/cli", - "version": "3.2.0", + "version": "3.3.0", "description": "Versioned command-line client for building, deploying, and verifying OpenCloud applications", "type": "module", "bin": { diff --git a/src/index.ts b/src/index.ts index e9c0071..b05d400 100644 --- a/src/index.ts +++ b/src/index.ts @@ -52,7 +52,7 @@ import { resolveWorkspaceFile, } from "./workspace-store.js"; -const CLI_VERSION = "3.2.0"; +const CLI_VERSION = "3.3.0"; const program = new Command() .name("opencloud") @@ -233,6 +233,7 @@ interface DevSessionWire { draftId: string; status: string; previewUrl: string; + browserPreviewUrl: string; activeRevision: { id: string; draftRevision: number; @@ -1056,7 +1057,8 @@ dev validation: synchronized.validation, localState: devStatePath(sourceRoot), next: [ - "Open session.previewUrl or use `opencloud app dev request /`.", + "Give session.browserPreviewUrl to an owner or builder for a clearly marked Not live browser review.", + "Use `opencloud app dev request /` for agent inspection; do not give session.previewUrl to a human reviewer.", "After edits run `opencloud app dev sync `.", "Ordinary Functions remain dormant until `app dev invoke` or a deliberate preview action calls them; enqueuing a declared job wakes its system consumer.", "Add isolated fixtures with `app dev data`, then verify and run `app dev promote`; promotion follows production verification and reports the live URL.", @@ -1093,7 +1095,7 @@ dev dev .command("status") .description( - "Show the active revision, capability URL, and verification receipt", + "Show the active revision, browser review link, capability URL, and verification receipt", ) .argument("[directory]", "app source directory", ".") .action(async (directory) => { diff --git a/vendor/contracts/src/control-plane.test.ts b/vendor/contracts/src/control-plane.test.ts index bce03ba..1309342 100644 --- a/vendor/contracts/src/control-plane.test.ts +++ b/vendor/contracts/src/control-plane.test.ts @@ -413,6 +413,8 @@ describe("controlPlaneOperations", () => { draftId: "33333333-3333-4333-8333-333333333333", status: "active", previewUrl: "https://dev-example.opencloud.ai", + browserPreviewUrl: + "https://dev-example.opencloud.ai/_opencloud/dev/launch", baseDeploymentId: null, activeRevision: null, verification: null, @@ -434,9 +436,9 @@ describe("controlPlaneOperations", () => { expiresAt: "2026-08-06T00:00:00.000Z", }; - expect( - controlPlaneOperations.getDevSession.output.parse(session).capabilities, - ).toEqual(session.capabilities); + const parsed = controlPlaneOperations.getDevSession.output.parse(session); + expect(parsed.capabilities).toEqual(session.capabilities); + expect(parsed.browserPreviewUrl).toBe(session.browserPreviewUrl); expect(() => controlPlaneOperations.getDevSession.output.parse({ ...session, diff --git a/vendor/contracts/src/control-plane.ts b/vendor/contracts/src/control-plane.ts index d9f4a57..42338a4 100644 --- a/vendor/contracts/src/control-plane.ts +++ b/vendor/contracts/src/control-plane.ts @@ -497,6 +497,11 @@ export const devSessionOutput = z "expired", ]), previewUrl: z.url(), + browserPreviewUrl: z + .url() + .describe( + "Owner/builder review link that opens the isolated revision in a clearly marked Not live preview shell with responsive viewport controls.", + ), baseDeploymentId: uuid.nullable(), activeRevision: z .object({ @@ -1372,7 +1377,7 @@ export const controlPlaneOperations = { path: "/v1/apps/{appId}/drafts/{draftId}/dev-sessions", summary: "Start a development session", description: - "Creates or resumes an isolated preview for a validated draft and optionally applies its exact revision.", + "Creates or resumes an isolated preview for a validated draft, optionally applies its exact revision, and returns a browserPreviewUrl that a signed-in owner or builder can open in a clearly marked responsive preview shell before deployment.", auth: "bearer", scopes: ["app:deploy"], input: draftPath.extend({ @@ -1385,7 +1390,7 @@ export const controlPlaneOperations = { toolName: "start_dev_session", title: "Start dev session", description: - "Start or resume an isolated frontend and database preview for a validated draft.", + "Start or resume an isolated frontend and database preview for a validated draft. Give browserPreviewUrl to a signed-in owner or builder who wants to review it before deployment; the link opens a clearly marked Not live window with Full size, Tablet, Mobile, and Reload tools around isolated synthetic user A and never reads production data. An explicit no-deploy request stops at this review point and does not authorize promotion.", readOnlyHint: false, destructiveHint: false, idempotentHint: false, @@ -1397,7 +1402,7 @@ export const controlPlaneOperations = { path: "/v1/apps/{appId}/dev-sessions/{sessionId}", summary: "Get a development session", description: - "Returns preview state, capabilities, and verification status.", + "Returns preview state, the owner/builder browserPreviewUrl for the marked responsive review shell, capabilities, and verification status.", auth: "bearer", scopes: ["app:read"], input: devSessionPath,