forgehive 0.7.4 → 0.7.6
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 +38 -8
- package/dist/cli.js +40 -17
- package/forgehive/commands/fh-docs.md +16 -6
- package/forgehive/commands/full-party.md +9 -4
- package/package.json +20 -6
package/README.md
CHANGED
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
<p align="center">
|
|
15
15
|
<img src="https://img.shields.io/badge/node-%3E%3D18-brightgreen" alt="Node.js ≥ 18">
|
|
16
16
|
<img src="https://img.shields.io/badge/typescript-5.8-blue" alt="TypeScript">
|
|
17
|
-
<img src="https://img.shields.io/badge/tests-
|
|
18
|
-
<img src="https://img.shields.io/badge/bundle-
|
|
17
|
+
<img src="https://img.shields.io/badge/tests-273%20passing-success" alt="273 tests">
|
|
18
|
+
<img src="https://img.shields.io/badge/bundle-259KB-lightgrey" alt="259KB bundle">
|
|
19
19
|
<img src="https://img.shields.io/badge/license-MIT-green" alt="MIT">
|
|
20
20
|
</p>
|
|
21
21
|
|
|
@@ -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 — Stable
|
|
48
|
+
## Status: v0.7.5 — Stable
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
273 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
|
|
|
@@ -109,14 +109,14 @@ This makes both `fh` and `forgehive` available globally.
|
|
|
109
109
|
git clone https://github.com/matharnica/forgehive
|
|
110
110
|
cd forgehive
|
|
111
111
|
npm install
|
|
112
|
-
npm run build # compiles to dist/cli.js (~
|
|
112
|
+
npm run build # compiles to dist/cli.js (~259 KB)
|
|
113
113
|
npm link # makes 'fh' available globally
|
|
114
114
|
```
|
|
115
115
|
|
|
116
116
|
Verify the installation:
|
|
117
117
|
|
|
118
118
|
```bash
|
|
119
|
-
fh --version # should print 0.7.
|
|
119
|
+
fh --version # should print 0.7.5
|
|
120
120
|
fh --help # lists all available commands
|
|
121
121
|
```
|
|
122
122
|
|
|
@@ -332,6 +332,23 @@ Parses conventional commits (`feat:`, `fix:`, `chore:`, `docs:`, etc.) and group
|
|
|
332
332
|
|
|
333
333
|
---
|
|
334
334
|
|
|
335
|
+
### Docs
|
|
336
|
+
|
|
337
|
+
```bash
|
|
338
|
+
fh docs # list existing documentation
|
|
339
|
+
fh docs user [--output path] # generate user guide → docs/user-guide.md
|
|
340
|
+
fh docs api [--output path] # generate API reference → docs/api.md
|
|
341
|
+
fh docs onboard [--output path] # generate onboarding doc → ONBOARDING.md
|
|
342
|
+
fh docs changelog [--since tag] [--output path] # generate changelog → CHANGELOG.md
|
|
343
|
+
fh docs adr "<title>" # create Architecture Decision Record
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
Generates documentation from your project's stack, memory, and git history. Each subcommand writes to a default path inside `docs/` (created if missing) or to the path given via `--output`. `fh docs user` and `fh docs api` write to `docs/user-guide.md` and `docs/api.md` respectively. `fh docs adr` creates a numbered ADR file in `.forgehive/memory/adrs/`.
|
|
347
|
+
|
|
348
|
+
> `fh docs onboard` and `fh onboard` both generate onboarding documentation — they share the same generator. `fh docs onboard` allows specifying a custom `--output` path; `fh onboard` writes to stdout by default.
|
|
349
|
+
|
|
350
|
+
---
|
|
351
|
+
|
|
335
352
|
### Developer Metrics
|
|
336
353
|
|
|
337
354
|
```bash
|
|
@@ -847,9 +864,9 @@ Global credential store (chmod 600). Managed exclusively via `fh mcp auth` comma
|
|
|
847
864
|
|---|---|
|
|
848
865
|
| Runtime | Node.js ≥ 18, ESM |
|
|
849
866
|
| Language | TypeScript |
|
|
850
|
-
| Build | esbuild -> `dist/cli.js` (~
|
|
867
|
+
| Build | esbuild -> `dist/cli.js` (~259 KB, single bundle) |
|
|
851
868
|
| Type check | `tsc --noEmit` |
|
|
852
|
-
| Tests | `node:test` (native) + tsx ESM loader,
|
|
869
|
+
| Tests | `node:test` (native) + tsx ESM loader, 273 tests |
|
|
853
870
|
| Dependencies | `js-yaml` (sole runtime dependency) |
|
|
854
871
|
|
|
855
872
|
```bash
|
|
@@ -860,6 +877,19 @@ npm test # node --import tsx/esm --test test/*.test.ts
|
|
|
860
877
|
|
|
861
878
|
---
|
|
862
879
|
|
|
880
|
+
## Changelog
|
|
881
|
+
|
|
882
|
+
| Version | What's new |
|
|
883
|
+
|---|---|
|
|
884
|
+
| **0.7.5** | `fh --version` reads from `package.json` (no longer hardcoded) |
|
|
885
|
+
| **0.7.4** | Party slash commands installed by `fh init` (`/party`, `/review-party`, `/design-party`, `/full-party`, `/security-party`) |
|
|
886
|
+
| **0.7.3** | User Docs generation (`fh docs user`, `fh docs api`, `fh docs list`) |
|
|
887
|
+
| **0.7.2** | `fh --help`, `fh init --force`, `fh story sprint`, `fh velocity show` fixes |
|
|
888
|
+
| **0.7.1** | Story Cards, Epics, Velocity tracking |
|
|
889
|
+
| **0.7.0** | CI, Map, Onboard, Changelog, Metrics, Sync, Background agents |
|
|
890
|
+
|
|
891
|
+
---
|
|
892
|
+
|
|
863
893
|
## License
|
|
864
894
|
|
|
865
895
|
MIT
|
package/dist/cli.js
CHANGED
|
@@ -5915,10 +5915,10 @@ function groupByType(commits) {
|
|
|
5915
5915
|
}
|
|
5916
5916
|
return groups;
|
|
5917
5917
|
}
|
|
5918
|
-
function formatChangelog(commits,
|
|
5918
|
+
function formatChangelog(commits, version2) {
|
|
5919
5919
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
5920
5920
|
const lines = [];
|
|
5921
|
-
lines.push(`## [${
|
|
5921
|
+
lines.push(`## [${version2}] \u2014 ${date}`);
|
|
5922
5922
|
lines.push("");
|
|
5923
5923
|
if (commits.length === 0) {
|
|
5924
5924
|
lines.push("No changes.");
|
|
@@ -6460,7 +6460,7 @@ import fs30 from "node:fs";
|
|
|
6460
6460
|
import path31 from "node:path";
|
|
6461
6461
|
import { spawnSync as spawnSync11 } from "node:child_process";
|
|
6462
6462
|
var SOURCE_EXTS = [".ts", ".tsx", ".js", ".jsx", ".py", ".go"];
|
|
6463
|
-
var IGNORE_DIRS3 = ["node_modules", ".git", "dist", ".forgehive", "coverage", ".next", "build", "test"];
|
|
6463
|
+
var IGNORE_DIRS3 = ["node_modules", ".git", "dist", ".forgehive", "coverage", ".next", "build", "test", "__tests__", "spec"];
|
|
6464
6464
|
var EXPORT_PATTERNS = [
|
|
6465
6465
|
/^export\s+(?:async\s+)?function\s+(\w+)/gm,
|
|
6466
6466
|
/^export\s+(?:const|let|var)\s+(\w+)/gm,
|
|
@@ -6476,6 +6476,27 @@ function readCapabilities2(forgehiveDir2) {
|
|
|
6476
6476
|
return {};
|
|
6477
6477
|
}
|
|
6478
6478
|
}
|
|
6479
|
+
function extractCapabilityInfo(caps) {
|
|
6480
|
+
if (typeof caps.language === "string") {
|
|
6481
|
+
return {
|
|
6482
|
+
language: caps.language,
|
|
6483
|
+
packageManager: typeof caps.packageManager === "string" ? caps.packageManager : void 0,
|
|
6484
|
+
entryPoints: Array.isArray(caps.entryPoints) ? caps.entryPoints : void 0
|
|
6485
|
+
};
|
|
6486
|
+
}
|
|
6487
|
+
const confirmed = caps.capabilities?.confirmed ?? [];
|
|
6488
|
+
const ids = confirmed.map((c) => c.id ?? "").filter(Boolean);
|
|
6489
|
+
let language;
|
|
6490
|
+
if (ids.includes("typescript")) language = "typescript";
|
|
6491
|
+
else if (ids.includes("javascript")) language = "javascript";
|
|
6492
|
+
else if (ids.includes("python")) language = "python";
|
|
6493
|
+
else if (ids.includes("go")) language = "go";
|
|
6494
|
+
let packageManager;
|
|
6495
|
+
if (ids.includes("pnpm")) packageManager = "pnpm";
|
|
6496
|
+
else if (ids.includes("yarn")) packageManager = "yarn";
|
|
6497
|
+
else if (ids.includes("npm")) packageManager = "npm";
|
|
6498
|
+
return { language, packageManager };
|
|
6499
|
+
}
|
|
6479
6500
|
function readMemoryFiles2(forgehiveDir2) {
|
|
6480
6501
|
const memDir = path31.join(forgehiveDir2, "memory");
|
|
6481
6502
|
if (!fs30.existsSync(memDir)) return {};
|
|
@@ -6518,6 +6539,7 @@ function walkSourceFiles(dir) {
|
|
|
6518
6539
|
function generateUserGuide(projectRoot2, forgehiveDir2) {
|
|
6519
6540
|
const projectName = path31.basename(projectRoot2);
|
|
6520
6541
|
const caps = readCapabilities2(forgehiveDir2);
|
|
6542
|
+
const { language: lang, packageManager, entryPoints } = extractCapabilityInfo(caps);
|
|
6521
6543
|
const memFiles = readMemoryFiles2(forgehiveDir2);
|
|
6522
6544
|
const commits = getRecentCommits2(projectRoot2);
|
|
6523
6545
|
const lines = [];
|
|
@@ -6528,16 +6550,15 @@ function generateUserGuide(projectRoot2, forgehiveDir2) {
|
|
|
6528
6550
|
lines.push("## Overview");
|
|
6529
6551
|
lines.push("");
|
|
6530
6552
|
if (memFiles["project.md"]) {
|
|
6531
|
-
const content = memFiles["project.md"].replace(/^---[\s\S]*?---\n
|
|
6553
|
+
const content = memFiles["project.md"].replace(/^---[\s\S]*?---\n/, "").trim();
|
|
6532
6554
|
lines.push(content);
|
|
6533
6555
|
} else {
|
|
6534
|
-
lines.push(`${projectName} is a ${
|
|
6556
|
+
lines.push(`${projectName} is a ${lang ?? "software"} application.`);
|
|
6535
6557
|
}
|
|
6536
6558
|
lines.push("");
|
|
6537
6559
|
lines.push("## Requirements");
|
|
6538
6560
|
lines.push("");
|
|
6539
|
-
const pm =
|
|
6540
|
-
const lang = caps.language;
|
|
6561
|
+
const pm = packageManager ?? "npm";
|
|
6541
6562
|
if (lang === "typescript" || lang === "javascript") {
|
|
6542
6563
|
lines.push("- **Node.js** \u2265 18");
|
|
6543
6564
|
lines.push(`- **${pm}** (package manager)`);
|
|
@@ -6564,7 +6585,6 @@ function generateUserGuide(projectRoot2, forgehiveDir2) {
|
|
|
6564
6585
|
}
|
|
6565
6586
|
lines.push("```");
|
|
6566
6587
|
lines.push("");
|
|
6567
|
-
const entryPoints = caps.entryPoints;
|
|
6568
6588
|
if (Array.isArray(entryPoints) && entryPoints.length > 0) {
|
|
6569
6589
|
lines.push("## Getting Started");
|
|
6570
6590
|
lines.push("");
|
|
@@ -6576,7 +6596,7 @@ function generateUserGuide(projectRoot2, forgehiveDir2) {
|
|
|
6576
6596
|
if (memFiles["stack.md"]) {
|
|
6577
6597
|
lines.push("## Configuration");
|
|
6578
6598
|
lines.push("");
|
|
6579
|
-
const content = memFiles["stack.md"].replace(/^---[\s\S]*?---\n
|
|
6599
|
+
const content = memFiles["stack.md"].replace(/^---[\s\S]*?---\n/, "").trim();
|
|
6580
6600
|
lines.push(content);
|
|
6581
6601
|
lines.push("");
|
|
6582
6602
|
}
|
|
@@ -6644,16 +6664,19 @@ function listExistingDocs(projectRoot2) {
|
|
|
6644
6664
|
}
|
|
6645
6665
|
|
|
6646
6666
|
// src/cli.ts
|
|
6667
|
+
import { createRequire } from "node:module";
|
|
6668
|
+
var require2 = createRequire(import.meta.url);
|
|
6669
|
+
var { version } = require2("../package.json");
|
|
6647
6670
|
var [, , command, subcommand, ...rest] = process.argv;
|
|
6648
6671
|
var projectRoot = process.cwd();
|
|
6649
6672
|
var forgehiveDir = path32.join(projectRoot, ".forgehive");
|
|
6650
6673
|
if (command === "--version" || command === "-v") {
|
|
6651
|
-
console.log(
|
|
6674
|
+
console.log(version);
|
|
6652
6675
|
process.exit(0);
|
|
6653
6676
|
}
|
|
6654
6677
|
if (command === "--help" || command === "-h" || command === "help") {
|
|
6655
6678
|
console.log(`
|
|
6656
|
-
forgehive
|
|
6679
|
+
forgehive v${version} \u2014 Context-aware AI development environment
|
|
6657
6680
|
|
|
6658
6681
|
USAGE
|
|
6659
6682
|
fh <command> [subcommand] [options]
|
|
@@ -7440,16 +7463,16 @@ Setze diese Umgebungsvariablen:`);
|
|
|
7440
7463
|
const since = sinceArg ?? getLatestTag(projectRoot) ?? void 0;
|
|
7441
7464
|
const rawLog = getGitLogSince(projectRoot, since);
|
|
7442
7465
|
const commits = parseGitLog(rawLog);
|
|
7443
|
-
let
|
|
7466
|
+
let version2 = "unreleased";
|
|
7444
7467
|
try {
|
|
7445
7468
|
const pkgPath = path32.join(projectRoot, "package.json");
|
|
7446
7469
|
if (fs31.existsSync(pkgPath)) {
|
|
7447
7470
|
const pkg = JSON.parse(fs31.readFileSync(pkgPath, "utf8").replace(/^\s*\/\/.*$/gm, ""));
|
|
7448
|
-
|
|
7471
|
+
version2 = pkg.version ?? "unreleased";
|
|
7449
7472
|
}
|
|
7450
7473
|
} catch {
|
|
7451
7474
|
}
|
|
7452
|
-
const md = formatChangelog(commits,
|
|
7475
|
+
const md = formatChangelog(commits, version2);
|
|
7453
7476
|
const outputPath = outputArg ?? path32.join(projectRoot, "CHANGELOG.md");
|
|
7454
7477
|
let existing = "";
|
|
7455
7478
|
if (fs31.existsSync(outputPath)) existing = fs31.readFileSync(outputPath, "utf8");
|
|
@@ -7662,8 +7685,8 @@ Setze diese Umgebungsvariablen:`);
|
|
|
7662
7685
|
pkg = JSON.parse(fs31.readFileSync(path32.join(projectRoot, "package.json"), "utf8"));
|
|
7663
7686
|
} catch {
|
|
7664
7687
|
}
|
|
7665
|
-
const
|
|
7666
|
-
const md = formatChangelog(commits,
|
|
7688
|
+
const pkgVersion = pkg.version ?? "unreleased";
|
|
7689
|
+
const md = formatChangelog(commits, pkgVersion);
|
|
7667
7690
|
const outputPath = outputArg ?? path32.join(projectRoot, "CHANGELOG.md");
|
|
7668
7691
|
let existing = "";
|
|
7669
7692
|
if (fs31.existsSync(outputPath)) existing = fs31.readFileSync(outputPath, "utf8");
|
|
@@ -7677,7 +7700,7 @@ Setze diese Umgebungsvariablen:`);
|
|
|
7677
7700
|
}
|
|
7678
7701
|
const adrsDir = path32.join(forgehiveDir, "memory", "adrs");
|
|
7679
7702
|
fs31.mkdirSync(adrsDir, { recursive: true });
|
|
7680
|
-
const existing = fs31.
|
|
7703
|
+
const existing = fs31.readdirSync(adrsDir).filter((f) => f.endsWith(".md")).length;
|
|
7681
7704
|
const adrId = String(existing + 1).padStart(4, "0");
|
|
7682
7705
|
const slug = title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
7683
7706
|
const filename = `${adrId}-${slug}.md`;
|
|
@@ -20,12 +20,22 @@ For interactive generation with editing, continue below.
|
|
|
20
20
|
Ask the user: **"Was soll ich dokumentieren?"**
|
|
21
21
|
|
|
22
22
|
Options:
|
|
23
|
-
1. **
|
|
24
|
-
2. **
|
|
25
|
-
3. **
|
|
26
|
-
4. **
|
|
27
|
-
5. **
|
|
28
|
-
6. **
|
|
23
|
+
1. **User Guide** — write or update `docs/user-guide.md` for end users
|
|
24
|
+
2. **README update** — reflect recent features/changes
|
|
25
|
+
3. **API reference** — document endpoints or exported functions (`docs/api.md`)
|
|
26
|
+
4. **CHANGELOG** — run `fh docs changelog` and review the output
|
|
27
|
+
5. **ADR** — document an architecture decision (`fh docs adr "<title>"`)
|
|
28
|
+
6. **Inline docs** — add JSDoc/docstrings to changed functions
|
|
29
|
+
7. **ONBOARDING** — run `fh docs onboard` and review
|
|
30
|
+
|
|
31
|
+
### For User Guide
|
|
32
|
+
|
|
33
|
+
1. Run `fh docs user` to generate a baseline → `docs/user-guide.md`
|
|
34
|
+
2. Read the generated file
|
|
35
|
+
3. Read `.forgehive/memory/project.md` for additional context
|
|
36
|
+
4. Expand sections that are thin: add real usage examples, explain non-obvious behavior, describe common workflows
|
|
37
|
+
5. Remove or correct any placeholder text or auto-generated boilerplate that doesn't match the actual project
|
|
38
|
+
6. Ensure the guide covers: installation, first run, core commands, configuration, troubleshooting
|
|
29
39
|
|
|
30
40
|
### For README updates
|
|
31
41
|
|
|
@@ -2,11 +2,11 @@ You are running a Full Party using ForgeHive.
|
|
|
2
2
|
|
|
3
3
|
## Full Party
|
|
4
4
|
|
|
5
|
-
**Agents:** Nora (Senior Research Analyst), Eli (Documentation Architect), Remy (Product Strategist), Suki (Experience Designer), Viktor (Systems Architect), Kai (Principal Engineer), Sam (Quality Architect)
|
|
5
|
+
**Agents:** Nora (Senior Research Analyst), Eli (Documentation Architect), Remy (Product Strategist), Suki (Experience Designer), Viktor (Systems Architect), Kai (Principal Engineer), Sam (Quality Architect), Vera (Security Architect)
|
|
6
6
|
|
|
7
|
-
**Mission:** Comprehensive multi-discipline review of a major feature or release — all
|
|
7
|
+
**Mission:** Comprehensive multi-discipline review of a major feature or release — all eight specialists working in parallel on their domain.
|
|
8
8
|
|
|
9
|
-
> **Warning:** This party spins up
|
|
9
|
+
> **Warning:** This party spins up 8 worktrees simultaneously. Reserve this for major milestones, release candidates, and significant architectural changes. For smaller reviews, use `/review-party` or `/design-party` instead.
|
|
10
10
|
|
|
11
11
|
## Protocol
|
|
12
12
|
|
|
@@ -17,7 +17,7 @@ Run:
|
|
|
17
17
|
fh party run --set full
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
This spins up isolated worktrees for all
|
|
20
|
+
This spins up isolated worktrees for all 8 agents. Each works their specialization in parallel.
|
|
21
21
|
|
|
22
22
|
### Step 2: Define the milestone
|
|
23
23
|
|
|
@@ -63,6 +63,11 @@ Before the party starts, describe what is being reviewed — be specific:
|
|
|
63
63
|
- Identifies high-risk paths with insufficient coverage
|
|
64
64
|
- Produces: a test coverage and risk report
|
|
65
65
|
|
|
66
|
+
**Vera** (Security Architect) — threat modeling, attack surface analysis:
|
|
67
|
+
- Reviews authentication, authorization, and input handling
|
|
68
|
+
- Flags injection risks, insecure defaults, and data exposure
|
|
69
|
+
- Produces: a security review with severity-labeled findings
|
|
70
|
+
|
|
66
71
|
### Step 4: Check status
|
|
67
72
|
|
|
68
73
|
After all agents complete:
|
package/package.json
CHANGED
|
@@ -1,15 +1,29 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "forgehive",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.6",
|
|
4
4
|
"description": "Context-aware AI development environment — one binary, your stack.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
|
-
"forgehive": "
|
|
8
|
-
"fh": "
|
|
7
|
+
"forgehive": "dist/cli.js",
|
|
8
|
+
"fh": "dist/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist/",
|
|
12
|
+
"forgehive/"
|
|
13
|
+
],
|
|
14
|
+
"keywords": [
|
|
15
|
+
"claude",
|
|
16
|
+
"claude-code",
|
|
17
|
+
"ai",
|
|
18
|
+
"mcp",
|
|
19
|
+
"agents",
|
|
20
|
+
"context",
|
|
21
|
+
"forgehive",
|
|
22
|
+
"development"
|
|
23
|
+
],
|
|
24
|
+
"engines": {
|
|
25
|
+
"node": ">=18"
|
|
9
26
|
},
|
|
10
|
-
"files": ["dist/", "forgehive/"],
|
|
11
|
-
"keywords": ["claude", "claude-code", "ai", "mcp", "agents", "context", "forgehive", "development"],
|
|
12
|
-
"engines": { "node": ">=18" },
|
|
13
27
|
"scripts": {
|
|
14
28
|
"build": "esbuild src/cli.ts --bundle --platform=node --format=esm --outfile=dist/cli.js && chmod +x dist/cli.js",
|
|
15
29
|
"prepublishOnly": "npm run build",
|