Skip to content

Commit e1b9707

Browse files
committed
docs: add AI operator manual and patch profiles
1 parent 2267a91 commit e1b9707

9 files changed

Lines changed: 327 additions & 19 deletions

File tree

README-zh.md

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,18 @@
4444
- 修改 VS Code 扩展文件前先备份(保留 *.bak)。
4545
4646
步骤:
47-
1) 在本仓库运行:`npm test`
48-
2) 应用补丁到已安装扩展:`npm run apply`
49-
3) 幂等验证:`npm run verify`
50-
4) 告诉我编辑 `C:\Users\<我>\.codex\config.toml` 并设置:
47+
1) 克隆本仓库并以仓库根目录作为工作目录:
48+
`git clone https://github.com/MaxMiksa/Codex-Folding.git`
49+
2) 运行:`npm test`
50+
3) 运行:`node tools/workflow-fold/inspect.mjs`
51+
4) 应用补丁到已安装扩展:`npm run apply`
52+
5) 幂等验证:`npm run verify`
53+
6) 告诉我编辑 `C:\Users\<我>\.codex\config.toml` 并设置:
5154
`codex.workflow.collapseByDefault = "collapse"`
52-
5) 告诉我重启 VS Code。
53-
6) 输出所有被修改文件及其备份文件的绝对路径。
55+
7) 告诉我重启 VS Code。
56+
8) 输出所有被修改文件及其备份文件的绝对路径。
57+
9) 另外为我保存一份本地手册副本:
58+
`docs/AI_OPERATOR_MANUAL.md`
5459
```
5560

5661
### 卸载 Prompt(发给 AI)
@@ -113,4 +118,3 @@
113118
如有任何问题或建议,请联系 Zheyuan (Max) Kong (卡内基梅隆大学,宾夕法尼亚州)。
114119

115120
Zheyuan (Max) Kong: kongzheyuan@outlook.com | zheyuank@andrew.cmu.edu
116-

README.md

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,18 @@ Constraints:
4444
- Create backups of any modified VS Code extension files (keep *.bak).
4545
4646
Steps:
47-
1) In this repo, run: `npm test`
48-
2) Apply the patch to the installed extension: `npm run apply`
49-
3) Verify idempotence: `npm run verify`
50-
4) Tell me to edit `C:\Users\<ME>\.codex\config.toml` and set:
47+
1) Clone this repo and open it as your working directory:
48+
`git clone https://github.com/MaxMiksa/Codex-Folding.git`
49+
2) Run: `npm test`
50+
3) Run: `node tools/workflow-fold/inspect.mjs`
51+
4) Apply the patch: `npm run apply`
52+
5) Verify idempotence: `npm run verify`
53+
6) Tell me to edit `C:\Users\<ME>\.codex\config.toml` and set:
5154
`codex.workflow.collapseByDefault = "collapse"`
52-
5) Tell me to restart VS Code.
53-
6) Output the absolute paths of modified files and their backups.
55+
7) Tell me to restart VS Code.
56+
8) Output the absolute paths of modified files and their backups.
57+
9) Also save a local copy of this manual for me:
58+
`docs/AI_OPERATOR_MANUAL.md`
5459
```
5560

5661
### Uninstall Prompt (give to AI)
@@ -114,4 +119,3 @@ Welcome to submit Issues and Pull Requests!
114119
Any questions or suggestions? Please contact Zheyuan (Max) Kong (Carnegie Mellon University, Pittsburgh, PA).
115120

116121
Zheyuan (Max) Kong: kongzheyuan@outlook.com | zheyuank@andrew.cmu.edu
117-

docs/AI_OPERATOR_MANUAL.md

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# Codex Folding — AI Operator Manual (Single Source of Truth)
2+
3+
This manual is designed for an AI agent to perform a deterministic install/uninstall on Windows with minimal guesswork.
4+
5+
## Goal
6+
7+
Install **Workflow folding** into the Codex VS Code extension (`openai.chatgpt`) so that each turn shows:
8+
1) user message (unchanged)
9+
2) `Workflow` folding row (new)
10+
3) final answer (unchanged)
11+
12+
All pre-final process items (reasoning/tool calls/tool output/status/error items) must be inside the `Workflow` fold.
13+
14+
## Preconditions
15+
16+
- Windows
17+
- VS Code installed
18+
- Codex extension installed: Publisher `OpenAI`, Extension id `openai.chatgpt`
19+
- Node.js available (no dependencies required for this repo’s scripts)
20+
21+
## Parameters (config)
22+
23+
- Config file: `%USERPROFILE%\.codex\config.toml`
24+
- Key: `codex.workflow.collapseByDefault`
25+
- Values:
26+
- `"collapse"`: show Workflow, default collapsed
27+
- `"expand"`: show Workflow, default expanded
28+
- `"disable"`: disable feature (upstream behavior)
29+
- Default: missing key is treated as `"disable"`
30+
- Note: VS Code restart is required after config changes.
31+
32+
## Install Steps (deterministic)
33+
34+
1. Clone repo
35+
- `git clone https://github.com/MaxMiksa/Codex-Folding.git`
36+
- `cd Codex-Folding`
37+
38+
2. Run unit tests
39+
- `npm test`
40+
41+
3. Inspect local environment & compatibility
42+
- Run: `node tools/workflow-fold/inspect.mjs`
43+
- The inspector must:
44+
- detect installed extension dir under `%USERPROFILE%\.vscode\extensions\openai.chatgpt-*`
45+
- read extension `package.json` for version (if available)
46+
- find the active webview bundle referenced by `webview/index.html`
47+
- report whether there is a matching profile under `docs/patch-profiles/openai.chatgpt/<version>/`
48+
49+
4. Apply patch (creates backups once)
50+
- `npm run apply`
51+
- Must create backups `*.bak` next to each modified file (only if missing).
52+
53+
5. Configure default collapse
54+
- Ensure `%USERPROFILE%\.codex\config.toml` contains:
55+
- `codex.workflow.collapseByDefault = "collapse"`
56+
57+
6. Restart VS Code
58+
59+
7. Verify install
60+
- `npm run verify`
61+
- Confirm:
62+
- `Workflow` appears per turn
63+
- timer updates while running
64+
- expanded workflow preserves original content rendering
65+
66+
## Uninstall Steps (deterministic)
67+
68+
1. Locate the installed extension directory:
69+
- `%USERPROFILE%\.vscode\extensions\openai.chatgpt-*`
70+
71+
2. Restore originals from backups (do not delete backups)
72+
- Restore:
73+
- `out\extension.js` from `out\extension.js.bak`
74+
- active `webview\assets\index-*.js` from its `.bak`
75+
- `webview\assets\zh-CN-*.js` from its `.bak`
76+
77+
3. Restart VS Code
78+
79+
4. Verify uninstall
80+
- Ensure markers are absent:
81+
- `CODEX_WORKFLOW_FOLD_PATCH`
82+
- `codex-workflow-collapse`
83+
84+
## What files are modified (installed extension)
85+
86+
The patch touches exactly 3 installed files (plus backups):
87+
- `out/extension.js`
88+
- `webview/assets/index-*.js` (the entry referenced by `webview/index.html`)
89+
- `webview/assets/zh-CN-*.js`
90+
91+
The exact injected snippets are documented here:
92+
- `docs/patch-profiles/openai.chatgpt/0.4.66-win32-x64/INJECTION_host_extension.js.txt`
93+
- `docs/patch-profiles/openai.chatgpt/0.4.66-win32-x64/INJECTION_webview_index.js.txt`
94+
- `docs/patch-profiles/openai.chatgpt/0.4.66-win32-x64/INJECTION_zh-CN.js.txt`
95+
96+
For absolute path examples and the author machine’s recorded changes:
97+
- `docs/FILES_CHANGED_ABSOLUTE.md`

