@firfi/huly-mcp 0.49.6 → 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 +15 -3
  2. package/dist/index.cjs +1168 -1039
  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(
@@ -125061,7 +125069,7 @@ var init_unavailable_diagnostics = __esm({
125061
125069
  });
125062
125070
 
125063
125071
  // src/huly/errors-base.ts
125064
- var HulyError, NoUpdateFieldsError, HulyConnectionError, HulyDataInvalidError, HulyUnavailableError, HulyAuthError, HulyModelNameSchema, HulyModelFieldSchema, HulyModelMetadataError;
125072
+ var HulyError, NoUpdateFieldsError, HulyConnectionOperation, HulyHttpStatus, HulyConnectionDiagnostic, HulyConnectionError, HTTP_ERROR_STATUS_PATTERN, hulyHttpStatusFromCause, makeOperationConnectionError, HulyDataInvalidError, HulyUnavailableError, HulyAuthError, HulyModelNameSchema, HulyModelFieldSchema, HulyModelMetadataError;
125065
125073
  var init_errors_base = __esm({
125066
125074
  "src/huly/errors-base.ts"() {
125067
125075
  "use strict";
@@ -125080,11 +125088,67 @@ var init_errors_base = __esm({
125080
125088
  return `${this.operation} requires at least one update field: ${this.fields.join(", ")}`;
125081
125089
  }
125082
125090
  };
125091
+ HulyConnectionOperation = Schema_exports.Literals([
125092
+ "findAll",
125093
+ "findOne",
125094
+ "findAllInModel",
125095
+ "createDoc",
125096
+ "conditionalCreateDoc",
125097
+ "updateDoc",
125098
+ "conditionalUpdateDoc",
125099
+ "addCollection",
125100
+ "updateCollection",
125101
+ "removeCollection",
125102
+ "removeDoc",
125103
+ "conditionalRemoveDoc",
125104
+ "createMixin",
125105
+ "updateMixin",
125106
+ "uploadMarkup",
125107
+ "fetchMarkup",
125108
+ "updateMarkup",
125109
+ "searchFulltext",
125110
+ "getWorkspaceMembers",
125111
+ "getPersonInfo",
125112
+ "updateWorkspaceRole",
125113
+ "getWorkspaceInfo",
125114
+ "getUserWorkspaces",
125115
+ "createWorkspace",
125116
+ "deleteWorkspace",
125117
+ "getUserProfile",
125118
+ "setMyProfile",
125119
+ "createAccessLink",
125120
+ "updateAllowReadOnlyGuests",
125121
+ "updateAllowGuestSignUp",
125122
+ "getRegionInfo"
125123
+ ]);
125124
+ HulyHttpStatus = Schema_exports.Int.check(Schema_exports.isBetween({ minimum: 100, maximum: 599 })).pipe(
125125
+ Schema_exports.brand("HulyHttpStatus")
125126
+ );
125127
+ HulyConnectionDiagnostic = Schema_exports.Struct({
125128
+ operation: HulyConnectionOperation,
125129
+ httpStatus: Schema_exports.optionalKey(HulyHttpStatus)
125130
+ });
125083
125131
  HulyConnectionError = class extends Schema_exports.TaggedError()("HulyConnectionError", {
125084
125132
  message: Schema_exports.String,
125085
- cause: Schema_exports.optional(Schema_exports.Defect())
125133
+ cause: Schema_exports.optional(Schema_exports.Defect()),
125134
+ diagnostic: Schema_exports.optionalKey(HulyConnectionDiagnostic)
125086
125135
  }) {
125087
125136
  };
125137
+ HTTP_ERROR_STATUS_PATTERN = /\bHTTP(?: error)?\s+(?<status>[1-5]\d{2})\b/i;
125138
+ hulyHttpStatusFromCause = (cause) => {
125139
+ if (!(cause instanceof Error)) return void 0;
125140
+ const statusText = HTTP_ERROR_STATUS_PATTERN.exec(cause.message)?.groups?.status;
125141
+ if (statusText === void 0) return void 0;
125142
+ return HulyHttpStatus.make(Number(statusText));
125143
+ };
125144
+ makeOperationConnectionError = (operation, cause) => {
125145
+ const httpStatus = hulyHttpStatusFromCause(cause);
125146
+ const message = `${operation} failed${httpStatus === void 0 ? "" : ` with HTTP ${httpStatus}`}`;
125147
+ return new HulyConnectionError({
125148
+ message,
125149
+ diagnostic: { operation, ...httpStatus === void 0 ? {} : { httpStatus } }
125150
+ });
125151
+ };
125088
125152
  HulyDataInvalidError = class extends Schema_exports.TaggedError()("HulyDataInvalidError", {
125089
125153
  operation: Schema_exports.String,
125090
125154
  entity: Schema_exports.String,
@@ -125144,7 +125208,7 @@ var VERSION;
125144
125208
  var init_version = __esm({
125145
125209
  "src/version.ts"() {
125146
125210
  "use strict";
125147
- VERSION = true ? "0.49.6" : "0.0.0-dev";
125211
+ VERSION = true ? "0.50.0" : "0.0.0-dev";
125148
125212
  }
125149
125213
  });
125150
125214
 
@@ -125489,7 +125553,7 @@ var init_errors_contacts = __esm({
125489
125553
  { identifier: Schema_exports.String, matches: AmbiguousMatchCount }
125490
125554
  ) {
125491
125555
  get message() {
125492
- 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`;
125493
125557
  }
125494
125558
  };
125495
125559
  OrganizationNotFoundError = class extends Schema_exports.TaggedError()(
@@ -128260,7 +128324,7 @@ var init_tool_responses = __esm({
128260
128324
  });
128261
128325
 
128262
128326
  // src/mcp/error-mapping.ts
128263
- var INVALID_PARAMS_TAGS, INTERNAL_ERROR_PREFIX, hulyUnavailableMessage, mapDomainErrorToMcp, isClientResolutionError, clientResolutionFailure, mapClientResolutionErrorToMcp, mapClientResolutionCauseToMcp, clientResolutionErrorMessage, clientResolutionCauseMessage, mapParseErrorToMcp, mapParseCauseToMcp, mapDomainCauseToMcp;
128327
+ var INVALID_PARAMS_TAGS, INTERNAL_ERROR_PREFIX, CONNECTION_ERROR_GUIDANCE, hulyConnectionMessage, hulyUnavailableMessage, mapDomainErrorToMcp, isClientResolutionError, clientResolutionFailure, redactResolutionDetail, mapClientResolutionErrorToMcp, mapClientResolutionCauseToMcp, clientResolutionErrorMessage, clientResolutionCauseMessage, mapParseErrorToMcp, mapParseCauseToMcp, mapDomainCauseToMcp;
128264
128328
  var init_error_mapping = __esm({
128265
128329
  "src/mcp/error-mapping.ts"() {
128266
128330
  "use strict";
@@ -128472,9 +128536,13 @@ var init_error_mapping = __esm({
128472
128536
  INTERNAL_ERROR_PREFIX = {
128473
128537
  FileUploadError: "File upload error",
128474
128538
  HulyStorageConfigError: "Storage configuration error",
128475
- HulyConnectionError: "Connection error",
128476
128539
  HulyAuthError: "Authentication error"
128477
128540
  };
128541
+ CONNECTION_ERROR_GUIDANCE = "Verify HULY_URL, workspace, and network connectivity before retrying.";
128542
+ hulyConnectionMessage = (error3) => {
128543
+ const diagnostic = error3.diagnostic;
128544
+ return diagnostic === void 0 ? `Connection error while communicating with Huly. ${CONNECTION_ERROR_GUIDANCE}` : `Connection error while communicating with Huly: ${diagnostic.operation} failed${diagnostic.httpStatus === void 0 ? "" : ` with HTTP ${diagnostic.httpStatus}`}. ${CONNECTION_ERROR_GUIDANCE}`;
128545
+ };
128478
128546
  hulyUnavailableMessage = (error3) => {
128479
128547
  const failureGuidance = error3.failureKind === "timeout" ? " The request timed out; verify HULY_CONNECTION_TIMEOUT before retrying." : error3.failureKind === "dns" || error3.failureKind === "tls" ? " Verify the hostname, certificate, DNS, and proxy configuration before retrying." : "";
128480
128548
  if (isDefaultHulyCloudOrigin(error3.endpointOrigin)) {
@@ -128487,12 +128555,7 @@ var init_error_mapping = __esm({
128487
128555
  return createErrorResponse(hulyUnavailableMessage(error3), McpErrorCode.InternalError, error3._tag, warnings);
128488
128556
  }
128489
128557
  if (error3 instanceof HulyConnectionError) {
128490
- return createErrorResponse(
128491
- "Connection error while communicating with Huly. Verify HULY_URL, workspace, and network connectivity before retrying.",
128492
- McpErrorCode.InternalError,
128493
- error3._tag,
128494
- warnings
128495
- );
128558
+ return createErrorResponse(hulyConnectionMessage(error3), McpErrorCode.InternalError, error3._tag, warnings);
128496
128559
  }
128497
128560
  if (INVALID_PARAMS_TAGS.has(error3._tag)) {
128498
128561
  return createErrorResponse(error3.message, McpErrorCode.InvalidParams, error3._tag, warnings);
@@ -128507,9 +128570,10 @@ var init_error_mapping = __esm({
128507
128570
  if (!Cause_exports.isCause(error3)) return void 0;
128508
128571
  return findRecoverableCauseFailure(error3, isClientResolutionError);
128509
128572
  };
128573
+ redactResolutionDetail = (failure) => failure instanceof HulyConnectionError ? new HulyConnectionError({ message: "" }) : failure;
128510
128574
  mapClientResolutionErrorToMcp = (error3) => {
128511
128575
  const failure = clientResolutionFailure(error3);
128512
- return failure === void 0 ? mapDomainErrorToMcp(new HulyError({ message: "Failed to initialize Huly clients" })) : mapDomainErrorToMcp(failure);
128576
+ return failure === void 0 ? mapDomainErrorToMcp(new HulyError({ message: "Failed to initialize Huly clients" })) : mapDomainErrorToMcp(redactResolutionDetail(failure));
128513
128577
  };
128514
128578
  mapClientResolutionCauseToMcp = (cause) => mapClientResolutionErrorToMcp(cause);
128515
128579
  clientResolutionErrorMessage = (error3) => mapClientResolutionErrorToMcp(error3).content[0].text;
@@ -178671,39 +178735,36 @@ var init_client = __esm({
178671
178735
  );
178672
178736
  const markupUrlConfig = { refUrl: UrlString.make(refUrl), imageUrl: UrlString.make(imageUrl) };
178673
178737
  const workbenchUrlConfig = { baseUrl: UrlString.make(config2.url), workspaceUrlSlug };
178674
- const withClient = (op, errorMsg) => Effect_exports.tryPromise({
178675
- try: () => op(client),
178676
- catch: (e) => new HulyConnectionError({ message: `${errorMsg}: ${String(e)}`, cause: e })
178677
- });
178738
+ const withClient = (op, operation) => Effect_exports.tryPromise({ try: () => op(client), catch: (error3) => makeOperationConnectionError(operation, error3) });
178678
178739
  const operations = {
178679
178740
  getAccountUuid: () => accountUuid,
178680
178741
  getPrimarySocialId: () => primarySocialId,
178681
178742
  getSocialIds: () => socialIds,
178682
178743
  workbenchUrlConfig,
178683
178744
  markupUrlConfig,
178684
- findAll: (_class, query, options) => withClient((client2) => client2.findAll(_class, query, options), "findAll failed"),
178685
- findOne: (_class, query, options) => withClient((client2) => client2.findOne(_class, query, options), "findOne failed"),
178745
+ findAll: (_class, query, options) => withClient((client2) => client2.findAll(_class, query, options), "findAll"),
178746
+ findOne: (_class, query, options) => withClient((client2) => client2.findOne(_class, query, options), "findOne"),
178686
178747
  findAllInModel: (_class, query, options) => withClient(
178687
178748
  (client2) => Promise.resolve(client2.getModel().findAllSync(_class, query, options)),
178688
- "findAllInModel failed"
178749
+ "findAllInModel"
178689
178750
  ),
178690
- createDoc: (_class, space, attributes, id2) => withClient((client2) => client2.createDoc(_class, space, attributes, id2), "createDoc failed"),
178751
+ createDoc: (_class, space, attributes, id2) => withClient((client2) => client2.createDoc(_class, space, attributes, id2), "createDoc"),
178691
178752
  createDocIfNotMatched: (_class, space, attributes, id2, matchClass, matchQuery, scope3) => withClient(async (client2) => {
178692
178753
  const apply2 = client2.apply(scope3);
178693
178754
  apply2.notMatch(matchClass, matchQuery);
178694
178755
  await apply2.createDoc(_class, space, attributes, id2);
178695
178756
  return (await apply2.commit()).result ? "applied" : "condition-not-met";
178696
- }, "conditional createDoc failed"),
178697
- updateDoc: (_class, space, objectId, ops, retrieve) => withClient((client2) => client2.updateDoc(_class, space, objectId, ops, retrieve), "updateDoc failed"),
178757
+ }, "conditionalCreateDoc"),
178758
+ updateDoc: (_class, space, objectId, ops, retrieve) => withClient((client2) => client2.updateDoc(_class, space, objectId, ops, retrieve), "updateDoc"),
178698
178759
  updateDocIfMatched: (_class, space, objectId, matchQuery, operations2, scope3) => withClient(async (client2) => {
178699
178760
  const apply2 = client2.apply(scope3);
178700
178761
  apply2.match(_class, matchQuery);
178701
178762
  await apply2.updateDoc(_class, space, objectId, operations2);
178702
178763
  return (await apply2.commit()).result ? "applied" : "condition-not-met";
178703
- }, "conditional updateDoc failed"),
178764
+ }, "conditionalUpdateDoc"),
178704
178765
  addCollection: (_class, space, attachedTo, attachedToClass, collection, attributes, id2) => withClient(
178705
178766
  (client2) => client2.addCollection(_class, space, attachedTo, attachedToClass, collection, attributes, id2),
178706
- "addCollection failed"
178767
+ "addCollection"
178707
178768
  ),
178708
178769
  updateCollection: (_class, space, objectId, attachedTo, attachedToClass, collection, operations2, retrieve) => withClient(
178709
178770
  (client2) => client2.updateCollection(
@@ -178716,40 +178777,40 @@ var init_client = __esm({
178716
178777
  operations2,
178717
178778
  retrieve
178718
178779
  ),
178719
- "updateCollection failed"
178780
+ "updateCollection"
178720
178781
  ),
178721
178782
  removeCollection: (_class, space, objectId, attachedTo, attachedToClass, collection) => withClient(
178722
178783
  (client2) => client2.removeCollection(_class, space, objectId, attachedTo, attachedToClass, collection),
178723
- "removeCollection failed"
178784
+ "removeCollection"
178724
178785
  ),
178725
- removeDoc: (_class, space, objectId) => withClient((client2) => client2.removeDoc(_class, space, objectId), "removeDoc failed"),
178786
+ removeDoc: (_class, space, objectId) => withClient((client2) => client2.removeDoc(_class, space, objectId), "removeDoc"),
178726
178787
  removeDocIfMatched: (_class, space, objectId, matchQuery, scope3) => withClient(async (client2) => {
178727
178788
  const apply2 = client2.apply(scope3);
178728
178789
  apply2.match(_class, matchQuery);
178729
178790
  await apply2.removeDoc(_class, space, objectId);
178730
178791
  return (await apply2.commit()).result ? "applied" : "condition-not-met";
178731
- }, "conditional removeDoc failed"),
178792
+ }, "conditionalRemoveDoc"),
178732
178793
  createMixin: (objectId, objectClass, objectSpace, mixin, attributes) => withClient(
178733
178794
  (client2) => client2.createMixin(objectId, objectClass, objectSpace, mixin, attributes),
178734
- "createMixin failed"
178795
+ "createMixin"
178735
178796
  ),
178736
178797
  updateMixin: (objectId, objectClass, objectSpace, mixin, attributes) => withClient(
178737
178798
  (client2) => client2.updateMixin(objectId, objectClass, objectSpace, mixin, attributes),
178738
- "updateMixin failed"
178799
+ "updateMixin"
178739
178800
  ),
178740
178801
  uploadMarkup: (objectClass, objectId, objectAttr, markup, format5) => Effect_exports.tryPromise({
178741
178802
  try: () => markupOps.uploadMarkup(objectClass, objectId, objectAttr, markup, format5),
178742
- catch: (e) => new HulyConnectionError({ message: `uploadMarkup failed: ${String(e)}`, cause: e })
178803
+ catch: (error3) => makeOperationConnectionError("uploadMarkup", error3)
178743
178804
  }),
178744
178805
  fetchMarkup: (objectClass, objectId, objectAttr, id2, format5) => Effect_exports.tryPromise({
178745
178806
  try: () => markupOps.fetchMarkup(objectClass, objectId, objectAttr, id2, format5),
178746
- catch: (e) => new HulyConnectionError({ message: `fetchMarkup failed: ${String(e)}`, cause: e })
178807
+ catch: (error3) => makeOperationConnectionError("fetchMarkup", error3)
178747
178808
  }),
178748
178809
  updateMarkup: (objectClass, objectId, objectAttr, markup, format5) => Effect_exports.tryPromise({
178749
178810
  try: () => markupOps.updateMarkup(objectClass, objectId, objectAttr, markup, format5),
178750
- catch: (e) => new HulyConnectionError({ message: `updateMarkup failed: ${String(e)}`, cause: e })
178811
+ catch: (error3) => makeOperationConnectionError("updateMarkup", error3)
178751
178812
  }),
178752
- searchFulltext: (query, options) => withClient((client2) => client2.searchFulltext(query, options), "searchFulltext failed")
178813
+ searchFulltext: (query, options) => withClient((client2) => client2.searchFulltext(query, options), "searchFulltext")
178753
178814
  };
178754
178815
  return operations;
178755
178816
  })
@@ -179225,14 +179286,50 @@ var init_update_guards = __esm({
179225
179286
  }
179226
179287
  });
179227
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
+
179228
179324
  // src/huly/operations/contacts-shared.ts
179229
- 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;
179230
179326
  var init_contacts_shared = __esm({
179231
179327
  "src/huly/operations/contacts-shared.ts"() {
179232
179328
  "use strict";
179233
179329
  import_core38 = __toESM(require_lib6(), 1);
179234
179330
  init_dist();
179235
179331
  init_shared();
179332
+ init_assertions();
179236
179333
  init_errors4();
179237
179334
  init_huly_plugins();
179238
179335
  init_query_helpers();
@@ -179268,24 +179365,60 @@ var init_contacts_shared = __esm({
179268
179365
  return emailMap;
179269
179366
  });
179270
179367
  findPersonIdsByEmailSearch = (client, emailSearch) => Effect_exports.gen(function* () {
179271
- const value3 = { $like: `%${escapeLikeWildcards(emailSearch)}%` };
179272
- const [channels, socialIdentities] = yield* Effect_exports.all([
179273
- client.findAll(
179274
- contact.class.Channel,
179275
- hulyQuery({ provider: contact.channelProvider.Email, value: value3 })
179276
- ),
179368
+ const [channelPersonIds, socialIdentities] = yield* Effect_exports.all([
179369
+ findPersonIdsByEmailChannelSearch(client, emailSearch),
179277
179370
  client.findAll(
179278
179371
  contact.class.SocialIdentity,
179279
- hulyQuery({ type: import_core38.SocialIdType.EMAIL, value: value3 })
179372
+ hulyQuery({
179373
+ type: import_core38.SocialIdType.EMAIL,
179374
+ value: { $like: `%${escapeLikeWildcards(emailSearch)}%` }
179375
+ })
179280
179376
  )
179281
179377
  ]);
179282
179378
  return [
179283
- .../* @__PURE__ */ new Set([
179284
- ...channels.map((channel) => toRef(channel.attachedTo)),
179285
- ...socialIdentities.map((identity2) => toRef(identity2.attachedTo))
179286
- ])
179379
+ .../* @__PURE__ */ new Set([...channelPersonIds, ...socialIdentities.map((identity2) => toRef(identity2.attachedTo))])
179287
179380
  ];
179288
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
+ );
179289
179422
  findPersonBySocialIdentityEmail = (client, email3) => Effect_exports.gen(function* () {
179290
179423
  const identity2 = yield* client.findOne(contact.class.SocialIdentity, {
179291
179424
  type: import_core38.SocialIdType.EMAIL,
@@ -179295,43 +179428,23 @@ var init_contacts_shared = __esm({
179295
179428
  return yield* client.findOne(contact.class.Person, { _id: identity2.attachedTo });
179296
179429
  });
179297
179430
  findPersonByExactEmail = (client, email3) => Effect_exports.gen(function* () {
179298
- const socialIdentities = yield* client.findAll(contact.class.SocialIdentity, {
179299
- type: import_core38.SocialIdType.EMAIL,
179300
- value: email3
179301
- });
179302
- const channels = yield* client.findAll(contact.class.Channel, {
179303
- value: email3,
179304
- provider: contact.channelProvider.Email
179305
- });
179306
- const personIds = [
179307
- .../* @__PURE__ */ new Set([
179308
- ...socialIdentities.map((identity2) => identity2.attachedTo),
179309
- ...channels.map((channel) => channel.attachedTo)
179310
- ])
179311
- ];
179312
- if (personIds.length === 0) {
179313
- return void 0;
179314
- }
179315
- const persons = yield* client.findAll(contact.class.Person, {
179316
- _id: { $in: personIds.map(toRef) }
179317
- });
179318
- if (persons.length === 0) {
179319
- return void 0;
179320
- }
179321
- if (persons.length > 1) {
179322
- return yield* new PersonIdentifierAmbiguousError({ identifier: email3, matches: Count.make(persons.length) });
179323
- }
179324
- 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
+ );
179325
179439
  });
179326
179440
  findPersonByExactName = (client, name) => Effect_exports.gen(function* () {
179327
- const persons = yield* client.findAll(contact.class.Person, { name });
179328
- if (persons.length === 0) {
179329
- return void 0;
179330
- }
179331
- if (persons.length > 1) {
179332
- return yield* new PersonIdentifierAmbiguousError({ identifier: name, matches: Count.make(persons.length) });
179333
- }
179334
- 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
+ );
179335
179448
  });
179336
179449
  findPersonByExactEmailOrName = (client, identifier2) => isEmailIdentifier(identifier2) ? findPersonByExactEmail(client, identifier2) : findPersonByExactName(client, identifier2);
179337
179450
  findPersonByIdOrExactEmailOrName = (client, identifier2) => Effect_exports.gen(function* () {
@@ -179384,35 +179497,6 @@ var init_contacts_shared = __esm({
179384
179497
  }
179385
179498
  });
179386
179499
 
179387
- // src/utils/assertions.ts
179388
- var PAIR_LENGTH, AssertionError, assertExists, isExistent, assertAt, isNonEmpty3, isSingle, isPair;
179389
- var init_assertions = __esm({
179390
- "src/utils/assertions.ts"() {
179391
- "use strict";
179392
- PAIR_LENGTH = 2;
179393
- AssertionError = class extends Error {
179394
- _tag = "AssertionError";
179395
- constructor(message) {
179396
- super(message);
179397
- this.name = "AssertionError";
179398
- }
179399
- };
179400
- assertExists = (value3, message) => {
179401
- if (value3 === null || value3 === void 0) {
179402
- throw new AssertionError(message ?? "Expected value to exist");
179403
- }
179404
- return value3;
179405
- };
179406
- isExistent = (value3) => value3 !== null && value3 !== void 0;
179407
- assertAt = (arr, index2, message) => {
179408
- return assertExists(arr[index2], message ?? `Expected array item at index ${index2}`);
179409
- };
179410
- isNonEmpty3 = (arr) => arr.length > 0;
179411
- isSingle = (arr) => arr.length === 1;
179412
- isPair = (arr) => arr.length === PAIR_LENGTH;
179413
- }
179414
- });
179415
-
179416
179500
  // src/huly/operations/spaces-shared.ts
179417
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;
179418
179502
  var init_spaces_shared = __esm({
@@ -183437,10 +183521,7 @@ var init_workspace_client = __esm({
183437
183521
  { url: config2.url, auth: config2.auth, workspace: config2.workspace },
183438
183522
  sdk
183439
183523
  );
183440
- const withClient = (op, errorMsg) => Effect_exports.tryPromise({
183441
- try: () => op(client),
183442
- catch: (e) => new HulyConnectionError({ message: `${errorMsg}: ${String(e)}`, cause: e })
183443
- });
183524
+ const withClient = (op, operation) => Effect_exports.tryPromise({ try: () => op(client), catch: (error3) => makeOperationConnectionError(operation, error3) });
183444
183525
  const accessLinkIdentityOptions = (options) => ({
183445
183526
  ...options.firstName !== void 0 ? { firstName: options.firstName } : {},
183446
183527
  ...options.lastName !== void 0 ? { lastName: options.lastName } : {},
@@ -183454,25 +183535,19 @@ var init_workspace_client = __esm({
183454
183535
  });
183455
183536
  const toAccountClientAccessLinkOptions = (options) => options === void 0 ? void 0 : { ...accessLinkIdentityOptions(options), ...accessLinkTimingOptions(options) };
183456
183537
  const operations = {
183457
- getWorkspaceMembers: () => withClient((c) => c.getWorkspaceMembers(), "Failed to get workspace members"),
183458
- getPersonInfo: (account) => withClient((c) => c.getPersonInfo(account), "Failed to get person info"),
183459
- updateWorkspaceRole: (account, role) => withClient((c) => c.updateWorkspaceRole(account, role), "Failed to update workspace role"),
183460
- getWorkspaceInfo: (updateLastVisit) => withClient((c) => c.getWorkspaceInfo(updateLastVisit), "Failed to get workspace info"),
183461
- getUserWorkspaces: () => withClient((c) => c.getUserWorkspaces(), "Failed to get user workspaces"),
183462
- createWorkspace: (name, region) => withClient((c) => c.createWorkspace(name, region), "Failed to create workspace"),
183463
- deleteWorkspace: () => withClient((c) => c.deleteWorkspace(), "Failed to delete workspace"),
183464
- getUserProfile: (personUuid) => withClient((c) => c.getUserProfile(personUuid), "Failed to get user profile"),
183465
- setMyProfile: (profile) => withClient((c) => c.setMyProfile(profile), "Failed to set my profile"),
183466
- createAccessLink: (role, options) => withClient(
183467
- (c) => c.createAccessLink(role, toAccountClientAccessLinkOptions(options)),
183468
- "Failed to create access link"
183469
- ),
183470
- updateAllowReadOnlyGuests: (readOnlyGuestsAllowed) => withClient(
183471
- (c) => c.updateAllowReadOnlyGuests(readOnlyGuestsAllowed),
183472
- "Failed to update read-only guest setting"
183473
- ),
183474
- updateAllowGuestSignUp: (guestSignUpAllowed) => withClient((c) => c.updateAllowGuestSignUp(guestSignUpAllowed), "Failed to update guest sign-up setting"),
183475
- getRegionInfo: () => withClient((c) => c.getRegionInfo(), "Failed to get region info")
183538
+ getWorkspaceMembers: () => withClient((c) => c.getWorkspaceMembers(), "getWorkspaceMembers"),
183539
+ getPersonInfo: (account) => withClient((c) => c.getPersonInfo(account), "getPersonInfo"),
183540
+ updateWorkspaceRole: (account, role) => withClient((c) => c.updateWorkspaceRole(account, role), "updateWorkspaceRole"),
183541
+ getWorkspaceInfo: (updateLastVisit) => withClient((c) => c.getWorkspaceInfo(updateLastVisit), "getWorkspaceInfo"),
183542
+ getUserWorkspaces: () => withClient((c) => c.getUserWorkspaces(), "getUserWorkspaces"),
183543
+ createWorkspace: (name, region) => withClient((c) => c.createWorkspace(name, region), "createWorkspace"),
183544
+ deleteWorkspace: () => withClient((c) => c.deleteWorkspace(), "deleteWorkspace"),
183545
+ getUserProfile: (personUuid) => withClient((c) => c.getUserProfile(personUuid), "getUserProfile"),
183546
+ setMyProfile: (profile) => withClient((c) => c.setMyProfile(profile), "setMyProfile"),
183547
+ createAccessLink: (role, options) => withClient((c) => c.createAccessLink(role, toAccountClientAccessLinkOptions(options)), "createAccessLink"),
183548
+ updateAllowReadOnlyGuests: (readOnlyGuestsAllowed) => withClient((c) => c.updateAllowReadOnlyGuests(readOnlyGuestsAllowed), "updateAllowReadOnlyGuests"),
183549
+ updateAllowGuestSignUp: (guestSignUpAllowed) => withClient((c) => c.updateAllowGuestSignUp(guestSignUpAllowed), "updateAllowGuestSignUp"),
183550
+ getRegionInfo: () => withClient((c) => c.getRegionInfo(), "getRegionInfo")
183476
183551
  };
183477
183552
  return operations;
183478
183553
  })
@@ -193821,7 +193896,7 @@ var init_persons = __esm({
193821
193896
  };
193822
193897
  applyPersonEmailSearch = (client, query, emailSearch) => Effect_exports.gen(function* () {
193823
193898
  if (emailSearch === void 0 || emailSearch === "") return true;
193824
- const matchingPersonIds = yield* findPersonIdsByEmailSearch(client, emailSearch);
193899
+ const matchingPersonIds = yield* findPersonIdsByEmailSearch(client, NonEmptyString2.make(emailSearch));
193825
193900
  if (matchingPersonIds.length === 0) return false;
193826
193901
  query._id = { $in: matchingPersonIds };
193827
193902
  return true;
@@ -199859,319 +199934,947 @@ var init_issues_parent = __esm({
199859
199934
  }
199860
199935
  });
199861
199936
 
199862
- // src/huly/operations/issues-move.ts
199863
- var import_core87, import_tracker3, issueTargetClass, addLabel, moveIssue, updateDescendantParents;
199864
- var init_issues_move = __esm({
199865
- "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"() {
199866
199941
  "use strict";
199867
- import_core87 = __toESM(require_lib6(), 1);
199868
- import_tracker3 = __toESM(require_lib25(), 1);
199869
199942
  init_dist();
199870
- init_shared();
199871
- init_tags();
199872
- init_huly_plugins();
199873
- init_issues_parent();
199874
- init_issues_shared();
199875
- init_query_helpers();
199876
- init_sdk_boundary();
199877
- init_tags_shared();
199878
- issueTargetClass = TagTargetClass.make(String(tracker.class.Issue));
199879
- addLabel = (params2) => Effect_exports.gen(function* () {
199880
- const { issue: issue2, project } = yield* findProjectAndIssue(params2);
199881
- const labelTitle = TagIdentifier.make(params2.label.trim());
199882
- const tag2 = yield* ensureTagElement({
199883
- targetClass: issueTargetClass,
199884
- titleOrId: labelTitle,
199885
- color: params2.color,
199886
- fallbackCategory: tracker.category.Other
199887
- });
199888
- const result3 = yield* attachTagReference({
199889
- tag: tag2,
199890
- objectId: issue2._id,
199891
- objectClass: tracker.class.Issue,
199892
- space: project._id,
199893
- collection: "labels",
199894
- matchTitleCaseInsensitive: true
199895
- });
199896
- return { identifier: IssueIdentifier.make(issue2.identifier), labelAdded: result3.attached };
199897
- });
199898
- moveIssue = (params2) => Effect_exports.gen(function* () {
199899
- const { client, issue: issue2, project } = yield* findProjectAndIssue(params2);
199900
- const oldParentIsIssue = hasConcreteIssueParent(issue2);
199901
- const newParentParam = params2.newParent;
199902
- const target = newParentParam !== null ? yield* Effect_exports.gen(function* () {
199903
- const parentIssue = yield* findIssueInProject(client, project, newParentParam);
199904
- return {
199905
- _tag: "Child",
199906
- identifier: IssueIdentifier.make(parentIssue.identifier),
199907
- issue: parentIssue,
199908
- parent: childIssueParent(parentIssue, project._id)
199909
- };
199910
- }) : { _tag: "TopLevel", parent: topLevelIssueParent() };
199911
- if (target._tag === "Child") {
199912
- yield* attachIssueChild(client, project._id, issue2._id, target.issue, {});
199913
- } else {
199914
- yield* client.updateDoc(tracker.class.Issue, project._id, issue2._id, {
199915
- attachedTo: toRef(target.parent.attachedTo),
199916
- attachedToClass: target.parent.attachedToClass,
199917
- collection: target.parent.collection,
199918
- parents: target.parent.parents
199919
- });
199920
- }
199921
- if (oldParentIsIssue) {
199922
- yield* client.updateDoc(
199923
- tracker.class.Issue,
199924
- project._id,
199925
- // issue.attachedTo is Ref<Doc>; for sub-issues it points to the parent issue.
199926
- // Cast needed because updateDoc expects Ref<HulyIssue> but attachedTo is Ref<Doc>.
199927
- toRef(issue2.attachedTo),
199928
- { $inc: { subIssues: -1 } }
199929
- );
199930
- }
199931
- if (issue2.subIssues > 0) {
199932
- yield* updateDescendantParents(client, project._id, issue2, target.parent.parents);
199933
- }
199934
- const result3 = { identifier: IssueIdentifier.make(issue2.identifier), moved: true };
199935
- if (target._tag === "Child") {
199936
- return { ...result3, newParent: target.identifier };
199937
- }
199938
- return result3;
199939
- });
199940
- updateDescendantParents = (client, spaceId, parentIssue, parentNewParents) => Effect_exports.gen(function* () {
199941
- const thisParentInfo = {
199942
- parentId: parentIssue._id,
199943
- identifier: parentIssue.identifier,
199944
- parentTitle: parentIssue.title,
199945
- space: spaceId
199946
- };
199947
- const children = yield* client.findAll(
199948
- tracker.class.Issue,
199949
- hulyQuery({ attachedTo: parentIssue._id, space: spaceId })
199950
- );
199951
- for (const child of children) {
199952
- const childNewParents = [...parentNewParents, thisParentInfo];
199953
- yield* client.updateDoc(tracker.class.Issue, spaceId, child._id, { parents: childNewParents });
199954
- if (child.subIssues > 0) {
199955
- yield* updateDescendantParents(client, spaceId, child, childNewParents);
199956
- }
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 });
199957
199951
  }
199952
+ return rendered.rendered;
199958
199953
  });
199959
199954
  }
199960
199955
  });
199961
199956
 
199962
- // src/huly/operations/issue-creators-read.ts
199963
- var parsePersonRef, uniqueCreatorIds, creatorRef, creatorForIssue, loadIssueCreatorIndex;
199964
- var init_issue_creators_read = __esm({
199965
- "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"() {
199966
199961
  "use strict";
199967
199962
  init_dist();
199968
- init_issues();
199969
- init_tool_warnings();
199970
- init_diagnostics();
199963
+ init_shared();
199964
+ init_assertions();
199965
+ init_errors4();
199971
199966
  init_huly_plugins();
199972
199967
  init_contacts_shared();
199973
199968
  init_query_helpers();
199974
199969
  init_sdk_boundary();
199975
- parsePersonRef = Schema_exports.decodeUnknownOption(PersonRefSchema);
199976
- uniqueCreatorIds = (issues) => [
199977
- ...new Set(issues.flatMap((issue2) => issue2.createdBy === void 0 ? [] : [issue2.createdBy]))
199978
- ];
199979
- creatorRef = (person, emailByPerson) => parsePersonRef({
199980
- id: person._id,
199981
- ...person.name.trim() === "" ? {} : { name: person.name },
199982
- ...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
+ ]);
199983
199984
  });
199984
- creatorForIssue = (index2, issue2) => issue2.createdBy === void 0 ? void 0 : index2.get(issue2.createdBy);
199985
- loadIssueCreatorIndex = (client, issues) => Effect_exports.gen(function* () {
199986
- const creatorIds = uniqueCreatorIds(issues);
199987
- if (creatorIds.length === 0) return /* @__PURE__ */ new Map();
199988
- const identities = yield* client.findAll(
199989
- contact.class.SocialIdentity,
199990
- hulyQuery({ _id: { $in: creatorIds.map(toSocialIdentityRef) } })
199991
- );
199992
- const personIds = [...new Set(identities.map((identity2) => identity2.attachedTo))];
199993
- const persons = personIds.length === 0 ? [] : yield* client.findAll(
199994
- contact.class.Person,
199995
- hulyQuery({ _id: { $in: personIds.map(toRef) } })
199996
- );
199997
- const emailByPerson = yield* batchGetEmailsForPersons(
199998
- client,
199999
- persons.map((person) => person._id)
200000
- );
200001
- const personById = new Map(persons.map((person) => [person._id, person]));
200002
- const index2 = /* @__PURE__ */ new Map();
200003
- for (const identity2 of identities) {
200004
- const person = personById.get(identity2.attachedTo);
200005
- if (person === void 0) continue;
200006
- const parsed = creatorRef(person, emailByPerson);
200007
- if (Option_exports.isSome(parsed)) index2.set(identity2._id, parsed.value);
200008
- }
200009
- const unresolvedCount = creatorIds.filter((creatorId) => !index2.has(creatorId)).length;
200010
- if (unresolvedCount > 0) {
200011
- const diagnostics = yield* Diagnostics;
200012
- yield* diagnostics.warnAgent({
200013
- code: IssueCreatorMetadataDegradedWarningCode,
200014
- message: `${unresolvedCount} unresolved issue creator reference(s) were omitted from issue results.`
200015
- });
200016
- }
200017
- 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));
200018
200001
  });
200019
200002
  }
200020
200003
  });
200021
200004
 
200022
- // src/huly/operations/issue-labels-read.ts
200023
- 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;
200024
- var init_issue_labels_read = __esm({
200025
- "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"() {
200026
200009
  "use strict";
200027
200010
  init_dist();
200028
- init_shared();
200029
- init_tool_warnings();
200030
- init_diagnostics();
200011
+ init_normalize();
200012
+ init_errors4();
200031
200013
  init_huly_plugins();
200014
+ init_issue_assignee_resolution();
200032
200015
  init_query_helpers();
200033
- init_sdk_boundary();
200034
- IssueLabelAttachmentBoundarySchema = Schema_exports.Struct({
200035
- _id: TagReferenceId,
200036
- attachedTo: IssueId,
200037
- title: Schema_exports.optional(Schema_exports.Unknown),
200038
- color: Schema_exports.optional(Schema_exports.Unknown)
200039
- }).annotate({
200040
- title: "IssueLabelAttachmentBoundary",
200041
- 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
+ });
200042
200022
  });
200043
- NormalizedLabelTitle = NonEmptyString2.pipe(Schema_exports.brand("NormalizedLabelTitle"));
200044
- decodeAttachment = Schema_exports.decodeUnknownResult(IssueLabelAttachmentBoundarySchema);
200045
- decodeTitle = Schema_exports.decodeUnknownResult(NonEmptyString2);
200046
- decodeColor = Schema_exports.decodeUnknownResult(ColorCode);
200047
- toDocRef2 = (id2) => toRef(IssueId.make(id2));
200048
- toIssueRef = toRef;
200049
- normalizeLabelTitle = (title) => NormalizedLabelTitle.make(title.toLowerCase());
200050
- COLOR_SORT_WIDTH = 2;
200051
- compareStrings = (left, right) => Number(left > right) - Number(left < right);
200052
- candidateSortKey = (candidate) => [
200053
- candidate.normalizedTitle,
200054
- candidate.color === void 0 ? "1" : "0",
200055
- candidate.title,
200056
- String(candidate.color).padStart(COLOR_SORT_WIDTH, "0"),
200057
- candidate.referenceId
200058
- ].join("\0");
200059
- compareCandidates = (left, right) => compareStrings(candidateSortKey(left), candidateSortKey(right));
200060
- toCandidate3 = (input) => {
200061
- const attachment2 = decodeAttachment(input);
200062
- if (Result_exports.isFailure(attachment2)) {
200063
- return { _tag: "Rejected", degradationReason: "malformed_attachment" };
200064
- }
200065
- const title = decodeTitle(attachment2.success.title);
200066
- if (Result_exports.isFailure(title)) {
200067
- 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);
200068
200030
  }
200069
- const colorInput = attachment2.success.color;
200070
- const color = colorInput === void 0 ? void 0 : decodeColor(colorInput);
200071
- const candidate = {
200072
- referenceId: attachment2.success._id,
200073
- issueId: attachment2.success.attachedTo,
200074
- title: title.success,
200075
- normalizedTitle: normalizeLabelTitle(title.success),
200076
- ...color !== void 0 && Result_exports.isSuccess(color) ? { color: color.success } : {}
200077
- };
200078
- return color !== void 0 && Result_exports.isFailure(color) ? { _tag: "DegradedSuccess", candidate, degradationReason: "invalid_color" } : { _tag: "Success", candidate };
200031
+ return [...taskTypesById.values()];
200079
200032
  };
200080
- projectionCandidate = (projection) => projection._tag === "Rejected" ? [] : [projection.candidate];
200081
- projectionDegradationReason = (projection) => {
200082
- switch (projection._tag) {
200083
- case "Success":
200084
- return [];
200085
- case "DegradedSuccess":
200086
- case "Rejected":
200087
- 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
+ );
200088
200041
  }
200089
- };
200090
- projectCandidateGroup = (candidates) => {
200091
- const sorted = [...candidates].sort(compareCandidates);
200092
- return sorted.filter(
200093
- (candidate, index2) => sorted.findIndex((other) => other.normalizedTitle === candidate.normalizedTitle) === index2
200094
- ).map((candidate) => ({
200095
- title: candidate.title,
200096
- ...candidate.color === void 0 ? {} : { color: candidate.color }
200097
- }));
200098
- };
200099
- buildIssueLabelIndex = (attachments) => {
200100
- const projections = attachments.map(toCandidate3);
200101
- const candidates = projections.flatMap(projectionCandidate);
200102
- const issueIds = [...new Set(candidates.map((candidate) => candidate.issueId))];
200103
- return {
200104
- byIssueId: new Map(
200105
- issueIds.map((issueId) => [
200106
- issueId,
200107
- projectCandidateGroup(candidates.filter((candidate) => candidate.issueId === issueId))
200108
- ])
200109
- ),
200110
- degradationReasons: projections.flatMap(projectionDegradationReason)
200111
- };
200112
- };
200113
- countReason = (reasons, reason) => reasons.filter((candidate) => candidate === reason).length;
200114
- degradationMessage = (reasons) => {
200115
- const malformedAttachments = countReason(reasons, "malformed_attachment");
200116
- const malformedTitles = countReason(reasons, "missing_or_malformed_title");
200117
- const invalidColors = countReason(reasons, "invalid_color");
200118
- 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.`;
200119
- };
200120
- labelsForIssue = (index2, issueId) => index2.byIssueId.get(IssueId.make(issueId)) ?? [];
200121
- issueIdsMatchingLabel = (index2, label) => {
200122
- const normalizedFilter = normalizeLabelTitle(label);
200123
- return [...index2.byIssueId].filter(([, labels]) => labels.some((summary) => normalizeLabelTitle(summary.title) === normalizedFilter)).map(([issueId]) => toIssueRef(issueId)).sort(compareStrings);
200124
- };
200125
- loadIssueLabelIndex = (client, space, issueIds) => Effect_exports.gen(function* () {
200126
- if (issueIds !== void 0 && issueIds.length === 0) return buildIssueLabelIndex([]);
200127
- const diagnostics = yield* Diagnostics;
200128
- const baseQuery = {
200129
- space,
200130
- attachedToClass: tracker.class.Issue,
200131
- collection: "labels"
200132
- };
200133
- const query = issueIds === void 0 ? baseQuery : { ...baseQuery, attachedTo: { $in: issueIds.map(toDocRef2) } };
200134
- const attachments = yield* client.findAll(tags.class.TagReference, hulyQuery(query));
200135
- const index2 = buildIssueLabelIndex(attachments);
200136
- if (index2.degradationReasons.length > 0) {
200137
- yield* diagnostics.warnAgent({
200138
- code: IssueLabelMetadataDegradedWarningCode,
200139
- message: degradationMessage(index2.degradationReasons)
200140
- });
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
+ );
200141
200060
  }
200142
- 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 };
200143
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
+ };
200144
200091
  }
200145
200092
  });
200146
200093
 
200147
- // src/huly/operations/issue-milestones-read.ts
200148
- var parseMilestoneRef, uniqueMilestoneRefs, milestoneForIssue, loadIssueMilestoneIndex;
200149
- var init_issue_milestones_read = __esm({
200150
- "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"() {
200151
200098
  "use strict";
200099
+ import_core87 = __toESM(require_lib6(), 1);
200100
+ import_rank5 = __toESM(require_lib24(), 1);
200101
+ import_tracker3 = __toESM(require_lib25(), 1);
200152
200102
  init_dist();
200153
200103
  init_issues();
200154
200104
  init_shared();
200155
- init_tool_warnings();
200156
- init_diagnostics();
200105
+ init_errors4();
200157
200106
  init_huly_plugins();
200107
+ init_issue_native_references();
200108
+ init_issues_parent();
200109
+ init_issues_shared();
200110
+ init_issues_write_shared();
200158
200111
  init_query_helpers();
200159
- parseMilestoneRef = Schema_exports.decodeUnknownOption(IssueMilestoneRefSchema);
200160
- uniqueMilestoneRefs = (issues) => [
200161
- ...new Set(
200162
- issues.flatMap((issue2) => issue2.milestone === null || issue2.milestone === void 0 ? [] : [issue2.milestone])
200163
- )
200164
- ];
200165
- milestoneForIssue = (index2, issue2) => issue2.milestone === null || issue2.milestone === void 0 ? void 0 : index2.get(MilestoneId.make(issue2.milestone));
200166
- loadIssueMilestoneIndex = (client, project, issues) => Effect_exports.gen(function* () {
200167
- const refs = uniqueMilestoneRefs(issues);
200168
- if (refs.length === 0) return /* @__PURE__ */ new Map();
200169
- const milestones = yield* client.findAll(
200170
- tracker.class.Milestone,
200171
- hulyQuery({ space: project._id, _id: { $in: refs } })
200172
- );
200173
- const index2 = /* @__PURE__ */ new Map();
200174
- for (const milestone of milestones) {
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) {
200175
200878
  const parsed = parseMilestoneRef({ id: milestone._id, label: milestone.label });
200176
200879
  if (Option_exports.isSome(parsed)) index2.set(parsed.value.id, parsed.value);
200177
200880
  }
@@ -200251,12 +200954,12 @@ var init_milestone_resolution = __esm({
200251
200954
  });
200252
200955
 
200253
200956
  // src/huly/operations/issues-read.ts
200254
- 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;
200255
200958
  var init_issues_read = __esm({
200256
200959
  "src/huly/operations/issues-read.ts"() {
200257
200960
  "use strict";
200258
- import_core88 = __toESM(require_lib6(), 1);
200259
- import_tracker4 = __toESM(require_lib25(), 1);
200961
+ import_core90 = __toESM(require_lib6(), 1);
200962
+ import_tracker5 = __toESM(require_lib25(), 1);
200260
200963
  init_dist();
200261
200964
  init_issues();
200262
200965
  init_shared();
@@ -200264,6 +200967,7 @@ var init_issues_read = __esm({
200264
200967
  init_huly_plugins();
200265
200968
  init_components2();
200266
200969
  init_contacts_shared();
200970
+ init_issue_assignee_resolution();
200267
200971
  init_issue_creators_read();
200268
200972
  init_issue_labels_read();
200269
200973
  init_issue_milestones_read();
@@ -200294,9 +200998,9 @@ var init_issues_read = __esm({
200294
200998
  query.status = yield* resolveStatusByName([...statuses], params2.status, params2.project);
200295
200999
  }
200296
201000
  if (params2.assignee !== void 0) {
200297
- const assigneePerson = yield* findPersonByEmailOrName(client, params2.assignee);
200298
- if (assigneePerson === void 0) return false;
200299
- 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;
200300
201004
  }
200301
201005
  return true;
200302
201006
  });
@@ -200436,164 +201140,55 @@ var init_issues_read = __esm({
200436
201140
  tracker.class.Issue,
200437
201141
  hulyQuery(effectiveQuery),
200438
201142
  withLookup(
200439
- { limit, sort: { modifiedOn: import_core88.SortingOrder.Descending } },
201143
+ { limit, sort: { modifiedOn: import_core90.SortingOrder.Descending } },
200440
201144
  { assignee: contact.class.Person }
200441
201145
  )
200442
201146
  );
200443
201147
  const labelIndex = labelFilterContext === void 0 ? yield* loadIssueLabelIndex(
200444
201148
  client,
200445
- project._id,
200446
- issues.map((issue2) => issue2._id)
200447
- ) : labelFilterContext.index;
200448
- const milestoneIndex = yield* loadIssueMilestoneIndex(client, project, issues);
200449
- const creatorIndex = yield* loadIssueCreatorIndex(client, issues);
200450
- const rawSummaries = issues.map(
200451
- (issue2) => issueSummaryProjection(issue2, statuses, labelIndex, milestoneIndex, creatorIndex)
200452
- );
200453
- const parseIssueSummaries = Schema_exports.decodeUnknownEffect(Schema_exports.Array(IssueSummarySchema));
200454
- const validated = yield* parseIssueSummaries(rawSummaries).pipe(
200455
- Effect_exports.mapError(
200456
- (parseError) => new HulyDataInvalidError({ operation: "listIssues", entity: "issue", cause: parseError })
200457
- )
200458
- );
200459
- return [...validated];
200460
- });
200461
- getIssue = (params2) => Effect_exports.gen(function* () {
200462
- const { client, project, statuses } = yield* findProjectWithStatuses(params2.project);
200463
- const issue2 = yield* findIssueForRead(client, project, params2);
200464
- const statusName = resolveStatusName(statuses, issue2.status);
200465
- const person = yield* loadIssueAssignee(client, issue2);
200466
- const description = yield* loadIssueDescription(client, issue2);
200467
- const labelIndex = yield* loadIssueLabelIndex(client, project._id, [issue2._id]);
200468
- const milestoneIndex = yield* loadIssueMilestoneIndex(client, project, [issue2]);
200469
- const creatorIndex = yield* loadIssueCreatorIndex(client, [issue2]);
200470
- const milestone = milestoneForIssue(milestoneIndex, issue2);
200471
- const creator = creatorForIssue(creatorIndex, issue2);
200472
- const projected = issueDetailProjection(
200473
- issue2,
200474
- params2,
200475
- statusName,
200476
- person,
200477
- description,
200478
- labelsForIssue(labelIndex, issue2._id),
200479
- milestone,
200480
- creator
200481
- );
200482
- return yield* parseIssue(projected).pipe(
200483
- Effect_exports.mapError(
200484
- (parseError) => new HulyDataInvalidError({ operation: "getIssue", entity: "issue", cause: parseError })
200485
- )
200486
- );
200487
- });
200488
- }
200489
- });
200490
-
200491
- // src/huly/operations/issue-native-references.ts
200492
- var renderIssueDescriptionForWrite;
200493
- var init_issue_native_references = __esm({
200494
- "src/huly/operations/issue-native-references.ts"() {
200495
- "use strict";
200496
- init_dist();
200497
- init_client();
200498
- init_errors4();
200499
- init_native_reference_markup();
200500
- renderIssueDescriptionForWrite = (description) => Effect_exports.gen(function* () {
200501
- const client = yield* HulyClient;
200502
- const rendered = renderMarkdownWithNativeReferencesForWrite(description, client.markupUrlConfig, "description");
200503
- if (rendered._tag === "malformed") {
200504
- return yield* new IssueReferenceError({ reason: rendered.reason });
200505
- }
200506
- return rendered.rendered;
200507
- });
200508
- }
200509
- });
200510
-
200511
- // src/huly/operations/issues-write-shared.ts
200512
- var resolveAssignee, TASK_TYPE_DISCOVERY_HINT, taskTypeMatches, describeTaskTypeOptions, mergeTaskTypes2, resolveTaskTypeWorkflow, validStatusNames, resolveStatusForTaskType, chooseStatusForTaskType;
200513
- var init_issues_write_shared = __esm({
200514
- "src/huly/operations/issues-write-shared.ts"() {
200515
- "use strict";
200516
- init_dist();
200517
- init_normalize();
200518
- init_errors4();
200519
- init_huly_plugins();
200520
- init_contacts_shared();
200521
- init_query_helpers();
200522
- resolveAssignee = (client, assigneeIdentifier) => Effect_exports.gen(function* () {
200523
- const person = yield* findPersonByEmailOrName(client, assigneeIdentifier);
200524
- if (person === void 0) {
200525
- return yield* new PersonNotFoundError({ identifier: assigneeIdentifier });
200526
- }
200527
- return person;
200528
- });
200529
- TASK_TYPE_DISCOVERY_HINT = "Use list_task_types or get_project_type to discover valid task types and statuses.";
200530
- taskTypeMatches = (taskType, taskTypeRef) => String(taskType._id) === String(taskTypeRef) || normalizeForComparison(taskType.name) === normalizeForComparison(taskTypeRef);
200531
- 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(", ")}.`;
200532
- mergeTaskTypes2 = (first, second) => {
200533
- const taskTypesById = /* @__PURE__ */ new Map();
200534
- for (const taskType of [...first, ...second]) {
200535
- taskTypesById.set(String(taskType._id), taskType);
200536
- }
200537
- return [...taskTypesById.values()];
200538
- };
200539
- resolveTaskTypeWorkflow = (client, project, projectType, projectStatuses, taskTypeRef, projectIdentifier) => Effect_exports.gen(function* () {
200540
- const workflowProjectType = projectType ?? (yield* client.findOne(task.class.ProjectType, hulyQuery({ _id: project.type })));
200541
- if (workflowProjectType === void 0) {
200542
- return yield* Effect_exports.fail(
200543
- new HulyError({
200544
- message: `Project '${projectIdentifier}' does not expose a project type/workflow, so taskType cannot be resolved. ${TASK_TYPE_DISCOVERY_HINT}`
200545
- })
200546
- );
200547
- }
200548
- const taskTypesByProjectTypeList = yield* client.findAll(
200549
- task.class.TaskType,
200550
- hulyQuery({ _id: { $in: [...workflowProjectType.tasks] } })
200551
- );
200552
- const taskTypesByParent = yield* client.findAll(
200553
- task.class.TaskType,
200554
- hulyQuery({ parent: workflowProjectType._id })
200555
- );
200556
- const taskTypes = mergeTaskTypes2([...taskTypesByProjectTypeList], [...taskTypesByParent]);
200557
- const matches = [...taskTypes].filter((candidate) => taskTypeMatches(candidate, taskTypeRef));
200558
- const selectedTaskType = matches.length === 1 ? matches[0] : void 0;
200559
- if (selectedTaskType === void 0) {
200560
- const reason = matches.length === 0 ? "was not found" : "matched more than one task type";
200561
- return yield* Effect_exports.fail(
200562
- new HulyError({
200563
- message: `Task type '${taskTypeRef}' ${reason} in project '${projectIdentifier}' workflow. ${describeTaskTypeOptions([...taskTypes])} ${TASK_TYPE_DISCOVERY_HINT}`
200564
- })
200565
- );
200566
- }
200567
- const scopedStatuses = selectedTaskType.statuses.flatMap(
200568
- (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)
200569
201156
  );
200570
- const defaultStatusId = selectedTaskType.statuses.includes(project.defaultIssueStatus) ? project.defaultIssueStatus : selectedTaskType.statuses.at(0);
200571
- 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];
200572
201164
  });
200573
- validStatusNames = (workflow) => workflow.statuses.length === 0 ? workflow.taskType.statuses.join(", ") : workflow.statuses.map((status) => status.name).join(", ");
200574
- resolveStatusForTaskType = (workflow, statusName, projectIdentifier) => {
200575
- const normalizedStatusName = normalizeForComparison(statusName);
200576
- const match9 = workflow.statuses.find((status) => normalizeForComparison(status.name) === normalizedStatusName);
200577
- const statusNames = validStatusNames(workflow);
200578
- return match9 !== void 0 ? Effect_exports.succeed(match9._id) : Effect_exports.fail(
200579
- new HulyError({
200580
- 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}`
200581
- })
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
200582
201185
  );
200583
- };
200584
- chooseStatusForTaskType = (workflow, requestedStatus, currentStatus, projectIdentifier) => {
200585
- if (requestedStatus !== void 0) {
200586
- return resolveStatusForTaskType(workflow, requestedStatus, projectIdentifier);
200587
- }
200588
- if (currentStatus !== void 0 && workflow.taskType.statuses.includes(currentStatus)) {
200589
- return Effect_exports.succeed(currentStatus);
200590
- }
200591
- return workflow.defaultStatusId !== void 0 ? Effect_exports.succeed(workflow.defaultStatusId) : Effect_exports.fail(
200592
- new HulyError({
200593
- message: `Task type '${workflow.taskType.name}' in project '${projectIdentifier}' has no valid status. ${TASK_TYPE_DISCOVERY_HINT}`
200594
- })
201186
+ return yield* parseIssue(projected).pipe(
201187
+ Effect_exports.mapError(
201188
+ (parseError) => new HulyDataInvalidError({ operation: "getIssue", entity: "issue", cause: parseError })
201189
+ )
200595
201190
  );
200596
- };
201191
+ });
200597
201192
  }
200598
201193
  });
200599
201194
 
@@ -200698,127 +201293,6 @@ var init_issues_update = __esm({
200698
201293
  }
200699
201294
  });
200700
201295
 
200701
- // src/huly/operations/issues-write.ts
200702
- var import_core89, import_rank5, import_tracker5, TxIncResult2, extractUpdatedSequence, requireUpdatedSequence, resolveCreateIssueTaskType, resolveCreateIssueStatus, resolveCreateIssueAssignee, renderCreateIssueDescription, resolveCreateIssueParent, uploadCreateIssueDescription, createIssue, deleteIssue;
200703
- var init_issues_write = __esm({
200704
- "src/huly/operations/issues-write.ts"() {
200705
- "use strict";
200706
- import_core89 = __toESM(require_lib6(), 1);
200707
- import_rank5 = __toESM(require_lib24(), 1);
200708
- import_tracker5 = __toESM(require_lib25(), 1);
200709
- init_dist();
200710
- init_issues();
200711
- init_shared();
200712
- init_errors4();
200713
- init_huly_plugins();
200714
- init_issue_native_references();
200715
- init_issues_parent();
200716
- init_issues_shared();
200717
- init_issues_write_shared();
200718
- init_query_helpers();
200719
- init_sdk_boundary();
200720
- TxIncResult2 = Schema_exports.Struct({ object: Schema_exports.Struct({ sequence: Schema_exports.Number }) });
200721
- extractUpdatedSequence = (txResult) => {
200722
- const decoded = Schema_exports.decodeUnknownOption(TxIncResult2)(txResult);
200723
- return decoded._tag === "Some" ? decoded.value.object.sequence : void 0;
200724
- };
200725
- requireUpdatedSequence = (txResult, projectIdentifier) => {
200726
- const sequence = extractUpdatedSequence(txResult);
200727
- return sequence === void 0 ? Effect_exports.fail(
200728
- new HulyError({
200729
- message: `Project '${projectIdentifier}' sequence increment did not return the updated sequence; issue creation stopped to avoid a duplicate identifier.`
200730
- })
200731
- ) : Effect_exports.succeed(sequence);
200732
- };
200733
- 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);
200734
- resolveCreateIssueStatus = (workflow, taskTypeWorkflow, params2) => {
200735
- if (taskTypeWorkflow !== void 0) {
200736
- return chooseStatusForTaskType(taskTypeWorkflow, params2.status, void 0, params2.project);
200737
- }
200738
- if (params2.status !== void 0) return resolveStatusByName(workflow.statuses, params2.status, params2.project);
200739
- if (workflow.defaultStatusId !== void 0) return Effect_exports.succeed(workflow.defaultStatusId);
200740
- return Effect_exports.fail(new InvalidStatusError({ status: "(default)", project: params2.project }));
200741
- };
200742
- resolveCreateIssueAssignee = (client, params2) => params2.assignee === void 0 ? Effect_exports.succeed(null) : Effect_exports.map(resolveAssignee(client, params2.assignee), (person) => person._id);
200743
- renderCreateIssueDescription = (params2) => params2.description !== void 0 && params2.description.trim() !== "" ? renderIssueDescriptionForWrite(params2.description) : Effect_exports.succeed(void 0);
200744
- resolveCreateIssueParent = (client, project, parentIssue) => parentIssue === void 0 ? Effect_exports.succeed(topLevelIssueParent()) : Effect_exports.map(findIssueInProject(client, project, parentIssue), (parent) => childIssueParent(parent, project._id));
200745
- uploadCreateIssueDescription = (client, issueId, renderedDescription) => renderedDescription === void 0 ? Effect_exports.succeed(null) : client.uploadMarkup(
200746
- tracker.class.Issue,
200747
- issueId,
200748
- "description",
200749
- renderedDescription.markup,
200750
- renderedDescription.format
200751
- );
200752
- createIssue = (params2) => Effect_exports.gen(function* () {
200753
- const { client, defaultStatusId, project, projectType, statuses } = yield* findProjectWithStatuses(params2.project);
200754
- const issueId = (0, import_core89.generateId)();
200755
- const workflow = { projectType, statuses, defaultStatusId };
200756
- const taskTypeWorkflow = yield* resolveCreateIssueTaskType(client, project, workflow, params2);
200757
- const statusRef = yield* resolveCreateIssueStatus(workflow, taskTypeWorkflow, params2);
200758
- const assigneeRef = yield* resolveCreateIssueAssignee(client, params2);
200759
- const renderedDescription = yield* renderCreateIssueDescription(params2);
200760
- const { attachedTo, attachedToClass, collection, parents } = yield* resolveCreateIssueParent(
200761
- client,
200762
- project,
200763
- params2.parentIssue
200764
- );
200765
- const incOps = { $inc: { sequence: 1 } };
200766
- const incResult = yield* client.updateDoc(
200767
- tracker.class.Project,
200768
- toRef("core:space:Space"),
200769
- project._id,
200770
- incOps,
200771
- true
200772
- );
200773
- const sequence = yield* requireUpdatedSequence(incResult, params2.project);
200774
- const lastIssue = yield* client.findOne(
200775
- tracker.class.Issue,
200776
- hulyQuery({ space: project._id }),
200777
- { sort: { rank: import_core89.SortingOrder.Descending } }
200778
- );
200779
- const rank = (0, import_rank5.makeRank)(lastIssue?.rank, void 0);
200780
- const descriptionMarkupRef = yield* uploadCreateIssueDescription(client, issueId, renderedDescription);
200781
- const priority = stringToPriority(params2.priority ?? DEFAULT_ISSUE_PRIORITY);
200782
- const identifier2 = `${project.identifier}-${sequence}`;
200783
- const issueData = {
200784
- title: params2.title,
200785
- description: descriptionMarkupRef,
200786
- status: statusRef,
200787
- number: sequence,
200788
- kind: taskTypeWorkflow?.taskType._id ?? tracker.taskTypes.Issue,
200789
- identifier: identifier2,
200790
- priority,
200791
- assignee: assigneeRef,
200792
- component: null,
200793
- estimation: params2.estimation ?? 0,
200794
- remainingTime: 0,
200795
- reportedTime: 0,
200796
- reports: 0,
200797
- subIssues: 0,
200798
- parents,
200799
- childInfo: [],
200800
- dueDate: params2.dueDate ?? null,
200801
- rank
200802
- };
200803
- yield* client.addCollection(
200804
- tracker.class.Issue,
200805
- project._id,
200806
- attachedTo,
200807
- attachedToClass,
200808
- collection,
200809
- issueData,
200810
- issueId
200811
- );
200812
- return { identifier: IssueIdentifier.make(identifier2), issueId: IssueId.make(issueId) };
200813
- });
200814
- deleteIssue = (params2) => Effect_exports.gen(function* () {
200815
- const { client, issue: issue2, project } = yield* findProjectAndIssue(params2);
200816
- yield* client.removeDoc(tracker.class.Issue, project._id, issue2._id);
200817
- return { identifier: IssueIdentifier.make(issue2.identifier), deleted: true };
200818
- });
200819
- }
200820
- });
200821
-
200822
201296
  // src/huly/operations/issues.ts
200823
201297
  var init_issues2 = __esm({
200824
201298
  "src/huly/operations/issues.ts"() {
@@ -200830,351 +201304,6 @@ var init_issues2 = __esm({
200830
201304
  }
200831
201305
  });
200832
201306
 
200833
- // src/huly/operations/issue-templates.ts
200834
- var import_core90, NOT_FOUND_INDEX2, findTemplateByIdOrTitle, findProjectAndTemplate, resolveTemplateReferenceLabels, templateChildProjection, resolveChild, buildTemplateChild, listIssueTemplates, getIssueTemplate, createIssueTemplate, resolveIssueFromTemplateAssignee, templateChildCreateParams, templateChildUpdate, createTemplateChildIssues, createIssueFromTemplate, updateIssueTemplate, deleteIssueTemplate, addTemplateChild, removeTemplateChild;
200835
- var init_issue_templates2 = __esm({
200836
- "src/huly/operations/issue-templates.ts"() {
200837
- "use strict";
200838
- import_core90 = __toESM(require_lib6(), 1);
200839
- init_dist();
200840
- init_issue_templates();
200841
- init_issues();
200842
- init_shared();
200843
- init_time();
200844
- init_assertions();
200845
- init_errors4();
200846
- init_clear_field_updates();
200847
- init_components2();
200848
- init_contacts_shared();
200849
- init_issues_parent();
200850
- init_issues_shared();
200851
- init_issues2();
200852
- init_query_helpers();
200853
- init_sdk_boundary();
200854
- init_update_guards();
200855
- init_huly_plugins();
200856
- init_markup();
200857
- NOT_FOUND_INDEX2 = -1;
200858
- findTemplateByIdOrTitle = (client, projectId, templateIdOrTitle) => Effect_exports.gen(function* () {
200859
- const template = (yield* client.findOne(tracker.class.IssueTemplate, {
200860
- space: projectId,
200861
- _id: toRef(templateIdOrTitle)
200862
- })) ?? (yield* client.findOne(tracker.class.IssueTemplate, {
200863
- space: projectId,
200864
- title: templateIdOrTitle
200865
- }));
200866
- return template;
200867
- });
200868
- findProjectAndTemplate = (params2) => Effect_exports.gen(function* () {
200869
- const { client, project } = yield* findProject(params2.project);
200870
- const template = yield* findTemplateByIdOrTitle(client, project._id, params2.template);
200871
- if (template === void 0) {
200872
- return yield* new IssueTemplateNotFoundError({ identifier: params2.template, project: params2.project });
200873
- }
200874
- return { client, project, template };
200875
- });
200876
- resolveTemplateReferenceLabels = (client, assignee, component) => Effect_exports.gen(function* () {
200877
- const assigneeName = assignee === null ? void 0 : (yield* client.findOne(contact.class.Person, hulyQuery({ _id: assignee })))?.name;
200878
- const componentLabel = component === null ? void 0 : (yield* client.findOne(tracker.class.Component, hulyQuery({ _id: component })))?.label;
200879
- return {
200880
- ...assigneeName === void 0 ? {} : { assigneeName },
200881
- ...componentLabel === void 0 ? {} : { componentLabel }
200882
- };
200883
- });
200884
- templateChildProjection = (child, description, labels) => {
200885
- const rawEstimation = zeroAsUnset(NonNegativeNumber.make(child.estimation));
200886
- const estimation = rawEstimation === void 0 ? void 0 : PositiveTimeHours.make(rawEstimation);
200887
- return {
200888
- id: IssueTemplateChildId.make(child.id),
200889
- title: child.title,
200890
- priority: priorityToString(child.priority),
200891
- ...description === void 0 ? {} : { description },
200892
- ...labels.assigneeName === void 0 ? {} : { assignee: PersonName.make(labels.assigneeName) },
200893
- ...labels.componentLabel === void 0 ? {} : { component: ComponentLabel.make(labels.componentLabel) },
200894
- ...estimation === void 0 ? {} : { estimation }
200895
- };
200896
- };
200897
- resolveChild = (client, markupUrlConfig, child) => Effect_exports.gen(function* () {
200898
- const labels = yield* resolveTemplateReferenceLabels(client, child.assignee, child.component);
200899
- const description = child.description ? yield* optionalMarkupToMarkdown(child.description, markupUrlConfig, "", {
200900
- operation: "getIssueTemplate",
200901
- entity: "issue template child description"
200902
- }) : void 0;
200903
- return templateChildProjection(child, description, labels);
200904
- });
200905
- buildTemplateChild = (client, markupUrlConfig, projectId, projectIdentifier, input) => Effect_exports.gen(function* () {
200906
- const assigneeParam = input.assignee;
200907
- const assigneeRef = assigneeParam !== void 0 ? yield* Effect_exports.gen(function* () {
200908
- const person = yield* findPersonByEmailOrName(client, assigneeParam);
200909
- if (person === void 0) {
200910
- return yield* new PersonNotFoundError({ identifier: assigneeParam });
200911
- }
200912
- return person._id;
200913
- }) : null;
200914
- const componentParam = input.component;
200915
- const componentRef = componentParam !== void 0 ? yield* Effect_exports.gen(function* () {
200916
- const component = yield* findComponentByIdOrLabel(client, projectId, componentParam);
200917
- if (component === void 0) {
200918
- return yield* new ComponentNotFoundError({ identifier: componentParam, project: projectIdentifier });
200919
- }
200920
- return component._id;
200921
- }) : null;
200922
- return {
200923
- id: (0, import_core90.generateId)(),
200924
- title: input.title,
200925
- description: optionalMarkdownToMarkup(input.description, markupUrlConfig, ""),
200926
- priority: stringToPriority(input.priority ?? DEFAULT_ISSUE_PRIORITY),
200927
- assignee: assigneeRef,
200928
- component: componentRef,
200929
- estimation: input.estimation ?? 0
200930
- };
200931
- });
200932
- listIssueTemplates = (params2) => Effect_exports.gen(function* () {
200933
- const { client, project } = yield* findProject(params2.project);
200934
- const limit = clampLimit(params2.limit);
200935
- const templates2 = yield* client.findAll(
200936
- tracker.class.IssueTemplate,
200937
- { space: project._id },
200938
- { limit, sort: { modifiedOn: import_core90.SortingOrder.Descending } }
200939
- );
200940
- const summaries = templates2.map((t) => {
200941
- const base2 = {
200942
- id: IssueTemplateId.make(t._id),
200943
- title: t.title,
200944
- priority: priorityToString(t.priority),
200945
- modifiedOn: Timestamp.make(t.modifiedOn)
200946
- };
200947
- if (t.children.length > 0) {
200948
- return { ...base2, childrenCount: Count.make(t.children.length) };
200949
- }
200950
- return base2;
200951
- });
200952
- return summaries;
200953
- });
200954
- getIssueTemplate = (params2) => Effect_exports.gen(function* () {
200955
- const { client, template } = yield* findProjectAndTemplate(params2);
200956
- const markupUrlConfig = client.markupUrlConfig;
200957
- const labels = yield* resolveTemplateReferenceLabels(client, template.assignee, template.component);
200958
- const description = yield* optionalMarkupToMarkdown(template.description, markupUrlConfig, "", {
200959
- operation: "getIssueTemplate",
200960
- entity: "issue template description"
200961
- });
200962
- const resolvedChildren = [];
200963
- for (const child of template.children) {
200964
- resolvedChildren.push(yield* resolveChild(client, markupUrlConfig, child));
200965
- }
200966
- const result3 = {
200967
- id: IssueTemplateId.make(template._id),
200968
- title: template.title,
200969
- description,
200970
- priority: priorityToString(template.priority),
200971
- assignee: labels.assigneeName !== void 0 ? PersonName.make(labels.assigneeName) : void 0,
200972
- component: labels.componentLabel !== void 0 ? ComponentLabel.make(labels.componentLabel) : void 0,
200973
- estimation: template.estimation > 0 ? PositiveTimeHours.make(template.estimation) : void 0,
200974
- project: params2.project,
200975
- modifiedOn: Timestamp.make(template.modifiedOn),
200976
- createdOn: template.createdOn === void 0 ? void 0 : Timestamp.make(template.createdOn)
200977
- };
200978
- if (resolvedChildren.length > 0) {
200979
- return { ...result3, children: resolvedChildren };
200980
- }
200981
- return result3;
200982
- });
200983
- createIssueTemplate = (params2) => Effect_exports.gen(function* () {
200984
- const { client, project } = yield* findProject(params2.project);
200985
- const markupUrlConfig = client.markupUrlConfig;
200986
- const templateId = (0, import_core90.generateId)();
200987
- const assigneeParam = params2.assignee;
200988
- const assigneeRef = assigneeParam !== void 0 ? yield* Effect_exports.gen(function* () {
200989
- const person = yield* findPersonByEmailOrName(client, assigneeParam);
200990
- if (person === void 0) {
200991
- return yield* new PersonNotFoundError({ identifier: assigneeParam });
200992
- }
200993
- return person._id;
200994
- }) : null;
200995
- const componentParam = params2.component;
200996
- const componentRef = componentParam !== void 0 ? yield* Effect_exports.gen(function* () {
200997
- const component = yield* findComponentByIdOrLabel(client, project._id, componentParam);
200998
- if (component === void 0) {
200999
- return yield* new ComponentNotFoundError({ identifier: componentParam, project: params2.project });
201000
- }
201001
- return component._id;
201002
- }) : null;
201003
- const priority = stringToPriority(params2.priority ?? DEFAULT_ISSUE_PRIORITY);
201004
- const children = [];
201005
- if (params2.children !== void 0) {
201006
- for (const childInput of params2.children) {
201007
- children.push(yield* buildTemplateChild(client, markupUrlConfig, project._id, params2.project, childInput));
201008
- }
201009
- }
201010
- const templateData = {
201011
- title: params2.title,
201012
- description: optionalMarkdownToMarkup(params2.description, markupUrlConfig, ""),
201013
- priority,
201014
- assignee: assigneeRef,
201015
- component: componentRef,
201016
- estimation: params2.estimation ?? 0,
201017
- children,
201018
- comments: 0
201019
- };
201020
- yield* client.createDoc(tracker.class.IssueTemplate, project._id, templateData, templateId);
201021
- return { id: IssueTemplateId.make(templateId), title: params2.title };
201022
- });
201023
- resolveIssueFromTemplateAssignee = (client, params2, template) => Effect_exports.gen(function* () {
201024
- if (params2.assignee !== void 0) return params2.assignee;
201025
- if (template.assignee === null) return void 0;
201026
- const person = yield* client.findOne(contact.class.Person, hulyQuery({ _id: template.assignee }));
201027
- if (person === void 0) return void 0;
201028
- const emailChannel = yield* client.findOne(
201029
- contact.class.Channel,
201030
- hulyQuery({ attachedTo: person._id, provider: contact.channelProvider.Email })
201031
- );
201032
- return Email.make(emailChannel?.value ?? person.name);
201033
- });
201034
- templateChildCreateParams = (params2, child, markupUrlConfig) => optionalMarkupToMarkdown(child.description, markupUrlConfig, void 0, {
201035
- operation: "createIssueFromTemplate",
201036
- entity: "issue template child description"
201037
- }).pipe(
201038
- Effect_exports.map(
201039
- (description) => ({
201040
- project: params2.project,
201041
- title: child.title,
201042
- priority: priorityToString(child.priority),
201043
- ...description === void 0 ? {} : { description }
201044
- })
201045
- )
201046
- );
201047
- templateChildUpdate = (child) => ({
201048
- ...child.assignee === null ? {} : { assignee: child.assignee },
201049
- ...child.component === null ? {} : { component: child.component },
201050
- ...child.estimation > 0 ? { estimation: child.estimation } : {}
201051
- });
201052
- createTemplateChildIssues = (client, project, template, params2, parentResult, title, markupUrlConfig) => Effect_exports.gen(function* () {
201053
- const parentIssue = {
201054
- _id: toRef(parentResult.issueId),
201055
- identifier: parentResult.identifier,
201056
- title,
201057
- parents: []
201058
- };
201059
- for (const child of template.children) {
201060
- const childParams = yield* templateChildCreateParams(params2, child, markupUrlConfig);
201061
- const childResult = yield* createIssue(childParams);
201062
- yield* attachIssueChild(
201063
- client,
201064
- project._id,
201065
- toRef(childResult.issueId),
201066
- parentIssue,
201067
- templateChildUpdate(child)
201068
- );
201069
- }
201070
- });
201071
- createIssueFromTemplate = (params2) => Effect_exports.gen(function* () {
201072
- const { client, project, template } = yield* findProjectAndTemplate(params2);
201073
- const markupUrlConfig = client.markupUrlConfig;
201074
- const title = params2.title ?? template.title;
201075
- const description = params2.description ?? (yield* optionalMarkupToMarkdown(template.description, markupUrlConfig, void 0, {
201076
- operation: "createIssueFromTemplate",
201077
- entity: "issue template description"
201078
- }));
201079
- const priority = params2.priority ?? priorityToString(template.priority);
201080
- const assignee = yield* resolveIssueFromTemplateAssignee(client, params2, template);
201081
- const issueParams = {
201082
- project: params2.project,
201083
- title,
201084
- description,
201085
- priority,
201086
- assignee,
201087
- status: params2.status
201088
- };
201089
- const result3 = yield* createIssue(issueParams);
201090
- if (template.component !== null) {
201091
- yield* client.updateDoc(tracker.class.Issue, project._id, toRef(result3.issueId), {
201092
- component: template.component
201093
- });
201094
- }
201095
- const includeChildren = params2.includeChildren ?? DEFAULT_INCLUDE_TEMPLATE_CHILDREN;
201096
- if (includeChildren && template.children.length > 0) {
201097
- yield* createTemplateChildIssues(client, project, template, params2, result3, title, markupUrlConfig);
201098
- return { ...result3, childrenCreated: Count.make(template.children.length) };
201099
- }
201100
- return result3;
201101
- });
201102
- updateIssueTemplate = (params2) => Effect_exports.gen(function* () {
201103
- yield* requireUpdateFields("update_issue_template", params2, UPDATE_ISSUE_TEMPLATE_FIELDS);
201104
- const { client, project, template } = yield* findProjectAndTemplate(params2);
201105
- const markupUrlConfig = client.markupUrlConfig;
201106
- const updateEntries = {
201107
- title: Effect_exports.succeed(params2.title === void 0 ? {} : { title: params2.title }),
201108
- description: Effect_exports.succeed(
201109
- params2.description === void 0 ? {} : { description: optionalMarkdownToMarkup(clearTextAsEmptyString(params2.description), markupUrlConfig, "") }
201110
- ),
201111
- priority: Effect_exports.succeed(params2.priority === void 0 ? {} : { priority: stringToPriority(params2.priority) }),
201112
- assignee: Effect_exports.gen(function* () {
201113
- if (params2.assignee === void 0) return {};
201114
- if (params2.assignee === null) return { assignee: null };
201115
- const person = yield* findPersonByEmailOrName(client, params2.assignee);
201116
- if (person === void 0) {
201117
- return yield* new PersonNotFoundError({ identifier: params2.assignee });
201118
- }
201119
- return { assignee: person._id };
201120
- }),
201121
- component: Effect_exports.gen(function* () {
201122
- if (params2.component === void 0) return {};
201123
- if (params2.component === null) return { component: null };
201124
- const component = yield* findComponentByIdOrLabel(client, project._id, params2.component);
201125
- if (component === void 0) {
201126
- return yield* new ComponentNotFoundError({ identifier: params2.component, project: params2.project });
201127
- }
201128
- return { component: component._id };
201129
- }),
201130
- estimation: Effect_exports.succeed(
201131
- params2.estimation === void 0 ? {} : { estimation: params2.estimation === null ? 0 : params2.estimation }
201132
- )
201133
- };
201134
- const updateOps = mergeUpdateEntries(
201135
- yield* Effect_exports.all(Object.values(updateEntries))
201136
- );
201137
- yield* client.updateDoc(tracker.class.IssueTemplate, project._id, template._id, updateOps);
201138
- return { id: IssueTemplateId.make(template._id), updated: true };
201139
- });
201140
- deleteIssueTemplate = (params2) => Effect_exports.gen(function* () {
201141
- const { client, project, template } = yield* findProjectAndTemplate(params2);
201142
- yield* client.removeDoc(tracker.class.IssueTemplate, project._id, template._id);
201143
- return { id: IssueTemplateId.make(template._id), deleted: true };
201144
- });
201145
- addTemplateChild = (params2) => Effect_exports.gen(function* () {
201146
- const { client, project, template } = yield* findProjectAndTemplate(params2);
201147
- const markupUrlConfig = client.markupUrlConfig;
201148
- const child = yield* buildTemplateChild(client, markupUrlConfig, project._id, params2.project, {
201149
- title: params2.title,
201150
- description: params2.description,
201151
- priority: params2.priority,
201152
- assignee: params2.assignee,
201153
- component: params2.component,
201154
- estimation: params2.estimation
201155
- });
201156
- const newChildren = [...template.children, child];
201157
- yield* client.updateDoc(tracker.class.IssueTemplate, project._id, template._id, { children: newChildren });
201158
- return { id: IssueTemplateChildId.make(child.id), title: child.title, added: true };
201159
- });
201160
- removeTemplateChild = (params2) => Effect_exports.gen(function* () {
201161
- const { client, project, template } = yield* findProjectAndTemplate(params2);
201162
- const childIndex = template.children.findIndex((c) => String(c.id) === String(params2.childId));
201163
- if (childIndex === NOT_FOUND_INDEX2) {
201164
- return yield* new TemplateChildNotFoundError({
201165
- childId: params2.childId,
201166
- template: params2.template,
201167
- project: params2.project
201168
- });
201169
- }
201170
- const removedChild = assertAt(template.children, childIndex);
201171
- const newChildren = template.children.filter((_, i) => i !== childIndex);
201172
- yield* client.updateDoc(tracker.class.IssueTemplate, project._id, template._id, { children: newChildren });
201173
- return { id: IssueTemplateChildId.make(removedChild.id), title: removedChild.title, removed: true };
201174
- });
201175
- }
201176
- });
201177
-
201178
201307
  // src/huly/operations/tags.ts
201179
201308
  var import_core91, toTagSummary, buildUpdateTagOperations, listTags, createTag, updateTag, deleteTag, listAttachedTags, attachTag, detachTag;
201180
201309
  var init_tags2 = __esm({
@@ -201464,7 +201593,7 @@ var init_issues3 = __esm({
201464
201593
  name: "list_issues",
201465
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(
201466
201595
  StatusCategoryValues
201467
- )}), 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.`,
201468
201597
  category: CATEGORY24,
201469
201598
  inputSchema: listIssuesParamsJsonSchema,
201470
201599
  resultSchema: ListIssuesResultSchema
@@ -201486,7 +201615,7 @@ var init_issues3 = __esm({
201486
201615
  defineTool(
201487
201616
  {
201488
201617
  name: "create_issue",
201489
- 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.",
201490
201619
  category: CATEGORY24,
201491
201620
  inputSchema: createIssueParamsJsonSchema,
201492
201621
  resultSchema: CreateIssueResultSchema
@@ -201497,7 +201626,7 @@ var init_issues3 = __esm({
201497
201626
  defineTool(
201498
201627
  {
201499
201628
  name: "update_issue",
201500
- 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.",
201501
201630
  category: CATEGORY24,
201502
201631
  inputSchema: updateIssueParamsJsonSchema,
201503
201632
  resultSchema: UpdateIssueResultSchema
@@ -223136,7 +223265,7 @@ if (unsupportedRuntime) {
223136
223265
  detectedNodeVersion: process.versions.node,
223137
223266
  executable: process.execPath,
223138
223267
  requiredNodeVersion: nodeEngineRequirement,
223139
- serverVersion: "0.49.6"
223268
+ serverVersion: "0.50.0"
223140
223269
  });
223141
223270
  startUnsupportedNodeMcp(config2);
223142
223271
  } else {