forgeos 0.1.0-alpha.26 → 0.1.0-alpha.27

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 (67) hide show
  1. package/.npmignore +6 -0
  2. package/AGENTS.md +1 -1
  3. package/CHANGELOG.md +14 -0
  4. package/bin/forge.mjs +0 -0
  5. package/docs/changelog.md +13 -0
  6. package/package.json +7 -1
  7. package/src/forge/_generated/releaseManifest.json +1 -1
  8. package/src/forge/_generated/releaseManifest.ts +3 -3
  9. package/src/forge/cli/changed.ts +25 -20
  10. package/src/forge/cli/output.ts +1 -1
  11. package/src/forge/compiler/integration/add.ts +38 -1
  12. package/src/forge/compiler/integration/plan.ts +2 -11
  13. package/src/forge/compiler/orchestrator/fast-check.ts +4 -0
  14. package/src/forge/compiler/orchestrator/manifest.ts +1 -1
  15. package/src/forge/compiler/orchestrator/plan.ts +163 -1
  16. package/src/forge/compiler/orchestrator/types.ts +1 -1
  17. package/src/forge/runtime/executor.ts +18 -15
  18. package/src/forge/version.ts +1 -1
  19. package/src/forge/workspace/change-summary.ts +34 -0
  20. package/adapters/java/target/classes/dev/forgeos/adapter/Auth.class +0 -0
  21. package/adapters/java/target/classes/dev/forgeos/adapter/Diagnostic.class +0 -0
  22. package/adapters/java/target/classes/dev/forgeos/adapter/Entry.class +0 -0
  23. package/adapters/java/target/classes/dev/forgeos/adapter/EntryKind.class +0 -0
  24. package/adapters/java/target/classes/dev/forgeos/adapter/ErrorInfo.class +0 -0
  25. package/adapters/java/target/classes/dev/forgeos/adapter/Forge.class +0 -0
  26. package/adapters/java/target/classes/dev/forgeos/adapter/ForgeCall.class +0 -0
  27. package/adapters/java/target/classes/dev/forgeos/adapter/ForgeContext.class +0 -0
  28. package/adapters/java/target/classes/dev/forgeos/adapter/ForgeHandler.class +0 -0
  29. package/adapters/java/target/classes/dev/forgeos/adapter/ForgeHttpHandler.class +0 -0
  30. package/adapters/java/target/classes/dev/forgeos/adapter/ForgeRegistry$EntryOption.class +0 -0
  31. package/adapters/java/target/classes/dev/forgeos/adapter/ForgeRegistry$RegisteredEntry.class +0 -0
  32. package/adapters/java/target/classes/dev/forgeos/adapter/ForgeRegistry$RegistryOption.class +0 -0
  33. package/adapters/java/target/classes/dev/forgeos/adapter/ForgeRegistry.class +0 -0
  34. package/adapters/java/target/classes/dev/forgeos/adapter/Json.class +0 -0
  35. package/adapters/java/target/classes/dev/forgeos/adapter/Manifest.class +0 -0
  36. package/adapters/java/target/classes/dev/forgeos/adapter/RequestEnvelope.class +0 -0
  37. package/adapters/java/target/classes/dev/forgeos/adapter/ResponseEnvelope.class +0 -0
  38. package/adapters/java/target/classes/dev/forgeos/adapter/Risk.class +0 -0
  39. package/adapters/java/target/classes/dev/forgeos/adapter/Schemas.class +0 -0
  40. package/adapters/java/target/classes/dev/forgeos/adapter/Service.class +0 -0
  41. package/adapters/java/target/classes/dev/forgeos/adapter/TransactionMode.class +0 -0
  42. package/adapters/java/target/classes/dev/forgeos/adapter/TypedForgeHandler.class +0 -0
  43. package/adapters/java/target/forge-java-adapter-0.1.0-alpha.11.jar +0 -0
  44. package/adapters/java/target/maven-archiver/pom.properties +0 -3
  45. package/adapters/java/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst +0 -23
  46. package/adapters/java/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst +0 -20
  47. package/adapters/java-spring-boot-starter/target/classes/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +0 -1
  48. package/adapters/java-spring-boot-starter/target/classes/dev/forgeos/adapter/spring/ForgeCommand.class +0 -0
  49. package/adapters/java-spring-boot-starter/target/classes/dev/forgeos/adapter/spring/ForgeExternalService.class +0 -0
  50. package/adapters/java-spring-boot-starter/target/classes/dev/forgeos/adapter/spring/ForgeQuery.class +0 -0
  51. package/adapters/java-spring-boot-starter/target/classes/dev/forgeos/adapter/spring/ForgeServiceBeanCondition.class +0 -0
  52. package/adapters/java-spring-boot-starter/target/classes/dev/forgeos/adapter/spring/ForgeSpringAutoConfiguration.class +0 -0
  53. package/adapters/java-spring-boot-starter/target/classes/dev/forgeos/adapter/spring/ForgeSpringRuntime.class +0 -0
  54. package/adapters/java-spring-boot-starter/target/forge-java-spring-boot-starter-0.1.0-alpha.11.jar +0 -0
  55. package/adapters/java-spring-boot-starter/target/maven-archiver/pom.properties +0 -3
  56. package/adapters/java-spring-boot-starter/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst +0 -6
  57. package/adapters/java-spring-boot-starter/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst +0 -6
  58. package/examples/java-billing/target/classes/dev/forgeos/examples/billing/CreateInvoiceInput.class +0 -0
  59. package/examples/java-billing/target/classes/dev/forgeos/examples/billing/Invoice.class +0 -0
  60. package/examples/java-billing/target/classes/dev/forgeos/examples/billing/Main$EmptyInput.class +0 -0
  61. package/examples/java-billing/target/classes/dev/forgeos/examples/billing/Main$Options.class +0 -0
  62. package/examples/java-billing/target/classes/dev/forgeos/examples/billing/Main.class +0 -0
  63. package/examples/java-billing/target/java-billing-0.1.0-alpha.11-all.jar +0 -0
  64. package/examples/java-billing/target/java-billing-0.1.0-alpha.11.jar +0 -0
  65. package/examples/java-billing/target/maven-archiver/pom.properties +0 -3
  66. package/examples/java-billing/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst +0 -5
  67. package/examples/java-billing/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst +0 -3
