aoaoe 0.56.0 → 0.58.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 CHANGED
@@ -244,6 +244,10 @@ commands:
244
244
  config --diff show only fields that differ from defaults
245
245
  notify-test send a test notification to configured webhooks
246
246
  doctor comprehensive health check (config, tools, daemon, disk)
247
+ logs show recent conversation log entries
248
+ logs --actions show action log entries (from ~/.aoaoe/actions.log)
249
+ logs --grep <pattern> filter log entries by substring or regex
250
+ logs -n <count> number of entries to show (default: 50)
247
251
  task manage tasks and sessions (list, start, stop, new, rm, edit)
248
252
  tasks show task progress (from aoaoe.tasks.json)
249
253
  history review recent actions (from ~/.aoaoe/actions.log)
package/dist/config.d.ts CHANGED
@@ -30,6 +30,10 @@ export declare function parseCliArgs(argv: string[]): {
30
30
  configDiff: boolean;
31
31
  notifyTest: boolean;
32
32
  runDoctor: boolean;
33
+ runLogs: boolean;
34
+ logsActions: boolean;
35
+ logsGrep?: string;
36
+ logsCount?: number;
33
37
  runInit: boolean;
34
38
  initForce: boolean;
35
39
  runTaskCli: boolean;
package/dist/config.js CHANGED
@@ -299,7 +299,7 @@ export function parseCliArgs(argv) {
299
299
  let initForce = false;
300
300
  let runTaskCli = false;
301
301
  let registerTitle;
302
- const defaults = { overrides, help: false, version: false, register: false, testContext: false, runTest: false, showTasks: false, showHistory: false, showStatus: false, showConfig: false, configValidate: false, configDiff: false, notifyTest: false, runDoctor: false, runInit: false, initForce: false, runTaskCli: false };
302
+ const defaults = { overrides, help: false, version: false, register: false, testContext: false, runTest: false, showTasks: false, showHistory: false, showStatus: false, showConfig: false, configValidate: false, configDiff: false, notifyTest: false, runDoctor: false, runLogs: false, logsActions: false, logsGrep: undefined, logsCount: undefined, runInit: false, initForce: false, runTaskCli: false };
303
303
  // check for subcommand as first non-flag arg
304
304
  if (argv[2] === "test-context") {
305
305
  return { ...defaults, testContext: true };
@@ -330,6 +330,22 @@ export function parseCliArgs(argv) {
330
330
  if (argv[2] === "doctor") {
331
331
  return { ...defaults, runDoctor: true };
332
332
  }
333
+ if (argv[2] === "logs") {
334
+ const actions = argv.includes("--actions") || argv.includes("-a");
335
+ let grep;
336
+ let count;
337
+ for (let i = 3; i < argv.length; i++) {
338
+ if ((argv[i] === "--grep" || argv[i] === "-g") && argv[i + 1]) {
339
+ grep = argv[++i];
340
+ }
341
+ else if ((argv[i] === "-n" || argv[i] === "--count") && argv[i + 1]) {
342
+ const val = parseInt(argv[++i], 10);
343
+ if (!isNaN(val) && val > 0)
344
+ count = val;
345
+ }
346
+ }
347
+ return { ...defaults, runLogs: true, logsActions: actions, logsGrep: grep, logsCount: count };
348
+ }
333
349
  if (argv[2] === "init") {
334
350
  const force = argv.includes("--force") || argv.includes("-f");
335
351
  return { ...defaults, runInit: true, initForce: force };
@@ -419,7 +435,7 @@ export function parseCliArgs(argv) {
419
435
  break;
420
436
  }
421
437
  }
422
- return { overrides, help, version, register: false, testContext: false, runTest: false, showTasks: false, showHistory: false, showStatus: false, showConfig: false, configValidate: false, configDiff: false, notifyTest: false, runDoctor: false, runInit: false, initForce: false, runTaskCli: false };
438
+ return { overrides, help, version, register: false, testContext: false, runTest: false, showTasks: false, showHistory: false, showStatus: false, showConfig: false, configValidate: false, configDiff: false, notifyTest: false, runDoctor: false, runLogs: false, logsActions: false, logsGrep: undefined, logsCount: undefined, runInit: false, initForce: false, runTaskCli: false };
423
439
  }
424
440
  export function printHelp() {
425
441
  console.log(`aoaoe - autonomous supervisor for agent-of-empires sessions
@@ -441,6 +457,10 @@ commands:
441
457
  config --diff show only fields that differ from defaults
442
458
  notify-test send a test notification to configured webhooks
443
459
  doctor comprehensive health check (config, tools, daemon, disk)
460
+ logs show recent conversation log entries (last 50)
461
+ logs --actions show action log entries (from ~/.aoaoe/actions.log)
462
+ logs --grep <pattern> filter log entries by substring or regex
463
+ logs -n <count> number of entries to show (default: 50)
444
464
  task manage tasks and sessions (list, start, stop, new, rm, edit)
445
465
  tasks show task progress (from aoaoe.tasks.json)
446
466
  history review recent actions (from ~/.aoaoe/actions.log)
@@ -467,6 +487,11 @@ options:
467
487
  init options:
468
488
  --force, -f overwrite existing config
469
489
 
490
+ logs options:
491
+ --actions, -a show action log instead of conversation log
492
+ --grep, -g <pattern> filter entries by substring or regex
493
+ -n, --count <number> number of entries to show (default: 50)
494
+
470
495
  register options:
471
496
  --title, -t <name> session title in AoE (default: aoaoe)
472
497
 
package/dist/console.d.ts CHANGED
@@ -65,5 +65,11 @@ export declare function summarizeRecentActions(logLines: string[], windowMs?: nu
65
65
  * Pure function: takes stderr text, returns a plain-English explanation.
66
66
  */
67
67
  export declare function friendlyError(stderr: string): string;
68
+ /**
69
+ * Filter log lines by a grep pattern (substring or regex).
70
+ * Tries the pattern as a regex first; falls back to plain case-insensitive substring match
71
+ * if the pattern is not valid regex syntax.
72
+ */
73
+ export declare function filterLogLines(lines: string[], pattern: string): string[];
68
74
  export declare function colorizeConsoleLine(line: string): string;
69
75
  //# sourceMappingURL=console.d.ts.map
package/dist/console.js CHANGED
@@ -365,6 +365,25 @@ export function friendlyError(stderr) {
365
365
  const firstLine = s.split("\n")[0].trim();
366
366
  return firstLine.length > 120 ? firstLine.slice(0, 117) + "..." : firstLine;
367
367
  }
368
+ /**
369
+ * Filter log lines by a grep pattern (substring or regex).
370
+ * Tries the pattern as a regex first; falls back to plain case-insensitive substring match
371
+ * if the pattern is not valid regex syntax.
372
+ */
373
+ export function filterLogLines(lines, pattern) {
374
+ let re = null;
375
+ try {
376
+ re = new RegExp(pattern, "i");
377
+ }
378
+ catch {
379
+ // invalid regex — use substring
380
+ }
381
+ return lines.filter((line) => {
382
+ if (re)
383
+ return re.test(line);
384
+ return line.toLowerCase().includes(pattern.toLowerCase());
385
+ });
386
+ }
368
387
  // colorize a single console line for inline terminal output
369
388
  // applied to each line as it's written (not batch like chat.ts colorize)
370
389
  export function colorizeConsoleLine(line) {
package/dist/index.js CHANGED
@@ -7,7 +7,7 @@ import { printDashboard } from "./dashboard.js";
7
7
  import { InputReader } from "./input.js";
8
8
  import { ReasonerConsole } from "./console.js";
9
9
  import { writeState, buildSessionStates, checkInterrupt, clearInterrupt, cleanupState, acquireLock, readState } from "./daemon-state.js";
10
- import { formatSessionSummaries, formatActionDetail, formatPlainEnglishAction, narrateObservation, summarizeRecentActions, friendlyError } from "./console.js";
10
+ import { formatSessionSummaries, formatActionDetail, formatPlainEnglishAction, narrateObservation, summarizeRecentActions, friendlyError, colorizeConsoleLine, filterLogLines } from "./console.js";
11
11
  import { loadGlobalContext, resolveProjectDirWithSource, discoverContextFiles, loadSessionContext } from "./context.js";
12
12
  import { tick as loopTick } from "./loop.js";
13
13
  import { exec as shellExec } from "./shell.js";
@@ -28,7 +28,7 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
28
28
  const AOAOE_DIR = join(homedir(), ".aoaoe"); // watch dir for wakeable sleep
29
29
  const INPUT_FILE = join(AOAOE_DIR, "pending-input.txt"); // file IPC from chat.ts
30
30
  async function main() {
31
- const { overrides, help, version, register, testContext: isTestContext, runTest, showTasks, showHistory, showStatus, showConfig, configValidate, configDiff, notifyTest, runDoctor, runInit, initForce, runTaskCli: isTaskCli, registerTitle } = parseCliArgs(process.argv);
31
+ const { overrides, help, version, register, testContext: isTestContext, runTest, showTasks, showHistory, showStatus, showConfig, configValidate, configDiff, notifyTest, runDoctor, runLogs, logsActions, logsGrep, logsCount, runInit, initForce, runTaskCli: isTaskCli, registerTitle } = parseCliArgs(process.argv);
32
32
  if (help) {
33
33
  printHelp();
34
34
  process.exit(0);
@@ -96,6 +96,11 @@ async function main() {
96
96
  await runDoctorCheck();
97
97
  return;
98
98
  }
99
+ // `aoaoe logs` -- show conversation or action log entries
100
+ if (runLogs) {
101
+ await showLogs(logsActions, logsGrep, logsCount);
102
+ return;
103
+ }
99
104
  // `aoaoe task` -- task management CLI
100
105
  if (isTaskCli) {
101
106
  await runTaskCli(process.argv);
@@ -1188,6 +1193,104 @@ async function showActionHistory() {
1188
1193
  console.log(` breakdown: ${breakdown}`);
1189
1194
  console.log("");
1190
1195
  }
1196
+ // `aoaoe logs` -- show conversation or action log entries
1197
+ async function showLogs(actions, grep, count) {
1198
+ const n = count ?? 50;
1199
+ if (actions) {
1200
+ // show action log entries (JSONL from ~/.aoaoe/actions.log)
1201
+ const logFile = join(homedir(), ".aoaoe", "actions.log");
1202
+ if (!existsSync(logFile)) {
1203
+ console.log("no action log found (no actions have been taken yet)");
1204
+ return;
1205
+ }
1206
+ let lines;
1207
+ try {
1208
+ lines = readFileSync(logFile, "utf-8").trim().split("\n").filter((l) => l.trim());
1209
+ }
1210
+ catch {
1211
+ console.error("failed to read action log");
1212
+ return;
1213
+ }
1214
+ if (lines.length === 0) {
1215
+ console.log("action log is empty");
1216
+ return;
1217
+ }
1218
+ // apply grep filter before slicing
1219
+ if (grep) {
1220
+ lines = filterLogLines(lines, grep);
1221
+ if (lines.length === 0) {
1222
+ console.log(`no action log entries matching '${grep}'`);
1223
+ return;
1224
+ }
1225
+ }
1226
+ const recent = lines.slice(-n);
1227
+ console.log("");
1228
+ console.log(` action log (last ${recent.length} of ${lines.length}${grep ? ` matching '${grep}'` : ""})`);
1229
+ console.log(` ${"─".repeat(70)}`);
1230
+ for (const line of recent) {
1231
+ try {
1232
+ const entry = toActionLogEntry(JSON.parse(line));
1233
+ if (!entry)
1234
+ continue;
1235
+ const time = new Date(entry.timestamp).toLocaleTimeString();
1236
+ const date = new Date(entry.timestamp).toLocaleDateString();
1237
+ const icon = entry.success ? `${GREEN}+${RESET}` : `${RED}!${RESET}`;
1238
+ const actionName = entry.action.action;
1239
+ const session = entry.action.session?.slice(0, 8) ?? entry.action.title ?? "";
1240
+ const detail = entry.detail.length > 50 ? entry.detail.slice(0, 47) + "..." : entry.detail;
1241
+ console.log(` ${icon} ${DIM}${date} ${time}${RESET} ${YELLOW}${actionName.padEnd(16)}${RESET} ${session.padEnd(10)} ${detail}`);
1242
+ }
1243
+ catch {
1244
+ // skip unparseable lines
1245
+ }
1246
+ }
1247
+ console.log(` ${"─".repeat(70)}`);
1248
+ console.log("");
1249
+ }
1250
+ else {
1251
+ // show conversation log entries (text from ~/.aoaoe/conversation.log)
1252
+ const logFile = join(homedir(), ".aoaoe", "conversation.log");
1253
+ if (!existsSync(logFile)) {
1254
+ console.log("no conversation log found (daemon hasn't run yet)");
1255
+ return;
1256
+ }
1257
+ let lines;
1258
+ try {
1259
+ const content = readFileSync(logFile, "utf-8");
1260
+ lines = content.split("\n");
1261
+ }
1262
+ catch {
1263
+ console.error("failed to read conversation log");
1264
+ return;
1265
+ }
1266
+ // remove trailing empty line from split
1267
+ if (lines.length > 0 && lines[lines.length - 1] === "") {
1268
+ lines.pop();
1269
+ }
1270
+ if (lines.length === 0) {
1271
+ console.log("conversation log is empty");
1272
+ return;
1273
+ }
1274
+ // apply grep filter before slicing
1275
+ if (grep) {
1276
+ lines = filterLogLines(lines, grep);
1277
+ if (lines.length === 0) {
1278
+ console.log(`no conversation log entries matching '${grep}'`);
1279
+ return;
1280
+ }
1281
+ }
1282
+ const recent = lines.slice(-n);
1283
+ console.log("");
1284
+ console.log(` conversation log (last ${recent.length} of ${lines.length}${grep ? ` matching '${grep}'` : ""})`);
1285
+ console.log(` ${"─".repeat(70)}`);
1286
+ // colorize using the same function as the inline console output
1287
+ for (const line of recent) {
1288
+ console.log(` ${colorizeConsoleLine(line)}`);
1289
+ }
1290
+ console.log(` ${"─".repeat(70)}`);
1291
+ console.log("");
1292
+ }
1293
+ }
1191
1294
  // `aoaoe test` -- dynamically import and run the integration test
1192
1295
  async function runIntegrationTest() {
1193
1296
  const testModule = resolve(__dirname, "integration-test.js");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aoaoe",
3
- "version": "0.56.0",
3
+ "version": "0.58.0",
4
4
  "description": "Autonomous supervisor for agent-of-empires sessions using OpenCode or Claude Code",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",