@eric0117/agentforge 0.1.0

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.
Files changed (40) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +275 -0
  3. package/dist/add-agent.js +145 -0
  4. package/dist/add-skill.js +185 -0
  5. package/dist/agent-prompt.js +211 -0
  6. package/dist/agentforge-config.js +106 -0
  7. package/dist/agents/claude.js +46 -0
  8. package/dist/agents/codex.js +67 -0
  9. package/dist/agents/cursor.js +54 -0
  10. package/dist/agents/index.js +15 -0
  11. package/dist/agents/io.js +252 -0
  12. package/dist/agents/types.js +1 -0
  13. package/dist/cli.js +374 -0
  14. package/dist/confirm.js +20 -0
  15. package/dist/doctor.js +223 -0
  16. package/dist/enter.js +85 -0
  17. package/dist/init.js +272 -0
  18. package/dist/lang-prompt.js +88 -0
  19. package/dist/list-skills.js +120 -0
  20. package/dist/logo.js +181 -0
  21. package/dist/path-prompt.js +148 -0
  22. package/dist/remove-agent.js +63 -0
  23. package/dist/remove-skill.js +88 -0
  24. package/dist/rename.js +222 -0
  25. package/dist/skill-prompt.js +199 -0
  26. package/dist/skills-data.js +727 -0
  27. package/dist/sync-skills.js +59 -0
  28. package/dist/templates/CLAUDE.md.tpl +141 -0
  29. package/dist/templates/context-handoff.SKILL.md.tpl +222 -0
  30. package/dist/templates/cross-repo-impact.SKILL.md.tpl +241 -0
  31. package/dist/templates/feature-retro.SKILL.md.tpl +312 -0
  32. package/dist/templates/feature-start.SKILL.md.tpl +631 -0
  33. package/dist/templates/history.SKILL.md.tpl +165 -0
  34. package/dist/templates/incident-context.SKILL.md.tpl +260 -0
  35. package/dist/templates/pr-create.SKILL.md.tpl +403 -0
  36. package/dist/templates/pr-review-analyze.SKILL.md.tpl +303 -0
  37. package/dist/templates/pre-deploy-check.SKILL.md.tpl +350 -0
  38. package/dist/templates/project-router.SKILL.md.tpl +55 -0
  39. package/dist/templates/release-coordinate.SKILL.md.tpl +209 -0
  40. package/package.json +54 -0
