trellis 3.2.3 → 3.2.4
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/CHANGELOG.md +10 -0
- package/README.md +4 -0
- package/dist/better-sqlite-backend-CDYOAJDF.js +209 -0
- package/dist/boot-middleware-LBJX4N2S.js +9 -0
- package/dist/boot-middleware-PATBLD52.js +9 -0
- package/dist/bridge-G5DPW6TY.js +2361 -0
- package/dist/bridge-JSSPQPRH.js +2389 -0
- package/dist/bridge-LNXE4HAW.js +2389 -0
- package/dist/bridge-OAAXJWSA.js +2389 -0
- package/dist/bridge-SFS63RHC.js +2367 -0
- package/dist/bridge-U5TOUBVM.js +2389 -0
- package/dist/browser/index.js +12 -12
- package/dist/{chunk-KSU2GW22.js → chunk-276W52FK.js} +8 -0
- package/dist/{chunk-KFQGP6VL.js → chunk-2ESYSVXG.js} +15 -0
- package/dist/{chunk-L5N5PR2S.js → chunk-2WW2X2BR.js} +313 -77
- package/dist/chunk-3XCOAP6G.js +48 -0
- package/dist/chunk-53PDCTJ3.js +1856 -0
- package/dist/{chunk-N6MYZT4O.js → chunk-547FZFKO.js} +1 -1
- package/dist/{chunk-7DUMWO5L.js → chunk-7WVOPXJV.js} +3 -3
- package/dist/chunk-CMSFD6OV.js +11801 -0
- package/dist/{chunk-RSWUFTO2.js → chunk-CPUYCCLT.js} +2 -2
- package/dist/{chunk-4HYPLFJD.js → chunk-FA5TFVA5.js} +1 -1
- package/dist/{chunk-4XIVMVHC.js → chunk-G3XIHPSQ.js} +1 -1
- package/dist/{chunk-JHHEXEDM.js → chunk-GCQF75T4.js} +3 -3
- package/dist/{chunk-FKQO5A3H.js → chunk-GHG4H3AS.js} +2 -2
- package/dist/{chunk-GLM4HGN4.js → chunk-GRWQPKYK.js} +1 -1
- package/dist/{chunk-PZ4XYZ4J.js → chunk-GXA73CNC.js} +33 -8
- package/dist/{chunk-6GEZ6DN5.js → chunk-H6VTC5SS.js} +3 -3
- package/dist/{chunk-S3XLFZ27.js → chunk-IHHSOBJS.js} +1 -1
- package/dist/chunk-IJNC25UD.js +2243 -0
- package/dist/{chunk-VDAKEOML.js → chunk-J6OUIION.js} +1 -1
- package/dist/chunk-JAVAYMMS.js +6 -0
- package/dist/{chunk-S6GBJ2ZB.js → chunk-JCQQFLO5.js} +1 -1
- package/dist/{chunk-FWRS4CSC.js → chunk-KQG6ZYXP.js} +3 -3
- package/dist/chunk-KXAISKZT.js +119 -0
- package/dist/chunk-N3R74ZSR.js +7949 -0
- package/dist/{chunk-GU374KWZ.js → chunk-NLFRRGX6.js} +3 -3
- package/dist/{chunk-XMQ7G77X.js → chunk-OB4CMMX6.js} +1 -1
- package/dist/chunk-OKNASCZY.js +182 -0
- package/dist/chunk-ONOPPX5E.js +394 -0
- package/dist/chunk-QMSU2RAH.js +98 -0
- package/dist/{chunk-TCKXSOBP.js → chunk-RARKFVWU.js} +8 -1
- package/dist/{chunk-2AACZRII.js → chunk-SJWVDS5M.js} +751 -162
- package/dist/{chunk-SPSPV5BC.js → chunk-SZ3VAB5P.js} +159 -2
- package/dist/chunk-V2ASD6RQ.js +147 -0
- package/dist/{chunk-KQ4A2D2P.js → chunk-V4YCJDYL.js} +58 -38
- package/dist/{chunk-LNUIGRDZ.js → chunk-VWKLKLYB.js} +1 -1
- package/dist/chunk-W5PADCDF.js +1856 -0
- package/dist/{chunk-MLC5BUYO.js → chunk-WMERMSWI.js} +1 -1
- package/dist/chunk-WXAURJUD.js +1948 -0
- package/dist/chunk-YC5I32PS.js +147 -0
- package/dist/{chunk-VBYUTRXX.js → chunk-YKVB4LUQ.js} +3 -3
- package/dist/{chunk-NWSW5YNS.js → chunk-YPT6XMS4.js} +20 -50
- package/dist/cli/deploy-cli.d.ts.map +1 -1
- package/dist/cli/deploy-cli.js +43 -4
- package/dist/cli/gateway-deploy-cli.d.ts +19 -0
- package/dist/cli/gateway-deploy-cli.d.ts.map +1 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +1360 -881
- package/dist/cli/lane.d.ts.map +1 -1
- package/dist/cli/protocol.d.ts +6 -0
- package/dist/cli/protocol.d.ts.map +1 -0
- package/dist/client/index.browser.js +2 -2
- package/dist/client/index.js +11 -11
- package/dist/client/sdk.browser.js +1 -1
- package/dist/client/sdk.js +2 -2
- package/dist/cms/index.js +1 -1
- package/dist/config-KMY6RRK3.js +19 -0
- package/dist/core/index.js +13 -13
- package/dist/core/kernel/boot-middleware.d.ts +1 -1
- package/dist/core/kernel/boot-middleware.d.ts.map +1 -1
- package/dist/core/kernel/schema-middleware.d.ts +2 -1
- package/dist/core/kernel/schema-middleware.d.ts.map +1 -1
- package/dist/core/kernel/trellis-kernel.d.ts +10 -10
- package/dist/core/kernel/trellis-kernel.d.ts.map +1 -1
- package/dist/core/persist/factory.js +2 -2
- package/dist/core/persist/sqljs-backend.js +2 -2
- package/dist/db/index.js +30 -25
- package/dist/decisions/index.js +4 -4
- package/dist/embeddings/index.js +2 -2
- package/dist/engine.d.ts +24 -6
- package/dist/engine.d.ts.map +1 -1
- package/dist/gateway-deploy-cli-4TU4V3QI.js +312 -0
- package/dist/gateway-deploy-cli-A4ISTDHJ.js +298 -0
- package/dist/gateway-deploy-cli-D3XTKJQJ.js +312 -0
- package/dist/gateway-deploy-cli-ECV3OQCN.js +305 -0
- package/dist/gateway-deploy-cli-JUHKVIJE.js +296 -0
- package/dist/gateway-deploy-cli-NSDW2JLT.js +310 -0
- package/dist/gateway-serve-CM5EAZ52.js +113 -0
- package/dist/import-AJLYHFIA.js +10 -0
- package/dist/index.js +11 -11
- package/dist/launch-explorer-FVX6ZABW.js +95 -0
- package/dist/links/index.js +2 -2
- package/dist/mcp/bridge.d.ts +45 -0
- package/dist/mcp/bridge.d.ts.map +1 -0
- package/dist/mcp/discovery.d.ts +15 -0
- package/dist/mcp/discovery.d.ts.map +1 -0
- package/dist/mcp/gateway-config.d.ts +20 -0
- package/dist/mcp/gateway-config.d.ts.map +1 -0
- package/dist/mcp/gateway-serve.d.ts +19 -0
- package/dist/mcp/gateway-serve.d.ts.map +1 -0
- package/dist/mcp/gateway-serve.js +119 -0
- package/dist/mcp/graph-summary.d.ts +47 -0
- package/dist/mcp/graph-summary.d.ts.map +1 -0
- package/dist/mcp/room-audit.d.ts +14 -0
- package/dist/mcp/room-audit.d.ts.map +1 -0
- package/dist/mcp/room-helpers.d.ts +43 -0
- package/dist/mcp/room-helpers.d.ts.map +1 -0
- package/dist/mcp/room-registry.d.ts +32 -0
- package/dist/mcp/room-registry.d.ts.map +1 -0
- package/dist/mcp/room.d.ts +28 -0
- package/dist/mcp/room.d.ts.map +1 -0
- package/dist/plugins/agent-memory/index.js +1 -1
- package/dist/plugins/idea-garden/index.js +1 -1
- package/dist/plugins/plan-approval/index.js +1 -1
- package/dist/plugins/proactive-watcher/index.js +1 -1
- package/dist/protocol/envelope.d.ts +30 -0
- package/dist/protocol/envelope.d.ts.map +1 -0
- package/dist/protocol/index.d.ts +3 -0
- package/dist/protocol/index.d.ts.map +1 -0
- package/dist/protocol/whereami.d.ts +33 -0
- package/dist/protocol/whereami.d.ts.map +1 -0
- package/dist/query-KHDDIR5G.js +31 -0
- package/dist/react/index.js +1 -1
- package/dist/react/realtime.js +1 -1
- package/dist/react/schema-hooks.js +5 -5
- package/dist/realtime/index.js +3 -3
- package/dist/realtime/relay-server.d.ts.map +1 -1
- package/dist/realtime/room.d.ts.map +1 -1
- package/dist/realtime.bundle.js +2 -0
- package/dist/relay-server-BT6DCJ7F.js +12 -0
- package/dist/relay-server-MPQVGNQU.js +12 -0
- package/dist/relay-server-PAPW2EWC.js +12 -0
- package/dist/remote-manager-6ERQUBSL.js +224 -0
- package/dist/remote-manager-G665WWYY.js +224 -0
- package/dist/remote-manager-HJTEZ4OF.js +224 -0
- package/dist/remote-manager-NYP2Y5UR.js +224 -0
- package/dist/remote-manager-WGLCAMMC.js +224 -0
- package/dist/scaffold/write.d.ts.map +1 -1
- package/dist/schema/index.js +1 -1
- package/dist/server/cors.d.ts.map +1 -1
- package/dist/server/deploy-gateway.d.ts +27 -0
- package/dist/server/deploy-gateway.d.ts.map +1 -0
- package/dist/server/deploy.d.ts.map +1 -1
- package/dist/server/deploy.js +3 -2
- package/dist/server/discovery-mcp-gateway.d.ts +13 -0
- package/dist/server/discovery-mcp-gateway.d.ts.map +1 -0
- package/dist/server/index.js +38 -31
- package/dist/server/mcp-gateway.d.ts +27 -0
- package/dist/server/mcp-gateway.d.ts.map +1 -0
- package/dist/server/mcp-oauth-metadata.d.ts +31 -0
- package/dist/server/mcp-oauth-metadata.d.ts.map +1 -0
- package/dist/server/node-adapter.d.ts +7 -0
- package/dist/server/node-adapter.d.ts.map +1 -1
- package/dist/server/node-adapter.js +2 -2
- package/dist/server/realtime.d.ts.map +1 -1
- package/dist/server/server.d.ts +8 -0
- package/dist/server/server.d.ts.map +1 -1
- package/dist/server/streamable-mcp-gateway.d.ts +12 -0
- package/dist/server/streamable-mcp-gateway.d.ts.map +1 -0
- package/dist/server/usage-meter.d.ts +11 -0
- package/dist/server/usage-meter.d.ts.map +1 -1
- package/dist/server-4VEZHXXS.js +23 -0
- package/dist/{server-OGVWNDNK.js → server-556BMK4C.js} +1 -1
- package/dist/server-FQT2VYRE.js +23 -0
- package/dist/server-HGZE4ECC.js +23 -0
- package/dist/server-J4JKEAMH.js +23 -0
- package/dist/server-LXPM5TFR.js +23 -0
- package/dist/server-POB4NEUX.js +18 -0
- package/dist/server-VJKAPGPG.js +23 -0
- package/dist/server-YHS3XIIG.js +23 -0
- package/dist/server-ZHTPWPXS.js +23 -0
- package/dist/sprites-NC6D7YZS.js +27 -0
- package/dist/svelte/index.js +3 -3
- package/dist/svelte/schema-hooks.js +4 -4
- package/dist/sync/index.js +4 -4
- package/dist/tenancy-2SZTP4UD.js +16 -0
- package/dist/tenancy-7MTSESMJ.js +16 -0
- package/dist/tenancy-U4E7ZEAG.js +16 -0
- package/dist/vcs/decompose.d.ts.map +1 -1
- package/dist/vcs/index.js +5 -5
- package/dist/vcs/lane-disk-materialize.d.ts +11 -0
- package/dist/vcs/lane-disk-materialize.d.ts.map +1 -0
- package/dist/vcs/lane-worktree.d.ts +21 -0
- package/dist/vcs/lane-worktree.d.ts.map +1 -0
- package/dist/vcs/store.d.ts +28 -0
- package/dist/vcs/store.d.ts.map +1 -0
- package/dist/vcs/types.d.ts +5 -0
- package/dist/vcs/types.d.ts.map +1 -1
- package/dist/vm-config-YZRJ3KUB.js +21 -0
- package/dist/vue/index.js +3 -3
- package/dist/vue/schema-hooks.js +4 -4
- package/package.json +4 -3
- package/dist/chunk-GFZCJ4EH.js +0 -108
|
@@ -349,6 +349,157 @@ function findEntityId(binding) {
|
|
|
349
349
|
return void 0;
|
|
350
350
|
}
|
|
351
351
|
|
|
352
|
+
// src/core/kernel/schema-middleware.ts
|
|
353
|
+
function createSchemaMiddleware(config) {
|
|
354
|
+
const strict = config.strict ?? true;
|
|
355
|
+
return {
|
|
356
|
+
name: "schema-validation",
|
|
357
|
+
async handleOp(op, ctx, next) {
|
|
358
|
+
if (!op.facts || op.facts.length === 0) {
|
|
359
|
+
return next(op, ctx);
|
|
360
|
+
}
|
|
361
|
+
const ontologies = config.getOntologies();
|
|
362
|
+
const errors = [];
|
|
363
|
+
const entities = new Set(
|
|
364
|
+
op.facts.filter((fact) => fact.a === "type").map((fact) => fact.e)
|
|
365
|
+
);
|
|
366
|
+
for (const entityId of entities) {
|
|
367
|
+
const typeFact = op.facts.find((fact) => fact.e === entityId && fact.a === "type");
|
|
368
|
+
if (!typeFact) continue;
|
|
369
|
+
const entityType = String(typeFact.v);
|
|
370
|
+
const schema = resolveSchemaForEntity(entityType, entityId, op.facts, ontologies);
|
|
371
|
+
if (!schema) continue;
|
|
372
|
+
for (const fact of op.facts) {
|
|
373
|
+
if (fact.e !== entityId) continue;
|
|
374
|
+
const fieldSpec = schema.fields.find((field) => field.name === fact.a);
|
|
375
|
+
if (!fieldSpec) continue;
|
|
376
|
+
const validationError = validateValue(fact.a, fact.v, fieldSpec);
|
|
377
|
+
if (validationError) errors.push(validationError);
|
|
378
|
+
}
|
|
379
|
+
for (const fieldSpec of schema.fields) {
|
|
380
|
+
if (!fieldSpec.required) continue;
|
|
381
|
+
const hasValue = op.facts.some(
|
|
382
|
+
(fact) => fact.e === entityId && fact.a === fieldSpec.name && fact.v !== null && fact.v !== void 0 && fact.v !== ""
|
|
383
|
+
);
|
|
384
|
+
if (!hasValue) {
|
|
385
|
+
errors.push(`Missing required field: ${fieldSpec.name} on entity ${entityId}`);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
if (errors.length > 0 && strict) {
|
|
390
|
+
const errorMsg = [...new Set(errors)].join("; ");
|
|
391
|
+
throw new Error(`Schema validation failed: ${errorMsg}`);
|
|
392
|
+
}
|
|
393
|
+
return next(op, ctx);
|
|
394
|
+
}
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
function collectionSlugFromCollectionId(collectionId) {
|
|
398
|
+
const prefix = "collectionMeta:";
|
|
399
|
+
if (!collectionId.startsWith(prefix)) return null;
|
|
400
|
+
const slug = collectionId.slice(prefix.length).trim();
|
|
401
|
+
return slug || null;
|
|
402
|
+
}
|
|
403
|
+
function findPerCollectionRecordSchema(slug, ontologies) {
|
|
404
|
+
const suffix = `/collections/${slug}/Record`;
|
|
405
|
+
for (const schema of ontologies.values()) {
|
|
406
|
+
if (schema["@id"].endsWith(suffix)) return schema;
|
|
407
|
+
}
|
|
408
|
+
return void 0;
|
|
409
|
+
}
|
|
410
|
+
function resolveSchemaForEntity(entityType, entityId, facts, ontologies) {
|
|
411
|
+
const shortType = entityType.includes(":") ? entityType.split(":").pop() : entityType;
|
|
412
|
+
if (shortType === "CollectionRecord") {
|
|
413
|
+
const collectionIdFact = facts.find(
|
|
414
|
+
(fact) => fact.e === entityId && fact.a === "collectionId"
|
|
415
|
+
);
|
|
416
|
+
const slug = collectionIdFact ? collectionSlugFromCollectionId(String(collectionIdFact.v)) : null;
|
|
417
|
+
if (slug) {
|
|
418
|
+
const perCollection = findPerCollectionRecordSchema(slug, ontologies);
|
|
419
|
+
if (perCollection?.fields?.length) return perCollection;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
return ontologies.get(entityType) ?? ontologies.get(shortType) ?? ontologies.get(shortType.toLowerCase()) ?? ontologies.get(entityType.toLowerCase());
|
|
423
|
+
}
|
|
424
|
+
function validateValue(fieldName, value, spec) {
|
|
425
|
+
if (value === null || value === void 0) {
|
|
426
|
+
return null;
|
|
427
|
+
}
|
|
428
|
+
const actualType = typeof value;
|
|
429
|
+
switch (spec.valueType) {
|
|
430
|
+
case "title":
|
|
431
|
+
case "rich_text":
|
|
432
|
+
case "select":
|
|
433
|
+
case "multi_select":
|
|
434
|
+
case "status":
|
|
435
|
+
case "phone_number":
|
|
436
|
+
case "url":
|
|
437
|
+
case "email": {
|
|
438
|
+
if (actualType !== "string") {
|
|
439
|
+
return `Field ${fieldName}: expected string, got ${actualType}`;
|
|
440
|
+
}
|
|
441
|
+
const text = value;
|
|
442
|
+
if (spec.minLength !== void 0 && text.length < spec.minLength) {
|
|
443
|
+
return `Field ${fieldName}: must be at least ${spec.minLength} characters`;
|
|
444
|
+
}
|
|
445
|
+
if (spec.maxLength !== void 0 && text.length > spec.maxLength) {
|
|
446
|
+
return `Field ${fieldName}: must be at most ${spec.maxLength} characters`;
|
|
447
|
+
}
|
|
448
|
+
if (spec.pattern) {
|
|
449
|
+
try {
|
|
450
|
+
if (!new RegExp(spec.pattern).test(text)) {
|
|
451
|
+
return `Field ${fieldName}: invalid format`;
|
|
452
|
+
}
|
|
453
|
+
} catch {
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
if (spec.selectOptions && spec.selectOptions.length > 0) {
|
|
457
|
+
if (!spec.selectOptions.includes(value)) {
|
|
458
|
+
return `Field ${fieldName}: value "${value}" not in allowed options`;
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
break;
|
|
462
|
+
}
|
|
463
|
+
case "number":
|
|
464
|
+
if (actualType !== "number") {
|
|
465
|
+
return `Field ${fieldName}: expected number, got ${actualType}`;
|
|
466
|
+
}
|
|
467
|
+
if (spec.min !== void 0 && value < spec.min) {
|
|
468
|
+
return `Field ${fieldName}: value ${value} below minimum ${spec.min}`;
|
|
469
|
+
}
|
|
470
|
+
if (spec.max !== void 0 && value > spec.max) {
|
|
471
|
+
return `Field ${fieldName}: value ${value} above maximum ${spec.max}`;
|
|
472
|
+
}
|
|
473
|
+
break;
|
|
474
|
+
case "checkbox":
|
|
475
|
+
if (actualType !== "boolean") {
|
|
476
|
+
return `Field ${fieldName}: expected boolean, got ${actualType}`;
|
|
477
|
+
}
|
|
478
|
+
break;
|
|
479
|
+
case "date":
|
|
480
|
+
if (actualType === "string") {
|
|
481
|
+
const date = new Date(value);
|
|
482
|
+
if (isNaN(date.getTime())) {
|
|
483
|
+
return `Field ${fieldName}: invalid date format`;
|
|
484
|
+
}
|
|
485
|
+
} else if (actualType !== "object") {
|
|
486
|
+
return `Field ${fieldName}: expected date string or object, got ${actualType}`;
|
|
487
|
+
}
|
|
488
|
+
break;
|
|
489
|
+
case "files":
|
|
490
|
+
case "people":
|
|
491
|
+
case "relation":
|
|
492
|
+
case "rollup":
|
|
493
|
+
case "formula":
|
|
494
|
+
case "ai_generated":
|
|
495
|
+
case "json":
|
|
496
|
+
break;
|
|
497
|
+
default:
|
|
498
|
+
break;
|
|
499
|
+
}
|
|
500
|
+
return null;
|
|
501
|
+
}
|
|
502
|
+
|
|
352
503
|
// src/core/kernel/boot-middleware.ts
|
|
353
504
|
function buildOntologyIndex(schemas) {
|
|
354
505
|
const map = /* @__PURE__ */ new Map();
|
|
@@ -368,10 +519,16 @@ function buildOntologyIndex(schemas) {
|
|
|
368
519
|
}
|
|
369
520
|
function attachStandardMiddleware(kernel) {
|
|
370
521
|
kernel.removeMiddleware("logic-computation");
|
|
371
|
-
|
|
522
|
+
kernel.removeMiddleware("schema-validation");
|
|
523
|
+
const getOntologies = () => buildOntologyIndex(kernel.listOntologies());
|
|
524
|
+
kernel.addMiddleware(
|
|
525
|
+
createSchemaMiddleware({
|
|
526
|
+
getOntologies
|
|
527
|
+
})
|
|
528
|
+
);
|
|
372
529
|
kernel.addMiddleware(
|
|
373
530
|
createLogicMiddleware({
|
|
374
|
-
ontologies,
|
|
531
|
+
ontologies: getOntologies(),
|
|
375
532
|
getStore: () => kernel.getStore(),
|
|
376
533
|
getEntityType: (entityId) => kernel.getEntity(entityId)?.type
|
|
377
534
|
})
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import {
|
|
2
|
+
loadVmConfig
|
|
3
|
+
} from "./chunk-UZRUP7QW.js";
|
|
4
|
+
import {
|
|
5
|
+
readConfig
|
|
6
|
+
} from "./chunk-JA7AIHRK.js";
|
|
7
|
+
|
|
8
|
+
// src/mcp/gateway-config.ts
|
|
9
|
+
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
10
|
+
import { join, resolve } from "path";
|
|
11
|
+
var GATEWAY_CONFIG_FILE = ".trellis-mcp-gateway.json";
|
|
12
|
+
function gatewayConfigPath(dir = ".") {
|
|
13
|
+
return resolve(join(dir, GATEWAY_CONFIG_FILE));
|
|
14
|
+
}
|
|
15
|
+
function readGatewayConfig(dir = ".") {
|
|
16
|
+
const path = gatewayConfigPath(dir);
|
|
17
|
+
if (!existsSync(path)) return null;
|
|
18
|
+
try {
|
|
19
|
+
return JSON.parse(readFileSync(path, "utf8"));
|
|
20
|
+
} catch {
|
|
21
|
+
throw new Error(`Failed to parse ${path}: invalid JSON`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function writeGatewayConfig(config, dir = ".") {
|
|
25
|
+
writeFileSync(
|
|
26
|
+
gatewayConfigPath(dir),
|
|
27
|
+
JSON.stringify(config, null, 2) + "\n",
|
|
28
|
+
"utf8"
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// src/mcp/room-registry.ts
|
|
33
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
34
|
+
import { resolve as resolve2 } from "path";
|
|
35
|
+
function normalizeBaseUrl(url) {
|
|
36
|
+
return url.replace(/\/$/, "");
|
|
37
|
+
}
|
|
38
|
+
function roomMcpPathForUrl(baseUrl) {
|
|
39
|
+
const env = process.env.TRELLIS_MCP_PATH?.trim();
|
|
40
|
+
if (env) return env.startsWith("/") ? env : `/${env}`;
|
|
41
|
+
try {
|
|
42
|
+
const host = new URL(baseUrl).hostname;
|
|
43
|
+
if (/\.sprites\.app$/i.test(host)) return "/trellis/mcp";
|
|
44
|
+
} catch {
|
|
45
|
+
}
|
|
46
|
+
return "/mcp";
|
|
47
|
+
}
|
|
48
|
+
function toMcpUrl(base) {
|
|
49
|
+
const trimmed = normalizeBaseUrl(base);
|
|
50
|
+
if (trimmed.endsWith("/mcp") || trimmed.endsWith("/trellis/mcp")) {
|
|
51
|
+
return trimmed;
|
|
52
|
+
}
|
|
53
|
+
return `${trimmed}${roomMcpPathForUrl(trimmed)}`;
|
|
54
|
+
}
|
|
55
|
+
function parseRegistryJson(raw, source) {
|
|
56
|
+
try {
|
|
57
|
+
const data = JSON.parse(raw);
|
|
58
|
+
const rooms = Array.isArray(data) ? data : data.rooms ?? [];
|
|
59
|
+
return rooms.filter((r) => r.name && r.url).map((r) => ({
|
|
60
|
+
name: r.name,
|
|
61
|
+
url: normalizeBaseUrl(r.url),
|
|
62
|
+
mcpUrl: r.mcpUrl ? normalizeBaseUrl(r.mcpUrl) : toMcpUrl(r.url),
|
|
63
|
+
apiKey: r.apiKey,
|
|
64
|
+
source,
|
|
65
|
+
deployedAt: r.deployedAt,
|
|
66
|
+
active: r.active
|
|
67
|
+
}));
|
|
68
|
+
} catch {
|
|
69
|
+
return [];
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function listRegisteredRooms(opts = {}) {
|
|
73
|
+
const configDir = opts.configDir ?? ".";
|
|
74
|
+
const byUrl = /* @__PURE__ */ new Map();
|
|
75
|
+
const envRooms = process.env.TRELLIS_MCP_GATEWAY_ROOMS?.trim();
|
|
76
|
+
if (envRooms) {
|
|
77
|
+
for (const room of parseRegistryJson(envRooms, "env")) {
|
|
78
|
+
byUrl.set(room.url, room);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
const registryPath = process.env.TRELLIS_ROOM_REGISTRY?.trim() ?? resolve2(configDir, ".trellis-rooms.json");
|
|
82
|
+
if (existsSync2(registryPath)) {
|
|
83
|
+
try {
|
|
84
|
+
const raw = readFileSync2(registryPath, "utf8");
|
|
85
|
+
for (const room of parseRegistryJson(raw, "registry")) {
|
|
86
|
+
byUrl.set(room.url, room);
|
|
87
|
+
}
|
|
88
|
+
} catch {
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
const vm = loadVmConfig();
|
|
92
|
+
for (const [name, sprite] of Object.entries(vm.sprites)) {
|
|
93
|
+
if (!sprite.hasTrellis && !sprite.apiKey) continue;
|
|
94
|
+
const url = normalizeBaseUrl(sprite.url);
|
|
95
|
+
byUrl.set(url, {
|
|
96
|
+
name,
|
|
97
|
+
url,
|
|
98
|
+
mcpUrl: toMcpUrl(url),
|
|
99
|
+
apiKey: sprite.apiKey,
|
|
100
|
+
source: "vm",
|
|
101
|
+
active: vm.activeSprite === name
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
const dbConfig = readConfig(configDir);
|
|
105
|
+
if (dbConfig?.mode === "remote" && dbConfig.url) {
|
|
106
|
+
const url = normalizeBaseUrl(dbConfig.url);
|
|
107
|
+
const name = dbConfig.spriteName ?? url.replace(/^https?:\/\//, "").split(".")[0];
|
|
108
|
+
if (!byUrl.has(url)) {
|
|
109
|
+
byUrl.set(url, {
|
|
110
|
+
name,
|
|
111
|
+
url,
|
|
112
|
+
mcpUrl: toMcpUrl(url),
|
|
113
|
+
apiKey: dbConfig.apiKey,
|
|
114
|
+
source: "project",
|
|
115
|
+
deployedAt: dbConfig.deployedAt,
|
|
116
|
+
active: true
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return [...byUrl.values()].sort((a, b) => a.name.localeCompare(b.name));
|
|
121
|
+
}
|
|
122
|
+
function getRegisteredRoom(nameOrUrl, opts) {
|
|
123
|
+
const needle = nameOrUrl.trim().toLowerCase();
|
|
124
|
+
const rooms = listRegisteredRooms(opts);
|
|
125
|
+
return rooms.find(
|
|
126
|
+
(r) => r.name.toLowerCase() === needle || r.url.toLowerCase() === needle || r.mcpUrl.toLowerCase() === needle || normalizeBaseUrl(needle).endsWith(r.name.toLowerCase())
|
|
127
|
+
) ?? null;
|
|
128
|
+
}
|
|
129
|
+
function gatewayPublicUrl(opts) {
|
|
130
|
+
const fromConfig = readGatewayConfig(opts?.configDir ?? ".")?.publicUrl?.trim();
|
|
131
|
+
if (fromConfig) return fromConfig.replace(/\/$/, "");
|
|
132
|
+
if (opts?.gatewayPublicUrl?.trim()) {
|
|
133
|
+
return opts.gatewayPublicUrl.trim().replace(/\/$/, "");
|
|
134
|
+
}
|
|
135
|
+
const env = process.env.TRELLIS_MCP_GATEWAY_PUBLIC_URL?.trim();
|
|
136
|
+
if (env) return env.replace(/\/$/, "");
|
|
137
|
+
return "https://mcp.trellis.computer";
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export {
|
|
141
|
+
gatewayConfigPath,
|
|
142
|
+
writeGatewayConfig,
|
|
143
|
+
roomMcpPathForUrl,
|
|
144
|
+
listRegisteredRooms,
|
|
145
|
+
getRegisteredRoom,
|
|
146
|
+
gatewayPublicUrl
|
|
147
|
+
};
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
EAVStore,
|
|
6
6
|
init_eav_store
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-G3XIHPSQ.js";
|
|
8
8
|
|
|
9
9
|
// src/core/kernel/trellis-kernel.ts
|
|
10
10
|
init_eav_store();
|
|
@@ -541,11 +541,11 @@ var TrellisKernel = class {
|
|
|
541
541
|
* Create a new entity with the given type and attributes.
|
|
542
542
|
* Returns the entity ID.
|
|
543
543
|
*/
|
|
544
|
-
async createEntity(entityId, type, attributes = {}, links) {
|
|
545
|
-
const facts = [
|
|
546
|
-
|
|
547
|
-
{ e: entityId, a: "createdAt", v: (/* @__PURE__ */ new Date()).toISOString() }
|
|
548
|
-
|
|
544
|
+
async createEntity(entityId, type, attributes = {}, links, ctx) {
|
|
545
|
+
const facts = [{ e: entityId, a: "type", v: type }];
|
|
546
|
+
if (attributes.createdAt === void 0) {
|
|
547
|
+
facts.push({ e: entityId, a: "createdAt", v: (/* @__PURE__ */ new Date()).toISOString() });
|
|
548
|
+
}
|
|
549
549
|
for (const [attr, value] of Object.entries(attributes)) {
|
|
550
550
|
facts.push({ e: entityId, a: attr, v: value });
|
|
551
551
|
}
|
|
@@ -554,10 +554,14 @@ var TrellisKernel = class {
|
|
|
554
554
|
a: l.attribute,
|
|
555
555
|
e2: l.targetEntityId
|
|
556
556
|
}));
|
|
557
|
-
return this.mutate(
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
557
|
+
return this.mutate(
|
|
558
|
+
"addFacts",
|
|
559
|
+
{
|
|
560
|
+
facts,
|
|
561
|
+
links: linkRecords.length > 0 ? linkRecords : void 0
|
|
562
|
+
},
|
|
563
|
+
ctx
|
|
564
|
+
);
|
|
561
565
|
}
|
|
562
566
|
/**
|
|
563
567
|
* Get an entity by ID, returning all its facts and links.
|
|
@@ -576,7 +580,7 @@ var TrellisKernel = class {
|
|
|
576
580
|
/**
|
|
577
581
|
* Update an entity's attributes. Deletes old values and adds new ones.
|
|
578
582
|
*/
|
|
579
|
-
async updateEntity(entityId, updates) {
|
|
583
|
+
async updateEntity(entityId, updates, ctx) {
|
|
580
584
|
const existingFacts = this.store.getFactsByEntity(entityId);
|
|
581
585
|
const deleteFacts = [];
|
|
582
586
|
const addFacts = [];
|
|
@@ -588,21 +592,29 @@ var TrellisKernel = class {
|
|
|
588
592
|
const updatedAtFacts = existingFacts.filter((f2) => f2.a === "updatedAt");
|
|
589
593
|
deleteFacts.push(...updatedAtFacts);
|
|
590
594
|
addFacts.push({ e: entityId, a: "updatedAt", v: (/* @__PURE__ */ new Date()).toISOString() });
|
|
591
|
-
return this.mutate(
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
+
return this.mutate(
|
|
596
|
+
"addFacts",
|
|
597
|
+
{
|
|
598
|
+
facts: addFacts,
|
|
599
|
+
deleteFacts
|
|
600
|
+
},
|
|
601
|
+
ctx
|
|
602
|
+
);
|
|
595
603
|
}
|
|
596
604
|
/**
|
|
597
605
|
* Delete an entity and all its facts and links.
|
|
598
606
|
*/
|
|
599
|
-
async deleteEntity(entityId) {
|
|
607
|
+
async deleteEntity(entityId, ctx) {
|
|
600
608
|
const facts = this.store.getFactsByEntity(entityId);
|
|
601
609
|
const links = this.store.getLinksByEntity(entityId);
|
|
602
|
-
return this.mutate(
|
|
603
|
-
deleteFacts
|
|
604
|
-
|
|
605
|
-
|
|
610
|
+
return this.mutate(
|
|
611
|
+
"deleteFacts",
|
|
612
|
+
{
|
|
613
|
+
deleteFacts: facts,
|
|
614
|
+
deleteLinks: links
|
|
615
|
+
},
|
|
616
|
+
ctx
|
|
617
|
+
);
|
|
606
618
|
}
|
|
607
619
|
/**
|
|
608
620
|
* List entities by type, with optional attribute filters.
|
|
@@ -632,18 +644,26 @@ var TrellisKernel = class {
|
|
|
632
644
|
/**
|
|
633
645
|
* Add a link between two entities.
|
|
634
646
|
*/
|
|
635
|
-
async addLink(sourceId, attribute, targetId) {
|
|
636
|
-
return this.mutate(
|
|
637
|
-
|
|
638
|
-
|
|
647
|
+
async addLink(sourceId, attribute, targetId, ctx) {
|
|
648
|
+
return this.mutate(
|
|
649
|
+
"addLinks",
|
|
650
|
+
{
|
|
651
|
+
links: [{ e1: sourceId, a: attribute, e2: targetId }]
|
|
652
|
+
},
|
|
653
|
+
ctx
|
|
654
|
+
);
|
|
639
655
|
}
|
|
640
656
|
/**
|
|
641
657
|
* Remove a link between two entities.
|
|
642
658
|
*/
|
|
643
|
-
async removeLink(sourceId, attribute, targetId) {
|
|
644
|
-
return this.mutate(
|
|
645
|
-
deleteLinks
|
|
646
|
-
|
|
659
|
+
async removeLink(sourceId, attribute, targetId, ctx) {
|
|
660
|
+
return this.mutate(
|
|
661
|
+
"deleteLinks",
|
|
662
|
+
{
|
|
663
|
+
deleteLinks: [{ e1: sourceId, a: attribute, e2: targetId }]
|
|
664
|
+
},
|
|
665
|
+
ctx
|
|
666
|
+
);
|
|
647
667
|
}
|
|
648
668
|
/**
|
|
649
669
|
* Add a fact to an entity.
|
|
@@ -837,32 +857,32 @@ var TrellisKernel = class {
|
|
|
837
857
|
/**
|
|
838
858
|
* Create a node (alias for createEntity with schema validation).
|
|
839
859
|
*/
|
|
840
|
-
async createNode(id, data, type,
|
|
841
|
-
return this.createEntity(id, type, data);
|
|
860
|
+
async createNode(id, data, type, ctx) {
|
|
861
|
+
return this.createEntity(id, type, data, void 0, ctx);
|
|
842
862
|
}
|
|
843
863
|
/**
|
|
844
864
|
* Update a node (alias for updateEntity with schema validation).
|
|
845
865
|
*/
|
|
846
|
-
async updateNode(id, data, type,
|
|
847
|
-
return this.updateEntity(id, data);
|
|
866
|
+
async updateNode(id, data, type, ctx) {
|
|
867
|
+
return this.updateEntity(id, data, ctx);
|
|
848
868
|
}
|
|
849
869
|
/**
|
|
850
870
|
* Delete a node (alias for deleteEntity).
|
|
851
871
|
*/
|
|
852
|
-
async deleteNode(id,
|
|
853
|
-
return this.deleteEntity(id);
|
|
872
|
+
async deleteNode(id, ctx) {
|
|
873
|
+
return this.deleteEntity(id, ctx);
|
|
854
874
|
}
|
|
855
875
|
/**
|
|
856
876
|
* Link two nodes (alias for addLink).
|
|
857
877
|
*/
|
|
858
|
-
async link(e1, a, e2,
|
|
859
|
-
return this.addLink(e1, a, e2);
|
|
878
|
+
async link(e1, a, e2, ctx) {
|
|
879
|
+
return this.addLink(e1, a, e2, ctx);
|
|
860
880
|
}
|
|
861
881
|
/**
|
|
862
882
|
* Unlink two nodes (alias for removeLink).
|
|
863
883
|
*/
|
|
864
|
-
async unlink(e1, a, e2,
|
|
865
|
-
return this.removeLink(e1, a, e2);
|
|
884
|
+
async unlink(e1, a, e2, ctx) {
|
|
885
|
+
return this.removeLink(e1, a, e2, ctx);
|
|
866
886
|
}
|
|
867
887
|
// -------------------------------------------------------------------------
|
|
868
888
|
// Middleware
|