forgeos 0.1.0-alpha.44 → 0.1.0-alpha.46

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.44 input=3c44e5f9f6fd4afe42accec6d73bca4f36f188ed9de5fb11f4a890d3020fe2bc content=721818a6f9a664aa898092d4aa5cd68cbbd8ad6e150c7d3ad3ef785a2e3fcf53
1
+ // @forge-generated generator=0.1.0-alpha.46 input=fa019b5420e754f08100c96852edfc9ea0b39a6b050cbd9bc99106b88775c207 content=721818a6f9a664aa898092d4aa5cd68cbbd8ad6e150c7d3ad3ef785a2e3fcf53
2
2
  # AGENTS.md
3
3
 
4
4
  <!-- forge-generated:start -->
package/CHANGELOG.md CHANGED
@@ -1,5 +1,43 @@
1
1
  # forgeos
2
2
 
3
+ ## 0.1.0-alpha.46
4
+
5
+ ### Patch Changes
6
+
7
+ - Smooth the package upgrade apply path used by real ForgeOS apps.
8
+
9
+ - `forge deps upgrade-apply` and `forge deps upgrade-rollback` now accept the
10
+ `planDir` returned by `forge deps upgrade-plan`, automatically resolving it
11
+ to `plan.json`.
12
+ - Passing a directory without `plan.json` now returns a targeted
13
+ `FORGE_DEPS_TARGET_NOT_FOUND` diagnostic with the exact suggested command
14
+ instead of falling through to a generic JSON parse failure.
15
+ - Add regression coverage for applying upgrade plans through the returned
16
+ directory path and for invalid plan directories.
17
+
18
+ ## 0.1.0-alpha.45
19
+
20
+ ### Patch Changes
21
+
22
+ - Smooth the WorkOS, field-test, and deploy-readiness DX discovered during real
23
+ app field testing.
24
+
25
+ - Accept `--real` through the top-level unknown-option guard so documented
26
+ commands like `forge workos setup --real --file workos-seed.yml --json` and
27
+ `forge workos prove --real --file workos-seed.yml --json` run instead of
28
+ being rejected before parsing.
29
+ - Treat known WorkOS CLI duplicate-resource seed responses as explicit clean
30
+ idempotency: Forge now records `seedAlreadyAppliedReason`, suppresses the
31
+ scary duplicate stderr from the successful JSON result, and writes seed
32
+ state with the already-applied status.
33
+ - Run `forge field-test run` through an async harness process and emit
34
+ periodic stderr heartbeats so long realistic probes no longer look frozen
35
+ while preserving machine-readable JSON output.
36
+ - Add a `deploy-env-sources` check to `forge deploy check --production` that
37
+ reports which env sources were inspected, which keys were present, and which
38
+ production keys are still missing without printing secret values; `.env` and
39
+ `.env.local` are shown as local guidance, not production deploy evidence.
40
+
3
41
  ## 0.1.0-alpha.44
4
42
 
5
43
  ### Patch Changes
package/docs/changelog.md CHANGED
@@ -6,6 +6,32 @@ The canonical source file in the repository is `CHANGELOG.md`.
6
6
 
7
7
  ## Unreleased
8
8
 
9
+ ## 0.1.0-alpha.46
10
+
11
+ - `forge deps upgrade-apply` and `forge deps upgrade-rollback` now accept the
12
+ `planDir` returned by `forge deps upgrade-plan`, resolving it to the nested
13
+ `plan.json` automatically.
14
+ - Invalid upgrade plan directories now return a precise
15
+ `FORGE_DEPS_TARGET_NOT_FOUND` diagnostic with suggested commands instead of a
16
+ generic JSON parse failure.
17
+ - Added regression coverage for plan-directory apply behavior and missing
18
+ `plan.json` diagnostics.
19
+
20
+ ## 0.1.0-alpha.45
21
+
22
+ - `forge workos setup/prove --real` now passes the top-level unknown-option
23
+ guard, matching the documented no-dashboard WorkOS apply flow.
24
+ - `forge workos seed --file workos-seed.yml --json` now treats known WorkOS
25
+ duplicate-resource responses as explicit idempotency, suppressing duplicate
26
+ stderr in successful JSON output while recording `seedAlreadyAppliedReason`
27
+ and seed state.
28
+ - `forge field-test run` now uses an async harness process with periodic
29
+ progress heartbeats on stderr so realistic probes do not appear stuck.
30
+ - `forge deploy check --production` now reports sanitized env-source evidence,
31
+ including which production keys were found or missing, while keeping `.env`
32
+ and `.env.local` clearly marked as local guidance rather than production
33
+ deploy evidence.
34
+
9
35
  ## 0.1.0-alpha.44
