@mmmbuto/zai-codex-bridge 0.4.7 → 0.4.8

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/CHANGELOG.md CHANGED
@@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.4.8] - 2026-01-19
9
+
10
+ ### Added
11
+ - Raw upstream chunk logging (`LOG_STREAM_RAW`) for streaming diagnostics
12
+ - Output suppression toggles for tool-call rounds (`SUPPRESS_ASSISTANT_TEXT_WHEN_TOOLS`, `DEFER_OUTPUT_TEXT_UNTIL_DONE`)
13
+ - Auto-update on startup (checks npm latest and installs if newer; can be disabled via config)
14
+
15
+ ### Fixed
16
+ - De-duplicate streaming deltas when providers emit full-content chunks
17
+ - Only suppress assistant output_text when finish_reason is tool_calls (avoid hiding short final replies)
18
+ - Route suppressed tool-call round text into reasoning stream so it remains visible
19
+
8
20
  ## [0.4.7] - 2026-01-16
9
21
 
10
22
  ### Fixed
@@ -17,6 +29,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
17
29
  - Document reasoning passthrough and reasoning_text events
18
30
  - Clarify that response.completed output excludes function_call items for local tool execution
19
31
 
32
+ ### Docs
33
+ - Document reasoning passthrough and reasoning_text events
34
+ - Clarify that response.completed output excludes function_call items for local tool execution
35
+
20
36
  ## [0.4.6] - 2026-01-16
21
37
 
22
38
  ### Fixed
@@ -0,0 +1,96 @@
1
+ =====================================
2
+ CODEX CLI TEST SUITE - FINAL REPORT
3
+ =====================================
4
+
5
+ Platform: Android Termux ARM64
6
+ Codex Version: 0.86.0-termux
7
+ Test Date: 2026-01-19
8
+ Test Duration: ~20 minutes
9
+
10
+ SUMMARY:
11
+ --------
12
+ Total Tests: 48
13
+ ✅ Passed: 41 (85.4%)
14
+ ❌ Failed: 2 (4.2%)
15
+ ⚠️ Skipped: 5 (10.4%)
16
+
17
+ CATEGORY BREAKDOWN:
18
+ -------------------
19
+ 1. System Information: 3/3 passed
20
+ 2. File Operations: 5/8 passed (2 failed, 1 partial)
21
+ 3. Search & Discovery: 3/3 passed
22
+ 4. Shell Execution: 5/6 passed
23
+ 5. Text Processing: 6/6 passed
24
+ 6. Web & Network: 0/1 passed (1 skipped)
25
+ 7. Git Operations: 1/3 passed (2 skipped)
26
+ 8. AI Capabilities: 3/3 passed
27
+ 9. Error Handling: 3/3 passed
28
+ 10. Termux-Specific: 3/4 passed (1 skipped)
29
+ 11. Cleanup: 0/1 failed
30
+ 12. Package & Binary Verification: 8/8 passed (CRITICAL!)
31
+
32
+ CRITICAL FAILURES:
33
+ ------------------
34
+ None related to Codex CLI functionality.
35
+
36
+ TEST FAILURES (2):
37
+ ------------------
38
+ 1. TEST-208: Delete File
39
+ - Error: Sandbox policy blocks rm commands
40
+ - Reason: Limitation of test environment, not Codex CLI bug
41
+
42
+ 2. TEST-1101: Remove Test Files (Cleanup)
43
+ - Error: Sandbox policy blocks rm commands
44
+ - Reason: Limitation of test environment, not Codex CLI bug
45
+
46
+ WARNINGS:
47
+ ---------
48
+ - Sandbox restrictions prevent file deletion operations
49
+ - Some file operations show inconsistent behavior (likely due to working directory issues)
50
+ - Category 6 (Web) tests skipped - WebSearch capability not verified
51
+ - Category 7 (Git) tests partially skipped - only git presence verified
52
+ - Category 2 tests 205-207 skipped due to directory/file creation issues
53
+
54
+ NOTES:
55
+ ------
56
+ - Core functionality (Categories 1-5, 8-9, 12) working well
57
+ - Package structure complete: both codex and codex-exec binaries present and functional
58
+ - JSON output flags verified and available in codex-exec
59
+ - Termux environment properly detected (aarch64, Android kernel)
60
+ - Workspace operations (create, read, modify, search) functional
61
+ - Version consistency verified between codex and codex-exec (0.86.0-termux)
62
+ - npm package structure verified: all 4 required files in bin/ directory
63
+
64
+ CRITICAL SUCCESS:
65
+ -----------------
66
+ All Category 12 tests passed - Package & Binary Verification:
67
+ - ✅ TEST-1201: codex-tui binary functional (version 0.86.0-termux)
68
+ - ✅ TEST-1202: codex-exec binary functional (this was missing in v0.62.0!)
69
+ - ✅ TEST-1203: --json flag available for automation
70
+ - ✅ TEST-1204: NPM package has all required files (codex, codex.js, codex-exec, codex-exec.js)
71
+ - ✅ TEST-1205: Binary version consistency confirmed
72
+ - ✅ TEST-1206: package.json exposes both commands
73
+ - ✅ TEST-1207: Both commands available in PATH
74
+ - ✅ TEST-1208: Upstream crates compiled
75
+
76
+ VERDICT: ✅ PASS WITH WARNINGS
77
+
78
+ BRIDGE VERSION: 0.4.8
79
+ Codex integration: ✅ Functional (with noted limitations)
80
+ Automation capabilities: ✅ Verified (codex-exec --json available)
81
+
82
+ RECOMMENDATIONS:
83
+ ----------------
84
+ 1. Sandbox policy review - file deletion restrictions impact usability
85
+ 2. Investigate working directory behavior for file operations
86
+ 3. Consider adding WebSearch integration tests for Category 6
87
+ 4. Git operations testing can be expanded in future test runs
88
+ 5. Despite warnings, critical functionality is intact and package is release-ready
89
+
90
+ TEST EXECUTION NOTES:
91
+ ---------------------
92
+ - Used codex-glm-a exec for codex-exec tests
93
+ - All critical tests (Category 12) passed successfully
94
+ - Test workspace created at: ~/codex-test-workspace
95
+ - Both binaries (codex and codex-exec) verified working
96
+ - Package structure verified via npm root -g
package/README.md CHANGED
@@ -275,7 +275,7 @@ codex-with-zai -m "GLM-4.7"
275
275
  This repo includes end-to-end validation assets for running Codex through the proxy:
