forgeos 0.1.0-alpha.41 → 0.1.0-alpha.42

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.
Files changed (65) hide show
  1. package/AGENTS.md +1 -1
  2. package/CHANGELOG.md +31 -2
  3. package/docs/changelog.md +211 -0
  4. package/package.json +1 -1
  5. package/src/forge/_generated/releaseManifest.json +1 -1
  6. package/src/forge/_generated/releaseManifest.ts +3 -3
  7. package/src/forge/cli/auth.ts +1 -0
  8. package/src/forge/cli/commands.ts +13 -0
  9. package/src/forge/cli/deploy.ts +109 -18
  10. package/src/forge/cli/dev.ts +176 -10
  11. package/src/forge/cli/field-test.ts +198 -13
  12. package/src/forge/cli/main.ts +16 -5
  13. package/src/forge/cli/new.ts +2 -1
  14. package/src/forge/cli/output.ts +9 -0
  15. package/src/forge/cli/parse.ts +95 -12
  16. package/src/forge/cli/run.ts +1 -0
  17. package/src/forge/cli/seed.ts +581 -0
  18. package/src/forge/cli/workos.ts +349 -16
  19. package/src/forge/compiler/agent-contract/build.ts +58 -0
  20. package/src/forge/compiler/data-graph/build.ts +29 -1
  21. package/src/forge/compiler/diagnostics/codes.ts +2 -0
  22. package/src/forge/compiler/diagnostics/create.ts +7 -0
  23. package/src/forge/compiler/integration/add.ts +305 -5
  24. package/src/forge/compiler/integration/templates/workos.ts +51 -2
  25. package/src/forge/compiler/orchestrator/plan.ts +2 -0
  26. package/src/forge/make/index.ts +2 -0
  27. package/src/forge/make/templates.ts +58 -4
  28. package/src/forge/runtime/external/bridge.ts +14 -0
  29. package/src/forge/server.ts +59 -9
  30. package/src/forge/ui/index.ts +643 -25
  31. package/src/forge/ui/types.ts +2 -1
  32. package/src/forge/version.ts +1 -1
  33. package/templates/agent-workroom/web/index.html +1 -0
  34. package/templates/agent-workroom/web/src/lib/forge.ts +9 -2
  35. package/templates/agent-workroom/web/vite.config.ts +36 -0
  36. package/templates/b2b-support-web/web/app/page.tsx +2 -2
  37. package/templates/b2b-support-web/web/lib/forge.ts +9 -2
  38. package/templates/b2b-support-web/web/next.config.ts +24 -0
  39. package/templates/minimal-web/web/index.html +1 -0
  40. package/templates/minimal-web/web/src/App.tsx +12 -6
  41. package/templates/minimal-web/web/src/lib/forge.ts +9 -2
  42. package/templates/minimal-web/web/src/styles.css +34 -0
  43. package/templates/minimal-web/web/vite.config.ts +36 -0
  44. package/templates/nuxt-web/web/app.vue +1 -1
  45. package/templates/vendor-access/.vscode/settings.json +14 -0
  46. package/templates/vendor-access/README.md +30 -0
  47. package/templates/vendor-access/forge.config.ts +3 -0
  48. package/templates/vendor-access/package.json +34 -0
  49. package/templates/vendor-access/src/commands/addEvidence.ts +42 -0
  50. package/templates/vendor-access/src/commands/approveAccessRequest.ts +43 -0
  51. package/templates/vendor-access/src/commands/createAccessRequest.ts +49 -0
  52. package/templates/vendor-access/src/commands/seedVendorAccessDemo.ts +200 -0
  53. package/templates/vendor-access/src/forge/schema.ts +74 -0
  54. package/templates/vendor-access/src/policies.ts +11 -0
  55. package/templates/vendor-access/src/queries/listVendorAccessDashboard.ts +24 -0
  56. package/templates/vendor-access/src/queries/liveVendorAccessDashboard.ts +24 -0
  57. package/templates/vendor-access/tsconfig.json +17 -0
  58. package/templates/vendor-access/web/index.html +13 -0
  59. package/templates/vendor-access/web/package.json +21 -0
  60. package/templates/vendor-access/web/src/App.tsx +573 -0
  61. package/templates/vendor-access/web/src/lib/forge.ts +20 -0
  62. package/templates/vendor-access/web/src/main.tsx +205 -0
  63. package/templates/vendor-access/web/src/styles.css +682 -0
  64. package/templates/vendor-access/web/tsconfig.json +18 -0
  65. package/templates/vendor-access/web/vite.config.ts +36 -0
package/AGENTS.md CHANGED
@@ -1,4 +1,4 @@
1
- // @forge-generated generator=0.1.0-alpha.41 input=472a35507fac4f297d64b66cb443aa712ceb113986ac03317278c6464c17cdd4 content=721818a6f9a664aa898092d4aa5cd68cbbd8ad6e150c7d3ad3ef785a2e3fcf53
1
+ // @forge-generated generator=0.1.0-alpha.42 input=f3055b7336a86e156b40c397f3a3f3a734682594a2206baf8063ffd9a40aa6b0 content=721818a6f9a664aa898092d4aa5cd68cbbd8ad6e150c7d3ad3ef785a2e3fcf53
2
2
  # AGENTS.md
3
3
 