package/.npmignore CHANGED
@@ -5,6 +5,12 @@ node_modules/
5
5
  .forge/
6
6
  tests/
7
7
  examples/
8
+ adapters/**/target/
9
+ examples/**/target/
10
+ *.class
11
+ *.jar
12
+ **/*.class
13
+ **/*.jar
8
14
  src/forge/_generated/**
9
15
  !src/forge/_generated/
10
16
  !src/forge/_generated/releaseManifest.json
package/AGENTS.md CHANGED
@@ -1,4 +1,4 @@
1
- // @forge-generated generator=0.1.0-alpha.26 input=23c00c5407aab4088b55b49905f2b195667a75b8544fa180786ac637ee67e1e5 content=0d493cf0e41b71cb652d5e0e1b0c1f83d2a1281b748321f0b00f0773ba93074e
1
+ // @forge-generated generator=0.1.0-alpha.27 input=6c5ffcc15b409d33158dc8e5a5c4684c2d59b0e31e7c9064bdb6dacbe95ac874 content=0d493cf0e41b71cb652d5e0e1b0c1f83d2a1281b748321f0b00f0773ba93074e
2
2
  # AGENTS.md
3
3
 
4
4
  <!-- forge-generated:start -->
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # forgeos
2
2
 
3
+ ## 0.1.0-alpha.27
4
+
5
+ ### Patch Changes
6
+
7
+ - Stabilize `forge add convex` and generated integration artifacts.
8
+
9
+ - Re-emit integration adapters, docs, and testkits from the main generator so `forge generate --check` and `forge verify --smoke` stay clean after `forge add`.
10
+ - Keep partial `forge add` plans from deleting unrelated generated files before the full generator can reconcile the workspace.
11
+ - Include changed package-manager files such as `package.json` and lockfiles in `forge add --json` handoffs.
12
+ - Replace stale fast-check manifest hashes instead of merging them, and invalidate old manifest schemas to avoid phantom generated drift.
13
+ - Skip Bun module mock registration when the active Bun runtime does not expose `Bun.mock.module`, while still applying mock secret env vars.
14
+ - Filter generated and operational filesystem noise from `forge changed --authored` in non-git workspaces.
15
+ - Keep Java build outputs such as `target/`, `.class`, and `.jar` files out of the published npm tarball.
16
+
3
17
  ## 0.1.0-alpha.26
4
18
 
5
19
  ### Patch Changes
package/bin/forge.mjs CHANGED
File without changes
package/docs/changelog.md CHANGED
@@ -6,6 +6,19 @@ The canonical source file in the repository is `CHANGELOG.md`.
6
6
 
7
7
  ## Unreleased
8
8
 
9
+ ## 0.1.0-alpha.27
10
+
11
+ - Stabilized the `forge add convex` loop: integration docs/testkits are now
12
+ re-emitted by the main generator, partial `forge add` plans no longer remove
13
+ unrelated generated files, stale fast-check manifest hashes are pruned instead
14
+ of merged, and `forge add --json` includes changed package-manager files.
15
+ - Made runtime mock mode tolerate Bun builds without `Bun.mock.module` while
16
+ still applying mock secret environment variables.
17
+ - Filtered generated and operational filesystem noise from
18
+ `forge changed --authored` in non-git workspaces.
19
+ - Excluded Java build outputs such as `target/`, `.class`, and `.jar` files
20
+ from the published npm tarball.
21
+
9
22
  ## 0.1.0-alpha.26
10
23
 
11
24
  - Hardened the field-demo loop after the Team Onboarding app exercise:
package/package.json CHANGED
@@ -1,16 +1,22 @@
1
1
  {
2
2
  "name": "forgeos",
3
- "version": "0.1.0-alpha.26",
3
+ "version": "0.1.0-alpha.27",
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",
7
7
  "files": [
8
8
  "adapters/",
9
+ "!adapters/**/target/**",
10
+ "!adapters/**/*.class",
11
+ "!adapters/**/*.jar",
9
12
  "bin/",
10
13
  "docs/cair-protocol.md",
11
14
  "docs/forge-protocol.md",
12
15
  "examples/go-billing/",
13
16
  "examples/java-billing/",
17
+ "!examples/**/target/**",
18
+ "!examples/**/*.class",
19
+ "!examples/**/*.jar",
14
20
  "packages/eslint-plugin-forge/",
15
21
  "schemas/",
16
22
  "src/",
