@anchrd/intel-api 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/README.md +96 -0
  2. package/bin/intel.mjs +134 -0
  3. package/dist/adapters/cloudflare/cloudflare-flow-workflow.d.ts +21 -0
  4. package/dist/adapters/cloudflare/cloudflare-flow-workflow.js +39 -0
  5. package/dist/adapters/cloudflare/cloudflare.d.ts +8 -0
  6. package/dist/adapters/cloudflare/cloudflare.js +200 -0
  7. package/dist/adapters/cloudflare/cloudflare.types.d.ts +29 -0
  8. package/dist/adapters/cloudflare/cloudflare.types.js +1 -0
  9. package/dist/adapters/content/content.d.ts +3 -0
  10. package/dist/adapters/content/content.js +22 -0
  11. package/dist/adapters/content/content.types.d.ts +14 -0
  12. package/dist/adapters/content/content.types.js +1 -0
  13. package/dist/adapters/db/db-flows.d.ts +6 -0
  14. package/dist/adapters/db/db-flows.js +466 -0
  15. package/dist/adapters/db/db-indexing.d.ts +3 -0
  16. package/dist/adapters/db/db-indexing.js +70 -0
  17. package/dist/adapters/db/db-oauth.d.ts +3 -0
  18. package/dist/adapters/db/db-oauth.js +26 -0
  19. package/dist/adapters/db/db-tools.d.ts +6 -0
  20. package/dist/adapters/db/db-tools.js +200 -0
  21. package/dist/adapters/db/db.d.ts +6 -0
  22. package/dist/adapters/db/db.js +755 -0
  23. package/dist/adapters/db/db.types.d.ts +16 -0
  24. package/dist/adapters/db/db.types.js +1 -0
  25. package/dist/adapters/document-converter/document-converter.d.ts +2 -0
  26. package/dist/adapters/document-converter/document-converter.js +25 -0
  27. package/dist/adapters/document-converter/document-converter.types.d.ts +9 -0
  28. package/dist/adapters/document-converter/document-converter.types.js +1 -0
  29. package/dist/adapters/flow-runtime/flow-runtime.d.ts +3 -0
  30. package/dist/adapters/flow-runtime/flow-runtime.js +22 -0
  31. package/dist/adapters/flow-runtime/flow-runtime.types.d.ts +19 -0
  32. package/dist/adapters/flow-runtime/flow-runtime.types.js +1 -0
  33. package/dist/adapters/index-queue/index-queue.d.ts +10 -0
  34. package/dist/adapters/index-queue/index-queue.js +12 -0
  35. package/dist/adapters/index-queue/index-queue.types.d.ts +11 -0
  36. package/dist/adapters/index-queue/index-queue.types.js +1 -0
  37. package/dist/adapters/json-schema/json-schema.d.ts +2 -0
  38. package/dist/adapters/json-schema/json-schema.js +31 -0
  39. package/dist/adapters/openid/openid.d.ts +5 -0
  40. package/dist/adapters/openid/openid.js +159 -0
  41. package/dist/adapters/portal-tokens/portal-tokens.d.ts +8 -0
  42. package/dist/adapters/portal-tokens/portal-tokens.js +71 -0
  43. package/dist/adapters/remote-tools/remote-tools.d.ts +5 -0
  44. package/dist/adapters/remote-tools/remote-tools.js +109 -0
  45. package/dist/adapters/semantic-index/semantic-index.d.ts +2 -0
  46. package/dist/adapters/semantic-index/semantic-index.js +57 -0
  47. package/dist/adapters/semantic-index/semantic-index.types.d.ts +32 -0
  48. package/dist/adapters/semantic-index/semantic-index.types.js +1 -0
  49. package/dist/adapters/session-cookie/session-cookie.d.ts +5 -0
  50. package/dist/adapters/session-cookie/session-cookie.js +81 -0
  51. package/dist/adapters/tool-source-policy/tool-source-policy.d.ts +1 -0
  52. package/dist/adapters/tool-source-policy/tool-source-policy.js +22 -0
  53. package/dist/auth/auth.d.ts +2 -0
  54. package/dist/auth/auth.js +176 -0
  55. package/dist/auth/auth.types.d.ts +104 -0
  56. package/dist/auth/auth.types.js +1 -0
  57. package/dist/build/build.d.ts +2 -0
  58. package/dist/build/build.js +125 -0
  59. package/dist/build/build.types.d.ts +17 -0
  60. package/dist/build/build.types.js +1 -0
  61. package/dist/cli/cli.d.ts +4 -0
  62. package/dist/cli/cli.js +141 -0
  63. package/dist/cli/cli.types.d.ts +14 -0
  64. package/dist/cli/cli.types.js +1 -0
  65. package/dist/flows/flows.d.ts +4 -0
  66. package/dist/flows/flows.js +409 -0
  67. package/dist/flows/flows.types.d.ts +108 -0
  68. package/dist/flows/flows.types.js +1 -0
  69. package/dist/http/http.d.ts +8 -0
  70. package/dist/http/http.js +286 -0
  71. package/dist/http/http.types.d.ts +14 -0
  72. package/dist/http/http.types.js +1 -0
  73. package/dist/indexing/indexing.d.ts +6 -0
  74. package/dist/indexing/indexing.js +48 -0
  75. package/dist/indexing/indexing.types.d.ts +10 -0
  76. package/dist/indexing/indexing.types.js +1 -0
  77. package/dist/intel/intel.d.ts +3 -0
  78. package/dist/intel/intel.js +77 -0
  79. package/dist/intel/intel.types.d.ts +14 -0
  80. package/dist/intel/intel.types.js +1 -0
  81. package/dist/knowledge/knowledge.d.ts +2 -0
  82. package/dist/knowledge/knowledge.js +479 -0
  83. package/dist/knowledge/knowledge.types.d.ts +162 -0
  84. package/dist/knowledge/knowledge.types.js +1 -0
  85. package/dist/mcp/mcp.d.ts +2 -0
  86. package/dist/mcp/mcp.js +484 -0
  87. package/dist/mcp/mcp.types.d.ts +10 -0
  88. package/dist/mcp/mcp.types.js +1 -0
  89. package/dist/prepare/prepare.d.ts +4 -0
  90. package/dist/prepare/prepare.js +16 -0
  91. package/dist/prepare/prepare.types.d.ts +9 -0
  92. package/dist/prepare/prepare.types.js +1 -0
  93. package/dist/shared/gate-authorization/gate-authorization.d.ts +4 -0
  94. package/dist/shared/gate-authorization/gate-authorization.js +19 -0
  95. package/dist/shared/intel-error/intel-error.d.ts +5 -0
  96. package/dist/shared/intel-error/intel-error.js +10 -0
  97. package/dist/shared/problem-details/problem-details.d.ts +8 -0
  98. package/dist/shared/problem-details/problem-details.js +4 -0
  99. package/dist/shared/safe-return-path/safe-return-path.d.ts +2 -0
  100. package/dist/shared/safe-return-path/safe-return-path.js +11 -0
  101. package/dist/shared/sha256/sha256.d.ts +1 -0
  102. package/dist/shared/sha256/sha256.js +9 -0
  103. package/dist/tools/tools.d.ts +2 -0
  104. package/dist/tools/tools.js +107 -0
  105. package/dist/tools/tools.types.d.ts +56 -0
  106. package/dist/tools/tools.types.js +1 -0
  107. package/examples/branding/favicon.svg +5 -0
  108. package/examples/branding/logo.svg +5 -0
  109. package/examples/branding/theme.css +16 -0
  110. package/examples/dev.vars.example +7 -0
  111. package/examples/intel.json +9 -0
  112. package/migrations/0000_intel_foundation.sql +203 -0
  113. package/migrations/0001_portal_native_tools.sql +21 -0
  114. package/package.json +62 -0
