forgehive 0.7.7 → 0.7.9

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
@@ -16,7 +16,7 @@
16
16
  <img src="https://img.shields.io/badge/typescript-5.8-blue" alt="TypeScript">
17
17
  <img src="https://img.shields.io/badge/tests-273%20passing-success" alt="273 tests">
18
18
  <img src="https://img.shields.io/badge/bundle-259KB-lightgrey" alt="259KB bundle">
19
- <img src="https://img.shields.io/badge/license-MIT-green" alt="MIT">
19
+ <img src="https://img.shields.io/badge/license-Elastic%202.0-orange" alt="Elastic License 2.0">
20
20
  </p>
21
21
 
22
22
  ---
@@ -45,9 +45,9 @@ Claude loses all project knowledge between sessions. forgehive solves this by wr
45
45
 
46
46
  ---
47
47
 
48
- ## Status: v0.7.5 — Stable
48
+ ## Status: v0.7.7 — Stable
49
49
 
50
- 273 passing tests back the commands listed below. The v0.7 feature set has been validated end-to-end.
50
+ 297 passing tests back the commands listed below. The v0.7 feature set has been validated end-to-end.
51
51
 
52
52
  **Stable — use with confidence:**
53
53
 
@@ -125,7 +125,7 @@ npm link # makes 'fh' available globally
125
125
  Verify the installation:
126
126
 
127
127
  ```bash
128
- fh --version # should print 0.7.5
128
+ fh --version # should print 0.7.7
129
129
  fh --help # lists all available commands
130
130
  ```
131
131
 
@@ -890,6 +890,8 @@ npm test # node --import tsx/esm --test test/*.test.ts
890
890
 
891
891
  | Version | What's new |
892
892
  |---|---|
893
+ | **0.7.7** | User Guide (`docs/user-guide.md`) included in npm package; Documentation table in README |
894
+ | **0.7.6** | YAML shape fix in `fh docs user`; frontmatter regex fix; 8 new tests for HIGH RISK paths |
893
895
  | **0.7.5** | `fh --version` reads from `package.json` (no longer hardcoded) |
894
896
  | **0.7.4** | Party slash commands installed by `fh init` (`/party`, `/review-party`, `/design-party`, `/full-party`, `/security-party`) |
895
897
  | **0.7.3** | User Docs generation (`fh docs user`, `fh docs api`, `fh docs list`) |
@@ -901,4 +903,4 @@ npm test # node --import tsx/esm --test test/*.test.ts
901
903
 
902
904
  ## License
903
905
 
