minutework 0.1.50 → 0.1.52

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -147,15 +147,17 @@ minutework deploy --preview
147
147
 
148
148
  Combined **tenant-app + sidecar** workspaces keep sidecar setup explicit. Root `pnpm install` stays Node-only and does not run `poetry install` for you. If you need the sidecar, run `pnpm run install:sidecar` from the workspace root or `cd sidecar && poetry install` yourself before `minutework dev` or `minutework test`. Sidecar-only scaffolds have no root `package.json`; install Python deps once inside `sidecar/` before running local sidecar workflows.
149
149
 
150
- For direct third-party web hosts such as Vercel, deploy `tenant-app` only. In Vercel, point the project Root Directory at `tenant-app`; the optional sidecar remains a separate Poetry-managed surface.
150
+ For direct third-party web hosts such as Vercel, deploy `tenant-app` only. In Vercel, point the project Root Directory at `tenant-app`; the optional sidecar remains a separate Poetry-managed surface. To keep `@minutework/web-auth` same-origin on a bring-your-own host, set `MW_GATEWAY_BASE_URL` to the platform gateway base URL — the template's `next.config.mjs` then proxies `/_mw/*` to the gateway — and run `minutework deploy --live --host <your-domain>` so the gateway recognizes that host as your tenant's live canonical customer-web origin.
151
151
 
152
152
  `link` provisions or resolves the default published-site property for the active tenant and stores that property key in repo-local state. The SDK-based `tenant-app/.env.example` contains only the app metadata contract used by the template: `NEXT_PUBLIC_MW_APP_ID`, `MW_TEMPLATE_APP_NAME`, and optional `MW_PUBLIC_BASE_URL`. Browser auth and manifest calls use same-origin `/_mw` routes through `@minutework/web-auth`; do not add platform content tokens or public-site property vars to the tenant app.
153
153
 
154
- `deploy --preview` always revalidates and recompiles before submit, prints a local-vs-remote diff, requires confirmation unless `--yes` is passed, polls typed receipts until a terminal state, and persists the last known preview deploy state under `.minutework/deploy/preview/status.json`. This alpha is preview-first; live public delivery remains follow-on.
154
+ `deploy --preview` always revalidates and recompiles before submit, prints a local-vs-remote diff, requires confirmation unless `--yes` is passed, polls typed receipts until a terminal state, and persists the last known preview deploy state under `.minutework/deploy/preview/status.json`.
155
+
156
+ `deploy --live` is the self-serve lane for a **`tenant-app` customer-web** surface (browser signup/signin via `@minutework/web-auth` on same-origin `/_mw`). It provisions a customer-web property, binds a canonical live host, and activates the compiled release **only after it passes the platform publication-review attestation gate** (the same gate as `publish`); a rejected attestation prints the review findings and exits 1 without activating. Once live, the platform gateway resolves that host and serves `/_mw/auth/{csrf,signup,login,session,verify-email,logout}` for real tenant-scoped customer accounts. By default it binds a managed subdomain (`<tenant>.<customer-web-domain>`, auto-verified by the platform). Pass `--host <domain>` to bind a bring-your-own (Vercel/custom) domain: the first run prints a DNS/HTTP verification challenge; re-run with `--host <domain> --verify <challenge>` once the record is published to confirm and activate. Live activation requires an interactive token or a deploy token minted with the `deploy.live.request` scope. MinuteWork-hosted byte-hosting of the tenant-app itself remains follow-on; until then, host the built `tenant-app` yourself (see Vercel below) and use this lane to make `/_mw` work for that host.
155
157
 
156
158
  ## Machine-readable output (`--json`)
157
159
 
158
- `validate`, `compile`, `codegen`, `deploy --preview`, `publish`, and `gaps` accept `--json` so an IDE coding agent can drive them unattended and parse one stable shape. With `--json` the command prints a single result envelope to stdout and nothing else:
160
+ `validate`, `compile`, `codegen`, `deploy --preview`, `deploy --live`, `publish`, and `gaps` accept `--json` so an IDE coding agent can drive them unattended and parse one stable shape. With `--json` the command prints a single result envelope to stdout and nothing else:
159
161
 