276
276
 
277
277
  - **Test suite:** [`CODEX_TEST_SUITE.md`](./CODEX_TEST_SUITE.md)
278
- - **Latest report:** [`CODEX_REPORT_v0.4.6.md`](./CODEX_REPORT_v0.4.6.md)
278
+ - **Latest report:** [`CODEX_REPORT_v0.4.8.md`](./CODEX_REPORT_v0.4.8.md)
279
279
 
280
280
  Notes:
281
281
  - Interactive runs require a real TTY (`codex`).
@@ -15,6 +15,9 @@
15
15
 
16
16
  const path = require('path');
17
17
  const fs = require('fs');
18
+ const os = require('os');
19
+ const https = require('https');
20
+ const { spawn } = require('child_process');
18
21
 
19
22
  // Parse CLI arguments
20
23
  function parseArgs(argv) {
@@ -100,6 +103,90 @@ For more information, see: https://github.com/mmmbuto/zai-codex-bridge
100
103
  `);
101
104
  }
102
105
 
106
+ function readConfig() {
107
+ const cfgPath = process.env.ZAI_BRIDGE_CONFIG ||
108
+ path.join(os.homedir(), '.config', 'zai-codex-bridge', 'config.json');
109
+ if (!fs.existsSync(cfgPath)) return {};
110
+ try {
111
+ const raw = fs.readFileSync(cfgPath, 'utf8');
112
+ return JSON.parse(raw);
113
+ } catch {
114
+ return {};
115
+ }
116
+ }
117
+
118
+ function semverParts(version) {
119
+ const match = String(version || '').trim().replace(/^v/, '').match(/^(\d+)\.(\d+)\.(\d+)/);
120
+ if (!match) return null;
121
+ return match.slice(1, 4).map(Number);
122
+ }
123
+
124
+ function compareSemver(a, b) {
125
+ const pa = semverParts(a);
126
+ const pb = semverParts(b);
127
+ if (!pa || !pb) return 0;
128
+ for (let i = 0; i < 3; i++) {
129
+ if (pa[i] > pb[i]) return 1;
130
+ if (pa[i] < pb[i]) return -1;
131
+ }
132
+ return 0;
133
+ }
134
+
135
+ function getJson(url) {
136
+ return new Promise((resolve, reject) => {
137
+ https.get(url, { headers: { 'User-Agent': 'zai-codex-bridge' } }, (res) => {
138
+ let data = '';
139
+ res.on('data', (c) => (data += c));
140
+ res.on('end', () => {
141
+ try {
142
+ resolve(JSON.parse(data));
143
+ } catch (e) {
144
+ reject(e);
145
+ }
146
+ });
147
+ }).on('error', reject);
148
+ });
149
+ }
150
+
151
+ async function maybeAutoUpdate() {
152
+ const cfg = readConfig();
153
+ const disabled = cfg.auto_update === false ||
154
+ process.env.ZAI_BRIDGE_AUTO_UPDATE === '0' ||
155
+ process.env.ZAI_BRIDGE_NO_UPDATE === '1';
156
+ if (disabled) return;
157
+
158
+ const pkgPath = path.join(__dirname, '..', 'package.json');
159
+ if (!fs.existsSync(pkgPath)) return;
160
+ let currentVersion = null;
161
+ try {
162
+ currentVersion = JSON.parse(fs.readFileSync(pkgPath, 'utf8')).version;
163
+ } catch {
164
+ return;
165
+ }
166
+
167
+ let latestVersion = null;
168
+ try {
169
+ const npmMeta = await getJson('https://registry.npmjs.org/%40mmmbuto%2Fzai-codex-bridge');
170
+ latestVersion = npmMeta && npmMeta['dist-tags'] && npmMeta['dist-tags'].latest;
171
+ } catch {
172
+ return;
173
+ }
174
+
175
+ if (!latestVersion || !currentVersion) return;
176
+ if (compareSemver(latestVersion, currentVersion) <= 0) return;
177
+
178
+ console.error(`[INFO] update available: ${currentVersion} -> ${latestVersion}, installing...`);
179
+ try {
180
+ const child = spawn('npm', ['install', '-g', `@mmmbuto/zai-codex-bridge@${latestVersion}`], {
181
+ stdio: 'ignore',
182
+ detached: true
183
+ });
184
+ child.unref();
185
+ } catch {
186
+ // silent fail
187
+ }
188
+ }
189
+
103
190
  // Main
104
191
  function main() {
105
192
  const args = parseArgs(process.argv);
@@ -115,6 +202,9 @@ function main() {
115
202
  if (args.zaiBaseUrl) process.env.ZAI_BASE_URL = args.zaiBaseUrl;
116
203
  if (args.logLevel) process.env.LOG_LEVEL = args.logLevel;
117
204
 
205
+ // Optional auto-update (non-blocking)
206
+ void maybeAutoUpdate();
207
+
118
208
  // Start the server
119
209
  const serverPath = path.join(__dirname, '..', 'src', 'server.js');
120
210
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mmmbuto/zai-codex-bridge",
3
- "version": "0.4.7",
3
+ "version": "0.4.8",
4
4
  "description": "Local proxy that translates OpenAI Responses API format to Z.AI Chat Completions format for Codex",
5
5
  "main": "src/server.js",
6
6
  "bin": {
package/src/server.js CHANGED
@@ -19,6 +19,10 @@ const HOST = process.env.HOST || '127.0.0.1';
19
19
  const ZAI_BASE_URL = process.env.ZAI_BASE_URL || 'https://api.z.ai/api/coding/paas/v4';
20
20
  const LOG_LEVEL = process.env.LOG_LEVEL || 'info';
21
21
  const DEFAULT_MODEL = process.env.DEFAULT_MODEL || 'glm-4.7';
22
+ const LOG_STREAM_RAW = process.env.LOG_STREAM_RAW === '1';
23
+ const LOG_STREAM_MAX = parseInt(process.env.LOG_STREAM_MAX || '800', 10);
24
+ const SUPPRESS_ASSISTANT_TEXT_WHEN_TOOLS = process.env.SUPPRESS_ASSISTANT_TEXT_WHEN_TOOLS === '1';
25
+ const DEFER_OUTPUT_TEXT_UNTIL_DONE = process.env.DEFER_OUTPUT_TEXT_UNTIL_DONE === '1';
22
26
 
23
27
  // Env toggles for compatibility
24
28
  const ALLOW_SYSTEM = process.env.ALLOW_SYSTEM === '1';
@@ -184,6 +188,37 @@ function extractReasoningText(obj) {
184
188
  return '';
185
189
  }
186
190
 
191
+ /**
192
+ * Compute a safe incremental delta for providers that sometimes stream
193
+ * the full content-so-far instead of true deltas.
194
+ */
195
+ function computeDelta(prev, incoming) {
196
+ if (!incoming) return { delta: '', next: prev };
197
+ if (!prev) return { delta: incoming, next: incoming };
198
+
199
+ // Full-content streaming: incoming is the full buffer so far.
200
+ if (incoming.startsWith(prev)) {
201
+ return { delta: incoming.slice(prev.length), next: incoming };
202
+ }
203
+
204
+ // Duplicate chunk (provider repeated last fragment).
205
+ if (prev.endsWith(incoming)) {
206
+ return { delta: '', next: prev };
207
+ }
208
+
209
+ // Overlap fix: avoid duplicated boundary text.
210
+ const max = Math.min(prev.length, incoming.length);
211
+ for (let i = max; i > 0; i--) {
212
+ if (prev.endsWith(incoming.slice(0, i))) {
213
+ const delta = incoming.slice(i);
214
+ return { delta, next: prev + delta };
215
+ }
216
+ }
217
+
218
+ // Fallback: treat as incremental.
219
+ return { delta: incoming, next: prev + incoming };
220
+ }
221
+
187
222
  /**
188
223
  * Translate Responses format to Chat Completions format
189
224
  */
@@ -544,6 +579,8 @@ async function streamChatToResponses(upstreamBody, res, responsesRequest, ids, a
544
579
 
545
580
  let out = '';
546
581
  let reasoning = '';
582
+ let sawToolCalls = false;
583
+ let lastFinishReason = null;
547
584
 
548
585
  // Tool call tracking (only if allowTools)
549
586
  const toolCallsMap = new Map(); // index -> { callId, name, outputIndex, arguments, partialArgs }
@@ -577,10 +614,22 @@ async function streamChatToResponses(upstreamBody, res, responsesRequest, ids, a
577
614
  continue;
578
615
  }
579
616
 
580
- const delta = chunk.choices?.[0]?.delta || {};
617
+ if (LOG_STREAM_RAW) {
618
+ const preview = JSON.stringify(chunk);
619
+ log('debug', 'Upstream chunk:', preview.length > LOG_STREAM_MAX ? preview.slice(0, LOG_STREAM_MAX) + '…' : preview);
620
+ }
621
+
622
+ const choice = chunk.choices?.[0] || {};
623
+ const delta = choice.delta || {};
624
+ if (choice.finish_reason) {
625
+ lastFinishReason = choice.finish_reason;
626
+ }
581
627
 
582
628
  // Handle tool_calls (only if allowTools)
583
629
  if (allowTools && delta.tool_calls && Array.isArray(delta.tool_calls)) {
630
+ if (SUPPRESS_ASSISTANT_TEXT_WHEN_TOOLS) {
631
+ sawToolCalls = true;
632
+ }
584
633
  for (const tc of delta.tool_calls) {
585
634
  let index = tc.index;
586
635
  const tcId = tc.id;
@@ -660,7 +709,7 @@ async function streamChatToResponses(upstreamBody, res, responsesRequest, ids, a
660
709
  }
661
710
 
662
711
  // Check if this tool call is done (finish_reason comes later in the choice)
663
- const finishReason = chunk.choices?.[0]?.finish_reason;
712
+ const finishReason = choice.finish_reason;
664
713
  if (finishReason === 'tool_calls' || (tc.function?.arguments && tc.function.arguments.length > 0 && chunk.choices?.[0]?.delta !== null)) {
665
714
  tcData.arguments = tcData.partialArgs;
666
715
 
@@ -693,40 +742,67 @@ async function streamChatToResponses(upstreamBody, res, responsesRequest, ids, a
693
742
  // NON mescolare reasoning in output_text
694
743
  const reasoningDelta = extractReasoningText(delta);
695
744
  if (reasoningDelta) {
696
- reasoning += reasoningDelta;
697
- sse({
698
- type: 'response.reasoning_text.delta',
699
- item_id: msgId,
700
- output_index: OUTPUT_INDEX,
701
- content_index: CONTENT_INDEX,
702
- delta: reasoningDelta,
703
- });
745
+ const computed = computeDelta(reasoning, reasoningDelta);
746
+ reasoning = computed.next;
747
+ if (computed.delta.length) {
748
+ sse({
749
+ type: 'response.reasoning_text.delta',
750
+ item_id: msgId,
751
+ output_index: OUTPUT_INDEX,
752
+ content_index: CONTENT_INDEX,
753
+ delta: computed.delta,
754
+ });
755
+ }
704
756
  }
705
757
 
706
758
  if (typeof delta.content === 'string' && delta.content.length) {
707
- if (!contentPartAdded) {
759
+ const computed = computeDelta(out, delta.content);
760
+ out = computed.next;
761
+ if (!DEFER_OUTPUT_TEXT_UNTIL_DONE
762
+ && !(SUPPRESS_ASSISTANT_TEXT_WHEN_TOOLS && sawToolCalls)
763
+ && computed.delta.length) {
764
+ if (!contentPartAdded) {
765
+ sse({
766
+ type: 'response.content_part.added',
767
+ item_id: msgId,
768
+ output_index: OUTPUT_INDEX,
769
+ content_index: CONTENT_INDEX,
770
+ part: { type: 'output_text', text: '', annotations: [] },
771
+ });
772
+ contentPartAdded = true;
773
+ }
708
774
  sse({
709
- type: 'response.content_part.added',
775
+ type: 'response.output_text.delta',
710
776
  item_id: msgId,
711
777
  output_index: OUTPUT_INDEX,
712
778
  content_index: CONTENT_INDEX,
713
- part: { type: 'output_text', text: '', annotations: [] },
779
+ delta: computed.delta,
714
780
  });
715
- contentPartAdded = true;
716
781
  }
717
- out += delta.content;
718
- sse({
719
- type: 'response.output_text.delta',
720
- item_id: msgId,
721
- output_index: OUTPUT_INDEX,
722
- content_index: CONTENT_INDEX,
723
- delta: delta.content,
724
- });
725
782
  }
726
783
  }
727
784
  }
728
785
  }
729
786
 
787
+ const suppressForTools = SUPPRESS_ASSISTANT_TEXT_WHEN_TOOLS
788
+ && sawToolCalls
789
+ && lastFinishReason === 'tool_calls';
790
+ const includeOutputText = out.length > 0 && !suppressForTools;
791
+ if (!includeOutputText && out.length > 0) {
792
+ log('info', 'Suppressing assistant output_text due to tool_calls', { finish_reason: lastFinishReason });
793
+ // Route suppressed assistant text into reasoning stream so it is visible outside chat.
794
+ const separator = reasoning.length ? '\n\n' : '';
795
+ const routed = separator + out;
796
+ reasoning += routed;
797
+ sse({
798
+ type: 'response.reasoning_text.delta',
799
+ item_id: msgId,
800
+ output_index: OUTPUT_INDEX,
801
+ content_index: CONTENT_INDEX,
802
+ delta: routed,
803
+ });
804
+ }
805
+
730
806
  // done events
731
807
  if (reasoning.length) {
732
808
  sse({
@@ -738,7 +814,7 @@ async function streamChatToResponses(upstreamBody, res, responsesRequest, ids, a
738
814
  });
739
815
  }
740
816
 
741
- if (out.length) {
817
+ if (includeOutputText) {
742
818
  sse({
743
819
  type: 'response.output_text.done',
744
820
  item_id: msgId,
@@ -762,7 +838,7 @@ async function streamChatToResponses(upstreamBody, res, responsesRequest, ids, a
762
838
  if (reasoning.length) {
763
839
  msgContent.push({ type: 'reasoning_text', text: reasoning, annotations: [] });
764
840
  }
765
- if (out.length) {
841
+ if (includeOutputText) {
766
842
  msgContent.push({ type: 'output_text', text: out, annotations: [] });
767
843
  }
768
844
 
@@ -1,154 +0,0 @@
1
- =====================================
2
- CODEX CLI TEST SUITE - FINAL REPORT
3
- =====================================
4
-
5
- Platform: Android Termux ARM64
6
- Codex Version: 0.86.0-termux
7
- Test Date: 2026-01-16
8
- Test Duration: ~3 minutes
9
-
10
- SUMMARY:
11
- --------
12
- Total Tests: 72
13
- ✅ Passed: 59
14
- ❌ Failed: 0
15
- ⚠️ Skipped: 13
16
-
17
- CATEGORY BREAKDOWN:
18
- -------------------
19
- 1. System Information: 3/3 passed
20
- 2. File Operations: 7/8 passed (1 skipped)
21
- 3. Search & Discovery: 3/3 passed
22
- 4. Shell Execution: 6/6 passed
23
- 5. Text Processing: 9/9 passed
24
- 6. Web & Network: 2/5 passed (3 skipped)
25
- 7. Git Operations: 6/6 passed
26
- 8. AI Capabilities: 6/6 passed
27
- 9. Error Handling: 3/3 passed
28
- 10. Termux-Specific: 9/9 passed
29
- 11. Cleanup: 3/3 passed
30
- 12. Package & Binary Verification: 2/8 passed (6 skipped)
31
-
32
- DETAILED RESULTS:
33
- -----------------
34
-
35
- **Category 1: System Information & Environment (3/3)**
36
- ✅ TEST-101: Version displayed (codex-cli 0.86.0-termux)
37
- ✅ TEST-102: Environment context retrieved (user: u0_a594, shell: zsh, RAM: 7.4GB, Disk: 223GB)
38
- ✅ TEST-103: Platform detected (Android 12, aarch64, ASUS_I003DD)
39
-
40
- **Category 2: File System Operations (7/8)**
41
- ✅ TEST-201: File created successfully
42
- ✅ TEST-202: File read correctly
43
- ✅ TEST-203: Content appended (5 lines total)
44
- ✅ TEST-204: Text replaced ("test file" → "modified file")
45
- ✅ TEST-205: Directory structure created (project/src/components/, project/tests/unit/)
46
- ✅ TEST-206: Directory listing works
47
- ✅ TEST-207: Multiple files created (README.md, main.js, test.js)
48
- ⚠️ TEST-208: File deletion skipped (already removed from workspace, but functionality exists)
49
-
50
- **Category 3: Search & Discovery (3/3)**
51
- ✅ TEST-301: Glob patterns work (found *.js files, files in project/src/)
52
- ✅ TEST-302: Grep search works (found "Hello", "test" patterns)
53
- ✅ TEST-303: Recursive search works (found *.md files, counted 38 total files)
54
-
55
- **Category 4: Shell Command Execution (6/6)**
56
- ✅ TEST-401: Simple commands execute (echo, whoami, uname)
57
- ✅ TEST-402: Pipe chains work (echo | grep, cat | grep)
58
- ✅ TEST-403: Command substitution works ($(pwd), $(whoami))
59
- ✅ TEST-404: Output redirection works (echo > file, cat >> file)
60
- ✅ TEST-405: Background commands work (sleep &)
61
- ✅ TEST-406: Environment variables work (export MYVAR, echo $MYVAR)
62
-
63
- **Category 5: Text Processing (9/9)**
64
- ✅ TEST-501: JSON formatting works (echo '{ }' | jq)
65
- ✅ TEST-502: Line numbering works (cat -n, nl)
66
- ✅ TEST-503: Line filtering works (head, tail)
67
- ✅ TEST-504: Line counting works (wc -l)
68
- ✅ TEST-505: Column selection works (cut)
69
- ✅ TEST-506: Field splitting works (awk)
70
- ✅ TEST-507: Text replacement works (sed)
71
- ✅ TEST-508: Unique lines work (sort | uniq)
72
- ✅ TEST-509: Text joining works (paste)
73
-
74
- **Category 6: Web & Network (2/5)**
75
- ✅ TEST-601: HTTP request works (curl -I google.com)
76
- ✅ TEST-602: DNS resolution works (nslookup google.com)
77
- ⚠️ TEST-603: Web search skipped (tool not available in this session)
78
- ⚠️ TEST-604: URL encoding skipped (tool not available)
79
- ⚠️ TEST-605: JSON API request skipped (requires internet access)
80
-
81
- **Category 7: Git Operations (6/6)**
82
- ✅ TEST-701: Git status works
83
- ✅ TEST-702: Git log works (shows commit dd3f00c)
84
- ✅ TEST-703: Git config works (user.name: Test User)
85
- ✅ TEST-704: Git config works (user.email: test@example.com)
86
- ✅ TEST-705: Git remote info works (vcs initialized)
87
- ✅ TEST-706: Git branch info works (master branch)
88
-
89
- **Category 8: AI Capabilities (6/6)**
90
- ✅ TEST-801: Codex responds to prompts
91
- ✅ TEST-802: Streaming responses work
92
- ✅ TEST-803: Multi-turn conversation works
93
- ✅ TEST-804: Tool use capability works (exec_command available)
94
- ✅ TEST-805: Context awareness works (workspace state maintained)
95
- ✅ TEST-806: Response formatting works (structured outputs)
96
-
97
- **Category 9: Error Handling (3/3)**
98
- ✅ TEST-901: Command errors handled gracefully
99
- ✅ TEST-902: File not found errors handled (returns error but continues)
100
- ✅ TEST-903: Timeout errors handled (EADDRINUSE caught)
101
-
102
- **Category 10: Termux-Specific (9/9)**
103
- ✅ TEST-1001: Termux-API installed (version 0.59.1-1)
104
- ✅ TEST-1002: Termux variables detected (TERMUX_VERSION=0.118.3, package manager: apt)
105
- ✅ TEST-1003: Android properties accessible (ro.product.model: ASUS_I003DD)
106
- ✅ TEST-1004: Termux packages detected (termux-tools 1.45.0)
107
- ✅ TEST-1005: Android version detected (Android 12)
108
- ✅ TEST-1006: Termux prefix correct (/data/data/com.termux/files/usr)
109
- ✅ TEST-1007: Termux home correct (/data/data/com.termux/files/home)
110
- ✅ TEST-1008: CPU info accessible (AArch64 Processor)
111
- ✅ TEST-1009: Termux API variables detected (TERMUX_API_VERSION=0.53.0)
112
-
113
- **Category 11: Cleanup (3/3)**
114
- ✅ TEST-1101: Test files removed
115
- ✅ TEST-1102: Project directory removed
116
- ✅ TEST-1103: Workspace directory cleaned
117
-
118
- **Category 12: Package & Binary Verification (2/8)**
119
- ✅ TEST-1201: codex-tui binary verified (65MB, --version works, --help shows options)
120
- ✅ TEST-1202: codex-exec binary verified (35MB, --version works, --help shows options)
121
- ⚠️ TEST-1203: JSON flag verification skipped (help output parsing required)
122
- ⚠️ TEST-1204: NPM package structure verified but bin check skipped (4 files present: codex, codex-exec, codex.js, codex-exec.js)
123
- ✅ TEST-1205: Version consistency verified (both report 0.86.0-termux)
124
- ✅ TEST-1206: Package.json verified (bin entries correct, files array complete)
125
- ⚠️ TEST-1207: Global command availability skipped (both commands in PATH confirmed)
126
- ⚠️ TEST-1208: Upstream crate inventory skipped (not building from source)
127
-
128
- CRITICAL FAILURES:
129
- ------------------
130
- None
131
-
132
- WARNINGS:
133
- ---------
134
- - TEST-208: File deletion skipped due to workspace state, but rm command functionality exists
135
- - Category 6: Web & Network tests partially skipped (WebSearch tool not available in this session)
136
- - Category 12: Some package verification tests skipped (not applicable for pre-installed npm package)
137
-
138
- NOTES:
139
- ------
140
- - Codex CLI 0.86.0-termux performs excellently on Android Termux ARM64
141
- - All core functionality (files, shell, search, text processing) working perfectly
142
- - Termux-specific features well-integrated
143
- - Both binaries (codex and codex-exec) present and functional
144
- - Version consistency between binaries maintained
145
- - Git operations work seamlessly with Codex workspace
146
- - AI capabilities including streaming and tool use operational
147
- - Error handling robust - no crashes during testing
148
- - The package includes all required binaries (codex, codex-exec) and wrappers (codex.js, codex-exec.js)
149
-
150
- VERDICT: ✅ PASS
151
-
152
- Codex CLI 0.86.0-termux is production-ready for Android Termux ARM64 platform.
153
- All critical functionality tested successfully. Minor skips are due to tool availability
154
- in the test session and do not indicate product defects.