modular-studio 1.0.4 → 1.0.6

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 (129) hide show
  1. package/README.md +122 -41
  2. package/dist/assets/Badge-DrUmDAXz.js +1 -0
  3. package/dist/assets/Input-ndEGQSgx.js +1 -0
  4. package/dist/assets/KnowledgeTab-CxlC76Rf.js +4 -0
  5. package/dist/assets/MemoryTab-CUScYWs9.js +16 -0
  6. package/dist/assets/QualificationTab-BqnWSQHm.js +1 -0
  7. package/dist/assets/ReviewTab-DKYl6cR9.js +103 -0
  8. package/dist/assets/Section-CgmwAj_2.js +1 -0
  9. package/dist/assets/TestTab-iJ2vCf9l.js +33 -0
  10. package/dist/assets/ToolsTab-C10Ulm8b.js +1 -0
  11. package/dist/assets/conversationStore-CkfEU2eV.js +1 -0
  12. package/dist/assets/icons-MKpPNvV8.js +1 -0
  13. package/dist/assets/index-B_ip7Amg.css +1 -0
  14. package/dist/assets/index-gBy3427k.js +143 -0
  15. package/dist/assets/{jszip.min-BK6ZQWkj.js → jszip.min-wf-D3Ix_.js} +1 -1
  16. package/dist/assets/markdown-DWF7F0i0.js +29 -0
  17. package/dist/assets/services-CTWXQK6j.js +356 -0
  18. package/dist/assets/stores-CeKWz7ou.js +1 -0
  19. package/dist/assets/vendor-D1h_O76p.js +9 -0
  20. package/dist/index.html +20 -16
  21. package/dist-server/bin/modular-mcp.js +0 -1
  22. package/dist-server/bin/modular-studio.js +0 -1
  23. package/dist-server/server/config.js +0 -1
  24. package/dist-server/server/data/mcp-tokens.json +3 -3
  25. package/dist-server/server/index.d.ts.map +1 -1
  26. package/dist-server/server/index.js +6 -1
  27. package/dist-server/server/mcp/manager.d.ts.map +1 -1
  28. package/dist-server/server/mcp/manager.js +16 -3
  29. package/dist-server/server/mcp/modular-server.js +0 -1
  30. package/dist-server/server/mcp/transport.js +0 -1
  31. package/dist-server/server/routes/agent-sdk.js +0 -1
  32. package/dist-server/server/routes/agents.d.ts +9 -5
  33. package/dist-server/server/routes/agents.d.ts.map +1 -1
  34. package/dist-server/server/routes/agents.js +108 -8
  35. package/dist-server/server/routes/auth-codex.js +0 -1
  36. package/dist-server/server/routes/cache.d.ts +3 -0
  37. package/dist-server/server/routes/cache.d.ts.map +1 -0
  38. package/dist-server/server/routes/cache.js +55 -0
  39. package/dist-server/server/routes/capabilities.js +0 -1
  40. package/dist-server/server/routes/claude-config.js +0 -1
  41. package/dist-server/server/routes/connectors.d.ts.map +1 -1
  42. package/dist-server/server/routes/connectors.js +224 -1
  43. package/dist-server/server/routes/conversations.js +0 -1
  44. package/dist-server/server/routes/embeddings.js +0 -1
  45. package/dist-server/server/routes/health.js +0 -1
  46. package/dist-server/server/routes/knowledge.js +0 -1
  47. package/dist-server/server/routes/lessons.d.ts +3 -0
  48. package/dist-server/server/routes/lessons.d.ts.map +1 -0
  49. package/dist-server/server/routes/lessons.js +46 -0
  50. package/dist-server/server/routes/llm.js +0 -1
  51. package/dist-server/server/routes/mcp-oauth.js +0 -1
  52. package/dist-server/server/routes/mcp.js +0 -1
  53. package/dist-server/server/routes/memory.d.ts +3 -0
  54. package/dist-server/server/routes/memory.d.ts.map +1 -0
  55. package/dist-server/server/routes/memory.js +314 -0
  56. package/dist-server/server/routes/pipeline.js +0 -1
  57. package/dist-server/server/routes/providers.js +0 -1
  58. package/dist-server/server/routes/qualification.d.ts.map +1 -1
  59. package/dist-server/server/routes/qualification.js +341 -75
  60. package/dist-server/server/routes/repo-index.d.ts.map +1 -1
  61. package/dist-server/server/routes/repo-index.js +7 -1
  62. package/dist-server/server/routes/runtime.js +0 -1
  63. package/dist-server/server/routes/skills-search.d.ts.map +1 -1
  64. package/dist-server/server/routes/skills-search.js +198 -8
  65. package/dist-server/server/routes/worktrees.js +0 -1
  66. package/dist-server/server/services/__tests__/embeddingService.test.js +0 -1
  67. package/dist-server/server/services/adapters/hindsightAdapter.d.ts +28 -0
  68. package/dist-server/server/services/adapters/hindsightAdapter.d.ts.map +1 -0
  69. package/dist-server/server/services/adapters/hindsightAdapter.js +63 -0
  70. package/dist-server/server/services/adapters/postgresAdapter.d.ts +29 -0
  71. package/dist-server/server/services/adapters/postgresAdapter.d.ts.map +1 -0
  72. package/dist-server/server/services/adapters/postgresAdapter.js +224 -0
  73. package/dist-server/server/services/adapters/sqliteAdapter.d.ts +28 -0
  74. package/dist-server/server/services/adapters/sqliteAdapter.d.ts.map +1 -0
  75. package/dist-server/server/services/adapters/sqliteAdapter.js +219 -0
  76. package/dist-server/server/services/adapters/storageAdapter.d.ts +22 -0
  77. package/dist-server/server/services/adapters/storageAdapter.d.ts.map +1 -0
  78. package/dist-server/server/services/adapters/storageAdapter.js +1 -0
  79. package/dist-server/server/services/agentRunner.js +0 -1
  80. package/dist-server/server/services/agentStore.d.ts +19 -3
  81. package/dist-server/server/services/agentStore.d.ts.map +1 -1
  82. package/dist-server/server/services/agentStore.js +117 -23
  83. package/dist-server/server/services/contentStore.js +0 -1
  84. package/dist-server/server/services/correctionDetector.d.ts +22 -0
  85. package/dist-server/server/services/correctionDetector.d.ts.map +1 -0
  86. package/dist-server/server/services/correctionDetector.js +91 -0
  87. package/dist-server/server/services/embeddingService.d.ts +2 -0
  88. package/dist-server/server/services/embeddingService.d.ts.map +1 -1
  89. package/dist-server/server/services/embeddingService.js +30 -19
  90. package/dist-server/server/services/factExtractor.js +0 -1
  91. package/dist-server/server/services/githubIndexer.js +0 -1
  92. package/dist-server/server/services/hindsightClient.d.ts +15 -0
  93. package/dist-server/server/services/hindsightClient.d.ts.map +1 -0
  94. package/dist-server/server/services/hindsightClient.js +47 -0
  95. package/dist-server/server/services/lessonExtractor.d.ts +19 -0
  96. package/dist-server/server/services/lessonExtractor.d.ts.map +1 -0
  97. package/dist-server/server/services/lessonExtractor.js +87 -0
  98. package/dist-server/server/services/mcpOAuth.js +0 -1
  99. package/dist-server/server/services/memoryScorer.js +0 -1
  100. package/dist-server/server/services/repoIndexer.js +0 -1
  101. package/dist-server/server/services/responseCache.d.ts +24 -0
  102. package/dist-server/server/services/responseCache.d.ts.map +1 -0
  103. package/dist-server/server/services/responseCache.js +163 -0
  104. package/dist-server/server/services/sqliteStore.d.ts +8 -0
  105. package/dist-server/server/services/sqliteStore.d.ts.map +1 -1
  106. package/dist-server/server/services/sqliteStore.js +53 -14
  107. package/dist-server/server/services/teamRunner.js +0 -1
  108. package/dist-server/server/services/worktreeManager.js +0 -1
  109. package/dist-server/server/types.d.ts +5 -0
  110. package/dist-server/server/types.d.ts.map +1 -1
  111. package/dist-server/server/types.js +0 -1
  112. package/dist-server/server/utils/pathSecurity.js +0 -1
  113. package/dist-server/src/services/budgetAllocator.js +0 -1
  114. package/dist-server/src/services/contradictionDetector.js +0 -1
  115. package/dist-server/src/services/treeIndexer.js +0 -1
  116. package/dist-server/src/store/knowledgeBase.d.ts +11 -0
  117. package/dist-server/src/store/knowledgeBase.d.ts.map +1 -1
  118. package/dist-server/src/store/knowledgeBase.js +13 -1
  119. package/dist-server/src/store/lessonStore.d.ts +26 -0
  120. package/dist-server/src/store/lessonStore.d.ts.map +1 -0
  121. package/dist-server/src/store/lessonStore.js +64 -0
  122. package/dist-server/src/store/memoryStore.d.ts +118 -0
  123. package/dist-server/src/store/memoryStore.d.ts.map +1 -0
  124. package/dist-server/src/store/memoryStore.js +272 -0
  125. package/dist-server/tsconfig.server.tsbuildinfo +1 -1
  126. package/package.json +9 -1
  127. package/dist/assets/graphPopulator-B3rQxb5A.js +0 -1
  128. package/dist/assets/index-BA_J-aHx.js +0 -686
  129. package/dist/assets/index-C7vpqKVZ.css +0 -1
