@open-tomato/rafa 0.17.0 → 0.18.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.
- package/NOTICE +9 -1
- package/README.md +27 -16
- package/dist/bundled/agents/build-error-resolver.md +144 -0
- package/dist/bundled/agents/code-reviewer.md +335 -0
- package/dist/bundled/agents/doc-updater.md +108 -0
- package/dist/bundled/agents/loop-implementer.md +57 -0
- package/dist/bundled/agents/qa-bug-reporter.md +164 -0
- package/dist/bundled/agents/tdd-guide.md +121 -0
- package/dist/bundled/bin/ts-symbols +272 -0
- package/dist/{SKILL.md → bundled/skills/dev-planner/SKILL.md} +5 -5
- package/dist/bundled/skills/documentation/SKILL.md +93 -0
- package/dist/bundled/skills/git-workflow/SKILL.md +242 -0
- package/dist/bundled/skills/ts-symbols/SKILL.md +82 -0
- package/dist/cli.js +4779 -3810
- package/dist/{describe-wbn759vf.js → describe-vq037dyt.js} +3 -3
- package/dist/effort/store/index.js +4 -4
- package/dist/{index-64wec0k7.js → index-0pdsq2hy.js} +2 -2
- package/dist/{index-4qd537z6.js → index-6vkd153j.js} +3291 -1282
- package/dist/{index-n3rw8rhr.js → index-944pncd8.js} +69 -1
- package/dist/{index-7t0qz29r.js → index-at9f1z2z.js} +17 -11
- package/dist/{index-r7cnr44m.js → index-cvpdvmtg.js} +1259 -2616
- package/dist/{index-p901zs2p.js → index-ddf85qac.js} +1 -1
- package/dist/{index-ps5sac9p.js → index-jva32qe6.js} +252 -7
- package/dist/{index-qzhpqmfy.js → index-kvnggvyk.js} +2 -2
- package/dist/index.js +7 -7
- package/dist/plan/index.js +3 -3
- package/dist/plan-prompt.md +2 -0
- package/package.json +2 -2
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: documentation
|
|
3
|
+
description: "Use when writing TSDoc, wiring TypeDoc, documenting a route with OpenAPI, or choosing between `.docs/` and `docs/`."
|
|
4
|
+
provenance: first-party
|
|
5
|
+
tags:
|
|
6
|
+
- tsdoc
|
|
7
|
+
- typedoc
|
|
8
|
+
- openapi
|
|
9
|
+
- swagger
|
|
10
|
+
- express
|
|
11
|
+
- mcp
|
|
12
|
+
- react
|
|
13
|
+
prevents: undocumented code and a docs command that wipes the tracked docs tree while exiting clean
|
|
14
|
+
signal: silent
|
|
15
|
+
when_to_use: "You are writing TSDoc, wiring documentation tooling, or deciding where a new document belongs. Prevents: undocumented code and a docs command that wipes the tracked docs tree while exiting clean"
|
|
16
|
+
stack:
|
|
17
|
+
- typescript
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
> Scope: file paths in this document are relative to `packages/service/` (the `@ar/service` package), except `.claude/`, the plans directory, the specs directory, and `tools/`, which live at the umbrella repo root.
|
|
21
|
+
|
|
22
|
+
# Documentation Skill
|
|
23
|
+
|
|
24
|
+
This skill defines how to document code in this repo.
|
|
25
|
+
Two kinds of documentation are maintained:
|
|
26
|
+
|
|
27
|
+
| Kind | Tool | Output | When to generate |
|
|
28
|
+
| --- | --- | --- | --- |
|
|
29
|
+
| **Code (TypeDoc)** | `typedoc` | typedoc's default `out`, which resolves to the TRACKED `docs/` tree | `bun run docs:generate` |
|
|
30
|
+
| **API (Swagger)** | `@asteasolutions/zod-to-openapi` + `swagger-ui-express` | `openapi.json` + served behind `ctx.requireAuth` at `GET /docs/` | `bun run docs:openapi` |
|
|
31
|
+
|
|
32
|
+
> Both rows are INSTALLED in `@ar/service` — the OpenAPI half is no longer a
|
|
33
|
+
> convention to adopt on some later day, and [`rules/openapi.md`](rules/openapi.md)
|
|
34
|
+
> records what is there rather than a setup to perform. The two scripts are
|
|
35
|
+
> SIBLINGS sharing no output tree, which is worth stating because the pair of
|
|
36
|
+
> names suggests they do: `docs:openapi` writes the gitignored `.docs/swagger/`,
|
|
37
|
+
> while `docs:generate` is a bare `typedoc` carrying no `typedoc.json` and no
|
|
38
|
+
> `typedocOptions` key in either `package.json` or `tsconfig.json` — all three
|
|
39
|
+
> measured absent — so it takes typedoc's own default `out`, the TRACKED `docs/`
|
|
40
|
+
> tree beside it, with `cleanOutputDir` defaulting true. Running it therefore
|
|
41
|
+
> DELETES that tree before writing (measured once at typedoc 0.28.20: 14 tracked
|
|
42
|
+
> files removed, at exit 0, for a site documenting nothing).
|
|
43
|
+
|
|
44
|
+
Manual documentation (ADRs, design notes) lives in `docs/` and is never gitignored.
|
|
45
|
+
Auto-generated outputs go in `.docs/` (dotfolder) and are always gitignored.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Rules index
|
|
50
|
+
|
|
51
|
+
| Rule file | When to use |
|
|
52
|
+
| --- | --- |
|
|
53
|
+
| [`rules/tsdoc.md`](rules/tsdoc.md) | Writing TSDoc comments on any TypeScript symbol |
|
|
54
|
+
| [`rules/openapi.md`](rules/openapi.md) | Documenting Express routes with OpenAPI/Swagger |
|
|
55
|
+
| [`rules/typedoc-setup.md`](rules/typedoc-setup.md) | Adding TypeDoc infra to the repo (or a project derived from it) |
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## Workflow
|
|
60
|
+
|
|
61
|
+
1. **Determine kind before touching**: identify whether documentation is manual or auto-generated before editing. Manual docs live in `docs/`; auto-generated outputs live in `.docs/`.
|
|
62
|
+
2. **Manual docs**: include author and date in the file header. Never gitignore `docs/`.
|
|
63
|
+
3. **Auto-generated docs**: outputs go in `.docs/` (dotfolder). If adding a new documentation tool, add its output folder to `.gitignore`.
|
|
64
|
+
4. **Update in parallel**: update documentation before or in parallel with code changes — do not defer docs to a follow-up PR.
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Quick checklist
|
|
69
|
+
|
|
70
|
+
Before marking a documentation task done:
|
|
71
|
+
|
|
72
|
+
- [ ] Every exported function, class, and interface has a TSDoc block with `@param` and `@returns`.
|
|
73
|
+
- [ ] Every file has a `@packageDocumentation` comment (or is covered by a module-level JSDoc).
|
|
74
|
+
- [ ] Every Express router factory is documented with `@remarks` listing its HTTP endpoints.
|
|
75
|
+
- [ ] `typedoc.json`, `tsconfig.docs.json`, and a `docs:generate` script exist (see [`rules/typedoc-setup.md`](rules/typedoc-setup.md)).
|
|
76
|
+
- [ ] `openapi.ts` exists and every route is registered in it — `openapi-coverage.test.ts` is the gate that says so, and a route added without a binding-table entry reddens it.
|
|
77
|
+
- [ ] `.docs/` is already gitignored twice over and needs no new entry: once at the repo root (`.gitignore`) and again at the package (`packages/service/.gitignore`), both files tracked. Running `git check-ignore -v` on the generated `openapi.json` names the PACKAGE rule, the nearer file winning — take the source off that output rather than predicting it.
|
|
78
|
+
- [ ] `docs/` (manual ADRs) is **not** gitignored.
|
|
79
|
+
- [ ] `bun run docs:openapi` passes with 0 errors. Do NOT reach for `bun run docs:generate` as a verification: it exits 0 while WIPING the tracked `docs/` tree (see the note under the table above).
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Toolchain
|
|
84
|
+
|
|
85
|
+
```text
|
|
86
|
+
typedoc → HTML docs from TSDoc comments → the TRACKED docs/ tree
|
|
87
|
+
@asteasolutions/zod-to-openapi → OpenAPI document from the Zod schemas the routes parse with
|
|
88
|
+
swagger-ui-express → serves that document behind ctx.requireAuth at GET /docs/
|
|
89
|
+
export-openapi.ts → writes openapi.json, via bun run docs:openapi
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Dependencies go in `devDependencies` where the toolchain is only ever a test's or a generator's — `@seriousme/openapi-schema-validator`, `@types/swagger-ui-express` and `typedoc` are all there.
|
|
93
|
+
BOTH OpenAPI runtime halves sit in `dependencies` instead, and not just `swagger-ui-express`: `src/index.ts` imports `generateOpenApiDocument` at boot to build the document it serves, so `@asteasolutions/zod-to-openapi` is a runtime dependency too.
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: git-workflow
|
|
3
|
+
description: "Use when pushing a branch, opening or updating a PR, naming a branch, rebasing, or force-pushing after a rebase."
|
|
4
|
+
provenance: first-party
|
|
5
|
+
prevents: duplicate PRs and outbound PR bodies published with leaked references and wrong diff counts
|
|
6
|
+
signal: silent
|
|
7
|
+
when_to_use: "You are naming a branch, pushing it, opening or updating a pull request, or recovering from a rebase. Prevents: duplicate PRs and outbound PR bodies published with leaked references and wrong diff counts"
|
|
8
|
+
tags:
|
|
9
|
+
- git
|
|
10
|
+
- workflow
|
|
11
|
+
- javascript
|
|
12
|
+
- shell
|
|
13
|
+
stack:
|
|
14
|
+
- javascript
|
|
15
|
+
- shell
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
# Git Workflow
|
|
19
|
+
|
|
20
|
+
## Branch, commit, and PR conventions
|
|
21
|
+
|
|
22
|
+
**Branch names:** `<type>/<issue-number>-<slug>` when the work is tied to a
|
|
23
|
+
GitHub issue — e.g. `feat/42-user-auth` — and plain `<type>/<slug>` otherwise.
|
|
24
|
+
`<type>` is one of the conventional-commit types (`feat fix chore docs
|
|
25
|
+
refactor test perf ci spike`).
|
|
26
|
+
|
|
27
|
+
**Commits** follow conventional commits: `type(scope): subject`.
|
|
28
|
+
|
|
29
|
+
**PR bodies** link the issue with GitHub's closing keywords: `Closes #42` for
|
|
30
|
+
a PR that finishes the issue, or `Refs #42` for one that only partially
|
|
31
|
+
addresses it. This distinction is load-bearing: only `Closes` triggers
|
|
32
|
+
GitHub's auto-close on merge. Working without an issue is fine — such a PR
|
|
33
|
+
simply carries no issue link; do not invent one to satisfy the convention.
|
|
34
|
+
|
|
35
|
+
### rafa project naming convention
|
|
36
|
+
|
|
37
|
+
For the rafa project specifically, issue numbers are prefixed with `rafa-` and
|
|
38
|
+
reflected throughout the spec and branch workflow:
|
|
39
|
+
|
|
40
|
+
- **Issue reference** (in prose): `#rafa-<n>` — e.g., `#rafa-20`
|
|
41
|
+
- **Spec file**: `.rafa/specs/rafa-<n>-<slug>.md` — e.g., `.rafa/specs/rafa-20-pr-commands.md`
|
|
42
|
+
- **Plan stub** (in prose): `rafa-<n>-<slug>` — e.g., `rafa-20-pr-commands`
|
|
43
|
+
- **Branch name**: `feat/rafa-<n>-<slug>` — e.g., `feat/rafa-20-pr-commands`
|
|
44
|
+
- **PR title**: `rafa-<n>: <title>` — e.g., `rafa-20: Add PR commands`
|
|
45
|
+
- **PR body closing line**: `Closes #<n>` — e.g., `Closes #20` (GitHub issue #20, not
|
|
46
|
+
`#rafa-20`; the prefix is a rafa naming convention, not a GitHub issue alias)
|
|
47
|
+
|
|
48
|
+
## Pushing and opening PRs
|
|
49
|
+
|
|
50
|
+
When pushing changes and creating PRs:
|
|
51
|
+
|
|
52
|
+
1. Always check if the branch has been pushed before. If not, use `git push -u` to set the upstream tracking branch on the first push. This ensures that future pushes and `gh pr create` commands work smoothly without needing to specify the remote/branch each time.
|
|
53
|
+
2. If the branch already has an associated PR, push to whichever remote the branch is tracking.
|
|
54
|
+
3. If the branch hasn't been pushed before, default to pushing to `origin`.
|
|
55
|
+
|
|
56
|
+
## PR-body close-out discipline (measured, this repo)
|
|
57
|
+
|
|
58
|
+
A PR body is the one piece of prose here that is OUTBOUND, unreviewable by any
|
|
59
|
+
gate, and irreversible once `gh pr create` returns. Four checks, all cheap:
|
|
60
|
+
|
|
61
|
+
1. **Sweep it for origin needles before the push.** `findForbiddenMatches(content,
|
|
62
|
+
path)` takes CONTENT, so one /tmp `.mjs` under bun can feed it the body file
|
|
63
|
+
alongside `git ls-files`, with a fragment-built planted control in the same run.
|
|
64
|
+
Re-run it immediately before `gh pr create` — a close-out sweep ordered ahead
|
|
65
|
+
of the tasks that finish the body swept a draft nobody will publish.
|
|
66
|
+
2. **Pre-flight with a control.** `gh pr list --head <branch> --state all` returning
|
|
67
|
+
nothing is a zero-hit scan; bare `--state open`, or `gh pr view`, both miss a
|
|
68
|
+
CLOSED prior PR on the same head. Send a known-existing head through the
|
|
69
|
+
IDENTICAL command shape in the same call so the empty result is readable.
|
|
70
|
+
Without it, a broken filter is indistinguishable from "no PR yet" — and the
|
|
71
|
+
consequence is a duplicate PR. The control's PR must be CLOSED or MERGED, not
|
|
72
|
+
merely one that HAS a PR: `--state all` exists precisely because the open-only
|
|
73
|
+
form misses a non-open prior PR, so an OPEN control proves only that the
|
|
74
|
+
command can find something and says nothing about the half whose failure
|
|
75
|
+
produces the duplicate. Measured opening one PR, the subject printed `<none>`
|
|
76
|
+
beside `25 MERGED` and `11 CLOSED` from two known heads.
|
|
77
|
+
3. **Re-read the REMOTE after creating.** The sweep proves the FILE is clean; only
|
|
78
|
+
`gh pr view <n> --json body -q .body` diffed against the swept file (normalise
|
|
79
|
+
CRLF and the trailing newline) proves the swept bytes are the published ones.
|
|
80
|
+
It is the only check that catches a `--body-file` pointed at a stale draft.
|
|
81
|
+
4. **Hold the four numbers three-dot, against the REMOTE base.** GitHub computes
|
|
82
|
+
`additions`/`deletions`/`changedFiles` from the base branch as the REMOTE has
|
|
83
|
+
it, so the local side is
|
|
84
|
+
`git diff --numstat $(git merge-base origin/main HEAD)..HEAD` summed after a
|
|
85
|
+
fetch — never `main..HEAD` two-dot, which drifts the moment main moves, and
|
|
86
|
+
never local `main` without checking. PRINT the local and remote merge-bases
|
|
87
|
+
against each other rather than assuming they agree: measured at one tip, local
|
|
88
|
+
`main` was 62 commits BEHIND `origin/main` (an ancestor, not diverged) while
|
|
89
|
+
both merge-bases with HEAD still resolved to the SAME commit — a coincidence
|
|
90
|
+
that would not survive the local branch moving past the fork point, and a
|
|
91
|
+
diverged local `main` otherwise attributes somebody else's commits to this
|
|
92
|
+
PR's diff with every number still looking plausible. Sum `--numstat`, not
|
|
93
|
+
`--shortstat`, so a binary file shows as `-` instead of silently contributing
|
|
94
|
+
zero, and report the binary count beside the totals. Read the commits list's
|
|
95
|
+
LAST oid against `git rev-parse HEAD` beside the counts: a count can agree
|
|
96
|
+
while the head differs.
|
|
97
|
+
5. **A CONFLICTING PR schedules NO workflow run at all**, so `gh pr checks <n>`
|
|
98
|
+
printing `no checks reported` is ambiguous between a run that has not
|
|
99
|
+
scheduled yet and one that never will. GitHub builds a `pull_request` run
|
|
100
|
+
against `refs/pull/<n>/merge`, which it cannot create for a PR that does not
|
|
101
|
+
merge cleanly — so the reading is a ref existence check, not a guess:
|
|
102
|
+
`git ls-remote origin 'refs/pull/<n>/*'` answers `head` alone where a
|
|
103
|
+
MERGEABLE control PR answers `head` AND `merge`. That ref check is the
|
|
104
|
+
WHOLE reading and `mergeable` is only a corroborator, because GitHub
|
|
105
|
+
computes mergeability lazily and `gh` does not poll for it: measured
|
|
106
|
+
opening one PR, the subject answered `CONFLICTING` while BOTH mergeable
|
|
107
|
+
control PRs answered `UNKNOWN` and still exposed `refs/pull/<n>/merge`.
|
|
108
|
+
So `UNKNOWN` beside a present merge ref is the HEALTHY shape, not a
|
|
109
|
+
second finding — never let it stand in for the ref check. Name the
|
|
110
|
+
conflict set with
|
|
111
|
+
`git merge-tree --write-tree --name-only origin/main HEAD`, which
|
|
112
|
+
changes no worktree state. Parse it carefully: its FIRST line is the
|
|
113
|
+
written TREE OID, so a probe reading the whole block as paths reports a
|
|
114
|
+
40-hex string as a conflicting file. The name list is the CONFLICT set
|
|
115
|
+
and not the changed-file set (the narrative below it carries
|
|
116
|
+
`Auto-merging <path>` lines for files that merged cleanly), and exit 1
|
|
117
|
+
is the signal rather than an error. Exit 1 has TWO causes though, a real
|
|
118
|
+
conflict or a failed invocation, so a CLEAN exit 0 is only worth trusting
|
|
119
|
+
beside a liveness control: build a two-sided conflict from loose objects
|
|
120
|
+
in a scratch repository (`git hash-object -w`, `git mktree`,
|
|
121
|
+
`git commit-tree` — no ref moved, no working tree touched), read it
|
|
122
|
+
through the same command, and confirm it answers exit 1 with a `CONFLICT`
|
|
123
|
+
line before believing the subject's exit 0. Do NOT rebase to clear it as an
|
|
124
|
+
afterthought inside a PR task: every commit oid moves, and a body whose
|
|
125
|
+
suite figures were measured at the pre-rebase tip stops describing the
|
|
126
|
+
head it is attached to.
|
|
127
|
+
|
|
128
|
+
**Every suite figure in the body must come from a run at the PR's OWN head.** A
|
|
129
|
+
loop that commits per task makes all plausible sources disagree and each was
|
|
130
|
+
correct when written (measured 679, then 690, then 692 cases across one plan, no
|
|
131
|
+
regression). Read the `pretest` stamp in the same capture, so the run is
|
|
132
|
+
simultaneously the artifact-freshness check and the proof the tree is publishable.
|
|
133
|
+
|
|
134
|
+
**Where the branch is carried-in red**, the hosted gate confirms the body's red
|
|
135
|
+
claim and is simultaneously NOT evidence about its suite figures: `back.yml` runs
|
|
136
|
+
the type-check before the suite under `bash -e`, so the job halts and vitest never
|
|
137
|
+
runs. Report both halves, or a reader seeing a red `test` job assumes the suite
|
|
138
|
+
is what failed.
|
|
139
|
+
|
|
140
|
+
## `gh pr create` branch detection
|
|
141
|
+
|
|
142
|
+
If `gh pr create` says `you must first push the current branch to a remote` even though `git push -u` succeeded, create the PR with an explicit head ref:
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
gh pr create --head <owner>:<branch> ...
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## `gh issue close --reason` takes two words
|
|
149
|
+
|
|
150
|
+
`--reason` accepts only `completed` and `not planned`, and `not planned` is
|
|
151
|
+
two words: written bare, `gh` parses `planned` as a positional argument and
|
|
152
|
+
the close fails. Quote it.
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
gh issue close <n> --reason "not planned" --comment "<why>"
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## GITHUB_TOKEN and workflow chaining
|
|
159
|
+
|
|
160
|
+
Actions performed using the default `GITHUB_TOKEN` (including labels added by `github-actions[bot]` via `actions/github-script`) do **not** trigger `pull_request_target` or other workflow events. This is a GitHub limitation to prevent infinite loops. If one workflow adds a label that should trigger another workflow (e.g., a labeling workflow adds `cc:rebase` to trigger a rebase workflow), the label-adding step must use a **PAT** or **GitHub App token** (e.g., a `PR_RW_GITHUB_TOKEN` secret) instead of `GITHUB_TOKEN`.
|
|
161
|
+
|
|
162
|
+
## GitHub API calls with special characters
|
|
163
|
+
|
|
164
|
+
When using `gh api` to post comments or replies containing backticks, `$()`, or other shell metacharacters, security hooks may block the command. Instead of passing the body inline with `-f body="..."`, write a JSON file and use `--input`:
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
# Write JSON body to a scratch file (use the Write tool, not echo/cat),
|
|
168
|
+
# somewhere untracked such as reply_body.json under a tmp/ directory
|
|
169
|
+
# {"body": "Your comment with `backticks` and special chars"}
|
|
170
|
+
|
|
171
|
+
gh api repos/${GH_ORG}/${GH_REPO_NAME}/pulls/123/comments/456/replies --input reply_body.json
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## Force-pushing after rebase with changes ahead and behind head
|
|
175
|
+
|
|
176
|
+
When rebasing a PR branch that has both new commits in the PR and new commits in upstream/main (i.e., the branch is both ahead and behind), the rebase will create a new commit history that doesn't match the existing remote branch. In this case, you must force-push to update the PR branch with the rebased commits. Use `--force-with-lease` to avoid overwriting others' work, but if the branch is tracking a different remote (e.g., `origin` instead of `upstream`), and the solution is plain `--force` do not execute. The allowed force push command in this scenario is:
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
git push --force-with-lease
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
**Note:** Plain `--force` can overwrite others' remote commits. Inform the team when this scenario comes up, and `--force-with-lease` cannot work. In normal setups, always prefer `--force-with-lease`.
|
|
184
|
+
|
|
185
|
+
## Rebase workflow and conflict resolution
|
|
186
|
+
|
|
187
|
+
### Handling unstaged changes during rebase
|
|
188
|
+
|
|
189
|
+
If `git rebase` fails with "You have unstaged changes" (common with spurious `package-lock.json` changes):
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
git stash push -m "Stashing changes before rebase"
|
|
193
|
+
git rebase origin/main
|
|
194
|
+
git stash pop
|
|
195
|
+
```
|
|
196
|
+
The stashed changes will be automatically merged back after the rebase completes.
|
|
197
|
+
|
|
198
|
+
**Note:** **Always** use `git stash pop` to restore a single stash after the rebase, rather than `git stash apply`, to avoid accidentally applying stash leftovers or the same stash multiple times if you need to rebase again.
|
|
199
|
+
|
|
200
|
+
## Rebasing with uncommitted changes
|
|
201
|
+
|
|
202
|
+
If you need to rebase but have uncommitted changes (e.g., package-lock.json from startup npm install):
|
|
203
|
+
|
|
204
|
+
1. Stash changes: `git stash push -m "Stash changes before rebase"`
|
|
205
|
+
2. Rebase: `git rebase origin/main` (resolve conflicts if needed)
|
|
206
|
+
3. After rebase completes, review stashed changes: `git stash show -p`
|
|
207
|
+
4. If stashed changes are spurious (e.g., package-lock.json peer markers when package.json conflicts were resolved during rebase), drop the stash: `git stash drop`
|
|
208
|
+
5. Otherwise, pop stash: `git stash pop` and discard spurious changes: `git restore package-lock.json` (if package.json unchanged)
|
|
209
|
+
|
|
210
|
+
This prevents rebase conflicts from uncommitted changes while preserving any work in progress.
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
### Conflict resolution tips
|
|
214
|
+
|
|
215
|
+
- **Modify/delete conflicts**: When a rebase shows `CONFLICT (modify/delete): <file> deleted in <commit> and modified in HEAD`, use `git rm <file>` (not `git add`) to resolve by confirming the deletion. Use `git add <file>` only when you want to keep the modified version instead.
|
|
216
|
+
- **Before rebasing:** If `bun install` modified `package-lock.json` (common in CI/local), discard changes with `git restore package-lock.json` to avoid "unstaged changes" errors
|
|
217
|
+
- When resolving import conflicts (e.g., `<<<<<<< HEAD` with different imports), keep **both** imports if both are valid and needed by the component
|
|
218
|
+
- If both sides of a conflict have valid imports/hooks, keep both and remove any duplicate constant redefinitions
|
|
219
|
+
- **Complementary additions**: When both sides added new sections at the end of a file (e.g., both added different documentation tips), keep both sections rather than choosing one — they're not truly conflicting, just different additions
|
|
220
|
+
- **Preserve variable declarations used in common code**: When one side of a conflict declares a variable (e.g., `const iframe = po.previewPanel.getPreviewIframeElement()`) that is referenced in non-conflicting code between or after conflict markers, keep the declaration even when adopting the other side's verification approach — the variable is needed regardless of which style you choose
|
|
221
|
+
- **React component wrapper conflicts**: When rebasing UI changes that conflict on wrapper div classes (e.g., `flex items-start space-x-2` vs `flex items-end gap-1`), keep the newer styling from the incoming commit but preserve any functional components (like dialogs or modals) that exist in HEAD but not in the incoming change
|
|
222
|
+
- **Refactoring conflicts**: When incoming commits refactor code (e.g., extracting inline logic into helper functions), and HEAD has new features in the same area, integrate HEAD's features into the new structure. Example: if incoming code moves streaming logic to `runSingleStreamPass()` and HEAD adds mid-turn compaction to the inline code, add compaction support to the new function rather than keeping the old inline version
|
|
223
|
+
|
|
224
|
+
## Git orphan branch pitfalls
|
|
225
|
+
|
|
226
|
+
- **`git checkout -` does not work after `git checkout --orphan`** — git does not record the pre-orphan branch in a way that `-` can resolve. Always capture the current branch before switching: `PREV=$(git branch --show-current)`, then return explicitly with `git checkout "$PREV"`.
|
|
227
|
+
- **Orphan commits break pre-commit hooks that reference `HEAD^1`** — a hook that diffs or lints against the parent commit fails with `fatal: ambiguous argument 'HEAD^1'` on a root commit. Hooks that require a parent commit are incompatible with orphan branches.
|
|
228
|
+
- **`git checkout <branch>` after staging on a side branch discards untracked working-tree files** — when you commit untracked files on branch B and then `git checkout A`, git restores the working tree to branch A's HEAD, removing any files that were committed on B but never existed on A. This affects both orphan branches and regular side branches used as checkpoint mechanisms — all accumulated task output files vanish on checkout-back.
|
|
229
|
+
|
|
230
|
+
## Shallow clone push limitations
|
|
231
|
+
|
|
232
|
+
- **"shallow update not allowed" when pushing to an empty remote** — a shallow clone can only push to a remote that already has the shallow boundary commit in its history. Pushing a tag or branch from `git clone --depth 1` to a bare repo with no objects fails. Fix: use the project's existing `origin` (which has full history), not a new empty remote. `git fetch --unshallow` makes the clone full but is expensive and defeats the depth-1 optimization.
|
|
233
|
+
- **All git refs in an ephemeral shallow clone are ephemeral** — if a cleanup step destroys the clone's directory, every pack object, tag, and branch goes with it. Refs must be pushed to the origin remote (which has the shallow boundary) before teardown if they need to survive.
|
|
234
|
+
|
|
235
|
+
## Tracking Tasks
|
|
236
|
+
|
|
237
|
+
1. **Commit often** with clear, descriptive messages following conventional commits format.
|
|
238
|
+
2. **Do not** include AI attribution in commit messages.
|
|
239
|
+
3. **Do not** create PRs without passing tests and lint checks — run all relevant tools first.
|
|
240
|
+
4. Follow [Branch, commit, and PR conventions](#branch-commit-and-pr-conventions)
|
|
241
|
+
above for branch names and PR bodies — nothing automates it here, so write
|
|
242
|
+
the `Closes #n` / `Refs #n` line by hand when the work is tied to an issue.
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ts-symbols
|
|
3
|
+
provenance: first-party
|
|
4
|
+
description: "Project-aware TypeScript symbol queries from the shell: definition, references, resolved type, outline."
|
|
5
|
+
prevents: a grep-based symbol sweep that misses re-exports and aliases while matching same-named strangers
|
|
6
|
+
signal: silent
|
|
7
|
+
when_to_use: "Use when tracing a TypeScript or JavaScript symbol from a shell — its definition, its references, its resolved type, or a file's exports — and the name is too overloaded, re-exported, or aliased for grep to answer. Prevents: a grep-based symbol sweep that misses re-exports and aliases while matching same-named strangers"
|
|
8
|
+
tags:
|
|
9
|
+
- ts
|
|
10
|
+
- symbols
|
|
11
|
+
- javascript
|
|
12
|
+
- shell
|
|
13
|
+
- typescript
|
|
14
|
+
stack:
|
|
15
|
+
- javascript
|
|
16
|
+
- shell
|
|
17
|
+
- typescript
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
# ts-symbols: TypeScript symbol queries from the shell
|
|
21
|
+
|
|
22
|
+
CLI wrapper around the TypeScript language service. It locates the nearest
|
|
23
|
+
`tsconfig.json` above the target file and answers project-aware symbol queries —
|
|
24
|
+
what grep cannot do when a name has many same-named matches, is re-exported
|
|
25
|
+
(`export { x as y }`), or is imported via path aliases.
|
|
26
|
+
|
|
27
|
+
Invocation: `ts-symbols` (on PATH via `~/.local/bin`), or equivalently
|
|
28
|
+
`bun ~/.claude/tools/ts-symbols/cli.ts`. Positions are 1-based `<file>:<line>:<col>`,
|
|
29
|
+
where col points at the identifier itself (not the line start). `grep -n` gives
|
|
30
|
+
the line; get the column with `awk 'NR==60 {print index($0, "config")}' <file>`.
|
|
31
|
+
|
|
32
|
+
## Commands
|
|
33
|
+
|
|
34
|
+
**outline** — exported + top-level symbols with kinds and lines. Use before
|
|
35
|
+
reading a big file end to end.
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
ts-symbols outline packages/service/src/config.ts
|
|
39
|
+
# 58: export type Config
|
|
40
|
+
# 60: export const config
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
**def** — jump from a usage to the declaration (follows imports, aliases, `.js`
|
|
44
|
+
NodeNext specifiers).
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
ts-symbols def packages/service/src/index.ts:18:10
|
|
48
|
+
# packages/service/src/config.ts:60:14 const config — export const config: Config = ...
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**refs** — every reference across the tsconfig project, tagged `[def]`,
|
|
52
|
+
`[write]`, or `[use]` with the source line. Trust this over grep for impact
|
|
53
|
+
analysis: it sees re-export sites and skips same-named strangers.
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
ts-symbols refs packages/service/src/config.ts:60:14
|
|
57
|
+
# packages/service/scripts/seed.ts:73:10 [write] import { config } from '../src/config.js';
|
|
58
|
+
# packages/service/src/index.ts:18:10 [write] import { config } from './config.js';
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
**type** — resolved type at a position (what an IDE hover shows). `--full`
|
|
62
|
+
additionally expands type aliases without truncation.
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
ts-symbols type packages/service/src/config.ts:60:14
|
|
66
|
+
# const config: { PORT: number; LOG_LEVEL: "fatal" | "error" | ...; }
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Notes
|
|
70
|
+
|
|
71
|
+
- `--json` on any command gives structured output.
|
|
72
|
+
- Exit codes: 0 results, 1 usage/error, 2 valid position but no results, 3 no
|
|
73
|
+
typescript under `<root>`: add it to the project.
|
|
74
|
+
- In monorepos the scope is the *nearest* tsconfig's project — refs from a
|
|
75
|
+
`packages/x` file cover that package, not sibling packages. For cross-package
|
|
76
|
+
impact, follow up with a grep for the module specifier (the package name as
|
|
77
|
+
imported).
|
|
78
|
+
- `--full` matters only when `type` prints a bare alias name; inline object
|
|
79
|
+
types are already fully shown.
|
|
80
|
+
- Files a tsconfig excludes (commonly `**/*.test.ts`) still work as targets.
|
|
81
|
+
- Grep is still right for strings, comments, non-TS files, and cheap
|
|
82
|
+
existence checks; reach for ts-symbols when identity matters.
|