forgeos 0.1.0-alpha.7 → 0.1.0-alpha.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +1 -1
- package/CHANGELOG.md +14 -0
- package/adapters/go/README.md +23 -0
- package/adapters/go/go.mod +3 -0
- package/adapters/go/http.go +149 -0
- package/adapters/go/registry.go +234 -0
- package/adapters/go/types.go +136 -0
- package/docs/changelog.md +82 -0
- package/docs/forge-protocol.md +155 -0
- package/examples/go-billing/go.mod +7 -0
- package/examples/go-billing/main.go +120 -0
- package/package.json +5 -1
- package/schemas/forge-manifest.schema.json +57 -0
- package/src/forge/_generated/actionSubscriptions.json +2 -2
- package/src/forge/_generated/actionSubscriptions.ts +3 -3
- package/src/forge/_generated/agentAdapterManifest.json +2 -2
- package/src/forge/_generated/agentAdapterManifest.ts +3 -3
- package/src/forge/_generated/agentContract.json +2 -2
- package/src/forge/_generated/agentContract.ts +5 -2
- package/src/forge/_generated/agentQuickstart.md +1 -1
- package/src/forge/_generated/agentTools.json +2 -2
- package/src/forge/_generated/agentTools.md +1 -1
- package/src/forge/_generated/agentTools.ts +2 -2
- package/src/forge/_generated/aiContext.ts +1 -1
- package/src/forge/_generated/aiModels.json +1 -1
- package/src/forge/_generated/aiModels.ts +1 -1
- package/src/forge/_generated/aiProviders.json +1 -1
- package/src/forge/_generated/aiProviders.ts +1 -1
- package/src/forge/_generated/aiRegistry.json +2 -2
- package/src/forge/_generated/aiRegistry.ts +3 -3
- package/src/forge/_generated/api.json +2 -2
- package/src/forge/_generated/api.ts +7 -2
- package/src/forge/_generated/appGraph.json +2 -2
- package/src/forge/_generated/appGraph.ts +661 -254
- package/src/forge/_generated/appMap.md +1 -1
- package/src/forge/_generated/artifactManifest.json +2 -2
- package/src/forge/_generated/artifactManifest.ts +2 -2
- package/src/forge/_generated/authClaims.json +1 -1
- package/src/forge/_generated/authClaims.ts +1 -1
- package/src/forge/_generated/authConfig.json +1 -1
- package/src/forge/_generated/authConfig.ts +1 -1
- package/src/forge/_generated/authContext.ts +1 -1
- package/src/forge/_generated/authRegistry.json +1 -1
- package/src/forge/_generated/authRegistry.ts +1 -1
- package/src/forge/_generated/buildInfo.json +2 -2
- package/src/forge/_generated/buildInfo.ts +4 -4
- package/src/forge/_generated/capabilityMap.json +2 -2
- package/src/forge/_generated/capabilityMap.md +1 -1
- package/src/forge/_generated/capabilityMap.ts +2 -2
- package/src/forge/_generated/client.ts +88 -1
- package/src/forge/_generated/clientApi.ts +2 -1
- package/src/forge/_generated/clientManifest.json +2 -2
- package/src/forge/_generated/clientManifest.ts +6 -4
- package/src/forge/_generated/clientTypes.ts +19 -1
- package/src/forge/_generated/configRegistry.json +1 -1
- package/src/forge/_generated/configRegistry.ts +1 -1
- package/src/forge/_generated/dataGraph.json +2 -2
- package/src/forge/_generated/dataGraph.ts +3 -3
- package/src/forge/_generated/db.json +1 -1
- package/src/forge/_generated/db.ts +1 -1
- package/src/forge/_generated/dbSecurityManifest.json +1 -1
- package/src/forge/_generated/dbSecurityManifest.ts +1 -1
- package/src/forge/_generated/dbSessionContext.json +1 -1
- package/src/forge/_generated/dbSessionContext.ts +1 -1
- package/src/forge/_generated/deployManifest.json +2 -2
- package/src/forge/_generated/deployManifest.ts +7 -7
- package/src/forge/_generated/devManifest.json +2 -2
- package/src/forge/_generated/devManifest.ts +3 -3
- package/src/forge/_generated/envSchema.json +1 -1
- package/src/forge/_generated/envSchema.ts +1 -1
- package/src/forge/_generated/externalServices.json +2 -0
- package/src/forge/_generated/externalServices.ts +9 -0
- package/src/forge/_generated/frontendGraph.json +1 -1
- package/src/forge/_generated/frontendGraph.ts +1 -1
- package/src/forge/_generated/importGuards.json +1 -1
- package/src/forge/_generated/importGuards.ts +1 -1
- package/src/forge/_generated/index.ts +2 -1
- package/src/forge/_generated/liveProductionManifest.json +1 -1
- package/src/forge/_generated/liveProductionManifest.ts +1 -1
- package/src/forge/_generated/liveProtocol.json +1 -1
- package/src/forge/_generated/liveProtocol.ts +1 -1
- package/src/forge/_generated/liveQueryRegistry.json +2 -2
- package/src/forge/_generated/liveQueryRegistry.ts +3 -3
- package/src/forge/_generated/liveTransportConfig.json +1 -1
- package/src/forge/_generated/liveTransportConfig.ts +1 -1
- package/src/forge/_generated/makeRegistry.json +2 -2
- package/src/forge/_generated/makeRegistry.ts +2 -2
- package/src/forge/_generated/makeTemplates.json +1 -1
- package/src/forge/_generated/makeTemplates.ts +1 -1
- package/src/forge/_generated/mockMap.json +1 -1
- package/src/forge/_generated/mockMap.ts +1 -1
- package/src/forge/_generated/operationPlaybooks.md +1 -1
- package/src/forge/_generated/packageGraph.json +2 -2
- package/src/forge/_generated/packageGraph.ts +2 -2
- package/src/forge/_generated/packageUpgradeRegistry.json +2 -2
- package/src/forge/_generated/packageUpgradeRegistry.ts +2 -2
- package/src/forge/_generated/permissionMatrix.json +2 -2
- package/src/forge/_generated/permissionMatrix.ts +3 -3
- package/src/forge/_generated/policyRegistry.json +2 -2
- package/src/forge/_generated/policyRegistry.ts +3 -3
- package/src/forge/_generated/queryRegistry.json +2 -2
- package/src/forge/_generated/queryRegistry.ts +3 -3
- package/src/forge/_generated/react.d.ts +1 -1
- package/src/forge/_generated/react.ts +1 -1
- package/src/forge/_generated/reactManifest.json +2 -2
- package/src/forge/_generated/reactManifest.ts +3 -3
- package/src/forge/_generated/releaseManifest.json +2 -2
- package/src/forge/_generated/releaseManifest.ts +3 -3
- package/src/forge/_generated/rlsPolicies.json +1 -1
- package/src/forge/_generated/rlsPolicies.sql +1 -1
- package/src/forge/_generated/rlsPolicies.ts +1 -1
- package/src/forge/_generated/runtimeGraph.json +2 -2
- package/src/forge/_generated/runtimeGraph.ts +3 -3
- package/src/forge/_generated/runtimeMatrix.json +1 -1
- package/src/forge/_generated/runtimeMatrix.ts +1 -1
- package/src/forge/_generated/runtimeRegistry.ts +1 -1
- package/src/forge/_generated/runtimeRules.md +1 -1
- package/src/forge/_generated/secretRegistry.json +1 -1
- package/src/forge/_generated/secretRegistry.ts +1 -1
- package/src/forge/_generated/secretsContext.ts +1 -1
- package/src/forge/_generated/serverApi.ts +2 -1
- package/src/forge/_generated/sourceMapManifest.json +2 -2
- package/src/forge/_generated/sourceMapManifest.ts +2 -2
- package/src/forge/_generated/sqlPlan.json +1 -1
- package/src/forge/_generated/sqlPlan.ts +1 -1
- package/src/forge/_generated/subscriptionManifest.json +2 -2
- package/src/forge/_generated/subscriptionManifest.ts +3 -3
- package/src/forge/_generated/symbolicationManifest.json +2 -2
- package/src/forge/_generated/symbolicationManifest.ts +2 -2
- package/src/forge/_generated/telemetryRegistry.json +2 -2
- package/src/forge/_generated/telemetryRegistry.ts +3 -3
- package/src/forge/_generated/telemetrySinks.json +2 -2
- package/src/forge/_generated/telemetrySinks.ts +2 -2
- package/src/forge/_generated/tenantScope.json +2 -2
- package/src/forge/_generated/tenantScope.ts +3 -3
- package/src/forge/_generated/testGraph.json +2 -2
- package/src/forge/_generated/testGraph.ts +57 -3
- package/src/forge/_generated/testPlanRegistry.json +2 -2
- package/src/forge/_generated/testPlanRegistry.ts +2 -2
- package/src/forge/_generated/uiRoutes.json +1 -1
- package/src/forge/_generated/uiRoutes.ts +1 -1
- package/src/forge/_generated/uiScenarios.json +1 -1
- package/src/forge/_generated/uiScenarios.ts +1 -1
- package/src/forge/_generated/uiTestManifest.json +2 -2
- package/src/forge/_generated/uiTestManifest.ts +2 -2
- package/src/forge/_generated/workflowRegistry.json +2 -2
- package/src/forge/_generated/workflowRegistry.ts +3 -3
- package/src/forge/_generated/workflowSubscriptions.json +2 -2
- package/src/forge/_generated/workflowSubscriptions.ts +3 -3
- package/src/forge/bench.ts +248 -0
- package/src/forge/cli/ai.ts +16 -1
- package/src/forge/cli/build.ts +1 -1
- package/src/forge/cli/commands.ts +118 -0
- package/src/forge/cli/main.ts +3 -1
- package/src/forge/cli/parse.ts +84 -0
- package/src/forge/cli/run.ts +41 -0
- package/src/forge/cli/verify.ts +201 -24
- package/src/forge/compiler/agent-contract/build.ts +121 -7
- package/src/forge/compiler/agent-contract/types.ts +30 -1
- package/src/forge/compiler/api-surface/build.ts +47 -0
- package/src/forge/compiler/app-graph/build.ts +33 -5
- package/src/forge/compiler/app-graph/module-graph.ts +73 -78
- package/src/forge/compiler/app-graph/parser.ts +24 -24
- package/src/forge/compiler/app-graph/profile.ts +26 -0
- package/src/forge/compiler/classifier/capabilities.ts +3 -2
- package/src/forge/compiler/classifier/classify.ts +32 -8
- package/src/forge/compiler/classifier/secrets.ts +3 -2
- package/src/forge/compiler/classifier/signals.ts +91 -1
- package/src/forge/compiler/client-sdk/build-manifest.ts +4 -0
- package/src/forge/compiler/client-sdk/render-client.ts +105 -0
- package/src/forge/compiler/diagnostics/codes.ts +12 -0
- package/src/forge/compiler/external-manifest/registry.ts +204 -0
- package/src/forge/compiler/external-manifest/types.ts +89 -0
- package/src/forge/compiler/external-manifest/validate.ts +335 -0
- package/src/forge/compiler/orchestrator/plan-profile.ts +23 -0
- package/src/forge/compiler/orchestrator/plan.ts +52 -11
- package/src/forge/compiler/orchestrator/profile.ts +65 -0
- package/src/forge/compiler/orchestrator/run.ts +97 -31
- package/src/forge/compiler/orchestrator/serialize.ts +13 -6
- package/src/forge/compiler/policy-registry/build.ts +44 -1
- package/src/forge/compiler/test-graph/build.ts +11 -3
- package/src/forge/compiler/types/cli.ts +3 -0
- package/src/forge/dev/server.ts +68 -0
- package/src/forge/runtime/external/bridge.ts +553 -0
- package/src/forge/version.ts +1 -1
package/AGENTS.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// @forge-generated generator=0.1.0-alpha.
|
|
1
|
+
// @forge-generated generator=0.1.0-alpha.9 input=f9063a03ef56a20a89f1418951bede5ab5ed87d800bb0512a0d0445309642a36 content=1611635edf59c122b013ba76c85bd333ab3b30b289aaea04a9074f9438782a50
|
|
2
2
|
# AGENTS.md
|
|
3
3
|
|
|
4
4
|
<!-- forge-generated:start -->
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# forgeos
|
|
2
2
|
|
|
3
|
+
## 0.1.0-alpha.9
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Reuse compiler classifier package signals across export classification, dropping repeated package signal scans.
|
|
8
|
+
- Reuse serialized graph JSON when rendering the largest generated TypeScript graph artifacts.
|
|
9
|
+
- Keep generated Forge artifacts aligned with the `0.1.0-alpha.9` compiler/runtime version.
|
|
10
|
+
|
|
11
|
+
## 0.1.0-alpha.8
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- [`7568756`](https://github.com/Stahldavid/forge/commit/756875688873dd60d3d6cf700a7bb7c211968c69) Thanks [@Stahldavid](https://github.com/Stahldavid)! - Publish prerelease packages through the ForgeOS alpha publisher so npm dist-tags stay aligned.
|
|
16
|
+
|
|
3
17
|
## 0.1.0-alpha.7
|
|
4
18
|
|
|
5
19
|
### Patch Changes
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Forge Go Adapter
|
|
2
|
+
|
|
3
|
+
`adapters/go` is the minimal Go SDK for external Forge runtimes. It registers
|
|
4
|
+
commands and queries, emits `forge.manifest.json`, and exposes a Forge-compatible
|
|
5
|
+
HTTP handler.
|
|
6
|
+
|
|
7
|
+
```go
|
|
8
|
+
app := forge.New("billing", forge.BaseURL("http://127.0.0.1:8787"))
|
|
9
|
+
|
|
10
|
+
app.Command("createInvoice", forge.Handle(createInvoice),
|
|
11
|
+
forge.Policy("billing.manage"),
|
|
12
|
+
forge.TenantScoped(true),
|
|
13
|
+
forge.NeedsApproval(true),
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
app.Query("listInvoices", forge.Handle(listInvoices),
|
|
17
|
+
forge.Policy("billing.manage"),
|
|
18
|
+
forge.TenantScoped(true),
|
|
19
|
+
)
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
The HTTP handler accepts Forge runtime envelopes on `/commands/:name` and
|
|
23
|
+
`/queries/:name`, then returns `{ "ok": true, "result": ... }` envelopes.
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
package forge
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"encoding/json"
|
|
5
|
+
"errors"
|
|
6
|
+
"net/http"
|
|
7
|
+
"strings"
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
func (registry *Registry) HTTPHandler() http.Handler {
|
|
11
|
+
mux := http.NewServeMux()
|
|
12
|
+
mux.HandleFunc(registry.service.Health, registry.handleHealth)
|
|
13
|
+
mux.HandleFunc("/manifest", registry.handleManifest)
|
|
14
|
+
mux.HandleFunc("/commands/", registry.handleRuntime(KindCommand, "/commands/"))
|
|
15
|
+
mux.HandleFunc("/queries/", registry.handleRuntime(KindQuery, "/queries/"))
|
|
16
|
+
return mux
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
func (registry *Registry) handleHealth(response http.ResponseWriter, request *http.Request) {
|
|
20
|
+
writeJSON(response, http.StatusOK, map[string]any{
|
|
21
|
+
"ok": true,
|
|
22
|
+
"service": registry.service.Name,
|
|
23
|
+
})
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
func (registry *Registry) handleManifest(response http.ResponseWriter, request *http.Request) {
|
|
27
|
+
baseURL := request.URL.Query().Get("baseUrl")
|
|
28
|
+
if baseURL == "" {
|
|
29
|
+
baseURL = registry.service.BaseURL
|
|
30
|
+
}
|
|
31
|
+
writeJSON(response, http.StatusOK, registry.Manifest(baseURL))
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
func (registry *Registry) handleRuntime(kind EntryKind, prefix string) http.HandlerFunc {
|
|
35
|
+
return func(response http.ResponseWriter, request *http.Request) {
|
|
36
|
+
name := strings.TrimPrefix(request.URL.Path, prefix)
|
|
37
|
+
registered, ok := registry.lookup[lookupKey(kind, name)]
|
|
38
|
+
if !ok {
|
|
39
|
+
writeError(response, http.StatusNotFound, "", "FORGE_GO_ENTRY_NOT_FOUND", "external entry not found")
|
|
40
|
+
return
|
|
41
|
+
}
|
|
42
|
+
if request.Method != http.MethodPost && request.Method != http.MethodGet {
|
|
43
|
+
writeError(response, http.StatusMethodNotAllowed, "", "FORGE_GO_METHOD_NOT_ALLOWED", "external entry only accepts GET or POST")
|
|
44
|
+
return
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
envelope, err := readRequestEnvelope(request)
|
|
48
|
+
traceID := traceIDFrom(request, envelope)
|
|
49
|
+
if err != nil {
|
|
50
|
+
writeError(response, http.StatusBadRequest, traceID, "FORGE_GO_BAD_REQUEST", err.Error())
|
|
51
|
+
return
|
|
52
|
+
}
|
|
53
|
+
if envelope.Forge.Service == "" {
|
|
54
|
+
envelope.Forge.Service = registry.service.Name
|
|
55
|
+
}
|
|
56
|
+
if envelope.Forge.Entry == "" {
|
|
57
|
+
envelope.Forge.Entry = name
|
|
58
|
+
}
|
|
59
|
+
if envelope.Forge.Kind == "" {
|
|
60
|
+
envelope.Forge.Kind = string(kind)
|
|
61
|
+
}
|
|
62
|
+
if envelope.Forge.TraceID == "" {
|
|
63
|
+
envelope.Forge.TraceID = traceID
|
|
64
|
+
}
|
|
65
|
+
if envelope.Auth.Kind == "" {
|
|
66
|
+
envelope.Auth = authFromHeaders(request.Header)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
call := &Context{
|
|
70
|
+
Auth: envelope.Auth,
|
|
71
|
+
Forge: envelope.Forge,
|
|
72
|
+
Headers: request.Header,
|
|
73
|
+
}
|
|
74
|
+
result, err := registered.handler(request.Context(), call, envelope.Args)
|
|
75
|
+
if err != nil {
|
|
76
|
+
writeError(response, http.StatusInternalServerError, envelope.Forge.TraceID, "FORGE_GO_HANDLER_FAILED", err.Error())
|
|
77
|
+
return
|
|
78
|
+
}
|
|
79
|
+
writeJSON(response, http.StatusOK, ResponseEnvelope{
|
|
80
|
+
OK: true,
|
|
81
|
+
Result: result,
|
|
82
|
+
TraceID: envelope.Forge.TraceID,
|
|
83
|
+
})
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
func readRequestEnvelope(request *http.Request) (RequestEnvelope, error) {
|
|
88
|
+
if request.Method == http.MethodGet {
|
|
89
|
+
args := request.URL.Query().Get("args")
|
|
90
|
+
if args == "" {
|
|
91
|
+
args = "{}"
|
|
92
|
+
}
|
|
93
|
+
return RequestEnvelope{Args: json.RawMessage(args)}, nil
|
|
94
|
+
}
|
|
95
|
+
defer request.Body.Close()
|
|
96
|
+
var envelope RequestEnvelope
|
|
97
|
+
decoder := json.NewDecoder(request.Body)
|
|
98
|
+
if err := decoder.Decode(&envelope); err != nil {
|
|
99
|
+
return envelope, err
|
|
100
|
+
}
|
|
101
|
+
if len(envelope.Args) == 0 {
|
|
102
|
+
envelope.Args = json.RawMessage("{}")
|
|
103
|
+
}
|
|
104
|
+
if !json.Valid(envelope.Args) {
|
|
105
|
+
return envelope, errors.New("request args must be valid JSON")
|
|
106
|
+
}
|
|
107
|
+
return envelope, nil
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
func authFromHeaders(headers http.Header) Auth {
|
|
111
|
+
auth := Auth{Kind: headers.Get("x-forge-auth-kind")}
|
|
112
|
+
if auth.Kind == "" {
|
|
113
|
+
auth.Kind = "anonymous"
|
|
114
|
+
}
|
|
115
|
+
auth.UserID = headers.Get("x-forge-user-id")
|
|
116
|
+
auth.TenantID = headers.Get("x-forge-tenant-id")
|
|
117
|
+
auth.Role = headers.Get("x-forge-role")
|
|
118
|
+
return auth
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
func traceIDFrom(request *http.Request, envelope RequestEnvelope) string {
|
|
122
|
+
if envelope.Forge.TraceID != "" {
|
|
123
|
+
return envelope.Forge.TraceID
|
|
124
|
+
}
|
|
125
|
+
return request.Header.Get("x-forge-trace-id")
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
func writeError(response http.ResponseWriter, status int, traceID string, code string, message string) {
|
|
129
|
+
writeJSON(response, status, ResponseEnvelope{
|
|
130
|
+
OK: false,
|
|
131
|
+
Diagnostics: []Diagnostic{{
|
|
132
|
+
Severity: "error",
|
|
133
|
+
Code: code,
|
|
134
|
+
Message: message,
|
|
135
|
+
Docs: []string{"docs/forge-protocol.md"},
|
|
136
|
+
}},
|
|
137
|
+
Error: &ErrorInfo{
|
|
138
|
+
Code: code,
|
|
139
|
+
Message: message,
|
|
140
|
+
},
|
|
141
|
+
TraceID: traceID,
|
|
142
|
+
})
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
func writeJSON(response http.ResponseWriter, status int, body any) {
|
|
146
|
+
response.Header().Set("content-type", "application/json")
|
|
147
|
+
response.WriteHeader(status)
|
|
148
|
+
_ = json.NewEncoder(response).Encode(body)
|
|
149
|
+
}
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
package forge
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"encoding/json"
|
|
5
|
+
"io"
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
type Registry struct {
|
|
9
|
+
service Service
|
|
10
|
+
framework string
|
|
11
|
+
schemas map[string]any
|
|
12
|
+
entries []registeredEntry
|
|
13
|
+
lookup map[string]registeredEntry
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
type registeredEntry struct {
|
|
17
|
+
entry Entry
|
|
18
|
+
handler HandlerFunc
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
type RegistryOption func(*Registry)
|
|
22
|
+
type EntryOption func(*Entry)
|
|
23
|
+
|
|
24
|
+
func New(serviceName string, options ...RegistryOption) *Registry {
|
|
25
|
+
registry := &Registry{
|
|
26
|
+
service: Service{
|
|
27
|
+
Name: serviceName,
|
|
28
|
+
Transport: "http",
|
|
29
|
+
Health: "/health",
|
|
30
|
+
},
|
|
31
|
+
framework: "net/http",
|
|
32
|
+
schemas: map[string]any{},
|
|
33
|
+
lookup: map[string]registeredEntry{},
|
|
34
|
+
}
|
|
35
|
+
for _, option := range options {
|
|
36
|
+
option(registry)
|
|
37
|
+
}
|
|
38
|
+
return registry
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
func Framework(value string) RegistryOption {
|
|
42
|
+
return func(registry *Registry) {
|
|
43
|
+
registry.framework = value
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
func BaseURL(value string) RegistryOption {
|
|
48
|
+
return func(registry *Registry) {
|
|
49
|
+
registry.service.BaseURL = value
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
func Health(path string) RegistryOption {
|
|
54
|
+
return func(registry *Registry) {
|
|
55
|
+
registry.service.Health = path
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
func SchemaRef(name string, schema any) RegistryOption {
|
|
60
|
+
return func(registry *Registry) {
|
|
61
|
+
registry.schemas[name] = schema
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
func (registry *Registry) Command(name string, handler HandlerFunc, options ...EntryOption) {
|
|
66
|
+
entry := Entry{
|
|
67
|
+
Name: name,
|
|
68
|
+
Kind: KindCommand,
|
|
69
|
+
Path: "/commands/" + name,
|
|
70
|
+
Method: "POST",
|
|
71
|
+
Transaction: TransactionExternalManaged,
|
|
72
|
+
Risk: RiskWrite,
|
|
73
|
+
}
|
|
74
|
+
registry.add(entry, handler, options...)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
func (registry *Registry) Query(name string, handler HandlerFunc, options ...EntryOption) {
|
|
78
|
+
entry := Entry{
|
|
79
|
+
Name: name,
|
|
80
|
+
Kind: KindQuery,
|
|
81
|
+
Path: "/queries/" + name,
|
|
82
|
+
Method: "POST",
|
|
83
|
+
Transaction: TransactionReadOnly,
|
|
84
|
+
Risk: RiskRead,
|
|
85
|
+
}
|
|
86
|
+
registry.add(entry, handler, options...)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
func (registry *Registry) add(entry Entry, handler HandlerFunc, options ...EntryOption) {
|
|
90
|
+
for _, option := range options {
|
|
91
|
+
option(&entry)
|
|
92
|
+
}
|
|
93
|
+
registered := registeredEntry{entry: entry, handler: handler}
|
|
94
|
+
registry.entries = append(registry.entries, registered)
|
|
95
|
+
registry.lookup[lookupKey(entry.Kind, entry.Name)] = registered
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
func Description(value string) EntryOption {
|
|
99
|
+
return func(entry *Entry) {
|
|
100
|
+
entry.Description = value
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
func Path(value string) EntryOption {
|
|
105
|
+
return func(entry *Entry) {
|
|
106
|
+
entry.Path = value
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
func Method(value string) EntryOption {
|
|
111
|
+
return func(entry *Entry) {
|
|
112
|
+
entry.Method = value
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
func InputSchema(schema any) EntryOption {
|
|
117
|
+
return func(entry *Entry) {
|
|
118
|
+
entry.InputSchema = schema
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
func OutputSchema(schema any) EntryOption {
|
|
123
|
+
return func(entry *Entry) {
|
|
124
|
+
entry.OutputSchema = schema
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
func Policy(value string) EntryOption {
|
|
129
|
+
return func(entry *Entry) {
|
|
130
|
+
entry.Policy = value
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
func TenantScoped(value bool) EntryOption {
|
|
135
|
+
return func(entry *Entry) {
|
|
136
|
+
entry.TenantScoped = value
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
func TransactionMode(value Transaction) EntryOption {
|
|
141
|
+
return func(entry *Entry) {
|
|
142
|
+
entry.Transaction = value
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
func EntryRisk(value Risk) EntryOption {
|
|
147
|
+
return func(entry *Entry) {
|
|
148
|
+
entry.Risk = value
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
func NeedsApproval(value bool) EntryOption {
|
|
153
|
+
return func(entry *Entry) {
|
|
154
|
+
entry.NeedsApproval = &value
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
func Effects(values ...string) EntryOption {
|
|
159
|
+
return func(entry *Entry) {
|
|
160
|
+
entry.Effects = append([]string{}, values...)
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
func ReadOnly() EntryOption {
|
|
165
|
+
return func(entry *Entry) {
|
|
166
|
+
entry.Transaction = TransactionReadOnly
|
|
167
|
+
entry.Risk = RiskRead
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
func (registry *Registry) Manifest(baseURL string) Manifest {
|
|
172
|
+
service := registry.service
|
|
173
|
+
if baseURL != "" {
|
|
174
|
+
service.BaseURL = baseURL
|
|
175
|
+
}
|
|
176
|
+
entries := make([]Entry, 0, len(registry.entries))
|
|
177
|
+
for _, registered := range registry.entries {
|
|
178
|
+
entries = append(entries, registered.entry)
|
|
179
|
+
}
|
|
180
|
+
manifest := Manifest{
|
|
181
|
+
ForgeProtocol: ProtocolVersion,
|
|
182
|
+
Language: "go",
|
|
183
|
+
Framework: registry.framework,
|
|
184
|
+
Service: service,
|
|
185
|
+
Entries: entries,
|
|
186
|
+
}
|
|
187
|
+
if len(registry.schemas) > 0 {
|
|
188
|
+
manifest.Schemas = registry.schemas
|
|
189
|
+
}
|
|
190
|
+
return manifest
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
func (registry *Registry) MarshalManifest(baseURL string) ([]byte, error) {
|
|
194
|
+
return json.MarshalIndent(registry.Manifest(baseURL), "", " ")
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
func (registry *Registry) WriteManifest(writer io.Writer, baseURL string) error {
|
|
198
|
+
encoded, err := registry.MarshalManifest(baseURL)
|
|
199
|
+
if err != nil {
|
|
200
|
+
return err
|
|
201
|
+
}
|
|
202
|
+
if _, err := writer.Write(encoded); err != nil {
|
|
203
|
+
return err
|
|
204
|
+
}
|
|
205
|
+
_, err = writer.Write([]byte("\n"))
|
|
206
|
+
return err
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
func Object(properties map[string]any, required ...string) Schema {
|
|
210
|
+
schema := Schema{
|
|
211
|
+
"type": "object",
|
|
212
|
+
"properties": properties,
|
|
213
|
+
}
|
|
214
|
+
if len(required) > 0 {
|
|
215
|
+
schema["required"] = required
|
|
216
|
+
}
|
|
217
|
+
return schema
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
func String() Schema {
|
|
221
|
+
return Schema{"type": "string"}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
func Boolean() Schema {
|
|
225
|
+
return Schema{"type": "boolean"}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
func Array(items any) Schema {
|
|
229
|
+
return Schema{"type": "array", "items": items}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
func lookupKey(kind EntryKind, name string) string {
|
|
233
|
+
return string(kind) + ":" + name
|
|
234
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
package forge
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"context"
|
|
5
|
+
"encoding/json"
|
|
6
|
+
"net/http"
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
const ProtocolVersion = "1.0"
|
|
10
|
+
|
|
11
|
+
type EntryKind string
|
|
12
|
+
type Risk string
|
|
13
|
+
type Transaction string
|
|
14
|
+
|
|
15
|
+
const (
|
|
16
|
+
KindCommand EntryKind = "command"
|
|
17
|
+
KindQuery EntryKind = "query"
|
|
18
|
+
|
|
19
|
+
RiskRead Risk = "read"
|
|
20
|
+
RiskWrite Risk = "write"
|
|
21
|
+
RiskDestructive Risk = "destructive"
|
|
22
|
+
RiskExternal Risk = "external"
|
|
23
|
+
|
|
24
|
+
TransactionReadOnly Transaction = "read-only"
|
|
25
|
+
TransactionExternalManaged Transaction = "external-managed"
|
|
26
|
+
TransactionForgeManaged Transaction = "forge-managed"
|
|
27
|
+
TransactionSaga Transaction = "saga"
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
type Schema map[string]any
|
|
31
|
+
|
|
32
|
+
type Manifest struct {
|
|
33
|
+
ForgeProtocol string `json:"forgeProtocol"`
|
|
34
|
+
Language string `json:"language"`
|
|
35
|
+
Framework string `json:"framework,omitempty"`
|
|
36
|
+
Service Service `json:"service"`
|
|
37
|
+
Entries []Entry `json:"entries"`
|
|
38
|
+
Schemas map[string]any `json:"schemas,omitempty"`
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
type Service struct {
|
|
42
|
+
Name string `json:"name"`
|
|
43
|
+
Transport string `json:"transport"`
|
|
44
|
+
BaseURL string `json:"baseUrl,omitempty"`
|
|
45
|
+
Command string `json:"command,omitempty"`
|
|
46
|
+
Health string `json:"health,omitempty"`
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
type Entry struct {
|
|
50
|
+
Name string `json:"name"`
|
|
51
|
+
Kind EntryKind `json:"kind"`
|
|
52
|
+
Description string `json:"description,omitempty"`
|
|
53
|
+
Path string `json:"path,omitempty"`
|
|
54
|
+
Method string `json:"method,omitempty"`
|
|
55
|
+
InputSchema any `json:"inputSchema,omitempty"`
|
|
56
|
+
OutputSchema any `json:"outputSchema,omitempty"`
|
|
57
|
+
Policy string `json:"policy,omitempty"`
|
|
58
|
+
TenantScoped bool `json:"tenantScoped,omitempty"`
|
|
59
|
+
Transaction Transaction `json:"transaction,omitempty"`
|
|
60
|
+
Risk Risk `json:"risk,omitempty"`
|
|
61
|
+
NeedsApproval *bool `json:"needsApproval,omitempty"`
|
|
62
|
+
Effects []string `json:"effects,omitempty"`
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
type Auth struct {
|
|
66
|
+
Kind string `json:"kind"`
|
|
67
|
+
UserID string `json:"userId,omitempty"`
|
|
68
|
+
TenantID string `json:"tenantId,omitempty"`
|
|
69
|
+
Role string `json:"role,omitempty"`
|
|
70
|
+
Roles []string `json:"roles,omitempty"`
|
|
71
|
+
Permissions []string `json:"permissions,omitempty"`
|
|
72
|
+
Email string `json:"email,omitempty"`
|
|
73
|
+
Name string `json:"name,omitempty"`
|
|
74
|
+
Claims map[string]any `json:"claims,omitempty"`
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
type ForgeCall struct {
|
|
78
|
+
Service string `json:"service"`
|
|
79
|
+
Entry string `json:"entry"`
|
|
80
|
+
Kind string `json:"kind"`
|
|
81
|
+
TraceID string `json:"traceId"`
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
type Context struct {
|
|
85
|
+
Auth Auth
|
|
86
|
+
Forge ForgeCall
|
|
87
|
+
Headers http.Header
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
type HandlerFunc func(context.Context, *Context, json.RawMessage) (any, error)
|
|
91
|
+
|
|
92
|
+
type RequestEnvelope struct {
|
|
93
|
+
Args json.RawMessage `json:"args"`
|
|
94
|
+
Auth Auth `json:"auth"`
|
|
95
|
+
Forge ForgeCall `json:"forge"`
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
type ResponseEnvelope struct {
|
|
99
|
+
OK bool `json:"ok"`
|
|
100
|
+
Result any `json:"result,omitempty"`
|
|
101
|
+
Diagnostics []Diagnostic `json:"diagnostics,omitempty"`
|
|
102
|
+
Error *ErrorInfo `json:"error,omitempty"`
|
|
103
|
+
TraceID string `json:"traceId,omitempty"`
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
type Diagnostic struct {
|
|
107
|
+
Severity string `json:"severity"`
|
|
108
|
+
Code string `json:"code"`
|
|
109
|
+
Message string `json:"message"`
|
|
110
|
+
File string `json:"file,omitempty"`
|
|
111
|
+
FixHint string `json:"fixHint,omitempty"`
|
|
112
|
+
Docs []string `json:"docs,omitempty"`
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
type ErrorInfo struct {
|
|
116
|
+
Code string `json:"code"`
|
|
117
|
+
Message string `json:"message"`
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
func Decode(raw json.RawMessage, target any) error {
|
|
121
|
+
if len(raw) == 0 || string(raw) == "null" {
|
|
122
|
+
raw = json.RawMessage("{}")
|
|
123
|
+
}
|
|
124
|
+
return json.Unmarshal(raw, target)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
func Handle[In any, Out any](handler func(context.Context, *Context, In) (Out, error)) HandlerFunc {
|
|
128
|
+
return func(ctx context.Context, call *Context, raw json.RawMessage) (any, error) {
|
|
129
|
+
var input In
|
|
130
|
+
if err := Decode(raw, &input); err != nil {
|
|
131
|
+
var zero Out
|
|
132
|
+
return zero, err
|
|
133
|
+
}
|
|
134
|
+
return handler(ctx, call, input)
|
|
135
|
+
}
|
|
136
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
Release history for the `forgeos` npm package (`alpha` dist-tag).
|
|
4
|
+
|
|
5
|
+
The canonical source file in the repository is `CHANGELOG.md`.
|
|
6
|
+
|
|
7
|
+
## Unreleased
|
|
8
|
+
|
|
9
|
+
Release and packaging hardening:
|
|
10
|
+
|
|
11
|
+
- Added `forge --version` / `forge --version --json`.
|
|
12
|
+
- Updated `create-forgeos-app` help to read the wrapper package version instead of a hardcoded string and bumped the wrapper to `0.1.0-alpha.2`.
|
|
13
|
+
- Added dependency vulnerability evidence with an explicit waiver file and CI release gate.
|
|
14
|
+
- Updated generated web template dependencies to current Vite/plugin-react and Next majors.
|
|
15
|
+
|
|
16
|
+
## 0.1.0-alpha.5
|
|
17
|
+
|
|
18
|
+
Release alignment for the public alpha channel:
|
|
19
|
+
|
|
20
|
+
- Added `forge ai redteam --model-level --json` with deterministic prompt-injection, secret-exfiltration, approval-bypass, cross-tenant, and indirect tool-injection probes.
|
|
21
|
+
- Added `forge security prove --full --json` support for source checkouts, with graceful structural-proof fallback when packaged apps do not include ForgeOS test fixtures.
|
|
22
|
+
- Strengthened npm publish workflows to run `security prove --db postgres --full --json`.
|
|
23
|
+
- Added public registry smoke coverage for `forgeos@alpha` and `create-forgeos-app@alpha`.
|
|
24
|
+
- Bumped the create-app wrapper package line to `create-forgeos-app@0.1.0-alpha.1`.
|
|
25
|
+
|
|
26
|
+
## 0.1.0-alpha.4
|
|
27
|
+
|
|
28
|
+
Security assurance and release evidence hardening:
|
|
29
|
+
|
|
30
|
+
- Added value-aware telemetry redaction for known secret values in safe-looking fields, messages, details, outputs, and stack traces.
|
|
31
|
+
- Added webhook signature, timestamp, and replay protection helpers with Stripe/GitHub/generic HMAC coverage.
|
|
32
|
+
- Added HTTP tenant-isolation tests that exercise the dev server/API boundary, not only the internal runtime executor.
|
|
33
|
+
- Added `forge rls mutate-test --json` to kill dangerous generated RLS mutations such as missing FORCE RLS, missing policies, unconditional predicates, and `BYPASSRLS`.
|
|
34
|
+
- Extended `forge security prove --json` with RLS mutation proof and invariant-level evidence metadata.
|
|
35
|
+
- Added scripts to split security evidence by invariant and emit basic release supply-chain evidence plus CycloneDX SBOM.
|
|
36
|
+
- Strengthened publish/security workflows so release gates use Postgres-backed security proof, RLS mutation proof, release evidence, and SBOM generation.
|
|
37
|
+
|
|
38
|
+
## 0.1.0-alpha.3
|
|
39
|
+
|
|
40
|
+
Native Forge AI agents on top of Vercel AI SDK v6:
|
|
41
|
+
|
|
42
|
+
- Added `aiTool` and `agent` primitives with generated `agentTools.json` / `agentTools.md`.
|
|
43
|
+
- Added `ctx.agent.run` and `ctx.ai.runAgent` using AI SDK `ToolLoopAgent`.
|
|
44
|
+
- Added auto-tools for commands, queries, and liveQueries with read-only vs approval-required writes.
|
|
45
|
+
- Added dev agent endpoints: `POST /ai/agents/run` and `POST /ai/agents/chat`.
|
|
46
|
+
- Extended `forge ai` CLI with `tools`, `agents`, and `trace` subcommands.
|
|
47
|
+
- Added `forge inspect agent-tools` and agent tool metadata in `agentContract.json`.
|
|
48
|
+
- Upgraded runtime dependency to AI SDK v6 for tool calling, streaming UI, and MCP compatibility.
|
|
49
|
+
|
|
50
|
+
Documentation:
|
|
51
|
+
|
|
52
|
+
- Added public [AI](ai.md) page and AST-aware `rename command` codemod docs.
|
|
53
|
+
- Full RTD expansion: [Agent Workflow](agent-workflow.md), [Frontend](frontend.md), [Security & Data](security-and-data.md), [Authoring](authoring.md), [Testing & Repair](testing-and-repair.md), [Self-Host](self-host.md), [Templates](templates.md), Material theme, search, and Mermaid diagrams.
|
|
54
|
+
|
|
55
|
+
## 0.1.0-alpha.2
|
|
56
|
+
|
|
57
|
+
Windows and generated-app hardening:
|
|
58
|
+
|
|
59
|
+
- Fixed Node ESM handler loading on Windows by importing generated app modules through `file://` URLs across commands, queries, liveQueries, outbox actions, workflow steps, mocks, and telemetry adapters.
|
|
60
|
+
- Fixed `forge dev` SSE streaming on the Node HTTP fallback so liveQuery snapshots are flushed immediately instead of buffering forever.
|
|
61
|
+
- Hardened generated app scaffolding and web dev spawning on Windows.
|
|
62
|
+
- Updated the B2B support template to route frontend imports through `web/lib/forge.ts` and use safer handler input validation.
|
|
63
|
+
- Added focused tests for Node compatibility, template scaffolding, runtime imports, and streaming responses.
|
|
64
|
+
- Added `create-forgeos-app@alpha` for `npm create forgeos-app@alpha`.
|
|
65
|
+
- Added GitHub Packages mirror workflow for scoped package publishing.
|
|
66
|
+
|
|
67
|
+
## 0.1.0-alpha.1
|
|
68
|
+
|
|
69
|
+
Republish alpha with the dependency/API oracle improvements:
|
|
70
|
+
|
|
71
|
+
- Added dependency API inspection commands for agents: `forge deps api`, `forge deps trace`, and `forge deps runtime-compat`.
|
|
72
|
+
- Added dependency API summaries to `agentContract.json`.
|
|
73
|
+
- Added package resolution traces, runtime compatibility metadata, and runtime/type mismatch diagnostics to `packageGraph`.
|
|
74
|
+
- Reduced package graph warning noise for `package.json` metadata exports, declaration-file subpaths, and pattern exports.
|
|
75
|
+
|
|
76
|
+
## 0.1.0-alpha.0
|
|
77
|
+
|
|
78
|
+
Initial alpha packaging baseline for ForgeOS.
|
|
79
|
+
|
|
80
|
+
This release line validates npm installation, the `forge` CLI binary, template creation, generated contracts, and the agent-native local development loop.
|
|
81
|
+
|
|
82
|
+
Added Read the Docs-ready public documentation, generator/package version alignment checks, and a broad generated-app field-test harness for release hardening.
|