@soleri/core 2.5.0 → 2.7.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 (84) hide show
  1. package/dist/brain/intelligence.d.ts +1 -0
  2. package/dist/brain/intelligence.d.ts.map +1 -1
  3. package/dist/brain/intelligence.js +160 -148
  4. package/dist/brain/intelligence.js.map +1 -1
  5. package/dist/control/identity-manager.d.ts +3 -1
  6. package/dist/control/identity-manager.d.ts.map +1 -1
  7. package/dist/control/identity-manager.js +53 -51
  8. package/dist/control/identity-manager.js.map +1 -1
  9. package/dist/control/intent-router.d.ts +1 -0
  10. package/dist/control/intent-router.d.ts.map +1 -1
  11. package/dist/control/intent-router.js +41 -32
  12. package/dist/control/intent-router.js.map +1 -1
  13. package/dist/curator/curator.d.ts +1 -0
  14. package/dist/curator/curator.d.ts.map +1 -1
  15. package/dist/curator/curator.js +58 -99
  16. package/dist/curator/curator.js.map +1 -1
  17. package/dist/facades/facade-factory.js +1 -1
  18. package/dist/facades/facade-factory.js.map +1 -1
  19. package/dist/governance/governance.d.ts +1 -0
  20. package/dist/governance/governance.d.ts.map +1 -1
  21. package/dist/governance/governance.js +51 -68
  22. package/dist/governance/governance.js.map +1 -1
  23. package/dist/index.d.ts +2 -1
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +1 -0
  26. package/dist/index.js.map +1 -1
  27. package/dist/persistence/index.d.ts +2 -1
  28. package/dist/persistence/index.d.ts.map +1 -1
  29. package/dist/persistence/index.js +1 -0
  30. package/dist/persistence/index.js.map +1 -1
  31. package/dist/persistence/postgres-provider.d.ts +46 -0
  32. package/dist/persistence/postgres-provider.d.ts.map +1 -0
  33. package/dist/persistence/postgres-provider.js +115 -0
  34. package/dist/persistence/postgres-provider.js.map +1 -0
  35. package/dist/persistence/sqlite-provider.d.ts +5 -2
  36. package/dist/persistence/sqlite-provider.d.ts.map +1 -1
  37. package/dist/persistence/sqlite-provider.js +37 -1
  38. package/dist/persistence/sqlite-provider.js.map +1 -1
  39. package/dist/persistence/types.d.ts +23 -1
  40. package/dist/persistence/types.d.ts.map +1 -1
  41. package/dist/project/project-registry.d.ts +4 -4
  42. package/dist/project/project-registry.d.ts.map +1 -1
  43. package/dist/project/project-registry.js +32 -50
  44. package/dist/project/project-registry.js.map +1 -1
  45. package/dist/runtime/admin-extra-ops.d.ts +3 -3
  46. package/dist/runtime/admin-extra-ops.d.ts.map +1 -1
  47. package/dist/runtime/admin-extra-ops.js +33 -3
  48. package/dist/runtime/admin-extra-ops.js.map +1 -1
  49. package/dist/runtime/core-ops.d.ts +4 -4
  50. package/dist/runtime/core-ops.js +4 -4
  51. package/dist/runtime/runtime.js +1 -1
  52. package/dist/runtime/runtime.js.map +1 -1
  53. package/dist/runtime/vault-extra-ops.d.ts +3 -2
  54. package/dist/runtime/vault-extra-ops.d.ts.map +1 -1
  55. package/dist/runtime/vault-extra-ops.js +40 -2
  56. package/dist/runtime/vault-extra-ops.js.map +1 -1
  57. package/dist/vault/vault.d.ts +21 -0
  58. package/dist/vault/vault.d.ts.map +1 -1
  59. package/dist/vault/vault.js +99 -0
  60. package/dist/vault/vault.js.map +1 -1
  61. package/package.json +4 -2
  62. package/src/__tests__/admin-extra-ops.test.ts +2 -2
  63. package/src/__tests__/core-ops.test.ts +8 -2
  64. package/src/__tests__/persistence.test.ts +66 -0
  65. package/src/__tests__/postgres-provider.test.ts +58 -0
  66. package/src/__tests__/vault-extra-ops.test.ts +2 -2
  67. package/src/__tests__/vault.test.ts +184 -0
  68. package/src/brain/intelligence.ts +258 -307
  69. package/src/control/identity-manager.ts +77 -75
  70. package/src/control/intent-router.ts +55 -57
  71. package/src/curator/curator.ts +124 -145
  72. package/src/facades/facade-factory.ts +1 -1
  73. package/src/governance/governance.ts +90 -107
  74. package/src/index.ts +2 -0
  75. package/src/persistence/index.ts +2 -0
  76. package/src/persistence/postgres-provider.ts +157 -0
  77. package/src/persistence/sqlite-provider.ts +55 -2
  78. package/src/persistence/types.ts +31 -1
  79. package/src/project/project-registry.ts +69 -74
  80. package/src/runtime/admin-extra-ops.ts +36 -3
  81. package/src/runtime/core-ops.ts +4 -4
  82. package/src/runtime/runtime.ts +1 -1
  83. package/src/runtime/vault-extra-ops.ts +42 -2
  84. package/src/vault/vault.ts +118 -0
