@monte3l/groundwork 1.0.0-rc.2 → 1.0.0-rc.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (170) hide show
  1. package/README.md +13 -5
  2. package/bin/m3l-groundwork.mjs +36 -2
  3. package/dist/assets.d.ts +10 -0
  4. package/dist/assets.js +14 -0
  5. package/dist/baseline-stage.d.ts +173 -0
  6. package/dist/baseline-stage.js +215 -0
  7. package/dist/caps.d.ts +4 -1
  8. package/dist/caps.js +17 -3
  9. package/dist/conflicts.d.ts +23 -2
  10. package/dist/conflicts.js +89 -11
  11. package/dist/customize-paths.d.ts +92 -0
  12. package/dist/customize-paths.js +115 -0
  13. package/dist/emit.d.ts +50 -1
  14. package/dist/emit.js +121 -13
  15. package/dist/fatal.d.ts +70 -0
  16. package/dist/fatal.js +132 -0
  17. package/dist/format-error.d.ts +113 -0
  18. package/dist/format-error.js +553 -0
  19. package/dist/fs-guard.d.ts +142 -0
  20. package/dist/fs-guard.js +222 -0
  21. package/dist/git.js +10 -1
  22. package/dist/harness/conformance.js +2 -0
  23. package/dist/harness/frontmatter.js +2 -13
  24. package/dist/harness/grade.js +37 -8
  25. package/dist/harness/rules.d.ts +20 -3
  26. package/dist/harness/rules.js +108 -6
  27. package/dist/harness/types.d.ts +13 -0
  28. package/dist/harness/types.js +3 -0
  29. package/dist/inventory.d.ts +77 -3
  30. package/dist/inventory.js +103 -12
  31. package/dist/jsonc.d.ts +49 -2
  32. package/dist/jsonc.js +140 -7
  33. package/dist/main.d.ts +62 -3
  34. package/dist/main.js +538 -67
  35. package/dist/merge-json.d.ts +47 -4
  36. package/dist/merge-json.js +120 -8
  37. package/dist/mode.js +12 -2
  38. package/dist/pack-stage.d.ts +210 -0
  39. package/dist/pack-stage.js +287 -0
  40. package/dist/packs.d.ts +19 -13
  41. package/dist/packs.js +231 -28
  42. package/dist/palette.d.ts +23 -0
  43. package/dist/palette.js +22 -0
  44. package/dist/plugin.d.ts +122 -6
  45. package/dist/plugin.js +687 -47
  46. package/dist/report.d.ts +21 -2
  47. package/dist/report.js +93 -5
  48. package/dist/staging.d.ts +176 -0
  49. package/dist/staging.js +375 -0
  50. package/dist/survey/fs-walk.d.ts +34 -2
  51. package/dist/survey/fs-walk.js +70 -5
  52. package/dist/survey/internal/blocked-path.d.ts +27 -0
  53. package/dist/survey/internal/blocked-path.js +129 -0
  54. package/dist/survey/internal/package-json.d.ts +13 -0
  55. package/dist/survey/internal/package-json.js +37 -0
  56. package/dist/survey/internal/read-guard.d.ts +178 -0
  57. package/dist/survey/internal/read-guard.js +276 -0
  58. package/dist/survey/survey-docs.d.ts +17 -2
  59. package/dist/survey/survey-docs.js +61 -21
  60. package/dist/survey/survey-harness.d.ts +20 -2
  61. package/dist/survey/survey-harness.js +87 -46
  62. package/dist/survey/survey-shape.d.ts +17 -2
  63. package/dist/survey/survey-shape.js +60 -46
  64. package/dist/survey/survey-toolchain.d.ts +16 -1
  65. package/dist/survey/survey-toolchain.js +69 -66
  66. package/dist/survey/survey.js +6 -4
  67. package/dist/survey/types.d.ts +79 -0
  68. package/dist/survey/types.js +2 -6
  69. package/dist/term.d.ts +80 -0
  70. package/dist/term.js +145 -0
  71. package/dist/tokens.js +2 -0
  72. package/dist/toolchain/conformance.js +2 -0
  73. package/dist/toolchain/grade.js +26 -8
  74. package/dist/toolchain/rules.d.ts +13 -4
  75. package/dist/toolchain/rules.js +16 -0
  76. package/dist/toolchain/tsconfig-chain.d.ts +2 -0
  77. package/dist/toolchain/tsconfig-chain.js +32 -8
  78. package/dist/toolchain/types.d.ts +16 -4
  79. package/dist/toolchain/types.js +3 -0
  80. package/package.json +4 -3
  81. package/plugin/skills/customize/SKILL.md +292 -18
  82. package/plugin/src/domain-map.ts +39 -14
  83. package/plugin/src/index.ts +5 -1
  84. package/plugin/src/kind-facet-map.ts +25 -8
  85. package/plugin/src/pack-map.ts +147 -25
  86. package/plugin/src/plugin-map.ts +236 -0
  87. package/templates/core/.claude/agents/Explore.md +0 -1
  88. package/templates/core/.claude/agents/code-implementer.md +4 -4
  89. package/templates/core/.claude/agents/code-reviewer.md +4 -4
  90. package/templates/core/.claude/agents/silent-failure-hunter.md +2 -2
  91. package/templates/core/.claude/agents/test-author.md +7 -5
  92. package/templates/core/.claude/hooks/guard-branch-isolation.mjs +56 -10
  93. package/templates/core/.claude/hooks/guard-double-background.mjs +13 -8
  94. package/templates/core/.claude/hooks/guard-git-push-signed.mjs +12 -9
  95. package/templates/core/.claude/hooks/guard-hub-src-writes.mjs +1890 -38
  96. package/templates/core/.claude/hooks/guard-js-extension.mjs +2 -1
  97. package/templates/core/.claude/hooks/guard-no-commonjs.mjs +7 -5
  98. package/templates/core/.claude/hooks/guard-secret-writes.mjs +7 -5
  99. package/templates/core/.claude/hooks/inject-decision-gate.mjs +12 -9
  100. package/templates/core/.claude/hooks/post-edit-verify.mjs +276 -98
  101. package/templates/core/.claude/rules/agent-dispatch.md +7 -0
  102. package/templates/core/.claude/rules/tests.md +2 -2
  103. package/templates/core/.claude/settings.json +5 -0
  104. package/templates/core/.claude/skills/finishing-work/SKILL.md +58 -10
  105. package/templates/core/.claude/skills/harness-guidance/SKILL.md +16 -7
  106. package/templates/core/.claude/skills/starting-work/SKILL.md +5 -0
  107. package/templates/core/.claude/skills/triaging-ci/SKILL.md +9 -8
  108. package/templates/core/.claude/skills/typescript-guidance/SKILL.md +137 -20
  109. package/templates/core/.claude/skills/typescript-guidance/references/area-catalog.md +135 -0
  110. package/templates/core/.claude/skills/typescript-guidance/references/tooling-sources.md +113 -0
  111. package/templates/core/.claude/skills/writing-commits/SKILL.md +2 -2
  112. package/templates/core/.github/dependabot.yml +18 -0
  113. package/templates/core/.github/workflows/ci.yml +15 -15
  114. package/templates/core/.github/workflows/dependency-review.yml +2 -2
  115. package/templates/core/.github/workflows/security-audit.yml +10 -4
  116. package/templates/core/.prettierignore +4 -0
  117. package/templates/core/CLAUDE.md +53 -3
  118. package/templates/core/README.md +30 -10
  119. package/templates/core/_gitignore +17 -0
  120. package/templates/core/bin/check-exports.mjs +11 -5
  121. package/templates/core/bin/lib/agent-roster.mjs +1 -1
  122. package/templates/core/bin/lib/frontmatter.mjs +4 -2
  123. package/templates/core/bin/lib/harness-rules.mjs +169 -20
  124. package/templates/core/bin/lib/protected-paths.mjs +93 -5
  125. package/templates/core/bin/lib/toolchain-rules.mjs +187 -26
  126. package/templates/core/bin/lib/verify-steps.mjs +29 -11
  127. package/templates/core/bin/verify.mjs +12 -0
  128. package/templates/core/eslint.config.js +5 -0
  129. package/templates/core/package.json +7 -7
  130. package/templates/core/vitest.config.ts +8 -1
  131. package/templates/packs/README.md +35 -24
  132. package/templates/packs/github/files/.claude/skills/reviewing-dependabot-prs/SKILL.md +133 -0
  133. package/templates/packs/github/files/.claude/skills/triaging-scan-alerts/SKILL.md +88 -0
  134. package/templates/packs/github/files/.claude/skills/watching-pr-checks/SKILL.md +94 -0
  135. package/templates/packs/github/files/.github/workflows/claude-pr-review.yml +267 -0
  136. package/templates/packs/github/files/.github/workflows/claude.yml +106 -0
  137. package/templates/packs/github/pack.json +19 -0
  138. package/templates/packs/harness-extras/files/.claude/hooks/guard-readonly-bash.mjs +1122 -65
  139. package/templates/packs/harness-extras/files/.claude/hooks/reinject-compact-handoff.mjs +147 -13
  140. package/templates/packs/{statusline → harness-extras}/files/.claude/hooks/statusline.mjs +6 -2
  141. package/templates/packs/harness-extras/files/.claude/hooks/write-compact-handoff.mjs +227 -44
  142. package/templates/packs/harness-extras/pack.json +18 -13
  143. package/templates/packs/publishing/files/.changeset/README.md +25 -0
  144. package/templates/packs/publishing/files/.changeset/config.json +7 -0
  145. package/templates/packs/publishing/files/.github/release-tools/package.json +9 -0
  146. package/templates/packs/publishing/files/.github/workflows/release.yml +293 -0
  147. package/templates/packs/publishing/files/REUSE.toml +28 -0
  148. package/templates/packs/publishing/files/bin/check-dts-deps.mjs +234 -0
  149. package/templates/packs/publishing/files/bin/check-license-headers.mjs +217 -0
  150. package/templates/packs/publishing/files/bin/check-publish-version.mjs +149 -0
  151. package/templates/packs/publishing/files/bin/lib/npm-publish-args.mjs +86 -0
  152. package/templates/packs/publishing/files/bin/pnpm-publish-shim.mjs +86 -0
  153. package/templates/packs/publishing/pack.json +35 -0
  154. package/templates/packs/{harness-extras → quality}/files/bin/check-file-budget.mjs +6 -4
  155. package/templates/packs/quality/pack.json +29 -0
  156. package/templates/packs/supply-chain/files/.github/workflows/gitleaks.yml +52 -0
  157. package/templates/packs/supply-chain/files/.github/workflows/scorecard.yml +48 -0
  158. package/templates/packs/supply-chain/files/.gitleaks.toml +2 -0
  159. package/templates/packs/supply-chain/pack.json +19 -0
  160. package/templates/packs/worktrees/files/.claude/hooks/ensure-worktree-deps.mjs +283 -0
  161. package/templates/packs/worktrees/files/.claude/hooks/guard-worktree-only.mjs +245 -0
  162. package/templates/packs/worktrees/files/.claude/hooks/repair-core-bare.mjs +335 -0
  163. package/templates/packs/worktrees/files/.claude/skills/working-in-worktrees/SKILL.md +139 -0
  164. package/templates/packs/worktrees/files/.worktreeinclude +11 -0
  165. package/templates/packs/worktrees/pack.json +64 -0
  166. package/templates/packs/statusline/pack.json +0 -31
  167. /package/templates/packs/{statusline → harness-extras}/files/.claude/hooks/statusline-layout.mjs +0 -0
  168. /package/templates/packs/{statusline → harness-extras}/files/.claude/hooks/subagent-statusline.mjs +0 -0
  169. /package/templates/packs/{harness-extras → quality}/files/.claude/agents/type-design-analyzer.md +0 -0
  170. /package/templates/packs/{harness-extras → quality}/files/bin/file-budget-baseline.json +0 -0