@@ -0,0 +1,403 @@
1
+ ---
2
+ name: agentforge-pr-create
3
+ description: Opens pull requests for a feature whose work lives across multiple repo worktrees. Walks the anvil/<slug>/ directory, detects which repos have commits ahead of their base branch, lets the user multi-select which ones to PR, then opens one PR per repo via gh CLI. Titles and bodies are drafted from anvil/<slug>/CLAUDE.md (feature description) plus each repo's diff stat and commit log. Adds cross-references between the PRs so reviewers see the bundle. Triggers on "open PRs for this feature", "make PRs", "ship it", "create the PRs". Never force-pushes; never merges.
4
+ ---
5
+
6
+ # agentforge-pr-create
7
+
8
+ A feature in this workspace can live across several worktrees (`anvil/<slug>/<repo>/`).
9
+ GitHub PRs are repo-scoped, so this skill opens **one PR per repo that actually has
10
+ changes**, drafts each PR from the feature's shared description, and stitches them
11
+ together with cross-references.
12
+
13
+ **This skill creates PRs (an externally visible action).** Always confirm with the user
14
+ before pushing or opening anything.
15
+
16
+ ## When to apply
17
+
18
+ Trigger phrases:
19
+ - "Open PRs for this feature."
20
+ - "Make the PRs."
21
+ - "Create PRs for the worktrees."
22
+ - "Ship it."
23
+ - "Time to open PRs."
24
+
25
+ If the user is mid-implementation, this is the wrong skill — point them to keep
26
+ working and come back when the feature is ready for review.
27
+
28
+ ## Concurrency lock
29
+
30
+ Before opening or editing PRs, take the workspace lock so another session doesn't
31
+ race with this one:
32
+
33
+ ```bash
34
+ LOCK="anvil/<slug>/.agentforge.lock"
35
+ if [ -f "$LOCK" ]; then
36
+ cat "$LOCK"
37
+ # → another session is opening PRs for this feature. Stop and tell the user.
38
+ fi
39
+ printf 'pid=%s\nstarted=%s\nskill=agentforge-pr-create\n' \
40
+ "$$" "$(date -u +%FT%TZ)" > "$LOCK"
41
+ ```
42
+
43
+ Release on success and on every failure path.
44
+
45
+ ## Preconditions
46
+
47
+ - `gh` CLI authenticated (`gh auth status`). If not, surface a clear error and stop.
48
+ - Each target worktree has a remote configured (`git -C <worktree> remote get-url
49
+ origin`). If not, tell the user and skip that repo.
50
+ - The user is somewhere under an agentforge workspace — `repos/` and `anvil/` are
51
+ visible from cwd by walking up.
52
+
53
+ ## Step 1 — Identify the feature
54
+
55
+ Resolve which `anvil/<slug>/` we're working with:
56
+
57
+ - If cwd is `…/anvil/<slug>/…`, use that `<slug>`.
58
+ - If cwd is the workspace root, list `anvil/*/` and ask the user to pick.
59
+ - Read `anvil/<slug>/CLAUDE.md` to get the feature description + originally-intended
60
+ repo list. (Created by `agentforge-feature-start`.) If it's missing, ask the user
61
+ for a one-line description.
62
+
63
+ ## Step 2 — Detect repos with actual changes
64
+
65
+ For each subdirectory of `anvil/<slug>/` that contains a `.git` (or is a worktree):
66
+
67
+ ```bash
68
+ # what's the base branch?
69
+ git -C anvil/<slug>/<repo> rev-parse --abbrev-ref @{upstream} 2>/dev/null
70
+ # fallback: origin/main or origin/master
71
+ ```
72
+
73
+ For each candidate worktree, compute:
74
+
75
+ ```bash
76
+ git -C anvil/<slug>/<repo> rev-list --count <base>..HEAD # commits ahead
77
+ git -C anvil/<slug>/<repo> status --porcelain # uncommitted changes
78
+ ```
79
+
80
+ Build a candidate set:
81
+ - **Includes**: repos with `commits-ahead > 0`.
82
+ - **Excludes** with a note: repos with no commits ahead (nothing to PR), repos with
83
+ uncommitted changes (warn the user but offer to include after they commit), repos
84
+ without a remote.
85
+ - **Includes with warning**: if HEAD is behind the base branch, suggest rebasing first.
86
+
87
+ Show the candidate set as a table:
88
+
89
+ ```
90
+ anvil/feat-search-ranking/
91
+ ✓ backend-api 3 commits ahead (will PR)
92
+ ✓ admin-web 1 commit ahead (will PR)
93
+ ⚠ worker-service 2 uncommitted (skipped — commit first?)
94
+ ✗ mobile-app 0 commits ahead (nothing to PR)
95
+ ```
96
+
97
+ ## Step 3 — Let the user pick
98
+
99
+ Present the includable repos as a **multi-select**, with all of them pre-checked.
100
+ Never assume — the user may want to PR only a subset (e.g. open backend first, follow
101
+ with frontend later).
102
+
103
+ If a structured multi-select is available, use it. Otherwise accept a list of names
104
+ or numbers.
105
+
106
+ ## Step 4 — Push branches (if needed)
107
+
108
+ For each chosen worktree, ensure the branch is on the remote:
109
+
110
+ ```bash
111
+ git -C anvil/<slug>/<repo> rev-parse --abbrev-ref HEAD # branch name
112
+ git -C anvil/<slug>/<repo> push -u origin <branch> # publish if needed
113
+ ```
114
+
115
+ **Never use `--force` or `--force-with-lease`.** If the remote has diverging commits,
116
+ stop and ask the user. They may have an open PR on the same branch already.
117
+
118
+ ## Step 4.5 — Check for an existing PR template
119
+
120
+ Before drafting the body, check whether each repo ships a PR template:
121
+
122
+ ```bash
123
+ for path in \
124
+ repos/<repo>/.github/PULL_REQUEST_TEMPLATE.md \
125
+ repos/<repo>/.github/pull_request_template.md \
126
+ repos/<repo>/PULL_REQUEST_TEMPLATE.md \
127
+ repos/<repo>/docs/PULL_REQUEST_TEMPLATE.md; do
128
+ [ -f "$path" ] && echo "$path"
129
+ done
130
+ ```
131
+
132
+ If a template exists, **use it as the skeleton** and fill the agentforge-generated
133
+ content into matching sections (look for headings like `## What`, `## Why`, `## How`,
134
+ `## Test plan`, `### Description`). If a section exists in the template but the
135
+ generator has no content for it, leave that section's placeholder untouched. **Do
136
+ not strip checklists** the template ships — they may be required by branch
137
+ protection or review automation.
138
+
139
+ If no template exists, use the body template in the next step.
140
+
141
+ ### Language of the PR title and body
142
+
143
+ **Write prose (the `What`, `Why`, `How`, `Test plan` sections, `Changes` bullets,
144
+ PR-template prose fields) in the workspace's output language** — see the
145
+ "Output language" instruction at the bottom of this file. The PR will be read by
146
+ teammates who share that workspace, so the natural-language sections follow
147
+ that language.
148
+
149
+ Keep the following in their original form regardless of language:
150
+ - Conventional Commits type/scope prefix (`feat:`, `fix(api):`, ...)
151
+ - code identifiers, commands, file paths, branch names, commit SHAs
152
+ - proper nouns (gh, GitHub, Kafka, Redis, etc.)
153
+ - the "Cross-repo" links
154
+
155
+ For example, a Korean workspace produces titles like
156
+ `feat: 새로운 기능 추가` and bodies in Korean prose, while a Japanese workspace
157
+ produces `feat: 新機能を追加` and Japanese prose. An English workspace produces
158
+ English throughout.
159
+
160
+ ## Step 5 — Draft titles and bodies
161
+
162
+ For each chosen repo, prepare a PR draft. Re-use these inputs:
163
+
164
+ - **Feature description** — first heading / first paragraph of `anvil/<slug>/CLAUDE.md`.
165
+ - **This repo's diff stat** — `git -C <worktree> diff --stat <base>...HEAD`.
166
+ - **This repo's commit log** — `git -C <worktree> log --oneline <base>..HEAD`.
167
+ - **Conventional Commits hints** — derive a `type(scope):` prefix from the diff
168
+ (`feat`, `fix`, `refactor`, `chore`, `docs`) and from any module-like directory name
169
+ that dominates the changes.
170
+
171
+ ### Title
172
+
173
+ ```
174
+ <type>(<scope>): <one-line summary derived from feature description>
175
+ ```
176
+
177
+ Examples:
178
+ - `feat(api): add new endpoint`
179
+ - `fix(worker): handle empty payloads`
180
+ - `refactor(ui): extract shared form components`
181
+
182
+ Keep titles under 72 chars. If the feature description is too long, summarize.
183
+
184
+ ### Body template
185
+
186
+ ```markdown
187
+ ## What
188
+
189
+ <2–4 sentence summary distilled from anvil/<slug>/CLAUDE.md.>
190
+
191
+ ## Why
192
+
193
+ <1–2 sentences on the motivation — pull from the "Why" line in the feature CLAUDE.md
194
+ if present, otherwise leave a placeholder for the user to fill in.>
195
+
196
+ ## How
197
+
198
+ <bullet list summarizing the commits and the diff stat for THIS repo only.>
199
+
200
+ ## Test plan
201
+
202
+ - [ ] <derived from the changes; if there are new tests in the diff, list them>
203
+ - [ ] <if there are no tests, leave an unchecked todo for the user>
204
+
205
+ ## Cross-repo
206
+
207
+ This PR is part of feature **`<slug>`**. Sibling PRs:
208
+ - {placeholder for org/repo#NUM — filled in once all PRs are created}
209
+
210
+ ---
211
+
212
+ 🤖 Drafted by `agentforge-pr-create`. Edit freely before requesting reviews.
213
+ ```
214
+
215
+ Show each draft to the user **before opening**. Let them edit titles or bodies in
216
+ place (offer a "looks good / let me edit X" prompt per PR or "edit all in chat
217
+ first").
218
+
219
+ ## Step 6 — Open the PRs
220
+
221
+ For each approved draft, run:
222
+
223
+ ```bash
224
+ gh pr create \
225
+ --repo <owner>/<repo> \
226
+ --base <base-branch> \
227
+ --head <branch> \
228
+ --title "<title>" \
229
+ --body "<body>" \
230
+ --draft # only if the user explicitly asked for drafts
231
+ ```
232
+
233
+ Capture the returned URL and the PR number for each repo.
234
+
235
+ If a PR for the same branch already exists, do **not** create a new one. Instead:
236
+ - Tell the user "PR #N already exists for this branch on `<repo>`."
237
+ - Offer to update its title / body (`gh pr edit`) — only with explicit confirmation.
238
+
239
+ ## Step 7 — Cross-link the PRs (including pre-existing ones)
240
+
241
+ After every PR is created or located, gather **the full set of sibling PRs for this
242
+ slug** — that includes:
243
+
244
+ - PRs you just created in this run.
245
+ - PRs that already existed for the same head branch (a previous run, or a
246
+ teammate's PR). Discover them per repo. The head branch is **whatever the
247
+ worktree's HEAD points to**, not necessarily the slug — `feature-start` lets
248
+ each repo follow its own branch-naming convention, so resolve it from git:
249
+ ```bash
250
+ branch=$(git -C anvil/<slug>/<repo> rev-parse --abbrev-ref HEAD)
251
+ gh -R <owner>/<repo> pr list --head "$branch" --state open \
252
+ --json number,url,headRefName,baseRefName
253
+ ```
254
+ If multiple PRs share the head branch, the most recent open one is the canonical
255
+ sibling for that repo.
256
+
257
+ Build a single sibling list `[<owner1>/<repo1>#<num1>, <owner2>/<repo2>#<num2>, ...]`,
258
+ then patch the `## Cross-repo` section of **every PR in the list**, not just the new
259
+ ones. This ensures that PRs opened earlier (when the feature only spanned a subset of
260
+ repos) get their cross-repo section updated to reflect the full current set.
261
+
262
+ For each sibling:
263
+
264
+ ```bash
265
+ # fetch current body
266
+ gh pr view <num> --repo <owner>/<repo> --json body --jq .body > /tmp/body.md
267
+
268
+ # replace (or insert) the "## Cross-repo" section, then:
269
+ gh pr edit <num> --repo <owner>/<repo> --body-file /tmp/updated.md
270
+ ```
271
+
272
+ Replacement rules for the Cross-repo block:
273
+ - Identify the existing `## Cross-repo` heading and replace everything from that
274
+ heading to the next `## ` (or end of file) with the new block.
275
+ - If no `## Cross-repo` heading exists, append the new block to the end.
276
+ - The block lists *other* siblings (not the PR itself). For PR `A`, the block lists
277
+ `B, C, ...` etc.
278
+ - Do not touch the rest of the body. Preserve user edits exactly.
279
+
280
+ This is the same flow for both first-time PR creation and later re-runs when a new
281
+ repo is added to the feature (via `agentforge-feature-start` in additive mode and
282
+ `agentforge-pr-create` re-run): every PR's Cross-repo section ends up reflecting the
283
+ current full set.
284
+
285
+ ## Step 8 — Report back (partial-failure aware)
286
+
287
+ PR creation can partially fail (auth, branch protection, network). Report
288
+ **explicitly per repo** with status: created / edited / skipped / failed.
289
+
290
+ ```
291
+ Feature `feat-search-ranking`:
292
+
293
+ ✓ backend-api → https://github.com/acme/backend-api/pull/412 (created)
294
+ ✓ admin-web → https://github.com/acme/admin-web/pull/88 (created)
295
+ ✗ worker-service failed: branch protection requires checks to pass first
296
+ ⏭ mobile-app skipped: no commits ahead
297
+
298
+ Cross-repo section patched on: backend-api#412, admin-web#88
299
+ Cross-repo section NOT patched on: worker-service (PR not created)
300
+ ```
301
+
302
+ For failures:
303
+ - State the underlying error verbatim (the gh stderr line).
304
+ - **Do not roll back successful PRs.** They're already public — that's the user's
305
+ call. Tell the user the retry path: re-run `agentforge-pr-create` and only the
306
+ failed/skipped repos will be candidates.
307
+ - The Cross-repo patch in Step 7 should still run for the PRs that did get created,
308
+ but exclude the failed ones from the sibling list (they don't exist).
309
+
310
+ ## Step 9 — PR summary
311
+
312
+ After all PRs are open (or even just one), print a single copy-paste-ready summary
313
+ block. **Strictly about the PRs themselves** — no greetings, no "please review", no
314
+ reviewer mentions, no deadlines, no addressing of any audience. Just the PRs.
315
+
316
+ Output format — plain text, portable to any chat or doc tool, wrapped in a fenced
317
+ code block so the user can copy verbatim:
318
+
319
+ ````
320
+ ```
321
+ [<slug>]
322
+
323
+ <repo-1> · #<num>
324
+ <pr-url>
325
+ What: <one-line summary of the change, from the PR title/body>
326
+ Why: <one-line motivation, from the PR body's "Why" section if present>
327
+ Changes:
328
+ - <bullet 1 — a meaningful change, not noise>
329
+ - <bullet 2>
330
+ - <bullet 3>
331
+ Diff: <N> files · +<added> / -<removed>
332
+
333
+ <repo-2> · #<num>
334
+ <pr-url>
335
+ What: ...
336
+ Why: ...
337
+ Changes:
338
+ - ...
339
+ Diff: ...
340
+ ```
341
+ ````
342
+
343
+ Notes for the body:
344
+ - **Labels (`What:`, `Why:`, `Changes:`, `Diff:`) stay in English** so the block
345
+ format is recognizable across teams. The **values after the colons are written
346
+ in the workspace's output language** — the same prose language used in the PR
347
+ body itself (Korean for a Korean workspace, etc.).
348
+ - **Pull `What` / `Why` from the PR body you just generated**, not from raw commit
349
+ messages. Strip markdown headings and trim to one sentence.
350
+ - **`Changes:` is 2–5 bullets max.** Group related commits; skip cosmetic or merge
351
+ commits. Each bullet should make sense to someone who has not seen the diff.
352
+ - **`Diff:` numbers** come from `git -C <worktree> diff --shortstat <base>...HEAD`.
353
+ - Repos appear in the order the user selected them.
354
+ - Keep it plain text — no emoji decorations, no Slack/markdown-specific syntax. The
355
+ user may be pasting into chat, a doc, a ticket, anywhere.
356
+
357
+ Print this block in the chat after the "Report back" output. Do not save it to a
358
+ file unless the user asks.
359
+
360
+ Tone check before printing: read your draft once and remove any phrasing that **asks**
361
+ for something or **addresses** the reader (e.g. "please review", "FYI", "let me
362
+ know"). The block must read as a pure status object describing the PRs.
363
+
364
+ ## Rules
365
+
366
+ - **Always confirm before pushing or creating.** PRs are externally visible. Show
367
+ drafts; require explicit "yes" before `gh pr create`.
368
+ - **Never force-push.** If push fails because the remote has diverging commits, stop
369
+ and report. Let the user decide how to reconcile.
370
+ - **Never auto-merge.** This skill only opens PRs. Reviewing and merging stays with
371
+ the user.
372
+ - **Never bypass branch protection.** If a base branch requires checks or specific
373
+ labels, just open the PR — don't try to game the rules.
374
+ - **Respect existing PRs.** If a PR already exists on the same head branch, edit
375
+ (with permission) instead of recreating.
376
+ - **One repo with no changes is not an error.** Just skip it silently with a note.
377
+ - **Match each PR body to that repo's diff** — do not paste the cross-repo summary as
378
+ if everything happened in one repo. Each PR reads as standalone first, then with
379
+ cross-references.
380
+ - **Conventional Commits is a hint, not a rule.** If the repo doesn't use them, drop
381
+ the prefix and use a plain title.
382
+
383
+ ## Activity log
384
+
385
+ After each successful PR action (created, edited, cross-link patched), append a
386
+ JSONL line to `<workspace>/agentforge/log.jsonl`:
387
+
388
+ ```bash
389
+ mkdir -p <workspace>/agentforge
390
+ printf '%s\n' "$(jq -nc \
391
+ --arg ts "$(date -u +%FT%TZ)" \
392
+ --arg skill agentforge-pr-create \
393
+ --arg slug '<slug>' \
394
+ --arg action '<created|edited|cross-linked>' \
395
+ --arg repo '<repo>' \
396
+ --arg pr '<pr-url-or-number>' \
397
+ '{ts:$ts, skill:$skill, slug:$slug, action:$action, repo:$repo, pr:$pr}')" \
398
+ >> <workspace>/agentforge/log.jsonl
399
+ ```
400
+
401
+ ## Output language
402
+
403
+ {{OUTPUT_LANGUAGE_INSTRUCTION}}