@anchrd/intel 0.59.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 (364) hide show
  1. package/README.md +496 -0
  2. package/bin/intel.mjs +134 -0
  3. package/dist/adapters/cloudflare/cloudflare-flow-workflow.d.ts +42 -0
  4. package/dist/adapters/cloudflare/cloudflare-flow-workflow.js +89 -0
  5. package/dist/adapters/cloudflare/cloudflare.d.ts +29 -0
  6. package/dist/adapters/cloudflare/cloudflare.js +416 -0
  7. package/dist/adapters/cloudflare/cloudflare.types.d.ts +31 -0
  8. package/dist/adapters/cloudflare/cloudflare.types.js +1 -0
  9. package/dist/adapters/content/content.d.ts +3 -0
  10. package/dist/adapters/content/content.js +128 -0
  11. package/dist/adapters/content/content.types.d.ts +38 -0
  12. package/dist/adapters/content/content.types.js +1 -0
  13. package/dist/adapters/db/db-audit.d.ts +62 -0
  14. package/dist/adapters/db/db-audit.js +150 -0
  15. package/dist/adapters/db/db-boards.d.ts +6 -0
  16. package/dist/adapters/db/db-boards.js +324 -0
  17. package/dist/adapters/db/db-feed.d.ts +30 -0
  18. package/dist/adapters/db/db-feed.js +276 -0
  19. package/dist/adapters/db/db-flows.d.ts +42 -0
  20. package/dist/adapters/db/db-flows.js +1311 -0
  21. package/dist/adapters/db/db-grants.d.ts +133 -0
  22. package/dist/adapters/db/db-grants.js +269 -0
  23. package/dist/adapters/db/db-indexing.d.ts +3 -0
  24. package/dist/adapters/db/db-indexing.js +200 -0
  25. package/dist/adapters/db/db-oauth.d.ts +3 -0
  26. package/dist/adapters/db/db-oauth.js +26 -0
  27. package/dist/adapters/db/db-prompts.d.ts +46 -0
  28. package/dist/adapters/db/db-prompts.js +144 -0
  29. package/dist/adapters/db/db.d.ts +6 -0
  30. package/dist/adapters/db/db.js +1687 -0
  31. package/dist/adapters/db/db.types.d.ts +16 -0
  32. package/dist/adapters/db/db.types.js +1 -0
  33. package/dist/adapters/document-converter/document-converter.d.ts +2 -0
  34. package/dist/adapters/document-converter/document-converter.js +26 -0
  35. package/dist/adapters/document-converter/document-converter.types.d.ts +17 -0
  36. package/dist/adapters/document-converter/document-converter.types.js +1 -0
  37. package/dist/adapters/flow-runtime/flow-runtime.d.ts +3 -0
  38. package/dist/adapters/flow-runtime/flow-runtime.js +22 -0
  39. package/dist/adapters/flow-runtime/flow-runtime.types.d.ts +19 -0
  40. package/dist/adapters/flow-runtime/flow-runtime.types.js +1 -0
  41. package/dist/adapters/index-queue/index-queue.d.ts +10 -0
  42. package/dist/adapters/index-queue/index-queue.js +12 -0
  43. package/dist/adapters/index-queue/index-queue.types.d.ts +11 -0
  44. package/dist/adapters/index-queue/index-queue.types.js +1 -0
  45. package/dist/adapters/json-schema/json-schema.d.ts +2 -0
  46. package/dist/adapters/json-schema/json-schema.js +77 -0
  47. package/dist/adapters/openid/openid.d.ts +5 -0
  48. package/dist/adapters/openid/openid.js +301 -0
  49. package/dist/adapters/portal-tokens/portal-tokens.d.ts +8 -0
  50. package/dist/adapters/portal-tokens/portal-tokens.js +79 -0
  51. package/dist/adapters/remote-tools/remote-tools.d.ts +5 -0
  52. package/dist/adapters/remote-tools/remote-tools.js +129 -0
  53. package/dist/adapters/semantic-index/semantic-index.d.ts +2 -0
  54. package/dist/adapters/semantic-index/semantic-index.js +139 -0
  55. package/dist/adapters/semantic-index/semantic-index.types.d.ts +56 -0
  56. package/dist/adapters/semantic-index/semantic-index.types.js +1 -0
  57. package/dist/adapters/session-cookie/session-cookie.d.ts +5 -0
  58. package/dist/adapters/session-cookie/session-cookie.js +87 -0
  59. package/dist/adapters/tool-source-policy/tool-source-policy.d.ts +1 -0
  60. package/dist/adapters/tool-source-policy/tool-source-policy.js +22 -0
  61. package/dist/audit/audit.d.ts +2 -0
  62. package/dist/audit/audit.js +87 -0
  63. package/dist/audit/audit.types.d.ts +23 -0
  64. package/dist/audit/audit.types.js +1 -0
  65. package/dist/auth/auth.d.ts +2 -0
  66. package/dist/auth/auth.js +284 -0
  67. package/dist/auth/auth.types.d.ts +108 -0
  68. package/dist/auth/auth.types.js +1 -0
  69. package/dist/boards/boards.d.ts +44 -0
  70. package/dist/boards/boards.js +447 -0
  71. package/dist/boards/boards.types.d.ts +117 -0
  72. package/dist/boards/boards.types.js +1 -0
  73. package/dist/build/build.d.ts +2 -0
  74. package/dist/build/build.js +192 -0
  75. package/dist/build/build.types.d.ts +17 -0
  76. package/dist/build/build.types.js +1 -0
  77. package/dist/bundle/bundle.d.ts +4 -0
  78. package/dist/bundle/bundle.js +1194 -0
  79. package/dist/bundle/bundle.types.d.ts +33 -0
  80. package/dist/bundle/bundle.types.js +1 -0
  81. package/dist/cli/cli.d.ts +4 -0
  82. package/dist/cli/cli.js +262 -0
  83. package/dist/cli/cli.types.d.ts +14 -0
  84. package/dist/cli/cli.types.js +1 -0
  85. package/dist/contract/audit.d.ts +50 -0
  86. package/dist/contract/audit.js +72 -0
  87. package/dist/contract/board.d.ts +150 -0
  88. package/dist/contract/board.js +262 -0
  89. package/dist/contract/bundle.d.ts +147 -0
  90. package/dist/contract/bundle.js +139 -0
  91. package/dist/contract/contract.d.ts +112 -0
  92. package/dist/contract/contract.js +143 -0
  93. package/dist/contract/feed.d.ts +126 -0
  94. package/dist/contract/feed.js +149 -0
  95. package/dist/contract/flow-run.d.ts +346 -0
  96. package/dist/contract/flow-run.js +194 -0
  97. package/dist/contract/flow.d.ts +1057 -0
  98. package/dist/contract/flow.js +552 -0
  99. package/dist/contract/node.d.ts +551 -0
  100. package/dist/contract/node.js +456 -0
  101. package/dist/contract/share.d.ts +216 -0
  102. package/dist/contract/share.js +134 -0
  103. package/dist/contract/table.d.ts +171 -0
  104. package/dist/contract/table.js +117 -0
  105. package/dist/contract/tool.d.ts +122 -0
  106. package/dist/contract/tool.js +172 -0
  107. package/dist/feed/feed.d.ts +2 -0
  108. package/dist/feed/feed.js +77 -0
  109. package/dist/feed/feed.types.d.ts +23 -0
  110. package/dist/feed/feed.types.js +1 -0
  111. package/dist/flows/flows.d.ts +41 -0
  112. package/dist/flows/flows.js +2216 -0
  113. package/dist/flows/flows.types.d.ts +339 -0
  114. package/dist/flows/flows.types.js +1 -0
  115. package/dist/http/http.d.ts +9 -0
  116. package/dist/http/http.js +874 -0
  117. package/dist/http/http.types.d.ts +22 -0
  118. package/dist/http/http.types.js +1 -0
  119. package/dist/indexing/indexing.d.ts +6 -0
  120. package/dist/indexing/indexing.js +239 -0
  121. package/dist/indexing/indexing.types.d.ts +11 -0
  122. package/dist/indexing/indexing.types.js +1 -0
  123. package/dist/intel/intel.d.ts +3 -0
  124. package/dist/intel/intel.js +194 -0
  125. package/dist/intel/intel.types.d.ts +24 -0
  126. package/dist/intel/intel.types.js +1 -0
  127. package/dist/mcp/mcp.d.ts +2 -0
  128. package/dist/mcp/mcp.js +1292 -0
  129. package/dist/mcp/mcp.types.d.ts +25 -0
  130. package/dist/mcp/mcp.types.js +1 -0
  131. package/dist/nodes/document-links/document-links.d.ts +20 -0
  132. package/dist/nodes/document-links/document-links.js +57 -0
  133. package/dist/nodes/nodes.d.ts +2 -0
  134. package/dist/nodes/nodes.js +1667 -0
  135. package/dist/nodes/nodes.types.d.ts +511 -0
  136. package/dist/nodes/nodes.types.js +1 -0
  137. package/dist/prepare/prepare.d.ts +4 -0
  138. package/dist/prepare/prepare.js +16 -0
  139. package/dist/prepare/prepare.types.d.ts +9 -0
  140. package/dist/prepare/prepare.types.js +1 -0
  141. package/dist/prompts/prompts.d.ts +2 -0
  142. package/dist/prompts/prompts.js +65 -0
  143. package/dist/prompts/prompts.types.d.ts +71 -0
  144. package/dist/prompts/prompts.types.js +1 -0
  145. package/dist/shared/callers/callers.d.ts +28 -0
  146. package/dist/shared/callers/callers.js +30 -0
  147. package/dist/shared/csv/csv.d.ts +13 -0
  148. package/dist/shared/csv/csv.js +85 -0
  149. package/dist/shared/document-text/document-text.d.ts +21 -0
  150. package/dist/shared/document-text/document-text.js +31 -0
  151. package/dist/shared/gate-authorization/gate-authorization.d.ts +5 -0
  152. package/dist/shared/gate-authorization/gate-authorization.js +26 -0
  153. package/dist/shared/grant-expiry/grant-expiry.d.ts +19 -0
  154. package/dist/shared/grant-expiry/grant-expiry.js +26 -0
  155. package/dist/shared/intel-error/intel-error.d.ts +22 -0
  156. package/dist/shared/intel-error/intel-error.js +27 -0
  157. package/dist/shared/plain-title/plain-title.d.ts +16 -0
  158. package/dist/shared/plain-title/plain-title.js +45 -0
  159. package/dist/shared/problem-details/problem-details.d.ts +30 -0
  160. package/dist/shared/problem-details/problem-details.js +18 -0
  161. package/dist/shared/report-unexpected-error/report-unexpected-error.d.ts +1 -0
  162. package/dist/shared/report-unexpected-error/report-unexpected-error.js +37 -0
  163. package/dist/shared/safe-return-path/safe-return-path.d.ts +2 -0
  164. package/dist/shared/safe-return-path/safe-return-path.js +11 -0
  165. package/dist/shared/sha256/sha256.d.ts +2 -0
  166. package/dist/shared/sha256/sha256.js +14 -0
  167. package/dist/tools/tool-servers/tool-servers.d.ts +46 -0
  168. package/dist/tools/tool-servers/tool-servers.js +177 -0
  169. package/dist/tools/tools.d.ts +2 -0
  170. package/dist/tools/tools.js +207 -0
  171. package/dist/tools/tools.types.d.ts +56 -0
  172. package/dist/tools/tools.types.js +1 -0
  173. package/examples/branding/favicon.svg +5 -0
  174. package/examples/branding/logo.svg +5 -0
  175. package/examples/branding/theme.css +16 -0
  176. package/examples/dev.vars.example +7 -0
  177. package/examples/intel.json +9 -0
  178. package/migrations/0000_intel_foundation.sql +203 -0
  179. package/migrations/0001_portal_native_tools.sql +21 -0
  180. package/migrations/0002_flows_in_the_knowledge_tree.sql +34 -0
  181. package/migrations/0003_folder_permissions.sql +211 -0
  182. package/migrations/0004_subflow_runs.sql +14 -0
  183. package/migrations/0005_flow_node_cleanup.sql +28 -0
  184. package/migrations/0005_tables_in_the_knowledge_tree.sql +68 -0
  185. package/migrations/0006_links_are_written_in_the_text.sql +20 -0
  186. package/migrations/0007_no_node_waits.sql +69 -0
  187. package/migrations/0008_three_layers.sql +130 -0
  188. package/migrations/0009_no_context_policy.sql +48 -0
  189. package/migrations/0010_no_run_waits_a_year.sql +27 -0
  190. package/migrations/0011_one_name_for_the_tree.sql +53 -0
  191. package/migrations/0012_table_snapshots.sql +29 -0
  192. package/migrations/0017_a_vector_per_card.sql +38 -0
  193. package/migrations/0018_no_context_policy_at_last.sql +97 -0
  194. package/migrations/0019_one_name_for_the_grants.sql +52 -0
  195. package/migrations/0020_cascade_purge_replay.sql +11 -0
  196. package/migrations/0021_a_flow_carries_its_own_grant.sql +44 -0
  197. package/migrations/0022_a_cursor_over_the_journal.sql +14 -0
  198. package/migrations/0023_a_board_and_its_tasks.sql +116 -0
  199. package/migrations/0024_the_archive_is_a_column.sql +33 -0
  200. package/migrations/0025_archiving_takes_the_subtree.sql +29 -0
  201. package/migrations/0026_one_feed_over_two_kinds.sql +23 -0
  202. package/migrations/0027_the_runs_of_every_flow.sql +27 -0
  203. package/migrations/0028_a_prompt_name_over_two_kinds.sql +70 -0
  204. package/package.json +118 -0
  205. package/src/contract/CLAUDE.md +152 -0
  206. package/src/contract/README.md +102 -0
  207. package/src/contract/audit.ts +85 -0
  208. package/src/contract/board.ts +306 -0
  209. package/src/contract/bundle.ts +157 -0
  210. package/src/contract/contract.ts +161 -0
  211. package/src/contract/feed.ts +165 -0
  212. package/src/contract/flow-run.ts +241 -0
  213. package/src/contract/flow.ts +675 -0
  214. package/src/contract/node.ts +583 -0
  215. package/src/contract/share.ts +196 -0
  216. package/src/contract/table.ts +178 -0
  217. package/src/contract/tool.ts +202 -0
  218. package/ui/README.md +110 -0
  219. package/ui/components.json +21 -0
  220. package/ui/index.html +13 -0
  221. package/ui/package.json +11 -0
  222. package/ui/scripts/lint-tokens.mjs +187 -0
  223. package/ui/src/access-summary/access-summary.tsx +385 -0
  224. package/ui/src/app/action-slot/action-slot.tsx +27 -0
  225. package/ui/src/app/app-sidebar/app-sidebar.tsx +71 -0
  226. package/ui/src/app/app-tree/app-tree.tsx +1175 -0
  227. package/ui/src/app/app.tsx +87 -0
  228. package/ui/src/app/header-search/header-search.tsx +294 -0
  229. package/ui/src/app/reindex-dialog/reindex-dialog.tsx +79 -0
  230. package/ui/src/app/settings-dialog/settings-dialog.tsx +135 -0
  231. package/ui/src/app/sidebar-preferences/sidebar-preferences.ts +68 -0
  232. package/ui/src/app/sidebar-preferences/sidebar-preferences.types.ts +15 -0
  233. package/ui/src/app/sidebar-resize-handle/sidebar-resize-handle.tsx +86 -0
  234. package/ui/src/app/tree-expansion/tree-expansion.ts +107 -0
  235. package/ui/src/app/tree-expansion/tree-expansion.types.ts +31 -0
  236. package/ui/src/app/tree-move/tree-move.tsx +427 -0
  237. package/ui/src/app/tree-reveal/tree-reveal.ts +64 -0
  238. package/ui/src/app/tree-reveal/tree-reveal.types.ts +16 -0
  239. package/ui/src/app/user-footer/user-footer.tsx +188 -0
  240. package/ui/src/app/view-menu/view-menu.tsx +115 -0
  241. package/ui/src/app-root/app-root.tsx +109 -0
  242. package/ui/src/app-root/app-root.types.ts +27 -0
  243. package/ui/src/archive/archive.tsx +417 -0
  244. package/ui/src/attachment-detail/attachment-detail.ts +52 -0
  245. package/ui/src/attachment-viewer/attachment-viewer.tsx +166 -0
  246. package/ui/src/blocknote-view/blocknote-view.tsx +30 -0
  247. package/ui/src/board/board-assignee/board-assignee-picker.tsx +132 -0
  248. package/ui/src/board/board-assignee/board-assignee.ts +48 -0
  249. package/ui/src/board/board-assignee/board-assignee.tsx +75 -0
  250. package/ui/src/board/board-chip/board-chip.tsx +46 -0
  251. package/ui/src/board/board-crumbs/board-crumbs.ts +56 -0
  252. package/ui/src/board/board-crumbs/board-crumbs.tsx +111 -0
  253. package/ui/src/board/board-data/board-data.ts +195 -0
  254. package/ui/src/board/board-data/board-data.types.ts +38 -0
  255. package/ui/src/board/board-dates/board-dates.ts +40 -0
  256. package/ui/src/board/board-dates/board-dates.tsx +105 -0
  257. package/ui/src/board/board-kanban/board-kanban.ts +162 -0
  258. package/ui/src/board/board-kanban/board-kanban.tsx +680 -0
  259. package/ui/src/board/board-open-task/board-open-task.ts +32 -0
  260. package/ui/src/board/board-panel/board-panel.tsx +259 -0
  261. package/ui/src/board/board-settings/board-settings.tsx +226 -0
  262. package/ui/src/board/board-status/board-status.tsx +60 -0
  263. package/ui/src/board/board-stripes/board-stripes.ts +128 -0
  264. package/ui/src/board/board-table/board-table.ts +53 -0
  265. package/ui/src/board/board-table/board-table.tsx +610 -0
  266. package/ui/src/board/board-task/board-task.ts +108 -0
  267. package/ui/src/board/board-task/board-task.tsx +335 -0
  268. package/ui/src/board/board-title-row/board-title-row.tsx +66 -0
  269. package/ui/src/branding/branding.tsx +17 -0
  270. package/ui/src/branding/custom-logo.ts +1 -0
  271. package/ui/src/branding/favicon.default.svg +5 -0
  272. package/ui/src/branding/favicon.svg +5 -0
  273. package/ui/src/components/ui/avatar.tsx +39 -0
  274. package/ui/src/components/ui/button.tsx +64 -0
  275. package/ui/src/components/ui/collapsible.tsx +20 -0
  276. package/ui/src/components/ui/command.tsx +160 -0
  277. package/ui/src/components/ui/dialog.tsx +143 -0
  278. package/ui/src/components/ui/dropdown-menu.tsx +187 -0
  279. package/ui/src/components/ui/input.tsx +21 -0
  280. package/ui/src/components/ui/popover.tsx +41 -0
  281. package/ui/src/components/ui/select.tsx +163 -0
  282. package/ui/src/components/ui/separator.tsx +26 -0
  283. package/ui/src/components/ui/sheet.tsx +136 -0
  284. package/ui/src/components/ui/sidebar.tsx +693 -0
  285. package/ui/src/components/ui/skeleton.tsx +13 -0
  286. package/ui/src/components/ui/switch.tsx +25 -0
  287. package/ui/src/components/ui/table.tsx +82 -0
  288. package/ui/src/components/ui/tabs.tsx +52 -0
  289. package/ui/src/components/ui/tooltip.tsx +51 -0
  290. package/ui/src/data/intel-data-provider/intel-data-provider.ts +685 -0
  291. package/ui/src/data/intel-data-provider/intel-data-provider.types.ts +266 -0
  292. package/ui/src/data/query-client.ts +18 -0
  293. package/ui/src/data/request-refusal/refusal-notice.tsx +36 -0
  294. package/ui/src/data/request-refusal/request-refusal.ts +51 -0
  295. package/ui/src/data/sign-in/sign-in.ts +97 -0
  296. package/ui/src/data/sign-in/sign-in.types.ts +15 -0
  297. package/ui/src/document-link/document-link.tsx +114 -0
  298. package/ui/src/document-markdown/document-markdown.ts +195 -0
  299. package/ui/src/editor-schema/editor-schema.ts +23 -0
  300. package/ui/src/entry-picker/entry-picker.tsx +238 -0
  301. package/ui/src/feed/feed.tsx +344 -0
  302. package/ui/src/file-preview/file-preview-view.tsx +496 -0
  303. package/ui/src/file-preview/file-preview.tsx +28 -0
  304. package/ui/src/file-preview/pdf-file-preview.tsx +5 -0
  305. package/ui/src/file-preview/presentation-file-preview.tsx +21 -0
  306. package/ui/src/file-preview/spreadsheet-file-preview.tsx +5 -0
  307. package/ui/src/file-preview/word-file-preview.tsx +5 -0
  308. package/ui/src/flow-runs/flow-runs.tsx +238 -0
  309. package/ui/src/flows/flows.tsx +1646 -0
  310. package/ui/src/flows/node-icon/node-icon.ts +34 -0
  311. package/ui/src/flows/node-palette/node-palette.tsx +214 -0
  312. package/ui/src/flows/node-palette/node-palette.types.ts +15 -0
  313. package/ui/src/folder-contents/folder-contents.tsx +321 -0
  314. package/ui/src/folder-index/folder-index.ts +55 -0
  315. package/ui/src/frontmatter/frontmatter.tsx +193 -0
  316. package/ui/src/graph-pane/graph-pane.tsx +53 -0
  317. package/ui/src/hooks/use-mobile.ts +19 -0
  318. package/ui/src/i18n/custom.json +4 -0
  319. package/ui/src/i18n/de.json +609 -0
  320. package/ui/src/i18n/en.json +609 -0
  321. package/ui/src/i18n/es.json +609 -0
  322. package/ui/src/i18n/i18n-context.tsx +65 -0
  323. package/ui/src/i18n/i18n-languages/i18n-languages.ts +83 -0
  324. package/ui/src/i18n/i18n.ts +32 -0
  325. package/ui/src/i18n/i18n.types.ts +49 -0
  326. package/ui/src/kind-icon.ts +97 -0
  327. package/ui/src/lib/utils.ts +6 -0
  328. package/ui/src/main.tsx +68 -0
  329. package/ui/src/modal/modal.tsx +53 -0
  330. package/ui/src/node-details/node-details.tsx +545 -0
  331. package/ui/src/node-editor/node-editor.tsx +304 -0
  332. package/ui/src/node-graph/graph-notice.tsx +21 -0
  333. package/ui/src/node-graph/node-graph.ts +214 -0
  334. package/ui/src/node-graph/node-graph.tsx +295 -0
  335. package/ui/src/node-import/node-import.tsx +418 -0
  336. package/ui/src/node-save-error.ts +46 -0
  337. package/ui/src/node-source/node-source.tsx +128 -0
  338. package/ui/src/node-table/node-table.tsx +107 -0
  339. package/ui/src/nodes/nodes.tsx +240 -0
  340. package/ui/src/rename-resource/rename-resource.ts +80 -0
  341. package/ui/src/resolved-names/resolved-names.tsx +67 -0
  342. package/ui/src/resource-error.ts +33 -0
  343. package/ui/src/resource-menu/resource-menu.tsx +1156 -0
  344. package/ui/src/router/router-context.ts +6 -0
  345. package/ui/src/router/router.tsx +67 -0
  346. package/ui/src/router/router.types.ts +8 -0
  347. package/ui/src/router/selection-search.ts +88 -0
  348. package/ui/src/save-button/save-button.tsx +94 -0
  349. package/ui/src/section-hint/section-hint.tsx +40 -0
  350. package/ui/src/sign-in-refused/sign-in-refused.tsx +35 -0
  351. package/ui/src/styles.css +189 -0
  352. package/ui/src/table-columns/table-columns.tsx +379 -0
  353. package/ui/src/theme/custom.css +1 -0
  354. package/ui/src/theme/theme-context.tsx +89 -0
  355. package/ui/src/theme/theme.ts +70 -0
  356. package/ui/src/time/relative-time.tsx +41 -0
  357. package/ui/src/time/time-context.tsx +78 -0
  358. package/ui/src/time/time.ts +165 -0
  359. package/ui/src/title-row/title-row.tsx +185 -0
  360. package/ui/src/tools/tools.tsx +546 -0
  361. package/ui/src/user-name/user-name.ts +61 -0
  362. package/ui/src/verbatim/verbatim.tsx +68 -0
  363. package/ui/tsconfig.json +17 -0
  364. package/ui/vite.config.ts +129 -0
