forgeos 0.1.0-alpha.50 → 0.1.0-alpha.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/AGENTS.md CHANGED
@@ -1,4 +1,4 @@
1
- // @forge-generated generator=0.1.0-alpha.50 input=5f918b7dab43b47f2774c505897503c0b5ddc26d4022167410ed9f3b76190ee6 content=721818a6f9a664aa898092d4aa5cd68cbbd8ad6e150c7d3ad3ef785a2e3fcf53
1
+ // @forge-generated generator=0.1.0-alpha.52 input=9a95853ed8e82db41be0b0cc4fc809e0b1c0c12fd1ac024d386bc651a70d965b content=721818a6f9a664aa898092d4aa5cd68cbbd8ad6e150c7d3ad3ef785a2e3fcf53
2
2
  # AGENTS.md
3
3
 
4
4
  <!-- forge-generated:start -->
package/CHANGELOG.md CHANGED
@@ -1,5 +1,42 @@
1
1
  # forgeos
2
2
 
3
+ ## 0.1.0-alpha.52
4
+
5
+ ### Patch Changes
6
+
7
+ - Make WorkOS FGA real-rollout failures produce a concrete operator artifact.
8
+
9
+ - Generated WorkOS FGA setup guides now include an explicit automation
10
+ boundary explaining that ForgeOS derives the graph, syncs resources, and
11
+ proves Authorization API checks, but does not invent unsupported WorkOS
12
+ resource-type creation commands.
13
+ - `forge workos fga sync --real --write --json` now remains useful when the
14
+ WorkOS Authorization API reports missing resource types: the JSON includes
15
+ `setupGuidePath` and the written guide lists the resource types, parents,
16
+ permissions, roles, example external IDs, membership env, and rerun
17
+ commands needed to finish the hosted setup.
18
+
19
+ ## 0.1.0-alpha.51
20
+
21
+ ### Patch Changes
22
+
23
+ - Make the WorkOS FGA production doctor explicit enough for real P2 rollout.
24
+
25
+ - `forge workos fga doctor --real --json` now reports structured readiness
26
+ for the full hosted path: FGA plan, hosted seed evidence, hosted resource
27
+ type/resource sync, `organizationMembershipId` env, real proof state, and
28
+ production readiness.
29
+ - FGA JSON output now includes `membershipEnv`, `seedState`, and `readiness`
30
+ metadata so agents can choose the next command without scraping human text.
31
+ - Hosted FGA setup data now states that WorkOS resource type creation is not
32
+ automated by the WorkOS API/CLI path, while resource sync and authorization
33
+ checks remain ForgeOS-driven after those resource types exist.
34
+ - WorkOS real checks now read `deploy/.env.production` as an explicit deploy
35
+ evidence source, and `forge deploy check --production` runs WorkOS/FGA
36
+ doctors with those values in scope.
37
+ - Human output now distinguishes local FGA planning success from real
38
+ production-gate readiness.
39
+
3
40
  ## 0.1.0-alpha.50
4
41
 
5
42
  ### Patch Changes
package/docs/changelog.md CHANGED
@@ -6,6 +6,33 @@ The canonical source file in the repository is `CHANGELOG.md`.
6
6
 
7
7
  ## Unreleased
8
8
 
9
+ ## 0.1.0-alpha.52
10
+
11
+ - Generated WorkOS FGA setup guides now include an explicit automation boundary
12
+ describing what ForgeOS can automate versus the hosted WorkOS resource-type
13
+ configuration that must exist before real resource sync.
14
+ - `forge workos fga sync --real --write --json` now provides a concrete
15
+ `setupGuidePath` even when real sync fails because hosted WorkOS resource
16
+ types are missing, so agents have a deterministic artifact for the remaining
17
+ setup and rerun commands.
18
+
19
+ ## 0.1.0-alpha.51
20
+
21
+ - `forge workos fga doctor --real --json` now reports a structured readiness
22
+ object for the full hosted FGA path: app-derived plan, hosted seed state,
23
+ real resource sync, membership env for WorkOS access checks, proof state, and
24
+ production readiness.
25
+ - FGA command JSON now includes `membershipEnv`, `seedState`, and `readiness`
26
+ metadata so agents can continue the no-dashboard WorkOS flow deterministically.
27
+ - Hosted FGA setup output now explicitly states that WorkOS resource type
28
+ creation is hosted WorkOS configuration, while ForgeOS can still sync
29
+ resources and run Authorization API checks after those types exist.
30
+ - WorkOS real checks now read `deploy/.env.production` as deploy evidence, and
31
+ `forge deploy check --production` runs WorkOS/FGA doctors with those values
32
+ in scope.
33
+ - Human FGA output now separates local planning success from real production
34
+ gate readiness.
35
+
9
36
  ## 0.1.0-alpha.50
