okengine 0.13.0 → 0.15.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.
- package/manifest.v1.schema.json +7 -1
- package/package.json +4 -5
- package/site/content/docs/ai/mcp.mdx +27 -2
- package/site/content/docs/elements/ai.mdx +59 -11
- package/site/content/docs/elements/channel.mdx +1 -0
- package/site/content/docs/elements/clock.mdx +30 -12
- package/site/content/docs/elements/flow.mdx +9 -3
- package/site/content/docs/elements/gate.mdx +25 -22
- package/site/content/docs/elements/signal.mdx +71 -25
- package/site/content/docs/elements/store.mdx +87 -28
- package/site/content/docs/elements/vault.mdx +1 -0
- package/site/content/docs/get-started/basic-usage.mdx +22 -13
- package/site/content/docs/get-started/index.mdx +5 -0
- package/site/content/docs/get-started/installation.mdx +2 -2
- package/site/content/docs/get-started/introduction.mdx +11 -3
- package/site/content/docs/get-started/meta.json +1 -1
- package/site/content/docs/get-started/project-structure.mdx +932 -0
- package/site/content/docs/reference/cli.md +13 -10
- package/site/content/docs/reference/client.mdx +25 -21
- package/site/content/docs/reference/fx.mdx +27 -22
- package/site/content/docs/reference/security.md +1 -1
- package/src/auth/bindings.ts +14 -5
- package/src/auth/cross-plane.ts +10 -3
- package/src/cli/ai-setup/ai-setup.test.ts +62 -0
- package/src/cli/ai-setup/apply.ts +32 -1
- package/src/cli/ai-setup/recommend.test.ts +25 -0
- package/src/cli/ai-setup/recommend.ts +8 -3
- package/src/cli/attach-host-console.test.ts +3 -2
- package/src/cli/attach-host-console.ts +3 -0
- package/src/cli/build.test.ts +4 -2
- package/src/cli/db-seed.ts +48 -15
- package/src/cli/db.test.ts +104 -0
- package/src/cli/db.ts +122 -10
- package/src/cli/dev-controls.test.ts +20 -0
- package/src/cli/dev-controls.ts +13 -0
- package/src/cli/dev.test.ts +15 -4
- package/src/cli/dev.ts +102 -29
- package/src/cli/ensure-drizzle-config.ts +2 -1
- package/src/cli/tui/DevLive.tsx +12 -2
- package/src/cli/tui/keys.test.ts +2 -1
- package/src/cli/tui/keys.ts +3 -2
- package/src/compiler/aot.test.ts +1 -1
- package/src/compiler/effects-infer.ts +58 -3
- package/src/compiler/extract.test.ts +458 -29
- package/src/compiler/extract.ts +387 -69
- package/src/compiler/flow-path.test.ts +96 -0
- package/src/compiler/flow-path.ts +173 -0
- package/src/compiler/generate-adopt.test.ts +112 -3
- package/src/compiler/generate-adopt.ts +280 -26
- package/src/compiler/response.ts +45 -1
- package/src/compiler/schema-from-ast.ts +609 -0
- package/src/console/server/ai.ts +5 -2
- package/src/console/server/bind.ts +2 -2
- package/src/console/server/console.test.ts +3 -0
- package/src/console/server/flows.ts +121 -40
- package/src/console/server/invoke-user-flow.test.ts +3 -1
- package/src/console/server/invoke-user-flow.ts +17 -2
- package/src/console/server/iso-at.test.ts +9 -0
- package/src/console/server/iso-at.ts +11 -0
- package/src/console/server/security-headers.ts +6 -3
- package/src/console/server/serve.ts +17 -2
- package/src/console/server/spa-proxy.test.ts +1 -0
- package/src/console/server/sql-catalog.ts +147 -7
- package/src/console/server/sql-rls.test.ts +16 -0
- package/src/console/server/state.ts +8 -0
- package/src/console/server/store.test.ts +7 -4
- package/src/console/server/store.ts +142 -58
- package/src/console/ui-next/dist/assets/agent-disclosure-C0X1fbWF.js +1 -0
- package/src/console/ui-next/dist/assets/cache-glyph-F1FI122b.js +1 -0
- package/src/console/ui-next/dist/assets/{call-pii-button-bqkxMrJH.js → call-pii-button-DEDCl_j3.js} +1 -1
- package/src/console/ui-next/dist/assets/collapsible-LPqGvfoz.js +1 -0
- package/src/console/ui-next/dist/assets/{confirm-sheet-DDCRmG62.js → confirm-sheet-3ptDzXbz.js} +1 -1
- package/src/console/ui-next/dist/assets/{duration-tone-oiRxPVsZ.js → duration-tone-sC3lGABz.js} +1 -1
- package/src/console/ui-next/dist/assets/{explorer-empty-HjTnVQoR.js → explorer-empty-BvYrygyO.js} +1 -1
- package/src/console/ui-next/dist/assets/flows-page-Dluo1Bd7.js +1 -0
- package/src/console/ui-next/dist/assets/{highlighted-json-CvDPvveV.js → highlighted-json-CS_O8L-r.js} +1 -1
- package/src/console/ui-next/dist/assets/http-method--sWDdXSB.js +1 -0
- package/src/console/ui-next/dist/assets/index-Ca3HZMVq.js +66 -0
- package/src/console/ui-next/dist/assets/index-UtTDRQpS.css +2 -0
- package/src/console/ui-next/dist/assets/{link-DF7SZ9Ek.js → link-COeyggt-.js} +1 -1
- package/src/console/ui-next/dist/assets/observability-page-HK9-BO8z.js +4 -0
- package/src/console/ui-next/dist/assets/react-D8E3mtu1.js +1 -0
- package/src/console/ui-next/dist/assets/replica-lag-DBIFFf7d.js +18 -0
- package/src/console/ui-next/dist/assets/sheet-form-Dnwa5oOR.js +1 -0
- package/src/console/ui-next/dist/assets/shortcut-keys-CoqwEIi0.js +1 -0
- package/src/console/ui-next/dist/assets/skeleton-BHcfDYcb.js +1 -0
- package/src/console/ui-next/dist/assets/store-page-BSohH3wM.js +41 -0
- package/src/console/ui-next/dist/assets/trace-detail-sheet-CFIGRnnA.js +2 -0
- package/src/console/ui-next/dist/assets/tree-expand-toggle-BgLl34w7.js +54 -0
- package/src/console/ui-next/dist/assets/units-page-B0cFE76A.js +1 -0
- package/src/console/ui-next/dist/assets/{use-vault-list-Cl79j_ku.js → use-vault-list-BLbZhzyF.js} +1 -1
- package/src/console/ui-next/dist/assets/vault-page-B1SbYe10.js +2 -0
- package/src/console/ui-next/dist/index.html +6 -6
- package/src/console/ui-next/seed-invoke-host.ts +2 -0
- package/src/console/ui-next/src/client.ts +35 -7
- package/src/console/ui-next/src/components/motion/table/index.tsx +16 -0
- package/src/console/ui-next/src/components/motion/table/types.ts +4 -0
- package/src/console/ui-next/src/components/ui/kbd.tsx +2 -2
- package/src/console/ui-next/src/features/flows/graph/build-flow-graph.test.ts +18 -0
- package/src/console/ui-next/src/features/flows/graph/build-flow-graph.ts +14 -1
- package/src/console/ui-next/src/features/flows/graph/neighborhood.test.ts +17 -0
- package/src/console/ui-next/src/features/flows/graph/neighborhood.ts +16 -3
- package/src/console/ui-next/src/features/flows/traces/effect-kind.ts +3 -1
- package/src/console/ui-next/src/features/flows/traces/effect-summary.ts +24 -0
- package/src/console/ui-next/src/features/flows/traces/http-method.ts +19 -0
- package/src/console/ui-next/src/features/flows/traces/trace-detail-sheet.tsx +9 -3
- package/src/console/ui-next/src/features/flows/traces/trace-detail.test.ts +29 -2
- package/src/console/ui-next/src/features/flows/traces/traces-pane.tsx +10 -3
- package/src/console/ui-next/src/features/observability/lib/ask-count.test.ts +25 -0
- package/src/console/ui-next/src/features/observability/lib/ask-count.ts +4 -1
- package/src/console/ui-next/src/features/store/detail/browse-section.tsx +45 -1
- package/src/console/ui-next/src/features/store/detail/resource-panel.tsx +78 -16
- package/src/console/ui-next/src/features/store/detail/store-row-detail-sheet.tsx +155 -14
- package/src/console/ui-next/src/features/store/explorer/store-tree.tsx +33 -133
- package/src/console/ui-next/src/features/store/files/file-preview.tsx +4 -1
- package/src/console/ui-next/src/features/store/grid/rls-policy-sheet.tsx +326 -165
- package/src/console/ui-next/src/features/store/grid/sql-insert-sheet.tsx +6 -0
- package/src/console/ui-next/src/features/store/grid/store-data-grid.tsx +50 -3
- package/src/console/ui-next/src/features/store/lib/files-meta.test.ts +3 -0
- package/src/console/ui-next/src/features/store/lib/files-meta.ts +12 -0
- package/src/console/ui-next/src/features/store/lib/query-defaults.test.ts +25 -0
- package/src/console/ui-next/src/features/store/lib/query-defaults.ts +85 -3
- package/src/console/ui-next/src/features/store/lib/query-gate.ts +30 -4
- package/src/console/ui-next/src/features/store/lib/rls-policy.test.ts +139 -0
- package/src/console/ui-next/src/features/store/lib/rls-policy.ts +223 -21
- package/src/console/ui-next/src/features/store/lib/schema-graph.ts +4 -0
- package/src/console/ui-next/src/features/store/lib/sql-catalog.test.ts +24 -0
- package/src/console/ui-next/src/features/store/lib/sql-catalog.ts +19 -0
- package/src/console/ui-next/src/features/store/lib/store-tree.test.ts +6 -0
- package/src/console/ui-next/src/features/store/lib/store-tree.ts +13 -0
- package/src/console/ui-next/src/features/store/query/query-console.tsx +48 -14
- package/src/console/ui-next/src/features/store/query/query-gate-menu.tsx +19 -20
- package/src/console/ui-next/src/features/store/query/query-gate-parts.tsx +2 -1
- package/src/console/ui-next/src/features/store/query/query-results.tsx +110 -83
- package/src/console/ui-next/src/features/store/schema/schema-table-node.tsx +17 -0
- package/src/console/ui-next/src/features/units/call/call-api-panel.tsx +112 -72
- package/src/console/ui-next/src/features/units/detail/effects-summary.tsx +12 -4
- package/src/console/ui-next/src/features/units/lib/contract-input.test.ts +206 -1
- package/src/console/ui-next/src/features/units/lib/contract-input.ts +55 -0
- package/src/console/ui-next/src/features/vault/lib/types.ts +1 -1
- package/src/docker/compose-health.test.ts +27 -0
- package/src/docker/compose-health.ts +19 -3
- package/src/docker/docker.test.ts +4 -1
- package/src/docker/dockerfile.ts +1 -1
- package/src/docker/recipes/pgdog.ts +2 -0
- package/src/drivers/ai-anthropic.ts +5 -0
- package/src/drivers/ai-ollama.ts +49 -30
- package/src/drivers/ai-openai-compatible.ts +57 -46
- package/src/drivers/ai-providers.test.ts +3 -0
- package/src/drivers/bun-native-completeness.test.ts +7 -9
- package/src/drivers/clock-postgres.ts +13 -9
- package/src/drivers/instances-postgres.ts +4 -6
- package/src/drivers/journal-postgres.ts +13 -9
- package/src/drivers/pg-rls.test.ts +87 -0
- package/src/drivers/pg-rls.ts +233 -7
- package/src/drivers/pglite.ts +26 -3
- package/src/drivers/postgres.test.ts +23 -0
- package/src/drivers/postgres.ts +133 -9
- package/src/drivers/redis.ts +11 -4
- package/src/drivers/signal-redis.ts +24 -14
- package/src/drivers/signal-types.ts +2 -1
- package/src/drivers/types.ts +10 -0
- package/src/elements/ai/declare.ts +109 -0
- package/src/elements/ai/errors.test.ts +5 -1
- package/src/elements/ai/errors.ts +30 -2
- package/src/elements/ai/eval.ts +4 -6
- package/src/elements/ai/mcp-client.test.ts +206 -0
- package/src/elements/ai/mcp-client.ts +362 -0
- package/src/elements/ai/mcp-http.ts +159 -0
- package/src/elements/ai/mcp-mock.ts +134 -0
- package/src/elements/ai/mcp-protocol.ts +234 -0
- package/src/elements/ai/mcp-stdio.test.ts +50 -0
- package/src/elements/ai/mcp-stdio.ts +212 -0
- package/src/elements/ai/mcp-transport.ts +70 -0
- package/src/elements/ai/runtime.ts +159 -29
- package/src/elements/ai.test.ts +139 -0
- package/src/elements/ai.ts +16 -0
- package/src/elements/clock/declare.ts +26 -1
- package/src/elements/clock/health.test.ts +43 -0
- package/src/elements/clock/runtime.ts +55 -2
- package/src/elements/clock/schedule.ts +71 -142
- package/src/elements/clock.test.ts +9 -40
- package/src/elements/clock.ts +6 -1
- package/src/elements/gate/boot.ts +5 -5
- package/src/elements/gate/declare.ts +36 -4
- package/src/elements/gate/flatten.ts +1 -1
- package/src/elements/gate/runtime.ts +1 -1
- package/src/elements/index.ts +2 -0
- package/src/elements/signal/declare.ts +2 -1
- package/src/elements/signal/runtime.ts +16 -1
- package/src/elements/signal.ts +1 -0
- package/src/elements/store/cache.test.ts +2 -0
- package/src/elements/store/cache.ts +3 -3
- package/src/elements/store/declare.ts +9 -6
- package/src/elements/store/emit-drizzle.ts +44 -8
- package/src/elements/store/resource.test.ts +1 -1
- package/src/elements/store/rls-identity.test.ts +95 -0
- package/src/elements/store/rls-identity.ts +116 -0
- package/src/elements/store/runtime.ts +4 -0
- package/src/elements/store/schema-decl.test.ts +37 -0
- package/src/elements/store/schema-decl.ts +161 -0
- package/src/elements/store/seed.ts +1 -1
- package/src/elements/store/sql-condition.test.ts +12 -0
- package/src/elements/store/sql-condition.ts +26 -2
- package/src/elements/store/sql-rls-isolation.test.ts +165 -0
- package/src/elements/store/sql-rls-stamp.test.ts +117 -0
- package/src/elements/store/sql-session.ts +81 -3
- package/src/elements/store/upsert-app.test.ts +1 -1
- package/src/elements/store.ts +14 -0
- package/src/elements/vault/builtin-adapter.ts +17 -0
- package/src/full.ts +2 -0
- package/src/http.ts +20 -3
- package/src/index.ts +14 -1
- package/src/kernel/adopt-barrel-fresh.test.ts +1 -1
- package/src/kernel/adopt-routes.ts +30 -2
- package/src/kernel/app.ts +227 -77
- package/src/kernel/auto-cache.test.ts +8 -8
- package/src/kernel/auto-registry.test.ts +54 -9
- package/src/kernel/boot-bind/ai.ts +24 -0
- package/src/kernel/boot-bind/clock.ts +2 -0
- package/src/kernel/boot.test.ts +4 -4
- package/src/kernel/boot.ts +5 -3
- package/src/kernel/effects-stamping.test.ts +3 -3
- package/src/kernel/element-registries.ts +15 -5
- package/src/kernel/errors.ts +24 -0
- package/src/kernel/flow-units.ts +64 -0
- package/src/kernel/flow.ts +29 -17
- package/src/kernel/fx-dead-letters.test.ts +77 -0
- package/src/kernel/fx.test.ts +22 -0
- package/src/kernel/fx.ts +135 -6
- package/src/kernel/horizontal-child.ts +4 -4
- package/src/kernel/http-path-pending.ts +20 -0
- package/src/kernel/http-resource.ts +4 -0
- package/src/kernel/http-stream.test.ts +174 -0
- package/src/kernel/index.ts +2 -0
- package/src/kernel/pipeline.test.ts +2 -2
- package/src/kernel/plugin-elements.test.ts +1 -1
- package/src/kernel/plugin-needs.test.ts +1 -1
- package/src/kernel/ready.test.ts +2 -2
- package/src/kernel/resource-mount.test.ts +14 -0
- package/src/kernel/run-duration.test.ts +2 -2
- package/src/kernel/stamp-http.test.ts +79 -0
- package/src/kernel/stamp-http.ts +75 -0
- package/src/kernel/triggers.ts +52 -27
- package/src/manifest/mcp-ref.ts +88 -0
- package/src/manifest/types.ts +41 -2
- package/src/manifest/validate.test.ts +20 -0
- package/src/mcp/docs-server.ts +1 -1
- package/src/mcp/server.ts +1 -1
- package/src/plugins/compression.test.ts +21 -0
- package/src/plugins/compression.ts +1 -0
- package/src/release/measure.ts +2 -2
- package/src/runtime/bun.ts +41 -4
- package/src/runtime/json-code-block.test.ts +2 -2
- package/src/runtime/serve.test.ts +4 -4
- package/src/term.test.ts +52 -4
- package/src/term.ts +125 -17
- package/src/test/reset-element-registries.ts +10 -3
- package/src/cli/ask-seed.test.ts +0 -96
- package/src/cli/ask-seed.ts +0 -82
- package/src/console/ui-next/dist/assets/cache-glyph-CLPBqZeb.js +0 -1
- package/src/console/ui-next/dist/assets/collapsible-DYb0xU8C.js +0 -1
- package/src/console/ui-next/dist/assets/flows-page-Dg8CTE29.js +0 -1
- package/src/console/ui-next/dist/assets/http-method-BJ92Z_ke.js +0 -1
- package/src/console/ui-next/dist/assets/index-Bp-R7jtM.js +0 -66
- package/src/console/ui-next/dist/assets/index-D4Ldtj79.css +0 -2
- package/src/console/ui-next/dist/assets/observability-page-DAnpEaq1.js +0 -4
- package/src/console/ui-next/dist/assets/query-gate-parts-1m8m1iNp.js +0 -2
- package/src/console/ui-next/dist/assets/react-B1ML8gxg.js +0 -1
- package/src/console/ui-next/dist/assets/replica-lag-C8_BRt2x.js +0 -18
- package/src/console/ui-next/dist/assets/sheet-form-D-ata7jy.js +0 -1
- package/src/console/ui-next/dist/assets/shortcut-keys-DO4IsVqv.js +0 -1
- package/src/console/ui-next/dist/assets/skeleton-CL_X0GCj.js +0 -1
- package/src/console/ui-next/dist/assets/store-page-v3LXdYpr.js +0 -45
- package/src/console/ui-next/dist/assets/trace-detail-sheet-D16lWQMt.js +0 -2
- package/src/console/ui-next/dist/assets/units-page-BtQ0bqMe.js +0 -1
- package/src/console/ui-next/dist/assets/vault-page-Ca-MvcmJ.js +0 -2
package/src/cli/dev.ts
CHANGED
|
@@ -31,8 +31,8 @@ import {
|
|
|
31
31
|
createAnchoredBoard,
|
|
32
32
|
createBootProgress,
|
|
33
33
|
devStatusFromAiPhase,
|
|
34
|
-
formatAppReadyLine,
|
|
35
34
|
formatBootWarn,
|
|
35
|
+
formatBoundSurfaces,
|
|
36
36
|
formatClaimNote,
|
|
37
37
|
formatCliChrome,
|
|
38
38
|
formatDevBanner,
|
|
@@ -83,7 +83,7 @@ export interface DevSurfaceHandle {
|
|
|
83
83
|
|
|
84
84
|
/** App surface returned by {@link DevOptions.startApp}. */
|
|
85
85
|
export interface DevAppHandle {
|
|
86
|
-
readonly stop: () => void
|
|
86
|
+
readonly stop: () => void | Promise<void>;
|
|
87
87
|
/** Bound listen port (set when serve chooses an ephemeral port). */
|
|
88
88
|
readonly port?: number;
|
|
89
89
|
/** Base URL of the app server. */
|
|
@@ -181,12 +181,9 @@ export interface DevOptions {
|
|
|
181
181
|
/**
|
|
182
182
|
* Injectable `.adopt()` barrel regeneration (tests). Default: real
|
|
183
183
|
* `generateAdoptBarrel` + atomic write to `<cwd>/src/flows/generated.ts`
|
|
184
|
-
* (`generated.ts.tmp` → rename). Runs
|
|
185
|
-
*
|
|
186
|
-
*
|
|
187
|
-
* identically (unlike a virtual-module Bun plugin, which does not — see
|
|
188
|
-
* `compiler/generate-adopt.ts`). Atomic so a concurrent import during
|
|
189
|
-
* `bun --hot` never sees a torn mid-write file.
|
|
184
|
+
* (`generated.ts.tmp` → rename). Runs at session start and again on
|
|
185
|
+
* `src/flows/**` changes except `generated.ts` itself. Write-if-changed
|
|
186
|
+
* so the `src/` watcher + bun `--hot` do not loop.
|
|
190
187
|
*
|
|
191
188
|
* @param cwd - Project root
|
|
192
189
|
*/
|
|
@@ -481,6 +478,7 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
481
478
|
files: readonly string[];
|
|
482
479
|
cwd: string;
|
|
483
480
|
env: Record<string, string>;
|
|
481
|
+
aiServiceName?: string;
|
|
484
482
|
} | null = null;
|
|
485
483
|
let stackSqlDriver = "postgres";
|
|
486
484
|
let stackKvDriver = "redis";
|
|
@@ -658,6 +656,7 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
658
656
|
files: composeFiles,
|
|
659
657
|
cwd: dockerOut,
|
|
660
658
|
env: { ...stackEnv! },
|
|
659
|
+
aiServiceName: derived.specs.find((s) => s.role === "ai")?.serviceName,
|
|
661
660
|
};
|
|
662
661
|
|
|
663
662
|
// Stream compose health until infra is up (AI may stay pending — model load).
|
|
@@ -942,7 +941,9 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
942
941
|
return { code: 0, plan };
|
|
943
942
|
}
|
|
944
943
|
|
|
944
|
+
let boardPaused = false;
|
|
945
945
|
const repaintBoard = (aiStatus?: DevStatus): void => {
|
|
946
|
+
if (boardPaused) return;
|
|
946
947
|
bootBoard.paint(paintBootBoard(aiStatus ?? heroAiStatus));
|
|
947
948
|
};
|
|
948
949
|
|
|
@@ -1026,15 +1027,6 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
1026
1027
|
`oke db push (dev · ${result.dialect}) ${result.code === 0 ? "ok" : "failed"}`,
|
|
1027
1028
|
),
|
|
1028
1029
|
);
|
|
1029
|
-
if (result.code === 0) {
|
|
1030
|
-
const { maybeAskSeed } = await import("./ask-seed.ts");
|
|
1031
|
-
await maybeAskSeed({
|
|
1032
|
-
cwd,
|
|
1033
|
-
env: configEnv,
|
|
1034
|
-
write,
|
|
1035
|
-
stdinIsTTY: options.stdinIsTTY ?? process.stdin.isTTY,
|
|
1036
|
-
});
|
|
1037
|
-
}
|
|
1038
1030
|
} catch (err) {
|
|
1039
1031
|
write(await formatDevSchemaSyncFailure(cwd, err, "boot"));
|
|
1040
1032
|
}
|
|
@@ -1323,14 +1315,14 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
1323
1315
|
write(formatBootWarn(notice));
|
|
1324
1316
|
}
|
|
1325
1317
|
bootNotices.length = 0;
|
|
1326
|
-
write(
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1318
|
+
write(
|
|
1319
|
+
formatBoundSurfaces({
|
|
1320
|
+
appUrl: `http://127.0.0.1:${boundAppPort}`,
|
|
1321
|
+
consoleUrl: `http://127.0.0.1:${boundConsolePort}`,
|
|
1322
|
+
mcpUrl: mcpServer ? `http://127.0.0.1:${boundMcpPort}` : null,
|
|
1323
|
+
docsMcpUrl: docsMcpServer ? `http://127.0.0.1:${boundDocsMcpPort}` : null,
|
|
1324
|
+
}),
|
|
1325
|
+
);
|
|
1334
1326
|
write(formatDevLogSeparator());
|
|
1335
1327
|
chromeReady = true;
|
|
1336
1328
|
};
|
|
@@ -1358,6 +1350,10 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
1358
1350
|
const watchFs: DevWatchFn =
|
|
1359
1351
|
options.watchFs ?? ((path, watchOptions, listener) => watch(path, watchOptions, listener));
|
|
1360
1352
|
const watcher = watchFs(resolve(cwd, "src"), { recursive: true }, (_event, filename) => {
|
|
1353
|
+
const rel = (filename?.toString() ?? "").replace(/\\/g, "/");
|
|
1354
|
+
if (isFlowsTreeWatchPath(rel)) {
|
|
1355
|
+
void syncAdoptBarrel(cwd);
|
|
1356
|
+
}
|
|
1361
1357
|
void regen(appUrl);
|
|
1362
1358
|
// Only live-extract when the host did not pin a Manifest (tests).
|
|
1363
1359
|
if (options.manifest === undefined) {
|
|
@@ -1388,7 +1384,7 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
1388
1384
|
const host = attachedHost;
|
|
1389
1385
|
attachedHost = null;
|
|
1390
1386
|
void host?.stop();
|
|
1391
|
-
app.stop();
|
|
1387
|
+
void Promise.resolve(app.stop());
|
|
1392
1388
|
consoleServer.stop();
|
|
1393
1389
|
mcpServer?.stop();
|
|
1394
1390
|
docsMcpServer?.stop();
|
|
@@ -1489,6 +1485,25 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
1489
1485
|
await syncComposeBoard();
|
|
1490
1486
|
paintReadyChrome();
|
|
1491
1487
|
};
|
|
1488
|
+
const waitComposeReady = async (): Promise<void> => {
|
|
1489
|
+
const { watchComposeHealth } = await import("../docker/compose-health.ts");
|
|
1490
|
+
const aiServiceName = started.aiServiceName;
|
|
1491
|
+
liveComposeHealth = await watchComposeHealth({
|
|
1492
|
+
files: started.files,
|
|
1493
|
+
cwd: started.cwd,
|
|
1494
|
+
env: started.env,
|
|
1495
|
+
run: composeHealthRun,
|
|
1496
|
+
timeoutMs: 20_000,
|
|
1497
|
+
isDone: (map) => {
|
|
1498
|
+
if (map.size === 0) return true;
|
|
1499
|
+
return [...map.entries()].every(
|
|
1500
|
+
([name, s]) => name === aiServiceName || s === "ready" || s === "error",
|
|
1501
|
+
);
|
|
1502
|
+
},
|
|
1503
|
+
});
|
|
1504
|
+
if (liveComposeHealth.get("ai") === "error") heroAiStatus = "error";
|
|
1505
|
+
};
|
|
1506
|
+
|
|
1492
1507
|
const composeAction = async (action: DevComposeControlAction): Promise<void> => {
|
|
1493
1508
|
const files = started.files;
|
|
1494
1509
|
const finalArgs =
|
|
@@ -1510,6 +1525,7 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
1510
1525
|
const detail = [stdout.trim(), stderr.trim()].filter(Boolean).join("\n");
|
|
1511
1526
|
throw new Error(`docker compose ${action} exited ${code}` + (detail ? `\n${detail}` : ""));
|
|
1512
1527
|
}
|
|
1528
|
+
if (action === "up") await waitComposeReady();
|
|
1513
1529
|
await syncComposeBoard();
|
|
1514
1530
|
};
|
|
1515
1531
|
|
|
@@ -1517,6 +1533,25 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
1517
1533
|
const { launchDevLiveControls } = await import("./tui/DevLive.tsx");
|
|
1518
1534
|
await launchDevLiveControls({
|
|
1519
1535
|
onRefresh: () => refreshChrome(),
|
|
1536
|
+
onSeed: async () => {
|
|
1537
|
+
const { runSlashCli } = await import("./tui/slash-run.ts");
|
|
1538
|
+
boardPaused = true;
|
|
1539
|
+
const lines: string[] = [];
|
|
1540
|
+
try {
|
|
1541
|
+
const code = await runSlashCli(cwd, ["db", "seed", "--force"], (line) => {
|
|
1542
|
+
lines.push(line);
|
|
1543
|
+
write(line);
|
|
1544
|
+
});
|
|
1545
|
+
if (code === 0) return;
|
|
1546
|
+
const last = [...lines]
|
|
1547
|
+
.reverse()
|
|
1548
|
+
.map((line) => line.trim())
|
|
1549
|
+
.find((line) => line.length > 0 && !line.startsWith("✗") && !line.startsWith("$"));
|
|
1550
|
+
throw new Error(last || "oke db seed failed");
|
|
1551
|
+
} finally {
|
|
1552
|
+
boardPaused = false;
|
|
1553
|
+
}
|
|
1554
|
+
},
|
|
1520
1555
|
onComposeUp: () => composeAction("up"),
|
|
1521
1556
|
onComposeStop: () => composeAction("stop"),
|
|
1522
1557
|
onQuit: () => {
|
|
@@ -1589,6 +1624,20 @@ function isSchemaDeclDefinitionError(err: unknown, declarePath: string): boolean
|
|
|
1589
1624
|
return declarePath.length > 0 && blob.includes(declarePath);
|
|
1590
1625
|
}
|
|
1591
1626
|
|
|
1627
|
+
/**
|
|
1628
|
+
* True when a `src/` watcher event is a flows tree change that should
|
|
1629
|
+
* regenerate `generated.ts` (never the generated file itself).
|
|
1630
|
+
*
|
|
1631
|
+
* @param rel - Watcher filename (POSIX or Windows)
|
|
1632
|
+
*/
|
|
1633
|
+
export function isFlowsTreeWatchPath(rel: string): boolean {
|
|
1634
|
+
const posix = rel.replace(/\\/g, "/");
|
|
1635
|
+
if (!posix.includes("flows/")) return false;
|
|
1636
|
+
const base = posix.split("/").pop() ?? posix;
|
|
1637
|
+
if (base === "generated.ts" || base === "generated.ts.tmp") return false;
|
|
1638
|
+
return true;
|
|
1639
|
+
}
|
|
1640
|
+
|
|
1592
1641
|
/**
|
|
1593
1642
|
* Frame a schema-sync failure for the `oke dev` loop: warn loud for developer
|
|
1594
1643
|
* bugs, soft-skip only known environmental gaps. Never crashes the session.
|
|
@@ -1652,6 +1701,29 @@ async function tryLoadProjectManifest(cwd: string): Promise<Manifest | null | un
|
|
|
1652
1701
|
return extracted;
|
|
1653
1702
|
}
|
|
1654
1703
|
|
|
1704
|
+
/**
|
|
1705
|
+
* SIGKILL a pid and every child (`bun --hot` leaves a worker).
|
|
1706
|
+
*
|
|
1707
|
+
* @param pid - Root pid
|
|
1708
|
+
*/
|
|
1709
|
+
function killProcessTree(pid: number): void {
|
|
1710
|
+
const listed = Bun.spawnSync(["pgrep", "-P", String(pid)], {
|
|
1711
|
+
stdout: "pipe",
|
|
1712
|
+
stderr: "pipe",
|
|
1713
|
+
});
|
|
1714
|
+
if (listed.exitCode === 0) {
|
|
1715
|
+
for (const line of listed.stdout.toString().split("\n")) {
|
|
1716
|
+
const child = Number(line.trim());
|
|
1717
|
+
if (Number.isInteger(child) && child > 0) killProcessTree(child);
|
|
1718
|
+
}
|
|
1719
|
+
}
|
|
1720
|
+
try {
|
|
1721
|
+
process.kill(pid, "SIGKILL");
|
|
1722
|
+
} catch {
|
|
1723
|
+
// Already gone.
|
|
1724
|
+
}
|
|
1725
|
+
}
|
|
1726
|
+
|
|
1655
1727
|
/**
|
|
1656
1728
|
* Default app boot: `bun --hot` on the shipped runner (socket-preserving).
|
|
1657
1729
|
*
|
|
@@ -1687,17 +1759,18 @@ async function startAppHot(
|
|
|
1687
1759
|
});
|
|
1688
1760
|
|
|
1689
1761
|
let stopped = false;
|
|
1690
|
-
const stop = () => {
|
|
1691
|
-
if (stopped) return;
|
|
1762
|
+
const stop = (): Promise<void> => {
|
|
1763
|
+
if (stopped) return proc.exited.then(() => {});
|
|
1692
1764
|
stopped = true;
|
|
1693
1765
|
try {
|
|
1694
1766
|
// SIGKILL so `bun --hot` cannot linger and hold the project directory
|
|
1695
1767
|
// open (create-oke afterEach `rmSync` otherwise races the child exit).
|
|
1696
|
-
proc.
|
|
1768
|
+
killProcessTree(proc.pid);
|
|
1697
1769
|
} catch {
|
|
1698
1770
|
// Inconsequential: process already exited — kill is idempotent best-effort.
|
|
1699
1771
|
}
|
|
1700
1772
|
void unlink(readyPath).catch(() => {});
|
|
1773
|
+
return proc.exited.then(() => {});
|
|
1701
1774
|
};
|
|
1702
1775
|
|
|
1703
1776
|
try {
|
|
@@ -24,7 +24,8 @@ export default defineConfig({
|
|
|
24
24
|
dialect: "postgresql",
|
|
25
25
|
schema: "./src/db/schema.drizzle.ts",
|
|
26
26
|
out: "./src/db/migrations",
|
|
27
|
-
//
|
|
27
|
+
// Domain tables live in public. Schema \`oke\` (RLS) and \`oke_console\` are engine-owned.
|
|
28
|
+
schemaFilter: ["public"],
|
|
28
29
|
tablesFilter: ["!oke_*"],
|
|
29
30
|
dbCredentials: {
|
|
30
31
|
url: process.env.DATABASE_URL ?? process.env.OKE_STORE_SQL_URL!,
|
package/src/cli/tui/DevLive.tsx
CHANGED
|
@@ -13,6 +13,7 @@ import { TUI_BRAND, TUI_HINT, TUI_MUTED, TUI_WARN } from "./theme.ts";
|
|
|
13
13
|
/** Props for {@link DevLiveControls}. */
|
|
14
14
|
export type DevLiveControlsProps = {
|
|
15
15
|
readonly onRefresh: () => void | Promise<void>;
|
|
16
|
+
readonly onSeed: () => void | Promise<void>;
|
|
16
17
|
readonly onComposeUp: () => void | Promise<void>;
|
|
17
18
|
readonly onComposeStop: () => void | Promise<void>;
|
|
18
19
|
readonly onQuit: () => void;
|
|
@@ -49,6 +50,14 @@ export function DevLiveControls(props: DevLiveControlsProps): ReactElement {
|
|
|
49
50
|
.finally(() => setBusy(false));
|
|
50
51
|
return;
|
|
51
52
|
}
|
|
53
|
+
if (ctrl === "s") {
|
|
54
|
+
setBusy(true);
|
|
55
|
+
void Promise.resolve(props.onSeed())
|
|
56
|
+
.then(() => setStatus("seeded"))
|
|
57
|
+
.catch((err: unknown) => setStatus(err instanceof Error ? err.message : String(err)))
|
|
58
|
+
.finally(() => setBusy(false));
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
52
61
|
if (ctrl === "u" || ctrl === "x") {
|
|
53
62
|
setBusy(true);
|
|
54
63
|
const run = ctrl === "u" ? props.onComposeUp : props.onComposeStop;
|
|
@@ -66,13 +75,13 @@ export function DevLiveControls(props: DevLiveControlsProps): ReactElement {
|
|
|
66
75
|
oke dev
|
|
67
76
|
</Text>
|
|
68
77
|
<Text color={TUI_MUTED}> · controls · </Text>
|
|
69
|
-
<Text color={TUI_HINT}>? help · r refresh · q quit · u up · x stop</Text>
|
|
78
|
+
<Text color={TUI_HINT}>? help · r refresh · s seed · q quit · u up · x stop</Text>
|
|
70
79
|
{busy ? <Text color={TUI_WARN}> · working…</Text> : null}
|
|
71
80
|
{status ? <Text color={TUI_MUTED}>{` · ${status}`}</Text> : null}
|
|
72
81
|
</Text>
|
|
73
82
|
{help ? (
|
|
74
83
|
<Text color={TUI_MUTED}>
|
|
75
|
-
r clear/refresh board · q quit · u compose up · x compose stop
|
|
84
|
+
r clear/refresh board · s oke db seed · q quit · u compose up · x compose stop
|
|
76
85
|
</Text>
|
|
77
86
|
) : null}
|
|
78
87
|
</Box>
|
|
@@ -104,6 +113,7 @@ export async function launchDevLiveControls(props: DevLiveControlsProps): Promis
|
|
|
104
113
|
|
|
105
114
|
const bound: DevLiveControlsProps = {
|
|
106
115
|
onRefresh: () => afterStdout(props.onRefresh),
|
|
116
|
+
onSeed: () => afterStdout(props.onSeed),
|
|
107
117
|
onComposeUp: () => afterStdout(props.onComposeUp),
|
|
108
118
|
onComposeStop: () => afterStdout(props.onComposeStop),
|
|
109
119
|
onQuit: props.onQuit,
|
package/src/cli/tui/keys.test.ts
CHANGED
|
@@ -2,10 +2,11 @@ import { describe, expect, test } from "bun:test";
|
|
|
2
2
|
import { mapDevControlInput } from "./keys.ts";
|
|
3
3
|
|
|
4
4
|
describe("mapDevControlInput", () => {
|
|
5
|
-
test("maps ? r q u x and aliases", () => {
|
|
5
|
+
test("maps ? r s q u x and aliases", () => {
|
|
6
6
|
expect(mapDevControlInput("?", {})).toBe("?");
|
|
7
7
|
expect(mapDevControlInput("h", {})).toBe("?");
|
|
8
8
|
expect(mapDevControlInput("r", {})).toBe("r");
|
|
9
|
+
expect(mapDevControlInput("s", {})).toBe("s");
|
|
9
10
|
expect(mapDevControlInput("q", {})).toBe("q");
|
|
10
11
|
expect(mapDevControlInput("u", {})).toBe("u");
|
|
11
12
|
expect(mapDevControlInput("x", {})).toBe("x");
|
package/src/cli/tui/keys.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shared keyboard mapping for Ink `useInput` and pure tests.
|
|
3
|
-
* Parity with legacy `parseDevControlKey` (`? r q u x`).
|
|
3
|
+
* Parity with legacy `parseDevControlKey` (`? r s q u x`).
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
/** Dev control action from a keypress. */
|
|
7
|
-
export type DevControlKey = "?" | "r" | "q" | "u" | "x";
|
|
7
|
+
export type DevControlKey = "?" | "r" | "s" | "q" | "u" | "x";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Map Ink input (+ ctrl) to a control key.
|
|
@@ -20,6 +20,7 @@ export function mapDevControlInput(
|
|
|
20
20
|
if (input === "?" || input === "h" || input === "H") return "?";
|
|
21
21
|
if (input === "q" || input === "Q") return "q";
|
|
22
22
|
if (input === "r" || input === "R") return "r";
|
|
23
|
+
if (input === "s" || input === "S") return "s";
|
|
23
24
|
if (input === "u" || input === "U") return "u";
|
|
24
25
|
if (input === "x" || input === "X") return "x";
|
|
25
26
|
return null;
|
package/src/compiler/aot.test.ts
CHANGED
|
@@ -129,7 +129,7 @@ describe("typed error narrowing end-to-end", () => {
|
|
|
129
129
|
const FlightFull = z.object({ seatsLeft: z.number() });
|
|
130
130
|
|
|
131
131
|
on(
|
|
132
|
-
http.post("/bookings").
|
|
132
|
+
http.post("/bookings").public(),
|
|
133
133
|
flow("bookings.create", {
|
|
134
134
|
in: Booking,
|
|
135
135
|
out: z.object({ id: z.string() }),
|
|
@@ -12,6 +12,7 @@ import type {
|
|
|
12
12
|
ResourceRef,
|
|
13
13
|
SecretRef,
|
|
14
14
|
SignalRef,
|
|
15
|
+
SignalResourceRef,
|
|
15
16
|
TemplateRef,
|
|
16
17
|
FlowRef,
|
|
17
18
|
} from "../manifest/types.ts";
|
|
@@ -56,6 +57,8 @@ export interface InferBinding {
|
|
|
56
57
|
| "flow"
|
|
57
58
|
| "embed"
|
|
58
59
|
| "table"
|
|
60
|
+
| "mcp-server"
|
|
61
|
+
| "mcp-tool"
|
|
59
62
|
| "unknown";
|
|
60
63
|
/** Resolved resource / name. */
|
|
61
64
|
readonly ref: string;
|
|
@@ -142,7 +145,7 @@ const TABLE_ARG_METHODS = new Set([
|
|
|
142
145
|
* @param options - Handler AST, bindings, and annotation flag
|
|
143
146
|
*/
|
|
144
147
|
export function inferEffects(options: InferEffectsOptions): InferredEffects {
|
|
145
|
-
const reads = new Set<ResourceRef>();
|
|
148
|
+
const reads = new Set<ResourceRef | SignalResourceRef>();
|
|
146
149
|
const writes = new Set<ResourceRef>();
|
|
147
150
|
const emits = new Set<SignalRef>();
|
|
148
151
|
const sends = new Set<TemplateRef>();
|
|
@@ -173,6 +176,12 @@ export function inferEffects(options: InferEffectsOptions): InferredEffects {
|
|
|
173
176
|
continue;
|
|
174
177
|
}
|
|
175
178
|
|
|
179
|
+
if (chain.rootMethod === "deadLetters" && call === chain.rootCall) {
|
|
180
|
+
const ref = resolveNamed(call.arguments[0], options.bindings, "signal");
|
|
181
|
+
if (ref) reads.add(`signal:${ref}`);
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
|
|
176
185
|
if (chain.rootMethod === "send" && call === chain.rootCall) {
|
|
177
186
|
const ref = resolveNamed(call.arguments[0], options.bindings, "template");
|
|
178
187
|
if (ref) sends.add(ref);
|
|
@@ -203,7 +212,7 @@ export function inferEffects(options: InferEffectsOptions): InferredEffects {
|
|
|
203
212
|
}
|
|
204
213
|
|
|
205
214
|
if (chain.rootMethod === "call" && call === chain.rootCall) {
|
|
206
|
-
const ref =
|
|
215
|
+
const ref = resolveCallTarget(call.arguments[0], options.bindings);
|
|
207
216
|
if (ref) calls.add(ref);
|
|
208
217
|
continue;
|
|
209
218
|
}
|
|
@@ -541,12 +550,58 @@ function toolsFromAskOptions(
|
|
|
541
550
|
);
|
|
542
551
|
const out: FlowRef[] = [];
|
|
543
552
|
for (const el of els) {
|
|
544
|
-
const ref =
|
|
553
|
+
const ref = resolveCallTarget(el, bindings);
|
|
545
554
|
if (ref) out.push(ref as FlowRef);
|
|
546
555
|
}
|
|
547
556
|
return out;
|
|
548
557
|
}
|
|
549
558
|
|
|
559
|
+
/**
|
|
560
|
+
* Resolve `fx.call` / ask-tools: flow name, `mcp:` ref, or `server.tool("x")`.
|
|
561
|
+
*
|
|
562
|
+
* @param node - Argument AST
|
|
563
|
+
* @param bindings - Known bindings
|
|
564
|
+
*/
|
|
565
|
+
export function resolveCallTarget(
|
|
566
|
+
node: AstNode | undefined,
|
|
567
|
+
bindings: ReadonlyMap<string, InferBinding>,
|
|
568
|
+
): string | undefined {
|
|
569
|
+
const mcp = resolveMcpToolExpr(node, bindings);
|
|
570
|
+
if (mcp) return mcp;
|
|
571
|
+
return resolveNamed(node, bindings, "flow");
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
/**
|
|
575
|
+
* Resolve `server.tool("name")` or a bound `mcp-tool` identifier.
|
|
576
|
+
*
|
|
577
|
+
* @param node - AST
|
|
578
|
+
* @param bindings - Known bindings
|
|
579
|
+
*/
|
|
580
|
+
export function resolveMcpToolExpr(
|
|
581
|
+
node: AstNode | undefined,
|
|
582
|
+
bindings: ReadonlyMap<string, InferBinding>,
|
|
583
|
+
): string | undefined {
|
|
584
|
+
if (!node) return undefined;
|
|
585
|
+
if (node.type === "CallExpression") {
|
|
586
|
+
const callee = (node as CallExpression).callee;
|
|
587
|
+
if (callee.type === "MemberExpression") {
|
|
588
|
+
const member = callee as AstNode & { object: AstNode; property: AstNode };
|
|
589
|
+
const obj = identifierName(member.object);
|
|
590
|
+
const prop = identifierName(member.property);
|
|
591
|
+
const tool = stringArg((node as CallExpression).arguments[0]);
|
|
592
|
+
if (obj && prop === "tool" && tool) {
|
|
593
|
+
const server = bindings.get(obj);
|
|
594
|
+
if (server?.kind === "mcp-server") {
|
|
595
|
+
return `mcp:${server.ref}/${tool}`;
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
const binding = resolveBinding(node, bindings);
|
|
601
|
+
if (binding?.kind === "mcp-tool") return binding.ref;
|
|
602
|
+
return undefined;
|
|
603
|
+
}
|
|
604
|
+
|
|
550
605
|
/**
|
|
551
606
|
* String literal argument.
|
|
552
607
|
*
|