@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,46 @@
1
+ import { type ToolServer } from "../../contract/tool.js";
2
+ /**
3
+ * The portal's own directory tool. It is an ordinary entry in `tools/list`, so it is reached the
4
+ * same way every other tool is: `tools/call` with the asking user's portal token.
5
+ *
6
+ * ⚠️ Its presence in the live list is also the permission check. A deployment whose portal does not
7
+ * offer it, or a user whose Access policies hide it, gets no server list at all — and therefore
8
+ * cannot delegate anything. That is deliberate: the alternative would be inventing the server list
9
+ * out of tool names, which is exactly the guess this module exists to avoid.
10
+ */
11
+ export declare const ServerDirectoryTool = "portal_list_servers";
12
+ export interface ToolServerDirectoryAnswer {
13
+ isError: boolean;
14
+ content: unknown[];
15
+ structuredContent?: unknown;
16
+ }
17
+ /**
18
+ * The servers this user reaches: the portal's directory, confirmed against the portal's live tool
19
+ * list.
20
+ *
21
+ * Two sets come out of one answer, and keeping them apart is the whole of this function:
22
+ *
23
+ * - **`declared`** — every identifier the directory mentions at all, disabled rows included. It is
24
+ * the universe `serverOf` attributes against, and it must be as WIDE as possible. ⚠️ Narrowing it
25
+ * widens the delegation: drop `wiki_extra` because the portal marked it disabled, and the live
26
+ * tool `wiki_extra__read` falls back onto `wiki` — a tool of a server nobody delegated, handed to
27
+ * an agent that was given `wiki`. Filtering therefore happens after attribution, never before it.
28
+ * - **the returned list** — what may actually be delegated: enabled, and confirmed by at least one
29
+ * live tool. Intel cannot prove that a directory identifier is the same string the namespace uses,
30
+ * so it only ever offers handles it has just seen work.
31
+ *
32
+ * ⚠️ What remains outside Intel's reach: a directory that omits a server whose tools ARE in
33
+ * `tools/list`. Nothing in the answer distinguishes that from a tool of the enclosing namespace, and
34
+ * the portal is the authority on its own servers — so an incomplete directory widens by exactly one
35
+ * namespace level, and it is a portal defect rather than something this code can detect.
36
+ */
37
+ export interface ToolServerDirectory {
38
+ /** Every identifier the directory mentioned. Attribute against this, never against `servers`. */
39
+ declared: string[];
40
+ /** What may be offered and delegated: enabled, and confirmed by a live tool. */
41
+ servers: ToolServer[];
42
+ }
43
+ export declare function toolServersFrom(input: {
44
+ directory: ToolServerDirectoryAnswer;
45
+ toolNames: string[];
46
+ }): ToolServerDirectory | null;
@@ -0,0 +1,177 @@
1
+ import { z } from "zod";
2
+ import { serverOf } from "../../contract/tool.js";
3
+ /**
4
+ * The portal's own directory tool. It is an ordinary entry in `tools/list`, so it is reached the
5
+ * same way every other tool is: `tools/call` with the asking user's portal token.
6
+ *
7
+ * ⚠️ Its presence in the live list is also the permission check. A deployment whose portal does not
8
+ * offer it, or a user whose Access policies hide it, gets no server list at all — and therefore
9
+ * cannot delegate anything. That is deliberate: the alternative would be inventing the server list
10
+ * out of tool names, which is exactly the guess this module exists to avoid.
11
+ */
12
+ export const ServerDirectoryTool = "portal_list_servers";
13
+ /**
14
+ * What the portal answers about one server, read as tolerantly as possible.
15
+ *
16
+ * ⚠️ Only the shape is assumed, never the vocabulary. The portal is somebody else's product and its
17
+ * payload is not part of any contract Intel owns, so every field is optional and the answer is
18
+ * accepted from `structuredContent`, from `{ servers: [...] }`, from a JSON text block, or — the
19
+ * form the live portal actually uses — from the prose block `proseRows` reads. What makes a row
20
+ * usable is not that it parsed but that its identifier is confirmed against the live tool list
21
+ * below.
22
+ */
23
+ const DirectoryRow = z.looseObject({
24
+ id: z.string().optional(),
25
+ name: z.string().optional(),
26
+ enabled: z.boolean().optional(),
27
+ });
28
+ const DirectoryRows = z.array(DirectoryRow);
29
+ const DirectoryEnvelope = z.looseObject({ servers: DirectoryRows });
30
+ /** A line the portal meant as a directory entry: `- <display name> (<handle>): <state>`. */
31
+ const ProseRow = /^\s*[-*•]\s+(.+?)\s*\(([^()\s]+)\)\s*:\s*(.*)$/;
32
+ /** What claims to be an entry at all. Everything else in the block is a heading or a hint. */
33
+ const ProseBullet = /^\s*[-*•]\s/;
34
+ /**
35
+ * ⚠️ Never the ✓. A tick is decoration: a different locale, a plain-text client or a later version
36
+ * of the portal writes the same fact another way, and a reading that hangs on one code point would
37
+ * silently switch every server off. What is read is the word, and the word alone.
38
+ *
39
+ * It has to be the WHOLE state, not a word inside it, because "disabled" contains "enabled" and
40
+ * "not enabled" is built from it — a substring test would read both as switched on, and that is the
41
+ * one direction this must never get wrong. Anything else the portal might write ("aktiviert",
42
+ * "enabled (3 tools)") is therefore not offerable, and stays declared.
43
+ */
44
+ function readsAsEnabled(state) {
45
+ const words = state.toLowerCase().match(/\p{L}+/gu);
46
+ return words !== null && words.length === 1 && words[0] === "enabled";
47
+ }
48
+ /**
49
+ * The portal's prose form: a heading, one bullet per server, a closing hint. It is what the live
50
+ * portal actually answers (#233), and it is read only after every JSON reading in `rows` has failed.
51
+ *
52
+ * ⚠️ This reading hangs on somebody else's wording and can break without warning. The portal owes
53
+ * Intel no format at all, so a reworded state, a translated page or a changed layout is a normal
54
+ * event here rather than a defect. Two things keep that from becoming a quiet widening:
55
+ *
56
+ * - **A bullet that does not read as a row refuses the whole answer.** Skipping it would hand back
57
+ * a directory with one server missing, and a missing row is not a smaller list — it lets that
58
+ * server's tools fall back onto the shorter handle that encloses them, which is exactly the
59
+ * widening the split between `declared` and `servers` exists to prevent. The price is that a
60
+ * portal which one day bullets its closing hint fails loudly with the same closed
61
+ * `tool_servers_unavailable` that #233 found; that is the intended direction.
62
+ * - **Nothing read here can invent a server.** A handle no live tool confirms is never offered, so
63
+ * a misread line costs an offer, never a delegation.
64
+ */
65
+ function proseRows(answer) {
66
+ const parsed = [];
67
+ for (const block of answer.content) {
68
+ if (typeof block !== "object" || block === null || !("text" in block))
69
+ continue;
70
+ const text = block.text;
71
+ if (typeof text !== "string")
72
+ continue;
73
+ for (const line of text.split("\n")) {
74
+ if (!ProseBullet.test(line))
75
+ continue;
76
+ const [, name, handle, state] = ProseRow.exec(line) ?? [];
77
+ if (name === undefined || handle === undefined)
78
+ return null;
79
+ // `id` carries the handle and `name` the display name, but neither is believed on its own:
80
+ // both stay candidates in `toolServersFrom`, and the live tool list decides which one
81
+ // actually namespaces.
82
+ parsed.push({ id: handle, name, enabled: readsAsEnabled(state ?? "") });
83
+ }
84
+ }
85
+ return parsed.length > 0 ? parsed : null;
86
+ }
87
+ /**
88
+ * Every place the portal could reasonably have put its list, tried in order. An MCP tool result is
89
+ * either structured or text, and a server that answers with `{ servers: [...] }` is as likely as
90
+ * one that answers with a bare array.
91
+ *
92
+ * ⚠️ The prose reading comes last and is ADDITIONAL, never replacing. The portal is somebody else's
93
+ * product: it answers in prose today and may answer structured tomorrow, and a structured answer
94
+ * must keep winning on the day it arrives beside a human sentence.
95
+ */
96
+ function rows(answer) {
97
+ const candidates = [answer.structuredContent];
98
+ for (const block of answer.content) {
99
+ if (typeof block === "object" && block !== null && "text" in block) {
100
+ const text = block.text;
101
+ if (typeof text !== "string")
102
+ continue;
103
+ try {
104
+ candidates.push(JSON.parse(text));
105
+ }
106
+ catch {
107
+ // A text block that is not JSON may still be the directory — see `proseRows` above. It is
108
+ // not fed to the JSON readings here, and it does not make them fail either: the portal may
109
+ // well add a human sentence beside the payload.
110
+ }
111
+ }
112
+ }
113
+ for (const candidate of candidates) {
114
+ const bare = DirectoryRows.safeParse(candidate);
115
+ if (bare.success)
116
+ return bare.data;
117
+ const wrapped = DirectoryEnvelope.safeParse(candidate);
118
+ if (wrapped.success)
119
+ return wrapped.data.servers;
120
+ }
121
+ return proseRows(answer);
122
+ }
123
+ /**
124
+ * ⚠️ The rule itself — longest match against declared handles, never a cut at an underscore — is
125
+ * `serverOf` in the contract (`src/contract`), because the tools screen has to read a name exactly the
126
+ * way the delegation does (#212). What stays here is what the rule is USED for: a tool whose prefix
127
+ * matches no declared handle belongs to no server and can never be delegated, which is what keeps
128
+ * the portal's own management tools (`portal_list_servers`, `portal_toggle_servers`) out of an
129
+ * agent's reach — the portal does not list itself as an upstream server.
130
+ */
131
+ /**
132
+ * ⚠️ A handle that would carry the portal's OWN tools is never a server anybody can be given.
133
+ *
134
+ * The portal does not list itself as an upstream, so in practice `portal` never appears in the
135
+ * directory — but "in practice" is not a guard. One row called `portal` (an upstream a customer
136
+ * happens to name that way, a future portal that describes itself) would make `portal_toggle_servers`
137
+ * a delegable tool, and an agent could then switch its delegator's MCP servers on and off. The rule
138
+ * is written as a question about reach rather than as a blocklist of one string: if delegating this
139
+ * handle would hand over `portal_list_servers`, the handle is refused.
140
+ */
141
+ function ownsTheDirectory(handle) {
142
+ return ServerDirectoryTool.startsWith(`${handle}_`);
143
+ }
144
+ export function toolServersFrom(input) {
145
+ const parsed = rows(input.directory);
146
+ if (parsed === null)
147
+ return null;
148
+ // `id` and `name` are both offered as candidates because the portal's directory names them
149
+ // separately and only one of them is the namespace. The live list decides which.
150
+ const display = new Map();
151
+ const offerable = new Set();
152
+ for (const row of parsed) {
153
+ for (const candidate of [row.name, row.id]) {
154
+ if (candidate === undefined || candidate.length === 0)
155
+ continue;
156
+ if (ownsTheDirectory(candidate))
157
+ continue;
158
+ if (!display.has(candidate))
159
+ display.set(candidate, row.name ?? row.id ?? candidate);
160
+ if (row.enabled !== false)
161
+ offerable.add(candidate);
162
+ }
163
+ }
164
+ const counts = new Map();
165
+ for (const toolName of input.toolNames) {
166
+ const handle = serverOf(toolName, display.keys());
167
+ if (handle === null || !offerable.has(handle))
168
+ continue;
169
+ counts.set(handle, (counts.get(handle) ?? 0) + 1);
170
+ }
171
+ return {
172
+ declared: [...display.keys()],
173
+ servers: [...counts.entries()]
174
+ .map(([handle, toolCount]) => ({ handle, name: display.get(handle) ?? handle, toolCount }))
175
+ .sort((a, b) => a.handle.localeCompare(b.handle)),
176
+ };
177
+ }
@@ -0,0 +1,2 @@
1
+ import type { ToolDeps, ToolService } from "./tools.types.js";
2
+ export declare function createTools(deps: ToolDeps): ToolService;
@@ -0,0 +1,207 @@
1
+ import { IntelError } from "../shared/intel-error/intel-error.js";
2
+ import { reportUnexpectedError } from "../shared/report-unexpected-error/report-unexpected-error.js";
3
+ import { ServerDirectoryTool, toolServersFrom, } from "./tool-servers/tool-servers.js";
4
+ const CallTimeoutMs = 15_000;
5
+ const MaxTools = 1_000;
6
+ const MaxResultBytes = 1_000_000;
7
+ // Refresh slightly early so a call cannot start with a token that expires mid-flight.
8
+ const RefreshWindowMs = 30_000;
9
+ /*
10
+ * ⚠️ Until #390 this file answered two kinds of caller: a person, and an agent acting on somebody
11
+ * else's portal connection (D30). The second one is gone with the agents, and with it the
12
+ * delegation lookup, the cut against the portal's server directory, and the audit row that named
13
+ * both principals. What is left is the rule the delegation was an exception to: the token is read
14
+ * per actor and never shared — one operator token for everybody would make every catalog the same
15
+ * one and the portal's Access policies decorative (ADR-0003).
16
+ */
17
+ export function createTools(deps) {
18
+ function portal() {
19
+ if (!deps.portalUrl || !deps.sourceAllowed(deps.portalUrl)) {
20
+ throw new IntelError(503, "portal_not_configured", "No MCP portal is configured for this deployment");
21
+ }
22
+ return deps.portalUrl;
23
+ }
24
+ // Authorization for tools lives entirely in the portal, so "may this user act" reduces to "does
25
+ // this user have a usable portal token".
26
+ async function accessToken(actor) {
27
+ const stored = await deps.tokens.read(actor.id);
28
+ if (!stored) {
29
+ throw new IntelError(401, "portal_not_connected", "The portal has not signed this user in yet");
30
+ }
31
+ if (stored.expiresAt > deps.now().getTime() + RefreshWindowMs)
32
+ return stored.accessToken;
33
+ const refreshed = stored.refreshToken ? await deps.refresh(stored) : null;
34
+ if (!refreshed) {
35
+ // Losing a connection is a visible event for the person and an invisible one for everybody
36
+ // else: the screen simply asks them to sign in again, and no trace says why. The two reasons
37
+ // need telling apart — a portal that issues no refresh token at all is a configuration
38
+ // problem, a refresh that gets rejected is a different one (#97).
39
+ reportUnexpectedError(new Error(`portal token dropped: ${stored.refreshToken ? "refresh was rejected" : "no refresh token was ever issued"}`));
40
+ // A token that cannot be renewed is dropped: leaving it would keep failing every call with a
41
+ // stale credential. The browser answers this by signing in silently again (#60); an MCP
42
+ // client sees the code and repeats its own authorization.
43
+ await deps.tokens.clear(actor.id);
44
+ throw new IntelError(401, "portal_reconnect_required", "The portal sign-in for this user has expired");
45
+ }
46
+ await deps.tokens.write(actor.id, refreshed);
47
+ return refreshed.accessToken;
48
+ }
49
+ /**
50
+ * ⚠️ Whatever the portal answers, the caller hears which side is at fault — never a bare 500.
51
+ *
52
+ * Measured against the live installation (#308): adding ONE server to the portal made
53
+ * `/api/v1/tools` answer `500 internal_error`, and with it every tool of every OTHER server
54
+ * disappeared — an empty tools screen, an agent profile that can offer nothing, and no hint
55
+ * anywhere which of the four servers caused it. The failure is total by nature (there is one
56
+ * `tools/list` for the whole portal, and the MCP client either parses it or does not), but the
57
+ * SILENCE was ours: the throw travelled up unhandled.
58
+ *
59
+ * `tool_catalog_unreadable` is therefore not a nicer word for the same outage. It is the
60
+ * difference between "Intel is broken" and "the portal answered something Intel could not read,
61
+ * and the reason is in the log" — the same rule `adapters/json-schema` learned the hard way in
62
+ * #229, where a catch-all that renamed the failure hid it for weeks.
63
+ */
64
+ async function remoteTools(actor) {
65
+ const token = await accessToken(actor);
66
+ const remote = await deps.remote
67
+ .list(portal(), token, AbortSignal.timeout(CallTimeoutMs))
68
+ .catch((error) => {
69
+ // An IntelError on this path is a decision somebody already made (an expired sign-in, a
70
+ // refusal). Renaming it would throw away the one message that names the actual cause.
71
+ if (error instanceof IntelError)
72
+ throw error;
73
+ reportUnexpectedError(error);
74
+ // ⚠️ Deliberately says nothing about WHY. This one catch covers a portal that answered
75
+ // something unparseable, a portal that did not answer at all (the deadline above), and a
76
+ // portal that refused — and a message naming one of them would be wrong for the other two.
77
+ // That is the #229 mistake in miniature: a sentence more specific than the evidence sends
78
+ // the reader looking in the wrong place. The evidence is in the log.
79
+ throw new IntelError(502, "tool_catalog_unreadable", "The MCP portal's tool list could not be read; the reason was logged");
80
+ });
81
+ if (remote.length > MaxTools) {
82
+ throw new IntelError(502, "tool_catalog_too_large", "The portal returned too many tools");
83
+ }
84
+ return remote;
85
+ }
86
+ /**
87
+ * The servers the portal says this connection reaches, confirmed against its live tool list.
88
+ *
89
+ * ⚠️ Fails rather than answering "none" when the portal keeps no directory. An empty list would
90
+ * be indistinguishable from "you have no servers", and the difference decides whether a screen
91
+ * says "connect something" or "this portal cannot be delegated from".
92
+ */
93
+ async function serverList(actor, toolNames) {
94
+ if (!toolNames.includes(ServerDirectoryTool)) {
95
+ throw new IntelError(502, "tool_servers_unavailable", `The portal does not offer ${ServerDirectoryTool}, so its servers cannot be listed`);
96
+ }
97
+ const answer = await deps.remote.call({
98
+ url: portal(),
99
+ accessToken: await accessToken(actor),
100
+ name: ServerDirectoryTool,
101
+ arguments: {},
102
+ signal: AbortSignal.timeout(CallTimeoutMs),
103
+ });
104
+ const directory = answer.isError ? null : toolServersFrom({ directory: answer, toolNames });
105
+ if (directory === null) {
106
+ throw new IntelError(502, "tool_servers_unavailable", "The portal did not answer with a server list this Intel can read");
107
+ }
108
+ return directory;
109
+ }
110
+ /**
111
+ * One live tools/list is both the catalog and the authorization answer: the portal only returns
112
+ * what this user may reach. Nothing here is cached as a permission.
113
+ */
114
+ async function capabilities(actor) {
115
+ const remote = await remoteTools(actor);
116
+ const items = [];
117
+ for (const tool of remote) {
118
+ items.push({
119
+ ...tool,
120
+ fingerprint: await deps.fingerprint({
121
+ name: tool.name,
122
+ inputSchema: tool.inputSchema,
123
+ outputSchema: tool.outputSchema,
124
+ annotations: tool.annotations,
125
+ }),
126
+ });
127
+ }
128
+ return items;
129
+ }
130
+ async function requireCapability(actor, name) {
131
+ const found = (await capabilities(actor)).find((capability) => capability.name === name);
132
+ if (!found) {
133
+ throw new IntelError(404, "tool_not_available", `Tool ${name} is not available to you`);
134
+ }
135
+ return found;
136
+ }
137
+ async function call(actor, input) {
138
+ if (!actor.canExecute) {
139
+ throw new IntelError(403, "tool_execute_forbidden", "Tool execution permission is required");
140
+ }
141
+ const capability = await requireCapability(actor, input.name);
142
+ const validation = deps.validate(capability.inputSchema, input.arguments);
143
+ if (!validation.valid) {
144
+ throw new IntelError(400, "tool_arguments_invalid", validation.detail ?? "Invalid arguments");
145
+ }
146
+ const result = await deps.remote.call({
147
+ url: portal(),
148
+ accessToken: await accessToken(actor),
149
+ name: capability.name,
150
+ arguments: input.arguments,
151
+ signal: AbortSignal.timeout(CallTimeoutMs),
152
+ });
153
+ if (new TextEncoder().encode(JSON.stringify(result)).byteLength > MaxResultBytes) {
154
+ throw new IntelError(502, "tool_result_too_large", "Tool result exceeded the Intel limit");
155
+ }
156
+ return result;
157
+ }
158
+ // A token that is gone or beyond renewal is the same answer as never having signed in, so reading
159
+ // a catalog reports it as a state. Only a portal that does not answer stays an error — the view
160
+ // has to tell "sign in again" apart from "the portal failed", and a 401 here would otherwise look
161
+ // like an expired Intel session to the browser.
162
+ function disconnected(error) {
163
+ return (error instanceof IntelError &&
164
+ (error.code === "portal_not_connected" || error.code === "portal_reconnect_required"));
165
+ }
166
+ return {
167
+ async catalog(actor) {
168
+ const stored = await deps.tokens.read(actor.id);
169
+ // No portal sign-in yet is a normal state, not an error: the browser answers it by running
170
+ // the silent sign-in and asking again (#60).
171
+ if (!stored)
172
+ return { portalConnected: false, items: [] };
173
+ try {
174
+ return { portalConnected: true, items: await capabilities(actor) };
175
+ }
176
+ catch (error) {
177
+ if (disconnected(error))
178
+ return { portalConnected: false, items: [] };
179
+ throw error;
180
+ }
181
+ },
182
+ async servers(actor) {
183
+ const stored = await deps.tokens.read(actor.id);
184
+ if (!stored)
185
+ return { portalConnected: false, items: [] };
186
+ try {
187
+ const remote = await remoteTools(actor);
188
+ const { servers } = await serverList(actor, remote.map((tool) => tool.name));
189
+ return { portalConnected: true, items: servers };
190
+ }
191
+ catch (error) {
192
+ if (disconnected(error))
193
+ return { portalConnected: false, items: [] };
194
+ throw error;
195
+ }
196
+ },
197
+ execute: async (actor, input) => await call(actor, input),
198
+ async test(actor, input) {
199
+ const capability = await requireCapability(actor, input.name);
200
+ if (capability.annotations.readOnlyHint !== true ||
201
+ capability.annotations.destructiveHint === true) {
202
+ throw new IntelError(409, "tool_test_unsafe", "Only explicitly read-only, non-destructive tools can run in the test surface");
203
+ }
204
+ return await call(actor, input);
205
+ },
206
+ };
207
+ }
@@ -0,0 +1,56 @@
1
+ import type { ExecuteToolInput, TestToolInput, ToolCapability, ToolCatalog, ToolServerCatalog, ToolTestResult } from "../contract/tool.js";
2
+ export interface ToolActor {
3
+ id: string;
4
+ email: string;
5
+ canExecute: boolean;
6
+ }
7
+ export interface PortalToken {
8
+ accessToken: string;
9
+ refreshToken: string | null;
10
+ expiresAt: number;
11
+ issuer: string;
12
+ clientId: string;
13
+ resource: string;
14
+ }
15
+ export interface PortalTokenStore {
16
+ read(userId: string): Promise<PortalToken | null>;
17
+ write(userId: string, token: PortalToken): Promise<void>;
18
+ clear(userId: string): Promise<void>;
19
+ }
20
+ export interface RemoteTool {
21
+ name: string;
22
+ title: string | null;
23
+ description: string | null;
24
+ inputSchema: Record<string, unknown>;
25
+ outputSchema: Record<string, unknown> | null;
26
+ annotations: ToolCapability["annotations"];
27
+ }
28
+ export interface RemoteTools {
29
+ list(url: string, accessToken: string, signal: AbortSignal): Promise<RemoteTool[]>;
30
+ call(input: {
31
+ url: string;
32
+ accessToken: string;
33
+ name: string;
34
+ arguments: Record<string, unknown>;
35
+ signal: AbortSignal;
36
+ }): Promise<ToolTestResult>;
37
+ }
38
+ export interface ToolDeps {
39
+ portalUrl: string | null;
40
+ remote: RemoteTools;
41
+ tokens: PortalTokenStore;
42
+ refresh(token: PortalToken): Promise<PortalToken | null>;
43
+ now(): Date;
44
+ fingerprint(value: unknown): Promise<string>;
45
+ sourceAllowed(url: string): boolean;
46
+ validate(schema: Record<string, unknown>, value: unknown): {
47
+ valid: boolean;
48
+ detail?: string;
49
+ };
50
+ }
51
+ export interface ToolService {
52
+ catalog(actor: ToolActor): Promise<ToolCatalog>;
53
+ servers(actor: ToolActor): Promise<ToolServerCatalog>;
54
+ execute(actor: ToolActor, input: ExecuteToolInput): Promise<ToolTestResult>;
55
+ test(actor: ToolActor, input: TestToolInput): Promise<ToolTestResult>;
56
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,5 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
2
+ <title>Customer Intel</title>
3
+ <rect width="32" height="32" rx="8" fill="oklch(0.5 0.18 250)"/>
4
+ <path d="M10 10h12v12H10zM7 14h3m12 0h3M14 7v3m4-3v3M14 22v3m4-3v3" fill="none" stroke="white" stroke-width="2" stroke-linecap="round"/>
5
+ </svg>
@@ -0,0 +1,5 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
2
+ <title>Customer Intel</title>
3
+ <rect width="32" height="32" rx="8" fill="oklch(0.5 0.18 250)"/>
4
+ <path d="M10 10h12v12H10zM7 14h3m12 0h3M14 7v3m4-3v3M14 22v3m4-3v3" fill="none" stroke="white" stroke-width="2" stroke-linecap="round"/>
5
+ </svg>
@@ -0,0 +1,16 @@
1
+ :root {
2
+ --radius: 0.75rem;
3
+ --primary: oklch(0.5 0.18 250);
4
+ --primary-foreground: oklch(0.98 0.01 250);
5
+ --sidebar-primary: oklch(0.5 0.18 250);
6
+ --sidebar-primary-foreground: oklch(0.98 0.01 250);
7
+ --ring: oklch(0.62 0.14 250);
8
+ }
9
+
10
+ .dark {
11
+ --primary: oklch(0.72 0.14 250);
12
+ --primary-foreground: oklch(0.16 0.03 250);
13
+ --sidebar-primary: oklch(0.72 0.14 250);
14
+ --sidebar-primary-foreground: oklch(0.16 0.03 250);
15
+ --ring: oklch(0.68 0.13 250);
16
+ }
@@ -0,0 +1,7 @@
1
+ GATE_URL=http://localhost:8787
2
+ INTEL_URL=http://localhost:8788
3
+ MCP_PORTAL_URL=https://portal.example.com/mcp
4
+ TOOL_SOURCE_ORIGINS=https://portal.example.com
5
+ ALLOW_INSECURE_OAUTH=true
6
+ GATE_SERVICE_KEY=replace-with-local-gate-service-key
7
+ INTEL_SESSION_SECRET=replace-with-at-least-32-random-bytes
@@ -0,0 +1,9 @@
1
+ {
2
+ "ui": {
3
+ "theme": "./branding/theme.css",
4
+ "logo": "./branding/logo.svg",
5
+ "favicon": "./branding/favicon.svg",
6
+ "defaultLanguage": "en",
7
+ "languages": {}
8
+ }
9
+ }