okengine 0.10.2 → 0.11.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/package.json +76 -10
- package/site/content/docs/ai/mcp.mdx +0 -1
- package/site/content/docs/deployment/docker-swarm.mdx +48 -111
- package/site/content/docs/deployment/docker.mdx +43 -36
- package/site/content/docs/deployment/index.mdx +9 -9
- package/site/content/docs/deployment/kubernetes.mdx +4 -4
- package/site/content/docs/elements/ai.mdx +7 -13
- package/site/content/docs/elements/channel.mdx +9 -13
- package/site/content/docs/elements/clock.mdx +8 -14
- package/site/content/docs/elements/flow.mdx +46 -54
- package/site/content/docs/elements/gate.mdx +6 -11
- package/site/content/docs/elements/signal.mdx +2 -8
- package/site/content/docs/elements/store.mdx +79 -93
- package/site/content/docs/elements/vault.mdx +89 -76
- package/site/content/docs/get-started/basic-usage.mdx +8 -14
- package/site/content/docs/get-started/installation.mdx +36 -36
- package/site/content/docs/get-started/introduction.mdx +11 -0
- package/site/content/docs/get-started/why.mdx +3 -4
- package/site/content/docs/index.mdx +0 -1
- package/site/content/docs/meta.json +0 -1
- package/site/content/docs/plugins/anonymous.mdx +1 -1
- package/site/content/docs/plugins/magic-link.mdx +11 -11
- package/site/content/docs/plugins/otp.mdx +2 -2
- package/site/content/docs/plugins/passkey.mdx +1 -1
- package/site/content/docs/plugins/two-factor.mdx +1 -1
- package/site/content/docs/plugins/username.mdx +1 -1
- package/site/content/docs/recipes/caddy.mdx +1 -1
- package/site/content/docs/recipes/cockroachdb.mdx +2 -2
- package/site/content/docs/recipes/dragonfly.mdx +1 -1
- package/site/content/docs/recipes/index.mdx +1 -2
- package/site/content/docs/recipes/llama-cpp.mdx +21 -23
- package/site/content/docs/recipes/mailpit.mdx +11 -11
- package/site/content/docs/recipes/meilisearch.mdx +10 -10
- package/site/content/docs/recipes/meta.json +0 -1
- package/site/content/docs/recipes/ollama.mdx +1 -1
- package/site/content/docs/recipes/pgdog.mdx +12 -9
- package/site/content/docs/recipes/postgres.mdx +3 -3
- package/site/content/docs/recipes/redis.mdx +2 -2
- package/site/content/docs/recipes/rustfs.mdx +10 -7
- package/site/content/docs/recipes/sglang.mdx +1 -1
- package/site/content/docs/recipes/supabase-docker.mdx +1 -1
- package/site/content/docs/recipes/timescale.mdx +2 -2
- package/site/content/docs/recipes/valkey.mdx +1 -1
- package/site/content/docs/recipes/vllm.mdx +1 -1
- package/site/content/docs/recipes/yugabytedb.mdx +2 -2
- package/site/content/docs/reference/cli.md +61 -38
- package/site/content/docs/reference/configuration.mdx +145 -70
- package/site/content/docs/reference/environment-variables.mdx +36 -28
- package/site/content/docs/reference/errors.mdx +28 -29
- package/site/content/docs/reference/fx.mdx +14 -7
- package/site/content/docs/reference/i18n.mdx +17 -6
- package/site/content/docs/reference/index.mdx +5 -0
- package/site/content/docs/reference/meta.json +1 -0
- package/site/content/docs/reference/migrating-environments.mdx +158 -0
- package/site/content/docs/reference/plugins.mdx +2 -2
- package/src/auth/gate-auth.test.ts +12 -10
- package/src/cli/ai-setup/ai-setup.test.ts +30 -16
- package/src/cli/ai-setup/apply.ts +111 -15
- package/src/cli/ai-setup/catalog.ts +3 -3
- package/src/cli/ai-setup/index.ts +1 -1
- package/src/cli/ai-setup/prompts.ts +1 -1
- package/src/cli/ai-setup/recommend.test.ts +1 -1
- package/src/cli/ask-seed.test.ts +3 -3
- package/src/cli/build.ts +8 -9
- package/src/cli/db-auto-push.test.ts +6 -3
- package/src/cli/db-auto-push.ts +7 -5
- package/src/cli/db-seed.ts +7 -8
- package/src/cli/db.test.ts +70 -71
- package/src/cli/db.ts +86 -12
- package/src/cli/dev-controller.test.ts +35 -0
- package/src/cli/dev-controller.ts +298 -0
- package/src/cli/dev-controls.ts +11 -65
- package/src/cli/dev-db-push.test.ts +47 -15
- package/src/cli/dev-schema-sync.test.ts +11 -11
- package/src/cli/dev-schema-sync.ts +10 -10
- package/src/cli/dev-session-lock.test.ts +106 -0
- package/src/cli/dev-session-lock.ts +209 -0
- package/src/cli/dev.test.ts +246 -114
- package/src/cli/dev.ts +153 -205
- package/src/cli/doc-staleness.test.ts +3 -6
- package/src/cli/docker-clean.test.ts +33 -1
- package/src/cli/docker-clean.ts +28 -33
- package/src/cli/docker-cli.test.ts +12 -11
- package/src/cli/docker.ts +95 -20
- package/src/cli/doctor.test.ts +40 -0
- package/src/cli/doctor.ts +142 -9
- package/src/cli/drizzle-env.test.ts +11 -13
- package/src/cli/drizzle-env.ts +18 -11
- package/src/cli/ensure-drizzle-config.ts +11 -14
- package/src/cli/hero-meta.test.ts +15 -15
- package/src/cli/hero-meta.ts +10 -9
- package/src/cli/index.ts +36 -6
- package/src/cli/load-config.images.test.ts +44 -10
- package/src/cli/load-config.source.test.ts +50 -0
- package/src/cli/load-config.ts +35 -29
- package/src/cli/meilisearch-local.ts +1 -2
- package/src/cli/mode.ts +7 -58
- package/src/cli/registry.ts +175 -19
- package/src/cli/resolve-dev-sql-env.test.ts +8 -16
- package/src/cli/resolve-dev-sql-env.ts +13 -15
- package/src/cli/safe-defaults.test.ts +29 -11
- package/src/cli/schema.ts +65 -16
- package/src/cli/test.ts +58 -0
- package/src/cli/tui/App.tsx +252 -0
- package/src/cli/tui/DevLive.tsx +116 -0
- package/src/cli/tui/components/ConfirmDialog.tsx +48 -0
- package/src/cli/tui/components/HeaderBar.tsx +67 -0
- package/src/cli/tui/components/LogStream.tsx +47 -0
- package/src/cli/tui/components/PanelCard.tsx +39 -0
- package/src/cli/tui/components/SelectRow.tsx +37 -0
- package/src/cli/tui/components/SlashPalette.tsx +172 -0
- package/src/cli/tui/components/Spinner.tsx +32 -0
- package/src/cli/tui/components/StatusBar.tsx +51 -0
- package/src/cli/tui/components/StatusDot.tsx +37 -0
- package/src/cli/tui/components/TabBar.tsx +49 -0
- package/src/cli/tui/components/Wordmark.tsx +43 -0
- package/src/cli/tui/format.ts +38 -0
- package/src/cli/tui/keys.test.ts +18 -0
- package/src/cli/tui/keys.ts +26 -0
- package/src/cli/tui/launch.test.ts +18 -0
- package/src/cli/tui/launch.ts +57 -0
- package/src/cli/tui/panels/Dashboard.tsx +201 -0
- package/src/cli/tui/panels/Database.tsx +198 -0
- package/src/cli/tui/panels/Dev.tsx +257 -0
- package/src/cli/tui/panels/Docker.tsx +357 -0
- package/src/cli/tui/panels/Navigator.test.ts +22 -0
- package/src/cli/tui/panels/Navigator.tsx +213 -0
- package/src/cli/tui/slash-catalog.test.ts +31 -0
- package/src/cli/tui/slash-catalog.ts +184 -0
- package/src/cli/tui/slash-run.ts +54 -0
- package/src/cli/tui/state/ports.ts +95 -0
- package/src/cli/tui/theme.ts +24 -0
- package/src/cli/vault-cmd.test.ts +402 -0
- package/src/cli/vault-cmd.ts +727 -69
- package/src/cli/vault-secure-input.test.ts +56 -0
- package/src/cli/vault-secure-input.ts +124 -0
- package/src/compiler/effects-infer.ts +7 -0
- package/src/compiler/extract.ts +12 -0
- package/src/compiler/fixtures/skyport/oke.config.ts +7 -5
- package/src/compiler/fixtures/skyport/src/flows/payments/index.ts +1 -1
- package/src/compiler/fixtures/skyport.expected.json +1 -1
- package/src/compiler/generate-adopt.ts +27 -1
- package/src/compiler-entry.ts +7 -0
- package/src/config/define-config.test.ts +111 -47
- package/src/config/driver-defaults.test.ts +115 -0
- package/src/config/driver-defaults.ts +156 -0
- package/src/config/index.ts +246 -131
- package/src/config/resolve-driver.test.ts +14 -19
- package/src/console/server/app.ts +4 -2
- package/src/console/server/console.test.ts +58 -1
- package/src/console/server/flows.ts +22 -2
- package/src/console/server/index.ts +3 -0
- package/src/console/server/operator-db.test.ts +55 -13
- package/src/console/server/operator-db.ts +305 -263
- package/src/console/server/serve.ts +16 -7
- package/src/console/server/state.ts +31 -9
- package/src/console/server/vault.test.ts +120 -5
- package/src/console/server/vault.ts +208 -12
- package/src/console/ui/dist/assets/{index-D-9KFce5.js → index--Y0Uaz-m.js} +2 -2
- package/src/console/ui/dist/assets/panel-vault-BkZdJPX8.js +1 -0
- package/src/console/ui/dist/assets/style-C3L349iZ.css +3 -0
- package/src/console/ui/dist/index.html +2 -2
- package/src/console/ui/shell/client.ts +16 -0
- package/src/console/ui/shell/panels/vault/VaultPanel.tsx +54 -1
- package/src/console/ui/vault/VaultA11yView.tsx +33 -1
- package/src/console/ui/vault/backend.test.ts +75 -0
- package/src/console/ui/vault/backend.ts +117 -0
- package/src/console/ui/vault/fixture.ts +21 -2
- package/src/console/ui/vault/index.ts +11 -1
- package/src/console/ui/vault/types.ts +26 -0
- package/src/docker/compose.ts +164 -61
- package/src/docker/derive.ts +106 -12
- package/src/docker/docker.test.ts +156 -110
- package/src/docker/helpers.ts +98 -0
- package/src/docker/images-config.test.ts +163 -0
- package/src/docker/index.ts +30 -5
- package/src/docker/recipes/index.ts +0 -3
- package/src/docker/recipes/llama-cpp.ts +4 -4
- package/src/docker/recipes/pgdog.ts +9 -2
- package/src/docker/resources.test.ts +71 -0
- package/src/docker/resources.ts +176 -0
- package/src/docker/stack-id.test.ts +11 -4
- package/src/docker/stack-id.ts +42 -32
- package/src/docker/stack.integration.test.ts +4 -15
- package/src/docker/types.ts +35 -3
- package/src/drivers/ai-ollama.integration.test.ts +2 -2
- package/src/drivers/conformance.test.ts +11 -12
- package/src/drivers/drizzle-dialect.test.ts +0 -4
- package/src/drivers/drizzle-dialect.ts +7 -13
- package/src/drivers/index.ts +24 -7
- package/src/drivers/journal-postgres.test.ts +3 -1
- package/src/drivers/journal-postgres.ts +4 -2
- package/src/drivers/meilisearch.ts +1 -1
- package/src/drivers/pglite.ts +28 -5
- package/src/drivers/types.ts +9 -11
- package/src/drivers/vault-aws-secrets-manager.test.ts +159 -0
- package/src/drivers/vault-aws-secrets-manager.ts +333 -0
- package/src/drivers/vault-builtin.test.ts +110 -0
- package/src/drivers/vault-builtin.ts +184 -0
- package/src/drivers/vault-driver-removal.test.ts +13 -0
- package/src/drivers/vault-managed.test.ts +95 -0
- package/src/drivers/vault-managed.ts +101 -25
- package/src/drivers/vault-types.ts +25 -5
- package/src/elements/ai/runtime.ts +1 -1
- package/src/elements/clock/chaos.test.ts +4 -1
- package/src/elements/clock/durable.ts +57 -4
- package/src/elements/clock.test.ts +13 -14
- package/src/elements/gate/constants.ts +18 -0
- package/src/elements/gate.test.ts +1 -1
- package/src/elements/gate.ts +2 -2
- package/src/elements/store/domain-ddl.test.ts +5 -12
- package/src/elements/store/emit-drizzle.ts +44 -19
- package/src/elements/store/index-boot.test.ts +15 -116
- package/src/elements/store/load-plugin-tables.ts +1 -1
- package/src/elements/store/resource-list-docs.fixture.ts +12 -6
- package/src/elements/store/resource-list-docs.test.ts +64 -44
- package/src/elements/store/resource.test.ts +17 -10
- package/src/elements/store/runtime.ts +9 -12
- package/src/elements/store/schema-decl.test.ts +16 -32
- package/src/elements/store/seed.test.ts +1 -2
- package/src/elements/store/seed.ts +7 -8
- package/src/elements/store/sql-condition.test.ts +2 -2
- package/src/elements/store/sql-session.test.ts +8 -10
- package/src/elements/store/sql-session.ts +10 -2
- package/src/elements/store.test.ts +13 -13
- package/src/elements/vault/audit.ts +233 -0
- package/src/elements/vault/boot-chain.test.ts +78 -0
- package/src/elements/vault/boot-chain.ts +43 -39
- package/src/elements/vault/builtin-adapter.test.ts +479 -0
- package/src/elements/vault/builtin-adapter.ts +1184 -0
- package/src/elements/vault/crypto.test.ts +237 -0
- package/src/elements/vault/crypto.ts +431 -0
- package/src/elements/vault/declare.ts +164 -3
- package/src/elements/vault/errors.ts +56 -0
- package/src/elements/vault/kms-unseal.test.ts +76 -0
- package/src/elements/vault/kms-unseal.ts +181 -0
- package/src/elements/vault/path.ts +90 -0
- package/src/elements/vault/resilience.test.ts +102 -0
- package/src/elements/vault/resilience.ts +107 -0
- package/src/elements/vault/runtime.ts +36 -4
- package/src/elements/vault/security-checklist.test.ts +130 -0
- package/src/elements/vault/storage.ts +448 -0
- package/src/elements/vault/types.ts +288 -0
- package/src/elements/vault/unseal.ts +150 -0
- package/src/elements/vault.test.ts +72 -4
- package/src/elements/vault.ts +91 -2
- package/src/full.ts +248 -0
- package/src/http.ts +41 -0
- package/src/i18n/interpolate-simple.ts +37 -0
- package/src/i18n/messages.ts +51 -4
- package/src/i18n-entry.ts +7 -0
- package/src/index.ts +35 -145
- package/src/journal-entry.ts +20 -0
- package/src/kernel/adopt-barrel-fresh.test.ts +25 -10
- package/src/kernel/app.ts +40 -42
- package/src/kernel/auto-registry.test.ts +2 -2
- package/src/kernel/boot-bind/ai.test.ts +5 -5
- package/src/kernel/boot-bind/ai.ts +2 -1
- package/src/kernel/boot-bind/channel.test.ts +6 -6
- package/src/kernel/boot-bind/channel.ts +5 -4
- package/src/kernel/boot-bind/clock.ts +5 -5
- package/src/kernel/boot-bind/gate.ts +6 -7
- package/src/kernel/boot-bind/honor-config.test.ts +42 -42
- package/src/kernel/boot-bind/journal.ts +5 -5
- package/src/kernel/boot-bind/signal.ts +3 -1
- package/src/kernel/boot-bind/store.test.ts +55 -37
- package/src/kernel/boot-bind/store.ts +24 -34
- package/src/kernel/boot-bind/vault.ts +19 -4
- package/src/kernel/boot.test.ts +12 -4
- package/src/kernel/boot.ts +31 -19
- package/src/kernel/budget-entry.ts +1 -1
- package/src/kernel/compensate.test.ts +288 -1
- package/src/kernel/compensate.ts +126 -0
- package/src/kernel/concurrency.test.ts +10 -9
- package/src/kernel/effects-stamping.test.ts +27 -2
- package/src/kernel/element-registries.ts +5 -3
- package/src/kernel/flow.ts +4 -2
- package/src/kernel/fx.test.ts +119 -3
- package/src/kernel/fx.ts +215 -40
- package/src/kernel/index.ts +14 -0
- package/src/kernel/journal.ts +130 -7
- package/src/kernel/pipeline.test.ts +20 -6
- package/src/kernel/redacted.test.ts +35 -0
- package/src/kernel/redacted.ts +24 -2
- package/src/kernel/router/create-default.ts +16 -0
- package/src/kernel/router/create-edge.ts +18 -0
- package/src/kernel/router/create.ts +23 -0
- package/src/kernel/router/index.ts +23 -0
- package/src/kernel/router/linear.ts +88 -0
- package/src/kernel/router/regexp.ts +188 -0
- package/src/kernel/router/smart.ts +120 -0
- package/src/kernel/router/trie.ts +108 -0
- package/src/kernel/router/types.ts +56 -0
- package/src/kernel/router.ts +18 -532
- package/src/kernel-entry.ts +43 -0
- package/src/manifest/fixtures/skyport.excerpt.json +1 -1
- package/src/manifest/fixtures/skyport.manifest.json +1 -1
- package/src/plugins/config-source.test.ts +7 -7
- package/src/release/build-lib.ts +58 -0
- package/src/release/exports.test.ts +4 -2
- package/src/release/exports.ts +30 -4
- package/src/release/measure.ts +101 -22
- package/src/runs/duckdb.ts +7 -2
- package/src/shared/optional-peer.ts +41 -0
- package/src/term.test.ts +3 -44
- package/src/test/create-test-app.ts +12 -0
- package/src/test/provisions.integration.test.ts +1 -1
- package/src/test/reset-element-registries.ts +2 -0
- package/src/upgrade/codemods.test.ts +7 -20
- package/src/upgrade/codemods.ts +93 -60
- package/site/content/docs/console/access.mdx +0 -29
- package/site/content/docs/console/ai.mdx +0 -35
- package/site/content/docs/console/architecture.mdx +0 -35
- package/site/content/docs/console/channels.mdx +0 -37
- package/site/content/docs/console/clock.mdx +0 -51
- package/site/content/docs/console/flows.mdx +0 -31
- package/site/content/docs/console/gates.mdx +0 -73
- package/site/content/docs/console/index.mdx +0 -54
- package/site/content/docs/console/manifest-diff.mdx +0 -34
- package/site/content/docs/console/meta.json +0 -24
- package/site/content/docs/console/overview.mdx +0 -40
- package/site/content/docs/console/plugins.mdx +0 -41
- package/site/content/docs/console/privacy.mdx +0 -32
- package/site/content/docs/console/runs.mdx +0 -50
- package/site/content/docs/console/signals.mdx +0 -40
- package/site/content/docs/console/store.mdx +0 -32
- package/site/content/docs/console/tenancy.mdx +0 -32
- package/site/content/docs/console/traces.mdx +0 -38
- package/site/content/docs/console/vault.mdx +0 -41
- package/site/content/docs/recipes/openbao.mdx +0 -141
- package/src/cli/ask-dev-mode.ts +0 -40
- package/src/cli/dev-mode.test.ts +0 -45
- package/src/cli/dev-mode.ts +0 -78
- package/src/cli/openbao-bootstrap.test.ts +0 -150
- package/src/cli/openbao-bootstrap.ts +0 -321
- package/src/cli/openbao-restart.integration.test.ts +0 -145
- package/src/console/ui/dist/assets/panel-vault-Za1GyJfM.js +0 -1
- package/src/console/ui/dist/assets/style-C8MxEWPd.css +0 -3
- package/src/docker/recipes/openbao.ts +0 -47
- package/src/drivers/libsql.ts +0 -179
- package/src/drivers/sqlite.ts +0 -44
- package/src/drivers/vault-openbao.test.ts +0 -97
- package/src/drivers/vault-openbao.ts +0 -143
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project Navigator — Manifest tree with expand/collapse.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Box, Text, useInput } from "ink";
|
|
6
|
+
import { useEffect, useState, type ReactElement } from "react";
|
|
7
|
+
import type { Manifest } from "../../../manifest/types.ts";
|
|
8
|
+
import { TUI_ACCENT, TUI_ERR, TUI_MUTED } from "../theme.ts";
|
|
9
|
+
|
|
10
|
+
/** Props for {@link NavigatorPanel}. */
|
|
11
|
+
export type NavigatorPanelProps = {
|
|
12
|
+
readonly cwd: string;
|
|
13
|
+
readonly active: boolean;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
type NavNode = {
|
|
17
|
+
readonly id: string;
|
|
18
|
+
readonly label: string;
|
|
19
|
+
readonly kind?: "category" | "item" | "meta";
|
|
20
|
+
readonly count?: number;
|
|
21
|
+
readonly children?: readonly NavNode[];
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Build a tree from a Manifest.
|
|
26
|
+
*
|
|
27
|
+
* @param manifest - Parsed/extracted manifest
|
|
28
|
+
*/
|
|
29
|
+
export function manifestToNavTree(manifest: Manifest): readonly NavNode[] {
|
|
30
|
+
const section = (title: string, record: Record<string, unknown> | undefined): NavNode => {
|
|
31
|
+
const keys = record ? Object.keys(record).sort() : [];
|
|
32
|
+
return {
|
|
33
|
+
id: title,
|
|
34
|
+
label: title,
|
|
35
|
+
kind: "category",
|
|
36
|
+
count: keys.length,
|
|
37
|
+
children: keys.map((name) => ({
|
|
38
|
+
id: `${title}:${name}`,
|
|
39
|
+
label: name,
|
|
40
|
+
kind: "item" as const,
|
|
41
|
+
})),
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const ai = manifest.ai;
|
|
46
|
+
const aiChildren: NavNode[] = [];
|
|
47
|
+
if (ai?.models) {
|
|
48
|
+
const keys = Object.keys(ai.models);
|
|
49
|
+
aiChildren.push({
|
|
50
|
+
id: "ai.models",
|
|
51
|
+
label: "models",
|
|
52
|
+
kind: "category",
|
|
53
|
+
count: keys.length,
|
|
54
|
+
children: keys.map((n) => ({ id: `ai.models:${n}`, label: n, kind: "item" })),
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
if (ai?.prompts) {
|
|
58
|
+
const keys = Object.keys(ai.prompts);
|
|
59
|
+
aiChildren.push({
|
|
60
|
+
id: "ai.prompts",
|
|
61
|
+
label: "prompts",
|
|
62
|
+
kind: "category",
|
|
63
|
+
count: keys.length,
|
|
64
|
+
children: keys.map((n) => ({ id: `ai.prompts:${n}`, label: n, kind: "item" })),
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
if (ai?.agents) {
|
|
68
|
+
const keys = Object.keys(ai.agents);
|
|
69
|
+
aiChildren.push({
|
|
70
|
+
id: "ai.agents",
|
|
71
|
+
label: "agents",
|
|
72
|
+
kind: "category",
|
|
73
|
+
count: keys.length,
|
|
74
|
+
children: keys.map((n) => ({ id: `ai.agents:${n}`, label: n, kind: "item" })),
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return [
|
|
79
|
+
{ id: "app", label: `app: ${manifest.app}`, kind: "meta" },
|
|
80
|
+
section("flows", manifest.flows as Record<string, unknown> | undefined),
|
|
81
|
+
section("signals", manifest.signals as Record<string, unknown> | undefined),
|
|
82
|
+
section("stores", manifest.stores as Record<string, unknown> | undefined),
|
|
83
|
+
section("clocks", manifest.clocks as Record<string, unknown> | undefined),
|
|
84
|
+
section("gates", manifest.gates as Record<string, unknown> | undefined),
|
|
85
|
+
section("vault", manifest.vault as Record<string, unknown> | undefined),
|
|
86
|
+
section("channels", manifest.channels as Record<string, unknown> | undefined),
|
|
87
|
+
{
|
|
88
|
+
id: "ai",
|
|
89
|
+
label: "ai",
|
|
90
|
+
kind: "category",
|
|
91
|
+
count: aiChildren.length,
|
|
92
|
+
children: aiChildren,
|
|
93
|
+
},
|
|
94
|
+
];
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Flatten tree for arrow-key navigation.
|
|
99
|
+
*
|
|
100
|
+
* @param nodes - Roots
|
|
101
|
+
* @param expanded - Expanded ids
|
|
102
|
+
*/
|
|
103
|
+
function flatten(
|
|
104
|
+
nodes: readonly NavNode[],
|
|
105
|
+
expanded: ReadonlySet<string>,
|
|
106
|
+
depth = 0,
|
|
107
|
+
): readonly { node: NavNode; depth: number }[] {
|
|
108
|
+
const out: { node: NavNode; depth: number }[] = [];
|
|
109
|
+
for (const node of nodes) {
|
|
110
|
+
out.push({ node, depth });
|
|
111
|
+
if (node.children && expanded.has(node.id)) {
|
|
112
|
+
out.push(...flatten(node.children, expanded, depth + 1));
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return out;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Manifest browser.
|
|
120
|
+
*
|
|
121
|
+
* @param props - cwd
|
|
122
|
+
*/
|
|
123
|
+
export function NavigatorPanel(props: NavigatorPanelProps): ReactElement {
|
|
124
|
+
const [tree, setTree] = useState<readonly NavNode[]>([]);
|
|
125
|
+
const [expanded, setExpanded] = useState<Set<string>>(
|
|
126
|
+
() => new Set(["flows", "signals", "stores"]),
|
|
127
|
+
);
|
|
128
|
+
const [selected, setSelected] = useState(0);
|
|
129
|
+
const [error, setError] = useState("");
|
|
130
|
+
|
|
131
|
+
useEffect(() => {
|
|
132
|
+
let cancelled = false;
|
|
133
|
+
void (async () => {
|
|
134
|
+
try {
|
|
135
|
+
const { extractManifest } = await import("../../../compiler/extract.ts");
|
|
136
|
+
const manifest = await extractManifest({ rootDir: props.cwd });
|
|
137
|
+
if (!cancelled) {
|
|
138
|
+
setTree(manifestToNavTree(manifest));
|
|
139
|
+
setError("");
|
|
140
|
+
}
|
|
141
|
+
} catch (err) {
|
|
142
|
+
if (!cancelled) setError(err instanceof Error ? err.message : String(err));
|
|
143
|
+
}
|
|
144
|
+
})();
|
|
145
|
+
return () => {
|
|
146
|
+
cancelled = true;
|
|
147
|
+
};
|
|
148
|
+
}, [props.cwd]);
|
|
149
|
+
|
|
150
|
+
const rows = flatten(tree, expanded);
|
|
151
|
+
|
|
152
|
+
const toggle = (expand: boolean | "toggle"): void => {
|
|
153
|
+
const row = rows[selected];
|
|
154
|
+
if (!row?.node.children?.length) return;
|
|
155
|
+
setExpanded((prev) => {
|
|
156
|
+
const next = new Set(prev);
|
|
157
|
+
if (expand === true) next.add(row.node.id);
|
|
158
|
+
else if (expand === false) next.delete(row.node.id);
|
|
159
|
+
else if (next.has(row.node.id)) next.delete(row.node.id);
|
|
160
|
+
else next.add(row.node.id);
|
|
161
|
+
return next;
|
|
162
|
+
});
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
useInput(
|
|
166
|
+
(_input, key) => {
|
|
167
|
+
if (!props.active) return;
|
|
168
|
+
if (key.upArrow) setSelected((i) => Math.max(0, i - 1));
|
|
169
|
+
if (key.downArrow) setSelected((i) => Math.min(Math.max(0, rows.length - 1), i + 1));
|
|
170
|
+
if (key.rightArrow) toggle(true);
|
|
171
|
+
if (key.leftArrow) toggle(false);
|
|
172
|
+
if (key.return) toggle("toggle");
|
|
173
|
+
},
|
|
174
|
+
{ isActive: props.active },
|
|
175
|
+
);
|
|
176
|
+
|
|
177
|
+
return (
|
|
178
|
+
<Box flexDirection="column" gap={0} flexGrow={1}>
|
|
179
|
+
<Text bold color={TUI_ACCENT}>
|
|
180
|
+
Project Navigator
|
|
181
|
+
</Text>
|
|
182
|
+
<Text color={TUI_MUTED} dimColor>
|
|
183
|
+
Manifest tree · ↑↓ · → expand · ← collapse · Enter toggle
|
|
184
|
+
</Text>
|
|
185
|
+
{error ? <Text color={TUI_ERR}>{error}</Text> : null}
|
|
186
|
+
{rows.map((row, i) => {
|
|
187
|
+
const hasKids = Boolean(row.node.children?.length);
|
|
188
|
+
const open = expanded.has(row.node.id);
|
|
189
|
+
const branch = hasKids ? (open ? "▾ " : "▸ ") : " ";
|
|
190
|
+
const on = props.active && i === selected;
|
|
191
|
+
const isCategory = row.node.kind === "category";
|
|
192
|
+
return (
|
|
193
|
+
<Text
|
|
194
|
+
key={row.node.id}
|
|
195
|
+
bold={on || isCategory}
|
|
196
|
+
color={on ? TUI_ACCENT : isCategory ? TUI_ACCENT : undefined}
|
|
197
|
+
>
|
|
198
|
+
{" ".repeat(row.depth)}
|
|
199
|
+
{on ? "› " : " "}
|
|
200
|
+
{branch}
|
|
201
|
+
{row.node.label}
|
|
202
|
+
{typeof row.node.count === "number" ? (
|
|
203
|
+
<Text color={TUI_MUTED}>{` (${row.node.count})`}</Text>
|
|
204
|
+
) : null}
|
|
205
|
+
</Text>
|
|
206
|
+
);
|
|
207
|
+
})}
|
|
208
|
+
{rows.length === 0 && !error ? (
|
|
209
|
+
<Text color={TUI_MUTED}>Loading Manifest… extract from src/ or oke.manifest.json</Text>
|
|
210
|
+
) : null}
|
|
211
|
+
</Box>
|
|
212
|
+
);
|
|
213
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import { commonPrefix, filterSlashActions, parseSlashArgv, slashCatalog } from "./slash-catalog.ts";
|
|
3
|
+
|
|
4
|
+
describe("slashCatalog", () => {
|
|
5
|
+
test("includes panel jumps and core cli commands", () => {
|
|
6
|
+
const all = slashCatalog();
|
|
7
|
+
expect(all.some((a) => a.id === "panel dashboard")).toBe(true);
|
|
8
|
+
expect(all.some((a) => a.id === "dev")).toBe(true);
|
|
9
|
+
expect(all.some((a) => a.id === "db push")).toBe(true);
|
|
10
|
+
expect(all.some((a) => a.id === "db studio")).toBe(true);
|
|
11
|
+
expect(all.some((a) => a.id === "doctor")).toBe(true);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
test("filterSlashActions prefixes db", () => {
|
|
15
|
+
const hits = filterSlashActions("db", 20);
|
|
16
|
+
expect(hits.length).toBeGreaterThan(0);
|
|
17
|
+
expect(hits.every((h) => h.id.includes("db") || h.summary.toLowerCase().includes("db"))).toBe(
|
|
18
|
+
true,
|
|
19
|
+
);
|
|
20
|
+
expect(hits[0]?.id.startsWith("db")).toBe(true);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test("filterSlashActions empty returns top slice", () => {
|
|
24
|
+
expect(filterSlashActions("", 5)).toHaveLength(5);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test("commonPrefix and parseSlashArgv", () => {
|
|
28
|
+
expect(commonPrefix(["db push", "db studio", "db seed"])).toBe("db ");
|
|
29
|
+
expect(parseSlashArgv(" db push ")).toEqual(["db", "push"]);
|
|
30
|
+
});
|
|
31
|
+
});
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Flattened slash-command catalogue — TUI jumps + full `oke` CLI surface.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { OKE_COMMANDS, type CliCommand } from "../registry.ts";
|
|
6
|
+
|
|
7
|
+
/** Kind of slash action. */
|
|
8
|
+
export type SlashKind = "panel" | "cli";
|
|
9
|
+
|
|
10
|
+
/** One autofill / runnable slash entry. */
|
|
11
|
+
export type SlashAction = {
|
|
12
|
+
/** Canonical command after `/` (e.g. `db push`, `dev`, `panel dashboard`). */
|
|
13
|
+
readonly id: string;
|
|
14
|
+
/** Display label (usually same as id). */
|
|
15
|
+
readonly label: string;
|
|
16
|
+
readonly summary: string;
|
|
17
|
+
readonly kind: SlashKind;
|
|
18
|
+
/** Args after `oke` for CLI actions. */
|
|
19
|
+
readonly argv?: readonly string[];
|
|
20
|
+
/** Panel id for TUI jumps. */
|
|
21
|
+
readonly panel?: string;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const PANEL_JUMPS: readonly SlashAction[] = [
|
|
25
|
+
{
|
|
26
|
+
id: "panel dashboard",
|
|
27
|
+
label: "panel dashboard",
|
|
28
|
+
summary: "Jump to Dashboard",
|
|
29
|
+
kind: "panel",
|
|
30
|
+
panel: "dashboard",
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
id: "panel dev",
|
|
34
|
+
label: "panel dev",
|
|
35
|
+
summary: "Jump to Dev",
|
|
36
|
+
kind: "panel",
|
|
37
|
+
panel: "dev",
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
id: "panel database",
|
|
41
|
+
label: "panel database",
|
|
42
|
+
summary: "Jump to Database",
|
|
43
|
+
kind: "panel",
|
|
44
|
+
panel: "database",
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
id: "panel docker",
|
|
48
|
+
label: "panel docker",
|
|
49
|
+
summary: "Jump to Docker",
|
|
50
|
+
kind: "panel",
|
|
51
|
+
panel: "docker",
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
id: "panel navigator",
|
|
55
|
+
label: "panel navigator",
|
|
56
|
+
summary: "Jump to Navigator",
|
|
57
|
+
kind: "panel",
|
|
58
|
+
panel: "navigator",
|
|
59
|
+
},
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Expand a registry command into slash actions (leaf + each subcommand).
|
|
64
|
+
*
|
|
65
|
+
* @param cmd - Registry command
|
|
66
|
+
*/
|
|
67
|
+
function expandCommand(cmd: CliCommand): readonly SlashAction[] {
|
|
68
|
+
const out: SlashAction[] = [];
|
|
69
|
+
if (cmd.leaf || !cmd.subcommands?.length) {
|
|
70
|
+
out.push({
|
|
71
|
+
id: cmd.name,
|
|
72
|
+
label: cmd.name,
|
|
73
|
+
summary: cmd.summary,
|
|
74
|
+
kind: "cli",
|
|
75
|
+
argv: [cmd.name],
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
if (cmd.subcommands) {
|
|
79
|
+
for (const sub of cmd.subcommands) {
|
|
80
|
+
// Nested like vault key rotate — positionals may be more tokens.
|
|
81
|
+
const pos = sub.positionals?.trim();
|
|
82
|
+
const base = `${cmd.name} ${sub.name}`;
|
|
83
|
+
out.push({
|
|
84
|
+
id: base,
|
|
85
|
+
label: base,
|
|
86
|
+
summary: sub.summary,
|
|
87
|
+
kind: "cli",
|
|
88
|
+
argv: [cmd.name, sub.name],
|
|
89
|
+
});
|
|
90
|
+
// Offer common nested positionals as separate autofill stubs when they
|
|
91
|
+
// look like literal tokens (not <placeholders>).
|
|
92
|
+
if (pos && !pos.includes("<") && !pos.includes("[")) {
|
|
93
|
+
const tokens = pos.split(/\s+/).filter(Boolean);
|
|
94
|
+
out.push({
|
|
95
|
+
id: `${base} ${tokens.join(" ")}`,
|
|
96
|
+
label: `${base} ${tokens.join(" ")}`,
|
|
97
|
+
summary: sub.summary,
|
|
98
|
+
kind: "cli",
|
|
99
|
+
argv: [cmd.name, sub.name, ...tokens],
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return out;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
let cached: readonly SlashAction[] | undefined;
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Full slash catalogue (panels + every registry command/subcommand).
|
|
111
|
+
*/
|
|
112
|
+
export function slashCatalog(): readonly SlashAction[] {
|
|
113
|
+
if (cached) return cached;
|
|
114
|
+
const cli = OKE_COMMANDS.flatMap((c) => expandCommand(c));
|
|
115
|
+
// Prefer panel jumps + high-traffic commands near the top for empty query.
|
|
116
|
+
cached = [...PANEL_JUMPS, ...cli];
|
|
117
|
+
return cached;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Score + filter catalogue entries for autofill.
|
|
122
|
+
*
|
|
123
|
+
* Matching: prefix on id, then substring, then word-prefix. Case-insensitive.
|
|
124
|
+
*
|
|
125
|
+
* @param query - Text after `/` (no leading slash)
|
|
126
|
+
* @param limit - Max suggestions
|
|
127
|
+
*/
|
|
128
|
+
export function filterSlashActions(query: string, limit: number = 12): readonly SlashAction[] {
|
|
129
|
+
const q = query.trim().toLowerCase();
|
|
130
|
+
const all = slashCatalog();
|
|
131
|
+
if (q.length === 0) {
|
|
132
|
+
return all.slice(0, limit);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
type Ranked = { readonly action: SlashAction; readonly score: number };
|
|
136
|
+
const ranked: Ranked[] = [];
|
|
137
|
+
for (const action of all) {
|
|
138
|
+
const id = action.id.toLowerCase();
|
|
139
|
+
const summary = action.summary.toLowerCase();
|
|
140
|
+
let score = -1;
|
|
141
|
+
if (id === q) score = 1000;
|
|
142
|
+
else if (id.startsWith(q)) score = 800 - id.length;
|
|
143
|
+
else if (id.includes(` ${q}`) || id.includes(q)) score = 500 - id.indexOf(q);
|
|
144
|
+
else if (summary.includes(q)) score = 200;
|
|
145
|
+
else {
|
|
146
|
+
// Word-prefix: every query token starts a word in id
|
|
147
|
+
const words = id.split(/[\s:/._-]+/);
|
|
148
|
+
const tokens = q.split(/\s+/).filter(Boolean);
|
|
149
|
+
if (tokens.length > 0 && tokens.every((t) => words.some((w) => w.startsWith(t)))) {
|
|
150
|
+
score = 400;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
if (score >= 0) ranked.push({ action, score });
|
|
154
|
+
}
|
|
155
|
+
ranked.sort((a, b) => b.score - a.score || a.action.id.localeCompare(b.action.id));
|
|
156
|
+
return ranked.slice(0, limit).map((r) => r.action);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Longest common prefix among suggestion ids (for Tab autofill).
|
|
161
|
+
*
|
|
162
|
+
* @param ids - Candidate labels
|
|
163
|
+
*/
|
|
164
|
+
export function commonPrefix(ids: readonly string[]): string {
|
|
165
|
+
if (ids.length === 0) return "";
|
|
166
|
+
let prefix = ids[0]!;
|
|
167
|
+
for (let i = 1; i < ids.length; i++) {
|
|
168
|
+
const s = ids[i]!;
|
|
169
|
+
let j = 0;
|
|
170
|
+
while (j < prefix.length && j < s.length && prefix[j] === s[j]) j++;
|
|
171
|
+
prefix = prefix.slice(0, j);
|
|
172
|
+
if (prefix.length === 0) break;
|
|
173
|
+
}
|
|
174
|
+
return prefix;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Parse free-typed slash input into argv after `oke`.
|
|
179
|
+
*
|
|
180
|
+
* @param raw - Text after `/`
|
|
181
|
+
*/
|
|
182
|
+
export function parseSlashArgv(raw: string): readonly string[] {
|
|
183
|
+
return raw.trim().split(/\s+/).filter(Boolean);
|
|
184
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Execute a slash CLI action — spawn `oke` with full argv, stream into logs.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { resolve } from "node:path";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Run `oke <argv…>` in `cwd`, appending stdout/stderr lines via `onLog`.
|
|
9
|
+
*
|
|
10
|
+
* @param cwd - Project root
|
|
11
|
+
* @param argv - Args after `oke`
|
|
12
|
+
* @param onLog - Log sink
|
|
13
|
+
*/
|
|
14
|
+
export async function runSlashCli(
|
|
15
|
+
cwd: string,
|
|
16
|
+
argv: readonly string[],
|
|
17
|
+
onLog: (line: string) => void,
|
|
18
|
+
): Promise<number> {
|
|
19
|
+
const cliEntry = resolve(import.meta.dir, "../index.ts");
|
|
20
|
+
onLog(`$ oke ${argv.join(" ")}\n`);
|
|
21
|
+
|
|
22
|
+
// Prefer in-repo entry so local TUI always hits this checkout.
|
|
23
|
+
const proc = Bun.spawn(["bun", cliEntry, ...argv], {
|
|
24
|
+
cwd,
|
|
25
|
+
stdout: "pipe",
|
|
26
|
+
stderr: "pipe",
|
|
27
|
+
env: {
|
|
28
|
+
...process.env,
|
|
29
|
+
// Force non-interactive child (no nested TUI).
|
|
30
|
+
OKE_NO_TUI: "1",
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const pump = async (stream: ReadableStream<Uint8Array> | null): Promise<void> => {
|
|
35
|
+
if (!stream) return;
|
|
36
|
+
const reader = stream.getReader();
|
|
37
|
+
const dec = new TextDecoder();
|
|
38
|
+
let buf = "";
|
|
39
|
+
for (;;) {
|
|
40
|
+
const { done, value } = await reader.read();
|
|
41
|
+
if (done) break;
|
|
42
|
+
buf += dec.decode(value, { stream: true });
|
|
43
|
+
const parts = buf.split("\n");
|
|
44
|
+
buf = parts.pop() ?? "";
|
|
45
|
+
for (const line of parts) onLog(`${line}\n`);
|
|
46
|
+
}
|
|
47
|
+
if (buf.length > 0) onLog(`${buf}\n`);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
await Promise.all([pump(proc.stdout), pump(proc.stderr)]);
|
|
51
|
+
const code = await proc.exited;
|
|
52
|
+
onLog(code === 0 ? `✓ exit ${code}\n` : `✗ exit ${code}\n`);
|
|
53
|
+
return code;
|
|
54
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Poll preferred OKE ports for the Dashboard.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { APP_PORT, CONSOLE_PORT, DOCS_MCP_PORT, MCP_PORT } from "../../../runtime/types.ts";
|
|
6
|
+
import type { DevStatus } from "../../../term.ts";
|
|
7
|
+
import { isPortInUse } from "../../ports.ts";
|
|
8
|
+
import {
|
|
9
|
+
type DevOwnership,
|
|
10
|
+
type DevSessionPorts,
|
|
11
|
+
resolveDevOwnership,
|
|
12
|
+
} from "../../dev-session-lock.ts";
|
|
13
|
+
|
|
14
|
+
/** One surface row on the dashboard. */
|
|
15
|
+
export type SurfaceStatus = {
|
|
16
|
+
readonly id: "app" | "console" | "mcp" | "docsMcp";
|
|
17
|
+
readonly label: string;
|
|
18
|
+
readonly port: number;
|
|
19
|
+
readonly status: DevStatus;
|
|
20
|
+
readonly url: string;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/** Snapshot for Dashboard / Dev panel. */
|
|
24
|
+
export type PortSnapshot = {
|
|
25
|
+
readonly ownership: DevOwnership;
|
|
26
|
+
readonly surfaces: readonly SurfaceStatus[];
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Preferred ports (config overrides later if needed).
|
|
31
|
+
*
|
|
32
|
+
* @param cwd - Project root
|
|
33
|
+
*/
|
|
34
|
+
export async function pollPortSnapshot(
|
|
35
|
+
cwd: string,
|
|
36
|
+
preferred: DevSessionPorts = {
|
|
37
|
+
app: APP_PORT,
|
|
38
|
+
console: CONSOLE_PORT,
|
|
39
|
+
mcp: MCP_PORT,
|
|
40
|
+
docsMcp: DOCS_MCP_PORT,
|
|
41
|
+
},
|
|
42
|
+
): Promise<PortSnapshot> {
|
|
43
|
+
const { ownership, lock, busy } = await resolveDevOwnership(cwd, preferred);
|
|
44
|
+
const ports = lock?.ports ?? preferred;
|
|
45
|
+
const toStatus = (busyPort: boolean): DevStatus => (busyPort ? "ready" : "idle");
|
|
46
|
+
return {
|
|
47
|
+
ownership,
|
|
48
|
+
surfaces: [
|
|
49
|
+
{
|
|
50
|
+
id: "app",
|
|
51
|
+
label: "App",
|
|
52
|
+
port: ports.app,
|
|
53
|
+
status: toStatus(busy.app),
|
|
54
|
+
url: `http://127.0.0.1:${ports.app}`,
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
id: "console",
|
|
58
|
+
label: "Console",
|
|
59
|
+
port: ports.console,
|
|
60
|
+
status: toStatus(busy.console),
|
|
61
|
+
url: `http://127.0.0.1:${ports.console}`,
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
id: "mcp",
|
|
65
|
+
label: "MCP",
|
|
66
|
+
port: ports.mcp,
|
|
67
|
+
status: toStatus(busy.mcp),
|
|
68
|
+
url: `http://127.0.0.1:${ports.mcp}`,
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
id: "docsMcp",
|
|
72
|
+
label: "Docs MCP",
|
|
73
|
+
port: ports.docsMcp,
|
|
74
|
+
status: toStatus(busy.docsMcp),
|
|
75
|
+
url: `http://127.0.0.1:${ports.docsMcp}`,
|
|
76
|
+
},
|
|
77
|
+
],
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Light HTTP probe — upgrades idle→error when port open but not answering.
|
|
83
|
+
*
|
|
84
|
+
* @param url - Base URL
|
|
85
|
+
*/
|
|
86
|
+
export async function probeHttpOk(url: string): Promise<boolean> {
|
|
87
|
+
try {
|
|
88
|
+
const res = await fetch(url, { signal: AbortSignal.timeout(800) });
|
|
89
|
+
return res.status < 500;
|
|
90
|
+
} catch {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export { isPortInUse };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Ink color tokens — aligned with `oke dev` green brand.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/** Brand / logo / active tab (matches oke dev wordmark). */
|
|
6
|
+
export const TUI_BRAND = "green" as const;
|
|
7
|
+
|
|
8
|
+
/** Focused rows, panel titles, links. */
|
|
9
|
+
export const TUI_ACCENT = "cyan" as const;
|
|
10
|
+
|
|
11
|
+
/** Online / success / managed. */
|
|
12
|
+
export const TUI_OK = "green" as const;
|
|
13
|
+
|
|
14
|
+
/** Offline / error. */
|
|
15
|
+
export const TUI_ERR = "red" as const;
|
|
16
|
+
|
|
17
|
+
/** Warning / destructive / pending. */
|
|
18
|
+
export const TUI_WARN = "yellow" as const;
|
|
19
|
+
|
|
20
|
+
/** Chrome borders, inactive text. */
|
|
21
|
+
export const TUI_MUTED = "gray" as const;
|
|
22
|
+
|
|
23
|
+
/** Shortcut hints. */
|
|
24
|
+
export const TUI_HINT = "yellow" as const;
|