okengine 0.9.0 → 0.10.0
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/manifest.v1.schema.json +9 -1
- package/package.json +3 -3
- package/site/content/docs/console/runs.mdx +10 -0
- package/site/content/docs/console/traces.mdx +4 -0
- package/site/content/docs/elements/ai.mdx +54 -32
- package/site/content/docs/elements/channel.mdx +105 -14
- package/site/content/docs/elements/clock.mdx +1 -0
- package/site/content/docs/elements/flow.mdx +42 -8
- package/site/content/docs/get-started/basic-usage.mdx +5 -1
- package/site/content/docs/get-started/installation.mdx +9 -5
- package/site/content/docs/meta.json +2 -0
- package/site/content/docs/plugins/otp.mdx +58 -46
- package/site/content/docs/providers/azure-redis.mdx +85 -0
- package/site/content/docs/providers/cockroachdb.mdx +86 -0
- package/site/content/docs/providers/digitalocean-caching.mdx +88 -0
- package/site/content/docs/providers/dragonfly-cloud.mdx +82 -0
- package/site/content/docs/providers/elasticache.mdx +92 -0
- package/site/content/docs/providers/index.mdx +101 -0
- package/site/content/docs/providers/memorystore.mdx +89 -0
- package/site/content/docs/providers/meta.json +20 -0
- package/site/content/docs/providers/neon.mdx +115 -0
- package/site/content/docs/providers/redis-cloud.mdx +93 -0
- package/site/content/docs/providers/supabase.mdx +117 -0
- package/site/content/docs/providers/upstash.mdx +91 -0
- package/site/content/docs/providers/yugabytedb.mdx +95 -0
- package/site/content/docs/recipes/caddy.mdx +128 -0
- package/site/content/docs/recipes/cockroachdb.mdx +127 -0
- package/site/content/docs/recipes/dragonfly.mdx +125 -0
- package/site/content/docs/recipes/index.mdx +146 -0
- package/site/content/docs/recipes/llama-cpp.mdx +153 -0
- package/site/content/docs/recipes/mailpit.mdx +136 -0
- package/site/content/docs/recipes/meilisearch.mdx +139 -0
- package/site/content/docs/recipes/meta.json +31 -0
- package/site/content/docs/recipes/ollama.mdx +142 -0
- package/site/content/docs/recipes/openbao.mdx +141 -0
- package/site/content/docs/recipes/pgdog.mdx +137 -0
- package/site/content/docs/recipes/postgres.mdx +136 -0
- package/site/content/docs/recipes/redis.mdx +130 -0
- package/site/content/docs/recipes/rustfs.mdx +148 -0
- package/site/content/docs/recipes/sglang.mdx +105 -0
- package/site/content/docs/recipes/supabase-docker.mdx +145 -0
- package/site/content/docs/recipes/timescale.mdx +129 -0
- package/site/content/docs/recipes/traefik.mdx +136 -0
- package/site/content/docs/recipes/valkey.mdx +121 -0
- package/site/content/docs/recipes/vllm.mdx +106 -0
- package/site/content/docs/recipes/yugabytedb.mdx +135 -0
- package/site/content/docs/reference/cli.md +42 -6
- package/site/content/docs/reference/configuration.mdx +5 -3
- package/site/content/docs/reference/environment-variables.mdx +12 -12
- package/site/content/docs/reference/fx.mdx +38 -4
- package/src/auth/otp-capability.ts +14 -14
- package/src/cli/ai-setup/ai-setup.test.ts +32 -12
- package/src/cli/ai-setup/apply.ts +65 -23
- package/src/cli/ai-setup/catalog.ts +1316 -35
- package/src/cli/ai-setup/detect-ollama.ts +47 -0
- package/src/cli/ai-setup/index.ts +44 -7
- package/src/cli/ai-setup/prompts.ts +430 -486
- package/src/cli/ai-setup/recommend.test.ts +150 -50
- package/src/cli/ai-setup/recommend.ts +118 -101
- package/src/cli/ask-seed.test.ts +68 -0
- package/src/cli/ask-seed.ts +79 -0
- package/src/cli/db-seed-redact.test.ts +25 -0
- package/src/cli/db-seed.ts +36 -7
- package/src/cli/db.test.ts +1 -1
- package/src/cli/db.ts +2 -2
- package/src/cli/dev-controls.test.ts +107 -0
- package/src/cli/dev-controls.ts +354 -0
- package/src/cli/dev-schema-sync.ts +12 -4
- package/src/cli/dev.test.ts +50 -30
- package/src/cli/dev.ts +607 -66
- package/src/cli/drizzle-env.test.ts +40 -6
- package/src/cli/drizzle-env.ts +22 -1
- package/src/cli/ensure-drizzle-config.ts +6 -4
- package/src/cli/hero-meta.test.ts +13 -1
- package/src/cli/hero-meta.ts +28 -6
- package/src/cli/index.ts +5 -0
- package/src/cli/registry.ts +24 -0
- package/src/cli/replay.test.ts +105 -0
- package/src/cli/replay.ts +206 -0
- package/src/compiler/extract.ts +3 -3
- package/src/config/index.ts +3 -3
- package/src/console/server/claim.ts +3 -1
- package/src/console/ui/dist/assets/{index-ClX0ZCe5.js → index-D-9KFce5.js} +2 -2
- package/src/console/ui/dist/assets/panel-overview-CW0CQEc2.js +1 -0
- package/src/console/ui/dist/assets/panel-runs-BxuyDI3x.js +1 -0
- package/src/console/ui/dist/assets/{panel-signals-Dsxdu_AR.js → panel-signals-BXofbj7v.js} +1 -1
- package/src/console/ui/dist/assets/{panel-store-hy7O8HOs.js → panel-store-B8mH-arU.js} +1 -1
- package/src/console/ui/dist/assets/{panel-traces-CBiAe5go.js → panel-traces-DSA-ZWnf.js} +1 -1
- package/src/console/ui/dist/index.html +1 -1
- package/src/console/ui/overview/slo.ts +31 -3
- package/src/console/ui/overview/types.ts +6 -0
- package/src/console/ui/runs/errors.test.ts +53 -0
- package/src/console/ui/runs/errors.ts +88 -0
- package/src/console/ui/runs/index.ts +8 -0
- package/src/console/ui/runs/search.ts +16 -0
- package/src/console/ui/shell/panels/runs/RunsPanel.tsx +72 -1
- package/src/docker/ai-model-status.test.ts +101 -0
- package/src/docker/ai-model-status.ts +276 -0
- package/src/docker/compose-health.test.ts +115 -0
- package/src/docker/compose-health.ts +234 -0
- package/src/docker/compose.ts +24 -8
- package/src/docker/derive.ts +35 -9
- package/src/docker/docker.test.ts +304 -12
- package/src/docker/helpers.ts +56 -0
- package/src/docker/index.ts +52 -0
- package/src/docker/ollama-pull.ts +232 -0
- package/src/docker/recipes/cockroach.ts +24 -0
- package/src/docker/recipes/index.ts +32 -0
- package/src/docker/recipes/llama-cpp.ts +273 -0
- package/src/docker/recipes/ollama.ts +19 -23
- package/src/docker/recipes/pgdog.ts +4 -1
- package/src/docker/recipes/postgres.ts +5 -18
- package/src/docker/recipes/sglang.ts +55 -0
- package/src/docker/recipes/supabase.ts +21 -0
- package/src/docker/recipes/timescale.ts +18 -0
- package/src/docker/recipes/vllm.ts +44 -0
- package/src/docker/recipes/yugabyte.ts +23 -0
- package/src/docker/stack-id.test.ts +22 -0
- package/src/docker/stack-id.ts +38 -4
- package/src/docker/types.ts +15 -0
- package/src/drivers/ai-ollama.integration.test.ts +7 -4
- package/src/drivers/signal-engine.ts +10 -0
- package/src/drivers/signal-postgres.ts +24 -2
- package/src/drivers/signal-types.ts +10 -0
- package/src/elements/channel/fallback.test.ts +91 -0
- package/src/elements/channel/hard-bounce.test.ts +82 -0
- package/src/elements/channel/injection.test.ts +153 -0
- package/src/elements/channel/locale-ar.test.ts +102 -0
- package/src/elements/channel/otp-delivery.ts +5 -2
- package/src/elements/channel/receipts-ledger.test.ts +100 -0
- package/src/elements/channel/runtime.ts +24 -1
- package/src/elements/channel/test-helpers.ts +60 -0
- package/src/elements/channel/whatsapp-compliance.test.ts +124 -0
- package/src/elements/store/cache.ts +1 -1
- package/src/elements/store/emit-drizzle.ts +43 -9
- package/src/elements/store/runtime.ts +1 -1
- package/src/elements/store/schema-decl.test.ts +2 -0
- package/src/elements/store/schema-decl.ts +15 -0
- package/src/elements/store/seed.ts +1 -1
- package/src/index.ts +1 -0
- package/src/kernel/app.ts +118 -11
- package/src/kernel/boot-bind/signal.ts +6 -2
- package/src/kernel/boot-bind/store.ts +2 -1
- package/src/kernel/boot.test.ts +6 -5
- package/src/kernel/boot.ts +8 -3
- package/src/kernel/compensate.test.ts +131 -0
- package/src/kernel/correlation.test.ts +108 -0
- package/src/kernel/effect-timing.test.ts +82 -0
- package/src/kernel/flow.ts +38 -0
- package/src/kernel/fx-runs.test.ts +49 -0
- package/src/kernel/fx.test.ts +14 -0
- package/src/kernel/fx.ts +111 -1
- package/src/manifest/types.ts +8 -2
- package/src/plugins/auth-delivery.mailpit.integration.test.ts +1 -1
- package/src/plugins/auth-methods.security.test.ts +3 -3
- package/src/plugins/auth-methods.test.ts +1 -1
- package/src/plugins/index.ts +2 -2
- package/src/plugins/otp.test.ts +21 -19
- package/src/plugins/otp.ts +36 -34
- package/src/plugins/taqnyat.live.test.ts +3 -3
- package/src/runs/collect.ts +3 -0
- package/src/runs/export-otlp.ts +64 -0
- package/src/runs/index.ts +16 -0
- package/src/runs/parquet.ts +9 -0
- package/src/runs/types.ts +5 -0
- package/src/runs/window.test.ts +68 -0
- package/src/runs/window.ts +148 -0
- package/src/runtime/boot-warn.test.ts +45 -0
- package/src/runtime/boot-warn.ts +17 -0
- package/src/runtime/dev-request-log.ts +5 -5
- package/src/term.test.ts +95 -10
- package/src/term.ts +369 -14
- package/src/console/ui/dist/assets/panel-overview-DONDzBd2.js +0 -1
- package/src/console/ui/dist/assets/panel-runs-D5zf-D9c.js +0 -1
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Boot honesty suppress flag for the `oke dev` Backend child.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { afterEach, describe, expect, test } from "bun:test";
|
|
6
|
+
import { emitBootWarn } from "./boot-warn.ts";
|
|
7
|
+
|
|
8
|
+
describe("emitBootWarn", () => {
|
|
9
|
+
const prev = process.env["OKE_SUPPRESS_BOOT_WARN"];
|
|
10
|
+
|
|
11
|
+
afterEach(() => {
|
|
12
|
+
if (prev === undefined) delete process.env["OKE_SUPPRESS_BOOT_WARN"];
|
|
13
|
+
else process.env["OKE_SUPPRESS_BOOT_WARN"] = prev;
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
test("forwards to console.warn by default", () => {
|
|
17
|
+
delete process.env["OKE_SUPPRESS_BOOT_WARN"];
|
|
18
|
+
const lines: string[] = [];
|
|
19
|
+
const original = console.warn;
|
|
20
|
+
console.warn = (...args: unknown[]) => {
|
|
21
|
+
lines.push(args.map(String).join(" "));
|
|
22
|
+
};
|
|
23
|
+
try {
|
|
24
|
+
emitBootWarn("oke boot: test notice");
|
|
25
|
+
expect(lines).toEqual(["oke boot: test notice"]);
|
|
26
|
+
} finally {
|
|
27
|
+
console.warn = original;
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test("no-ops when OKE_SUPPRESS_BOOT_WARN=1", () => {
|
|
32
|
+
process.env["OKE_SUPPRESS_BOOT_WARN"] = "1";
|
|
33
|
+
const lines: string[] = [];
|
|
34
|
+
const original = console.warn;
|
|
35
|
+
console.warn = (...args: unknown[]) => {
|
|
36
|
+
lines.push(args.map(String).join(" "));
|
|
37
|
+
};
|
|
38
|
+
try {
|
|
39
|
+
emitBootWarn("oke boot: hidden");
|
|
40
|
+
expect(lines).toEqual([]);
|
|
41
|
+
} finally {
|
|
42
|
+
console.warn = original;
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Boot honesty lines (`oke boot: …`) — once per process, suppressible in
|
|
3
|
+
* the `oke dev` Backend child so the parent Console owns the notice.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Emit a boot warning unless suppressed for this process.
|
|
8
|
+
*
|
|
9
|
+
* Set `OKE_SUPPRESS_BOOT_WARN=1` on the Backend child during `oke dev` so
|
|
10
|
+
* Signal / Channel / files process-local notices print once (parent only).
|
|
11
|
+
*
|
|
12
|
+
* @param message - Full warning text (usually prefixed `oke boot:`)
|
|
13
|
+
*/
|
|
14
|
+
export function emitBootWarn(message: string): void {
|
|
15
|
+
if (process.env["OKE_SUPPRESS_BOOT_WARN"] === "1") return;
|
|
16
|
+
console.warn(message);
|
|
17
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Dev-only request lines for `oke dev` (
|
|
2
|
+
* Dev-only request lines for `oke dev` (Backend / Console / MCP).
|
|
3
3
|
*
|
|
4
4
|
* Gated by `OKE_DEV_REQUEST_LOG=1`. Surfaces share one TTY; label + color
|
|
5
5
|
* keep streams readable without a multiplexer.
|
|
@@ -18,22 +18,22 @@ export function shouldLogDevRequests(): boolean {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
|
-
* Active surface for this async context, or `OKE_DEV_SURFACE`, or `
|
|
21
|
+
* Active surface for this async context, or `OKE_DEV_SURFACE`, or `Backend`.
|
|
22
22
|
*/
|
|
23
23
|
export function currentDevSurface(): DevLogSurface {
|
|
24
24
|
const fromAls = surfaceAls.getStore();
|
|
25
25
|
if (fromAls) return fromAls;
|
|
26
26
|
const fromEnv = process.env.OKE_DEV_SURFACE;
|
|
27
|
-
if (fromEnv === "
|
|
27
|
+
if (fromEnv === "Backend" || fromEnv === "Console" || fromEnv === "MCP") {
|
|
28
28
|
return fromEnv;
|
|
29
29
|
}
|
|
30
|
-
return "
|
|
30
|
+
return "Backend";
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
/**
|
|
34
34
|
* Run a handler tagged with a surface (Console wrap around `app.fetch`).
|
|
35
35
|
*
|
|
36
|
-
* @param surface -
|
|
36
|
+
* @param surface - Backend · Console · MCP
|
|
37
37
|
* @param fn - Async work
|
|
38
38
|
*/
|
|
39
39
|
export function runWithDevSurface<T>(
|
package/src/term.test.ts
CHANGED
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
import { describe, expect, test } from "bun:test";
|
|
6
6
|
import {
|
|
7
7
|
formatAppReadyLine,
|
|
8
|
+
formatBootWarn,
|
|
8
9
|
formatClaimNote,
|
|
10
|
+
formatCliChrome,
|
|
9
11
|
formatDevBanner,
|
|
10
12
|
formatDevHero,
|
|
11
13
|
formatDevLogSeparator,
|
|
@@ -13,6 +15,11 @@ import {
|
|
|
13
15
|
formatServiceLine,
|
|
14
16
|
formatRequestLine,
|
|
15
17
|
formatStackSummary,
|
|
18
|
+
countTermLines,
|
|
19
|
+
createAnchoredBoard,
|
|
20
|
+
createBootProgress,
|
|
21
|
+
createRewritableBlock,
|
|
22
|
+
formatStatusDot,
|
|
16
23
|
formatStatusLine,
|
|
17
24
|
termStyle,
|
|
18
25
|
} from "./term.ts";
|
|
@@ -38,9 +45,10 @@ describe("term", () => {
|
|
|
38
45
|
runtimeEnv: "local",
|
|
39
46
|
system: "darwin 25.4.0 · bun 1.3.14",
|
|
40
47
|
elements: [
|
|
41
|
-
{ element: "flow", detail: "
|
|
42
|
-
{ element: "store", detail: "sql postgres · kv redis" },
|
|
43
|
-
{ element: "signal", detail: "memory" },
|
|
48
|
+
{ element: "flow", detail: "", status: "ready" },
|
|
49
|
+
{ element: "store", detail: "sql postgres · kv redis", status: "ready" },
|
|
50
|
+
{ element: "signal", detail: "memory", status: "ready" },
|
|
51
|
+
{ element: "ai", detail: "openai-compatible · smollm2", status: "pending" },
|
|
44
52
|
],
|
|
45
53
|
});
|
|
46
54
|
expect(out).toContain("oke dev v0.2.4");
|
|
@@ -53,11 +61,65 @@ describe("term", () => {
|
|
|
53
61
|
expect(out).toContain("elements");
|
|
54
62
|
expect(out).toContain("store");
|
|
55
63
|
expect(out).toContain("postgres");
|
|
64
|
+
expect(out).toContain("● flow");
|
|
65
|
+
expect(out).toContain("● ai");
|
|
56
66
|
expect(out).not.toContain("on(Trigger)");
|
|
57
67
|
expect(out).not.toContain("O·K·E");
|
|
58
68
|
expect(out).not.toMatch(/\u001b\[/);
|
|
59
69
|
});
|
|
60
70
|
|
|
71
|
+
test("formatStatusDot colors by status", () => {
|
|
72
|
+
const s = termStyle(true);
|
|
73
|
+
expect(formatStatusDot("ready", true)).toBe(`${s.green}●${s.reset}`);
|
|
74
|
+
expect(formatStatusDot("pending", true)).toBe(`${s.yellow}●${s.reset}`);
|
|
75
|
+
expect(formatStatusDot("error", true)).toBe(`${s.red}●${s.reset}`);
|
|
76
|
+
expect(formatStatusDot("idle", true)).toBe(`${s.dim}●${s.reset}`);
|
|
77
|
+
expect(formatStatusDot("ready", false)).toBe("●");
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test("createRewritableBlock appends when disabled", () => {
|
|
81
|
+
let out = "";
|
|
82
|
+
const block = createRewritableBlock((t) => {
|
|
83
|
+
out += t;
|
|
84
|
+
}, false);
|
|
85
|
+
block.paint("a\nb\n");
|
|
86
|
+
block.paint("c\n");
|
|
87
|
+
expect(out).toBe("a\nb\nc\n");
|
|
88
|
+
expect(countTermLines("a\nb\n")).toBe(2);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test("createBootProgress replaces keyed rows then clears", () => {
|
|
92
|
+
let out = "";
|
|
93
|
+
const progress = createBootProgress((t) => {
|
|
94
|
+
out += t;
|
|
95
|
+
}, false);
|
|
96
|
+
progress.set("compose", "compose…\n");
|
|
97
|
+
progress.set("compose", "compose ok\n");
|
|
98
|
+
progress.set("vault", "vault ok\n");
|
|
99
|
+
// Non-TTY appends each set (including replacements).
|
|
100
|
+
expect(out).toContain("compose ok\n");
|
|
101
|
+
expect(out).toContain("vault ok\n");
|
|
102
|
+
progress.clear();
|
|
103
|
+
// clear is a no-op on the stream when rewrite is disabled
|
|
104
|
+
expect(out).toContain("vault ok\n");
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
test("createAnchoredBoard wrapWrite tracks below output", () => {
|
|
108
|
+
let out = "";
|
|
109
|
+
const board = createAnchoredBoard((t) => {
|
|
110
|
+
out += t;
|
|
111
|
+
}, false);
|
|
112
|
+
board.paint("board\n");
|
|
113
|
+
const w = board.wrapWrite((t) => {
|
|
114
|
+
out += t;
|
|
115
|
+
});
|
|
116
|
+
w("below\n");
|
|
117
|
+
board.paint("board2\n"); // non-TTY: no rewrite append
|
|
118
|
+
expect(out).toContain("board\n");
|
|
119
|
+
expect(out).toContain("below\n");
|
|
120
|
+
board.stop();
|
|
121
|
+
});
|
|
122
|
+
|
|
61
123
|
test("formatServiceLine / formatAppReadyLine include URL", () => {
|
|
62
124
|
expect(formatServiceLine("Console", "http://127.0.0.1:6533", false)).toContain(
|
|
63
125
|
"http://127.0.0.1:6533",
|
|
@@ -65,7 +127,7 @@ describe("term", () => {
|
|
|
65
127
|
expect(formatAppReadyLine("http://127.0.0.1:6530", false)).toContain("http://127.0.0.1:6530");
|
|
66
128
|
});
|
|
67
129
|
|
|
68
|
-
test("formatDevHero keeps
|
|
130
|
+
test("formatDevHero keeps Backend Console MCP URLs", () => {
|
|
69
131
|
const out = formatDevHero({
|
|
70
132
|
appUrl: "http://127.0.0.1:6530",
|
|
71
133
|
consoleUrl: "http://127.0.0.1:6533",
|
|
@@ -73,12 +135,12 @@ describe("term", () => {
|
|
|
73
135
|
profile: "local",
|
|
74
136
|
runtimeEnv: "local",
|
|
75
137
|
system: "darwin 25.4.0 · bun 1.3.14",
|
|
76
|
-
elements: [{ element: "flow", detail: "
|
|
138
|
+
elements: [{ element: "flow", detail: "", status: "ready" }],
|
|
77
139
|
color: false,
|
|
78
140
|
});
|
|
79
141
|
expect(out).toContain("oke dev");
|
|
80
142
|
expect(out).toContain("██");
|
|
81
|
-
expect(out).toContain("
|
|
143
|
+
expect(out).toContain("Backend");
|
|
82
144
|
expect(out).toContain("Console");
|
|
83
145
|
expect(out).toContain("MCP");
|
|
84
146
|
expect(out).toContain("http://127.0.0.1:6530");
|
|
@@ -106,10 +168,27 @@ describe("term", () => {
|
|
|
106
168
|
expect(formatStatusLine("stack up (sql)", false)).toContain("stack up");
|
|
107
169
|
});
|
|
108
170
|
|
|
171
|
+
test("formatBootWarn wraps under Notice chrome", () => {
|
|
172
|
+
const out = formatBootWarn(
|
|
173
|
+
"oke boot: Channel suppression defaults to process-local memory for multi-instance",
|
|
174
|
+
false,
|
|
175
|
+
);
|
|
176
|
+
expect(out).toContain("Notice");
|
|
177
|
+
expect(out).toContain("process-local");
|
|
178
|
+
expect(out).not.toContain("oke boot:");
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
test("formatCliChrome routes boot and status lines", () => {
|
|
182
|
+
const out = formatCliChrome("oke db seed: ok\noke boot: hello world\n", false);
|
|
183
|
+
expect(out).toContain("oke db seed: ok");
|
|
184
|
+
expect(out).toContain("Notice");
|
|
185
|
+
expect(out).toContain("hello world");
|
|
186
|
+
});
|
|
187
|
+
|
|
109
188
|
test("formatRequestLine shows date, time, surface, flow, ms, status", () => {
|
|
110
189
|
const at = new Date(2026, 6, 26, 3, 11, 42);
|
|
111
190
|
const out = formatRequestLine({
|
|
112
|
-
surface: "
|
|
191
|
+
surface: "Backend",
|
|
113
192
|
method: "GET",
|
|
114
193
|
path: "/health",
|
|
115
194
|
flow: "main.health",
|
|
@@ -120,7 +199,7 @@ describe("term", () => {
|
|
|
120
199
|
});
|
|
121
200
|
expect(out).toContain("2026-07-26");
|
|
122
201
|
expect(out).toContain("03:11:42");
|
|
123
|
-
expect(out).toContain("
|
|
202
|
+
expect(out).toContain("Backend");
|
|
124
203
|
expect(out).toContain("200");
|
|
125
204
|
expect(out).not.toMatch(/\u001b\[/);
|
|
126
205
|
});
|
|
@@ -144,14 +223,20 @@ describe("term", () => {
|
|
|
144
223
|
const out = formatStackSummary({
|
|
145
224
|
project: "oke-dev-a3f791",
|
|
146
225
|
services: [
|
|
147
|
-
{ label: "postgres", hostPort: 15975 },
|
|
148
|
-
{ label: "redis", hostPort: 16975 },
|
|
226
|
+
{ label: "postgres", hostPort: 15975, status: "ready" },
|
|
227
|
+
{ label: "redis", hostPort: 16975, status: "ready" },
|
|
228
|
+
{ label: "ai", hostPort: 23975, detail: "gemma4:e4b-q4_K_M", status: "pending" },
|
|
149
229
|
],
|
|
150
230
|
appDrivers: ["postgres", "redis"],
|
|
151
231
|
color: false,
|
|
152
232
|
});
|
|
153
233
|
expect(out).toContain("Docker");
|
|
154
234
|
expect(out).toContain(":15975");
|
|
235
|
+
expect(out).toContain("gemma4:e4b-q4_K_M");
|
|
236
|
+
expect(out).toContain("● postgres");
|
|
237
|
+
expect(out).toContain("● ai");
|
|
238
|
+
// Blank │ row separates the Docker header from whatever sits above.
|
|
239
|
+
expect(out).toMatch(/│\n◇ {2}Docker/);
|
|
155
240
|
expect(out).not.toMatch(/\u001b\[/);
|
|
156
241
|
});
|
|
157
242
|
});
|