10
36
 
11
37
  - `forge inspect ui --ergonomics` now treats helper-based seed recovery inside
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "forgeos",
3
- "version": "0.1.0-alpha.44",
3
+ "version": "0.1.0-alpha.46",
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.44","releaseId":"forgeos@0.1.0-alpha.44+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.46","releaseId":"forgeos@0.1.0-alpha.46+unknown","schemaVersion":"0.1.0"}
@@ -1,4 +1,4 @@
1
- // @forge-generated generator=0.1.0-alpha.44 input=3c44e5f9f6fd4afe42accec6d73bca4f36f188ed9de5fb11f4a890d3020fe2bc content=3d89cc8170a2affb58421e25ec58882655d6ea2399efe65a822d99e1afa1ddb5
1
+ // @forge-generated generator=0.1.0-alpha.46 input=fa019b5420e754f08100c96852edfc9ea0b39a6b050cbd9bc99106b88775c207 content=715d49dd9abed8465a5cf5e82713973aab97cc178fda3b1e8b1647b93683ee58
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.44",
23
- "releaseId": "forgeos@0.1.0-alpha.44+unknown",
22
+ "packageVersion": "0.1.0-alpha.46",
23
+ "releaseId": "forgeos@0.1.0-alpha.46+unknown",
24
24
  "schemaVersion": "0.1.0"
25
25
  } as const;
@@ -120,6 +120,23 @@ function fieldTestReportCandidates(workspaceRoot: string): Array<{ path: string;
120
120
  }
121
121
 
122
122
  const FIELD_TEST_PRODUCTION_COMMAND = "forge field-test run --realistic --json";
123
+ const DEPLOY_ENV_FILE = "deploy/.env.production";
124
+ const LOCAL_ENV_FILES = [".env", ".env.local"];
125
+ const DEPLOY_ENV_KEYS = [
126
+ "DATABASE_URL",
127
+ "FORGE_AUTH_MODE",
128
+ "FORGE_AUTH_ISSUER",
129
+ "FORGE_AUTH_AUDIENCE",
130
+ "FORGE_AUTH_JWKS_URI",
131
+ "FORGE_AUTH_DISCOVERY_URL",
132
+ "WORKOS_API_KEY",
133
+ "WORKOS_CLIENT_ID",
134
+ "WORKOS_COOKIE_PASSWORD",
135
+ "WORKOS_REDIRECT_URI",
136
+ "WORKOS_POST_LOGIN_REDIRECT_URI",
137
+ "WORKOS_POST_LOGOUT_REDIRECT_URI",
138
+ "WORKOS_WEBHOOK_SECRET",
139
+ ];
123
140
 
