ax-agents 0.1.10 → 0.1.11

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.
Files changed (2) hide show
  1. package/ax.js +81 -2
  2. package/package.json +1 -1
package/ax.js CHANGED
@@ -1075,6 +1075,44 @@ function findClaudeLogPath(sessionId, sessionName) {
1075
1075
  return directPath;
1076
1076
  }
1077
1077
 
1078
+ // Fallback: most recently modified session from index (handles /new creating new sessions)
1079
+ if (existsSync(indexPath)) {
1080
+ try {
1081
+ const index = JSON.parse(readFileSync(indexPath, "utf-8"));
1082
+ if (index.entries?.length) {
1083
+ const sorted = [...index.entries].sort((a, b) => {
1084
+ const aTime = a.modified ? new Date(a.modified).getTime() : 0;
1085
+ const bTime = b.modified ? new Date(b.modified).getTime() : 0;
1086
+ return bTime - aTime;
1087
+ });
1088
+ const newest = sorted[0];
1089
+ if (newest?.fullPath && existsSync(newest.fullPath)) {
1090
+ debug("log", `findClaudeLogPath: fallback to most recent via index -> ${newest.fullPath}`);
1091
+ return newest.fullPath;
1092
+ }
1093
+ }
1094
+ } catch (err) {
1095
+ debugError("findClaudeLogPath:index-fallback", err);
1096
+ }
1097
+ }
1098
+
1099
+ // Final fallback: most recently modified .jsonl file (for projects without index)
1100
+ try {
1101
+ const files = readdirSync(claudeProjectDir)
1102
+ .filter((f) => f.endsWith(".jsonl"))
1103
+ .map((f) => {
1104
+ const fullPath = path.join(claudeProjectDir, f);
1105
+ return { path: fullPath, mtime: statSync(fullPath).mtimeMs };
1106
+ })
1107
+ .sort((a, b) => b.mtime - a.mtime);
1108
+ if (files.length > 0) {
1109
+ debug("log", `findClaudeLogPath: fallback to most recent file -> ${files[0].path}`);
1110
+ return files[0].path;
1111
+ }
1112
+ } catch (err) {
1113
+ debugError("findClaudeLogPath:file-fallback", err);
1114
+ }
1115
+
1078
1116
  debug("log", `findClaudeLogPath: not found`);
1079
1117
  return null;
1080
1118
  }
@@ -1120,13 +1158,54 @@ function findNewestClaudeSessionUuid(sessionName) {
1120
1158
  }
1121
1159
 
1122
1160
  /**
1161
+ * Find Codex log path by checking which .jsonl file the Codex process has open.
1162
+ * Uses lsof as the source of truth - whatever file the process has open is the current log.
1163
+ * Falls back to timestamp-based matching if lsof fails.
1123
1164
  * @param {string} sessionName
1124
1165
  * @returns {string | null}
1125
1166
  */
1126
1167
  function findCodexLogPath(sessionName) {
1127
1168
  debug("log", `findCodexLogPath: sessionName=${sessionName}`);
1128
- // For Codex, we need to match by timing since we can't control the session ID
1129
- // Get tmux session creation time
1169
+
1170
+ // Primary method: find the log file via lsof (what file does Codex have open?)
1171
+ try {
1172
+ // Get tmux pane PID
1173
+ const paneResult = spawnSync(
1174
+ "tmux",
1175
+ ["list-panes", "-t", sessionName, "-F", "#{pane_pid}"],
1176
+ { encoding: "utf-8" }
1177
+ );
1178
+ if (paneResult.status === 0 && paneResult.stdout.trim()) {
1179
+ const panePid = parseInt(paneResult.stdout.trim().split("\n")[0], 10);
1180
+ if (!isNaN(panePid)) {
1181
+ // Find child process named "codex"
1182
+ const pgrepResult = spawnSync("pgrep", ["-P", panePid.toString(), "-x", "codex"], {
1183
+ encoding: "utf-8",
1184
+ });
1185
+ if (pgrepResult.status === 0 && pgrepResult.stdout.trim()) {
1186
+ const codexPid = parseInt(pgrepResult.stdout.trim().split("\n")[0], 10);
1187
+ if (!isNaN(codexPid)) {
1188
+ // Use lsof to find which .jsonl file it has open
1189
+ const lsofResult = spawnSync("lsof", ["-p", codexPid.toString()], {
1190
+ encoding: "utf-8",
1191
+ });
1192
+ if (lsofResult.status === 0) {
1193
+ const match = lsofResult.stdout.match(/(\S+\.jsonl)\s*$/m);
1194
+ if (match) {
1195
+ debug("log", `findCodexLogPath: lsof found ${match[1]}`);
1196
+ return match[1];
1197
+ }
1198
+ }
1199
+ }
1200
+ }
1201
+ }
1202
+ }
1203
+ debug("log", `findCodexLogPath: lsof method failed, falling back to timestamp`);
1204
+ } catch (err) {
1205
+ debug("log", `findCodexLogPath: lsof exception, falling back to timestamp`);
1206
+ }
1207
+
1208
+ // Fallback: timestamp-based matching (for when process isn't running or lsof fails)
1130
1209
  try {
1131
1210
  const result = spawnSync(
1132
1211
  "tmux",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ax-agents",
3
- "version": "0.1.10",
3
+ "version": "0.1.11",
4
4
  "description": "A CLI for orchestrating AI coding agents via tmux",
5
5
  "bin": {
6
6
  "ax": "ax.js",