docs/INSTALL_FOR_AI.md

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,21 @@
1414
- Command: `npm test`
1515
- Expected: PASS
1616

17-
2. Apply patch (creates `*.bak` backups once)
17+
2. Inspect compatibility (recommended)
18+
- Command: `node tools/workflow-fold/inspect.mjs`
19+
- Expected:
20+
- Prints the installed extension folder name (`openai.chatgpt-...`)
21+
- Prints the active webview bundle (`webview/assets/index-*.js`)
22+
- Prints whether a matching profile exists under `docs/patch-profiles/openai.chatgpt/<version>/` (preferred)
23+
24+
3. Apply patch (creates `*.bak` backups once)
1825
- Command: `npm run apply`
1926
- Expected: outputs `PATCHED:` or `OK:` lines, no errors
2027

21-
3. Verify idempotence (no changes on second run)
28+
4. Verify idempotence (no changes on second run)
2229
- Command: `npm run verify`
2330

24-
4. Configure default behavior
31+
5. Configure default behavior
2532
- Edit `C:\Users\<USER>\.codex\config.toml`
2633
- Set:
2734
- `codex.workflow.collapseByDefault = "collapse"`
@@ -30,7 +37,7 @@
3037
- `"expand"`: show Workflow and default expanded
3138
- `"disable"`: disable feature (upstream behavior)
3239

