@gethmy/agent 1.14.0 → 1.14.2

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 (3) hide show
  1. package/dist/cli.js +39 -21
  2. package/dist/index.js +39 -21
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -463,7 +463,7 @@ var init_types = __esm(() => {
463
463
  worktreeGcIntervalMs: 5 * 60000
464
464
  },
465
465
  planning: DEFAULT_PLANNING_CONFIG,
466
- playbooks: { enabled: false, humanStageColumns: [] }
466
+ playbooks: { enabled: true, humanStageColumns: [] }
467
467
  };
468
468
  });
469
469
 
@@ -1980,7 +1980,24 @@ function fetchBaseBranch(repoRoot, baseBranch, attempts = 3, fetchImpl = (root,
1980
1980
  const detail = e?.stderr?.toString?.().trim() || (lastErr instanceof Error ? lastErr.message : String(lastErr));
1981
1981
  throw new WorktreeBaseError(`Could not fetch origin/${baseBranch} after ${attempts} attempts — ` + `refusing to build on a stale base. ${detail}`);
1982
1982
  }
1983
- function createWorktree(basePath, baseBranch, branchName) {
1983
+ function resolveWorktreeStartRef(baseBranch, branchName, continueExisting, branchExistsOnRemote) {
1984
+ if (continueExisting && branchExistsOnRemote()) {
1985
+ return `origin/${branchName}`;
1986
+ }
1987
+ return `origin/${baseBranch}`;
1988
+ }
1989
+ function fetchExistingBranch(repoRoot, branchName) {
1990
+ try {
1991
+ execFileSync3("git", ["fetch", "origin", branchName], {
1992
+ cwd: repoRoot,
1993
+ stdio: "pipe"
1994
+ });
1995
+ return true;
1996
+ } catch {
1997
+ return false;
1998
+ }
1999
+ }
2000
+ function createWorktree(basePath, baseBranch, branchName, opts = {}) {
1984
2001
  const repoRoot = execFileSync3("git", ["rev-parse", "--show-toplevel"], {
1985
2002
  encoding: "utf-8"
1986
2003
  }).trim();
@@ -1996,16 +2013,10 @@ function createWorktree(basePath, baseBranch, branchName) {
1996
2013
  });
1997
2014
  } catch {}
1998
2015
  fetchBaseBranch(repoRoot, baseBranch);
1999
- log.info(TAG5, `Creating worktree: ${worktreeDir} (branch: ${branchName})`);
2016
+ const startRef = resolveWorktreeStartRef(baseBranch, branchName, opts.continueExisting ?? false, () => fetchExistingBranch(repoRoot, branchName));
2017
+ log.info(TAG5, `Creating worktree: ${worktreeDir} (branch: ${branchName}, base: ${startRef})`);
2000
2018
  try {
2001
- execFileSync3("git", [
2002
- "worktree",
2003
- "add",
2004
- "-B",
2005
- branchName,
2006
- worktreeDir,
2007
- `origin/${baseBranch}`
2008
- ], { cwd: repoRoot, stdio: "pipe" });
2019
+ execFileSync3("git", ["worktree", "add", "-B", branchName, worktreeDir, startRef], { cwd: repoRoot, stdio: "pipe" });
2009
2020
  } catch (err) {
2010
2021
  const msg = err instanceof Error ? err.message : String(err);
2011
2022
  log.warn(TAG5, `worktree add failed, attempting forced recovery: ${msg}`);
@@ -2027,14 +2038,7 @@ function createWorktree(basePath, baseBranch, branchName) {
2027
2038
  stdio: "pipe"
2028
2039
  });
2029
2040
  } catch {}
2030
- execFileSync3("git", [
2031
- "worktree",
2032
- "add",
2033
- "-B",
2034
- branchName,
2035
- worktreeDir,
2036
- `origin/${baseBranch}`
2037
- ], { cwd: repoRoot, stdio: "pipe" });
2041
+ execFileSync3("git", ["worktree", "add", "-B", branchName, worktreeDir, startRef], { cwd: repoRoot, stdio: "pipe" });
2038
2042
  }
2039
2043
  log.info(TAG5, "Installing dependencies in worktree...");
2040
2044
  try {
@@ -2307,6 +2311,12 @@ class MergeMonitor {
2307
2311
  log.warn(TAG7, `Failed to update card: ${err instanceof Error ? err.message : err}`);
2308
2312
  }
2309
2313
  }
