Skip to content

Commit 7d6305e

Browse files
committed
Release v1.1.1
1 parent b5c0ede commit 7d6305e

18 files changed

Lines changed: 599 additions & 215 deletions

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,6 @@ logs/
1313
data/
1414
data-gym-cache/
1515
react_app/dist/
16+
packaging/.cache/
17+
packaging/dist/
1618
tmp*/

GITHUB_RELEASE.md

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,24 @@
1-
# Codex Context Studio v1.1.0
1+
# Codex Context Studio v1.1.1
22

3-
A visual, editable context layer for Codex. This release focuses on the Context Studio identity, clearer bilingual documentation, and safer transcript rebuilding for newer Codex request metadata.
3+
This release updates the Windows packaging pipeline and makes the installed app use a bundled embedded Python runtime instead of the previous PyInstaller server executables.
44

55
## What's New
66

7-
- Renamed the user-facing project identity to Codex Context Studio
8-
- Reworked the English and Chinese READMEs with updated feature descriptions, architecture diagrams, and screenshots
9-
- Moved screenshots into language-specific folders for clearer documentation
10-
- Preserved Codex internal turn metadata and turn IDs when rebuilding request input
11-
- Added support for `custom_tool_call.namespace` during response-to-request projection
12-
- Improved compact request metadata detection across differently cased client metadata keys
13-
- Localized grouped tool-call labels in the context workbench
14-
- Expanded proxy core and cursor delta tests for metadata and request rebuild behavior
7+
- Replaced the old PyInstaller packaging path with a dedicated `packaging/` build pipeline
8+
- Bundled an embedded Python runtime into the Electron app package
9+
- Updated Electron startup to run backend services through `python -m backend.web_server` and `python -m backend.proxy_fastapi`
10+
- Moved NSIS installer customization into `packaging/windows/installer.nsh`
11+
- Updated CLI and Desktop shims so hooks and notifications resolve through the installed shim directory
12+
- Improved Desktop config repair for managed notify commands
13+
- Redirected packaged Electron window logs to the user state log directory
14+
- Updated documentation to use `npm run package:win`
1515

1616
## Download
1717

1818
Download and run:
1919

2020
```text
21-
Codex Context Proxy Setup 1.1.0.exe
21+
Codex Context Proxy Setup 1.1.1.exe
2222
```
2323

2424
After installation, open a new terminal and enable the proxy:
@@ -42,6 +42,5 @@ codex ctx proxy off
4242
## Notes
4343

4444
- This project does not replace Codex.
45-
- It does not modify the official Codex CLI source code.
4645
- CLI support is the primary path.
4746
- Codex Desktop support is experimental because it modifies local Codex configuration.

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ npm run typecheck
166166
npm test
167167
168168
# Build Windows installer
169-
npm run dist:win
169+
npm run package:win
170170
```
171171

172172
---

README.zh-CN.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ npm run typecheck
167167
npm test
168168
169169
# 构建 Windows 安装包
170-
npm run dist:win
170+
npm run package:win
171171
```
172172

173173
---

RELEASE.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,20 @@
1111

1212
```powershell
1313
npm install
14-
npm run dist:win
14+
npm run package:win
1515
```
1616

1717
生成的安装包在:
1818

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

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

2525
## 用户怎么用
2626

27-
用户安装 `Codex Context Proxy Setup 1.1.0.exe` 后,安装器会自动安装 `codex ctx proxy ...` 控制命令,但不会默认打开代理。
27+
用户安装 `Codex Context Proxy Setup 1.1.1.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 1.1.0.exe
106+
release/Codex Context Proxy Setup 1.1.1.exe
107107
```
108108

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

backend/codex_item_registry.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
from __future__ import annotations
22

33
import json
4-
import sys
54
from dataclasses import dataclass
65
from pathlib import Path
76
from typing import Any
@@ -108,9 +107,6 @@ def _resolve_registry_path() -> Path:
108107
Path(__file__).resolve().parents[1] / REGISTRY_RELATIVE_PATH,
109108
Path.cwd() / REGISTRY_RELATIVE_PATH,
110109
]
111-
pyinstaller_root = getattr(sys, "_MEIPASS", None)
112-
if pyinstaller_root:
113-
candidates.insert(0, Path(pyinstaller_root) / REGISTRY_RELATIVE_PATH)
114110

115111
for candidate in candidates:
116112
if candidate.is_file():

electron/context-window.cjs

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -250,10 +250,10 @@ function sourcePythonCandidates(root) {
250250
return candidates;
251251
}
252252

