Skip to content

Commit 4f0633f

Browse files
committed
merge(dev): resolve openai-chat EOF conflict for #793
Keep the restored #773 finish-less EOF rules (answer text required; pending tool calls fail closed before flush) while taking tip's clearer mid-tool-call truncation message.
2 parents 413027e + f2b61ee commit 4f0633f

1,883 files changed

Lines changed: 209295 additions & 2279 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,19 @@ dist/
44
*.log
55
.DS_Store
66

7-
# Maintainer-only planning notes. `devlog` is a private submodule
8-
# (lidge-jun/opencodex-internal) pinned by gitlink; its contents are never
9-
# tracked here. Commit inside the submodule, then bump the pointer separately.
10-
devlog/
7+
# Maintainer planning notes are TRACKED in this repository (`devlog/`). Security
8+
# material is not: see the "Security working notes" section of AGENTS.md.
9+
#
10+
# These exclusions were previously enforced by devlog's own .gitignore, which stops
11+
# applying now that devlog is not a separate repository. Reference clones are
12+
# third-party source with their own licenses and must never enter this history.
13+
devlog/_chase/_cca/
14+
devlog/_chase/_litellm/
15+
devlog/_fin/opencode-cursor/
16+
devlog/_plan/*/_ref_*/
17+
devlog/**/*-security-redaction/
18+
devlog/**/*_security_findings/
19+
devlog/**/security-advisory-draft*
1120

1221
# Scratch space. Security working notes — unreleased findings, draft advisories,
1322
# exploit reasoning, pre-disclosure patch plans — belong here or in a

.gitmodules

Lines changed: 0 additions & 6 deletions
This file was deleted.

AGENTS.md

Lines changed: 46 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -22,42 +22,39 @@ Bun-native TypeScript with no separate server compile step.
2222
changing shared subsystems.
2323
- `scripts/` — release and maintenance tooling; `scripts/release.ts` is the
2424
release authority.
25-
- `devlog/` — maintainer-only planning and investigation notes. This is a
26-
**private submodule** (`lidge-jun/opencodex-internal`), not a directory of
27-
this repository. See "The `devlog` submodule" below.
25+
- `devlog/` — planning and investigation notes, tracked in this repository. See
26+
"The `devlog` directory" below for what may and may not go there.
2827

2928
Read the nearest nested `AGENTS.md` before changing files in a scoped
3029
directory (`src/`, `gui/`, `docs-site/`, `scripts/`, `.github/`).
3130

32-
## The `devlog` submodule
33-
34-
Planning notes, triage matrices, and investigation artifacts live in the private
35-
`lidge-jun/opencodex-internal` repository, wired in as the `devlog` submodule.
36-
They quote live infrastructure state, provider behaviour, unfixed defects, and
37-
internal triage reasoning, so a public clone should carry the runtime and its
38-
docs and nothing else.
39-
40-
The pointer is deliberately **loose**, so a missing or stale `devlog` can never
41-
fail a check:
42-
43-
- `.gitmodules` declares `ignore = dirty`, `update = none`, and `shallow = true`.
44-
A dirty or moved submodule working tree does not show up in `git status` on
45-
the parent, and `git submodule update` will not touch it unless asked
46-
explicitly.
47-
- No workflow checks it out. `actions/checkout` runs without `submodules:`, so
48-
CI clones the public tree only and the private URL is never resolved.
49-
- Nothing in the build, test, typecheck, or privacy-scan path reads from
50-
`devlog/`. Contributors without access see an empty directory and every gate
51-
still passes.
52-
- `devlog/` stays listed in `.gitignore` for the working tree; the submodule
53-
gitlink is tracked, its contents are not.
54-
55-
Two rules keep it that way. Never commit anything under `devlog/` to *this*
56-
repository — commit inside the submodule, then update the pointer here as a
57-
separate commit. And never nest a git repository inside the submodule: a
58-
`160000` gitlink in a tree that CI does not initialize breaks
59-
`actions/checkout` for every contributor, which is exactly what happened before
60-
this split.
31+
## The `devlog` directory
32+
33+
Planning notes, triage matrices, and investigation artifacts live in `devlog/`,
34+
tracked like any other documentation. There is no submodule and no private
35+
mirror. It was a private submodule until the pointer churn outgrew its value:
36+
1723 commits touched the gitlink, and `dev`, `preview`, and `main` each carried a
37+
different pointer, so every branch move and promotion dragged a diff.
38+
39+
- `devlog/_plan/` — units still open, one directory per unit, decade-numbered
40+
docs.
41+
- `devlog/_fin/` — closed units, moved here once a terminal outcome is recorded.
42+
A `_fin` unit is a record of work already visible in public git history.
43+
- `devlog/_chase/` — external reference material for parity comparisons.
44+
Reference *clones* are gitignored: they are third-party source carrying their
45+
own licenses and have no business in this repository's history.
46+
47+
Nothing in the build, typecheck, or test path reads from `devlog/`, so a
48+
contributor who ignores it entirely still passes every gate. `privacy:scan` does
49+
read it — that is deliberate, and it is what makes a public devlog safe rather
50+
than merely visible.
51+
52+
Two mechanical guards in `tests/repo-hygiene.test.ts` back this up: no `160000`
53+
gitlink may be tracked anywhere, and neither the vendored reference clones nor
54+
the security triage excised before publication may reappear in the index. Both
55+
were driven red once to prove they are not vacuous. The gitlink assertion exists
56+
because a gitlink in a tree CI does not initialize breaks `actions/checkout` for
57+
every contributor, which happened twice.
6158

