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
@@ -6,7 +6,18 @@ import { GENERATED_DIR } from "../compiler/emitter/constants.ts";
6
6
  import type { Diagnostic } from "../compiler/types/diagnostic.ts";
7
7
  import type { PackageGraph } from "../compiler/types/package-graph.ts";
8
8
  import type { ForgeLock } from "../compiler/types/lock.ts";
9
+ import { createDiagnostic } from "../compiler/diagnostics/create.ts";
10
+ import {
11
+ FORGE_DEPS_RUNTIME_TYPE_MISMATCH,
12
+ FORGE_DEPS_UNKNOWN_EXPORT,
13
+ } from "../compiler/diagnostics/codes.ts";
9
14
  import { resolveByPackageName } from "../compiler/recipes/registry.ts";
15
+ import {
16
+ defaultPackageMetadata,
17
+ defaultRuntimeCompatibility,
18
+ summarizeDependencyApi,
19
+ traceForPackage,
20
+ } from "../compiler/package-graph/oracle.ts";
10
21
  import {
11
22
  createUpgradePlan,
12
23
  listOutdatedFromFixture,
@@ -20,6 +31,9 @@ import {
20
31
  export type DepsSubcommand =
21
32
  | "outdated"
22
33
  | "inspect"
34
+ | "api"
35
+ | "trace"
36
+ | "runtime-compat"
23
37
  | "diff"
24
38
  | "upgrade-plan"
25
39
  | "upgrade-apply"
@@ -30,6 +44,7 @@ export type DepsSubcommand =
30
44
  export interface DepsCommandOptions {
31
45
  subcommand: DepsSubcommand;
32
46
  packageName?: string;
47
+ symbolName?: string;
33
48
  planPath?: string;
34
49
  target?: string;
35
50
  json: boolean;
@@ -68,38 +83,68 @@ function planPathFor(workspaceRoot: string, planIdOrPath: string): string {
68
83
  return join(workspaceRoot, ".forge", "upgrades", planIdOrPath, "plan.json");
69
84
  }
70
85
 
71
- function inspectPackage(workspaceRoot: string, packageName: string): DepsCommandResult {
86
+ function findPackage(workspaceRoot: string, packageName: string): {
87
+ graph: PackageGraph | null;
88
+ pkg: PackageGraph["packages"][number] | undefined;
89
+ lock: ForgeLock | null;
90
+ } {
72
91
  const graph = readGeneratedJson<PackageGraph>(workspaceRoot, `${GENERATED_DIR}/packageGraph.json`);
73
92
  const lock = nodeFileSystem.exists(join(workspaceRoot, "forge.lock"))
74
93
  ? (JSON.parse((nodeFileSystem.readText(join(workspaceRoot, "forge.lock")) ?? "")) as ForgeLock)
75
94
  : null;
76
95
  const pkg = graph?.packages.find((candidate) => candidate.name === packageName);
96
+ return { graph, pkg, lock };
97
+ }
98
+
99
+ function packageMissing(packageName: string): DepsCommandResult {
100
+ return {
101
+ ok: false,
102
+ diagnostics: [{
103
+ severity: "error",
104
+ code: "FORGE_DEPS_PACKAGE_NOT_INSTALLED",
105
+ message: `package '${packageName}' is not present in generated packageGraph`,
106
+ fixHint: "Run forge generate, then retry the deps command.",
107
+ suggestedCommands: ["forge generate", `forge deps inspect ${packageName} --json`],
108
+ }],
109
+ exitCode: 1,
110
+ };
111
+ }
112
+
113
+ function inspectPackage(workspaceRoot: string, packageName: string): DepsCommandResult {
114
+ const { pkg, lock } = findPackage(workspaceRoot, packageName);
77
115
  const lockEntry = lock?.packages.find((candidate) => candidate.name === packageName);
78
116
  const recipe = resolveByPackageName(packageName);
79
117
 
80
118
  if (!pkg) {
81
- return {
82
- ok: false,
83
- diagnostics: [{
84
- severity: "error",
85
- code: "FORGE_DEPS_PACKAGE_NOT_INSTALLED",
86
- message: `package '${packageName}' is not present in generated packageGraph`,
87
- }],
88
- exitCode: 1,
89
- };
119
+ return packageMissing(packageName);
90
120
  }
91
121
 
122
+ const runtimeMismatchDiagnostics = (pkg.runtimeTypeMismatches ?? []).map((mismatch) =>
123
+ createDiagnostic({
124
+ severity: "warning",
125
+ code: FORGE_DEPS_RUNTIME_TYPE_MISMATCH,
126
+ message: `${packageName} ${mismatch.entrypoint} export '${mismatch.exportName}' is ${mismatch.kind}`,
127
+ fixHint: "Run forge deps api/trace and check package runtime inspection before relying on this export.",
128
+ suggestedCommands: [
129
+ `forge deps api ${packageName} ${mismatch.exportName} --json`,
130
+ `forge deps trace ${packageName} --json`,
131
+ ],
132
+ }),
133
+ );
134
+
92
135
  return {
93
- ok: true,
136
+ ok: runtimeMismatchDiagnostics.every((diagnostic) => diagnostic.severity !== "error"),
94
137
  data: {
95
138
  package: packageName,
96
139
  version: pkg.version,
140
+ source: pkg.source,
97
141
  integrationAlias: recipe?.alias,
98
142
  recipeVersion: recipe?.recipeVersion,
99
143
  runtimeContexts: {
100
144
  allowed: lockEntry?.runtimeContexts ?? [],
101
145
  denied: recipe?.contexts.denied ?? [],
102
146
  },
147
+ oracle: summarizeDependencyApi(pkg),
103
148
  usedBy: {
104
149
  generatedAdapters: (recipe?.adapters ?? []).map(
105
150
  (adapter) => `src/forge/_generated/packages/${adapter}`,
@@ -107,6 +152,90 @@ function inspectPackage(workspaceRoot: string, packageName: string): DepsCommand
107
152
  },
108
153
  secrets: (recipe?.secrets ?? []).map((secret) => secret.envVar),
109
154
  },
155
+ diagnostics: runtimeMismatchDiagnostics,
156
+ exitCode: 0,
157
+ };
158
+ }
159
+
160
+ function inspectPackageApi(workspaceRoot: string, packageName: string, symbolName: string | undefined): DepsCommandResult {
161
+ const { pkg } = findPackage(workspaceRoot, packageName);
162
+ if (!pkg) {
163
+ return packageMissing(packageName);
164
+ }
165
+ if (!symbolName) {
166
+ return {
167
+ ok: false,
168
+ diagnostics: [{
169
+ severity: "error",
170
+ code: FORGE_DEPS_UNKNOWN_EXPORT,
171
+ message: "symbol name is required",
172
+ fixHint: `Use: forge deps api ${packageName} <symbol> --json`,
173
+ }],
174
+ exitCode: 1,
175
+ };
176
+ }
177
+ const summary = summarizeDependencyApi(pkg, symbolName);
178
+ if (summary.symbols.length === 0) {
179
+ return {
180
+ ok: false,
181
+ data: summary,
182
+ diagnostics: [
183
+ createDiagnostic({
184
+ severity: "error",
185
+ code: FORGE_DEPS_UNKNOWN_EXPORT,
186
+ message: `${packageName} does not expose '${symbolName}' in generated packageGraph`,
187
+ fixHint: "Run forge deps inspect to list exports, or run forge generate if node_modules changed.",
188
+ suggestedCommands: [`forge deps inspect ${packageName} --json`, "forge generate"],
189
+ }),
190
+ ],
191
+ exitCode: 1,
192
+ };
193
+ }
194
+ return {
195
+ ok: true,
196
+ data: summary,
197
+ diagnostics: [],
198
+ exitCode: 0,
199
+ };
200
+ }
201
+
202
+ function tracePackage(workspaceRoot: string, packageName: string): DepsCommandResult {
203
+ const { pkg } = findPackage(workspaceRoot, packageName);
204
+ if (!pkg) {
205
+ return packageMissing(packageName);
206
+ }
207
+ return {
208
+ ok: true,
209
+ data: {
210
+ package: packageName,
211
+ version: pkg.version,
212
+ source: pkg.source,
213
+ resolutionMode: pkg.resolutionMode,
214
+ traces: traceForPackage(pkg),
215
+ runtimeShapeAvailable: Boolean(pkg.runtimeShape),
216
+ runtimeTypeMismatches: pkg.runtimeTypeMismatches ?? [],
217
+ },
218
+ diagnostics: [],
219
+ exitCode: 0,
220
+ };
221
+ }
222
+
223
+ function runtimeCompatPackage(workspaceRoot: string, packageName: string): DepsCommandResult {
224
+ const { pkg } = findPackage(workspaceRoot, packageName);
225
+ if (!pkg) {
226
+ return packageMissing(packageName);
227
+ }
228
+ return {
229
+ ok: true,
230
+ data: {
231
+ package: packageName,
232
+ version: pkg.version,
233
+ runtimeCompatibility: pkg.runtimeCompatibility ?? defaultRuntimeCompatibility(),
234
+ metadata: pkg.metadata ?? defaultPackageMetadata(pkg.entrypoints.length),
235
+ runtimeContexts: pkg.entrypoints.flatMap((entrypoint) =>
236
+ entrypoint.exports.flatMap((exported) => exported.classification.compatible),
237
+ ).filter((value, index, array) => array.indexOf(value) === index).sort(),
238
+ },
110
239
  diagnostics: [],
111
240
  exitCode: 0,
112
241
  };
@@ -129,6 +258,27 @@ export async function runDepsCommand(options: DepsCommandOptions): Promise<DepsC
129
258
  return inspectPackage(options.workspaceRoot, options.packageName);
130
259
  }
131
260
 
261
+ if (options.subcommand === "api") {
262
+ if (!options.packageName) {
263
+ return missingPackage();
264
+ }
265
+ return inspectPackageApi(options.workspaceRoot, options.packageName, options.symbolName);
266
+ }
267
+
268
+ if (options.subcommand === "trace") {
269
+ if (!options.packageName) {
270
+ return missingPackage();
271
+ }
272
+ return tracePackage(options.workspaceRoot, options.packageName);
273
+ }
274
+
275
+ if (options.subcommand === "runtime-compat") {
276
+ if (!options.packageName) {
277
+ return missingPackage();
278
+ }
279
+ return runtimeCompatPackage(options.workspaceRoot, options.packageName);
280
+ }
281
+
132
282
  if (options.subcommand === "diff" || options.subcommand === "upgrade-plan" || options.subcommand === "risk") {
133
283
  if (!options.packageName) {
134
284
  return missingPackage();
@@ -273,5 +423,22 @@ export function formatDepsHuman(subcommand: DepsSubcommand, result: DepsCommandR
273
423
  const data = result.data as { planDir?: string; plan?: { risk?: { level?: string } } } | undefined;
274
424
  return `upgrade plan written: ${data?.planDir ?? "not written"}\nrisk: ${data?.plan?.risk?.level ?? "unknown"}\n`;
275
425
  }
426
+ if (subcommand === "api") {
427
+ const data = result.data as { package?: string; version?: string; symbols?: Array<{ entrypoint: string; name: string; signature: string }> } | undefined;
428
+ const symbols = data?.symbols ?? [];
429
+ return `deps api ${data?.package ?? ""}@${data?.version ?? ""}\n${symbols.map((symbol) => `${symbol.entrypoint} ${symbol.name}: ${symbol.signature}`).join("\n")}\n`;
430
+ }
431
+ if (subcommand === "trace") {
432
+ const data = result.data as { package?: string; version?: string; traces?: Array<{ entrypoint: string; trace: Array<{ step: string; status: string; detail: string }> }> } | undefined;
433
+ const lines = (data?.traces ?? []).flatMap((entry) => [
434
+ `${entry.entrypoint}:`,
435
+ ...entry.trace.map((step) => ` ${step.status} ${step.step}: ${step.detail}`),
436
+ ]);
437
+ return `deps trace ${data?.package ?? ""}@${data?.version ?? ""}\n${lines.join("\n")}\n`;
438
+ }
439
+ if (subcommand === "runtime-compat") {
440
+ const data = result.data as { package?: string; version?: string; runtimeCompatibility?: Record<string, unknown> } | undefined;
441
+ return `deps runtime-compat ${data?.package ?? ""}@${data?.version ?? ""}\n${JSON.stringify(data?.runtimeCompatibility ?? {}, null, 2)}\n`;
442
+ }
276
443
  return `deps ${subcommand} ok${diagnostics ? `\n${diagnostics}` : ""}\n`;
277
444
  }
@@ -147,6 +147,30 @@ function hasWebApp(workspaceRoot: string): boolean {
147
147
  );
148
148
  }
149
149
 
150
+ function sanitizeProcessEnv(
151
+ env: NodeJS.ProcessEnv,
152
+ extra: Record<string, string>,
153
+ ): Record<string, string> {
154
+ const sanitized: Record<string, string> = {};
155
+ for (const [key, value] of Object.entries(env)) {
156
+ if (typeof value === "string") {
157
+ sanitized[key] = value;
158
+ }
159
+ }
160
+ return {
161
+ ...sanitized,
162
+ ...extra,
163
+ };
164
+ }
165
+
166
+ function wrapWindowsShellCommand(command: string[]): string[] {
167
+ const executable = command[0];
168
+ if (process.platform !== "win32" || !executable || !/\.(cmd|bat)$/i.test(executable)) {
169
+ return command;
170
+ }
171
+ return [process.env.ComSpec ?? "cmd.exe", "/d", "/c", ...command];
172
+ }
173
+
150
174
  function startWebDevServer(input: {
151
175
  workspaceRoot: string;
152
176
  host: string;
@@ -161,24 +185,27 @@ function startWebDevServer(input: {
161
185
 
162
186
  const pkg = readPackageJson(input.workspaceRoot);
163
187
  const packageManager = detectPackageManager(input.workspaceRoot);
164
- const env = {
165
- ...process.env,
188
+ const env = sanitizeProcessEnv(process.env, {
166
189
  PORT: String(input.port),
167
190
  NEXT_PUBLIC_FORGE_URL: input.apiUrl,
168
191
  VITE_FORGE_URL: input.apiUrl,
169
- };
192
+ });
170
193
  const rawCommand =
171
194
  pkg?.scripts?.dev
172
195
  ? [packageManager, "run", "dev", "--", ...webDevArgsForPackage(pkg, input)]
173
196
  : ["node", "--import", "tsx", "server.ts"];
174
- const command = resolvePackageManagerArgv(rawCommand);
197
+ const command = wrapWindowsShellCommand(resolvePackageManagerArgv(rawCommand));
175
198
  const cwd = pkg?.scripts?.dev ? webRoot : webRoot;
176
199
  const child = spawn(command[0]!, command.slice(1), {
177
200
  cwd,
178
- stdio: ["ignore", input.json ? "pipe" : "inherit", input.json ? "pipe" : "inherit"],
201
+ stdio: ["ignore", "pipe", "pipe"],
179
202
  env,
180
203
  windowsHide: true,
181
204
  });
205
+ if (!input.json) {
206
+ child.stdout?.on("data", (chunk: Buffer) => process.stdout.write(chunk));
207
+ child.stderr?.on("data", (chunk: Buffer) => process.stderr.write(chunk));
208
+ }
182
209
  return {
183
210
  url: `http://${input.host}:${input.port}`,
184
211
  port: input.port,
@@ -1,4 +1,4 @@
1
- export { CLI_VERSION } from "./version.ts";
1
+ export { CLI_VERSION } from "./version.ts";
2
2
  export { parseCli, hasUnknownOption, type ParsedCli, type ForgeCommand } from "./parse.ts";
3
3
  export { runNewCommand, type NewCommandOptions, type NewCommandResult } from "./new.ts";
4
4
  export { runSelfHostCommand, type SelfHostCommandOptions } from "./self-host.ts";
@@ -17,9 +17,9 @@ export {
17
17
  } from "./doctor.ts";
18
18
  export {
19
19
  executeCommand,
20
- runGenerateCommand,
21
- runAddCommand,
22
- runCheckCommand,
23
- runInspectCommand,
24
- } from "./commands.ts";
25
- export { main } from "./main.ts";
20
+ runGenerateCommand,
21
+ runAddCommand,
22
+ runCheckCommand,
23
+ runInspectCommand,
24
+ } from "./commands.ts";
25
+ export { main } from "./main.ts";
@@ -32,60 +32,60 @@ export async function main(argv: string[] = process.argv.slice(2)): Promise<numb
32
32
  }
33
33
 
34
34
  const unknown = hasUnknownOption(argv);
35
- if (unknown) {
36
- const diagnostic = createDiagnostic({
37
- severity: "error",
38
- code: "FORGE_CLI_USAGE",
39
- message: `unrecognized option '${unknown}'`,
40
- });
41
-
42
- if (argv.includes("--json")) {
43
- process.stdout.write(
44
- formatJsonResult({
45
- errors: [diagnostic],
46
- exitCode: 1,
47
- failureKind: "usage",
48
- }),
49
- );
50
- } else {
51
- console.error(`error ${diagnostic.code}: ${diagnostic.message}`);
52
- }
53
- return 1;
54
- }
55
-
56
- const parsed = parseCli(argv);
57
- if (parsed.errors.length > 0) {
58
- const errors = parsed.errors.map((message) =>
59
- createDiagnostic({
60
- severity: "error",
61
- code: "FORGE_CLI_USAGE",
62
- message,
63
- }),
64
- );
65
-
66
- if (argv.includes("--json")) {
67
- process.stdout.write(
68
- formatJsonResult({
69
- errors,
70
- exitCode: 1,
71
- failureKind: "usage",
72
- }),
73
- );
74
- } else {
75
- for (const error of errors) {
76
- console.error(`error ${error.code}: ${error.message}`);
77
- }
78
- }
79
- return 1;
80
- }
81
-
82
- if (parsed.command === null) {
83
- return 1;
84
- }
85
-
86
- return executeCommand(parsed.command);
87
- }
88
-
35
+ if (unknown) {
36
+ const diagnostic = createDiagnostic({
37
+ severity: "error",
38
+ code: "FORGE_CLI_USAGE",
39
+ message: `unrecognized option '${unknown}'`,
40
+ });
41
+
42
+ if (argv.includes("--json")) {
43
+ process.stdout.write(
44
+ formatJsonResult({
45
+ errors: [diagnostic],
46
+ exitCode: 1,
47
+ failureKind: "usage",
48
+ }),
49
+ );
50
+ } else {
51
+ console.error(`error ${diagnostic.code}: ${diagnostic.message}`);
52
+ }
53
+ return 1;
54
+ }
55
+
56
+ const parsed = parseCli(argv);
57
+ if (parsed.errors.length > 0) {
58
+ const errors = parsed.errors.map((message) =>
59
+ createDiagnostic({
60
+ severity: "error",
61
+ code: "FORGE_CLI_USAGE",
62
+ message,
63
+ }),
64
+ );
65
+
66
+ if (argv.includes("--json")) {
67
+ process.stdout.write(
68
+ formatJsonResult({
69
+ errors,
70
+ exitCode: 1,
71
+ failureKind: "usage",
72
+ }),
73
+ );
74
+ } else {
75
+ for (const error of errors) {
76
+ console.error(`error ${error.code}: ${error.message}`);
77
+ }
78
+ }
79
+ return 1;
80
+ }
81
+
82
+ if (parsed.command === null) {
83
+ return 1;
84
+ }
85
+
86
+ return executeCommand(parsed.command);
87
+ }
88
+
89
89
  if (isMainModule(import.meta)) {
90
90
  const exitCode = await main();
91
91
  process.exit(exitCode);
@@ -57,6 +57,8 @@ const REQUIRED_GITIGNORE_PATHS = [
57
57
  ".forge/agent-adapters/",
58
58
  ] as const;
59
59
 
60
+ const DEFAULT_FORGE_PACKAGE_SPEC = "npm:forgeos@alpha";
61
+
60
62
  const TEXT_EXTENSIONS = new Set([
61
63
  "",
62
64
  ".css",
@@ -135,7 +137,10 @@ function forgePackageSpec(targetDir: string, options: Pick<NewCommandOptions, "f
135
137
  if (options.forgePackageSpec && !options.localForge) {
136
138
  return normalizeForgePackageSpec(options.forgePackageSpec);
137
139
  }
138
- return localForgePackageSpec(targetDir);
140
+ if (options.localForge) {
141
+ return localForgePackageSpec(targetDir);
142
+ }
143
+ return DEFAULT_FORGE_PACKAGE_SPEC;
139
144
  }
140
145
 
141
146
  function packageManagerSpec(packageManager: string): string {
@@ -207,6 +212,28 @@ function analyzeGitHygiene(targetDir: string): NewCommandResult["gitHygiene"] {
207
212
  };
208
213
  }
209
214
 
215
+ function ensureGitignore(targetDir: string): void {
216
+ const gitignorePath = join(targetDir, ".gitignore");
217
+ const existing = nodeFileSystem.exists(gitignorePath)
218
+ ? (nodeFileSystem.readText(gitignorePath) ?? "")
219
+ : "";
220
+ const normalized = existing.replace(/\r\n/g, "\n");
221
+ const missingPaths = REQUIRED_GITIGNORE_PATHS.filter(
222
+ (path) => !normalized.includes(path),
223
+ );
224
+ if (normalized.trim().length > 0 && missingPaths.length === 0) {
225
+ return;
226
+ }
227
+
228
+ const sections = [
229
+ normalized.trimEnd(),
230
+ normalized.trim().length > 0 ? "" : "node_modules/\ndist/\n.env\n.env.local",
231
+ "# ForgeOS generated and local runtime artifacts",
232
+ ...missingPaths,
233
+ ].filter(Boolean);
234
+ nodeFileSystem.writeText(gitignorePath, `${sections.join("\n")}\n`);
235
+ }
236
+
210
237
  async function spawnCommand(
211
238
  command: string,
212
239
  args: string[],
@@ -393,6 +420,7 @@ export async function runNewCommand(options: NewCommandOptions): Promise<NewComm
393
420
 
394
421
  nodeFileSystem.mkdirp(targetDir);
395
422
  cpSync(source, targetDir, { recursive: true, force: true });
423
+ ensureGitignore(targetDir);
396
424
  replaceTokens(
397
425
  targetDir,
398
426
  options.name,