@@ -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.26","releaseId":"forgeos@0.1.0-alpha.26+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.27","releaseId":"forgeos@0.1.0-alpha.27+unknown","schemaVersion":"0.1.0"}
@@ -1,4 +1,4 @@
1
- // @forge-generated generator=0.1.0-alpha.26 input=23c00c5407aab4088b55b49905f2b195667a75b8544fa180786ac637ee67e1e5 content=967d4e05aa540b3e3d843fa6ed4516658ab4c364c1d8c42a14f36c57b75dff71
1
+ // @forge-generated generator=0.1.0-alpha.27 input=6c5ffcc15b409d33158dc8e5a5c4684c2d59b0e31e7c9064bdb6dacbe95ac874 content=3a34de2474ecf200ab734c0a01f9dd2c6a780af76bd650d3238c8b46313542b3
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.26",
23
- "releaseId": "forgeos@0.1.0-alpha.26+unknown",
22
+ "packageVersion": "0.1.0-alpha.27",
23
+ "releaseId": "forgeos@0.1.0-alpha.27+unknown",
24
24
  "schemaVersion": "0.1.0"
25
25
  } as const;
@@ -1,5 +1,9 @@
1
1
  import type { CategorizedFileSummary, DiffPlan } from "../workspace/change-summary.ts";
2
- import { buildDiffPlanFromChangeSummary, summarizeChangeTypes } from "../workspace/change-summary.ts";
2
+ import {
3
+ buildDiffPlanFromChangeSummary,
4
+ filterCategorizedSummary,
5
+ summarizeChangeTypes,
6
+ } from "../workspace/change-summary.ts";
3
7
  import { buildWorkspaceGitSummary, type WorkspaceGitSummary } from "../workspace/git-summary.ts";
4
8
 
