okengine 0.1.4 → 0.2.1

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.
Files changed (84) hide show
  1. package/AGENTS.md +1 -1
  2. package/README.md +48 -15
  3. package/docs/spec/{complete-example.md → example.md} +0 -1
  4. package/docs/spec/unified-theory.md +1 -1
  5. package/package.json +21 -8
  6. package/src/auth/index.ts +1 -0
  7. package/src/cli/dev.ts +3 -1
  8. package/src/cli/doc-drift.ts +54 -21
  9. package/src/client/index.ts +1 -0
  10. package/src/config/index.ts +1 -0
  11. package/src/console/index.ts +26 -13
  12. package/src/console/server/app.ts +44 -7
  13. package/src/console/server/flows.ts +2 -6
  14. package/src/console/server/index.ts +2 -1
  15. package/src/console/server/lazy-panels.test.ts +27 -0
  16. package/src/console/server/panel-load.ts +28 -0
  17. package/src/console/server/plugin.ts +1 -1
  18. package/src/console/server/plugins.ts +7 -6
  19. package/src/console/server/public-flows.ts +12 -0
  20. package/src/console/server/state.ts +159 -122
  21. package/src/console/server/store.ts +13 -10
  22. package/src/drivers/index.ts +2 -6
  23. package/src/drivers/vault-sops.ts +20 -1
  24. package/src/elements/ai.ts +1 -0
  25. package/src/elements/channel.ts +1 -0
  26. package/src/elements/clock.ts +1 -0
  27. package/src/elements/gate.ts +1 -0
  28. package/src/elements/signal.ts +1 -0
  29. package/src/elements/store.ts +1 -0
  30. package/src/elements/vault.ts +1 -0
  31. package/src/index.ts +9 -0
  32. package/src/kernel/app.ts +1 -1
  33. package/src/kernel/boot-bind/ai.ts +31 -0
  34. package/src/kernel/boot-bind/channel.ts +27 -0
  35. package/src/kernel/boot-bind/clock.ts +74 -0
  36. package/src/kernel/boot-bind/gate.ts +28 -0
  37. package/src/kernel/boot-bind/runs.ts +28 -0
  38. package/src/kernel/boot-bind/signal.ts +68 -0
  39. package/src/kernel/boot-bind/store.ts +47 -0
  40. package/src/kernel/boot-bind/vault.ts +36 -0
  41. package/src/kernel/boot.test.ts +85 -1
  42. package/src/kernel/boot.ts +250 -212
  43. package/src/kernel/index.ts +2 -0
  44. package/src/mcp/data.ts +1 -0
  45. package/src/mcp/docs-index.ts +252 -0
  46. package/src/mcp/docs-mcp.test.ts +176 -0
  47. package/src/mcp/docs-server.ts +233 -0
  48. package/src/mcp/docs-tools.ts +143 -0
  49. package/src/mcp/index.ts +30 -5
  50. package/src/mcp/protocol.ts +2 -1
  51. package/src/release/exports.test.ts +71 -0
  52. package/src/release/exports.ts +156 -0
  53. package/src/release/index.ts +21 -0
  54. package/src/release/limits.ts +9 -0
  55. package/src/release/measure.exports.test.ts +82 -0
  56. package/src/release/measure.ts +297 -14
  57. package/src/release/publish.ts +14 -3
  58. package/src/release/readme.test.ts +61 -0
  59. package/src/release/readme.ts +13 -0
  60. package/src/runs/index.ts +1 -0
  61. package/src/runtime/index.ts +1 -0
  62. package/src/runtime/security.test.ts +6 -1
  63. package/src/runtime/types.ts +6 -0
  64. package/src/test/create-test-app.ts +2 -0
  65. package/src/test/index.ts +1 -0
  66. package/src/console/ui/dist/assets/index-B71Yl_SS.js +0 -10
  67. package/src/console/ui/dist/assets/panel-access-Dd37LU2c.js +0 -64
  68. package/src/console/ui/dist/assets/panel-ai-CC7LR6-J.js +0 -1
  69. package/src/console/ui/dist/assets/panel-architecture-B5b3iKCz.js +0 -1
  70. package/src/console/ui/dist/assets/panel-channels-CeNjTKXp.js +0 -1
  71. package/src/console/ui/dist/assets/panel-clock-DgFTLoHV.js +0 -1
  72. package/src/console/ui/dist/assets/panel-diff-DxehccqB.js +0 -1
  73. package/src/console/ui/dist/assets/panel-flows-BtrVn-Eg.js +0 -45
  74. package/src/console/ui/dist/assets/panel-gates-Z9MKRGdH.js +0 -1
  75. package/src/console/ui/dist/assets/panel-overview-Bd48d9km.js +0 -1
  76. package/src/console/ui/dist/assets/panel-plugins-DWd0TowH.js +0 -1
  77. package/src/console/ui/dist/assets/panel-runs-BwsWqKeB.js +0 -1
  78. package/src/console/ui/dist/assets/panel-signals-9najbZY2.js +0 -1
  79. package/src/console/ui/dist/assets/panel-store-OHkP2pDp.js +0 -1
  80. package/src/console/ui/dist/assets/panel-traces-tn2JoY8U.js +0 -1
  81. package/src/console/ui/dist/assets/panel-vault-BbfWdox0.js +0 -1
  82. package/src/console/ui/dist/assets/rolldown-runtime-CNC7AqOf.js +0 -1
  83. package/src/console/ui/dist/assets/style-Cnl7WLya.css +0 -3
  84. package/src/console/ui/dist/index.html +0 -14
