lancer-shared 1.2.329 → 1.2.331

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.
@@ -18,8 +18,8 @@ const ROOM_CRM_STATUS_ORDER = [
18
18
  const ROOM_CRM_STATUS_LABELS = {
19
19
  new: 'New',
20
20
  follow_up: 'Follow Up',
21
- qualified: 'Qualified',
22
- won: 'Won',
21
+ qualified: 'Negotiating',
22
+ won: 'Active Contract',
23
23
  archived: 'Archived',
24
24
  };
25
25
  const DEFAULT_ROOM_CRM_STATUS = 'new';
@@ -76,6 +76,20 @@ const normalizeRoomCrmStatuses = (statuses) => {
76
76
  .map((status) => normalizeListStatus(status))
77
77
  .filter((status) => status !== null)));
78
78
  };
79
+ const ROOM_CRM_ARCHIVED_REASON_ORDER = [
80
+ 'completed',
81
+ 'not_fit',
82
+ 'lost',
83
+ 'no_response',
84
+ 'other',
85
+ ];
86
+ const ROOM_CRM_ARCHIVED_REASON_LABELS = {
87
+ completed: 'Completed',
88
+ not_fit: 'Not fit',
89
+ lost: 'Lost',
90
+ no_response: 'No response',
91
+ other: 'Other',
92
+ };
79
93
 