160
162
  ```json
161
163
  {
@@ -23,6 +23,10 @@ receive:
23
23
  `useMinuteWorkSession().status`; mobile uses `@minutework/native-auth`
24
24
  bearer-token storage for its same-named password method and sends the
25
25
  configured `EXPO_PUBLIC_MW_TENANT_ID` tenant context
26
+ - `tenant-app` browser customer auth (`/_mw` signup/login) only works on a
27
+ live, canonical customer-web host; reach it with self-serve
28
+ `minutework deploy --live` (attestation-gated), not `deploy --preview` — see
29
+ `tenant-app-customer-auth-deploy/SKILL.md`
26
30
  - `mw.core.site` is a runtime baseline capability
27
31
  - tenant public authoring is runtime/CMS-backed through `mw.core.site`
28
32
  - Vuilder-owned public sites use `vuilder-public-site` and public-dj CMS
@@ -58,6 +62,7 @@ Generated-workspace-first guidance should live here, especially:
58
62
  - `integration-broker-and-connectors/SKILL.md`
59
63
  - `layering-and-import-modes/SKILL.md`
60
64
  - `standalone-mobile-client/SKILL.md`
65
+ - `tenant-app-customer-auth-deploy/SKILL.md`
61
66
  - `capability-gap-reporting/SKILL.md`
62
67
  - `shadow-participation-and-guest-threads/SKILL.md`
63
68
  - `email-ingress-and-thread-routing/SKILL.md`
@@ -20,6 +20,12 @@ flows, or the default MinuteWork site model.
20
20
  runtime-canonical through `mw.core.site` and installed app-pack data.
21
21
  - `tenant-app` is the combined web starter for public routes plus the private
22
22
  `/app` workspace.
23
+ - For `tenant-app` **browser customer auth** (`@minutework/web-auth` same-origin
24
+ `/_mw` signup/login), read `tenant-app-customer-auth-deploy/SKILL.md`: `/_mw`
25
+ only works on a live, canonical customer-web host, reached with self-serve
26
+ `minutework deploy --live` (attestation-gated). That is a distinct property
27
+ and host from the anonymous public-site delivery covered here, and
28
+ `deploy --preview` does not enable it.
23
29
  - Do not add a server-only public content token adapter to `tenant-app`.
24
30
  Public content should come from hosted published releases/snapshots or
25
31
  gateway-approved public-content routes over the MinuteWork substrate, not
@@ -0,0 +1,72 @@
1
+ ---
2
+ name: tenant-app-customer-auth-deploy
3
+ description: "tenant-app browser customer auth: @minutework/web-auth same-origin /_mw signup/login works only on a live, canonical customer-web host. Reach it with self-serve minutework deploy --live (attestation-gated); deploy --preview does not enable /_mw."
4
+ ---
5
+
6
+ # Tenant-App Customer-Auth Deploy
7
+
8
+ Use this skill when a `tenant-app` needs **browser customer signup/login** (the
9
+ `@minutework/web-auth` SDK: `signUp` / `signInWithPassword` /
10
+ `useMinuteWorkSession()` against same-origin `/_mw/auth/*`), or when the symptom
11
+ is "customer auth / `/_mw` returns 404, how do I make login work / go live?".
12
+
13
+ The SDK contract is already correct in the starter; the missing half is making
14
+ the platform gateway **recognize the host** so it serves `/_mw`.
15
+
16
+ ## The trust gate (never bypass it)
17
+
18
+ `/_mw/auth/{csrf,signup,login,session,verify-email,logout}` is served by the
19
+ platform gateway, but only for a host that resolves to a **live, canonical,
20
+ verified** customer-web binding plus a **live** release
21
+ (`resolve_tenant_for_customer_web_host`: `route_role="live"`,
22
+ `is_canonical=True`, verified `DomainBinding`, live `SiteRelease`). Preview and
23
+ non-canonical hosts are rejected by design — customer auth creates real
24
+ tenant-scoped accounts. Do not try to relax this, point `/_mw` at a remote
25
+ project URL, or add per-app auth/gateway BFF routes. The fix is to reach live,
26
+ not to work around the gate.
27
+
28
+ ## How to reach live: `minutework deploy --live`
29
+
30
+ Run `minutework deploy --live` for the `tenant-app` workspace. It is self-serve
31
+ and host-agnostic, and it:
32
+
33
+ - provisions a **customer-web** `PublishedWebProperty` (distinct from any
34
+ vuilder public-site property — different `property_key` and host; do not
35
+ conflate them),
36
+ - binds a **canonical live host**, and
37
+ - activates the compiled release **live only after it passes the same
38
+ publication-review attestation gate as `minutework publish`** (`approved` /
39
+ `approved_with_warnings`). A rejected attestation prints the review findings
40
+ and exits 1 without activating — fix the findings, don't retry blindly.
41
+
42
+ Authorize it with an interactive developer token or a deploy token minted with
43
+ the `deploy.live.request` scope (`minutework deploy --live --json --yes` runs
44
+ unattended; without `--yes` it returns `confirmation_required`).
45
+
46
+ ## Host shapes
47
+
48
+ - **Managed subdomain (default):** no flag. The platform derives
49
+ `<tenant>.<customer-web-domain>` and auto-verifies it (it owns that DNS).
50
+ Single-shot: `minutework deploy --live`.
51
+ - **Bring-your-own / custom domain (Vercel, etc.):**
52
+ `minutework deploy --live --host <domain>` registers the host and prints a
53
+ DNS/HTTP verification challenge; publish the record, then re-run
54
+ `minutework deploy --live --host <domain> --verify <challenge>` to confirm and
55
+ activate. On a BYO host, set `MW_GATEWAY_BASE_URL` in the tenant-app so the
56
+ template's `next.config.mjs` proxies same-origin `/_mw/*` to the gateway
57
+ (managed-subdomain hosts are gateway-fronted and need no rewrite).
58
+
59
+ ## Boundaries and current limits
60
+
61
+ - `deploy --preview` is preview-only and does **not** enable `/_mw` customer
62
+ auth (preview ≠ live; the gateway rejects preview hosts). Use `--live`.
63
+ - MinuteWork-hosted byte-hosting of the tenant-app bundle is follow-on. Today
64
+ host the built `tenant-app` yourself (e.g. Vercel) and use `--live` to make
65
+ `/_mw` resolve for that host; the lane only owns the host binding + live
66
+ activation, not the bundle hosting.
67
+ - The web session principal is `tenant_customer` (not an operator
68
+ `Membership`); status precedence stays `loading -> verification_required ->
69
+ authenticated -> unauthenticated`.
70
+ - For anonymous public-site content (not customer auth), use
71
+ `published-web-and-mw-core-site/SKILL.md` and hosted published snapshots
72
+ instead.
@@ -1,3 +1,7 @@
1
1
  NEXT_PUBLIC_MW_APP_ID=tenant.app
2
2
  MW_TEMPLATE_APP_NAME=Tenant App
3
3
  MW_PUBLIC_BASE_URL=
4
+ # Only needed when hosting this app off-platform (Vercel / custom domain). Set to the
5
+ # MinuteWork platform gateway base URL to transparently proxy same-origin /_mw/* customer
6
+ # auth to the gateway. Leave blank for managed-subdomain hosts (gateway-fronted).
7
+ MW_GATEWAY_BASE_URL=
@@ -20,6 +20,15 @@ function resolveTurbopackRoot(startDirectory) {
20
20
  }
21
21
  }
22
22
 
23
+ // Bring-your-own host support: when this tenant-app is hosted off-platform (Vercel
24
+ // or a custom domain) instead of being fronted by the MinuteWork gateway, set
25
+ // MW_GATEWAY_BASE_URL so same-origin `/_mw/*` customer-auth calls are transparently
26
+ // proxied to the platform gateway. The gateway serves customer auth for this tenant's
27
+ // live canonical customer-web host (provisioned via `minutework deploy --live`), so
28
+ // @minutework/web-auth keeps its same-origin contract without a remote project URL.
29
+ // Unset by default: managed-subdomain hosts are gateway-fronted and need no rewrite.
30
+ const gatewayBaseUrl = (process.env.MW_GATEWAY_BASE_URL || "").trim().replace(/\/+$/, "");
31
+
23
32
  const nextConfig = {
24
33
  reactStrictMode: true,
25
34
  typedRoutes: true,
@@ -28,6 +37,13 @@ const nextConfig = {
28
37
  turbopack: {
29
38
  root: resolveTurbopackRoot(__dirname),
30
39
  },
40
+ ...(gatewayBaseUrl
41
+ ? {
42
+ async rewrites() {
43
+ return [{ destination: `${gatewayBaseUrl}/_mw/:path*`, source: "/_mw/:path*" }];
44
+ },
45
+ }
46
+ : {}),
31
47
  };
32
48
 
33
49
  export default nextConfig;
@@ -0,0 +1,46 @@
1
+ import type { HostedPreviewReleaseMetadata } from "@minutework/schema-compiler";
2
+ import { type DeveloperClientDependencies, createDeveloperClient } from "./developer-client.js";
3
+ import type { CliIo } from "./index.js";
4
+ export declare const MINUTEWORK_CUSTOMER_WEB_PACKAGE_VERSION = "MinuteWorkCustomerWebPackageV1";
5
+ /**
6
+ * Bundle a compiled tenant-app starter directory into the same gate-artifact shape
7
+ * the publication-review pipeline consumes (`appId`, `artifactSetDigest`,
8
+ * `compileGraph.documents.appManifests`, `sourceBundle.files`, `dependencyExport`).
9
+ * Bundling the real source is deliberate: the live customer-web gate must run the
10
+ * static-security/economic/ui gates over the actual tenant-app source, not an empty set.
11
+ */
12
+ export declare function buildCustomerWebPackage(options: {
13
+ releaseMetadata: HostedPreviewReleaseMetadata;
14
+ workspaceRoot: string;
15
+ }): Promise<Record<string, unknown>>;
16
+ export type CustomerWebLiveDeployDependencies = DeveloperClientDependencies & {
17
+ confirmCustomerWebLiveDeploy?: (context: {
18
+ canonicalHost: string;
19
+ propertyKey: string;
20
+ }) => Promise<boolean>;
21
+ };
22
+ /**
23
+ * Drive a single self-serve live customer-web deploy: provision + bind the canonical
24
+ * host, run the tenant-app release through the live publication-review gate, and (only
25
+ * on an approved attestation) activate it live so the gateway serves same-origin `/_mw`.
26
+ */
27
+ export declare function runCustomerWebLiveDeploy(options: {
28
+ client: ReturnType<typeof createDeveloperClient>;
29
+ customHostname?: string;
30
+ dependencies?: CustomerWebLiveDeployDependencies;
31
+ hostLabel?: string;
32
+ io: CliIo;
33
+ json: boolean;
34
+ releaseMetadata: HostedPreviewReleaseMetadata;
35
+ renderJson: (envelope: {
36
+ error?: {
37
+ message: string;
38
+ };
39
+ ok: boolean;
40
+ result?: unknown;
41
+ status: string;
42
+ }) => string;
43
+ verifyChallengeResponse?: string;
44
+ workspaceRoot: string;
45
+ yes: boolean;
46
+ }): Promise<number>;
@@ -0,0 +1,250 @@
1
+ import { createHash } from "node:crypto";
2
+ import { promises as fs } from "node:fs";
3
+ import path from "node:path";
4
+ export const MINUTEWORK_CUSTOMER_WEB_PACKAGE_VERSION = "MinuteWorkCustomerWebPackageV1";
5
+ const _IGNORED_DIRECTORIES = new Set([
6
+ ".git",
7
+ ".next",
8
+ ".turbo",
9
+ ".vercel",
10
+ "coverage",
11
+ "dist",
12
+ "node_modules",
13
+ "out",
14
+ ]);
15
+ /**
16
+ * Bundle a compiled tenant-app starter directory into the same gate-artifact shape
17
+ * the publication-review pipeline consumes (`appId`, `artifactSetDigest`,
18
+ * `compileGraph.documents.appManifests`, `sourceBundle.files`, `dependencyExport`).
19
+ * Bundling the real source is deliberate: the live customer-web gate must run the
20
+ * static-security/economic/ui gates over the actual tenant-app source, not an empty set.
21
+ */
22
+ export async function buildCustomerWebPackage(options) {
23
+ const starterRoot = path.join(options.workspaceRoot, options.releaseMetadata.starterPath);
24
+ const files = await buildSourceFiles(starterRoot);
25
+ const sourceBundleDigest = sha256Hex(JSON.stringify(files.map((file) => ({ path: file.path, sha256: file.sha256 }))));
26
+ const dependencyExport = await buildDependencyExport(starterRoot);
27
+ const appManifest = {
28
+ app_class: "combined_web",
29
+ app_id: options.releaseMetadata.appId,
30
+ app_version: options.releaseMetadata.releaseKey,
31
+ };
32
+ const artifactSetDigest = sha256Hex(JSON.stringify({
33
+ appManifest,
34
+ dependencyExport: { kind: dependencyExport.kind, sha256: dependencyExport.sha256 },
35
+ release: options.releaseMetadata,
36
+ sourceBundle: sourceBundleDigest,
37
+ version: MINUTEWORK_CUSTOMER_WEB_PACKAGE_VERSION,
38
+ }));
39
+ return {
40
+ appId: options.releaseMetadata.appId,
41
+ artifactSetDigest,
42
+ compileGraph: {
43
+ documents: {
44
+ appManifests: [appManifest],
45
+ },
46
+ },
47
+ dependencyExport,
48
+ sourceBundle: { files, sha256: sourceBundleDigest },
49
+ version: MINUTEWORK_CUSTOMER_WEB_PACKAGE_VERSION,
50
+ };
51
+ }
52
+ async function buildSourceFiles(root) {
53
+ const files = [];
54
+ async function visit(currentPath) {
55
+ const stat = await fs.lstat(currentPath);
56
+ if (stat.isSymbolicLink()) {
57
+ return;
58
+ }
59
+ if (stat.isDirectory()) {
60
+ const entries = await fs.readdir(currentPath);
61
+ await Promise.all(entries
62
+ .filter((entry) => !_IGNORED_DIRECTORIES.has(entry))
63
+ .sort()
64
+ .map((entry) => visit(path.join(currentPath, entry))));
65
+ return;
66
+ }
67
+ if (!stat.isFile()) {
68
+ return;
69
+ }
70
+ const relativePath = path.relative(root, currentPath).split(path.sep).join("/");
71
+ const contents = await fs.readFile(currentPath);
72
+ files.push({
73
+ contentBase64: contents.toString("base64"),
74
+ path: relativePath,
75
+ sha256: createHash("sha256").update(contents).digest("hex"),
76
+ });
77
+ }
78
+ await visit(root);
79
+ files.sort((left, right) => left.path.localeCompare(right.path));
80
+ return files;
81
+ }
82
+ async function buildDependencyExport(starterRoot) {
83
+ for (const [filename, kind] of [
84
+ ["pnpm-lock.yaml", "pnpm_lock"],
85
+ ["package-lock.json", "npm_lock"],
86
+ ["yarn.lock", "yarn_lock"],
87
+ ]) {
88
+ try {
89
+ const content = await fs.readFile(path.join(starterRoot, filename), "utf8");
90
+ return { content, kind, sha256: sha256Hex(content) };
91
+ }
92
+ catch (error) {
93
+ if (error.code !== "ENOENT") {
94
+ throw error;
95
+ }
96
+ }
97
+ }
98
+ return { content: "", kind: "none", sha256: sha256Hex("") };
99
+ }
100
+ function sha256Hex(value) {
101
+ return createHash("sha256").update(value).digest("hex");
102
+ }
103
+ /**
104
+ * Drive a single self-serve live customer-web deploy: provision + bind the canonical
105
+ * host, run the tenant-app release through the live publication-review gate, and (only
106
+ * on an approved attestation) activate it live so the gateway serves same-origin `/_mw`.
107
+ */
108
+ export async function runCustomerWebLiveDeploy(options) {
109
+ const link = await options.client.linkCustomerWeb({
110
+ customHostname: options.customHostname,
111
+ hostLabel: options.hostLabel,
112
+ });
113
+ const propertyKey = link.property.property_key;
114
+ // Bring-your-own custom domains must clear an out-of-band DNS / HTTP challenge before
115
+ // they can be promoted canonical. If the host is not yet verified, surface the
116
+ // challenge and stop — re-run with --verify <token> once the record is in place.
117
+ if (link.host.verification_required && !options.verifyChallengeResponse) {
118
+ return renderPendingVerification({ io: options.io, json: options.json, link, renderJson: options.renderJson });
119
+ }
120
+ if (options.verifyChallengeResponse) {
121
+ const verified = await options.client.verifyCustomerWebDomain({
122
+ challengeResponse: options.verifyChallengeResponse,
123
+ hostname: link.host.hostname,
124
+ propertyKey,
125
+ });
126
+ if (verified.host.verification_status !== "verified") {
127
+ const message = `Custom host ${verified.host.hostname} did not verify; re-check the DNS/HTTP challenge.`;
128
+ if (options.json) {
129
+ options.io.stdout(options.renderJson({ error: { message }, ok: false, status: "verification_failed" }));
130
+ }
131
+ else {
132
+ options.io.stderr(message);
133
+ }
134
+ return 1;
135
+ }
136
+ }
137
+ const canonicalHost = link.host.canonical_host || link.host.hostname;
138
+ if (options.json && !options.yes) {
139
+ options.io.stdout(options.renderJson({
140
+ error: {
141
+ message: "Live customer-web deploy needs confirmation; re-run with --yes (required alongside --json).",
142
+ },
143
+ ok: false,
144
+ result: { canonicalHost, propertyKey },
145
+ status: "confirmation_required",
146
+ }));
147
+ return 1;
148
+ }
149
+ const confirmed = options.yes ||
150
+ (await (options.dependencies?.confirmCustomerWebLiveDeploy ?? defaultConfirmCustomerWebLiveDeploy)({
151
+ canonicalHost,
152
+ propertyKey,
153
+ }));
154
+ if (!confirmed) {
155
+ options.io.stderr("Live customer-web deploy cancelled.");
156
+ return 1;
157
+ }
158
+ const packagePayload = await buildCustomerWebPackage({
159
+ releaseMetadata: options.releaseMetadata,
160
+ workspaceRoot: options.workspaceRoot,
161
+ });
162
+ const response = await options.client.activateCustomerWebLive({
163
+ packagePayload,
164
+ propertyKey,
165
+ releaseKey: options.releaseMetadata.releaseKey,
166
+ runtimeContentRef: options.releaseMetadata.runtimeContentRef,
167
+ });
168
+ const succeeded = response.activated && response.resolves_live;
169
+ if (options.json) {
170
+ options.io.stdout(options.renderJson({
171
+ ok: succeeded,
172
+ result: {
173
+ activated: response.activated,
174
+ attestationState: response.attestation_state,
175
+ canonicalHost: response.canonical_host,
176
+ findings: response.findings,
177
+ propertyKey,
178
+ reason: response.reason,
179
+ resolvesLive: response.resolves_live,
180
+ },
181
+ status: response.attestation_state,
182
+ }));
183
+ return succeeded ? 0 : 1;
184
+ }
185
+ renderActivateResult(options.io, response);
186
+ return succeeded ? 0 : 1;
187
+ }
188
+ function renderPendingVerification(options) {
189
+ const host = options.link.host;
190
+ if (options.json) {
191
+ options.io.stdout(options.renderJson({
192
+ ok: false,
193
+ result: {
194
+ challengeToken: host.challenge_token,
195
+ hostname: host.hostname,
196
+ propertyKey: options.link.property.property_key,
197
+ verificationMethod: host.verification_method,
198
+ },
199
+ status: "verification_required",
200
+ }));
201
+ return 2;
202
+ }
203
+ options.io.stdout(`Registered custom customer-web host ${host.hostname} (pending verification).`);
204
+ options.io.stdout(`Verification method: ${host.verification_method}`);
205
+ options.io.stdout(`Challenge token: ${host.challenge_token}`);
206
+ options.io.stdout(`Publish the challenge (DNS TXT / HTTP well-known), then re-run with --host ${host.hostname} --verify ${host.challenge_token}.`);
207
+ return 2;
208
+ }
209
+ function renderActivateResult(io, response) {
210
+ if (response.activated && response.resolves_live) {
211
+ io.stdout(`Live customer-web host: https://${response.canonical_host}/`);
212
+ io.stdout(`Attestation: ${response.attestation_state}`);
213
+ io.stdout("Same-origin /_mw customer auth is now served for this host.");
214
+ }
215
+ else if (response.activated) {
216
+ io.stderr(`Release activated but the host is not resolving live yet (reason: ${response.reason || "unknown"}).`);
217
+ }
218
+ else {
219
+ io.stderr(`Live customer-web deploy rejected by the publication-review gate (attestation: ${response.attestation_state}).`);
220
+ }
221
+ if (response.findings.length > 0) {
222
+ io.stdout(`Review findings (${response.findings.length}):`);
223
+ for (const finding of response.findings) {
224
+ io.stdout(` [${finding.severity}] ${finding.gate_id}/${finding.finding_kind}: ${finding.summary}`);
225
+ if (finding.evidence_ref) {
226
+ io.stdout(` evidence: ${finding.evidence_ref}`);
227
+ }
228
+ if (finding.remediation) {
229
+ io.stdout(` fix: ${finding.remediation}`);
230
+ }
231
+ }
232
+ }
233
+ }
234
+ async function defaultConfirmCustomerWebLiveDeploy(context) {
235
+ const { createInterface } = await import("node:readline/promises");
236
+ if (!process.stdin.isTTY || !process.stdout.isTTY) {
237
+ throw new Error("Live customer-web deploy requires confirmation. Re-run interactively or pass `--yes`.");
238
+ }
239
+ const readline = createInterface({ input: process.stdin, output: process.stdout });
240
+ try {
241
+ const answer = (await readline.question(`Activate ${context.propertyKey} live on ${context.canonicalHost}? [y/N] `))
242
+ .trim()
243
+ .toLowerCase();
244
+ return answer === "y" || answer === "yes";
245
+ }
246
+ finally {
247
+ readline.close();
248
+ }
249
+ }
250
+ //# sourceMappingURL=customer-web.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"customer-web.js","sourceRoot":"","sources":["../src/customer-web.ts"],"names":[],"mappings":"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"}
package/dist/deploy.d.ts CHANGED
@@ -1,7 +1,8 @@
1
+ import { type CustomerWebLiveDeployDependencies } from "./customer-web.js";
1
2
  import { type DeveloperClientDependencies } from "./developer-client.js";
2
3
  import type { CliIo } from "./index.js";
3
4
  import type { CliStatePaths, PlatformName } from "./paths.js";
4
- export type DeployDependencies = DeveloperClientDependencies & {
5
+ export type DeployDependencies = DeveloperClientDependencies & CustomerWebLiveDeployDependencies & {
5
6
  confirmPreviewDeploy?: (context: {
6
7
  appId?: string;
7
8
  localReleaseDigest: string;
@@ -24,4 +25,4 @@ export declare function runDeployCommand(options: {
24
25
  io: CliIo;
25
26
  paths: CliStatePaths;
26
27
  platform: PlatformName;
27
- }): Promise<0 | 1>;
28
+ }): Promise<number>;