@@ -0,0 +1,58 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { translateSql } from '../persistence/postgres-provider.js';
3
+ import { PostgresPersistenceProvider } from '../persistence/postgres-provider.js';
4
+
5
+ describe('translateSql', () => {
6
+ it('converts positional ? to $N', () => {
7
+ const result = translateSql('SELECT * FROM t WHERE a = ? AND b = ?', ['x', 'y']);
8
+ expect(result.sql).toBe('SELECT * FROM t WHERE a = $1 AND b = $2');
9
+ expect(result.values).toEqual(['x', 'y']);
10
+ });
11
+
12
+ it('converts named @params to $N', () => {
13
+ const result = translateSql('INSERT INTO t (a, b) VALUES (@name, @age)', {
14
+ name: 'Alice',
15
+ age: 30,
16
+ });
17
+ expect(result.sql).toBe('INSERT INTO t (a, b) VALUES ($1, $2)');
18
+ expect(result.values).toEqual(['Alice', 30]);
19
+ });
20
+
21
+ it('deduplicates repeated named params', () => {
22
+ const result = translateSql('SELECT * FROM t WHERE a = @x OR b = @x', { x: 42 });
23
+ expect(result.sql).toBe('SELECT * FROM t WHERE a = $1 OR b = $1');
24
+ expect(result.values).toEqual([42]);
25
+ });
26
+
27
+ it('replaces unixepoch()', () => {
28
+ const result = translateSql('INSERT INTO t (ts) VALUES (unixepoch())');
29
+ expect(result.sql).toBe('INSERT INTO t (ts) VALUES (EXTRACT(EPOCH FROM NOW())::integer)');
30
+ expect(result.values).toEqual([]);
31
+ });
32
+
33
+ it('handles no params', () => {
34
+ const result = translateSql('SELECT 1');
35
+ expect(result.sql).toBe('SELECT 1');
36
+ expect(result.values).toEqual([]);
37
+ });
38
+
39
+ it('handles mixed: ? params + unixepoch()', () => {
40
+ const result = translateSql('UPDATE t SET name = ?, updated_at = unixepoch() WHERE id = ?', [
41
+ 'Bob',
42
+ 'id-1',
43
+ ]);
44
+ expect(result.sql).toBe(
45
+ 'UPDATE t SET name = $1, updated_at = EXTRACT(EPOCH FROM NOW())::integer WHERE id = $2',
46
+ );
47
+ expect(result.values).toEqual(['Bob', 'id-1']);
48
+ });
49
+ });
50
+
51
+ describe('PostgresPersistenceProvider', () => {
52
+ it('backend returns postgres', () => {
53
+ // Access backend without connecting (class-level property)
54
+ // We can't instantiate without pg, so we test the translateSql export
55
+ // and verify the class exists with correct typing
56
+ expect(PostgresPersistenceProvider).toBeDefined();
57
+ });
58
+ });
@@ -47,8 +47,8 @@ describe('createVaultExtraOps', () => {
47
47
  return op;
48
48
  }
49
49
 
50
- it('should return 20 ops', () => {
51
- expect(ops.length).toBe(20);
50
+ it('should return 23 ops', () => {
51
+ expect(ops.length).toBe(23);
52
52
  });
53
53
 
54
54
  it('should have all expected op names', () => {
@@ -491,4 +491,188 @@ describe('Vault', () => {
491
491
  expect(stats.byProject).toEqual({ '/a': 2, '/b': 1 });
492
492
  });
493
493
  });
494
+
495
+ describe('Vault archival and optimization', () => {
496
+ it('archive moves old entries', () => {
497
+ const v = new Vault(':memory:');
498
+ v.seed([
499
+ {
500
+ id: 'old-1',
501
+ type: 'pattern',
502
+ domain: 'test',
503
+ title: 'Old Pattern',
504
+ severity: 'suggestion',
505
+ description: 'Old entry',
506
+ tags: ['test'],
507
+ },
508
+ ]);
509
+ // Manually set the updated_at to 200 days ago
510
+ v.getProvider().run('UPDATE entries SET updated_at = ? WHERE id = ?', [
511
+ Math.floor(Date.now() / 1000) - 200 * 86400,
512
+ 'old-1',
513
+ ]);
514
+ v.seed([
515
+ {
516
+ id: 'new-1',
517
+ type: 'pattern',
518
+ domain: 'test',
519
+ title: 'New Pattern',
520
+ severity: 'suggestion',
521
+ description: 'New entry',
522
+ tags: ['test'],
523
+ },
524
+ ]);
525
+
526
+ const result = v.archive({ olderThanDays: 90 });
527
+ expect(result.archived).toBe(1);
528
+ expect(v.get('old-1')).toBeNull();
529
+ expect(v.get('new-1')).not.toBeNull();
530
+ v.close();
531
+ });
532
+
533
+ it('archive respects olderThanDays', () => {
534
+ const v = new Vault(':memory:');
535
+ v.seed([
536
+ {
537
+ id: 'e1',
538
+ type: 'pattern',
539
+ domain: 'test',
540
+ title: 'Entry',
541
+ severity: 'suggestion',
542
+ description: 'Not old enough',
543
+ tags: ['test'],
544
+ },
545
+ ]);
546
+ // Entry is fresh (just created), archive with 1 day threshold
547
+ const result = v.archive({ olderThanDays: 1 });
548
+ expect(result.archived).toBe(0);
549
+ expect(v.get('e1')).not.toBeNull();
550
+ v.close();
551
+ });
552
+
553
+ it('archive returns 0 when no candidates', () => {
554
+ const v = new Vault(':memory:');
555
+ const result = v.archive({ olderThanDays: 30 });
556
+ expect(result.archived).toBe(0);
557
+ v.close();
558
+ });
559
+
560
+ it('archived entries excluded from search', () => {
561
+ const v = new Vault(':memory:');
562
+ v.seed([
563
+ {
564
+ id: 'search-1',
565
+ type: 'pattern',
566
+ domain: 'test',
567
+ title: 'Searchable Pattern',
568
+ severity: 'suggestion',
569
+ description: 'Should be archived',
570
+ tags: ['search'],
571
+ },
572
+ ]);
573
+ v.getProvider().run('UPDATE entries SET updated_at = ? WHERE id = ?', [
574
+ Math.floor(Date.now() / 1000) - 200 * 86400,
575
+ 'search-1',
576
+ ]);
577
+
578
+ // Before archive: should appear in search
579
+ const before = v.search('searchable');
580
+ expect(before.length).toBeGreaterThan(0);
581
+
582
+ v.archive({ olderThanDays: 90 });
583
+
584
+ // After archive: should not appear
585
+ const after = v.search('searchable');
586
+ expect(after.length).toBe(0);
587
+ v.close();
588
+ });
589
+
590
+ it('restore brings entry back', () => {
591
+ const v = new Vault(':memory:');
592
+ v.seed([
593
+ {
594
+ id: 'restore-1',
595
+ type: 'pattern',
596
+ domain: 'test',
597
+ title: 'Restore Me',
598
+ severity: 'suggestion',
599
+ description: 'Will be restored',
600
+ tags: ['test'],
601
+ },
602
+ ]);
603
+ v.getProvider().run('UPDATE entries SET updated_at = ? WHERE id = ?', [
604
+ Math.floor(Date.now() / 1000) - 200 * 86400,
605
+ 'restore-1',
606
+ ]);
607
+ v.archive({ olderThanDays: 90 });
608
+ expect(v.get('restore-1')).toBeNull();
609
+
610
+ const restored = v.restore('restore-1');
611
+ expect(restored).toBe(true);
612
+ expect(v.get('restore-1')).not.toBeNull();
613
+ expect(v.get('restore-1')!.title).toBe('Restore Me');
614
+ v.close();
615
+ });
616
+
617
+ it('restore returns false for missing id', () => {
618
+ const v = new Vault(':memory:');
619
+ const result = v.restore('nonexistent');
620
+ expect(result).toBe(false);
621
+ v.close();
622
+ });
623
+
624
+ it('restored entry appears in search', () => {
625
+ const v = new Vault(':memory:');
626
+ v.seed([
627
+ {
628
+ id: 'search-restore',
629
+ type: 'pattern',
630
+ domain: 'test',
631
+ title: 'Unique Findable Pattern',
632
+ severity: 'suggestion',
633
+ description: 'Will be found after restore',
634
+ tags: ['test'],
635
+ },
636
+ ]);
637
+ v.getProvider().run('UPDATE entries SET updated_at = ? WHERE id = ?', [
638
+ Math.floor(Date.now() / 1000) - 200 * 86400,
639
+ 'search-restore',
640
+ ]);
641
+ v.archive({ olderThanDays: 90 });
642
+ v.restore('search-restore');
643
+
644
+ const results = v.search('unique findable');
645
+ expect(results.length).toBeGreaterThan(0);
646
+ v.close();
647
+ });
648
+
649
+ it('optimize runs without error', () => {
650
+ const v = new Vault(':memory:');
651
+ v.seed([
652
+ {
653
+ id: 'opt-1',
654
+ type: 'pattern',
655
+ domain: 'test',
656
+ title: 'Optimize Test',
657
+ severity: 'suggestion',
658
+ description: 'For optimization',
659
+ tags: ['test'],
660
+ },
661
+ ]);
662
+
663
+ expect(() => v.optimize()).not.toThrow();
664
+ v.close();
665
+ });
666
+
667
+ it('optimize returns status', () => {
668
+ const v = new Vault(':memory:');
669
+ const status = v.optimize();
670
+ expect(status).toHaveProperty('vacuumed');
671
+ expect(status).toHaveProperty('analyzed');
672
+ expect(status).toHaveProperty('ftsRebuilt');
673
+ // SQLite backend should analyze and rebuild FTS
674
+ expect(status.analyzed).toBe(true);
675
+ v.close();
676
+ });
677
+ });
494
678
  });