80
94
  const defaultQuestions = [
81
95
  {
@@ -7826,6 +7840,7 @@ const SearchFieldsSchema = z.object({
7826
7840
  exactPhrase: z.string().default(''),
7827
7841
  titleSearch: z.string().default(''), // AND logic for titles
7828
7842
  titleAny: z.string().default(''), // OR logic for titles
7843
+ titleNoneAny: z.string().default(''), // NOT logic for titles
7829
7844
  skillsSearch: z.string().default(''),
7830
7845
  });
7831
7846
  class SearchQueryBuilder {
@@ -7897,6 +7912,14 @@ class SearchQueryBuilder {
7897
7912
  parts.push(`(${titleParts.join(' OR ')})`);
7898
7913
  }
7899
7914
  }
7915
+ if (validatedFields.titleNoneAny.trim()) {
7916
+ const titleTerms = this.splitTerms(validatedFields.titleNoneAny);
7917
+ const titleNotParts = titleTerms.map((term) => {
7918
+ const isQuoted = term.startsWith('"') && term.endsWith('"');
7919
+ return isQuoted ? `NOT title:${term}` : `NOT title:"${term}"`;
7920
+ });
7921
+ parts.push(...titleNotParts);
7922
+ }
7900
7923
  if (validatedFields.skillsSearch.trim()) {
7901
7924
  const skillsTerms = this.splitTerms(validatedFields.skillsSearch);
7902
7925
  if (skillsTerms.length === 1) {
@@ -7932,6 +7955,8 @@ class SearchQueryBuilder {
7932
7955
  descriptions.push(`Title (all): ${validatedFields.titleSearch}`);
7933
7956
  if (validatedFields.titleAny)
7934
7957
  descriptions.push(`Title (any): ${validatedFields.titleAny}`);
7958
+ if (validatedFields.titleNoneAny)
7959
+ descriptions.push(`Title (excluding any): ${validatedFields.titleNoneAny}`);
7935
7960
  if (validatedFields.skillsSearch)
7936
7961
  descriptions.push(`Skills: ${validatedFields.skillsSearch}`);
7937
7962
  return descriptions.length > 0 ? descriptions.join(' • ') : 'All results';
@@ -7961,6 +7986,7 @@ class SearchQueryBuilder {
7961
7986
  exactPhrase: '',
7962
7987
  titleSearch: '',
7963
7988
  titleAny: '',
7989
+ titleNoneAny: '',
7964
7990
  skillsSearch: '',
7965
7991
  };
7966
7992
  if (!query || query.trim() === '*') {
@@ -7993,7 +8019,35 @@ class SearchQueryBuilder {
7993
8019
  // Remove the matched group from remaining query
7994
8020
  remainingQuery = remainingQuery.replace(match[0], '').trim();
7995
8021
  }
7996
- // 2. THEN: Extract individual title: and skills: patterns
8022
+ // 2. THEN: Extract NOT title groups like NOT (title:"a" OR title:"b")
8023
+ const titleNotGroupPattern = /NOT\s+\((title:"[^"]+"(?:\s+OR\s+title:"[^"]+")+?)\)/g;
8024
+ const titleNotGroupMatches = [...remainingQuery.matchAll(titleNotGroupPattern)];
8025
+ for (const match of titleNotGroupMatches) {
8026
+ const terms = match[1]
8027
+ .split(/\s+OR\s+/)
8028
+ .map((term) => term.replace(/^title:"([^"]+)"$/, '"$1"'))
8029
+ .filter(Boolean);
8030
+ result.titleNoneAny = result.titleNoneAny
8031
+ ? `${result.titleNoneAny} ${terms.join(' ')}`
8032
+ : terms.join(' ');
8033
+ remainingQuery = remainingQuery.replace(match[0], '').trim();
8034
+ }
8035
+ // 3. Extract individual NOT title: terms before generic title extraction
8036
+ const titleNotPattern = /NOT\s+title:("([^"]+)"|([^\s)]+))/g;
8037
+ const titleNotMatches = [...remainingQuery.matchAll(titleNotPattern)];
8038
+ if (titleNotMatches.length > 0) {
8039
+ const terms = titleNotMatches.map((match) => {
8040
+ if (match[2]) {
8041
+ return `"${match[2]}"`;
8042
+ }
8043
+ return match[3];
8044
+ });
8045
+ result.titleNoneAny = result.titleNoneAny
8046
+ ? `${result.titleNoneAny} ${terms.join(' ')}`
8047
+ : terms.join(' ');
8048
+ remainingQuery = remainingQuery.replace(titleNotPattern, '').trim();
8049
+ }
8050
+ // 4. THEN: Extract individual title: and skills: patterns
7997
8051
  const fieldPatterns = [
7998
8052
  { field: 'titleSearch', pattern: /title:("([^"]+)"|([^\s)]+))/g },
7999
8053
  { field: 'skillsSearch', pattern: /skills:("([^"]+)"|([^\s)]+))/g },
@@ -8018,7 +8072,7 @@ class SearchQueryBuilder {
8018
8072
  remainingQuery = remainingQuery.replace(pattern, '').trim();
8019
8073
  }
8020
8074
  }
8021
- // 3. Handle legacy grouped field searches like title:(term1 AND term2)
8075
+ // 5. Handle legacy grouped field searches like title:(term1 AND term2)
8022
8076
  const groupedFieldPattern = /(title|skills):\(([^)]+)\)/g;
8023
8077
  let groupMatch;
8024
8078
  while ((groupMatch = groupedFieldPattern.exec(remainingQuery)) !== null) {
@@ -8046,7 +8100,7 @@ class SearchQueryBuilder {
8046
8100
  }
8047
8101
  remainingQuery = remainingQuery.replace(groupMatch[0], '').trim();
8048
8102
  }
8049
- // 4. Extract grouped NOT expressions: NOT (term1 OR term2 OR ...)
8103
+ // 6. Extract grouped NOT expressions: NOT (term1 OR term2 OR ...)
8050
8104
  const groupedNotPattern = /NOT\s+\(([^)]+(?:\s+OR\s+[^)]+)+)\)/g;
8051
8105
  const groupedNotMatches = [...remainingQuery.matchAll(groupedNotPattern)];
8052
8106
  if (groupedNotMatches.length > 0) {
@@ -8056,9 +8110,9 @@ class SearchQueryBuilder {
8056
8110
  .replace(groupedNotMatches[0][0], '')
8057
8111
  .trim();
8058
8112
  }
8059
- // 5. Extract individual NOT terms (only if no grouped NOT was found)
8113
+ // 7. Extract individual NOT terms (only if no grouped NOT was found)
8060
8114
  if (!result.noneWords) {
8061
- const notPattern = /NOT\s+("([^"]+)"|([^\s)]+))/g;
8115
+ const notPattern = /NOT\s+(?!title:)("([^"]+)"|([^\s)]+))/g;
8062
8116
  const notMatches = [...remainingQuery.matchAll(notPattern)];
8063
8117
  if (notMatches.length > 0) {
8064
8118
  const noneTerms = notMatches.map((match) => {
@@ -8071,7 +8125,7 @@ class SearchQueryBuilder {
8071
8125
  remainingQuery = remainingQuery.replace(notPattern, '').trim();
8072
8126
  }
8073
8127
  }
8074
- // 6. Process grouped expressions - DON'T clean up connectors first!
8128
+ // 8. Process grouped expressions - DON'T clean up connectors first!
8075
8129
  // Extract OR groups (anyWords) - PROCESS FIRST
8076
8130
  const orGroupPattern = /\(([^)]+(?:\s+OR\s+[^)]+)+)\)/g;
8077
8131
  const orMatches = [...remainingQuery.matchAll(orGroupPattern)];
@@ -8090,14 +8144,14 @@ class SearchQueryBuilder {
8090
8144
  }
8091
8145
  // NOW clean up connectors after group processing
8092
8146
  remainingQuery = this.cleanupConnectors(remainingQuery);
8093
- // 7. Extract standalone quoted phrases (exactPhrase) - ONLY after all groups processed
8147
+ // 9. Extract standalone quoted phrases (exactPhrase) - ONLY after all groups processed
8094
8148
  const standaloneQuotePattern = /(?:^|\s)("([^"]+)")(?=\s|$)/g;
