parallel-codex-tui 0.2.0 → 0.2.2
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/.parallel-codex/config.example.toml +4 -4
- package/README.md +13 -13
- package/dist/cli.js +4 -0
- package/dist/core/config.js +8 -8
- package/dist/core/system-proxy.js +79 -0
- package/dist/tui/App.js +2 -2
- package/dist/tui/keyboard.js +5 -0
- package/dist/version.js +1 -1
- package/package.json +1 -1
|
@@ -4,18 +4,18 @@ defaultMode = "auto"
|
|
|
4
4
|
[router.codex]
|
|
5
5
|
command = "codex"
|
|
6
6
|
args = ["exec", "--ephemeral", "--ignore-rules", "-c", "model_reasoning_effort=low", "--skip-git-repo-check", "--sandbox", "read-only", "--color", "never", "-"]
|
|
7
|
-
timeoutMs =
|
|
7
|
+
timeoutMs = 60000
|
|
8
8
|
# Stop a silent Router before the total ceiling so one transient retry stays bounded.
|
|
9
|
-
firstOutputTimeoutMs =
|
|
9
|
+
firstOutputTimeoutMs = 30000
|
|
10
10
|
# Reset after every stdout/stderr chunk; timeoutMs remains the hard ceiling.
|
|
11
|
-
idleTimeoutMs =
|
|
11
|
+
idleTimeoutMs = 30000
|
|
12
12
|
# Stop a noisy or malformed classifier before it can grow Router memory without bound (1 KiB..16 MiB).
|
|
13
13
|
maxOutputBytes = 1048576
|
|
14
14
|
# Retry one transient Router failure before asking the user; 1 disables automatic retry.
|
|
15
15
|
maxAttempts = 2
|
|
16
16
|
retryDelayMs = 500
|
|
17
17
|
# Active-task follow-ups fail safely to Main after this shorter Codex timeout.
|
|
18
|
-
followUpTimeoutMs =
|
|
18
|
+
followUpTimeoutMs = 45000
|
|
19
19
|
# Non-interactive fallback; the TUI pauses and asks before executing it.
|
|
20
20
|
fallback = "simple"
|
|
21
21
|
|
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ Built with Codex-assisted development.
|
|
|
6
6
|
|
|
7
7
|
## Current Release
|
|
8
8
|
|
|
9
|
-
`v0.2.
|
|
9
|
+
`v0.2.2` is available from [npm](https://www.npmjs.com/package/parallel-codex-tui/v/0.2.2) and as a [GitHub Release](https://github.com/allendred/parallel-codex-tui/releases/tag/v0.2.2). It automatically inherits the macOS system proxy when explicit proxy variables are absent, expands the default Router cold-start budget, and retains the single Up/Down request-history fix from `v0.2.1`.
|
|
10
10
|
|
|
11
11
|
The release keeps terminal scrolling and copying available at the same time without requiring Shift. Ordinary left-drag selection remains owned by the terminal while alternate-scroll delivers the wheel to chat, Worker logs, and structured views. `Ctrl+Y` copies the visible view as a fallback. It preserves the embedded native Agent scrollback across status-detail round trips and real PTY resizes.
|
|
12
12
|
|
|
@@ -20,7 +20,7 @@ Highlights:
|
|
|
20
20
|
- Named Worker Providers support Codex-compatible, Claude-compatible, OpenAI-compatible, Anthropic-compatible, and custom generic commands with independent role, model, environment, permission, resume, and interactive settings.
|
|
21
21
|
- Worker overview, Feature board, collaboration timeline, Task center, status details, rendered Markdown/Diff/error logs, Unicode search, keyboard navigation, mouse scrolling, and configurable themes share one terminal UI system.
|
|
22
22
|
|
|
23
|
-
Release acceptance includes a real three-Feature Tetris task with parallel Actor/Critic waves and final integration review. Real Codex and Claude probes both proved fresh and same-session resume calls, the semantic Router completed a live classification, and one TUI completed Main calls in two workspaces before restoring the first workspace without leaking chat state. PTY coverage runs in Apple Terminal, tmux, and Zellij profiles at narrow and wide sizes, including status/log equivalence and preserving the native output tail across status-detail round trips. The deterministic repository suite passed 1,
|
|
23
|
+
Release acceptance includes a real three-Feature Tetris task with parallel Actor/Critic waves and final integration review. Real Codex and Claude probes both proved fresh and same-session resume calls, the semantic Router completed a live classification, and one TUI completed Main calls in two workspaces before restoring the first workspace without leaking chat state. PTY coverage runs in Apple Terminal, tmux, and Zellij profiles at narrow and wide sizes, including status/log equivalence and preserving the native output tail across status-detail round trips. The deterministic repository suite passed 1,262 tests across 123 files; one quota-consuming real-Agent test is skipped by default and passes through `npm run test:real-agents`.
|
|
24
24
|
|
|
25
25
|
Real Provider probes depend on valid local CLI credentials. In particular, authenticate the Claude CLI before selecting a Claude-compatible Worker, then run `parallel-codex-tui --doctor --probe-agents` to prove fresh and resumed calls on that machine.
|
|
26
26
|
|
|
@@ -205,7 +205,7 @@ The doctor output includes `preview:` and `semantic:` ANSI swatch rows so you ca
|
|
|
205
205
|
- Simple requests stay in the main TUI flow and do not create Judge, Actor, or Critic workers.
|
|
206
206
|
- Consecutive simple requests reuse the main worker's native session across app restarts when the CLI exposes a session id.
|
|
207
207
|
- The workspace chat transcript is appended to `.parallel-codex/sessions/main/chat.jsonl`; startup restores the latest 200 valid messages and skips isolated corrupt rows. The shared tail reader reads JSONL backward in bounded chunks, so a long-running chat does not require loading its lifetime transcript and a partial or oversized final row cannot hide earlier valid messages.
|
|
208
|
-
- Chat drafts support Unicode-safe Left/Right, Home/End, Backspace, and Delete editing
|
|
208
|
+
- Chat drafts support Unicode-safe Left/Right, Home/End, Backspace, and Delete editing. A single Up/Down recalls persisted user requests and returns to the exact unsent draft; Ctrl+Up/Down remains available, while repeated alternate-scroll arrow bursts continue to scroll chat. Long input stays on one row with the visible window centered around the logical cursor.
|
|
209
209
|
- Bracketed multiline paste stays in one draft instead of submitting the first line; logical line breaks and tabs appear as `↵` and `⇥` in the single-row input until the complete request is submitted.
|
|
210
210
|
- Complex requests create a session under `.parallel-codex/sessions/`.
|
|
211
211
|
- Task lifecycle is a checked state machine. A task enters `routed` only after the turn and route files are durable, and enters `ready_for_pair` only after Judge artifacts validate; invalid phase skips are rejected before metadata or event projections change. Persisted follow-up turns that still carry an older `done` state are recovered as cancelled and retryable on startup instead of being hidden as completed.
|
|
@@ -264,17 +264,17 @@ defaultMode = "auto"
|
|
|
264
264
|
[router.codex]
|
|
265
265
|
command = "codex"
|
|
266
266
|
args = ["exec", "--ephemeral", "--ignore-rules", "-c", "model_reasoning_effort=low", "--skip-git-repo-check", "--sandbox", "read-only", "--color", "never", "-"]
|
|
267
|
-
timeoutMs =
|
|
268
|
-
firstOutputTimeoutMs =
|
|
269
|
-
idleTimeoutMs =
|
|
267
|
+
timeoutMs = 60000
|
|
268
|
+
firstOutputTimeoutMs = 30000
|
|
269
|
+
idleTimeoutMs = 30000
|
|
270
270
|
maxOutputBytes = 1048576
|
|
271
271
|
maxAttempts = 2
|
|
272
272
|
retryDelayMs = 500
|
|
273
|
-
followUpTimeoutMs =
|
|
273
|
+
followUpTimeoutMs = 45000
|
|
274
274
|
fallback = "simple"
|
|
275
275
|
```
|
|
276
276
|
|
|
277
|
-
Set `defaultMode = "simple"` / `defaultMode = "complex"` to force one path. In `auto` mode, routing is semantic through an ephemeral, low-reasoning Codex run. Only `simple` and `complex` are accepted route modes; harmless casing and surrounding whitespace are normalized, while invalid JSON or an unknown mode uses the configured fallback and appears as `invalid output` in the status bar. `fallback = "simple"` or `fallback = "complex"` supplies the non-interactive fallback path; the safe default is `simple` and there is no keyword-only router. `firstOutputTimeoutMs` stops a silent process, `idleTimeoutMs` resets after every stdout or stderr chunk, and `timeoutMs` remains the hard ceiling even while output continues. `maxOutputBytes` bounds combined Router stdout and stderr in memory; exceeding it stops the process tree and reports invalid output instead of waiting for a timeout. The 1 MiB default can be configured from 1 KiB through 16 MiB. The
|
|
277
|
+
Set `defaultMode = "simple"` / `defaultMode = "complex"` to force one path. In `auto` mode, routing is semantic through an ephemeral, low-reasoning Codex run. Only `simple` and `complex` are accepted route modes; harmless casing and surrounding whitespace are normalized, while invalid JSON or an unknown mode uses the configured fallback and appears as `invalid output` in the status bar. `fallback = "simple"` or `fallback = "complex"` supplies the non-interactive fallback path; the safe default is `simple` and there is no keyword-only router. `firstOutputTimeoutMs` stops a silent process, `idleTimeoutMs` resets after every stdout or stderr chunk, and `timeoutMs` remains the hard ceiling even while output continues. `maxOutputBytes` bounds combined Router stdout and stderr in memory; exceeding it stops the process tree and reports invalid output instead of waiting for a timeout. The 1 MiB default can be configured from 1 KiB through 16 MiB. The 30-second first-output and idle defaults stay below the 60-second total ceiling, leaving room for a proxied Codex cold start while preserving distinct failure evidence. An idle deadline begins after the latest output, while the hard ceiling still bounds every attempt. A watchdog only runs separately when its limit is lower than the active initial or follow-up total timeout, avoiding competing timers at the same deadline.
|
|
278
278
|
|
|
279
279
|
On POSIX systems the Router command runs in its own process group. Timeout, cancellation, and stdin failure send `SIGTERM`, wait briefly for graceful cleanup, then use `SIGKILL` when any group member remains. A retry, fallback choice, or completed cancellation is not exposed until that command tree is confirmed stopped, so a previous classifier cannot overlap the next Router or Worker. If termination cannot be verified after `SIGKILL`, the request fails closed instead of continuing around a live process.
|
|
280
280
|
|
|
@@ -290,7 +290,7 @@ Every new Router fallback persists an authoritative `router_failure_kind` alongs
|
|
|
290
290
|
|
|
291
291
|
### Proxy Environment
|
|
292
292
|
|
|
293
|
-
|
|
293
|
+
On macOS, startup automatically inherits enabled HTTP, HTTPS, SOCKS, and bypass settings from System Settings when the corresponding process environment variables are absent. Explicit shell variables and local config remain authoritative. Set `PARALLEL_CODEX_INHERIT_SYSTEM_PROXY=0` to opt out. Configure provider-specific values explicitly when one agent needs a different route:
|
|
294
294
|
|
|
295
295
|
```toml
|
|
296
296
|
[router.codex.env]
|
|
@@ -308,7 +308,7 @@ NO_PROXY = "localhost,127.0.0.1"
|
|
|
308
308
|
|
|
309
309
|
`router.codex.env` applies only to semantic classification. `workers.<id>.model.env` applies to fresh/resumed runs and embedded native attach for that named Worker Provider. Keep these values in local `config.toml`, which is ignored by Git.
|
|
310
310
|
|
|
311
|
-
Run `parallel-codex-tui --doctor` after changing proxy settings. Doctor checks referenced environment variables
|
|
311
|
+
Run `parallel-codex-tui --doctor` after changing proxy settings. Doctor checks referenced environment variables and labels inherited or configured proxy host/port checks as local-endpoint reachability without printing credentials. If system-proxy detection is unavailable, Doctor reports that the macOS proxy was not inherited and points to the explicit config table. Then run `parallel-codex-tui --doctor --probe-router` when you also need to verify the real Codex Router path through that proxy; this explicit probe can take up to `router.codex.timeoutMs`. A timed-out request is identified as `first output timeout`, `idle timeout after stdout/stderr`, or `total timeout`; `via <proxy-host:port>` remains context, not a claim that the proxy caused the failure. The audit never exposes the proxy URL or credentials.
|
|
312
312
|
|
|
313
313
|
## Mock Mode
|
|
314
314
|
|
|
@@ -452,7 +452,7 @@ Keep `[router.codex]` on `read-only`; routing only classifies requests and does
|
|
|
452
452
|
|
|
453
453
|
The process adapter sends each role prompt to stdin and records stdout/stderr in `output.log`. Worker success is separate from the operating-system exit code: a total, first-output, idle, or stdin watchdog failure remains failed even when the terminated CLI handles `SIGTERM` and exits with code `0`, so the next role never starts from a timed-out checkpoint. `firstOutputTimeoutMs` owns silent startup, `idleTimeoutMs` starts only after real stdout/stderr activity, and `timeoutMs` remains the hard ceiling; equal or longer secondary watchdogs do not race the total deadline.
|
|
454
454
|
|
|
455
|
-
In chat, scroll long conversation history with the mouse wheel
|
|
455
|
+
In chat, scroll long conversation history with the mouse wheel or PageUp/PageDown; sending a new message returns to the latest reply. A single Up/Down recalls persisted request history, and Ctrl+Up/Down remains an alternative. The outer TUI never enables application mouse tracking, so ordinary left-drag selection and system copy work without Shift while alternate-scroll keeps the wheel active in chat and Worker logs. `Ctrl+Y` also copies the current visible chat, rendered Worker log, native Agent screen, or structured overview without changing terminal modes. macOS uses `pbcopy`; Linux uses `wl-copy`, `xclip`, or `xsel` when available and falls back to OSC 52. After a complex task completes, use the same controls to move through its structured result and press `Ctrl+D` to toggle details. Press `Ctrl+N` to preserve the current session and start a new task, `Ctrl+W` to open worker logs, and `Tab` to cycle the selected worker when workers exist. `Ctrl+S` opens the same status detail view from chat, logs, Worker overview, or an embedded native session; it keeps the footer compact while exposing the complete route, reason, selected Provider/model, phase, activity timestamp, and native session. Press `Ctrl+S` or `Esc` to return without interrupting the underlying Worker. While a request is running, press `Esc` to stop it. After a failed or cancelled task, press `Ctrl+R` to retry the same turn or `Ctrl+N` to start independently. In worker-log views, scroll with the mouse wheel, Up/Down, or PageUp/PageDown, press `Tab` to cycle workers, `Ctrl+N` to start a new task, and `Esc` to return to chat.
|
|
456
456
|
|
|
457
457
|
`Ctrl+B` opens a live Worker overview without replacing the `Ctrl+W` log shortcut. It summarizes every Judge, Actor, and Critic by turn, role, named Provider, persisted model, state, phase, latest summary, and native-session availability. The selected active worker gets a live activity line showing its first-output deadline while starting and its idle deadline after output begins. The line stays muted while healthy, changes to warning for the final 20% and danger once overdue. Up/Down, PageUp/PageDown, the mouse wheel, or `Tab` changes the selected worker; Enter or `Ctrl+W` opens its rendered log, `Ctrl+O` attaches to its native session, and `Esc` returns to the originating chat or log view. Router diagnostics and the project picker also return to the overview when opened from there.
|
|
458
458
|
|
|
@@ -516,12 +516,12 @@ The release job installs npm `^11.5.1`, runs on Node `24.15.x`, publishes the pr
|
|
|
516
516
|
To publish a release, update `package.json` and `src/version.ts` to the same version, then push a matching tag:
|
|
517
517
|
|
|
518
518
|
```bash
|
|
519
|
-
VERSION=0.2.
|
|
519
|
+
VERSION=0.2.2
|
|
520
520
|
git tag "v$VERSION"
|
|
521
521
|
git push origin "v$VERSION"
|
|
522
522
|
```
|
|
523
523
|
|
|
524
|
-
You can also run the Release workflow manually and enter the same tag value. The release tag must match `package.json`; for example, package version `0.2.
|
|
524
|
+
You can also run the Release workflow manually and enter the same tag value. The release tag must match `package.json`; for example, package version `0.2.2` requires tag `v0.2.2`. Published tags such as `v0.2.1` are immutable and must not be moved or reused.
|
|
525
525
|
|
|
526
526
|
## Publishing Hygiene
|
|
527
527
|
|
package/dist/cli.js
CHANGED
|
@@ -16,6 +16,7 @@ import { configPath, loadConfig, withUiThemeOverride, writeDefaultConfig } from
|
|
|
16
16
|
import { pathExists } from "./core/file-store.js";
|
|
17
17
|
import { exportDiagnostics } from "./core/diagnostics.js";
|
|
18
18
|
import { readRouterAudit } from "./core/router-audit.js";
|
|
19
|
+
import { inheritMacSystemProxy } from "./core/system-proxy.js";
|
|
19
20
|
import { loadTaskSessionDetails as loadPersistedTaskSessionDetails } from "./core/task-session-details.js";
|
|
20
21
|
import { listWorkspaceChoices } from "./core/workspace.js";
|
|
21
22
|
import { runDoctor, runRuntimePreflight } from "./doctor.js";
|
|
@@ -40,6 +41,9 @@ async function main() {
|
|
|
40
41
|
process.exit(1);
|
|
41
42
|
}
|
|
42
43
|
const cliArgs = parseCliArgs(rawArgs, process.cwd());
|
|
44
|
+
if (!cliArgs.help && !cliArgs.themes && !cliArgs.version && !cliArgs.init) {
|
|
45
|
+
await inheritMacSystemProxy(process.env);
|
|
46
|
+
}
|
|
43
47
|
if (!cliArgs.help && !cliArgs.themes && !cliArgs.version) {
|
|
44
48
|
await prepareAppRoot(cliArgs.appRoot);
|
|
45
49
|
}
|
package/dist/core/config.js
CHANGED
|
@@ -74,13 +74,13 @@ const CodexRouterConfigSchema = z.object({
|
|
|
74
74
|
"never",
|
|
75
75
|
"-"
|
|
76
76
|
]),
|
|
77
|
-
timeoutMs: z.number().int().positive().default(
|
|
78
|
-
firstOutputTimeoutMs: z.number().int().positive().default(
|
|
79
|
-
idleTimeoutMs: z.number().int().positive().default(
|
|
77
|
+
timeoutMs: z.number().int().positive().default(60000),
|
|
78
|
+
firstOutputTimeoutMs: z.number().int().positive().default(30000),
|
|
79
|
+
idleTimeoutMs: z.number().int().positive().default(30000),
|
|
80
80
|
maxOutputBytes: z.number().int().min(1024).max(16 * 1024 * 1024).default(1024 * 1024),
|
|
81
81
|
maxAttempts: z.number().int().min(1).max(3).default(2),
|
|
82
82
|
retryDelayMs: z.number().int().min(0).max(10000).default(500),
|
|
83
|
-
followUpTimeoutMs: z.number().int().positive().max(120000).default(
|
|
83
|
+
followUpTimeoutMs: z.number().int().positive().max(120000).default(45000),
|
|
84
84
|
fallback: z.enum(["simple", "complex"]).default("simple"),
|
|
85
85
|
env: z.record(z.string()).default({})
|
|
86
86
|
});
|
|
@@ -165,13 +165,13 @@ export function defaultConfig(projectRoot) {
|
|
|
165
165
|
"never",
|
|
166
166
|
"-"
|
|
167
167
|
],
|
|
168
|
-
timeoutMs:
|
|
169
|
-
firstOutputTimeoutMs:
|
|
170
|
-
idleTimeoutMs:
|
|
168
|
+
timeoutMs: 60000,
|
|
169
|
+
firstOutputTimeoutMs: 30000,
|
|
170
|
+
idleTimeoutMs: 30000,
|
|
171
171
|
maxOutputBytes: 1024 * 1024,
|
|
172
172
|
maxAttempts: 2,
|
|
173
173
|
retryDelayMs: 500,
|
|
174
|
-
followUpTimeoutMs:
|
|
174
|
+
followUpTimeoutMs: 45000,
|
|
175
175
|
fallback: "simple",
|
|
176
176
|
env: {}
|
|
177
177
|
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
const proxyEnvironmentNames = ["HTTP_PROXY", "HTTPS_PROXY", "ALL_PROXY"];
|
|
3
|
+
export async function inheritMacSystemProxy(env = process.env, options = {}) {
|
|
4
|
+
if ((options.platform ?? process.platform) !== "darwin" || systemProxyInheritanceDisabled(env)) {
|
|
5
|
+
return [];
|
|
6
|
+
}
|
|
7
|
+
const output = await (options.readSettings ?? readMacSystemProxySettings)();
|
|
8
|
+
const settings = parseMacSystemProxySettings(output);
|
|
9
|
+
if (!settings.http && !settings.https && !settings.socks) {
|
|
10
|
+
return [];
|
|
11
|
+
}
|
|
12
|
+
const inherited = {
|
|
13
|
+
HTTP_PROXY: settings.http ? proxyUrl("http", settings.http) : null,
|
|
14
|
+
HTTPS_PROXY: settings.https ? proxyUrl("http", settings.https) : null,
|
|
15
|
+
ALL_PROXY: settings.socks ? proxyUrl("socks5h", settings.socks) : null
|
|
16
|
+
};
|
|
17
|
+
const applied = [];
|
|
18
|
+
for (const name of proxyEnvironmentNames) {
|
|
19
|
+
const value = inherited[name];
|
|
20
|
+
if (!value || environmentHasName(env, name)) {
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
env[name] = value;
|
|
24
|
+
applied.push(name);
|
|
25
|
+
}
|
|
26
|
+
if (settings.exceptions.length > 0 && !environmentHasName(env, "NO_PROXY")) {
|
|
27
|
+
env.NO_PROXY = settings.exceptions.join(",");
|
|
28
|
+
applied.push("NO_PROXY");
|
|
29
|
+
}
|
|
30
|
+
return applied;
|
|
31
|
+
}
|
|
32
|
+
export function parseMacSystemProxySettings(output) {
|
|
33
|
+
return {
|
|
34
|
+
http: parseProxyEndpoint(output, "HTTP"),
|
|
35
|
+
https: parseProxyEndpoint(output, "HTTPS"),
|
|
36
|
+
socks: parseProxyEndpoint(output, "SOCKS"),
|
|
37
|
+
exceptions: parseProxyExceptions(output)
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function parseProxyEndpoint(output, prefix) {
|
|
41
|
+
const enabled = output.match(new RegExp(`\\b${prefix}Enable\\s*:\\s*(\\d+)`))?.[1] === "1";
|
|
42
|
+
const host = output.match(new RegExp(`\\b${prefix}Proxy\\s*:\\s*(\\S+)`))?.[1];
|
|
43
|
+
const port = Number(output.match(new RegExp(`\\b${prefix}Port\\s*:\\s*(\\d+)`))?.[1]);
|
|
44
|
+
return enabled && host && Number.isInteger(port) && port > 0 ? { host, port } : null;
|
|
45
|
+
}
|
|
46
|
+
function parseProxyExceptions(output) {
|
|
47
|
+
const block = output.match(/ExceptionsList\s*:\s*<array>\s*\{([\s\S]*?)\n\s*\}/)?.[1] ?? "";
|
|
48
|
+
const exceptions = [...block.matchAll(/^\s*\d+\s*:\s*(.+?)\s*$/gm)]
|
|
49
|
+
.map((match) => normalizeProxyException(match[1] ?? ""))
|
|
50
|
+
.filter((value) => Boolean(value));
|
|
51
|
+
return [...new Set(exceptions)];
|
|
52
|
+
}
|
|
53
|
+
function normalizeProxyException(value) {
|
|
54
|
+
const normalized = value.trim();
|
|
55
|
+
if (!normalized) {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
if (normalized === "<local>") {
|
|
59
|
+
return "localhost";
|
|
60
|
+
}
|
|
61
|
+
return normalized.startsWith("*.") ? normalized.slice(1) : normalized;
|
|
62
|
+
}
|
|
63
|
+
function proxyUrl(protocol, endpoint) {
|
|
64
|
+
const host = endpoint.host.includes(":") ? `[${endpoint.host}]` : endpoint.host;
|
|
65
|
+
return `${protocol}://${host}:${endpoint.port}`;
|
|
66
|
+
}
|
|
67
|
+
function environmentHasName(env, name) {
|
|
68
|
+
return Object.entries(env).some(([candidate, value]) => (candidate.toUpperCase() === name && Boolean(value?.trim())));
|
|
69
|
+
}
|
|
70
|
+
function systemProxyInheritanceDisabled(env) {
|
|
71
|
+
return /^(?:0|false|no|off)$/i.test(env.PARALLEL_CODEX_INHERIT_SYSTEM_PROXY?.trim() ?? "");
|
|
72
|
+
}
|
|
73
|
+
function readMacSystemProxySettings() {
|
|
74
|
+
return new Promise((resolve) => {
|
|
75
|
+
execFile("scutil", ["--proxy"], { timeout: 1000 }, (error, stdout) => {
|
|
76
|
+
resolve(error ? "" : stdout);
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
}
|
package/dist/tui/App.js
CHANGED
|
@@ -19,7 +19,7 @@ import { TerminalOutput } from "./TerminalOutput.js";
|
|
|
19
19
|
import { NativeTerminalScreen } from "./terminal-screen.js";
|
|
20
20
|
import { WorkerOutputView } from "./WorkerOutputView.js";
|
|
21
21
|
import { compactEndByDisplayWidth, displayWidth, wrapByDisplayWidth } from "./display-width.js";
|
|
22
|
-
import { isAttachShortcut, isCopyShortcut, isDiagnosticsShortcut, isExitShortcut, isLogsShortcut, isNewTaskShortcut, isRouterDiagnosticsShortcut, isStatusDetailsShortcut, isTaskResultShortcut, isTaskSessionsShortcut, isWorkerOverviewShortcut, isWorkerSearchShortcut, isWorkspaceShortcut, mouseScrollDelta, rawHistoryDelta, rawPageScrollDelta, rawPlainArrowDelta, scrollDelta, workerLogJumpKind } from "./keyboard.js";
|
|
22
|
+
import { isAttachShortcut, isCopyShortcut, isDiagnosticsShortcut, isExitShortcut, isLogsShortcut, isNewTaskShortcut, isRouterDiagnosticsShortcut, isStatusDetailsShortcut, isTaskResultShortcut, isTaskSessionsShortcut, isWorkerOverviewShortcut, isWorkerSearchShortcut, isWorkspaceShortcut, mouseScrollDelta, rawChatScrollArrowDelta, rawHistoryDelta, rawPageScrollDelta, rawPlainArrowDelta, scrollDelta, workerLogJumpKind } from "./keyboard.js";
|
|
23
23
|
import { createRawInputDecoder, tokenizeRawInput } from "./raw-input-decoder.js";
|
|
24
24
|
import { decodeHtmlEntities } from "./markdown-text.js";
|
|
25
25
|
import { configureTuiTheme, TUI_THEME } from "./theme.js";
|
|
@@ -1389,7 +1389,7 @@ export function App({ config, orchestrator, cwd, initialTaskId = null, initialRo
|
|
|
1389
1389
|
return;
|
|
1390
1390
|
}
|
|
1391
1391
|
const wheelDelta = mouseScrollDelta(chunk, 3);
|
|
1392
|
-
const arrowScrollDelta =
|
|
1392
|
+
const arrowScrollDelta = rawChatScrollArrowDelta(chunk);
|
|
1393
1393
|
const pageDelta = rawPageScrollDelta(chunk, Math.max(1, outputHeight - 1));
|
|
1394
1394
|
const historyDelta = wheelDelta + arrowScrollDelta + pageDelta;
|
|
1395
1395
|
if (historyDelta !== 0 && chatMaxScrollOffsetRef.current > 0) {
|
package/dist/tui/keyboard.js
CHANGED
|
@@ -79,6 +79,11 @@ export function rawPlainArrowDelta(input) {
|
|
|
79
79
|
}
|
|
80
80
|
return delta;
|
|
81
81
|
}
|
|
82
|
+
export function rawChatScrollArrowDelta(input) {
|
|
83
|
+
const delta = rawPlainArrowDelta(input);
|
|
84
|
+
// Alternate-scroll wheels arrive as arrow bursts; one arrow remains a draft-history keypress.
|
|
85
|
+
return Math.abs(delta) > 1 ? delta : 0;
|
|
86
|
+
}
|
|
82
87
|
export function mouseScrollDelta(input, linesPerWheel = 3) {
|
|
83
88
|
let delta = 0;
|
|
84
89
|
for (const match of input.matchAll(/\x1b\[<(\d+);\d+;\d+[mM]/g)) {
|
package/dist/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = "0.2.
|
|
1
|
+
export const version = "0.2.2";
|