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.
- package/AGENTS.md +1 -1
- package/CHANGELOG.md +31 -2
- package/docs/changelog.md +211 -0
- package/package.json +1 -1
- package/src/forge/_generated/releaseManifest.json +1 -1
- package/src/forge/_generated/releaseManifest.ts +3 -3
- package/src/forge/cli/auth.ts +1 -0
- package/src/forge/cli/commands.ts +13 -0
- package/src/forge/cli/deploy.ts +109 -18
- package/src/forge/cli/dev.ts +176 -10
- package/src/forge/cli/field-test.ts +198 -13
- package/src/forge/cli/main.ts +16 -5
- package/src/forge/cli/new.ts +2 -1
- package/src/forge/cli/output.ts +9 -0
- package/src/forge/cli/parse.ts +95 -12
- package/src/forge/cli/run.ts +1 -0
- package/src/forge/cli/seed.ts +581 -0
- package/src/forge/cli/workos.ts +349 -16
- package/src/forge/compiler/agent-contract/build.ts +58 -0
- package/src/forge/compiler/data-graph/build.ts +29 -1
- package/src/forge/compiler/diagnostics/codes.ts +2 -0
- package/src/forge/compiler/diagnostics/create.ts +7 -0
- package/src/forge/compiler/integration/add.ts +305 -5
- package/src/forge/compiler/integration/templates/workos.ts +51 -2
- package/src/forge/compiler/orchestrator/plan.ts +2 -0
- package/src/forge/make/index.ts +2 -0
- package/src/forge/make/templates.ts +58 -4
- package/src/forge/runtime/external/bridge.ts +14 -0
- package/src/forge/server.ts +59 -9
- package/src/forge/ui/index.ts +643 -25
- package/src/forge/ui/types.ts +2 -1
- package/src/forge/version.ts +1 -1
- package/templates/agent-workroom/web/index.html +1 -0
- package/templates/agent-workroom/web/src/lib/forge.ts +9 -2
- package/templates/agent-workroom/web/vite.config.ts +36 -0
- package/templates/b2b-support-web/web/app/page.tsx +2 -2
- package/templates/b2b-support-web/web/lib/forge.ts +9 -2
- package/templates/b2b-support-web/web/next.config.ts +24 -0
- package/templates/minimal-web/web/index.html +1 -0
- package/templates/minimal-web/web/src/App.tsx +12 -6
- package/templates/minimal-web/web/src/lib/forge.ts +9 -2
- package/templates/minimal-web/web/src/styles.css +34 -0
- package/templates/minimal-web/web/vite.config.ts +36 -0
- package/templates/nuxt-web/web/app.vue +1 -1
- package/templates/vendor-access/.vscode/settings.json +14 -0
- package/templates/vendor-access/README.md +30 -0
- package/templates/vendor-access/forge.config.ts +3 -0
- package/templates/vendor-access/package.json +34 -0
- package/templates/vendor-access/src/commands/addEvidence.ts +42 -0
- package/templates/vendor-access/src/commands/approveAccessRequest.ts +43 -0
- package/templates/vendor-access/src/commands/createAccessRequest.ts +49 -0
- package/templates/vendor-access/src/commands/seedVendorAccessDemo.ts +200 -0
- package/templates/vendor-access/src/forge/schema.ts +74 -0
- package/templates/vendor-access/src/policies.ts +11 -0
- package/templates/vendor-access/src/queries/listVendorAccessDashboard.ts +24 -0
- package/templates/vendor-access/src/queries/liveVendorAccessDashboard.ts +24 -0
- package/templates/vendor-access/tsconfig.json +17 -0
- package/templates/vendor-access/web/index.html +13 -0
- package/templates/vendor-access/web/package.json +21 -0
- package/templates/vendor-access/web/src/App.tsx +573 -0
- package/templates/vendor-access/web/src/lib/forge.ts +20 -0
- package/templates/vendor-access/web/src/main.tsx +205 -0
- package/templates/vendor-access/web/src/styles.css +682 -0
- package/templates/vendor-access/web/tsconfig.json +18 -0
- 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.
|
|
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 +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.
|
|
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.
|
|
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.
|
|
23
|
-
"releaseId": "forgeos@0.1.0-alpha.
|
|
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;
|
package/src/forge/cli/auth.ts
CHANGED
|
@@ -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;
|
package/src/forge/cli/deploy.ts
CHANGED
|
@@ -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
|
|
139
|
-
authProbes
|
|
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
|
|
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
|
|
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 --
|
|
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
|
-
|
|
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
|
|
579
|
+
"forge deploy package --target docker",
|
|
501
580
|
"cp deploy/.env.production.example deploy/.env.production",
|
|
502
581
|
"forge deploy check --production --json",
|
|
503
|
-
|
|
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:
|
|
779
|
+
ok: fieldReportComplete,
|
|
699
780
|
severity: options.production ? "error" : "warning",
|
|
700
781
|
message: fieldSummary?.ok
|
|
701
|
-
?
|
|
702
|
-
? `field-test report ${latestFieldReport?.path} passed with runtime and
|
|
703
|
-
: `field-test report ${latestFieldReport?.path} passed but is missing
|
|
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
|
-
|
|
707
|
-
command:
|
|
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:
|
|
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
|
|