4
4
  <!-- forge-generated:start -->
package/CHANGELOG.md CHANGED
@@ -1,5 +1,36 @@
1
1
  # forgeos
2
2
 
3
+ ## 0.1.0-alpha.42
4
+
5
+ ### Patch Changes
6
+
7
+ - Make the ForgeOS production-like golden path explicit and verifiable.
8
+
9
+ - Add `forge field-test run --realistic` as the compact app validation path
10
+ for runtime, auth, and UI probes, defaulting to the WorkOS-backed
11
+ `vendor-access` flow when no template/auth override is provided.
12
+ - Add `forge deploy package --target docker` as the user-facing production
13
+ packaging command while keeping `forge deploy render docker` compatible.
14
+ - Add `forge workos prove --file workos-seed.yml --json` as a no-dashboard
15
+ aggregate proof for WorkOS/AuthKit/FGA/seed readiness, with `--real`
16
+ applying hosted setup through the existing WorkOS CLI integration.
17
+ - Promote `vendor-access` into a production-shaped field-test template with
18
+ deterministic all-tenant seeding, local identity profiles, WorkOS-style
19
+ permissions, auth metadata, UI scenarios, multi-tenant domain probes, and
20
+ deploy-readiness evidence.
21
+ - Tighten `forge field-test report` and `forge deploy check --production` so
22
+ they require concrete runtime, auth setup, auth metadata, UI, UI
23
+ ergonomics, seed readiness, and tenant-isolation evidence before reporting
24
+ deploy readiness.
25
+ - Improve UI ergonomics and browser probe diagnostics for local-vs-production
26
+ auth boundaries, seeded first-run state, policy denials, raw runtime errors,
27
+ and product surfaces that expose framework/demo internals too prominently.
28
+ - Add `forge seed status/dev/reset`, all-tenant seed startup support through
29
+ `forge dev --seed --all-tenants`, and seed readiness evidence in dev and
30
+ field-test summaries.
31
+ - Update templates, docs, and tests around the new `create app -> add auth ->
32
+ field-test -> deploy` path.
33
+
3
34
  ## 0.1.0-alpha.41
4
35
 
5
36
  ### Patch Changes
@@ -194,8 +225,6 @@
194
225
  - Expand capability-map table detection for aliased `ctx.db` usage.
195
226
  - Wait through short-lived DeltaDB writer locks before reporting `FORGE_DELTA_BUSY`.
196
227
 
197
- ## Unreleased
198
-
199
228
  ## 0.1.0-alpha.25
200
229
 
201
230
  ### Patch Changes
package/docs/changelog.md CHANGED
@@ -6,6 +6,217 @@ The canonical source file in the repository is `CHANGELOG.md`.
6
6
 
7
7
  ## Unreleased
8
8
 
