gnhf 0.1.0 → 0.1.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.
- package/README.md +12 -9
- package/dist/cli.mjs +30 -17
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
<
|
|
1
|
+
<p align="center">Before I go to bed, I tell my agents:</p>
|
|
2
|
+
<h1 align="center">good night, have fun</h1>
|
|
3
|
+
|
|
2
4
|
<p align="center">
|
|
3
5
|
<a href="https://www.npmjs.com/package/gnhf"
|
|
4
6
|
><img
|
|
@@ -33,14 +35,15 @@
|
|
|
33
35
|
/></a>
|
|
34
36
|
</p>
|
|
35
37
|
|
|
36
|
-
<
|
|
37
|
-
|
|
38
|
-
|
|
38
|
+
<p align="center">
|
|
39
|
+
<img src="docs/splash.png" alt="gnhf — Good Night, Have Fun" width="800">
|
|
40
|
+
</p>
|
|
39
41
|
|
|
40
|
-
gnhf is
|
|
42
|
+
gnhf is a [ralph loop](https://ghuntley.com/ralph/) orchestrator that keeps your agents running while you sleep — each iteration makes one small, committed, documented change towards an objective.
|
|
43
|
+
You wake up to a branch full of clean work and a log of everything that happened.
|
|
41
44
|
|
|
42
|
-
- **
|
|
43
|
-
- **
|
|
45
|
+
- **Dead simple** — one command starts an autonomous loop that runs until you Ctrl+C
|
|
46
|
+
- **Autonomous by design** — each iteration is committed on success, rolled back on failure, with exponential backoff and auto-abort after consecutive failures
|
|
44
47
|
- **Agent-agnostic** — works with Claude Code or Codex out of the box
|
|
45
48
|
|
|
46
49
|
## Quick Start
|
|
@@ -105,7 +108,7 @@ npm link
|
|
|
105
108
|
│ ┌──────────┘ │
|
|
106
109
|
▼ ▼ │
|
|
107
110
|
┌────────────┐ yes ┌──────────┐ │
|
|
108
|
-
│
|
|
111
|
+
│ 3 consec. ├─────────►│ abort │ │
|
|
109
112
|
│ failures? │ └──────────┘ │
|
|
110
113
|
└─────┬──────┘ │
|
|
111
114
|
no │ │
|
|
@@ -140,7 +143,7 @@ Config lives at `~/.gnhf/config.yml`:
|
|
|
140
143
|
agent: claude
|
|
141
144
|
|
|
142
145
|
# Abort after this many consecutive failures
|
|
143
|
-
maxConsecutiveFailures:
|
|
146
|
+
maxConsecutiveFailures: 3
|
|
144
147
|
```
|
|
145
148
|
|
|
146
149
|
CLI flags override config file values.
|
package/dist/cli.mjs
CHANGED
|
@@ -12,7 +12,7 @@ import { createHash } from "node:crypto";
|
|
|
12
12
|
//#region src/core/config.ts
|
|
13
13
|
const DEFAULT_CONFIG = {
|
|
14
14
|
agent: "claude",
|
|
15
|
-
maxConsecutiveFailures:
|
|
15
|
+
maxConsecutiveFailures: 3
|
|
16
16
|
};
|
|
17
17
|
function loadConfig(overrides) {
|
|
18
18
|
const configPath = join(homedir(), ".gnhf", "config.yml");
|
|
@@ -401,11 +401,18 @@ This is iteration ${params.n} of an ongoing loop to fully accomplish the objecti
|
|
|
401
401
|
## Instructions
|
|
402
402
|
|
|
403
403
|
1. Read .gnhf/runs/${params.runId}/notes.md first to understand what has been done in previous iterations.
|
|
404
|
-
2. Focus on
|
|
405
|
-
3.
|
|
404
|
+
2. Focus on the next smallest logical unit of work that's individually testable and would make incremental progress towards the objective - that's the scope of this iteration.
|
|
405
|
+
3. If you made code changes, run build/tests/linters/formatters if available to validate your work.
|
|
406
406
|
4. Do NOT make any git commits. Commits will be handled automatically by the gnhf orchestrator.
|
|
407
407
|
5. When you are done, respond with a JSON object according to the provided schema.
|
|
408
408
|
|
|
409
|
+
## Output
|
|
410
|
+
|
|
411
|
+
- success: whether you were able to complete your iteration. set to false only if something made it impossible for you to do your work
|
|
412
|
+
- summary: a concise one-sentence summary of the accomplishment in this iteration
|
|
413
|
+
- key_changes_made: an array of descriptions for key changes you made. don't group this by file - group by logical units of work. don't describe activities - describe material outcomes
|
|
414
|
+
- key_learnings: an array of new learnings that were surprising and weren't captured by previous notes
|
|
415
|
+
|
|
409
416
|
## Objective
|
|
410
417
|
|
|
411
418
|
${params.prompt}`;
|
|
@@ -767,24 +774,30 @@ function formatTokens(count) {
|
|
|
767
774
|
//#region src/utils/wordwrap.ts
|
|
768
775
|
function wordWrap(text, width, maxLines) {
|
|
769
776
|
if (!text) return [];
|
|
770
|
-
const words = text.split(/\s+/);
|
|
771
777
|
const lines = [];
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
if (
|
|
775
|
-
|
|
776
|
-
lines.push(current);
|
|
777
|
-
current = "";
|
|
778
|
-
}
|
|
779
|
-
for (let i = 0; i < word.length; i += width) lines.push(word.slice(i, i + width));
|
|
778
|
+
for (const paragraph of text.split("\n")) {
|
|
779
|
+
const words = paragraph.split(/\s+/).filter(Boolean);
|
|
780
|
+
if (words.length === 0) {
|
|
781
|
+
lines.push("");
|
|
780
782
|
continue;
|
|
781
783
|
}
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
784
|
+
let current = "";
|
|
785
|
+
for (const word of words) {
|
|
786
|
+
if (word.length > width) {
|
|
787
|
+
if (current) {
|
|
788
|
+
lines.push(current);
|
|
789
|
+
current = "";
|
|
790
|
+
}
|
|
791
|
+
for (let i = 0; i < word.length; i += width) lines.push(word.slice(i, i + width));
|
|
792
|
+
continue;
|
|
793
|
+
}
|
|
794
|
+
if (current && current.length + 1 + word.length > width) {
|
|
795
|
+
lines.push(current);
|
|
796
|
+
current = word;
|
|
797
|
+
} else current = current ? current + " " + word : word;
|
|
798
|
+
}
|
|
799
|
+
if (current) lines.push(current);
|
|
786
800
|
}
|
|
787
|
-
if (current) lines.push(current);
|
|
788
801
|
if (maxLines && lines.length > maxLines) {
|
|
789
802
|
const capped = lines.slice(0, maxLines);
|
|
790
803
|
const last = capped[maxLines - 1];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gnhf",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Before I go to bed, I tell my agents: good night, have fun",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -40,6 +40,10 @@
|
|
|
40
40
|
"publishConfig": {
|
|
41
41
|
"access": "public"
|
|
42
42
|
},
|
|
43
|
+
"repository": {
|
|
44
|
+
"type": "git",
|
|
45
|
+
"url": "https://github.com/kunchenguid/gnhf"
|
|
46
|
+
},
|
|
43
47
|
"engines": {
|
|
44
48
|
"node": ">=20"
|
|
45
49
|
}
|