codex-lens 0.1.12 → 0.1.14

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/build.js CHANGED
@@ -20,7 +20,6 @@ async function buildAll() {
20
20
  'src/aggregator.js',
21
21
  'src/watcher.js',
22
22
  'src/pty-manager.js',
23
- 'src/snapshot-manager.js',
24
23
  'src/lib/sse-parser.js',
25
24
  'src/lib/diff-builder.js',
26
25
  'src/lib/log-manager.js',
@@ -28,9 +27,14 @@ async function buildAll() {
28
27
  ];
29
28
 
30
29
  for (const file of backendFiles) {
30
+ const fullPath = resolve(__dirname, file);
31
+ if (!existsSync(fullPath)) {
32
+ console.log(`Skipping (not found): ${file}`);
33
+ continue;
34
+ }
31
35
  try {
32
36
  await esbuildBuild({
33
- entryPoints: [resolve(__dirname, file)],
37
+ entryPoints: [fullPath],
34
38
  outfile: resolve(__dirname, file.replace('src/', 'dist/')),
35
39
  bundle: false,
36
40
  platform: 'node',
@@ -8,7 +8,6 @@ import { createProxyServer } from "./proxy.js";
8
8
  import { FileWatcher, scanDirectory } from "./watcher.js";
9
9
  import { createLogger } from "./lib/logger.js";
10
10
  import { spawnCodex, writeToPty, resizePty, killPty, onPtyData, onPtyExit, getPtyState, getOutputBuffer } from "./pty-manager.js";
11
- import { SnapshotManager } from "./snapshot-manager.js";
12
11
  import path from "path";
13
12
  import { fileURLToPath } from "url";
14
13
  import { readFileSync, existsSync } from "fs";
@@ -51,9 +50,6 @@ class Aggregator {
51
50
  this.proxyServer = null;
52
51
  this.fileWatcher = null;
53
52
  this.ptyProcess = null;
54
- this.snapshotManager = new SnapshotManager();
55
- this.currentTaskId = null;
56
- this.taskStatus = "idle";
57
53
  }
58
54
  async start(proxyPort) {
59
55
  await fetchLatestVersion();
@@ -214,103 +210,7 @@ class Aggregator {
214
210
  }
215
211
  }));
216
212
  }
217
- } else if (data.type === "start_task") {
218
- this.handleStartTask(ws);
219
- } else if (data.type === "rollback_task") {
220
- this.handleRollbackTask(ws);
221
- } else if (data.type === "complete_task") {
222
- this.handleCompleteTask(ws);
223
- } else if (data.type === "get_task_status") {
224
- ws.send(JSON.stringify({
225
- type: "task_status",
226
- data: {
227
- status: this.taskStatus,
228
- taskId: this.currentTaskId
229
- }
230
- }));
231
- }
232
- }
233
- async handleStartTask(ws) {
234
- if (this.taskStatus === "running") {
235
- ws.send(JSON.stringify({ type: "error", message: "Task already running" }));
236
- return;
237
- }
238
- this.currentTaskId = Date.now().toString();
239
- this.taskStatus = "running";
240
- const result = await this.snapshotManager.createSnapshot(this.projectRoot, this.currentTaskId);
241
- if (result.success) {
242
- logger.info(`Task started: ${this.currentTaskId}, ${result.filesCount} files snapshotted`);
243
- this.broadcast({
244
- type: "task_status",
245
- data: {
246
- status: this.taskStatus,
247
- taskId: this.currentTaskId,
248
- filesCount: result.filesCount
249
- }
250
- });
251
- ws.send(JSON.stringify({
252
- type: "task_started",
253
- data: {
254
- taskId: this.currentTaskId,
255
- filesCount: result.filesCount
256
- }
257
- }));
258
- } else {
259
- this.taskStatus = "idle";
260
- this.currentTaskId = null;
261
- ws.send(JSON.stringify({ type: "error", message: "Failed to create snapshot: " + result.error }));
262
- }
263
- }
264
- async handleRollbackTask(ws) {
265
- if (!this.currentTaskId || this.taskStatus !== "running") {
266
- ws.send(JSON.stringify({ type: "error", message: "No active task to rollback" }));
267
- return;
268
213
  }
269
- const taskId = this.currentTaskId;
270
- const result = await this.snapshotManager.restoreSnapshot(taskId);
271
- if (result.success) {
272
- await this.snapshotManager.deleteSnapshot(taskId);
273
- logger.info(`Task rolled back: ${taskId}, ${result.restoredCount} files restored`);
274
- this.taskStatus = "idle";
275
- this.currentTaskId = null;
276
- this.broadcast({
277
- type: "task_status",
278
- data: {
279
- status: this.taskStatus,
280
- taskId: null
281
- }
282
- });
283
- ws.send(JSON.stringify({
284
- type: "task_rolled_back",
285
- data: {
286
- restoredCount: result.restoredCount
287
- }
288
- }));
289
- } else {
290
- ws.send(JSON.stringify({ type: "error", message: "Failed to rollback: " + result.error }));
291
- }
292
- }
293
- async handleCompleteTask(ws) {
294
- if (!this.currentTaskId || this.taskStatus !== "running") {
295
- ws.send(JSON.stringify({ type: "error", message: "No active task to complete" }));
296
- return;
297
- }
298
- const taskId = this.currentTaskId;
299
- await this.snapshotManager.deleteSnapshot(taskId);
300
- logger.info(`Task completed: ${taskId}`);
301
- this.taskStatus = "idle";
302
- this.currentTaskId = null;
303
- this.broadcast({
304
- type: "task_status",
305
- data: {
306
- status: this.taskStatus,
307
- taskId: null
308
- }
309
- });
310
- ws.send(JSON.stringify({
311
- type: "task_completed",
312
- data: {}
313
- }));
314
214
  }