6259
## Security working notes
6360

@@ -67,9 +64,23 @@ or bypass reasoning, reproduction steps for an unfixed defect, and
6764
pre-disclosure patch plans.
6865

6966
Use `.tmp/` in the working tree (already gitignored) or a `mktemp -d` path.
70-
`devlog/` is **not** an acceptable location, and neither is a private
71-
repository: both get cloned across machines and CI, both outlive the embargo,
72-
and neither history is practical to purge afterwards.
67+
`devlog/` is **not** an acceptable location — it is a public directory in a
68+
public repository, so anything committed there is disclosed the moment it is
69+
pushed, and the history is not practical to purge afterwards. A private
70+
repository is not acceptable either: it gets cloned across machines and CI and
71+
outlives the embargo.
72+
73+
**This binds maintainers exactly as it binds contributors and agents.** The rule
74+
has been violated by maintainer-authored triage before: two units of open
75+
security review accumulated under `devlog/_plan/` and had to be excised before
76+
this directory could be published. Seniority is not an exemption, and "it is
77+
only in the private half" is no longer a thing that exists.
78+
79+
The test to apply before writing a security note into `devlog/`: **is there
80+
already a public diff that reveals this weakness?** If the fix has shipped, the
81+
writeup discloses nothing new and belongs in `_fin/`. If it has not, the note is
82+
pre-disclosure material and goes to scratch. That distinction is why closed
83+
hardening records stay in the tree while open triage does not.
7384

7485
Only the published outcome reaches a repository — the fix itself, its
7586
regression test, the release note, the advisory once it is public. Draft the

bin/ocx.mjs

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@
1010
*/
1111
import { spawn, spawnSync } from "node:child_process";
1212
import { createRequire } from "node:module";
13-
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
13+
import { existsSync, readFileSync, readdirSync } from "node:fs";
1414
import { homedir } from "node:os";
1515
import { dirname, join, resolve } from "node:path";
1616
import { fileURLToPath } from "node:url";
17+
import { isRealBunBinary } from "../src/lib/bun-binary-validator.mjs";
1718
import { npmInvocation } from "../src/update/npm-invocation.mjs";
1819
import { handoffWindowsTrayForUpdate, planWindowsTrayUpdate } from "../src/update/tray-update-plan.mjs";
1920

@@ -287,18 +288,14 @@ function bunBinDir() {
287288
return dirname(require.resolve("bun/package.json"));
288289
}
289290

290-
// The `bun` package ships a tiny ASCII placeholder at bin/bun.exe until its
291-
// postinstall downloads the real ~60MB binary. --ignore-scripts / pnpm leave
292-
// the ~450-byte stub in place, which is NOT executable (ENOEXEC). A size gate
293-
// cleanly distinguishes the stub from a real binary on every platform.
294-
const REAL_BUN_MIN_BYTES = 1_000_000;
291+
const BUN_OVERRIDE_ENV = "OPENCODEX_BUN_PATH";
295292

