Skip to content

Commit b2de243

Browse files
committed
Release v0.3.0 environment setup fixes
1 parent b9d4aed commit b2de243

10 files changed

Lines changed: 211 additions & 21 deletions

File tree

.github/workflows/build-macos.yml

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
name: Build macOS
2+
3+
on:
4+
workflow_dispatch:
5+
push:
6+
tags:
7+
- 'v*'
8+
9+
permissions:
10+
contents: write
11+
12+
jobs:
13+
build-macos:
14+
name: macOS package (${{ matrix.arch }})
15+
runs-on: ${{ matrix.runner }}
16+
env:
17+
CSC_IDENTITY_AUTO_DISCOVERY: 'false'
18+
strategy:
19+
fail-fast: false
20+
matrix:
21+
include:
22+
- arch: arm64
23+
runner: macos-15
24+
- arch: x64
25+
runner: macos-15-intel
26+
27+
steps:
28+
- name: Checkout
29+
uses: actions/checkout@v4
30+
31+
- name: Set up Node.js
32+
uses: actions/setup-node@v4
33+
with:
34+
node-version: 22
35+
cache: npm
36+
37+
- name: Set up Python
38+
uses: actions/setup-python@v5
39+
with:
40+
python-version: '3.12'
41+
42+
- name: Install Node dependencies
43+
run: npm ci
44+
45+
- name: Typecheck
46+
run: npm run typecheck
47+
48+
- name: Build macOS app
49+
run: npm run dist:mac
50+
51+
- name: Upload macOS artifact
52+
uses: actions/upload-artifact@v4
53+
with:
54+
name: codex-context-proxy-macos-${{ matrix.arch }}
55+
path: |
56+
release/*.dmg
57+
release/*.zip
58+
release/*.blockmap
59+
60+
release:
61+
name: Attach artifacts to GitHub release
62+
if: startsWith(github.ref, 'refs/tags/')
63+
needs: build-macos
64+
runs-on: ubuntu-latest
65+
steps:
66+
- name: Download macOS artifacts
67+
uses: actions/download-artifact@v4
68+
with:
69+
path: release-artifacts
70+
pattern: codex-context-proxy-macos-*
71+
merge-multiple: true
72+
73+
- name: Attach artifacts to GitHub release
74+
uses: softprops/action-gh-release@v2
75+
with:
76+
files: |
77+
release-artifacts/*.dmg
78+
release-artifacts/*.zip
79+
release-artifacts/*.blockmap

GITHUB_RELEASE.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1-
# Codex Context Proxy v0.2.0
1+
# Codex Context Proxy v0.3.0
22

33
A visual, editable context layer for Codex. Let AI edit AI's context with surgical precision, giving you more control and freedom over what Codex sees.
44

55
## What's Included
66

7+
- Fixes for Python environment setup and dependency installation
8+
- `npm run setup:python` for creating and updating the local `.venv`
9+
- Test scripts now prefer the project `.venv` when available
10+
- Added Brotli and zstandard runtime dependencies for compressed responses
711
- Visual context map for Codex sessions
812
- Token overview for current context usage
913
- Manual context inspection and editing panel
@@ -19,7 +23,7 @@ A visual, editable context layer for Codex. Let AI edit AI's context with surgic
1923
Download and run:
2024

2125
```text
22-
Codex Context Proxy Setup 0.2.0.exe
26+
Codex Context Proxy Setup 0.3.0.exe
2327
```
2428

2529
After installation, open a new terminal and enable the proxy:

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ context window
9797
Download and run the Windows installer:
9898

9999
```text
100-
Codex Context Proxy Setup 0.2.0.exe
100+
Codex Context Proxy Setup 0.3.0.exe
101101
```
102102

103103
After installation, open a new terminal and enable the proxy:
@@ -158,6 +158,7 @@ Install dependencies:
158158

159159
```powershell
160160
npm install
161+
npm run setup:python
161162
```
162163

163164
Run the local Codex flow:
@@ -187,7 +188,7 @@ npm run dist:win
187188
The installer is generated at:
188189

189190
```text
190-
release/Codex Context Proxy Setup 0.2.0.exe
191+
release/Codex Context Proxy Setup 0.3.0.exe
191192
```
192193

193194
## Notes

README.zh-CN.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ context window
9797
下载并运行 Windows 安装包:
9898

9999
```text
100-
Codex Context Proxy Setup 0.2.0.exe
100+
Codex Context Proxy Setup 0.3.0.exe
101101
```
102102

103103
安装完成后,重新打开一个终端,然后启用代理:
@@ -158,6 +158,7 @@ codex ctx desktop off
158158

159159
```powershell
160160
npm install
161+
npm run setup:python
161162
```
162163

163164
运行本地 Codex 流程:
@@ -187,7 +188,7 @@ npm run dist:win
187188
安装包会生成在:
188189

189190
```text
190-
release/Codex Context Proxy Setup 0.2.0.exe
191+
release/Codex Context Proxy Setup 0.3.0.exe
191192
```
192193

193194
## 说明

RELEASE.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,14 @@ npm run dist:win
1717
生成的安装包在:
1818

1919
```text
20-
release/Codex Context Proxy Setup 0.2.0.exe
20+
release/Codex Context Proxy Setup 0.3.0.exe
2121
```
2222

2323
安装包会带上 Electron 前端、React 构建产物、`web_server.py``proxy_server.py` 以及打包后的 Python exe。用户不需要自己安装 Node 或 Python。
2424

2525
## 用户怎么用
2626

27-
用户安装 `Codex Context Proxy Setup 0.2.0.exe` 后,安装器会自动安装 `codex ctx proxy ...` 控制命令,但不会默认打开代理。
27+
用户安装 `Codex Context Proxy Setup 0.3.0.exe` 后,安装器会自动安装 `codex ctx proxy ...` 控制命令,但不会默认打开代理。
2828

2929
安装完成后,重新打开一个终端,然后使用:
3030

@@ -103,7 +103,7 @@ codex ctx desktop status
103103
把下面这个文件上传到 GitHub Releases、网盘或下载页即可:
104104

105105
```text
106-
release/Codex Context Proxy Setup 0.2.0.exe
106+
release/Codex Context Proxy Setup 0.3.0.exe
107107
```
108108

109109
旧的 `hashcode Setup ...exe` 是历史产物,不要发布。

electron/context-window.cjs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -154,14 +154,18 @@ async function waitFor(port, pathname, label, timeoutMs = 30000) {
154154
}
155155

156156
function pythonCommand(root) {
157-
const localPython = path.join(root, '.venv', 'Scripts', 'python.exe');
158-
return fs.existsSync(localPython) ? localPython : 'python';
157+
const localPython = process.platform === 'win32'
158+
? path.join(root, '.venv', 'Scripts', 'python.exe')
159+
: path.join(root, '.venv', 'bin', 'python');
160+
const fallbackPython = process.platform === 'win32' ? 'python' : 'python3';
161+
return fs.existsSync(localPython) ? localPython : fallbackPython;
159162
}
160163

161164
function pythonServerCommand(root, scriptName, exeName) {
162-
const bundledExe = path.join(root, 'python_dist', exeName, `${exeName}.exe`);
163-
if (fs.existsSync(bundledExe)) {
164-
return { command: bundledExe, args: [] };
165+
const executableName = process.platform === 'win32' ? `${exeName}.exe` : exeName;
166+
const bundledExecutable = path.join(root, 'python_dist', exeName, executableName);
167+
if (fs.existsSync(bundledExecutable)) {
168+
return { command: bundledExecutable, args: [] };
165169
}
166170

167171
return { command: pythonCommand(root), args: [scriptName] };

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
{
22
"name": "hash-context-codex-lab",
3-
"version": "0.2.0",
3+
"version": "0.3.0",
44
"private": true,
55
"description": "Local context proxy and workbench companion for Codex.",
66
"author": "",
77
"main": "electron/context-window.cjs",
88
"scripts": {
99
"start": "npm run start:backend",
10+
"setup:python": "powershell -NoProfile -ExecutionPolicy Bypass -Command \"if (-not (Test-Path '.venv\\Scripts\\python.exe')) { python -m venv .venv }; .venv\\Scripts\\python.exe -m pip install --upgrade pip; .venv\\Scripts\\python.exe -m pip install -r requirements.txt\"",
1011
"start:backend": "if exist .venv\\Scripts\\python.exe (.venv\\Scripts\\python.exe web_server.py) else (python web_server.py)",
1112
"proxy": "if exist .venv\\Scripts\\python.exe (.venv\\Scripts\\python.exe proxy_server.py) else (python proxy_server.py)",
1213
"codex": "powershell -NoProfile -ExecutionPolicy Bypass -File scripts/codex-with-context.ps1",
@@ -27,13 +28,15 @@
2728
"dev": "vite --config react_app/vite.config.ts",
2829
"dev:react": "vite --config react_app/vite.config.ts",
2930
"typecheck": "tsc -p react_app/tsconfig.json --noEmit",
30-
"test:compact-proxy": "python scripts/test_compact_proxy.py",
31+
"test:compact-proxy": "if exist .venv\\Scripts\\python.exe (.venv\\Scripts\\python.exe scripts/test_compact_proxy.py) else (python scripts/test_compact_proxy.py)",
3132
"build": "npm run build:react",
3233
"build:react": "vite build --config react_app/vite.config.ts",
33-
"build:python": "powershell -NoProfile -ExecutionPolicy Bypass -File scripts/build-python.ps1",
34+
"build:python": "node scripts/build-python.mjs",
3435
"preview:react": "vite preview --config react_app/vite.config.ts",
3536
"pack:win": "npm run build:react && npm run build:python && electron-builder --win --dir",
36-
"dist:win": "npm run build:react && npm run build:python && electron-builder --win nsis"
37+
"dist:win": "npm run build:react && npm run build:python && electron-builder --win nsis",
38+
"pack:mac": "npm run build:react && npm run build:python && electron-builder --mac --dir",
39+
"dist:mac": "npm run build:react && npm run build:python && electron-builder --mac"
3740
},
3841
"dependencies": {
3942
"highlight.js": "^11.11.1",
@@ -72,7 +75,6 @@
7275
"requirements.txt",
7376
"RELEASE.md",
7477
".env.example",
75-
".venv/**/*",
7678
"static/**/*",
7779
"react_app/dist/**/*",
7880
"python_dist/**/*",
@@ -86,6 +88,17 @@
8688
"signAndEditExecutable": false,
8789
"forceCodeSigning": false
8890
},
91+
"mac": {
92+
"target": [
93+
"dmg",
94+
"zip"
95+
],
96+
"artifactName": "${productName}-${version}-${os}-${arch}.${ext}",
97+
"category": "public.app-category.developer-tools",
98+
"hardenedRuntime": false,
99+
"gatekeeperAssess": false,
100+
"identity": null
101+
},
89102
"nsis": {
90103
"oneClick": false,
91104
"allowToChangeInstallationDirectory": true,

requirements.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
openai>=2.0.0
22
python-dotenv>=1.0.1
33
tiktoken>=0.7.0
4+
Brotli>=1.1.0
5+
zstandard>=0.23.0

scripts/build-python.mjs

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import { rmSync, existsSync } from 'node:fs';
2+
import path from 'node:path';
3+
import { spawnSync } from 'node:child_process';
4+
import { fileURLToPath } from 'node:url';
5+
6+
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
7+
const buildVenv = path.join(root, '.build-venv');
8+
const pythonDist = path.join(root, 'python_dist');
9+
const webWork = path.join(root, '.tmp-pyinstaller-web');
10+
const proxyWork = path.join(root, '.tmp-pyinstaller-proxy');
11+
const isWindows = process.platform === 'win32';
12+
const venvPython = isWindows
13+
? path.join(buildVenv, 'Scripts', 'python.exe')
14+
: path.join(buildVenv, 'bin', 'python');
15+
const systemPython = process.env.PYTHON || (isWindows ? 'python' : 'python3');
16+
17+
function run(command, args, options = {}) {
18+
const result = spawnSync(command, args, {
19+
cwd: root,
20+
stdio: 'inherit',
21+
shell: false,
22+
...options,
23+
});
24+
25+
if (result.error) {
26+
throw result.error;
27+
}
28+
if (result.status !== 0) {
29+
throw new Error(`${command} ${args.join(' ')} failed with exit code ${result.status}`);
30+
}
31+
}
32+
33+
function removeWorkspacePath(target) {
34+
const resolvedRoot = path.resolve(root);
35+
const resolvedTarget = path.resolve(target);
36+
const relative = path.relative(resolvedRoot, resolvedTarget);
37+
38+
if (relative.startsWith('..') || path.isAbsolute(relative)) {
39+
throw new Error(`Refusing to remove path outside workspace: ${resolvedTarget}`);
40+
}
41+
42+
rmSync(resolvedTarget, { recursive: true, force: true });
43+
}
44+
45+
if (!existsSync(venvPython)) {
46+
run(systemPython, ['-m', 'venv', buildVenv]);
47+
}
48+
49+
run(venvPython, ['-m', 'pip', 'install', '--upgrade', 'pip']);
50+
run(venvPython, ['-m', 'pip', 'install', '-r', path.join(root, 'requirements.txt'), 'pyinstaller']);
51+
52+
removeWorkspacePath(pythonDist);
53+
removeWorkspacePath(webWork);
54+
removeWorkspacePath(proxyWork);
55+
56+
run(venvPython, [
57+
'-m',
58+
'PyInstaller',
59+
'--noconfirm',
60+
'--clean',
61+
'--distpath',
62+
pythonDist,
63+
'--workpath',
64+
webWork,
65+
'--specpath',
66+
webWork,
67+
'--name',
68+
'hash-web-server',
69+
path.join(root, 'web_server.py'),
70+
]);
71+
72+
run(venvPython, [
73+
'-m',
74+
'PyInstaller',
75+
'--noconfirm',
76+
'--clean',
77+
'--distpath',
78+
pythonDist,
79+
'--workpath',
80+
proxyWork,
81+
'--specpath',
82+
proxyWork,
83+
'--name',
84+
'hash-proxy-server',
85+
path.join(root, 'proxy_server.py'),
86+
]);

0 commit comments

Comments
 (0)