Skip to content

Commit bc2170d

Browse files
committed
feat(AI-81): author stage-chapters SKILL.md scaffold
Adds skills/stage-chapters/SKILL.md at the repo root with vercel-labs/skills frontmatter, prerequisites (stage-cli + git repo checks), base ref detection (origin/HEAD → main → master), merge-base diff retrieval, JSON-shape documentation matching ChaptersFileSchema, and the final stage-cli show step. Step 3 (cluster + narrate) is left as a TODO pointing at Issue 11.
1 parent f5d23d8 commit bc2170d

1 file changed

Lines changed: 158 additions & 0 deletions

File tree

skills/stage-chapters/SKILL.md

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
---
2+
name: stage-chapters
3+
description: Generate Stage chapters for the current local git branch and open them in a browser for review.
4+
user-invocable: true
5+
---
6+
7+
# stage-chapters
8+
9+
Generates a Stage chapter run for the current local git branch and opens it in a browser. The skill detects the base ref, computes the diff, generates chapters from it, writes a JSON file matching the `stage-cli` schema, and hands the file to `stage-cli show` to launch the SPA.
10+
11+
## Prerequisites
12+
13+
Run these checks before any other work. If either fails, stop with the error message — do not continue.
14+
15+
1. **`stage-cli` is installed.** Run `which stage-cli`. If it exits non-zero, instruct the user:
16+
17+
```
18+
stage-cli is not installed. Run:
19+
20+
npm install -g stage-cli
21+
22+
Then retry /stage-chapters.
23+
```
24+
25+
Stop.
26+
27+
2. **The current directory is a git repo.** Run `git rev-parse --is-inside-work-tree`. If it does not print `true`, stop with:
28+
29+
```
30+
/stage-chapters must be run inside a git repository.
31+
```
32+
33+
## Step 1 — Detect base ref
34+
35+
Find the branch the user reviews against. Try each of the following in order; use the first that succeeds:
36+
37+
1. `git rev-parse --verify origin/HEAD 2>/dev/null` — typically resolves to `refs/remotes/origin/main`. Strip the leading `refs/remotes/origin/` to recover the bare base name.
38+
2. `git rev-parse --verify main` — fall back to a local `main` branch.
39+
3. `git rev-parse --verify master` — final fallback for older repos.
40+
41+
If all three fail, stop with:
42+
43+
```
44+
No default branch detected. Tried origin/HEAD, main, and master.
45+
```
46+
47+
Save the resolved base name (e.g. `main`) as `<base>` for the next steps.
48+
49+
## Step 2 — Get the diff
50+
51+
Compute the merge-base, capture the relevant SHAs, and dump the unified diff:
52+
53+
```bash
54+
MERGE_BASE=$(git merge-base <base> HEAD)
55+
BASE_SHA=$(git rev-parse <base>)
56+
HEAD_SHA=$(git rev-parse HEAD)
57+
58+
git diff "$MERGE_BASE"..
59+
```
60+
61+
The trailing `..` is intentional — it includes working-tree changes for tracked files alongside committed changes on the branch. Save the full diff text into context for Step 3.
62+
63+
`BASE_SHA`, `HEAD_SHA`, and `MERGE_BASE` are full 40-character SHAs and feed directly into the JSON `scope` field in Step 4.
64+
65+
## Step 3 — Cluster + narrate
66+
67+
> **TODO:** See Issue 11 for the chapter generation prompt port. For now, leave this step as a placeholder. The next revision of this skill will produce a `chapters` array shaped per the schema documented in Step 4.
68+
69+
## Step 4 — Write JSON file
70+
71+
Compute a unique temp path. Epoch nanoseconds keep concurrent runs from colliding:
72+
73+
```bash
74+
TMPFILE="${TMPDIR:-/tmp}/stage-chapters-$(date +%s%N).json"
75+
```
76+
77+
The `${TMPDIR:-/tmp}` fallback matters on macOS, where `os.tmpdir()` resolves to `/var/folders/...` but `$TMPDIR` is not always set in every shell.
78+
79+
Write a JSON file at `"$TMPFILE"` matching the shape below. The file must validate against `ChaptersFileSchema` in `packages/cli/src/schema.ts`; mismatched fields will be rejected by `stage-cli show`.
80+
81+
High-level shape:
82+
83+
```
84+
{ scope: {...}, chapters: [...], generatedAt: "..." }
85+
```
86+
87+
Full example:
88+
89+
```jsonc
90+
{
91+
"scope": {
92+
// Either committed (no working-tree changes):
93+
"kind": "committed",
94+
"baseSha": "<40-char SHA>",
95+
"headSha": "<40-char SHA>",
96+
"mergeBaseSha": "<40-char SHA>"
97+
98+
// Or workingTree (when the diff includes uncommitted tracked changes):
99+
// "kind": "workingTree",
100+
// "ref": "work" | "staged" | "unstaged",
101+
// "baseSha": "<40-char SHA>",
102+
// "headSha": "<40-char SHA>",
103+
// "mergeBaseSha": "<40-char SHA>"
104+
},
105+
"chapters": [
106+
{
107+
"id": "ch-1",
108+
"order": 1,
109+
"title": "Short imperative title",
110+
"summary": "Why this chapter matters to the reviewer.",
111+
"hunkRefs": [
112+
{ "filePath": "path/to/file.ts", "oldStart": 42 }
113+
],
114+
"keyChanges": [
115+
{
116+
"content": "A judgment-call question for the reviewer (not source code).",
117+
"lineRefs": [
118+
{
119+
"filePath": "path/to/file.ts",
120+
"side": "additions",
121+
"startLine": 50,
122+
"endLine": 55
123+
}
124+
]
125+
}
126+
]
127+
}
128+
],
129+
"generatedAt": "2026-05-04T12:34:56.000Z"
130+
}
131+
```
132+
133+
Field rules:
134+
135+
| Field | Constraint |
136+
|-------|------------|
137+
| `scope.kind` | `"committed"` or `"workingTree"` |
138+
| `scope.ref` | Required when `kind` is `"workingTree"`; one of `"work"`, `"staged"`, `"unstaged"` |
139+
| `scope.baseSha` / `headSha` / `mergeBaseSha` | Full 40-character lowercase hex SHAs |
140+
| `chapters[].id` | Non-empty, unique within the run |
141+
| `chapters[].order` | Positive integer (1-indexed) |
142+
| `chapters[].hunkRefs[].oldStart` | Non-negative integer — the pre-image start line from the unified-diff `@@` header (`0` for new files) |
143+
| `chapters[].keyChanges[].lineRefs` | Array with at least one entry |
144+
| `lineRefs[].side` | `"additions"` (right side) or `"deletions"` (left side) |
145+
| `lineRefs[].startLine` / `endLine` | Positive integers; `endLine >= startLine` |
146+
| `generatedAt` | ISO 8601 datetime string |
147+
148+
## Step 5 — Display generated chapters
149+
150+
Hand the file to `stage-cli`:
151+
152+
```bash
153+
stage-cli show "$TMPFILE"
154+
```
155+
156+
`stage-cli show` validates the JSON, inserts a new `chapter_run` plus chapters and key changes into the local SQLite database, boots a loopback HTTP server, and opens the browser to the new run. The command stays running and serves the SPA until the user kills it with Ctrl+C — invoke it as the final command in the workflow rather than expecting it to print a value and exit.
157+
158+
Do not pass a `runId` and do not call a separate `stage-cli ingest`. `show <path>` does ingestion and serving in one step.

0 commit comments

Comments
 (0)