@ai-development-environment/control-agent 0.0.51 → 0.0.53

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/control-agent.js +149 -34
  2. package/package.json +1 -1
@@ -5980,6 +5980,8 @@ var WORKTREE_OPERATIONS = [
5980
5980
  "OPEN_EDITOR",
5981
5981
  "FORCE_PUSH",
5982
5982
  "SYNC",
5983
+ "REBASE",
5984
+ "CANCEL_REBASE",
5983
5985
  "PUSH",
5984
5986
  "RESET",
5985
5987
  "STASH_ALL",
@@ -13422,7 +13424,7 @@ var runWorkflowGitCheckpoint = async (payloadValue, _timeoutMs, signal) => {
13422
13424
  import { createWriteStream as createWriteStream2, watch } from "node:fs";
13423
13425
  import { mkdtemp as mkdtemp5, open as open2, readFile as readFile7, realpath as realpath6, rm as rm8, stat as stat8 } from "node:fs/promises";
13424
13426
  import { tmpdir as tmpdir5 } from "node:os";
13425
- import { basename as basename4, dirname as dirname6, join as join10, relative as relative5 } from "node:path";
13427
+ import { basename as basename4, dirname as dirname6, isAbsolute as isAbsolute5, join as join10, relative as relative5 } from "node:path";
13426
13428
  import { spawn as spawn5 } from "node:child_process";
13427
13429
  var successfulProcess7 = {
13428
13430
  exitCode: 0,
@@ -13446,9 +13448,13 @@ function statusChangeState(value) {
13446
13448
  const entries = value.split("\0").filter(Boolean);
13447
13449
  let hasStagedChanges = false;
13448
13450
  let hasUnstagedChanges = false;
13451
+ let hasConflicts = false;
13449
13452
  for (let index = 0; index < entries.length; index += 1) {
13450
13453
  const code = entries[index].slice(0, 2);
13451
13454
  const untracked = code === "??";
13455
+ if (["DD", "AU", "UD", "UA", "DU", "AA", "UU"].includes(code)) {
13456
+ hasConflicts = true;
13457
+ }
13452
13458
  if (!untracked && code[0] !== " " && code[0] !== "?" && code[0] !== "!") {
13453
13459
  hasStagedChanges = true;
13454
13460
  }
@@ -13459,7 +13465,50 @@ function statusChangeState(value) {
13459
13465
  index += 1;
13460
13466
  }
13461
13467
  }
13462
- return { hasStagedChanges, hasUnstagedChanges };
13468
+ return { hasStagedChanges, hasUnstagedChanges, hasConflicts };
13469
+ }
13470
+ async function rebaseInProgress(folder, timeoutMs, signal) {
13471
+ for (const name of ["rebase-merge", "rebase-apply"]) {
13472
+ const pathResult = await git3(
13473
+ folder,
13474
+ ["rev-parse", "--git-path", name],
13475
+ timeoutMs,
13476
+ signal
13477
+ );
13478
+ if (pathResult.exitCode !== 0) continue;
13479
+ const candidate = pathResult.stdout.trim();
13480
+ if (!candidate) continue;
13481
+ try {
13482
+ await stat8(isAbsolute5(candidate) ? candidate : join10(folder, candidate));
13483
+ return true;
13484
+ } catch {
13485
+ }
13486
+ }
13487
+ return false;
13488
+ }
13489
+ async function rebaseBranch(folder, timeoutMs, signal) {
13490
+ for (const name of ["rebase-merge/head-name", "rebase-apply/head-name"]) {
13491
+ const pathResult = await git3(
13492
+ folder,
13493
+ ["rev-parse", "--git-path", name],
13494
+ timeoutMs,
13495
+ signal
13496
+ );
13497
+ if (pathResult.exitCode !== 0) continue;
13498
+ const candidate = pathResult.stdout.trim();
13499
+ if (!candidate) continue;
13500
+ try {
13501
+ const headName = (await readFile7(
13502
+ isAbsolute5(candidate) ? candidate : join10(folder, candidate),
13503
+ "utf8"
13504
+ )).trim();
13505
+ if (headName.startsWith("refs/heads/")) {
13506
+ return headName.slice("refs/heads/".length);
13507
+ }
13508
+ } catch {
13509
+ }
13510
+ }
13511
+ return null;
13463
13512
  }
13464
13513
  function closeWorktreeWatch(entry) {
13465
13514
  if (entry.timer) clearTimeout(entry.timer);
@@ -13483,39 +13532,44 @@ async function flushWorktreeActivity(entry) {
13483
13532
  entry.pending = false;
13484
13533
  try {
13485
13534
  const signal = new AbortController().signal;
13486
- const [status2, branchResult, headResult, codeStateHash] = await Promise.all(
13487
- [
13488
- git3(
13489
- entry.folder,
13490
- [
13491
- "--no-optional-locks",
13492
- "status",
13493
- "--porcelain=v1",
13494
- "-z",
13495
- "--untracked-files=all"
13496
- ],
13497
- entry.timeoutMs,
13498
- signal
13499
- ),
13500
- git3(
13501
- entry.folder,
13502
- ["symbolic-ref", "--short", "-q", "HEAD"],
13503
- entry.timeoutMs,
13504
- signal
13505
- ),
13506
- git3(entry.folder, ["rev-parse", "HEAD"], entry.timeoutMs, signal),
13507
- worktreeCodeStateHash(entry.folder, entry.timeoutMs, signal)
13508
- ]
13509
- );
13510
- const branch = branchResult.exitCode === 0 ? branchResult.stdout.trim() : null;
13535
+ const [status2, branchResult, headResult, codeStateHash, rebasing] = await Promise.all([
13536
+ git3(
13537
+ entry.folder,
13538
+ [
13539
+ "--no-optional-locks",
13540
+ "status",
13541
+ "--porcelain=v1",
13542
+ "-z",
13543
+ "--untracked-files=all"
13544
+ ],
13545
+ entry.timeoutMs,
13546
+ signal
13547
+ ),
13548
+ git3(
13549
+ entry.folder,
13550
+ ["symbolic-ref", "--short", "-q", "HEAD"],
13551
+ entry.timeoutMs,
13552
+ signal
13553
+ ),
13554
+ git3(entry.folder, ["rev-parse", "HEAD"], entry.timeoutMs, signal),
13555
+ worktreeCodeStateHash(entry.folder, entry.timeoutMs, signal),
13556
+ rebaseInProgress(entry.folder, entry.timeoutMs, signal)
13557
+ ]);
13558
+ const symbolicBranch = branchResult.exitCode === 0 ? branchResult.stdout.trim() : null;
13559
+ const branch = symbolicBranch ?? (rebasing ? await rebaseBranch(entry.folder, entry.timeoutMs, signal) : null);
13511
13560
  const headSha = headResult.exitCode === 0 ? headResult.stdout.trim() : null;
13512
13561
  const headIdentity = headSha ? `${branch ?? ""}\0${headSha}` : null;
13513
- const changes = status2.exitCode === 0 ? statusChangeState(status2.stdout) : { hasStagedChanges: false, hasUnstagedChanges: false };
13562
+ const changes = status2.exitCode === 0 ? statusChangeState(status2.stdout) : {
13563
+ hasStagedChanges: false,
13564
+ hasUnstagedChanges: false,
13565
+ hasConflicts: false
13566
+ };
13514
13567
  const report = {
13515
13568
  codebaseId: entry.codebaseId,
13516
13569
  gitDirectory: entry.gitDirectory,
13517
13570
  codeStateHash,
13518
13571
  ...changes,
13572
+ rebaseInProgress: rebasing,
13519
13573
  pushStatus: await worktreePushStatus(
13520
13574
  entry.folder,
13521
13575
  branch,
@@ -13686,9 +13740,14 @@ async function inspectWorktreeItem(folderValue2, rootFolder, baseBranch, primary
13686
13740
  const checkedAt = (/* @__PURE__ */ new Date()).toISOString();
13687
13741
  try {
13688
13742
  const folder = await realpath6(folderValue2);
13689
- const [gitDir, branchResult, headResult, statusResult] = await Promise.all([
13743
+ const [gitDir, branchResult, headResult, statusResult, rebasing] = await Promise.all([
13690
13744
  gitDirectory(folder, timeoutMs, signal),
13691
- git3(folder, ["symbolic-ref", "--short", "-q", "HEAD"], timeoutMs, signal),
13745
+ git3(
13746
+ folder,
13747
+ ["symbolic-ref", "--short", "-q", "HEAD"],
13748
+ timeoutMs,
13749
+ signal
13750
+ ),
13692
13751
  git3(folder, ["rev-parse", "HEAD"], timeoutMs, signal),
13693
13752
  git3(
13694
13753
  folder,
@@ -13701,9 +13760,11 @@ async function inspectWorktreeItem(folderValue2, rootFolder, baseBranch, primary
13701
13760
  ],
13702
13761
  timeoutMs,
13703
13762
  signal
13704
- )
13763
+ ),
13764
+ rebaseInProgress(folder, timeoutMs, signal)
13705
13765
  ]);
13706
- const branch = branchResult.exitCode === 0 ? branchResult.stdout.trim() : null;
13766
+ const symbolicBranch = branchResult.exitCode === 0 ? branchResult.stdout.trim() : null;
13767
+ const branch = symbolicBranch ?? (rebasing ? await rebaseBranch(folder, timeoutMs, signal) : null);
13707
13768
  const upstreamResult = branch ? await git3(
13708
13769
  folder,
13709
13770
  ["rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{upstream}"],
@@ -13719,7 +13780,11 @@ async function inspectWorktreeItem(folderValue2, rootFolder, baseBranch, primary
13719
13780
  signal
13720
13781
  ) : { ahead: null, behind: null };
13721
13782
  const syncState = worktreeSyncState(branch, upstream, upstreamCounts);
13722
- const changes = statusResult.exitCode === 0 ? statusChangeState(statusResult.stdout) : { hasStagedChanges: false, hasUnstagedChanges: false };
13783
+ const changes = statusResult.exitCode === 0 ? statusChangeState(statusResult.stdout) : {
13784
+ hasStagedChanges: false,
13785
+ hasUnstagedChanges: false,
13786
+ hasConflicts: false
13787
+ };
13723
13788
  return {
13724
13789
  gitDirectory: gitDir,
13725
13790
  folder,
@@ -13735,6 +13800,7 @@ async function inspectWorktreeItem(folderValue2, rootFolder, baseBranch, primary
13735
13800
  baseAhead: baseCounts.ahead,
13736
13801
  baseBehind: baseCounts.behind,
13737
13802
  ...changes,
13803
+ rebaseInProgress: rebasing,
13738
13804
  pushStatus: await worktreePushStatus(
13739
13805
  folder,
13740
13806
  branch,
@@ -13763,6 +13829,8 @@ async function inspectWorktreeItem(folderValue2, rootFolder, baseBranch, primary
13763
13829
  baseBehind: null,
13764
13830
  hasStagedChanges: false,
13765
13831
  hasUnstagedChanges: false,
13832
+ rebaseInProgress: false,
13833
+ hasConflicts: false,
13766
13834
  pushStatus: "UNKNOWN",
13767
13835
  availability: "ERROR",
13768
13836
  error: cleanError3(error),
@@ -15239,12 +15307,59 @@ var operateWorktree = async (payload, timeoutMs, signal) => {
15239
15307
  signal
15240
15308
  );
15241
15309
  if (rebase.exitCode !== 0) {
15242
- await git3(folder, ["rebase", "--abort"], timeoutMs, signal);
15310
+ const status2 = await git3(
15311
+ folder,
15312
+ ["status", "--porcelain=v1", "-z"],
15313
+ timeoutMs,
15314
+ signal
15315
+ );
15316
+ const conflicts = status2.exitCode === 0 && statusChangeState(status2.stdout).hasConflicts;
15317
+ if (!(conflicts && await rebaseInProgress(folder, timeoutMs, signal))) {
15318
+ await git3(folder, ["rebase", "--abort"], timeoutMs, signal);
15319
+ }
15243
15320
  throw new Error(cleanError3(rebase.stderr || "Rebase failed"));
15244
15321
  }
15245
15322
  await runGit(["push", "--force-with-lease"], "Sync push failed");
15246
15323
  break;
15247
15324
  }
15325
+ case "REBASE": {
15326
+ if (!branch) throw new Error("Rebase requires a branch");
15327
+ if (!input.baseBranch) throw new Error("Rebase requires a base branch");
15328
+ const statusResult = await runGit(
15329
+ ["status", "--porcelain"],
15330
+ "Could not inspect worktree changes"
15331
+ );
15332
+ if (statusResult.stdout.trim())
15333
+ throw new Error("Stash or commit changes before rebasing");
15334
+ await runGit(["fetch", "origin"], "Could not fetch origin");
15335
+ const rebase = await git3(
15336
+ folder,
15337
+ ["rebase", `refs/remotes/origin/${input.baseBranch}`],
15338
+ timeoutMs,
15339
+ signal
15340
+ );
15341
+ if (rebase.exitCode !== 0) {
15342
+ const status2 = await git3(
15343
+ folder,
15344
+ ["status", "--porcelain=v1", "-z"],
15345
+ timeoutMs,
15346
+ signal
15347
+ );
15348
+ const conflicts = status2.exitCode === 0 && statusChangeState(status2.stdout).hasConflicts;
15349
+ if (!(conflicts && await rebaseInProgress(folder, timeoutMs, signal))) {
15350
+ await git3(folder, ["rebase", "--abort"], timeoutMs, signal);
15351
+ }
15352
+ throw new Error(cleanError3(rebase.stderr || "Rebase failed"));
15353
+ }
15354
+ break;
15355
+ }
15356
+ case "CANCEL_REBASE": {
15357
+ if (!await rebaseInProgress(folder, timeoutMs, signal)) {
15358
+ throw new Error("No rebase is in progress");
15359
+ }
15360
+ await runGit(["rebase", "--abort"], "Could not cancel rebase");
15361
+ break;
15362
+ }
15248
15363
  case "PUSH":
15249
15364
  if (!branch) throw new Error("Push requires a branch");
15250
15365
  await runGit(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-development-environment/control-agent",
3
- "version": "0.0.51",
3
+ "version": "0.0.53",
4
4
  "description": "Control agent for the AI Development Environment",
5
5
  "license": "MIT",
6
6
  "repository": {