forgeos 0.1.0-alpha.65 → 0.1.0-alpha.67

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 (284) hide show
  1. package/.npmignore +19 -19
  2. package/AGENTS.md +1 -1
  3. package/CHANGELOG.md +24 -0
  4. package/LICENSE +21 -21
  5. package/README.md +525 -525
  6. package/adapters/java/README.md +68 -68
  7. package/adapters/java/pom.xml +47 -47
  8. package/adapters/java/src/main/java/dev/forgeos/adapter/Auth.java +20 -20
  9. package/adapters/java/src/main/java/dev/forgeos/adapter/Diagnostic.java +16 -16
  10. package/adapters/java/src/main/java/dev/forgeos/adapter/Entry.java +38 -38
  11. package/adapters/java/src/main/java/dev/forgeos/adapter/EntryKind.java +16 -16
  12. package/adapters/java/src/main/java/dev/forgeos/adapter/ErrorInfo.java +4 -4
  13. package/adapters/java/src/main/java/dev/forgeos/adapter/Forge.java +94 -94
  14. package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeCall.java +12 -12
  15. package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeContext.java +11 -11
  16. package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeHandler.java +8 -8
  17. package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeHttpHandler.java +179 -179
  18. package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeRegistry.java +121 -121
  19. package/adapters/java/src/main/java/dev/forgeos/adapter/Json.java +14 -14
  20. package/adapters/java/src/main/java/dev/forgeos/adapter/Manifest.java +14 -14
  21. package/adapters/java/src/main/java/dev/forgeos/adapter/RequestEnvelope.java +6 -6
  22. package/adapters/java/src/main/java/dev/forgeos/adapter/ResponseEnvelope.java +25 -25
  23. package/adapters/java/src/main/java/dev/forgeos/adapter/Risk.java +18 -18
  24. package/adapters/java/src/main/java/dev/forgeos/adapter/Schemas.java +36 -36
  25. package/adapters/java/src/main/java/dev/forgeos/adapter/Service.java +65 -65
  26. package/adapters/java/src/main/java/dev/forgeos/adapter/TransactionMode.java +18 -18
  27. package/adapters/java/src/main/java/dev/forgeos/adapter/TypedForgeHandler.java +6 -6
  28. package/adapters/java-spring-boot-starter/README.md +32 -32
  29. package/adapters/java-spring-boot-starter/pom.xml +49 -49
  30. package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeCommand.java +22 -22
  31. package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeExternalService.java +15 -15
  32. package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeQuery.java +16 -16
  33. package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeServiceBeanCondition.java +18 -18
  34. package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeSpringAutoConfiguration.java +16 -16
  35. package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeSpringRuntime.java +104 -104
  36. package/adapters/java-spring-boot-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +1 -1
  37. package/bin/forge.mjs +38 -38
  38. package/docs/agent-fabric.md +131 -0
  39. package/examples/java-billing/pom.xml +60 -60
  40. package/examples/java-billing/src/main/java/dev/forgeos/examples/billing/CreateInvoiceInput.java +4 -4
  41. package/examples/java-billing/src/main/java/dev/forgeos/examples/billing/Invoice.java +11 -11
  42. package/examples/java-billing/src/main/java/dev/forgeos/examples/billing/Main.java +127 -127
  43. package/package.json +5 -4
  44. package/packages/eslint-plugin-forge/index.ts +15 -15
  45. package/packages/eslint-plugin-forge/package.json +10 -10
  46. package/packages/eslint-plugin-forge/src/check-source.ts +95 -95
  47. package/packages/eslint-plugin-forge/src/load-artifacts.ts +24 -24
  48. package/packages/eslint-plugin-forge/src/rule-no-forge-guard-violation.ts +93 -93
  49. package/schemas/agent-fabric/v0.1/control-event.schema.json +281 -281
  50. package/scripts/field-test-forgeos.mjs +1021 -1021
  51. package/src/forge/_generated/releaseManifest.json +1 -1
  52. package/src/forge/_generated/releaseManifest.ts +3 -3
  53. package/src/forge/agent-adapters/index.ts +7 -3
  54. package/src/forge/agent-adapters/types.ts +1 -0
  55. package/src/forge/agent-fabric/attached-snapshot.ts +55 -0
  56. package/src/forge/agent-fabric/attached-task-contract.ts +105 -0
  57. package/src/forge/agent-fabric/attached-task-service.ts +127 -0
  58. package/src/forge/agent-fabric/attached-task-store.ts +109 -0
  59. package/src/forge/agent-fabric/codex-adversarial-review.ts +229 -0
  60. package/src/forge/agent-fabric/codex-sdk-worker.ts +163 -0
  61. package/src/forge/agent-fabric/index.ts +19 -0
  62. package/src/forge/agent-fabric/local-adaptive-digest-worker.mjs +26 -26
  63. package/src/forge/agent-fabric/local-change-review-service.ts +374 -0
  64. package/src/forge/agent-fabric/local-task-server.ts +324 -249
  65. package/src/forge/agent-fabric/managed-environment.ts +205 -0
  66. package/src/forge/agent-fabric/managed-run-contract.ts +102 -0
  67. package/src/forge/agent-fabric/managed-run-service.ts +392 -0
  68. package/src/forge/agent-fabric/managed-run-store.ts +135 -0
  69. package/src/forge/agent-fabric/managed-workspace.ts +214 -0
  70. package/src/forge/agent-fabric/readiness.ts +26 -0
  71. package/src/forge/agent-fabric/workflow-engine.ts +218 -0
  72. package/src/forge/agent-fabric/workflow-task-actions.ts +104 -0
  73. package/src/forge/agent-fabric/workflow-templates.ts +11 -0
  74. package/src/forge/agent-memory/bridge.ts +309 -47
  75. package/src/forge/agent-memory/context-pack.ts +8 -1
  76. package/src/forge/agent-memory/hook-runner.ts +38 -19
  77. package/src/forge/agent-memory/mcp.ts +500 -286
  78. package/src/forge/agent-memory/sources/codex-hook-runner.mjs +343 -234
  79. package/src/forge/agent-memory/sources/codex.ts +49 -7
  80. package/src/forge/agent-memory/types.ts +11 -0
  81. package/src/forge/bench.ts +154 -154
  82. package/src/forge/cair/action-journal.ts +61 -61
  83. package/src/forge/cair/action-parser.ts +314 -314
  84. package/src/forge/cair/action-validator.ts +40 -40
  85. package/src/forge/cair/actions.ts +1818 -1818
  86. package/src/forge/cair/format.ts +77 -77
  87. package/src/forge/cair/index.ts +106 -106
  88. package/src/forge/cair/query.ts +478 -478
  89. package/src/forge/cair/snapshot.ts +315 -315
  90. package/src/forge/cair/types.ts +248 -248
  91. package/src/forge/cli/ai.ts +816 -816
  92. package/src/forge/cli/codex-app-server.ts +877 -877
  93. package/src/forge/cli/fabric.ts +205 -131
  94. package/src/forge/cli/index.ts +26 -26
  95. package/src/forge/cli/main.ts +259 -245
  96. package/src/forge/cli/next-actions.ts +23 -23
  97. package/src/forge/cli/parse.ts +3574 -3542
  98. package/src/forge/cli/release.ts +309 -309
  99. package/src/forge/cli/self-host.ts +510 -510
  100. package/src/forge/compiler/ai-registry/parse.ts +219 -219
  101. package/src/forge/compiler/app-graph/classify.ts +10 -10
  102. package/src/forge/compiler/app-graph/dup-symbol.ts +29 -29
  103. package/src/forge/compiler/app-graph/extract.ts +231 -231
  104. package/src/forge/compiler/app-graph/forge-apis.ts +25 -25
  105. package/src/forge/compiler/app-graph/index.ts +11 -11
  106. package/src/forge/compiler/app-graph/module-graph.ts +151 -151
  107. package/src/forge/compiler/app-graph/parser.ts +71 -71
  108. package/src/forge/compiler/app-graph/symbols.ts +48 -48
  109. package/src/forge/compiler/app-graph/types.ts +43 -43
  110. package/src/forge/compiler/app-graph/versions.ts +14 -14
  111. package/src/forge/compiler/cache/index.ts +17 -17
  112. package/src/forge/compiler/cache/key.ts +46 -46
  113. package/src/forge/compiler/cache/scheduler.ts +72 -72
  114. package/src/forge/compiler/cache/store.ts +78 -78
  115. package/src/forge/compiler/classifier/capabilities.ts +64 -64
  116. package/src/forge/compiler/classifier/classify.ts +76 -76
  117. package/src/forge/compiler/classifier/contexts.ts +188 -188
  118. package/src/forge/compiler/classifier/index.ts +18 -18
  119. package/src/forge/compiler/classifier/runtime-matrix.ts +45 -45
  120. package/src/forge/compiler/classifier/secrets.ts +31 -31
  121. package/src/forge/compiler/classifier/signals.ts +95 -95
  122. package/src/forge/compiler/client-sdk/build-manifest.ts +210 -210
  123. package/src/forge/compiler/data-graph/sql/serialize.ts +89 -89
  124. package/src/forge/compiler/data-graph/sql/types.ts +38 -38
  125. package/src/forge/compiler/diagnostics/index.ts +57 -57
  126. package/src/forge/compiler/emitter/artifact-kind.ts +14 -14
  127. package/src/forge/compiler/emitter/barrel.ts +47 -47
  128. package/src/forge/compiler/emitter/constants.ts +7 -7
  129. package/src/forge/compiler/emitter/emit.ts +223 -223
  130. package/src/forge/compiler/emitter/index.ts +24 -24
  131. package/src/forge/compiler/emitter/lock.ts +61 -61
  132. package/src/forge/compiler/external-manifest/registry.ts +205 -205
  133. package/src/forge/compiler/external-manifest/types.ts +91 -91
  134. package/src/forge/compiler/external-manifest/validate.ts +373 -373
  135. package/src/forge/compiler/frontend-graph/build.ts +623 -623
  136. package/src/forge/compiler/guards/artifacts.ts +96 -96
  137. package/src/forge/compiler/guards/check-import-guards.ts +106 -106
  138. package/src/forge/compiler/guards/index.ts +11 -11
  139. package/src/forge/compiler/guards/propagate-contexts.ts +57 -57
  140. package/src/forge/compiler/index.ts +17 -17
  141. package/src/forge/compiler/integration/index.ts +17 -17
  142. package/src/forge/compiler/integration/snapshot.ts +54 -54
  143. package/src/forge/compiler/integration/templates/convex.ts +70 -70
  144. package/src/forge/compiler/orchestrator/discover.ts +214 -214
  145. package/src/forge/compiler/orchestrator/guards.ts +5 -5
  146. package/src/forge/compiler/orchestrator/index.ts +27 -27
  147. package/src/forge/compiler/orchestrator/orphans.ts +51 -51
  148. package/src/forge/compiler/orchestrator/profile.ts +23 -23
  149. package/src/forge/compiler/orchestrator/serialize.ts +979 -979
  150. package/src/forge/compiler/orchestrator/verify.ts +35 -35
  151. package/src/forge/compiler/package-graph/capabilities-stub.ts +33 -33
  152. package/src/forge/compiler/package-graph/checksum.ts +107 -107
  153. package/src/forge/compiler/package-graph/exports-discovery.ts +91 -91
  154. package/src/forge/compiler/package-graph/extract-dts.ts +32 -32
  155. package/src/forge/compiler/package-graph/index.ts +24 -24
  156. package/src/forge/compiler/package-graph/jsdoc.ts +50 -50
  157. package/src/forge/compiler/package-graph/oracle.ts +326 -326
  158. package/src/forge/compiler/package-graph/read-file.ts +21 -21
  159. package/src/forge/compiler/package-graph/resolve.ts +131 -131
  160. package/src/forge/compiler/package-manager/adapter.ts +240 -240
  161. package/src/forge/compiler/package-manager/commands.ts +51 -51
  162. package/src/forge/compiler/package-manager/detect.ts +65 -65
  163. package/src/forge/compiler/package-manager/executor.ts +146 -146
  164. package/src/forge/compiler/package-manager/index.ts +22 -22
  165. package/src/forge/compiler/package-manager/parse-spec.ts +16 -16
  166. package/src/forge/compiler/primitives/compare.ts +26 -26
  167. package/src/forge/compiler/primitives/hash.ts +29 -29
  168. package/src/forge/compiler/primitives/header.ts +43 -43
  169. package/src/forge/compiler/primitives/index.ts +45 -45
  170. package/src/forge/compiler/primitives/paths.ts +24 -24
  171. package/src/forge/compiler/primitives/serialize.ts +66 -66
  172. package/src/forge/compiler/primitives/sort.ts +87 -87
  173. package/src/forge/compiler/recipes/helpers.ts +37 -37
  174. package/src/forge/compiler/sandbox/artifact-sanitize.ts +26 -26
  175. package/src/forge/compiler/sandbox/backends/child.ts +123 -123
  176. package/src/forge/compiler/sandbox/backends/docker.ts +173 -173
  177. package/src/forge/compiler/sandbox/index.ts +51 -51
  178. package/src/forge/compiler/sandbox/inspect.ts +143 -143
  179. package/src/forge/compiler/sandbox/inspector-entry.ts +115 -115
  180. package/src/forge/compiler/sandbox/limits.ts +31 -31
  181. package/src/forge/compiler/sandbox/scrub-env.ts +60 -60
  182. package/src/forge/compiler/sandbox/secret-scan.ts +54 -54
  183. package/src/forge/compiler/sandbox/serialize.ts +106 -106
  184. package/src/forge/compiler/sandbox/types.ts +7 -7
  185. package/src/forge/compiler/test-graph/build.ts +285 -285
  186. package/src/forge/compiler/types/app-graph.ts +87 -87
  187. package/src/forge/compiler/types/capability.ts +29 -29
  188. package/src/forge/compiler/types/classification.ts +9 -9
  189. package/src/forge/compiler/types/diagnostic.ts +2 -2
  190. package/src/forge/compiler/types/frontend-graph.ts +81 -81
  191. package/src/forge/compiler/types/import-guards.ts +19 -19
  192. package/src/forge/compiler/types/index.ts +98 -98
  193. package/src/forge/compiler/types/json.ts +3 -3
  194. package/src/forge/compiler/types/lock.ts +37 -37
  195. package/src/forge/compiler/types/runtime-matrix.ts +16 -16
  196. package/src/forge/compiler/types/runtime.ts +30 -30
  197. package/src/forge/compiler/types/sandbox.ts +24 -24
  198. package/src/forge/delta/broker-runner.mjs +5 -0
  199. package/src/forge/delta/broker.ts +429 -0
  200. package/src/forge/delta/classifier.ts +52 -52
  201. package/src/forge/delta/explain.ts +238 -238
  202. package/src/forge/delta/git-observer.ts +24 -0
  203. package/src/forge/delta/ids.ts +40 -40
  204. package/src/forge/delta/index.ts +25 -25
  205. package/src/forge/delta/process-identity.ts +31 -0
  206. package/src/forge/delta/queue-status.ts +190 -0
  207. package/src/forge/delta/redaction.ts +50 -50
  208. package/src/forge/delta/schema.ts +135 -135
  209. package/src/forge/delta/session.ts +142 -142
  210. package/src/forge/delta/status.ts +82 -145
  211. package/src/forge/delta/store.ts +77 -32
  212. package/src/forge/delta/timeline.ts +178 -178
  213. package/src/forge/dev/types.ts +63 -63
  214. package/src/forge/dev/watch.ts +119 -119
  215. package/src/forge/intent/index.ts +509 -509
  216. package/src/forge/make/types.ts +153 -153
  217. package/src/forge/refactor/index.ts +1937 -1937
  218. package/src/forge/refactor/runtime-rename.ts +598 -598
  219. package/src/forge/repair/rules/index.ts +476 -476
  220. package/src/forge/review/types.ts +211 -211
  221. package/src/forge/runtime/db/generated-client.ts +305 -305
  222. package/src/forge/runtime/db/pglite-adapter.ts +33 -11
  223. package/src/forge/runtime/runner/run-entry.ts +236 -236
  224. package/src/forge/version.ts +1 -1
  225. package/templates/agent-workroom/AGENTS.md +29 -29
  226. package/templates/agent-workroom/README.md +34 -34
  227. package/templates/agent-workroom/forge.config.ts +3 -3
  228. package/templates/agent-workroom/package.json +34 -34
  229. package/templates/agent-workroom/pnpm-workspace.yaml +2 -2
  230. package/templates/agent-workroom/src/actions/indexAgentSignal.ts +10 -10
  231. package/templates/agent-workroom/src/commands/openWorkroom.ts +61 -61
  232. package/templates/agent-workroom/src/commands/recordAgentSignal.ts +119 -119
  233. package/templates/agent-workroom/src/commands/recordCheckRun.ts +52 -52
  234. package/templates/agent-workroom/src/forge/schema.ts +54 -54
  235. package/templates/agent-workroom/src/policies.ts +6 -6
  236. package/templates/agent-workroom/src/queries/listWorkrooms.ts +11 -11
  237. package/templates/agent-workroom/src/queries/liveWorkroom.ts +63 -63
  238. package/templates/agent-workroom/tsconfig.json +16 -16
  239. package/templates/agent-workroom/web/index.html +13 -13
  240. package/templates/agent-workroom/web/package.json +21 -21
  241. package/templates/agent-workroom/web/src/App.tsx +345 -345
  242. package/templates/agent-workroom/web/src/main.tsx +13 -13
  243. package/templates/agent-workroom/web/src/styles.css +545 -545
  244. package/templates/agent-workroom/web/tsconfig.json +27 -27
  245. package/templates/b2b-support-web/package.json +37 -37
  246. package/templates/b2b-support-web/pnpm-workspace.yaml +2 -2
  247. package/templates/b2b-support-web/web/package.json +21 -21
  248. package/templates/minimal-web/package.json +34 -34
  249. package/templates/minimal-web/pnpm-workspace.yaml +2 -2
  250. package/templates/minimal-web/web/index.html +13 -13
  251. package/templates/minimal-web/web/src/styles.css +190 -190
  252. package/templates/nuxt-web/.vscode/settings.json +14 -14
  253. package/templates/nuxt-web/.yarnrc.yml +1 -1
  254. package/templates/nuxt-web/README.md +30 -30
  255. package/templates/nuxt-web/forge.config.ts +3 -3
  256. package/templates/nuxt-web/package.json +34 -34
  257. package/templates/nuxt-web/pnpm-workspace.yaml +2 -2
  258. package/templates/nuxt-web/src/actions/logNoteCreated.ts +11 -11
  259. package/templates/nuxt-web/src/commands/createNote.ts +26 -26
  260. package/templates/nuxt-web/src/forge/schema.ts +12 -12
  261. package/templates/nuxt-web/src/policies.ts +6 -6
  262. package/templates/nuxt-web/src/queries/listNotes.ts +8 -8
  263. package/templates/nuxt-web/src/queries/liveNotes.ts +8 -8
  264. package/templates/nuxt-web/tsconfig.json +17 -17
  265. package/templates/nuxt-web/web/app.vue +67 -67
  266. package/templates/nuxt-web/web/components/LiveNotes.vue +89 -89
  267. package/templates/nuxt-web/web/components/NoteComposer.vue +100 -100
  268. package/templates/nuxt-web/web/composables/forge.ts +13 -13
  269. package/templates/nuxt-web/web/composables/useNotes.ts +24 -24
  270. package/templates/nuxt-web/web/nuxt.config.ts +11 -11
  271. package/templates/nuxt-web/web/package.json +19 -19
  272. package/templates/nuxt-web/web/plugins/forge.client.ts +10 -10
  273. package/templates/nuxt-web/web/plugins/forge.server.ts +10 -10
  274. package/templates/nuxt-web/web/server/api/forge-health.get.ts +7 -7
  275. package/templates/nuxt-web/web/tsconfig.json +6 -6
  276. package/templates/vendor-access/.vscode/settings.json +14 -14
  277. package/templates/vendor-access/README.md +30 -30
  278. package/templates/vendor-access/package.json +35 -35
  279. package/templates/vendor-access/pnpm-workspace.yaml +2 -2
  280. package/templates/vendor-access/tsconfig.json +17 -17
  281. package/templates/vendor-access/web/index.html +13 -13
  282. package/templates/vendor-access/web/package.json +21 -21
  283. package/templates/vendor-access/web/src/styles.css +682 -682
  284. package/templates/vendor-access/web/tsconfig.json +18 -18
