codex-lens 0.1.34 → 0.1.36

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/CLAUDE.md ADDED
@@ -0,0 +1,61 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Project Overview
6
+
7
+ Codex-Lens is a visualization tool for Codex that monitors API requests and file system changes. It provides a UI with file explorer, code viewer with diff highlighting, integrated terminal, and Git status.
8
+
9
+ ## Tech Stack
10
+
11
+ - **Frontend**: React 18, Vite, CodeMirror 6
12
+ - **Backend**: Node.js (ESM), Express, WebSocket
13
+ - **Terminal**: xterm.js, node-pty
14
+ - **File Watching**: chokidar
15
+ - **Diff Generation**: diff
16
+
17
+ ## Commands
18
+
19
+ ```bash
20
+ npm run dev # Start Vite dev server (port 5173)
21
+ npm run build # Build with esbuild (backend) + Vite (frontend) -> dist/
22
+ npm start # Run the production CLI from dist/
23
+ ```
24
+
25
+ ## Architecture
26
+
27
+ ### Backend (src/ - built to dist/)
28
+
29
+ - **aggregator.js** - Central server class. Coordinates HTTP (port 5174), WebSocket, proxy, file watcher, PTY, and Git. Contains embedded fallback HTML UI.
30
+ - **cli.js** - Entry point. Finds Codex binary, creates aggregator, opens browser.
31
+ - **proxy.js** - Intercepts OpenAI API requests, parses SSE streams, broadcasts events.
32
+ - **watcher.js** - chokidar-based file watcher. Tracks code files, generates diffs on change, emits file_tree updates.
33
+ - **pty-manager.js** - Spawns/管理 Codex PTY process via node-pty. Handles terminal I/O and buffering.
34
+ - **git-manager.js** - Git operations (status --porcelain, stage, unstage, commit). Debounces status broadcasts.
35
+
36
+ ### Frontend (src/components/)
37
+
38
+ - **App.jsx** - Main component. Manages tabs, WebSocket connection, file tree, Git status panel.
39
+ - **CodeViewer.jsx** - CodeMirror 6 wrapper with syntax highlighting (20+ languages) and diff decoration plugin.
40
+ - **TerminalPanel.jsx** - xterm.js terminal connected via WebSocket to backend.
41
+
42
+ ### Communication Flow
43
+
44
+ 1. Frontend connects via WebSocket (`/ws`) to aggregator
45
+ 2. Aggregator broadcasts file_change, file_tree, git_status events
46
+ 3. File watcher detects changes -> emits via WebSocket -> App updates state
47
+ 4. PTY forwards terminal I/O via separate WebSocket (`/ws/terminal`)
48
+ 5. Git status updates are debounced (500ms) after file changes
49
+
50
+ ### Key Files
51
+
52
+ - `src/index.html` - HTML entry point served by Vite in dev
53
+ - `src/global.css` - Global styles
54
+ - `src/lib/logger.js` - Logging utility
55
+ - `src/lib/sse-parser.js` - SSE stream parser for proxy
56
+ - `src/lib/diff-builder.js` - Diff generation utilities
57
+
58
+ ## Build System
59
+
60
+ - `build.js` - esbuild bundles each backend file individually (no bundling), Vite builds frontend to `dist/public/`
61
+ - `vite.config.js` - Vite configured with src as root, proxies `/ws` and `/api` to port 5174
@@ -269,6 +269,27 @@ class Aggregator {
269
269
  await this.gitManager.commit(data.message);
270
270
  this.gitManager.broadcastUpdate();
271
271
  }
272
+ } else if (data.type === "git_push") {
273
+ if (this.gitManager?.isGitRepo()) {
274
+ const result = await this.gitManager.push();
275
+ this.broadcast({ type: "git_operation_result", operation: "push", success: result.success, message: result.message });
276
+ if (result.success) {
277
+ this.gitManager.broadcastUpdate();
278
+ }
279
+ }
280
+ } else if (data.type === "git_pull") {
281
+ if (this.gitManager?.isGitRepo()) {
282
+ const result = await this.gitManager.pull();
283
+ this.broadcast({ type: "git_operation_result", operation: "pull", success: result.success, message: result.message });
284
+ if (result.success) {
285
+ this.gitManager.broadcastUpdate();
286
+ }
287
+ }
288
+ } else if (data.type === "git_fetch") {
289
+ if (this.gitManager?.isGitRepo()) {
290
+ const result = await this.gitManager.fetch();
291
+ this.broadcast({ type: "git_operation_result", operation: "fetch", success: result.success, message: result.message });
292
+ }
272
293
  }
273
294
  }
274
295
  broadcast(event) {
@@ -111,6 +111,22 @@ class GitManager {
111
111
  await this.runGitCommand(["commit", "-m", message]);
112
112
  return this.getStatus();
113
113
  }
114
+ async runRemoteOperation(operation, args, successMsg) {
115
+ const result = await this.runGitCommand(args);
116
+ return {
117
+ success: result.code === 0,
118
+ message: result.code === 0 ? successMsg : result.stderr || `${operation} \u5931\u8D25`
119
+ };
120
+ }
121
+ async push() {
122
+ return this.runRemoteOperation("Push", ["push"], "Push \u6210\u529F");
123
+ }
124
+ async pull() {
125
+ return this.runRemoteOperation("Pull", ["pull"], "Pull \u6210\u529F");
126
+ }
127
+ async fetch() {
128
+ return this.runRemoteOperation("Fetch", ["fetch", "--all"], "Fetch \u6210\u529F");
129
+ }
114
130
  async broadcastUpdate() {
115
131
  const branch = await this.getCurrentBranch();
116
132
  const status = await this.getStatus();