claude-codex-pair 0.2.0 → 0.3.0
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/README.md +2 -1
- package/dist/pair.js +80 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -167,6 +167,7 @@ pair init
|
|
|
167
167
|
pair uninit # undo pair init in this worktree (keeps history; see "Uninstall")
|
|
168
168
|
pair register | unregister # run by Codex in its shell: let pair_listen notify this session
|
|
169
169
|
pair mcp # stdio MCP server for Codex (see "Let pair wake Codex")
|
|
170
|
+
pair ps # list running pair mcp and pair wait processes, where they run, and what started them
|
|
170
171
|
```
|
|
171
172
|
|
|
172
173
|
`pair status` shows the channel, worktree root, installed package version, and each lane's turn.
|
|
@@ -175,7 +176,7 @@ It also checks the generated instructions on disk:
|
|
|
175
176
|
```
|
|
176
177
|
channel: /Users/you/.pair/your-repo-12345678
|
|
177
178
|
worktree: /Users/you/your-repo
|
|
178
|
-
version: claude-codex-pair 0.
|
|
179
|
+
version: claude-codex-pair 0.2.0
|
|
179
180
|
claude-to-codex: idle
|
|
180
181
|
codex-to-claude: idle
|
|
181
182
|
instructions on disk (does not verify what running agents loaded):
|
package/dist/pair.js
CHANGED
|
@@ -1059,6 +1059,81 @@ function uninit(channel, root) {
|
|
|
1059
1059
|
const summary = removed.length > 0 ? removed.map((item) => `removed: ${item}`) : [`nothing from pair init found in ${root}`];
|
|
1060
1060
|
return [...summary, ...notes].join("\n");
|
|
1061
1061
|
}
|
|
1062
|
+
const PS_LINE = /^\s*(\d+)\s+(\d+)\s+(\w{3} \w{3}\s+\d+ [\d:]+ \d{4})\s+(.*)$/; // lstart is always 5 fields
|
|
1063
|
+
// node itself runs the script, so a wrapper whose command line mentions it (`zsh -c "… pair.js wait"`) doesn't match
|
|
1064
|
+
const PAIR_PROCESS = /^(?:\S*\/)?node(?: -\S+)* \S*\/(?:bin\/pair|dist\/pair\.js) ((?:mcp|wait)\b.*)$/;
|
|
1065
|
+
const SHELL = /^(?:\S*\/)?(?:zsh|bash|sh|dash|fish)(?: |$)/;
|
|
1066
|
+
function listProcesses() {
|
|
1067
|
+
let out;
|
|
1068
|
+
try {
|
|
1069
|
+
out = execFileSync("ps", ["-axo", "pid=,ppid=,lstart=,command="], { encoding: "utf8", env: { ...process.env, LC_ALL: "C" } });
|
|
1070
|
+
}
|
|
1071
|
+
catch (error) {
|
|
1072
|
+
throw new PairError(`can't list processes (${error instanceof Error ? error.message : String(error)}); agent sandboxes often block ps, so run pair ps in your own terminal`);
|
|
1073
|
+
}
|
|
1074
|
+
return out.split("\n").flatMap((line) => {
|
|
1075
|
+
const match = PS_LINE.exec(line);
|
|
1076
|
+
return match ? [{ pid: Number(match[1]), ppid: Number(match[2]), started: match[3], command: match[4] }] : [];
|
|
1077
|
+
});
|
|
1078
|
+
}
|
|
1079
|
+
/** Working directories by pid: /proc on Linux, lsof elsewhere. Unknown ones are left out. */
|
|
1080
|
+
function workingDirs(pids) {
|
|
1081
|
+
const dirs = new Map();
|
|
1082
|
+
if (existsSync("/proc/self/cwd")) {
|
|
1083
|
+
for (const pid of pids) {
|
|
1084
|
+
try {
|
|
1085
|
+
dirs.set(pid, realpathSync(`/proc/${pid}/cwd`));
|
|
1086
|
+
}
|
|
1087
|
+
catch {
|
|
1088
|
+
// gone, or not ours
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
return dirs;
|
|
1092
|
+
}
|
|
1093
|
+
let out = "";
|
|
1094
|
+
try {
|
|
1095
|
+
out = execFileSync("lsof", ["-a", "-d", "cwd", "-Fpn", "-p", pids.join(",")], { encoding: "utf8" });
|
|
1096
|
+
}
|
|
1097
|
+
catch (error) {
|
|
1098
|
+
// lsof exits 1 when one of the pids is gone, but still prints the rest
|
|
1099
|
+
out = error instanceof Error && "stdout" in error ? String(error.stdout) : "";
|
|
1100
|
+
}
|
|
1101
|
+
let pid = 0;
|
|
1102
|
+
for (const line of out.split("\n")) {
|
|
1103
|
+
if (line.startsWith("p")) {
|
|
1104
|
+
pid = Number(line.slice(1));
|
|
1105
|
+
}
|
|
1106
|
+
else if (line.startsWith("n")) {
|
|
1107
|
+
dirs.set(pid, line.slice(1));
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
return dirs;
|
|
1111
|
+
}
|
|
1112
|
+
/** Every running `pair mcp` and `pair wait` on this machine, with what started it. */
|
|
1113
|
+
function ps() {
|
|
1114
|
+
const all = listProcesses();
|
|
1115
|
+
const byPid = new Map(all.map((proc) => [proc.pid, proc]));
|
|
1116
|
+
const ours = all.flatMap((proc) => {
|
|
1117
|
+
const match = PAIR_PROCESS.exec(proc.command);
|
|
1118
|
+
return match ? [{ ...proc, args: match[1] }] : [];
|
|
1119
|
+
});
|
|
1120
|
+
if (ours.length === 0) {
|
|
1121
|
+
return "no pair mcp or pair wait is running";
|
|
1122
|
+
}
|
|
1123
|
+
const dirs = workingDirs(ours.map((proc) => proc.pid));
|
|
1124
|
+
return ours
|
|
1125
|
+
.flatMap((proc) => {
|
|
1126
|
+
let host = byPid.get(proc.ppid);
|
|
1127
|
+
while (host && SHELL.test(host.command)) {
|
|
1128
|
+
host = byPid.get(host.ppid); // an agent runs pair wait through a shell; show the agent
|
|
1129
|
+
}
|
|
1130
|
+
return [
|
|
1131
|
+
`pair ${proc.args} pid ${proc.pid} since ${proc.started} in ${dirs.get(proc.pid) ?? "?"}`,
|
|
1132
|
+
` started by ${host ? `${host.pid}: ${host.command.slice(0, 160)}` : `${proc.ppid} (gone)`}`,
|
|
1133
|
+
];
|
|
1134
|
+
})
|
|
1135
|
+
.join("\n");
|
|
1136
|
+
}
|
|
1062
1137
|
function readBody(source) {
|
|
1063
1138
|
if (!source) {
|
|
1064
1139
|
throw new PairError("send needs a message file, or - for stdin");
|
|
@@ -1087,7 +1162,8 @@ const USAGE = `usage:
|
|
|
1087
1162
|
pair init
|
|
1088
1163
|
pair uninit (remove what pair init wrote in this worktree; keeps history)
|
|
1089
1164
|
pair register | unregister (in Codex's shell: let pair_listen notify this session)
|
|
1090
|
-
pair mcp (stdio MCP server for Codex, providing pair_listen)
|
|
1165
|
+
pair mcp (stdio MCP server for Codex, providing pair_listen)
|
|
1166
|
+
pair ps (list running pair mcp and pair wait processes)`;
|
|
1091
1167
|
async function main(argv) {
|
|
1092
1168
|
const { values, positionals } = parseArgs({
|
|
1093
1169
|
args: argv,
|
|
@@ -1143,6 +1219,9 @@ async function main(argv) {
|
|
|
1143
1219
|
case "mcp":
|
|
1144
1220
|
await serveMcp();
|
|
1145
1221
|
return 0;
|
|
1222
|
+
case "ps":
|
|
1223
|
+
console.log(ps());
|
|
1224
|
+
return 0;
|
|
1146
1225
|
default:
|
|
1147
1226
|
console.error(USAGE);
|
|
1148
1227
|
return 1;
|