8095
8149
  const quoteMatches = [...remainingQuery.matchAll(standaloneQuotePattern)];
8096
8150
  if (quoteMatches.length > 0) {
8097
8151
  result.exactPhrase = quoteMatches[0][2];
8098
8152
  remainingQuery = remainingQuery.replace(quoteMatches[0][1], '').trim();
8099
8153
  }
8100
- // 8. Handle remaining simple terms as allWords
8154
+ // 10. Handle remaining simple terms as allWords
8101
8155
  if (remainingQuery) {
8102
8156
  const remainingTerms = this.splitTermsWithQuotes(remainingQuery);
8103
8157
  if (remainingTerms.length > 0) {
@@ -8845,6 +8899,13 @@ const roomCrmStatusEnum = z.enum([
8845
8899
  'won',
8846
8900
  'archived',
8847
8901
  ]);
8902
+ const roomCrmArchivedReasonEnum = z.enum([
8903
+ 'completed',
8904
+ 'not_fit',
8905
+ 'lost',
8906
+ 'no_response',
8907
+ 'other',
8908
+ ]);
8848
8909
  const roomJobClientHistorySchema = z.object({
8849
8910
  jobUrl: z.string().nullable(),
8850
8911
  title: z.string().nullable(),
@@ -8886,6 +8947,7 @@ const roomSchema = z.object({
8886
8947
  roomNote: roomNoteSchema.optional(),
8887
8948
  crmStatus: roomCrmStatusEnum.optional(),
8888
8949
  crmStatusUpdatedAt: z.number().optional(),
8950
+ crmArchivedReason: roomCrmArchivedReasonEnum.optional().nullable(),
8889
8951
  jobClientHistory: roomJobClientHistorySchema.optional(),
8890
8952
  });
8891
8953
  const roomsMetadataSchema = z.object({
@@ -8934,6 +8996,7 @@ const updateRoomNotesRequestBodySchema = z.object({
8934
8996
  });
8935
8997
  const updateRoomCrmStatusRequestBodySchema = z.object({
8936
8998
  status: roomCrmStatusEnum,
8999
+ archivedReason: roomCrmArchivedReasonEnum.optional(),
8937
9000
  });
8938
9001
  const sendMessageRequestSchema = z.object({
8939
9002
  message: z.string(),
@@ -24627,6 +24690,8 @@ exports.ProposalGenerationFailedException = ProposalGenerationFailedException;
24627
24690
  exports.ProposalSubmitFailedException = ProposalSubmitFailedException;
24628
24691
  exports.PuppeteerConnectionErrorException = PuppeteerConnectionErrorException;
24629
24692
  exports.QuestionPairNotMatchingException = QuestionPairNotMatchingException;
24693
+ exports.ROOM_CRM_ARCHIVED_REASON_LABELS = ROOM_CRM_ARCHIVED_REASON_LABELS;
24694
+ exports.ROOM_CRM_ARCHIVED_REASON_ORDER = ROOM_CRM_ARCHIVED_REASON_ORDER;
24630
24695
  exports.ROOM_CRM_KANBAN_STATUS_ORDER = ROOM_CRM_KANBAN_STATUS_ORDER;
24631
24696
  exports.ROOM_CRM_STATUS_BY_ID = ROOM_CRM_STATUS_BY_ID;
24632
24697
  exports.ROOM_CRM_STATUS_IDS = ROOM_CRM_STATUS_IDS;
@@ -24955,6 +25020,7 @@ exports.regionSchema = regionSchema;
24955
25020
  exports.registerSchema = registerSchema;
24956
25021
  exports.requiredEarningsEnum = requiredEarningsEnum;
24957
25022
  exports.requiredJSSEnum = requiredJSSEnum;
25023
+ exports.roomCrmArchivedReasonEnum = roomCrmArchivedReasonEnum;
24958
25024
  exports.roomCrmStatusEnum = roomCrmStatusEnum;
24959
25025
  exports.roomJobClientHistorySchema = roomJobClientHistorySchema;
24960
25026
  exports.roomMessageSchema = roomMessageSchema;