@zodic/shared 0.0.306 → 0.0.308

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.
@@ -312,44 +312,8 @@ export class ArchetypeService {
312
312
  return;
313
313
  }
314
314
 
315
- let blocks: string[] = [];
316
- let ptBlocks: string[] = [];
317
-
318
- try {
319
- blocks = response
320
- .split('-EN')[1]
321
- .split('-PT')[0]
322
- .trim()
323
- .split(/\n\d\.\s*\n?/)
324
- .filter(Boolean);
325
-
326
- ptBlocks = response
327
- .split('-PT')[1]
328
- .trim()
329
- .split(/\n\d\.\s*\n?/)
330
- .filter(Boolean);
331
- } catch (err) {
332
- console.error(`❌ [Single] Parsing failed for ${combination}`, err);
333
- await db.insert(schema.archetypeNameDumps).values({
334
- id: combination,
335
- combination,
336
- rawText: response,
337
- parsedSuccessfully: 0,
338
- createdAt: Date.now(),
339
- });
340
- return;
341
- }
342
-
343
- const englishNames = blocks.map((block) => ({
344
- name: block.match(/• Name:\s*(.+)/)?.[1]?.trim() || '',
345
- essenceLine: block.match(/• Essence:\s*(.+)/)?.[1]?.trim() || '',
346
- }));
347
-
348
- const portugueseVariants = ptBlocks.map((block) => ({
349
- masc: block.match(/• Masculino:\s*(.+)/)?.[1]?.trim() || '',
350
- fem: block.match(/• Feminino:\s*(.+)/)?.[1]?.trim() || '',
351
- essenceLine: block.match(/• Essência:\s*(.+)/)?.[1]?.trim() || '',
352
- }));
315
+ const { english: englishNames, portuguese: portugueseVariants } =
316
+ this.parseArchetypeNameBlocks(response);
353
317
 