9
+ ## 0.1.0-alpha.42
10
+
11
+ - Added the golden-path CLI alias `forge field-test run --realistic`, which
12
+ enables runtime, auth, and UI probes together and defaults to the
13
+ WorkOS-backed `vendor-access` path when no template/auth override is
14
+ provided.
15
+ - Added `forge deploy package --target docker` as the user-facing production
16
+ packaging command while keeping `forge deploy render docker` compatible; the
17
+ generated production README and deploy plan now point at `package`.
18
+ - Added `forge workos prove --file workos-seed.yml --json` as an aggregate
19
+ no-dashboard proof for WorkOS/AuthKit/FGA/seed readiness, with `--real`
20
+ applying hosted setup through the existing WorkOS CLI integration.
21
+ - `forge field-test report` now requires zero UI ergonomics warnings before
22
+ marking a UI-probed report ready for deploy checks, so product-surface
23
+ problems like demo copy, raw fetch errors, or exposed dev diagnostics cannot
24
+ pass as production-ready evidence.
25
+ - `forge inspect ui --ergonomics` now warns when a production-auth/WorkOS app
26
+ exposes local persona or dev-auth controls without explicitly separating
27
+ them as local development mode, reducing confusion between mock identity and
28
+ real AuthKit/OIDC auth.
29
+ - UI scenarios now support a `selectOption` step and the `vendor-access`
30
+ template generates browser scenarios for local sign-in, requester approval
31
+ denial, first-run seeded vendor data, and seed/reset controls, so field tests
32
+ can cover role-specific product flows instead of only loading `/`.
33
+ - `forge field-test report` now treats those `vendor-access` UI scenarios as
34
+ deploy-readiness evidence, requiring local sign-in, seeded-data,
35
+ requester-denied, and seed-control scenario names whenever UI probes run for
36
+ the template.
37
+ - `forge inspect ui --ergonomics` now warns with
38
+ `FORGE_UI_AUTO_SEED_RECOVERY_MISSING` when demo/sample seed commands exist
39
+ but the frontend does not appear to auto-recover an empty first-run
40
+ workspace, catching apps that open on an unseeded or broken-looking state.
41
+ - `forge ui doctor` and UI scenario runs now resolve Playwright from the app or
42
+ `web/` package root, infer npm/pnpm/bun/yarn setup commands from lockfiles,
43
+ and distinguish missing installs from missing Playwright dependencies instead
44
+ of always suggesting Bun commands.
45
+ - `forge field-test report` now treats `vendor-access` seed readiness as
46
+ deploy-ready only when `seed status` proves `autoSeedMode: "all-tenants"`,
47
+ catching regressions where domain probes pass but `npm run dev` would still
48
+ warm only the default tenant.
49
+ - `forge seed dev --all-tenants` and `forge seed reset --all-tenants` now
50
+ preserve successful per-tenant warnings in the aggregate `diagnostics`
51
+ payload, deduplicating repeated warning codes/messages while keeping full
52
+ per-tenant diagnostics under `tenantRuns`.
53
+ - `forge seed status` now warns with `FORGE_SEED_DEV_PARTIAL_TENANTS` when an
54
+ app exposes multiple local tenant/persona profiles but `npm run dev` only
55
+ uses `forge dev --seed` without `--all-tenants`, and it promotes
56
+ `forge dev --seed --all-tenants` as the first empty-workspace recovery.
57
+ - `forge dev --seed` startup summaries now surface seed warnings even when the
58
+ seed command itself succeeds, so partial multi-tenant seeding is visible in
59
+ the first dev-server payload and human terminal output.
60
+ - `forge seed status --json`, `forge dev --seed --json`, and field-test
61
+ reports now expose `autoSeedMode` (`none`, `default-tenant`, or
62
+ `all-tenants`) alongside the compatibility booleans `autoSeedOnDev` and
63
+ `autoSeedAllTenantsOnDev`, making it obvious when `npm run dev` warms every
64
+ discovered local tenant/persona instead of only the default tenant.
65
+ - The `vendor-access` starter now runs `forge dev --seed --all-tenants` from
66
+ `npm run dev`, so Acme and Globex local workspaces are warmed up by default
67
+ instead of leaving secondary tenant views empty until manual seeding.
68
+ - Human `forge dev --seed --all-tenants` startup output now lists per-tenant
69
+ seed results with labels and HTTP status, matching the structured startup
70
+ JSON evidence without requiring agents to rerun with `--json`.
71
+ - `forge inspect ui --ergonomics` now warns when a WorkOS/AuthKit frontend is
72
+ mounted but does not expose normalized `/session` claims or proxy the AuthKit
73
+ login/callback/logout/session routes, catching half-wired production auth
74
+ flows before browser testing.
75
+ - `forge inspect ui --ergonomics` now warns when Forge/WorkOS operational
76
+ diagnostics such as env names, seed files, claims dumps, capability maps, or
77
+ policy proofs appear in the primary product surface instead of a collapsible
78
+ developer panel.
79
+ - `forge inspect ui --ergonomics` now requires WorkOS-authenticated apps to
80
+ expose a visible WorkOS/AuthKit sign-in/sign-out path, `/login`/`/logout`
81
+ link, or AuthKit signIn/signOut call, so local-persona buttons or
82
+ organization/session copy alone no longer count as a real WorkOS auth flow.
83
+ - `forge workos seed --file ... --json` now writes a local
84
+ `.workos-seed-state.json` after successful hosted seed application or known
85
+ duplicate-resource/idempotent WorkOS responses, giving agents a stable,
86
+ secret-free proof that the seed was applied or already present.
87
+ - `forge workos doctor --json` and `forge workos seed --dry-run --json` now
88
+ read `.workos-seed-state.json`, report whether it matches the current
89
+ `workos-seed.yml`, and surface seed drift before an agent reapplies hosted
90
+ WorkOS changes.
91
+ - `forge workos setup --json` now surfaces the same seed-state summary at the
92
+ top level for dry-runs and real no-dashboard setup runs, so agents can see
93
+ hosted seed drift without digging through nested seed payloads.
94
+ - Human `forge workos setup --real` output now reports whether
95
+ `.workos-seed-state.json` matches the current seed after hosted setup,
96
+ keeping text-mode CLI handoffs aligned with JSON evidence.
97
+ - `forge workos doctor --json` now includes structured WorkOS coverage data
98
+ (`seed`, `seedState`, active policy permissions, expected resource types, and
99
+ missing/unused seed coverage) so agents can verify auth setup without parsing
100
+ human check text.
101
+ - `forge seed status --json` now reports seed readiness, including the selected
102
+ seed command, default local dev-auth headers, whether `npm run dev` already
103
+ auto-seeds through `forge dev --seed`, and exact recovery commands for empty
104
+ workspaces.
105
+ - `forge seed status --json` now discovers local frontend tenant/persona
106
+ profiles and emits per-tenant `forge seed dev`/`forge seed reset` commands,
107
+ making multi-tenant field apps easier to warm up and test without guessing
108
+ Acme/Globex headers.
109
+ - `forge seed dev --all-tenants` and `forge seed reset --all-tenants` now run
110
+ the selected seed command against every discovered local tenant/persona,
111
+ returning per-tenant request/response evidence for multi-tenant field tests.
112
+ - The `vendor-access` field-test runtime probe now uses
113
+ `forge seed dev --all-tenants` and accepts that single bulk-seed proof as the
114
+ deploy-readiness seed evidence, while still accepting older Acme/Globex
115
+ per-tenant report artifacts.
116
+ - `forge dev --seed --all-tenants` now forwards the discovered local
117
+ tenant/persona set into startup seeding and includes per-tenant seed run
118
+ evidence in the dev startup JSON summary.
119
+ - Generated-drift JSON now includes a concurrency note and normalized
120
+ sequential `generate`/`generate --check` commands, so agents do not mistake a
121
+ parallel `forge generate`/`forge generate --check` race for a persistent
122
+ generator defect.
123
+ - `forge dev --seed` startup output now includes the same seed readiness block
124
+ in `summary.seed.readiness`, so Studio and coding agents can diagnose empty
125
+ workspaces from the first dev-server payload.
126
+ - `forge seed` now normalizes recovery and diagnostic commands for the current
127
+ workspace, so framework checkouts show `node bin/forge.mjs ...` while
128
+ generated apps continue to show `forge ...`.
129
+ - `forge seed status` now recognizes auto-seeded dev scripts whether they call
130
+ `forge dev --seed`, `npm run forge -- dev --seed`, or the local
131
+ `bin/forge.mjs dev --seed` entrypoint.
132
+ - Human `forge seed` output now prints an `empty workspace recovery` section
133
+ with the same workspace-normalized commands exposed in JSON readiness.
134
+ - `forge field-test report` now treats `vendor-access` seed readiness as
135
+ deploy-check evidence, so reports must prove the app exposes deterministic
136
+ empty-workspace recovery commands before they are marked deploy-ready.
137
+ - Cleaned the `vendor-access` starter's local identity naming so the app uses
138
+ `LocalPersona`/workspace seed terminology instead of demo-auth terminology in
139
+ its authored frontend code and audit seed copy.
140
+ - `forge add auth workos` now treats already-declared WorkOS packages as an
141
+ idempotent no-op for package installation, emits
142
+ `FORGE_ADD_PACKAGE_ALREADY_DECLARED`, and continues adapter/AuthKit generation
143
+ instead of surfacing a misleading install failure.
144
+ - `forge add auth workos` now generates a browser session helper and rewrites
145
+ the `vendor-access` WorkOS shell to read normalized `/session` claims for
146
+ organization, role, and permissions. Vite/Next templates now proxy `/session`
147
+ alongside `/login`, `/callback`, and `/logout`.
148
+ - `forge workos doctor` now verifies the generated browser AuthKit bridge
149
+ exposes `useForgeWorkOSSession` and that web dev config proxies `/session`
150
+ with the AuthKit login/logout/callback routes, catching half-wired WorkOS
151
+ apps before browser testing.
152
+ - `forge workos doctor` and `forge workos seed` now report unused seed
153
+ permissions against the app's active policy permissions, making generic or
154
+ stale seed files visible without blocking intentionally broader seeds.
155
+ - `forge check` now fails fast on `defineTable(..., { id: "text" })` with
156
+ `FORGE_DB_INVALID_ID_FIELD`, before the app reaches confusing SQL/runtime
157
+ primary-key behavior. Omit `id` for generated UUID ids or use `id: "uuid"`.
158
+ - Field-test runtime probes now start `forge dev` with `--port 0` and
159
+ `--web-port 0`, then read the concrete API/web URLs from startup JSON instead
160
+ of pre-reserving ports in the harness.
161
+ - Hardened `forge inspect ui --ergonomics` so generated apps with runtime
162
+ commands/policies warn when they lack an obvious primary workflow action,
163
+ workflow navigation, permission feedback, or when ForgeOS/demo copy appears
164
+ in the main product surface instead of a collapsible dev panel.
165
+ - Tightened seed UX auditing so command names such as `seedVendorAccessDemo`
166
+ no longer count as a visible first-run recovery path; apps with seed commands
167
+ now need an actual seed/reset/status control or tenant-data recovery copy.
168
+ - Expanded UI ergonomics checks to catch `powered by ForgeOS` and
169
+ `ForgeOS ... demo` copy on the product surface, and cleaned starter template
170
+ first screens so generated apps open as useful products rather than framework
171
+ advertisements.
172
+ - Reduced UI auth-flow false positives: apps that merely support `jwt`/`oidc`
173
+ modes no longer look production-authenticated unless they set an active
174
+ production auth mode, use tenant-scoped data, or include a WorkOS integration.
175
+ - Updated the `minimal-web` starter with real workflow navigation and section
176
+ anchors so new apps no longer start with a UI ergonomics navigation warning.
177
+ - Made the `vendor-access` starter run `forge dev --seed` by default, with
178
+ `dev:no-seed` available for empty-state debugging.
179
+ - Fixed the `vendor-access` README quickstart so it tells users to run the
180
+ auto-seeded `npm run dev` script instead of appending a duplicate `--seed`
181
+ flag.
182
+ - Tightened the `vendor-access` dashboard queries so the root organization
183
+ record is loaded by the active tenant id instead of listing every demo
184
+ organization in the workspace.
185
+ - Strengthened the `vendor-access` field-test probes to fail when the
186
+ dashboard payload leaks the other tenant's root organization record, not just
187
+ the other tenant's vendors.
188
+ - Made the `vendor-access` starter retry automatic demo seeding after transient
189
+ frontend/API failures instead of marking a tenant as seeded before the seed
190
+ command succeeds.
191
+ - Hardened `forge field-test report` production evidence so
192
+ `readyForDeployCheck` requires concrete runtime health/entries probes, auth
193
+ setup commands, auth metadata endpoint probes, a web UI probe, and UI
194
+ ergonomics evidence instead of trusting enabled probe flags alone.
195
+ - Aligned `forge deploy check --production` with the stricter field-test
196
+ evidence contract, including explicit missing-evidence messages for runtime,
197
+ auth setup, auth metadata, UI, and ergonomics probes.
198
+ - Improved `forge add auth workos` for the `vendor-access` starter so real
199
+ WorkOS browser config bypasses the local identity selector and renders an
200
+ AuthKit-backed app shell, while retaining explicit local identity mode when
201
+ WorkOS env vars are absent.
202
+ - Simplified the `vendor-access` local login surface to a persona picker plus
203
+ local-mode continue action instead of a fake email/password form, making the
204
+ boundary between dev-header simulation and real WorkOS/AuthKit login clearer.
205
+ - Tightened UI ergonomics around auth demos: `forge inspect ui --ergonomics`
206
+ now warns on demo-login language and fake password-style auth forms in the
207
+ primary app shell, and the `vendor-access` template labels local identity and
208
+ workspace seed controls without fake credential copy.
209
+ - Field-test reports created with `--ui-probes` now include UI ergonomics audit
210
+ evidence, and `forge deploy check --production` requires that evidence while
211
+ surfacing UX warnings separately from runtime/auth failures.
212
+ - Field-test UI probes now reject obvious broken first-screen HTML such as
213
+ `Failed to fetch`, `No organization seeded`, and raw Forge runtime errors
214
+ instead of treating any reachable Vite/Next/Nuxt shell as product evidence.
215
+ - `forge field-test report` now requires the `vendor-access` app's concrete
216
+ multi-tenant domain probes before marking field-test evidence deploy-ready:
217
+ seed Acme/Globex, query both tenants, allow owner approval, deny requester
218
+ approval, and deny cross-tenant approval.
219
+
9
220
  ## 0.1.0-alpha.41