@@ -1,8 +1,8 @@
1
- package dev.forgeos.adapter;
2
-
3
- import com.fasterxml.jackson.databind.JsonNode;
4
-
5
- @FunctionalInterface
6
- public interface ForgeHandler {
7
- Object handle(ForgeContext context, JsonNode args) throws Exception;
8
- }
1
+ package dev.forgeos.adapter;
2
+
3
+ import com.fasterxml.jackson.databind.JsonNode;
4
+
5
+ @FunctionalInterface
6
+ public interface ForgeHandler {
7
+ Object handle(ForgeContext context, JsonNode args) throws Exception;
8
+ }
@@ -1,179 +1,179 @@
1
- package dev.forgeos.adapter;
2
-
3
- import com.fasterxml.jackson.databind.JsonNode;
4
- import com.sun.net.httpserver.Headers;
5
- import com.sun.net.httpserver.HttpExchange;
6
- import com.sun.net.httpserver.HttpHandler;
7
- import com.sun.net.httpserver.HttpServer;
8
- import java.io.IOException;
9
- import java.io.InputStream;
10
- import java.io.OutputStream;
11
- import java.net.InetSocketAddress;
12
- import java.net.URI;
13
- import java.net.URLDecoder;
14
- import java.nio.charset.StandardCharsets;
15
- import java.util.HashMap;
16
- import java.util.List;
17
- import java.util.Map;
18
-
19
- public final class ForgeHttpHandler implements HttpHandler {
20
- private final ForgeRegistry registry;
21
-
22
- public ForgeHttpHandler(ForgeRegistry registry) {
23
- this.registry = registry;
24
- }
25
-
26
- public static HttpServer listen(ForgeRegistry registry, String host, int port) throws IOException {
27
- HttpServer server = HttpServer.create(new InetSocketAddress(host, port), 0);
28
- ForgeHttpHandler handler = new ForgeHttpHandler(registry);
29
- server.createContext("/", handler);
30
- server.start();
31
- return server;
32
- }
33
-
34
- @Override
35
- public void handle(HttpExchange exchange) throws IOException {
36
- String path = exchange.getRequestURI().getPath();
37
- try {
38
- if (registry.healthPath().equals(path)) {
39
- writeJson(exchange, 200, Map.of("ok", true, "service", registry.serviceName()));
40
- return;
41
- }
42
- if ("/manifest".equals(path)) {
43
- String baseUrl = queryParams(exchange.getRequestURI()).getOrDefault("baseUrl", registry.baseUrl());
44
- writeJson(exchange, 200, registry.manifest(baseUrl));
45
- return;
46
- }
47
- if (path.startsWith("/commands/")) {
48
- handleRuntime(exchange, EntryKind.COMMAND, path.substring("/commands/".length()));
49
- return;
50
- }
51
- if (path.startsWith("/queries/")) {
52
- handleRuntime(exchange, EntryKind.QUERY, path.substring("/queries/".length()));
53
- return;
54
- }
55
- writeError(exchange, 404, traceIdFrom(exchange, null), "FORGE_JAVA_ROUTE_NOT_FOUND", "route not found");
56
- } catch (Exception error) {
57
- writeError(exchange, 500, traceIdFrom(exchange, null), "FORGE_JAVA_HANDLER_FAILED", error.getMessage());
58
- }
59
- }
60
-
61
- private void handleRuntime(HttpExchange exchange, EntryKind kind, String rawName) throws IOException {
62
- String name = decode(rawName);
63
- if (!"POST".equals(exchange.getRequestMethod()) && !"GET".equals(exchange.getRequestMethod())) {
64
- writeError(exchange, 405, traceIdFrom(exchange, null), "FORGE_JAVA_METHOD_NOT_ALLOWED", "external entry only accepts GET or POST");
65
- return;
66
- }
67
-
68
- ForgeRegistry.RegisteredEntry registered = registry.lookup(kind, name);
69
- if (registered == null) {
70
- writeError(exchange, 404, traceIdFrom(exchange, null), "FORGE_JAVA_ENTRY_NOT_FOUND", "external entry not found");
71
- return;
72
- }
73
-
74
- RequestEnvelope envelope;
75
- try {
76
- envelope = readEnvelope(exchange);
77
- } catch (Exception error) {
78
- writeError(exchange, 400, traceIdFrom(exchange, null), "FORGE_JAVA_BAD_REQUEST", error.getMessage());
79
- return;
80
- }
81
-
82
- String traceId = traceIdFrom(exchange, envelope);
83
- ForgeCall forge = envelope.forge() == null
84
- ? new ForgeCall(registry.serviceName(), name, kind.value(), traceId)
85
- : envelope.forge().withDefaults(registry.serviceName(), name, kind.value(), traceId);
86
- Auth auth = envelope.auth() == null || envelope.auth().kind() == null
87
- ? authFromHeaders(exchange.getRequestHeaders())
88
- : envelope.auth();
89
-
90
- ForgeContext context = new ForgeContext(auth, forge, exchange.getRequestHeaders());
91
- try {
92
- Object result = registered.handler().handle(context, envelope.args());
93
- writeJson(exchange, 200, ResponseEnvelope.ok(result, forge.traceId()));
94
- } catch (Exception error) {
95
- writeError(exchange, 500, forge.traceId(), "FORGE_JAVA_HANDLER_FAILED", error.getMessage());
96
- }
97
- }
98
-
99
- private RequestEnvelope readEnvelope(HttpExchange exchange) throws IOException {
100
- if ("GET".equals(exchange.getRequestMethod())) {
101
- String args = queryParams(exchange.getRequestURI()).getOrDefault("args", "{}");
102
- JsonNode argsNode = Json.MAPPER.readTree(args);
103
- return new RequestEnvelope(argsNode, null, null);
104
- }
105
-
106
- try (InputStream body = exchange.getRequestBody()) {
107
- byte[] bytes = body.readAllBytes();
108
- if (bytes.length == 0) {
109
- return new RequestEnvelope(Json.MAPPER.createObjectNode(), null, null);
110
- }
111
- RequestEnvelope envelope = Json.MAPPER.readValue(bytes, RequestEnvelope.class);
112
- JsonNode args = envelope.args() == null ? Json.MAPPER.createObjectNode() : envelope.args();
113
- return new RequestEnvelope(args, envelope.auth(), envelope.forge());
114
- }
115
- }
116
-
117
- private static Auth authFromHeaders(Headers headers) {
118
- String kind = firstHeader(headers, "x-forge-auth-kind");
119
- if (kind == null || kind.isBlank()) {
120
- kind = "anonymous";
121
- }
122
- return new Auth(
123
- kind,
124
- firstHeader(headers, "x-forge-user-id"),
125
- firstHeader(headers, "x-forge-tenant-id"),
126
- firstHeader(headers, "x-forge-role"),
127
- null,
128
- null,
129
- null,
130
- null,
131
- null
132
- );
133
- }
134
-
135
- private static String traceIdFrom(HttpExchange exchange, RequestEnvelope envelope) {
136
- if (envelope != null && envelope.forge() != null && envelope.forge().traceId() != null) {
137
- return envelope.forge().traceId();
138
- }
139
- return firstHeader(exchange.getRequestHeaders(), "x-forge-trace-id");
140
- }
141
-
142
- private static String firstHeader(Headers headers, String name) {
143
- List<String> values = headers.get(name);
144
- if (values == null || values.isEmpty()) {
145
- values = headers.get(name.toLowerCase());
146
- }
147
- return values == null || values.isEmpty() ? null : values.get(0);
148
- }
149
-
150
- private static Map<String, String> queryParams(URI uri) {
151
- Map<String, String> params = new HashMap<>();
152
- String query = uri.getRawQuery();
153
- if (query == null || query.isBlank()) {
154
- return params;
155
- }
156
- for (String part : query.split("&")) {
157
- String[] pieces = part.split("=", 2);
158
- params.put(decode(pieces[0]), pieces.length > 1 ? decode(pieces[1]) : "");
159
- }
160
- return params;
161
- }
162
-
163
- private static String decode(String value) {
164
- return URLDecoder.decode(value, StandardCharsets.UTF_8);
165
- }
166
-
167
- private static void writeError(HttpExchange exchange, int status, String traceId, String code, String message) throws IOException {
168
- writeJson(exchange, status, ResponseEnvelope.error(code, message, traceId));
169
- }
170
-
171
- private static void writeJson(HttpExchange exchange, int status, Object body) throws IOException {
172
- byte[] bytes = Json.MAPPER.writeValueAsBytes(body);
173
- exchange.getResponseHeaders().set("content-type", "application/json");
174
- exchange.sendResponseHeaders(status, bytes.length);
175
- try (OutputStream response = exchange.getResponseBody()) {
176
- response.write(bytes);
177
- }
178
- }
179
- }
1
+ package dev.forgeos.adapter;
2
+
3
+ import com.fasterxml.jackson.databind.JsonNode;
4
+ import com.sun.net.httpserver.Headers;
5
+ import com.sun.net.httpserver.HttpExchange;
6
+ import com.sun.net.httpserver.HttpHandler;
7
+ import com.sun.net.httpserver.HttpServer;
8
+ import java.io.IOException;
9
+ import java.io.InputStream;
10
+ import java.io.OutputStream;
11
+ import java.net.InetSocketAddress;
12
+ import java.net.URI;
13
+ import java.net.URLDecoder;
14
+ import java.nio.charset.StandardCharsets;
15
+ import java.util.HashMap;
16
+ import java.util.List;
17
+ import java.util.Map;
18
+
19
+ public final class ForgeHttpHandler implements HttpHandler {
20
+ private final ForgeRegistry registry;
21
+
22
+ public ForgeHttpHandler(ForgeRegistry registry) {
23
+ this.registry = registry;
24
+ }
25
+
26
+ public static HttpServer listen(ForgeRegistry registry, String host, int port) throws IOException {
27
+ HttpServer server = HttpServer.create(new InetSocketAddress(host, port), 0);
28
+ ForgeHttpHandler handler = new ForgeHttpHandler(registry);
29
+ server.createContext("/", handler);
30
+ server.start();
31
+ return server;
32
+ }
33
+
34
+ @Override
35
+ public void handle(HttpExchange exchange) throws IOException {
36
+ String path = exchange.getRequestURI().getPath();
37
+ try {
38
+ if (registry.healthPath().equals(path)) {
39
+ writeJson(exchange, 200, Map.of("ok", true, "service", registry.serviceName()));
40
+ return;
41
+ }
42
+ if ("/manifest".equals(path)) {
43
+ String baseUrl = queryParams(exchange.getRequestURI()).getOrDefault("baseUrl", registry.baseUrl());
44
+ writeJson(exchange, 200, registry.manifest(baseUrl));
45
+ return;
46
+ }
47
+ if (path.startsWith("/commands/")) {
48
+ handleRuntime(exchange, EntryKind.COMMAND, path.substring("/commands/".length()));
49
+ return;
50
+ }
51
+ if (path.startsWith("/queries/")) {
52
+ handleRuntime(exchange, EntryKind.QUERY, path.substring("/queries/".length()));
53
+ return;
54
+ }
55
+ writeError(exchange, 404, traceIdFrom(exchange, null), "FORGE_JAVA_ROUTE_NOT_FOUND", "route not found");
56
+ } catch (Exception error) {
57
+ writeError(exchange, 500, traceIdFrom(exchange, null), "FORGE_JAVA_HANDLER_FAILED", error.getMessage());
58
+ }
59
+ }
60
+
61
+ private void handleRuntime(HttpExchange exchange, EntryKind kind, String rawName) throws IOException {
62
+ String name = decode(rawName);
63
+ if (!"POST".equals(exchange.getRequestMethod()) && !"GET".equals(exchange.getRequestMethod())) {
64
+ writeError(exchange, 405, traceIdFrom(exchange, null), "FORGE_JAVA_METHOD_NOT_ALLOWED", "external entry only accepts GET or POST");
65
+ return;
66
+ }
67
+
68
+ ForgeRegistry.RegisteredEntry registered = registry.lookup(kind, name);
69
+ if (registered == null) {
70
+ writeError(exchange, 404, traceIdFrom(exchange, null), "FORGE_JAVA_ENTRY_NOT_FOUND", "external entry not found");
71
+ return;
72
+ }
73
+
74
+ RequestEnvelope envelope;
75
+ try {
76
+ envelope = readEnvelope(exchange);
77
+ } catch (Exception error) {
78
+ writeError(exchange, 400, traceIdFrom(exchange, null), "FORGE_JAVA_BAD_REQUEST", error.getMessage());
79
+ return;
80
+ }
81
+
82
+ String traceId = traceIdFrom(exchange, envelope);
83
+ ForgeCall forge = envelope.forge() == null
84
+ ? new ForgeCall(registry.serviceName(), name, kind.value(), traceId)
85
+ : envelope.forge().withDefaults(registry.serviceName(), name, kind.value(), traceId);
86
+ Auth auth = envelope.auth() == null || envelope.auth().kind() == null
87
+ ? authFromHeaders(exchange.getRequestHeaders())
88
+ : envelope.auth();
89
+
90
+ ForgeContext context = new ForgeContext(auth, forge, exchange.getRequestHeaders());
91
+ try {
92
+ Object result = registered.handler().handle(context, envelope.args());
93
+ writeJson(exchange, 200, ResponseEnvelope.ok(result, forge.traceId()));
94
+ } catch (Exception error) {
95
+ writeError(exchange, 500, forge.traceId(), "FORGE_JAVA_HANDLER_FAILED", error.getMessage());
96
+ }
97
+ }
98
+
99
+ private RequestEnvelope readEnvelope(HttpExchange exchange) throws IOException {
100
+ if ("GET".equals(exchange.getRequestMethod())) {
101
+ String args = queryParams(exchange.getRequestURI()).getOrDefault("args", "{}");
102
+ JsonNode argsNode = Json.MAPPER.readTree(args);
103
+ return new RequestEnvelope(argsNode, null, null);
104
+ }
105
+
106
+ try (InputStream body = exchange.getRequestBody()) {
107
+ byte[] bytes = body.readAllBytes();
108
+ if (bytes.length == 0) {
109
+ return new RequestEnvelope(Json.MAPPER.createObjectNode(), null, null);
110
+ }
111
+ RequestEnvelope envelope = Json.MAPPER.readValue(bytes, RequestEnvelope.class);
112
+ JsonNode args = envelope.args() == null ? Json.MAPPER.createObjectNode() : envelope.args();
113
+ return new RequestEnvelope(args, envelope.auth(), envelope.forge());
114
+ }
115
+ }
116
+
117
+ private static Auth authFromHeaders(Headers headers) {
118
+ String kind = firstHeader(headers, "x-forge-auth-kind");
119
+ if (kind == null || kind.isBlank()) {
120
+ kind = "anonymous";
121
+ }
122
+ return new Auth(
123
+ kind,
124
+ firstHeader(headers, "x-forge-user-id"),
125
+ firstHeader(headers, "x-forge-tenant-id"),
126
+ firstHeader(headers, "x-forge-role"),
127
+ null,
128
+ null,
129
+ null,
130
+ null,
131
+ null
132
+ );
133
+ }
134
+
135
+ private static String traceIdFrom(HttpExchange exchange, RequestEnvelope envelope) {
136
+ if (envelope != null && envelope.forge() != null && envelope.forge().traceId() != null) {
137
+ return envelope.forge().traceId();
138
+ }
139
+ return firstHeader(exchange.getRequestHeaders(), "x-forge-trace-id");
140
+ }
141
+
142
+ private static String firstHeader(Headers headers, String name) {
143
+ List<String> values = headers.get(name);
144
+ if (values == null || values.isEmpty()) {
145
+ values = headers.get(name.toLowerCase());
146
+ }
147
+ return values == null || values.isEmpty() ? null : values.get(0);
148
+ }
149
+
150
+ private static Map<String, String> queryParams(URI uri) {
151
+ Map<String, String> params = new HashMap<>();
152
+ String query = uri.getRawQuery();
153
+ if (query == null || query.isBlank()) {
154
+ return params;
155
+ }
156
+ for (String part : query.split("&")) {
157
+ String[] pieces = part.split("=", 2);
158
+ params.put(decode(pieces[0]), pieces.length > 1 ? decode(pieces[1]) : "");
159
+ }
160
+ return params;
161
+ }
162
+
163
+ private static String decode(String value) {
164
+ return URLDecoder.decode(value, StandardCharsets.UTF_8);
165
+ }
166
+
167
+ private static void writeError(HttpExchange exchange, int status, String traceId, String code, String message) throws IOException {
168
+ writeJson(exchange, status, ResponseEnvelope.error(code, message, traceId));
169
+ }
170
+
171
+ private static void writeJson(HttpExchange exchange, int status, Object body) throws IOException {
172
+ byte[] bytes = Json.MAPPER.writeValueAsBytes(body);
173
+ exchange.getResponseHeaders().set("content-type", "application/json");
174
+ exchange.sendResponseHeaders(status, bytes.length);
175
+ try (OutputStream response = exchange.getResponseBody()) {
176
+ response.write(bytes);
177
+ }
178
+ }
179
+ }
@@ -1,121 +1,121 @@
1
- package dev.forgeos.adapter;
2
-
3
- import java.io.IOException;
4
- import java.io.OutputStream;
5
- import java.util.ArrayList;
6
- import java.util.LinkedHashMap;
7
- import java.util.List;
8
- import java.util.Map;
9
-
10
- public final class ForgeRegistry {
11
- private final Service service;
12
- private final Map<String, Object> schemas = new LinkedHashMap<>();
13
- private final List<RegisteredEntry> entries = new ArrayList<>();
14
- private final Map<String, RegisteredEntry> lookup = new LinkedHashMap<>();
15
- private String framework = "java/jdk-http";
16
-
17
- public ForgeRegistry(String serviceName, RegistryOption... options) {
18
- this.service = new Service(serviceName, "http", null, null, "/health");
19
- for (RegistryOption option : options) {
20
- option.apply(this);
21
- }
22
- }
23
-
24
- public String serviceName() {
25
- return service.name();
26
- }
27
-
28
- public String baseUrl() {
29
- return service.baseUrl();
30
- }
31
-
32
- public String healthPath() {
33
- return service.health() == null ? "/health" : service.health();
34
- }
35
-
36
- public void command(String name, ForgeHandler handler, EntryOption... options) {
37
- Entry entry = new Entry();
38
- entry.name = name;
39
- entry.kind = EntryKind.COMMAND.value();
40
- entry.path = "/commands/" + name;
41
- entry.method = "POST";
42
- entry.transaction = TransactionMode.EXTERNAL_MANAGED.value();
43
- entry.risk = Risk.WRITE.value();
44
- add(entry, handler, options);
45
- }
46
-
47
- public void query(String name, ForgeHandler handler, EntryOption... options) {
48
- Entry entry = new Entry();
49
- entry.name = name;
50
- entry.kind = EntryKind.QUERY.value();
51
- entry.path = "/queries/" + name;
52
- entry.method = "POST";
53
- entry.transaction = TransactionMode.READ_ONLY.value();
54
- entry.risk = Risk.READ.value();
55
- add(entry, handler, options);
56
- }
57
-
58
- public Manifest manifest(String baseUrl) {
59
- Service manifestService = service;
60
- if (baseUrl != null && !baseUrl.isBlank()) {
61
- manifestService = new Service(service.name(), service.transport(), baseUrl, service.command(), service.health());
62
- }
63
- List<Entry> manifestEntries = entries.stream().map(registered -> registered.entry().copy()).toList();
64
- return new Manifest("1.0", "java", framework, manifestService, manifestEntries, schemas.isEmpty() ? null : schemas);
65
- }
66
-
67
- public byte[] marshalManifest(String baseUrl) throws IOException {
68
- return Json.MAPPER.writerWithDefaultPrettyPrinter().writeValueAsBytes(manifest(baseUrl));
69
- }
70
-
71
- public void writeManifest(OutputStream output, String baseUrl) throws IOException {
72
- output.write(marshalManifest(baseUrl));
73
- output.write('\n');
74
- }
75
-
76
- RegisteredEntry lookup(EntryKind kind, String name) {
77
- return lookup.get(key(kind, name));
78
- }
79
-
80
- void setFramework(String framework) {
81
- this.framework = framework;
82
- }
83
-
84
- void setBaseUrl(String baseUrl) {
85
- this.service.setBaseUrl(baseUrl);
86
- }
87
-
88
- void setHealth(String health) {
89
- this.service.setHealth(health);
90
- }
91
-
92
- void addSchema(String name, Object schema) {
93
- this.schemas.put(name, schema);
94
- }
95
-
96
- private void add(Entry entry, ForgeHandler handler, EntryOption... options) {
97
- for (EntryOption option : options) {
98
- option.apply(entry);
99
- }
100
- RegisteredEntry registered = new RegisteredEntry(entry, handler);
101
- entries.add(registered);
102
- lookup.put(key(EntryKind.valueOf(entry.kind.toUpperCase()), entry.name), registered);
103
- }
104
-
105
- private static String key(EntryKind kind, String name) {
106
- return kind.value() + ":" + name;
107
- }
108
-
109
- @FunctionalInterface
110
- public interface RegistryOption {
111
- void apply(ForgeRegistry registry);
112
- }
113
-
114
- @FunctionalInterface
115
- public interface EntryOption {
116
- void apply(Entry entry);
117
- }
118
-
119
- record RegisteredEntry(Entry entry, ForgeHandler handler) {
120
- }
121
- }
1
+ package dev.forgeos.adapter;
2
+
3
+ import java.io.IOException;
4
+ import java.io.OutputStream;
5
+ import java.util.ArrayList;
6
+ import java.util.LinkedHashMap;
7
+ import java.util.List;
8
+ import java.util.Map;
9
+
10
+ public final class ForgeRegistry {
11
+ private final Service service;
12
+ private final Map<String, Object> schemas = new LinkedHashMap<>();
13
+ private final List<RegisteredEntry> entries = new ArrayList<>();
14
+ private final Map<String, RegisteredEntry> lookup = new LinkedHashMap<>();
15
+ private String framework = "java/jdk-http";
16
+
17
+ public ForgeRegistry(String serviceName, RegistryOption... options) {
18
+ this.service = new Service(serviceName, "http", null, null, "/health");
19
+ for (RegistryOption option : options) {
20
+ option.apply(this);
21
+ }
22
+ }
23
+
24
+ public String serviceName() {
25
+ return service.name();
26
+ }
27
+
28
+ public String baseUrl() {
29
+ return service.baseUrl();
30
+ }
31
+
32
+ public String healthPath() {
33
+ return service.health() == null ? "/health" : service.health();
34
+ }
35
+
36
+ public void command(String name, ForgeHandler handler, EntryOption... options) {
37
+ Entry entry = new Entry();
38
+ entry.name = name;
39
+ entry.kind = EntryKind.COMMAND.value();
40
+ entry.path = "/commands/" + name;
41
+ entry.method = "POST";
42
+ entry.transaction = TransactionMode.EXTERNAL_MANAGED.value();
43
+ entry.risk = Risk.WRITE.value();
44
+ add(entry, handler, options);
45
+ }
46
+
47
+ public void query(String name, ForgeHandler handler, EntryOption... options) {
48
+ Entry entry = new Entry();
49
+ entry.name = name;
50
+ entry.kind = EntryKind.QUERY.value();
51
+ entry.path = "/queries/" + name;
52
+ entry.method = "POST";
53
+ entry.transaction = TransactionMode.READ_ONLY.value();
54
+ entry.risk = Risk.READ.value();
55
+ add(entry, handler, options);
56
+ }
57
+
58
+ public Manifest manifest(String baseUrl) {
59
+ Service manifestService = service;
60
+ if (baseUrl != null && !baseUrl.isBlank()) {
61
+ manifestService = new Service(service.name(), service.transport(), baseUrl, service.command(), service.health());
62
+ }
63
+ List<Entry> manifestEntries = entries.stream().map(registered -> registered.entry().copy()).toList();
64
+ return new Manifest("1.0", "java", framework, manifestService, manifestEntries, schemas.isEmpty() ? null : schemas);
65
+ }
66
+
67
+ public byte[] marshalManifest(String baseUrl) throws IOException {
68
+ return Json.MAPPER.writerWithDefaultPrettyPrinter().writeValueAsBytes(manifest(baseUrl));
69
+ }
70
+
71
+ public void writeManifest(OutputStream output, String baseUrl) throws IOException {
72
+ output.write(marshalManifest(baseUrl));
73
+ output.write('\n');
74
+ }
75
+
76
+ RegisteredEntry lookup(EntryKind kind, String name) {
77
+ return lookup.get(key(kind, name));
78
+ }
79
+
80
+ void setFramework(String framework) {
81
+ this.framework = framework;
82
+ }
83
+
84
+ void setBaseUrl(String baseUrl) {
85
+ this.service.setBaseUrl(baseUrl);
86
+ }
87
+
88
+ void setHealth(String health) {
89
+ this.service.setHealth(health);
90
+ }
91
+
92
+ void addSchema(String name, Object schema) {
93
+ this.schemas.put(name, schema);
94
+ }
95
+
96
+ private void add(Entry entry, ForgeHandler handler, EntryOption... options) {
97
+ for (EntryOption option : options) {
98
+ option.apply(entry);
99
+ }
100
+ RegisteredEntry registered = new RegisteredEntry(entry, handler);
101
+ entries.add(registered);
102
+ lookup.put(key(EntryKind.valueOf(entry.kind.toUpperCase()), entry.name), registered);
103
+ }
104
+
105
+ private static String key(EntryKind kind, String name) {
106
+ return kind.value() + ":" + name;
107
+ }
108
+
109
+ @FunctionalInterface
110
+ public interface RegistryOption {
111
+ void apply(ForgeRegistry registry);
112
+ }
113
+
114
+ @FunctionalInterface
115
+ public interface EntryOption {
116
+ void apply(Entry entry);
117
+ }
118
+
119
+ record RegisteredEntry(Entry entry, ForgeHandler handler) {
120
+ }
121
+ }
@@ -1,14 +1,14 @@
1
- package dev.forgeos.adapter;
2
-
3
- import com.fasterxml.jackson.annotation.JsonInclude;
4
- import com.fasterxml.jackson.databind.DeserializationFeature;
5
- import com.fasterxml.jackson.databind.ObjectMapper;
6
-
7
- public final class Json {
8
- public static final ObjectMapper MAPPER = new ObjectMapper()
9
- .setSerializationInclusion(JsonInclude.Include.NON_NULL)
10
- .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
11
-
12
- private Json() {
13
- }
14
- }
1
+ package dev.forgeos.adapter;
2
+
3
+ import com.fasterxml.jackson.annotation.JsonInclude;
4
+ import com.fasterxml.jackson.databind.DeserializationFeature;
5
+ import com.fasterxml.jackson.databind.ObjectMapper;
6
+
7
+ public final class Json {
8
+ public static final ObjectMapper MAPPER = new ObjectMapper()
9
+ .setSerializationInclusion(JsonInclude.Include.NON_NULL)
10
+ .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
11
+
12
+ private Json() {
13
+ }
14
+ }