@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.
- package/README.md +496 -0
- package/bin/intel.mjs +134 -0
- package/dist/adapters/cloudflare/cloudflare-flow-workflow.d.ts +42 -0
- package/dist/adapters/cloudflare/cloudflare-flow-workflow.js +89 -0
- package/dist/adapters/cloudflare/cloudflare.d.ts +29 -0
- package/dist/adapters/cloudflare/cloudflare.js +416 -0
- package/dist/adapters/cloudflare/cloudflare.types.d.ts +31 -0
- package/dist/adapters/cloudflare/cloudflare.types.js +1 -0
- package/dist/adapters/content/content.d.ts +3 -0
- package/dist/adapters/content/content.js +128 -0
- package/dist/adapters/content/content.types.d.ts +38 -0
- package/dist/adapters/content/content.types.js +1 -0
- package/dist/adapters/db/db-audit.d.ts +62 -0
- package/dist/adapters/db/db-audit.js +150 -0
- package/dist/adapters/db/db-boards.d.ts +6 -0
- package/dist/adapters/db/db-boards.js +324 -0
- package/dist/adapters/db/db-feed.d.ts +30 -0
- package/dist/adapters/db/db-feed.js +276 -0
- package/dist/adapters/db/db-flows.d.ts +42 -0
- package/dist/adapters/db/db-flows.js +1311 -0
- package/dist/adapters/db/db-grants.d.ts +133 -0
- package/dist/adapters/db/db-grants.js +269 -0
- package/dist/adapters/db/db-indexing.d.ts +3 -0
- package/dist/adapters/db/db-indexing.js +200 -0
- package/dist/adapters/db/db-oauth.d.ts +3 -0
- package/dist/adapters/db/db-oauth.js +26 -0
- package/dist/adapters/db/db-prompts.d.ts +46 -0
- package/dist/adapters/db/db-prompts.js +144 -0
- package/dist/adapters/db/db.d.ts +6 -0
- package/dist/adapters/db/db.js +1687 -0
- package/dist/adapters/db/db.types.d.ts +16 -0
- package/dist/adapters/db/db.types.js +1 -0
- package/dist/adapters/document-converter/document-converter.d.ts +2 -0
- package/dist/adapters/document-converter/document-converter.js +26 -0
- package/dist/adapters/document-converter/document-converter.types.d.ts +17 -0
- package/dist/adapters/document-converter/document-converter.types.js +1 -0
- package/dist/adapters/flow-runtime/flow-runtime.d.ts +3 -0
- package/dist/adapters/flow-runtime/flow-runtime.js +22 -0
- package/dist/adapters/flow-runtime/flow-runtime.types.d.ts +19 -0
- package/dist/adapters/flow-runtime/flow-runtime.types.js +1 -0
- package/dist/adapters/index-queue/index-queue.d.ts +10 -0
- package/dist/adapters/index-queue/index-queue.js +12 -0
- package/dist/adapters/index-queue/index-queue.types.d.ts +11 -0
- package/dist/adapters/index-queue/index-queue.types.js +1 -0
- package/dist/adapters/json-schema/json-schema.d.ts +2 -0
- package/dist/adapters/json-schema/json-schema.js +77 -0
- package/dist/adapters/openid/openid.d.ts +5 -0
- package/dist/adapters/openid/openid.js +301 -0
- package/dist/adapters/portal-tokens/portal-tokens.d.ts +8 -0
- package/dist/adapters/portal-tokens/portal-tokens.js +79 -0
- package/dist/adapters/remote-tools/remote-tools.d.ts +5 -0
- package/dist/adapters/remote-tools/remote-tools.js +129 -0
- package/dist/adapters/semantic-index/semantic-index.d.ts +2 -0
- package/dist/adapters/semantic-index/semantic-index.js +139 -0
- package/dist/adapters/semantic-index/semantic-index.types.d.ts +56 -0
- package/dist/adapters/semantic-index/semantic-index.types.js +1 -0
- package/dist/adapters/session-cookie/session-cookie.d.ts +5 -0
- package/dist/adapters/session-cookie/session-cookie.js +87 -0
- package/dist/adapters/tool-source-policy/tool-source-policy.d.ts +1 -0
- package/dist/adapters/tool-source-policy/tool-source-policy.js +22 -0
- package/dist/audit/audit.d.ts +2 -0
- package/dist/audit/audit.js +87 -0
- package/dist/audit/audit.types.d.ts +23 -0
- package/dist/audit/audit.types.js +1 -0
- package/dist/auth/auth.d.ts +2 -0
- package/dist/auth/auth.js +284 -0
- package/dist/auth/auth.types.d.ts +108 -0
- package/dist/auth/auth.types.js +1 -0
- package/dist/boards/boards.d.ts +44 -0
- package/dist/boards/boards.js +447 -0
- package/dist/boards/boards.types.d.ts +117 -0
- package/dist/boards/boards.types.js +1 -0
- package/dist/build/build.d.ts +2 -0
- package/dist/build/build.js +192 -0
- package/dist/build/build.types.d.ts +17 -0
- package/dist/build/build.types.js +1 -0
- package/dist/bundle/bundle.d.ts +4 -0
- package/dist/bundle/bundle.js +1194 -0
- package/dist/bundle/bundle.types.d.ts +33 -0
- package/dist/bundle/bundle.types.js +1 -0
- package/dist/cli/cli.d.ts +4 -0
- package/dist/cli/cli.js +262 -0
- package/dist/cli/cli.types.d.ts +14 -0
- package/dist/cli/cli.types.js +1 -0
- package/dist/contract/audit.d.ts +50 -0
- package/dist/contract/audit.js +72 -0
- package/dist/contract/board.d.ts +150 -0
- package/dist/contract/board.js +262 -0
- package/dist/contract/bundle.d.ts +147 -0
- package/dist/contract/bundle.js +139 -0
- package/dist/contract/contract.d.ts +112 -0
- package/dist/contract/contract.js +143 -0
- package/dist/contract/feed.d.ts +126 -0
- package/dist/contract/feed.js +149 -0
- package/dist/contract/flow-run.d.ts +346 -0
- package/dist/contract/flow-run.js +194 -0
- package/dist/contract/flow.d.ts +1057 -0
- package/dist/contract/flow.js +552 -0
- package/dist/contract/node.d.ts +551 -0
- package/dist/contract/node.js +456 -0
- package/dist/contract/share.d.ts +216 -0
- package/dist/contract/share.js +134 -0
- package/dist/contract/table.d.ts +171 -0
- package/dist/contract/table.js +117 -0
- package/dist/contract/tool.d.ts +122 -0
- package/dist/contract/tool.js +172 -0
- package/dist/feed/feed.d.ts +2 -0
- package/dist/feed/feed.js +77 -0
- package/dist/feed/feed.types.d.ts +23 -0
- package/dist/feed/feed.types.js +1 -0
- package/dist/flows/flows.d.ts +41 -0
- package/dist/flows/flows.js +2216 -0
- package/dist/flows/flows.types.d.ts +339 -0
- package/dist/flows/flows.types.js +1 -0
- package/dist/http/http.d.ts +9 -0
- package/dist/http/http.js +874 -0
- package/dist/http/http.types.d.ts +22 -0
- package/dist/http/http.types.js +1 -0
- package/dist/indexing/indexing.d.ts +6 -0
- package/dist/indexing/indexing.js +239 -0
- package/dist/indexing/indexing.types.d.ts +11 -0
- package/dist/indexing/indexing.types.js +1 -0
- package/dist/intel/intel.d.ts +3 -0
- package/dist/intel/intel.js +194 -0
- package/dist/intel/intel.types.d.ts +24 -0
- package/dist/intel/intel.types.js +1 -0
- package/dist/mcp/mcp.d.ts +2 -0
- package/dist/mcp/mcp.js +1292 -0
- package/dist/mcp/mcp.types.d.ts +25 -0
- package/dist/mcp/mcp.types.js +1 -0
- package/dist/nodes/document-links/document-links.d.ts +20 -0
- package/dist/nodes/document-links/document-links.js +57 -0
- package/dist/nodes/nodes.d.ts +2 -0
- package/dist/nodes/nodes.js +1667 -0
- package/dist/nodes/nodes.types.d.ts +511 -0
- package/dist/nodes/nodes.types.js +1 -0
- package/dist/prepare/prepare.d.ts +4 -0
- package/dist/prepare/prepare.js +16 -0
- package/dist/prepare/prepare.types.d.ts +9 -0
- package/dist/prepare/prepare.types.js +1 -0
- package/dist/prompts/prompts.d.ts +2 -0
- package/dist/prompts/prompts.js +65 -0
- package/dist/prompts/prompts.types.d.ts +71 -0
- package/dist/prompts/prompts.types.js +1 -0
- package/dist/shared/callers/callers.d.ts +28 -0
- package/dist/shared/callers/callers.js +30 -0
- package/dist/shared/csv/csv.d.ts +13 -0
- package/dist/shared/csv/csv.js +85 -0
- package/dist/shared/document-text/document-text.d.ts +21 -0
- package/dist/shared/document-text/document-text.js +31 -0
- package/dist/shared/gate-authorization/gate-authorization.d.ts +5 -0
- package/dist/shared/gate-authorization/gate-authorization.js +26 -0
- package/dist/shared/grant-expiry/grant-expiry.d.ts +19 -0
- package/dist/shared/grant-expiry/grant-expiry.js +26 -0
- package/dist/shared/intel-error/intel-error.d.ts +22 -0
- package/dist/shared/intel-error/intel-error.js +27 -0
- package/dist/shared/plain-title/plain-title.d.ts +16 -0
- package/dist/shared/plain-title/plain-title.js +45 -0
- package/dist/shared/problem-details/problem-details.d.ts +30 -0
- package/dist/shared/problem-details/problem-details.js +18 -0
- package/dist/shared/report-unexpected-error/report-unexpected-error.d.ts +1 -0
- package/dist/shared/report-unexpected-error/report-unexpected-error.js +37 -0
- package/dist/shared/safe-return-path/safe-return-path.d.ts +2 -0
- package/dist/shared/safe-return-path/safe-return-path.js +11 -0
- package/dist/shared/sha256/sha256.d.ts +2 -0
- package/dist/shared/sha256/sha256.js +14 -0
- package/dist/tools/tool-servers/tool-servers.d.ts +46 -0
- package/dist/tools/tool-servers/tool-servers.js +177 -0
- package/dist/tools/tools.d.ts +2 -0
- package/dist/tools/tools.js +207 -0
- package/dist/tools/tools.types.d.ts +56 -0
- package/dist/tools/tools.types.js +1 -0
- package/examples/branding/favicon.svg +5 -0
- package/examples/branding/logo.svg +5 -0
- package/examples/branding/theme.css +16 -0
- package/examples/dev.vars.example +7 -0
- package/examples/intel.json +9 -0
- package/migrations/0000_intel_foundation.sql +203 -0
- package/migrations/0001_portal_native_tools.sql +21 -0
- package/migrations/0002_flows_in_the_knowledge_tree.sql +34 -0
- package/migrations/0003_folder_permissions.sql +211 -0
- package/migrations/0004_subflow_runs.sql +14 -0
- package/migrations/0005_flow_node_cleanup.sql +28 -0
- package/migrations/0005_tables_in_the_knowledge_tree.sql +68 -0
- package/migrations/0006_links_are_written_in_the_text.sql +20 -0
- package/migrations/0007_no_node_waits.sql +69 -0
- package/migrations/0008_three_layers.sql +130 -0
- package/migrations/0009_no_context_policy.sql +48 -0
- package/migrations/0010_no_run_waits_a_year.sql +27 -0
- package/migrations/0011_one_name_for_the_tree.sql +53 -0
- package/migrations/0012_table_snapshots.sql +29 -0
- package/migrations/0017_a_vector_per_card.sql +38 -0
- package/migrations/0018_no_context_policy_at_last.sql +97 -0
- package/migrations/0019_one_name_for_the_grants.sql +52 -0
- package/migrations/0020_cascade_purge_replay.sql +11 -0
- package/migrations/0021_a_flow_carries_its_own_grant.sql +44 -0
- package/migrations/0022_a_cursor_over_the_journal.sql +14 -0
- package/migrations/0023_a_board_and_its_tasks.sql +116 -0
- package/migrations/0024_the_archive_is_a_column.sql +33 -0
- package/migrations/0025_archiving_takes_the_subtree.sql +29 -0
- package/migrations/0026_one_feed_over_two_kinds.sql +23 -0
- package/migrations/0027_the_runs_of_every_flow.sql +27 -0
- package/migrations/0028_a_prompt_name_over_two_kinds.sql +70 -0
- package/package.json +118 -0
- package/src/contract/CLAUDE.md +152 -0
- package/src/contract/README.md +102 -0
- package/src/contract/audit.ts +85 -0
- package/src/contract/board.ts +306 -0
- package/src/contract/bundle.ts +157 -0
- package/src/contract/contract.ts +161 -0
- package/src/contract/feed.ts +165 -0
- package/src/contract/flow-run.ts +241 -0
- package/src/contract/flow.ts +675 -0
- package/src/contract/node.ts +583 -0
- package/src/contract/share.ts +196 -0
- package/src/contract/table.ts +178 -0
- package/src/contract/tool.ts +202 -0
- package/ui/README.md +110 -0
- package/ui/components.json +21 -0
- package/ui/index.html +13 -0
- package/ui/package.json +11 -0
- package/ui/scripts/lint-tokens.mjs +187 -0
- package/ui/src/access-summary/access-summary.tsx +385 -0
- package/ui/src/app/action-slot/action-slot.tsx +27 -0
- package/ui/src/app/app-sidebar/app-sidebar.tsx +71 -0
- package/ui/src/app/app-tree/app-tree.tsx +1175 -0
- package/ui/src/app/app.tsx +87 -0
- package/ui/src/app/header-search/header-search.tsx +294 -0
- package/ui/src/app/reindex-dialog/reindex-dialog.tsx +79 -0
- package/ui/src/app/settings-dialog/settings-dialog.tsx +135 -0
- package/ui/src/app/sidebar-preferences/sidebar-preferences.ts +68 -0
- package/ui/src/app/sidebar-preferences/sidebar-preferences.types.ts +15 -0
- package/ui/src/app/sidebar-resize-handle/sidebar-resize-handle.tsx +86 -0
- package/ui/src/app/tree-expansion/tree-expansion.ts +107 -0
- package/ui/src/app/tree-expansion/tree-expansion.types.ts +31 -0
- package/ui/src/app/tree-move/tree-move.tsx +427 -0
- package/ui/src/app/tree-reveal/tree-reveal.ts +64 -0
- package/ui/src/app/tree-reveal/tree-reveal.types.ts +16 -0
- package/ui/src/app/user-footer/user-footer.tsx +188 -0
- package/ui/src/app/view-menu/view-menu.tsx +115 -0
- package/ui/src/app-root/app-root.tsx +109 -0
- package/ui/src/app-root/app-root.types.ts +27 -0
- package/ui/src/archive/archive.tsx +417 -0
- package/ui/src/attachment-detail/attachment-detail.ts +52 -0
- package/ui/src/attachment-viewer/attachment-viewer.tsx +166 -0
- package/ui/src/blocknote-view/blocknote-view.tsx +30 -0
- package/ui/src/board/board-assignee/board-assignee-picker.tsx +132 -0
- package/ui/src/board/board-assignee/board-assignee.ts +48 -0
- package/ui/src/board/board-assignee/board-assignee.tsx +75 -0
- package/ui/src/board/board-chip/board-chip.tsx +46 -0
- package/ui/src/board/board-crumbs/board-crumbs.ts +56 -0
- package/ui/src/board/board-crumbs/board-crumbs.tsx +111 -0
- package/ui/src/board/board-data/board-data.ts +195 -0
- package/ui/src/board/board-data/board-data.types.ts +38 -0
- package/ui/src/board/board-dates/board-dates.ts +40 -0
- package/ui/src/board/board-dates/board-dates.tsx +105 -0
- package/ui/src/board/board-kanban/board-kanban.ts +162 -0
- package/ui/src/board/board-kanban/board-kanban.tsx +680 -0
- package/ui/src/board/board-open-task/board-open-task.ts +32 -0
- package/ui/src/board/board-panel/board-panel.tsx +259 -0
- package/ui/src/board/board-settings/board-settings.tsx +226 -0
- package/ui/src/board/board-status/board-status.tsx +60 -0
- package/ui/src/board/board-stripes/board-stripes.ts +128 -0
- package/ui/src/board/board-table/board-table.ts +53 -0
- package/ui/src/board/board-table/board-table.tsx +610 -0
- package/ui/src/board/board-task/board-task.ts +108 -0
- package/ui/src/board/board-task/board-task.tsx +335 -0
- package/ui/src/board/board-title-row/board-title-row.tsx +66 -0
- package/ui/src/branding/branding.tsx +17 -0
- package/ui/src/branding/custom-logo.ts +1 -0
- package/ui/src/branding/favicon.default.svg +5 -0
- package/ui/src/branding/favicon.svg +5 -0
- package/ui/src/components/ui/avatar.tsx +39 -0
- package/ui/src/components/ui/button.tsx +64 -0
- package/ui/src/components/ui/collapsible.tsx +20 -0
- package/ui/src/components/ui/command.tsx +160 -0
- package/ui/src/components/ui/dialog.tsx +143 -0
- package/ui/src/components/ui/dropdown-menu.tsx +187 -0
- package/ui/src/components/ui/input.tsx +21 -0
- package/ui/src/components/ui/popover.tsx +41 -0
- package/ui/src/components/ui/select.tsx +163 -0
- package/ui/src/components/ui/separator.tsx +26 -0
- package/ui/src/components/ui/sheet.tsx +136 -0
- package/ui/src/components/ui/sidebar.tsx +693 -0
- package/ui/src/components/ui/skeleton.tsx +13 -0
- package/ui/src/components/ui/switch.tsx +25 -0
- package/ui/src/components/ui/table.tsx +82 -0
- package/ui/src/components/ui/tabs.tsx +52 -0
- package/ui/src/components/ui/tooltip.tsx +51 -0
- package/ui/src/data/intel-data-provider/intel-data-provider.ts +685 -0
- package/ui/src/data/intel-data-provider/intel-data-provider.types.ts +266 -0
- package/ui/src/data/query-client.ts +18 -0
- package/ui/src/data/request-refusal/refusal-notice.tsx +36 -0
- package/ui/src/data/request-refusal/request-refusal.ts +51 -0
- package/ui/src/data/sign-in/sign-in.ts +97 -0
- package/ui/src/data/sign-in/sign-in.types.ts +15 -0
- package/ui/src/document-link/document-link.tsx +114 -0
- package/ui/src/document-markdown/document-markdown.ts +195 -0
- package/ui/src/editor-schema/editor-schema.ts +23 -0
- package/ui/src/entry-picker/entry-picker.tsx +238 -0
- package/ui/src/feed/feed.tsx +344 -0
- package/ui/src/file-preview/file-preview-view.tsx +496 -0
- package/ui/src/file-preview/file-preview.tsx +28 -0
- package/ui/src/file-preview/pdf-file-preview.tsx +5 -0
- package/ui/src/file-preview/presentation-file-preview.tsx +21 -0
- package/ui/src/file-preview/spreadsheet-file-preview.tsx +5 -0
- package/ui/src/file-preview/word-file-preview.tsx +5 -0
- package/ui/src/flow-runs/flow-runs.tsx +238 -0
- package/ui/src/flows/flows.tsx +1646 -0
- package/ui/src/flows/node-icon/node-icon.ts +34 -0
- package/ui/src/flows/node-palette/node-palette.tsx +214 -0
- package/ui/src/flows/node-palette/node-palette.types.ts +15 -0
- package/ui/src/folder-contents/folder-contents.tsx +321 -0
- package/ui/src/folder-index/folder-index.ts +55 -0
- package/ui/src/frontmatter/frontmatter.tsx +193 -0
- package/ui/src/graph-pane/graph-pane.tsx +53 -0
- package/ui/src/hooks/use-mobile.ts +19 -0
- package/ui/src/i18n/custom.json +4 -0
- package/ui/src/i18n/de.json +609 -0
- package/ui/src/i18n/en.json +609 -0
- package/ui/src/i18n/es.json +609 -0
- package/ui/src/i18n/i18n-context.tsx +65 -0
- package/ui/src/i18n/i18n-languages/i18n-languages.ts +83 -0
- package/ui/src/i18n/i18n.ts +32 -0
- package/ui/src/i18n/i18n.types.ts +49 -0
- package/ui/src/kind-icon.ts +97 -0
- package/ui/src/lib/utils.ts +6 -0
- package/ui/src/main.tsx +68 -0
- package/ui/src/modal/modal.tsx +53 -0
- package/ui/src/node-details/node-details.tsx +545 -0
- package/ui/src/node-editor/node-editor.tsx +304 -0
- package/ui/src/node-graph/graph-notice.tsx +21 -0
- package/ui/src/node-graph/node-graph.ts +214 -0
- package/ui/src/node-graph/node-graph.tsx +295 -0
- package/ui/src/node-import/node-import.tsx +418 -0
- package/ui/src/node-save-error.ts +46 -0
- package/ui/src/node-source/node-source.tsx +128 -0
- package/ui/src/node-table/node-table.tsx +107 -0
- package/ui/src/nodes/nodes.tsx +240 -0
- package/ui/src/rename-resource/rename-resource.ts +80 -0
- package/ui/src/resolved-names/resolved-names.tsx +67 -0
- package/ui/src/resource-error.ts +33 -0
- package/ui/src/resource-menu/resource-menu.tsx +1156 -0
- package/ui/src/router/router-context.ts +6 -0
- package/ui/src/router/router.tsx +67 -0
- package/ui/src/router/router.types.ts +8 -0
- package/ui/src/router/selection-search.ts +88 -0
- package/ui/src/save-button/save-button.tsx +94 -0
- package/ui/src/section-hint/section-hint.tsx +40 -0
- package/ui/src/sign-in-refused/sign-in-refused.tsx +35 -0
- package/ui/src/styles.css +189 -0
- package/ui/src/table-columns/table-columns.tsx +379 -0
- package/ui/src/theme/custom.css +1 -0
- package/ui/src/theme/theme-context.tsx +89 -0
- package/ui/src/theme/theme.ts +70 -0
- package/ui/src/time/relative-time.tsx +41 -0
- package/ui/src/time/time-context.tsx +78 -0
- package/ui/src/time/time.ts +165 -0
- package/ui/src/title-row/title-row.tsx +185 -0
- package/ui/src/tools/tools.tsx +546 -0
- package/ui/src/user-name/user-name.ts +61 -0
- package/ui/src/verbatim/verbatim.tsx +68 -0
- package/ui/tsconfig.json +17 -0
- package/ui/vite.config.ts +129 -0
package/README.md
ADDED
|
@@ -0,0 +1,496 @@
|
|
|
1
|
+
# @anchrd/intel
|
|
2
|
+
|
|
3
|
+
Intel is a customer-deployed, model-agnostic operating layer for company intelligence and processes. It
|
|
4
|
+
gives people and MCP-capable AI clients the same governed access to three surfaces:
|
|
5
|
+
|
|
6
|
+
- **Intelligence** — company content as nodes, with sharing, immutable versions, retrieval, citations and a graph
|
|
7
|
+
- **Flows** — versioned, durable processes that reference nodes and Tools
|
|
8
|
+
- **Tools** — MCP capabilities discovered through a Cloudflare MCP Portal
|
|
9
|
+
|
|
10
|
+
The UI, the HTTP API and the Intel MCP surface call the same application services, so authorization,
|
|
11
|
+
validation and side effects never differ by surface. You deploy it into your own Cloudflare account
|
|
12
|
+
against your own Gate; nothing runs on Anchrd infrastructure.
|
|
13
|
+
|
|
14
|
+
This package contains the portable server, the Cloudflare adapter, the D1 migrations and the
|
|
15
|
+
customer CLI.
|
|
16
|
+
|
|
17
|
+
## Requirements
|
|
18
|
+
|
|
19
|
+
- A [Gate](https://www.npmjs.com/package/@anchrd/gate-sdk) instance — Gate owns identity and
|
|
20
|
+
capabilities, and is the only required Anchrd dependency
|
|
21
|
+
- A Cloudflare account with Workers, D1, R2, Queues and Workflows (Vectorize, Workers AI and an AI
|
|
22
|
+
Gateway are optional and only add semantic search and attachment conversion)
|
|
23
|
+
- Node 22 or newer
|
|
24
|
+
|
|
25
|
+
## Setting Intel up
|
|
26
|
+
|
|
27
|
+
Nine steps. Step 3 talks only to Gate and can happen at any point; the rest run in this order,
|
|
28
|
+
because each one needs what the one before it produced. **Step 8 is the one people skip**, and
|
|
29
|
+
skipping it produces an installation that looks broken and is not.
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npm install @anchrd/intel
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### 1. Create the Cloudflare resources
|
|
36
|
+
|
|
37
|
+
Workflows are created by the deploy in step 7; everything else has to exist first.
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
wrangler d1 create intel # note the printed database_id
|
|
41
|
+
wrangler r2 bucket create intel-content
|
|
42
|
+
wrangler queues create intel-indexing
|
|
43
|
+
wrangler queues create intel-indexing-dlq # without it an exhausted message is dropped silently
|
|
44
|
+
wrangler vectorize create intel-nodes --dimensions=1024 --metric=cosine # optional, see Bindings
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
The Vectorize shape is not a free choice: 1024 dimensions and cosine are what Intel's default
|
|
48
|
+
multilingual Workers AI embedding model (`@cf/baai/bge-m3`) produces. Nothing in the deploy compares
|
|
49
|
+
the two, so an index created with other values fails later, at the first write.
|
|
50
|
+
|
|
51
|
+
### 2. Write the Worker
|
|
52
|
+
|
|
53
|
+
The customer edge re-exports the ready-made Cloudflare shell and nothing else. The named Workflow
|
|
54
|
+
class has to travel with it or Wrangler cannot find the entrypoint:
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
// biome-ignore lint/performance/noBarrelFile: Wrangler needs the named Workflow entrypoint.
|
|
58
|
+
export { default, IntelFlowWorkflow } from "@anchrd/intel/cloudflare";
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Its Wrangler configuration declares the bindings from the table below, and points
|
|
62
|
+
`migrations_dir` at `.intel/migrations` — the directory step 4 fills. `assets.directory` points at
|
|
63
|
+
`.intel/ui`, which step 5 fills.
|
|
64
|
+
|
|
65
|
+
### 3. Declare Intel's interfaces in Gate
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
GATE_URL=… GATE_SERVICE_KEY=… npx intel bootstrap
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
⚠️ **`bootstrap` reads its configuration from the environment of the shell it runs in**, not from
|
|
72
|
+
the Worker's secrets — the two are different places that happen to use the same names. Without both
|
|
73
|
+
values it stops with `Error: GATE_URL and GATE_SERVICE_KEY must be set.` before it does anything.
|
|
74
|
+
|
|
75
|
+
It declares five interfaces — `intel`, `nodes`, `flows`, `tools`, `mcp` — with the functions listed
|
|
76
|
+
under *Permission, layer one* below. It is idempotent and safe to repeat after an upgrade.
|
|
77
|
+
|
|
78
|
+
⚠️ **`bootstrap` hands out no grant, and it takes none away as long as the declared list does not
|
|
79
|
+
change.** It creates the permissions an administrator can hand out; it hands out none of them. This
|
|
80
|
+
is step 8, and it is why a fresh installation shows an empty screen to everybody including the
|
|
81
|
+
person who installed it.
|
|
82
|
+
|
|
83
|
+
⚠️ **But a function that falls out of a still-declared interface takes its grants with it.**
|
|
84
|
+
Declaring is an upsert that REPLACES an interface's function list, and Gate deletes every grant on a
|
|
85
|
+
function the new list no longer names. So an upgrade that retires a function also retires every role
|
|
86
|
+
assignment on it — against a running installation that is a change to who may do what, not a
|
|
87
|
+
read. `bootstrap` reads the catalog before it writes and names each one as it goes:
|
|
88
|
+
|
|
89
|
+
```text
|
|
90
|
+
Removed flows:approve from Gate; every grant on it was deleted with it.
|
|
91
|
+
Declared 5 Intel interfaces in Gate.
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
A run that dropped nothing says so instead: `No declared function was dropped, so Gate deleted no
|
|
95
|
+
grant.` And if the catalog cannot be read, `bootstrap` writes nothing at all rather than delete
|
|
96
|
+
grants it would then be unable to name.
|
|
97
|
+
|
|
98
|
+
⚠️ It never revokes a whole **interface**. One an older version declared stays declared in Gate:
|
|
99
|
+
`bootstrap` writes only the handles it names, so an interface outside that list keeps its functions
|
|
100
|
+
and its grants. That is harmless, and removing one is an act in Gate, by hand.
|
|
101
|
+
|
|
102
|
+
### 4. Copy the migrations out of `node_modules`
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
npx intel prepare
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
This writes the versioned SQL to `.intel/migrations`. It only copies — applying them is the next
|
|
109
|
+
step, and nothing does it for you:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
wrangler d1 migrations apply intel --local # a local Worker
|
|
113
|
+
wrangler d1 migrations apply intel --remote # the deployed one
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Migration filenames and their order are immutable after release. Re-run `intel prepare` after every
|
|
117
|
+
upgrade of this package, before applying.
|
|
118
|
+
|
|
119
|
+
### 5. Build the UI
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
npx intel build
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
`intel build` reads an optional strict `intel.json`, applies the customer branding, and writes the
|
|
126
|
+
static output to `.intel/ui`. See *Branding* below. No customer build output ever lives in
|
|
127
|
+
`node_modules`.
|
|
128
|
+
|
|
129
|
+
### 6. Configure the Worker
|
|
130
|
+
|
|
131
|
+
Set the variables and secrets from the two tables below. `GATE_SERVICE_KEY` and
|
|
132
|
+
`INTEL_SESSION_SECRET` are Wrangler secrets (`wrangler secret put …`); the rest are plain vars.
|
|
133
|
+
|
|
134
|
+
For a local Worker, copy `node_modules/@anchrd/intel/examples/dev.vars.example` to `.dev.vars`.
|
|
135
|
+
|
|
136
|
+
### 7. Check it, then deploy
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
npx intel doctor
|
|
140
|
+
wrangler deploy
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
`doctor` checks the same environment `bootstrap` uses, plus the installed packages and migrations
|
|
144
|
+
and the Gate interfaces. It reports every problem at once rather than the first:
|
|
145
|
+
|
|
146
|
+
```text
|
|
147
|
+
Note: MCP_PORTAL_URL is unset, so the Tools area stays empty.
|
|
148
|
+
FAIL GATE_URL is missing
|
|
149
|
+
FAIL INTEL_URL is missing
|
|
150
|
+
FAIL GATE_SERVICE_KEY is missing
|
|
151
|
+
FAIL TOOL_SOURCE_ORIGINS is missing
|
|
152
|
+
FAIL INTEL_SESSION_SECRET must contain at least 32 bytes
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
It also compares the Gate interfaces **in both directions**. A function or a whole interface Gate
|
|
156
|
+
carries that this version of Intel no longer declares is reported as a `NOTE`, never as a `FAIL`:
|
|
157
|
+
nothing is broken by it, and a check one knows red stops being read. Each note names the surplus,
|
|
158
|
+
why it went, and what to do about it:
|
|
159
|
+
|
|
160
|
+
```text
|
|
161
|
+
NOTE Gate carries flows:approve, which Intel does not declare — the approval node is gone (#73).
|
|
162
|
+
NOTE Gate carries the interface knowledge (read, write), which Intel does not declare — the whole interface became `nodes` (#152, after #125).
|
|
163
|
+
NOTE The next `intel bootstrap` removes a surplus function and every grant on it (#474). Take the grant away in Gate first if anybody should keep it.
|
|
164
|
+
NOTE `bootstrap` never touches an interface Intel does not declare, so a surplus one stays until somebody removes it in Gate by hand — which takes its grants with it.
|
|
165
|
+
OK Intel packages, configuration, and Gate interfaces are ready.
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
⚠️ **`doctor` cannot see the Worker's secrets.** It answers about the shell it runs in, so it says
|
|
169
|
+
nothing about whether the deployed Worker is configured. `GET /health` on the deployed Worker
|
|
170
|
+
answers `{"status":"ok"}`; a Worker missing one of the five required variables answers
|
|
171
|
+
`500 configuration_missing` and names them.
|
|
172
|
+
|
|
173
|
+
⚠️ **`doctor` does not check that step 4 happened.** It looks for the migrations *installed* in
|
|
174
|
+
`node_modules`, not for the copies in `.intel/migrations`, so it answers `OK` on a project that never
|
|
175
|
+
ran `intel prepare`. `wrangler deploy` does not mind an empty `migrations_dir` either, and the first
|
|
176
|
+
sign is a database with no tables in it. The `.intel/migrations` directory has to be checked by eye.
|
|
177
|
+
|
|
178
|
+
### 8. Hand out permissions — both layers
|
|
179
|
+
|
|
180
|
+
This is the step that decides whether anybody sees anything, and it is entirely manual.
|
|
181
|
+
|
|
182
|
+
1. In **Gate**, grant people the Intel capabilities from *Permission, layer one*. Without
|
|
183
|
+
`nodes.read` the sidebar answers `403` and says a permission is missing.
|
|
184
|
+
2. In **Intel**, share a node with them. Without a grant the tree is empty — correctly, because
|
|
185
|
+
nothing has been shared yet.
|
|
186
|
+
|
|
187
|
+
Both are needed. Neither on its own produces a usable screen, and the symptom of missing either one
|
|
188
|
+
is the same shape: a view with nothing in it. See *Permission has two layers* below.
|
|
189
|
+
|
|
190
|
+
### 9. Connect the portal, if there is one
|
|
191
|
+
|
|
192
|
+
Tools are optional. If the installation has a Cloudflare MCP Portal, set `MCP_PORTAL_URL` and add
|
|
193
|
+
its origin to `TOOL_SOURCE_ORIGINS`, then read *Tools come from the portal* below — two settings
|
|
194
|
+
outside this repository decide whether the silent sign-in can work at all.
|
|
195
|
+
|
|
196
|
+
## Bindings
|
|
197
|
+
|
|
198
|
+
The reference Wrangler deployment binds all of these. "Required" means a request fails without it,
|
|
199
|
+
not that Wrangler refuses to deploy.
|
|
200
|
+
|
|
201
|
+
| Binding | Resource | Required | What its absence costs |
|
|
202
|
+
|---|---|---|---|
|
|
203
|
+
| `DB` | D1 | **yes** | Nothing works: D1 owns metadata, relationships, grants, flow and run state, audit |
|
|
204
|
+
| `CONTENT` | R2 | **yes** | Node content and attachments cannot be read or written |
|
|
205
|
+
| `INDEXING` | Queue | **yes** | Every save fails; this is the queue that builds the indexes |
|
|
206
|
+
| `FLOWS` | Workflow `IntelFlowWorkflow` | **yes** | Flows cannot be run |
|
|
207
|
+
| `ASSETS` | static assets from `.intel/ui` | for the UI | The API and MCP surface still answer; the browser application is not served at all |
|
|
208
|
+
| `AI` | Workers AI | no | **Two losses, and only one is obvious.** No semantic search, and no attachment conversion — an uploaded PDF or Word file is stored intact but never becomes searchable text |
|
|
209
|
+
| `SEARCH` | Vectorize index, 1024 dims, cosine | no | Search silently falls back to lexical only. Nothing says so, and half a search looks exactly like a whole one |
|
|
210
|
+
|
|
211
|
+
⚠️ **Semantic search needs `AI`, `SEARCH` *and* the variable `AI_GATEWAY_ID`.** Any one of the three
|
|
212
|
+
missing leaves search lexical. If you add them to an existing installation, run `intel reindex`
|
|
213
|
+
afterwards — the embeddings for content already stored are built by that pass and by nothing else.
|
|
214
|
+
|
|
215
|
+
⚠️ **The gateway is a condition, not an option.** Intel makes no Workers AI call without it: no
|
|
216
|
+
gateway name, no semantic index and no attachment conversion. The alternative — calling Workers AI
|
|
217
|
+
directly whenever the variable is absent — is the failure this rule exists against, because a spend
|
|
218
|
+
limit set on the gateway counts only what passes through it. An installation embedding past it works
|
|
219
|
+
perfectly, costs money, and tells nobody.
|
|
220
|
+
|
|
221
|
+
There is no `AGENT` service binding, and `AI_GATEWAY_ACCOUNT_ID` and the `AI_GATEWAY_READ_TOKEN`
|
|
222
|
+
secret are gone. All three belonged to the agent runtime, which is no longer part of Intel; an
|
|
223
|
+
installation that still carries them can drop them, including
|
|
224
|
+
`wrangler secret delete AI_GATEWAY_READ_TOKEN`. ⚠️ `AI_GATEWAY_ID` is **not** among them: it carries
|
|
225
|
+
a different job now, described in the row below.
|
|
226
|
+
|
|
227
|
+
## Variables and secrets
|
|
228
|
+
|
|
229
|
+
Every value below is read in **two different places** depending on the command, and mixing them up
|
|
230
|
+
is the most common setup failure:
|
|
231
|
+
|
|
232
|
+
- the **Worker's** environment — what the deployed Intel reads on every request;
|
|
233
|
+
- the **shell's** environment — what `intel bootstrap`, `intel doctor` and `intel reindex` read.
|
|
234
|
+
|
|
235
|
+
`GATE_URL`, `GATE_SERVICE_KEY`, `INTEL_URL`, `INTEL_SESSION_SECRET` and `TOOL_SOURCE_ORIGINS` are
|
|
236
|
+
needed in both. Setting them only as Wrangler secrets leaves the CLI blind, and setting them only in
|
|
237
|
+
a shell leaves the Worker answering `500 configuration_missing`.
|
|
238
|
+
|
|
239
|
+
⚠️ `MCP_PORTAL_URL` is the eighth value in the same trap, and the one that fails quietly.
|
|
240
|
+
`intel doctor` reads it from the shell as well, so a portal configured only as a Wrangler var makes
|
|
241
|
+
`doctor` report `MCP_PORTAL_URL is unset` about an installation that is configured correctly — and
|
|
242
|
+
skip the origin check it would otherwise have run.
|
|
243
|
+
|
|
244
|
+
| Name | Where | Required | What it does, and what a wrong value does |
|
|
245
|
+
|---|---|---|---|
|
|
246
|
+
| `GATE_URL` | Worker + shell | **yes** | The Gate this installation authenticates against. Wrong: every request is refused and no login completes |
|
|
247
|
+
| `GATE_SERVICE_KEY` | Worker secret + shell | **yes** | Intel's own service credential at Gate. Wrong: every authorization call fails, so everything answers as unauthenticated. It is a secret and never appears in a response, log or tool result |
|
|
248
|
+
| `INTEL_URL` | Worker + shell | **yes** | Intel's own public base URL. It is also **the OAuth resource identifier**: Intel asks Gate for a token for `<INTEL_URL>/mcp`. ⚠️ A trailing-slash or scheme difference is a *different* resource. ⚠️ **Changing it later is a one-way street**: the resource is bound once on the Gate side and cannot be re-pointed — the way back is deleting the Gate service and setting it up again. Decide the hostname before the first login, not after |
|
|
249
|
+
| `INTEL_SESSION_SECRET` | Worker secret + shell | **yes** | Derives the key for the encrypted `HttpOnly` session cookie and for sealing each person's portal token in D1. Must be at least 32 bytes. ⚠️ **Changing it invalidates every session and makes every stored portal token unreadable** — everybody signs in again, and everybody reconnects to the portal |
|
|
250
|
+
| `TOOL_SOURCE_ORIGINS` | Worker + shell | **yes** | Comma-separated **exact origins** Intel is allowed to fetch tools from. ⚠️ An entry carrying a path or credentials is refused — and refused *per request*, so a bad value deploys cleanly and then answers `500` on everything |
|
|
251
|
+
| `MCP_PORTAL_URL` | Worker + shell (for `doctor`) | no | The portal's Streamable HTTP MCP endpoint. Unset means the Tools area stays empty and Intel says so rather than reporting an error. ⚠️ Its origin must also appear in `TOOL_SOURCE_ORIGINS`; `intel doctor` fails when it does not — but only if it can see the value, so set it in the shell too before believing the check ran |
|
|
252
|
+
| `ALLOW_INSECURE_OAUTH` | Worker | no | `true` permits an `http://` OAuth issuer. **Local development only.** Production issuers must be HTTPS |
|
|
253
|
+
| `FLOW_RUN_STALL_TIMEOUT` | Worker | no | How long a run may stand on one step before it is ended as stalled, e.g. `30 minutes`. Too short is worse than the problem: it ends runs that were merely slow |
|
|
254
|
+
| `AI_GATEWAY_ID` | Worker | for `AI` | The **name** of the AI Gateway every Workers AI call is routed through, as it stands in the address of its dashboard page. ⚠️ Unset means Intel calls Workers AI **not at all** — no semantic index, no attachment conversion — rather than calling it directly. A wrong name fails the embedding and conversion calls loudly, which is the intended direction: a spend limit set on the gateway counts only what reaches it |
|
|
255
|
+
| `INTEL_OPERATOR_TOKEN` | shell | for `reindex` | A short-lived bearer carrying the Gate capability `intel.admin`, used only by `intel reindex`. Not a Worker value and not a stored one |
|
|
256
|
+
|
|
257
|
+
Gate OAuth uses PKCE and dynamic public-client registration; browser access tokens stay inside an
|
|
258
|
+
encrypted `HttpOnly` cookie and are never exposed to the UI bundle or D1.
|
|
259
|
+
|
|
260
|
+
## Branding: `intel.json`
|
|
261
|
+
|
|
262
|
+
Put `intel.json` next to the customer project's `package.json`:
|
|
263
|
+
|
|
264
|
+
```json
|
|
265
|
+
{
|
|
266
|
+
"ui": {
|
|
267
|
+
"theme": "./branding/theme.css",
|
|
268
|
+
"logo": "./branding/logo.svg",
|
|
269
|
+
"favicon": "./branding/favicon.svg",
|
|
270
|
+
"defaultLanguage": "en",
|
|
271
|
+
"languages": {}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
The theme is plain CSS containing shadcn semantic tokens such as `--primary`, `--background`,
|
|
277
|
+
`--sidebar`, and `--radius`. It is loaded after Intel's defaults, so customer tokens win without a
|
|
278
|
+
component fork. Unknown config fields, missing assets, non-SVG branding, and incomplete language
|
|
279
|
+
catalogs fail the build rather than producing a half-branded application. A ready-to-copy starting
|
|
280
|
+
point is included under `node_modules/@anchrd/intel/examples`.
|
|
281
|
+
|
|
282
|
+
The file is optional: `intel build` without it produces the default Intel branding.
|
|
283
|
+
|
|
284
|
+
## Permission has two layers
|
|
285
|
+
|
|
286
|
+
Access to anything in Intel is the **and** of two independent answers, and neither layer knows about
|
|
287
|
+
the other. This is the single most common source of "it is broken" reports, because a person missing
|
|
288
|
+
either layer sees roughly the same thing: a screen with nothing on it.
|
|
289
|
+
|
|
290
|
+
### Layer one: the Gate capability
|
|
291
|
+
|
|
292
|
+
What somebody may do *at all*, granted in Gate. `intel bootstrap` declares these; an administrator
|
|
293
|
+
grants them.
|
|
294
|
+
|
|
295
|
+
| Interface | Functions |
|
|
296
|
+
|---|---|
|
|
297
|
+
| `intel` | `admin` |
|
|
298
|
+
| `nodes` | `read`, `create`, `write`, `share` |
|
|
299
|
+
| `flows` | `read`, `create`, `write`, `publish`, `run`, `share` |
|
|
300
|
+
| `tools` | `read`, `test`, `execute` |
|
|
301
|
+
| `mcp` | `connect` |
|
|
302
|
+
|
|
303
|
+
A missing capability answers **`403`**, and the screen says a permission is missing.
|
|
304
|
+
|
|
305
|
+
⚠️ **`mcp.connect` is the one that gates a whole endpoint rather than an action.** Intel's own MCP
|
|
306
|
+
endpoint (`POST /mcp`, the one an MCP client or a portal connects to) checks it **on every request**
|
|
307
|
+
and answers `403` without it — before any tool runs and before anything is read. Two things follow
|
|
308
|
+
for an operator:
|
|
309
|
+
|
|
310
|
+
- **Somebody who should use Intel through an MCP client needs `mcp.connect` in Intel**, beside their
|
|
311
|
+
`nodes.*` capabilities. Without it the client authenticates successfully and every call is refused.
|
|
312
|
+
- **Revoking it takes effect on the next call**, with no new sign-in and nothing to press. If a
|
|
313
|
+
Cloudflare Access policy in front of the endpoint also compares the `mcp` claim, that layer is the
|
|
314
|
+
slower of the two — the claim is written once per sign-in and a running session carries it for up
|
|
315
|
+
to 24 hours, while this check reads the live grant rows every time.
|
|
316
|
+
|
|
317
|
+
The web UI is unaffected: it speaks the HTTP surface, which is gated by `nodes.*`, `flows.*` and
|
|
318
|
+
`tools.*` as before.
|
|
319
|
+
|
|
320
|
+
### Layer two: the grant on the node
|
|
321
|
+
|
|
322
|
+
What somebody may reach *in this tree*, granted in Intel on a node. Four verbs — `read`, `write`,
|
|
323
|
+
`execute`, `share` — each granted on its own; none implies another. Seeing a process is deliberately
|
|
324
|
+
separable from being allowed to start it.
|
|
325
|
+
|
|
326
|
+
A grant on a **folder is inherited by everything beneath it**, including nodes created after the
|
|
327
|
+
grant was made. That is the usual way to share a whole area.
|
|
328
|
+
|
|
329
|
+
A missing grant answers **`404`**, never `403`: Intel gives the same answer for "there is no such
|
|
330
|
+
node" and "not for you", so that a refusal never confirms that something exists.
|
|
331
|
+
|
|
332
|
+
### Reading the empty screen
|
|
333
|
+
|
|
334
|
+
| What you see | Which layer |
|
|
335
|
+
|---|---|
|
|
336
|
+
| A sentence naming a missing permission | Gate — layer one |
|
|
337
|
+
| An empty tree, no error | Intel — nothing has been shared with this person yet |
|
|
338
|
+
| A node that vanished between two visits | Its grant was revoked; revocation takes effect immediately, on every path, without a new login |
|
|
339
|
+
|
|
340
|
+
A shared node appears in the recipient's navigation on its own, at the top level, without exposing
|
|
341
|
+
the titles of the folders above it. Nobody has to be sent a link.
|
|
342
|
+
|
|
343
|
+
### Three things about grants that surprise people
|
|
344
|
+
|
|
345
|
+
- **A flow is not a node, and is reached by two things at once.** The folder it is filed in passes
|
|
346
|
+
its grants down, and since #530 a grant may sit on the flow itself; they add up. Move a flow and
|
|
347
|
+
you have changed the first half of that. A grant on one flow does not reach the flows it calls —
|
|
348
|
+
the answer names them, and `flow_validate` tells the person about to run what is still missing.
|
|
349
|
+
- **`organization` + `execute` on a folder makes that folder a library**: flows from anywhere in the
|
|
350
|
+
tree may then call into it. The share dialog warns before the click, because the way back is
|
|
351
|
+
narrow — revoking is refused with `409 folder_execute_in_use` for as long as one of those callers
|
|
352
|
+
still calls.
|
|
353
|
+
- **A grant can be complete and a flow still stop.** A run is re-authorized against the person
|
|
354
|
+
running it, so a flow in a shared folder that reads a document outside it stops for somebody who
|
|
355
|
+
cannot read that document. The answer names what was out of reach.
|
|
356
|
+
|
|
357
|
+
## Export and import
|
|
358
|
+
|
|
359
|
+
`GET /api/v1/nodes/export` writes the whole installation as this caller may read it; the same route
|
|
360
|
+
under a node id exports that subtree. Import is the mirror:
|
|
361
|
+
|
|
362
|
+
```bash
|
|
363
|
+
curl -X POST https://intel.example.com/api/v1/nodes/import \
|
|
364
|
+
-H "authorization: Bearer $TOKEN" \
|
|
365
|
+
-H "content-type: application/zip" \
|
|
366
|
+
-H "idempotency-key: $(uuidgen)" \
|
|
367
|
+
--data-binary @bundle.zip
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
⚠️ **The idempotency key travels as a header.** The body is the zip itself, so there is nowhere else
|
|
371
|
+
to put it. A request without the header is refused.
|
|
372
|
+
|
|
373
|
+
Only nodes the caller may read enter the bundle; exporting a folder that is out of reach answers
|
|
374
|
+
`404`. A fresh import answers `201`; a repeat of the same idempotency key answers `200` with the
|
|
375
|
+
summary of the earlier import, because this request created nothing.
|
|
376
|
+
|
|
377
|
+
⚠️ **A bundle carries only the current state of each node. Version history does not survive
|
|
378
|
+
export → import.** A document with two versions comes back with one, and the earlier one is then
|
|
379
|
+
retrievable nowhere. Everything else survives in full — nodes per kind, table content including a
|
|
380
|
+
previous `redefine`, and attachments byte for byte. The loss is accepted and deliberate, but anyone
|
|
381
|
+
moving an installation this way has to know about it **before** they start: after the import there
|
|
382
|
+
is nothing to recover from.
|
|
383
|
+
|
|
384
|
+
## Tools come from the portal
|
|
385
|
+
|
|
386
|
+
Intel stores no tool permissions. The catalog is a **live `tools/list`** made with the requesting
|
|
387
|
+
person's own token, never a mirrored table. Two consequences follow, and both are correct behaviour
|
|
388
|
+
rather than bugs:
|
|
389
|
+
|
|
390
|
+
- **Two people legitimately see different tools**, and the same person can see a different set
|
|
391
|
+
tomorrow. What is offered is whatever the portal answers for them at that moment.
|
|
392
|
+
- **A tool can disappear between defining a flow and running it.** Published flows pin immutable
|
|
393
|
+
MCP schema fingerprints, so a changed or vanished tool is reported by name instead of being
|
|
394
|
+
silently substituted.
|
|
395
|
+
|
|
396
|
+
The portal endpoint exposes RFC 9728 metadata. The Tools UI follows that metadata, dynamically
|
|
397
|
+
registers with Gate or Cloudflare Access, and completes a separate PKCE flow — silently, with
|
|
398
|
+
`prompt=none`, as soon as a Gate session exists. Nobody is asked to connect anything.
|
|
399
|
+
|
|
400
|
+
⚠️ **Two settings outside this repository decide whether that silent sign-in can work.** In
|
|
401
|
+
Cloudflare Zero Trust → Access controls → AI controls → your portal → Edit → Advanced settings,
|
|
402
|
+
`Managed OAuth` must be enabled, and an Access policy must carry the people who use Intel. Without
|
|
403
|
+
both, every silent sign-in is refused and the Tools area shows "No access to the company portal" —
|
|
404
|
+
correct behaviour for somebody outside every policy, and a misleading one for a deployment that
|
|
405
|
+
simply never enabled the setting.
|
|
406
|
+
|
|
407
|
+
⚠️ **Somebody who carries the Gate capability `mcp.connect` at no service at all is not sent into
|
|
408
|
+
that sign-in.** Gate answers that question service-wide, Intel asks it before the first redirect,
|
|
409
|
+
and the person stays here reading a sentence that says whom to ask — rather than landing on the
|
|
410
|
+
portal's own error page, outside Intel, with no way back but the browser's back button
|
|
411
|
+
(anchrd/intel#434). Grant `mcp.connect` alongside the Intel capabilities to everyone who should
|
|
412
|
+
reach Tools.
|
|
413
|
+
|
|
414
|
+
Two things that guard deliberately does not do. It **names no server**: the answer is one bit, so
|
|
415
|
+
somebody who may reach a different product's MCP server walks on and sees what the portal offers
|
|
416
|
+
them. And it **promises nothing** — this is the part worth knowing before you grant: the portal
|
|
417
|
+
decides on the `mcp` claim frozen into the ID token, and a running Cloudflare Access session carries
|
|
418
|
+
the old claim for up to 24 hours. ⚠️ **Inside that window the old dead end is still open.** Somebody
|
|
419
|
+
who was granted `mcp.connect` a minute ago is not refused here, walks on, and Access then decides on
|
|
420
|
+
the claim state that produced the error page in the first place. The guard closes the trip that is
|
|
421
|
+
certainly pointless; it does not close this one. The way out is the same as before — sign out of
|
|
422
|
+
Access and in again, so a new ID token carries the new claim. (Not measured against a running
|
|
423
|
+
installation; the claim lifetime is the documented one.) Against a Gate too old to answer the
|
|
424
|
+
question at all, nobody is refused here.
|
|
425
|
+
|
|
426
|
+
The Tools screen distinguishes four situations rather than calling all of them "no access": a
|
|
427
|
+
refusal that really came back, an expired connection, a sign-in that broke, and a sign-in that was
|
|
428
|
+
started and never answered. Only the first has no button, because only there is there nothing a
|
|
429
|
+
second attempt would change.
|
|
430
|
+
|
|
431
|
+
The only tool secret Intel stores is the resulting per-user access token for its own portal
|
|
432
|
+
endpoint — one per person, never one shared operator token — sealed with a key derived from
|
|
433
|
+
`INTEL_SESSION_SECRET` and kept in the `portal_tokens` table of your D1; provider credentials stay
|
|
434
|
+
with the portal and never reach Intel.
|
|
435
|
+
|
|
436
|
+
Intel unseals that token just in time and renews it shortly before it expires. **"Expired" above is
|
|
437
|
+
what a failed renewal looks like**: a token that cannot be renewed is dropped rather than kept and
|
|
438
|
+
retried with, the browser signs in again silently, and an MCP client repeats its own authorization.
|
|
439
|
+
Two different causes end up there — a portal that issued no refresh token at all, which is a
|
|
440
|
+
configuration problem, and a refresh that was rejected, which is not — and Intel logs which of the
|
|
441
|
+
two it was, because the person only ever sees "sign in again". The Intel audience token is never forwarded to another OAuth
|
|
442
|
+
resource. Durable Flow state contains no browser, Gate, or provider credentials.
|
|
443
|
+
|
|
444
|
+
## The `intel` CLI
|
|
445
|
+
|
|
446
|
+
```text
|
|
447
|
+
intel prepare Copy versioned D1 migrations to .intel/migrations
|
|
448
|
+
intel bootstrap Idempotently declare Intel interfaces in Gate
|
|
449
|
+
intel build Apply intel.json and atomically build the customer UI
|
|
450
|
+
intel doctor Check packages, environment, migrations, UI, and Gate interfaces
|
|
451
|
+
intel reindex Request a full authorized search-index rebuild
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
All five run in the customer project directory — the one holding `package.json`, `intel.json` and
|
|
455
|
+
`node_modules` — and read their configuration from that shell's environment.
|
|
456
|
+
|
|
457
|
+
`intel reindex` needs `INTEL_URL` and a short-lived `INTEL_OPERATOR_TOKEN`. It asks the running
|
|
458
|
+
installation to rebuild the derived indexes from D1 and R2 and returns as soon as the request is
|
|
459
|
+
accepted; the work happens on the indexing queue. Reach for it after adding `AI`, `SEARCH` and
|
|
460
|
+
`AI_GATEWAY_ID` to an installation that ran without them, and after restoring an emptied Vectorize
|
|
461
|
+
index.
|
|
462
|
+
|
|
463
|
+
## Writing against the API directly
|
|
464
|
+
|
|
465
|
+
Everything the browser does is available over HTTP and over the Intel MCP surface, against the same
|
|
466
|
+
application services. The schemas are inside this package under `src/contract` — the runtime-
|
|
467
|
+
validated wire formats the server, the browser application and every MCP tool share. Read
|
|
468
|
+
[`src/contract/README.md`](./src/contract/README.md) first: it carries the six things that reliably
|
|
469
|
+
cost a first-time caller an afternoon.
|
|
470
|
+
|
|
471
|
+
## What is in this package
|
|
472
|
+
|
|
473
|
+
One package carries all of Intel, and that is deliberate: an installation pins **one** version
|
|
474
|
+
number instead of three that could drift apart.
|
|
475
|
+
|
|
476
|
+
| Path | What it is |
|
|
477
|
+
|---|---|
|
|
478
|
+
| `dist/` | the server: portable application services, the HTTP and MCP adapters, the Cloudflare shell behind `@anchrd/intel/cloudflare` |
|
|
479
|
+
| `bin/intel.mjs` | the `intel` CLI — `prepare`, `bootstrap`, `build`, `doctor`, `reindex` |
|
|
480
|
+
| `migrations/` | the D1 migrations, copied out by `intel prepare` |
|
|
481
|
+
| `src/contract/` | the wire schemas, as source, because the browser application compiles them too |
|
|
482
|
+
| `ui/` | the browser application, shipped as **source** so `intel build` applies your own theme, logo and languages — see [`ui/README.md`](./ui/README.md) |
|
|
483
|
+
|
|
484
|
+
⚠️ **Installing this package pulls the browser build toolchain with it** — Vite, React, Tailwind and
|
|
485
|
+
the document renderers are runtime dependencies here, even if you never run `intel build`. That is
|
|
486
|
+
the knowingly accepted cost of one version number: a headless Intel has no consumer today, and
|
|
487
|
+
splitting one out later is more expensive than not building it now.
|
|
488
|
+
|
|
489
|
+
⚠️ **`@anchrd/intel-api`, `@anchrd/intel-ui` and `@anchrd/intel-contract` are the predecessors of this
|
|
490
|
+
package.** Once this package is on npm they get an `npm deprecate` pointing here. They are **not**
|
|
491
|
+
deleted, and the versions that are published stay published.
|
|
492
|
+
|
|
493
|
+
## License
|
|
494
|
+
|
|
495
|
+
Proprietary. Published publicly for installation convenience; this is not an open-source license and
|
|
496
|
+
grants no right to use, copy, modify or redistribute the software. Contact Anchrd for licensing.
|
package/bin/intel.mjs
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { spawn } from "node:child_process";
|
|
3
|
+
import { cp, mkdir, readFile, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
4
|
+
import { dirname, resolve } from "node:path";
|
|
5
|
+
import { createGateClient } from "@anchrd/gate-sdk";
|
|
6
|
+
import { createCli } from "../dist/cli/cli.js";
|
|
7
|
+
|
|
8
|
+
// Since #827 the surface and the migrations travel inside @anchrd/intel itself, so an installation
|
|
9
|
+
// finds both below one package directory. The second entry of each pair is this repository's own
|
|
10
|
+
// tree, which is what `bun run build` and `bun run dev` walk.
|
|
11
|
+
const uiCandidates = [
|
|
12
|
+
{ dir: "node_modules/@anchrd/intel/ui", outDir: ".intel/ui" },
|
|
13
|
+
{ dir: "packages/intel/ui", outDir: "packages/intel/ui/dist" },
|
|
14
|
+
];
|
|
15
|
+
const migrationCandidates = ["node_modules/@anchrd/intel/migrations", "packages/intel/migrations"];
|
|
16
|
+
|
|
17
|
+
// npm sets npm_execpath to its own JavaScript entry point. Running that through the current Node
|
|
18
|
+
// binary avoids the .cmd shim entirely, which matters on Windows: Node has refused to spawn a .cmd
|
|
19
|
+
// without a shell since CVE-2024-27980, and cmd.exe expands %NAME% even inside quotes, so a checkout
|
|
20
|
+
// path containing a percent sign would be rewritten.
|
|
21
|
+
function npmScriptPath(command) {
|
|
22
|
+
if (command !== "npm") return null;
|
|
23
|
+
const execPath = process.env.npm_execpath;
|
|
24
|
+
return execPath?.endsWith(".js") ? execPath : null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Only reached on the Windows shell fallback, where cmd.exe would otherwise split on whitespace.
|
|
28
|
+
function quoteForCmd(argument) {
|
|
29
|
+
if (!/[\s"^&|<>()]/.test(argument)) return argument;
|
|
30
|
+
return `"${argument.replaceAll('"', '""')}"`;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function spawnArguments(command, args) {
|
|
34
|
+
const script = npmScriptPath(command);
|
|
35
|
+
if (script) return [process.execPath, [script, ...args]];
|
|
36
|
+
if (process.platform !== "win32") return [command, args];
|
|
37
|
+
return [`${command}.cmd`, args.map(quoteForCmd)];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function isFile(path) {
|
|
41
|
+
try {
|
|
42
|
+
return (await stat(path)).isFile();
|
|
43
|
+
} catch (error) {
|
|
44
|
+
if (error?.code === "ENOENT" || error?.code === "ENOTDIR") return false;
|
|
45
|
+
throw error;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async function isDirectory(path) {
|
|
50
|
+
try {
|
|
51
|
+
return (await stat(path)).isDirectory();
|
|
52
|
+
} catch (error) {
|
|
53
|
+
if (error?.code === "ENOENT" || error?.code === "ENOTDIR") return false;
|
|
54
|
+
throw error;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async function replaceDir(from, to) {
|
|
59
|
+
await mkdir(dirname(to), { recursive: true });
|
|
60
|
+
const backup = `${to}.old`;
|
|
61
|
+
await rm(backup, { recursive: true, force: true });
|
|
62
|
+
let hasBackup = false;
|
|
63
|
+
try {
|
|
64
|
+
await rename(to, backup);
|
|
65
|
+
hasBackup = true;
|
|
66
|
+
} catch (error) {
|
|
67
|
+
if (error?.code !== "ENOENT") throw error;
|
|
68
|
+
}
|
|
69
|
+
try {
|
|
70
|
+
await rename(from, to);
|
|
71
|
+
} catch (error) {
|
|
72
|
+
if (hasBackup) await rename(backup, to);
|
|
73
|
+
throw error;
|
|
74
|
+
}
|
|
75
|
+
if (hasBackup) await rm(backup, { recursive: true, force: true });
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const cli = createCli({
|
|
79
|
+
env: process.env,
|
|
80
|
+
fetch: globalThis.fetch,
|
|
81
|
+
createGateInterfaces: (url, serviceKey) => createGateClient({ url, serviceKey }).interfaces,
|
|
82
|
+
readTextFile: async (path) => {
|
|
83
|
+
try {
|
|
84
|
+
return await readFile(path, "utf8");
|
|
85
|
+
} catch (error) {
|
|
86
|
+
if (error?.code === "ENOENT") return null;
|
|
87
|
+
throw error;
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
writeTextFile: async (path, content) => {
|
|
91
|
+
await mkdir(dirname(path), { recursive: true });
|
|
92
|
+
await writeFile(path, content, "utf8");
|
|
93
|
+
},
|
|
94
|
+
resolveUi: async () => {
|
|
95
|
+
for (const candidate of uiCandidates) {
|
|
96
|
+
if (await isFile(`${candidate.dir}/package.json`)) {
|
|
97
|
+
return { dir: candidate.dir, outDir: resolve(process.cwd(), candidate.outDir) };
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return null;
|
|
101
|
+
},
|
|
102
|
+
resolveMigrations: async () => {
|
|
103
|
+
for (const dir of migrationCandidates) {
|
|
104
|
+
if (await isDirectory(dir)) {
|
|
105
|
+
return { dir, outDir: resolve(process.cwd(), ".intel/migrations") };
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return null;
|
|
109
|
+
},
|
|
110
|
+
copyDir: async (from, to) => {
|
|
111
|
+
await rm(to, { recursive: true, force: true });
|
|
112
|
+
await mkdir(dirname(to), { recursive: true });
|
|
113
|
+
await cp(from, to, { recursive: true });
|
|
114
|
+
},
|
|
115
|
+
exec: (command, args, { cwd }) =>
|
|
116
|
+
new Promise((resolveCode, reject) => {
|
|
117
|
+
const child = spawn(...spawnArguments(command, args), {
|
|
118
|
+
cwd,
|
|
119
|
+
stdio: "inherit",
|
|
120
|
+
shell: process.platform === "win32" && !npmScriptPath(command),
|
|
121
|
+
});
|
|
122
|
+
child.on("error", reject);
|
|
123
|
+
child.on("close", (code) => resolveCode(code ?? 1));
|
|
124
|
+
}),
|
|
125
|
+
replaceDir,
|
|
126
|
+
log: (message) => console.log(message),
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
try {
|
|
130
|
+
process.exitCode = await cli.run(process.argv.slice(2));
|
|
131
|
+
} catch (error) {
|
|
132
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
133
|
+
process.exitCode = 1;
|
|
134
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { CloudflareEnv } from "./cloudflare.types.js";
|
|
2
|
+
interface WorkflowEvent<Params> {
|
|
3
|
+
payload: Readonly<Params>;
|
|
4
|
+
}
|
|
5
|
+
interface WorkflowStep {
|
|
6
|
+
do<T>(name: string, callback: () => Promise<T>): Promise<T>;
|
|
7
|
+
waitForEvent(name: string, options: {
|
|
8
|
+
type: string;
|
|
9
|
+
timeout?: string | number;
|
|
10
|
+
}): Promise<unknown>;
|
|
11
|
+
}
|
|
12
|
+
interface FlowWorkflowParams {
|
|
13
|
+
runId: string;
|
|
14
|
+
}
|
|
15
|
+
interface IntelFlowWorkflowInstance {
|
|
16
|
+
run(event: Readonly<WorkflowEvent<FlowWorkflowParams>>, step: WorkflowStep): Promise<unknown>;
|
|
17
|
+
}
|
|
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 declare function driveFlowRun(step: WorkflowStep, deps: {
|
|
28
|
+
readStatus(): Promise<{
|
|
29
|
+
status: string;
|
|
30
|
+
error: string | null;
|
|
31
|
+
}>;
|
|
32
|
+
hasRunningChild(): Promise<boolean>;
|
|
33
|
+
markFailed(error: string): Promise<void>;
|
|
34
|
+
stallTimeout: string;
|
|
35
|
+
}): Promise<{
|
|
36
|
+
status: string;
|
|
37
|
+
error: string | null;
|
|
38
|
+
}>;
|
|
39
|
+
export declare const IntelFlowWorkflow: {
|
|
40
|
+
new (context: unknown, env: CloudflareEnv): IntelFlowWorkflowInstance;
|
|
41
|
+
};
|
|
42
|
+
export {};
|