@firfi/huly-mcp 0.11.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -150748,6 +150748,7 @@ var MasterTagNotFoundError = class extends Schema_exports.TaggedError()(
150748
150748
  };
150749
150749
 
150750
150750
  // src/huly/errors-contacts.ts
150751
+ var MIN_AMBIGUOUS_PERSON_MATCHES = 2;
150751
150752
  var PersonNotFoundError = class extends Schema_exports.TaggedError()(
150752
150753
  "PersonNotFoundError",
150753
150754
  {
@@ -150758,6 +150759,17 @@ var PersonNotFoundError = class extends Schema_exports.TaggedError()(
150758
150759
  return `Person '${this.identifier}' not found`;
150759
150760
  }
150760
150761
  };
150762
+ var PersonIdentifierAmbiguousError = class extends Schema_exports.TaggedError()(
150763
+ "PersonIdentifierAmbiguousError",
150764
+ {
150765
+ identifier: Schema_exports.String,
150766
+ matches: Schema_exports.Number.pipe(Schema_exports.int(), Schema_exports.greaterThanOrEqualTo(MIN_AMBIGUOUS_PERSON_MATCHES))
150767
+ }
150768
+ ) {
150769
+ get message() {
150770
+ return `Person identifier '${this.identifier}' matched ${this.matches} people; use an exact email address instead`;
150771
+ }
150772
+ };
150761
150773
  var OrganizationNotFoundError = class extends Schema_exports.TaggedError()(
150762
150774
  "OrganizationNotFoundError",
150763
150775
  {
@@ -151147,6 +151159,26 @@ var DirectMessageIdentifierAmbiguousError = class extends Schema_exports.TaggedE
151147
151159
  return `Direct message '${this.identifier}' is ambiguous (${this.matches} matches); use the DM _id`;
151148
151160
  }
151149
151161
  };
151162
+ var CannotDirectMessageSelfError = class extends Schema_exports.TaggedError()(
151163
+ "CannotDirectMessageSelfError",
151164
+ {
151165
+ identifier: Schema_exports.String
151166
+ }
151167
+ ) {
151168
+ get message() {
151169
+ return `Cannot start a direct-message conversation with yourself ('${this.identifier}')`;
151170
+ }
151171
+ };
151172
+ var PersonNotAnEmployeeError = class extends Schema_exports.TaggedError()(
151173
+ "PersonNotAnEmployeeError",
151174
+ {
151175
+ identifier: Schema_exports.String
151176
+ }
151177
+ ) {
151178
+ get message() {
151179
+ return `Person '${this.identifier}' is not a workspace member (no Huly account) and cannot receive direct messages`;
151180
+ }
151181
+ };
151150
151182
  var MessageNotFoundError = class extends Schema_exports.TaggedError()(
151151
151183
  "MessageNotFoundError",
151152
151184
  {
@@ -151395,6 +151427,7 @@ var HulyDomainError = Schema_exports.Union(
151395
151427
  IssueNotFoundError,
151396
151428
  ProjectNotFoundError,
151397
151429
  InvalidStatusError,
151430
+ PersonIdentifierAmbiguousError,
151398
151431
  PersonNotFoundError,
151399
151432
  OrganizationNotFoundError,
151400
151433
  OrganizationIdentifierAmbiguousError,
@@ -151411,9 +151444,11 @@ var HulyDomainError = Schema_exports.Union(
151411
151444
  CommentNotFoundError,
151412
151445
  MilestoneNotFoundError,
151413
151446
  ChannelNotFoundError,
151447
+ CannotDirectMessageSelfError,
151414
151448
  DirectMessageIdentifierAmbiguousError,
151415
151449
  DirectMessageNotFoundError,
151416
151450
  MessageNotFoundError,
151451
+ PersonNotAnEmployeeError,
151417
151452
  ThreadReplyNotFoundError,
151418
151453
  CalendarNotAccessibleError,
151419
151454
  EventNotFoundError,
@@ -171366,7 +171401,7 @@ var PostHog = class extends PostHogBackendClient {
171366
171401
  };
171367
171402
 
171368
171403
  // src/version.ts
171369
- var VERSION = true ? "0.11.0" : "0.0.0-dev";
171404
+ var VERSION = true ? "0.12.0" : "0.0.0-dev";
171370
171405
 
171371
171406
  // src/telemetry/posthog.ts
171372
171407
  var POSTHOG_API_KEY = "phc_TGfFqCGdnF0p68wuFzd5WSw1IsBvOJW0YgoMJDyZPjm";
@@ -171494,6 +171529,7 @@ var INVALID_PARAMS_TAGS = /* @__PURE__ */ new Set([
171494
171529
  "IssueNotFoundError",
171495
171530
  "ProjectNotFoundError",
171496
171531
  "InvalidStatusError",
171532
+ "PersonIdentifierAmbiguousError",
171497
171533
  "PersonNotFoundError",
171498
171534
  "OrganizationNotFoundError",
171499
171535
  "OrganizationIdentifierAmbiguousError",
@@ -171510,6 +171546,8 @@ var INVALID_PARAMS_TAGS = /* @__PURE__ */ new Set([
171510
171546
  "ChannelNotFoundError",
171511
171547
  "DirectMessageIdentifierAmbiguousError",
171512
171548
  "DirectMessageNotFoundError",
171549
+ "CannotDirectMessageSelfError",
171550
+ "PersonNotAnEmployeeError",
171513
171551
  "MessageNotFoundError",
171514
171552
  "ThreadReplyNotFoundError",
171515
171553
  "CalendarNotAccessibleError",
@@ -171600,21 +171638,58 @@ var ActivityCount = Schema_exports.NonNegativeInt.annotations({
171600
171638
  description: "Non-negative integer count for activity replies or reactions"
171601
171639
  });
171602
171640
  var ActivityAction = Schema_exports.Literal("create", "update", "remove");
171641
+ var hasAll = (...values4) => values4.every((value3) => value3 !== void 0);
171603
171642
  var ListActivityParamsSchema = Schema_exports.Struct({
171604
- objectId: NonEmptyString2.annotations({
171605
- description: "ID of the object to get activity for"
171606
- }),
171607
- objectClass: ObjectClassName.annotations({
171608
- description: "Class of the object (e.g., 'tracker:class:Issue')"
171609
- }),
171643
+ objectId: Schema_exports.optional(NonEmptyString2.annotations({
171644
+ description: "Advanced: internal Huly object ID to get activity for. Use with objectClass. Prefer project+issueIdentifier, teamspace+document, or channel when available."
171645
+ })),
171646
+ objectClass: Schema_exports.optional(ObjectClassName.annotations({
171647
+ description: "Advanced: internal Huly object class for objectId, such as 'tracker:class:Issue'. Use with objectId."
171648
+ })),
171649
+ project: Schema_exports.optional(ProjectIdentifier.annotations({
171650
+ description: "Project identifier for issue activity, e.g. 'HULY'. Use with issueIdentifier."
171651
+ })),
171652
+ issueIdentifier: Schema_exports.optional(IssueIdentifier.annotations({
171653
+ description: "Issue identifier for issue activity, e.g. 'HULY-123' or '123'. Use with project."
171654
+ })),
171655
+ teamspace: Schema_exports.optional(TeamspaceIdentifier.annotations({
171656
+ description: "Teamspace name or ID for document activity. Use with document."
171657
+ })),
171658
+ document: Schema_exports.optional(DocumentIdentifier.annotations({
171659
+ description: "Document title or ID for document activity. Use with teamspace."
171660
+ })),
171661
+ channel: Schema_exports.optional(ChannelIdentifier.annotations({
171662
+ description: "Channel name or ID for channel activity."
171663
+ })),
171610
171664
  limit: Schema_exports.optional(
171611
171665
  LimitParam.annotations({
171612
171666
  description: "Maximum number of activity messages to return (default: 50)"
171613
171667
  })
171614
171668
  )
171615
- }).annotations({
171669
+ }).pipe(
171670
+ Schema_exports.filter((params) => {
171671
+ const rawObjectMode = hasAll(params.objectId, params.objectClass);
171672
+ const issueMode = hasAll(params.project, params.issueIdentifier);
171673
+ const documentMode = hasAll(params.teamspace, params.document);
171674
+ const channelMode = params.channel !== void 0;
171675
+ const modeCount = [rawObjectMode, issueMode, documentMode, channelMode].filter(Boolean).length;
171676
+ if (params.objectId !== void 0 !== (params.objectClass !== void 0)) {
171677
+ return "Provide both objectId and objectClass for raw object activity, or use a friendly target mode.";
171678
+ }
171679
+ if (params.project !== void 0 !== (params.issueIdentifier !== void 0)) {
171680
+ return "Provide both project and issueIdentifier for issue activity.";
171681
+ }
171682
+ if (params.teamspace !== void 0 !== (params.document !== void 0)) {
171683
+ return "Provide both teamspace and document for document activity.";
171684
+ }
171685
+ if (modeCount !== 1) {
171686
+ return "Choose exactly one activity target mode: objectId+objectClass, project+issueIdentifier, teamspace+document, or channel.";
171687
+ }
171688
+ return void 0;
171689
+ })
171690
+ ).annotations({
171616
171691
  title: "ListActivityParams",
171617
- description: "Parameters for listing activity on an object"
171692
+ description: "Parameters for listing activity on a Huly object. Prefer friendly identifiers; raw objectId+objectClass is for advanced callers."
171618
171693
  });
171619
171694
  var AddReactionParamsSchema = Schema_exports.Struct({
171620
171695
  messageId: ActivityMessageId.annotations({
@@ -171687,7 +171762,66 @@ var ListMentionsParamsSchema = Schema_exports.Struct({
171687
171762
  title: "ListMentionsParams",
171688
171763
  description: "Parameters for listing mentions of the current user"
171689
171764
  });
171690
- var listActivityParamsJsonSchema = JSONSchema_exports.make(ListActivityParamsSchema);
171765
+ var activityLimitJsonSchema = {
171766
+ type: "integer",
171767
+ minimum: 1,
171768
+ maximum: MAX_LIMIT,
171769
+ description: "Maximum number of activity messages to return (default: 50)"
171770
+ };
171771
+ var targetStringJsonSchema = (description) => ({
171772
+ type: "string",
171773
+ minLength: 1,
171774
+ description
171775
+ });
171776
+ var listActivityParamsJsonSchema = {
171777
+ type: "object",
171778
+ description: "Choose exactly one target mode for activity lookup: project+issueIdentifier, teamspace+document, channel, or objectId+objectClass.",
171779
+ oneOf: [
171780
+ {
171781
+ title: "Issue activity target",
171782
+ type: "object",
171783
+ additionalProperties: false,
171784
+ required: ["project", "issueIdentifier"],
171785
+ properties: {
171786
+ project: targetStringJsonSchema("Project identifier for issue activity, e.g. 'HULY'."),
171787
+ issueIdentifier: targetStringJsonSchema("Issue identifier for issue activity, e.g. 'HULY-123' or '123'."),
171788
+ limit: activityLimitJsonSchema
171789
+ }
171790
+ },
171791
+ {
171792
+ title: "Document activity target",
171793
+ type: "object",
171794
+ additionalProperties: false,
171795
+ required: ["teamspace", "document"],
171796
+ properties: {
171797
+ teamspace: targetStringJsonSchema("Teamspace name or ID for document activity."),
171798
+ document: targetStringJsonSchema("Document title or ID for document activity."),
171799
+ limit: activityLimitJsonSchema
171800
+ }
171801
+ },
171802
+ {
171803
+ title: "Channel activity target",
171804
+ type: "object",
171805
+ additionalProperties: false,
171806
+ required: ["channel"],
171807
+ properties: {
171808
+ channel: targetStringJsonSchema("Channel name or ID for channel activity."),
171809
+ limit: activityLimitJsonSchema
171810
+ }
171811
+ },
171812
+ {
171813
+ title: "Raw Huly object activity target",
171814
+ type: "object",
171815
+ additionalProperties: false,
171816
+ required: ["objectId", "objectClass"],
171817
+ properties: {
171818
+ objectId: targetStringJsonSchema("Internal Huly object ID to get activity for."),
171819
+ objectClass: targetStringJsonSchema("Internal Huly object class for objectId, such as 'tracker:class:Issue'."),
171820
+ limit: activityLimitJsonSchema
171821
+ }
171822
+ }
171823
+ ]
171824
+ };
171691
171825
  var addReactionParamsJsonSchema = JSONSchema_exports.make(AddReactionParamsSchema);
171692
171826
  var removeReactionParamsJsonSchema = JSONSchema_exports.make(RemoveReactionParamsSchema);
171693
171827
  var listReactionsParamsJsonSchema = JSONSchema_exports.make(ListReactionsParamsSchema);
@@ -171754,6 +171888,9 @@ var ListSavedMessagesResultSchema = Schema_exports.Array(SavedMessageWireSchema)
171754
171888
  var ListMentionsResultSchema = Schema_exports.Array(MentionWireSchema);
171755
171889
 
171756
171890
  // src/huly/operations/activity.ts
171891
+ var import_core22 = __toESM(require_lib4(), 1);
171892
+
171893
+ // src/huly/operations/channels.ts
171757
171894
  var import_core19 = __toESM(require_lib4(), 1);
171758
171895
 
171759
171896
  // src/huly/operations/query-helpers.ts
@@ -171795,552 +171932,311 @@ var task = require_lib34().default;
171795
171932
  var time3 = require_lib35().default;
171796
171933
  var tracker = require_lib36().default;
171797
171934
 
171798
- // src/huly/operations/activity.ts
171799
- var optionalTimestamp = (value3) => value3 === void 0 ? void 0 : Timestamp.make(value3);
171800
- var optionalNullableTimestamp = (value3) => value3 === void 0 || value3 === null ? value3 : Timestamp.make(value3);
171801
- var optionalActivityCount = (value3) => value3 === void 0 ? void 0 : ActivityCount.make(value3);
171802
- var optionalPersonId = (value3) => value3 === void 0 || value3 === "" ? void 0 : PersonId.make(value3);
171803
- var serverPopulatedCreateBy = "";
171804
- var listActivity = (params) => Effect_exports.gen(function* () {
171805
- const client = yield* HulyClient;
171806
- const limit = clampLimit(params.limit);
171807
- const messages = yield* client.findAll(
171808
- activity.class.ActivityMessage,
171809
- {
171810
- attachedTo: toRef(params.objectId),
171811
- attachedToClass: toRef(params.objectClass)
171812
- },
171935
+ // src/huly/operations/channel-messages-shared.ts
171936
+ var findChannelMessage = (params) => Effect_exports.gen(function* () {
171937
+ const { channel, client } = yield* findChannel(params.channel);
171938
+ const message = yield* client.findOne(
171939
+ chunter.class.ChatMessage,
171813
171940
  {
171814
- limit,
171815
- sort: {
171816
- modifiedOn: import_core19.SortingOrder.Descending
171817
- }
171941
+ _id: toRef(params.messageId),
171942
+ space: channel._id
171818
171943
  }
171819
171944
  );
171820
- const result = messages.map((msg) => ({
171821
- id: ActivityMessageId.make(msg._id),
171822
- objectId: NonEmptyString2.make(msg.attachedTo),
171823
- objectClass: ObjectClassName.make(msg.attachedToClass),
171824
- modifiedBy: PersonId.make(msg.modifiedBy),
171825
- modifiedOn: optionalTimestamp(msg.modifiedOn),
171826
- isPinned: msg.isPinned,
171827
- replies: optionalActivityCount(msg.replies),
171828
- reactions: optionalActivityCount(msg.reactions),
171829
- editedOn: optionalNullableTimestamp(msg.editedOn)
171830
- }));
171831
- return result;
171945
+ if (message === void 0) {
171946
+ return yield* new MessageNotFoundError({
171947
+ messageId: params.messageId,
171948
+ channel: params.channel
171949
+ });
171950
+ }
171951
+ return { client, channel, message };
171832
171952
  });
171833
- var addReaction = (params) => Effect_exports.gen(function* () {
171834
- const client = yield* HulyClient;
171835
- const message = yield* findOneOrFail(
171836
- client,
171837
- activity.class.ActivityMessage,
171838
- { _id: toRef(params.messageId) },
171839
- () => new ActivityMessageNotFoundError({ messageId: params.messageId })
171840
- );
171841
- const reactionId = (0, import_core19.generateId)();
171842
- const reactionData = {
171843
- emoji: params.emoji,
171844
- createBy: serverPopulatedCreateBy
171953
+
171954
+ // src/huly/operations/channels-messages.ts
171955
+ var updateChannelMessage = (params) => Effect_exports.gen(function* () {
171956
+ const { channel, client, message } = yield* findChannelMessage(params);
171957
+ const markupUrlConfig = client.markupUrlConfig;
171958
+ const markup = markdownToMarkupString(params.body, markupUrlConfig);
171959
+ const now2 = yield* Clock_exports.currentTimeMillis;
171960
+ const updateOps = {
171961
+ message: markup,
171962
+ editedOn: now2
171845
171963
  };
171846
- yield* client.addCollection(
171847
- activity.class.Reaction,
171848
- message.space,
171964
+ yield* client.updateDoc(
171965
+ chunter.class.ChatMessage,
171966
+ channel._id,
171849
171967
  message._id,
171850
- activity.class.ActivityMessage,
171851
- "reactions",
171852
- reactionData,
171853
- reactionId
171968
+ updateOps
171854
171969
  );
171855
- return {
171856
- reactionId: ReactionId.make(reactionId),
171857
- messageId: ActivityMessageId.make(params.messageId)
171858
- };
171970
+ return { id: MessageId.make(message._id), updated: true };
171859
171971
  });
171860
- var removeReaction = (params) => Effect_exports.gen(function* () {
171861
- const client = yield* HulyClient;
171862
- const reaction = yield* findOneOrFail(
171863
- client,
171864
- activity.class.Reaction,
171865
- {
171866
- attachedTo: toRef(params.messageId),
171867
- emoji: params.emoji
171868
- },
171869
- () => new ReactionNotFoundError({
171870
- messageId: params.messageId,
171871
- emoji: params.emoji
171872
- })
171873
- );
171972
+ var deleteChannelMessage = (params) => Effect_exports.gen(function* () {
171973
+ const { channel, client, message } = yield* findChannelMessage(params);
171874
171974
  yield* client.removeDoc(
171875
- activity.class.Reaction,
171876
- reaction.space,
171877
- reaction._id
171878
- );
171879
- return {
171880
- messageId: ActivityMessageId.make(params.messageId),
171881
- removed: true
171882
- };
171883
- });
171884
- var listReactions = (params) => Effect_exports.gen(function* () {
171885
- const client = yield* HulyClient;
171886
- const limit = clampLimit(params.limit);
171887
- const reactions = yield* client.findAll(
171888
- activity.class.Reaction,
171889
- {
171890
- attachedTo: toRef(params.messageId)
171891
- },
171892
- { limit }
171975
+ chunter.class.ChatMessage,
171976
+ channel._id,
171977
+ message._id
171893
171978
  );
171894
- const result = reactions.map((r) => ({
171895
- id: ReactionId.make(r._id),
171896
- messageId: ActivityMessageId.make(r.attachedTo),
171897
- emoji: EmojiCode.make(r.emoji),
171898
- createdBy: optionalPersonId(r.createBy)
171899
- }));
171900
- return result;
171979
+ return { id: MessageId.make(message._id), deleted: true };
171901
171980
  });
171902
- var saveMessage = (params) => Effect_exports.gen(function* () {
171981
+
171982
+ // src/huly/operations/channels.ts
171983
+ var personIdsAsSocialIdentityRefs = (ids3) => ids3;
171984
+ var findChannel = (identifier2) => Effect_exports.gen(function* () {
171903
171985
  const client = yield* HulyClient;
171904
- const message = yield* findOneOrFail(
171986
+ const channel = yield* findByNameOrId(
171905
171987
  client,
171906
- activity.class.ActivityMessage,
171907
- { _id: toRef(params.messageId) },
171908
- () => new ActivityMessageNotFoundError({ messageId: params.messageId })
171909
- );
171910
- const savedId = (0, import_core19.generateId)();
171911
- yield* client.createDoc(
171912
- activity.class.SavedMessage,
171913
- core.space.Workspace,
171914
- {
171915
- attachedTo: message._id
171916
- },
171917
- savedId
171988
+ chunter.class.Channel,
171989
+ { name: identifier2 },
171990
+ { _id: toRef(identifier2) }
171918
171991
  );
171919
- return {
171920
- savedId: SavedMessageId.make(savedId),
171921
- messageId: ActivityMessageId.make(params.messageId)
171922
- };
171992
+ if (channel === void 0) {
171993
+ return yield* new ChannelNotFoundError({ identifier: identifier2 });
171994
+ }
171995
+ return { client, channel };
171923
171996
  });
171924
- var unsaveMessage = (params) => Effect_exports.gen(function* () {
171925
- const client = yield* HulyClient;
171926
- const saved = yield* findOneOrFail(
171927
- client,
171928
- activity.class.SavedMessage,
171929
- {
171930
- attachedTo: toRef(params.messageId)
171931
- },
171932
- () => new SavedMessageNotFoundError({ messageId: params.messageId })
171997
+ var buildSocialIdToPersonNameMap = (client, socialIds) => Effect_exports.gen(function* () {
171998
+ if (socialIds.length === 0) {
171999
+ return /* @__PURE__ */ new Map();
172000
+ }
172001
+ const socialIdentities = yield* client.findAll(
172002
+ contact.class.SocialIdentity,
172003
+ { _id: { $in: personIdsAsSocialIdentityRefs(socialIds) } }
171933
172004
  );
171934
- yield* client.removeDoc(
171935
- activity.class.SavedMessage,
171936
- saved.space,
171937
- saved._id
172005
+ if (socialIdentities.length === 0) {
172006
+ return /* @__PURE__ */ new Map();
172007
+ }
172008
+ const personRefs = [...new Set(socialIdentities.map((si) => si.attachedTo))];
172009
+ const persons = yield* client.findAll(
172010
+ contact.class.Person,
172011
+ { _id: { $in: personRefs } }
171938
172012
  );
171939
- return {
171940
- messageId: ActivityMessageId.make(params.messageId),
171941
- removed: true
171942
- };
171943
- });
171944
- var listSavedMessages = (params) => Effect_exports.gen(function* () {
171945
- const client = yield* HulyClient;
171946
- const limit = clampLimit(params.limit);
171947
- const saved = yield* client.findAll(
171948
- activity.class.SavedMessage,
171949
- {},
171950
- { limit }
172013
+ const personById = new Map(persons.map((p) => [p._id, p]));
172014
+ const result = /* @__PURE__ */ new Map();
172015
+ for (const si of socialIdentities) {
172016
+ const person = personById.get(si.attachedTo);
172017
+ if (person !== void 0) {
172018
+ result.set(si._id, person.name);
172019
+ }
172020
+ }
172021
+ return result;
172022
+ });
172023
+ var buildAccountUuidToNameMap = (client, accountUuids) => Effect_exports.gen(function* () {
172024
+ if (accountUuids.length === 0) {
172025
+ return /* @__PURE__ */ new Map();
172026
+ }
172027
+ const employees = yield* client.findAll(
172028
+ contact.mixin.Employee,
172029
+ { personUuid: { $in: accountUuids } }
171951
172030
  );
171952
- const result = saved.map((s) => ({
171953
- id: SavedMessageId.make(s._id),
171954
- messageId: ActivityMessageId.make(s.attachedTo)
171955
- }));
172031
+ const result = /* @__PURE__ */ new Map();
172032
+ for (const emp of employees) {
172033
+ if (emp.personUuid !== void 0) {
172034
+ result.set(emp.personUuid, emp.name);
172035
+ }
172036
+ }
171956
172037
  return result;
171957
172038
  });
171958
- var listMentions = (params) => Effect_exports.gen(function* () {
172039
+ var listChannels = (params) => Effect_exports.gen(function* () {
171959
172040
  const client = yield* HulyClient;
172041
+ const query = {};
172042
+ if (!params.includeArchived) {
172043
+ query.archived = false;
172044
+ }
172045
+ if (params.nameSearch !== void 0 && params.nameSearch.trim() !== "") {
172046
+ query.name = { $like: `%${escapeLikeWildcards(params.nameSearch)}%` };
172047
+ }
172048
+ if (params.nameRegex !== void 0 && params.nameRegex.trim() !== "") {
172049
+ query.name = { $regex: params.nameRegex };
172050
+ }
172051
+ if (params.topicSearch !== void 0 && params.topicSearch.trim() !== "") {
172052
+ query.topic = { $like: `%${escapeLikeWildcards(params.topicSearch)}%` };
172053
+ }
171960
172054
  const limit = clampLimit(params.limit);
171961
- const mentions = yield* client.findAll(
171962
- activity.class.UserMentionInfo,
171963
- {},
172055
+ const channels = yield* client.findAll(
172056
+ chunter.class.Channel,
172057
+ query,
171964
172058
  {
171965
172059
  limit,
171966
172060
  sort: {
171967
- modifiedOn: import_core19.SortingOrder.Descending
172061
+ name: import_core19.SortingOrder.Ascending
171968
172062
  }
171969
172063
  }
171970
172064
  );
171971
- const result = mentions.map((m) => ({
171972
- id: MentionId.make(m._id),
171973
- messageId: ActivityMessageId.make(m.attachedTo),
171974
- userId: PersonId.make(m.user),
171975
- content: m.content
172065
+ const summaries = channels.map((ch) => ({
172066
+ id: ChannelId.make(ch._id),
172067
+ name: ChannelName.make(ch.name),
172068
+ topic: ch.topic || void 0,
172069
+ private: ch.private,
172070
+ archived: ch.archived,
172071
+ members: ch.members.length,
172072
+ messages: ch.messages,
172073
+ modifiedOn: ch.modifiedOn
171976
172074
  }));
172075
+ return summaries;
172076
+ });
172077
+ var getChannel = (params) => Effect_exports.gen(function* () {
172078
+ const { channel, client } = yield* findChannel(params.channel);
172079
+ const memberNames = channel.members.length > 0 ? yield* Effect_exports.gen(function* () {
172080
+ const accountUuidToName = yield* buildAccountUuidToNameMap(client, channel.members);
172081
+ return channel.members.map((m) => accountUuidToName.get(m)).filter((n) => n !== void 0);
172082
+ }) : void 0;
172083
+ const result = {
172084
+ id: ChannelId.make(channel._id),
172085
+ name: ChannelName.make(channel.name),
172086
+ topic: channel.topic || void 0,
172087
+ description: channel.description || void 0,
172088
+ private: channel.private,
172089
+ archived: channel.archived,
172090
+ members: memberNames?.map((m) => PersonName.make(m)),
172091
+ messages: channel.messages,
172092
+ modifiedOn: channel.modifiedOn,
172093
+ createdOn: channel.createdOn
172094
+ };
171977
172095
  return result;
171978
172096
  });
171979
-
171980
- // src/mcp/tools/registry.ts
171981
- var deriveTitle = (name) => name.split("_").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
171982
- var READ_PREFIXES = ["list_", "get_", "search_", "fulltext_", "download_", "preview_"];
171983
- var CREATE_PREFIXES = ["create_", "add_", "upload_", "send_", "log_"];
171984
- var UPDATE_PREFIXES = [
171985
- "update_",
171986
- "edit_",
171987
- "set_",
171988
- "pin_",
171989
- "unpin_",
171990
- "mark_",
171991
- "archive_",
171992
- "start_",
171993
- "stop_",
171994
- "save_",
171995
- "unsave_",
171996
- "remove_",
171997
- "move_"
171998
- ];
171999
- var DELETE_PREFIXES = ["delete_"];
172000
- var matchesPrefix = (name, prefixes) => prefixes.some((p) => name.startsWith(p));
172001
- var deriveAnnotations = (name) => {
172002
- const title = deriveTitle(name);
172003
- if (matchesPrefix(name, READ_PREFIXES)) {
172004
- return { title, readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
172005
- }
172006
- if (matchesPrefix(name, CREATE_PREFIXES)) {
172007
- return { title, readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
172008
- }
172009
- if (matchesPrefix(name, UPDATE_PREFIXES)) {
172010
- return { title, readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false };
172011
- }
172012
- if (matchesPrefix(name, DELETE_PREFIXES)) {
172013
- return { title, readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false };
172014
- }
172015
- return { title, readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false };
172016
- };
172017
- var resolveAnnotations = (tool) => ({
172018
- ...deriveAnnotations(tool.name),
172019
- ...tool.annotations
172097
+ var createChannel = (params) => Effect_exports.gen(function* () {
172098
+ const client = yield* HulyClient;
172099
+ const channelId = (0, import_core19.generateId)();
172100
+ const channelData = {
172101
+ name: params.name,
172102
+ topic: params.topic || "",
172103
+ description: "",
172104
+ private: params.private ?? false,
172105
+ archived: false,
172106
+ members: [client.getAccountUuid()],
172107
+ owners: [client.getAccountUuid()]
172108
+ };
172109
+ yield* client.createDoc(
172110
+ chunter.class.Channel,
172111
+ toRef(channelId),
172112
+ channelData,
172113
+ channelId
172114
+ );
172115
+ return { id: ChannelId.make(channelId), name: ChannelName.make(params.name) };
172020
172116
  });
172021
- var encodeOutput = (schema, result) => Schema_exports.encodeUnknownSync(schema)(result);
172022
- var provideHulyClient = (args2) => (effect2) => Either_exports.right(effect2.pipe(Effect_exports.provideService(HulyClient, args2.hulyClient)));
172023
- var provideStorageClient = (args2) => (effect2) => Either_exports.right(effect2.pipe(Effect_exports.provideService(HulyStorageClient, args2.storageClient)));
172024
- var provideCombinedClient = (args2) => (effect2) => Either_exports.right(
172025
- effect2.pipe(
172026
- Effect_exports.provideService(HulyClient, args2.hulyClient),
172027
- Effect_exports.provideService(HulyStorageClient, args2.storageClient)
172028
- )
172029
- );
172030
- var provideWorkspaceClient = (args2) => (effect2) => args2.workspaceClient !== void 0 ? Either_exports.right(effect2.pipe(Effect_exports.provideService(WorkspaceClient, args2.workspaceClient))) : Either_exports.left(mapDomainErrorToMcp(new HulyError({ message: "WorkspaceClient not available" })));
172031
- var createHandler = (toolName, provide4, parse5, operation, encode8) => async (args2, hulyClient, storageClient, workspaceClient) => {
172032
- const parseResult = await Effect_exports.runPromiseExit(parse5(args2));
172033
- if (Exit_exports.isFailure(parseResult)) {
172034
- return mapParseCauseToMcp(parseResult.cause, toolName);
172035
- }
172036
- const provided = provide4({ hulyClient, storageClient, workspaceClient })(operation(parseResult.value));
172037
- if (Either_exports.isLeft(provided)) {
172038
- return provided.left;
172117
+ var updateChannel = (params) => Effect_exports.gen(function* () {
172118
+ const { channel, client } = yield* findChannel(params.channel);
172119
+ const updateOps = {};
172120
+ if (params.name !== void 0) {
172121
+ updateOps.name = params.name;
172039
172122
  }
172040
- const operationResult = await Effect_exports.runPromiseExit(provided.right);
172041
- if (Exit_exports.isFailure(operationResult)) {
172042
- return mapDomainCauseToMcp(operationResult.cause);
172123
+ if (params.topic !== void 0) {
172124
+ updateOps.topic = params.topic;
172043
172125
  }
172044
- try {
172045
- const output = encode8 !== void 0 ? encode8(operationResult.value) : operationResult.value;
172046
- return createSuccessResponse(output);
172047
- } catch {
172048
- return mapDomainErrorToMcp(new HulyError({ message: `Tool ${toolName} produced invalid output` }));
172126
+ if (Object.keys(updateOps).length === 0) {
172127
+ return { id: ChannelId.make(channel._id), updated: false };
172049
172128
  }
172050
- };
172051
- var createToolHandler = (toolName, parse5, operation) => createHandler(toolName, provideHulyClient, parse5, operation);
172052
- var createEncodedToolHandler = (toolName, parse5, operation, outputSchema) => createHandler(
172053
- toolName,
172054
- provideHulyClient,
172055
- parse5,
172056
- operation,
172057
- (result) => encodeOutput(outputSchema, result)
172058
- );
172059
- var createStorageToolHandler = (toolName, parse5, operation) => createHandler(toolName, provideStorageClient, parse5, operation);
172060
- var createCombinedToolHandler = (toolName, parse5, operation) => createHandler(toolName, provideCombinedClient, parse5, operation);
172061
- var createEncodedWorkspaceToolHandler = (toolName, parse5, operation, outputSchema) => createHandler(
172062
- toolName,
172063
- provideWorkspaceClient,
172064
- parse5,
172065
- operation,
172066
- (result) => encodeOutput(outputSchema, result)
172067
- );
172068
- var createEncodedNoParamsWorkspaceToolHandler = (toolName, operation, outputSchema) => createHandler(
172069
- toolName,
172070
- provideWorkspaceClient,
172071
- () => Effect_exports.succeed(void 0),
172072
- operation,
172073
- (result) => encodeOutput(outputSchema, result)
172074
- );
172075
-
172076
- // src/mcp/tools/activity.ts
172077
- var CATEGORY = "activity";
172078
- var activityTools = [
172079
- {
172080
- name: "list_activity",
172081
- description: "List activity messages for a Huly object. Returns activity sorted by date (newest first).",
172082
- category: CATEGORY,
172083
- inputSchema: listActivityParamsJsonSchema,
172084
- handler: createEncodedToolHandler(
172085
- "list_activity",
172086
- parseListActivityParams,
172087
- listActivity,
172088
- ListActivityResultSchema
172089
- )
172090
- },
172091
- {
172092
- name: "add_reaction",
172093
- description: "Add an emoji reaction to an activity message.",
172094
- category: CATEGORY,
172095
- inputSchema: addReactionParamsJsonSchema,
172096
- handler: createEncodedToolHandler(
172097
- "add_reaction",
172098
- parseAddReactionParams,
172099
- addReaction,
172100
- AddReactionResultSchema
172101
- )
172102
- },
172103
- {
172104
- name: "remove_reaction",
172105
- description: "Remove an emoji reaction from an activity message.",
172106
- category: CATEGORY,
172107
- inputSchema: removeReactionParamsJsonSchema,
172108
- handler: createEncodedToolHandler(
172109
- "remove_reaction",
172110
- parseRemoveReactionParams,
172111
- removeReaction,
172112
- RemoveReactionResultSchema
172113
- )
172114
- },
172115
- {
172116
- name: "list_reactions",
172117
- description: "List reactions on an activity message.",
172118
- category: CATEGORY,
172119
- inputSchema: listReactionsParamsJsonSchema,
172120
- handler: createEncodedToolHandler(
172121
- "list_reactions",
172122
- parseListReactionsParams,
172123
- listReactions,
172124
- ListReactionsResultSchema
172125
- )
172126
- },
172127
- {
172128
- name: "save_message",
172129
- description: "Save/bookmark an activity message for later reference.",
172130
- category: CATEGORY,
172131
- inputSchema: saveMessageParamsJsonSchema,
172132
- handler: createEncodedToolHandler(
172133
- "save_message",
172134
- parseSaveMessageParams,
172135
- saveMessage,
172136
- SaveMessageResultSchema
172137
- )
172138
- },
172139
- {
172140
- name: "unsave_message",
172141
- description: "Remove an activity message from saved/bookmarks.",
172142
- category: CATEGORY,
172143
- inputSchema: unsaveMessageParamsJsonSchema,
172144
- handler: createEncodedToolHandler(
172145
- "unsave_message",
172146
- parseUnsaveMessageParams,
172147
- unsaveMessage,
172148
- UnsaveMessageResultSchema
172149
- )
172150
- },
172151
- {
172152
- name: "list_saved_messages",
172153
- description: "List saved/bookmarked activity messages.",
172154
- category: CATEGORY,
172155
- inputSchema: listSavedMessagesParamsJsonSchema,
172156
- handler: createEncodedToolHandler(
172157
- "list_saved_messages",
172158
- parseListSavedMessagesParams,
172159
- listSavedMessages,
172160
- ListSavedMessagesResultSchema
172161
- )
172162
- },
172163
- {
172164
- name: "list_mentions",
172165
- description: "List @mentions of the current user in activity messages.",
172166
- category: CATEGORY,
172167
- inputSchema: listMentionsParamsJsonSchema,
172168
- handler: createEncodedToolHandler(
172169
- "list_mentions",
172170
- parseListMentionsParams,
172171
- listMentions,
172172
- ListMentionsResultSchema
172173
- )
172174
- }
172175
- ];
172176
-
172177
- // src/domain/schemas/attachments.ts
172178
- var ListAttachmentsParamsSchema = Schema_exports.Struct({
172179
- objectId: NonEmptyString2.annotations({
172180
- description: "ID of the parent object (issue, document, etc.)"
172181
- }),
172182
- objectClass: ObjectClassName.annotations({
172183
- description: "Class of the parent object (e.g., 'tracker:class:Issue', 'document:class:Document')"
172184
- }),
172185
- limit: Schema_exports.optional(
172186
- LimitParam.annotations({
172187
- description: "Maximum number of attachments to return (default: 50)"
172188
- })
172189
- )
172190
- }).annotations({
172191
- title: "ListAttachmentsParams",
172192
- description: "Parameters for listing attachments on an object"
172193
- });
172194
- var GetAttachmentParamsSchema = Schema_exports.Struct({
172195
- attachmentId: AttachmentId.annotations({
172196
- description: "Attachment ID"
172197
- })
172198
- }).annotations({
172199
- title: "GetAttachmentParams",
172200
- description: "Parameters for getting a single attachment"
172201
- });
172202
- var FileSourceFields = {
172203
- filename: NonEmptyString2.annotations({
172204
- description: "Name of the file"
172205
- }),
172206
- contentType: MimeType.annotations({
172207
- description: "MIME type of the file (e.g., 'image/png', 'application/pdf')"
172208
- }),
172209
- filePath: Schema_exports.optional(Schema_exports.String.annotations({
172210
- description: "Local file path to upload (preferred - avoids context flooding)"
172211
- })),
172212
- fileUrl: Schema_exports.optional(Schema_exports.String.annotations({
172213
- description: "URL to fetch file from (for remote files)"
172214
- })),
172215
- data: Schema_exports.optional(Schema_exports.String.annotations({
172216
- description: "Base64-encoded file data (fallback for small files <10KB)"
172217
- })),
172218
- description: Schema_exports.optional(Schema_exports.String.annotations({
172219
- description: "Attachment description"
172220
- })),
172221
- pinned: Schema_exports.optional(Schema_exports.Boolean.annotations({
172222
- description: "Whether to pin the attachment (default: false)"
172223
- }))
172224
- };
172225
- var hasFileSource = (params) => {
172226
- const hasSource = params.filePath || params.fileUrl || params.data;
172227
- return hasSource ? true : "Must provide filePath, fileUrl, or data";
172228
- };
172229
- var AddAttachmentParamsBase = Schema_exports.Struct({
172230
- objectId: NonEmptyString2.annotations({
172231
- description: "ID of the parent object (issue, document, etc.)"
172232
- }),
172233
- objectClass: ObjectClassName.annotations({
172234
- description: "Class of the parent object (e.g., 'tracker:class:Issue', 'document:class:Document')"
172235
- }),
172236
- space: SpaceId.annotations({
172237
- description: "Space ID where the parent object resides"
172238
- }),
172239
- ...FileSourceFields
172129
+ yield* client.updateDoc(
172130
+ chunter.class.Channel,
172131
+ toRef(channel._id),
172132
+ channel._id,
172133
+ updateOps
172134
+ );
172135
+ return { id: ChannelId.make(channel._id), updated: true };
172240
172136
  });
172241
- var AddAttachmentParamsSchema = AddAttachmentParamsBase.pipe(
172242
- Schema_exports.filter(hasFileSource)
172243
- ).annotations({
172244
- title: "AddAttachmentParams",
172245
- description: "Parameters for adding an attachment. Provide ONE of: filePath, fileUrl, or data"
172137
+ var deleteChannel = (params) => Effect_exports.gen(function* () {
172138
+ const { channel, client } = yield* findChannel(params.channel);
172139
+ yield* client.removeDoc(
172140
+ chunter.class.Channel,
172141
+ toRef(channel._id),
172142
+ channel._id
172143
+ );
172144
+ return { id: ChannelId.make(channel._id), deleted: true };
172246
172145
  });
172247
- var UpdateAttachmentParamsSchema = Schema_exports.Struct({
172248
- attachmentId: AttachmentId.annotations({
172249
- description: "Attachment ID"
172250
- }),
172251
- description: Schema_exports.optional(
172252
- Schema_exports.NullOr(Schema_exports.String).annotations({
172253
- description: "New description (null to clear)"
172254
- })
172255
- ),
172256
- pinned: Schema_exports.optional(Schema_exports.Boolean.annotations({
172257
- description: "Pin or unpin the attachment"
172258
- }))
172259
- }).annotations({
172260
- title: "UpdateAttachmentParams",
172261
- description: "Parameters for updating an attachment"
172146
+ var listChannelMessages = (params) => Effect_exports.gen(function* () {
172147
+ const { channel, client } = yield* findChannel(params.channel);
172148
+ const markupUrlConfig = client.markupUrlConfig;
172149
+ const limit = clampLimit(params.limit);
172150
+ const messages = yield* client.findAll(
172151
+ chunter.class.ChatMessage,
172152
+ {
172153
+ space: channel._id
172154
+ },
172155
+ {
172156
+ limit,
172157
+ sort: {
172158
+ createdOn: import_core19.SortingOrder.Descending
172159
+ }
172160
+ }
172161
+ );
172162
+ const total = messages.total;
172163
+ const uniqueSocialIds = [
172164
+ ...new Set(
172165
+ messages.map((msg) => msg.modifiedBy)
172166
+ )
172167
+ ];
172168
+ const socialIdToName = yield* buildSocialIdToPersonNameMap(client, uniqueSocialIds);
172169
+ const summaries = messages.map((msg) => {
172170
+ const senderName = socialIdToName.get(msg.modifiedBy);
172171
+ return {
172172
+ id: MessageId.make(msg._id),
172173
+ body: markupToMarkdownString(msg.message, markupUrlConfig),
172174
+ sender: senderName !== void 0 ? PersonName.make(senderName) : void 0,
172175
+ senderId: msg.modifiedBy,
172176
+ createdOn: msg.createdOn,
172177
+ modifiedOn: msg.modifiedOn,
172178
+ editedOn: msg.editedOn,
172179
+ replies: msg.replies
172180
+ };
172181
+ });
172182
+ return { messages: summaries, total };
172262
172183
  });
172263
- var DeleteAttachmentParamsSchema = Schema_exports.Struct({
172264
- attachmentId: AttachmentId.annotations({
172265
- description: "Attachment ID to delete"
172266
- })
172267
- }).annotations({
172268
- title: "DeleteAttachmentParams",
172269
- description: "Parameters for deleting an attachment"
172184
+ var sendChannelMessage = (params) => Effect_exports.gen(function* () {
172185
+ const { channel, client } = yield* findChannel(params.channel);
172186
+ const markupUrlConfig = client.markupUrlConfig;
172187
+ const messageId = (0, import_core19.generateId)();
172188
+ const markup = markdownToMarkupString(params.body, markupUrlConfig);
172189
+ const messageData = {
172190
+ message: markup,
172191
+ attachments: 0
172192
+ };
172193
+ yield* client.addCollection(
172194
+ chunter.class.ChatMessage,
172195
+ channel._id,
172196
+ channel._id,
172197
+ chunter.class.Channel,
172198
+ "messages",
172199
+ messageData,
172200
+ messageId
172201
+ );
172202
+ return { id: MessageId.make(messageId), channelId: ChannelId.make(channel._id) };
172270
172203
  });
172271
- var PinAttachmentParamsSchema = Schema_exports.Struct({
172272
- attachmentId: AttachmentId.annotations({
172273
- description: "Attachment ID"
172274
- }),
172275
- pinned: Schema_exports.Boolean.annotations({
172276
- description: "Whether to pin (true) or unpin (false)"
172277
- })
172278
- }).annotations({
172279
- title: "PinAttachmentParams",
172280
- description: "Parameters for pinning/unpinning an attachment"
172204
+ var listDirectMessages = (params) => Effect_exports.gen(function* () {
172205
+ const client = yield* HulyClient;
172206
+ const limit = clampLimit(params.limit);
172207
+ const dms = yield* client.findAll(
172208
+ chunter.class.DirectMessage,
172209
+ { members: client.getAccountUuid() },
172210
+ {
172211
+ limit,
172212
+ sort: {
172213
+ modifiedOn: import_core19.SortingOrder.Descending
172214
+ }
172215
+ }
172216
+ );
172217
+ const total = dms.total;
172218
+ const uniqueAccountUuids = [
172219
+ ...new Set(
172220
+ dms.flatMap((dm) => dm.members)
172221
+ )
172222
+ ];
172223
+ const accountUuidToName = yield* buildAccountUuidToNameMap(client, uniqueAccountUuids);
172224
+ const summaries = dms.map((dm) => {
172225
+ const participants = dm.members.map((m) => accountUuidToName.get(m)).filter((n) => n !== void 0).map((n) => PersonName.make(n));
172226
+ const participantIds = dm.members.map((m) => AccountUuid.make(m));
172227
+ return {
172228
+ id: ChannelId.make(dm._id),
172229
+ participants,
172230
+ participantIds,
172231
+ messages: dm.messages,
172232
+ modifiedOn: dm.modifiedOn
172233
+ };
172234
+ });
172235
+ return { conversations: summaries, total };
172281
172236
  });
172282
- var DownloadAttachmentParamsSchema = Schema_exports.Struct({
172283
- attachmentId: AttachmentId.annotations({
172284
- description: "Attachment ID"
172285
- })
172286
- }).annotations({
172287
- title: "DownloadAttachmentParams",
172288
- description: "Parameters for getting attachment download URL"
172289
- });
172290
- var AddIssueAttachmentParamsBase = Schema_exports.Struct({
172291
- project: ProjectIdentifier.annotations({
172292
- description: "Project identifier (e.g., 'HULY')"
172293
- }),
172294
- identifier: IssueIdentifier.annotations({
172295
- description: "Issue identifier (e.g., 'HULY-123')"
172296
- }),
172297
- ...FileSourceFields
172298
- });
172299
- var AddIssueAttachmentParamsSchema = AddIssueAttachmentParamsBase.pipe(
172300
- Schema_exports.filter(hasFileSource)
172301
- ).annotations({
172302
- title: "AddIssueAttachmentParams",
172303
- description: "Parameters for adding an attachment to an issue"
172304
- });
172305
- var AddDocumentAttachmentParamsBase = Schema_exports.Struct({
172306
- teamspace: TeamspaceIdentifier.annotations({
172307
- description: "Teamspace name or ID"
172308
- }),
172309
- document: DocumentIdentifier.annotations({
172310
- description: "Document title or ID"
172311
- }),
172312
- ...FileSourceFields
172313
- });
172314
- var AddDocumentAttachmentParamsSchema = AddDocumentAttachmentParamsBase.pipe(
172315
- Schema_exports.filter(hasFileSource)
172316
- ).annotations({
172317
- title: "AddDocumentAttachmentParams",
172318
- description: "Parameters for adding an attachment to a document"
172319
- });
172320
- var listAttachmentsParamsJsonSchema = JSONSchema_exports.make(ListAttachmentsParamsSchema);
172321
- var getAttachmentParamsJsonSchema = JSONSchema_exports.make(GetAttachmentParamsSchema);
172322
- var addAttachmentParamsJsonSchema = JSONSchema_exports.make(AddAttachmentParamsSchema);
172323
- var updateAttachmentParamsJsonSchema = JSONSchema_exports.make(UpdateAttachmentParamsSchema);
172324
- var deleteAttachmentParamsJsonSchema = JSONSchema_exports.make(DeleteAttachmentParamsSchema);
172325
- var pinAttachmentParamsJsonSchema = JSONSchema_exports.make(PinAttachmentParamsSchema);
172326
- var downloadAttachmentParamsJsonSchema = JSONSchema_exports.make(DownloadAttachmentParamsSchema);
172327
- var addIssueAttachmentParamsJsonSchema = JSONSchema_exports.make(AddIssueAttachmentParamsSchema);
172328
- var addDocumentAttachmentParamsJsonSchema = JSONSchema_exports.make(AddDocumentAttachmentParamsSchema);
172329
- var parseListAttachmentsParams = Schema_exports.decodeUnknown(ListAttachmentsParamsSchema);
172330
- var parseGetAttachmentParams = Schema_exports.decodeUnknown(GetAttachmentParamsSchema);
172331
- var parseAddAttachmentParams = Schema_exports.decodeUnknown(AddAttachmentParamsSchema);
172332
- var parseUpdateAttachmentParams = Schema_exports.decodeUnknown(UpdateAttachmentParamsSchema);
172333
- var parseDeleteAttachmentParams = Schema_exports.decodeUnknown(DeleteAttachmentParamsSchema);
172334
- var parsePinAttachmentParams = Schema_exports.decodeUnknown(PinAttachmentParamsSchema);
172335
- var parseDownloadAttachmentParams = Schema_exports.decodeUnknown(DownloadAttachmentParamsSchema);
172336
- var parseAddIssueAttachmentParams = Schema_exports.decodeUnknown(AddIssueAttachmentParamsSchema);
172337
- var parseAddDocumentAttachmentParams = Schema_exports.decodeUnknown(AddDocumentAttachmentParamsSchema);
172338
-
172339
- // src/huly/operations/attachments.ts
172340
- var import_core23 = __toESM(require_lib4(), 1);
172341
172237
 
172342
172238
  // src/huly/operations/documents.ts
172343
- var import_core22 = __toESM(require_lib4(), 1);
172239
+ var import_core21 = __toESM(require_lib4(), 1);
172344
172240
  var import_rank = __toESM(require_lib33(), 1);
172345
172241
 
172346
172242
  // src/huly/operations/documents-edit.ts
@@ -172432,566 +172328,555 @@ var countOccurrences = (text, search) => {
172432
172328
  };
172433
172329
 
172434
172330
  // src/huly/operations/documents-inline-comments.ts
172435
- var import_core21 = __toESM(require_lib4(), 1);
172436
- var import_text3 = __toESM(require_lib9(), 1);
172437
-
172438
- // src/huly/operations/channels.ts
172439
172331
  var import_core20 = __toESM(require_lib4(), 1);
172440
-
172441
- // src/huly/operations/channel-messages-shared.ts
172442
- var findChannelMessage = (params) => Effect_exports.gen(function* () {
172443
- const { channel, client } = yield* findChannel(params.channel);
172444
- const message = yield* client.findOne(
172445
- chunter.class.ChatMessage,
172446
- {
172447
- _id: toRef(params.messageId),
172448
- space: channel._id
172332
+ var import_text3 = __toESM(require_lib9(), 1);
172333
+ var INLINE_COMMENT_MARK_TYPE = "inline-comment";
172334
+ var extractInlineComments = (root) => {
172335
+ const threadMap = /* @__PURE__ */ new Map();
172336
+ (0, import_text3.traverseAllMarks)(root, (textNode, mark) => {
172337
+ if (String(mark.type) !== INLINE_COMMENT_MARK_TYPE) return;
172338
+ const threadId = mark.attrs?.thread;
172339
+ if (typeof threadId !== "string" || threadId === "") return;
172340
+ const text = textNode.text ?? "";
172341
+ if (!threadMap.has(threadId)) {
172342
+ threadMap.set(threadId, []);
172449
172343
  }
172450
- );
172451
- if (message === void 0) {
172452
- return yield* new MessageNotFoundError({
172453
- messageId: params.messageId,
172454
- channel: params.channel
172455
- });
172456
- }
172457
- return { client, channel, message };
172458
- });
172459
-
172460
- // src/huly/operations/channels-messages.ts
172461
- var updateChannelMessage = (params) => Effect_exports.gen(function* () {
172462
- const { channel, client, message } = yield* findChannelMessage(params);
172344
+ threadMap.get(threadId)?.push(text);
172345
+ });
172346
+ return [...threadMap.entries()].map(([threadId, textFragments]) => ({
172347
+ threadId,
172348
+ textFragments
172349
+ }));
172350
+ };
172351
+ var listInlineComments = (params) => Effect_exports.gen(function* () {
172352
+ const { client, doc } = yield* findTeamspaceAndDocument({
172353
+ teamspace: params.teamspace,
172354
+ document: params.document
172355
+ });
172463
172356
  const markupUrlConfig = client.markupUrlConfig;
172464
- const markup = markdownToMarkupString(params.body, markupUrlConfig);
172465
- const now2 = yield* Clock_exports.currentTimeMillis;
172466
- const updateOps = {
172467
- message: markup,
172468
- editedOn: now2
172469
- };
172470
- yield* client.updateDoc(
172471
- chunter.class.ChatMessage,
172472
- channel._id,
172473
- message._id,
172474
- updateOps
172475
- );
172476
- return { id: MessageId.make(message._id), updated: true };
172477
- });
172478
- var deleteChannelMessage = (params) => Effect_exports.gen(function* () {
172479
- const { channel, client, message } = yield* findChannelMessage(params);
172480
- yield* client.removeDoc(
172481
- chunter.class.ChatMessage,
172482
- channel._id,
172483
- message._id
172357
+ if (!doc.content) {
172358
+ return { comments: [], total: 0 };
172359
+ }
172360
+ const rawMarkup = yield* client.fetchMarkup(
172361
+ doc._class,
172362
+ doc._id,
172363
+ "content",
172364
+ doc.content,
172365
+ "markup"
172484
172366
  );
172485
- return { id: MessageId.make(message._id), deleted: true };
172367
+ const root = (0, import_text3.markupToJSON)(rawMarkup);
172368
+ const extracted = extractInlineComments(root);
172369
+ if (extracted.length === 0) {
172370
+ return { comments: [], total: 0 };
172371
+ }
172372
+ let nameMap = /* @__PURE__ */ new Map();
172373
+ const threadRepliesMap = /* @__PURE__ */ new Map();
172374
+ if (params.includeReplies) {
172375
+ const threadIds = extracted.map((c) => toRef(c.threadId));
172376
+ const allReplies = yield* client.findAll(
172377
+ chunter.class.ThreadMessage,
172378
+ { attachedTo: { $in: threadIds } },
172379
+ { sort: { createdOn: import_core20.SortingOrder.Ascending } }
172380
+ );
172381
+ for (const r of allReplies) {
172382
+ const key = r.attachedTo;
172383
+ if (!threadRepliesMap.has(key)) {
172384
+ threadRepliesMap.set(key, []);
172385
+ }
172386
+ threadRepliesMap.get(key)?.push(r);
172387
+ }
172388
+ const senderIds = [
172389
+ ...new Set(
172390
+ allReplies.map((r) => r.createdBy).filter((id) => id !== void 0)
172391
+ )
172392
+ ];
172393
+ nameMap = yield* buildSocialIdToPersonNameMap(client, senderIds);
172394
+ }
172395
+ const comments = extracted.map((comment) => {
172396
+ const thread = {
172397
+ threadId: comment.threadId,
172398
+ text: comment.textFragments.join("")
172399
+ };
172400
+ if (params.includeReplies) {
172401
+ const threadReplies = threadRepliesMap.get(comment.threadId) ?? [];
172402
+ const replies = threadReplies.map((r) => ({
172403
+ id: r._id,
172404
+ body: optionalMarkupToMarkdown(r.message, markupUrlConfig, ""),
172405
+ sender: r.createdBy !== void 0 ? nameMap.get(r.createdBy) : void 0,
172406
+ createdOn: r.createdOn
172407
+ }));
172408
+ return { ...thread, replies };
172409
+ }
172410
+ return thread;
172411
+ });
172412
+ return { comments, total: comments.length };
172486
172413
  });
172487
172414
 
172488
- // src/huly/operations/channels.ts
172489
- var personIdsAsSocialIdentityRefs = (ids3) => ids3;
172490
- var findChannel = (identifier2) => Effect_exports.gen(function* () {
172415
+ // src/huly/operations/documents.ts
172416
+ var findTeamspace = (identifier2, opts) => Effect_exports.gen(function* () {
172491
172417
  const client = yield* HulyClient;
172492
- const channel = yield* findByNameOrId(
172418
+ const nameQuery = { name: identifier2 };
172419
+ const idQuery = { _id: toRef(identifier2) };
172420
+ if (!opts?.includeArchived) {
172421
+ nameQuery.archived = false;
172422
+ idQuery.archived = false;
172423
+ }
172424
+ const teamspace = yield* findByNameOrId(
172493
172425
  client,
172494
- chunter.class.Channel,
172495
- { name: identifier2 },
172496
- { _id: toRef(identifier2) }
172426
+ documentPlugin.class.Teamspace,
172427
+ nameQuery,
172428
+ idQuery
172497
172429
  );
172498
- if (channel === void 0) {
172499
- return yield* new ChannelNotFoundError({ identifier: identifier2 });
172430
+ if (teamspace === void 0) {
172431
+ return yield* new TeamspaceNotFoundError({ identifier: identifier2 });
172500
172432
  }
172501
- return { client, channel };
172433
+ return { client, teamspace };
172502
172434
  });
172503
- var buildSocialIdToPersonNameMap = (client, socialIds) => Effect_exports.gen(function* () {
172504
- if (socialIds.length === 0) {
172505
- return /* @__PURE__ */ new Map();
172506
- }
172507
- const socialIdentities = yield* client.findAll(
172508
- contact.class.SocialIdentity,
172509
- { _id: { $in: personIdsAsSocialIdentityRefs(socialIds) } }
172510
- );
172511
- if (socialIdentities.length === 0) {
172512
- return /* @__PURE__ */ new Map();
172513
- }
172514
- const personRefs = [...new Set(socialIdentities.map((si) => si.attachedTo))];
172515
- const persons = yield* client.findAll(
172516
- contact.class.Person,
172517
- { _id: { $in: personRefs } }
172435
+ var findTeamspaceAndDocument = (params) => Effect_exports.gen(function* () {
172436
+ const { client, teamspace } = yield* findTeamspace(params.teamspace);
172437
+ const doc = yield* findByNameOrId(
172438
+ client,
172439
+ documentPlugin.class.Document,
172440
+ { space: teamspace._id, title: params.document },
172441
+ { space: teamspace._id, _id: toRef(params.document) }
172518
172442
  );
172519
- const personById = new Map(persons.map((p) => [p._id, p]));
172520
- const result = /* @__PURE__ */ new Map();
172521
- for (const si of socialIdentities) {
172522
- const person = personById.get(si.attachedTo);
172523
- if (person !== void 0) {
172524
- result.set(si._id, person.name);
172525
- }
172443
+ if (doc === void 0) {
172444
+ return yield* new DocumentNotFoundError({
172445
+ identifier: params.document,
172446
+ teamspace: params.teamspace
172447
+ });
172526
172448
  }
172527
- return result;
172449
+ return { client, teamspace, doc };
172528
172450
  });
172529
- var buildAccountUuidToNameMap = (client, accountUuids) => Effect_exports.gen(function* () {
172530
- if (accountUuids.length === 0) {
172531
- return /* @__PURE__ */ new Map();
172532
- }
172533
- const employees = yield* client.findAll(
172534
- contact.mixin.Employee,
172535
- { personUuid: { $in: accountUuids } }
172536
- );
172537
- const result = /* @__PURE__ */ new Map();
172538
- for (const emp of employees) {
172539
- if (emp.personUuid !== void 0) {
172540
- result.set(emp.personUuid, emp.name);
172541
- }
172542
- }
172543
- return result;
172544
- });
172545
- var listChannels = (params) => Effect_exports.gen(function* () {
172546
- const client = yield* HulyClient;
172547
- const query = {};
172548
- if (!params.includeArchived) {
172549
- query.archived = false;
172550
- }
172551
- if (params.nameSearch !== void 0 && params.nameSearch.trim() !== "") {
172552
- query.name = { $like: `%${escapeLikeWildcards(params.nameSearch)}%` };
172553
- }
172554
- if (params.nameRegex !== void 0 && params.nameRegex.trim() !== "") {
172555
- query.name = { $regex: params.nameRegex };
172556
- }
172557
- if (params.topicSearch !== void 0 && params.topicSearch.trim() !== "") {
172558
- query.topic = { $like: `%${escapeLikeWildcards(params.topicSearch)}%` };
172451
+ var listTeamspaces = (params) => Effect_exports.gen(function* () {
172452
+ const client = yield* HulyClient;
172453
+ const query = {};
172454
+ if (!params.includeArchived) {
172455
+ query.archived = false;
172559
172456
  }
172560
172457
  const limit = clampLimit(params.limit);
172561
- const channels = yield* client.findAll(
172562
- chunter.class.Channel,
172458
+ const teamspaces = yield* client.findAll(
172459
+ documentPlugin.class.Teamspace,
172563
172460
  query,
172564
172461
  {
172565
172462
  limit,
172566
172463
  sort: {
172567
- name: import_core20.SortingOrder.Ascending
172464
+ name: import_core21.SortingOrder.Ascending
172568
172465
  }
172569
172466
  }
172570
172467
  );
172571
- const summaries = channels.map((ch) => ({
172572
- id: ChannelId.make(ch._id),
172573
- name: ChannelName.make(ch.name),
172574
- topic: ch.topic || void 0,
172575
- private: ch.private,
172576
- archived: ch.archived,
172577
- members: ch.members.length,
172578
- messages: ch.messages,
172579
- modifiedOn: ch.modifiedOn
172468
+ const total = teamspaces.total;
172469
+ const summaries = teamspaces.map((ts) => ({
172470
+ id: TeamspaceId.make(ts._id),
172471
+ name: ts.name,
172472
+ description: ts.description || void 0,
172473
+ archived: ts.archived,
172474
+ private: ts.private
172580
172475
  }));
172581
- return summaries;
172476
+ return {
172477
+ teamspaces: summaries,
172478
+ total
172479
+ };
172582
172480
  });
172583
- var getChannel = (params) => Effect_exports.gen(function* () {
172584
- const { channel, client } = yield* findChannel(params.channel);
172585
- const memberNames = channel.members.length > 0 ? yield* Effect_exports.gen(function* () {
172586
- const accountUuidToName = yield* buildAccountUuidToNameMap(client, channel.members);
172587
- return channel.members.map((m) => accountUuidToName.get(m)).filter((n) => n !== void 0);
172588
- }) : void 0;
172589
- const result = {
172590
- id: ChannelId.make(channel._id),
172591
- name: ChannelName.make(channel.name),
172592
- topic: channel.topic || void 0,
172593
- description: channel.description || void 0,
172594
- private: channel.private,
172595
- archived: channel.archived,
172596
- members: memberNames?.map((m) => PersonName.make(m)),
172597
- messages: channel.messages,
172598
- modifiedOn: channel.modifiedOn,
172599
- createdOn: channel.createdOn
172481
+ var getTeamspace = (params) => Effect_exports.gen(function* () {
172482
+ const { client, teamspace } = yield* findTeamspace(params.teamspace, { includeArchived: true });
172483
+ const docs = yield* client.findAll(
172484
+ documentPlugin.class.Document,
172485
+ { space: teamspace._id },
172486
+ { limit: 1, total: true }
172487
+ );
172488
+ return {
172489
+ id: TeamspaceId.make(teamspace._id),
172490
+ name: teamspace.name,
172491
+ description: teamspace.description || void 0,
172492
+ archived: teamspace.archived,
172493
+ private: teamspace.private,
172494
+ documents: docs.total
172600
172495
  };
172601
- return result;
172602
172496
  });
172603
- var createChannel = (params) => Effect_exports.gen(function* () {
172497
+ var createTeamspace = (params) => Effect_exports.gen(function* () {
172604
172498
  const client = yield* HulyClient;
172605
- const channelId = (0, import_core20.generateId)();
172606
- const channelData = {
172499
+ const existing = yield* client.findOne(
172500
+ documentPlugin.class.Teamspace,
172501
+ { name: params.name, archived: false }
172502
+ );
172503
+ if (existing !== void 0) {
172504
+ return {
172505
+ id: TeamspaceId.make(existing._id),
172506
+ name: existing.name,
172507
+ created: false
172508
+ };
172509
+ }
172510
+ const teamspaceId = (0, import_core21.generateId)();
172511
+ const teamspaceData = {
172607
172512
  name: params.name,
172608
- topic: params.topic || "",
172609
- description: "",
172513
+ description: params.description ?? "",
172610
172514
  private: params.private ?? false,
172611
172515
  archived: false,
172612
172516
  members: [client.getAccountUuid()],
172613
- owners: [client.getAccountUuid()]
172517
+ owners: [client.getAccountUuid()],
172518
+ icon: documentPlugin.icon.Teamspace,
172519
+ type: documentPlugin.spaceType.DefaultTeamspaceType
172614
172520
  };
172615
172521
  yield* client.createDoc(
172616
- chunter.class.Channel,
172617
- toRef(channelId),
172618
- channelData,
172619
- channelId
172522
+ documentPlugin.class.Teamspace,
172523
+ core.space.Space,
172524
+ teamspaceData,
172525
+ teamspaceId
172620
172526
  );
172621
- return { id: ChannelId.make(channelId), name: ChannelName.make(params.name) };
172527
+ return {
172528
+ id: TeamspaceId.make(teamspaceId),
172529
+ name: params.name,
172530
+ created: true
172531
+ };
172622
172532
  });
172623
- var updateChannel = (params) => Effect_exports.gen(function* () {
172624
- const { channel, client } = yield* findChannel(params.channel);
172533
+ var updateTeamspace = (params) => Effect_exports.gen(function* () {
172534
+ const { client, teamspace } = yield* findTeamspace(params.teamspace, { includeArchived: true });
172625
172535
  const updateOps = {};
172626
172536
  if (params.name !== void 0) {
172627
172537
  updateOps.name = params.name;
172628
172538
  }
172629
- if (params.topic !== void 0) {
172630
- updateOps.topic = params.topic;
172539
+ if (params.description !== void 0) {
172540
+ updateOps.description = params.description === null ? "" : params.description;
172541
+ }
172542
+ if (params.archived !== void 0) {
172543
+ updateOps.archived = params.archived;
172631
172544
  }
172632
172545
  if (Object.keys(updateOps).length === 0) {
172633
- return { id: ChannelId.make(channel._id), updated: false };
172546
+ return { id: TeamspaceId.make(teamspace._id), updated: false };
172634
172547
  }
172635
172548
  yield* client.updateDoc(
172636
- chunter.class.Channel,
172637
- toRef(channel._id),
172638
- channel._id,
172549
+ documentPlugin.class.Teamspace,
172550
+ core.space.Space,
172551
+ teamspace._id,
172639
172552
  updateOps
172640
172553
  );
172641
- return { id: ChannelId.make(channel._id), updated: true };
172554
+ return { id: TeamspaceId.make(teamspace._id), updated: true };
172642
172555
  });
172643
- var deleteChannel = (params) => Effect_exports.gen(function* () {
172644
- const { channel, client } = yield* findChannel(params.channel);
172556
+ var deleteTeamspace = (params) => Effect_exports.gen(function* () {
172557
+ const { client, teamspace } = yield* findTeamspace(params.teamspace, { includeArchived: true });
172645
172558
  yield* client.removeDoc(
172646
- chunter.class.Channel,
172647
- toRef(channel._id),
172648
- channel._id
172559
+ documentPlugin.class.Teamspace,
172560
+ core.space.Space,
172561
+ teamspace._id
172649
172562
  );
172650
- return { id: ChannelId.make(channel._id), deleted: true };
172563
+ return { id: TeamspaceId.make(teamspace._id), deleted: true };
172651
172564
  });
172652
- var listChannelMessages = (params) => Effect_exports.gen(function* () {
172653
- const { channel, client } = yield* findChannel(params.channel);
172654
- const markupUrlConfig = client.markupUrlConfig;
172565
+ var listDocuments = (params) => Effect_exports.gen(function* () {
172566
+ const { client, teamspace } = yield* findTeamspace(params.teamspace);
172655
172567
  const limit = clampLimit(params.limit);
172656
- const messages = yield* client.findAll(
172657
- chunter.class.ChatMessage,
172658
- {
172659
- space: channel._id
172660
- },
172568
+ const query = {
172569
+ space: teamspace._id
172570
+ };
172571
+ if (params.titleSearch !== void 0 && params.titleSearch.trim() !== "") {
172572
+ query.title = { $like: `%${escapeLikeWildcards(params.titleSearch)}%` };
172573
+ }
172574
+ if (params.titleRegex !== void 0 && params.titleRegex.trim() !== "") {
172575
+ query.title = { $regex: params.titleRegex };
172576
+ }
172577
+ if (params.contentSearch !== void 0 && params.contentSearch.trim() !== "") {
172578
+ query.$search = params.contentSearch;
172579
+ }
172580
+ const documents = yield* client.findAll(
172581
+ documentPlugin.class.Document,
172582
+ query,
172661
172583
  {
172662
172584
  limit,
172663
172585
  sort: {
172664
- createdOn: import_core20.SortingOrder.Descending
172586
+ modifiedOn: import_core21.SortingOrder.Descending
172665
172587
  }
172666
172588
  }
172667
172589
  );
172668
- const total = messages.total;
172669
- const uniqueSocialIds = [
172670
- ...new Set(
172671
- messages.map((msg) => msg.modifiedBy)
172672
- )
172673
- ];
172674
- const socialIdToName = yield* buildSocialIdToPersonNameMap(client, uniqueSocialIds);
172675
- const summaries = messages.map((msg) => {
172676
- const senderName = socialIdToName.get(msg.modifiedBy);
172677
- return {
172678
- id: MessageId.make(msg._id),
172679
- body: markupToMarkdownString(msg.message, markupUrlConfig),
172680
- sender: senderName !== void 0 ? PersonName.make(senderName) : void 0,
172681
- senderId: msg.modifiedBy,
172682
- createdOn: msg.createdOn,
172683
- modifiedOn: msg.modifiedOn,
172684
- editedOn: msg.editedOn,
172685
- replies: msg.replies
172686
- };
172687
- });
172688
- return { messages: summaries, total };
172590
+ const total = documents.total;
172591
+ const summaries = documents.map((doc) => ({
172592
+ id: DocumentId.make(doc._id),
172593
+ title: doc.title,
172594
+ teamspace: teamspace.name,
172595
+ url: buildDocumentUrlFromConfig(client.workbenchUrlConfig, doc.title, DocumentId.make(doc._id)),
172596
+ modifiedOn: doc.modifiedOn
172597
+ }));
172598
+ return {
172599
+ documents: summaries,
172600
+ total
172601
+ };
172689
172602
  });
172690
- var sendChannelMessage = (params) => Effect_exports.gen(function* () {
172691
- const { channel, client } = yield* findChannel(params.channel);
172692
- const markupUrlConfig = client.markupUrlConfig;
172693
- const messageId = (0, import_core20.generateId)();
172694
- const markup = markdownToMarkupString(params.body, markupUrlConfig);
172695
- const messageData = {
172696
- message: markup,
172697
- attachments: 0
172603
+ var getDocument = (params) => Effect_exports.gen(function* () {
172604
+ const { client, doc, teamspace } = yield* findTeamspaceAndDocument({
172605
+ teamspace: params.teamspace,
172606
+ document: params.document
172607
+ });
172608
+ const content = doc.content ? yield* client.fetchMarkup(
172609
+ doc._class,
172610
+ doc._id,
172611
+ "content",
172612
+ doc.content,
172613
+ "markdown"
172614
+ ) : void 0;
172615
+ const result = {
172616
+ id: DocumentId.make(doc._id),
172617
+ title: doc.title,
172618
+ content,
172619
+ teamspace: teamspace.name,
172620
+ url: buildDocumentUrlFromConfig(client.workbenchUrlConfig, doc.title, DocumentId.make(doc._id)),
172621
+ modifiedOn: doc.modifiedOn,
172622
+ createdOn: doc.createdOn
172698
172623
  };
172699
- yield* client.addCollection(
172700
- chunter.class.ChatMessage,
172701
- channel._id,
172702
- channel._id,
172703
- chunter.class.Channel,
172704
- "messages",
172705
- messageData,
172706
- messageId
172707
- );
172708
- return { id: MessageId.make(messageId), channelId: ChannelId.make(channel._id) };
172624
+ return result;
172709
172625
  });
172710
- var listDirectMessages = (params) => Effect_exports.gen(function* () {
172711
- const client = yield* HulyClient;
172712
- const limit = clampLimit(params.limit);
172713
- const dms = yield* client.findAll(
172714
- chunter.class.DirectMessage,
172715
- { members: client.getAccountUuid() },
172716
- {
172717
- limit,
172718
- sort: {
172719
- modifiedOn: import_core20.SortingOrder.Descending
172720
- }
172721
- }
172722
- );
172723
- const total = dms.total;
172724
- const uniqueAccountUuids = [
172725
- ...new Set(
172726
- dms.flatMap((dm) => dm.members)
172727
- )
172728
- ];
172729
- const accountUuidToName = yield* buildAccountUuidToNameMap(client, uniqueAccountUuids);
172730
- const summaries = dms.map((dm) => {
172731
- const participants = dm.members.map((m) => accountUuidToName.get(m)).filter((n) => n !== void 0).map((n) => PersonName.make(n));
172732
- const participantIds = dm.members.map((m) => AccountUuid.make(m));
172733
- return {
172734
- id: ChannelId.make(dm._id),
172735
- participants,
172736
- participantIds,
172737
- messages: dm.messages,
172738
- modifiedOn: dm.modifiedOn
172739
- };
172740
- });
172741
- return { conversations: summaries, total };
172742
- });
172743
-
172744
- // src/huly/operations/documents-inline-comments.ts
172745
- var INLINE_COMMENT_MARK_TYPE = "inline-comment";
172746
- var extractInlineComments = (root) => {
172747
- const threadMap = /* @__PURE__ */ new Map();
172748
- (0, import_text3.traverseAllMarks)(root, (textNode, mark) => {
172749
- if (String(mark.type) !== INLINE_COMMENT_MARK_TYPE) return;
172750
- const threadId = mark.attrs?.thread;
172751
- if (typeof threadId !== "string" || threadId === "") return;
172752
- const text = textNode.text ?? "";
172753
- if (!threadMap.has(threadId)) {
172754
- threadMap.set(threadId, []);
172626
+ var createDocument = (params) => Effect_exports.gen(function* () {
172627
+ const { client, teamspace } = yield* findTeamspace(params.teamspace);
172628
+ const documentId = (0, import_core21.generateId)();
172629
+ const parent = params.parent;
172630
+ const parentRef = parent === void 0 ? documentPlugin.ids.NoParent : yield* Effect_exports.gen(function* () {
172631
+ const parentDoc = yield* findByNameOrId(
172632
+ client,
172633
+ documentPlugin.class.Document,
172634
+ { space: teamspace._id, title: parent },
172635
+ { space: teamspace._id, _id: toRef(parent) }
172636
+ );
172637
+ if (parentDoc === void 0) {
172638
+ return yield* new DocumentNotFoundError({
172639
+ identifier: parent,
172640
+ teamspace: params.teamspace
172641
+ });
172755
172642
  }
172756
- threadMap.get(threadId)?.push(text);
172757
- });
172758
- return [...threadMap.entries()].map(([threadId, textFragments]) => ({
172759
- threadId,
172760
- textFragments
172761
- }));
172762
- };
172763
- var listInlineComments = (params) => Effect_exports.gen(function* () {
172764
- const { client, doc } = yield* findTeamspaceAndDocument({
172765
- teamspace: params.teamspace,
172766
- document: params.document
172643
+ return parentDoc._id;
172767
172644
  });
172768
- const markupUrlConfig = client.markupUrlConfig;
172769
- if (!doc.content) {
172770
- return { comments: [], total: 0 };
172771
- }
172772
- const rawMarkup = yield* client.fetchMarkup(
172773
- doc._class,
172774
- doc._id,
172645
+ const lastDoc = yield* client.findOne(
172646
+ documentPlugin.class.Document,
172647
+ { space: teamspace._id },
172648
+ { sort: { rank: import_core21.SortingOrder.Descending } }
172649
+ );
172650
+ const rank = (0, import_rank.makeRank)(lastDoc?.rank, void 0);
172651
+ const contentMarkupRef = params.content !== void 0 && params.content.trim() !== "" ? yield* client.uploadMarkup(
172652
+ documentPlugin.class.Document,
172653
+ documentId,
172775
172654
  "content",
172776
- doc.content,
172777
- "markup"
172655
+ params.content,
172656
+ "markdown"
172657
+ ) : null;
172658
+ const documentData = {
172659
+ title: params.title,
172660
+ content: contentMarkupRef,
172661
+ parent: parentRef,
172662
+ rank
172663
+ };
172664
+ yield* client.createDoc(
172665
+ documentPlugin.class.Document,
172666
+ teamspace._id,
172667
+ documentData,
172668
+ documentId
172778
172669
  );
172779
- const root = (0, import_text3.markupToJSON)(rawMarkup);
172780
- const extracted = extractInlineComments(root);
172781
- if (extracted.length === 0) {
172782
- return { comments: [], total: 0 };
172783
- }
172784
- let nameMap = /* @__PURE__ */ new Map();
172785
- const threadRepliesMap = /* @__PURE__ */ new Map();
172786
- if (params.includeReplies) {
172787
- const threadIds = extracted.map((c) => toRef(c.threadId));
172788
- const allReplies = yield* client.findAll(
172789
- chunter.class.ThreadMessage,
172790
- { attachedTo: { $in: threadIds } },
172791
- { sort: { createdOn: import_core21.SortingOrder.Ascending } }
172792
- );
172793
- for (const r of allReplies) {
172794
- const key = r.attachedTo;
172795
- if (!threadRepliesMap.has(key)) {
172796
- threadRepliesMap.set(key, []);
172797
- }
172798
- threadRepliesMap.get(key)?.push(r);
172799
- }
172800
- const senderIds = [
172801
- ...new Set(
172802
- allReplies.map((r) => r.createdBy).filter((id) => id !== void 0)
172803
- )
172804
- ];
172805
- nameMap = yield* buildSocialIdToPersonNameMap(client, senderIds);
172806
- }
172807
- const comments = extracted.map((comment) => {
172808
- const thread = {
172809
- threadId: comment.threadId,
172810
- text: comment.textFragments.join("")
172811
- };
172812
- if (params.includeReplies) {
172813
- const threadReplies = threadRepliesMap.get(comment.threadId) ?? [];
172814
- const replies = threadReplies.map((r) => ({
172815
- id: r._id,
172816
- body: optionalMarkupToMarkdown(r.message, markupUrlConfig, ""),
172817
- sender: r.createdBy !== void 0 ? nameMap.get(r.createdBy) : void 0,
172818
- createdOn: r.createdOn
172819
- }));
172820
- return { ...thread, replies };
172821
- }
172822
- return thread;
172823
- });
172824
- return { comments, total: comments.length };
172670
+ return {
172671
+ id: DocumentId.make(documentId),
172672
+ title: params.title,
172673
+ url: buildDocumentUrlFromConfig(client.workbenchUrlConfig, params.title, DocumentId.make(documentId))
172674
+ };
172675
+ });
172676
+ var deleteDocument = (params) => Effect_exports.gen(function* () {
172677
+ const { client, doc, teamspace } = yield* findTeamspaceAndDocument(params);
172678
+ yield* client.removeDoc(
172679
+ documentPlugin.class.Document,
172680
+ teamspace._id,
172681
+ doc._id
172682
+ );
172683
+ return { id: DocumentId.make(doc._id), deleted: true };
172825
172684
  });
172826
172685
 
172827
- // src/huly/operations/documents.ts
172828
- var findTeamspace = (identifier2, opts) => Effect_exports.gen(function* () {
172686
+ // src/huly/operations/issues-shared.ts
172687
+ var import_tracker = __toESM(require_lib36(), 1);
172688
+
172689
+ // src/utils/normalize.ts
172690
+ var normalizeForComparison = (s) => s.replace(/[-_ ]/g, "").toLowerCase();
172691
+
172692
+ // src/huly/operations/issues-shared.ts
172693
+ var zeroAsUnset = (value3) => value3 > 0 ? PositiveNumber.make(value3) : void 0;
172694
+ var findProject = (projectIdentifier) => Effect_exports.gen(function* () {
172829
172695
  const client = yield* HulyClient;
172830
- const nameQuery = { name: identifier2 };
172831
- const idQuery = { _id: toRef(identifier2) };
172832
- if (!opts?.includeArchived) {
172833
- nameQuery.archived = false;
172834
- idQuery.archived = false;
172835
- }
172836
- const teamspace = yield* findByNameOrId(
172696
+ const project3 = yield* findOneOrFail(
172837
172697
  client,
172838
- documentPlugin.class.Teamspace,
172839
- nameQuery,
172840
- idQuery
172698
+ tracker.class.Project,
172699
+ { identifier: projectIdentifier },
172700
+ () => new ProjectNotFoundError({ identifier: projectIdentifier })
172841
172701
  );
172842
- if (teamspace === void 0) {
172843
- return yield* new TeamspaceNotFoundError({ identifier: identifier2 });
172844
- }
172845
- return { client, teamspace };
172702
+ return { client, project: project3 };
172846
172703
  });
172847
- var findTeamspaceAndDocument = (params) => Effect_exports.gen(function* () {
172848
- const { client, teamspace } = yield* findTeamspace(params.teamspace);
172849
- const doc = yield* findByNameOrId(
172704
+ var findProjectWithStatuses = (projectIdentifier) => Effect_exports.gen(function* () {
172705
+ const client = yield* HulyClient;
172706
+ const project3 = yield* findOneOrFail(
172850
172707
  client,
172851
- documentPlugin.class.Document,
172852
- { space: teamspace._id, title: params.document },
172853
- { space: teamspace._id, _id: toRef(params.document) }
172708
+ tracker.class.Project,
172709
+ { identifier: projectIdentifier },
172710
+ () => new ProjectNotFoundError({ identifier: projectIdentifier }),
172711
+ { lookup: { type: task.class.ProjectType } }
172854
172712
  );
172855
- if (doc === void 0) {
172856
- return yield* new DocumentNotFoundError({
172857
- identifier: params.document,
172858
- teamspace: params.teamspace
172859
- });
172713
+ const projectType = project3.$lookup?.type;
172714
+ const statuses = [];
172715
+ if (projectType?.statuses) {
172716
+ const statusRefs = projectType.statuses.map((s) => s._id);
172717
+ if (statusRefs.length > 0) {
172718
+ const statusDocsResult = yield* Effect_exports.either(
172719
+ client.findAll(
172720
+ core.class.Status,
172721
+ { _id: { $in: statusRefs } }
172722
+ )
172723
+ );
172724
+ if (statusDocsResult._tag === "Right") {
172725
+ for (const doc of statusDocsResult.right) {
172726
+ const categoryStr = doc.category ? doc.category : "";
172727
+ statuses.push({
172728
+ _id: doc._id,
172729
+ name: doc.name,
172730
+ isDone: categoryStr === task.statusCategory.Won,
172731
+ isCanceled: categoryStr === task.statusCategory.Lost
172732
+ });
172733
+ }
172734
+ } else {
172735
+ yield* Effect_exports.logWarning(
172736
+ `Status query failed for project ${projectIdentifier}, using fallback. Category-based filtering (open/done/canceled) will use name heuristics. Error: ${statusDocsResult.left.message}`
172737
+ );
172738
+ for (const ps of projectType.statuses) {
172739
+ const name = ps._id.split(":").pop() ?? "Unknown";
172740
+ const nameLower = name.toLowerCase();
172741
+ const isDone5 = nameLower.includes("done") || nameLower.includes("complete") || nameLower.includes("finished") || nameLower.includes("resolved") || nameLower.includes("closed");
172742
+ const isCanceled = nameLower.includes("cancel") || nameLower.includes("reject") || nameLower.includes("abort") || nameLower.includes("wontfix") || nameLower.includes("invalid");
172743
+ statuses.push({
172744
+ _id: ps._id,
172745
+ name,
172746
+ isDone: isDone5,
172747
+ isCanceled
172748
+ });
172749
+ }
172750
+ }
172751
+ }
172860
172752
  }
172861
- return { client, teamspace, doc };
172753
+ const defaultStatusId = project3.defaultIssueStatus || statuses[0]?._id;
172754
+ return { client, project: project3, statuses, defaultStatusId };
172862
172755
  });
172863
- var listTeamspaces = (params) => Effect_exports.gen(function* () {
172864
- const client = yield* HulyClient;
172865
- const query = {};
172866
- if (!params.includeArchived) {
172867
- query.archived = false;
172756
+ var parseIssueIdentifier = (identifier2, projectIdentifier) => {
172757
+ const idStr = String(identifier2).trim();
172758
+ const match16 = idStr.match(/^([A-Z]+)-(\d+)$/i);
172759
+ if (match16) {
172760
+ return {
172761
+ fullIdentifier: `${match16[1].toUpperCase()}-${match16[2]}`,
172762
+ number: parseInt(match16[2], 10)
172763
+ };
172868
172764
  }
172869
- const limit = clampLimit(params.limit);
172870
- const teamspaces = yield* client.findAll(
172871
- documentPlugin.class.Teamspace,
172872
- query,
172765
+ const numMatch = idStr.match(/^\d+$/);
172766
+ if (numMatch) {
172767
+ const num = parseInt(idStr, 10);
172768
+ return {
172769
+ fullIdentifier: `${projectIdentifier.toUpperCase()}-${num}`,
172770
+ number: num
172771
+ };
172772
+ }
172773
+ return { fullIdentifier: idStr, number: null };
172774
+ };
172775
+ var findIssueInProject = (client, project3, identifierStr) => Effect_exports.gen(function* () {
172776
+ const { fullIdentifier, number: number8 } = parseIssueIdentifier(
172777
+ identifierStr,
172778
+ project3.identifier
172779
+ );
172780
+ const issue2 = (yield* client.findOne(
172781
+ tracker.class.Issue,
172873
172782
  {
172874
- limit,
172875
- sort: {
172876
- name: import_core22.SortingOrder.Ascending
172877
- }
172783
+ space: project3._id,
172784
+ identifier: fullIdentifier
172878
172785
  }
172879
- );
172880
- const total = teamspaces.total;
172881
- const summaries = teamspaces.map((ts) => ({
172882
- id: TeamspaceId.make(ts._id),
172883
- name: ts.name,
172884
- description: ts.description || void 0,
172885
- archived: ts.archived,
172886
- private: ts.private
172887
- }));
172888
- return {
172889
- teamspaces: summaries,
172890
- total
172891
- };
172786
+ )) ?? (number8 !== null ? yield* client.findOne(
172787
+ tracker.class.Issue,
172788
+ {
172789
+ space: project3._id,
172790
+ number: number8
172791
+ }
172792
+ ) : void 0);
172793
+ if (issue2 === void 0) {
172794
+ return yield* new IssueNotFoundError({
172795
+ identifier: identifierStr,
172796
+ project: project3.identifier
172797
+ });
172798
+ }
172799
+ return issue2;
172892
172800
  });
172893
- var getTeamspace = (params) => Effect_exports.gen(function* () {
172894
- const { client, teamspace } = yield* findTeamspace(params.teamspace, { includeArchived: true });
172895
- const docs = yield* client.findAll(
172896
- documentPlugin.class.Document,
172897
- { space: teamspace._id },
172898
- { limit: 1, total: true }
172899
- );
172900
- return {
172901
- id: TeamspaceId.make(teamspace._id),
172902
- name: teamspace.name,
172903
- description: teamspace.description || void 0,
172904
- archived: teamspace.archived,
172905
- private: teamspace.private,
172906
- documents: docs.total
172907
- };
172801
+ var findProjectAndIssue = (params) => Effect_exports.gen(function* () {
172802
+ const { client, project: project3 } = yield* findProject(params.project);
172803
+ const issue2 = yield* findIssueInProject(client, project3, params.identifier);
172804
+ return { client, project: project3, issue: issue2 };
172908
172805
  });
172909
- var createTeamspace = (params) => Effect_exports.gen(function* () {
172910
- const client = yield* HulyClient;
172911
- const existing = yield* client.findOne(
172912
- documentPlugin.class.Teamspace,
172913
- { name: params.name, archived: false }
172806
+ var priorityToStringMap = {
172807
+ [import_tracker.IssuePriority.Urgent]: "urgent",
172808
+ [import_tracker.IssuePriority.High]: "high",
172809
+ [import_tracker.IssuePriority.Medium]: "medium",
172810
+ [import_tracker.IssuePriority.Low]: "low",
172811
+ [import_tracker.IssuePriority.NoPriority]: "no-priority"
172812
+ };
172813
+ var priorityToString = (priority) => priorityToStringMap[priority];
172814
+ var stringToPriorityMap = {
172815
+ "urgent": import_tracker.IssuePriority.Urgent,
172816
+ "high": import_tracker.IssuePriority.High,
172817
+ "medium": import_tracker.IssuePriority.Medium,
172818
+ "low": import_tracker.IssuePriority.Low,
172819
+ "no-priority": import_tracker.IssuePriority.NoPriority
172820
+ };
172821
+ var stringToPriority = (priority) => stringToPriorityMap[priority];
172822
+ var resolveStatusByName = (statuses, statusName, project3) => {
172823
+ const normalizedInput = normalizeForComparison(statusName);
172824
+ const matchingStatus = statuses.find(
172825
+ (s) => normalizeForComparison(s.name) === normalizedInput
172914
172826
  );
172915
- if (existing !== void 0) {
172916
- return {
172917
- id: TeamspaceId.make(existing._id),
172918
- name: existing.name,
172919
- created: false
172920
- };
172827
+ if (matchingStatus === void 0) {
172828
+ return Effect_exports.fail(new InvalidStatusError({ status: statusName, project: project3 }));
172921
172829
  }
172922
- const teamspaceId = (0, import_core22.generateId)();
172923
- const teamspaceData = {
172924
- name: params.name,
172925
- description: params.description ?? "",
172926
- private: params.private ?? false,
172927
- archived: false,
172928
- members: [client.getAccountUuid()],
172929
- owners: [client.getAccountUuid()],
172930
- icon: documentPlugin.icon.Teamspace,
172931
- type: documentPlugin.spaceType.DefaultTeamspaceType
172932
- };
172933
- yield* client.createDoc(
172934
- documentPlugin.class.Teamspace,
172935
- core.space.Space,
172936
- teamspaceData,
172937
- teamspaceId
172938
- );
172939
- return {
172940
- id: TeamspaceId.make(teamspaceId),
172941
- name: params.name,
172942
- created: true
172943
- };
172830
+ return Effect_exports.succeed(matchingStatus._id);
172831
+ };
172832
+
172833
+ // src/huly/operations/activity.ts
172834
+ var optionalTimestamp = (value3) => value3 === void 0 ? void 0 : Timestamp.make(value3);
172835
+ var optionalNullableTimestamp = (value3) => value3 === void 0 || value3 === null ? value3 : Timestamp.make(value3);
172836
+ var optionalActivityCount = (value3) => value3 === void 0 ? void 0 : ActivityCount.make(value3);
172837
+ var optionalPersonId = (value3) => value3 === void 0 || value3 === "" ? void 0 : PersonId.make(value3);
172838
+ var activityTarget = (client, objectId, objectClass) => ({
172839
+ client,
172840
+ objectId: NonEmptyString2.make(objectId),
172841
+ objectClass: ObjectClassName.make(objectClass)
172944
172842
  });
172945
- var updateTeamspace = (params) => Effect_exports.gen(function* () {
172946
- const { client, teamspace } = yield* findTeamspace(params.teamspace, { includeArchived: true });
172947
- const updateOps = {};
172948
- if (params.name !== void 0) {
172949
- updateOps.name = params.name;
172843
+ var resolveActivityTarget = (params) => Effect_exports.gen(function* () {
172844
+ if (params.objectId !== void 0 && params.objectClass !== void 0) {
172845
+ const client = yield* HulyClient;
172846
+ return activityTarget(client, params.objectId, params.objectClass);
172950
172847
  }
172951
- if (params.description !== void 0) {
172952
- updateOps.description = params.description === null ? "" : params.description;
172848
+ if (params.project !== void 0 && params.issueIdentifier !== void 0) {
172849
+ const { client, issue: issue2 } = yield* findProjectAndIssue({
172850
+ project: params.project,
172851
+ identifier: params.issueIdentifier
172852
+ });
172853
+ return activityTarget(client, issue2._id, tracker.class.Issue);
172953
172854
  }
172954
- if (params.archived !== void 0) {
172955
- updateOps.archived = params.archived;
172855
+ if (params.teamspace !== void 0 && params.document !== void 0) {
172856
+ const { client, doc } = yield* findTeamspaceAndDocument({
172857
+ teamspace: params.teamspace,
172858
+ document: params.document
172859
+ });
172860
+ return activityTarget(client, doc._id, documentPlugin.class.Document);
172956
172861
  }
172957
- if (Object.keys(updateOps).length === 0) {
172958
- return { id: TeamspaceId.make(teamspace._id), updated: false };
172862
+ if (params.channel !== void 0) {
172863
+ const { channel, client } = yield* findChannel(params.channel);
172864
+ return activityTarget(client, channel._id, chunter.class.Channel);
172959
172865
  }
172960
- yield* client.updateDoc(
172961
- documentPlugin.class.Teamspace,
172962
- core.space.Space,
172963
- teamspace._id,
172964
- updateOps
172965
- );
172966
- return { id: TeamspaceId.make(teamspace._id), updated: true };
172967
- });
172968
- var deleteTeamspace = (params) => Effect_exports.gen(function* () {
172969
- const { client, teamspace } = yield* findTeamspace(params.teamspace, { includeArchived: true });
172970
- yield* client.removeDoc(
172971
- documentPlugin.class.Teamspace,
172972
- core.space.Space,
172973
- teamspace._id
172866
+ return yield* Effect_exports.dieMessage(
172867
+ "Invalid list_activity parameters: choose objectId+objectClass, project+issueIdentifier, teamspace+document, or channel."
172974
172868
  );
172975
- return { id: TeamspaceId.make(teamspace._id), deleted: true };
172976
172869
  });
172977
- var listDocuments = (params) => Effect_exports.gen(function* () {
172978
- const { client, teamspace } = yield* findTeamspace(params.teamspace);
172870
+ var serverPopulatedCreateBy = "";
172871
+ var listActivity = (params) => Effect_exports.gen(function* () {
172872
+ const target = yield* resolveActivityTarget(params);
172979
172873
  const limit = clampLimit(params.limit);
172980
- const query = {
172981
- space: teamspace._id
172982
- };
172983
- if (params.titleSearch !== void 0 && params.titleSearch.trim() !== "") {
172984
- query.title = { $like: `%${escapeLikeWildcards(params.titleSearch)}%` };
172985
- }
172986
- if (params.titleRegex !== void 0 && params.titleRegex.trim() !== "") {
172987
- query.title = { $regex: params.titleRegex };
172988
- }
172989
- if (params.contentSearch !== void 0 && params.contentSearch.trim() !== "") {
172990
- query.$search = params.contentSearch;
172991
- }
172992
- const documents = yield* client.findAll(
172993
- documentPlugin.class.Document,
172994
- query,
172874
+ const messages = yield* target.client.findAll(
172875
+ activity.class.ActivityMessage,
172876
+ {
172877
+ attachedTo: toRef(target.objectId),
172878
+ attachedToClass: toRef(target.objectClass)
172879
+ },
172995
172880
  {
172996
172881
  limit,
172997
172882
  sort: {
@@ -172999,250 +172884,527 @@ var listDocuments = (params) => Effect_exports.gen(function* () {
172999
172884
  }
173000
172885
  }
173001
172886
  );
173002
- const total = documents.total;
173003
- const summaries = documents.map((doc) => ({
173004
- id: DocumentId.make(doc._id),
173005
- title: doc.title,
173006
- teamspace: teamspace.name,
173007
- url: buildDocumentUrlFromConfig(client.workbenchUrlConfig, doc.title, DocumentId.make(doc._id)),
173008
- modifiedOn: doc.modifiedOn
172887
+ const result = messages.map((msg) => ({
172888
+ id: ActivityMessageId.make(msg._id),
172889
+ objectId: NonEmptyString2.make(msg.attachedTo),
172890
+ objectClass: ObjectClassName.make(msg.attachedToClass),
172891
+ modifiedBy: PersonId.make(msg.modifiedBy),
172892
+ modifiedOn: optionalTimestamp(msg.modifiedOn),
172893
+ isPinned: msg.isPinned,
172894
+ replies: optionalActivityCount(msg.replies),
172895
+ reactions: optionalActivityCount(msg.reactions),
172896
+ editedOn: optionalNullableTimestamp(msg.editedOn)
173009
172897
  }));
172898
+ return result;
172899
+ });
172900
+ var addReaction = (params) => Effect_exports.gen(function* () {
172901
+ const client = yield* HulyClient;
172902
+ const message = yield* findOneOrFail(
172903
+ client,
172904
+ activity.class.ActivityMessage,
172905
+ { _id: toRef(params.messageId) },
172906
+ () => new ActivityMessageNotFoundError({ messageId: params.messageId })
172907
+ );
172908
+ const reactionId = (0, import_core22.generateId)();
172909
+ const reactionData = {
172910
+ emoji: params.emoji,
172911
+ createBy: serverPopulatedCreateBy
172912
+ };
172913
+ yield* client.addCollection(
172914
+ activity.class.Reaction,
172915
+ message.space,
172916
+ message._id,
172917
+ activity.class.ActivityMessage,
172918
+ "reactions",
172919
+ reactionData,
172920
+ reactionId
172921
+ );
173010
172922
  return {
173011
- documents: summaries,
173012
- total
172923
+ reactionId: ReactionId.make(reactionId),
172924
+ messageId: ActivityMessageId.make(params.messageId)
173013
172925
  };
173014
172926
  });
173015
- var getDocument = (params) => Effect_exports.gen(function* () {
173016
- const { client, doc, teamspace } = yield* findTeamspaceAndDocument({
173017
- teamspace: params.teamspace,
173018
- document: params.document
173019
- });
173020
- const content = doc.content ? yield* client.fetchMarkup(
173021
- doc._class,
173022
- doc._id,
173023
- "content",
173024
- doc.content,
173025
- "markdown"
173026
- ) : void 0;
173027
- const result = {
173028
- id: DocumentId.make(doc._id),
173029
- title: doc.title,
173030
- content,
173031
- teamspace: teamspace.name,
173032
- url: buildDocumentUrlFromConfig(client.workbenchUrlConfig, doc.title, DocumentId.make(doc._id)),
173033
- modifiedOn: doc.modifiedOn,
173034
- createdOn: doc.createdOn
173035
- };
173036
- return result;
172927
+ var removeReaction = (params) => Effect_exports.gen(function* () {
172928
+ const client = yield* HulyClient;
172929
+ const reaction = yield* findOneOrFail(
172930
+ client,
172931
+ activity.class.Reaction,
172932
+ {
172933
+ attachedTo: toRef(params.messageId),
172934
+ emoji: params.emoji
172935
+ },
172936
+ () => new ReactionNotFoundError({
172937
+ messageId: params.messageId,
172938
+ emoji: params.emoji
172939
+ })
172940
+ );
172941
+ yield* client.removeDoc(
172942
+ activity.class.Reaction,
172943
+ reaction.space,
172944
+ reaction._id
172945
+ );
172946
+ return {
172947
+ messageId: ActivityMessageId.make(params.messageId),
172948
+ removed: true
172949
+ };
172950
+ });
172951
+ var listReactions = (params) => Effect_exports.gen(function* () {
172952
+ const client = yield* HulyClient;
172953
+ const limit = clampLimit(params.limit);
172954
+ const reactions = yield* client.findAll(
172955
+ activity.class.Reaction,
172956
+ {
172957
+ attachedTo: toRef(params.messageId)
172958
+ },
172959
+ { limit }
172960
+ );
172961
+ const result = reactions.map((r) => ({
172962
+ id: ReactionId.make(r._id),
172963
+ messageId: ActivityMessageId.make(r.attachedTo),
172964
+ emoji: EmojiCode.make(r.emoji),
172965
+ createdBy: optionalPersonId(r.createBy)
172966
+ }));
172967
+ return result;
172968
+ });
172969
+ var saveMessage = (params) => Effect_exports.gen(function* () {
172970
+ const client = yield* HulyClient;
172971
+ const message = yield* findOneOrFail(
172972
+ client,
172973
+ activity.class.ActivityMessage,
172974
+ { _id: toRef(params.messageId) },
172975
+ () => new ActivityMessageNotFoundError({ messageId: params.messageId })
172976
+ );
172977
+ const savedId = (0, import_core22.generateId)();
172978
+ yield* client.createDoc(
172979
+ activity.class.SavedMessage,
172980
+ core.space.Workspace,
172981
+ {
172982
+ attachedTo: message._id
172983
+ },
172984
+ savedId
172985
+ );
172986
+ return {
172987
+ savedId: SavedMessageId.make(savedId),
172988
+ messageId: ActivityMessageId.make(params.messageId)
172989
+ };
172990
+ });
172991
+ var unsaveMessage = (params) => Effect_exports.gen(function* () {
172992
+ const client = yield* HulyClient;
172993
+ const saved = yield* findOneOrFail(
172994
+ client,
172995
+ activity.class.SavedMessage,
172996
+ {
172997
+ attachedTo: toRef(params.messageId)
172998
+ },
172999
+ () => new SavedMessageNotFoundError({ messageId: params.messageId })
173000
+ );
173001
+ yield* client.removeDoc(
173002
+ activity.class.SavedMessage,
173003
+ saved.space,
173004
+ saved._id
173005
+ );
173006
+ return {
173007
+ messageId: ActivityMessageId.make(params.messageId),
173008
+ removed: true
173009
+ };
173010
+ });
173011
+ var listSavedMessages = (params) => Effect_exports.gen(function* () {
173012
+ const client = yield* HulyClient;
173013
+ const limit = clampLimit(params.limit);
173014
+ const saved = yield* client.findAll(
173015
+ activity.class.SavedMessage,
173016
+ {},
173017
+ { limit }
173018
+ );
173019
+ const result = saved.map((s) => ({
173020
+ id: SavedMessageId.make(s._id),
173021
+ messageId: ActivityMessageId.make(s.attachedTo)
173022
+ }));
173023
+ return result;
173024
+ });
173025
+ var listMentions = (params) => Effect_exports.gen(function* () {
173026
+ const client = yield* HulyClient;
173027
+ const limit = clampLimit(params.limit);
173028
+ const mentions = yield* client.findAll(
173029
+ activity.class.UserMentionInfo,
173030
+ {},
173031
+ {
173032
+ limit,
173033
+ sort: {
173034
+ modifiedOn: import_core22.SortingOrder.Descending
173035
+ }
173036
+ }
173037
+ );
173038
+ const result = mentions.map((m) => ({
173039
+ id: MentionId.make(m._id),
173040
+ messageId: ActivityMessageId.make(m.attachedTo),
173041
+ userId: PersonId.make(m.user),
173042
+ content: m.content
173043
+ }));
173044
+ return result;
173045
+ });
173046
+
173047
+ // src/mcp/tools/registry.ts
173048
+ var deriveTitle = (name) => name.split("_").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
173049
+ var READ_PREFIXES = ["list_", "get_", "search_", "fulltext_", "download_", "preview_"];
173050
+ var CREATE_PREFIXES = ["create_", "add_", "upload_", "send_", "log_"];
173051
+ var UPDATE_PREFIXES = [
173052
+ "update_",
173053
+ "edit_",
173054
+ "set_",
173055
+ "pin_",
173056
+ "unpin_",
173057
+ "mark_",
173058
+ "archive_",
173059
+ "start_",
173060
+ "stop_",
173061
+ "save_",
173062
+ "unsave_",
173063
+ "remove_",
173064
+ "move_"
173065
+ ];
173066
+ var DELETE_PREFIXES = ["delete_"];
173067
+ var matchesPrefix = (name, prefixes) => prefixes.some((p) => name.startsWith(p));
173068
+ var deriveAnnotations = (name) => {
173069
+ const title = deriveTitle(name);
173070
+ if (matchesPrefix(name, READ_PREFIXES)) {
173071
+ return { title, readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
173072
+ }
173073
+ if (matchesPrefix(name, CREATE_PREFIXES)) {
173074
+ return { title, readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
173075
+ }
173076
+ if (matchesPrefix(name, UPDATE_PREFIXES)) {
173077
+ return { title, readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false };
173078
+ }
173079
+ if (matchesPrefix(name, DELETE_PREFIXES)) {
173080
+ return { title, readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false };
173081
+ }
173082
+ return { title, readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false };
173083
+ };
173084
+ var resolveAnnotations = (tool) => ({
173085
+ ...deriveAnnotations(tool.name),
173086
+ ...tool.annotations
173087
+ });
173088
+ var encodeOutput = (schema, result) => Schema_exports.encodeUnknownSync(schema)(result);
173089
+ var provideHulyClient = (args2) => (effect2) => Either_exports.right(effect2.pipe(Effect_exports.provideService(HulyClient, args2.hulyClient)));
173090
+ var provideStorageClient = (args2) => (effect2) => Either_exports.right(effect2.pipe(Effect_exports.provideService(HulyStorageClient, args2.storageClient)));
173091
+ var provideCombinedClient = (args2) => (effect2) => Either_exports.right(
173092
+ effect2.pipe(
173093
+ Effect_exports.provideService(HulyClient, args2.hulyClient),
173094
+ Effect_exports.provideService(HulyStorageClient, args2.storageClient)
173095
+ )
173096
+ );
173097
+ var provideWorkspaceClient = (args2) => (effect2) => args2.workspaceClient !== void 0 ? Either_exports.right(effect2.pipe(Effect_exports.provideService(WorkspaceClient, args2.workspaceClient))) : Either_exports.left(mapDomainErrorToMcp(new HulyError({ message: "WorkspaceClient not available" })));
173098
+ var createHandler = (toolName, provide4, parse5, operation, encode8) => async (args2, hulyClient, storageClient, workspaceClient) => {
173099
+ const parseResult = await Effect_exports.runPromiseExit(parse5(args2));
173100
+ if (Exit_exports.isFailure(parseResult)) {
173101
+ return mapParseCauseToMcp(parseResult.cause, toolName);
173102
+ }
173103
+ const provided = provide4({ hulyClient, storageClient, workspaceClient })(operation(parseResult.value));
173104
+ if (Either_exports.isLeft(provided)) {
173105
+ return provided.left;
173106
+ }
173107
+ const operationResult = await Effect_exports.runPromiseExit(provided.right);
173108
+ if (Exit_exports.isFailure(operationResult)) {
173109
+ return mapDomainCauseToMcp(operationResult.cause);
173110
+ }
173111
+ try {
173112
+ const output = encode8 !== void 0 ? encode8(operationResult.value) : operationResult.value;
173113
+ return createSuccessResponse(output);
173114
+ } catch {
173115
+ return mapDomainErrorToMcp(new HulyError({ message: `Tool ${toolName} produced invalid output` }));
173116
+ }
173117
+ };
173118
+ var createToolHandler = (toolName, parse5, operation) => createHandler(toolName, provideHulyClient, parse5, operation);
173119
+ var createEncodedToolHandler = (toolName, parse5, operation, outputSchema) => createHandler(
173120
+ toolName,
173121
+ provideHulyClient,
173122
+ parse5,
173123
+ operation,
173124
+ (result) => encodeOutput(outputSchema, result)
173125
+ );
173126
+ var createStorageToolHandler = (toolName, parse5, operation) => createHandler(toolName, provideStorageClient, parse5, operation);
173127
+ var createCombinedToolHandler = (toolName, parse5, operation) => createHandler(toolName, provideCombinedClient, parse5, operation);
173128
+ var createEncodedWorkspaceToolHandler = (toolName, parse5, operation, outputSchema) => createHandler(
173129
+ toolName,
173130
+ provideWorkspaceClient,
173131
+ parse5,
173132
+ operation,
173133
+ (result) => encodeOutput(outputSchema, result)
173134
+ );
173135
+ var createEncodedNoParamsWorkspaceToolHandler = (toolName, operation, outputSchema) => createHandler(
173136
+ toolName,
173137
+ provideWorkspaceClient,
173138
+ () => Effect_exports.succeed(void 0),
173139
+ operation,
173140
+ (result) => encodeOutput(outputSchema, result)
173141
+ );
173142
+
173143
+ // src/mcp/tools/activity.ts
173144
+ var CATEGORY = "activity";
173145
+ var activityTools = [
173146
+ {
173147
+ name: "list_activity",
173148
+ description: "List activity messages for a Huly issue, document, channel, or raw Huly object. Prefer friendly targets: project+issueIdentifier for issues, teamspace+document for documents, or channel for channels. Advanced callers may pass objectId+objectClass directly. Returns activity sorted by date (newest first).",
173149
+ category: CATEGORY,
173150
+ inputSchema: listActivityParamsJsonSchema,
173151
+ handler: createEncodedToolHandler(
173152
+ "list_activity",
173153
+ parseListActivityParams,
173154
+ listActivity,
173155
+ ListActivityResultSchema
173156
+ )
173157
+ },
173158
+ {
173159
+ name: "add_reaction",
173160
+ description: "Add an emoji reaction to an activity message.",
173161
+ category: CATEGORY,
173162
+ inputSchema: addReactionParamsJsonSchema,
173163
+ handler: createEncodedToolHandler(
173164
+ "add_reaction",
173165
+ parseAddReactionParams,
173166
+ addReaction,
173167
+ AddReactionResultSchema
173168
+ )
173169
+ },
173170
+ {
173171
+ name: "remove_reaction",
173172
+ description: "Remove an emoji reaction from an activity message.",
173173
+ category: CATEGORY,
173174
+ inputSchema: removeReactionParamsJsonSchema,
173175
+ handler: createEncodedToolHandler(
173176
+ "remove_reaction",
173177
+ parseRemoveReactionParams,
173178
+ removeReaction,
173179
+ RemoveReactionResultSchema
173180
+ )
173181
+ },
173182
+ {
173183
+ name: "list_reactions",
173184
+ description: "List reactions on an activity message.",
173185
+ category: CATEGORY,
173186
+ inputSchema: listReactionsParamsJsonSchema,
173187
+ handler: createEncodedToolHandler(
173188
+ "list_reactions",
173189
+ parseListReactionsParams,
173190
+ listReactions,
173191
+ ListReactionsResultSchema
173192
+ )
173193
+ },
173194
+ {
173195
+ name: "save_message",
173196
+ description: "Save/bookmark an activity message for later reference.",
173197
+ category: CATEGORY,
173198
+ inputSchema: saveMessageParamsJsonSchema,
173199
+ handler: createEncodedToolHandler(
173200
+ "save_message",
173201
+ parseSaveMessageParams,
173202
+ saveMessage,
173203
+ SaveMessageResultSchema
173204
+ )
173205
+ },
173206
+ {
173207
+ name: "unsave_message",
173208
+ description: "Remove an activity message from saved/bookmarks.",
173209
+ category: CATEGORY,
173210
+ inputSchema: unsaveMessageParamsJsonSchema,
173211
+ handler: createEncodedToolHandler(
173212
+ "unsave_message",
173213
+ parseUnsaveMessageParams,
173214
+ unsaveMessage,
173215
+ UnsaveMessageResultSchema
173216
+ )
173217
+ },
173218
+ {
173219
+ name: "list_saved_messages",
173220
+ description: "List saved/bookmarked activity messages.",
173221
+ category: CATEGORY,
173222
+ inputSchema: listSavedMessagesParamsJsonSchema,
173223
+ handler: createEncodedToolHandler(
173224
+ "list_saved_messages",
173225
+ parseListSavedMessagesParams,
173226
+ listSavedMessages,
173227
+ ListSavedMessagesResultSchema
173228
+ )
173229
+ },
173230
+ {
173231
+ name: "list_mentions",
173232
+ description: "List @mentions of the current user in activity messages.",
173233
+ category: CATEGORY,
173234
+ inputSchema: listMentionsParamsJsonSchema,
173235
+ handler: createEncodedToolHandler(
173236
+ "list_mentions",
173237
+ parseListMentionsParams,
173238
+ listMentions,
173239
+ ListMentionsResultSchema
173240
+ )
173241
+ }
173242
+ ];
173243
+
173244
+ // src/domain/schemas/attachments.ts
173245
+ var ListAttachmentsParamsSchema = Schema_exports.Struct({
173246
+ objectId: NonEmptyString2.annotations({
173247
+ description: "ID of the parent object (issue, document, etc.)"
173248
+ }),
173249
+ objectClass: ObjectClassName.annotations({
173250
+ description: "Class of the parent object (e.g., 'tracker:class:Issue', 'document:class:Document')"
173251
+ }),
173252
+ limit: Schema_exports.optional(
173253
+ LimitParam.annotations({
173254
+ description: "Maximum number of attachments to return (default: 50)"
173255
+ })
173256
+ )
173257
+ }).annotations({
173258
+ title: "ListAttachmentsParams",
173259
+ description: "Parameters for listing attachments on an object"
173260
+ });
173261
+ var GetAttachmentParamsSchema = Schema_exports.Struct({
173262
+ attachmentId: AttachmentId.annotations({
173263
+ description: "Attachment ID"
173264
+ })
173265
+ }).annotations({
173266
+ title: "GetAttachmentParams",
173267
+ description: "Parameters for getting a single attachment"
173268
+ });
173269
+ var FileSourceFields = {
173270
+ filename: NonEmptyString2.annotations({
173271
+ description: "Name of the file"
173272
+ }),
173273
+ contentType: MimeType.annotations({
173274
+ description: "MIME type of the file (e.g., 'image/png', 'application/pdf')"
173275
+ }),
173276
+ filePath: Schema_exports.optional(Schema_exports.String.annotations({
173277
+ description: "Local file path to upload (preferred - avoids context flooding)"
173278
+ })),
173279
+ fileUrl: Schema_exports.optional(Schema_exports.String.annotations({
173280
+ description: "URL to fetch file from (for remote files)"
173281
+ })),
173282
+ data: Schema_exports.optional(Schema_exports.String.annotations({
173283
+ description: "Base64-encoded file data (fallback for small files <10KB)"
173284
+ })),
173285
+ description: Schema_exports.optional(Schema_exports.String.annotations({
173286
+ description: "Attachment description"
173287
+ })),
173288
+ pinned: Schema_exports.optional(Schema_exports.Boolean.annotations({
173289
+ description: "Whether to pin the attachment (default: false)"
173290
+ }))
173291
+ };
173292
+ var hasFileSource = (params) => {
173293
+ const hasSource = params.filePath || params.fileUrl || params.data;
173294
+ return hasSource ? true : "Must provide filePath, fileUrl, or data";
173295
+ };
173296
+ var AddAttachmentParamsBase = Schema_exports.Struct({
173297
+ objectId: NonEmptyString2.annotations({
173298
+ description: "ID of the parent object (issue, document, etc.)"
173299
+ }),
173300
+ objectClass: ObjectClassName.annotations({
173301
+ description: "Class of the parent object (e.g., 'tracker:class:Issue', 'document:class:Document')"
173302
+ }),
173303
+ space: SpaceId.annotations({
173304
+ description: "Space ID where the parent object resides"
173305
+ }),
173306
+ ...FileSourceFields
173307
+ });
173308
+ var AddAttachmentParamsSchema = AddAttachmentParamsBase.pipe(
173309
+ Schema_exports.filter(hasFileSource)
173310
+ ).annotations({
173311
+ title: "AddAttachmentParams",
173312
+ description: "Parameters for adding an attachment. Provide ONE of: filePath, fileUrl, or data"
173037
173313
  });
173038
- var createDocument = (params) => Effect_exports.gen(function* () {
173039
- const { client, teamspace } = yield* findTeamspace(params.teamspace);
173040
- const documentId = (0, import_core22.generateId)();
173041
- const parent = params.parent;
173042
- const parentRef = parent === void 0 ? documentPlugin.ids.NoParent : yield* Effect_exports.gen(function* () {
173043
- const parentDoc = yield* findByNameOrId(
173044
- client,
173045
- documentPlugin.class.Document,
173046
- { space: teamspace._id, title: parent },
173047
- { space: teamspace._id, _id: toRef(parent) }
173048
- );
173049
- if (parentDoc === void 0) {
173050
- return yield* new DocumentNotFoundError({
173051
- identifier: parent,
173052
- teamspace: params.teamspace
173053
- });
173054
- }
173055
- return parentDoc._id;
173056
- });
173057
- const lastDoc = yield* client.findOne(
173058
- documentPlugin.class.Document,
173059
- { space: teamspace._id },
173060
- { sort: { rank: import_core22.SortingOrder.Descending } }
173061
- );
173062
- const rank = (0, import_rank.makeRank)(lastDoc?.rank, void 0);
173063
- const contentMarkupRef = params.content !== void 0 && params.content.trim() !== "" ? yield* client.uploadMarkup(
173064
- documentPlugin.class.Document,
173065
- documentId,
173066
- "content",
173067
- params.content,
173068
- "markdown"
173069
- ) : null;
173070
- const documentData = {
173071
- title: params.title,
173072
- content: contentMarkupRef,
173073
- parent: parentRef,
173074
- rank
173075
- };
173076
- yield* client.createDoc(
173077
- documentPlugin.class.Document,
173078
- teamspace._id,
173079
- documentData,
173080
- documentId
173081
- );
173082
- return {
173083
- id: DocumentId.make(documentId),
173084
- title: params.title,
173085
- url: buildDocumentUrlFromConfig(client.workbenchUrlConfig, params.title, DocumentId.make(documentId))
173086
- };
173314
+ var UpdateAttachmentParamsSchema = Schema_exports.Struct({
173315
+ attachmentId: AttachmentId.annotations({
173316
+ description: "Attachment ID"
173317
+ }),
173318
+ description: Schema_exports.optional(
173319
+ Schema_exports.NullOr(Schema_exports.String).annotations({
173320
+ description: "New description (null to clear)"
173321
+ })
173322
+ ),
173323
+ pinned: Schema_exports.optional(Schema_exports.Boolean.annotations({
173324
+ description: "Pin or unpin the attachment"
173325
+ }))
173326
+ }).annotations({
173327
+ title: "UpdateAttachmentParams",
173328
+ description: "Parameters for updating an attachment"
173087
173329
  });
173088
- var deleteDocument = (params) => Effect_exports.gen(function* () {
173089
- const { client, doc, teamspace } = yield* findTeamspaceAndDocument(params);
173090
- yield* client.removeDoc(
173091
- documentPlugin.class.Document,
173092
- teamspace._id,
173093
- doc._id
173094
- );
173095
- return { id: DocumentId.make(doc._id), deleted: true };
173330
+ var DeleteAttachmentParamsSchema = Schema_exports.Struct({
173331
+ attachmentId: AttachmentId.annotations({
173332
+ description: "Attachment ID to delete"
173333
+ })
173334
+ }).annotations({
173335
+ title: "DeleteAttachmentParams",
173336
+ description: "Parameters for deleting an attachment"
173096
173337
  });
173097
-
173098
- // src/huly/operations/issues-shared.ts
173099
- var import_tracker = __toESM(require_lib36(), 1);
173100
-
173101
- // src/utils/normalize.ts
173102
- var normalizeForComparison = (s) => s.replace(/[-_ ]/g, "").toLowerCase();
173103
-
173104
- // src/huly/operations/issues-shared.ts
173105
- var zeroAsUnset = (value3) => value3 > 0 ? PositiveNumber.make(value3) : void 0;
173106
- var findProject = (projectIdentifier) => Effect_exports.gen(function* () {
173107
- const client = yield* HulyClient;
173108
- const project3 = yield* findOneOrFail(
173109
- client,
173110
- tracker.class.Project,
173111
- { identifier: projectIdentifier },
173112
- () => new ProjectNotFoundError({ identifier: projectIdentifier })
173113
- );
173114
- return { client, project: project3 };
173338
+ var PinAttachmentParamsSchema = Schema_exports.Struct({
173339
+ attachmentId: AttachmentId.annotations({
173340
+ description: "Attachment ID"
173341
+ }),
173342
+ pinned: Schema_exports.Boolean.annotations({
173343
+ description: "Whether to pin (true) or unpin (false)"
173344
+ })
173345
+ }).annotations({
173346
+ title: "PinAttachmentParams",
173347
+ description: "Parameters for pinning/unpinning an attachment"
173115
173348
  });
173116
- var findProjectWithStatuses = (projectIdentifier) => Effect_exports.gen(function* () {
173117
- const client = yield* HulyClient;
173118
- const project3 = yield* findOneOrFail(
173119
- client,
173120
- tracker.class.Project,
173121
- { identifier: projectIdentifier },
173122
- () => new ProjectNotFoundError({ identifier: projectIdentifier }),
173123
- { lookup: { type: task.class.ProjectType } }
173124
- );
173125
- const projectType = project3.$lookup?.type;
173126
- const statuses = [];
173127
- if (projectType?.statuses) {
173128
- const statusRefs = projectType.statuses.map((s) => s._id);
173129
- if (statusRefs.length > 0) {
173130
- const statusDocsResult = yield* Effect_exports.either(
173131
- client.findAll(
173132
- core.class.Status,
173133
- { _id: { $in: statusRefs } }
173134
- )
173135
- );
173136
- if (statusDocsResult._tag === "Right") {
173137
- for (const doc of statusDocsResult.right) {
173138
- const categoryStr = doc.category ? doc.category : "";
173139
- statuses.push({
173140
- _id: doc._id,
173141
- name: doc.name,
173142
- isDone: categoryStr === task.statusCategory.Won,
173143
- isCanceled: categoryStr === task.statusCategory.Lost
173144
- });
173145
- }
173146
- } else {
173147
- yield* Effect_exports.logWarning(
173148
- `Status query failed for project ${projectIdentifier}, using fallback. Category-based filtering (open/done/canceled) will use name heuristics. Error: ${statusDocsResult.left.message}`
173149
- );
173150
- for (const ps of projectType.statuses) {
173151
- const name = ps._id.split(":").pop() ?? "Unknown";
173152
- const nameLower = name.toLowerCase();
173153
- const isDone5 = nameLower.includes("done") || nameLower.includes("complete") || nameLower.includes("finished") || nameLower.includes("resolved") || nameLower.includes("closed");
173154
- const isCanceled = nameLower.includes("cancel") || nameLower.includes("reject") || nameLower.includes("abort") || nameLower.includes("wontfix") || nameLower.includes("invalid");
173155
- statuses.push({
173156
- _id: ps._id,
173157
- name,
173158
- isDone: isDone5,
173159
- isCanceled
173160
- });
173161
- }
173162
- }
173163
- }
173164
- }
173165
- const defaultStatusId = project3.defaultIssueStatus || statuses[0]?._id;
173166
- return { client, project: project3, statuses, defaultStatusId };
173349
+ var DownloadAttachmentParamsSchema = Schema_exports.Struct({
173350
+ attachmentId: AttachmentId.annotations({
173351
+ description: "Attachment ID"
173352
+ })
173353
+ }).annotations({
173354
+ title: "DownloadAttachmentParams",
173355
+ description: "Parameters for getting attachment download URL"
173167
173356
  });
173168
- var parseIssueIdentifier = (identifier2, projectIdentifier) => {
173169
- const idStr = String(identifier2).trim();
173170
- const match16 = idStr.match(/^([A-Z]+)-(\d+)$/i);
173171
- if (match16) {
173172
- return {
173173
- fullIdentifier: `${match16[1].toUpperCase()}-${match16[2]}`,
173174
- number: parseInt(match16[2], 10)
173175
- };
173176
- }
173177
- const numMatch = idStr.match(/^\d+$/);
173178
- if (numMatch) {
173179
- const num = parseInt(idStr, 10);
173180
- return {
173181
- fullIdentifier: `${projectIdentifier.toUpperCase()}-${num}`,
173182
- number: num
173183
- };
173184
- }
173185
- return { fullIdentifier: idStr, number: null };
173186
- };
173187
- var findIssueInProject = (client, project3, identifierStr) => Effect_exports.gen(function* () {
173188
- const { fullIdentifier, number: number8 } = parseIssueIdentifier(
173189
- identifierStr,
173190
- project3.identifier
173191
- );
173192
- const issue2 = (yield* client.findOne(
173193
- tracker.class.Issue,
173194
- {
173195
- space: project3._id,
173196
- identifier: fullIdentifier
173197
- }
173198
- )) ?? (number8 !== null ? yield* client.findOne(
173199
- tracker.class.Issue,
173200
- {
173201
- space: project3._id,
173202
- number: number8
173203
- }
173204
- ) : void 0);
173205
- if (issue2 === void 0) {
173206
- return yield* new IssueNotFoundError({
173207
- identifier: identifierStr,
173208
- project: project3.identifier
173209
- });
173210
- }
173211
- return issue2;
173357
+ var AddIssueAttachmentParamsBase = Schema_exports.Struct({
173358
+ project: ProjectIdentifier.annotations({
173359
+ description: "Project identifier (e.g., 'HULY')"
173360
+ }),
173361
+ identifier: IssueIdentifier.annotations({
173362
+ description: "Issue identifier (e.g., 'HULY-123')"
173363
+ }),
173364
+ ...FileSourceFields
173212
173365
  });
173213
- var findProjectAndIssue = (params) => Effect_exports.gen(function* () {
173214
- const { client, project: project3 } = yield* findProject(params.project);
173215
- const issue2 = yield* findIssueInProject(client, project3, params.identifier);
173216
- return { client, project: project3, issue: issue2 };
173366
+ var AddIssueAttachmentParamsSchema = AddIssueAttachmentParamsBase.pipe(
173367
+ Schema_exports.filter(hasFileSource)
173368
+ ).annotations({
173369
+ title: "AddIssueAttachmentParams",
173370
+ description: "Parameters for adding an attachment to an issue"
173217
173371
  });
173218
- var priorityToStringMap = {
173219
- [import_tracker.IssuePriority.Urgent]: "urgent",
173220
- [import_tracker.IssuePriority.High]: "high",
173221
- [import_tracker.IssuePriority.Medium]: "medium",
173222
- [import_tracker.IssuePriority.Low]: "low",
173223
- [import_tracker.IssuePriority.NoPriority]: "no-priority"
173224
- };
173225
- var priorityToString = (priority) => priorityToStringMap[priority];
173226
- var stringToPriorityMap = {
173227
- "urgent": import_tracker.IssuePriority.Urgent,
173228
- "high": import_tracker.IssuePriority.High,
173229
- "medium": import_tracker.IssuePriority.Medium,
173230
- "low": import_tracker.IssuePriority.Low,
173231
- "no-priority": import_tracker.IssuePriority.NoPriority
173232
- };
173233
- var stringToPriority = (priority) => stringToPriorityMap[priority];
173234
- var resolveStatusByName = (statuses, statusName, project3) => {
173235
- const normalizedInput = normalizeForComparison(statusName);
173236
- const matchingStatus = statuses.find(
173237
- (s) => normalizeForComparison(s.name) === normalizedInput
173238
- );
173239
- if (matchingStatus === void 0) {
173240
- return Effect_exports.fail(new InvalidStatusError({ status: statusName, project: project3 }));
173241
- }
173242
- return Effect_exports.succeed(matchingStatus._id);
173243
- };
173372
+ var AddDocumentAttachmentParamsBase = Schema_exports.Struct({
173373
+ teamspace: TeamspaceIdentifier.annotations({
173374
+ description: "Teamspace name or ID"
173375
+ }),
173376
+ document: DocumentIdentifier.annotations({
173377
+ description: "Document title or ID"
173378
+ }),
173379
+ ...FileSourceFields
173380
+ });
173381
+ var AddDocumentAttachmentParamsSchema = AddDocumentAttachmentParamsBase.pipe(
173382
+ Schema_exports.filter(hasFileSource)
173383
+ ).annotations({
173384
+ title: "AddDocumentAttachmentParams",
173385
+ description: "Parameters for adding an attachment to a document"
173386
+ });
173387
+ var listAttachmentsParamsJsonSchema = JSONSchema_exports.make(ListAttachmentsParamsSchema);
173388
+ var getAttachmentParamsJsonSchema = JSONSchema_exports.make(GetAttachmentParamsSchema);
173389
+ var addAttachmentParamsJsonSchema = JSONSchema_exports.make(AddAttachmentParamsSchema);
173390
+ var updateAttachmentParamsJsonSchema = JSONSchema_exports.make(UpdateAttachmentParamsSchema);
173391
+ var deleteAttachmentParamsJsonSchema = JSONSchema_exports.make(DeleteAttachmentParamsSchema);
173392
+ var pinAttachmentParamsJsonSchema = JSONSchema_exports.make(PinAttachmentParamsSchema);
173393
+ var downloadAttachmentParamsJsonSchema = JSONSchema_exports.make(DownloadAttachmentParamsSchema);
173394
+ var addIssueAttachmentParamsJsonSchema = JSONSchema_exports.make(AddIssueAttachmentParamsSchema);
173395
+ var addDocumentAttachmentParamsJsonSchema = JSONSchema_exports.make(AddDocumentAttachmentParamsSchema);
173396
+ var parseListAttachmentsParams = Schema_exports.decodeUnknown(ListAttachmentsParamsSchema);
173397
+ var parseGetAttachmentParams = Schema_exports.decodeUnknown(GetAttachmentParamsSchema);
173398
+ var parseAddAttachmentParams = Schema_exports.decodeUnknown(AddAttachmentParamsSchema);
173399
+ var parseUpdateAttachmentParams = Schema_exports.decodeUnknown(UpdateAttachmentParamsSchema);
173400
+ var parseDeleteAttachmentParams = Schema_exports.decodeUnknown(DeleteAttachmentParamsSchema);
173401
+ var parsePinAttachmentParams = Schema_exports.decodeUnknown(PinAttachmentParamsSchema);
173402
+ var parseDownloadAttachmentParams = Schema_exports.decodeUnknown(DownloadAttachmentParamsSchema);
173403
+ var parseAddIssueAttachmentParams = Schema_exports.decodeUnknown(AddIssueAttachmentParamsSchema);
173404
+ var parseAddDocumentAttachmentParams = Schema_exports.decodeUnknown(AddDocumentAttachmentParamsSchema);
173244
173405
 
173245
173406
  // src/huly/operations/attachments.ts
173407
+ var import_core23 = __toESM(require_lib4(), 1);
173246
173408
  var clearAttachmentDescription = (ops) => {
173247
173409
  Object.assign(ops, { description: "" });
173248
173410
  };
@@ -176681,14 +176843,24 @@ var DeleteDmMessageParamsSchema = Schema_exports.Struct({
176681
176843
  title: "DeleteDmMessageParams",
176682
176844
  description: "Parameters for deleting a direct-message message"
176683
176845
  });
176846
+ var CreateDirectMessageParamsSchema = Schema_exports.Struct({
176847
+ person: PersonRefInput.annotations({
176848
+ description: "Participant to open a one-to-one DM with: email address or exact display name (e.g. `Smith,Bill`). Resolved via the Employee mixin to a Huly account."
176849
+ })
176850
+ }).annotations({
176851
+ title: "CreateDirectMessageParams",
176852
+ description: "Parameters for opening a one-to-one direct-message conversation with another workspace member. If a one-to-one DM with that participant already exists, it is returned unchanged."
176853
+ });
176684
176854
  var listDmMessagesParamsJsonSchema = JSONSchema_exports.make(ListDmMessagesParamsSchema);
176685
176855
  var sendDmMessageParamsJsonSchema = JSONSchema_exports.make(SendDmMessageParamsSchema);
176686
176856
  var updateDmMessageParamsJsonSchema = JSONSchema_exports.make(UpdateDmMessageParamsSchema);
176687
176857
  var deleteDmMessageParamsJsonSchema = JSONSchema_exports.make(DeleteDmMessageParamsSchema);
176858
+ var createDirectMessageParamsJsonSchema = JSONSchema_exports.make(CreateDirectMessageParamsSchema);
176688
176859
  var parseListDmMessagesParams = Schema_exports.decodeUnknown(ListDmMessagesParamsSchema);
176689
176860
  var parseSendDmMessageParams = Schema_exports.decodeUnknown(SendDmMessageParamsSchema);
176690
176861
  var parseUpdateDmMessageParams = Schema_exports.decodeUnknown(UpdateDmMessageParamsSchema);
176691
176862
  var parseDeleteDmMessageParams = Schema_exports.decodeUnknown(DeleteDmMessageParamsSchema);
176863
+ var parseCreateDirectMessageParams = Schema_exports.decodeUnknown(CreateDirectMessageParamsSchema);
176692
176864
 
176693
176865
  // src/domain/schemas/time.ts
176694
176866
  var LogTimeParamsSchema = Schema_exports.Struct({
@@ -176987,6 +177159,7 @@ var RemoveIssueRelationResultSchema = Schema_exports.Struct({
176987
177159
  });
176988
177160
  var ListIssueRelationsResultSchema = Schema_exports.Struct({
176989
177161
  blockedBy: Schema_exports.Array(RelationEntryWireSchema),
177162
+ blocks: Schema_exports.Array(RelationEntryWireSchema),
176990
177163
  relations: Schema_exports.Array(RelationEntryWireSchema),
176991
177164
  documents: Schema_exports.Array(DocumentRelationEntryWireSchema)
176992
177165
  });
@@ -178092,118 +178265,275 @@ var updateCard = (params) => Effect_exports.gen(function* () {
178092
178265
  );
178093
178266
  updateOps.content = contentMarkupRef;
178094
178267
  }
178095
- }
178096
- if (Object.keys(updateOps).length === 0 && !contentUpdatedInPlace) {
178097
- return { id: CardId.make(card._id), updated: false };
178098
- }
178099
- if (Object.keys(updateOps).length > 0) {
178100
- yield* client.updateDoc(
178101
- card._class,
178102
- cardSpace._id,
178103
- card._id,
178104
- updateOps
178268
+ }
178269
+ if (Object.keys(updateOps).length === 0 && !contentUpdatedInPlace) {
178270
+ return { id: CardId.make(card._id), updated: false };
178271
+ }
178272
+ if (Object.keys(updateOps).length > 0) {
178273
+ yield* client.updateDoc(
178274
+ card._class,
178275
+ cardSpace._id,
178276
+ card._id,
178277
+ updateOps
178278
+ );
178279
+ }
178280
+ return { id: CardId.make(card._id), updated: true };
178281
+ });
178282
+ var deleteCard = (params) => Effect_exports.gen(function* () {
178283
+ const { card, cardSpace, client } = yield* findCardSpaceAndCard({
178284
+ card: params.card,
178285
+ cardSpace: params.cardSpace
178286
+ });
178287
+ yield* client.removeDoc(
178288
+ card._class,
178289
+ cardSpace._id,
178290
+ card._id
178291
+ );
178292
+ return { id: CardId.make(card._id), deleted: true };
178293
+ });
178294
+
178295
+ // src/mcp/tools/cards.ts
178296
+ var CATEGORY4 = "cards";
178297
+ var cardTools = [
178298
+ {
178299
+ name: "list_card_spaces",
178300
+ description: "List all Huly card spaces. Returns card spaces sorted by name. Card spaces are containers for cards.",
178301
+ category: CATEGORY4,
178302
+ inputSchema: listCardSpacesParamsJsonSchema,
178303
+ handler: createToolHandler(
178304
+ "list_card_spaces",
178305
+ parseListCardSpacesParams,
178306
+ listCardSpaces
178307
+ )
178308
+ },
178309
+ {
178310
+ name: "list_master_tags",
178311
+ description: "List master tags (card types) available in a Huly card space. Master tags define the type/schema of cards that can be created in a space.",
178312
+ category: CATEGORY4,
178313
+ inputSchema: listMasterTagsParamsJsonSchema,
178314
+ handler: createToolHandler(
178315
+ "list_master_tags",
178316
+ parseListMasterTagsParams,
178317
+ listMasterTags
178318
+ )
178319
+ },
178320
+ {
178321
+ name: "list_cards",
178322
+ description: "List cards in a Huly card space. Returns cards sorted by modification date (newest first). Supports filtering by type (master tag), title substring, and content search.",
178323
+ category: CATEGORY4,
178324
+ inputSchema: listCardsParamsJsonSchema,
178325
+ handler: createToolHandler(
178326
+ "list_cards",
178327
+ parseListCardsParams,
178328
+ listCards
178329
+ )
178330
+ },
178331
+ {
178332
+ name: "get_card",
178333
+ description: "Retrieve full details for a Huly card including markdown content. Use this to view card content and metadata.",
178334
+ category: CATEGORY4,
178335
+ inputSchema: getCardParamsJsonSchema,
178336
+ handler: createToolHandler(
178337
+ "get_card",
178338
+ parseGetCardParams,
178339
+ getCard
178340
+ )
178341
+ },
178342
+ {
178343
+ name: "create_card",
178344
+ description: "Create a new card in a Huly card space. Requires a master tag (card type). Content supports markdown formatting. Returns the created card id.",
178345
+ category: CATEGORY4,
178346
+ inputSchema: createCardParamsJsonSchema,
178347
+ handler: createToolHandler(
178348
+ "create_card",
178349
+ parseCreateCardParams,
178350
+ createCard
178351
+ )
178352
+ },
178353
+ {
178354
+ name: "update_card",
178355
+ description: "Update fields on an existing Huly card. Only provided fields are modified. Content updates support markdown.",
178356
+ category: CATEGORY4,
178357
+ inputSchema: updateCardParamsJsonSchema,
178358
+ handler: createToolHandler(
178359
+ "update_card",
178360
+ parseUpdateCardParams,
178361
+ updateCard
178362
+ )
178363
+ },
178364
+ {
178365
+ name: "delete_card",
178366
+ description: "Permanently delete a Huly card. This action cannot be undone.",
178367
+ category: CATEGORY4,
178368
+ inputSchema: deleteCardParamsJsonSchema,
178369
+ handler: createToolHandler(
178370
+ "delete_card",
178371
+ parseDeleteCardParams,
178372
+ deleteCard
178373
+ )
178374
+ }
178375
+ ];
178376
+
178377
+ // src/huly/operations/direct-messages.ts
178378
+ var import_core28 = __toESM(require_lib4(), 1);
178379
+
178380
+ // src/huly/operations/contacts-shared.ts
178381
+ var import_core27 = __toESM(require_lib4(), 1);
178382
+ var isEmailIdentifier = Schema_exports.is(Email);
178383
+ var findPersonById = (client, personId) => client.findOne(
178384
+ contact.class.Person,
178385
+ { _id: toRef(personId) }
178386
+ );
178387
+ var findPersonByEmail = (client, email3) => Effect_exports.gen(function* () {
178388
+ const channels = yield* client.findAll(
178389
+ contact.class.Channel,
178390
+ {
178391
+ value: email3,
178392
+ provider: contact.channelProvider.Email
178393
+ }
178394
+ );
178395
+ if (channels.length === 0) {
178396
+ return void 0;
178397
+ }
178398
+ const channel = channels[0];
178399
+ return yield* client.findOne(
178400
+ contact.class.Person,
178401
+ { _id: toRef(channel.attachedTo) }
178402
+ );
178403
+ });
178404
+ var batchGetEmailsForPersons = (client, personIds) => Effect_exports.gen(function* () {
178405
+ if (personIds.length === 0) {
178406
+ return /* @__PURE__ */ new Map();
178407
+ }
178408
+ const channels = yield* client.findAll(
178409
+ contact.class.Channel,
178410
+ {
178411
+ attachedTo: { $in: personIds },
178412
+ provider: contact.channelProvider.Email
178413
+ }
178414
+ );
178415
+ const emailMap = /* @__PURE__ */ new Map();
178416
+ for (const channel of channels) {
178417
+ if (!emailMap.has(channel.attachedTo)) {
178418
+ emailMap.set(channel.attachedTo, channel.value);
178419
+ }
178420
+ }
178421
+ return emailMap;
178422
+ });
178423
+ var findPersonBySocialIdentityEmail = (client, email3) => Effect_exports.gen(function* () {
178424
+ const identity5 = yield* client.findOne(
178425
+ contact.class.SocialIdentity,
178426
+ {
178427
+ type: import_core27.SocialIdType.EMAIL,
178428
+ value: email3
178429
+ }
178430
+ );
178431
+ if (identity5 === void 0) return void 0;
178432
+ return yield* client.findOne(
178433
+ contact.class.Person,
178434
+ { _id: identity5.attachedTo }
178435
+ );
178436
+ });
178437
+ var findPersonByExactEmail = (client, email3) => Effect_exports.gen(function* () {
178438
+ const socialIdentities = yield* client.findAll(
178439
+ contact.class.SocialIdentity,
178440
+ {
178441
+ type: import_core27.SocialIdType.EMAIL,
178442
+ value: email3
178443
+ }
178444
+ );
178445
+ const channels = yield* client.findAll(
178446
+ contact.class.Channel,
178447
+ {
178448
+ value: email3,
178449
+ provider: contact.channelProvider.Email
178450
+ }
178451
+ );
178452
+ const personIds = [
178453
+ .../* @__PURE__ */ new Set([
178454
+ ...socialIdentities.map((identity5) => identity5.attachedTo),
178455
+ ...channels.map((channel) => channel.attachedTo)
178456
+ ])
178457
+ ];
178458
+ if (personIds.length === 0) {
178459
+ return void 0;
178460
+ }
178461
+ const persons = yield* client.findAll(
178462
+ contact.class.Person,
178463
+ { _id: { $in: personIds.map(toRef) } }
178464
+ );
178465
+ if (persons.length === 0) {
178466
+ return void 0;
178467
+ }
178468
+ if (persons.length > 1) {
178469
+ return yield* new PersonIdentifierAmbiguousError({ identifier: email3, matches: persons.length });
178470
+ }
178471
+ return persons[0];
178472
+ });
178473
+ var findPersonByExactName = (client, name) => Effect_exports.gen(function* () {
178474
+ const persons = yield* client.findAll(
178475
+ contact.class.Person,
178476
+ { name }
178477
+ );
178478
+ if (persons.length === 0) {
178479
+ return void 0;
178480
+ }
178481
+ if (persons.length > 1) {
178482
+ return yield* new PersonIdentifierAmbiguousError({ identifier: name, matches: persons.length });
178483
+ }
178484
+ return persons[0];
178485
+ });
178486
+ var findPersonByExactEmailOrName = (client, identifier2) => isEmailIdentifier(identifier2) ? findPersonByExactEmail(client, identifier2) : findPersonByExactName(client, identifier2);
178487
+ var findPersonByEmailOrName = (client, emailOrName) => Effect_exports.gen(function* () {
178488
+ const socialIdentityPerson = yield* findPersonBySocialIdentityEmail(client, emailOrName);
178489
+ if (socialIdentityPerson !== void 0) return socialIdentityPerson;
178490
+ const exactChannel = yield* client.findOne(
178491
+ contact.class.Channel,
178492
+ {
178493
+ value: emailOrName,
178494
+ provider: contact.channelProvider.Email
178495
+ }
178496
+ );
178497
+ if (exactChannel !== void 0) {
178498
+ const person = yield* client.findOne(
178499
+ contact.class.Person,
178500
+ { _id: toRef(exactChannel.attachedTo) }
178501
+ );
178502
+ if (person !== void 0) return person;
178503
+ }
178504
+ const exactPerson = yield* client.findOne(
178505
+ contact.class.Person,
178506
+ { name: emailOrName }
178507
+ );
178508
+ if (exactPerson !== void 0) return exactPerson;
178509
+ const escaped = escapeLikeWildcards(emailOrName);
178510
+ const likeChannel = yield* client.findOne(
178511
+ contact.class.Channel,
178512
+ {
178513
+ value: { $like: `%${escaped}%` },
178514
+ provider: contact.channelProvider.Email
178515
+ }
178516
+ );
178517
+ if (likeChannel !== void 0) {
178518
+ const person = yield* client.findOne(
178519
+ contact.class.Person,
178520
+ { _id: toRef(likeChannel.attachedTo) }
178105
178521
  );
178522
+ if (person !== void 0) return person;
178106
178523
  }
178107
- return { id: CardId.make(card._id), updated: true };
178108
- });
178109
- var deleteCard = (params) => Effect_exports.gen(function* () {
178110
- const { card, cardSpace, client } = yield* findCardSpaceAndCard({
178111
- card: params.card,
178112
- cardSpace: params.cardSpace
178113
- });
178114
- yield* client.removeDoc(
178115
- card._class,
178116
- cardSpace._id,
178117
- card._id
178524
+ const likePerson = yield* client.findOne(
178525
+ contact.class.Person,
178526
+ { name: { $like: `%${escaped}%` } }
178118
178527
  );
178119
- return { id: CardId.make(card._id), deleted: true };
178528
+ return likePerson;
178120
178529
  });
178121
178530
 
178122
- // src/mcp/tools/cards.ts
178123
- var CATEGORY4 = "cards";
178124
- var cardTools = [
178125
- {
178126
- name: "list_card_spaces",
178127
- description: "List all Huly card spaces. Returns card spaces sorted by name. Card spaces are containers for cards.",
178128
- category: CATEGORY4,
178129
- inputSchema: listCardSpacesParamsJsonSchema,
178130
- handler: createToolHandler(
178131
- "list_card_spaces",
178132
- parseListCardSpacesParams,
178133
- listCardSpaces
178134
- )
178135
- },
178136
- {
178137
- name: "list_master_tags",
178138
- description: "List master tags (card types) available in a Huly card space. Master tags define the type/schema of cards that can be created in a space.",
178139
- category: CATEGORY4,
178140
- inputSchema: listMasterTagsParamsJsonSchema,
178141
- handler: createToolHandler(
178142
- "list_master_tags",
178143
- parseListMasterTagsParams,
178144
- listMasterTags
178145
- )
178146
- },
178147
- {
178148
- name: "list_cards",
178149
- description: "List cards in a Huly card space. Returns cards sorted by modification date (newest first). Supports filtering by type (master tag), title substring, and content search.",
178150
- category: CATEGORY4,
178151
- inputSchema: listCardsParamsJsonSchema,
178152
- handler: createToolHandler(
178153
- "list_cards",
178154
- parseListCardsParams,
178155
- listCards
178156
- )
178157
- },
178158
- {
178159
- name: "get_card",
178160
- description: "Retrieve full details for a Huly card including markdown content. Use this to view card content and metadata.",
178161
- category: CATEGORY4,
178162
- inputSchema: getCardParamsJsonSchema,
178163
- handler: createToolHandler(
178164
- "get_card",
178165
- parseGetCardParams,
178166
- getCard
178167
- )
178168
- },
178169
- {
178170
- name: "create_card",
178171
- description: "Create a new card in a Huly card space. Requires a master tag (card type). Content supports markdown formatting. Returns the created card id.",
178172
- category: CATEGORY4,
178173
- inputSchema: createCardParamsJsonSchema,
178174
- handler: createToolHandler(
178175
- "create_card",
178176
- parseCreateCardParams,
178177
- createCard
178178
- )
178179
- },
178180
- {
178181
- name: "update_card",
178182
- description: "Update fields on an existing Huly card. Only provided fields are modified. Content updates support markdown.",
178183
- category: CATEGORY4,
178184
- inputSchema: updateCardParamsJsonSchema,
178185
- handler: createToolHandler(
178186
- "update_card",
178187
- parseUpdateCardParams,
178188
- updateCard
178189
- )
178190
- },
178191
- {
178192
- name: "delete_card",
178193
- description: "Permanently delete a Huly card. This action cannot be undone.",
178194
- category: CATEGORY4,
178195
- inputSchema: deleteCardParamsJsonSchema,
178196
- handler: createToolHandler(
178197
- "delete_card",
178198
- parseDeleteCardParams,
178199
- deleteCard
178200
- )
178201
- }
178202
- ];
178203
-
178204
178531
  // src/huly/operations/direct-messages.ts
178205
- var import_core27 = __toESM(require_lib4(), 1);
178206
- var ONE_TO_ONE_DM_MEMBER_COUNT = 2;
178532
+ var sortedMemberPair = (first2, second) => [first2, second].sort();
178533
+ var hasExactMembers = (dm, sortedMembers) => {
178534
+ const dmMembers = [...dm.members].sort();
178535
+ return dmMembers.length === sortedMembers.length && sortedMembers.every((member, index) => dmMembers[index] === member);
178536
+ };
178207
178537
  var findDirectMessage = (identifier2) => Effect_exports.gen(function* () {
178208
178538
  const client = yield* HulyClient;
178209
178539
  const byId = yield* client.findOne(
@@ -178233,9 +178563,8 @@ var findDirectMessage = (identifier2) => Effect_exports.gen(function* () {
178233
178563
  chunter.class.DirectMessage,
178234
178564
  { members: accountUuid }
178235
178565
  );
178236
- const matches = directMessages.filter(
178237
- (dm) => dm.members.length === ONE_TO_ONE_DM_MEMBER_COUNT && dm.members.includes(accountUuid) && accountUuids.some((candidate) => dm.members.includes(candidate))
178238
- );
178566
+ const memberPairs = accountUuids.map((candidate) => sortedMemberPair(accountUuid, candidate));
178567
+ const matches = directMessages.filter((dm) => memberPairs.some((members) => hasExactMembers(dm, members)));
178239
178568
  if (matches.length === 0) {
178240
178569
  return yield* new DirectMessageNotFoundError({ identifier: identifier2 });
178241
178570
  }
@@ -178270,7 +178599,7 @@ var listDirectMessageMessages = (params) => Effect_exports.gen(function* () {
178270
178599
  { space: dm._id },
178271
178600
  {
178272
178601
  limit,
178273
- sort: { createdOn: import_core27.SortingOrder.Descending }
178602
+ sort: { createdOn: import_core28.SortingOrder.Descending }
178274
178603
  }
178275
178604
  );
178276
178605
  const total = messages.total;
@@ -178296,7 +178625,7 @@ var listDirectMessageMessages = (params) => Effect_exports.gen(function* () {
178296
178625
  var sendDirectMessage = (params) => Effect_exports.gen(function* () {
178297
178626
  const { client, dm } = yield* findDirectMessage(params.dm);
178298
178627
  const markupUrlConfig = client.markupUrlConfig;
178299
- const messageId = (0, import_core27.generateId)();
178628
+ const messageId = (0, import_core28.generateId)();
178300
178629
  const markup = markdownToMarkupString(params.body, markupUrlConfig);
178301
178630
  const messageData = {
178302
178631
  message: markup,
@@ -178339,9 +178668,56 @@ var deleteDirectMessage = (params) => Effect_exports.gen(function* () {
178339
178668
  );
178340
178669
  return { id: MessageId.make(message._id), deleted: true };
178341
178670
  });
178671
+ var resolveEmployeeAccount = (identifier2) => Effect_exports.gen(function* () {
178672
+ const client = yield* HulyClient;
178673
+ const person = yield* findPersonByExactEmailOrName(client, identifier2);
178674
+ if (person === void 0) {
178675
+ return yield* new PersonNotFoundError({ identifier: identifier2 });
178676
+ }
178677
+ const employee = yield* client.findOne(
178678
+ contact.mixin.Employee,
178679
+ { _id: toRef(person._id) }
178680
+ );
178681
+ if (employee?.personUuid === void 0) {
178682
+ return yield* new PersonNotAnEmployeeError({ identifier: identifier2 });
178683
+ }
178684
+ return employee.personUuid;
178685
+ });
178686
+ var createDirectMessage = (params) => Effect_exports.gen(function* () {
178687
+ const client = yield* HulyClient;
178688
+ const me = client.getAccountUuid();
178689
+ const other = yield* resolveEmployeeAccount(params.person);
178690
+ if (other === me) {
178691
+ return yield* new CannotDirectMessageSelfError({ identifier: params.person });
178692
+ }
178693
+ const existingDms = yield* client.findAll(
178694
+ chunter.class.DirectMessage,
178695
+ { members: me }
178696
+ );
178697
+ const members = sortedMemberPair(me, other);
178698
+ const existing = existingDms.find((dm) => hasExactMembers(dm, members));
178699
+ if (existing !== void 0) {
178700
+ return { id: ChannelId.make(existing._id), created: false };
178701
+ }
178702
+ const dmId = (0, import_core28.generateId)();
178703
+ const dmData = {
178704
+ name: "",
178705
+ description: "",
178706
+ private: true,
178707
+ archived: false,
178708
+ members
178709
+ };
178710
+ yield* client.createDoc(
178711
+ chunter.class.DirectMessage,
178712
+ toRef(core.space.Space),
178713
+ dmData,
178714
+ dmId
178715
+ );
178716
+ return { id: ChannelId.make(dmId), created: true };
178717
+ });
178342
178718
 
178343
178719
  // src/huly/operations/threads.ts
178344
- var import_core28 = __toESM(require_lib4(), 1);
178720
+ var import_core29 = __toESM(require_lib4(), 1);
178345
178721
  var findReply = (client, channel, message, replyId) => Effect_exports.gen(function* () {
178346
178722
  const reply = yield* client.findOne(
178347
178723
  chunter.class.ThreadMessage,
@@ -178372,7 +178748,7 @@ var listThreadReplies = (params) => Effect_exports.gen(function* () {
178372
178748
  {
178373
178749
  limit,
178374
178750
  sort: {
178375
- createdOn: import_core28.SortingOrder.Ascending
178751
+ createdOn: import_core29.SortingOrder.Ascending
178376
178752
  }
178377
178753
  }
178378
178754
  );
@@ -178400,7 +178776,7 @@ var listThreadReplies = (params) => Effect_exports.gen(function* () {
178400
178776
  var addThreadReply = (params) => Effect_exports.gen(function* () {
178401
178777
  const { channel, client, message } = yield* findChannelMessage(params);
178402
178778
  const markupUrlConfig = client.markupUrlConfig;
178403
- const replyId = (0, import_core28.generateId)();
178779
+ const replyId = (0, import_core29.generateId)();
178404
178780
  const markup = markdownToMarkupString(params.body, markupUrlConfig);
178405
178781
  const replyData = {
178406
178782
  message: markup,
@@ -178565,6 +178941,17 @@ var channelTools = [
178565
178941
  listDirectMessages
178566
178942
  )
178567
178943
  },
178944
+ {
178945
+ name: "create_direct_message",
178946
+ description: "Open a one-to-one direct-message conversation with a workspace member. The `person` argument accepts an email or exact display name (e.g. `Smith,Bill`). Idempotent: if a DM with that participant already exists, returns it (`created: false`); otherwise creates a new DM (`created: true`). The returned `id` can be passed as `dm` to send_dm_message, list_dm_messages, etc.",
178947
+ category: CATEGORY5,
178948
+ inputSchema: createDirectMessageParamsJsonSchema,
178949
+ handler: createToolHandler(
178950
+ "create_direct_message",
178951
+ parseCreateDirectMessageParams,
178952
+ createDirectMessage
178953
+ )
178954
+ },
178568
178955
  {
178569
178956
  name: "list_dm_messages",
178570
178957
  description: "List messages in a direct-message conversation, newest first. The `dm` argument accepts either the DM `_id` or a participant display name (e.g. `Kerr,Shannon`); a name resolves only to a one-to-one DM with the authenticated account.",
@@ -178656,7 +179043,7 @@ var channelTools = [
178656
179043
  ];
178657
179044
 
178658
179045
  // src/huly/operations/comments.ts
178659
- var import_core29 = __toESM(require_lib4(), 1);
179046
+ var import_core30 = __toESM(require_lib4(), 1);
178660
179047
  var findProjectAndIssue2 = (params) => findProjectAndIssue({ project: params.project, identifier: params.issueIdentifier });
178661
179048
  var findComment = (params) => Effect_exports.gen(function* () {
178662
179049
  const { client, issue: issue2, project: project3 } = yield* findProjectAndIssue2({
@@ -178695,7 +179082,7 @@ var listComments = (params) => Effect_exports.gen(function* () {
178695
179082
  {
178696
179083
  limit,
178697
179084
  sort: {
178698
- createdOn: import_core29.SortingOrder.Ascending
179085
+ createdOn: import_core30.SortingOrder.Ascending
178699
179086
  }
178700
179087
  }
178701
179088
  );
@@ -178724,7 +179111,7 @@ var addComment = (params) => Effect_exports.gen(function* () {
178724
179111
  issueIdentifier: params.issueIdentifier
178725
179112
  });
178726
179113
  const markupUrlConfig = client.markupUrlConfig;
178727
- const commentId = (0, import_core29.generateId)();
179114
+ const commentId = (0, import_core30.generateId)();
178728
179115
  const commentData = {
178729
179116
  message: markdownToMarkupString(params.body, markupUrlConfig)
178730
179117
  };
@@ -178850,106 +179237,6 @@ var leadClassIds = {
178850
179237
  }
178851
179238
  };
178852
179239
 
178853
- // src/huly/operations/contacts-shared.ts
178854
- var import_core30 = __toESM(require_lib4(), 1);
178855
- var findPersonById = (client, personId) => client.findOne(
178856
- contact.class.Person,
178857
- { _id: toRef(personId) }
178858
- );
178859
- var findPersonByEmail = (client, email3) => Effect_exports.gen(function* () {
178860
- const channels = yield* client.findAll(
178861
- contact.class.Channel,
178862
- {
178863
- value: email3,
178864
- provider: contact.channelProvider.Email
178865
- }
178866
- );
178867
- if (channels.length === 0) {
178868
- return void 0;
178869
- }
178870
- const channel = channels[0];
178871
- return yield* client.findOne(
178872
- contact.class.Person,
178873
- { _id: toRef(channel.attachedTo) }
178874
- );
178875
- });
178876
- var batchGetEmailsForPersons = (client, personIds) => Effect_exports.gen(function* () {
178877
- if (personIds.length === 0) {
178878
- return /* @__PURE__ */ new Map();
178879
- }
178880
- const channels = yield* client.findAll(
178881
- contact.class.Channel,
178882
- {
178883
- attachedTo: { $in: personIds },
178884
- provider: contact.channelProvider.Email
178885
- }
178886
- );
178887
- const emailMap = /* @__PURE__ */ new Map();
178888
- for (const channel of channels) {
178889
- if (!emailMap.has(channel.attachedTo)) {
178890
- emailMap.set(channel.attachedTo, channel.value);
178891
- }
178892
- }
178893
- return emailMap;
178894
- });
178895
- var findPersonBySocialIdentityEmail = (client, email3) => Effect_exports.gen(function* () {
178896
- const identity5 = yield* client.findOne(
178897
- contact.class.SocialIdentity,
178898
- {
178899
- type: import_core30.SocialIdType.EMAIL,
178900
- value: email3
178901
- }
178902
- );
178903
- if (identity5 === void 0) return void 0;
178904
- return yield* client.findOne(
178905
- contact.class.Person,
178906
- { _id: identity5.attachedTo }
178907
- );
178908
- });
178909
- var findPersonByEmailOrName = (client, emailOrName) => Effect_exports.gen(function* () {
178910
- const socialIdentityPerson = yield* findPersonBySocialIdentityEmail(client, emailOrName);
178911
- if (socialIdentityPerson !== void 0) return socialIdentityPerson;
178912
- const exactChannel = yield* client.findOne(
178913
- contact.class.Channel,
178914
- {
178915
- value: emailOrName,
178916
- provider: contact.channelProvider.Email
178917
- }
178918
- );
178919
- if (exactChannel !== void 0) {
178920
- const person = yield* client.findOne(
178921
- contact.class.Person,
178922
- { _id: toRef(exactChannel.attachedTo) }
178923
- );
178924
- if (person !== void 0) return person;
178925
- }
178926
- const exactPerson = yield* client.findOne(
178927
- contact.class.Person,
178928
- { name: emailOrName }
178929
- );
178930
- if (exactPerson !== void 0) return exactPerson;
178931
- const escaped = escapeLikeWildcards(emailOrName);
178932
- const likeChannel = yield* client.findOne(
178933
- contact.class.Channel,
178934
- {
178935
- value: { $like: `%${escaped}%` },
178936
- provider: contact.channelProvider.Email
178937
- }
178938
- );
178939
- if (likeChannel !== void 0) {
178940
- const person = yield* client.findOne(
178941
- contact.class.Person,
178942
- { _id: toRef(likeChannel.attachedTo) }
178943
- );
178944
- if (person !== void 0) return person;
178945
- }
178946
- const likePerson = yield* client.findOne(
178947
- contact.class.Person,
178948
- { name: { $like: `%${escaped}%` } }
178949
- );
178950
- return likePerson;
178951
- });
178952
-
178953
179240
  // src/huly/operations/organizations.ts
178954
179241
  var findOrganizationByIdentifier = (client, identifier2) => Effect_exports.gen(function* () {
178955
179242
  const byId = yield* client.findOne(
@@ -180557,9 +180844,6 @@ var listIssueRelations = (params) => Effect_exports.gen(function* () {
180557
180844
  });
180558
180845
  const blockedByRefs = issue2.blockedBy ?? [];
180559
180846
  const relationsRefs = issue2.relations ?? [];
180560
- if (blockedByRefs.length === 0 && relationsRefs.length === 0) {
180561
- return { blockedBy: [], relations: [], documents: [] };
180562
- }
180563
180847
  const docClass = String(documentPlugin.class.Document);
180564
180848
  const issueRelationsRefs = [];
180565
180849
  const docRelationsRefs = [];
@@ -180584,6 +180868,16 @@ var listIssueRelations = (params) => Effect_exports.gen(function* () {
180584
180868
  _id: toIssueId(String(r._id)),
180585
180869
  _class: toObjectClassName(String(r._class))
180586
180870
  });
180871
+ const toIssueEntry = (i) => ({
180872
+ identifier: toIssueIdentifier(i.identifier),
180873
+ _id: toIssueId(String(i._id)),
180874
+ _class: toObjectClassName(String(i._class))
180875
+ });
180876
+ const blockingIssueCandidates = yield* client.findAll(
180877
+ tracker.class.Issue,
180878
+ { "blockedBy._id": toRef(issue2._id) }
180879
+ );
180880
+ const blocks = blockingIssueCandidates.filter((candidate) => candidate._id !== issue2._id && hasRelationById(candidate.blockedBy, issue2._id)).map(toIssueEntry);
180587
180881
  const documents = [];
180588
180882
  if (docRelationsRefs.length > 0) {
180589
180883
  const toDocRef = toRef;
@@ -180617,6 +180911,7 @@ var listIssueRelations = (params) => Effect_exports.gen(function* () {
180617
180911
  }
180618
180912
  return {
180619
180913
  blockedBy: blockedByRefs.map(toEntry),
180914
+ blocks,
180620
180915
  relations: issueRelationsRefs.map(toEntry),
180621
180916
  documents
180622
180917
  };
@@ -182082,7 +182377,7 @@ var issueTools = [
182082
182377
  },
182083
182378
  {
182084
182379
  name: "list_issue_relations",
182085
- description: "List all relations of an issue. Returns blockedBy (issues blocking this one), relations (bidirectional issue links), and documents (linked documents with title/teamspace). Does NOT return issues that this issue blocks \u2014 use list_issue_relations on the target issue to see that.",
182380
+ description: "List all relations of an issue. Returns blockedBy (issues blocking this one), blocks (issues this one blocks), relations (bidirectional issue links), and documents (linked documents with title/teamspace).",
182086
182381
  category: CATEGORY11,
182087
182382
  inputSchema: listIssueRelationsParamsJsonSchema,
182088
182383
  handler: createEncodedToolHandler(