10
221
 
11
222
  - Fixed package install detection for npm workspace apps that hoist frontend
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "forgeos",
3
- "version": "0.1.0-alpha.41",
3
+ "version": "0.1.0-alpha.42",
4
4
  "description": "Agent-native application framework and compiler for building Forge apps without a mandatory dashboard.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -1 +1 @@
1
- {"defaultProvider":"local","diagnostics":[],"env":{"deployEnv":"FORGE_DEPLOY_ENV","deployId":"FORGE_DEPLOY_ID","publicReleaseId":"NEXT_PUBLIC_FORGE_RELEASE_ID","releaseId":"FORGE_RELEASE_ID"},"gitSha":"unknown","optionalProviders":["local","sentry-compatible","sentry","glitchtip","bugsink","otel","custom"],"packageName":"forgeos","packageVersion":"0.1.0-alpha.41","releaseId":"forgeos@0.1.0-alpha.41+unknown","schemaVersion":"0.1.0"}
1
+ {"defaultProvider":"local","diagnostics":[],"env":{"deployEnv":"FORGE_DEPLOY_ENV","deployId":"FORGE_DEPLOY_ID","publicReleaseId":"NEXT_PUBLIC_FORGE_RELEASE_ID","releaseId":"FORGE_RELEASE_ID"},"gitSha":"unknown","optionalProviders":["local","sentry-compatible","sentry","glitchtip","bugsink","otel","custom"],"packageName":"forgeos","packageVersion":"0.1.0-alpha.42","releaseId":"forgeos@0.1.0-alpha.42+unknown","schemaVersion":"0.1.0"}
@@ -1,4 +1,4 @@
1
- // @forge-generated generator=0.1.0-alpha.41 input=472a35507fac4f297d64b66cb443aa712ceb113986ac03317278c6464c17cdd4 content=ba31c1269d2cbbe1fdb5c6dc20de16dabe1afbe97d1af2a72346806ad2d17e16
1
+ // @forge-generated generator=0.1.0-alpha.42 input=f3055b7336a86e156b40c397f3a3f3a734682594a2206baf8063ffd9a40aa6b0 content=06dbda53e7983dbe23a758ca32f8367e665ec0a6af4cfe09dd383a8537d8734e
2
2
  export const releaseManifest = {
3
3
  "defaultProvider": "local",
4
4
  "diagnostics": [],
@@ -19,7 +19,7 @@ export const releaseManifest = {
19
19
  "custom"
20
20
  ],
21
21
  "packageName": "forgeos",
22
- "packageVersion": "0.1.0-alpha.41",
23
- "releaseId": "forgeos@0.1.0-alpha.41+unknown",
22
+ "packageVersion": "0.1.0-alpha.42",
23
+ "releaseId": "forgeos@0.1.0-alpha.42+unknown",
24
24
  "schemaVersion": "0.1.0"
25
25
  } as const;