124
141
  function summarizeFieldTestReport(data: Record<string, unknown>) {
125
142
  const results = Array.isArray(data.results) ? data.results as Array<Record<string, unknown>> : [];
@@ -428,7 +445,7 @@ function renderEnvExample(workspaceRoot: string): string {
428
445
  }
429
446
 
430
447
  function hasProductionEnvFile(workspaceRoot: string): boolean {
431
- return nodeFileSystem.exists(join(workspaceRoot, "deploy/.env.production"));
448
+ return nodeFileSystem.exists(join(workspaceRoot, DEPLOY_ENV_FILE));
432
449
  }
433
450
 
434
451
  function parseEnvValue(value: string): string {
@@ -442,8 +459,8 @@ function parseEnvValue(value: string): string {
442
459
  return trimmed;
443
460
  }
444
461
 
445
- function readDeployEnvFile(workspaceRoot: string): Record<string, string> {
446
- const absolute = join(workspaceRoot, "deploy/.env.production");
462
+ function readEnvFile(workspaceRoot: string, relative: string): Record<string, string> {
463
+ const absolute = join(workspaceRoot, relative);
447
464
  if (!nodeFileSystem.exists(absolute)) return {};
448
465
  const text = nodeFileSystem.readText(absolute) ?? "";
449
466
  const values: Record<string, string> = {};
@@ -457,6 +474,63 @@ function readDeployEnvFile(workspaceRoot: string): Record<string, string> {
457
474
  return values;
458
475
  }
459
476
 
477
+ function readDeployEnvFile(workspaceRoot: string): Record<string, string> {
478
+ return readEnvFile(workspaceRoot, DEPLOY_ENV_FILE);
479
+ }
480
+
481
+ function envKeys(values: Record<string, string>): string[] {
482
+ return DEPLOY_ENV_KEYS.filter((key) => Boolean(values[key])).sort();
483
+ }
484
+
485
+ function processDeployEnv(): Record<string, string> {
486
+ return Object.fromEntries(
487
+ DEPLOY_ENV_KEYS
488
+ .filter((key) => Boolean(process.env[key]))
489
+ .map((key) => [key, process.env[key]!]),
490
+ );
491
+ }
492
+
493
+ function deployEnvSources(workspaceRoot: string): Record<string, unknown> {
494
+ const processEnv = processDeployEnv();
495
+ const deployEnv = readDeployEnvFile(workspaceRoot);
496
+ const localSources = LOCAL_ENV_FILES.map((path) => {
497
+ const values = readEnvFile(workspaceRoot, path);
498
+ return {
499
+ path,
500
+ present: nodeFileSystem.exists(join(workspaceRoot, path)),
501
+ role: "local-guidance",
502
+ readForProduction: false,
503
+ keys: envKeys(values),
504
+ };
505
+ });
506
+ const productionEvidence = {
507
+ ...deployEnv,
508
+ ...processEnv,
509
+ };
510
+ return {
511
+ readOrder: ["process.env", DEPLOY_ENV_FILE],
512
+ note: `${DEPLOY_ENV_FILE} and current process env are production deploy evidence; .env/.env.local are reported only as local guidance and are not used to pass production gates.`,
513
+ sources: [
514
+ {
515
+ path: "process.env",
516
+ present: envKeys(processEnv).length > 0,
517
+ role: "production-evidence",
518
+ readForProduction: true,
519
+ keys: envKeys(processEnv),
520
+ },
521
+ {
522
+ path: DEPLOY_ENV_FILE,
523
+ present: hasProductionEnvFile(workspaceRoot),
524
+ role: "production-evidence",
525
+ readForProduction: true,
526
+ keys: envKeys(deployEnv),
527
+ },
528
+ ...localSources,
529
+ ],
530
+ missingProductionKeys: DEPLOY_ENV_KEYS.filter((key) => !productionEvidence[key]),
531
+ };
532
+ }
533
+
460
534
  function deployEnvValue(workspaceRoot: string, name: string): string | undefined {
461
535
  return process.env[name] || readDeployEnvFile(workspaceRoot)[name];
462
536
  }
@@ -494,15 +568,15 @@ function databaseReady(options: DeployCommandOptions): boolean {
494
568
 
495
569
  function databaseReadyMessage(options: DeployCommandOptions): string {
496
570
  if (process.env.DATABASE_URL) return "DATABASE_URL is set in the current environment";
497
- if (readDeployEnvFile(options.workspaceRoot).DATABASE_URL) return "DATABASE_URL is set in deploy/.env.production";
498
- if (hasProductionEnvFile(options.workspaceRoot)) return "deploy/.env.production is present but does not set DATABASE_URL";
571
+ if (readDeployEnvFile(options.workspaceRoot).DATABASE_URL) return `DATABASE_URL is set in ${DEPLOY_ENV_FILE}`;
572
+ if (hasProductionEnvFile(options.workspaceRoot)) return `${DEPLOY_ENV_FILE} is present but does not set DATABASE_URL`;
499
573
  if (hasRenderedProductionEnvExample(options.workspaceRoot)) {
500
574
  return options.production
501
- ? "deploy/.env.production.example is only a template; copy it to deploy/.env.production with DATABASE_URL or set DATABASE_URL"
575
+ ? `deploy/.env.production.example is only a template; copy it to ${DEPLOY_ENV_FILE} with DATABASE_URL or set DATABASE_URL`
502
576
  : "deploy/.env.production.example is present";
503
577
  }
504
578
  return options.production
505
- ? "production deploy requires DATABASE_URL or deploy/.env.production"
579
+ ? `production deploy requires DATABASE_URL or ${DEPLOY_ENV_FILE}`
506
580
  : "deploy readiness requires DATABASE_URL or rendered deploy/.env.production.example";
507
581
  }
508
582
 
@@ -650,6 +724,13 @@ async function buildChecks(options: DeployCommandOptions): Promise<DeployCommand
650
724
  found: lockfiles,
651
725
  },
652
726
  });
727
+ checks.push({
728
+ name: "deploy-env-sources",
729
+ ok: true,
730
+ severity: "warning",
731
+ message: `${DEPLOY_ENV_FILE} and process.env are production deploy evidence; .env/.env.local are local guidance only`,
732
+ details: deployEnvSources(options.workspaceRoot),
733
+ });
653
734
 
654
735
  const auth = await withDeployEnv(options.workspaceRoot, async () => loadAuthConfigFromEnv(options.workspaceRoot));
655
736
  const productionAuth = auth.mode === "jwt" || auth.mode === "oidc";
@@ -73,15 +73,55 @@ function readGeneratedJson<T>(workspaceRoot: string, relative: string): T | null
73
73
  return JSON.parse(raw) as T;
74
74
  }
75
75
 
76
- function planPathFor(workspaceRoot: string, planIdOrPath: string): string {
77
- if (nodeFileSystem.exists(planIdOrPath)) {
78
- return planIdOrPath;
79
- }
80
- const direct = join(workspaceRoot, planIdOrPath);
81
- if (nodeFileSystem.exists(direct)) {
82
- return direct;
76
+ function resolvePlanPathFor(
77
+ workspaceRoot: string,
78
+ planIdOrPath: string,
79
+ ): { ok: true; path: string } | { ok: false; diagnostics: Diagnostic[] } {
80
+ const candidates = [
81
+ planIdOrPath,
82
+ join(workspaceRoot, planIdOrPath),
83
+ join(workspaceRoot, ".forge", "upgrades", planIdOrPath, "plan.json"),
84
+ ];
85
+
86
+ for (const candidate of candidates) {
87
+ if (!nodeFileSystem.exists(candidate)) {
88
+ continue;
89
+ }
90
+ if (!nodeFileSystem.isDirectory(candidate)) {
91
+ return { ok: true, path: candidate };
92
+ }
93
+ const nestedPlan = join(candidate, "plan.json");
94
+ if (nodeFileSystem.exists(nestedPlan) && !nodeFileSystem.isDirectory(nestedPlan)) {
95
+ return { ok: true, path: nestedPlan };
96
+ }
97
+ return {
98
+ ok: false,
99
+ diagnostics: [{
100
+ severity: "error",
101
+ code: "FORGE_DEPS_TARGET_NOT_FOUND",
102
+ message: `upgrade plan directory '${planIdOrPath}' does not contain plan.json`,
103
+ fixHint: "Pass the plan.json file returned by forge deps upgrade-plan, or rerun upgrade-plan.",
104
+ suggestedCommands: [
105
+ `forge deps upgrade-apply ${nestedPlan} --json`,
106
+ "forge deps upgrade-plan <package> --to latest --json",
107
+ ],
108
+ }],
109
+ };
83
110
  }
84
- return join(workspaceRoot, ".forge", "upgrades", planIdOrPath, "plan.json");
111
+
112
+ return {
113
+ ok: false,
114
+ diagnostics: [{
115
+ severity: "error",
116
+ code: "FORGE_DEPS_TARGET_NOT_FOUND",
117
+ message: `upgrade plan '${planIdOrPath}' was not found`,
118
+ fixHint: "Use the planDir or plan.json path returned by forge deps upgrade-plan.",
119
+ suggestedCommands: [
120
+ `forge deps upgrade-apply .forge/upgrades/${planIdOrPath}/plan.json --json`,
121
+ "forge deps upgrade-plan <package> --to latest --json",
122
+ ],
123
+ }],
124
+ };
85
125
  }
86
126
 
87
127
  function findPackage(workspaceRoot: string, packageName: string): {
@@ -395,9 +435,17 @@ export async function runDepsCommand(options: DepsCommandOptions): Promise<DepsC
395
435
  if (!options.planPath) {
396
436
  return missingPlan();
397
437
  }
438
+ const resolvedPlan = resolvePlanPathFor(options.workspaceRoot, options.planPath);
439
+ if (!resolvedPlan.ok) {
440
+ return {
441
+ ok: false,
442
+ diagnostics: resolvedPlan.diagnostics,
443
+ exitCode: 1,
444
+ };
445
+ }
398
446
  const applied = await applyUpgradePlan({
399
447
  workspaceRoot: options.workspaceRoot,
400
- planPath: planPathFor(options.workspaceRoot, options.planPath),
448
+ planPath: resolvedPlan.path,
401
449
  yes: options.yes,
402
450
  allowScripts: options.allowScripts,
403
451
  skipTests: options.skipTests,
@@ -409,6 +457,7 @@ export async function runDepsCommand(options: DepsCommandOptions): Promise<DepsC
409
457
  applied: applied.applied,
410
458
  rolledBack: applied.rolledBack,
411
459
  reinstallCommand: applied.plan?.rollback.reinstallCommand,
460
+ planPath: resolvedPlan.path,
412
461
  },
413
462
  diagnostics: applied.diagnostics,
414
463
  exitCode: applied.exitCode,
@@ -419,15 +468,24 @@ export async function runDepsCommand(options: DepsCommandOptions): Promise<DepsC
419
468
  if (!options.planPath) {
420
469
  return missingPlan();
421
470
  }
471
+ const resolvedPlan = resolvePlanPathFor(options.workspaceRoot, options.planPath);
472
+ if (!resolvedPlan.ok) {
473
+ return {
474
+ ok: false,
475
+ diagnostics: resolvedPlan.diagnostics,
476
+ exitCode: 1,
477
+ };
478
+ }
422
479
  const rolledBack = rollbackUpgradePlan({
423
480
  workspaceRoot: options.workspaceRoot,
424
- planPath: planPathFor(options.workspaceRoot, options.planPath),
481
+ planPath: resolvedPlan.path,
425
482
  });
426
483
  return {
427
484
  ok: rolledBack.ok,
428
485
  data: {
429
486
  rolledBack: rolledBack.rolledBack,
430
487
  reinstallCommand: rolledBack.plan?.rollback.reinstallCommand,
488
+ planPath: resolvedPlan.path,
431
489
  },
432
490
  diagnostics: rolledBack.diagnostics,
433
491
  exitCode: rolledBack.exitCode,
@@ -1,4 +1,4 @@
1
- import { spawnSync } from "node:child_process";
1
+ import { spawn } from "node:child_process";
2
2
  import { existsSync, readFileSync } from "node:fs";
3
3
  import { dirname, isAbsolute, join } from "node:path";
4
4
  import { fileURLToPath } from "node:url";
@@ -400,7 +400,56 @@ async function createFieldTestApp(options: FieldTestCommandOptions): Promise<Fie
400
400
  });
401
401
  }
402
402
 
403
- function runHarness(options: FieldTestCommandOptions): FieldTestCommandResult {
403
+ function shouldEmitProgress(): boolean {
404
+ return process.env.FORGE_FIELD_TEST_PROGRESS !== "0";
405
+ }
406
+
407
+ function runHarnessProcess(
408
+ options: FieldTestCommandOptions,
409
+ args: string[],
410
+ ): Promise<{ status: number | null; stdout: string; stderr: string }> {
411
+ return new Promise((resolve) => {
412
+ const startedAt = Date.now();
413
+ const emitProgress = shouldEmitProgress();
414
+ const child = spawn(process.execPath, args, {
415
+ cwd: options.workspaceRoot,
416
+ stdio: ["ignore", "pipe", "pipe"],
417
+ windowsHide: true,
418
+ });
419
+ let stdout = "";
420
+ let stderr = "";
421
+ let settled = false;
422
+ child.stdout?.setEncoding("utf8");
423
+ child.stderr?.setEncoding("utf8");
424
+ child.stdout?.on("data", (chunk) => {
425
+ stdout += chunk;
426
+ });
427
+ child.stderr?.on("data", (chunk) => {
428
+ stderr += chunk;
429
+ });
430
+ const heartbeat = emitProgress
431
+ ? setInterval(() => {
432
+ const elapsed = Math.round((Date.now() - startedAt) / 1000);
433
+ process.stderr.write(`[forge] field-test still running after ${elapsed}s; timeout=${options.timeoutMs}ms\n`);
434
+ }, 30_000)
435
+ : undefined;
436
+ const finish = (status: number | null, extraStderr = "") => {
437
+ if (settled) return;
438
+ settled = true;
439
+ if (heartbeat) clearInterval(heartbeat);
440
+ if (extraStderr) stderr += extraStderr;
441
+ resolve({ status, stdout, stderr });
442
+ };
443
+ child.on("error", (error) => {
444
+ finish(1, `${error.message}\n`);
445
+ });
446
+ child.on("close", (status) => {
447
+ finish(status);
448
+ });
449
+ });
450
+ }
451
+
452
+ async function runHarness(options: FieldTestCommandOptions): Promise<FieldTestCommandResult> {
404
453
  const script = scriptPath(options.workspaceRoot);
405
454
  if (!script) {
406
455
  return {
@@ -433,11 +482,7 @@ function runHarness(options: FieldTestCommandOptions): FieldTestCommandResult {
433
482
  if (options.forgeSpec) args.push("--forge-spec", options.forgeSpec);
434
483
  if (reportPath) args.push("--write-report", reportPath);
435
484
  if (options.json) args.push("--json");
436
- const result = spawnSync(process.execPath, args, {
437
- cwd: options.workspaceRoot,
438
- encoding: "utf8",
439
- windowsHide: true,
440
- });
485
+ const result = await runHarnessProcess(options, args);
441
486
  const reportAbsolute = reportPath ? resolveReportPath(options.workspaceRoot, reportPath) : null;
442
487
  const reportData = reportAbsolute && existsSync(reportAbsolute)
443
488
  ? JSON.parse(readFileSync(reportAbsolute, "utf8")) as unknown
@@ -3069,6 +3069,7 @@ export function hasUnknownOption(argv: string[]): string | null {
3069
3069
  "--auth-probes",
3070
3070
  "--ui-probes",
3071
3071
  "--realistic",
3072
+ "--real",
3072
3073
  "--write-report",
3073
3074
  "--tenant-scoped",
3074
3075
  "--field",
@@ -703,7 +703,9 @@ function seedData(input: {
703
703
  dryRun?: boolean;
704
704
  seedFileSanitized?: boolean;
705
705
  seedAlreadyApplied?: boolean;
706
+ seedAlreadyAppliedReason?: string;
706
707
  seedStateFile?: string;
708
+ workosCli?: Record<string, unknown>;
707
709
  configActions?: WorkOSConfigActionResult[];
708
710
  nextCommand?: string;
709
711
  }): Record<string, unknown> {
@@ -716,7 +718,9 @@ function seedData(input: {
716
718
  dryRun: input.dryRun ?? false,
717
719
  seedFileSanitized: input.seedFileSanitized ?? false,
718
720
  seedAlreadyApplied: input.seedAlreadyApplied ?? false,
721
+ ...(input.seedAlreadyAppliedReason ? { seedAlreadyAppliedReason: input.seedAlreadyAppliedReason } : {}),
719
722
  ...(input.seedStateFile ? { seedStateFile: input.seedStateFile } : {}),
723
+ ...(input.workosCli ? { workosCli: input.workosCli } : {}),
720
724
  configActions: input.configActions ?? [],
721
725
  ...(input.nextCommand ? { nextCommand: input.nextCommand } : {}),
722
726
  };
@@ -1087,6 +1091,9 @@ export function runWorkOSSeedCommand(options: WorkOSCommandOptions): WorkOSComma
1087
1091
  const child = runExternalCommand(delegatedCommand, options);
1088
1092
  const seedAlreadyApplied =
1089
1093
  child.status !== 0 && isWorkOSSeedAlreadyApplied(child.stdout, child.stderr);
1094
+ const seedAlreadyAppliedReason = seedAlreadyApplied
1095
+ ? "workos-cli-existing-resource"
1096
+ : undefined;
1090
1097
  const seedStateFile = child.status === 0 || seedAlreadyApplied
1091
1098
  ? writeWorkOSSeedState({
1092
1099
  workspaceRoot: options.workspaceRoot,
@@ -1113,11 +1120,17 @@ export function runWorkOSSeedCommand(options: WorkOSCommandOptions): WorkOSComma
1113
1120
  seedState: latestSeedState,
1114
1121
  seedFileSanitized: preparedSeed.sanitized,
1115
1122
  seedAlreadyApplied,
1123
+ seedAlreadyAppliedReason,
1116
1124
  seedStateFile,
1125
+ workosCli: {
1126
+ status: child.status,
1127
+ idempotentConflict: seedAlreadyApplied,
1128
+ stderrSuppressed: seedAlreadyApplied && Boolean(child.stderr.trim()),
1129
+ },
1117
1130
  configActions,
1118
1131
  }),
1119
1132
  stdout: child.stdout,
1120
- stderr: child.stderr,
1133
+ stderr: seedAlreadyApplied ? undefined : child.stderr,
1121
1134
  exitCode: child.status === 0 || seedAlreadyApplied ? 0 : 1,
1122
1135
  };
1123
1136
  } finally {
@@ -1,3 +1,3 @@
1
- export const FORGEOS_VERSION = "0.1.0-alpha.44";
1
+ export const FORGEOS_VERSION = "0.1.0-alpha.46";
2
2
  export const GENERATOR_VERSION = FORGEOS_VERSION;
3
3
  export const CLI_VERSION = FORGEOS_VERSION;