253-
function pythonScriptCommand(root, scriptName) {
253+
function pythonModuleCommand(root, moduleName) {
254254
for (const candidate of sourcePythonCandidates(root)) {
255255
if (pythonCandidateWorks(candidate)) {
256-
return { command: candidate.command, args: [...candidate.args, scriptName] };
256+
return { command: candidate.command, args: [...candidate.args, '-m', moduleName] };
257257
}
258258
}
259259

@@ -267,31 +267,35 @@ function pythonScriptCommand(root, scriptName) {
267267
throw new Error('No usable Python runtime found. Run npm run setup:python or set HASH_CONTEXT_PYTHON to a Python with the project dependencies installed.');
268268
}
269269

270-
function pythonServerCommand(root, scriptName, exeName) {
271-
const preferSource =
272-
process.env.HASH_CONTEXT_PREFER_SOURCE_SERVERS === '1' ||
273-
(!app.isPackaged && process.env.HASH_CONTEXT_USE_BUNDLED_PYTHON !== '1');
274-
if (preferSource) {
275-
return pythonScriptCommand(root, scriptName);
276-
}
277-
270+
function bundledPythonCommand(root, moduleName) {
278271
const candidates = process.platform === 'win32'
279272
? [
280-
path.join(root, 'python_dist', exeName, `${exeName}.exe`),
281-
path.join(root, 'python_dist', `${exeName}.exe`),
273+
path.join(root, 'python-runtime', 'python.exe'),
274+
path.join(process.resourcesPath || root, 'app', 'python-runtime', 'python.exe'),
282275
]
283276
: [
284-
path.join(root, 'python_dist', exeName),
285-
path.join(root, 'python_dist', exeName, exeName),
277+
path.join(root, 'python-runtime', 'bin', 'python3'),
278+
path.join(root, 'python-runtime', 'bin', 'python'),
286279
];
287280

288-
for (const bundledExecutable of candidates) {
289-
if (fs.existsSync(bundledExecutable)) {
290-
return { command: bundledExecutable, args: [] };
281+
for (const bundledPython of candidates) {
282+
if (fs.existsSync(bundledPython)) {
283+
return { command: bundledPython, args: ['-m', moduleName] };
291284
}
292285
}
293286

294-
return pythonScriptCommand(root, scriptName);
287+
return null;
288+
}
289+
290+
function pythonServerCommand(root, moduleName) {
291+
const preferSource =
292+
process.env.HASH_CONTEXT_PREFER_SOURCE_SERVERS === '1' ||
293+
(!app.isPackaged && process.env.HASH_CONTEXT_USE_BUNDLED_PYTHON !== '1');
294+
if (preferSource) {
295+
return pythonModuleCommand(root, moduleName);
296+
}
297+
298+
return bundledPythonCommand(root, moduleName) || pythonModuleCommand(root, moduleName);
295299
}
296300

297301
function pythonPathForRoot(root) {
@@ -315,13 +319,15 @@ function cleanEnv(extra = {}) {
315319
function pipeChildLogs(child, label) {
316320
child.stdout.on('data', (chunk) => {
317321
const text = chunk.toString().trim();
318-
console.log(`[${label}] ${text}`);
319-
writeLog(`[${label}] ${text}`);
322+
if (text) {
323+
writeLog(`[${label}] ${text}`);
324+
}
320325
});
321326
child.stderr.on('data', (chunk) => {
322327
const text = chunk.toString().trim();
323-
console.error(`[${label}] ${text}`);
324-
writeLog(`[${label}:error] ${text}`);
328+
if (text) {
329+
writeLog(`[${label}:error] ${text}`);
330+
}
325331
});
326332
}
327333

@@ -333,7 +339,7 @@ async function startBackend(root) {
333339
}
334340

335341
writeLog('starting backend');
336-
const serverCommand = pythonServerCommand(root, path.join('backend', 'web_server.py'), 'hash-web-server');
342+
const serverCommand = pythonServerCommand(root, 'backend.web_server');
337343
backendProcess = spawn(serverCommand.command, serverCommand.args, {
338344
cwd: root,
339345
env: cleanEnv({
@@ -361,7 +367,7 @@ async function startProxy(root) {
361367
}
362368

363369
writeLog('starting proxy');
364-
const serverCommand = pythonServerCommand(root, path.join('backend', 'proxy_fastapi.py'), 'hash-proxy-server');
370+
const serverCommand = pythonServerCommand(root, 'backend.proxy_fastapi');
365371
proxyProcess = spawn(serverCommand.command, serverCommand.args, {
366372
cwd: root,
367373
env: cleanEnv({

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: 3 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "hash-context-codex-lab",
3-
"version": "1.1.0",
3+
"version": "1.1.1",
44
"private": true,
55
"description": "Local context proxy and workbench companion for Codex.",
66
"author": "",
@@ -32,12 +32,9 @@
3232
"test:frontend-contract": "node scripts/run-frontend-contract-tests.mjs",
3333
"build": "npm run build:react",
3434
"build:react": "vite build --config react_app/vite.config.ts",
35-
"build:python": "node scripts/build-python.mjs",
3635
"preview:react": "vite preview --config react_app/vite.config.ts",
37-
"pack:win": "npm run build:react && npm run build:python && electron-builder --win --dir",
38-
"dist:win": "npm run build:react && npm run build:python && electron-builder --win nsis --publish never",
39-
"pack:mac": "npm run build:react && npm run build:python && electron-builder --mac --dir",
40-
"dist:mac": "npm run build:react && npm run build:python && electron-builder --mac --publish never"
36+
"package:win": "node packaging/build.mjs --target installer",
37+
"package:win:dir": "node packaging/build.mjs --target dir"
4138
},
4239
"dependencies": {
4340
"@phosphor-icons/web": "^2.1.2",
@@ -61,55 +58,5 @@
6158
"electron-builder": "^26.8.1",
6259
"typescript": "^5.9.3",
6360
"vite": "^7.1.12"
64-
},
65-
"build": {
66-
"appId": "dev.codex-context.proxy",
67-
"productName": "Codex Context Proxy",
68-
"asar": false,
69-
"directories": {
70-
"output": "release"
71-
},
72-
"files": [
73-
"electron/**/*",
74-
"codex_context.py",
75-
"backend/**/*",
76-
"requirements.txt",
77-
"RELEASE.md",
78-
".env.example",
79-
"static/**/*",
80-
"react_app/dist/**/*",
81-
"python_dist/*",
82-
"python_dist/**/*",
83-
"shared/**/*",
84-
"scripts/**/*",
85-
"simple_agent/**/*",
86-
"agent_runtime/**/*",
87-
"package.json"
88-
],
89-
"win": {
90-
"icon": "electron/assets/hash-icon.ico",
91-
"target": "nsis",
92-
"signAndEditExecutable": false,
93-
"forceCodeSigning": false
94-
},
95-
"mac": {
96-
"icon": "electron/assets/hash-icon.icns",
97-
"target": [
98-
"dmg",
99-
"zip"
100-
],
101-
"artifactName": "${productName}-${version}-${os}-${arch}.${ext}",
102-
"category": "public.app-category.developer-tools",
103-
"hardenedRuntime": false,
104-
"gatekeeperAssess": false,
105-
"identity": null
106-
},
107-
"nsis": {
108-
"oneClick": false,
109-
"allowToChangeInstallationDirectory": true,
110-
"installerIcon": "electron/assets/hash-icon.ico",
111-
"uninstallerIcon": "electron/assets/hash-icon.ico",
112-
"include": "build/installer.nsh"
113-
}
11461
}
11562
}

packaging/after-pack.cjs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
const { existsSync } = require('node:fs');
2+
const path = require('node:path');
3+
const { spawnSync } = require('node:child_process');
4+
5+
function assertFile(filePath, label) {
6+
if (!existsSync(filePath)) {
7+
throw new Error(`${label} was not found: ${filePath}`);
8+
}
9+
}
10+
11+
function run(command, args) {
12+
const result = spawnSync(command, args, { stdio: 'inherit' });
13+
if (result.error) {
14+
throw result.error;
15+
}
16+
if (result.status !== 0) {
17+
throw new Error(`${command} failed with exit code ${result.status}`);
18+
}
19+
}
20+
21+
module.exports = async function afterPack(context) {
22+
if (context.electronPlatformName !== 'win32') {
23+
return;
24+
}
25+
26+
const projectDir = context.packager.projectDir;
27+
const appInfo = context.packager.appInfo;
28+
const productName = appInfo.productName || 'Codex Context Proxy';
29+
const productFilename = appInfo.productFilename || productName;
30+
const version = appInfo.version;
31+
const exePath = path.join(context.appOutDir, `${productFilename}.exe`);
32+
const iconPath = path.join(projectDir, 'electron', 'assets', 'hash-icon.ico');
33+
const rceditPath = path.join(projectDir, 'node_modules', 'electron-winstaller', 'vendor', 'rcedit.exe');
34+
35+
assertFile(exePath, 'Packaged executable');
36+
assertFile(iconPath, 'Executable icon');
37+
assertFile(rceditPath, 'rcedit executable');
38+
39+
run(rceditPath, [
40+
exePath,
41+
'--set-icon',
42+
iconPath,
43+
'--set-version-string',
44+
'ProductName',
45+
productName,
46+
'--set-version-string',
47+
'FileDescription',
48+
productName,
49+
'--set-version-string',
50+
'CompanyName',
51+
productName,
52+
'--set-file-version',
53+
version,
54+
'--set-product-version',
55+
version,
56+
]);
57+
};

0 commit comments

Comments
 (0)