feat(codex): SessionMutator stub + session-file resolver
Wires the host's mirror hook end-to-end: FindCodexSessionFile walks ~/.codex/sessions/<YYYY>/<MM>/<DD>/rollout-*-<thread_id>.jsonl to prove the path for the captured thread_id, then logs the no-op. Real rewrite is deferred to v2: codex keys tool calls by `call_<id>` not the `toolu_<id>` Plexum's canonical block format uses, so a v1 rewriter would never find a matching id. When tool-call id round-trip through codex's native surface lands, the rewriter plugs into this file's path resolver. Also rescues cmd/plexum-openai-provider-plugin/main.go from .gitignore (the bare 'plexum-openai-provider-plugin' pattern was too greedy — it matched the source directory). Tightened to '/plexum-openai-provider-plugin' + '/bin/' so only built binaries get ignored.
This commit is contained in:
63
internal/runner/session_mutate.go
Normal file
63
internal/runner/session_mutate.go
Normal file
@@ -0,0 +1,63 @@
|
||||
// session_mutate.go — codex session file path resolution. The actual
|
||||
// JSONL rewrite is deferred (see main.go MutateSession comment): codex
|
||||
// keys tool calls by `call_<id>`, not the `toolu_<id>` Plexum uses,
|
||||
// so a v1 mirror would never match anything. We expose the path
|
||||
// finder here so the host-side wiring telemetry stays useful and the
|
||||
// v2 rewriter has its entry point.
|
||||
//
|
||||
// Codex layout (observed):
|
||||
//
|
||||
// ~/.codex/sessions/<YYYY>/<MM>/<DD>/rollout-<ISO>-<thread_id>.jsonl
|
||||
//
|
||||
// Older layout (pre-0.5x) wrote into the top-level sessions dir with
|
||||
// the same filename convention. We probe both.
|
||||
|
||||
package runner
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// FindCodexSessionFile resolves the rollout JSONL for the thread_id
|
||||
// captured into workspace/.plexum-codex-session. Returns ("", error)
|
||||
// when no session id is recorded yet OR no matching file is on disk.
|
||||
func FindCodexSessionFile(workspace string) (string, error) {
|
||||
threadID := loadSessionID(workspace)
|
||||
if threadID == "" {
|
||||
return "", errors.New("no thread_id captured yet")
|
||||
}
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
root := filepath.Join(home, ".codex", "sessions")
|
||||
var found string
|
||||
err = filepath.WalkDir(root, func(p string, d os.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return nil // tolerate per-entry errors; keep walking
|
||||
}
|
||||
if d.IsDir() {
|
||||
return nil
|
||||
}
|
||||
name := d.Name()
|
||||
if !strings.HasSuffix(name, ".jsonl") && !strings.HasSuffix(name, ".json") {
|
||||
return nil
|
||||
}
|
||||
if strings.Contains(name, threadID) {
|
||||
found = p
|
||||
return filepath.SkipAll
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if found == "" {
|
||||
return "", fmt.Errorf("no rollout file for thread_id=%s under %s", threadID, root)
|
||||
}
|
||||
return found, nil
|
||||
}
|
||||
Reference in New Issue
Block a user