@firfi/huly-mcp 0.49.7 → 0.50.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.
Files changed (3) hide show
  1. package/README.md +3 -3
  2. package/dist/index.cjs +1081 -996
  3. package/package.json +2 -2
package/dist/index.cjs CHANGED
@@ -115697,7 +115697,11 @@ var init_issues = __esm({
115697
115697
  )}. Use status for exact project-specific status names.`
115698
115698
  })
115699
115699
  ),
115700
- assignee: Schema_exports.optional(PersonRefInput.annotate({ description: "Filter by assignee email or display name" })),
115700
+ assignee: Schema_exports.optional(
115701
+ PersonRefInput.annotate({
115702
+ description: "Filter by assignee email, Person display name, or exact agent UserProfile title"
115703
+ })
115704
+ ),
115701
115705
  creator: Schema_exports.optional(
115702
115706
  PersonRefInput.annotate({
115703
115707
  description: "Filter by creator using a raw Person ID, exact email address, or exact display name. Ambiguous exact display names are rejected; unknown people return an empty list."
@@ -115806,7 +115810,9 @@ var init_issues = __esm({
115806
115810
  priority: Schema_exports.optional(
115807
115811
  IssuePrioritySchema.annotate({ description: "Issue priority (urgent, high, medium, low, no-priority)" })
115808
115812
  ),
115809
- assignee: Schema_exports.optional(PersonRefInput.annotate({ description: "Assignee email address or display name" })),
115813
+ assignee: Schema_exports.optional(
115814
+ PersonRefInput.annotate({ description: "Assignee email, Person display name, or exact agent UserProfile title" })
115815
+ ),
115810
115816
  status: Schema_exports.optional(
115811
115817
  StatusName.annotate({ description: "Initial status (uses project default if not specified)" })
115812
115818
  ),
@@ -115848,7 +115854,9 @@ var init_issues = __esm({
115848
115854
  ),
115849
115855
  priority: Schema_exports.optional(IssuePrioritySchema.annotate({ description: "New issue priority" })),
115850
115856
  assignee: Schema_exports.optional(
115851
- Schema_exports.NullOr(PersonRefInput).annotate({ description: "New assignee email or display name (null to unassign)" })
115857
+ Schema_exports.NullOr(PersonRefInput).annotate({
115858
+ description: "New assignee email, Person display name, or exact agent UserProfile title (null to unassign)"
115859
+ })
115852
115860
  ),
115853
115861
  status: Schema_exports.optional(StatusName.annotate({ description: "New status" })),
115854
115862
  taskType: Schema_exports.optional(
@@ -125200,7 +125208,7 @@ var VERSION;
125200
125208
  var init_version = __esm({
125201
125209
  "src/version.ts"() {
125202
125210
  "use strict";
125203
- VERSION = true ? "0.49.7" : "0.0.0-dev";
125211
+ VERSION = true ? "0.50.0" : "0.0.0-dev";
125204
125212
  }
125205
125213
  });
125206
125214
 
@@ -125545,7 +125553,7 @@ var init_errors_contacts = __esm({
125545
125553
  { identifier: Schema_exports.String, matches: AmbiguousMatchCount }
125546
125554
  ) {
125547
125555
  get message() {
125548
- return `Person identifier '${this.identifier}' matched ${this.matches} people; use an exact email address instead`;
125556
+ return `Person identifier '${this.identifier}' matched ${this.matches} people; use a unique Person display name or email address instead`;
125549
125557
  }
125550
125558
  };
125551
125559
  OrganizationNotFoundError = class extends Schema_exports.TaggedError()(
@@ -179278,14 +179286,50 @@ var init_update_guards = __esm({
179278
179286
  }
179279
179287
  });
179280
179288
 
179289
+ // src/utils/assertions.ts
179290
+ var PAIR_LENGTH, AssertionError, assertExists, isExistent, assertAt, isNonEmpty3, isSingle, isPair, getOneOrNoneEffect;
179291
+ var init_assertions = __esm({
179292
+ "src/utils/assertions.ts"() {
179293
+ "use strict";
179294
+ init_dist();
179295
+ PAIR_LENGTH = 2;
179296
+ AssertionError = class extends Error {
179297
+ _tag = "AssertionError";
179298
+ constructor(message) {
179299
+ super(message);
179300
+ this.name = "AssertionError";
179301
+ }
179302
+ };
179303
+ assertExists = (value3, message) => {
179304
+ if (value3 === null || value3 === void 0) {
179305
+ throw new AssertionError(message ?? "Expected value to exist");
179306
+ }
179307
+ return value3;
179308
+ };
179309
+ isExistent = (value3) => value3 !== null && value3 !== void 0;
179310
+ assertAt = (arr, index2, message) => {
179311
+ return assertExists(arr[index2], message ?? `Expected array item at index ${index2}`);
179312
+ };
179313
+ isNonEmpty3 = (arr) => arr.length > 0;
179314
+ isSingle = (arr) => arr.length === 1;
179315
+ isPair = (arr) => arr.length === PAIR_LENGTH;
179316
+ getOneOrNoneEffect = (arr, onTooMany) => {
179317
+ if (arr.length === 0) return Effect_exports.succeed(Option_exports.none());
179318
+ if (isSingle(arr)) return Effect_exports.succeed(Option_exports.some(arr[0]));
179319
+ return Effect_exports.fail(onTooMany(arr));
179320
+ };
179321
+ }
179322
+ });
179323
+
179281
179324
  // src/huly/operations/contacts-shared.ts
179282
- var import_core38, isEmailIdentifier, findPersonById, findPersonByEmail, batchGetEmailsForPersons, findPersonIdsByEmailSearch, findPersonBySocialIdentityEmail, findPersonByExactEmail, findPersonByExactName, findPersonByExactEmailOrName, findPersonByIdOrExactEmailOrName, resolveEmployeeAccountUuid, findPersonByEmailOrName;
179325
+ var import_core38, isEmailIdentifier, findPersonById, findPersonByEmail, batchGetEmailsForPersons, findPersonIdsByEmailSearch, findPersonIdsByEmailChannelSearch, findPersonIdsByExactEmailSources, loadPeopleByIds, findPeopleByExactName, findPeopleByNameSearch, findPersonBySocialIdentityEmail, findPersonByExactEmail, findPersonByExactName, findPersonByExactEmailOrName, findPersonByIdOrExactEmailOrName, resolveEmployeeAccountUuid, findPersonByEmailOrName;
179283
179326
  var init_contacts_shared = __esm({
179284
179327
  "src/huly/operations/contacts-shared.ts"() {
179285
179328
  "use strict";
179286
179329
  import_core38 = __toESM(require_lib6(), 1);
179287
179330
  init_dist();
179288
179331
  init_shared();
179332
+ init_assertions();
179289
179333
  init_errors4();
179290
179334
  init_huly_plugins();
179291
179335
  init_query_helpers();
@@ -179321,24 +179365,60 @@ var init_contacts_shared = __esm({
179321
179365
  return emailMap;
179322
179366
  });
179323
179367
  findPersonIdsByEmailSearch = (client, emailSearch) => Effect_exports.gen(function* () {
179324
- const value3 = { $like: `%${escapeLikeWildcards(emailSearch)}%` };
179325
- const [channels, socialIdentities] = yield* Effect_exports.all([
179326
- client.findAll(
179327
- contact.class.Channel,
179328
- hulyQuery({ provider: contact.channelProvider.Email, value: value3 })
179329
- ),
179368
+ const [channelPersonIds, socialIdentities] = yield* Effect_exports.all([
179369
+ findPersonIdsByEmailChannelSearch(client, emailSearch),
179330
179370
  client.findAll(
179331
179371
  contact.class.SocialIdentity,
179332
- hulyQuery({ type: import_core38.SocialIdType.EMAIL, value: value3 })
179372
+ hulyQuery({
179373
+ type: import_core38.SocialIdType.EMAIL,
179374
+ value: { $like: `%${escapeLikeWildcards(emailSearch)}%` }
179375
+ })
179333
179376
  )
179334
179377
  ]);
179335
179378
  return [
179336
- .../* @__PURE__ */ new Set([
179337
- ...channels.map((channel) => toRef(channel.attachedTo)),
179338
- ...socialIdentities.map((identity2) => toRef(identity2.attachedTo))
179339
- ])
179379
+ .../* @__PURE__ */ new Set([...channelPersonIds, ...socialIdentities.map((identity2) => toRef(identity2.attachedTo))])
179340
179380
  ];
179341
179381
  });
179382
+ findPersonIdsByEmailChannelSearch = (client, emailSearch) => Effect_exports.map(
179383
+ client.findAll(
179384
+ contact.class.Channel,
179385
+ hulyQuery({
179386
+ provider: contact.channelProvider.Email,
179387
+ value: { $like: `%${escapeLikeWildcards(emailSearch)}%` }
179388
+ })
179389
+ ),
179390
+ (channels) => [...new Set(channels.map((channel) => toRef(channel.attachedTo)))]
179391
+ );
179392
+ findPersonIdsByExactEmailSources = (client, email3) => Effect_exports.map(
179393
+ Effect_exports.all([
179394
+ client.findAll(
179395
+ contact.class.SocialIdentity,
179396
+ hulyQuery({ type: import_core38.SocialIdType.EMAIL, value: email3 })
179397
+ ),
179398
+ client.findAll(
179399
+ contact.class.Channel,
179400
+ hulyQuery({ value: email3, provider: contact.channelProvider.Email })
179401
+ )
179402
+ ]),
179403
+ ([socialIdentities, channels]) => [
179404
+ .../* @__PURE__ */ new Set([
179405
+ ...socialIdentities.map((identity2) => toRef(identity2.attachedTo)),
179406
+ ...channels.map((channel) => toRef(channel.attachedTo))
179407
+ ])
179408
+ ]
179409
+ );
179410
+ loadPeopleByIds = (client, personIds) => {
179411
+ const uniqueIds = [...new Set(personIds)];
179412
+ return uniqueIds.length === 0 ? Effect_exports.succeed([]) : Effect_exports.map(
179413
+ client.findAll(contact.class.Person, hulyQuery({ _id: { $in: uniqueIds } })),
179414
+ (people) => [...new Map(people.map((person) => [person._id, person])).values()]
179415
+ );
179416
+ };
179417
+ findPeopleByExactName = (client, name) => client.findAll(contact.class.Person, hulyQuery({ name }));
179418
+ findPeopleByNameSearch = (client, nameSearch) => client.findAll(
179419
+ contact.class.Person,
179420
+ hulyQuery({ name: { $like: `%${escapeLikeWildcards(nameSearch)}%` } })
179421
+ );
179342
179422
  findPersonBySocialIdentityEmail = (client, email3) => Effect_exports.gen(function* () {
179343
179423
  const identity2 = yield* client.findOne(contact.class.SocialIdentity, {
179344
179424
  type: import_core38.SocialIdType.EMAIL,
@@ -179348,43 +179428,23 @@ var init_contacts_shared = __esm({
179348
179428
  return yield* client.findOne(contact.class.Person, { _id: identity2.attachedTo });
179349
179429
  });
179350
179430
  findPersonByExactEmail = (client, email3) => Effect_exports.gen(function* () {
179351
- const socialIdentities = yield* client.findAll(contact.class.SocialIdentity, {
179352
- type: import_core38.SocialIdType.EMAIL,
179353
- value: email3
179354
- });
179355
- const channels = yield* client.findAll(contact.class.Channel, {
179356
- value: email3,
179357
- provider: contact.channelProvider.Email
179358
- });
179359
- const personIds = [
179360
- .../* @__PURE__ */ new Set([
179361
- ...socialIdentities.map((identity2) => identity2.attachedTo),
179362
- ...channels.map((channel) => channel.attachedTo)
179363
- ])
179364
- ];
179365
- if (personIds.length === 0) {
179366
- return void 0;
179367
- }
179368
- const persons = yield* client.findAll(contact.class.Person, {
179369
- _id: { $in: personIds.map(toRef) }
179370
- });
179371
- if (persons.length === 0) {
179372
- return void 0;
179373
- }
179374
- if (persons.length > 1) {
179375
- return yield* new PersonIdentifierAmbiguousError({ identifier: email3, matches: Count.make(persons.length) });
179376
- }
179377
- return persons[0];
179431
+ const personIds = yield* findPersonIdsByExactEmailSources(client, email3);
179432
+ const persons = yield* loadPeopleByIds(client, personIds);
179433
+ return Option_exports.getOrUndefined(
179434
+ yield* getOneOrNoneEffect(
179435
+ persons,
179436
+ (matches) => new PersonIdentifierAmbiguousError({ identifier: email3, matches: Count.make(matches.length) })
179437
+ )
179438
+ );
179378
179439
  });
179379
179440
  findPersonByExactName = (client, name) => Effect_exports.gen(function* () {
179380
- const persons = yield* client.findAll(contact.class.Person, { name });
179381
- if (persons.length === 0) {
179382
- return void 0;
179383
- }
179384
- if (persons.length > 1) {
179385
- return yield* new PersonIdentifierAmbiguousError({ identifier: name, matches: Count.make(persons.length) });
179386
- }
179387
- return persons[0];
179441
+ const persons = yield* findPeopleByExactName(client, name);
179442
+ return Option_exports.getOrUndefined(
179443
+ yield* getOneOrNoneEffect(
179444
+ persons,
179445
+ (matches) => new PersonIdentifierAmbiguousError({ identifier: name, matches: Count.make(matches.length) })
179446
+ )
179447
+ );
179388
179448
  });
179389
179449
  findPersonByExactEmailOrName = (client, identifier2) => isEmailIdentifier(identifier2) ? findPersonByExactEmail(client, identifier2) : findPersonByExactName(client, identifier2);
179390
179450
  findPersonByIdOrExactEmailOrName = (client, identifier2) => Effect_exports.gen(function* () {
@@ -179437,35 +179497,6 @@ var init_contacts_shared = __esm({
179437
179497
  }
179438
179498
  });
179439
179499
 
179440
- // src/utils/assertions.ts
179441
- var PAIR_LENGTH, AssertionError, assertExists, isExistent, assertAt, isNonEmpty3, isSingle, isPair;
179442
- var init_assertions = __esm({
179443
- "src/utils/assertions.ts"() {
179444
- "use strict";
179445
- PAIR_LENGTH = 2;
179446
- AssertionError = class extends Error {
179447
- _tag = "AssertionError";
179448
- constructor(message) {
179449
- super(message);
179450
- this.name = "AssertionError";
179451
- }
179452
- };
179453
- assertExists = (value3, message) => {
179454
- if (value3 === null || value3 === void 0) {
179455
- throw new AssertionError(message ?? "Expected value to exist");
179456
- }
179457
- return value3;
179458
- };
179459
- isExistent = (value3) => value3 !== null && value3 !== void 0;
179460
- assertAt = (arr, index2, message) => {
179461
- return assertExists(arr[index2], message ?? `Expected array item at index ${index2}`);
179462
- };
179463
- isNonEmpty3 = (arr) => arr.length > 0;
179464
- isSingle = (arr) => arr.length === 1;
179465
- isPair = (arr) => arr.length === PAIR_LENGTH;
179466
- }
179467
- });
179468
-
179469
179500
  // src/huly/operations/spaces-shared.ts
179470
179501
  var import_core39, spaceClass, sortStrings, uniqueSorted, mergeUniqueSortedAccountUuids, removeAccountUuids, arraysEqual, optionalString, optionalObjectClassName, RoleAssignmentStorageSchema, RoleAssignmentStorageObjectSchema, parseRoleAssignmentStorageObject, validStoredAccountUuid, parsedSpaceRoleAssignmentEntry, spaceRoleAssignmentSource, roleAssignmentsMalformedError, readSpaceRoleAssignmentEntries, spaceRoleAssignmentEntries, hasSpaceRoleAssignmentMixin, strictSpaceRoleAssignments, roleAssignmentDegradationMessage, spaceRoleAssignmentsMixin, applySpaceFilters, findSpace, spaceMapById, updateSpaceDoc, resolveMembers;
179471
179502
  var init_spaces_shared = __esm({
@@ -193865,7 +193896,7 @@ var init_persons = __esm({
193865
193896
  };
193866
193897
  applyPersonEmailSearch = (client, query, emailSearch) => Effect_exports.gen(function* () {
193867
193898
  if (emailSearch === void 0 || emailSearch === "") return true;
193868
- const matchingPersonIds = yield* findPersonIdsByEmailSearch(client, emailSearch);
193899
+ const matchingPersonIds = yield* findPersonIdsByEmailSearch(client, NonEmptyString2.make(emailSearch));
193869
193900
  if (matchingPersonIds.length === 0) return false;
193870
193901
  query._id = { $in: matchingPersonIds };
193871
193902
  return true;
@@ -199903,332 +199934,960 @@ var init_issues_parent = __esm({
199903
199934
  }
199904
199935
  });
199905
199936
 
199906
- // src/huly/operations/issues-move.ts
199907
- var import_core87, import_tracker3, issueTargetClass, addLabel, moveIssue, updateDescendantParents;
199908
- var init_issues_move = __esm({
199909
- "src/huly/operations/issues-move.ts"() {
199937
+ // src/huly/operations/issue-native-references.ts
199938
+ var renderIssueDescriptionForWrite;
199939
+ var init_issue_native_references = __esm({
199940
+ "src/huly/operations/issue-native-references.ts"() {
199910
199941
  "use strict";
199911
- import_core87 = __toESM(require_lib6(), 1);
199912
- import_tracker3 = __toESM(require_lib25(), 1);
199913
199942
  init_dist();
199914
- init_shared();
199915
- init_tags();
199916
- init_huly_plugins();
199917
- init_issues_parent();
199918
- init_issues_shared();
199919
- init_query_helpers();
199920
- init_sdk_boundary();
199921
- init_tags_shared();
199922
- issueTargetClass = TagTargetClass.make(String(tracker.class.Issue));
199923
- addLabel = (params2) => Effect_exports.gen(function* () {
199924
- const { issue: issue2, project } = yield* findProjectAndIssue(params2);
199925
- const labelTitle = TagIdentifier.make(params2.label.trim());
199926
- const tag2 = yield* ensureTagElement({
199927
- targetClass: issueTargetClass,
199928
- titleOrId: labelTitle,
199929
- color: params2.color,
199930
- fallbackCategory: tracker.category.Other
199931
- });
199932
- const result3 = yield* attachTagReference({
199933
- tag: tag2,
199934
- objectId: issue2._id,
199935
- objectClass: tracker.class.Issue,
199936
- space: project._id,
199937
- collection: "labels",
199938
- matchTitleCaseInsensitive: true
199939
- });
199940
- return { identifier: IssueIdentifier.make(issue2.identifier), labelAdded: result3.attached };
199941
- });
199942
- moveIssue = (params2) => Effect_exports.gen(function* () {
199943
- const { client, issue: issue2, project } = yield* findProjectAndIssue(params2);
199944
- const oldParentIsIssue = hasConcreteIssueParent(issue2);
199945
- const newParentParam = params2.newParent;
199946
- const target = newParentParam !== null ? yield* Effect_exports.gen(function* () {
199947
- const parentIssue = yield* findIssueInProject(client, project, newParentParam);
199948
- return {
199949
- _tag: "Child",
199950
- identifier: IssueIdentifier.make(parentIssue.identifier),
199951
- issue: parentIssue,
199952
- parent: childIssueParent(parentIssue, project._id)
199953
- };
199954
- }) : { _tag: "TopLevel", parent: topLevelIssueParent() };
199955
- if (target._tag === "Child") {
199956
- yield* attachIssueChild(client, project._id, issue2._id, target.issue, {});
199957
- } else {
199958
- yield* client.updateDoc(tracker.class.Issue, project._id, issue2._id, {
199959
- attachedTo: toRef(target.parent.attachedTo),
199960
- attachedToClass: target.parent.attachedToClass,
199961
- collection: target.parent.collection,
199962
- parents: target.parent.parents
199963
- });
199964
- }
199965
- if (oldParentIsIssue) {
199966
- yield* client.updateDoc(
199967
- tracker.class.Issue,
199968
- project._id,
199969
- // issue.attachedTo is Ref<Doc>; for sub-issues it points to the parent issue.
199970
- // Cast needed because updateDoc expects Ref<HulyIssue> but attachedTo is Ref<Doc>.
199971
- toRef(issue2.attachedTo),
199972
- { $inc: { subIssues: -1 } }
199973
- );
199974
- }
199975
- if (issue2.subIssues > 0) {
199976
- yield* updateDescendantParents(client, project._id, issue2, target.parent.parents);
199977
- }
199978
- const result3 = { identifier: IssueIdentifier.make(issue2.identifier), moved: true };
199979
- if (target._tag === "Child") {
199980
- return { ...result3, newParent: target.identifier };
199981
- }
199982
- return result3;
199983
- });
199984
- updateDescendantParents = (client, spaceId, parentIssue, parentNewParents) => Effect_exports.gen(function* () {
199985
- const thisParentInfo = {
199986
- parentId: parentIssue._id,
199987
- identifier: parentIssue.identifier,
199988
- parentTitle: parentIssue.title,
199989
- space: spaceId
199990
- };
199991
- const children = yield* client.findAll(
199992
- tracker.class.Issue,
199993
- hulyQuery({ attachedTo: parentIssue._id, space: spaceId })
199994
- );
199995
- for (const child of children) {
199996
- const childNewParents = [...parentNewParents, thisParentInfo];
199997
- yield* client.updateDoc(tracker.class.Issue, spaceId, child._id, { parents: childNewParents });
199998
- if (child.subIssues > 0) {
199999
- yield* updateDescendantParents(client, spaceId, child, childNewParents);
200000
- }
199943
+ init_client();
199944
+ init_errors4();
199945
+ init_native_reference_markup();
199946
+ renderIssueDescriptionForWrite = (description) => Effect_exports.gen(function* () {
199947
+ const client = yield* HulyClient;
199948
+ const rendered = renderMarkdownWithNativeReferencesForWrite(description, client.markupUrlConfig, "description");
199949
+ if (rendered._tag === "malformed") {
199950
+ return yield* new IssueReferenceError({ reason: rendered.reason });
200001
199951
  }
199952
+ return rendered.rendered;
200002
199953
  });
200003
199954
  }
200004
199955
  });
200005
199956
 
200006
- // src/huly/operations/issue-creators-read.ts
200007
- var parsePersonRef, uniqueCreatorIds, creatorRef, creatorForIssue, loadIssueCreatorIndex;
200008
- var init_issue_creators_read = __esm({
200009
- "src/huly/operations/issue-creators-read.ts"() {
199957
+ // src/huly/operations/issue-assignee-resolution.ts
199958
+ var findExactPeople, findFuzzyPeople, oneAssigneeOrNone, findIssueAssignee;
199959
+ var init_issue_assignee_resolution = __esm({
199960
+ "src/huly/operations/issue-assignee-resolution.ts"() {
200010
199961
  "use strict";
200011
199962
  init_dist();
200012
- init_issues();
200013
- init_tool_warnings();
200014
- init_diagnostics();
199963
+ init_shared();
199964
+ init_assertions();
199965
+ init_errors4();
200015
199966
  init_huly_plugins();
200016
199967
  init_contacts_shared();
200017
199968
  init_query_helpers();
200018
199969
  init_sdk_boundary();
200019
- parsePersonRef = Schema_exports.decodeUnknownOption(PersonRefSchema);
200020
- uniqueCreatorIds = (issues) => [
200021
- ...new Set(issues.flatMap((issue2) => issue2.createdBy === void 0 ? [] : [issue2.createdBy]))
200022
- ];
200023
- creatorRef = (person, emailByPerson) => parsePersonRef({
200024
- id: person._id,
200025
- ...person.name.trim() === "" ? {} : { name: person.name },
200026
- ...emailByPerson.has(person._id) ? { email: emailByPerson.get(person._id) } : {}
199970
+ findExactPeople = Effect_exports.fn("IssueAssigneeResolution.findExactPeople")(function* (client, identifier2) {
199971
+ const [emailPersonIds, namedPeople, profiles] = yield* Effect_exports.all([
199972
+ findPersonIdsByExactEmailSources(client, identifier2),
199973
+ findPeopleByExactName(client, identifier2),
199974
+ client.findAll(
199975
+ toClassRef(contact.class.UserProfile),
199976
+ hulyQuery({ title: identifier2 })
199977
+ )
199978
+ ]);
199979
+ return yield* loadPeopleByIds(client, [
199980
+ ...emailPersonIds,
199981
+ ...namedPeople.map((person) => person._id),
199982
+ ...profiles.map((profile) => profile.person)
199983
+ ]);
200027
199984
  });
200028
- creatorForIssue = (index2, issue2) => issue2.createdBy === void 0 ? void 0 : index2.get(issue2.createdBy);
200029
- loadIssueCreatorIndex = (client, issues) => Effect_exports.gen(function* () {
200030
- const creatorIds = uniqueCreatorIds(issues);
200031
- if (creatorIds.length === 0) return /* @__PURE__ */ new Map();
200032
- const identities = yield* client.findAll(
200033
- contact.class.SocialIdentity,
200034
- hulyQuery({ _id: { $in: creatorIds.map(toSocialIdentityRef) } })
200035
- );
200036
- const personIds = [...new Set(identities.map((identity2) => identity2.attachedTo))];
200037
- const persons = personIds.length === 0 ? [] : yield* client.findAll(
200038
- contact.class.Person,
200039
- hulyQuery({ _id: { $in: personIds.map(toRef) } })
200040
- );
200041
- const emailByPerson = yield* batchGetEmailsForPersons(
200042
- client,
200043
- persons.map((person) => person._id)
200044
- );
200045
- const personById = new Map(persons.map((person) => [person._id, person]));
200046
- const index2 = /* @__PURE__ */ new Map();
200047
- for (const identity2 of identities) {
200048
- const person = personById.get(identity2.attachedTo);
200049
- if (person === void 0) continue;
200050
- const parsed = creatorRef(person, emailByPerson);
200051
- if (Option_exports.isSome(parsed)) index2.set(identity2._id, parsed.value);
200052
- }
200053
- const unresolvedCount = creatorIds.filter((creatorId) => !index2.has(creatorId)).length;
200054
- if (unresolvedCount > 0) {
200055
- const diagnostics = yield* Diagnostics;
200056
- yield* diagnostics.warnAgent({
200057
- code: IssueCreatorMetadataDegradedWarningCode,
200058
- message: `${unresolvedCount} unresolved issue creator reference(s) were omitted from issue results.`
200059
- });
200060
- }
200061
- return index2;
199985
+ findFuzzyPeople = Effect_exports.fn("IssueAssigneeResolution.findFuzzyPeople")(function* (client, identifier2) {
199986
+ const [emailPersonIds, namedPeople] = yield* Effect_exports.all([
199987
+ findPersonIdsByEmailChannelSearch(client, identifier2),
199988
+ findPeopleByNameSearch(client, identifier2)
199989
+ ]);
199990
+ return yield* loadPeopleByIds(client, [...emailPersonIds, ...namedPeople.map((person) => person._id)]);
199991
+ });
199992
+ oneAssigneeOrNone = (identifier2, people) => getOneOrNoneEffect(
199993
+ people,
199994
+ (matches) => new PersonIdentifierAmbiguousError({ identifier: identifier2, matches: Count.make(matches.length) })
199995
+ );
199996
+ findIssueAssignee = Effect_exports.fn("IssueAssigneeResolution.findIssueAssignee")(function* (client, identifier2) {
199997
+ const exactPeople = yield* findExactPeople(client, identifier2);
199998
+ const exactPerson = yield* oneAssigneeOrNone(identifier2, exactPeople);
199999
+ if (Option_exports.isSome(exactPerson)) return exactPerson;
200000
+ return yield* oneAssigneeOrNone(identifier2, yield* findFuzzyPeople(client, identifier2));
200062
200001
  });
200063
200002
  }
200064
200003
  });
200065
200004
 
200066
- // src/huly/operations/issue-labels-read.ts
200067
- var IssueLabelAttachmentBoundarySchema, NormalizedLabelTitle, decodeAttachment, decodeTitle, decodeColor, toDocRef2, toIssueRef, normalizeLabelTitle, COLOR_SORT_WIDTH, compareStrings, candidateSortKey, compareCandidates, toCandidate3, projectionCandidate, projectionDegradationReason, projectCandidateGroup, buildIssueLabelIndex, countReason, degradationMessage, labelsForIssue, issueIdsMatchingLabel, loadIssueLabelIndex;
200068
- var init_issue_labels_read = __esm({
200069
- "src/huly/operations/issue-labels-read.ts"() {
200005
+ // src/huly/operations/issues-write-shared.ts
200006
+ var resolveAssignee, TASK_TYPE_DISCOVERY_HINT, taskTypeMatches, describeTaskTypeOptions, mergeTaskTypes2, resolveTaskTypeWorkflow, validStatusNames, resolveStatusForTaskType, chooseStatusForTaskType;
200007
+ var init_issues_write_shared = __esm({
200008
+ "src/huly/operations/issues-write-shared.ts"() {
200070
200009
  "use strict";
200071
200010
  init_dist();
200072
- init_shared();
200073
- init_tool_warnings();
200074
- init_diagnostics();
200011
+ init_normalize();
200012
+ init_errors4();
200075
200013
  init_huly_plugins();
200014
+ init_issue_assignee_resolution();
200076
200015
  init_query_helpers();
200077
- init_sdk_boundary();
200078
- IssueLabelAttachmentBoundarySchema = Schema_exports.Struct({
200079
- _id: TagReferenceId,
200080
- attachedTo: IssueId,
200081
- title: Schema_exports.optional(Schema_exports.Unknown),
200082
- color: Schema_exports.optional(Schema_exports.Unknown)
200083
- }).annotate({
200084
- title: "IssueLabelAttachmentBoundary",
200085
- description: "Partial Huly TagReference fields used to project issue labels. Missing or malformed presentation fields are handled by stable projection rules."
200016
+ resolveAssignee = (client, assigneeIdentifier) => Effect_exports.gen(function* () {
200017
+ const person = yield* findIssueAssignee(client, assigneeIdentifier);
200018
+ return yield* Option_exports.match(person, {
200019
+ onNone: () => Effect_exports.fail(new PersonNotFoundError({ identifier: assigneeIdentifier })),
200020
+ onSome: Effect_exports.succeed
200021
+ });
200086
200022
  });
200087
- NormalizedLabelTitle = NonEmptyString2.pipe(Schema_exports.brand("NormalizedLabelTitle"));
200088
- decodeAttachment = Schema_exports.decodeUnknownResult(IssueLabelAttachmentBoundarySchema);
200089
- decodeTitle = Schema_exports.decodeUnknownResult(NonEmptyString2);
200090
- decodeColor = Schema_exports.decodeUnknownResult(ColorCode);
200091
- toDocRef2 = (id2) => toRef(IssueId.make(id2));
200092
- toIssueRef = toRef;
200093
- normalizeLabelTitle = (title) => NormalizedLabelTitle.make(title.toLowerCase());
200094
- COLOR_SORT_WIDTH = 2;
200095
- compareStrings = (left, right) => Number(left > right) - Number(left < right);
200096
- candidateSortKey = (candidate) => [
200097
- candidate.normalizedTitle,
200098
- candidate.color === void 0 ? "1" : "0",
200099
- candidate.title,
200100
- String(candidate.color).padStart(COLOR_SORT_WIDTH, "0"),
200101
- candidate.referenceId
200102
- ].join("\0");
200103
- compareCandidates = (left, right) => compareStrings(candidateSortKey(left), candidateSortKey(right));
200104
- toCandidate3 = (input) => {
200105
- const attachment2 = decodeAttachment(input);
200106
- if (Result_exports.isFailure(attachment2)) {
200107
- return { _tag: "Rejected", degradationReason: "malformed_attachment" };
200108
- }
200109
- const title = decodeTitle(attachment2.success.title);
200110
- if (Result_exports.isFailure(title)) {
200111
- return { _tag: "Rejected", degradationReason: "missing_or_malformed_title" };
200023
+ TASK_TYPE_DISCOVERY_HINT = "Use list_task_types or get_project_type to discover valid task types and statuses.";
200024
+ taskTypeMatches = (taskType, taskTypeRef) => String(taskType._id) === String(taskTypeRef) || normalizeForComparison(taskType.name) === normalizeForComparison(taskTypeRef);
200025
+ describeTaskTypeOptions = (taskTypes) => taskTypes.length === 0 ? "No task types are configured for this project type." : `Available task types: ${taskTypes.map((taskType) => `${taskType.name} (${taskType._id})`).join(", ")}.`;
200026
+ mergeTaskTypes2 = (first, second) => {
200027
+ const taskTypesById = /* @__PURE__ */ new Map();
200028
+ for (const taskType of [...first, ...second]) {
200029
+ taskTypesById.set(String(taskType._id), taskType);
200112
200030
  }
200113
- const colorInput = attachment2.success.color;
200114
- const color = colorInput === void 0 ? void 0 : decodeColor(colorInput);
200115
- const candidate = {
200116
- referenceId: attachment2.success._id,
200117
- issueId: attachment2.success.attachedTo,
200118
- title: title.success,
200119
- normalizedTitle: normalizeLabelTitle(title.success),
200120
- ...color !== void 0 && Result_exports.isSuccess(color) ? { color: color.success } : {}
200121
- };
200122
- return color !== void 0 && Result_exports.isFailure(color) ? { _tag: "DegradedSuccess", candidate, degradationReason: "invalid_color" } : { _tag: "Success", candidate };
200031
+ return [...taskTypesById.values()];
200123
200032
  };
200124
- projectionCandidate = (projection) => projection._tag === "Rejected" ? [] : [projection.candidate];
200125
- projectionDegradationReason = (projection) => {
200126
- switch (projection._tag) {
200127
- case "Success":
200128
- return [];
200129
- case "DegradedSuccess":
200130
- case "Rejected":
200131
- return [projection.degradationReason];
200033
+ resolveTaskTypeWorkflow = (client, project, projectType, projectStatuses, taskTypeRef, projectIdentifier) => Effect_exports.gen(function* () {
200034
+ const workflowProjectType = projectType ?? (yield* client.findOne(task.class.ProjectType, hulyQuery({ _id: project.type })));
200035
+ if (workflowProjectType === void 0) {
200036
+ return yield* Effect_exports.fail(
200037
+ new HulyError({
200038
+ message: `Project '${projectIdentifier}' does not expose a project type/workflow, so taskType cannot be resolved. ${TASK_TYPE_DISCOVERY_HINT}`
200039
+ })
200040
+ );
200132
200041
  }
200133
- };
200134
- projectCandidateGroup = (candidates) => {
200135
- const sorted = [...candidates].sort(compareCandidates);
200136
- return sorted.filter(
200137
- (candidate, index2) => sorted.findIndex((other) => other.normalizedTitle === candidate.normalizedTitle) === index2
200138
- ).map((candidate) => ({
200139
- title: candidate.title,
200140
- ...candidate.color === void 0 ? {} : { color: candidate.color }
200141
- }));
200142
- };
200143
- buildIssueLabelIndex = (attachments) => {
200144
- const projections = attachments.map(toCandidate3);
200145
- const candidates = projections.flatMap(projectionCandidate);
200146
- const issueIds = [...new Set(candidates.map((candidate) => candidate.issueId))];
200147
- return {
200148
- byIssueId: new Map(
200149
- issueIds.map((issueId) => [
200150
- issueId,
200151
- projectCandidateGroup(candidates.filter((candidate) => candidate.issueId === issueId))
200152
- ])
200153
- ),
200154
- degradationReasons: projections.flatMap(projectionDegradationReason)
200155
- };
200156
- };
200157
- countReason = (reasons, reason) => reasons.filter((candidate) => candidate === reason).length;
200158
- degradationMessage = (reasons) => {
200159
- const malformedAttachments = countReason(reasons, "malformed_attachment");
200160
- const malformedTitles = countReason(reasons, "missing_or_malformed_title");
200161
- const invalidColors = countReason(reasons, "invalid_color");
200162
- return `Issue label summaries omitted or partially projected malformed Huly metadata: ${malformedAttachments} malformed attachment(s), ${malformedTitles} missing or malformed title(s), and ${invalidColors} invalid color(s). Duplicate case-insensitive titles prefer a reference with a valid color.`;
200163
- };
200164
- labelsForIssue = (index2, issueId) => index2.byIssueId.get(IssueId.make(issueId)) ?? [];
200165
- issueIdsMatchingLabel = (index2, label) => {
200166
- const normalizedFilter = normalizeLabelTitle(label);
200167
- return [...index2.byIssueId].filter(([, labels]) => labels.some((summary) => normalizeLabelTitle(summary.title) === normalizedFilter)).map(([issueId]) => toIssueRef(issueId)).sort(compareStrings);
200168
- };
200169
- loadIssueLabelIndex = (client, space, issueIds) => Effect_exports.gen(function* () {
200170
- if (issueIds !== void 0 && issueIds.length === 0) return buildIssueLabelIndex([]);
200171
- const diagnostics = yield* Diagnostics;
200172
- const baseQuery = {
200173
- space,
200174
- attachedToClass: tracker.class.Issue,
200175
- collection: "labels"
200176
- };
200177
- const query = issueIds === void 0 ? baseQuery : { ...baseQuery, attachedTo: { $in: issueIds.map(toDocRef2) } };
200178
- const attachments = yield* client.findAll(tags.class.TagReference, hulyQuery(query));
200179
- const index2 = buildIssueLabelIndex(attachments);
200180
- if (index2.degradationReasons.length > 0) {
200181
- yield* diagnostics.warnAgent({
200182
- code: IssueLabelMetadataDegradedWarningCode,
200183
- message: degradationMessage(index2.degradationReasons)
200184
- });
200042
+ const taskTypesByProjectTypeList = yield* client.findAll(
200043
+ task.class.TaskType,
200044
+ hulyQuery({ _id: { $in: [...workflowProjectType.tasks] } })
200045
+ );
200046
+ const taskTypesByParent = yield* client.findAll(
200047
+ task.class.TaskType,
200048
+ hulyQuery({ parent: workflowProjectType._id })
200049
+ );
200050
+ const taskTypes = mergeTaskTypes2([...taskTypesByProjectTypeList], [...taskTypesByParent]);
200051
+ const matches = [...taskTypes].filter((candidate) => taskTypeMatches(candidate, taskTypeRef));
200052
+ const selectedTaskType = matches.length === 1 ? matches[0] : void 0;
200053
+ if (selectedTaskType === void 0) {
200054
+ const reason = matches.length === 0 ? "was not found" : "matched more than one task type";
200055
+ return yield* Effect_exports.fail(
200056
+ new HulyError({
200057
+ message: `Task type '${taskTypeRef}' ${reason} in project '${projectIdentifier}' workflow. ${describeTaskTypeOptions([...taskTypes])} ${TASK_TYPE_DISCOVERY_HINT}`
200058
+ })
200059
+ );
200185
200060
  }
200186
- return index2;
200061
+ const scopedStatuses = selectedTaskType.statuses.flatMap(
200062
+ (statusId) => projectStatuses.filter((status) => status._id === statusId)
200063
+ );
200064
+ const defaultStatusId = selectedTaskType.statuses.includes(project.defaultIssueStatus) ? project.defaultIssueStatus : selectedTaskType.statuses.at(0);
200065
+ return { defaultStatusId, statuses: scopedStatuses, taskType: selectedTaskType };
200187
200066
  });
200067
+ validStatusNames = (workflow) => workflow.statuses.length === 0 ? workflow.taskType.statuses.join(", ") : workflow.statuses.map((status) => status.name).join(", ");
200068
+ resolveStatusForTaskType = (workflow, statusName, projectIdentifier) => {
200069
+ const normalizedStatusName = normalizeForComparison(statusName);
200070
+ const match9 = workflow.statuses.find((status) => normalizeForComparison(status.name) === normalizedStatusName);
200071
+ const statusNames = validStatusNames(workflow);
200072
+ return match9 !== void 0 ? Effect_exports.succeed(match9._id) : Effect_exports.fail(
200073
+ new HulyError({
200074
+ message: `Status '${statusName}' is not valid for task type '${workflow.taskType.name}' in project '${projectIdentifier}'. Valid statuses for this task type: ${statusNames}. ${TASK_TYPE_DISCOVERY_HINT}`
200075
+ })
200076
+ );
200077
+ };
200078
+ chooseStatusForTaskType = (workflow, requestedStatus, currentStatus, projectIdentifier) => {
200079
+ if (requestedStatus !== void 0) {
200080
+ return resolveStatusForTaskType(workflow, requestedStatus, projectIdentifier);
200081
+ }
200082
+ if (currentStatus !== void 0 && workflow.taskType.statuses.includes(currentStatus)) {
200083
+ return Effect_exports.succeed(currentStatus);
200084
+ }
200085
+ return workflow.defaultStatusId !== void 0 ? Effect_exports.succeed(workflow.defaultStatusId) : Effect_exports.fail(
200086
+ new HulyError({
200087
+ message: `Task type '${workflow.taskType.name}' in project '${projectIdentifier}' has no valid status. ${TASK_TYPE_DISCOVERY_HINT}`
200088
+ })
200089
+ );
200090
+ };
200188
200091
  }
200189
200092
  });
200190
200093
 
200191
- // src/huly/operations/issue-milestones-read.ts
200192
- var parseMilestoneRef, uniqueMilestoneRefs, milestoneForIssue, loadIssueMilestoneIndex;
200193
- var init_issue_milestones_read = __esm({
200194
- "src/huly/operations/issue-milestones-read.ts"() {
200094
+ // src/huly/operations/issues-write.ts
200095
+ var import_core87, import_rank5, import_tracker3, TxIncResult2, extractUpdatedSequence, requireUpdatedSequence, resolveCreateIssueTaskType, resolveCreateIssueStatus, resolveCreateIssueAssignee, renderCreateIssueDescription, resolveCreateIssueParent, uploadCreateIssueDescription, createIssueWithAssignee, createIssue, createIssueWithResolvedAssignee, deleteIssue;
200096
+ var init_issues_write = __esm({
200097
+ "src/huly/operations/issues-write.ts"() {
200195
200098
  "use strict";
200099
+ import_core87 = __toESM(require_lib6(), 1);
200100
+ import_rank5 = __toESM(require_lib24(), 1);
200101
+ import_tracker3 = __toESM(require_lib25(), 1);
200196
200102
  init_dist();
200197
200103
  init_issues();
200198
200104
  init_shared();
200199
- init_tool_warnings();
200200
- init_diagnostics();
200105
+ init_errors4();
200201
200106
  init_huly_plugins();
200107
+ init_issue_native_references();
200108
+ init_issues_parent();
200109
+ init_issues_shared();
200110
+ init_issues_write_shared();
200202
200111
  init_query_helpers();
200203
- parseMilestoneRef = Schema_exports.decodeUnknownOption(IssueMilestoneRefSchema);
200204
- uniqueMilestoneRefs = (issues) => [
200205
- ...new Set(
200206
- issues.flatMap((issue2) => issue2.milestone === null || issue2.milestone === void 0 ? [] : [issue2.milestone])
200207
- )
200208
- ];
200209
- milestoneForIssue = (index2, issue2) => issue2.milestone === null || issue2.milestone === void 0 ? void 0 : index2.get(MilestoneId.make(issue2.milestone));
200210
- loadIssueMilestoneIndex = (client, project, issues) => Effect_exports.gen(function* () {
200211
- const refs = uniqueMilestoneRefs(issues);
200212
- if (refs.length === 0) return /* @__PURE__ */ new Map();
200213
- const milestones = yield* client.findAll(
200214
- tracker.class.Milestone,
200215
- hulyQuery({ space: project._id, _id: { $in: refs } })
200216
- );
200217
- const index2 = /* @__PURE__ */ new Map();
200218
- for (const milestone of milestones) {
200219
- const parsed = parseMilestoneRef({ id: milestone._id, label: milestone.label });
200220
- if (Option_exports.isSome(parsed)) index2.set(parsed.value.id, parsed.value);
200221
- }
200222
- const unresolvedCount = refs.filter((ref) => !index2.has(MilestoneId.make(ref))).length;
200223
- if (unresolvedCount > 0) {
200224
- const diagnostics = yield* Diagnostics;
200225
- yield* diagnostics.warnAgent({
200226
- code: IssueMilestoneMetadataDegradedWarningCode,
200227
- message: `${unresolvedCount} unresolved milestone reference(s) were omitted from issue results.`
200228
- });
200229
- }
200230
- return index2;
200231
- });
200112
+ init_sdk_boundary();
200113
+ TxIncResult2 = Schema_exports.Struct({ object: Schema_exports.Struct({ sequence: Schema_exports.Number }) });
200114
+ extractUpdatedSequence = (txResult) => {
200115
+ const decoded = Schema_exports.decodeUnknownOption(TxIncResult2)(txResult);
200116
+ return decoded._tag === "Some" ? decoded.value.object.sequence : void 0;
200117
+ };
200118
+ requireUpdatedSequence = (txResult, projectIdentifier) => {
200119
+ const sequence = extractUpdatedSequence(txResult);
200120
+ return sequence === void 0 ? Effect_exports.fail(
200121
+ new HulyError({
200122
+ message: `Project '${projectIdentifier}' sequence increment did not return the updated sequence; issue creation stopped to avoid a duplicate identifier.`
200123
+ })
200124
+ ) : Effect_exports.succeed(sequence);
200125
+ };
200126
+ resolveCreateIssueTaskType = (client, project, workflow, params2) => params2.taskType === void 0 ? Effect_exports.succeed(void 0) : resolveTaskTypeWorkflow(client, project, workflow.projectType, workflow.statuses, params2.taskType, params2.project);
200127
+ resolveCreateIssueStatus = (workflow, taskTypeWorkflow, params2) => {
200128
+ if (taskTypeWorkflow !== void 0) {
200129
+ return chooseStatusForTaskType(taskTypeWorkflow, params2.status, void 0, params2.project);
200130
+ }
200131
+ if (params2.status !== void 0) return resolveStatusByName(workflow.statuses, params2.status, params2.project);
200132
+ if (workflow.defaultStatusId !== void 0) return Effect_exports.succeed(workflow.defaultStatusId);
200133
+ return Effect_exports.fail(new InvalidStatusError({ status: "(default)", project: params2.project }));
200134
+ };
200135
+ resolveCreateIssueAssignee = (client, params2) => params2.assignee === void 0 ? Effect_exports.succeed(null) : Effect_exports.map(resolveAssignee(client, params2.assignee), (person) => person._id);
200136
+ renderCreateIssueDescription = (params2) => params2.description !== void 0 && params2.description.trim() !== "" ? renderIssueDescriptionForWrite(params2.description) : Effect_exports.succeed(void 0);
200137
+ resolveCreateIssueParent = (client, project, parentIssue) => parentIssue === void 0 ? Effect_exports.succeed(topLevelIssueParent()) : Effect_exports.map(findIssueInProject(client, project, parentIssue), (parent) => childIssueParent(parent, project._id));
200138
+ uploadCreateIssueDescription = (client, issueId, renderedDescription) => renderedDescription === void 0 ? Effect_exports.succeed(null) : client.uploadMarkup(
200139
+ tracker.class.Issue,
200140
+ issueId,
200141
+ "description",
200142
+ renderedDescription.markup,
200143
+ renderedDescription.format
200144
+ );
200145
+ createIssueWithAssignee = Effect_exports.fn("Issues.createWithAssignee")(function* (params2, assigneeResolution) {
200146
+ const { client, defaultStatusId, project, projectType, statuses } = yield* findProjectWithStatuses(params2.project);
200147
+ const issueId = (0, import_core87.generateId)();
200148
+ const workflow = { projectType, statuses, defaultStatusId };
200149
+ const taskTypeWorkflow = yield* resolveCreateIssueTaskType(client, project, workflow, params2);
200150
+ const statusRef = yield* resolveCreateIssueStatus(workflow, taskTypeWorkflow, params2);
200151
+ const assigneeRef = yield* assigneeResolution(client, params2);
200152
+ const renderedDescription = yield* renderCreateIssueDescription(params2);
200153
+ const { attachedTo, attachedToClass, collection, parents } = yield* resolveCreateIssueParent(
200154
+ client,
200155
+ project,
200156
+ params2.parentIssue
200157
+ );
200158
+ const incOps = { $inc: { sequence: 1 } };
200159
+ const incResult = yield* client.updateDoc(
200160
+ tracker.class.Project,
200161
+ toRef("core:space:Space"),
200162
+ project._id,
200163
+ incOps,
200164
+ true
200165
+ );
200166
+ const sequence = yield* requireUpdatedSequence(incResult, params2.project);
200167
+ const lastIssue = yield* client.findOne(
200168
+ tracker.class.Issue,
200169
+ hulyQuery({ space: project._id }),
200170
+ { sort: { rank: import_core87.SortingOrder.Descending } }
200171
+ );
200172
+ const rank = (0, import_rank5.makeRank)(lastIssue?.rank, void 0);
200173
+ const descriptionMarkupRef = yield* uploadCreateIssueDescription(client, issueId, renderedDescription);
200174
+ const priority = stringToPriority(params2.priority ?? DEFAULT_ISSUE_PRIORITY);
200175
+ const identifier2 = `${project.identifier}-${sequence}`;
200176
+ const issueData = {
200177
+ title: params2.title,
200178
+ description: descriptionMarkupRef,
200179
+ status: statusRef,
200180
+ number: sequence,
200181
+ kind: taskTypeWorkflow?.taskType._id ?? tracker.taskTypes.Issue,
200182
+ identifier: identifier2,
200183
+ priority,
200184
+ assignee: assigneeRef,
200185
+ component: null,
200186
+ estimation: params2.estimation ?? 0,
200187
+ remainingTime: 0,
200188
+ reportedTime: 0,
200189
+ reports: 0,
200190
+ subIssues: 0,
200191
+ parents,
200192
+ childInfo: [],
200193
+ dueDate: params2.dueDate ?? null,
200194
+ rank
200195
+ };
200196
+ yield* client.addCollection(
200197
+ tracker.class.Issue,
200198
+ project._id,
200199
+ attachedTo,
200200
+ attachedToClass,
200201
+ collection,
200202
+ issueData,
200203
+ issueId
200204
+ );
200205
+ return { identifier: IssueIdentifier.make(identifier2), issueId: IssueId.make(issueId) };
200206
+ });
200207
+ createIssue = (params2) => createIssueWithAssignee(params2, resolveCreateIssueAssignee);
200208
+ createIssueWithResolvedAssignee = (params2) => createIssueWithAssignee(params2, () => Effect_exports.succeed(params2.resolvedAssignee));
200209
+ deleteIssue = (params2) => Effect_exports.gen(function* () {
200210
+ const { client, issue: issue2, project } = yield* findProjectAndIssue(params2);
200211
+ yield* client.removeDoc(tracker.class.Issue, project._id, issue2._id);
200212
+ return { identifier: IssueIdentifier.make(issue2.identifier), deleted: true };
200213
+ });
200214
+ }
200215
+ });
200216
+
200217
+ // src/huly/operations/issue-templates.ts
200218
+ var import_core88, NOT_FOUND_INDEX2, findTemplateByIdOrTitle, findProjectAndTemplate, resolveTemplateReferenceLabels, templateChildProjection, resolveChild, buildTemplateChild, listIssueTemplates, getIssueTemplate, createIssueTemplate, resolveIssueFromTemplateAssignee, templateChildCreateParams, templateChildUpdate, createTemplateChildIssues, createIssueFromTemplate, updateIssueTemplate, deleteIssueTemplate, addTemplateChild, removeTemplateChild;
200219
+ var init_issue_templates2 = __esm({
200220
+ "src/huly/operations/issue-templates.ts"() {
200221
+ "use strict";
200222
+ import_core88 = __toESM(require_lib6(), 1);
200223
+ init_dist();
200224
+ init_issue_templates();
200225
+ init_issues();
200226
+ init_shared();
200227
+ init_time();
200228
+ init_assertions();
200229
+ init_errors4();
200230
+ init_clear_field_updates();
200231
+ init_components2();
200232
+ init_contacts_shared();
200233
+ init_issues_parent();
200234
+ init_issues_shared();
200235
+ init_issues_write();
200236
+ init_query_helpers();
200237
+ init_sdk_boundary();
200238
+ init_update_guards();
200239
+ init_huly_plugins();
200240
+ init_markup();
200241
+ NOT_FOUND_INDEX2 = -1;
200242
+ findTemplateByIdOrTitle = (client, projectId, templateIdOrTitle) => Effect_exports.gen(function* () {
200243
+ const template = (yield* client.findOne(tracker.class.IssueTemplate, {
200244
+ space: projectId,
200245
+ _id: toRef(templateIdOrTitle)
200246
+ })) ?? (yield* client.findOne(tracker.class.IssueTemplate, {
200247
+ space: projectId,
200248
+ title: templateIdOrTitle
200249
+ }));
200250
+ return template;
200251
+ });
200252
+ findProjectAndTemplate = (params2) => Effect_exports.gen(function* () {
200253
+ const { client, project } = yield* findProject(params2.project);
200254
+ const template = yield* findTemplateByIdOrTitle(client, project._id, params2.template);
200255
+ if (template === void 0) {
200256
+ return yield* new IssueTemplateNotFoundError({ identifier: params2.template, project: params2.project });
200257
+ }
200258
+ return { client, project, template };
200259
+ });
200260
+ resolveTemplateReferenceLabels = (client, assignee, component) => Effect_exports.gen(function* () {
200261
+ const assigneeName = assignee === null ? void 0 : (yield* client.findOne(contact.class.Person, hulyQuery({ _id: assignee })))?.name;
200262
+ const componentLabel = component === null ? void 0 : (yield* client.findOne(tracker.class.Component, hulyQuery({ _id: component })))?.label;
200263
+ return {
200264
+ ...assigneeName === void 0 ? {} : { assigneeName },
200265
+ ...componentLabel === void 0 ? {} : { componentLabel }
200266
+ };
200267
+ });
200268
+ templateChildProjection = (child, description, labels) => {
200269
+ const rawEstimation = zeroAsUnset(NonNegativeNumber.make(child.estimation));
200270
+ const estimation = rawEstimation === void 0 ? void 0 : PositiveTimeHours.make(rawEstimation);
200271
+ return {
200272
+ id: IssueTemplateChildId.make(child.id),
200273
+ title: child.title,
200274
+ priority: priorityToString(child.priority),
200275
+ ...description === void 0 ? {} : { description },
200276
+ ...labels.assigneeName === void 0 ? {} : { assignee: PersonName.make(labels.assigneeName) },
200277
+ ...labels.componentLabel === void 0 ? {} : { component: ComponentLabel.make(labels.componentLabel) },
200278
+ ...estimation === void 0 ? {} : { estimation }
200279
+ };
200280
+ };
200281
+ resolveChild = (client, markupUrlConfig, child) => Effect_exports.gen(function* () {
200282
+ const labels = yield* resolveTemplateReferenceLabels(client, child.assignee, child.component);
200283
+ const description = child.description ? yield* optionalMarkupToMarkdown(child.description, markupUrlConfig, "", {
200284
+ operation: "getIssueTemplate",
200285
+ entity: "issue template child description"
200286
+ }) : void 0;
200287
+ return templateChildProjection(child, description, labels);
200288
+ });
200289
+ buildTemplateChild = (client, markupUrlConfig, projectId, projectIdentifier, input) => Effect_exports.gen(function* () {
200290
+ const assigneeParam = input.assignee;
200291
+ const assigneeRef = assigneeParam !== void 0 ? yield* Effect_exports.gen(function* () {
200292
+ const person = yield* findPersonByEmailOrName(client, assigneeParam);
200293
+ if (person === void 0) {
200294
+ return yield* new PersonNotFoundError({ identifier: assigneeParam });
200295
+ }
200296
+ return person._id;
200297
+ }) : null;
200298
+ const componentParam = input.component;
200299
+ const componentRef = componentParam !== void 0 ? yield* Effect_exports.gen(function* () {
200300
+ const component = yield* findComponentByIdOrLabel(client, projectId, componentParam);
200301
+ if (component === void 0) {
200302
+ return yield* new ComponentNotFoundError({ identifier: componentParam, project: projectIdentifier });
200303
+ }
200304
+ return component._id;
200305
+ }) : null;
200306
+ return {
200307
+ id: (0, import_core88.generateId)(),
200308
+ title: input.title,
200309
+ description: optionalMarkdownToMarkup(input.description, markupUrlConfig, ""),
200310
+ priority: stringToPriority(input.priority ?? DEFAULT_ISSUE_PRIORITY),
200311
+ assignee: assigneeRef,
200312
+ component: componentRef,
200313
+ estimation: input.estimation ?? 0
200314
+ };
200315
+ });
200316
+ listIssueTemplates = (params2) => Effect_exports.gen(function* () {
200317
+ const { client, project } = yield* findProject(params2.project);
200318
+ const limit = clampLimit(params2.limit);
200319
+ const templates2 = yield* client.findAll(
200320
+ tracker.class.IssueTemplate,
200321
+ { space: project._id },
200322
+ { limit, sort: { modifiedOn: import_core88.SortingOrder.Descending } }
200323
+ );
200324
+ const summaries = templates2.map((t) => {
200325
+ const base2 = {
200326
+ id: IssueTemplateId.make(t._id),
200327
+ title: t.title,
200328
+ priority: priorityToString(t.priority),
200329
+ modifiedOn: Timestamp.make(t.modifiedOn)
200330
+ };
200331
+ if (t.children.length > 0) {
200332
+ return { ...base2, childrenCount: Count.make(t.children.length) };
200333
+ }
200334
+ return base2;
200335
+ });
200336
+ return summaries;
200337
+ });
200338
+ getIssueTemplate = (params2) => Effect_exports.gen(function* () {
200339
+ const { client, template } = yield* findProjectAndTemplate(params2);
200340
+ const markupUrlConfig = client.markupUrlConfig;
200341
+ const labels = yield* resolveTemplateReferenceLabels(client, template.assignee, template.component);
200342
+ const description = yield* optionalMarkupToMarkdown(template.description, markupUrlConfig, "", {
200343
+ operation: "getIssueTemplate",
200344
+ entity: "issue template description"
200345
+ });
200346
+ const resolvedChildren = [];
200347
+ for (const child of template.children) {
200348
+ resolvedChildren.push(yield* resolveChild(client, markupUrlConfig, child));
200349
+ }
200350
+ const result3 = {
200351
+ id: IssueTemplateId.make(template._id),
200352
+ title: template.title,
200353
+ description,
200354
+ priority: priorityToString(template.priority),
200355
+ assignee: labels.assigneeName !== void 0 ? PersonName.make(labels.assigneeName) : void 0,
200356
+ component: labels.componentLabel !== void 0 ? ComponentLabel.make(labels.componentLabel) : void 0,
200357
+ estimation: template.estimation > 0 ? PositiveTimeHours.make(template.estimation) : void 0,
200358
+ project: params2.project,
200359
+ modifiedOn: Timestamp.make(template.modifiedOn),
200360
+ createdOn: template.createdOn === void 0 ? void 0 : Timestamp.make(template.createdOn)
200361
+ };
200362
+ if (resolvedChildren.length > 0) {
200363
+ return { ...result3, children: resolvedChildren };
200364
+ }
200365
+ return result3;
200366
+ });
200367
+ createIssueTemplate = (params2) => Effect_exports.gen(function* () {
200368
+ const { client, project } = yield* findProject(params2.project);
200369
+ const markupUrlConfig = client.markupUrlConfig;
200370
+ const templateId = (0, import_core88.generateId)();
200371
+ const assigneeParam = params2.assignee;
200372
+ const assigneeRef = assigneeParam !== void 0 ? yield* Effect_exports.gen(function* () {
200373
+ const person = yield* findPersonByEmailOrName(client, assigneeParam);
200374
+ if (person === void 0) {
200375
+ return yield* new PersonNotFoundError({ identifier: assigneeParam });
200376
+ }
200377
+ return person._id;
200378
+ }) : null;
200379
+ const componentParam = params2.component;
200380
+ const componentRef = componentParam !== void 0 ? yield* Effect_exports.gen(function* () {
200381
+ const component = yield* findComponentByIdOrLabel(client, project._id, componentParam);
200382
+ if (component === void 0) {
200383
+ return yield* new ComponentNotFoundError({ identifier: componentParam, project: params2.project });
200384
+ }
200385
+ return component._id;
200386
+ }) : null;
200387
+ const priority = stringToPriority(params2.priority ?? DEFAULT_ISSUE_PRIORITY);
200388
+ const children = [];
200389
+ if (params2.children !== void 0) {
200390
+ for (const childInput of params2.children) {
200391
+ children.push(yield* buildTemplateChild(client, markupUrlConfig, project._id, params2.project, childInput));
200392
+ }
200393
+ }
200394
+ const templateData = {
200395
+ title: params2.title,
200396
+ description: optionalMarkdownToMarkup(params2.description, markupUrlConfig, ""),
200397
+ priority,
200398
+ assignee: assigneeRef,
200399
+ component: componentRef,
200400
+ estimation: params2.estimation ?? 0,
200401
+ children,
200402
+ comments: 0
200403
+ };
200404
+ yield* client.createDoc(tracker.class.IssueTemplate, project._id, templateData, templateId);
200405
+ return { id: IssueTemplateId.make(templateId), title: params2.title };
200406
+ });
200407
+ resolveIssueFromTemplateAssignee = (client, params2, template) => Effect_exports.gen(function* () {
200408
+ if (params2.assignee === void 0) {
200409
+ if (template.assignee === null) return null;
200410
+ const templatePerson = yield* client.findOne(
200411
+ contact.class.Person,
200412
+ hulyQuery({ _id: template.assignee })
200413
+ );
200414
+ return templatePerson?._id ?? null;
200415
+ }
200416
+ const person = yield* findPersonByEmailOrName(client, params2.assignee);
200417
+ if (person === void 0) return yield* new PersonNotFoundError({ identifier: params2.assignee });
200418
+ return person._id;
200419
+ });
200420
+ templateChildCreateParams = (params2, child, markupUrlConfig) => optionalMarkupToMarkdown(child.description, markupUrlConfig, void 0, {
200421
+ operation: "createIssueFromTemplate",
200422
+ entity: "issue template child description"
200423
+ }).pipe(
200424
+ Effect_exports.map(
200425
+ (description) => ({
200426
+ project: params2.project,
200427
+ title: child.title,
200428
+ priority: priorityToString(child.priority),
200429
+ resolvedAssignee: null,
200430
+ ...description === void 0 ? {} : { description }
200431
+ })
200432
+ )
200433
+ );
200434
+ templateChildUpdate = (child) => ({
200435
+ ...child.assignee === null ? {} : { assignee: child.assignee },
200436
+ ...child.component === null ? {} : { component: child.component },
200437
+ ...child.estimation > 0 ? { estimation: child.estimation } : {}
200438
+ });
200439
+ createTemplateChildIssues = (client, project, template, params2, parentResult, title, markupUrlConfig) => Effect_exports.gen(function* () {
200440
+ const parentIssue = {
200441
+ _id: toRef(parentResult.issueId),
200442
+ identifier: parentResult.identifier,
200443
+ title,
200444
+ parents: []
200445
+ };
200446
+ for (const child of template.children) {
200447
+ const childParams = yield* templateChildCreateParams(params2, child, markupUrlConfig);
200448
+ const childResult = yield* createIssueWithResolvedAssignee(childParams);
200449
+ yield* attachIssueChild(
200450
+ client,
200451
+ project._id,
200452
+ toRef(childResult.issueId),
200453
+ parentIssue,
200454
+ templateChildUpdate(child)
200455
+ );
200456
+ }
200457
+ });
200458
+ createIssueFromTemplate = (params2) => Effect_exports.gen(function* () {
200459
+ const { client, project, template } = yield* findProjectAndTemplate(params2);
200460
+ const markupUrlConfig = client.markupUrlConfig;
200461
+ const title = params2.title ?? template.title;
200462
+ const description = params2.description ?? (yield* optionalMarkupToMarkdown(template.description, markupUrlConfig, void 0, {
200463
+ operation: "createIssueFromTemplate",
200464
+ entity: "issue template description"
200465
+ }));
200466
+ const priority = params2.priority ?? priorityToString(template.priority);
200467
+ const assignee = yield* resolveIssueFromTemplateAssignee(client, params2, template);
200468
+ const issueParams = {
200469
+ project: params2.project,
200470
+ title,
200471
+ description,
200472
+ priority,
200473
+ resolvedAssignee: assignee,
200474
+ status: params2.status
200475
+ };
200476
+ const result3 = yield* createIssueWithResolvedAssignee(issueParams);
200477
+ if (template.component !== null) {
200478
+ yield* client.updateDoc(tracker.class.Issue, project._id, toRef(result3.issueId), {
200479
+ component: template.component
200480
+ });
200481
+ }
200482
+ const includeChildren = params2.includeChildren ?? DEFAULT_INCLUDE_TEMPLATE_CHILDREN;
200483
+ if (includeChildren && template.children.length > 0) {
200484
+ yield* createTemplateChildIssues(client, project, template, params2, result3, title, markupUrlConfig);
200485
+ return { ...result3, childrenCreated: Count.make(template.children.length) };
200486
+ }
200487
+ return result3;
200488
+ });
200489
+ updateIssueTemplate = (params2) => Effect_exports.gen(function* () {
200490
+ yield* requireUpdateFields("update_issue_template", params2, UPDATE_ISSUE_TEMPLATE_FIELDS);
200491
+ const { client, project, template } = yield* findProjectAndTemplate(params2);
200492
+ const markupUrlConfig = client.markupUrlConfig;
200493
+ const updateEntries = {
200494
+ title: Effect_exports.succeed(params2.title === void 0 ? {} : { title: params2.title }),
200495
+ description: Effect_exports.succeed(
200496
+ params2.description === void 0 ? {} : { description: optionalMarkdownToMarkup(clearTextAsEmptyString(params2.description), markupUrlConfig, "") }
200497
+ ),
200498
+ priority: Effect_exports.succeed(params2.priority === void 0 ? {} : { priority: stringToPriority(params2.priority) }),
200499
+ assignee: Effect_exports.gen(function* () {
200500
+ if (params2.assignee === void 0) return {};
200501
+ if (params2.assignee === null) return { assignee: null };
200502
+ const person = yield* findPersonByEmailOrName(client, params2.assignee);
200503
+ if (person === void 0) {
200504
+ return yield* new PersonNotFoundError({ identifier: params2.assignee });
200505
+ }
200506
+ return { assignee: person._id };
200507
+ }),
200508
+ component: Effect_exports.gen(function* () {
200509
+ if (params2.component === void 0) return {};
200510
+ if (params2.component === null) return { component: null };
200511
+ const component = yield* findComponentByIdOrLabel(client, project._id, params2.component);
200512
+ if (component === void 0) {
200513
+ return yield* new ComponentNotFoundError({ identifier: params2.component, project: params2.project });
200514
+ }
200515
+ return { component: component._id };
200516
+ }),
200517
+ estimation: Effect_exports.succeed(
200518
+ params2.estimation === void 0 ? {} : { estimation: params2.estimation === null ? 0 : params2.estimation }
200519
+ )
200520
+ };
200521
+ const updateOps = mergeUpdateEntries(
200522
+ yield* Effect_exports.all(Object.values(updateEntries))
200523
+ );
200524
+ yield* client.updateDoc(tracker.class.IssueTemplate, project._id, template._id, updateOps);
200525
+ return { id: IssueTemplateId.make(template._id), updated: true };
200526
+ });
200527
+ deleteIssueTemplate = (params2) => Effect_exports.gen(function* () {
200528
+ const { client, project, template } = yield* findProjectAndTemplate(params2);
200529
+ yield* client.removeDoc(tracker.class.IssueTemplate, project._id, template._id);
200530
+ return { id: IssueTemplateId.make(template._id), deleted: true };
200531
+ });
200532
+ addTemplateChild = (params2) => Effect_exports.gen(function* () {
200533
+ const { client, project, template } = yield* findProjectAndTemplate(params2);
200534
+ const markupUrlConfig = client.markupUrlConfig;
200535
+ const child = yield* buildTemplateChild(client, markupUrlConfig, project._id, params2.project, {
200536
+ title: params2.title,
200537
+ description: params2.description,
200538
+ priority: params2.priority,
200539
+ assignee: params2.assignee,
200540
+ component: params2.component,
200541
+ estimation: params2.estimation
200542
+ });
200543
+ const newChildren = [...template.children, child];
200544
+ yield* client.updateDoc(tracker.class.IssueTemplate, project._id, template._id, { children: newChildren });
200545
+ return { id: IssueTemplateChildId.make(child.id), title: child.title, added: true };
200546
+ });
200547
+ removeTemplateChild = (params2) => Effect_exports.gen(function* () {
200548
+ const { client, project, template } = yield* findProjectAndTemplate(params2);
200549
+ const childIndex = template.children.findIndex((c) => String(c.id) === String(params2.childId));
200550
+ if (childIndex === NOT_FOUND_INDEX2) {
200551
+ return yield* new TemplateChildNotFoundError({
200552
+ childId: params2.childId,
200553
+ template: params2.template,
200554
+ project: params2.project
200555
+ });
200556
+ }
200557
+ const removedChild = assertAt(template.children, childIndex);
200558
+ const newChildren = template.children.filter((_, i) => i !== childIndex);
200559
+ yield* client.updateDoc(tracker.class.IssueTemplate, project._id, template._id, { children: newChildren });
200560
+ return { id: IssueTemplateChildId.make(removedChild.id), title: removedChild.title, removed: true };
200561
+ });
200562
+ }
200563
+ });
200564
+
200565
+ // src/huly/operations/issues-move.ts
200566
+ var import_core89, import_tracker4, issueTargetClass, addLabel, moveIssue, updateDescendantParents;
200567
+ var init_issues_move = __esm({
200568
+ "src/huly/operations/issues-move.ts"() {
200569
+ "use strict";
200570
+ import_core89 = __toESM(require_lib6(), 1);
200571
+ import_tracker4 = __toESM(require_lib25(), 1);
200572
+ init_dist();
200573
+ init_shared();
200574
+ init_tags();
200575
+ init_huly_plugins();
200576
+ init_issues_parent();
200577
+ init_issues_shared();
200578
+ init_query_helpers();
200579
+ init_sdk_boundary();
200580
+ init_tags_shared();
200581
+ issueTargetClass = TagTargetClass.make(String(tracker.class.Issue));
200582
+ addLabel = (params2) => Effect_exports.gen(function* () {
200583
+ const { issue: issue2, project } = yield* findProjectAndIssue(params2);
200584
+ const labelTitle = TagIdentifier.make(params2.label.trim());
200585
+ const tag2 = yield* ensureTagElement({
200586
+ targetClass: issueTargetClass,
200587
+ titleOrId: labelTitle,
200588
+ color: params2.color,
200589
+ fallbackCategory: tracker.category.Other
200590
+ });
200591
+ const result3 = yield* attachTagReference({
200592
+ tag: tag2,
200593
+ objectId: issue2._id,
200594
+ objectClass: tracker.class.Issue,
200595
+ space: project._id,
200596
+ collection: "labels",
200597
+ matchTitleCaseInsensitive: true
200598
+ });
200599
+ return { identifier: IssueIdentifier.make(issue2.identifier), labelAdded: result3.attached };
200600
+ });
200601
+ moveIssue = (params2) => Effect_exports.gen(function* () {
200602
+ const { client, issue: issue2, project } = yield* findProjectAndIssue(params2);
200603
+ const oldParentIsIssue = hasConcreteIssueParent(issue2);
200604
+ const newParentParam = params2.newParent;
200605
+ const target = newParentParam !== null ? yield* Effect_exports.gen(function* () {
200606
+ const parentIssue = yield* findIssueInProject(client, project, newParentParam);
200607
+ return {
200608
+ _tag: "Child",
200609
+ identifier: IssueIdentifier.make(parentIssue.identifier),
200610
+ issue: parentIssue,
200611
+ parent: childIssueParent(parentIssue, project._id)
200612
+ };
200613
+ }) : { _tag: "TopLevel", parent: topLevelIssueParent() };
200614
+ if (target._tag === "Child") {
200615
+ yield* attachIssueChild(client, project._id, issue2._id, target.issue, {});
200616
+ } else {
200617
+ yield* client.updateDoc(tracker.class.Issue, project._id, issue2._id, {
200618
+ attachedTo: toRef(target.parent.attachedTo),
200619
+ attachedToClass: target.parent.attachedToClass,
200620
+ collection: target.parent.collection,
200621
+ parents: target.parent.parents
200622
+ });
200623
+ }
200624
+ if (oldParentIsIssue) {
200625
+ yield* client.updateDoc(
200626
+ tracker.class.Issue,
200627
+ project._id,
200628
+ // issue.attachedTo is Ref<Doc>; for sub-issues it points to the parent issue.
200629
+ // Cast needed because updateDoc expects Ref<HulyIssue> but attachedTo is Ref<Doc>.
200630
+ toRef(issue2.attachedTo),
200631
+ { $inc: { subIssues: -1 } }
200632
+ );
200633
+ }
200634
+ if (issue2.subIssues > 0) {
200635
+ yield* updateDescendantParents(client, project._id, issue2, target.parent.parents);
200636
+ }
200637
+ const result3 = { identifier: IssueIdentifier.make(issue2.identifier), moved: true };
200638
+ if (target._tag === "Child") {
200639
+ return { ...result3, newParent: target.identifier };
200640
+ }
200641
+ return result3;
200642
+ });
200643
+ updateDescendantParents = (client, spaceId, parentIssue, parentNewParents) => Effect_exports.gen(function* () {
200644
+ const thisParentInfo = {
200645
+ parentId: parentIssue._id,
200646
+ identifier: parentIssue.identifier,
200647
+ parentTitle: parentIssue.title,
200648
+ space: spaceId
200649
+ };
200650
+ const children = yield* client.findAll(
200651
+ tracker.class.Issue,
200652
+ hulyQuery({ attachedTo: parentIssue._id, space: spaceId })
200653
+ );
200654
+ for (const child of children) {
200655
+ const childNewParents = [...parentNewParents, thisParentInfo];
200656
+ yield* client.updateDoc(tracker.class.Issue, spaceId, child._id, { parents: childNewParents });
200657
+ if (child.subIssues > 0) {
200658
+ yield* updateDescendantParents(client, spaceId, child, childNewParents);
200659
+ }
200660
+ }
200661
+ });
200662
+ }
200663
+ });
200664
+
200665
+ // src/huly/operations/issue-creators-read.ts
200666
+ var parsePersonRef, uniqueCreatorIds, creatorRef, creatorForIssue, loadIssueCreatorIndex;
200667
+ var init_issue_creators_read = __esm({
200668
+ "src/huly/operations/issue-creators-read.ts"() {
200669
+ "use strict";
200670
+ init_dist();
200671
+ init_issues();
200672
+ init_tool_warnings();
200673
+ init_diagnostics();
200674
+ init_huly_plugins();
200675
+ init_contacts_shared();
200676
+ init_query_helpers();
200677
+ init_sdk_boundary();
200678
+ parsePersonRef = Schema_exports.decodeUnknownOption(PersonRefSchema);
200679
+ uniqueCreatorIds = (issues) => [
200680
+ ...new Set(issues.flatMap((issue2) => issue2.createdBy === void 0 ? [] : [issue2.createdBy]))
200681
+ ];
200682
+ creatorRef = (person, emailByPerson) => parsePersonRef({
200683
+ id: person._id,
200684
+ ...person.name.trim() === "" ? {} : { name: person.name },
200685
+ ...emailByPerson.has(person._id) ? { email: emailByPerson.get(person._id) } : {}
200686
+ });
200687
+ creatorForIssue = (index2, issue2) => issue2.createdBy === void 0 ? void 0 : index2.get(issue2.createdBy);
200688
+ loadIssueCreatorIndex = (client, issues) => Effect_exports.gen(function* () {
200689
+ const creatorIds = uniqueCreatorIds(issues);
200690
+ if (creatorIds.length === 0) return /* @__PURE__ */ new Map();
200691
+ const identities = yield* client.findAll(
200692
+ contact.class.SocialIdentity,
200693
+ hulyQuery({ _id: { $in: creatorIds.map(toSocialIdentityRef) } })
200694
+ );
200695
+ const personIds = [...new Set(identities.map((identity2) => identity2.attachedTo))];
200696
+ const persons = personIds.length === 0 ? [] : yield* client.findAll(
200697
+ contact.class.Person,
200698
+ hulyQuery({ _id: { $in: personIds.map(toRef) } })
200699
+ );
200700
+ const emailByPerson = yield* batchGetEmailsForPersons(
200701
+ client,
200702
+ persons.map((person) => person._id)
200703
+ );
200704
+ const personById = new Map(persons.map((person) => [person._id, person]));
200705
+ const index2 = /* @__PURE__ */ new Map();
200706
+ for (const identity2 of identities) {
200707
+ const person = personById.get(identity2.attachedTo);
200708
+ if (person === void 0) continue;
200709
+ const parsed = creatorRef(person, emailByPerson);
200710
+ if (Option_exports.isSome(parsed)) index2.set(identity2._id, parsed.value);
200711
+ }
200712
+ const unresolvedCount = creatorIds.filter((creatorId) => !index2.has(creatorId)).length;
200713
+ if (unresolvedCount > 0) {
200714
+ const diagnostics = yield* Diagnostics;
200715
+ yield* diagnostics.warnAgent({
200716
+ code: IssueCreatorMetadataDegradedWarningCode,
200717
+ message: `${unresolvedCount} unresolved issue creator reference(s) were omitted from issue results.`
200718
+ });
200719
+ }
200720
+ return index2;
200721
+ });
200722
+ }
200723
+ });
200724
+
200725
+ // src/huly/operations/issue-labels-read.ts
200726
+ var IssueLabelAttachmentBoundarySchema, NormalizedLabelTitle, decodeAttachment, decodeTitle, decodeColor, toDocRef2, toIssueRef, normalizeLabelTitle, COLOR_SORT_WIDTH, compareStrings, candidateSortKey, compareCandidates, toCandidate3, projectionCandidate, projectionDegradationReason, projectCandidateGroup, buildIssueLabelIndex, countReason, degradationMessage, labelsForIssue, issueIdsMatchingLabel, loadIssueLabelIndex;
200727
+ var init_issue_labels_read = __esm({
200728
+ "src/huly/operations/issue-labels-read.ts"() {
200729
+ "use strict";
200730
+ init_dist();
200731
+ init_shared();
200732
+ init_tool_warnings();
200733
+ init_diagnostics();
200734
+ init_huly_plugins();
200735
+ init_query_helpers();
200736
+ init_sdk_boundary();
200737
+ IssueLabelAttachmentBoundarySchema = Schema_exports.Struct({
200738
+ _id: TagReferenceId,
200739
+ attachedTo: IssueId,
200740
+ title: Schema_exports.optional(Schema_exports.Unknown),
200741
+ color: Schema_exports.optional(Schema_exports.Unknown)
200742
+ }).annotate({
200743
+ title: "IssueLabelAttachmentBoundary",
200744
+ description: "Partial Huly TagReference fields used to project issue labels. Missing or malformed presentation fields are handled by stable projection rules."
200745
+ });
200746
+ NormalizedLabelTitle = NonEmptyString2.pipe(Schema_exports.brand("NormalizedLabelTitle"));
200747
+ decodeAttachment = Schema_exports.decodeUnknownResult(IssueLabelAttachmentBoundarySchema);
200748
+ decodeTitle = Schema_exports.decodeUnknownResult(NonEmptyString2);
200749
+ decodeColor = Schema_exports.decodeUnknownResult(ColorCode);
200750
+ toDocRef2 = (id2) => toRef(IssueId.make(id2));
200751
+ toIssueRef = toRef;
200752
+ normalizeLabelTitle = (title) => NormalizedLabelTitle.make(title.toLowerCase());
200753
+ COLOR_SORT_WIDTH = 2;
200754
+ compareStrings = (left, right) => Number(left > right) - Number(left < right);
200755
+ candidateSortKey = (candidate) => [
200756
+ candidate.normalizedTitle,
200757
+ candidate.color === void 0 ? "1" : "0",
200758
+ candidate.title,
200759
+ String(candidate.color).padStart(COLOR_SORT_WIDTH, "0"),
200760
+ candidate.referenceId
200761
+ ].join("\0");
200762
+ compareCandidates = (left, right) => compareStrings(candidateSortKey(left), candidateSortKey(right));
200763
+ toCandidate3 = (input) => {
200764
+ const attachment2 = decodeAttachment(input);
200765
+ if (Result_exports.isFailure(attachment2)) {
200766
+ return { _tag: "Rejected", degradationReason: "malformed_attachment" };
200767
+ }
200768
+ const title = decodeTitle(attachment2.success.title);
200769
+ if (Result_exports.isFailure(title)) {
200770
+ return { _tag: "Rejected", degradationReason: "missing_or_malformed_title" };
200771
+ }
200772
+ const colorInput = attachment2.success.color;
200773
+ const color = colorInput === void 0 ? void 0 : decodeColor(colorInput);
200774
+ const candidate = {
200775
+ referenceId: attachment2.success._id,
200776
+ issueId: attachment2.success.attachedTo,
200777
+ title: title.success,
200778
+ normalizedTitle: normalizeLabelTitle(title.success),
200779
+ ...color !== void 0 && Result_exports.isSuccess(color) ? { color: color.success } : {}
200780
+ };
200781
+ return color !== void 0 && Result_exports.isFailure(color) ? { _tag: "DegradedSuccess", candidate, degradationReason: "invalid_color" } : { _tag: "Success", candidate };
200782
+ };
200783
+ projectionCandidate = (projection) => projection._tag === "Rejected" ? [] : [projection.candidate];
200784
+ projectionDegradationReason = (projection) => {
200785
+ switch (projection._tag) {
200786
+ case "Success":
200787
+ return [];
200788
+ case "DegradedSuccess":
200789
+ case "Rejected":
200790
+ return [projection.degradationReason];
200791
+ }
200792
+ };
200793
+ projectCandidateGroup = (candidates) => {
200794
+ const sorted = [...candidates].sort(compareCandidates);
200795
+ return sorted.filter(
200796
+ (candidate, index2) => sorted.findIndex((other) => other.normalizedTitle === candidate.normalizedTitle) === index2
200797
+ ).map((candidate) => ({
200798
+ title: candidate.title,
200799
+ ...candidate.color === void 0 ? {} : { color: candidate.color }
200800
+ }));
200801
+ };
200802
+ buildIssueLabelIndex = (attachments) => {
200803
+ const projections = attachments.map(toCandidate3);
200804
+ const candidates = projections.flatMap(projectionCandidate);
200805
+ const issueIds = [...new Set(candidates.map((candidate) => candidate.issueId))];
200806
+ return {
200807
+ byIssueId: new Map(
200808
+ issueIds.map((issueId) => [
200809
+ issueId,
200810
+ projectCandidateGroup(candidates.filter((candidate) => candidate.issueId === issueId))
200811
+ ])
200812
+ ),
200813
+ degradationReasons: projections.flatMap(projectionDegradationReason)
200814
+ };
200815
+ };
200816
+ countReason = (reasons, reason) => reasons.filter((candidate) => candidate === reason).length;
200817
+ degradationMessage = (reasons) => {
200818
+ const malformedAttachments = countReason(reasons, "malformed_attachment");
200819
+ const malformedTitles = countReason(reasons, "missing_or_malformed_title");
200820
+ const invalidColors = countReason(reasons, "invalid_color");
200821
+ return `Issue label summaries omitted or partially projected malformed Huly metadata: ${malformedAttachments} malformed attachment(s), ${malformedTitles} missing or malformed title(s), and ${invalidColors} invalid color(s). Duplicate case-insensitive titles prefer a reference with a valid color.`;
200822
+ };
200823
+ labelsForIssue = (index2, issueId) => index2.byIssueId.get(IssueId.make(issueId)) ?? [];
200824
+ issueIdsMatchingLabel = (index2, label) => {
200825
+ const normalizedFilter = normalizeLabelTitle(label);
200826
+ return [...index2.byIssueId].filter(([, labels]) => labels.some((summary) => normalizeLabelTitle(summary.title) === normalizedFilter)).map(([issueId]) => toIssueRef(issueId)).sort(compareStrings);
200827
+ };
200828
+ loadIssueLabelIndex = (client, space, issueIds) => Effect_exports.gen(function* () {
200829
+ if (issueIds !== void 0 && issueIds.length === 0) return buildIssueLabelIndex([]);
200830
+ const diagnostics = yield* Diagnostics;
200831
+ const baseQuery = {
200832
+ space,
200833
+ attachedToClass: tracker.class.Issue,
200834
+ collection: "labels"
200835
+ };
200836
+ const query = issueIds === void 0 ? baseQuery : { ...baseQuery, attachedTo: { $in: issueIds.map(toDocRef2) } };
200837
+ const attachments = yield* client.findAll(tags.class.TagReference, hulyQuery(query));
200838
+ const index2 = buildIssueLabelIndex(attachments);
200839
+ if (index2.degradationReasons.length > 0) {
200840
+ yield* diagnostics.warnAgent({
200841
+ code: IssueLabelMetadataDegradedWarningCode,
200842
+ message: degradationMessage(index2.degradationReasons)
200843
+ });
200844
+ }
200845
+ return index2;
200846
+ });
200847
+ }
200848
+ });
200849
+
200850
+ // src/huly/operations/issue-milestones-read.ts
200851
+ var parseMilestoneRef, uniqueMilestoneRefs, milestoneForIssue, loadIssueMilestoneIndex;
200852
+ var init_issue_milestones_read = __esm({
200853
+ "src/huly/operations/issue-milestones-read.ts"() {
200854
+ "use strict";
200855
+ init_dist();
200856
+ init_issues();
200857
+ init_shared();
200858
+ init_tool_warnings();
200859
+ init_diagnostics();
200860
+ init_huly_plugins();
200861
+ init_query_helpers();
200862
+ parseMilestoneRef = Schema_exports.decodeUnknownOption(IssueMilestoneRefSchema);
200863
+ uniqueMilestoneRefs = (issues) => [
200864
+ ...new Set(
200865
+ issues.flatMap((issue2) => issue2.milestone === null || issue2.milestone === void 0 ? [] : [issue2.milestone])
200866
+ )
200867
+ ];
200868
+ milestoneForIssue = (index2, issue2) => issue2.milestone === null || issue2.milestone === void 0 ? void 0 : index2.get(MilestoneId.make(issue2.milestone));
200869
+ loadIssueMilestoneIndex = (client, project, issues) => Effect_exports.gen(function* () {
200870
+ const refs = uniqueMilestoneRefs(issues);
200871
+ if (refs.length === 0) return /* @__PURE__ */ new Map();
200872
+ const milestones = yield* client.findAll(
200873
+ tracker.class.Milestone,
200874
+ hulyQuery({ space: project._id, _id: { $in: refs } })
200875
+ );
200876
+ const index2 = /* @__PURE__ */ new Map();
200877
+ for (const milestone of milestones) {
200878
+ const parsed = parseMilestoneRef({ id: milestone._id, label: milestone.label });
200879
+ if (Option_exports.isSome(parsed)) index2.set(parsed.value.id, parsed.value);
200880
+ }
200881
+ const unresolvedCount = refs.filter((ref) => !index2.has(MilestoneId.make(ref))).length;
200882
+ if (unresolvedCount > 0) {
200883
+ const diagnostics = yield* Diagnostics;
200884
+ yield* diagnostics.warnAgent({
200885
+ code: IssueMilestoneMetadataDegradedWarningCode,
200886
+ message: `${unresolvedCount} unresolved milestone reference(s) were omitted from issue results.`
200887
+ });
200888
+ }
200889
+ return index2;
200890
+ });
200232
200891
  }
200233
200892
  });
200234
200893
 
@@ -200295,12 +200954,12 @@ var init_milestone_resolution = __esm({
200295
200954
  });
200296
200955
 
200297
200956
  // src/huly/operations/issues-read.ts
200298
- var import_core88, import_tracker4, resolveStatusName, hasUnknownStatusCategory, requireKnownStatusCategories, statusIdsByCategory, applyStatusAndAssigneeFilters, applyCreatorFilter, applyIssueTextFilters, applyIssuePresenceFilters, applyIssueScopeFilters, applyIssueMilestoneFilter, applyIssueQueryFilters, issueSummaryProjection, findIssueForRead, loadIssueAssignee, loadIssueDescription, issueDetailRelationshipFields, issueDetailMetricFields, issueDetailProjection, listIssues, getIssue;
200957
+ var import_core90, import_tracker5, resolveStatusName, hasUnknownStatusCategory, requireKnownStatusCategories, statusIdsByCategory, applyStatusAndAssigneeFilters, applyCreatorFilter, applyIssueTextFilters, applyIssuePresenceFilters, applyIssueScopeFilters, applyIssueMilestoneFilter, applyIssueQueryFilters, issueSummaryProjection, findIssueForRead, loadIssueAssignee, loadIssueDescription, issueDetailRelationshipFields, issueDetailMetricFields, issueDetailProjection, listIssues, getIssue;
200299
200958
  var init_issues_read = __esm({
200300
200959
  "src/huly/operations/issues-read.ts"() {
200301
200960
  "use strict";
200302
- import_core88 = __toESM(require_lib6(), 1);
200303
- import_tracker4 = __toESM(require_lib25(), 1);
200961
+ import_core90 = __toESM(require_lib6(), 1);
200962
+ import_tracker5 = __toESM(require_lib25(), 1);
200304
200963
  init_dist();
200305
200964
  init_issues();
200306
200965
  init_shared();
@@ -200308,6 +200967,7 @@ var init_issues_read = __esm({
200308
200967
  init_huly_plugins();
200309
200968
  init_components2();
200310
200969
  init_contacts_shared();
200970
+ init_issue_assignee_resolution();
200311
200971
  init_issue_creators_read();
200312
200972
  init_issue_labels_read();
200313
200973
  init_issue_milestones_read();
@@ -200338,9 +200998,9 @@ var init_issues_read = __esm({
200338
200998
  query.status = yield* resolveStatusByName([...statuses], params2.status, params2.project);
200339
200999
  }
200340
201000
  if (params2.assignee !== void 0) {
200341
- const assigneePerson = yield* findPersonByEmailOrName(client, params2.assignee);
200342
- if (assigneePerson === void 0) return false;
200343
- query.assignee = assigneePerson._id;
201001
+ const assigneePerson = yield* findIssueAssignee(client, params2.assignee);
201002
+ if (Option_exports.isNone(assigneePerson)) return false;
201003
+ query.assignee = assigneePerson.value._id;
200344
201004
  }
200345
201005
  return true;
200346
201006
  });
@@ -200480,164 +201140,55 @@ var init_issues_read = __esm({
200480
201140
  tracker.class.Issue,
200481
201141
  hulyQuery(effectiveQuery),
200482
201142
  withLookup(
200483
- { limit, sort: { modifiedOn: import_core88.SortingOrder.Descending } },
201143
+ { limit, sort: { modifiedOn: import_core90.SortingOrder.Descending } },
200484
201144
  { assignee: contact.class.Person }
200485
201145
  )
200486
201146
  );
200487
201147
  const labelIndex = labelFilterContext === void 0 ? yield* loadIssueLabelIndex(
200488
201148
  client,
200489
- project._id,
200490
- issues.map((issue2) => issue2._id)
200491
- ) : labelFilterContext.index;
200492
- const milestoneIndex = yield* loadIssueMilestoneIndex(client, project, issues);
200493
- const creatorIndex = yield* loadIssueCreatorIndex(client, issues);
200494
- const rawSummaries = issues.map(
200495
- (issue2) => issueSummaryProjection(issue2, statuses, labelIndex, milestoneIndex, creatorIndex)
200496
- );
200497
- const parseIssueSummaries = Schema_exports.decodeUnknownEffect(Schema_exports.Array(IssueSummarySchema));
200498
- const validated = yield* parseIssueSummaries(rawSummaries).pipe(
200499
- Effect_exports.mapError(
200500
- (parseError) => new HulyDataInvalidError({ operation: "listIssues", entity: "issue", cause: parseError })
200501
- )
200502
- );
200503
- return [...validated];
200504
- });
200505
- getIssue = (params2) => Effect_exports.gen(function* () {
200506
- const { client, project, statuses } = yield* findProjectWithStatuses(params2.project);
200507
- const issue2 = yield* findIssueForRead(client, project, params2);
200508
- const statusName = resolveStatusName(statuses, issue2.status);
200509
- const person = yield* loadIssueAssignee(client, issue2);
200510
- const description = yield* loadIssueDescription(client, issue2);
200511
- const labelIndex = yield* loadIssueLabelIndex(client, project._id, [issue2._id]);
200512
- const milestoneIndex = yield* loadIssueMilestoneIndex(client, project, [issue2]);
200513
- const creatorIndex = yield* loadIssueCreatorIndex(client, [issue2]);
200514
- const milestone = milestoneForIssue(milestoneIndex, issue2);
200515
- const creator = creatorForIssue(creatorIndex, issue2);
200516
- const projected = issueDetailProjection(
200517
- issue2,
200518
- params2,
200519
- statusName,
200520
- person,
200521
- description,
200522
- labelsForIssue(labelIndex, issue2._id),
200523
- milestone,
200524
- creator
200525
- );
200526
- return yield* parseIssue(projected).pipe(
200527
- Effect_exports.mapError(
200528
- (parseError) => new HulyDataInvalidError({ operation: "getIssue", entity: "issue", cause: parseError })
200529
- )
200530
- );
200531
- });
200532
- }
200533
- });
200534
-
200535
- // src/huly/operations/issue-native-references.ts
200536
- var renderIssueDescriptionForWrite;
200537
- var init_issue_native_references = __esm({
200538
- "src/huly/operations/issue-native-references.ts"() {
200539
- "use strict";
200540
- init_dist();
200541
- init_client();
200542
- init_errors4();
200543
- init_native_reference_markup();
200544
- renderIssueDescriptionForWrite = (description) => Effect_exports.gen(function* () {
200545
- const client = yield* HulyClient;
200546
- const rendered = renderMarkdownWithNativeReferencesForWrite(description, client.markupUrlConfig, "description");
200547
- if (rendered._tag === "malformed") {
200548
- return yield* new IssueReferenceError({ reason: rendered.reason });
200549
- }
200550
- return rendered.rendered;
200551
- });
200552
- }
200553
- });
200554
-
200555
- // src/huly/operations/issues-write-shared.ts
200556
- var resolveAssignee, TASK_TYPE_DISCOVERY_HINT, taskTypeMatches, describeTaskTypeOptions, mergeTaskTypes2, resolveTaskTypeWorkflow, validStatusNames, resolveStatusForTaskType, chooseStatusForTaskType;
200557
- var init_issues_write_shared = __esm({
200558
- "src/huly/operations/issues-write-shared.ts"() {
200559
- "use strict";
200560
- init_dist();
200561
- init_normalize();
200562
- init_errors4();
200563
- init_huly_plugins();
200564
- init_contacts_shared();
200565
- init_query_helpers();
200566
- resolveAssignee = (client, assigneeIdentifier) => Effect_exports.gen(function* () {
200567
- const person = yield* findPersonByEmailOrName(client, assigneeIdentifier);
200568
- if (person === void 0) {
200569
- return yield* new PersonNotFoundError({ identifier: assigneeIdentifier });
200570
- }
200571
- return person;
200572
- });
200573
- TASK_TYPE_DISCOVERY_HINT = "Use list_task_types or get_project_type to discover valid task types and statuses.";
200574
- taskTypeMatches = (taskType, taskTypeRef) => String(taskType._id) === String(taskTypeRef) || normalizeForComparison(taskType.name) === normalizeForComparison(taskTypeRef);
200575
- describeTaskTypeOptions = (taskTypes) => taskTypes.length === 0 ? "No task types are configured for this project type." : `Available task types: ${taskTypes.map((taskType) => `${taskType.name} (${taskType._id})`).join(", ")}.`;
200576
- mergeTaskTypes2 = (first, second) => {
200577
- const taskTypesById = /* @__PURE__ */ new Map();
200578
- for (const taskType of [...first, ...second]) {
200579
- taskTypesById.set(String(taskType._id), taskType);
200580
- }
200581
- return [...taskTypesById.values()];
200582
- };
200583
- resolveTaskTypeWorkflow = (client, project, projectType, projectStatuses, taskTypeRef, projectIdentifier) => Effect_exports.gen(function* () {
200584
- const workflowProjectType = projectType ?? (yield* client.findOne(task.class.ProjectType, hulyQuery({ _id: project.type })));
200585
- if (workflowProjectType === void 0) {
200586
- return yield* Effect_exports.fail(
200587
- new HulyError({
200588
- message: `Project '${projectIdentifier}' does not expose a project type/workflow, so taskType cannot be resolved. ${TASK_TYPE_DISCOVERY_HINT}`
200589
- })
200590
- );
200591
- }
200592
- const taskTypesByProjectTypeList = yield* client.findAll(
200593
- task.class.TaskType,
200594
- hulyQuery({ _id: { $in: [...workflowProjectType.tasks] } })
200595
- );
200596
- const taskTypesByParent = yield* client.findAll(
200597
- task.class.TaskType,
200598
- hulyQuery({ parent: workflowProjectType._id })
200599
- );
200600
- const taskTypes = mergeTaskTypes2([...taskTypesByProjectTypeList], [...taskTypesByParent]);
200601
- const matches = [...taskTypes].filter((candidate) => taskTypeMatches(candidate, taskTypeRef));
200602
- const selectedTaskType = matches.length === 1 ? matches[0] : void 0;
200603
- if (selectedTaskType === void 0) {
200604
- const reason = matches.length === 0 ? "was not found" : "matched more than one task type";
200605
- return yield* Effect_exports.fail(
200606
- new HulyError({
200607
- message: `Task type '${taskTypeRef}' ${reason} in project '${projectIdentifier}' workflow. ${describeTaskTypeOptions([...taskTypes])} ${TASK_TYPE_DISCOVERY_HINT}`
200608
- })
200609
- );
200610
- }
200611
- const scopedStatuses = selectedTaskType.statuses.flatMap(
200612
- (statusId) => projectStatuses.filter((status) => status._id === statusId)
201149
+ project._id,
201150
+ issues.map((issue2) => issue2._id)
201151
+ ) : labelFilterContext.index;
201152
+ const milestoneIndex = yield* loadIssueMilestoneIndex(client, project, issues);
201153
+ const creatorIndex = yield* loadIssueCreatorIndex(client, issues);
201154
+ const rawSummaries = issues.map(
201155
+ (issue2) => issueSummaryProjection(issue2, statuses, labelIndex, milestoneIndex, creatorIndex)
200613
201156
  );
200614
- const defaultStatusId = selectedTaskType.statuses.includes(project.defaultIssueStatus) ? project.defaultIssueStatus : selectedTaskType.statuses.at(0);
200615
- return { defaultStatusId, statuses: scopedStatuses, taskType: selectedTaskType };
201157
+ const parseIssueSummaries = Schema_exports.decodeUnknownEffect(Schema_exports.Array(IssueSummarySchema));
201158
+ const validated = yield* parseIssueSummaries(rawSummaries).pipe(
201159
+ Effect_exports.mapError(
201160
+ (parseError) => new HulyDataInvalidError({ operation: "listIssues", entity: "issue", cause: parseError })
201161
+ )
201162
+ );
201163
+ return [...validated];
200616
201164
  });
200617
- validStatusNames = (workflow) => workflow.statuses.length === 0 ? workflow.taskType.statuses.join(", ") : workflow.statuses.map((status) => status.name).join(", ");
200618
- resolveStatusForTaskType = (workflow, statusName, projectIdentifier) => {
200619
- const normalizedStatusName = normalizeForComparison(statusName);
200620
- const match9 = workflow.statuses.find((status) => normalizeForComparison(status.name) === normalizedStatusName);
200621
- const statusNames = validStatusNames(workflow);
200622
- return match9 !== void 0 ? Effect_exports.succeed(match9._id) : Effect_exports.fail(
200623
- new HulyError({
200624
- message: `Status '${statusName}' is not valid for task type '${workflow.taskType.name}' in project '${projectIdentifier}'. Valid statuses for this task type: ${statusNames}. ${TASK_TYPE_DISCOVERY_HINT}`
200625
- })
201165
+ getIssue = (params2) => Effect_exports.gen(function* () {
201166
+ const { client, project, statuses } = yield* findProjectWithStatuses(params2.project);
201167
+ const issue2 = yield* findIssueForRead(client, project, params2);
201168
+ const statusName = resolveStatusName(statuses, issue2.status);
201169
+ const person = yield* loadIssueAssignee(client, issue2);
201170
+ const description = yield* loadIssueDescription(client, issue2);
201171
+ const labelIndex = yield* loadIssueLabelIndex(client, project._id, [issue2._id]);
201172
+ const milestoneIndex = yield* loadIssueMilestoneIndex(client, project, [issue2]);
201173
+ const creatorIndex = yield* loadIssueCreatorIndex(client, [issue2]);
201174
+ const milestone = milestoneForIssue(milestoneIndex, issue2);
201175
+ const creator = creatorForIssue(creatorIndex, issue2);
201176
+ const projected = issueDetailProjection(
201177
+ issue2,
201178
+ params2,
201179
+ statusName,
201180
+ person,
201181
+ description,
201182
+ labelsForIssue(labelIndex, issue2._id),
201183
+ milestone,
201184
+ creator
200626
201185
  );
200627
- };
200628
- chooseStatusForTaskType = (workflow, requestedStatus, currentStatus, projectIdentifier) => {
200629
- if (requestedStatus !== void 0) {
200630
- return resolveStatusForTaskType(workflow, requestedStatus, projectIdentifier);
200631
- }
200632
- if (currentStatus !== void 0 && workflow.taskType.statuses.includes(currentStatus)) {
200633
- return Effect_exports.succeed(currentStatus);
200634
- }
200635
- return workflow.defaultStatusId !== void 0 ? Effect_exports.succeed(workflow.defaultStatusId) : Effect_exports.fail(
200636
- new HulyError({
200637
- message: `Task type '${workflow.taskType.name}' in project '${projectIdentifier}' has no valid status. ${TASK_TYPE_DISCOVERY_HINT}`
200638
- })
201186
+ return yield* parseIssue(projected).pipe(
201187
+ Effect_exports.mapError(
201188
+ (parseError) => new HulyDataInvalidError({ operation: "getIssue", entity: "issue", cause: parseError })
201189
+ )
200639
201190
  );
200640
- };
201191
+ });
200641
201192
  }
200642
201193
  });
200643
201194
 
@@ -200742,127 +201293,6 @@ var init_issues_update = __esm({
200742
201293
  }
200743
201294
  });
200744
201295
 
200745
- // src/huly/operations/issues-write.ts
200746
- var import_core89, import_rank5, import_tracker5, TxIncResult2, extractUpdatedSequence, requireUpdatedSequence, resolveCreateIssueTaskType, resolveCreateIssueStatus, resolveCreateIssueAssignee, renderCreateIssueDescription, resolveCreateIssueParent, uploadCreateIssueDescription, createIssue, deleteIssue;
200747
- var init_issues_write = __esm({
200748
- "src/huly/operations/issues-write.ts"() {
200749
- "use strict";
200750
- import_core89 = __toESM(require_lib6(), 1);
200751
- import_rank5 = __toESM(require_lib24(), 1);
200752
- import_tracker5 = __toESM(require_lib25(), 1);
200753
- init_dist();
200754
- init_issues();
200755
- init_shared();
200756
- init_errors4();
200757
- init_huly_plugins();
200758
- init_issue_native_references();
200759
- init_issues_parent();
200760
- init_issues_shared();
200761
- init_issues_write_shared();
200762
- init_query_helpers();
200763
- init_sdk_boundary();
200764
- TxIncResult2 = Schema_exports.Struct({ object: Schema_exports.Struct({ sequence: Schema_exports.Number }) });
200765
- extractUpdatedSequence = (txResult) => {
200766
- const decoded = Schema_exports.decodeUnknownOption(TxIncResult2)(txResult);
200767
- return decoded._tag === "Some" ? decoded.value.object.sequence : void 0;
200768
- };
200769
- requireUpdatedSequence = (txResult, projectIdentifier) => {
200770
- const sequence = extractUpdatedSequence(txResult);
200771
- return sequence === void 0 ? Effect_exports.fail(
200772
- new HulyError({
200773
- message: `Project '${projectIdentifier}' sequence increment did not return the updated sequence; issue creation stopped to avoid a duplicate identifier.`
200774
- })
200775
- ) : Effect_exports.succeed(sequence);
200776
- };
200777
- resolveCreateIssueTaskType = (client, project, workflow, params2) => params2.taskType === void 0 ? Effect_exports.succeed(void 0) : resolveTaskTypeWorkflow(client, project, workflow.projectType, workflow.statuses, params2.taskType, params2.project);
200778
- resolveCreateIssueStatus = (workflow, taskTypeWorkflow, params2) => {
200779
- if (taskTypeWorkflow !== void 0) {
200780
- return chooseStatusForTaskType(taskTypeWorkflow, params2.status, void 0, params2.project);
200781
- }
200782
- if (params2.status !== void 0) return resolveStatusByName(workflow.statuses, params2.status, params2.project);
200783
- if (workflow.defaultStatusId !== void 0) return Effect_exports.succeed(workflow.defaultStatusId);
200784
- return Effect_exports.fail(new InvalidStatusError({ status: "(default)", project: params2.project }));
200785
- };
200786
- resolveCreateIssueAssignee = (client, params2) => params2.assignee === void 0 ? Effect_exports.succeed(null) : Effect_exports.map(resolveAssignee(client, params2.assignee), (person) => person._id);
200787
- renderCreateIssueDescription = (params2) => params2.description !== void 0 && params2.description.trim() !== "" ? renderIssueDescriptionForWrite(params2.description) : Effect_exports.succeed(void 0);
200788
- resolveCreateIssueParent = (client, project, parentIssue) => parentIssue === void 0 ? Effect_exports.succeed(topLevelIssueParent()) : Effect_exports.map(findIssueInProject(client, project, parentIssue), (parent) => childIssueParent(parent, project._id));
200789
- uploadCreateIssueDescription = (client, issueId, renderedDescription) => renderedDescription === void 0 ? Effect_exports.succeed(null) : client.uploadMarkup(
200790
- tracker.class.Issue,
200791
- issueId,
200792
- "description",
200793
- renderedDescription.markup,
200794
- renderedDescription.format
200795
- );
200796
- createIssue = (params2) => Effect_exports.gen(function* () {
200797
- const { client, defaultStatusId, project, projectType, statuses } = yield* findProjectWithStatuses(params2.project);
200798
- const issueId = (0, import_core89.generateId)();
200799
- const workflow = { projectType, statuses, defaultStatusId };
200800
- const taskTypeWorkflow = yield* resolveCreateIssueTaskType(client, project, workflow, params2);
200801
- const statusRef = yield* resolveCreateIssueStatus(workflow, taskTypeWorkflow, params2);
200802
- const assigneeRef = yield* resolveCreateIssueAssignee(client, params2);
200803
- const renderedDescription = yield* renderCreateIssueDescription(params2);
200804
- const { attachedTo, attachedToClass, collection, parents } = yield* resolveCreateIssueParent(
200805
- client,
200806
- project,
200807
- params2.parentIssue
200808
- );
200809
- const incOps = { $inc: { sequence: 1 } };
200810
- const incResult = yield* client.updateDoc(
200811
- tracker.class.Project,
200812
- toRef("core:space:Space"),
200813
- project._id,
200814
- incOps,
200815
- true
200816
- );
200817
- const sequence = yield* requireUpdatedSequence(incResult, params2.project);
200818
- const lastIssue = yield* client.findOne(
200819
- tracker.class.Issue,
200820
- hulyQuery({ space: project._id }),
200821
- { sort: { rank: import_core89.SortingOrder.Descending } }
200822
- );
200823
- const rank = (0, import_rank5.makeRank)(lastIssue?.rank, void 0);
200824
- const descriptionMarkupRef = yield* uploadCreateIssueDescription(client, issueId, renderedDescription);
200825
- const priority = stringToPriority(params2.priority ?? DEFAULT_ISSUE_PRIORITY);
200826
- const identifier2 = `${project.identifier}-${sequence}`;
200827
- const issueData = {
200828
- title: params2.title,
200829
- description: descriptionMarkupRef,
200830
- status: statusRef,
200831
- number: sequence,
200832
- kind: taskTypeWorkflow?.taskType._id ?? tracker.taskTypes.Issue,
200833
- identifier: identifier2,
200834
- priority,
200835
- assignee: assigneeRef,
200836
- component: null,
200837
- estimation: params2.estimation ?? 0,
200838
- remainingTime: 0,
200839
- reportedTime: 0,
200840
- reports: 0,
200841
- subIssues: 0,
200842
- parents,
200843
- childInfo: [],
200844
- dueDate: params2.dueDate ?? null,
200845
- rank
200846
- };
200847
- yield* client.addCollection(
200848
- tracker.class.Issue,
200849
- project._id,
200850
- attachedTo,
200851
- attachedToClass,
200852
- collection,
200853
- issueData,
200854
- issueId
200855
- );
200856
- return { identifier: IssueIdentifier.make(identifier2), issueId: IssueId.make(issueId) };
200857
- });
200858
- deleteIssue = (params2) => Effect_exports.gen(function* () {
200859
- const { client, issue: issue2, project } = yield* findProjectAndIssue(params2);
200860
- yield* client.removeDoc(tracker.class.Issue, project._id, issue2._id);
200861
- return { identifier: IssueIdentifier.make(issue2.identifier), deleted: true };
200862
- });
200863
- }
200864
- });
200865
-
200866
201296
  // src/huly/operations/issues.ts
200867
201297
  var init_issues2 = __esm({
200868
201298
  "src/huly/operations/issues.ts"() {
@@ -200874,351 +201304,6 @@ var init_issues2 = __esm({
200874
201304
  }
200875
201305
  });
200876
201306
 
200877
- // src/huly/operations/issue-templates.ts
200878
- var import_core90, NOT_FOUND_INDEX2, findTemplateByIdOrTitle, findProjectAndTemplate, resolveTemplateReferenceLabels, templateChildProjection, resolveChild, buildTemplateChild, listIssueTemplates, getIssueTemplate, createIssueTemplate, resolveIssueFromTemplateAssignee, templateChildCreateParams, templateChildUpdate, createTemplateChildIssues, createIssueFromTemplate, updateIssueTemplate, deleteIssueTemplate, addTemplateChild, removeTemplateChild;
200879
- var init_issue_templates2 = __esm({
200880
- "src/huly/operations/issue-templates.ts"() {
200881
- "use strict";
200882
- import_core90 = __toESM(require_lib6(), 1);
200883
- init_dist();
200884
- init_issue_templates();
200885
- init_issues();
200886
- init_shared();
200887
- init_time();
200888
- init_assertions();
200889
- init_errors4();
200890
- init_clear_field_updates();
200891
- init_components2();
200892
- init_contacts_shared();
200893
- init_issues_parent();
200894
- init_issues_shared();
200895
- init_issues2();
200896
- init_query_helpers();
200897
- init_sdk_boundary();
200898
- init_update_guards();
200899
- init_huly_plugins();
200900
- init_markup();
200901
- NOT_FOUND_INDEX2 = -1;
200902
- findTemplateByIdOrTitle = (client, projectId, templateIdOrTitle) => Effect_exports.gen(function* () {
200903
- const template = (yield* client.findOne(tracker.class.IssueTemplate, {
200904
- space: projectId,
200905
- _id: toRef(templateIdOrTitle)
200906
- })) ?? (yield* client.findOne(tracker.class.IssueTemplate, {
200907
- space: projectId,
200908
- title: templateIdOrTitle
200909
- }));
200910
- return template;
200911
- });
200912
- findProjectAndTemplate = (params2) => Effect_exports.gen(function* () {
200913
- const { client, project } = yield* findProject(params2.project);
200914
- const template = yield* findTemplateByIdOrTitle(client, project._id, params2.template);
200915
- if (template === void 0) {
200916
- return yield* new IssueTemplateNotFoundError({ identifier: params2.template, project: params2.project });
200917
- }
200918
- return { client, project, template };
200919
- });
200920
- resolveTemplateReferenceLabels = (client, assignee, component) => Effect_exports.gen(function* () {
200921
- const assigneeName = assignee === null ? void 0 : (yield* client.findOne(contact.class.Person, hulyQuery({ _id: assignee })))?.name;
200922
- const componentLabel = component === null ? void 0 : (yield* client.findOne(tracker.class.Component, hulyQuery({ _id: component })))?.label;
200923
- return {
200924
- ...assigneeName === void 0 ? {} : { assigneeName },
200925
- ...componentLabel === void 0 ? {} : { componentLabel }
200926
- };
200927
- });
200928
- templateChildProjection = (child, description, labels) => {
200929
- const rawEstimation = zeroAsUnset(NonNegativeNumber.make(child.estimation));
200930
- const estimation = rawEstimation === void 0 ? void 0 : PositiveTimeHours.make(rawEstimation);
200931
- return {
200932
- id: IssueTemplateChildId.make(child.id),
200933
- title: child.title,
200934
- priority: priorityToString(child.priority),
200935
- ...description === void 0 ? {} : { description },
200936
- ...labels.assigneeName === void 0 ? {} : { assignee: PersonName.make(labels.assigneeName) },
200937
- ...labels.componentLabel === void 0 ? {} : { component: ComponentLabel.make(labels.componentLabel) },
200938
- ...estimation === void 0 ? {} : { estimation }
200939
- };
200940
- };
200941
- resolveChild = (client, markupUrlConfig, child) => Effect_exports.gen(function* () {
200942
- const labels = yield* resolveTemplateReferenceLabels(client, child.assignee, child.component);
200943
- const description = child.description ? yield* optionalMarkupToMarkdown(child.description, markupUrlConfig, "", {
200944
- operation: "getIssueTemplate",
200945
- entity: "issue template child description"
200946
- }) : void 0;
200947
- return templateChildProjection(child, description, labels);
200948
- });
200949
- buildTemplateChild = (client, markupUrlConfig, projectId, projectIdentifier, input) => Effect_exports.gen(function* () {
200950
- const assigneeParam = input.assignee;
200951
- const assigneeRef = assigneeParam !== void 0 ? yield* Effect_exports.gen(function* () {
200952
- const person = yield* findPersonByEmailOrName(client, assigneeParam);
200953
- if (person === void 0) {
200954
- return yield* new PersonNotFoundError({ identifier: assigneeParam });
200955
- }
200956
- return person._id;
200957
- }) : null;
200958
- const componentParam = input.component;
200959
- const componentRef = componentParam !== void 0 ? yield* Effect_exports.gen(function* () {
200960
- const component = yield* findComponentByIdOrLabel(client, projectId, componentParam);
200961
- if (component === void 0) {
200962
- return yield* new ComponentNotFoundError({ identifier: componentParam, project: projectIdentifier });
200963
- }
200964
- return component._id;
200965
- }) : null;
200966
- return {
200967
- id: (0, import_core90.generateId)(),
200968
- title: input.title,
200969
- description: optionalMarkdownToMarkup(input.description, markupUrlConfig, ""),
200970
- priority: stringToPriority(input.priority ?? DEFAULT_ISSUE_PRIORITY),
200971
- assignee: assigneeRef,
200972
- component: componentRef,
200973
- estimation: input.estimation ?? 0
200974
- };
200975
- });
200976
- listIssueTemplates = (params2) => Effect_exports.gen(function* () {
200977
- const { client, project } = yield* findProject(params2.project);
200978
- const limit = clampLimit(params2.limit);
200979
- const templates2 = yield* client.findAll(
200980
- tracker.class.IssueTemplate,
200981
- { space: project._id },
200982
- { limit, sort: { modifiedOn: import_core90.SortingOrder.Descending } }
200983
- );
200984
- const summaries = templates2.map((t) => {
200985
- const base2 = {
200986
- id: IssueTemplateId.make(t._id),
200987
- title: t.title,
200988
- priority: priorityToString(t.priority),
200989
- modifiedOn: Timestamp.make(t.modifiedOn)
200990
- };
200991
- if (t.children.length > 0) {
200992
- return { ...base2, childrenCount: Count.make(t.children.length) };
200993
- }
200994
- return base2;
200995
- });
200996
- return summaries;
200997
- });
200998
- getIssueTemplate = (params2) => Effect_exports.gen(function* () {
200999
- const { client, template } = yield* findProjectAndTemplate(params2);
201000
- const markupUrlConfig = client.markupUrlConfig;
201001
- const labels = yield* resolveTemplateReferenceLabels(client, template.assignee, template.component);
201002
- const description = yield* optionalMarkupToMarkdown(template.description, markupUrlConfig, "", {
201003
- operation: "getIssueTemplate",
201004
- entity: "issue template description"
201005
- });
201006
- const resolvedChildren = [];
201007
- for (const child of template.children) {
201008
- resolvedChildren.push(yield* resolveChild(client, markupUrlConfig, child));
201009
- }
201010
- const result3 = {
201011
- id: IssueTemplateId.make(template._id),
201012
- title: template.title,
201013
- description,
201014
- priority: priorityToString(template.priority),
201015
- assignee: labels.assigneeName !== void 0 ? PersonName.make(labels.assigneeName) : void 0,
201016
- component: labels.componentLabel !== void 0 ? ComponentLabel.make(labels.componentLabel) : void 0,
201017
- estimation: template.estimation > 0 ? PositiveTimeHours.make(template.estimation) : void 0,
201018
- project: params2.project,
201019
- modifiedOn: Timestamp.make(template.modifiedOn),
201020
- createdOn: template.createdOn === void 0 ? void 0 : Timestamp.make(template.createdOn)
201021
- };
201022
- if (resolvedChildren.length > 0) {
201023
- return { ...result3, children: resolvedChildren };
201024
- }
201025
- return result3;
201026
- });
201027
- createIssueTemplate = (params2) => Effect_exports.gen(function* () {
201028
- const { client, project } = yield* findProject(params2.project);
201029
- const markupUrlConfig = client.markupUrlConfig;
201030
- const templateId = (0, import_core90.generateId)();
201031
- const assigneeParam = params2.assignee;
201032
- const assigneeRef = assigneeParam !== void 0 ? yield* Effect_exports.gen(function* () {
201033
- const person = yield* findPersonByEmailOrName(client, assigneeParam);
201034
- if (person === void 0) {
201035
- return yield* new PersonNotFoundError({ identifier: assigneeParam });
201036
- }
201037
- return person._id;
201038
- }) : null;
201039
- const componentParam = params2.component;
201040
- const componentRef = componentParam !== void 0 ? yield* Effect_exports.gen(function* () {
201041
- const component = yield* findComponentByIdOrLabel(client, project._id, componentParam);
201042
- if (component === void 0) {
201043
- return yield* new ComponentNotFoundError({ identifier: componentParam, project: params2.project });
201044
- }
201045
- return component._id;
201046
- }) : null;
201047
- const priority = stringToPriority(params2.priority ?? DEFAULT_ISSUE_PRIORITY);
201048
- const children = [];
201049
- if (params2.children !== void 0) {
201050
- for (const childInput of params2.children) {
201051
- children.push(yield* buildTemplateChild(client, markupUrlConfig, project._id, params2.project, childInput));
201052
- }
201053
- }
201054
- const templateData = {
201055
- title: params2.title,
201056
- description: optionalMarkdownToMarkup(params2.description, markupUrlConfig, ""),
201057
- priority,
201058
- assignee: assigneeRef,
201059
- component: componentRef,
201060
- estimation: params2.estimation ?? 0,
201061
- children,
201062
- comments: 0
201063
- };
201064
- yield* client.createDoc(tracker.class.IssueTemplate, project._id, templateData, templateId);
201065
- return { id: IssueTemplateId.make(templateId), title: params2.title };
201066
- });
201067
- resolveIssueFromTemplateAssignee = (client, params2, template) => Effect_exports.gen(function* () {
201068
- if (params2.assignee !== void 0) return params2.assignee;
201069
- if (template.assignee === null) return void 0;
201070
- const person = yield* client.findOne(contact.class.Person, hulyQuery({ _id: template.assignee }));
201071
- if (person === void 0) return void 0;
201072
- const emailChannel = yield* client.findOne(
201073
- contact.class.Channel,
201074
- hulyQuery({ attachedTo: person._id, provider: contact.channelProvider.Email })
201075
- );
201076
- return Email.make(emailChannel?.value ?? person.name);
201077
- });
201078
- templateChildCreateParams = (params2, child, markupUrlConfig) => optionalMarkupToMarkdown(child.description, markupUrlConfig, void 0, {
201079
- operation: "createIssueFromTemplate",
201080
- entity: "issue template child description"
201081
- }).pipe(
201082
- Effect_exports.map(
201083
- (description) => ({
201084
- project: params2.project,
201085
- title: child.title,
201086
- priority: priorityToString(child.priority),
201087
- ...description === void 0 ? {} : { description }
201088
- })
201089
- )
201090
- );
201091
- templateChildUpdate = (child) => ({
201092
- ...child.assignee === null ? {} : { assignee: child.assignee },
201093
- ...child.component === null ? {} : { component: child.component },
201094
- ...child.estimation > 0 ? { estimation: child.estimation } : {}
201095
- });
201096
- createTemplateChildIssues = (client, project, template, params2, parentResult, title, markupUrlConfig) => Effect_exports.gen(function* () {
201097
- const parentIssue = {
201098
- _id: toRef(parentResult.issueId),
201099
- identifier: parentResult.identifier,
201100
- title,
201101
- parents: []
201102
- };
201103
- for (const child of template.children) {
201104
- const childParams = yield* templateChildCreateParams(params2, child, markupUrlConfig);
201105
- const childResult = yield* createIssue(childParams);
201106
- yield* attachIssueChild(
201107
- client,
201108
- project._id,
201109
- toRef(childResult.issueId),
201110
- parentIssue,
201111
- templateChildUpdate(child)
201112
- );
201113
- }
201114
- });
201115
- createIssueFromTemplate = (params2) => Effect_exports.gen(function* () {
201116
- const { client, project, template } = yield* findProjectAndTemplate(params2);
201117
- const markupUrlConfig = client.markupUrlConfig;
201118
- const title = params2.title ?? template.title;
201119
- const description = params2.description ?? (yield* optionalMarkupToMarkdown(template.description, markupUrlConfig, void 0, {
201120
- operation: "createIssueFromTemplate",
201121
- entity: "issue template description"
201122
- }));
201123
- const priority = params2.priority ?? priorityToString(template.priority);
201124
- const assignee = yield* resolveIssueFromTemplateAssignee(client, params2, template);
201125
- const issueParams = {
201126
- project: params2.project,
201127
- title,
201128
- description,
201129
- priority,
201130
- assignee,
201131
- status: params2.status
201132
- };
201133
- const result3 = yield* createIssue(issueParams);
201134
- if (template.component !== null) {
201135
- yield* client.updateDoc(tracker.class.Issue, project._id, toRef(result3.issueId), {
201136
- component: template.component
201137
- });
201138
- }
201139
- const includeChildren = params2.includeChildren ?? DEFAULT_INCLUDE_TEMPLATE_CHILDREN;
201140
- if (includeChildren && template.children.length > 0) {
201141
- yield* createTemplateChildIssues(client, project, template, params2, result3, title, markupUrlConfig);
201142
- return { ...result3, childrenCreated: Count.make(template.children.length) };
201143
- }
201144
- return result3;
201145
- });
201146
- updateIssueTemplate = (params2) => Effect_exports.gen(function* () {
201147
- yield* requireUpdateFields("update_issue_template", params2, UPDATE_ISSUE_TEMPLATE_FIELDS);
201148
- const { client, project, template } = yield* findProjectAndTemplate(params2);
201149
- const markupUrlConfig = client.markupUrlConfig;
201150
- const updateEntries = {
201151
- title: Effect_exports.succeed(params2.title === void 0 ? {} : { title: params2.title }),
201152
- description: Effect_exports.succeed(
201153
- params2.description === void 0 ? {} : { description: optionalMarkdownToMarkup(clearTextAsEmptyString(params2.description), markupUrlConfig, "") }
201154
- ),
201155
- priority: Effect_exports.succeed(params2.priority === void 0 ? {} : { priority: stringToPriority(params2.priority) }),
201156
- assignee: Effect_exports.gen(function* () {
201157
- if (params2.assignee === void 0) return {};
201158
- if (params2.assignee === null) return { assignee: null };
201159
- const person = yield* findPersonByEmailOrName(client, params2.assignee);
201160
- if (person === void 0) {
201161
- return yield* new PersonNotFoundError({ identifier: params2.assignee });
201162
- }
201163
- return { assignee: person._id };
201164
- }),
201165
- component: Effect_exports.gen(function* () {
201166
- if (params2.component === void 0) return {};
201167
- if (params2.component === null) return { component: null };
201168
- const component = yield* findComponentByIdOrLabel(client, project._id, params2.component);
201169
- if (component === void 0) {
201170
- return yield* new ComponentNotFoundError({ identifier: params2.component, project: params2.project });
201171
- }
201172
- return { component: component._id };
201173
- }),
201174
- estimation: Effect_exports.succeed(
201175
- params2.estimation === void 0 ? {} : { estimation: params2.estimation === null ? 0 : params2.estimation }
201176
- )
201177
- };
201178
- const updateOps = mergeUpdateEntries(
201179
- yield* Effect_exports.all(Object.values(updateEntries))
201180
- );
201181
- yield* client.updateDoc(tracker.class.IssueTemplate, project._id, template._id, updateOps);
201182
- return { id: IssueTemplateId.make(template._id), updated: true };
201183
- });
201184
- deleteIssueTemplate = (params2) => Effect_exports.gen(function* () {
201185
- const { client, project, template } = yield* findProjectAndTemplate(params2);
201186
- yield* client.removeDoc(tracker.class.IssueTemplate, project._id, template._id);
201187
- return { id: IssueTemplateId.make(template._id), deleted: true };
201188
- });
201189
- addTemplateChild = (params2) => Effect_exports.gen(function* () {
201190
- const { client, project, template } = yield* findProjectAndTemplate(params2);
201191
- const markupUrlConfig = client.markupUrlConfig;
201192
- const child = yield* buildTemplateChild(client, markupUrlConfig, project._id, params2.project, {
201193
- title: params2.title,
201194
- description: params2.description,
201195
- priority: params2.priority,
201196
- assignee: params2.assignee,
201197
- component: params2.component,
201198
- estimation: params2.estimation
201199
- });
201200
- const newChildren = [...template.children, child];
201201
- yield* client.updateDoc(tracker.class.IssueTemplate, project._id, template._id, { children: newChildren });
201202
- return { id: IssueTemplateChildId.make(child.id), title: child.title, added: true };
201203
- });
201204
- removeTemplateChild = (params2) => Effect_exports.gen(function* () {
201205
- const { client, project, template } = yield* findProjectAndTemplate(params2);
201206
- const childIndex = template.children.findIndex((c) => String(c.id) === String(params2.childId));
201207
- if (childIndex === NOT_FOUND_INDEX2) {
201208
- return yield* new TemplateChildNotFoundError({
201209
- childId: params2.childId,
201210
- template: params2.template,
201211
- project: params2.project
201212
- });
201213
- }
201214
- const removedChild = assertAt(template.children, childIndex);
201215
- const newChildren = template.children.filter((_, i) => i !== childIndex);
201216
- yield* client.updateDoc(tracker.class.IssueTemplate, project._id, template._id, { children: newChildren });
201217
- return { id: IssueTemplateChildId.make(removedChild.id), title: removedChild.title, removed: true };
201218
- });
201219
- }
201220
- });
201221
-
201222
201307
  // src/huly/operations/tags.ts
201223
201308
  var import_core91, toTagSummary, buildUpdateTagOperations, listTags, createTag, updateTag, deleteTag, listAttachedTags, attachTag, detachTag;
201224
201309
  var init_tags2 = __esm({
@@ -201508,7 +201593,7 @@ var init_issues3 = __esm({
201508
201593
  name: "list_issues",
201509
201594
  description: `Query Huly issues with optional filters. Returns issues sorted by modification date (newest first). Supports filtering by project, exact workflow status name (status), Huly SDK task.statusCategory key (statusCategory: ${enumValuesDescription(
201510
201595
  StatusCategoryValues
201511
- )}), assignee, creator (raw Person ID, exact email, or exact display name), component, a human-readable attached label title (label, exact and case-insensitive), milestone (project-scoped ID or exact case-insensitive label), milestone presence (hasMilestone), parentIssue (to list children of a specific issue), and isTopLevel (to return only native top-level issues). Creator, label, and milestone filters are applied before the result limit; ambiguous creator display names fail actionably and unknown creators return an empty list. Each result includes creator as a stable Person reference { id, name?, email? } when resolvable and the assigned milestone as { id, label } when resolvable. Supports searching by title substring (titleSearch) and description content (descriptionSearch). Each result includes deterministic label summaries with title and available color; missing labels are an empty array, duplicate titles collapse case-insensitively while preferring a valid color, and unusable partial attachments are omitted with a tool warning.`,
201596
+ )}), assignee (email, Person display name, or exact agent UserProfile title), creator (raw Person ID, exact email, or exact display name), component, a human-readable attached label title (label, exact and case-insensitive), milestone (project-scoped ID or exact case-insensitive label), milestone presence (hasMilestone), parentIssue (to list children of a specific issue), and isTopLevel (to return only native top-level issues). Creator, label, and milestone filters are applied before the result limit; ambiguous creator display names fail actionably and unknown creators return an empty list. Each result includes creator as a stable Person reference { id, name?, email? } when resolvable and the assigned milestone as { id, label } when resolvable. Supports searching by title substring (titleSearch) and description content (descriptionSearch). Each result includes deterministic label summaries with title and available color; missing labels are an empty array, duplicate titles collapse case-insensitively while preferring a valid color, and unusable partial attachments are omitted with a tool warning.`,
201512
201597
  category: CATEGORY24,