33-
5. Restart VS Code
40+
6. Restart VS Code
3441

3542
## What gets modified
3643

@@ -40,4 +47,3 @@
4047
- `webview\assets\zh-CN-*.js` (adds i18n strings)
4148

4249
See `docs/FILES_CHANGED_ABSOLUTE.md` for absolute paths on the author machine.
43-
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
Host patch (injected into installed extension `out/extension.js`)
2+
3+
Purpose:
4+
- Read `%USERPROFILE%\.codex\config.toml` and extract:
5+
`codex.workflow.collapseByDefault = "collapse" | "expand" | "disable"`
6+
- Inject the value into the webview HTML as:
7+
`<meta name="codex-workflow-collapse" content="...">`
8+
9+
Injected snippet (minified style, inserted inside `getWebviewContentProduction` before `return l`):
10+
11+
let wf="disable";try{let d=wt({preferWsl:Bt()}),f=MB.join(d,"config.toml"),txt=await jy.promises.readFile(f,"utf-8");let m=txt.match(/^\s*codex\.workflow\.collapseByDefault\s*=\s*"(collapse|expand|disable)"\s*$/m);m&&(wf=m[1])}catch{}l=l.replace("</head>",`<meta name="codex-workflow-collapse" content="${wf}">\n</head>`);
12+
13+
Verification marker:
14+
- The patched file must contain the string: `codex-workflow-collapse`
15+
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
Webview patch (injected into installed webview bundle `webview/assets/index-*.js`)
2+
3+
Purpose:
4+
- Add a synthetic `workflow` item per turn that groups all “process items” between:
5+
- `user-message` (start of turn)
6+
- `assistant-message` (final answer)
7+
- Render `workflow` as a clickable header (fold/unfold), with:
8+
- status: `Working` / `Done`
9+
- timer: updates every 1s while running
10+
- Preserve original rendering of children when expanded.
11+
12+
Key behaviors:
13+
- If `codex.workflow.collapseByDefault` is:
14+
- `disable`: do nothing (upstream behavior)
15+
- `collapse`: show Workflow, default folded
16+
- `expand`: show Workflow, default expanded
17+
- Detects mode from:
18+
`<meta name="codex-workflow-collapse" content="...">`
19+
20+
Verification marker:
21+
- The patched file must contain the string: `CODEX_WORKFLOW_FOLD_PATCH`
22+
23+
Injected patch code is owned by this repo and can be reviewed in:
24+
- `tools/workflow-fold/patcher.mjs` (search for `CODEX_WORKFLOW_FOLD_PATCH`)
25+
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
Locale patch (injected into `webview/assets/zh-CN-*.js`)
2+
3+
Adds a few i18n keys used by the Workflow header:
4+
5+
- `codex.workflow.label`: 工作流
6+
- `codex.workflow.status.working`: 进行中
7+
- `codex.workflow.status.done`: 完成
8+
- `codex.workflow.headerSuffix`: ({status},{elapsed})
9+
10+
Verification marker:
11+
- The patched file must contain the string: `codex.workflow.label`
12+
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
{
2+
"extension": {
3+
"publisher": "OpenAI",
4+
"id": "openai.chatgpt",
5+
"folderName": "openai.chatgpt-0.4.66-win32-x64",
6+
"testedOn": {
7+
"os": "Windows",
8+
"codexCli": "0.89.0"
9+
}
10+
},
11+
"targets": [
12+
{
13+
"kind": "host",
14+
"relativePath": "out/extension.js",
15+
"backupSuffix": ".bak",
16+
"verifyIncludes": ["codex-workflow-collapse"]
17+
},
18+
{
19+
"kind": "webview",
20+
"relativePath": "webview/assets/index-*.js",
21+
"backupSuffix": ".bak",
22+
"verifyIncludes": ["CODEX_WORKFLOW_FOLD_PATCH"]
23+
},
24+
{
25+
"kind": "i18n",
26+
"relativePath": "webview/assets/zh-CN-*.js",
27+
"backupSuffix": ".bak",
28+
"verifyIncludes": ["codex.workflow.label"]
29+
}
30+
],
31+
"config": {
32+
"file": "%USERPROFILE%/.codex/config.toml",
33+
"key": "codex.workflow.collapseByDefault",
34+
"values": ["collapse", "expand", "disable"],
35+
"default": "disable",
36+
"restartRequired": true
37+
}
38+
}
39+

