forgeos 0.1.0-alpha.0 → 0.1.0-alpha.2

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 (283) hide show
  1. package/.npmignore +9 -1
  2. package/AGENTS.md +6 -1
  3. package/CHANGELOG.md +30 -0
  4. package/CONTRIBUTING.md +22 -1
  5. package/README.md +30 -3
  6. package/bin/forge.mjs +4 -3
  7. package/package.json +3 -1
  8. package/packages/eslint-plugin-forge/index.ts +15 -15
  9. package/packages/eslint-plugin-forge/package.json +10 -10
  10. package/packages/eslint-plugin-forge/src/check-source.ts +95 -95
  11. package/packages/eslint-plugin-forge/src/load-artifacts.ts +24 -24
  12. package/packages/eslint-plugin-forge/src/rule-no-forge-guard-violation.ts +93 -93
  13. package/src/forge/_generated/actionSubscriptions.json +2 -2
  14. package/src/forge/_generated/actionSubscriptions.ts +3 -3
  15. package/src/forge/_generated/agentAdapterManifest.json +2 -2
  16. package/src/forge/_generated/agentAdapterManifest.ts +3 -3
  17. package/src/forge/_generated/agentContract.json +2 -2
  18. package/src/forge/_generated/agentContract.ts +6786 -2
  19. package/src/forge/_generated/agentQuickstart.md +1 -1
  20. package/src/forge/_generated/aiContext.ts +1 -1
  21. package/src/forge/_generated/aiModels.json +1 -1
  22. package/src/forge/_generated/aiModels.ts +1 -1
  23. package/src/forge/_generated/aiProviders.json +1 -1
  24. package/src/forge/_generated/aiProviders.ts +1 -1
  25. package/src/forge/_generated/aiRegistry.json +2 -2
  26. package/src/forge/_generated/aiRegistry.ts +3 -3
  27. package/src/forge/_generated/api.json +2 -2
  28. package/src/forge/_generated/api.ts +1 -1
  29. package/src/forge/_generated/appGraph.json +2 -2
  30. package/src/forge/_generated/appGraph.ts +1297 -1141
  31. package/src/forge/_generated/appMap.md +1 -1
  32. package/src/forge/_generated/artifactManifest.json +2 -2
  33. package/src/forge/_generated/artifactManifest.ts +2 -2
  34. package/src/forge/_generated/authClaims.json +1 -1
  35. package/src/forge/_generated/authClaims.ts +1 -1
  36. package/src/forge/_generated/authConfig.json +1 -1
  37. package/src/forge/_generated/authConfig.ts +1 -1
  38. package/src/forge/_generated/authContext.ts +1 -1
  39. package/src/forge/_generated/authRegistry.json +1 -1
  40. package/src/forge/_generated/authRegistry.ts +1 -1
  41. package/src/forge/_generated/buildInfo.json +2 -2
  42. package/src/forge/_generated/buildInfo.ts +4 -4
  43. package/src/forge/_generated/capabilityMap.json +2 -2
  44. package/src/forge/_generated/capabilityMap.md +1 -1
  45. package/src/forge/_generated/capabilityMap.ts +2 -2
  46. package/src/forge/_generated/client.ts +1 -1
  47. package/src/forge/_generated/clientApi.ts +1 -1
  48. package/src/forge/_generated/clientManifest.json +2 -2
  49. package/src/forge/_generated/clientManifest.ts +3 -3
  50. package/src/forge/_generated/clientTypes.ts +1 -1
  51. package/src/forge/_generated/configRegistry.json +1 -1
  52. package/src/forge/_generated/configRegistry.ts +1 -1
  53. package/src/forge/_generated/dataGraph.json +2 -2
  54. package/src/forge/_generated/dataGraph.ts +3 -3
  55. package/src/forge/_generated/db.json +1 -1
  56. package/src/forge/_generated/db.ts +1 -1
  57. package/src/forge/_generated/dbSecurityManifest.json +1 -1
  58. package/src/forge/_generated/dbSecurityManifest.ts +1 -1
  59. package/src/forge/_generated/dbSessionContext.json +1 -1
  60. package/src/forge/_generated/dbSessionContext.ts +1 -1
  61. package/src/forge/_generated/deployManifest.json +2 -2
  62. package/src/forge/_generated/deployManifest.ts +7 -7
  63. package/src/forge/_generated/devManifest.json +2 -2
  64. package/src/forge/_generated/devManifest.ts +3 -3
  65. package/src/forge/_generated/envSchema.json +1 -1
  66. package/src/forge/_generated/envSchema.ts +1 -1
  67. package/src/forge/_generated/frontendGraph.json +1 -1
  68. package/src/forge/_generated/frontendGraph.ts +1 -1
  69. package/src/forge/_generated/importGuards.json +2 -2
  70. package/src/forge/_generated/importGuards.ts +35 -1
  71. package/src/forge/_generated/index.ts +1 -1
  72. package/src/forge/_generated/liveProductionManifest.json +1 -1
  73. package/src/forge/_generated/liveProductionManifest.ts +1 -1
  74. package/src/forge/_generated/liveProtocol.json +1 -1
  75. package/src/forge/_generated/liveProtocol.ts +1 -1
  76. package/src/forge/_generated/liveQueryRegistry.json +2 -2
  77. package/src/forge/_generated/liveQueryRegistry.ts +3 -3
  78. package/src/forge/_generated/liveTransportConfig.json +1 -1
  79. package/src/forge/_generated/liveTransportConfig.ts +1 -1
  80. package/src/forge/_generated/makeRegistry.json +2 -2
  81. package/src/forge/_generated/makeRegistry.ts +2 -2
  82. package/src/forge/_generated/makeTemplates.json +1 -1
  83. package/src/forge/_generated/makeTemplates.ts +1 -1
  84. package/src/forge/_generated/mockMap.json +1 -1
  85. package/src/forge/_generated/mockMap.ts +1 -1
  86. package/src/forge/_generated/operationPlaybooks.md +7 -5
  87. package/src/forge/_generated/packageGraph.json +2 -2
  88. package/src/forge/_generated/packageGraph.ts +90964 -14284
  89. package/src/forge/_generated/packageUpgradeRegistry.json +2 -2
  90. package/src/forge/_generated/packageUpgradeRegistry.ts +2 -2
  91. package/src/forge/_generated/permissionMatrix.json +2 -2
  92. package/src/forge/_generated/permissionMatrix.ts +3 -3
  93. package/src/forge/_generated/policyRegistry.json +2 -2
  94. package/src/forge/_generated/policyRegistry.ts +3 -3
  95. package/src/forge/_generated/queryRegistry.json +2 -2
  96. package/src/forge/_generated/queryRegistry.ts +3 -3
  97. package/src/forge/_generated/react.d.ts +1 -1
  98. package/src/forge/_generated/react.ts +1 -1
  99. package/src/forge/_generated/reactManifest.json +2 -2
  100. package/src/forge/_generated/reactManifest.ts +3 -3
  101. package/src/forge/_generated/releaseManifest.json +2 -2
  102. package/src/forge/_generated/releaseManifest.ts +3 -3
  103. package/src/forge/_generated/rlsPolicies.json +1 -1
  104. package/src/forge/_generated/rlsPolicies.sql +1 -1
  105. package/src/forge/_generated/rlsPolicies.ts +1 -1
  106. package/src/forge/_generated/runtimeGraph.json +2 -2
  107. package/src/forge/_generated/runtimeGraph.ts +3 -3
  108. package/src/forge/_generated/runtimeMatrix.json +2 -2
  109. package/src/forge/_generated/runtimeMatrix.ts +106177 -7917
  110. package/src/forge/_generated/runtimeRegistry.ts +1 -1
  111. package/src/forge/_generated/runtimeRules.md +1 -1
  112. package/src/forge/_generated/secretRegistry.json +1 -1
  113. package/src/forge/_generated/secretRegistry.ts +1 -1
  114. package/src/forge/_generated/secretsContext.ts +1 -1
  115. package/src/forge/_generated/serverApi.ts +1 -1
  116. package/src/forge/_generated/sourceMapManifest.json +2 -2
  117. package/src/forge/_generated/sourceMapManifest.ts +2 -2
  118. package/src/forge/_generated/sqlPlan.json +1 -1
  119. package/src/forge/_generated/sqlPlan.ts +1 -1
  120. package/src/forge/_generated/subscriptionManifest.json +2 -2
  121. package/src/forge/_generated/subscriptionManifest.ts +3 -3
  122. package/src/forge/_generated/symbolicationManifest.json +2 -2
  123. package/src/forge/_generated/symbolicationManifest.ts +2 -2
  124. package/src/forge/_generated/telemetryRegistry.json +2 -2
  125. package/src/forge/_generated/telemetryRegistry.ts +3 -3
  126. package/src/forge/_generated/telemetrySinks.json +2 -2
  127. package/src/forge/_generated/telemetrySinks.ts +2 -2
  128. package/src/forge/_generated/tenantScope.json +2 -2
  129. package/src/forge/_generated/tenantScope.ts +3 -3
  130. package/src/forge/_generated/testGraph.json +2 -2
  131. package/src/forge/_generated/testGraph.ts +129 -75
  132. package/src/forge/_generated/testPlanRegistry.json +2 -2
  133. package/src/forge/_generated/testPlanRegistry.ts +2 -2
  134. package/src/forge/_generated/uiRoutes.json +1 -1
  135. package/src/forge/_generated/uiRoutes.ts +1 -1
  136. package/src/forge/_generated/uiScenarios.json +1 -1
  137. package/src/forge/_generated/uiScenarios.ts +1 -1
  138. package/src/forge/_generated/uiTestManifest.json +2 -2
  139. package/src/forge/_generated/uiTestManifest.ts +2 -2
  140. package/src/forge/_generated/workflowRegistry.json +2 -2
  141. package/src/forge/_generated/workflowRegistry.ts +3 -3
  142. package/src/forge/_generated/workflowSubscriptions.json +2 -2
  143. package/src/forge/_generated/workflowSubscriptions.ts +3 -3
  144. package/src/forge/cli/commands.ts +861 -861
  145. package/src/forge/cli/deps.ts +178 -11
  146. package/src/forge/cli/dev.ts +32 -5
  147. package/src/forge/cli/index.ts +7 -7
  148. package/src/forge/cli/main.ts +54 -54
  149. package/src/forge/cli/new.ts +29 -1
  150. package/src/forge/cli/output.ts +97 -97
  151. package/src/forge/cli/parse.ts +679 -673
  152. package/src/forge/cli/version.ts +1 -1
  153. package/src/forge/compiler/agent-contract/build.ts +28 -0
  154. package/src/forge/compiler/agent-contract/types.ts +16 -0
  155. package/src/forge/compiler/app-graph/build.ts +112 -112
  156. package/src/forge/compiler/app-graph/classify.ts +10 -10
  157. package/src/forge/compiler/app-graph/dup-symbol.ts +29 -29
  158. package/src/forge/compiler/app-graph/extract.ts +123 -123
  159. package/src/forge/compiler/app-graph/forge-apis.ts +29 -29
  160. package/src/forge/compiler/app-graph/index.ts +11 -11
  161. package/src/forge/compiler/app-graph/module-graph.ts +316 -316
  162. package/src/forge/compiler/app-graph/parser.ts +119 -119
  163. package/src/forge/compiler/app-graph/symbols.ts +48 -48
  164. package/src/forge/compiler/app-graph/tsconfig-hash.ts +62 -62
  165. package/src/forge/compiler/app-graph/types.ts +43 -43
  166. package/src/forge/compiler/app-graph/versions.ts +14 -14
  167. package/src/forge/compiler/cache/index.ts +17 -17
  168. package/src/forge/compiler/cache/key.ts +46 -46
  169. package/src/forge/compiler/cache/scheduler.ts +72 -72
  170. package/src/forge/compiler/cache/store.ts +78 -78
  171. package/src/forge/compiler/classifier/capabilities.ts +78 -78
  172. package/src/forge/compiler/classifier/classify.ts +113 -113
  173. package/src/forge/compiler/classifier/contexts.ts +188 -188
  174. package/src/forge/compiler/classifier/index.ts +18 -18
  175. package/src/forge/compiler/classifier/runtime-matrix.ts +45 -45
  176. package/src/forge/compiler/classifier/secrets.ts +41 -41
  177. package/src/forge/compiler/classifier/signals.ts +129 -129
  178. package/src/forge/compiler/diagnostics/codes.ts +125 -120
  179. package/src/forge/compiler/diagnostics/create.ts +87 -87
  180. package/src/forge/compiler/diagnostics/index.ts +41 -41
  181. package/src/forge/compiler/emitter/artifact-kind.ts +14 -14
  182. package/src/forge/compiler/emitter/barrel.ts +38 -38
  183. package/src/forge/compiler/emitter/constants.ts +7 -7
  184. package/src/forge/compiler/emitter/emit.ts +234 -237
  185. package/src/forge/compiler/emitter/index.ts +24 -24
  186. package/src/forge/compiler/emitter/lock.ts +61 -61
  187. package/src/forge/compiler/emitter/render.ts +73 -73
  188. package/src/forge/compiler/guards/artifacts.ts +96 -96
  189. package/src/forge/compiler/guards/check-import-guards.ts +106 -106
  190. package/src/forge/compiler/guards/index.ts +11 -11
  191. package/src/forge/compiler/guards/propagate-contexts.ts +57 -57
  192. package/src/forge/compiler/index.ts +17 -17
  193. package/src/forge/compiler/integration/add.ts +493 -493
  194. package/src/forge/compiler/integration/index.ts +17 -17
  195. package/src/forge/compiler/integration/plan.ts +279 -279
  196. package/src/forge/compiler/integration/render.ts +189 -189
  197. package/src/forge/compiler/integration/snapshot.ts +52 -52
  198. package/src/forge/compiler/orchestrator/discover.ts +214 -214
  199. package/src/forge/compiler/orchestrator/guards.ts +5 -5
  200. package/src/forge/compiler/orchestrator/index.ts +27 -27
  201. package/src/forge/compiler/orchestrator/manifest.ts +69 -69
  202. package/src/forge/compiler/orchestrator/orphans.ts +51 -51
  203. package/src/forge/compiler/orchestrator/plan.ts +804 -804
  204. package/src/forge/compiler/orchestrator/run.ts +178 -178
  205. package/src/forge/compiler/orchestrator/serialize.ts +859 -859
  206. package/src/forge/compiler/orchestrator/types.ts +23 -23
  207. package/src/forge/compiler/orchestrator/verify.ts +35 -35
  208. package/src/forge/compiler/package-graph/capabilities-stub.ts +33 -33
  209. package/src/forge/compiler/package-graph/checksum.ts +107 -97
  210. package/src/forge/compiler/package-graph/compiler.ts +444 -363
  211. package/src/forge/compiler/package-graph/constants.ts +4 -4
  212. package/src/forge/compiler/package-graph/exports-discovery.ts +91 -84
  213. package/src/forge/compiler/package-graph/extract-dts.ts +32 -32
  214. package/src/forge/compiler/package-graph/index.ts +24 -24
  215. package/src/forge/compiler/package-graph/jsdoc.ts +50 -50
  216. package/src/forge/compiler/package-graph/oracle.ts +326 -0
  217. package/src/forge/compiler/package-graph/read-file.ts +21 -21
  218. package/src/forge/compiler/package-graph/resolve.ts +131 -127
  219. package/src/forge/compiler/package-manager/adapter.ts +232 -232
  220. package/src/forge/compiler/package-manager/commands.ts +47 -47
  221. package/src/forge/compiler/package-manager/detect.ts +65 -65
  222. package/src/forge/compiler/package-manager/executor.ts +29 -29
  223. package/src/forge/compiler/package-manager/index.ts +22 -22
  224. package/src/forge/compiler/package-manager/parse-spec.ts +16 -16
  225. package/src/forge/compiler/package-manager/version.ts +20 -20
  226. package/src/forge/compiler/primitives/compare.ts +26 -26
  227. package/src/forge/compiler/primitives/hash.ts +42 -33
  228. package/src/forge/compiler/primitives/header.ts +43 -43
  229. package/src/forge/compiler/primitives/index.ts +45 -45
  230. package/src/forge/compiler/primitives/paths.ts +24 -24
  231. package/src/forge/compiler/primitives/serialize.ts +66 -66
  232. package/src/forge/compiler/primitives/sort.ts +87 -87
  233. package/src/forge/compiler/recipes/definitions.ts +269 -269
  234. package/src/forge/compiler/recipes/helpers.ts +37 -37
  235. package/src/forge/compiler/recipes/index.ts +21 -21
  236. package/src/forge/compiler/recipes/registry.ts +87 -87
  237. package/src/forge/compiler/sandbox/artifact-sanitize.ts +26 -26
  238. package/src/forge/compiler/sandbox/backends/child.ts +123 -123
  239. package/src/forge/compiler/sandbox/backends/docker.ts +173 -173
  240. package/src/forge/compiler/sandbox/index.ts +51 -51
  241. package/src/forge/compiler/sandbox/inspect.ts +143 -143
  242. package/src/forge/compiler/sandbox/inspector-entry.ts +115 -115
  243. package/src/forge/compiler/sandbox/limits.ts +31 -31
  244. package/src/forge/compiler/sandbox/scrub-env.ts +60 -60
  245. package/src/forge/compiler/sandbox/secret-scan.ts +54 -54
  246. package/src/forge/compiler/sandbox/serialize.ts +106 -106
  247. package/src/forge/compiler/sandbox/types.ts +7 -7
  248. package/src/forge/compiler/types/app-graph.ts +71 -71
  249. package/src/forge/compiler/types/capability.ts +29 -29
  250. package/src/forge/compiler/types/classification.ts +9 -9
  251. package/src/forge/compiler/types/cli.ts +85 -85
  252. package/src/forge/compiler/types/diagnostic.ts +2 -2
  253. package/src/forge/compiler/types/emit.ts +25 -25
  254. package/src/forge/compiler/types/import-guards.ts +19 -19
  255. package/src/forge/compiler/types/index.ts +98 -98
  256. package/src/forge/compiler/types/integration.ts +25 -25
  257. package/src/forge/compiler/types/json.ts +3 -3
  258. package/src/forge/compiler/types/lock.ts +37 -37
  259. package/src/forge/compiler/types/package-graph.ts +122 -77
  260. package/src/forge/compiler/types/runtime-matrix.ts +16 -16
  261. package/src/forge/compiler/types/runtime.ts +30 -30
  262. package/src/forge/compiler/types/sandbox.ts +24 -24
  263. package/src/forge/dev/server.ts +16 -2
  264. package/src/forge/refactor/index.ts +10 -2
  265. package/src/forge/refactor/runtime-rename.ts +598 -0
  266. package/src/forge/runtime/executor.ts +3 -2
  267. package/src/forge/runtime/live/live-query-runner.ts +2 -1
  268. package/src/forge/runtime/outbox/process.ts +2 -1
  269. package/src/forge/runtime/query/run-query.ts +2 -1
  270. package/src/forge/runtime/runner/run-entry.ts +2 -1
  271. package/src/forge/runtime/telemetry/sinks/posthog.ts +4 -5
  272. package/src/forge/runtime/telemetry/sinks/sentry.ts +4 -5
  273. package/src/forge/runtime/workflows/resolve-step.ts +2 -1
  274. package/src/forge/version.ts +3 -0
  275. package/templates/b2b-support-web/src/actions/captureTicketCreated.ts +7 -2
  276. package/templates/b2b-support-web/src/commands/closeTicket.ts +6 -1
  277. package/templates/b2b-support-web/src/commands/createTicket.ts +8 -2
  278. package/templates/b2b-support-web/src/queries/getTicket.ts +8 -1
  279. package/templates/b2b-support-web/web/components/CreateTicketForm.tsx +1 -2
  280. package/templates/b2b-support-web/web/components/PolicyDeniedDemo.tsx +1 -2
  281. package/templates/b2b-support-web/web/components/TicketList.tsx +1 -2
  282. package/templates/b2b-support-web/web/components/TraceDetails.tsx +1 -1
  283. package/templates/b2b-support-web/web/lib/forge.ts +1 -0
