@firfi/huly-mcp 0.15.0 → 0.16.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/README.md +4 -2
- package/dist/index.cjs +792 -266
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -406,9 +406,11 @@ For a Smithery publish schema example, see [docs/SMITHERY_URL_PUBLISH.md](docs/S
|
|
|
406
406
|
| Tool | Description |
|
|
407
407
|
|------|-------------|
|
|
408
408
|
| `list_associations` | List Huly association definitions: class-level typed links that define which document classes may be related. Use this before create_relation to discover association IDs, source/target classes, and whether relation writes are supported. |
|
|
409
|
+
| `create_association` | Idempotently create one Huly association definition between two non-system classes. Use sourceClass/targetClass with sourceRole/targetRole and cardinality; returns an existing identical association by default. |
|
|
410
|
+
| `delete_association` | Idempotently delete one Huly association definition only when no concrete relations reference it. If relations exist, delete_relation must clean them up first; deleting an already-missing association is a successful no-op. |
|
|
409
411
|
| `list_relations` | List concrete Huly relation instances under an association, optionally filtered by source and target documents. Requires at least one filter to avoid broad workspace scans. |
|
|
410
|
-
| `create_relation` | Idempotently create one concrete relation between two resolved documents
|
|
411
|
-
| `delete_relation` | Idempotently delete one concrete relation by relation ID or by exact association/source/target triple.
|
|
412
|
+
| `create_relation` | Idempotently create one concrete relation between two resolved documents for a writable association. Enforces association endpoint classes, direction, duplicate handling, automation-only restrictions, and cardinality. |
|
|
413
|
+
| `delete_relation` | Idempotently delete one concrete relation by relation ID or by exact association/source/target triple. Triple deletes use the same direction semantics as create_relation and fail if the selector is ambiguous. |
|
|
412
414
|
|
|
413
415
|
### Activity
|
|
414
416
|
|
package/dist/index.cjs
CHANGED
|
@@ -151353,12 +151353,305 @@ var InvalidContentTypeError = class extends Schema_exports.TaggedError()(
|
|
|
151353
151353
|
}
|
|
151354
151354
|
};
|
|
151355
151355
|
|
|
151356
|
+
// src/domain/schemas/generic-associations.ts
|
|
151357
|
+
var AssociationIdentifier = NonEmptyString2.pipe(Schema_exports.brand("AssociationIdentifier"));
|
|
151358
|
+
var AssociationName = NonEmptyString2.pipe(Schema_exports.brand("AssociationName"));
|
|
151359
|
+
var AssociationRoleName = NonEmptyString2.pipe(Schema_exports.brand("AssociationRoleName"));
|
|
151360
|
+
var RelationIdentifier = NonEmptyString2.pipe(Schema_exports.brand("RelationIdentifier"));
|
|
151361
|
+
var ListRelationsWarning = NonEmptyString2.pipe(Schema_exports.brand("ListRelationsWarning"));
|
|
151362
|
+
var CardinalityValues = [
|
|
151363
|
+
"one-to-one",
|
|
151364
|
+
"one-to-many",
|
|
151365
|
+
"many-to-many"
|
|
151366
|
+
];
|
|
151367
|
+
var CardinalitySchema = Schema_exports.Literal(...CardinalityValues).annotations({
|
|
151368
|
+
description: `Association cardinality: ${enumValuesDescription(CardinalityValues)}`
|
|
151369
|
+
});
|
|
151370
|
+
var RelationDirectionValues = ["source-to-target", "target-to-source", "either"];
|
|
151371
|
+
var RelationDirectionSchema = Schema_exports.Literal(...RelationDirectionValues);
|
|
151372
|
+
var DefaultRelationDirection = "source-to-target";
|
|
151373
|
+
var relationDirectionDescription = `Relation traversal direction: ${enumValuesDescription(RelationDirectionValues)}. Defaults to ${DefaultRelationDirection}.`;
|
|
151374
|
+
var RelationIfExistsSchema = Schema_exports.Literal("return_existing", "fail");
|
|
151375
|
+
var AssociationIfExistsSchema = Schema_exports.Literal("return_existing", "fail");
|
|
151376
|
+
var RawObjectLocatorSchema = Schema_exports.Struct({
|
|
151377
|
+
kind: Schema_exports.Literal("raw"),
|
|
151378
|
+
id: DocId.annotations({
|
|
151379
|
+
description: "Raw Huly document _id"
|
|
151380
|
+
}),
|
|
151381
|
+
class: Schema_exports.optional(ObjectClassName.annotations({
|
|
151382
|
+
description: "Raw Huly document class, such as tracker:class:Issue. Required unless the association side determines the expected class."
|
|
151383
|
+
}))
|
|
151384
|
+
});
|
|
151385
|
+
var IssueObjectLocatorSchema = Schema_exports.Struct({
|
|
151386
|
+
kind: Schema_exports.Literal("issue"),
|
|
151387
|
+
issue: IssueIdentifier.annotations({
|
|
151388
|
+
description: "Issue identifier, such as HULY-123, or a numeric issue number when project is also provided."
|
|
151389
|
+
}),
|
|
151390
|
+
project: Schema_exports.optional(ProjectIdentifier.annotations({
|
|
151391
|
+
description: "Project identifier. Optional when issue already includes a project prefix like HULY-123."
|
|
151392
|
+
}))
|
|
151393
|
+
});
|
|
151394
|
+
var DocumentObjectLocatorSchema = Schema_exports.Struct({
|
|
151395
|
+
kind: Schema_exports.Literal("document"),
|
|
151396
|
+
document: DocumentIdentifier.annotations({
|
|
151397
|
+
description: "Document title or ID"
|
|
151398
|
+
}),
|
|
151399
|
+
teamspace: Schema_exports.optional(TeamspaceIdentifier.annotations({
|
|
151400
|
+
description: "Teamspace name or ID. If omitted, document title matches must be unique across the workspace."
|
|
151401
|
+
}))
|
|
151402
|
+
});
|
|
151403
|
+
var GenericObjectLocatorSchema = Schema_exports.Union(
|
|
151404
|
+
RawObjectLocatorSchema,
|
|
151405
|
+
IssueObjectLocatorSchema,
|
|
151406
|
+
DocumentObjectLocatorSchema
|
|
151407
|
+
).annotations({
|
|
151408
|
+
title: "GenericObjectLocator",
|
|
151409
|
+
description: "Explicit locator for a Huly document endpoint. Use raw for known _id values, issue for tracker issues, or document for Huly documents. Card locators are intentionally not included until a robust card resolver is available."
|
|
151410
|
+
});
|
|
151411
|
+
var ResolvedObjectSummarySchema = Schema_exports.Struct({
|
|
151412
|
+
id: DocId,
|
|
151413
|
+
class: ObjectClassName,
|
|
151414
|
+
display: NonEmptyString2,
|
|
151415
|
+
locatorKind: Schema_exports.Literal("raw", "issue", "document"),
|
|
151416
|
+
warning: Schema_exports.optional(Schema_exports.String)
|
|
151417
|
+
});
|
|
151418
|
+
var AssociationSummarySchema = Schema_exports.Struct({
|
|
151419
|
+
associationId: AssociationId,
|
|
151420
|
+
name: Schema_exports.optional(AssociationName),
|
|
151421
|
+
label: Schema_exports.optional(NonEmptyString2),
|
|
151422
|
+
description: Schema_exports.optional(Schema_exports.String),
|
|
151423
|
+
sourceClass: ObjectClassName,
|
|
151424
|
+
sourceClassLabel: Schema_exports.optional(NonEmptyString2.annotations({
|
|
151425
|
+
description: "Best-effort human display label for sourceClass when the class is known to this server"
|
|
151426
|
+
})),
|
|
151427
|
+
targetClass: ObjectClassName,
|
|
151428
|
+
targetClassLabel: Schema_exports.optional(NonEmptyString2.annotations({
|
|
151429
|
+
description: "Best-effort human display label for targetClass when the class is known to this server"
|
|
151430
|
+
})),
|
|
151431
|
+
sourceRole: Schema_exports.optional(AssociationRoleName),
|
|
151432
|
+
targetRole: Schema_exports.optional(AssociationRoleName),
|
|
151433
|
+
relationClass: Schema_exports.optional(ObjectClassName),
|
|
151434
|
+
cardinality: CardinalitySchema,
|
|
151435
|
+
symmetric: Schema_exports.Boolean,
|
|
151436
|
+
system: Schema_exports.Boolean,
|
|
151437
|
+
canListRelations: Schema_exports.Boolean,
|
|
151438
|
+
canCreateRelation: Schema_exports.Boolean,
|
|
151439
|
+
canDeleteRelation: Schema_exports.Boolean,
|
|
151440
|
+
unsupportedReason: Schema_exports.optional(Schema_exports.String)
|
|
151441
|
+
});
|
|
151442
|
+
var RelationSummarySchema = Schema_exports.Struct({
|
|
151443
|
+
relationId: RelationId,
|
|
151444
|
+
associationId: AssociationId,
|
|
151445
|
+
associationName: Schema_exports.optional(AssociationName),
|
|
151446
|
+
source: ResolvedObjectSummarySchema,
|
|
151447
|
+
target: ResolvedObjectSummarySchema,
|
|
151448
|
+
createdOn: Schema_exports.optional(Timestamp),
|
|
151449
|
+
modifiedOn: Schema_exports.optional(Timestamp)
|
|
151450
|
+
});
|
|
151451
|
+
var ListAssociationsParamsSchema = Schema_exports.Struct({
|
|
151452
|
+
association: Schema_exports.optional(AssociationIdentifier.annotations({
|
|
151453
|
+
description: "Association _id, source/target role name, or stable association name"
|
|
151454
|
+
})),
|
|
151455
|
+
sourceClass: Schema_exports.optional(ObjectClassName.annotations({
|
|
151456
|
+
description: "Only return associations whose source class matches this Huly class ID"
|
|
151457
|
+
})),
|
|
151458
|
+
targetClass: Schema_exports.optional(ObjectClassName.annotations({
|
|
151459
|
+
description: "Only return associations whose target class matches this Huly class ID"
|
|
151460
|
+
})),
|
|
151461
|
+
writableOnly: Schema_exports.optional(Schema_exports.Boolean.annotations({
|
|
151462
|
+
description: "Only return associations whose relation create/delete path has been validated and allowlisted"
|
|
151463
|
+
})),
|
|
151464
|
+
includeSystem: Schema_exports.optional(Schema_exports.Boolean.annotations({
|
|
151465
|
+
description: "Include internal/system associations. Defaults to false."
|
|
151466
|
+
})),
|
|
151467
|
+
limit: Schema_exports.optional(LimitParam.annotations({
|
|
151468
|
+
description: "Maximum number of associations to return (default: 50)"
|
|
151469
|
+
}))
|
|
151470
|
+
}).annotations({
|
|
151471
|
+
title: "ListAssociationsParams",
|
|
151472
|
+
description: "Parameters for listing generic Huly association definitions"
|
|
151473
|
+
});
|
|
151474
|
+
var ListAssociationsResultSchema = Schema_exports.Struct({
|
|
151475
|
+
associations: Schema_exports.Array(AssociationSummarySchema),
|
|
151476
|
+
total: Schema_exports.Number
|
|
151477
|
+
});
|
|
151478
|
+
var CreateAssociationParamsSchema = Schema_exports.Struct({
|
|
151479
|
+
sourceClass: ObjectClassName.annotations({
|
|
151480
|
+
description: "Source Huly class ID, such as tracker:class:Issue. core:class:* system classes are rejected."
|
|
151481
|
+
}),
|
|
151482
|
+
targetClass: ObjectClassName.annotations({
|
|
151483
|
+
description: "Target Huly class ID, such as tracker:class:Issue. core:class:* system classes are rejected."
|
|
151484
|
+
}),
|
|
151485
|
+
sourceRole: AssociationRoleName.annotations({
|
|
151486
|
+
description: "Role name stored on the source side of the association."
|
|
151487
|
+
}),
|
|
151488
|
+
targetRole: AssociationRoleName.annotations({
|
|
151489
|
+
description: "Role name stored on the target side of the association."
|
|
151490
|
+
}),
|
|
151491
|
+
cardinality: CardinalitySchema,
|
|
151492
|
+
automationOnly: Schema_exports.optional(Schema_exports.Boolean.annotations({
|
|
151493
|
+
description: "Whether Huly automation-only UI paths should own relation writes for this association. Defaults to false."
|
|
151494
|
+
})),
|
|
151495
|
+
ifExists: Schema_exports.optional(AssociationIfExistsSchema.annotations({
|
|
151496
|
+
description: "return_existing (default) returns an identical existing association; fail reports an existing association as an error"
|
|
151497
|
+
}))
|
|
151498
|
+
}).annotations({
|
|
151499
|
+
title: "CreateAssociationParams",
|
|
151500
|
+
description: "Parameters for idempotently creating a Huly association definition in the model space. The created association can then be used with create_relation."
|
|
151501
|
+
});
|
|
151502
|
+
var CreateAssociationResultSchema = Schema_exports.Struct({
|
|
151503
|
+
association: AssociationSummarySchema,
|
|
151504
|
+
created: Schema_exports.Boolean,
|
|
151505
|
+
existing: Schema_exports.Boolean
|
|
151506
|
+
});
|
|
151507
|
+
var DeleteAssociationParamsSchema = Schema_exports.Struct({
|
|
151508
|
+
association: AssociationIdentifier.annotations({
|
|
151509
|
+
description: "Association _id or unambiguous name returned by list_associations. Deleting a missing association is a successful no-op."
|
|
151510
|
+
})
|
|
151511
|
+
}).annotations({
|
|
151512
|
+
title: "DeleteAssociationParams",
|
|
151513
|
+
description: "Parameters for idempotently deleting a Huly association definition. The association must have zero concrete relations."
|
|
151514
|
+
});
|
|
151515
|
+
var DeleteAssociationResultSchema = Schema_exports.Struct({
|
|
151516
|
+
association: AssociationIdentifier,
|
|
151517
|
+
associationId: Schema_exports.optional(AssociationId),
|
|
151518
|
+
deleted: Schema_exports.Boolean,
|
|
151519
|
+
relationCount: Schema_exports.Number,
|
|
151520
|
+
reason: Schema_exports.optional(Schema_exports.Literal("not_found", "deleted"))
|
|
151521
|
+
});
|
|
151522
|
+
var ListRelationsParamsBaseSchema = Schema_exports.Struct({
|
|
151523
|
+
association: Schema_exports.optional(AssociationIdentifier.annotations({
|
|
151524
|
+
description: "Association _id or name. If omitted, relations are listed only across supported visible associations."
|
|
151525
|
+
})),
|
|
151526
|
+
source: Schema_exports.optional(GenericObjectLocatorSchema.annotations({
|
|
151527
|
+
description: "Optional source endpoint filter"
|
|
151528
|
+
})),
|
|
151529
|
+
target: Schema_exports.optional(GenericObjectLocatorSchema.annotations({
|
|
151530
|
+
description: "Optional target endpoint filter"
|
|
151531
|
+
})),
|
|
151532
|
+
direction: Schema_exports.optional(RelationDirectionSchema.annotations({
|
|
151533
|
+
description: relationDirectionDescription
|
|
151534
|
+
})),
|
|
151535
|
+
limit: Schema_exports.optional(LimitParam.annotations({
|
|
151536
|
+
description: "Maximum number of relations to return (default: 50)"
|
|
151537
|
+
}))
|
|
151538
|
+
}).annotations({
|
|
151539
|
+
title: "ListRelationsParams",
|
|
151540
|
+
description: "Parameters for listing concrete Huly relation instances"
|
|
151541
|
+
});
|
|
151542
|
+
var ListRelationsParamsSchema = ListRelationsParamsBaseSchema.pipe(
|
|
151543
|
+
Schema_exports.filter(
|
|
151544
|
+
(params) => params.association === void 0 && params.source === void 0 && params.target === void 0 ? "Provide at least one of association, source, or target to avoid broad workspace scans." : void 0
|
|
151545
|
+
)
|
|
151546
|
+
).annotations({
|
|
151547
|
+
title: "ListRelationsParams",
|
|
151548
|
+
description: "Parameters for listing concrete Huly relation instances"
|
|
151549
|
+
});
|
|
151550
|
+
var ListRelationsResultSchema = Schema_exports.Struct({
|
|
151551
|
+
relations: Schema_exports.Array(RelationSummarySchema),
|
|
151552
|
+
total: Schema_exports.Number,
|
|
151553
|
+
warnings: Schema_exports.optional(
|
|
151554
|
+
Schema_exports.NonEmptyArray(ListRelationsWarning).annotations({
|
|
151555
|
+
description: "Non-fatal warnings about result completeness or resolution. Treat these as guidance for narrowing a follow-up call."
|
|
151556
|
+
})
|
|
151557
|
+
)
|
|
151558
|
+
});
|
|
151559
|
+
var CreateRelationParamsSchema = Schema_exports.Struct({
|
|
151560
|
+
association: AssociationIdentifier.annotations({
|
|
151561
|
+
description: "Association _id or unambiguous name returned by list_associations"
|
|
151562
|
+
}),
|
|
151563
|
+
source: GenericObjectLocatorSchema.annotations({
|
|
151564
|
+
description: "Source endpoint document"
|
|
151565
|
+
}),
|
|
151566
|
+
target: GenericObjectLocatorSchema.annotations({
|
|
151567
|
+
description: "Target endpoint document"
|
|
151568
|
+
}),
|
|
151569
|
+
direction: Schema_exports.optional(RelationDirectionSchema.annotations({
|
|
151570
|
+
description: relationDirectionDescription
|
|
151571
|
+
})),
|
|
151572
|
+
ifExists: Schema_exports.optional(RelationIfExistsSchema.annotations({
|
|
151573
|
+
description: "return_existing (default) returns an existing relation; fail reports an existing relation as an error"
|
|
151574
|
+
}))
|
|
151575
|
+
}).annotations({
|
|
151576
|
+
title: "CreateRelationParams",
|
|
151577
|
+
description: "Parameters for idempotently creating a concrete generic relation"
|
|
151578
|
+
});
|
|
151579
|
+
var CreateRelationResultSchema = Schema_exports.Struct({
|
|
151580
|
+
relationId: RelationId,
|
|
151581
|
+
associationId: AssociationId,
|
|
151582
|
+
source: ResolvedObjectSummarySchema,
|
|
151583
|
+
target: ResolvedObjectSummarySchema,
|
|
151584
|
+
created: Schema_exports.Boolean,
|
|
151585
|
+
existing: Schema_exports.Boolean
|
|
151586
|
+
});
|
|
151587
|
+
var DeleteRelationByIdParamsSchema = Schema_exports.Struct({
|
|
151588
|
+
relation: RelationIdentifier.annotations({
|
|
151589
|
+
description: "Concrete relation _id to delete"
|
|
151590
|
+
})
|
|
151591
|
+
}).annotations({
|
|
151592
|
+
title: "DeleteRelationByIdParams",
|
|
151593
|
+
description: "Delete one concrete relation by its relation ID."
|
|
151594
|
+
});
|
|
151595
|
+
var DeleteRelationByTripleParamsSchema = Schema_exports.Struct({
|
|
151596
|
+
association: AssociationIdentifier.annotations({
|
|
151597
|
+
description: "Association _id or unambiguous name"
|
|
151598
|
+
}),
|
|
151599
|
+
source: GenericObjectLocatorSchema.annotations({
|
|
151600
|
+
description: "Source endpoint"
|
|
151601
|
+
}),
|
|
151602
|
+
target: GenericObjectLocatorSchema.annotations({
|
|
151603
|
+
description: "Target endpoint"
|
|
151604
|
+
}),
|
|
151605
|
+
direction: Schema_exports.optional(RelationDirectionSchema.annotations({
|
|
151606
|
+
description: relationDirectionDescription
|
|
151607
|
+
}))
|
|
151608
|
+
}).annotations({
|
|
151609
|
+
title: "DeleteRelationByTripleParams",
|
|
151610
|
+
description: "Delete one concrete relation by exact association + source + target triple."
|
|
151611
|
+
});
|
|
151612
|
+
var DeleteRelationParamsSchema = Schema_exports.Union(
|
|
151613
|
+
DeleteRelationByIdParamsSchema,
|
|
151614
|
+
DeleteRelationByTripleParamsSchema
|
|
151615
|
+
).annotations({
|
|
151616
|
+
title: "DeleteRelationParams",
|
|
151617
|
+
description: "Parameters for idempotently deleting one concrete generic relation. Provide either relation, or the full association + source + target triple."
|
|
151618
|
+
});
|
|
151619
|
+
var DeleteRelationResultSchema = Schema_exports.Struct({
|
|
151620
|
+
relationId: Schema_exports.optional(RelationId),
|
|
151621
|
+
associationId: Schema_exports.optional(AssociationId),
|
|
151622
|
+
deleted: Schema_exports.Boolean,
|
|
151623
|
+
reason: Schema_exports.optional(Schema_exports.Literal("not_found", "deleted"))
|
|
151624
|
+
});
|
|
151625
|
+
var listAssociationsParamsJsonSchema = JSONSchema_exports.make(ListAssociationsParamsSchema);
|
|
151626
|
+
var createAssociationParamsJsonSchema = JSONSchema_exports.make(CreateAssociationParamsSchema);
|
|
151627
|
+
var deleteAssociationParamsJsonSchema = JSONSchema_exports.make(DeleteAssociationParamsSchema);
|
|
151628
|
+
var listRelationsParamsJsonSchema = {
|
|
151629
|
+
...JSONSchema_exports.make(ListRelationsParamsBaseSchema),
|
|
151630
|
+
anyOf: [
|
|
151631
|
+
{ required: ["association"] },
|
|
151632
|
+
{ required: ["source"] },
|
|
151633
|
+
{ required: ["target"] }
|
|
151634
|
+
]
|
|
151635
|
+
};
|
|
151636
|
+
var createRelationParamsJsonSchema = JSONSchema_exports.make(CreateRelationParamsSchema);
|
|
151637
|
+
var deleteRelationParamsJsonSchema = {
|
|
151638
|
+
...JSONSchema_exports.make(DeleteRelationParamsSchema),
|
|
151639
|
+
type: "object"
|
|
151640
|
+
};
|
|
151641
|
+
var strictParseOptions = { onExcessProperty: "error" };
|
|
151642
|
+
var parseListAssociationsParams = Schema_exports.decodeUnknown(ListAssociationsParamsSchema, strictParseOptions);
|
|
151643
|
+
var parseCreateAssociationParams = Schema_exports.decodeUnknown(CreateAssociationParamsSchema, strictParseOptions);
|
|
151644
|
+
var parseDeleteAssociationParams = Schema_exports.decodeUnknown(DeleteAssociationParamsSchema, strictParseOptions);
|
|
151645
|
+
var parseListRelationsParams = Schema_exports.decodeUnknown(ListRelationsParamsSchema, strictParseOptions);
|
|
151646
|
+
var parseCreateRelationParams = Schema_exports.decodeUnknown(CreateRelationParamsSchema, strictParseOptions);
|
|
151647
|
+
var parseDeleteRelationParams = Schema_exports.decodeUnknown(DeleteRelationParamsSchema, strictParseOptions);
|
|
151648
|
+
|
|
151356
151649
|
// src/huly/errors-generic-associations.ts
|
|
151357
151650
|
var CandidateSchema = Schema_exports.Struct({
|
|
151358
151651
|
id: AssociationId,
|
|
151359
|
-
name: Schema_exports.optional(
|
|
151360
|
-
sourceClass: Schema_exports.optional(
|
|
151361
|
-
targetClass: Schema_exports.optional(
|
|
151652
|
+
name: Schema_exports.optional(AssociationName),
|
|
151653
|
+
sourceClass: Schema_exports.optional(ObjectClassName),
|
|
151654
|
+
targetClass: Schema_exports.optional(ObjectClassName)
|
|
151362
151655
|
});
|
|
151363
151656
|
var formatCandidates = (candidates) => candidates.map((candidate) => {
|
|
151364
151657
|
const name = candidate.name === void 0 ? "" : `${candidate.name} `;
|
|
@@ -151419,6 +151712,64 @@ var RelationMutationUnsupportedError = class extends Schema_exports.TaggedError(
|
|
|
151419
151712
|
return `Generic relation mutation${id} is not supported: ${this.reason}. Call list_associations with writableOnly=true to discover writable associations.`;
|
|
151420
151713
|
}
|
|
151421
151714
|
};
|
|
151715
|
+
var AssociationSystemClassUnsupportedError = class extends Schema_exports.TaggedError()(
|
|
151716
|
+
"AssociationSystemClassUnsupportedError",
|
|
151717
|
+
{
|
|
151718
|
+
className: ObjectClassName,
|
|
151719
|
+
operation: Schema_exports.Literal("create_association", "delete_association", "create_relation", "delete_relation")
|
|
151720
|
+
}
|
|
151721
|
+
) {
|
|
151722
|
+
get message() {
|
|
151723
|
+
return `${this.operation} does not support core system class '${this.className}' in generic association writes.`;
|
|
151724
|
+
}
|
|
151725
|
+
};
|
|
151726
|
+
var AssociationConflictError = class extends Schema_exports.TaggedError()(
|
|
151727
|
+
"AssociationConflictError",
|
|
151728
|
+
{
|
|
151729
|
+
associationId: AssociationId,
|
|
151730
|
+
reason: Schema_exports.String
|
|
151731
|
+
}
|
|
151732
|
+
) {
|
|
151733
|
+
get message() {
|
|
151734
|
+
return `Association '${this.associationId}' already exists but conflicts with the requested definition: ${this.reason}.`;
|
|
151735
|
+
}
|
|
151736
|
+
};
|
|
151737
|
+
var AssociationInUseError = class extends Schema_exports.TaggedError()(
|
|
151738
|
+
"AssociationInUseError",
|
|
151739
|
+
{
|
|
151740
|
+
associationId: AssociationId,
|
|
151741
|
+
relationCount: Schema_exports.Number,
|
|
151742
|
+
sampleRelationIds: Schema_exports.Array(RelationId)
|
|
151743
|
+
}
|
|
151744
|
+
) {
|
|
151745
|
+
get message() {
|
|
151746
|
+
const sample2 = this.sampleRelationIds.length === 0 ? "" : ` Sample relation IDs: ${this.sampleRelationIds.join(", ")}.`;
|
|
151747
|
+
return `Association '${this.associationId}' cannot be deleted because ${this.relationCount} relation(s) still reference it. Delete those relations first.${sample2}`;
|
|
151748
|
+
}
|
|
151749
|
+
};
|
|
151750
|
+
var RelationCardinalityViolationError = class extends Schema_exports.TaggedError()(
|
|
151751
|
+
"RelationCardinalityViolationError",
|
|
151752
|
+
{
|
|
151753
|
+
associationId: AssociationId,
|
|
151754
|
+
cardinality: CardinalitySchema,
|
|
151755
|
+
reason: Schema_exports.String
|
|
151756
|
+
}
|
|
151757
|
+
) {
|
|
151758
|
+
get message() {
|
|
151759
|
+
return `Relation violates ${this.cardinality} cardinality for association '${this.associationId}': ${this.reason}.`;
|
|
151760
|
+
}
|
|
151761
|
+
};
|
|
151762
|
+
var RelationDirectionAmbiguousError = class extends Schema_exports.TaggedError()(
|
|
151763
|
+
"RelationDirectionAmbiguousError",
|
|
151764
|
+
{
|
|
151765
|
+
associationId: AssociationId,
|
|
151766
|
+
reason: Schema_exports.String
|
|
151767
|
+
}
|
|
151768
|
+
) {
|
|
151769
|
+
get message() {
|
|
151770
|
+
return `Relation direction is ambiguous for association '${this.associationId}': ${this.reason}. Use source-to-target or target-to-source.`;
|
|
151771
|
+
}
|
|
151772
|
+
};
|
|
151422
151773
|
var RelationEndpointClassMismatchError = class extends Schema_exports.TaggedError()(
|
|
151423
151774
|
"RelationEndpointClassMismatchError",
|
|
151424
151775
|
{
|
|
@@ -152274,9 +152625,14 @@ var HulyDomainError = Schema_exports.Union(
|
|
|
152274
152625
|
ProcessExecutionNotCancellableError,
|
|
152275
152626
|
AssociationNotFoundError,
|
|
152276
152627
|
AssociationIdentifierAmbiguousError,
|
|
152628
|
+
AssociationSystemClassUnsupportedError,
|
|
152629
|
+
AssociationConflictError,
|
|
152630
|
+
AssociationInUseError,
|
|
152277
152631
|
RelationNotFoundError,
|
|
152278
152632
|
RelationIdentifierAmbiguousError,
|
|
152279
152633
|
RelationMutationUnsupportedError,
|
|
152634
|
+
RelationCardinalityViolationError,
|
|
152635
|
+
RelationDirectionAmbiguousError,
|
|
152280
152636
|
RelationEndpointClassMismatchError,
|
|
152281
152637
|
GenericObjectIdentifierAmbiguousError,
|
|
152282
152638
|
GenericObjectLocatorInvalidError,
|
|
@@ -172203,7 +172559,7 @@ var PostHog = class extends PostHogBackendClient {
|
|
|
172203
172559
|
};
|
|
172204
172560
|
|
|
172205
172561
|
// src/version.ts
|
|
172206
|
-
var VERSION = true ? "0.
|
|
172562
|
+
var VERSION = true ? "0.16.0" : "0.0.0-dev";
|
|
172207
172563
|
|
|
172208
172564
|
// src/telemetry/posthog.ts
|
|
172209
172565
|
var POSTHOG_API_KEY = "phc_TGfFqCGdnF0p68wuFzd5WSw1IsBvOJW0YgoMJDyZPjm";
|
|
@@ -172387,9 +172743,14 @@ var INVALID_PARAMS_TAGS = /* @__PURE__ */ new Set([
|
|
|
172387
172743
|
"ProcessCardNotFoundError",
|
|
172388
172744
|
"AssociationNotFoundError",
|
|
172389
172745
|
"AssociationIdentifierAmbiguousError",
|
|
172746
|
+
"AssociationSystemClassUnsupportedError",
|
|
172747
|
+
"AssociationConflictError",
|
|
172748
|
+
"AssociationInUseError",
|
|
172390
172749
|
"RelationNotFoundError",
|
|
172391
172750
|
"RelationIdentifierAmbiguousError",
|
|
172392
172751
|
"RelationMutationUnsupportedError",
|
|
172752
|
+
"RelationCardinalityViolationError",
|
|
172753
|
+
"RelationDirectionAmbiguousError",
|
|
172393
172754
|
"RelationEndpointClassMismatchError",
|
|
172394
172755
|
"GenericObjectIdentifierAmbiguousError",
|
|
172395
172756
|
"GenericObjectLocatorInvalidError",
|
|
@@ -172458,6 +172819,40 @@ var toMcpResponse = (response) => {
|
|
|
172458
172819
|
return wire;
|
|
172459
172820
|
};
|
|
172460
172821
|
|
|
172822
|
+
// src/mcp/input-schema-compat.ts
|
|
172823
|
+
var ROOT_COMPOSITION_KEYS = /* @__PURE__ */ new Set(["anyOf", "oneOf", "allOf"]);
|
|
172824
|
+
var isRecord2 = (value3) => typeof value3 === "object" && value3 !== null && !Array.isArray(value3);
|
|
172825
|
+
var isObjectSchema = (schema) => "type" in schema && schema.type === "object";
|
|
172826
|
+
var mergeObjectFields = (sources) => {
|
|
172827
|
+
const merged = sources.reduce(
|
|
172828
|
+
(acc, source) => isRecord2(source) ? { ...source, ...acc } : acc,
|
|
172829
|
+
{}
|
|
172830
|
+
);
|
|
172831
|
+
return Object.keys(merged).length > 0 ? merged : void 0;
|
|
172832
|
+
};
|
|
172833
|
+
var rootCompositionBranches = (schema) => [...ROOT_COMPOSITION_KEYS].flatMap((key) => {
|
|
172834
|
+
const branches = schema[key];
|
|
172835
|
+
return Array.isArray(branches) ? branches.filter(isRecord2) : [];
|
|
172836
|
+
});
|
|
172837
|
+
var schemaAndCompositionDescendants = (schema) => [
|
|
172838
|
+
schema,
|
|
172839
|
+
...rootCompositionBranches(schema).flatMap(schemaAndCompositionDescendants)
|
|
172840
|
+
];
|
|
172841
|
+
var mergedSchemaField = (schema, field) => mergeObjectFields(schemaAndCompositionDescendants(schema).map((branch) => branch[field]));
|
|
172842
|
+
var toClientCompatibleInputSchema = (schema) => {
|
|
172843
|
+
const rootFields = Object.fromEntries(
|
|
172844
|
+
Object.entries(schema).filter(([key]) => key !== "type" && !ROOT_COMPOSITION_KEYS.has(key))
|
|
172845
|
+
);
|
|
172846
|
+
const properties = mergedSchemaField(schema, "properties");
|
|
172847
|
+
const defs = mergedSchemaField(schema, "$defs");
|
|
172848
|
+
return {
|
|
172849
|
+
...rootFields,
|
|
172850
|
+
type: "object",
|
|
172851
|
+
...properties === void 0 ? {} : { properties },
|
|
172852
|
+
...defs === void 0 ? {} : { $defs: defs }
|
|
172853
|
+
};
|
|
172854
|
+
};
|
|
172855
|
+
|
|
172461
172856
|
// src/mcp/tool-output-schema.ts
|
|
172462
172857
|
var defaultToolOutputSchema = {
|
|
172463
172858
|
type: "object",
|
|
@@ -175928,242 +176323,6 @@ var calendarTools = [
|
|
|
175928
176323
|
}
|
|
175929
176324
|
];
|
|
175930
176325
|
|
|
175931
|
-
// src/domain/schemas/generic-associations.ts
|
|
175932
|
-
var AssociationIdentifier = NonEmptyString2.pipe(Schema_exports.brand("AssociationIdentifier"));
|
|
175933
|
-
var RelationIdentifier = NonEmptyString2.pipe(Schema_exports.brand("RelationIdentifier"));
|
|
175934
|
-
var ListRelationsWarning = NonEmptyString2.pipe(Schema_exports.brand("ListRelationsWarning"));
|
|
175935
|
-
var CardinalityValues = [
|
|
175936
|
-
"one-to-one",
|
|
175937
|
-
"one-to-many",
|
|
175938
|
-
"many-to-many"
|
|
175939
|
-
];
|
|
175940
|
-
var CardinalitySchema = Schema_exports.Literal(...CardinalityValues).annotations({
|
|
175941
|
-
description: `Association cardinality: ${enumValuesDescription(CardinalityValues)}`
|
|
175942
|
-
});
|
|
175943
|
-
var RelationDirectionValues = ["source-to-target", "target-to-source", "either"];
|
|
175944
|
-
var RelationDirectionSchema = Schema_exports.Literal(...RelationDirectionValues);
|
|
175945
|
-
var DefaultRelationDirection = "source-to-target";
|
|
175946
|
-
var relationDirectionDescription = `Relation traversal direction: ${enumValuesDescription(RelationDirectionValues)}. Defaults to ${DefaultRelationDirection}.`;
|
|
175947
|
-
var RelationIfExistsSchema = Schema_exports.Literal("return_existing", "fail");
|
|
175948
|
-
var RawObjectLocatorSchema = Schema_exports.Struct({
|
|
175949
|
-
kind: Schema_exports.Literal("raw"),
|
|
175950
|
-
id: DocId.annotations({
|
|
175951
|
-
description: "Raw Huly document _id"
|
|
175952
|
-
}),
|
|
175953
|
-
class: Schema_exports.optional(ObjectClassName.annotations({
|
|
175954
|
-
description: "Raw Huly document class, such as tracker:class:Issue. Required unless the association side determines the expected class."
|
|
175955
|
-
}))
|
|
175956
|
-
});
|
|
175957
|
-
var IssueObjectLocatorSchema = Schema_exports.Struct({
|
|
175958
|
-
kind: Schema_exports.Literal("issue"),
|
|
175959
|
-
issue: IssueIdentifier.annotations({
|
|
175960
|
-
description: "Issue identifier, such as HULY-123, or a numeric issue number when project is also provided."
|
|
175961
|
-
}),
|
|
175962
|
-
project: Schema_exports.optional(ProjectIdentifier.annotations({
|
|
175963
|
-
description: "Project identifier. Optional when issue already includes a project prefix like HULY-123."
|
|
175964
|
-
}))
|
|
175965
|
-
});
|
|
175966
|
-
var DocumentObjectLocatorSchema = Schema_exports.Struct({
|
|
175967
|
-
kind: Schema_exports.Literal("document"),
|
|
175968
|
-
document: DocumentIdentifier.annotations({
|
|
175969
|
-
description: "Document title or ID"
|
|
175970
|
-
}),
|
|
175971
|
-
teamspace: Schema_exports.optional(TeamspaceIdentifier.annotations({
|
|
175972
|
-
description: "Teamspace name or ID. If omitted, document title matches must be unique across the workspace."
|
|
175973
|
-
}))
|
|
175974
|
-
});
|
|
175975
|
-
var GenericObjectLocatorSchema = Schema_exports.Union(
|
|
175976
|
-
RawObjectLocatorSchema,
|
|
175977
|
-
IssueObjectLocatorSchema,
|
|
175978
|
-
DocumentObjectLocatorSchema
|
|
175979
|
-
).annotations({
|
|
175980
|
-
title: "GenericObjectLocator",
|
|
175981
|
-
description: "Explicit locator for a Huly document endpoint. Use raw for known _id values, issue for tracker issues, or document for Huly documents. Card locators are intentionally not included until a robust card resolver is available."
|
|
175982
|
-
});
|
|
175983
|
-
var ResolvedObjectSummarySchema = Schema_exports.Struct({
|
|
175984
|
-
id: DocId,
|
|
175985
|
-
class: ObjectClassName,
|
|
175986
|
-
display: NonEmptyString2,
|
|
175987
|
-
locatorKind: Schema_exports.Literal("raw", "issue", "document"),
|
|
175988
|
-
warning: Schema_exports.optional(Schema_exports.String)
|
|
175989
|
-
});
|
|
175990
|
-
var AssociationSummarySchema = Schema_exports.Struct({
|
|
175991
|
-
associationId: AssociationId,
|
|
175992
|
-
name: Schema_exports.optional(NonEmptyString2),
|
|
175993
|
-
label: Schema_exports.optional(NonEmptyString2),
|
|
175994
|
-
description: Schema_exports.optional(Schema_exports.String),
|
|
175995
|
-
sourceClass: ObjectClassName,
|
|
175996
|
-
sourceClassLabel: Schema_exports.optional(NonEmptyString2.annotations({
|
|
175997
|
-
description: "Best-effort human display label for sourceClass when the class is known to this server"
|
|
175998
|
-
})),
|
|
175999
|
-
targetClass: ObjectClassName,
|
|
176000
|
-
targetClassLabel: Schema_exports.optional(NonEmptyString2.annotations({
|
|
176001
|
-
description: "Best-effort human display label for targetClass when the class is known to this server"
|
|
176002
|
-
})),
|
|
176003
|
-
sourceRole: Schema_exports.optional(NonEmptyString2),
|
|
176004
|
-
targetRole: Schema_exports.optional(NonEmptyString2),
|
|
176005
|
-
relationClass: Schema_exports.optional(ObjectClassName),
|
|
176006
|
-
cardinality: CardinalitySchema,
|
|
176007
|
-
symmetric: Schema_exports.Boolean,
|
|
176008
|
-
system: Schema_exports.Boolean,
|
|
176009
|
-
canListRelations: Schema_exports.Boolean,
|
|
176010
|
-
canCreateRelation: Schema_exports.Boolean,
|
|
176011
|
-
canDeleteRelation: Schema_exports.Boolean,
|
|
176012
|
-
unsupportedReason: Schema_exports.optional(Schema_exports.String)
|
|
176013
|
-
});
|
|
176014
|
-
var RelationSummarySchema = Schema_exports.Struct({
|
|
176015
|
-
relationId: RelationId,
|
|
176016
|
-
associationId: AssociationId,
|
|
176017
|
-
associationName: Schema_exports.optional(NonEmptyString2),
|
|
176018
|
-
source: ResolvedObjectSummarySchema,
|
|
176019
|
-
target: ResolvedObjectSummarySchema,
|
|
176020
|
-
createdOn: Schema_exports.optional(Timestamp),
|
|
176021
|
-
modifiedOn: Schema_exports.optional(Timestamp)
|
|
176022
|
-
});
|
|
176023
|
-
var ListAssociationsParamsSchema = Schema_exports.Struct({
|
|
176024
|
-
association: Schema_exports.optional(AssociationIdentifier.annotations({
|
|
176025
|
-
description: "Association _id, source/target role name, or stable association name"
|
|
176026
|
-
})),
|
|
176027
|
-
sourceClass: Schema_exports.optional(ObjectClassName.annotations({
|
|
176028
|
-
description: "Only return associations whose source class matches this Huly class ID"
|
|
176029
|
-
})),
|
|
176030
|
-
targetClass: Schema_exports.optional(ObjectClassName.annotations({
|
|
176031
|
-
description: "Only return associations whose target class matches this Huly class ID"
|
|
176032
|
-
})),
|
|
176033
|
-
writableOnly: Schema_exports.optional(Schema_exports.Boolean.annotations({
|
|
176034
|
-
description: "Only return associations whose relation create/delete path has been validated and allowlisted"
|
|
176035
|
-
})),
|
|
176036
|
-
includeSystem: Schema_exports.optional(Schema_exports.Boolean.annotations({
|
|
176037
|
-
description: "Include internal/system associations. Defaults to false."
|
|
176038
|
-
})),
|
|
176039
|
-
limit: Schema_exports.optional(LimitParam.annotations({
|
|
176040
|
-
description: "Maximum number of associations to return (default: 50)"
|
|
176041
|
-
}))
|
|
176042
|
-
}).annotations({
|
|
176043
|
-
title: "ListAssociationsParams",
|
|
176044
|
-
description: "Parameters for listing generic Huly association definitions"
|
|
176045
|
-
});
|
|
176046
|
-
var ListAssociationsResultSchema = Schema_exports.Struct({
|
|
176047
|
-
associations: Schema_exports.Array(AssociationSummarySchema),
|
|
176048
|
-
total: Schema_exports.Number
|
|
176049
|
-
});
|
|
176050
|
-
var ListRelationsParamsBaseSchema = Schema_exports.Struct({
|
|
176051
|
-
association: Schema_exports.optional(AssociationIdentifier.annotations({
|
|
176052
|
-
description: "Association _id or name. If omitted, relations are listed only across supported visible associations."
|
|
176053
|
-
})),
|
|
176054
|
-
source: Schema_exports.optional(GenericObjectLocatorSchema.annotations({
|
|
176055
|
-
description: "Optional source endpoint filter"
|
|
176056
|
-
})),
|
|
176057
|
-
target: Schema_exports.optional(GenericObjectLocatorSchema.annotations({
|
|
176058
|
-
description: "Optional target endpoint filter"
|
|
176059
|
-
})),
|
|
176060
|
-
direction: Schema_exports.optional(RelationDirectionSchema.annotations({
|
|
176061
|
-
description: relationDirectionDescription
|
|
176062
|
-
})),
|
|
176063
|
-
limit: Schema_exports.optional(LimitParam.annotations({
|
|
176064
|
-
description: "Maximum number of relations to return (default: 50)"
|
|
176065
|
-
}))
|
|
176066
|
-
}).annotations({
|
|
176067
|
-
title: "ListRelationsParams",
|
|
176068
|
-
description: "Parameters for listing concrete Huly relation instances"
|
|
176069
|
-
});
|
|
176070
|
-
var ListRelationsParamsSchema = ListRelationsParamsBaseSchema.pipe(
|
|
176071
|
-
Schema_exports.filter(
|
|
176072
|
-
(params) => params.association === void 0 && params.source === void 0 && params.target === void 0 ? "Provide at least one of association, source, or target to avoid broad workspace scans." : void 0
|
|
176073
|
-
)
|
|
176074
|
-
).annotations({
|
|
176075
|
-
title: "ListRelationsParams",
|
|
176076
|
-
description: "Parameters for listing concrete Huly relation instances"
|
|
176077
|
-
});
|
|
176078
|
-
var ListRelationsResultSchema = Schema_exports.Struct({
|
|
176079
|
-
relations: Schema_exports.Array(RelationSummarySchema),
|
|
176080
|
-
total: Schema_exports.Number,
|
|
176081
|
-
warnings: Schema_exports.optional(
|
|
176082
|
-
Schema_exports.NonEmptyArray(ListRelationsWarning).annotations({
|
|
176083
|
-
description: "Non-fatal warnings about result completeness or resolution. Treat these as guidance for narrowing a follow-up call."
|
|
176084
|
-
})
|
|
176085
|
-
)
|
|
176086
|
-
});
|
|
176087
|
-
var CreateRelationParamsSchema = Schema_exports.Struct({
|
|
176088
|
-
association: AssociationIdentifier.annotations({
|
|
176089
|
-
description: "Association _id or unambiguous name returned by list_associations"
|
|
176090
|
-
}),
|
|
176091
|
-
source: GenericObjectLocatorSchema.annotations({
|
|
176092
|
-
description: "Source endpoint document"
|
|
176093
|
-
}),
|
|
176094
|
-
target: GenericObjectLocatorSchema.annotations({
|
|
176095
|
-
description: "Target endpoint document"
|
|
176096
|
-
}),
|
|
176097
|
-
ifExists: Schema_exports.optional(RelationIfExistsSchema.annotations({
|
|
176098
|
-
description: "return_existing (default) returns an existing relation; fail reports an existing relation as an error"
|
|
176099
|
-
}))
|
|
176100
|
-
}).annotations({
|
|
176101
|
-
title: "CreateRelationParams",
|
|
176102
|
-
description: "Parameters for idempotently creating a concrete generic relation"
|
|
176103
|
-
});
|
|
176104
|
-
var CreateRelationResultSchema = Schema_exports.Struct({
|
|
176105
|
-
relationId: RelationId,
|
|
176106
|
-
associationId: AssociationId,
|
|
176107
|
-
source: ResolvedObjectSummarySchema,
|
|
176108
|
-
target: ResolvedObjectSummarySchema,
|
|
176109
|
-
created: Schema_exports.Boolean,
|
|
176110
|
-
existing: Schema_exports.Boolean
|
|
176111
|
-
});
|
|
176112
|
-
var DeleteRelationByIdParamsSchema = Schema_exports.Struct({
|
|
176113
|
-
relation: RelationIdentifier.annotations({
|
|
176114
|
-
description: "Concrete relation _id to delete"
|
|
176115
|
-
})
|
|
176116
|
-
}).annotations({
|
|
176117
|
-
title: "DeleteRelationByIdParams",
|
|
176118
|
-
description: "Delete one concrete relation by its relation ID."
|
|
176119
|
-
});
|
|
176120
|
-
var DeleteRelationByTripleParamsSchema = Schema_exports.Struct({
|
|
176121
|
-
association: AssociationIdentifier.annotations({
|
|
176122
|
-
description: "Association _id or unambiguous name"
|
|
176123
|
-
}),
|
|
176124
|
-
source: GenericObjectLocatorSchema.annotations({
|
|
176125
|
-
description: "Source endpoint"
|
|
176126
|
-
}),
|
|
176127
|
-
target: GenericObjectLocatorSchema.annotations({
|
|
176128
|
-
description: "Target endpoint"
|
|
176129
|
-
})
|
|
176130
|
-
}).annotations({
|
|
176131
|
-
title: "DeleteRelationByTripleParams",
|
|
176132
|
-
description: "Delete one concrete relation by exact association + source + target triple."
|
|
176133
|
-
});
|
|
176134
|
-
var DeleteRelationParamsSchema = Schema_exports.Union(
|
|
176135
|
-
DeleteRelationByIdParamsSchema,
|
|
176136
|
-
DeleteRelationByTripleParamsSchema
|
|
176137
|
-
).annotations({
|
|
176138
|
-
title: "DeleteRelationParams",
|
|
176139
|
-
description: "Parameters for idempotently deleting one concrete generic relation. Provide either relation, or the full association + source + target triple."
|
|
176140
|
-
});
|
|
176141
|
-
var DeleteRelationResultSchema = Schema_exports.Struct({
|
|
176142
|
-
relationId: Schema_exports.optional(RelationId),
|
|
176143
|
-
associationId: Schema_exports.optional(AssociationId),
|
|
176144
|
-
deleted: Schema_exports.Boolean,
|
|
176145
|
-
reason: Schema_exports.optional(Schema_exports.Literal("not_found", "deleted"))
|
|
176146
|
-
});
|
|
176147
|
-
var listAssociationsParamsJsonSchema = JSONSchema_exports.make(ListAssociationsParamsSchema);
|
|
176148
|
-
var listRelationsParamsJsonSchema = {
|
|
176149
|
-
...JSONSchema_exports.make(ListRelationsParamsBaseSchema),
|
|
176150
|
-
anyOf: [
|
|
176151
|
-
{ required: ["association"] },
|
|
176152
|
-
{ required: ["source"] },
|
|
176153
|
-
{ required: ["target"] }
|
|
176154
|
-
]
|
|
176155
|
-
};
|
|
176156
|
-
var createRelationParamsJsonSchema = JSONSchema_exports.make(CreateRelationParamsSchema);
|
|
176157
|
-
var deleteRelationParamsJsonSchema = {
|
|
176158
|
-
...JSONSchema_exports.make(DeleteRelationParamsSchema),
|
|
176159
|
-
type: "object"
|
|
176160
|
-
};
|
|
176161
|
-
var strictParseOptions = { onExcessProperty: "error" };
|
|
176162
|
-
var parseListAssociationsParams = Schema_exports.decodeUnknown(ListAssociationsParamsSchema, strictParseOptions);
|
|
176163
|
-
var parseListRelationsParams = Schema_exports.decodeUnknown(ListRelationsParamsSchema, strictParseOptions);
|
|
176164
|
-
var parseCreateRelationParams = Schema_exports.decodeUnknown(CreateRelationParamsSchema, strictParseOptions);
|
|
176165
|
-
var parseDeleteRelationParams = Schema_exports.decodeUnknown(DeleteRelationParamsSchema, strictParseOptions);
|
|
176166
|
-
|
|
176167
176326
|
// src/domain/schemas/projects.ts
|
|
176168
176327
|
var ProjectSummarySchema = Schema_exports.Struct({
|
|
176169
176328
|
identifier: ProjectIdentifier,
|
|
@@ -182081,7 +182240,6 @@ var documentTools = [
|
|
|
182081
182240
|
|
|
182082
182241
|
// src/huly/operations/generic-associations.ts
|
|
182083
182242
|
var import_core35 = __toESM(require_lib4(), 1);
|
|
182084
|
-
var WRITE_UNSUPPORTED_REASON = "no generic association relation write path has been live-validated for this workspace";
|
|
182085
182243
|
var ASSOCIATION_DISCOVERY_LIMIT = 200;
|
|
182086
182244
|
var ASSOCIATION_DISCOVERY_LIMIT_WARNING = ListRelationsWarning.make(
|
|
182087
182245
|
`Association discovery reached the local ${ASSOCIATION_DISCOVERY_LIMIT}-association cap for at least one endpoint orientation. Huly did not indicate whether more matching associations exist, so list_relations may omit older matching associations; pass a specific association from list_associations to avoid this discovery cap.`
|
|
@@ -182097,8 +182255,7 @@ var VISIBLE_ASSOCIATION_FILTERS = {
|
|
|
182097
182255
|
sourceClass: void 0,
|
|
182098
182256
|
targetClass: void 0
|
|
182099
182257
|
};
|
|
182100
|
-
var associationName = (association) => association.nameA === association.nameB ? association.nameA : `${association.nameA} -> ${association.nameB}
|
|
182101
|
-
var optionalNonEmpty = (value3) => value3 === void 0 ? void 0 : NonEmptyString2.make(value3);
|
|
182258
|
+
var associationName = (association) => association.nameA === association.nameB ? AssociationName.make(association.nameA) : AssociationName.make(`${association.nameA} -> ${association.nameB}`);
|
|
182102
182259
|
var classLabelEntry = (classRef2, label) => [
|
|
182103
182260
|
ObjectClassName.make(classRef2),
|
|
182104
182261
|
NonEmptyString2.make(label)
|
|
@@ -182116,7 +182273,19 @@ var KNOWN_CLASS_LABELS = new Map([
|
|
|
182116
182273
|
classLabelEntry(tracker.class.Milestone, "Milestone")
|
|
182117
182274
|
]);
|
|
182118
182275
|
var classLabel = (classRef2) => KNOWN_CLASS_LABELS.get(classRef2);
|
|
182119
|
-
var
|
|
182276
|
+
var isSystemClassName = (className) => className.startsWith("core:class:");
|
|
182277
|
+
var isSystemAssociation = (association) => isSystemClassName(String(association.classA)) || isSystemClassName(String(association.classB));
|
|
182278
|
+
var associationAutomationOnly = (association) => association.automationOnly === true;
|
|
182279
|
+
var relationWriteUnsupportedReason = (association) => {
|
|
182280
|
+
if (isSystemAssociation(association)) {
|
|
182281
|
+
return "association uses a core:class:* system class";
|
|
182282
|
+
}
|
|
182283
|
+
if (associationAutomationOnly(association)) {
|
|
182284
|
+
return "association is automation-only";
|
|
182285
|
+
}
|
|
182286
|
+
return void 0;
|
|
182287
|
+
};
|
|
182288
|
+
var isRelationWritableAssociation = (association) => relationWriteUnsupportedReason(association) === void 0;
|
|
182120
182289
|
var isSymmetric = (association) => association.classA === association.classB && association.nameA === association.nameB;
|
|
182121
182290
|
var ASSOCIATION_CARDINALITY = {
|
|
182122
182291
|
"1:1": "one-to-one",
|
|
@@ -182126,33 +182295,39 @@ var ASSOCIATION_CARDINALITY = {
|
|
|
182126
182295
|
var exactCardinalityMapping = (value3) => value3;
|
|
182127
182296
|
exactCardinalityMapping(true);
|
|
182128
182297
|
var cardinality = (type) => ASSOCIATION_CARDINALITY[type];
|
|
182298
|
+
var SDK_CARDINALITY = {
|
|
182299
|
+
"one-to-one": "1:1",
|
|
182300
|
+
"one-to-many": "1:N",
|
|
182301
|
+
"many-to-many": "N:N"
|
|
182302
|
+
};
|
|
182129
182303
|
var toAssociationSummary = (association) => {
|
|
182130
182304
|
const sourceClass = ObjectClassName.make(association.classA);
|
|
182131
182305
|
const targetClass = ObjectClassName.make(association.classB);
|
|
182306
|
+
const unsupportedReason = relationWriteUnsupportedReason(association);
|
|
182132
182307
|
return {
|
|
182133
182308
|
associationId: AssociationId.make(association._id),
|
|
182134
|
-
name:
|
|
182309
|
+
name: associationName(association),
|
|
182135
182310
|
sourceClass,
|
|
182136
182311
|
sourceClassLabel: classLabel(sourceClass),
|
|
182137
182312
|
targetClass,
|
|
182138
182313
|
targetClassLabel: classLabel(targetClass),
|
|
182139
|
-
sourceRole:
|
|
182140
|
-
targetRole:
|
|
182314
|
+
sourceRole: AssociationRoleName.make(association.nameA),
|
|
182315
|
+
targetRole: AssociationRoleName.make(association.nameB),
|
|
182141
182316
|
relationClass: ObjectClassName.make(core.class.Relation),
|
|
182142
182317
|
cardinality: cardinality(association.type),
|
|
182143
182318
|
symmetric: isSymmetric(association),
|
|
182144
182319
|
system: isSystemAssociation(association),
|
|
182145
182320
|
canListRelations: true,
|
|
182146
|
-
canCreateRelation:
|
|
182147
|
-
canDeleteRelation:
|
|
182148
|
-
unsupportedReason:
|
|
182321
|
+
canCreateRelation: unsupportedReason === void 0,
|
|
182322
|
+
canDeleteRelation: unsupportedReason === void 0,
|
|
182323
|
+
...unsupportedReason === void 0 ? {} : { unsupportedReason }
|
|
182149
182324
|
};
|
|
182150
182325
|
};
|
|
182151
182326
|
var toCandidate = (association) => ({
|
|
182152
182327
|
id: AssociationId.make(association._id),
|
|
182153
182328
|
name: associationName(association),
|
|
182154
|
-
sourceClass: association.classA,
|
|
182155
|
-
targetClass: association.classB
|
|
182329
|
+
sourceClass: ObjectClassName.make(association.classA),
|
|
182330
|
+
targetClass: ObjectClassName.make(association.classB)
|
|
182156
182331
|
});
|
|
182157
182332
|
var matchesAssociationIdentifier = (association, identifier2) => {
|
|
182158
182333
|
const normalized = identifier2.trim().toLowerCase();
|
|
@@ -182169,7 +182344,7 @@ var associationListFiltersFromParams = (params) => ({
|
|
|
182169
182344
|
});
|
|
182170
182345
|
var associationMatchesFilters = (association, filters) => (filters.includeSystem || !isSystemAssociation(association)) && (filters.sourceClass === void 0 || association.classA === String(filters.sourceClass)) && (filters.targetClass === void 0 || association.classB === String(filters.targetClass));
|
|
182171
182346
|
var filterVisible = (associations, filters) => associations.filter(
|
|
182172
|
-
(association) => associationMatchesFilters(association, filters) && !filters.writableOnly
|
|
182347
|
+
(association) => associationMatchesFilters(association, filters) && (!filters.writableOnly || isRelationWritableAssociation(association))
|
|
182173
182348
|
);
|
|
182174
182349
|
var listAssociationDocs = (client, params) => {
|
|
182175
182350
|
const query = {};
|
|
@@ -182266,6 +182441,155 @@ var resolveAssociation = (client, identifier2, filters) => Effect_exports.gen(fu
|
|
|
182266
182441
|
}
|
|
182267
182442
|
return candidates[0];
|
|
182268
182443
|
});
|
|
182444
|
+
var rejectSystemClass = (className, operation) => isSystemClassName(String(className)) ? Effect_exports.fail(new AssociationSystemClassUnsupportedError({ className, operation })) : Effect_exports.void;
|
|
182445
|
+
var systemClassInAssociation = (association) => {
|
|
182446
|
+
if (isSystemClassName(String(association.classA))) {
|
|
182447
|
+
return ObjectClassName.make(association.classA);
|
|
182448
|
+
}
|
|
182449
|
+
if (isSystemClassName(String(association.classB))) {
|
|
182450
|
+
return ObjectClassName.make(association.classB);
|
|
182451
|
+
}
|
|
182452
|
+
return void 0;
|
|
182453
|
+
};
|
|
182454
|
+
var ensureRelationMutationSupported = (association, operation) => {
|
|
182455
|
+
const systemClass = systemClassInAssociation(association);
|
|
182456
|
+
if (systemClass !== void 0) {
|
|
182457
|
+
return Effect_exports.fail(new AssociationSystemClassUnsupportedError({ className: systemClass, operation }));
|
|
182458
|
+
}
|
|
182459
|
+
if (associationAutomationOnly(association)) {
|
|
182460
|
+
return Effect_exports.fail(
|
|
182461
|
+
new RelationMutationUnsupportedError({
|
|
182462
|
+
associationId: AssociationId.make(association._id),
|
|
182463
|
+
reason: "association is automation-only"
|
|
182464
|
+
})
|
|
182465
|
+
);
|
|
182466
|
+
}
|
|
182467
|
+
return Effect_exports.void;
|
|
182468
|
+
};
|
|
182469
|
+
var exactAssociationQuery = (params) => ({
|
|
182470
|
+
classA: toClassRef(params.sourceClass),
|
|
182471
|
+
classB: toClassRef(params.targetClass),
|
|
182472
|
+
nameA: params.sourceRole,
|
|
182473
|
+
nameB: params.targetRole
|
|
182474
|
+
});
|
|
182475
|
+
var createdAssociationSummaryInput = (id, params) => ({
|
|
182476
|
+
_id: id,
|
|
182477
|
+
classA: toClassRef(params.sourceClass),
|
|
182478
|
+
classB: toClassRef(params.targetClass),
|
|
182479
|
+
nameA: params.sourceRole,
|
|
182480
|
+
nameB: params.targetRole,
|
|
182481
|
+
type: SDK_CARDINALITY[params.cardinality],
|
|
182482
|
+
automationOnly: params.automationOnly ?? false
|
|
182483
|
+
});
|
|
182484
|
+
var createAssociation = (params) => Effect_exports.gen(function* () {
|
|
182485
|
+
const client = yield* HulyClient;
|
|
182486
|
+
yield* rejectSystemClass(params.sourceClass, "create_association");
|
|
182487
|
+
yield* rejectSystemClass(params.targetClass, "create_association");
|
|
182488
|
+
const existing = yield* client.findOne(
|
|
182489
|
+
core.class.Association,
|
|
182490
|
+
hulyQuery(exactAssociationQuery(params))
|
|
182491
|
+
);
|
|
182492
|
+
if (existing !== void 0) {
|
|
182493
|
+
if (params.ifExists === "fail") {
|
|
182494
|
+
return yield* new AssociationConflictError({
|
|
182495
|
+
associationId: AssociationId.make(existing._id),
|
|
182496
|
+
reason: "ifExists=fail was requested"
|
|
182497
|
+
});
|
|
182498
|
+
}
|
|
182499
|
+
if (cardinality(existing.type) !== params.cardinality) {
|
|
182500
|
+
return yield* new AssociationConflictError({
|
|
182501
|
+
associationId: AssociationId.make(existing._id),
|
|
182502
|
+
reason: `existing cardinality is ${cardinality(existing.type)}, requested ${params.cardinality}`
|
|
182503
|
+
});
|
|
182504
|
+
}
|
|
182505
|
+
if (associationAutomationOnly(existing) !== (params.automationOnly ?? false)) {
|
|
182506
|
+
return yield* new AssociationConflictError({
|
|
182507
|
+
associationId: AssociationId.make(existing._id),
|
|
182508
|
+
reason: `existing automationOnly is ${associationAutomationOnly(existing)}, requested ${params.automationOnly ?? false}`
|
|
182509
|
+
});
|
|
182510
|
+
}
|
|
182511
|
+
return {
|
|
182512
|
+
association: toAssociationSummary(existing),
|
|
182513
|
+
created: false,
|
|
182514
|
+
existing: true
|
|
182515
|
+
};
|
|
182516
|
+
}
|
|
182517
|
+
const attributes = {
|
|
182518
|
+
classA: toClassRef(params.sourceClass),
|
|
182519
|
+
classB: toClassRef(params.targetClass),
|
|
182520
|
+
nameA: params.sourceRole,
|
|
182521
|
+
nameB: params.targetRole,
|
|
182522
|
+
type: SDK_CARDINALITY[params.cardinality],
|
|
182523
|
+
automationOnly: params.automationOnly ?? false
|
|
182524
|
+
};
|
|
182525
|
+
const associationId = yield* client.createDoc(
|
|
182526
|
+
core.class.Association,
|
|
182527
|
+
toRef(core.space.Model),
|
|
182528
|
+
attributes
|
|
182529
|
+
);
|
|
182530
|
+
return {
|
|
182531
|
+
association: toAssociationSummary(createdAssociationSummaryInput(associationId, params)),
|
|
182532
|
+
created: true,
|
|
182533
|
+
existing: false
|
|
182534
|
+
};
|
|
182535
|
+
});
|
|
182536
|
+
var ensureAssociationDeletionSupported = (association) => {
|
|
182537
|
+
const systemClass = systemClassInAssociation(association);
|
|
182538
|
+
return systemClass === void 0 ? Effect_exports.void : Effect_exports.fail(
|
|
182539
|
+
new AssociationSystemClassUnsupportedError({
|
|
182540
|
+
className: systemClass,
|
|
182541
|
+
operation: "delete_association"
|
|
182542
|
+
})
|
|
182543
|
+
);
|
|
182544
|
+
};
|
|
182545
|
+
var countAssociationRelations = (client, association) => Effect_exports.map(
|
|
182546
|
+
client.findAll(
|
|
182547
|
+
core.class.Relation,
|
|
182548
|
+
hulyQuery({
|
|
182549
|
+
association: toRef(association._id)
|
|
182550
|
+
}),
|
|
182551
|
+
{ limit: 5 }
|
|
182552
|
+
),
|
|
182553
|
+
(relations) => ({
|
|
182554
|
+
total: Math.max(relations.total, relations.length),
|
|
182555
|
+
sampleRelationIds: relations.map((relation) => RelationId.make(relation._id))
|
|
182556
|
+
})
|
|
182557
|
+
);
|
|
182558
|
+
var deleteAssociation = (params) => Effect_exports.gen(function* () {
|
|
182559
|
+
const client = yield* HulyClient;
|
|
182560
|
+
const association = yield* resolveAssociation(
|
|
182561
|
+
client,
|
|
182562
|
+
params.association,
|
|
182563
|
+
MUTATION_ASSOCIATION_FILTERS
|
|
182564
|
+
).pipe(
|
|
182565
|
+
Effect_exports.catchTag("AssociationNotFoundError", () => Effect_exports.succeed(void 0))
|
|
182566
|
+
);
|
|
182567
|
+
if (association === void 0) {
|
|
182568
|
+
return {
|
|
182569
|
+
association: params.association,
|
|
182570
|
+
deleted: false,
|
|
182571
|
+
relationCount: 0,
|
|
182572
|
+
reason: "not_found"
|
|
182573
|
+
};
|
|
182574
|
+
}
|
|
182575
|
+
yield* ensureAssociationDeletionSupported(association);
|
|
182576
|
+
const relationUsage = yield* countAssociationRelations(client, association);
|
|
182577
|
+
if (relationUsage.total > 0) {
|
|
182578
|
+
return yield* new AssociationInUseError({
|
|
182579
|
+
associationId: AssociationId.make(association._id),
|
|
182580
|
+
relationCount: relationUsage.total,
|
|
182581
|
+
sampleRelationIds: relationUsage.sampleRelationIds
|
|
182582
|
+
});
|
|
182583
|
+
}
|
|
182584
|
+
yield* client.removeDoc(core.class.Association, association.space, association._id);
|
|
182585
|
+
return {
|
|
182586
|
+
association: params.association,
|
|
182587
|
+
associationId: AssociationId.make(association._id),
|
|
182588
|
+
deleted: true,
|
|
182589
|
+
relationCount: 0,
|
|
182590
|
+
reason: "deleted"
|
|
182591
|
+
};
|
|
182592
|
+
});
|
|
182269
182593
|
var listAssociations = (params) => Effect_exports.gen(function* () {
|
|
182270
182594
|
const client = yield* HulyClient;
|
|
182271
182595
|
if (params.association !== void 0) {
|
|
@@ -182480,7 +182804,7 @@ var resolveRelationEndpointFromCache = (docsByClass, id, className) => {
|
|
|
182480
182804
|
var relationToSummary = (association, relation, docsByClass) => ({
|
|
182481
182805
|
relationId: RelationId.make(relation._id),
|
|
182482
182806
|
associationId: AssociationId.make(association._id),
|
|
182483
|
-
associationName:
|
|
182807
|
+
associationName: associationName(association),
|
|
182484
182808
|
source: resolveRelationEndpointFromCache(docsByClass, relation.docA, association.classA),
|
|
182485
182809
|
target: resolveRelationEndpointFromCache(docsByClass, relation.docB, association.classB),
|
|
182486
182810
|
createdOn: relation.createdOn,
|
|
@@ -182718,21 +183042,182 @@ var listRelations = (params) => Effect_exports.gen(function* () {
|
|
|
182718
183042
|
total: summaries.length
|
|
182719
183043
|
};
|
|
182720
183044
|
});
|
|
183045
|
+
var resolveRelationWriteEndpoints = (client, association, params) => Effect_exports.gen(function* () {
|
|
183046
|
+
const direction = params.direction ?? DefaultRelationDirection;
|
|
183047
|
+
if (direction === "source-to-target") {
|
|
183048
|
+
const source2 = yield* resolveGenericObject(client, params.source, association.classA, "source");
|
|
183049
|
+
const target2 = yield* resolveGenericObject(client, params.target, association.classB, "target");
|
|
183050
|
+
return { docA: source2, docB: target2, source: source2, target: target2 };
|
|
183051
|
+
}
|
|
183052
|
+
if (direction === "target-to-source") {
|
|
183053
|
+
const source2 = yield* resolveGenericObject(client, params.source, association.classB, "source");
|
|
183054
|
+
const target2 = yield* resolveGenericObject(client, params.target, association.classA, "target");
|
|
183055
|
+
return { docA: target2, docB: source2, source: source2, target: target2 };
|
|
183056
|
+
}
|
|
183057
|
+
const source = yield* resolveGenericObject(client, params.source, void 0, "source");
|
|
183058
|
+
const target = yield* resolveGenericObject(client, params.target, void 0, "target");
|
|
183059
|
+
const matchesForward = String(source.class) === association.classA && String(target.class) === association.classB;
|
|
183060
|
+
const matchesReverse = String(source.class) === association.classB && String(target.class) === association.classA;
|
|
183061
|
+
if (matchesForward && matchesReverse) {
|
|
183062
|
+
return yield* new RelationDirectionAmbiguousError({
|
|
183063
|
+
associationId: AssociationId.make(association._id),
|
|
183064
|
+
reason: "both endpoints match both sides of the association"
|
|
183065
|
+
});
|
|
183066
|
+
}
|
|
183067
|
+
if (matchesForward) {
|
|
183068
|
+
return { docA: source, docB: target, source, target };
|
|
183069
|
+
}
|
|
183070
|
+
if (matchesReverse) {
|
|
183071
|
+
return { docA: target, docB: source, source, target };
|
|
183072
|
+
}
|
|
183073
|
+
yield* validateEitherEndpointClasses(association, source, target);
|
|
183074
|
+
return yield* new RelationEndpointClassMismatchError({
|
|
183075
|
+
field: "source",
|
|
183076
|
+
expectedClass: `${association.classA} or ${association.classB}`,
|
|
183077
|
+
actualClass: source.class
|
|
183078
|
+
});
|
|
183079
|
+
});
|
|
183080
|
+
var exactRelationQuery = (association, endpoints) => ({
|
|
183081
|
+
association: toRef(association._id),
|
|
183082
|
+
docA: toRef(endpoints.docA.id),
|
|
183083
|
+
docB: toRef(endpoints.docB.id)
|
|
183084
|
+
});
|
|
183085
|
+
var findExactRelations = (client, association, endpoints, limit) => Effect_exports.map(
|
|
183086
|
+
client.findAll(
|
|
183087
|
+
core.class.Relation,
|
|
183088
|
+
hulyQuery(exactRelationQuery(association, endpoints)),
|
|
183089
|
+
{ limit }
|
|
183090
|
+
),
|
|
183091
|
+
(relations) => [...relations]
|
|
183092
|
+
);
|
|
183093
|
+
var findCardinalityConflict = (client, association, endpoints) => Effect_exports.gen(function* () {
|
|
183094
|
+
if (association.type === "N:N") {
|
|
183095
|
+
return void 0;
|
|
183096
|
+
}
|
|
183097
|
+
const docBConflict = yield* client.findOne(
|
|
183098
|
+
core.class.Relation,
|
|
183099
|
+
hulyQuery({
|
|
183100
|
+
association: toRef(association._id),
|
|
183101
|
+
docB: toRef(endpoints.docB.id)
|
|
183102
|
+
})
|
|
183103
|
+
);
|
|
183104
|
+
if (docBConflict !== void 0) {
|
|
183105
|
+
return docBConflict;
|
|
183106
|
+
}
|
|
183107
|
+
if (association.type === "1:1") {
|
|
183108
|
+
return yield* client.findOne(
|
|
183109
|
+
core.class.Relation,
|
|
183110
|
+
hulyQuery({
|
|
183111
|
+
association: toRef(association._id),
|
|
183112
|
+
docA: toRef(endpoints.docA.id)
|
|
183113
|
+
})
|
|
183114
|
+
);
|
|
183115
|
+
}
|
|
183116
|
+
return void 0;
|
|
183117
|
+
});
|
|
183118
|
+
var enforceCardinality = (client, association, endpoints) => Effect_exports.gen(function* () {
|
|
183119
|
+
const conflict = yield* findCardinalityConflict(client, association, endpoints);
|
|
183120
|
+
if (conflict === void 0) {
|
|
183121
|
+
return;
|
|
183122
|
+
}
|
|
183123
|
+
const reason = association.type === "1:1" ? "one-to-one associations allow each endpoint to appear in only one relation" : "one-to-many associations allow each target-side endpoint to appear in only one relation";
|
|
183124
|
+
return yield* new RelationCardinalityViolationError({
|
|
183125
|
+
associationId: AssociationId.make(association._id),
|
|
183126
|
+
cardinality: cardinality(association.type),
|
|
183127
|
+
reason
|
|
183128
|
+
});
|
|
183129
|
+
});
|
|
182721
183130
|
var createRelation = (params) => Effect_exports.gen(function* () {
|
|
182722
183131
|
const client = yield* HulyClient;
|
|
182723
183132
|
const association = yield* resolveAssociation(client, params.association, MUTATION_ASSOCIATION_FILTERS);
|
|
182724
|
-
|
|
183133
|
+
yield* ensureRelationMutationSupported(association, "create_relation");
|
|
183134
|
+
const endpoints = yield* resolveRelationWriteEndpoints(client, association, params);
|
|
183135
|
+
const exact = yield* findExactRelations(client, association, endpoints, 1);
|
|
183136
|
+
const existing = exact.at(0);
|
|
183137
|
+
if (existing !== void 0) {
|
|
183138
|
+
if (params.ifExists === "fail") {
|
|
183139
|
+
return yield* new RelationCardinalityViolationError({
|
|
183140
|
+
associationId: AssociationId.make(association._id),
|
|
183141
|
+
cardinality: cardinality(association.type),
|
|
183142
|
+
reason: `relation '${existing._id}' already exists`
|
|
183143
|
+
});
|
|
183144
|
+
}
|
|
183145
|
+
return {
|
|
183146
|
+
relationId: RelationId.make(existing._id),
|
|
183147
|
+
associationId: AssociationId.make(association._id),
|
|
183148
|
+
source: endpoints.source,
|
|
183149
|
+
target: endpoints.target,
|
|
183150
|
+
created: false,
|
|
183151
|
+
existing: true
|
|
183152
|
+
};
|
|
183153
|
+
}
|
|
183154
|
+
yield* enforceCardinality(client, association, endpoints);
|
|
183155
|
+
const relationId = yield* client.createDoc(
|
|
183156
|
+
core.class.Relation,
|
|
183157
|
+
toRef(core.space.Workspace),
|
|
183158
|
+
{
|
|
183159
|
+
association: toRef(association._id),
|
|
183160
|
+
docA: toRef(endpoints.docA.id),
|
|
183161
|
+
docB: toRef(endpoints.docB.id)
|
|
183162
|
+
}
|
|
183163
|
+
);
|
|
183164
|
+
return {
|
|
183165
|
+
relationId: RelationId.make(relationId),
|
|
182725
183166
|
associationId: AssociationId.make(association._id),
|
|
182726
|
-
|
|
182727
|
-
|
|
183167
|
+
source: endpoints.source,
|
|
183168
|
+
target: endpoints.target,
|
|
183169
|
+
created: true,
|
|
183170
|
+
existing: false
|
|
183171
|
+
};
|
|
182728
183172
|
});
|
|
182729
183173
|
var deleteRelation = (params) => Effect_exports.gen(function* () {
|
|
182730
183174
|
const client = yield* HulyClient;
|
|
182731
|
-
|
|
182732
|
-
|
|
182733
|
-
|
|
182734
|
-
|
|
182735
|
-
|
|
183175
|
+
if ("relation" in params) {
|
|
183176
|
+
const existing = yield* client.findOne(
|
|
183177
|
+
core.class.Relation,
|
|
183178
|
+
hulyQuery({ _id: toRef(params.relation) })
|
|
183179
|
+
);
|
|
183180
|
+
if (existing === void 0) {
|
|
183181
|
+
return {
|
|
183182
|
+
relationId: RelationId.make(params.relation),
|
|
183183
|
+
deleted: false,
|
|
183184
|
+
reason: "not_found"
|
|
183185
|
+
};
|
|
183186
|
+
}
|
|
183187
|
+
const association2 = yield* resolveAssociation(client, existing.association, MUTATION_ASSOCIATION_FILTERS);
|
|
183188
|
+
yield* ensureRelationMutationSupported(association2, "delete_relation");
|
|
183189
|
+
yield* client.removeDoc(core.class.Relation, existing.space, existing._id);
|
|
183190
|
+
return {
|
|
183191
|
+
relationId: RelationId.make(existing._id),
|
|
183192
|
+
associationId: AssociationId.make(association2._id),
|
|
183193
|
+
deleted: true,
|
|
183194
|
+
reason: "deleted"
|
|
183195
|
+
};
|
|
183196
|
+
}
|
|
183197
|
+
const association = yield* resolveAssociation(client, params.association, MUTATION_ASSOCIATION_FILTERS);
|
|
183198
|
+
yield* ensureRelationMutationSupported(association, "delete_relation");
|
|
183199
|
+
const endpoints = yield* resolveRelationWriteEndpoints(client, association, params);
|
|
183200
|
+
const matches = yield* findExactRelations(client, association, endpoints, 2);
|
|
183201
|
+
if (matches.length === 0) {
|
|
183202
|
+
return {
|
|
183203
|
+
associationId: AssociationId.make(association._id),
|
|
183204
|
+
deleted: false,
|
|
183205
|
+
reason: "not_found"
|
|
183206
|
+
};
|
|
183207
|
+
}
|
|
183208
|
+
if (matches.length > 1) {
|
|
183209
|
+
return yield* new RelationIdentifierAmbiguousError({
|
|
183210
|
+
identifier: `${params.association}/${endpoints.docA.id}/${endpoints.docB.id}`,
|
|
183211
|
+
relationIds: matches.map((relation) => RelationId.make(relation._id))
|
|
183212
|
+
});
|
|
183213
|
+
}
|
|
183214
|
+
yield* client.removeDoc(core.class.Relation, matches[0].space, matches[0]._id);
|
|
183215
|
+
return {
|
|
183216
|
+
relationId: RelationId.make(matches[0]._id),
|
|
183217
|
+
associationId: AssociationId.make(association._id),
|
|
183218
|
+
deleted: true,
|
|
183219
|
+
reason: "deleted"
|
|
183220
|
+
};
|
|
182736
183221
|
});
|
|
182737
183222
|
|
|
182738
183223
|
// src/mcp/tools/generic-associations.ts
|
|
@@ -182750,6 +183235,42 @@ var genericAssociationTools = [
|
|
|
182750
183235
|
ListAssociationsResultSchema
|
|
182751
183236
|
)
|
|
182752
183237
|
},
|
|
183238
|
+
{
|
|
183239
|
+
name: "create_association",
|
|
183240
|
+
description: "Idempotently create one Huly association definition between two non-system classes. Use sourceClass/targetClass with sourceRole/targetRole and cardinality; returns an existing identical association by default.",
|
|
183241
|
+
category: CATEGORY11,
|
|
183242
|
+
inputSchema: createAssociationParamsJsonSchema,
|
|
183243
|
+
annotations: {
|
|
183244
|
+
readOnlyHint: false,
|
|
183245
|
+
destructiveHint: false,
|
|
183246
|
+
idempotentHint: true,
|
|
183247
|
+
openWorldHint: false
|
|
183248
|
+
},
|
|
183249
|
+
handler: createEncodedToolHandler(
|
|
183250
|
+
"create_association",
|
|
183251
|
+
parseCreateAssociationParams,
|
|
183252
|
+
createAssociation,
|
|
183253
|
+
CreateAssociationResultSchema
|
|
183254
|
+
)
|
|
183255
|
+
},
|
|
183256
|
+
{
|
|
183257
|
+
name: "delete_association",
|
|
183258
|
+
description: "Idempotently delete one Huly association definition only when no concrete relations reference it. If relations exist, delete_relation must clean them up first; deleting an already-missing association is a successful no-op.",
|
|
183259
|
+
category: CATEGORY11,
|
|
183260
|
+
inputSchema: deleteAssociationParamsJsonSchema,
|
|
183261
|
+
annotations: {
|
|
183262
|
+
readOnlyHint: false,
|
|
183263
|
+
destructiveHint: true,
|
|
183264
|
+
idempotentHint: true,
|
|
183265
|
+
openWorldHint: false
|
|
183266
|
+
},
|
|
183267
|
+
handler: createEncodedToolHandler(
|
|
183268
|
+
"delete_association",
|
|
183269
|
+
parseDeleteAssociationParams,
|
|
183270
|
+
deleteAssociation,
|
|
183271
|
+
DeleteAssociationResultSchema
|
|
183272
|
+
)
|
|
183273
|
+
},
|
|
182753
183274
|
{
|
|
182754
183275
|
name: "list_relations",
|
|
182755
183276
|
description: "List concrete Huly relation instances under an association, optionally filtered by source and target documents. Requires at least one filter to avoid broad workspace scans.",
|
|
@@ -182764,7 +183285,7 @@ var genericAssociationTools = [
|
|
|
182764
183285
|
},
|
|
182765
183286
|
{
|
|
182766
183287
|
name: "create_relation",
|
|
182767
|
-
description: "Idempotently create one concrete relation between two resolved documents
|
|
183288
|
+
description: "Idempotently create one concrete relation between two resolved documents for a writable association. Enforces association endpoint classes, direction, duplicate handling, automation-only restrictions, and cardinality.",
|
|
182768
183289
|
category: CATEGORY11,
|
|
182769
183290
|
inputSchema: createRelationParamsJsonSchema,
|
|
182770
183291
|
annotations: {
|
|
@@ -182782,9 +183303,15 @@ var genericAssociationTools = [
|
|
|
182782
183303
|
},
|
|
182783
183304
|
{
|
|
182784
183305
|
name: "delete_relation",
|
|
182785
|
-
description: "Idempotently delete one concrete relation by relation ID or by exact association/source/target triple.
|
|
183306
|
+
description: "Idempotently delete one concrete relation by relation ID or by exact association/source/target triple. Triple deletes use the same direction semantics as create_relation and fail if the selector is ambiguous.",
|
|
182786
183307
|
category: CATEGORY11,
|
|
182787
183308
|
inputSchema: deleteRelationParamsJsonSchema,
|
|
183309
|
+
annotations: {
|
|
183310
|
+
readOnlyHint: false,
|
|
183311
|
+
destructiveHint: true,
|
|
183312
|
+
idempotentHint: true,
|
|
183313
|
+
openWorldHint: false
|
|
183314
|
+
},
|
|
182788
183315
|
handler: createEncodedToolHandler(
|
|
182789
183316
|
"delete_relation",
|
|
182790
183317
|
parseDeleteRelationParams,
|
|
@@ -188643,7 +189170,6 @@ var handleVersionTool = async () => {
|
|
|
188643
189170
|
const latest = await fetchLatestNpmVersion();
|
|
188644
189171
|
return createSuccessResponse({ current: VERSION, latest });
|
|
188645
189172
|
};
|
|
188646
|
-
var isObjectSchema = (schema) => "type" in schema && schema.type === "object";
|
|
188647
189173
|
var McpServerError = class extends Schema_exports.TaggedError()(
|
|
188648
189174
|
"McpServerError",
|
|
188649
189175
|
{
|
|
@@ -188709,7 +189235,7 @@ var createMcpServer = (resolveClients, telemetry, registry2, createServer = () =
|
|
|
188709
189235
|
return [{
|
|
188710
189236
|
name: tool.name,
|
|
188711
189237
|
description: tool.description,
|
|
188712
|
-
inputSchema: tool.inputSchema,
|
|
189238
|
+
inputSchema: toClientCompatibleInputSchema(tool.inputSchema),
|
|
188713
189239
|
outputSchema: defaultToolOutputSchema,
|
|
188714
189240
|
annotations: resolveAnnotations(tool)
|
|
188715
189241
|
}];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@firfi/huly-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"description": "MCP server for Huly integration",
|
|
5
5
|
"mcpName": "io.github.dearlordylord/huly-mcp",
|
|
6
6
|
"type": "module",
|
|
@@ -107,10 +107,10 @@
|
|
|
107
107
|
"check-format": "find src test -name '*.ts' -print0 | xargs -0 eslint --rule '@effect/dprint: error'",
|
|
108
108
|
"check-all": "pnpm build && pnpm typecheck && pnpm verify-registry-metadata && pnpm lint && pnpm test",
|
|
109
109
|
"circular": "madge --extensions ts --circular src",
|
|
110
|
-
"local-release": "
|
|
110
|
+
"local-release": "pnpm dlx @changesets/cli@2.30.0 version && pnpm sync-registry-metadata && git add package.json CHANGELOG.md server.json .changeset && (git diff --cached --quiet || HUSKY=0 git commit -m \"RELEASING: Releasing 1 package(s)\") && PKG_VERSION=$(node -p \"require('./package.json').version\") && pnpm dlx esbuild@0.27.2 src/index.ts --bundle --platform=node --format=cjs --outfile=dist/index.cjs --external:ws \"--define:PKG_VERSION=\\\"$PKG_VERSION\\\"\" && pnpm verify-version && npm_config_ignore_scripts=true pnpm dlx @changesets/cli@2.30.0 publish",
|
|
111
111
|
"verify-version": "node -e \"const v=require('./package.json').version; const d=require('fs').readFileSync('dist/index.cjs','utf8'); if(!d.includes('\\\"'+v+'\\\"'))throw new Error('dist version mismatch: expected '+v)\"",
|
|
112
|
-
"verify-registry-metadata": "
|
|
113
|
-
"sync-registry-metadata": "
|
|
114
|
-
"update-readme": "
|
|
112
|
+
"verify-registry-metadata": "node scripts/sync-registry-metadata.mjs --check",
|
|
113
|
+
"sync-registry-metadata": "node scripts/sync-registry-metadata.mjs",
|
|
114
|
+
"update-readme": "node scripts/update-readme-tools.mjs"
|
|
115
115
|
}
|
|
116
116
|
}
|