tools/workflow-fold/inspect.mjs

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import fs from "node:fs/promises";
2+
import path from "node:path";
3+
import os from "node:os";
4+
5+
async function fileExists(p) {
6+
try {
7+
await fs.access(p);
8+
return true;
9+
} catch {
10+
return false;
11+
}
12+
}
13+
14+
async function findInstalledExtensionDirs() {
15+
const base = path.join(os.homedir(), ".vscode", "extensions");
16+
if (!(await fileExists(base))) return [];
17+
const entries = await fs.readdir(base, { withFileTypes: true });
18+
return entries
19+
.filter((e) => e.isDirectory() && e.name.startsWith("openai.chatgpt-"))
20+
.map((e) => ({ name: e.name, dir: path.join(base, e.name) }));
21+
}
22+
23+
async function readActiveWebviewBundle(extDir) {
24+
const htmlPath = path.join(extDir, "webview", "index.html");
25+
const html = await fs.readFile(htmlPath, "utf8");
26+
const m = html.match(/src="\.\/assets\/(index-[^"]+\.js)"/);
27+
if (!m) return null;
28+
return m[1];
29+
}
30+
31+
async function readExtensionPackageJson(extDir) {
32+
const p = path.join(extDir, "package.json");
33+
try {
34+
const txt = await fs.readFile(p, "utf8");
35+
return JSON.parse(txt);
36+
} catch {
37+
return null;
38+
}
39+
}
40+
41+
async function findProfileForFolderName(folderName) {
42+
const base = path.join(process.cwd(), "docs", "patch-profiles", "openai.chatgpt");
43+
44+
// Preferred: match the "version part" (folder name without publisher/id prefix),
45+
// e.g. "openai.chatgpt-0.4.66-win32-x64" -> "0.4.66-win32-x64".
46+
const versionPart = folderName.startsWith("openai.chatgpt-")
47+
? folderName.slice("openai.chatgpt-".length)
48+
: folderName;
49+
50+
const candidates = [
51+
path.join(base, versionPart),
52+
path.join(base, folderName),
53+
];
54+
55+
for (const p of candidates) {
56+
if (await fileExists(p)) return p;
57+
}
58+
return null;
59+
}
60+
61+
function out(lines) {
62+
process.stdout.write(lines.filter(Boolean).join("\n") + "\n");
63+
}
64+
65+
async function main() {
66+
const dirs = await findInstalledExtensionDirs();
67+
if (dirs.length === 0) {
68+
out([
69+
"No installed VS Code extension found matching: openai.chatgpt-*",
70+
`Searched: ${path.join(os.homedir(), ".vscode", "extensions")}`,
71+
]);
72+
process.exit(2);
73+
}
74+
75+
// Prefer newest mtime.
76+
const stats = await Promise.all(
77+
dirs.map(async (d) => ({ ...d, stat: await fs.stat(d.dir) }))
78+
);
79+
stats.sort((a, b) => b.stat.mtimeMs - a.stat.mtimeMs);
80+
81+
const chosen = stats[0];
82+
const folderName = chosen.name;
83+
const extDir = chosen.dir;
84+
const pkg = await readExtensionPackageJson(extDir);
85+
const activeWebview = await readActiveWebviewBundle(extDir);
86+
const profile = await findProfileForFolderName(folderName);
87+
88+
out([
89+
`Installed extension folder: ${extDir}`,
90+
pkg?.version ? `Extension version (package.json): ${pkg.version}` : null,
91+
activeWebview ? `Active webview bundle: webview/assets/${activeWebview}` : null,
92+
profile ? `Matching patch profile: ${profile}` : "Matching patch profile: (none)",
93+
"",
94+
"Recommended next steps:",
95+
"1) Run tests: `npm test`",
96+
"2) Apply patch: `npm run apply`",
97+
"3) Verify (idempotent): `npm run verify`",
98+
"",
99+
"If no matching profile exists:",
100+
"- You can still try applying the patch (it uses robust anchors + markers).",
101+
"- If patching fails, collect the folder name + active bundle name and add a new profile folder under:",
102+
" `docs/patch-profiles/openai.chatgpt/<folderName>/`",
103+
]);
104+
}
105+
106+
await main();

0 commit comments

Comments
 (0)