@xnetjs/plugins 0.2.0 → 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 +12 -0
- package/dist/index.js +1146 -966
- package/dist/services/node.d.ts +12 -0
- package/dist/services/node.js +1146 -966
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -4876,6 +4876,86 @@ function hasWriteScope(plan) {
|
|
|
4876
4876
|
);
|
|
4877
4877
|
}
|
|
4878
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
|
+
|
|
4879
4959
|
// src/ai-surface/page-markdown.ts
|
|
4880
4960
|
var XNET_MARKDOWN_DIRECTIVE_SPECS = [
|
|
4881
4961
|
{
|
|
@@ -5111,7 +5191,7 @@ function findJsonPayloadEnd(src, startIndex) {
|
|
|
5111
5191
|
function parseJsonObject(rawPayload, label, errors) {
|
|
5112
5192
|
try {
|
|
5113
5193
|
const parsed = JSON.parse(rawPayload);
|
|
5114
|
-
if (
|
|
5194
|
+
if (isRecord4(parsed)) return parsed;
|
|
5115
5195
|
errors.push(`${label} payload must be a JSON object`);
|
|
5116
5196
|
return null;
|
|
5117
5197
|
} catch {
|
|
@@ -5145,7 +5225,7 @@ function unquoteYamlScalar(value) {
|
|
|
5145
5225
|
return trimmed.slice(1, -1);
|
|
5146
5226
|
}
|
|
5147
5227
|
}
|
|
5148
|
-
function
|
|
5228
|
+
function isRecord4(value) {
|
|
5149
5229
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5150
5230
|
}
|
|
5151
5231
|
function markdownDiffPrefix(kind) {
|
|
@@ -5154,900 +5234,1094 @@ function markdownDiffPrefix(kind) {
|
|
|
5154
5234
|
return " ";
|
|
5155
5235
|
}
|
|
5156
5236
|
|
|
5157
|
-
// src/ai-surface/
|
|
5158
|
-
var
|
|
5159
|
-
|
|
5160
|
-
|
|
5161
|
-
|
|
5162
|
-
|
|
5163
|
-
|
|
5164
|
-
|
|
5165
|
-
|
|
5166
|
-
|
|
5167
|
-
|
|
5168
|
-
|
|
5169
|
-
|
|
5170
|
-
|
|
5171
|
-
|
|
5172
|
-
|
|
5173
|
-
|
|
5174
|
-
|
|
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}`);
|
|
5175
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}`);
|
|
5176
5266
|
}
|
|
5177
|
-
|
|
5178
|
-
|
|
5179
|
-
sequence = 0;
|
|
5180
|
-
auditEvents = [];
|
|
5181
|
-
rollbackSnapshots = /* @__PURE__ */ new Map();
|
|
5182
|
-
/** Contributed tools by name (exploration 0196), de-duped at construction. */
|
|
5183
|
-
extraTools = /* @__PURE__ */ new Map();
|
|
5184
|
-
/** The contributed (non-built-in) tools, with built-in name collisions removed. */
|
|
5185
|
-
getExtraTools() {
|
|
5186
|
-
const builtIn = new Set(this.builtInTools().map((t) => t.name));
|
|
5187
|
-
return [...this.extraTools.values()].filter((t) => !builtIn.has(t.name));
|
|
5267
|
+
if (parsed.protocol !== "xnet:") {
|
|
5268
|
+
throw new Error(`Invalid xNet resource URI: ${uri}`);
|
|
5188
5269
|
}
|
|
5189
|
-
|
|
5190
|
-
|
|
5191
|
-
|
|
5192
|
-
|
|
5193
|
-
|
|
5194
|
-
|
|
5195
|
-
|
|
5196
|
-
|
|
5197
|
-
|
|
5198
|
-
),
|
|
5199
|
-
createResource(
|
|
5200
|
-
"xnet://workspace/recent",
|
|
5201
|
-
"Recent Workspace Nodes",
|
|
5202
|
-
"Recent nodes with ids, schemas, titles, and revisions.",
|
|
5203
|
-
"application/json",
|
|
5204
|
-
"low",
|
|
5205
|
-
["workspace.read"]
|
|
5206
|
-
),
|
|
5207
|
-
createResource(
|
|
5208
|
-
"xnet://nodes",
|
|
5209
|
-
"All Nodes",
|
|
5210
|
-
"Limited list of nodes in the local store.",
|
|
5211
|
-
"application/json",
|
|
5212
|
-
"low",
|
|
5213
|
-
["workspace.read"]
|
|
5214
|
-
),
|
|
5215
|
-
createResource(
|
|
5216
|
-
"xnet://schemas",
|
|
5217
|
-
"All Schemas",
|
|
5218
|
-
"List of available schemas and property metadata.",
|
|
5219
|
-
"application/json",
|
|
5220
|
-
"low",
|
|
5221
|
-
["workspace.read"]
|
|
5222
|
-
),
|
|
5223
|
-
createResource(
|
|
5224
|
-
"xnet://page/{pageId}.md",
|
|
5225
|
-
"Page Markdown",
|
|
5226
|
-
"Markdown projection for a page, including xNet frontmatter identity.",
|
|
5227
|
-
"text/markdown",
|
|
5228
|
-
"low",
|
|
5229
|
-
["page.read"],
|
|
5230
|
-
true
|
|
5231
|
-
),
|
|
5232
|
-
createResource(
|
|
5233
|
-
"xnet://page/{pageId}/outline",
|
|
5234
|
-
"Page Outline",
|
|
5235
|
-
"Page heading outline extracted from the Markdown projection.",
|
|
5236
|
-
"application/json",
|
|
5237
|
-
"low",
|
|
5238
|
-
["page.read"],
|
|
5239
|
-
true
|
|
5240
|
-
),
|
|
5241
|
-
createResource(
|
|
5242
|
-
"xnet://database/{databaseId}/schema",
|
|
5243
|
-
"Database Schema",
|
|
5244
|
-
"Database node metadata, declared properties, and known column descriptors.",
|
|
5245
|
-
"application/json",
|
|
5246
|
-
"low",
|
|
5247
|
-
["database.read"],
|
|
5248
|
-
true
|
|
5249
|
-
),
|
|
5250
|
-
createResource(
|
|
5251
|
-
"xnet://database/{databaseId}/views",
|
|
5252
|
-
"Database Views",
|
|
5253
|
-
"Known database view descriptors from the database node projection.",
|
|
5254
|
-
"application/json",
|
|
5255
|
-
"low",
|
|
5256
|
-
["database.read"],
|
|
5257
|
-
true
|
|
5258
|
-
),
|
|
5259
|
-
createResource(
|
|
5260
|
-
"xnet://database/{databaseId}/sample?limit=10",
|
|
5261
|
-
"Database Sample Rows",
|
|
5262
|
-
"Bounded sample of rows for a database using NodeQueryDescriptor semantics.",
|
|
5263
|
-
"application/json",
|
|
5264
|
-
"low",
|
|
5265
|
-
["database.read", "database.query"],
|
|
5266
|
-
true
|
|
5267
|
-
),
|
|
5268
|
-
createResource(
|
|
5269
|
-
"xnet://canvas/{canvasId}/viewport?x=0&y=0&w=1000&h=800",
|
|
5270
|
-
"Canvas Viewport",
|
|
5271
|
-
"Viewport-scoped canvas objects and edges.",
|
|
5272
|
-
"application/json",
|
|
5273
|
-
"low",
|
|
5274
|
-
["canvas.read"],
|
|
5275
|
-
true
|
|
5276
|
-
),
|
|
5277
|
-
createResource(
|
|
5278
|
-
"xnet://canvas/{canvasId}/objects",
|
|
5279
|
-
"Canvas Objects",
|
|
5280
|
-
"Bounded list of canvas objects and connectors.",
|
|
5281
|
-
"application/json",
|
|
5282
|
-
"low",
|
|
5283
|
-
["canvas.read"],
|
|
5284
|
-
true
|
|
5285
|
-
),
|
|
5286
|
-
createResource(
|
|
5287
|
-
"xnet://canvas/{canvasId}/selection?ids=object-1,object-2",
|
|
5288
|
-
"Canvas Selection",
|
|
5289
|
-
"Selection-scoped canvas objects, edges, and source previews.",
|
|
5290
|
-
"application/json",
|
|
5291
|
-
"low",
|
|
5292
|
-
["canvas.read"],
|
|
5293
|
-
true
|
|
5294
|
-
),
|
|
5295
|
-
createResource(
|
|
5296
|
-
"xnet://canvas/{canvasId}/json-canvas",
|
|
5297
|
-
"Canvas JSON Canvas",
|
|
5298
|
-
"JSON Canvas projection with xNet source metadata sidecars.",
|
|
5299
|
-
"application/json",
|
|
5300
|
-
"low",
|
|
5301
|
-
["canvas.read"],
|
|
5302
|
-
true
|
|
5303
|
-
)
|
|
5304
|
-
];
|
|
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}`);
|
|
5305
5279
|
}
|
|
5306
|
-
|
|
5307
|
-
|
|
5308
|
-
|
|
5309
|
-
|
|
5310
|
-
);
|
|
5311
|
-
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}`);
|
|
5312
5284
|
}
|
|
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
|
-
|
|
5348
|
-
|
|
5349
|
-
|
|
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." }
|
|
5350
5456
|
},
|
|
5351
|
-
|
|
5352
|
-
|
|
5353
|
-
|
|
5354
|
-
|
|
5355
|
-
|
|
5356
|
-
|
|
5357
|
-
|
|
5358
|
-
|
|
5359
|
-
|
|
5360
|
-
|
|
5361
|
-
|
|
5362
|
-
|
|
5363
|
-
|
|
5364
|
-
|
|
5365
|
-
|
|
5366
|
-
|
|
5367
|
-
|
|
5368
|
-
|
|
5369
|
-
|
|
5370
|
-
|
|
5371
|
-
|
|
5372
|
-
|
|
5373
|
-
|
|
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" }
|
|
5374
5511
|
}
|
|
5375
5512
|
},
|
|
5376
|
-
|
|
5377
|
-
|
|
5378
|
-
|
|
5379
|
-
|
|
5380
|
-
|
|
5381
|
-
|
|
5382
|
-
|
|
5383
|
-
|
|
5384
|
-
|
|
5385
|
-
|
|
5386
|
-
|
|
5387
|
-
|
|
5388
|
-
|
|
5389
|
-
|
|
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."
|
|
5390
5546
|
}
|
|
5391
5547
|
},
|
|
5392
|
-
|
|
5393
|
-
|
|
5394
|
-
|
|
5395
|
-
|
|
5396
|
-
|
|
5397
|
-
|
|
5398
|
-
|
|
5399
|
-
|
|
5400
|
-
|
|
5401
|
-
|
|
5402
|
-
|
|
5403
|
-
|
|
5404
|
-
|
|
5405
|
-
|
|
5406
|
-
|
|
5407
|
-
|
|
5408
|
-
|
|
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." }
|
|
5409
5570
|
},
|
|
5410
|
-
|
|
5411
|
-
|
|
5412
|
-
|
|
5413
|
-
|
|
5414
|
-
|
|
5415
|
-
|
|
5416
|
-
|
|
5417
|
-
|
|
5418
|
-
|
|
5419
|
-
|
|
5420
|
-
|
|
5421
|
-
|
|
5422
|
-
|
|
5423
|
-
|
|
5424
|
-
|
|
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." }
|
|
5425
5599
|
},
|
|
5426
|
-
|
|
5427
|
-
|
|
5428
|
-
|
|
5429
|
-
|
|
5430
|
-
|
|
5431
|
-
|
|
5432
|
-
|
|
5433
|
-
|
|
5434
|
-
|
|
5435
|
-
|
|
5436
|
-
|
|
5437
|
-
|
|
5438
|
-
|
|
5439
|
-
|
|
5440
|
-
|
|
5441
|
-
|
|
5442
|
-
|
|
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." }
|
|
5443
5627
|
},
|
|
5444
|
-
|
|
5445
|
-
|
|
5446
|
-
|
|
5447
|
-
|
|
5448
|
-
|
|
5449
|
-
|
|
5450
|
-
|
|
5451
|
-
|
|
5452
|
-
|
|
5453
|
-
|
|
5454
|
-
|
|
5455
|
-
|
|
5456
|
-
|
|
5457
|
-
|
|
5458
|
-
|
|
5459
|
-
|
|
5460
|
-
|
|
5461
|
-
|
|
5462
|
-
|
|
5463
|
-
|
|
5464
|
-
}
|
|
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." }
|
|
5465
5648
|
},
|
|
5466
|
-
|
|
5467
|
-
|
|
5468
|
-
|
|
5469
|
-
|
|
5470
|
-
|
|
5471
|
-
|
|
5472
|
-
|
|
5473
|
-
|
|
5474
|
-
|
|
5475
|
-
|
|
5476
|
-
|
|
5477
|
-
|
|
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."
|
|
5478
5679
|
}
|
|
5479
5680
|
},
|
|
5480
|
-
|
|
5481
|
-
|
|
5482
|
-
|
|
5483
|
-
|
|
5484
|
-
|
|
5485
|
-
|
|
5486
|
-
|
|
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: {
|
|
5487
5701
|
type: "object",
|
|
5488
|
-
|
|
5489
|
-
|
|
5490
|
-
|
|
5491
|
-
type: "boolean",
|
|
5492
|
-
description: "Must be true to perform the rollback."
|
|
5493
|
-
}
|
|
5494
|
-
},
|
|
5495
|
-
required: ["rollbackHandle", "confirmRollback"]
|
|
5496
|
-
}
|
|
5497
|
-
},
|
|
5498
|
-
{
|
|
5499
|
-
name: "xnet_database_describe",
|
|
5500
|
-
title: "Describe database",
|
|
5501
|
-
description: "Describe database schema, columns, views, row schema, and row counts.",
|
|
5502
|
-
risk: "low",
|
|
5503
|
-
requiredScopes: ["database.read"],
|
|
5504
|
-
inputSchema: {
|
|
5702
|
+
description: "Optional NodeQueryDescriptor-compatible query shape."
|
|
5703
|
+
},
|
|
5704
|
+
where: {
|
|
5505
5705
|
type: "object",
|
|
5506
|
-
|
|
5507
|
-
|
|
5508
|
-
|
|
5509
|
-
type: "boolean",
|
|
5510
|
-
description: "Include a small descriptor-backed row sample."
|
|
5511
|
-
}
|
|
5512
|
-
},
|
|
5513
|
-
required: ["databaseId"]
|
|
5514
|
-
}
|
|
5515
|
-
},
|
|
5516
|
-
{
|
|
5517
|
-
name: "xnet_database_query",
|
|
5518
|
-
title: "Query database rows",
|
|
5519
|
-
description: "Read a bounded page of database rows using NodeQueryDescriptor-compatible options.",
|
|
5520
|
-
risk: "low",
|
|
5521
|
-
requiredScopes: ["database.read", "database.query"],
|
|
5522
|
-
inputSchema: {
|
|
5706
|
+
description: "Optional exact property filters for row nodes."
|
|
5707
|
+
},
|
|
5708
|
+
search: {
|
|
5523
5709
|
type: "object",
|
|
5524
|
-
|
|
5525
|
-
|
|
5526
|
-
|
|
5527
|
-
descriptor: {
|
|
5528
|
-
type: "object",
|
|
5529
|
-
description: "Optional NodeQueryDescriptor-compatible query shape."
|
|
5530
|
-
},
|
|
5531
|
-
where: {
|
|
5532
|
-
type: "object",
|
|
5533
|
-
description: "Optional exact property filters for row nodes."
|
|
5534
|
-
},
|
|
5535
|
-
search: {
|
|
5536
|
-
type: "object",
|
|
5537
|
-
description: "Optional NodeQueryDescriptor search filter."
|
|
5538
|
-
},
|
|
5539
|
-
orderBy: {
|
|
5540
|
-
type: "object",
|
|
5541
|
-
description: "Optional NodeQueryDescriptor order map."
|
|
5542
|
-
},
|
|
5543
|
-
materializedView: {
|
|
5544
|
-
type: "object",
|
|
5545
|
-
description: "Optional materialized view query options."
|
|
5546
|
-
},
|
|
5547
|
-
count: { type: "string", description: "Page count mode: exact, estimate, or none." },
|
|
5548
|
-
limit: { type: "number", description: "Maximum row count." },
|
|
5549
|
-
offset: { type: "number", description: "Row offset." }
|
|
5550
|
-
},
|
|
5551
|
-
required: ["databaseId"]
|
|
5552
|
-
}
|
|
5553
|
-
},
|
|
5554
|
-
{
|
|
5555
|
-
name: "xnet_database_sample",
|
|
5556
|
-
title: "Sample database rows",
|
|
5557
|
-
description: "Return a small deterministic sample for schema and content inspection.",
|
|
5558
|
-
risk: "low",
|
|
5559
|
-
requiredScopes: ["database.read", "database.query"],
|
|
5560
|
-
inputSchema: {
|
|
5710
|
+
description: "Optional NodeQueryDescriptor search filter."
|
|
5711
|
+
},
|
|
5712
|
+
orderBy: {
|
|
5561
5713
|
type: "object",
|
|
5562
|
-
|
|
5563
|
-
|
|
5564
|
-
|
|
5565
|
-
sampleSize: { type: "number", description: "Sample row count." },
|
|
5566
|
-
descriptor: {
|
|
5567
|
-
type: "object",
|
|
5568
|
-
description: "Optional NodeQueryDescriptor-compatible query shape."
|
|
5569
|
-
}
|
|
5570
|
-
},
|
|
5571
|
-
required: ["databaseId"]
|
|
5572
|
-
}
|
|
5573
|
-
},
|
|
5574
|
-
{
|
|
5575
|
-
name: "xnet_database_explain_query",
|
|
5576
|
-
title: "Explain database query",
|
|
5577
|
-
description: "Explain descriptor, pagination, materialized view, and storage plan metadata.",
|
|
5578
|
-
risk: "low",
|
|
5579
|
-
requiredScopes: ["database.read", "database.query", "storage.diagnostics"],
|
|
5580
|
-
inputSchema: {
|
|
5714
|
+
description: "Optional NodeQueryDescriptor order map."
|
|
5715
|
+
},
|
|
5716
|
+
materializedView: {
|
|
5581
5717
|
type: "object",
|
|
5582
|
-
|
|
5583
|
-
|
|
5584
|
-
|
|
5585
|
-
|
|
5586
|
-
|
|
5587
|
-
description: "Optional NodeQueryDescriptor-compatible query shape."
|
|
5588
|
-
},
|
|
5589
|
-
limit: { type: "number", description: "Maximum row count for the dry-run query." },
|
|
5590
|
-
offset: { type: "number", description: "Row offset." }
|
|
5591
|
-
},
|
|
5592
|
-
required: ["databaseId"]
|
|
5593
|
-
}
|
|
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." }
|
|
5594
5723
|
},
|
|
5595
|
-
|
|
5596
|
-
|
|
5597
|
-
|
|
5598
|
-
|
|
5599
|
-
|
|
5600
|
-
|
|
5601
|
-
|
|
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: {
|
|
5602
5754
|
type: "object",
|
|
5603
|
-
|
|
5604
|
-
databaseId: { type: "string", description: "Database node id." },
|
|
5605
|
-
baseRevision: { type: "string", description: "Revision the mutation was based on." },
|
|
5606
|
-
operations: { type: "array", description: "Database operations to validate." },
|
|
5607
|
-
intent: { type: "string", description: "User or agent intent for the mutation." },
|
|
5608
|
-
actor: { type: "string", description: "Agent or user creating the plan." }
|
|
5609
|
-
},
|
|
5610
|
-
required: ["databaseId", "operations"]
|
|
5755
|
+
description: "Optional NodeQueryDescriptor-compatible query shape."
|
|
5611
5756
|
}
|
|
5612
5757
|
},
|
|
5613
|
-
|
|
5614
|
-
|
|
5615
|
-
|
|
5616
|
-
|
|
5617
|
-
|
|
5618
|
-
|
|
5619
|
-
|
|
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: {
|
|
5620
5781
|
type: "object",
|
|
5621
|
-
|
|
5622
|
-
|
|
5623
|
-
|
|
5624
|
-
|
|
5625
|
-
description: "Must be true to apply the database mutation plan."
|
|
5626
|
-
},
|
|
5627
|
-
allowStale: {
|
|
5628
|
-
type: "boolean",
|
|
5629
|
-
description: "Allow applying when the plan base revision differs from the live database node."
|
|
5630
|
-
}
|
|
5631
|
-
},
|
|
5632
|
-
required: ["plan", "confirmApply"]
|
|
5633
|
-
}
|
|
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." }
|
|
5634
5786
|
},
|
|
5635
|
-
|
|
5636
|
-
|
|
5637
|
-
|
|
5638
|
-
|
|
5639
|
-
|
|
5640
|
-
|
|
5641
|
-
|
|
5642
|
-
|
|
5643
|
-
|
|
5644
|
-
|
|
5645
|
-
|
|
5646
|
-
|
|
5647
|
-
|
|
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." }
|
|
5648
5813
|
},
|
|
5649
|
-
|
|
5650
|
-
|
|
5651
|
-
|
|
5652
|
-
|
|
5653
|
-
|
|
5654
|
-
|
|
5655
|
-
|
|
5656
|
-
|
|
5657
|
-
|
|
5658
|
-
|
|
5659
|
-
|
|
5660
|
-
|
|
5661
|
-
|
|
5662
|
-
|
|
5663
|
-
|
|
5664
|
-
|
|
5665
|
-
|
|
5666
|
-
|
|
5667
|
-
|
|
5668
|
-
|
|
5669
|
-
|
|
5670
|
-
|
|
5671
|
-
|
|
5672
|
-
}
|
|
5673
|
-
},
|
|
5674
|
-
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."
|
|
5675
5837
|
}
|
|
5676
5838
|
},
|
|
5677
|
-
|
|
5678
|
-
|
|
5679
|
-
|
|
5680
|
-
|
|
5681
|
-
|
|
5682
|
-
|
|
5683
|
-
|
|
5684
|
-
|
|
5685
|
-
|
|
5686
|
-
|
|
5687
|
-
|
|
5688
|
-
|
|
5689
|
-
|
|
5690
|
-
|
|
5691
|
-
|
|
5692
|
-
|
|
5693
|
-
|
|
5694
|
-
|
|
5695
|
-
|
|
5696
|
-
|
|
5697
|
-
|
|
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."
|
|
5698
5868
|
}
|
|
5699
5869
|
},
|
|
5700
|
-
|
|
5701
|
-
|
|
5702
|
-
|
|
5703
|
-
|
|
5704
|
-
|
|
5705
|
-
|
|
5706
|
-
|
|
5707
|
-
|
|
5708
|
-
|
|
5709
|
-
|
|
5710
|
-
|
|
5711
|
-
|
|
5712
|
-
|
|
5713
|
-
|
|
5714
|
-
|
|
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." }
|
|
5715
5894
|
},
|
|
5716
|
-
|
|
5717
|
-
|
|
5718
|
-
|
|
5719
|
-
|
|
5720
|
-
|
|
5721
|
-
|
|
5722
|
-
|
|
5723
|
-
|
|
5724
|
-
|
|
5725
|
-
|
|
5726
|
-
|
|
5727
|
-
|
|
5728
|
-
|
|
5729
|
-
|
|
5730
|
-
|
|
5731
|
-
|
|
5732
|
-
|
|
5733
|
-
|
|
5734
|
-
|
|
5735
|
-
|
|
5736
|
-
|
|
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." }
|
|
5737
5923
|
},
|
|
5738
|
-
|
|
5739
|
-
|
|
5740
|
-
|
|
5741
|
-
|
|
5742
|
-
|
|
5743
|
-
|
|
5744
|
-
|
|
5745
|
-
|
|
5746
|
-
|
|
5747
|
-
|
|
5748
|
-
|
|
5749
|
-
|
|
5750
|
-
|
|
5751
|
-
|
|
5752
|
-
|
|
5753
|
-
|
|
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."
|
|
5754
5947
|
}
|
|
5755
5948
|
},
|
|
5756
|
-
|
|
5757
|
-
|
|
5758
|
-
|
|
5759
|
-
|
|
5760
|
-
|
|
5761
|
-
|
|
5762
|
-
|
|
5763
|
-
|
|
5764
|
-
|
|
5765
|
-
|
|
5766
|
-
|
|
5767
|
-
|
|
5768
|
-
|
|
5769
|
-
|
|
5770
|
-
|
|
5771
|
-
|
|
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."
|
|
5772
5968
|
}
|
|
5773
5969
|
},
|
|
5774
|
-
|
|
5775
|
-
|
|
5776
|
-
|
|
5777
|
-
|
|
5778
|
-
|
|
5779
|
-
|
|
5780
|
-
|
|
5781
|
-
|
|
5782
|
-
|
|
5783
|
-
|
|
5784
|
-
|
|
5785
|
-
|
|
5786
|
-
|
|
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." }
|
|
5787
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
|
+
)
|
|
5788
6299
|
];
|
|
5789
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
|
+
*/
|
|
5790
6316
|
async callTool(name, args = {}) {
|
|
5791
|
-
|
|
5792
|
-
|
|
5793
|
-
|
|
5794
|
-
|
|
5795
|
-
|
|
5796
|
-
limit: readOptionalNumber(args, "limit"),
|
|
5797
|
-
offset: readOptionalNumber(args, "offset")
|
|
5798
|
-
});
|
|
5799
|
-
case "xnet_graph_expand":
|
|
5800
|
-
return await this.expandGraph({
|
|
5801
|
-
nodeId: readRequiredString(args, "nodeId"),
|
|
5802
|
-
hops: readOptionalNumber(args, "hops"),
|
|
5803
|
-
limit: readOptionalNumber(args, "limit")
|
|
5804
|
-
});
|
|
5805
|
-
case "xnet_create_context_pack":
|
|
5806
|
-
return await this.createContextPack({
|
|
5807
|
-
query: readOptionalString(args, "query"),
|
|
5808
|
-
seeds: readContextSeeds(args.seeds),
|
|
5809
|
-
limit: readOptionalNumber(args, "limit")
|
|
5810
|
-
});
|
|
5811
|
-
case "xnet_create_external_context_resource":
|
|
5812
|
-
return this.createExternalContextResource({
|
|
5813
|
-
url: readRequiredString(args, "url"),
|
|
5814
|
-
text: readRequiredString(args, "text"),
|
|
5815
|
-
mimeType: readOptionalString(args, "mimeType")
|
|
5816
|
-
});
|
|
5817
|
-
case "xnet_read_page_markdown": {
|
|
5818
|
-
const content = await this.readPageMarkdown(
|
|
5819
|
-
readRequiredString(args, "pageId"),
|
|
5820
|
-
readOptionalBoolean(args, "includeFrontmatter") ?? true
|
|
5821
|
-
);
|
|
5822
|
-
return { markdown: content.text, mimeType: content.mimeType, uri: content.uri };
|
|
5823
|
-
}
|
|
5824
|
-
case "xnet_validate_page_markdown": {
|
|
5825
|
-
const pageId = readOptionalString(args, "pageId");
|
|
5826
|
-
const node = pageId ? await this.getNodeOrThrow(pageId) : null;
|
|
5827
|
-
return validateXNetPageMarkdown(readRequiredString(args, "markdown"), {
|
|
5828
|
-
pageId,
|
|
5829
|
-
schemaId: node?.schemaId,
|
|
5830
|
-
baseRevision: readOptionalString(args, "baseRevision")
|
|
5831
|
-
});
|
|
5832
|
-
}
|
|
5833
|
-
case "xnet_plan_page_patch":
|
|
5834
|
-
return await this.planPagePatch(args);
|
|
5835
|
-
case "xnet_apply_page_markdown":
|
|
5836
|
-
return await this.applyPageMarkdown(args);
|
|
5837
|
-
case "xnet_get_audit_log":
|
|
5838
|
-
return this.getAuditLog({
|
|
5839
|
-
planId: readOptionalString(args, "planId"),
|
|
5840
|
-
limit: readOptionalNumber(args, "limit")
|
|
5841
|
-
});
|
|
5842
|
-
case "xnet_rollback_page_markdown":
|
|
5843
|
-
return await this.rollbackPageMarkdown(args);
|
|
5844
|
-
case "xnet_database_describe":
|
|
5845
|
-
return await this.describeDatabase(readRequiredString(args, "databaseId"), {
|
|
5846
|
-
includeSample: readOptionalBoolean(args, "includeSample") ?? false
|
|
5847
|
-
});
|
|
5848
|
-
case "xnet_database_query":
|
|
5849
|
-
return await this.queryDatabase({
|
|
5850
|
-
databaseId: readRequiredString(args, "databaseId"),
|
|
5851
|
-
schemaId: readOptionalString(args, "schemaId"),
|
|
5852
|
-
descriptor: readOptionalRecord(args, "descriptor"),
|
|
5853
|
-
where: readOptionalRecord(args, "where"),
|
|
5854
|
-
search: args.search,
|
|
5855
|
-
orderBy: readOptionalRecord(args, "orderBy"),
|
|
5856
|
-
materializedView: args.materializedView,
|
|
5857
|
-
count: readOptionalString(args, "count"),
|
|
5858
|
-
limit: readOptionalNumber(args, "limit"),
|
|
5859
|
-
offset: readOptionalNumber(args, "offset")
|
|
5860
|
-
});
|
|
5861
|
-
case "xnet_database_sample":
|
|
5862
|
-
return await this.sampleDatabase({
|
|
5863
|
-
databaseId: readRequiredString(args, "databaseId"),
|
|
5864
|
-
schemaId: readOptionalString(args, "schemaId"),
|
|
5865
|
-
descriptor: readOptionalRecord(args, "descriptor"),
|
|
5866
|
-
sampleSize: readOptionalNumber(args, "sampleSize")
|
|
5867
|
-
});
|
|
5868
|
-
case "xnet_database_explain_query":
|
|
5869
|
-
return await this.explainDatabaseQuery({
|
|
5870
|
-
databaseId: readRequiredString(args, "databaseId"),
|
|
5871
|
-
schemaId: readOptionalString(args, "schemaId"),
|
|
5872
|
-
descriptor: readOptionalRecord(args, "descriptor"),
|
|
5873
|
-
limit: readOptionalNumber(args, "limit"),
|
|
5874
|
-
offset: readOptionalNumber(args, "offset")
|
|
5875
|
-
});
|
|
5876
|
-
case "xnet_plan_database_mutation":
|
|
5877
|
-
return await this.planDatabaseMutation(args);
|
|
5878
|
-
case "xnet_apply_database_mutation":
|
|
5879
|
-
return await this.applyDatabaseMutation(args);
|
|
5880
|
-
case "xnet_canvas_list":
|
|
5881
|
-
return await this.listCanvases({
|
|
5882
|
-
limit: readOptionalNumber(args, "limit"),
|
|
5883
|
-
offset: readOptionalNumber(args, "offset")
|
|
5884
|
-
});
|
|
5885
|
-
case "xnet_canvas_read_viewport":
|
|
5886
|
-
return await this.readCanvasViewport({
|
|
5887
|
-
canvasId: readRequiredString(args, "canvasId"),
|
|
5888
|
-
x: readOptionalNumber(args, "x"),
|
|
5889
|
-
y: readOptionalNumber(args, "y"),
|
|
5890
|
-
w: readOptionalNumber(args, "w"),
|
|
5891
|
-
h: readOptionalNumber(args, "h"),
|
|
5892
|
-
tileSize: readOptionalNumber(args, "tileSize"),
|
|
5893
|
-
tileIds: readStringArray(args.tileIds),
|
|
5894
|
-
includeSourcePreviews: readOptionalBoolean(args, "includeSourcePreviews") ?? false
|
|
5895
|
-
});
|
|
5896
|
-
case "xnet_canvas_read_selection":
|
|
5897
|
-
return await this.readCanvasSelection({
|
|
5898
|
-
canvasId: readRequiredString(args, "canvasId"),
|
|
5899
|
-
objectIds: readRequiredStringArray(args.objectIds, "objectIds"),
|
|
5900
|
-
includeSourcePreviews: readOptionalBoolean(args, "includeSourcePreviews") ?? false
|
|
5901
|
-
});
|
|
5902
|
-
case "xnet_canvas_search":
|
|
5903
|
-
return await this.searchCanvas({
|
|
5904
|
-
canvasId: readRequiredString(args, "canvasId"),
|
|
5905
|
-
query: readRequiredString(args, "query"),
|
|
5906
|
-
limit: readOptionalNumber(args, "limit")
|
|
5907
|
-
});
|
|
5908
|
-
case "xnet_canvas_export_json_canvas":
|
|
5909
|
-
return await this.exportCanvasJsonCanvas({
|
|
5910
|
-
canvasId: readRequiredString(args, "canvasId"),
|
|
5911
|
-
includeXNetMetadata: readOptionalBoolean(args, "includeXNetMetadata") ?? true,
|
|
5912
|
-
x: readOptionalNumber(args, "x"),
|
|
5913
|
-
y: readOptionalNumber(args, "y"),
|
|
5914
|
-
w: readOptionalNumber(args, "w"),
|
|
5915
|
-
h: readOptionalNumber(args, "h")
|
|
5916
|
-
});
|
|
5917
|
-
case "xnet_canvas_plan_json_canvas_import":
|
|
5918
|
-
return await this.planCanvasJsonCanvasImport(args);
|
|
5919
|
-
case "xnet_plan_canvas_mutation":
|
|
5920
|
-
return await this.planCanvasMutation(args);
|
|
5921
|
-
case "xnet_validate_mutation_plan": {
|
|
5922
|
-
const validation = validateAiMutationPlan(args.plan);
|
|
5923
|
-
return { validation };
|
|
5924
|
-
}
|
|
5925
|
-
default: {
|
|
5926
|
-
const extra = this.extraTools.get(name);
|
|
5927
|
-
if (extra) return await extra.invoke(args);
|
|
5928
|
-
throw new Error(`Unknown AI surface tool: ${name}`);
|
|
5929
|
-
}
|
|
5930
|
-
}
|
|
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}`);
|
|
5931
6322
|
}
|
|
5932
6323
|
async readResource(uri) {
|
|
5933
|
-
|
|
5934
|
-
if (uri === "xnet://nodes") {
|
|
5935
|
-
const nodes = await this.config.store.list({ limit: this.limits.maxListLimit });
|
|
5936
|
-
return this.jsonResource(uri, { nodes, count: nodes.length, limit: this.limits.maxListLimit });
|
|
5937
|
-
}
|
|
5938
|
-
if (uri === "xnet://schemas") {
|
|
5939
|
-
return this.jsonResource(uri, { schemas: await this.getSchemaSummaries(true) });
|
|
5940
|
-
}
|
|
5941
|
-
if (parsed.host === "workspace" && parsed.parts[0] === "summary") {
|
|
5942
|
-
return this.jsonResource(uri, await this.getWorkspaceSummary());
|
|
5943
|
-
}
|
|
5944
|
-
if (parsed.host === "workspace" && parsed.parts[0] === "recent") {
|
|
5945
|
-
return this.jsonResource(uri, await this.getRecentNodes());
|
|
5946
|
-
}
|
|
5947
|
-
if (parsed.host === "workspace" && parsed.parts[0] === "search") {
|
|
5948
|
-
return this.jsonResource(
|
|
5949
|
-
uri,
|
|
5950
|
-
await this.search({
|
|
5951
|
-
query: parsed.searchParams.get("q") ?? "",
|
|
5952
|
-
schemaId: parsed.searchParams.get("schema") ?? void 0,
|
|
5953
|
-
limit: readUrlNumber(parsed.searchParams, "limit"),
|
|
5954
|
-
offset: readUrlNumber(parsed.searchParams, "offset")
|
|
5955
|
-
})
|
|
5956
|
-
);
|
|
5957
|
-
}
|
|
5958
|
-
if (parsed.host === "node" && parsed.parts[0]) {
|
|
5959
|
-
return this.jsonResource(uri, await this.getNodeProjection(parsed.parts[0]));
|
|
5960
|
-
}
|
|
5961
|
-
if (parsed.host === "page" && parsed.parts[0]) {
|
|
5962
|
-
const pageId = parsed.parts[0].endsWith(".md") ? parsed.parts[0].slice(0, -".md".length) : parsed.parts[0];
|
|
5963
|
-
if (parsed.parts.length === 1 || parsed.parts[0].endsWith(".md")) {
|
|
5964
|
-
return await this.readPageMarkdown(pageId, true, uri);
|
|
5965
|
-
}
|
|
5966
|
-
if (parsed.parts[1] === "outline") {
|
|
5967
|
-
return this.jsonResource(uri, await this.readPageOutline(pageId));
|
|
5968
|
-
}
|
|
5969
|
-
if (parsed.parts[1] === "context-pack") {
|
|
5970
|
-
return this.jsonResource(
|
|
5971
|
-
uri,
|
|
5972
|
-
await this.createContextPack({ seeds: [{ kind: "page", id: pageId }] })
|
|
5973
|
-
);
|
|
5974
|
-
}
|
|
5975
|
-
}
|
|
5976
|
-
if (parsed.host === "database" && parsed.parts[0]) {
|
|
5977
|
-
const databaseId = parsed.parts[0];
|
|
5978
|
-
if (parsed.parts[1] === "schema") {
|
|
5979
|
-
return this.jsonResource(uri, await this.describeDatabase(databaseId));
|
|
5980
|
-
}
|
|
5981
|
-
if (parsed.parts[1] === "views") {
|
|
5982
|
-
return this.jsonResource(uri, await this.readDatabaseViews(databaseId));
|
|
5983
|
-
}
|
|
5984
|
-
if (parsed.parts[1] === "sample") {
|
|
5985
|
-
return this.jsonResource(
|
|
5986
|
-
uri,
|
|
5987
|
-
await this.sampleDatabase({
|
|
5988
|
-
databaseId,
|
|
5989
|
-
sampleSize: readUrlNumber(parsed.searchParams, "limit")
|
|
5990
|
-
})
|
|
5991
|
-
);
|
|
5992
|
-
}
|
|
5993
|
-
if (parsed.parts[1] === "query") {
|
|
5994
|
-
return this.jsonResource(
|
|
5995
|
-
uri,
|
|
5996
|
-
await this.queryDatabase({
|
|
5997
|
-
databaseId,
|
|
5998
|
-
schemaId: parsed.searchParams.get("schema") ?? void 0,
|
|
5999
|
-
search: parsed.searchParams.get("q") ?? void 0,
|
|
6000
|
-
materializedView: parsed.searchParams.get("view") ? { viewId: parsed.searchParams.get("view") ?? "" } : void 0,
|
|
6001
|
-
limit: readUrlNumber(parsed.searchParams, "limit"),
|
|
6002
|
-
offset: readUrlNumber(parsed.searchParams, "offset")
|
|
6003
|
-
})
|
|
6004
|
-
);
|
|
6005
|
-
}
|
|
6006
|
-
}
|
|
6007
|
-
if (parsed.host === "canvas" && parsed.parts[0]) {
|
|
6008
|
-
const canvasId = parsed.parts[0];
|
|
6009
|
-
if (parsed.parts[1] === "viewport") {
|
|
6010
|
-
return this.jsonResource(
|
|
6011
|
-
uri,
|
|
6012
|
-
await this.readCanvasViewport({
|
|
6013
|
-
canvasId,
|
|
6014
|
-
x: readUrlNumber(parsed.searchParams, "x"),
|
|
6015
|
-
y: readUrlNumber(parsed.searchParams, "y"),
|
|
6016
|
-
w: readUrlNumber(parsed.searchParams, "w"),
|
|
6017
|
-
h: readUrlNumber(parsed.searchParams, "h"),
|
|
6018
|
-
tileSize: readUrlNumber(parsed.searchParams, "tileSize"),
|
|
6019
|
-
tileIds: readCsvStringArray(parsed.searchParams.get("tileIds")),
|
|
6020
|
-
includeSourcePreviews: parsed.searchParams.get("includeSourcePreviews") === "true"
|
|
6021
|
-
})
|
|
6022
|
-
);
|
|
6023
|
-
}
|
|
6024
|
-
if (parsed.parts[1] === "objects") {
|
|
6025
|
-
return this.jsonResource(uri, await this.readCanvasObjects(canvasId));
|
|
6026
|
-
}
|
|
6027
|
-
if (parsed.parts[1] === "selection") {
|
|
6028
|
-
return this.jsonResource(
|
|
6029
|
-
uri,
|
|
6030
|
-
await this.readCanvasSelection({
|
|
6031
|
-
canvasId,
|
|
6032
|
-
objectIds: readCsvStringArray(parsed.searchParams.get("ids")),
|
|
6033
|
-
includeSourcePreviews: parsed.searchParams.get("includeSourcePreviews") !== "false"
|
|
6034
|
-
})
|
|
6035
|
-
);
|
|
6036
|
-
}
|
|
6037
|
-
if (parsed.parts[1] === "json-canvas") {
|
|
6038
|
-
return this.jsonResource(
|
|
6039
|
-
uri,
|
|
6040
|
-
await this.exportCanvasJsonCanvas({
|
|
6041
|
-
canvasId,
|
|
6042
|
-
includeXNetMetadata: parsed.searchParams.get("includeXNetMetadata") !== "false"
|
|
6043
|
-
})
|
|
6044
|
-
);
|
|
6045
|
-
}
|
|
6046
|
-
if (parsed.parts[1] === "object" && parsed.parts[2]) {
|
|
6047
|
-
return this.jsonResource(uri, await this.readCanvasObject(canvasId, parsed.parts[2]));
|
|
6048
|
-
}
|
|
6049
|
-
}
|
|
6050
|
-
throw new Error(`Resource not found: ${uri}`);
|
|
6324
|
+
return await BUILT_IN_RESOURCE_ROUTES.resolve(this.host, uri);
|
|
6051
6325
|
}
|
|
6052
6326
|
toJsonText(value, format = "concise") {
|
|
6053
6327
|
return this.stringifyJson(value, format);
|
|
@@ -6144,7 +6418,7 @@ var AiSurfaceService = class {
|
|
|
6144
6418
|
const results = Array.isArray(search.results) ? search.results : [];
|
|
6145
6419
|
const ids = [];
|
|
6146
6420
|
for (const result of results) {
|
|
6147
|
-
if (
|
|
6421
|
+
if (isRecord3(result) && typeof result.id === "string") ids.push(result.id);
|
|
6148
6422
|
}
|
|
6149
6423
|
return ids;
|
|
6150
6424
|
}
|
|
@@ -6786,8 +7060,8 @@ var AiSurfaceService = class {
|
|
|
6786
7060
|
h: options.h,
|
|
6787
7061
|
includeSourcePreviews: false
|
|
6788
7062
|
});
|
|
6789
|
-
const objects = Array.isArray(viewport.objects) ? viewport.objects.filter(
|
|
6790
|
-
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) : [];
|
|
6791
7065
|
return {
|
|
6792
7066
|
canvasId: options.canvasId,
|
|
6793
7067
|
revision: viewport.revision,
|
|
@@ -6829,7 +7103,7 @@ var AiSurfaceService = class {
|
|
|
6829
7103
|
});
|
|
6830
7104
|
const objects = Array.isArray(viewport.objects) ? viewport.objects : [];
|
|
6831
7105
|
const object = objects.find(
|
|
6832
|
-
(candidate) =>
|
|
7106
|
+
(candidate) => isRecord3(candidate) && readRecordString(candidate, "id") === objectId
|
|
6833
7107
|
);
|
|
6834
7108
|
if (!object) throw new Error(`Canvas object not found: ${objectId}`);
|
|
6835
7109
|
return {
|
|
@@ -7305,7 +7579,7 @@ function invalidPageApplyResult(plan, validation) {
|
|
|
7305
7579
|
return {
|
|
7306
7580
|
applied: false,
|
|
7307
7581
|
pageId: "unknown",
|
|
7308
|
-
planId:
|
|
7582
|
+
planId: isRecord3(plan) && typeof plan.id === "string" ? plan.id : "unknown",
|
|
7309
7583
|
mode: "node-property",
|
|
7310
7584
|
baseRevision: "unknown",
|
|
7311
7585
|
liveRevision: "unknown",
|
|
@@ -7328,7 +7602,7 @@ function rejectedPageApplyResult(input) {
|
|
|
7328
7602
|
};
|
|
7329
7603
|
}
|
|
7330
7604
|
function isMutationPlan(value) {
|
|
7331
|
-
return
|
|
7605
|
+
return isRecord3(value) && typeof value.id === "string" && typeof value.actor === "string" && typeof value.intent === "string" && Array.isArray(value.changes) && isRecord3(value.validation);
|
|
7332
7606
|
}
|
|
7333
7607
|
function createResource(uri, name, description, mimeType, risk, requiredScopes, dynamic = false) {
|
|
7334
7608
|
return {
|
|
@@ -7341,22 +7615,6 @@ function createResource(uri, name, description, mimeType, risk, requiredScopes,
|
|
|
7341
7615
|
dynamic
|
|
7342
7616
|
};
|
|
7343
7617
|
}
|
|
7344
|
-
function parseXNetUri(uri) {
|
|
7345
|
-
let parsed;
|
|
7346
|
-
try {
|
|
7347
|
-
parsed = new URL(uri);
|
|
7348
|
-
} catch {
|
|
7349
|
-
throw new Error(`Invalid xNet resource URI: ${uri}`);
|
|
7350
|
-
}
|
|
7351
|
-
if (parsed.protocol !== "xnet:") {
|
|
7352
|
-
throw new Error(`Invalid xNet resource URI: ${uri}`);
|
|
7353
|
-
}
|
|
7354
|
-
return {
|
|
7355
|
-
host: parsed.hostname,
|
|
7356
|
-
parts: parsed.pathname.split("/").filter(Boolean).map((part) => decodeURIComponent(part)),
|
|
7357
|
-
searchParams: parsed.searchParams
|
|
7358
|
-
};
|
|
7359
|
-
}
|
|
7360
7618
|
function renderPageMarkdown(node, includeFrontmatter, exportedAt) {
|
|
7361
7619
|
const title = readStringProperty(node, "title") ?? "Untitled Page";
|
|
7362
7620
|
const body = readMarkdownBody(node);
|
|
@@ -7383,7 +7641,7 @@ function readMarkdownBody(node) {
|
|
|
7383
7641
|
const value = readStringProperty(node, "markdown") ?? readStringProperty(node, "content") ?? readStringProperty(node, "body") ?? readStringProperty(node, "text") ?? readStringProperty(node, "description");
|
|
7384
7642
|
if (value) return value;
|
|
7385
7643
|
const richContent = node.properties.content;
|
|
7386
|
-
if (
|
|
7644
|
+
if (isRecord3(richContent)) {
|
|
7387
7645
|
return `\`\`\`json
|
|
7388
7646
|
${JSON.stringify(richContent, null, 2)}
|
|
7389
7647
|
\`\`\``;
|
|
@@ -7444,7 +7702,7 @@ function relationFieldNames(schema) {
|
|
|
7444
7702
|
if (!schema) return [];
|
|
7445
7703
|
const fields = [];
|
|
7446
7704
|
for (const [name, definition] of Object.entries(schema.properties)) {
|
|
7447
|
-
if (
|
|
7705
|
+
if (isRecord3(definition) && definition.type === "relation") fields.push(name);
|
|
7448
7706
|
}
|
|
7449
7707
|
return fields;
|
|
7450
7708
|
}
|
|
@@ -7474,7 +7732,7 @@ function readArrayProperty(node, property) {
|
|
|
7474
7732
|
}
|
|
7475
7733
|
function readNestedArrayProperty(node, objectProperty, arrayProperty) {
|
|
7476
7734
|
const value = node.properties[objectProperty];
|
|
7477
|
-
return
|
|
7735
|
+
return isRecord3(value) && Array.isArray(value[arrayProperty]) ? value[arrayProperty] : void 0;
|
|
7478
7736
|
}
|
|
7479
7737
|
function belongsToDatabase(node, databaseId) {
|
|
7480
7738
|
return readStringProperty(node, "databaseId") === databaseId || readStringProperty(node, "database") === databaseId || readStringProperty(node, "parentDatabaseId") === databaseId;
|
|
@@ -7533,7 +7791,7 @@ function normalizeQuerySearch(value) {
|
|
|
7533
7791
|
const text3 = value.trim();
|
|
7534
7792
|
return text3 ? { text: text3 } : void 0;
|
|
7535
7793
|
}
|
|
7536
|
-
if (!
|
|
7794
|
+
if (!isRecord3(value) || typeof value.text !== "string" || !value.text.trim()) {
|
|
7537
7795
|
return void 0;
|
|
7538
7796
|
}
|
|
7539
7797
|
const fields = Array.isArray(value.fields) ? value.fields.filter(
|
|
@@ -7549,7 +7807,7 @@ function normalizeQueryMaterializedView(value) {
|
|
|
7549
7807
|
const viewId2 = value.trim();
|
|
7550
7808
|
return viewId2 ? { viewId: viewId2 } : void 0;
|
|
7551
7809
|
}
|
|
7552
|
-
if (!
|
|
7810
|
+
if (!isRecord3(value)) return void 0;
|
|
7553
7811
|
const viewId = readRecordString(value, "viewId");
|
|
7554
7812
|
if (!viewId) return void 0;
|
|
7555
7813
|
const maxAgeMs = readRecordNumber(value, "maxAgeMs");
|
|
@@ -7822,7 +8080,7 @@ function invalidDatabaseApplyResult(plan, validation) {
|
|
|
7822
8080
|
return {
|
|
7823
8081
|
applied: false,
|
|
7824
8082
|
databaseId: "unknown",
|
|
7825
|
-
planId:
|
|
8083
|
+
planId: isRecord3(plan) && typeof plan.id === "string" ? plan.id : "unknown",
|
|
7826
8084
|
baseRevision: "unknown",
|
|
7827
8085
|
liveRevision: "unknown",
|
|
7828
8086
|
appliedChangeIds: [],
|
|
@@ -7840,7 +8098,7 @@ function readTransactionOperations(operation) {
|
|
|
7840
8098
|
);
|
|
7841
8099
|
}
|
|
7842
8100
|
function readTransactionOperation(value, path) {
|
|
7843
|
-
if (!
|
|
8101
|
+
if (!isRecord3(value)) throw new Error(`${path} must be an object`);
|
|
7844
8102
|
if (value.type === "create") {
|
|
7845
8103
|
const options = readRecord(value, "options");
|
|
7846
8104
|
const schemaId = options ? readRecordString(options, "schemaId") : void 0;
|
|
@@ -7933,15 +8191,15 @@ function databaseEntityMatchesId(entity, id) {
|
|
|
7933
8191
|
}
|
|
7934
8192
|
function readRecordArrayProperty(record, key) {
|
|
7935
8193
|
const value = record[key];
|
|
7936
|
-
return Array.isArray(value) ? value.filter(
|
|
8194
|
+
return Array.isArray(value) ? value.filter(isRecord3) : [];
|
|
7937
8195
|
}
|
|
7938
8196
|
function isCanvasNode(node) {
|
|
7939
8197
|
return node.schemaId.includes("/Canvas") || node.schemaId.includes("Canvas@") || Array.isArray(node.properties.objects) || Array.isArray(node.properties.nodes);
|
|
7940
8198
|
}
|
|
7941
8199
|
function readCanvasScene(canvas) {
|
|
7942
8200
|
return {
|
|
7943
|
-
objects: (readArrayProperty(canvas, "objects") ?? readArrayProperty(canvas, "nodes") ?? []).filter(
|
|
7944
|
-
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)
|
|
7945
8203
|
};
|
|
7946
8204
|
}
|
|
7947
8205
|
function normalizeCanvasObject(object) {
|
|
@@ -8084,8 +8342,8 @@ function canvasObjectFile(object) {
|
|
|
8084
8342
|
return readRecordString(object, "file") ?? readRecordString(object, "filePath") ?? readRecordString(properties ?? {}, "file") ?? readRecordString(properties ?? {}, "filePath");
|
|
8085
8343
|
}
|
|
8086
8344
|
function jsonCanvasDocumentToCanvasOperations(document) {
|
|
8087
|
-
const nodes = Array.isArray(document.nodes) ? document.nodes.filter(
|
|
8088
|
-
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) : [];
|
|
8089
8347
|
const nodeIds = new Set(nodes.map((node) => readRecordString(node, "id")).filter(Boolean));
|
|
8090
8348
|
const warnings = edges.flatMap((edge) => {
|
|
8091
8349
|
const fromNode = readRecordString(edge, "fromNode");
|
|
@@ -8317,10 +8575,10 @@ function readOperations(value) {
|
|
|
8317
8575
|
throw new Error("operations must contain at least one operation");
|
|
8318
8576
|
}
|
|
8319
8577
|
return value.map((operation, index) => {
|
|
8320
|
-
if (!
|
|
8578
|
+
if (!isRecord3(operation) || typeof operation.op !== "string") {
|
|
8321
8579
|
throw new Error(`operations[${index}].op must be a string`);
|
|
8322
8580
|
}
|
|
8323
|
-
const args =
|
|
8581
|
+
const args = isRecord3(operation.args) ? operation.args : {};
|
|
8324
8582
|
return createAiOperation(
|
|
8325
8583
|
operation.op,
|
|
8326
8584
|
args,
|
|
@@ -8328,15 +8586,6 @@ function readOperations(value) {
|
|
|
8328
8586
|
);
|
|
8329
8587
|
});
|
|
8330
8588
|
}
|
|
8331
|
-
function readContextSeeds(value) {
|
|
8332
|
-
if (!Array.isArray(value)) return [];
|
|
8333
|
-
return value.map((seed) => {
|
|
8334
|
-
if (!isRecord4(seed)) return null;
|
|
8335
|
-
const kind = typeof seed.kind === "string" ? seed.kind : null;
|
|
8336
|
-
const id = typeof seed.id === "string" ? seed.id : null;
|
|
8337
|
-
return kind && id ? { kind, id } : null;
|
|
8338
|
-
}).filter((seed) => seed !== null);
|
|
8339
|
-
}
|
|
8340
8589
|
function uriForSeed(seed) {
|
|
8341
8590
|
switch (seed.kind) {
|
|
8342
8591
|
case "node":
|
|
@@ -8396,75 +8645,6 @@ function stringifyTruncatedJson(text3, maxCharacters) {
|
|
|
8396
8645
|
function quoteYaml(value) {
|
|
8397
8646
|
return JSON.stringify(value);
|
|
8398
8647
|
}
|
|
8399
|
-
function readRequiredString(record, key) {
|
|
8400
|
-
const value = record[key];
|
|
8401
|
-
if (typeof value !== "string" || !value.trim()) {
|
|
8402
|
-
throw new Error(`${key} must be a non-empty string`);
|
|
8403
|
-
}
|
|
8404
|
-
return value;
|
|
8405
|
-
}
|
|
8406
|
-
function readRequiredRecord(record, key) {
|
|
8407
|
-
const value = record[key];
|
|
8408
|
-
if (!isRecord4(value)) {
|
|
8409
|
-
throw new Error(`${key} must be an object`);
|
|
8410
|
-
}
|
|
8411
|
-
return value;
|
|
8412
|
-
}
|
|
8413
|
-
function readRequiredStringArray(value, key) {
|
|
8414
|
-
const result = readStringArray(value);
|
|
8415
|
-
if (result.length === 0) {
|
|
8416
|
-
throw new Error(`${key} must contain at least one string`);
|
|
8417
|
-
}
|
|
8418
|
-
return result;
|
|
8419
|
-
}
|
|
8420
|
-
function readStringArray(value) {
|
|
8421
|
-
if (!Array.isArray(value)) return [];
|
|
8422
|
-
return value.filter((item) => typeof item === "string" && item.trim() !== "");
|
|
8423
|
-
}
|
|
8424
|
-
function readCsvStringArray(value) {
|
|
8425
|
-
if (!value) return [];
|
|
8426
|
-
return value.split(",").map((item) => item.trim()).filter(Boolean);
|
|
8427
|
-
}
|
|
8428
|
-
function readOptionalString(record, key) {
|
|
8429
|
-
const value = record[key];
|
|
8430
|
-
return typeof value === "string" && value.trim() ? value : void 0;
|
|
8431
|
-
}
|
|
8432
|
-
function readOptionalRecord(record, key) {
|
|
8433
|
-
return readRecord(record, key);
|
|
8434
|
-
}
|
|
8435
|
-
function readOptionalNumber(record, key) {
|
|
8436
|
-
const value = record[key];
|
|
8437
|
-
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
8438
|
-
}
|
|
8439
|
-
function readOptionalBoolean(record, key) {
|
|
8440
|
-
const value = record[key];
|
|
8441
|
-
return typeof value === "boolean" ? value : void 0;
|
|
8442
|
-
}
|
|
8443
|
-
function readUrlNumber(params, key) {
|
|
8444
|
-
const value = params.get(key);
|
|
8445
|
-
if (value === null) return void 0;
|
|
8446
|
-
const parsed = Number(value);
|
|
8447
|
-
return Number.isFinite(parsed) ? parsed : void 0;
|
|
8448
|
-
}
|
|
8449
|
-
function readRecordString(record, key) {
|
|
8450
|
-
const value = record[key];
|
|
8451
|
-
return typeof value === "string" && value.trim() ? value : void 0;
|
|
8452
|
-
}
|
|
8453
|
-
function readRecord(record, key) {
|
|
8454
|
-
const value = record[key];
|
|
8455
|
-
return isRecord4(value) ? value : void 0;
|
|
8456
|
-
}
|
|
8457
|
-
function readRecordNumber(record, key) {
|
|
8458
|
-
const value = record[key];
|
|
8459
|
-
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
8460
|
-
}
|
|
8461
|
-
function readRecordBoolean(record, key) {
|
|
8462
|
-
const value = record[key];
|
|
8463
|
-
return typeof value === "boolean" ? value : void 0;
|
|
8464
|
-
}
|
|
8465
|
-
function isRecord4(value) {
|
|
8466
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8467
|
-
}
|
|
8468
8648
|
|
|
8469
8649
|
// src/sandbox/ast-validator.ts
|
|
8470
8650
|
import * as acorn from "acorn";
|