@@ -1,189 +1,189 @@
1
- import type { SecretRequirement } from "../types/capability.ts";
2
- import type { IntegrationRecipe } from "../types/integration.ts";
3
- import type { RuntimeContext } from "../types/runtime.ts";
4
- import { RUNTIME_CONTEXTS } from "../types/runtime.ts";
5
- import { serializeCanonical } from "../primitives/serialize.ts";
6
- import {
7
- buildTemplateInput,
8
- renderQualityAdapter,
9
- renderQualityDoc,
10
- renderQualityIntegration,
11
- renderQualityTestkit,
12
- } from "./templates/index.ts";
13
- import type { IntegrationTemplateInput } from "./templates/types.ts";
14
-
15
- function capitalizeSegment(value: string): string {
16
- return value
17
- .split(/[^a-zA-Z0-9]+/)
18
- .filter(Boolean)
19
- .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
20
- .join("");
21
- }
22
-
23
- export function parseAdapterContext(filename: string): RuntimeContext | null {
24
- const base = filename.replace(/\.ts$/, "");
25
- for (const context of RUNTIME_CONTEXTS) {
26
- if (base.endsWith(`.${context}`)) {
27
- return context;
28
- }
29
- }
30
- return null;
31
- }
32
-
33
- function skeletonAdapter(input: IntegrationTemplateInput): string {
34
- const secretNames = input.secrets.map((secret) => secret.envVar).sort();
35
- const exportName = `forge${capitalizeSegment(input.alias)}${capitalizeSegment(input.context)}Adapter`;
36
-
37
- return [
38
- `/** Forge generated adapter for ${input.alias} (${input.context} context). */`,
39
- `export const ${exportName} = ${serializeCanonical({
40
- alias: input.alias,
41
- packageName: input.packageName,
42
- context: input.context,
43
- secrets: secretNames,
44
- }).trim()} as const;`,
45
- "",
46
- ].join("\n");
47
- }
48
-
49
- function skeletonTestkit(alias: string, packageName: string): string {
50
- const exportName = `create${capitalizeSegment(alias)}Mock`;
51
- return [
52
- `/** Forge generated mock testkit for ${alias}. */`,
53
- `export function ${exportName}() {`,
54
- ` return ${serializeCanonical({
55
- alias,
56
- packageName,
57
- mocked: true,
58
- }).trim()} as const;`,
59
- `}`,
60
- "",
61
- ].join("\n");
62
- }
63
-
64
- function skeletonDoc(input: IntegrationTemplateInput): string {
65
- const secretNames = input.secrets.map((secret) => secret.envVar).sort();
66
- const lines = [
67
- `# ${input.alias} integration`,
68
- "",
69
- "Generated by Forge.",
70
- "",
71
- `Packages: ${input.packageNames.join(", ")}`,
72
- "",
73
- `Compatible contexts: ${input.compatible.join(", ")}`,
74
- "",
75
- `Incompatible contexts: ${input.incompatible.join(", ")}`,
76
- "",
77
- ];
78
-
79
- if (secretNames.length > 0) {
80
- lines.push(`Secrets (names only): ${secretNames.join(", ")}`, "");
81
- }
82
-
83
- return lines.join("\n");
84
- }
85
-
86
- export function createRenderContext(input: {
87
- alias: string;
88
- recipe: IntegrationRecipe;
89
- context: RuntimeContext;
90
- packageName: string;
91
- packageNames: string[];
92
- secrets: SecretRequirement[];
93
- compatible: RuntimeContext[];
94
- incompatible: RuntimeContext[];
95
- }): IntegrationTemplateInput {
96
- return buildTemplateInput(input);
97
- }
98
-
99
- export function renderAdapterModule(input: {
100
- alias: string;
101
- recipe: IntegrationRecipe;
102
- context: RuntimeContext;
103
- packageName: string;
104
- packageNames: string[];
105
- secrets: SecretRequirement[];
106
- compatible: RuntimeContext[];
107
- incompatible: RuntimeContext[];
108
- }): string {
109
- const ctx = createRenderContext(input);
110
- const adapterFilename = `${input.alias}.${input.context}.ts`;
111
- const quality = renderQualityAdapter(adapterFilename, ctx);
112
- if (quality) {
113
- return quality;
114
- }
115
-
116
- const resolvedName = input.recipe.adapters.find((name) =>
117
- parseAdapterContext(name) === input.context,
118
- );
119
- if (resolvedName) {
120
- const byName = renderQualityAdapter(resolvedName, ctx);
121
- if (byName) {
122
- return byName;
123
- }
124
- }
125
-
126
- return skeletonAdapter(ctx);
127
- }
128
-
129
- export function renderIntegrationModule(
130
- relativePath: string,
131
- input: IntegrationTemplateInput,
132
- ): string {
133
- const quality = renderQualityIntegration(relativePath, input);
134
- if (quality) {
135
- return quality;
136
- }
137
-
138
- return [
139
- `/** Forge generated integration module: ${relativePath} */`,
140
- `export const forgeIntegration = ${serializeCanonical({
141
- alias: input.alias,
142
- module: relativePath,
143
- }).trim()} as const;`,
144
- "",
145
- ].join("\n");
146
- }
147
-
148
- export function renderTestkitModule(
149
- alias: string,
150
- packageName: string,
151
- input?: IntegrationTemplateInput,
152
- ): string {
153
- const filename = `${alias}.mock.ts`;
154
- if (input) {
155
- const quality = renderQualityTestkit(filename, input);
156
- if (quality) {
157
- return quality;
158
- }
159
- }
160
- return skeletonTestkit(alias, packageName);
161
- }
162
-
163
- export function renderIntegrationDoc(input: {
164
- alias: string;
165
- recipe: IntegrationRecipe;
166
- packageNames: string[];
167
- secrets: SecretRequirement[];
168
- compatible: RuntimeContext[];
169
- incompatible: RuntimeContext[];
170
- }): string {
171
- const ctx = buildTemplateInput({
172
- alias: input.alias,
173
- recipe: input.recipe,
174
- context: "shared",
175
- packageName: input.packageNames[0] ?? input.alias,
176
- packageNames: input.packageNames,
177
- secrets: input.secrets,
178
- compatible: input.compatible,
179
- incompatible: input.incompatible,
180
- });
181
-
182
- const docName = `${input.alias}.md`;
183
- const quality = renderQualityDoc(docName, ctx);
184
- if (quality) {
185
- return quality;
186
- }
187
-
188
- return skeletonDoc(ctx);
189
- }
1
+ import type { SecretRequirement } from "../types/capability.ts";
2
+ import type { IntegrationRecipe } from "../types/integration.ts";
3
+ import type { RuntimeContext } from "../types/runtime.ts";
4
+ import { RUNTIME_CONTEXTS } from "../types/runtime.ts";
5
+ import { serializeCanonical } from "../primitives/serialize.ts";
6
+ import {
7
+ buildTemplateInput,
8
+ renderQualityAdapter,
9
+ renderQualityDoc,
10
+ renderQualityIntegration,
11
+ renderQualityTestkit,
12
+ } from "./templates/index.ts";
13
+ import type { IntegrationTemplateInput } from "./templates/types.ts";
14
+
15
+ function capitalizeSegment(value: string): string {
16
+ return value
17
+ .split(/[^a-zA-Z0-9]+/)
18
+ .filter(Boolean)
19
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
20
+ .join("");
21
+ }
22
+
23
+ export function parseAdapterContext(filename: string): RuntimeContext | null {
24
+ const base = filename.replace(/\.ts$/, "");
25
+ for (const context of RUNTIME_CONTEXTS) {
26
+ if (base.endsWith(`.${context}`)) {
27
+ return context;
28
+ }
29
+ }
30
+ return null;
31
+ }
32
+
33
+ function skeletonAdapter(input: IntegrationTemplateInput): string {
34
+ const secretNames = input.secrets.map((secret) => secret.envVar).sort();
35
+ const exportName = `forge${capitalizeSegment(input.alias)}${capitalizeSegment(input.context)}Adapter`;
36
+
37
+ return [
38
+ `/** Forge generated adapter for ${input.alias} (${input.context} context). */`,
39
+ `export const ${exportName} = ${serializeCanonical({
40
+ alias: input.alias,
41
+ packageName: input.packageName,
42
+ context: input.context,
43
+ secrets: secretNames,
44
+ }).trim()} as const;`,
45
+ "",
46
+ ].join("\n");
47
+ }
48
+
49
+ function skeletonTestkit(alias: string, packageName: string): string {
50
+ const exportName = `create${capitalizeSegment(alias)}Mock`;
51
+ return [
52
+ `/** Forge generated mock testkit for ${alias}. */`,
53
+ `export function ${exportName}() {`,
54
+ ` return ${serializeCanonical({
55
+ alias,
56
+ packageName,
57
+ mocked: true,
58
+ }).trim()} as const;`,
59
+ `}`,
60
+ "",
61
+ ].join("\n");
62
+ }
63
+
64
+ function skeletonDoc(input: IntegrationTemplateInput): string {
65
+ const secretNames = input.secrets.map((secret) => secret.envVar).sort();
66
+ const lines = [
67
+ `# ${input.alias} integration`,
68
+ "",
69
+ "Generated by Forge.",
70
+ "",
71
+ `Packages: ${input.packageNames.join(", ")}`,
72
+ "",
73
+ `Compatible contexts: ${input.compatible.join(", ")}`,
74
+ "",
75
+ `Incompatible contexts: ${input.incompatible.join(", ")}`,
76
+ "",
77
+ ];
78
+
79
+ if (secretNames.length > 0) {
80
+ lines.push(`Secrets (names only): ${secretNames.join(", ")}`, "");
81
+ }
82
+
83
+ return lines.join("\n");
84
+ }
85
+
86
+ export function createRenderContext(input: {
87
+ alias: string;
88
+ recipe: IntegrationRecipe;
89
+ context: RuntimeContext;
90
+ packageName: string;
91
+ packageNames: string[];
92
+ secrets: SecretRequirement[];
93
+ compatible: RuntimeContext[];
94
+ incompatible: RuntimeContext[];
95
+ }): IntegrationTemplateInput {
96
+ return buildTemplateInput(input);
97
+ }
98
+
99
+ export function renderAdapterModule(input: {
100
+ alias: string;
101
+ recipe: IntegrationRecipe;
102
+ context: RuntimeContext;
103
+ packageName: string;
104
+ packageNames: string[];
105
+ secrets: SecretRequirement[];
106
+ compatible: RuntimeContext[];
107
+ incompatible: RuntimeContext[];
108
+ }): string {
109
+ const ctx = createRenderContext(input);
110
+ const adapterFilename = `${input.alias}.${input.context}.ts`;
111
+ const quality = renderQualityAdapter(adapterFilename, ctx);
112
+ if (quality) {
113
+ return quality;
114
+ }
115
+
116
+ const resolvedName = input.recipe.adapters.find((name) =>
117
+ parseAdapterContext(name) === input.context,
118
+ );
119
+ if (resolvedName) {
120
+ const byName = renderQualityAdapter(resolvedName, ctx);
121
+ if (byName) {
122
+ return byName;
123
+ }
124
+ }
125
+
126
+ return skeletonAdapter(ctx);
127
+ }
128
+
129
+ export function renderIntegrationModule(
130
+ relativePath: string,
131
+ input: IntegrationTemplateInput,
132
+ ): string {
133
+ const quality = renderQualityIntegration(relativePath, input);
134
+ if (quality) {
135
+ return quality;
136
+ }
137
+
138
+ return [
139
+ `/** Forge generated integration module: ${relativePath} */`,
140
+ `export const forgeIntegration = ${serializeCanonical({
141
+ alias: input.alias,
142
+ module: relativePath,
143
+ }).trim()} as const;`,
144
+ "",
145
+ ].join("\n");
146
+ }
147
+
148
+ export function renderTestkitModule(
149
+ alias: string,
150
+ packageName: string,
151
+ input?: IntegrationTemplateInput,
152
+ ): string {
153
+ const filename = `${alias}.mock.ts`;
154
+ if (input) {
155
+ const quality = renderQualityTestkit(filename, input);
156
+ if (quality) {
157
+ return quality;
158
+ }
159
+ }
160
+ return skeletonTestkit(alias, packageName);
161
+ }
162
+
163
+ export function renderIntegrationDoc(input: {
164
+ alias: string;
165
+ recipe: IntegrationRecipe;
166
+ packageNames: string[];
167
+ secrets: SecretRequirement[];
168
+ compatible: RuntimeContext[];
169
+ incompatible: RuntimeContext[];
170
+ }): string {
171
+ const ctx = buildTemplateInput({
172
+ alias: input.alias,
173
+ recipe: input.recipe,
174
+ context: "shared",
175
+ packageName: input.packageNames[0] ?? input.alias,
176
+ packageNames: input.packageNames,
177
+ secrets: input.secrets,
178
+ compatible: input.compatible,
179
+ incompatible: input.incompatible,
180
+ });
181
+
182
+ const docName = `${input.alias}.md`;
183
+ const quality = renderQualityDoc(docName, ctx);
184
+ if (quality) {
185
+ return quality;
186
+ }
187
+
188
+ return skeletonDoc(ctx);
189
+ }
@@ -1,52 +1,52 @@
1
- import { join } from "node:path";
2
- import { nodeFileSystem } from "../fs/index.ts";
3
- import { detectPackageManager, getLockfileForPm } from "../package-manager/detect.ts";
4
- import { FORGE_LOCK_PATH } from "../emitter/constants.ts";
5
- import { manifestPath } from "../orchestrator/manifest.ts";
6
-
7
- export interface VersionControlledSnapshot {
8
- files: Map<string, string | null>;
9
- }
10
-
11
- function readOptional(path: string): string | null {
12
- return nodeFileSystem.readText(path);
13
- }
14
-
15
- export function snapshotVersionControlled(
16
- workspaceRoot: string,
17
- ): VersionControlledSnapshot {
18
- const pm = detectPackageManager(workspaceRoot);
19
- const lockfile = getLockfileForPm(pm);
20
- const paths = [
21
- "package.json",
22
- lockfile,
23
- FORGE_LOCK_PATH,
24
- manifestPath(join(workspaceRoot, ".forge", "cache")).replace(
25
- `${workspaceRoot.replace(/\\/g, "/")}/`,
26
- "",
27
- ),
28
- ];
29
-
30
- const files = new Map<string, string | null>();
31
- for (const relative of paths) {
32
- const normalized = relative.replace(/\\/g, "/");
33
- files.set(normalized, readOptional(join(workspaceRoot, normalized)));
34
- }
35
-
36
- return { files };
37
- }
38
-
39
- export function restoreVersionControlledSnapshot(
40
- workspaceRoot: string,
41
- snapshot: VersionControlledSnapshot,
42
- ): void {
43
- for (const [relative, content] of snapshot.files) {
44
- const absolute = join(workspaceRoot, relative);
45
- if (content === null) {
46
- nodeFileSystem.remove(absolute);
47
- continue;
48
- }
49
-
50
- nodeFileSystem.writeText(absolute, content);
51
- }
52
- }
1
+ import { join } from "node:path";
2
+ import { nodeFileSystem } from "../fs/index.ts";
3
+ import { detectPackageManager, getLockfileForPm } from "../package-manager/detect.ts";
4
+ import { FORGE_LOCK_PATH } from "../emitter/constants.ts";
5
+ import { manifestPath } from "../orchestrator/manifest.ts";
6
+
7
+ export interface VersionControlledSnapshot {
8
+ files: Map<string, string | null>;
9
+ }
10
+
11
+ function readOptional(path: string): string | null {
12
+ return nodeFileSystem.readText(path);
13
+ }
14
+
15
+ export function snapshotVersionControlled(
16
+ workspaceRoot: string,
17
+ ): VersionControlledSnapshot {
18
+ const pm = detectPackageManager(workspaceRoot);
19
+ const lockfile = getLockfileForPm(pm);
20
+ const paths = [
21
+ "package.json",
22
+ lockfile,
23
+ FORGE_LOCK_PATH,
24
+ manifestPath(join(workspaceRoot, ".forge", "cache")).replace(
25
+ `${workspaceRoot.replace(/\\/g, "/")}/`,
26
+ "",
27
+ ),
28
+ ];
29
+
30
+ const files = new Map<string, string | null>();
31
+ for (const relative of paths) {
32
+ const normalized = relative.replace(/\\/g, "/");
33
+ files.set(normalized, readOptional(join(workspaceRoot, normalized)));
34
+ }
35
+
36
+ return { files };
37
+ }
38
+
39
+ export function restoreVersionControlledSnapshot(
40
+ workspaceRoot: string,
41
+ snapshot: VersionControlledSnapshot,
42
+ ): void {
43
+ for (const [relative, content] of snapshot.files) {
44
+ const absolute = join(workspaceRoot, relative);
45
+ if (content === null) {
46
+ nodeFileSystem.remove(absolute);
47
+ continue;
48
+ }
49
+
50
+ nodeFileSystem.writeText(absolute, content);
51
+ }
52
+ }