10
37
 
11
38
  - WorkOS hosted setup now includes explicit
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "forgeos",
3
- "version": "0.1.0-alpha.50",
3
+ "version": "0.1.0-alpha.52",
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.50","releaseId":"forgeos@0.1.0-alpha.50+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.52","releaseId":"forgeos@0.1.0-alpha.52+unknown","schemaVersion":"0.1.0"}
@@ -1,4 +1,4 @@
1
- // @forge-generated generator=0.1.0-alpha.50 input=5f918b7dab43b47f2774c505897503c0b5ddc26d4022167410ed9f3b76190ee6 content=5bb2a5849e690e58325fbd495bd3b1ad63a42f77c8c1d06464b64c27f9192c6c
1
+ // @forge-generated generator=0.1.0-alpha.52 input=9a95853ed8e82db41be0b0cc4fc809e0b1c0c12fd1ac024d386bc651a70d965b content=d4d4c9fd5f2fe5a5d3fa127d43487901cf1e68875b7ac99abdfe9a9cc90265ee
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.50",
23
- "releaseId": "forgeos@0.1.0-alpha.50+unknown",
22
+ "packageVersion": "0.1.0-alpha.52",
23
+ "releaseId": "forgeos@0.1.0-alpha.52+unknown",
24
24
  "schemaVersion": "0.1.0"
25
25
  } as const;
@@ -821,13 +821,15 @@ async function buildChecks(options: DeployCommandOptions): Promise<DeployCommand
821
821
  },
822
822
  });
