Skip to content

Commit eb7a3d8

Browse files
refactor: migrate protocol + docs tooling into buddy commands
Per Chris: reusable tooling should be discoverable behind `buddy`, not loose scripts. Move the protocol governance + docs-freshness tooling out of .github/scripts and expose it as `buddy protocol:*` (16 commands) and `buddy docs:*` (6). The protocol suite/evidence data stays under .github/protocol; the pre-install / CI-internal glue (check-lockfile-version, check-dependency-commits, deploy/resolve-target) stays as scripts. - .github/scripts/{protocol,docs} -> app/Commands/{protocol,docs}. Same depth, so root + framework-import paths are unchanged; sync-suite.test.ts's combined `../../protocol` ref needed one more `../` since app/Commands and .github/protocol are not siblings. - Each tool's `if (import.meta.main)` body extracted to `export run()`; a runTool() helper swaps process.argv so each tool's existing --check/--write parsing works unchanged. - app/Commands/{Protocol,Docs}.ts register the commands; package.json + CI now invoke `buddy <cmd>`. Verified: every command runs; protocol:conformance 15/37; moved tests 48/0; lint clean. The manifest/desktop/craft/docs:buddy checks fail only locally (missing rfcs git object, env-dependent evidence, machine-path doc noise), identical on origin/main and green in CI.
1 parent 28ec913 commit eb7a3d8

33 files changed

Lines changed: 529 additions & 91 deletions

.github/scripts/protocol/desktop-support.ts

Lines changed: 0 additions & 34 deletions
This file was deleted.

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,8 +174,8 @@ jobs:
174174
env:
175175
PROTOCOL_REPORT_DIR: .github/protocol/reports
176176
run: |
177-
bun test ./.github/scripts/protocol/run-conformance.test.ts
178-
bun test ./.github/scripts/protocol/craft-evidence.test.ts ./.github/scripts/protocol/desktop-lifecycle-report.test.ts
177+
bun test ./app/Commands/protocol/run-conformance.test.ts
178+
bun test ./app/Commands/protocol/craft-evidence.test.ts ./app/Commands/protocol/desktop-lifecycle-report.test.ts
179179
bun test ./.github/scripts/deploy/resolve-target.test.ts
180180
bun run protocol:drivers:test
181181
bun run protocol:conformance

.github/workflows/desktop-lifecycle.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,16 @@ on:
55
branches: [main]
66
paths:
77
- storage/framework/core/desktop/**
8-
- .github/scripts/protocol/craft-evidence.ts
9-
- .github/scripts/protocol/desktop-lifecycle-report.ts
8+
- app/Commands/protocol/craft-evidence.ts
9+
- app/Commands/protocol/desktop-lifecycle-report.ts
1010
- .github/protocol/evidence/craft.json
1111
- .github/workflows/desktop-lifecycle.yml
1212
pull_request:
1313
branches: [main]
1414
paths:
1515
- storage/framework/core/desktop/**
16-
- .github/scripts/protocol/craft-evidence.ts
17-
- .github/scripts/protocol/desktop-lifecycle-report.ts
16+
- app/Commands/protocol/craft-evidence.ts
17+
- app/Commands/protocol/desktop-lifecycle-report.ts
1818
- .github/protocol/evidence/craft.json
1919
- .github/workflows/desktop-lifecycle.yml
2020
workflow_dispatch:
@@ -123,7 +123,7 @@ jobs:
123123

124124
- name: Validate and attest lifecycle report
125125
run: >-
126-
bun .github/scripts/protocol/desktop-lifecycle-report.ts
126+
bun app/Commands/protocol/desktop-lifecycle-report.ts
127127
--report .craft-contract/artifacts/native-lifecycle/${{ matrix.name }}/report.json
128128
--output .github/protocol/reports/desktop/${{ matrix.name }}/attestation.json
129129
--revision "$CRAFT_SOURCE_REVISION"

app/Commands.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,6 @@ export type CommandRegistry = Record<string, string | CommandConfig>
2828
*/
2929
export default {
3030
'inspire': 'Inspire',
31+
'protocol': 'Protocol',
32+
'docs': 'Docs',
3133
} satisfies CommandRegistry

