aismemory 0.1.0 → 0.3.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 (100) hide show
  1. package/README.md +1 -0
  2. package/dist/__tests__/auto-handoff.test.d.ts +1 -0
  3. package/dist/__tests__/auto-handoff.test.js +72 -0
  4. package/dist/__tests__/auto-handoff.test.js.map +1 -0
  5. package/dist/__tests__/cli-review.test.d.ts +1 -0
  6. package/dist/__tests__/cli-review.test.js +26 -0
  7. package/dist/__tests__/cli-review.test.js.map +1 -0
  8. package/dist/__tests__/config.test.d.ts +1 -0
  9. package/dist/__tests__/config.test.js +54 -0
  10. package/dist/__tests__/config.test.js.map +1 -0
  11. package/dist/__tests__/hydration.test.d.ts +1 -0
  12. package/dist/__tests__/hydration.test.js +111 -0
  13. package/dist/__tests__/hydration.test.js.map +1 -0
  14. package/dist/__tests__/integration.test.d.ts +1 -0
  15. package/dist/__tests__/integration.test.js +36 -0
  16. package/dist/__tests__/integration.test.js.map +1 -0
  17. package/dist/__tests__/local-claude-source.test.d.ts +1 -0
  18. package/dist/__tests__/local-claude-source.test.js +97 -0
  19. package/dist/__tests__/local-claude-source.test.js.map +1 -0
  20. package/dist/__tests__/local-mirror.test.d.ts +1 -0
  21. package/dist/__tests__/local-mirror.test.js +95 -0
  22. package/dist/__tests__/local-mirror.test.js.map +1 -0
  23. package/dist/__tests__/pipeline-ingestion.test.d.ts +1 -0
  24. package/dist/__tests__/pipeline-ingestion.test.js +161 -0
  25. package/dist/__tests__/pipeline-ingestion.test.js.map +1 -0
  26. package/dist/__tests__/pipeline-scope-resolver.test.d.ts +1 -0
  27. package/dist/__tests__/pipeline-scope-resolver.test.js +51 -0
  28. package/dist/__tests__/pipeline-scope-resolver.test.js.map +1 -0
  29. package/dist/__tests__/pipeline-trust-tagger.test.d.ts +1 -0
  30. package/dist/__tests__/pipeline-trust-tagger.test.js +24 -0
  31. package/dist/__tests__/pipeline-trust-tagger.test.js.map +1 -0
  32. package/dist/__tests__/prompt-resource.test.d.ts +1 -0
  33. package/dist/__tests__/prompt-resource.test.js +218 -0
  34. package/dist/__tests__/prompt-resource.test.js.map +1 -0
  35. package/dist/__tests__/read-claude-memory-tree.test.d.ts +1 -0
  36. package/dist/__tests__/read-claude-memory-tree.test.js +37 -0
  37. package/dist/__tests__/read-claude-memory-tree.test.js.map +1 -0
  38. package/dist/__tests__/refresh.test.d.ts +1 -0
  39. package/dist/__tests__/refresh.test.js +73 -0
  40. package/dist/__tests__/refresh.test.js.map +1 -0
  41. package/dist/__tests__/trust-ledger.test.d.ts +1 -0
  42. package/dist/__tests__/trust-ledger.test.js +55 -0
  43. package/dist/__tests__/trust-ledger.test.js.map +1 -0
  44. package/dist/auto-handoff.d.ts +15 -0
  45. package/dist/auto-handoff.js +53 -0
  46. package/dist/auto-handoff.js.map +1 -0
  47. package/dist/cli/read-claude-memory-tree.d.ts +7 -0
  48. package/dist/cli/read-claude-memory-tree.js +65 -0
  49. package/dist/cli/read-claude-memory-tree.js.map +1 -0
  50. package/dist/cli/sync-memory.d.ts +2 -0
  51. package/dist/cli/sync-memory.js +155 -0
  52. package/dist/cli/sync-memory.js.map +1 -0
  53. package/dist/config.d.ts +11 -0
  54. package/dist/config.js +51 -0
  55. package/dist/config.js.map +1 -0
  56. package/dist/hydration.d.ts +2 -0
  57. package/dist/hydration.js +62 -0
  58. package/dist/hydration.js.map +1 -0
  59. package/dist/index.js +173 -11
  60. package/dist/index.js.map +1 -1
  61. package/dist/local-mirror.d.ts +15 -0
  62. package/dist/local-mirror.js +56 -0
  63. package/dist/local-mirror.js.map +1 -0
  64. package/dist/pipeline/dedupe.d.ts +11 -0
  65. package/dist/pipeline/dedupe.js +21 -0
  66. package/dist/pipeline/dedupe.js.map +1 -0
  67. package/dist/pipeline/ingestion.d.ts +56 -0
  68. package/dist/pipeline/ingestion.js +86 -0
  69. package/dist/pipeline/ingestion.js.map +1 -0
  70. package/dist/pipeline/scope-resolver.d.ts +15 -0
  71. package/dist/pipeline/scope-resolver.js +28 -0
  72. package/dist/pipeline/scope-resolver.js.map +1 -0
  73. package/dist/pipeline/trust-tagger.d.ts +10 -0
  74. package/dist/pipeline/trust-tagger.js +12 -0
  75. package/dist/pipeline/trust-tagger.js.map +1 -0
  76. package/dist/pipeline/types.d.ts +41 -0
  77. package/dist/pipeline/types.js +6 -0
  78. package/dist/pipeline/types.js.map +1 -0
  79. package/dist/prompt-resource.d.ts +2 -0
  80. package/dist/prompt-resource.js +77 -0
  81. package/dist/prompt-resource.js.map +1 -0
  82. package/dist/refresh.d.ts +3 -0
  83. package/dist/refresh.js +25 -0
  84. package/dist/refresh.js.map +1 -0
  85. package/dist/review/cli-review.d.ts +10 -0
  86. package/dist/review/cli-review.js +47 -0
  87. package/dist/review/cli-review.js.map +1 -0
  88. package/dist/sources/local-claude.d.ts +11 -0
  89. package/dist/sources/local-claude.js +137 -0
  90. package/dist/sources/local-claude.js.map +1 -0
  91. package/dist/sources/types.d.ts +53 -0
  92. package/dist/sources/types.js +9 -0
  93. package/dist/sources/types.js.map +1 -0
  94. package/dist/trust-ledger.d.ts +8 -0
  95. package/dist/trust-ledger.js +61 -0
  96. package/dist/trust-ledger.js.map +1 -0
  97. package/dist/types.d.ts +45 -0
  98. package/dist/types.js +2 -0
  99. package/dist/types.js.map +1 -0
  100. package/package.json +5 -3