5
9
  export interface ChangedCommandResult {
@@ -39,6 +43,8 @@ interface GeneratedChangeExplanation {
39
43
  summary: string;
40
44
  }
41
45
 
46
+ const AUTHORED_CHANGE_TYPES = ["source", "tests", "docs", "config", "assets", "other"] as const;
47
+
42
48
  function emptyCategory(summary: CategorizedFileSummary, category: keyof CategorizedFileSummary["byType"]): boolean {
43
49
  return summary.byType[category].count === 0;
44
50
  }
@@ -183,23 +189,22 @@ export function runChangedCommand(workspaceRoot: string, options: { authoredOnly
183
189
  const changed = git.changeSummary.changed;
184
190
  const humanChanges = selectHumanChangeSummary(changed);
185
191
  const derivedChanges = selectDerivedChangeSummary(changed);
186
- const authoredChanged: CategorizedFileSummary = {
187
- ...changed,
188
- total: { ...changed.total, count: humanChanges.total },
189
- byType: {
190
- ...changed.byType,
191
- generated: { count: 0, sample: [], hidden: 0 },
192
- },
193
- primaryTypes: changed.primaryTypes.filter((type) => type !== "generated"),
194
- };
192
+ const authoredChanged = filterCategorizedSummary(changed, [...AUTHORED_CHANGE_TYPES]);
193
+ const authoredStaged = filterCategorizedSummary(git.changeSummary.staged, [...AUTHORED_CHANGE_TYPES]);
194
+ const authoredUnstaged = filterCategorizedSummary(git.changeSummary.unstaged, [...AUTHORED_CHANGE_TYPES]);
195
+ const authoredUntracked = filterCategorizedSummary(git.changeSummary.untracked, [...AUTHORED_CHANGE_TYPES]);
196
+ const viewHumanChanges = options.authoredOnly ? selectHumanChangeSummary(authoredChanged) : humanChanges;
195
197
  const viewChanged = options.authoredOnly ? authoredChanged : changed;
198
+ const viewStaged = options.authoredOnly ? authoredStaged : git.changeSummary.staged;
199
+ const viewUnstaged = options.authoredOnly ? authoredUnstaged : git.changeSummary.unstaged;
200
+ const viewUntracked = options.authoredOnly ? authoredUntracked : git.changeSummary.untracked;
196
201
  const viewDerivedChanges: DerivedChangeSummary = options.authoredOnly
197
202
  ? { total: 0, generated: { count: 0, sample: [], hidden: 0 } }
198
203
  : derivedChanges;
199
204
  const risks = buildRisks(git);
200
205
  const recommendedCommands = buildRecommendedCommands(git);
201
- const reviewFocus = buildReviewFocus(humanChanges, viewDerivedChanges);
202
- const generatedExplanation = buildGeneratedChangeExplanation(humanChanges, viewDerivedChanges);
206
+ const reviewFocus = buildReviewFocus(viewHumanChanges, viewDerivedChanges);
207
+ const generatedExplanation = buildGeneratedChangeExplanation(viewHumanChanges, viewDerivedChanges);
203
208
  const diffPlan: DiffPlan = buildDiffPlanFromChangeSummary(viewChanged);
204
209
  const ok = git.available || git.source === "filesystem";
205
210
 
@@ -213,11 +218,11 @@ export function runChangedCommand(workspaceRoot: string, options: { authoredOnly
213
218
  commit: git.commit,
214
219
  view: options.authoredOnly ? "authored" : "all",
215
220
  changedFiles: viewChanged.total.count,
216
- humanFiles: humanChanges.total,
221
+ humanFiles: viewHumanChanges.total,
217
222
  generatedFiles: viewDerivedChanges.total,
218
- stagedFiles: git.staged.count,
219
- unstagedFiles: git.unstaged.count,
220
- untrackedFiles: git.untracked.count,
223
+ stagedFiles: viewStaged.total.count,
224
+ unstagedFiles: viewUnstaged.total.count,
225
+ untrackedFiles: viewUntracked.total.count,
221
226
  primaryTypes: viewChanged.primaryTypes,
222
227
  changeTypes: summarizeChangeTypes(viewChanged),
223
228
  },
@@ -228,11 +233,11 @@ export function runChangedCommand(workspaceRoot: string, options: { authoredOnly
228
233
  branch: git.branch,
229
234
  commit: git.commit,
230
235
  changed: viewChanged,
231
- staged: git.changeSummary.staged,
232
- unstaged: git.changeSummary.unstaged,
233
- untracked: git.changeSummary.untracked,
236
+ staged: viewStaged,
237
+ unstaged: viewUnstaged,
238
+ untracked: viewUntracked,
234
239
  },
235
- humanChanges,
240
+ humanChanges: viewHumanChanges,
236
241
  derivedChanges: viewDerivedChanges,
237
242
  reviewFocus,
238
243
  generatedExplanation,
@@ -157,11 +157,11 @@ export function buildAddJson(result: ForgeAddResult): Record<string, unknown> {
157
157
  const integrationNextActions =
158
158
  result.exitCode === 0 && result.mode === "integration" && result.targetKind === "forge-integration"
159
159
  ? [
160
+ "forge generate",
160
161
  ...(result.recipePackages ?? []).map((pkg) => `forge deps inspect ${pkg} --json`),
161
162
  ...((result.requiredSecrets?.length ?? 0) > 0 || (result.optionalSecrets?.length ?? 0) > 0
162
163
  ? ["forge secrets check --json", "forge inspect secrets --json"]
163
164
  : []),
164
- "forge generate",
165
165
  "forge check --json",
166
166
  "forge verify --smoke",
167
167
  ]
@@ -344,6 +344,39 @@ function dependencyFromInstall(
344
344
  };
345
345
  }
346
346
 
347
+ function fileHashOrNull(path: string): string | null {
348
+ if (!nodeFileSystem.exists(path)) {
349
+ return null;
350
+ }
351
+ return hashStable(nodeFileSystem.readText(path) ?? "");
352
+ }
353
+
354
+ function snapshotPackageManagerFiles(
355
+ workspaceRoot: string,
356
+ pm: PackageManagerAdapter,
357
+ ): Map<string, string | null> {
358
+ const paths = ["package.json", pm.lockfile];
359
+ return new Map(
360
+ paths.map((path) => [
361
+ path,
362
+ fileHashOrNull(join(workspaceRoot, path)),
363
+ ]),
364
+ );
365
+ }
366
+
367
+ function changedPackageManagerFiles(
368
+ workspaceRoot: string,
369
+ before: Map<string, string | null>,
370
+ ): string[] {
371
+ const changed: string[] = [];
372
+ for (const [path, previousHash] of before) {
373
+ if (fileHashOrNull(join(workspaceRoot, path)) !== previousHash) {
374
+ changed.push(path);
375
+ }
376
+ }
377
+ return changed.sort();
378
+ }
379
+
347
380
  async function analyzeRecipePackages(
348
381
  recipe: NonNullable<ReturnType<typeof resolveRecipe>>,
349
382
  ctx: ReturnType<typeof discover>,
@@ -635,6 +668,7 @@ export async function forgeAdd(
635
668
  const snapshot = snapshotVersionControlled(options.workspaceRoot);
636
669
 
637
670
  try {
671
+ const packageManagerBefore = snapshotPackageManagerFiles(options.workspaceRoot, pm);
638
672
  for (const pkg of recipe.packages) {
639
673
  await pm.add(pkg.packageName, {
640
674
  cwd: options.workspaceRoot,
@@ -735,7 +769,10 @@ export async function forgeAdd(
735
769
  alias: normalized,
736
770
  mode: "integration",
737
771
  ...recipeResultMetadata(recipe),
738
- changed: emitResult.changed,
772
+ changed: [
773
+ ...changedPackageManagerFiles(options.workspaceRoot, packageManagerBefore),
774
+ ...emitResult.changed,
775
+ ],
739
776
  unchanged: emitResult.unchanged,
740
777
  warnings: warningsCombined,
741
778
  errors: [],
@@ -20,7 +20,6 @@ import { PACKAGE_ANALYZER_VERSION } from "../package-graph/constants.ts";
20
20
  import { RECIPE_SCHEMA_VERSION } from "../recipes/definitions.ts";
21
21
  import { hashStable } from "../primitives/hash.ts";
22
22
  import { stableSortEmitFiles, stableSortStrings } from "../primitives/index.ts";
23
- import { detectOrphanedGeneratedFiles } from "../orchestrator/orphans.ts";
24
23
  import type { DiscoverContext } from "../orchestrator/types.ts";
25
24
  import {
26
25
  createRenderContext,
@@ -254,17 +253,9 @@ export function buildIntegrationEmitPlan(input: IntegrationPlanInput): EmitPlan
254
253
  const lockEntry = buildLockEntry(recipe, classified, generatedFiles);
255
254
  const lock = mergeLockPackages(input.existingLock, lockEntry, ctx);
256
255
 
257
- const sortedFiles = stableSortEmitFiles(files);
258
- const plannedPathSet = new Set(sortedFiles.map((file) => file.path));
259
- const orphanedFiles = detectOrphanedGeneratedFiles(
260
- ctx.workspaceRoot,
261
- ctx.generatedDir,
262
- plannedPathSet,
263
- );
264
-
265
256
  return {
266
- files: sortedFiles,
267
- orphanedFiles,
257
+ files: stableSortEmitFiles(files),
258
+ orphanedFiles: [],
268
259
  lock,
269
260
  };
270
261
  }
@@ -8,6 +8,7 @@ import type { GenerateResult } from "../types/cli.ts";
8
8
  import type { Diagnostic } from "../types/diagnostic.ts";
9
9
  import { discover } from "./discover.ts";
10
10
  import { loadManifest } from "./manifest.ts";
11
+ import { ORCHESTRATOR_MANIFEST_VERSION } from "./types.ts";
11
12
 
12
13
  export type FastGenerateCheckResult =
13
14
  | {
@@ -55,6 +56,9 @@ export function runFastGenerateCheck(workspaceRootInput: string): FastGenerateCh
55
56
  const manifest = loadManifest(cacheDir);
56
57
  const trackedFiles = Object.keys(manifest.fileHashes).sort();
57
58
 
59
+ if (manifest.schemaVersion !== ORCHESTRATOR_MANIFEST_VERSION) {
60
+ return { kind: "miss", reason: "manifest schema version changed" };
61
+ }
58
62
  if (!manifest.inputFingerprint || trackedFiles.length === 0) {
59
63
  return { kind: "miss", reason: "manifest missing input fingerprint or file hashes" };
60
64
  }
@@ -83,7 +83,7 @@ export function updateManifestAfterWrite(
83
83
  ): OrchestratorManifest {
84
84
  return {
85
85
  ...manifest,
86
- fileHashes: { ...manifest.fileHashes, ...fileHashes },
86
+ fileHashes,
87
87
  priorAppGraph,
88
88
  inputFingerprint,
89
89
  ...(sourceFileIndex !== undefined ? { sourceFileIndex } : {}),
@@ -94,6 +94,8 @@ import { detectCapabilities } from "../classifier/capabilities.ts";
94
94
  import { detectSecrets } from "../classifier/secrets.ts";
95
95
  import { resolveByPackageName } from "../recipes/registry.ts";
96
96
  import { RECIPE_SCHEMA_VERSION } from "../recipes/definitions.ts";
97
+ import type { IntegrationRecipe } from "../types/integration.ts";
98
+ import type { RuntimeContext } from "../types/runtime.ts";
97
99
  import {
98
100
  FORGE_LOCK_SCHEMA_VERSION,
99
101
  GENERATED_DIR,
@@ -104,6 +106,14 @@ import { hashStable } from "../primitives/hash.ts";
104
106
  import { stableSortEmitFiles } from "../primitives/sort.ts";
105
107
  import { detectOrphanedGeneratedFiles } from "./orphans.ts";
106
108
  import type { DiscoverContext } from "./types.ts";
109
+ import {
110
+ createRenderContext,
111
+ parseAdapterContext,
112
+ renderAdapterModule,
113
+ renderIntegrationDoc,
114
+ renderIntegrationModule,
115
+ renderTestkitModule,
116
+ } from "../integration/render.ts";
107
117
  import {
108
118
  serializeAppGraphJson,
109
119
  serializeDataGraphJson,
@@ -233,6 +243,156 @@ function makeEmitFile(path: string, content: string): EmitFile {
233
243
  };
234
244
  }
235
245
 
246
+ function primaryPackageName(recipe: IntegrationRecipe): string {
247
+ return recipe.packages[0]?.packageName ?? recipe.alias;
248
+ }
249
+
250
+ function packageNamesForRecipe(recipe: IntegrationRecipe): string[] {
251
+ return recipe.packages.map((pkg) => pkg.packageName);
252
+ }
253
+
254
+ function compatibleContextsForRecipe(pkg: ClassifiedPackage): RuntimeContext[] {
255
+ const recipe = pkg.recipe ?? resolveByPackageName(pkg.api.name);
256
+ if (!recipe) {
257
+ return [...pkg.classification.compatible];
258
+ }
259
+
260
+ const contexts = new Set<RuntimeContext>(recipe.contexts.allowed);
261
+ for (const recipePackage of recipe.packages) {
262
+ for (const ctx of recipePackage.contexts?.allowed ?? []) {
263
+ contexts.add(ctx);
264
+ }
265
+ }
266
+ for (const ctx of pkg.classification.compatible) {
267
+ contexts.add(ctx);
268
+ }
269
+ return [...contexts];
270
+ }
271
+
272
+ function shouldEmitAdapter(
273
+ adapterFilename: string,
274
+ compatible: RuntimeContext[],
275
+ ): boolean {
276
+ const context = parseAdapterContext(adapterFilename);
277
+ return context === null || compatible.includes(context);
278
+ }
279
+
280
+ function buildRecipeGeneratedFiles(pkg: ClassifiedPackage): string[] {
281
+ const recipe = pkg.recipe ?? resolveByPackageName(pkg.api.name);
282
+ if (!recipe) {
283
+ return [];
284
+ }
285
+
286
+ const compatible = compatibleContextsForRecipe(pkg);
287
+ const paths: string[] = [];
288
+
289
+ for (const adapter of recipe.adapters) {
290
+ if (shouldEmitAdapter(adapter, compatible)) {
291
+ paths.push(`${GENERATED_DIR}/packages/${adapter}`);
292
+ }
293
+ }
294
+ for (const integration of recipe.integrations ?? []) {
295
+ paths.push(`${GENERATED_DIR}/integrations/${integration}`);
296
+ }
297
+ for (const testkit of recipe.testkits) {
298
+ paths.push(`${GENERATED_DIR}/testkits/${testkit}`);
299
+ }
300
+ for (const doc of recipe.docs) {
301
+ paths.push(`${GENERATED_DIR}/docs/${doc}`);
302
+ }
303
+
304
+ paths.push(
305
+ `${GENERATED_DIR}/runtimeMatrix.ts`,
306
+ `${GENERATED_DIR}/runtimeMatrix.json`,
307
+ `${GENERATED_DIR}/importGuards.ts`,
308
+ `${GENERATED_DIR}/importGuards.json`,
309
+ );
310
+
311
+ return paths.sort();
312
+ }
313
+
314
+ function buildIntegrationArtifactFiles(pkg: ClassifiedPackage): EmitFile[] {
315
+ const recipe = pkg.recipe ?? resolveByPackageName(pkg.api.name);
316
+ if (!recipe) {
317
+ return [];
318
+ }
319
+
320
+ const compatible = compatibleContextsForRecipe(pkg);
321
+ const incompatible = [...pkg.classification.incompatible];
322
+ const secrets = detectSecrets(pkg.api, recipe);
323
+ const packageNames = packageNamesForRecipe(recipe);
324
+ const packageName = primaryPackageName(recipe);
325
+ const templateCtx = createRenderContext({
326
+ alias: recipe.alias,
327
+ recipe,
328
+ context: "server",
329
+ packageName,
330
+ packageNames,
331
+ secrets,
332
+ compatible,
333
+ incompatible,
334
+ });
335
+ const files: EmitFile[] = [];
336
+
337
+ for (const adapter of recipe.adapters) {
338
+ if (!shouldEmitAdapter(adapter, compatible)) {
339
+ continue;
340
+ }
341
+ const context = parseAdapterContext(adapter) ?? "server";
342
+ files.push(
343
+ makeEmitFile(
344
+ `${GENERATED_DIR}/packages/${adapter}`,
345
+ renderAdapterModule({
346
+ alias: recipe.alias,
347
+ recipe,
348
+ context,
349
+ packageName,
350
+ packageNames,
351
+ secrets,
352
+ compatible,
353
+ incompatible,
354
+ }),
355
+ ),
356
+ );
357
+ }
358
+
359
+ for (const integration of recipe.integrations ?? []) {
360
+ files.push(
361
+ makeEmitFile(
362
+ `${GENERATED_DIR}/integrations/${integration}`,
363
+ renderIntegrationModule(integration, templateCtx),
364
+ ),
365
+ );
366
+ }
367
+
368
+ for (const testkit of recipe.testkits) {
369
+ files.push(
370
+ makeEmitFile(
371
+ `${GENERATED_DIR}/testkits/${testkit}`,
372
+ renderTestkitModule(recipe.alias, packageName, templateCtx),
373
+ ),
374
+ );
375
+ }
376
+
377
+ for (const doc of recipe.docs) {
378
+ files.push(
379
+ makeEmitFile(
380
+ `${GENERATED_DIR}/docs/${doc}`,
381
+ renderIntegrationDoc({
382
+ alias: recipe.alias,
383
+ recipe,
384
+ packageNames,
385
+ secrets,
386
+ compatible,
387
+ incompatible,
388
+ }),
389
+ ),
390
+ );
391
+ }
392
+
393
+ return files;
394
+ }
395
+
236
396
  function buildLockEntry(pkg: ClassifiedPackage): ForgeLockEntry {
237
397
  const recipe = pkg.recipe ?? resolveByPackageName(pkg.api.name);
238
398
  const secrets = detectSecrets(pkg.api, recipe ?? undefined);
@@ -250,7 +410,7 @@ function buildLockEntry(pkg: ClassifiedPackage): ForgeLockEntry {
250
410
  secrets,
251
411
  },
252
412
  secrets,
253
- generatedFiles: [],
413
+ generatedFiles: buildRecipeGeneratedFiles(pkg),
254
414
  contentChecksum: pkg.api.contentChecksum,
255
415
  };
256
416
  }
@@ -412,6 +572,7 @@ export function plan(input: PlanInput): EmitPlan {
412
572
  apiSurface,
413
573
  sources: input.ctx.sources,
414
574
  });
575
+ const integrationArtifactFiles = input.classified.flatMap(buildIntegrationArtifactFiles);
415
576
  const supportArtifactsMs = performance.now() - checkpoint;
416
577
  checkpoint = performance.now();
417
578
 
@@ -517,6 +678,7 @@ export function plan(input: PlanInput): EmitPlan {
517
678
  `${GENERATED_DIR}/importGuards.json`,
518
679
  serializeImportGuardsJson(matrix, input.appGraph.moduleGraph),
519
680
  ),
681
+ ...integrationArtifactFiles,
520
682
  makeEmitFile(
521
683
  `${GENERATED_DIR}/dataGraph.ts`,
522
684
  serializeDataGraphTs(dataGraph),
@@ -3,7 +3,7 @@ import type { Dependency } from "../types/package-graph.ts";
3
3
  import type { PackageManager } from "../types/runtime.ts";
4
4
  import type { SourceFileIndex } from "./workspace-index.ts";
5
5
 
6
- export const ORCHESTRATOR_MANIFEST_VERSION = "1";
6
+ export const ORCHESTRATOR_MANIFEST_VERSION = "2";
7
7
 
8
8
  export interface DiscoverContext {
9
9
  workspaceRoot: string;
@@ -213,6 +213,23 @@ function capitalizeSegment(value: string): string {
213
213
  }
214
214
 
215
215
  async function applyMocks(workspaceRoot: string, lock: ForgeLock | null): Promise<void> {
216
+ if (lock) {
217
+ for (const pkg of lock.packages) {
218
+ for (const secret of pkg.secrets) {
219
+ if (!process.env[secret.envVar]) {
220
+ process.env[secret.envVar] = `sk_forge_mock_${secret.envVar.toLowerCase()}`;
221
+ }
222
+ }
223
+ }
224
+ }
225
+
226
+ const bunMock = (globalThis as typeof globalThis & {
227
+ Bun?: { mock?: { module?: (specifier: string, factory: () => unknown) => void } };
228
+ }).Bun?.mock;
229
+ if (typeof bunMock?.module !== "function") {
230
+ return;
231
+ }
232
+
216
233
  const mockMap = loadMockMap(workspaceRoot);
217
234
 
218
235
  for (const [packageName, relativePath] of Object.entries(mockMap).sort()) {
@@ -225,11 +242,7 @@ async function applyMocks(workspaceRoot: string, lock: ForgeLock | null): Promis
225
242
  const factoryName = `create${capitalizeSegment(packageName)}Mock`;
226
243
  const factory = mod[factoryName];
227
244
 
228
- const bunMock = Bun as typeof Bun & {
229
- mock: { module: (specifier: string, factory: () => unknown) => void };
230
- };
231
-
232
- bunMock.mock.module(packageName, () => {
245
+ bunMock.module(packageName, () => {
233
246
  if (typeof factory === "function") {
234
247
  const mockValue = (factory as () => unknown)();
235
248
  if (typeof mockValue === "function") {
@@ -243,16 +256,6 @@ async function applyMocks(workspaceRoot: string, lock: ForgeLock | null): Promis
243
256
  return mod;
244
257
  });
245
258
  }
246
-
247
- if (lock) {
248
- for (const pkg of lock.packages) {
249
- for (const secret of pkg.secrets) {
250
- if (!process.env[secret.envVar]) {
251
- process.env[secret.envVar] = `sk_forge_mock_${secret.envVar.toLowerCase()}`;
252
- }
253
- }
254
- }
255
- }
256
259
  }
257
260
 
258
261
  let activeDbAdapter: DbAdapter | null = null;
@@ -1,3 +1,3 @@
1
- export const FORGEOS_VERSION = "0.1.0-alpha.26";
1
+ export const FORGEOS_VERSION = "0.1.0-alpha.27";
2
2
  export const GENERATOR_VERSION = FORGEOS_VERSION;
3
3
  export const CLI_VERSION = FORGEOS_VERSION;
@@ -183,6 +183,40 @@ export function categorizeFiles(
183
183
  };
184
184
  }
185
185
 
186
+ export function filterCategorizedSummary(
187
+ summary: CategorizedFileSummary,
188
+ includeTypes: ChangeType[],
189
+ sampleSize = 8,
190
+ ): CategorizedFileSummary {
191
+ const include = new Set(includeTypes);
192
+ const byType = Object.fromEntries(
193
+ CHANGE_TYPES.map((type) => {
194
+ const current = summary.byType[type];
195
+ return [
196
+ type,
197
+ include.has(type) ? current : { count: 0, sample: [], hidden: 0 },
198
+ ];
199
+ }),
200
+ ) as Record<ChangeType, FileListSummary>;
201
+ const totalCount = includeTypes.reduce((count, type) => count + summary.byType[type].count, 0);
202
+ const totalSample = includeTypes
203
+ .flatMap((type) => summary.byType[type].sample)
204
+ .sort()
205
+ .slice(0, sampleSize);
206
+ const primaryTypes = CHANGE_TYPES
207
+ .filter((type) => byType[type].count > 0)
208
+ .sort((left, right) => byType[right].count - byType[left].count);
209
+ return {
210
+ total: {
211
+ count: totalCount,
212
+ sample: totalSample,
213
+ hidden: Math.max(0, totalCount - totalSample.length),
214
+ },
215
+ byType,
216
+ primaryTypes,
217
+ };
218
+ }
219
+
186
220
  export function summarizeChangeTypes(summary: CategorizedFileSummary): string {
187
221
  return summary.primaryTypes
188
222
  .slice(0, 5)
@@ -1,3 +0,0 @@
1
- artifactId=forge-java-adapter
2
- groupId=dev.forgeos
3
- version=0.1.0-alpha.11
@@ -1,23 +0,0 @@
1
- dev/forgeos/adapter/TypedForgeHandler.class
2
- dev/forgeos/adapter/Forge.class
3
- dev/forgeos/adapter/Diagnostic.class
4
- dev/forgeos/adapter/ForgeHttpHandler.class
5
- dev/forgeos/adapter/Service.class
6
- dev/forgeos/adapter/Schemas.class
7
- dev/forgeos/adapter/ForgeCall.class
8
- dev/forgeos/adapter/Risk.class
9
- dev/forgeos/adapter/ForgeHandler.class
10
- dev/forgeos/adapter/Entry.class
11
- dev/forgeos/adapter/TransactionMode.class
12
- dev/forgeos/adapter/ResponseEnvelope.class
13
- dev/forgeos/adapter/RequestEnvelope.class
14
- dev/forgeos/adapter/ForgeRegistry$RegistryOption.class
15
- dev/forgeos/adapter/Auth.class
16
- dev/forgeos/adapter/Manifest.class
17
- dev/forgeos/adapter/ForgeContext.class
18
- dev/forgeos/adapter/ForgeRegistry$RegisteredEntry.class
19
- dev/forgeos/adapter/ForgeRegistry$EntryOption.class
20
- dev/forgeos/adapter/EntryKind.class
21
- dev/forgeos/adapter/ForgeRegistry.class
22
- dev/forgeos/adapter/ErrorInfo.class
23
- dev/forgeos/adapter/Json.class
@@ -1,20 +0,0 @@
1
- /home/runner/work/forge/forge/adapters/java/src/main/java/dev/forgeos/adapter/Auth.java
2
- /home/runner/work/forge/forge/adapters/java/src/main/java/dev/forgeos/adapter/Diagnostic.java
3
- /home/runner/work/forge/forge/adapters/java/src/main/java/dev/forgeos/adapter/Entry.java
4
- /home/runner/work/forge/forge/adapters/java/src/main/java/dev/forgeos/adapter/EntryKind.java
5
- /home/runner/work/forge/forge/adapters/java/src/main/java/dev/forgeos/adapter/ErrorInfo.java
6
- /home/runner/work/forge/forge/adapters/java/src/main/java/dev/forgeos/adapter/Forge.java
7
- /home/runner/work/forge/forge/adapters/java/src/main/java/dev/forgeos/adapter/ForgeCall.java
8
- /home/runner/work/forge/forge/adapters/java/src/main/java/dev/forgeos/adapter/ForgeContext.java
9
- /home/runner/work/forge/forge/adapters/java/src/main/java/dev/forgeos/adapter/ForgeHandler.java
10
- /home/runner/work/forge/forge/adapters/java/src/main/java/dev/forgeos/adapter/ForgeHttpHandler.java
11
- /home/runner/work/forge/forge/adapters/java/src/main/java/dev/forgeos/adapter/ForgeRegistry.java
12
- /home/runner/work/forge/forge/adapters/java/src/main/java/dev/forgeos/adapter/Json.java
13
- /home/runner/work/forge/forge/adapters/java/src/main/java/dev/forgeos/adapter/Manifest.java
14
- /home/runner/work/forge/forge/adapters/java/src/main/java/dev/forgeos/adapter/RequestEnvelope.java
15
- /home/runner/work/forge/forge/adapters/java/src/main/java/dev/forgeos/adapter/ResponseEnvelope.java
16
- /home/runner/work/forge/forge/adapters/java/src/main/java/dev/forgeos/adapter/Risk.java
17
- /home/runner/work/forge/forge/adapters/java/src/main/java/dev/forgeos/adapter/Schemas.java
18
- /home/runner/work/forge/forge/adapters/java/src/main/java/dev/forgeos/adapter/Service.java
19
- /home/runner/work/forge/forge/adapters/java/src/main/java/dev/forgeos/adapter/TransactionMode.java
20
- /home/runner/work/forge/forge/adapters/java/src/main/java/dev/forgeos/adapter/TypedForgeHandler.java
@@ -1,3 +0,0 @@
1
- artifactId=forge-java-spring-boot-starter
2
- groupId=dev.forgeos
3
- version=0.1.0-alpha.11
@@ -1,6 +0,0 @@
1
- dev/forgeos/adapter/spring/ForgeServiceBeanCondition.class
2
- dev/forgeos/adapter/spring/ForgeSpringRuntime.class
3
- dev/forgeos/adapter/spring/ForgeExternalService.class
4
- dev/forgeos/adapter/spring/ForgeSpringAutoConfiguration.class
5
- dev/forgeos/adapter/spring/ForgeQuery.class
6
- dev/forgeos/adapter/spring/ForgeCommand.class
@@ -1,6 +0,0 @@
1
- /home/runner/work/forge/forge/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeCommand.java
2
- /home/runner/work/forge/forge/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeExternalService.java
3
- /home/runner/work/forge/forge/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeQuery.java
4
- /home/runner/work/forge/forge/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeServiceBeanCondition.java
5
- /home/runner/work/forge/forge/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeSpringAutoConfiguration.java
6
- /home/runner/work/forge/forge/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeSpringRuntime.java
@@ -1,3 +0,0 @@
1
- artifactId=java-billing
2
- groupId=dev.forgeos.examples
3
- version=0.1.0-alpha.11
@@ -1,5 +0,0 @@
1
- dev/forgeos/examples/billing/Main.class
2
- dev/forgeos/examples/billing/Invoice.class
3
- dev/forgeos/examples/billing/Main$EmptyInput.class
4
- dev/forgeos/examples/billing/Main$Options.class
5
- dev/forgeos/examples/billing/CreateInvoiceInput.class
@@ -1,3 +0,0 @@
1
- /home/runner/work/forge/forge/examples/java-billing/src/main/java/dev/forgeos/examples/billing/CreateInvoiceInput.java
2
- /home/runner/work/forge/forge/examples/java-billing/src/main/java/dev/forgeos/examples/billing/Invoice.java
3
- /home/runner/work/forge/forge/examples/java-billing/src/main/java/dev/forgeos/examples/billing/Main.java