app/Commands/Docs.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import type { CLI } from '@stacksjs/types'
2+
import { run as runArtifacts } from './docs/generated-artifacts'
3+
import { run as runBuddyDocs } from './docs/buddy-commands'
4+
import { run as runLinks } from './docs/links'
5+
import { runTool } from './run-tool'
6+
7+
/**
8+
* Repo-scoped `buddy docs:*` commands wrapping the documentation-freshness
9+
* tooling under `app/Commands/docs/`: the generated buddy command reference,
10+
* generated API artifacts (OpenAPI + types), and internal link checking.
11+
*/
12+
export default function (cli: CLI): void {
13+
cli
14+
.command('docs:buddy', 'Regenerate the buddy command reference doc')
15+
.action(async () => {
16+
await runTool(runBuddyDocs, '--write')
17+
})
18+
19+
cli
20+
.command('docs:buddy:check', 'Verify the buddy command reference doc is current')
21+
.action(async () => {
22+
await runTool(runBuddyDocs, '--check')
23+
})
24+
25+
cli
26+
.command('docs:artifacts', 'Regenerate the generated API artifacts (OpenAPI + types)')
27+
.action(async () => {
28+
await runTool(runArtifacts, '--write')
29+
})
30+
31+
cli
32+
.command('docs:artifacts:check', 'Verify the generated API artifacts are current')
33+
.action(async () => {
34+
await runTool(runArtifacts, '--check')
35+
})
36+
37+
cli
38+
.command('docs:links', 'Report internal documentation links')
39+
.action(async () => {
40+
await runTool(runLinks)
41+
})
42+
43+
cli
44+
.command('docs:links:check', 'Verify internal documentation links resolve')
45+
.action(async () => {
46+
await runTool(runLinks, '--check')
47+
})
48+
}