296293
function findBunBinary(bunDir) {
297294
// The npm `bun` package ships the binary as bin/bun.exe on every platform;
298295
// probe bin/bun too for forward compatibility.
299296
for (const name of ["bun.exe", "bun"]) {
300297
const p = join(bunDir, "bin", name);
301-
if (existsSync(p) && statSync(p).size >= REAL_BUN_MIN_BYTES) return p;
298+
if (isRealBunBinary(p)) return p;
302299
}
303300
return null;
304301
}
@@ -317,6 +314,17 @@ function fail(msg) {
317314
}
318315

319316
function resolveBun() {
317+
// Keep direct npm-launcher starts aligned with durable service/shim installs:
318+
// a valid explicit runtime must win even when the bundled dependency exists.
319+
const override = process.env[BUN_OVERRIDE_ENV]?.trim();
320+
if (override) {
321+
const overridePath = resolve(override);
322+
if (isRealBunBinary(overridePath)) return overridePath;
323+
console.error(
324+
`opencodex: ${BUN_OVERRIDE_ENV} is missing, unreadable, or not a complete Bun binary; falling back to the bundled runtime.`,
325+
);
326+
}
327+
320328
let bunDir;
321329
try {
322330
bunDir = bunBinDir();

bunfig.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,8 @@
88
# The npm script already uses `bun test ./tests/`; this makes a bare `bun test` behave the same.
99
[test]
1010
root = "tests"
11+
# Sandboxes HOME/OPENCODEX_HOME/CODEX_HOME and arms the real-home write guard for EVERY
12+
# invocation, including a bare `bun test <file>` that skips `scripts/test.ts`. A test
13+
# once overwrote a real user config through that unwrapped path; see
14+
# devlog/_plan/260730_codex_rs_upstream_v2_live_handoff/070.
15+
preload = ["./tests/preload.ts"]

devlog

Lines changed: 0 additions & 1 deletion
This file was deleted.

devlog/.gitignore

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Reference repos are cloned for analysis, never tracked. A nested .git becomes a
2+
# 160000 gitlink in the parent index and breaks actions/checkout downstream.
3+
_chase/_cca/
4+
_chase/_litellm/
5+
_fin/opencode-cursor/
6+
_plan/*/_ref_*/
7+
8+
# Security working notes never belong in a repository, not even a private one.
9+
# Use .tmp/ in the public tree or a mktemp -d path instead. See README.md.
10+
*-security-redaction/
11+
*_security_findings/
12+
**/security-advisory-draft*
13+
14+
.DS_Store

devlog/.patchprobe

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
probe

devlog/README.md

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# devlog
2+
3+
Planning and investigation notes for
4+
[lidge-jun/opencodex](https://github.com/lidge-jun/opencodex), tracked in that
5+
repository. Public.
6+
7+
## Why these are public
8+
9+
These notes were a private submodule until the bookkeeping outgrew the benefit:
10+
1723 commits touched the gitlink, and `dev`, `preview`, and `main` each held a
11+
different pointer, so every branch move and promotion dragged a diff. The
12+
privacy was doing one job — keeping pre-disclosure security material out of
13+
public view — and that job is now done by a rule plus a check instead, which is
14+
cheaper and does not tax every ordinary commit.
15+
16+
What that trade requires is stated below and is not optional.
17+
18+
## What belongs here
19+
20+
Closed records: plans, audits, measurements, and post-mortems for work that has
21+
shipped. A `_fin/` unit documents something already visible in public git
22+
history, so publishing the writeup discloses nothing the diff does not.
23+
24+
## Layout
25+
26+
- `_plan/` — units still open. One directory per unit, decade-numbered docs.
27+
- `_fin/` — closed units. A unit moves here once its terminal outcome is
28+
recorded (`DONE`, `NOOP`, `BLOCKED`, or `NEEDS_HUMAN` with the reason).
29+
- `_chase/` — external reference material captured for parity comparisons.
30+
31+
## Security working notes do not live here
32+
33+
**Never commit unreleased security findings, draft advisories, exploit paths, or
34+
pre-disclosure patch plans here.** This directory is public, so a commit is a
35+
disclosure the moment it is pushed, and the history is impractical to purge. A
36+
private repository is no better: it is cloned across machines and CI and
37+
outlives the embargo.
38+
39+
**This binds maintainers.** It has been violated by maintainer-authored triage
40+
before — two units of open security review accumulated under `_plan/` and had to
41+
be excised before this directory could be published.
42+
43+
The deciding question before writing a security note here: **is there already a
44+
public diff that reveals this weakness?** If yes, it is a closed record and
45+
belongs in `_fin/`. If no, it is pre-disclosure material and belongs in scratch.
46+
47+
Security work happens in an untracked scratch directory (`.tmp/` in the public
48+
working tree, or a `mktemp -d` path), and only the published outcome — release
49+
notes, advisory text, the fix itself — reaches any repository. See the
50+
"Security working notes" section of the public [`AGENTS.md`](https://github.com/lidge-jun/opencodex/blob/dev/AGENTS.md)
51+
for the full rule.
52+
53+
## Submodule hygiene
54+
55+
The public repository pins this repository by commit and declares
56+
`ignore = dirty`, `update = none`, `shallow = true`. Public CI never checks it
57+
out and nothing in the build or test path reads from it, so an unavailable or
58+
stale pointer cannot fail a public check. Do not add embedded git repositories
59+
here; a nested `.git` becomes a `160000` gitlink in the parent index and breaks
60+
`actions/checkout` for everyone.

devlog/_chase/00_parity-index.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# parity 분석 인덱스 (3 upstream)
2+
3+
opencodex 프록시 레이어가 따라잡는 세 upstream의 parity 스냅샷. 각 문서는
4+
분석 시점의 upstream HEAD를 박아둔다. 재분석 시 HEAD를 갱신하고 delta만 본다.
5+
6+
## 분석 baseline HEAD (2026-07-01 분석)
7+
8+
| slug | repo | 분석 HEAD | 날짜 | 문서 |
9+
|---|---|---|---|---|
10+
| jawcode (gjc) | `lidge-jun/jawcode` | `27311f6` | 2026-07-01 04:35 | `10_jawcode.md` |
11+
| cli-proxy-api (cca) | `router-for-me/CLIProxyAPI` | `00114be` | 2026-06-29 18:59 | `20_cli-proxy-api.md` |
12+
| litellm | `BerriAI/litellm` | `be4d0d8` | 2026-06-30 12:25 | `30_litellm.md` |
13+
14+
> jawcode 로컬 HEAD는 분석 직후 `a06f814`(docs-only, `docs(chase): close 10.062 → _fin`)로
15+
> 한 커밋 앞섰다. 코드 변경 없음 — 분석 baseline은 마지막 코드 커밋 `27311f6`이 정확하다.
16+
17+
opencodex baseline (분석 시): registry provider **48개**, adapter 종류 6
18+
(`openai-chat`×37, `anthropic`×4, `google`×3, `openai-responses`×2, `kiro`×1, `azure-openai`×1).
19+
20+
## 세 upstream의 성격이 다르다 (parity 축도 다름)
21+
22+
| upstream | 성격 | opencodex와의 관계 | parity 축 |
23+
|---|---|---|---|
24+
| jawcode | TS 멀티-프로바이더 AI 패키지 (47 provider 모듈) | **직접 포팅 출처** (1차 SOT) | provider-by-provider wire/auth 1:1 대조 |
25+
| cli-proxy-api | Go OAuth IDE 프록시 (antigravity/codex/claude/kimi/vertex/xai) | wire/auth/quirks **외부 교차검증** (2차) | executor/translator/signature 동작 대조 |
26+
| litellm | Python 범용 SDK (130 provider 폴더, 모델가격 맵) | 모델 카탈로그/커버리지 폭 **참조** (3차) | provider·model 커버리지 폭, 컨텍스트 윈도우 |
27+
28+
## 분석 방법
29+
30+
- jawcode: 로컬 `/Users/jun/Developer/new/700_projects/jawcode` (clone 불필요)
31+
- cca: `devlog/_chase/_cca/` (shallow clone, gitignored)
32+
- litellm: `devlog/_chase/_litellm/` (shallow clone, gitignored)
33+
34+
클론 디렉터리는 `devlog/` 통째 gitignore로 자동 무시. 노트(`*.md`)만 `git add -f`.
35+
36+
세부는 각 문서 참조.

0 commit comments

Comments
 (0)