aoaoe 0.54.0 → 0.55.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
@@ -241,6 +241,7 @@ commands:
241
241
  status quick daemon health check (is it running? what's it doing?)
242
242
  config show the effective resolved config (defaults + file)
243
243
  config --validate validate config + check tool availability
244
+ config --diff show only fields that differ from defaults
244
245
  notify-test send a test notification to configured webhooks
245
246
  task manage tasks and sessions (list, start, stop, new, rm, edit)
246
247
  tasks show task progress (from aoaoe.tasks.json)
package/dist/config.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import type { AoaoeConfig } from "./types.js";
2
+ export declare const DEFAULTS: AoaoeConfig;
2
3
  export declare function findConfigFile(): string | null;
3
4
  export declare function configFileExists(): boolean;
4
5
  export declare function defaultConfigPath(): string;
@@ -9,6 +10,11 @@ export declare function warnUnknownKeys(raw: unknown, source: string): void;
9
10
  export declare function validateConfig(config: AoaoeConfig): void;
10
11
  export declare function validateEnvironment(config: AoaoeConfig): Promise<void>;
11
12
  export declare function deepMerge(...objects: Record<string, unknown>[]): AoaoeConfig;
13
+ export declare function computeConfigDiff(current: Record<string, unknown>, defaults: Record<string, unknown>, prefix?: string): Array<{
14
+ path: string;
15
+ current: unknown;
16
+ default: unknown;
17
+ }>;
12
18
  export declare function parseCliArgs(argv: string[]): {
13
19
  overrides: Partial<AoaoeConfig>;
14
20
  help: boolean;
@@ -21,6 +27,7 @@ export declare function parseCliArgs(argv: string[]): {
21
27
  showStatus: boolean;
22
28
  showConfig: boolean;
23
29
  configValidate: boolean;
30
+ configDiff: boolean;
24
31
  notifyTest: boolean;
25
32
  runInit: boolean;
26
33
  initForce: boolean;
package/dist/config.js CHANGED
@@ -9,7 +9,7 @@ const AOAOE_DIR = join(homedir(), ".aoaoe");
9
9
  const CONFIG_NAMES = ["aoaoe.config.json", ".aoaoe.json"];
10
10
  // search order: ~/.aoaoe/ first (canonical), then cwd (local override for dev)
11
11
  const CONFIG_SEARCH_DIRS = [AOAOE_DIR, process.cwd()];
12
- const DEFAULTS = {
12
+ export const DEFAULTS = {
13
13
  reasoner: "opencode",
14
14
  pollIntervalMs: 10_000,
15
15
  opencode: {
@@ -259,6 +259,31 @@ export function deepMerge(...objects) {
259
259
  }
260
260
  return result;
261
261
  }
262
+ // compute fields that differ between two config objects (flat dot-notation paths)
263
+ // exported for testing
264
+ export function computeConfigDiff(current, defaults, prefix = "") {
265
+ const diffs = [];
266
+ const allKeys = new Set([...Object.keys(current), ...Object.keys(defaults)]);
267
+ for (const key of allKeys) {
268
+ const fullPath = prefix ? `${prefix}.${key}` : key;
269
+ const curVal = current[key];
270
+ const defVal = defaults[key];
271
+ // both are plain objects — recurse
272
+ if (curVal && defVal &&
273
+ typeof curVal === "object" && !Array.isArray(curVal) &&
274
+ typeof defVal === "object" && !Array.isArray(defVal)) {
275
+ diffs.push(...computeConfigDiff(curVal, defVal, fullPath));
276
+ continue;
277
+ }
278
+ // compare with JSON.stringify for arrays/objects, === for primitives
279
+ const curStr = JSON.stringify(curVal);
280
+ const defStr = JSON.stringify(defVal);
281
+ if (curStr !== defStr) {
282
+ diffs.push({ path: fullPath, current: curVal, default: defVal });
283
+ }
284
+ }
285
+ return diffs;
286
+ }
262
287
  function log(msg) {
263
288
  console.error(`[config] ${msg}`);
264
289
  }
@@ -274,7 +299,7 @@ export function parseCliArgs(argv) {
274
299
  let initForce = false;
275
300
  let runTaskCli = false;
276
301
  let registerTitle;
277
- const defaults = { overrides, help: false, version: false, register: false, testContext: false, runTest: false, showTasks: false, showHistory: false, showStatus: false, showConfig: false, configValidate: false, notifyTest: 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, runInit: false, initForce: false, runTaskCli: false };
278
303
  // check for subcommand as first non-flag arg
279
304
  if (argv[2] === "test-context") {
280
305
  return { ...defaults, testContext: true };
@@ -296,7 +321,8 @@ export function parseCliArgs(argv) {
296
321
  }
297
322
  if (argv[2] === "config") {
298
323
  const validate = argv.includes("--validate") || argv.includes("-V");
299
- return { ...defaults, showConfig: true, configValidate: validate };
324
+ const diff = argv.includes("--diff");
325
+ return { ...defaults, showConfig: true, configValidate: validate, configDiff: diff };
300
326
  }
301
327
  if (argv[2] === "notify-test") {
302
328
  return { ...defaults, notifyTest: true };
@@ -390,7 +416,7 @@ export function parseCliArgs(argv) {
390
416
  break;
391
417
  }
392
418
  }
393
- return { overrides, help, version, register: false, testContext: false, runTest: false, showTasks: false, showHistory: false, showStatus: false, showConfig: false, configValidate: false, notifyTest: false, runInit: false, initForce: false, runTaskCli: false };
419
+ return { overrides, help, version, register: false, testContext: false, runTest: false, showTasks: false, showHistory: false, showStatus: false, showConfig: false, configValidate: false, configDiff: false, notifyTest: false, runInit: false, initForce: false, runTaskCli: false };
394
420
  }
395
421
  export function printHelp() {
396
422
  console.log(`aoaoe - autonomous supervisor for agent-of-empires sessions
@@ -408,7 +434,8 @@ commands:
408
434
  (none) start the supervisor daemon (interactive TUI)
409
435
  status quick daemon health check (is it running? what's it doing?)
410
436
  config show the effective resolved config (defaults + file)
411
- config --validate validate config file + check tool availability
437
+ config --validate validate config + check tool availability
438
+ config --diff show only fields that differ from defaults
412
439
  notify-test send a test notification to configured webhooks
413
440
  task manage tasks and sessions (list, start, stop, new, rm, edit)
414
441
  tasks show task progress (from aoaoe.tasks.json)
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { loadConfig, validateEnvironment, parseCliArgs, printHelp, configFileExists, findConfigFile } from "./config.js";
2
+ import { loadConfig, validateEnvironment, parseCliArgs, printHelp, configFileExists, findConfigFile, DEFAULTS, computeConfigDiff } from "./config.js";
3
3
  import { Poller, computeTmuxName } from "./poller.js";
4
4
  import { createReasoner } from "./reasoner/index.js";
5
5
  import { Executor } from "./executor.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, notifyTest, runInit, initForce, runTaskCli: isTaskCli, registerTitle } = parseCliArgs(process.argv);
31
+ const { overrides, help, version, register, testContext: isTestContext, runTest, showTasks, showHistory, showStatus, showConfig, configValidate, configDiff, notifyTest, runInit, initForce, runTaskCli: isTaskCli, registerTitle } = parseCliArgs(process.argv);
32
32
  if (help) {
33
33
  printHelp();
34
34
  process.exit(0);
@@ -73,11 +73,14 @@ async function main() {
73
73
  showDaemonStatus();
74
74
  return;
75
75
  }
76
- // `aoaoe config` -- show effective resolved config (with optional --validate)
76
+ // `aoaoe config` -- show effective resolved config (with optional --validate or --diff)
77
77
  if (showConfig) {
78
78
  if (configValidate) {
79
79
  await runConfigValidation();
80
80
  }
81
+ else if (configDiff) {
82
+ showConfigDiff();
83
+ }
81
84
  else {
82
85
  showEffectiveConfig();
83
86
  }
@@ -1243,6 +1246,42 @@ function showDaemonStatus() {
1243
1246
  console.log(` ${statusIcon} ${BOLD}${s.title}${RESET} (${s.tool}) ${s.status}${userTag}${taskTag}`);
1244
1247
  }
1245
1248
  }
1249
+ // last action from actions.log
1250
+ try {
1251
+ const actionsLogPath = join(homedir(), ".aoaoe", "actions.log");
1252
+ if (existsSync(actionsLogPath)) {
1253
+ const content = readFileSync(actionsLogPath, "utf-8").trim();
1254
+ if (content) {
1255
+ const logLines = content.split("\n").filter((l) => l.trim());
1256
+ // find last non-wait action
1257
+ for (let i = logLines.length - 1; i >= 0; i--) {
1258
+ try {
1259
+ const entry = toActionLogEntry(JSON.parse(logLines[i]));
1260
+ if (!entry || entry.action.action === "wait")
1261
+ continue;
1262
+ const ago = Date.now() - entry.timestamp;
1263
+ const agoStr = ago < 60_000 ? `${Math.floor(ago / 1000)}s ago` :
1264
+ ago < 3_600_000 ? `${Math.floor(ago / 60_000)}m ago` :
1265
+ `${Math.floor(ago / 3_600_000)}h ago`;
1266
+ const icon = entry.success ? `${GREEN}+${RESET}` : `${RED}!${RESET}`;
1267
+ const session = entry.action.session?.slice(0, 8) ?? entry.action.title ?? "";
1268
+ const detail = entry.detail.length > 40 ? entry.detail.slice(0, 37) + "..." : entry.detail;
1269
+ console.log("");
1270
+ console.log(` last action: ${icon} ${entry.action.action} ${session} ${DIM}(${agoStr})${RESET}`);
1271
+ if (detail)
1272
+ console.log(` ${DIM}${detail}${RESET}`);
1273
+ break;
1274
+ }
1275
+ catch {
1276
+ // skip malformed lines
1277
+ }
1278
+ }
1279
+ }
1280
+ }
1281
+ }
1282
+ catch {
1283
+ // best-effort — actions.log might not exist
1284
+ }
1246
1285
  console.log("");
1247
1286
  }
1248
1287
  // `aoaoe config --validate` -- validate config file, field values, and tool availability
@@ -1363,6 +1402,33 @@ async function runConfigValidation() {
1363
1402
  if (failed > 0)
1364
1403
  process.exit(1);
1365
1404
  }
1405
+ // `aoaoe config --diff` -- show only fields that differ from defaults
1406
+ function showConfigDiff() {
1407
+ const configPath = findConfigFile();
1408
+ const configResult = loadConfig();
1409
+ const { _configPath, ...config } = configResult;
1410
+ const diffs = computeConfigDiff(config, DEFAULTS);
1411
+ console.log("");
1412
+ console.log(" aoaoe — config diff (vs. defaults)");
1413
+ console.log(` ${"─".repeat(50)}`);
1414
+ console.log(` source: ${configPath ?? "defaults (no config file found)"}`);
1415
+ console.log("");
1416
+ if (diffs.length === 0) {
1417
+ console.log(" (no differences — config matches defaults)");
1418
+ }
1419
+ else {
1420
+ for (const d of diffs) {
1421
+ const curStr = d.current === undefined ? `${DIM}(not set)${RESET}` : `${GREEN}${JSON.stringify(d.current)}${RESET}`;
1422
+ const defStr = d.default === undefined ? `${DIM}(not set)${RESET}` : `${DIM}${JSON.stringify(d.default)}${RESET}`;
1423
+ console.log(` ${YELLOW}${d.path}${RESET}`);
1424
+ console.log(` current: ${curStr}`);
1425
+ console.log(` default: ${defStr}`);
1426
+ }
1427
+ console.log("");
1428
+ console.log(` ${diffs.length} field(s) differ from defaults`);
1429
+ }
1430
+ console.log("");
1431
+ }
1366
1432
  // `aoaoe config` -- show the effective resolved config (defaults + file + any notes)
1367
1433
  function showEffectiveConfig() {
1368
1434
  const configPath = findConfigFile();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aoaoe",
3
- "version": "0.54.0",
3
+ "version": "0.55.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",