- TokenCtx + Classify + formatTokenCount (R2.2, R3.1-3.5, R4.4) - ReadTokenCtx orchestrator: env > PID walk > transcript parse (R1.1-1.6, R2.1-2.6) - parseLastUsage: 10MB scanner, JSONL last-assistant-wins, zero-usage qualifies (R2.1-2.3) - parsePIDFile: strict two-line layout; rejects partial/corrupted writes (R6.2-6.3) - resolveViaPIDWalk: 8-hop ancestor walk, liveness + start-stamp check (R1.2, R6.1, R6.3) - proc_darwin.go (x/sys/unix kinfo_proc) + proc_linux.go (/proc/stat field 22) - parseStatStartTime: platform-agnostic, handles comm with parens/spaces Parent 1.0 from dev/plans/26174-planctl-context-tokens/tasks.md
61 lines
1.7 KiB
Go
61 lines
1.7 KiB
Go
//go:build linux
|
|
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
"syscall"
|
|
)
|
|
|
|
// spec:26174-planctl-context-tokens/R1.2+R6.3+D§3.3
|
|
// ppidOf returns the parent PID of pid by reading /proc/<pid>/status.
|
|
// Returns 0 on error.
|
|
func ppidOf(pid int) int {
|
|
data, err := os.ReadFile(fmt.Sprintf("/proc/%d/status", pid))
|
|
if err != nil {
|
|
return 0
|
|
}
|
|
for _, line := range strings.Split(string(data), "\n") {
|
|
if strings.HasPrefix(line, "PPid:") {
|
|
s := strings.TrimSpace(strings.TrimPrefix(line, "PPid:"))
|
|
n, err := strconv.Atoi(s)
|
|
if err != nil {
|
|
return 0
|
|
}
|
|
return n
|
|
}
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// spec:26174-planctl-context-tokens/R6.3+D§3.3
|
|
// processAlive reports whether a process with pid exists.
|
|
func processAlive(pid int) bool {
|
|
if pid <= 0 {
|
|
return false
|
|
}
|
|
return syscall.Kill(pid, 0) == nil
|
|
}
|
|
|
|
// spec:26174-planctl-context-tokens/R6.3+D§3.3+D§4.1
|
|
// processStartTimeSec returns the process start time as raw clock ticks since boot,
|
|
// read from /proc/<pid>/stat field 22 (starttime). The hook writes the same units
|
|
// (clock ticks) on Linux per §5.5/§4.1, so comparison units match.
|
|
//
|
|
// The name retains "Sec" for API symmetry with the macOS implementation (which
|
|
// returns epoch seconds). Within a platform both sides match; cross-platform
|
|
// comparison never happens.
|
|
//
|
|
// /proc/<pid>/stat is a single line: "pid (comm) state ppid ... starttime ...".
|
|
// `comm` can contain spaces and parens. We find the LAST ')' and tokenize the
|
|
// remainder so comm noise can't shift field indices.
|
|
func processStartTimeSec(pid int) (int64, error) {
|
|
data, err := os.ReadFile(fmt.Sprintf("/proc/%d/stat", pid))
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return parseStatStartTime(string(data))
|
|
}
|