ai-vault 3.0.0 → 3.0.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"scheduler.d.ts","sourceRoot":"","sources":["../../src/utils/scheduler.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAI3D,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,OAAO,CAAS;;IAQxB;;OAEG;IACH,OAAO,CAAC,UAAU;IAuBlB;;OAEG;IACG,OAAO,CAAC,QAAQ,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAYtD;;OAEG;IACG,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQlD;;OAEG;IACG,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAQvD;;OAEG;IACG,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;IAU1D;;OAEG;YACW,WAAW;IAkCzB;;OAEG;YACW,aAAa;IAuC3B;;OAEG;YACW,eAAe;IAW7B;;OAEG;YACW,cAAc;IAS5B;;OAEG;YACW,cAAc;IA4B5B;;OAEG;YACW,gBAAgB;IAU9B;;OAEG;YACW,kBAAkB;IAWhC;;OAEG;YACW,iBAAiB;IAqB/B;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAgC3B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IA0B3B;;OAEG;IACH,OAAO,CAAC,SAAS;CAIlB"}
1
+ {"version":3,"file":"scheduler.d.ts","sourceRoot":"","sources":["../../src/utils/scheduler.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAQH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAI3D,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,OAAO,CAAS;;IAQxB;;OAEG;IACH,OAAO,CAAC,UAAU;IA+ClB;;OAEG;IACG,OAAO,CAAC,QAAQ,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAYtD;;OAEG;IACG,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQlD;;OAEG;IACG,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAQvD;;OAEG;IACG,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;IAU1D;;OAEG;YACW,WAAW;IAkCzB;;OAEG;YACW,aAAa;IAuC3B;;OAEG;YACW,eAAe;IAW7B;;OAEG;YACW,cAAc;IAS5B;;OAEG;YACW,cAAc;IA4B5B;;OAEG;YACW,gBAAgB;IAU9B;;OAEG;YACW,kBAAkB;IAWhC;;OAEG;YACW,iBAAiB;IAqB/B;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAgC3B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IA0B3B;;OAEG;IACH,OAAO,CAAC,SAAS;CAIlB"}
@@ -8,6 +8,7 @@ import { exec, execSync } from 'child_process';
8
8
  import { promisify } from 'util';
9
9
  import { platform } from 'os';
10
10
  import fs from 'fs/promises';
11
+ import fsSync from 'fs';
11
12
  import path from 'path';
12
13
  const execAsync = promisify(exec);
13
14
  export class Scheduler {
@@ -29,6 +30,29 @@ export class Scheduler {
29
30
  }
30
31
  // Get the full path to the installed binary
31
32
  // This is important for cron jobs which don't have the same PATH
33
+ // First, try to resolve from the current script location
34
+ // This works for both npm global installs and local installs
35
+ try {
36
+ const scriptPath = process.argv[1];
37
+ if (scriptPath && path.isAbsolute(scriptPath)) {
38
+ // For npm global installs, the script is typically in a bin directory
39
+ // We need to find the symlink that points to it
40
+ const binDir = path.dirname(scriptPath);
41
+ const possibleBinPath = path.join(binDir, 'ai-vault');
42
+ // Check if this is a valid executable
43
+ try {
44
+ fsSync.accessSync(possibleBinPath, fsSync.constants.X_OK);
45
+ return possibleBinPath;
46
+ }
47
+ catch {
48
+ // Not executable or doesn't exist at this path
49
+ }
50
+ }
51
+ }
52
+ catch {
53
+ // process.argv[1] not available or invalid
54
+ }
55
+ // Try which/where command
32
56
  try {
33
57
  const command = this.platform === 'win32' ? 'where ai-vault' : 'which ai-vault';
34
58
  const result = execSync(command, {
@@ -1 +1 @@
1
- {"version":3,"file":"scheduler.js","sourceRoot":"","sources":["../../src/utils/scheduler.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"scheduler.js","sourceRoot":"","sources":["../../src/utils/scheduler.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-vault",
3
- "version": "3.0.0",
3
+ "version": "3.0.1",
4
4
  "description": "Own your data. Open-source CLI tool for comprehensive backup of AI interactions—conversations, images, videos, code artifacts, and metadata—across ChatGPT, Claude, Grok, Gemini, and more.",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -9,6 +9,7 @@
9
9
  },
10
10
  "files": [
11
11
  "dist/**/*",
12
+ "ui/dist/**/*",
12
13
  "README.md",
13
14
  "LICENSE"
14
15
  ],
@@ -30,9 +31,13 @@
30
31
  "format": "prettier --write \"src/**/*.ts\" \"*.md\" \"*.json\" \"*.yml\"",
31
32
  "format:check": "prettier --check \"src/**/*.ts\" \"*.md\" \"*.json\" \"*.yml\"",
32
33
  "test": "vitest run",
34
+ "test:unit": "vitest run --config vitest.config.ts",
35
+ "test:integration": "vitest run --config vitest.config.integration.ts",
36
+ "test:all": "pnpm run test:unit && pnpm run test:integration",
33
37
  "test:watch": "vitest watch",
34
38
  "test:ui": "vitest --ui",
35
39
  "test:coverage": "vitest run --coverage",
40
+ "test:coverage:integration": "vitest run --config vitest.config.integration.ts --coverage",
36
41
  "prepare": "husky",
37
42
  "postinstall": "playwright install chromium --with-deps || echo 'Note: Run pnpm exec playwright install chromium if browser installation failed'",
38
43
  "prepublishOnly": "pnpm run build",
@@ -91,6 +96,7 @@
91
96
  "@vitest/coverage-v8": "^4.0.4",
92
97
  "@vitest/ui": "^4.0.4",
93
98
  "eslint": "^9.38.0",
99
+ "execa": "^9.6.0",
94
100
  "globals": "^16.4.0",
95
101
  "husky": "^9.1.7",
96
102
  "lint-staged": "^16.2.6",
@@ -0,0 +1,566 @@
1
+ /**
2
+ * AI Vault Web UI
3
+ * Lightweight vanilla JavaScript SPA
4
+ */
5
+
6
+ const API_BASE = window.location.origin + '/api';
7
+
8
+ class App {
9
+ constructor() {
10
+ this.currentPage = 'dashboard';
11
+ this.currentOffset = 0;
12
+ this.currentLimit = 50;
13
+ this.init();
14
+ }
15
+
16
+ async init() {
17
+ // Setup navigation
18
+ document.querySelectorAll('.nav-link').forEach((link) => {
19
+ link.addEventListener('click', (e) => {
20
+ e.preventDefault();
21
+ const page = link.dataset.page;
22
+ this.navigateTo(page);
23
+ });
24
+ });
25
+
26
+ // Setup search on enter
27
+ const searchInput = document.getElementById('search-input');
28
+ if (searchInput) {
29
+ searchInput.addEventListener('keypress', (e) => {
30
+ if (e.key === 'Enter') {
31
+ this.performSearch();
32
+ }
33
+ });
34
+ }
35
+
36
+ // Setup filters
37
+ const providerFilter = document.getElementById('provider-filter');
38
+ const sortFilter = document.getElementById('sort-filter');
39
+ if (providerFilter && sortFilter) {
40
+ providerFilter.addEventListener('change', () => this.loadConversations());
41
+ sortFilter.addEventListener('change', () => this.loadConversations());
42
+ }
43
+
44
+ // Load initial data
45
+ await this.loadDashboard();
46
+ }
47
+
48
+ navigateTo(page) {
49
+ // Update nav links
50
+ document.querySelectorAll('.nav-link').forEach((link) => {
51
+ link.classList.remove('active');
52
+ if (link.dataset.page === page) {
53
+ link.classList.add('active');
54
+ }
55
+ });
56
+
57
+ // Update pages
58
+ document.querySelectorAll('.page').forEach((p) => {
59
+ p.classList.remove('active');
60
+ });
61
+ document.getElementById(`${page}-page`).classList.add('active');
62
+
63
+ this.currentPage = page;
64
+
65
+ // Load page data
66
+ switch (page) {
67
+ case 'dashboard':
68
+ this.loadDashboard();
69
+ break;
70
+ case 'conversations':
71
+ this.loadConversations();
72
+ break;
73
+ case 'search':
74
+ // Search is interactive
75
+ break;
76
+ case 'media':
77
+ this.loadMedia();
78
+ break;
79
+ case 'schedules':
80
+ this.loadSchedules();
81
+ break;
82
+ case 'settings':
83
+ this.loadSettings();
84
+ break;
85
+ }
86
+ }
87
+
88
+ showLoading() {
89
+ document.getElementById('loading-overlay').classList.remove('hidden');
90
+ }
91
+
92
+ hideLoading() {
93
+ document.getElementById('loading-overlay').classList.add('hidden');
94
+ }
95
+
96
+ showToast(message, type = 'success') {
97
+ const toast = document.createElement('div');
98
+ toast.className = `toast ${type}`;
99
+ toast.textContent = message;
100
+
101
+ const container = document.getElementById('toast-container');
102
+ container.appendChild(toast);
103
+
104
+ setTimeout(() => {
105
+ toast.remove();
106
+ }, 5000);
107
+ }
108
+
109
+ async apiGet(endpoint) {
110
+ try {
111
+ const response = await fetch(`${API_BASE}${endpoint}`);
112
+ if (!response.ok) {
113
+ throw new Error(`HTTP error! status: ${response.status}`);
114
+ }
115
+ return await response.json();
116
+ } catch (error) {
117
+ console.error('API Error:', error);
118
+ this.showToast(`API Error: ${error.message}`, 'error');
119
+ throw error;
120
+ }
121
+ }
122
+
123
+ async apiPost(endpoint, data) {
124
+ try {
125
+ const response = await fetch(`${API_BASE}${endpoint}`, {
126
+ method: 'POST',
127
+ headers: {
128
+ 'Content-Type': 'application/json',
129
+ },
130
+ body: JSON.stringify(data),
131
+ });
132
+ if (!response.ok) {
133
+ throw new Error(`HTTP error! status: ${response.status}`);
134
+ }
135
+ return await response.json();
136
+ } catch (error) {
137
+ console.error('API Error:', error);
138
+ this.showToast(`API Error: ${error.message}`, 'error');
139
+ throw error;
140
+ }
141
+ }
142
+
143
+ async loadDashboard() {
144
+ this.showLoading();
145
+ try {
146
+ // Load stats
147
+ const convData = await this.apiGet('/conversations/stats');
148
+ document.getElementById('total-conversations').textContent =
149
+ convData.totalConversations || 0;
150
+ document.getElementById('total-messages').textContent = convData.totalMessages || 0;
151
+
152
+ // Load media stats
153
+ const mediaData = await this.apiGet('/media/stats');
154
+ document.getElementById('total-media').textContent = mediaData.totalFiles || 0;
155
+
156
+ // Load providers
157
+ const providersData = await this.apiGet('/providers');
158
+ document.getElementById('total-providers').textContent =
159
+ providersData.providers?.length || 0;
160
+
161
+ // Populate provider filter
162
+ const providerFilter = document.getElementById('provider-filter');
163
+ const mediaProviderFilter = document.getElementById('media-provider-filter');
164
+ providersData.providers?.forEach((provider) => {
165
+ const option = document.createElement('option');
166
+ option.value = provider.name;
167
+ option.textContent = provider.displayName || provider.name;
168
+ providerFilter.appendChild(option.cloneNode(true));
169
+ mediaProviderFilter.appendChild(option.cloneNode(true));
170
+ });
171
+
172
+ // Display providers
173
+ const providersList = document.getElementById('providers-list');
174
+ providersList.innerHTML = '';
175
+
176
+ for (const provider of providersData.providers || []) {
177
+ try {
178
+ const status = await this.apiGet(`/providers/${provider.name}/status`);
179
+ const card = document.createElement('div');
180
+ card.className = 'provider-card';
181
+ card.innerHTML = `
182
+ <h4>${status.displayName || provider.name}</h4>
183
+ <span class="status ${status.isAuthenticated ? 'connected' : 'disconnected'}">
184
+ ${status.isAuthenticated ? '✓ Connected' : '✗ Disconnected'}
185
+ </span>
186
+ <p><strong>Auth Method:</strong> ${status.authMethod}</p>
187
+ ${
188
+ convData.byProvider?.[provider.name]
189
+ ? `<p><strong>Conversations:</strong> ${convData.byProvider[provider.name].conversations}</p>`
190
+ : ''
191
+ }
192
+ `;
193
+ providersList.appendChild(card);
194
+ } catch (error) {
195
+ console.error(`Failed to load provider ${provider.name}:`, error);
196
+ }
197
+ }
198
+ } catch (error) {
199
+ console.error('Failed to load dashboard:', error);
200
+ } finally {
201
+ this.hideLoading();
202
+ }
203
+ }
204
+
205
+ async loadConversations() {
206
+ this.showLoading();
207
+ try {
208
+ const provider = document.getElementById('provider-filter').value;
209
+ const sortValue = document.getElementById('sort-filter').value;
210
+ const [sortBy, sortOrder] = sortValue.split('-');
211
+ const limit = parseInt(document.getElementById('limit-filter').value) || 50;
212
+
213
+ const params = new URLSearchParams({
214
+ offset: this.currentOffset,
215
+ limit,
216
+ sortBy,
217
+ sortOrder,
218
+ });
219
+
220
+ if (provider) {
221
+ params.append('provider', provider);
222
+ }
223
+
224
+ const data = await this.apiGet(`/conversations?${params}`);
225
+
226
+ const list = document.getElementById('conversations-list');
227
+ list.innerHTML = '';
228
+
229
+ data.conversations.forEach((conv) => {
230
+ const card = document.createElement('div');
231
+ card.className = 'conversation-card';
232
+ card.innerHTML = `
233
+ <h4>${this.escapeHtml(conv.title || 'Untitled')}</h4>
234
+ <p>${this.escapeHtml(conv.preview || 'No preview available')}</p>
235
+ <div class="meta">
236
+ <span>Provider: ${conv.provider}</span>
237
+ <span>Messages: ${conv.messageCount || 0}</span>
238
+ <span>Updated: ${new Date(conv.updatedAt).toLocaleDateString()}</span>
239
+ </div>
240
+ `;
241
+ card.addEventListener('click', () => this.showConversation(conv.provider, conv.id));
242
+ list.appendChild(card);
243
+ });
244
+
245
+ // Update pagination
246
+ document.getElementById('page-info').textContent = `Showing ${this.currentOffset + 1}-${
247
+ this.currentOffset + data.conversations.length
248
+ } of ${data.pagination.total}`;
249
+ document.getElementById('prev-btn').disabled = this.currentOffset === 0;
250
+ document.getElementById('next-btn').disabled = !data.pagination.hasMore;
251
+ } catch (error) {
252
+ console.error('Failed to load conversations:', error);
253
+ } finally {
254
+ this.hideLoading();
255
+ }
256
+ }
257
+
258
+ async showConversation(provider, id) {
259
+ this.showLoading();
260
+ try {
261
+ const data = await this.apiGet(`/conversations/${provider}/${id}`);
262
+
263
+ // Create modal or navigate to detail view
264
+ const modal = document.createElement('div');
265
+ modal.className = 'loading-overlay';
266
+ modal.style.alignItems = 'flex-start';
267
+ modal.style.overflow = 'auto';
268
+ modal.innerHTML = `
269
+ <div style="background: var(--bg); padding: 2rem; border-radius: var(--radius); max-width: 800px; width: 90%; margin: 2rem auto;">
270
+ <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 1rem;">
271
+ <h2>${this.escapeHtml(data.conversation.title || 'Untitled')}</h2>
272
+ <button class="btn" onclick="this.parentElement.parentElement.parentElement.remove()">Close</button>
273
+ </div>
274
+ <div style="margin-bottom: 1rem; color: var(--text-secondary);">
275
+ <p>Provider: ${provider}</p>
276
+ <p>Created: ${new Date(data.conversation.createdAt).toLocaleString()}</p>
277
+ <p>Updated: ${new Date(data.conversation.updatedAt).toLocaleString()}</p>
278
+ <p>Messages: ${data.conversation.messages?.length || 0}</p>
279
+ </div>
280
+ <hr style="border: none; border-top: 1px solid var(--border); margin: 1rem 0;">
281
+ <div style="white-space: pre-wrap; font-family: monospace; max-height: 60vh; overflow: auto;">
282
+ ${this.escapeHtml(data.markdown || JSON.stringify(data.conversation, null, 2))}
283
+ </div>
284
+ </div>
285
+ `;
286
+ document.body.appendChild(modal);
287
+ } catch (error) {
288
+ console.error('Failed to load conversation:', error);
289
+ } finally {
290
+ this.hideLoading();
291
+ }
292
+ }
293
+
294
+ async performSearch() {
295
+ const query = document.getElementById('search-input').value.trim();
296
+ if (!query) {
297
+ this.showToast('Please enter a search query', 'warning');
298
+ return;
299
+ }
300
+
301
+ this.showLoading();
302
+ try {
303
+ const data = await this.apiPost('/search/query', { query, limit: 50 });
304
+
305
+ const results = document.getElementById('search-results');
306
+ results.innerHTML = '';
307
+
308
+ if (data.results.length === 0) {
309
+ results.innerHTML = '<p style="text-align: center; color: var(--text-secondary);">No results found</p>';
310
+ return;
311
+ }
312
+
313
+ data.results.forEach((result) => {
314
+ const card = document.createElement('div');
315
+ card.className = 'search-result';
316
+ card.innerHTML = `
317
+ <h4>${this.escapeHtml(result.title)}</h4>
318
+ <p>${this.escapeHtml(result.preview)}</p>
319
+ <div class="meta">
320
+ <span>Provider: ${result.provider}</span>
321
+ <span>Score: ${result.score.toFixed(2)}</span>
322
+ <span>Updated: ${new Date(result.updatedAt).toLocaleDateString()}</span>
323
+ </div>
324
+ ${
325
+ result.matches.length > 0
326
+ ? `<div class="context">"...${this.escapeHtml(result.matches[0].context)}..."</div>`
327
+ : ''
328
+ }
329
+ `;
330
+ card.style.cursor = 'pointer';
331
+ card.addEventListener('click', () => this.showConversation(result.provider, result.id));
332
+ results.appendChild(card);
333
+ });
334
+
335
+ this.showToast(`Found ${data.results.length} results`, 'success');
336
+ } catch (error) {
337
+ console.error('Search failed:', error);
338
+ } finally {
339
+ this.hideLoading();
340
+ }
341
+ }
342
+
343
+ async loadMedia() {
344
+ this.showLoading();
345
+ try {
346
+ // Load media stats
347
+ const statsData = await this.apiGet('/media/stats');
348
+ const statsGrid = document.getElementById('media-stats');
349
+ statsGrid.innerHTML = `
350
+ <div class="stat-card">
351
+ <div class="stat-label">Total Files</div>
352
+ <div class="stat-value">${statsData.totalFiles || 0}</div>
353
+ </div>
354
+ <div class="stat-card">
355
+ <div class="stat-label">Total Size</div>
356
+ <div class="stat-value">${this.formatBytes(statsData.totalSize || 0)}</div>
357
+ </div>
358
+ `;
359
+
360
+ // Load media list
361
+ const provider = document.getElementById('media-provider-filter').value;
362
+ const type = document.getElementById('media-type-filter').value;
363
+
364
+ const params = new URLSearchParams({ limit: 100 });
365
+ if (provider) params.append('provider', provider);
366
+ if (type) params.append('type', type);
367
+
368
+ const data = await this.apiGet(`/media?${params}`);
369
+
370
+ const mediaList = document.getElementById('media-list');
371
+ mediaList.innerHTML = '';
372
+
373
+ data.media.forEach((item) => {
374
+ const mediaItem = document.createElement('div');
375
+ mediaItem.className = 'media-item';
376
+
377
+ if (item.type === 'image') {
378
+ mediaItem.innerHTML = `<img src="/api/media/${item.provider}/${item.hash}" alt="${item.filename || 'Image'}" />`;
379
+ } else {
380
+ mediaItem.innerHTML = `<div style="padding: 1rem; text-align: center;">${item.filename || item.type}</div>`;
381
+ }
382
+
383
+ mediaList.appendChild(mediaItem);
384
+ });
385
+ } catch (error) {
386
+ console.error('Failed to load media:', error);
387
+ } finally {
388
+ this.hideLoading();
389
+ }
390
+ }
391
+
392
+ async loadSchedules() {
393
+ this.showLoading();
394
+ try {
395
+ const data = await this.apiGet('/schedules');
396
+
397
+ const list = document.getElementById('schedules-list');
398
+ list.innerHTML = '';
399
+
400
+ if (data.schedules.length === 0) {
401
+ list.innerHTML = '<p style="text-align: center; color: var(--text-secondary);">No schedules configured</p>';
402
+ return;
403
+ }
404
+
405
+ data.schedules.forEach((schedule) => {
406
+ const card = document.createElement('div');
407
+ card.className = 'schedule-card';
408
+ card.innerHTML = `
409
+ <div class="info">
410
+ <h4>${this.escapeHtml(schedule.description)}</h4>
411
+ <p>Provider: ${schedule.provider} | Cron: ${schedule.cron}</p>
412
+ <p>Status: ${schedule.enabled ? 'Enabled' : 'Disabled'}</p>
413
+ </div>
414
+ <div class="actions">
415
+ <button class="btn" onclick="app.toggleSchedule('${schedule.id}', ${!schedule.enabled})">
416
+ ${schedule.enabled ? 'Disable' : 'Enable'}
417
+ </button>
418
+ <button class="btn" style="background: var(--danger); color: white;" onclick="app.deleteSchedule('${schedule.id}')">
419
+ Delete
420
+ </button>
421
+ </div>
422
+ `;
423
+ list.appendChild(card);
424
+ });
425
+ } catch (error) {
426
+ console.error('Failed to load schedules:', error);
427
+ } finally {
428
+ this.hideLoading();
429
+ }
430
+ }
431
+
432
+ async loadSettings() {
433
+ this.showLoading();
434
+ try {
435
+ const data = await this.apiGet('/settings/info');
436
+
437
+ const infoDiv = document.getElementById('system-info');
438
+ infoDiv.innerHTML = `
439
+ <p><strong>Version:</strong> ${data.info.version}</p>
440
+ <p><strong>Platform:</strong> ${data.info.platform} (${data.info.arch})</p>
441
+ <p><strong>Node Version:</strong> ${data.info.nodeVersion}</p>
442
+ <p><strong>Archive Directory:</strong> ${data.info.archiveDir}</p>
443
+ `;
444
+
445
+ document.getElementById('archive-dir').value = data.info.archiveDir;
446
+ } catch (error) {
447
+ console.error('Failed to load settings:', error);
448
+ } finally {
449
+ this.hideLoading();
450
+ }
451
+ }
452
+
453
+ async triggerArchive() {
454
+ const provider = prompt('Enter provider name (or leave empty for all):');
455
+
456
+ this.showLoading();
457
+ try {
458
+ const data = await this.apiPost('/archive/start', {
459
+ provider: provider || undefined,
460
+ });
461
+
462
+ this.showToast(`Archive started: ${data.operationId}`, 'success');
463
+
464
+ // Poll for completion
465
+ const checkStatus = async () => {
466
+ try {
467
+ const status = await this.apiGet(`/archive/operation/${data.operationId}`);
468
+ if (status.status === 'completed') {
469
+ this.showToast('Archive completed successfully!', 'success');
470
+ this.loadDashboard();
471
+ } else if (status.status === 'failed') {
472
+ this.showToast(`Archive failed: ${status.error}`, 'error');
473
+ } else {
474
+ setTimeout(checkStatus, 2000);
475
+ }
476
+ } catch (error) {
477
+ console.error('Failed to check archive status:', error);
478
+ }
479
+ };
480
+
481
+ setTimeout(checkStatus, 2000);
482
+ } catch (error) {
483
+ console.error('Failed to start archive:', error);
484
+ } finally {
485
+ this.hideLoading();
486
+ }
487
+ }
488
+
489
+ async rebuildSearchIndex() {
490
+ if (!confirm('Rebuild search index? This may take a few minutes.')) {
491
+ return;
492
+ }
493
+
494
+ this.showLoading();
495
+ try {
496
+ const data = await this.apiPost('/search/index', {});
497
+ this.showToast(
498
+ `Search index rebuilt: ${data.stats.documentsIndexed} documents indexed`,
499
+ 'success'
500
+ );
501
+ } catch (error) {
502
+ console.error('Failed to rebuild search index:', error);
503
+ } finally {
504
+ this.hideLoading();
505
+ }
506
+ }
507
+
508
+ async toggleSchedule(id, enable) {
509
+ this.showLoading();
510
+ try {
511
+ await this.apiPost(`/schedules/${id}/${enable ? 'enable' : 'disable'}`, {});
512
+ this.showToast(`Schedule ${enable ? 'enabled' : 'disabled'}`, 'success');
513
+ this.loadSchedules();
514
+ } catch (error) {
515
+ console.error('Failed to toggle schedule:', error);
516
+ } finally {
517
+ this.hideLoading();
518
+ }
519
+ }
520
+
521
+ async deleteSchedule(id) {
522
+ if (!confirm('Delete this schedule?')) {
523
+ return;
524
+ }
525
+
526
+ this.showLoading();
527
+ try {
528
+ await fetch(`${API_BASE}/schedules/${id}`, { method: 'DELETE' });
529
+ this.showToast('Schedule deleted', 'success');
530
+ this.loadSchedules();
531
+ } catch (error) {
532
+ console.error('Failed to delete schedule:', error);
533
+ } finally {
534
+ this.hideLoading();
535
+ }
536
+ }
537
+
538
+ prevPage() {
539
+ if (this.currentOffset > 0) {
540
+ this.currentOffset = Math.max(0, this.currentOffset - this.currentLimit);
541
+ this.loadConversations();
542
+ }
543
+ }
544
+
545
+ nextPage() {
546
+ this.currentOffset += this.currentLimit;
547
+ this.loadConversations();
548
+ }
549
+
550
+ escapeHtml(text) {
551
+ const div = document.createElement('div');
552
+ div.textContent = text;
553
+ return div.innerHTML;
554
+ }
555
+
556
+ formatBytes(bytes) {
557
+ if (bytes === 0) return '0 Bytes';
558
+ const k = 1024;
559
+ const sizes = ['Bytes', 'KB', 'MB', 'GB'];
560
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
561
+ return Math.round((bytes / Math.pow(k, i)) * 100) / 100 + ' ' + sizes[i];
562
+ }
563
+ }
564
+
565
+ // Initialize app
566
+ const app = new App();
@@ -0,0 +1,521 @@
1
+ /* AI Vault - Clean Minimal Design */
2
+
3
+ :root {
4
+ --primary: #2563eb;
5
+ --primary-dark: #1e40af;
6
+ --secondary: #64748b;
7
+ --success: #10b981;
8
+ --warning: #f59e0b;
9
+ --danger: #ef4444;
10
+ --bg: #ffffff;
11
+ --bg-secondary: #f8fafc;
12
+ --bg-tertiary: #f1f5f9;
13
+ --text: #0f172a;
14
+ --text-secondary: #64748b;
15
+ --border: #e2e8f0;
16
+ --shadow: rgba(0, 0, 0, 0.1);
17
+ --radius: 8px;
18
+ }
19
+
20
+ @media (prefers-color-scheme: dark) {
21
+ :root {
22
+ --bg: #0f172a;
23
+ --bg-secondary: #1e293b;
24
+ --bg-tertiary: #334155;
25
+ --text: #f8fafc;
26
+ --text-secondary: #94a3b8;
27
+ --border: #334155;
28
+ --shadow: rgba(0, 0, 0, 0.3);
29
+ }
30
+ }
31
+
32
+ * {
33
+ margin: 0;
34
+ padding: 0;
35
+ box-sizing: border-box;
36
+ }
37
+
38
+ body {
39
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial,
40
+ sans-serif;
41
+ background: var(--bg);
42
+ color: var(--text);
43
+ line-height: 1.6;
44
+ }
45
+
46
+ /* Navigation */
47
+ .navbar {
48
+ background: var(--bg-secondary);
49
+ border-bottom: 1px solid var(--border);
50
+ padding: 1rem 0;
51
+ position: sticky;
52
+ top: 0;
53
+ z-index: 100;
54
+ }
55
+
56
+ .nav-container {
57
+ max-width: 1200px;
58
+ margin: 0 auto;
59
+ padding: 0 2rem;
60
+ display: flex;
61
+ align-items: center;
62
+ justify-content: space-between;
63
+ }
64
+
65
+ .nav-brand h1 {
66
+ font-size: 1.5rem;
67
+ font-weight: 600;
68
+ }
69
+
70
+ .nav-links {
71
+ display: flex;
72
+ gap: 1rem;
73
+ }
74
+
75
+ .nav-link {
76
+ color: var(--text-secondary);
77
+ text-decoration: none;
78
+ padding: 0.5rem 1rem;
79
+ border-radius: var(--radius);
80
+ transition: all 0.2s;
81
+ }
82
+
83
+ .nav-link:hover {
84
+ background: var(--bg-tertiary);
85
+ color: var(--text);
86
+ }
87
+
88
+ .nav-link.active {
89
+ background: var(--primary);
90
+ color: white;
91
+ }
92
+
93
+ /* Container */
94
+ .container {
95
+ max-width: 1200px;
96
+ margin: 0 auto;
97
+ padding: 2rem;
98
+ }
99
+
100
+ /* Pages */
101
+ .page {
102
+ display: none;
103
+ }
104
+
105
+ .page.active {
106
+ display: block;
107
+ }
108
+
109
+ /* Headings */
110
+ h2 {
111
+ font-size: 2rem;
112
+ margin-bottom: 1.5rem;
113
+ font-weight: 600;
114
+ }
115
+
116
+ h3 {
117
+ font-size: 1.5rem;
118
+ margin: 2rem 0 1rem;
119
+ font-weight: 600;
120
+ }
121
+
122
+ /* Stats Grid */
123
+ .stats-grid {
124
+ display: grid;
125
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
126
+ gap: 1.5rem;
127
+ margin-bottom: 2rem;
128
+ }
129
+
130
+ .stat-card {
131
+ background: var(--bg-secondary);
132
+ border: 1px solid var(--border);
133
+ border-radius: var(--radius);
134
+ padding: 1.5rem;
135
+ box-shadow: 0 1px 3px var(--shadow);
136
+ }
137
+
138
+ .stat-label {
139
+ font-size: 0.875rem;
140
+ color: var(--text-secondary);
141
+ text-transform: uppercase;
142
+ letter-spacing: 0.05em;
143
+ margin-bottom: 0.5rem;
144
+ }
145
+
146
+ .stat-value {
147
+ font-size: 2.5rem;
148
+ font-weight: 700;
149
+ color: var(--primary);
150
+ }
151
+
152
+ /* Providers Grid */
153
+ .providers-grid {
154
+ display: grid;
155
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
156
+ gap: 1.5rem;
157
+ margin-bottom: 2rem;
158
+ }
159
+
160
+ .provider-card {
161
+ background: var(--bg-secondary);
162
+ border: 1px solid var(--border);
163
+ border-radius: var(--radius);
164
+ padding: 1.5rem;
165
+ box-shadow: 0 1px 3px var(--shadow);
166
+ }
167
+
168
+ .provider-card h4 {
169
+ font-size: 1.25rem;
170
+ margin-bottom: 0.5rem;
171
+ }
172
+
173
+ .provider-card .status {
174
+ display: inline-block;
175
+ padding: 0.25rem 0.75rem;
176
+ border-radius: 9999px;
177
+ font-size: 0.875rem;
178
+ font-weight: 500;
179
+ margin-bottom: 1rem;
180
+ }
181
+
182
+ .provider-card .status.connected {
183
+ background: #d1fae5;
184
+ color: #065f46;
185
+ }
186
+
187
+ .provider-card .status.disconnected {
188
+ background: #fee2e2;
189
+ color: #991b1b;
190
+ }
191
+
192
+ /* Buttons */
193
+ .btn {
194
+ padding: 0.75rem 1.5rem;
195
+ border: none;
196
+ border-radius: var(--radius);
197
+ font-size: 1rem;
198
+ font-weight: 500;
199
+ cursor: pointer;
200
+ transition: all 0.2s;
201
+ background: var(--bg-tertiary);
202
+ color: var(--text);
203
+ }
204
+
205
+ .btn:hover {
206
+ opacity: 0.9;
207
+ transform: translateY(-1px);
208
+ }
209
+
210
+ .btn-primary {
211
+ background: var(--primary);
212
+ color: white;
213
+ }
214
+
215
+ .btn-primary:hover {
216
+ background: var(--primary-dark);
217
+ }
218
+
219
+ .btn-secondary {
220
+ background: var(--secondary);
221
+ color: white;
222
+ }
223
+
224
+ .action-buttons {
225
+ display: flex;
226
+ gap: 1rem;
227
+ margin-top: 2rem;
228
+ }
229
+
230
+ /* Filters */
231
+ .filters {
232
+ display: flex;
233
+ gap: 1rem;
234
+ margin-bottom: 1.5rem;
235
+ flex-wrap: wrap;
236
+ }
237
+
238
+ .filter-select,
239
+ .filter-input {
240
+ padding: 0.75rem;
241
+ border: 1px solid var(--border);
242
+ border-radius: var(--radius);
243
+ background: var(--bg);
244
+ color: var(--text);
245
+ font-size: 1rem;
246
+ }
247
+
248
+ /* Conversations List */
249
+ .conversations-list {
250
+ display: flex;
251
+ flex-direction: column;
252
+ gap: 1rem;
253
+ }
254
+
255
+ .conversation-card {
256
+ background: var(--bg-secondary);
257
+ border: 1px solid var(--border);
258
+ border-radius: var(--radius);
259
+ padding: 1.5rem;
260
+ cursor: pointer;
261
+ transition: all 0.2s;
262
+ }
263
+
264
+ .conversation-card:hover {
265
+ box-shadow: 0 4px 6px var(--shadow);
266
+ transform: translateY(-2px);
267
+ }
268
+
269
+ .conversation-card h4 {
270
+ font-size: 1.125rem;
271
+ margin-bottom: 0.5rem;
272
+ }
273
+
274
+ .conversation-card .meta {
275
+ display: flex;
276
+ gap: 1rem;
277
+ font-size: 0.875rem;
278
+ color: var(--text-secondary);
279
+ margin-top: 0.5rem;
280
+ }
281
+
282
+ /* Search */
283
+ .search-box {
284
+ display: flex;
285
+ gap: 1rem;
286
+ margin-bottom: 2rem;
287
+ }
288
+
289
+ .search-input {
290
+ flex: 1;
291
+ padding: 0.75rem 1rem;
292
+ border: 1px solid var(--border);
293
+ border-radius: var(--radius);
294
+ font-size: 1rem;
295
+ background: var(--bg);
296
+ color: var(--text);
297
+ }
298
+
299
+ .search-results {
300
+ display: flex;
301
+ flex-direction: column;
302
+ gap: 1rem;
303
+ }
304
+
305
+ .search-result {
306
+ background: var(--bg-secondary);
307
+ border: 1px solid var(--border);
308
+ border-radius: var(--radius);
309
+ padding: 1.5rem;
310
+ }
311
+
312
+ .search-result h4 {
313
+ margin-bottom: 0.5rem;
314
+ }
315
+
316
+ .search-result .highlight {
317
+ background: yellow;
318
+ padding: 0 0.25rem;
319
+ }
320
+
321
+ .search-result .context {
322
+ font-size: 0.875rem;
323
+ color: var(--text-secondary);
324
+ margin-top: 0.5rem;
325
+ font-style: italic;
326
+ }
327
+
328
+ /* Media Grid */
329
+ .media-grid {
330
+ display: grid;
331
+ grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
332
+ gap: 1rem;
333
+ }
334
+
335
+ .media-item {
336
+ background: var(--bg-secondary);
337
+ border: 1px solid var(--border);
338
+ border-radius: var(--radius);
339
+ overflow: hidden;
340
+ cursor: pointer;
341
+ transition: all 0.2s;
342
+ }
343
+
344
+ .media-item:hover {
345
+ transform: scale(1.05);
346
+ box-shadow: 0 4px 6px var(--shadow);
347
+ }
348
+
349
+ .media-item img {
350
+ width: 100%;
351
+ height: 200px;
352
+ object-fit: cover;
353
+ }
354
+
355
+ /* Schedules List */
356
+ .schedules-list {
357
+ display: flex;
358
+ flex-direction: column;
359
+ gap: 1rem;
360
+ margin-top: 1.5rem;
361
+ }
362
+
363
+ .schedule-card {
364
+ background: var(--bg-secondary);
365
+ border: 1px solid var(--border);
366
+ border-radius: var(--radius);
367
+ padding: 1.5rem;
368
+ display: flex;
369
+ justify-content: space-between;
370
+ align-items: center;
371
+ }
372
+
373
+ .schedule-card .info h4 {
374
+ margin-bottom: 0.25rem;
375
+ }
376
+
377
+ .schedule-card .info p {
378
+ font-size: 0.875rem;
379
+ color: var(--text-secondary);
380
+ }
381
+
382
+ .schedule-card .actions {
383
+ display: flex;
384
+ gap: 0.5rem;
385
+ }
386
+
387
+ /* Settings */
388
+ .settings-section {
389
+ background: var(--bg-secondary);
390
+ border: 1px solid var(--border);
391
+ border-radius: var(--radius);
392
+ padding: 1.5rem;
393
+ margin-bottom: 1.5rem;
394
+ }
395
+
396
+ .input-full {
397
+ width: 100%;
398
+ padding: 0.75rem;
399
+ border: 1px solid var(--border);
400
+ border-radius: var(--radius);
401
+ background: var(--bg);
402
+ color: var(--text);
403
+ font-size: 1rem;
404
+ margin-bottom: 1rem;
405
+ }
406
+
407
+ /* Pagination */
408
+ .pagination {
409
+ display: flex;
410
+ justify-content: space-between;
411
+ align-items: center;
412
+ margin-top: 2rem;
413
+ }
414
+
415
+ /* Loading */
416
+ .loading-overlay {
417
+ position: fixed;
418
+ top: 0;
419
+ left: 0;
420
+ right: 0;
421
+ bottom: 0;
422
+ background: rgba(0, 0, 0, 0.5);
423
+ display: flex;
424
+ flex-direction: column;
425
+ align-items: center;
426
+ justify-content: center;
427
+ z-index: 1000;
428
+ }
429
+
430
+ .loading-overlay.hidden {
431
+ display: none;
432
+ }
433
+
434
+ .loading-spinner {
435
+ width: 50px;
436
+ height: 50px;
437
+ border: 4px solid var(--bg-tertiary);
438
+ border-top-color: var(--primary);
439
+ border-radius: 50%;
440
+ animation: spin 1s linear infinite;
441
+ }
442
+
443
+ @keyframes spin {
444
+ to {
445
+ transform: rotate(360deg);
446
+ }
447
+ }
448
+
449
+ .loading-text {
450
+ color: white;
451
+ font-size: 1.125rem;
452
+ margin-top: 1rem;
453
+ }
454
+
455
+ /* Toast */
456
+ .toast-container {
457
+ position: fixed;
458
+ bottom: 2rem;
459
+ right: 2rem;
460
+ z-index: 1001;
461
+ display: flex;
462
+ flex-direction: column;
463
+ gap: 0.5rem;
464
+ }
465
+
466
+ .toast {
467
+ background: var(--bg-secondary);
468
+ border: 1px solid var(--border);
469
+ border-radius: var(--radius);
470
+ padding: 1rem 1.5rem;
471
+ box-shadow: 0 4px 6px var(--shadow);
472
+ min-width: 300px;
473
+ animation: slideIn 0.3s ease;
474
+ }
475
+
476
+ @keyframes slideIn {
477
+ from {
478
+ transform: translateX(100%);
479
+ opacity: 0;
480
+ }
481
+ to {
482
+ transform: translateX(0);
483
+ opacity: 1;
484
+ }
485
+ }
486
+
487
+ .toast.success {
488
+ border-left: 4px solid var(--success);
489
+ }
490
+
491
+ .toast.error {
492
+ border-left: 4px solid var(--danger);
493
+ }
494
+
495
+ .toast.warning {
496
+ border-left: 4px solid var(--warning);
497
+ }
498
+
499
+ /* Responsive */
500
+ @media (max-width: 768px) {
501
+ .nav-links {
502
+ flex-wrap: wrap;
503
+ }
504
+
505
+ .stats-grid {
506
+ grid-template-columns: 1fr;
507
+ }
508
+
509
+ .filters {
510
+ flex-direction: column;
511
+ }
512
+
513
+ .search-box {
514
+ flex-direction: column;
515
+ }
516
+
517
+ .pagination {
518
+ flex-direction: column;
519
+ gap: 1rem;
520
+ }
521
+ }
@@ -0,0 +1,148 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>AI Vault - Your AI Conversation Archive</title>
7
+ <link rel="stylesheet" href="/assets/styles.css" />
8
+ </head>
9
+ <body>
10
+ <!-- Navigation -->
11
+ <nav class="navbar">
12
+ <div class="nav-container">
13
+ <div class="nav-brand">
14
+ <h1>🏛️ AI Vault</h1>
15
+ </div>
16
+ <div class="nav-links">
17
+ <a href="#" data-page="dashboard" class="nav-link active">Dashboard</a>
18
+ <a href="#" data-page="conversations" class="nav-link">Conversations</a>
19
+ <a href="#" data-page="search" class="nav-link">Search</a>
20
+ <a href="#" data-page="media" class="nav-link">Media</a>
21
+ <a href="#" data-page="schedules" class="nav-link">Schedules</a>
22
+ <a href="#" data-page="settings" class="nav-link">Settings</a>
23
+ </div>
24
+ </div>
25
+ </nav>
26
+
27
+ <!-- Main Content -->
28
+ <main class="container">
29
+ <!-- Dashboard Page -->
30
+ <div id="dashboard-page" class="page active">
31
+ <h2>Dashboard</h2>
32
+ <div class="stats-grid">
33
+ <div class="stat-card">
34
+ <div class="stat-label">Total Conversations</div>
35
+ <div class="stat-value" id="total-conversations">-</div>
36
+ </div>
37
+ <div class="stat-card">
38
+ <div class="stat-label">Total Messages</div>
39
+ <div class="stat-value" id="total-messages">-</div>
40
+ </div>
41
+ <div class="stat-card">
42
+ <div class="stat-label">Media Files</div>
43
+ <div class="stat-value" id="total-media">-</div>
44
+ </div>
45
+ <div class="stat-card">
46
+ <div class="stat-label">Providers</div>
47
+ <div class="stat-value" id="total-providers">-</div>
48
+ </div>
49
+ </div>
50
+
51
+ <h3>Providers</h3>
52
+ <div id="providers-list" class="providers-grid"></div>
53
+
54
+ <div class="action-buttons">
55
+ <button class="btn btn-primary" onclick="app.triggerArchive()">Archive Now</button>
56
+ <button class="btn btn-secondary" onclick="app.rebuildSearchIndex()">Rebuild Search Index</button>
57
+ </div>
58
+ </div>
59
+
60
+ <!-- Conversations Page -->
61
+ <div id="conversations-page" class="page">
62
+ <h2>Conversations</h2>
63
+ <div class="filters">
64
+ <select id="provider-filter" class="filter-select">
65
+ <option value="">All Providers</option>
66
+ </select>
67
+ <select id="sort-filter" class="filter-select">
68
+ <option value="updatedAt-desc">Latest First</option>
69
+ <option value="updatedAt-asc">Oldest First</option>
70
+ <option value="title-asc">Title A-Z</option>
71
+ </select>
72
+ <input type="number" id="limit-filter" placeholder="Limit" value="50" class="filter-input" />
73
+ </div>
74
+ <div id="conversations-list" class="conversations-list"></div>
75
+ <div class="pagination">
76
+ <button class="btn" onclick="app.prevPage()" id="prev-btn">Previous</button>
77
+ <span id="page-info"></span>
78
+ <button class="btn" onclick="app.nextPage()" id="next-btn">Next</button>
79
+ </div>
80
+ </div>
81
+
82
+ <!-- Search Page -->
83
+ <div id="search-page" class="page">
84
+ <h2>Search Conversations</h2>
85
+ <div class="search-box">
86
+ <input
87
+ type="text"
88
+ id="search-input"
89
+ placeholder="Search across all conversations..."
90
+ class="search-input"
91
+ />
92
+ <button class="btn btn-primary" onclick="app.performSearch()">Search</button>
93
+ </div>
94
+ <div id="search-results" class="search-results"></div>
95
+ </div>
96
+
97
+ <!-- Media Page -->
98
+ <div id="media-page" class="page">
99
+ <h2>Media Gallery</h2>
100
+ <div class="filters">
101
+ <select id="media-provider-filter" class="filter-select">
102
+ <option value="">All Providers</option>
103
+ </select>
104
+ <select id="media-type-filter" class="filter-select">
105
+ <option value="">All Types</option>
106
+ <option value="image">Images</option>
107
+ <option value="video">Videos</option>
108
+ <option value="document">Documents</option>
109
+ </select>
110
+ </div>
111
+ <div id="media-stats" class="stats-grid"></div>
112
+ <div id="media-list" class="media-grid"></div>
113
+ </div>
114
+
115
+ <!-- Schedules Page -->
116
+ <div id="schedules-page" class="page">
117
+ <h2>Backup Schedules</h2>
118
+ <button class="btn btn-primary" onclick="app.showAddScheduleForm()">Add Schedule</button>
119
+ <div id="schedules-list" class="schedules-list"></div>
120
+ </div>
121
+
122
+ <!-- Settings Page -->
123
+ <div id="settings-page" class="page">
124
+ <h2>Settings</h2>
125
+ <div class="settings-section">
126
+ <h3>System Information</h3>
127
+ <div id="system-info"></div>
128
+ </div>
129
+ <div class="settings-section">
130
+ <h3>Archive Directory</h3>
131
+ <input type="text" id="archive-dir" class="input-full" />
132
+ <button class="btn btn-primary" onclick="app.saveSettings()">Save Settings</button>
133
+ </div>
134
+ </div>
135
+ </main>
136
+
137
+ <!-- Loading Overlay -->
138
+ <div id="loading-overlay" class="loading-overlay hidden">
139
+ <div class="loading-spinner"></div>
140
+ <div class="loading-text">Loading...</div>
141
+ </div>
142
+
143
+ <!-- Toast Notifications -->
144
+ <div id="toast-container" class="toast-container"></div>
145
+
146
+ <script src="/assets/app.js"></script>
147
+ </body>
148
+ </html>