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 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` | `data/agentopia.db` | SQLite database 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,6 +1,5 @@
1
- import * as pty from 'node-pty';
2
1
  export interface PtySession {
3
- pty: pty.IPty;
2
+ pty: import('node-pty').IPty;
4
3
  agentId: string;
5
4
  createdAt: number;
6
5
  outputBuffer: string;
@@ -1 +1 @@
1
- {"version":3,"file":"terminal.d.ts","sourceRoot":"","sources":["../../src/services/terminal.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAQhC,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC;IACd,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,CA+FZ;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
+ {"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":"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"}
1
+ {"version":3,"file":"terminal.js","sourceRoot":"","sources":["../../src/services/terminal.ts"],"names":[],"mappings":";;;;;AAiFA,sDAwGC;AAED,sCAEC;AAED,wCAWC;AAED,gDAIC;AAED,gDAEC;AAED,sCAEC;AAvND,gDAAwB;AACxB,4CAAoB;AACpB,6CAA6C;AAE7C,sCAAmC;AACnC,uDAA+B;AAE/B,IAAI,GAAG,GAAqC,IAAI,CAAC;AACjD,IAAI,CAAC;IAAC,GAAG,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAAC,CAAC;AAAC,MAAM,CAAC;IAAC,gBAAM,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;AAAC,CAAC;AASnF,uCAAuC;AACvC,MAAM,WAAW,GAAG,IAAI,GAAG,EAAsB,CAAC;AAClD,MAAM,qBAAqB,GAAG,MAAM,CAAC;AAErC,SAAS,oBAAoB,CAAC,QAAgB;IAC5C,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,OAAO,GAAG,EAAE,CAAC;IACjB,IAAI,KAAK,GAAqB,IAAI,CAAC;IACnC,IAAI,MAAM,GAAG,KAAK,CAAC;IAEnB,KAAK,MAAM,EAAE,IAAI,QAAQ,EAAE,CAAC;QAC1B,IAAI,MAAM,EAAE,CAAC;YACX,OAAO,IAAI,EAAE,CAAC;YACd,MAAM,GAAG,KAAK,CAAC;YACf,SAAS;QACX,CAAC;QAED,IAAI,KAAK,KAAK,GAAG,EAAE,CAAC;YAClB,IAAI,EAAE,KAAK,GAAG;gBAAE,KAAK,GAAG,IAAI,CAAC;;gBACxB,OAAO,IAAI,EAAE,CAAC;YACnB,SAAS;QACX,CAAC;QAED,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC;YAChB,MAAM,GAAG,IAAI,CAAC;YACd,SAAS;QACX,CAAC;QAED,IAAI,KAAK,KAAK,GAAG,EAAE,CAAC;YAClB,IAAI,EAAE,KAAK,GAAG;gBAAE,KAAK,GAAG,IAAI,CAAC;;gBACxB,OAAO,IAAI,EAAE,CAAC;YACnB,SAAS;QACX,CAAC;QAED,IAAI,EAAE,KAAK,GAAG,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YAC7B,KAAK,GAAG,EAAE,CAAC;YACX,SAAS;QACX,CAAC;QAED,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;YAClB,IAAI,OAAO,EAAE,CAAC;gBACZ,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBACrB,OAAO,GAAG,EAAE,CAAC;YACf,CAAC;YACD,SAAS;QACX,CAAC;QAED,OAAO,IAAI,EAAE,CAAC;IAChB,CAAC;IAED,IAAI,MAAM;QAAE,OAAO,IAAI,IAAI,CAAC;IAC5B,IAAI,OAAO;QAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAClC,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,mBAAmB,CAAC,QAAgB;IAC3C,OAAO,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AACtC,CAAC;AAED;;;GAGG;AACH,SAAgB,qBAAqB,CACnC,OAAe,EACf,UAAmB,EACnB,OAAe,GAAG,EAClB,OAAe,EAAE;IAEjB,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CAAC,6DAA6D,CAAC,CAAC;IACjF,CAAC;IAED,IAAI,CAAC,UAAU,IAAI,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;QAC5C,OAAO,WAAW,CAAC,GAAG,CAAC,OAAO,CAAE,CAAC;IACnC,CAAC;IAED,+BAA+B;IAC/B,cAAc,CAAC,OAAO,CAAC,CAAC;IAExB,uCAAuC;IACvC,MAAM,EAAE,GAAG,IAAA,sBAAW,GAAE,CAAC;IACzB,MAAM,KAAK,GAAG,EAAE,CAAC,OAAO,CAAC,mCAAmC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAsB,CAAC;IAEhG,IAAI,GAAG,GAAG,KAAK,EAAE,iBAAiB,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IACpD,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,GAAG,GAAG,cAAI,CAAC,IAAI,CAAC,YAAE,CAAC,OAAO,EAAE,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAEtE,8DAA8D;IAC9D,IAAI,eAAe,GAAG,QAAQ,CAAC;IAC/B,IAAI,KAAK,EAAE,CAAC;QACV,IAAI,KAAK,CAAC,gBAAgB,EAAE,CAAC;YAC3B,eAAe,GAAG,KAAK,CAAC,gBAAgB,CAAC,IAAI,EAAE,IAAI,QAAQ,CAAC;QAC9D,CAAC;aAAM,CAAC;YACN,MAAM,OAAO,GAAG,EAAE,CAAC,OAAO,CAAC,oDAAoD,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAA6C,CAAC;YACnJ,IAAI,OAAO,EAAE,gBAAgB,EAAE,CAAC;gBAC9B,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC,IAAI,EAAE,IAAI,QAAQ,CAAC;YAChE,CAAC;iBAAM,CAAC;gBACN,eAAe,GAAG,eAAM,CAAC,sBAAsB,IAAI,QAAQ,CAAC;YAC9D,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,MAAM,GAAG,oBAAoB,CAAC,eAAe,CAAC,CAAC;IACrD,MAAM,WAAW,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC;IAC1C,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAEjC,6CAA6C;IAC7C,MAAM,SAAS,GAAG,KAAK,EAAE,UAAU,IAAI,SAAS,CAAC;IACjD,MAAM,QAAQ,GAAG,cAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,WAAW,EAAE,CAAC;IAC1D,MAAM,cAAc,GAAG,QAAQ,KAAK,KAAK,IAAI,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK,KAAK,CAAC;IACzF,MAAM,WAAW,GAAa,EAAE,CAAC;IACjC,IAAI,cAAc,EAAE,CAAC;QACnB,WAAW,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAC;QACnD,IAAI,SAAS,EAAE,CAAC;YACd,WAAW,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;QAC1C,CAAC;IACH,CAAC;IAED,MAAM,UAAU,GAAG;QACjB,IAAI,EAAE,gBAAgB;QACtB,IAAI;QACJ,IAAI;QACJ,GAAG;QACH,GAAG,EAAE;YACH,GAAG,OAAO,CAAC,GAAG;YACd,QAAQ,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;YACpF,QAAQ,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;SAC3D;KAC5B,CAAC;IAEF,MAAM,SAAS,GAAG,CAAC,GAAG,QAAQ,EAAE,GAAG,WAAW,CAAC,CAAC;IAChD,IAAI,UAAoB,CAAC;IAEzB,IAAI,mBAAmB,CAAC,eAAe,CAAC,EAAE,CAAC;QACzC,MAAM,SAAS,GAAG,CAAC,GAAW,EAAU,EAAE,CAAC,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,GAAG,CAAC;QAClF,MAAM,YAAY,GAAG,CAAC,eAAe,EAAE,GAAG,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAChF,gBAAM,CAAC,IAAI,CAAC,0BAA0B,OAAO,eAAe,YAAY,OAAO,GAAG,EAAE,CAAC,CAAC;QACtF,UAAU,GAAG,GAAG,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,YAAY,CAAC,EAAE,UAAU,CAAC,CAAC;IACvE,CAAC;SAAM,CAAC;QACN,gBAAM,CAAC,IAAI,CAAC,0BAA0B,OAAO,KAAK,WAAW,IAAI,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,GAAG,EAAE,CAAC,CAAC;QAClG,UAAU,GAAG,GAAG,CAAC,KAAK,CAAC,WAAW,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;IAC7D,CAAC;IAED,MAAM,OAAO,GAAe;QAC1B,GAAG,EAAE,UAAU;QACf,OAAO;QACP,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;QACrB,YAAY,EAAE,EAAE;KACjB,CAAC;IAEF,0EAA0E;IAC1E,gDAAgD;IAChD,UAAU,CAAC,MAAM,CAAC,CAAC,IAAY,EAAE,EAAE;QACjC,OAAO,CAAC,YAAY,IAAI,IAAI,CAAC;QAC7B,IAAI,OAAO,CAAC,YAAY,CAAC,MAAM,GAAG,qBAAqB,EAAE,CAAC;YACxD,OAAO,CAAC,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,qBAAqB,CAAC,CAAC;QAC5E,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,WAAW,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAElC,UAAU,CAAC,MAAM,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE;QACjC,gBAAM,CAAC,IAAI,CAAC,iBAAiB,OAAO,qBAAqB,QAAQ,EAAE,CAAC,CAAC;QACrE,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC9B,CAAC,CAAC,CAAC;IAEH,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAgB,aAAa,CAAC,OAAe;IAC3C,OAAO,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AAClC,CAAC;AAED,SAAgB,cAAc,CAAC,OAAe;IAC5C,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACzC,IAAI,CAAC,OAAO;QAAE,OAAO,KAAK,CAAC;IAE3B,IAAI,CAAC;QACH,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;IACrB,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,gBAAM,CAAC,KAAK,CAAC,CAAC,EAAE,gCAAgC,OAAO,EAAE,CAAC,CAAC;IAC7D,CAAC;IACD,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC5B,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAgB,kBAAkB;IAChC,KAAK,MAAM,CAAC,OAAO,CAAC,IAAI,WAAW,EAAE,CAAC;QACpC,cAAc,CAAC,OAAO,CAAC,CAAC;IAC1B,CAAC;AACH,CAAC;AAED,SAAgB,kBAAkB,CAAC,OAAe;IAChD,OAAO,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,YAAY,IAAI,EAAE,CAAC;AACtD,CAAC;AAED,SAAgB,aAAa,CAAC,OAAe;IAC3C,OAAO,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AAClC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentopia",
3
- "version": "1.1.2",
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
  }
@@ -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, '&lt;').replace(/>/g, '&gt;') + '</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, '&lt;').replace(/>/g, '&gt;');
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