@oomerevren/tryforge 0.1.2 → 0.1.3
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/CHANGELOG.md +107 -13
- package/README.md +172 -232
- package/dist/cli/src/adapters/agents-md.js +24 -0
- package/dist/cli/src/adapters/base.js +99 -0
- package/dist/cli/src/adapters/claude.js +43 -14
- package/dist/cli/src/adapters/codex.js +18 -17
- package/dist/cli/src/adapters/cursor.js +44 -30
- package/dist/cli/src/adapters/dsh.js +28 -30
- package/dist/cli/src/adapters/generic.js +10 -7
- package/dist/cli/src/adapters/opencode.js +23 -23
- package/dist/cli/src/adapters/types.js +12 -9
- package/dist/cli/src/adapters/windsurf.js +48 -28
- package/dist/cli/src/commands/add-external.js +111 -0
- package/dist/cli/src/commands/audit.js +68 -30
- package/dist/cli/src/commands/init.js +2 -2
- package/dist/cli/src/commands/install.js +90 -15
- package/dist/cli/src/commands/pack.js +119 -0
- package/dist/cli/src/commands/sync.js +181 -0
- package/dist/cli/src/commands/test.js +72 -0
- package/dist/cli/src/commands/tui.js +191 -0
- package/dist/cli/src/commands/update.js +4 -4
- package/dist/cli/src/commands/verify.js +62 -0
- package/dist/cli/src/core/fsutil.js +37 -0
- package/dist/cli/src/core/installer.js +9 -9
- package/dist/cli/src/core/lock.js +97 -10
- package/dist/cli/src/core/merge.js +108 -0
- package/dist/cli/src/core/plugin.js +2 -2
- package/dist/cli/src/core/project.js +136 -4
- package/dist/cli/src/core/registry.js +9 -9
- package/dist/cli/src/core/scan.js +159 -0
- package/dist/cli/src/core/semver.js +7 -7
- package/dist/cli/src/core/sign.js +2 -2
- package/dist/cli/src/core/sources.js +171 -0
- package/dist/cli/src/index.js +83 -16
- package/dist/index.cjs +359 -0
- package/dist/scripts/build-registry.js +2 -4
- package/dist/scripts/publish-verified.js +17 -9
- package/dist/scripts/seed-registry-13lite.js +5 -5
- package/dist/scripts/seed-registry.js +4 -4
- package/dist/scripts/verify-npm-mcps.js +6 -4
- package/package.json +15 -6
package/README.md
CHANGED
|
@@ -1,107 +1,54 @@
|
|
|
1
|
-
# Forge — The
|
|
1
|
+
# Forge — The Universal Package Manager for AI Agent Context, Skills & MCPs
|
|
2
|
+
|
|
3
|
+
> **Stop manually copying `.cursorrules` and `mcp.json` across 5 different AI editors. One command to rule them all.**
|
|
4
|
+
|
|
5
|
+
<div align="center">
|
|
2
6
|
|
|
3
7
|
[](https://github.com/oomerevren-beep/forge/actions)
|
|
4
8
|
[](https://www.npmjs.com/package/tryforge)
|
|
5
9
|
[](https://www.npmjs.com/package/tryforge)
|
|
6
10
|
[](LICENSE)
|
|
7
|
-
[](registry/index.json)
|
|
8
12
|
[](https://github.com/oomerevren-beep/forge)
|
|
9
13
|
|
|
10
|
-
>
|
|
11
|
-
|
|
12
|
-
`brew` is for system packages. `forge` is for AI agent packages. One command, every harness — no more `git clone + cp SKILL.md` four times for four tools.
|
|
14
|
+
<br>
|
|
13
15
|
|
|
14
16
|
```bash
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
# Windows PowerShell
|
|
18
|
-
irm https://raw.githubusercontent.com/oomerevren-beep/forge/main/install.ps1 | iex
|
|
19
|
-
# or, with Node 22+
|
|
20
|
-
npm i -g tryforge
|
|
17
|
+
npx -y tryforge doctor
|
|
18
|
+
forge add agent-security-auditor
|
|
21
19
|
```
|
|
22
20
|
|
|
23
|
-
|
|
24
|
-
forge doctor # detect your harnesses
|
|
25
|
-
forge add pdf/extract # skill → all harnesses at once
|
|
26
|
-
forge add mcp/filesystem # MCP server → auto mcp.json
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
**Star to get notified at v1.0** — questions in [Discussions](https://github.com/oomerevren-beep/forge/discussions).
|
|
21
|
+
<br>
|
|
30
22
|
|
|
31
|
-
<
|
|
32
|
-
<img src="docs/assets/og.png" alt="Forge — The Homebrew for AI Agents" width="640" />
|
|
33
|
-
</p>
|
|
34
|
-
<p align="center">
|
|
35
|
-
<img src="docs/assets/demo.gif" alt="forge demo — doctor, search, add, list in seconds" width="640" />
|
|
36
|
-
<br><em>7-second wow: <code>forge doctor → search → add → list</code></em>
|
|
37
|
-
</p>
|
|
38
|
-
|
|
39
|
-
---
|
|
23
|
+
<em>3-second wow: `forge add agent-security-auditor` writes rules to Cursor, Claude, Codex, Windsurf — simultaneously.</em>
|
|
40
24
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
- [Why Forge?](#why-forge)
|
|
44
|
-
- [Features](#features)
|
|
45
|
-
- [Install](#install)
|
|
46
|
-
- [Quick Start](#quick-start)
|
|
47
|
-
- [Team Sync — `forge install`](#team-sync--forge-install)
|
|
48
|
-
- [Create a Package](#create-a-package)
|
|
49
|
-
- [How it Works](#how-it-works)
|
|
50
|
-
- [Comparison](#comparison)
|
|
51
|
-
- [Registry — 250 Packages](#registry--250-packages)
|
|
52
|
-
- [Architecture](#architecture)
|
|
53
|
-
- [Docs](#docs)
|
|
54
|
-
- [Roadmap](#roadmap)
|
|
55
|
-
- [Contributing](#contributing)
|
|
56
|
-
- [FAQ](#faq)
|
|
57
|
-
- [License](#license)
|
|
25
|
+
</div>
|
|
58
26
|
|
|
59
27
|
---
|
|
60
28
|
|
|
61
29
|
## Why Forge?
|
|
62
30
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
- `obra/superpowers` — **~280k stars** — install is still manual `git clone + cp`
|
|
66
|
-
- `deepseek-harness` — **~208k stars, ~2 days to 100k** — proved "Everything is a Plugin", but DeepSeek-only
|
|
67
|
-
- `anthropics/skills` — **~173k stars** — Claude-only
|
|
68
|
-
- `mcp-registry` — MCP-only, no skills or agents
|
|
69
|
-
|
|
70
|
-
Result: a developer using Claude Code + Codex + OpenCode + Cursor installs the **same package 4 times by hand**. No `update`, no `forge.toml`, no team sync.
|
|
71
|
-
|
|
72
|
-
**Forge fixes it:** 6 package types × 7 harnesses × one CLI. Like `brew` unified system packages, `forge` unifies agent packages. Viral loop: creators promote `forge add me` to distribute their own work.
|
|
73
|
-
|
|
74
|
-
| Type | Example | What it does |
|
|
75
|
-
|------|---------|--------------|
|
|
76
|
-
| `skill` | `anthropics/plan` | `SKILL.md` capability (Anthropic standard) |
|
|
77
|
-
| `mcp` | `mcp/filesystem` | Model Context Protocol server |
|
|
78
|
-
| `plugin` | `dsh/desktop` | Harness extension |
|
|
79
|
-
| `agent` | `agency/frontend` | Subagent definition |
|
|
80
|
-
| `command` | `cmd/plan` | Slash command `/plan` |
|
|
81
|
-
| `hook` | `hook/pre-tool` | Lifecycle hook |
|
|
31
|
+
You're using Claude Code + Codex + OpenCode + Cursor. You want the same security rules, MCP servers, and skills everywhere. Today you:
|
|
82
32
|
|
|
83
|
-
|
|
33
|
+
1. `git clone` a repo
|
|
34
|
+
2. Copy `SKILL.md` to 4 different folders
|
|
35
|
+
3. Manually paste the same rules into `.cursorrules`, `CLAUDE.md`, `.windsurfrules`
|
|
36
|
+
4. Repeat for every new skill, every update
|
|
84
37
|
|
|
85
|
-
|
|
38
|
+
**Forge fixes it.** One command → every editor. Deterministic `forge.toml` → your whole team ships the same AI context.
|
|
86
39
|
|
|
87
|
-
|
|
88
|
-
- **Multi-harness — 7 adapters today.** One file per harness, so adding Antigravity, Droid, or Copilot is a single PR. Symlink (junction on Windows) preferred, copy fallback.
|
|
89
|
-
- **Team sync — `forge.toml` + `forge.lock`.** Like `package.json` for agents. `forge install` / `forge install --frozen` for CI.
|
|
90
|
-
- **Search in <200ms.** Offline scored `search.json` + typed index, no API key.
|
|
91
|
-
- **Git-native registry.** Every package is a GitHub repo. Forkable, private registry ready. No central DB.
|
|
92
|
-
- **Safe by default.** `sha256`-verified tarballs or hard fail (no silent fallback); mock content only with explicit `--mock`; `forge audit` flags unverified installs; `forge doctor` health check; Windows/Linux/macOS.
|
|
40
|
+
<div align="center">
|
|
93
41
|
|
|
94
|
-
|
|
42
|
+
| | Manual Setup | Forge |
|
|
43
|
+
|---|---|---|
|
|
44
|
+
| Multi-editor support | ❌ Copy-paste × 4 | ✅ One command |
|
|
45
|
+
| Version pinning | ❌ None | ✅ `forge.lock` + SHA-256 |
|
|
46
|
+
| Security audit | ❌ Zero | ✅ AST scanner (HIGH = refuse) |
|
|
47
|
+
| Team sync | ❌ Out of sync | ✅ `forge sync` |
|
|
48
|
+
| Updates | ❌ Manual | ✅ `forge update` |
|
|
49
|
+
| Zero-install | ❌ | ✅ `npx -y tryforge` |
|
|
95
50
|
|
|
96
|
-
|
|
97
|
-
|---------|:------:|
|
|
98
|
-
| Claude Code | ✅ |
|
|
99
|
-
| Codex | ✅ |
|
|
100
|
-
| OpenCode | ✅ |
|
|
101
|
-
| Cursor | ✅ |
|
|
102
|
-
| DeepSeek (dsh) | ⚠️ (community/untested) |
|
|
103
|
-
| Windsurf | ✅ |
|
|
104
|
-
| Generic (any other) | ✅ |
|
|
51
|
+
</div>
|
|
105
52
|
|
|
106
53
|
---
|
|
107
54
|
|
|
@@ -114,238 +61,229 @@ curl -fsSL https://raw.githubusercontent.com/oomerevren-beep/forge/main/install.
|
|
|
114
61
|
# Windows PowerShell
|
|
115
62
|
irm https://raw.githubusercontent.com/oomerevren-beep/forge/main/install.ps1 | iex
|
|
116
63
|
|
|
117
|
-
#
|
|
64
|
+
# Or with Node 22+
|
|
118
65
|
npm i -g tryforge
|
|
119
66
|
```
|
|
120
67
|
|
|
121
|
-
|
|
68
|
+
```bash
|
|
69
|
+
npx -y tryforge doctor # zero-install — no global install needed
|
|
70
|
+
```
|
|
122
71
|
|
|
123
72
|
---
|
|
124
73
|
|
|
125
|
-
## Quick Start
|
|
126
|
-
|
|
127
|
-
60 seconds, copy-paste:
|
|
74
|
+
## Quick Start (60 seconds)
|
|
128
75
|
|
|
129
76
|
```bash
|
|
130
|
-
|
|
131
|
-
forge
|
|
132
|
-
forge add anthropics/plan # install latest → all harnesses at once
|
|
133
|
-
```
|
|
77
|
+
# 1. Initialize your project
|
|
78
|
+
npx forge init
|
|
134
79
|
|
|
135
|
-
|
|
80
|
+
# 2. Add the packages you want
|
|
81
|
+
forge add github:my-org/agent-security
|
|
82
|
+
forge add pdf/merge
|
|
83
|
+
forge add mcp/filesystem
|
|
136
84
|
|
|
137
|
-
|
|
138
|
-
forge
|
|
139
|
-
forge list # installed, with versions
|
|
140
|
-
forge info mcp/github # detail + versions + engines
|
|
141
|
-
forge outdated # what can be updated
|
|
142
|
-
forge update # update all (or: forge update mcp/github)
|
|
143
|
-
forge remove obra/superpowers
|
|
85
|
+
# 3. Sync every editor
|
|
86
|
+
npx forge sync
|
|
144
87
|
```
|
|
145
88
|
|
|
146
|
-
|
|
147
|
-
# version pinning
|
|
148
|
-
forge add anthropics/plan@1.1.0
|
|
149
|
-
forge add anthropics/plan@^1.2.0
|
|
89
|
+
Done. Cursor, Claude Code, Codex, OpenCode, Windsurf, DSH — all share the same context.
|
|
150
90
|
|
|
151
|
-
|
|
152
|
-
forge add anthropics/plan --dry-run
|
|
91
|
+
---
|
|
153
92
|
|
|
154
|
-
|
|
155
|
-
forge add skill/pdf --mock
|
|
156
|
-
forge install --mock # same opt-in for project installs
|
|
157
|
-
forge update mcp/github --mock
|
|
158
|
-
```
|
|
93
|
+
## Supported Harnesses
|
|
159
94
|
|
|
160
|
-
|
|
95
|
+
| Harness | Status | Rule Format |
|
|
96
|
+
|---------|:------:|-------------|
|
|
97
|
+
| Claude Code | ✅ | `CLAUDE.md` merged blocks |
|
|
98
|
+
| Cursor | ✅ | `.cursor/rules/*.mdc` |
|
|
99
|
+
| OpenCode | ✅ | `AGENTS.md` shared blocks |
|
|
100
|
+
| Codex | ✅ | `AGENTS.md` shared blocks |
|
|
101
|
+
| Windsurf | ✅ | `.windsurfrules` merged |
|
|
102
|
+
| DSH | ⚠️ | `AGENTS.md` (community) |
|
|
103
|
+
| Generic | ✅ | `.forge/` fallback |
|
|
161
104
|
|
|
162
|
-
|
|
105
|
+
---
|
|
163
106
|
|
|
164
|
-
|
|
107
|
+
## Team Sync — `forge.toml`
|
|
165
108
|
|
|
166
109
|
```toml
|
|
167
|
-
#
|
|
110
|
+
# forge.toml — single source of truth for your project's AI context
|
|
168
111
|
[project]
|
|
169
112
|
name = "my-app"
|
|
170
|
-
version = "
|
|
113
|
+
version = "1.0.0"
|
|
171
114
|
|
|
172
115
|
[dependencies]
|
|
173
|
-
"
|
|
174
|
-
"mcp
|
|
175
|
-
"obra/superpowers" = "^3.0.0"
|
|
176
|
-
"skill/pdf" = "^1.0.0"
|
|
177
|
-
```
|
|
116
|
+
"agent-pr-reviewer" = "^1.2.0"
|
|
117
|
+
"mcp-filesystem" = "^1.0.0"
|
|
178
118
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
forge outdated # shows 1.1.0 → 1.2.0 etc.
|
|
183
|
-
forge update # bumps to latest within semver
|
|
184
|
-
```
|
|
119
|
+
[skills.team-rules]
|
|
120
|
+
source = "github:my-org/team-skills"
|
|
121
|
+
ref = "main"
|
|
185
122
|
|
|
186
|
-
|
|
123
|
+
[agents.developer]
|
|
124
|
+
model = "claude-3-7-sonnet"
|
|
125
|
+
system_prompt = "Senior engineer. TDD. No shortcuts."
|
|
187
126
|
|
|
188
|
-
|
|
127
|
+
[mcp.servers.postgres]
|
|
128
|
+
command = "npx"
|
|
129
|
+
args = ["-y", "@modelcontextprotocol/server-postgres", "postgresql://localhost/db"]
|
|
189
130
|
|
|
190
|
-
|
|
131
|
+
[permissions]
|
|
132
|
+
denied_paths = [".env*", "id_rsa*", "./secrets"]
|
|
133
|
+
allow_network = false
|
|
134
|
+
```
|
|
191
135
|
|
|
192
136
|
```bash
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
forge
|
|
196
|
-
#
|
|
197
|
-
|
|
198
|
-
cat forge.toml
|
|
199
|
-
# [package] name="my-skill" version="0.1.0" type="skill" ...
|
|
200
|
-
|
|
201
|
-
forge publish # (v0.2) validates → tarball → GitHub Release → registry PR
|
|
137
|
+
# Everyone on the team runs:
|
|
138
|
+
git pull
|
|
139
|
+
npx forge sync
|
|
140
|
+
# That's it — identical AI context across every editor
|
|
202
141
|
```
|
|
203
142
|
|
|
204
|
-
Until `publish` lands, open a PR adding `registry/packages/<slug>.json` (see `schema/forge.schema.json`), then `npm run registry:build`. Minimal working example: [examples/minimal-skill/](examples/minimal-skill/).
|
|
205
|
-
|
|
206
143
|
---
|
|
207
144
|
|
|
208
|
-
##
|
|
145
|
+
## Security
|
|
209
146
|
|
|
210
|
-
|
|
211
|
-
forge add anthropics/plan
|
|
212
|
-
→ resolve ^1.2.0 → tarball URL + sha256 (from local/bundled registry/index.json; CDN in v0.3)
|
|
213
|
-
→ download to ~/.forge/cache/tarballs/ → verify sha256 (hard fail on mismatch) → extract to ~/.forge/packages/anthropics-plan@1.2.0/
|
|
214
|
-
→ adapter: symlink/copy to all 7 harnesses (Claude/Codex/OpenCode/Cursor/DSH/Windsurf/Generic)
|
|
215
|
-
→ if MCP: backup mcp.json → inject server entry
|
|
216
|
-
```
|
|
147
|
+
Forge is **fail-closed** by default:
|
|
217
148
|
|
|
218
|
-
|
|
149
|
+
- **sha256 verification** — every package is hash-pinned; mismatch = exit 1
|
|
150
|
+
- **Static scanner** — 19 rules (shell-danger, prompt-inject, perm-violation); HIGH blocks install
|
|
151
|
+
- **`forge audit`** — flags mock/unverified installs (exit 1 on high-severity)
|
|
152
|
+
- **`forge.toml` [permissions]** — denied paths enforced per-project
|
|
219
153
|
|
|
220
|
-
```
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
cache/tarballs/ # downloaded .tar.gz
|
|
225
|
-
links.json # {pkg, version, adapters[]} source of truth
|
|
154
|
+
```bash
|
|
155
|
+
forge audit # scan installed packages
|
|
156
|
+
forge test ./my-package # pre-publish validation
|
|
157
|
+
forge verify ./my-package # full schema + security + adapter check
|
|
226
158
|
```
|
|
227
159
|
|
|
228
160
|
---
|
|
229
161
|
|
|
230
|
-
##
|
|
231
|
-
|
|
232
|
-
| | **Forge** | `npx skills` (Vercel) | `anthropics/skills` | `DSH` | `mcp-registry` |
|
|
233
|
-
|---|---|---|---|---|---|
|
|
234
|
-
| Türler | **6** (skill/mcp/plugin/agent/command/hook) | 1 (skill) | 1 (skill) | plugin | 1 (mcp) |
|
|
235
|
-
| Harness | **7** (Claude/Codex/OpenCode/Cursor/DSH/Windsurf/Generic) | 75+ ajan | 1 | 1 | ~1 |
|
|
236
|
-
| Versiyonlama | **semver + lock** | skills-lock.json | none | none | partial |
|
|
237
|
-
| Güncelleme | `forge update` | check/update | manual | manual | manual |
|
|
238
|
-
| Takım senkronu | **`forge.toml` + `forge.lock`** | none | none | none | none |
|
|
239
|
-
| Arama | `<200ms` offline | `skills find` | GitHub search | none | web only |
|
|
240
|
-
| Paket doğrulama | **sha256 + fail-closed** | none | none | none | none |
|
|
241
|
-
| Yerel CLI | **evet** (npm i -g) | npx (her seferinde indirir) | manual | manual | — |
|
|
162
|
+
## Available Packages
|
|
242
163
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
---
|
|
164
|
+
**21 verified packages** (sha256-pinned). Registry is git-native and forkable.
|
|
246
165
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
166
|
+
| Category | Examples |
|
|
167
|
+
|----------|----------|
|
|
168
|
+
| Skills | `cmd/plan`, `cmd/review`, `obra/superpowers` |
|
|
169
|
+
| MCP Servers | `mcp/filesystem`, `mcp/github`, `mcp/postgres`, `mcp/memory`, `mcp/sequential-thinking` |
|
|
170
|
+
| Agents | `agency/frontend`, `agency/backend` |
|
|
171
|
+
| PDF Tools | `pdf/merge`, `pdf/split`, `pdf/forms`, `pdf/ocr`, `pdf/extract`, `pdf/compress`, `pdf/convert`, `pdf/tables` |
|
|
250
172
|
|
|
251
173
|
```bash
|
|
252
|
-
forge search
|
|
253
|
-
forge search
|
|
254
|
-
forge
|
|
255
|
-
forge info pdf/compress # versions, engines, sha
|
|
174
|
+
forge search pdf
|
|
175
|
+
forge search mcp
|
|
176
|
+
forge info mcp/github
|
|
256
177
|
```
|
|
257
178
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
```bash
|
|
261
|
-
npm run registry:build # index + search + stats + --check in CI
|
|
262
|
-
```
|
|
179
|
+
---
|
|
263
180
|
|
|
264
|
-
|
|
181
|
+
## Commands
|
|
182
|
+
|
|
183
|
+
| Command | What it does |
|
|
184
|
+
|---------|-------------|
|
|
185
|
+
| `forge add <pkg>` | Install to all harnesses (registry, GitHub, local) |
|
|
186
|
+
| `forge remove <pkg>` | Uninstall from all harnesses |
|
|
187
|
+
| `forge install` | Install all `[dependencies]` from `forge.toml` |
|
|
188
|
+
| `forge install --frozen` | CI mode: exact from `forge.lock` |
|
|
189
|
+
| `forge sync` | One-command team sync (skills + rules + MCP + roles) |
|
|
190
|
+
| `forge init <name>` | Scaffold a new package |
|
|
191
|
+
| `forge test <pkg>` | Validate against adapter matrix (dry-run) |
|
|
192
|
+
| `forge pack` | Build verified tarball |
|
|
193
|
+
| `forge verify <pkg>` | Schema + security + adapter check |
|
|
194
|
+
| `forge audit` | Scan installed packages (fail-closed) |
|
|
195
|
+
| `forge doctor` | Health check harnesses + store |
|
|
196
|
+
| `forge search <query>` | Fuzzy search (<200ms, offline) |
|
|
197
|
+
| `forge list` | List installed packages |
|
|
198
|
+
| `forge outdated` | Show packages with newer versions |
|
|
199
|
+
| `forge update` | Update all (or one) to latest |
|
|
200
|
+
| `forge tui` | Interactive terminal dashboard |
|
|
265
201
|
|
|
266
202
|
---
|
|
267
203
|
|
|
268
204
|
## Architecture
|
|
269
205
|
|
|
270
206
|
```
|
|
271
|
-
CLI (TypeScript
|
|
207
|
+
CLI (TypeScript)
|
|
272
208
|
├─ registry client (index.json + semver)
|
|
273
|
-
├─ store (~/.forge/
|
|
274
|
-
├─ adapters (
|
|
275
|
-
|
|
209
|
+
├─ store (~/.forge/ + links.json + cache)
|
|
210
|
+
├─ adapters (1 file per harness — symlink or copy)
|
|
211
|
+
├─ core (merge engine, security scanner, lock, sources)
|
|
212
|
+
└─ commands (add/remove/sync/audit/test/pack/verify/tui)
|
|
276
213
|
```
|
|
277
214
|
|
|
278
|
-
|
|
215
|
+
**v0.1 → v0.2 → v1.0:**
|
|
216
|
+
- **v0.1** (now): 7 harnesses, 21 verified packages, full CLI
|
|
217
|
+
- **v0.2**: `forge publish`, Rust rewrite for `cargo install`
|
|
218
|
+
- **v1.0**: Team registry, `brew install forge`, `winget`
|
|
219
|
+
|
|
220
|
+
See [docs/ROADMAP.md](docs/ROADMAP.md).
|
|
279
221
|
|
|
280
222
|
---
|
|
281
223
|
|
|
282
|
-
##
|
|
224
|
+
## Add a Package
|
|
283
225
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
226
|
+
```bash
|
|
227
|
+
# 1. Create your package
|
|
228
|
+
forge init my-skill --type skill --yes
|
|
229
|
+
# Edit SKILL.md + forge.toml
|
|
230
|
+
|
|
231
|
+
# 2. Verify it
|
|
232
|
+
forge verify .
|
|
233
|
+
|
|
234
|
+
# 3. Publish (v0.2: tarball + GitHub Release + registry PR)
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
Until `publish` lands, open a PR adding `registry/packages/<slug>.json` + run `npm run registry:build -- --check`.
|
|
294
238
|
|
|
295
239
|
---
|
|
296
240
|
|
|
297
|
-
##
|
|
241
|
+
## Add a Harness
|
|
298
242
|
|
|
299
|
-
|
|
300
|
-
**v0.2 — NPM moment**: `forge publish`, deps, `cargo install`.
|
|
301
|
-
**v0.3 — Store moment**: `forge run`, Rust binary, GUI.
|
|
302
|
-
**v1.0 — Cloud**: team registry, `brew install forge`, `winget`.
|
|
243
|
+
One file: `cli/src/adapters/<name>.ts`. Implement the `Adapter` interface. Register in `adapters/index.ts`. Done.
|
|
303
244
|
|
|
304
|
-
See
|
|
245
|
+
See [docs/ADAPTERS.md](docs/ADAPTERS.md).
|
|
305
246
|
|
|
306
247
|
---
|
|
307
248
|
|
|
308
|
-
##
|
|
249
|
+
## Documentation
|
|
309
250
|
|
|
310
|
-
|
|
251
|
+
- [Install Guide](docs/INSTALL.md)
|
|
252
|
+
- [Package Spec](docs/SPEC.md) — `forge.toml` fields per type
|
|
253
|
+
- [Architecture](docs/ARCHITECTURE.md) — components, security, perf
|
|
254
|
+
- [Adapters](docs/ADAPTERS.md) — add a harness in one file
|
|
255
|
+
- [Registry](docs/REGISTRY.md) — index schema, publish, fork
|
|
256
|
+
- [Roadmap](docs/ROADMAP.md)
|
|
257
|
+
- [Examples](examples/)
|
|
311
258
|
|
|
312
|
-
|
|
313
|
-
2. **Verify on install**: İndirme sırasında hash kontrol edilir — uyarsa exit 1
|
|
314
|
-
3. **Audit trail**: `forge audit` mock/tamamlanmamış kurulumları listeler
|
|
259
|
+
---
|
|
315
260
|
|
|
316
|
-
|
|
261
|
+
## Badges
|
|
317
262
|
|
|
318
|
-
|
|
319
|
-
- Add a harness: `cli/src/adapters/<name>.ts` → register in `adapters/index.ts` → `forge doctor`
|
|
320
|
-
- PR checklist: `npm run build && npm test && npm run registry:build -- --check`
|
|
321
|
-
- New? Start with [`good first issue`](https://github.com/oomerevren-beep/forge/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) — questions in [Discussions](https://github.com/oomerevren-beep/forge/discussions)
|
|
263
|
+
Add `forge` to your project:
|
|
322
264
|
|
|
323
|
-
|
|
265
|
+
```markdown
|
|
266
|
+
[](https://github.com/oomerevren-beep/forge)
|
|
267
|
+
```
|
|
324
268
|
|
|
325
269
|
---
|
|
326
270
|
|
|
327
271
|
## FAQ
|
|
328
272
|
|
|
329
273
|
**Is this just for Claude Code?**
|
|
330
|
-
No. 7 harnesses today, one file per new harness. The point is *universal
|
|
331
|
-
|
|
332
|
-
**How is this different from `mcp-registry` or `skills` repos?**
|
|
333
|
-
Those are single-type and single-harness. Forge is `brew` for *all* agent package types, on *every* harness, with versioning/lock/search.
|
|
274
|
+
No. 7 harnesses today, one file per new harness. The point is *universal*.
|
|
334
275
|
|
|
335
276
|
**Does `install.sh` need `forge.sh` domain?**
|
|
336
|
-
No.
|
|
337
|
-
|
|
338
|
-
**Are most packages mock content?**
|
|
339
|
-
Honest answer: 245 of 250 registry entries still carry placeholder SHAs (only 5 verified so far). Forge is fail-closed — installing one without `--mock` errors out instead of silently faking it; `forge audit` flags every unverified install. Real tarballs land as maintainers verify them (tracked for Faz 13-full).
|
|
277
|
+
No. Works from GitHub raw today.
|
|
340
278
|
|
|
341
|
-
**
|
|
342
|
-
|
|
279
|
+
**Are packages verified?**
|
|
280
|
+
21 are sha256-pinned and pass the static scanner. The rest is tracked for Phase 13.
|
|
343
281
|
|
|
344
|
-
**
|
|
345
|
-
|
|
282
|
+
**Windows support?**
|
|
283
|
+
Full. Junction on dirs, file-by-file copy fallback for non-ASCII paths, PowerShell installer.
|
|
346
284
|
|
|
347
285
|
**Private registry?**
|
|
348
|
-
Yes. Fork this repo, keep `registry/` private, point `~/.forge/config.toml`
|
|
286
|
+
Yes. Fork this repo, keep `registry/` private, point `~/.forge/config.toml` to your own index.
|
|
349
287
|
|
|
350
288
|
---
|
|
351
289
|
|
|
@@ -355,7 +293,9 @@ MIT — see [LICENSE](LICENSE).
|
|
|
355
293
|
|
|
356
294
|
---
|
|
357
295
|
|
|
358
|
-
<
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
</
|
|
296
|
+
<div align="center">
|
|
297
|
+
|
|
298
|
+
<strong>Star this repo to get notified at v1.0.</strong><br>
|
|
299
|
+
<code>forge add</code> → 7 places at once. <code>forge sync</code> → team sync. Homebrew simple.
|
|
300
|
+
|
|
301
|
+
</div>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// cli/src/adapters/agents-md.ts — Shared AGENTS.md rule sync (Phase 2).
|
|
2
|
+
//
|
|
3
|
+
// OpenCode, Codex, and DSH all honor the AGENTS.md project convention:
|
|
4
|
+
// standard system-prompt rules in one shared file. Forge merges one marked
|
|
5
|
+
// block per package and never touches surrounding user content.
|
|
6
|
+
import { join } from "path";
|
|
7
|
+
import { pointerBody, syncBlockFile, unsyncBlockFile, shouldSyncRules, } from "./base.js";
|
|
8
|
+
export function agentsMdPath(projectDir) {
|
|
9
|
+
return join(projectDir, "AGENTS.md");
|
|
10
|
+
}
|
|
11
|
+
export function syncAgentsMd(projectDir, pkgSlug, skillPath, meta) {
|
|
12
|
+
const file = agentsMdPath(projectDir);
|
|
13
|
+
if (!shouldSyncRules(projectDir, file))
|
|
14
|
+
return;
|
|
15
|
+
syncBlockFile(file, pkgSlug, meta?.version ?? "0.0.0", pointerBody({
|
|
16
|
+
slug: pkgSlug,
|
|
17
|
+
version: meta?.version ?? "",
|
|
18
|
+
description: meta?.description ?? `${pkgSlug} (installed via Forge)`,
|
|
19
|
+
skillPath,
|
|
20
|
+
}));
|
|
21
|
+
}
|
|
22
|
+
export function unsyncAgentsMd(projectDir, pkgSlug) {
|
|
23
|
+
unsyncBlockFile(agentsMdPath(projectDir), pkgSlug);
|
|
24
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
// cli/src/adapters/base.ts — Shared adapter foundation (Phase 2).
|
|
2
|
+
//
|
|
3
|
+
// Eliminates the copy-pasted project-or-home resolution, list/isInstalled
|
|
4
|
+
// loops, and rule-file sync shared by all file-based harness adapters.
|
|
5
|
+
// Adapters keep their own path quirks; everything mechanical lives here.
|
|
6
|
+
//
|
|
7
|
+
// Test hook: set FORGE_TEST_HOME to redirect home-dir resolution into a
|
|
8
|
+
// temp dir so adapter tests never touch the real ~/.cursor, ~/.claude, ...
|
|
9
|
+
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
10
|
+
import { join, dirname } from "path";
|
|
11
|
+
import { homedir } from "os";
|
|
12
|
+
import { installSkillFiles, uninstallSkillFiles, listDirNames, ensureDir, backupFileIfExists, } from "./types.js";
|
|
13
|
+
import { upsertForgeBlock, removeForgeBlock } from "../core/merge.js";
|
|
14
|
+
export function testHome() {
|
|
15
|
+
return process.env.FORGE_TEST_HOME ?? homedir();
|
|
16
|
+
}
|
|
17
|
+
/** Build the instruction body for rule files: SKILL.md/agent.md excerpt, capped. */
|
|
18
|
+
export function instructionBody(srcDir, fallback) {
|
|
19
|
+
for (const f of ["SKILL.md", "agent.md"]) {
|
|
20
|
+
try {
|
|
21
|
+
const p = join(srcDir, f);
|
|
22
|
+
if (existsSync(p)) {
|
|
23
|
+
const text = readFileSync(p, "utf-8").trim().slice(0, 2000);
|
|
24
|
+
if (text.length > 0)
|
|
25
|
+
return `${text}\n`;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
/* unreadable source — use the fallback line */
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return `${fallback}\n`;
|
|
33
|
+
}
|
|
34
|
+
/** Short pointer body for merged files (CLAUDE.md, AGENTS.md, .windsurfrules). */
|
|
35
|
+
export function pointerBody(pkg) {
|
|
36
|
+
const at = pkg.version ? `@${pkg.version}` : "";
|
|
37
|
+
return `- ${pkg.slug}${at}: ${pkg.description}\n Full instructions: ${pkg.skillPath}\n`;
|
|
38
|
+
}
|
|
39
|
+
export async function sharedList(paths) {
|
|
40
|
+
for (const b of paths.skillBases()) {
|
|
41
|
+
if (existsSync(b))
|
|
42
|
+
return listDirNames(b);
|
|
43
|
+
}
|
|
44
|
+
return [];
|
|
45
|
+
}
|
|
46
|
+
export async function sharedIsInstalled(paths, pkgSlug) {
|
|
47
|
+
return paths.skillBases().some((b) => existsSync(join(b, pkgSlug)));
|
|
48
|
+
}
|
|
49
|
+
export function sharedUninstall(paths, pkgSlug) {
|
|
50
|
+
for (const b of paths.skillBases())
|
|
51
|
+
uninstallSkillFiles(pkgSlug, b);
|
|
52
|
+
}
|
|
53
|
+
export function sharedInstall(paths, pkgSlug, srcDir) {
|
|
54
|
+
installSkillFiles("forge", pkgSlug, srcDir, paths.installBase());
|
|
55
|
+
}
|
|
56
|
+
const PROJECT_MARKERS = [
|
|
57
|
+
"forge.toml",
|
|
58
|
+
"package.json",
|
|
59
|
+
".git",
|
|
60
|
+
"AGENTS.md",
|
|
61
|
+
"CLAUDE.md",
|
|
62
|
+
".cursor",
|
|
63
|
+
"opencode.json",
|
|
64
|
+
".codex",
|
|
65
|
+
".windsurf",
|
|
66
|
+
".dsh",
|
|
67
|
+
];
|
|
68
|
+
/** True when dir looks like a project (or already holds the rule file). */
|
|
69
|
+
export function isProjectDir(dir) {
|
|
70
|
+
return PROJECT_MARKERS.some((m) => existsSync(join(dir, m)));
|
|
71
|
+
}
|
|
72
|
+
/** Merge-gate for cwd-root rule files: sync when the file exists or dir is a project. */
|
|
73
|
+
export function shouldSyncRules(dir, filePath) {
|
|
74
|
+
return existsSync(filePath) || isProjectDir(dir);
|
|
75
|
+
}
|
|
76
|
+
/** Write a fully forge-managed per-package file (e.g. .cursor/rules/<slug>.mdc).
|
|
77
|
+
* An existing file WITHOUT a forge marker is backed up (.bak) first so user
|
|
78
|
+
* content is never silently lost; files already carrying our marker for the
|
|
79
|
+
* same id are overwritten in place.
|
|
80
|
+
*/
|
|
81
|
+
export function writeManagedFile(filePath, id, content) {
|
|
82
|
+
ensureDir(dirname(filePath));
|
|
83
|
+
if (existsSync(filePath)) {
|
|
84
|
+
const raw = readFileSync(filePath, "utf-8");
|
|
85
|
+
if (!raw.includes(`id="${id}"`))
|
|
86
|
+
backupFileIfExists(filePath);
|
|
87
|
+
}
|
|
88
|
+
writeFileSync(filePath, content);
|
|
89
|
+
}
|
|
90
|
+
/** Merge a forge block into a user-owned file (never touches outside content). */
|
|
91
|
+
export function syncBlockFile(filePath, id, version, body) {
|
|
92
|
+
ensureDir(dirname(filePath));
|
|
93
|
+
upsertForgeBlock(filePath, id, version, body);
|
|
94
|
+
}
|
|
95
|
+
/** Remove only our block; delete the file when forge created it and it is now blank. */
|
|
96
|
+
export function unsyncBlockFile(filePath, id) {
|
|
97
|
+
removeForgeBlock(filePath, id, { deleteIfEmpty: true });
|
|
98
|
+
}
|
|
99
|
+
export { upsertForgeBlock, removeForgeBlock };
|