@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
|
@@ -0,0 +1,675 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import {
|
|
3
|
+
baseVersion,
|
|
4
|
+
IdempotencyKey,
|
|
5
|
+
IntelId,
|
|
6
|
+
IsoDateTime,
|
|
7
|
+
LinkConfiguration,
|
|
8
|
+
PromptName,
|
|
9
|
+
} from "./contract.ts";
|
|
10
|
+
import { NodeKind } from "./node.ts";
|
|
11
|
+
import { serverOf, ToolName, ToolServerHandle } from "./tool.ts";
|
|
12
|
+
|
|
13
|
+
export const FlowNodeId = z.string().regex(/^[A-Za-z0-9][A-Za-z0-9_-]{0,99}$/);
|
|
14
|
+
export const FlowPosition = z.strictObject({ x: z.number().finite(), y: z.number().finite() });
|
|
15
|
+
// A node has a title and nothing else to write in prose (#39). A second free text beside it was
|
|
16
|
+
// kept half up to date on both sides, and for an instruction the same sentence already belongs in
|
|
17
|
+
// the instruction itself.
|
|
18
|
+
const FlowNodeBase = {
|
|
19
|
+
id: FlowNodeId,
|
|
20
|
+
position: FlowPosition,
|
|
21
|
+
label: z.string().trim().min(1).max(160),
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// Which version of the callee a sub-flow call takes (ADR-0004 §5). Three states rather than an
|
|
25
|
+
// optional identifier, because the difference between them is a decision and has to be readable:
|
|
26
|
+
//
|
|
27
|
+
// - `latest` the draft default. Nobody should have to version things while building, and
|
|
28
|
+
// publishing turns this into `pinned` — visibly, before the author publishes.
|
|
29
|
+
// - `follows` "always latest", chosen on purpose. The call rides along with the callee, so a
|
|
30
|
+
// change to the building block changes this flow too. Publishing leaves it alone.
|
|
31
|
+
// - `pinned` one immutable version, whatever is published elsewhere.
|
|
32
|
+
//
|
|
33
|
+
// ⚠️ Without the freeze a change to a building block would silently change the behavior of every
|
|
34
|
+
// published flow using it, which contradicts the immutable versions and pinned schema fingerprints
|
|
35
|
+
// Intel otherwise guarantees. That is why `latest` cannot survive publishing.
|
|
36
|
+
export const SubflowVersionMode = z.enum(["latest", "follows", "pinned"]);
|
|
37
|
+
export type SubflowVersionMode = z.infer<typeof SubflowVersionMode>;
|
|
38
|
+
|
|
39
|
+
export const SubflowVersion = z.discriminatedUnion("mode", [
|
|
40
|
+
z.strictObject({ mode: z.literal("latest") }),
|
|
41
|
+
z.strictObject({ mode: z.literal("follows") }),
|
|
42
|
+
z.strictObject({ mode: z.literal("pinned"), versionId: IntelId }),
|
|
43
|
+
]);
|
|
44
|
+
export type SubflowVersion = z.infer<typeof SubflowVersion>;
|
|
45
|
+
|
|
46
|
+
// The three layers a node can belong to (D25). Which one a kind is in decides what it may carry and
|
|
47
|
+
// where it may sit, and both rules are enforced in `compileFlow` rather than only drawn in the
|
|
48
|
+
// editor — a graph arrives over MCP as readily as from the canvas.
|
|
49
|
+
//
|
|
50
|
+
// ⚠️ A LINK never stands in the chain. It hangs off a step on a `context` edge, and that is the
|
|
51
|
+
// distinction the graph has drawn since #37 without anyone enforcing it — which is exactly how a
|
|
52
|
+
// start with an attachment once began its run at the attachment (the "flow edges only" comments in
|
|
53
|
+
// `flows.ts`). Marker and step keep the chain; a link is what a step works with.
|
|
54
|
+
export const FlowNodeLayer = z.enum(["marker", "step", "link"]);
|
|
55
|
+
export type FlowNodeLayer = z.infer<typeof FlowNodeLayer>;
|
|
56
|
+
|
|
57
|
+
export const flowNodeLayer = {
|
|
58
|
+
trigger: "marker",
|
|
59
|
+
output: "marker",
|
|
60
|
+
instruction: "step",
|
|
61
|
+
condition: "step",
|
|
62
|
+
subflow: "step",
|
|
63
|
+
folder: "link",
|
|
64
|
+
document: "link",
|
|
65
|
+
upload: "link",
|
|
66
|
+
table: "link",
|
|
67
|
+
tool: "link",
|
|
68
|
+
} as const satisfies Record<string, FlowNodeLayer>;
|
|
69
|
+
|
|
70
|
+
export const FlowNode = z.discriminatedUnion("kind", [
|
|
71
|
+
z.strictObject({
|
|
72
|
+
...FlowNodeBase,
|
|
73
|
+
kind: z.literal("trigger"),
|
|
74
|
+
// ⚠️ `manual` is the only mode there is. `webhook` and `schedule` stood here and fired nothing:
|
|
75
|
+
// a flow is carried out by an external agent that brings its own schedule, which is what the
|
|
76
|
+
// code does rather than what it intends — `step()` hands back the current node, `completeStep`
|
|
77
|
+
// takes the result from outside, and the Cloudflare workflow waits rather than drives. #32 was
|
|
78
|
+
// closed on that basis, and a mode nothing triggers is a promise nobody keeps.
|
|
79
|
+
configuration: z.strictObject({ mode: z.literal("manual") }),
|
|
80
|
+
}),
|
|
81
|
+
z.strictObject({
|
|
82
|
+
...FlowNodeBase,
|
|
83
|
+
kind: z.literal("instruction"),
|
|
84
|
+
configuration: z.strictObject({ prompt: z.string().min(1).max(50_000) }),
|
|
85
|
+
}),
|
|
86
|
+
// The four link kinds that name something in the shared tree. They are separate kinds rather than
|
|
87
|
+
// one with a `kind` field so the canvas, the palette and the picker can each say what they mean
|
|
88
|
+
// without reading into a configuration — and so a stored graph says it too.
|
|
89
|
+
z.strictObject({ ...FlowNodeBase, kind: z.literal("folder"), configuration: LinkConfiguration }),
|
|
90
|
+
z.strictObject({
|
|
91
|
+
...FlowNodeBase,
|
|
92
|
+
kind: z.literal("document"),
|
|
93
|
+
configuration: LinkConfiguration,
|
|
94
|
+
}),
|
|
95
|
+
z.strictObject({ ...FlowNodeBase, kind: z.literal("upload"), configuration: LinkConfiguration }),
|
|
96
|
+
z.strictObject({ ...FlowNodeBase, kind: z.literal("table"), configuration: LinkConfiguration }),
|
|
97
|
+
/**
|
|
98
|
+
* A tool step names a SERVER, and optionally the functions of it that this step may use.
|
|
99
|
+
*
|
|
100
|
+
* ⚠️ It named a single function until #489, together with a raw argument object the author had to
|
|
101
|
+
* write as JSON. That modelled the protocol instead of the intent: an author gives a step access
|
|
102
|
+
* to Notion; WHICH of Notion's 28 functions runs, and with which arguments, follows from the
|
|
103
|
+
* step's instruction and can only be known while the flow runs.
|
|
104
|
+
*
|
|
105
|
+
* `allow: null` means every function of that server. A list narrows it, and every entry has to
|
|
106
|
+
* belong to `server` — checked below, because a name from another server would make the step ask
|
|
107
|
+
* for something the portal routes somewhere else entirely.
|
|
108
|
+
*
|
|
109
|
+
* ⚠️ `allow` is an INSTRUCTION to the agent, not a boundary Intel enforces (#518). Intel is a
|
|
110
|
+
* library: it says what is to be done, it does not execute. A flow is carried out by an agent
|
|
111
|
+
* that reaches the portal with its OWN token, and that agent may call the portal directly —
|
|
112
|
+
* Intel never sees the call. What bounds it is the agent's own portal grant, checked by the
|
|
113
|
+
* portal on every call; what `allow` does is tell the agent which of those functions this step
|
|
114
|
+
* is meant to use, the same way an instruction step tells it what to write.
|
|
115
|
+
*
|
|
116
|
+
* That is not a gap to be closed by adding a check here. Enforcing it would mean routing every
|
|
117
|
+
* call through Intel and making it the executor — the one thing this product is not.
|
|
118
|
+
*
|
|
119
|
+
* ⚠️ There is deliberately no `arguments` field any more. Arguments are produced at run time and
|
|
120
|
+
* validated against the tool's own `inputSchema` from a live `tools/list`; a stored copy would be
|
|
121
|
+
* a second source for something the far side already defines, and it would go stale silently.
|
|
122
|
+
*/
|
|
123
|
+
z.strictObject({
|
|
124
|
+
...FlowNodeBase,
|
|
125
|
+
kind: z.literal("tool"),
|
|
126
|
+
configuration: z
|
|
127
|
+
.strictObject({
|
|
128
|
+
server: ToolServerHandle,
|
|
129
|
+
allow: z.array(ToolName).nullable().default(null),
|
|
130
|
+
fingerprint: z
|
|
131
|
+
.string()
|
|
132
|
+
.regex(/^[a-f0-9]{64}$/)
|
|
133
|
+
.nullable()
|
|
134
|
+
.default(null),
|
|
135
|
+
})
|
|
136
|
+
.check((ctx) => {
|
|
137
|
+
const { server, allow } = ctx.value;
|
|
138
|
+
if (allow === null) return;
|
|
139
|
+
// The prefix rule is the contract's own (`serverOf`), so a step cannot claim a function
|
|
140
|
+
// that the portal would route somewhere else entirely.
|
|
141
|
+
for (const name of allow) {
|
|
142
|
+
if (serverOf(name, [server]) === null) {
|
|
143
|
+
ctx.issues.push({
|
|
144
|
+
code: "custom",
|
|
145
|
+
input: name,
|
|
146
|
+
message: `An allowed function has to belong to the step's server: ${name} is not a function of ${server}`,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}),
|
|
151
|
+
}),
|
|
152
|
+
z.strictObject({
|
|
153
|
+
...FlowNodeBase,
|
|
154
|
+
kind: z.literal("condition"),
|
|
155
|
+
configuration: z.strictObject({
|
|
156
|
+
mode: z.literal("semantic"),
|
|
157
|
+
instruction: z.string().min(1).max(10_000),
|
|
158
|
+
}),
|
|
159
|
+
}),
|
|
160
|
+
// ⚠️ There is no `approval` kind, and adding one back is a product decision rather than a schema
|
|
161
|
+
// addition (#73). It waited on a named person with a deadline, which needs a queue, a
|
|
162
|
+
// notification, a stand-in and an answer to "the deadline passed" — none of which exist. Without
|
|
163
|
+
// it, D24 holds without exception: nothing in Intel waits. A stored graph that still carries one
|
|
164
|
+
// is rewritten to a `condition` by migration 0007, because the question it asked is one the agent
|
|
165
|
+
// can answer.
|
|
166
|
+
//
|
|
167
|
+
// The seventh kind: one flow calls another (ADR-0004 §3). A schema addition, not hidden behavior
|
|
168
|
+
// in a generic code node — which flow is called has to be readable from the graph, or neither the
|
|
169
|
+
// publish-time call rule nor the sidebar could see it.
|
|
170
|
+
z.strictObject({
|
|
171
|
+
...FlowNodeBase,
|
|
172
|
+
kind: z.literal("subflow"),
|
|
173
|
+
// What the called flow is given travels through `StartFlowRunInput.input` — the schema every run
|
|
174
|
+
// already uses. A second, static input here would be a promise the execution does not keep.
|
|
175
|
+
configuration: z.strictObject({
|
|
176
|
+
flowId: IntelId,
|
|
177
|
+
version: SubflowVersion.default({ mode: "latest" }),
|
|
178
|
+
}),
|
|
179
|
+
}),
|
|
180
|
+
// ⚠️ The end marks, it does not make. It used to carry a `template` that nothing ever read, and a
|
|
181
|
+
// node called "Result" that appeared to produce one is what everybody read it as. The result of a
|
|
182
|
+
// run is what the last step before it hands in (D25) — `completeStep` carries that forward.
|
|
183
|
+
z.strictObject({
|
|
184
|
+
...FlowNodeBase,
|
|
185
|
+
kind: z.literal("output"),
|
|
186
|
+
configuration: z.strictObject({}),
|
|
187
|
+
}),
|
|
188
|
+
]);
|
|
189
|
+
export type FlowNode = z.infer<typeof FlowNode>;
|
|
190
|
+
|
|
191
|
+
// The two things an edge can mean (#37). `flow` is the order of work — "and then". `context` is what
|
|
192
|
+
// a step works with: a document consulted in exactly this step, an approval obtained in exactly this
|
|
193
|
+
// step, or, at the output, the table a result is written to.
|
|
194
|
+
//
|
|
195
|
+
// ⚠️ `flow` is the default, and that is the whole of the migration: every edge stored before this
|
|
196
|
+
// existed parses into the meaning it already had. Nothing about saved graphs has to be rewritten.
|
|
197
|
+
export const FlowEdgeKind = z.enum(["flow", "context"]);
|
|
198
|
+
export type FlowEdgeKind = z.infer<typeof FlowEdgeKind>;
|
|
199
|
+
|
|
200
|
+
export const FlowEdge = z.strictObject({
|
|
201
|
+
id: FlowNodeId,
|
|
202
|
+
source: FlowNodeId,
|
|
203
|
+
target: FlowNodeId,
|
|
204
|
+
kind: FlowEdgeKind.default("flow"),
|
|
205
|
+
label: z.string().trim().min(1).max(120).nullable().default(null),
|
|
206
|
+
sourceHandle: z.string().trim().min(1).max(120).nullable().default(null),
|
|
207
|
+
});
|
|
208
|
+
export type FlowEdge = z.infer<typeof FlowEdge>;
|
|
209
|
+
|
|
210
|
+
export const FlowGraph = z.strictObject({
|
|
211
|
+
nodes: z.array(FlowNode).min(2).max(200),
|
|
212
|
+
edges: z.array(FlowEdge).min(1).max(500),
|
|
213
|
+
});
|
|
214
|
+
export type FlowGraph = z.infer<typeof FlowGraph>;
|
|
215
|
+
|
|
216
|
+
export const Flow = z.strictObject({
|
|
217
|
+
id: IntelId,
|
|
218
|
+
// The one thing a Flow shares with a document: its place in the shared folder tree (ADR-0004).
|
|
219
|
+
// Everything else stays apart — versions, R2 body and Vectorize belong to the document, the graph,
|
|
220
|
+
// runs and approvals to the flow. `null` is the root of that same tree.
|
|
221
|
+
parentId: IntelId.nullable(),
|
|
222
|
+
title: z.string().min(1).max(240),
|
|
223
|
+
description: z.string().max(2_000).nullable(),
|
|
224
|
+
ownerId: IntelId,
|
|
225
|
+
currentVersionId: IntelId.nullable(),
|
|
226
|
+
publishedVersionId: IntelId.nullable(),
|
|
227
|
+
createdAt: IsoDateTime,
|
|
228
|
+
updatedAt: IsoDateTime,
|
|
229
|
+
archivedAt: IsoDateTime.nullable(),
|
|
230
|
+
// The slash command this flow is offered under, or `null` (#775). It is set at `flow_publish`
|
|
231
|
+
// and nowhere else: publishing is already the decision that this flow is for other people, and a
|
|
232
|
+
// second switch beside it would ask the same question twice.
|
|
233
|
+
//
|
|
234
|
+
// ⚠️ It SURVIVES `flow_unpublish`, and that is deliberate. Withdrawing a publication takes the
|
|
235
|
+
// flow out of `prompts/list` — the name it keeps is what makes republishing it the same command
|
|
236
|
+
// rather than a new one, and a client that stored the old one is not left pointing at a name that
|
|
237
|
+
// now means somebody else's flow. The name stays taken while the flow is withdrawn, and whoever
|
|
238
|
+
// asks for it is told which flow holds it.
|
|
239
|
+
promptName: PromptName.nullable(),
|
|
240
|
+
});
|
|
241
|
+
export type Flow = z.infer<typeof Flow>;
|
|
242
|
+
|
|
243
|
+
export const FlowVersion = z.strictObject({
|
|
244
|
+
id: IntelId,
|
|
245
|
+
flowId: IntelId,
|
|
246
|
+
sequence: z.number().int().positive(),
|
|
247
|
+
graph: FlowGraph,
|
|
248
|
+
createdBy: IntelId,
|
|
249
|
+
createdAt: IsoDateTime,
|
|
250
|
+
});
|
|
251
|
+
export type FlowVersion = z.infer<typeof FlowVersion>;
|
|
252
|
+
|
|
253
|
+
export const FlowDocument = z.strictObject({
|
|
254
|
+
flow: Flow,
|
|
255
|
+
version: FlowVersion.nullable(),
|
|
256
|
+
});
|
|
257
|
+
export type FlowDocument = z.infer<typeof FlowDocument>;
|
|
258
|
+
|
|
259
|
+
// One version as the history shows it: the metadata without the graph it carries. A flow's history
|
|
260
|
+
// is as long as its edits, and a list that shipped every graph would pay for drawings nobody asked
|
|
261
|
+
// for — whoever needs one asks for that one version.
|
|
262
|
+
export const FlowVersionSummary = z.strictObject({
|
|
263
|
+
id: IntelId,
|
|
264
|
+
flowId: IntelId,
|
|
265
|
+
sequence: z.number().int().positive(),
|
|
266
|
+
createdBy: IntelId,
|
|
267
|
+
createdAt: IsoDateTime,
|
|
268
|
+
// Whether this is the version the flow currently publishes. Derived from the flow row when the
|
|
269
|
+
// list is read, never stored on the version: a version is immutable and "published" is not a
|
|
270
|
+
// property of it — it is the flow's choice, revocable without touching the version.
|
|
271
|
+
published: z.boolean(),
|
|
272
|
+
});
|
|
273
|
+
export type FlowVersionSummary = z.infer<typeof FlowVersionSummary>;
|
|
274
|
+
|
|
275
|
+
export const FlowVersionList = z.strictObject({
|
|
276
|
+
flowId: IntelId,
|
|
277
|
+
items: z.array(FlowVersionSummary),
|
|
278
|
+
});
|
|
279
|
+
export type FlowVersionList = z.infer<typeof FlowVersionList>;
|
|
280
|
+
|
|
281
|
+
// Both identifiers, deliberately: a version ID alone would resolve whatever version carries it,
|
|
282
|
+
// whichever flow it belongs to, and the ACL is answered on the flow. The pair makes a foreign
|
|
283
|
+
// version a 404 rather than a read.
|
|
284
|
+
export const GetFlowVersionInput = z.strictObject({
|
|
285
|
+
flowId: IntelId.describe(
|
|
286
|
+
"Flow the version belongs to. Named alongside the version so access is decided on the flow.",
|
|
287
|
+
),
|
|
288
|
+
versionId: IntelId.describe("Version to read, from flow_version_list."),
|
|
289
|
+
});
|
|
290
|
+
export type GetFlowVersionInput = z.infer<typeof GetFlowVersionInput>;
|
|
291
|
+
// The same for flows: which of them call another flow that this reader may also see (#59). An
|
|
292
|
+
// expand arrow on a flow whose calls are all hidden promises content that expanding it cannot
|
|
293
|
+
// deliver.
|
|
294
|
+
export const FlowList = z.strictObject({
|
|
295
|
+
items: z.array(Flow),
|
|
296
|
+
withCalls: z.array(IntelId).default([]),
|
|
297
|
+
});
|
|
298
|
+
export type FlowList = z.infer<typeof FlowList>;
|
|
299
|
+
|
|
300
|
+
export const ReferencedNode = z.strictObject({
|
|
301
|
+
id: IntelId,
|
|
302
|
+
title: z.string().min(1).max(240),
|
|
303
|
+
});
|
|
304
|
+
export type ReferencedNode = z.infer<typeof ReferencedNode>;
|
|
305
|
+
|
|
306
|
+
// What a flow touches: the documents its tree links name and the tools its Tool steps call,
|
|
307
|
+
// read straight out of the graph. Deliberately not a conflict report — there is no arithmetic here
|
|
308
|
+
// and nothing that can go stale, because the graph is the answer. Whether a given person may reach
|
|
309
|
+
// any of it is decided where it can be decided honestly: when the folder is shared, and at runtime
|
|
310
|
+
// (ADR-0004 §4). For tools it can only ever be the latter, because the catalog is a live query with
|
|
311
|
+
// the requesting user's own token (ADR-0003).
|
|
312
|
+
//
|
|
313
|
+
// ⚠️ `nodes` names only what the asking user may see. The rest falls into TWO fields, and keeping
|
|
314
|
+
// them apart is the whole of #509: `invalidNodes` are references that name nothing at all any more,
|
|
315
|
+
// `hiddenNodes` is a count of the ones that exist and are out of this reader's reach.
|
|
316
|
+
//
|
|
317
|
+
// ⚠️ They used to be one number, and the number was read out as "you cannot see it" — a sentence
|
|
318
|
+
// about a PERMISSION, in front of a broken link. The two states suggest opposite actions and only
|
|
319
|
+
// one of them helps: with a permission one asks for access and waits, with a dead reference the step
|
|
320
|
+
// has to be replaced before the flow can run at all. #492 decided that such a reference is marked
|
|
321
|
+
// visibly invalid rather than left silently pointed at an id nothing answers.
|
|
322
|
+
//
|
|
323
|
+
// ⚠️ `invalidNodes` carries IDS, never titles, and that is not the same concession `hiddenNodes`
|
|
324
|
+
// makes. There is nothing left to name — the row is gone — and the id is one the caller sent us out
|
|
325
|
+
// of a graph they may already read, so it discloses nothing they did not write themselves.
|
|
326
|
+
export const FlowRequirements = z.strictObject({
|
|
327
|
+
flowId: IntelId,
|
|
328
|
+
versionId: IntelId.nullable(),
|
|
329
|
+
nodes: z.array(ReferencedNode),
|
|
330
|
+
invalidNodes: z.array(IntelId),
|
|
331
|
+
hiddenNodes: z.number().int().nonnegative(),
|
|
332
|
+
servers: z.array(ToolServerHandle),
|
|
333
|
+
});
|
|
334
|
+
export type FlowRequirements = z.infer<typeof FlowRequirements>;
|
|
335
|
+
|
|
336
|
+
// What stands between this flow and a run, asked on demand and answered for the person asking.
|
|
337
|
+
//
|
|
338
|
+
// ⚠️ A snapshot, and it says so. The tool catalog is a live query with the requesting user's own
|
|
339
|
+
// token (ADR-0003), so what is reachable now can be different tomorrow, and the same flow answers
|
|
340
|
+
// differently for two people. That is why this is a question one asks rather than a badge on the
|
|
341
|
+
// flow: a standing "this flow has conflicts" would be wrong for tools by construction (#72, D24).
|
|
342
|
+
export const FlowValidation = z.strictObject({
|
|
343
|
+
flowId: IntelId,
|
|
344
|
+
versionId: IntelId.nullable(),
|
|
345
|
+
// Empty means it would start now — for this person, at this moment.
|
|
346
|
+
problems: z.array(
|
|
347
|
+
z.strictObject({
|
|
348
|
+
code: z.string().min(1).max(80),
|
|
349
|
+
detail: z.string().min(1).max(2_000),
|
|
350
|
+
}),
|
|
351
|
+
),
|
|
352
|
+
checkedAt: IsoDateTime,
|
|
353
|
+
});
|
|
354
|
+
export type FlowValidation = z.infer<typeof FlowValidation>;
|
|
355
|
+
|
|
356
|
+
export const CreateFlowInput = z.strictObject({
|
|
357
|
+
parentId: IntelId.nullable()
|
|
358
|
+
.default(null)
|
|
359
|
+
.describe("Folder to file the flow in. `null` puts it at the top level."),
|
|
360
|
+
title: z.string().trim().min(1).max(240).describe("What the flow is called."),
|
|
361
|
+
description: z
|
|
362
|
+
.string()
|
|
363
|
+
.trim()
|
|
364
|
+
.max(2_000)
|
|
365
|
+
.nullable()
|
|
366
|
+
.default(null)
|
|
367
|
+
.describe("Optional sentence about what the flow is for."),
|
|
368
|
+
idempotencyKey: IdempotencyKey,
|
|
369
|
+
});
|
|
370
|
+
export type CreateFlowInput = z.infer<typeof CreateFlowInput>;
|
|
371
|
+
|
|
372
|
+
// Renaming and moving a flow. Both are organization and nothing else: they touch no version, no
|
|
373
|
+
// published graph and no run, because organization has to stay free of consequence or nobody dares
|
|
374
|
+
// to reorganize (ADR-0004).
|
|
375
|
+
export const UpdateFlowInput = z
|
|
376
|
+
.strictObject({
|
|
377
|
+
flowId: IntelId.describe("Flow to rename or move."),
|
|
378
|
+
baseUpdatedAt: IsoDateTime.describe(
|
|
379
|
+
"`updatedAt` as flow_get last reported it. A newer value on the server means somebody else changed the flow first and the call is refused.",
|
|
380
|
+
),
|
|
381
|
+
title: z
|
|
382
|
+
.string()
|
|
383
|
+
.trim()
|
|
384
|
+
.min(1)
|
|
385
|
+
.max(240)
|
|
386
|
+
.optional()
|
|
387
|
+
.describe("New title. Omit to leave it as it is."),
|
|
388
|
+
description: z
|
|
389
|
+
.string()
|
|
390
|
+
.trim()
|
|
391
|
+
.max(2_000)
|
|
392
|
+
.nullable()
|
|
393
|
+
.optional()
|
|
394
|
+
.describe("New description, or `null` to clear it. Omit to leave it as it is."),
|
|
395
|
+
parentId: IntelId.nullable()
|
|
396
|
+
.optional()
|
|
397
|
+
.describe(
|
|
398
|
+
"Folder to move the flow into, or `null` for the top level. Omit to leave it where it is. Moving touches no version, no published graph and no run.",
|
|
399
|
+
),
|
|
400
|
+
idempotencyKey: IdempotencyKey,
|
|
401
|
+
})
|
|
402
|
+
.refine(
|
|
403
|
+
(input) =>
|
|
404
|
+
input.title !== undefined || input.description !== undefined || input.parentId !== undefined,
|
|
405
|
+
{ error: "At least one change is required" },
|
|
406
|
+
);
|
|
407
|
+
export type UpdateFlowInput = z.infer<typeof UpdateFlowInput>;
|
|
408
|
+
|
|
409
|
+
// Archiving a flow is the same shape as archiving a document, deliberately: `archived` is a boolean
|
|
410
|
+
// rather than a one-way verb, because an archive nothing returns from is a delete under a friendlier
|
|
411
|
+
// name. Restoring is the same call with `false`.
|
|
412
|
+
export const ArchiveFlowInput = z.strictObject({
|
|
413
|
+
flowId: IntelId.describe("Flow to archive or restore."),
|
|
414
|
+
baseUpdatedAt: IsoDateTime.describe(
|
|
415
|
+
"`updatedAt` as flow_get last reported it. A newer value on the server means somebody else changed the flow first and the call is refused.",
|
|
416
|
+
),
|
|
417
|
+
archived: z
|
|
418
|
+
.boolean()
|
|
419
|
+
.describe(
|
|
420
|
+
"`true` archives the flow, `false` restores it. Nothing is deleted and every version stays readable.",
|
|
421
|
+
),
|
|
422
|
+
idempotencyKey: IdempotencyKey,
|
|
423
|
+
});
|
|
424
|
+
export type ArchiveFlowInput = z.infer<typeof ArchiveFlowInput>;
|
|
425
|
+
|
|
426
|
+
// ⚠️ The flow half of the one irreversible act in Intel (#457). No `baseUpdatedAt`, no
|
|
427
|
+
// `idempotencyKey`, for the same two reasons the node's has neither: an archived flow is not being
|
|
428
|
+
// edited, and a replay has nothing to replay — deleting twice deletes once and then answers 404.
|
|
429
|
+
export const PurgeFlowInput = z.strictObject({
|
|
430
|
+
flowId: IntelId.describe(
|
|
431
|
+
"Flow to delete for good. It must already be archived — a living flow has no path into nothing.",
|
|
432
|
+
),
|
|
433
|
+
});
|
|
434
|
+
export type PurgeFlowInput = z.infer<typeof PurgeFlowInput>;
|
|
435
|
+
|
|
436
|
+
export const PurgeFlowResult = z.strictObject({
|
|
437
|
+
purged: z.literal(true),
|
|
438
|
+
title: z.string(),
|
|
439
|
+
});
|
|
440
|
+
export type PurgeFlowResult = z.infer<typeof PurgeFlowResult>;
|
|
441
|
+
|
|
442
|
+
// Three answers, not two: an absent `parentId` lists every visible flow (the search dialog asks
|
|
443
|
+
// that), `null` lists the root of the shared tree and an ID lists one folder (the sidebar tree asks
|
|
444
|
+
// per level, which is what keeps the tree off the N+1 it used to load with).
|
|
445
|
+
export const ListFlowsInput = z.strictObject({
|
|
446
|
+
parentId: IntelId.nullable()
|
|
447
|
+
.optional()
|
|
448
|
+
.describe(
|
|
449
|
+
"Three answers, not two: omit it to list every flow this reader may see, pass `null` for the top level, or a folder id for one level of it.",
|
|
450
|
+
),
|
|
451
|
+
// The only way back to an archived flow, and the only place that asks for one: the bounded read
|
|
452
|
+
// behind the relation graph has no such flag on purpose (#30). A drawing that includes what was
|
|
453
|
+
// archived says the tidying up never happened.
|
|
454
|
+
//
|
|
455
|
+
// ⚠️ `.optional()` rather than `.default(false)`, unlike `ListNodesInput`. This schema is
|
|
456
|
+
// the argument type of `listFlows` on three layers, and a default makes the field required in the
|
|
457
|
+
// *parsed* type — every existing caller that lists a folder would have to spell out the answer to
|
|
458
|
+
// a question it is not asking. Absent means "without the archive" everywhere it is read.
|
|
459
|
+
includeArchived: z
|
|
460
|
+
.boolean()
|
|
461
|
+
.optional()
|
|
462
|
+
.describe("Include archived flows beside the live ones. Absent means without them."),
|
|
463
|
+
// The same question for flows, and the same override of `parentId` — see `ListNodesInput`.
|
|
464
|
+
archivedOnly: z
|
|
465
|
+
.boolean()
|
|
466
|
+
.optional()
|
|
467
|
+
.describe(
|
|
468
|
+
"List only archived flows, across the whole tree. Overrides parentId rather than narrowing it.",
|
|
469
|
+
),
|
|
470
|
+
});
|
|
471
|
+
export type ListFlowsInput = z.infer<typeof ListFlowsInput>;
|
|
472
|
+
|
|
473
|
+
export const GetFlowInput = z.strictObject({
|
|
474
|
+
flowId: IntelId.describe("Flow to read, from flow_list."),
|
|
475
|
+
});
|
|
476
|
+
export type GetFlowInput = z.infer<typeof GetFlowInput>;
|
|
477
|
+
export const SaveFlowVersionInput = z.strictObject({
|
|
478
|
+
flowId: IntelId.describe("Flow to append a version to."),
|
|
479
|
+
// ⚠️ `baseVersion`, not `IntelId.nullable()` (#459). The field is required-nullable either way;
|
|
480
|
+
// what changes is what a caller who left it out is told. Zod's own `expected string, received
|
|
481
|
+
// undefined` reads as "this needs an id" to somebody holding a flow created one call earlier —
|
|
482
|
+
// whose `currentVersionId` is `null` and can be nothing else. That reading cost a session at
|
|
483
|
+
// #437, and this was the third field carrying it.
|
|
484
|
+
baseVersionId: baseVersion(
|
|
485
|
+
"baseVersionId takes the `currentVersionId` from flow_get, or null when the flow has no version yet — and it has to be sent.",
|
|
486
|
+
).describe(
|
|
487
|
+
"The version this edit was made against, from flow_get, or `null` for a flow that has none yet. If the flow has moved on since, the call is refused rather than overwriting the newer version.",
|
|
488
|
+
),
|
|
489
|
+
graph: FlowGraph.describe(
|
|
490
|
+
"The complete graph — nodes and edges — not a patch. It is validated before it is stored, so an unreachable node or a dangling edge is refused here rather than at run time.",
|
|
491
|
+
),
|
|
492
|
+
idempotencyKey: IdempotencyKey,
|
|
493
|
+
});
|
|
494
|
+
export type SaveFlowVersionInput = z.infer<typeof SaveFlowVersionInput>;
|
|
495
|
+
export const PublishFlowInput = z.strictObject({
|
|
496
|
+
flowId: IntelId.describe("Flow to publish a version of."),
|
|
497
|
+
versionId: IntelId.describe(
|
|
498
|
+
"Which version becomes the published one. Publishing freezes what it calls: a sub-flow call set to `latest` is pinned to the version current at this moment. flow_publish_preview shows that beforehand.",
|
|
499
|
+
),
|
|
500
|
+
// ⚠️ Optional, and its absence means "leave the name as it is" rather than "no name". Publishing
|
|
501
|
+
// a second version of a flow that is already offered must not silently withdraw its command, and
|
|
502
|
+
// that is what a required-nullable field here would do to every caller who republishes without
|
|
503
|
+
// thinking about prompts (#775). `null` is how a name is actually given up.
|
|
504
|
+
promptName: PromptName.nullable()
|
|
505
|
+
.optional()
|
|
506
|
+
.describe(
|
|
507
|
+
"Offer this flow as a slash command under this name, or `null` to stop offering it. Omit to keep whatever name it has — republishing a flow does not withdraw its command.",
|
|
508
|
+
),
|
|
509
|
+
idempotencyKey: IdempotencyKey,
|
|
510
|
+
});
|
|
511
|
+
export type PublishFlowInput = z.infer<typeof PublishFlowInput>;
|
|
512
|
+
|
|
513
|
+
// The way back out of a publication (#146). No versionId: what is withdrawn is whatever is
|
|
514
|
+
// published now, and naming one would invite a race between reading it and revoking it. Versions
|
|
515
|
+
// are untouched — republishing any of them is one `publish` away.
|
|
516
|
+
export const UnpublishFlowInput = z.strictObject({
|
|
517
|
+
flowId: IntelId.describe(
|
|
518
|
+
"Flow to withdraw. What is withdrawn is whatever is published now — there is no versionId, so there is no race between reading it and revoking it. Versions are untouched.",
|
|
519
|
+
),
|
|
520
|
+
idempotencyKey: IdempotencyKey,
|
|
521
|
+
});
|
|
522
|
+
export type UnpublishFlowInput = z.infer<typeof UnpublishFlowInput>;
|
|
523
|
+
|
|
524
|
+
export const PreviewFlowPublishInput = z.strictObject({
|
|
525
|
+
flowId: IntelId.describe("Flow the version belongs to."),
|
|
526
|
+
versionId: IntelId.describe(
|
|
527
|
+
"The version flow_publish would be called with. Nothing is changed by asking.",
|
|
528
|
+
),
|
|
529
|
+
});
|
|
530
|
+
export type PreviewFlowPublishInput = z.infer<typeof PreviewFlowPublishInput>;
|
|
531
|
+
|
|
532
|
+
// One sub-flow call as publishing will leave it (ADR-0004 §5). `freezes` is the whole point of the
|
|
533
|
+
// preview: it marks the calls whose `latest` publishing turns into `versionId`, so the author reads
|
|
534
|
+
// the decision before making it rather than after.
|
|
535
|
+
//
|
|
536
|
+
// ⚠️ Only callees the asking actor may reach are listed at all. A call whose callee they cannot see
|
|
537
|
+
// is left out rather than named, because a title is the thing an unreachable flow must not hand out.
|
|
538
|
+
export const FlowPublishCall = z.strictObject({
|
|
539
|
+
nodeId: FlowNodeId,
|
|
540
|
+
nodeLabel: z.string().min(1).max(160),
|
|
541
|
+
calleeId: IntelId,
|
|
542
|
+
calleeTitle: z.string().min(1).max(240),
|
|
543
|
+
mode: SubflowVersionMode,
|
|
544
|
+
// The version this call will take once published. `null` when it follows the callee, which is the
|
|
545
|
+
// one case where the answer is only known at run time.
|
|
546
|
+
versionId: IntelId.nullable(),
|
|
547
|
+
versionSequence: z.number().int().positive().nullable(),
|
|
548
|
+
freezes: z.boolean(),
|
|
549
|
+
// The callee has a published version to be called at all. `false` is what publishing will refuse.
|
|
550
|
+
available: z.boolean(),
|
|
551
|
+
});
|
|
552
|
+
export type FlowPublishCall = z.infer<typeof FlowPublishCall>;
|
|
553
|
+
|
|
554
|
+
/**
|
|
555
|
+
* What a tool step will be allowed to reach once this version is published (#517).
|
|
556
|
+
*
|
|
557
|
+
* ⚠️ It is in the preview because publishing FREEZES it: from that moment the step's surface is
|
|
558
|
+
* pinned, and a function the provider adds later is not inherited. An author who cannot see the
|
|
559
|
+
* surface before confirming is asked to freeze something they were never shown.
|
|
560
|
+
*/
|
|
561
|
+
export const FlowPublishTool = z.strictObject({
|
|
562
|
+
nodeId: FlowNodeId,
|
|
563
|
+
nodeLabel: z.string().min(1).max(160),
|
|
564
|
+
server: ToolServerHandle,
|
|
565
|
+
// `null` is "every function of that server". A list is what the step narrowed itself to, and it
|
|
566
|
+
// is spelled out rather than counted: the whole point of the preview is that a human can read it.
|
|
567
|
+
allow: z.array(ToolName).nullable(),
|
|
568
|
+
// The server is reachable for the person publishing. `false` is what publishing will refuse.
|
|
569
|
+
available: z.boolean(),
|
|
570
|
+
});
|
|
571
|
+
export type FlowPublishTool = z.infer<typeof FlowPublishTool>;
|
|
572
|
+
|
|
573
|
+
export const FlowPublishPreview = z.strictObject({
|
|
574
|
+
flowId: IntelId,
|
|
575
|
+
versionId: IntelId,
|
|
576
|
+
calls: z.array(FlowPublishCall),
|
|
577
|
+
tools: z.array(FlowPublishTool),
|
|
578
|
+
});
|
|
579
|
+
export type FlowPublishPreview = z.infer<typeof FlowPublishPreview>;
|
|
580
|
+
// A flow's own sharing schemas live in `share.ts` beside the node's (#530): `ShareFlowInput`,
|
|
581
|
+
// `RevokeFlowGrantInput`, `ListFlowGrantsInput`. They are there rather than here because a grant is
|
|
582
|
+
// one subject with two kinds of target, not two features — and `ShareResult` answers for both.
|
|
583
|
+
|
|
584
|
+
// What accesses what, for one level of the shared tree (#19). A folder answers it for its contents,
|
|
585
|
+
// a single flow for itself. Documents and flows are two kinds of thing that share one tree
|
|
586
|
+
// (ADR-0004 §1), so the graph carries both and says which of them it is.
|
|
587
|
+
//
|
|
588
|
+
// ⚠️ **DERIVED from `NodeKind`, not written out beside it** (#376). It was a hand-kept copy until
|
|
589
|
+
// D66 added two kinds, and the copy did not follow — the graph would have gone on answering about
|
|
590
|
+
// four kinds while the tree held six, and nothing would have said so. That is the same failure
|
|
591
|
+
// `check:boundaries` refuses elsewhere; here the extra member `flow` had kept it out of the
|
|
592
|
+
// checker's reach.
|
|
593
|
+
export const RelationNodeKind = z.enum([...NodeKind.options, "flow"]);
|
|
594
|
+
export type RelationNodeKind = z.infer<typeof RelationNodeKind>;
|
|
595
|
+
|
|
596
|
+
export const RelationNode = z.strictObject({
|
|
597
|
+
id: IntelId,
|
|
598
|
+
kind: RelationNodeKind,
|
|
599
|
+
title: z.string().min(1).max(240),
|
|
600
|
+
// Inside the level being shown, rather than something it reaches out to. A flow reading a policy
|
|
601
|
+
// document from another folder pulls that document in, and the difference should be legible.
|
|
602
|
+
inScope: z.boolean(),
|
|
603
|
+
// ⚠️ The radial tree's own structure (#825), and deliberately not an edge: a "belongs" relation
|
|
604
|
+
// would duplicate what `parentId` already says and give two places for the two to drift.
|
|
605
|
+
// `depth` is the ring this node sits on, counted from the folder or flow being viewed (depth 0).
|
|
606
|
+
// A node reached only through a `reads`/`calls` edge — never part of the tree itself — carries the
|
|
607
|
+
// depth of whichever in-tree node reached it and a `null` parent, so the renderer knows not to
|
|
608
|
+
// draw a membership arc for it.
|
|
609
|
+
parentId: IntelId.nullable(),
|
|
610
|
+
depth: z.number().int().nonnegative(),
|
|
611
|
+
});
|
|
612
|
+
export type RelationNode = z.infer<typeof RelationNode>;
|
|
613
|
+
|
|
614
|
+
export const RelationEdge = z.strictObject({
|
|
615
|
+
id: z.string().min(1).max(400),
|
|
616
|
+
source: IntelId,
|
|
617
|
+
target: IntelId,
|
|
618
|
+
relation: z.enum(["reads", "calls"]),
|
|
619
|
+
});
|
|
620
|
+
export type RelationEdge = z.infer<typeof RelationEdge>;
|
|
621
|
+
|
|
622
|
+
// A user who may reach a node the viewer is looking at, and only ever THAT (#825). No name here on
|
|
623
|
+
// purpose: `id` is resolved through the same directory lookup every other screen already uses
|
|
624
|
+
// (`ResolvedNamesProvider`), so a name that later changes does not have to be threaded through this
|
|
625
|
+
// schema as well.
|
|
626
|
+
export const RelationUser = z.strictObject({ id: IntelId });
|
|
627
|
+
export type RelationUser = z.infer<typeof RelationUser>;
|
|
628
|
+
|
|
629
|
+
// ⚠️ Drawn only from a node the viewer holds `share` on (#825, `nodes.ts:1537`). `node_effective_access_list`
|
|
630
|
+
// refuses a caller without `share` with a `403` — a graph that drew this edge anyway would hand out,
|
|
631
|
+
// for every node in it, an answer the tool right next to it refuses to give.
|
|
632
|
+
export const RelationAccessEdge = z.strictObject({ userId: IntelId, nodeId: IntelId });
|
|
633
|
+
export type RelationAccessEdge = z.infer<typeof RelationAccessEdge>;
|
|
634
|
+
|
|
635
|
+
export const RelationGraphScope = z.discriminatedUnion("of", [
|
|
636
|
+
z.strictObject({ of: z.literal("folder"), folderId: IntelId.nullable() }),
|
|
637
|
+
z.strictObject({ of: z.literal("flow"), flowId: IntelId }),
|
|
638
|
+
]);
|
|
639
|
+
export type RelationGraphScope = z.infer<typeof RelationGraphScope>;
|
|
640
|
+
|
|
641
|
+
export const RelationGraphInput = z.strictObject({
|
|
642
|
+
scope: RelationGraphScope.describe(
|
|
643
|
+
"What to draw around: one folder — `null` for the whole tree — or one flow.",
|
|
644
|
+
),
|
|
645
|
+
// How much is drawn before the answer is summarized instead. A big folder has to stay usable, and
|
|
646
|
+
// the cut-off is reported rather than swallowed.
|
|
647
|
+
limit: z
|
|
648
|
+
.number()
|
|
649
|
+
.int()
|
|
650
|
+
.min(1)
|
|
651
|
+
.max(300)
|
|
652
|
+
.default(60)
|
|
653
|
+
.describe(
|
|
654
|
+
"How many nodes the drawing may carry before it is summarized instead. What was left out is reported in `omitted` rather than swallowed.",
|
|
655
|
+
),
|
|
656
|
+
});
|
|
657
|
+
export type RelationGraphInput = z.infer<typeof RelationGraphInput>;
|
|
658
|
+
|
|
659
|
+
// ⚠️ Only what the asking user may see is in here. A node they may not reach is absent, not greyed
|
|
660
|
+
// out and not counted: an edge to a placeholder would already tell them the thing exists, which is
|
|
661
|
+
// the leak this schema has to make impossible to write by accident. `omitted` is about the size
|
|
662
|
+
// limit alone, never about permissions.
|
|
663
|
+
export const RelationGraph = z.strictObject({
|
|
664
|
+
scope: RelationGraphScope,
|
|
665
|
+
nodes: z.array(RelationNode),
|
|
666
|
+
edges: z.array(RelationEdge),
|
|
667
|
+
// The outer ring (#825). `users` is the distinct set `access` points at — never every member of
|
|
668
|
+
// the organization, and never a user reachable only through an `email` or `organization` grant,
|
|
669
|
+
// because neither names a single account this drawing could point a line at.
|
|
670
|
+
users: z.array(RelationUser),
|
|
671
|
+
access: z.array(RelationAccessEdge),
|
|
672
|
+
omitted: z.number().int().nonnegative(),
|
|
673
|
+
limit: z.number().int().positive(),
|
|
674
|
+
});
|
|
675
|
+
export type RelationGraph = z.infer<typeof RelationGraph>;
|