@@ -0,0 +1,113 @@
1
+ # Upstream tooling sources -- the allowlist
2
+
3
+ The sibling allowlist to `typescript-sources.md` in this same directory
4
+ (reused directly for the TypeScript-owner tier, not duplicated). This file
5
+ is `gaps` mode's ecosystem-tooling list and covers the TypeScript-adjacent
6
+ tooling `research` and `refresh` don't sweep: the package manager, the lint
7
+ runner's non-TypeScript-specific config, the test runner, the formatter,
8
+ dependency hygiene, and Node's own release schedule.
9
+
10
+ **A `gaps`-mode research brief passes the union of both files' domain lists**
11
+ when an area touches TypeScript itself (the tsconfig/typed-linting areas
12
+ always need `typescript-sources.md`'s list too); an area this file alone
13
+ covers (pnpm settings, Node pinning) needs only this file's list. Each file's
14
+ own GitHub caveat applies only to the GitHub paths it names regardless -- a
15
+ path allowed by `typescript-sources.md`'s caveat is not automatically allowed
16
+ by this file's caveat, and vice versa.
17
+
18
+ ## Domain allowlist
19
+
20
+ Pass verbatim as `WebSearch`'s `allowed_domains`, alongside
21
+ `typescript-guidance`'s own list when both are in scope for a given area:
22
+
23
+ ```
24
+ pnpm.io, knip.dev, vitest.dev, eslint.org, prettier.io, docs.npmjs.com,
25
+ nodejs.org
26
+ ```
27
+
28
+ Plus **the official docs of a tool the project's interview actually
29
+ selected** for bundling, if one was chosen and isn't already covered above
30
+ (a specific bundler's own docs).
31
+
32
+ One of the fixed domains is **path-scoped within a domain
33
+ `typescript-guidance` also uses, for a different path**:
34
+
35
+ - `nodejs.org` hosts the whole Node.js documentation site.
36
+ `typescript-guidance`'s own allowlist scopes it to `/api/typescript.html`
37
+ (the runtime type-stripping boundary). This file's own scope is
38
+ `/en/about/previous-releases` (the LTS/EOL schedule), for the
39
+ Node-version-pinning area only. Passing a bare `nodejs.org` to
40
+ `allowed_domains` allows both paths; treat a citation from any other
41
+ `nodejs.org` path as out of scope for either allowlist.
42
+
43
+ ## The tier
44
+
45
+ Every domain here is **T1 by default** for its own tool -- owner-normative,
46
+ the same standing `typescript-guidance`'s T1 gives `typescriptlang.org` for
47
+ TypeScript itself. Most of these tools have exactly one canonical doc
48
+ source, unlike TypeScript's ecosystem of adjacent linters/checkers, so most
49
+ citations from this file carry `TIER: T1` in the findings format `research` mode defines (which `gaps`
50
+ mode reuses).
51
+
52
+ - `pnpm.io` -- pnpm's own CLI, workspace, and `.npmrc`/supply-chain-setting
53
+ reference.
54
+ - `knip.dev` -- unused-dependency/unused-export tooling.
55
+ - `vitest.dev` -- the default test runner this baseline ships. **Tier here
56
+ is T1**, for a different purpose than its T2 listing in
57
+ `typescript-sources.md`: that file's T2 covers auditing the config of a
58
+ test runner the interview has already selected (`research`/`refresh`);
59
+ this file's T1 covers recommending vitest be **added** to a project that
60
+ has no test runner configured at all yet (`gaps`). Once a runner is
61
+ selected and configured, further scrutiny of its config is
62
+ `research`/`refresh` territory at T2, not `gaps` mode's -- the same domain
63
+ carries two tier labels because the modes consult it for two different
64
+ purposes.
65
+ - `eslint.org` -- ESLint's own core rules and flat-config reference (as
66
+ opposed to `typescript-eslint.io`, which stays `research`/`refresh`'s
67
+ territory for typed-linting presets specifically).
68
+ - `prettier.io` -- formatting.
69
+ - `docs.npmjs.com` -- npm-the-registry conventions (`package.json` fields,
70
+ `engines`, publishing) as distinct from any one package manager's CLI.
71
+ - `nodejs.org/en/about/previous-releases` -- the LTS/EOL schedule, for the
72
+ Node-version-pinning area. See the path-scope note above.
73
+
74
+ **Explicitly out of scope**, named so an agent that finds one drops it
75
+ rather than substituting it for missing coverage:
76
+
77
+ - A package manager's or tool's community wiki, forum post, or blog
78
+ aggregator (as opposed to its own docs site).
79
+ - An individual author's blog post about a tool, however highly ranked.
80
+ - `github.com/tsconfig/bases` and similar community-consensus
81
+ repositories -- consensus, not an owner's own word.
82
+
83
+ ## GitHub caveat
84
+
85
+ `allowed_domains` filters by domain, not path, so a bare `github.com`
86
+ allowance would let through any repo. Agents researching an area covered by
87
+ this file may include `github.com` and `raw.githubusercontent.com` in their
88
+ search domains, but must **only cite or fetch URLs under**:
89
+
90
+ - `changesets/changesets` (release automation)
91
+ - `typescript-eslint/typescript-eslint` (only for the release-compatibility
92
+ question -- "does this typescript-eslint version support this TypeScript
93
+ version" -- the rule semantics themselves stay `typescript-guidance`'s
94
+ T2 territory via `typescript-eslint.io`)
95
+ - `nodejs/Release` (the machine-readable Node release schedule, cross-checked
96
+ against `nodejs.org/en/about/previous-releases`)
97
+
98
+ Drop any other GitHub result, however highly ranked, the same as
99
+ `typescript-guidance`'s own caveat requires.
100
+
101
+ ## Coverage discipline
102
+
103
+ Reject any non-allowlisted domain outright and say so in the report, rather
104
+ than substituting a community blog, an individual author's material, or a
105
+ Stack Overflow answer for missing coverage. A facet that turns up no
106
+ qualifying source is itself a reportable coverage gap, not a reason to lower
107
+ the bar -- see `SKILL.md`'s Gaps mode, step 2.
108
+
109
+ ## Current-date anchor
110
+
111
+ Every research brief must state today's date explicitly, the same discipline
112
+ `typescript-guidance` applies -- a `retrieved <date>` stamp otherwise depends
113
+ on the spoke inferring the date itself, which is unreliable.
@@ -31,7 +31,7 @@ reviewer who wasn't in the room.
31
31
  ```bash
32
32
  git diff --staged # the files about to be committed
33
33
  git diff # unstaged context (reference only)
34
- git log main...HEAD --oneline # commits already on this branch
34
+ git log main..HEAD --oneline # commits already on this branch
35
35
  ```
36
36
 
37
37
  Read all three outputs before drafting anything. The staged diff is the
@@ -62,7 +62,7 @@ Rules enforced by commitlint:
62
62
 
63
63
  - **Imperative present tense** — "implement", "add", "fix", not "implemented"
64
64
  - **All lowercase** after `type:` — never `Feat:` or `feat: Add`
65
- - **≤ 70 characters** (hard limit — commitlint will reject longer subjects)
65
+ - **≤ 70 characters** (this skill's own target; commitlint's `config-conventional` only rejects headers over 100)
66
66
  - **No trailing period**
67
67
  - **Be specific** — name the module, file, class, or exported symbol
68
68
 
@@ -0,0 +1,18 @@
1
+ version: 2
2
+
3
+ updates:
4
+ # Keeps the action majors in .github/workflows/ from going stale. Every
5
+ # `uses:` line is pinned by commit SHA (not a floating tag), so Dependabot
6
+ # opening a PR to move the pin forward is what keeps that pinning
7
+ # affordable to maintain -- the same mechanism it would use for a floating
8
+ # tag, closing the "a compromised upstream tag" gap a floating `@vN`
9
+ # doesn't. npm updates are deliberately not enabled here -- add them later
10
+ # with `groups:` batching if the project wants it.
11
+ - package-ecosystem: "github-actions"
12
+ directory: "/"
13
+ schedule:
14
+ interval: "weekly"
15
+ commit-message:
16
+ prefix: "ci"
17
+ labels:
18
+ - "dependencies"
@@ -24,11 +24,11 @@ jobs:
24
24
  runs-on: ubuntu-latest
25
25
  timeout-minutes: 10
26
26
  steps:
27
- - uses: actions/checkout@v6
27
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
28
28
  with:
29
29
  persist-credentials: false
30
- - uses: pnpm/action-setup@v4
31
- - uses: actions/setup-node@v7
30
+ - uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0
31
+ - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
32
32
  with:
33
33
  node-version-file: .node-version
34
34
  cache: pnpm
@@ -40,11 +40,11 @@ jobs:
40
40
  runs-on: ubuntu-latest
41
41
  timeout-minutes: 10
42
42
  steps:
43
- - uses: actions/checkout@v6
43
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
44
44
  with:
45
45
  persist-credentials: false
46
- - uses: pnpm/action-setup@v4
47
- - uses: actions/setup-node@v7
46
+ - uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0
47
+ - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
48
48
  with:
49
49
  node-version-file: .node-version
50
50
  cache: pnpm
@@ -56,11 +56,11 @@ jobs:
56
56
  runs-on: ubuntu-latest
57
57
  timeout-minutes: 10
58
58
  steps:
59
- - uses: actions/checkout@v6
59
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
60
60
  with:
61
61
  persist-credentials: false
62
- - uses: pnpm/action-setup@v4
63
- - uses: actions/setup-node@v7
62
+ - uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0
63
+ - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
64
64
  with:
65
65
  node-version-file: .node-version
66
66
  cache: pnpm
@@ -72,11 +72,11 @@ jobs:
72
72
  runs-on: ubuntu-latest
73
73
  timeout-minutes: 10
74
74
  steps:
75
- - uses: actions/checkout@v6
75
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
76
76
  with:
77
77
  persist-credentials: false
78
- - uses: pnpm/action-setup@v4
79
- - uses: actions/setup-node@v7
78
+ - uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0
79
+ - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
80
80
  with:
81
81
  node-version-file: .node-version
82
82
  cache: pnpm
@@ -88,11 +88,11 @@ jobs:
88
88
  runs-on: ubuntu-latest
89
89
  timeout-minutes: 15
90
90
  steps:
91
- - uses: actions/checkout@v6
91
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
92
92
  with:
93
93
  persist-credentials: false
94
- - uses: pnpm/action-setup@v4
95
- - uses: actions/setup-node@v7
94
+ - uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0
95
+ - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
96
96
  with:
97
97
  node-version-file: .node-version
98
98
  cache: pnpm
@@ -17,10 +17,10 @@ jobs:
17
17
  runs-on: ubuntu-latest
18
18
  timeout-minutes: 10
19
19
  steps:
20
- - uses: actions/checkout@v6
20
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
21
21
  with:
22
22
  persist-credentials: false
23
- - uses: actions/dependency-review-action@v4
23
+ - uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5
24
24
  with:
25
25
  fail-on-severity: high
26
26
  allow-licenses: MIT, MIT-0, Apache-2.0, BSD-2-Clause, BSD-3-Clause, ISC, 0BSD, CC0-1.0, Unlicense, CC-BY-4.0
@@ -10,6 +10,12 @@ on:
10
10
  permissions:
11
11
  contents: read
12
12
 
13
+ # A manual dispatch overlapping the daily run would otherwise race to open
14
+ # the same failure issue.
15
+ concurrency:
16
+ group: security-audit
17
+ cancel-in-progress: false
18
+
13
19
  jobs:
14
20
  audit:
15
21
  name: Dependency audit
@@ -21,11 +27,11 @@ jobs:
21
27
  contents: read
22
28
  issues: write
23
29
  steps:
24
- - uses: actions/checkout@v6
30
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
25
31
  with:
26
32
  persist-credentials: false
27
- - uses: pnpm/action-setup@v4
28
- - uses: actions/setup-node@v7
33
+ - uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0
34
+ - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
29
35
  with:
30
36
  node-version-file: .node-version
31
37
  cache: pnpm
@@ -34,7 +40,7 @@ jobs:
34
40
  run: pnpm audit --audit-level=high
35
41
  - name: Open an issue on failure
36
42
  if: failure()
37
- uses: actions/github-script@v8
43
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
38
44
  with:
39
45
  script: |
40
46
  const title = "Scheduled security audit failed";
@@ -3,3 +3,7 @@ dist/
3
3
  coverage/
4
4
  pnpm-lock.yaml
5
5
  CHANGELOG.md
6
+ # A worktree the harness creates (see .gitignore) is a full, independent
7
+ # checkout under here -- without this, prettier double-visits (and can fail
8
+ # on) that copy's own in-progress state, which is a different session's WIP.
9
+ .claude/worktrees/
@@ -29,7 +29,7 @@ Run any task with `pnpm <script>`.
29
29
  | `pnpm knip` | Unused-dependency / unused-export hygiene; a `verify` step. `knip.json` ignores `@commitlint/config-conventional` and `@commitlint/types`, which are loaded by a string and a JSDoc type knip cannot see |
30
30
  | `pnpm check:exports` | publint + are-the-types-wrong against a packed tarball |
31
31
  | `pnpm check:node-version` | `.node-version` is authoritative; forbids a hardcoded pin in CI |
32
- | `pnpm verify` | Every gate above, in the same order CI runs them |
32
+ | `pnpm verify` | Every gate above plus the `harness`/`toolchain` graders, in `verify-steps.mjs` order; CI runs them as five parallel group lanes |
33
33
  | `pnpm prepare` | Installs the lefthook git hooks |
34
34
 
35
35
  Run `pnpm verify` before considering any task done — it reproduces CI
@@ -71,6 +71,53 @@ contract:
71
71
  Must-fix findings route back to `code-implementer`, and the loop repeats
72
72
  until clean.
73
73
 
74
+ **The guard also screens `Bash`, but only conservatively.** The same hook
75
+ runs on every `Bash` call and blocks a command that visibly writes into
76
+ `src/` or `tests/` (redirects, `tee`, `sed -i`, `cp`/`mv` into them, a
77
+ `python`/`node`/`php` snippet that writes or deletes there, a copy, move or
78
+ removal of a parent of `src/` such as `rsync -a /tmp/x/ ./` or `rm -rf .`, and
79
+ similar) unless the caller is `test-author` or `code-implementer`. It cannot
80
+ catch an indirect write -- an interpreter running a script from a project
81
+ file, an `eval`, a computed path, a parent of the project root (`rm -rf ..`), a workspace container below the project root (`tools/packages/foo`), a build step, a formatter or fixer
82
+ (`prettier --write`, `eslint --fix`), `git rm`/`git mv`, `find -exec`, `xargs` with a computed operand, `tar`/`curl -o`, a very long
83
+ interpreter call (allowed with a stderr note) -- so hub-and-spoke remains a convention backed by a guard that raises the bar,
84
+ not a proof. To override it deliberately, run the command yourself with the
85
+ `!` prefix at the Claude Code prompt, or edit the hook's registration in
86
+ `.claude/settings.json`.
87
+
88
+ **A Claude Code Enterprise/managed deployment sits above this and can
89
+ silently disable it.** Managed settings (a `managed-settings.json` file, an
90
+ MDM policy, or a claude.ai-console-managed remote policy) take precedence
91
+ over every file this baseline installs, with no project-level override, and
92
+ two managed-only keys -- `allowManagedHooksOnly` and
93
+ `allowManagedPermissionRulesOnly` -- make Claude Code skip this project's
94
+ own `.claude/settings.json` hooks and permission rules entirely rather than
95
+ merge with them (see
96
+ [Claude Code's managed-settings docs](https://code.claude.com/docs/en/managed-settings)).
97
+ Nothing in this project can detect or gate against that from inside the
98
+ repo -- the managed file lives outside any working tree, at an OS-level
99
+ path. Run `/status` on a machine you don't control before trusting
100
+ `guard-hub-src-writes.mjs`/`guard-branch-isolation.mjs`: its "Setting
101
+ sources" line names every active source, and if these hooks aren't among
102
+ what's actually running, treat hub-and-spoke as an unenforced checklist
103
+ until confirmed otherwise.
104
+
105
+ **An installed Claude Code mod is a second silent override, below managed
106
+ settings.** Per the
107
+ [hooks guide](https://code.claude.com/docs/en/hooks-guide), a mod that
108
+ handles `tool.check` "can approve a call that your `PreToolUse` hook blocked,
109
+ unless the hook is in managed settings", and project `PreToolUse` hooks run
110
+ only after the last mod calls `next` (see the
111
+ [mods events reference](https://code.claude.com/docs/en/plugins/mods/events)).
112
+ Only managed-settings hooks outrank a mod, and nothing in the repo can detect
113
+ one. Check `/plugin` for installed mods alongside `/status`.
114
+
115
+ **The guard keys on `agent_id` as well as `agent_type`.** Claude Code sends
116
+ `agent_type` both inside a subagent and in a main session started with
117
+ `--agent <name>`; only a call inside a subagent also carries `agent_id`. A
118
+ call counts as a writer spoke only with both present, so a hub launched as
119
+ `claude --agent code-implementer` is still the hub and is blocked.
120
+
74
121
  Full dispatch-sizing and recovery guidance: `.claude/rules/agent-dispatch.md`
75
122
  (auto-loads when editing `.claude/skills/**` or `.claude/agents/**`).
76
123
 
@@ -111,7 +158,9 @@ fix the config it points at.
111
158
  **Enforced at write time by hooks:** `any` implied by CommonJS constructs
112
159
  (`require`, `module.exports`, `__dirname`, `__filename`), a missing `.js`
113
160
  extension on a relative import, a hand-edit to `dist/` or `coverage/`, a
114
- write to `src/`/`tests/` while on `main`, a real secret written to disk.
161
+ write to `src/`/`tests/` while on `main`, a real secret written to disk,
162
+ an unsigned `git push` when `commit.gpgsign` is on, and a `run_in_background`
163
+ Bash call stacked with a shell-level detach construct.
115
164
 
116
165
  **No automated guard — need conscious care:** no `any` in the public API;
117
166
  never swallow an error silently; no top-level side effects; never
@@ -122,6 +171,7 @@ never swallow an error silently; no top-level side effects; never
122
171
  This baseline is frozen at the moment `m3l-groundwork` last emitted it. Run
123
172
  `/customize`'s guidance pass — or `.claude/skills/typescript-guidance/` /
124
173
  `.claude/skills/harness-guidance/` directly in refresh mode — periodically
125
- to sweep the toolchain and harness against current upstream guidance. See
174
+ to sweep the toolchain and harness against current upstream guidance; its
175
+ `gaps` mode recommends tooling the project doesn't have yet. See
126
176
  `docs/research/typescript-refresh.md` and `docs/research/harness-refresh.md`
127
177
  for the living trackers.
@@ -3,6 +3,15 @@
3
3
  Bootstrapped by [m3l-groundwork](https://github.com/monte3l/m3l-groundwork) —
4
4
  a deterministic TypeScript + Claude Code project bootstrapper.
5
5
 
6
+ ## What you just got
7
+
8
+ A TypeScript project wired up with a strict compiler configuration, ESLint,
9
+ Prettier, Vitest (with a coverage gate), and a Claude Code harness under
10
+ `.claude/` — agents, skills, hooks, and rules that shape how Claude Code
11
+ works in this repository. All of it is deliberately generic: a correct,
12
+ working starting point for any TypeScript project, not yet specific to what
13
+ __PROJECT_NAME__ actually does.
14
+
6
15
  ## Getting started
7
16
 
8
17
  ```bash
@@ -10,15 +19,26 @@ pnpm install
10
19
  pnpm verify
11
20
  ```
12
21
 
13
- `pnpm verify` runs the same checks CI runs: format, lint, typecheck, build,
14
- and test with coverage. See `CLAUDE.md` for the full command reference and
15
- the project's conventions.
22
+ `pnpm verify` runs the same checks CI runs — format, lint, typecheck, build,
23
+ and test with coverage — in one command, so you can catch a failure locally
24
+ before pushing. See `CLAUDE.md` for the full command reference and this
25
+ project's conventions.
26
+
27
+ ## Tailor it to your project
28
+
29
+ This baseline is frozen at the moment it was generated, and deliberately
30
+ generic until you adapt it. To tailor it to __PROJECT_NAME__:
31
+
32
+ 1. Open this repository in [Claude Code](https://claude.com/claude-code).
33
+ 2. Run the `/customize` slash command.
34
+ 3. Answer a short interview (project kind, runtime target, test strictness,
35
+ CI depth). Claude Code then tailors the baseline to your answers and
36
+ runs a live guidance pass against current official TypeScript and
37
+ Anthropic documentation, so the result reflects up-to-date recommended
38
+ practice rather than what was true when this baseline was generated.
16
39
 
17
- ## Customize this baseline
40
+ ## Glossary
18
41
 
19
- This project shipped with a frozen, universal TypeScript + Claude Code
20
- baseline. Run `/customize` inside Claude Code to tailor it: answer a short
21
- interview (project kind, runtime target, test strictness, CI depth), then
22
- let the guidance pass validate the result against current official
23
- TypeScript and Anthropic guidance rather than what was true when the
24
- baseline was built.
42
+ Run into an unfamiliar term in `CLAUDE.md`, this README, or the `.claude/`
43
+ harness? See the upstream
44
+ [glossary](https://github.com/monte3l/m3l-groundwork/blob/main/docs/glossary.md).
@@ -14,6 +14,23 @@ coverage/
14
14
  # Local overrides
15
15
  lefthook-local.yml
16
16
 
17
+ # A worktree the harness creates (`claude --worktree`, Agent tool
18
+ # `isolation: "worktree"`, or `EnterWorktree`) lands under here as a full,
19
+ # independent checkout -- including its own copy of every file this project
20
+ # already scans. Without this, prettier/eslint/vitest all double-visit (and
21
+ # can fail on) that copy's own in-progress state, which belongs to a
22
+ # different session, not this project's tracked content.
23
+ .claude/worktrees/
24
+
25
+ # Never commit secrets. (Also relevant to worktrees: a project that adds a
26
+ # `.worktreeinclude` file -- gitignore-syntax, Claude Code convention, see
27
+ # code.claude.com/docs/en/worktrees -- can only carry a gitignored file like
28
+ # this into a new worktree, never a tracked one, so it stays gitignored
29
+ # regardless of whether that file exists here.)
30
+ .env
31
+ .env.local
32
+ .env.*.local
33
+
17
34
  # Scratch state written by opt-in harness-extras pack hooks (e.g. the
18
35
  # compaction-handoff artifact) -- harmless if the pack isn't installed.
19
36
  tmp/
@@ -2,11 +2,17 @@
2
2
  /**
3
3
  * Real packaging correctness: packs the target package (`--cwd <dir>`,
4
4
  * default the repo root) with `pnpm pack`, then runs publint and
5
- * are-the-types-wrong (attw) against the resulting tarball. Skips cleanly
6
- * (exit 0, one warning) when the target has no `exports` field -- a project
7
- * that isn't published doesn't need this gate, and `/customize` removes the
8
- * step entirely for non-library project kinds rather than leaving a
9
- * permanently-skipped one behind.
5
+ * are-the-types-wrong (attw) against the resulting tarball -- checking the
6
+ * actual published artifact, not just the source tree. publint checks that
7
+ * `package.json` (its `exports` map, `main`/`module`/`types` fields, and
8
+ * which files are actually included) resolves the way consumers and
9
+ * bundlers expect. attw checks that the package's TypeScript type
10
+ * declarations actually match what each entry point resolves to at runtime
11
+ * -- e.g. that an ESM import doesn't quietly get pointed at CommonJS-shaped
12
+ * types. Skips cleanly (exit 0, one warning) when the target has no
13
+ * `exports` field -- a project that isn't published doesn't need this gate,
14
+ * and `/customize` removes the step entirely for non-library project kinds
15
+ * rather than leaving a permanently-skipped one behind.
10
16
  */
11
17
  import process from "node:process";
12
18
  import { execFileSync } from "node:child_process";
@@ -1,5 +1,5 @@
1
1
  /**
2
- * The writer-spoke roster: the only subagent names a PreToolUse[Write|Edit]
2
+ * The writer-spoke roster: the only subagent names a PreToolUse[Write|Edit|Bash]
3
3
  * hook trusts to write into a guarded `src/`/`tests/` path. Kept as one
4
4
  * small, static source so `guard-hub-src-writes.mjs` and this project's
5
5
  * `code-implementer`/`test-author` agent definitions can't silently drift
@@ -5,8 +5,10 @@
5
5
  * list scalars. Not supported: nested mappings (recorded as an empty string
6
6
  * rather than misparsed), anchors, tags. Every string result is trimmed.
7
7
  *
8
- * This file is the emitted twin of m3l-groundwork's own
9
- * `packages/cli/src/harness/frontmatter.ts`; a parity test keeps them equal.
8
+ * Also used by m3l-groundwork's own adopt mode (the tool that generated this
9
+ * project's harness); if you're contributing a change back upstream, keep
10
+ * this file's behavior in sync with its source at
11
+ * `packages/cli/src/harness/frontmatter.ts` there.
10
12
  */
11
13
 
12
14
  const KEY_LINE = /^([A-Za-z_][\w-]*):(?:[ \t]+(.*))?$/;