agentopia 1.1.2 → 1.1.4
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.
- package/README.md +6 -3
- package/bin/agentopia.js +24 -0
- package/dist/services/terminal.d.ts +1 -2
- package/dist/services/terminal.d.ts.map +1 -1
- package/dist/services/terminal.js +10 -34
- package/dist/services/terminal.js.map +1 -1
- package/package.json +4 -4
- package/public/js/files-panel.js +222 -0
package/README.md
CHANGED
|
@@ -96,13 +96,16 @@ Agentopia creates a **shared workspace** where multiple AI agents operate as a t
|
|
|
96
96
|
|
|
97
97
|
```bash
|
|
98
98
|
npm install -g agentopia
|
|
99
|
-
|
|
100
|
-
# Start the server (database created in current directory)
|
|
101
99
|
agentopia
|
|
102
100
|
```
|
|
103
101
|
|
|
104
102
|
That's it. Open `http://localhost:4567`.
|
|
105
103
|
|
|
104
|
+
```bash
|
|
105
|
+
# CLI options
|
|
106
|
+
agentopia --port 8080 --host 0.0.0.0 --db ./my-project.db --no-auth
|
|
107
|
+
```
|
|
108
|
+
|
|
106
109
|
### Option 2: Clone & Run
|
|
107
110
|
|
|
108
111
|
```bash
|
|
@@ -125,7 +128,7 @@ On first visit, you'll be prompted to create an admin account.
|
|
|
125
128
|
|----------|---------|-------------|
|
|
126
129
|
| `AGENTOPIA_PORT` | `4567` | Server port |
|
|
127
130
|
| `AGENTOPIA_HOST` | `0.0.0.0` | Bind address |
|
|
128
|
-
| `AGENTOPIA_DB_PATH` |
|
|
131
|
+
| `AGENTOPIA_DB_PATH` | `./agentopia.db` | SQLite database path |
|
|
129
132
|
| `AGENTOPIA_ORCHESTRATOR_ENGINE` | `langgraph` | `native` or `langgraph` |
|
|
130
133
|
| `AGENTOPIA_NO_AUTH` | `false` | Disable authentication |
|
|
131
134
|
|
package/bin/agentopia.js
CHANGED
|
@@ -1,2 +1,26 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const args = process.argv.slice(2);
|
|
4
|
+
for (let i = 0; i < args.length; i++) {
|
|
5
|
+
if (args[i] === '--port' && args[i + 1]) process.env.AGENTOPIA_PORT = args[++i];
|
|
6
|
+
else if (args[i] === '--host' && args[i + 1]) process.env.AGENTOPIA_HOST = args[++i];
|
|
7
|
+
else if (args[i] === '--db' && args[i + 1]) process.env.AGENTOPIA_DB_PATH = args[++i];
|
|
8
|
+
else if (args[i] === '--no-auth') process.env.AGENTOPIA_NO_AUTH = 'true';
|
|
9
|
+
else if (args[i] === '--help' || args[i] === '-h') {
|
|
10
|
+
console.log(`
|
|
11
|
+
Agentopia - Multi-Agent Collaboration Platform
|
|
12
|
+
|
|
13
|
+
Usage: agentopia [options]
|
|
14
|
+
|
|
15
|
+
Options:
|
|
16
|
+
--port <port> Server port (default: 4567)
|
|
17
|
+
--host <host> Bind address (default: 0.0.0.0)
|
|
18
|
+
--db <path> SQLite database path (default: ./agentopia.db)
|
|
19
|
+
--no-auth Disable authentication
|
|
20
|
+
-h, --help Show this help message
|
|
21
|
+
`);
|
|
22
|
+
process.exit(0);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
2
26
|
require('../dist/index.js');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"terminal.d.ts","sourceRoot":"","sources":["../../src/services/terminal.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"terminal.d.ts","sourceRoot":"","sources":["../../src/services/terminal.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,OAAO,UAAU,EAAE,IAAI,CAAC;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;CACtB;AA6DD;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,OAAO,EACnB,IAAI,GAAE,MAAY,EAClB,IAAI,GAAE,MAAW,GAChB,UAAU,CAmGZ;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEtD;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAWvD;AAED,wBAAgB,kBAAkB,IAAI,IAAI,CAIzC;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAErE"}
|
|
@@ -1,37 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
4
|
};
|
|
@@ -42,12 +9,18 @@ exports.killPtySession = killPtySession;
|
|
|
42
9
|
exports.killAllPtySessions = killAllPtySessions;
|
|
43
10
|
exports.getPtyOutputBuffer = getPtyOutputBuffer;
|
|
44
11
|
exports.getPtySession = getPtySession;
|
|
45
|
-
const pty = __importStar(require("node-pty"));
|
|
46
12
|
const path_1 = __importDefault(require("path"));
|
|
47
13
|
const os_1 = __importDefault(require("os"));
|
|
48
14
|
const database_1 = require("../db/database");
|
|
49
15
|
const config_1 = require("../config");
|
|
50
16
|
const logger_1 = __importDefault(require("../logger"));
|
|
17
|
+
let pty = null;
|
|
18
|
+
try {
|
|
19
|
+
pty = require('node-pty');
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
logger_1.default.warn('node-pty not available');
|
|
23
|
+
}
|
|
51
24
|
// Map of agentId -> active PTY session
|
|
52
25
|
const ptySessions = new Map();
|
|
53
26
|
const PTY_OUTPUT_BUFFER_MAX = 200000;
|
|
@@ -107,6 +80,9 @@ function needsShellExecution(template) {
|
|
|
107
80
|
* If `newSession` is true, kill any existing session first.
|
|
108
81
|
*/
|
|
109
82
|
function getOrCreatePtySession(agentId, newSession, cols = 120, rows = 30) {
|
|
83
|
+
if (!pty) {
|
|
84
|
+
throw new Error('Interactive terminal not available (node-pty not installed)');
|
|
85
|
+
}
|
|
110
86
|
if (!newSession && ptySessions.has(agentId)) {
|
|
111
87
|
return ptySessions.get(agentId);
|
|
112
88
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"terminal.js","sourceRoot":"","sources":["../../src/services/terminal.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"terminal.js","sourceRoot":"","sources":["../../src/services/terminal.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentopia",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.4",
|
|
4
4
|
"description": "Multi-Agent Collaboration Platform",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -30,9 +30,6 @@
|
|
|
30
30
|
"node-cron": "^3.0.3",
|
|
31
31
|
"uuid": "^11.1.0"
|
|
32
32
|
},
|
|
33
|
-
"optionalDependencies": {
|
|
34
|
-
"node-pty": "^1.1.0"
|
|
35
|
-
},
|
|
36
33
|
"devDependencies": {
|
|
37
34
|
"@types/better-sqlite3": "^7.6.12",
|
|
38
35
|
"@types/node": "^22.10.0",
|
|
@@ -43,5 +40,8 @@
|
|
|
43
40
|
"nodemon": "^3.1.14",
|
|
44
41
|
"tsx": "^4.19.0",
|
|
45
42
|
"typescript": "^5.7.0"
|
|
43
|
+
},
|
|
44
|
+
"optionalDependencies": {
|
|
45
|
+
"node-pty": "^1.1.0"
|
|
46
46
|
}
|
|
47
47
|
}
|
package/public/js/files-panel.js
CHANGED
|
@@ -392,6 +392,9 @@
|
|
|
392
392
|
if (!editorEl) return;
|
|
393
393
|
const existing = editorEl.querySelector('.files-preview-iframe');
|
|
394
394
|
if (existing) existing.remove();
|
|
395
|
+
// Also remove rich previews (docx/xlsx/pptx/sqlite)
|
|
396
|
+
const richPreview = editorEl.querySelector('.files-rich-preview');
|
|
397
|
+
if (richPreview) richPreview.remove();
|
|
395
398
|
// Restore Monaco editor visibility if hidden
|
|
396
399
|
if (this.state.editor) {
|
|
397
400
|
this.state.editor.getDomNode().style.display = '';
|
|
@@ -499,6 +502,225 @@
|
|
|
499
502
|
}
|
|
500
503
|
}
|
|
501
504
|
|
|
505
|
+
showRichPreview(filePath, label, contentHtml) {
|
|
506
|
+
const editorEl = this.el('editorId');
|
|
507
|
+
if (!editorEl) return;
|
|
508
|
+
if (this.state.editor) this.state.editor.getDomNode().style.display = 'none';
|
|
509
|
+
const existing = editorEl.querySelector('.files-rich-preview');
|
|
510
|
+
if (existing) existing.remove();
|
|
511
|
+
const container = document.createElement('div');
|
|
512
|
+
container.className = 'files-rich-preview';
|
|
513
|
+
container.style.cssText = 'width:100%;height:100%;overflow:auto;background:#fff;color:#222;padding:16px;box-sizing:border-box;font-size:14px;';
|
|
514
|
+
container.innerHTML = contentHtml;
|
|
515
|
+
editorEl.appendChild(container);
|
|
516
|
+
this.state.previewMode = label;
|
|
517
|
+
this.updateSaveButton();
|
|
518
|
+
this.setStatus(`Preview: ${filePath}`);
|
|
519
|
+
this.showBanner(`${label} preview: ${filePath}`, '');
|
|
520
|
+
this.renderTree();
|
|
521
|
+
this.applyMobileEditorFocus(true);
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
removeRichPreview() {
|
|
525
|
+
const editorEl = this.el('editorId');
|
|
526
|
+
if (!editorEl) return;
|
|
527
|
+
const existing = editorEl.querySelector('.files-rich-preview');
|
|
528
|
+
if (existing) existing.remove();
|
|
529
|
+
if (this.state.editor) this.state.editor.getDomNode().style.display = '';
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
async loadOfficeLib(mode) {
|
|
533
|
+
if (mode === 'docx') {
|
|
534
|
+
if (!window._mammothLoaded) {
|
|
535
|
+
await this._loadScript('https://cdn.jsdelivr.net/npm/mammoth@1.8.0/mammoth.browser.min.js');
|
|
536
|
+
window._mammothLoaded = true;
|
|
537
|
+
}
|
|
538
|
+
} else if (mode === 'xlsx') {
|
|
539
|
+
if (!window.XLSX) {
|
|
540
|
+
await this._loadScript('https://cdn.jsdelivr.net/npm/xlsx@0.18.5/dist/xlsx.full.min.js');
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
_loadScript(url) {
|
|
546
|
+
return new Promise((resolve, reject) => {
|
|
547
|
+
const s = document.createElement('script');
|
|
548
|
+
s.src = url;
|
|
549
|
+
s.onload = resolve;
|
|
550
|
+
s.onerror = () => reject(new Error('Failed to load ' + url));
|
|
551
|
+
document.head.appendChild(s);
|
|
552
|
+
});
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
async showOfficePreview(filePath, mode) {
|
|
556
|
+
this.setStatus(`Loading ${mode.toUpperCase()} preview...`);
|
|
557
|
+
try {
|
|
558
|
+
await this.loadOfficeLib(mode);
|
|
559
|
+
const downloadUrl = `/api/agents/${this.getAgentId()}/files/download?path=${encodeURIComponent(filePath)}`;
|
|
560
|
+
const res = await fetch(downloadUrl, { headers: typeof apiHeaders === 'function' ? apiHeaders() : {} });
|
|
561
|
+
if (!res.ok) throw new Error('Failed to download file');
|
|
562
|
+
const arrayBuffer = await res.arrayBuffer();
|
|
563
|
+
|
|
564
|
+
let html = '';
|
|
565
|
+
if (mode === 'docx') {
|
|
566
|
+
const result = await mammoth.convertToHtml({ arrayBuffer });
|
|
567
|
+
html = '<div style="max-width:800px;margin:0 auto;line-height:1.6">' + result.value + '</div>';
|
|
568
|
+
if (result.messages && result.messages.length > 0) {
|
|
569
|
+
html += '<div style="margin-top:16px;padding:8px;background:#fff3cd;border-radius:4px;font-size:12px;color:#856404">' +
|
|
570
|
+
result.messages.map(m => m.message).join('<br>') + '</div>';
|
|
571
|
+
}
|
|
572
|
+
} else if (mode === 'xlsx') {
|
|
573
|
+
const workbook = XLSX.read(arrayBuffer, { type: 'array' });
|
|
574
|
+
html = '<div>';
|
|
575
|
+
// Sheet tabs
|
|
576
|
+
if (workbook.SheetNames.length > 1) {
|
|
577
|
+
html += '<div style="margin-bottom:12px;display:flex;gap:4px;flex-wrap:wrap">';
|
|
578
|
+
workbook.SheetNames.forEach((name, i) => {
|
|
579
|
+
html += '<button onclick="this.closest(\'.files-rich-preview\').querySelectorAll(\'.xlsx-sheet\').forEach((s,j)=>{s.style.display=j===' + i + '?\'block\':\'none\'});this.parentElement.querySelectorAll(\'button\').forEach((b,j)=>{b.style.background=j===' + i + '?\'#0366d6\':\'#e1e4e8\';b.style.color=j===' + i + '?\'#fff\':\'#222\'})" style="padding:4px 12px;border:none;border-radius:4px;cursor:pointer;font-size:12px;' + (i === 0 ? 'background:#0366d6;color:#fff' : 'background:#e1e4e8;color:#222') + '">' + name + '</button>';
|
|
580
|
+
});
|
|
581
|
+
html += '</div>';
|
|
582
|
+
}
|
|
583
|
+
workbook.SheetNames.forEach((name, i) => {
|
|
584
|
+
const sheet = workbook.Sheets[name];
|
|
585
|
+
const sheetHtml = XLSX.utils.sheet_to_html(sheet, { editable: false });
|
|
586
|
+
html += '<div class="xlsx-sheet" style="display:' + (i === 0 ? 'block' : 'none') + ';overflow-x:auto">' + sheetHtml + '</div>';
|
|
587
|
+
});
|
|
588
|
+
html += '</div>';
|
|
589
|
+
// Style the generated tables
|
|
590
|
+
html += '<style>.files-rich-preview table{border-collapse:collapse;font-size:13px;min-width:100%}.files-rich-preview td,.files-rich-preview th{border:1px solid #d0d7de;padding:4px 8px;text-align:left;white-space:nowrap}.files-rich-preview tr:first-child td,.files-rich-preview th{background:#f6f8fa;font-weight:600}</style>';
|
|
591
|
+
} else if (mode === 'pptx') {
|
|
592
|
+
// Basic PPTX info — extract slide count from [Content_Types].xml inside the zip
|
|
593
|
+
html = await this._renderPptxPreview(arrayBuffer);
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
this.removeRichPreview();
|
|
597
|
+
this.removePreviewIframe();
|
|
598
|
+
this.showRichPreview(filePath, mode.toUpperCase(), html);
|
|
599
|
+
} catch (error) {
|
|
600
|
+
this.setStatus(error.message || 'Preview failed');
|
|
601
|
+
this.showBanner(error.message || 'Preview failed', 'error');
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
async _renderPptxPreview(arrayBuffer) {
|
|
606
|
+
// Use JSZip to extract slide info from PPTX
|
|
607
|
+
if (!window.JSZip) {
|
|
608
|
+
await this._loadScript('https://cdn.jsdelivr.net/npm/jszip@3.10.1/dist/jszip.min.js');
|
|
609
|
+
}
|
|
610
|
+
const zip = await JSZip.loadAsync(arrayBuffer);
|
|
611
|
+
const slideFiles = Object.keys(zip.files).filter(f => /^ppt\/slides\/slide\d+\.xml$/.test(f)).sort();
|
|
612
|
+
const slideCount = slideFiles.length;
|
|
613
|
+
|
|
614
|
+
let html = '<div style="max-width:800px;margin:0 auto">';
|
|
615
|
+
html += '<div style="margin-bottom:16px;font-size:16px;font-weight:600">PowerPoint Presentation — ' + slideCount + ' slide' + (slideCount !== 1 ? 's' : '') + '</div>';
|
|
616
|
+
|
|
617
|
+
// Extract text content from each slide
|
|
618
|
+
for (let i = 0; i < slideFiles.length; i++) {
|
|
619
|
+
const xmlContent = await zip.file(slideFiles[i]).async('string');
|
|
620
|
+
// Extract text between <a:t> tags
|
|
621
|
+
const textMatches = xmlContent.match(/<a:t>([^<]*)<\/a:t>/g) || [];
|
|
622
|
+
const texts = textMatches.map(m => m.replace(/<\/?a:t>/g, '')).filter(t => t.trim());
|
|
623
|
+
|
|
624
|
+
html += '<div style="border:1px solid #d0d7de;border-radius:8px;padding:16px;margin-bottom:12px;background:#f6f8fa">';
|
|
625
|
+
html += '<div style="font-size:12px;color:#656d76;margin-bottom:8px;font-weight:600">Slide ' + (i + 1) + '</div>';
|
|
626
|
+
if (texts.length > 0) {
|
|
627
|
+
html += '<div style="line-height:1.5">' + texts.map(t => '<div>' + t.replace(/</g, '<').replace(/>/g, '>') + '</div>').join('') + '</div>';
|
|
628
|
+
} else {
|
|
629
|
+
html += '<div style="color:#8b949e;font-style:italic">No text content</div>';
|
|
630
|
+
}
|
|
631
|
+
html += '</div>';
|
|
632
|
+
}
|
|
633
|
+
html += '</div>';
|
|
634
|
+
return html;
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
async showSqlitePreview(filePath) {
|
|
638
|
+
this.setStatus('Loading SQLite preview...');
|
|
639
|
+
try {
|
|
640
|
+
const baseUrl = `/api/agents/${this.getAgentId()}/files/sqlite?path=${encodeURIComponent(filePath)}`;
|
|
641
|
+
const res = await fetch(baseUrl, { headers: typeof apiHeaders === 'function' ? apiHeaders() : {} });
|
|
642
|
+
if (!res.ok) {
|
|
643
|
+
const err = await res.json().catch(() => ({}));
|
|
644
|
+
throw new Error(err.error || 'Failed to load SQLite file');
|
|
645
|
+
}
|
|
646
|
+
const data = await res.json();
|
|
647
|
+
const tables = data.tables || [];
|
|
648
|
+
|
|
649
|
+
let html = '<div style="max-width:100%;margin:0 auto" id="sqlite-preview-root">';
|
|
650
|
+
html += '<div style="margin-bottom:16px;font-size:16px;font-weight:600">SQLite Database — ' + tables.length + ' table' + (tables.length !== 1 ? 's' : '') + '</div>';
|
|
651
|
+
html += '<div style="display:flex;gap:4px;flex-wrap:wrap;margin-bottom:16px">';
|
|
652
|
+
tables.forEach((t, i) => {
|
|
653
|
+
html += '<button data-table="' + t.name + '" onclick="window[\'' + this.apiName + '\']._sqliteLoadTable(this)" style="padding:4px 12px;border:none;border-radius:4px;cursor:pointer;font-size:12px;' + (i === 0 ? 'background:#0366d6;color:#fff' : 'background:#e1e4e8;color:#222') + '">' + t.name + ' (' + t.rowCount + ')</button>';
|
|
654
|
+
});
|
|
655
|
+
html += '</div>';
|
|
656
|
+
html += '<div id="sqlite-table-content" style="overflow-x:auto"></div>';
|
|
657
|
+
html += '</div>';
|
|
658
|
+
|
|
659
|
+
this.removeRichPreview();
|
|
660
|
+
this.removePreviewIframe();
|
|
661
|
+
this.showRichPreview(filePath, 'SQLite', html);
|
|
662
|
+
|
|
663
|
+
// Store state for table loading
|
|
664
|
+
this._sqliteFilePath = filePath;
|
|
665
|
+
// Expose for onclick
|
|
666
|
+
window[this.apiName]._sqliteLoadTable = (btn) => this._sqliteLoadTable(btn);
|
|
667
|
+
|
|
668
|
+
// Load first table automatically
|
|
669
|
+
if (tables.length > 0) {
|
|
670
|
+
const firstBtn = this.el('editorId')?.querySelector('button[data-table]');
|
|
671
|
+
if (firstBtn) this._sqliteLoadTable(firstBtn);
|
|
672
|
+
}
|
|
673
|
+
} catch (error) {
|
|
674
|
+
this.setStatus(error.message || 'SQLite preview failed');
|
|
675
|
+
this.showBanner(error.message || 'SQLite preview failed', 'error');
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
async _sqliteLoadTable(btn) {
|
|
680
|
+
const tableName = btn.dataset.table;
|
|
681
|
+
if (!tableName) return;
|
|
682
|
+
|
|
683
|
+
// Update tab button styles
|
|
684
|
+
const container = btn.parentElement;
|
|
685
|
+
if (container) {
|
|
686
|
+
container.querySelectorAll('button').forEach(b => {
|
|
687
|
+
b.style.background = b === btn ? '#0366d6' : '#e1e4e8';
|
|
688
|
+
b.style.color = b === btn ? '#fff' : '#222';
|
|
689
|
+
});
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
const contentEl = document.getElementById('sqlite-table-content');
|
|
693
|
+
if (!contentEl) return;
|
|
694
|
+
contentEl.innerHTML = '<div style="color:#656d76;padding:8px">Loading...</div>';
|
|
695
|
+
|
|
696
|
+
try {
|
|
697
|
+
const url = `/api/agents/${this.getAgentId()}/files/sqlite?path=${encodeURIComponent(this._sqliteFilePath)}&table=${encodeURIComponent(tableName)}&limit=200`;
|
|
698
|
+
const res = await fetch(url, { headers: typeof apiHeaders === 'function' ? apiHeaders() : {} });
|
|
699
|
+
if (!res.ok) throw new Error('Failed to load table');
|
|
700
|
+
const data = await res.json();
|
|
701
|
+
|
|
702
|
+
let html = '<div style="font-size:12px;color:#656d76;margin-bottom:8px">' + data.totalRows + ' rows total (showing ' + data.rows.length + ')</div>';
|
|
703
|
+
html += '<table style="border-collapse:collapse;font-size:13px;min-width:100%"><thead><tr>';
|
|
704
|
+
data.columns.forEach(col => {
|
|
705
|
+
html += '<th style="border:1px solid #d0d7de;padding:4px 8px;background:#f6f8fa;font-weight:600;white-space:nowrap">' + col.name + '<span style="color:#8b949e;font-weight:400;margin-left:4px;font-size:11px">' + col.type + '</span></th>';
|
|
706
|
+
});
|
|
707
|
+
html += '</tr></thead><tbody>';
|
|
708
|
+
data.rows.forEach(row => {
|
|
709
|
+
html += '<tr>';
|
|
710
|
+
data.columns.forEach(col => {
|
|
711
|
+
const val = row[col.name];
|
|
712
|
+
const display = val === null ? '<span style="color:#8b949e">NULL</span>' : String(val).length > 200 ? String(val).slice(0, 200) + '…' : String(val).replace(/</g, '<').replace(/>/g, '>');
|
|
713
|
+
html += '<td style="border:1px solid #d0d7de;padding:4px 8px;white-space:nowrap;max-width:400px;overflow:hidden;text-overflow:ellipsis">' + display + '</td>';
|
|
714
|
+
});
|
|
715
|
+
html += '</tr>';
|
|
716
|
+
});
|
|
717
|
+
html += '</tbody></table>';
|
|
718
|
+
contentEl.innerHTML = html;
|
|
719
|
+
} catch (error) {
|
|
720
|
+
contentEl.innerHTML = '<div style="color:#f85149;padding:8px">' + (error.message || 'Failed to load table') + '</div>';
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
|
|
502
724
|
async activate() {
|
|
503
725
|
this.updateWorkingDirectoryState();
|
|
504
726
|
|