201513
201598
  inputSchema: listIssuesParamsJsonSchema,
201514
201599
  resultSchema: ListIssuesResultSchema
@@ -201530,7 +201615,7 @@ var init_issues3 = __esm({
201530
201615
  defineTool(
201531
201616
  {
201532
201617
  name: "create_issue",
201533
- description: "Create a new issue in a Huly project. Omit parentIssue for a native top-level issue, or specify parentIssue to create a sub-issue. Optionally set taskType by ID or display name; it is resolved within the target project's project type, and status is validated against that task type's workflow. Use list_task_types or get_project_type to discover valid task types and statuses. Description supports markdown formatting; markdown links to current-workspace Huly browse URLs with _class, _id, and label become native references, while external URLs stay normal links. Returns the created issue identifier.",
201618
+ description: "Create a new issue in a Huly project. Assignee accepts an email, Person display name, or exact agent UserProfile title and always stores the linked Person. Omit parentIssue for a native top-level issue, or specify parentIssue to create a sub-issue. Optionally set taskType by ID or display name; it is resolved within the target project's project type, and status is validated against that task type's workflow. Use list_task_types or get_project_type to discover valid task types and statuses. Description supports markdown formatting; markdown links to current-workspace Huly browse URLs with _class, _id, and label become native references, while external URLs stay normal links. Returns the created issue identifier.",
201534
201619
  category: CATEGORY24,
201535
201620
  inputSchema: createIssueParamsJsonSchema,
201536
201621
  resultSchema: CreateIssueResultSchema
@@ -201541,7 +201626,7 @@ var init_issues3 = __esm({
201541
201626
  defineTool(
201542
201627
  {
201543
201628
  name: "update_issue",
201544
- description: "Update fields on an existing Huly issue. Optionally set taskType by ID or display name; it is resolved within the target project's project type, and the status is preserved only when valid for the new task type. Use list_task_types or get_project_type to discover valid task types and statuses. Only provided fields are modified. Description updates support markdown; markdown links to current-workspace Huly browse URLs with _class, _id, and label become native references, while external URLs stay normal links.",
201629
+ description: "Update fields on an existing Huly issue. Assignee accepts an email, Person display name, or exact agent UserProfile title and always stores the linked Person; use null to unassign. Optionally set taskType by ID or display name; it is resolved within the target project's project type, and the status is preserved only when valid for the new task type. Use list_task_types or get_project_type to discover valid task types and statuses. Only provided fields are modified. Description updates support markdown; markdown links to current-workspace Huly browse URLs with _class, _id, and label become native references, while external URLs stay normal links.",
201545
201630
  category: CATEGORY24,
201546
201631
  inputSchema: updateIssueParamsJsonSchema,
201547
201632
  resultSchema: UpdateIssueResultSchema
@@ -223180,7 +223265,7 @@ if (unsupportedRuntime) {
223180
223265
  detectedNodeVersion: process.versions.node,
223181
223266
  executable: process.execPath,
223182
223267
  requiredNodeVersion: nodeEngineRequirement,
223183
- serverVersion: "0.49.7"
223268
+ serverVersion: "0.50.0"
223184
223269
  });
223185
223270
  startUnsupportedNodeMcp(config2);
223186
223271
  } else {