okengine 0.1.4

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 (674) hide show
  1. package/AGENTS.md +91 -0
  2. package/README.md +327 -0
  3. package/docs/spec/complete-example.md +1188 -0
  4. package/docs/spec/console.md +739 -0
  5. package/docs/spec/four-applications.md +1188 -0
  6. package/docs/spec/unified-theory.md +489 -0
  7. package/package.json +152 -0
  8. package/spec/manifest.v1.schema.json +624 -0
  9. package/src/auth/api-keys.ts +168 -0
  10. package/src/auth/attenuation.ts +116 -0
  11. package/src/auth/auth.test.ts +273 -0
  12. package/src/auth/cross-plane.ts +98 -0
  13. package/src/auth/index.ts +112 -0
  14. package/src/auth/invites.ts +66 -0
  15. package/src/auth/invoke-as.ts +49 -0
  16. package/src/auth/operator.ts +178 -0
  17. package/src/auth/planes.ts +102 -0
  18. package/src/auth/plugin.ts +44 -0
  19. package/src/auth/roles.ts +84 -0
  20. package/src/auth/sessions.ts +418 -0
  21. package/src/auth/tables.ts +131 -0
  22. package/src/cli/args.ts +50 -0
  23. package/src/cli/branch.ts +75 -0
  24. package/src/cli/build.ts +86 -0
  25. package/src/cli/client-add.test.ts +140 -0
  26. package/src/cli/client-add.ts +164 -0
  27. package/src/cli/completion.test.ts +58 -0
  28. package/src/cli/completion.ts +296 -0
  29. package/src/cli/dev-app-runner.ts +77 -0
  30. package/src/cli/dev.test.ts +435 -0
  31. package/src/cli/dev.ts +594 -0
  32. package/src/cli/doc-drift.test.ts +146 -0
  33. package/src/cli/doc-drift.ts +397 -0
  34. package/src/cli/docker-cli.test.ts +221 -0
  35. package/src/cli/docker.ts +127 -0
  36. package/src/cli/doctor-diff-examples.ts +92 -0
  37. package/src/cli/doctor-diff.test.ts +91 -0
  38. package/src/cli/doctor-diff.ts +274 -0
  39. package/src/cli/doctor-pii.test.ts +98 -0
  40. package/src/cli/doctor-pii.ts +151 -0
  41. package/src/cli/doctor.test.ts +150 -0
  42. package/src/cli/doctor.ts +223 -0
  43. package/src/cli/eval.ts +122 -0
  44. package/src/cli/exit.ts +19 -0
  45. package/src/cli/gates-list.test.ts +47 -0
  46. package/src/cli/gates-list.ts +84 -0
  47. package/src/cli/images.ts +277 -0
  48. package/src/cli/index.ts +99 -0
  49. package/src/cli/json-out.test.ts +129 -0
  50. package/src/cli/load-config.ts +71 -0
  51. package/src/cli/mcp-from-console.ts +50 -0
  52. package/src/cli/privacy-erase.ts +73 -0
  53. package/src/cli/registry.ts +455 -0
  54. package/src/cli/safe-defaults.test.ts +92 -0
  55. package/src/cli/schema.ts +196 -0
  56. package/src/cli/stack.ts +82 -0
  57. package/src/cli/start.ts +106 -0
  58. package/src/cli/upgrade.ts +105 -0
  59. package/src/cli/vault-cmd.ts +140 -0
  60. package/src/client/budget-entry.ts +34 -0
  61. package/src/client/budget.test.ts +17 -0
  62. package/src/client/create.test.ts +159 -0
  63. package/src/client/create.ts +152 -0
  64. package/src/client/errors.ts +60 -0
  65. package/src/client/index.ts +35 -0
  66. package/src/client/notes-contract.test.ts +289 -0
  67. package/src/client/transport.test.ts +123 -0
  68. package/src/client/transport.ts +254 -0
  69. package/src/client/types.ts +282 -0
  70. package/src/compiler/aot.test.ts +248 -0
  71. package/src/compiler/aot.ts +182 -0
  72. package/src/compiler/differential.test.ts +241 -0
  73. package/src/compiler/dynamic.ts +54 -0
  74. package/src/compiler/effects-infer.ts +541 -0
  75. package/src/compiler/emit.ts +40 -0
  76. package/src/compiler/extract.test.ts +177 -0
  77. package/src/compiler/extract.ts +1368 -0
  78. package/src/compiler/fixtures/raw/raw-unannotated.ts +28 -0
  79. package/src/compiler/fixtures/skyport/oke.config.ts +24 -0
  80. package/src/compiler/fixtures/skyport/src/ai.ts +15 -0
  81. package/src/compiler/fixtures/skyport/src/app.ts +10 -0
  82. package/src/compiler/fixtures/skyport/src/channels.ts +6 -0
  83. package/src/compiler/fixtures/skyport/src/core.ts +3 -0
  84. package/src/compiler/fixtures/skyport/src/flows/bookings/index.ts +57 -0
  85. package/src/compiler/fixtures/skyport/src/flows/bookings/signals.ts +11 -0
  86. package/src/compiler/fixtures/skyport/src/flows/payments/index.ts +14 -0
  87. package/src/compiler/fixtures/skyport/src/flows/support/index.ts +20 -0
  88. package/src/compiler/fixtures/skyport/src/gates.ts +14 -0
  89. package/src/compiler/fixtures/skyport/src/journeys.ts +9 -0
  90. package/src/compiler/fixtures/skyport/src/schema.ts +3 -0
  91. package/src/compiler/fixtures/skyport/src/vault.ts +6 -0
  92. package/src/compiler/fixtures/skyport.expected.json +241 -0
  93. package/src/compiler/fixtures/triggers/five-triggers.ts +69 -0
  94. package/src/compiler/http-parse.ts +214 -0
  95. package/src/compiler/index.ts +67 -0
  96. package/src/compiler/response.ts +89 -0
  97. package/src/compiler/sucrose.ts +238 -0
  98. package/src/config/index.ts +167 -0
  99. package/src/console/budget.test.ts +73 -0
  100. package/src/console/index.ts +30 -0
  101. package/src/console/server/access.test.ts +370 -0
  102. package/src/console/server/access.ts +777 -0
  103. package/src/console/server/ai.test.ts +172 -0
  104. package/src/console/server/ai.ts +632 -0
  105. package/src/console/server/app.ts +294 -0
  106. package/src/console/server/auth-rate.test.ts +81 -0
  107. package/src/console/server/auth-rate.ts +72 -0
  108. package/src/console/server/bind.ts +25 -0
  109. package/src/console/server/channels.test.ts +179 -0
  110. package/src/console/server/channels.ts +469 -0
  111. package/src/console/server/claim.test.ts +66 -0
  112. package/src/console/server/claim.ts +134 -0
  113. package/src/console/server/clock.test.ts +239 -0
  114. package/src/console/server/clock.ts +390 -0
  115. package/src/console/server/console.test.ts +338 -0
  116. package/src/console/server/diff.test.ts +299 -0
  117. package/src/console/server/diff.ts +352 -0
  118. package/src/console/server/dry-run.audit.test.ts +118 -0
  119. package/src/console/server/flows-invoke.test.ts +148 -0
  120. package/src/console/server/flows.ts +3633 -0
  121. package/src/console/server/gates.test.ts +360 -0
  122. package/src/console/server/gates.ts +869 -0
  123. package/src/console/server/index.ts +141 -0
  124. package/src/console/server/live.test.ts +30 -0
  125. package/src/console/server/live.ts +109 -0
  126. package/src/console/server/plugin.ts +50 -0
  127. package/src/console/server/plugins.test.ts +131 -0
  128. package/src/console/server/plugins.ts +429 -0
  129. package/src/console/server/runs-pii.ts +98 -0
  130. package/src/console/server/security-headers.ts +97 -0
  131. package/src/console/server/security.gate.test.ts +286 -0
  132. package/src/console/server/serve.ts +319 -0
  133. package/src/console/server/signals.test.ts +88 -0
  134. package/src/console/server/signals.ts +282 -0
  135. package/src/console/server/state.ts +982 -0
  136. package/src/console/server/store.test.ts +233 -0
  137. package/src/console/server/store.ts +861 -0
  138. package/src/console/server/structural.ts +95 -0
  139. package/src/console/server/vault.test.ts +251 -0
  140. package/src/console/server/vault.ts +430 -0
  141. package/src/console/ui/access/AccessA11yView.tsx +237 -0
  142. package/src/console/ui/access/a11y.test.tsx +122 -0
  143. package/src/console/ui/access/acknowledgement.test.ts +13 -0
  144. package/src/console/ui/access/acknowledgement.ts +35 -0
  145. package/src/console/ui/access/blast-radius.test.ts +26 -0
  146. package/src/console/ui/access/blast-radius.ts +40 -0
  147. package/src/console/ui/access/confirmation.test.ts +38 -0
  148. package/src/console/ui/access/confirmation.ts +36 -0
  149. package/src/console/ui/access/fixture.ts +203 -0
  150. package/src/console/ui/access/grantable.test.ts +17 -0
  151. package/src/console/ui/access/grantable.ts +36 -0
  152. package/src/console/ui/access/hygiene.test.ts +12 -0
  153. package/src/console/ui/access/hygiene.ts +39 -0
  154. package/src/console/ui/access/index.ts +54 -0
  155. package/src/console/ui/access/provenance.test.ts +12 -0
  156. package/src/console/ui/access/provenance.ts +29 -0
  157. package/src/console/ui/access/search.test.ts +17 -0
  158. package/src/console/ui/access/search.ts +72 -0
  159. package/src/console/ui/access/types.ts +111 -0
  160. package/src/console/ui/ai/AiA11yView.tsx +265 -0
  161. package/src/console/ui/ai/a11y.test.tsx +99 -0
  162. package/src/console/ui/ai/findings.ts +41 -0
  163. package/src/console/ui/ai/fixture.ts +182 -0
  164. package/src/console/ui/ai/format.ts +90 -0
  165. package/src/console/ui/ai/group.test.ts +37 -0
  166. package/src/console/ui/ai/group.ts +88 -0
  167. package/src/console/ui/ai/index.ts +66 -0
  168. package/src/console/ui/ai/promotion.test.ts +77 -0
  169. package/src/console/ui/ai/promotion.ts +150 -0
  170. package/src/console/ui/ai/search.test.ts +40 -0
  171. package/src/console/ui/ai/search.ts +89 -0
  172. package/src/console/ui/ai/types.ts +139 -0
  173. package/src/console/ui/architecture/ArchitectureA11yView.tsx +163 -0
  174. package/src/console/ui/architecture/a11y.test.tsx +97 -0
  175. package/src/console/ui/architecture/boundary.ts +42 -0
  176. package/src/console/ui/architecture/declared.ts +165 -0
  177. package/src/console/ui/architecture/fixture.ts +74 -0
  178. package/src/console/ui/architecture/index.ts +84 -0
  179. package/src/console/ui/architecture/layers.ts +64 -0
  180. package/src/console/ui/architecture/layout.ts +68 -0
  181. package/src/console/ui/architecture/pathologies.ts +260 -0
  182. package/src/console/ui/architecture/search.ts +145 -0
  183. package/src/console/ui/architecture/traffic.ts +102 -0
  184. package/src/console/ui/architecture/types.ts +144 -0
  185. package/src/console/ui/architecture/view.test.ts +165 -0
  186. package/src/console/ui/architecture/view.ts +516 -0
  187. package/src/console/ui/channels/ChannelsA11yView.tsx +180 -0
  188. package/src/console/ui/channels/a11y.test.tsx +96 -0
  189. package/src/console/ui/channels/confirmation.test.ts +37 -0
  190. package/src/console/ui/channels/confirmation.ts +27 -0
  191. package/src/console/ui/channels/fallback.test.ts +15 -0
  192. package/src/console/ui/channels/fallback.ts +20 -0
  193. package/src/console/ui/channels/findings.ts +38 -0
  194. package/src/console/ui/channels/fixture.ts +134 -0
  195. package/src/console/ui/channels/group.ts +25 -0
  196. package/src/console/ui/channels/index.ts +57 -0
  197. package/src/console/ui/channels/locale.test.ts +17 -0
  198. package/src/console/ui/channels/locale.ts +31 -0
  199. package/src/console/ui/channels/mask.test.ts +14 -0
  200. package/src/console/ui/channels/mask.ts +12 -0
  201. package/src/console/ui/channels/search.ts +58 -0
  202. package/src/console/ui/channels/taxonomy.test.ts +17 -0
  203. package/src/console/ui/channels/taxonomy.ts +49 -0
  204. package/src/console/ui/channels/types.ts +117 -0
  205. package/src/console/ui/clock/ClockA11yView.tsx +182 -0
  206. package/src/console/ui/clock/a11y.test.tsx +99 -0
  207. package/src/console/ui/clock/confirmation.test.ts +32 -0
  208. package/src/console/ui/clock/confirmation.ts +34 -0
  209. package/src/console/ui/clock/findings.ts +40 -0
  210. package/src/console/ui/clock/fixture.ts +111 -0
  211. package/src/console/ui/clock/health.test.ts +25 -0
  212. package/src/console/ui/clock/health.ts +61 -0
  213. package/src/console/ui/clock/index.ts +49 -0
  214. package/src/console/ui/clock/search.test.ts +39 -0
  215. package/src/console/ui/clock/search.ts +76 -0
  216. package/src/console/ui/clock/timeline.test.ts +44 -0
  217. package/src/console/ui/clock/timeline.ts +41 -0
  218. package/src/console/ui/clock/types.ts +78 -0
  219. package/src/console/ui/clock/waiting-on.test.ts +34 -0
  220. package/src/console/ui/clock/waiting-on.ts +83 -0
  221. package/src/console/ui/confirmation.unify.test.ts +92 -0
  222. package/src/console/ui/diff/DiffA11yView.tsx +85 -0
  223. package/src/console/ui/diff/a11y.test.tsx +99 -0
  224. package/src/console/ui/diff/fixture.ts +85 -0
  225. package/src/console/ui/diff/group.test.ts +58 -0
  226. package/src/console/ui/diff/group.ts +97 -0
  227. package/src/console/ui/diff/index.ts +38 -0
  228. package/src/console/ui/diff/search.test.ts +32 -0
  229. package/src/console/ui/diff/search.ts +75 -0
  230. package/src/console/ui/diff/summary.ts +74 -0
  231. package/src/console/ui/diff/types.ts +48 -0
  232. package/src/console/ui/dist/assets/index-B71Yl_SS.js +10 -0
  233. package/src/console/ui/dist/assets/panel-access-Dd37LU2c.js +64 -0
  234. package/src/console/ui/dist/assets/panel-ai-CC7LR6-J.js +1 -0
  235. package/src/console/ui/dist/assets/panel-architecture-B5b3iKCz.js +1 -0
  236. package/src/console/ui/dist/assets/panel-channels-CeNjTKXp.js +1 -0
  237. package/src/console/ui/dist/assets/panel-clock-DgFTLoHV.js +1 -0
  238. package/src/console/ui/dist/assets/panel-diff-DxehccqB.js +1 -0
  239. package/src/console/ui/dist/assets/panel-flows-BtrVn-Eg.js +45 -0
  240. package/src/console/ui/dist/assets/panel-gates-Z9MKRGdH.js +1 -0
  241. package/src/console/ui/dist/assets/panel-overview-Bd48d9km.js +1 -0
  242. package/src/console/ui/dist/assets/panel-plugins-DWd0TowH.js +1 -0
  243. package/src/console/ui/dist/assets/panel-runs-BwsWqKeB.js +1 -0
  244. package/src/console/ui/dist/assets/panel-signals-9najbZY2.js +1 -0
  245. package/src/console/ui/dist/assets/panel-store-OHkP2pDp.js +1 -0
  246. package/src/console/ui/dist/assets/panel-traces-tn2JoY8U.js +1 -0
  247. package/src/console/ui/dist/assets/panel-vault-BbfWdox0.js +1 -0
  248. package/src/console/ui/dist/assets/rolldown-runtime-CNC7AqOf.js +1 -0
  249. package/src/console/ui/dist/assets/style-Cnl7WLya.css +3 -0
  250. package/src/console/ui/dist/index.html +14 -0
  251. package/src/console/ui/flows/FlowsA11yView.tsx +155 -0
  252. package/src/console/ui/flows/a11y.test.tsx +105 -0
  253. package/src/console/ui/flows/buffer.test.ts +91 -0
  254. package/src/console/ui/flows/buffer.ts +118 -0
  255. package/src/console/ui/flows/confirmation.ts +131 -0
  256. package/src/console/ui/flows/contract.test.ts +89 -0
  257. package/src/console/ui/flows/contract.ts +353 -0
  258. package/src/console/ui/flows/fixture.ts +81 -0
  259. package/src/console/ui/flows/graph.test.ts +101 -0
  260. package/src/console/ui/flows/graph.ts +549 -0
  261. package/src/console/ui/flows/index.ts +87 -0
  262. package/src/console/ui/flows/save-as-test.test.ts +47 -0
  263. package/src/console/ui/flows/save-as-test.ts +99 -0
  264. package/src/console/ui/flows/search.ts +255 -0
  265. package/src/console/ui/flows/tiers.ts +140 -0
  266. package/src/console/ui/gates/GatesA11yView.tsx +192 -0
  267. package/src/console/ui/gates/a11y.test.tsx +116 -0
  268. package/src/console/ui/gates/audit.test.ts +40 -0
  269. package/src/console/ui/gates/audit.ts +63 -0
  270. package/src/console/ui/gates/denial.test.ts +36 -0
  271. package/src/console/ui/gates/denial.ts +51 -0
  272. package/src/console/ui/gates/findings.ts +19 -0
  273. package/src/console/ui/gates/fixture.ts +189 -0
  274. package/src/console/ui/gates/group.test.ts +30 -0
  275. package/src/console/ui/gates/group.ts +102 -0
  276. package/src/console/ui/gates/index.ts +47 -0
  277. package/src/console/ui/gates/search.test.ts +49 -0
  278. package/src/console/ui/gates/search.ts +115 -0
  279. package/src/console/ui/gates/types.ts +121 -0
  280. package/src/console/ui/overview/OverviewA11yView.tsx +152 -0
  281. package/src/console/ui/overview/a11y.test.tsx +113 -0
  282. package/src/console/ui/overview/busiest.ts +26 -0
  283. package/src/console/ui/overview/compose.ts +133 -0
  284. package/src/console/ui/overview/cost.test.ts +39 -0
  285. package/src/console/ui/overview/cost.ts +138 -0
  286. package/src/console/ui/overview/fixture.ts +161 -0
  287. package/src/console/ui/overview/golden.ts +57 -0
  288. package/src/console/ui/overview/index.ts +59 -0
  289. package/src/console/ui/overview/rank.test.ts +136 -0
  290. package/src/console/ui/overview/rank.ts +210 -0
  291. package/src/console/ui/overview/slo.test.ts +73 -0
  292. package/src/console/ui/overview/slo.ts +229 -0
  293. package/src/console/ui/overview/types.ts +121 -0
  294. package/src/console/ui/overview/verdict.ts +131 -0
  295. package/src/console/ui/plugins/PluginsA11yView.tsx +227 -0
  296. package/src/console/ui/plugins/a11y.test.tsx +97 -0
  297. package/src/console/ui/plugins/command.test.ts +22 -0
  298. package/src/console/ui/plugins/command.ts +27 -0
  299. package/src/console/ui/plugins/findings.ts +39 -0
  300. package/src/console/ui/plugins/fixture.ts +233 -0
  301. package/src/console/ui/plugins/group.test.ts +38 -0
  302. package/src/console/ui/plugins/group.ts +67 -0
  303. package/src/console/ui/plugins/index.ts +40 -0
  304. package/src/console/ui/plugins/search.ts +67 -0
  305. package/src/console/ui/plugins/types.ts +115 -0
  306. package/src/console/ui/runs/RunsA11yView.tsx +267 -0
  307. package/src/console/ui/runs/a11y.test.tsx +99 -0
  308. package/src/console/ui/runs/explain.test.ts +23 -0
  309. package/src/console/ui/runs/explain.ts +32 -0
  310. package/src/console/ui/runs/fixture.ts +189 -0
  311. package/src/console/ui/runs/group.test.ts +24 -0
  312. package/src/console/ui/runs/group.ts +85 -0
  313. package/src/console/ui/runs/histogram.test.ts +31 -0
  314. package/src/console/ui/runs/histogram.ts +85 -0
  315. package/src/console/ui/runs/index.ts +75 -0
  316. package/src/console/ui/runs/project.ts +122 -0
  317. package/src/console/ui/runs/query.test.ts +50 -0
  318. package/src/console/ui/runs/query.ts +283 -0
  319. package/src/console/ui/runs/search.test.ts +45 -0
  320. package/src/console/ui/runs/search.ts +141 -0
  321. package/src/console/ui/runs/trace-link.test.ts +30 -0
  322. package/src/console/ui/runs/trace-link.ts +99 -0
  323. package/src/console/ui/runs/types.ts +137 -0
  324. package/src/console/ui/shell/App.tsx +56 -0
  325. package/src/console/ui/shell/client.ts +1715 -0
  326. package/src/console/ui/shell/components/ui.tsx +110 -0
  327. package/src/console/ui/shell/index.html +12 -0
  328. package/src/console/ui/shell/layout/Shell.tsx +95 -0
  329. package/src/console/ui/shell/main.tsx +281 -0
  330. package/src/console/ui/shell/panels/Access.tsx +5 -0
  331. package/src/console/ui/shell/panels/Ai.tsx +5 -0
  332. package/src/console/ui/shell/panels/Architecture.tsx +5 -0
  333. package/src/console/ui/shell/panels/Channels.tsx +5 -0
  334. package/src/console/ui/shell/panels/Clock.tsx +5 -0
  335. package/src/console/ui/shell/panels/Diff.tsx +5 -0
  336. package/src/console/ui/shell/panels/Flows.tsx +5 -0
  337. package/src/console/ui/shell/panels/Gates.tsx +5 -0
  338. package/src/console/ui/shell/panels/Overview.tsx +6 -0
  339. package/src/console/ui/shell/panels/Plugins.tsx +5 -0
  340. package/src/console/ui/shell/panels/Runs.tsx +5 -0
  341. package/src/console/ui/shell/panels/Signals.tsx +5 -0
  342. package/src/console/ui/shell/panels/Store.tsx +5 -0
  343. package/src/console/ui/shell/panels/Traces.tsx +5 -0
  344. package/src/console/ui/shell/panels/Vault.tsx +5 -0
  345. package/src/console/ui/shell/panels/access/AccessPanel.tsx +813 -0
  346. package/src/console/ui/shell/panels/ai/AiPanel.tsx +563 -0
  347. package/src/console/ui/shell/panels/architecture/ArchitecturePanel.tsx +377 -0
  348. package/src/console/ui/shell/panels/channels/ChannelsPanel.tsx +454 -0
  349. package/src/console/ui/shell/panels/clock/ClockPanel.tsx +479 -0
  350. package/src/console/ui/shell/panels/diff/DiffPanel.tsx +275 -0
  351. package/src/console/ui/shell/panels/flows/ContractEditor.tsx +301 -0
  352. package/src/console/ui/shell/panels/flows/FlowDrawer.tsx +350 -0
  353. package/src/console/ui/shell/panels/flows/FlowsPanel.tsx +502 -0
  354. package/src/console/ui/shell/panels/gates/GatesPanel.tsx +482 -0
  355. package/src/console/ui/shell/panels/overview/OverviewPanel.tsx +428 -0
  356. package/src/console/ui/shell/panels/plugins/PluginsPanel.tsx +413 -0
  357. package/src/console/ui/shell/panels/runs/RunsPanel.tsx +649 -0
  358. package/src/console/ui/shell/panels/signals/SignalsPanel.tsx +840 -0
  359. package/src/console/ui/shell/panels/store/StorePanel.tsx +787 -0
  360. package/src/console/ui/shell/panels/traces/TracesPanel.tsx +539 -0
  361. package/src/console/ui/shell/panels/vault/VaultPanel.tsx +449 -0
  362. package/src/console/ui/shell/plugin/Sandbox.tsx +29 -0
  363. package/src/console/ui/shell/setup/Wizard.tsx +189 -0
  364. package/src/console/ui/shell/styles.css +75 -0
  365. package/src/console/ui/signals/SignalsA11yView.tsx +276 -0
  366. package/src/console/ui/signals/a11y.test.tsx +99 -0
  367. package/src/console/ui/signals/confirmation.test.ts +39 -0
  368. package/src/console/ui/signals/confirmation.ts +63 -0
  369. package/src/console/ui/signals/dry-run.test.ts +18 -0
  370. package/src/console/ui/signals/dry-run.ts +36 -0
  371. package/src/console/ui/signals/durable.test.ts +22 -0
  372. package/src/console/ui/signals/durable.ts +41 -0
  373. package/src/console/ui/signals/findings.ts +33 -0
  374. package/src/console/ui/signals/fixture.ts +242 -0
  375. package/src/console/ui/signals/group.test.ts +32 -0
  376. package/src/console/ui/signals/group.ts +49 -0
  377. package/src/console/ui/signals/index.ts +52 -0
  378. package/src/console/ui/signals/monitor.test.ts +30 -0
  379. package/src/console/ui/signals/monitor.ts +79 -0
  380. package/src/console/ui/signals/schema-form.test.ts +34 -0
  381. package/src/console/ui/signals/schema-form.ts +112 -0
  382. package/src/console/ui/signals/search.ts +102 -0
  383. package/src/console/ui/signals/types.ts +71 -0
  384. package/src/console/ui/store/StoreA11yView.tsx +199 -0
  385. package/src/console/ui/store/a11y.test.tsx +99 -0
  386. package/src/console/ui/store/cache-view.test.ts +13 -0
  387. package/src/console/ui/store/cache-view.ts +36 -0
  388. package/src/console/ui/store/confirmation.test.ts +38 -0
  389. package/src/console/ui/store/confirmation.ts +55 -0
  390. package/src/console/ui/store/dry-run.test.ts +15 -0
  391. package/src/console/ui/store/dry-run.ts +29 -0
  392. package/src/console/ui/store/fixture.ts +163 -0
  393. package/src/console/ui/store/group.test.ts +21 -0
  394. package/src/console/ui/store/group.ts +41 -0
  395. package/src/console/ui/store/index.ts +40 -0
  396. package/src/console/ui/store/search.ts +78 -0
  397. package/src/console/ui/store/types.ts +65 -0
  398. package/src/console/ui/store/will-not-fire.test.ts +19 -0
  399. package/src/console/ui/store/will-not-fire.ts +40 -0
  400. package/src/console/ui/traces/TracesA11yView.tsx +200 -0
  401. package/src/console/ui/traces/a11y.test.tsx +97 -0
  402. package/src/console/ui/traces/chain.test.ts +61 -0
  403. package/src/console/ui/traces/chain.ts +144 -0
  404. package/src/console/ui/traces/critical-path.test.ts +24 -0
  405. package/src/console/ui/traces/critical-path.ts +59 -0
  406. package/src/console/ui/traces/filter.test.ts +78 -0
  407. package/src/console/ui/traces/filter.ts +112 -0
  408. package/src/console/ui/traces/fixture.ts +126 -0
  409. package/src/console/ui/traces/fold.test.ts +67 -0
  410. package/src/console/ui/traces/fold.ts +170 -0
  411. package/src/console/ui/traces/index.ts +64 -0
  412. package/src/console/ui/traces/mini.ts +65 -0
  413. package/src/console/ui/traces/replay.test.ts +24 -0
  414. package/src/console/ui/traces/replay.ts +35 -0
  415. package/src/console/ui/traces/sampling.test.ts +26 -0
  416. package/src/console/ui/traces/sampling.ts +66 -0
  417. package/src/console/ui/traces/search.ts +148 -0
  418. package/src/console/ui/traces/tier.ts +72 -0
  419. package/src/console/ui/traces/types.ts +125 -0
  420. package/src/console/ui/tsconfig.json +20 -0
  421. package/src/console/ui/vault/VaultA11yView.tsx +177 -0
  422. package/src/console/ui/vault/a11y.test.tsx +97 -0
  423. package/src/console/ui/vault/blast-radius.test.ts +35 -0
  424. package/src/console/ui/vault/blast-radius.ts +55 -0
  425. package/src/console/ui/vault/confirmation.test.ts +41 -0
  426. package/src/console/ui/vault/confirmation.ts +39 -0
  427. package/src/console/ui/vault/dormant.test.ts +37 -0
  428. package/src/console/ui/vault/dormant.ts +28 -0
  429. package/src/console/ui/vault/export-safe.test.ts +30 -0
  430. package/src/console/ui/vault/export-safe.ts +65 -0
  431. package/src/console/ui/vault/fixture.ts +75 -0
  432. package/src/console/ui/vault/group.test.ts +25 -0
  433. package/src/console/ui/vault/group.ts +50 -0
  434. package/src/console/ui/vault/index.ts +45 -0
  435. package/src/console/ui/vault/search.ts +62 -0
  436. package/src/console/ui/vault/types.ts +57 -0
  437. package/src/console/ui/vite.config.ts +84 -0
  438. package/src/console/xss.gate.test.ts +118 -0
  439. package/src/docker/compose.ts +226 -0
  440. package/src/docker/credentials.ts +25 -0
  441. package/src/docker/derive.ts +83 -0
  442. package/src/docker/docker.test.ts +185 -0
  443. package/src/docker/dockerfile.integration.test.ts +170 -0
  444. package/src/docker/dockerfile.ts +39 -0
  445. package/src/docker/helpers.ts +103 -0
  446. package/src/docker/index.ts +52 -0
  447. package/src/docker/pin.ts +90 -0
  448. package/src/docker/recipes/index.ts +33 -0
  449. package/src/docker/recipes/postgres.ts +18 -0
  450. package/src/docker/recipes/redis.ts +18 -0
  451. package/src/docker/stack.integration.test.ts +140 -0
  452. package/src/docker/stack.ts +62 -0
  453. package/src/docker/types.ts +134 -0
  454. package/src/drivers/ai-anthropic.ts +128 -0
  455. package/src/drivers/ai-mock.ts +82 -0
  456. package/src/drivers/ai-openai-compatible.ts +139 -0
  457. package/src/drivers/ai-providers.test.ts +163 -0
  458. package/src/drivers/ai-types.ts +83 -0
  459. package/src/drivers/bun-native-completeness.test.ts +155 -0
  460. package/src/drivers/channel-console.ts +118 -0
  461. package/src/drivers/channel-fcm.ts +96 -0
  462. package/src/drivers/channel-resend.ts +27 -0
  463. package/src/drivers/channel-smtp.ts +33 -0
  464. package/src/drivers/channel-types.ts +160 -0
  465. package/src/drivers/channel-unifonic.ts +79 -0
  466. package/src/drivers/channel-wa-cloud.ts +84 -0
  467. package/src/drivers/channel-webpush.ts +317 -0
  468. package/src/drivers/conformance.test.ts +89 -0
  469. package/src/drivers/conformance.ts +162 -0
  470. package/src/drivers/fs.ts +73 -0
  471. package/src/drivers/index.ts +194 -0
  472. package/src/drivers/kv-lua.ts +222 -0
  473. package/src/drivers/memory.ts +472 -0
  474. package/src/drivers/pgvector.ts +130 -0
  475. package/src/drivers/postgres.ts +221 -0
  476. package/src/drivers/redis.ts +254 -0
  477. package/src/drivers/s3.ts +129 -0
  478. package/src/drivers/signal-engine.ts +690 -0
  479. package/src/drivers/signal-memory.ts +27 -0
  480. package/src/drivers/signal-nats.ts +131 -0
  481. package/src/drivers/signal-postgres.ts +1089 -0
  482. package/src/drivers/signal-redis.ts +275 -0
  483. package/src/drivers/signal-types.ts +328 -0
  484. package/src/drivers/sqlite.ts +53 -0
  485. package/src/drivers/types.ts +334 -0
  486. package/src/drivers/vault-dotenv-parse.ts +56 -0
  487. package/src/drivers/vault-env.ts +101 -0
  488. package/src/drivers/vault-infisical.ts +61 -0
  489. package/src/drivers/vault-managed.ts +42 -0
  490. package/src/drivers/vault-memory.ts +38 -0
  491. package/src/drivers/vault-openbao.ts +80 -0
  492. package/src/drivers/vault-sops.ts +252 -0
  493. package/src/drivers/vault-types.ts +84 -0
  494. package/src/elements/ai/declare.ts +206 -0
  495. package/src/elements/ai/eval.ts +113 -0
  496. package/src/elements/ai/pii.ts +108 -0
  497. package/src/elements/ai/runtime.ts +540 -0
  498. package/src/elements/ai/schema.ts +194 -0
  499. package/src/elements/ai.test.ts +393 -0
  500. package/src/elements/ai.ts +56 -0
  501. package/src/elements/channel/consent.ts +81 -0
  502. package/src/elements/channel/costs.test.ts +62 -0
  503. package/src/elements/channel/costs.ts +130 -0
  504. package/src/elements/channel/declare.ts +141 -0
  505. package/src/elements/channel/email-auth.test.ts +47 -0
  506. package/src/elements/channel/email-auth.ts +109 -0
  507. package/src/elements/channel/locale.ts +97 -0
  508. package/src/elements/channel/mask.test.ts +19 -0
  509. package/src/elements/channel/mask.ts +60 -0
  510. package/src/elements/channel/mime.ts +23 -0
  511. package/src/elements/channel/outcomes.test.ts +40 -0
  512. package/src/elements/channel/outcomes.ts +126 -0
  513. package/src/elements/channel/receipts.ts +121 -0
  514. package/src/elements/channel/runtime.ts +500 -0
  515. package/src/elements/channel/suppression.ts +136 -0
  516. package/src/elements/channel.test.ts +232 -0
  517. package/src/elements/channel.ts +109 -0
  518. package/src/elements/clock/actions.ts +170 -0
  519. package/src/elements/clock/declare.ts +58 -0
  520. package/src/elements/clock/dst.ts +197 -0
  521. package/src/elements/clock/durable.ts +140 -0
  522. package/src/elements/clock/duration.ts +29 -0
  523. package/src/elements/clock/health.test.ts +103 -0
  524. package/src/elements/clock/health.ts +112 -0
  525. package/src/elements/clock/leader.ts +127 -0
  526. package/src/elements/clock/reconcile.ts +241 -0
  527. package/src/elements/clock/runtime.ts +243 -0
  528. package/src/elements/clock/schedule.ts +262 -0
  529. package/src/elements/clock/time-travel.ts +53 -0
  530. package/src/elements/clock.test.ts +365 -0
  531. package/src/elements/clock.ts +80 -0
  532. package/src/elements/gate/declare.ts +134 -0
  533. package/src/elements/gate/permissions.ts +104 -0
  534. package/src/elements/gate/runtime.ts +177 -0
  535. package/src/elements/gate/strategies.ts +388 -0
  536. package/src/elements/gate.test.ts +145 -0
  537. package/src/elements/gate.ts +41 -0
  538. package/src/elements/index.ts +169 -0
  539. package/src/elements/signal/chaos-child.ts +47 -0
  540. package/src/elements/signal/declare.ts +77 -0
  541. package/src/elements/signal/dry-run-replay.test.ts +95 -0
  542. package/src/elements/signal/dry-run-write-isolation.test.ts +94 -0
  543. package/src/elements/signal/reconcile.test.ts +23 -0
  544. package/src/elements/signal/reconcile.ts +122 -0
  545. package/src/elements/signal/runtime.ts +94 -0
  546. package/src/elements/signal.test.ts +457 -0
  547. package/src/elements/signal.ts +26 -0
  548. package/src/elements/store/cache.ts +197 -0
  549. package/src/elements/store/classify.ts +125 -0
  550. package/src/elements/store/declare.ts +200 -0
  551. package/src/elements/store/files-policy.test.ts +31 -0
  552. package/src/elements/store/files-policy.ts +70 -0
  553. package/src/elements/store/replica.ts +68 -0
  554. package/src/elements/store/runtime.ts +393 -0
  555. package/src/elements/store/sql-condition.ts +205 -0
  556. package/src/elements/store/sql-session.ts +579 -0
  557. package/src/elements/store/table.ts +282 -0
  558. package/src/elements/store.test.ts +370 -0
  559. package/src/elements/store.ts +99 -0
  560. package/src/elements/vault/declare.ts +143 -0
  561. package/src/elements/vault/fingerprint.ts +30 -0
  562. package/src/elements/vault/redact.ts +52 -0
  563. package/src/elements/vault/runtime.ts +461 -0
  564. package/src/elements/vault.test.ts +296 -0
  565. package/src/elements/vault.ts +44 -0
  566. package/src/index.ts +183 -0
  567. package/src/kernel/adopt-routes.ts +194 -0
  568. package/src/kernel/app.ts +1068 -0
  569. package/src/kernel/auth-resolve.ts +93 -0
  570. package/src/kernel/boot.test.ts +173 -0
  571. package/src/kernel/boot.ts +439 -0
  572. package/src/kernel/budget-entry.ts +55 -0
  573. package/src/kernel/budget.test.ts +19 -0
  574. package/src/kernel/call.test.ts +83 -0
  575. package/src/kernel/capability.ts +113 -0
  576. package/src/kernel/dry-run.test.ts +64 -0
  577. package/src/kernel/dry-run.ts +171 -0
  578. package/src/kernel/effects.test.ts +89 -0
  579. package/src/kernel/effects.ts +140 -0
  580. package/src/kernel/errors.registry.test.ts +39 -0
  581. package/src/kernel/errors.ts +225 -0
  582. package/src/kernel/flow.test.ts +154 -0
  583. package/src/kernel/flow.ts +290 -0
  584. package/src/kernel/fx.test.ts +245 -0
  585. package/src/kernel/fx.ts +996 -0
  586. package/src/kernel/hook-timing.test.ts +72 -0
  587. package/src/kernel/hook-timing.ts +190 -0
  588. package/src/kernel/hooks.test.ts +181 -0
  589. package/src/kernel/hooks.ts +275 -0
  590. package/src/kernel/index.ts +278 -0
  591. package/src/kernel/journal.ts +405 -0
  592. package/src/kernel/journey.ts +75 -0
  593. package/src/kernel/on.ts +74 -0
  594. package/src/kernel/pipeline.test.ts +349 -0
  595. package/src/kernel/pipeline.ts +245 -0
  596. package/src/kernel/plug.ts +82 -0
  597. package/src/kernel/plugin/capabilities.test.ts +84 -0
  598. package/src/kernel/plugin/conflicts.test.ts +106 -0
  599. package/src/kernel/plugin/decorate.test.ts +111 -0
  600. package/src/kernel/plugin/scoping.test.ts +138 -0
  601. package/src/kernel/plugin.ts +485 -0
  602. package/src/kernel/rate-limit.ts +25 -0
  603. package/src/kernel/registry.ts +398 -0
  604. package/src/kernel/router.test.ts +114 -0
  605. package/src/kernel/router.ts +556 -0
  606. package/src/kernel/routing-budget.test.ts +19 -0
  607. package/src/kernel/run-telemetry.ts +70 -0
  608. package/src/kernel/triggers.ts +324 -0
  609. package/src/kernel/unit.ts +88 -0
  610. package/src/manifest/diff.test.ts +866 -0
  611. package/src/manifest/diff.ts +1670 -0
  612. package/src/manifest/fixtures/base.manifest.json +112 -0
  613. package/src/manifest/fixtures/skyport.excerpt.json +51 -0
  614. package/src/manifest/fixtures/skyport.manifest.json +153 -0
  615. package/src/manifest/index.ts +27 -0
  616. package/src/manifest/types.ts +358 -0
  617. package/src/manifest/undeclared.test.ts +82 -0
  618. package/src/manifest/undeclared.ts +65 -0
  619. package/src/manifest/validate.test.ts +105 -0
  620. package/src/manifest/validate.ts +174 -0
  621. package/src/mcp/authorization.ts +340 -0
  622. package/src/mcp/confirmation.ts +174 -0
  623. package/src/mcp/data.ts +90 -0
  624. package/src/mcp/index.ts +80 -0
  625. package/src/mcp/injection.gate.test.ts +176 -0
  626. package/src/mcp/mcp.test.ts +348 -0
  627. package/src/mcp/protocol.ts +172 -0
  628. package/src/mcp/server.ts +283 -0
  629. package/src/mcp/session.ts +139 -0
  630. package/src/mcp/tools.ts +391 -0
  631. package/src/plugins/catalogue.test.ts +48 -0
  632. package/src/plugins/catalogue.ts +113 -0
  633. package/src/plugins/node-import-scan.test.ts +28 -0
  634. package/src/plugins/node-import-scan.ts +98 -0
  635. package/src/plugins/supply-chain.test.ts +48 -0
  636. package/src/plugins/supply-chain.ts +460 -0
  637. package/src/release/index.ts +30 -0
  638. package/src/release/limits.ts +20 -0
  639. package/src/release/measure.ts +443 -0
  640. package/src/release/publish.ts +56 -0
  641. package/src/runs/bench.test.ts +93 -0
  642. package/src/runs/collect.ts +144 -0
  643. package/src/runs/drivers/clickhouse.ts +108 -0
  644. package/src/runs/drivers/files.ts +201 -0
  645. package/src/runs/drivers/memory.ts +94 -0
  646. package/src/runs/drivers/postgres.ts +110 -0
  647. package/src/runs/duckdb.ts +99 -0
  648. package/src/runs/index.ts +82 -0
  649. package/src/runs/outlier.ts +180 -0
  650. package/src/runs/parquet.ts +210 -0
  651. package/src/runs/privacy.ts +49 -0
  652. package/src/runs/runs.test.ts +324 -0
  653. package/src/runs/runtime.ts +229 -0
  654. package/src/runs/shred.ts +243 -0
  655. package/src/runs/telemetry.ts +10 -0
  656. package/src/runs/types.ts +179 -0
  657. package/src/runtime/bun.ts +140 -0
  658. package/src/runtime/cold-start.bench.ts +20 -0
  659. package/src/runtime/index.ts +46 -0
  660. package/src/runtime/primitives.ts +242 -0
  661. package/src/runtime/security.test.ts +170 -0
  662. package/src/runtime/security.ts +168 -0
  663. package/src/runtime/serve.test.ts +223 -0
  664. package/src/runtime/types.ts +217 -0
  665. package/src/runtime/web-standard.ts +77 -0
  666. package/src/test/create-test-app.test.ts +161 -0
  667. package/src/test/create-test-app.ts +533 -0
  668. package/src/test/index.ts +21 -0
  669. package/src/test/provisions.integration.test.ts +174 -0
  670. package/src/upgrade/codemods.test.ts +58 -0
  671. package/src/upgrade/codemods.ts +83 -0
  672. package/src/validation/index.ts +23 -0
  673. package/src/validation/standard-schema.test.ts +96 -0
  674. package/src/validation/standard-schema.ts +316 -0