@@ -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
- projectSupplyChain,
28
- projectSupplyChainSync,
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
+ ]);
@@ -13,19 +13,11 @@ import {
13
13
  type RoleStore,
14
14
  type SessionStore,
15
15
  } from "../../auth/index.ts";
16
- import {
17
- accessCreateInvite,
18
- accessCreateKey,
19
- accessRevokeKey,
20
- accessRotateKey,
21
- accessSetRoleGrants,
22
- effectivePermissions,
23
- keyBlastRadius,
24
- projectAccessPanel,
25
- type AccessEffectivePermissions,
26
- type AccessKeyBlastRadius,
27
- type AccessKeyRow,
28
- type AccessPanelProjection,
16
+ import type {
17
+ AccessEffectivePermissions,
18
+ AccessKeyBlastRadius,
19
+ AccessKeyRow,
20
+ AccessPanelProjection,
29
21
  } from "./access.ts";
30
22
  import { deriveModuleActions, type GateRuntime } from "../../elements/gate.ts";
31
23
  import type {
@@ -34,94 +26,61 @@ import type {
34
26
  SignalReplayOptions,
35
27
  SignalReplayResult,
36
28
  } from "../../drivers/signal-types.ts";
37
- import type { AiRuntime, EvalSuiteResult } from "../../elements/ai.ts";
29
+ import type {
30
+ AgentToolEffect,
31
+ AiRuntime,
32
+ EvalSuiteResult,
33
+ } from "../../elements/ai.ts";
38
34
  import {
39
35
  createMemorySignalConfigStore,
40
36
  type SignalConfigStore,
41
37
  } from "../../elements/signal/reconcile.ts";
42
38
  import type { Manifest } from "../../manifest/types.ts";
43
39
  import type { WideEvent } from "../../runs/types.ts";
44
- import {
45
- effectsForFlowFromManifest,
46
- projectAiPanel,
47
- type ConsoleAiProjection,
48
- } from "./ai.ts";
40
+ import type { ConsoleAiProjection } from "./ai.ts";
49
41
  import {
50
42
  createLoginAttemptBag,
51
43
  type LoginAttemptBag,
52
44
  } from "./auth-rate.ts";
53
45
  import { mintClaimCode, type ClaimCodeState } from "./claim.ts";
54
- import {
55
- discardViaBus,
56
- projectSignalsList,
57
- replayViaBus,
58
- type ConsoleSignalRow,
59
- } from "./signals.ts";
60
- import {
61
- deleteStore,
62
- editStore,
63
- projectStoresList,
64
- purgeStoreCache,
65
- queryStore,
66
- runStoreSql,
67
- type ConsoleStoreRow,
68
- type StoreDeleteInput,
69
- type StoreEditInput,
70
- type StoreQueryInput,
71
- type StoreQueryResult,
46
+ import type { ConsoleSignalRow } from "./signals.ts";
47
+ import type {
48
+ ConsoleStoreRow,
49
+ StoreDeleteInput,
50
+ StoreEditInput,
51
+ StoreEditResult,
52
+ StoreQueryInput,
53
+ StoreQueryResult,
72
54
  } from "./store.ts";
73
55
  import type { ClockRuntime, EditScheduleInput } from "../../elements/clock.ts";
74
56
  import type { StoreRuntime } from "../../elements/store.ts";
75
57
  import type { VaultRuntime } from "../../elements/vault.ts";
76
58
  import type { JournalStore } from "../../kernel/journal.ts";
77
59
  import type { ResourceRef } from "../../manifest/types.ts";
78
- import {
79
- editCronSchedule,
80
- pauseCronNow,
81
- projectClocksList,
82
- runCronNow,
83
- wakeEarlyNow,
84
- type ConsoleClockList,
85
- } from "./clock.ts";
60
+ import type { ConsoleClockList } from "./clock.ts";
86
61
  import {
87
62
  createDefaultGateAuthStores,
88
63
  createManifestGateRuntime,
89
- powersForPrincipal,
90
- projectGatesPanel,
91
- simulateGates,
92
64
  type GatesPanelProjection,
93
65
  type SimulateGatesInput,
94
66
  type SimulateGatesResult,
95
67
  } from "./gates.ts";
96
- import {
97
- projectVaultList,
98
- rotateVaultValue,
99
- setVaultValue,
100
- type ConsoleVaultRow,
101
- type VaultWriteInput,
102
- } from "./vault.ts";
68
+ import type { ConsoleVaultRow, VaultWriteInput } from "./vault.ts";
103
69
  import type { ChannelInbox } from "../../drivers/channel-types.ts";
104
70
  import type { ChannelRuntime, TemplateCatalog } from "../../elements/channel.ts";
105
- import {
106
- previewChannelTemplate,
107
- projectChannelsList,
108
- revealChannelRecipient,
109
- sendChannelTest,
110
- verifyChannelAuth,
111
- type ConsoleChannelPreview,
112
- type ConsoleChannelsList,
113
- type EmailAuthResult,
71
+ import type {
72
+ ConsoleChannelPreview,
73
+ ConsoleChannelsList,
74
+ EmailAuthResult,
114
75
  } from "./channels.ts";
115
76
  import type { OkeConfig } from "../../config/index.ts";
116
77
  import type { PluginRegistry } from "../../kernel/registry.ts";
78
+ import type { ConsolePluginsList } from "./plugins.ts";
79
+ import type { ConsoleDiffProjection } from "./diff.ts";
117
80
  import {
118
- projectPluginsList,
119
- type ConsolePluginsList,
120
- } from "./plugins.ts";
121
- import {
122
- projectManifestDiff,
123
- type ConsoleDiffProjection,
124
- } from "./diff.ts";
81
+ loadConsolePanel,
82
+ type ConsolePanelId,
83
+ } from "./panel-load.ts";
125
84
 
126
85
  /** User-plane identity row for the Flows invoke-as picker. */
127
86
  export interface ConsoleIdentity {
@@ -149,6 +108,11 @@ export interface ConsoleState {
149
108
  previousManifest: Manifest | null;
150
109
  /** Live-channel subscribers. */
151
110
  readonly liveSubscribers: Set<(msg: ConsoleLiveMessage) => void>;
111
+ /**
112
+ * Panel backends constructed on first access (lazy). Empty after
113
+ * {@link createConsoleState}; grows as panels are visited.
114
+ */
115
+ readonly constructedPanels: ReadonlySet<ConsolePanelId>;
152
116
  /** Role store (data, not code) — Gates · Access. */
153
117
  readonly roles: RoleStore;
154
118
  /** API key store — first-class principals. */
@@ -248,7 +212,7 @@ export interface ConsoleState {
248
212
  editStore: (
249
213
  input: StoreEditInput,
250
214
  options?: { readonly dryRun?: boolean },
251
- ) => Promise<Awaited<ReturnType<typeof editStore>>>;
215
+ ) => Promise<StoreEditResult>;
252
216
  /** Delete rows/keys. */
253
217
  deleteStore: (
254
218
  input: StoreDeleteInput,
@@ -457,7 +421,15 @@ export function createConsoleState(
457
421
  const signalConfig = createMemorySignalConfigStore();
458
422
  const gateAuth = createDefaultGateAuthStores();
459
423
  const invites = createOperatorInviteStore();
460
- seedAccessDemoData(gateAuth.apiKeys, invites, now);
424
+ const constructed = new Set<ConsolePanelId>();
425
+ let accessSeeded = false;
426
+
427
+ const markPanel = async <T>(
428
+ id: ConsolePanelId,
429
+ ): Promise<T> => {
430
+ constructed.add(id);
431
+ return loadConsolePanel<T>(id);
432
+ };
461
433
 
462
434
  const state: ConsoleState = {
463
435
  operators,
@@ -470,13 +442,21 @@ export function createConsoleState(
470
442
  manifest: options.manifest ?? null,
471
443
  previousManifest: options.previousManifest ?? null,
472
444
  liveSubscribers,
445
+ get constructedPanels() {
446
+ return constructed;
447
+ },
473
448
  roles: gateAuth.roles,
474
449
  apiKeys: gateAuth.apiKeys,
475
450
  invites,
476
451
  accessTtlMs: options.accessTtlMs ?? ACCESS_TTL_MS,
477
452
  roleMembers: gateAuth.roleMembers,
478
453
  listAccess: async (actorScopes) => {
479
- return projectAccessPanel({
454
+ const access = await markPanel<typeof import("./access.ts")>("access");
455
+ if (!accessSeeded) {
456
+ seedAccessDemoData(state.apiKeys, state.invites, state.now);
457
+ accessSeeded = true;
458
+ }
459
+ return access.projectAccessPanel({
480
460
  manifest: state.manifest,
481
461
  roles: state.roles,
482
462
  apiKeys: state.apiKeys,
@@ -490,7 +470,8 @@ export function createConsoleState(
490
470
  });
491
471
  },
492
472
  accessEffective: async (input) => {
493
- return effectivePermissions({
473
+ const access = await markPanel<typeof import("./access.ts")>("access");
474
+ return access.effectivePermissions({
494
475
  ...input,
495
476
  roles: state.roles,
496
477
  apiKeys: state.apiKeys,
@@ -500,8 +481,9 @@ export function createConsoleState(
500
481
  });
501
482
  },
502
483
  accessKeyBlast: async (keyId) => {
484
+ const access = await markPanel<typeof import("./access.ts")>("access");
503
485
  const runs = await state.listRuns();
504
- return keyBlastRadius({
486
+ return access.keyBlastRadius({
505
487
  keyId,
506
488
  apiKeys: state.apiKeys,
507
489
  runs,
@@ -509,23 +491,29 @@ export function createConsoleState(
509
491
  });
510
492
  },
511
493
  accessCreateKey: async (input) => {
512
- return accessCreateKey(state.apiKeys, {
494
+ const access = await markPanel<typeof import("./access.ts")>("access");
495
+ return access.accessCreateKey(state.apiKeys, {
513
496
  ...input,
514
497
  catalog: accessCatalog(state),
515
498
  now: state.now,
516
499
  });
517
500
  },
518
501
  accessRevokeKey: async (keyId) => {
519
- return accessRevokeKey({
502
+ const access = await markPanel<typeof import("./access.ts")>("access");
503
+ return access.accessRevokeKey({
520
504
  apiKeys: state.apiKeys,
521
505
  sessions: state.sessions,
522
506
  keyId,
523
507
  now: state.now,
524
508
  });
525
509
  },
526
- accessRotateKey: async (keyId) => accessRotateKey(state.apiKeys, keyId),
510
+ accessRotateKey: async (keyId) => {
511
+ const access = await markPanel<typeof import("./access.ts")>("access");
512
+ return access.accessRotateKey(state.apiKeys, keyId);
513
+ },
527
514
  accessSetRoleGrants: async (input) => {
528
- accessSetRoleGrants({
515
+ const access = await markPanel<typeof import("./access.ts")>("access");
516
+ access.accessSetRoleGrants({
529
517
  roles: state.roles,
530
518
  roleId: input.roleId,
531
519
  scopes: input.scopes,
@@ -534,7 +522,8 @@ export function createConsoleState(
534
522
  });
535
523
  },
536
524
  accessCreateInvite: async (input) => {
537
- const row = accessCreateInvite(state.invites, {
525
+ const access = await markPanel<typeof import("./access.ts")>("access");
526
+ const row = access.accessCreateInvite(state.invites, {
538
527
  ...input,
539
528
  now: state.now,
540
529
  });
@@ -542,6 +531,9 @@ export function createConsoleState(
542
531
  },
543
532
  gateRuntime: options.gateRuntime ?? null,
544
533
  listGates: async () => {
534
+ const { ensureConsolePanelRuntimes } = await import("./app.ts");
535
+ await ensureConsolePanelRuntimes(state, "gates");
536
+ const gates = await markPanel<typeof import("./gates.ts")>("gates");
545
537
  const operatorRoles = new Map<string, readonly string[]>();
546
538
  const ops = new Map<string, { name: string; email: string }>();
547
539
  for (const [id, roleIds] of operators.roles) {
@@ -550,7 +542,7 @@ export function createConsoleState(
550
542
  for (const op of operators.operators.values()) {
551
543
  ops.set(op.id, { name: op.name, email: op.email });
552
544
  }
553
- return projectGatesPanel({
545
+ return gates.projectGatesPanel({
554
546
  manifest: state.manifest,
555
547
  roles: state.roles,
556
548
  apiKeys: state.apiKeys,
@@ -562,7 +554,8 @@ export function createConsoleState(
562
554
  });
563
555
  },
564
556
  simulateGates: async (input) => {
565
- return simulateGates({
557
+ const gates = await markPanel<typeof import("./gates.ts")>("gates");
558
+ return gates.simulateGates({
566
559
  ...input,
567
560
  manifest: state.manifest,
568
561
  gateRuntime: state.gateRuntime,
@@ -573,7 +566,8 @@ export function createConsoleState(
573
566
  });
574
567
  },
575
568
  powersForPrincipal: async (input) => {
576
- return powersForPrincipal({
569
+ const gates = await markPanel<typeof import("./gates.ts")>("gates");
570
+ return gates.powersForPrincipal({
577
571
  ...input,
578
572
  manifest: state.manifest,
579
573
  gateRuntime: state.gateRuntime,
@@ -587,8 +581,11 @@ export function createConsoleState(
587
581
  signalConfig,
588
582
  signalBus: null,
589
583
  listSignals: async () => {
584
+ const { ensureConsolePanelRuntimes } = await import("./app.ts");
585
+ await ensureConsolePanelRuntimes(state, "signals");
586
+ const signals = await markPanel<typeof import("./signals.ts")>("signals");
590
587
  const runs = await state.listRuns();
591
- return projectSignalsList({
588
+ return signals.projectSignalsList({
592
589
  manifest: state.manifest,
593
590
  config: state.signalConfig,
594
591
  bus: state.signalBus,
@@ -604,6 +601,7 @@ export function createConsoleState(
604
601
  });
605
602
  },
606
603
  replaySignals: async (opts) => {
604
+ const signals = await markPanel<typeof import("./signals.ts")>("signals");
607
605
  if (!state.signalBus) {
608
606
  return {
609
607
  attempted: 0,
@@ -614,16 +612,20 @@ export function createConsoleState(
614
612
  wouldHaveFired: [],
615
613
  };
616
614
  }
617
- return replayViaBus(state.signalBus, opts);
615
+ return signals.replayViaBus(state.signalBus, opts);
618
616
  },
619
617
  discardSignals: async (opts) => {
618
+ const signals = await markPanel<typeof import("./signals.ts")>("signals");
620
619
  if (!state.signalBus) return { discarded: 0 };
621
- return discardViaBus(state.signalBus, opts);
620
+ return signals.discardViaBus(state.signalBus, opts);
622
621
  },
623
622
  storeRuntime: null,
624
623
  listStores: async () => {
624
+ const { ensureConsolePanelRuntimes } = await import("./app.ts");
625
+ await ensureConsolePanelRuntimes(state, "store");
626
+ const store = await markPanel<typeof import("./store.ts")>("store");
625
627
  const runs = await state.listRuns();
626
- return projectStoresList({
628
+ return store.projectStoresList({
627
629
  manifest: state.manifest,
628
630
  runtime: state.storeRuntime,
629
631
  cwd: state.cwd,
@@ -636,37 +638,45 @@ export function createConsoleState(
636
638
  });
637
639
  },
638
640
  queryStore: async (input) => {
641
+ const store = await markPanel<typeof import("./store.ts")>("store");
639
642
  if (!state.storeRuntime) {
640
643
  return { facet: input.ref.split(":")[0] as "sql", rows: [], masked: true };
641
644
  }
642
- return queryStore(state.storeRuntime, state.manifest, input);
645
+ return store.queryStore(state.storeRuntime, state.manifest, input);
643
646
  },
644
647
  editStore: async (input, opts) => {
648
+ const store = await markPanel<typeof import("./store.ts")>("store");
645
649
  if (!state.storeRuntime) {
646
650
  throw new Error("Store runtime not bound");
647
651
  }
648
- return editStore(state.storeRuntime, state.manifest, input, {
652
+ return store.editStore(state.storeRuntime, state.manifest, input, {
649
653
  production: state.production,
650
654
  dryRun: opts?.dryRun,
651
655
  });
652
656
  },
653
657
  deleteStore: async (input) => {
658
+ const store = await markPanel<typeof import("./store.ts")>("store");
654
659
  if (!state.storeRuntime) return { deleted: 0 };
655
- return deleteStore(state.storeRuntime, input);
660
+ return store.deleteStore(state.storeRuntime, input);
656
661
  },
657
662
  purgeStoreCache: async (resource) => {
663
+ const store = await markPanel<typeof import("./store.ts")>("store");
658
664
  if (!state.storeRuntime) return { keys: [] };
659
- return purgeStoreCache(state.storeRuntime, resource);
665
+ return store.purgeStoreCache(state.storeRuntime, resource);
660
666
  },
661
667
  runStoreSql: async (ref, sqlText, options) => {
668
+ const store = await markPanel<typeof import("./store.ts")>("store");
662
669
  if (!state.storeRuntime) {
663
670
  throw new Error("Store runtime not bound");
664
671
  }
665
- return runStoreSql(state.storeRuntime, ref, sqlText, options);
672
+ return store.runStoreSql(state.storeRuntime, ref, sqlText, options);
666
673
  },
667
674
  clockRuntime: options.clockRuntime ?? null,
668
675
  listClocks: async () => {
669
- return projectClocksList({
676
+ const { ensureConsolePanelRuntimes } = await import("./app.ts");
677
+ await ensureConsolePanelRuntimes(state, "clock");
678
+ const clock = await markPanel<typeof import("./clock.ts")>("clock");
679
+ return clock.projectClocksList({
670
680
  manifest: state.manifest,
671
681
  runtime: state.clockRuntime,
672
682
  journal: state.journalStore,
@@ -674,23 +684,26 @@ export function createConsoleState(
674
684
  });
675
685
  },
676
686
  runCronNow: async (name) => {
687
+ const clock = await markPanel<typeof import("./clock.ts")>("clock");
677
688
  if (!state.clockRuntime) {
678
689
  throw new Error("Clock runtime not bound");
679
690
  }
680
- return runCronNow(state.clockRuntime, name);
691
+ return clock.runCronNow(state.clockRuntime, name);
681
692
  },
682
693
  pauseCron: async (name) => {
694
+ const clock = await markPanel<typeof import("./clock.ts")>("clock");
683
695
  if (!state.clockRuntime) {
684
696
  throw new Error("Clock runtime not bound");
685
697
  }
686
- const row = await pauseCronNow(state.clockRuntime, name);
698
+ const row = await clock.pauseCronNow(state.clockRuntime, name);
687
699
  return { name: row.name, status: row.status };
688
700
  },
689
701
  editSchedule: async (input) => {
702
+ const clock = await markPanel<typeof import("./clock.ts")>("clock");
690
703
  if (!state.clockRuntime) {
691
704
  throw new Error("Clock runtime not bound");
692
705
  }
693
- const row = await editCronSchedule(state.clockRuntime, input);
706
+ const row = await clock.editCronSchedule(state.clockRuntime, input);
694
707
  return {
695
708
  name: row.name,
696
709
  effectiveCron: row.effectiveCron,
@@ -698,10 +711,11 @@ export function createConsoleState(
698
711
  };
699
712
  },
700
713
  wakeEarly: async (runId) => {
714
+ const clock = await markPanel<typeof import("./clock.ts")>("clock");
701
715
  if (!state.journalStore) {
702
716
  throw new Error("Journal store not bound");
703
717
  }
704
- const result = await wakeEarlyNow(state.journalStore, runId, {
718
+ const result = await clock.wakeEarlyNow(state.journalStore, runId, {
705
719
  now: state.now,
706
720
  });
707
721
  return {
@@ -714,7 +728,10 @@ export function createConsoleState(
714
728
  journalStore: options.journalStore ?? null,
715
729
  vaultEnv: options.vaultEnv ?? "dev",
716
730
  listVault: async () => {
717
- return projectVaultList({
731
+ const { ensureConsolePanelRuntimes } = await import("./app.ts");
732
+ await ensureConsolePanelRuntimes(state, "vault");
733
+ const vault = await markPanel<typeof import("./vault.ts")>("vault");
734
+ return vault.projectVaultList({
718
735
  manifest: state.manifest,
719
736
  runtime: state.vaultRuntime,
720
737
  journal: state.journalStore,
@@ -723,24 +740,29 @@ export function createConsoleState(
723
740
  });
724
741
  },
725
742
  setVault: async (input) => {
743
+ const vault = await markPanel<typeof import("./vault.ts")>("vault");
726
744
  if (!state.vaultRuntime) {
727
745
  throw new Error("Vault runtime not bound");
728
746
  }
729
- return setVaultValue(state.vaultRuntime, input);
747
+ return vault.setVaultValue(state.vaultRuntime, input);
730
748
  },
731
749
  rotateVault: async (input) => {
750
+ const vault = await markPanel<typeof import("./vault.ts")>("vault");
732
751
  if (!state.vaultRuntime) {
733
752
  throw new Error("Vault runtime not bound");
734
753
  }
735
- return rotateVaultValue(state.vaultRuntime, input);
754
+ return vault.rotateVaultValue(state.vaultRuntime, input);
736
755
  },
737
756
  identities: [...(options.identities ?? defaultDevIdentities())],
738
757
  production: options.production ?? process.env.NODE_ENV === "production",
739
758
  aiRuntime: null,
740
759
  evalResults: [],
741
760
  listAi: async () => {
761
+ const { ensureConsolePanelRuntimes } = await import("./app.ts");
762
+ await ensureConsolePanelRuntimes(state, "ai");
763
+ const ai = await markPanel<typeof import("./ai.ts")>("ai");
742
764
  const runs = await state.listRuns();
743
- return projectAiPanel({
765
+ return ai.projectAiPanel({
744
766
  manifest: state.manifest,
745
767
  aiRuntime: state.aiRuntime,
746
768
  runs,
@@ -748,8 +770,9 @@ export function createConsoleState(
748
770
  });
749
771
  },
750
772
  listDiff: async () => {
773
+ const diff = await markPanel<typeof import("./diff.ts")>("diff");
751
774
  const runs = await state.listRuns();
752
- return projectManifestDiff({
775
+ return diff.projectManifestDiff({
753
776
  before: state.previousManifest,
754
777
  after: state.manifest,
755
778
  runs,
@@ -758,29 +781,36 @@ export function createConsoleState(
758
781
  },
759
782
  okeConfig: options.okeConfig ?? null,
760
783
  pluginRegistry: options.pluginRegistry ?? null,
761
- listPlugins: async () =>
762
- projectPluginsList({
784
+ listPlugins: async () => {
785
+ const plugins = await markPanel<typeof import("./plugins.ts")>("plugins");
786
+ return plugins.projectPluginsList({
763
787
  manifest: state.manifest,
764
788
  config: state.okeConfig,
765
789
  registry: state.pluginRegistry,
766
790
  cwd: state.cwd,
767
791
  now: state.now,
768
792
  fetchNpm: false,
769
- }),
793
+ });
794
+ },
770
795
  channelRuntime: options.channelRuntime ?? null,
771
796
  channelInbox: options.channelInbox ?? null,
772
797
  channelCatalog: options.channelCatalog ?? {},
773
- listChannels: async () =>
774
- projectChannelsList({
798
+ listChannels: async () => {
799
+ const { ensureConsolePanelRuntimes } = await import("./app.ts");
800
+ await ensureConsolePanelRuntimes(state, "channels");
801
+ const channels = await markPanel<typeof import("./channels.ts")>("channels");
802
+ return channels.projectChannelsList({
775
803
  manifest: state.manifest,
776
804
  runtime: state.channelRuntime,
777
805
  inbox: state.channelInbox,
778
806
  production: state.production,
779
807
  now: state.now,
780
808
  catalog: state.channelCatalog,
781
- }),
782
- previewChannel: async (input) =>
783
- previewChannelTemplate({
809
+ });
810
+ },
811
+ previewChannel: async (input) => {
812
+ const channels = await markPanel<typeof import("./channels.ts")>("channels");
813
+ return channels.previewChannelTemplate({
784
814
  runtime: state.channelRuntime,
785
815
  manifest: state.manifest,
786
816
  catalog: state.channelCatalog,
@@ -789,20 +819,26 @@ export function createConsoleState(
789
819
  profileLocale: input.profileLocale,
790
820
  acceptLanguage: input.acceptLanguage,
791
821
  data: input.data,
792
- }),
793
- verifyChannelAuth: async (fromOrDomain) =>
794
- verifyChannelAuth(fromOrDomain),
795
- revealChannel: async (id) =>
796
- revealChannelRecipient({
822
+ });
823
+ },
824
+ verifyChannelAuth: async (fromOrDomain) => {
825
+ const channels = await markPanel<typeof import("./channels.ts")>("channels");
826
+ return channels.verifyChannelAuth(fromOrDomain);
827
+ },
828
+ revealChannel: async (id) => {
829
+ const channels = await markPanel<typeof import("./channels.ts")>("channels");
830
+ return channels.revealChannelRecipient({
797
831
  runtime: state.channelRuntime,
798
832
  inbox: state.channelInbox,
799
833
  id,
800
- }),
834
+ });
835
+ },
801
836
  sendChannelTest: async (input) => {
837
+ const channels = await markPanel<typeof import("./channels.ts")>("channels");
802
838
  if (!state.channelRuntime) {
803
839
  throw new Error("Channel runtime not bound");
804
840
  }
805
- return sendChannelTest(state.channelRuntime, input);
841
+ return channels.sendChannelTest(state.channelRuntime, input);
806
842
  },
807
843
  get setupClosed() {
808
844
  return operators.operators.size > 0;
@@ -823,16 +859,17 @@ export function bindAiRuntime(state: ConsoleState, runtime: AiRuntime): void {
823
859
  }
824
860
 
825
861
  /**
826
- * Resolve tool-flow effects from the current Manifest (for AiRuntime options).
862
+ * Resolve tool-flow effects from the current Manifest (lazy AI panel module).
827
863
  *
828
864
  * @param state - Console state
829
865
  * @param flowName - Tool flow
830
866
  */
831
- export function consoleEffectsForFlow(
867
+ export async function consoleEffectsForFlow(
832
868
  state: ConsoleState,
833
869
  flowName: string,
834
- ): ReturnType<typeof effectsForFlowFromManifest> {
835
- return effectsForFlowFromManifest(state.manifest, flowName);
870
+ ): Promise<readonly AgentToolEffect[]> {
871
+ const ai = await loadConsolePanel<typeof import("./ai.ts")>("ai");
872
+ return ai.effectsForFlowFromManifest(state.manifest, flowName);
836
873
  }
837
874
 
838
875
  /**