okengine 0.6.1 → 0.8.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.
Files changed (167) hide show
  1. package/AGENTS.md +2 -2
  2. package/README.md +73 -181
  3. package/package.json +3 -3
  4. package/site/content/docs/console/clock.mdx +25 -5
  5. package/site/content/docs/console/signals.mdx +13 -4
  6. package/site/content/docs/elements/ai.mdx +29 -2
  7. package/site/content/docs/elements/channel.mdx +42 -25
  8. package/site/content/docs/elements/clock.mdx +59 -25
  9. package/site/content/docs/elements/flow.mdx +8 -2
  10. package/site/content/docs/elements/gate.mdx +8 -1
  11. package/site/content/docs/elements/signal.mdx +173 -29
  12. package/site/content/docs/elements/store.mdx +595 -73
  13. package/site/content/docs/elements/vault.mdx +15 -5
  14. package/site/content/docs/get-started/basic-usage.mdx +13 -6
  15. package/site/content/docs/get-started/installation.mdx +52 -14
  16. package/site/content/docs/get-started/introduction.mdx +1 -1
  17. package/site/content/docs/plugins/magic-link.mdx +42 -0
  18. package/site/content/docs/plugins/phone-number.mdx +78 -17
  19. package/site/content/docs/plugins/two-factor.mdx +1 -0
  20. package/site/content/docs/reference/cli.md +32 -2
  21. package/site/content/docs/reference/configuration.mdx +15 -13
  22. package/site/content/docs/reference/environment-variables.mdx +32 -18
  23. package/site/content/docs/reference/errors.mdx +12 -11
  24. package/site/content/docs/reference/fx.mdx +15 -13
  25. package/site/content/docs/reference/security.md +3 -1
  26. package/src/cli/ai-setup/ai-setup.test.ts +144 -0
  27. package/src/cli/ai-setup/apply.ts +214 -0
  28. package/src/cli/ai-setup/catalog.ts +263 -0
  29. package/src/cli/ai-setup/detect-ollama.ts +166 -0
  30. package/src/cli/ai-setup/index.ts +228 -0
  31. package/src/cli/ai-setup/prompts.ts +649 -0
  32. package/src/cli/ai-setup/recommend.test.ts +100 -0
  33. package/src/cli/ai-setup/recommend.ts +203 -0
  34. package/src/cli/ai.ts +38 -0
  35. package/src/cli/db-auto-push.test.ts +6 -1
  36. package/src/cli/db-auto-push.ts +8 -3
  37. package/src/cli/db-seed.ts +359 -0
  38. package/src/cli/db.test.ts +341 -3
  39. package/src/cli/db.ts +75 -8
  40. package/src/cli/dev-db-push.test.ts +59 -0
  41. package/src/cli/dev.test.ts +40 -0
  42. package/src/cli/dev.ts +55 -1
  43. package/src/cli/docker-clean.test.ts +179 -0
  44. package/src/cli/docker-clean.ts +406 -0
  45. package/src/cli/docker.ts +16 -4
  46. package/src/cli/ensure-drizzle-config.ts +1 -1
  47. package/src/cli/hero-meta.test.ts +6 -5
  48. package/src/cli/hero-meta.ts +7 -1
  49. package/src/cli/index.ts +5 -0
  50. package/src/cli/load-config.images.test.ts +22 -0
  51. package/src/cli/load-config.ts +7 -2
  52. package/src/cli/openbao-bootstrap.test.ts +1 -0
  53. package/src/cli/openbao-bootstrap.ts +9 -2
  54. package/src/cli/registry.ts +116 -2
  55. package/src/client/live-gap.test.ts +35 -0
  56. package/src/client/transport.test.ts +21 -0
  57. package/src/client/transport.ts +27 -5
  58. package/src/compiler/effects-infer.ts +1 -0
  59. package/src/compiler/fixtures/skyport/oke.config.ts +1 -1
  60. package/src/config/define-config.test.ts +6 -6
  61. package/src/config/index.ts +5 -1
  62. package/src/console/server/console.test.ts +45 -0
  63. package/src/console/server/flows.ts +39 -9
  64. package/src/console/server/i18n.ts +41 -0
  65. package/src/console/server/vault.ts +12 -38
  66. package/src/console/ui/dist/assets/index-ClX0ZCe5.js +10 -0
  67. package/src/console/ui/dist/assets/{panel-access-BGv45snf.js → panel-access-ri1X9Otj.js} +1 -1
  68. package/src/console/ui/dist/assets/{panel-ai-B2S7LEii.js → panel-ai-DLHjRoJk.js} +1 -1
  69. package/src/console/ui/dist/assets/{panel-architecture-D7UJh91v.js → panel-architecture-DI3bQF3J.js} +1 -1
  70. package/src/console/ui/dist/assets/{panel-channels-9T3ybqRu.js → panel-channels-BDYWX29p.js} +1 -1
  71. package/src/console/ui/dist/assets/{panel-clock-Cb1UXGRQ.js → panel-clock-i-JpTjVB.js} +1 -1
  72. package/src/console/ui/dist/assets/{panel-diff-DmYbKWmN.js → panel-diff-CFuWxiXy.js} +1 -1
  73. package/src/console/ui/dist/assets/{panel-flows-PiHwT55z.js → panel-flows-B8TRhcoe.js} +1 -1
  74. package/src/console/ui/dist/assets/{panel-gates-BQGYXvjT.js → panel-gates-CfkBgco7.js} +1 -1
  75. package/src/console/ui/dist/assets/{panel-overview-BBnRO18l.js → panel-overview-DONDzBd2.js} +1 -1
  76. package/src/console/ui/dist/assets/{panel-plugins-D0PsmVw2.js → panel-plugins-DDJwTehL.js} +1 -1
  77. package/src/console/ui/dist/assets/{panel-runs-CWuRDe0r.js → panel-runs-D5zf-D9c.js} +1 -1
  78. package/src/console/ui/dist/assets/{panel-signals-Bbg4ewpP.js → panel-signals-Dsxdu_AR.js} +1 -1
  79. package/src/console/ui/dist/assets/{panel-store-CPCbsDRa.js → panel-store-hy7O8HOs.js} +1 -1
  80. package/src/console/ui/dist/assets/{panel-traces-DVAzuA_S.js → panel-traces-CBiAe5go.js} +1 -1
  81. package/src/console/ui/dist/assets/{panel-vault-D1_MvOmo.js → panel-vault-Za1GyJfM.js} +1 -1
  82. package/src/console/ui/dist/index.html +1 -1
  83. package/src/console/ui/shell/components/ui.tsx +5 -1
  84. package/src/console/ui/shell/setup/Wizard.tsx +26 -5
  85. package/src/docker/cleanup.test.ts +193 -0
  86. package/src/docker/cleanup.ts +355 -0
  87. package/src/docker/docker.test.ts +4 -0
  88. package/src/docker/index.ts +19 -0
  89. package/src/docker/recipes/ollama.ts +10 -5
  90. package/src/drivers/ai-ollama.ts +45 -2
  91. package/src/drivers/ai-providers.test.ts +31 -0
  92. package/src/drivers/channel-sently.test.ts +8 -0
  93. package/src/drivers/channel-taqnyat-mail.ts +34 -0
  94. package/src/drivers/channel-types.ts +71 -0
  95. package/src/drivers/clock-postgres.test.ts +258 -0
  96. package/src/drivers/clock-postgres.ts +410 -0
  97. package/src/drivers/index.ts +21 -0
  98. package/src/drivers/journal-postgres.test.ts +175 -0
  99. package/src/drivers/journal-postgres.ts +492 -0
  100. package/src/drivers/signal-engine.ts +98 -25
  101. package/src/drivers/signal-nats.ts +4 -4
  102. package/src/drivers/signal-postgres.ts +158 -64
  103. package/src/drivers/signal-redis.ts +4 -4
  104. package/src/drivers/signal-types.ts +61 -2
  105. package/src/drivers/vault-driver-removal.test.ts +5 -1
  106. package/src/elements/channel/runtime.ts +51 -0
  107. package/src/elements/channel.test.ts +71 -0
  108. package/src/elements/clock/chaos-child.ts +389 -0
  109. package/src/elements/clock/chaos.test.ts +204 -0
  110. package/src/elements/clock/durable.ts +7 -0
  111. package/src/elements/clock/reconcile.ts +110 -0
  112. package/src/elements/clock/runtime.ts +13 -0
  113. package/src/elements/clock.test.ts +164 -2
  114. package/src/elements/clock.ts +2 -1
  115. package/src/elements/gate/runtime.ts +6 -0
  116. package/src/elements/signal/chaos-child.ts +41 -4
  117. package/src/elements/signal/declare.ts +4 -1
  118. package/src/elements/signal/delivery-modes.test.ts +179 -0
  119. package/src/elements/signal/key-ordering.test.ts +306 -0
  120. package/src/elements/signal/lease-reclaim.test.ts +123 -0
  121. package/src/elements/signal/optional-emit.test.ts +76 -0
  122. package/src/elements/signal/order-lifecycle.test.ts +130 -0
  123. package/src/elements/signal/orphan-messages.test.ts +152 -0
  124. package/src/elements/signal/runtime.ts +11 -4
  125. package/src/elements/signal/schema-emit.test.ts +107 -0
  126. package/src/elements/signal.test.ts +89 -5
  127. package/src/elements/store/files-fx.ts +104 -0
  128. package/src/elements/store/files-image.test.ts +251 -0
  129. package/src/elements/store/files-image.ts +494 -0
  130. package/src/elements/store/runtime.ts +60 -0
  131. package/src/elements/store/seed.test.ts +27 -0
  132. package/src/elements/store/seed.ts +68 -0
  133. package/src/elements/store/sql-session.test.ts +39 -0
  134. package/src/elements/store/sql-session.ts +55 -0
  135. package/src/elements/store/upsert-app.test.ts +103 -0
  136. package/src/elements/store.ts +29 -0
  137. package/src/elements/vault/boot-chain.ts +150 -0
  138. package/src/elements/vault/runtime.ts +8 -0
  139. package/src/index.ts +15 -0
  140. package/src/kernel/app.ts +168 -15
  141. package/src/kernel/boot-bind/channel.test.ts +16 -0
  142. package/src/kernel/boot-bind/channel.ts +13 -0
  143. package/src/kernel/boot-bind/clock.ts +63 -7
  144. package/src/kernel/boot-bind/gate.ts +71 -3
  145. package/src/kernel/boot-bind/honor-config.test.ts +348 -0
  146. package/src/kernel/boot-bind/journal.ts +89 -0
  147. package/src/kernel/boot-bind/signal.ts +64 -7
  148. package/src/kernel/boot-bind/vault.ts +27 -8
  149. package/src/kernel/boot.test.ts +6 -4
  150. package/src/kernel/boot.ts +63 -15
  151. package/src/kernel/concurrency.ts +1 -1
  152. package/src/kernel/errors.ts +8 -2
  153. package/src/kernel/fx.test.ts +19 -0
  154. package/src/kernel/fx.ts +153 -9
  155. package/src/kernel/index.ts +6 -0
  156. package/src/kernel/journal-boot.test.ts +397 -0
  157. package/src/kernel/journal-suspend.ts +35 -0
  158. package/src/kernel/journal.test.ts +142 -0
  159. package/src/kernel/journal.ts +202 -27
  160. package/src/plugins/auth-methods.security.test.ts +10 -7
  161. package/src/plugins/phone-number.ts +67 -10
  162. package/src/plugins/taqnyat.live.test.ts +174 -0
  163. package/src/runtime/dev-request-log.test.ts +20 -1
  164. package/src/runtime/dev-request-log.ts +38 -0
  165. package/src/term.test.ts +15 -0
  166. package/src/term.ts +8 -3
  167. package/src/console/ui/dist/assets/index-CjxwRGVv.js +0 -10