@@ -0,0 +1,219 @@
1
+ import initSqlJs from 'sql.js';
2
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ import { homedir } from 'node:os';
5
+ import { textSimilarity } from '../memoryScorer.js';
6
+ const DB_DIR = join(homedir(), '.modular-studio');
7
+ const MEMORY_DB_PATH = join(DB_DIR, 'memory.db');
8
+ export class SqliteAdapter {
9
+ db = null;
10
+ lastWrite = 0;
11
+ async initialize() {
12
+ const SQL = await initSqlJs();
13
+ if (!existsSync(DB_DIR)) {
14
+ mkdirSync(DB_DIR, { recursive: true, mode: 0o755 });
15
+ }
16
+ if (existsSync(MEMORY_DB_PATH)) {
17
+ const buffer = readFileSync(MEMORY_DB_PATH);
18
+ this.db = new SQL.Database(buffer);
19
+ }
20
+ else {
21
+ this.db = new SQL.Database();
22
+ }
23
+ this.createTables();
24
+ }
25
+ createTables() {
26
+ if (!this.db)
27
+ return;
28
+ this.db.run(`CREATE TABLE IF NOT EXISTS facts (
29
+ id TEXT PRIMARY KEY,
30
+ content TEXT NOT NULL,
31
+ tags TEXT NOT NULL,
32
+ type TEXT NOT NULL,
33
+ timestamp INTEGER NOT NULL,
34
+ domain TEXT NOT NULL,
35
+ granularity TEXT NOT NULL,
36
+ embedding BLOB,
37
+ owner_agent_id TEXT
38
+ )`);
39
+ // Create FTS5 table for full-text search
40
+ this.db.run(`CREATE VIRTUAL TABLE IF NOT EXISTS facts_fts USING fts5(
41
+ content,
42
+ content='facts',
43
+ content_rowid='rowid'
44
+ )`);
45
+ // Triggers to keep FTS in sync
46
+ this.db.run(`CREATE TRIGGER IF NOT EXISTS facts_ai AFTER INSERT ON facts BEGIN
47
+ INSERT INTO facts_fts(rowid, content) VALUES (new.rowid, new.content);
48
+ END`);
49
+ this.db.run(`CREATE TRIGGER IF NOT EXISTS facts_ad AFTER DELETE ON facts BEGIN
50
+ INSERT INTO facts_fts(facts_fts, rowid, content) VALUES('delete', old.rowid, old.content);
51
+ END`);
52
+ this.db.run(`CREATE TRIGGER IF NOT EXISTS facts_au AFTER UPDATE ON facts BEGIN
53
+ INSERT INTO facts_fts(facts_fts, rowid, content) VALUES('delete', old.rowid, old.content);
54
+ INSERT INTO facts_fts(rowid, content) VALUES (new.rowid, new.content);
55
+ END`);
56
+ this.saveDb();
57
+ }
58
+ saveDb() {
59
+ if (!this.db)
60
+ return;
61
+ const data = this.db.export();
62
+ const buffer = Buffer.from(data);
63
+ writeFileSync(MEMORY_DB_PATH, buffer);
64
+ this.lastWrite = Date.now();
65
+ }
66
+ async storeFact(fact) {
67
+ if (!this.db)
68
+ await this.initialize();
69
+ if (!this.db)
70
+ throw new Error('Database not initialized');
71
+ const embedding = fact.embedding ? Buffer.from(new Float32Array(fact.embedding).buffer) : null;
72
+ this.db.run(`INSERT OR REPLACE INTO facts (
73
+ id, content, tags, type, timestamp, domain, granularity, embedding, owner_agent_id
74
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
75
+ fact.id,
76
+ fact.content,
77
+ JSON.stringify(fact.tags),
78
+ fact.type,
79
+ fact.timestamp,
80
+ fact.domain,
81
+ fact.granularity,
82
+ embedding,
83
+ fact.ownerAgentId || null
84
+ ]);
85
+ this.saveDb();
86
+ }
87
+ async getFacts(options) {
88
+ if (!this.db)
89
+ await this.initialize();
90
+ if (!this.db)
91
+ return [];
92
+ let query = 'SELECT * FROM facts';
93
+ const params = [];
94
+ if (options?.domain) {
95
+ query += ' WHERE domain = ?';
96
+ params.push(options.domain);
97
+ }
98
+ query += ' ORDER BY timestamp DESC';
99
+ if (options?.limit) {
100
+ query += ' LIMIT ?';
101
+ params.push(options.limit);
102
+ if (options.offset) {
103
+ query += ' OFFSET ?';
104
+ params.push(options.offset);
105
+ }
106
+ }
107
+ const result = this.db.exec(query, params);
108
+ if (result.length === 0)
109
+ return [];
110
+ return result[0].values.map(row => this.rowToFact(row));
111
+ }
112
+ rowToFact(row) {
113
+ const embedding = row[7] ? new Float32Array(new Uint8Array(row[7]).buffer) : undefined;
114
+ return {
115
+ id: row[0],
116
+ content: row[1],
117
+ tags: JSON.parse(row[2]),
118
+ type: row[3],
119
+ timestamp: row[4],
120
+ domain: row[5],
121
+ granularity: row[6],
122
+ embedding: embedding ? Array.from(embedding) : undefined,
123
+ ownerAgentId: row[8] || undefined
124
+ };
125
+ }
126
+ async searchFacts(query, k = 5) {
127
+ if (!this.db)
128
+ await this.initialize();
129
+ if (!this.db)
130
+ return [];
131
+ // First try FTS5 full-text search
132
+ const ftsResult = this.db.exec(`
133
+ SELECT facts.*, rank FROM facts_fts
134
+ JOIN facts ON facts.rowid = facts_fts.rowid
135
+ WHERE facts_fts MATCH ?
136
+ ORDER BY rank
137
+ LIMIT ?
138
+ `, [query, k]);
139
+ if (ftsResult.length > 0) {
140
+ return ftsResult[0].values.map(row => ({
141
+ ...this.rowToFact(row),
142
+ score: 1.0 - row[9] * 0.1 // Convert rank to score
143
+ }));
144
+ }
145
+ // Fallback to similarity search
146
+ const allFacts = await this.getFacts();
147
+ const scored = allFacts
148
+ .map(fact => ({
149
+ ...fact,
150
+ score: textSimilarity(fact.content, query)
151
+ }))
152
+ .filter(fact => fact.score > 0.1)
153
+ .sort((a, b) => b.score - a.score)
154
+ .slice(0, k);
155
+ return scored;
156
+ }
157
+ async deleteFact(id) {
158
+ if (!this.db)
159
+ await this.initialize();
160
+ if (!this.db)
161
+ return;
162
+ this.db.run('DELETE FROM facts WHERE id = ?', [id]);
163
+ this.saveDb();
164
+ }
165
+ async updateFact(id, patch) {
166
+ if (!this.db)
167
+ await this.initialize();
168
+ if (!this.db)
169
+ return;
170
+ const updates = [];
171
+ const params = [];
172
+ if (patch.content !== undefined) {
173
+ updates.push('content = ?');
174
+ params.push(patch.content);
175
+ }
176
+ if (patch.tags !== undefined) {
177
+ updates.push('tags = ?');
178
+ params.push(JSON.stringify(patch.tags));
179
+ }
180
+ if (patch.type !== undefined) {
181
+ updates.push('type = ?');
182
+ params.push(patch.type);
183
+ }
184
+ if (patch.domain !== undefined) {
185
+ updates.push('domain = ?');
186
+ params.push(patch.domain);
187
+ }
188
+ if (patch.embedding !== undefined) {
189
+ updates.push('embedding = ?');
190
+ const embedding = patch.embedding ? Buffer.from(new Float32Array(patch.embedding).buffer) : null;
191
+ params.push(embedding);
192
+ }
193
+ if (updates.length === 0)
194
+ return;
195
+ params.push(id);
196
+ this.db.run(`UPDATE facts SET ${updates.join(', ')} WHERE id = ?`, params);
197
+ this.saveDb();
198
+ }
199
+ async getHealth() {
200
+ if (!this.db)
201
+ await this.initialize();
202
+ if (!this.db)
203
+ return { status: 'error', factCount: 0 };
204
+ const result = this.db.exec('SELECT COUNT(*) FROM facts');
205
+ const factCount = result[0]?.values[0]?.[0] ?? 0;
206
+ return {
207
+ status: 'healthy',
208
+ factCount,
209
+ lastWrite: this.lastWrite || undefined
210
+ };
211
+ }
212
+ async close() {
213
+ if (this.db) {
214
+ this.saveDb();
215
+ this.db.close();
216
+ this.db = null;
217
+ }
218
+ }
219
+ }
@@ -0,0 +1,22 @@
1
+ import type { Fact } from '../../../src/store/memoryStore.js';
2
+ export interface StorageAdapter {
3
+ initialize(): Promise<void>;
4
+ storeFact(fact: Fact): Promise<void>;
5
+ getFacts(options?: {
6
+ domain?: string;
7
+ limit?: number;
8
+ offset?: number;
9
+ }): Promise<Fact[]>;
10
+ searchFacts(query: string, k?: number): Promise<Array<Fact & {
11
+ score: number;
12
+ }>>;
13
+ deleteFact(id: string): Promise<void>;
14
+ updateFact(id: string, patch: Partial<Fact>): Promise<void>;
15
+ getHealth(): Promise<{
16
+ status: string;
17
+ factCount: number;
18
+ lastWrite?: number;
19
+ }>;
20
+ close(): Promise<void>;
21
+ }
22
+ //# sourceMappingURL=storageAdapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storageAdapter.d.ts","sourceRoot":"","sources":["../../../../server/services/adapters/storageAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,mCAAmC,CAAC;AAE9D,MAAM,WAAW,cAAc;IAC7B,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,SAAS,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,QAAQ,CAAC,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IAC1F,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,GAAG;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC;IACjF,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5D,SAAS,IAAI,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAChF,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB"}
@@ -292,4 +292,3 @@ export async function runAgent(config, onProgress) {
292
292
  };
293
293
  }
294
294
  }
295
- //# sourceMappingURL=agentRunner.js.map
@@ -1,7 +1,8 @@
1
1
  /**
2
- * Agent Store — Persistent agent state on disk
3
- * Directory: ~/.modular-studio/agents/
4
- * Each agent: {id}.json containing full state snapshot
2
+ * Agent Store — Persistent agent state on disk with versioning
3
+ * Directory: ~/.modular-studio/agents/{agentId}/
4
+ * Latest state: latest.json
5
+ * Versions: versions/{timestamp}-v{major}.{minor}.{patch}.json
5
6
  */
6
7
  export interface SavedAgentState {
7
8
  id: string;
@@ -27,13 +28,28 @@ export interface SavedAgentState {
27
28
  outputFormats: string[];
28
29
  tokenBudget: number;
29
30
  prompt: string;
31
+ selectedModel: string;
32
+ }
33
+ export interface AgentVersion {
34
+ id: string;
35
+ version: string;
36
+ timestamp: number;
37
+ label?: string;
38
+ changeSummary?: string;
39
+ snapshot: SavedAgentState;
30
40
  }
31
41
  export interface AgentSummary {
32
42
  id: string;
33
43
  agentMeta: SavedAgentState['agentMeta'];
34
44
  savedAt: string;
45
+ currentVersion: string;
35
46
  }
36
47
  export declare function saveAgent(id: string, state: SavedAgentState): void;
48
+ export declare function createAgentVersion(id: string, version: string, label?: string, changeSummary?: string): AgentVersion | null;
49
+ export declare function listAgentVersions(id: string): AgentVersion[];
50
+ export declare function getAgentVersion(id: string, version: string): AgentVersion | null;
51
+ export declare function restoreAgentVersion(id: string, version: string): boolean;
52
+ export declare function deleteAgentVersion(id: string, version: string): boolean;
37
53
  export declare function loadAgent(id: string): SavedAgentState | null;
38
54
  export declare function listAgents(): AgentSummary[];
39
55
  export declare function deleteAgent(id: string): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"agentStore.d.ts","sourceRoot":"","sources":["../../../server/services/agentStore.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAmBH,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE;QACT,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,EAAE,CAAC;QACf,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC1C,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IACzC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IACpC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IACtC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IAClC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IACtC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,eAAe,CAAC,WAAW,CAAC,CAAC;IACxC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,GAAG,IAAI,CAKlE;AAED,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAQ5D;AAED,wBAAgB,UAAU,IAAI,YAAY,EAAE,CAiB3C;AAED,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAK/C"}
1
+ {"version":3,"file":"agentStore.d.ts","sourceRoot":"","sources":["../../../server/services/agentStore.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA4BH,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE;QACT,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,EAAE,CAAC;QACf,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC1C,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IACzC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IACpC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IACtC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IAClC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IACtC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,eAAe,CAAC;CAC3B;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,eAAe,CAAC,WAAW,CAAC,CAAC;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,GAAG,IAAI,CAQlE;AAED,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAsB3H;AAED,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,YAAY,EAAE,CAiB5D;AAED,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAGhF;AAED,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAMxE;AAED,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAavE;AAED,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAQ5D;AAED,wBAAgB,UAAU,IAAI,YAAY,EAAE,CAyB3C;AAED,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CA2B/C"}
@@ -1,27 +1,97 @@
1
1
  /**
2
- * Agent Store — Persistent agent state on disk
3
- * Directory: ~/.modular-studio/agents/
4
- * Each agent: {id}.json containing full state snapshot
2
+ * Agent Store — Persistent agent state on disk with versioning
3
+ * Directory: ~/.modular-studio/agents/{agentId}/
4
+ * Latest state: latest.json
5
+ * Versions: versions/{timestamp}-v{major}.{minor}.{patch}.json
5
6
  */
6
7
  import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync, readdirSync } from 'node:fs';
7
8
  import { join } from 'node:path';
8
9
  import { homedir } from 'node:os';
9
10
  const AGENTS_DIR = join(homedir(), '.modular-studio', 'agents');
10
- function ensureDir() {
11
- if (!existsSync(AGENTS_DIR)) {
12
- mkdirSync(AGENTS_DIR, { recursive: true, mode: 0o755 });
11
+ function ensureDir(path) {
12
+ const dir = path || AGENTS_DIR;
13
+ if (!existsSync(dir)) {
14
+ mkdirSync(dir, { recursive: true, mode: 0o755 });
13
15
  }
14
16
  }
15
- function agentPath(id) {
17
+ function agentDir(id) {
16
18
  const safe = id.replace(/[^a-zA-Z0-9_-]/g, '_');
17
- return join(AGENTS_DIR, `${safe}.json`);
19
+ return join(AGENTS_DIR, safe);
20
+ }
21
+ function agentPath(id) {
22
+ return join(agentDir(id), 'latest.json');
23
+ }
24
+ function versionsDir(id) {
25
+ return join(agentDir(id), 'versions');
18
26
  }
19
27
  export function saveAgent(id, state) {
20
- ensureDir();
28
+ const dir = agentDir(id);
29
+ ensureDir(dir);
21
30
  state.id = id;
22
31
  state.savedAt = new Date().toISOString();
23
32
  writeFileSync(agentPath(id), JSON.stringify(state, null, 2), 'utf-8');
24
33
  }
34
+ export function createAgentVersion(id, version, label, changeSummary) {
35
+ const current = loadAgent(id);
36
+ if (!current)
37
+ return null;
38
+ const dir = versionsDir(id);
39
+ ensureDir(dir);
40
+ const timestamp = Date.now();
41
+ const versionData = {
42
+ id: `${timestamp}-${version.replace(/\./g, '_')}`,
43
+ version,
44
+ timestamp,
45
+ label,
46
+ changeSummary,
47
+ snapshot: current,
48
+ };
49
+ const filename = `${timestamp}-v${version.replace(/\./g, '_')}.json`;
50
+ const path = join(dir, filename);
51
+ writeFileSync(path, JSON.stringify(versionData, null, 2), 'utf-8');
52
+ return versionData;
53
+ }
54
+ export function listAgentVersions(id) {
55
+ const dir = versionsDir(id);
56
+ if (!existsSync(dir))
57
+ return [];
58
+ const files = readdirSync(dir).filter(f => f.endsWith('.json'));
59
+ const versions = [];
60
+ for (const file of files) {
61
+ try {
62
+ const data = JSON.parse(readFileSync(join(dir, file), 'utf-8'));
63
+ versions.push(data);
64
+ }
65
+ catch {
66
+ // skip corrupt files
67
+ }
68
+ }
69
+ return versions.sort((a, b) => a.timestamp - b.timestamp);
70
+ }
71
+ export function getAgentVersion(id, version) {
72
+ const versions = listAgentVersions(id);
73
+ return versions.find(v => v.version === version) || null;
74
+ }
75
+ export function restoreAgentVersion(id, version) {
76
+ const versionData = getAgentVersion(id, version);
77
+ if (!versionData)
78
+ return false;
79
+ saveAgent(id, versionData.snapshot);
80
+ return true;
81
+ }
82
+ export function deleteAgentVersion(id, version) {
83
+ const versions = listAgentVersions(id);
84
+ const target = versions.find(v => v.version === version);
85
+ if (!target)
86
+ return false;
87
+ const dir = versionsDir(id);
88
+ const files = readdirSync(dir);
89
+ const targetFile = files.find(f => f.includes(version.replace(/\./g, '_')));
90
+ if (!targetFile)
91
+ return false;
92
+ unlinkSync(join(dir, targetFile));
93
+ return true;
94
+ }
25
95
  export function loadAgent(id) {
26
96
  const p = agentPath(id);
27
97
  if (!existsSync(p))
@@ -35,28 +105,52 @@ export function loadAgent(id) {
35
105
  }
36
106
  export function listAgents() {
37
107
  ensureDir();
38
- const files = readdirSync(AGENTS_DIR).filter((f) => f.endsWith('.json'));
108
+ const dirs = readdirSync(AGENTS_DIR, { withFileTypes: true })
109
+ .filter(d => d.isDirectory())
110
+ .map(d => d.name);
39
111
  const summaries = [];
40
- for (const file of files) {
112
+ for (const dir of dirs) {
41
113
  try {
42
- const raw = JSON.parse(readFileSync(join(AGENTS_DIR, file), 'utf-8'));
43
- summaries.push({
44
- id: raw.id ?? file.replace('.json', ''),
45
- agentMeta: raw.agentMeta ?? { name: '', description: '', icon: 'brain', category: 'general', tags: [], avatar: 'bot' },
46
- savedAt: raw.savedAt ?? '',
47
- });
114
+ const agent = loadAgent(dir);
115
+ if (agent) {
116
+ summaries.push({
117
+ id: agent.id,
118
+ agentMeta: agent.agentMeta,
119
+ savedAt: agent.savedAt,
120
+ currentVersion: agent.version || '0.1.0',
121
+ });
122
+ }
48
123
  }
49
124
  catch {
50
- // skip corrupt files
125
+ // skip corrupt agents
51
126
  }
52
127
  }
53
128
  return summaries;
54
129
  }
55
130
  export function deleteAgent(id) {
56
- const p = agentPath(id);
57
- if (!existsSync(p))
131
+ const dir = agentDir(id);
132
+ if (!existsSync(dir))
58
133
  return false;
59
- unlinkSync(p);
60
- return true;
134
+ try {
135
+ // Delete all version files
136
+ const vDir = versionsDir(id);
137
+ if (existsSync(vDir)) {
138
+ const files = readdirSync(vDir);
139
+ for (const file of files) {
140
+ unlinkSync(join(vDir, file));
141
+ }
142
+ unlinkSync(vDir);
143
+ }
144
+ // Delete latest.json
145
+ const latestPath = agentPath(id);
146
+ if (existsSync(latestPath)) {
147
+ unlinkSync(latestPath);
148
+ }
149
+ // Delete directory
150
+ unlinkSync(dir);
151
+ return true;
152
+ }
153
+ catch {
154
+ return false;
155
+ }
61
156
  }
62
- //# sourceMappingURL=agentStore.js.map
@@ -65,4 +65,3 @@ export function localSourceId(repoPath) {
65
65
  const sanitized = repoPath.replace(/[\\/]/g, '-').replace(/[^a-zA-Z0-9-]/g, '').replace(/-+/g, '-').replace(/^-|-$/g, '');
66
66
  return `local-${sanitized}`.toLowerCase();
67
67
  }
68
- //# sourceMappingURL=contentStore.js.map
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Correction Detector — identifies when a user is correcting the assistant.
3
+ *
4
+ * Two signal types:
5
+ * direct — regex patterns: "no", "wrong", "not like that", "actually", "instead", "I said"
6
+ * rephrase — consecutive user messages with cosine similarity > 0.85
7
+ */
8
+ export interface CorrectionSignal {
9
+ type: 'direct' | 'rephrase' | 'override';
10
+ confidence: number;
11
+ userMessage: string;
12
+ previousAssistant: string;
13
+ correctedBehavior: string;
14
+ }
15
+ /** Sync direct-signal detection — regex only, no async needed. */
16
+ export declare function detectCorrection(userMessage: string, previousAssistant: string): CorrectionSignal | null;
17
+ /**
18
+ * Async rephrase detection — cosine similarity > 0.85 between consecutive user messages.
19
+ * Falls back to null if embeddings are unavailable.
20
+ */
21
+ export declare function detectRephrase(userMessage: string, previousAssistant: string, previousUserMessage: string): Promise<CorrectionSignal | null>;
22
+ //# sourceMappingURL=correctionDetector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"correctionDetector.d.ts","sourceRoot":"","sources":["../../../server/services/correctionDetector.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,QAAQ,GAAG,UAAU,GAAG,UAAU,CAAC;IACzC,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAoDD,kEAAkE;AAClE,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,MAAM,EACnB,iBAAiB,EAAE,MAAM,GACxB,gBAAgB,GAAG,IAAI,CAiBzB;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAClC,WAAW,EAAE,MAAM,EACnB,iBAAiB,EAAE,MAAM,EACzB,mBAAmB,EAAE,MAAM,GAC1B,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAelC"}
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Correction Detector — identifies when a user is correcting the assistant.
3
+ *
4
+ * Two signal types:
5
+ * direct — regex patterns: "no", "wrong", "not like that", "actually", "instead", "I said"
6
+ * rephrase — consecutive user messages with cosine similarity > 0.85
7
+ */
8
+ const PATTERNS = [
9
+ { pattern: /^\s*no[,.]?\s/i, type: 'direct', confidence: 0.9 },
10
+ { pattern: /\b(wrong|that'?s wrong|not right|incorrect)\b/i, type: 'direct', confidence: 0.9 },
11
+ { pattern: /\bnot like that\b/i, type: 'direct', confidence: 0.95 },
12
+ { pattern: /\bactually[,]?\s/i, type: 'rephrase', confidence: 0.75 },
13
+ { pattern: /\binstead[,]?\s/i, type: 'override', confidence: 0.8 },
14
+ { pattern: /\bi said\b/i, type: 'override', confidence: 0.85 },
15
+ { pattern: /\bi meant\b/i, type: 'rephrase', confidence: 0.85 },
16
+ ];
17
+ function extractCorrectedBehavior(userMessage) {
18
+ const trimmed = userMessage.trim();
19
+ return trimmed.length > 200 ? trimmed.slice(0, 200) + '…' : trimmed;
20
+ }
21
+ function cosineSim(a, b) {
22
+ let dot = 0, na = 0, nb = 0;
23
+ for (let i = 0; i < a.length; i++) {
24
+ dot += a[i] * b[i];
25
+ na += a[i] * a[i];
26
+ nb += b[i] * b[i];
27
+ }
28
+ const denom = Math.sqrt(na) * Math.sqrt(nb);
29
+ return denom === 0 ? 0 : dot / denom;
30
+ }
31
+ async function fetchEmbedding(text) {
32
+ try {
33
+ const res = await fetch('/api/knowledge/embed', {
34
+ method: 'POST',
35
+ headers: { 'Content-Type': 'application/json' },
36
+ body: JSON.stringify({ texts: [text] }),
37
+ });
38
+ if (!res.ok)
39
+ return null;
40
+ const raw = await res.json();
41
+ if (typeof raw !== 'object' || raw === null || !('embeddings' in raw))
42
+ return null;
43
+ const embs = raw.embeddings;
44
+ if (!Array.isArray(embs) || !Array.isArray(embs[0]))
45
+ return null;
46
+ return embs[0];
47
+ }
48
+ catch {
49
+ return null;
50
+ }
51
+ }
52
+ /** Sync direct-signal detection — regex only, no async needed. */
53
+ export function detectCorrection(userMessage, previousAssistant) {
54
+ if (!previousAssistant)
55
+ return null;
56
+ for (const rule of PATTERNS) {
57
+ rule.pattern.lastIndex = 0;
58
+ if (rule.pattern.test(userMessage)) {
59
+ return {
60
+ type: rule.type,
61
+ confidence: rule.confidence,
62
+ userMessage,
63
+ previousAssistant,
64
+ correctedBehavior: extractCorrectedBehavior(userMessage),
65
+ };
66
+ }
67
+ }
68
+ return null;
69
+ }
70
+ /**
71
+ * Async rephrase detection — cosine similarity > 0.85 between consecutive user messages.
72
+ * Falls back to null if embeddings are unavailable.
73
+ */
74
+ export async function detectRephrase(userMessage, previousAssistant, previousUserMessage) {
75
+ const [embA, embB] = await Promise.all([
76
+ fetchEmbedding(userMessage),
77
+ fetchEmbedding(previousUserMessage),
78
+ ]);
79
+ if (!embA || !embB)
80
+ return null;
81
+ const sim = cosineSim(embA, embB);
82
+ if (sim <= 0.85)
83
+ return null;
84
+ return {
85
+ type: 'rephrase',
86
+ confidence: sim,
87
+ userMessage,
88
+ previousAssistant,
89
+ correctedBehavior: extractCorrectedBehavior(userMessage),
90
+ };
91
+ }
@@ -23,6 +23,8 @@ declare class EmbeddingServiceImpl implements EmbeddingService {
23
23
  private cache;
24
24
  private maxCacheSize;
25
25
  initialize(): Promise<void>;
26
+ private static readonly MAX_RETRIES;
27
+ private static readonly RETRY_DELAYS_MS;
26
28
  private _doInitialize;
27
29
  isReady(): boolean;
28
30
  private hashText;
@@ -1 +1 @@
1
- {"version":3,"file":"embeddingService.d.ts","sourceRoot":"","sources":["../../../server/services/embeddingService.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,MAAM,WAAW,gBAAgB;IAC/B,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACvC,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACjD,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC;IAC7C,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAC,EAAE,CAAC;IAC3F,OAAO,IAAI,OAAO,CAAC;CACpB;AAOD,cAAM,oBAAqB,YAAW,gBAAgB;IACpD,OAAO,CAAC,KAAK,CAAa;IAC1B,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,WAAW,CAA8B;IAGjD,OAAO,CAAC,KAAK,CAAiC;IAC9C,OAAO,CAAC,YAAY,CAAS;IAEvB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;YASnB,aAAa;IAyB3B,OAAO,IAAI,OAAO;IAIlB,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,qBAAqB;YAgBf,MAAM;IA0Cd,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAQ5C,4EAA4E;IAC5E,OAAO,CAAC,aAAa,CAAQ;IAE7B,OAAO,CAAC,gBAAgB;IAIlB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;IA2DtD,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM;IA4B5C,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAC,EAAE;IAgBpF,SAAS;;;;;;;CAUhB;AAGD,QAAA,MAAM,gBAAgB,sBAA6B,CAAC;AAEpD,4CAA4C;AAC5C,wBAAgB,gBAAgB,IAAI,IAAI,CAKvC;AAED,OAAO,EAAE,gBAAgB,EAAE,CAAC;AAC5B,eAAe,gBAAgB,CAAC"}
1
+ {"version":3,"file":"embeddingService.d.ts","sourceRoot":"","sources":["../../../server/services/embeddingService.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,MAAM,WAAW,gBAAgB;IAC/B,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACvC,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACjD,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC;IAC7C,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAC,EAAE,CAAC;IAC3F,OAAO,IAAI,OAAO,CAAC;CACpB;AAOD,cAAM,oBAAqB,YAAW,gBAAgB;IACpD,OAAO,CAAC,KAAK,CAAa;IAC1B,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,WAAW,CAA8B;IAGjD,OAAO,CAAC,KAAK,CAAiC;IAC9C,OAAO,CAAC,YAAY,CAAS;IAEvB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IASjC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAK;IACxC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAuB;YAEhD,aAAa;IAoC3B,OAAO,IAAI,OAAO;IAIlB,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,qBAAqB;YAgBf,MAAM;IA0Cd,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAQ5C,4EAA4E;IAC5E,OAAO,CAAC,aAAa,CAAQ;IAE7B,OAAO,CAAC,gBAAgB;IAIlB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;IA2DtD,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM;IA4B5C,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAC,EAAE;IAgBpF,SAAS;;;;;;;CAUhB;AAGD,QAAA,MAAM,gBAAgB,sBAA6B,CAAC;AAEpD,4CAA4C;AAC5C,wBAAgB,gBAAgB,IAAI,IAAI,CAKvC;AAED,OAAO,EAAE,gBAAgB,EAAE,CAAC;AAC5B,eAAe,gBAAgB,CAAC"}