@@ -0,0 +1,107 @@
1
+ import { IntelError } from "../shared/intel-error/intel-error.js";
2
+ const CallTimeoutMs = 15_000;
3
+ const MaxTools = 1_000;
4
+ const MaxResultBytes = 1_000_000;
5
+ // Refresh slightly early so a call cannot start with a token that expires mid-flight.
6
+ const RefreshWindowMs = 30_000;
7
+ export function createTools(deps) {
8
+ function portal() {
9
+ if (!deps.portalUrl || !deps.sourceAllowed(deps.portalUrl)) {
10
+ throw new IntelError(503, "portal_not_configured", "No MCP portal is configured for this deployment");
11
+ }
12
+ return deps.portalUrl;
13
+ }
14
+ // Authorization for tools lives entirely in the portal, so "may this user act" reduces to "does
15
+ // this user have a usable portal token".
16
+ async function accessToken(actor) {
17
+ const stored = await deps.tokens.read(actor.id);
18
+ if (!stored) {
19
+ throw new IntelError(401, "portal_not_connected", "Connect the MCP portal to use tools");
20
+ }
21
+ if (stored.expiresAt > deps.now().getTime() + RefreshWindowMs)
22
+ return stored.accessToken;
23
+ const refreshed = stored.refreshToken ? await deps.refresh(stored) : null;
24
+ if (!refreshed) {
25
+ // A token that cannot be renewed is dropped: leaving it would keep failing every call with a
26
+ // stale credential instead of prompting a reconnect.
27
+ await deps.tokens.clear(actor.id);
28
+ throw new IntelError(401, "portal_reconnect_required", "Reconnect the MCP portal to continue");
29
+ }
30
+ await deps.tokens.write(actor.id, refreshed);
31
+ return refreshed.accessToken;
32
+ }
33
+ // One live tools/list is both the catalog and the authorization answer: the portal only returns
34
+ // what this user may reach. Nothing here is cached as a permission.
35
+ async function capabilities(actor) {
36
+ const token = await accessToken(actor);
37
+ const remote = await deps.remote.list(portal(), token, AbortSignal.timeout(CallTimeoutMs));
38
+ if (remote.length > MaxTools) {
39
+ throw new IntelError(502, "tool_catalog_too_large", "The portal returned too many tools");
40
+ }
41
+ const items = [];
42
+ for (const tool of remote) {
43
+ items.push({
44
+ ...tool,
45
+ fingerprint: await deps.fingerprint({
46
+ name: tool.name,
47
+ inputSchema: tool.inputSchema,
48
+ outputSchema: tool.outputSchema,
49
+ annotations: tool.annotations,
50
+ }),
51
+ });
52
+ }
53
+ return items;
54
+ }
55
+ async function requireCapability(actor, name) {
56
+ const found = (await capabilities(actor)).find((capability) => capability.name === name);
57
+ if (!found) {
58
+ throw new IntelError(404, "tool_not_available", `Tool ${name} is not available to you`);
59
+ }
60
+ return found;
61
+ }
62
+ async function call(actor, input) {
63
+ if (!actor.canExecute) {
64
+ throw new IntelError(403, "tool_execute_forbidden", "Tool execution permission is required");
65
+ }
66
+ const capability = await requireCapability(actor, input.name);
67
+ const validation = deps.validate(capability.inputSchema, input.arguments);
68
+ if (!validation.valid) {
69
+ throw new IntelError(400, "tool_arguments_invalid", validation.detail ?? "Invalid arguments");
70
+ }
71
+ const result = await deps.remote.call({
72
+ url: portal(),
73
+ accessToken: await accessToken(actor),
74
+ name: capability.name,
75
+ arguments: input.arguments,
76
+ signal: AbortSignal.timeout(CallTimeoutMs),
77
+ });
78
+ if (new TextEncoder().encode(JSON.stringify(result)).byteLength > MaxResultBytes) {
79
+ throw new IntelError(502, "tool_result_too_large", "Tool result exceeded the Intel limit");
80
+ }
81
+ return result;
82
+ }
83
+ return {
84
+ async catalog(actor) {
85
+ const stored = await deps.tokens.read(actor.id);
86
+ // An unconnected portal is a normal state, not an error: the UI shows a connect prompt.
87
+ if (!stored)
88
+ return { portalConnected: false, items: [] };
89
+ return { portalConnected: true, items: await capabilities(actor) };
90
+ },
91
+ execute: async (actor, input) => await call(actor, input),
92
+ async test(actor, input) {
93
+ const capability = await requireCapability(actor, input.name);
94
+ if (capability.annotations.readOnlyHint !== true ||
95
+ capability.annotations.destructiveHint === true) {
96
+ throw new IntelError(409, "tool_test_unsafe", "Only explicitly read-only, non-destructive tools can run in the test surface");
97
+ }
98
+ return await call(actor, input);
99
+ },
100
+ async unavailable(actor, names) {
101
+ if (names.length === 0)
102
+ return [];
103
+ const available = new Set((await capabilities(actor)).map((capability) => capability.name));
104
+ return names.filter((name) => !available.has(name));
105
+ },
106
+ };
107
+ }
@@ -0,0 +1,56 @@
1
+ import type { ExecuteToolInput, TestToolInput, ToolCapability, ToolCatalog, ToolTestResult } from "@anchrd/intel-contract";
2
+ export interface ToolActor {
3
+ id: string;
4
+ email: string;
5
+ canExecute: boolean;
6
+ }
7
+ export interface PortalToken {
8
+ accessToken: string;
9
+ refreshToken: string | null;
10
+ expiresAt: number;
11
+ issuer: string;
12
+ clientId: string;
13
+ resource: string;
14
+ }
15
+ export interface PortalTokenStore {
16
+ read(userId: string): Promise<PortalToken | null>;
17
+ write(userId: string, token: PortalToken): Promise<void>;
18
+ clear(userId: string): Promise<void>;
19
+ }
20
+ export interface RemoteTool {
21
+ name: string;
22
+ title: string | null;
23
+ description: string | null;
24
+ inputSchema: Record<string, unknown>;
25
+ outputSchema: Record<string, unknown> | null;
26
+ annotations: ToolCapability["annotations"];
27
+ }
28
+ export interface RemoteTools {
29
+ list(url: string, accessToken: string, signal: AbortSignal): Promise<RemoteTool[]>;
30
+ call(input: {
31
+ url: string;
32
+ accessToken: string;
33
+ name: string;
34
+ arguments: Record<string, unknown>;
35
+ signal: AbortSignal;
36
+ }): Promise<ToolTestResult>;
37
+ }
38
+ export interface ToolDeps {
39
+ portalUrl: string | null;
40
+ remote: RemoteTools;
41
+ tokens: PortalTokenStore;
42
+ refresh(token: PortalToken): Promise<PortalToken | null>;
43
+ now(): Date;
44
+ fingerprint(value: unknown): Promise<string>;
45
+ sourceAllowed(url: string): boolean;
46
+ validate(schema: Record<string, unknown>, value: unknown): {
47
+ valid: boolean;
48
+ detail?: string;
49
+ };
50
+ }
51
+ export interface ToolService {
52
+ catalog(actor: ToolActor): Promise<ToolCatalog>;
53
+ execute(actor: ToolActor, input: ExecuteToolInput): Promise<ToolTestResult>;
54
+ test(actor: ToolActor, input: TestToolInput): Promise<ToolTestResult>;
55
+ unavailable(actor: ToolActor, names: string[]): Promise<string[]>;
56
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,5 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
2
+ <title>Customer Intel</title>
3
+ <rect width="32" height="32" rx="8" fill="oklch(0.5 0.18 250)"/>
4
+ <path d="M10 10h12v12H10zM7 14h3m12 0h3M14 7v3m4-3v3M14 22v3m4-3v3" fill="none" stroke="white" stroke-width="2" stroke-linecap="round"/>
5
+ </svg>
@@ -0,0 +1,5 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
2
+ <title>Customer Intel</title>
3
+ <rect width="32" height="32" rx="8" fill="oklch(0.5 0.18 250)"/>
4
+ <path d="M10 10h12v12H10zM7 14h3m12 0h3M14 7v3m4-3v3M14 22v3m4-3v3" fill="none" stroke="white" stroke-width="2" stroke-linecap="round"/>
5
+ </svg>
@@ -0,0 +1,16 @@
1
+ :root {
2
+ --radius: 0.75rem;
3
+ --primary: oklch(0.5 0.18 250);
4
+ --primary-foreground: oklch(0.98 0.01 250);
5
+ --sidebar-primary: oklch(0.5 0.18 250);
6
+ --sidebar-primary-foreground: oklch(0.98 0.01 250);
7
+ --ring: oklch(0.62 0.14 250);
8
+ }
9
+
10
+ .dark {
11
+ --primary: oklch(0.72 0.14 250);
12
+ --primary-foreground: oklch(0.16 0.03 250);
13
+ --sidebar-primary: oklch(0.72 0.14 250);
14
+ --sidebar-primary-foreground: oklch(0.16 0.03 250);
15
+ --ring: oklch(0.68 0.13 250);
16
+ }
@@ -0,0 +1,7 @@
1
+ GATE_URL=http://localhost:8787
2
+ INTEL_URL=http://localhost:8788
3
+ MCP_PORTAL_URL=https://portal.example.com/mcp
4
+ TOOL_SOURCE_ORIGINS=https://portal.example.com
5
+ ALLOW_INSECURE_OAUTH=true
6
+ GATE_SERVICE_KEY=replace-with-local-gate-service-key
7
+ INTEL_SESSION_SECRET=replace-with-at-least-32-random-bytes
@@ -0,0 +1,9 @@
1
+ {
2
+ "ui": {
3
+ "theme": "./branding/theme.css",
4
+ "logo": "./branding/logo.svg",
5
+ "favicon": "./branding/favicon.svg",
6
+ "defaultLanguage": "en",
7
+ "languages": {}
8
+ }
9
+ }
@@ -0,0 +1,203 @@
1
+ PRAGMA foreign_keys = ON;
2
+
3
+ CREATE TABLE knowledge_nodes (
4
+ id TEXT PRIMARY KEY NOT NULL,
5
+ parent_id TEXT REFERENCES knowledge_nodes(id),
6
+ kind TEXT NOT NULL CHECK (kind IN ('folder', 'document', 'attachment')),
7
+ title TEXT NOT NULL CHECK (length(title) BETWEEN 1 AND 240),
8
+ description TEXT CHECK (description IS NULL OR length(description) <= 2000),
9
+ context_policy TEXT NOT NULL CHECK (context_policy IN ('pinned', 'relevant', 'explicit')),
10
+ owner_id TEXT NOT NULL,
11
+ current_version_id TEXT,
12
+ created_at TEXT NOT NULL,
13
+ updated_at TEXT NOT NULL,
14
+ archived_at TEXT
15
+ );
16
+
17
+ CREATE INDEX knowledge_nodes_parent_idx ON knowledge_nodes(parent_id, archived_at, title);
18
+ CREATE INDEX knowledge_nodes_owner_idx ON knowledge_nodes(owner_id, archived_at);
19
+
20
+ CREATE TABLE knowledge_versions (
21
+ id TEXT PRIMARY KEY NOT NULL,
22
+ node_id TEXT NOT NULL REFERENCES knowledge_nodes(id),
23
+ sequence INTEGER NOT NULL CHECK (sequence > 0),
24
+ content_key TEXT NOT NULL UNIQUE,
25
+ media_type TEXT NOT NULL,
26
+ content_hash TEXT NOT NULL CHECK (length(content_hash) = 64),
27
+ size INTEGER NOT NULL CHECK (size >= 0),
28
+ created_by TEXT NOT NULL,
29
+ created_at TEXT NOT NULL,
30
+ UNIQUE (node_id, sequence)
31
+ );
32
+
33
+ CREATE INDEX knowledge_versions_node_idx ON knowledge_versions(node_id, sequence DESC);
34
+
35
+ CREATE TABLE knowledge_links (
36
+ id TEXT PRIMARY KEY NOT NULL,
37
+ source_node_id TEXT NOT NULL REFERENCES knowledge_nodes(id) ON DELETE CASCADE,
38
+ target_node_id TEXT NOT NULL REFERENCES knowledge_nodes(id) ON DELETE CASCADE,
39
+ relation TEXT NOT NULL CHECK (relation IN ('references', 'related', 'depends_on', 'implements')),
40
+ label TEXT CHECK (label IS NULL OR length(label) BETWEEN 1 AND 120),
41
+ created_by TEXT NOT NULL,
42
+ created_at TEXT NOT NULL,
43
+ CHECK (source_node_id <> target_node_id),
44
+ UNIQUE (source_node_id, target_node_id, relation)
45
+ );
46
+
47
+ CREATE INDEX knowledge_links_source_idx ON knowledge_links(source_node_id, created_at);
48
+ CREATE INDEX knowledge_links_target_idx ON knowledge_links(target_node_id, created_at);
49
+
50
+ CREATE TABLE knowledge_index_state (
51
+ version_id TEXT PRIMARY KEY NOT NULL REFERENCES knowledge_versions(id),
52
+ status TEXT NOT NULL CHECK (status IN ('pending', 'indexed', 'error')),
53
+ attempt_count INTEGER NOT NULL DEFAULT 0,
54
+ last_error TEXT,
55
+ updated_at TEXT NOT NULL
56
+ );
57
+
58
+ CREATE INDEX knowledge_index_state_status_idx ON knowledge_index_state(status, updated_at);
59
+
60
+ CREATE TABLE resource_grants (
61
+ id TEXT PRIMARY KEY NOT NULL,
62
+ resource_type TEXT NOT NULL CHECK (resource_type IN ('knowledge', 'flow', 'tool-source')),
63
+ resource_id TEXT NOT NULL,
64
+ principal_type TEXT NOT NULL CHECK (principal_type IN ('user', 'email', 'organization')),
65
+ principal_id TEXT NOT NULL,
66
+ role TEXT NOT NULL CHECK (role IN ('viewer', 'commenter', 'editor', 'manager')),
67
+ expires_at TEXT,
68
+ created_by TEXT NOT NULL,
69
+ created_at TEXT NOT NULL,
70
+ UNIQUE (resource_type, resource_id, principal_type, principal_id)
71
+ );
72
+
73
+ CREATE INDEX resource_grants_principal_idx ON resource_grants(
74
+ principal_type,
75
+ principal_id,
76
+ resource_type,
77
+ expires_at
78
+ );
79
+
80
+ CREATE TABLE idempotency_keys (
81
+ actor_id TEXT NOT NULL,
82
+ operation TEXT NOT NULL,
83
+ idempotency_key TEXT NOT NULL,
84
+ resource_id TEXT NOT NULL,
85
+ created_at TEXT NOT NULL,
86
+ PRIMARY KEY (actor_id, operation, idempotency_key)
87
+ );
88
+
89
+ CREATE INDEX idempotency_keys_created_idx ON idempotency_keys(created_at);
90
+
91
+ CREATE TABLE audit_events (
92
+ id TEXT PRIMARY KEY NOT NULL,
93
+ actor_id TEXT NOT NULL,
94
+ action TEXT NOT NULL,
95
+ resource_type TEXT NOT NULL,
96
+ resource_id TEXT NOT NULL,
97
+ metadata_json TEXT NOT NULL DEFAULT '{}',
98
+ occurred_at TEXT NOT NULL
99
+ );
100
+
101
+ CREATE INDEX audit_events_resource_idx ON audit_events(resource_type, resource_id, occurred_at DESC);
102
+ CREATE INDEX audit_events_actor_idx ON audit_events(actor_id, occurred_at DESC);
103
+
104
+ CREATE TABLE oauth_clients (
105
+ issuer TEXT NOT NULL,
106
+ redirect_uri TEXT NOT NULL,
107
+ client_id TEXT NOT NULL,
108
+ created_at TEXT NOT NULL,
109
+ PRIMARY KEY (issuer, redirect_uri)
110
+ );
111
+
112
+ CREATE TABLE tool_sources (
113
+ id TEXT PRIMARY KEY NOT NULL,
114
+ name TEXT NOT NULL,
115
+ url TEXT NOT NULL UNIQUE,
116
+ connection_handle TEXT NOT NULL,
117
+ enabled INTEGER NOT NULL DEFAULT 1 CHECK (enabled IN (0, 1)),
118
+ created_by TEXT NOT NULL,
119
+ created_at TEXT NOT NULL,
120
+ updated_at TEXT NOT NULL,
121
+ last_discovered_at TEXT
122
+ );
123
+
124
+ CREATE TABLE tool_catalog (
125
+ source_id TEXT NOT NULL REFERENCES tool_sources(id) ON DELETE CASCADE,
126
+ name TEXT NOT NULL,
127
+ title TEXT,
128
+ description TEXT,
129
+ input_schema_json TEXT NOT NULL,
130
+ output_schema_json TEXT,
131
+ annotations_json TEXT NOT NULL,
132
+ fingerprint TEXT NOT NULL,
133
+ discovered_at TEXT NOT NULL,
134
+ PRIMARY KEY (source_id, name)
135
+ );
136
+
137
+ CREATE INDEX tool_catalog_title_idx ON tool_catalog(source_id, title, name);
138
+
139
+ CREATE TABLE flows (
140
+ id TEXT PRIMARY KEY NOT NULL,
141
+ title TEXT NOT NULL,
142
+ description TEXT,
143
+ owner_id TEXT NOT NULL,
144
+ current_version_id TEXT,
145
+ published_version_id TEXT,
146
+ created_at TEXT NOT NULL,
147
+ updated_at TEXT NOT NULL,
148
+ archived_at TEXT
149
+ );
150
+
151
+ CREATE INDEX flows_owner_idx ON flows(owner_id, archived_at, updated_at DESC);
152
+
153
+ CREATE TABLE flow_versions (
154
+ id TEXT PRIMARY KEY NOT NULL,
155
+ flow_id TEXT NOT NULL REFERENCES flows(id),
156
+ sequence INTEGER NOT NULL CHECK (sequence > 0),
157
+ graph_json TEXT NOT NULL,
158
+ created_by TEXT NOT NULL,
159
+ created_at TEXT NOT NULL,
160
+ UNIQUE (flow_id, sequence)
161
+ );
162
+
163
+ CREATE INDEX flow_versions_flow_idx ON flow_versions(flow_id, sequence DESC);
164
+
165
+ CREATE TABLE flow_runs (
166
+ id TEXT PRIMARY KEY NOT NULL,
167
+ flow_id TEXT NOT NULL REFERENCES flows(id),
168
+ version_id TEXT NOT NULL REFERENCES flow_versions(id),
169
+ status TEXT NOT NULL CHECK (status IN ('queued', 'running', 'waiting', 'completed', 'failed', 'cancelled')),
170
+ current_node_id TEXT,
171
+ input_json TEXT NOT NULL,
172
+ output_json TEXT,
173
+ error TEXT,
174
+ initiated_by TEXT NOT NULL,
175
+ created_at TEXT NOT NULL,
176
+ updated_at TEXT NOT NULL,
177
+ completed_at TEXT,
178
+ transition_id TEXT
179
+ );
180
+
181
+ CREATE INDEX flow_runs_flow_idx ON flow_runs(flow_id, created_at DESC);
182
+ CREATE INDEX flow_runs_status_idx ON flow_runs(status, updated_at);
183
+
184
+ CREATE TABLE flow_run_steps (
185
+ id TEXT PRIMARY KEY NOT NULL,
186
+ run_id TEXT NOT NULL REFERENCES flow_runs(id),
187
+ node_id TEXT NOT NULL,
188
+ outcome TEXT NOT NULL CHECK (outcome IN ('completed', 'failed')),
189
+ branch TEXT,
190
+ output_json TEXT,
191
+ error TEXT,
192
+ completed_by TEXT NOT NULL,
193
+ completed_at TEXT NOT NULL,
194
+ UNIQUE (run_id, node_id)
195
+ );
196
+
197
+ CREATE VIRTUAL TABLE knowledge_fts USING fts5(
198
+ version_id UNINDEXED,
199
+ node_id UNINDEXED,
200
+ title,
201
+ content,
202
+ tokenize = 'unicode61 remove_diacritics 2'
203
+ );
@@ -0,0 +1,21 @@
1
+ -- ADR-0003: the Cloudflare MCP portal owns tool discovery, tool permissions and provider
2
+ -- credentials. Intel no longer registers sources, mirrors a catalog or grants access to tools.
3
+ -- 0.1.x shipped these tables, so they are dropped explicitly rather than removed from 0000.
4
+
5
+ DROP INDEX IF EXISTS tool_catalog_title_idx;
6
+ DROP TABLE IF EXISTS tool_catalog;
7
+ DROP TABLE IF EXISTS tool_sources;
8
+
9
+ -- Grants for a resource type that no longer exists would otherwise linger and keep matching the
10
+ -- ACL predicate shape used by knowledge and flows. The CHECK constraint still lists 'tool-source';
11
+ -- rebuilding the table to drop one unused enum value is not worth the migration risk.
12
+ DELETE FROM resource_grants WHERE resource_type = 'tool-source';
13
+
14
+ -- The only tool-related secret Intel stores: the per-user access token for its own portal
15
+ -- endpoint, sealed with the INTEL_SESSION_SECRET-derived key. No provider credential reaches D1.
16
+ CREATE TABLE portal_tokens (
17
+ user_id TEXT PRIMARY KEY NOT NULL,
18
+ sealed TEXT NOT NULL,
19
+ expires_at TEXT NOT NULL,
20
+ updated_at TEXT NOT NULL
21
+ );
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "@anchrd/intel-api",
3
+ "version": "0.2.0",
4
+ "type": "module",
5
+ "license": "UNLICENSED",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/anchrd/intel.git",
9
+ "directory": "packages/api"
10
+ },
11
+ "publishConfig": {
12
+ "access": "public"
13
+ },
14
+ "bin": {
15
+ "intel": "bin/intel.mjs"
16
+ },
17
+ "exports": {
18
+ ".": {
19
+ "types": "./dist/intel/intel.d.ts",
20
+ "default": "./dist/intel/intel.js"
21
+ },
22
+ "./cloudflare": {
23
+ "types": "./dist/adapters/cloudflare/cloudflare.d.ts",
24
+ "default": "./dist/adapters/cloudflare/cloudflare.js"
25
+ },
26
+ "./cloudflare-workflow": {
27
+ "types": "./dist/adapters/cloudflare/cloudflare-flow-workflow.d.ts",
28
+ "default": "./dist/adapters/cloudflare/cloudflare-flow-workflow.js"
29
+ }
30
+ },
31
+ "files": [
32
+ "bin",
33
+ "dist",
34
+ "examples",
35
+ "migrations"
36
+ ],
37
+ "scripts": {
38
+ "build": "tsc -p tsconfig.build.json && node ../../scripts/pack/fix-dts.mjs",
39
+ "prepack": "bun run build && node ../../scripts/pack/to-dist-manifest.mjs",
40
+ "postpack": "node ../../scripts/pack/restore-manifest.mjs",
41
+ "test": "vitest run",
42
+ "typecheck": "tsc --noEmit"
43
+ },
44
+ "dependencies": {
45
+ "@anchrd/gate-sdk": "^0.7.0",
46
+ "@anchrd/intel-contract": "^0.2.0",
47
+ "@modelcontextprotocol/sdk": "^1.30.0",
48
+ "ajv": "^8.20.0",
49
+ "hono": "^4.12.32",
50
+ "openid-client": "^6.8.4",
51
+ "ulid": "^3.0.2",
52
+ "zod": "^4.4.3"
53
+ },
54
+ "devDependencies": {
55
+ "@cloudflare/vitest-pool-workers": "^0.19.0",
56
+ "vitest": "^4.1.10",
57
+ "wrangler": "^4.115.0"
58
+ },
59
+ "main": "./dist/intel/intel.js",
60
+ "module": "./dist/intel/intel.js",
61
+ "types": "./dist/intel/intel.d.ts"
62
+ }