354
318
  async function isEnglishNameDuplicate(name: string): Promise<boolean> {
355
319
  const result = await db
@@ -483,39 +447,7 @@ export class ArchetypeService {
483
447
  const block = blocks[i];
484
448
  console.log(`📦 [Batch] Processing: ${combination}`);
485
449
 
486
- let en = '';
487
- let pt = '';
488
- try {
489
- en = block.split('-EN')[1].split('-PT')[0].trim();
490
- pt = block.split('-PT')[1].trim();
491
- } catch (err) {
492
- console.error(`❌ [Batch] Parsing failed for: ${combination}`, err);
493
- await db.insert(schema.archetypeNameDumps).values({
494
- id: combination,
495
- combination,
496
- rawText: block,
497
- parsedSuccessfully: 0,
498
- createdAt: Date.now(),
499
- });
500
- continue;
501
- }
502
-
503
- const english = en
504
- .split(/\n\d\.\s*\n?/)
505
- .filter(Boolean)
506
- .map((line) => ({
507
- name: line.match(/• Name:\s*(.+)/)?.[1]?.trim() || '',
508
- essenceLine: line.match(/• Essence:\s*(.+)/)?.[1]?.trim() || '',
509
- }));
510
-
511
- const portuguese = pt
512
- .split(/\n\d\.\s*\n?/)
513
- .filter(Boolean)
514
- .map((line) => ({
515
- masc: line.match(/• Masculino:\s*(.+)/)?.[1]?.trim() || '',
516
- fem: line.match(/• Feminino:\s*(.+)/)?.[1]?.trim() || '',
517
- essenceLine: line.match(/• Essência:\s*(.+)/)?.[1]?.trim() || '',
518
- }));
450
+ const { english, portuguese } = this.parseArchetypeNameBlocks(block);
519
451
 
520
452
  for (let j = 0; j < 3; j++) {
521
453
  const index = (j + 1).toString();
@@ -678,7 +610,12 @@ export class ArchetypeService {
678
610
  return;
679
611
  }
680
612
 
681
- const blocks = response
613
+ // Clean up the response by removing unexpected suffixes
614
+ const cleanedResponse = response
615
+ .replace(/###|---\s*###|-\s*###/g, '')
616
+ .trim();
617
+
618
+ const blocks = cleanedResponse
682
619
  .split(/Composition \d+/)
683
620
  .slice(1)
684
621
  .map((b) => b.trim());
@@ -691,13 +628,13 @@ export class ArchetypeService {
691
628
 
692
629
  console.log(`🔄 [Batch] Processing: ${combination}`);
693
630
 
694
- let en = '';
695
- let pt = '';
696
- try {
697
- en = block.split('-EN')[1].split('-PT')[0].trim();
698
- pt = block.split('-PT')[1].trim();
699
- } catch (err) {
700
- console.error(`❌ [Batch] Parsing failed for: ${combination}`, err);
631
+ const { english, portuguese } = this.parseArchetypeNameBlocks(block);
632
+
633
+ if (
634
+ english.length !== indexes.length ||
635
+ portuguese.length !== indexes.length
636
+ ) {
637
+ console.error(`❌ [Batch] Parsing failed for: ${combination}`);
701
638
  await this.context
702
639
  .drizzle()
703
640
  .insert(schema.archetypeNameDumps)
@@ -711,37 +648,27 @@ export class ArchetypeService {
711
648
  continue;
712
649
  }
713
650
 
714
- const english = en
715
- .split(/\n\d\.\s*\n?/)
716
- .filter(Boolean)
717
- .map((line) => ({
718
- name: line.match(/• Name:\s*(.+)/)?.[1]?.trim() || '',
719
- essenceLine: line.match(/• Essence:\s*(.+)/)?.[1]?.trim() || '',
720
- }));
721
-
722
- const portuguese = pt
723
- .split(/\n\d\.\s*\n?/)
724
- .filter(Boolean)
725
- .map((line) => ({
726
- masc: line.match(/• Masculino:\s*(.+)/)?.[1]?.trim() || '',
727
- fem: line.match(/• Feminino:\s*(.+)/)?.[1]?.trim() || '',
728
- essenceLine: line.match(/• Essência:\s*(.+)/)?.[1]?.trim() || '',
729
- }));
730
-
731
651
  for (const index of indexes) {
732
- if (!english[index - 1] || !portuguese[index - 1]) {
733
- await this.context.drizzle().insert(schema.archetypeNameDumps).values({
734
- id: `${combination}:${index}:${Date.now()}`,
735
- combination,
736
- rawText: block,
737
- parsedSuccessfully: 0,
738
- createdAt: Date.now(),
739
- });
740
- console.warn(`⚠️ [Batch] Skipping index ${index} for ${combination} due to missing parsed block`);
652
+ const idx = index - 1;
653
+ const englishEntry = english[idx];
654
+ const ptEntry = portuguese[idx];
655
+
656
+ if (!englishEntry || !ptEntry) {
657
+ await this.context
658
+ .drizzle()
659
+ .insert(schema.archetypeNameDumps)
660
+ .values({
661
+ id: `${combination}:${index}:${Date.now()}`,
662
+ combination,
663
+ rawText: block,
664
+ parsedSuccessfully: 0,
665
+ createdAt: Date.now(),
666
+ });
667
+ console.warn(
668
+ `⚠️ [Batch] Skipping index ${index} for ${combination} due to missing parsed block`
669
+ );
741
670
  continue;
742
671
  }
743
- const englishEntry = english[index - 1];
744
- const ptEntry = portuguese[index - 1];
745
672
 
746
673
  for (const gender of ['male', 'female']) {
747
674
  const enId = `${combination}:${gender}:${index}`;
@@ -805,11 +732,13 @@ export class ArchetypeService {
805
732
  `🎉 [Batch] Completed regenerating ${compositions.length} combinations`
806
733
  );
807
734
  }
808
-
735
+
809
736
  async fetchMissingArchetypeCompositions(): Promise<Composition[]> {
810
737
  const db = this.context.drizzle();
811
738
  const incomplete = await this.findIncompleteCombinations();
812
- console.log(`🔎 [Fetch] Retrieved ${incomplete.length} incomplete combinations`);
739
+ console.log(
740
+ `🔎 [Fetch] Retrieved ${incomplete.length} incomplete combinations`
741
+ );
813
742
  const limited = incomplete.slice(0, 400);
814
743
 
815
744
  const compositions: Composition[] = [];
@@ -844,13 +773,92 @@ export class ArchetypeService {
844
773
  moon,
845
774
  indexesToGenerate,
846
775
  });
847
- console.log(`✅ [Fetch] Will regenerate indexes [${indexesToGenerate.join(', ')}] for ${combination}`);
776
+ console.log(
777
+ `✅ [Fetch] Will regenerate indexes [${indexesToGenerate.join(
778
+ ', '
779
+ )}] for ${combination}`
780
+ );
848
781
  }
849
782
  }
850
783
 
851
- console.log(`📦 [Fetch] Total compositions to regenerate (limited to 400): ${compositions.length}`);
852
-
853
-
784
+ console.log(
785
+ `📦 [Fetch] Total compositions to regenerate (limited to 400): ${compositions.length}`
786
+ );
787
+
854
788
  return compositions;
855
789
  }
790
+
791
+ private parseArchetypeNameBlocks(block: string): {
792
+ english: { name: string; essenceLine: string }[];
793
+ portuguese: { masc: string; fem: string; essenceLine: string }[];
794
+ } {
795
+ const result = {
796
+ english: [] as { name: string; essenceLine: string }[],
797
+ portuguese: [] as { masc: string; fem: string; essenceLine: string }[],
798
+ };
799
+
800
+ try {
801
+ // Normalize the block by replacing multiple spaces with a single space and ensuring newlines
802
+ const normalizedBlock = block
803
+ .replace(/\s+/g, ' ')
804
+ .replace(/-EN\s*/, '-EN\n')
805
+ .replace(/-PT\s*/, '\n-PT\n')
806
+ .trim();
807
+
808
+ // Split into EN and PT sections
809
+ const sections = normalizedBlock.split(/\n?-PT\n/);
810
+ const enSection = sections[0]?.replace(/-EN\n/, '').trim() ?? '';
811
+ const ptSection = sections[1]?.trim() ?? '';
812
+
813
+ // Parse English entries
814
+ result.english = enSection
815
+ .split(/\n?\d+\.\s*\n?/)
816
+ .filter(Boolean)
817
+ .map((entry, i) => {
818
+ const nameMatch = entry.match(/• Name:\s*([^•]+)/);
819
+ const essenceMatch = entry.match(/• Essence:\s*([^•]+)/);
820
+ const name = nameMatch?.[1]?.trim() ?? '';
821
+ const essenceLine = essenceMatch?.[1]?.trim() ?? '';
822
+ if (!name || !essenceLine) {
823
+ console.warn(
824
+ `⚠️ [Parse] Incomplete English entry ${i + 1}:`,
825
+ entry
826
+ );
827
+ }
828
+ return { name, essenceLine };
829
+ });
830
+
831
+ // Parse Portuguese entries
832
+ result.portuguese = ptSection
833
+ .split(/\n?\d+\.\s*\n?/)
834
+ .filter(Boolean)
835
+ .map((entry, i) => {
836
+ const mascMatch = entry.match(/• Masculino:\s*([^•]+)/);
837
+ const femMatch = entry.match(/• Feminino:\s*([^•]+)/);
838
+ const essenceMatch = entry.match(/• Essência:\s*([^•]+)/);
839
+ const masc = mascMatch?.[1]?.trim() ?? '';
840
+ const fem = femMatch?.[1]?.trim() ?? '';
841
+ const essenceLine = essenceMatch?.[1]?.trim() ?? '';
842
+ if (!masc || !fem || !essenceLine) {
843
+ console.warn(
844
+ `⚠️ [Parse] Incomplete Portuguese entry ${i + 1}:`,
845
+ entry
846
+ );
847
+ }
848
+ // Validate gender consistency
849
+ if (masc.startsWith('A ') && fem.startsWith('O ')) {
850
+ console.warn(
851
+ `⚠️ [Parse] Gender mismatch in Portuguese entry ${i + 1}:`,
852
+ entry
853
+ );
854
+ return { masc: fem, fem: masc, essenceLine }; // Swap to correct the mismatch
855
+ }
856
+ return { masc, fem, essenceLine };
857
+ });
858
+ } catch (error) {
859
+ console.error('❌ [Parse] Failed to parse block:', error);
860
+ }
861
+
862
+ return result;
863
+ }
856
864
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zodic/shared",
3
- "version": "0.0.306",
3
+ "version": "0.0.308",
4
4
  "module": "index.ts",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -211,6 +211,14 @@ For every composition, return:
211
211
  Avoid names that sound like objects, titles, or abstract forces (e.g., The Lantern, The Eclipse, The Veil).
212
212
  Instead, use names that suggest a personified being or living archetype, such as The Masked Oracle, The Starborn Seeker, or The Dancer of the Falling Sky.
213
213
 
214
+ **Formatting Rules**:
215
+ - Each composition block must start with "Composition <number>" on its own line.
216
+ - Within each composition block, the English section must start with "-EN" on its own line, followed by the entries.
217
+ - The Portuguese section must start with "-PT" on its own line, followed by the entries.
218
+ - Each entry (e.g., "1.", "2.", "3.") must be on its own line, with its sub-items (e.g., "• Name: ...", "• Masculino: ...") on separate lines.
219
+ - Do not include any extra characters, suffixes, or separators (e.g., "###", "---", or extra newlines) at the end of the response or between composition blocks.
220
+ - Ensure that Portuguese names correctly match the gender: "Masculino" names should use masculine forms (e.g., "O Sábio"), and "Feminino" names should use feminine forms (e.g., "A Sábia").
221
+
214
222
  Do not include any commentary or explanations outside the defined output structure. Only return the output block for each composition, exactly as described:`;
215
223
 
216
224
  const compositionBlocks = compositions.map((comp, i) => {
@@ -219,7 +227,7 @@ Do not include any commentary or explanations outside the defined output structu
219
227
  const moon = influenceMap.moon[comp.moon];
220
228
  const indexes = comp.indexesToGenerate ?? [1, 2, 3];
221
229
 
222
- const influences = `\n\n### Composition ${i + 1}
230
+ const influences = `\n\nComposition ${i + 1}
223
231
 
224
232
  • First Influence – ${sun.label}: ${sun.description}
225
233
  • Second Influence – ${asc.label}: ${asc.description}
@@ -228,28 +236,28 @@ Do not include any commentary or explanations outside the defined output structu
228
236
  const enLines = indexes
229
237
  .map(
230
238
  (idx) => `${idx}.
231
- • Name: [Name that emphasizes the ${
232
- ['first', 'second', 'third'][idx - 1]
233
- } influence, while blending the other two]
234
- • Essence: [Short poetic description line in English]`
239
+ • Name: [Name that emphasizes the ${
240
+ ['first', 'second', 'third'][idx - 1]
241
+ } influence, while blending the other two]
242
+ • Essence: [Short poetic description line in English]`
235
243
  )
236
244
  .join('\n');
237
245
 
238
246
  const ptLines = indexes
239
247
  .map(
240
248
  (idx) => `${idx}.
241
- • Masculino: [Portuguese name (masc)]
242
- • Feminino: [Portuguese name (fem)]
243
- • Essência: [Short poetic description line in Portuguese]`
249
+ • Masculino: [Portuguese name (masc)]
250
+ • Feminino: [Portuguese name (fem)]
251
+ • Essência: [Short poetic description line in Portuguese]`
244
252
  )
245
253
  .join('\n');
246
254
 
247
255
  return `${influences}
248
256
 
249
- \`\n-EN
257
+ \`\n-EN
250
258
  ${enLines}
251
259
 
252
- -PT
260
+ -PT
253
261
  ${ptLines}
254
262
  \``;
255
263
  });