@@ -7,8 +7,10 @@
7
7
  import { z } from "zod";
8
8
  import {
9
9
  authenticateOperator,
10
+ BreachCheckError,
10
11
  createOperator,
11
12
  issueSession,
13
+ PasswordPolicyError,
12
14
  scopesForRoles,
13
15
  userPrincipal,
14
16
  type IssuedSession,
@@ -24,6 +26,7 @@ import { maskWideEventForConsole, piiFieldNamesFromManifest } from "./runs-pii.t
24
26
  import { ClockResourceNotFoundError, ScheduleNotOverridableError } from "./clock.ts";
25
27
  import { createFileDiff, emitStructuralDiff } from "./structural.ts";
26
28
  import type { ConsoleState } from "./state.ts";
29
+ import { consoleFailureMessage } from "./i18n.ts";
27
30
  import { PUBLIC_CONSOLE_FLOWS } from "./public-flows.ts";
28
31
  import { tenancyDeclared } from "./store.ts";
29
32
 
@@ -38,7 +41,8 @@ const ClaimIn = z.object({
38
41
  claimCode: z.string().min(1),
39
42
  email: z.string().email(),
40
43
  name: z.string().min(1),
41
- password: z.string().min(8),
44
+ /** Matches default operator password policy (minLength 12). */
45
+ password: z.string().min(12),
42
46
  });
43
47
 
44
48
  const SessionOut = z.object({
@@ -292,7 +296,11 @@ const InvokeOut = z.object({
292
296
  });
293
297
 
294
298
  const SetupClosed = z.object({ reason: z.string() });
295
- const ClaimFailed = z.object({ reason: z.string() });
299
+ const ClaimFailed = z.object({
300
+ reason: z.string(),
301
+ /** Password-policy detail lines when `reason` is `password_policy`. */
302
+ reasons: z.array(z.string()).optional(),
303
+ });
296
304
  const AuthFailed = z.object({});
297
305
  const AuthRateLimited = z.object({ reason: z.string() });
298
306
  const NotFound = z.object({ flowId: z.string() });
@@ -1688,17 +1696,39 @@ function createSetupClaim(state: ConsoleState) {
1688
1696
  errors: { SetupClosed, ClaimFailed },
1689
1697
  do: async (input: z.infer<typeof ClaimIn>, fx) => {
1690
1698
  if (state.setupClosed) {
1691
- return fail("SetupClosed", { reason: "first operator already exists" });
1699
+ const data = { reason: "first_operator_exists" };
1700
+ return fail("SetupClosed", data, { message: consoleFailureMessage("SetupClosed", data) });
1692
1701
  }
1693
1702
  const verified = verifyClaimCode(state.claim, input.claimCode, state.now);
1694
1703
  if (!verified.ok) {
1695
- return fail("ClaimFailed", { reason: verified.reason });
1704
+ const data = { reason: verified.reason };
1705
+ return fail("ClaimFailed", data, { message: consoleFailureMessage("ClaimFailed", data) });
1706
+ }
1707
+ let op: Awaited<ReturnType<typeof createOperator>>;
1708
+ try {
1709
+ op = await createOperator(state.operators, {
1710
+ email: input.email,
1711
+ name: input.name,
1712
+ password: input.password,
1713
+ });
1714
+ } catch (err) {
1715
+ if (err instanceof PasswordPolicyError) {
1716
+ const data = {
1717
+ reason: "password_policy",
1718
+ reasons: [...err.reasons],
1719
+ };
1720
+ return fail("ClaimFailed", data, {
1721
+ message: consoleFailureMessage("ClaimFailed", data),
1722
+ });
1723
+ }
1724
+ if (err instanceof BreachCheckError) {
1725
+ const data = { reason: "password_breached" };
1726
+ return fail("ClaimFailed", data, {
1727
+ message: consoleFailureMessage("ClaimFailed", data),
1728
+ });
1729
+ }
1730
+ throw err;
1696
1731
  }
1697
- const op = await createOperator(state.operators, {
1698
- email: input.email,
1699
- name: input.name,
1700
- password: input.password,
1701
- });
1702
1732
  state.persistOperator(op.id);
1703
1733
  const issued = await issueOperatorSession(state, op.id);
1704
1734
  fx.log.info("console.setup.claim", { operatorId: op.id });
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Console-only failure copy — kept out of kernel built-in catalogs so the
3
+ * edge profile and app exports do not pay for operator-claim strings.
4
+ */
5
+
6
+ const en = {
7
+ ClaimFailed: "Could not create the first operator.",
8
+ "ClaimFailed.mismatch": "That claim code does not match. Copy it from the boot log.",
9
+ "ClaimFailed.expired": "That claim code expired. Restart `oke dev` for a new one.",
10
+ "ClaimFailed.rate_limited": "Too many claim attempts. Wait a minute and try again.",
11
+ "ClaimFailed.missing": "No claim code is active. Restart `oke dev` to mint one.",
12
+ "ClaimFailed.password_policy":
13
+ "Password needs at least 12 characters, including a letter and a number.",
14
+ "ClaimFailed.password_breached":
15
+ "Choose a different password — this one appears in a breach list.",
16
+ SetupClosed: "Setup is closed — an operator already exists. Sign in instead.",
17
+ "SetupClosed.first_operator_exists":
18
+ "Setup is closed — an operator already exists. Sign in instead.",
19
+ } as const;
20
+
21
+ /**
22
+ * Resolve a Console claim/setup failure message (English; boot log is EN).
23
+ *
24
+ * @param code - Failure code
25
+ * @param data - Failure data (may include `reason`)
26
+ */
27
+ export function consoleFailureMessage(code: string, data?: unknown): string {
28
+ const reason =
29
+ data !== null &&
30
+ data !== undefined &&
31
+ typeof data === "object" &&
32
+ "reason" in data &&
33
+ typeof (data as { reason: unknown }).reason === "string"
34
+ ? (data as { reason: string }).reason
35
+ : undefined;
36
+ if (reason) {
37
+ const keyed = en[`${code}.${reason}` as keyof typeof en];
38
+ if (keyed !== undefined) return keyed;
39
+ }
40
+ return en[code as keyof typeof en] ?? code;
41
+ }
@@ -6,21 +6,16 @@
6
6
  * rotation blast radius are derived — never reimplemented in the UI.
7
7
  */
8
8
 
9
- import { readFileSync } from "node:fs";
10
- import { resolve } from "node:path";
11
9
  import type { ConfigEnv } from "../../config/index.ts";
12
- import { envVaultDriver, memoryVaultDriver, openbaoVaultDriver } from "../../drivers/index.ts";
13
- import { parseDotenv } from "../../drivers/vault-dotenv-parse.ts";
10
+ import { buildVaultBootChain } from "../../elements/vault/boot-chain.ts";
14
11
  import {
15
12
  createVaultRuntime,
16
13
  vault as declareVault,
17
- type VaultChainLayer,
18
14
  type VaultResolutionSource,
19
15
  type VaultResolutionStep,
20
16
  type VaultRuntime,
21
17
  type VaultSecretDecl,
22
18
  } from "../../elements/vault.ts";
23
- import { resolveComposeEnvPath } from "../../elements/vault/chain.ts";
24
19
  import type { JournalRun, JournalStore } from "../../kernel/journal.ts";
25
20
  import type { Manifest } from "../../manifest/types.ts";
26
21
 
@@ -236,41 +231,20 @@ export async function createManifestVaultRuntime(
236
231
  });
237
232
 
238
233
  const seed = options.seed ?? {};
239
- const composeEnv = resolveComposeEnvPath(cwd);
240
- const envMap = parseDotenv(readFileSync(composeEnv.path, "utf8").toString());
241
- const openbaoUrl = process.env.OKE_VAULT_URL ?? envMap.get("OKE_VAULT_URL");
242
- const openbaoToken = process.env.OKE_VAULT_TOKEN ?? envMap.get("OKE_VAULT_TOKEN");
243
- const openbaoMount = process.env.OKE_VAULT_MOUNT ?? envMap.get("OKE_VAULT_MOUNT") ?? "secret";
244
- const driverLayer: VaultChainLayer =
245
- openbaoUrl && openbaoToken
246
- ? {
247
- driver: openbaoVaultDriver,
248
- source: "driver",
249
- options: { url: openbaoUrl, token: openbaoToken, mount: openbaoMount },
250
- }
251
- : {
252
- driver: memoryVaultDriver,
253
- source: "driver",
254
- options: { secrets: seed },
255
- };
234
+ const env = options.env ?? "local";
235
+ // Auto-detect: prefer OpenBao when credentials exist; soft-fallback to memory
236
+ // (historical Console behaviour never fail the Console for missing vault).
256
237
  const runtime = createVaultRuntime({
257
238
  secrets,
258
- allowDevFallbacks: options.allowDevFallbacks ?? (options.env ?? "local") !== "prod",
239
+ allowDevFallbacks: options.allowDevFallbacks ?? env !== "prod",
259
240
  now: options.now,
260
- chain: [
261
- { driver: envVaultDriver, source: "process.env" },
262
- {
263
- driver: envVaultDriver,
264
- source: ".env.local",
265
- options: { path: resolve(cwd, ".env.local") },
266
- },
267
- {
268
- driver: envVaultDriver,
269
- source: composeEnv.source,
270
- options: { path: composeEnv.path },
271
- },
272
- driverLayer,
273
- ],
241
+ chain: buildVaultBootChain({
242
+ cwd,
243
+ driverId: "openbao",
244
+ env,
245
+ seed,
246
+ missingOpenbao: "memory",
247
+ }),
274
248
  });
275
249
  await runtime.boot();
276
250
  return runtime;