xab 9.0.0 → 11.0.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.
Files changed (2) hide show
  1. package/dist/index.js +94 -7
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -448,7 +448,28 @@ async function runStreamedWithProgress(thread, prompt, onProgress, turnOpts) {
448
448
  const cmd = item.command ?? "";
449
449
  const status = item.status;
450
450
  if (status === "in_progress") {
451
- onProgress("exec", `$ ${cmd}`);
451
+ const inner = cmd.replace(/^\/bin\/(?:ba)?sh\s+-\w+\s+['"](.*)['"]$/s, "$1") || cmd;
452
+ const readMatch = inner.match(/\b(?:cat|head|tail|less|bat|nl)\s+(?:-\w+\s+)*['"]?([^\s'"|\]]+)/);
453
+ const sedMatch = inner.match(/\bsed\s+-n\s+['"]?\d+.*?['"]?\s+['"]?([^\s'"]+)/);
454
+ const rgMatch = inner.match(/\brg\s+(?:-[^\s]+\s+)*['"]?(.+?)['"]?\s+(\S+)/);
455
+ const gitShowMatch = inner.match(/\bgit\s+show\s+(\S+)/);
456
+ const gitDiffMatch = inner.match(/\bgit\s+diff\b/);
457
+ const gitLogMatch = inner.match(/\bgit\s+log\b/);
458
+ if (readMatch) {
459
+ onProgress("read", readMatch[1]);
460
+ } else if (sedMatch) {
461
+ onProgress("read", sedMatch[1]);
462
+ } else if (rgMatch) {
463
+ onProgress("grep", `"${rgMatch[1]}" in ${rgMatch[2]}`);
464
+ } else if (gitShowMatch) {
465
+ onProgress("read", `git show ${gitShowMatch[1]}`);
466
+ } else if (gitDiffMatch) {
467
+ onProgress("exec", `$ ${inner.slice(0, 120)}`);
468
+ } else if (gitLogMatch) {
469
+ onProgress("exec", `$ ${inner.slice(0, 120)}`);
470
+ } else {
471
+ onProgress("exec", `$ ${inner.slice(0, 120)}`);
472
+ }
452
473
  } else if (status === "completed") {
453
474
  const output = item.aggregated_output ?? "";
454
475
  if (output) {
@@ -468,17 +489,45 @@ async function runStreamedWithProgress(thread, prompt, onProgress, turnOpts) {
468
489
  }
469
490
  break;
470
491
  }
492
+ case "mcp_tool_call": {
493
+ const tool = item.tool ?? "";
494
+ const args = item.arguments ?? {};
495
+ const status = item.status;
496
+ if (status === "in_progress") {
497
+ if (tool.toLowerCase().includes("read")) {
498
+ onProgress("read", (args.file_path ?? args.path ?? tool).slice(0, 120));
499
+ } else if (tool.toLowerCase().includes("grep") || tool.toLowerCase().includes("search")) {
500
+ onProgress("grep", `"${(args.pattern ?? "").slice(0, 60)}" ${args.path ?? ""}`);
501
+ } else if (tool.toLowerCase().includes("glob") || tool.toLowerCase().includes("find")) {
502
+ onProgress("glob", (args.pattern ?? args.path ?? tool).slice(0, 120));
503
+ } else {
504
+ onProgress("tool", `${tool} ${JSON.stringify(args).slice(0, 80)}`);
505
+ }
506
+ }
507
+ break;
508
+ }
471
509
  case "reasoning": {
472
510
  const text = item.text ?? "";
473
- if (text && event.type === "item.completed") {
474
- onProgress("think", text.split(`
475
- `)[0].slice(0, 120));
511
+ if (text) {
512
+ const lines = text.split(`
513
+ `).filter(Boolean);
514
+ for (const line of lines.slice(0, 3)) {
515
+ onProgress("think", line.slice(0, 150));
516
+ }
476
517
  }
477
518
  break;
478
519
  }
479
520
  case "agent_message": {
521
+ const text = item.text ?? "";
480
522
  if (event.type === "item.completed") {
481
- finalResponse = item.text ?? "";
523
+ finalResponse = text;
524
+ }
525
+ if (event.type === "item.updated" && text) {
526
+ const lastLine = text.split(`
527
+ `).filter(Boolean).pop();
528
+ if (lastLine && lastLine.length > 10) {
529
+ onProgress("think", lastLine.slice(0, 150));
530
+ }
482
531
  }
483
532
  break;
484
533
  }
@@ -1387,6 +1436,9 @@ async function runEngine(opts, cb) {
1387
1436
  autoSkip = true
1388
1437
  } = opts;
1389
1438
  const config = loadConfig(repoPath, opts.configPath);
1439
+ if (opts.hints?.length) {
1440
+ config.promptHints = [...config.promptHints ?? [], ...opts.hints];
1441
+ }
1390
1442
  const effectiveMaxAttempts = opts.maxAttempts ?? config.maxAttempts ?? Infinity;
1391
1443
  const effectiveWorkBranch = opts.workBranch ?? config.workBranch;
1392
1444
  const commitPrefix = config.commitPrefix ?? "backmerge:";
@@ -1402,6 +1454,12 @@ async function runEngine(opts, cb) {
1402
1454
  for (const l of logs)
1403
1455
  cb.onLog(` ${l}`, "gray");
1404
1456
  }
1457
+ if (config.promptHints && config.promptHints.length > 0) {
1458
+ cb.onLog(`Active hints (${config.promptHints.length}):`, "cyan");
1459
+ for (const h of config.promptHints) {
1460
+ cb.onLog(` \u2192 ${h}`, "cyan");
1461
+ }
1462
+ }
1405
1463
  cb.onStatus("Discovering repo structure & docs...");
1406
1464
  const repoCtx = buildRepoContext(repoPath, config);
1407
1465
  const instrCount = repoCtx.instructions.size;
@@ -1998,8 +2056,32 @@ async function runBatch(opts) {
1998
2056
  onProgress(phase, msg) {
1999
2057
  if (jsonl)
2000
2058
  emitJsonl({ event: "progress", phase, msg });
2059
+ const subMatch = msg.match(/^\[(\w+)\]\s*(.*)/);
2060
+ const sub = subMatch ? subMatch[1] : phase;
2061
+ const text = subMatch ? subMatch[2] : msg;
2001
2062
  let icon;
2002
- switch (phase) {
2063
+ switch (sub) {
2064
+ case "read":
2065
+ icon = chalk.cyan("\uD83D\uDCD6");
2066
+ break;
2067
+ case "grep":
2068
+ icon = chalk.cyan("\uD83D\uDD0D");
2069
+ break;
2070
+ case "glob":
2071
+ icon = chalk.cyan("\uD83D\uDCC2");
2072
+ break;
2073
+ case "exec":
2074
+ icon = chalk.yellow("\u26A1");
2075
+ break;
2076
+ case "file":
2077
+ icon = chalk.green("\u270F\uFE0F");
2078
+ break;
2079
+ case "think":
2080
+ icon = chalk.blue("\uD83D\uDCAD");
2081
+ break;
2082
+ case "tool":
2083
+ icon = chalk.dim("\uD83D\uDD27");
2084
+ break;
2003
2085
  case "analyze":
2004
2086
  icon = chalk.blue("\u25C6");
2005
2087
  break;
@@ -2013,7 +2095,7 @@ async function runBatch(opts) {
2013
2095
  icon = chalk.dim("\xB7");
2014
2096
  break;
2015
2097
  }
2016
- log(` ${ts()} ${icon} ${chalk.dim(msg)}`);
2098
+ log(` ${ts()} ${icon} ${chalk.dim(text)}`);
2017
2099
  },
2018
2100
  onLog(msg, color) {
2019
2101
  if (jsonl)
@@ -2970,6 +3052,7 @@ var batch = false;
2970
3052
  var jsonl = false;
2971
3053
  var resume = true;
2972
3054
  var showHelp = false;
3055
+ var hints = [];
2973
3056
  for (let i = 0;i < args.length; i++) {
2974
3057
  const arg = args[i];
2975
3058
  if (arg === "--help" || arg === "-h")
@@ -3010,6 +3093,8 @@ for (let i = 0;i < args.length; i++) {
3010
3093
  maxAttempts = parseInt(args[++i], 10) || 2;
3011
3094
  else if (arg === "--config" && args[i + 1])
3012
3095
  configPath = args[++i];
3096
+ else if (arg === "--hint" && args[i + 1])
3097
+ hints.push(args[++i]);
3013
3098
  else if (!arg.startsWith("-"))
3014
3099
  repoPath = arg;
3015
3100
  }
@@ -3046,6 +3131,7 @@ Behavior:
3046
3131
  --no-auto-skip Don't auto-skip commits AI identifies as present
3047
3132
  --max-attempts <n> Max retries per commit (default: unlimited)
3048
3133
  --no-resume Don't resume from interrupted runs (default: auto-resume)
3134
+ --hint <text> Operator hint injected into AI prompts (repeatable)
3049
3135
  --config <path> Path to config file (default: auto-discover)
3050
3136
  --help, -h Show this help
3051
3137
 
@@ -3106,6 +3192,7 @@ var engineOpts = {
3106
3192
  review,
3107
3193
  autoSkip,
3108
3194
  resume,
3195
+ ...hints.length > 0 && { hints },
3109
3196
  maxAttempts,
3110
3197
  ...startAfter && { startAfter },
3111
3198
  ...limit > 0 && { limit },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xab",
3
- "version": "9.0.0",
3
+ "version": "11.0.0",
4
4
  "description": "AI-powered curated branch reconciliation engine",
5
5
  "type": "module",
6
6
  "bin": {