From 43335bc2495c597477fc140aefe066f552c3c294 Mon Sep 17 00:00:00 2001 From: onevcat Date: Tue, 29 Sep 2026 09:14:44 +0900 Subject: [PATCH] Preserve caller argument boundaries and daemon log continuity --- docs/components/agent-detection.md | 3 ++ docs/components/cli.md | 2 ++ .../AgentDetection/CodexLogProvider.swift | 14 ++++++--- .../AgentDetection/ProcessDetection.swift | 9 ++++++ supacodeTests/CodexLogProviderTests.swift | 29 +++++++++++++++++++ .../ProcessDetectionSmokeTests.swift | 12 ++++++++ 6 files changed, 65 insertions(+), 4 deletions(-) diff --git a/docs/components/agent-detection.md b/docs/components/agent-detection.md index b08e87a0e..3b4349969 100644 --- a/docs/components/agent-detection.md +++ b/docs/components/agent-detection.md @@ -119,6 +119,9 @@ at a `~/.grok/` install (so Cursor's own `agent` entrypoint stays Cursor). Until the pane's Codex submits its first message, and for a moment after each new submit, detection falls back to the screen. A Codex launched from an Agent Profile or with `--no-daemon` owns its logs and is read directly. + If a previously established daemon binding becomes unavailable, detection falls + back to the screen but retains its log cursors. When the binding returns, it + consumes pending events without replaying earlier turn starts. Claude reads the detected PID's native registry under its configured root (`~/.claude/sessions` by default). `busy` and `shell` mean **Working**, including diff --git a/docs/components/cli.md b/docs/components/cli.md index 57f33f1e5..4c0fc8b34 100644 --- a/docs/components/cli.md +++ b/docs/components/cli.md @@ -132,6 +132,8 @@ the submitted prompts there (mode 0600); Prowl deletes the file once the pane's longer be undone. A pane whose Codex has not submitted anything yet, or whose shell overrides those variables, cannot be mapped, and caller-scoped commands fail with `SOURCE_REQUIRED`. +Session logs larger than 64 MiB are not mapped. Restarting Codex in the pane resets its +session log; its first indexed submit can establish the mapping again. Codex launched from an Agent Profile, or with `--no-daemon`, runs commands inside the pane and is not affected. diff --git a/supacode/Infrastructure/AgentDetection/CodexLogProvider.swift b/supacode/Infrastructure/AgentDetection/CodexLogProvider.swift index d66c96a47..62fae841d 100644 --- a/supacode/Infrastructure/AgentDetection/CodexLogProvider.swift +++ b/supacode/Infrastructure/AgentDetection/CodexLogProvider.swift @@ -57,10 +57,16 @@ actor CodexLogProvider { .compactMap { parse($0)?.transcriptPath } var liveOffsets: [URL: UInt64] = [:] // An embedded TUI owns its rollouts. A TUI that owns none may drive daemon threads. - if complete, paths.isEmpty, let daemonBinding, let binding = await daemonBinding(process, configRoot) { - paths = binding.paths.map { URL(filePath: $0, directoryHint: .notDirectory) } - for (path, offset) in binding.liveOffsets { - liveOffsets[URL(filePath: path, directoryHint: .notDirectory)] = offset + if complete, paths.isEmpty, let daemonBinding { + if let binding = await daemonBinding(process, configRoot) { + paths = binding.paths.map { URL(filePath: $0, directoryHint: .notDirectory) } + for (path, offset) in binding.liveOffsets { + liveOffsets[URL(filePath: path, directoryHint: .notDirectory)] = offset + } + } else if !cursors.isEmpty { + // A failed lookup does not prove that previously bound work disappeared. + // Suspend authority and keep the cursors until a complete binding returns. + complete = false } } let events = sample(paths: paths, inventoryComplete: complete, liveOffsets: liveOffsets) diff --git a/supacode/Infrastructure/AgentDetection/ProcessDetection.swift b/supacode/Infrastructure/AgentDetection/ProcessDetection.swift index fa89752ac..1a3e1799d 100644 --- a/supacode/Infrastructure/AgentDetection/ProcessDetection.swift +++ b/supacode/Infrastructure/AgentDetection/ProcessDetection.swift @@ -327,6 +327,15 @@ nonisolated enum ProcessDetection { } var strings: [String] = [] + // Only the executable-path padding may contain extra NUL bytes. Within argv, + // each NUL ends one argument, including an empty one. + for _ in 0..