package/README.md CHANGED
@@ -36,6 +36,7 @@ After approving, your agent has persistent memory. Every future session auto-aut
36
36
  | `full_context` | Load complete agent context (personality, goals, facts, skills) |
37
37
  | `dream` | Trigger memory consolidation (promotes important, archives old) |
38
38
  | `handoff` | Save session context for the next session |
39
+ | `agent_load` | Switch the active agent by name — triggers on "get me X", "bring me X", "load X", "/agent X", "switch to X" |
39
40
 
40
41
  ## Works With
41
42
 
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,72 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { ActivityTracker, buildHandoffPayload } from '../auto-handoff.js';
3
+ describe('ActivityTracker', () => {
4
+ it('tracks tool usage counts', () => {
5
+ const tracker = new ActivityTracker();
6
+ tracker.recordToolUse('store_memory');
7
+ tracker.recordToolUse('store_memory');
8
+ tracker.recordToolUse('recall_memories');
9
+ const counts = tracker.getToolCounts();
10
+ expect(counts['store_memory']).toBe(2);
11
+ expect(counts['recall_memories']).toBe(1);
12
+ });
13
+ it('tracks stored memory content', () => {
14
+ const tracker = new ActivityTracker();
15
+ tracker.recordMemoryStored('learned about TypeScript generics');
16
+ tracker.recordMemoryStored('user prefers concise responses');
17
+ const memories = tracker.getStoredMemories();
18
+ expect(memories).toHaveLength(2);
19
+ expect(memories[0]).toBe('learned about TypeScript generics');
20
+ expect(memories[1]).toBe('user prefers concise responses');
21
+ });
22
+ it('reports hasActivity false when no tools used', () => {
23
+ const tracker = new ActivityTracker();
24
+ expect(tracker.hasActivity()).toBe(false);
25
+ });
26
+ it('reports hasActivity true once a tool is recorded', () => {
27
+ const tracker = new ActivityTracker();
28
+ tracker.recordToolUse('any_tool');
29
+ expect(tracker.hasActivity()).toBe(true);
30
+ });
31
+ it('returns defensive copies from getToolCounts and getStoredMemories', () => {
32
+ const tracker = new ActivityTracker();
33
+ tracker.recordToolUse('tool_a');
34
+ tracker.recordMemoryStored('mem_a');
35
+ const counts = tracker.getToolCounts();
36
+ counts['tool_b'] = 99;
37
+ expect(tracker.getToolCounts()['tool_b']).toBeUndefined();
38
+ const memories = tracker.getStoredMemories();
39
+ memories.push('injected');
40
+ expect(tracker.getStoredMemories()).toHaveLength(1);
41
+ });
42
+ });
43
+ describe('buildHandoffPayload', () => {
44
+ it('builds summary from activity including tool counts and memory count', () => {
45
+ const tracker = new ActivityTracker();
46
+ tracker.recordToolUse('store_memory');
47
+ tracker.recordToolUse('store_memory');
48
+ tracker.recordToolUse('recall_memories');
49
+ tracker.recordMemoryStored('first memory');
50
+ tracker.recordMemoryStored('second memory');
51
+ const payload = buildHandoffPayload(tracker);
52
+ expect(payload.summary).toContain('store_memory (2)');
53
+ expect(payload.summary).toContain('recall_memories (1)');
54
+ expect(payload.summary).toContain('Stored 2 memories.');
55
+ expect(payload.keyLearnings).toEqual(['first memory', 'second memory']);
56
+ });
57
+ it('returns minimal payload when no activity', () => {
58
+ const tracker = new ActivityTracker();
59
+ const payload = buildHandoffPayload(tracker);
60
+ expect(payload.summary).toBe('No significant activity this session.');
61
+ expect(payload.keyLearnings).toEqual([]);
62
+ });
63
+ it('omits memory count phrase when no memories stored', () => {
64
+ const tracker = new ActivityTracker();
65
+ tracker.recordToolUse('recall_memories');
66
+ const payload = buildHandoffPayload(tracker);
67
+ expect(payload.summary).toContain('recall_memories (1)');
68
+ expect(payload.summary).not.toContain('memories.');
69
+ expect(payload.keyLearnings).toEqual([]);
70
+ });
71
+ });
72
+ //# sourceMappingURL=auto-handoff.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto-handoff.test.js","sourceRoot":"","sources":["../../src/__tests__/auto-handoff.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,26 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { filterByImportance, bulkSelectAll, bulkDeselectAll } from '../review/cli-review.js';
3
+ function draft(importance) {
4
+ const prov = {
5
+ source: 's',
6
+ sourceHash: 'h' + importance,
7
+ importedAt: '',
8
+ importedBy: 'a',
9
+ sourceScope: { kind: 'project', label: 'p' },
10
+ sourcePrompt: '',
11
+ };
12
+ return { content: 'c', type: 'fact', importance, trustScore: 0.5, provenance: prov };
13
+ }
14
+ describe('review bulk actions', () => {
15
+ const drafts = [draft(0.3), draft(0.6), draft(0.8), draft(0.9)];
16
+ it('selectAll returns full set', () => {
17
+ expect(bulkSelectAll(drafts)).toHaveLength(4);
18
+ });
19
+ it('deselectAll returns empty set', () => {
20
+ expect(bulkDeselectAll(drafts)).toHaveLength(0);
21
+ });
22
+ it('filterByImportance returns only drafts at or above threshold', () => {
23
+ expect(filterByImportance(drafts, 0.7)).toHaveLength(2);
24
+ });
25
+ });
26
+ //# sourceMappingURL=cli-review.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-review.test.js","sourceRoot":"","sources":["../../src/__tests__/cli-review.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAG7F,SAAS,KAAK,CAAC,UAAkB;IAC/B,MAAM,IAAI,GAAqB;QAC7B,MAAM,EAAE,GAAG;QACX,UAAU,EAAE,GAAG,GAAG,UAAU;QAC5B,UAAU,EAAE,EAAE;QACd,UAAU,EAAE,GAAG;QACf,WAAW,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAe;QACzD,YAAY,EAAE,EAAE;KACjB,CAAC;IACF,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;AACvF,CAAC;AAED,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;IACnC,MAAM,MAAM,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;IAEhE,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;QACpC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;QACvC,MAAM,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8DAA8D,EAAE,GAAG,EAAE;QACtE,MAAM,CAAC,kBAAkB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,54 @@
1
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
2
+ import { mkdtempSync, rmSync, writeFileSync, mkdirSync, readdirSync } from 'node:fs';
3
+ import { tmpdir } from 'node:os';
4
+ import { join } from 'node:path';
5
+ import { SyncConfig } from '../config.js';
6
+ describe('SyncConfig', () => {
7
+ let tmpHome;
8
+ beforeEach(() => {
9
+ tmpHome = mkdtempSync(join(tmpdir(), 'aismem-cfg-'));
10
+ });
11
+ afterEach(() => rmSync(tmpHome, { recursive: true, force: true }));
12
+ it('returns defaults when no file exists', () => {
13
+ const cfg = new SyncConfig(tmpHome);
14
+ expect(cfg.retentionDays).toBe(30);
15
+ expect(cfg.autoCommit('claude-local')).toBe(false);
16
+ expect(cfg.scopePreference('/any/path')).toBeNull();
17
+ });
18
+ it('reads autoCommit per source from file', () => {
19
+ mkdirSync(join(tmpHome, '.aismemory'), { recursive: true });
20
+ writeFileSync(join(tmpHome, '.aismemory', 'config.json'), JSON.stringify({ retentionDays: 14, autoCommit: { 'claude-local': true } }));
21
+ const cfg = new SyncConfig(tmpHome);
22
+ expect(cfg.retentionDays).toBe(14);
23
+ expect(cfg.autoCommit('claude-local')).toBe(true);
24
+ expect(cfg.autoCommit('chatgpt-paste')).toBe(false);
25
+ });
26
+ it('saves scope preference keyed by project path', () => {
27
+ const cfg = new SyncConfig(tmpHome);
28
+ cfg.saveScopePreference('/users/me/corbot', {
29
+ kind: 'project',
30
+ label: 'Corbot',
31
+ projectPath: '/users/me/corbot',
32
+ });
33
+ const cfg2 = new SyncConfig(tmpHome);
34
+ const pref = cfg2.scopePreference('/users/me/corbot');
35
+ expect(pref?.kind).toBe('project');
36
+ expect(pref?.label).toBe('Corbot');
37
+ });
38
+ it('recovers from corrupt config file by backing it up', () => {
39
+ mkdirSync(join(tmpHome, '.aismemory'), { recursive: true });
40
+ writeFileSync(join(tmpHome, '.aismemory', 'config.json'), '{not valid json');
41
+ // Suppress the expected console.warn for this test
42
+ const warn = vi.spyOn(console, 'warn').mockImplementation(() => { });
43
+ try {
44
+ const cfg = new SyncConfig(tmpHome);
45
+ expect(cfg.retentionDays).toBe(30); // falls back to default
46
+ const files = readdirSync(join(tmpHome, '.aismemory'));
47
+ expect(files.some((f) => f.startsWith('config.json.corrupt-'))).toBe(true);
48
+ }
49
+ finally {
50
+ warn.mockRestore();
51
+ }
52
+ });
53
+ });
54
+ //# sourceMappingURL=config.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.test.js","sourceRoot":"","sources":["../../src/__tests__/config.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,111 @@
1
+ import { describe, it, expect, vi, afterEach } from 'vitest';
2
+ import { hydrateIdentity } from '../hydration.js';
3
+ const AIS_URL = 'https://ais.example.com';
4
+ const AGENT_ID = 'agent-123';
5
+ const TOKEN = 'test-token';
6
+ const mockFullContextResponse = {
7
+ success: true,
8
+ data: {
9
+ identity: {
10
+ id: 'agent-123',
11
+ did: 'did:example:agent-123',
12
+ name: 'Test Agent',
13
+ description: 'A test agent',
14
+ status: 'active',
15
+ },
16
+ personality: {
17
+ traits: [{ name: 'curious', value: 0.9 }],
18
+ communicationStyle: 'concise',
19
+ tonePreferences: ['professional'],
20
+ },
21
+ goals: [{ title: 'Complete task', progress: 50, status: 'IN_PROGRESS' }],
22
+ recentMemories: [
23
+ {
24
+ id: 'mem-1',
25
+ content: 'Learned something useful',
26
+ type: 'episodic',
27
+ importance: 0.8,
28
+ createdAt: '2026-04-03T00:00:00Z',
29
+ },
30
+ ],
31
+ skills: [{ name: 'TypeScript' }, { name: 'Testing' }],
32
+ lastHandoff: {
33
+ summary: 'Previous session summary',
34
+ keyLearnings: ['lesson one'],
35
+ taskContext: 'Working on hydration',
36
+ createdAt: '2026-04-02T00:00:00Z',
37
+ },
38
+ assembledAt: '2026-04-03T01:00:00Z',
39
+ context: { totalTokens: 1234 },
40
+ },
41
+ };
42
+ afterEach(() => {
43
+ vi.unstubAllGlobals();
44
+ });
45
+ describe('hydrateIdentity', () => {
46
+ it('fetches full-context and returns AgentContext on success', async () => {
47
+ const mockFetch = vi.fn().mockResolvedValue({
48
+ ok: true,
49
+ json: () => Promise.resolve(mockFullContextResponse),
50
+ });
51
+ vi.stubGlobal('fetch', mockFetch);
52
+ const result = await hydrateIdentity(AIS_URL, AGENT_ID, TOKEN);
53
+ expect(mockFetch).toHaveBeenCalledWith(`${AIS_URL}/v1/agents/${AGENT_ID}/full-context`, { headers: { Authorization: `Bearer ${TOKEN}` } });
54
+ expect(result).not.toBeNull();
55
+ expect(result.identity.id).toBe('agent-123');
56
+ expect(result.identity.name).toBe('Test Agent');
57
+ expect(result.personality).not.toBeNull();
58
+ expect(result.personality.traits).toHaveLength(1);
59
+ expect(result.goals).toHaveLength(1);
60
+ expect(result.goals[0].title).toBe('Complete task');
61
+ expect(result.recentMemories).toHaveLength(1);
62
+ expect(result.skills).toHaveLength(2);
63
+ expect(result.lastHandoff).not.toBeNull();
64
+ expect(result.lastHandoff.summary).toBe('Previous session summary');
65
+ expect(result.assembledAt).toBe('2026-04-03T01:00:00Z');
66
+ expect(result.totalTokens).toBe(1234);
67
+ });
68
+ it('returns null on network failure (graceful degradation)', async () => {
69
+ const mockFetch = vi.fn().mockRejectedValue(new Error('Network error'));
70
+ vi.stubGlobal('fetch', mockFetch);
71
+ const result = await hydrateIdentity(AIS_URL, AGENT_ID, TOKEN);
72
+ expect(result).toBeNull();
73
+ });
74
+ it('returns null on non-200 response', async () => {
75
+ const mockFetch = vi.fn().mockResolvedValue({
76
+ ok: false,
77
+ status: 401,
78
+ });
79
+ vi.stubGlobal('fetch', mockFetch);
80
+ const result = await hydrateIdentity(AIS_URL, AGENT_ID, TOKEN);
81
+ expect(result).toBeNull();
82
+ });
83
+ it('returns null when response success is false', async () => {
84
+ const mockFetch = vi.fn().mockResolvedValue({
85
+ ok: true,
86
+ json: () => Promise.resolve({ success: false }),
87
+ });
88
+ vi.stubGlobal('fetch', mockFetch);
89
+ const result = await hydrateIdentity(AIS_URL, AGENT_ID, TOKEN);
90
+ expect(result).toBeNull();
91
+ });
92
+ it('handles null personality and lastHandoff', async () => {
93
+ const mockFetch = vi.fn().mockResolvedValue({
94
+ ok: true,
95
+ json: () => Promise.resolve({
96
+ success: true,
97
+ data: {
98
+ ...mockFullContextResponse.data,
99
+ personality: null,
100
+ lastHandoff: null,
101
+ },
102
+ }),
103
+ });
104
+ vi.stubGlobal('fetch', mockFetch);
105
+ const result = await hydrateIdentity(AIS_URL, AGENT_ID, TOKEN);
106
+ expect(result).not.toBeNull();
107
+ expect(result.personality).toBeNull();
108
+ expect(result.lastHandoff).toBeNull();
109
+ });
110
+ });
111
+ //# sourceMappingURL=hydration.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hydration.test.js","sourceRoot":"","sources":["../../src/__tests__/hydration.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,36 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { assemblePrompt } from '../prompt-resource.js';
3
+ import { ActivityTracker, buildHandoffPayload } from '../auto-handoff.js';
4
+ describe('activation lifecycle integration', () => {
5
+ it('assembles prompt from hydrated context and produces handoff from activity', () => {
6
+ // Simulate hydrated context (what hydrateIdentity returns)
7
+ const ctx = {
8
+ identity: { id: 'a1', did: 'did:web:ais:agents:a1', name: 'Tank', description: 'Skills expert', status: 'active' },
9
+ personality: { traits: [{ name: 'directness', value: 0.9 }], communicationStyle: 'concise', tonePreferences: ['technical'] },
10
+ goals: [{ title: 'Ship activation', progress: 0, status: 'active' }],
11
+ recentMemories: [{ id: 'm1', content: 'AIS enables statistical learning', type: 'lesson', importance: 0.9, createdAt: '2026-04-03' }],
12
+ skills: [],
13
+ lastHandoff: { summary: 'Shipped effectiveness integration', keyLearnings: ['dual-write works'], taskContext: 'main', createdAt: '2026-04-02' },
14
+ assembledAt: '2026-04-03T00:00:00Z',
15
+ totalTokens: 300,
16
+ };
17
+ // Prompt should contain identity + personality + memories + handoff
18
+ const prompt = assemblePrompt(ctx);
19
+ expect(prompt).toContain('Name: Tank');
20
+ expect(prompt).toContain('concise');
21
+ expect(prompt).toContain('AIS enables statistical learning');
22
+ expect(prompt).toContain('Shipped effectiveness integration');
23
+ expect(prompt).toContain('continuous entity');
24
+ // Simulate session activity
25
+ const tracker = new ActivityTracker();
26
+ tracker.recordToolUse('remember');
27
+ tracker.recordToolUse('recall');
28
+ tracker.recordMemoryStored('New lesson from this session');
29
+ // Handoff should capture activity
30
+ const handoff = buildHandoffPayload(tracker);
31
+ expect(handoff.summary).toContain('remember (1)');
32
+ expect(handoff.summary).toContain('recall (1)');
33
+ expect(handoff.keyLearnings).toContain('New lesson from this session');
34
+ });
35
+ });
36
+ //# sourceMappingURL=integration.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"integration.test.js","sourceRoot":"","sources":["../../src/__tests__/integration.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAG1E,QAAQ,CAAC,kCAAkC,EAAE,GAAG,EAAE;IAChD,EAAE,CAAC,2EAA2E,EAAE,GAAG,EAAE;QACnF,2DAA2D;QAC3D,MAAM,GAAG,GAAiB;YACxB,QAAQ,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,uBAAuB,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,EAAE,QAAQ,EAAE;YAClH,WAAW,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,EAAE,kBAAkB,EAAE,SAAS,EAAE,eAAe,EAAE,CAAC,WAAW,CAAC,EAAE;YAC5H,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,iBAAiB,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;YACpE,cAAc,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,kCAAkC,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC;YACrI,MAAM,EAAE,EAAE;YACV,WAAW,EAAE,EAAE,OAAO,EAAE,mCAAmC,EAAE,YAAY,EAAE,CAAC,kBAAkB,CAAC,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE;YAC/I,WAAW,EAAE,sBAAsB;YACnC,WAAW,EAAE,GAAG;SACjB,CAAC;QAEF,oEAAoE;QACpE,MAAM,MAAM,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;QACnC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;QACvC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QACpC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,kCAAkC,CAAC,CAAC;QAC7D,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,mCAAmC,CAAC,CAAC;QAC9D,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC;QAE9C,4BAA4B;QAC5B,MAAM,OAAO,GAAG,IAAI,eAAe,EAAE,CAAC;QACtC,OAAO,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC;QAClC,OAAO,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;QAChC,OAAO,CAAC,kBAAkB,CAAC,8BAA8B,CAAC,CAAC;QAE3D,kCAAkC;QAClC,MAAM,OAAO,GAAG,mBAAmB,CAAC,OAAO,CAAC,CAAC;QAC7C,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;QAClD,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;QAChD,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,SAAS,CAAC,8BAA8B,CAAC,CAAC;IACzE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,97 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { readFileSync, readdirSync, statSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ import { LocalClaudeSource } from '../sources/local-claude.js';
5
+ function readFixtureFs(root) {
6
+ const files = [];
7
+ function walk(dir) {
8
+ for (const name of readdirSync(dir)) {
9
+ const full = join(dir, name);
10
+ const st = statSync(full);
11
+ if (st.isDirectory())
12
+ walk(full);
13
+ else if (name.endsWith('.md'))
14
+ files.push({ path: full, content: readFileSync(full, 'utf8') });
15
+ }
16
+ }
17
+ walk(root);
18
+ return { rootPath: root, files };
19
+ }
20
+ const FIXTURE_PATH = join(__dirname, 'fixtures', 'local-claude', 'project-a');
21
+ const SCOPE = { kind: 'project', label: 'fixture-project' };
22
+ describe('LocalClaudeSource', () => {
23
+ const adapter = new LocalClaudeSource();
24
+ const fs = readFixtureFs(FIXTURE_PATH);
25
+ it('parses MEMORY.md bullets as context entries', () => {
26
+ const { memories, warnings } = adapter.parseResponse(fs);
27
+ expect(warnings).toHaveLength(0);
28
+ const contextEntries = memories.filter((m) => m.sourceCategory === 'memory-index');
29
+ expect(contextEntries.length).toBeGreaterThanOrEqual(3);
30
+ expect(contextEntries[0]?.content).toMatch(/Monorepo/);
31
+ });
32
+ it('parses feedback_*.md files as lesson entries', () => {
33
+ const { memories } = adapter.parseResponse(fs);
34
+ const lessons = memories.filter((m) => m.sourceCategory === 'feedback');
35
+ expect(lessons).toHaveLength(1);
36
+ expect(lessons[0]?.content).toMatch(/Integration tests/);
37
+ });
38
+ it('parses agent_*.md files as fact entries', () => {
39
+ const { memories } = adapter.parseResponse(fs);
40
+ const facts = memories.filter((m) => m.sourceCategory === 'agent');
41
+ expect(facts).toHaveLength(1);
42
+ expect(facts[0]?.content).toMatch(/Tank/);
43
+ });
44
+ it('mapToAis produces type matching the category', () => {
45
+ const { memories } = adapter.parseResponse(fs);
46
+ const feedback = memories.find((m) => m.sourceCategory === 'feedback');
47
+ expect(feedback).toBeDefined();
48
+ const draft = adapter.mapToAis(feedback, SCOPE, 'agent1');
49
+ expect(draft.type).toBe('lesson');
50
+ expect(draft.trustScore).toBe(0);
51
+ expect(draft.provenance.source).toBe('claude-local');
52
+ expect(draft.provenance.sourcePrompt).toBe('');
53
+ });
54
+ it('extractionPrompt returns empty string (filesystem adapter)', () => {
55
+ expect(adapter.extractionPrompt(SCOPE)).toBe('');
56
+ });
57
+ it('dedupeKey is deterministic 64-char hex', () => {
58
+ const src = { content: 'x', sourceCategory: 'feedback' };
59
+ const k1 = adapter.dedupeKey(src);
60
+ const k2 = adapter.dedupeKey(src);
61
+ expect(k1).toBe(k2);
62
+ expect(k1).toMatch(/^[0-9a-f]{64}$/);
63
+ });
64
+ it('handles CRLF and BOM in MEMORY.md', () => {
65
+ const fsInput = {
66
+ rootPath: '/synthetic',
67
+ files: [
68
+ {
69
+ path: '/synthetic/MEMORY.md',
70
+ content: '\uFEFF# Heading\r\n\r\n## Section\r\n- First CRLF bullet\r\n- Second CRLF bullet\r\n',
71
+ },
72
+ ],
73
+ };
74
+ const { memories, warnings } = adapter.parseResponse(fsInput);
75
+ expect(warnings).toHaveLength(0);
76
+ const bullets = memories.filter((m) => m.sourceCategory === 'memory-index');
77
+ expect(bullets).toHaveLength(2);
78
+ expect(bullets[0]?.content).toBe('First CRLF bullet');
79
+ expect(bullets[1]?.content).toBe('Second CRLF bullet');
80
+ });
81
+ it('skips nested bullets in MEMORY.md', () => {
82
+ const fsInput = {
83
+ rootPath: '/synthetic',
84
+ files: [
85
+ {
86
+ path: '/synthetic/MEMORY.md',
87
+ content: '## Section\n- Parent bullet\n - Nested child\n - Deeply nested\n- Another parent\n',
88
+ },
89
+ ],
90
+ };
91
+ const { memories } = adapter.parseResponse(fsInput);
92
+ const bullets = memories.filter((m) => m.sourceCategory === 'memory-index');
93
+ expect(bullets).toHaveLength(2);
94
+ expect(bullets.map((b) => b.content)).toEqual(['Parent bullet', 'Another parent']);
95
+ });
96
+ });
97
+ //# sourceMappingURL=local-claude-source.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-claude-source.test.js","sourceRoot":"","sources":["../../src/__tests__/local-claude-source.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,95 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import { mkdtempSync, rmSync, existsSync, readFileSync, mkdirSync, writeFileSync } from 'node:fs';
3
+ import { tmpdir } from 'node:os';
4
+ import { join } from 'node:path';
5
+ import { LocalMirror } from '../local-mirror.js';
6
+ function draft(content) {
7
+ const prov = {
8
+ source: 'claude-local',
9
+ sourceHash: 'abc',
10
+ importedAt: new Date().toISOString(),
11
+ importedBy: 'agent1',
12
+ sourceScope: { kind: 'project', label: 'test' },
13
+ sourcePrompt: '',
14
+ };
15
+ return { content, type: 'fact', importance: 0.5, trustScore: 0.5, provenance: prov };
16
+ }
17
+ describe('LocalMirror', () => {
18
+ let tmpHome;
19
+ beforeEach(() => {
20
+ tmpHome = mkdtempSync(join(tmpdir(), 'aismem-mirror-'));
21
+ });
22
+ afterEach(() => rmSync(tmpHome, { recursive: true, force: true }));
23
+ it('appends one JSONL line per entry', () => {
24
+ const mirror = new LocalMirror(tmpHome, 30);
25
+ mirror.append('agent1', [
26
+ { aisMemoryId: 'mem1', memory: draft('first') },
27
+ { aisMemoryId: 'mem2', memory: draft('second') },
28
+ ]);
29
+ const path = join(tmpHome, '.aismemory', 'cache', 'agent1.jsonl');
30
+ const content = readFileSync(path, 'utf8').trim().split('\n');
31
+ expect(content).toHaveLength(2);
32
+ const first = JSON.parse(content[0]);
33
+ expect(first.aisMemoryId).toBe('mem1');
34
+ });
35
+ it('cleanup deletes entries older than retentionDays', () => {
36
+ const mirror = new LocalMirror(tmpHome, 7);
37
+ const oldDraft = draft('old');
38
+ oldDraft.provenance.importedAt = new Date(Date.now() - 1000 * 60 * 60 * 24 * 30).toISOString();
39
+ mirror.append('agent1', [{ aisMemoryId: 'old1', memory: oldDraft }]);
40
+ mirror.append('agent1', [{ aisMemoryId: 'new1', memory: draft('new') }]);
41
+ mirror.cleanup('agent1');
42
+ const path = join(tmpHome, '.aismemory', 'cache', 'agent1.jsonl');
43
+ const lines = readFileSync(path, 'utf8').trim().split('\n');
44
+ expect(lines).toHaveLength(1);
45
+ expect(JSON.parse(lines[0]).aisMemoryId).toBe('new1');
46
+ });
47
+ it('scrub deletes the mirror file entirely', () => {
48
+ const mirror = new LocalMirror(tmpHome, 30);
49
+ mirror.append('agent1', [{ aisMemoryId: 'mem1', memory: draft('hi') }]);
50
+ const path = join(tmpHome, '.aismemory', 'cache', 'agent1.jsonl');
51
+ expect(existsSync(path)).toBe(true);
52
+ mirror.scrub('agent1');
53
+ expect(existsSync(path)).toBe(false);
54
+ });
55
+ it('cleanup is a no-op when mirror file does not exist', () => {
56
+ const mirror = new LocalMirror(tmpHome, 30);
57
+ // Should not throw
58
+ expect(() => mirror.cleanup('agent-no-file')).not.toThrow();
59
+ });
60
+ it('cleanup produces a clean file when all entries have expired', () => {
61
+ const mirror = new LocalMirror(tmpHome, 7);
62
+ const oldDraft = draft('old');
63
+ oldDraft.provenance.importedAt = new Date(Date.now() - 1000 * 60 * 60 * 24 * 30).toISOString();
64
+ mirror.append('agent1', [{ aisMemoryId: 'old1', memory: oldDraft }]);
65
+ mirror.cleanup('agent1');
66
+ const path = join(tmpHome, '.aismemory', 'cache', 'agent1.jsonl');
67
+ // File should exist but be empty (no surviving entries)
68
+ expect(existsSync(path)).toBe(true);
69
+ expect(readFileSync(path, 'utf8')).toBe('');
70
+ });
71
+ it('scrub is a no-op when mirror file does not exist', () => {
72
+ const mirror = new LocalMirror(tmpHome, 30);
73
+ expect(() => mirror.scrub('agent-no-file')).not.toThrow();
74
+ });
75
+ it('cleanup silently drops malformed JSONL lines', () => {
76
+ const mirror = new LocalMirror(tmpHome, 30);
77
+ // Manually write a mix of valid + malformed lines to the mirror file
78
+ const path = join(tmpHome, '.aismemory', 'cache', 'agent1.jsonl');
79
+ mkdirSync(join(tmpHome, '.aismemory', 'cache'), { recursive: true });
80
+ const validEntry = JSON.stringify({
81
+ aisMemoryId: 'good1',
82
+ memory: draft('valid'),
83
+ importedAt: new Date().toISOString(),
84
+ });
85
+ writeFileSync(path, `${validEntry}\nnot json\n${validEntry}\n`);
86
+ mirror.cleanup('agent1');
87
+ const lines = readFileSync(path, 'utf8').trim().split('\n');
88
+ // Only the two valid lines survive
89
+ expect(lines).toHaveLength(2);
90
+ lines.forEach((line) => {
91
+ expect(() => JSON.parse(line)).not.toThrow();
92
+ });
93
+ });
94
+ });
95
+ //# sourceMappingURL=local-mirror.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-mirror.test.js","sourceRoot":"","sources":["../../src/__tests__/local-mirror.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACrE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAClG,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAGjD,SAAS,KAAK,CAAC,OAAe;IAC5B,MAAM,IAAI,GAAqB;QAC7B,MAAM,EAAE,cAAc;QACtB,UAAU,EAAE,KAAK;QACjB,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACpC,UAAU,EAAE,QAAQ;QACpB,WAAW,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE;QAC/C,YAAY,EAAE,EAAE;KACjB,CAAC;IACF,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;AACvF,CAAC;AAED,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,IAAI,OAAe,CAAC;IAEpB,UAAU,CAAC,GAAG,EAAE;QACd,OAAO,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,gBAAgB,CAAC,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAEnE,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC1C,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAC5C,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE;YACtB,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,EAAE;YAC/C,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC,EAAE;SACjD,CAAC,CAAC;QACH,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,cAAc,CAAC,CAAC;QAClE,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC9D,MAAM,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAChC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAW,CAA4B,CAAC;QAC1E,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAC3C,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;QAC9B,QAAQ,CAAC,UAAU,CAAC,UAAU,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;QAC/F,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;QACrE,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;QACzE,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACzB,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,cAAc,CAAC,CAAC;QAClE,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC5D,MAAM,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC9B,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAW,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAClE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;QAChD,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAC5C,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;QACxE,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,cAAc,CAAC,CAAC;QAClE,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QACvB,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;QAC5D,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAC5C,mBAAmB;QACnB,MAAM,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;IAC9D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6DAA6D,EAAE,GAAG,EAAE;QACrE,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAC3C,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;QAC9B,QAAQ,CAAC,UAAU,CAAC,UAAU,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;QAC/F,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;QACrE,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACzB,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,cAAc,CAAC,CAAC;QAClE,wDAAwD;QACxD,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpC,MAAM,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAC5C,MAAM,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;IAC5D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACtD,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAC5C,qEAAqE;QACrE,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,cAAc,CAAC,CAAC;QAClE,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,YAAY,EAAE,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACrE,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC;YAChC,WAAW,EAAE,OAAO;YACpB,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC;YACtB,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACrC,CAAC,CAAC;QACH,aAAa,CAAC,IAAI,EAAE,GAAG,UAAU,eAAe,UAAU,IAAI,CAAC,CAAC;QAChE,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACzB,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC5D,mCAAmC;QACnC,MAAM,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC9B,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;YACrB,MAAM,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QAC/C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1 @@
1
+ export {};