okengine 0.1.6 → 0.2.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/AGENTS.md +1 -1
- package/README.md +36 -29
- package/docs/spec/example.md +1187 -0
- package/docs/spec/unified-theory.md +1 -1
- package/package.json +20 -6
- package/src/cli/dev-app-runner.ts +6 -2
- package/src/cli/dev.ts +19 -10
- package/src/cli/doc-drift.ts +54 -21
- package/src/console/index.ts +25 -13
- package/src/console/server/app.ts +44 -7
- package/src/console/server/claim.test.ts +7 -4
- package/src/console/server/claim.ts +2 -7
- package/src/console/server/flows.ts +2 -6
- package/src/console/server/index.ts +2 -1
- package/src/console/server/lazy-panels.test.ts +27 -0
- package/src/console/server/panel-load.ts +28 -0
- package/src/console/server/plugin.ts +1 -1
- package/src/console/server/plugins.ts +7 -6
- package/src/console/server/public-flows.ts +12 -0
- package/src/console/server/state.ts +159 -122
- package/src/console/server/store.ts +13 -10
- package/src/console/ui/dist/assets/index-B71Yl_SS.js +10 -0
- package/src/console/ui/dist/assets/panel-access-Dd37LU2c.js +64 -0
- package/src/console/ui/dist/assets/panel-ai-CC7LR6-J.js +1 -0
- package/src/console/ui/dist/assets/panel-architecture-B5b3iKCz.js +1 -0
- package/src/console/ui/dist/assets/panel-channels-CeNjTKXp.js +1 -0
- package/src/console/ui/dist/assets/panel-clock-DgFTLoHV.js +1 -0
- package/src/console/ui/dist/assets/panel-diff-DxehccqB.js +1 -0
- package/src/console/ui/dist/assets/panel-flows-BtrVn-Eg.js +45 -0
- package/src/console/ui/dist/assets/panel-gates-Z9MKRGdH.js +1 -0
- package/src/console/ui/dist/assets/panel-overview-Bd48d9km.js +1 -0
- package/src/console/ui/dist/assets/panel-plugins-DWd0TowH.js +1 -0
- package/src/console/ui/dist/assets/panel-runs-BwsWqKeB.js +1 -0
- package/src/console/ui/dist/assets/panel-signals-9najbZY2.js +1 -0
- package/src/console/ui/dist/assets/panel-store-OHkP2pDp.js +1 -0
- package/src/console/ui/dist/assets/panel-traces-tn2JoY8U.js +1 -0
- package/src/console/ui/dist/assets/panel-vault-BbfWdox0.js +1 -0
- package/src/console/ui/dist/assets/rolldown-runtime-CNC7AqOf.js +1 -0
- package/src/console/ui/dist/assets/style-Cnl7WLya.css +3 -0
- package/src/console/ui/dist/index.html +14 -0
- package/src/docs-origin.ts +19 -0
- package/src/drivers/index.ts +1 -6
- package/src/drivers/vault-sops.ts +20 -1
- package/src/kernel/app.ts +1 -1
- package/src/kernel/boot-bind/ai.ts +31 -0
- package/src/kernel/boot-bind/channel.ts +27 -0
- package/src/kernel/boot-bind/clock.ts +74 -0
- package/src/kernel/boot-bind/gate.ts +28 -0
- package/src/kernel/boot-bind/runs.ts +28 -0
- package/src/kernel/boot-bind/signal.ts +68 -0
- package/src/kernel/boot-bind/store.ts +47 -0
- package/src/kernel/boot-bind/vault.ts +36 -0
- package/src/kernel/boot.test.ts +85 -1
- package/src/kernel/boot.ts +250 -212
- package/src/kernel/errors.registry.test.ts +4 -2
- package/src/kernel/errors.ts +3 -1
- package/src/kernel/fx.test.ts +2 -2
- package/src/kernel/index.ts +2 -0
- package/src/mcp/data.ts +1 -0
- package/src/mcp/docs-index.ts +252 -0
- package/src/mcp/docs-mcp.test.ts +176 -0
- package/src/mcp/docs-server.ts +233 -0
- package/src/mcp/docs-tools.ts +143 -0
- package/src/mcp/index.ts +29 -5
- package/src/mcp/protocol.ts +2 -1
- package/src/release/exports.test.ts +71 -0
- package/src/release/exports.ts +156 -0
- package/src/release/index.ts +21 -0
- package/src/release/limits.ts +9 -0
- package/src/release/measure.exports.test.ts +82 -0
- package/src/release/measure.ts +297 -14
- package/src/release/publish.ts +14 -3
- package/src/release/readme.test.ts +61 -0
- package/src/release/readme.ts +13 -0
- package/src/runtime/index.ts +1 -0
- package/src/runtime/security.test.ts +6 -1
- package/src/runtime/types.ts +6 -0
- package/src/term.test.ts +51 -0
- package/src/term.ts +158 -0
- package/src/test/create-test-app.ts +2 -0
|
@@ -416,7 +416,7 @@ Plus `oke import express|hono|elysia` codemods for the mechanical parts. Migrati
|
|
|
416
416
|
|---|---|
|
|
417
417
|
| Kernel (edge profile) | < 15 kB |
|
|
418
418
|
| Client runtime | < 3 kB |
|
|
419
|
-
| Cold start on Bun | < 75 ms |
|
|
419
|
+
| Cold start on Bun | < 75 ms in CI (GitHub Actions runners are less predictable than a dev machine); measured ~25–30 ms on real hardware |
|
|
420
420
|
| p99 routing overhead | < 1 ms |
|
|
421
421
|
|
|
422
422
|
A regression fails OKE's own build. Claims we cannot measure, we do not make.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "okengine",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "One law. Eight elements. Ten exports. One package. One manifest. Every backend need is derived, never added.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -10,7 +10,9 @@
|
|
|
10
10
|
"url": "git+https://github.com/omqkhafi/okengine.git"
|
|
11
11
|
},
|
|
12
12
|
"workspaces": [
|
|
13
|
-
"
|
|
13
|
+
"packages/*",
|
|
14
|
+
"examples/*",
|
|
15
|
+
"site"
|
|
14
16
|
],
|
|
15
17
|
"scripts": {
|
|
16
18
|
"typecheck": "tsc --noEmit",
|
|
@@ -33,6 +35,7 @@
|
|
|
33
35
|
"test:mcp": "bun test src/mcp",
|
|
34
36
|
"test:console:smoke": "bunx playwright test tests/console/smoke.spec.ts",
|
|
35
37
|
"build:console": "bunx vite build --config src/console/ui/vite.config.ts",
|
|
38
|
+
"prepack": "bun run build:console",
|
|
36
39
|
"bench:cold-start": "bun test ./src/runtime/cold-start.bench.ts",
|
|
37
40
|
"bench:client": "bun test src/client/budget.test.ts",
|
|
38
41
|
"bench:console": "bun test src/console/budget.test.ts",
|
|
@@ -44,10 +47,13 @@
|
|
|
44
47
|
"gate:errors": "bun test src/kernel/errors.registry.test.ts",
|
|
45
48
|
"gate:codemods": "bun test src/upgrade/codemods.test.ts",
|
|
46
49
|
"test:examples": "bun test examples/notes && bun test examples/linkly && bun test examples/provisions && bun test examples/skyport",
|
|
47
|
-
"test:create-oke": "bun run --cwd packages/create-oke typecheck && bun test packages/create-oke/src && CREATE_OKE_INTEGRATION=1 bun test packages/create-oke/tests/scaffold.integration.test.ts packages/create-oke/tests/dev.integration.test.ts",
|
|
50
|
+
"test:create-oke": "bun run --cwd packages/create-oke typecheck && bun test packages/create-oke/src && CREATE_OKE_INTEGRATION=1 bun test --timeout 180000 packages/create-oke/tests/scaffold.integration.test.ts packages/create-oke/tests/dev.integration.test.ts",
|
|
48
51
|
"test:doc-drift": "bun src/cli/doc-drift.ts",
|
|
52
|
+
"site:sync": "bun run --cwd site sync",
|
|
53
|
+
"site:dev": "bun run --cwd site dev",
|
|
54
|
+
"site:build": "bun run --cwd site build",
|
|
49
55
|
"test:skyport-docker": "bun test examples/skyport/tests/docker.test.ts",
|
|
50
|
-
"ci": "bun run bench:cold-start && bun run typecheck && bun run test && bun run budgets && bun run gate:doctor-diff && bun run gate:errors && bun run gate:codemods && bun run test:doc-drift && bun run test:examples && bun run test:skyport-docker && bun run test:create-oke",
|
|
56
|
+
"ci": "bun run bench:cold-start && bun run typecheck && bun run test && bun run budgets && bun run gate:doctor-diff && bun run gate:errors && bun run gate:codemods && bun run test:doc-drift && bun run site:build && bun run test:examples && bun run test:skyport-docker && bun run test:create-oke",
|
|
51
57
|
"gate:publish": "bun test scripts/publish.gate.test.ts",
|
|
52
58
|
"bump": "bun run scripts/bump-version.ts",
|
|
53
59
|
"publish:all": "bun run scripts/publish.ts",
|
|
@@ -60,13 +66,13 @@
|
|
|
60
66
|
},
|
|
61
67
|
"dependencies": {
|
|
62
68
|
"@duckdb/node-api": "^1.5.5-r.1",
|
|
63
|
-
"age-encryption": "^0.3.0",
|
|
64
69
|
"ajv": "^8.20.0",
|
|
65
70
|
"ajv-formats": "^3.0.1",
|
|
66
71
|
"oxc-parser": "^0.141.0",
|
|
67
72
|
"sently": "^0.8.0"
|
|
68
73
|
},
|
|
69
74
|
"devDependencies": {
|
|
75
|
+
"age-encryption": "^0.3.0",
|
|
70
76
|
"@base-ui/react": "^1.6.0",
|
|
71
77
|
"@codemirror/commands": "^6.10.4",
|
|
72
78
|
"@codemirror/lang-json": "^6.0.2",
|
|
@@ -103,11 +109,16 @@
|
|
|
103
109
|
"zod": "^4.4.3"
|
|
104
110
|
},
|
|
105
111
|
"peerDependencies": {
|
|
112
|
+
"age-encryption": "^0.3.0",
|
|
106
113
|
"drizzle-kit": ">=1.0.0-rc.0",
|
|
107
114
|
"drizzle-orm": ">=1.0.0-rc.0",
|
|
108
|
-
"drizzle-seed": ">=0.3.0"
|
|
115
|
+
"drizzle-seed": ">=0.3.0",
|
|
116
|
+
"zod": ">=3.23.0"
|
|
109
117
|
},
|
|
110
118
|
"peerDependenciesMeta": {
|
|
119
|
+
"age-encryption": {
|
|
120
|
+
"optional": true
|
|
121
|
+
},
|
|
111
122
|
"drizzle-kit": {
|
|
112
123
|
"optional": true
|
|
113
124
|
},
|
|
@@ -116,6 +127,9 @@
|
|
|
116
127
|
},
|
|
117
128
|
"drizzle-seed": {
|
|
118
129
|
"optional": true
|
|
130
|
+
},
|
|
131
|
+
"zod": {
|
|
132
|
+
"optional": true
|
|
119
133
|
}
|
|
120
134
|
},
|
|
121
135
|
"engines": {
|
|
@@ -17,6 +17,7 @@ import { resolve } from "node:path";
|
|
|
17
17
|
import { pathToFileURL } from "node:url";
|
|
18
18
|
import { createBunRuntime } from "../runtime/bun.ts";
|
|
19
19
|
import { APP_PORT, type FetchApp } from "../runtime/types.ts";
|
|
20
|
+
import { formatAppReadyLine } from "../term.ts";
|
|
20
21
|
|
|
21
22
|
/** Stable Bun.serve id so `--hot` reuses the socket across soft reloads. */
|
|
22
23
|
export const DEV_APP_SERVE_ID = "oke-dev-app";
|
|
@@ -59,8 +60,11 @@ const handle = createBunRuntime().serve(mod.app, {
|
|
|
59
60
|
id: DEV_APP_SERVE_ID,
|
|
60
61
|
});
|
|
61
62
|
|
|
62
|
-
|
|
63
|
-
|
|
63
|
+
process.stdout.write(
|
|
64
|
+
formatAppReadyLine(
|
|
65
|
+
`http://${formatHostForUrl(hostname)}:${handle.port}`,
|
|
66
|
+
),
|
|
67
|
+
);
|
|
64
68
|
|
|
65
69
|
if (readyPath !== undefined && readyPath.length > 0) {
|
|
66
70
|
await Bun.write(readyPath, `${handle.port}\n`);
|
package/src/cli/dev.ts
CHANGED
|
@@ -23,6 +23,11 @@ import {
|
|
|
23
23
|
CONSOLE_PORT,
|
|
24
24
|
MCP_PORT,
|
|
25
25
|
} from "../runtime/types.ts";
|
|
26
|
+
import {
|
|
27
|
+
formatDevBanner,
|
|
28
|
+
formatServiceLine,
|
|
29
|
+
formatStatusLine,
|
|
30
|
+
} from "../term.ts";
|
|
26
31
|
import { clientAdd } from "./client-add.ts";
|
|
27
32
|
import { loadManifest, loadOkeConfig, resolveImages } from "./load-config.ts";
|
|
28
33
|
import { mcpContextFromConsole } from "./mcp-from-console.ts";
|
|
@@ -258,7 +263,7 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
258
263
|
}
|
|
259
264
|
});
|
|
260
265
|
await up(composeFiles, cwd);
|
|
261
|
-
write(`
|
|
266
|
+
write(formatStatusLine(`stack up (${stackRoles.join(", ")})`));
|
|
262
267
|
}
|
|
263
268
|
}
|
|
264
269
|
|
|
@@ -272,10 +277,7 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
272
277
|
stackEnv,
|
|
273
278
|
};
|
|
274
279
|
|
|
275
|
-
write(
|
|
276
|
-
`oke dev: app :${appPort} · Console :${consolePort} · MCP :${mcpPort}\n`,
|
|
277
|
-
);
|
|
278
|
-
write("oke dev: watching — client types regenerate on save\n");
|
|
280
|
+
write(formatDevBanner());
|
|
279
281
|
|
|
280
282
|
if (options.dryRun) return { code: 0, plan };
|
|
281
283
|
|
|
@@ -312,7 +314,12 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
312
314
|
? { manifest: seedManifest }
|
|
313
315
|
: {}),
|
|
314
316
|
});
|
|
315
|
-
write(
|
|
317
|
+
write(
|
|
318
|
+
formatServiceLine(
|
|
319
|
+
"Console",
|
|
320
|
+
`http://127.0.0.1:${server.port}`,
|
|
321
|
+
),
|
|
322
|
+
);
|
|
316
323
|
return {
|
|
317
324
|
console: server.console,
|
|
318
325
|
port: server.port,
|
|
@@ -334,7 +341,7 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
334
341
|
context: mcpOptions.context,
|
|
335
342
|
now: mcpOptions.now,
|
|
336
343
|
});
|
|
337
|
-
write(
|
|
344
|
+
write(formatServiceLine("MCP", `http://127.0.0.1:${server.port}`));
|
|
338
345
|
return {
|
|
339
346
|
port: server.port,
|
|
340
347
|
url: server.url,
|
|
@@ -352,7 +359,7 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
352
359
|
url: appUrl,
|
|
353
360
|
out: resolve(cwd, "oke-client.d.ts"),
|
|
354
361
|
});
|
|
355
|
-
write("
|
|
362
|
+
write(formatStatusLine("regenerated oke-client.d.ts"));
|
|
356
363
|
} catch {
|
|
357
364
|
// App may not be ready yet — ignore until next save.
|
|
358
365
|
}
|
|
@@ -500,7 +507,9 @@ async function startAppHot(
|
|
|
500
507
|
if (stopped) return;
|
|
501
508
|
stopped = true;
|
|
502
509
|
try {
|
|
503
|
-
|
|
510
|
+
// SIGKILL so `bun --hot` cannot linger and hold the project directory
|
|
511
|
+
// open (create-oke afterEach `rmSync` otherwise races the child exit).
|
|
512
|
+
proc.kill("SIGKILL");
|
|
504
513
|
} catch {
|
|
505
514
|
// already exited
|
|
506
515
|
}
|
|
@@ -513,7 +522,7 @@ async function startAppHot(
|
|
|
513
522
|
proc,
|
|
514
523
|
APP_READY_TIMEOUT_MS,
|
|
515
524
|
);
|
|
516
|
-
// Child prints
|
|
525
|
+
// Child prints the App ready line (again on each soft reload).
|
|
517
526
|
const url = new URL(`http://${hostname}:${boundPort}/`);
|
|
518
527
|
return { stop, port: boundPort, url };
|
|
519
528
|
} catch (err) {
|
package/src/cli/doc-drift.ts
CHANGED
|
@@ -14,6 +14,10 @@
|
|
|
14
14
|
* Usage:
|
|
15
15
|
* bun src/cli/doc-drift.ts
|
|
16
16
|
* bun src/cli/doc-drift.ts docs/spec/four-applications.md README.md
|
|
17
|
+
* bun src/cli/doc-drift.ts site/content/docs/learn/notes.md
|
|
18
|
+
*
|
|
19
|
+
* Default paths: four-applications.md, README.md, and every markdown/MDX file
|
|
20
|
+
* under site/content/docs (claimed fences only — prose-only pages skip).
|
|
17
21
|
*/
|
|
18
22
|
|
|
19
23
|
import { resolve } from "node:path";
|
|
@@ -21,8 +25,27 @@ import { Window } from "happy-dom";
|
|
|
21
25
|
|
|
22
26
|
const ROOT = resolve(import.meta.dir, "../..");
|
|
23
27
|
|
|
24
|
-
/**
|
|
25
|
-
|
|
28
|
+
/**
|
|
29
|
+
* Discover site content markdown that may contain claimed fences.
|
|
30
|
+
*
|
|
31
|
+
* @param root - Repo root
|
|
32
|
+
*/
|
|
33
|
+
async function discoverSiteDocs(root: string): Promise<string[]> {
|
|
34
|
+
const docsDir = resolve(root, "site/content/docs");
|
|
35
|
+
const out: string[] = [];
|
|
36
|
+
try {
|
|
37
|
+
const glob = new Bun.Glob("**/*.{md,mdx}");
|
|
38
|
+
for await (const rel of glob.scan({ cwd: docsDir, onlyFiles: true })) {
|
|
39
|
+
out.push(resolve(docsDir, rel));
|
|
40
|
+
}
|
|
41
|
+
} catch {
|
|
42
|
+
// site/ not present yet — skip
|
|
43
|
+
}
|
|
44
|
+
return out.sort();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Core docs that must contain claimed fences. */
|
|
48
|
+
const REQUIRED_DOCS: readonly string[] = [
|
|
26
49
|
resolve(ROOT, "docs/spec/four-applications.md"),
|
|
27
50
|
resolve(ROOT, "README.md"),
|
|
28
51
|
];
|
|
@@ -315,6 +338,9 @@ export async function checkDocDrift(
|
|
|
315
338
|
/**
|
|
316
339
|
* Run doc-drift over one or more markdown files.
|
|
317
340
|
*
|
|
341
|
+
* Site content under `site/` may have zero claimed fences (prose-only pages);
|
|
342
|
+
* only `docs/spec/four-applications.md` and `README.md` require at least one.
|
|
343
|
+
*
|
|
318
344
|
* @param paths - Absolute or repo-relative markdown paths
|
|
319
345
|
*/
|
|
320
346
|
export async function runDocDrift(
|
|
@@ -324,32 +350,36 @@ export async function runDocDrift(
|
|
|
324
350
|
let ok = true;
|
|
325
351
|
let total = 0;
|
|
326
352
|
let mermaidTotal = 0;
|
|
353
|
+
let checkedFiles = 0;
|
|
327
354
|
|
|
328
355
|
for (const path of paths) {
|
|
329
356
|
const abs = resolve(ROOT, path);
|
|
330
357
|
const label = abs.startsWith(ROOT + "/")
|
|
331
358
|
? abs.slice(ROOT.length + 1)
|
|
332
359
|
: abs;
|
|
360
|
+
const requireClaimed = !label.startsWith("site/");
|
|
333
361
|
const markdown = await Bun.file(abs).text();
|
|
334
362
|
const fences = parseClaimedFences(markdown);
|
|
335
363
|
if (fences.length === 0) {
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
const result = await checkDocDrift(fences);
|
|
342
|
-
total += fences.length;
|
|
343
|
-
if (!result.ok) {
|
|
344
|
-
ok = false;
|
|
345
|
-
messages.push(
|
|
346
|
-
`doc-drift: ${result.failures.length} failure(s) in ${label}`,
|
|
347
|
-
);
|
|
348
|
-
for (const f of result.failures) messages.push(` · ${f}`);
|
|
364
|
+
if (requireClaimed) {
|
|
365
|
+
messages.push(`doc-drift: no claimed fences found in ${label}`);
|
|
366
|
+
ok = false;
|
|
367
|
+
}
|
|
349
368
|
} else {
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
369
|
+
checkedFiles++;
|
|
370
|
+
const result = await checkDocDrift(fences);
|
|
371
|
+
total += fences.length;
|
|
372
|
+
if (!result.ok) {
|
|
373
|
+
ok = false;
|
|
374
|
+
messages.push(
|
|
375
|
+
`doc-drift: ${result.failures.length} failure(s) in ${label}`,
|
|
376
|
+
);
|
|
377
|
+
for (const f of result.failures) messages.push(` · ${f}`);
|
|
378
|
+
} else {
|
|
379
|
+
messages.push(
|
|
380
|
+
`doc-drift: ok — ${fences.length} claimed fence(s) in ${label}`,
|
|
381
|
+
);
|
|
382
|
+
}
|
|
353
383
|
}
|
|
354
384
|
|
|
355
385
|
const mermaidFences = parseMermaidFences(markdown);
|
|
@@ -370,11 +400,11 @@ export async function runDocDrift(
|
|
|
370
400
|
}
|
|
371
401
|
}
|
|
372
402
|
|
|
373
|
-
if (ok &&
|
|
403
|
+
if (ok && checkedFiles > 1) {
|
|
374
404
|
const mermaidNote =
|
|
375
405
|
mermaidTotal > 0 ? ` · ${mermaidTotal} mermaid fence(s)` : "";
|
|
376
406
|
messages.push(
|
|
377
|
-
`doc-drift: ok — ${total} claimed fence(s) across ${
|
|
407
|
+
`doc-drift: ok — ${total} claimed fence(s) across ${checkedFiles} file(s)${mermaidNote}`,
|
|
378
408
|
);
|
|
379
409
|
}
|
|
380
410
|
|
|
@@ -383,7 +413,10 @@ export async function runDocDrift(
|
|
|
383
413
|
|
|
384
414
|
async function main(): Promise<number> {
|
|
385
415
|
const args = process.argv.slice(2);
|
|
386
|
-
const paths =
|
|
416
|
+
const paths =
|
|
417
|
+
args.length > 0
|
|
418
|
+
? args
|
|
419
|
+
: [...REQUIRED_DOCS, ...(await discoverSiteDocs(ROOT))];
|
|
387
420
|
const { ok, messages } = await runDocDrift(paths);
|
|
388
421
|
for (const m of messages) {
|
|
389
422
|
if (ok) console.log(m);
|
package/src/console/index.ts
CHANGED
|
@@ -3,29 +3,41 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Built on `createClient<ConsoleApp>`. Every action is a real flow through `fx`;
|
|
5
5
|
* the audit log is the trace (docs/spec/console.md).
|
|
6
|
+
*
|
|
7
|
+
* Imports leaf modules (not `server/index`) so unused panel projectors stay out
|
|
8
|
+
* of the `okengine/console` graph when tree-shaken.
|
|
9
|
+
*
|
|
6
10
|
* @module
|
|
7
11
|
*/
|
|
8
12
|
|
|
9
13
|
export {
|
|
10
14
|
bootConsoleApp,
|
|
15
|
+
createConsoleApp,
|
|
16
|
+
type ConsoleApp,
|
|
17
|
+
type ConsoleAppHandle,
|
|
18
|
+
type CreateConsoleAppOptions,
|
|
19
|
+
} from "./server/app.ts";
|
|
20
|
+
export {
|
|
11
21
|
CLAIM_TTL_MS,
|
|
22
|
+
mintClaimCode,
|
|
23
|
+
printClaimCodeOnce,
|
|
24
|
+
verifyClaimCode,
|
|
25
|
+
} from "./server/claim.ts";
|
|
26
|
+
export { feedManifest } from "./server/live.ts";
|
|
27
|
+
export { consolePlugin } from "./server/plugin.ts";
|
|
28
|
+
export {
|
|
12
29
|
CONSOLE_COOKIES,
|
|
13
30
|
CONSOLE_CSP,
|
|
14
31
|
PLUGIN_IFRAME_SANDBOX,
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
feedManifest,
|
|
19
|
-
mintClaimCode,
|
|
20
|
-
printClaimCodeOnce,
|
|
32
|
+
withConsoleSecurityHeaders,
|
|
33
|
+
} from "./server/security-headers.ts";
|
|
34
|
+
export {
|
|
21
35
|
serveConsole,
|
|
22
36
|
startConsoleApp,
|
|
23
|
-
verifyClaimCode,
|
|
24
|
-
withConsoleSecurityHeaders,
|
|
25
|
-
type ConsoleApp,
|
|
26
|
-
type ConsoleAppHandle,
|
|
27
37
|
type ConsoleServerHandle,
|
|
28
|
-
type ConsoleState,
|
|
29
|
-
type CreateConsoleAppOptions,
|
|
30
38
|
type ServeConsoleOptions,
|
|
31
|
-
} from "./server/
|
|
39
|
+
} from "./server/serve.ts";
|
|
40
|
+
export {
|
|
41
|
+
createConsoleState,
|
|
42
|
+
type ConsoleState,
|
|
43
|
+
} from "./server/state.ts";
|
|
@@ -140,16 +140,53 @@ export async function bootConsoleApp(
|
|
|
140
140
|
if (!runs) return [];
|
|
141
141
|
return runs.all();
|
|
142
142
|
};
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
await bindManifestVaultRuntime(handle.state);
|
|
146
|
-
await bindManifestGateRuntime(handle.state);
|
|
147
|
-
await bindManifestClockRuntime(handle.state);
|
|
148
|
-
bindManifestAiRuntime(handle.state);
|
|
149
|
-
bindManifestChannelRuntime(handle.state);
|
|
143
|
+
// Element runtimes bind lazily on first panel access (see ensure* below
|
|
144
|
+
// via list* methods / bindManifest* callers) — not all seventeen at boot.
|
|
150
145
|
return handle.app;
|
|
151
146
|
}
|
|
152
147
|
|
|
148
|
+
/**
|
|
149
|
+
* Ensure Manifest-backed element runtimes for a panel are bound (idempotent).
|
|
150
|
+
*
|
|
151
|
+
* @param state - Console state
|
|
152
|
+
* @param panel - Panel id that was visited
|
|
153
|
+
*/
|
|
154
|
+
export async function ensureConsolePanelRuntimes(
|
|
155
|
+
state: ConsoleState,
|
|
156
|
+
panel:
|
|
157
|
+
| "signals"
|
|
158
|
+
| "store"
|
|
159
|
+
| "vault"
|
|
160
|
+
| "gates"
|
|
161
|
+
| "clock"
|
|
162
|
+
| "ai"
|
|
163
|
+
| "channels",
|
|
164
|
+
): Promise<void> {
|
|
165
|
+
switch (panel) {
|
|
166
|
+
case "signals":
|
|
167
|
+
await bindManifestSignalBus(state);
|
|
168
|
+
break;
|
|
169
|
+
case "store":
|
|
170
|
+
await bindManifestStoreRuntime(state);
|
|
171
|
+
break;
|
|
172
|
+
case "vault":
|
|
173
|
+
await bindManifestVaultRuntime(state);
|
|
174
|
+
break;
|
|
175
|
+
case "gates":
|
|
176
|
+
await bindManifestGateRuntime(state);
|
|
177
|
+
break;
|
|
178
|
+
case "clock":
|
|
179
|
+
await bindManifestClockRuntime(state);
|
|
180
|
+
break;
|
|
181
|
+
case "ai":
|
|
182
|
+
bindManifestAiRuntime(state);
|
|
183
|
+
break;
|
|
184
|
+
case "channels":
|
|
185
|
+
bindManifestChannelRuntime(state);
|
|
186
|
+
break;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
153
190
|
/**
|
|
154
191
|
* Bind a ChannelRuntime + console inbox from the Manifest when no host
|
|
155
192
|
* runtime is attached — Console surfaces real receipts / inbox, not mocks.
|
|
@@ -52,10 +52,13 @@ describe("claim code", () => {
|
|
|
52
52
|
|
|
53
53
|
test("prints to boot log exactly once", () => {
|
|
54
54
|
const state = mintClaimCode(() => 1);
|
|
55
|
-
const
|
|
56
|
-
printClaimCodeOnce(state, (l) =>
|
|
57
|
-
printClaimCodeOnce(state, (l) =>
|
|
58
|
-
|
|
55
|
+
const chunks: string[] = [];
|
|
56
|
+
printClaimCodeOnce(state, (l) => chunks.push(l));
|
|
57
|
+
printClaimCodeOnce(state, (l) => chunks.push(l));
|
|
58
|
+
const joined = chunks.join("");
|
|
59
|
+
expect(joined).toContain(state.code);
|
|
60
|
+
expect(joined).toContain("Claim code");
|
|
61
|
+
expect(chunks.length).toBe(1);
|
|
59
62
|
});
|
|
60
63
|
|
|
61
64
|
test("constantTimeEqual is length-safe", () => {
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* and rate-limited (console §2.5 · §10.4).
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
import { formatClaimNote } from "../../term.ts";
|
|
8
9
|
import {
|
|
9
10
|
AUTH_RATE_LIMIT,
|
|
10
11
|
AUTH_RATE_WINDOW_MS,
|
|
@@ -67,13 +68,7 @@ export function printClaimCodeOnce(
|
|
|
67
68
|
): void {
|
|
68
69
|
if (state.printed) return;
|
|
69
70
|
state.printed = true;
|
|
70
|
-
write(
|
|
71
|
-
write("┌─────────────────────────────────────────────────────────┐");
|
|
72
|
-
write("│ oke Console — first-admin claim code (expires 30 min) │");
|
|
73
|
-
write(`│ ${state.code} │`);
|
|
74
|
-
write("│ Whoever can read this log already owns the server. │");
|
|
75
|
-
write("└─────────────────────────────────────────────────────────┘");
|
|
76
|
-
write("");
|
|
71
|
+
write(formatClaimNote(state.code));
|
|
77
72
|
}
|
|
78
73
|
|
|
79
74
|
/** Result of {@link verifyClaimCode}. */
|
|
@@ -30,14 +30,10 @@ import {
|
|
|
30
30
|
} from "./clock.ts";
|
|
31
31
|
import { createFileDiff, emitStructuralDiff } from "./structural.ts";
|
|
32
32
|
import type { ConsoleState } from "./state.ts";
|
|
33
|
+
import { PUBLIC_CONSOLE_FLOWS } from "./public-flows.ts";
|
|
33
34
|
import { tenancyDeclared } from "./store.ts";
|
|
34
35
|
|
|
35
|
-
|
|
36
|
-
export const PUBLIC_CONSOLE_FLOWS = new Set([
|
|
37
|
-
"console.setup.status",
|
|
38
|
-
"console.setup.claim",
|
|
39
|
-
"console.session.login",
|
|
40
|
-
]);
|
|
36
|
+
export { PUBLIC_CONSOLE_FLOWS };
|
|
41
37
|
|
|
42
38
|
const SetupStatusOut = z.object({
|
|
43
39
|
setupClosed: z.boolean(),
|
|
@@ -30,6 +30,7 @@ export {
|
|
|
30
30
|
bindManifestVaultRuntime,
|
|
31
31
|
bootConsoleApp,
|
|
32
32
|
createConsoleApp,
|
|
33
|
+
ensureConsolePanelRuntimes,
|
|
33
34
|
type ConsoleApp,
|
|
34
35
|
type ConsoleAppHandle,
|
|
35
36
|
type CreateConsoleAppOptions,
|
|
@@ -72,8 +73,8 @@ export {
|
|
|
72
73
|
} from "./claim.ts";
|
|
73
74
|
export {
|
|
74
75
|
createConsoleBindings,
|
|
75
|
-
PUBLIC_CONSOLE_FLOWS,
|
|
76
76
|
} from "./flows.ts";
|
|
77
|
+
export { PUBLIC_CONSOLE_FLOWS } from "./public-flows.ts";
|
|
77
78
|
export {
|
|
78
79
|
createLiveWebsocket,
|
|
79
80
|
feedManifest,
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Console per-panel backends construct lazily on first access.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, expect, test } from "bun:test";
|
|
6
|
+
import { createConsoleState } from "./state.ts";
|
|
7
|
+
|
|
8
|
+
describe("console — lazy panel construction", () => {
|
|
9
|
+
test("createConsoleState constructs no panel backends", () => {
|
|
10
|
+
const state = createConsoleState({ silentClaim: true, secret: "x" });
|
|
11
|
+
expect([...state.constructedPanels]).toEqual([]);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
test("only the visited panel is constructed", async () => {
|
|
15
|
+
const state = createConsoleState({ silentClaim: true, secret: "x" });
|
|
16
|
+
expect([...state.constructedPanels]).toEqual([]);
|
|
17
|
+
|
|
18
|
+
await state.listVault();
|
|
19
|
+
expect([...state.constructedPanels]).toEqual(["vault"]);
|
|
20
|
+
|
|
21
|
+
await state.listStores();
|
|
22
|
+
expect([...state.constructedPanels].sort()).toEqual(["store", "vault"]);
|
|
23
|
+
|
|
24
|
+
await state.listVault();
|
|
25
|
+
expect([...state.constructedPanels].sort()).toEqual(["store", "vault"]);
|
|
26
|
+
});
|
|
27
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lazy Console panel module loader — expression `new URL` keeps panel
|
|
3
|
+
* backends out of the createConsoleState / createConsoleApp graph until
|
|
4
|
+
* first access (mirrors kernel boot-bind).
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/** Panel ids that own server-side projection / mutation modules. */
|
|
8
|
+
export type ConsolePanelId =
|
|
9
|
+
| "access"
|
|
10
|
+
| "gates"
|
|
11
|
+
| "signals"
|
|
12
|
+
| "store"
|
|
13
|
+
| "clock"
|
|
14
|
+
| "vault"
|
|
15
|
+
| "ai"
|
|
16
|
+
| "channels"
|
|
17
|
+
| "plugins"
|
|
18
|
+
| "diff";
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Load a Console panel module by id without bundling it into the parent.
|
|
22
|
+
*
|
|
23
|
+
* @param id - Panel module stem (`store`, `vault`, …)
|
|
24
|
+
*/
|
|
25
|
+
export async function loadConsolePanel<T>(id: ConsolePanelId): Promise<T> {
|
|
26
|
+
const url = new URL(`./${id}.ts`, import.meta.url);
|
|
27
|
+
return import(url.href) as Promise<T>;
|
|
28
|
+
}
|
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
* Never installs — hands a `bun add …` command for community packages.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import { runDoctorDiff } from "../../cli/doctor-diff.ts";
|
|
10
9
|
import {
|
|
11
10
|
allHookCostSummaries,
|
|
12
11
|
type HookCostSummary,
|
|
@@ -23,11 +22,9 @@ import {
|
|
|
23
22
|
isCorePluginOn,
|
|
24
23
|
type PluginConfigProbe,
|
|
25
24
|
} from "../../plugins/catalogue.ts";
|
|
26
|
-
import {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
type PackageJsonProbe,
|
|
30
|
-
type SupplyChainSignals,
|
|
25
|
+
import type {
|
|
26
|
+
PackageJsonProbe,
|
|
27
|
+
SupplyChainSignals,
|
|
31
28
|
} from "../../plugins/supply-chain.ts";
|
|
32
29
|
import type { ScanSourceFile } from "../../plugins/node-import-scan.ts";
|
|
33
30
|
|
|
@@ -308,6 +305,9 @@ async function buildRow(input: {
|
|
|
308
305
|
fetchNpm: input.options.fetchNpm,
|
|
309
306
|
};
|
|
310
307
|
|
|
308
|
+
const { projectSupplyChain, projectSupplyChainSync } = await import(
|
|
309
|
+
"../../plugins/supply-chain.ts"
|
|
310
|
+
);
|
|
311
311
|
const supplyChain = input.options.syncSupplyChain
|
|
312
312
|
? projectSupplyChainSync(supplyOpts)
|
|
313
313
|
: await projectSupplyChain(supplyOpts);
|
|
@@ -357,6 +357,7 @@ export async function loadCapabilityDiffByPlugin(
|
|
|
357
357
|
manifest: Manifest | null,
|
|
358
358
|
): Promise<Readonly<Record<string, readonly ManifestChange[]>>> {
|
|
359
359
|
try {
|
|
360
|
+
const { runDoctorDiff } = await import("../../cli/doctor-diff.ts");
|
|
360
361
|
const result = await runDoctorDiff({
|
|
361
362
|
cwd,
|
|
362
363
|
...(manifest ? { after: manifest } : {}),
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Console flows that may run without an operator session.
|
|
3
|
+
*
|
|
4
|
+
* Kept out of `flows.ts` so `consolePlugin` does not pull the full flow graph.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/** Public setup / session entry flows (no operator session required). */
|
|
8
|
+
export const PUBLIC_CONSOLE_FLOWS = new Set([
|
|
9
|
+
"console.setup.status",
|
|
10
|
+
"console.setup.claim",
|
|
11
|
+
"console.session.login",
|
|
12
|
+
]);
|