904
- MIT
906
+ Elastic License 2.0 (ELv2) — kostenlos selbst hosten für den eigenen Betrieb. Weiterverkauf als Managed Service nicht erlaubt.
package/dist/cli.js CHANGED
@@ -2753,6 +2753,8 @@ var init_harness = __esm({
2753
2753
  init_js_yaml();
2754
2754
  import fs31 from "node:fs";
2755
2755
  import path32 from "node:path";
2756
+ import { spawnSync as spawnSync12 } from "node:child_process";
2757
+ import { createInterface } from "node:readline";
2756
2758
 
2757
2759
  // src/scanner.ts
2758
2760
  import fs from "node:fs";
@@ -6550,7 +6552,7 @@ function generateUserGuide(projectRoot2, forgehiveDir2) {
6550
6552
  lines.push("## Overview");
6551
6553
  lines.push("");
6552
6554
  if (memFiles["project.md"]) {
6553
- const content = memFiles["project.md"].replace(/^---[\s\S]*?---\n/, "").trim();
6555
+ const content = memFiles["project.md"].replace(/^---[\s\S]*?---\n?/, "").trim();
6554
6556
  lines.push(content);
6555
6557
  } else {
6556
6558
  lines.push(`${projectName} is a ${lang ?? "software"} application.`);
@@ -6585,7 +6587,7 @@ function generateUserGuide(projectRoot2, forgehiveDir2) {
6585
6587
  }
6586
6588
  lines.push("```");
6587
6589
  lines.push("");
6588
- if (Array.isArray(entryPoints) && entryPoints.length > 0) {
6590
+ if ((lang === "typescript" || lang === "javascript") && Array.isArray(entryPoints) && entryPoints.length > 0) {
6589
6591
  lines.push("## Getting Started");
6590
6592
  lines.push("");
6591
6593
  lines.push("```bash");
@@ -6596,7 +6598,7 @@ function generateUserGuide(projectRoot2, forgehiveDir2) {
6596
6598
  if (memFiles["stack.md"]) {
6597
6599
  lines.push("## Configuration");
6598
6600
  lines.push("");
6599
- const content = memFiles["stack.md"].replace(/^---[\s\S]*?---\n/, "").trim();
6601
+ const content = memFiles["stack.md"].replace(/^---[\s\S]*?---\n?/, "").trim();
6600
6602
  lines.push(content);
6601
6603
  lines.push("");
6602
6604
  }
@@ -6682,7 +6684,7 @@ USAGE
6682
6684
  fh <command> [subcommand] [options]
6683
6685
 
6684
6686
  SETUP
6685
- fh init Set up forgehive in the current project
6687
+ fh init [--yes] Set up forgehive in the current project
6686
6688
  fh confirm Activate capabilities (draft \u2192 confirmed)
6687
6689
  fh rollback Remove forgehive from the project
6688
6690
  fh status Show current project state
@@ -6759,41 +6761,77 @@ function loadClaudeMdBlock() {
6759
6761
  if (!fs31.existsSync(templatePath)) return "## forgehive\n\nSee .forgehive/ for configuration.";
6760
6762
  return fs31.readFileSync(templatePath, "utf8");
6761
6763
  }
6762
- if (command === "init") {
6763
- const forgehiveDirExists = fs31.existsSync(forgehiveDir);
6764
- if (forgehiveDirExists && !rest.includes("--force")) {
6765
- console.log(`\u26A0 .forgehive/ existiert bereits in diesem Projekt.`);
6766
- console.log(` Nutze 'fh init --force' um neu zu initialisieren (\xFCberschreibt capabilities.yaml).`);
6767
- console.log(` Nutze 'fh scan --update' um nur den Scan zu aktualisieren.`);
6768
- process.exit(0);
6764
+ async function promptConfirm(question) {
6765
+ if (!process.stdin.isTTY) return false;
6766
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
6767
+ return new Promise((resolve) => {
6768
+ rl.question(question, (answer) => {
6769
+ rl.close();
6770
+ const a = answer.trim().toLowerCase();
6771
+ resolve(a === "y" || a === "yes" || a === "");
6772
+ });
6773
+ });
6774
+ }
6775
+ function buildCapabilitySummary(ids) {
6776
+ if (ids.length === 0) return " Erkannt: (keine Capabilities)";
6777
+ const lines = [];
6778
+ for (let i = 0; i < ids.length && lines.length < 4; i += 4) {
6779
+ lines.push(" \u2022 " + ids.slice(i, i + 4).join(" \xB7 "));
6769
6780
  }
6770
- console.log("\u{1F50D} Analysiere Projekt...\n");
6771
- const scanResult = scan(projectRoot);
6772
- const tierCount = [1, 2, 3].map((t) => scanResult.signals.filter((s) => s.tier === t).length);
6773
- console.log(` \u2713 ${tierCount[0]} Technologie-Signale erkannt`);
6774
- console.log(` \u2713 ${tierCount[1]} Infrastruktur-Signale erkannt`);
6775
- console.log(` \u2713 ${tierCount[2]} Kontext-Signale erkannt`);
6776
- console.log();
6777
- const capMap = mapSignalsToCapabilities(scanResult);
6778
- const block = loadClaudeMdBlock();
6779
- writeForgehiveDir(projectRoot, scanResult, capMap, block);
6780
- const hash = computeHash(projectRoot);
6781
- fs31.writeFileSync(path32.join(forgehiveDir, ".scan-hash"), hash, "utf8");
6782
- const runtimeDir = path32.join(
6783
- path32.dirname(new URL(import.meta.url).pathname),
6784
- "..",
6785
- "forgehive"
6786
- );
6787
- initForgehiveRuntime(forgehiveDir, runtimeDir);
6788
- console.log("\u2713 .forgehive/ eingerichtet");
6789
- console.log("\u2713 CLAUDE.md aktualisiert\n");
6790
- console.log("Erkannte Capabilities:");
6791
- for (const cap of capMap.confirmed) {
6792
- console.log(` + ${cap.id} (aus ${cap.source})`);
6793
- }
6794
- console.log("\nN\xE4chster Schritt:");
6795
- console.log(" Pr\xFCfe .forgehive/capabilities.yaml und f\xFChre dann aus:");
6796
- console.log(" fh confirm\n");
6781
+ return " Erkannt:\n" + lines.join("\n");
6782
+ }
6783
+ if (command === "init") {
6784
+ (async () => {
6785
+ const gitCheck = spawnSync12("git", ["--version"], { stdio: "ignore" });
6786
+ if (gitCheck.error || gitCheck.status !== 0) {
6787
+ console.error("Fehler: git nicht gefunden.");
6788
+ console.error(" Installation: https://git-scm.com");
6789
+ process.exit(1);
6790
+ }
6791
+ const forgehiveDirExists = fs31.existsSync(forgehiveDir);
6792
+ if (forgehiveDirExists && !rest.includes("--force")) {
6793
+ console.log(`\u26A0 .forgehive/ existiert bereits in diesem Projekt.`);
6794
+ console.log(` Nutze 'fh init --force' um neu zu initialisieren (\xFCberschreibt capabilities.yaml).`);
6795
+ console.log(` Nutze 'fh scan --update' um nur den Scan zu aktualisieren.`);
6796
+ process.exit(0);
6797
+ }
6798
+ console.log("\u{1F50D} Analysiere Projekt...\n");
6799
+ const scanResult = scan(projectRoot);
6800
+ const tierCount = [1, 2, 3].map((t) => scanResult.signals.filter((s) => s.tier === t).length);
6801
+ console.log(` \u2713 ${tierCount[0]} Technologie-Signale erkannt`);
6802
+ console.log(` \u2713 ${tierCount[1]} Infrastruktur-Signale erkannt`);
6803
+ console.log(` \u2713 ${tierCount[2]} Kontext-Signale erkannt`);
6804
+ console.log();
6805
+ const capMap = mapSignalsToCapabilities(scanResult);
6806
+ const block = loadClaudeMdBlock();
6807
+ writeForgehiveDir(projectRoot, scanResult, capMap, block);
6808
+ const hash = computeHash(projectRoot);
6809
+ fs31.writeFileSync(path32.join(forgehiveDir, ".scan-hash"), hash, "utf8");
6810
+ const runtimeDir = path32.join(
6811
+ path32.dirname(new URL(import.meta.url).pathname),
6812
+ "..",
6813
+ "forgehive"
6814
+ );
6815
+ initForgehiveRuntime(forgehiveDir, runtimeDir);
6816
+ console.log("\u2713 forgehive initialisiert\n");
6817
+ console.log(buildCapabilitySummary(capMap.confirmed.map((c) => c.id)));
6818
+ console.log();
6819
+ if (subcommand === "--yes" || rest.includes("--yes")) {
6820
+ confirm(projectRoot);
6821
+ console.log("\u2713 Capabilities best\xE4tigt\n");
6822
+ } else {
6823
+ const ok = await promptConfirm(" Capabilities best\xE4tigen? [Y/n] ");
6824
+ if (ok) {
6825
+ confirm(projectRoot);
6826
+ console.log("\u2713 Capabilities best\xE4tigt\n");
6827
+ } else {
6828
+ console.log(" \xDCberpr\xFCfe .forgehive/capabilities.yaml, dann: fh confirm\n");
6829
+ }
6830
+ }
6831
+ })().catch((err) => {
6832
+ console.error(`Fehler: ${err.message}`);
6833
+ process.exit(1);
6834
+ });
6797
6835
  } else if (command === "confirm") {
6798
6836
  try {
6799
6837
  confirm(projectRoot);
@@ -1,6 +1,6 @@
1
1
  # forgehive — User Guide
2
2
 
3
- > Version 0.7.6 · [npm](https://www.npmjs.com/package/forgehive) · `npm install -g forgehive`
3
+ > Version 0.7.7 · [npm](https://www.npmjs.com/package/forgehive) · `npm install -g forgehive`
4
4
 
5
5
  forgehive (`fh`) gives Claude Code persistent memory about your project. Without it, Claude forgets everything between sessions — your stack, your conventions, your decisions. With it, Claude opens every session already knowing your codebase.
6
6
 
@@ -17,7 +17,7 @@ Requires **Node.js ≥ 18** and **Claude Code** (`claude` CLI). Installs two ali
17
17
  Verify:
18
18
 
19
19
  ```bash
20
- fh --version # prints 0.7.6
20
+ fh --version # prints 0.7.7
21
21
  fh --help # full command reference
22
22
  ```
23
23
 
@@ -106,7 +106,12 @@ The memory files in `.forgehive/memory/` are the most important part of forgehiv
106
106
 
107
107
  ```bash
108
108
  fh docs adr "Use Postgres over MongoDB"
109
- fh memory adr list # list all ADRs
109
+ ```
110
+
111
+ **List all ADRs:**
112
+
113
+ ```bash
114
+ fh memory adr list
110
115
  ```
111
116
 
112
117
  **View all memory:**
@@ -0,0 +1,116 @@
1
+ You are running the ForgeHive refactor workflow.
2
+
3
+ ## Refactor Workflow
4
+
5
+ **Agenten:** Kai (Plan) → Viktor + Sam + Eli (parallel)
6
+
7
+ **Mission:** Strukturierter Code-Umbau — erst verstehen und planen, dann parallel implementieren, testen und dokumentieren.
8
+
9
+ ## Protocol
10
+
11
+ ### Step 0: Scope klären
12
+
13
+ Frage den User:
14
+
15
+ ---
16
+
17
+ **Was soll refactored werden?**
18
+
19
+ Gib eine der folgenden Angaben:
20
+ - **Freie Beschreibung** — z.B. „die Docs-Generierung soll sauberer modularisiert werden"
21
+ - **Dateipfade** — z.B. `src/docs.ts`, `src/cli.ts`
22
+ - **Ziel-Statement** — z.B. „extrahiere generateUserGuide in ein eigenes Modul"
23
+
24
+ ---
25
+
26
+ Wenn der Scope unklar ist: frage nach, bis das Ziel eindeutig ist.
27
+
28
+ Dann führt **Kai** (Principal Engineer) die Ist-Analyse durch:
29
+ 1. Lese alle betroffenen Dateien
30
+ 2. Führe `git diff HEAD` aus (aktuelle uncommitted Änderungen)
31
+ 3. Liste alle Exports der Scope-Dateien und wo sie importiert werden
32
+ 4. Identifiziere Abhängigkeiten (wer importiert was aus den Scope-Dateien)
33
+
34
+ ### Step 1: Refactor-Plan erstellen (Kai)
35
+
36
+ Erstelle folgenden Plan:
37
+
38
+ ```
39
+ ## Refactor-Plan: <Ziel>
40
+
41
+ **Ziel:** <Ein Satz>
42
+
43
+ **Betroffene Dateien:**
44
+ - src/foo.ts → src/foo/index.ts + src/foo/helpers.ts
45
+
46
+ **Bewegte Exports:**
47
+ - `helperFn` aus foo.ts → foo/helpers.ts (re-exportiert aus foo/index.ts)
48
+
49
+ **Breaking Changes:** keine / [Liste]
50
+
51
+ **Risiken:** [z.B. zirkuläre Imports möglich bei X]
52
+
53
+ **Nicht geändert:** [öffentliche API, bestehende Tests für Y, ...]
54
+ ```
55
+
56
+ ⚠️ **USER-APPROVAL GATE** — kein Code ohne explizites OK. Warte auf Bestätigung.
57
+
58
+ ### Step 2: Parallel Party starten
59
+
60
+ Nach Approval:
61
+
62
+ ```bash
63
+ fh party run refactor
64
+ ```
65
+
66
+ Alle drei Agenten erhalten Kai's genehmigten Refactor-Plan als Kontext.
67
+
68
+ **Viktor** (Systems Architect):
69
+ - Implementiert die Änderungen Datei für Datei nach Plan
70
+ - Darf nicht ohne User-Freigabe vom Plan abweichen
71
+ - Meldet unvorhergesehene Abhängigkeiten explizit
72
+
73
+ **Sam** (Quality Architect):
74
+ - Liest bestehende Tests für betroffene Dateien
75
+ - Schreibt neue Tests für umbenannte/verschobene Exports
76
+ - Fixiert Tests die durch den Refactor brechen
77
+ - Führt Testsuit am Ende aus — alle grün?
78
+
79
+ **Eli** (Documentation Architect):
80
+ - Aktualisiert Inline-Kommentare in geänderten Dateien
81
+ - Aktualisiert Referenzen in README und docs/
82
+ - Schreibt CHANGELOG-Eintrag für den Refactor
83
+
84
+ ### Step 3: Verifikation
85
+
86
+ ```bash
87
+ fh party status
88
+ ```
89
+
90
+ Synthesebericht erstellen:
91
+
92
+ ```
93
+ ## Refactor-Abschlussbericht
94
+
95
+ ### Viktor — Implementierung
96
+ [Was wurde umgebaut]
97
+
98
+ ### Sam — Tests
99
+ [Welche Tests angepasst/neu — Teststatus: ✅ alle grün / ⚠️ N fehlgeschlagen]
100
+
101
+ ### Eli — Dokumentation
102
+ [Was wurde aktualisiert]
103
+
104
+ ### Offene Punkte
105
+ [Was blieb unerledigt oder braucht Follow-up]
106
+
107
+ ### Verdict: ✅ Fertig / ⚠️ Offen
108
+ ```
109
+
110
+ Abschlussfrage: **„Soll ich direkt einen Commit erstellen?"**
111
+
112
+ ### Step 4: Cleanup
113
+
114
+ ```bash
115
+ fh party cleanup
116
+ ```
@@ -8,55 +8,74 @@ You are running a Review Party using ForgeHive.
8
8
 
9
9
  ## Protocol
10
10
 
11
- ### Step 1: Launch the party
11
+ ### Step 0: Scope selection
12
+
13
+ **Before doing anything else**, ask the user what to review:
14
+
15
+ ---
16
+
17
+ **Was soll reviewed werden?**
18
+
19
+ 1. **Aktuelle Änderungen** — uncommitted working tree (`git diff HEAD`)
20
+ 2. **Letzter Commit** — `git diff HEAD~1..HEAD`
21
+ 3. **Branch vs main** — alles seit dem Abzweigen (`git diff main...HEAD`)
22
+ 4. **Letzte N Commits** — Anzahl angeben
23
+ 5. **Commit-Range** — z.B. `abc123..def456`
24
+ 6. **Spezifische Dateien** — Dateipfade angeben
25
+ 7. **PR** — PR-Nummer oder Branch-Name angeben
26
+
27
+ ---
28
+
29
+ Wait for the user's answer. Then resolve the scope to a concrete `git diff` command and show the `--stat` output to confirm:
12
30
 
13
- Run:
14
31
  ```bash
15
- fh party run --set review
32
+ # Example for option 3:
33
+ git diff main...HEAD --stat
16
34
  ```
17
35
 
18
- This spins up isolated git worktrees for Kai, Sam, and Eli. Each agent reviews the current diff in parallel.
19
-
20
- ### Step 2: Set the scope
36
+ If the diff is empty or the result looks wrong, say so and ask the user to clarify before proceeding.
21
37
 
22
- Before the party starts, specify what is being reviewed — a branch name, a PR, or a commit range:
38
+ ### Step 1: Launch the party
23
39
 
40
+ Once the scope is confirmed, run:
24
41
  ```bash
25
- git diff main...HEAD --stat # show what changed
42
+ fh party run review
26
43
  ```
27
44
 
28
- Share this with the party so all three agents review the same surface area.
45
+ This spins up isolated git worktrees for Kai, Sam, and Eli.
46
+
47
+ ### Step 2: Dispatch agents in parallel
29
48
 
30
- ### Step 3: Parallel review
49
+ Pass each agent the confirmed scope and diff summary. Each agent works independently:
31
50
 
32
- **Kai** (Principal Engineer) — in his worktree:
33
- - Reviews code quality and correctness
51
+ **Kai** (Principal Engineer):
52
+ - Reviews code quality and correctness within the scoped diff
34
53
  - Flags bugs, logic errors, and anti-patterns
35
54
  - Checks for ambiguous naming, hidden coupling, and missing error handling
36
55
  - Labels findings: `[BUG]`, `[DESIGN]`, `[NIT]`, `[Q]`, `[+]`
37
56
 
38
- **Sam** (Quality Architect) — in his worktree:
57
+ **Sam** (Quality Architect):
39
58
  - Checks test coverage for the changed code
40
59
  - Identifies missing edge cases, error states, and boundary conditions
41
- - Flags paths that are high-risk but untested
42
- - Proposes specific tests for any gaps found
60
+ - Flags high-risk untested paths
61
+ - Proposes specific tests for gaps
43
62
 
44
- **Eli** (Documentation Architect) — in his worktree:
45
- - Checks if README and docs reflect the changes
63
+ **Eli** (Documentation Architect):
64
+ - Checks if README and docs reflect the changes in scope
46
65
  - Flags missing or outdated inline documentation
47
- - Reviews any CHANGELOG entries for accuracy
66
+ - Reviews CHANGELOG entries for accuracy
48
67
  - Checks that public API changes are documented
49
68
 
50
- ### Step 4: Check status
69
+ ### Step 3: Check status
51
70
 
52
- After each agent completes their review:
71
+ After each agent completes:
53
72
  ```bash
54
73
  fh party status
55
74
  ```
56
75
 
57
- ### Step 5: Synthesize findings
76
+ ### Step 4: Synthesize findings
58
77
 
59
- Collect the three reports and merge them into a unified review:
78
+ Merge the three reports into a unified review:
60
79
 
61
80
  1. **Blocking issues** — anything from Kai or Sam that must be fixed before merge
62
81
  2. **Test gaps** — Sam's missing coverage items
@@ -65,7 +84,7 @@ Collect the three reports and merge them into a unified review:
65
84
 
66
85
  Present the synthesized report to the user and ask: **"Soll ich die Blocking Issues direkt fixen?"**
67
86
 
68
- ### Step 6: Cleanup
87
+ ### Step 5: Cleanup
69
88
 
70
89
  ```bash
71
90
  fh party cleanup
@@ -41,3 +41,11 @@ sets:
41
41
  models:
42
42
  vera: claude-opus-4-7
43
43
  sam: claude-sonnet-4-6
44
+ refactor:
45
+ agents: [viktor, sam, eli]
46
+ trigger: "/fh-refactor"
47
+ description: "Refactor — Implementierung + Tests + Doku parallel"
48
+ models:
49
+ viktor: claude-opus-4-7
50
+ sam: claude-sonnet-4-6
51
+ eli: claude-sonnet-4-6
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "forgehive",
3
- "version": "0.7.7",
3
+ "version": "0.7.9",
4
4
  "description": "Context-aware AI development environment — one binary, your stack.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -9,7 +9,7 @@
9
9
  },
10
10
  "files": [
11
11
  "dist/",
12
- "docs/",
12
+ "docs/user-guide.md",
13
13
  "forgehive/"
14
14
  ],
15
15
  "keywords": [
@@ -22,6 +22,7 @@
22
22
  "forgehive",
23
23
  "development"
24
24
  ],
25
+ "license": "Elastic-2.0",
25
26
  "engines": {
26
27
  "node": ">=18"
27
28
  },