@firfi/huly-mcp 0.31.0 → 0.31.1
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 +5 -2
- package/dist/index.cjs +339 -12
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -269,7 +269,7 @@ The roadmap is driven by SDK parity and the project principle that this server s
|
|
|
269
269
|
|
|
270
270
|
Highest-value additions for coding agents:
|
|
271
271
|
|
|
272
|
-
- Generic space follow-ups: role
|
|
272
|
+
- Generic space follow-ups: role/permission definition writes, generic space creation, and module-specific wrappers above the shared space foundation. Generic space metadata, member/owner mutations, and typed-space role member mutations are covered by the shared spaces tools.
|
|
273
273
|
- SDK discovery phase 2: space types, roles, permissions, plugin configuration, sequence metadata, and richer tool hints.
|
|
274
274
|
- Drive follow-ups: drive create/update/delete, item move/rename/delete, adding new versions to existing files, permissions, and comments/activity.
|
|
275
275
|
- Planner/ToDos: personal and project ToDo CRUD, scheduling, complete/reopen, priority, privacy/visibility, and document action items.
|
|
@@ -298,7 +298,7 @@ Planned feature surfaces:
|
|
|
298
298
|
- Chat and communication: direct-message send/update/delete, group DMs, channel member mutations, join/leave/request access, archive/unarchive, star/favorite channels, close/reopen conversations, pinned messages, message attachments, translation, applets, in-message polls, and guest communication settings.
|
|
299
299
|
- Notifications and activity: browser/push subscription internals, provider defaults, UI presenter/viewlet metadata, and activity control/extension metadata.
|
|
300
300
|
- Attachments and media: previews/preview metadata and friendly wrappers for additional object types beyond issue/document.
|
|
301
|
-
- Core schema and workspace administration: attribute/property create/update/delete/hide, enum CRUD/options, sequence management, role
|
|
301
|
+
- Core schema and workspace administration: attribute/property create/update/delete/hide, enum CRUD/options, sequence management, role/permission definition writes, generic space creation, global space admins, integrations registry, invite settings, role capability settings, and workspace setting metadata.
|
|
302
302
|
- Integrations: GitHub repository/project mappings and sync metadata (deferred), Google Calendar connect/configure/sync controls, Bitrix entity/field mappings and sync status, Gmail/email channel messages, Telegram messages, Huly Mail/Mail plugin behavior, AI assistant integration state, and AI bot configuration if server-side APIs expose stable behavior.
|
|
303
303
|
- Templates, rating, support, billing, analytics, views, workbench, and preferences: message templates/categories/fields, document/person rating data blocked by unpublished `@hcengineering/rating` SDK package (#90), support conversations, billing tier/status discovery, onboarding channels, saved filtered views, user view preferences, tabs/widgets/apps, and module preference discovery/update.
|
|
304
304
|
- Document-specific gaps: snapshot restore, backlinks, notes, structured action items/tables, PDF/export, advanced document relationships, and document printing/export once SDK support is safe.
|
|
@@ -740,6 +740,9 @@ SDK upgrade revisit:
|
|
|
740
740
|
| `add_space_members` | Idempotently add members to an existing Huly space. Members accept account UUID, exact email, or exact person display name and resolve to Huly account UUIDs before replacing the full members array. |
|
|
741
741
|
| `remove_space_members` | Idempotently remove members from an existing Huly space. Members accept account UUID, exact email, or exact person display name and resolve to Huly account UUIDs before replacing the full members array. |
|
|
742
742
|
| `set_space_owners` | Replace owners on an existing Huly space. Owners accept account UUID, exact email, or exact person display name. By default, owners are also ensured in members. |
|
|
743
|
+
| `set_space_role_members` | Replace members assigned to one role on a typed Huly space while preserving all other role assignments. Role accepts a raw role _id or exact role name from the space's SpaceType. Members accept account UUID, exact email, or exact person display name; pass members=[] to clear this role. |
|
|
744
|
+
| `add_space_role_members` | Idempotently add members to one role on a typed Huly space while preserving all other role assignments. Role accepts a raw role _id or exact role name from the space's SpaceType. Members accept account UUID, exact email, or exact person display name. |
|
|
745
|
+
| `remove_space_role_members` | Idempotently remove members from one role on a typed Huly space while preserving all other role assignments. Role accepts a raw role _id or exact role name from the space's SpaceType. Members accept account UUID, exact email, or exact person display name. |
|
|
743
746
|
|
|
744
747
|
### Tag-Categories
|
|
745
748
|
|
package/dist/index.cjs
CHANGED
|
@@ -154570,6 +154570,10 @@ var AmbiguousSpaceTypeMatchSchema = Schema_exports.Struct({
|
|
|
154570
154570
|
name: NonEmptyString2,
|
|
154571
154571
|
targetClass: ObjectClassName
|
|
154572
154572
|
});
|
|
154573
|
+
var AmbiguousSpaceRoleMatchSchema = Schema_exports.Struct({
|
|
154574
|
+
id: RoleId,
|
|
154575
|
+
name: NonEmptyString2
|
|
154576
|
+
});
|
|
154573
154577
|
var SpaceNotFoundError = class extends Schema_exports.TaggedError()(
|
|
154574
154578
|
"SpaceNotFoundError",
|
|
154575
154579
|
{
|
|
@@ -154614,6 +154618,54 @@ var SpaceTypeIdentifierAmbiguousError = class extends Schema_exports.TaggedError
|
|
|
154614
154618
|
return `Space type '${this.identifier}' is ambiguous; use a space type id. Matches: ${details}`;
|
|
154615
154619
|
}
|
|
154616
154620
|
};
|
|
154621
|
+
var SpaceNotTypedError = class extends Schema_exports.TaggedError()(
|
|
154622
|
+
"SpaceNotTypedError",
|
|
154623
|
+
{
|
|
154624
|
+
id: SpaceId,
|
|
154625
|
+
name: NonEmptyString2
|
|
154626
|
+
}
|
|
154627
|
+
) {
|
|
154628
|
+
get message() {
|
|
154629
|
+
return `Space '${this.name}' (${this.id}) is not typed; role members can only be changed on spaces with a SpaceType`;
|
|
154630
|
+
}
|
|
154631
|
+
};
|
|
154632
|
+
var SpaceRoleNotFoundError = class extends Schema_exports.TaggedError()(
|
|
154633
|
+
"SpaceRoleNotFoundError",
|
|
154634
|
+
{
|
|
154635
|
+
identifier: NonEmptyString2,
|
|
154636
|
+
spaceType: SpaceTypeId
|
|
154637
|
+
}
|
|
154638
|
+
) {
|
|
154639
|
+
get message() {
|
|
154640
|
+
return `Role '${this.identifier}' not found in space type '${this.spaceType}'`;
|
|
154641
|
+
}
|
|
154642
|
+
};
|
|
154643
|
+
var SpaceRoleIdentifierAmbiguousError = class extends Schema_exports.TaggedError()(
|
|
154644
|
+
"SpaceRoleIdentifierAmbiguousError",
|
|
154645
|
+
{
|
|
154646
|
+
identifier: NonEmptyString2,
|
|
154647
|
+
spaceType: SpaceTypeId,
|
|
154648
|
+
matches: Schema_exports.Array(AmbiguousSpaceRoleMatchSchema).pipe(Schema_exports.minItems(MIN_AMBIGUOUS_SPACE_MATCHES))
|
|
154649
|
+
}
|
|
154650
|
+
) {
|
|
154651
|
+
get message() {
|
|
154652
|
+
const details = this.matches.map((match16) => `${match16.id} (${match16.name})`).join(", ");
|
|
154653
|
+
return `Role '${this.identifier}' is ambiguous in space type '${this.spaceType}'; use a role id. Matches: ${details}`;
|
|
154654
|
+
}
|
|
154655
|
+
};
|
|
154656
|
+
var SpaceRoleAssignmentsMalformedError = class extends Schema_exports.TaggedError()(
|
|
154657
|
+
"SpaceRoleAssignmentsMalformedError",
|
|
154658
|
+
{
|
|
154659
|
+
space: SpaceId,
|
|
154660
|
+
spaceType: SpaceTypeId,
|
|
154661
|
+
targetClass: ObjectClassName,
|
|
154662
|
+
reason: NonEmptyString2
|
|
154663
|
+
}
|
|
154664
|
+
) {
|
|
154665
|
+
get message() {
|
|
154666
|
+
return `Role assignments for space '${this.space}' and space type '${this.spaceType}' are malformed at '${this.targetClass}': ${this.reason}. Refusing to write role members to avoid access-control data loss.`;
|
|
154667
|
+
}
|
|
154668
|
+
};
|
|
154617
154669
|
|
|
154618
154670
|
// src/huly/errors-test-management.ts
|
|
154619
154671
|
var TestProjectNotFoundError = class extends Schema_exports.TaggedError()(
|
|
@@ -154890,6 +154942,10 @@ var HulyDomainError = Schema_exports.Union(
|
|
|
154890
154942
|
HulyClassNotFoundError,
|
|
154891
154943
|
SpaceNotFoundError,
|
|
154892
154944
|
SpaceIdentifierAmbiguousError,
|
|
154945
|
+
SpaceNotTypedError,
|
|
154946
|
+
SpaceRoleNotFoundError,
|
|
154947
|
+
SpaceRoleIdentifierAmbiguousError,
|
|
154948
|
+
SpaceRoleAssignmentsMalformedError,
|
|
154893
154949
|
SpaceTypeNotFoundError,
|
|
154894
154950
|
SpaceTypeIdentifierAmbiguousError,
|
|
154895
154951
|
TodoNotFoundError,
|
|
@@ -155423,6 +155479,7 @@ var import_api_client3 = __toESM(require_lib20(), 1);
|
|
|
155423
155479
|
// src/huly/operations/sdk-boundary.ts
|
|
155424
155480
|
var toRef = (id) => id;
|
|
155425
155481
|
var toClassRef = (id) => id;
|
|
155482
|
+
var toMixinRef = (id) => id;
|
|
155426
155483
|
var toAccountUuid = (uuid5) => uuid5;
|
|
155427
155484
|
var UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
155428
155485
|
var validatePersonUuid = (uuid5) => {
|
|
@@ -165843,6 +165900,9 @@ var INVALID_PARAMS_TAGS = /* @__PURE__ */ new Set([
|
|
|
165843
165900
|
"GenericObjectNotFoundError",
|
|
165844
165901
|
"SpaceNotFoundError",
|
|
165845
165902
|
"SpaceIdentifierAmbiguousError",
|
|
165903
|
+
"SpaceNotTypedError",
|
|
165904
|
+
"SpaceRoleNotFoundError",
|
|
165905
|
+
"SpaceRoleIdentifierAmbiguousError",
|
|
165846
165906
|
"SpaceTypeNotFoundError",
|
|
165847
165907
|
"SpaceTypeIdentifierAmbiguousError",
|
|
165848
165908
|
"DriveNotFoundError",
|
|
@@ -166487,12 +166547,16 @@ var StdioServerTransport = class {
|
|
|
166487
166547
|
};
|
|
166488
166548
|
|
|
166489
166549
|
// src/domain/schemas/tool-warnings.ts
|
|
166490
|
-
var ToolWarningCodeSchema = Schema_exports.Literal(
|
|
166550
|
+
var ToolWarningCodeSchema = Schema_exports.Literal(
|
|
166551
|
+
"status_metadata_unresolved",
|
|
166552
|
+
"space_role_assignments_degraded"
|
|
166553
|
+
).annotations({
|
|
166491
166554
|
identifier: "ToolWarningCode",
|
|
166492
166555
|
title: "ToolWarningCode",
|
|
166493
166556
|
description: "Machine-readable code for an agent-visible MCP tool warning."
|
|
166494
166557
|
});
|
|
166495
166558
|
var StatusMetadataUnresolvedWarningCode = ToolWarningCodeSchema.literals[0];
|
|
166559
|
+
var SpaceRoleAssignmentsDegradedWarningCode = ToolWarningCodeSchema.literals[1];
|
|
166496
166560
|
var ToolWarningSchema = Schema_exports.Struct({
|
|
166497
166561
|
code: ToolWarningCodeSchema,
|
|
166498
166562
|
message: Schema_exports.Trim.pipe(Schema_exports.nonEmptyString()).annotations({
|
|
@@ -166554,9 +166618,13 @@ var clearableText = (description) => Schema_exports.NullOr(Schema_exports.String
|
|
|
166554
166618
|
var limitDescription = (subject) => `Maximum ${subject} to return (default: ${DEFAULT_LIMIT}).`;
|
|
166555
166619
|
var SpacePermissionScopeSchema = Schema_exports.Literal("space", "workspace");
|
|
166556
166620
|
var SpaceMemberIdentifier = NonEmptyString2.pipe(Schema_exports.brand("SpaceMemberIdentifier"));
|
|
166621
|
+
var SpaceRoleIdentifier = NonEmptyString2.pipe(Schema_exports.brand("SpaceRoleIdentifier"));
|
|
166557
166622
|
var SpaceMemberIdentifierSchema = SpaceMemberIdentifier.annotations({
|
|
166558
166623
|
description: "Workspace member to resolve. Accepts a Huly account UUID directly, an exact email address, or an exact person display name."
|
|
166559
166624
|
});
|
|
166625
|
+
var SpaceRoleIdentifierSchema = SpaceRoleIdentifier.annotations({
|
|
166626
|
+
description: "Role to resolve within the space's SpaceType. Accepts a raw Huly role _id or an exact role name from get_space_type."
|
|
166627
|
+
});
|
|
166560
166628
|
var SpaceRoleAssignmentSchema = Schema_exports.Struct({
|
|
166561
166629
|
roleId: RoleId,
|
|
166562
166630
|
members: Schema_exports.Array(AccountUuid)
|
|
@@ -166731,6 +166799,28 @@ var SetSpaceOwnersParamsSchema = Schema_exports.Struct({
|
|
|
166731
166799
|
description: `Also add each owner to members. Defaults to ${DEFAULT_SPACE_OWNER_ENSURE_MEMBERS}.`
|
|
166732
166800
|
}))
|
|
166733
166801
|
});
|
|
166802
|
+
var SpaceRoleMemberMutationFields = {
|
|
166803
|
+
space: SpaceIdentifier.annotations({
|
|
166804
|
+
description: "Typed space _id or exact space name whose role assignment should change. The space must have a SpaceType."
|
|
166805
|
+
}),
|
|
166806
|
+
class: Schema_exports.optional(SpaceClassFilter.annotations({
|
|
166807
|
+
description: "Optional raw Huly space class ID used to disambiguate exact-name lookup."
|
|
166808
|
+
})),
|
|
166809
|
+
type: Schema_exports.optional(SpaceTypeId.annotations({
|
|
166810
|
+
description: "Optional raw Huly SpaceType _id used to disambiguate exact-name lookup."
|
|
166811
|
+
})),
|
|
166812
|
+
role: SpaceRoleIdentifierSchema,
|
|
166813
|
+
members: Schema_exports.Array(SpaceMemberIdentifierSchema).pipe(Schema_exports.minItems(1)).annotations({
|
|
166814
|
+
description: "Members to add or remove from this role. Each entry may be an account UUID, exact email address, or exact person name."
|
|
166815
|
+
})
|
|
166816
|
+
};
|
|
166817
|
+
var SpaceRoleMemberMutationParamsSchema = Schema_exports.Struct(SpaceRoleMemberMutationFields);
|
|
166818
|
+
var SetSpaceRoleMembersParamsSchema = Schema_exports.Struct({
|
|
166819
|
+
...SpaceRoleMemberMutationFields,
|
|
166820
|
+
members: Schema_exports.Array(SpaceMemberIdentifierSchema).annotations({
|
|
166821
|
+
description: "Replacement member list for this role only. Each entry may be an account UUID, exact email address, or exact person name. Pass [] to clear this role."
|
|
166822
|
+
})
|
|
166823
|
+
});
|
|
166734
166824
|
var listSpacesParamsJsonSchema = JSONSchema_exports.make(ListSpacesParamsSchema);
|
|
166735
166825
|
var getSpaceParamsJsonSchema = JSONSchema_exports.make(GetSpaceParamsSchema);
|
|
166736
166826
|
var listSpaceTypesParamsJsonSchema = JSONSchema_exports.make(ListSpaceTypesParamsSchema);
|
|
@@ -166742,6 +166832,8 @@ var updateSpaceParamsJsonSchema = withAtLeastOneRequired(
|
|
|
166742
166832
|
);
|
|
166743
166833
|
var spaceMemberMutationParamsJsonSchema = JSONSchema_exports.make(SpaceMemberMutationParamsSchema);
|
|
166744
166834
|
var setSpaceOwnersParamsJsonSchema = JSONSchema_exports.make(SetSpaceOwnersParamsSchema);
|
|
166835
|
+
var spaceRoleMemberMutationParamsJsonSchema = JSONSchema_exports.make(SpaceRoleMemberMutationParamsSchema);
|
|
166836
|
+
var setSpaceRoleMembersParamsJsonSchema = JSONSchema_exports.make(SetSpaceRoleMembersParamsSchema);
|
|
166745
166837
|
var parseListSpacesParams = Schema_exports.decodeUnknown(ListSpacesParamsSchema);
|
|
166746
166838
|
var parseGetSpaceParams = Schema_exports.decodeUnknown(GetSpaceParamsSchema);
|
|
166747
166839
|
var parseListSpaceTypesParams = Schema_exports.decodeUnknown(ListSpaceTypesParamsSchema);
|
|
@@ -166750,6 +166842,8 @@ var parseListSpacePermissionsParams = Schema_exports.decodeUnknown(ListSpacePerm
|
|
|
166750
166842
|
var parseUpdateSpaceParams = Schema_exports.decodeUnknown(UpdateSpaceParamsSchema);
|
|
166751
166843
|
var parseSpaceMemberMutationParams = Schema_exports.decodeUnknown(SpaceMemberMutationParamsSchema);
|
|
166752
166844
|
var parseSetSpaceOwnersParams = Schema_exports.decodeUnknown(SetSpaceOwnersParamsSchema);
|
|
166845
|
+
var parseSpaceRoleMemberMutationParams = Schema_exports.decodeUnknown(SpaceRoleMemberMutationParamsSchema);
|
|
166846
|
+
var parseSetSpaceRoleMembersParams = Schema_exports.decodeUnknown(SetSpaceRoleMembersParamsSchema);
|
|
166753
166847
|
|
|
166754
166848
|
// src/domain/schemas/sdk-discovery.ts
|
|
166755
166849
|
var import_core10 = __toESM(require_lib4(), 1);
|
|
@@ -174642,7 +174736,7 @@ var makeDiagnosticsScope = Effect_exports.gen(function* () {
|
|
|
174642
174736
|
});
|
|
174643
174737
|
|
|
174644
174738
|
// src/version.ts
|
|
174645
|
-
var VERSION = true ? "0.31.
|
|
174739
|
+
var VERSION = true ? "0.31.1" : "0.0.0-dev";
|
|
174646
174740
|
|
|
174647
174741
|
// src/mcp/tool-output-schema.ts
|
|
174648
174742
|
var toolWarningCodeEnum = [...ToolWarningCodeSchema.literals];
|
|
@@ -175142,6 +175236,93 @@ var removeAccountUuids = (current, removals) => {
|
|
|
175142
175236
|
var arraysEqual = (left3, right3) => left3.length === right3.length && left3.every((value3, index) => value3 === right3[index]);
|
|
175143
175237
|
var optionalString = (value3) => value3 === void 0 || value3 === "" ? void 0 : value3;
|
|
175144
175238
|
var optionalObjectClassName = (value3) => value3 === void 0 || value3 === "" ? void 0 : ObjectClassName.make(value3);
|
|
175239
|
+
var RoleAssignmentStorageSchema = Schema_exports.Record({ key: Schema_exports.String, value: Schema_exports.Array(AccountUuid) });
|
|
175240
|
+
var isRecordObject = (value3) => typeof value3 === "object" && value3 !== null && !Array.isArray(value3);
|
|
175241
|
+
var validStoredAccountUuid = (value3) => {
|
|
175242
|
+
const decoded = Schema_exports.decodeUnknownEither(AccountUuid)(value3);
|
|
175243
|
+
return decoded._tag === "Right" ? toAccountUuid(NonEmptyString2.make(decoded.right)) : void 0;
|
|
175244
|
+
};
|
|
175245
|
+
var parsedSpaceRoleAssignmentEntry = (roleId, members) => ({
|
|
175246
|
+
_tag: "entry",
|
|
175247
|
+
entry: [
|
|
175248
|
+
toRef(roleId),
|
|
175249
|
+
sortStrings(members).map(toAccountUuid)
|
|
175250
|
+
]
|
|
175251
|
+
});
|
|
175252
|
+
var spaceRoleAssignmentSource = (space, spaceType) => Object.prototype.hasOwnProperty.call(space, spaceType.targetClass) ? { present: true, value: Object.entries(space).find(([key]) => key === spaceType.targetClass)?.[1] } : { present: false, value: void 0 };
|
|
175253
|
+
var roleAssignmentsMalformedError = (space, spaceType, reason) => new SpaceRoleAssignmentsMalformedError({
|
|
175254
|
+
space: SpaceId.make(space._id),
|
|
175255
|
+
spaceType: SpaceTypeId.make(spaceType._id),
|
|
175256
|
+
targetClass: ObjectClassName.make(spaceType.targetClass),
|
|
175257
|
+
reason: NonEmptyString2.make(reason)
|
|
175258
|
+
});
|
|
175259
|
+
var readSpaceRoleAssignmentEntries = (space, spaceType, validRoleIds) => {
|
|
175260
|
+
const source = spaceRoleAssignmentSource(space, spaceType);
|
|
175261
|
+
if (!source.present) return { entries: [], degradationReasons: [] };
|
|
175262
|
+
if (!isRecordObject(source.value)) {
|
|
175263
|
+
return {
|
|
175264
|
+
entries: [],
|
|
175265
|
+
degradationReasons: [`role assignment mixin ${spaceType.targetClass} is not an object`]
|
|
175266
|
+
};
|
|
175267
|
+
}
|
|
175268
|
+
const parsed = Object.entries(source.value).flatMap(([roleId, members]) => {
|
|
175269
|
+
if (!validRoleIds.has(toRef(roleId))) {
|
|
175270
|
+
return [{
|
|
175271
|
+
_tag: "dropped",
|
|
175272
|
+
reason: `role assignment '${roleId}' is not defined on space type ${spaceType._id}`
|
|
175273
|
+
}];
|
|
175274
|
+
}
|
|
175275
|
+
if (!Array.isArray(members)) {
|
|
175276
|
+
return [{ _tag: "dropped", reason: `role assignment '${roleId}' members are not an array` }];
|
|
175277
|
+
}
|
|
175278
|
+
const accountUuids = members.flatMap((member) => {
|
|
175279
|
+
const accountUuid = validStoredAccountUuid(member);
|
|
175280
|
+
return accountUuid === void 0 ? [] : [accountUuid];
|
|
175281
|
+
});
|
|
175282
|
+
const invalidMemberCount = members.length - accountUuids.length;
|
|
175283
|
+
return [
|
|
175284
|
+
...invalidMemberCount > 0 ? [{
|
|
175285
|
+
_tag: "dropped",
|
|
175286
|
+
reason: `role assignment '${roleId}' has ${invalidMemberCount} malformed account UUID value(s)`
|
|
175287
|
+
}] : [],
|
|
175288
|
+
parsedSpaceRoleAssignmentEntry(roleId, accountUuids)
|
|
175289
|
+
];
|
|
175290
|
+
});
|
|
175291
|
+
return {
|
|
175292
|
+
entries: parsed.flatMap((item) => item._tag === "entry" ? [item.entry] : []),
|
|
175293
|
+
degradationReasons: parsed.flatMap((item) => item._tag === "dropped" ? [item.reason] : [])
|
|
175294
|
+
};
|
|
175295
|
+
};
|
|
175296
|
+
var spaceRoleAssignmentEntries = (space, spaceType, validRoleIds) => readSpaceRoleAssignmentEntries(space, spaceType, validRoleIds).entries;
|
|
175297
|
+
var hasSpaceRoleAssignmentMixin = (space, spaceType) => spaceRoleAssignmentSource(space, spaceType).present;
|
|
175298
|
+
var strictSpaceRoleAssignments = (space, spaceType, validRoleIds) => Effect_exports.gen(function* () {
|
|
175299
|
+
const source = spaceRoleAssignmentSource(space, spaceType);
|
|
175300
|
+
if (!source.present) return {};
|
|
175301
|
+
const decoded = Schema_exports.decodeUnknownEither(RoleAssignmentStorageSchema)(source.value);
|
|
175302
|
+
if (decoded._tag === "Left") {
|
|
175303
|
+
return yield* roleAssignmentsMalformedError(
|
|
175304
|
+
space,
|
|
175305
|
+
spaceType,
|
|
175306
|
+
`expected an object whose keys are role ids and values are arrays of account UUIDs`
|
|
175307
|
+
);
|
|
175308
|
+
}
|
|
175309
|
+
const unknownRoleIds = Object.keys(decoded.right).filter((roleId) => !validRoleIds.has(toRef(roleId)));
|
|
175310
|
+
if (unknownRoleIds.length > 0) {
|
|
175311
|
+
return yield* roleAssignmentsMalformedError(
|
|
175312
|
+
space,
|
|
175313
|
+
spaceType,
|
|
175314
|
+
`unknown role assignment key(s): ${unknownRoleIds.join(", ")}`
|
|
175315
|
+
);
|
|
175316
|
+
}
|
|
175317
|
+
return Object.fromEntries(
|
|
175318
|
+
Object.entries(decoded.right).map(([roleId, members]) => [
|
|
175319
|
+
toRef(roleId),
|
|
175320
|
+
members.map((member) => toAccountUuid(NonEmptyString2.make(member)))
|
|
175321
|
+
])
|
|
175322
|
+
);
|
|
175323
|
+
});
|
|
175324
|
+
var roleAssignmentDegradationMessage = (reasons) => `Some typed-space role assignment data was omitted because existing Huly storage is malformed: ${reasons.join("; ")}. Read results include only valid role assignments; role-member write tools will refuse to modify this space until the stored role assignment data is repaired.`;
|
|
175325
|
+
var spaceRoleAssignmentsMixin = (spaceType) => toMixinRef(spaceType.targetClass);
|
|
175145
175326
|
var applySpaceFilters = (query, filters) => {
|
|
175146
175327
|
const next4 = { ...query };
|
|
175147
175328
|
if (!filters.includeArchived) {
|
|
@@ -178923,7 +179104,7 @@ var contactCoveredRationale = "Current contacts tools expose person, organizatio
|
|
|
178923
179104
|
var cardCoveredRationale = "Current card tools cover card spaces, master tags, and card CRUD.";
|
|
178924
179105
|
var chunterCoveredRationale = "Current channel and direct-message tools cover channels, channel messages, one-to-one DM listing, and thread replies.";
|
|
178925
179106
|
var coreCoveredRationale = "Existing tools expose user statuses, full-text search, blobs through storage/download flows, generic association/relation discovery/mutation helpers, class/interface/mixin, attribute, enum, plugin configuration, domain index configuration, sequence, and space type capability discovery.";
|
|
178926
|
-
var coreGapRationale = "Remaining core write-side configuration, role
|
|
179107
|
+
var coreGapRationale = "Remaining core write-side configuration, role/permission definition writes, generic space creation, class collaborator metadata, statuses, and write-side model management are represented as matrix gaps. Generic space discovery, space type/permission reads, safe existing-space metadata updates, member mutations, owner replacement, typed-space role member mutations, object collaborators, read-only plugin configuration, domain index configuration, and sequence discovery are covered.";
|
|
178927
179108
|
var coreNotMcpFacingRationale = "Core primitive model infrastructure, transaction classes, type wrappers, and versioning internals are not LLM-facing product resources by themselves.";
|
|
178928
179109
|
var routingRow = (classId, packageName, exportName, hint) => ({
|
|
178929
179110
|
classId: ObjectClassName.make(classId),
|
|
@@ -189784,14 +189965,15 @@ var toSpaceSummary = (space) => ({
|
|
|
189784
189965
|
membersCount: Count.make(space.members.length),
|
|
189785
189966
|
ownersCount: Count.make(space.owners?.length ?? 0)
|
|
189786
189967
|
});
|
|
189787
|
-
var roleAssignments = (space) => {
|
|
189788
|
-
if (
|
|
189789
|
-
|
|
189968
|
+
var roleAssignments = (space, spaceType, validRoleIds) => {
|
|
189969
|
+
if (spaceType === void 0) return void 0;
|
|
189970
|
+
const entries2 = spaceRoleAssignmentEntries(space, spaceType, validRoleIds);
|
|
189971
|
+
return entries2.length === 0 ? void 0 : entries2.map(([roleId, members]) => ({
|
|
189790
189972
|
roleId: RoleId.make(roleId),
|
|
189791
|
-
members:
|
|
189973
|
+
members: members.map((member) => AccountUuid.make(member))
|
|
189792
189974
|
}));
|
|
189793
189975
|
};
|
|
189794
|
-
var toSpaceDetail = (space) => ({
|
|
189976
|
+
var toSpaceDetail = (space, spaceType, validRoleIds = /* @__PURE__ */ new Set()) => ({
|
|
189795
189977
|
id: SpaceId.make(space._id),
|
|
189796
189978
|
name: space.name,
|
|
189797
189979
|
description: space.description,
|
|
@@ -189802,7 +189984,7 @@ var toSpaceDetail = (space) => ({
|
|
|
189802
189984
|
autoJoin: space.autoJoin,
|
|
189803
189985
|
members: space.members.map((member) => AccountUuid.make(member)),
|
|
189804
189986
|
owners: (space.owners ?? []).map((owner) => AccountUuid.make(owner)),
|
|
189805
|
-
roleAssignments: roleAssignments(space)
|
|
189987
|
+
roleAssignments: roleAssignments(space, spaceType, validRoleIds)
|
|
189806
189988
|
});
|
|
189807
189989
|
var spaceTypeSummary = (spaceType, descriptor3) => ({
|
|
189808
189990
|
id: SpaceTypeId.make(spaceType._id),
|
|
@@ -189884,8 +190066,28 @@ var listSpaces = (params) => Effect_exports.gen(function* () {
|
|
|
189884
190066
|
});
|
|
189885
190067
|
var getSpace = (params) => Effect_exports.gen(function* () {
|
|
189886
190068
|
const client = yield* HulyClient;
|
|
190069
|
+
const diagnostics = yield* Diagnostics;
|
|
189887
190070
|
const space = yield* findSpace(client, params);
|
|
189888
|
-
|
|
190071
|
+
const spaceType = space.type === void 0 ? void 0 : yield* client.findOne(
|
|
190072
|
+
core.class.SpaceType,
|
|
190073
|
+
hulyQuery({ _id: toRef(space.type) })
|
|
190074
|
+
);
|
|
190075
|
+
const roles = spaceType === void 0 ? [] : yield* client.findAll(
|
|
190076
|
+
core.class.Role,
|
|
190077
|
+
hulyQuery({ attachedTo: spaceType._id }),
|
|
190078
|
+
{ limit: Math.max(spaceType.roles, 1) }
|
|
190079
|
+
);
|
|
190080
|
+
const validRoleIds = new Set(roles.map((role) => role._id));
|
|
190081
|
+
if (spaceType !== void 0) {
|
|
190082
|
+
const readResult = readSpaceRoleAssignmentEntries(space, spaceType, validRoleIds);
|
|
190083
|
+
if (readResult.degradationReasons.length > 0) {
|
|
190084
|
+
yield* diagnostics.warnAgent({
|
|
190085
|
+
code: SpaceRoleAssignmentsDegradedWarningCode,
|
|
190086
|
+
message: roleAssignmentDegradationMessage(readResult.degradationReasons)
|
|
190087
|
+
});
|
|
190088
|
+
}
|
|
190089
|
+
}
|
|
190090
|
+
return toSpaceDetail(space, spaceType, validRoleIds);
|
|
189889
190091
|
});
|
|
189890
190092
|
var listSpaceTypes = (params) => Effect_exports.gen(function* () {
|
|
189891
190093
|
const client = yield* HulyClient;
|
|
@@ -190068,8 +190270,8 @@ var describeHulySpaceTypeCapabilities = (params) => Effect_exports.gen(function*
|
|
|
190068
190270
|
roles: detail.roles,
|
|
190069
190271
|
rolePermissions: detail.availablePermissions,
|
|
190070
190272
|
assignmentShape: {
|
|
190071
|
-
storedOnSpaceField: HulyConfigurationMetadataKey.make(
|
|
190072
|
-
roleKeyField: HulyConfigurationMetadataKey.make("
|
|
190273
|
+
storedOnSpaceField: HulyConfigurationMetadataKey.make(`mixin:${detail.targetClass}`),
|
|
190274
|
+
roleKeyField: HulyConfigurationMetadataKey.make("role._id"),
|
|
190073
190275
|
memberValueShape: "accountUuidArrayOrUndefined",
|
|
190074
190276
|
readProjectionTools: ["get_space"].map((tool) => HulyMcpToolName.make(tool))
|
|
190075
190277
|
}
|
|
@@ -190403,6 +190605,104 @@ var searchTools = [
|
|
|
190403
190605
|
];
|
|
190404
190606
|
|
|
190405
190607
|
// src/huly/operations/spaces-write.ts
|
|
190608
|
+
var roleClass = core.class.Role;
|
|
190609
|
+
var spaceTypeClass = core.class.SpaceType;
|
|
190610
|
+
var requireTypedSpaceType = (space) => Effect_exports.gen(function* () {
|
|
190611
|
+
if (space.type === void 0) {
|
|
190612
|
+
return yield* new SpaceNotTypedError({
|
|
190613
|
+
id: SpaceId.make(space._id),
|
|
190614
|
+
name: NonEmptyString2.make(space.name)
|
|
190615
|
+
});
|
|
190616
|
+
}
|
|
190617
|
+
return SpaceTypeId.make(space.type);
|
|
190618
|
+
});
|
|
190619
|
+
var findSpaceType2 = (client, spaceType) => Effect_exports.gen(function* () {
|
|
190620
|
+
const result = yield* client.findOne(
|
|
190621
|
+
spaceTypeClass,
|
|
190622
|
+
hulyQuery({ _id: toRef(spaceType) })
|
|
190623
|
+
);
|
|
190624
|
+
if (result === void 0) {
|
|
190625
|
+
return yield* new SpaceRoleNotFoundError({
|
|
190626
|
+
identifier: NonEmptyString2.make("SpaceType roles"),
|
|
190627
|
+
spaceType
|
|
190628
|
+
});
|
|
190629
|
+
}
|
|
190630
|
+
return result;
|
|
190631
|
+
});
|
|
190632
|
+
var resolveSpaceRole = (client, spaceType, role) => Effect_exports.gen(function* () {
|
|
190633
|
+
const byId = yield* client.findOne(
|
|
190634
|
+
roleClass,
|
|
190635
|
+
hulyQuery({
|
|
190636
|
+
_id: toRef(role),
|
|
190637
|
+
attachedTo: toRef(spaceType)
|
|
190638
|
+
})
|
|
190639
|
+
);
|
|
190640
|
+
if (byId !== void 0) return byId;
|
|
190641
|
+
const matches = yield* client.findAll(
|
|
190642
|
+
roleClass,
|
|
190643
|
+
hulyQuery({
|
|
190644
|
+
attachedTo: toRef(spaceType),
|
|
190645
|
+
name: role
|
|
190646
|
+
}),
|
|
190647
|
+
{ limit: 2 }
|
|
190648
|
+
);
|
|
190649
|
+
if (matches.length === 0) {
|
|
190650
|
+
return yield* new SpaceRoleNotFoundError({
|
|
190651
|
+
identifier: NonEmptyString2.make(role),
|
|
190652
|
+
spaceType
|
|
190653
|
+
});
|
|
190654
|
+
}
|
|
190655
|
+
if (matches.length > 1) {
|
|
190656
|
+
return yield* new SpaceRoleIdentifierAmbiguousError({
|
|
190657
|
+
identifier: NonEmptyString2.make(role),
|
|
190658
|
+
spaceType,
|
|
190659
|
+
matches: matches.map((match16) => ({
|
|
190660
|
+
id: RoleId.make(match16._id),
|
|
190661
|
+
name: NonEmptyString2.make(match16.name)
|
|
190662
|
+
}))
|
|
190663
|
+
});
|
|
190664
|
+
}
|
|
190665
|
+
return matches[0];
|
|
190666
|
+
});
|
|
190667
|
+
var findSpaceTypeRoles = (client, spaceType) => client.findAll(
|
|
190668
|
+
roleClass,
|
|
190669
|
+
hulyQuery({ attachedTo: spaceType._id }),
|
|
190670
|
+
{ limit: Math.max(spaceType.roles, 1) }
|
|
190671
|
+
);
|
|
190672
|
+
var writeSpaceRoleMembers = (client, space, spaceType, role, currentAssignments, members) => {
|
|
190673
|
+
const mixin = spaceRoleAssignmentsMixin(spaceType);
|
|
190674
|
+
const attributes = { ...currentAssignments, [role._id]: members };
|
|
190675
|
+
const objectId = toRef(space._id);
|
|
190676
|
+
const objectClass = toClassRef(space._class);
|
|
190677
|
+
const objectSpace = toRef(space.space);
|
|
190678
|
+
return hasSpaceRoleAssignmentMixin(space, spaceType) ? client.updateMixin(objectId, objectClass, objectSpace, mixin, attributes).pipe(Effect_exports.asVoid) : client.createMixin(objectId, objectClass, objectSpace, mixin, attributes).pipe(Effect_exports.asVoid);
|
|
190679
|
+
};
|
|
190680
|
+
var mutateSpaceRoleMembers = (params, mutateMembers) => Effect_exports.gen(function* () {
|
|
190681
|
+
const client = yield* HulyClient;
|
|
190682
|
+
const space = yield* findSpace(client, params);
|
|
190683
|
+
const spaceType = yield* requireTypedSpaceType(space);
|
|
190684
|
+
const spaceTypeDoc = yield* findSpaceType2(client, spaceType);
|
|
190685
|
+
const role = yield* resolveSpaceRole(client, spaceType, params.role);
|
|
190686
|
+
const validRoles = yield* findSpaceTypeRoles(client, spaceTypeDoc);
|
|
190687
|
+
const resolvedMembers = yield* resolveMembers(client, params.members);
|
|
190688
|
+
const currentAssignments = yield* strictSpaceRoleAssignments(
|
|
190689
|
+
space,
|
|
190690
|
+
spaceTypeDoc,
|
|
190691
|
+
new Set(validRoles.map((validRole) => validRole._id))
|
|
190692
|
+
);
|
|
190693
|
+
const currentMembers = sortStrings(currentAssignments[role._id] ?? []).map(toAccountUuid);
|
|
190694
|
+
const nextMembers = mutateMembers(currentMembers, resolvedMembers).map(toAccountUuid);
|
|
190695
|
+
const changed = !arraysEqual(currentMembers, nextMembers);
|
|
190696
|
+
if (changed) {
|
|
190697
|
+
yield* writeSpaceRoleMembers(client, space, spaceTypeDoc, role, currentAssignments, nextMembers);
|
|
190698
|
+
}
|
|
190699
|
+
return {
|
|
190700
|
+
id: SpaceId.make(space._id),
|
|
190701
|
+
roleId: RoleId.make(role._id),
|
|
190702
|
+
members: nextMembers.map((member) => AccountUuid.make(member)),
|
|
190703
|
+
changed
|
|
190704
|
+
};
|
|
190705
|
+
});
|
|
190406
190706
|
var mutateSpaceMembers = (params, mutateMembers) => Effect_exports.gen(function* () {
|
|
190407
190707
|
const client = yield* HulyClient;
|
|
190408
190708
|
const space = yield* findSpace(client, params);
|
|
@@ -190455,6 +190755,9 @@ var setSpaceOwners = (params) => Effect_exports.gen(function* () {
|
|
|
190455
190755
|
changed: changedOwners || changedMembers
|
|
190456
190756
|
};
|
|
190457
190757
|
});
|
|
190758
|
+
var setSpaceRoleMembers = (params) => mutateSpaceRoleMembers(params, (_currentMembers, resolvedMembers) => sortStrings(resolvedMembers).map(toAccountUuid));
|
|
190759
|
+
var addSpaceRoleMembers = (params) => mutateSpaceRoleMembers(params, mergeUniqueSortedAccountUuids);
|
|
190760
|
+
var removeSpaceRoleMembers = (params) => mutateSpaceRoleMembers(params, removeAccountUuids);
|
|
190458
190761
|
|
|
190459
190762
|
// src/mcp/tools/spaces.ts
|
|
190460
190763
|
var CATEGORY28 = "spaces";
|
|
@@ -190521,6 +190824,30 @@ var spaceTools = [
|
|
|
190521
190824
|
category: CATEGORY28,
|
|
190522
190825
|
inputSchema: setSpaceOwnersParamsJsonSchema,
|
|
190523
190826
|
handler: createToolHandler("set_space_owners", parseSetSpaceOwnersParams, setSpaceOwners)
|
|
190827
|
+
},
|
|
190828
|
+
{
|
|
190829
|
+
name: "set_space_role_members",
|
|
190830
|
+
description: "Replace members assigned to one role on a typed Huly space while preserving all other role assignments. Role accepts a raw role _id or exact role name from the space's SpaceType. Members accept account UUID, exact email, or exact person display name; pass members=[] to clear this role.",
|
|
190831
|
+
category: CATEGORY28,
|
|
190832
|
+
inputSchema: setSpaceRoleMembersParamsJsonSchema,
|
|
190833
|
+
annotations: { idempotentHint: true, destructiveHint: false },
|
|
190834
|
+
handler: createToolHandler("set_space_role_members", parseSetSpaceRoleMembersParams, setSpaceRoleMembers)
|
|
190835
|
+
},
|
|
190836
|
+
{
|
|
190837
|
+
name: "add_space_role_members",
|
|
190838
|
+
description: "Idempotently add members to one role on a typed Huly space while preserving all other role assignments. Role accepts a raw role _id or exact role name from the space's SpaceType. Members accept account UUID, exact email, or exact person display name.",
|
|
190839
|
+
category: CATEGORY28,
|
|
190840
|
+
inputSchema: spaceRoleMemberMutationParamsJsonSchema,
|
|
190841
|
+
annotations: { idempotentHint: true, destructiveHint: false },
|
|
190842
|
+
handler: createToolHandler("add_space_role_members", parseSpaceRoleMemberMutationParams, addSpaceRoleMembers)
|
|
190843
|
+
},
|
|
190844
|
+
{
|
|
190845
|
+
name: "remove_space_role_members",
|
|
190846
|
+
description: "Idempotently remove members from one role on a typed Huly space while preserving all other role assignments. Role accepts a raw role _id or exact role name from the space's SpaceType. Members accept account UUID, exact email, or exact person display name.",
|
|
190847
|
+
category: CATEGORY28,
|
|
190848
|
+
inputSchema: spaceRoleMemberMutationParamsJsonSchema,
|
|
190849
|
+
annotations: { idempotentHint: true, destructiveHint: false },
|
|
190850
|
+
handler: createToolHandler("remove_space_role_members", parseSpaceRoleMemberMutationParams, removeSpaceRoleMembers)
|
|
190524
190851
|
}
|
|
190525
190852
|
];
|
|
190526
190853
|
|