2314
+ try {
2315
+ await this.client.updateCard(card.id, { assignedAgentId: null });
2316
+ log.info(TAG7, `Cleared agent assignment on #${card.short_id}`);
2317
+ } catch (err) {
2318
+ log.warn(TAG7, `Failed to clear agent assignment on #${card.short_id}: ${err instanceof Error ? err.message : err}`);
2319
+ }
2310
2320
  const branchName = extractBranchFromDescription(card.description);
2311
2321
  if (branchName) {
2312
2322
  try {
@@ -4600,7 +4610,7 @@ class ProgressTracker {
4600
4610
  this.transitionTo("testing");
4601
4611
  }
4602
4612
  } else if (name === "mcp__harmony__harmony_end_agent_session") {
4603
- this.transitionTo("finishing");
4613
+ this.enterFinishingAndStop();
4604
4614
  }
4605
4615
  if (name === "mcp__harmony__harmony_toggle_subtask" && this.subtaskMode) {
4606
4616
  const val = this.extractString(input, "completed");
@@ -4659,6 +4669,14 @@ class ProgressTracker {
4659
4669
  this.lastAction = "";
4660
4670
  this.scheduleUpdate(PHASES[newPhase].label);
4661
4671
  }
4672
+ enterFinishingAndStop() {
4673
+ if (PHASE_ORDER.finishing > PHASE_ORDER[this.phase]) {
4674
+ this.runEventSink?.recordPhaseChanged("finishing", this.phase);
4675
+ this.phase = "finishing";
4676
+ this.progress = Math.max(this.progress, PHASES.finishing.min);
4677
+ }
4678
+ this.stop();
4679
+ }
4662
4680
  incrementProgress() {
4663
4681
  const config = PHASES[this.phase];
4664
4682
  const range = config.max - config.min;
@@ -7232,7 +7250,7 @@ class Worker {
7232
7250
  await this.holdStageCard(card, stageCtx.reason);
7233
7251
  return;
7234
7252
  }
7235
- this.worktreePath = createWorktree(this.config.worktree.basePath, this.config.worktree.baseBranch, this.branchName);
7253
+ this.worktreePath = createWorktree(this.config.worktree.basePath, this.config.worktree.baseBranch, this.branchName, { continueExisting: stageCtx.kind === "run" });
7236
7254
  if (this.aborted)
7237
7255
  return;
7238
7256
  const enriched = {
package/dist/index.js CHANGED
@@ -462,7 +462,7 @@ var init_types = __esm(() => {
462
462
  worktreeGcIntervalMs: 5 * 60000
463
463
  },
464
464
  planning: DEFAULT_PLANNING_CONFIG,
465
- playbooks: { enabled: false, humanStageColumns: [] }
465
+ playbooks: { enabled: true, humanStageColumns: [] }
466
466
  };
467
467
  });
468
468
 
@@ -1979,7 +1979,24 @@ function fetchBaseBranch(repoRoot, baseBranch, attempts = 3, fetchImpl = (root,
1979
1979
  const detail = e?.stderr?.toString?.().trim() || (lastErr instanceof Error ? lastErr.message : String(lastErr));
1980
1980
  throw new WorktreeBaseError(`Could not fetch origin/${baseBranch} after ${attempts} attempts — ` + `refusing to build on a stale base. ${detail}`);
1981
1981
  }
1982
- function createWorktree(basePath, baseBranch, branchName) {
1982
+ function resolveWorktreeStartRef(baseBranch, branchName, continueExisting, branchExistsOnRemote) {
1983
+ if (continueExisting && branchExistsOnRemote()) {
1984
+ return `origin/${branchName}`;
1985
+ }
1986
+ return `origin/${baseBranch}`;
1987
+ }
1988
+ function fetchExistingBranch(repoRoot, branchName) {
1989
+ try {
1990
+ execFileSync3("git", ["fetch", "origin", branchName], {
1991
+ cwd: repoRoot,
1992
+ stdio: "pipe"
1993
+ });
1994
+ return true;
1995
+ } catch {
1996
+ return false;
1997
+ }
1998
+ }
1999
+ function createWorktree(basePath, baseBranch, branchName, opts = {}) {
1983
2000
  const repoRoot = execFileSync3("git", ["rev-parse", "--show-toplevel"], {
1984
2001
  encoding: "utf-8"
1985
2002
  }).trim();
@@ -1995,16 +2012,10 @@ function createWorktree(basePath, baseBranch, branchName) {
1995
2012
  });
1996
2013
  } catch {}
1997
2014
  fetchBaseBranch(repoRoot, baseBranch);
1998
- log.info(TAG5, `Creating worktree: ${worktreeDir} (branch: ${branchName})`);
2015
+ const startRef = resolveWorktreeStartRef(baseBranch, branchName, opts.continueExisting ?? false, () => fetchExistingBranch(repoRoot, branchName));
2016
+ log.info(TAG5, `Creating worktree: ${worktreeDir} (branch: ${branchName}, base: ${startRef})`);
1999
2017
  try {
2000
- execFileSync3("git", [
2001
- "worktree",
2002
- "add",
2003
- "-B",
2004
- branchName,
2005
- worktreeDir,
2006
- `origin/${baseBranch}`
2007
- ], { cwd: repoRoot, stdio: "pipe" });
2018
+ execFileSync3("git", ["worktree", "add", "-B", branchName, worktreeDir, startRef], { cwd: repoRoot, stdio: "pipe" });
2008
2019
  } catch (err) {
2009
2020
  const msg = err instanceof Error ? err.message : String(err);
2010
2021
  log.warn(TAG5, `worktree add failed, attempting forced recovery: ${msg}`);
@@ -2026,14 +2037,7 @@ function createWorktree(basePath, baseBranch, branchName) {
2026
2037
  stdio: "pipe"
2027
2038
  });
2028
2039
  } catch {}
2029
- execFileSync3("git", [
2030
- "worktree",
2031
- "add",
2032
- "-B",
2033
- branchName,
2034
- worktreeDir,
2035
- `origin/${baseBranch}`
2036
- ], { cwd: repoRoot, stdio: "pipe" });
2040
+ execFileSync3("git", ["worktree", "add", "-B", branchName, worktreeDir, startRef], { cwd: repoRoot, stdio: "pipe" });
2037
2041
  }
2038
2042
  log.info(TAG5, "Installing dependencies in worktree...");
2039
2043
  try {
@@ -2306,6 +2310,12 @@ class MergeMonitor {
2306
2310
  log.warn(TAG7, `Failed to update card: ${err instanceof Error ? err.message : err}`);
2307
2311
  }
2308
2312
  }
2313
+ try {
2314
+ await this.client.updateCard(card.id, { assignedAgentId: null });
2315
+ log.info(TAG7, `Cleared agent assignment on #${card.short_id}`);
2316
+ } catch (err) {
2317
+ log.warn(TAG7, `Failed to clear agent assignment on #${card.short_id}: ${err instanceof Error ? err.message : err}`);
2318
+ }
2309
2319
  const branchName = extractBranchFromDescription(card.description);
2310
2320
  if (branchName) {
2311
2321
  try {
@@ -4599,7 +4609,7 @@ class ProgressTracker {
4599
4609
  this.transitionTo("testing");
4600
4610
  }
4601
4611
  } else if (name === "mcp__harmony__harmony_end_agent_session") {
4602
- this.transitionTo("finishing");
4612
+ this.enterFinishingAndStop();
4603
4613
  }
4604
4614
  if (name === "mcp__harmony__harmony_toggle_subtask" && this.subtaskMode) {
4605
4615
  const val = this.extractString(input, "completed");
@@ -4658,6 +4668,14 @@ class ProgressTracker {
4658
4668
  this.lastAction = "";
4659
4669
  this.scheduleUpdate(PHASES[newPhase].label);
4660
4670
  }
4671
+ enterFinishingAndStop() {
4672
+ if (PHASE_ORDER.finishing > PHASE_ORDER[this.phase]) {
4673
+ this.runEventSink?.recordPhaseChanged("finishing", this.phase);
4674
+ this.phase = "finishing";
4675
+ this.progress = Math.max(this.progress, PHASES.finishing.min);
4676
+ }
4677
+ this.stop();
4678
+ }
4661
4679
  incrementProgress() {
4662
4680
  const config = PHASES[this.phase];
4663
4681
  const range = config.max - config.min;
@@ -7231,7 +7249,7 @@ class Worker {
7231
7249
  await this.holdStageCard(card, stageCtx.reason);
7232
7250
  return;
7233
7251
  }
7234
- this.worktreePath = createWorktree(this.config.worktree.basePath, this.config.worktree.baseBranch, this.branchName);
7252
+ this.worktreePath = createWorktree(this.config.worktree.basePath, this.config.worktree.baseBranch, this.branchName, { continueExisting: stageCtx.kind === "run" });
7235
7253
  if (this.aborted)
7236
7254
  return;
7237
7255
  const enriched = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gethmy/agent",
3
- "version": "1.14.0",
3
+ "version": "1.14.2",
4
4
  "description": "Push-based agent daemon for Harmony — watches board assignments and spawns Claude CLI workers",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",