gnhf 0.1.37 → 0.1.39

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
@@ -159,6 +159,7 @@ Pass `--current-branch` to run on the branch you are already on instead of creat
159
159
  Pass `--push` to push the current branch after each successful iteration.
160
160
  Together, `--current-branch --push` is useful for loose projects where you want a deployed or locally watched branch to update throughout the run.
161
161
 
162
+ - Re-running the same prompt with `--current-branch` resumes the existing `.gnhf/runs/<runId>/` history on a clean working tree and continues iteration numbering.
162
163
  - Push failures abort the run after preserving the successful local commit.
163
164
  - gnhf never force-pushes or auto-pulls for this mode.
164
165
  - `--push` also works with the default `gnhf/` branch mode and sets `origin` as the upstream when needed.
@@ -276,7 +277,7 @@ You can also pass a raw custom ACP server command directly as a quoted `acp:` sp
276
277
 
277
278
  - Omit it to keep the default `gnhf <iteration>: <summary>` format.
278
279
  - Set `preset: conventional` to ask the agent for `type` and optional `scope`, then commit as `type(scope): summary` for semantic-release style workflows. Valid types are `build`, `ci`, `docs`, `feat`, `fix`, `perf`, `refactor`, `test`, and `chore`; invalid or missing types fall back to `chore`, and empty scopes are omitted.
279
- - The resolved commit-message convention is saved per run, so resuming a `gnhf/` branch keeps the original subject format even if `config.yml` changes later.
280
+ - The resolved commit-message convention is saved per run, so resuming keeps the original subject format even if `config.yml` changes later.
280
281
 
281
282
  ### Custom Agent Paths
282
283
 