@@ -0,0 +1,352 @@
1
+ /**
2
+ * Console Manifest Diff projection (console §9.12).
3
+ *
4
+ * Classification comes only from {@link diffManifest}. This module enriches
5
+ * each change with real Runs traffic, a weekly bill, and the CI gate status.
6
+ */
7
+
8
+ import {
9
+ costOf,
10
+ DEFAULT_MEDIUM_COSTS,
11
+ type MediumCosts,
12
+ } from "../../elements/channel/costs.ts";
13
+ import { diffManifest, highestSeverity } from "../../manifest/diff.ts";
14
+ import type {
15
+ Channel,
16
+ DiffCategory,
17
+ DiffKind,
18
+ Flow,
19
+ Manifest,
20
+ ManifestChange,
21
+ } from "../../manifest/types.ts";
22
+ import {
23
+ flowNameFromPath,
24
+ isDeclaredBreak,
25
+ } from "../../manifest/undeclared.ts";
26
+ import type { WideEvent } from "../../runs/types.ts";
27
+
28
+ /** One week in milliseconds. */
29
+ export const WEEK_MS = 7 * 86_400_000;
30
+
31
+ /** CI gate status for a contract-breaking change. */
32
+ export type DiffCiGate = "blocked" | "acknowledged";
33
+
34
+ /** Enriched Manifest Diff line for the Console panel. */
35
+ export interface ConsoleDiffChange {
36
+ readonly path: string;
37
+ readonly category: DiffCategory;
38
+ readonly kind: DiffKind;
39
+ readonly summary: string;
40
+ readonly before?: unknown;
41
+ readonly after?: unknown;
42
+ /** Owning flow when the path is under `/flows/{name}`. */
43
+ readonly flowName: string | null;
44
+ /** Real Runs count for that flow in the last week. */
45
+ readonly runCountLastWeek: number;
46
+ /**
47
+ * Change × traffic copy, e.g. "this flow ran 41,208 times last week,
48
+ * it sent nothing, and it will now email every caller."
49
+ */
50
+ readonly blastLine: string | null;
51
+ /** Weekly bill delta in USD (rate × recent volume), not per-call. */
52
+ readonly weeklyDeltaUsd: number | null;
53
+ /** Formatted weekly bill, e.g. "+$212 per week". */
54
+ readonly weeklyBillLine: string | null;
55
+ /**
56
+ * CI gate: undeclared contract breaks are `blocked`;
57
+ * `breaking: true` acknowledgements are `acknowledged`.
58
+ * Null for non-contract-breaking categories.
59
+ */
60
+ readonly ciGate: DiffCiGate | null;
61
+ }
62
+
63
+ /** Full Manifest Diff panel projection. */
64
+ export interface ConsoleDiffProjection {
65
+ /** Whether a baseline Manifest is available to compare. */
66
+ readonly hasBaseline: boolean;
67
+ /** Highest blast-radius category, or null when empty / no baseline. */
68
+ readonly severity: DiffCategory | null;
69
+ /** Count of undeclared (blocked) contract breaks. */
70
+ readonly blockedCount: number;
71
+ /** Count of `breaking: true` acknowledged contract breaks. */
72
+ readonly acknowledgedCount: number;
73
+ /** Changes sorted by blast radius, then path. */
74
+ readonly changes: readonly ConsoleDiffChange[];
75
+ }
76
+
77
+ /** Options for {@link projectManifestDiff}. */
78
+ export interface ProjectManifestDiffOptions {
79
+ readonly before: Manifest | null;
80
+ readonly after: Manifest | null;
81
+ readonly runs?: readonly WideEvent[];
82
+ readonly now?: number;
83
+ readonly costs?: MediumCosts;
84
+ }
85
+
86
+ /**
87
+ * Project Manifest Diff for the Console — classify via {@link diffManifest},
88
+ * then multiply by real Runs traffic and weekly cost.
89
+ *
90
+ * @param options - Baseline, candidate, Runs, clock
91
+ */
92
+ export function projectManifestDiff(
93
+ options: ProjectManifestDiffOptions,
94
+ ): ConsoleDiffProjection {
95
+ const before = options.before;
96
+ const after = options.after;
97
+ if (!before || !after) {
98
+ return {
99
+ hasBaseline: false,
100
+ severity: null,
101
+ blockedCount: 0,
102
+ acknowledgedCount: 0,
103
+ changes: [],
104
+ };
105
+ }
106
+
107
+ const now = options.now ?? Date.now();
108
+ const costs = options.costs ?? DEFAULT_MEDIUM_COSTS;
109
+ const runs = options.runs ?? [];
110
+ const runCounts = countRunsByFlowLastWeek(runs, now);
111
+
112
+ const { changes: raw } = diffManifest(before, after);
113
+ const channels = after.channels ?? before.channels;
114
+
115
+ const changes = [...raw]
116
+ .map((c) =>
117
+ enrichChange(c, {
118
+ before,
119
+ after,
120
+ runCounts,
121
+ channels,
122
+ costs,
123
+ }),
124
+ )
125
+ .sort(compareDiffChanges);
126
+
127
+ let blockedCount = 0;
128
+ let acknowledgedCount = 0;
129
+ for (const c of changes) {
130
+ if (c.ciGate === "blocked") blockedCount += 1;
131
+ if (c.ciGate === "acknowledged") acknowledgedCount += 1;
132
+ }
133
+
134
+ return {
135
+ hasBaseline: true,
136
+ severity: highestSeverity(changes),
137
+ blockedCount,
138
+ acknowledgedCount,
139
+ changes,
140
+ };
141
+ }
142
+
143
+ /**
144
+ * Count real Runs per flow over the trailing week window.
145
+ *
146
+ * @param runs - Wide events from the Runs store
147
+ * @param now - Clock (epoch ms)
148
+ */
149
+ export function countRunsByFlowLastWeek(
150
+ runs: readonly WideEvent[],
151
+ now: number,
152
+ ): ReadonlyMap<string, number> {
153
+ const start = now - WEEK_MS;
154
+ const counts = new Map<string, number>();
155
+ for (const r of runs) {
156
+ if (r.startedAt < start || r.startedAt > now) continue;
157
+ counts.set(r.flow, (counts.get(r.flow) ?? 0) + 1);
158
+ }
159
+ return counts;
160
+ }
161
+
162
+ /**
163
+ * Format an integer with thousands separators (en-US).
164
+ *
165
+ * @param n - Count
166
+ */
167
+ export function formatRunCount(n: number): string {
168
+ return n.toLocaleString("en-US");
169
+ }
170
+
171
+ /**
172
+ * Format a weekly bill delta — unit is the week, never per-call.
173
+ *
174
+ * @param weeklyDeltaUsd - Signed USD for the week
175
+ */
176
+ export function formatWeeklyBill(weeklyDeltaUsd: number): string {
177
+ const abs = Math.abs(weeklyDeltaUsd);
178
+ const digits = abs >= 1 ? 0 : 2;
179
+ const body = `$${abs.toFixed(digits)}`;
180
+ if (weeklyDeltaUsd > 0) return `+${body} per week`;
181
+ if (weeklyDeltaUsd < 0) return `-${body} per week`;
182
+ return `${body} per week`;
183
+ }
184
+
185
+ /**
186
+ * Build the change × traffic line when send effects (or similar) widen.
187
+ *
188
+ * @param options - Flow pair, run count, channels
189
+ */
190
+ export function formatBlastLine(options: {
191
+ readonly flowName: string;
192
+ readonly runCount: number;
193
+ readonly beforeFlow: Flow | undefined;
194
+ readonly afterFlow: Flow | undefined;
195
+ readonly channels: Record<string, Channel> | undefined;
196
+ }): string | null {
197
+ const { runCount, beforeFlow, afterFlow, channels } = options;
198
+ const beforeSends = beforeFlow?.effects?.sends ?? [];
199
+ const afterSends = afterFlow?.effects?.sends ?? [];
200
+ const added = afterSends.filter((t) => !beforeSends.includes(t));
201
+ if (added.length === 0) return null;
202
+
203
+ const past =
204
+ beforeSends.length === 0
205
+ ? "sent nothing"
206
+ : `sent via ${describeMedia(beforeSends, channels)}`;
207
+ const future = `will now ${verbForMedia(describeMedia(added, channels))} every caller`;
208
+ return `this flow ran ${formatRunCount(runCount)} times last week, it ${past}, and it ${future}`;
209
+ }
210
+
211
+ /**
212
+ * Weekly bill from estimatePerCall and/or newly declared send media.
213
+ *
214
+ * @param options - Flow pair, volume, costs
215
+ */
216
+ export function weeklyCostDeltaUsd(options: {
217
+ readonly beforeFlow: Flow | undefined;
218
+ readonly afterFlow: Flow | undefined;
219
+ readonly runCount: number;
220
+ readonly channels: Record<string, Channel> | undefined;
221
+ readonly costs: MediumCosts;
222
+ }): number | null {
223
+ const { beforeFlow, afterFlow, runCount, channels, costs } = options;
224
+ const beforeEst = beforeFlow?.cost?.estimatePerCall ?? 0;
225
+ const afterEst = afterFlow?.cost?.estimatePerCall ?? 0;
226
+ let perCall = afterEst - beforeEst;
227
+
228
+ const beforeSends = new Set(beforeFlow?.effects?.sends ?? []);
229
+ const afterSends = afterFlow?.effects?.sends ?? [];
230
+ for (const t of afterSends) {
231
+ if (!beforeSends.has(t)) {
232
+ perCall += costOf(mediumOf(t, channels), costs);
233
+ }
234
+ }
235
+ for (const t of beforeSends) {
236
+ if (!afterSends.includes(t)) {
237
+ perCall -= costOf(mediumOf(t, channels), costs);
238
+ }
239
+ }
240
+
241
+ if (perCall === 0) return null;
242
+ return perCall * runCount;
243
+ }
244
+
245
+ function enrichChange(
246
+ change: ManifestChange,
247
+ ctx: {
248
+ readonly before: Manifest;
249
+ readonly after: Manifest;
250
+ readonly runCounts: ReadonlyMap<string, number>;
251
+ readonly channels: Record<string, Channel> | undefined;
252
+ readonly costs: MediumCosts;
253
+ },
254
+ ): ConsoleDiffChange {
255
+ const flowName = flowNameFromPath(change.path);
256
+ const runCountLastWeek =
257
+ flowName !== null ? (ctx.runCounts.get(flowName) ?? 0) : 0;
258
+ const beforeFlow =
259
+ flowName !== null ? ctx.before.flows?.[flowName] : undefined;
260
+ const afterFlow = flowName !== null ? ctx.after.flows?.[flowName] : undefined;
261
+
262
+ let ciGate: DiffCiGate | null = null;
263
+ if (change.category === "contract-breaking") {
264
+ ciGate = isDeclaredBreak(change, ctx.before, ctx.after)
265
+ ? "acknowledged"
266
+ : "blocked";
267
+ }
268
+
269
+ // Traffic × cost copy belongs on effect / send / cost paths — not every
270
+ // row for the same flow (e.g. a gate change must not inherit a send bill).
271
+ const effectScoped =
272
+ flowName !== null &&
273
+ (change.category === "effect-widening" ||
274
+ change.path.includes("/effects") ||
275
+ change.path.includes("/sends") ||
276
+ change.path.includes("/cost"));
277
+
278
+ const blastLine = effectScoped
279
+ ? formatBlastLine({
280
+ flowName,
281
+ runCount: runCountLastWeek,
282
+ beforeFlow,
283
+ afterFlow,
284
+ channels: ctx.channels,
285
+ })
286
+ : null;
287
+
288
+ const weeklyDeltaUsd = effectScoped
289
+ ? weeklyCostDeltaUsd({
290
+ beforeFlow,
291
+ afterFlow,
292
+ runCount: runCountLastWeek,
293
+ channels: ctx.channels,
294
+ costs: ctx.costs,
295
+ })
296
+ : null;
297
+
298
+ return {
299
+ path: change.path,
300
+ category: change.category,
301
+ kind: change.kind,
302
+ summary: change.summary,
303
+ ...(change.before !== undefined ? { before: change.before } : {}),
304
+ ...(change.after !== undefined ? { after: change.after } : {}),
305
+ flowName,
306
+ runCountLastWeek,
307
+ blastLine,
308
+ weeklyDeltaUsd,
309
+ weeklyBillLine:
310
+ weeklyDeltaUsd !== null ? formatWeeklyBill(weeklyDeltaUsd) : null,
311
+ ciGate,
312
+ };
313
+ }
314
+
315
+ function compareDiffChanges(a: ConsoleDiffChange, b: ConsoleDiffChange): number {
316
+ const rank: Record<DiffCategory, number> = {
317
+ "contract-breaking": 3,
318
+ "permission-widening": 2,
319
+ "effect-widening": 1,
320
+ "no-impact": 0,
321
+ };
322
+ const byCat = rank[b.category] - rank[a.category];
323
+ if (byCat !== 0) return byCat;
324
+ return a.path.localeCompare(b.path);
325
+ }
326
+
327
+ function mediumOf(
328
+ template: string,
329
+ channels: Record<string, Channel> | undefined,
330
+ ): string {
331
+ return channels?.[template]?.medium ?? "email";
332
+ }
333
+
334
+ function describeMedia(
335
+ templates: readonly string[],
336
+ channels: Record<string, Channel> | undefined,
337
+ ): string {
338
+ const media = [
339
+ ...new Set(templates.map((t) => mediumOf(t, channels))),
340
+ ];
341
+ if (media.length === 0) return "nothing";
342
+ if (media.length === 1) return media[0]!;
343
+ return media.join("/");
344
+ }
345
+
346
+ function verbForMedia(media: string): string {
347
+ if (media === "email") return "email";
348
+ if (media === "sms") return "sms";
349
+ if (media === "whatsapp") return "whatsapp";
350
+ if (media === "push") return "push";
351
+ return `send ${media} to`;
352
+ }
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Exhaustive dry-run / preview audit across `src/console` (console §10.5).
3
+ *
4
+ * Reversibility dual-test (stub irreversible effects AND isolate writes with
5
+ * explicit refusal) is required only for affordances that execute work under
6
+ * dry-run. Locale / template "preview" and metadata-only `dryRun` flags are
7
+ * not that class.
8
+ */
9
+
10
+ import { describe, expect, test } from "bun:test";
11
+ import { readdir } from "node:fs/promises";
12
+ import { join } from "node:path";
13
+
14
+ const CONSOLE_ROOT = `${import.meta.dir}/..`;
15
+
16
+ /** Server flows that offer true dry-run / write-isolated preview. */
17
+ const EXPECTED_DRY_RUN_FLOWS = [
18
+ "console.signals.dryRunReplay",
19
+ "console.store.preview",
20
+ "console.store.edit", // dryRun:true branch
21
+ ] as const;
22
+
23
+ /**
24
+ * Collect TypeScript sources under `src/console`.
25
+ *
26
+ * @param dir - Directory
27
+ */
28
+ async function collectSources(dir: string): Promise<string[]> {
29
+ const out: string[] = [];
30
+ const entries = await readdir(dir, { withFileTypes: true });
31
+ for (const entry of entries) {
32
+ const path = join(dir, entry.name);
33
+ if (entry.isDirectory()) {
34
+ if (
35
+ entry.name === "dist" ||
36
+ entry.name === "node_modules" ||
37
+ entry.name === ".git"
38
+ ) {
39
+ continue;
40
+ }
41
+ out.push(...(await collectSources(path)));
42
+ continue;
43
+ }
44
+ if (/\.tsx?$/.test(entry.name) && !entry.name.endsWith(".test.ts")) {
45
+ out.push(path);
46
+ }
47
+ }
48
+ return out;
49
+ }
50
+
51
+ describe("console dry-run / preview audit", () => {
52
+ test("withDryRun is only used by Signals + Store (server)", async () => {
53
+ const files = await collectSources(CONSOLE_ROOT);
54
+ const hits: string[] = [];
55
+ for (const file of files) {
56
+ const text = await Bun.file(file).text();
57
+ if (!text.includes("withDryRun")) continue;
58
+ // Kernel re-export / type-only mentions in UI comments are fine to list.
59
+ hits.push(file.replace(`${CONSOLE_ROOT}/`, "src/console/"));
60
+ }
61
+ // Server dual-test sites + kernel import sites under console/server.
62
+ const allowed = hits.filter(
63
+ (h) =>
64
+ h.includes("store.ts") ||
65
+ h.includes("store.test.ts") ||
66
+ h.includes("flows.ts") ||
67
+ h.includes("dry-run"),
68
+ );
69
+ const unexpected = hits.filter((h) => !allowed.includes(h));
70
+ // UI may mention withDryRun in comments / client types — flag only
71
+ // executable imports of the kernel helper outside Signals/Store server.
72
+ const executable = unexpected.filter((h) => {
73
+ // Already filtered .test.ts; allow client type fields named dryRun.
74
+ return h.includes("/server/");
75
+ });
76
+ expect(executable).toEqual([]);
77
+ });
78
+
79
+ test("dry-run / preview affordances that mutate are dual-tested", async () => {
80
+ const storeTest = await Bun.file(
81
+ `${import.meta.dir}/store.test.ts`,
82
+ ).text();
83
+ expect(storeTest).toContain("preview dual test (withDryRun)");
84
+ expect(storeTest).toContain("DryRunWriteIsolationError");
85
+
86
+ const signalIsolation = await Bun.file(
87
+ `${import.meta.dir}/../../elements/signal/dry-run-write-isolation.test.ts`,
88
+ ).text();
89
+ expect(signalIsolation).toContain("dry-run replay — write isolation");
90
+
91
+ const signalStub = await Bun.file(
92
+ `${import.meta.dir}/../../elements/signal/dry-run-replay.test.ts`,
93
+ ).text();
94
+ expect(signalStub.length).toBeGreaterThan(0);
95
+
96
+ const flows = await Bun.file(`${import.meta.dir}/flows.ts`).text();
97
+ for (const name of EXPECTED_DRY_RUN_FLOWS) {
98
+ expect(flows).toContain(name);
99
+ }
100
+ });
101
+
102
+ test("Channels preview is locale template rendering, not dry-run mutation", async () => {
103
+ const flows = await Bun.file(`${import.meta.dir}/flows.ts`).text();
104
+ const previewIdx = flows.indexOf('name: "console.channel.preview"');
105
+ expect(previewIdx).toBeGreaterThan(0);
106
+ const slice = flows.slice(previewIdx, previewIdx + 800);
107
+ expect(slice).not.toContain("withDryRun");
108
+ expect(slice).toContain("state.previewChannel");
109
+ });
110
+
111
+ test("Traces dryRun is metadata / logging, not withDryRun execution", async () => {
112
+ const flows = await Bun.file(`${import.meta.dir}/flows.ts`).text();
113
+ const idx = flows.indexOf('name: "console.traces.replay"');
114
+ expect(idx).toBeGreaterThan(0);
115
+ const slice = flows.slice(idx, idx + 500);
116
+ expect(slice).not.toContain("withDryRun");
117
+ });
118
+ });
@@ -0,0 +1,148 @@
1
+ /**
2
+ * Console flows invoke-as + identities (console §9.2).
3
+ */
4
+
5
+ import { describe, expect, test } from "bun:test";
6
+ import { mkdtemp } from "node:fs/promises";
7
+ import { tmpdir } from "node:os";
8
+ import { join } from "node:path";
9
+ import { FLOWS_TEST_MANIFEST } from "../ui/flows/fixture.ts";
10
+ import { startConsoleApp } from "./serve.ts";
11
+ import { setManifest } from "./state.ts";
12
+
13
+ describe("console flows invoke", () => {
14
+ test("lists identities and invokes as a user with local validation path", async () => {
15
+ const cwd = await mkdtemp(join(tmpdir(), "oke-console-flows-"));
16
+ const handle = await startConsoleApp({
17
+ cwd,
18
+ secret: "test-secret-flows",
19
+ silentClaim: true,
20
+ production: false,
21
+ manifest: FLOWS_TEST_MANIFEST,
22
+ });
23
+ try {
24
+ setManifest(handle.state, FLOWS_TEST_MANIFEST);
25
+ const code = handle.state.claim.code;
26
+ const claimRes = await handle.app.fetch(
27
+ new Request("http://console.test/console/setup/claim", {
28
+ method: "POST",
29
+ headers: { "content-type": "application/json" },
30
+ body: JSON.stringify({
31
+ claimCode: code,
32
+ email: "ops@example.com",
33
+ name: "Ops",
34
+ password: "password123",
35
+ }),
36
+ }),
37
+ );
38
+ expect(claimRes.status).toBe(200);
39
+ const claimBody = (await claimRes.json()) as {
40
+ data: { accessToken: string };
41
+ };
42
+ const auth = {
43
+ authorization: `Bearer ${claimBody.data.accessToken}`,
44
+ "content-type": "application/json",
45
+ };
46
+
47
+ const idsRes = await handle.app.fetch(
48
+ new Request("http://console.test/console/flows/identities", {
49
+ headers: auth,
50
+ }),
51
+ );
52
+ expect(idsRes.status).toBe(200);
53
+ const idsBody = (await idsRes.json()) as {
54
+ data: { identities: Array<{ id: string }> };
55
+ };
56
+ expect(idsBody.data.identities.length).toBeGreaterThan(0);
57
+ const asUserId = idsBody.data.identities[0]!.id;
58
+
59
+ const invokeRes = await handle.app.fetch(
60
+ new Request("http://console.test/console/flows/invoke", {
61
+ method: "POST",
62
+ headers: auth,
63
+ body: JSON.stringify({
64
+ flowId: "bookings.create",
65
+ body: { flightId: "SK1", seats: 2 },
66
+ asUserId,
67
+ }),
68
+ }),
69
+ );
70
+ expect(invokeRes.status).toBe(200);
71
+ const invokeBody = (await invokeRes.json()) as {
72
+ data: { ok: true; response: { id: string }; peakTier: string };
73
+ error: null;
74
+ };
75
+ expect(invokeBody.error).toBeNull();
76
+ expect(invokeBody.data.ok).toBe(true);
77
+ expect(invokeBody.data.response.id).toMatch(/^inv_/);
78
+ expect(invokeBody.data.peakTier).toBe("emits");
79
+ } finally {
80
+ await handle.app.stop();
81
+ }
82
+ });
83
+
84
+ test("production irreversible invoke requires typed confirmation", async () => {
85
+ const cwd = await mkdtemp(join(tmpdir(), "oke-console-flows-"));
86
+ const handle = await startConsoleApp({
87
+ cwd,
88
+ secret: "test-secret-flows",
89
+ silentClaim: true,
90
+ production: true,
91
+ manifest: FLOWS_TEST_MANIFEST,
92
+ });
93
+ try {
94
+ const code = handle.state.claim.code;
95
+ const claimRes = await handle.app.fetch(
96
+ new Request("http://console.test/console/setup/claim", {
97
+ method: "POST",
98
+ headers: { "content-type": "application/json" },
99
+ body: JSON.stringify({
100
+ claimCode: code,
101
+ email: "ops@example.com",
102
+ name: "Ops",
103
+ password: "password123",
104
+ }),
105
+ }),
106
+ );
107
+ const claimBody = (await claimRes.json()) as {
108
+ data: { accessToken: string };
109
+ };
110
+ const auth = {
111
+ authorization: `Bearer ${claimBody.data.accessToken}`,
112
+ "content-type": "application/json",
113
+ };
114
+
115
+ const denied = await handle.app.fetch(
116
+ new Request("http://console.test/console/flows/invoke", {
117
+ method: "POST",
118
+ headers: auth,
119
+ body: JSON.stringify({
120
+ flowId: "fulfillment.onOrder",
121
+ body: {},
122
+ asUserId: "user_demo",
123
+ }),
124
+ }),
125
+ );
126
+ expect(denied.status).toBe(400);
127
+ const deniedBody = (await denied.json()) as { error: { code: string } };
128
+ expect(deniedBody.error.code).toBe("ConfirmRequired");
129
+
130
+ const ok = await handle.app.fetch(
131
+ new Request("http://console.test/console/flows/invoke", {
132
+ method: "POST",
133
+ headers: auth,
134
+ body: JSON.stringify({
135
+ flowId: "fulfillment.onOrder",
136
+ body: {},
137
+ asUserId: "user_demo",
138
+ confirmation: "INVOKE",
139
+ reason: "incident dry-run",
140
+ }),
141
+ }),
142
+ );
143
+ expect(ok.status).toBe(200);
144
+ } finally {
145
+ await handle.app.stop();
146
+ }
147
+ });
148
+ });