@monte3l/groundwork 1.0.0-rc.2 → 1.0.0-rc.4
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 +13 -5
- package/bin/m3l-groundwork.mjs +36 -2
- package/dist/assets.d.ts +10 -0
- package/dist/assets.js +14 -0
- package/dist/baseline-stage.d.ts +173 -0
- package/dist/baseline-stage.js +215 -0
- package/dist/caps.d.ts +4 -1
- package/dist/caps.js +17 -3
- package/dist/conflicts.d.ts +23 -2
- package/dist/conflicts.js +89 -11
- package/dist/customize-paths.d.ts +92 -0
- package/dist/customize-paths.js +115 -0
- package/dist/emit.d.ts +50 -1
- package/dist/emit.js +121 -13
- package/dist/fatal.d.ts +70 -0
- package/dist/fatal.js +132 -0
- package/dist/format-error.d.ts +113 -0
- package/dist/format-error.js +553 -0
- package/dist/fs-guard.d.ts +142 -0
- package/dist/fs-guard.js +222 -0
- package/dist/git.js +10 -1
- package/dist/harness/conformance.js +2 -0
- package/dist/harness/frontmatter.js +2 -13
- package/dist/harness/grade.js +37 -8
- package/dist/harness/rules.d.ts +20 -3
- package/dist/harness/rules.js +108 -6
- package/dist/harness/types.d.ts +13 -0
- package/dist/harness/types.js +3 -0
- package/dist/inventory.d.ts +77 -3
- package/dist/inventory.js +103 -12
- package/dist/jsonc.d.ts +49 -2
- package/dist/jsonc.js +140 -7
- package/dist/main.d.ts +62 -3
- package/dist/main.js +574 -67
- package/dist/merge-json.d.ts +47 -4
- package/dist/merge-json.js +120 -8
- package/dist/mode.js +12 -2
- package/dist/pack-stage.d.ts +210 -0
- package/dist/pack-stage.js +287 -0
- package/dist/packs.d.ts +21 -13
- package/dist/packs.js +241 -28
- package/dist/palette.d.ts +23 -0
- package/dist/palette.js +22 -0
- package/dist/plugin.d.ts +122 -6
- package/dist/plugin.js +687 -47
- package/dist/report.d.ts +21 -2
- package/dist/report.js +93 -5
- package/dist/staging.d.ts +176 -0
- package/dist/staging.js +375 -0
- package/dist/survey/fs-walk.d.ts +34 -2
- package/dist/survey/fs-walk.js +70 -5
- package/dist/survey/internal/blocked-path.d.ts +27 -0
- package/dist/survey/internal/blocked-path.js +129 -0
- package/dist/survey/internal/package-json.d.ts +13 -0
- package/dist/survey/internal/package-json.js +37 -0
- package/dist/survey/internal/read-guard.d.ts +178 -0
- package/dist/survey/internal/read-guard.js +276 -0
- package/dist/survey/survey-docs.d.ts +17 -2
- package/dist/survey/survey-docs.js +61 -21
- package/dist/survey/survey-harness.d.ts +20 -2
- package/dist/survey/survey-harness.js +87 -46
- package/dist/survey/survey-shape.d.ts +17 -2
- package/dist/survey/survey-shape.js +60 -46
- package/dist/survey/survey-toolchain.d.ts +16 -1
- package/dist/survey/survey-toolchain.js +69 -66
- package/dist/survey/survey.js +6 -4
- package/dist/survey/types.d.ts +79 -0
- package/dist/survey/types.js +2 -6
- package/dist/term.d.ts +80 -0
- package/dist/term.js +145 -0
- package/dist/tokens.js +2 -0
- package/dist/toolchain/conformance.js +2 -0
- package/dist/toolchain/grade.js +26 -8
- package/dist/toolchain/rules.d.ts +13 -4
- package/dist/toolchain/rules.js +16 -0
- package/dist/toolchain/tsconfig-chain.d.ts +2 -0
- package/dist/toolchain/tsconfig-chain.js +32 -8
- package/dist/toolchain/types.d.ts +16 -4
- package/dist/toolchain/types.js +3 -0
- package/package.json +4 -3
- package/plugin/skills/customize/SKILL.md +292 -18
- package/plugin/src/domain-map.ts +39 -14
- package/plugin/src/index.ts +5 -1
- package/plugin/src/kind-facet-map.ts +25 -8
- package/plugin/src/pack-map.ts +147 -25
- package/plugin/src/plugin-map.ts +236 -0
- package/templates/core/.claude/agents/Explore.md +0 -1
- package/templates/core/.claude/agents/code-implementer.md +4 -4
- package/templates/core/.claude/agents/code-reviewer.md +4 -4
- package/templates/core/.claude/agents/silent-failure-hunter.md +2 -2
- package/templates/core/.claude/agents/test-author.md +7 -5
- package/templates/core/.claude/hooks/guard-branch-isolation.mjs +56 -10
- package/templates/core/.claude/hooks/guard-double-background.mjs +13 -8
- package/templates/core/.claude/hooks/guard-git-push-signed.mjs +12 -9
- package/templates/core/.claude/hooks/guard-hub-src-writes.mjs +1890 -38
- package/templates/core/.claude/hooks/guard-js-extension.mjs +2 -1
- package/templates/core/.claude/hooks/guard-no-commonjs.mjs +7 -5
- package/templates/core/.claude/hooks/guard-secret-writes.mjs +7 -5
- package/templates/core/.claude/hooks/inject-decision-gate.mjs +12 -9
- package/templates/core/.claude/hooks/post-edit-verify.mjs +276 -98
- package/templates/core/.claude/rules/agent-dispatch.md +7 -0
- package/templates/core/.claude/rules/tests.md +2 -2
- package/templates/core/.claude/settings.json +5 -0
- package/templates/core/.claude/skills/finishing-work/SKILL.md +58 -10
- package/templates/core/.claude/skills/harness-guidance/SKILL.md +16 -7
- package/templates/core/.claude/skills/starting-work/SKILL.md +5 -0
- package/templates/core/.claude/skills/triaging-ci/SKILL.md +9 -8
- package/templates/core/.claude/skills/typescript-guidance/SKILL.md +137 -20
- package/templates/core/.claude/skills/typescript-guidance/references/area-catalog.md +135 -0
- package/templates/core/.claude/skills/typescript-guidance/references/tooling-sources.md +113 -0
- package/templates/core/.claude/skills/writing-commits/SKILL.md +2 -2
- package/templates/core/.github/dependabot.yml +18 -0
- package/templates/core/.github/workflows/ci.yml +15 -15
- package/templates/core/.github/workflows/dependency-review.yml +2 -2
- package/templates/core/.github/workflows/security-audit.yml +10 -4
- package/templates/core/.prettierignore +4 -0
- package/templates/core/CLAUDE.md +53 -3
- package/templates/core/README.md +30 -10
- package/templates/core/_gitignore +17 -0
- package/templates/core/bin/check-exports.mjs +11 -5
- package/templates/core/bin/lib/agent-roster.mjs +1 -1
- package/templates/core/bin/lib/frontmatter.mjs +4 -2
- package/templates/core/bin/lib/harness-rules.mjs +169 -20
- package/templates/core/bin/lib/protected-paths.mjs +93 -5
- package/templates/core/bin/lib/toolchain-rules.mjs +187 -26
- package/templates/core/bin/lib/verify-steps.mjs +29 -11
- package/templates/core/bin/verify.mjs +12 -0
- package/templates/core/eslint.config.js +5 -0
- package/templates/core/package.json +7 -7
- package/templates/core/vitest.config.ts +8 -1
- package/templates/packs/README.md +44 -24
- package/templates/packs/github/files/.claude/skills/reviewing-dependabot-prs/SKILL.md +133 -0
- package/templates/packs/github/files/.claude/skills/triaging-scan-alerts/SKILL.md +88 -0
- package/templates/packs/github/files/.claude/skills/watching-pr-checks/SKILL.md +94 -0
- package/templates/packs/github/files/.github/workflows/claude-pr-review.yml +267 -0
- package/templates/packs/github/files/.github/workflows/claude.yml +106 -0
- package/templates/packs/github/pack.json +19 -0
- package/templates/packs/harness-extras/files/.claude/hooks/guard-readonly-bash.mjs +1122 -65
- package/templates/packs/harness-extras/files/.claude/hooks/reinject-compact-handoff.mjs +147 -13
- package/templates/packs/{statusline → harness-extras}/files/.claude/hooks/statusline.mjs +6 -2
- package/templates/packs/harness-extras/files/.claude/hooks/write-compact-handoff.mjs +227 -44
- package/templates/packs/harness-extras/pack.json +18 -13
- package/templates/packs/publishing/files/.changeset/README.md +25 -0
- package/templates/packs/publishing/files/.changeset/config.json +7 -0
- package/templates/packs/publishing/files/.github/release-tools/package.json +9 -0
- package/templates/packs/publishing/files/.github/workflows/release.yml +295 -0
- package/templates/packs/publishing/files/REUSE.toml +28 -0
- package/templates/packs/publishing/files/bin/check-dts-deps.mjs +234 -0
- package/templates/packs/publishing/files/bin/check-license-headers.mjs +217 -0
- package/templates/packs/publishing/files/bin/check-publish-version.mjs +149 -0
- package/templates/packs/publishing/files/bin/lib/npm-publish-args.mjs +86 -0
- package/templates/packs/publishing/files/bin/pnpm-publish-shim.mjs +86 -0
- package/templates/packs/publishing/pack.json +41 -0
- package/templates/packs/{harness-extras → quality}/files/bin/check-file-budget.mjs +6 -4
- package/templates/packs/quality/pack.json +29 -0
- package/templates/packs/supply-chain/files/.github/workflows/gitleaks.yml +52 -0
- package/templates/packs/supply-chain/files/.github/workflows/scorecard.yml +48 -0
- package/templates/packs/supply-chain/files/.gitleaks.toml +2 -0
- package/templates/packs/supply-chain/pack.json +19 -0
- package/templates/packs/worktrees/files/.claude/hooks/ensure-worktree-deps.mjs +283 -0
- package/templates/packs/worktrees/files/.claude/hooks/guard-worktree-only.mjs +245 -0
- package/templates/packs/worktrees/files/.claude/hooks/repair-core-bare.mjs +335 -0
- package/templates/packs/worktrees/files/.claude/skills/working-in-worktrees/SKILL.md +139 -0
- package/templates/packs/worktrees/files/.worktreeinclude +11 -0
- package/templates/packs/worktrees/pack.json +64 -0
- package/templates/packs/statusline/pack.json +0 -31
- /package/templates/packs/{statusline → harness-extras}/files/.claude/hooks/statusline-layout.mjs +0 -0
- /package/templates/packs/{statusline → harness-extras}/files/.claude/hooks/subagent-statusline.mjs +0 -0
- /package/templates/packs/{harness-extras → quality}/files/.claude/agents/type-design-analyzer.md +0 -0
- /package/templates/packs/{harness-extras → quality}/files/bin/file-budget-baseline.json +0 -0
|
@@ -39,7 +39,37 @@ gh pr view --json state,mergedAt,headRefName,baseRefName
|
|
|
39
39
|
Record `headRefName` — every later step operates on this branch, not
|
|
40
40
|
whatever the user typed.
|
|
41
41
|
|
|
42
|
-
### 2 —
|
|
42
|
+
### 2 — Check for a linked worktree
|
|
43
|
+
|
|
44
|
+
`headRefName` may be checked out in a linked worktree (created by
|
|
45
|
+
`claude --worktree`, the `EnterWorktree` tool, or `git worktree add`) rather
|
|
46
|
+
than in the main checkout directly — check before assuming otherwise:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
git worktree list --porcelain
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
If a worktree has `headRefName` checked out:
|
|
53
|
+
|
|
54
|
+
- **If the session entered it via `EnterWorktree`/`--worktree` and is still
|
|
55
|
+
there**, use the `ExitWorktree` tool (keep, don't remove — removal happens
|
|
56
|
+
safely in Step 4, after the merge-ancestry check) to return to the main
|
|
57
|
+
checkout _first_. `git checkout main` below fails outright ("already used
|
|
58
|
+
by worktree") because `main` is already checked out in the main worktree —
|
|
59
|
+
git refuses to check out the same branch in two places at once, regardless
|
|
60
|
+
of which branch the other worktree happens to be on. (If the session
|
|
61
|
+
merely `cd`'d into a plain `git worktree add` checkout — no `EnterWorktree`
|
|
62
|
+
involved — `ExitWorktree` has nothing to exit; just `cd` back to the main
|
|
63
|
+
checkout instead.)
|
|
64
|
+
After `ExitWorktree`, run `git config core.bare`: Claude Code's worktree
|
|
65
|
+
tools have been reported to leave it `true` in a normal repository's shared
|
|
66
|
+
config (anthropics/claude-code#58345, #69802), which breaks `git status`
|
|
67
|
+
here. If it prints `true`, run `git config --local core.bare false` before
|
|
68
|
+
going on.
|
|
69
|
+
- Otherwise, no action needed yet — just remember the worktree's path for
|
|
70
|
+
Step 4.
|
|
71
|
+
|
|
72
|
+
### 3 — Return to `main` and pull
|
|
43
73
|
|
|
44
74
|
```bash
|
|
45
75
|
git checkout main
|
|
@@ -48,7 +78,7 @@ git pull
|
|
|
48
78
|
|
|
49
79
|
Skip this if already on `main` with nothing to pull.
|
|
50
80
|
|
|
51
|
-
###
|
|
81
|
+
### 4 — Delete the merged branch
|
|
52
82
|
|
|
53
83
|
**Before removing anything, confirm no backgrounded command (a `git push`,
|
|
54
84
|
a verify run, or similar) is still running against the branch you're about
|
|
@@ -63,6 +93,24 @@ merged" does not mean every commit on the branch landed. Run `git log
|
|
|
63
93
|
<branch> ^origin/main --oneline` before any branch-deleting cleanup — a
|
|
64
94
|
non-empty result is a commit about to be abandoned, not noise.
|
|
65
95
|
|
|
96
|
+
**If Step 2 found a linked worktree for this branch, remove it before
|
|
97
|
+
deleting the branch** — `git branch -d`/`-D` refuses a branch that's still
|
|
98
|
+
checked out anywhere. `status --porcelain` only reports tracked and
|
|
99
|
+
untracked-but-not-ignored changes — it says nothing about a gitignored file
|
|
100
|
+
that only exists in this worktree (a `.env`, an in-progress scratch file),
|
|
101
|
+
so **confirm with the user before running `remove`**, the same as `unlock`,
|
|
102
|
+
rather than treating an empty `status --porcelain` alone as proof there's
|
|
103
|
+
nothing to lose:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
git -C <worktree-path> status --porcelain # must be empty; investigate first if not
|
|
107
|
+
git worktree unlock <worktree-path> # only if locked, and only after confirming with the user
|
|
108
|
+
git worktree remove <worktree-path> # confirm with the user first -- see above
|
|
109
|
+
git worktree prune
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Then delete the branch itself:
|
|
113
|
+
|
|
66
114
|
```bash
|
|
67
115
|
git branch -d <headRefName>
|
|
68
116
|
```
|
|
@@ -72,7 +120,7 @@ after a squash merge), don't force-delete without asking: confirm the merge
|
|
|
72
120
|
really landed via `gh pr view` above, then use `git branch -D <headRefName>`
|
|
73
121
|
only with the user's go-ahead.
|
|
74
122
|
|
|
75
|
-
###
|
|
123
|
+
### 5 — Prune stale remote-tracking refs
|
|
76
124
|
|
|
77
125
|
```bash
|
|
78
126
|
git fetch --prune
|
|
@@ -82,7 +130,7 @@ Cheap and safe regardless of the branch outcome above — clears the
|
|
|
82
130
|
`[deleted]` marker for this and any other already-merged branch's remote
|
|
83
131
|
ref.
|
|
84
132
|
|
|
85
|
-
###
|
|
133
|
+
### 6 — Work log check
|
|
86
134
|
|
|
87
135
|
If the project keeps work logs (check whether a `docs/logs/` directory or
|
|
88
136
|
equivalent convention exists), apply a substance test, not a commit-type
|
|
@@ -98,20 +146,20 @@ commit directly to `main`** — branch first (`git switch -c docs/<slug>-log`),
|
|
|
98
146
|
commit there, push, and open a PR, even for a trivial docs-only change, if
|
|
99
147
|
the project requires a PR for every change to `main`.
|
|
100
148
|
|
|
101
|
-
###
|
|
149
|
+
### 7 — Orphaned journal sweep
|
|
102
150
|
|
|
103
151
|
Check the scratchpad directory for any writer-spoke dispatch journal older
|
|
104
152
|
than the current task that has no corresponding open work — ask before
|
|
105
153
|
deleting, since a file from a different, still-in-progress task can look
|
|
106
154
|
identical to a genuine orphan.
|
|
107
155
|
|
|
108
|
-
###
|
|
156
|
+
### 8 — Report
|
|
109
157
|
|
|
110
|
-
One-line summary: branch deleted (or kept, with
|
|
111
|
-
present/written/skipped, journals swept/left.
|
|
158
|
+
One-line summary: worktree removed (if any), branch deleted (or kept, with
|
|
159
|
+
why), refs pruned, work log present/written/skipped, journals swept/left.
|
|
112
160
|
|
|
113
161
|
## Notes
|
|
114
162
|
|
|
115
163
|
This skill is read-and-confirm heavy by design — every destructive step
|
|
116
|
-
(branch delete, journal delete) asks first rather
|
|
117
|
-
always-asks tail beats no tail at all.
|
|
164
|
+
(worktree unlock/removal, branch delete, journal delete) asks first rather
|
|
165
|
+
than assuming. A cautious, always-asks tail beats no tail at all.
|
|
@@ -17,8 +17,15 @@ description: >-
|
|
|
17
17
|
|
|
18
18
|
One skill, two modes, sharing one allowlist
|
|
19
19
|
(`references/official-sources.md`) so they can't drift apart. Pick the mode
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
by what's actually being asked, not by surface phrasing: a question that
|
|
21
|
+
names one setting, one hook, one agent, or one narrow facet of `.claude/` —
|
|
22
|
+
even when phrased as "is X still current" — stays `research`, because
|
|
23
|
+
there's one thing to look up and answer. A request that names no specific
|
|
24
|
+
facet, that asks about the whole `.claude/` surface ("our harness", "are we
|
|
25
|
+
behind"), or that's periodic/`/customize`-driven, is `refresh`. When
|
|
26
|
+
genuinely torn between the two, default to `research` — it's cheaper and
|
|
27
|
+
faster — and say in the answer that a full `refresh` sweep is available if
|
|
28
|
+
the question turns out to implicate more than the one facet asked about.
|
|
22
29
|
|
|
23
30
|
**Must only run in the main (hub) agent, never inside a subagent** — it ends
|
|
24
31
|
in `EnterPlanMode` (refresh) or dispatches other agents (either mode), which
|
|
@@ -104,8 +111,7 @@ concern) — every other facet below is identical regardless of project kind.
|
|
|
104
111
|
|
|
105
112
|
Each brief carries: the facet row, Step 2's delta, the tracker's prior
|
|
106
113
|
claims for that facet, the allowlist + GitHub caveat + date anchor, the
|
|
107
|
-
|
|
108
|
-
format per claim:
|
|
114
|
+
facet id, and this verdict format per claim:
|
|
109
115
|
|
|
110
116
|
```
|
|
111
117
|
CLAIM: <the tracker's prior claim, or "NEW" if none existed>
|
|
@@ -114,10 +120,13 @@ concern) — every other facet below is identical regardless of project kind.
|
|
|
114
120
|
REPO-IMPACT: <which emitted file(s) this affects, or "none">
|
|
115
121
|
```
|
|
116
122
|
|
|
117
|
-
Return value: **
|
|
118
|
-
|
|
123
|
+
Return value: **the full verdict list inline, inside the ~8,000-character
|
|
124
|
+
cap** -- `Explore` holds no write tool, so it cannot write a file. Put
|
|
125
|
+
every non-"none" REPO-IMPACT claim first so a truncation drops only
|
|
126
|
+
the no-impact ones. The hub saves each returned report to
|
|
127
|
+
`<run-dir>/<facet-id>.md` itself; that is what step 4 reads.
|
|
119
128
|
|
|
120
|
-
4. **Aggregate.** Read every
|
|
129
|
+
4. **Aggregate.** Read every saved facet report in full. Four buckets:
|
|
121
130
|
confirmed drift with repo impact (verify each against the cited file
|
|
122
131
|
itself before trusting it — an agent can misread a page), guidance
|
|
123
132
|
changes with no impact, dead/moved URLs, coverage gaps.
|
|
@@ -76,6 +76,11 @@ surface the decisions still open.
|
|
|
76
76
|
|
|
77
77
|
### 5 — Act on the confirmed decisions
|
|
78
78
|
|
|
79
|
+
If `.claude/skills/working-in-worktrees/` exists (an optional add-on, not
|
|
80
|
+
part of this baseline), use its start mode for this step instead of a bare
|
|
81
|
+
`git switch -c` — it gets the same branch, plus an isolated worktree and its
|
|
82
|
+
own installed dependencies in one move. Otherwise:
|
|
83
|
+
|
|
79
84
|
```bash
|
|
80
85
|
git switch -c feat/<slug> # or fix/<slug>
|
|
81
86
|
```
|
|
@@ -70,14 +70,15 @@ the first failure, typically the last 50–100 lines before the run aborted.
|
|
|
70
70
|
|
|
71
71
|
### 3 — Map to the pipeline step
|
|
72
72
|
|
|
73
|
-
`.github/workflows/ci.yml`'s lanes each run `node bin/verify.mjs --
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
the
|
|
78
|
-
step's `cmd` array joined as a shell command
|
|
79
|
-
|
|
80
|
-
|
|
73
|
+
`.github/workflows/ci.yml`'s lanes each run `node bin/verify.mjs --group <name>`
|
|
74
|
+
(`format`, `lint`, `typecheck`, `build`, `test`); a group runs every step
|
|
75
|
+
in it from `bin/lib/verify-steps.mjs`, and that file's `cmd` field IS the
|
|
76
|
+
local reproduction command. Find the `▶ <step name> (<id>)` line the log
|
|
77
|
+
prints just before the failure, then reproduce with `node bin/verify.mjs
|
|
78
|
+
--step <id>` (or the step's `cmd` array joined as a shell command). If no
|
|
79
|
+
`▶` line is visible, match the failing job's name to its group and run
|
|
80
|
+
`node bin/verify.mjs --group <name>`. `--step` is for local debugging only
|
|
81
|
+
and never appears in a workflow file.
|
|
81
82
|
|
|
82
83
|
### 4 — Report the diagnosis
|
|
83
84
|
|
|
@@ -1,34 +1,53 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: typescript-guidance
|
|
3
3
|
description: >-
|
|
4
|
-
|
|
4
|
+
Three-mode TypeScript guidance skill. `research` mode answers a single
|
|
5
5
|
TypeScript/toolchain question from owner-normative upstream sources only
|
|
6
6
|
(typescriptlang.org, the devblog, microsoft/TypeScript releases,
|
|
7
7
|
nodejs.org type stripping, typescript-eslint.io, attw, publint). `refresh`
|
|
8
8
|
mode sweeps this project's whole TypeScript-facing surface — tsconfig,
|
|
9
|
-
eslint, packaging,
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
9
|
+
eslint, packaging, the test config/approach — against a living tracker and
|
|
10
|
+
produces a remediation plan. `gaps` mode profiles the toolchain offline,
|
|
11
|
+
then researches live before recommending tooling the project does NOT have
|
|
12
|
+
yet, each recommendation with a source fetched that run. Use for
|
|
13
|
+
/typescript-guidance, "what does the TypeScript team say about X", "are we
|
|
14
|
+
behind on TypeScript", "is our tsconfig still current", "what tooling are
|
|
15
|
+
we missing", or before changing a compiler flag. Not for a general Claude
|
|
16
|
+
Code automation review, and not how this project's config is wired today
|
|
17
|
+
— that's CLAUDE.md and the config files.
|
|
15
18
|
---
|
|
16
19
|
|
|
17
20
|
# typescript-guidance
|
|
18
21
|
|
|
19
|
-
One skill,
|
|
22
|
+
One skill, three modes, sharing one allowlist
|
|
20
23
|
(`references/typescript-sources.md`) so they can't drift apart. Pick the
|
|
21
|
-
mode
|
|
22
|
-
|
|
24
|
+
mode by what's actually being asked, not by surface phrasing. First, is the
|
|
25
|
+
thing not configured at all? "What are we missing", "any gaps in our
|
|
26
|
+
toolchain", "should we add typed linting" are `gaps` even when they name one
|
|
27
|
+
tool, because absence decides it. Otherwise a question that names one flag,
|
|
28
|
+
one setting, or one narrow facet — even when phrased as "is X still
|
|
29
|
+
current" — stays `research`, because there's one thing to look up and
|
|
30
|
+
answer. A request that names no specific facet, that asks
|
|
31
|
+
about the whole TypeScript-facing surface ("our tsconfig", "our toolchain",
|
|
32
|
+
"are we behind"), or that's periodic/`/customize`-driven, is `refresh`. A
|
|
33
|
+
request about tooling the project **doesn't have at all** is `gaps`,
|
|
34
|
+
whereas "X is configured, is it still right" is `research` or `refresh`,
|
|
35
|
+
never `gaps`. When genuinely torn between `research` and `refresh`, default
|
|
36
|
+
to `research` — it's cheaper and faster — and say in the answer that a full
|
|
37
|
+
`refresh` sweep is available if the question turns out to implicate more
|
|
38
|
+
than the one facet asked about.
|
|
23
39
|
|
|
24
40
|
**Must only run in the main (hub) agent, never inside a subagent** — it ends
|
|
25
|
-
in `EnterPlanMode` (refresh) or an `AskUserQuestion` (
|
|
26
|
-
occasionally),
|
|
41
|
+
in `EnterPlanMode` (refresh) or an `AskUserQuestion` (research or refresh,
|
|
42
|
+
occasionally), and every mode launches parallel `Explore` research agents,
|
|
43
|
+
none of which a subagent can do (`disallowedTools: Agent` on every spoke).
|
|
27
44
|
|
|
28
45
|
**No files are written by this skill itself** in research mode by default;
|
|
29
|
-
refresh mode writes to exactly one file, the tracker, in Step 5
|
|
46
|
+
refresh mode writes to exactly one file, the tracker, in Step 5; `gaps` mode
|
|
47
|
+
never writes a file — it proposes, and hands any accepted recommendation to
|
|
48
|
+
`starting-work` and the normal TDD pipeline.
|
|
30
49
|
|
|
31
|
-
## Authority (read this before
|
|
50
|
+
## Authority (read this before any mode)
|
|
32
51
|
|
|
33
52
|
This skill has authority over **every TypeScript-facing file in the
|
|
34
53
|
project** — `tsconfig.base.json`, `tsconfig.json`, `eslint.config.js`,
|
|
@@ -40,6 +59,17 @@ its config shape), `package.json`'s TypeScript-toolchain entries, packaging
|
|
|
40
59
|
**most deeply**, never which facets it may or may not touch. A facet with
|
|
41
60
|
low priority still gets swept; it just gets less dedicated attention per run.
|
|
42
61
|
|
|
62
|
+
`gaps` mode never overlaps that authority. It covers what's **missing** — a
|
|
63
|
+
flag, script, config block or package the project doesn't have configured at
|
|
64
|
+
all. Drift in something that already exists is `research`'s or `refresh`'s
|
|
65
|
+
question and is never re-answered under `gaps`; if a `gaps` profile turns out
|
|
66
|
+
to be "configured but looks stale", say so and switch mode instead of
|
|
67
|
+
writing a recommendation. Any compiler-flag or config change `gaps`
|
|
68
|
+
proposes goes through `research` before it is implemented: `gaps`' live
|
|
69
|
+
research is scoped to "does this exist, and what's the current recommended
|
|
70
|
+
shape if we add it", and doesn't carry `research`'s full precedence and
|
|
71
|
+
conflict-resolution machinery for an existing value.
|
|
72
|
+
|
|
43
73
|
## Research mode
|
|
44
74
|
|
|
45
75
|
1. **Scope the topic.** Read the topic from the invocation or the
|
|
@@ -108,8 +138,7 @@ low priority still gets swept; it just gets less dedicated attention per run.
|
|
|
108
138
|
|
|
109
139
|
Each brief carries: the facet row, Step 2's delta, the tracker's prior
|
|
110
140
|
claims for that facet, the allowlist + GitHub caveat + date anchor, the
|
|
111
|
-
|
|
112
|
-
format per claim:
|
|
141
|
+
facet id, and this verdict format per claim:
|
|
113
142
|
|
|
114
143
|
```
|
|
115
144
|
CLAIM: <the tracker's prior claim, or "NEW" if none existed>
|
|
@@ -118,10 +147,13 @@ low priority still gets swept; it just gets less dedicated attention per run.
|
|
|
118
147
|
REPO-IMPACT: <which emitted file(s) this affects, or "none">
|
|
119
148
|
```
|
|
120
149
|
|
|
121
|
-
Return value: **
|
|
122
|
-
|
|
150
|
+
Return value: **the full verdict list inline, inside the ~8,000-character
|
|
151
|
+
cap** -- `Explore` holds no write tool, so it cannot write a file. Put
|
|
152
|
+
every non-"none" REPO-IMPACT claim first so a truncation drops only
|
|
153
|
+
the no-impact ones. The hub saves each returned report to
|
|
154
|
+
`<run-dir>/<facet-id>.md` itself; that is what step 4 reads.
|
|
123
155
|
|
|
124
|
-
4. **Aggregate.** Read every
|
|
156
|
+
4. **Aggregate.** Read every saved facet report in full. Four buckets:
|
|
125
157
|
confirmed drift with repo impact (verify each against the cited file
|
|
126
158
|
itself before trusting it — an agent can misread a page), guidance
|
|
127
159
|
changes with no impact, dead/moved URLs, coverage gaps.
|
|
@@ -133,6 +165,89 @@ low priority still gets swept; it just gets less dedicated attention per run.
|
|
|
133
165
|
confirmed-drift item. No drift → skip plan mode, report a clean sweep,
|
|
134
166
|
still update the tracker.
|
|
135
167
|
|
|
168
|
+
## Gaps mode
|
|
169
|
+
|
|
170
|
+
Recommends TypeScript-ecosystem **tooling the project doesn't have yet** and
|
|
171
|
+
never rules on tooling it already has. Every recommendation is grounded on
|
|
172
|
+
official guidance fetched **live**, in this run: cross-project compatibility
|
|
173
|
+
state (a new TypeScript major before `typescript-eslint` supports it, a
|
|
174
|
+
package-manager major dropping a setting) shifts on its own schedule, so
|
|
175
|
+
anything baked into this file as a fixed answer would go stale within months.
|
|
176
|
+
This mode ships no answers, only where to look and what to ask.
|
|
177
|
+
|
|
178
|
+
1. **Profile (offline; no network calls).** Establish what the project
|
|
179
|
+
already has before researching anything:
|
|
180
|
+
- `package.json`'s `scripts`, `dependencies`, `devDependencies`, and
|
|
181
|
+
`pnpm-workspace.yaml` (workspaces, `catalog`/`catalogs`) if present;
|
|
182
|
+
- the resolved tsconfig chain — every `tsconfig*.json` following
|
|
183
|
+
`extends`, using `bin/lib/toolchain-rules.mjs`'s tsconfig-chain
|
|
184
|
+
resolution if it exists rather than re-deriving the rules by hand;
|
|
185
|
+
- lint/test/hygiene config — `eslint.config.*` (or `.eslintrc.*`),
|
|
186
|
+
`vitest.config.ts` (or another runner's), `knip.json`;
|
|
187
|
+
- existing gates — run `node bin/check-toolchain.mjs` if present, and
|
|
188
|
+
read `.groundwork/inventory.json` if present (its `toolchainGrade` and
|
|
189
|
+
`toolchainConformance` are exactly this profile, already computed);
|
|
190
|
+
- budget — count `.claude/agents/*.md`, `.claude/skills/*/`,
|
|
191
|
+
`.claude/hooks/*.{mjs,js}`, `.github/workflows/*.yml` and
|
|
192
|
+
`package.json`'s `scripts` keys if the project states a cap on any of
|
|
193
|
+
them (`CLAUDE.md`, or an adoption report's cap table): with no room
|
|
194
|
+
left, prefer a `verify-steps` gate over a new `package.json` script;
|
|
195
|
+
- verify-step wiring — `bin/lib/verify-steps.mjs` /
|
|
196
|
+
`bin/lib/verify-steps.packs.json`, or whatever gate runner exists.
|
|
197
|
+
|
|
198
|
+
Map every signal to the areas in `references/area-catalog.md`, which names
|
|
199
|
+
the signals to look for and the questions to research per area and holds
|
|
200
|
+
no answers of its own. An area with no signal at all (no monorepo hints,
|
|
201
|
+
no release workflow) still gets a light pass: "you have none of this,
|
|
202
|
+
here is what to consider" is itself a recommendation, not silence.
|
|
203
|
+
|
|
204
|
+
2. **Research live (mandatory).** No recommendation reaches the report
|
|
205
|
+
without a source fetched in this run. Read `references/tooling-sources.md`
|
|
206
|
+
(the ecosystem-tooling allowlist) and `references/typescript-sources.md`
|
|
207
|
+
(the TypeScript-owner allowlist, reused rather than duplicated). Pick the
|
|
208
|
+
areas from `area-catalog.md` that the profile made relevant — or only the
|
|
209
|
+
one category the user named. **Launch all agents in a single message**,
|
|
210
|
+
always `subagent_type: "Explore"`, breadth `"very thorough"`, one per
|
|
211
|
+
relevant area. Each brief carries: that area's signals-and-questions
|
|
212
|
+
verbatim; both allowlists pasted verbatim, each with its own GitHub-path
|
|
213
|
+
caveat kept separate (a domain allowed by one file's caveat is not
|
|
214
|
+
automatically allowed by the other's); today's date; "reject any
|
|
215
|
+
non-allowlisted domain outright and say so, rather than substituting a
|
|
216
|
+
blog post or an individual author's material"; "you hold no write tool —
|
|
217
|
+
findings travel only in your response"; research mode's findings format
|
|
218
|
+
above; and an ~8,000-character (~2,000-token) return cap. Read every
|
|
219
|
+
agent's full inline findings. A failed or empty fetch for an area is a
|
|
220
|
+
**coverage gap**, reported as such — never dropped, never backfilled from
|
|
221
|
+
an unlisted source.
|
|
222
|
+
3. **Report.** In this order:
|
|
223
|
+
- **Codebase profile** — a short summary of what step 1 found, so the
|
|
224
|
+
reader can see the recommendations are grounded in this project.
|
|
225
|
+
- **Recommendations** — 1–2 per relevant area (3–5 for a single area the
|
|
226
|
+
user named). Each gives: **Why** (the specific project signal, not
|
|
227
|
+
"generally good practice"), **What** (the concrete config block, script
|
|
228
|
+
or package to add), **Source** (the URL, fetched today, with its tier),
|
|
229
|
+
and **Cost** (cap impact, and whether it's a `verify-steps` gate or a
|
|
230
|
+
`package.json` script).
|
|
231
|
+
- **Unverified claims** — a signal step 2 could not verify against an
|
|
232
|
+
allowlisted source is named as "unverified — not recommended", not
|
|
233
|
+
omitted.
|
|
234
|
+
- **No web tools at all** (offline, sandboxed): report the profile alone,
|
|
235
|
+
say plainly that no live research ran, and recommend nothing — an
|
|
236
|
+
unverified recommendation is worse than none.
|
|
237
|
+
- **Hand-off** — point any accepted recommendation at `starting-work`
|
|
238
|
+
(branch first) and the normal test-author → code-implementer →
|
|
239
|
+
review-spoke pipeline. This mode never writes the change itself.
|
|
240
|
+
|
|
241
|
+
**Recommendation discipline.** Never recommend adding a tool or preset that
|
|
242
|
+
live research shows doesn't yet support the project's current toolchain
|
|
243
|
+
version: recommending something that can't be installed against the
|
|
244
|
+
already-pinned TypeScript is worse than recommending nothing, so name the
|
|
245
|
+
incompatibility as a blocker instead. (Second-guessing a version the project
|
|
246
|
+
already pinned is `research`'s territory, not this mode's.) When the
|
|
247
|
+
project's scripts are at their cap, prefer a `verify-steps` gate
|
|
248
|
+
(`["node", "bin/check-x.mjs"]`, no `package.json` script needed) over a new
|
|
249
|
+
script.
|
|
250
|
+
|
|
136
251
|
## Why this exists, separately from "how is our config wired"
|
|
137
252
|
|
|
138
253
|
Research mode answers "what does upstream say about X." Nothing else in the
|
|
@@ -140,4 +255,6 @@ baseline asks the inverse — "is what's already configured still what
|
|
|
140
255
|
upstream recommends" — because every lint/typecheck/test gate is a closed
|
|
141
256
|
loop checking the repo against its own prior decisions. A stale pin one
|
|
142
257
|
major behind upstream passes every one of those gates cleanly; only a live
|
|
143
|
-
sweep against the actual upstream surfaces it.
|
|
258
|
+
sweep against the actual upstream surfaces it. For the same reason, a
|
|
259
|
+
missing tool trips no gate at all — nothing fails when a check that was
|
|
260
|
+
never installed doesn't run — which is what `gaps` mode is for.
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# Area catalog -- signals to detect, questions to research
|
|
2
|
+
|
|
3
|
+
For each area: what to look for in `gaps` mode's step 1 (the signal), and what to ask a
|
|
4
|
+
step 2 research agent (the question). **This file holds no answers** --
|
|
5
|
+
an answer here would be exactly the kind of baked-in claim that goes stale
|
|
6
|
+
within months. Pick the areas step 1's signals make relevant; don't
|
|
7
|
+
research every area unconditionally on every run.
|
|
8
|
+
|
|
9
|
+
## tsconfig flags and deprecations
|
|
10
|
+
|
|
11
|
+
- **Signal**: the resolved tsconfig chain (step 1) is missing a
|
|
12
|
+
strict-family flag entirely, or sets no `target`/`lib` at all for the
|
|
13
|
+
project's actual runtime.
|
|
14
|
+
- **Research**: what compiler options does the current TypeScript release
|
|
15
|
+
recommend adding for this project's runtime target (Node-only, browser,
|
|
16
|
+
both), for a tsconfig that doesn't set them yet? (Whether an option the
|
|
17
|
+
project already sets has since been deprecated, or an already-set
|
|
18
|
+
`target`/`lib` is now outdated, is drift in existing config --
|
|
19
|
+
`research`/`refresh`'s question, not `gaps` mode's; hand it off rather
|
|
20
|
+
than research it here.)
|
|
21
|
+
|
|
22
|
+
## module resolution by project kind
|
|
23
|
+
|
|
24
|
+
- **Signal**: no `moduleResolution` set anywhere in the resolved tsconfig
|
|
25
|
+
chain at all.
|
|
26
|
+
- **Research**: what does the current TypeScript Modules reference recommend
|
|
27
|
+
for this project's actual shipping shape (published package vs. bundled
|
|
28
|
+
app vs. both), for a tsconfig that doesn't set one yet? (An already-set
|
|
29
|
+
`moduleResolution` that doesn't match what the project actually ships --
|
|
30
|
+
a package with an `exports` map on `node16`/`nodenext` that should be on
|
|
31
|
+
`bundler`, say -- is drift in existing config, `research`/`refresh`'s
|
|
32
|
+
question, not `gaps` mode's.)
|
|
33
|
+
|
|
34
|
+
## typed linting
|
|
35
|
+
|
|
36
|
+
- **Signal**: `eslint.config.js` has no `typescript-eslint` typed-linting
|
|
37
|
+
preset (`recommendedTypeChecked`/`strictTypeChecked`/`stylisticTypeChecked`)
|
|
38
|
+
configured at all.
|
|
39
|
+
- **Research**: what does typescript-eslint's current documentation recommend
|
|
40
|
+
for a project with no typed linting yet -- and, since a recommendation to
|
|
41
|
+
add it must actually be installable, does the version that would be added
|
|
42
|
+
support the project's current TypeScript version? This is exactly the kind
|
|
43
|
+
of cross-project compatibility gap a stale skill answer would miss (a new
|
|
44
|
+
TypeScript major that `typescript-eslint` doesn't support yet, say).
|
|
45
|
+
(Whether an _already-pinned_
|
|
46
|
+
`typescript-eslint` version is stale or incompatible is drift in existing
|
|
47
|
+
config -- `research`/`refresh`'s question, not `gaps` mode's.)
|
|
48
|
+
|
|
49
|
+
## testing
|
|
50
|
+
|
|
51
|
+
- **Signal**: no test runner configured at all.
|
|
52
|
+
- **Research**: what does the current official docs of a reasonable default
|
|
53
|
+
test runner recommend for a TypeScript project with none configured yet --
|
|
54
|
+
config shape, coverage tooling, and any TypeScript-specific caveat
|
|
55
|
+
(type-checking test files, `expectTypeOf`-style assertions)? (A runner that
|
|
56
|
+
already exists but has no coverage gate, or whose config no longer matches
|
|
57
|
+
its own current docs, is drift in existing config -- `research`/`refresh`'s
|
|
58
|
+
question via its `testing-language-features` facet, not `gaps` mode's.)
|
|
59
|
+
|
|
60
|
+
## packaging and export validation
|
|
61
|
+
|
|
62
|
+
- **Signal**: a published package (has a `bin` or `exports` field, isn't
|
|
63
|
+
`private: true`) with no `publint`/`arethetypeswrong` check wired into its
|
|
64
|
+
verify gate.
|
|
65
|
+
- **Research**: what do `publint.dev` and `arethetypeswrong.github.io`
|
|
66
|
+
currently flag as common packaging mistakes, and is either tool's current
|
|
67
|
+
recommended invocation different from a bare CLI call (e.g. a config
|
|
68
|
+
flag this project should pass)?
|
|
69
|
+
|
|
70
|
+
## dependency hygiene
|
|
71
|
+
|
|
72
|
+
- **Signal**: no `knip` (or equivalent unused-export/unused-dependency
|
|
73
|
+
tool) configured at all.
|
|
74
|
+
- **Research**: what does `knip.dev`'s current documentation recommend for
|
|
75
|
+
a project shaped like this one (workspaces, multiple entry points, a CLI
|
|
76
|
+
`bin`) that has no such tool yet? (An existing `knip.json` that looks stale
|
|
77
|
+
against the project's actual entry points is drift in existing config, not
|
|
78
|
+
absence -- `knip.json` is a `research`/`refresh` domain file; switch mode
|
|
79
|
+
rather than researching a fix here.)
|
|
80
|
+
|
|
81
|
+
## pnpm supply-chain settings
|
|
82
|
+
|
|
83
|
+
- **Signal**: `pnpm-workspace.yaml`/`.npmrc` has no supply-chain-hardening
|
|
84
|
+
setting configured at all -- no lifecycle-script allowlist, no
|
|
85
|
+
`packageManager` corepack pin in `package.json`, no audit setting.
|
|
86
|
+
- **Research**: what supply-chain-hardening settings does the project's
|
|
87
|
+
actual pnpm major currently document (lifecycle-script allowlisting,
|
|
88
|
+
`minimumReleaseAge`, audit settings), for a project that has none
|
|
89
|
+
configured yet? (Whether an existing setting has since been renamed or
|
|
90
|
+
removed by a newer pnpm major -- a lifecycle-script allowlist key moving
|
|
91
|
+
to a different file, for example -- is drift in something already
|
|
92
|
+
configured, not absence; hand it to `research`/`refresh` rather than
|
|
93
|
+
research it here, since `pnpm-workspace.yaml` is one of its own domain
|
|
94
|
+
files.)
|
|
95
|
+
|
|
96
|
+
## scripts and verify gates
|
|
97
|
+
|
|
98
|
+
- **Signal**: a check this project runs by hand (or not at all) that a
|
|
99
|
+
comparable project would gate in CI -- a missing `check:exports`-equivalent
|
|
100
|
+
on a published package, no `pnpm verify`-shaped aggregator at all.
|
|
101
|
+
- **Research**: n/a in the live-fetch sense (this is a project-structure
|
|
102
|
+
question, not an upstream-guidance one) -- but check whether the project's
|
|
103
|
+
gate runner shape (a package script vs. a dedicated
|
|
104
|
+
`bin/verify.mjs`-style aggregator) matches current tooling convention for
|
|
105
|
+
its ecosystem before recommending which shape to add.
|
|
106
|
+
|
|
107
|
+
## monorepo and catalogs
|
|
108
|
+
|
|
109
|
+
- **Signal**: multiple `package.json` files under one root with no
|
|
110
|
+
`pnpm-workspace.yaml`, or a workspace with repeated identical dependency
|
|
111
|
+
version pins across packages that pnpm's `catalog`/`catalogs` feature
|
|
112
|
+
exists to deduplicate.
|
|
113
|
+
- **Research**: what does pnpm's current workspace/catalog documentation
|
|
114
|
+
recommend for this shape, and does the pinned pnpm major actually support
|
|
115
|
+
the catalog syntax being recommended?
|
|
116
|
+
|
|
117
|
+
## Node version pinning
|
|
118
|
+
|
|
119
|
+
- **Signal**: no Node version pin anywhere at all -- no `.node-version`, no
|
|
120
|
+
`.nvmrc`, no `engines.node`.
|
|
121
|
+
- **Research**: what does `nodejs.org`'s current release schedule recommend
|
|
122
|
+
pinning to for a new project? (A disagreement between multiple existing
|
|
123
|
+
pins, or a pin that's already past its documented end-of-life, is drift in
|
|
124
|
+
something already configured -- `research`/`refresh`'s question, not
|
|
125
|
+
`gaps` mode's.)
|
|
126
|
+
|
|
127
|
+
## release automation
|
|
128
|
+
|
|
129
|
+
- **Signal**: a package that's published (not `private: true`) with no
|
|
130
|
+
automated release pipeline (no changesets, no equivalent version-bump
|
|
131
|
+
automation).
|
|
132
|
+
- **Research**: what does `changesets/changesets`'s current documentation
|
|
133
|
+
recommend for this project's publishing shape (single package vs.
|
|
134
|
+
workspace)? If the project already has a release workflow, that is drift
|
|
135
|
+
in existing config, not a gap -- hand it to `research`/`refresh`.
|