823
823
  if (hasWorkOSIntegration(options.workspaceRoot)) {
824
- const workosDoctor = runWorkOSCommand({
825
- subcommand: "doctor",
826
- workspaceRoot: options.workspaceRoot,
827
- json: true,
828
- yes: false,
829
- dryRun: true,
830
- });
824
+ const workosDoctor = await withDeployEnv(options.workspaceRoot, async () =>
825
+ runWorkOSCommand({
826
+ subcommand: "doctor",
827
+ workspaceRoot: options.workspaceRoot,
828
+ json: true,
829
+ yes: false,
830
+ dryRun: true,
831
+ })
832
+ );
831
833
  checks.push({
832
834
  name: "workos-doctor",
833
835
  ok: workosDoctor.exitCode === 0,
@@ -853,15 +855,17 @@ async function buildChecks(options: DeployCommandOptions): Promise<DeployCommand
853
855
  command: "forge workos prove --real --file workos-seed.yml --json",
854
856
  details: seedState,
855
857
  });
856
- const workosFgaDoctor = runWorkOSCommand({
857
- subcommand: "fga",
858
- fgaAction: "doctor",
859
- workspaceRoot: options.workspaceRoot,
860
- json: true,
861
- yes: false,
862
- dryRun: true,
863
- real: options.production,
864
- });
858
+ const workosFgaDoctor = await withDeployEnv(options.workspaceRoot, async () =>
859
+ runWorkOSCommand({
860
+ subcommand: "fga",
861
+ fgaAction: "doctor",
862
+ workspaceRoot: options.workspaceRoot,
863
+ json: true,
864
+ yes: false,
865
+ dryRun: true,
866
+ real: options.production,
867
+ })
868
+ );
865
869
  checks.push({
866
870
  name: "workos-fga-proof",
867
871
  ok: !options.production || workosFgaDoctor.exitCode === 0,
@@ -324,6 +324,7 @@ function parseEnvText(text: string): Record<string, string> {
324
324
  function readRealEnv(workspaceRoot: string): Record<string, string> {
325
325
  return {
326
326
  ...parseEnvText(readRawText(workspaceRoot, ".env")),
327
+ ...parseEnvText(readRawText(workspaceRoot, "deploy/.env.production")),
327
328
  ...parseEnvText(readRawText(workspaceRoot, ".env.local")),
328
329
  ...Object.fromEntries(
329
330
  Object.entries(process.env)
@@ -677,12 +678,21 @@ export interface WorkOSFgaStateSummary {
677
678
  diagnostics: string[];
678
679
  }
679
680
 
681
+ export interface WorkOSFgaMembershipEnvSummary {
682
+ requiredEnv: string[];
683
+ presentEnv: string[];
684
+ missingEnv: string[];
685
+ jsonEnvPresent: boolean;
686
+ complete: boolean;
687
+ }
688
+
680
689
  export interface WorkOSFgaHostedSetup {
681
690
  requiredResourceTypes: string[];
682
691
  rootResourceType: "organization";
683
692
  missingResourceTypes: string[];
684
693
  requiredMembershipEnv: string[];
685
694
  managedBy: "hosted-workos";
695
+ resourceTypeAutomation: "not-supported-by-workos-api" | "not-needed";
686
696
  cliSupport: "resources-and-checks";
687
697
  sdkSupport: "resources-and-checks";
688
698
  docs: string[];
@@ -710,6 +720,19 @@ export interface WorkOSFgaSetupGuide {
710
720
  unsupportedAutomation: string[];
711
721
  }
712
722
 
723
+ export interface WorkOSFgaReadiness {
724
+ real: boolean;
725
+ planReady: boolean;
726
+ seedReady: boolean;
727
+ resourceTypesConfigured: boolean;
728
+ membershipEnvReady: boolean;
729
+ synced: boolean;
730
+ proved: boolean;
731
+ productionReady: boolean;
732
+ nextCommand: string;
733
+ nextActions: string[];
734
+ }
735
+
713
736
  function slugifyExternalIdPart(value: string): string {
714
737
  return value
715
738
  .trim()
@@ -951,6 +974,24 @@ function fgaMembershipEnvKey(organization: string): string {
951
974
  return `WORKOS_FGA_MEMBERSHIP_${suffix}`;
952
975
  }
953
976
 
977
+ function workOSFgaMembershipEnvSummary(
978
+ workspaceRoot: string,
979
+ organizations: string[],
980
+ ): WorkOSFgaMembershipEnvSummary {
981
+ const env = readRealEnv(workspaceRoot);
982
+ const requiredEnv = organizations.map(fgaMembershipEnvKey);
983
+ const jsonEnvPresent = hasValue(env, "WORKOS_FGA_MEMBERSHIPS_JSON") || hasValue(env, "WORKOS_FGA_TEST_MEMBERSHIPS");
984
+ const presentEnv = requiredEnv.filter((name) => hasValue(env, name));
985
+ const missingEnv = jsonEnvPresent ? [] : requiredEnv.filter((name) => !presentEnv.includes(name));
986
+ return {
987
+ requiredEnv,
988
+ presentEnv,
989
+ missingEnv,
990
+ jsonEnvPresent,
991
+ complete: jsonEnvPresent || missingEnv.length === 0,
992
+ };
993
+ }
994
+
954
995
  function extractMissingWorkOSFgaResourceTypes(data: unknown, manifest?: WorkOSFgaManifest): string[] {
955
996
  const missing = new Set<string>();
956
997
  const add = (value: unknown) => {
@@ -999,6 +1040,7 @@ function workOSFgaHostedSetup(manifest: WorkOSFgaManifest, sdkData?: unknown): W
999
1040
  missingResourceTypes,
1000
1041
  requiredMembershipEnv,
1001
1042
  managedBy: "hosted-workos",
1043
+ resourceTypeAutomation: requiredResourceTypes.length > 0 ? "not-supported-by-workos-api" : "not-needed",
1002
1044
  cliSupport: "resources-and-checks",
1003
1045
  sdkSupport: "resources-and-checks",
1004
1046
  docs: [
@@ -1107,6 +1149,13 @@ function workOSFgaSetupGuide(manifest: WorkOSFgaManifest, hostedSetup: WorkOSFga
1107
1149
  "ForgeOS derived this resource graph from the app contract, policies, and workos-seed.yml.",
1108
1150
  "WorkOS resource type configuration is hosted WorkOS configuration. ForgeOS uses the WorkOS CLI/API or SDK to sync resources and prove authorization checks after those resource types exist.",
1109
1151
  "",
1152
+ "## Automation Boundary",
1153
+ "",
1154
+ "- ForgeOS can derive the FGA graph, generate this setup guide, sync WorkOS FGA resources, and run Authorization API access checks.",
1155
+ "- ForgeOS does not invent WorkOS CLI/API calls for resource type creation. The current public WorkOS automation surface supports resources and checks after resource types exist.",
1156
+ "- Configure each non-organization resource type below in hosted WorkOS, then rerun the real sync/proof commands.",
1157
+ "- The `organization` node is treated as the WorkOS tenant root and is not created as an authorization resource.",
1158
+ "",
1110
1159
  "## Resource Types",
1111
1160
  "",
1112
1161
  ...resourceTypes.flatMap((resourceType) => [
@@ -1179,11 +1228,14 @@ function writeWorkOSFgaSetupGuide(
1179
1228
 
1180
1229
  function fgaData(input: {
1181
1230
  action: WorkOSFgaAction;
1231
+ workspaceRoot: string;
1182
1232
  manifest: WorkOSFgaManifest;
1183
1233
  state: WorkOSFgaStateSummary;
1234
+ seedState?: WorkOSSeedStateSummary;
1184
1235
  real?: boolean;
1185
1236
  cliAuth?: WorkOSCliAuthSummary;
1186
1237
  workosSdk?: unknown;
1238
+ readiness?: WorkOSFgaReadiness;
1187
1239
  stateFile?: string;
1188
1240
  nextCommand?: string;
1189
1241
  nextActions?: string[];
@@ -1191,12 +1243,16 @@ function fgaData(input: {
1191
1243
  }): Record<string, unknown> {
1192
1244
  const hostedSetup = workOSFgaHostedSetup(input.manifest, input.workosSdk);
1193
1245
  const setupGuide = workOSFgaSetupGuide(input.manifest, hostedSetup);
1246
+ const membershipEnv = workOSFgaMembershipEnvSummary(input.workspaceRoot, input.manifest.organizations);
1194
1247
  return {
1195
1248
  action: input.action,
1196
1249
  real: input.real ?? false,
1197
1250
  manifest: input.manifest,
1198
1251
  state: input.state,
1252
+ ...(input.seedState ? { seedState: input.seedState } : {}),
1253
+ ...(input.readiness ? { readiness: input.readiness } : {}),
1199
1254
  hostedSetup,
1255
+ membershipEnv,
1200
1256
  resourceTypeSetup: setupGuide.resourceTypes,
1201
1257
  setupGuide,
1202
1258
  ...(input.cliAuth ? { cliAuth: input.cliAuth } : {}),
@@ -2573,6 +2629,133 @@ function collectWorkOSFgaChecks(input: {
2573
2629
  ];
2574
2630
  }
2575
2631
 
2632
+ function workOSFgaReadiness(input: {
2633
+ workspaceRoot: string;
2634
+ file: string;
2635
+ manifest: WorkOSFgaManifest;
2636
+ state: WorkOSFgaStateSummary;
2637
+ seedState: WorkOSSeedStateSummary;
2638
+ real: boolean;
2639
+ }): WorkOSFgaReadiness {
2640
+ const membershipEnv = workOSFgaMembershipEnvSummary(input.workspaceRoot, input.manifest.organizations);
2641
+ const planReady = input.manifest.diagnostics.length === 0 &&
2642
+ input.manifest.resourceTypes.includes("organization") &&
2643
+ input.manifest.proofScenarios.some((scenario) => scenario.expected === "allow") &&
2644
+ input.manifest.proofScenarios.some((scenario) => scenario.expected === "deny");
2645
+ const seedReady = !input.real || Boolean(input.seedState.exists && input.seedState.valid && input.seedState.matchesSeedHash === true);
2646
+ const synced = Boolean(input.state.exists && input.state.valid && input.state.matchesManifestHash === true);
2647
+ const resourceTypesConfigured = !input.real || Boolean(synced && input.state.mode === "real" && input.state.sdkOk === true);
2648
+ const membershipEnvReady = !input.real || membershipEnv.complete;
2649
+ const proved = !input.real
2650
+ ? Boolean(input.state.provedAt)
2651
+ : Boolean(synced && input.state.mode === "real" && input.state.sdkOk === true && input.state.provedAt);
2652
+ const productionReady = Boolean(planReady && seedReady && resourceTypesConfigured && membershipEnvReady && proved);
2653
+ let nextCommand = `forge workos fga plan --file ${input.file} --write --json`;
2654
+ if (planReady && input.real && !seedReady) {
2655
+ nextCommand = `forge workos prove --real --file ${input.file} --json`;
2656
+ } else if (planReady && input.real && !resourceTypesConfigured) {
2657
+ nextCommand = `forge workos fga sync --real --file ${input.file} --write --json`;
2658
+ } else if (planReady && input.real && !membershipEnvReady) {
2659
+ nextCommand = `forge workos fga prove --real --file ${input.file} --json`;
2660
+ } else if (planReady && input.real && !proved) {
2661
+ nextCommand = `forge workos fga prove --real --file ${input.file} --json`;
2662
+ } else if (planReady && !input.real && !synced) {
2663
+ nextCommand = `forge workos fga sync --file ${input.file} --json`;
2664
+ } else if (planReady && !input.real && !proved) {
2665
+ nextCommand = `forge workos fga prove --file ${input.file} --json`;
2666
+ } else if (productionReady || (planReady && !input.real)) {
2667
+ nextCommand = "forge deploy check --production --json";
2668
+ }
2669
+ const nextActions = [
2670
+ ...(planReady ? [] : [`repair FGA manifest gaps, then run forge workos fga plan --file ${input.file} --write --json`]),
2671
+ ...(input.real && !seedReady ? [`apply/prove hosted WorkOS seed: forge workos prove --real --file ${input.file} --json`] : []),
2672
+ ...(input.real && !resourceTypesConfigured
2673
+ ? [
2674
+ "configure hosted WorkOS FGA resource types listed in resourceTypeSetup",
2675
+ `sync real WorkOS FGA resources: forge workos fga sync --real --file ${input.file} --write --json`,
2676
+ ]
2677
+ : []),
2678
+ ...(input.real && !membershipEnvReady
2679
+ ? [`set WORKOS_FGA_MEMBERSHIPS_JSON or ${membershipEnv.missingEnv.join(", ") || "WORKOS_FGA_MEMBERSHIP_<ORG>"} before real access checks`]
2680
+ : []),
2681
+ ...(input.real && membershipEnvReady && resourceTypesConfigured && !proved
2682
+ ? [`prove real WorkOS FGA access checks: forge workos fga prove --real --file ${input.file} --json`]
2683
+ : []),
2684
+ ...(productionReady ? ["rerun forge deploy check --production --json"] : []),
2685
+ ...(!input.real && planReady && !synced ? [`run forge workos fga sync --file ${input.file} --json`] : []),
2686
+ ...(!input.real && planReady && synced && !proved ? [`run forge workos fga prove --file ${input.file} --json`] : []),
2687
+ ];
2688
+ return {
2689
+ real: input.real,
2690
+ planReady,
2691
+ seedReady,
2692
+ resourceTypesConfigured,
2693
+ membershipEnvReady,
2694
+ synced,
2695
+ proved,
2696
+ productionReady,
2697
+ nextCommand,
2698
+ nextActions,
2699
+ };
2700
+ }
2701
+
2702
+ function collectWorkOSFgaDoctorChecks(input: {
2703
+ workspaceRoot: string;
2704
+ file: string;
2705
+ manifest: WorkOSFgaManifest;
2706
+ state: WorkOSFgaStateSummary;
2707
+ seedState: WorkOSSeedStateSummary;
2708
+ real: boolean;
2709
+ }): WorkOSCheck[] {
2710
+ const readiness = workOSFgaReadiness(input);
2711
+ const membershipEnv = workOSFgaMembershipEnvSummary(input.workspaceRoot, input.manifest.organizations);
2712
+ return [
2713
+ ...collectWorkOSFgaChecks({
2714
+ manifest: input.manifest,
2715
+ state: input.state,
2716
+ requireState: input.real,
2717
+ requireRealState: input.real,
2718
+ requireProof: input.real,
2719
+ }),
2720
+ {
2721
+ name: "fga-seed-state",
2722
+ ok: !input.real || readiness.seedReady,
2723
+ detail: !input.real
2724
+ ? "hosted seed evidence is only required for --real doctor"
2725
+ : readiness.seedReady
2726
+ ? `${WORKOS_SEED_STATE_FILE} matches ${input.file}`
2727
+ : `real FGA proof requires hosted seed evidence matching ${input.file}; run forge workos prove --real --file ${input.file} --json`,
2728
+ },
2729
+ {
2730
+ name: "fga-hosted-resource-types",
2731
+ ok: !input.real || readiness.resourceTypesConfigured,
2732
+ detail: !input.real
2733
+ ? "hosted WorkOS resource type existence is only verified by --real sync/prove"
2734
+ : readiness.resourceTypesConfigured
2735
+ ? `${WORKOS_FGA_STATE_FILE} records successful real Authorization API resource sync`
2736
+ : "real FGA requires hosted WorkOS resource types for every non-organization resource; run forge workos fga plan --write and configure any listed resource types before sync",
2737
+ },
2738
+ {
2739
+ name: "fga-membership-env",
2740
+ ok: !input.real || readiness.membershipEnvReady,
2741
+ detail: !input.real
2742
+ ? "organizationMembershipId env is only required for real WorkOS access checks"
2743
+ : readiness.membershipEnvReady
2744
+ ? `membership env is present${membershipEnv.jsonEnvPresent ? " through WORKOS_FGA_MEMBERSHIPS_JSON" : ` through ${membershipEnv.presentEnv.join(", ")}`}`
2745
+ : `missing organizationMembershipId env for real checks: WORKOS_FGA_MEMBERSHIPS_JSON or ${membershipEnv.missingEnv.join(", ")}`,
2746
+ },
2747
+ {
2748
+ name: "fga-production-readiness",
2749
+ ok: !input.real || readiness.productionReady,
2750
+ detail: !input.real
2751
+ ? "run forge workos fga doctor --real --json for production FGA gates"
2752
+ : readiness.productionReady
2753
+ ? "real WorkOS FGA seed, resource sync, membership env, and proof are current"
2754
+ : `real WorkOS FGA is not production-ready; next command: ${readiness.nextCommand}`,
2755
+ },
2756
+ ];
2757
+ }
2758
+
2576
2759
  export function runWorkOSFgaCommand(options: WorkOSCommandOptions): WorkOSCommandResult {
2577
2760
  const action = options.fgaAction ?? "doctor";
2578
2761
  const file = options.file ?? DEFAULT_SEED_FILE;
@@ -2608,8 +2791,10 @@ export function runWorkOSFgaCommand(options: WorkOSCommandOptions): WorkOSComman
2608
2791
  applied: false,
2609
2792
  data: fgaData({
2610
2793
  action,
2794
+ workspaceRoot: options.workspaceRoot,
2611
2795
  manifest,
2612
2796
  state,
2797
+ seedState,
2613
2798
  real,
2614
2799
  ...(writtenSetupGuidePath ? { setupGuidePath: writtenSetupGuidePath } : {}),
2615
2800
  nextCommand: `forge workos fga sync --file ${file} --json`,
@@ -2642,8 +2827,10 @@ export function runWorkOSFgaCommand(options: WorkOSCommandOptions): WorkOSComman
2642
2827
  applied: false,
2643
2828
  data: fgaData({
2644
2829
  action,
2830
+ workspaceRoot: options.workspaceRoot,
2645
2831
  manifest,
2646
2832
  state,
2833
+ seedState,
2647
2834
  real,
2648
2835
  ...(cliAuth ? { cliAuth } : {}),
2649
2836
  ...(writtenSetupGuidePath ? { setupGuidePath: writtenSetupGuidePath } : {}),
@@ -2661,8 +2848,10 @@ export function runWorkOSFgaCommand(options: WorkOSCommandOptions): WorkOSComman
2661
2848
  applied: false,
2662
2849
  data: fgaData({
2663
2850
  action,
2851
+ workspaceRoot: options.workspaceRoot,
2664
2852
  manifest,
2665
2853
  state,
2854
+ seedState,
2666
2855
  real,
2667
2856
  ...(cliAuth ? { cliAuth } : {}),
2668
2857
  ...(writtenSetupGuidePath ? { setupGuidePath: writtenSetupGuidePath } : {}),
@@ -2688,8 +2877,10 @@ export function runWorkOSFgaCommand(options: WorkOSCommandOptions): WorkOSComman
2688
2877
  applied: false,
2689
2878
  data: fgaData({
2690
2879
  action,
2880
+ workspaceRoot: options.workspaceRoot,
2691
2881
  manifest,
2692
2882
  state,
2883
+ seedState,
2693
2884
  real,
2694
2885
  ...(cliAuth ? { cliAuth } : {}),
2695
2886
  workosSdk: sdk.data,
@@ -2718,8 +2909,10 @@ export function runWorkOSFgaCommand(options: WorkOSCommandOptions): WorkOSComman
2718
2909
  applied: true,
2719
2910
  data: fgaData({
2720
2911
  action,
2912
+ workspaceRoot: options.workspaceRoot,
2721
2913
  manifest,
2722
2914
  state,
2915
+ seedState,
2723
2916
  real,
2724
2917
  ...(cliAuth ? { cliAuth } : {}),
2725
2918
  ...(sdk ? { workosSdk: sdk.data } : {}),
@@ -2789,8 +2982,10 @@ export function runWorkOSFgaCommand(options: WorkOSCommandOptions): WorkOSComman
2789
2982
  applied: Boolean(ok && !options.dryRun),
2790
2983
  data: fgaData({
2791
2984
  action,
2985
+ workspaceRoot: options.workspaceRoot,
2792
2986
  manifest,
2793
2987
  state,
2988
+ seedState,
2794
2989
  real,
2795
2990
  ...(cliAuth ? { cliAuth } : {}),
2796
2991
  ...(sdk ? { workosSdk: sdk.data } : {}),
@@ -2804,20 +2999,40 @@ export function runWorkOSFgaCommand(options: WorkOSCommandOptions): WorkOSComman
2804
2999
  };
2805
3000
  }
2806
3001
 
2807
- const ok = checks.every((check) => check.ok);
3002
+ const doctorChecks = collectWorkOSFgaDoctorChecks({
3003
+ workspaceRoot: options.workspaceRoot,
3004
+ file,
3005
+ manifest,
3006
+ state,
3007
+ seedState,
3008
+ real,
3009
+ });
3010
+ const readiness = workOSFgaReadiness({
3011
+ workspaceRoot: options.workspaceRoot,
3012
+ file,
3013
+ manifest,
3014
+ state,
3015
+ seedState,
3016
+ real,
3017
+ });
3018
+ const ok = doctorChecks.every((check) => check.ok);
2808
3019
  return {
2809
3020
  ok,
2810
3021
  kind: "workos-fga",
2811
- checks,
3022
+ checks: doctorChecks,
2812
3023
  command,
2813
3024
  applied: false,
2814
3025
  data: fgaData({
2815
3026
  action,
3027
+ workspaceRoot: options.workspaceRoot,
2816
3028
  manifest,
2817
3029
  state,
3030
+ seedState,
3031
+ readiness,
2818
3032
  real,
2819
3033
  ...(writtenSetupGuidePath ? { setupGuidePath: writtenSetupGuidePath } : {}),
2820
- nextCommand: state.exists ? `forge workos fga prove --file ${file} --json` : `forge workos fga sync --file ${file} --json`,
3034
+ nextCommand: readiness.nextCommand,
3035
+ nextActions: readiness.nextActions,
2821
3036
  }),
2822
3037
  exitCode: ok ? 0 : 1,
2823
3038
  };
@@ -2953,6 +3168,8 @@ export function formatWorkOSHuman(result: WorkOSCommandResult): string {
2953
3168
  lines.push(`WorkOS FGA sync recorded${data.stateFile ? ` in ${data.stateFile}` : ""}; run ${data.nextCommand ?? "forge workos fga prove --json"}.`);
2954
3169
  } else if (result.ok && data.action === "prove") {
2955
3170
  lines.push(`WorkOS FGA proof passed${data.real ? " for real-mode state" : " locally"}; production deploy gates can inspect the FGA state.`);
3171
+ } else if (result.ok && data.action === "doctor") {
3172
+ lines.push(`WorkOS FGA doctor passed${data.real ? " for real production gates" : " for local planning"}; run ${data.nextCommand ?? "forge workos fga sync --json"} if you need the next proof step.`);
2956
3173
  } else if (!result.ok) {
2957
3174
  lines.push("WorkOS FGA check failed; inspect manifest diagnostics, seed coverage, and FGA state.");
2958
3175
  for (const action of data.nextActions ?? []) {
@@ -1,3 +1,3 @@
1
- export const FORGEOS_VERSION = "0.1.0-alpha.50";
1
+ export const FORGEOS_VERSION = "0.1.0-alpha.52";
2
2
  export const GENERATOR_VERSION = FORGEOS_VERSION;
3
3
  export const CLI_VERSION = FORGEOS_VERSION;