315
215
  broadcast(event) {
316
216
  const message = JSON.stringify(event);
@@ -29,4 +29,4 @@
29
29
  * The original design remains. The terminal itself
30
30
  * has been extended to include xterm CSI codes, among
31
31
  * other features.
32
- */.xterm{cursor:text;position:relative;user-select:none;-ms-user-select:none;-webkit-user-select:none}.xterm.focus,.xterm:focus{outline:none}.xterm .xterm-helpers{position:absolute;top:0;z-index:5}.xterm .xterm-helper-textarea{padding:0;border:0;margin:0;position:absolute;opacity:0;left:-9999em;top:0;width:0;height:0;z-index:-5;white-space:nowrap;overflow:hidden;resize:none}.xterm .composition-view{background:#000;color:#fff;display:none;position:absolute;white-space:nowrap;z-index:1}.xterm .composition-view.active{display:block}.xterm .xterm-viewport{background-color:#000;overflow-y:scroll;cursor:default;position:absolute;right:0;left:0;top:0;bottom:0}.xterm .xterm-screen{position:relative}.xterm .xterm-screen canvas{position:absolute;left:0;top:0}.xterm .xterm-scroll-area{visibility:hidden}.xterm-char-measure-element{display:inline-block;visibility:hidden;position:absolute;top:0;left:-9999em;line-height:normal}.xterm.enable-mouse-events{cursor:default}.xterm.xterm-cursor-pointer,.xterm .xterm-cursor-pointer{cursor:pointer}.xterm.column-select.focus{cursor:crosshair}.xterm .xterm-accessibility:not(.debug),.xterm .xterm-message{position:absolute;left:0;top:0;bottom:0;right:0;z-index:10;color:transparent;pointer-events:none}.xterm .xterm-accessibility-tree:not(.debug) *::selection{color:transparent}.xterm .xterm-accessibility-tree{-webkit-user-select:text;user-select:text;white-space:pre}.xterm .live-region{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}.xterm-dim{opacity:1!important}.xterm-underline-1{text-decoration:underline}.xterm-underline-2{text-decoration:double underline}.xterm-underline-3{text-decoration:wavy underline}.xterm-underline-4{text-decoration:dotted underline}.xterm-underline-5{text-decoration:dashed underline}.xterm-overline{text-decoration:overline}.xterm-overline.xterm-underline-1{text-decoration:overline underline}.xterm-overline.xterm-underline-2{text-decoration:overline double underline}.xterm-overline.xterm-underline-3{text-decoration:overline wavy underline}.xterm-overline.xterm-underline-4{text-decoration:overline dotted underline}.xterm-overline.xterm-underline-5{text-decoration:overline dashed underline}.xterm-strikethrough{text-decoration:line-through}.xterm-screen .xterm-decoration-container .xterm-decoration{z-index:6;position:absolute}.xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer{z-index:7}.xterm-decoration-overview-ruler{z-index:8;position:absolute;top:0;right:0;pointer-events:none}.xterm-decoration-top{z-index:2;position:relative}:root{--bg-primary: #0F172A;--bg-secondary: #1E293B;--bg-tertiary: #334155;--text-primary: #F8FAFC;--text-secondary: #94A3B8;--text-muted: #64748B;--border-color: #475569;--accent-color: #22C55E;--accent-hover: #16A34A;--accent-glow: rgba(34, 197, 94, .3);--diff-add-bg: rgba(34, 197, 94, .15);--diff-add-text: #4ADE80;--diff-add-border: #22C55E;--diff-remove-bg: rgba(239, 68, 68, .15);--diff-remove-text: #F87171;--diff-remove-border: #EF4444;--danger-color: #EF4444;--danger-hover: #DC2626;--success-color: #22C55E;--success-hover: #16A34A;--warning-color: #F59E0B;--font-family: "Fira Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;--font-mono: "Fira Code", "SF Mono", "Consolas", "Monaco", monospace;--shadow-sm: 0 1px 2px rgba(0, 0, 0, .3);--shadow-md: 0 4px 12px rgba(0, 0, 0, .4);--shadow-lg: 0 8px 32px rgba(0, 0, 0, .5);--shadow-glow: 0 0 20px var(--accent-glow);--radius-sm: 4px;--radius-md: 8px;--radius-lg: 12px;--transition-fast: .15s ease;--transition-normal: .2s ease;--transition-slow: .3s ease}@media (prefers-reduced-motion: reduce){*,*:before,*:after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}}*{margin:0;padding:0;box-sizing:border-box}html,body,#root{height:100%;width:100%;overflow:hidden}body{font-family:var(--font-family);background-color:var(--bg-primary);color:var(--text-primary);font-size:14px;line-height:1.6;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.app-container{display:flex;height:100vh;width:100vw}.panel{display:flex;flex-direction:column;overflow:hidden;background:var(--bg-secondary);border-right:1px solid var(--border-color)}.panel:last-child{border-right:none}.panel-header{padding:12px 16px;background:linear-gradient(180deg,var(--bg-tertiary) 0%,var(--bg-secondary) 100%);border-bottom:1px solid var(--border-color);font-weight:600;font-size:11px;text-transform:uppercase;letter-spacing:.5px;color:var(--text-secondary);display:flex;align-items:center;gap:8px}.panel-content{flex:1;overflow:auto}.file-tree{padding:8px}.file-item{padding:6px 12px;cursor:pointer;border-radius:var(--radius-sm);display:flex;align-items:center;gap:8px;transition:background var(--transition-fast),transform var(--transition-fast)}.file-item:hover{background:var(--bg-tertiary)}.file-item:active{transform:scale(.98)}.file-item.active{background:var(--accent-color);color:var(--text-primary);box-shadow:var(--shadow-glow)}.file-icon{width:16px;height:16px;display:flex;align-items:center;justify-content:center;font-size:14px}.file-name{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.diff-line{font-family:var(--font-mono);font-size:13px;padding:2px 16px;white-space:pre;border-left:3px solid transparent;transition:background var(--transition-fast)}.diff-line.added{background:var(--diff-add-bg);color:var(--diff-add-text);border-left-color:var(--diff-add-border)}.diff-line.removed{background:var(--diff-remove-bg);color:var(--diff-remove-text);border-left-color:var(--diff-remove-border)}.diff-line:before{display:inline-block;width:20px;margin-right:8px;text-align:center;font-weight:600}.diff-line.added:before{content:"+";color:var(--diff-add-text)}.diff-line.removed:before{content:"-";color:var(--diff-remove-text)}.chat-message{padding:12px 16px;margin:8px 12px;border-radius:var(--radius-lg);max-width:85%;line-height:1.5}.chat-message.user{background:var(--accent-color);color:#fff;margin-left:auto;box-shadow:var(--shadow-md)}.chat-message.codex{background:var(--bg-tertiary);color:var(--text-primary);border:1px solid var(--border-color)}.chat-input-container{padding:12px;border-top:1px solid var(--border-color);background:var(--bg-secondary)}.chat-input{width:100%;padding:10px 14px;background:var(--bg-primary);border:1px solid var(--border-color);border-radius:var(--radius-md);color:var(--text-primary);font-family:var(--font-family);font-size:14px;resize:none;transition:border-color var(--transition-fast),box-shadow var(--transition-fast)}.chat-input:focus{outline:none;border-color:var(--accent-color);box-shadow:var(--shadow-glow)}::-webkit-scrollbar{width:8px;height:8px}::-webkit-scrollbar-track{background:var(--bg-primary)}::-webkit-scrollbar-thumb{background:var(--border-color);border-radius:4px}::-webkit-scrollbar-thumb:hover{background:var(--text-muted)}.ws-status{display:inline-block;width:8px;height:8px;border-radius:50%;margin-left:8px;transition:background var(--transition-normal),box-shadow var(--transition-normal)}.ws-status.connected{background:var(--success-color);box-shadow:0 0 8px var(--success-color)}.ws-status.disconnected{background:var(--danger-color);box-shadow:0 0 8px var(--danger-color)}.version-info{display:flex;align-items:center;gap:8px;margin-left:auto}.version-number{font-size:11px;color:var(--text-muted);font-weight:500;font-family:var(--font-mono)}.update-badge{font-size:10px;padding:3px 8px;background:var(--warning-color);color:var(--bg-primary);border-radius:var(--radius-sm);cursor:pointer;font-weight:600;transition:background var(--transition-fast),transform var(--transition-fast)}.update-badge:hover{background:#fbbf24;transform:translateY(-1px)}.terminal-wrapper{flex:1;overflow:hidden;min-height:0}.left-panel{width:260px;flex-shrink:0}.middle-panel{flex:1;min-width:300px}.right-panel{width:40%;min-width:300px;max-width:60%}.section{margin-bottom:16px}.section-title{padding:12px 16px 8px;font-size:10px;font-weight:600;color:var(--text-muted);text-transform:uppercase;letter-spacing:.5px}.empty-state{padding:32px;text-align:center;color:var(--text-muted);font-size:13px;display:flex;flex-direction:column;align-items:center;gap:8px}.empty-state:before{content:"📄";font-size:32px;opacity:.5}.code-panel{font-family:var(--font-mono)}.code-content{padding:16px;white-space:pre-wrap;word-break:break-all;line-height:1.7}.diff-container{font-family:var(--font-mono);font-size:13px;padding:8px 0}.tab-bar{display:flex;background:var(--bg-primary);border-bottom:1px solid var(--border-color);overflow-x:auto;min-height:40px}.tab{display:flex;align-items:center;gap:8px;padding:10px 16px;background:var(--bg-secondary);border-right:1px solid var(--border-color);cursor:pointer;min-width:100px;max-width:200px;font-size:13px;color:var(--text-secondary);transition:background var(--transition-fast),color var(--transition-fast)}.tab:hover{background:var(--bg-tertiary);color:var(--text-primary)}.tab.active{background:var(--bg-primary);color:var(--text-primary);border-bottom:2px solid var(--accent-color)}.tab-name{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tab-close{background:none;border:none;color:var(--text-muted);font-size:14px;cursor:pointer;padding:2px 4px;border-radius:var(--radius-sm);line-height:1;transition:background var(--transition-fast),color var(--transition-fast)}.tab-close:hover{background:#ffffff1a;color:var(--text-primary)}.context-menu{position:fixed;background:var(--bg-tertiary);border:1px solid var(--border-color);border-radius:var(--radius-md);padding:4px 0;min-width:160px;box-shadow:var(--shadow-lg);z-index:1000;animation:contextMenuIn .15s ease}@keyframes contextMenuIn{0%{opacity:0;transform:scale(.95)}to{opacity:1;transform:scale(1)}}.context-menu-item{padding:10px 16px;cursor:pointer;font-size:13px;color:var(--text-primary);transition:background var(--transition-fast),color var(--transition-fast)}.context-menu-item:hover{background:var(--accent-color);color:#fff}.file-context-menu{position:fixed;background:var(--bg-tertiary);border:1px solid var(--border-color);border-radius:var(--radius-md);padding:4px 0;min-width:180px;box-shadow:var(--shadow-lg);z-index:1000;animation:contextMenuIn .15s ease}.task-bar{display:flex;align-items:center;justify-content:space-between;padding:10px 16px;background:linear-gradient(180deg,var(--bg-tertiary) 0%,var(--bg-secondary) 100%);border-bottom:1px solid var(--border-color);min-height:48px}.task-status{display:flex;align-items:center;gap:10px;font-size:13px;font-weight:500}.task-status.idle{color:var(--text-muted)}.task-status.running{color:var(--accent-color)}.task-status:before{content:"";display:inline-block;width:8px;height:8px;border-radius:50%}.task-status.idle:before{background:var(--text-muted)}.task-status.running:before{background:var(--accent-color);box-shadow:0 0 8px var(--accent-color);animation:pulse 1.5s infinite}@keyframes pulse{0%,to{opacity:1;box-shadow:0 0 8px var(--accent-color)}50%{opacity:.6;box-shadow:0 0 4px var(--accent-color)}}.task-buttons{display:flex;gap:8px}.task-btn{padding:8px 16px;border:none;border-radius:var(--radius-sm);font-size:12px;font-weight:600;cursor:pointer;transition:background var(--transition-fast),transform var(--transition-fast),box-shadow var(--transition-fast);font-family:var(--font-family)}.task-btn:hover{transform:translateY(-1px)}.task-btn:active{transform:translateY(0)}.task-btn-start{background:var(--accent-color);color:#fff;box-shadow:var(--shadow-sm)}.task-btn-start:hover{background:var(--accent-hover);box-shadow:var(--shadow-glow)}.task-btn-start:disabled{background:var(--bg-tertiary);color:var(--text-muted);cursor:not-allowed;box-shadow:none}.task-btn-start:disabled:hover{transform:none}.task-btn-rollback{background:var(--danger-color);color:#fff}.task-btn-rollback:hover{background:var(--danger-hover);box-shadow:0 4px 12px #ef44444d}.task-btn-complete{background:var(--success-color);color:#fff}.task-btn-complete:hover{background:var(--success-hover);box-shadow:0 4px 12px #22c55e4d}.modal-overlay{position:fixed;top:0;left:0;right:0;bottom:0;background:#000000b3;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);display:flex;align-items:center;justify-content:center;z-index:2000;animation:modalOverlayIn .2s ease}@keyframes modalOverlayIn{0%{opacity:0}to{opacity:1}}.modal-content{background:var(--bg-secondary);border:1px solid var(--border-color);border-radius:var(--radius-lg);padding:24px;min-width:340px;max-width:420px;box-shadow:var(--shadow-lg);animation:modalContentIn .2s ease}@keyframes modalContentIn{0%{opacity:0;transform:scale(.95) translateY(-10px)}to{opacity:1;transform:scale(1) translateY(0)}}.modal-title{font-size:18px;font-weight:600;margin-bottom:12px;color:var(--text-primary)}.modal-body{font-size:14px;color:var(--text-secondary);margin-bottom:24px;line-height:1.7}.modal-buttons{display:flex;justify-content:flex-end;gap:12px}.modal-btn{padding:10px 20px;border:none;border-radius:var(--radius-sm);font-size:13px;font-weight:600;cursor:pointer;transition:background var(--transition-fast),transform var(--transition-fast);font-family:var(--font-family)}.modal-btn:hover{transform:translateY(-1px)}.modal-btn:active{transform:translateY(0)}.modal-btn-cancel{background:var(--bg-tertiary);color:var(--text-primary);border:1px solid var(--border-color)}.modal-btn-cancel:hover{background:var(--border-color)}.modal-btn-danger{background:var(--danger-color);color:#fff}.modal-btn-danger:hover{background:var(--danger-hover);box-shadow:0 4px 12px #ef44444d}@media (max-width: 768px){.left-panel{width:200px}.right-panel{width:50%;min-width:200px}}@media (max-width: 480px){.app-container{flex-direction:column}.left-panel,.right-panel{width:100%;max-width:none;min-width:auto}.middle-panel{min-height:300px}}
32
+ */.xterm{cursor:text;position:relative;user-select:none;-ms-user-select:none;-webkit-user-select:none}.xterm.focus,.xterm:focus{outline:none}.xterm .xterm-helpers{position:absolute;top:0;z-index:5}.xterm .xterm-helper-textarea{padding:0;border:0;margin:0;position:absolute;opacity:0;left:-9999em;top:0;width:0;height:0;z-index:-5;white-space:nowrap;overflow:hidden;resize:none}.xterm .composition-view{background:#000;color:#fff;display:none;position:absolute;white-space:nowrap;z-index:1}.xterm .composition-view.active{display:block}.xterm .xterm-viewport{background-color:#000;overflow-y:scroll;cursor:default;position:absolute;right:0;left:0;top:0;bottom:0}.xterm .xterm-screen{position:relative}.xterm .xterm-screen canvas{position:absolute;left:0;top:0}.xterm .xterm-scroll-area{visibility:hidden}.xterm-char-measure-element{display:inline-block;visibility:hidden;position:absolute;top:0;left:-9999em;line-height:normal}.xterm.enable-mouse-events{cursor:default}.xterm.xterm-cursor-pointer,.xterm .xterm-cursor-pointer{cursor:pointer}.xterm.column-select.focus{cursor:crosshair}.xterm .xterm-accessibility:not(.debug),.xterm .xterm-message{position:absolute;left:0;top:0;bottom:0;right:0;z-index:10;color:transparent;pointer-events:none}.xterm .xterm-accessibility-tree:not(.debug) *::selection{color:transparent}.xterm .xterm-accessibility-tree{-webkit-user-select:text;user-select:text;white-space:pre}.xterm .live-region{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}.xterm-dim{opacity:1!important}.xterm-underline-1{text-decoration:underline}.xterm-underline-2{text-decoration:double underline}.xterm-underline-3{text-decoration:wavy underline}.xterm-underline-4{text-decoration:dotted underline}.xterm-underline-5{text-decoration:dashed underline}.xterm-overline{text-decoration:overline}.xterm-overline.xterm-underline-1{text-decoration:overline underline}.xterm-overline.xterm-underline-2{text-decoration:overline double underline}.xterm-overline.xterm-underline-3{text-decoration:overline wavy underline}.xterm-overline.xterm-underline-4{text-decoration:overline dotted underline}.xterm-overline.xterm-underline-5{text-decoration:overline dashed underline}.xterm-strikethrough{text-decoration:line-through}.xterm-screen .xterm-decoration-container .xterm-decoration{z-index:6;position:absolute}.xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer{z-index:7}.xterm-decoration-overview-ruler{z-index:8;position:absolute;top:0;right:0;pointer-events:none}.xterm-decoration-top{z-index:2;position:relative}:root{--bg-primary: #0F172A;--bg-secondary: #1E293B;--bg-tertiary: #334155;--text-primary: #F8FAFC;--text-secondary: #94A3B8;--text-muted: #64748B;--border-color: #475569;--accent-color: #22C55E;--accent-hover: #16A34A;--accent-glow: rgba(34, 197, 94, .3);--diff-add-bg: rgba(34, 197, 94, .15);--diff-add-text: #4ADE80;--diff-add-border: #22C55E;--diff-remove-bg: rgba(239, 68, 68, .15);--diff-remove-text: #F87171;--diff-remove-border: #EF4444;--danger-color: #EF4444;--danger-hover: #DC2626;--success-color: #22C55E;--success-hover: #16A34A;--warning-color: #F59E0B;--font-family: "Fira Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;--font-mono: "Fira Code", "SF Mono", "Consolas", "Monaco", monospace;--shadow-sm: 0 1px 2px rgba(0, 0, 0, .3);--shadow-md: 0 4px 12px rgba(0, 0, 0, .4);--shadow-lg: 0 8px 32px rgba(0, 0, 0, .5);--shadow-glow: 0 0 20px var(--accent-glow);--radius-sm: 4px;--radius-md: 8px;--radius-lg: 12px;--transition-fast: .15s ease;--transition-normal: .2s ease;--transition-slow: .3s ease}@media (prefers-reduced-motion: reduce){*,*:before,*:after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}}*{margin:0;padding:0;box-sizing:border-box}html,body,#root{height:100%;width:100%;overflow:hidden}body{font-family:var(--font-family);background-color:var(--bg-primary);color:var(--text-primary);font-size:14px;line-height:1.6;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.app-container{display:flex;height:100vh;width:100vw}.panel{display:flex;flex-direction:column;overflow:hidden;background:var(--bg-secondary);border-right:1px solid var(--border-color)}.panel:last-child{border-right:none}.panel-header{padding:12px 16px;background:linear-gradient(180deg,var(--bg-tertiary) 0%,var(--bg-secondary) 100%);border-bottom:1px solid var(--border-color);font-weight:600;font-size:11px;text-transform:uppercase;letter-spacing:.5px;color:var(--text-secondary);display:flex;align-items:center;gap:8px}.panel-content{flex:1;overflow:auto}.file-tree{padding:8px}.file-item{padding:6px 12px;cursor:pointer;border-radius:var(--radius-sm);display:flex;align-items:center;gap:8px;transition:background var(--transition-fast),transform var(--transition-fast)}.file-item:hover{background:var(--bg-tertiary)}.file-item:active{transform:scale(.98)}.file-item.active{background:var(--accent-color);color:var(--text-primary);box-shadow:var(--shadow-glow)}.file-icon{width:16px;height:16px;display:flex;align-items:center;justify-content:center;font-size:14px}.file-name{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.diff-line{font-family:var(--font-mono);font-size:13px;padding:2px 16px;white-space:pre;border-left:3px solid transparent;transition:background var(--transition-fast)}.diff-line.added{background:var(--diff-add-bg);color:var(--diff-add-text);border-left-color:var(--diff-add-border)}.diff-line.removed{background:var(--diff-remove-bg);color:var(--diff-remove-text);border-left-color:var(--diff-remove-border)}.diff-line:before{display:inline-block;width:20px;margin-right:8px;text-align:center;font-weight:600}.diff-line.added:before{content:"+";color:var(--diff-add-text)}.diff-line.removed:before{content:"-";color:var(--diff-remove-text)}.chat-message{padding:12px 16px;margin:8px 12px;border-radius:var(--radius-lg);max-width:85%;line-height:1.5}.chat-message.user{background:var(--accent-color);color:#fff;margin-left:auto;box-shadow:var(--shadow-md)}.chat-message.codex{background:var(--bg-tertiary);color:var(--text-primary);border:1px solid var(--border-color)}.chat-input-container{padding:12px;border-top:1px solid var(--border-color);background:var(--bg-secondary)}.chat-input{width:100%;padding:10px 14px;background:var(--bg-primary);border:1px solid var(--border-color);border-radius:var(--radius-md);color:var(--text-primary);font-family:var(--font-family);font-size:14px;resize:none;transition:border-color var(--transition-fast),box-shadow var(--transition-fast)}.chat-input:focus{outline:none;border-color:var(--accent-color);box-shadow:var(--shadow-glow)}::-webkit-scrollbar{width:8px;height:8px}::-webkit-scrollbar-track{background:var(--bg-primary)}::-webkit-scrollbar-thumb{background:var(--border-color);border-radius:4px}::-webkit-scrollbar-thumb:hover{background:var(--text-muted)}.ws-status{display:inline-block;width:8px;height:8px;border-radius:50%;margin-left:8px;transition:background var(--transition-normal),box-shadow var(--transition-normal)}.ws-status.connected{background:var(--success-color);box-shadow:0 0 8px var(--success-color)}.ws-status.disconnected{background:var(--danger-color);box-shadow:0 0 8px var(--danger-color)}.version-info{display:flex;align-items:center;gap:8px;margin-left:auto}.version-number{font-size:11px;color:var(--text-muted);font-weight:500;font-family:var(--font-mono)}.update-badge{font-size:10px;padding:3px 8px;background:var(--warning-color);color:var(--bg-primary);border-radius:var(--radius-sm);cursor:pointer;font-weight:600;transition:background var(--transition-fast),transform var(--transition-fast)}.update-badge:hover{background:#fbbf24;transform:translateY(-1px)}.terminal-wrapper{flex:1;overflow:hidden;min-height:0}.left-panel{width:260px;flex-shrink:0}.middle-panel{flex:1;min-width:300px}.right-panel{width:40%;min-width:300px;max-width:60%}.section{margin-bottom:16px}.section-title{padding:12px 16px 8px;font-size:10px;font-weight:600;color:var(--text-muted);text-transform:uppercase;letter-spacing:.5px}.empty-state{padding:32px;text-align:center;color:var(--text-muted);font-size:13px;display:flex;flex-direction:column;align-items:center;gap:8px}.empty-state:before{content:"📄";font-size:32px;opacity:.5}.code-panel{font-family:var(--font-mono)}.code-content{padding:16px;white-space:pre-wrap;word-break:break-all;line-height:1.7}.diff-container{font-family:var(--font-mono);font-size:13px;padding:8px 0}.tab-bar{display:flex;background:var(--bg-primary);border-bottom:1px solid var(--border-color);overflow-x:auto;min-height:40px}.tab{display:flex;align-items:center;gap:8px;padding:10px 16px;background:var(--bg-secondary);border-right:1px solid var(--border-color);cursor:pointer;min-width:100px;max-width:200px;font-size:13px;color:var(--text-secondary);transition:background var(--transition-fast),color var(--transition-fast)}.tab:hover{background:var(--bg-tertiary);color:var(--text-primary)}.tab.active{background:var(--bg-primary);color:var(--text-primary);border-bottom:2px solid var(--accent-color)}.tab-name{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tab-close{background:none;border:none;color:var(--text-muted);font-size:14px;cursor:pointer;padding:2px 4px;border-radius:var(--radius-sm);line-height:1;transition:background var(--transition-fast),color var(--transition-fast)}.tab-close:hover{background:#ffffff1a;color:var(--text-primary)}.context-menu{position:fixed;background:var(--bg-tertiary);border:1px solid var(--border-color);border-radius:var(--radius-md);padding:4px 0;min-width:160px;box-shadow:var(--shadow-lg);z-index:1000;animation:contextMenuIn .15s ease}@keyframes contextMenuIn{0%{opacity:0;transform:scale(.95)}to{opacity:1;transform:scale(1)}}.context-menu-item{padding:10px 16px;cursor:pointer;font-size:13px;color:var(--text-primary);transition:background var(--transition-fast),color var(--transition-fast)}.context-menu-item:hover{background:var(--accent-color);color:#fff}.file-context-menu{position:fixed;background:var(--bg-tertiary);border:1px solid var(--border-color);border-radius:var(--radius-md);padding:4px 0;min-width:180px;box-shadow:var(--shadow-lg);z-index:1000;animation:contextMenuIn .15s ease}.task-bar{display:flex;align-items:center;justify-content:space-between;padding:10px 16px;background:linear-gradient(180deg,var(--bg-tertiary) 0%,var(--bg-secondary) 100%);border-bottom:1px solid var(--border-color);min-height:48px}.task-status{display:flex;align-items:center;gap:10px;font-size:13px;font-weight:500}.task-status.idle{color:var(--text-muted)}.task-status.running{color:var(--accent-color)}.task-status:before{content:"";display:inline-block;width:8px;height:8px;border-radius:50%}.task-status.idle:before{background:var(--text-muted)}.task-status.running:before{background:var(--accent-color);box-shadow:0 0 8px var(--accent-color);animation:pulse 1.5s infinite}@keyframes pulse{0%,to{opacity:1;box-shadow:0 0 8px var(--accent-color)}50%{opacity:.6;box-shadow:0 0 4px var(--accent-color)}}.task-buttons{display:flex;gap:8px}.task-btn{padding:8px 16px;border:none;border-radius:var(--radius-sm);font-size:12px;font-weight:600;cursor:pointer;transition:background var(--transition-fast),transform var(--transition-fast),box-shadow var(--transition-fast);font-family:var(--font-family)}.task-btn:hover{transform:translateY(-1px)}.task-btn:active{transform:translateY(0)}.task-btn-clear{background:var(--bg-tertiary);color:var(--text-primary);border:1px solid var(--border-color)}.task-btn-clear:hover{background:var(--border-color)}.modal-overlay{position:fixed;top:0;left:0;right:0;bottom:0;background:#000000b3;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);display:flex;align-items:center;justify-content:center;z-index:2000;animation:modalOverlayIn .2s ease}@keyframes modalOverlayIn{0%{opacity:0}to{opacity:1}}.modal-content{background:var(--bg-secondary);border:1px solid var(--border-color);border-radius:var(--radius-lg);padding:24px;min-width:340px;max-width:420px;box-shadow:var(--shadow-lg);animation:modalContentIn .2s ease}@keyframes modalContentIn{0%{opacity:0;transform:scale(.95) translateY(-10px)}to{opacity:1;transform:scale(1) translateY(0)}}.modal-title{font-size:18px;font-weight:600;margin-bottom:12px;color:var(--text-primary)}.modal-body{font-size:14px;color:var(--text-secondary);margin-bottom:24px;line-height:1.7}.modal-buttons{display:flex;justify-content:flex-end;gap:12px}.modal-btn{padding:10px 20px;border:none;border-radius:var(--radius-sm);font-size:13px;font-weight:600;cursor:pointer;transition:background var(--transition-fast),transform var(--transition-fast);font-family:var(--font-family)}.modal-btn:hover{transform:translateY(-1px)}.modal-btn:active{transform:translateY(0)}.modal-btn-cancel{background:var(--bg-tertiary);color:var(--text-primary);border:1px solid var(--border-color)}.modal-btn-cancel:hover{background:var(--border-color)}.modal-btn-danger{background:var(--danger-color);color:#fff}.modal-btn-danger:hover{background:var(--danger-hover);box-shadow:0 4px 12px #ef44444d}@media (max-width: 768px){.left-panel{width:200px}.right-panel{width:50%;min-width:200px}}@media (max-width: 480px){.app-container{flex-direction:column}.left-panel,.right-panel{width:100%;max-width:none;min-width:auto}.middle-panel{min-height:300px}}