codex-lens 0.1.28 → 0.1.30
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 +1 -0
- package/dist/aggregator.js +40 -1
- package/dist/git-manager.js +142 -0
- package/dist/public/assets/{main-BRIK-RhC.js → main-8FK9vFAz.js} +37 -37
- package/dist/public/assets/{main-DNXrKVO-.css → main-CnRUPtz5.css} +1 -1
- package/dist/public/index.html +2 -2
- package/dist/watcher.js +16 -0
- package/package.json +1 -1
- package/src/aggregator.js +43 -1
- package/src/components/App.jsx +169 -1
- package/src/git-manager.js +168 -0
- package/src/global.css +304 -0
- package/src/watcher.js +20 -0
package/build.js
CHANGED
package/dist/aggregator.js
CHANGED
|
@@ -7,6 +7,7 @@ import { createProxyServer } from "./proxy.js";
|
|
|
7
7
|
import { FileWatcher, scanDirectory } from "./watcher.js";
|
|
8
8
|
import { createLogger } from "./lib/logger.js";
|
|
9
9
|
import { spawnCodex, writeToPty, resizePty, killPty, onPtyData, onPtyExit, getPtyState, getOutputBuffer } from "./pty-manager.js";
|
|
10
|
+
import { createGitManager } from "./git-manager.js";
|
|
10
11
|
import path from "path";
|
|
11
12
|
import { fileURLToPath } from "url";
|
|
12
13
|
import { readFileSync, existsSync, writeFileSync } from "fs";
|
|
@@ -49,6 +50,7 @@ class Aggregator {
|
|
|
49
50
|
this.proxyServer = null;
|
|
50
51
|
this.fileWatcher = null;
|
|
51
52
|
this.ptyProcess = null;
|
|
53
|
+
this.gitManager = null;
|
|
52
54
|
}
|
|
53
55
|
async start(proxyPort) {
|
|
54
56
|
await fetchLatestVersion();
|
|
@@ -134,6 +136,16 @@ class Aggregator {
|
|
|
134
136
|
await this.proxyServer.start();
|
|
135
137
|
this.fileWatcher = new FileWatcher(this.projectRoot, (event) => this.broadcast(event));
|
|
136
138
|
await this.fileWatcher.start();
|
|
139
|
+
this.gitManager = createGitManager(this.projectRoot, (event) => this.broadcast(event));
|
|
140
|
+
if (this.gitManager.isGitRepo()) {
|
|
141
|
+
await this.gitManager.broadcastUpdate();
|
|
142
|
+
logger.info("Git repository detected, git status broadcasting enabled");
|
|
143
|
+
this.fileWatcher.setGitStatusCallback((filePath) => {
|
|
144
|
+
if (this.gitManager?.isGitRepo()) {
|
|
145
|
+
this.gitManager.scheduleStatusUpdate();
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
}
|
|
137
149
|
await this.startCodex(proxyPort);
|
|
138
150
|
return { httpPort: HTTP_PORT, proxyPort };
|
|
139
151
|
}
|
|
@@ -209,7 +221,7 @@ class Aggregator {
|
|
|
209
221
|
}
|
|
210
222
|
}
|
|
211
223
|
}
|
|
212
|
-
handleClientMessage(data, ws) {
|
|
224
|
+
async handleClientMessage(data, ws) {
|
|
213
225
|
if (data.type === "user_message") {
|
|
214
226
|
writeToPty(data.data + "\r");
|
|
215
227
|
} else if (data.type === "open_file") {
|
|
@@ -227,6 +239,33 @@ class Aggregator {
|
|
|
227
239
|
}
|
|
228
240
|
}));
|
|
229
241
|
}
|
|
242
|
+
} else if (data.type === "git_status_request") {
|
|
243
|
+
if (this.gitManager?.isGitRepo()) {
|
|
244
|
+
this.gitManager.broadcastUpdate();
|
|
245
|
+
}
|
|
246
|
+
} else if (data.type === "git_stage") {
|
|
247
|
+
if (this.gitManager?.isGitRepo()) {
|
|
248
|
+
if (data.filePath) {
|
|
249
|
+
await this.gitManager.stageFile(data.filePath);
|
|
250
|
+
} else {
|
|
251
|
+
await this.gitManager.stageAll();
|
|
252
|
+
}
|
|
253
|
+
this.gitManager.broadcastUpdate();
|
|
254
|
+
}
|
|
255
|
+
} else if (data.type === "git_unstage") {
|
|
256
|
+
if (this.gitManager?.isGitRepo()) {
|
|
257
|
+
if (data.filePath) {
|
|
258
|
+
await this.gitManager.unstageFile(data.filePath);
|
|
259
|
+
} else {
|
|
260
|
+
await this.gitManager.unstageAll();
|
|
261
|
+
}
|
|
262
|
+
this.gitManager.broadcastUpdate();
|
|
263
|
+
}
|
|
264
|
+
} else if (data.type === "git_commit") {
|
|
265
|
+
if (this.gitManager?.isGitRepo()) {
|
|
266
|
+
await this.gitManager.commit(data.message);
|
|
267
|
+
this.gitManager.broadcastUpdate();
|
|
268
|
+
}
|
|
230
269
|
}
|
|
231
270
|
}
|
|
232
271
|
broadcast(event) {
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { spawn } from "child_process";
|
|
3
|
+
import { existsSync } from "fs";
|
|
4
|
+
import { join } from "path";
|
|
5
|
+
import { createLogger } from "./lib/logger.js";
|
|
6
|
+
const logger = createLogger("GitManager");
|
|
7
|
+
class GitManager {
|
|
8
|
+
constructor(projectRoot, wsEmitter) {
|
|
9
|
+
this.projectRoot = projectRoot;
|
|
10
|
+
this.wsEmitter = wsEmitter;
|
|
11
|
+
this.gitDir = join(projectRoot, ".git");
|
|
12
|
+
this.currentStatus = null;
|
|
13
|
+
this.currentBranch = null;
|
|
14
|
+
this._statusTimeout = null;
|
|
15
|
+
}
|
|
16
|
+
isGitRepo() {
|
|
17
|
+
return existsSync(this.gitDir);
|
|
18
|
+
}
|
|
19
|
+
runGitCommand(args) {
|
|
20
|
+
return new Promise((resolve, reject) => {
|
|
21
|
+
const proc = spawn("git", args, {
|
|
22
|
+
cwd: this.projectRoot,
|
|
23
|
+
shell: true,
|
|
24
|
+
windowsHide: true
|
|
25
|
+
});
|
|
26
|
+
let stdout = "";
|
|
27
|
+
let stderr = "";
|
|
28
|
+
proc.stdout?.on("data", (data) => {
|
|
29
|
+
stdout += data.toString();
|
|
30
|
+
});
|
|
31
|
+
proc.stderr?.on("data", (data) => {
|
|
32
|
+
stderr += data.toString();
|
|
33
|
+
});
|
|
34
|
+
proc.on("close", (code) => {
|
|
35
|
+
resolve({ code, stdout, stderr });
|
|
36
|
+
});
|
|
37
|
+
proc.on("error", (err) => {
|
|
38
|
+
reject(err);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
parsePorcelainStatus(output) {
|
|
43
|
+
const lines = output.trim().split("\n");
|
|
44
|
+
const result = {
|
|
45
|
+
staged: [],
|
|
46
|
+
unstaged: [],
|
|
47
|
+
untracked: [],
|
|
48
|
+
conflicted: []
|
|
49
|
+
};
|
|
50
|
+
for (const line of lines) {
|
|
51
|
+
if (!line || line.length < 3) continue;
|
|
52
|
+
const indexStatus = line[0];
|
|
53
|
+
const workTreeStatus = line[1];
|
|
54
|
+
const path = line.slice(3).trim();
|
|
55
|
+
const fileInfo = { path, indexStatus, workTreeStatus };
|
|
56
|
+
if (indexStatus !== " " && indexStatus !== "?") {
|
|
57
|
+
result.staged.push(fileInfo);
|
|
58
|
+
}
|
|
59
|
+
if (workTreeStatus === "M" || workTreeStatus === "D") {
|
|
60
|
+
result.unstaged.push(fileInfo);
|
|
61
|
+
}
|
|
62
|
+
if (indexStatus === "?" && workTreeStatus === "?") {
|
|
63
|
+
result.untracked.push(fileInfo);
|
|
64
|
+
}
|
|
65
|
+
if (indexStatus === "U" || workTreeStatus === "U") {
|
|
66
|
+
result.conflicted.push(fileInfo);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return result;
|
|
70
|
+
}
|
|
71
|
+
async getStatus() {
|
|
72
|
+
if (!this.isGitRepo()) return null;
|
|
73
|
+
try {
|
|
74
|
+
const { stdout } = await this.runGitCommand(["status", "--porcelain"]);
|
|
75
|
+
this.currentStatus = this.parsePorcelainStatus(stdout);
|
|
76
|
+
return this.currentStatus;
|
|
77
|
+
} catch (error) {
|
|
78
|
+
logger.error(`Failed to get git status: ${error.message}`);
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
async getCurrentBranch() {
|
|
83
|
+
if (!this.isGitRepo()) return null;
|
|
84
|
+
try {
|
|
85
|
+
const { stdout } = await this.runGitCommand(["branch", "--show-current"]);
|
|
86
|
+
this.currentBranch = stdout.trim();
|
|
87
|
+
return this.currentBranch;
|
|
88
|
+
} catch (error) {
|
|
89
|
+
logger.error(`Failed to get branch: ${error.message}`);
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
async stageFile(filePath) {
|
|
94
|
+
await this.runGitCommand(["add", filePath]);
|
|
95
|
+
return this.getStatus();
|
|
96
|
+
}
|
|
97
|
+
async unstageFile(filePath) {
|
|
98
|
+
await this.runGitCommand(["reset", "HEAD", "--", filePath]);
|
|
99
|
+
return this.getStatus();
|
|
100
|
+
}
|
|
101
|
+
async stageAll() {
|
|
102
|
+
await this.runGitCommand(["add", "-A"]);
|
|
103
|
+
return this.getStatus();
|
|
104
|
+
}
|
|
105
|
+
async unstageAll() {
|
|
106
|
+
await this.runGitCommand(["reset", "HEAD"]);
|
|
107
|
+
return this.getStatus();
|
|
108
|
+
}
|
|
109
|
+
async commit(message) {
|
|
110
|
+
await this.runGitCommand(["commit", "-m", message]);
|
|
111
|
+
return this.getStatus();
|
|
112
|
+
}
|
|
113
|
+
async broadcastUpdate() {
|
|
114
|
+
const branch = await this.getCurrentBranch();
|
|
115
|
+
const status = await this.getStatus();
|
|
116
|
+
this.wsEmitter({
|
|
117
|
+
type: "git_status",
|
|
118
|
+
data: {
|
|
119
|
+
isRepo: true,
|
|
120
|
+
branch,
|
|
121
|
+
status,
|
|
122
|
+
stagedCount: status?.staged?.length || 0,
|
|
123
|
+
unstagedCount: (status?.unstaged?.length || 0) + (status?.untracked?.length || 0),
|
|
124
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
scheduleStatusUpdate() {
|
|
129
|
+
if (this._statusTimeout) {
|
|
130
|
+
clearTimeout(this._statusTimeout);
|
|
131
|
+
}
|
|
132
|
+
this._statusTimeout = setTimeout(() => {
|
|
133
|
+
this.broadcastUpdate();
|
|
134
|
+
}, 500);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
function createGitManager(projectRoot, wsEmitter) {
|
|
138
|
+
return new GitManager(projectRoot, wsEmitter);
|
|
139
|
+
}
|
|
140
|
+
export {
|
|
141
|
+
createGitManager
|
|
142
|
+
};
|