ax-agents 0.1.9 → 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.
- package/ax.js +89 -10
- package/package.json +1 -1
package/ax.js
CHANGED
|
@@ -308,7 +308,7 @@ ${progress || "(No progress yet)"}
|
|
|
308
308
|
## Your Task
|
|
309
309
|
${userPrompt}
|
|
310
310
|
|
|
311
|
-
Remember: Work on ONE thing, update ${relProgressPath},
|
|
311
|
+
Remember: Work on ONE thing, update ${relProgressPath}, then verify it works.
|
|
312
312
|
When ALL tasks are complete, output <promise>COMPLETE</promise>`;
|
|
313
313
|
}
|
|
314
314
|
|
|
@@ -639,7 +639,7 @@ const RFP_PREAMBLE = `## Guidelines
|
|
|
639
639
|
// Note: DO_PREAMBLE is a template - {progressPath} gets replaced at runtime
|
|
640
640
|
const DO_PREAMBLE = `You are an autonomous coding agent in a loop. Each iteration:
|
|
641
641
|
|
|
642
|
-
1. Read {progressPath} to see what's done.
|
|
642
|
+
1. Read {progressPath} to see what's done (empty means nothing done yet).
|
|
643
643
|
2. Choose the next task:
|
|
644
644
|
- Start with trivial/mechanistic work. It banks progress, builds context, and constrains nothing.
|
|
645
645
|
- Then do foundational work that makes harder problems easier and safer to approach.
|
|
@@ -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
|
-
|
|
1129
|
-
//
|
|
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",
|
|
@@ -1428,17 +1507,17 @@ function formatClaudeLogEntry(entry) {
|
|
|
1428
1507
|
const input = part.input || part.arguments || {};
|
|
1429
1508
|
let summary;
|
|
1430
1509
|
if (name === "Bash" && input.command) {
|
|
1431
|
-
summary = input.command
|
|
1510
|
+
summary = truncate(input.command, 50);
|
|
1432
1511
|
} else if (
|
|
1433
1512
|
name === "Task" &&
|
|
1434
1513
|
(input.description || input.subagent_type)
|
|
1435
1514
|
) {
|
|
1436
1515
|
// Task tool: show description or subagent type
|
|
1437
1516
|
summary = input.description || input.subagent_type || "";
|
|
1438
|
-
summary = summary
|
|
1517
|
+
summary = truncate(summary, 40);
|
|
1439
1518
|
} else {
|
|
1440
1519
|
const target = input.file_path || input.path || input.pattern || "";
|
|
1441
|
-
summary = target.split("/").pop() || target
|
|
1520
|
+
summary = target.split("/").pop() || truncate(target, 30);
|
|
1442
1521
|
}
|
|
1443
1522
|
output.push({ type: "tool", content: `> ${name}(${summary})` });
|
|
1444
1523
|
}
|
|
@@ -1476,14 +1555,14 @@ function formatCodexLogEntry(entry) {
|
|
|
1476
1555
|
try {
|
|
1477
1556
|
const args = JSON.parse(entry.payload.arguments || "{}");
|
|
1478
1557
|
if (name === "shell_command" && args.command) {
|
|
1479
|
-
summary = args.command
|
|
1558
|
+
summary = truncate(args.command, 50);
|
|
1480
1559
|
} else if (name === "Task" && (args.description || args.subagent_type)) {
|
|
1481
1560
|
// Task tool: show description or subagent type
|
|
1482
1561
|
summary = args.description || args.subagent_type || "";
|
|
1483
|
-
summary = summary
|
|
1562
|
+
summary = truncate(summary, 40);
|
|
1484
1563
|
} else {
|
|
1485
1564
|
const target = args.file_path || args.path || args.pattern || "";
|
|
1486
|
-
summary = target.split("/").pop() || target
|
|
1565
|
+
summary = target.split("/").pop() || truncate(target, 30);
|
|
1487
1566
|
}
|
|
1488
1567
|
} catch {
|
|
1489
1568
|
summary = "...";
|