@xnetjs/plugins 0.1.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +50 -1
- package/dist/index.js +1148 -966
- package/dist/services/node.d.ts +12 -0
- package/dist/services/node.js +1146 -966
- package/package.json +6 -6
package/dist/index.js
CHANGED
|
@@ -516,6 +516,7 @@ var ContributionRegistry = class {
|
|
|
516
516
|
importers = new TypedRegistry();
|
|
517
517
|
mentionProviders = new TypedRegistry();
|
|
518
518
|
agentTools = new TypedRegistry();
|
|
519
|
+
surfaceDock = new TypedRegistry();
|
|
519
520
|
/**
|
|
520
521
|
* Clear all registries (for cleanup/testing)
|
|
521
522
|
*/
|
|
@@ -540,6 +541,7 @@ var ContributionRegistry = class {
|
|
|
540
541
|
this.importers.clear();
|
|
541
542
|
this.mentionProviders.clear();
|
|
542
543
|
this.agentTools.clear();
|
|
544
|
+
this.surfaceDock.clear();
|
|
543
545
|
}
|
|
544
546
|
};
|
|
545
547
|
|
|
@@ -4874,6 +4876,86 @@ function hasWriteScope(plan) {
|
|
|
4874
4876
|
);
|
|
4875
4877
|
}
|
|
4876
4878
|
|
|
4879
|
+
// src/ai-surface/args.ts
|
|
4880
|
+
function readRequiredString(record, key) {
|
|
4881
|
+
const value = record[key];
|
|
4882
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
4883
|
+
throw new Error(`${key} must be a non-empty string`);
|
|
4884
|
+
}
|
|
4885
|
+
return value;
|
|
4886
|
+
}
|
|
4887
|
+
function readRequiredRecord(record, key) {
|
|
4888
|
+
const value = record[key];
|
|
4889
|
+
if (!isRecord3(value)) {
|
|
4890
|
+
throw new Error(`${key} must be an object`);
|
|
4891
|
+
}
|
|
4892
|
+
return value;
|
|
4893
|
+
}
|
|
4894
|
+
function readRequiredStringArray(value, key) {
|
|
4895
|
+
const result = readStringArray(value);
|
|
4896
|
+
if (result.length === 0) {
|
|
4897
|
+
throw new Error(`${key} must contain at least one string`);
|
|
4898
|
+
}
|
|
4899
|
+
return result;
|
|
4900
|
+
}
|
|
4901
|
+
function readStringArray(value) {
|
|
4902
|
+
if (!Array.isArray(value)) return [];
|
|
4903
|
+
return value.filter((item) => typeof item === "string" && item.trim() !== "");
|
|
4904
|
+
}
|
|
4905
|
+
function readCsvStringArray(value) {
|
|
4906
|
+
if (!value) return [];
|
|
4907
|
+
return value.split(",").map((item) => item.trim()).filter(Boolean);
|
|
4908
|
+
}
|
|
4909
|
+
function readOptionalString(record, key) {
|
|
4910
|
+
const value = record[key];
|
|
4911
|
+
return typeof value === "string" && value.trim() ? value : void 0;
|
|
4912
|
+
}
|
|
4913
|
+
function readOptionalRecord(record, key) {
|
|
4914
|
+
return readRecord(record, key);
|
|
4915
|
+
}
|
|
4916
|
+
function readOptionalNumber(record, key) {
|
|
4917
|
+
const value = record[key];
|
|
4918
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
4919
|
+
}
|
|
4920
|
+
function readOptionalBoolean(record, key) {
|
|
4921
|
+
const value = record[key];
|
|
4922
|
+
return typeof value === "boolean" ? value : void 0;
|
|
4923
|
+
}
|
|
4924
|
+
function readUrlNumber(params, key) {
|
|
4925
|
+
const value = params.get(key);
|
|
4926
|
+
if (value === null) return void 0;
|
|
4927
|
+
const parsed = Number(value);
|
|
4928
|
+
return Number.isFinite(parsed) ? parsed : void 0;
|
|
4929
|
+
}
|
|
4930
|
+
function readRecordString(record, key) {
|
|
4931
|
+
const value = record[key];
|
|
4932
|
+
return typeof value === "string" && value.trim() ? value : void 0;
|
|
4933
|
+
}
|
|
4934
|
+
function readRecord(record, key) {
|
|
4935
|
+
const value = record[key];
|
|
4936
|
+
return isRecord3(value) ? value : void 0;
|
|
4937
|
+
}
|
|
4938
|
+
function readRecordNumber(record, key) {
|
|
4939
|
+
const value = record[key];
|
|
4940
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
4941
|
+
}
|
|
4942
|
+
function readRecordBoolean(record, key) {
|
|
4943
|
+
const value = record[key];
|
|
4944
|
+
return typeof value === "boolean" ? value : void 0;
|
|
4945
|
+
}
|
|
4946
|
+
function isRecord3(value) {
|
|
4947
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4948
|
+
}
|
|
4949
|
+
function readContextSeeds(value) {
|
|
4950
|
+
if (!Array.isArray(value)) return [];
|
|
4951
|
+
return value.map((seed) => {
|
|
4952
|
+
if (!isRecord3(seed)) return null;
|
|
4953
|
+
const kind = typeof seed.kind === "string" ? seed.kind : null;
|
|
4954
|
+
const id = typeof seed.id === "string" ? seed.id : null;
|
|
4955
|
+
return kind && id ? { kind, id } : null;
|
|
4956
|
+
}).filter((seed) => seed !== null);
|
|
4957
|
+
}
|
|
4958
|
+
|
|
4877
4959
|
// src/ai-surface/page-markdown.ts
|
|
4878
4960
|
var XNET_MARKDOWN_DIRECTIVE_SPECS = [
|
|
4879
4961
|
{
|
|
@@ -5109,7 +5191,7 @@ function findJsonPayloadEnd(src, startIndex) {
|
|
|
5109
5191
|
function parseJsonObject(rawPayload, label, errors) {
|
|
5110
5192
|
try {
|
|
5111
5193
|
const parsed = JSON.parse(rawPayload);
|
|
5112
|
-
if (
|
|
5194
|
+
if (isRecord4(parsed)) return parsed;
|
|
5113
5195
|
errors.push(`${label} payload must be a JSON object`);
|
|
5114
5196
|
return null;
|
|
5115
5197
|
} catch {
|
|
@@ -5143,7 +5225,7 @@ function unquoteYamlScalar(value) {
|
|
|
5143
5225
|
return trimmed.slice(1, -1);
|
|
5144
5226
|
}
|
|
5145
5227
|
}
|
|
5146
|
-
function
|
|
5228
|
+
function isRecord4(value) {
|
|
5147
5229
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5148
5230
|
}
|
|
5149
5231
|
function markdownDiffPrefix(kind) {
|
|
@@ -5152,900 +5234,1094 @@ function markdownDiffPrefix(kind) {
|
|
|
5152
5234
|
return " ";
|
|
5153
5235
|
}
|
|
5154
5236
|
|
|
5155
|
-
// src/ai-surface/
|
|
5156
|
-
var
|
|
5157
|
-
|
|
5158
|
-
|
|
5159
|
-
|
|
5160
|
-
|
|
5161
|
-
|
|
5162
|
-
|
|
5163
|
-
|
|
5164
|
-
|
|
5165
|
-
|
|
5166
|
-
|
|
5167
|
-
|
|
5168
|
-
|
|
5169
|
-
|
|
5170
|
-
|
|
5171
|
-
|
|
5172
|
-
|
|
5237
|
+
// src/ai-surface/resources/router.ts
|
|
5238
|
+
var XNET_URI_PREFIX = "xnet://";
|
|
5239
|
+
var PARAM_SEGMENT_PATTERN = /^\{([a-zA-Z][a-zA-Z0-9]*)\}(.*)$/;
|
|
5240
|
+
function createAiResourceRouter() {
|
|
5241
|
+
const routes = [];
|
|
5242
|
+
const router = {
|
|
5243
|
+
register(template, handler) {
|
|
5244
|
+
routes.push(compileRoute(template, handler));
|
|
5245
|
+
return router;
|
|
5246
|
+
},
|
|
5247
|
+
async resolve(host, uri) {
|
|
5248
|
+
const parsed = parseXNetUri(uri);
|
|
5249
|
+
for (const route of routes) {
|
|
5250
|
+
const params = matchRoute(route, parsed);
|
|
5251
|
+
if (params) {
|
|
5252
|
+
return await route.handler(host, { uri, params, searchParams: parsed.searchParams });
|
|
5253
|
+
}
|
|
5254
|
+
}
|
|
5255
|
+
throw new Error(`Resource not found: ${uri}`);
|
|
5173
5256
|
}
|
|
5257
|
+
};
|
|
5258
|
+
return router;
|
|
5259
|
+
}
|
|
5260
|
+
function parseXNetUri(uri) {
|
|
5261
|
+
let parsed;
|
|
5262
|
+
try {
|
|
5263
|
+
parsed = new URL(uri);
|
|
5264
|
+
} catch {
|
|
5265
|
+
throw new Error(`Invalid xNet resource URI: ${uri}`);
|
|
5174
5266
|
}
|
|
5175
|
-
|
|
5176
|
-
|
|
5177
|
-
sequence = 0;
|
|
5178
|
-
auditEvents = [];
|
|
5179
|
-
rollbackSnapshots = /* @__PURE__ */ new Map();
|
|
5180
|
-
/** Contributed tools by name (exploration 0196), de-duped at construction. */
|
|
5181
|
-
extraTools = /* @__PURE__ */ new Map();
|
|
5182
|
-
/** The contributed (non-built-in) tools, with built-in name collisions removed. */
|
|
5183
|
-
getExtraTools() {
|
|
5184
|
-
const builtIn = new Set(this.builtInTools().map((t) => t.name));
|
|
5185
|
-
return [...this.extraTools.values()].filter((t) => !builtIn.has(t.name));
|
|
5267
|
+
if (parsed.protocol !== "xnet:") {
|
|
5268
|
+
throw new Error(`Invalid xNet resource URI: ${uri}`);
|
|
5186
5269
|
}
|
|
5187
|
-
|
|
5188
|
-
|
|
5189
|
-
|
|
5190
|
-
|
|
5191
|
-
|
|
5192
|
-
|
|
5193
|
-
|
|
5194
|
-
|
|
5195
|
-
|
|
5196
|
-
),
|
|
5197
|
-
createResource(
|
|
5198
|
-
"xnet://workspace/recent",
|
|
5199
|
-
"Recent Workspace Nodes",
|
|
5200
|
-
"Recent nodes with ids, schemas, titles, and revisions.",
|
|
5201
|
-
"application/json",
|
|
5202
|
-
"low",
|
|
5203
|
-
["workspace.read"]
|
|
5204
|
-
),
|
|
5205
|
-
createResource(
|
|
5206
|
-
"xnet://nodes",
|
|
5207
|
-
"All Nodes",
|
|
5208
|
-
"Limited list of nodes in the local store.",
|
|
5209
|
-
"application/json",
|
|
5210
|
-
"low",
|
|
5211
|
-
["workspace.read"]
|
|
5212
|
-
),
|
|
5213
|
-
createResource(
|
|
5214
|
-
"xnet://schemas",
|
|
5215
|
-
"All Schemas",
|
|
5216
|
-
"List of available schemas and property metadata.",
|
|
5217
|
-
"application/json",
|
|
5218
|
-
"low",
|
|
5219
|
-
["workspace.read"]
|
|
5220
|
-
),
|
|
5221
|
-
createResource(
|
|
5222
|
-
"xnet://page/{pageId}.md",
|
|
5223
|
-
"Page Markdown",
|
|
5224
|
-
"Markdown projection for a page, including xNet frontmatter identity.",
|
|
5225
|
-
"text/markdown",
|
|
5226
|
-
"low",
|
|
5227
|
-
["page.read"],
|
|
5228
|
-
true
|
|
5229
|
-
),
|
|
5230
|
-
createResource(
|
|
5231
|
-
"xnet://page/{pageId}/outline",
|
|
5232
|
-
"Page Outline",
|
|
5233
|
-
"Page heading outline extracted from the Markdown projection.",
|
|
5234
|
-
"application/json",
|
|
5235
|
-
"low",
|
|
5236
|
-
["page.read"],
|
|
5237
|
-
true
|
|
5238
|
-
),
|
|
5239
|
-
createResource(
|
|
5240
|
-
"xnet://database/{databaseId}/schema",
|
|
5241
|
-
"Database Schema",
|
|
5242
|
-
"Database node metadata, declared properties, and known column descriptors.",
|
|
5243
|
-
"application/json",
|
|
5244
|
-
"low",
|
|
5245
|
-
["database.read"],
|
|
5246
|
-
true
|
|
5247
|
-
),
|
|
5248
|
-
createResource(
|
|
5249
|
-
"xnet://database/{databaseId}/views",
|
|
5250
|
-
"Database Views",
|
|
5251
|
-
"Known database view descriptors from the database node projection.",
|
|
5252
|
-
"application/json",
|
|
5253
|
-
"low",
|
|
5254
|
-
["database.read"],
|
|
5255
|
-
true
|
|
5256
|
-
),
|
|
5257
|
-
createResource(
|
|
5258
|
-
"xnet://database/{databaseId}/sample?limit=10",
|
|
5259
|
-
"Database Sample Rows",
|
|
5260
|
-
"Bounded sample of rows for a database using NodeQueryDescriptor semantics.",
|
|
5261
|
-
"application/json",
|
|
5262
|
-
"low",
|
|
5263
|
-
["database.read", "database.query"],
|
|
5264
|
-
true
|
|
5265
|
-
),
|
|
5266
|
-
createResource(
|
|
5267
|
-
"xnet://canvas/{canvasId}/viewport?x=0&y=0&w=1000&h=800",
|
|
5268
|
-
"Canvas Viewport",
|
|
5269
|
-
"Viewport-scoped canvas objects and edges.",
|
|
5270
|
-
"application/json",
|
|
5271
|
-
"low",
|
|
5272
|
-
["canvas.read"],
|
|
5273
|
-
true
|
|
5274
|
-
),
|
|
5275
|
-
createResource(
|
|
5276
|
-
"xnet://canvas/{canvasId}/objects",
|
|
5277
|
-
"Canvas Objects",
|
|
5278
|
-
"Bounded list of canvas objects and connectors.",
|
|
5279
|
-
"application/json",
|
|
5280
|
-
"low",
|
|
5281
|
-
["canvas.read"],
|
|
5282
|
-
true
|
|
5283
|
-
),
|
|
5284
|
-
createResource(
|
|
5285
|
-
"xnet://canvas/{canvasId}/selection?ids=object-1,object-2",
|
|
5286
|
-
"Canvas Selection",
|
|
5287
|
-
"Selection-scoped canvas objects, edges, and source previews.",
|
|
5288
|
-
"application/json",
|
|
5289
|
-
"low",
|
|
5290
|
-
["canvas.read"],
|
|
5291
|
-
true
|
|
5292
|
-
),
|
|
5293
|
-
createResource(
|
|
5294
|
-
"xnet://canvas/{canvasId}/json-canvas",
|
|
5295
|
-
"Canvas JSON Canvas",
|
|
5296
|
-
"JSON Canvas projection with xNet source metadata sidecars.",
|
|
5297
|
-
"application/json",
|
|
5298
|
-
"low",
|
|
5299
|
-
["canvas.read"],
|
|
5300
|
-
true
|
|
5301
|
-
)
|
|
5302
|
-
];
|
|
5270
|
+
return {
|
|
5271
|
+
host: parsed.hostname,
|
|
5272
|
+
parts: parsed.pathname.split("/").filter(Boolean).map((part) => decodeURIComponent(part)),
|
|
5273
|
+
searchParams: parsed.searchParams
|
|
5274
|
+
};
|
|
5275
|
+
}
|
|
5276
|
+
function compileRoute(template, handler) {
|
|
5277
|
+
if (!template.startsWith(XNET_URI_PREFIX)) {
|
|
5278
|
+
throw new Error(`Resource route template must start with ${XNET_URI_PREFIX}: ${template}`);
|
|
5303
5279
|
}
|
|
5304
|
-
|
|
5305
|
-
|
|
5306
|
-
|
|
5307
|
-
|
|
5308
|
-
);
|
|
5309
|
-
return [...this.builtInTools(), ...extras];
|
|
5280
|
+
const [path] = template.slice(XNET_URI_PREFIX.length).split("?");
|
|
5281
|
+
const [host, ...rawSegments] = path.split("/").filter(Boolean);
|
|
5282
|
+
if (!host) {
|
|
5283
|
+
throw new Error(`Resource route template must include a host: ${template}`);
|
|
5310
5284
|
}
|
|
5311
|
-
|
|
5312
|
-
|
|
5313
|
-
|
|
5314
|
-
|
|
5315
|
-
|
|
5316
|
-
|
|
5317
|
-
|
|
5318
|
-
|
|
5319
|
-
|
|
5320
|
-
|
|
5321
|
-
|
|
5322
|
-
|
|
5323
|
-
|
|
5324
|
-
|
|
5325
|
-
|
|
5326
|
-
|
|
5327
|
-
|
|
5328
|
-
|
|
5329
|
-
|
|
5330
|
-
|
|
5331
|
-
|
|
5332
|
-
|
|
5333
|
-
|
|
5334
|
-
|
|
5335
|
-
|
|
5336
|
-
|
|
5337
|
-
|
|
5338
|
-
|
|
5339
|
-
|
|
5340
|
-
|
|
5341
|
-
|
|
5342
|
-
|
|
5343
|
-
|
|
5344
|
-
|
|
5345
|
-
|
|
5346
|
-
|
|
5347
|
-
|
|
5285
|
+
return {
|
|
5286
|
+
host,
|
|
5287
|
+
segments: rawSegments.map((segment) => {
|
|
5288
|
+
const param = PARAM_SEGMENT_PATTERN.exec(segment);
|
|
5289
|
+
return param ? { kind: "param", name: param[1], suffix: param[2] } : { kind: "literal", value: segment };
|
|
5290
|
+
}),
|
|
5291
|
+
handler
|
|
5292
|
+
};
|
|
5293
|
+
}
|
|
5294
|
+
function matchRoute(route, parsed) {
|
|
5295
|
+
if (parsed.host !== route.host) return null;
|
|
5296
|
+
if (parsed.parts.length !== route.segments.length) return null;
|
|
5297
|
+
const params = {};
|
|
5298
|
+
for (const [index, segment] of route.segments.entries()) {
|
|
5299
|
+
const part = parsed.parts[index];
|
|
5300
|
+
if (segment.kind === "literal") {
|
|
5301
|
+
if (part !== segment.value) return null;
|
|
5302
|
+
continue;
|
|
5303
|
+
}
|
|
5304
|
+
if (segment.suffix && !part.endsWith(segment.suffix)) return null;
|
|
5305
|
+
params[segment.name] = segment.suffix ? part.slice(0, -segment.suffix.length) : part;
|
|
5306
|
+
}
|
|
5307
|
+
return params;
|
|
5308
|
+
}
|
|
5309
|
+
|
|
5310
|
+
// src/ai-surface/resources/routes.ts
|
|
5311
|
+
function createBuiltInResourceRouter() {
|
|
5312
|
+
return createAiResourceRouter().register(
|
|
5313
|
+
"xnet://nodes",
|
|
5314
|
+
async (host, { uri }) => host.jsonResource(uri, await host.listNodes())
|
|
5315
|
+
).register(
|
|
5316
|
+
"xnet://schemas",
|
|
5317
|
+
async (host, { uri }) => host.jsonResource(uri, await host.listSchemas())
|
|
5318
|
+
).register(
|
|
5319
|
+
"xnet://workspace/summary",
|
|
5320
|
+
async (host, { uri }) => host.jsonResource(uri, await host.getWorkspaceSummary())
|
|
5321
|
+
).register(
|
|
5322
|
+
"xnet://workspace/recent",
|
|
5323
|
+
async (host, { uri }) => host.jsonResource(uri, await host.getRecentNodes())
|
|
5324
|
+
).register(
|
|
5325
|
+
"xnet://workspace/search",
|
|
5326
|
+
async (host, { uri, searchParams }) => host.jsonResource(
|
|
5327
|
+
uri,
|
|
5328
|
+
await host.search({
|
|
5329
|
+
query: searchParams.get("q") ?? "",
|
|
5330
|
+
schemaId: searchParams.get("schema") ?? void 0,
|
|
5331
|
+
limit: readUrlNumber(searchParams, "limit"),
|
|
5332
|
+
offset: readUrlNumber(searchParams, "offset")
|
|
5333
|
+
})
|
|
5334
|
+
)
|
|
5335
|
+
).register(
|
|
5336
|
+
"xnet://node/{nodeId}",
|
|
5337
|
+
async (host, { uri, params }) => host.jsonResource(uri, await host.getNodeProjection(params.nodeId))
|
|
5338
|
+
).register(
|
|
5339
|
+
"xnet://page/{pageId}.md",
|
|
5340
|
+
async (host, { uri, params }) => await host.readPageMarkdown(params.pageId, true, uri)
|
|
5341
|
+
).register(
|
|
5342
|
+
"xnet://page/{pageId}",
|
|
5343
|
+
async (host, { uri, params }) => await host.readPageMarkdown(params.pageId, true, uri)
|
|
5344
|
+
).register(
|
|
5345
|
+
"xnet://page/{pageId}/outline",
|
|
5346
|
+
async (host, { uri, params }) => host.jsonResource(uri, await host.readPageOutline(params.pageId))
|
|
5347
|
+
).register(
|
|
5348
|
+
"xnet://page/{pageId}/context-pack",
|
|
5349
|
+
async (host, { uri, params }) => host.jsonResource(
|
|
5350
|
+
uri,
|
|
5351
|
+
await host.createContextPack({ seeds: [{ kind: "page", id: params.pageId }] })
|
|
5352
|
+
)
|
|
5353
|
+
).register(
|
|
5354
|
+
"xnet://database/{databaseId}/schema",
|
|
5355
|
+
async (host, { uri, params }) => host.jsonResource(uri, await host.describeDatabase(params.databaseId))
|
|
5356
|
+
).register(
|
|
5357
|
+
"xnet://database/{databaseId}/views",
|
|
5358
|
+
async (host, { uri, params }) => host.jsonResource(uri, await host.readDatabaseViews(params.databaseId))
|
|
5359
|
+
).register(
|
|
5360
|
+
"xnet://database/{databaseId}/sample",
|
|
5361
|
+
async (host, { uri, params, searchParams }) => host.jsonResource(
|
|
5362
|
+
uri,
|
|
5363
|
+
await host.sampleDatabase({
|
|
5364
|
+
databaseId: params.databaseId,
|
|
5365
|
+
sampleSize: readUrlNumber(searchParams, "limit")
|
|
5366
|
+
})
|
|
5367
|
+
)
|
|
5368
|
+
).register(
|
|
5369
|
+
"xnet://database/{databaseId}/query",
|
|
5370
|
+
async (host, { uri, params, searchParams }) => host.jsonResource(
|
|
5371
|
+
uri,
|
|
5372
|
+
await host.queryDatabase({
|
|
5373
|
+
databaseId: params.databaseId,
|
|
5374
|
+
schemaId: searchParams.get("schema") ?? void 0,
|
|
5375
|
+
search: searchParams.get("q") ?? void 0,
|
|
5376
|
+
materializedView: searchParams.get("view") ? { viewId: searchParams.get("view") ?? "" } : void 0,
|
|
5377
|
+
limit: readUrlNumber(searchParams, "limit"),
|
|
5378
|
+
offset: readUrlNumber(searchParams, "offset")
|
|
5379
|
+
})
|
|
5380
|
+
)
|
|
5381
|
+
).register(
|
|
5382
|
+
"xnet://canvas/{canvasId}/viewport",
|
|
5383
|
+
async (host, { uri, params, searchParams }) => host.jsonResource(
|
|
5384
|
+
uri,
|
|
5385
|
+
await host.readCanvasViewport({
|
|
5386
|
+
canvasId: params.canvasId,
|
|
5387
|
+
x: readUrlNumber(searchParams, "x"),
|
|
5388
|
+
y: readUrlNumber(searchParams, "y"),
|
|
5389
|
+
w: readUrlNumber(searchParams, "w"),
|
|
5390
|
+
h: readUrlNumber(searchParams, "h"),
|
|
5391
|
+
tileSize: readUrlNumber(searchParams, "tileSize"),
|
|
5392
|
+
tileIds: readCsvStringArray(searchParams.get("tileIds")),
|
|
5393
|
+
includeSourcePreviews: searchParams.get("includeSourcePreviews") === "true"
|
|
5394
|
+
})
|
|
5395
|
+
)
|
|
5396
|
+
).register(
|
|
5397
|
+
"xnet://canvas/{canvasId}/objects",
|
|
5398
|
+
async (host, { uri, params }) => host.jsonResource(uri, await host.readCanvasObjects(params.canvasId))
|
|
5399
|
+
).register(
|
|
5400
|
+
"xnet://canvas/{canvasId}/selection",
|
|
5401
|
+
async (host, { uri, params, searchParams }) => host.jsonResource(
|
|
5402
|
+
uri,
|
|
5403
|
+
await host.readCanvasSelection({
|
|
5404
|
+
canvasId: params.canvasId,
|
|
5405
|
+
objectIds: readCsvStringArray(searchParams.get("ids")),
|
|
5406
|
+
includeSourcePreviews: searchParams.get("includeSourcePreviews") !== "false"
|
|
5407
|
+
})
|
|
5408
|
+
)
|
|
5409
|
+
).register(
|
|
5410
|
+
"xnet://canvas/{canvasId}/json-canvas",
|
|
5411
|
+
async (host, { uri, params, searchParams }) => host.jsonResource(
|
|
5412
|
+
uri,
|
|
5413
|
+
await host.exportCanvasJsonCanvas({
|
|
5414
|
+
canvasId: params.canvasId,
|
|
5415
|
+
includeXNetMetadata: searchParams.get("includeXNetMetadata") !== "false"
|
|
5416
|
+
})
|
|
5417
|
+
)
|
|
5418
|
+
).register(
|
|
5419
|
+
"xnet://canvas/{canvasId}/object/{objectId}",
|
|
5420
|
+
async (host, { uri, params }) => host.jsonResource(uri, await host.readCanvasObject(params.canvasId, params.objectId))
|
|
5421
|
+
);
|
|
5422
|
+
}
|
|
5423
|
+
|
|
5424
|
+
// src/ai-surface/tools/audit.ts
|
|
5425
|
+
var getAuditLogTool = {
|
|
5426
|
+
definition: {
|
|
5427
|
+
name: "xnet_get_audit_log",
|
|
5428
|
+
title: "Read AI audit log",
|
|
5429
|
+
description: "Read recent AI mutation audit events with optional plan filtering.",
|
|
5430
|
+
risk: "low",
|
|
5431
|
+
requiredScopes: ["workspace.read"],
|
|
5432
|
+
inputSchema: {
|
|
5433
|
+
type: "object",
|
|
5434
|
+
properties: {
|
|
5435
|
+
planId: { type: "string", description: "Optional mutation plan id filter." },
|
|
5436
|
+
limit: { type: "number", description: "Maximum audit events to return." }
|
|
5437
|
+
}
|
|
5438
|
+
}
|
|
5439
|
+
},
|
|
5440
|
+
execute: (host, args) => host.getAuditLog({
|
|
5441
|
+
planId: readOptionalString(args, "planId"),
|
|
5442
|
+
limit: readOptionalNumber(args, "limit")
|
|
5443
|
+
})
|
|
5444
|
+
};
|
|
5445
|
+
var validateMutationPlanTool = {
|
|
5446
|
+
definition: {
|
|
5447
|
+
name: "xnet_validate_mutation_plan",
|
|
5448
|
+
title: "Validate mutation plan",
|
|
5449
|
+
description: "Validate a serialized mutation plan and return errors or warnings.",
|
|
5450
|
+
risk: "medium",
|
|
5451
|
+
requiredScopes: ["workspace.read"],
|
|
5452
|
+
inputSchema: {
|
|
5453
|
+
type: "object",
|
|
5454
|
+
properties: {
|
|
5455
|
+
plan: { type: "object", description: "Mutation plan object to validate." }
|
|
5348
5456
|
},
|
|
5349
|
-
|
|
5350
|
-
|
|
5351
|
-
|
|
5352
|
-
|
|
5353
|
-
|
|
5354
|
-
|
|
5355
|
-
|
|
5356
|
-
|
|
5357
|
-
|
|
5358
|
-
|
|
5359
|
-
|
|
5360
|
-
|
|
5361
|
-
|
|
5362
|
-
|
|
5363
|
-
|
|
5364
|
-
|
|
5365
|
-
|
|
5366
|
-
|
|
5367
|
-
|
|
5368
|
-
|
|
5369
|
-
|
|
5370
|
-
|
|
5371
|
-
|
|
5457
|
+
required: ["plan"]
|
|
5458
|
+
}
|
|
5459
|
+
},
|
|
5460
|
+
execute: (_host, args) => {
|
|
5461
|
+
const validation = validateAiMutationPlan(args.plan);
|
|
5462
|
+
return { validation };
|
|
5463
|
+
}
|
|
5464
|
+
};
|
|
5465
|
+
|
|
5466
|
+
// src/ai-surface/tools/canvas.ts
|
|
5467
|
+
var canvasListTool = {
|
|
5468
|
+
definition: {
|
|
5469
|
+
name: "xnet_canvas_list",
|
|
5470
|
+
title: "List canvases",
|
|
5471
|
+
description: "List canvas nodes visible to the AI surface.",
|
|
5472
|
+
risk: "low",
|
|
5473
|
+
requiredScopes: ["canvas.read"],
|
|
5474
|
+
inputSchema: {
|
|
5475
|
+
type: "object",
|
|
5476
|
+
properties: {
|
|
5477
|
+
limit: { type: "number", description: "Maximum canvas count." },
|
|
5478
|
+
offset: { type: "number", description: "Canvas offset." }
|
|
5479
|
+
}
|
|
5480
|
+
}
|
|
5481
|
+
},
|
|
5482
|
+
execute: async (host, args) => await host.listCanvases({
|
|
5483
|
+
limit: readOptionalNumber(args, "limit"),
|
|
5484
|
+
offset: readOptionalNumber(args, "offset")
|
|
5485
|
+
})
|
|
5486
|
+
};
|
|
5487
|
+
var canvasReadViewportTool = {
|
|
5488
|
+
definition: {
|
|
5489
|
+
name: "xnet_canvas_read_viewport",
|
|
5490
|
+
title: "Read canvas viewport",
|
|
5491
|
+
description: "Read canvas objects and edges intersecting a viewport.",
|
|
5492
|
+
risk: "low",
|
|
5493
|
+
requiredScopes: ["canvas.read"],
|
|
5494
|
+
inputSchema: {
|
|
5495
|
+
type: "object",
|
|
5496
|
+
properties: {
|
|
5497
|
+
canvasId: { type: "string", description: "Canvas node id." },
|
|
5498
|
+
x: { type: "number", description: "Viewport x." },
|
|
5499
|
+
y: { type: "number", description: "Viewport y." },
|
|
5500
|
+
w: { type: "number", description: "Viewport width." },
|
|
5501
|
+
h: { type: "number", description: "Viewport height." },
|
|
5502
|
+
includeSourcePreviews: {
|
|
5503
|
+
type: "boolean",
|
|
5504
|
+
description: "Include previews for source-backed objects."
|
|
5505
|
+
},
|
|
5506
|
+
tileSize: { type: "number", description: "Optional tile size for tile scoping." },
|
|
5507
|
+
tileIds: {
|
|
5508
|
+
type: "array",
|
|
5509
|
+
description: "Optional tile ids such as 0/1/-2 to constrain the read.",
|
|
5510
|
+
items: { type: "string" }
|
|
5372
5511
|
}
|
|
5373
5512
|
},
|
|
5374
|
-
|
|
5375
|
-
|
|
5376
|
-
|
|
5377
|
-
|
|
5378
|
-
|
|
5379
|
-
|
|
5380
|
-
|
|
5381
|
-
|
|
5382
|
-
|
|
5383
|
-
|
|
5384
|
-
|
|
5385
|
-
|
|
5386
|
-
|
|
5387
|
-
|
|
5513
|
+
required: ["canvasId"]
|
|
5514
|
+
}
|
|
5515
|
+
},
|
|
5516
|
+
execute: async (host, args) => await host.readCanvasViewport({
|
|
5517
|
+
canvasId: readRequiredString(args, "canvasId"),
|
|
5518
|
+
x: readOptionalNumber(args, "x"),
|
|
5519
|
+
y: readOptionalNumber(args, "y"),
|
|
5520
|
+
w: readOptionalNumber(args, "w"),
|
|
5521
|
+
h: readOptionalNumber(args, "h"),
|
|
5522
|
+
tileSize: readOptionalNumber(args, "tileSize"),
|
|
5523
|
+
tileIds: readStringArray(args.tileIds),
|
|
5524
|
+
includeSourcePreviews: readOptionalBoolean(args, "includeSourcePreviews") ?? false
|
|
5525
|
+
})
|
|
5526
|
+
};
|
|
5527
|
+
var canvasReadSelectionTool = {
|
|
5528
|
+
definition: {
|
|
5529
|
+
name: "xnet_canvas_read_selection",
|
|
5530
|
+
title: "Read canvas selection",
|
|
5531
|
+
description: "Read selected canvas objects, connected edges, and optional source previews.",
|
|
5532
|
+
risk: "low",
|
|
5533
|
+
requiredScopes: ["canvas.read"],
|
|
5534
|
+
inputSchema: {
|
|
5535
|
+
type: "object",
|
|
5536
|
+
properties: {
|
|
5537
|
+
canvasId: { type: "string", description: "Canvas node id." },
|
|
5538
|
+
objectIds: {
|
|
5539
|
+
type: "array",
|
|
5540
|
+
description: "Selected object ids.",
|
|
5541
|
+
items: { type: "string" }
|
|
5542
|
+
},
|
|
5543
|
+
includeSourcePreviews: {
|
|
5544
|
+
type: "boolean",
|
|
5545
|
+
description: "Include previews for source-backed objects."
|
|
5388
5546
|
}
|
|
5389
5547
|
},
|
|
5390
|
-
|
|
5391
|
-
|
|
5392
|
-
|
|
5393
|
-
|
|
5394
|
-
|
|
5395
|
-
|
|
5396
|
-
|
|
5397
|
-
|
|
5398
|
-
|
|
5399
|
-
|
|
5400
|
-
|
|
5401
|
-
|
|
5402
|
-
|
|
5403
|
-
|
|
5404
|
-
|
|
5405
|
-
|
|
5406
|
-
|
|
5548
|
+
required: ["canvasId", "objectIds"]
|
|
5549
|
+
}
|
|
5550
|
+
},
|
|
5551
|
+
execute: async (host, args) => await host.readCanvasSelection({
|
|
5552
|
+
canvasId: readRequiredString(args, "canvasId"),
|
|
5553
|
+
objectIds: readRequiredStringArray(args.objectIds, "objectIds"),
|
|
5554
|
+
includeSourcePreviews: readOptionalBoolean(args, "includeSourcePreviews") ?? false
|
|
5555
|
+
})
|
|
5556
|
+
};
|
|
5557
|
+
var canvasSearchTool = {
|
|
5558
|
+
definition: {
|
|
5559
|
+
name: "xnet_canvas_search",
|
|
5560
|
+
title: "Search canvas",
|
|
5561
|
+
description: "Search canvas object text, labels, ids, and source metadata.",
|
|
5562
|
+
risk: "low",
|
|
5563
|
+
requiredScopes: ["canvas.read"],
|
|
5564
|
+
inputSchema: {
|
|
5565
|
+
type: "object",
|
|
5566
|
+
properties: {
|
|
5567
|
+
canvasId: { type: "string", description: "Canvas node id." },
|
|
5568
|
+
query: { type: "string", description: "Search text." },
|
|
5569
|
+
limit: { type: "number", description: "Maximum result count." }
|
|
5407
5570
|
},
|
|
5408
|
-
|
|
5409
|
-
|
|
5410
|
-
|
|
5411
|
-
|
|
5412
|
-
|
|
5413
|
-
|
|
5414
|
-
|
|
5415
|
-
|
|
5416
|
-
|
|
5417
|
-
|
|
5418
|
-
|
|
5419
|
-
|
|
5420
|
-
|
|
5421
|
-
|
|
5422
|
-
|
|
5571
|
+
required: ["canvasId", "query"]
|
|
5572
|
+
}
|
|
5573
|
+
},
|
|
5574
|
+
execute: async (host, args) => await host.searchCanvas({
|
|
5575
|
+
canvasId: readRequiredString(args, "canvasId"),
|
|
5576
|
+
query: readRequiredString(args, "query"),
|
|
5577
|
+
limit: readOptionalNumber(args, "limit")
|
|
5578
|
+
})
|
|
5579
|
+
};
|
|
5580
|
+
var canvasExportJsonCanvasTool = {
|
|
5581
|
+
definition: {
|
|
5582
|
+
name: "xnet_canvas_export_json_canvas",
|
|
5583
|
+
title: "Export canvas as JSON Canvas",
|
|
5584
|
+
description: "Export a canvas or viewport as JSON Canvas with xNet source metadata.",
|
|
5585
|
+
risk: "low",
|
|
5586
|
+
requiredScopes: ["canvas.read"],
|
|
5587
|
+
inputSchema: {
|
|
5588
|
+
type: "object",
|
|
5589
|
+
properties: {
|
|
5590
|
+
canvasId: { type: "string", description: "Canvas node id." },
|
|
5591
|
+
includeXNetMetadata: {
|
|
5592
|
+
type: "boolean",
|
|
5593
|
+
description: "Include xNet source metadata. Defaults to true."
|
|
5594
|
+
},
|
|
5595
|
+
x: { type: "number", description: "Optional viewport x." },
|
|
5596
|
+
y: { type: "number", description: "Optional viewport y." },
|
|
5597
|
+
w: { type: "number", description: "Optional viewport width." },
|
|
5598
|
+
h: { type: "number", description: "Optional viewport height." }
|
|
5423
5599
|
},
|
|
5424
|
-
|
|
5425
|
-
|
|
5426
|
-
|
|
5427
|
-
|
|
5428
|
-
|
|
5429
|
-
|
|
5430
|
-
|
|
5431
|
-
|
|
5432
|
-
|
|
5433
|
-
|
|
5434
|
-
|
|
5435
|
-
|
|
5436
|
-
|
|
5437
|
-
|
|
5438
|
-
|
|
5439
|
-
|
|
5440
|
-
|
|
5600
|
+
required: ["canvasId"]
|
|
5601
|
+
}
|
|
5602
|
+
},
|
|
5603
|
+
execute: async (host, args) => await host.exportCanvasJsonCanvas({
|
|
5604
|
+
canvasId: readRequiredString(args, "canvasId"),
|
|
5605
|
+
includeXNetMetadata: readOptionalBoolean(args, "includeXNetMetadata") ?? true,
|
|
5606
|
+
x: readOptionalNumber(args, "x"),
|
|
5607
|
+
y: readOptionalNumber(args, "y"),
|
|
5608
|
+
w: readOptionalNumber(args, "w"),
|
|
5609
|
+
h: readOptionalNumber(args, "h")
|
|
5610
|
+
})
|
|
5611
|
+
};
|
|
5612
|
+
var canvasPlanJsonCanvasImportTool = {
|
|
5613
|
+
definition: {
|
|
5614
|
+
name: "xnet_canvas_plan_json_canvas_import",
|
|
5615
|
+
title: "Plan JSON Canvas import",
|
|
5616
|
+
description: "Convert a JSON Canvas document into a plan-only canvas mutation.",
|
|
5617
|
+
risk: "medium",
|
|
5618
|
+
requiredScopes: ["canvas.read", "canvas.propose"],
|
|
5619
|
+
inputSchema: {
|
|
5620
|
+
type: "object",
|
|
5621
|
+
properties: {
|
|
5622
|
+
canvasId: { type: "string", description: "Canvas node id." },
|
|
5623
|
+
document: { type: "object", description: "JSON Canvas document." },
|
|
5624
|
+
baseRevision: { type: "string", description: "Revision the import was based on." },
|
|
5625
|
+
actor: { type: "string", description: "Agent or user creating the plan." },
|
|
5626
|
+
intent: { type: "string", description: "User or agent intent for the import." }
|
|
5441
5627
|
},
|
|
5442
|
-
|
|
5443
|
-
|
|
5444
|
-
|
|
5445
|
-
|
|
5446
|
-
|
|
5447
|
-
|
|
5448
|
-
|
|
5449
|
-
|
|
5450
|
-
|
|
5451
|
-
|
|
5452
|
-
|
|
5453
|
-
|
|
5454
|
-
|
|
5455
|
-
|
|
5456
|
-
|
|
5457
|
-
|
|
5458
|
-
|
|
5459
|
-
|
|
5460
|
-
|
|
5461
|
-
|
|
5462
|
-
}
|
|
5628
|
+
required: ["canvasId", "document"]
|
|
5629
|
+
}
|
|
5630
|
+
},
|
|
5631
|
+
execute: async (host, args) => await host.planCanvasJsonCanvasImport(args)
|
|
5632
|
+
};
|
|
5633
|
+
var planCanvasMutationTool = {
|
|
5634
|
+
definition: {
|
|
5635
|
+
name: "xnet_plan_canvas_mutation",
|
|
5636
|
+
title: "Plan canvas mutation",
|
|
5637
|
+
description: "Create a canvas mutation plan for later review without applying it.",
|
|
5638
|
+
risk: "medium",
|
|
5639
|
+
requiredScopes: ["canvas.read", "canvas.propose"],
|
|
5640
|
+
inputSchema: {
|
|
5641
|
+
type: "object",
|
|
5642
|
+
properties: {
|
|
5643
|
+
canvasId: { type: "string", description: "Canvas node id." },
|
|
5644
|
+
baseRevision: { type: "string", description: "Revision the mutation was based on." },
|
|
5645
|
+
operations: { type: "array", description: "Canvas operations to validate." },
|
|
5646
|
+
intent: { type: "string", description: "User or agent intent for the mutation." },
|
|
5647
|
+
actor: { type: "string", description: "Agent or user creating the plan." }
|
|
5463
5648
|
},
|
|
5464
|
-
|
|
5465
|
-
|
|
5466
|
-
|
|
5467
|
-
|
|
5468
|
-
|
|
5469
|
-
|
|
5470
|
-
|
|
5471
|
-
|
|
5472
|
-
|
|
5473
|
-
|
|
5474
|
-
|
|
5475
|
-
|
|
5649
|
+
required: ["canvasId", "operations"]
|
|
5650
|
+
}
|
|
5651
|
+
},
|
|
5652
|
+
execute: async (host, args) => await host.planCanvasMutation(args)
|
|
5653
|
+
};
|
|
5654
|
+
var canvasToolEntries = [
|
|
5655
|
+
canvasListTool,
|
|
5656
|
+
canvasReadViewportTool,
|
|
5657
|
+
canvasReadSelectionTool,
|
|
5658
|
+
canvasSearchTool,
|
|
5659
|
+
canvasExportJsonCanvasTool,
|
|
5660
|
+
canvasPlanJsonCanvasImportTool,
|
|
5661
|
+
planCanvasMutationTool
|
|
5662
|
+
];
|
|
5663
|
+
|
|
5664
|
+
// src/ai-surface/tools/database.ts
|
|
5665
|
+
var databaseDescribeTool = {
|
|
5666
|
+
definition: {
|
|
5667
|
+
name: "xnet_database_describe",
|
|
5668
|
+
title: "Describe database",
|
|
5669
|
+
description: "Describe database schema, columns, views, row schema, and row counts.",
|
|
5670
|
+
risk: "low",
|
|
5671
|
+
requiredScopes: ["database.read"],
|
|
5672
|
+
inputSchema: {
|
|
5673
|
+
type: "object",
|
|
5674
|
+
properties: {
|
|
5675
|
+
databaseId: { type: "string", description: "Database node id." },
|
|
5676
|
+
includeSample: {
|
|
5677
|
+
type: "boolean",
|
|
5678
|
+
description: "Include a small descriptor-backed row sample."
|
|
5476
5679
|
}
|
|
5477
5680
|
},
|
|
5478
|
-
|
|
5479
|
-
|
|
5480
|
-
|
|
5481
|
-
|
|
5482
|
-
|
|
5483
|
-
|
|
5484
|
-
|
|
5681
|
+
required: ["databaseId"]
|
|
5682
|
+
}
|
|
5683
|
+
},
|
|
5684
|
+
execute: async (host, args) => await host.describeDatabase(readRequiredString(args, "databaseId"), {
|
|
5685
|
+
includeSample: readOptionalBoolean(args, "includeSample") ?? false
|
|
5686
|
+
})
|
|
5687
|
+
};
|
|
5688
|
+
var databaseQueryTool = {
|
|
5689
|
+
definition: {
|
|
5690
|
+
name: "xnet_database_query",
|
|
5691
|
+
title: "Query database rows",
|
|
5692
|
+
description: "Read a bounded page of database rows using NodeQueryDescriptor-compatible options.",
|
|
5693
|
+
risk: "low",
|
|
5694
|
+
requiredScopes: ["database.read", "database.query"],
|
|
5695
|
+
inputSchema: {
|
|
5696
|
+
type: "object",
|
|
5697
|
+
properties: {
|
|
5698
|
+
databaseId: { type: "string", description: "Database node id." },
|
|
5699
|
+
schemaId: { type: "string", description: "Optional row schema IRI." },
|
|
5700
|
+
descriptor: {
|
|
5485
5701
|
type: "object",
|
|
5486
|
-
|
|
5487
|
-
|
|
5488
|
-
|
|
5489
|
-
type: "boolean",
|
|
5490
|
-
description: "Must be true to perform the rollback."
|
|
5491
|
-
}
|
|
5492
|
-
},
|
|
5493
|
-
required: ["rollbackHandle", "confirmRollback"]
|
|
5494
|
-
}
|
|
5495
|
-
},
|
|
5496
|
-
{
|
|
5497
|
-
name: "xnet_database_describe",
|
|
5498
|
-
title: "Describe database",
|
|
5499
|
-
description: "Describe database schema, columns, views, row schema, and row counts.",
|
|
5500
|
-
risk: "low",
|
|
5501
|
-
requiredScopes: ["database.read"],
|
|
5502
|
-
inputSchema: {
|
|
5702
|
+
description: "Optional NodeQueryDescriptor-compatible query shape."
|
|
5703
|
+
},
|
|
5704
|
+
where: {
|
|
5503
5705
|
type: "object",
|
|
5504
|
-
|
|
5505
|
-
|
|
5506
|
-
|
|
5507
|
-
type: "boolean",
|
|
5508
|
-
description: "Include a small descriptor-backed row sample."
|
|
5509
|
-
}
|
|
5510
|
-
},
|
|
5511
|
-
required: ["databaseId"]
|
|
5512
|
-
}
|
|
5513
|
-
},
|
|
5514
|
-
{
|
|
5515
|
-
name: "xnet_database_query",
|
|
5516
|
-
title: "Query database rows",
|
|
5517
|
-
description: "Read a bounded page of database rows using NodeQueryDescriptor-compatible options.",
|
|
5518
|
-
risk: "low",
|
|
5519
|
-
requiredScopes: ["database.read", "database.query"],
|
|
5520
|
-
inputSchema: {
|
|
5706
|
+
description: "Optional exact property filters for row nodes."
|
|
5707
|
+
},
|
|
5708
|
+
search: {
|
|
5521
5709
|
type: "object",
|
|
5522
|
-
|
|
5523
|
-
|
|
5524
|
-
|
|
5525
|
-
descriptor: {
|
|
5526
|
-
type: "object",
|
|
5527
|
-
description: "Optional NodeQueryDescriptor-compatible query shape."
|
|
5528
|
-
},
|
|
5529
|
-
where: {
|
|
5530
|
-
type: "object",
|
|
5531
|
-
description: "Optional exact property filters for row nodes."
|
|
5532
|
-
},
|
|
5533
|
-
search: {
|
|
5534
|
-
type: "object",
|
|
5535
|
-
description: "Optional NodeQueryDescriptor search filter."
|
|
5536
|
-
},
|
|
5537
|
-
orderBy: {
|
|
5538
|
-
type: "object",
|
|
5539
|
-
description: "Optional NodeQueryDescriptor order map."
|
|
5540
|
-
},
|
|
5541
|
-
materializedView: {
|
|
5542
|
-
type: "object",
|
|
5543
|
-
description: "Optional materialized view query options."
|
|
5544
|
-
},
|
|
5545
|
-
count: { type: "string", description: "Page count mode: exact, estimate, or none." },
|
|
5546
|
-
limit: { type: "number", description: "Maximum row count." },
|
|
5547
|
-
offset: { type: "number", description: "Row offset." }
|
|
5548
|
-
},
|
|
5549
|
-
required: ["databaseId"]
|
|
5550
|
-
}
|
|
5551
|
-
},
|
|
5552
|
-
{
|
|
5553
|
-
name: "xnet_database_sample",
|
|
5554
|
-
title: "Sample database rows",
|
|
5555
|
-
description: "Return a small deterministic sample for schema and content inspection.",
|
|
5556
|
-
risk: "low",
|
|
5557
|
-
requiredScopes: ["database.read", "database.query"],
|
|
5558
|
-
inputSchema: {
|
|
5710
|
+
description: "Optional NodeQueryDescriptor search filter."
|
|
5711
|
+
},
|
|
5712
|
+
orderBy: {
|
|
5559
5713
|
type: "object",
|
|
5560
|
-
|
|
5561
|
-
|
|
5562
|
-
|
|
5563
|
-
sampleSize: { type: "number", description: "Sample row count." },
|
|
5564
|
-
descriptor: {
|
|
5565
|
-
type: "object",
|
|
5566
|
-
description: "Optional NodeQueryDescriptor-compatible query shape."
|
|
5567
|
-
}
|
|
5568
|
-
},
|
|
5569
|
-
required: ["databaseId"]
|
|
5570
|
-
}
|
|
5571
|
-
},
|
|
5572
|
-
{
|
|
5573
|
-
name: "xnet_database_explain_query",
|
|
5574
|
-
title: "Explain database query",
|
|
5575
|
-
description: "Explain descriptor, pagination, materialized view, and storage plan metadata.",
|
|
5576
|
-
risk: "low",
|
|
5577
|
-
requiredScopes: ["database.read", "database.query", "storage.diagnostics"],
|
|
5578
|
-
inputSchema: {
|
|
5714
|
+
description: "Optional NodeQueryDescriptor order map."
|
|
5715
|
+
},
|
|
5716
|
+
materializedView: {
|
|
5579
5717
|
type: "object",
|
|
5580
|
-
|
|
5581
|
-
|
|
5582
|
-
|
|
5583
|
-
|
|
5584
|
-
|
|
5585
|
-
description: "Optional NodeQueryDescriptor-compatible query shape."
|
|
5586
|
-
},
|
|
5587
|
-
limit: { type: "number", description: "Maximum row count for the dry-run query." },
|
|
5588
|
-
offset: { type: "number", description: "Row offset." }
|
|
5589
|
-
},
|
|
5590
|
-
required: ["databaseId"]
|
|
5591
|
-
}
|
|
5718
|
+
description: "Optional materialized view query options."
|
|
5719
|
+
},
|
|
5720
|
+
count: { type: "string", description: "Page count mode: exact, estimate, or none." },
|
|
5721
|
+
limit: { type: "number", description: "Maximum row count." },
|
|
5722
|
+
offset: { type: "number", description: "Row offset." }
|
|
5592
5723
|
},
|
|
5593
|
-
|
|
5594
|
-
|
|
5595
|
-
|
|
5596
|
-
|
|
5597
|
-
|
|
5598
|
-
|
|
5599
|
-
|
|
5724
|
+
required: ["databaseId"]
|
|
5725
|
+
}
|
|
5726
|
+
},
|
|
5727
|
+
execute: async (host, args) => await host.queryDatabase({
|
|
5728
|
+
databaseId: readRequiredString(args, "databaseId"),
|
|
5729
|
+
schemaId: readOptionalString(args, "schemaId"),
|
|
5730
|
+
descriptor: readOptionalRecord(args, "descriptor"),
|
|
5731
|
+
where: readOptionalRecord(args, "where"),
|
|
5732
|
+
search: args.search,
|
|
5733
|
+
orderBy: readOptionalRecord(args, "orderBy"),
|
|
5734
|
+
materializedView: args.materializedView,
|
|
5735
|
+
count: readOptionalString(args, "count"),
|
|
5736
|
+
limit: readOptionalNumber(args, "limit"),
|
|
5737
|
+
offset: readOptionalNumber(args, "offset")
|
|
5738
|
+
})
|
|
5739
|
+
};
|
|
5740
|
+
var databaseSampleTool = {
|
|
5741
|
+
definition: {
|
|
5742
|
+
name: "xnet_database_sample",
|
|
5743
|
+
title: "Sample database rows",
|
|
5744
|
+
description: "Return a small deterministic sample for schema and content inspection.",
|
|
5745
|
+
risk: "low",
|
|
5746
|
+
requiredScopes: ["database.read", "database.query"],
|
|
5747
|
+
inputSchema: {
|
|
5748
|
+
type: "object",
|
|
5749
|
+
properties: {
|
|
5750
|
+
databaseId: { type: "string", description: "Database node id." },
|
|
5751
|
+
schemaId: { type: "string", description: "Optional row schema IRI." },
|
|
5752
|
+
sampleSize: { type: "number", description: "Sample row count." },
|
|
5753
|
+
descriptor: {
|
|
5600
5754
|
type: "object",
|
|
5601
|
-
|
|
5602
|
-
databaseId: { type: "string", description: "Database node id." },
|
|
5603
|
-
baseRevision: { type: "string", description: "Revision the mutation was based on." },
|
|
5604
|
-
operations: { type: "array", description: "Database operations to validate." },
|
|
5605
|
-
intent: { type: "string", description: "User or agent intent for the mutation." },
|
|
5606
|
-
actor: { type: "string", description: "Agent or user creating the plan." }
|
|
5607
|
-
},
|
|
5608
|
-
required: ["databaseId", "operations"]
|
|
5755
|
+
description: "Optional NodeQueryDescriptor-compatible query shape."
|
|
5609
5756
|
}
|
|
5610
5757
|
},
|
|
5611
|
-
|
|
5612
|
-
|
|
5613
|
-
|
|
5614
|
-
|
|
5615
|
-
|
|
5616
|
-
|
|
5617
|
-
|
|
5758
|
+
required: ["databaseId"]
|
|
5759
|
+
}
|
|
5760
|
+
},
|
|
5761
|
+
execute: async (host, args) => await host.sampleDatabase({
|
|
5762
|
+
databaseId: readRequiredString(args, "databaseId"),
|
|
5763
|
+
schemaId: readOptionalString(args, "schemaId"),
|
|
5764
|
+
descriptor: readOptionalRecord(args, "descriptor"),
|
|
5765
|
+
sampleSize: readOptionalNumber(args, "sampleSize")
|
|
5766
|
+
})
|
|
5767
|
+
};
|
|
5768
|
+
var databaseExplainQueryTool = {
|
|
5769
|
+
definition: {
|
|
5770
|
+
name: "xnet_database_explain_query",
|
|
5771
|
+
title: "Explain database query",
|
|
5772
|
+
description: "Explain descriptor, pagination, materialized view, and storage plan metadata.",
|
|
5773
|
+
risk: "low",
|
|
5774
|
+
requiredScopes: ["database.read", "database.query", "storage.diagnostics"],
|
|
5775
|
+
inputSchema: {
|
|
5776
|
+
type: "object",
|
|
5777
|
+
properties: {
|
|
5778
|
+
databaseId: { type: "string", description: "Database node id." },
|
|
5779
|
+
schemaId: { type: "string", description: "Optional row schema IRI." },
|
|
5780
|
+
descriptor: {
|
|
5618
5781
|
type: "object",
|
|
5619
|
-
|
|
5620
|
-
|
|
5621
|
-
|
|
5622
|
-
|
|
5623
|
-
description: "Must be true to apply the database mutation plan."
|
|
5624
|
-
},
|
|
5625
|
-
allowStale: {
|
|
5626
|
-
type: "boolean",
|
|
5627
|
-
description: "Allow applying when the plan base revision differs from the live database node."
|
|
5628
|
-
}
|
|
5629
|
-
},
|
|
5630
|
-
required: ["plan", "confirmApply"]
|
|
5631
|
-
}
|
|
5782
|
+
description: "Optional NodeQueryDescriptor-compatible query shape."
|
|
5783
|
+
},
|
|
5784
|
+
limit: { type: "number", description: "Maximum row count for the dry-run query." },
|
|
5785
|
+
offset: { type: "number", description: "Row offset." }
|
|
5632
5786
|
},
|
|
5633
|
-
|
|
5634
|
-
|
|
5635
|
-
|
|
5636
|
-
|
|
5637
|
-
|
|
5638
|
-
|
|
5639
|
-
|
|
5640
|
-
|
|
5641
|
-
|
|
5642
|
-
|
|
5643
|
-
|
|
5644
|
-
|
|
5645
|
-
|
|
5787
|
+
required: ["databaseId"]
|
|
5788
|
+
}
|
|
5789
|
+
},
|
|
5790
|
+
execute: async (host, args) => await host.explainDatabaseQuery({
|
|
5791
|
+
databaseId: readRequiredString(args, "databaseId"),
|
|
5792
|
+
schemaId: readOptionalString(args, "schemaId"),
|
|
5793
|
+
descriptor: readOptionalRecord(args, "descriptor"),
|
|
5794
|
+
limit: readOptionalNumber(args, "limit"),
|
|
5795
|
+
offset: readOptionalNumber(args, "offset")
|
|
5796
|
+
})
|
|
5797
|
+
};
|
|
5798
|
+
var planDatabaseMutationTool = {
|
|
5799
|
+
definition: {
|
|
5800
|
+
name: "xnet_plan_database_mutation",
|
|
5801
|
+
title: "Plan database mutation",
|
|
5802
|
+
description: "Create a database mutation plan for later review without applying it.",
|
|
5803
|
+
risk: "medium",
|
|
5804
|
+
requiredScopes: ["database.read", "database.propose"],
|
|
5805
|
+
inputSchema: {
|
|
5806
|
+
type: "object",
|
|
5807
|
+
properties: {
|
|
5808
|
+
databaseId: { type: "string", description: "Database node id." },
|
|
5809
|
+
baseRevision: { type: "string", description: "Revision the mutation was based on." },
|
|
5810
|
+
operations: { type: "array", description: "Database operations to validate." },
|
|
5811
|
+
intent: { type: "string", description: "User or agent intent for the mutation." },
|
|
5812
|
+
actor: { type: "string", description: "Agent or user creating the plan." }
|
|
5646
5813
|
},
|
|
5647
|
-
|
|
5648
|
-
|
|
5649
|
-
|
|
5650
|
-
|
|
5651
|
-
|
|
5652
|
-
|
|
5653
|
-
|
|
5654
|
-
|
|
5655
|
-
|
|
5656
|
-
|
|
5657
|
-
|
|
5658
|
-
|
|
5659
|
-
|
|
5660
|
-
|
|
5661
|
-
|
|
5662
|
-
|
|
5663
|
-
|
|
5664
|
-
|
|
5665
|
-
|
|
5666
|
-
|
|
5667
|
-
|
|
5668
|
-
|
|
5669
|
-
|
|
5670
|
-
}
|
|
5671
|
-
},
|
|
5672
|
-
required: ["canvasId"]
|
|
5814
|
+
required: ["databaseId", "operations"]
|
|
5815
|
+
}
|
|
5816
|
+
},
|
|
5817
|
+
execute: async (host, args) => await host.planDatabaseMutation(args)
|
|
5818
|
+
};
|
|
5819
|
+
var applyDatabaseMutationTool = {
|
|
5820
|
+
definition: {
|
|
5821
|
+
name: "xnet_apply_database_mutation",
|
|
5822
|
+
title: "Apply database mutation plan",
|
|
5823
|
+
description: "Apply a validated database row/schema mutation plan with transactional row rollback and audit logging.",
|
|
5824
|
+
risk: "high",
|
|
5825
|
+
requiredScopes: ["database.read", "database.write.rows", "database.write.schema"],
|
|
5826
|
+
inputSchema: {
|
|
5827
|
+
type: "object",
|
|
5828
|
+
properties: {
|
|
5829
|
+
plan: { type: "object", description: "Validated database mutation plan." },
|
|
5830
|
+
confirmApply: {
|
|
5831
|
+
type: "boolean",
|
|
5832
|
+
description: "Must be true to apply the database mutation plan."
|
|
5833
|
+
},
|
|
5834
|
+
allowStale: {
|
|
5835
|
+
type: "boolean",
|
|
5836
|
+
description: "Allow applying when the plan base revision differs from the live database node."
|
|
5673
5837
|
}
|
|
5674
5838
|
},
|
|
5675
|
-
|
|
5676
|
-
|
|
5677
|
-
|
|
5678
|
-
|
|
5679
|
-
|
|
5680
|
-
|
|
5681
|
-
|
|
5682
|
-
|
|
5683
|
-
|
|
5684
|
-
|
|
5685
|
-
|
|
5686
|
-
|
|
5687
|
-
|
|
5688
|
-
|
|
5689
|
-
|
|
5690
|
-
|
|
5691
|
-
|
|
5692
|
-
|
|
5693
|
-
|
|
5694
|
-
|
|
5695
|
-
|
|
5839
|
+
required: ["plan", "confirmApply"]
|
|
5840
|
+
}
|
|
5841
|
+
},
|
|
5842
|
+
execute: async (host, args) => await host.applyDatabaseMutation(args)
|
|
5843
|
+
};
|
|
5844
|
+
var databaseToolEntries = [
|
|
5845
|
+
databaseDescribeTool,
|
|
5846
|
+
databaseQueryTool,
|
|
5847
|
+
databaseSampleTool,
|
|
5848
|
+
databaseExplainQueryTool,
|
|
5849
|
+
planDatabaseMutationTool,
|
|
5850
|
+
applyDatabaseMutationTool
|
|
5851
|
+
];
|
|
5852
|
+
|
|
5853
|
+
// src/ai-surface/tools/page-mutation.ts
|
|
5854
|
+
var readPageMarkdownTool = {
|
|
5855
|
+
definition: {
|
|
5856
|
+
name: "xnet_read_page_markdown",
|
|
5857
|
+
title: "Read page Markdown",
|
|
5858
|
+
description: "Read a page as Markdown with optional xNet frontmatter.",
|
|
5859
|
+
risk: "low",
|
|
5860
|
+
requiredScopes: ["page.read"],
|
|
5861
|
+
inputSchema: {
|
|
5862
|
+
type: "object",
|
|
5863
|
+
properties: {
|
|
5864
|
+
pageId: { type: "string", description: "Page node id." },
|
|
5865
|
+
includeFrontmatter: {
|
|
5866
|
+
type: "boolean",
|
|
5867
|
+
description: "Include xNet identity frontmatter. Defaults to true."
|
|
5696
5868
|
}
|
|
5697
5869
|
},
|
|
5698
|
-
|
|
5699
|
-
|
|
5700
|
-
|
|
5701
|
-
|
|
5702
|
-
|
|
5703
|
-
|
|
5704
|
-
|
|
5705
|
-
|
|
5706
|
-
|
|
5707
|
-
|
|
5708
|
-
|
|
5709
|
-
|
|
5710
|
-
|
|
5711
|
-
|
|
5712
|
-
|
|
5870
|
+
required: ["pageId"]
|
|
5871
|
+
}
|
|
5872
|
+
},
|
|
5873
|
+
execute: async (host, args) => {
|
|
5874
|
+
const content = await host.readPageMarkdown(
|
|
5875
|
+
readRequiredString(args, "pageId"),
|
|
5876
|
+
readOptionalBoolean(args, "includeFrontmatter") ?? true
|
|
5877
|
+
);
|
|
5878
|
+
return { markdown: content.text, mimeType: content.mimeType, uri: content.uri };
|
|
5879
|
+
}
|
|
5880
|
+
};
|
|
5881
|
+
var validatePageMarkdownTool = {
|
|
5882
|
+
definition: {
|
|
5883
|
+
name: "xnet_validate_page_markdown",
|
|
5884
|
+
title: "Validate page Markdown",
|
|
5885
|
+
description: "Validate xNet page frontmatter and supported xNet Markdown directives.",
|
|
5886
|
+
risk: "low",
|
|
5887
|
+
requiredScopes: ["page.read"],
|
|
5888
|
+
inputSchema: {
|
|
5889
|
+
type: "object",
|
|
5890
|
+
properties: {
|
|
5891
|
+
pageId: { type: "string", description: "Optional target page node id." },
|
|
5892
|
+
baseRevision: { type: "string", description: "Optional expected base revision." },
|
|
5893
|
+
markdown: { type: "string", description: "Markdown to validate." }
|
|
5713
5894
|
},
|
|
5714
|
-
|
|
5715
|
-
|
|
5716
|
-
|
|
5717
|
-
|
|
5718
|
-
|
|
5719
|
-
|
|
5720
|
-
|
|
5721
|
-
|
|
5722
|
-
|
|
5723
|
-
|
|
5724
|
-
|
|
5725
|
-
|
|
5726
|
-
|
|
5727
|
-
|
|
5728
|
-
|
|
5729
|
-
|
|
5730
|
-
|
|
5731
|
-
|
|
5732
|
-
|
|
5733
|
-
|
|
5734
|
-
|
|
5895
|
+
required: ["markdown"]
|
|
5896
|
+
}
|
|
5897
|
+
},
|
|
5898
|
+
execute: async (host, args) => {
|
|
5899
|
+
const pageId = readOptionalString(args, "pageId");
|
|
5900
|
+
const node = pageId ? await host.getNodeOrThrow(pageId) : null;
|
|
5901
|
+
return validateXNetPageMarkdown(readRequiredString(args, "markdown"), {
|
|
5902
|
+
pageId,
|
|
5903
|
+
schemaId: node?.schemaId,
|
|
5904
|
+
baseRevision: readOptionalString(args, "baseRevision")
|
|
5905
|
+
});
|
|
5906
|
+
}
|
|
5907
|
+
};
|
|
5908
|
+
var planPagePatchTool = {
|
|
5909
|
+
definition: {
|
|
5910
|
+
name: "xnet_plan_page_patch",
|
|
5911
|
+
title: "Plan page Markdown patch",
|
|
5912
|
+
description: "Validate an edited Markdown page and return a mutation plan without applying it.",
|
|
5913
|
+
risk: "medium",
|
|
5914
|
+
requiredScopes: ["page.read", "page.propose"],
|
|
5915
|
+
inputSchema: {
|
|
5916
|
+
type: "object",
|
|
5917
|
+
properties: {
|
|
5918
|
+
pageId: { type: "string", description: "Page node id." },
|
|
5919
|
+
baseRevision: { type: "string", description: "Revision the patch was based on." },
|
|
5920
|
+
markdown: { type: "string", description: "Proposed full Markdown replacement." },
|
|
5921
|
+
intent: { type: "string", description: "User or agent intent for the patch." },
|
|
5922
|
+
actor: { type: "string", description: "Agent or user creating the plan." }
|
|
5735
5923
|
},
|
|
5736
|
-
|
|
5737
|
-
|
|
5738
|
-
|
|
5739
|
-
|
|
5740
|
-
|
|
5741
|
-
|
|
5742
|
-
|
|
5743
|
-
|
|
5744
|
-
|
|
5745
|
-
|
|
5746
|
-
|
|
5747
|
-
|
|
5748
|
-
|
|
5749
|
-
|
|
5750
|
-
|
|
5751
|
-
|
|
5924
|
+
required: ["pageId", "markdown"]
|
|
5925
|
+
}
|
|
5926
|
+
},
|
|
5927
|
+
execute: async (host, args) => await host.planPagePatch(args)
|
|
5928
|
+
};
|
|
5929
|
+
var applyPageMarkdownTool = {
|
|
5930
|
+
definition: {
|
|
5931
|
+
name: "xnet_apply_page_markdown",
|
|
5932
|
+
title: "Apply page Markdown plan",
|
|
5933
|
+
description: "Apply a validated page Markdown mutation plan through the configured TipTap/Yjs document adapter, with a node-property fallback.",
|
|
5934
|
+
risk: "high",
|
|
5935
|
+
requiredScopes: ["page.read", "page.write"],
|
|
5936
|
+
inputSchema: {
|
|
5937
|
+
type: "object",
|
|
5938
|
+
properties: {
|
|
5939
|
+
plan: { type: "object", description: "Validated page Markdown mutation plan." },
|
|
5940
|
+
confirmApply: {
|
|
5941
|
+
type: "boolean",
|
|
5942
|
+
description: "Must be true to apply the page Markdown plan."
|
|
5943
|
+
},
|
|
5944
|
+
allowStale: {
|
|
5945
|
+
type: "boolean",
|
|
5946
|
+
description: "Allow applying when the plan base revision differs from the live node."
|
|
5752
5947
|
}
|
|
5753
5948
|
},
|
|
5754
|
-
|
|
5755
|
-
|
|
5756
|
-
|
|
5757
|
-
|
|
5758
|
-
|
|
5759
|
-
|
|
5760
|
-
|
|
5761
|
-
|
|
5762
|
-
|
|
5763
|
-
|
|
5764
|
-
|
|
5765
|
-
|
|
5766
|
-
|
|
5767
|
-
|
|
5768
|
-
|
|
5769
|
-
|
|
5949
|
+
required: ["plan", "confirmApply"]
|
|
5950
|
+
}
|
|
5951
|
+
},
|
|
5952
|
+
execute: async (host, args) => await host.applyPageMarkdown(args)
|
|
5953
|
+
};
|
|
5954
|
+
var rollbackPageMarkdownTool = {
|
|
5955
|
+
definition: {
|
|
5956
|
+
name: "xnet_rollback_page_markdown",
|
|
5957
|
+
title: "Rollback page Markdown apply",
|
|
5958
|
+
description: "Rollback a previously applied page Markdown plan by rollback handle.",
|
|
5959
|
+
risk: "high",
|
|
5960
|
+
requiredScopes: ["page.write"],
|
|
5961
|
+
inputSchema: {
|
|
5962
|
+
type: "object",
|
|
5963
|
+
properties: {
|
|
5964
|
+
rollbackHandle: { type: "string", description: "Rollback handle from apply result." },
|
|
5965
|
+
confirmRollback: {
|
|
5966
|
+
type: "boolean",
|
|
5967
|
+
description: "Must be true to perform the rollback."
|
|
5770
5968
|
}
|
|
5771
5969
|
},
|
|
5772
|
-
|
|
5773
|
-
|
|
5774
|
-
|
|
5775
|
-
|
|
5776
|
-
|
|
5777
|
-
|
|
5778
|
-
|
|
5779
|
-
|
|
5780
|
-
|
|
5781
|
-
|
|
5782
|
-
|
|
5783
|
-
|
|
5784
|
-
|
|
5970
|
+
required: ["rollbackHandle", "confirmRollback"]
|
|
5971
|
+
}
|
|
5972
|
+
},
|
|
5973
|
+
execute: async (host, args) => await host.rollbackPageMarkdown(args)
|
|
5974
|
+
};
|
|
5975
|
+
|
|
5976
|
+
// src/ai-surface/tools/search.ts
|
|
5977
|
+
var searchTool4 = {
|
|
5978
|
+
definition: {
|
|
5979
|
+
name: "xnet_search",
|
|
5980
|
+
title: "Search xNet workspace",
|
|
5981
|
+
description: "Search node titles and searchable properties with pagination and limits.",
|
|
5982
|
+
risk: "low",
|
|
5983
|
+
requiredScopes: ["workspace.search"],
|
|
5984
|
+
inputSchema: {
|
|
5985
|
+
type: "object",
|
|
5986
|
+
properties: {
|
|
5987
|
+
query: { type: "string", description: "Search text." },
|
|
5988
|
+
schemaId: { type: "string", description: "Optional schema IRI filter." },
|
|
5989
|
+
limit: { type: "number", description: "Maximum result count." },
|
|
5990
|
+
offset: { type: "number", description: "Result offset for pagination." }
|
|
5991
|
+
},
|
|
5992
|
+
required: ["query"]
|
|
5993
|
+
}
|
|
5994
|
+
},
|
|
5995
|
+
execute: async (host, args) => await host.search({
|
|
5996
|
+
query: readRequiredString(args, "query"),
|
|
5997
|
+
schemaId: readOptionalString(args, "schemaId") ?? readOptionalString(args, "schema"),
|
|
5998
|
+
limit: readOptionalNumber(args, "limit"),
|
|
5999
|
+
offset: readOptionalNumber(args, "offset")
|
|
6000
|
+
})
|
|
6001
|
+
};
|
|
6002
|
+
var graphExpandTool = {
|
|
6003
|
+
definition: {
|
|
6004
|
+
name: "xnet_graph_expand",
|
|
6005
|
+
title: "Expand a node along its relations",
|
|
6006
|
+
description: "Walk typed relation edges out from a node to its connected neighbors (bounded by hops and a result limit). Use for just-in-time expansion: fetch a specific node\u2019s connections only when you need them, instead of pulling the whole graph into context.",
|
|
6007
|
+
risk: "low",
|
|
6008
|
+
requiredScopes: ["workspace.read"],
|
|
6009
|
+
inputSchema: {
|
|
6010
|
+
type: "object",
|
|
6011
|
+
properties: {
|
|
6012
|
+
nodeId: { type: "string", description: "The node to expand from." },
|
|
6013
|
+
hops: {
|
|
6014
|
+
type: "number",
|
|
6015
|
+
description: "How many relation hops to walk (1\u20132, default 1)."
|
|
6016
|
+
},
|
|
6017
|
+
limit: { type: "number", description: "Maximum neighbors to return." }
|
|
6018
|
+
},
|
|
6019
|
+
required: ["nodeId"]
|
|
6020
|
+
}
|
|
6021
|
+
},
|
|
6022
|
+
execute: async (host, args) => await host.expandGraph({
|
|
6023
|
+
nodeId: readRequiredString(args, "nodeId"),
|
|
6024
|
+
hops: readOptionalNumber(args, "hops"),
|
|
6025
|
+
limit: readOptionalNumber(args, "limit")
|
|
6026
|
+
})
|
|
6027
|
+
};
|
|
6028
|
+
var createContextPackTool = {
|
|
6029
|
+
definition: {
|
|
6030
|
+
name: "xnet_create_context_pack",
|
|
6031
|
+
title: "Create context pack",
|
|
6032
|
+
description: "Create a bounded context pack from seeds and optional search results.",
|
|
6033
|
+
risk: "low",
|
|
6034
|
+
requiredScopes: ["workspace.read", "workspace.search"],
|
|
6035
|
+
inputSchema: {
|
|
6036
|
+
type: "object",
|
|
6037
|
+
properties: {
|
|
6038
|
+
query: { type: "string", description: "Optional search query." },
|
|
6039
|
+
seeds: {
|
|
6040
|
+
type: "array",
|
|
6041
|
+
description: "Seed resources such as pages, databases, canvases, or nodes.",
|
|
6042
|
+
items: {
|
|
6043
|
+
type: "object",
|
|
6044
|
+
properties: {
|
|
6045
|
+
kind: { type: "string", description: "Seed kind." },
|
|
6046
|
+
id: { type: "string", description: "Seed id." }
|
|
6047
|
+
}
|
|
6048
|
+
}
|
|
6049
|
+
},
|
|
6050
|
+
limit: { type: "number", description: "Maximum resources to include." }
|
|
5785
6051
|
}
|
|
6052
|
+
}
|
|
6053
|
+
},
|
|
6054
|
+
execute: async (host, args) => await host.createContextPack({
|
|
6055
|
+
query: readOptionalString(args, "query"),
|
|
6056
|
+
seeds: readContextSeeds(args.seeds),
|
|
6057
|
+
limit: readOptionalNumber(args, "limit")
|
|
6058
|
+
})
|
|
6059
|
+
};
|
|
6060
|
+
var createExternalContextResourceTool = {
|
|
6061
|
+
definition: {
|
|
6062
|
+
name: "xnet_create_external_context_resource",
|
|
6063
|
+
title: "Create untrusted external context resource",
|
|
6064
|
+
description: "Wrap externally fetched content as an untrusted context-pack resource with an explicit instruction boundary.",
|
|
6065
|
+
risk: "medium",
|
|
6066
|
+
requiredScopes: ["network.fetch"],
|
|
6067
|
+
inputSchema: {
|
|
6068
|
+
type: "object",
|
|
6069
|
+
properties: {
|
|
6070
|
+
url: { type: "string", description: "External source URL." },
|
|
6071
|
+
text: { type: "string", description: "Fetched external text content." },
|
|
6072
|
+
mimeType: { type: "string", description: "Source MIME type. Defaults to text/plain." }
|
|
6073
|
+
},
|
|
6074
|
+
required: ["url", "text"]
|
|
6075
|
+
}
|
|
6076
|
+
},
|
|
6077
|
+
execute: (host, args) => host.createExternalContextResource({
|
|
6078
|
+
url: readRequiredString(args, "url"),
|
|
6079
|
+
text: readRequiredString(args, "text"),
|
|
6080
|
+
mimeType: readOptionalString(args, "mimeType")
|
|
6081
|
+
})
|
|
6082
|
+
};
|
|
6083
|
+
var searchToolEntries = [
|
|
6084
|
+
searchTool4,
|
|
6085
|
+
graphExpandTool,
|
|
6086
|
+
createContextPackTool,
|
|
6087
|
+
createExternalContextResourceTool
|
|
6088
|
+
];
|
|
6089
|
+
|
|
6090
|
+
// src/ai-surface/tools/index.ts
|
|
6091
|
+
var BUILT_IN_TOOL_ENTRIES = [
|
|
6092
|
+
...searchToolEntries,
|
|
6093
|
+
readPageMarkdownTool,
|
|
6094
|
+
validatePageMarkdownTool,
|
|
6095
|
+
planPagePatchTool,
|
|
6096
|
+
applyPageMarkdownTool,
|
|
6097
|
+
getAuditLogTool,
|
|
6098
|
+
rollbackPageMarkdownTool,
|
|
6099
|
+
...databaseToolEntries,
|
|
6100
|
+
...canvasToolEntries,
|
|
6101
|
+
validateMutationPlanTool
|
|
6102
|
+
];
|
|
6103
|
+
var BUILT_IN_TOOLS_BY_NAME = new Map(
|
|
6104
|
+
BUILT_IN_TOOL_ENTRIES.map((entry) => [entry.definition.name, entry])
|
|
6105
|
+
);
|
|
6106
|
+
|
|
6107
|
+
// src/ai-surface/service.ts
|
|
6108
|
+
var DEFAULT_LIMITS = {
|
|
6109
|
+
maxListLimit: 100,
|
|
6110
|
+
maxSearchScan: 500,
|
|
6111
|
+
maxSearchResults: 20,
|
|
6112
|
+
maxContextResources: 12,
|
|
6113
|
+
maxCharactersPerResource: 12e3,
|
|
6114
|
+
maxJsonCharacters: 24e3,
|
|
6115
|
+
maxCanvasObjects: 200,
|
|
6116
|
+
maxDatabaseRows: 100
|
|
6117
|
+
};
|
|
6118
|
+
var BUILT_IN_RESOURCE_ROUTES = createBuiltInResourceRouter();
|
|
6119
|
+
var AiSurfaceService = class {
|
|
6120
|
+
constructor(config) {
|
|
6121
|
+
this.config = config;
|
|
6122
|
+
this.limits = { ...DEFAULT_LIMITS, ...config.limits };
|
|
6123
|
+
this.clock = config.clock ?? (() => /* @__PURE__ */ new Date());
|
|
6124
|
+
for (const tool of config.extraTools ?? []) {
|
|
6125
|
+
if (!this.extraTools.has(tool.name)) this.extraTools.set(tool.name, tool);
|
|
6126
|
+
}
|
|
6127
|
+
}
|
|
6128
|
+
limits;
|
|
6129
|
+
clock;
|
|
6130
|
+
sequence = 0;
|
|
6131
|
+
auditEvents = [];
|
|
6132
|
+
rollbackSnapshots = /* @__PURE__ */ new Map();
|
|
6133
|
+
/** Contributed tools by name (exploration 0196), de-duped at construction. */
|
|
6134
|
+
extraTools = /* @__PURE__ */ new Map();
|
|
6135
|
+
/**
|
|
6136
|
+
* The narrow surface handed to built-in tool handlers and resource routes
|
|
6137
|
+
* (`tools/`, `resources/`): closures over the private methods, so the class
|
|
6138
|
+
* stays the facade and its public type is unchanged. The closures are lazy —
|
|
6139
|
+
* nothing here runs until a tool call or resource read arrives.
|
|
6140
|
+
*/
|
|
6141
|
+
host = {
|
|
6142
|
+
search: (options) => this.search(options),
|
|
6143
|
+
expandGraph: (options) => this.expandGraph(options),
|
|
6144
|
+
createContextPack: (options) => this.createContextPack(options),
|
|
6145
|
+
createExternalContextResource: (options) => this.createExternalContextResource(options),
|
|
6146
|
+
getWorkspaceSummary: () => this.getWorkspaceSummary(),
|
|
6147
|
+
getRecentNodes: () => this.getRecentNodes(),
|
|
6148
|
+
listNodes: async () => {
|
|
6149
|
+
const nodes = await this.config.store.list({ limit: this.limits.maxListLimit });
|
|
6150
|
+
return { nodes, count: nodes.length, limit: this.limits.maxListLimit };
|
|
6151
|
+
},
|
|
6152
|
+
listSchemas: async () => ({ schemas: await this.getSchemaSummaries(true) }),
|
|
6153
|
+
getNodeOrThrow: (id) => this.getNodeOrThrow(id),
|
|
6154
|
+
getNodeProjection: (id) => this.getNodeProjection(id),
|
|
6155
|
+
readPageMarkdown: (pageId, includeFrontmatter, uri) => this.readPageMarkdown(pageId, includeFrontmatter, uri),
|
|
6156
|
+
readPageOutline: (pageId) => this.readPageOutline(pageId),
|
|
6157
|
+
planPagePatch: (args) => this.planPagePatch(args),
|
|
6158
|
+
applyPageMarkdown: (args) => this.applyPageMarkdown(args),
|
|
6159
|
+
rollbackPageMarkdown: (args) => this.rollbackPageMarkdown(args),
|
|
6160
|
+
getAuditLog: (options) => this.getAuditLog(options),
|
|
6161
|
+
describeDatabase: (databaseId, options) => this.describeDatabase(databaseId, options),
|
|
6162
|
+
readDatabaseViews: (databaseId) => this.readDatabaseViews(databaseId),
|
|
6163
|
+
queryDatabase: (options) => this.queryDatabase(options),
|
|
6164
|
+
sampleDatabase: (options) => this.sampleDatabase(options),
|
|
6165
|
+
explainDatabaseQuery: (options) => this.explainDatabaseQuery(options),
|
|
6166
|
+
planDatabaseMutation: (args) => this.planDatabaseMutation(args),
|
|
6167
|
+
applyDatabaseMutation: (args) => this.applyDatabaseMutation(args),
|
|
6168
|
+
listCanvases: (options) => this.listCanvases(options),
|
|
6169
|
+
readCanvasViewport: (options) => this.readCanvasViewport(options),
|
|
6170
|
+
readCanvasObjects: (canvasId) => this.readCanvasObjects(canvasId),
|
|
6171
|
+
readCanvasSelection: (options) => this.readCanvasSelection(options),
|
|
6172
|
+
searchCanvas: (options) => this.searchCanvas(options),
|
|
6173
|
+
exportCanvasJsonCanvas: (options) => this.exportCanvasJsonCanvas(options),
|
|
6174
|
+
readCanvasObject: (canvasId, objectId) => this.readCanvasObject(canvasId, objectId),
|
|
6175
|
+
planCanvasJsonCanvasImport: (args) => this.planCanvasJsonCanvasImport(args),
|
|
6176
|
+
planCanvasMutation: (args) => this.planCanvasMutation(args),
|
|
6177
|
+
jsonResource: (uri, value) => this.jsonResource(uri, value)
|
|
6178
|
+
};
|
|
6179
|
+
/** The contributed (non-built-in) tools, with built-in name collisions removed. */
|
|
6180
|
+
getExtraTools() {
|
|
6181
|
+
const builtIn = new Set(this.builtInTools().map((t) => t.name));
|
|
6182
|
+
return [...this.extraTools.values()].filter((t) => !builtIn.has(t.name));
|
|
6183
|
+
}
|
|
6184
|
+
getResources() {
|
|
6185
|
+
return [
|
|
6186
|
+
createResource(
|
|
6187
|
+
"xnet://workspace/summary",
|
|
6188
|
+
"Workspace Summary",
|
|
6189
|
+
"High-level schema counts, recent nodes, and AI surface capabilities.",
|
|
6190
|
+
"application/json",
|
|
6191
|
+
"low",
|
|
6192
|
+
["workspace.read"]
|
|
6193
|
+
),
|
|
6194
|
+
createResource(
|
|
6195
|
+
"xnet://workspace/recent",
|
|
6196
|
+
"Recent Workspace Nodes",
|
|
6197
|
+
"Recent nodes with ids, schemas, titles, and revisions.",
|
|
6198
|
+
"application/json",
|
|
6199
|
+
"low",
|
|
6200
|
+
["workspace.read"]
|
|
6201
|
+
),
|
|
6202
|
+
createResource(
|
|
6203
|
+
"xnet://nodes",
|
|
6204
|
+
"All Nodes",
|
|
6205
|
+
"Limited list of nodes in the local store.",
|
|
6206
|
+
"application/json",
|
|
6207
|
+
"low",
|
|
6208
|
+
["workspace.read"]
|
|
6209
|
+
),
|
|
6210
|
+
createResource(
|
|
6211
|
+
"xnet://schemas",
|
|
6212
|
+
"All Schemas",
|
|
6213
|
+
"List of available schemas and property metadata.",
|
|
6214
|
+
"application/json",
|
|
6215
|
+
"low",
|
|
6216
|
+
["workspace.read"]
|
|
6217
|
+
),
|
|
6218
|
+
createResource(
|
|
6219
|
+
"xnet://page/{pageId}.md",
|
|
6220
|
+
"Page Markdown",
|
|
6221
|
+
"Markdown projection for a page, including xNet frontmatter identity.",
|
|
6222
|
+
"text/markdown",
|
|
6223
|
+
"low",
|
|
6224
|
+
["page.read"],
|
|
6225
|
+
true
|
|
6226
|
+
),
|
|
6227
|
+
createResource(
|
|
6228
|
+
"xnet://page/{pageId}/outline",
|
|
6229
|
+
"Page Outline",
|
|
6230
|
+
"Page heading outline extracted from the Markdown projection.",
|
|
6231
|
+
"application/json",
|
|
6232
|
+
"low",
|
|
6233
|
+
["page.read"],
|
|
6234
|
+
true
|
|
6235
|
+
),
|
|
6236
|
+
createResource(
|
|
6237
|
+
"xnet://database/{databaseId}/schema",
|
|
6238
|
+
"Database Schema",
|
|
6239
|
+
"Database node metadata, declared properties, and known column descriptors.",
|
|
6240
|
+
"application/json",
|
|
6241
|
+
"low",
|
|
6242
|
+
["database.read"],
|
|
6243
|
+
true
|
|
6244
|
+
),
|
|
6245
|
+
createResource(
|
|
6246
|
+
"xnet://database/{databaseId}/views",
|
|
6247
|
+
"Database Views",
|
|
6248
|
+
"Known database view descriptors from the database node projection.",
|
|
6249
|
+
"application/json",
|
|
6250
|
+
"low",
|
|
6251
|
+
["database.read"],
|
|
6252
|
+
true
|
|
6253
|
+
),
|
|
6254
|
+
createResource(
|
|
6255
|
+
"xnet://database/{databaseId}/sample?limit=10",
|
|
6256
|
+
"Database Sample Rows",
|
|
6257
|
+
"Bounded sample of rows for a database using NodeQueryDescriptor semantics.",
|
|
6258
|
+
"application/json",
|
|
6259
|
+
"low",
|
|
6260
|
+
["database.read", "database.query"],
|
|
6261
|
+
true
|
|
6262
|
+
),
|
|
6263
|
+
createResource(
|
|
6264
|
+
"xnet://canvas/{canvasId}/viewport?x=0&y=0&w=1000&h=800",
|
|
6265
|
+
"Canvas Viewport",
|
|
6266
|
+
"Viewport-scoped canvas objects and edges.",
|
|
6267
|
+
"application/json",
|
|
6268
|
+
"low",
|
|
6269
|
+
["canvas.read"],
|
|
6270
|
+
true
|
|
6271
|
+
),
|
|
6272
|
+
createResource(
|
|
6273
|
+
"xnet://canvas/{canvasId}/objects",
|
|
6274
|
+
"Canvas Objects",
|
|
6275
|
+
"Bounded list of canvas objects and connectors.",
|
|
6276
|
+
"application/json",
|
|
6277
|
+
"low",
|
|
6278
|
+
["canvas.read"],
|
|
6279
|
+
true
|
|
6280
|
+
),
|
|
6281
|
+
createResource(
|
|
6282
|
+
"xnet://canvas/{canvasId}/selection?ids=object-1,object-2",
|
|
6283
|
+
"Canvas Selection",
|
|
6284
|
+
"Selection-scoped canvas objects, edges, and source previews.",
|
|
6285
|
+
"application/json",
|
|
6286
|
+
"low",
|
|
6287
|
+
["canvas.read"],
|
|
6288
|
+
true
|
|
6289
|
+
),
|
|
6290
|
+
createResource(
|
|
6291
|
+
"xnet://canvas/{canvasId}/json-canvas",
|
|
6292
|
+
"Canvas JSON Canvas",
|
|
6293
|
+
"JSON Canvas projection with xNet source metadata sidecars.",
|
|
6294
|
+
"application/json",
|
|
6295
|
+
"low",
|
|
6296
|
+
["canvas.read"],
|
|
6297
|
+
true
|
|
6298
|
+
)
|
|
5786
6299
|
];
|
|
5787
6300
|
}
|
|
6301
|
+
/** The full tool surface: built-in `xnet_*` tools plus contributed extras. */
|
|
6302
|
+
getTools() {
|
|
6303
|
+
const extras = this.getExtraTools().map(
|
|
6304
|
+
({ invoke: _invoke, ...def }) => def
|
|
6305
|
+
);
|
|
6306
|
+
return [...this.builtInTools(), ...extras];
|
|
6307
|
+
}
|
|
6308
|
+
builtInTools() {
|
|
6309
|
+
return BUILT_IN_TOOL_ENTRIES.map((entry) => entry.definition);
|
|
6310
|
+
}
|
|
6311
|
+
/**
|
|
6312
|
+
* Dispatch a tool call: the built-in registry first (a built-in `xnet_*`
|
|
6313
|
+
* name always wins), then contributed tools (plugin/connector `agentTools`,
|
|
6314
|
+
* exploration 0196).
|
|
6315
|
+
*/
|
|
5788
6316
|
async callTool(name, args = {}) {
|
|
5789
|
-
|
|
5790
|
-
|
|
5791
|
-
|
|
5792
|
-
|
|
5793
|
-
|
|
5794
|
-
limit: readOptionalNumber(args, "limit"),
|
|
5795
|
-
offset: readOptionalNumber(args, "offset")
|
|
5796
|
-
});
|
|
5797
|
-
case "xnet_graph_expand":
|
|
5798
|
-
return await this.expandGraph({
|
|
5799
|
-
nodeId: readRequiredString(args, "nodeId"),
|
|
5800
|
-
hops: readOptionalNumber(args, "hops"),
|
|
5801
|
-
limit: readOptionalNumber(args, "limit")
|
|
5802
|
-
});
|
|
5803
|
-
case "xnet_create_context_pack":
|
|
5804
|
-
return await this.createContextPack({
|
|
5805
|
-
query: readOptionalString(args, "query"),
|
|
5806
|
-
seeds: readContextSeeds(args.seeds),
|
|
5807
|
-
limit: readOptionalNumber(args, "limit")
|
|
5808
|
-
});
|
|
5809
|
-
case "xnet_create_external_context_resource":
|
|
5810
|
-
return this.createExternalContextResource({
|
|
5811
|
-
url: readRequiredString(args, "url"),
|
|
5812
|
-
text: readRequiredString(args, "text"),
|
|
5813
|
-
mimeType: readOptionalString(args, "mimeType")
|
|
5814
|
-
});
|
|
5815
|
-
case "xnet_read_page_markdown": {
|
|
5816
|
-
const content = await this.readPageMarkdown(
|
|
5817
|
-
readRequiredString(args, "pageId"),
|
|
5818
|
-
readOptionalBoolean(args, "includeFrontmatter") ?? true
|
|
5819
|
-
);
|
|
5820
|
-
return { markdown: content.text, mimeType: content.mimeType, uri: content.uri };
|
|
5821
|
-
}
|
|
5822
|
-
case "xnet_validate_page_markdown": {
|
|
5823
|
-
const pageId = readOptionalString(args, "pageId");
|
|
5824
|
-
const node = pageId ? await this.getNodeOrThrow(pageId) : null;
|
|
5825
|
-
return validateXNetPageMarkdown(readRequiredString(args, "markdown"), {
|
|
5826
|
-
pageId,
|
|
5827
|
-
schemaId: node?.schemaId,
|
|
5828
|
-
baseRevision: readOptionalString(args, "baseRevision")
|
|
5829
|
-
});
|
|
5830
|
-
}
|
|
5831
|
-
case "xnet_plan_page_patch":
|
|
5832
|
-
return await this.planPagePatch(args);
|
|
5833
|
-
case "xnet_apply_page_markdown":
|
|
5834
|
-
return await this.applyPageMarkdown(args);
|
|
5835
|
-
case "xnet_get_audit_log":
|
|
5836
|
-
return this.getAuditLog({
|
|
5837
|
-
planId: readOptionalString(args, "planId"),
|
|
5838
|
-
limit: readOptionalNumber(args, "limit")
|
|
5839
|
-
});
|
|
5840
|
-
case "xnet_rollback_page_markdown":
|
|
5841
|
-
return await this.rollbackPageMarkdown(args);
|
|
5842
|
-
case "xnet_database_describe":
|
|
5843
|
-
return await this.describeDatabase(readRequiredString(args, "databaseId"), {
|
|
5844
|
-
includeSample: readOptionalBoolean(args, "includeSample") ?? false
|
|
5845
|
-
});
|
|
5846
|
-
case "xnet_database_query":
|
|
5847
|
-
return await this.queryDatabase({
|
|
5848
|
-
databaseId: readRequiredString(args, "databaseId"),
|
|
5849
|
-
schemaId: readOptionalString(args, "schemaId"),
|
|
5850
|
-
descriptor: readOptionalRecord(args, "descriptor"),
|
|
5851
|
-
where: readOptionalRecord(args, "where"),
|
|
5852
|
-
search: args.search,
|
|
5853
|
-
orderBy: readOptionalRecord(args, "orderBy"),
|
|
5854
|
-
materializedView: args.materializedView,
|
|
5855
|
-
count: readOptionalString(args, "count"),
|
|
5856
|
-
limit: readOptionalNumber(args, "limit"),
|
|
5857
|
-
offset: readOptionalNumber(args, "offset")
|
|
5858
|
-
});
|
|
5859
|
-
case "xnet_database_sample":
|
|
5860
|
-
return await this.sampleDatabase({
|
|
5861
|
-
databaseId: readRequiredString(args, "databaseId"),
|
|
5862
|
-
schemaId: readOptionalString(args, "schemaId"),
|
|
5863
|
-
descriptor: readOptionalRecord(args, "descriptor"),
|
|
5864
|
-
sampleSize: readOptionalNumber(args, "sampleSize")
|
|
5865
|
-
});
|
|
5866
|
-
case "xnet_database_explain_query":
|
|
5867
|
-
return await this.explainDatabaseQuery({
|
|
5868
|
-
databaseId: readRequiredString(args, "databaseId"),
|
|
5869
|
-
schemaId: readOptionalString(args, "schemaId"),
|
|
5870
|
-
descriptor: readOptionalRecord(args, "descriptor"),
|
|
5871
|
-
limit: readOptionalNumber(args, "limit"),
|
|
5872
|
-
offset: readOptionalNumber(args, "offset")
|
|
5873
|
-
});
|
|
5874
|
-
case "xnet_plan_database_mutation":
|
|
5875
|
-
return await this.planDatabaseMutation(args);
|
|
5876
|
-
case "xnet_apply_database_mutation":
|
|
5877
|
-
return await this.applyDatabaseMutation(args);
|
|
5878
|
-
case "xnet_canvas_list":
|
|
5879
|
-
return await this.listCanvases({
|
|
5880
|
-
limit: readOptionalNumber(args, "limit"),
|
|
5881
|
-
offset: readOptionalNumber(args, "offset")
|
|
5882
|
-
});
|
|
5883
|
-
case "xnet_canvas_read_viewport":
|
|
5884
|
-
return await this.readCanvasViewport({
|
|
5885
|
-
canvasId: readRequiredString(args, "canvasId"),
|
|
5886
|
-
x: readOptionalNumber(args, "x"),
|
|
5887
|
-
y: readOptionalNumber(args, "y"),
|
|
5888
|
-
w: readOptionalNumber(args, "w"),
|
|
5889
|
-
h: readOptionalNumber(args, "h"),
|
|
5890
|
-
tileSize: readOptionalNumber(args, "tileSize"),
|
|
5891
|
-
tileIds: readStringArray(args.tileIds),
|
|
5892
|
-
includeSourcePreviews: readOptionalBoolean(args, "includeSourcePreviews") ?? false
|
|
5893
|
-
});
|
|
5894
|
-
case "xnet_canvas_read_selection":
|
|
5895
|
-
return await this.readCanvasSelection({
|
|
5896
|
-
canvasId: readRequiredString(args, "canvasId"),
|
|
5897
|
-
objectIds: readRequiredStringArray(args.objectIds, "objectIds"),
|
|
5898
|
-
includeSourcePreviews: readOptionalBoolean(args, "includeSourcePreviews") ?? false
|
|
5899
|
-
});
|
|
5900
|
-
case "xnet_canvas_search":
|
|
5901
|
-
return await this.searchCanvas({
|
|
5902
|
-
canvasId: readRequiredString(args, "canvasId"),
|
|
5903
|
-
query: readRequiredString(args, "query"),
|
|
5904
|
-
limit: readOptionalNumber(args, "limit")
|
|
5905
|
-
});
|
|
5906
|
-
case "xnet_canvas_export_json_canvas":
|
|
5907
|
-
return await this.exportCanvasJsonCanvas({
|
|
5908
|
-
canvasId: readRequiredString(args, "canvasId"),
|
|
5909
|
-
includeXNetMetadata: readOptionalBoolean(args, "includeXNetMetadata") ?? true,
|
|
5910
|
-
x: readOptionalNumber(args, "x"),
|
|
5911
|
-
y: readOptionalNumber(args, "y"),
|
|
5912
|
-
w: readOptionalNumber(args, "w"),
|
|
5913
|
-
h: readOptionalNumber(args, "h")
|
|
5914
|
-
});
|
|
5915
|
-
case "xnet_canvas_plan_json_canvas_import":
|
|
5916
|
-
return await this.planCanvasJsonCanvasImport(args);
|
|
5917
|
-
case "xnet_plan_canvas_mutation":
|
|
5918
|
-
return await this.planCanvasMutation(args);
|
|
5919
|
-
case "xnet_validate_mutation_plan": {
|
|
5920
|
-
const validation = validateAiMutationPlan(args.plan);
|
|
5921
|
-
return { validation };
|
|
5922
|
-
}
|
|
5923
|
-
default: {
|
|
5924
|
-
const extra = this.extraTools.get(name);
|
|
5925
|
-
if (extra) return await extra.invoke(args);
|
|
5926
|
-
throw new Error(`Unknown AI surface tool: ${name}`);
|
|
5927
|
-
}
|
|
5928
|
-
}
|
|
6317
|
+
const builtIn = BUILT_IN_TOOLS_BY_NAME.get(name);
|
|
6318
|
+
if (builtIn) return await builtIn.execute(this.host, args);
|
|
6319
|
+
const extra = this.extraTools.get(name);
|
|
6320
|
+
if (extra) return await extra.invoke(args);
|
|
6321
|
+
throw new Error(`Unknown AI surface tool: ${name}`);
|
|
5929
6322
|
}
|
|
5930
6323
|
async readResource(uri) {
|
|
5931
|
-
|
|
5932
|
-
if (uri === "xnet://nodes") {
|
|
5933
|
-
const nodes = await this.config.store.list({ limit: this.limits.maxListLimit });
|
|
5934
|
-
return this.jsonResource(uri, { nodes, count: nodes.length, limit: this.limits.maxListLimit });
|
|
5935
|
-
}
|
|
5936
|
-
if (uri === "xnet://schemas") {
|
|
5937
|
-
return this.jsonResource(uri, { schemas: await this.getSchemaSummaries(true) });
|
|
5938
|
-
}
|
|
5939
|
-
if (parsed.host === "workspace" && parsed.parts[0] === "summary") {
|
|
5940
|
-
return this.jsonResource(uri, await this.getWorkspaceSummary());
|
|
5941
|
-
}
|
|
5942
|
-
if (parsed.host === "workspace" && parsed.parts[0] === "recent") {
|
|
5943
|
-
return this.jsonResource(uri, await this.getRecentNodes());
|
|
5944
|
-
}
|
|
5945
|
-
if (parsed.host === "workspace" && parsed.parts[0] === "search") {
|
|
5946
|
-
return this.jsonResource(
|
|
5947
|
-
uri,
|
|
5948
|
-
await this.search({
|
|
5949
|
-
query: parsed.searchParams.get("q") ?? "",
|
|
5950
|
-
schemaId: parsed.searchParams.get("schema") ?? void 0,
|
|
5951
|
-
limit: readUrlNumber(parsed.searchParams, "limit"),
|
|
5952
|
-
offset: readUrlNumber(parsed.searchParams, "offset")
|
|
5953
|
-
})
|
|
5954
|
-
);
|
|
5955
|
-
}
|
|
5956
|
-
if (parsed.host === "node" && parsed.parts[0]) {
|
|
5957
|
-
return this.jsonResource(uri, await this.getNodeProjection(parsed.parts[0]));
|
|
5958
|
-
}
|
|
5959
|
-
if (parsed.host === "page" && parsed.parts[0]) {
|
|
5960
|
-
const pageId = parsed.parts[0].endsWith(".md") ? parsed.parts[0].slice(0, -".md".length) : parsed.parts[0];
|
|
5961
|
-
if (parsed.parts.length === 1 || parsed.parts[0].endsWith(".md")) {
|
|
5962
|
-
return await this.readPageMarkdown(pageId, true, uri);
|
|
5963
|
-
}
|
|
5964
|
-
if (parsed.parts[1] === "outline") {
|
|
5965
|
-
return this.jsonResource(uri, await this.readPageOutline(pageId));
|
|
5966
|
-
}
|
|
5967
|
-
if (parsed.parts[1] === "context-pack") {
|
|
5968
|
-
return this.jsonResource(
|
|
5969
|
-
uri,
|
|
5970
|
-
await this.createContextPack({ seeds: [{ kind: "page", id: pageId }] })
|
|
5971
|
-
);
|
|
5972
|
-
}
|
|
5973
|
-
}
|
|
5974
|
-
if (parsed.host === "database" && parsed.parts[0]) {
|
|
5975
|
-
const databaseId = parsed.parts[0];
|
|
5976
|
-
if (parsed.parts[1] === "schema") {
|
|
5977
|
-
return this.jsonResource(uri, await this.describeDatabase(databaseId));
|
|
5978
|
-
}
|
|
5979
|
-
if (parsed.parts[1] === "views") {
|
|
5980
|
-
return this.jsonResource(uri, await this.readDatabaseViews(databaseId));
|
|
5981
|
-
}
|
|
5982
|
-
if (parsed.parts[1] === "sample") {
|
|
5983
|
-
return this.jsonResource(
|
|
5984
|
-
uri,
|
|
5985
|
-
await this.sampleDatabase({
|
|
5986
|
-
databaseId,
|
|
5987
|
-
sampleSize: readUrlNumber(parsed.searchParams, "limit")
|
|
5988
|
-
})
|
|
5989
|
-
);
|
|
5990
|
-
}
|
|
5991
|
-
if (parsed.parts[1] === "query") {
|
|
5992
|
-
return this.jsonResource(
|
|
5993
|
-
uri,
|
|
5994
|
-
await this.queryDatabase({
|
|
5995
|
-
databaseId,
|
|
5996
|
-
schemaId: parsed.searchParams.get("schema") ?? void 0,
|
|
5997
|
-
search: parsed.searchParams.get("q") ?? void 0,
|
|
5998
|
-
materializedView: parsed.searchParams.get("view") ? { viewId: parsed.searchParams.get("view") ?? "" } : void 0,
|
|
5999
|
-
limit: readUrlNumber(parsed.searchParams, "limit"),
|
|
6000
|
-
offset: readUrlNumber(parsed.searchParams, "offset")
|
|
6001
|
-
})
|
|
6002
|
-
);
|
|
6003
|
-
}
|
|
6004
|
-
}
|
|
6005
|
-
if (parsed.host === "canvas" && parsed.parts[0]) {
|
|
6006
|
-
const canvasId = parsed.parts[0];
|
|
6007
|
-
if (parsed.parts[1] === "viewport") {
|
|
6008
|
-
return this.jsonResource(
|
|
6009
|
-
uri,
|
|
6010
|
-
await this.readCanvasViewport({
|
|
6011
|
-
canvasId,
|
|
6012
|
-
x: readUrlNumber(parsed.searchParams, "x"),
|
|
6013
|
-
y: readUrlNumber(parsed.searchParams, "y"),
|
|
6014
|
-
w: readUrlNumber(parsed.searchParams, "w"),
|
|
6015
|
-
h: readUrlNumber(parsed.searchParams, "h"),
|
|
6016
|
-
tileSize: readUrlNumber(parsed.searchParams, "tileSize"),
|
|
6017
|
-
tileIds: readCsvStringArray(parsed.searchParams.get("tileIds")),
|
|
6018
|
-
includeSourcePreviews: parsed.searchParams.get("includeSourcePreviews") === "true"
|
|
6019
|
-
})
|
|
6020
|
-
);
|
|
6021
|
-
}
|
|
6022
|
-
if (parsed.parts[1] === "objects") {
|
|
6023
|
-
return this.jsonResource(uri, await this.readCanvasObjects(canvasId));
|
|
6024
|
-
}
|
|
6025
|
-
if (parsed.parts[1] === "selection") {
|
|
6026
|
-
return this.jsonResource(
|
|
6027
|
-
uri,
|
|
6028
|
-
await this.readCanvasSelection({
|
|
6029
|
-
canvasId,
|
|
6030
|
-
objectIds: readCsvStringArray(parsed.searchParams.get("ids")),
|
|
6031
|
-
includeSourcePreviews: parsed.searchParams.get("includeSourcePreviews") !== "false"
|
|
6032
|
-
})
|
|
6033
|
-
);
|
|
6034
|
-
}
|
|
6035
|
-
if (parsed.parts[1] === "json-canvas") {
|
|
6036
|
-
return this.jsonResource(
|
|
6037
|
-
uri,
|
|
6038
|
-
await this.exportCanvasJsonCanvas({
|
|
6039
|
-
canvasId,
|
|
6040
|
-
includeXNetMetadata: parsed.searchParams.get("includeXNetMetadata") !== "false"
|
|
6041
|
-
})
|
|
6042
|
-
);
|
|
6043
|
-
}
|
|
6044
|
-
if (parsed.parts[1] === "object" && parsed.parts[2]) {
|
|
6045
|
-
return this.jsonResource(uri, await this.readCanvasObject(canvasId, parsed.parts[2]));
|
|
6046
|
-
}
|
|
6047
|
-
}
|
|
6048
|
-
throw new Error(`Resource not found: ${uri}`);
|
|
6324
|
+
return await BUILT_IN_RESOURCE_ROUTES.resolve(this.host, uri);
|
|
6049
6325
|
}
|
|
6050
6326
|
toJsonText(value, format = "concise") {
|
|
6051
6327
|
return this.stringifyJson(value, format);
|
|
@@ -6142,7 +6418,7 @@ var AiSurfaceService = class {
|
|
|
6142
6418
|
const results = Array.isArray(search.results) ? search.results : [];
|
|
6143
6419
|
const ids = [];
|
|
6144
6420
|
for (const result of results) {
|
|
6145
|
-
if (
|
|
6421
|
+
if (isRecord3(result) && typeof result.id === "string") ids.push(result.id);
|
|
6146
6422
|
}
|
|
6147
6423
|
return ids;
|
|
6148
6424
|
}
|
|
@@ -6784,8 +7060,8 @@ var AiSurfaceService = class {
|
|
|
6784
7060
|
h: options.h,
|
|
6785
7061
|
includeSourcePreviews: false
|
|
6786
7062
|
});
|
|
6787
|
-
const objects = Array.isArray(viewport.objects) ? viewport.objects.filter(
|
|
6788
|
-
const edges = Array.isArray(viewport.edges) ? viewport.edges.filter(
|
|
7063
|
+
const objects = Array.isArray(viewport.objects) ? viewport.objects.filter(isRecord3) : [];
|
|
7064
|
+
const edges = Array.isArray(viewport.edges) ? viewport.edges.filter(isRecord3) : [];
|
|
6789
7065
|
return {
|
|
6790
7066
|
canvasId: options.canvasId,
|
|
6791
7067
|
revision: viewport.revision,
|
|
@@ -6827,7 +7103,7 @@ var AiSurfaceService = class {
|
|
|
6827
7103
|
});
|
|
6828
7104
|
const objects = Array.isArray(viewport.objects) ? viewport.objects : [];
|
|
6829
7105
|
const object = objects.find(
|
|
6830
|
-
(candidate) =>
|
|
7106
|
+
(candidate) => isRecord3(candidate) && readRecordString(candidate, "id") === objectId
|
|
6831
7107
|
);
|
|
6832
7108
|
if (!object) throw new Error(`Canvas object not found: ${objectId}`);
|
|
6833
7109
|
return {
|
|
@@ -7303,7 +7579,7 @@ function invalidPageApplyResult(plan, validation) {
|
|
|
7303
7579
|
return {
|
|
7304
7580
|
applied: false,
|
|
7305
7581
|
pageId: "unknown",
|
|
7306
|
-
planId:
|
|
7582
|
+
planId: isRecord3(plan) && typeof plan.id === "string" ? plan.id : "unknown",
|
|
7307
7583
|
mode: "node-property",
|
|
7308
7584
|
baseRevision: "unknown",
|
|
7309
7585
|
liveRevision: "unknown",
|
|
@@ -7326,7 +7602,7 @@ function rejectedPageApplyResult(input) {
|
|
|
7326
7602
|
};
|
|
7327
7603
|
}
|
|
7328
7604
|
function isMutationPlan(value) {
|
|
7329
|
-
return
|
|
7605
|
+
return isRecord3(value) && typeof value.id === "string" && typeof value.actor === "string" && typeof value.intent === "string" && Array.isArray(value.changes) && isRecord3(value.validation);
|
|
7330
7606
|
}
|
|
7331
7607
|
function createResource(uri, name, description, mimeType, risk, requiredScopes, dynamic = false) {
|
|
7332
7608
|
return {
|
|
@@ -7339,22 +7615,6 @@ function createResource(uri, name, description, mimeType, risk, requiredScopes,
|
|
|
7339
7615
|
dynamic
|
|
7340
7616
|
};
|
|
7341
7617
|
}
|
|
7342
|
-
function parseXNetUri(uri) {
|
|
7343
|
-
let parsed;
|
|
7344
|
-
try {
|
|
7345
|
-
parsed = new URL(uri);
|
|
7346
|
-
} catch {
|
|
7347
|
-
throw new Error(`Invalid xNet resource URI: ${uri}`);
|
|
7348
|
-
}
|
|
7349
|
-
if (parsed.protocol !== "xnet:") {
|
|
7350
|
-
throw new Error(`Invalid xNet resource URI: ${uri}`);
|
|
7351
|
-
}
|
|
7352
|
-
return {
|
|
7353
|
-
host: parsed.hostname,
|
|
7354
|
-
parts: parsed.pathname.split("/").filter(Boolean).map((part) => decodeURIComponent(part)),
|
|
7355
|
-
searchParams: parsed.searchParams
|
|
7356
|
-
};
|
|
7357
|
-
}
|
|
7358
7618
|
function renderPageMarkdown(node, includeFrontmatter, exportedAt) {
|
|
7359
7619
|
const title = readStringProperty(node, "title") ?? "Untitled Page";
|
|
7360
7620
|
const body = readMarkdownBody(node);
|
|
@@ -7381,7 +7641,7 @@ function readMarkdownBody(node) {
|
|
|
7381
7641
|
const value = readStringProperty(node, "markdown") ?? readStringProperty(node, "content") ?? readStringProperty(node, "body") ?? readStringProperty(node, "text") ?? readStringProperty(node, "description");
|
|
7382
7642
|
if (value) return value;
|
|
7383
7643
|
const richContent = node.properties.content;
|
|
7384
|
-
if (
|
|
7644
|
+
if (isRecord3(richContent)) {
|
|
7385
7645
|
return `\`\`\`json
|
|
7386
7646
|
${JSON.stringify(richContent, null, 2)}
|
|
7387
7647
|
\`\`\``;
|
|
@@ -7442,7 +7702,7 @@ function relationFieldNames(schema) {
|
|
|
7442
7702
|
if (!schema) return [];
|
|
7443
7703
|
const fields = [];
|
|
7444
7704
|
for (const [name, definition] of Object.entries(schema.properties)) {
|
|
7445
|
-
if (
|
|
7705
|
+
if (isRecord3(definition) && definition.type === "relation") fields.push(name);
|
|
7446
7706
|
}
|
|
7447
7707
|
return fields;
|
|
7448
7708
|
}
|
|
@@ -7472,7 +7732,7 @@ function readArrayProperty(node, property) {
|
|
|
7472
7732
|
}
|
|
7473
7733
|
function readNestedArrayProperty(node, objectProperty, arrayProperty) {
|
|
7474
7734
|
const value = node.properties[objectProperty];
|
|
7475
|
-
return
|
|
7735
|
+
return isRecord3(value) && Array.isArray(value[arrayProperty]) ? value[arrayProperty] : void 0;
|
|
7476
7736
|
}
|
|
7477
7737
|
function belongsToDatabase(node, databaseId) {
|
|
7478
7738
|
return readStringProperty(node, "databaseId") === databaseId || readStringProperty(node, "database") === databaseId || readStringProperty(node, "parentDatabaseId") === databaseId;
|
|
@@ -7531,7 +7791,7 @@ function normalizeQuerySearch(value) {
|
|
|
7531
7791
|
const text3 = value.trim();
|
|
7532
7792
|
return text3 ? { text: text3 } : void 0;
|
|
7533
7793
|
}
|
|
7534
|
-
if (!
|
|
7794
|
+
if (!isRecord3(value) || typeof value.text !== "string" || !value.text.trim()) {
|
|
7535
7795
|
return void 0;
|
|
7536
7796
|
}
|
|
7537
7797
|
const fields = Array.isArray(value.fields) ? value.fields.filter(
|
|
@@ -7547,7 +7807,7 @@ function normalizeQueryMaterializedView(value) {
|
|
|
7547
7807
|
const viewId2 = value.trim();
|
|
7548
7808
|
return viewId2 ? { viewId: viewId2 } : void 0;
|
|
7549
7809
|
}
|
|
7550
|
-
if (!
|
|
7810
|
+
if (!isRecord3(value)) return void 0;
|
|
7551
7811
|
const viewId = readRecordString(value, "viewId");
|
|
7552
7812
|
if (!viewId) return void 0;
|
|
7553
7813
|
const maxAgeMs = readRecordNumber(value, "maxAgeMs");
|
|
@@ -7820,7 +8080,7 @@ function invalidDatabaseApplyResult(plan, validation) {
|
|
|
7820
8080
|
return {
|
|
7821
8081
|
applied: false,
|
|
7822
8082
|
databaseId: "unknown",
|
|
7823
|
-
planId:
|
|
8083
|
+
planId: isRecord3(plan) && typeof plan.id === "string" ? plan.id : "unknown",
|
|
7824
8084
|
baseRevision: "unknown",
|
|
7825
8085
|
liveRevision: "unknown",
|
|
7826
8086
|
appliedChangeIds: [],
|
|
@@ -7838,7 +8098,7 @@ function readTransactionOperations(operation) {
|
|
|
7838
8098
|
);
|
|
7839
8099
|
}
|
|
7840
8100
|
function readTransactionOperation(value, path) {
|
|
7841
|
-
if (!
|
|
8101
|
+
if (!isRecord3(value)) throw new Error(`${path} must be an object`);
|
|
7842
8102
|
if (value.type === "create") {
|
|
7843
8103
|
const options = readRecord(value, "options");
|
|
7844
8104
|
const schemaId = options ? readRecordString(options, "schemaId") : void 0;
|
|
@@ -7931,15 +8191,15 @@ function databaseEntityMatchesId(entity, id) {
|
|
|
7931
8191
|
}
|
|
7932
8192
|
function readRecordArrayProperty(record, key) {
|
|
7933
8193
|
const value = record[key];
|
|
7934
|
-
return Array.isArray(value) ? value.filter(
|
|
8194
|
+
return Array.isArray(value) ? value.filter(isRecord3) : [];
|
|
7935
8195
|
}
|
|
7936
8196
|
function isCanvasNode(node) {
|
|
7937
8197
|
return node.schemaId.includes("/Canvas") || node.schemaId.includes("Canvas@") || Array.isArray(node.properties.objects) || Array.isArray(node.properties.nodes);
|
|
7938
8198
|
}
|
|
7939
8199
|
function readCanvasScene(canvas) {
|
|
7940
8200
|
return {
|
|
7941
|
-
objects: (readArrayProperty(canvas, "objects") ?? readArrayProperty(canvas, "nodes") ?? []).filter(
|
|
7942
|
-
edges: (readArrayProperty(canvas, "edges") ?? readArrayProperty(canvas, "connectors") ?? []).filter(
|
|
8201
|
+
objects: (readArrayProperty(canvas, "objects") ?? readArrayProperty(canvas, "nodes") ?? []).filter(isRecord3).map(normalizeCanvasObject),
|
|
8202
|
+
edges: (readArrayProperty(canvas, "edges") ?? readArrayProperty(canvas, "connectors") ?? []).filter(isRecord3).map(normalizeCanvasEdge)
|
|
7943
8203
|
};
|
|
7944
8204
|
}
|
|
7945
8205
|
function normalizeCanvasObject(object) {
|
|
@@ -8082,8 +8342,8 @@ function canvasObjectFile(object) {
|
|
|
8082
8342
|
return readRecordString(object, "file") ?? readRecordString(object, "filePath") ?? readRecordString(properties ?? {}, "file") ?? readRecordString(properties ?? {}, "filePath");
|
|
8083
8343
|
}
|
|
8084
8344
|
function jsonCanvasDocumentToCanvasOperations(document) {
|
|
8085
|
-
const nodes = Array.isArray(document.nodes) ? document.nodes.filter(
|
|
8086
|
-
const edges = Array.isArray(document.edges) ? document.edges.filter(
|
|
8345
|
+
const nodes = Array.isArray(document.nodes) ? document.nodes.filter(isRecord3) : [];
|
|
8346
|
+
const edges = Array.isArray(document.edges) ? document.edges.filter(isRecord3) : [];
|
|
8087
8347
|
const nodeIds = new Set(nodes.map((node) => readRecordString(node, "id")).filter(Boolean));
|
|
8088
8348
|
const warnings = edges.flatMap((edge) => {
|
|
8089
8349
|
const fromNode = readRecordString(edge, "fromNode");
|
|
@@ -8315,10 +8575,10 @@ function readOperations(value) {
|
|
|
8315
8575
|
throw new Error("operations must contain at least one operation");
|
|
8316
8576
|
}
|
|
8317
8577
|
return value.map((operation, index) => {
|
|
8318
|
-
if (!
|
|
8578
|
+
if (!isRecord3(operation) || typeof operation.op !== "string") {
|
|
8319
8579
|
throw new Error(`operations[${index}].op must be a string`);
|
|
8320
8580
|
}
|
|
8321
|
-
const args =
|
|
8581
|
+
const args = isRecord3(operation.args) ? operation.args : {};
|
|
8322
8582
|
return createAiOperation(
|
|
8323
8583
|
operation.op,
|
|
8324
8584
|
args,
|
|
@@ -8326,15 +8586,6 @@ function readOperations(value) {
|
|
|
8326
8586
|
);
|
|
8327
8587
|
});
|
|
8328
8588
|
}
|
|
8329
|
-
function readContextSeeds(value) {
|
|
8330
|
-
if (!Array.isArray(value)) return [];
|
|
8331
|
-
return value.map((seed) => {
|
|
8332
|
-
if (!isRecord4(seed)) return null;
|
|
8333
|
-
const kind = typeof seed.kind === "string" ? seed.kind : null;
|
|
8334
|
-
const id = typeof seed.id === "string" ? seed.id : null;
|
|
8335
|
-
return kind && id ? { kind, id } : null;
|
|
8336
|
-
}).filter((seed) => seed !== null);
|
|
8337
|
-
}
|
|
8338
8589
|
function uriForSeed(seed) {
|
|
8339
8590
|
switch (seed.kind) {
|
|
8340
8591
|
case "node":
|
|
@@ -8394,75 +8645,6 @@ function stringifyTruncatedJson(text3, maxCharacters) {
|
|
|
8394
8645
|
function quoteYaml(value) {
|
|
8395
8646
|
return JSON.stringify(value);
|
|
8396
8647
|
}
|
|
8397
|
-
function readRequiredString(record, key) {
|
|
8398
|
-
const value = record[key];
|
|
8399
|
-
if (typeof value !== "string" || !value.trim()) {
|
|
8400
|
-
throw new Error(`${key} must be a non-empty string`);
|
|
8401
|
-
}
|
|
8402
|
-
return value;
|
|
8403
|
-
}
|
|
8404
|
-
function readRequiredRecord(record, key) {
|
|
8405
|
-
const value = record[key];
|
|
8406
|
-
if (!isRecord4(value)) {
|
|
8407
|
-
throw new Error(`${key} must be an object`);
|
|
8408
|
-
}
|
|
8409
|
-
return value;
|
|
8410
|
-
}
|
|
8411
|
-
function readRequiredStringArray(value, key) {
|
|
8412
|
-
const result = readStringArray(value);
|
|
8413
|
-
if (result.length === 0) {
|
|
8414
|
-
throw new Error(`${key} must contain at least one string`);
|
|
8415
|
-
}
|
|
8416
|
-
return result;
|
|
8417
|
-
}
|
|
8418
|
-
function readStringArray(value) {
|
|
8419
|
-
if (!Array.isArray(value)) return [];
|
|
8420
|
-
return value.filter((item) => typeof item === "string" && item.trim() !== "");
|
|
8421
|
-
}
|
|
8422
|
-
function readCsvStringArray(value) {
|
|
8423
|
-
if (!value) return [];
|
|
8424
|
-
return value.split(",").map((item) => item.trim()).filter(Boolean);
|
|
8425
|
-
}
|
|
8426
|
-
function readOptionalString(record, key) {
|
|
8427
|
-
const value = record[key];
|
|
8428
|
-
return typeof value === "string" && value.trim() ? value : void 0;
|
|
8429
|
-
}
|
|
8430
|
-
function readOptionalRecord(record, key) {
|
|
8431
|
-
return readRecord(record, key);
|
|
8432
|
-
}
|
|
8433
|
-
function readOptionalNumber(record, key) {
|
|
8434
|
-
const value = record[key];
|
|
8435
|
-
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
8436
|
-
}
|
|
8437
|
-
function readOptionalBoolean(record, key) {
|
|
8438
|
-
const value = record[key];
|
|
8439
|
-
return typeof value === "boolean" ? value : void 0;
|
|
8440
|
-
}
|
|
8441
|
-
function readUrlNumber(params, key) {
|
|
8442
|
-
const value = params.get(key);
|
|
8443
|
-
if (value === null) return void 0;
|
|
8444
|
-
const parsed = Number(value);
|
|
8445
|
-
return Number.isFinite(parsed) ? parsed : void 0;
|
|
8446
|
-
}
|
|
8447
|
-
function readRecordString(record, key) {
|
|
8448
|
-
const value = record[key];
|
|
8449
|
-
return typeof value === "string" && value.trim() ? value : void 0;
|
|
8450
|
-
}
|
|
8451
|
-
function readRecord(record, key) {
|
|
8452
|
-
const value = record[key];
|
|
8453
|
-
return isRecord4(value) ? value : void 0;
|
|
8454
|
-
}
|
|
8455
|
-
function readRecordNumber(record, key) {
|
|
8456
|
-
const value = record[key];
|
|
8457
|
-
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
8458
|
-
}
|
|
8459
|
-
function readRecordBoolean(record, key) {
|
|
8460
|
-
const value = record[key];
|
|
8461
|
-
return typeof value === "boolean" ? value : void 0;
|
|
8462
|
-
}
|
|
8463
|
-
function isRecord4(value) {
|
|
8464
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8465
|
-
}
|
|
8466
8648
|
|
|
8467
8649
|
// src/sandbox/ast-validator.ts
|
|
8468
8650
|
import * as acorn from "acorn";
|