app/Commands/Protocol.ts

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
import type { CLI } from '@stacksjs/types'
2+
import { run as runConformance } from './protocol/run-conformance'
3+
import { run as runCraft } from './protocol/craft-evidence'
4+
import { run as runDesktop } from './protocol/desktop-support'
5+
import { run as runDrivers } from './protocol/driver-registry'
6+
import { run as runDriverContracts } from './protocol/run-driver-contracts'
7+
import { run as runPantry } from './protocol/pantry-evidence'
8+
import { run as runRelease } from './protocol/release-manifest'
9+
import { run as runManifest } from './protocol/source-manifest'
10+
import { run as runSync } from './protocol/sync-suite'
11+
import { runTool } from './run-tool'
12+
13+
/**
14+
* Repo-scoped `buddy protocol:*` commands. The governance tooling itself lives
15+
* beside this file under `app/Commands/protocol/`; the protocol suite + evidence
16+
* DATA stays under `.github/protocol/`. These wrap the tooling so it is
17+
* discoverable via the CLI (`buddy protocol:conformance`) instead of a bare
18+
* `bun app/Commands/protocol/...`.
19+
*/
20+
export default function (cli: CLI): void {
21+
cli
22+
.command('protocol:conformance', 'Generate the Stacks protocol conformance report')
23+
.action(async () => {
24+
await runConformance()
25+
})
26+
27+
cli
28+
.command('protocol:sync', 'Sync the vendored protocol suite from stacksjs/rfcs')
29+
.option('--source <path>', 'Path to a local rfcs checkout', { default: undefined })
30+
.action(async (options: { source?: string }) => {
31+
await runTool(runSync, '--write', ...(options.source ? ['--source', options.source] : []))
32+
})
33+
34+
cli
35+
.command('protocol:check', 'Verify the vendored protocol suite is pinned + internally consistent')
36+
.action(async () => {
37+
await runTool(runSync, '--check')
38+
})
39+
40+
cli
41+
.command('protocol:manifest', 'Write the protocol source manifest')
42+
.option('--revision <ref>', 'Source revision to pin (default HEAD)', { default: undefined })
43+
.action(async (options: { revision?: string }) => {
44+
await runTool(runManifest, '--write', ...(options.revision ? ['--revision', options.revision] : []))
45+
})
46+
47+
cli
48+
.command('protocol:manifest:check', 'Verify the protocol source manifest is current')
49+
.action(async () => {
50+
await runTool(runManifest, '--check')
51+
})
52+
53+
cli
54+
.command('protocol:release', 'Write the protocol release manifest')
55+
.option('--tag <tag>', 'Release tag', { default: undefined })
56+
.action(async (options: { tag?: string }) => {
57+
await runTool(runRelease, '--write', ...(options.tag ? ['--tag', options.tag] : []))
58+
})
59+
60+
cli
61+
.command('protocol:release:check', 'Verify the protocol release manifest is current')
62+
.action(async () => {
63+
await runTool(runRelease, '--check')
64+
})
65+
66+
cli
67+
.command('protocol:drivers', 'Write the driver capability registry evidence')
68+
.action(async () => {
69+
await runTool(runDrivers, '--write')
70+
})
71+
72+
cli
73+
.command('protocol:drivers:check', 'Verify the driver capability registry evidence')
74+
.action(async () => {
75+
await runTool(runDrivers, '--check')
76+
})
77+
78+
cli
79+
.command('protocol:drivers:test', 'Run the driver contract suite')
80+
.action(async () => {
81+
await runTool(runDriverContracts)
82+
})
83+
84+
cli
85+
.command('protocol:desktop', 'Write the desktop support matrix evidence')
86+
.action(async () => {
87+
await runTool(runDesktop, '--write')
88+
})
89+
90+
cli
91+
.command('protocol:desktop:check', 'Verify the desktop support matrix evidence')
92+
.action(async () => {
93+
await runTool(runDesktop, '--check')
94+
})
95+
96+
cli
97+
.command('protocol:pantry', 'Write the pantry evidence')
98+
.action(async () => {
99+
await runTool(runPantry, '--write')
100+
})
101+
102+
cli
103+
.command('protocol:pantry:check', 'Verify the pantry evidence')
104+
.action(async () => {
105+
await runTool(runPantry, '--check')
106+
})
107+
108+
cli
109+
.command('protocol:craft', 'Write the Craft evidence')
110+
.action(async () => {
111+
await runTool(runCraft, '--write')
112+
})
113+
114+
cli
115+
.command('protocol:craft:check', 'Verify the Craft evidence')
116+
.action(async () => {
117+
await runTool(runCraft, '--check')
118+
})
119+
}
File renamed without changes.
Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ export function renderBuddyCommandReference(inventory: BuddyInventory): string {
8989
'title: Buddy Command Reference',
9090
'description: Generated reference for every Buddy command, argument, option, alias, default, and example.',
9191
'---',
92-
'<!-- Generated by .github/scripts/docs/buddy-commands.ts. Do not edit by hand. -->',
92+
'<!-- Generated by app/Commands/docs/buddy-commands.ts. Do not edit by hand. -->',
9393
'',
9494
'# Buddy Command Reference',
9595
'',
@@ -125,10 +125,10 @@ export function loadBuddyInventory(): BuddyInventory {
125125
return inventory
126126
}
127127

128-
if (import.meta.main) {
128+
export async function run(): Promise<void> {
129129
const mode = process.argv.includes('--write') ? 'write' : process.argv.includes('--check') ? 'check' : null
130130
if (!mode) {
131-
console.error('usage: bun .github/scripts/docs/buddy-commands.ts --write | --check')
131+
console.error('usage: bun app/Commands/docs/buddy-commands.ts --write | --check')
132132
process.exit(2)
133133
}
134134

@@ -145,3 +145,6 @@ if (import.meta.main) {
145145
console.log('Buddy command reference matches the runtime registry')
146146
}
147147
}
148+
149+
if (import.meta.main)
150+
await run()
File renamed without changes.

.github/scripts/docs/generated-artifacts.ts renamed to app/Commands/docs/generated-artifacts.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,12 @@ async function check(): Promise<void> {
5151
console.log(`Generated API artifacts are current (${Object.keys(JSON.parse(expected.openApi).paths).length} paths)`)
5252
}
5353

54-
if (import.meta.main) {
54+
export async function run(): Promise<void> {
5555
try {
5656
if (process.argv.includes('--write')) await write()
5757
else if (process.argv.includes('--check')) await check()
5858
else {
59-
console.error('usage: bun .github/scripts/docs/generated-artifacts.ts --write | --check')
59+
console.error('usage: bun app/Commands/docs/generated-artifacts.ts --write | --check')
6060
process.exit(2)
6161
}
6262
}
@@ -65,3 +65,6 @@ if (import.meta.main) {
6565
process.exit(1)
6666
}
6767
}
68+
69+
if (import.meta.main)
70+
await run()

0 commit comments

Comments
 (0)