@@ -0,0 +1,89 @@
1
+ // The runtime module is provided by workerd and intentionally has no Node package resolution path.
2
+ // @ts-expect-error cloudflare:workers is available inside the deployed Worker runtime.
3
+ import { WorkflowEntrypoint as RuntimeWorkflowEntrypoint } from "cloudflare:workers";
4
+ class WorkflowEntrypoint extends RuntimeWorkflowEntrypoint {
5
+ }
6
+ /**
7
+ * How long a run may stand on one step before nobody is working on it any more (#83).
8
+ *
9
+ * ⚠️ This is a product decision and not a constant somebody may tune while reading the code. Too
10
+ * short is worse than the problem it fixes: it ends runs that were only slow, which destroys work
11
+ * instead of merely displaying it wrongly. 30 minutes covers a large document, a sluggish API and
12
+ * a person who walks away from an approval; it does not cover a tab that was closed yesterday.
13
+ *
14
+ * The deployment may override it with `FLOW_RUN_STALL_TIMEOUT` (a Workflows duration, e.g. "2
15
+ * hours"), which is what makes the figure readable in operation rather than buried here.
16
+ */
17
+ const DefaultStallTimeout = "30 minutes";
18
+ /**
19
+ * What the durable wait actually does, with storage handed in.
20
+ *
21
+ * ⚠️ Separated from the class because `WorkflowEntrypoint` is a runtime class that cannot be
22
+ * constructed outside workerd's workflow context — so as long as this logic lived inside it, none
23
+ * of it could be tested, including the rule that keeps a caller alive while its child runs. That
24
+ * rule is the one that decides whether this feature destroys work or not, and it had to be
25
+ * provable. The shell below is now only bindings and SQL, which is what `CLAUDE.md` asks of it.
26
+ */
27
+ export async function driveFlowRun(step, deps) {
28
+ const fail = async (name, error) => await step.do(name, async () => {
29
+ await deps.markFailed(error);
30
+ return { status: "failed", error };
31
+ });
32
+ for (let iteration = 0; iteration < 500; iteration += 1) {
33
+ const state = await step.do(`inspect flow run ${iteration}`, async () => await deps.readStatus());
34
+ if (["completed", "failed", "cancelled"].includes(state.status))
35
+ return state;
36
+ try {
37
+ await step.waitForEvent(`wait for flow run ${iteration}`, {
38
+ type: "advance",
39
+ // ⚠️ The clock starts HERE, which is what makes it "since the last step" rather than "since
40
+ // the run began": every `advance` returns to the top of the loop and waits anew. A flow
41
+ // with one genuinely long step is measured against that step, not against its total length.
42
+ timeout: deps.stallTimeout,
43
+ });
44
+ }
45
+ catch {
46
+ // ⚠️ A caller standing on a sub-flow node looks exactly like a run nobody is working on — it
47
+ // is waiting, by design, for the called run to finish. Ending it here would tear down a
48
+ // caller because its child was slow, which is the one way this fix could destroy work rather
49
+ // than merely display it wrongly. So the timeout asks first, and waits again if a child is
50
+ // still going.
51
+ const waiting = await step.do(`check called run ${iteration}`, async () => await deps.hasRunningChild());
52
+ if (waiting)
53
+ continue;
54
+ return await fail(`expire flow run ${iteration}`, "Nothing has moved this run forward, so it was ended. Whatever was running it stopped without reporting a result — start it again if it is still needed.");
55
+ }
56
+ }
57
+ return await fail("fail flow step limit", "Flow exceeded the maximum durable step count");
58
+ }
59
+ class IntelFlowWorkflowImplementation extends WorkflowEntrypoint {
60
+ async run(event, step) {
61
+ const runId = event.payload.runId;
62
+ return await driveFlowRun(step, {
63
+ readStatus: async () => {
64
+ const row = await this.env.DB.prepare("SELECT status, error FROM flow_runs WHERE id = ?")
65
+ .bind(runId)
66
+ .first();
67
+ return row ?? { status: "failed", error: "Flow run disappeared" };
68
+ },
69
+ hasRunningChild: async () => {
70
+ const row = await this.env.DB.prepare(`SELECT id FROM flow_runs
71
+ WHERE parent_run_id = ? AND status IN ('queued', 'running')
72
+ LIMIT 1`)
73
+ .bind(runId)
74
+ .first();
75
+ return row !== null;
76
+ },
77
+ markFailed: async (error) => {
78
+ const occurredAt = new Date().toISOString();
79
+ await this.env.DB.prepare(`UPDATE flow_runs
80
+ SET status = 'failed', error = ?, completed_at = ?, updated_at = ?
81
+ WHERE id = ? AND status NOT IN ('completed', 'failed', 'cancelled')`)
82
+ .bind(error, occurredAt, occurredAt, runId)
83
+ .run();
84
+ },
85
+ stallTimeout: this.env.FLOW_RUN_STALL_TIMEOUT || DefaultStallTimeout,
86
+ });
87
+ }
88
+ }
89
+ export const IntelFlowWorkflow = IntelFlowWorkflowImplementation;
@@ -0,0 +1,29 @@
1
+ import type { DocumentConverter } from "../document-converter/document-converter.types.js";
2
+ import type { SemanticIndex } from "../semantic-index/semantic-index.types.js";
3
+ import type { CloudflareEnv, CloudflareExecutionContext, IndexQueueBatch } from "./cloudflare.types.js";
4
+ export { IntelFlowWorkflow } from "./cloudflare-flow-workflow.js";
5
+ export declare function isSpaNavigation(request: Request): boolean;
6
+ /**
7
+ * The two ports that call Workers AI, and the one condition that decides whether they exist at all
8
+ * (#800).
9
+ *
10
+ * ⚠️ **No gateway id, no ports.** The obvious spelling would have been to pass the gateway when
11
+ * there is one and call Workers AI directly when there is not — and that is precisely the silent
12
+ * bypass the spend limit exists against: the deployment keeps embedding on every save and every
13
+ * `reindex`, the gateway counts none of it, and nobody notices because everything works. A missing
14
+ * semantic index is a state this repository already knows and describes (see the bindings table in
15
+ * the package README); an unmetered one is not.
16
+ *
17
+ * ⚠️ Both ports fall away together, because both call Workers AI: the embeddings through `run` and
18
+ * the attachment conversion through `toMarkdown`. Repairing only the first half would have left a
19
+ * second door open on the same account.
20
+ */
21
+ export declare function createAiPorts(env: CloudflareEnv): {
22
+ semantic: SemanticIndex | undefined;
23
+ converter: DocumentConverter | undefined;
24
+ };
25
+ declare const _default: {
26
+ fetch(request: Request, env: CloudflareEnv, _context: CloudflareExecutionContext): Promise<Response>;
27
+ queue(batch: IndexQueueBatch, env: CloudflareEnv): Promise<void>;
28
+ };
29
+ export default _default;
@@ -0,0 +1,416 @@
1
+ import { createGateClient } from "@anchrd/gate-sdk";
2
+ import { ulid } from "ulid";
3
+ import { createAudit } from "../../audit/audit.js";
4
+ import { createBrowserAuth } from "../../auth/auth.js";
5
+ import { createBoards, FIRST_DEFAULT_COLUMN } from "../../boards/boards.js";
6
+ import { createBundle } from "../../bundle/bundle.js";
7
+ import { serverOf } from "../../contract/tool.js";
8
+ import { createFeed } from "../../feed/feed.js";
9
+ import { createFlows } from "../../flows/flows.js";
10
+ import { createIndexing, PermanentIndexingError } from "../../indexing/indexing.js";
11
+ import { createIntel } from "../../intel/intel.js";
12
+ import { createNodes } from "../../nodes/nodes.js";
13
+ import { createPrompts } from "../../prompts/prompts.js";
14
+ import { bearer } from "../../shared/gate-authorization/gate-authorization.js";
15
+ import { IntelError } from "../../shared/intel-error/intel-error.js";
16
+ import { sha256Hex } from "../../shared/sha256/sha256.js";
17
+ import { createTools } from "../../tools/tools.js";
18
+ import { createContentStore } from "../content/content.js";
19
+ import { createNodeRepository } from "../db/db.js";
20
+ import { createAuditRepository } from "../db/db-audit.js";
21
+ import { createBoardRepository } from "../db/db-boards.js";
22
+ import { createFeedRepository } from "../db/db-feed.js";
23
+ import { createFlowRepository } from "../db/db-flows.js";
24
+ import { createNodeIndexRepository } from "../db/db-indexing.js";
25
+ import { createOAuthClientStore } from "../db/db-oauth.js";
26
+ import { createPromptRepository } from "../db/db-prompts.js";
27
+ import { createDocumentConverter } from "../document-converter/document-converter.js";
28
+ import { createFlowRuntime } from "../flow-runtime/flow-runtime.js";
29
+ import { createIndexQueue, IndexMessage } from "../index-queue/index-queue.js";
30
+ import { createJsonSchemaValidator } from "../json-schema/json-schema.js";
31
+ import { createOpenId } from "../openid/openid.js";
32
+ import { createPortalTokenStore } from "../portal-tokens/portal-tokens.js";
33
+ import { createRemoteTools } from "../remote-tools/remote-tools.js";
34
+ import { createSemanticIndex } from "../semantic-index/semantic-index.js";
35
+ import { createSessionCodec } from "../session-cookie/session-cookie.js";
36
+ import { createToolSourcePolicy } from "../tool-source-policy/tool-source-policy.js";
37
+ // biome-ignore lint/performance/noBarrelFile: The package entry must expose Wrangler's named Workflow class.
38
+ export { IntelFlowWorkflow } from "./cloudflare-flow-workflow.js";
39
+ const workerPrefixes = ["/api", "/auth", "/.well-known", "/mcp", "/health"];
40
+ export function isSpaNavigation(request) {
41
+ if (request.method !== "GET" && request.method !== "HEAD")
42
+ return false;
43
+ if (!request.headers.get("accept")?.includes("text/html"))
44
+ return false;
45
+ const { pathname } = new URL(request.url);
46
+ return !workerPrefixes.some((prefix) => pathname === prefix || pathname.startsWith(`${prefix}/`));
47
+ }
48
+ // A missing variable would otherwise surface deep inside a request as an opaque URL or crypto
49
+ // error. Naming it once here keeps a misconfigured deployment diagnosable.
50
+ const requiredVariables = [
51
+ "GATE_URL",
52
+ "GATE_SERVICE_KEY",
53
+ "INTEL_URL",
54
+ "INTEL_SESSION_SECRET",
55
+ "TOOL_SOURCE_ORIGINS",
56
+ ];
57
+ function assertConfigured(env) {
58
+ const missing = requiredVariables.filter((name) => !env[name]?.trim());
59
+ if (missing.length) {
60
+ throw new IntelError(500, "configuration_missing", `Intel is missing required configuration: ${missing.join(", ")}`);
61
+ }
62
+ }
63
+ /**
64
+ * The two ports that call Workers AI, and the one condition that decides whether they exist at all
65
+ * (#800).
66
+ *
67
+ * ⚠️ **No gateway id, no ports.** The obvious spelling would have been to pass the gateway when
68
+ * there is one and call Workers AI directly when there is not — and that is precisely the silent
69
+ * bypass the spend limit exists against: the deployment keeps embedding on every save and every
70
+ * `reindex`, the gateway counts none of it, and nobody notices because everything works. A missing
71
+ * semantic index is a state this repository already knows and describes (see the bindings table in
72
+ * the package README); an unmetered one is not.
73
+ *
74
+ * ⚠️ Both ports fall away together, because both call Workers AI: the embeddings through `run` and
75
+ * the attachment conversion through `toMarkdown`. Repairing only the first half would have left a
76
+ * second door open on the same account.
77
+ */
78
+ export function createAiPorts(env) {
79
+ const gateway = env.AI_GATEWAY_ID?.trim();
80
+ if (!env.AI || !gateway)
81
+ return { semantic: undefined, converter: undefined };
82
+ return {
83
+ // Vectorize stays its own condition: without an index to write into there is nothing to embed
84
+ // for, and that half of the answer predates this ticket.
85
+ semantic: env.SEARCH
86
+ ? createSemanticIndex({ ai: env.AI, index: env.SEARCH, gateway })
87
+ : undefined,
88
+ converter: createDocumentConverter({ ai: env.AI, gateway }),
89
+ };
90
+ }
91
+ export default {
92
+ async fetch(request, env, _context) {
93
+ if (env.ASSETS && isSpaNavigation(request)) {
94
+ return await env.ASSETS.fetch(new Request(new URL("/", request.url), { method: "GET" }));
95
+ }
96
+ assertConfigured(env);
97
+ const now = () => new Date();
98
+ const { semantic } = createAiPorts(env);
99
+ // Built before the tree because the tree has to ask it one question: who calls into a folder
100
+ // from outside it. The repository knows no service, so this stays one direction of dependency.
101
+ const flowRepository = createFlowRepository({ db: env.DB, now });
102
+ const nodeRepository = createNodeRepository({ db: env.DB, now });
103
+ const auditRepository = createAuditRepository({ db: env.DB, now });
104
+ const feedRepository = createFeedRepository({ db: env.DB, now });
105
+ const boardRepository = createBoardRepository({ db: env.DB, now });
106
+ const contentStore = createContentStore(env.CONTENT);
107
+ const gate = createGateClient({ url: env.GATE_URL, serviceKey: env.GATE_SERVICE_KEY });
108
+ const oauth = createOpenId({
109
+ fetch: globalThis.fetch.bind(globalThis),
110
+ allowInsecure: env.ALLOW_INSECURE_OAUTH === "true",
111
+ });
112
+ const intelResource = `${env.INTEL_URL.replace(/\/+$/, "")}/mcp`;
113
+ const portalUrl = env.MCP_PORTAL_URL?.trim() || null;
114
+ const portalTokens = createPortalTokenStore({
115
+ db: env.DB,
116
+ secret: env.INTEL_SESSION_SECRET,
117
+ crypto,
118
+ now,
119
+ });
120
+ const tools = createTools({
121
+ portalUrl,
122
+ remote: createRemoteTools({ fetch: globalThis.fetch.bind(globalThis) }),
123
+ tokens: portalTokens,
124
+ refresh: async (token) => {
125
+ try {
126
+ const refreshed = await oauth.refresh({
127
+ issuer: token.issuer,
128
+ clientId: token.clientId,
129
+ resource: token.resource,
130
+ refreshToken: token.refreshToken ?? "",
131
+ });
132
+ return {
133
+ ...token,
134
+ accessToken: refreshed.accessToken,
135
+ refreshToken: refreshed.refreshToken ?? token.refreshToken,
136
+ expiresAt: now().getTime() + Math.max(30, refreshed.expiresIn) * 1_000,
137
+ };
138
+ }
139
+ catch {
140
+ // A refusal from the portal's issuer means the grant is gone; the caller drops the token
141
+ // and asks the user to reconnect rather than retrying a dead credential.
142
+ return null;
143
+ }
144
+ },
145
+ now,
146
+ validate: createJsonSchemaValidator(),
147
+ sourceAllowed: createToolSourcePolicy(env.TOOL_SOURCE_ORIGINS),
148
+ fingerprint: async (value) => {
149
+ return await sha256Hex(crypto, JSON.stringify(value));
150
+ },
151
+ });
152
+ const nodes = createNodes({
153
+ repository: nodeRepository,
154
+ content: contentStore,
155
+ id: ulid,
156
+ now,
157
+ // ⚠️ The REPOSITORY, not the board service — that is what keeps this from being a cycle. The
158
+ // board service needs the node service to create a task; the node service needs only the two
159
+ // reads below to file one.
160
+ // ⚠️ `"write"` for the same reason as below: this answers "may this actor file a card here",
161
+ // not "may they look at it". Reading it with `"read"` would let somebody nest a card under a
162
+ // task on a board they may only look at.
163
+ boardOfTask: async (who, taskId) => (await boardRepository.taskRow(who, taskId, "write"))?.boardId ?? null,
164
+ attachToBoard: async (who, taskId, boardId, occurredAt) => {
165
+ // ⚠️ `"write"` — the actor is filing a task on this board, and the board's own creation
166
+ // path is a write too. `"read"` here would put back exactly the hole #649 found.
167
+ const columns = await boardRepository.columnsOf(who, boardId, "write");
168
+ // `null` means the parent is not a board this actor may read — then there is nothing to
169
+ // file the task on, and the node stands on its own. That is the folder case, and it is
170
+ // silent on purpose: a `task` filed in a plain folder is unusual, not an error.
171
+ if (columns === null)
172
+ return;
173
+ const status = columns[0] ?? FIRST_DEFAULT_COLUMN;
174
+ await boardRepository.attach({
175
+ nodeId: taskId,
176
+ boardId,
177
+ status,
178
+ assigneeId: null,
179
+ labels: [],
180
+ startDate: null,
181
+ dueDate: null,
182
+ dependsOn: null,
183
+ position: await boardRepository.nextPosition(boardId, status),
184
+ occurredAt,
185
+ });
186
+ },
187
+ indexing: createIndexQueue(env.INDEXING),
188
+ semantic,
189
+ externalFlowCallers: async (who, folderId) => await flowRepository.externalCallers(who, folderId),
190
+ flowNodeReferences: async (who, folderId) => await flowRepository.nodeReferences(who, folderId),
191
+ // ⚠️ The real one, like its two neighbours: the refusal is only worth anything if it reads
192
+ // real published graphs and the real visibility predicate (#457).
193
+ flowsUsingNode: async (who, nodeId) => await flowRepository.flowsUsingNode({ ...who, canRun: true }, nodeId),
194
+ // ⚠️ `canExecute: true` is not a permission being granted here — the servers list touches
195
+ // nothing and executes nothing. It exists because `ToolActor` carries the flag for the one
196
+ // method that needs it, and a `false` would read as if listing were gated on execution.
197
+ toolServers: async (who) => {
198
+ const catalog = await tools.servers({ id: who.id, email: who.email, canExecute: true });
199
+ return catalog.items.map((server) => server.handle);
200
+ },
201
+ hash: async (content) => {
202
+ const source = typeof content === "string"
203
+ ? new TextEncoder().encode(content)
204
+ : Uint8Array.from(content).buffer;
205
+ return await sha256Hex(crypto, source);
206
+ },
207
+ });
208
+ const auth = createBrowserAuth({
209
+ baseUrl: env.INTEL_URL,
210
+ gateUrl: env.GATE_URL,
211
+ resource: intelResource,
212
+ oauth,
213
+ clients: createOAuthClientStore(env.DB),
214
+ sessions: createSessionCodec({ secret: env.INTEL_SESSION_SECRET, crypto }),
215
+ portalUrl,
216
+ portalTokens,
217
+ now,
218
+ });
219
+ const flows = createFlows({
220
+ repository: flowRepository,
221
+ runtime: createFlowRuntime(env.FLOWS),
222
+ id: ulid,
223
+ now,
224
+ folderAccess: async (actor, folderId) => await nodes.folderAccess(actor, folderId),
225
+ // ⚠️ Straight to the repository, past the node service: this one question is asked WITHOUT the
226
+ // visibility predicate on purpose (#733), and a service method taking an actor would invite
227
+ // somebody to hand one in.
228
+ parentArchivedAt: async (folderId) => await nodeRepository.parentArchivedAt(folderId),
229
+ nodeChildren: async (actor, folderId, limit) => await nodes.childrenBounded(actor, { parentId: folderId, limit }),
230
+ // The tree's own visibility lookup, unchanged on the way through: the relation graph, the
231
+ // requirements list and every tree link of every run read this one answer, so none of
232
+ // them can be kinder than the others.
233
+ visibleNodes: async (actor, nodeId) => await nodes.visibleNode(actor, nodeId),
234
+ // The outer ring of the relation graph (#825), straight to the repository like
235
+ // `parentArchivedAt` above: the graph has already proven a node visible through `visibleNodes`
236
+ // by the time it asks either of these, so there is nothing left for a service-level wrapper to
237
+ // add beyond what `nodes.ts:1537` already checks for `node_effective_access_list`.
238
+ nodeShareable: async (actor, nodeId) => await nodeRepository.can(actor, nodeId, "share"),
239
+ nodeEffectiveAccess: async (nodeId) => await nodeRepository.listEffectiveAccess(nodeId),
240
+ /**
241
+ * ⚠️ The fingerprint of a whole SURFACE, not of one tool (#489). A step names a server and
242
+ * optionally the functions of it it may use, so what publishing freezes is that set — every
243
+ * covered function's own fingerprint, sorted so the order the portal happens to answer in
244
+ * cannot change the result, and hashed into one value.
245
+ *
246
+ * `null` in three cases, and all three have to refuse a publish: the catalog is unreachable,
247
+ * the server offers this user nothing, or a function the step explicitly allows is gone. The
248
+ * last one matters most — a narrowed step whose function disappeared is not a step that may
249
+ * quietly fall back to the rest of the server.
250
+ */
251
+ toolSurfaceFingerprint: async (actor, server, allow) => {
252
+ const catalog = await tools
253
+ .catalog({ id: actor.id, email: actor.email, canExecute: true })
254
+ .catch(() => null);
255
+ if (!catalog)
256
+ return null;
257
+ const reachable = new Map(catalog.items.map((item) => [item.name, item.fingerprint]));
258
+ const covered = allow === null
259
+ ? [...reachable.keys()].filter((name) => serverOf(name, [server]) !== null)
260
+ : allow;
261
+ if (covered.length === 0)
262
+ return null;
263
+ const parts = [];
264
+ for (const name of [...new Set(covered)].sort()) {
265
+ const fingerprint = reachable.get(name);
266
+ if (!fingerprint)
267
+ return null;
268
+ parts.push(`${name}:${fingerprint}`);
269
+ }
270
+ // ⚠️ The handle and the narrowing mode are part of what is hashed, not just the covered
271
+ // functions. Without them two different surfaces could collide: a server whose only
272
+ // function is allowed explicitly would hash the same as the same server left open, and the
273
+ // difference between "this one function" and "whatever this server offers" is exactly what
274
+ // publishing is meant to freeze.
275
+ const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode([server, allow === null ? "*" : "allow", ...parts].join("\n")));
276
+ return [...new Uint8Array(digest)].map((b) => b.toString(16).padStart(2, "0")).join("");
277
+ },
278
+ // Which of the named servers this user does NOT reach. A server is reached when the live
279
+ // catalog carries at least one function of it — the same live answer the tool surface uses,
280
+ // never a mirrored table.
281
+ // ⚠️ The catalog error is NOT caught here, and that is the whole point. Answering an
282
+ // unreadable portal with "all of them are missing" turns an outage into a sentence about
283
+ // PERMISSIONS — the reader goes asking for access they already have, while the portal is
284
+ // simply down. `tools.catalog` already tells the two apart (`tool_catalog_unreadable`,
285
+ // `portal_not_connected`), and letting that answer through is the same rule the tool surface
286
+ // keeps one screen up: a sentence more specific than the evidence sends the reader looking in
287
+ // the wrong place.
288
+ unavailableServers: async (actor, servers) => {
289
+ if (servers.length === 0)
290
+ return [];
291
+ const catalog = await tools.catalog({ id: actor.id, email: actor.email, canExecute: true });
292
+ return servers.filter((server) => !catalog.items.some((item) => serverOf(item.name, [server]) !== null));
293
+ },
294
+ });
295
+ return await createIntel({
296
+ baseUrl: env.INTEL_URL,
297
+ gateUrl: env.GATE_URL,
298
+ gate,
299
+ nodes,
300
+ flows,
301
+ tools,
302
+ audit: createAudit({ audit: auditRepository }),
303
+ feed: createFeed({ feed: feedRepository }),
304
+ /**
305
+ * The slash-command catalogue (#775). It reads its own rows through its own repository and
306
+ * borrows exactly one thing from the node service: reading one document, with the
307
+ * authorization walk that service already performs. A second reader into R2 here would be a
308
+ * second place for that ACL to be applied, and the one that gets it wrong is the one nobody
309
+ * looks at.
310
+ */
311
+ prompts: createPrompts({
312
+ repository: createPromptRepository({ db: env.DB, now }),
313
+ // ⚠️ Handed on whole, and nothing is decided here. Turning a stored version into readable
314
+ // text is business behaviour, and this shell maps bindings — it does not get to know what a
315
+ // BlockNote payload is.
316
+ readDocument: async (actor, nodeId) => await nodes.get(actor, nodeId),
317
+ }),
318
+ boards: createBoards({
319
+ boards: boardRepository,
320
+ nodes,
321
+ now,
322
+ /**
323
+ * The seam to gate's directory (#700, D70).
324
+ *
325
+ * ⚠️ BUILT HERE AND NOWHERE ELSE, because this is the only place that legitimately holds
326
+ * the caller's bearer. `Actor` carries the resolved identity, never the credential that
327
+ * produced it, and the board service must stay that way: it narrows what gate offers, it
328
+ * does not get to speak for anybody.
329
+ *
330
+ * ⚠️ The token is resolved LAZILY and at most once. Two doors lead in and they answer
331
+ * differently — `/mcp` and the API carry an `Authorization` header, the browser carries a
332
+ * cookie the session has to be asked about — and doing that work eagerly would cost a
333
+ * session read on every request that never opens a picker.
334
+ *
335
+ * ⚠️ No token means an EMPTY answer, never a throw. A picker with no names shows nothing;
336
+ * a board that refuses to load because gate was slow is the worse outcome, and it would
337
+ * take the whole screen with it.
338
+ */
339
+ directory: (() => {
340
+ let pending = null;
341
+ const token = () => {
342
+ pending ??= (async () => bearer(request.headers) ?? (await auth.resolve(request.headers))?.bearer ?? null)();
343
+ return pending;
344
+ };
345
+ return {
346
+ async search(query) {
347
+ const value = await token();
348
+ if (!value)
349
+ return [];
350
+ return await gate.directory.search(value, { q: query });
351
+ },
352
+ async resolve(ids) {
353
+ const value = await token();
354
+ if (!value)
355
+ return [];
356
+ return await gate.directory.resolve(value, { ids });
357
+ },
358
+ };
359
+ })(),
360
+ }),
361
+ bundle: createBundle({
362
+ repository: nodeRepository,
363
+ flows: flowRepository,
364
+ content: contentStore,
365
+ id: ulid,
366
+ now,
367
+ hash: async (content) => {
368
+ const source = typeof content === "string"
369
+ ? new TextEncoder().encode(content)
370
+ : Uint8Array.from(content).buffer;
371
+ return await sha256Hex(crypto, source);
372
+ },
373
+ indexing: createIndexQueue(env.INDEXING),
374
+ }),
375
+ auth,
376
+ }).fetch(request);
377
+ },
378
+ async queue(batch, env) {
379
+ const { semantic, converter } = createAiPorts(env);
380
+ const indexing = createIndexing({
381
+ repository: createNodeIndexRepository(env.DB),
382
+ content: createContentStore(env.CONTENT),
383
+ semantic,
384
+ converter,
385
+ hash: async (content) => await sha256Hex(crypto, content),
386
+ now: () => new Date(),
387
+ });
388
+ for (const message of batch.messages) {
389
+ const parsed = IndexMessage.safeParse(message.body);
390
+ if (!parsed.success) {
391
+ console.warn("Intel discarded an invalid indexing queue message");
392
+ message.ack();
393
+ continue;
394
+ }
395
+ try {
396
+ await indexing.index(parsed.data.versionId);
397
+ message.ack();
398
+ }
399
+ catch (error) {
400
+ if (error instanceof PermanentIndexingError) {
401
+ console.warn("Intel discarded a permanently unindexable node version", {
402
+ versionId: parsed.data.versionId,
403
+ error: error.message,
404
+ });
405
+ message.ack();
406
+ continue;
407
+ }
408
+ console.error("Intel indexing failed; Cloudflare retry policy will apply", {
409
+ versionId: parsed.data.versionId,
410
+ error: error instanceof Error ? error.message : "indexing_failed",
411
+ });
412
+ message.retry();
413
+ }
414
+ }
415
+ },
416
+ };
@@ -0,0 +1,31 @@
1
+ import type { R2Bucket } from "../content/content.types.js";
2
+ import type { D1Database } from "../db/db.types.js";
3
+ import type { MarkdownAiBinding } from "../document-converter/document-converter.types.js";
4
+ import type { WorkflowBinding } from "../flow-runtime/flow-runtime.types.js";
5
+ import type { IndexMessage } from "../index-queue/index-queue.js";
6
+ import type { QueueBatch, QueueProducer } from "../index-queue/index-queue.types.js";
7
+ import type { VectorizeBinding, WorkersAiBinding } from "../semantic-index/semantic-index.types.js";
8
+ export interface CloudflareEnv {
9
+ ASSETS?: {
10
+ fetch(request: Request): Promise<Response>;
11
+ };
12
+ DB: D1Database;
13
+ CONTENT: R2Bucket;
14
+ INDEXING: QueueProducer<IndexMessage>;
15
+ FLOWS: WorkflowBinding;
16
+ AI?: WorkersAiBinding & MarkdownAiBinding;
17
+ SEARCH?: VectorizeBinding;
18
+ GATE_URL: string;
19
+ GATE_SERVICE_KEY: string;
20
+ INTEL_URL: string;
21
+ INTEL_SESSION_SECRET: string;
22
+ TOOL_SOURCE_ORIGINS: string;
23
+ MCP_PORTAL_URL?: string;
24
+ ALLOW_INSECURE_OAUTH?: string;
25
+ AI_GATEWAY_ID?: string;
26
+ FLOW_RUN_STALL_TIMEOUT?: string;
27
+ }
28
+ export interface CloudflareExecutionContext {
29
+ waitUntil(promise: Promise<unknown>): void;
30
+ }
31
+ export type IndexQueueBatch = QueueBatch<unknown>;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,3 @@
1
+ import type { ContentStore } from "../../nodes/nodes.types.js";
2
+ import type { R2Bucket } from "./content.types.js";
3
+ export declare function createContentStore(bucket: R2Bucket): ContentStore;