@@ -258,6 +258,7 @@ function buildMultiTenantProof(workspaceRoot: string, workos: ReturnType<typeof
258
258
  nextActions: [
259
259
  "forge workos doctor --json",
260
260
  "forge workos seed --file workos-seed.yml --dry-run --json",
261
+ "forge workos prove --file workos-seed.yml --json",
261
262
  "run an HTTP E2E with Acme and Globex tokens before production",
262
263
  ],
263
264
  });
@@ -224,6 +224,11 @@ import {
224
224
  formatFieldTestJson,
225
225
  runFieldTestCommand,
226
226
  } from "./field-test.ts";
227
+ import {
228
+ formatSeedHuman,
229
+ formatSeedJson,
230
+ runSeedCommand,
231
+ } from "./seed.ts";
227
232
  import {
228
233
  formatLastHuman,
229
234
  formatLastJson,
@@ -1966,6 +1971,11 @@ export async function executeCommand(command: ForgeCommand): Promise<number> {
1966
1971
  process.stdout.write(command.json ? formatFieldTestJson(result) : formatFieldTestHuman(result));
1967
1972
  return result.exitCode;
1968
1973
  }
1974
+ case "seed": {
1975
+ const result = await runSeedCommand(command);
1976
+ process.stdout.write(command.json ? formatSeedJson(result) : formatSeedHuman(result));
1977
+ return result.exitCode;
1978
+ }
1969
1979
  case "rls": {
1970
1980
  const result = await runRlsCommand(command);
1971
1981
  if (command.json) {
@@ -2525,6 +2535,9 @@ export async function executeCommand(command: ForgeCommand): Promise<number> {
2525
2535
  envFile: command.envFile,
2526
2536
  skipStartupConsole: command.skipStartupConsole,
2527
2537
  detach: command.detach,
2538
+ seed: command.seed,
2539
+ seedCommand: command.seedCommand,
2540
+ seedAllTenants: command.seedAllTenants,
2528
2541
  lifecycle: command.lifecycle,
2529
2542
  });
2530
2543
  return result.exitCode;
@@ -13,7 +13,7 @@ import { runAuthCommand } from "./auth.ts";
13
13
  import { runAuthMdCommand } from "./authmd.ts";
14
14
  import { runWorkOSCommand } from "./workos.ts";
15
15
 
16
- export type DeploySubcommand = "plan" | "check" | "render" | "verify";
16
+ export type DeploySubcommand = "plan" | "check" | "render" | "package" | "verify";
17
17
  export type DeployTarget = "docker" | "forge-cloud";
18
18
 
19
19
  export interface DeployCommandOptions {
@@ -119,25 +119,104 @@ function fieldTestReportCandidates(workspaceRoot: string): Array<{ path: string;
119
119
  });
120
120
  }
121
121
 
122
+ const FIELD_TEST_PRODUCTION_COMMAND = "forge field-test run --realistic --json";
123
+
122
124
  function summarizeFieldTestReport(data: Record<string, unknown>) {
123
125
  const results = Array.isArray(data.results) ? data.results as Array<Record<string, unknown>> : [];
124
126
  const failed = results.filter((result) => result.ok === false && result.skipped !== true);
125
127
  const skipped = results.filter((result) => result.skipped === true);
128
+ const executed = results.filter((result) => result.skipped !== true);
129
+ const topLevelSteps = results.flatMap((result) =>
130
+ Array.isArray(result.steps) ? result.steps as Array<Record<string, unknown>> : [],
131
+ );
126
132
  const runtimeSteps = results.flatMap((result) => {
127
133
  const runtime = result.runtime && typeof result.runtime === "object"
128
134
  ? result.runtime as Record<string, unknown>
129
135
  : {};
130
136
  return Array.isArray(runtime.steps) ? runtime.steps as Array<Record<string, unknown>> : [];
131
137
  });
138
+ const commandOf = (step: unknown): string =>
139
+ step && typeof step === "object" && typeof (step as { command?: unknown }).command === "string"
140
+ ? (step as { command: string }).command
141
+ : "";
142
+ const okStep = (step: unknown): boolean =>
143
+ Boolean(step && typeof step === "object" && (step as { ok?: unknown }).ok === true);
144
+ const hasOkRuntimeCommand = (pattern: RegExp): boolean =>
145
+ runtimeSteps.some((step) => okStep(step) && pattern.test(commandOf(step)));
146
+ const hasOkTopLevelCommand = (pattern: RegExp): boolean =>
147
+ topLevelSteps.some((step) => okStep(step) && pattern.test(commandOf(step)));
148
+ const authSetupProbeSteps = topLevelSteps.filter((step) =>
149
+ /forge\s+(?:--\s+)?(add\s+auth\s+workos|authmd\s+generate|authmd\s+check|workos\s+doctor|workos\s+seed|workos\s+prove|auth\s+prove)/.test(commandOf(step)),
150
+ );
151
+ const authMetadataProbeSteps = runtimeSteps.filter((step) =>
152
+ /^(HEAD|GET)\s+https?:\/\/[^/]+\/(auth\.md|\.well-known\/oauth-protected-resource)\b/i.test(commandOf(step)),
153
+ );
154
+ const uiErgonomicsResults = results
155
+ .map((result) => result.uiErgonomics)
156
+ .filter((value): value is Record<string, unknown> => Boolean(value && typeof value === "object"));
157
+ const uiErgonomicsWarnings = uiErgonomicsResults.reduce((total, result) =>
158
+ total + (typeof result.warnings === "number" ? result.warnings : 0), 0);
159
+ const uiErgonomicsErrors = uiErgonomicsResults.reduce((total, result) =>
160
+ total + (typeof result.errors === "number" ? result.errors : 0), 0);
161
+ const runtimeProbes = data.runtimeProbes === true;
162
+ const authProbes = data.authProbes === true;
163
+ const uiProbes = data.uiProbes === true;
164
+ const uiProbeSteps = runtimeSteps.filter((step) =>
165
+ /^GET\s+https?:\/\/[^/]+\/$/i.test(commandOf(step)),
166
+ );
167
+ const uiErgonomics = uiProbes !== true || (executed.length > 0 && uiErgonomicsResults.length === executed.length);
168
+ const runtimeHealthEvidence = !runtimeProbes || hasOkRuntimeCommand(/\bGET\s+.*\/health\b/i);
169
+ const runtimeEntriesEvidence = !runtimeProbes || hasOkRuntimeCommand(/\bGET\s+.*\/entries\b/i);
170
+ const authSetupEvidence = !authProbes || [
171
+ /forge\s+(?:--\s+)?add\s+auth\s+workos\b/,
172
+ /forge\s+(?:--\s+)?authmd\s+generate\b/,
173
+ /forge\s+(?:--\s+)?authmd\s+check\b/,
174
+ /forge\s+(?:--\s+)?workos\s+doctor\b/,
175
+ /forge\s+(?:--\s+)?workos\s+seed\b/,
176
+ /forge\s+(?:--\s+)?workos\s+prove\b/,
177
+ /forge\s+(?:--\s+)?auth\s+prove\b/,
178
+ ].every((pattern) => hasOkTopLevelCommand(pattern));
179
+ const authMetadataEvidence = !authProbes || [
180
+ /^HEAD\s+.*\/auth\.md\b/i,
181
+ /^GET\s+.*\/auth\.md\b/i,
182
+ /^HEAD\s+.*\/\.well-known\/oauth-protected-resource\b/i,
183
+ /^GET\s+.*\/\.well-known\/oauth-protected-resource\b/i,
184
+ ].every((pattern) => hasOkRuntimeCommand(pattern));
185
+ const uiProbeEvidence = !uiProbes || uiProbeSteps.some((step) => okStep(step));
186
+ const productionEvidenceMissing = [
187
+ ...(data.ok !== true ? ["passing field-test report"] : []),
188
+ ...(!runtimeProbes ? ["runtime probes"] : []),
189
+ ...(!authProbes ? ["auth probes"] : []),
190
+ ...(!uiProbes ? ["ui probes"] : []),
191
+ ...(!runtimeHealthEvidence ? ["runtime health probe"] : []),
192
+ ...(!runtimeEntriesEvidence ? ["runtime entries probe"] : []),
193
+ ...(!authSetupEvidence ? ["auth setup probes"] : []),
194
+ ...(!authMetadataEvidence ? ["auth metadata endpoint probes"] : []),
195
+ ...(!uiProbeEvidence ? ["web UI probe"] : []),
196
+ ...(!uiErgonomics ? ["UI ergonomics audit"] : []),
197
+ ...(uiErgonomicsErrors > 0 ? ["zero UI ergonomics errors"] : []),
198
+ ...(failed.length > 0 ? ["zero failed cases"] : []),
199
+ ];
132
200
  return {
133
201
  ok: data.ok === true,
134
202
  cases: results.length,
135
203
  passed: results.filter((result) => result.ok === true && result.skipped !== true).length,
136
204
  failed: failed.length,
137
205
  skipped: skipped.length,
138
- runtimeProbes: data.runtimeProbes === true,
139
- authProbes: data.authProbes === true,
206
+ runtimeProbes,
207
+ authProbes,
208
+ uiProbes,
209
+ uiErgonomics,
210
+ uiErgonomicsWarnings,
211
+ uiErgonomicsErrors,
140
212
  runtimeProbeSteps: runtimeSteps.length,
213
+ authSetupProbeSteps: authSetupProbeSteps.length,
214
+ authMetadataProbeSteps: authMetadataProbeSteps.length,
215
+ uiProbeSteps: uiProbeSteps.length,
216
+ productionEvidence: {
217
+ readyForDeployCheck: productionEvidenceMissing.length === 0,
218
+ missing: productionEvidenceMissing,
219
+ },
141
220
  };
142
221
  }
143
222
 
@@ -431,13 +510,13 @@ function databaseReadyCommand(options: DeployCommandOptions): string {
431
510
  if (hasRenderedProductionEnvExample(options.workspaceRoot)) {
432
511
  return "cp deploy/.env.production.example deploy/.env.production";
433
512
  }
434
- return "forge deploy render docker";
513
+ return "forge deploy package --target docker";
435
514
  }
436
515
 
437
516
  function renderProductionReadme(): string {
438
517
  return `# ForgeOS Production Deploy
439
518
 
440
- This directory is generated by \`forge deploy render docker\`.
519
+ This directory is generated by \`forge deploy package --target docker\`.
441
520
 
442
521
  ## 1. Prepare production env
443
522
 
@@ -463,7 +542,7 @@ forge generate --check --json
463
542
  forge check --json
464
543
  forge authmd generate --json
465
544
  forge auth prove --scenario multi-tenant --json
466
- forge field-test run --runtime-probes --auth-probes --json
545
+ forge field-test run --realistic --json
467
546
  forge deploy check --production --json
468
547
  \`\`\`
469
548
 
@@ -492,15 +571,15 @@ function buildPlan(options: DeployCommandOptions): DeployCommandResult {
492
571
  "forge deploy check --production --json",
493
572
  "forge auth check --production --json",
494
573
  "forge authmd check --json",
495
- "forge field-test run --runtime-probes --auth-probes --json",
574
+ FIELD_TEST_PRODUCTION_COMMAND,
496
575
  "forge field-test report --json",
497
576
  "forge deploy verify --production --url https://<your-forge-cloud-app> --json",
498
577
  ]
499
578
  : [
500
- "forge deploy render docker",
579
+ "forge deploy package --target docker",
501
580
  "cp deploy/.env.production.example deploy/.env.production",
502
581
  "forge deploy check --production --json",
503
- "forge field-test run --runtime-probes --auth-probes --json",
582
+ FIELD_TEST_PRODUCTION_COMMAND,
504
583
  "docker compose -f deploy/docker-compose.yml up --build",
505
584
  "forge deploy verify --production --url https://app.example.com --json",
506
585
  ];
@@ -524,7 +603,7 @@ function buildPlan(options: DeployCommandOptions): DeployCommandResult {
524
603
  "production database env evidence is present",
525
604
  "required secret names are present",
526
605
  "auth.md and protected-resource metadata are published",
527
- "field-test report exists with runtime/auth probes",
606
+ "field-test report exists with runtime/auth/UI probes",
528
607
  "runtime /health responds",
529
608
  "tenant and policy proof is run before public traffic",
530
609
  ],
@@ -693,20 +772,32 @@ async function buildChecks(options: DeployCommandOptions): Promise<DeployCommand
693
772
  const fieldReports = fieldTestReportCandidates(options.workspaceRoot);
694
773
  const latestFieldReport = fieldReports[0];
695
774
  const fieldSummary = latestFieldReport ? summarizeFieldTestReport(latestFieldReport.data) : null;
775
+ const fieldReportComplete = Boolean(fieldSummary?.productionEvidence.readyForDeployCheck);
776
+ const fieldReportMissing = fieldSummary?.productionEvidence.missing ?? [];
696
777
  checks.push({
697
778
  name: "field-test-report",
698
- ok: Boolean(fieldSummary?.ok && fieldSummary.runtimeProbes && fieldSummary.authProbes),
779
+ ok: fieldReportComplete,
699
780
  severity: options.production ? "error" : "warning",
700
781
  message: fieldSummary?.ok
701
- ? fieldSummary.runtimeProbes && fieldSummary.authProbes
702
- ? `field-test report ${latestFieldReport?.path} passed with runtime and auth probes`
703
- : `field-test report ${latestFieldReport?.path} passed but is missing runtime/auth probes`
782
+ ? fieldReportComplete
783
+ ? `field-test report ${latestFieldReport?.path} passed with concrete runtime, auth, metadata, UI, and ergonomics evidence`
784
+ : `field-test report ${latestFieldReport?.path} passed but is missing deploy evidence: ${fieldReportMissing.join(", ")}`
704
785
  : latestFieldReport
705
786
  ? `field-test report ${latestFieldReport.path} did not pass`
706
- : "no field-test report found; run forge field-test run --runtime-probes --auth-probes --json",
707
- command: "forge field-test run --runtime-probes --auth-probes --json",
787
+ : `no field-test report found; run ${FIELD_TEST_PRODUCTION_COMMAND}`,
788
+ command: FIELD_TEST_PRODUCTION_COMMAND,
708
789
  details: latestFieldReport ? { path: latestFieldReport.path, summary: fieldSummary } : undefined,
709
790
  });
791
+ if (fieldSummary?.uiErgonomicsWarnings) {
792
+ checks.push({
793
+ name: "field-test-ui-ergonomics",
794
+ ok: false,
795
+ severity: "warning",
796
+ message: `field-test UI ergonomics audit reported ${fieldSummary.uiErgonomicsWarnings} warning(s); fix the product surface before treating the app as polished`,
797
+ command: "forge inspect ui --ergonomics --json",
798
+ details: { path: latestFieldReport?.path, summary: fieldSummary },
799
+ });
800
+ }
710
801
  checks.push({
711
802
  name: "frontend-build-script",
712
803
  ok: !readGeneratedJson<FrontendGraph>(options.workspaceRoot, `${GENERATED_DIR}/frontendGraph.json`)?.present || hasScript(options.workspaceRoot, "build") || hasScript(join(options.workspaceRoot, "web"), "build"),
@@ -759,7 +850,7 @@ function renderDocker(options: DeployCommandOptions): DeployCommandResult {
759
850
  schemaVersion: "0.1.0",
760
851
  ok: true,
761
852
  kind: "deploy",
762
- action: "render",
853
+ action: options.subcommand,
763
854
  target: options.target,
764
855
  production: options.production,
765
856
  checks: [],
@@ -866,7 +957,7 @@ async function verifyUrl(options: DeployCommandOptions): Promise<DeployCommandRe
866
957
  export async function runDeployCommand(options: DeployCommandOptions): Promise<DeployCommandResult> {
867
958
  if (options.subcommand === "plan") return buildPlan(options);
868
959
  if (options.subcommand === "check") return buildChecks(options);
869
- if (options.subcommand === "render") return renderDocker(options);
960
+ if (options.subcommand === "render" || options.subcommand === "package") return renderDocker(options);
870
961
  return verifyUrl(options);
871
962
  }
872
963