@xnetjs/plugins 0.0.2 → 0.0.3
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 +30 -0
- package/dist/index.d.ts +3759 -173
- package/dist/index.js +9923 -651
- package/dist/services/node.d.ts +1207 -1
- package/dist/services/node.js +7067 -584
- package/package.json +8 -4
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import * as _xnetjs_data from '@xnetjs/data';
|
|
2
|
-
import { SchemaIRI, NodeStore, NodeState } from '@xnetjs/data';
|
|
2
|
+
import { SchemaIRI, NodeStore, NodeState, NodeQueryDescriptor, NodeQueryResult } from '@xnetjs/data';
|
|
3
3
|
import { Extension } from '@tiptap/core';
|
|
4
4
|
import { ComponentType } from 'react';
|
|
5
|
+
import { PublicWriteBudgetPolicy, AbuseSurface, AISignalProvenanceInput } from '@xnetjs/abuse';
|
|
6
|
+
import { InstallProvenance, TrustTier } from '@xnetjs/trust';
|
|
7
|
+
export { InstallProvenance, TrustTier as PluginTrustTier, SandboxKind, deriveTrustTier, requiresCapabilityReprompt, sandboxForTier } from '@xnetjs/trust';
|
|
5
8
|
|
|
6
9
|
/**
|
|
7
10
|
* Core types for the plugin system
|
|
@@ -57,10 +60,256 @@ interface ExtensionStorage {
|
|
|
57
60
|
}
|
|
58
61
|
declare function createExtensionStorage(): ExtensionStorage;
|
|
59
62
|
|
|
63
|
+
/**
|
|
64
|
+
* AI surface contract types for xNet resources, tools, mutation plans, and audit events.
|
|
65
|
+
*/
|
|
66
|
+
type AiRiskLevel = 'low' | 'medium' | 'high' | 'critical';
|
|
67
|
+
type AiScope = 'workspace.read' | 'workspace.search' | 'page.read' | 'page.propose' | 'page.write' | 'database.read' | 'database.query' | 'database.propose' | 'database.write.rows' | 'database.write.schema' | 'canvas.read' | 'canvas.propose' | 'canvas.write' | 'storage.diagnostics' | 'storage.recovery' | 'network.fetch' | 'agent.workspace.export' | 'agent.workspace.import';
|
|
68
|
+
declare const AI_RISK_LEVELS: readonly AiRiskLevel[];
|
|
69
|
+
declare const AI_SCOPES: readonly AiScope[];
|
|
70
|
+
type AiTargetKind = 'workspace' | 'node' | 'page' | 'database' | 'databaseRows' | 'canvas' | 'storage';
|
|
71
|
+
declare const AI_TARGET_KINDS: readonly AiTargetKind[];
|
|
72
|
+
type AiJsonSchemaType = 'string' | 'number' | 'boolean' | 'object' | 'array';
|
|
73
|
+
type AiJsonSchema = {
|
|
74
|
+
type: AiJsonSchemaType;
|
|
75
|
+
description?: string;
|
|
76
|
+
enum?: readonly string[];
|
|
77
|
+
properties?: Record<string, AiJsonSchema>;
|
|
78
|
+
required?: readonly string[];
|
|
79
|
+
items?: AiJsonSchema;
|
|
80
|
+
additionalProperties?: boolean | AiJsonSchema;
|
|
81
|
+
};
|
|
82
|
+
type AiResource = {
|
|
83
|
+
uri: string;
|
|
84
|
+
name: string;
|
|
85
|
+
description?: string;
|
|
86
|
+
mimeType: string;
|
|
87
|
+
risk: AiRiskLevel;
|
|
88
|
+
requiredScopes: AiScope[];
|
|
89
|
+
dynamic?: boolean;
|
|
90
|
+
};
|
|
91
|
+
type AiToolDefinition = {
|
|
92
|
+
name: string;
|
|
93
|
+
title: string;
|
|
94
|
+
description: string;
|
|
95
|
+
risk: AiRiskLevel;
|
|
96
|
+
requiredScopes: AiScope[];
|
|
97
|
+
inputSchema: {
|
|
98
|
+
type: 'object';
|
|
99
|
+
properties: Record<string, AiJsonSchema>;
|
|
100
|
+
required?: readonly string[];
|
|
101
|
+
};
|
|
102
|
+
};
|
|
103
|
+
type AiToolCallResult = {
|
|
104
|
+
content: Array<{
|
|
105
|
+
type: 'text';
|
|
106
|
+
text: string;
|
|
107
|
+
}>;
|
|
108
|
+
};
|
|
109
|
+
/**
|
|
110
|
+
* A tool the AI surface can list and call but whose implementation lives outside
|
|
111
|
+
* the surface (a plugin/connector contribution, exploration 0196). `invoke`
|
|
112
|
+
* returns raw data; the surface serializes it for the model, keeping contributed
|
|
113
|
+
* tools symmetric with the built-in `xnet_*` tools.
|
|
114
|
+
*/
|
|
115
|
+
type AiExtraTool = AiToolDefinition & {
|
|
116
|
+
invoke: (args: Record<string, unknown>) => unknown | Promise<unknown>;
|
|
117
|
+
};
|
|
118
|
+
type AiValidationResult = {
|
|
119
|
+
valid: boolean;
|
|
120
|
+
warnings: string[];
|
|
121
|
+
errors: string[];
|
|
122
|
+
};
|
|
123
|
+
type AiOperation<TArgs extends Record<string, unknown> = Record<string, unknown>> = {
|
|
124
|
+
op: string;
|
|
125
|
+
args: TArgs;
|
|
126
|
+
rationale?: string;
|
|
127
|
+
};
|
|
128
|
+
type AiChangeSet = {
|
|
129
|
+
targetKind: AiTargetKind;
|
|
130
|
+
targetId: string;
|
|
131
|
+
baseRevision: string;
|
|
132
|
+
operations: AiOperation[];
|
|
133
|
+
};
|
|
134
|
+
type AiMutationPlanStatus = 'proposed' | 'validated' | 'applied' | 'rejected';
|
|
135
|
+
type AiMutationPlan = {
|
|
136
|
+
id: string;
|
|
137
|
+
workspaceId?: string;
|
|
138
|
+
actor: string;
|
|
139
|
+
intent: string;
|
|
140
|
+
risk: AiRiskLevel;
|
|
141
|
+
requiredScopes: AiScope[];
|
|
142
|
+
changes: AiChangeSet[];
|
|
143
|
+
validation: AiValidationResult;
|
|
144
|
+
createdAt: string;
|
|
145
|
+
status: AiMutationPlanStatus;
|
|
146
|
+
};
|
|
147
|
+
type AiAuditEvent = {
|
|
148
|
+
id: string;
|
|
149
|
+
planId: string;
|
|
150
|
+
actor: string;
|
|
151
|
+
risk: AiRiskLevel;
|
|
152
|
+
requiredScopes: AiScope[];
|
|
153
|
+
validation: AiValidationResult;
|
|
154
|
+
appliedChangeIds: string[];
|
|
155
|
+
rollbackHandle?: string;
|
|
156
|
+
createdAt: string;
|
|
157
|
+
};
|
|
158
|
+
type AiContextSeed = {
|
|
159
|
+
kind: AiTargetKind;
|
|
160
|
+
id: string;
|
|
161
|
+
};
|
|
162
|
+
type AiContextPackResource = {
|
|
163
|
+
uri: string;
|
|
164
|
+
mimeType: string;
|
|
165
|
+
text: string;
|
|
166
|
+
trust: {
|
|
167
|
+
level: 'workspace' | 'external-untrusted';
|
|
168
|
+
instructionBoundary: string;
|
|
169
|
+
};
|
|
170
|
+
citation: {
|
|
171
|
+
kind: AiTargetKind;
|
|
172
|
+
id: string;
|
|
173
|
+
revision?: string;
|
|
174
|
+
};
|
|
175
|
+
};
|
|
176
|
+
type AiContextPack = {
|
|
177
|
+
id: string;
|
|
178
|
+
query?: string;
|
|
179
|
+
seeds: AiContextSeed[];
|
|
180
|
+
resources: AiContextPackResource[];
|
|
181
|
+
createdAt: string;
|
|
182
|
+
limits: {
|
|
183
|
+
maxResources: number;
|
|
184
|
+
maxCharactersPerResource: number;
|
|
185
|
+
};
|
|
186
|
+
};
|
|
187
|
+
declare function isAiRiskLevel(value: unknown): value is AiRiskLevel;
|
|
188
|
+
declare function isAiScope(value: unknown): value is AiScope;
|
|
189
|
+
declare function isAiTargetKind(value: unknown): value is AiTargetKind;
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* @xnetjs/plugins — agent tools contribution point (exploration 0196).
|
|
193
|
+
*
|
|
194
|
+
* 0194 Phase 2 (`contributionsAsAiTools`) let the AI call a plugin *command*.
|
|
195
|
+
* This adds first-class, model-facing tools that are NOT tied to a UI command —
|
|
196
|
+
* the shape a Connector uses to expose, say, `slack_search_mentions` that reads
|
|
197
|
+
* the governed node store. Register once via `contributes.agentTools`; the host
|
|
198
|
+
* folds them into the AI surface's `extraTools`, so they appear in the in-app
|
|
199
|
+
* AI, the MCP server, and the files-first skill alike.
|
|
200
|
+
*
|
|
201
|
+
* A tool's `invoke` returns raw data; the surface serializes it for the model,
|
|
202
|
+
* keeping contributed tools symmetric with the built-in `xnet_*` tools.
|
|
203
|
+
*/
|
|
204
|
+
|
|
205
|
+
/** Input schema shape, shared with `AiToolDefinition`. */
|
|
206
|
+
type AgentToolInputSchema = AiToolDefinition['inputSchema'];
|
|
207
|
+
/**
|
|
208
|
+
* A plugin-contributed agent tool. Registered under `id`; exposed to the model
|
|
209
|
+
* under `name` (snake_case, plugin-namespaced by convention, e.g.
|
|
210
|
+
* `slack_search_mentions`).
|
|
211
|
+
*/
|
|
212
|
+
interface AgentToolContribution {
|
|
213
|
+
/** Registry key, plugin-scoped (e.g. `dev.xnet.connector.slack.search`). */
|
|
214
|
+
id: string;
|
|
215
|
+
/** Model-facing tool name (snake_case), e.g. `slack_search_mentions`. */
|
|
216
|
+
name: string;
|
|
217
|
+
/** Human title for menus (defaults to `name`). */
|
|
218
|
+
title?: string;
|
|
219
|
+
/** What the tool does — shown to the model. */
|
|
220
|
+
description: string;
|
|
221
|
+
/** Risk surfaced to the agent + consent layer (default `medium`). */
|
|
222
|
+
risk?: AiRiskLevel;
|
|
223
|
+
/** AI scopes this tool requires (default none). */
|
|
224
|
+
requiredScopes?: AiScope[];
|
|
225
|
+
/** JSON schema for the tool args (default: empty object schema). */
|
|
226
|
+
inputSchema?: AgentToolInputSchema;
|
|
227
|
+
/** Execute the tool. Returns raw data; the surface serializes it for the model. */
|
|
228
|
+
invoke: (args: Record<string, unknown>) => unknown | Promise<unknown>;
|
|
229
|
+
}
|
|
230
|
+
/** Convert one contribution into an AI-surface tool. */
|
|
231
|
+
declare function agentToolToExtraTool(tool: AgentToolContribution): AiExtraTool;
|
|
232
|
+
/**
|
|
233
|
+
* Convert contributed agent tools into AI-surface tools, de-duped by tool name
|
|
234
|
+
* (first wins — registration order). Pass the result as the AI surface's
|
|
235
|
+
* `extraTools` so they surface in the in-app AI and the MCP server.
|
|
236
|
+
*/
|
|
237
|
+
declare function agentToolsAsExtraTools(tools: readonly AgentToolContribution[]): AiExtraTool[];
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* @xnetjs/plugins — extensible mention/typeahead providers (exploration 0194
|
|
241
|
+
* Phase 4).
|
|
242
|
+
*
|
|
243
|
+
* The editor's `[[` / `#` / `@` typeaheads are host-callback-driven and not
|
|
244
|
+
* extensible by plugins. This contribution point lets a plugin add a new entity
|
|
245
|
+
* type to a trigger — a GitHub plugin makes `@` resolve issues, a CRM plugin
|
|
246
|
+
* makes it resolve contacts — and the host merges them with its own suggestions.
|
|
247
|
+
*
|
|
248
|
+
* `resolveMentionProviders` is the consumer logic the editor runs: it fans the
|
|
249
|
+
* query out to every provider for a trigger in parallel, merges by priority,
|
|
250
|
+
* dedups by suggestion id, and **timeout-guards** each provider so one slow or
|
|
251
|
+
* throwing provider can never block (or break) the menu.
|
|
252
|
+
*/
|
|
253
|
+
/** A single typeahead suggestion offered by a provider. */
|
|
254
|
+
interface MentionSuggestion {
|
|
255
|
+
/** Stable id, used for dedup across providers. */
|
|
256
|
+
id: string;
|
|
257
|
+
/** Text shown in the menu. */
|
|
258
|
+
label: string;
|
|
259
|
+
/** Secondary text (e.g. a handle, path, or type). */
|
|
260
|
+
detail?: string;
|
|
261
|
+
/** The reference to insert when chosen (defaults to `id`). */
|
|
262
|
+
value?: string;
|
|
263
|
+
/** Lucide icon name. */
|
|
264
|
+
icon?: string;
|
|
265
|
+
}
|
|
266
|
+
/** A plugin-contributed provider for one typeahead trigger. */
|
|
267
|
+
interface MentionProviderContribution {
|
|
268
|
+
/** Unique provider id. */
|
|
269
|
+
id: string;
|
|
270
|
+
/** Trigger token: `'[['` | `'#'` | `'@'`, or a plugin's own string. */
|
|
271
|
+
trigger: string;
|
|
272
|
+
/** Lower runs first when merging (default 100). */
|
|
273
|
+
priority?: number;
|
|
274
|
+
/** Resolve suggestions for a query under this trigger. */
|
|
275
|
+
getSuggestions: (query: string) => MentionSuggestion[] | Promise<MentionSuggestion[]>;
|
|
276
|
+
}
|
|
277
|
+
interface ResolveMentionOptions {
|
|
278
|
+
/** Per-provider timeout; a provider that exceeds it contributes nothing. */
|
|
279
|
+
timeoutMs?: number;
|
|
280
|
+
/** Cap the merged result length. */
|
|
281
|
+
limit?: number;
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Merge the suggestions from every provider registered for `trigger`, in
|
|
285
|
+
* priority order, deduped by suggestion id, each provider timeout-guarded.
|
|
286
|
+
*/
|
|
287
|
+
declare function resolveMentionProviders(providers: readonly MentionProviderContribution[], trigger: string, query: string, options?: ResolveMentionOptions): Promise<MentionSuggestion[]>;
|
|
288
|
+
|
|
60
289
|
/**
|
|
61
290
|
* Contribution types and registry for plugin-provided extensions
|
|
62
291
|
*/
|
|
63
292
|
|
|
293
|
+
/**
|
|
294
|
+
* How a command opts in to being callable by the AI agent as a tool
|
|
295
|
+
* (exploration 0194 Phase 2). Absent / `aiExposed:false` → the AI never sees it.
|
|
296
|
+
*/
|
|
297
|
+
interface AiCommandExposure {
|
|
298
|
+
/** Expose this command to the AI agent as a callable tool. Opt-in. */
|
|
299
|
+
aiExposed?: boolean;
|
|
300
|
+
/** JSON schema for the tool's args (defaults to an empty object schema). */
|
|
301
|
+
aiInputSchema?: {
|
|
302
|
+
type: 'object';
|
|
303
|
+
properties: Record<string, AiJsonSchema>;
|
|
304
|
+
required?: readonly string[];
|
|
305
|
+
};
|
|
306
|
+
/** Risk level surfaced to the agent + consent (default `medium`). */
|
|
307
|
+
aiRisk?: AiRiskLevel;
|
|
308
|
+
/** AI scopes this command requires (checked against the plugin's grant; default none). */
|
|
309
|
+
aiScopes?: AiScope[];
|
|
310
|
+
/** Arg-taking AI invocation; falls back to `execute()` when absent. */
|
|
311
|
+
aiInvoke?: (args: Record<string, unknown>) => unknown | Promise<unknown>;
|
|
312
|
+
}
|
|
64
313
|
interface ViewContribution {
|
|
65
314
|
/** Unique view type identifier */
|
|
66
315
|
type: string;
|
|
@@ -77,7 +326,7 @@ interface ViewProps {
|
|
|
77
326
|
nodeId: string;
|
|
78
327
|
schemaId: string;
|
|
79
328
|
}
|
|
80
|
-
interface CommandContribution {
|
|
329
|
+
interface CommandContribution extends AiCommandExposure {
|
|
81
330
|
/** Unique command ID */
|
|
82
331
|
id: string;
|
|
83
332
|
/** Display name */
|
|
@@ -143,6 +392,24 @@ interface EditorContribution {
|
|
|
143
392
|
/** Priority for extension ordering (lower = earlier, default: 100) */
|
|
144
393
|
priority?: number;
|
|
145
394
|
}
|
|
395
|
+
/**
|
|
396
|
+
* Status bar item contributed by a plugin (0166 workbench).
|
|
397
|
+
* Left side = workspace scope; right side = view scope.
|
|
398
|
+
*/
|
|
399
|
+
interface StatusBarContribution {
|
|
400
|
+
/** Unique item ID */
|
|
401
|
+
id: string;
|
|
402
|
+
/** Static text, or a getter polled on render */
|
|
403
|
+
text: string | (() => string);
|
|
404
|
+
/** Which side of the status bar (default 'left') */
|
|
405
|
+
side?: 'left' | 'right';
|
|
406
|
+
/** Tooltip */
|
|
407
|
+
tooltip?: string;
|
|
408
|
+
/** Command id (CommandRegistry) to run on click */
|
|
409
|
+
command?: string;
|
|
410
|
+
/** Priority within the side (lower = earlier) */
|
|
411
|
+
priority?: number;
|
|
412
|
+
}
|
|
146
413
|
interface SidebarContribution {
|
|
147
414
|
/** Unique item ID */
|
|
148
415
|
id: string;
|
|
@@ -163,6 +430,73 @@ interface SidebarContribution {
|
|
|
163
430
|
/** Optional panel component to render */
|
|
164
431
|
panel?: ComponentType;
|
|
165
432
|
}
|
|
433
|
+
/**
|
|
434
|
+
* Dashboard widget contribution (0162).
|
|
435
|
+
*
|
|
436
|
+
* Mirrors WidgetDefinition from @xnetjs/dashboard structurally (kept
|
|
437
|
+
* dependency-free here, like ViewContribution). The host assigns the trust
|
|
438
|
+
* tier from the plugin's install source — plugins never self-declare it —
|
|
439
|
+
* and registers the widget into the dashboard WidgetRegistry.
|
|
440
|
+
*/
|
|
441
|
+
interface WidgetContribution {
|
|
442
|
+
/** Widget registry key, e.g. 'com.example.burndown' (plugin-scoped) */
|
|
443
|
+
type: string;
|
|
444
|
+
/** Display name shown in the widget picker */
|
|
445
|
+
name: string;
|
|
446
|
+
/** Lucide icon name or component */
|
|
447
|
+
icon?: string | ComponentType;
|
|
448
|
+
/** Short description for the picker */
|
|
449
|
+
description?: string;
|
|
450
|
+
/** Config fields driving the auto-generated editor */
|
|
451
|
+
configFields?: WidgetContributionConfigField[];
|
|
452
|
+
/** Default + minimum tile size in 12-column grid units */
|
|
453
|
+
defaultSize: {
|
|
454
|
+
w: number;
|
|
455
|
+
h: number;
|
|
456
|
+
minW?: number;
|
|
457
|
+
minH?: number;
|
|
458
|
+
};
|
|
459
|
+
/** Sensible defaults so a freshly added widget renders immediately */
|
|
460
|
+
getStubConfig: (ctx: {
|
|
461
|
+
schemas: string[];
|
|
462
|
+
}) => {
|
|
463
|
+
config: Record<string, unknown>;
|
|
464
|
+
query?: unknown;
|
|
465
|
+
};
|
|
466
|
+
/** The renderer (runs in the tier-appropriate host) */
|
|
467
|
+
component: ComponentType<WidgetContributionProps>;
|
|
468
|
+
}
|
|
469
|
+
interface WidgetContributionConfigField {
|
|
470
|
+
key: string;
|
|
471
|
+
label: string;
|
|
472
|
+
type: 'property-select' | 'select' | 'number' | 'checkbox' | 'text' | 'color';
|
|
473
|
+
options?: Array<{
|
|
474
|
+
label: string;
|
|
475
|
+
value: string;
|
|
476
|
+
}>;
|
|
477
|
+
required?: boolean;
|
|
478
|
+
description?: string;
|
|
479
|
+
defaultValue?: unknown;
|
|
480
|
+
}
|
|
481
|
+
interface WidgetContributionProps {
|
|
482
|
+
config: Record<string, unknown>;
|
|
483
|
+
data: {
|
|
484
|
+
rows: Array<Record<string, unknown> & {
|
|
485
|
+
id: string;
|
|
486
|
+
}>;
|
|
487
|
+
aggregates: unknown;
|
|
488
|
+
queries: Record<string, Array<Record<string, unknown> & {
|
|
489
|
+
id: string;
|
|
490
|
+
}>>;
|
|
491
|
+
loading: boolean;
|
|
492
|
+
error: Error | null;
|
|
493
|
+
};
|
|
494
|
+
width: number;
|
|
495
|
+
height: number;
|
|
496
|
+
variables: Readonly<Record<string, unknown>>;
|
|
497
|
+
onConfigChange?: (next: Record<string, unknown>) => void;
|
|
498
|
+
onOpenNode?: (nodeId: string, schemaId: string) => void;
|
|
499
|
+
}
|
|
166
500
|
interface PropertyHandlerContribution {
|
|
167
501
|
/** Property type this handler manages */
|
|
168
502
|
type: string;
|
|
@@ -228,6 +562,128 @@ interface SchemaContribution {
|
|
|
228
562
|
/** The schema definition */
|
|
229
563
|
schema: unknown;
|
|
230
564
|
}
|
|
565
|
+
type CanvasPreviewTier = 'summary' | 'thumbnail' | 'shell' | 'live';
|
|
566
|
+
type CanvasIngestInputKind = 'url' | 'file' | 'data-transfer' | 'text' | 'node' | 'custom';
|
|
567
|
+
type CanvasToolGroup = 'select' | 'create' | 'connect' | 'annotate' | 'layout' | 'custom';
|
|
568
|
+
type CanvasLayoutScope = 'selection' | 'frame' | 'canvas' | 'query-results' | 'mind-map' | 'custom';
|
|
569
|
+
type CanvasInspectorPlacement = 'popover' | 'side-panel' | 'bottom-panel';
|
|
570
|
+
type CanvasTemplateCategory = 'planning' | 'research' | 'operations' | 'diagramming' | 'erp' | 'custom';
|
|
571
|
+
type CanvasContributionPermission = 'canvas.read' | 'canvas.write' | 'canvas.ingest' | 'canvas.render' | 'canvas.layout' | 'network' | 'storage' | 'clipboard';
|
|
572
|
+
interface CanvasContributionBase {
|
|
573
|
+
/** Unique contribution ID, preferably plugin-scoped */
|
|
574
|
+
id: string;
|
|
575
|
+
/** Contribution discriminator for validation and registry routing */
|
|
576
|
+
type: string;
|
|
577
|
+
/** Display name shown in canvas menus, toolbars, or inspectors */
|
|
578
|
+
name?: string;
|
|
579
|
+
/** Short help text for command palettes and plugin management */
|
|
580
|
+
description?: string;
|
|
581
|
+
/** Lucide icon name or plugin-owned icon token */
|
|
582
|
+
icon?: string;
|
|
583
|
+
/** Lower values win when multiple plugin contributions match */
|
|
584
|
+
priority?: number;
|
|
585
|
+
/** Fine-grained capabilities requested by this canvas contribution */
|
|
586
|
+
permissions?: CanvasContributionPermission[];
|
|
587
|
+
}
|
|
588
|
+
interface CanvasCardContribution extends CanvasContributionBase {
|
|
589
|
+
type: 'canvas.card';
|
|
590
|
+
/** Source schema this card knows how to render */
|
|
591
|
+
schemaId?: string;
|
|
592
|
+
/** External-reference provider ID, such as youtube, spotify, github, or crm */
|
|
593
|
+
provider?: string;
|
|
594
|
+
/** Canvas object kinds supported by this card */
|
|
595
|
+
canvasKinds?: string[];
|
|
596
|
+
/** LOD tiers this card can satisfy */
|
|
597
|
+
previewTiers?: CanvasPreviewTier[];
|
|
598
|
+
/** Sandboxed renderer module/function ID */
|
|
599
|
+
rendererEntrypoint: string;
|
|
600
|
+
/** Optional deterministic thumbnail/summary entrypoint */
|
|
601
|
+
previewEntrypoint?: string;
|
|
602
|
+
/** Human-readable fallback label when renderer is unavailable */
|
|
603
|
+
fallbackLabel?: string;
|
|
604
|
+
}
|
|
605
|
+
interface CanvasIngestorContribution extends CanvasContributionBase {
|
|
606
|
+
type: 'canvas.ingestor';
|
|
607
|
+
input: CanvasIngestInputKind;
|
|
608
|
+
/** MIME types accepted by file/data-transfer ingestors */
|
|
609
|
+
mimeTypes?: string[];
|
|
610
|
+
/** File extensions accepted by file ingestors */
|
|
611
|
+
fileExtensions?: string[];
|
|
612
|
+
/** URL patterns or provider tokens matched by URL ingestors */
|
|
613
|
+
urlPatterns?: string[];
|
|
614
|
+
/** Sandboxed matcher entrypoint */
|
|
615
|
+
matchEntrypoint: string;
|
|
616
|
+
/** Sandboxed ingestion entrypoint */
|
|
617
|
+
ingestEntrypoint: string;
|
|
618
|
+
}
|
|
619
|
+
interface CanvasToolContribution extends CanvasContributionBase {
|
|
620
|
+
type: 'canvas.tool';
|
|
621
|
+
group?: CanvasToolGroup;
|
|
622
|
+
keybinding?: string;
|
|
623
|
+
cursor?: string;
|
|
624
|
+
/** Sandboxed activation entrypoint that returns a tool controller */
|
|
625
|
+
activationEntrypoint: string;
|
|
626
|
+
}
|
|
627
|
+
interface CanvasLayoutContribution extends CanvasContributionBase {
|
|
628
|
+
type: 'canvas.layout';
|
|
629
|
+
scope: CanvasLayoutScope;
|
|
630
|
+
supportedKinds?: string[];
|
|
631
|
+
supportedSchemas?: string[];
|
|
632
|
+
/** Sandboxed layout function entrypoint */
|
|
633
|
+
applyEntrypoint: string;
|
|
634
|
+
}
|
|
635
|
+
interface CanvasEdgeContribution extends CanvasContributionBase {
|
|
636
|
+
type: 'canvas.edge';
|
|
637
|
+
label: string;
|
|
638
|
+
directed: boolean;
|
|
639
|
+
allowedSourceSchemas?: string[];
|
|
640
|
+
allowedTargetSchemas?: string[];
|
|
641
|
+
style?: 'solid' | 'dashed' | 'dotted';
|
|
642
|
+
}
|
|
643
|
+
interface CanvasInspectorContribution extends CanvasContributionBase {
|
|
644
|
+
type: 'canvas.inspector';
|
|
645
|
+
placement: CanvasInspectorPlacement;
|
|
646
|
+
supportedKinds?: string[];
|
|
647
|
+
supportedSchemas?: string[];
|
|
648
|
+
supportedProviders?: string[];
|
|
649
|
+
/** Sandboxed panel renderer entrypoint */
|
|
650
|
+
panelEntrypoint: string;
|
|
651
|
+
}
|
|
652
|
+
interface CanvasTemplateContribution extends CanvasContributionBase {
|
|
653
|
+
type: 'canvas.template';
|
|
654
|
+
category: CanvasTemplateCategory;
|
|
655
|
+
tags?: string[];
|
|
656
|
+
/** Sandboxed template instantiation entrypoint */
|
|
657
|
+
instantiateEntrypoint: string;
|
|
658
|
+
/** Optional preview renderer entrypoint */
|
|
659
|
+
previewEntrypoint?: string;
|
|
660
|
+
}
|
|
661
|
+
type CanvasContribution = CanvasCardContribution | CanvasIngestorContribution | CanvasToolContribution | CanvasLayoutContribution | CanvasEdgeContribution | CanvasInspectorContribution | CanvasTemplateContribution;
|
|
662
|
+
/**
|
|
663
|
+
* Importer contribution (exploration 0189).
|
|
664
|
+
*
|
|
665
|
+
* A data-export / source importer — e.g. an Instagram or YouTube archive
|
|
666
|
+
* importer. Mirrors `@xnetjs/social`'s `SocialImportAdapter` *structurally* so
|
|
667
|
+
* the first-party social adapters can register through the plugin system
|
|
668
|
+
* without `@xnetjs/plugins` depending on `@xnetjs/social` (dependency direction
|
|
669
|
+
* stays social → plugins). The `adapter` is opaque to the registry; the consumer
|
|
670
|
+
* (the import flow) casts it to its known importer shape. This is the same
|
|
671
|
+
* "defined now, consumed later" pattern as the canvas contributions.
|
|
672
|
+
*/
|
|
673
|
+
interface ImporterContribution {
|
|
674
|
+
/** Unique importer ID, preferably plugin-scoped (e.g. 'fyi.xnet.import.instagram'). */
|
|
675
|
+
id: string;
|
|
676
|
+
/** Source platform/system this importer handles (e.g. 'instagram', 'youtube'). */
|
|
677
|
+
platform: string;
|
|
678
|
+
/** Importer version. */
|
|
679
|
+
version: string;
|
|
680
|
+
/** Human-readable label for the import picker. */
|
|
681
|
+
name?: string;
|
|
682
|
+
/** Lucide icon name. */
|
|
683
|
+
icon?: string;
|
|
684
|
+
/** The importer adapter implementation (structurally a `SocialImportAdapter`). */
|
|
685
|
+
adapter: unknown;
|
|
686
|
+
}
|
|
231
687
|
/**
|
|
232
688
|
* A registry for typed contributions with change notifications
|
|
233
689
|
*/
|
|
@@ -252,19 +708,151 @@ declare class TypedRegistry<T extends {
|
|
|
252
708
|
*/
|
|
253
709
|
declare class ContributionRegistry {
|
|
254
710
|
readonly views: TypedRegistry<ViewContribution>;
|
|
711
|
+
readonly widgets: TypedRegistry<WidgetContribution>;
|
|
255
712
|
readonly commands: TypedRegistry<CommandContribution>;
|
|
256
713
|
readonly slashCommands: TypedRegistry<SlashCommandContribution>;
|
|
257
714
|
readonly sidebar: TypedRegistry<SidebarContribution>;
|
|
715
|
+
readonly statusBar: TypedRegistry<StatusBarContribution>;
|
|
258
716
|
readonly editor: TypedRegistry<EditorContribution>;
|
|
259
717
|
readonly propertyHandlers: TypedRegistry<PropertyHandlerContribution>;
|
|
260
718
|
readonly blocks: TypedRegistry<BlockContribution>;
|
|
261
719
|
readonly settings: TypedRegistry<SettingContribution>;
|
|
720
|
+
readonly canvasCards: TypedRegistry<CanvasCardContribution>;
|
|
721
|
+
readonly canvasIngestors: TypedRegistry<CanvasIngestorContribution>;
|
|
722
|
+
readonly canvasTools: TypedRegistry<CanvasToolContribution>;
|
|
723
|
+
readonly canvasLayouts: TypedRegistry<CanvasLayoutContribution>;
|
|
724
|
+
readonly canvasEdges: TypedRegistry<CanvasEdgeContribution>;
|
|
725
|
+
readonly canvasInspectors: TypedRegistry<CanvasInspectorContribution>;
|
|
726
|
+
readonly canvasTemplates: TypedRegistry<CanvasTemplateContribution>;
|
|
727
|
+
readonly importers: TypedRegistry<ImporterContribution>;
|
|
728
|
+
readonly mentionProviders: TypedRegistry<MentionProviderContribution>;
|
|
729
|
+
readonly agentTools: TypedRegistry<AgentToolContribution>;
|
|
262
730
|
/**
|
|
263
731
|
* Clear all registries (for cleanup/testing)
|
|
264
732
|
*/
|
|
265
733
|
clear(): void;
|
|
266
734
|
}
|
|
267
735
|
|
|
736
|
+
/**
|
|
737
|
+
* Canvas plugin permission policy helpers.
|
|
738
|
+
*/
|
|
739
|
+
|
|
740
|
+
type CanvasPluginPermissionDecisionStatus = 'allowed' | 'prompt-required' | 'blocked';
|
|
741
|
+
type CanvasPluginPromptMode = 'allow-once' | 'allow-workspace' | 'deny';
|
|
742
|
+
type CanvasPluginWorkspacePolicy = {
|
|
743
|
+
allowUnknownPlugins?: boolean;
|
|
744
|
+
trustedPluginIds?: string[];
|
|
745
|
+
blockedPluginIds?: string[];
|
|
746
|
+
allowedPermissions?: CanvasContributionPermission[] | '*';
|
|
747
|
+
blockedPermissions?: CanvasContributionPermission[];
|
|
748
|
+
promptPermissions?: CanvasContributionPermission[];
|
|
749
|
+
allowedNetworkDomains?: string[];
|
|
750
|
+
blockedNetworkDomains?: string[];
|
|
751
|
+
};
|
|
752
|
+
type CanvasPluginPermissionGateInput = {
|
|
753
|
+
pluginId: string;
|
|
754
|
+
contributionId: string;
|
|
755
|
+
contributionName?: string;
|
|
756
|
+
requestedPermissions?: CanvasContributionPermission[];
|
|
757
|
+
requestedNetworkDomains?: string[];
|
|
758
|
+
policy?: CanvasPluginWorkspacePolicy | null;
|
|
759
|
+
};
|
|
760
|
+
type CanvasPluginPermissionPromptOption = {
|
|
761
|
+
mode: CanvasPluginPromptMode;
|
|
762
|
+
label: string;
|
|
763
|
+
description: string;
|
|
764
|
+
persistsDecision: boolean;
|
|
765
|
+
};
|
|
766
|
+
type CanvasPluginPermissionPrompt = {
|
|
767
|
+
pluginId: string;
|
|
768
|
+
contributionId: string;
|
|
769
|
+
title: string;
|
|
770
|
+
message: string;
|
|
771
|
+
requestedPermissions: CanvasContributionPermission[];
|
|
772
|
+
requestedNetworkDomains: string[];
|
|
773
|
+
options: CanvasPluginPermissionPromptOption[];
|
|
774
|
+
};
|
|
775
|
+
type CanvasPluginPermissionGateDecision = {
|
|
776
|
+
status: CanvasPluginPermissionDecisionStatus;
|
|
777
|
+
allowed: boolean;
|
|
778
|
+
prompt: CanvasPluginPermissionPrompt | null;
|
|
779
|
+
grantedPermissions: CanvasContributionPermission[];
|
|
780
|
+
pendingPermissions: CanvasContributionPermission[];
|
|
781
|
+
blockedPermissions: CanvasContributionPermission[];
|
|
782
|
+
blockedNetworkDomains: string[];
|
|
783
|
+
pendingNetworkDomains: string[];
|
|
784
|
+
issues: string[];
|
|
785
|
+
};
|
|
786
|
+
declare function evaluateCanvasPluginPermissionGate(input: CanvasPluginPermissionGateInput): CanvasPluginPermissionGateDecision;
|
|
787
|
+
declare function createCanvasPluginPermissionPrompt(input: {
|
|
788
|
+
pluginId: string;
|
|
789
|
+
contributionId: string;
|
|
790
|
+
contributionName?: string;
|
|
791
|
+
requestedPermissions: CanvasContributionPermission[];
|
|
792
|
+
requestedNetworkDomains: string[];
|
|
793
|
+
}): CanvasPluginPermissionPrompt;
|
|
794
|
+
declare function normalizeCanvasPluginWorkspacePolicy(policy?: CanvasPluginWorkspacePolicy | null): Required<CanvasPluginWorkspacePolicy>;
|
|
795
|
+
|
|
796
|
+
/**
|
|
797
|
+
* @xnetjs/plugins — FeatureModule (exploration 0189).
|
|
798
|
+
*
|
|
799
|
+
* A `FeatureModule` is the uniform shape every first-party integration and
|
|
800
|
+
* community plugin can take: a superset of `XNetExtension` (the client
|
|
801
|
+
* contributions) that also **declares its capability surface** and, by
|
|
802
|
+
* convention via a shared `id`, links to a hub-side feature mounted through
|
|
803
|
+
* `@xnetjs/hub`'s feature registry.
|
|
804
|
+
*
|
|
805
|
+
* The client stays hub-free on purpose: `hub` here is a *declarative pointer*
|
|
806
|
+
* (an id), not server code. The actual hub routes/secrets live in the hub
|
|
807
|
+
* package's `HubFeature`, and the hub's capability/secret broker is what
|
|
808
|
+
* enforces `capabilities.secrets`. This keeps the dependency direction clean
|
|
809
|
+
* (no `@xnetjs/plugins` → `@xnetjs/hub` edge) while letting one manifest
|
|
810
|
+
* document the full two-sided surface — billing, GitHub, importers, and
|
|
811
|
+
* eventually core surfaces all expressed the same way.
|
|
812
|
+
*/
|
|
813
|
+
|
|
814
|
+
/**
|
|
815
|
+
* The capability surface a module declares. The install UI renders this as a
|
|
816
|
+
* consent dialog; the hub broker injects only the declared `secrets`; the
|
|
817
|
+
* client sandbox exposes only the declared `endowments`.
|
|
818
|
+
*/
|
|
819
|
+
interface ModuleCapabilities {
|
|
820
|
+
/**
|
|
821
|
+
* Env secret keys the module's hub half is permitted to read. Supports exact
|
|
822
|
+
* keys (`STRIPE_SECRET_KEY`) and `PREFIX_*` globs (`BTCPAY_*`). First-party
|
|
823
|
+
* tier only — community modules never receive raw secrets.
|
|
824
|
+
*/
|
|
825
|
+
secrets?: string[];
|
|
826
|
+
/** Schema IRIs the module may write. */
|
|
827
|
+
schemaWrite?: string[];
|
|
828
|
+
/** Schema IRIs the module may read. */
|
|
829
|
+
schemaRead?: string[];
|
|
830
|
+
/** Network domains the module may reach (allowlist), e.g. for unfurl/proxy. */
|
|
831
|
+
network?: string[];
|
|
832
|
+
/** Host APIs the client sandbox should expose to the module's code. */
|
|
833
|
+
endowments?: string[];
|
|
834
|
+
}
|
|
835
|
+
/**
|
|
836
|
+
* A two-sided feature module. Inherits all client `contributes` (including the
|
|
837
|
+
* new `importers` point) from `XNetExtension`, and adds the capability
|
|
838
|
+
* declaration + the hub linkage.
|
|
839
|
+
*/
|
|
840
|
+
interface FeatureModule extends XNetExtension {
|
|
841
|
+
/** Declared capability surface (client + hub). The hub broker enforces `secrets`. */
|
|
842
|
+
capabilities?: ModuleCapabilities;
|
|
843
|
+
/**
|
|
844
|
+
* Declarative pointer to a hub-side feature. By convention the hub feature is
|
|
845
|
+
* registered under the same `id` and mounted at `/x/<featureId>` (or, for the
|
|
846
|
+
* bundled first-party features, at their legacy path). Absence means the
|
|
847
|
+
* module is client-only.
|
|
848
|
+
*/
|
|
849
|
+
hub?: {
|
|
850
|
+
featureId: string;
|
|
851
|
+
};
|
|
852
|
+
}
|
|
853
|
+
/** Define a feature module with type checking (mirrors `defineExtension`). */
|
|
854
|
+
declare function defineFeatureModule(module: FeatureModule): FeatureModule;
|
|
855
|
+
|
|
268
856
|
/**
|
|
269
857
|
* NodeStore middleware chain for pre/post change hooks
|
|
270
858
|
*/
|
|
@@ -369,6 +957,8 @@ interface ExtensionContext {
|
|
|
369
957
|
registerSchema(schema: unknown): Disposable$1;
|
|
370
958
|
/** Register a custom view type */
|
|
371
959
|
registerView(view: ViewContribution): Disposable$1;
|
|
960
|
+
/** Register a dashboard widget (trust tier assigned by the host) */
|
|
961
|
+
registerWidget(widget: WidgetContribution): Disposable$1;
|
|
372
962
|
/** Register a property type handler */
|
|
373
963
|
registerPropertyHandler(type: string, handler: PropertyHandlerContribution['handler']): Disposable$1;
|
|
374
964
|
/** Register a command */
|
|
@@ -381,6 +971,26 @@ interface ExtensionContext {
|
|
|
381
971
|
registerSlashCommand(cmd: SlashCommandContribution): Disposable$1;
|
|
382
972
|
/** Register a custom block type */
|
|
383
973
|
registerBlockType(block: BlockContribution): Disposable$1;
|
|
974
|
+
/** Register a canvas card renderer descriptor */
|
|
975
|
+
registerCanvasCard(card: CanvasCardContribution): Disposable$1;
|
|
976
|
+
/** Register a canvas ingestor descriptor */
|
|
977
|
+
registerCanvasIngestor(ingestor: CanvasIngestorContribution): Disposable$1;
|
|
978
|
+
/** Register a canvas tool descriptor */
|
|
979
|
+
registerCanvasTool(tool: CanvasToolContribution): Disposable$1;
|
|
980
|
+
/** Register a canvas layout descriptor */
|
|
981
|
+
registerCanvasLayout(layout: CanvasLayoutContribution): Disposable$1;
|
|
982
|
+
/** Register a canvas edge relationship descriptor */
|
|
983
|
+
registerCanvasEdge(edge: CanvasEdgeContribution): Disposable$1;
|
|
984
|
+
/** Register a canvas inspector descriptor */
|
|
985
|
+
registerCanvasInspector(inspector: CanvasInspectorContribution): Disposable$1;
|
|
986
|
+
/** Register a canvas template descriptor */
|
|
987
|
+
registerCanvasTemplate(template: CanvasTemplateContribution): Disposable$1;
|
|
988
|
+
/** Register a data-export / source importer (exploration 0189) */
|
|
989
|
+
registerImporter(importer: ImporterContribution): Disposable$1;
|
|
990
|
+
/** Register a mention/typeahead provider (exploration 0194) */
|
|
991
|
+
registerMentionProvider(provider: MentionProviderContribution): Disposable$1;
|
|
992
|
+
/** Register a model-facing agent tool (exploration 0196) */
|
|
993
|
+
registerAgentTool(tool: AgentToolContribution): Disposable$1;
|
|
384
994
|
/** Add middleware to NodeStore */
|
|
385
995
|
addMiddleware(middleware: NodeStoreMiddleware): Disposable$1;
|
|
386
996
|
/** Plugin-private storage */
|
|
@@ -398,6 +1008,13 @@ interface CreateContextOptions {
|
|
|
398
1008
|
middlewareChain?: {
|
|
399
1009
|
add(middleware: NodeStoreMiddleware): Disposable$1;
|
|
400
1010
|
};
|
|
1011
|
+
/**
|
|
1012
|
+
* Declared capability grant (exploration 0192). When present, the plugin's
|
|
1013
|
+
* `store` handle is wrapped so writes outside `schemaWrite` throw — turning the
|
|
1014
|
+
* declaration into an enforced gate at the one choke point a plugin can't
|
|
1015
|
+
* route around. Absent/empty → the store is handed through unguarded.
|
|
1016
|
+
*/
|
|
1017
|
+
capabilities?: ModuleCapabilities;
|
|
401
1018
|
}
|
|
402
1019
|
/**
|
|
403
1020
|
* Create an ExtensionContext for a plugin
|
|
@@ -408,6 +1025,29 @@ declare function createExtensionContext(options: CreateContextOptions): Extensio
|
|
|
408
1025
|
* Plugin manifest types and validation
|
|
409
1026
|
*/
|
|
410
1027
|
|
|
1028
|
+
/**
|
|
1029
|
+
* How a plugin is monetized (exploration 0196). `free` is the default when
|
|
1030
|
+
* `pricing` is absent. Paid plugins (`one-time`/`subscription`) are gated at
|
|
1031
|
+
* install by a license check (see `PluginRegistry.install`'s `checkLicense`).
|
|
1032
|
+
*/
|
|
1033
|
+
interface PluginPricing {
|
|
1034
|
+
/** `free` — no license required. `one-time`/`subscription` — license-gated. */
|
|
1035
|
+
mode: 'free' | 'one-time' | 'subscription';
|
|
1036
|
+
/** Price in integer minor units (e.g. cents). Omitted/0 for free. */
|
|
1037
|
+
amountMinor?: number;
|
|
1038
|
+
/** ISO-4217 currency code (e.g. `USD`). Required when `amountMinor` > 0. */
|
|
1039
|
+
currency?: string;
|
|
1040
|
+
/**
|
|
1041
|
+
* Who runs checkout: `managed` = the xNet marketplace via Stripe Connect (the
|
|
1042
|
+
* platform takes its fee); `byo` = the author hosts their own checkout and
|
|
1043
|
+
* mints their own license (xNet takes 0%). Default `managed`.
|
|
1044
|
+
*/
|
|
1045
|
+
billing?: 'managed' | 'byo';
|
|
1046
|
+
/** Free-trial length in days (subscriptions). */
|
|
1047
|
+
trialDays?: number;
|
|
1048
|
+
}
|
|
1049
|
+
/** True when a pricing descriptor denotes a paid plugin that needs a license. */
|
|
1050
|
+
declare function isPaidPricing(pricing: PluginPricing | undefined): boolean;
|
|
411
1051
|
/**
|
|
412
1052
|
* Plugin manifest - defines what a plugin provides and how it integrates
|
|
413
1053
|
*/
|
|
@@ -422,12 +1062,31 @@ interface XNetExtension {
|
|
|
422
1062
|
description?: string;
|
|
423
1063
|
/** Author name or organization */
|
|
424
1064
|
author?: string;
|
|
425
|
-
/** Minimum compatible xNet version */
|
|
1065
|
+
/** Minimum compatible xNet version (semver range, e.g. ">=0.6.0") */
|
|
426
1066
|
xnetVersion?: string;
|
|
427
1067
|
/** Platforms this plugin supports (default: all) */
|
|
428
1068
|
platforms?: Platform[];
|
|
429
1069
|
/** Permission declarations */
|
|
430
1070
|
permissions?: PluginPermissions;
|
|
1071
|
+
/**
|
|
1072
|
+
* Other plugins this one requires, as `{ '<pluginId>': '<versionRange>' }`
|
|
1073
|
+
* (exploration 0192). Resolved at install time — see `ecosystem/dependencies`.
|
|
1074
|
+
*/
|
|
1075
|
+
dependencies?: Record<string, string>;
|
|
1076
|
+
/**
|
|
1077
|
+
* SPDX license id (exploration 0196). Paid plugins must declare a license the
|
|
1078
|
+
* marketplace pre-approves — `FSL-1.1-MIT` / `FSL-1.1-Apache-2.0` (source-
|
|
1079
|
+
* available, auto-opens after 2 years) or an OSI id (`MIT`, `Apache-2.0`, …).
|
|
1080
|
+
* Defaults to `MIT` when absent.
|
|
1081
|
+
*/
|
|
1082
|
+
license?: string;
|
|
1083
|
+
/** How this plugin is monetized (exploration 0196). Absent = free. */
|
|
1084
|
+
pricing?: PluginPricing;
|
|
1085
|
+
/**
|
|
1086
|
+
* The publisher's DID. Supersedes the bare `author` string for paid plugins —
|
|
1087
|
+
* licenses, payouts, and provenance attach to this identity (exploration 0196).
|
|
1088
|
+
*/
|
|
1089
|
+
publisherDid?: string;
|
|
431
1090
|
/** Static contributions declared in manifest */
|
|
432
1091
|
contributes?: PluginContributions;
|
|
433
1092
|
/** Called when plugin is activated */
|
|
@@ -441,6 +1100,8 @@ interface XNetExtension {
|
|
|
441
1100
|
interface PluginContributions {
|
|
442
1101
|
schemas?: SchemaContribution[];
|
|
443
1102
|
views?: ViewContribution[];
|
|
1103
|
+
/** Dashboard widgets (0162); trust tier is host-assigned at registration */
|
|
1104
|
+
widgets?: WidgetContribution[];
|
|
444
1105
|
editorExtensions?: EditorContribution[];
|
|
445
1106
|
propertyHandlers?: PropertyHandlerContribution[];
|
|
446
1107
|
blocks?: BlockContribution[];
|
|
@@ -448,6 +1109,19 @@ interface PluginContributions {
|
|
|
448
1109
|
settings?: SettingContribution[];
|
|
449
1110
|
sidebarItems?: SidebarContribution[];
|
|
450
1111
|
slashCommands?: SlashCommandContribution[];
|
|
1112
|
+
canvasCards?: CanvasCardContribution[];
|
|
1113
|
+
canvasIngestors?: CanvasIngestorContribution[];
|
|
1114
|
+
canvasTools?: CanvasToolContribution[];
|
|
1115
|
+
canvasLayouts?: CanvasLayoutContribution[];
|
|
1116
|
+
canvasEdges?: CanvasEdgeContribution[];
|
|
1117
|
+
canvasInspectors?: CanvasInspectorContribution[];
|
|
1118
|
+
canvasTemplates?: CanvasTemplateContribution[];
|
|
1119
|
+
/** Data-export / source importers (exploration 0189). */
|
|
1120
|
+
importers?: ImporterContribution[];
|
|
1121
|
+
/** Mention/typeahead providers — extend `[[`/`#`/`@` (exploration 0194). */
|
|
1122
|
+
mentionProviders?: MentionProviderContribution[];
|
|
1123
|
+
/** Model-facing agent tools — what a Connector exposes (exploration 0196). */
|
|
1124
|
+
agentTools?: AgentToolContribution[];
|
|
451
1125
|
}
|
|
452
1126
|
declare class PluginValidationError extends Error {
|
|
453
1127
|
readonly issues: string[];
|
|
@@ -463,6 +1137,148 @@ declare function validateManifest(manifest: unknown): XNetExtension;
|
|
|
463
1137
|
*/
|
|
464
1138
|
declare function defineExtension(manifest: XNetExtension): XNetExtension;
|
|
465
1139
|
|
|
1140
|
+
/**
|
|
1141
|
+
* @xnetjs/plugins — importer resolution (exploration 0189).
|
|
1142
|
+
*
|
|
1143
|
+
* Consumer-side helpers for the `importers` contribution point: pull the adapter
|
|
1144
|
+
* objects out of plugin contributions, and merge them with a set of built-in
|
|
1145
|
+
* importers (deduped by id — a plugin-contributed importer overrides a built-in
|
|
1146
|
+
* with the same id). Kept generic and adapter-shape-agnostic so the social
|
|
1147
|
+
* import flow (or any importer host) can call it without `@xnetjs/plugins`
|
|
1148
|
+
* depending on `@xnetjs/social`.
|
|
1149
|
+
*/
|
|
1150
|
+
|
|
1151
|
+
/** The adapter objects carried by importer contributions (opaque to the registry). */
|
|
1152
|
+
declare function importerAdapters(contributions: readonly ImporterContribution[]): unknown[];
|
|
1153
|
+
/**
|
|
1154
|
+
* Merge built-in importer adapters with contributed ones, deduped by `id`. A
|
|
1155
|
+
* contributed importer with the same id as a built-in overrides it (so a plugin
|
|
1156
|
+
* can replace a first-party importer). The consumer casts the result to its own
|
|
1157
|
+
* importer-adapter type.
|
|
1158
|
+
*/
|
|
1159
|
+
declare function resolveImporters<A extends {
|
|
1160
|
+
id: string;
|
|
1161
|
+
}>(builtIns: readonly A[], contributed: readonly A[]): A[];
|
|
1162
|
+
|
|
1163
|
+
/**
|
|
1164
|
+
* Fake canvas plugin fixtures for CRM, ERP, and media-provider cards.
|
|
1165
|
+
*/
|
|
1166
|
+
|
|
1167
|
+
type CanvasPluginFixtureKind = 'crm' | 'erp' | 'media-provider';
|
|
1168
|
+
type CanvasPluginFixtureCardSample = {
|
|
1169
|
+
id: string;
|
|
1170
|
+
pluginId: string;
|
|
1171
|
+
contributionId: string;
|
|
1172
|
+
title: string;
|
|
1173
|
+
subtitle: string;
|
|
1174
|
+
schemaId?: `xnet://${string}/${string}`;
|
|
1175
|
+
provider?: string;
|
|
1176
|
+
canvasKind: string;
|
|
1177
|
+
previewTier: 'summary' | 'thumbnail' | 'shell' | 'live';
|
|
1178
|
+
properties: Record<string, unknown>;
|
|
1179
|
+
};
|
|
1180
|
+
type CanvasPluginFixture = {
|
|
1181
|
+
kind: CanvasPluginFixtureKind;
|
|
1182
|
+
manifest: XNetExtension;
|
|
1183
|
+
sampleCards: CanvasPluginFixtureCardSample[];
|
|
1184
|
+
};
|
|
1185
|
+
declare const CRM_CANVAS_PLUGIN_FIXTURE: CanvasPluginFixture;
|
|
1186
|
+
declare const ERP_CANVAS_PLUGIN_FIXTURE: CanvasPluginFixture;
|
|
1187
|
+
declare const MEDIA_PROVIDER_CANVAS_PLUGIN_FIXTURE: CanvasPluginFixture;
|
|
1188
|
+
declare const CANVAS_PLUGIN_FIXTURES: CanvasPluginFixture[];
|
|
1189
|
+
declare function getCanvasPluginFixture(kind: CanvasPluginFixtureKind): CanvasPluginFixture | undefined;
|
|
1190
|
+
declare function createCanvasPluginFixtureManifests(): XNetExtension[];
|
|
1191
|
+
declare function createCanvasPluginFixtureCards(): CanvasPluginFixtureCardSample[];
|
|
1192
|
+
|
|
1193
|
+
/**
|
|
1194
|
+
* Sample ERP canvas prototype built from the ERP canvas plugin fixture.
|
|
1195
|
+
*/
|
|
1196
|
+
|
|
1197
|
+
type CanvasErpPrototypeEntityKind = 'purchase-order' | 'inventory-item';
|
|
1198
|
+
type CanvasErpPrototypeRisk = 'low' | 'medium' | 'high';
|
|
1199
|
+
type CanvasErpPrototypeStatus = 'awaiting-shipment' | 'in-transit' | 'qa-hold' | 'stockout-risk' | 'healthy' | 'receiving';
|
|
1200
|
+
type CanvasErpPrototypeLayoutKind = 'supply-chain' | 'procurement-kanban' | 'inventory-risk-grid' | 'receiving-timeline';
|
|
1201
|
+
type CanvasErpPrototypeAuditOperation = 'created' | 'moved' | 'resized' | 'field-updated' | 'bulk-updated' | 'synced';
|
|
1202
|
+
type CanvasErpPrototypeAuditSource = 'user' | 'plugin' | 'external-system';
|
|
1203
|
+
type CanvasErpPrototypeRect = {
|
|
1204
|
+
readonly x: number;
|
|
1205
|
+
readonly y: number;
|
|
1206
|
+
readonly width: number;
|
|
1207
|
+
readonly height: number;
|
|
1208
|
+
};
|
|
1209
|
+
type CanvasErpPrototypeCard = Omit<CanvasPluginFixtureCardSample, 'properties'> & {
|
|
1210
|
+
readonly sourceNodeId: `xnet://fixtures.erp/${string}`;
|
|
1211
|
+
readonly entityKind: CanvasErpPrototypeEntityKind;
|
|
1212
|
+
readonly status: CanvasErpPrototypeStatus;
|
|
1213
|
+
readonly risk: CanvasErpPrototypeRisk;
|
|
1214
|
+
readonly position: CanvasErpPrototypeRect;
|
|
1215
|
+
readonly tags: readonly string[];
|
|
1216
|
+
readonly properties: Record<string, unknown>;
|
|
1217
|
+
};
|
|
1218
|
+
type CanvasErpPrototypeEdge = {
|
|
1219
|
+
readonly id: string;
|
|
1220
|
+
readonly contributionId: 'erp.supplies' | 'erp.delayed-by';
|
|
1221
|
+
readonly sourceCardId: string;
|
|
1222
|
+
readonly targetCardId: string;
|
|
1223
|
+
readonly label: string;
|
|
1224
|
+
readonly directed: true;
|
|
1225
|
+
readonly style: 'solid' | 'dotted';
|
|
1226
|
+
readonly properties: Record<string, unknown>;
|
|
1227
|
+
};
|
|
1228
|
+
type CanvasErpPrototypeQueryPredicate = {
|
|
1229
|
+
readonly field: string;
|
|
1230
|
+
readonly operator: 'equals' | 'not-equals' | 'less-than' | 'greater-than' | 'contains';
|
|
1231
|
+
readonly value: unknown;
|
|
1232
|
+
};
|
|
1233
|
+
type CanvasErpPrototypeQueryFrame = {
|
|
1234
|
+
readonly id: string;
|
|
1235
|
+
readonly title: string;
|
|
1236
|
+
readonly layoutKind: CanvasErpPrototypeLayoutKind;
|
|
1237
|
+
readonly bounds: CanvasErpPrototypeRect;
|
|
1238
|
+
readonly schemaIds: readonly `xnet://${string}/${string}`[];
|
|
1239
|
+
readonly predicates: readonly CanvasErpPrototypeQueryPredicate[];
|
|
1240
|
+
readonly cardIds: readonly string[];
|
|
1241
|
+
};
|
|
1242
|
+
type CanvasErpPrototypeCommand = {
|
|
1243
|
+
readonly id: string;
|
|
1244
|
+
readonly label: string;
|
|
1245
|
+
readonly scope: 'single-card' | 'multi-card' | 'frame';
|
|
1246
|
+
readonly requiredPermissions: readonly ('canvas.read' | 'canvas.write' | 'canvas.layout')[];
|
|
1247
|
+
readonly supportedEntityKinds: readonly CanvasErpPrototypeEntityKind[];
|
|
1248
|
+
};
|
|
1249
|
+
type CanvasErpPrototypeAuditEntry = {
|
|
1250
|
+
readonly id: string;
|
|
1251
|
+
readonly cardId: string;
|
|
1252
|
+
readonly operation: CanvasErpPrototypeAuditOperation;
|
|
1253
|
+
readonly source: CanvasErpPrototypeAuditSource;
|
|
1254
|
+
readonly actor: string;
|
|
1255
|
+
readonly at: string;
|
|
1256
|
+
readonly summary: string;
|
|
1257
|
+
readonly batchId?: string;
|
|
1258
|
+
};
|
|
1259
|
+
type CanvasErpPrototypeRiskSummary = {
|
|
1260
|
+
readonly total: number;
|
|
1261
|
+
readonly low: number;
|
|
1262
|
+
readonly medium: number;
|
|
1263
|
+
readonly high: number;
|
|
1264
|
+
};
|
|
1265
|
+
type CanvasErpPrototypeScenario = {
|
|
1266
|
+
readonly id: string;
|
|
1267
|
+
readonly title: string;
|
|
1268
|
+
readonly pluginManifest: XNetExtension;
|
|
1269
|
+
readonly templateId: 'erp.procurement-war-room';
|
|
1270
|
+
readonly cards: readonly CanvasErpPrototypeCard[];
|
|
1271
|
+
readonly edges: readonly CanvasErpPrototypeEdge[];
|
|
1272
|
+
readonly queryFrames: readonly CanvasErpPrototypeQueryFrame[];
|
|
1273
|
+
readonly commands: readonly CanvasErpPrototypeCommand[];
|
|
1274
|
+
readonly auditEntries: readonly CanvasErpPrototypeAuditEntry[];
|
|
1275
|
+
readonly riskSummary: CanvasErpPrototypeRiskSummary;
|
|
1276
|
+
};
|
|
1277
|
+
declare function createCanvasErpPrototypeRiskSummary(cards: readonly CanvasErpPrototypeCard[]): CanvasErpPrototypeRiskSummary;
|
|
1278
|
+
declare function createCanvasErpPrototypeScenario(): CanvasErpPrototypeScenario;
|
|
1279
|
+
declare function getCanvasErpPrototypeCardsForFrame(scenario: CanvasErpPrototypeScenario, frameId: string): CanvasErpPrototypeCard[];
|
|
1280
|
+
declare function getCanvasErpPrototypeAuditEntriesForCard(scenario: CanvasErpPrototypeScenario, cardId: string): CanvasErpPrototypeAuditEntry[];
|
|
1281
|
+
|
|
466
1282
|
/**
|
|
467
1283
|
* Keyboard Shortcut Manager
|
|
468
1284
|
*
|
|
@@ -488,77 +1304,1590 @@ declare function defineExtension(manifest: XNetExtension): XNetExtension;
|
|
|
488
1304
|
* execute: () => console.log('Executed!')
|
|
489
1305
|
* })
|
|
490
1306
|
*
|
|
491
|
-
* // Attach to window
|
|
492
|
-
* window.addEventListener('keydown', (e) => manager.handleKeyDown(e))
|
|
493
|
-
* ```
|
|
1307
|
+
* // Attach to window
|
|
1308
|
+
* window.addEventListener('keydown', (e) => manager.handleKeyDown(e))
|
|
1309
|
+
* ```
|
|
1310
|
+
*/
|
|
1311
|
+
declare class ShortcutManager {
|
|
1312
|
+
private shortcuts;
|
|
1313
|
+
private enabled;
|
|
1314
|
+
/**
|
|
1315
|
+
* Register a command with a keyboard shortcut.
|
|
1316
|
+
*
|
|
1317
|
+
* @param command - Command with keybinding
|
|
1318
|
+
* @returns Disposable to unregister the shortcut
|
|
1319
|
+
*/
|
|
1320
|
+
register(command: CommandContribution): Disposable$1;
|
|
1321
|
+
/**
|
|
1322
|
+
* Unregister a command by ID.
|
|
1323
|
+
*/
|
|
1324
|
+
unregister(commandId: string): boolean;
|
|
1325
|
+
/**
|
|
1326
|
+
* Handle a keyboard event.
|
|
1327
|
+
*
|
|
1328
|
+
* @param event - Keyboard event
|
|
1329
|
+
* @returns True if a shortcut was triggered
|
|
1330
|
+
*/
|
|
1331
|
+
handleKeyDown(event: KeyboardEvent): boolean;
|
|
1332
|
+
/**
|
|
1333
|
+
* Enable or disable shortcut handling.
|
|
1334
|
+
*/
|
|
1335
|
+
setEnabled(enabled: boolean): void;
|
|
1336
|
+
/**
|
|
1337
|
+
* Check if shortcuts are enabled.
|
|
1338
|
+
*/
|
|
1339
|
+
isEnabled(): boolean;
|
|
1340
|
+
/**
|
|
1341
|
+
* Get all registered shortcuts.
|
|
1342
|
+
*/
|
|
1343
|
+
getAll(): CommandContribution[];
|
|
1344
|
+
/**
|
|
1345
|
+
* Get the shortcut for a command ID.
|
|
1346
|
+
*/
|
|
1347
|
+
getShortcut(commandId: string): string | undefined;
|
|
1348
|
+
/**
|
|
1349
|
+
* Format a keybinding for display (using platform-specific symbols).
|
|
1350
|
+
*/
|
|
1351
|
+
formatForDisplay(keybinding: string): string;
|
|
1352
|
+
/**
|
|
1353
|
+
* Normalize a keybinding string for consistent lookup.
|
|
1354
|
+
*/
|
|
1355
|
+
private normalize;
|
|
1356
|
+
/**
|
|
1357
|
+
* Convert normalized form back to display form.
|
|
1358
|
+
*/
|
|
1359
|
+
private denormalize;
|
|
1360
|
+
/**
|
|
1361
|
+
* Convert a keyboard event to a normalized string.
|
|
1362
|
+
*/
|
|
1363
|
+
private eventToString;
|
|
1364
|
+
/**
|
|
1365
|
+
* Clear all registered shortcuts.
|
|
1366
|
+
*/
|
|
1367
|
+
clear(): void;
|
|
1368
|
+
}
|
|
1369
|
+
/**
|
|
1370
|
+
* Get or create the global ShortcutManager instance.
|
|
1371
|
+
*/
|
|
1372
|
+
declare function getShortcutManager(): ShortcutManager;
|
|
1373
|
+
/**
|
|
1374
|
+
* Install the global shortcut manager on the window.
|
|
1375
|
+
* Call this once at app startup.
|
|
1376
|
+
*/
|
|
1377
|
+
declare function installShortcutHandler(): () => void;
|
|
1378
|
+
|
|
1379
|
+
/**
|
|
1380
|
+
* Workspace Command Registry
|
|
1381
|
+
*
|
|
1382
|
+
* One registry for every keyboard-driven verb in the workspace
|
|
1383
|
+
* (exploration 0161, phase 3). Generalizes ShortcutManager with:
|
|
1384
|
+
*
|
|
1385
|
+
* - **Scopes**: commands belong to a scope ('global', 'surface:grid',
|
|
1386
|
+
* 'task-focused', …). Surfaces activate their scope on focus/mount and
|
|
1387
|
+
* dispose on blur/unmount; only commands in active scopes fire. The most
|
|
1388
|
+
* recently activated scope wins key conflicts (global loses to all).
|
|
1389
|
+
* - **Single-key verbs**: Linear-style bindings ('s', 'a', 'p') that are
|
|
1390
|
+
* automatically suppressed while any input/textarea/contenteditable has
|
|
1391
|
+
* focus — modifier combos can opt into editors via `allowInInput`.
|
|
1392
|
+
* - **Chords**: 'g t'-style two-step sequences with a pending-step timeout.
|
|
1393
|
+
*
|
|
1394
|
+
* Surfaces register commands instead of owning their own key handling, so
|
|
1395
|
+
* the palette can list every available action with its binding.
|
|
1396
|
+
*/
|
|
1397
|
+
|
|
1398
|
+
type CommandScope = 'global' | (string & NonNullable<unknown>);
|
|
1399
|
+
interface CommandContext {
|
|
1400
|
+
/** The scope the command was resolved in */
|
|
1401
|
+
scope: CommandScope;
|
|
1402
|
+
/** The triggering keyboard event (absent when run from the palette) */
|
|
1403
|
+
event?: KeyboardEvent;
|
|
1404
|
+
}
|
|
1405
|
+
interface WorkspaceCommand {
|
|
1406
|
+
/** Unique id, e.g. 'task.setStatus' */
|
|
1407
|
+
id: string;
|
|
1408
|
+
/** Palette title, e.g. 'Change status…' */
|
|
1409
|
+
title: string;
|
|
1410
|
+
/** Scope this command belongs to (default 'global') */
|
|
1411
|
+
scope?: CommandScope;
|
|
1412
|
+
/**
|
|
1413
|
+
* Key binding: a single key ('s', '?'), a modifier combo ('Mod-K'),
|
|
1414
|
+
* or a space-separated chord ('g t'). Omit for palette-only commands.
|
|
1415
|
+
*/
|
|
1416
|
+
key?: string;
|
|
1417
|
+
/** Allow firing while an input/editor has focus (modifier combos only) */
|
|
1418
|
+
allowInInput?: boolean;
|
|
1419
|
+
/** Availability guard checked at dispatch and palette-listing time */
|
|
1420
|
+
when?: () => boolean;
|
|
1421
|
+
run: (context: CommandContext) => void | Promise<void>;
|
|
1422
|
+
}
|
|
1423
|
+
declare class CommandRegistry {
|
|
1424
|
+
private commands;
|
|
1425
|
+
/** Active scopes in activation order ('global' is always index 0) */
|
|
1426
|
+
private scopeStack;
|
|
1427
|
+
private pendingSteps;
|
|
1428
|
+
private pendingTimer;
|
|
1429
|
+
private enabled;
|
|
1430
|
+
register(command: WorkspaceCommand): Disposable$1;
|
|
1431
|
+
/**
|
|
1432
|
+
* Activate a scope (e.g. when a surface mounts or a task row gains
|
|
1433
|
+
* focus). Re-activating moves it to the top of the priority stack.
|
|
1434
|
+
*/
|
|
1435
|
+
activateScope(scope: CommandScope): Disposable$1;
|
|
1436
|
+
isScopeActive(scope: CommandScope): boolean;
|
|
1437
|
+
getActiveScopes(): CommandScope[];
|
|
1438
|
+
/** Commands available right now (active scope + passing when()) */
|
|
1439
|
+
getAvailableCommands(): WorkspaceCommand[];
|
|
1440
|
+
getAllCommands(): WorkspaceCommand[];
|
|
1441
|
+
/**
|
|
1442
|
+
* Commands declared in any of the given scopes (passing `when()`),
|
|
1443
|
+
* regardless of whether those scopes are currently active. Lets a
|
|
1444
|
+
* context-aware command menu surface, say, the focused-task verbs even
|
|
1445
|
+
* when its own input has stolen scope focus.
|
|
1446
|
+
*/
|
|
1447
|
+
commandsForScopes(scopes: readonly CommandScope[]): WorkspaceCommand[];
|
|
1448
|
+
getCommand(id: string): WorkspaceCommand | undefined;
|
|
1449
|
+
runCommand(id: string): Promise<boolean>;
|
|
1450
|
+
setEnabled(enabled: boolean): void;
|
|
1451
|
+
/**
|
|
1452
|
+
* Handle a keydown. Returns true when a command fired (or a chord step
|
|
1453
|
+
* was consumed); callers should attach exactly one handler per window.
|
|
1454
|
+
*/
|
|
1455
|
+
handleKeyDown(event: KeyboardEvent): boolean;
|
|
1456
|
+
/** Format a binding for display ('Mod-K' → '⌘K' on Mac). */
|
|
1457
|
+
formatForDisplay(binding: string): string;
|
|
1458
|
+
clear(): void;
|
|
1459
|
+
private clearPending;
|
|
1460
|
+
}
|
|
1461
|
+
declare function getCommandRegistry(): CommandRegistry;
|
|
1462
|
+
/**
|
|
1463
|
+
* Install the global command handler on the window.
|
|
1464
|
+
* Call once at app startup.
|
|
1465
|
+
*/
|
|
1466
|
+
declare function installCommandHandler(): () => void;
|
|
1467
|
+
|
|
1468
|
+
/**
|
|
1469
|
+
* Editor schema-skew guard for plugin contributions (exploration 0205).
|
|
1470
|
+
*
|
|
1471
|
+
* A plugin editor contribution whose TipTap extension is a Node or Mark changes
|
|
1472
|
+
* the PERSISTED document schema. Under Yjs collaboration, if some collaborators
|
|
1473
|
+
* have the plugin and others don't, ProseMirror silently drops the unknown
|
|
1474
|
+
* content and the corruption syncs without any error. Behavior-only extensions
|
|
1475
|
+
* (commands, keymaps, decorations, slash items) are skew-safe.
|
|
1476
|
+
*
|
|
1477
|
+
* This module classifies a plugin's editor contributions so the registry can
|
|
1478
|
+
* warn loudly in development. It mirrors `@xnetjs/editor`'s extension-tiers
|
|
1479
|
+
* classifier but lives here so the plugins package needs no editor dependency.
|
|
1480
|
+
*/
|
|
1481
|
+
|
|
1482
|
+
interface EditorSchemaRisk {
|
|
1483
|
+
/** The contribution id. */
|
|
1484
|
+
id: string;
|
|
1485
|
+
/** 'node' | 'mark' (the skew-sensitive kinds). */
|
|
1486
|
+
kind: string;
|
|
1487
|
+
/** The TipTap extension name. */
|
|
1488
|
+
name: string;
|
|
1489
|
+
}
|
|
1490
|
+
/** True if the extension defines persisted document schema (a Node or Mark). */
|
|
1491
|
+
declare function isSchemaDefiningExtension(ext: {
|
|
1492
|
+
type?: string;
|
|
1493
|
+
}): boolean;
|
|
1494
|
+
/**
|
|
1495
|
+
* Of a plugin's editor contributions, return those that add persisted schema
|
|
1496
|
+
* and therefore risk silent Yjs content loss across version skew. Empty array
|
|
1497
|
+
* means the contributions are skew-safe.
|
|
1498
|
+
*/
|
|
1499
|
+
declare function findEditorSchemaRisks(contributions: readonly EditorContribution[]): EditorSchemaRisk[];
|
|
1500
|
+
/**
|
|
1501
|
+
* Warn (in development) when a plugin's editor contributions add schema. Returns
|
|
1502
|
+
* the detected risks so callers can also gate or surface them.
|
|
1503
|
+
*/
|
|
1504
|
+
declare function warnOnEditorSchemaRisks(pluginId: string, contributions: readonly EditorContribution[]): EditorSchemaRisk[];
|
|
1505
|
+
|
|
1506
|
+
/**
|
|
1507
|
+
* @xnetjs/plugins — the Connector primitive (exploration 0196).
|
|
1508
|
+
*
|
|
1509
|
+
* A Connector is xNet's answer to the agent-native CLI (Printing Press / OpenClaw):
|
|
1510
|
+
* instead of giving the agent a credentialed shell, it syncs an external service
|
|
1511
|
+
* into governed XNet nodes and exposes agent-callable tools over them. It is a
|
|
1512
|
+
* `FeatureModule` subtype that bundles three things:
|
|
1513
|
+
*
|
|
1514
|
+
* 1. a `capabilities` manifest — `secrets` (held by the hub broker, never the
|
|
1515
|
+
* agent), `schemaWrite` (what it may materialize), `network` (where it may
|
|
1516
|
+
* reach);
|
|
1517
|
+
* 2. a server-side `sync` adapter that pulls the external API into nodes; and
|
|
1518
|
+
* 3. `agentTools` the model can call over the synced, policy-evaluated store.
|
|
1519
|
+
*
|
|
1520
|
+
* `defineConnector` produces the `FeatureModule` (so it installs, consents, and
|
|
1521
|
+
* ships through the marketplace like any plugin) plus the sync spec and tools.
|
|
1522
|
+
* The hub half is wired by convention under `<id>.sync` (see the hub
|
|
1523
|
+
* `connectorSyncFeature`). The guards are enforced by composition — `guardStore`,
|
|
1524
|
+
* `guardedFetch`, `scopedEnv`, the policy evaluator — not by new code here.
|
|
1525
|
+
*/
|
|
1526
|
+
|
|
1527
|
+
/** How often a connector re-syncs. `manual` = only on explicit/agent trigger. */
|
|
1528
|
+
type ConnectorCadence = 'manual' | 'hourly' | 'daily' | {
|
|
1529
|
+
everyMs: number;
|
|
1530
|
+
};
|
|
1531
|
+
/** The minimal node store surface a connector's `pull` writes through. */
|
|
1532
|
+
interface ConnectorStore {
|
|
1533
|
+
create(options: {
|
|
1534
|
+
schemaId: string;
|
|
1535
|
+
properties: Record<string, unknown>;
|
|
1536
|
+
}): Promise<{
|
|
1537
|
+
id: string;
|
|
1538
|
+
schemaId: string;
|
|
1539
|
+
}>;
|
|
1540
|
+
get(id: string): Promise<{
|
|
1541
|
+
schemaId: string;
|
|
1542
|
+
} | null>;
|
|
1543
|
+
update(id: string, options: {
|
|
1544
|
+
properties: Record<string, unknown>;
|
|
1545
|
+
}): Promise<unknown>;
|
|
1546
|
+
}
|
|
1547
|
+
/** A `fetch`-like the connector reaches the network through (host-allowlisted). */
|
|
1548
|
+
type ConnectorFetch = (input: string | {
|
|
1549
|
+
url: string;
|
|
1550
|
+
}, init?: unknown) => Promise<unknown>;
|
|
1551
|
+
/** Context handed to `pull`: scoped secrets, guarded fetch + store, target space. */
|
|
1552
|
+
interface ConnectorSyncContext {
|
|
1553
|
+
/** Broker-scoped env — only the keys declared in `capabilities.secrets`. */
|
|
1554
|
+
env: Record<string, string | undefined>;
|
|
1555
|
+
/** Guarded fetch — egress limited to `capabilities.network`. */
|
|
1556
|
+
fetch: ConnectorFetch;
|
|
1557
|
+
/** Guarded store — writes limited to `capabilities.schemaWrite`, space-stamped. */
|
|
1558
|
+
store: ConnectorStore;
|
|
1559
|
+
/** The target Space id every synced node is scoped to (the cascade boundary). */
|
|
1560
|
+
space: string;
|
|
1561
|
+
}
|
|
1562
|
+
interface ConnectorSyncResult {
|
|
1563
|
+
/** Number of nodes written this run. */
|
|
1564
|
+
written: number;
|
|
1565
|
+
[key: string]: unknown;
|
|
1566
|
+
}
|
|
1567
|
+
interface ConnectorSyncSpec {
|
|
1568
|
+
/** Schema IRIs this connector materializes (must be a subset of `schemaWrite`). */
|
|
1569
|
+
schemas: string[];
|
|
1570
|
+
/**
|
|
1571
|
+
* The relation property each synced node carries the target Space in (default
|
|
1572
|
+
* `space`). The runner stamps it so an author cannot forget — that stamp is
|
|
1573
|
+
* what makes the space cascade (and thus cross-contamination protection) hold.
|
|
1574
|
+
*/
|
|
1575
|
+
spaceProperty?: string;
|
|
1576
|
+
/** Re-sync cadence (default `manual`). */
|
|
1577
|
+
cadence?: ConnectorCadence;
|
|
1578
|
+
/** Pull external data into nodes. Runs hub-side with scoped secrets. */
|
|
1579
|
+
pull(ctx: ConnectorSyncContext): Promise<ConnectorSyncResult>;
|
|
1580
|
+
}
|
|
1581
|
+
interface ConnectorDefinition {
|
|
1582
|
+
/** Reverse-domain id, e.g. `dev.xnet.connector.slack`. */
|
|
1583
|
+
id: string;
|
|
1584
|
+
/** Human-readable name. */
|
|
1585
|
+
name: string;
|
|
1586
|
+
/** Semantic version (default `0.1.0`). */
|
|
1587
|
+
version?: string;
|
|
1588
|
+
author?: string;
|
|
1589
|
+
description?: string;
|
|
1590
|
+
/** The capability surface — enforced, not advisory. `network` is required. */
|
|
1591
|
+
capabilities: ModuleCapabilities & {
|
|
1592
|
+
schemaWrite: string[];
|
|
1593
|
+
network: string[];
|
|
1594
|
+
};
|
|
1595
|
+
/** Server-side sync adapter. */
|
|
1596
|
+
sync: ConnectorSyncSpec;
|
|
1597
|
+
/** Model-facing tools over the synced store. */
|
|
1598
|
+
agentTools?: AgentToolContribution[];
|
|
1599
|
+
}
|
|
1600
|
+
/** The product of {@link defineConnector}: a module plus its runnable parts. */
|
|
1601
|
+
interface DefinedConnector {
|
|
1602
|
+
/** The installable, consent-gated, marketplace-shippable feature module. */
|
|
1603
|
+
module: FeatureModule;
|
|
1604
|
+
/** The sync adapter (run by the hub `connectorSyncFeature`). */
|
|
1605
|
+
sync: ConnectorSyncSpec;
|
|
1606
|
+
/** The contributed agent tools. */
|
|
1607
|
+
agentTools: AgentToolContribution[];
|
|
1608
|
+
/** The original definition. */
|
|
1609
|
+
definition: ConnectorDefinition;
|
|
1610
|
+
}
|
|
1611
|
+
declare class ConnectorDefinitionError extends Error {
|
|
1612
|
+
constructor(message: string);
|
|
1613
|
+
}
|
|
1614
|
+
/**
|
|
1615
|
+
* Define a Connector. Validates the capability/sync coherence (every synced
|
|
1616
|
+
* schema is writable; a network host is declared) and produces a `FeatureModule`
|
|
1617
|
+
* whose `hub.featureId` points at the sync feature mounted under `<id>.sync`.
|
|
1618
|
+
*
|
|
1619
|
+
* @throws {ConnectorDefinitionError} when the definition is incoherent.
|
|
1620
|
+
*/
|
|
1621
|
+
declare function defineConnector(def: ConnectorDefinition): DefinedConnector;
|
|
1622
|
+
|
|
1623
|
+
/**
|
|
1624
|
+
* @xnetjs/plugins — plugin contributions as AI tools (exploration 0194 Phase 2).
|
|
1625
|
+
*
|
|
1626
|
+
* The AI agent can read/write the workspace (the `AiSurfaceService` tools), but
|
|
1627
|
+
* until now it could not invoke a *plugin command*. This exposes opted-in
|
|
1628
|
+
* commands as `AiToolDefinition`s with an `invoke`, so the agent's tool surface
|
|
1629
|
+
* grows with installed plugins — composable, the way MCP made the 2026 ecosystem.
|
|
1630
|
+
*
|
|
1631
|
+
* Opt-in is explicit (`aiExposed: true`) and capability-scoped (`aiScopes`): a
|
|
1632
|
+
* command the AI shouldn't touch simply never opts in, and a high-risk one is
|
|
1633
|
+
* surfaced as such so the agent/consent layer can gate it.
|
|
1634
|
+
*/
|
|
1635
|
+
|
|
1636
|
+
/** An `AiToolDefinition` that can actually be called. */
|
|
1637
|
+
type AiCallableTool = AiToolDefinition & {
|
|
1638
|
+
invoke: (args: Record<string, unknown>) => Promise<AiToolCallResult>;
|
|
1639
|
+
};
|
|
1640
|
+
/**
|
|
1641
|
+
* Wrap the opted-in plugin commands as capability-scoped, callable AI tools.
|
|
1642
|
+
* Only commands with `aiExposed: true` are included — exposure is never implicit.
|
|
1643
|
+
*/
|
|
1644
|
+
declare function contributionsAsAiTools(commands: readonly CommandContribution[]): AiCallableTool[];
|
|
1645
|
+
|
|
1646
|
+
/**
|
|
1647
|
+
* Validation helpers for AI surface mutation plans.
|
|
1648
|
+
*/
|
|
1649
|
+
|
|
1650
|
+
declare function createAiValidationResult(errors?: string[], warnings?: string[]): AiValidationResult;
|
|
1651
|
+
/**
|
|
1652
|
+
* Validate a serialized mutation plan before it can be previewed or applied.
|
|
1653
|
+
*/
|
|
1654
|
+
declare function validateAiMutationPlan(plan: unknown): AiValidationResult;
|
|
1655
|
+
/**
|
|
1656
|
+
* Return a copy of a plan with the latest validation result attached.
|
|
1657
|
+
*/
|
|
1658
|
+
declare function attachAiPlanValidation(plan: AiMutationPlan): AiMutationPlan;
|
|
1659
|
+
declare function serializeAiMutationPlan(plan: AiMutationPlan): string;
|
|
1660
|
+
declare function parseAiMutationPlan(serialized: string): {
|
|
1661
|
+
plan: AiMutationPlan | null;
|
|
1662
|
+
validation: AiValidationResult;
|
|
1663
|
+
};
|
|
1664
|
+
declare function createAiOperation<TArgs extends Record<string, unknown>>(op: string, args: TArgs, rationale?: string): AiOperation<TArgs>;
|
|
1665
|
+
declare function createAiChangeSet(input: AiChangeSet): AiChangeSet;
|
|
1666
|
+
|
|
1667
|
+
/**
|
|
1668
|
+
* Local HTTP API Server
|
|
1669
|
+
*
|
|
1670
|
+
* Provides a REST API for external integrations (N8N, MCP, etc.) to interact
|
|
1671
|
+
* with xNet data. Runs on localhost only (port 31415 by default).
|
|
1672
|
+
*
|
|
1673
|
+
* This is designed to run in the Electron main process.
|
|
1674
|
+
*/
|
|
1675
|
+
|
|
1676
|
+
type LocalAPITokenScope = 'health.read' | 'nodes.read' | 'nodes.write' | 'schemas.read' | 'events.read' | 'ai.read' | 'ai.write' | 'admin';
|
|
1677
|
+
type LocalAPITokenConfig = {
|
|
1678
|
+
token: string;
|
|
1679
|
+
label?: string;
|
|
1680
|
+
scopes: LocalAPITokenScope[];
|
|
1681
|
+
aiScopes?: AiScope[];
|
|
1682
|
+
createdAt?: string;
|
|
1683
|
+
};
|
|
1684
|
+
type LocalAPITokenSummary = Omit<LocalAPITokenConfig, 'token'>;
|
|
1685
|
+
/**
|
|
1686
|
+
* Node store interface (minimal subset needed by API)
|
|
1687
|
+
*/
|
|
1688
|
+
interface NodeStoreAPI {
|
|
1689
|
+
get(id: string): Promise<NodeData | null>;
|
|
1690
|
+
list(options?: {
|
|
1691
|
+
schemaId?: string;
|
|
1692
|
+
limit?: number;
|
|
1693
|
+
offset?: number;
|
|
1694
|
+
}): Promise<NodeData[]>;
|
|
1695
|
+
query?(descriptor: NodeQueryDescriptor): Promise<NodeQueryResult>;
|
|
1696
|
+
create(options: {
|
|
1697
|
+
schemaId: string;
|
|
1698
|
+
properties: Record<string, unknown>;
|
|
1699
|
+
}): Promise<NodeData>;
|
|
1700
|
+
update(id: string, options: {
|
|
1701
|
+
properties: Record<string, unknown>;
|
|
1702
|
+
}): Promise<NodeData>;
|
|
1703
|
+
delete(id: string): Promise<void>;
|
|
1704
|
+
subscribe(listener: (event: NodeChangeEventData) => void): () => void;
|
|
1705
|
+
}
|
|
1706
|
+
/**
|
|
1707
|
+
* Schema registry interface (minimal subset needed by API)
|
|
1708
|
+
*/
|
|
1709
|
+
interface SchemaRegistryAPI {
|
|
1710
|
+
getAllIRIs(): string[];
|
|
1711
|
+
get(iri: string): Promise<SchemaData | null>;
|
|
1712
|
+
}
|
|
1713
|
+
/**
|
|
1714
|
+
* Node data returned by API
|
|
1715
|
+
*/
|
|
1716
|
+
interface NodeData {
|
|
1717
|
+
id: string;
|
|
1718
|
+
schemaId: string;
|
|
1719
|
+
properties: Record<string, unknown>;
|
|
1720
|
+
deleted: boolean;
|
|
1721
|
+
createdAt: number;
|
|
1722
|
+
updatedAt: number;
|
|
1723
|
+
}
|
|
1724
|
+
/**
|
|
1725
|
+
* Schema data returned by API
|
|
1726
|
+
*/
|
|
1727
|
+
interface SchemaData {
|
|
1728
|
+
iri: string;
|
|
1729
|
+
name: string;
|
|
1730
|
+
properties: Record<string, unknown>;
|
|
1731
|
+
}
|
|
1732
|
+
/**
|
|
1733
|
+
* Node change event data
|
|
1734
|
+
*/
|
|
1735
|
+
interface NodeChangeEventData {
|
|
1736
|
+
change: {
|
|
1737
|
+
type: string;
|
|
1738
|
+
};
|
|
1739
|
+
node: NodeData | null;
|
|
1740
|
+
isRemote: boolean;
|
|
1741
|
+
}
|
|
1742
|
+
/**
|
|
1743
|
+
* API configuration
|
|
1744
|
+
*/
|
|
1745
|
+
interface LocalAPIConfig {
|
|
1746
|
+
/** Port to listen on (default: 31415) */
|
|
1747
|
+
port?: number;
|
|
1748
|
+
/** Host to bind to (default: '127.0.0.1') */
|
|
1749
|
+
host?: string;
|
|
1750
|
+
/** API token for authentication (optional) */
|
|
1751
|
+
token?: string;
|
|
1752
|
+
/** Scoped API tokens for local-only integrations. */
|
|
1753
|
+
tokens?: LocalAPITokenConfig[];
|
|
1754
|
+
/**
|
|
1755
|
+
* Allowed CORS origins (default: none).
|
|
1756
|
+
* Set to specific origins like ['http://localhost:3000'] for local dev,
|
|
1757
|
+
* or ['*'] to allow all origins (not recommended for production).
|
|
1758
|
+
* Empty array or undefined disables CORS entirely.
|
|
1759
|
+
*/
|
|
1760
|
+
allowedOrigins?: string[];
|
|
1761
|
+
/** NodeStore instance */
|
|
1762
|
+
store: NodeStoreAPI;
|
|
1763
|
+
/** SchemaRegistry instance */
|
|
1764
|
+
schemas: SchemaRegistryAPI;
|
|
1765
|
+
/** Shared AI surface service. A default service is created when omitted. */
|
|
1766
|
+
aiSurface?: AiSurfaceService;
|
|
1767
|
+
/** Optional output and pagination limits for the default AI surface. */
|
|
1768
|
+
aiLimits?: Partial<AiSurfaceLimits>;
|
|
1769
|
+
}
|
|
1770
|
+
|
|
1771
|
+
/**
|
|
1772
|
+
* AI surface service for focused resources, context packs, and plan-only tools.
|
|
1773
|
+
*/
|
|
1774
|
+
|
|
1775
|
+
type AiResourceContent = {
|
|
1776
|
+
uri: string;
|
|
1777
|
+
mimeType: string;
|
|
1778
|
+
text: string;
|
|
1779
|
+
};
|
|
1780
|
+
type AiSearchResult = {
|
|
1781
|
+
id: string;
|
|
1782
|
+
schemaId: string;
|
|
1783
|
+
title: string;
|
|
1784
|
+
snippet: string;
|
|
1785
|
+
score: number;
|
|
1786
|
+
revision: string;
|
|
1787
|
+
updatedAt: number;
|
|
1788
|
+
};
|
|
1789
|
+
type AiSearchOptions = {
|
|
1790
|
+
query: string;
|
|
1791
|
+
schemaId?: string;
|
|
1792
|
+
limit?: number;
|
|
1793
|
+
offset?: number;
|
|
1794
|
+
};
|
|
1795
|
+
type AiSurfaceLimits = {
|
|
1796
|
+
maxListLimit: number;
|
|
1797
|
+
maxSearchScan: number;
|
|
1798
|
+
maxSearchResults: number;
|
|
1799
|
+
maxContextResources: number;
|
|
1800
|
+
maxCharactersPerResource: number;
|
|
1801
|
+
maxJsonCharacters: number;
|
|
1802
|
+
maxCanvasObjects: number;
|
|
1803
|
+
maxDatabaseRows: number;
|
|
1804
|
+
};
|
|
1805
|
+
type AiPageMarkdownApplyAdapterInput = {
|
|
1806
|
+
pageId: string;
|
|
1807
|
+
markdown: string;
|
|
1808
|
+
bodyMarkdown: string;
|
|
1809
|
+
baseRevision: string;
|
|
1810
|
+
plan: AiMutationPlan;
|
|
1811
|
+
operation: AiOperation;
|
|
1812
|
+
};
|
|
1813
|
+
type AiPageMarkdownApplyAdapterResult = {
|
|
1814
|
+
mode: 'tiptap-yjs' | 'yjs' | 'custom';
|
|
1815
|
+
yjsField?: string;
|
|
1816
|
+
documentUpdate?: unknown;
|
|
1817
|
+
warnings?: string[];
|
|
1818
|
+
};
|
|
1819
|
+
type AiPageMarkdownApplyAdapter = {
|
|
1820
|
+
applyMarkdown(input: AiPageMarkdownApplyAdapterInput): Promise<AiPageMarkdownApplyAdapterResult>;
|
|
1821
|
+
};
|
|
1822
|
+
type AiPageMarkdownApplyResult = {
|
|
1823
|
+
applied: boolean;
|
|
1824
|
+
pageId: string;
|
|
1825
|
+
planId: string;
|
|
1826
|
+
mode: 'tiptap-yjs' | 'yjs' | 'custom' | 'node-property';
|
|
1827
|
+
baseRevision: string;
|
|
1828
|
+
liveRevision: string;
|
|
1829
|
+
markdownHash: string;
|
|
1830
|
+
bodyMarkdownHash: string;
|
|
1831
|
+
validation: {
|
|
1832
|
+
valid: boolean;
|
|
1833
|
+
errors: string[];
|
|
1834
|
+
warnings: string[];
|
|
1835
|
+
};
|
|
1836
|
+
auditEventId?: string;
|
|
1837
|
+
rollbackHandle?: string;
|
|
1838
|
+
yjsField?: string;
|
|
1839
|
+
documentUpdate?: unknown;
|
|
1840
|
+
};
|
|
1841
|
+
type AiPageMarkdownRollbackResult = {
|
|
1842
|
+
rolledBack: boolean;
|
|
1843
|
+
pageId: string;
|
|
1844
|
+
planId: string;
|
|
1845
|
+
rollbackHandle: string;
|
|
1846
|
+
auditEventId?: string;
|
|
1847
|
+
validation: {
|
|
1848
|
+
valid: boolean;
|
|
1849
|
+
errors: string[];
|
|
1850
|
+
warnings: string[];
|
|
1851
|
+
};
|
|
1852
|
+
};
|
|
1853
|
+
type AiDatabaseMutationApplyResult = {
|
|
1854
|
+
applied: boolean;
|
|
1855
|
+
databaseId: string;
|
|
1856
|
+
planId: string;
|
|
1857
|
+
baseRevision: string;
|
|
1858
|
+
liveRevision: string;
|
|
1859
|
+
appliedChangeIds: string[];
|
|
1860
|
+
rolledBackChangeIds: string[];
|
|
1861
|
+
validation: {
|
|
1862
|
+
valid: boolean;
|
|
1863
|
+
errors: string[];
|
|
1864
|
+
warnings: string[];
|
|
1865
|
+
};
|
|
1866
|
+
auditEventId?: string;
|
|
1867
|
+
};
|
|
1868
|
+
/** A node surfaced by an external retriever, with optional provenance. */
|
|
1869
|
+
type AiRetrievedNode = {
|
|
1870
|
+
nodeId: string;
|
|
1871
|
+
/** Human-readable graph path back to an entry node (for citation/provenance). */
|
|
1872
|
+
pathLabel?: string;
|
|
1873
|
+
};
|
|
1874
|
+
/**
|
|
1875
|
+
* Optional graph-aware retriever (exploration 0211). When provided, the `query`
|
|
1876
|
+
* path of `createContextPack` uses it instead of the built-in linear keyword
|
|
1877
|
+
* scan — i.e. hybrid vector + keyword entry search plus bounded graph expansion,
|
|
1878
|
+
* budgeted. The app injects `@xnetjs/brain`'s `retrieve` here (mapping its items
|
|
1879
|
+
* to `{ nodeId, pathLabel }`); absent it, context packs fall back to `search()`
|
|
1880
|
+
* with no behavior change.
|
|
1881
|
+
*/
|
|
1882
|
+
type AiContextRetriever = (query: string, options: {
|
|
1883
|
+
limit: number;
|
|
1884
|
+
}) => Promise<AiRetrievedNode[]>;
|
|
1885
|
+
type AiSurfaceServiceConfig = {
|
|
1886
|
+
store: NodeStoreAPI;
|
|
1887
|
+
schemas: SchemaRegistryAPI;
|
|
1888
|
+
limits?: Partial<AiSurfaceLimits>;
|
|
1889
|
+
clock?: () => Date;
|
|
1890
|
+
pageMarkdownAdapter?: AiPageMarkdownApplyAdapter;
|
|
1891
|
+
/**
|
|
1892
|
+
* Tools contributed from outside the surface — plugin/connector `agentTools`
|
|
1893
|
+
* (exploration 0196). They are appended to `getTools()` and dispatched by
|
|
1894
|
+
* `callTool()`, so every consumer (in-app AI, the MCP server, the files-first
|
|
1895
|
+
* skill) sees them by registering once. A built-in `xnet_*` name always wins
|
|
1896
|
+
* over a colliding extra tool.
|
|
1897
|
+
*/
|
|
1898
|
+
extraTools?: AiExtraTool[];
|
|
1899
|
+
/**
|
|
1900
|
+
* Optional graph-aware context retriever (exploration 0211). Drives the
|
|
1901
|
+
* `query` path of `createContextPack` when present; falls back to the built-in
|
|
1902
|
+
* keyword `search()` otherwise.
|
|
1903
|
+
*/
|
|
1904
|
+
retrieveContext?: AiContextRetriever;
|
|
1905
|
+
};
|
|
1906
|
+
declare class AiSurfaceService {
|
|
1907
|
+
private readonly config;
|
|
1908
|
+
private readonly limits;
|
|
1909
|
+
private readonly clock;
|
|
1910
|
+
private sequence;
|
|
1911
|
+
private auditEvents;
|
|
1912
|
+
private readonly rollbackSnapshots;
|
|
1913
|
+
/** Contributed tools by name (exploration 0196), de-duped at construction. */
|
|
1914
|
+
private readonly extraTools;
|
|
1915
|
+
constructor(config: AiSurfaceServiceConfig);
|
|
1916
|
+
/** The contributed (non-built-in) tools, with built-in name collisions removed. */
|
|
1917
|
+
private getExtraTools;
|
|
1918
|
+
getResources(): AiResource[];
|
|
1919
|
+
/** The full tool surface: built-in `xnet_*` tools plus contributed extras. */
|
|
1920
|
+
getTools(): AiToolDefinition[];
|
|
1921
|
+
private builtInTools;
|
|
1922
|
+
callTool(name: string, args?: Record<string, unknown>): Promise<unknown>;
|
|
1923
|
+
readResource(uri: string): Promise<AiResourceContent>;
|
|
1924
|
+
toJsonText(value: unknown, format?: 'concise' | 'detailed'): string;
|
|
1925
|
+
private getWorkspaceSummary;
|
|
1926
|
+
private getRecentNodes;
|
|
1927
|
+
search(options: AiSearchOptions): Promise<Record<string, unknown>>;
|
|
1928
|
+
/**
|
|
1929
|
+
* Candidate node ids for a context-pack query: the injected graph-aware
|
|
1930
|
+
* retriever (exploration 0211) when configured, else the built-in keyword
|
|
1931
|
+
* `search()`. Order is preserved (best-first).
|
|
1932
|
+
*/
|
|
1933
|
+
private candidateNodeIdsForQuery;
|
|
1934
|
+
createContextPack(options: {
|
|
1935
|
+
query?: string;
|
|
1936
|
+
seeds?: AiContextSeed[];
|
|
1937
|
+
limit?: number;
|
|
1938
|
+
}): Promise<AiContextPack>;
|
|
1939
|
+
/**
|
|
1940
|
+
* Walk typed relation edges out from a node to its connected neighbors, bounded
|
|
1941
|
+
* by `hops` (1–2) and a result `limit`. This is the just-in-time companion to
|
|
1942
|
+
* `createContextPack` (exploration 0211): retrieval hands the agent a budgeted
|
|
1943
|
+
* slice plus expandable node ids, and this lets it pull a specific node's
|
|
1944
|
+
* connections on demand instead of over-fetching the whole graph up front.
|
|
1945
|
+
*/
|
|
1946
|
+
private expandGraph;
|
|
1947
|
+
private graphExpansion;
|
|
1948
|
+
createExternalContextResource(options: {
|
|
1949
|
+
url: string;
|
|
1950
|
+
text: string;
|
|
1951
|
+
mimeType?: string;
|
|
1952
|
+
}): AiContextPackResource;
|
|
1953
|
+
private readPageMarkdown;
|
|
1954
|
+
private readPageOutline;
|
|
1955
|
+
private planPagePatch;
|
|
1956
|
+
private applyPageMarkdown;
|
|
1957
|
+
private finalizeAppliedPageMarkdown;
|
|
1958
|
+
private getAuditLog;
|
|
1959
|
+
private rollbackPageMarkdown;
|
|
1960
|
+
private recordAuditEvent;
|
|
1961
|
+
private describeDatabase;
|
|
1962
|
+
private readDatabaseViews;
|
|
1963
|
+
private queryDatabase;
|
|
1964
|
+
private sampleDatabase;
|
|
1965
|
+
private explainDatabaseQuery;
|
|
1966
|
+
private executeDatabaseQueryDescriptor;
|
|
1967
|
+
private listCanvases;
|
|
1968
|
+
private readCanvasObjects;
|
|
1969
|
+
private readCanvasViewport;
|
|
1970
|
+
private readCanvasSelection;
|
|
1971
|
+
private searchCanvas;
|
|
1972
|
+
private exportCanvasJsonCanvas;
|
|
1973
|
+
private planCanvasJsonCanvasImport;
|
|
1974
|
+
private readCanvasObject;
|
|
1975
|
+
private hydrateSourcePreviews;
|
|
1976
|
+
private planCanvasMutation;
|
|
1977
|
+
private planDatabaseMutation;
|
|
1978
|
+
private applyDatabaseMutation;
|
|
1979
|
+
private applyDatabaseRowOperations;
|
|
1980
|
+
private applyDatabaseRowTransactionOperation;
|
|
1981
|
+
private rollbackAppliedDatabaseRowChanges;
|
|
1982
|
+
private applyDatabaseSchemaOperations;
|
|
1983
|
+
private planSurfaceMutation;
|
|
1984
|
+
private validatedPlan;
|
|
1985
|
+
private getNodeOrThrow;
|
|
1986
|
+
private getNodeProjection;
|
|
1987
|
+
private getSchemaSummaries;
|
|
1988
|
+
private readSchemaSummary;
|
|
1989
|
+
private contextResourceForSeed;
|
|
1990
|
+
private jsonResource;
|
|
1991
|
+
private stringifyJson;
|
|
1992
|
+
private nextId;
|
|
1993
|
+
private nowIso;
|
|
1994
|
+
}
|
|
1995
|
+
declare function createAiSurfaceService(config: AiSurfaceServiceConfig): AiSurfaceService;
|
|
1996
|
+
|
|
1997
|
+
/**
|
|
1998
|
+
* Page Markdown validation for AI-edited xNet page projections.
|
|
1999
|
+
*/
|
|
2000
|
+
|
|
2001
|
+
type XNetPageMarkdownFrontmatter = {
|
|
2002
|
+
id?: string;
|
|
2003
|
+
schemaId?: string;
|
|
2004
|
+
revision?: string;
|
|
2005
|
+
exportedAt?: string;
|
|
2006
|
+
};
|
|
2007
|
+
type XNetMarkdownDirective = {
|
|
2008
|
+
kind: 'block' | 'inline' | 'wikilink';
|
|
2009
|
+
name: string;
|
|
2010
|
+
index: number;
|
|
2011
|
+
payload?: Record<string, unknown>;
|
|
2012
|
+
target?: string;
|
|
2013
|
+
};
|
|
2014
|
+
type XNetMarkdownDirectiveSpec = {
|
|
2015
|
+
kind: 'block' | 'inline' | 'wikilink';
|
|
2016
|
+
name: string;
|
|
2017
|
+
editorExtension: string;
|
|
2018
|
+
description: string;
|
|
2019
|
+
};
|
|
2020
|
+
type XNetPageMarkdownValidationOptions = {
|
|
2021
|
+
pageId?: string;
|
|
2022
|
+
schemaId?: string;
|
|
2023
|
+
baseRevision?: string;
|
|
2024
|
+
};
|
|
2025
|
+
type XNetPageMarkdownValidation = {
|
|
2026
|
+
frontmatter: XNetPageMarkdownFrontmatter | null;
|
|
2027
|
+
directives: XNetMarkdownDirective[];
|
|
2028
|
+
validation: AiValidationResult;
|
|
2029
|
+
};
|
|
2030
|
+
type XNetMarkdownDiffLineKind = 'context' | 'removed' | 'added';
|
|
2031
|
+
type XNetMarkdownDiffLine = {
|
|
2032
|
+
kind: XNetMarkdownDiffLineKind;
|
|
2033
|
+
text: string;
|
|
2034
|
+
beforeLine?: number;
|
|
2035
|
+
afterLine?: number;
|
|
2036
|
+
};
|
|
2037
|
+
type XNetMarkdownReviewDiff = {
|
|
2038
|
+
kind: 'markdown-diff';
|
|
2039
|
+
format: 'line';
|
|
2040
|
+
beforeLineCount: number;
|
|
2041
|
+
afterLineCount: number;
|
|
2042
|
+
lineCount: number;
|
|
2043
|
+
unifiedDiff: string;
|
|
2044
|
+
lines: XNetMarkdownDiffLine[];
|
|
2045
|
+
};
|
|
2046
|
+
declare const XNET_MARKDOWN_DIRECTIVE_SPECS: readonly [{
|
|
2047
|
+
readonly kind: "block";
|
|
2048
|
+
readonly name: "xnet-database";
|
|
2049
|
+
readonly editorExtension: "DatabaseEmbedExtension";
|
|
2050
|
+
readonly description: "Embeds a database view block with JSON view configuration.";
|
|
2051
|
+
}, {
|
|
2052
|
+
readonly kind: "block";
|
|
2053
|
+
readonly name: "xnet-page";
|
|
2054
|
+
readonly editorExtension: "PageEmbedExtension";
|
|
2055
|
+
readonly description: "Embeds a page preview block with page identity and preview metadata.";
|
|
2056
|
+
}, {
|
|
2057
|
+
readonly kind: "block";
|
|
2058
|
+
readonly name: "xnet-embed";
|
|
2059
|
+
readonly editorExtension: "EmbedExtension";
|
|
2060
|
+
readonly description: "Embeds rich external media with provider metadata.";
|
|
2061
|
+
}, {
|
|
2062
|
+
readonly kind: "inline";
|
|
2063
|
+
readonly name: "xnet-ref";
|
|
2064
|
+
readonly editorExtension: "SmartReferenceExtension";
|
|
2065
|
+
readonly description: "Embeds an inline smart reference to an external or internal resource.";
|
|
2066
|
+
}, {
|
|
2067
|
+
readonly kind: "inline";
|
|
2068
|
+
readonly name: "xnet-db-ref";
|
|
2069
|
+
readonly editorExtension: "DatabaseReferenceExtension";
|
|
2070
|
+
readonly description: "Embeds an inline database reference.";
|
|
2071
|
+
}, {
|
|
2072
|
+
readonly kind: "wikilink";
|
|
2073
|
+
readonly name: "wikilink";
|
|
2074
|
+
readonly editorExtension: "Wikilink";
|
|
2075
|
+
readonly description: "Parses [[Page Title]] wikilinks into xNet page links.";
|
|
2076
|
+
}];
|
|
2077
|
+
declare function validateXNetPageMarkdown(markdown: string, options?: XNetPageMarkdownValidationOptions): XNetPageMarkdownValidation;
|
|
2078
|
+
declare function getXNetMarkdownDirectiveSpecs(): readonly XNetMarkdownDirectiveSpec[];
|
|
2079
|
+
declare function parseXNetPageFrontmatter(markdown: string): XNetPageMarkdownFrontmatter | null;
|
|
2080
|
+
declare function stripXNetPageFrontmatter(markdown: string): string;
|
|
2081
|
+
declare function renderMarkdownLineDiff(before: string, after: string): string;
|
|
2082
|
+
declare function renderMarkdownReviewDiff(before: string, after: string): XNetMarkdownReviewDiff;
|
|
2083
|
+
|
|
2084
|
+
/**
|
|
2085
|
+
* Write guardrail for the MCP server (exploration 0175, "boundary hardening").
|
|
2086
|
+
*
|
|
2087
|
+
* The 0175 pitch is that xNet's guardrail makes an autonomous agent safe to
|
|
2088
|
+
* point at a workspace. But the generic `xnet_create/update/delete` tools used
|
|
2089
|
+
* to mutate the store directly, bypassing the mutation-plan guardrail that the
|
|
2090
|
+
* page/database tools enforce. This closes that gap for *every* MCP client
|
|
2091
|
+
* (OpenClaw, Claude Code, …) at the boundary, independent of the client's own
|
|
2092
|
+
* (often weak) safety model:
|
|
2093
|
+
*
|
|
2094
|
+
* - **Risk classification.** Deletes are `high`; creating an outward-facing node
|
|
2095
|
+
* (e.g. a chat message — "sending") is `high`; ordinary creates/updates are
|
|
2096
|
+
* `low`.
|
|
2097
|
+
* - **Confirmation gate.** `high`/`critical` and outward-facing writes return
|
|
2098
|
+
* `needs-confirmation` instead of mutating, until the caller re-issues with
|
|
2099
|
+
* `confirm: true` (after the human approves — see the ClawHub skill).
|
|
2100
|
+
* - **Cost budget.** Writes are charged against a per-surface budget
|
|
2101
|
+
* (`@xnetjs/abuse`); a runaway agent is throttled, not unbounded.
|
|
2102
|
+
* - **Provenance + audit.** Applied writes are recorded with their risk and an
|
|
2103
|
+
* optional AI-provenance evidence ref, queryable for review.
|
|
2104
|
+
*/
|
|
2105
|
+
|
|
2106
|
+
type McpWriteKind = 'create' | 'update' | 'delete';
|
|
2107
|
+
interface McpWriteRequest {
|
|
2108
|
+
kind: McpWriteKind;
|
|
2109
|
+
/** Schema IRI (for create). Used to detect outward-facing writes. */
|
|
2110
|
+
schemaId?: string;
|
|
2111
|
+
/** Target node id (for update/delete). */
|
|
2112
|
+
nodeId?: string;
|
|
2113
|
+
/** Caller confirmation; required to apply high-risk / outward-facing writes. */
|
|
2114
|
+
confirm?: boolean;
|
|
2115
|
+
/** Optional provenance from the calling agent (model that authored the write). */
|
|
2116
|
+
provenance?: AISignalProvenanceInput;
|
|
2117
|
+
}
|
|
2118
|
+
type McpWriteVerdict = {
|
|
2119
|
+
decision: 'allow';
|
|
2120
|
+
risk: AiRiskLevel;
|
|
2121
|
+
outwardFacing: boolean;
|
|
2122
|
+
provenanceRef: string | null;
|
|
2123
|
+
} | {
|
|
2124
|
+
decision: 'needs-confirmation';
|
|
2125
|
+
risk: AiRiskLevel;
|
|
2126
|
+
outwardFacing: boolean;
|
|
2127
|
+
reason: string;
|
|
2128
|
+
} | {
|
|
2129
|
+
decision: 'blocked';
|
|
2130
|
+
risk: AiRiskLevel;
|
|
2131
|
+
reason: string;
|
|
2132
|
+
};
|
|
2133
|
+
interface McpWriteAuditEvent {
|
|
2134
|
+
kind: McpWriteKind;
|
|
2135
|
+
risk: AiRiskLevel;
|
|
2136
|
+
outwardFacing: boolean;
|
|
2137
|
+
schemaId?: string;
|
|
2138
|
+
nodeId?: string;
|
|
2139
|
+
provenanceRef?: string;
|
|
2140
|
+
at: number;
|
|
2141
|
+
}
|
|
2142
|
+
interface McpWriteGuardrailOptions {
|
|
2143
|
+
/** Schema IRIs whose creation is outward-facing (raises risk, requires confirm). */
|
|
2144
|
+
outwardFacingSchemas?: readonly string[];
|
|
2145
|
+
/** Cost budget policy. Defaults to 120 writes / 60s on the surface. */
|
|
2146
|
+
budgetPolicy?: PublicWriteBudgetPolicy;
|
|
2147
|
+
/** Abuse surface for budget keys. Defaults to `localApi`. */
|
|
2148
|
+
surface?: AbuseSurface;
|
|
2149
|
+
/** Injectable clock (ms). Defaults to `Date.now`. */
|
|
2150
|
+
clock?: () => number;
|
|
2151
|
+
}
|
|
2152
|
+
declare class McpWriteGuardrail {
|
|
2153
|
+
private readonly outward;
|
|
2154
|
+
private readonly policy;
|
|
2155
|
+
private readonly surface;
|
|
2156
|
+
private readonly now;
|
|
2157
|
+
private usage;
|
|
2158
|
+
private auditLog;
|
|
2159
|
+
constructor(options?: McpWriteGuardrailOptions);
|
|
2160
|
+
/** Classify and gate a write. Does not mutate anything; charges budget only on `allow`. */
|
|
2161
|
+
evaluate(req: McpWriteRequest): McpWriteVerdict;
|
|
2162
|
+
/** Record an applied write for audit/rollback review. Returns the event. */
|
|
2163
|
+
recordApplied(req: McpWriteRequest, verdict: Extract<McpWriteVerdict, {
|
|
2164
|
+
decision: 'allow';
|
|
2165
|
+
}>, nodeId?: string): McpWriteAuditEvent;
|
|
2166
|
+
getAuditLog(limit?: number): McpWriteAuditEvent[];
|
|
2167
|
+
private classify;
|
|
2168
|
+
}
|
|
2169
|
+
|
|
2170
|
+
/**
|
|
2171
|
+
* @xnetjs/plugins — connector sync runner (exploration 0196).
|
|
2172
|
+
*
|
|
2173
|
+
* Runs a connector's `pull` with the guardrails composed, so the *author* writes
|
|
2174
|
+
* plain `store.create(...)` / `fetch(...)` and the *framework* guarantees:
|
|
2175
|
+
*
|
|
2176
|
+
* - **egress containment** — `fetch` is `guardedFetch`, limited to the declared
|
|
2177
|
+
* `capabilities.network`;
|
|
2178
|
+
* - **schema-write containment** — `store` is `guardStore`, limited to the
|
|
2179
|
+
* declared `capabilities.schemaWrite`;
|
|
2180
|
+
* - **space scoping** — every created node is stamped with the target Space, so
|
|
2181
|
+
* the authorization cascade keeps one space's synced data invisible to agents
|
|
2182
|
+
* working in another (no cross-contamination);
|
|
2183
|
+
* - **budget** — writes are charged against the `connector` surface, separate
|
|
2184
|
+
* from the interactive agent's `localApi` budget, so a bulk backfill is
|
|
2185
|
+
* throttled rather than unbounded.
|
|
2186
|
+
*
|
|
2187
|
+
* Secret scoping is the hub's job: `mountFeatures` hands `pull` a `scopedEnv`, so
|
|
2188
|
+
* this runner never sees (or needs) the full process env — keeping the dependency
|
|
2189
|
+
* direction clean (no `@xnetjs/plugins` → `@xnetjs/hub` edge).
|
|
2190
|
+
*/
|
|
2191
|
+
|
|
2192
|
+
declare class ConnectorSyncError extends Error {
|
|
2193
|
+
constructor(message: string);
|
|
2194
|
+
}
|
|
2195
|
+
/** A node store with the methods the runner guards (create/get/update). */
|
|
2196
|
+
type GuardableConnectorStore = ConnectorStore;
|
|
2197
|
+
interface RunConnectorSyncPorts {
|
|
2198
|
+
/** Broker-scoped env (the hub scopes it; tests pass a minimal object). */
|
|
2199
|
+
env: Record<string, string | undefined>;
|
|
2200
|
+
/** Underlying fetch — wrapped in `guardedFetch` before reaching `pull`. */
|
|
2201
|
+
fetch: ConnectorFetch;
|
|
2202
|
+
/** Underlying store — wrapped in `guardStore` + space-stamp before `pull`. */
|
|
2203
|
+
store: GuardableConnectorStore;
|
|
2204
|
+
/** Target Space id. Required unless `allowUnscoped` is set. */
|
|
2205
|
+
space: string | null;
|
|
2206
|
+
/** Write guardrail; defaults to a fresh `connector`-surface guardrail. */
|
|
2207
|
+
guardrail?: McpWriteGuardrail;
|
|
2208
|
+
/** Opt out of the space requirement (personal / intentionally unscoped sync). */
|
|
2209
|
+
allowUnscoped?: boolean;
|
|
2210
|
+
}
|
|
2211
|
+
/**
|
|
2212
|
+
* Run a connector's sync with all guards composed. The connector author's `pull`
|
|
2213
|
+
* sees a guarded fetch + store and a target space; it cannot reach undeclared
|
|
2214
|
+
* hosts, write undeclared schemas, leak across spaces, or exceed its budget.
|
|
2215
|
+
*
|
|
2216
|
+
* @throws {ConnectorSyncError} when a target space is required but missing.
|
|
2217
|
+
*/
|
|
2218
|
+
declare function runConnectorSync(def: ConnectorDefinition, ports: RunConnectorSyncPorts): Promise<ConnectorSyncResult>;
|
|
2219
|
+
|
|
2220
|
+
/**
|
|
2221
|
+
* @xnetjs/plugins — marketplace index + search (exploration 0192).
|
|
2222
|
+
*
|
|
2223
|
+
* The data layer behind the 0047 GitHub-backed registry: the shape of a
|
|
2224
|
+
* `registry.json` entry, pure browse/search/sort over it, rating aggregation,
|
|
2225
|
+
* and a `MarketplaceClient` whose network access is injected (a `fetchJson`
|
|
2226
|
+
* port) so it is unit-testable without a server. The in-app Marketplace view
|
|
2227
|
+
* renders on top of this; the view itself is app-side.
|
|
2228
|
+
*/
|
|
2229
|
+
|
|
2230
|
+
/** A single entry in the marketplace index (`registry.json`). */
|
|
2231
|
+
interface MarketplaceEntry {
|
|
2232
|
+
id: string;
|
|
2233
|
+
name: string;
|
|
2234
|
+
description: string;
|
|
2235
|
+
version: string;
|
|
2236
|
+
author: string;
|
|
2237
|
+
/** Search keywords / tags. */
|
|
2238
|
+
keywords?: string[];
|
|
2239
|
+
/** Coarse category for filtering (`productivity`, `finance`, `social`, …). */
|
|
2240
|
+
category?: string;
|
|
2241
|
+
/** Capabilities the plugin requests (drives the consent preview). */
|
|
2242
|
+
capabilities?: ModuleCapabilities;
|
|
2243
|
+
/** URL the full manifest is fetched from at install. */
|
|
2244
|
+
manifestUrl: string;
|
|
2245
|
+
/** Lifetime install count (trust signal). */
|
|
2246
|
+
installs?: number;
|
|
2247
|
+
/** GitHub stars / community signal. */
|
|
2248
|
+
stars?: number;
|
|
2249
|
+
/** SPDX license id (exploration 0196) — shown as a badge; gated by CI policy. */
|
|
2250
|
+
license?: string;
|
|
2251
|
+
/** Monetization (exploration 0196). Absent = free. */
|
|
2252
|
+
pricing?: PluginPricing;
|
|
2253
|
+
/** Publisher identity for paid listings (exploration 0196). */
|
|
2254
|
+
publisherDid?: string;
|
|
2255
|
+
/** Provenance reference for verification (see `./provenance`). */
|
|
2256
|
+
provenance?: {
|
|
2257
|
+
sigstoreBundleUrl?: string;
|
|
2258
|
+
sourceRepo?: string;
|
|
2259
|
+
sourceCommit?: string;
|
|
2260
|
+
};
|
|
2261
|
+
}
|
|
2262
|
+
/** How a marketplace listing is sorted. */
|
|
2263
|
+
type MarketplaceSort = 'relevance' | 'installs' | 'stars' | 'name';
|
|
2264
|
+
/** Filter an index by free-text query (name/description/keywords/author/category). */
|
|
2265
|
+
declare function searchMarketplace(index: readonly MarketplaceEntry[], query: string): MarketplaceEntry[];
|
|
2266
|
+
/** Sort a marketplace listing. `relevance` requires the originating `query`. */
|
|
2267
|
+
declare function sortMarketplace(entries: readonly MarketplaceEntry[], sort: MarketplaceSort, query?: string): MarketplaceEntry[];
|
|
2268
|
+
/** Filter by category (case-insensitive); empty/undefined category returns all. */
|
|
2269
|
+
declare function filterByCategory(entries: readonly MarketplaceEntry[], category: string | undefined): MarketplaceEntry[];
|
|
2270
|
+
/** A weighted signal about what the user works with (from workspace usage). */
|
|
2271
|
+
interface UsageSignal {
|
|
2272
|
+
/** A category the user engages with (e.g. `finance`). */
|
|
2273
|
+
category?: string;
|
|
2274
|
+
/** A keyword the user engages with (e.g. `invoice`). */
|
|
2275
|
+
keyword?: string;
|
|
2276
|
+
/** Relative strength (default 1). */
|
|
2277
|
+
weight?: number;
|
|
2278
|
+
}
|
|
2279
|
+
interface RecommendOptions {
|
|
2280
|
+
/** Ids already installed — excluded from recommendations. */
|
|
2281
|
+
installedIds?: readonly string[];
|
|
2282
|
+
/** Cap the number of recommendations (default 5). */
|
|
2283
|
+
limit?: number;
|
|
2284
|
+
}
|
|
2285
|
+
/**
|
|
2286
|
+
* Recommend extensions from the marketplace index for a user, given weighted
|
|
2287
|
+
* usage signals (category/keyword affinity). Excludes already-installed ids and
|
|
2288
|
+
* ranks by match score, with install-count as a tiebreaker. Pure — the "AI
|
|
2289
|
+
* brain" decides the signals; this turns them into a ranked shortlist.
|
|
2290
|
+
*/
|
|
2291
|
+
declare function recommendExtensions(index: readonly MarketplaceEntry[], signals: readonly UsageSignal[], options?: RecommendOptions): MarketplaceEntry[];
|
|
2292
|
+
/** A single rating (one node per rating; aggregated for display). */
|
|
2293
|
+
interface PluginRating {
|
|
2294
|
+
pluginId: string;
|
|
2295
|
+
/** 1–5 stars. */
|
|
2296
|
+
stars: number;
|
|
2297
|
+
authorDID: string;
|
|
2298
|
+
review?: string;
|
|
2299
|
+
}
|
|
2300
|
+
interface RatingSummary {
|
|
2301
|
+
count: number;
|
|
2302
|
+
average: number;
|
|
2303
|
+
/** Histogram indexed 1..5. */
|
|
2304
|
+
histogram: Record<1 | 2 | 3 | 4 | 5, number>;
|
|
2305
|
+
}
|
|
2306
|
+
/** Aggregate ratings into a summary (rounds stars to 1..5, ignores invalid). */
|
|
2307
|
+
declare function aggregateRatings(ratings: readonly PluginRating[]): RatingSummary;
|
|
2308
|
+
/** Injected network port so the client is testable without a real fetch. */
|
|
2309
|
+
type FetchJson = <T>(url: string) => Promise<T>;
|
|
2310
|
+
interface MarketplaceClientOptions {
|
|
2311
|
+
/** URL of the registry index (`registry.json`). */
|
|
2312
|
+
indexUrl: string;
|
|
2313
|
+
/** How to fetch JSON (defaults to `globalThis.fetch`). */
|
|
2314
|
+
fetchJson?: FetchJson;
|
|
2315
|
+
}
|
|
2316
|
+
/**
|
|
2317
|
+
* A thin client over the registry index: fetch once (cached), then browse/search
|
|
2318
|
+
* in memory. The marketplace stays offline-friendly — the index is small JSON.
|
|
2319
|
+
*/
|
|
2320
|
+
declare class MarketplaceClient {
|
|
2321
|
+
private readonly options;
|
|
2322
|
+
private cache;
|
|
2323
|
+
private readonly fetchJson;
|
|
2324
|
+
constructor(options: MarketplaceClientOptions);
|
|
2325
|
+
/** Fetch (and cache) the registry index. */
|
|
2326
|
+
load(force?: boolean): Promise<MarketplaceEntry[]>;
|
|
2327
|
+
/** Search + sort the index in one call. */
|
|
2328
|
+
search(query: string, opts?: {
|
|
2329
|
+
sort?: MarketplaceSort;
|
|
2330
|
+
category?: string;
|
|
2331
|
+
}): Promise<MarketplaceEntry[]>;
|
|
2332
|
+
}
|
|
2333
|
+
/** The provenance an install should pass to the registry (marketplace tier). */
|
|
2334
|
+
declare const MARKETPLACE_PROVENANCE: InstallProvenance;
|
|
2335
|
+
|
|
2336
|
+
/**
|
|
2337
|
+
* @xnetjs/plugins — connector artifacts + interop (exploration 0196).
|
|
2338
|
+
*
|
|
2339
|
+
* A Connector is governed *inside* xNet, but it should also be a good citizen of
|
|
2340
|
+
* the wider CLI/MCP ecosystem. From one definition this emits:
|
|
2341
|
+
*
|
|
2342
|
+
* - a `connectors`-category marketplace entry (so it ships like any plugin);
|
|
2343
|
+
* - per-tool descriptors for advertisement (what the user's own harness, e.g.
|
|
2344
|
+
* `xnet mcp serve`, exposes to Claude Code / Codex / OpenClaw);
|
|
2345
|
+
* - a per-connector `SKILL.md` fragment for external/files-first harnesses; and
|
|
2346
|
+
* - an `ImporterContribution`-shaped adapter, so a connector's sync doubles as
|
|
2347
|
+
* a one-shot importer (generalizing the dormant 0189 importers point).
|
|
2348
|
+
*
|
|
2349
|
+
* All pure — no I/O — so the marketplace publisher, the MCP server, and the CLI
|
|
2350
|
+
* each consume what they need.
|
|
2351
|
+
*/
|
|
2352
|
+
|
|
2353
|
+
/** The marketplace category every Connector lists under. */
|
|
2354
|
+
declare const CONNECTOR_CATEGORY = "connectors";
|
|
2355
|
+
/** A model-facing descriptor of one connector tool (for tool advertisement). */
|
|
2356
|
+
interface ConnectorToolDescriptor {
|
|
2357
|
+
name: string;
|
|
2358
|
+
description: string;
|
|
2359
|
+
risk: string;
|
|
2360
|
+
}
|
|
2361
|
+
interface ConnectorArtifacts {
|
|
2362
|
+
/** Tool descriptors the user's harness advertises (MCP `tools/list`-style). */
|
|
2363
|
+
agentTools: ConnectorToolDescriptor[];
|
|
2364
|
+
/** A per-connector SKILL.md fragment for external / files-first harnesses. */
|
|
2365
|
+
skillMarkdown: string;
|
|
2366
|
+
/** A `connectors`-category marketplace entry. */
|
|
2367
|
+
marketplaceEntry: MarketplaceEntry;
|
|
2368
|
+
}
|
|
2369
|
+
/** Build a `connectors`-category marketplace entry from a connector. */
|
|
2370
|
+
declare function connectorMarketplaceEntry(connector: DefinedConnector, options?: {
|
|
2371
|
+
manifestUrl?: string;
|
|
2372
|
+
}): MarketplaceEntry;
|
|
2373
|
+
/**
|
|
2374
|
+
* Expose a connector's sync as an `ImporterContribution` — the connector's
|
|
2375
|
+
* `pull` doubles as a one-shot importer for the source platform. The adapter is
|
|
2376
|
+
* opaque to the importers registry (the import flow casts it), matching the 0189
|
|
2377
|
+
* "defined now, consumed later" shape.
|
|
2378
|
+
*/
|
|
2379
|
+
declare function connectorAsImporter(connector: DefinedConnector): ImporterContribution;
|
|
2380
|
+
/**
|
|
2381
|
+
* Emit the portable artifacts for a connector: tool descriptors, a SKILL.md
|
|
2382
|
+
* fragment, and a marketplace entry. One definition → every surface.
|
|
2383
|
+
*/
|
|
2384
|
+
declare function emitConnectorArtifacts(connector: DefinedConnector, options?: {
|
|
2385
|
+
manifestUrl?: string;
|
|
2386
|
+
}): ConnectorArtifacts;
|
|
2387
|
+
|
|
2388
|
+
/**
|
|
2389
|
+
* @xnetjs/plugins — capability consent (exploration 0192).
|
|
2390
|
+
*
|
|
2391
|
+
* Turns a `ModuleCapabilities` declaration into human-readable consent lines for
|
|
2392
|
+
* the install dialog, and decides whether a given install even needs a consent
|
|
2393
|
+
* prompt (wiring `requiresCapabilityReprompt` into the install flow). The React
|
|
2394
|
+
* dialog is app-side; this is the headless logic it renders and obeys.
|
|
2395
|
+
*
|
|
2396
|
+
* Design note: a `*` (all-schemas) or raw-secret grant is rendered as `danger`
|
|
2397
|
+
* so the UI can shout — the npm-permissions failure mode is consent fatigue, so
|
|
2398
|
+
* broad grants must look different from narrow ones.
|
|
2399
|
+
*/
|
|
2400
|
+
|
|
2401
|
+
/** A single human-readable line in the consent dialog. */
|
|
2402
|
+
interface ConsentLine {
|
|
2403
|
+
/** Coarse icon hint for the UI (`edit`, `eye`, `globe`, `key`, `plug`). */
|
|
2404
|
+
icon: 'edit' | 'eye' | 'globe' | 'key' | 'plug';
|
|
2405
|
+
/** Human sentence, e.g. "Modify your Task data". */
|
|
2406
|
+
text: string;
|
|
2407
|
+
/** Whether this grant is broad/sensitive enough to warrant a warning. */
|
|
2408
|
+
danger: boolean;
|
|
2409
|
+
}
|
|
2410
|
+
/** Short, human label for a schema IRI: `xnet://xnet.fyi/Task@1.0.0` → `Task`. */
|
|
2411
|
+
declare function shortSchemaName(iri: string): string;
|
|
2412
|
+
/** Describe a capability grant as consent lines (one per declared capability). */
|
|
2413
|
+
declare function describeCapabilities(caps: ModuleCapabilities | undefined): ConsentLine[];
|
|
2414
|
+
/** The decision the install path makes about consent for a given install. */
|
|
2415
|
+
interface ConsentDecision {
|
|
2416
|
+
/** Provenance-derived trust tier this plugin will run at. */
|
|
2417
|
+
tier: TrustTier;
|
|
2418
|
+
/** Whether the user must be prompted before activation. */
|
|
2419
|
+
needsPrompt: boolean;
|
|
2420
|
+
/** The lines to show, if prompted. */
|
|
2421
|
+
lines: ConsentLine[];
|
|
2422
|
+
/** True if any requested grant is broad/sensitive. */
|
|
2423
|
+
hasDanger: boolean;
|
|
2424
|
+
}
|
|
2425
|
+
/**
|
|
2426
|
+
* Decide whether an install needs consent and what to show. `needsPrompt` is
|
|
2427
|
+
* true only when provenance requires a re-prompt AND the plugin actually
|
|
2428
|
+
* requests capabilities — a capability-free marketplace plugin still installs
|
|
2429
|
+
* into the marketplace sandbox tier but has nothing to consent to.
|
|
2430
|
+
*/
|
|
2431
|
+
declare function evaluateInstallConsent(provenance: InstallProvenance, caps: ModuleCapabilities | undefined): ConsentDecision;
|
|
2432
|
+
|
|
2433
|
+
/**
|
|
2434
|
+
* @xnetjs/plugins — connector install gate (exploration 0196).
|
|
2435
|
+
*
|
|
2436
|
+
* Connectors flow through the same provenance→trust + consent machinery as any
|
|
2437
|
+
* plugin, with one extra rule: **a connector that requests secrets can never be
|
|
2438
|
+
* auto-trusted on `ai-generated` provenance.** "The model authored it" must not
|
|
2439
|
+
* be sufficient to hand it a credential — a human promotes it (re-authoring or
|
|
2440
|
+
* publishing it, which changes the provenance) before it can hold a token.
|
|
2441
|
+
*/
|
|
2442
|
+
|
|
2443
|
+
interface ConnectorInstallGate {
|
|
2444
|
+
/** The normal capability-consent decision (lines, danger, reprompt). */
|
|
2445
|
+
consent: ConsentDecision;
|
|
2446
|
+
/** Whether the connector may install after the normal consent flow. */
|
|
2447
|
+
installable: boolean;
|
|
2448
|
+
/** Why it is not installable (requires manual promotion), when blocked. */
|
|
2449
|
+
blockedReason?: string;
|
|
2450
|
+
}
|
|
2451
|
+
/**
|
|
2452
|
+
* Evaluate whether a connector may install given its provenance + capabilities.
|
|
2453
|
+
* Returns the consent decision plus a hard gate that blocks secret-holding
|
|
2454
|
+
* AI-generated connectors from auto-install.
|
|
2455
|
+
*/
|
|
2456
|
+
declare function evaluateConnectorInstall(provenance: InstallProvenance, capabilities: ModuleCapabilities | undefined): ConnectorInstallGate;
|
|
2457
|
+
|
|
2458
|
+
/**
|
|
2459
|
+
* @xnetjs/plugins — wrap an external CLI as a Connector (exploration 0196).
|
|
2460
|
+
*
|
|
2461
|
+
* The interop play: an existing agent-native CLI (e.g. a Printing Press tool)
|
|
2462
|
+
* becomes a governed Connector by running it and mapping its output into nodes.
|
|
2463
|
+
* The wrapper governs the **output mapping** — the synced schema, the target
|
|
2464
|
+
* Space, the write budget — so the agent reads policy-evaluated nodes instead of
|
|
2465
|
+
* the raw CLI.
|
|
2466
|
+
*
|
|
2467
|
+
* Honest caveat: the wrapped CLI is a subprocess that reaches the network itself,
|
|
2468
|
+
* so its *egress* is NOT enforced by `guardedFetch`. `network` here is for the
|
|
2469
|
+
* consent/marketplace display; a wrapped CLI should be a trusted, clearly-labeled
|
|
2470
|
+
* tier. The `runCli` port is injected (no `@xnetjs/devkit` edge here), so the
|
|
2471
|
+
* caller decides how the CLI actually runs (and can sandbox it).
|
|
2472
|
+
*/
|
|
2473
|
+
|
|
2474
|
+
interface WrapCliConnectorOptions {
|
|
2475
|
+
/** Reverse-domain id, e.g. `dev.acme.connector.wikipedia-cli`. */
|
|
2476
|
+
id: string;
|
|
2477
|
+
name: string;
|
|
2478
|
+
version?: string;
|
|
2479
|
+
author?: string;
|
|
2480
|
+
description?: string;
|
|
2481
|
+
/** The schema each parsed record is materialized as. */
|
|
2482
|
+
schema: string;
|
|
2483
|
+
/** Hosts the CLI reaches — for display only (subprocess egress is not enforced). */
|
|
2484
|
+
network: string[];
|
|
2485
|
+
/** Secrets the CLI needs (held by the hub broker). */
|
|
2486
|
+
secrets?: string[];
|
|
2487
|
+
/** The Space relation property to stamp (default `space`). */
|
|
2488
|
+
spaceProperty?: string;
|
|
2489
|
+
/** Run the external CLI and return its stdout. Injected (e.g. a CommandRunner). */
|
|
2490
|
+
runCli: () => Promise<string>;
|
|
2491
|
+
/** Parse the CLI stdout into records; each becomes one node's properties. */
|
|
2492
|
+
parse: (stdout: string) => Array<Record<string, unknown>>;
|
|
2493
|
+
/** Optional agent tools over the synced nodes. */
|
|
2494
|
+
agentTools?: AgentToolContribution[];
|
|
2495
|
+
}
|
|
2496
|
+
/**
|
|
2497
|
+
* Produce a governed Connector that runs an external CLI and maps its output
|
|
2498
|
+
* into nodes. The CLI runs once per sync; each parsed record is written through
|
|
2499
|
+
* the guarded, space-stamped, budget-charged store.
|
|
2500
|
+
*/
|
|
2501
|
+
declare function wrapCliConnector(options: WrapCliConnectorOptions): DefinedConnector;
|
|
2502
|
+
|
|
2503
|
+
/**
|
|
2504
|
+
* @xnetjs/plugins — the Slack migration connector (exploration 0198).
|
|
2505
|
+
*
|
|
2506
|
+
* "Switch from Slack to XNet and bring my data with me." This is the Half-1
|
|
2507
|
+
* answer from exploration 0198: a {@link defineConnector} that pulls a Slack
|
|
2508
|
+
* workspace's channels and message history into XNet's native `Channel` and
|
|
2509
|
+
* `ChatMessage` nodes, through the guarded connector store (egress-contained to
|
|
2510
|
+
* `slack.com`, space-stamped, budget-charged). The Slack token lives in the hub
|
|
2511
|
+
* broker and never reaches the agent — it only ever sees the synced nodes.
|
|
2512
|
+
*
|
|
2513
|
+
* Message bodies are translated to GitHub-flavored markdown via
|
|
2514
|
+
* `@xnetjs/slack-compat` (Block Kit first, then `mrkdwn`), so they render
|
|
2515
|
+
* natively in XNet chat. Pagination, DMs, files and reactions are deferred (see
|
|
2516
|
+
* the exploration's checklist).
|
|
2517
|
+
*/
|
|
2518
|
+
|
|
2519
|
+
/** Default reverse-domain id; matches the worked example in the connector docs. */
|
|
2520
|
+
declare const SLACK_CONNECTOR_ID = "dev.xnet.connector.slack";
|
|
2521
|
+
declare const CHANNEL_SCHEMA = "xnet://xnet.fyi/Channel@1.0.0";
|
|
2522
|
+
declare const CHAT_MESSAGE_SCHEMA = "xnet://xnet.fyi/ChatMessage@1.0.0";
|
|
2523
|
+
interface SlackConnectorOptions {
|
|
2524
|
+
/** Override the connector id (default {@link SLACK_CONNECTOR_ID}). */
|
|
2525
|
+
id?: string;
|
|
2526
|
+
/**
|
|
2527
|
+
* Backing for the `slack_search_messages` agent tool. When provided, the
|
|
2528
|
+
* connector contributes a model-facing search over the imported messages;
|
|
2529
|
+
* when omitted, no agent tool is contributed (pull-only migration).
|
|
2530
|
+
*/
|
|
2531
|
+
search?: (args: {
|
|
2532
|
+
query: string;
|
|
2533
|
+
}) => unknown | Promise<unknown>;
|
|
2534
|
+
}
|
|
2535
|
+
/**
|
|
2536
|
+
* Build the Slack migration connector. The `pull` imports channels +
|
|
2537
|
+
* history into `Channel`/`ChatMessage` nodes via the guarded store.
|
|
2538
|
+
*/
|
|
2539
|
+
declare function buildSlackConnector(options?: SlackConnectorOptions): DefinedConnector;
|
|
2540
|
+
|
|
2541
|
+
/**
|
|
2542
|
+
* @xnetjs/plugins — the RSS / Atom connector (exploration 0213).
|
|
2543
|
+
*
|
|
2544
|
+
* The zero-auth, hobbyist-loved integration: poll a feed URL and materialize
|
|
2545
|
+
* each entry as a governed `FeedItem` node through the guarded connector store.
|
|
2546
|
+
* The parser is dependency-free (a small, defensive RSS+Atom extractor) so the
|
|
2547
|
+
* package keeps its no-runtime-deps posture. `guid` carries the feed entry's
|
|
2548
|
+
* stable id so a host can de-duplicate across polls.
|
|
2549
|
+
*/
|
|
2550
|
+
|
|
2551
|
+
declare const RSS_CONNECTOR_ID = "dev.xnet.connector.rss";
|
|
2552
|
+
declare const FEED_ITEM_SCHEMA = "xnet://xnet.fyi/FeedItem@1.0.0";
|
|
2553
|
+
/** One normalized feed entry (RSS `<item>` or Atom `<entry>`). */
|
|
2554
|
+
interface FeedEntry {
|
|
2555
|
+
title: string;
|
|
2556
|
+
link?: string;
|
|
2557
|
+
guid?: string;
|
|
2558
|
+
summary?: string;
|
|
2559
|
+
publishedAt?: number;
|
|
2560
|
+
}
|
|
2561
|
+
/**
|
|
2562
|
+
* Parse an RSS or Atom document into normalized entries. Defensive by design:
|
|
2563
|
+
* malformed or unknown markup yields fewer entries rather than throwing, and the
|
|
2564
|
+
* scan is linear so a hostile feed cannot pin the event loop.
|
|
2565
|
+
*/
|
|
2566
|
+
declare function parseFeed(xml: string): FeedEntry[];
|
|
2567
|
+
interface RssConnectorOptions {
|
|
2568
|
+
/** The RSS/Atom feed URL to poll. Its host becomes the sole `network` grant. */
|
|
2569
|
+
feedUrl: string;
|
|
2570
|
+
/** Override the connector id (default {@link RSS_CONNECTOR_ID}). */
|
|
2571
|
+
id?: string;
|
|
2572
|
+
/** The `Feed` node id every item links back to (optional). */
|
|
2573
|
+
feedNodeId?: string;
|
|
2574
|
+
/** Backing for an optional `rss_search_items` agent tool. */
|
|
2575
|
+
search?: (args: {
|
|
2576
|
+
query: string;
|
|
2577
|
+
}) => unknown | Promise<unknown>;
|
|
2578
|
+
}
|
|
2579
|
+
/**
|
|
2580
|
+
* Build the RSS/Atom connector. The `pull` polls one feed URL and materializes
|
|
2581
|
+
* its entries into `FeedItem` nodes via the guarded store.
|
|
2582
|
+
*/
|
|
2583
|
+
declare function buildRssConnector(options: RssConnectorOptions): DefinedConnector;
|
|
2584
|
+
|
|
2585
|
+
/**
|
|
2586
|
+
* @xnetjs/plugins — API pull connectors: GitHub, Notion, Airtable
|
|
2587
|
+
* (exploration 0213).
|
|
2588
|
+
*
|
|
2589
|
+
* The API-key tier of the integration catalog. Each polls a service's REST API
|
|
2590
|
+
* and materializes objects into the generic, governed `ExternalItem` node
|
|
2591
|
+
* (source / kind / externalId / title / url / status / raw), through the guarded
|
|
2592
|
+
* connector store — the credential stays in the hub broker; the agent only ever
|
|
2593
|
+
* sees the synced nodes. Schema IRIs are inlined (matching `slack-migration`) so
|
|
2594
|
+
* the package keeps no `@xnetjs/data` dependency.
|
|
2595
|
+
*
|
|
2596
|
+
* Robustness (0213 review): each pull (1) requires its declared secret to be
|
|
2597
|
+
* present (a misconfiguration is a loud error, not a silent `Bearer ` request),
|
|
2598
|
+
* (2) throws on a non-2xx response instead of returning `{ written: 0 }`, and
|
|
2599
|
+
* (3) follows the provider's pagination so it doesn't silently cap at one page.
|
|
2600
|
+
*/
|
|
2601
|
+
|
|
2602
|
+
declare const EXTERNAL_ITEM_SCHEMA = "xnet://xnet.fyi/ExternalItem@1.0.0";
|
|
2603
|
+
interface ApiConnectorBaseOptions {
|
|
2604
|
+
id?: string;
|
|
2605
|
+
search?: (args: {
|
|
2606
|
+
query: string;
|
|
2607
|
+
}) => unknown | Promise<unknown>;
|
|
2608
|
+
}
|
|
2609
|
+
declare const GITHUB_CONNECTOR_ID = "dev.xnet.connector.github";
|
|
2610
|
+
interface GithubConnectorOptions extends ApiConnectorBaseOptions {
|
|
2611
|
+
/** Repository owner (user or org). */
|
|
2612
|
+
owner: string;
|
|
2613
|
+
/** Repository name. */
|
|
2614
|
+
repo: string;
|
|
2615
|
+
}
|
|
2616
|
+
/**
|
|
2617
|
+
* Build the GitHub connector. Imports a repo's issues and pull requests
|
|
2618
|
+
* (`state=all`, all pages) into `ExternalItem` nodes via the GitHub REST API
|
|
2619
|
+
* (`GITHUB_TOKEN`).
|
|
2620
|
+
*/
|
|
2621
|
+
declare function buildGithubConnector(options: GithubConnectorOptions): DefinedConnector;
|
|
2622
|
+
declare const NOTION_CONNECTOR_ID = "dev.xnet.connector.notion";
|
|
2623
|
+
type NotionConnectorOptions = ApiConnectorBaseOptions;
|
|
2624
|
+
/**
|
|
2625
|
+
* Build the Notion connector. Imports pages the integration token can see (via
|
|
2626
|
+
* `/v1/search`, following `has_more`) into `ExternalItem` nodes (`NOTION_TOKEN`).
|
|
2627
|
+
*/
|
|
2628
|
+
declare function buildNotionConnector(options?: NotionConnectorOptions): DefinedConnector;
|
|
2629
|
+
declare const AIRTABLE_CONNECTOR_ID = "dev.xnet.connector.airtable";
|
|
2630
|
+
interface AirtableConnectorOptions extends ApiConnectorBaseOptions {
|
|
2631
|
+
/** The Airtable base id (`app...`). */
|
|
2632
|
+
baseId: string;
|
|
2633
|
+
/** The table id or name. */
|
|
2634
|
+
tableId: string;
|
|
2635
|
+
}
|
|
2636
|
+
/**
|
|
2637
|
+
* Build the Airtable connector. Imports a table's records (following the
|
|
2638
|
+
* `offset` cursor) into `ExternalItem` nodes, preserving each record's fields in
|
|
2639
|
+
* `raw` (`AIRTABLE_TOKEN`).
|
|
2640
|
+
*/
|
|
2641
|
+
declare function buildAirtableConnector(options: AirtableConnectorOptions): DefinedConnector;
|
|
2642
|
+
declare const LINEAR_CONNECTOR_ID = "dev.xnet.connector.linear";
|
|
2643
|
+
type LinearConnectorOptions = ApiConnectorBaseOptions;
|
|
2644
|
+
/**
|
|
2645
|
+
* Build the Linear connector. Imports issues via Linear's GraphQL API (following
|
|
2646
|
+
* the `pageInfo` cursor) into `ExternalItem` nodes (`LINEAR_API_KEY`). Personal
|
|
2647
|
+
* API keys go in the `Authorization` header verbatim (no `Bearer` prefix).
|
|
2648
|
+
*/
|
|
2649
|
+
declare function buildLinearConnector(options?: LinearConnectorOptions): DefinedConnector;
|
|
2650
|
+
|
|
2651
|
+
/**
|
|
2652
|
+
* @xnetjs/plugins — network endowment (exploration 0192).
|
|
2653
|
+
*
|
|
2654
|
+
* The capability guard ({@link ../ecosystem/capability-guard}) closes the
|
|
2655
|
+
* `schemaWrite` hole at the store boundary. This closes the `network` hole at
|
|
2656
|
+
* the fetch boundary: a plugin that wants to reach the network gets a
|
|
2657
|
+
* `guardedFetch` whose every request is checked against its declared `network`
|
|
2658
|
+
* allowlist (`isNetworkAllowed`), so a plugin can only talk to the hosts it
|
|
2659
|
+
* declared — and a plugin that declared none gets no egress at all.
|
|
2660
|
+
*
|
|
2661
|
+
* Like `guardStore`, this is the one handle a plugin should receive instead of
|
|
2662
|
+
* the ambient `fetch`; the host injects it as the `network` endowment.
|
|
2663
|
+
*/
|
|
2664
|
+
|
|
2665
|
+
/** The subset of the `fetch` signature we wrap (kept structural, no DOM types). */
|
|
2666
|
+
type FetchLike = (input: string | {
|
|
2667
|
+
url: string;
|
|
2668
|
+
}, init?: unknown) => Promise<unknown>;
|
|
2669
|
+
/**
|
|
2670
|
+
* Wrap a `fetch` implementation so every request host is checked against the
|
|
2671
|
+
* plugin's declared `network` capability. Throws `CapabilityError` before the
|
|
2672
|
+
* request leaves if the host isn't allowed. A plugin with no `network` grant
|
|
2673
|
+
* can reach nothing (closed by default) — the wrapper still returns, but every
|
|
2674
|
+
* call throws until a host is declared.
|
|
2675
|
+
*
|
|
2676
|
+
* @param caps the plugin's declared capability grant
|
|
2677
|
+
* @param pluginId for error attribution
|
|
2678
|
+
* @param fetchImpl the underlying fetch (defaults to `globalThis.fetch`)
|
|
2679
|
+
*/
|
|
2680
|
+
declare function guardedFetch(caps: ModuleCapabilities | undefined, pluginId: string, fetchImpl?: FetchLike): FetchLike;
|
|
2681
|
+
|
|
2682
|
+
/**
|
|
2683
|
+
* @xnetjs/plugins — the outbound Action primitive (exploration 0213).
|
|
2684
|
+
*
|
|
2685
|
+
* Connectors *pull* an external service into nodes; an Action is the reverse —
|
|
2686
|
+
* "when something happens in xNet, reach out." It is the other half of the
|
|
2687
|
+
* Zapier/IFTTT story (post to Discord on task close, send an email, hit a
|
|
2688
|
+
* webhook) and the symmetric twin of {@link ../connectors/define-connector}:
|
|
2689
|
+
*
|
|
2690
|
+
* 1. a `capabilities` manifest — `network` (where it may POST, closed by
|
|
2691
|
+
* default) and `secrets` (held by the hub broker, e.g. a Discord webhook
|
|
2692
|
+
* URL or a bot token);
|
|
2693
|
+
* 2. a `trigger` declaring what fires it (a node change on given schemas, a
|
|
2694
|
+
* schedule, or manual); and
|
|
2695
|
+
* 3. a `dispatch(event, ctx)` that does the outbound call through a guarded,
|
|
2696
|
+
* SSRF-checked `fetch`.
|
|
2697
|
+
*
|
|
2698
|
+
* Like a Connector it produces a `FeatureModule` (so it installs, consents, and
|
|
2699
|
+
* ships through the marketplace), with the hub half wired by convention under
|
|
2700
|
+
* `<id>.trigger`. The guards are enforced by composition in the action runner
|
|
2701
|
+
* (see {@link ./runner}); this module is just the shape + validation.
|
|
2702
|
+
*/
|
|
2703
|
+
|
|
2704
|
+
/** What fires an action. */
|
|
2705
|
+
type ActionTrigger = {
|
|
2706
|
+
kind: 'schema-change';
|
|
2707
|
+
schemas: string[];
|
|
2708
|
+
} | {
|
|
2709
|
+
kind: 'schedule';
|
|
2710
|
+
cadence: ConnectorCadence;
|
|
2711
|
+
} | {
|
|
2712
|
+
kind: 'manual';
|
|
2713
|
+
};
|
|
2714
|
+
/** The change that triggered a dispatch (schema-change triggers carry a node). */
|
|
2715
|
+
interface ActionEvent {
|
|
2716
|
+
trigger: 'schema-change' | 'schedule' | 'manual';
|
|
2717
|
+
/** Change kind for schema-change events. */
|
|
2718
|
+
change?: 'create' | 'update' | 'delete';
|
|
2719
|
+
/** The affected node for schema-change events. */
|
|
2720
|
+
node?: {
|
|
2721
|
+
id: string;
|
|
2722
|
+
schemaId: string;
|
|
2723
|
+
properties?: Record<string, unknown>;
|
|
2724
|
+
};
|
|
2725
|
+
}
|
|
2726
|
+
/** Context handed to `dispatch`: scoped secrets + a guarded, SSRF-checked fetch. */
|
|
2727
|
+
interface ActionContext {
|
|
2728
|
+
/** Broker-scoped env — only the keys declared in `capabilities.secrets`. */
|
|
2729
|
+
env: Record<string, string | undefined>;
|
|
2730
|
+
/** Guarded fetch — egress limited to `capabilities.network`, SSRF-checked. */
|
|
2731
|
+
fetch: FetchLike;
|
|
2732
|
+
}
|
|
2733
|
+
interface ActionDefinition {
|
|
2734
|
+
/** Reverse-domain id, e.g. `dev.xnet.action.discord`. */
|
|
2735
|
+
id: string;
|
|
2736
|
+
name: string;
|
|
2737
|
+
version?: string;
|
|
2738
|
+
author?: string;
|
|
2739
|
+
description?: string;
|
|
2740
|
+
/** Capability surface — `network` is required (closed by default). */
|
|
2741
|
+
capabilities: ModuleCapabilities & {
|
|
2742
|
+
network: string[];
|
|
2743
|
+
};
|
|
2744
|
+
/** What fires this action. */
|
|
2745
|
+
trigger: ActionTrigger;
|
|
2746
|
+
/** Perform the outbound call. Runs hub-side with scoped secrets. */
|
|
2747
|
+
dispatch(event: ActionEvent, ctx: ActionContext): Promise<void>;
|
|
2748
|
+
/** Optional model-facing tools (e.g. a manual "send now"). */
|
|
2749
|
+
agentTools?: AgentToolContribution[];
|
|
2750
|
+
}
|
|
2751
|
+
/** The product of {@link defineAction}. */
|
|
2752
|
+
interface DefinedAction {
|
|
2753
|
+
module: FeatureModule;
|
|
2754
|
+
trigger: ActionTrigger;
|
|
2755
|
+
dispatch: ActionDefinition['dispatch'];
|
|
2756
|
+
agentTools: AgentToolContribution[];
|
|
2757
|
+
definition: ActionDefinition;
|
|
2758
|
+
}
|
|
2759
|
+
declare class ActionDefinitionError extends Error {
|
|
2760
|
+
constructor(message: string);
|
|
2761
|
+
}
|
|
2762
|
+
/**
|
|
2763
|
+
* Whether `action`'s trigger should fire for `event`. The "when X happens"
|
|
2764
|
+
* decision, kept pure so a host can fan an event out to matching actions.
|
|
2765
|
+
*/
|
|
2766
|
+
declare function shouldDispatch(trigger: ActionTrigger, event: ActionEvent): boolean;
|
|
2767
|
+
/**
|
|
2768
|
+
* Define an outbound Action. Validates the capability/trigger coherence (a
|
|
2769
|
+
* network host is declared; a schema-change trigger lists schemas) and produces
|
|
2770
|
+
* a `FeatureModule` whose `hub.featureId` points at `<id>.trigger`.
|
|
2771
|
+
*
|
|
2772
|
+
* @throws {ActionDefinitionError} when the definition is incoherent.
|
|
2773
|
+
*/
|
|
2774
|
+
declare function defineAction(def: ActionDefinition): DefinedAction;
|
|
2775
|
+
|
|
2776
|
+
/**
|
|
2777
|
+
* @xnetjs/plugins — outbound action runner (exploration 0213).
|
|
2778
|
+
*
|
|
2779
|
+
* Runs an action's `dispatch` with the guards composed, so the *author* writes a
|
|
2780
|
+
* plain `fetch(...)` and the *framework* guarantees:
|
|
2781
|
+
*
|
|
2782
|
+
* - **egress containment** — `fetch` is `guardedFetch`, limited to the declared
|
|
2783
|
+
* `capabilities.network`;
|
|
2784
|
+
* - **SSRF protection** — every request URL is `assertPublicUrl`-checked, so a
|
|
2785
|
+
* user-configured target cannot reach localhost, RFC-1918, or cloud metadata
|
|
2786
|
+
* even if the host was allowlisted via the configured URL.
|
|
2787
|
+
*
|
|
2788
|
+
* Secret scoping is the hub's job (a `scopedEnv` is passed in), keeping the
|
|
2789
|
+
* dependency direction clean (no `@xnetjs/plugins` → `@xnetjs/hub` edge).
|
|
2790
|
+
*/
|
|
2791
|
+
|
|
2792
|
+
declare class ActionDispatchError extends Error {
|
|
2793
|
+
constructor(message: string);
|
|
2794
|
+
}
|
|
2795
|
+
interface RunActionPorts {
|
|
2796
|
+
/** Broker-scoped env (the hub scopes it; tests pass a minimal object). */
|
|
2797
|
+
env: Record<string, string | undefined>;
|
|
2798
|
+
/** Underlying fetch — wrapped (network allowlist + SSRF) before `dispatch`. */
|
|
2799
|
+
fetch: FetchLike;
|
|
2800
|
+
}
|
|
2801
|
+
/**
|
|
2802
|
+
* Wrap a fetch so every outbound action request is (1) within the declared
|
|
2803
|
+
* `network` allowlist and (2) not pointed at a non-public host (SSRF).
|
|
2804
|
+
*/
|
|
2805
|
+
declare function guardedActionFetch(def: Pick<ActionDefinition, 'id' | 'capabilities'>, fetchImpl: FetchLike): FetchLike;
|
|
2806
|
+
/**
|
|
2807
|
+
* Run one action's `dispatch` with the guards composed. The author never sees
|
|
2808
|
+
* the raw fetch or the full env.
|
|
2809
|
+
*/
|
|
2810
|
+
declare function runAction(action: DefinedAction, event: ActionEvent, ports: RunActionPorts): Promise<void>;
|
|
2811
|
+
|
|
2812
|
+
/**
|
|
2813
|
+
* @xnetjs/plugins — SSRF guard for outbound actions (exploration 0213).
|
|
2814
|
+
*
|
|
2815
|
+
* Outbound actions POST to URLs that may be user-configured (a generic
|
|
2816
|
+
* webhook-out target). Even when the host is "allowlisted" (the action derived
|
|
2817
|
+
* its `network` grant from the configured URL), a user could point it at an
|
|
2818
|
+
* internal target — `http://169.254.169.254/` (cloud metadata), `localhost`, a
|
|
2819
|
+
* private RFC-1918 range — to exfiltrate credentials or reach internal
|
|
2820
|
+
* services. {@link assertPublicUrl} rejects those before the request leaves.
|
|
2821
|
+
*
|
|
2822
|
+
* This is a *literal-host* guard (scheme + hostname/IP inspection), not a
|
|
2823
|
+
* post-DNS-resolution guard: a hostname that resolves to a private IP at
|
|
2824
|
+
* request time is not caught here. That deeper check belongs in the fetch
|
|
2825
|
+
* implementation; this closes the common, cheap holes by construction.
|
|
494
2826
|
*/
|
|
495
|
-
declare class
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
/**
|
|
499
|
-
* Register a command with a keyboard shortcut.
|
|
500
|
-
*
|
|
501
|
-
* @param command - Command with keybinding
|
|
502
|
-
* @returns Disposable to unregister the shortcut
|
|
503
|
-
*/
|
|
504
|
-
register(command: CommandContribution): Disposable$1;
|
|
505
|
-
/**
|
|
506
|
-
* Unregister a command by ID.
|
|
507
|
-
*/
|
|
508
|
-
unregister(commandId: string): boolean;
|
|
509
|
-
/**
|
|
510
|
-
* Handle a keyboard event.
|
|
511
|
-
*
|
|
512
|
-
* @param event - Keyboard event
|
|
513
|
-
* @returns True if a shortcut was triggered
|
|
514
|
-
*/
|
|
515
|
-
handleKeyDown(event: KeyboardEvent): boolean;
|
|
516
|
-
/**
|
|
517
|
-
* Enable or disable shortcut handling.
|
|
518
|
-
*/
|
|
519
|
-
setEnabled(enabled: boolean): void;
|
|
520
|
-
/**
|
|
521
|
-
* Check if shortcuts are enabled.
|
|
522
|
-
*/
|
|
523
|
-
isEnabled(): boolean;
|
|
524
|
-
/**
|
|
525
|
-
* Get all registered shortcuts.
|
|
526
|
-
*/
|
|
527
|
-
getAll(): CommandContribution[];
|
|
528
|
-
/**
|
|
529
|
-
* Get the shortcut for a command ID.
|
|
530
|
-
*/
|
|
531
|
-
getShortcut(commandId: string): string | undefined;
|
|
532
|
-
/**
|
|
533
|
-
* Format a keybinding for display (using platform-specific symbols).
|
|
534
|
-
*/
|
|
535
|
-
formatForDisplay(keybinding: string): string;
|
|
536
|
-
/**
|
|
537
|
-
* Normalize a keybinding string for consistent lookup.
|
|
538
|
-
*/
|
|
539
|
-
private normalize;
|
|
540
|
-
/**
|
|
541
|
-
* Convert normalized form back to display form.
|
|
542
|
-
*/
|
|
543
|
-
private denormalize;
|
|
544
|
-
/**
|
|
545
|
-
* Convert a keyboard event to a normalized string.
|
|
546
|
-
*/
|
|
547
|
-
private eventToString;
|
|
548
|
-
/**
|
|
549
|
-
* Clear all registered shortcuts.
|
|
550
|
-
*/
|
|
551
|
-
clear(): void;
|
|
2827
|
+
declare class ActionSsrfError extends Error {
|
|
2828
|
+
readonly url: string;
|
|
2829
|
+
constructor(message: string, url: string);
|
|
552
2830
|
}
|
|
553
2831
|
/**
|
|
554
|
-
*
|
|
2832
|
+
* Throw {@link ActionSsrfError} unless `rawUrl` is a plausibly-public HTTP(S)
|
|
2833
|
+
* endpoint: rejects non-http(s) schemes, localhost, `.local`/`.internal`
|
|
2834
|
+
* suffixes, the cloud metadata host, and private/loopback/link-local IP
|
|
2835
|
+
* literals (v4 and v6).
|
|
555
2836
|
*/
|
|
556
|
-
declare function
|
|
2837
|
+
declare function assertPublicUrl(rawUrl: string): void;
|
|
2838
|
+
|
|
557
2839
|
/**
|
|
558
|
-
*
|
|
559
|
-
*
|
|
2840
|
+
* @xnetjs/plugins — first-party outbound actions (exploration 0213).
|
|
2841
|
+
*
|
|
2842
|
+
* The Top-5/Top-10 notification sinks built on {@link defineAction}: Discord and
|
|
2843
|
+
* Slack incoming webhooks, Telegram bots, transactional email (Resend), and a
|
|
2844
|
+
* generic webhook-out that bridges Zapier/Make/n8n. Each reads its credential
|
|
2845
|
+
* from the broker-scoped env, renders the triggering event to a message, and
|
|
2846
|
+
* POSTs through the guarded, SSRF-checked fetch. Hosts are declared at build
|
|
2847
|
+
* time so egress stays closed-by-default; the generic webhook-out locks its
|
|
2848
|
+
* `network` grant to the configured URL's host.
|
|
560
2849
|
*/
|
|
561
|
-
|
|
2850
|
+
|
|
2851
|
+
/** A compact, human-readable summary of the triggering event. */
|
|
2852
|
+
declare function renderEvent(event: ActionEvent): string;
|
|
2853
|
+
interface BaseActionOptions {
|
|
2854
|
+
/** Override the connector-style id. */
|
|
2855
|
+
id?: string;
|
|
2856
|
+
/** What fires the action (default: manual). */
|
|
2857
|
+
trigger?: ActionTrigger;
|
|
2858
|
+
/** Render the event to a message (default {@link renderEvent}). */
|
|
2859
|
+
render?: (event: ActionEvent) => string;
|
|
2860
|
+
}
|
|
2861
|
+
/** Discord: POST `{ content }` to an incoming-webhook URL (`DISCORD_WEBHOOK_URL`). */
|
|
2862
|
+
declare function buildDiscordAction(options?: BaseActionOptions): DefinedAction;
|
|
2863
|
+
/** Slack: POST `{ text }` to an incoming-webhook URL (`SLACK_WEBHOOK_URL`). */
|
|
2864
|
+
declare function buildSlackWebhookAction(options?: BaseActionOptions): DefinedAction;
|
|
2865
|
+
/** Telegram: send a message via the Bot API (`TELEGRAM_BOT_TOKEN`/`TELEGRAM_CHAT_ID`). */
|
|
2866
|
+
declare function buildTelegramAction(options?: BaseActionOptions): DefinedAction;
|
|
2867
|
+
interface EmailActionOptions extends BaseActionOptions {
|
|
2868
|
+
/** Verified sender, e.g. `xNet <alerts@example.com>`. */
|
|
2869
|
+
from: string;
|
|
2870
|
+
/** Recipient address(es). */
|
|
2871
|
+
to: string | string[];
|
|
2872
|
+
/** Subject line (default: a short event summary). */
|
|
2873
|
+
subject?: string;
|
|
2874
|
+
}
|
|
2875
|
+
/** Email (Resend): send a transactional email (`RESEND_API_KEY`). */
|
|
2876
|
+
declare function buildEmailAction(options: EmailActionOptions): DefinedAction;
|
|
2877
|
+
interface WebhookOutOptions extends BaseActionOptions {
|
|
2878
|
+
/** The destination URL. Its host becomes the action's sole `network` grant. */
|
|
2879
|
+
url: string;
|
|
2880
|
+
/** Transform the event into the POST body (default: the event itself). */
|
|
2881
|
+
transform?: (event: ActionEvent) => unknown;
|
|
2882
|
+
/** Extra request headers. */
|
|
2883
|
+
headers?: Record<string, string>;
|
|
2884
|
+
}
|
|
2885
|
+
/**
|
|
2886
|
+
* Generic webhook-out: POST each triggering event as JSON to a configured URL —
|
|
2887
|
+
* the escape hatch that bridges Zapier/Make/n8n/IFTTT. The `network` grant is
|
|
2888
|
+
* locked to the URL's host (and the SSRF guard still blocks internal targets).
|
|
2889
|
+
*/
|
|
2890
|
+
declare function buildWebhookOutAction(options: WebhookOutOptions): DefinedAction;
|
|
562
2891
|
|
|
563
2892
|
/**
|
|
564
2893
|
* PluginRegistry - Central coordinator for plugin lifecycle
|
|
@@ -570,10 +2899,49 @@ interface RegisteredPlugin {
|
|
|
570
2899
|
status: PluginStatus;
|
|
571
2900
|
context?: ExtensionContext;
|
|
572
2901
|
error?: Error;
|
|
2902
|
+
/** Where this plugin was installed from — derives its trust tier (0192). */
|
|
2903
|
+
provenance?: InstallProvenance;
|
|
2904
|
+
/** Provenance-derived execution trust tier (0192). */
|
|
2905
|
+
trustTier?: TrustTier;
|
|
2906
|
+
}
|
|
2907
|
+
/**
|
|
2908
|
+
* Result of a paid-plugin license check (exploration 0196). The host wires this
|
|
2909
|
+
* to `@xnetjs/licenses`' `checkLicenseFor`; the plugin package stays free of a
|
|
2910
|
+
* hard dependency on the license verifier.
|
|
2911
|
+
*/
|
|
2912
|
+
interface LicenseCheckResult {
|
|
2913
|
+
/** `true` if the buyer holds a valid license for this plugin. */
|
|
2914
|
+
ok: boolean;
|
|
2915
|
+
/** Why it failed (`no-license`, `expired`, `bad-signature`, …) — surfaced to UI. */
|
|
2916
|
+
reason?: string;
|
|
2917
|
+
}
|
|
2918
|
+
/** Options for {@link PluginRegistry.install} (all optional, back-compatible). */
|
|
2919
|
+
interface InstallOptions {
|
|
2920
|
+
/** Where the plugin came from. Drives trust tier + consent. Default `imported`. */
|
|
2921
|
+
provenance?: InstallProvenance;
|
|
2922
|
+
/** Host app version, for the `xnetVersion` compatibility gate. Skipped if absent. */
|
|
2923
|
+
hostVersion?: string;
|
|
2924
|
+
/**
|
|
2925
|
+
* Consent callback. Called only when provenance requires a re-prompt and the
|
|
2926
|
+
* plugin actually requests capabilities. Return `false` to abort the install.
|
|
2927
|
+
*/
|
|
2928
|
+
onConsent?: (decision: ConsentDecision) => boolean | Promise<boolean>;
|
|
2929
|
+
/**
|
|
2930
|
+
* Paid-license callback (exploration 0196). Called only when the manifest's
|
|
2931
|
+
* `pricing` is non-free. Return `{ ok: false }` to block the install with a
|
|
2932
|
+
* {@link LicenseRequiredError}. Absent ⇒ paid plugins are blocked (fail-closed).
|
|
2933
|
+
*/
|
|
2934
|
+
checkLicense?: (manifest: XNetExtension) => LicenseCheckResult | Promise<LicenseCheckResult>;
|
|
573
2935
|
}
|
|
574
2936
|
declare class PluginError extends Error {
|
|
575
2937
|
constructor(message: string);
|
|
576
2938
|
}
|
|
2939
|
+
/** Thrown when a paid plugin is installed without a valid license (0196). */
|
|
2940
|
+
declare class LicenseRequiredError extends PluginError {
|
|
2941
|
+
readonly pluginId: string;
|
|
2942
|
+
readonly reason: string;
|
|
2943
|
+
constructor(pluginId: string, reason: string);
|
|
2944
|
+
}
|
|
577
2945
|
/**
|
|
578
2946
|
* Manages plugin lifecycle: install, activate, deactivate, uninstall
|
|
579
2947
|
*/
|
|
@@ -586,9 +2954,15 @@ declare class PluginRegistry {
|
|
|
586
2954
|
private listeners;
|
|
587
2955
|
constructor(store: NodeStore, platform: Platform);
|
|
588
2956
|
/**
|
|
589
|
-
* Install and activate a plugin
|
|
2957
|
+
* Install and activate a plugin.
|
|
2958
|
+
*
|
|
2959
|
+
* Beyond manifest/platform validation, install runs the 0192 trust gates:
|
|
2960
|
+
* host-version compatibility, dependency resolution, and (for non-local
|
|
2961
|
+
* provenance) capability consent. Provenance derives the plugin's trust tier.
|
|
590
2962
|
*/
|
|
591
|
-
install(manifest: XNetExtension): Promise<void>;
|
|
2963
|
+
install(manifest: XNetExtension, options?: InstallOptions): Promise<void>;
|
|
2964
|
+
/** Dependencies of `manifest` not satisfied by currently installed plugins. */
|
|
2965
|
+
private missingDependencies;
|
|
592
2966
|
/**
|
|
593
2967
|
* Activate an installed plugin
|
|
594
2968
|
*/
|
|
@@ -649,6 +3023,530 @@ declare class PluginRegistry {
|
|
|
649
3023
|
loadFromStore(): Promise<void>;
|
|
650
3024
|
}
|
|
651
3025
|
|
|
3026
|
+
/**
|
|
3027
|
+
* @xnetjs/plugins — capability enforcement (exploration 0192).
|
|
3028
|
+
*
|
|
3029
|
+
* 0189 added `ModuleCapabilities` (`schemaWrite`/`schemaRead`/`network`/…) as a
|
|
3030
|
+
* *declaration*. This module makes the declaration load-bearing: it turns the
|
|
3031
|
+
* declared grant into runtime gates.
|
|
3032
|
+
*
|
|
3033
|
+
* The enforcement point is the `NodeStore` handle a plugin receives in its
|
|
3034
|
+
* `ExtensionContext`. Plugins call `ctx.store.create/update/delete` directly, so
|
|
3035
|
+
* wrapping that handle is the one choke point a plugin cannot route around. We
|
|
3036
|
+
* wrap with a `Proxy` (rather than re-implementing the store) so the guard keeps
|
|
3037
|
+
* working as `NodeStore` grows methods — only `create`/`update`/`delete`/`get`/
|
|
3038
|
+
* `list` are intercepted; everything else passes straight through.
|
|
3039
|
+
*
|
|
3040
|
+
* A grant with neither `schemaWrite` nor `schemaRead` is unconstrained (the guard
|
|
3041
|
+
* returns the store untouched) — first-party/host code is meant to be unguarded.
|
|
3042
|
+
*/
|
|
3043
|
+
|
|
3044
|
+
/** Thrown when a plugin tries to act outside its declared capability grant. */
|
|
3045
|
+
declare class CapabilityError extends Error {
|
|
3046
|
+
readonly pluginId: string;
|
|
3047
|
+
readonly capability: 'schemaWrite' | 'schemaRead' | 'network';
|
|
3048
|
+
readonly target: string;
|
|
3049
|
+
constructor(message: string, pluginId: string, capability: 'schemaWrite' | 'schemaRead' | 'network', target: string);
|
|
3050
|
+
}
|
|
3051
|
+
/**
|
|
3052
|
+
* Match a schema IRI against a capability pattern. Supports:
|
|
3053
|
+
* - exact: `xnet://xnet.fyi/Task@1.0.0`
|
|
3054
|
+
* - all: `*`
|
|
3055
|
+
* - version wildcard: `xnet://xnet.fyi/Task@*` (any version of Task)
|
|
3056
|
+
* - prefix wildcard: `xnet://xnet.fyi/*` (any schema under an authority)
|
|
3057
|
+
*/
|
|
3058
|
+
declare function matchSchemaIri(pattern: string, iri: string): boolean;
|
|
3059
|
+
/** Whether the grant permits writing the given schema IRI. */
|
|
3060
|
+
declare function isSchemaWriteAllowed(caps: ModuleCapabilities | undefined, iri: string): boolean;
|
|
3061
|
+
/**
|
|
3062
|
+
* Whether the grant permits reading the given schema IRI. A grant that declares
|
|
3063
|
+
* no `schemaRead` does not restrict reads (reads are lower risk than writes;
|
|
3064
|
+
* restricting them is opt-in by declaring `schemaRead`).
|
|
3065
|
+
*/
|
|
3066
|
+
declare function isSchemaReadAllowed(caps: ModuleCapabilities | undefined, iri: string): boolean;
|
|
3067
|
+
/**
|
|
3068
|
+
* Whether the grant permits a network request to the given URL/host. A
|
|
3069
|
+
* `network` entry may be an exact host (`api.stripe.com`) or a leading-dot
|
|
3070
|
+
* suffix (`.stripe.com`, matching any subdomain). No declared `network` → no
|
|
3071
|
+
* egress permitted (closed by default).
|
|
3072
|
+
*/
|
|
3073
|
+
declare function isNetworkAllowed(caps: ModuleCapabilities | undefined, urlOrHost: string): boolean;
|
|
3074
|
+
/** Assert a schema write is permitted, or throw {@link CapabilityError}. */
|
|
3075
|
+
declare function assertSchemaWrite(caps: ModuleCapabilities | undefined, iri: string, pluginId: string): void;
|
|
3076
|
+
/** Assert a network request is permitted, or throw {@link CapabilityError}. */
|
|
3077
|
+
declare function assertNetwork(caps: ModuleCapabilities | undefined, urlOrHost: string, pluginId: string): void;
|
|
3078
|
+
/**
|
|
3079
|
+
* Wrap a NodeStore so writes are checked against the plugin's grant. Returns the
|
|
3080
|
+
* store unchanged when the grant constrains nothing. Generic over the concrete
|
|
3081
|
+
* store type so callers keep their `NodeStore` typing.
|
|
3082
|
+
*/
|
|
3083
|
+
declare function guardStore<T extends object>(store: T, caps: ModuleCapabilities | undefined, pluginId: string): T;
|
|
3084
|
+
|
|
3085
|
+
/**
|
|
3086
|
+
* @xnetjs/plugins — version compatibility (exploration 0192).
|
|
3087
|
+
*
|
|
3088
|
+
* A tiny, dependency-free semver subset — enough to gate plugin installs on the
|
|
3089
|
+
* host's `xnetVersion` and to detect available updates. We deliberately avoid
|
|
3090
|
+
* pulling in `semver` (a node-centric dep) for what is a handful of comparisons;
|
|
3091
|
+
* the manifest already only accepts `\d+\.\d+\.\d+`-shaped versions.
|
|
3092
|
+
*
|
|
3093
|
+
* Supported range syntax: `*` / `x` (any), exact `1.2.3`, `>=1.2.3`, `>1.2.3`,
|
|
3094
|
+
* `<=1.2.3`, `<1.2.3`, caret `^1.2.3`, tilde `~1.2.3`. Pre-release/build
|
|
3095
|
+
* metadata is ignored (compared on major.minor.patch only).
|
|
3096
|
+
*/
|
|
3097
|
+
interface SemVer {
|
|
3098
|
+
major: number;
|
|
3099
|
+
minor: number;
|
|
3100
|
+
patch: number;
|
|
3101
|
+
}
|
|
3102
|
+
/** Parse `1.2.3` (ignoring any `-pre`/`+build` suffix). Returns null if invalid. */
|
|
3103
|
+
declare function parseVersion(input: string): SemVer | null;
|
|
3104
|
+
/** Compare two versions: negative if a<b, 0 if equal, positive if a>b. */
|
|
3105
|
+
declare function compareVersions(a: SemVer, b: SemVer): number;
|
|
3106
|
+
/**
|
|
3107
|
+
* Whether `version` satisfies `range`. Unknown/unparseable ranges are treated as
|
|
3108
|
+
* "any" (`true`) so a missing `xnetVersion` never blocks an install; an explicit
|
|
3109
|
+
* but malformed bound also fails open by design (we cannot prove incompatibility).
|
|
3110
|
+
*/
|
|
3111
|
+
declare function satisfiesRange(version: string, range: string): boolean;
|
|
3112
|
+
/**
|
|
3113
|
+
* Whether a plugin declaring `requiredHostRange` (its `xnetVersion`) is
|
|
3114
|
+
* compatible with `hostVersion`. A plugin with no declared requirement is
|
|
3115
|
+
* always compatible.
|
|
3116
|
+
*/
|
|
3117
|
+
declare function isHostCompatible(requiredHostRange: string | undefined, hostVersion: string): boolean;
|
|
3118
|
+
/**
|
|
3119
|
+
* Whether `available` is a newer version than `installed` (a real update is
|
|
3120
|
+
* offerable). Returns false when either side is unparseable.
|
|
3121
|
+
*/
|
|
3122
|
+
declare function hasUpdate(installed: string, available: string): boolean;
|
|
3123
|
+
|
|
3124
|
+
/**
|
|
3125
|
+
* @xnetjs/plugins — inter-plugin dependencies (exploration 0192).
|
|
3126
|
+
*
|
|
3127
|
+
* A plugin may declare `dependencies: { '<pluginId>': '<versionRange>' }` in its
|
|
3128
|
+
* manifest. These helpers resolve a safe install order (topological sort),
|
|
3129
|
+
* detect cycles, and report missing/incompatible dependencies — the pure logic
|
|
3130
|
+
* an installer runs before activating a set of plugins.
|
|
3131
|
+
*
|
|
3132
|
+
* Kept structural (operates on a minimal `{ id, version, dependencies }` shape)
|
|
3133
|
+
* so it works for `XNetExtension` and `FeatureModule` alike.
|
|
3134
|
+
*/
|
|
3135
|
+
/** The minimal manifest shape the dependency resolver needs. */
|
|
3136
|
+
interface DependencyNode {
|
|
3137
|
+
id: string;
|
|
3138
|
+
version: string;
|
|
3139
|
+
dependencies?: Record<string, string>;
|
|
3140
|
+
}
|
|
3141
|
+
/** A dependency that is absent or version-incompatible among installed plugins. */
|
|
3142
|
+
interface MissingDependency {
|
|
3143
|
+
/** The plugin that declares the requirement. */
|
|
3144
|
+
dependent: string;
|
|
3145
|
+
/** The required plugin id. */
|
|
3146
|
+
required: string;
|
|
3147
|
+
/** The required version range. */
|
|
3148
|
+
range: string;
|
|
3149
|
+
/** Why it is unsatisfied. */
|
|
3150
|
+
reason: 'not-installed' | 'version-mismatch';
|
|
3151
|
+
/** The installed version, when present but mismatched. */
|
|
3152
|
+
installedVersion?: string;
|
|
3153
|
+
}
|
|
3154
|
+
/**
|
|
3155
|
+
* Report dependencies of `target` that are not satisfied by `installed`.
|
|
3156
|
+
* Satisfied = a plugin with the required id is installed AND its version
|
|
3157
|
+
* satisfies the declared range.
|
|
3158
|
+
*/
|
|
3159
|
+
declare function findMissingDependencies(target: DependencyNode, installed: readonly DependencyNode[]): MissingDependency[];
|
|
3160
|
+
/** Thrown when a dependency graph contains a cycle. */
|
|
3161
|
+
declare class DependencyCycleError extends Error {
|
|
3162
|
+
readonly cycle: string[];
|
|
3163
|
+
constructor(cycle: string[]);
|
|
3164
|
+
}
|
|
3165
|
+
/**
|
|
3166
|
+
* Return the ids in a safe install order (dependencies before dependents).
|
|
3167
|
+
* Only edges *within the provided set* are ordered; dependencies on plugins not
|
|
3168
|
+
* in the set are ignored here (use {@link findMissingDependencies} for those).
|
|
3169
|
+
*
|
|
3170
|
+
* @throws {DependencyCycleError} if the graph cannot be linearised.
|
|
3171
|
+
*/
|
|
3172
|
+
declare function resolveInstallOrder(nodes: readonly DependencyNode[]): string[];
|
|
3173
|
+
|
|
3174
|
+
/**
|
|
3175
|
+
* @xnetjs/plugins — supply-chain provenance verification (exploration 0192).
|
|
3176
|
+
*
|
|
3177
|
+
* The 2025–26 marketplace-malware wave (GlassWorm, OctoRAT, typosquats) taught
|
|
3178
|
+
* the field one thing: "Verified Publisher" badges verify domain ownership, not
|
|
3179
|
+
* code safety. The answer the JS ecosystem converged on is Sigstore-style
|
|
3180
|
+
* **provenance** — a keyless attestation that a package was built from a known
|
|
3181
|
+
* source by a known builder, logged in a transparency ledger (Rekor).
|
|
3182
|
+
*
|
|
3183
|
+
* This module defines the verification *contract* and a **fail-closed** default.
|
|
3184
|
+
* The actual Sigstore bundle verification (cosign/rekor) is a pluggable
|
|
3185
|
+
* `ProvenanceVerifier` — wired in where the crypto deps are acceptable
|
|
3186
|
+
* (publishing CI / desktop). The substrate is safe by default: with no verifier,
|
|
3187
|
+
* everything is reported `unverified`, and the install UI decides what to do
|
|
3188
|
+
* with that (warn / block) — it never silently treats unsigned code as trusted.
|
|
3189
|
+
*/
|
|
3190
|
+
/** A provenance attestation attached to a marketplace package. */
|
|
3191
|
+
interface Provenance {
|
|
3192
|
+
/** The Sigstore bundle (or a URL to it). */
|
|
3193
|
+
sigstoreBundle?: string;
|
|
3194
|
+
/** Rekor transparency-log index, if logged. */
|
|
3195
|
+
rekorLogIndex?: number;
|
|
3196
|
+
/** DID/identity of the builder (CI workflow identity). */
|
|
3197
|
+
builderDID?: string;
|
|
3198
|
+
/** Source repository the artifact was built from. */
|
|
3199
|
+
sourceRepo?: string;
|
|
3200
|
+
/** Source commit SHA. */
|
|
3201
|
+
sourceCommit?: string;
|
|
3202
|
+
/** SHA-256 digest of the manifest/artifact being attested. */
|
|
3203
|
+
artifactDigest?: string;
|
|
3204
|
+
}
|
|
3205
|
+
/** The outcome of verifying provenance for an artifact. */
|
|
3206
|
+
interface ProvenanceResult {
|
|
3207
|
+
/** True only when a verifier cryptographically confirmed the attestation. */
|
|
3208
|
+
verified: boolean;
|
|
3209
|
+
/** Why verification failed or what could not be confirmed. */
|
|
3210
|
+
reason?: string;
|
|
3211
|
+
/** Source repo, when confirmed. */
|
|
3212
|
+
sourceRepo?: string;
|
|
3213
|
+
/** Builder identity, when confirmed. */
|
|
3214
|
+
builderDID?: string;
|
|
3215
|
+
}
|
|
3216
|
+
/** The input to a verification: the attestation plus the artifact it covers. */
|
|
3217
|
+
interface VerifyProvenanceInput {
|
|
3218
|
+
provenance?: Provenance;
|
|
3219
|
+
/** SHA-256 digest computed locally over the fetched manifest/artifact. */
|
|
3220
|
+
artifactDigest: string;
|
|
3221
|
+
}
|
|
3222
|
+
/** A pluggable verifier (cosign/rekor under the hood). */
|
|
3223
|
+
interface ProvenanceVerifier {
|
|
3224
|
+
verify(input: VerifyProvenanceInput): Promise<ProvenanceResult>;
|
|
3225
|
+
}
|
|
3226
|
+
/**
|
|
3227
|
+
* The default verifier: **fails closed**. Absent a real cryptographic verifier,
|
|
3228
|
+
* nothing is "verified" — unsigned/unattested packages are reported as such so
|
|
3229
|
+
* the UI surfaces an explicit "unverified build" state rather than a false green.
|
|
3230
|
+
*/
|
|
3231
|
+
declare const failClosedVerifier: ProvenanceVerifier;
|
|
3232
|
+
/**
|
|
3233
|
+
* Verify provenance, defaulting to the fail-closed verifier. A convenience
|
|
3234
|
+
* wrapper so callers always get a `ProvenanceResult` (never an exception) and
|
|
3235
|
+
* unverified is the safe default.
|
|
3236
|
+
*/
|
|
3237
|
+
declare function verifyProvenance(input: VerifyProvenanceInput, verifier?: ProvenanceVerifier): Promise<ProvenanceResult>;
|
|
3238
|
+
/** A one-line human summary of a provenance result, for the consent dialog. */
|
|
3239
|
+
declare function summarizeProvenance(result: ProvenanceResult): string;
|
|
3240
|
+
|
|
3241
|
+
/**
|
|
3242
|
+
* @xnetjs/plugins — plugin authoring test kit (exploration 0192).
|
|
3243
|
+
*
|
|
3244
|
+
* A zero-setup harness so plugin authors can unit-test a manifest without a real
|
|
3245
|
+
* NodeStore or the app: spin up an in-memory store, install the plugin into a
|
|
3246
|
+
* real `PluginRegistry`, and assert on the contributions it registered. This is
|
|
3247
|
+
* the "@xnetjs/plugin-testing" surface, kept in-package to avoid a new workspace
|
|
3248
|
+
* dependency.
|
|
3249
|
+
*/
|
|
3250
|
+
|
|
3251
|
+
interface MemNode {
|
|
3252
|
+
id: string;
|
|
3253
|
+
schemaId: string;
|
|
3254
|
+
properties: Record<string, unknown>;
|
|
3255
|
+
deleted?: boolean;
|
|
3256
|
+
}
|
|
3257
|
+
type Listener = (event: unknown) => void;
|
|
3258
|
+
/** A minimal in-memory NodeStore good enough for plugin lifecycle tests. */
|
|
3259
|
+
interface TestNodeStore {
|
|
3260
|
+
create(options: {
|
|
3261
|
+
schemaId: string;
|
|
3262
|
+
properties?: Record<string, unknown>;
|
|
3263
|
+
}): Promise<MemNode>;
|
|
3264
|
+
get(id: string): Promise<MemNode | null>;
|
|
3265
|
+
update(id: string, options: {
|
|
3266
|
+
properties?: Record<string, unknown>;
|
|
3267
|
+
}): Promise<MemNode>;
|
|
3268
|
+
delete(id: string): Promise<void>;
|
|
3269
|
+
list(options?: {
|
|
3270
|
+
schemaId?: string;
|
|
3271
|
+
}): Promise<MemNode[]>;
|
|
3272
|
+
subscribe(listener: Listener): () => void;
|
|
3273
|
+
/** Test helper: how many live nodes exist (optionally for one schema). */
|
|
3274
|
+
count(schemaId?: string): number;
|
|
3275
|
+
}
|
|
3276
|
+
declare function createTestNodeStore(initial?: MemNode[]): TestNodeStore;
|
|
3277
|
+
interface TestPluginHarness {
|
|
3278
|
+
registry: PluginRegistry;
|
|
3279
|
+
store: TestNodeStore;
|
|
3280
|
+
/** Install a plugin and return its registered record. */
|
|
3281
|
+
install(manifest: XNetExtension): Promise<void>;
|
|
3282
|
+
}
|
|
3283
|
+
interface TestHarnessOptions {
|
|
3284
|
+
platform?: Platform;
|
|
3285
|
+
initialNodes?: MemNode[];
|
|
3286
|
+
}
|
|
3287
|
+
/**
|
|
3288
|
+
* Build a ready-to-use plugin test harness: an in-memory store wired into a real
|
|
3289
|
+
* `PluginRegistry`. Use it to install a plugin and assert on
|
|
3290
|
+
* `registry.getContributions()` or `registry.get(id)?.status`.
|
|
3291
|
+
*
|
|
3292
|
+
* @example
|
|
3293
|
+
* const h = createTestPluginHarness()
|
|
3294
|
+
* await h.install(MyPlugin)
|
|
3295
|
+
* expect(h.registry.get('com.me.plugin')?.status).toBe('active')
|
|
3296
|
+
* expect(h.registry.getContributions().slashCommands.getAll()).toHaveLength(1)
|
|
3297
|
+
*/
|
|
3298
|
+
declare function createTestPluginHarness(options?: TestHarnessOptions): TestPluginHarness;
|
|
3299
|
+
|
|
3300
|
+
/**
|
|
3301
|
+
* @xnetjs/plugins — plugin project scaffolder (exploration 0192).
|
|
3302
|
+
*
|
|
3303
|
+
* The pure core behind `create-xnet-plugin`: given a small spec, produce the
|
|
3304
|
+
* full set of project files (manifest, tests, package.json, README) as a
|
|
3305
|
+
* path→content map. Keeping it pure means it's unit-testable without touching
|
|
3306
|
+
* disk; a thin CLI writes the map out.
|
|
3307
|
+
*
|
|
3308
|
+
* Templates mirror the authoring tracks in the explorations: `client`
|
|
3309
|
+
* (contributions only), `two-sided` (client + a hub feature + declared
|
|
3310
|
+
* capabilities), `ai-script` (a script-backed slash command), and `connector`
|
|
3311
|
+
* (0196 — sync an external service into governed nodes + expose agent tools).
|
|
3312
|
+
*/
|
|
3313
|
+
|
|
3314
|
+
type ScaffoldTemplate = 'client' | 'two-sided' | 'ai-script' | 'connector';
|
|
3315
|
+
interface ScaffoldSpec {
|
|
3316
|
+
/** Reverse-domain plugin id, e.g. `com.acme.kanban`. */
|
|
3317
|
+
id: string;
|
|
3318
|
+
/** Human-readable name. */
|
|
3319
|
+
name: string;
|
|
3320
|
+
/** Which starter template to generate. */
|
|
3321
|
+
template: ScaffoldTemplate;
|
|
3322
|
+
author?: string;
|
|
3323
|
+
description?: string;
|
|
3324
|
+
/** Declared capability grant (two-sided templates surface this in the manifest). */
|
|
3325
|
+
capabilities?: ModuleCapabilities;
|
|
3326
|
+
/** SPDX license id (exploration 0196). Defaults to FSL-1.1-MIT. */
|
|
3327
|
+
license?: string;
|
|
3328
|
+
/** Monetization (exploration 0196). When paid, the manifest declares `pricing`. */
|
|
3329
|
+
pricing?: PluginPricing;
|
|
3330
|
+
/** Publisher DID for paid plugins (exploration 0196). */
|
|
3331
|
+
publisherDid?: string;
|
|
3332
|
+
/** Copyright year for the generated LICENSE (defaults supplied by the caller). */
|
|
3333
|
+
year?: number;
|
|
3334
|
+
}
|
|
3335
|
+
interface ScaffoldResult {
|
|
3336
|
+
/** Project files keyed by relative path. */
|
|
3337
|
+
files: Record<string, string>;
|
|
3338
|
+
}
|
|
3339
|
+
declare class ScaffoldError extends Error {
|
|
3340
|
+
constructor(message: string);
|
|
3341
|
+
}
|
|
3342
|
+
/** `com.acme.kanban-board` → `KanbanBoard` (a safe JS identifier). */
|
|
3343
|
+
declare function pascalCase(id: string): string;
|
|
3344
|
+
/** `com.acme.kanban` → `acme-kanban` (an npm-safe package name). */
|
|
3345
|
+
declare function packageName(id: string): string;
|
|
3346
|
+
/**
|
|
3347
|
+
* Scaffold a plugin project as a path→content map. Pure: write the result to
|
|
3348
|
+
* disk with a thin CLI, or assert on it in tests.
|
|
3349
|
+
*
|
|
3350
|
+
* @throws {ScaffoldError} if the spec is invalid.
|
|
3351
|
+
*/
|
|
3352
|
+
declare function scaffoldPlugin(spec: ScaffoldSpec): ScaffoldResult;
|
|
3353
|
+
|
|
3354
|
+
/**
|
|
3355
|
+
* @xnetjs/plugins — paid-plugin license policy (exploration 0196).
|
|
3356
|
+
*
|
|
3357
|
+
* The marketplace pre-approves a small, fixed set of licenses so a paid plugin
|
|
3358
|
+
* needs no per-listing legal review. The default is **FSL-1.1-MIT** — source-
|
|
3359
|
+
* available, forbids only a competing marketplace, and auto-converts to MIT two
|
|
3360
|
+
* years after each version ships (mirrors `@xnetjs/cloud`'s FSL). Plain OSI
|
|
3361
|
+
* licenses are allowed too. This module is the single source of truth for the
|
|
3362
|
+
* allowed set and for generating the `LICENSE` file the scaffolder emits;
|
|
3363
|
+
* `scripts/check-plugin-licenses.sh` enforces the same set in CI.
|
|
3364
|
+
*/
|
|
3365
|
+
/** SPDX ids a paid plugin may declare. */
|
|
3366
|
+
declare const ALLOWED_PLUGIN_LICENSES: readonly ["FSL-1.1-MIT", "FSL-1.1-Apache-2.0", "MIT", "Apache-2.0", "AGPL-3.0-only"];
|
|
3367
|
+
type AllowedPluginLicense = (typeof ALLOWED_PLUGIN_LICENSES)[number];
|
|
3368
|
+
/** The default license suggested by the scaffolder for a new plugin. */
|
|
3369
|
+
declare const DEFAULT_PLUGIN_LICENSE: AllowedPluginLicense;
|
|
3370
|
+
/** True if `spdx` is one of the marketplace-approved licenses. */
|
|
3371
|
+
declare function isAllowedPluginLicense(spdx: string): spdx is AllowedPluginLicense;
|
|
3372
|
+
/**
|
|
3373
|
+
* Generate the `LICENSE` file body for a plugin, or `null` for an unrecognized
|
|
3374
|
+
* license (the scaffolder then omits the file and the author supplies their own).
|
|
3375
|
+
*/
|
|
3376
|
+
declare function pluginLicenseText(spdx: string, year: number, holder: string): string | null;
|
|
3377
|
+
|
|
3378
|
+
/**
|
|
3379
|
+
* @xnetjs/plugins — AI-authored plugin transform (exploration 0192).
|
|
3380
|
+
*
|
|
3381
|
+
* The hard part of AI authoring already ships (`@xnetjs/plugins/ai`:
|
|
3382
|
+
* NL → AST-validated script + provider routing). The missing headless step is
|
|
3383
|
+
* turning a generated script into an *installable* plugin: this wraps a
|
|
3384
|
+
* validated `GeneratedScript` into a `FeatureModule` whose command runs the
|
|
3385
|
+
* script, stamped with `ai-generated` provenance so the install path sandboxes
|
|
3386
|
+
* it at the `user` tier and still routes its capability requests through consent.
|
|
3387
|
+
*
|
|
3388
|
+
* It deliberately **refuses unvalidated code** — "the AI made it" never bypasses
|
|
3389
|
+
* the safety gate.
|
|
3390
|
+
*/
|
|
3391
|
+
|
|
3392
|
+
/** The subset of `@xnetjs/plugins/ai`'s `AIScriptResponse` this transform needs. */
|
|
3393
|
+
interface GeneratedScript {
|
|
3394
|
+
code: string;
|
|
3395
|
+
suggestedName: string;
|
|
3396
|
+
validated: boolean;
|
|
3397
|
+
explanation?: string;
|
|
3398
|
+
}
|
|
3399
|
+
/** Runs the generated script body (injected so this stays decoupled from the sandbox). */
|
|
3400
|
+
type ScriptExecutor = (code: string) => void | Promise<void>;
|
|
3401
|
+
interface ScriptToManifestInput {
|
|
3402
|
+
/** Reverse-domain id for the new plugin. */
|
|
3403
|
+
id: string;
|
|
3404
|
+
/** The validated generated script. */
|
|
3405
|
+
script: GeneratedScript;
|
|
3406
|
+
author?: string;
|
|
3407
|
+
/** Capabilities the script needs (default: none — Layer-1 scripts are sandboxed). */
|
|
3408
|
+
capabilities?: ModuleCapabilities;
|
|
3409
|
+
/** How to run the script when the command fires (default: throws until wired). */
|
|
3410
|
+
run?: ScriptExecutor;
|
|
3411
|
+
}
|
|
3412
|
+
interface AiAuthoredPlugin {
|
|
3413
|
+
manifest: FeatureModule;
|
|
3414
|
+
/** Always `ai-generated` — the install path derives the `user` trust tier from it. */
|
|
3415
|
+
provenance: InstallProvenance;
|
|
3416
|
+
/** The raw script body, for persistence/audit. */
|
|
3417
|
+
code: string;
|
|
3418
|
+
}
|
|
3419
|
+
declare class AiAuthoringError extends Error {
|
|
3420
|
+
constructor(message: string);
|
|
3421
|
+
}
|
|
3422
|
+
/**
|
|
3423
|
+
* Wrap a validated generated script into an installable, `ai-generated` plugin.
|
|
3424
|
+
*
|
|
3425
|
+
* @throws {AiAuthoringError} if the id is malformed or the script is unvalidated.
|
|
3426
|
+
*/
|
|
3427
|
+
declare function scriptToPluginManifest(input: ScriptToManifestInput): AiAuthoredPlugin;
|
|
3428
|
+
|
|
3429
|
+
/**
|
|
3430
|
+
* @xnetjs/plugins — run plugin code on the labs runtime ladder (0194 Phase 1).
|
|
3431
|
+
*
|
|
3432
|
+
* The unification the exploration calls for: instead of plugins maintaining their
|
|
3433
|
+
* own sandbox, user/marketplace-tier plugin code runs on the *same* runtime
|
|
3434
|
+
* ladder `@xnetjs/labs` uses (SES/QuickJS for `sandbox`, an iframe for `app`).
|
|
3435
|
+
* One sandbox, one security audit — and plugins gain the ladder's Python/server
|
|
3436
|
+
* tiers for free.
|
|
3437
|
+
*
|
|
3438
|
+
* The ladder is taken as a **structural port** (`PluginRuntimeLadder`), not an
|
|
3439
|
+
* `@xnetjs/labs` import: labs already depends on `@xnetjs/plugins`, so a direct
|
|
3440
|
+
* edge here would cycle. The host (web/electron) passes its concrete labs ladder.
|
|
3441
|
+
*
|
|
3442
|
+
* First-party code is trusted and runs in the host realm, NOT through the ladder
|
|
3443
|
+
* — `runPluginCode` rejects a first-party tier so a caller can't accidentally
|
|
3444
|
+
* sandbox (and slow) trusted code.
|
|
3445
|
+
*/
|
|
3446
|
+
|
|
3447
|
+
/** The labs runtime tiers a plugin can target. */
|
|
3448
|
+
type LadderRuntimeTier = 'sandbox' | 'app' | 'server';
|
|
3449
|
+
/** A single run on the ladder. */
|
|
3450
|
+
interface PluginRunInput {
|
|
3451
|
+
language: 'javascript' | 'typescript';
|
|
3452
|
+
tier: LadderRuntimeTier;
|
|
3453
|
+
code: string;
|
|
3454
|
+
/** Host bridge the sandbox may call (capability-gated by the host). */
|
|
3455
|
+
host?: unknown;
|
|
3456
|
+
}
|
|
3457
|
+
interface PluginRunResult {
|
|
3458
|
+
ok: boolean;
|
|
3459
|
+
value?: unknown;
|
|
3460
|
+
logs?: string[];
|
|
3461
|
+
error?: string;
|
|
3462
|
+
}
|
|
3463
|
+
/** The minimal slice of the labs `RuntimeLadder` this adapter needs. */
|
|
3464
|
+
interface PluginRuntimeLadder {
|
|
3465
|
+
run(input: PluginRunInput): Promise<PluginRunResult>;
|
|
3466
|
+
}
|
|
3467
|
+
declare class PluginRuntimeError extends Error {
|
|
3468
|
+
constructor(message: string);
|
|
3469
|
+
}
|
|
3470
|
+
/**
|
|
3471
|
+
* Map a plugin's trust tier to the ladder rung its code should run on. `user`
|
|
3472
|
+
* code runs in the deterministic `sandbox` (SES/QuickJS); `marketplace` code in
|
|
3473
|
+
* the `app` (iframe) rung. `first-party` has no ladder rung — it runs in the
|
|
3474
|
+
* host realm — so this throws for it.
|
|
3475
|
+
*/
|
|
3476
|
+
declare function ladderTierForTrust(tier: TrustTier): LadderRuntimeTier;
|
|
3477
|
+
interface RunPluginCodeInput {
|
|
3478
|
+
code: string;
|
|
3479
|
+
trustTier: TrustTier;
|
|
3480
|
+
language?: 'javascript' | 'typescript';
|
|
3481
|
+
host?: unknown;
|
|
3482
|
+
}
|
|
3483
|
+
/**
|
|
3484
|
+
* Run user/marketplace-tier plugin code on the labs ladder, choosing the rung by
|
|
3485
|
+
* trust tier. Throws `PluginRuntimeError` for first-party (which belongs in the
|
|
3486
|
+
* host realm). Returns the ladder's result unchanged.
|
|
3487
|
+
*/
|
|
3488
|
+
declare function runPluginCode(ladder: PluginRuntimeLadder, input: RunPluginCodeInput): Promise<PluginRunResult>;
|
|
3489
|
+
|
|
3490
|
+
/**
|
|
3491
|
+
* @xnetjs/plugins — the AI→Lab→Plugin assembly line (exploration 0194 Phase 2).
|
|
3492
|
+
*
|
|
3493
|
+
* Closes the authoring loop: the AI *generates* a script, the script *runs* in a
|
|
3494
|
+
* Lab so the AI (and the user) see real output, and only after a human approves
|
|
3495
|
+
* is it *published* as a plugin. Each hop is an injected port, so this is pure
|
|
3496
|
+
* orchestration — testable without the AI provider, the labs ladder, or the
|
|
3497
|
+
* registry, and free of the `plugins → labs` dependency edge.
|
|
3498
|
+
*
|
|
3499
|
+
* It never auto-publishes: publishing is always gated on `consent`. The script
|
|
3500
|
+
* must be validated before it becomes a plugin (`scriptToPluginManifest` refuses
|
|
3501
|
+
* unvalidated code), so "the AI made it" never bypasses the gate.
|
|
3502
|
+
*/
|
|
3503
|
+
|
|
3504
|
+
/** The result of running a generated script in a Lab. */
|
|
3505
|
+
interface LabRunOutcome {
|
|
3506
|
+
ok: boolean;
|
|
3507
|
+
output?: string;
|
|
3508
|
+
error?: string;
|
|
3509
|
+
}
|
|
3510
|
+
/** The injected capabilities the pipeline orchestrates. */
|
|
3511
|
+
interface AiPluginPipelinePorts {
|
|
3512
|
+
/** Generate a (validated) script from natural-language intent. */
|
|
3513
|
+
generate: (intent: string) => Promise<GeneratedScript>;
|
|
3514
|
+
/** Run the script in a Lab and report the real result. */
|
|
3515
|
+
runLab: (code: string) => Promise<LabRunOutcome>;
|
|
3516
|
+
/** Ask the human to approve publishing, given the plugin + its run output. */
|
|
3517
|
+
consent: (plugin: AiAuthoredPlugin, run: LabRunOutcome) => Promise<boolean>;
|
|
3518
|
+
/** Publish the approved plugin (e.g. `publishLabAsExtension` / `registry.install`). */
|
|
3519
|
+
publish: (plugin: AiAuthoredPlugin) => Promise<void>;
|
|
3520
|
+
}
|
|
3521
|
+
interface AiPluginPipelineInput {
|
|
3522
|
+
/** Natural-language description of the plugin to build. */
|
|
3523
|
+
intent: string;
|
|
3524
|
+
/** Reverse-domain id for the new plugin. */
|
|
3525
|
+
id: string;
|
|
3526
|
+
author?: string;
|
|
3527
|
+
}
|
|
3528
|
+
type AiPluginPipelineResult = {
|
|
3529
|
+
status: 'generation-invalid';
|
|
3530
|
+
reason: string;
|
|
3531
|
+
} | {
|
|
3532
|
+
status: 'run-failed';
|
|
3533
|
+
plugin: AiAuthoredPlugin;
|
|
3534
|
+
run: LabRunOutcome;
|
|
3535
|
+
} | {
|
|
3536
|
+
status: 'declined';
|
|
3537
|
+
plugin: AiAuthoredPlugin;
|
|
3538
|
+
run: LabRunOutcome;
|
|
3539
|
+
} | {
|
|
3540
|
+
status: 'published';
|
|
3541
|
+
plugin: AiAuthoredPlugin;
|
|
3542
|
+
run: LabRunOutcome;
|
|
3543
|
+
};
|
|
3544
|
+
/**
|
|
3545
|
+
* Run the generate → lab-test → consent → publish pipeline. Returns a tagged
|
|
3546
|
+
* result at whichever stage it stops; only `published` means the plugin landed.
|
|
3547
|
+
*/
|
|
3548
|
+
declare function runAiPluginPipeline(input: AiPluginPipelineInput, ports: AiPluginPipelinePorts): Promise<AiPluginPipelineResult>;
|
|
3549
|
+
|
|
652
3550
|
/**
|
|
653
3551
|
* Plugin schema - stores plugin metadata as Nodes for P2P sync
|
|
654
3552
|
*/
|
|
@@ -1187,6 +4085,65 @@ declare class ScriptRunner {
|
|
|
1187
4085
|
private handleScriptChange;
|
|
1188
4086
|
}
|
|
1189
4087
|
|
|
4088
|
+
/**
|
|
4089
|
+
* Canvas Plugin Sandbox
|
|
4090
|
+
*
|
|
4091
|
+
* Policy helpers for plugin-owned canvas renderers and preview generators.
|
|
4092
|
+
*/
|
|
4093
|
+
|
|
4094
|
+
type CanvasPluginSandboxKind = 'renderer' | 'preview';
|
|
4095
|
+
type CanvasPluginSandboxDomAccess = 'none' | 'isolated-iframe';
|
|
4096
|
+
type CanvasPluginSandboxNetworkAccess = 'none' | 'workspace-approved';
|
|
4097
|
+
type CanvasPluginSandboxMutationAccess = 'none';
|
|
4098
|
+
type CanvasPluginSandboxOutputKind = 'view-model' | 'html-fragment' | 'summary' | 'thumbnail' | 'template-draft';
|
|
4099
|
+
type CanvasPluginSandboxPolicy = {
|
|
4100
|
+
kind: CanvasPluginSandboxKind;
|
|
4101
|
+
timeoutMs: number;
|
|
4102
|
+
maxOutputBytes: number;
|
|
4103
|
+
domAccess: CanvasPluginSandboxDomAccess;
|
|
4104
|
+
networkAccess: CanvasPluginSandboxNetworkAccess;
|
|
4105
|
+
mutationAccess: CanvasPluginSandboxMutationAccess;
|
|
4106
|
+
allowedOutputKinds: CanvasPluginSandboxOutputKind[];
|
|
4107
|
+
blockedGlobals: string[];
|
|
4108
|
+
};
|
|
4109
|
+
type CanvasPluginSandboxRequest = {
|
|
4110
|
+
pluginId: string;
|
|
4111
|
+
contributionId: string;
|
|
4112
|
+
kind: CanvasPluginSandboxKind;
|
|
4113
|
+
entrypoint: string;
|
|
4114
|
+
permissions?: CanvasContributionPermission[];
|
|
4115
|
+
requestedNetworkDomains?: string[];
|
|
4116
|
+
};
|
|
4117
|
+
type CanvasPluginSandboxDecision = {
|
|
4118
|
+
allowed: boolean;
|
|
4119
|
+
policy: CanvasPluginSandboxPolicy;
|
|
4120
|
+
issues: string[];
|
|
4121
|
+
};
|
|
4122
|
+
type CanvasPluginSandboxOutput = {
|
|
4123
|
+
kind: CanvasPluginSandboxOutputKind;
|
|
4124
|
+
payload?: unknown;
|
|
4125
|
+
html?: string;
|
|
4126
|
+
bytes?: number;
|
|
4127
|
+
};
|
|
4128
|
+
type CanvasPluginSandboxOutputValidation = {
|
|
4129
|
+
valid: boolean;
|
|
4130
|
+
issues: string[];
|
|
4131
|
+
};
|
|
4132
|
+
type CanvasRendererSandboxContribution = CanvasCardContribution | CanvasInspectorContribution | CanvasTemplateContribution;
|
|
4133
|
+
declare function createCanvasPluginSandboxPolicy(kind: CanvasPluginSandboxKind, permissions?: CanvasContributionPermission[]): CanvasPluginSandboxPolicy;
|
|
4134
|
+
declare function evaluateCanvasPluginSandboxRequest(request: CanvasPluginSandboxRequest): CanvasPluginSandboxDecision;
|
|
4135
|
+
declare function createCanvasRendererSandboxRequest(input: {
|
|
4136
|
+
pluginId: string;
|
|
4137
|
+
contribution: CanvasRendererSandboxContribution;
|
|
4138
|
+
entrypoint?: string;
|
|
4139
|
+
}): CanvasPluginSandboxRequest;
|
|
4140
|
+
declare function createCanvasPreviewSandboxRequest(input: {
|
|
4141
|
+
pluginId: string;
|
|
4142
|
+
contribution: CanvasCardContribution | CanvasTemplateContribution;
|
|
4143
|
+
entrypoint?: string;
|
|
4144
|
+
}): CanvasPluginSandboxRequest;
|
|
4145
|
+
declare function validateCanvasPluginSandboxOutput(output: CanvasPluginSandboxOutput, policy: CanvasPluginSandboxPolicy): CanvasPluginSandboxOutputValidation;
|
|
4146
|
+
|
|
1190
4147
|
/**
|
|
1191
4148
|
* AI Prompt Builder for Script Generation
|
|
1192
4149
|
*
|
|
@@ -1264,10 +4221,100 @@ declare function buildRetryPrompt(originalPrompt: string, errors: string[]): str
|
|
|
1264
4221
|
* AI Provider Abstraction
|
|
1265
4222
|
*
|
|
1266
4223
|
* Defines a common interface for AI providers and includes
|
|
1267
|
-
* implementations for Anthropic, OpenAI,
|
|
4224
|
+
* implementations for Anthropic, OpenAI-compatible endpoints, OpenAI,
|
|
4225
|
+
* and local (Ollama).
|
|
1268
4226
|
*/
|
|
4227
|
+
type AIMessageRole = 'system' | 'user' | 'assistant' | 'tool';
|
|
4228
|
+
type AIMessage = {
|
|
4229
|
+
role: AIMessageRole;
|
|
4230
|
+
content: string;
|
|
4231
|
+
name?: string;
|
|
4232
|
+
toolCallId?: string;
|
|
4233
|
+
};
|
|
4234
|
+
type AIToolSpec = {
|
|
4235
|
+
name: string;
|
|
4236
|
+
description?: string;
|
|
4237
|
+
inputSchema?: Record<string, unknown>;
|
|
4238
|
+
};
|
|
4239
|
+
type AIPrivacyLevel = 'local' | 'cloud' | 'proxy';
|
|
4240
|
+
type AIModelQuality = 'local' | 'balanced' | 'strong';
|
|
4241
|
+
type AICostModel = {
|
|
4242
|
+
inputPerMillion: number;
|
|
4243
|
+
outputPerMillion: number;
|
|
4244
|
+
currency: 'USD';
|
|
4245
|
+
};
|
|
4246
|
+
type AIModelCapabilities = {
|
|
4247
|
+
tools: boolean;
|
|
4248
|
+
structuredOutputs: boolean;
|
|
4249
|
+
streaming: boolean;
|
|
4250
|
+
contextWindow: number;
|
|
4251
|
+
local: boolean;
|
|
4252
|
+
privacy: AIPrivacyLevel;
|
|
4253
|
+
quality: AIModelQuality;
|
|
4254
|
+
cost?: AICostModel;
|
|
4255
|
+
};
|
|
4256
|
+
type AIRiskLevel = 'low' | 'medium' | 'high' | 'critical';
|
|
4257
|
+
type AIComplexityLevel = 'low' | 'medium' | 'high';
|
|
4258
|
+
type AIGenerateRequest = {
|
|
4259
|
+
prompt?: string;
|
|
4260
|
+
messages?: AIMessage[];
|
|
4261
|
+
tools?: AIToolSpec[];
|
|
4262
|
+
responseSchema?: Record<string, unknown>;
|
|
4263
|
+
stream?: boolean;
|
|
4264
|
+
risk?: AIRiskLevel;
|
|
4265
|
+
complexity?: AIComplexityLevel;
|
|
4266
|
+
maxTokens?: number;
|
|
4267
|
+
temperature?: number;
|
|
4268
|
+
preferredProvider?: string;
|
|
4269
|
+
metadata?: Record<string, unknown>;
|
|
4270
|
+
};
|
|
4271
|
+
type AIToolCall = {
|
|
4272
|
+
id: string;
|
|
4273
|
+
name: string;
|
|
4274
|
+
arguments: Record<string, unknown>;
|
|
4275
|
+
};
|
|
4276
|
+
type AIUsage = {
|
|
4277
|
+
inputTokens?: number;
|
|
4278
|
+
outputTokens?: number;
|
|
4279
|
+
totalTokens?: number;
|
|
4280
|
+
estimatedCostUsd?: number;
|
|
4281
|
+
};
|
|
4282
|
+
type AIGenerateResponse = {
|
|
4283
|
+
text: string;
|
|
4284
|
+
provider: string;
|
|
4285
|
+
model: string;
|
|
4286
|
+
toolCalls?: AIToolCall[];
|
|
4287
|
+
usage?: AIUsage;
|
|
4288
|
+
};
|
|
4289
|
+
type AIStreamChunk = {
|
|
4290
|
+
type: 'text';
|
|
4291
|
+
text: string;
|
|
4292
|
+
provider: string;
|
|
4293
|
+
model: string;
|
|
4294
|
+
} | {
|
|
4295
|
+
type: 'tool_call';
|
|
4296
|
+
toolCall: AIToolCall;
|
|
4297
|
+
provider: string;
|
|
4298
|
+
model: string;
|
|
4299
|
+
} | {
|
|
4300
|
+
type: 'usage';
|
|
4301
|
+
usage: AIUsage;
|
|
4302
|
+
provider: string;
|
|
4303
|
+
model: string;
|
|
4304
|
+
} | {
|
|
4305
|
+
type: 'done';
|
|
4306
|
+
provider: string;
|
|
4307
|
+
model: string;
|
|
4308
|
+
};
|
|
4309
|
+
type AIProviderUsage = {
|
|
4310
|
+
requests: number;
|
|
4311
|
+
inputTokens: number;
|
|
4312
|
+
outputTokens: number;
|
|
4313
|
+
totalTokens: number;
|
|
4314
|
+
estimatedCostUsd: number;
|
|
4315
|
+
};
|
|
1269
4316
|
/**
|
|
1270
|
-
* Common interface for AI text generation providers
|
|
4317
|
+
* Common interface for AI text generation providers.
|
|
1271
4318
|
*/
|
|
1272
4319
|
interface AIProvider {
|
|
1273
4320
|
/** Provider name for display/logging */
|
|
@@ -1280,9 +4327,21 @@ interface AIProvider {
|
|
|
1280
4327
|
* @throws Error if generation fails
|
|
1281
4328
|
*/
|
|
1282
4329
|
generate(prompt: string): Promise<string>;
|
|
4330
|
+
/**
|
|
4331
|
+
* Generate a response with optional tool and structured-output metadata.
|
|
4332
|
+
*/
|
|
4333
|
+
generateWithTools?(request: AIGenerateRequest): Promise<AIGenerateResponse>;
|
|
4334
|
+
/**
|
|
4335
|
+
* Stream model output and tool events.
|
|
4336
|
+
*/
|
|
4337
|
+
stream?(request: AIGenerateRequest): AsyncIterable<AIStreamChunk>;
|
|
4338
|
+
/**
|
|
4339
|
+
* Describe model/provider capabilities for routing.
|
|
4340
|
+
*/
|
|
4341
|
+
getCapabilities?(): AIModelCapabilities;
|
|
1283
4342
|
}
|
|
1284
4343
|
/**
|
|
1285
|
-
* Options for configuring AI providers
|
|
4344
|
+
* Options for configuring AI providers.
|
|
1286
4345
|
*/
|
|
1287
4346
|
interface AIProviderOptions {
|
|
1288
4347
|
/** API key (for cloud providers) */
|
|
@@ -1295,20 +4354,40 @@ interface AIProviderOptions {
|
|
|
1295
4354
|
maxTokens?: number;
|
|
1296
4355
|
/** Temperature (0-1, higher = more creative) */
|
|
1297
4356
|
temperature?: number;
|
|
4357
|
+
/** Display name for OpenAI-compatible providers */
|
|
4358
|
+
providerName?: string;
|
|
4359
|
+
/** Additional HTTP headers for compatible proxies */
|
|
4360
|
+
defaultHeaders?: Record<string, string>;
|
|
4361
|
+
/** Whether an API key is required */
|
|
4362
|
+
apiKeyRequired?: boolean;
|
|
4363
|
+
/** Capability overrides for routing */
|
|
4364
|
+
capabilities?: Partial<AIModelCapabilities>;
|
|
4365
|
+
/**
|
|
4366
|
+
* Send the Anthropic browser-CORS header
|
|
4367
|
+
* (`anthropic-dangerous-direct-browser-access`) so a bring-your-own-key call
|
|
4368
|
+
* succeeds from browser JavaScript. Only `AnthropicProvider` reads this.
|
|
4369
|
+
* Defaults to `true` when a DOM is present (`typeof window !== 'undefined'`).
|
|
4370
|
+
*/
|
|
4371
|
+
allowBrowser?: boolean;
|
|
1298
4372
|
}
|
|
4373
|
+
type OpenAICompatibleProviderOptions = AIProviderOptions;
|
|
1299
4374
|
/**
|
|
1300
|
-
* AI provider type identifier
|
|
4375
|
+
* AI provider type identifier.
|
|
1301
4376
|
*/
|
|
1302
|
-
type AIProviderType = 'anthropic' | 'openai' | 'ollama' | 'custom';
|
|
4377
|
+
type AIProviderType = 'anthropic' | 'openai' | 'ollama' | 'openai-compatible' | 'openrouter' | 'ollama-openai' | 'lmstudio' | 'vllm' | 'litellm' | 'managed' | 'custom';
|
|
1303
4378
|
/**
|
|
1304
|
-
* Configuration for selecting an AI provider
|
|
4379
|
+
* Configuration for selecting an AI provider.
|
|
1305
4380
|
*/
|
|
1306
4381
|
interface AIProviderConfig {
|
|
1307
4382
|
type: AIProviderType;
|
|
1308
4383
|
options: AIProviderOptions;
|
|
1309
4384
|
}
|
|
4385
|
+
type AIProviderRouterOptions = {
|
|
4386
|
+
preferLocalRiskLevels?: AIRiskLevel[];
|
|
4387
|
+
strongModelRiskLevels?: AIRiskLevel[];
|
|
4388
|
+
};
|
|
1310
4389
|
/**
|
|
1311
|
-
* Error thrown when AI generation fails
|
|
4390
|
+
* Error thrown when AI generation fails.
|
|
1312
4391
|
*/
|
|
1313
4392
|
declare class AIGenerationError extends Error {
|
|
1314
4393
|
readonly provider: string;
|
|
@@ -1331,8 +4410,34 @@ declare class AnthropicProvider implements AIProvider {
|
|
|
1331
4410
|
private model;
|
|
1332
4411
|
private maxTokens;
|
|
1333
4412
|
private temperature;
|
|
4413
|
+
private allowBrowser;
|
|
1334
4414
|
constructor(options: AIProviderOptions);
|
|
4415
|
+
getCapabilities(): AIModelCapabilities;
|
|
4416
|
+
generate(prompt: string): Promise<string>;
|
|
4417
|
+
}
|
|
4418
|
+
/**
|
|
4419
|
+
* Tool-capable adapter for OpenAI-compatible chat completion endpoints.
|
|
4420
|
+
*
|
|
4421
|
+
* Works with OpenAI, OpenRouter, Ollama's `/v1` compatibility API,
|
|
4422
|
+
* LM Studio, vLLM, and LiteLLM.
|
|
4423
|
+
*/
|
|
4424
|
+
declare class OpenAICompatibleProvider implements AIProvider {
|
|
4425
|
+
readonly name: string;
|
|
4426
|
+
private apiKey?;
|
|
4427
|
+
private baseUrl;
|
|
4428
|
+
private model;
|
|
4429
|
+
private maxTokens;
|
|
4430
|
+
private temperature;
|
|
4431
|
+
private defaultHeaders;
|
|
4432
|
+
private capabilities;
|
|
4433
|
+
constructor(options?: OpenAICompatibleProviderOptions);
|
|
4434
|
+
getCapabilities(): AIModelCapabilities;
|
|
1335
4435
|
generate(prompt: string): Promise<string>;
|
|
4436
|
+
generateWithTools(request: AIGenerateRequest): Promise<AIGenerateResponse>;
|
|
4437
|
+
stream(request: AIGenerateRequest): AsyncIterable<AIStreamChunk>;
|
|
4438
|
+
private createHeaders;
|
|
4439
|
+
private createPayload;
|
|
4440
|
+
private parseToolCalls;
|
|
1336
4441
|
}
|
|
1337
4442
|
/**
|
|
1338
4443
|
* AI provider for OpenAI's GPT models.
|
|
@@ -1343,15 +4448,8 @@ declare class AnthropicProvider implements AIProvider {
|
|
|
1343
4448
|
* const response = await provider.generate('Hello!')
|
|
1344
4449
|
* ```
|
|
1345
4450
|
*/
|
|
1346
|
-
declare class OpenAIProvider
|
|
1347
|
-
readonly name = "OpenAI";
|
|
1348
|
-
private apiKey;
|
|
1349
|
-
private baseUrl;
|
|
1350
|
-
private model;
|
|
1351
|
-
private maxTokens;
|
|
1352
|
-
private temperature;
|
|
4451
|
+
declare class OpenAIProvider extends OpenAICompatibleProvider {
|
|
1353
4452
|
constructor(options: AIProviderOptions);
|
|
1354
|
-
generate(prompt: string): Promise<string>;
|
|
1355
4453
|
}
|
|
1356
4454
|
/**
|
|
1357
4455
|
* AI provider for local Ollama instance.
|
|
@@ -1368,8 +4466,78 @@ declare class OllamaProvider implements AIProvider {
|
|
|
1368
4466
|
private model;
|
|
1369
4467
|
private temperature;
|
|
1370
4468
|
constructor(options?: AIProviderOptions);
|
|
4469
|
+
getCapabilities(): AIModelCapabilities;
|
|
4470
|
+
generate(prompt: string): Promise<string>;
|
|
4471
|
+
}
|
|
4472
|
+
declare class AIProviderRouter implements AIProvider {
|
|
4473
|
+
readonly name = "AIProviderRouter";
|
|
4474
|
+
private providers;
|
|
4475
|
+
private options;
|
|
4476
|
+
private usageByProvider;
|
|
4477
|
+
constructor(providers: AIProvider[], options?: AIProviderRouterOptions);
|
|
4478
|
+
getCapabilities(): AIModelCapabilities;
|
|
4479
|
+
getUsage(): Record<string, AIProviderUsage>;
|
|
4480
|
+
selectProvider(request: AIGenerateRequest): AIProvider;
|
|
4481
|
+
generate(prompt: string): Promise<string>;
|
|
4482
|
+
generateWithTools(request: AIGenerateRequest): Promise<AIGenerateResponse>;
|
|
4483
|
+
stream(request: AIGenerateRequest): AsyncIterable<AIStreamChunk>;
|
|
4484
|
+
private canHandle;
|
|
4485
|
+
private shouldPreferLocal;
|
|
4486
|
+
private shouldPreferStrong;
|
|
4487
|
+
private getProviderCapabilities;
|
|
4488
|
+
private recordUsage;
|
|
4489
|
+
}
|
|
4490
|
+
/** The live budget snapshot a managed call reports back (drives the panel gauge). */
|
|
4491
|
+
interface ManagedBudgetSnapshot {
|
|
4492
|
+
/** Marked-up spend accrued this billing period, in USD. */
|
|
4493
|
+
spendThisPeriodUsd: number;
|
|
4494
|
+
/** Free included allotment for the period, in USD. */
|
|
4495
|
+
includedUsd: number;
|
|
4496
|
+
/** Hard monthly cap, in USD — requests stop here. */
|
|
4497
|
+
budgetUsd: number;
|
|
4498
|
+
/** Coarse state driving the gauge colour. */
|
|
4499
|
+
budgetState: 'included' | 'overage' | 'near-cap' | 'over-cap';
|
|
4500
|
+
}
|
|
4501
|
+
/** Thrown when managed AI returns `402` — the surprise-bill hard stop. */
|
|
4502
|
+
declare class AiBudgetError extends Error {
|
|
4503
|
+
readonly spentUsd: number;
|
|
4504
|
+
readonly budgetUsd: number;
|
|
4505
|
+
constructor(spentUsd: number, budgetUsd: number);
|
|
4506
|
+
}
|
|
4507
|
+
type ManagedProviderOptions = AIProviderOptions & {
|
|
4508
|
+
/** Injected fetch for tests; defaults to the global `fetch`. */
|
|
4509
|
+
fetchImpl?: typeof fetch;
|
|
4510
|
+
/** Receives the live budget after each managed call (drives the panel gauge). */
|
|
4511
|
+
onBudget?: (snapshot: ManagedBudgetSnapshot) => void;
|
|
4512
|
+
};
|
|
4513
|
+
/**
|
|
4514
|
+
* XNet Cloud **managed** AI provider (exploration 0208).
|
|
4515
|
+
*
|
|
4516
|
+
* Posts to the hub's `/ai/chat`, which forwards to the metered control-plane
|
|
4517
|
+
* gateway (OpenRouter behind a per-tenant budgeted key). Unlike every other cloud
|
|
4518
|
+
* provider it carries **no API key** — the hub injects the per-tenant credential
|
|
4519
|
+
* server-side — so it is the only cloud tier safe to use without the user pasting
|
|
4520
|
+
* a secret. It surfaces the live budget (so the panel can render "used / included
|
|
4521
|
+
* / cap") and turns a `402` into a typed {@link AiBudgetError} the UI can act on.
|
|
4522
|
+
*
|
|
4523
|
+
* Model switching is per-instance: the configured `model` is sent on every call,
|
|
4524
|
+
* so changing the picker rebuilds the provider (same pattern as the BYO tiers).
|
|
4525
|
+
* No `stream` method, so the runtime uses the request/response path.
|
|
4526
|
+
*/
|
|
4527
|
+
declare class ManagedProvider implements AIProvider {
|
|
4528
|
+
readonly name = "XNet Cloud";
|
|
4529
|
+
private readonly baseUrl;
|
|
4530
|
+
private readonly model?;
|
|
4531
|
+
private readonly fetchImpl;
|
|
4532
|
+
private readonly onBudget?;
|
|
4533
|
+
constructor(options?: ManagedProviderOptions);
|
|
4534
|
+
getCapabilities(): AIModelCapabilities;
|
|
1371
4535
|
generate(prompt: string): Promise<string>;
|
|
4536
|
+
generateWithTools(request: AIGenerateRequest): Promise<AIGenerateResponse>;
|
|
4537
|
+
private emitBudget;
|
|
1372
4538
|
}
|
|
4539
|
+
/** Build a {@link ManagedProvider} (parallels `createPromptApiProvider`). */
|
|
4540
|
+
declare const createManagedProvider: (options?: ManagedProviderOptions) => ManagedProvider;
|
|
1373
4541
|
/**
|
|
1374
4542
|
* Create an AI provider from configuration.
|
|
1375
4543
|
*
|
|
@@ -1385,6 +4553,7 @@ declare class OllamaProvider implements AIProvider {
|
|
|
1385
4553
|
* ```
|
|
1386
4554
|
*/
|
|
1387
4555
|
declare function createAIProvider(config: AIProviderConfig): AIProvider;
|
|
4556
|
+
declare function createAIProviderRouter(providers: AIProvider[], options?: AIProviderRouterOptions): AIProviderRouter;
|
|
1388
4557
|
/**
|
|
1389
4558
|
* Check if Ollama is available locally.
|
|
1390
4559
|
*
|
|
@@ -1498,6 +4667,478 @@ declare class ScriptGenerator {
|
|
|
1498
4667
|
*/
|
|
1499
4668
|
declare function generateScript(provider: AIProvider, request: AIScriptRequest): Promise<AIScriptResponse>;
|
|
1500
4669
|
|
|
4670
|
+
/**
|
|
4671
|
+
* In-app AI agent runtime for persistent threads, approvals, events, and telemetry.
|
|
4672
|
+
*/
|
|
4673
|
+
|
|
4674
|
+
type AiAgentOrchestratorMode = 'custom' | 'codex-app-server' | 'hybrid';
|
|
4675
|
+
type AiAgentThreadStatus = 'idle' | 'running' | 'waiting-approval' | 'cancelled' | 'failed';
|
|
4676
|
+
type AiAgentTurnRole = 'system' | 'user' | 'assistant' | 'tool';
|
|
4677
|
+
type AiAgentTurnStatus = 'pending' | 'streaming' | 'completed' | 'cancelled' | 'failed';
|
|
4678
|
+
type AiAgentApprovalStatus = 'pending' | 'approved' | 'rejected' | 'revision-requested';
|
|
4679
|
+
type AiAgentBackgroundJobStatus = 'queued' | 'running' | 'completed' | 'failed' | 'cancelled';
|
|
4680
|
+
type AiAgentEventType = 'thread.created' | 'turn.created' | 'model.delta' | 'model.completed' | 'tool.call' | 'usage' | 'approval.requested' | 'approval.resolved' | 'run.cancelled' | 'run.completed' | 'run.failed' | 'run.steered' | 'background.started' | 'background.completed' | 'background.failed' | 'background.cancelled';
|
|
4681
|
+
type AiAgentThread = {
|
|
4682
|
+
id: string;
|
|
4683
|
+
title: string;
|
|
4684
|
+
mode: AiAgentOrchestratorMode;
|
|
4685
|
+
status: AiAgentThreadStatus;
|
|
4686
|
+
createdAt: string;
|
|
4687
|
+
updatedAt: string;
|
|
4688
|
+
metadata?: Record<string, unknown>;
|
|
4689
|
+
};
|
|
4690
|
+
type AiAgentTurn = {
|
|
4691
|
+
id: string;
|
|
4692
|
+
threadId: string;
|
|
4693
|
+
role: AiAgentTurnRole;
|
|
4694
|
+
status: AiAgentTurnStatus;
|
|
4695
|
+
content: string;
|
|
4696
|
+
createdAt: string;
|
|
4697
|
+
updatedAt: string;
|
|
4698
|
+
provider?: string;
|
|
4699
|
+
model?: string;
|
|
4700
|
+
usage?: AIUsage;
|
|
4701
|
+
toolCalls?: AIToolCall[];
|
|
4702
|
+
error?: string;
|
|
4703
|
+
metadata?: Record<string, unknown>;
|
|
4704
|
+
};
|
|
4705
|
+
type AiAgentApproval = {
|
|
4706
|
+
id: string;
|
|
4707
|
+
threadId: string;
|
|
4708
|
+
turnId?: string;
|
|
4709
|
+
planId: string;
|
|
4710
|
+
risk: AiRiskLevel;
|
|
4711
|
+
requiredScopes: AiScope[];
|
|
4712
|
+
status: AiAgentApprovalStatus;
|
|
4713
|
+
createdAt: string;
|
|
4714
|
+
resolvedAt?: string;
|
|
4715
|
+
note?: string;
|
|
4716
|
+
plan: AiMutationPlan;
|
|
4717
|
+
};
|
|
4718
|
+
type AiAgentBackgroundJob = {
|
|
4719
|
+
id: string;
|
|
4720
|
+
kind: 'export' | 'analysis' | 'custom';
|
|
4721
|
+
title: string;
|
|
4722
|
+
status: AiAgentBackgroundJobStatus;
|
|
4723
|
+
createdAt: string;
|
|
4724
|
+
updatedAt: string;
|
|
4725
|
+
completedAt?: string;
|
|
4726
|
+
result?: unknown;
|
|
4727
|
+
error?: string;
|
|
4728
|
+
metadata?: Record<string, unknown>;
|
|
4729
|
+
};
|
|
4730
|
+
type AiAgentEvent = {
|
|
4731
|
+
id: string;
|
|
4732
|
+
threadId?: string;
|
|
4733
|
+
turnId?: string;
|
|
4734
|
+
type: AiAgentEventType;
|
|
4735
|
+
createdAt: string;
|
|
4736
|
+
payload: Record<string, unknown>;
|
|
4737
|
+
};
|
|
4738
|
+
type AiAgentTelemetrySnapshot = {
|
|
4739
|
+
runsStarted: number;
|
|
4740
|
+
runsCompleted: number;
|
|
4741
|
+
runsCancelled: number;
|
|
4742
|
+
runsFailed: number;
|
|
4743
|
+
totalLatencyMs: number;
|
|
4744
|
+
lastLatencyMs?: number;
|
|
4745
|
+
acceptedChanges: number;
|
|
4746
|
+
rejectedChanges: number;
|
|
4747
|
+
revisionRequests: number;
|
|
4748
|
+
toolFailures: number;
|
|
4749
|
+
backgroundJobsStarted: number;
|
|
4750
|
+
backgroundJobsCompleted: number;
|
|
4751
|
+
backgroundJobsFailed: number;
|
|
4752
|
+
};
|
|
4753
|
+
type AiAgentRuntimeSnapshot = {
|
|
4754
|
+
threads: AiAgentThread[];
|
|
4755
|
+
turns: AiAgentTurn[];
|
|
4756
|
+
approvals: AiAgentApproval[];
|
|
4757
|
+
backgroundJobs: AiAgentBackgroundJob[];
|
|
4758
|
+
events: AiAgentEvent[];
|
|
4759
|
+
telemetry: AiAgentTelemetrySnapshot;
|
|
4760
|
+
};
|
|
4761
|
+
type AiAgentRuntimeStorage = {
|
|
4762
|
+
load(): Promise<AiAgentRuntimeSnapshot | null>;
|
|
4763
|
+
save(snapshot: AiAgentRuntimeSnapshot): Promise<void>;
|
|
4764
|
+
};
|
|
4765
|
+
/**
|
|
4766
|
+
* Builds extra messages (workspace context, retrieved resources, …) to inject
|
|
4767
|
+
* before the conversation history on each run. Returned messages are placed
|
|
4768
|
+
* after {@link AiAgentRuntimeConfig.systemPrompt} and before the thread
|
|
4769
|
+
* history, so the model sees grounding context ahead of the dialogue. Resolve
|
|
4770
|
+
* to `[]` (or throw — failures are swallowed) to skip context for a turn.
|
|
4771
|
+
*/
|
|
4772
|
+
type AiAgentContextProvider = (input: {
|
|
4773
|
+
threadId: string;
|
|
4774
|
+
content: string;
|
|
4775
|
+
}) => AIMessage[] | Promise<AIMessage[]>;
|
|
4776
|
+
type AiAgentRuntimeConfig = {
|
|
4777
|
+
provider: AIProvider;
|
|
4778
|
+
storage?: AiAgentRuntimeStorage;
|
|
4779
|
+
clock?: () => Date;
|
|
4780
|
+
mode?: AiAgentOrchestratorMode;
|
|
4781
|
+
maxEvents?: number;
|
|
4782
|
+
/** Optional system prompt prepended to every run. */
|
|
4783
|
+
systemPrompt?: string;
|
|
4784
|
+
/** Optional hook injecting grounding context messages before the history. */
|
|
4785
|
+
contextProvider?: AiAgentContextProvider;
|
|
4786
|
+
};
|
|
4787
|
+
type AiAgentThreadCreateInput = {
|
|
4788
|
+
title: string;
|
|
4789
|
+
mode?: AiAgentOrchestratorMode;
|
|
4790
|
+
metadata?: Record<string, unknown>;
|
|
4791
|
+
};
|
|
4792
|
+
type AiAgentRunTurnInput = {
|
|
4793
|
+
threadId: string;
|
|
4794
|
+
content: string;
|
|
4795
|
+
request?: Omit<AIGenerateRequest, 'prompt' | 'messages'>;
|
|
4796
|
+
metadata?: Record<string, unknown>;
|
|
4797
|
+
};
|
|
4798
|
+
type AiAgentSelectionKind = 'page-text' | 'database-rows' | 'canvas-objects' | 'nodes';
|
|
4799
|
+
type AiAgentSelectionContext = {
|
|
4800
|
+
kind: AiAgentSelectionKind;
|
|
4801
|
+
label?: string;
|
|
4802
|
+
pageId?: string;
|
|
4803
|
+
databaseId?: string;
|
|
4804
|
+
canvasId?: string;
|
|
4805
|
+
nodeIds?: string[];
|
|
4806
|
+
rowIds?: string[];
|
|
4807
|
+
objectIds?: string[];
|
|
4808
|
+
text?: string;
|
|
4809
|
+
range?: {
|
|
4810
|
+
from: number;
|
|
4811
|
+
to: number;
|
|
4812
|
+
};
|
|
4813
|
+
};
|
|
4814
|
+
type AiAgentRunSelectionTurnInput = Omit<AiAgentRunTurnInput, 'content'> & {
|
|
4815
|
+
instruction: string;
|
|
4816
|
+
selection: AiAgentSelectionContext;
|
|
4817
|
+
};
|
|
4818
|
+
type AiAgentRunTurnResult = {
|
|
4819
|
+
runId: string;
|
|
4820
|
+
userTurn: AiAgentTurn;
|
|
4821
|
+
assistantTurn: AiAgentTurn;
|
|
4822
|
+
};
|
|
4823
|
+
type AiAgentApprovalRequestInput = {
|
|
4824
|
+
threadId: string;
|
|
4825
|
+
turnId?: string;
|
|
4826
|
+
plan: AiMutationPlan;
|
|
4827
|
+
};
|
|
4828
|
+
type AiAgentApprovalResolveInput = {
|
|
4829
|
+
approvalId: string;
|
|
4830
|
+
status: Exclude<AiAgentApprovalStatus, 'pending'>;
|
|
4831
|
+
note?: string;
|
|
4832
|
+
};
|
|
4833
|
+
type AiAgentBackgroundJobInput = {
|
|
4834
|
+
kind: AiAgentBackgroundJob['kind'];
|
|
4835
|
+
title: string;
|
|
4836
|
+
metadata?: Record<string, unknown>;
|
|
4837
|
+
};
|
|
4838
|
+
type AiAgentBackgroundJobRunner = (signal: AbortSignal) => Promise<unknown>;
|
|
4839
|
+
type AiAgentRuntimeListener = (event: AiAgentEvent, snapshot: AiAgentRuntimeSnapshot) => void;
|
|
4840
|
+
type AiAgentDisplayStateKind = 'read-only-answer' | 'proposed-change' | 'applied-change';
|
|
4841
|
+
type AiAgentDisplayState = {
|
|
4842
|
+
kind: AiAgentDisplayStateKind;
|
|
4843
|
+
label: string;
|
|
4844
|
+
planId?: string;
|
|
4845
|
+
approvalId?: string;
|
|
4846
|
+
auditEventId?: string;
|
|
4847
|
+
};
|
|
4848
|
+
declare class AiAgentRuntime {
|
|
4849
|
+
private readonly config;
|
|
4850
|
+
private snapshot;
|
|
4851
|
+
private readonly storage;
|
|
4852
|
+
private readonly clock;
|
|
4853
|
+
private readonly mode;
|
|
4854
|
+
private readonly maxEvents;
|
|
4855
|
+
private sequence;
|
|
4856
|
+
private loaded;
|
|
4857
|
+
private readonly listeners;
|
|
4858
|
+
private readonly activeRuns;
|
|
4859
|
+
private readonly activeJobs;
|
|
4860
|
+
constructor(config: AiAgentRuntimeConfig);
|
|
4861
|
+
load(): Promise<AiAgentRuntimeSnapshot>;
|
|
4862
|
+
getSnapshot(): AiAgentRuntimeSnapshot;
|
|
4863
|
+
subscribe(listener: AiAgentRuntimeListener): () => void;
|
|
4864
|
+
createThread(input: AiAgentThreadCreateInput): Promise<AiAgentThread>;
|
|
4865
|
+
runTurn(input: AiAgentRunTurnInput): Promise<AiAgentRunTurnResult>;
|
|
4866
|
+
runSelectionTurn(input: AiAgentRunSelectionTurnInput): Promise<AiAgentRunTurnResult>;
|
|
4867
|
+
cancelRun(runId: string): Promise<boolean>;
|
|
4868
|
+
steerRun(runId: string, message: string): Promise<boolean>;
|
|
4869
|
+
requestApproval(input: AiAgentApprovalRequestInput): Promise<AiAgentApproval>;
|
|
4870
|
+
resolveApproval(input: AiAgentApprovalResolveInput): Promise<AiAgentApproval>;
|
|
4871
|
+
startBackgroundJob(input: AiAgentBackgroundJobInput, runner: AiAgentBackgroundJobRunner): Promise<AiAgentBackgroundJob>;
|
|
4872
|
+
cancelBackgroundJob(jobId: string): Promise<boolean>;
|
|
4873
|
+
/**
|
|
4874
|
+
* Compose the messages sent to the provider for a run: the optional system
|
|
4875
|
+
* prompt, then optional grounding context, then the thread's prior
|
|
4876
|
+
* user/assistant turns in chronological order (which already include the
|
|
4877
|
+
* just-created user message). The in-flight (empty) assistant turn is
|
|
4878
|
+
* excluded. Context is best-effort — a throwing provider never fails the run.
|
|
4879
|
+
*/
|
|
4880
|
+
private buildRunMessages;
|
|
4881
|
+
private completeRun;
|
|
4882
|
+
private completeStreamingRun;
|
|
4883
|
+
private applyGenerateResponse;
|
|
4884
|
+
private applyStreamChunk;
|
|
4885
|
+
private appendAssistantText;
|
|
4886
|
+
private appendToolCall;
|
|
4887
|
+
private finishRun;
|
|
4888
|
+
private failRun;
|
|
4889
|
+
private completeBackgroundJob;
|
|
4890
|
+
private finishBackgroundJob;
|
|
4891
|
+
private failBackgroundJob;
|
|
4892
|
+
private createTurn;
|
|
4893
|
+
private updateThread;
|
|
4894
|
+
private updateTurn;
|
|
4895
|
+
private updateJob;
|
|
4896
|
+
private emit;
|
|
4897
|
+
private persist;
|
|
4898
|
+
private ensureLoaded;
|
|
4899
|
+
private getThreadOrThrow;
|
|
4900
|
+
private getTurnOrThrow;
|
|
4901
|
+
private nowIso;
|
|
4902
|
+
private nextId;
|
|
4903
|
+
}
|
|
4904
|
+
declare function createAiAgentRuntime(config: AiAgentRuntimeConfig): AiAgentRuntime;
|
|
4905
|
+
declare function createMemoryAiAgentRuntimeStorage(initial?: AiAgentRuntimeSnapshot): AiAgentRuntimeStorage & {
|
|
4906
|
+
snapshot(): AiAgentRuntimeSnapshot;
|
|
4907
|
+
};
|
|
4908
|
+
declare function renderSelectionPrompt(instruction: string, selection: AiAgentSelectionContext): string;
|
|
4909
|
+
declare function classifyAiAgentDisplayState(input: {
|
|
4910
|
+
plan?: AiMutationPlan;
|
|
4911
|
+
approval?: AiAgentApproval;
|
|
4912
|
+
auditEventId?: string;
|
|
4913
|
+
}): AiAgentDisplayState;
|
|
4914
|
+
|
|
4915
|
+
/**
|
|
4916
|
+
* Bring-Your-Own-Model connector contract (exploration 0174).
|
|
4917
|
+
*
|
|
4918
|
+
* No single transport reaches a model from a sandboxed HTTPS tab everywhere, so
|
|
4919
|
+
* the app probes a tiered set of "connectors" and degrades gracefully. Each
|
|
4920
|
+
* connector ultimately produces an {@link AIProvider} (see `../providers`); this
|
|
4921
|
+
* module only models *detection and selection* — which tiers are usable right
|
|
4922
|
+
* now and how capable each is — so it stays pure and unit-testable without a
|
|
4923
|
+
* GPU, Ollama, a key, or a browser.
|
|
4924
|
+
*/
|
|
4925
|
+
/** The model-access tiers, from the exploration's options A–E (+ managed, 0208). */
|
|
4926
|
+
type ConnectorTier = 'managed' | 'webllm' | 'local-server' | 'prompt-api' | 'cloud-key' | 'bridge';
|
|
4927
|
+
/**
|
|
4928
|
+
* How reliably the tier's model can call tools. This is the gate the
|
|
4929
|
+
* exploration identifies: `reliable` → full agentic writes; otherwise writes
|
|
4930
|
+
* must downgrade to "propose a plan, human applies" (see {@link writeModeFor}).
|
|
4931
|
+
*/
|
|
4932
|
+
type ToolCallingFidelity = 'reliable' | 'weak' | 'none';
|
|
4933
|
+
/** Whether the agent may apply writes itself, or must only propose them. */
|
|
4934
|
+
type WriteMode = 'agentic' | 'propose-only';
|
|
4935
|
+
/**
|
|
4936
|
+
* Injectable probes so detection is testable and host-agnostic. Every field has
|
|
4937
|
+
* a sensible default in {@link detectConnectors}; tests and non-browser hosts
|
|
4938
|
+
* override what they need.
|
|
4939
|
+
*/
|
|
4940
|
+
interface ConnectorEnv {
|
|
4941
|
+
/**
|
|
4942
|
+
* Probe XNet Cloud managed AI: GET `${managedUrl}/ai/health` is `ok` and the
|
|
4943
|
+
* tenant has AI enabled. Default: a same-origin fetch (returns false off-cloud).
|
|
4944
|
+
*/
|
|
4945
|
+
probeManaged?: (baseUrl: string) => Promise<boolean>;
|
|
4946
|
+
/** Base URL the hub serves the managed `/ai` routes from. Default: `''` (same origin). */
|
|
4947
|
+
managedUrl?: string;
|
|
4948
|
+
/** WebGPU present (enables in-tab models). Default: `navigator.gpu` check. */
|
|
4949
|
+
hasWebGpu?: () => boolean | Promise<boolean>;
|
|
4950
|
+
/** Chrome built-in `LanguageModel` present. Default: global check. */
|
|
4951
|
+
hasPromptApi?: () => boolean | Promise<boolean>;
|
|
4952
|
+
/** Local model endpoints to probe, in priority order. Default: Ollama, LM Studio. */
|
|
4953
|
+
localServerProbes?: readonly LocalServerProbe[];
|
|
4954
|
+
/** Whether a cloud API key is stored locally. Default: `false` (host wires this). */
|
|
4955
|
+
hasCloudKey?: () => boolean | Promise<boolean>;
|
|
4956
|
+
/** Probe a local bridge daemon. Default: GET `${bridgeUrl}/health`. */
|
|
4957
|
+
probeBridge?: (baseUrl: string) => Promise<boolean>;
|
|
4958
|
+
/** Bridge daemon base URL. Default: `http://127.0.0.1:31416`. */
|
|
4959
|
+
bridgeUrl?: string;
|
|
4960
|
+
}
|
|
4961
|
+
/** A named local model endpoint and how to detect it. */
|
|
4962
|
+
interface LocalServerProbe {
|
|
4963
|
+
label: string;
|
|
4964
|
+
baseUrl: string;
|
|
4965
|
+
probe: (baseUrl: string) => Promise<boolean>;
|
|
4966
|
+
}
|
|
4967
|
+
/** The result of probing one tier. */
|
|
4968
|
+
interface ConnectorDetection {
|
|
4969
|
+
tier: ConnectorTier;
|
|
4970
|
+
label: string;
|
|
4971
|
+
available: boolean;
|
|
4972
|
+
/** Extra context when available (e.g. the reachable endpoint or model). */
|
|
4973
|
+
detail?: string;
|
|
4974
|
+
/** When unavailable: why, and how to enable it. */
|
|
4975
|
+
setupHint?: string;
|
|
4976
|
+
/** Tool-calling fidelity → gates agentic vs propose-only writes. */
|
|
4977
|
+
toolCalling: ToolCallingFidelity;
|
|
4978
|
+
/** Preference rank; lower is more capable/preferred. */
|
|
4979
|
+
preference: number;
|
|
4980
|
+
}
|
|
4981
|
+
/** Map tool-calling fidelity to the safe write mode for that tier. */
|
|
4982
|
+
declare function writeModeFor(toolCalling: ToolCallingFidelity): WriteMode;
|
|
4983
|
+
|
|
4984
|
+
/**
|
|
4985
|
+
* Connector detection (exploration 0174).
|
|
4986
|
+
*
|
|
4987
|
+
* Probes the model-access tiers in parallel and returns them ranked by
|
|
4988
|
+
* capability so the chat panel can prefer the most capable available tier and
|
|
4989
|
+
* fall back gracefully. Pure given its {@link ConnectorEnv}; the defaults touch
|
|
4990
|
+
* `navigator`/`fetch` but every probe is overridable.
|
|
4991
|
+
*/
|
|
4992
|
+
|
|
4993
|
+
interface ConnectorMeta {
|
|
4994
|
+
label: string;
|
|
4995
|
+
toolCalling: ToolCallingFidelity;
|
|
4996
|
+
/** Lower = more capable/preferred. Mirrors the exploration: E > D > B > A > C. */
|
|
4997
|
+
preference: number;
|
|
4998
|
+
}
|
|
4999
|
+
/** Stable per-tier metadata. Keep ordering aligned with the recommendation. */
|
|
5000
|
+
declare const CONNECTOR_META: Record<ConnectorTier, ConnectorMeta>;
|
|
5001
|
+
/** Default local-model endpoints: Ollama (`/api/tags`) and LM Studio (`/v1/models`). */
|
|
5002
|
+
declare function defaultLocalServerProbes(): LocalServerProbe[];
|
|
5003
|
+
/** Probe an OpenAI-compatible server's `/v1/models`. Used for LM Studio etc. */
|
|
5004
|
+
declare function probeOpenAiCompatible(baseUrl: string): Promise<boolean>;
|
|
5005
|
+
/**
|
|
5006
|
+
* Detect which model connectors are usable right now, ranked by preference
|
|
5007
|
+
* (most capable first). Runs all probes concurrently.
|
|
5008
|
+
*/
|
|
5009
|
+
declare function detectConnectors(env?: ConnectorEnv): Promise<ConnectorDetection[]>;
|
|
5010
|
+
/** The most-preferred *available* connector, or null if none are usable. */
|
|
5011
|
+
declare function pickBestConnector(detections: readonly ConnectorDetection[]): ConnectorDetection | null;
|
|
5012
|
+
|
|
5013
|
+
/**
|
|
5014
|
+
* WebLLM provider adapter (exploration 0174, tier A).
|
|
5015
|
+
*
|
|
5016
|
+
* Wraps an in-tab WebGPU model (`@mlc-ai/web-llm`) behind the `AIProvider`
|
|
5017
|
+
* contract. To keep `@xnetjs/plugins` dependency-free and node-safe, the heavy
|
|
5018
|
+
* library is **not** a dependency here: the provider runs against a structural
|
|
5019
|
+
* {@link WebLLMEngineLike} interface, and `createWebLLMProvider` takes an
|
|
5020
|
+
* already-created engine. The web app supplies a real engine via a lazy
|
|
5021
|
+
* `import('@mlc-ai/web-llm')` + `CreateMLCEngine(...)` (see the "Connect a
|
|
5022
|
+
* model" guide); tests inject a fake.
|
|
5023
|
+
*
|
|
5024
|
+
* WebLLM exposes an OpenAI-compatible chat-completions surface. In-tab tool
|
|
5025
|
+
* calling is unreliable, so this reports `tools: false` — the chat panel routes
|
|
5026
|
+
* its writes through propose-only mode (see `writeModeFor`).
|
|
5027
|
+
*/
|
|
5028
|
+
|
|
5029
|
+
/** Minimal shape of an `@mlc-ai/web-llm` MLCEngine, structurally typed. */
|
|
5030
|
+
interface WebLLMEngineLike {
|
|
5031
|
+
chat: {
|
|
5032
|
+
completions: WebLLMCompletions;
|
|
5033
|
+
};
|
|
5034
|
+
}
|
|
5035
|
+
interface WebLLMCompletions {
|
|
5036
|
+
create(request: WebLLMRequest & {
|
|
5037
|
+
stream?: false;
|
|
5038
|
+
}): Promise<WebLLMResponse>;
|
|
5039
|
+
create(request: WebLLMRequest & {
|
|
5040
|
+
stream: true;
|
|
5041
|
+
}): Promise<AsyncIterable<WebLLMChunk>>;
|
|
5042
|
+
}
|
|
5043
|
+
interface WebLLMRequest {
|
|
5044
|
+
messages: Array<{
|
|
5045
|
+
role: string;
|
|
5046
|
+
content: string;
|
|
5047
|
+
}>;
|
|
5048
|
+
stream?: boolean;
|
|
5049
|
+
temperature?: number;
|
|
5050
|
+
max_tokens?: number;
|
|
5051
|
+
}
|
|
5052
|
+
interface WebLLMResponse {
|
|
5053
|
+
choices: Array<{
|
|
5054
|
+
message: {
|
|
5055
|
+
content: string | null;
|
|
5056
|
+
};
|
|
5057
|
+
}>;
|
|
5058
|
+
usage?: {
|
|
5059
|
+
prompt_tokens?: number;
|
|
5060
|
+
completion_tokens?: number;
|
|
5061
|
+
total_tokens?: number;
|
|
5062
|
+
};
|
|
5063
|
+
}
|
|
5064
|
+
interface WebLLMChunk {
|
|
5065
|
+
choices: Array<{
|
|
5066
|
+
delta: {
|
|
5067
|
+
content?: string;
|
|
5068
|
+
};
|
|
5069
|
+
}>;
|
|
5070
|
+
usage?: {
|
|
5071
|
+
prompt_tokens?: number;
|
|
5072
|
+
completion_tokens?: number;
|
|
5073
|
+
total_tokens?: number;
|
|
5074
|
+
};
|
|
5075
|
+
}
|
|
5076
|
+
interface WebLLMProviderOptions {
|
|
5077
|
+
engine: WebLLMEngineLike;
|
|
5078
|
+
/** Model id loaded into the engine (for reporting). */
|
|
5079
|
+
model: string;
|
|
5080
|
+
/** Context window of the loaded model, for capability reporting. */
|
|
5081
|
+
contextWindow?: number;
|
|
5082
|
+
}
|
|
5083
|
+
declare class WebLLMProvider implements AIProvider {
|
|
5084
|
+
readonly name = "webllm";
|
|
5085
|
+
private readonly engine;
|
|
5086
|
+
private readonly model;
|
|
5087
|
+
private readonly contextWindow;
|
|
5088
|
+
constructor(options: WebLLMProviderOptions);
|
|
5089
|
+
generate(prompt: string): Promise<string>;
|
|
5090
|
+
stream(request: AIGenerateRequest): AsyncIterable<AIStreamChunk>;
|
|
5091
|
+
getCapabilities(): AIModelCapabilities;
|
|
5092
|
+
}
|
|
5093
|
+
declare function createWebLLMProvider(options: WebLLMProviderOptions): WebLLMProvider;
|
|
5094
|
+
|
|
5095
|
+
/**
|
|
5096
|
+
* Chrome built-in AI provider adapter (exploration 0174, tier C).
|
|
5097
|
+
*
|
|
5098
|
+
* Wraps the browser's on-device `LanguageModel` (Gemini Nano) behind the
|
|
5099
|
+
* `AIProvider` contract. The API is Chrome-only and not yet in the DOM lib
|
|
5100
|
+
* types, so it is structurally typed here ({@link LanguageModelLike}); the
|
|
5101
|
+
* provider takes an injected session so it's testable without a browser, and
|
|
5102
|
+
* `createPromptApiProvider` resolves one from `globalThis.LanguageModel`.
|
|
5103
|
+
*
|
|
5104
|
+
* The Prompt API has no tool calling, so this reports `tools: false` →
|
|
5105
|
+
* propose-only writes (see `writeModeFor`).
|
|
5106
|
+
*/
|
|
5107
|
+
|
|
5108
|
+
/** Minimal shape of a Chrome `LanguageModel` session. */
|
|
5109
|
+
interface LanguageModelSessionLike {
|
|
5110
|
+
prompt(input: string): Promise<string>;
|
|
5111
|
+
promptStreaming(input: string): AsyncIterable<string>;
|
|
5112
|
+
}
|
|
5113
|
+
/** Minimal shape of the global `LanguageModel` factory. */
|
|
5114
|
+
interface LanguageModelLike {
|
|
5115
|
+
availability(): Promise<'unavailable' | 'downloadable' | 'downloading' | 'available'>;
|
|
5116
|
+
create(options?: {
|
|
5117
|
+
initialPrompts?: Array<{
|
|
5118
|
+
role: string;
|
|
5119
|
+
content: string;
|
|
5120
|
+
}>;
|
|
5121
|
+
}): Promise<LanguageModelSessionLike>;
|
|
5122
|
+
}
|
|
5123
|
+
interface PromptApiProviderOptions {
|
|
5124
|
+
session: LanguageModelSessionLike;
|
|
5125
|
+
model?: string;
|
|
5126
|
+
}
|
|
5127
|
+
declare class PromptApiProvider implements AIProvider {
|
|
5128
|
+
readonly name = "prompt-api";
|
|
5129
|
+
private readonly session;
|
|
5130
|
+
private readonly model;
|
|
5131
|
+
constructor(options: PromptApiProviderOptions);
|
|
5132
|
+
generate(prompt: string): Promise<string>;
|
|
5133
|
+
stream(request: AIGenerateRequest): AsyncIterable<AIStreamChunk>;
|
|
5134
|
+
getCapabilities(): AIModelCapabilities;
|
|
5135
|
+
}
|
|
5136
|
+
/**
|
|
5137
|
+
* Resolve a provider from the global `LanguageModel`, downloading the model if
|
|
5138
|
+
* needed. Returns null if the API is unavailable (not Chrome, or no model).
|
|
5139
|
+
*/
|
|
5140
|
+
declare function createPromptApiProvider(factory?: LanguageModelLike): Promise<PromptApiProvider | null>;
|
|
5141
|
+
|
|
1501
5142
|
/**
|
|
1502
5143
|
* Service Plugin Types
|
|
1503
5144
|
*
|
|
@@ -1692,93 +5333,6 @@ interface IProcessManager {
|
|
|
1692
5333
|
off<K extends keyof ProcessManagerEvents>(event: K, listener: ProcessManagerEvents[K]): void;
|
|
1693
5334
|
}
|
|
1694
5335
|
|
|
1695
|
-
/**
|
|
1696
|
-
* Local HTTP API Server
|
|
1697
|
-
*
|
|
1698
|
-
* Provides a REST API for external integrations (N8N, MCP, etc.) to interact
|
|
1699
|
-
* with xNet data. Runs on localhost only (port 31415 by default).
|
|
1700
|
-
*
|
|
1701
|
-
* This is designed to run in the Electron main process.
|
|
1702
|
-
*/
|
|
1703
|
-
/**
|
|
1704
|
-
* Node store interface (minimal subset needed by API)
|
|
1705
|
-
*/
|
|
1706
|
-
interface NodeStoreAPI {
|
|
1707
|
-
get(id: string): Promise<NodeData | null>;
|
|
1708
|
-
list(options?: {
|
|
1709
|
-
schemaId?: string;
|
|
1710
|
-
limit?: number;
|
|
1711
|
-
offset?: number;
|
|
1712
|
-
}): Promise<NodeData[]>;
|
|
1713
|
-
create(options: {
|
|
1714
|
-
schemaId: string;
|
|
1715
|
-
properties: Record<string, unknown>;
|
|
1716
|
-
}): Promise<NodeData>;
|
|
1717
|
-
update(id: string, options: {
|
|
1718
|
-
properties: Record<string, unknown>;
|
|
1719
|
-
}): Promise<NodeData>;
|
|
1720
|
-
delete(id: string): Promise<void>;
|
|
1721
|
-
subscribe(listener: (event: NodeChangeEventData) => void): () => void;
|
|
1722
|
-
}
|
|
1723
|
-
/**
|
|
1724
|
-
* Schema registry interface (minimal subset needed by API)
|
|
1725
|
-
*/
|
|
1726
|
-
interface SchemaRegistryAPI {
|
|
1727
|
-
getAllIRIs(): string[];
|
|
1728
|
-
get(iri: string): Promise<SchemaData | null>;
|
|
1729
|
-
}
|
|
1730
|
-
/**
|
|
1731
|
-
* Node data returned by API
|
|
1732
|
-
*/
|
|
1733
|
-
interface NodeData {
|
|
1734
|
-
id: string;
|
|
1735
|
-
schemaId: string;
|
|
1736
|
-
properties: Record<string, unknown>;
|
|
1737
|
-
deleted: boolean;
|
|
1738
|
-
createdAt: number;
|
|
1739
|
-
updatedAt: number;
|
|
1740
|
-
}
|
|
1741
|
-
/**
|
|
1742
|
-
* Schema data returned by API
|
|
1743
|
-
*/
|
|
1744
|
-
interface SchemaData {
|
|
1745
|
-
iri: string;
|
|
1746
|
-
name: string;
|
|
1747
|
-
properties: Record<string, unknown>;
|
|
1748
|
-
}
|
|
1749
|
-
/**
|
|
1750
|
-
* Node change event data
|
|
1751
|
-
*/
|
|
1752
|
-
interface NodeChangeEventData {
|
|
1753
|
-
change: {
|
|
1754
|
-
type: string;
|
|
1755
|
-
};
|
|
1756
|
-
node: NodeData | null;
|
|
1757
|
-
isRemote: boolean;
|
|
1758
|
-
}
|
|
1759
|
-
/**
|
|
1760
|
-
* API configuration
|
|
1761
|
-
*/
|
|
1762
|
-
interface LocalAPIConfig {
|
|
1763
|
-
/** Port to listen on (default: 31415) */
|
|
1764
|
-
port?: number;
|
|
1765
|
-
/** Host to bind to (default: '127.0.0.1') */
|
|
1766
|
-
host?: string;
|
|
1767
|
-
/** API token for authentication (optional) */
|
|
1768
|
-
token?: string;
|
|
1769
|
-
/**
|
|
1770
|
-
* Allowed CORS origins (default: none).
|
|
1771
|
-
* Set to specific origins like ['http://localhost:3000'] for local dev,
|
|
1772
|
-
* or ['*'] to allow all origins (not recommended for production).
|
|
1773
|
-
* Empty array or undefined disables CORS entirely.
|
|
1774
|
-
*/
|
|
1775
|
-
allowedOrigins?: string[];
|
|
1776
|
-
/** NodeStore instance */
|
|
1777
|
-
store: NodeStoreAPI;
|
|
1778
|
-
/** SchemaRegistry instance */
|
|
1779
|
-
schemas: SchemaRegistryAPI;
|
|
1780
|
-
}
|
|
1781
|
-
|
|
1782
5336
|
/**
|
|
1783
5337
|
* Service Client
|
|
1784
5338
|
*
|
|
@@ -1986,7 +5540,15 @@ declare function createWebhookEmitter(store: NodeStoreAPI): WebhookEmitter;
|
|
|
1986
5540
|
*/
|
|
1987
5541
|
interface MCPTool {
|
|
1988
5542
|
name: string;
|
|
5543
|
+
title?: string;
|
|
1989
5544
|
description: string;
|
|
5545
|
+
risk?: string;
|
|
5546
|
+
requiredScopes?: string[];
|
|
5547
|
+
/**
|
|
5548
|
+
* Tool Search Tool hint (advanced-tool-use): deferred tools are discovered
|
|
5549
|
+
* on demand instead of paying their definition tokens on every turn.
|
|
5550
|
+
*/
|
|
5551
|
+
defer_loading?: boolean;
|
|
1990
5552
|
inputSchema: {
|
|
1991
5553
|
type: 'object';
|
|
1992
5554
|
properties: Record<string, MCPPropertySchema>;
|
|
@@ -1999,7 +5561,11 @@ interface MCPTool {
|
|
|
1999
5561
|
interface MCPPropertySchema {
|
|
2000
5562
|
type: 'string' | 'number' | 'boolean' | 'object' | 'array';
|
|
2001
5563
|
description?: string;
|
|
5564
|
+
enum?: readonly string[];
|
|
5565
|
+
properties?: Record<string, MCPPropertySchema>;
|
|
5566
|
+
required?: string[];
|
|
2002
5567
|
items?: MCPPropertySchema;
|
|
5568
|
+
additionalProperties?: boolean | MCPPropertySchema;
|
|
2003
5569
|
}
|
|
2004
5570
|
/**
|
|
2005
5571
|
* MCP Resource definition
|
|
@@ -2009,6 +5575,9 @@ interface MCPResource {
|
|
|
2009
5575
|
name: string;
|
|
2010
5576
|
description?: string;
|
|
2011
5577
|
mimeType?: string;
|
|
5578
|
+
risk?: string;
|
|
5579
|
+
requiredScopes?: string[];
|
|
5580
|
+
dynamic?: boolean;
|
|
2012
5581
|
}
|
|
2013
5582
|
/**
|
|
2014
5583
|
* MCP Request from client
|
|
@@ -2038,10 +5607,27 @@ interface MCPResponse {
|
|
|
2038
5607
|
interface MCPServerConfig {
|
|
2039
5608
|
store: NodeStoreAPI;
|
|
2040
5609
|
schemas: SchemaRegistryAPI;
|
|
5610
|
+
/** Shared AI surface service. A default service is created when omitted. */
|
|
5611
|
+
aiSurface?: AiSurfaceService;
|
|
5612
|
+
/** Optional output and pagination limits for the default AI surface. */
|
|
5613
|
+
aiLimits?: Partial<AiSurfaceLimits>;
|
|
5614
|
+
/**
|
|
5615
|
+
* Plugin/connector agent tools to expose (exploration 0196). Folded into the
|
|
5616
|
+
* default AI surface's `extraTools`, so they appear in `tools/list` (deferred,
|
|
5617
|
+
* since not in {@link MCP_CORE_TOOL_NAMES}) and dispatch through `tools/call`.
|
|
5618
|
+
* Ignored when a pre-built `aiSurface` is supplied — wire `extraTools` there.
|
|
5619
|
+
*/
|
|
5620
|
+
agentTools?: AgentToolContribution[];
|
|
5621
|
+
/**
|
|
5622
|
+
* Write guardrail for the generic + first-class write tools. A default
|
|
5623
|
+
* guardrail (delete/outward writes need confirmation, cost budget, audit) is
|
|
5624
|
+
* created when omitted. Pass a configured instance to tune it.
|
|
5625
|
+
*/
|
|
5626
|
+
guardrail?: McpWriteGuardrail;
|
|
2041
5627
|
/** Server name (default: 'xnet') */
|
|
2042
5628
|
name?: string;
|
|
2043
5629
|
/** Server version (default: '1.0.0') */
|
|
2044
5630
|
version?: string;
|
|
2045
5631
|
}
|
|
2046
5632
|
|
|
2047
|
-
export { AIGenerationError, type AIProvider, type AIProviderConfig, type AIProviderOptions, type AIProviderType, type AIScriptRequest, type AIScriptResponse, AnthropicProvider, type ArrayHelpers, type BlockContribution, type BlockProps, type CommandContribution, ContributionRegistry, type DeliveryResult, type Disposable$1 as Disposable, type EditorContribution, type ExtensionContext, type ExtensionStorage, type FlatNode, type FormatHelpers, type IProcessManager, type LocalAPIConfig, type MCPPropertySchema, type MCPRequest, type MCPResource, type MCPResponse, type MCPServerConfig, type MCPTool, type MathHelpers, MiddlewareChain, type NodeChangeEvent, type NodeChangeEventData, type NodeData, type NodeStoreAPI, type NodeStoreMiddleware, OllamaProvider, OpenAIProvider, type PendingChange, type Platform, type PlatformCapabilities, type PluginContributions, PluginError, type PluginNode, type PluginNodeChangeEvent, type PluginNodeChangeListener, type PluginPermissions, PluginRegistry, PluginSchema, type PluginStatus, PluginValidationError, type ProcessManagerEvents, type PropertyCellProps, type PropertyEditorProps, type PropertyHandler, type PropertyHandlerContribution, type QueryFilter, type RegisteredPlugin, SERVICE_IPC_CHANNELS, type SandboxOptions, type SchemaContribution, type SchemaData, type SchemaDefinition, type SchemaProperty, type SchemaRegistryAPI, type ScriptContext, ScriptError, type ScriptExecutionResult, ScriptGenerationError, ScriptGenerator, type ScriptGeneratorOptions, type ScriptNode, type ScriptNodeChangeEvent, type ScriptOutputType, ScriptRunner, type ScriptRunnerOptions, ScriptSandbox, ScriptSchema, type ScriptStore, ScriptTimeoutError, type ScriptTriggerType, ScriptValidationError, type ServiceClient, type ServiceCommunication, type ServiceDefinition, type ServiceHealthCheck, type ServiceLifecycle, type ServiceOutputEvent, type ServiceProcessConfig, type ServiceProvides, type ServiceState, type ServiceStatus, type ServiceStatusEvent, type SettingContribution, type SettingsPanelProps, ShortcutManager, type SidebarContribution, type SlashCommandContext, type SlashCommandContribution, type TelemetryReporter, type TextHelpers, type ToolbarContribution, TypedRegistry, type ValidationResult, type ViewContribution, type ViewProps, type WebhookConfig, WebhookEmitter, type WebhookPayload, type XNetExtension, buildRetryPrompt, buildScriptPrompt, createAIProvider, createExtensionContext, createExtensionStorage, createScriptContext, createServiceClient, createWebhookEmitter, defineExtension, executeScript, generateScript, getPlatformCapabilities, getShortcutManager, installShortcutHandler, isOllamaAvailable, isScriptNode, isServiceClientAvailable, listOllamaModels, quickSafetyCheck, validateManifest, validateScript, validateScriptAST };
|
|
5633
|
+
export { type AIComplexityLevel, type AICostModel, type AIGenerateRequest, type AIGenerateResponse, AIGenerationError, type AIMessage, type AIMessageRole, type AIModelCapabilities, type AIModelQuality, type AIPrivacyLevel, type AIProvider, type AIProviderConfig, type AIProviderOptions, AIProviderRouter, type AIProviderRouterOptions, type AIProviderType, type AIProviderUsage, AIRTABLE_CONNECTOR_ID, type AIRiskLevel, type AIScriptRequest, type AIScriptResponse, type AIStreamChunk, type AIToolCall, type AIToolSpec, type AIUsage, AI_RISK_LEVELS, AI_SCOPES, AI_TARGET_KINDS, ALLOWED_PLUGIN_LICENSES, type ActionContext, type ActionDefinition, ActionDefinitionError, ActionDispatchError, type ActionEvent, ActionSsrfError, type ActionTrigger, type AgentToolContribution, type AgentToolInputSchema, type AiAgentApproval, type AiAgentApprovalRequestInput, type AiAgentApprovalResolveInput, type AiAgentApprovalStatus, type AiAgentBackgroundJob, type AiAgentBackgroundJobInput, type AiAgentBackgroundJobRunner, type AiAgentBackgroundJobStatus, type AiAgentDisplayState, type AiAgentDisplayStateKind, type AiAgentEvent, type AiAgentEventType, type AiAgentOrchestratorMode, type AiAgentRunSelectionTurnInput, type AiAgentRunTurnInput, type AiAgentRunTurnResult, AiAgentRuntime, type AiAgentRuntimeConfig, type AiAgentRuntimeListener, type AiAgentRuntimeSnapshot, type AiAgentRuntimeStorage, type AiAgentSelectionContext, type AiAgentSelectionKind, type AiAgentTelemetrySnapshot, type AiAgentThread, type AiAgentThreadCreateInput, type AiAgentThreadStatus, type AiAgentTurn, type AiAgentTurnRole, type AiAgentTurnStatus, type AiAuditEvent, type AiAuthoredPlugin, AiAuthoringError, AiBudgetError, type AiCallableTool, type AiChangeSet, type AiCommandExposure, type AiContextPack, type AiContextPackResource, type AiContextRetriever, type AiContextSeed, type AiDatabaseMutationApplyResult, type AiExtraTool, type AiJsonSchema, type AiJsonSchemaType, type AiMutationPlan, type AiMutationPlanStatus, type AiOperation, type AiPageMarkdownApplyAdapter, type AiPageMarkdownApplyAdapterInput, type AiPageMarkdownApplyAdapterResult, type AiPageMarkdownApplyResult, type AiPageMarkdownRollbackResult, type AiPluginPipelineInput, type AiPluginPipelinePorts, type AiPluginPipelineResult, type AiResource, type AiResourceContent, type AiRetrievedNode, type AiRiskLevel, type AiScope, type AiSearchOptions, type AiSearchResult, type AiSurfaceLimits, AiSurfaceService, type AiSurfaceServiceConfig, type AiTargetKind, type AiToolCallResult, type AiToolDefinition, type AiValidationResult, type AirtableConnectorOptions, type AllowedPluginLicense, AnthropicProvider, type ArrayHelpers, type BlockContribution, type BlockProps, CANVAS_PLUGIN_FIXTURES, CHANNEL_SCHEMA, CHAT_MESSAGE_SCHEMA, CONNECTOR_CATEGORY, CONNECTOR_META, CRM_CANVAS_PLUGIN_FIXTURE, type CanvasCardContribution, type CanvasContribution, type CanvasContributionBase, type CanvasContributionPermission, type CanvasEdgeContribution, type CanvasErpPrototypeAuditEntry, type CanvasErpPrototypeAuditOperation, type CanvasErpPrototypeAuditSource, type CanvasErpPrototypeCard, type CanvasErpPrototypeCommand, type CanvasErpPrototypeEdge, type CanvasErpPrototypeEntityKind, type CanvasErpPrototypeLayoutKind, type CanvasErpPrototypeQueryFrame, type CanvasErpPrototypeQueryPredicate, type CanvasErpPrototypeRect, type CanvasErpPrototypeRisk, type CanvasErpPrototypeRiskSummary, type CanvasErpPrototypeScenario, type CanvasErpPrototypeStatus, type CanvasIngestInputKind, type CanvasIngestorContribution, type CanvasInspectorContribution, type CanvasInspectorPlacement, type CanvasLayoutContribution, type CanvasLayoutScope, type CanvasPluginFixture, type CanvasPluginFixtureCardSample, type CanvasPluginFixtureKind, type CanvasPluginPermissionDecisionStatus, type CanvasPluginPermissionGateDecision, type CanvasPluginPermissionGateInput, type CanvasPluginPermissionPrompt, type CanvasPluginPermissionPromptOption, type CanvasPluginPromptMode, type CanvasPluginSandboxDecision, type CanvasPluginSandboxDomAccess, type CanvasPluginSandboxKind, type CanvasPluginSandboxMutationAccess, type CanvasPluginSandboxNetworkAccess, type CanvasPluginSandboxOutput, type CanvasPluginSandboxOutputKind, type CanvasPluginSandboxOutputValidation, type CanvasPluginSandboxPolicy, type CanvasPluginSandboxRequest, type CanvasPluginWorkspacePolicy, type CanvasPreviewTier, type CanvasRendererSandboxContribution, type CanvasTemplateCategory, type CanvasTemplateContribution, type CanvasToolContribution, type CanvasToolGroup, CapabilityError, type CommandContext, type CommandContribution, CommandRegistry, type CommandScope, type ConnectorArtifacts, type ConnectorCadence, type ConnectorDefinition, ConnectorDefinitionError, type ConnectorDetection, type ConnectorEnv, type ConnectorFetch, type ConnectorInstallGate, type ConnectorStore, type ConnectorSyncContext, ConnectorSyncError, type ConnectorSyncResult, type ConnectorSyncSpec, type ConnectorTier, type ConnectorToolDescriptor, type ConsentDecision, type ConsentLine, ContributionRegistry, DEFAULT_PLUGIN_LICENSE, type DefinedAction, type DefinedConnector, type DeliveryResult, DependencyCycleError, type DependencyNode, type Disposable$1 as Disposable, ERP_CANVAS_PLUGIN_FIXTURE, EXTERNAL_ITEM_SCHEMA, type EditorContribution, type EditorSchemaRisk, type EmailActionOptions, type ExtensionContext, type ExtensionStorage, FEED_ITEM_SCHEMA, type FeatureModule, type FeedEntry, type FetchJson, type FetchLike, type FlatNode, type FormatHelpers, GITHUB_CONNECTOR_ID, type GeneratedScript, type GithubConnectorOptions, type GuardableConnectorStore, type IProcessManager, type ImporterContribution, type InstallOptions, LINEAR_CONNECTOR_ID, type LabRunOutcome, type LadderRuntimeTier, type LanguageModelLike, type LanguageModelSessionLike, type LicenseCheckResult, LicenseRequiredError, type LinearConnectorOptions, type LocalAPIConfig, type LocalAPITokenConfig, type LocalAPITokenScope, type LocalAPITokenSummary, type LocalServerProbe, MARKETPLACE_PROVENANCE, type MCPPropertySchema, type MCPRequest, type MCPResource, type MCPResponse, type MCPServerConfig, type MCPTool, MEDIA_PROVIDER_CANVAS_PLUGIN_FIXTURE, type ManagedBudgetSnapshot, ManagedProvider, type ManagedProviderOptions, MarketplaceClient, type MarketplaceClientOptions, type MarketplaceEntry, type MarketplaceSort, type MathHelpers, type MentionProviderContribution, type MentionSuggestion, MiddlewareChain, type MissingDependency, type ModuleCapabilities, NOTION_CONNECTOR_ID, type NodeChangeEvent, type NodeChangeEventData, type NodeData, type NodeStoreAPI, type NodeStoreMiddleware, type NotionConnectorOptions, OllamaProvider, OpenAICompatibleProvider, type OpenAICompatibleProviderOptions, OpenAIProvider, type PendingChange, type Platform, type PlatformCapabilities, type PluginContributions, PluginError, type PluginNode, type PluginNodeChangeEvent, type PluginNodeChangeListener, type PluginPermissions, type PluginPricing, type PluginRating, PluginRegistry, type PluginRunInput, type PluginRunResult, PluginRuntimeError, type PluginRuntimeLadder, PluginSchema, type PluginStatus, PluginValidationError, type ProcessManagerEvents, PromptApiProvider, type PromptApiProviderOptions, type PropertyCellProps, type PropertyEditorProps, type PropertyHandler, type PropertyHandlerContribution, type Provenance, type ProvenanceResult, type ProvenanceVerifier, type QueryFilter, RSS_CONNECTOR_ID, type RatingSummary, type RecommendOptions, type RegisteredPlugin, type ResolveMentionOptions, type RssConnectorOptions, type RunActionPorts, type RunConnectorSyncPorts, type RunPluginCodeInput, SERVICE_IPC_CHANNELS, SLACK_CONNECTOR_ID, type SandboxOptions, ScaffoldError, type ScaffoldResult, type ScaffoldSpec, type ScaffoldTemplate, type SchemaContribution, type SchemaData, type SchemaDefinition, type SchemaProperty, type SchemaRegistryAPI, type ScriptContext, ScriptError, type ScriptExecutionResult, type ScriptExecutor, ScriptGenerationError, ScriptGenerator, type ScriptGeneratorOptions, type ScriptNode, type ScriptNodeChangeEvent, type ScriptOutputType, ScriptRunner, type ScriptRunnerOptions, ScriptSandbox, ScriptSchema, type ScriptStore, ScriptTimeoutError, type ScriptToManifestInput, type ScriptTriggerType, ScriptValidationError, type SemVer, type ServiceClient, type ServiceCommunication, type ServiceDefinition, type ServiceHealthCheck, type ServiceLifecycle, type ServiceOutputEvent, type ServiceProcessConfig, type ServiceProvides, type ServiceState, type ServiceStatus, type ServiceStatusEvent, type SettingContribution, type SettingsPanelProps, ShortcutManager, type SidebarContribution, type SlackConnectorOptions, type SlashCommandContext, type SlashCommandContribution, type StatusBarContribution, type TelemetryReporter, type TestHarnessOptions, type TestNodeStore, type TestPluginHarness, type TextHelpers, type ToolCallingFidelity, type ToolbarContribution, TypedRegistry, type UsageSignal, type ValidationResult, type VerifyProvenanceInput, type ViewContribution, type ViewProps, type WebLLMEngineLike, WebLLMProvider, type WebLLMProviderOptions, type WebhookConfig, WebhookEmitter, type WebhookOutOptions, type WebhookPayload, type WidgetContribution, type WidgetContributionConfigField, type WidgetContributionProps, type WorkspaceCommand, type WrapCliConnectorOptions, type WriteMode, XNET_MARKDOWN_DIRECTIVE_SPECS, type XNetExtension, type XNetMarkdownDiffLine, type XNetMarkdownDiffLineKind, type XNetMarkdownDirective, type XNetMarkdownDirectiveSpec, type XNetMarkdownReviewDiff, type XNetPageMarkdownFrontmatter, type XNetPageMarkdownValidation, type XNetPageMarkdownValidationOptions, agentToolToExtraTool, agentToolsAsExtraTools, aggregateRatings, assertNetwork, assertPublicUrl, assertSchemaWrite, attachAiPlanValidation, buildAirtableConnector, buildDiscordAction, buildEmailAction, buildGithubConnector, buildLinearConnector, buildNotionConnector, buildRetryPrompt, buildRssConnector, buildScriptPrompt, buildSlackConnector, buildSlackWebhookAction, buildTelegramAction, buildWebhookOutAction, classifyAiAgentDisplayState, compareVersions, connectorAsImporter, connectorMarketplaceEntry, contributionsAsAiTools, createAIProvider, createAIProviderRouter, createAiAgentRuntime, createAiChangeSet, createAiOperation, createAiSurfaceService, createAiValidationResult, createCanvasErpPrototypeRiskSummary, createCanvasErpPrototypeScenario, createCanvasPluginFixtureCards, createCanvasPluginFixtureManifests, createCanvasPluginPermissionPrompt, createCanvasPluginSandboxPolicy, createCanvasPreviewSandboxRequest, createCanvasRendererSandboxRequest, createExtensionContext, createExtensionStorage, createManagedProvider, createMemoryAiAgentRuntimeStorage, createPromptApiProvider, createScriptContext, createServiceClient, createTestNodeStore, createTestPluginHarness, createWebLLMProvider, createWebhookEmitter, defaultLocalServerProbes, defineAction, defineConnector, defineExtension, defineFeatureModule, describeCapabilities, detectConnectors, emitConnectorArtifacts, evaluateCanvasPluginPermissionGate, evaluateCanvasPluginSandboxRequest, evaluateConnectorInstall, evaluateInstallConsent, executeScript, failClosedVerifier, filterByCategory, findEditorSchemaRisks, findMissingDependencies, generateScript, getCanvasErpPrototypeAuditEntriesForCard, getCanvasErpPrototypeCardsForFrame, getCanvasPluginFixture, getCommandRegistry, getPlatformCapabilities, getShortcutManager, getXNetMarkdownDirectiveSpecs, guardStore, guardedActionFetch, guardedFetch, hasUpdate, importerAdapters, installCommandHandler, installShortcutHandler, isAiRiskLevel, isAiScope, isAiTargetKind, isAllowedPluginLicense, isHostCompatible, isNetworkAllowed, isOllamaAvailable, isPaidPricing, isSchemaDefiningExtension, isSchemaReadAllowed, isSchemaWriteAllowed, isScriptNode, isServiceClientAvailable, ladderTierForTrust, listOllamaModels, matchSchemaIri, normalizeCanvasPluginWorkspacePolicy, packageName, parseAiMutationPlan, parseFeed, parseVersion, parseXNetPageFrontmatter, pascalCase, pickBestConnector, pluginLicenseText, probeOpenAiCompatible, quickSafetyCheck, recommendExtensions, renderEvent, renderMarkdownLineDiff, renderMarkdownReviewDiff, renderSelectionPrompt, resolveImporters, resolveInstallOrder, resolveMentionProviders, runAction, runAiPluginPipeline, runConnectorSync, runPluginCode, satisfiesRange, scaffoldPlugin, scriptToPluginManifest, searchMarketplace, serializeAiMutationPlan, shortSchemaName, shouldDispatch, sortMarketplace, stripXNetPageFrontmatter, summarizeProvenance, validateAiMutationPlan, validateCanvasPluginSandboxOutput, validateManifest, validateScript, validateScriptAST, validateXNetPageMarkdown, verifyProvenance, warnOnEditorSchemaRisks, wrapCliConnector, writeModeFor };
|