okengine 0.22.0 → 0.23.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 +7 -0
- package/manifest.v1.schema.json +44 -0
- package/package.json +32 -19
- package/site/content/docs/ai/mcp.mdx +13 -9
- package/site/content/docs/ai/skills.mdx +1 -1
- package/site/content/docs/elements/ai/agents.mdx +61 -13
- package/site/content/docs/elements/ai/decide.mdx +536 -0
- package/site/content/docs/elements/ai/events.mdx +373 -0
- package/site/content/docs/elements/ai/index.mdx +9 -3
- package/site/content/docs/elements/ai/meta.json +1 -1
- package/site/content/docs/elements/ai/prompts.mdx +4 -2
- package/site/content/docs/elements/gate/auth.mdx +4 -1
- package/site/content/docs/elements/store/index.mdx +1 -1
- package/site/content/docs/elements/store/kv.mdx +5 -5
- package/site/content/docs/recipes/dragonfly.mdx +5 -5
- package/site/content/docs/recipes/index.mdx +6 -6
- package/site/content/docs/recipes/postgres.mdx +12 -8
- package/site/content/docs/recipes/redis.mdx +4 -4
- package/site/content/docs/reference/cli.mdx +2 -1
- package/site/content/docs/reference/configuration.mdx +9 -7
- package/site/content/docs/reference/fx.mdx +7 -6
- package/src/auth/api-key-sql.test.ts +44 -0
- package/src/auth/api-key-sql.ts +1 -0
- package/src/auth/api-keys.ts +30 -12
- package/src/auth/config.ts +6 -2
- package/src/auth/gate-auth.test.ts +20 -0
- package/src/cli/agents-md.test.ts +25 -0
- package/src/cli/ask-vault-gaps.test.ts +38 -1
- package/src/cli/ask-vault-gaps.ts +35 -2
- package/src/cli/decide.ts +174 -0
- package/src/cli/decision-lock-watch.test.ts +45 -0
- package/src/cli/decision-lock-watch.ts +51 -0
- package/src/cli/dev-app-runner.ts +34 -8
- package/src/cli/dev-auth-secret.test.ts +49 -0
- package/src/cli/dev-auth-secret.ts +49 -0
- package/src/cli/dev-hot.test.ts +41 -0
- package/src/cli/dev-hot.ts +48 -0
- package/src/cli/dev.test.ts +1 -1
- package/src/cli/dev.ts +24 -6
- package/src/cli/eval.ts +142 -1
- package/src/cli/index.ts +5 -0
- package/src/cli/load-config.images.test.ts +2 -2
- package/src/cli/load-config.ts +1 -1
- package/src/cli/mcp-from-console.ts +48 -0
- package/src/cli/registry.ts +35 -1
- package/src/client/agent.ts +307 -0
- package/src/client/transport.test.ts +20 -0
- package/src/client/transport.ts +2 -1
- package/src/client/types.ts +1 -1
- package/src/client-react/index.ts +7 -1
- package/src/client-react/use-agent-run.test.ts +271 -0
- package/src/client-react/use-agent-run.ts +193 -0
- package/src/compiler/ai-approval.test.ts +36 -0
- package/src/compiler/ai-repair.test.ts +22 -0
- package/src/compiler/decisions.extract.test.ts +164 -0
- package/src/compiler/effects-infer.ts +27 -1
- package/src/compiler/extract.ts +268 -12
- package/src/compiler/response.ts +35 -2
- package/src/config/index.ts +21 -3
- package/src/console/server/ai-runs-flows.ts +269 -0
- package/src/console/server/ai-runs.test.ts +323 -0
- package/src/console/server/ai-runs.ts +562 -0
- package/src/console/server/ai.ts +12 -1
- package/src/console/server/app.ts +10 -1
- package/src/console/server/decisions-flows.ts +157 -0
- package/src/console/server/decisions.test.ts +66 -0
- package/src/console/server/decisions.ts +229 -0
- package/src/console/server/flows.ts +50 -2
- package/src/console/server/invoke-user-flow.ts +9 -0
- package/src/console/server/runs-ingest.ts +16 -0
- package/src/console/server/serve.ts +5 -0
- package/src/console/server/state.ts +25 -1
- package/src/console/server/store-stats.test.ts +47 -0
- package/src/console/server/store-stats.ts +92 -18
- package/src/console/ui-next/dist/assets/access-page-DDKkhT9v.js +4 -0
- package/src/console/ui-next/dist/assets/{agent-disclosure-Bkohc_8X.js → agent-disclosure-62Xts8Xi.js} +1 -1
- package/src/console/ui-next/dist/assets/{cache-glyph-rL0lHxat.js → cache-glyph-DyeoKHKA.js} +1 -1
- package/src/console/ui-next/dist/assets/{call-pii-button-Deo4PP18.js → call-pii-button-DvfpLXsU.js} +1 -1
- package/src/console/ui-next/dist/assets/{collapsible-CoJ6amHf.js → collapsible-BY03SeCg.js} +1 -1
- package/src/console/ui-next/dist/assets/confirm-sheet-DZfuJXP4.js +1 -0
- package/src/console/ui-next/dist/assets/copy-inline-button-BTjPVjRT.js +1 -0
- package/src/console/ui-next/dist/assets/decisions-page-CgkKlA56.js +1 -0
- package/src/console/ui-next/dist/assets/detail-header-Dk5LipF6.js +1 -0
- package/src/console/ui-next/dist/assets/dropdown-menu-CRGrj5JU.js +1 -0
- package/src/console/ui-next/dist/assets/duration-tone-Y6HLjyJ5.js +9 -0
- package/src/console/ui-next/dist/assets/element-icons-C6t8Vlml.js +1 -0
- package/src/console/ui-next/dist/assets/explorer-chrome-Dslh2yE8.js +1 -0
- package/src/console/ui-next/dist/assets/explorer-empty-CIVg7Jgb.js +1 -0
- package/src/console/ui-next/dist/assets/flows-page-DLPfNy-_.js +1 -0
- package/src/console/ui-next/dist/assets/{highlighted-json-CPYBzDh0.js → highlighted-json-D7nNzpgB.js} +1 -1
- package/src/console/ui-next/dist/assets/{http-method-DTPevKmM.js → http-method-DdL19zzh.js} +1 -1
- package/src/console/ui-next/dist/assets/index-BlrN49Hs.css +2 -0
- package/src/console/ui-next/dist/assets/index-C0lc_s9d.js +58 -0
- package/src/console/ui-next/dist/assets/observability-page-CRlcyLCC.js +8 -0
- package/src/console/ui-next/dist/assets/{replica-lag-BM27lXld.js → replica-lag-Bb3FWUu9.js} +7 -7
- package/src/console/ui-next/dist/assets/request-meta-DYBMWhX8.js +1 -0
- package/src/console/ui-next/dist/assets/shortcut-keys-DTE1sjTC.js +1 -0
- package/src/console/ui-next/dist/assets/store-page-CcE-SXC8.js +41 -0
- package/src/console/ui-next/dist/assets/trace-detail-sheet-CKMSEQ4s.js +2 -0
- package/src/console/ui-next/dist/assets/tree-expand-toggle-QOfk0M0H.js +55 -0
- package/src/console/ui-next/dist/assets/units-page-DKC1CDDd.js +1 -0
- package/src/console/ui-next/dist/assets/use-vault-list-BAyQG8Re.js +1 -0
- package/src/console/ui-next/dist/assets/vault-page-B54v4Yit.js +2 -0
- package/src/console/ui-next/dist/index.html +4 -3
- package/src/console/ui-next/seed-parked-approval.ts +126 -0
- package/src/console/ui-next/src/client.ts +224 -1
- package/src/console/ui-next/src/components/explorer/detail-header.tsx +9 -0
- package/src/console/ui-next/src/components/explorer/explorer-start-toggle.tsx +5 -1
- package/src/console/ui-next/src/components/ui/sheet-form.tsx +21 -12
- package/src/console/ui-next/src/features/flows/decisions/decisions-page.tsx +216 -0
- package/src/console/ui-next/src/features/flows/decisions/resolve.test.ts +48 -0
- package/src/console/ui-next/src/features/flows/decisions/resolve.ts +111 -0
- package/src/console/ui-next/src/features/flows/flows-page.tsx +10 -0
- package/src/console/ui-next/src/features/flows/graph/element-map.ts +1 -0
- package/src/console/ui-next/src/features/flows/traces/effect-kind.ts +6 -0
- package/src/console/ui-next/src/features/flows/traces/effect-summary.test.ts +24 -0
- package/src/console/ui-next/src/features/flows/traces/effect-summary.ts +24 -0
- package/src/console/ui-next/src/features/flows/traces/http-status.ts +58 -0
- package/src/console/ui-next/src/features/flows/traces/request-client-card.tsx +355 -0
- package/src/console/ui-next/src/features/flows/traces/request-client.test.ts +114 -0
- package/src/console/ui-next/src/features/flows/traces/request-client.ts +423 -0
- package/src/console/ui-next/src/features/flows/traces/request-input-view.test.ts +52 -6
- package/src/console/ui-next/src/features/flows/traces/request-input-view.ts +85 -19
- package/src/console/ui-next/src/features/flows/traces/trace-detail-sheet.tsx +505 -80
- package/src/console/ui-next/src/features/flows/traces/trace-lanes.test.ts +61 -0
- package/src/console/ui-next/src/features/flows/traces/trace-lanes.ts +78 -0
- package/src/console/ui-next/src/features/flows/traces/trace-nav.test.ts +48 -0
- package/src/console/ui-next/src/features/flows/traces/trace-nav.ts +57 -0
- package/src/console/ui-next/src/features/flows/traces/trace-request-section.tsx +275 -96
- package/src/console/ui-next/src/features/flows/traces/traces-pane.tsx +16 -2
- package/src/console/ui-next/src/features/observability/detail/ai-runs.tsx +369 -0
- package/src/console/ui-next/src/features/observability/observability-page.tsx +31 -1
- package/src/console/ui-next/src/features/observability/state/observability-selection.ts +18 -3
- package/src/console/ui-next/src/features/store/performance/kv-performance-panel.tsx +12 -1
- package/src/console/ui-next/src/features/store/performance/performance-panel.tsx +14 -1
- package/src/console/ui-next/src/features/units/call/call-api-panel.tsx +1 -1
- package/src/console/ui-next/src/features/units/detail/flow-contract-panel.tsx +6 -2
- package/src/console/ui-next/src/features/units/explorer/units-tree.tsx +73 -18
- package/src/console/ui-next/src/features/units/lib/unit-tree.test.ts +21 -0
- package/src/console/ui-next/src/features/units/lib/unit-tree.ts +82 -0
- package/src/console/ui-next/src/features/units/units-page.tsx +25 -7
- package/src/console/ui-next/src/router.tsx +17 -0
- package/src/console/ui-next/ui-next-seed-runs.ts +23 -0
- package/src/console/ui-next/vite-console-kernel-plugin.ts +43 -3
- package/src/console/ui-next/vite.config.ts +9 -0
- package/src/docker/recipes/dragonfly.ts +3 -2
- package/src/docker/recipes/redis.ts +1 -1
- package/src/drivers/ai-anthropic.ts +212 -21
- package/src/drivers/ai-mock.ts +34 -1
- package/src/drivers/ai-openai-compatible.ts +67 -26
- package/src/drivers/ai-preconnect.ts +18 -0
- package/src/drivers/ai-stream.test.ts +62 -0
- package/src/drivers/ai-types.ts +20 -0
- package/src/drivers/journal-postgres.ts +289 -2
- package/src/drivers/memory-ddl.test.ts +18 -0
- package/src/drivers/memory.ts +21 -1
- package/src/drivers/pg-rls.test.ts +31 -0
- package/src/drivers/pg-rls.ts +15 -0
- package/src/drivers/postgres.test.ts +9 -0
- package/src/drivers/postgres.ts +49 -11
- package/src/elements/ai/agent-event-slot.ts +27 -0
- package/src/elements/ai/approval-http.ts +207 -0
- package/src/elements/ai/approval.test.ts +741 -0
- package/src/elements/ai/approval.ts +228 -0
- package/src/elements/ai/decisions/bind.ts +163 -0
- package/src/elements/ai/decisions/certificate.test.ts +291 -0
- package/src/elements/ai/decisions/certificate.ts +377 -0
- package/src/elements/ai/decisions/certify.ts +314 -0
- package/src/elements/ai/decisions/decide.test.ts +953 -0
- package/src/elements/ai/decisions/e2e.test.ts +399 -0
- package/src/elements/ai/decisions/export.test.ts +120 -0
- package/src/elements/ai/decisions/export.ts +146 -0
- package/src/elements/ai/decisions/fixtures/openrouter-request.json +24 -0
- package/src/elements/ai/decisions/fixtures/openrouter-response.json +22 -0
- package/src/elements/ai/decisions/fixtures/typesafe-request.json +19 -0
- package/src/elements/ai/decisions/fixtures/typesafe-response.json +13 -0
- package/src/elements/ai/decisions/http.test.ts +154 -0
- package/src/elements/ai/decisions/http.ts +240 -0
- package/src/elements/ai/decisions/labels.test.ts +282 -0
- package/src/elements/ai/decisions/labels.ts +257 -0
- package/src/elements/ai/decisions/openrouter.live.test.ts +136 -0
- package/src/elements/ai/decisions/openrouter.ts +36 -0
- package/src/elements/ai/decisions/provider.ts +102 -0
- package/src/elements/ai/decisions/typesafe.ts +36 -0
- package/src/elements/ai/declare.ts +252 -1
- package/src/elements/ai/events.test.ts +379 -0
- package/src/elements/ai/events.ts +138 -0
- package/src/elements/ai/run-events.test.ts +461 -0
- package/src/elements/ai/run-events.ts +522 -0
- package/src/elements/ai/runtime.ts +1186 -105
- package/src/elements/ai/stream-turn.ts +214 -0
- package/src/elements/ai/stream.live.test.ts +76 -0
- package/src/elements/ai/subagent.test.ts +136 -0
- package/src/elements/ai.test.ts +497 -3
- package/src/elements/ai.ts +16 -1
- package/src/elements/clock/durable.ts +27 -1
- package/src/elements/store/sql-session.test.ts +51 -0
- package/src/elements/store/sql-session.ts +111 -1
- package/src/i18n/catalogs/ar.ts +5 -0
- package/src/i18n/catalogs/en.ts +5 -0
- package/src/index.ts +2 -0
- package/src/kernel/agent-event-store.ts +448 -0
- package/src/kernel/app.ts +103 -1
- package/src/kernel/boot-bind/ai.ts +3 -0
- package/src/kernel/boot-bind/store.test.ts +26 -0
- package/src/kernel/boot-bind/store.ts +82 -6
- package/src/kernel/boot.ts +15 -4
- package/src/kernel/builtin-errors.ts +2 -0
- package/src/kernel/capability.ts +3 -0
- package/src/kernel/decision-label-store.ts +441 -0
- package/src/kernel/effects.test.ts +2 -1
- package/src/kernel/effects.ts +13 -1
- package/src/kernel/element-registries.ts +3 -0
- package/src/kernel/errors-text.ts +4 -0
- package/src/kernel/errors.ts +2 -0
- package/src/kernel/flow.test.ts +2 -3
- package/src/kernel/fx-decide.ts +761 -0
- package/src/kernel/fx.test.ts +12 -5
- package/src/kernel/fx.ts +312 -29
- package/src/kernel/http-frame.test.ts +94 -0
- package/src/kernel/http-frame.ts +203 -0
- package/src/kernel/journal.ts +104 -0
- package/src/kernel/json-result.ts +10 -0
- package/src/kernel/pipeline.test.ts +45 -0
- package/src/kernel/sse-id.ts +32 -0
- package/src/manifest/diff.ts +1 -0
- package/src/manifest/types.ts +29 -2
- package/src/mcp/ai-tools.test.ts +202 -0
- package/src/mcp/authorization.ts +66 -0
- package/src/mcp/session.ts +3 -0
- package/src/mcp/tools.ts +168 -0
- package/src/release/http-graph.test.ts +2 -0
- package/src/release/http-graph.ts +5 -0
- package/src/release/measure.ts +39 -14
- package/src/runs/collect.ts +4 -1
- package/src/runs/parquet.test.ts +27 -1
- package/src/runs/parquet.ts +19 -0
- package/src/runs/types.ts +31 -0
- package/src/runtime/json-code-block.test.ts +106 -47
- package/src/runtime/json-code-block.ts +1209 -46
- package/src/term.test.ts +13 -0
- package/src/term.ts +81 -49
- package/src/console/ui-next/dist/assets/PlusSignIcon-CwG3nxfu.js +0 -1
- package/src/console/ui-next/dist/assets/access-page-Ze6ckjdd.js +0 -4
- package/src/console/ui-next/dist/assets/copy-inline-button-CWG5_ZOh.js +0 -1
- package/src/console/ui-next/dist/assets/detail-header-b_ZzIsmU.js +0 -1
- package/src/console/ui-next/dist/assets/dropdown-menu-nwXEO1Ac.js +0 -1
- package/src/console/ui-next/dist/assets/duration-tone-BbQ_8z50.js +0 -9
- package/src/console/ui-next/dist/assets/element-icons-CwyLpVXz.js +0 -1
- package/src/console/ui-next/dist/assets/explorer-empty-C8sSCqYT.js +0 -1
- package/src/console/ui-next/dist/assets/flows-page-D2E7BtKK.js +0 -1
- package/src/console/ui-next/dist/assets/index-VxoEz295.css +0 -2
- package/src/console/ui-next/dist/assets/index-vTuwmeQz.js +0 -58
- package/src/console/ui-next/dist/assets/observability-page-SJTSzHFJ.js +0 -4
- package/src/console/ui-next/dist/assets/request-meta-BjFT7DNl.js +0 -1
- package/src/console/ui-next/dist/assets/shortcut-keys-CUNegEV4.js +0 -1
- package/src/console/ui-next/dist/assets/store-page-Qj9ThRE-.js +0 -41
- package/src/console/ui-next/dist/assets/trace-detail-sheet-Cmitq3da.js +0 -2
- package/src/console/ui-next/dist/assets/tree-expand-toggle-CbDIB-7x.js +0 -55
- package/src/console/ui-next/dist/assets/units-page-_PuYqFty.js +0 -1
- package/src/console/ui-next/dist/assets/use-vault-list-Cs45Czkt.js +0 -1
- package/src/console/ui-next/dist/assets/vault-page-BOMr0go9.js +0 -2
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
FilterHorizontalIcon,
|
|
9
9
|
Folder01Icon,
|
|
10
10
|
InternetAntenna03Icon,
|
|
11
|
+
PinIcon,
|
|
11
12
|
SecurityCheckIcon,
|
|
12
13
|
Timer01Icon,
|
|
13
14
|
UserIcon,
|
|
@@ -54,6 +55,10 @@ import {
|
|
|
54
55
|
countActiveFacets,
|
|
55
56
|
filterUnitTree,
|
|
56
57
|
filterUnitsAdvanced,
|
|
58
|
+
loadPinnedUnits,
|
|
59
|
+
orderPinnedGroups,
|
|
60
|
+
savePinnedUnits,
|
|
61
|
+
togglePinnedUnit,
|
|
57
62
|
unitTreeAncestorKeys,
|
|
58
63
|
unitTreeBandKey,
|
|
59
64
|
unitTreeGroupKey,
|
|
@@ -90,6 +95,7 @@ export function UnitsTree({ groups, selectedFlowId, onSelect }: UnitsTreeProps):
|
|
|
90
95
|
const [advancedOpen, setAdvancedOpen] = useState(false);
|
|
91
96
|
const [facets, setFacets] = useState<UnitTreeFacets>({});
|
|
92
97
|
const [openByKey, setOpenByKey] = useState<Readonly<Record<string, boolean>>>({});
|
|
98
|
+
const [pinned, setPinned] = useState<readonly string[]>(() => loadPinnedUnits());
|
|
93
99
|
|
|
94
100
|
const availableKinds = useMemo(() => {
|
|
95
101
|
const present = new Set<FlowTriggerKind>();
|
|
@@ -171,6 +177,14 @@ export function UnitsTree({ groups, selectedFlowId, onSelect }: UnitsTreeProps):
|
|
|
171
177
|
deliveries: toggleItem(prev.deliveries ?? [], delivery),
|
|
172
178
|
}));
|
|
173
179
|
|
|
180
|
+
const togglePin = (unit: string): void => {
|
|
181
|
+
setPinned((prev) => {
|
|
182
|
+
const next = togglePinnedUnit(prev, unit);
|
|
183
|
+
savePinnedUnits(next);
|
|
184
|
+
return next;
|
|
185
|
+
});
|
|
186
|
+
};
|
|
187
|
+
|
|
174
188
|
return (
|
|
175
189
|
<div className="flex h-full min-h-0 flex-col overflow-hidden" data-slot="units-tree">
|
|
176
190
|
<div className="shrink-0 border-b border-border/60">
|
|
@@ -341,6 +355,8 @@ export function UnitsTree({ groups, selectedFlowId, onSelect }: UnitsTreeProps):
|
|
|
341
355
|
}
|
|
342
356
|
selectedFlowId={selectedFlowId}
|
|
343
357
|
onSelect={onSelect}
|
|
358
|
+
pinned={pinned}
|
|
359
|
+
onTogglePin={togglePin}
|
|
344
360
|
/>
|
|
345
361
|
);
|
|
346
362
|
})}
|
|
@@ -438,6 +454,8 @@ function TriggerBand({
|
|
|
438
454
|
onGroupOpenChange,
|
|
439
455
|
selectedFlowId,
|
|
440
456
|
onSelect,
|
|
457
|
+
pinned,
|
|
458
|
+
onTogglePin,
|
|
441
459
|
}: {
|
|
442
460
|
readonly band: UnitTreeBand;
|
|
443
461
|
readonly open: boolean;
|
|
@@ -446,10 +464,13 @@ function TriggerBand({
|
|
|
446
464
|
readonly onGroupOpenChange: (unit: string, open: boolean) => void;
|
|
447
465
|
readonly selectedFlowId: string | null;
|
|
448
466
|
readonly onSelect: (flowId: string) => void;
|
|
467
|
+
readonly pinned: readonly string[];
|
|
468
|
+
readonly onTogglePin: (unit: string) => void;
|
|
449
469
|
}): JSX.Element {
|
|
450
470
|
const kindSpec = FLOW_TRIGGER_KIND_SPECS[band.id];
|
|
451
|
-
const
|
|
452
|
-
const
|
|
471
|
+
const groups = orderPinnedGroups(band.groups, pinned);
|
|
472
|
+
const flowCount = groups.reduce((n, g) => n + g.flows.length, 0);
|
|
473
|
+
const units = groups.map((g) => g.unit);
|
|
453
474
|
const unitsOpen = units.length > 0 && units.every((unit) => groupOpen(unit));
|
|
454
475
|
|
|
455
476
|
const toggleUnits = (): void => {
|
|
@@ -501,7 +522,7 @@ function TriggerBand({
|
|
|
501
522
|
/>
|
|
502
523
|
<CollapsibleContent>
|
|
503
524
|
<ul className="flex flex-col">
|
|
504
|
-
{
|
|
525
|
+
{groups.map((g) => (
|
|
505
526
|
<UnitGroupItem
|
|
506
527
|
key={`${band.id}:${g.unit}`}
|
|
507
528
|
group={g}
|
|
@@ -509,6 +530,8 @@ function TriggerBand({
|
|
|
509
530
|
onOpenChange={(next) => onGroupOpenChange(g.unit, next)}
|
|
510
531
|
selectedFlowId={selectedFlowId}
|
|
511
532
|
onSelect={onSelect}
|
|
533
|
+
pinned={pinned.includes(g.unit)}
|
|
534
|
+
onTogglePin={() => onTogglePin(g.unit)}
|
|
512
535
|
/>
|
|
513
536
|
))}
|
|
514
537
|
</ul>
|
|
@@ -529,30 +552,62 @@ function UnitGroupItem({
|
|
|
529
552
|
onOpenChange,
|
|
530
553
|
selectedFlowId,
|
|
531
554
|
onSelect,
|
|
555
|
+
pinned,
|
|
556
|
+
onTogglePin,
|
|
532
557
|
}: {
|
|
533
558
|
readonly group: UnitGroup;
|
|
534
559
|
readonly open: boolean;
|
|
535
560
|
readonly onOpenChange: (open: boolean) => void;
|
|
536
561
|
readonly selectedFlowId: string | null;
|
|
537
562
|
readonly onSelect: (flowId: string) => void;
|
|
563
|
+
readonly pinned: boolean;
|
|
564
|
+
readonly onTogglePin: () => void;
|
|
538
565
|
}): JSX.Element {
|
|
566
|
+
const pinLabel = pinned ? `Unpin ${group.unit}` : `Pin ${group.unit}`;
|
|
539
567
|
return (
|
|
540
|
-
<li data-slot="unit-group" data-unit={group.unit}>
|
|
568
|
+
<li data-slot="unit-group" data-unit={group.unit} data-pinned={pinned ? "true" : undefined}>
|
|
541
569
|
<Collapsible open={open} onOpenChange={onOpenChange}>
|
|
542
|
-
<CollapsibleTrigger
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
570
|
+
<CollapsibleTrigger
|
|
571
|
+
nativeButton={false}
|
|
572
|
+
className={cn(EXPLORER_GROUP_ROW_CLASS, "pl-4")}
|
|
573
|
+
data-slot="unit-group-toggle"
|
|
574
|
+
render={(props) => (
|
|
575
|
+
<div {...props}>
|
|
576
|
+
<HugeiconsIcon
|
|
577
|
+
icon={ArrowDown01Icon}
|
|
578
|
+
className={cn(EXPLORER_CHEVRON_CLASS, !open && "-rotate-90")}
|
|
579
|
+
aria-hidden
|
|
580
|
+
/>
|
|
581
|
+
<HugeiconsIcon
|
|
582
|
+
icon={Folder01Icon}
|
|
583
|
+
className={cn(EXPLORER_ICON_CLASS, "text-muted-foreground")}
|
|
584
|
+
aria-hidden
|
|
585
|
+
/>
|
|
586
|
+
<span className="flex min-w-0 flex-1 items-center">
|
|
587
|
+
<span className="min-w-0 truncate font-medium text-foreground">{group.unit}</span>
|
|
588
|
+
<button
|
|
589
|
+
type="button"
|
|
590
|
+
aria-label={pinLabel}
|
|
591
|
+
aria-pressed={pinned}
|
|
592
|
+
data-slot="unit-pin"
|
|
593
|
+
onClick={(event) => {
|
|
594
|
+
event.stopPropagation();
|
|
595
|
+
onTogglePin();
|
|
596
|
+
}}
|
|
597
|
+
className={cn(
|
|
598
|
+
"inline-flex shrink-0 items-center justify-center overflow-hidden text-muted-foreground transition-[width,opacity,margin] hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring/40 focus-visible:outline-none",
|
|
599
|
+
pinned
|
|
600
|
+
? "ml-1.5 size-3.5 text-foreground"
|
|
601
|
+
: "pointer-events-none ml-0 size-0 opacity-0 group-hover/folder:pointer-events-auto group-hover/folder:ml-1.5 group-hover/folder:size-3.5 group-hover/folder:opacity-100 group-focus-within/folder:pointer-events-auto group-focus-within/folder:ml-1.5 group-focus-within/folder:size-3.5 group-focus-within/folder:opacity-100",
|
|
602
|
+
)}
|
|
603
|
+
>
|
|
604
|
+
<HugeiconsIcon icon={PinIcon} className="size-3 shrink-0" aria-hidden />
|
|
605
|
+
</button>
|
|
606
|
+
</span>
|
|
607
|
+
<span className={EXPLORER_COUNT_CLASS}>{group.flows.length}</span>
|
|
608
|
+
</div>
|
|
609
|
+
)}
|
|
610
|
+
/>
|
|
556
611
|
<CollapsibleContent>
|
|
557
612
|
<ul className="flex flex-col">
|
|
558
613
|
{group.flows.map((f) => (
|
|
@@ -10,6 +10,9 @@ import {
|
|
|
10
10
|
countActiveFacets,
|
|
11
11
|
filterUnitTree,
|
|
12
12
|
filterUnitsAdvanced,
|
|
13
|
+
orderPinnedGroups,
|
|
14
|
+
parsePinnedUnits,
|
|
15
|
+
togglePinnedUnit,
|
|
13
16
|
unitTreeAncestorKeys,
|
|
14
17
|
unitTreeBandKey,
|
|
15
18
|
unitTreeGroupKey,
|
|
@@ -289,6 +292,24 @@ describe("bandUnitTree", () => {
|
|
|
289
292
|
expect(unitTreeAncestorKeys(bands, "missing")).toEqual([]);
|
|
290
293
|
});
|
|
291
294
|
|
|
295
|
+
test("pinned folders rise to the front and toggle in newest-first order", () => {
|
|
296
|
+
const http = bandUnitTree(TREE)[0]!;
|
|
297
|
+
expect(parsePinnedUnits(["orders", "", "orders", 1, "billing"])).toEqual(["orders", "billing"]);
|
|
298
|
+
expect(parsePinnedUnits("orders")).toEqual([]);
|
|
299
|
+
expect(orderPinnedGroups(http.groups, ["orders"]).map((g) => g.unit)).toEqual([
|
|
300
|
+
"orders",
|
|
301
|
+
"billing",
|
|
302
|
+
]);
|
|
303
|
+
expect(orderPinnedGroups(http.groups, []).map((g) => g.unit)).toEqual(["billing", "orders"]);
|
|
304
|
+
const pinned = togglePinnedUnit(togglePinnedUnit([], "billing"), "orders");
|
|
305
|
+
expect(pinned).toEqual(["orders", "billing"]);
|
|
306
|
+
expect(orderPinnedGroups(http.groups, pinned).map((g) => g.unit)).toEqual([
|
|
307
|
+
"orders",
|
|
308
|
+
"billing",
|
|
309
|
+
]);
|
|
310
|
+
expect(togglePinnedUnit(pinned, "orders")).toEqual(["billing"]);
|
|
311
|
+
});
|
|
312
|
+
|
|
292
313
|
test("bands and unit folders default closed unless searching", () => {
|
|
293
314
|
expect(unitTreeIsOpen("band:http", {})).toBe(false);
|
|
294
315
|
expect(unitTreeIsOpen("unit:http:billing", {})).toBe(false);
|
|
@@ -87,6 +87,88 @@ export function bandUnitTree(groups: readonly UnitGroup[]): readonly UnitTreeBan
|
|
|
87
87
|
});
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
+
/** localStorage key for pinned Units explorer folders. */
|
|
91
|
+
export const PINNED_UNITS_KEY = "oke_units_pinned";
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Parse a stored pin list. Empty and duplicate names are dropped; order is kept.
|
|
95
|
+
*
|
|
96
|
+
* @param value - JSON from localStorage
|
|
97
|
+
*/
|
|
98
|
+
export function parsePinnedUnits(value: unknown): readonly string[] {
|
|
99
|
+
if (!Array.isArray(value)) return [];
|
|
100
|
+
const seen = new Set<string>();
|
|
101
|
+
const out: string[] = [];
|
|
102
|
+
for (const item of value) {
|
|
103
|
+
if (typeof item !== "string" || item.length === 0 || seen.has(item)) continue;
|
|
104
|
+
seen.add(item);
|
|
105
|
+
out.push(item);
|
|
106
|
+
}
|
|
107
|
+
return out;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Load pinned unit folders from localStorage.
|
|
112
|
+
*/
|
|
113
|
+
export function loadPinnedUnits(): readonly string[] {
|
|
114
|
+
try {
|
|
115
|
+
if (typeof localStorage === "undefined") return [];
|
|
116
|
+
const raw = localStorage.getItem(PINNED_UNITS_KEY);
|
|
117
|
+
if (!raw) return [];
|
|
118
|
+
return parsePinnedUnits(JSON.parse(raw) as unknown);
|
|
119
|
+
} catch {
|
|
120
|
+
return [];
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Persist pinned unit folders. Newest pin is first.
|
|
126
|
+
*
|
|
127
|
+
* @param pinned - Unit names, newest first
|
|
128
|
+
*/
|
|
129
|
+
export function savePinnedUnits(pinned: readonly string[]): void {
|
|
130
|
+
try {
|
|
131
|
+
if (typeof localStorage === "undefined") return;
|
|
132
|
+
localStorage.setItem(PINNED_UNITS_KEY, JSON.stringify(pinned));
|
|
133
|
+
} catch {
|
|
134
|
+
// quota / private mode
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Pin or unpin a unit folder. A new pin is placed first.
|
|
140
|
+
*
|
|
141
|
+
* @param pinned - Current pins, newest first
|
|
142
|
+
* @param unit - Unit name to toggle
|
|
143
|
+
*/
|
|
144
|
+
export function togglePinnedUnit(pinned: readonly string[], unit: string): readonly string[] {
|
|
145
|
+
return pinned.includes(unit) ? pinned.filter((item) => item !== unit) : [unit, ...pinned];
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Lift pinned folders to the front of a band. Pin order is newest first;
|
|
150
|
+
* unpinned folders keep their current order.
|
|
151
|
+
*
|
|
152
|
+
* @param groups - Unit folders in one band
|
|
153
|
+
* @param pinned - Pinned unit names, newest first
|
|
154
|
+
*/
|
|
155
|
+
export function orderPinnedGroups(
|
|
156
|
+
groups: readonly UnitGroup[],
|
|
157
|
+
pinned: readonly string[],
|
|
158
|
+
): readonly UnitGroup[] {
|
|
159
|
+
if (pinned.length === 0 || groups.length < 2) return groups;
|
|
160
|
+
const rank = new Map(pinned.map((unit, index) => [unit, index]));
|
|
161
|
+
return groups
|
|
162
|
+
.map((group, index) => ({ group, index, pin: rank.get(group.unit) }))
|
|
163
|
+
.sort((a, b) => {
|
|
164
|
+
if (a.pin !== undefined && b.pin !== undefined) return a.pin - b.pin;
|
|
165
|
+
if (a.pin !== undefined) return -1;
|
|
166
|
+
if (b.pin !== undefined) return 1;
|
|
167
|
+
return a.index - b.index;
|
|
168
|
+
})
|
|
169
|
+
.map((row) => row.group);
|
|
170
|
+
}
|
|
171
|
+
|
|
90
172
|
/**
|
|
91
173
|
* Open-state key for a trigger-kind band in the Units tree.
|
|
92
174
|
*
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Flows page — Manifest service catalog
|
|
2
|
+
* Flows page — Manifest service catalog, contract, and a Call API rail.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { useMemo, type JSX } from "react";
|
|
@@ -27,6 +27,7 @@ export function UnitsPage(): JSX.Element {
|
|
|
27
27
|
useConsoleLive(true);
|
|
28
28
|
const { selectedFlowId: urlFlowId, setSelectedFlow } = useUnitsSelection();
|
|
29
29
|
const start = useExplorerStartPanel();
|
|
30
|
+
const callRail = useExplorerStartPanel();
|
|
30
31
|
const groups = useMemo(() => buildUnitTree(manifestQuery.data ?? null), [manifestQuery.data]);
|
|
31
32
|
const startToggle = (
|
|
32
33
|
<ExplorerStartToggle
|
|
@@ -37,6 +38,16 @@ export function UnitsPage(): JSX.Element {
|
|
|
37
38
|
dataSlot="flows-tree-toggle"
|
|
38
39
|
/>
|
|
39
40
|
);
|
|
41
|
+
const callToggle = (
|
|
42
|
+
<ExplorerStartToggle
|
|
43
|
+
open={callRail.open}
|
|
44
|
+
onToggle={callRail.toggle}
|
|
45
|
+
noun="Call API"
|
|
46
|
+
controlsId="call-api-rail"
|
|
47
|
+
dataSlot="call-api-toggle"
|
|
48
|
+
side="end"
|
|
49
|
+
/>
|
|
50
|
+
);
|
|
40
51
|
|
|
41
52
|
const selectedFlowId = urlFlowId ?? groups[0]?.flows[0]?.id ?? null;
|
|
42
53
|
const selectedRow = useMemo(() => {
|
|
@@ -79,25 +90,32 @@ export function UnitsPage(): JSX.Element {
|
|
|
79
90
|
<div className="h-full min-h-0 overflow-hidden">
|
|
80
91
|
{selectedRow ? (
|
|
81
92
|
<ResizablePanelGroup
|
|
82
|
-
orientation="
|
|
93
|
+
orientation="horizontal"
|
|
83
94
|
className="min-h-0 flex-1"
|
|
84
95
|
data-slot="units-inspector"
|
|
85
96
|
>
|
|
86
|
-
<ResizablePanel defaultSize="
|
|
97
|
+
<ResizablePanel defaultSize="62%" minSize="36%" className="min-h-0 overflow-hidden">
|
|
87
98
|
<FlowContractPanel
|
|
88
99
|
row={selectedRow}
|
|
89
100
|
manifest={manifestQuery.data ?? null}
|
|
90
101
|
runs={runs.data}
|
|
91
102
|
leading={startToggle}
|
|
103
|
+
trailing={callToggle}
|
|
92
104
|
/>
|
|
93
105
|
</ResizablePanel>
|
|
94
|
-
<ResizableHandle withHandle />
|
|
106
|
+
{callRail.open ? <ResizableHandle withHandle /> : null}
|
|
95
107
|
<ResizablePanel
|
|
96
|
-
|
|
97
|
-
|
|
108
|
+
panelRef={callRail.panelRef}
|
|
109
|
+
collapsible
|
|
110
|
+
collapsedSize={0}
|
|
111
|
+
defaultSize="38%"
|
|
112
|
+
minSize="352px"
|
|
113
|
+
onResize={callRail.onResize}
|
|
98
114
|
className="min-h-0 overflow-hidden"
|
|
99
115
|
>
|
|
100
|
-
<
|
|
116
|
+
<div id="call-api-rail" className="h-full min-h-0 overflow-hidden">
|
|
117
|
+
<CallApiPanel row={selectedRow} manifest={manifestQuery.data ?? null} />
|
|
118
|
+
</div>
|
|
101
119
|
</ResizablePanel>
|
|
102
120
|
</ResizablePanelGroup>
|
|
103
121
|
) : (
|
|
@@ -107,6 +107,22 @@ const flowsRoute = createRoute({
|
|
|
107
107
|
component: lazyRouteComponent(() => import("./features/units/units-page.tsx"), "UnitsPage"),
|
|
108
108
|
});
|
|
109
109
|
|
|
110
|
+
const decisionsRoute = createRoute({
|
|
111
|
+
getParentRoute: () => authenticatedRoute,
|
|
112
|
+
path: "/flows/decisions",
|
|
113
|
+
validateSearch: (search: Record<string, unknown>) => {
|
|
114
|
+
const decision =
|
|
115
|
+
typeof search.decision === "string" && search.decision.length > 0
|
|
116
|
+
? search.decision
|
|
117
|
+
: undefined;
|
|
118
|
+
return { ...(decision !== undefined ? { decision } : {}) };
|
|
119
|
+
},
|
|
120
|
+
component: lazyRouteComponent(
|
|
121
|
+
() => import("./features/flows/decisions/decisions-page.tsx"),
|
|
122
|
+
"DecisionsPage",
|
|
123
|
+
),
|
|
124
|
+
});
|
|
125
|
+
|
|
110
126
|
const storeRoute = createRoute({
|
|
111
127
|
getParentRoute: () => authenticatedRoute,
|
|
112
128
|
path: "/store",
|
|
@@ -152,6 +168,7 @@ const routeTree = rootRoute.addChildren([
|
|
|
152
168
|
authenticatedRoute.addChildren([
|
|
153
169
|
overviewRoute,
|
|
154
170
|
flowsRoute,
|
|
171
|
+
decisionsRoute,
|
|
155
172
|
storeRoute,
|
|
156
173
|
vaultRoute,
|
|
157
174
|
accessRoute,
|
|
@@ -363,6 +363,29 @@ export function createUiNextSeedRuns(now: number = Date.now()): readonly WideEve
|
|
|
363
363
|
replica: "replica",
|
|
364
364
|
replicaLagMs: 12,
|
|
365
365
|
buildVersion: BUILD,
|
|
366
|
+
http: {
|
|
367
|
+
request: {
|
|
368
|
+
method: "GET",
|
|
369
|
+
path: "/tasks",
|
|
370
|
+
query: { limit: "20" },
|
|
371
|
+
headers: {
|
|
372
|
+
accept: "application/json",
|
|
373
|
+
authorization: "[redacted]",
|
|
374
|
+
host: "localhost:6530",
|
|
375
|
+
"user-agent":
|
|
376
|
+
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
|
|
377
|
+
"sec-ch-ua-platform": '"macOS"',
|
|
378
|
+
"sec-ch-ua-mobile": "?0",
|
|
379
|
+
"cf-connecting-ip": "203.0.113.10",
|
|
380
|
+
},
|
|
381
|
+
},
|
|
382
|
+
response: {
|
|
383
|
+
status: 200,
|
|
384
|
+
headers: {
|
|
385
|
+
"content-type": "application/json",
|
|
386
|
+
},
|
|
387
|
+
},
|
|
388
|
+
},
|
|
366
389
|
output: {
|
|
367
390
|
count: 3,
|
|
368
391
|
tasks: [
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
import type { Plugin, ViteDevServer } from "vite";
|
|
16
16
|
import { isPortInUse } from "../../cli/ports.ts";
|
|
17
17
|
import { CONSOLE_PORT } from "../../runtime/types.ts";
|
|
18
|
-
import {
|
|
18
|
+
import type { ConsoleServerHandle } from "../server/serve.ts";
|
|
19
19
|
import {
|
|
20
20
|
isConsoleFresh,
|
|
21
21
|
isConsoleKernelSkipped,
|
|
@@ -30,6 +30,21 @@ import {
|
|
|
30
30
|
uiNextSeededSummary,
|
|
31
31
|
} from "./ui-next-seed.ts";
|
|
32
32
|
|
|
33
|
+
/**
|
|
34
|
+
* Load a Console module from its source file.
|
|
35
|
+
*
|
|
36
|
+
* Vite bundles this plugin into a config chunk. A literal `import()` is
|
|
37
|
+
* inlined there, and Bun `import.meta.dir` then points at that chunk, so
|
|
38
|
+
* `lazyRequire` looks for `aot.js` beside the chunk. A variable specifier
|
|
39
|
+
* stays out of the bundle and keeps the real source directory.
|
|
40
|
+
*
|
|
41
|
+
* @param relativePath - Path relative to this plugin file
|
|
42
|
+
*/
|
|
43
|
+
async function importSource<T>(relativePath: string): Promise<T> {
|
|
44
|
+
const href = new URL(relativePath, import.meta.url).href;
|
|
45
|
+
return (await import(href)) as T;
|
|
46
|
+
}
|
|
47
|
+
|
|
33
48
|
/** Vite SPA URL for ui-next (proxies `/console` → kernel :6533). */
|
|
34
49
|
const UI_NEXT_DEV_URL = "http://127.0.0.1:6537";
|
|
35
50
|
|
|
@@ -78,6 +93,7 @@ function printConsoleNextBanner(
|
|
|
78
93
|
export function okeConsoleKernelPlugin(): Plugin {
|
|
79
94
|
let handle: ConsoleServerHandle | null = null;
|
|
80
95
|
let stopping = false;
|
|
96
|
+
let parkedStop: (() => Promise<void>) | null = null;
|
|
81
97
|
|
|
82
98
|
const stop = (): void => {
|
|
83
99
|
if (stopping || !handle) return;
|
|
@@ -87,6 +103,8 @@ export function okeConsoleKernelPlugin(): Plugin {
|
|
|
87
103
|
} catch {
|
|
88
104
|
// ignore
|
|
89
105
|
}
|
|
106
|
+
void parkedStop?.();
|
|
107
|
+
parkedStop = null;
|
|
90
108
|
handle = null;
|
|
91
109
|
};
|
|
92
110
|
|
|
@@ -133,6 +151,15 @@ export function okeConsoleKernelPlugin(): Plugin {
|
|
|
133
151
|
|
|
134
152
|
const operators = fresh ? undefined : (await seedUiNextDevOperator()).store;
|
|
135
153
|
|
|
154
|
+
const parked = seeded
|
|
155
|
+
? await importSource<typeof import("./seed-parked-approval.ts")>(
|
|
156
|
+
"./seed-parked-approval.ts",
|
|
157
|
+
).then((mod) => mod.bootParkedApproval())
|
|
158
|
+
: null;
|
|
159
|
+
if (parked) parkedStop = () => parked.stop();
|
|
160
|
+
|
|
161
|
+
const { serveConsole } =
|
|
162
|
+
await importSource<typeof import("../server/serve.ts")>("../server/serve.ts");
|
|
136
163
|
handle = await serveConsole({
|
|
137
164
|
port,
|
|
138
165
|
hostname,
|
|
@@ -142,10 +169,21 @@ export function okeConsoleKernelPlugin(): Plugin {
|
|
|
142
169
|
env: "test",
|
|
143
170
|
secret: process.env.OKE_CONSOLE_SECRET ?? "oke-console-next-dev-secret",
|
|
144
171
|
...(operators ? { operators } : {}),
|
|
172
|
+
...(parked ? { journalStore: parked.store } : {}),
|
|
145
173
|
...(seeded
|
|
146
174
|
? { manifest: UI_NEXT_SEEDED_MANIFEST, vaultLayerSeed: UI_NEXT_SEED_VAULT_LAYERS }
|
|
147
175
|
: {}),
|
|
148
176
|
});
|
|
177
|
+
if (parked) {
|
|
178
|
+
handle.console.state.forwardAgent = (request) => parked.fetch(request);
|
|
179
|
+
handle.console.state.afterAgentApproval = () => parked.resume();
|
|
180
|
+
if (parked.log) {
|
|
181
|
+
const { setAgentEventLog } = await importSource<
|
|
182
|
+
typeof import("../../elements/ai/run-events.ts")
|
|
183
|
+
>("../../elements/ai/run-events.ts");
|
|
184
|
+
setAgentEventLog(parked.log);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
149
187
|
|
|
150
188
|
if (seeded) {
|
|
151
189
|
const runs = handle.console.app.bootResult?.runs;
|
|
@@ -154,7 +192,8 @@ export function okeConsoleKernelPlugin(): Plugin {
|
|
|
154
192
|
}
|
|
155
193
|
await appendUiNextSeedRun(runs);
|
|
156
194
|
if (handle.console.state.storeRuntime) {
|
|
157
|
-
const { seedUiNextStoreData } =
|
|
195
|
+
const { seedUiNextStoreData } =
|
|
196
|
+
await importSource<typeof import("./ui-next-seed.ts")>("./ui-next-seed.ts");
|
|
158
197
|
await seedUiNextStoreData(handle.console.state.storeRuntime);
|
|
159
198
|
}
|
|
160
199
|
// Same thin host substitute as the Playwright fixture — Replay hits
|
|
@@ -162,7 +201,8 @@ export function okeConsoleKernelPlugin(): Plugin {
|
|
|
162
201
|
handle.console.state.replayTrace = async ({ event, dryRun }) => ({
|
|
163
202
|
output: { replayed: event.id, dryRun, input: event.input ?? null },
|
|
164
203
|
});
|
|
165
|
-
const { bootUiNextSeedInvoke } =
|
|
204
|
+
const { bootUiNextSeedInvoke } =
|
|
205
|
+
await importSource<typeof import("./seed-invoke-host.ts")>("./seed-invoke-host.ts");
|
|
166
206
|
const seedInvoke = await bootUiNextSeedInvoke({
|
|
167
207
|
...(handle.console.state.storeRuntime
|
|
168
208
|
? { storeRuntime: handle.console.state.storeRuntime }
|
|
@@ -82,6 +82,15 @@ export default defineConfig(({ command }) => {
|
|
|
82
82
|
changeOrigin: true,
|
|
83
83
|
ws: true,
|
|
84
84
|
},
|
|
85
|
+
"/agent": {
|
|
86
|
+
// `oke dev` serves follow on the app (:6530). An explicit
|
|
87
|
+
// `OKE_CONSOLE_PROXY` is the Console kernel, which forwards `/agent`.
|
|
88
|
+
target:
|
|
89
|
+
attachToOkeDev && process.env["OKE_CONSOLE_PROXY"] === undefined
|
|
90
|
+
? "http://127.0.0.1:6530"
|
|
91
|
+
: consoleProxy,
|
|
92
|
+
changeOrigin: true,
|
|
93
|
+
},
|
|
85
94
|
},
|
|
86
95
|
},
|
|
87
96
|
};
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Dragonfly image recipe —
|
|
2
|
+
* Dragonfly image recipe — default `store.kv` pin.
|
|
3
3
|
*
|
|
4
|
-
* Peer of Redis / Valkey via
|
|
4
|
+
* Redis-wire-compatible and multi-threaded. Peer of Redis / Valkey via
|
|
5
|
+
* `images["store.kv"]` (driver id stays `redis`).
|
|
5
6
|
* Official image: `docker.dragonflydb.io/dragonflydb/dragonfly`.
|
|
6
7
|
*/
|
|
7
8
|
|