package/dist/cli.mjs CHANGED
@@ -17702,6 +17702,18 @@ function meteorCountForFrequency(frequency) {
17702
17702
  function meteorsStartingBefore(meteors, rowOffset, maxStartRow) {
17703
17703
  return meteors.filter((meteor) => rowOffset + meteor.y < maxStartRow);
17704
17704
  }
17705
+ function generateSideMeteorShower(terminalWidth, sideWidth, height, count, seed) {
17706
+ if (sideWidth <= 0 || height <= 0 || count <= 0) return [];
17707
+ const leftCount = Math.max(1, Math.ceil(count / 2));
17708
+ const rightCount = count - leftCount;
17709
+ const leftMeteors = generateMeteorShower(sideWidth, height, leftCount, seed);
17710
+ const rightXOffset = terminalWidth - sideWidth;
17711
+ const rightMeteors = generateMeteorShower(sideWidth, height, rightCount, seed + 1).map((meteor) => ({
17712
+ ...meteor,
17713
+ x: meteor.x + rightXOffset
17714
+ }));
17715
+ return [...leftMeteors, ...rightMeteors];
17716
+ }
17705
17717
  function placeStarsInCells(cells, stars, row, xMin, xMax, xOffset, now) {
17706
17718
  for (const star of stars) {
17707
17719
  if (star.y !== row || star.x < xMin || star.x >= xMax) continue;
@@ -17900,6 +17912,7 @@ var Renderer = class {
17900
17912
  sideStars = [];
17901
17913
  topMeteors = [];
17902
17914
  bottomMeteors = [];
17915
+ sideMeteors = [];
17903
17916
  cachedWidth = 0;
17904
17917
  cachedHeight = 0;
17905
17918
  meteorFrequency;
@@ -17995,6 +18008,7 @@ var Renderer = class {
17995
18008
  this.topStars = generateStarField(w, h, STAR_DENSITY, this.seedTop).map((s) => shrinkBig(s, s.y >= topHeight - proximityRows));
17996
18009
  this.bottomStars = generateStarField(w, h, STAR_DENSITY, this.seedBottom).map((s) => shrinkBig(s, s.y < proximityRows));
17997
18010
  this.sideStars = generateStarField(w, Math.max(BASE_CONTENT_ROWS, availableHeight), STAR_DENSITY, this.seedSide);
18011
+ this.sideMeteors = generateSideMeteorShower(w, Math.max(0, Math.floor((w - CONTENT_WIDTH) / 2)), Math.min(BASE_CONTENT_ROWS, availableHeight), meteorCountForFrequency(this.meteorFrequency), this.seedSide + METEOR_SEED_OFFSET);
17998
18012
  this.topMeteors = generateMeteorShower(w, topHeight, topHeight > 0 ? meteorCountForFrequency(this.meteorFrequency) : 0, this.seedTop + METEOR_SEED_OFFSET);
17999
18013
  this.bottomMeteors = generateMeteorShower(w, bottomHeight, bottomHeight > 0 ? meteorCountForFrequency(this.meteorFrequency) : 0, this.seedBottom + METEOR_SEED_OFFSET);
18000
18014
  return true;
@@ -18007,7 +18021,7 @@ var Renderer = class {
18007
18021
  const h = process$1.stdout.rows || 24;
18008
18022
  const resized = this.ensureStarFields(w, h);
18009
18023
  this.updateTerminalTitle(now);
18010
- const nextCells = buildFrameCells(this.prompt, this.agentName, this.state, this.topStars, this.bottomStars, this.sideStars, now, w, h, this.topMeteors, this.bottomMeteors);
18024
+ const nextCells = buildFrameCells(this.prompt, this.agentName, this.state, this.topStars, this.bottomStars, this.sideStars, now, w, h, this.topMeteors, this.bottomMeteors, this.sideMeteors);
18011
18025
  if (this.isFirstFrame || resized) {
18012
18026
  process$1.stdout.write("\x1B[H" + nextCells.map(rowToString).join("\n"));
18013
18027
  this.isFirstFrame = false;
@@ -18138,10 +18152,19 @@ function initializeNewBranch(prompt, cwd, schemaOptions) {
18138
18152
  const runId = createBranchWithSuffix(slugifyPrompt(prompt), cwd).split("/")[1];
18139
18153
  return setupRun(runId, prompt, baseCommit, cwd, schemaOptions);
18140
18154
  }
18155
+ function promptRunId(prompt) {
18156
+ return slugifyPrompt(prompt).split("/")[1];
18157
+ }
18158
+ function resumeCurrentBranchRun(prompt, cwd, schemaOptions) {
18159
+ const runId = promptRunId(prompt);
18160
+ if (!existsSync(join(cwd, ".gnhf", "runs", runId))) return null;
18161
+ ensureCleanWorkingTree(cwd);
18162
+ return resumeRun(runId, cwd, schemaOptions);
18163
+ }
18141
18164
  function initializeCurrentBranchRun(prompt, cwd, schemaOptions) {
18142
18165
  ensureCleanWorkingTree(cwd);
18143
18166
  const baseCommit = getHeadCommit(cwd);
18144
- return setupRun(createRunIdWithSuffix(slugifyPrompt(prompt).split("/")[1], cwd), prompt, baseCommit, cwd, schemaOptions);
18167
+ return setupRun(createRunIdWithSuffix(promptRunId(prompt), cwd), prompt, baseCommit, cwd, schemaOptions);
18145
18168
  }
18146
18169
  function branchNameWithSuffix(branchName, suffix) {
18147
18170
  return suffix === 0 ? branchName : `${branchName}-${suffix}`;
@@ -18443,7 +18466,14 @@ program.name("gnhf").description("Before I go to bed, I tell my agents: good nig
18443
18466
  program.help();
18444
18467
  return;
18445
18468
  }
18446
- runInfo = initializeCurrentBranchRun(prompt, cwd, schemaOptions);
18469
+ const existing = resumeCurrentBranchRun(prompt, cwd, buildResumeSchemaOptions(options.stopWhen, effectiveCommitMessage));
18470
+ if (existing) {
18471
+ runInfo = existing;
18472
+ effectiveStopWhen = existing.stopWhen;
18473
+ effectiveCommitMessage = existing.commitMessage;
18474
+ schemaOptions = buildSchemaOptions(effectiveStopWhen, effectiveCommitMessage);
18475
+ startIteration = getLastIterationNumber(existing);
18476
+ } else runInfo = initializeCurrentBranchRun(prompt, cwd, schemaOptions);
18447
18477
  } else if (onGnhfBranch) {
18448
18478
  const existingRunId = currentBranch.slice(5);
18449
18479
  const existingMetadata = peekRunMetadata(existingRunId, cwd);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gnhf",
3
- "version": "0.1.37",
3
+ "version": "0.1.39",
4
4
  "description": "Before I go to bed, I tell my agents: good night, have fun",
5
5
  "type": "module",
6
6
  "bin": {